Z80 Routines:Graphic:LineDraw

From WikiTI
Revision as of 05:52, 16 May 2010 by Galandros (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


Code

These routines are the best line draws routines around for z80.

Small (and fast for its size)

; Small and quite fast
; by Patai Gergely, thanks
DrawLineCompact		; This routine draws an unclipped line on an IX-pointed screen from (d,e) to (h,l)
 ld a,h			; Calculating delta X and swapping points if negative
 sub d			; (Lines are always drawn from left to right)
 jp nc,DL_okaydx
 ex de,hl
 neg
DL_okaydx:
 push af		; Saving DX (it will be popped into DE below)
 ld b,0			; Calculating the position of the first pixel to be drawn
 ld c,d			; IX+=D/8+E*12 (actually E*4+E*4+E*4)
 srl c
 srl c
 srl c
 add ix,bc
 ld c,e
 sla c
 sla c
 add ix,bc
 add ix,bc
 add ix,bc
 ld a,d			; Calculating the starting pixel mask
 ld c,$80
 and 7
 jp z,DL_okaymask
DL_calcmask:
 srl c
 dec a
 jp nz,DL_calcmask
DL_okaymask:
 ld a,l			; Calculating delta Y and negating the Y increment if necessary
 sub e			; This is the last instruction for which we need the original data
 ld hl,12
 jp nc,DL_okaydy
 ld hl,-12
 neg
DL_okaydy:
 pop de			; Recalling DX
 ld e,a			; D=DX, E=DY
 cp d
 jp c,DL_horizontal	; Line is rather horizontal than vertical
 ld (DL_VLinc+1),hl	; Modifying y increment
 push ix		; Loading IX to HL for speed; we don't need the old value of HL any more
 pop hl
 ld b,e			; Pixel counter
 inc b
 srl a			; Setting up gradient counter (A=E/2)
 ld (DL_HLinc+1),sp	; Backing up SP to a safe place
 di			; Interrupts are undesirable when we play around with SP :)
DL_VLinc:
 ld sp,0		; This value is replaced by +/- 12
DL_Vloop:
 ex af,af'		; Saving A to alternative register
 ld a,(hl)
 or c			; Writing pixel to current position
 ld (hl),a
 ex af,af'		; Recalling A (faster than push-pop, and there's no need for SP)
 add hl,sp
 sub d			; Handling gradient
 jp nc,DL_VnoSideStep
 rrc c			; Rotating mask
 jp nc,DL_VnoByte	; Handling byte boundary
 inc hl
DL_VnoByte:
 add a,e
DL_VnoSideStep:
 djnz DL_Vloop
 ld sp,(DL_HLinc+1)
 ret
DL_horizontal:
 ld (DL_HLinc+1),hl	; Modifying y increment
 push ix		; Loading IX to HL for speed; we don't need the old value of HL any more
 pop hl
 ld b,d			; Pixel counter
 inc b
 ld a,d			; Setting up gradient counter
 srl a
 ld (DL_VLinc+1),sp	; Backing up SP to a safe place
 di			; Interrupts again...
DL_HLinc:
 ld sp,0		; This value is replaced by +/- 12
DL_Hloop:
 ex af,af'		; Saving A to alternative register
 ld a,(hl)
 or c			; Writing pixel to current position
 ld (hl),a
 ex af,af'		; Recalling A
 rrc c			; Rotating mask
 jp nc,DL_HnoByte	; Handling byte boundary
 inc hl
DL_HnoByte:
 sub e			; Handling gradient
 jp nc,DL_HnoSideStep
 add hl,sp
 add a,d
DL_HnoSideStep:
 djnz DL_Hloop
 ld sp,(DL_VLinc+1)
 ret
 

Fast Version

Fast line routine, only sets pixels
(d,e),(h,l) = (x1,y1),(x2,y2)
NO clipping
James Montelongo

FastLine: ld a,h cp d jp nc,noswapx ex de,hl noswapx:

ld a,h sub d jp nc,posx neg posx: ld b,a ld a,l sub e jp nc,posy neg posY: ld c,a ld a,l ld hl,-12 cp e jp c,lineup ld hl,12 lineup: ld ix,xbit ld a,b cp c jp nc,xline ld b,c ld c,a ld ix,ybit xline: push hl ld a,d ld d,0 ld h,d sla e sla e ld l,e add hl,de add hl,de ld e,a and %00000111 srl e srl e srl e add hl,de ld de,gbuf add hl,de add a,a ld e,a ld d,0 add ix,de ld e,(ix) ld d,(ix+1) push hl pop ix ex de,hl pop de push hl ld h,b ld l,c ld a,h srl a inc b ret

Xbit:

.dw drawX0,drawX1,drawX2,drawX3
.dw drawX4,drawX5,drawX6,drawX7

Ybit:

.dw drawY0,drawY1,drawY2,drawY3
.dw drawY4,drawY5,drawY6,drawY7

DrawX0: set 7,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX1 ret DrawX1: set 6,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX2 ret DrawX2: set 5,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX3 ret DrawX3: set 4,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX4 ret DrawX4: set 3,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX5 ret DrawX5: set 2,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX6 ret DrawX6: set 1,(ix) add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX7 ret DrawX7: set 0,(ix) inc ix add a,c cp h jp c,$+3+2+1 add ix,de sub h djnz DrawX0 ret

DrawY0_: inc ix sub h dec b ret z DrawY0: set 7,(ix) add ix,de add a,l cp h jp nc,DrawY1_ djnz DrawY0 ret DrawY1_: sub h dec b ret z DrawY1: set 6,(ix) add ix,de add a,l cp h jp nc,DrawY2_ djnz DrawY1 ret DrawY2_: sub h dec b ret z DrawY2: set 5,(ix) add ix,de add a,l cp h jp nc,DrawY3_ djnz DrawY2 ret DrawY3_: sub h dec b ret z DrawY3: set 4,(ix) add ix,de add a,l cp h jp nc,DrawY4_ djnz DrawY3 ret DrawY4_: sub h dec b ret z DrawY4: set 3,(ix) add ix,de add a,l cp h jp nc,DrawY5_ djnz DrawY4 ret DrawY5_: sub h dec b ret z DrawY5: set 2,(ix) add ix,de add a,l cp h jp nc,DrawY6_ djnz DrawY5 ret DrawY6_: sub h dec b ret z DrawY6: set 1,(ix) add ix,de add a,l cp h jp nc,DrawY7_ djnz DrawY6 ret DrawY7_: sub h dec b ret z DrawY7: set 0,(ix) add ix,de add a,l cp h jp nc,DrawY0_ djnz DrawY7 ret

Special case of vertical lines

Special case of horizontal lines

Examples

For the compact version.

 ld hl,plotsscreen
 call ClearScreen
 ld de,$0000		; Hint: top left corner is at 0,0 and the bottom right at 95,63
 ld hl,$1008
 ld ix,plotsscreen
 call DrawLineCompact
 ld hl,SAVESSCREEN
 call ifastcopy
 call _getkey
 ret
 </wiki>

== Comments ==
There are benchmarks of some of this routines here: http://www.junemann.nl/maxcoderz/viewtopic.php?f=5&t=1940&start=15