Skip to navigation

Graphics: ScrollPlayerView

Name: ScrollPlayerView [Show more] Type: Subroutine Category: Graphics Summary: Scroll the screen and copy data from the screen buffer into screen memory to implement the player's scrolling landscape view
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * IRQHandler calls ScrollPlayerView
.ScrollPlayerView LDY lastPanKeyPressed \ Set Y to the direction of the last pan key that was \ pressed (which may not still be held down) \ \ So this contains the direction of any scrolling that \ we still need to apply, as follows: \ \ * 0 = pan right \ \ * 1 = pan left \ \ * 2 = pan up \ \ * 3 = pan down \ \ We use this as an index into various tables, to look \ up the correct values for the direction in which we \ want to scroll \ We now scroll the screen in the correct direction to \ pan the player's scrolling landscape view \ \ Note that we scroll the screen in the opposite \ direction to the pan direction, so if we are panning \ right we move the screen to the left, for example \ \ The screen address of the player's scrolling landscape \ view is stored in viewScreenAddr(1 0), so this is the \ address of the screen just below the energy icon and \ scanner row \ \ We therefore start the scrolling process by updating \ the screen address in viewScreenAddr(1 0) to point to \ the new address after scrolling \ \ Scrolling is done in individual steps, as follows: \ \ * When scrolling horizontally, we scroll by one \ column that's one character block wide (i.e. one \ byte, two pixels wide) \ \ * When scrolling vertically, we scroll by one row \ that's one character block tall (i.e. eight bytes, \ eight pixels tall) \ \ The amount of change that we need to apply to \ viewScreenAddr(1 0) for each of the four directions is \ given in the tables scrollScreenHi and scrollScreenLo, \ as 16-bit signed values, so we just need to look up \ the correct value and apply it to viewScreenAddr(1 0) \ \ For example, we advance viewScreenAddr(1 0) by eight \ bytes when panning right, as we need to scroll the \ screen to the left, so the start of the screen in \ memory moves on by eight bytes (one character block) \ \ This would scroll the screen to the left by two pixels \ as each character block is two pixels wide \ \ Similarly, we reduce viewScreenAddr(1 0) by 320 bytes \ when panning up, as we need to scroll the screen down, \ so the start of the screen in memory moves on by eight \ bytes (one character row of 40 character blocks with \ eight bytes per character block) \ \ This would scroll the screen to down by eight pixels \ as each character row is eight pixels wide LDA viewScreenAddr \ Apply the change in scrollScreen(Hi Lo) for the CLC \ current pan direction in Y to the screen address of ADC scrollScreenLo,Y \ the player's scrolling landscape, which is stored in STA viewScreenAddr \ viewScreenAddr(1 0) LDA viewScreenAddr+1 \ ADC scrollScreenHi,Y \ We start by calculating this: \ \ (A viewScreenAddr) = viewScreenAddr(1 0) \ + (scrollScreenHi+Y scrollScreenLo+Y) CMP #&80 \ If the high byte in A >= &80 then the new address is BCC scro1 \ past the end of screen memory, so subtract &20 from SBC #&20 \ the high byte so the address wraps around within the \ range of screen memory between &6000 and &8000 \ \ If the high byte is in range, jump to scro1 to check \ the high byte against the start of screen memory JMP scro2 \ Jump to scro2 to skip the next check, as we know it \ doesn't apply .scro1 CMP #&60 \ If the high byte in A < &60 then the new address is BCS scro2 \ before the start of screen memory, so add &20 to the ADC #&20 \ high byte so the address wraps around within the range \ of screen memory between &6000 and &8000 .scro2 STA viewScreenAddr+1 \ Store the high byte of the result, so we now have: \ \ viewScreenAddr(1 0) = viewScreenAddr(1 0) \ + (scrollScreenHi+Y scrollScreenLo+Y) \ \ with the address wrapped around as required \ We now reprogram the 6845 CRTC chip to scroll the \ screen in hardware (so-called "hardware scrolling") \ by setting 6845 registers R12 and R13 to the new \ address for the start of screen memory \ \ The registers actually require the address to be set \ in terms of character rows, so we need to set R12 and \ R12 to the address divided by 8 (see below) JSR GetIconRowAddress \ Set iconRowAddr(1 0) to the address in screen memory \ of the icon and scanner row at the top of the screen \ \ This calculates the address from viewScreenAddr(1 0), \ so the value returned will be the new start of screen \ memory, after the scroll is completed \ \ It also sets A to the high byte of the address of \ screen memory in iconRowAddr(1 0) STA screenAddrHi \ Set (screenAddrHi A) = iconRowAddr(1 0) / 8 LDA iconRowAddr \ LSR screenAddrHi \ So (screenAddrHi A) contains the new address of screen ROR A \ memory, divided by 8, which is suitable for passing to LSR screenAddrHi \ the 6845 CRTC to change the address of screen memory ROR A LSR screenAddrHi ROR A LDX #13 \ Set 6845 register R13 = A, for the low byte STX SHEILA+&00 \ STA SHEILA+&01 \ We do this by writing the register number (13) to \ SHEILA &00, and then the value (A) to SHEILA &01 LDX #12 \ Set 6845 register R12 = &0F, for the high byte STX SHEILA+&00 \ LDA screenAddrHi \ We do this by writing the register number (12) to STA SHEILA+&01 \ SHEILA &00, and then the value (screenAddrHi) to \ SHEILA &01 \ This sets 6845 registers (R12 R13) = (screenAddrHi A) \ to point to the start of screen memory in terms of \ character rows. There are 8 pixel lines in each \ character row, so to get the actual address of the \ start of screen memory, we multiply by 8: \ \ (screenAddrHi A) * 8 \ \ which is iconRowAddr(1 0), as set above \ \ So this whole thing sets the start of screen memory to \ the address of iconRowAddr(1 0), which scrolls the \ screen by the required amount DEC scrollCounter \ Decrement the scroll counter, as we have just scrolled \ the screen by one more step \ We now set viewScreenAddr(1 0) to the new address of \ the start of the player's landscape view, so that's \ the address of the top-left corner of the view, just \ below the energy icon and scanner bar at the top of \ the screen \ \ We now need to set toAddr(1 0) to the address in \ screen memory that we need to update now that the \ screen has been scrolled \ \ Scrolling the screen leads to the following update \ requirements: \ \ * When scrolling the screen to the left, we need to \ update the column on the right \ \ * When scrolling the screen to the right, we need to \ update the column on the left \ \ * When scrolling the screen down, we need to update \ the row along the top \ \ * When scrolling the screen up, we need to update \ the row along the bottom \ \ We want to set toAddr(1 0) to the address of the area \ in screen memory that we need to update, and the \ offset within screen memory of this area for each of \ the four directions is given in the tables at \ updateOffsetHi and updateOffsetLo, as 16-bit signed \ values, so we just need to look up the correct offset \ and apply it to viewScreenAddr(1 0) to get the address \ of the area of screen memory we need to update LDA viewScreenAddr \ Set toAddr(1 0) to the screen address of the player's CLC \ scrolling landscape, plus the offset for the current ADC updateOffsetLo,Y \ pan direction from updateOffset(Hi Lo) STA toAddr \ LDA viewScreenAddr+1 \ We start by calculating this: ADC updateOffsetHi,Y \ \ (A toAddr) = viewScreenAddr(1 0) \ + (updateOffsetHi+Y updateOffsetLo+Y) CMP #&80 \ If the high byte in A >= &80 then the new address is BCC scro3 \ past the end of screen memory, so subtract &20 from SBC #&20 \ the high byte so the address wraps around within the \ range of screen memory between &6000 and &8000 .scro3 STA toAddr+1 \ Store the high byte of the result, so we now have: \ \ toAddr(1 0) = viewScreenAddr(1 0) \ + (updateOffsetHi+Y updateOffsetLo+Y) \ \ with the address wrapped around as required \ By this point we have done the following to implement \ the required screen scrolling: \ \ * Updated viewScreenAddr(1 0) to the new address of \ the player's scrolling landscape \ \ * Updated the 6845 to scroll the screen by changing \ the address of screen memory \ \ * Decremented the counter in scrollCounter \ \ * Set toAddr(1 0) to the address of the area in \ screen memory that we now need to update \ \ We can now fall through into ShowScreenBuffer to copy \ the contents of the screen buffer into the area we \ need to update, so that the scroll reveals the correct \ part of the view