; Graphic screen initialization InitGraphics jsr _ShadowOn jsr _GrafOn lda #0 jsr _SetSCBs ldx #DefaultPalette lda #0 jsr _SetPalette ldx #SHR_LINE_WIDTH ldy #SHR_SCREEN_HEIGHT jsr _SetScreenMode jsr _InitBG0 ; Initialize the background layer lda EngineMode bit #ENGINE_MODE_TWO_LAYER beq :no_bg1 jsr _InitBG1 lda #0 jsr _ClearBG1Buffer :no_bg1 rts ; Allow the user to dynamically select one of the pre-configured screen sizes, or pass ; in a specific width and height. The screen is automatically centered. If this is ; not desired, then SetScreenRect should be used directly ; ; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%)) ; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%)) ; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%)) ; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%)) ; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%)) ; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%)) ; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%)) ; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%)) ; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%)) ; 9. Agony (Amiga) : 36 x 24 288 x 192 (27,648 bytes ( 86.4%)) ; 10. Atari Lynx : 20 x 13 160 x 102 (8,160 bytes ( 25.5%)) ; ; X = mode number OR width in bytes ; Y = height in pixels (if X > 8) _SetScreenMode cpx #11 bcs :direct ; if x > 10, then assume X and Y are the dimensions txa asl tax ldy ScreenModeHeight,x lda ScreenModeWidth,x tax :direct cpy #SHR_SCREEN_HEIGHT+1 bcs :exit cpx #SHR_LINE_WIDTH+1 bcs :exit phx ; Save X (width) and Y (height) phy lda #SHR_LINE_WIDTH ; Center the screen sec sbc 3,s lsr xba pha ; Save half the origin coordinate lda #SHR_SCREEN_HEIGHT sec sbc 3,s ; This is now Y because of the PHA above lsr ora 1,s plx ; Throw-away to pop the stack ply plx jsr SetScreenRect jmp FillScreen ; tail return :exit rts ; Return the current border color ($0 - $F) in the accumulator _GetBorderColor lda #0000 sep #$20 ldal BORDER_REG and #$0F rep #$20 rts ; Set the border color to the accumulator value. _SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z) and #$0F ; ACC = $0_(Y^Z) eorl BORDER_REG ; ACC = $W_(Y^Z^Z) = $W_Y stal BORDER_REG rep #$20 rts ; Clear to SHR screen to a specific color _ClearToColor ldx #$7D00 ;start at top of pixel data! ($2000-9D00) :clearloop dex dex stal SHR_SCREEN,x ;screen location bne :clearloop ;loop until we've worked our way down to 0 rts ; Set a palette values ; A = palette number, X = palette address _SetPalette and #$000F ; palette values are 0 - 15 and each palette is 32 bytes asl asl asl asl asl txy tax ]idx equ 0 lup 16 lda: $0000+]idx,y stal SHR_PALETTES+]idx,x ]idx equ ]idx+2 --^ rts ; Initialize the SCB _SetSCBs ldx #$0100 ;set all $100 scbs to A :scbloop dex dex stal SHR_SCB,x bne :scbloop rts ; Turn SHR screen On/Off _GrafOn sep #$20 lda #$C1 ; SHR On, Linear Memory Map On, Ignore Bank Latch stal NEW_VIDEO_REG rep #$20 rts _GrafOff sep #$20 lda #$01 ; SHR Off, Linear Memory Map Off stal NEW_VIDEO_REG rep #$20 rts ; Enable/Disable Shadowing. _ShadowOn sep #$20 ldal SHADOW_REG and #$F7 stal SHADOW_REG rep #$20 rts _ShadowOff sep #$20 ldal SHADOW_REG ora #$08 stal SHADOW_REG rep #$20 rts _GetVBL sep #$20 ldal VBL_HORZ_REG asl ldal VBL_VERT_REG rol ; put V5 into carry bit, if needed. See TN #39 for details. rep #$20 and #$00FF rts _WaitForVBL sep #$20 :wait1 ldal VBL_STATE_REG ; If we are already in VBL, then wait bmi :wait1 :wait2 ldal VBL_STATE_REG bpl :wait2 ; spin until transition into VBL rep #$20 rts ; Set the physical location of the virtual screen on the physical screen. The ; screen size must by a multiple of 8 ; ; A = XXYY where XX is the left edge [0, 159] and YY is the top edge [0, 199] ; X = width (in bytes) ; Y = height (in lines) ; ; This subroutine stores the screen positions in the direct page space and fills ; in the double-length ScreenAddrR table that holds the address of the right edge ; of the playfield. This table is used to set addresses in the code banks when the ; virtual origin is changed. ; ; We are not concerned about the raw performance of this function because it should ; usually only be executed once during app initialization. It doesn't get called ; with any significant frequency. SetScreenRect sty ScreenHeight ; Save the screen height and width stx ScreenWidth tax ; Temp save of the accumulator and #$00FF sta ScreenY0 clc adc ScreenHeight sta ScreenY1 txa ; Restore the accumulator xba and #$00FF sta ScreenX0 clc adc ScreenWidth sta ScreenX1 lda ScreenHeight ; Divide the height in scanlines by 8 to get the number tiles lsr lsr lsr sta ScreenTileHeight lda ScreenWidth ; Divide width in bytes by 4 to get the number of tiles lsr lsr sta ScreenTileWidth lda ScreenY0 ; Calculate the address of the first byte asl ; of the right side of the playfield tax lda ScreenAddr,x ; This is the address for the edge of the physical screen clc adc ScreenX1 dec pha ; Save for second loop ldx #0 ldy ScreenHeight :loop clc sta RTable,x adc #160 inx inx dey bne :loop ldy ScreenHeight pla ; Reset the address and continue filling in the :loop2 clc sta RTable,x adc #160 inx inx dey bne :loop2 ; Calculate the screen locations for each tile corner lda ScreenY0 ; Calculate the address of the first byte asl ; of the right side of the playfield tax lda ScreenAddr,x ; This is the address for the left edge of the physical screen clc adc ScreenX0 ldx #0 ldy #0 :tsloop sta TileStore+TS_SCREEN_ADDR,x clc adc #4 ; Go to the next tile iny cpy #41 ; If we've done 41 columns, move to the next line bcc :nohop ldy #0 clc adc #{8*160}-{4*41} :nohop inx inx cpx #TILE_STORE_SIZE-2 bcc :tsloop rts ; Clear the SHR screen and then infill the defined field FillScreen lda #0 jsr _ClearToColor ldy ScreenY0 :yloop tya asl a tax lda ScreenAddr,x clc adc ScreenX0 tax phy lda ScreenWidth lsr tay lda #$FFFF :xloop stal $E10000,x ; X is the absolute address inx inx dey bne :xloop ply iny cpy ScreenY1 bcc :yloop rts