; Support rotating the BG1 graphics by leveraging the fact that a rotation function can be decomposed ; into an addition of two function parametertized by the angle of rotation: pixel = *(f(x, a) + f(y, a)) ; ; The pre-build a number of rotation tables and then populate the direct page values and Y-register values ; for each line of the blitter, such that a single lda (00),y instruction fetches the appropriate data ; ; This is about as fast of a rotation as we can do. ; ; When possible, off-screen locations are calculate to produce an address of $FFFE, so that the last two bytes ; of the BG1 data buffer provides the "fill value". ANGLEBNK EXT _ApplyBG1XPosAngle :ptr equ $FC :stbl equ $FA phd ; save the direct page because we are going to switch to the pei BlitterDP ; blitter direct page space and fill in the addresses lda BG1Scaling pld and #$000F asl tax lda ScalingTables,x sta :stbl lda #^ANGLEBNK sta :ptr+2 sty :ptr ; Store in the new direct page ldx #162 :loop txy lda (:stbl),y ; Map the through the scaling factor tay lda [:ptr],y ; Load the underlying value sta 00,x ; store the value dex dex bpl :loop pld rts _ApplyBG1YPosAngle :virt_line equ tmp0 :lines_left equ tmp1 :draw_count equ tmp2 :ytbl_idx equ tmp3 :angle_tbl equ tmp4 :scale_ptr equ tmp5 sty :angle_tbl lda BG1Scaling ; Set the scaling table and #$0007 asl tax lda ScalingTables,x sta :scale_ptr lda BG1StartYMod208 sta :ytbl_idx ; Start copying from the first entry in the table lda StartYMod208 ; This is the base line of the virtual screen sta :virt_line ; Keep track of it lda ScreenHeight sta :lines_left ; Copy out the y-values from the rotation table into a temporary buffer ; Copy the rotation values into the code fields phb :loop lda :virt_line asl tax ldal BTableLow,x ; Get the address of the first code field line tay sep #$20 ldal BTableHigh,x pha ; push the bank on the stack plb rep #$20 lda :virt_line and #$000F eor #$FFFF inc clc adc #16 min :lines_left sta :draw_count ; Do this many lines asl tax lda :ytbl_idx ; Read from this location (duplicate every 4 lines) lsr lsr asl clc adc :angle_tbl sec sbc #ANGLEBNK jsr CopyAngleYTableToBG1Addr ; or CopyBG1YTableToBG1Addr2 lda :virt_line ; advance to the virtual line after the segment we just clc ; filled in adc :draw_count sta :virt_line lda :ytbl_idx ; advance the index into the YTable adc :draw_count sta :ytbl_idx lda :lines_left ; subtract the number of lines we just completed sec sbc :draw_count sta :lines_left jne :loop plb rts ; Unrolled copy routine to move y_angle entries into BG1_ADDR position with an additional ; shift. This has to be split into two ; ; A = index into the array (x2) ; Y = starting line * $1000 ; X = number of lines (x2) CopyAngleYTableToBG1Addr :ptr equ $FC :stbl equ $FA ; tax ; ldal ANGLEBNK+XX,x ; sta BG1_ADDR+$F000,y phy ; save y; used when writing phx ; Scale the mapping tay jsr SaveBG1AngleValues plx ; x is used directly in this routine ply jmp ApplyBG1OffsetValues SaveBG1AngleValues jmp (:tbl,x) :tbl da :none da :do01,:do02,:do03,:do04 da :do05,:do06,:do07,:do08 da :do09,:do10,:do11,:do12 da :do13,:do14,:do15,:do16 :do15 tax bra :x15 :do14 tax bra :x14 :do13 tax bra :x13 :do12 tax bra :x12 :do11 tax bra :x11 :do10 tax bra :x10 :do09 tax bra :x09 :do08 tax bra :x08 :do16 tax ldal ANGLEBNK+06,x stal BG1YCache+30 :x15 ldal ANGLEBNK+06,x stal BG1YCache+28 :x14 ldal ANGLEBNK+06,x stal BG1YCache+26 :x13 ldal ANGLEBNK+06,x stal BG1YCache+24 :x12 ldal ANGLEBNK+04,x stal BG1YCache+22 :x11 ldal ANGLEBNK+04,x stal BG1YCache+20 :x10 ldal ANGLEBNK+04,x stal BG1YCache+18 :x09 ldal ANGLEBNK+04,x stal BG1YCache+16 :x08 ldal ANGLEBNK+02,x stal BG1YCache+14 :x07 ldal ANGLEBNK+02,x stal BG1YCache+12 :x06 ldal ANGLEBNK+02,x stal BG1YCache+10 :x05 ldal ANGLEBNK+02,x stal BG1YCache+08 :x04 ldal ANGLEBNK+00,x stal BG1YCache+06 :x03 ldal ANGLEBNK+00,x stal BG1YCache+04 :x02 ldal ANGLEBNK+00,x stal BG1YCache+02 :x01 ldal ANGLEBNK+00,x stal BG1YCache+00 :none rts :do07 tax bra :x07 :do06 tax bra :x06 :do05 tax bra :x05 :do04 tax bra :x04 :do03 tax bra :x03 :do02 tax bra :x02 :do01 tax bra :x01