Z80 Routines:Graphic:LineDraw

From WikiTI
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
 

Comments

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