mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-11-26 07:49:17 +00:00
332 lines
11 KiB
ArmAsm
332 lines
11 KiB
ArmAsm
|
|
; 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
|