c64-livecoding/wip-hugo/routines/circle/circle.s

291 lines
7.3 KiB
ArmAsm

;;; -*- Mode: asm; indent-tabs-mode: t; tab-width: 8 -*-
;;We have named the parts of the circle as such.
;; |
;; qbb (7) | qab (8)
;; |
;; qba (2) | qaa (1)
;;---------------X-----------------> X
;; qca (4) | qda (3)
;; |
;; qcb (5) | qdb (6)
;; |
;; v Y
;; The q stands for quarter, whe have 4 quarter, and each quarter is split into 2 (a and b)
;; We use jerko's method https://schwarzers.com/algorithms/
;;
;; There exist 4 uniqe half-quarter-pairs such that they share the same byte_to_paint
; and another 4 uniqe ... such that they shair the same Y value.
;; The Y value is the mod 8 rest of the position of the byte to paint.
;; We paint one pixel in each half quarter area for each loop.
.proc circle; user-procedure :clobbers (A X Y) :clobbers-arguments 3
.include "circle.inc"
;; Because loop is so big, We need to save positions in pointer
LDA #<while_x_bigger_then_y
STA jmp_location_pointer
LDA #>while_x_bigger_then_y
STA jmp_location_pointer + 1
LDA #<endif
STA jmp_location_pointer_two
LDA #>endif
STA jmp_location_pointer_two + 1
;; X_math = radius (share the same address)
;;Y_math =0
LDA #$00
STA Y_math
;; t1 = radius >> 4
LDA radius
LSR
LSR
LSR
LSR
STA t1
draw_upper_px_in_circle:
;; move uppwards
SEC
LDA Y_pos
STA temp_
SBC radius
STA Y_pos
JSR pixel_draw
;; initial pixel for 2 half-quarter arias
LDA btp_mem_pos
STA btp_mem_pos_qbb
STA btp_mem_pos_qab
LDA btp_mem_pos + 1
STA btp_mem_pos_qbb + 1
STA btp_mem_pos_qab + 1
;; initial Y value for one half-quarter aria
STY Y_qbb
;; reset changes we have made to circle Y_pos
LDA temp_
STA Y_pos
draw_left_px_in_circle: ;similar as above
SEC
LDA X_pos
STA temp__
SBC radius
STA X_pos
JSR pixel_draw
LDA btp_mem_pos
STA btp_mem_pos_qca
STA btp_mem_pos_qba
LDA btp_mem_pos + 1
STA btp_mem_pos_qca + 1
STA btp_mem_pos_qba + 1
LDA byte_to_paint
STA byte_to_paint_qca
LDA temp__
STA X_pos
draw_lower_px_in_circle: ;similar as above
;; C=0 becuase pixel draw!
LDA Y_pos
ADC radius
STA Y_pos
JSR pixel_draw
LDA btp_mem_pos
STA btp_mem_pos_qdb
STA btp_mem_pos_qcb
LDA btp_mem_pos + 1
STA btp_mem_pos_qdb + 1
STA btp_mem_pos_qcb + 1
LDA byte_to_paint
STA byte_to_paint_qdb
STA byte_to_paint_qcb
STY Y_qdb
STY Y_qaa
LDA temp_
STA Y_pos
draw_right_px_in_circle:; similar as above
;; C =0 becuse pixel_draw
LDA X_pos
ADC radius
STA X_pos
JSR pixel_draw
LDA btp_mem_pos
STA btp_mem_pos_qda
LDA btp_mem_pos + 1
STA btp_mem_pos_qda + 1
STY Y_qda
STY Y_qaa
LDX #$08 ; X=8 always expected inside the loop
SEC
while_x_bigger_then_y: ; C=1 here because above and branching logic
draw_pixels:
draw_qaa:
LDY Y_qaa
LDA byte_to_paint ;A byte containing a single 1. Coresponds to 2^rest(X_pos/8)
ORA (btp_mem_pos), Y; Y = rest(Y_pos/8)
STA (btp_mem_pos), Y
draw_qba:
LDA byte_to_paint_qca
ORA (btp_mem_pos_qba), Y
STA (btp_mem_pos_qba), Y
draw_qda:
LDY Y_qda
LDA byte_to_paint
ORA (btp_mem_pos_qda), Y
STA (btp_mem_pos_qda), Y
draw_qca:
LDA byte_to_paint_qca
ORA (btp_mem_pos_qca), Y
STA (btp_mem_pos_qca), Y
draw_qcb:
LDY Y_qdb
LDA byte_to_paint_qcb
ORA (btp_mem_pos_qcb), Y
STA (btp_mem_pos_qcb), Y
draw_qdb:
LDA byte_to_paint_qdb
ORA (btp_mem_pos_qdb), Y
STA (btp_mem_pos_qdb), Y
draw_qbb:
LDY Y_qbb
LDA byte_to_paint_qcb
ORA (btp_mem_pos_qbb), Y
STA (btp_mem_pos_qbb), Y
draw_qab:
LDA byte_to_paint_qdb
ORA (btp_mem_pos_qab), Y
STA (btp_mem_pos_qab), Y
;; Y_math and X_math is the X and Y in the eye of the algorithm. Thsese are calculated seperatly from the pixel cordinates,
;; but are modified at the same time. This is becsuse the pixel cordinate system is complex (see pixel draw)
LDY #$07 ;; Y is expected to be 7 from this point on in the loop
change_Y:
INC Y_math ; y++
qaa_y:
DEC Y_qaa
BPL qaa_y_end
qaa_y_underflow:
;; Switch to chunk bellow
; So we subtract #$0140
;; Note that C =1, read from while_x_bigger_then_y label.
Sub_16 btp_mem_pos, btp_mem_pos + 1, #$40, #$01, ! ;-320
Sub_16 btp_mem_pos_qba, btp_mem_pos_qba + 1, #$40, #$01,!
STY Y_qaa ; Y_qaa =$07
qaa_y_end:
qda_y:
INC Y_qda
CPX Y_qda
BNE qda_y_end
qda_y_overflow:
Add_16 btp_mem_pos_qda, btp_mem_pos_qda + 1, #$3f, #$01,! ;+319 + C
Add_16 btp_mem_pos_qca, btp_mem_pos_qca + 1, #$40, #$01,! ;+320
LDA #$00
STA Y_qda
qda_y_end:
qdb_x:
LSR byte_to_paint_qdb
BCC qdb_x_end
qdb_x_overflow:
ROR byte_to_paint_qdb
Add_16 btp_mem_pos_qdb, btp_mem_pos_qdb + 1, #$08, #$00, !
Add_16 btp_mem_pos_qab, btp_mem_pos_qab + 1, #$08, #$00, !
qdb_x_end:
qcb_x:
ASL byte_to_paint_qcb
BCC qcb_x_end
qcb_x_overflow:
INC byte_to_paint_qcb
Sub_16 btp_mem_pos_qcb, btp_mem_pos_qcb + 1, #$08, #$00,!
Sub_16 btp_mem_pos_qbb, btp_mem_pos_qbb + 1, #$08, #$00,!
CLC
qcb_x_end:
;;t1 += y
;; C =0 becuse CLC above or branching logic
LDA t1
ADC Y_math
STA t1
;; t2 = t1 - x
SEC
SBC X_math
STA t2
;; if t2 < 0 then skip to endif
;; we can skipp CMP #$00 because SBC above do the same
BPL if
JMP (jmp_location_pointer_two) ; jump to endif
if:
change_x:
DEC X_math
STA t1 ; t1 = t2
qaa_x:
ASL byte_to_paint
BCC qaa_x_end
qaa_x_overflow:
Sub_16 btp_mem_pos_qaa, btp_mem_pos_qaa + 1, #$08, #$00, ! ;+8
Sub_16 btp_mem_pos_qda, btp_mem_pos_qda + 1, #$08, #$00, ! ;+8
;; Restores byte to paint
INC byte_to_paint
qaa_x_end:
qca_x:
LSR byte_to_paint_qca
BCC qca_x_end
qca_x_overflow:
ROR byte_to_paint_qca
Add_16 btp_mem_pos_qca, btp_mem_pos_qca + 1, #$08, #$00, !
Add_16 btp_mem_pos_qba, btp_mem_pos_qba + 1, #$08, #$00, !
qca_x_end:
qdb_y:
DEC Y_qdb
BPL qdb_y_end
qdb_overflow:
Sub_16 btp_mem_pos_qdb, btp_mem_pos_qdb + 1, #$3f, #$01, ! ;+320
Sub_16 btp_mem_pos_qcb, btp_mem_pos_qcb + 1, #$40, #$01, ! ;+320
STY Y_qdb
qdb_y_end:
qbb_y:
INC Y_qbb
CPX Y_qbb ; Is Y_qbb ==8 ?
BNE qbb_y_end
qbb_y_overflow:
Add_16 btp_mem_pos_qbb, btp_mem_pos_qbb + 1, #$3f, #$01, ! ;+320
Add_16 btp_mem_pos_qab, btp_mem_pos_qab + 1, #$40, #$01, ! ;+320
LDA #$00
STA Y_qbb
qbb_y_end:
endif:
;; repeat if X > Y
LDA X_math
CMP Y_math
BCC end
JMP (jmp_location_pointer)
end:
RTS
.endproc