START: LDA #$0000
TAZP ;SET ZEROPAGE @$0000_0000
LDA #$0001
TASP ;SET STACKPAGE @$0001_0000
LDWi $0000 ; LDW #$0000 - SET BLACK SCREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBa SCRCOL ; STB SCRCOL
JSR CLRSCR
LDWi $0005 ; LDW #$0005 - SET PIXEL COLOR GREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBa PXLCOL ; STB PXLCOL
LDA #$0140 ;X CENTER OF 640x480 SCREEN
STA SCRLO
LDA #$80F0 ;Y CENTER OF 640x480 SCREEN
STA SCRHI
LDY #$0000
LDX #$0010 ;16 PIXELS WIDE AROUND THE ORIGIN
STBiy SCRLO ; STB (SCRLO),Y
END JMP END
CLRSCR LDA #$0000 ;$8000_0000 START OF VIDEO MEMORY
STA SCRLO ;X VALUE
LDA #$8000
STA SCRHI ;Y VALUE
LDX #$01E0
LDA SCRCOL
AB LDY #$0280 ;$81DF_027F END OF VIDEO MEMORY
AA STA (SCRLO),Y
DEY
BNE AA
STA (SCRLO),Y ;GET THAT LAST PIXEL!
INC SCRHI
DEX
BNE AB
RTS
Ugh, not so easy to convert 6502 programs to 65Org16!
I successfully converted Lee's Square routine made for the 6502.
But I have a headache from trying to convert his SquareRoot routine.
EDIT: Ohhh, I found a fast routine here I'll try to convert! It works in MK's assembler/debugger, but there is no remainder, so testing sqrt(13)=3.6 = 3. Not even rounded off.
Yes I'm going for circles, but I need some code now! I can't afford weeks of figuring that stuff out. I never learned C.
I already have the Square routine, all I need is the SQRT and I'll have something I hope.
Maybe I will have to take some time converting Bresenham line algorithm to assembly. After these 2 algorithms, circle and line, the sky is the limit.
I just now realized (even after I was celebrating! ) I had to reset the origin after plotting each and every pixel! WOOOO!
EDIT: It's still not 100% because I was expecting a 1/2 circle on the right side only, but I may learn from the mistake!
START: LDA #$0000
TAZP ;SET ZEROPAGE @$0000_0000
LDA #$0001
TASP ;SET STACKPAGE @$0001_0000
LDWi $0000 ; LDW #$0000 - SET BLACK SCREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBzp SCRCOL ; STB SCRCOL
JSR CLRSCR
LDWi $0005 ; LDW #$0005 - SET PIXEL COLOR GREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBzp PXLCOL ; B ACCUMULATOR, PIXELCOLOR
LDA #$0000
STA Numberh
CLC
LDWi $0000 ; LDW #$0000
AC LDA #$0140 ; X CENTER OF 640x480 SCREEN
STA SCRLO
LDA #$80F0 ; Y CENTER OF 640x480 SCREEN
STA SCRHI ; START @ORIGIN
STWzp Number ; This 'Number' is actually X
JSR Square ; Now square it!
LDA #$E100 ; Radius=$F0, R^2=$E100
SBC Sqr ; Sqr=Number^2
STA Numberl ; This Numberl IS (R^2-X^2)
JSR SqRoot ; THIS ROUTINE WILL RETURN Root=SQRT(Numberl)
TWY
LDA SCRHI ;A ACCUMULATOR, Y COORDINATE
SBCAopCzp Root ;C ACCUMULATOR, Y MATH
STCzp SCRHI
STBiy SCRLO ;PLOT 1st Quadrant
ADCAopCzp Root
STCzp SCRHI
STBiy SCRLO ;PLOT 2nd Quadrant
INW
CPWi $00EF ; CPW #$00EF
BNE AC
END JMP END
EDIT: Tightened up the assembly code, same result except for the center pixel.
I was thinking Mandlebrot that Bruce had made for the 65816 and adapt it to 65Org16 (I thought he had originally made it for the 65Org16, guess I was wrong).
It was written to be easily ported to the 65org16, though. Except the for IIgs-specific code, like the ReadAsciiTime toolbox call, there are no 65C02 or later opcodes, like PHX, nor 65C02 or later addressing modes, like (stack,S),Y. So all that should be necessary is to discard the IIgs code and add your own OUTPUT, PLOT, etc. routines. I haven't tried actually porting it to the 65org16, but that's the intent.
GARTHWILSON wrote:
and there's Samuel Falvo's blitter article at http://6502org.wikidot.com/blitter-theory-part-1 (although it looks like a few equations need fixing in order to show up at all. I'll contact him.)
Garth! It's a wiki, fer cryin' out loud. You can make fixes yourself as you spot them. There's online reference material and everything. For info on \left and \right in LaTeX (used for the equations), see section 6 (p.13) here:
;*************************************************************************
; Draw a circle using Bresenham's circle algorithm
;
; 65C02 code written by Daryl Rictor
;*************************************************************************
; ZP variables
; ZP base address of data area
ZPBase = $00
XC = $00 + ZPBase ; Center Point
YC = $02 + ZPBase ;
R = $04 + ZPBase ; radius (1 byte)
XP = $06 + ZPBase ; plot point
YP = $08 + ZPBase ;
X1 = $0a + ZPBase ; x,y intermediate
Y1 = $0c + ZPBase ;
FF = $0e + ZPBase ; difference
FX = $10 + ZPBase ; diff x
FY = $12 + ZPBase ; diff y
; ------------------------------------------------------------------------
; SETPIXELCLIP: Test pixel @ XP,YP and plot if on screen
SETPIXELCLIP
; insert user code here
rts
; ------------------------------------------------------------------------
; CIRCLE: Draw a circle around the center XC/YC with radius in R.
;
; Must set an error code: NO
;
CIRCLE
lda R ; get Radius
bne _C1
lda XC ; if R=0, plot center point and exit
sta XP ; move center point to plot point var
lda XC+1
sta XP+1
lda YC
sta YP
lda YC+1
sta YP+1
jmp SETPIXELCLIP ; Plot as a point and exit
; int y = radius;
_C1 lda R ; 8 bit radius - can be expanded to 16 bit
sta Y1
stz Y1+1
; int x = 0;
stz X1
stz X1+1
; int f = 1 - radius; ; if using 16 bit radius, this code section
sec ; will need modifications
lda #$01
sbc R
sta FF
stz FF+1
bcs _C2
dec FF+1
; int ddF_x = 1;
_C2 lda #$01
sta FX
stz FX+1
; int ddF_y = -2 * radius; ; if using 16 bit radius, this code section
stz FY+1 ; will need modifications also
lda R
asl ; *2
sta FY
rol FY+1
lda FY
EOR #$FF
sta FY
lda FY+1
EOR #$FF
sta FY+1
inc FY
bne _C3
inc FY+1
; tgi_setpixel(xC, yC + y);
_C3 lda XC
sta XP
lda XC+1
sta XP+1
clc
lda YC
adc Y1
sta YP
lda YC+1
adc Y1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC, yC - y);
sec
lda YC
sbc Y1
sta YP
lda YC+1
sbc Y1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC + y, yC);
clc
lda XC
adc Y1
sta XP
lda XC+1
adc Y1+1
sta XP+1
lda YC
sta YP
lda YC+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC - y, yC);
sec
lda XC
sbc Y1
sta XP
lda XC+1
sbc Y1+1
sta XP+1
jsr SETPIXELCLIP
_CLOOP
; while (x < y) { ; calculate next plot step
sec
lda X1
sbc Y1
lda X1+1
sbc Y1+1
bcc _C4 ; x<y
rts
_C4 lda FF+1
bmi _C6
lda Y1
bne _C5
dec Y1+1
_C5 dec Y1
clc
lda FY
adc #$02
sta FY
tax
lda FY+1
adc #$00
sta FY+1
tay
clc
txa
adc FF
sta FF
tya
ADC FF+1
sta FF+1
_C6 inc X1
bne _C7
inc X1+1
_C7 clc
lda FX
adc #$02
sta FX
tax
lda FX+1
adc #$00
sta FX+1
tay
clc
txa
adc FF
sta FF
tya
ADC FF+1
sta FF+1 ; computations done - now plot 8 Octants
; tgi_setpixel(xC + x, yC + y);
clc
lda XC
adc X1
sta XP
pha
lda XC+1
adc X1+1
sta XP+1
pha
clc
lda YC
adc Y1
sta YP
lda YC+1
adc Y1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC - x, yC + y);
sec
lda XC
sbc X1
sta XP
lda XC+1
sbc X1+1
sta XP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC - x, yC - y);
sec
lda YC
sbc Y1
sta YP
lda YC+1
sbc Y1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC + x, yC - y);
pla
sta XP+1
pla
sta XP
jsr SETPIXELCLIP
; tgi_setpixel(xC + y, yC + x);
clc
lda XC
adc Y1
sta XP
pha
lda XC+1
adc Y1+1
sta XP+1
pha
clc
lda YC
adc X1
sta YP
lda YC+1
adc X1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC - y, yC + x);
sec
lda XC
sbc Y1
sta XP
lda XC+1
sbc Y1+1
sta XP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC - y, yC - x);
sec
lda YC
sbc X1
sta YP
lda YC+1
sbc X1+1
sta YP+1
jsr SETPIXELCLIP
; tgi_setpixel(xC + x, yC - y);
pla
sta XP+1
pla
sta XP
jsr SETPIXELCLIP
jmp _CLOOP
By the way, another technique to draw a circle is to draw a polygon instead using straight line segments from one point to the next. The location of the points are x=r*cos(phi) and y=r*sin(phi), but you can replace the sin() by a lookup table. This method is simple, reasonably fast (if you use the table), and can be easily modified to draw partial circles.
I reckon tables would be much faster, but looking at Daryl's take on the Bresenham algorithm I don't see any loops. That has got to be fast too, probably faster than what I'm doing now.
Is there another advantage besides speed for your idea?