## Meta

base:4x4_mode_and_circle_routine

# 4x4 mode and circle routine

By Malcontent.

This is a rather simple and fast way of painting blocky pixels. To use it you need to modify the character set so that each 4×4 tile has a nibble that matches its pattern.

For example:

```%xxxx0001 = 00	xxxx0110 = 01
01		   10	```

It looks like this:

A single point than can be bitshifted into position based on whether division of the co-ordinate leaves a carry. The point is then masked into the screen memory location with ORA. Starting with %00001000, LSR once to move the point to the right, and twice to move it down.

Tables speed up the conversion of x y co-ordinates to screen memory locations.

Much like the kernal plot, the registers are reversed. On entry have the x point in the y register and put the y point in the x register. There is no check for out of screen points. That shouldn't be hard to add.

On top of that I've added an implementation of Steve Judd's circle algorithm from C=Hacking #9. The plot routine alone uses few zeropage locations, so it could exit cleanly to BASIC, but the circle routine does not exit cleanly. It uses signed 16-bit integers for the center and the radius. It tries to be crafty in the way it decides what parts of the circle to draw. For smaller circles that don't need to be clipped, the algorithm can be further simplified/sped up. For BASIC compatibility, the variables need to be moved from the zeropage. Any optimizations to my weird clipping routine are welcome.

```!to "fourfour.prg",cbm

zp1 = \$fb
zp2 = \$fc
zx  = \$fd
zy  = \$fe
pnt = \$fa

;Circle variables are signed 16-bit values

xc  = \$e2	;X circle center
yc  = \$e4	;Y  "   "
xp  = \$e6	;X plot on circle edge
yp  = \$e8	;Y  "   "
xd  = \$ea	;Transformed point to draw
yd  = \$ec	;
tx  = \$ee
tmp = \$f0	;Single byte

screendia = 93	;If the center of the
;circle is on the screen,
;than the screen diagonal,
;then the circle does not
;need to be drawn.

blank = 96		;Offset to chars
;Also blank char

*=\$2800
chars   !bin "junkchars.b"

*=\$c000		;sys49152

INIT
lda \$d018	;Point vic to chars
eor #\$e
sta \$d018
jsr CLEARSCREEN

lda #20
sta xc
sta yc
lda #0
sta xc+1
sta r+1
sta yc+1
lda #5
sta r

-	inc \$d020
jsr CIRCLE
dec \$d020
inc xc
inc r
bne -
rts

;This is the main plot routine, a straight
;shot to here will plot a 4x4 pixel to the
;co-ordinates held in the x and y registers

PLOT 	lda #%00001000
sta pnt
tya
lsr
bcc +
lsr pnt		;Point shifts right
+	tay		;if division has a
txa		;remainder
lsr
bcc +
lsr pnt		;Point moves down
lsr pnt		;on remainder
+	tax

;x and y registers now hold 0-24,0-39
;so long as valid numbers went in.
;'pnt' contains the mask for the char.

lda lotable,x  	;Table holds the
sta zp1		;leftmost screen
sta zp2
lda (zp1),y	;Get screen graphic
sta (zp1),y
rts

CLEARSCREEN
ldx #0
-	lda #blank
sta \$0400,x
sta \$0400+\$ff,x
sta \$0400+\$ff+\$ff,x
sta \$0400+\$ff+\$ff+\$ff,x
lda #10
sta \$d800,x
sta \$d800+\$ff,x
sta \$d800+\$ff+\$ff,x
sta \$d800+\$ff+\$ff+\$ff,x
inx
bne -
rts

lotable	!byte \$00,\$28,\$50,\$78,\$a0,\$c8,\$f0
!byte \$18,\$40,\$68,\$90,\$b8,\$e0
!byte \$08,\$30,\$58,\$80,\$a8,\$d0,\$f8
!byte \$20,\$48,\$70,\$98,\$c0

hitable	!byte \$04,\$04,\$04,\$04,\$04,\$04,\$04
!byte \$05,\$05,\$05,\$05,\$05,\$05
!byte \$06,\$06,\$06,\$06,\$06,\$06,\$06
!byte \$07,\$07,\$07,\$07,\$07

;-----------------------------------

!macro PLOTCIRCLE {	;Plot a circle point
lda xd+1	;Is xy in screen?
bne *+21	;If no, branch to
lda yd+1	;instruction after
bne *+17	;the macro.
ldx yd
cpx #50
bcs *+11
ldy xd
cpy #80
bcs *+5
jsr PLOT	;Point is plotable
}

;Reject drawing the circle if the bounding
;box does not cross the screen.
;if x<0 and if x+r>0 then check y
;if x>0	and if x-r<screenwidth check y

nocir	rts

CIRCLE	lda xc+1
bmi negxcen
lda xc
sec
sbc r
sta xd
lda xc+1
sbc r+1
bmi checky
bne nocir
lda xd
cmp #80
bcc checky
rts
negxcen	lda xc
clc
sta xd
lda xc+1
bmi nocir
checky	lda yc+1
bmi negycen
lda yc
sec
sbc r
sta yd
lda yc+1
sbc r+1
bmi bbok
bne nocir
lda yd
cmp #50
bcc bbok
rts
negycen	lda yc
clc
sta yd
lda yc+1
bmi nocir

bbok	lda r		;Init radius and
sta xp		;set first point
sta tx		;to draw.
lda r+1
sta xp+1
lsr
sta tx+1	;tx=r/2
ror tx
lda #0
sta yp
sta yp+1

;jmp cloop	;***************

lda #\$18	;clc
-	sta radovfl	;Clear draw skips
sta top
sta topleft
sta topright
sta bottom
sta bottomleft
sta bottomright

;Some comparisons here modify the looping
;code that draws. Saves us from having to
;do the comparisons within the loop.

ldx #\$38	;sec
ldy #\$02	;decremented flag
lda xc+1
bmi drawr    	;x<0
bne drawl   	;x>\$ff
lda xc
cmp #80		;Screen width
bcs drawl   	;x>80
dey		;x in screen
bne yarc
drawr   stx topleft
stx bottomleft	;skip these
jmp yarc
drawl	stx topright
stx topright

yarc	lda yc+1
bmi drawb    	;y<0
bne drawt   	;y>\$ff
lda yc
cmp #50		;Screen height
bcs drawl   	;y>50
dey		;y in screen
bne cloop
lda r+1		;Center in screen.
lda r		;screen diagonal.
cmp #screendia
bcc cloop
toobig	rts
drawb   stx top    	;skip this
jmp cloop
drawt	stx bottom

;All set up. Now the heart of the circle
;calculations. From C=Hacking.
;70 IF X<=Y THEN 100
;80 Y=Y+1:TX=TX-Y
;90 IF TX<0 THEN X=X-1:TX=TX+X

cloop	jsr plot8
inc yp
bne +
inc yp+1
+	sec
lda tx
sbc yp
sta tx
lda tx+1
sbc yp+1
sta tx+1
bcs cloop
dec xp
bne +
dec xp+1
+	lda tx
sta tx
lda tx+1
sta tx+1
sec
lda xp
sbc yp
sta tmp
lda xp+1
sbc yp+1
ora tmp
bcs cloop
jsr plot8	;Get last bit
rts

;plot8 is modified by the circle init
;routine to avoid drawing unnecessary
;parts of the circle. It pokes SECs over
;CLCs to branch or fall through to the
;right transformations
;
;30 DRAW1,X+XO,Y+YO:DRAW1,Y+XO,X+YO
;40 DRAW1,XO-X,YO+Y:DRAW1,XO-Y,YO+X
;50 DRAW1,XO-X,YO-Y:DRAW1,XO-Y,YO-X
;60 DRAW1,XO+X,YO-Y:DRAW1,XO+Y,YO-X

noplot1	rts

plot8
bcs noplot1
top	clc		;clc draw top
bcc topleft
jmp bottom
topleft	clc
bcs topright
sec
lda xc
sbc xp
sta xd
lda xc+1
sbc xp+1
sta xd+1
sec
lda yc
sbc yp
sta yd
lda yc+1
sbc yp+1
sta yd+1
+PLOTCIRCLE
sec
lda xc
sbc yp
sta xd
lda xc+1
sbc yp+1
sta xd+1
sec
lda yc
sbc xp
sta yd
lda yc+1
sbc xp+1
sta yd+1
+PLOTCIRCLE
topright
clc
bcs bottom
lda xc
sta xd
lda xc+1
sta xd+1
sec
lda yc
sbc yp
sta yd
lda yc+1
sbc yp+1
sta yd+1
+PLOTCIRCLE
clc
lda xc
sta xd
lda xc+1
sta xd+1
sec
lda yc
sbc xp
sta yd
lda yc+1
sbc xp+1
sta yd+1
+PLOTCIRCLE
bottom 	clc		;bottom half
bcc bottomleft
rts
bottomleft
clc
bcs bottomright
sec
lda xc
sbc xp
sta xd
lda xc+1
sbc xp+1
sta xd+1
clc
lda yc
sta yd
lda yc+1
sta yd+1
+PLOTCIRCLE
sec
lda xc
sbc yp
sta xd
lda xc+1
sbc yp+1
sta xd+1
clc
lda yc
sta yd
lda yc+1
sta yd+1
+PLOTCIRCLE
bottomright
clc
bcs noplot
lda xp
sta xd
lda xp+1
sta xd+1
clc
lda yp
sta yd
lda yp+1
sta yd+1
+PLOTCIRCLE
clc
lda yp
sta xd
lda yp+1