Z80 Routines:Graphic:LineDraw
From WikiTI
Contents
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