base:4x4_mode_and_circle_routine
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:4x4_mode_and_circle_routine [2015-04-17 04:30] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
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: {{: | ||
+ | |||
+ | 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' | ||
+ | |||
+ | 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/ | ||
+ | |||
+ | Download the binary, source, and char data: {{: | ||
+ | |||
+ | < | ||
+ | !to " | ||
+ | |||
+ | 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 ; | ||
+ | xp = $e6 ;X plot on circle edge | ||
+ | yp = $e8 ; | ||
+ | xd = $ea ; | ||
+ | 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 " | ||
+ | |||
+ | *=$c000 ; | ||
+ | |||
+ | |||
+ | INIT | ||
+ | lda $d018 ; | ||
+ | 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 | ||
+ | ; | ||
+ | |||
+ | PLOT lda #%00001000 | ||
+ | sta pnt | ||
+ | tya | ||
+ | lsr | ||
+ | bcc + | ||
+ | lsr pnt ;Point shifts right | ||
+ | + tay ;if division has a | ||
+ | txa ; | ||
+ | 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. | ||
+ | ;' | ||
+ | |||
+ | lda lotable, | ||
+ | sta zp1 ; | ||
+ | lda hitable, | ||
+ | sta zp2 | ||
+ | lda (zp1), | ||
+ | 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, | ||
+ | sta $0400+$ff+$ff+$ff, | ||
+ | lda #10 | ||
+ | sta $d800,x | ||
+ | sta $d800+$ff,x | ||
+ | sta $d800+$ff+$ff, | ||
+ | sta $d800+$ff+$ff+$ff, | ||
+ | inx | ||
+ | bne - | ||
+ | rts | ||
+ | |||
+ | lotable !byte $00, | ||
+ | !byte $18, | ||
+ | !byte $08, | ||
+ | !byte $20, | ||
+ | |||
+ | hitable !byte $04, | ||
+ | !byte $05, | ||
+ | !byte $06, | ||
+ | !byte $07, | ||
+ | |||
+ | ; | ||
+ | |||
+ | !macro PLOTCIRCLE { ;Plot a circle point | ||
+ | lda xd+1 ;Is xy in screen? | ||
+ | bne *+21 ;If no, branch to | ||
+ | lda yd+1 ; | ||
+ | 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< | ||
+ | |||
+ | |||
+ | 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 ; | ||
+ | ror tx | ||
+ | lda #0 | ||
+ | sta yp | ||
+ | sta yp+1 | ||
+ | |||
+ | ;jmp cloop ; | ||
+ | |||
+ | lda #$18 ;clc | ||
+ | - sta radovfl ; | ||
+ | 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 # | ||
+ | lda xc+1 | ||
+ | bmi drawr ;x<0 | ||
+ | bne drawl | ||
+ | lda xc | ||
+ | cmp # | ||
+ | bcs drawl | ||
+ | dey ;x in screen | ||
+ | bne yarc | ||
+ | drawr stx topleft | ||
+ | stx bottomleft ; | ||
+ | jmp yarc | ||
+ | drawl stx topright | ||
+ | stx topright | ||
+ | |||
+ | yarc lda yc+1 | ||
+ | bmi drawb ;y<0 | ||
+ | bne drawt | ||
+ | lda yc | ||
+ | cmp # | ||
+ | bcs drawl | ||
+ | dey ;y in screen | ||
+ | bne cloop | ||
+ | lda r+1 ; | ||
+ | bne toobig ; | ||
+ | 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 | ||
+ | ; | ||
+ | ;70 IF X<=Y THEN 100 | ||
+ | ;80 Y=Y+1: | ||
+ | ;90 IF TX<0 THEN X=X-1: | ||
+ | |||
+ | 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, | ||
+ | ;40 DRAW1, | ||
+ | ;50 DRAW1, | ||
+ | ;60 DRAW1, | ||
+ | |||
+ | |||
+ | noplot1 rts | ||
+ | |||
+ | plot8 | ||
+ | radovfl clc ; | ||
+ | bcs noplot1 | ||
+ | top clc ; | ||
+ | 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 ; | ||
+ | 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 | ||
+ | </ | ||
base/4x4_mode_and_circle_routine.txt · Last modified: 2015-04-17 04:30 by 127.0.0.1