ZX81 Listing for picasm.asm


ZX81 assembly listing for *PICTURE ASM*SLR/2021**

ZX81 Assembly Program Listing

*PICTURE ASM*SLR/2021** (picasm.asm)


;
; The Picture
; v1.00 Steven Reid (c) 2021
; This is an assembly version of my old BASIC drawring routine.
;

        org 16514               ; stored in REM at top
        jr start             ; needed for z80asm

; title and copyright
copy:
        db $00,$27,$3e,$00,$38,$39,$2a,$3b,$2a,$33
        db $00,$37,$2a,$2e,$29,$00,$1e,$1c,$1e,$1d
        db $00,$17,$00,$17,$00,$39,$2d,$2a,$00,$35
        db $2e,$28,$39,$3a,$37,$2a,$00,$2e,$33,$00
        db $26,$38,$32,$00,$17,$00,$17,$76,$76
        ;  BY STEVEN REID 2021
        ;  * * THE PICTURE IN ASM * *

; macros
stop:           equ $0cdc
slow:           equ $0f2b
printat:        equ $08f5
pause:          equ $0f35

; system vars
d_file:         equ $400c

;
; Start of program!
;
start:

        ld hl,picturedata       ; start of picture data
mainloop:
        ld a,(hl)               ; check if we are at the end of the array
        cp $ff
;        jp z,waitloop           
        jp z,stop               ; all done

        ld de,linecoords        ; coordiantes (to)
        ld bc,4                 ; 4 to copy!
        ldir                    ; copy for coordinates
        push hl
        call draw_line          ; and go draw the line!
        pop hl

        jr mainloop             ; loop until out of data!

;waitloop:
;        ld   bc,1000
;        call pause
;        jp start

;        jp z,stop               ; all done

; End of loop!
;

        ;x can be 0 to 63
        ;y can be 0 to 45

picturedata:   ; start x1,y1 and end x2,y2 - 4 bytes per line
        db 25,38,61,38  ; boat bottom
        db 60,38,55,41
        db 55,41,30,41
        db 30,41,25,39

        db 48,38,48,8   ; mast

        db 48,8,45,11   ; flag
        db 45,11,48,11

        db 48,12,26,35  ; sales
        db 26,35,60,35
        db 59,35,48,12

        db 0,22,38,22   ; horizon
        db 53,22,64,22

        db 4,4,9,4      ; sun
        db 8,4,10,5
        db 9,5,9,7
        db 9,6,7,8
        db 8,8,4,8
        db 4,8,2,7
        db 2,7,2,6
        db 2,6,4,5
        db $ff          ; array done!

;
; Routines
;

;start code line

zxplot:
        ;alter pixel nominated by plotx and ploty
        ;plotmodes are flag2 bit 1. 0 = plot, 1 = unplot
        ;x can be 0 to 63
        ;y can be 0 to 45

        call calculate_origin


nozxplotcolour:
        ld a,(flag2)
        bit 1,a
        jp nz,unplot_pixel
        call plot_pixel

        ret
; end zxplot


calculate_origin:
        ; work out what square on the screen the pixel appears at
        ld a,(plotx)
        bit 7,a
        ret nz
        sub 64
        ret p

        ld a,(ploty)
        bit 7,a
        ret nz
        sub 46
        ret p

        ld a,$00
        ld (plotsector),a

        ld a,(plotx)
        srl a
        ld (plotx),a
        jr nc,pixelleft
        ld a,$01
        ld (plotsector),a  ;pixel is in right half

pixelleft:
        ld a,(ploty)
        srl a
        ld (ploty),a
        jr nc,pixelup
        ld a,(plotsector)
        set 1,a
        ld (plotsector),a  ;pixel is in lower half

pixelup:
        ;now find the correct screen position

        ld hl,(d_file)
        inc hl
        ld de,33
        ld a,(ploty)
        cp $0
        jr z,findx
        ld b,a

findy:
        add hl,de
        djnz findy

findx:
        ld de,$00
        ld a,(plotx)
        ld e,a
        add hl,de

        ld (plot_origin), hl

        ret

plot_pixel:
; plot the pixel in the co-ord from plot_origin (square on screen) and
; plotsector (actual pixel)
;   0= top left, 1 = top right, 2 = bottom left, 3 = bottom right

        ld hl,(plot_origin)

        ld a,(plotsector)
        cp $00
        jr z,plottl
        cp $01
        jr z,plottr
        cp $02
        jr z,plotbl
        cp $03
        jr z,plotbr

        ret


plottl: ;top left quadrant
        ld a,(hl)

plottlok:
        bit 7,a
        jr nz,tlinvert
        set 0,a
        ld (hl),a
        ret

tlinvert:
        res 0,a
        ld (hl),a
        ret

plottr: ;top right quadrant
        ld a,(hl)

plottrok:
        bit 7,a
        jr nz,trinvert
        set 1,a
        ld (hl),a
        ret

trinvert:
        res 1,a
        ld (hl),a
        ret

plotbl: ;bottom left quadrant
        ld a,(hl)

plotblok:
        bit 7,a
        jr nz,blinvert
        set 2,a
        ld (hl),a
        ret

blinvert:
        res 2,a
        ld (hl),a
        ret


plotbr: ;bottom right quadrant
        ld a,(hl)
        bit 7,a   ;collision detect
        ret nz

;plotbrok:
        set 7,a
        xor $07 ;invert all other bits
        ld (hl),a

ret  ; plot pixel

unplot_pixel:
        ; unplot the pixel in the co-ord from plot_origin (square on screen) and
        ; plotsector (actual pixel)
        ;  0= top left, 1 = top right, 2 = bottom left, 3 = bottom right
        ld hl,(plot_origin)

        ld a,(plotsector)
        cp $00
        jr z,uplottl
        cp $01
        jr z,uplottr
        cp $02
        jr z,uplotbl
        cp $03
        jr z,uplotbr

        ret

uplottl: ;top left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utlinvert
        res 0,a
        ld (hl),a
        ret

utlinvert:
        set 0,a
        ld (hl),a
        ret

uplottr: ;top right quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utrinvert
        res 1,a
        ld (hl),a
        ret

utrinvert:
        set 1,a
        ld (hl),a
        ret


uplotbl: ;bottom left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,ublinvert
        res 2,a
        ld (hl),a
        ret

ublinvert:
        set 2,a
        ld (hl),a
        ret


uplotbr: ;bottom right quadrant
        ld a,(hl)
        bit 7,a
        ret z
        res 7,a
        xor $07 ;invert all other bits
        ld (hl),a
        ret

        ret ;unplot pixel

draw_line_high:
        ; bresenham's algorithm
        ; for up down lines

        ld a,(x0p) ;dx = x1 - x0
        ld b,a
        ld a,(x1p)
        sub b
        ld (dx),a


        ld a,(y0p) ;dy = y1 - y0
        ld b,a
        ld a,(y1p)
        sub b
        ld (dy),a


        ld hl,xi ;xi =1
        ld (hl),$1

        ld a,(dx)
        bit 7,a ;if dx<0?

        jr z,dx_not_negh

        ;dx is < 0
        ld a,$ff   ;xi =-1
        ld (xi),a
        ld a,(dx) ; dx = -dx
        neg
        ld (dx),a

dx_not_negh:

        ld a,(dy) ;dis = (2 * dx) - dy
        ld b,a
        ld a,(dx)
        sla a ;dx*2
        sub b
        ld (dis),a

        ;x = x0
        ld a,(x0p)
        ld (x),a

        ld a,(y0p)  ;for y from y0 to y1
        ld (y),a
        ld b,a
        ld a,(y1p)
        sub b
        jr z,zero_line ;just plot the origin if line length is zero
        ld b,a ;b contains y1-y0


draw_line_looph:
        push bc

        ld a,(y)
        ld (ploty),a
        inc a
        ld (y),a

        ld a,(x)
        ld (plotx),a

        call zxplot  ;ploy x,y

        ;call single_step

        ld a,(dis)  ;if dis > 0
        bit 7,a
        jr nz,dis_lt0h


        ;x = x + xi
        ld a,(xi)
        ld b,a
        ld a,(x)
        add a,b
        ld (x),a

        ;dis = dis + (2 * (dx - dy))
        ld a,(dy)
        ld b,a
        ld a,(dx)
        sub b
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

        jr end_draw_line_looph

dis_lt0h:
        ;dis = dis + 2*dx
        ld a,(dx)
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a


end_draw_line_looph:
        pop bc

        djnz draw_line_looph

        ld hl,flag2
        res 1,(hl)

        ret ;draw_line_high

zero_line:
        ld a,(x0)
        ld (plotx),a

        ld a,(y0)
        ld (ploty),a

        call zxplot

        ret ;zero_line



draw_line_low:
        ; bresenham's algorithm

        ld a,(x0p) ;dx = x1 - x0
        ld b,a
        ld a,(x1p)
        sub b
        ld (dx),a


        ld a,(y0p) ;dy = y1 - y0
        ld b,a
        ld a,(y1p)
        sub b
        ld (dy),a


        ld hl,yi ;yi =1
        ld (hl),1

        bit 7,a ;if dy<0?

        jr z,dy_not_neg

        ;dy is < 0
        ld a,$ff   ;yi =-1
        ld (yi),a
        ld a,(dy) ; dy = -dy
        neg
        ld (dy),a

dy_not_neg:
        ld a,(dx) ;dis = (2 * dy) - dx
        ld b,a
        ld a,(dy)
        sla a ;dy*2
        sub b
        ld (dis),a

        ;y = y0
        ld a,(y0p)
        ld (y),a

        ld a,(x0p)  ;for x from x0 to x1
        ld (x),a
        ld b,a
        ld a,(x1p)
        sub b
        jr z,zero_line ;just plot the origin if line length is zero
        ld b,a ;b contains x1-x0


draw_line_loop:
        push bc

        ld a,(x)
        ld (plotx),a
        inc a
        ld (x),a

        ld a,(y)
        ld (ploty),a

        call zxplot  ;ploy x,y

        ld a,(dis)  ;if dis > 0
        bit 7,a
        jr nz,dis_lt0

        ;call print_star

        ;y = y + yi
        ld a,(yi)
        ld b,a
        ld a,(y)
        add a,b
        ld (y),a

        ;dis = dis + (2 * (dy - dx))
        ld a,(dx)
        ld b,a
        ld a,(dy)
        sub b
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

        jr end_draw_line_loop

dis_lt0:
        ;dis = dis + 2*dy
        ld a,(dy)
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

end_draw_line_loop:
        pop bc

        djnz draw_line_loop

        ld hl,flag2
        res 1,(hl)

        ret ;draw_line_low


undraw_line:
        ld hl,flag2
        set 1,(hl)


draw_line:
        ;will abort if both start and end are the same

        ld a,(x0)
        ld (x0p),a

        ld a,(x1)
        ld (x1p),a

        ld a,(y0)
        ld (y0p),a

        ld a,(y1)
        ld (y1p),a

        ;work out what configuration of the algorithm
        ;is correct to draw the line

        ;if abs(y1 - y0) < abs(x1 - x0)

        ld a,(y0)
        ld b,a
        ld a,(y1)
        sub b   ;a= y1-y0
        jr nc,y1gty0 ;nc = (y1-y0) >0
        neg ;change to abs value

y1gty0:
        ld c,a ;c = abs(y1 - y0)  ;works so far

        ld a,(x0)
        ld b,a
        ld a,(x1)
        sub b
        jr nc,x1gtx0
        neg

x1gtx0:
        ;a = abs(x1 - x0)

        sub c ;c = abs(y1 - y0)


        jr c,check_drawlinehigh ;abs(y1 - y0) < abs(x1 - x0) so use draw line high
        ;if x0 > x1 ;draw line low, else swap x0,y0 and x1,y1

        ld a,(x1)
        ld b,a
        ld a,(x0)
        sub b
        jp c,draw_line_low

        ;x1 > x0 so swap x0,x1 and y0,y1
        call swap_x0_x1_y0_y1

        jp draw_line_low


check_drawlinehigh:
        ;if y0 > y1
        ld a,(y1)
        ld b,a
        ld a,(y0)
        sub b
        jp c,draw_line_high

        ;plotlinehigh(x1, y1, x0, y0)

        ;x1 > x0 so swap x0,x1 and y0,y1

        call swap_x0_x1_y0_y1

        jp draw_line_high

        ;draw_line



swap_x0_x1_y0_y1:
        ld a,(y0)
        ld b,a
        ld a,(y1)
        ld (y0p),a
        ld a,b
        ld (y1p),a

        ld a,(x0)
        ld b,a
        ld a,(x1)
        ld (x0p),a
        ld a,b
        ld (x1p),a

        ret

get_cosine:
        ;same as sine plus 90 degrees
        sub $40


get_sine: ;take value of the a register and return the sine value from table
        ;first, work out what quadrant we're in
        cp $40
        jr nc,sine_quad2

        ;angle is top right quadrant
        ;count angle sine from bottom of table
        ld hl,sine_value_bottom
        ld de,$00
        ld e,a
        add hl,de
        ld a,(hl)

        ret

sine_quad2:
        cp $80
        jr nc,sine_quad3

        ;angle is bottom right quadrant
        ;count angle sine from top of table
        sub $40
        ld hl,sine_value_top
        ld de,$00
        ld e,a
        scf
        ccf
        sbc hl,de
        ld a,(hl)
        ret

sine_quad3:
        cp $c0
        jr nc,sine_quad4

        ;causing problems at $80

        ;angle is bottom left quadrant
        ;count negative angle sine from bottom of table
        sub $80
        ld hl,sine_value_bottom
        ld de,$00
        ld e,a
        add hl,de
        ld a,(hl)
        set 7,a
        ret

sine_quad4:
        ;angle is top left quadrant
        ;count negative angle sine from top of table

        ;causing problems at $ff

        sub $c0
        ld hl,sine_value_top
        ld de,$00
        ld e,a
        scf
        ccf
        sbc hl,de
        ld a,(hl)
        set 7,a
        ret ;get_sine

calculate_scaled_value:
        ;a register contains sine value
        ;multiply line_length by the sine and divide  by 128
        ;to get the displacement

        ld c,a ;preserve original displacement
        res 7,a

        cp $00
        jr z,calculate_zero_value

        ld b,a ;sine value
        ld a,(line_length)

        ld hl,$00

        ld l,a

        push hl
        pop de


        ;now multiply line length by the sine value

mult_sine_loop:
        add hl,de

        djnz mult_sine_loop

        ;divide result in hl register by 128

        ld b,$07

divide_by_128_loop:
        srl l
        srl h

        jr nc,nocarry_l_reg

        set 7,l

nocarry_l_reg:
        djnz divide_by_128_loop

        bit 7,c
        ret z
        ld a,l
        neg

calculate_zero_value:
        ld l,a

        ret ;calculate_scaled_value


;variables

flag2:
        db $00

plotmode:
        db $00

plotx:
        db $00

ploty:
        db $00

plotsector:
        db $00

plot_origin:
        db $00, $00

line_length:
        db $00


;line drawing x and y. variables ending in p are the parameters
;passed to the line draw program

linecoords:
x0:
        db $00

y0:
        db $00

x1:
        db $00

y1:
        db $00

x0p:
        db $00

y0p:
        db $00

x1p:
        db $00

y1p:
        db $00

;used for bresenham's line algorithm

dx:
        db $00

dy:
        db $00

xi:
        db $00

yi:
        db $00

dis:
        db $00

x:
        db $00

y:
        db $00


sine_value_bottom:  ;64 values f0r the sine of a value of 128, so a line of length
             ;128 would have a x length of 3 pixels at an angle of 1 unit of 63

        db $00,$03,$06,$09,$0c,$10,$13,$16,$19,$1c,$1f,$22,$25,$28,$2b
        db $2e,$31,$33,$36,$39,$3c,$3f,$41,$44,$47,$49,$4c,$4e,$51,$53
        db $55,$58,$5a,$5c,$5e,$60,$62,$64,$66,$68,$6a,$6b,$6d,$6f,$70
        db $71,$73,$74,$75,$76,$78,$79,$7a,$7a,$7b,$7c,$7d,$7d,$7e,$7e
        db $7e,$7f,$7f


sine_value_top:
        db $7f