ARTICLES
67 / 74 |
GAC Fast Line Fill
By Bruce ABBOTT (bruce.abbott@xtra.co.nz)
Information on cpcwiki
This patch speeds up GAC's area fill routine. The original code examined each pixel in the line to get the left and right edges of the area to be filled, then drew a line between them using the ROM function SCR HORIZONTAL.
My code fills in the line directly _while_ examining the pixels, resulting in a HUGE speed up! (up to 8x faster). Most pictures draw 3~5 times faster than before.
Fills one horizontal line with pattern (stops when it hits another color)
entry; HL = y, DE = x (coordinates to start filling from)
exit; HL = y, Carry Set (and no line drawn) if start pixel not paper color
2013-11-4 V1.0 Initial release, created with WinAPE 2.0 Alpha 18
2013-11-14 V1.1 Avoids filling top and bottom lines of picture frame. Repairs vertical picture frame lines at end of fill.
2013-11-15 V1.2 Constrained to picture area, no need to repair frame!
2013-11-16 V1.2b Reduced code size by 3 bytes.
ORG #2500 ; patch installs over original code at &2500
PUSH DE ; save x
PUSH HL ; save y
LD A,L
CP #46 ; abort if top of picture (y=70)
JR Z,abort
CP #C7 ; abort if bottom of picture (y=199)
JR Z,abort
CALL #BC1D ; SCR DOT POSITION -> addr=HL, numbits-1=B, mask=C
LD A,(#4029)
XOR (HL) ; color at x,y same as paper color?
AND C
JR Z,fill_line ; yes, fill the line
.abort:
SCF ; no, return with carry flag set = hit boundary
POP HL ; restore y
POP DE ; restore x
RET
.fill_line:
POP DE ; get y coord off stack
PUSH DE ; put y coord back on stack
LD A,(#4026) ; get fill pattern for odd lines
BIT 0,E ; is it an odd line?
JR NZ,odd
LD A,(#4027) ; no, get fill pattern for even lines
.odd:
LD D,A ; D = fill pattern
LD A,(#4029)
LD E,A ; E = paper color
PUSH HL ; save pixel address
PUSH BC ; save mask
.fill_left:
LD A,E ; A = paper color
.left_pixel:
XOR (HL) ; compare pixel color to paper color
AND C
JR NZ,done_left ; stop going left if hit edge of fill area
LD A,D ; A = fill pattern
XOR (HL)
AND C ; mask off other pixels
XOR (HL)
LD (HL),A ; set pixel to fill pattern color
RLC C ; rotate mask to select next pixel
JR NC,fill_left ; if not end of byte then do next pixel
LD A,E ; A = paper color
.left_byte:
DEC HL ; screen address - 1
CP (HL) ; test 4 pixels at once
JR NZ,left_pixel ; if not all paper color then test single pixels
LD (HL),D ; set byte to fill pattern
JR left_byte ; do next byte
.done_left:
POP BC ; back to start position (HL=address, C=mask)
POP HL
PUSH HL ; save pixel address
JR next_right ; start filling towards the right
.fill_right:
LD A,E ; A = paper color
.right_pixel:
XOR (HL) ; compare pixel color to paper color
AND C
JR NZ,repairframe ; stop going right if hit edge of fill area
LD A,D ; A = fill pattern
XOR (HL)
AND C ; mask off other pixels
XOR (HL)
LD (HL),A ; set pixel to fill pattern color
.next_right:
RRC C ; rotate mask to select next pixel
JR NC,fill_right ; if not end of byte then do next pixel
LD A,E ; A = paper color
.right_byte:
INC HL ; screen address + 1
CP (HL) ; test 4 pixels at once
JR NZ,right_pixel ; if not all paper color then test single pixels
LD (HL),D ; set byte to fill pattern
JR right_byte ; do next byte
.fill_end:
; ----------- don't redraw the picture frame after every fill! ------------
;
ORG #2592 ; patch installs over original code at &2592
.drawframe:
RET
.df_end:
;--- Repair left and right picture frame where fill may have touched it ---
;
ORG #25CB ; patch installs over original code at &25CB
.repairframe:
POP HL ; restore pixel address
POP DE ; restore y
POP BC ; restore x
SRL B
RR C
SRL B
RR C ; BC / 4 = byte position of pixel on line
LD A,C
SUB #07 ; - left frame byte position
LD C,A
SBC HL,BC ; HL = address of left frame byte
LD (HL),#10 ; set rightmost pixel in byte to frame color
LD C,#41
ADD HL,BC ; HL = address of right frame byte
LD (HL),#80 ; set leftmost pixel in byte to frame color
LD H,D
LD L,E ; HL = y
RET ; return with Carry Clear = line filled OK
.rp_end:
ORG #1E80 ; patch installs over original code at &1E80
.convert:
LD A,D
SRL A
LD A,E ; A = x/4
RRA
SRL A
SUB #07 ; -7 = number of bytes to left edge of picture
PUSH AF ; save numbytes
CALL #BC1D ; SCR DOT POSITION -> addr=HL, numbits-1=B, mask=C
POP AF
LD B,A ; b = number of bytes to left edge
RET
.con_end:
if #1e90-$ AND #8000
ORG too_much_code!
endif
ORG #2500 ; patch installs over original code at &2500
.fill:
PUSH HL ; save y
LD A,L
CP #46 ; abort if at bottom of picture (y=70)
JR Z,abort
CP #C7 ; abort if at top of picture (y=199)
JR Z,abort
PUSH HL ; save y
CALL convert ; convert (x,y) to scr addr, numbytes, mask
POP DE ; DE = y
LD A,(#4029)
XOR (HL) ; color at (x,y) same as paper color?
AND C
JR Z,fill_line ; yes, fill the line
.abort:
SCF ; no, return with carry flag set = hit boundary
POP HL ; restore y
RET
.fill_line:
BIT 0,E ; odd line?
LD DE,(#4026) ; D = even fill pattern, E = odd fill pattern
JR Z,even
LD D,E ; yes, D = odd fill pattern
.even: LD A,(#4029)
LD E,A ; E = paper color
PUSH HL ; save pixel address
PUSH BC ; save numbytes, mask
.fill_left:
LD A,E ; A = paper color
.left_pixel:
XOR (HL) ; compare pixel color to paper color
AND C
JR NZ,done_left ; stop going left if hit edge of fill area
LD A,D ; A = fill pattern
XOR (HL)
AND C ; mask off other pixels
XOR (HL)
LD (HL),A ; set pixel to fill pattern color
RLC C ; rotate mask to select next pixel
JR NC,fill_left ; if not end of byte then do next pixel
LD A,E ; A = paper color
JR byte_left
.left_byte:
DEC HL ; screen address - 1
CP (HL) ; test 4 pixels at once
JR NZ,left_pixel ; if not all paper color then test single pixels
LD (HL),D ; set byte to fill pattern
.byte_left:
DJNZ left_byte ; keep going until left edge reached
.done_left: ; back to start position
POP BC ; B=bytes to left edge, C=mask,
POP HL ; HL=address
LD A,#41
SUB B ; B = number of bytes to right edge of picture
LD B,A
JR next_right ; start filling towards the right
.fill_right:
LD A,E ; A = paper color
.right_pixel:
XOR (HL) ; compare pixel color to paper color
AND C
JR NZ,fill_done ; stop going right if hit edge of fill area
LD A,D ; A = fill pattern
XOR (HL)
AND C ; mask off other pixels
XOR (HL)
LD (HL),A ; set pixel to fill pattern color
.next_right:
RRC C ; rotate mask to select next pixel
JR NC,fill_right ; if not end of byte then do next pixel
LD A,E ; A = paper color
JR byte_right
.right_byte:
INC HL ; screen address + 1
CP (HL) ; test 4 pixels at once
JR NZ,right_pixel ; if not all paper color then test single pixels
LD (HL),D ; set byte to fill pattern
.byte_right:
DJNZ right_byte ; keep going until right edge reached
.fill_done:
POP HL ; restore y
AND A ; Carry clear = line filled
RET
.fill_end:
if #2564-$ AND #8000
ORG too_much_code!
endif
; ----------- don't redraw the picture frame after every fill! ------------
;
ORG #2592 ; patch installs over original code at &2592
.drawframe:
RET
.drawframe_end:
Article créé le : | Vendredi 15 Novembre 2013 à 22 h 23 |
Dernière mise à jour le : | Dimanche 17 Novembre 2013 à 15 h 01 |