User Tools

Site Tools


base:4x4_mode_and_circle_routine

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

base:4x4_mode_and_circle_routine [2015-04-17 04:30] (current)
Line 1: Line 1:
 +====== 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 4x4 tile has a nibble that matches its pattern.
 +
 +For example:
 +
 +  %xxxx0001 = 00 xxxx0110 = 01
 +              01    10
 +
 +It looks like this: {{:​base:​junkchar.png|}}
 +
 +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. ​
 +
 +Download the binary, source, and char data: {{:​base:​fourfour.zip|}}
 +
 +<​code>​
 +!to "​fourfour.prg",​cbm
 +
 +zp1 = $fb
 +zp2 = $fc
 +zx  = $fd
 +zy  = $fe
 +pnt = $fa
 +
 +;Circle variables are signed 16-bit values
 +
 +r   = $e0 ;Radius
 +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,
 + ;and the radius is larger ​
 + ;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
 + lda hitable,​x ;​address of row.
 + sta zp2
 + lda (zp1),​y ;​Get screen graphic
 + ora pnt ;mask in point.
 + 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
 + adc r
 + sta xd
 + lda xc+1
 + adc r+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
 + adc r
 + sta yd
 + lda yc+1
 + adc r+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.
 + bne toobig ;​Compare radius to
 + 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
 + adc xp
 + sta tx
 + lda tx+1
 + adc xp+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
 +radovfl clc ;​Radius overflow
 + 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
 + adc xp
 + sta xd
 + lda xc+1
 + adc xp+1
 + sta xd+1
 + sec
 + lda yc
 + sbc yp
 + sta yd
 + lda yc+1
 + sbc yp+1
 + sta yd+1
 + +PLOTCIRCLE
 + clc
 + lda xc
 + adc yp
 + sta xd
 + lda xc+1
 + adc yp+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
 + adc yp
 + sta yd
 + lda yc+1
 + adc yp+1
 + sta yd+1
 + +PLOTCIRCLE
 + sec
 + lda xc
 + sbc yp
 + sta xd
 + lda xc+1
 + sbc yp+1
 + sta xd+1
 + clc
 + lda yc
 + adc xp
 + sta yd
 + lda yc+1
 + adc xp+1
 + sta yd+1
 + +PLOTCIRCLE
 +bottomright
 + clc
 + bcs noplot
 + lda xp
 + adc xc
 + sta xd
 + lda xp+1
 + adc xc+1
 + sta xd+1
 + clc
 + lda yp
 + adc yc
 + sta yd
 + lda yp+1
 + adc yc+1
 + sta yd+1
 + +PLOTCIRCLE
 + clc
 + lda yp
 + adc xc
 + sta xd
 + lda yp+1
 + adc xc+1
 + sta xd+1
 + clc
 + lda xp
 + adc yc
 + sta yd
 + lda xp+1
 + adc yc+1
 + sta yd+1
 + +PLOTCIRCLE
 +noplot rts
 +</​code>​
  
base/4x4_mode_and_circle_routine.txt ยท Last modified: 2015-04-17 04:30 (external edit)