;;; -*- 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 + 1 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,! qcb_x_end: ;;t1 += y CLC 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) if: change_x: DEC X_math LDA t2 STA t1 ; t1 = t2 qaa_x: ASL byte_to_paint BCC qaa_x_end qaa_x_overflow: Sub_16 btp_mem_pos, btp_mem_pos + 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