English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. Blitz Basic

 
 
Thread Tools
Old 21 February 2019, 15:53   #1
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Horisontal Scrolling Demo (updated: 2019-03-12)

I started experimenting with tilemap scrolling techniques and will upload working examples here as I finish them. I'm basing this on the scrolling tricks C demos from Aminet: http://aminet.net/package/dev/src/ScrollingTrick

First off is a horisontal only corkscrew scroll, full screen 320x256 display. At a scrolling speed of 1px/frame, only ONE tile needs to be drawn per frame when scrolling left or right. If direction changes, then TWO tiles need to be drawn in that single frame. Bitmap size needed is only 352x256 (+some marginal height depending on total map width)

The zip file contains the code, tiles, the map as binary file and for Tiled (.tmx)

Next up I will see if I can figure out vertical scrolling from earoks Kiwi's Tale dev-notes...

Code:
; ****************************************************
;
; Interleaved single buffer horisontal corkscrew scrolling demo
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
;
; MIT License, read license.txt
;
; For a scrolling speed of 1px/frame, only one tile
; per frame needs to be drawn. Tiles needed to be
; drawn per frame equals scrolling speed.
;
; In order to use the Bitmap newtype, include the resident file
; Blitzlibs:Bb2objtypes.res in the residents list in the compiler options.
;
; Notes about the tilemap:
; The leftmost and rightmost columns of the tilemap will never be visible,
; so you need to add one padding row to the left and right.
;
; ****************************************************

; Include other source files
INCLUDE "system.bb2"

; Enable running from Workbench
WBStartup

; Set default type to word
DEFTYPE .w

Constants:
; -----------------------------------------------------------
#ScreenMainWidth=320   ; Width of visible screen
#ScreenMainHeight=256  ; Height of visible screen
#ScreenMainDepth=5     ; The depth of the screen
#ScreenMainColors=32   ; The number of colours for the main screen
#TileDepth=5           ; Tile bit depth
#TileWidth=16          ; Width of tiles
#TileHeight=16         ; Height of tiles
#TileXShift=4          ; Set according to #TileWidth (16->4, 32->5)
#TileYShift=4          ; Set according to #TileHeight (16->4, 32->5)
#MapWidth=82           ; Tilemap width (number of tiles wide)
#MapHeight=16          ; Tilemap height (number of tiles high)

; Calculated constants (from constants above)
#ScreenXCount=10                             ; Total number of screens horisontally in tilemap
#TileHeight1P=#TileHeight*#TileDepth         ; Used to get pointer to bitmap buffer
#TOffsB=#TileHeight1P-#ScreenMainDepth       ; Tile bottom offset for the interleaved bitmap
#BufferWidth=#ScreenMainWidth+#TileWidth*2   ; Buffer bitmap width (screen width + padding)
#BufferHeight=#ScreenMainHeight              ; Buffer bitmap height (screen height)
#BufferTilesX=#BufferWidth/#TileWidth        ; Number of tiles that fits horisontally on the buffer bitmap
#BufferTilesY=#BufferHeight/#TileHeight      ; Number of tiles that fits vertically on the buffer bitmap         
#MapXMax=#MapWidth*#TileWidth-#ScreenMainWidth-#TileWidth*2 ; Max X position on map   

; Keyboard etc. constants
#KeyUp=$4C
#KeyDown=$4D
#KeyLeft=$4F
#KeyRight=$4E
#KeyEscape=$45 
#DirNone=0
#DirUp=1
#DirDown=2
#DirLeft=3
#DirRight=4      

#BitmapBuffer1=1
#BitmapBuffer2=2
#BitmapTiles=3
#BitmapVTiles=4
#BitmapVBuffer1=5
#BitmapVBuffer2=6
#BobTemp=0
#PaletteMain=0
#CopListMain=0

; Tiles bitmap
#TileCountX=229     ; The number of tiles horisontally in the tiles bitmap
#TileCountY=1       ; The number of tiles vertically in the tiles bitmap

Macros:
; ---------------------------------------------------------------
; Get a tile from the tilemap array
; The bitwise AND 255 is for reading the byte value as unsigned
Macro GetTile
  (map(`1, `2) & 255)
End Macro
; Draw a tile
;!DrawTile{tileX,tileY,x,y}
Macro DrawTile
  BlockScroll (map(`1, `2) & 255) LSL #TileXShift, 0, #TileWidth, #TileHeight1P, `3, `4, #BitmapVTiles
End Macro
Macro DrawTileTop
  BlockScroll (map(`1, `2) & 255) LSL #TileXShift,0,#TileWidth,#TileDepth,`3,`4,#BitmapVTiles
End Macro
; #TOffsB=#TileHeight1P-#ScreenMainDepth = 16*5-5 = 75
Macro DrawTileBottom
  BlockScroll (map(`1, `2) & 255) LSL #TileXShift,#TOffsB,#TileWidth,#TileDepth,`3,`4+#TOffsB,#BitmapVTiles
End Macro
; Round down value to nearest tile height
; -16 is the same as ~(#TileHeight-1)
Macro RoundToBlockWidth
  (`1 & -#TileWidth)
End Macro
; This is a faster way of doing MOD #TileWidth
Macro ModNumSteps
  (`1 & (#TileWidth-1))
End Macro

Variables:
; ---------------------------------------------------------------
db.b=1                ; Keeps track of double buffer bitmap used (not in use currently)
x=0
y=0
tile_x=0
tile_y=0
map_w=0
map_h=0
map_x=0               
scroll_dir_prev.b=#DirNone

ScreenSetup:
; ---------------------------------------------------------------

; Create one bitmap for a single buffered display
BitMap #BitmapBuffer1,#BufferWidth,#BufferHeight+#ScreenXCount,#ScreenMainDepth

; Convert the bitmap to be interleaved
ConvertBMToIL{#BitmapBuffer1,#BufferWidth,#BufferHeight+#ScreenXCount,#ScreenMainDepth}

; Get a pointer to the background bitmap
*db1.bitmap = Addr Bitmap(#BitmapBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*db1\_xclip = $7FFF

; Create a "virtual" one plane bitmap for blitting to. We will still use the
; "normal" bitmap with the display command
CludgeBitMap #BitmapVBuffer1,#BufferWidth,(#BufferHeight+#ScreenXCount)*#ScreenMainDepth,1,*db1\_data[0]

; Get a pointer to the virtual bitmap
*dbv.bitmap = Addr Bitmap(#BitmapVBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*dbv\_xclip = $7FFF
*dbv\_yclip = $7FFF

; Create a bitmap for the tiles
BitMap #BitmapTiles,#TileCountX*#TileWidth,#TileCountY*#TileHeight,#ScreenMainDepth 
*bmt.bitmap = Addr Bitmap(#BitmapTiles)

; Load the tiles
LoadBitMap #BitmapTiles,"tilesrow32.iff"

; Load the palette from the same image
LoadPalette #PaletteMain,"tilesrow32.iff"

; Convert the tiles bitmap to be interleaved
ConvertBMToIL{#BitmapTiles, #TileCountX LSL #TileXShift, #TileCountY LSL #TileYShift, #ScreenMainDepth}

; Create a virtual 1-plane bitmap from the tiles bitmap
CludgeBitMap #BitmapVTiles, #TileCountX LSL #TileXShift, #TileHeight1P, 1, *bmt\_data[0]

; Read the tile map
If ReadFile(0,"world.map")
  ; First two words are width and height of tilemap
  ReadMem 0,&map_w,2
  ReadMem 0,&map_h,2
  ; Create a two dimensional array for the tilemap
  Dim map.b(map_w-1, map_h-1)
  ; Read the entire tilemap into the array
  ReadMem 0,&map(0,0),map_w*map_h
  ; Close the tilemap file
  CloseFile 0
EndIf

; Wait for disk activity to finish before going into Blitz mode
VWait 100 

; Go into blitz mode and enable blitzkeys
BLITZ
BlitzKeys On

; Create copperlists for the display (y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colors)
InitCopList #CopListMain,44,#ScreenMainHeight,$10+#ScreenMainDepth,8,#ScreenMainColors,0 

; Create a display using copperlist
CreateDisplay #CopListMain

; Set up palette
DisplayPalette #CopListMain,#PaletteMain  

; Use the virtual one plane bitmap
Use BitMap #BitmapVBuffer1

; Draw tiles to fill the whole bitmap
For y = 0 To #BufferTilesY-1
  For x = 0 To #BufferTilesX-1
    !DrawTile{x, y, x LSL #TileXShift, y * #TileHeight1P}
  Next
Next

MainLoop:
; -----------------------------------------------------------
Repeat

  ; Wait for vertical blank
  VWait 1

  ; Show bitmap on main copperlist
  DisplayBitMap #CopListMain,#BitmapBuffer1,map_x+#TileWidth,0

  ; Scrolling right?
  If RawStatus(#KeyRight) AND map_x < #MapXMax
    JSR ScrollRight : JSR ScrollRight
  Else
    ; Scrolling left?
    If RawStatus(#KeyLeft) AND map_x > 0
      JSR ScrollLeft : JSR ScrollLeft
    EndIf
  EndIf

Until RawStatus(#KeyEscape)=-1

; Quit game
End

; ------------------------------------------------
; Scroll Left
; ------------------------------------------------
ScrollLeft:
  ; Decrease position first
  map_x-1
  ; Get blit position
  x = !RoundToBlockWidth{map_x}
  tile_y = !ModNumSteps{map_x}
  y = tile_y * #TileHeight1P
  ; Blit tile
  If tile_y < #BufferTilesY
    tile_x = map_x LSR #TileXShift
    !DrawTile{tile_x, tile_y, x, y}
    ; Repair broken tile if needed
    If scroll_dir_prev = #DirRight
      If tile_y+1 < #BufferTilesY
        !DrawTileTop{tile_x, tile_y+1, x, y+#TileHeight1P}
      EndIf
    EndIf
  EndIf
  scroll_dir_prev=#DirLeft
  RTS

; ------------------------------------------------
; Scroll Right
; ------------------------------------------------
ScrollRight:
  ; Get blit position
  x = #BufferWidth + !RoundToBlockWidth{map_x}
  tile_y = !ModNumSteps{map_x}
  y = tile_y * #TileHeight1P
  ; Blit tile
  If tile_y < #BufferTilesY
    tile_x = map_x LSR #TileXShift + #BufferTilesX
    !DrawTile{tile_x, tile_y, x, y}
    ; Repair broken tile if needed
    If scroll_dir_prev = #DirLeft
      If tile_y-1 >= 0
        !DrawTileBottom{tile_x,tile_y-1,x,y-#TileHeight1P}
      EndIf
    EndIf
  EndIf
  ; Increase position last
  map_x+1
  ; Set right as previous scroll direction
  scroll_dir_prev=#DirRight
  RTS
Changelog
2019-03-12
- Added MIT license.txt
2019-03-11
- Changed to use interleaved bitmaps
- Optimisations and cleanup
2019-02-23
- Small optimisations
2019-02-21
- First version
Attached Files
File Type: zip ScrollX.zip (41.7 KB, 130 views)

Last edited by MickGyver; 12 March 2019 at 11:44. Reason: Updated the source (including the zip)
MickGyver is offline  
Old 21 February 2019, 16:23   #2
dodke
Registered User
 
Join Date: Feb 2018
Location: London / UK
Posts: 112
If you don't need much vertical scrolling necessarily you can still use the corkscrew method if you make the buffer just slightly taller than the screen.

I'm working on a game at the moment which uses a 384 pixels tall buffer so there's 160 pixels to scroll up/down with a 320 x 224 viewport which is kind of decent, way nicer than horizontal only.
I'm then updating 1 or 2 tiles per pixel scrolled.
I might do a proper raster split tile engine "next time" but for now it was much easier to get started with the corkscrew stuff.
dodke is offline  
Old 22 February 2019, 09:25   #3
carrion
Registered User
 
carrion's Avatar
 
Join Date: Dec 2016
Location: Warsaw area
Posts: 152
@MickGyver
Thanks man.
I will check that later today but judging the code quickly it's similar to what I did.
I wonder how you implement the vertical scroll. I'm stuck here. I mean I understand the principles (some helped me in other thread) but it's still buggy.
Wait for your solution.
and then finally 8 way? I'm really curious.
carrion is offline  
Old 22 February 2019, 09:32   #4
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by dodke View Post
If you don't need much vertical scrolling necessarily you can still use the corkscrew method if you make the buffer just slightly taller than the screen.

I'm working on a game at the moment which uses a 384 pixels tall buffer so there's 160 pixels to scroll up/down with a 320 x 224 viewport which is kind of decent, way nicer than horizontal only.
I'm then updating 1 or 2 tiles per pixel scrolled.
I might do a proper raster split tile engine "next time" but for now it was much easier to get started with the corkscrew stuff.
For minor vertical scrolling that is fine yes and probably works wonders. I'm aiming for getting 8-way scrolling in large maps to work.

Quote:
Originally Posted by carrion View Post
@MickGyver
Thanks man.
I will check that later today but judging the code quickly it's similar to what I did.
I wonder how you implement the vertical scroll. I'm stuck here. I mean I understand the principles (some helped me in other thread) but it's still buggy.
Wait for your solution.
and then finally 8 way? I'm really curious.
I'm curious to know if you solved some things differently/more efficiently, please let me know! Next I'm going to try vertical scrolling only, then 8-way scrolling if I get vertical scrolling to work. I have no idea though.

By the way you said somebody helped you in another thread, which thread is that? EDIT: It's this one I guess: http://eab.abime.net/showthread.php?t=81634&page=3

Last edited by MickGyver; 22 February 2019 at 09:42.
MickGyver is offline  
Old 22 February 2019, 19:42   #5
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Vertical Scrolling Demo (updated: 2019-03-11)

I have managed to get vertical tilemap scrolling working (using a coppersplit) thanks to earoks Kiwi's Tale dev notes. There is a small glitch when bitmap wraps around for some reason, can't figure it out at the moment. splitline becomes negative for a tile height, I can't get everything to sync, probably something simple with bitmap heights etc. Maybe Erik the Genius or somebody else can see what's wrong?

EDIT1: I edited the code a little, I found a hack/solution to the problem I explained above, the offset y position can for sure be handled in a prettier way than it is now however.

EDIT2: I figured it out and have edited the code, it should now be good to go. 8-way scrolling next.

Only two tiles needs drawing every frame, or it's like 10 frames with two tiles drawn, 6 frames with no tiles drawn. Visible area is 320x208. Bitmap size needed is only 320x240. If using a width of 256 (16 tiles) instead of 320 (20 tiles) then only one tile needs to be drawn per step when scrolling.

(The code uses the same tilemap etc. as in the ScrollX example above.)

Code:
; ****************************************************
;
; Interleaved single buffer vertical scrolling demo (coppersplit)
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
; and earoks (English Amiga Board) dev notes for Kiwi's Tale
;
; MIT License, read license.txt
;
; In order to use the Bitmap newtype, include the resident file
; Blitzlibs:Bb2objtypes.res in the residents list in the compiler options.
;
; Notes about the tilemap:
; The topmost and bottommost rows of the tilemap will never be visible,
; so you need to add one padding row to the top and bottom.
;
; ****************************************************

; Include other source files
INCLUDE "system.bb2"

; Enable running from Workbench
WBStartup

; Set default type to word
DEFTYPE .w

Constants:
; ---------------------------------------------------------------
#ScreenMainWidth=320   ; Width of visible screen
#ScreenMainHeight=208  ; Height of visible screen
#ScreenMainDepth=5     ; The bit depth of the main screen
#ScreenMainColors=32   ; The number of colors for the main screen
#HudHeight=40          ; Height of HUD
#HudDepth=5            ; The bit depth of the HUD
#HudColors=32          ; The number of colors for the HUD
#TileWidth=16          ; Width of tiles
#TileHeight=16         ; Height of tiles
#TileDepth=5           ; The bit depth of the tiles (other bit depths than 5 is untested)
#TileXShift=4          ; Set according to #TileWidth (16->4, 32->5)
#TileYShift=4          ; Set according to #TileHeight (16->4, 32->5)
#MapWidth=20           ; Tilemap width (number of tiles wide)
#MapHeight=52          ; Tilemap height (number of tiles high)
#ScrollSpeed=1         ; Scroll speed, this equals the number of tiles that needs to be drawn every frame

; Calculated constants (from constants above)
#TileXAndNot=0-#TileWidth                      ; Used for inverted bitshift AND to get nearest multiple of #TileWidth
#TileYAndNot=0-#TileHeight                     ; Used for inverted bitshift AND to get nearest multiple of TileHeight
#TileHeight1P=#TileHeight*#TileDepth           ; The tileheight for an interleaved bitmap
#BufferDepth=#ScreenMainDepth                  ; The buffer bit depth, same as main screen depth
#BufferWidth=#ScreenMainWidth                  ; Buffer bitmap width (screen width)
#BufferHeight=#ScreenMainHeight+#TileHeight*2  ; Buffer bitmap height (screen height + padding)
#BufferTilesX=#BufferWidth/#TileWidth          ; Number of tiles that fits horisontally on the buffer bitmap
#BufferTilesY=#BufferHeight/#TileHeight        ; Number of tiles that fits vertically on the buffer bitmap
#MapXMax=#MapWidth*#TileWidth-#ScreenMainWidth-#TileWidth*2     ; Camera max x position
#MapYMax=#MapHeight*#TileHeight-#ScreenMainHeight-#TileHeight*2 ; Camera max y position

; Keyboard etc. constants
#KeyUp=$4C
#KeyDown=$4D
#KeyLeft=$4F
#KeyRight=$4E
#KeyEscape=$45 
#DirNone=0
#DirUp=1
#DirDown=2
#DirLeft=3
#DirRight=4      

#BitmapTemp=0
#BitmapBuffer1=1
#BitmapBuffer2=2
#BitmapHud=3
#BitmapTiles=4
#BitmapVTiles=5
#BitmapVBuffer1=6
#BitmapVBuffer2=7

#PaletteMain=0
#PaletteHud=0
#CopListMain=0
#CopListHud=1

; Tiles bitmap
#TileCountX=229     ; The number of tiles horisontally in the tiles bitmap
#TileCountY=1       ; The number of tiles vertically in the tiles bitmap

Macros:
; ---------------------------------------------------------------
; Get a tile from the tilemap array
; The bitwise AND 255 is for reading the byte value as unsigned
Macro GetTile
  (map(`1, `2) & 255)
End Macro
; Draw a tile
;!DrawTile{TileX,TileY,X,Y}
Macro DrawTile
  BlockScroll (map(`1, `2) & 255) LSL #TileXShift, 0, #TileWidth, #TileHeight1P, `3, `4, #BitmapVTiles
End Macro
; Round down value to nearest tile height
; -16 is the same as ~(#TileHeight-1)
Macro RoundToBlockHeight
  (`1 & -#TileHeight)
End Macro
; This is a faster way of doing MOD #TileHeight
Macro ModNumSteps
  (`1 & (#TileHeight-1))
End Macro

Variables:
; ---------------------------------------------------------------
db.b=0                ; Keeps track of double buffer bitmap used (not in use currently)
x=0
y=0
tile_x=0
tile_y=0
map_w=0
map_h=0
map_x=0               
map_y=0
scroll_dir_prev.b=#DirNone
bp.l=0
videopos_y=0
show_y=0

ScreenSetup:
; ---------------------------------------------------------

; Create two bitmaps for double buffered display
BitMap #BitmapBuffer1,#BufferWidth,#BufferHeight,#BufferDepth
BitMap #BitmapHud,#ScreenMainWidth,#HudHeight,#HudDepth

; Convert the buffer bitmap to be interleaved
ConvertBMToIL{#BitmapBuffer1,#BufferWidth,#BufferHeight,#BufferDepth}

; Get a pointer to the background bitmap
*db1.bitmap = Addr Bitmap(#BitmapBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*db1\_xclip = $7FFF

; Create a "virtual" one plane bitmap for blitting to. We will still use the
; "normal" bitmap with the display command
CludgeBitMap #BitmapVBuffer1,#BufferWidth,#BufferHeight*#BufferDepth,1,*db1\_data[0]

; Get a pointer to the virtual bitmap
*dbv.bitmap = Addr Bitmap(#BitmapVBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*dbv\_xclip = $7FFF
*dbv\_yclip = $7FFF

; Create a bitmap for the tiles
BitMap #BitmapTiles,#TileCountX*#TileWidth,#TileCountY*#TileHeight,#TileDepth 
*bmt.bitmap = Addr Bitmap(#BitmapTiles)

; Load the tiles to bitmap 2
LoadBitMap #BitmapTiles,"tilesrow32.iff"

; Load the palette from the same image
LoadPalette #PaletteMain,"tilesrow32.iff"

; Convert the tiles bitmap to be interleaved
ConvertBMToIL{#BitmapTiles, #TileCountX LSL #TileXShift, #TileCountY LSL #TileYShift, #TileDepth}

; Create a virtual 1-plane bitmap from the tiles bitmap
CludgeBitMap #BitmapVTiles, #TileCountX LSL #TileXShift, #TileHeight1P, 1, *bmt\_data[0]

; Read the tile map
If ReadFile(0,"world.map")
  ; First two words are width and height of tilemap
  ReadMem 0,&map_w,2
  ReadMem 0,&map_h,2
  ; Create a two dimensional array for the tilemap
  Dim map.b(map_w-1, map_h-1)
  ; Read the entire tilemap into the array
  ReadMem 0,&map(0,0),map_w*map_h
  ; Close the tilemap file
  CloseFile 0
EndIf

; Wait for disk activity to finish before going into Blitz mode
VWait 100 

; Go into blitz mode and enable blitzkeys
BLITZ
BlitzKeys On

; Create copperlists for the display
; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours, 12 copper commands
InitCopList #CopListMain,44,#ScreenMainHeight,$10+#ScreenMainDepth,8,#ScreenMainColors,12    
; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours, 12 copper commands
InitCopList #CopListHud,46+#ScreenMainHeight,#HudHeight,$10+#HudDepth,8,#HudColors,12 

; Create a display using the copperlists
CreateDisplay #CopListMain,#CopListHud

; Set up palettes
DisplayPalette #CopListMain,#PaletteMain 
DisplayPalette #CopListHud,#PaletteHud  

; Output text to HUD bitmap
BitMapOutput #BitmapHud
Colour 18,4
Use BitMap #BitmapHud
Cls 4

; Use virtual buffer bitmap
Use BitMap #BitmapVBuffer1

; Draw tiles to fill the whole bitmap
For y = 0 To #BufferTilesY-1
  For x = 0 To #BufferTilesX-1
    !DrawTile{x, y, x LSL #TileXShift, y * #TileHeight1P}
  Next
Next

; Display HUD bitmap on HUD copperlist
DisplayBitMap #CopListHud,#BitmapHud,0,0

MainLoop:
; ---------------------------------------------------------
Repeat

  ; Wait for vertical blank
  VWait 1

  ; Set screen position
  show_y = (videopos_y+#TileHeight) MOD #BufferHeight
  splitline = #BufferHeight-show_y
 
  ; Show bitmap on copperlist
  DisplayBitMap 0,#BitmapBuffer1,0,show_y
  ; Reset the main copper list
  CopperReset 0, 0
  
  ; Are we displaying over the bottom edge
  If splitline < #ScreenMainHeight
    ; Wait until the bottom edge       
    CopperWait 0, splitline + 44         
    ; Reset the display to the top of the bitmap
    bp.l = *db1\_data[0]
    CopperMove $0e0, bp lsr 16
    CopperMove $0e2, bp & $ffff
    bp.l = *db1\_data[1]
    CopperMove $0e4, bp lsr 16
    CopperMove $0e6, bp & $ffff
    bp.l = *db1\_data[2]
    CopperMove $0e8, bp lsr 16
    CopperMove $0ea, bp & $ffff
    bp.l = *db1\_data[3]
    CopperMove $0ec, bp lsr 16
    CopperMove $0ee, bp & $ffff
    bp.l = *db1\_data[4]
    CopperMove $0f0, bp lsr 16
    CopperMove $0f2, bp & $ffff
  Else 
    ; If we're not displaying over the bottom edge, just wipe out our copper commands
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
  EndIf
  
  ; Scrolling up?
  If RawStatus(#KeyUp)
    JSR ScrollUp : JSR ScrollUp
  EndIf
  
  ; Scrolling down?
  If RawStatus(#KeyDown)
    JSR ScrollDown : JSR ScrollDown
  EndIf
  
  ;Locate 0,0 : Print "Y:",map_y,"  "

Until RawStatus(#KeyEscape)=-1

; Exit game
End

; ------------------------------------------------
; Scroll Up
; ------------------------------------------------
ScrollUp:
  If map_y > 0
    ; Decrease position first
    map_y-1
    videopos_y-1
    If videopos_y < 0 Then videopos_y+#BufferHeight
    ; Tile position
    tile_x = !ModNumSteps{map_y} LSL 1
    If tile_x < #BufferTilesX
      tile_y = map_y LSR #TileYShift
      x = tile_x LSL #TileXShift 
      y = !RoundToBlockHeight{videopos_y} * #BufferDepth
      !DrawTile{tile_x, tile_y, x, y}
      If tile_x+1 < #BufferTilesX
        !DrawTile{tile_x+1, tile_y, x+#TileWidth, y}
      EndIf
    EndIf
  EndIf
  RTS
  
; ------------------------------------------------
; Scroll Down
; ------------------------------------------------
ScrollDown:
  If map_y < #MapYMax
    tile_x = !ModNumSteps{map_y} LSL 1
    If tile_x < #BufferTilesX
      tile_y = #BufferTilesY + map_y LSR #TileYShift
      x = tile_x LSL #TileXShift 
      y = !RoundToBlockHeight{videopos_y} * #BufferDepth
      !DrawTile{tile_x, tile_y, x, y}
      If tile_x+1 < #BufferTilesX
        !DrawTile{tile_x+1, tile_y, x+#TileWidth, y}
      EndIf
    EndIf
    ; Increase position last
    map_y+1
    videopos_y+1
    If videopos_y >= #BufferHeight Then videopos_y-#BufferHeight
  EndIf
  RTS
Changelog
2019-03-12
- Added MIT license.txt
2019-03-11
- Changed to use interleaved bitmaps
- Optimisations and cleanup
2019-02-23
- Copper bug fixed (thanks to earok)
- Working HUD
2019-02-22
- First version
Attached Files
File Type: zip ScrollY.zip (41.6 KB, 90 views)

Last edited by MickGyver; 12 March 2019 at 11:45. Reason: Updated the demo source
MickGyver is offline  
Old 23 February 2019, 09:14   #6
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,542
I think I might have worked out the Copper bug (why you've needed to use CopperEnd there).

In the documentation of the CopperFX library

Quote:
The commands in this library insert copper instructions into the custom space in a Coplist object - you must therefore have custom space in your CopList if you want to use them.
But

Quote:
InitCopList 0,44,#SCR_H,$15,8,32,0 ; y=44, lores, smoothscroll, 5 bitplanes, 8
InitCopList 1,46+#SCR_H,14,$15,8,32,0 ; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours
You haven't assigned any copper space, hence you're writing the commands in a place they're not supposed to be (overwriting the Blitz copper commands that close off the screen normally, for example)

I think it's safe to be a bit generous and give yourself more copper space than you think you need.
earok is offline  
Old 23 February 2019, 12:31   #7
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by earok View Post
You haven't assigned any copper space, hence you're writing the commands in a place they're not supposed to be (overwriting the Blitz copper commands that close off the screen normally, for example)

I think it's safe to be a bit generous and give yourself more copper space than you think you need.
Thank you very much, that's it!
MickGyver is offline  
Old 24 February 2019, 00:44   #8
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,542
Quote:
Originally Posted by MickGyver View Post
Thank you very much, that's it!
Excellent!

There was one more thing I wanted to bring up. You might have noticed that the screen height the example isn't exactly fullscreen, that's indeed due to complications around having the vertical wrap past line 255.

However, it's perfectly possible to do so, but it's a little more tricky. You do indeed need to use CopperEnd in that case (and ONLY when the wrap is beyond line 255). On top of that, you need to make sure you run at least two wait commands to get to the correct line (since the wait command uses bytes for Y position, you can't specify a line higher than 255 - you need to do two wait commands).

ALSO, it makes it even more complicated if you have a second copper display (say, a UI bar at the bottom). It may be a bit easier if you're exercising total control over the copper, but if you're using Blitz's copperlist commands it may be far more complicated to manage.

For that reason, with the Kiwi's Tale I opted to make the top display end just short of the 255 line, and use all of the space underneath that for UI.
earok is offline  
Old 26 February 2019, 21:52   #9
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
8-Way Scrolling Beta

Quote:
Originally Posted by earok View Post
Excellent!

There was one more thing I wanted to bring up. You might have noticed that the screen height the example isn't exactly fullscreen, that's indeed due to complications around having the vertical wrap past line 255.

However, it's perfectly possible to do so, but it's a little more tricky. You do indeed need to use CopperEnd in that case (and ONLY when the wrap is beyond line 255). On top of that, you need to make sure you run at least two wait commands to get to the correct line (since the wait command uses bytes for Y position, you can't specify a line higher than 255 - you need to do two wait commands).

ALSO, it makes it even more complicated if you have a second copper display (say, a UI bar at the bottom). It may be a bit easier if you're exercising total control over the copper, but if you're using Blitz's copperlist commands it may be far more complicated to manage.

For that reason, with the Kiwi's Tale I opted to make the top display end just short of the 255 line, and use all of the space underneath that for UI.
Thanks, that's good to know! I will stick to a screen height like this to avoid complications, there's still plenty of room.

I have now almost managed to get 8-way tilemap scrolling to work using coppersplit+corkscrew by looking at http://aminet.net/package/dev/src/ScrollingTrick and the devnotes for Kiwi's Tale.

I would be super grateful if somebody else could have a look at what's wrong. The variable names are the same as in the ScrollingTrick examples and this demo is based on "Scroller_XYLimited". There are sources and html explanations in ScrollingTrick.lha.

The problem: When scrolling down-right there can be graphical errors of tile-wide lines. This is caused by corkscrew scrolling but for some reason I can't repair it. The repairing when switching from left-right or vice-versa is working.

Code:
; ****************************************************
;
; Single buffer 8-way tilemap scrolling demo (corkscrew+coppersplit)
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
; and earoks dev notes for Kiwi's Tale
;
; TODO: Fix graphic glitch when scrolling down-right (tile needs repairing)
; TODO: Implement double buffering
;
; In order to use the Bitmap newtype, include the resident file
; Blitzlibs:Bb2objtypes.res in the residents list in the compiler options.
;
; ****************************************************

;INCLUDE "helper_functions.bb2"

; Enable running from Workbench
WBStartup

; Set default type to word
DEFTYPE .w

; Set up interrupt 5 so we can cap to 25fps etc.
vb=0
SetInt 5
  vb+1
End SetInt

; Macros

; Get a tile from the tilemap array
; The bitwise AND 255 is for reading the byte value as unsigned
Macro GetTile
  (map(`1, `2) & 255)-1
End Macro
; Round down value to nearest tile width
; -16 is the same as ~(#TILE_W-1)
Macro RoundToBlockWidth
  `1 & -16
End Macro
; Round down value to nearest tile width
Macro RoundToBlockHeight
  `1 & -16
End Macro
; Frame (for debugging)
Macro Frame
  Box `1+1,`2+1,`1+14,`2+14,`3
End Macro

; Constants
#SCR_W=320        ; Width of visible screen
#SCR_H=208        ; Height of visible screen
#HUD_H=40         ; Height of HUD
#TILE_W=16        ; Width of tiles
#TILE_H=16        ; Height of tiles
#TILE_XSHIFT=4    ; Set according to #TILE_W (16->4, 32->5)
#TILE_YSHIFT=4    ; Set according to #TILE_H (16->4, 32->5)
#MAP_W=82         ; Tilemap width (number of tiles wide)
#MAP_H=51         ; Tilemap height (number of tiles high)
#SCROLL_SPEED=1   ; Scroll speed, this equals the number of tiles that needs to be drawn every frame

; Calculated constants (from constants above)
#SCR_XCOUNT=10                     ; Total number of screens horisontally in tilemap
#TILE_XPAD=#TILE_W                 ; The horisontal tile padding, for each side
#TILE_YPAD=#TILE_H                 ; The vertical tile padding 
#TILE_XANDNOT=0-#TILE_W            ; Used for inverted bitshift AND to get nearest multiple of TILE_W
#TILE_YANDNOT=0-#TILE_H            ; Used for inverted bitshift AND to get nearest multiple of TILE_H
#BM_W=#SCR_W+#TILE_XPAD*2          ; Buffer bitmap width (screen width + padding)
#BM_H=#SCR_H+#TILE_YPAD*2          ; Buffer bitmap height (screen height + padding)
#BUFFER_H=#BM_H                    ; 
#BM_TILES_X=#BM_W/#TILE_W          ; Number of tiles that fits horisontally on the buffer bitmap
#BM_TILES_Y=#BM_H/#TILE_H          ; Number of tiles that fits vertically on the buffer bitmap
#MAP_XMAX=#MAP_W*#TILE_W-#SCR_W-#TILE_W*2 
#MAP_YMAX=#MAP_H*#TILE_H-#SCR_H-#TILE_H*2   
#TWOBLOCKS=#BM_TILES_X-#TILE_H 
#TWOBLOCKSTEP=#TWOBLOCKS

; Keyboard etc. constants
#KEY_UP=$4C
#KEY_DOWN=$4D
#KEY_LEFT=$4F
#KEY_RIGHT=$4E
#KEY_ESCAPE=$45 
#KEY_BACKSPACE=$41
#DIR_NONE=0
#DIR_UP=1
#DIR_DOWN=2
#DIR_LEFT=3
#DIR_RIGHT=4      

; Tiles bitmap
#TILECOUNT_X=19       ; The number of tiles horisontally in the tiles bitmap
#TILECOUNT_Y=12       ; The number of tiles vertically in the tiles bitmap
#TILE_BLUE=205
#TILE_YELLOW=207
#TILE_ORANGE=208

#WHITE=18
#YELLOW=19
#TURQOISE=20
#ORANGE=21
#PINK=22

; Global variables
db.b=0                ; Keeps track of double buffer bitmap used (not in use currently)
x=0
y=0
x2=0
y2=0
ymax=0
i=0
mapx=0
mapy=0
tile=0
map_w=0
map_h=0
mapposx=0               ; Map X position, increments infinitely
mapposy=0
blit_yoffset.b=0      ; Y offset for blitting due to corkscrew scroll
scroll_dir_prev.b=#DIR_NONE
bp.l=0
videoposx=0
videoposy=0
show_y=0
splitline=0
splitoffset=0

; Create two bitmaps for double buffered display
BitMap 0,#BM_W,#BUFFER_H+20,5
BitMap 1,#BM_W,#BUFFER_H+20,5
BitMap 2,#SCR_W,#HUD_H,5

; Create a bitmap for the tiles
BitMap 3,#TILECOUNT_X*#TILE_W,#TILECOUNT_Y*#TILE_H,5 

; Load the tiles to bitmap 2
LoadBitMap 3,"tiles.iff"

; Load the palette from the same image
LoadPalette 0,"tiles.iff"

; Create shapes for all the tiles (increase the max number of shapes in compiler options to 255)
i = 0
For y=0 To #TILECOUNT_Y-1
  For x=0 To #TILECOUNT_X-1
    GetaShape i, x LSL #TILE_XSHIFT, y LSL #TILE_YSHIFT, #TILE_W, #TILE_H
    i+1
  Next
Next

; Helper tiles for debugging
;LoadBitMap 3,"tiles_helpers.iff"
;helpers_start=i
;For i=helpers_start To helpers_start+5
;  GetaShape i, i LSL #TILE_XSHIFT, 0, #TILE_W, #TILE_H
;Next

; Free the bitmap used to load the tiles
Free BitMap 3

; Read the tile map
If ReadFile(0,"world.map")
  ; First two words are width and height of tilemap
  ReadMem 0,&map_w,2
  ReadMem 0,&map_h,2
  ; Create a two dimensional array for the tilemap
  Dim map.b(map_w-1, map_h-1)
  ; Read the entire tilemap into the array
  ReadMem 0,&map(0,0),map_w*map_h
  ; Close the tilemap file
  CloseFile 0
EndIf

; Wait for disk activity to finish before going into Blitz mode
VWait 100 

; Go into blitz mode and enable blitzkeys
BLITZ
BlitzKeys On

; Create copperlists for the display
InitCopList 0,44,#SCR_H,$15,8,32,12    ; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours, 12 copper commands
InitCopList 1,46+#SCR_H,#HUD_H,$15,8,32,12    ; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours, 12 copper commands

; Create a display using copperlist 0 and 1
CreateDisplay 0,1

; Use palette 0 (second parameter) for copperlist 0 (first parameter)
DisplayPalette 0,0  
DisplayPalette 1,0   

; Output text to bitmap 2 (HUD)
BitMapOutput 2
Colour 18,4
Use BitMap 2
Cls 4

; Use first bitmap
Use BitMap db

; Draw tiles to fill the whole bitmap
For y = 0 To #BM_TILES_Y-1
  For x = 0 To #BM_TILES_X-1
    ; Map is exported from Tiled, so the value 0 means no tile, because of that the tile value is reduced by one
    Block !GetTile{x,y}, x LSL #TILE_XSHIFT, y LSL #TILE_YSHIFT
  Next
Next

; Copy bitmap 0 to bitmap 1 so both double buffer bitmaps are identical
CopyBitMap 0,1

; Display HUD bitmap on second copperlist
DisplayBitMap 1,2,0,0

; Get the pointer to the front buffer bitmap
*b.bitmap = Addr Bitmap(db)
*b\_xclip = $7FFF

block_videoposy=0
stepx=0
stepy=0
mapblocky=0
mapblockx=0
time_taken=0
time_max=0
timeq.q=0.0
time_dir_pressed=0

; The main loop
MainLoop:
Repeat

  ; Wait for vertical blank
  VWait 1
  vb=0

  ; Set screen position
  show_y = (videoposy+#TILE_H) MOD #BM_H
  splitline = #BM_H-show_y
 
  ; Show bitmap 0 on copperlist 0 at offset
  DisplayBitMap 0,db,mapposx+#TILE_XPAD,show_y
  ; Switch to other double buffer bitmap
  ; db = 1-db
  ; Use BitMap db
  ;StartTimer{}
  ; Reset the copper, this is needed for the library to work
  CopperReset 0, 0
  
  ; Update the copperlist
  ; Are we displaying over the bottom edge?
  
  If splitline < #SCR_H
    ; Scroll to the correct position
    splitoffset = (mapposx+#TILE_XPAD) / 8
    ; Wait until the bottom edge       
    CopperWait 0, splitline + 44         
    ; Reset the display to the top of the bitmap
    bp.l = *b\_data[0] + splitoffset
    CopperMove $0e0, bp lsr 16
    CopperMove $0e2, bp & $ffff
    bp.l = *b\_data[1] + splitoffset
    CopperMove $0e4, bp lsr 16
    CopperMove $0e6, bp & $ffff
    bp.l = *b\_data[2] + splitoffset
    CopperMove $0e8, bp lsr 16
    CopperMove $0ea, bp & $ffff
    bp.l = *b\_data[3] + splitoffset
    CopperMove $0ec, bp lsr 16
    CopperMove $0ee, bp & $ffff
    bp.l = *b\_data[4] + splitoffset
    CopperMove $0f0, bp lsr 16
    CopperMove $0f2, bp & $ffff 
  Else 
    ; If we're not displaying over the bottom edge, just wipe out our copper commands
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
  EndIf
  
  
  ; Reset the max value for the timer?
  If RawStatus(#KEY_BACKSPACE)
    time_max=0
  EndIf
  
  ; Scrolling up?
  If RawStatus(#KEY_UP) 
    BSR ScrollUp : BSR ScrollUp : BSR ScrollUp
  Else
    ; Scrolling down?
    If RawStatus(#KEY_DOWN)
      BSR ScrollDown : BSR ScrollDown : BSR ScrollDown
    EndIf
  EndIf
  ; Scrolling left?
  If RawStatus(#KEY_LEFT)
    BSR ScrollLeft : BSR ScrollLeft : BSR ScrollLeft
  Else
    ; Scrolling right?
    If RawStatus(#KEY_RIGHT)
      BSR ScrollRight : BSR ScrollRight : BSR ScrollRight
    EndIf
  EndIf
  
  ; Stop timer
  ;time_taken=EndTimer{}

  ; Check the result of the timer before printing
  If time_taken>time_max
    time_max=time_taken
    timeq=time_max*time_constant
  EndIf
  
  ; Print stuff to HUD
  Locate 0,0 : Print "mapposx:",mapposx,",mapposy:",mapposy,"      "
  Locate 0,1 : Print "mapblockx:",mapblockx,"mapblocky:",mapblocky,"      "
  Locate 0,2 : Print "stepx:",stepx,",block_videoposy:",block_videoposy,"      "
  Locate 0,3 : Print "timer:",0,",timer_max:",timeq,"us      "
  
Until RawStatus(#KEY_ESCAPE)=-1

; Quit game
End

ScrollUp:
  If mapposy > 0
    ; Increase position first
    mapposy-1
    mapblocky=mapposy LSR #TILE_YSHIFT
    stepy=mapposy & (#TILE_H-1)
    videoposy-1
    If videoposy<0 
      videoposy+#BM_H
    EndIf
    If stepy = (#TILE_H-1)
      block_videoposy-#TILE_H
      If block_videoposy<0 
        block_videoposy+#BM_H
      EndIf
      If stepx > 0 
        ; step 1: blit the 1st block in the fillup
        mapx=mapblockx+#BM_TILES_X
        mapy=mapblocky+1
        x=!RoundToBlockWidth{videoposx}
        y=(block_videoposy+#TILE_H) MOD #BM_H
        Block !GetTile{mapx,mapy}, x+#BM_W, y
        ; step 2: remove the (former) bottommost fill up block
        ; we blit a 'left' block
        If stepx+1 < #BM_TILES_Y
          mapy=stepx+1
          ;Else
          ;  mapy=#BM_TILES_Y-1
          ;EndIf
          y = (block_videoposy+(mapy LSL #TILE_YSHIFT)) MOD #BM_H
          mapx-#BM_TILES_X
          mapy+mapblocky
          Block !GetTile{mapx,mapy}, x, y
          ; Repair broken tile if needed
          If scroll_dir_prev=#DIR_RIGHT ; OK!!!
            If stepx+2 < #BM_TILES_Y
              y2=y+#TILE_H
              If y2>=#BM_H Then y2-#BM_H
              Block !GetTile{mapx,mapy+1}, x, y2
            EndIf
          EndIf
          ; Set previous direction as left
          scroll_dir_prev=#DIR_LEFT
        EndIf
      EndIf
    EndIf
    mapx=stepy
    mapy=mapblocky
    y=block_videoposy
    If mapx >= #TWOBLOCKSTEP
      ; blit only one block
      mapx+#TWOBLOCKSTEP
      x=mapx LSL #TILE_XSHIFT + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      Block !GetTile{mapx,mapy}, x, y
    Else
      ; Draw two tiles        
      mapx=mapx LSL 1
      x=mapx LSL #TILE_XSHIFT + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      Block !GetTile{mapx,mapy}, x, y
      Block !GetTile{mapx+1,mapy}, x+#TILE_W, y
    EndIf
  EndIf
  RTS
  
ScrollDown:
  If mapposy < #MAP_YMAX
    ; Get positions
    mapx = stepy
    mapy = mapblocky + #BM_TILES_Y
    y = block_videoposy
    If mapx >= #TWOBLOCKSTEP
      ; blit only one block
      mapx+#TWOBLOCKSTEP
      x=mapx LSL #TILE_XSHIFT + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      Block !GetTile{mapx,mapy}, x, y
    Else
      ; Blit two blocks
      mapx = mapx LSL 1
      x = mapx LSL #TILE_XSHIFT + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      ; Get tiles and draw them
      Block !GetTile{mapx,mapy}, x, y
      Block !GetTile{mapx+1,mapy}, x+#TILE_W, y
    EndIf
    ; Increase position
    mapposy+1
    mapblocky=mapposy LSR #TILE_YSHIFT
    stepy=mapposy & (#TILE_H-1)
    videoposy+1
    If videoposy>=#BM_H 
      videoposy-#BM_H
    EndIf
    ; If stepy=0 then we need to fix the horisontal fillup row
    If stepy=0
      block_videoposy+#TILE_H
      If block_videoposy>=#BM_H
        block_videoposy-#BM_H
      EndIf
      If stepx > 0
        ; step 1: blit the 1st block in the fillup row (y)
        mapx=mapblockx
        mapy=mapblocky
        x=!RoundToBlockWidth{videoposx}
        y=block_videoposy ; should be this value already
        Block !GetTile{mapx,mapy}, x, y
        ; step 2: blit the (new) bottommost fill up block
        ; we blit a 'right-block'
        If stepx < #BM_TILES_Y
          mapy=stepx
        Else
          mapy=#BM_TILES_Y-1
        EndIf
        x+#BM_W
        y=(block_videoposy+(mapy LSL #TILE_YSHIFT)) MOD #BM_H
        y2=(block_videoposy+((mapy+1) LSL #TILE_YSHIFT)) MOD #BM_H
        mapx+#BM_TILES_X
        mapy+mapblocky ; Can get out of range, does map need to be one tile higher?
        ; Repair broken tile if needed
        ; There's something wrong with down-right scrolling!
        ; If scroll_dir_prev=#DIR_LEFT 
          ;If stepx < #BM_TILES_Y-1
            ; y2=y-#TILE_H
            ; If y2<0 Then y2+#BM_H
            ;Block !GetTile{mapx,mapy+1}, x, y2
            ;!Frame{x,y,#YELLOW}
          ;EndIf
        ; EndIf
        Block !GetTile{mapx,mapy}, x, y
        ;!Frame{x,y,#WHITE}
        ; Set previous direction as right
        scroll_dir_prev=#DIR_RIGHT
      End If
    EndIf
  EndIf
  RTS
  
ScrollLeft:
  If mapposx > 0
    ; Decrease position
    mapposx-1
    mapblockx=mapposx LSR #TILE_XSHIFT
    stepx=mapposx & (#TILE_W-1)
    videoposx-1
    If stepx = (#TILE_W-1)
      ; step 1: blit the block which came in at the left side,
      ;         which might or might not be a fill up block
      mapx=mapblockx
      mapy=mapblocky
      If stepy > 0
        ; there is a fill up block 
        mapy+#BM_TILES_Y
      EndIf
      x=!RoundToBlockWidth{videoposx}
      y=block_videoposy
      ; Mostly ok
      Block !GetTile{mapx,mapy}, x, y
      ; step 2: remove the (former) rightmost fillup-block
      mapx=stepy
      If mapx > 0
        ; there is a fill up block
        If mapx >= #TWOBLOCKSTEP
          mapx+#TWOBLOCKSTEP
        Else
          mapx=mapx LSL 1 ; mapx=mapx*2
        EndIf
        x=!RoundToBlockWidth{videoposx}+(mapx LSL #TILE_XSHIFT) ; mapx*#TILE_W
        y=block_videoposy
        mapx+mapblockx
        mapy-#BM_TILES_Y
        ; Mostly ok
        Block !GetTile{mapx,mapy}, x, y
      EndIf
    EndIf  
    mapx=mapblockx
    mapy=stepx+1
    x=!RoundToBlockWidth{videoposx}
    y=(block_videoposy+(mapy LSL #TILE_YSHIFT)) MOD #BM_H
    mapy+mapblocky
    ; Repair broken tile if needed
    If scroll_dir_prev=#DIR_RIGHT ; OK!!!!
      If stepx+2 < #BM_TILES_Y
        y2=y+#TILE_H
        If y2>=#BM_H Then y2-#BM_H
        Block !GetTile{mapx,mapy+1}, x, y2
      EndIf
    EndIf
    If stepx+1 < #BM_TILES_Y ; Don't draw tiles every step, it's not needed/wanted
      Block !GetTile{mapx,mapy}, x, y
    EndIf
    If stepx > 0
      scroll_dir_prev=#DIR_LEFT
    Else
      scroll_dir_prev=#DIR_NONE
    EndIf
  EndIf
  RTS
  
ScrollRight:
  If mapposx < #MAP_XMAX
    mapx=mapblockx + #BM_TILES_X
    mapy=stepx+1
    x=!RoundToBlockWidth{videoposx}
    y=(block_videoposy+(mapy LSL #TILE_YSHIFT)) MOD #BM_H
    ;y2=(block_videoposy+((mapy-1) LSL #TILE_YSHIFT)) MOD #BM_H
    mapy+mapblocky
    ; Repair broken tile if needed
    If scroll_dir_prev=#DIR_LEFT 
      If stepx > 0 AND stepx < #BM_TILES_Y-1
        y2=y-#TILE_H
        If y2<0 Then y2+#BM_H
        Block !GetTile{mapx,mapy-1}, x+#BM_W, y2
      EndIf
    EndIf
    ; Blit one block
    If stepx+1 < #BM_TILES_Y ; Don't draw tiles every step, it's not needed/wanted
      Block !GetTile{mapx,mapy}, x+#BM_W, y
    EndIf
    ; Increase position
    mapposx+1
    mapblockx=mapposx LSR #TILE_XSHIFT
    stepx=mapposx & (#TILE_W-1)
    videoposx+1
    If stepx = 0
      ; step 1: blit the block which came in at the right side, ;         which is never a fill up block
      mapx=mapblockx+#BM_TILES_X-1
      mapy=mapblocky
      x=!RoundToBlockWidth{videoposx}+(#BM_TILES_X-1) LSL #TILE_XSHIFT
      y=block_videoposy
      ; Seems ok
      Block !GetTile{mapx,mapy}, x, y
      ; step 2: blit the (new) rightmost fillup-block
      mapx=stepy
      If mapx > 0
        ; there is a fill up block
        If mapx >= #TWOBLOCKSTEP
          mapx = mapx + (#TWOBLOCKSTEP-1)
        Else
          mapx = mapx LSL 1 - 1
        EndIf
        x=!RoundToBlockWidth{videoposx} + (mapx LSL #TILE_XSHIFT)
        y=block_videoposy
        mapx+mapblockx
        ; Seems ok
        Block !GetTile{mapx,mapy+#BM_TILES_Y}, x, y
      EndIf
    EndIf
    If stepx > 0
      scroll_dir_prev=#DIR_RIGHT
    Else
      scroll_dir_prev=#DIR_NONE
    EndIf
  EndIf
  RTS
EDIT: Removed attachment, new working version available.

Last edited by MickGyver; 11 March 2019 at 10:38. Reason: Removed the attachment due to updated version
MickGyver is offline  
Old 27 February 2019, 00:27   #10
Retro1234
Phone Homer
 
Retro1234's Avatar
 
Join Date: Jun 2006
Location: 5150
Posts: 5,775
If im correct the C Demo Scrolling trick uses the method were you draw behind and in front creating an identical image like this http://eab.abime.net/showthread.php?t=80646or for horizontal and vertical -
and no corkscrew is used ive only ever done 8 way scrolling like this and yes scrolling down right is the ultimate test - if you view the entire Bitmap save it as iff not just what is displayed on screen ie something like 640 *480 you will see it split into something like 4 identical pictures - when full scroll down right.

There must be a fairly simple formula for this something like screen width, height = number of tiles that must be drawn and height and width bimtmap must be to complete perfect down right scroll.

I never figured it out the formula and no one has ever published it to my knowledge I just guessed and worked on overkill to make sure I drew enough tiles etc.

and as you know Blitz has problems InitCopList corkscrew past 8191

Last edited by Retro1234; 27 February 2019 at 00:46.
Retro1234 is offline  
Old 27 February 2019, 07:20   #11
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by Retro1234 View Post
If im correct the C Demo Scrolling trick uses the method were you draw behind and in front creating an identical image like this http://eab.abime.net/showthread.php?t=80646or for horizontal and vertical -
and no corkscrew is used ive only ever done 8 way scrolling like this and yes scrolling down right is the ultimate test - if you view the entire Bitmap save it as iff not just what is displayed on screen ie something like 640 *480 you will see it split into something like 4 identical pictures - when full scroll down right.

There must be a fairly simple formula for this something like screen width, height = number of tiles that must be drawn and height and width bimtmap must be to complete perfect down right scroll.

I never figured it out the formula and no one has ever published it to my knowledge I just guessed and worked on overkill to make sure I drew enough tiles etc.

and as you know Blitz has problems InitCopList corkscrew past 8191
Thanks for the input, I didn't think of saving the bitmap for analysing, I will try that.

There are several scrolling methods explained in the ScrollingTrick archive. I'm trying to implement (almost there) the most efficient 8-way scrolling using a copper split for vertical scrolling and corkscrew for horisontal scrolling. The bitmap size needed is only a little more than screen size and incoming tiles are only drawn once.
MickGyver is offline  
Old 27 February 2019, 14:46   #12
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
This shows what's happening when scrolling down, then slightly right. It happens at certain x-positions only, sooo annoying, I'm so close to having this working.



The actual bitmap (thanks for the tip Retro1234)

MickGyver is offline  
Old 27 February 2019, 15:02   #13
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by MickGyver View Post
Thanks for the input, I didn't think of saving the bitmap for analysing, I will try that..

The demo programs in ScrollingTrick archive can be started with "HOW" parameter. Then the scrolling is disabled and you see on screen how the horizontal/vertical fillup columns are filled and readjusted while moving around.


Try something similiar with your code and compare.
aros-sg is offline  
Old 27 February 2019, 15:22   #14
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by MickGyver View Post
The actual bitmap (thanks for the tip Retro1234)

Hmm ... in theory the left side should be in false/different colors because of the plane shifting (if the bitmap is looked at the from fixed 0,0 position then the more to the right that you have scrolled, the more the new blocks have shifted into different planes. see scrollintrick demos with HOW param and keep scrolling to the right).
aros-sg is offline  
Old 27 February 2019, 18:14   #15
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by aros-sg View Post
Hmm ... in theory the left side should be in false/different colors because of the plane shifting

Or wait ... is that a non-interleaved bitmap? Scrolling algorithm would need modifications for that.
aros-sg is offline  
Old 27 February 2019, 18:48   #16
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by aros-sg View Post
Or wait ... is that a non-interleaved bitmap? Scrolling algorithm would need modifications for that.
Thanks for helping! That is a non-interleaved bitmap yes. My implementation seems to work fine except for that one small down-right graphic glitch. The tilemap I'm testing with is 80x50 tiles or 1280x800px big. I'm going to look into interleaved mode now.
MickGyver is offline  
Old 27 February 2019, 19:02   #17
Retro1234
Phone Homer
 
Retro1234's Avatar
 
Join Date: Jun 2006
Location: 5150
Posts: 5,775
cools pics, love stuff like that
Wheres the error? those 6 green lines? looks like the tiles are just slightly wrong Y position?
Retro1234 is offline  
Old 27 February 2019, 19:14   #18
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by Retro1234 View Post
cools pics, love stuff like that
Wheres the error? those 6 green lines? looks like the tiles are just slightly wrong Y position?
Those six green lines yes, they appear when scrolling down and then right, but only when scrolling down at certain x-values. My screen is only 208px high, the ScrollingTrick demos assume a 256px high screen so I have had to modify some things that could have created this bug. I'm going to try to convert this example to use interleaved shapes and bitmaps (if I can) to see if works any better. I somehow suspect that I shouldn't have to use interleaved bitmaps since the demo is otherwise working fine but you'll never know.
MickGyver is offline  
Old 27 February 2019, 19:46   #19
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by MickGyver View Post
I somehow suspect that I shouldn't have to use interleaved bitmaps since the demo is otherwise working fine but you'll never know.

If your code isn't using the "saveword" optimization as in demo sources (only save/restore 2 bytes which are ~"trashed" when left/right scrolling, instead of a whole tile/block) then that can be so.


But there are some differences for algorithm between interleaved and non interleaved bitmaps. For interleaved bitmap to be able to scroll 16 pixels to the right, the bitmap needs to only have additional 2 extra bytes (32 pixels -> 4 bytes -> 320 pixels -> 40 bytes). For a non interleaved bitmap that would be 2*numplanes extra bytes (32 pixels -> 4 * numplanes bytes, 320 pixels -> 40 * numplanes bytes).


Example: interleaved bitmap at start x pixel position 0 goes from 0x10000 to 0x20000. At start x pixel position 16 it goes from 0x10002 to 0x20002. That's the whole bitmap with all planes. Because interleaved bitmap is basically a bit like a vertical strecthed single plane bitmap.


For a non interleaved 2 plane bitmap at start x pixel position 0: plane 1 0x10000 to 0x11000. plane 2 0x12000 to 0x13000. At pixel position 16: plane 1 0x10002 to 0x11002. plane 2 0x12002 to 0x130002. Each plane needs an additional 2 bytes.
So in total 4 extra bytes.
aros-sg is offline  
Old 27 February 2019, 19:51   #20
Retro1234
Phone Homer
 
Retro1234's Avatar
 
Join Date: Jun 2006
Location: 5150
Posts: 5,775
Yeah guess is all that's happening is corkscrew is out of sync and not on correct Y position, 1 pixel out.
Retro1234 is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Tilemap Designer for Blitz Basic Havie Coders. Blitz Basic 5 16 June 2014 00:19
tilemap.library Samurai_Crow Coders. System 4 02 November 2011 21:08
smooth scrolling.is it possible? kirk support.WinUAE 30 01 October 2007 13:57
Tilemap + Scrolling routines source code Ultron Coders. General 0 02 April 2007 01:00
0.8.21 R2: Scrolling issues andreas support.WinUAE 0 12 March 2002 08:14

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 20:38.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.10544 seconds with 14 queries