Code: Select all
org 50000
Endless_Loop:
ld hl,Edge_Data
ld b,18
Frame_Loop:
push bc ; preserve B for loop
ld b,12
push hl
Edge_Loop:
push bc ; preserve B for loop
ld bc,(hl) ; B = ypos1 C = xpos1
inc hl
inc hl
ld de,(hl) ; D = ypos2 E = xpos2
inc hl
inc hl
push hl ; preserve edge pointer
call Draw_Line
pop hl
pop bc
djnz Edge_Loop
ld bc,$40ff ; Steve Wetherill floating bus frame sync from Sidewize
ld e,%00111010 ; red ink on white paper
sync:
ld a,r ; padding instruction
in a,(c)
cp e
jp nz,sync
ld b,12
pop hl
Erase_Loop:
push bc ; preserve B for loop
ld bc,(hl) ; B = ypos1 C = xpos1
inc hl
inc hl
ld de,(hl) ; D = ypos2 E = xpos2
inc hl
inc hl
push hl ; preserve edge pointer
call Erase_Line
pop hl
pop bc
djnz Erase_Loop
pop bc
djnz Frame_Loop
jp Endless_Loop
ret
; Plot routine
; B = Y pixel position
; C = X pixel position
;
Plot: CALL Get_Pixel_Address ; Get screen address in HL, pixel position (0 to 7) in A
LD BC,Plot_Point ; Address of point lookup table
ADD A,C ; Add pixel position to get entry in table
LD C,A
LD A,(BC) ; Get pixel data from table
OR (HL) ; OR with screen data
LD (HL),A ; Write back to screen
RET
; Unplot routine
; B = Y pixel position
; C = X pixel position
;
Unplot: CALL Get_Pixel_Address ; Same as Plot...
LD BC,Unplot_Point
ADD A,C
LD C,A
LD A,(BC)
AND (HL) ; AND with screen data
LD (HL),A
RET
; Draw Line routine
; B = Y pixel position 1
; C = X pixel position 1
; D = Y pixel position 2
; E = X pixel position 2
;
Draw_Line: LD A,D ; Check whether we are going to be drawing up
CP B
JR NC,Draw_Line_1
PUSH BC ; If we are, then this neat trick swaps BC and DE
PUSH DE ; using the stack, forcing the line to be always
POP BC ; drawn downwards
POP DE
Draw_Line_1: CALL Get_Pixel_Address ; Get screen address in HL, pixel position (0-7) in A
;
; At this point we have
; A = Pixel position (0-7)
; HL = Screen address of the start point
; BC = Start coordinate (B=Y1, C=X1)
; DE = End coordinates (D=Y2, E=X2)
;
LD IX,Plot_Point ; Point to the Plot_Point table
ADD A,IXL ; Add the pixel position to get entry in table
LD IXL,A
LD A,D ; Calculate the line height in B (Y2-Y1)
SUB B
LD B,A
LD A,E ; Calculate the line width in C (X2-X1)
SUB C
JR C,Draw_Line_X1 ; If carry set (negative result) then we are drawing from right to left
;
; This bit of code mods the main loop for drawing left to right
;
LD C,A ; Store the line width
LD A,0x2C ; Code for INC L
LD (Draw_Line_Q1_M3),A ; Mod the code
LD (Draw_Line_Q2_M3),A
LD A,0x0A ; Code for RRC D (CB 0A)
JR Draw_Line_X2 ; Skip the next bit
;
; This bit of code mods the main loop for drawing right to left
;
Draw_Line_X1: NEG ; The width of line is negative, so make it positive again
LD C,A ; Store the line width
LD A,0x2D ; Code for DEC L
LD (Draw_Line_Q1_M3),A
LD (Draw_Line_Q2_M3),A
LD A,0x02 ; Code for RLC D (CB 02)
;
; We've got the basic information at this point
;
Draw_Line_X2: LD (Draw_Line_Q1_M2 + 1),A ; A contains the code for RLC D or RRC D, so make the mods
LD (Draw_Line_Q2_M2 + 1),A
LD D,(IX+0) ; Get the pixel data from the Point_Plot table
LD A,B ; Check if B and C are 0
OR C
JR NZ,Draw_Line_Q ; There is a line to draw, so skip to the next bit
LD A,(HL) ; Here we've got a single point line, so plot and return
OR D
LD (HL),A
RET
;
; At this point
; HL = Screen address of the start point
; B = Line height
; C = Line width
; D = Pixel data
;
Draw_Line_Q: LD A,B ; Work out which diagonal we are on
CP C
JR NC,Draw_Line_Q2
;
; This bit of code draws the line where B<C (more horizontal than vertical)
;
Draw_Line_Q1: LD A,C
LD (Draw_Line_Q1_M1 + 1),A ; Self-mod the code again to store the line width
LD C,B
LD B,A
LD E,C ; Calculate the error value
SRL E
Draw_Line_Q1_L: LD A,(HL) ; Plot the pixel
OR D
LD (HL),A
LD A,E
SUB C
LD E,A
JR NC,Draw_Line_Q1_M2
Draw_Line_Q1_M1: ADD A,0 ; Add the line height (previously stored; self modifying code)
LD E,A
CALL Pixel_Address_Down
Draw_Line_Q1_M2: RRC D ; Rotate the pixel right or left; more self-modifying code
JR NC,Draw_Line_Q1_S
Draw_Line_Q1_M3: INC L ; If we get a carry then move to adjacent screen address; more self modifying code
Draw_Line_Q1_S: DJNZ Draw_Line_Q1_L ; Loop until the line is drawn
RET
;
; This bit draws the line where B>=C (more vertical than horizontal, or diagonal)
;
Draw_Line_Q2: LD (Draw_Line_Q2_M1 + 1),A
LD E,C ; Calculate the error value
SRL E
Draw_Line_Q2_L: LD A,(HL) ; Plot the pixel
OR D
LD (HL),A
LD A,E ; Get the error value
SUB C ; Add the line length to it (X2-X1)
JR NC,Draw_Line_Q2_S ; Skip the next bit if we don't get a carry
Draw_Line_Q2_M1: ADD A,0 ; Add the line height (previously stored; self modifying code)
Draw_Line_Q2_M2: RRC D ; Rotates the pixel right with carry
JR NC,Draw_Line_Q2_S
Draw_Line_Q2_M3: INC L ; If we get a carry then move to adjacent screen address; more self modifying code
Draw_Line_Q2_S: LD E,A ; Store the error value back in
CALL Pixel_Address_Down ; And also move down
DJNZ Draw_Line_Q2_L
RET
; Erase Line routine
; B = Y pixel position 1
; C = X pixel position 1
; D = Y pixel position 2
; E = X pixel position 2
;
Erase_Line: LD A,D ; Check whether we are going to be drawing up
CP B
JR NC,Erase_Line_1
PUSH BC ; If we are, then this neat trick swaps BC and DE
PUSH DE ; using the stack, forcing the line to be always
POP BC ; drawn downwards
POP DE
Erase_Line_1: CALL Get_Pixel_Address ; Get screen address in HL, pixel position (0-7) in A
;
; At this point we have
; A = Pixel position (0-7)
; HL = Screen address of the start point
; BC = Start coordinate (B=Y1, C=X1)
; DE = End coordinates (D=Y2, E=X2)
;
LD IX,Unplot_Point ; Point to the Unplot_Point table
ADD A,IXL ; Add the pixel position to get entry in table
LD IXL,A
LD A,D ; Calculate the line height in B (Y2-Y1)
SUB B
LD B,A
LD A,E ; Calculate the line width in C (X2-X1)
SUB C
JR C,Erase_Line_X1 ; If carry set (negative result) then we are drawing from right to left
;
; This bit of code mods the main loop for drawing left to right
;
LD C,A ; Store the line width
LD A,0x2C ; Code for INC L
LD (Erase_Line_Q1_M3),A ; Mod the code
LD (Erase_Line_Q2_M3),A
LD A,0x0A ; Code for RRC D (CB 0A)
JR Erase_Line_X2 ; Skip the next bit
;
; This bit of code mods the main loop for drawing right to left
;
Erase_Line_X1: NEG ; The width of line is negative, so make it positive again
LD C,A ; Store the line width
LD A,0x2D ; Code for DEC L
LD (Erase_Line_Q1_M3),A
LD (Erase_Line_Q2_M3),A
LD A,0x02 ; Code for RLC D (CB 02)
;
; We've got the basic information at this point
;
Erase_Line_X2: LD (Erase_Line_Q1_M2 + 1),A ; A contains the code for RLC D or RRC D, so make the mods
LD (Erase_Line_Q2_M2 + 1),A
LD D,(IX+0) ; Get the pixel data from the Unplot_Point table
LD A,B ; Check if B and C are 0
OR C
JR NZ,Erase_Line_Q ; There is a line to draw, so skip to the next bit
LD A,(HL) ; Here we've got a single point line, so plot and return
AND D
LD (HL),A
RET
;
; At this point
; HL = Screen address of the start point
; B = Line height
; C = Line width
; D = Pixel data
;
Erase_Line_Q: LD A,B ; Work out which diagonal we are on
CP C
JR NC,Erase_Line_Q2
;
; This bit of code draws the line where B<C (more horizontal than vertical)
;
Erase_Line_Q1: LD A,C
LD (Erase_Line_Q1_M1 + 1),A ; Self-mod the code again to store the line width
LD C,B
LD B,A
LD E,C ; Calculate the error value
SRL E
Erase_Line_Q1_L: LD A,(HL) ; Unplot the pixel
AND D
LD (HL),A
LD A,E
SUB C
LD E,A
JR NC,Erase_Line_Q1_M2
Erase_Line_Q1_M1: ADD A,0 ; Add the line height (previously stored; self modifying code)
LD E,A
CALL Pixel_Address_Down
Erase_Line_Q1_M2: RRC D ; Rotate the pixel right or left; more self-modifying code
JR C,Erase_Line_Q1_S ; Note the change here from the Draw_Line routine
Erase_Line_Q1_M3: INC L ; If we get no carry then move to adjacent screen address; more self modifying code
Erase_Line_Q1_S: DJNZ Erase_Line_Q1_L ; Loop until the line is drawn
RET
;
; This bit draws the line where B>=C (more vertical than horizontal, or diagonal)
;
Erase_Line_Q2: LD (Erase_Line_Q2_M1 + 1),A
LD E,C ; Calculate the error value
SRL E
Erase_Line_Q2_L: LD A,(HL) ; Unplot the pixel
AND D
LD (HL),A
LD A,E ; Get the error value
SUB C ; Add the line length to it (X2-X1)
JR NC,Erase_Line_Q2_S ; Skip the next bit if we don't get a carry
Erase_Line_Q2_M1: ADD A,0 ; Add the line height (previously stored; self modifying code)
Erase_Line_Q2_M2: RRC D ; Rotates the pixel right with carry
JR C,Erase_Line_Q2_S ; Note the change here from the Draw_Line routine
Erase_Line_Q2_M3: INC L ; If we get no carry then move to adjacent screen address; more self modifying code
Erase_Line_Q2_S: LD E,A ; Store the error value back in
CALL Pixel_Address_Down ; And also move down
DJNZ Erase_Line_Q2_L
RET
;; GET BUFFER PIXEL ADDRESS
;; B=y-pos C=x-pos
;; Returns: HL=Adress of pixel A=Byte of the pixel
Get_Buffer_Address:
ld l,0 ;
ld h,b ; B contains the Y-POS
srl h ;
rr l ;
srl h ;
rr l ; Shifts right 3x, then OR's low byte with 11100000
srl h ;
rr l ; divide by 8?
ld a,h ;
or 224 ; 11100000
ld h,a ;
ld a,c ; C contains the X-POS
rra ;
rra ; divide by 8
rra ;
and 31 ; 00011111 - strip out rolled in carry bytes
or l ;
ld l,a ;
ld a,c ;
and 7 ; 00000111
ret ;
; Get screen address
; B = Y pixel position
; C = X pixel position
; Returns address in HL and pixel position within character in A
;
Get_Pixel_Address: LD A,B ; Calculate Y2,Y1,Y0
AND %00000111 ; Mask out unwanted bits
OR %01000000 ; Set base address of screen
LD H,A ; Store in H
LD A,B ; Calculate Y7,Y6
RRA ; Shift to position
RRA
RRA
AND %00011000 ; Mask out unwanted bits
OR H ; OR with Y2,Y1,Y0
LD H,A ; Store in H
LD A,B ; Calculate Y5,Y4,Y3
RLA ; Shift to position
RLA
AND %11100000 ; Mask out unwanted bits
LD L,A ; Store in L
LD A,C ; Calculate X4,X3,X2,X1,X0
RRA ; Shift into position
RRA
RRA
AND %00011111 ; Mask out unwanted bits
OR L ; OR with Y5,Y4,Y3
LD L,A ; Store in L
LD A,C
AND 7
RET
; Move HL down one pixel line
;
Pixel_Address_Down: INC H ; Go down onto the next pixel line
LD A,H ; Check if we have gone onto next character boundary
AND 7
RET NZ ; No, so skip the next bit
LD A,L ; Go onto the next character line
ADD A,32
LD L,A
RET C ; Check if we have gone onto next third of screen
LD A,H ; Yes, so go onto next third
SUB 8
LD H,A
RET
; Note that the functions above only work if each of these tables are in a byte boundary
;
Plot_Point: DB %10000000,%01000000,%00100000,%00010000,%00001000,%00000100,%00000010,%00000001
Unplot_Point: DB %01111111,%10111111,%11011111,%11101111,%11110111,%11111011,%11111101,%11111110
Plot_Line_LHS: DB %11111111,%01111111,%00111111,%00011111,%00001111,%00000111,%00000011,%00000001
Plot_Line_RHS: DB %10000000,%11000000,%11100000,%11110000,%11111000,%11111100,%11111110,%11111111
Edge_Data:
;;;EDGE DATA
;;;FRAME #1 0 degrees
defb 164,7,231,7
defb 231,7,231,74
defb 231,74,164,74
defb 164,74,164,7
defb 218,21,178,21
defb 178,21,178,61
defb 178,61,218,61
defb 218,61,218,21
defb 164,7,178,21
defb 231,7,218,21
defb 231,74,218,61
defb 164,74,178,61
;;;FRAME #2 5 degrees
defb 162,8,229,6
defb 229,6,229,75
defb 229,75,162,73
defb 162,73,162,8
defb 220,20,180,21
defb 180,21,180,60
defb 180,60,220,61
defb 220,61,220,20
defb 162,8,180,21
defb 229,6,220,20
defb 229,75,220,61
defb 162,73,180,60
;;;FRAME #3 10 degrees
defb 161,9,226,5
defb 226,5,226,76
defb 226,76,161,72
defb 161,72,161,9
defb 222,20,182,21
defb 182,21,182,60
defb 182,60,222,61
defb 222,61,222,20
defb 161,9,182,21
defb 226,5,222,20
defb 226,76,222,61
defb 161,72,182,60
;;;FRAME #4 15 degrees
defb 160,10,223,4
defb 223,4,223,77
defb 223,77,160,71
defb 160,71,160,10
defb 224,19,184,21
defb 184,21,184,60
defb 184,60,224,62
defb 224,62,224,19
defb 160,10,184,21
defb 223,4,224,19
defb 223,77,224,62
defb 160,71,184,60
;;;FRAME #5 20 degrees
defb 160,11,219,4
defb 219,4,219,77
defb 219,77,160,70
defb 160,70,160,11
defb 225,19,186,22
defb 186,22,186,59
defb 186,59,225,62
defb 225,62,225,19
defb 160,11,186,22
defb 219,4,225,19
defb 219,77,225,62
defb 160,70,186,59
;;;FRAME #6 25 degrees
defb 160,12,216,3
defb 216,3,216,78
defb 216,78,160,69
defb 160,69,160,12
defb 227,18,188,22
defb 188,22,188,59
defb 188,59,227,63
defb 227,63,227,18
defb 160,12,188,22
defb 216,3,227,18
defb 216,78,227,63
defb 160,69,188,59
;;;FRAME #7 30 degrees
defb 160,13,211,3
defb 211,3,211,78
defb 211,78,160,68
defb 160,68,160,13
defb 229,18,191,22
defb 191,22,191,59
defb 191,59,229,63
defb 229,63,229,18
defb 160,13,191,22
defb 211,3,229,18
defb 211,78,229,63
defb 160,68,191,59
;;;FRAME #8 35 degrees
defb 160,14,207,2
defb 207,2,207,79
defb 207,79,160,67
defb 160,67,160,14
defb 230,17,193,22
defb 193,22,193,59
defb 193,59,230,64
defb 230,64,230,17
defb 160,14,193,22
defb 207,2,230,17
defb 207,79,230,64
defb 160,67,193,59
;;;FRAME #9 40 degrees
defb 161,15,202,2
defb 202,2,202,79
defb 202,79,161,66
defb 161,66,161,15
defb 232,16,195,22
defb 195,22,195,59
defb 195,59,232,65
defb 232,65,232,16
defb 161,15,195,22
defb 202,2,232,16
defb 202,79,232,65
defb 161,66,195,59
;;;FRAME #10 45 degrees
defb 162,16,198,2
defb 198,2,198,79
defb 198,79,162,66
defb 162,66,162,16
defb 233,16,198,22
defb 198,22,198,59
defb 198,59,233,66
defb 233,66,233,16
defb 162,16,198,22
defb 198,2,233,16
defb 198,79,233,66
defb 162,66,198,59
;;;FRAME #11 50 degrees
defb 163,16,193,2
defb 193,2,193,79
defb 193,79,163,65
defb 163,65,163,16
defb 234,15,200,22
defb 200,22,200,59
defb 200,59,234,66
defb 234,66,234,15
defb 163,16,200,22
defb 193,2,234,15
defb 193,79,234,66
defb 163,65,200,59
;;;FRAME #12 55 degrees
defb 165,17,188,2
defb 188,2,188,79
defb 188,79,165,64
defb 165,64,165,17
defb 235,14,202,22
defb 202,22,202,59
defb 202,59,235,67
defb 235,67,235,14
defb 165,17,202,22
defb 188,2,235,14
defb 188,79,235,67
defb 165,64,202,59
;;;FRAME #13 60 degrees
defb 166,18,184,3
defb 184,3,184,78
defb 184,78,166,63
defb 166,63,166,18
defb 235,13,204,22
defb 204,22,204,59
defb 204,59,235,68
defb 235,68,235,13
defb 166,18,204,22
defb 184,3,235,13
defb 184,78,235,68
defb 166,63,204,59
;;;FRAME #14 65 degrees
defb 168,18,179,3
defb 179,3,179,78
defb 179,78,168,63
defb 168,63,168,18
defb 235,12,207,22
defb 207,22,207,59
defb 207,59,235,69
defb 235,69,235,12
defb 168,18,207,22
defb 179,3,235,12
defb 179,78,235,69
defb 168,63,207,59
;;;FRAME #15 70 degrees
defb 170,19,176,4
defb 176,4,176,77
defb 176,77,170,62
defb 170,62,170,19
defb 235,11,209,22
defb 209,22,209,59
defb 209,59,235,70
defb 235,70,235,11
defb 170,19,209,22
defb 176,4,235,11
defb 176,77,235,70
defb 170,62,209,59
;;;FRAME #16 75 degrees
defb 171,19,172,4
defb 172,4,172,77
defb 172,77,171,62
defb 171,62,171,19
defb 235,10,211,21
defb 211,21,211,60
defb 211,60,235,71
defb 235,71,235,10
defb 171,19,211,21
defb 172,4,235,10
defb 172,77,235,71
defb 171,62,211,60
;;;FRAME #17 80 degrees
defb 173,20,169,5
defb 169,5,169,76
defb 169,76,173,61
defb 173,61,173,20
defb 234,9,213,21
defb 213,21,213,60
defb 213,60,234,72
defb 234,72,234,9
defb 173,20,213,21
defb 169,5,234,9
defb 169,76,234,72
defb 173,61,213,60
;;;FRAME #18 85 degrees
defb 175,20,166,6
defb 166,6,166,75
defb 166,75,175,61
defb 175,61,175,20
defb 233,8,215,21
defb 215,21,215,60
defb 215,60,233,73
defb 233,73,233,8
defb 175,20,215,21
defb 166,6,233,8
defb 166,75,233,73
defb 175,61,215,60
;;;Bytes = 648