English Amiga Board


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

 
 
Thread Tools
Old 27 February 2019, 22:01   #21
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by aros-sg View Post
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.
Again, thanks! Yeah, I'm not saving/restoring the word pointer, instead I'm drawing a whole tile to repair "broken" tiles. I converted the example to work with interleaved shapes and bitmaps. The problem remains, so the bug can probably be fixed for also for "normal" albm mode.

Funny thing actually, interleaved shapes and bitmaps made the scrolling algorithm about twice as slow (at least in WinUAE, A1200 config), wth, it's supposed to be faster. Scrolling in one direction three pixels takes ~650µs in normal mode and ~1250µs using interleaved shapes and bitmaps.
EDIT: The above is BS, it was probably a glitch in the matrix, testing it again today gave me the results (when scrolling horisontally 3px at top): ALBM: ~550µs, ILBM: ~450µs.

Quote:
Originally Posted by Retro1234 View Post
Yeah guess is all that's happening is corkscrew is out of sync and not on correct Y position, 1 pixel out.
I guess so, can't find the reason for it though.

Last edited by MickGyver; 28 February 2019 at 13:03.
MickGyver is offline  
Old 28 February 2019, 21:55   #22
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,543
@MickGyver

With Kiwi's Tale and the revised AlarCity engine, I approached scrolling in an entirely different fashion based on discussions with Alpine9000.

The principle of it is - there's an array that contains dirty blocks that need to be reblitted. That's basically it. The advantages for such an approach are:
  • Relative simplicity of code
  • Easy handling of blocks that need to be redrawn (eg, imagine a 'door' tile that opens, or a tile that animates every frame such as a water edge)
  • Easy way to reblit tiles that have been made dirty by drawing bobs (no need to do QBLIT or BBLIT, just using BLIT and BLOCK will suffice)
  • Which is to say, no need for a "third" buffer to restore from. Saves memory and blitting time.
  • Easy handling for a flicker free, double buffer system
  • Easy way to redraw the entire map (simply set the entire array as dirty)
  • Can easily handle scrolling no matter how many tiles you've scrolled in either direction in a single frame

To start with, I declare a few different arrays at the top of my code

Code:
;The width of the bitmap in number of tiles
#XFillSize = 19

;The height of the bitmap in number of tiles
#YFillSize = 16

;Number of buffers (just front and back buffer)
#NumOfBuffers=2

;The maximum level size supported
#MaxLevelSize=256

;My dirty buffer
Dim DirtyBuffer.l(#YFillSize,#NumOfBuffers)

;The last camera X position for each buffer
Dim LastDrawX(#NumOfBuffers)

;The last camera Y position for each buffer
Dim LastDrawY(#NumOfBuffers)

;Look up tables that convert a "real" tile X/Y position to the position on the wrapped bitmap
;Much faster than using Mod at real time
Dim XLookup(#MaxLevelSize)
Dim YLookup(#MaxLevelSize)
for i = 0 to 255
    XLookup(i) = i Mod #XFillSize
    YLookup(i) = i Mod #YFillSize
next
That should be relatively straight forward, but it might be confusing why the Dirty Buffer only has dimensions for the Y coordinate and backbuffer, but not the X coordinate. The reason is simply that the dirty X tile is flagged using bit operations. This gives an easy way to check an entire row to see if any tiles need to be redrawn (if DirtyBuffer(Y,BackBuffer)=0, I know that the entire row is clean and doesn't need to be redrawn).

Code:
;Translate the Camera position to Tile position
DrawX = CameraX lsr 4
DrawY = CameraY lsr 4

;How many tiles have we scrolled in either direction?
;Clamp this value to make sure we don't mark values outside of the buffer as dirty
XDelta = QLimit(DrawX - LastDrawX(BackBuffer),-#XFillSize+1,#XFillSize-1)
YDelta = QLimit(DrawY - LastDrawY(BackBuffer),-#YFillSize+1,#YFillSize-1)

;We're scrolling on the X Axis
if XDelta
	;We're scrolling left
	while XDelta < 0
		LastDrawX(BackBuffer) - 1
		wrappedx = XLookup(LastDrawX(BackBuffer))
		y = #YFillSize
		while y
			y-1
			DirtyBuffer(y,BackBuffer) BitSet wrappedx ;Set this one tile as dirty
		wend
		XDelta + 1
	wend            
	;We're scrolling right
	while XDelta > 0
		LastDrawX(BackBuffer) + 1
		wrappedx = XLookup(LastDrawX(BackBuffer) + #XFillSize - 1)
		y = #YFillSize
		while y
			y-1
			DirtyBuffer(y,BackBuffer) BitSet wrappedx ;Set this one tile as dirty
		wend
		XDelta - 1
	wend                 
endif

;We're scrolling on the Y Axis
if YDelta
	;We're scrolling up
	while YDelta < 0
		LastDrawY(BackBuffer) - 1
		wrappedy = YLookup(LastDrawY(BackBuffer))
		DirtyBuffer(wrappedy,BackBuffer) = -1 ;Set the whole row as dirty
		YDelta + 1
	wend
	;We're scrolling down
	while YDelta > 0
		LastDrawY(BackBuffer) + 1
		wrappedy = YLookup(LastDrawY(BackBuffer) + #YFillSize - 1)
		DirtyBuffer(wrappedy,BackBuffer) = -1 ;Set the whole row as dirty
		YDelta - 1                
	wend
endif        

;When we get here, check each row if dirty, and reblit the tiles if needed
y = #YFillSize
while y
	y-1
	wrappedy = YLookup(y+DrawY)
	row.l = DirtyBuffer(wrappedy,BackBuffer)
	if(row) ;Skip checking the row if there are no dirty tiles
		x = #XFillSize
		while x
			x-1
			
			wrappedx = XLookup(x+DrawX)
			if row BITTST wrappedx

				;Note that here my tile bitmap is a single long bitmap with only one column			
				tile = !GetTile{x + DrawX,y + DrawY}
				BlockScroll 0,tile * 80,16,80,(x+DrawX) * 16,((y+DrawY) * 80) mod #BufferHeightMax,#BitMap_Tiles
				;Hmm - I should be using a Look Up table for the Y coordinate above. Also LSL 4 rather than *16 for X
				
			endif

		wend
		DirtyBuffer(wrappedy,BackBuffer)=0 ;The entire row is now clean
	endif
wend
Hopefully that all makes sense. I'm not entirely sure the code above 'works' since I've copied and pasted, made some edits for clarification, but hopefully it'll be clear enough.

Note that my tiles are not literally 16x80. They're 16x16 with 5 bitplanes, but both the source and destination bitmaps are interleaved. I handle this in Blitz by treating the interleaved bitmaps like they were tall, single bitplane bitmaps.
earok is offline  
Old 28 February 2019, 22:26   #23
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by earok View Post
Hopefully that all makes sense. I'm not entirely sure the code above 'works' since I've copied and pasted, made some edits for clarification, but hopefully it'll be clear enough.
Thanks! So you ended up using blockscroll instead of coppersplit + corkscrew? Isn't that much slower? Did you get stuck with the coppersplit method for Kiwi's tale (I would love to know before I put too much time into this method)?

Last edited by MickGyver; 01 March 2019 at 16:42.
MickGyver is offline  
Old 28 February 2019, 22:30   #24
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,543
Quote:
Originally Posted by MickGyver View Post
Thanks! So you ended up using blockscroll instead of coppersplit + corkscrew? Isn't that much slower? Did you get stuck with the coppersplit method for Kiwi's tale (I would love to know before I put too much time into this method)?
No worries

I'm still using coppersplit+corkscrew, I'm using using the blockscroll command instead of block in order not to have to create a shape for each tile.
earok is offline  
Old 01 March 2019, 08:11   #25
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by earok View Post
No worries

I'm still using coppersplit+corkscrew, I'm using using the blockscroll command instead of block in order not to have to create a shape for each tile.
Ok, I get it now, thanks! I was too tired to read the code properly last night. That is a smart solution, thanks for sharing!

I guess the issue that I'm having is a special case where some tile is drawn where it shouldn't (wrong x-offset) due to corkscrew scrolling.
MickGyver is offline  
Old 01 March 2019, 15:36   #26
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by MickGyver View Post
That is a smart solution, thanks for sharing!

Except he seems to always blit complete row of tiles or complete column of tiles even when just scrolling one single pixel. That's super lame ;-p (I can say so, because ScrollingTrick.lha was written by me ...)



Quote:

I guess the issue that I'm having is a special case where some tile is drawn where it shouldn't (wrong x-offset) due to corkscrew scrolling.
It's more likely to do with what in original examples saveword stuff is doing. Horizontal scrolling is tricky because it basically makes the bitmap change it's position in memory.
Example tilemap with first screen full of 1-Tiles and screen to the right full of 2-Tiles, scrolled to X position 3:

Code:
21111111
21111111
21111111
11111111
11111111
11111111
Now depending on how you reached X position 3 (scrolled there from the right, or scrolled there from the left) either the last (plane)line of bottommost "2" Tile or the first (plane)line of the "1" Tile below it are trashed/overwritten.


So if now you were to scroll down this must be taken into account:


Code:
33333333
21111111
21111111
21111111
11111111
11111111
Here the middle "2" was already there, but may have been trashed because of previous X scrolling having been negative (to the left), so needs repair or repaint. And the newly blitted "2" at the bottom need to save for future scrolling the info that it will have trashed the 1 below it = basically by saying last_x_scroll == right_scroll. (Right scrolling trashes tile below. Left scrolling trashes tile above).
aros-sg is offline  
Old 01 March 2019, 16:22   #27
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by aros-sg View Post
ScrollingTrick.lha was written by me ...
Oh, you wrote it, it's a brilliant algorithm!

Quote:
It's more likely to do with what in original examples saveword stuff is doing. Horizontal scrolling is tricky because it basically makes the bitmap change it's position in memory.
Example tilemap with first screen full of 1-Tiles and screen to the right full of 2-Tiles, scrolled to X position 3:

Code:
21111111
21111111
21111111
11111111
11111111
11111111
Now depending on how you reached X position 3 (scrolled there from the right, or scrolled there from the left) either the last (plane)line of bottommost "2" Tile or the first (plane)line of the "1" Tile below it are trashed/overwritten.


So if now you were to scroll down this must be taken into account:


Code:
33333333
21111111
21111111
21111111
11111111
11111111
Here the middle "2" was already there, but may have been trashed because of previous X scrolling having been negative (to the left), so needs repair or repaint. And the newly blitted "2" at the bottom need to save for future scrolling the info that it will have trashed the 1 below it = basically by saying last_x_scroll == right_scroll. (Right scrolling trashes tile below. Left scrolling trashes tile above).
Thanks for the thorough explanation! The repairs needed from horisontal scrolling are mostly under control (I haven't implemented it yet for scrolling up and down), but I'm drawing a whole tile instead of just saving the word and pointer (I had some problems with storing only the word in BB2, I did it by using Peek/Poke but it seemed slow).

I think I have now narrowed down the problem to something related to what you explained above. Since the height of the screen in my example is only 208, there are a few steps where no tile is needed to be drawn when scrolling horisontally. When offsetting the horisontal fillup column downward like you explained above (at stepy=0, stepx>0), if stepx>=#BITMAPBLOCKSPERCOL then the first block of the vertical fillup row (yellow, blue and white squares) will overwrite one planeline of the last tile in the horisontal fillup column (pink squares).

MickGyver is offline  
Old 01 March 2019, 21:21   #28
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by earok View Post
With Kiwi's Tale and the revised AlarCity engine, I approached scrolling in an entirely different fashion based on discussions with Alpine9000.
I have your method of scrolling working now, I must say, it's a very "convenient" one. The ScrollingTrick method seems to be about five times faster BUT it is more complex. I still hope I can figure out the remaining bugs in that method. Do you mind if I upload a working version of your method here when I have cleaned it up?

Quote:
Hmm - I should be using a Look Up table for the Y coordinate above. Also LSL 4 rather than *16 for X
I tested it, it's worth it!

Last edited by MickGyver; 01 March 2019 at 21:58.
MickGyver is offline  
Old 04 March 2019, 15:56   #29
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by earok View Post
With Kiwi's Tale and the revised AlarCity engine, I approached scrolling in an entirely different fashion based on discussions with Alpine9000.
I made these optimisations to the scrolling algorithm:
  • Instead of using a single column of tiles, I changed to a single row of tiles. With this, a multiplication can be replaced with left shift and the iff file is also less than half the size.
  • Created a lookup table for the tile y-position.
  • Implemented the while-loop for x-scrolling in assembly.
  • Replaced multiplications and divisions with lsl and lsr where possible.
  • Calculating x+DrawY and y+DrawY once only.

These things seem to have sped up the algorithm according to these figures (WinUAE, A1200 configuration):

Code:
Before opt.
------------
R/L:  3680us
U/D:  2825us
Diag: 5920us

After opt.
------------
R/L:  1960us
U/D:  1200us
Diag: 2890us
The updated code:
Code:
#TileHeight1P=80

Dim XLookup(#MaxLevelSize)
Dim YLookup(#MaxLevelSize)
Dim YModLookup(#MaxLevelSize)
For i = 0 To #MaxLevelSize-1
  XLookup(i) = i MOD #XFillSize
  YLookup(i) = i MOD #YFillSize
  YModLookup(i) = (i * #TileHeight1P) MOD (#BufferHeightMax)    #BufferHeight)*#BufferDepth
Next


Code:
;Translate the Camera position to Tile position
DrawX = CameraX LSR #TileXShift 
DrawY = CameraY LSR #TileYShift

;How many tiles have we scrolled in either direction?
;Clamp this value to make sure we don't mark values outside of the buffer as dirty
XDelta = QLimit(DrawX - LastDrawX(BackBuffer),-#XFillSize+1,#XFillSize-1)
YDelta = QLimit(DrawY - LastDrawY(BackBuffer),-#YFillSize+1,#YFillSize-1)

; We're scrolling on the X Axis
If XDelta
  ; Set HeavyLoad flag
  HeavyLoad = True
  ; We're scrolling left
  While XDelta < 0
    LastDrawX(BackBuffer) - 1
    wrappedx = XLookup(LastDrawX(BackBuffer))
    ; This assembly loop is about 200us faster than the basic equivalent below
    GetReg d0,wrappedx ; Set d0 to wrappedx
    GetReg d1,&DirtyBuffer(0,BackBuffer) ; Set d1 to the address of DirtyBuffer(0,BackBuffer)
    MOVE.l d1,a0 ; Move the address above to a0
    MOVE.w #YFillSize-1,d2 ; Set d2 to #YFillSize-1 (for loop, using .w because DBRA operates on .w)
  LoopLeft:
    MOVE.l (a0),d1 ; Copy the long value at a2 to d1
    BSET.l d0,d1 ; Set wrappedx bit of d1
    MOVE.l d1,(a0)+ ; Copy d1 back to address a0, then increase a0 by 4 (l)
    DBRA   d2,LoopLeft ; Decrease the value of d0 and jump to LoopLeft if value is > -1
    ; y = #YFillSize
    ; While y
      ; y-1
      ; DirtyBuffer(y,BackBuffer) BitSet wrappedx ; Set this one tile (bit) as dirty
    ; Wend
    XDelta + 1
  Wend            
  ; We're scrolling right
  While XDelta > 0
    LastDrawX(BackBuffer) + 1
    wrappedx = XLookup(LastDrawX(BackBuffer) + #XFillSize-1)
    ; This assembly loop is about 200us faster than the basic equivalent below
    GetReg d0,wrappedx ; Set d0 to wrappedx
    GetReg d1,&DirtyBuffer(0,BackBuffer) ; Set d1 to the address of DirtyBuffer(0,BackBuffer)
    MOVE.l d1,a0 ; Move the address above to a0
    MOVE.w #YFillSize-1,d2 ; Set d2 to #YFillSize-1 (for loop, using .w because DBRA works with .w)
  LoopRight:   
    ; MOVEQ #0,d1 ; This method is equally fast
    ; BSET.l d0,d1
    ; OR.l  d1,(a0)+
    MOVE.l (a0),d1 ; Copy the long value at a2 to d1, BSET.l can only be used on d-register
    BSET.l d0,d1 ; Set wrappedx bit of d1
    MOVE.l d1,(a0)+ ; Copy d1 back to address a0, then increase a0 by 4 (l) 
    DBRA   d2,LoopRight ; Decrease the value of d0 and jump to LoopRight if value is > -1
    ; y = #YFillSize
    ; While y
      ; y-1
      ; DirtyBuffer(y,BackBuffer) BitSet wrappedx ; Set this one tile (bit) as dirty
    ; Wend
    XDelta - 1
  Wend                 
EndIf

; We're scrolling on the Y Axis
If YDelta
  ; Set HeavyLoad flag
  HeavyLoad = True
  ; We're scrolling up
  While YDelta < 0
    LastDrawY(BackBuffer) - 1
    wrappedy = YLookup(LastDrawY(BackBuffer))
    DirtyBuffer(wrappedy,BackBuffer) = #RowDirty ; Set the whole row as dirty
    YDelta + 1
  Wend
  ; We're scrolling down
  While YDelta > 0
    LastDrawY(BackBuffer) + 1
    wrappedy = YLookup(LastDrawY(BackBuffer) + #YFillSize-1)
    DirtyBuffer(wrappedy,BackBuffer) = #RowDirty ; Set the whole row as dirty
    YDelta - 1                
  Wend
EndIf        

; When we get here, check each row if dirty, and reblit the tiles if needed
y = #YFillSize
While y
  y-1
  ycalc=y+DrawY
  wrappedy = YLookup(ycalc)
  row = DirtyBuffer(wrappedy,BackBuffer)
  If row ; Skip checking the row if there are no dirty tiles
    x = #XFillSize
    While x
      x-1
      xcalc=x+DrawX
      wrappedx = XLookup(xcalc)
      If row BitTst wrappedx
        tile = !GetTile{xcalc,ycalc}
        ;Block tile, xcalc LSL 4, YModLookup(ycalc) ; Use this if you create shapes for all the tiles
          ;                     4               16          80                       4
          BlockScroll tile LSL #TileXShift, 0, #TileWidth, #TileHeight1P, xcalc LSL #TileXShift, YModLookup(ycalc), #BitmapVTiles
      EndIf
    Wend
    DirtyBuffer(wrappedy,BackBuffer)=0 ; The entire row is now clean
  EndIf
Wend

Last edited by MickGyver; 04 March 2019 at 18:19.
MickGyver is offline  
Old 04 March 2019, 23:43   #30
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,543
Quote:
Originally Posted by MickGyver View Post
I made these optimisations to the scrolling algorithm:
  • Instead of using a single column of tiles, I changed to a single row of tiles. With this, a multiplication can be replaced with left shift and the iff file is also less than half the size.
  • Created a lookup table for the tile y-position.
  • Implemented the while-loop for x-scrolling in assembly.
  • Replaced multiplications and divisions with lsl and lsr where possible.
  • Calculating x+DrawY and y+DrawY once only.
[/CODE]
Thanks, I'll implement those changes!
earok is offline  
Old 11 March 2019, 10:37   #31
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
8-Way Scrolling (Interleaved)

A few days ago I had eye surgery so to occupy my mind the day before, I was fighting to get the 8-way scrolling algorithm by aros-sg to work and I succeeded! There might be some bugs still, but according to my tests it seems to work. The example uses interleaved bitmaps. I have avoided using MOD, divisions and multiplications wherever possible.

Code:
; ****************************************************
;
; Interleaved single buffer 8-way tilemap scrolling demo (corkscrew+coppersplit)
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
; (more precisely Scroller_XYLimited, read the docs in ScrollingTrick.lha)
; 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 leftmost and rightmost columns and topmost and bottommost rows of the tilemap 
; will never be visible, so you need to add padding to the map.
;
; ****************************************************

; ...
; This code has been truncated to fit the post, download the zip file to view full source
; ...

; ----------------------------------------------
; SCROLL UP
; ---------------------------------------------- 
ScrollUp:
  If mapposy > 0
    ; Increase position first
    mapposy-1
    mapblocky=mapposy LSR #TileYShift
    stepy=!ModNumYSteps{mapposy}
    videoposy-1
    If videoposy<0 Then videoposy+#BitmapHeight
    If stepy = (#TileHeight-1)
      block_videoposy-#TileHeight
      If block_videoposy<0 Then block_videoposy+#BitmapHeight
      If stepx > #NoBlocks 
        ; Step 1: blit the 1st block in the fillup
        mapx=mapblockx+#BitmapTilesX
        mapy=mapblocky+1
        x=!RoundToBlockWidth{videoposx}
        y=(block_videoposy+#TileHeight) 
        If y>=#BitmapHeight Then y-#BitmapHeight
        !DrawTile{mapx, mapy, x+#BitmapWidth, y * #BufferDepth}
        ; Step 2: remove the (former) bottommost fill up block
        ;         we blit a 'left' block
        mapy=stepx-#NoBlocks+1
        y=(block_videoposy+(mapy LSL #TileYShift)) 
        If y>=#BitmapHeight Then y-#BitmapHeight
        mapx-#BitmapTilesX
        ; Repair broken tile if needed (the tile below the current drawn)
        If scroll_dir_prev=#DirRight 
          If mapy+1 < #BitmapTilesY
            y2=y+#TileHeight
            If y2>=#BitmapHeight Then y2-#BitmapHeight
            !DrawTileTop{mapx, mapy+mapblocky+1, x, y2 * #BufferDepth}
          EndIf
        EndIf
        !DrawTile{mapx, mapy+mapblocky, x, y * #BufferDepth}
        ; Set previous direction as left
        scroll_dir_prev=#DirLeft
      EndIf
    EndIf
    mapx=stepy
    mapy=mapblocky
    y=block_videoposy
    If mapx >= #TwoBlocks
      ; Blit only one block
      mapx+#TwoBlocks
      x=mapx LSL #TileXShift + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
    Else
      ; Draw two tiles        
      mapx=mapx LSL 1
      x=mapx LSL #TileXShift + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
      !DrawTile{mapx+1, mapy, x+#TileWidth, y * #BufferDepth}
    EndIf
  EndIf
  RTS
  
; ----------------------------------------------
; SCROLL DOWN
; ---------------------------------------------- 
ScrollDown:
  If mapposy < #MapYMax
    ; Get positions
    mapx = stepy
    mapy = mapblocky + #BitmapTilesY
    y = block_videoposy
    If mapx >= #TwoBlocks
      ; Blit only one block
      mapx+#TwoBlocks
      x=mapx LSL #TileXShift + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
    Else
      ; Blit two blocks
      mapx = mapx LSL 1
      x = mapx LSL #TileXShift + !RoundToBlockWidth{videoposx}
      mapx+mapblockx
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
      !DrawTile{mapx+1, mapy, x+#TileWidth, y * #BufferDepth}
    EndIf
    ; Increase position
    mapposy+1
    mapblocky=mapposy LSR #TileYShift
    stepy=!ModNumYSteps{mapposy}
    videoposy+1
    If videoposy>=#BitmapHeight Then videoposy-#BitmapHeight
    ; If stepy=0 then we need to fix the horisontal fillup row
    If stepy=0
      block_videoposy+#TileHeight
      If block_videoposy>=#BitmapHeight Then block_videoposy-#BitmapHeight
      If stepx >= #NoBlocks
        ; Step 1: blit the 1st block in the fillup row (y)
        mapx=mapblockx
        mapy=mapblocky
        x=!RoundToBlockWidth{videoposx}
        y=block_videoposy
        !DrawTile{mapx, mapy, x, y * #BufferDepth}
        mapy=stepx-#NoBlocks
        y=(block_videoposy+(mapy LSL #TileYShift))
        If y>=#BitmapHeight Then y-#BitmapHeight
        x+#BitmapWidth
        mapx+#BitmapTilesX
        If scroll_dir_prev=#DirLeft 
          If (mapy-1) > 0 AND (mapy-1) < #BitmapTilesY-1
            y2=y-#TileHeight
            If y2<0 Then y2+#BitmapHeight
            !DrawTileBottom{mapx, mapy+mapblocky-1, x, y2 * #BufferDepth}
          EndIf
        EndIf
        !DrawTile{mapx, mapy+mapblocky , x, y * #BufferDepth}
        ; Set previous direction as right
        scroll_dir_prev=#DirRight
      EndIf
    EndIf
  EndIf
  RTS
  
; ----------------------------------------------
; SCROLL LEFT
; ---------------------------------------------- 
ScrollLeft:
  If mapposx > 0
    ; Decrease position
    mapposx-1
    mapblockx=mapposx LSR #TileXShift
    stepx=!ModNumXSteps{mapposx}
    videoposx-1
    If stepx = (#TileWidth-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+#BitmapTilesY
      EndIf
      x=!RoundToBlockWidth{videoposx}
      y=block_videoposy
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
      ; Step 2: remove the (former) rightmost fillup-block
      mapx=stepy
      If mapx > 0
        ; There is a fill up block
        If mapx >= #TwoBlocks
          mapx+#TwoBlocks
        Else
          mapx+mapx; mapx=mapx*2
        EndIf
        x=!RoundToBlockWidth{videoposx}+(mapx LSL #TileXShift) ; mapx*#TileWidth
        y=block_videoposy
        mapx+mapblockx
        mapy-#BitmapTilesY
        !DrawTile{mapx, mapy, x, y * #BufferDepth}
      EndIf
    EndIf  
    mapx=mapblockx
    mapy=stepx-#NoBlocks+1
    x=!RoundToBlockWidth{videoposx}
    y=(block_videoposy+(mapy LSL #TileYShift)) ;MOD #BitmapHeight
    If y>=#BitmapHeight Then y-#BitmapHeight
    ; Repair broken tile if needed (the tile below the current drawn)
    If scroll_dir_prev=#DirRight
      If mapy+1 < #BitmapTilesY
        y2=y+#TileHeight
        If y2>=#BitmapHeight Then y2-#BitmapHeight
        !DrawTileTop{mapx, mapy+mapblocky+1, x, y2 * #BufferDepth}
      EndIf
    EndIf
    If stepx >= #NoBlocks ; Don't draw tiles every step, it's not needed/wanted
      !DrawTile{mapx, mapy+mapblocky, x, y * #BufferDepth}
    EndIf
    If stepx > 0
      scroll_dir_prev=#DirLeft
    Else
      scroll_dir_prev=#DirNone
    EndIf
  EndIf
  RTS
 
; ----------------------------------------------
; SCROLL RIGHT
; ---------------------------------------------- 
ScrollRight:
  If mapposx < #MapXMax
    mapx=mapblockx + #BitmapTilesX
    mapy=stepx-#NoBlocks+1
    x=!RoundToBlockWidth{videoposx}
    y=(block_videoposy+(mapy LSL #TileYShift)) ;MOD #BitmapHeight
    If y>=#BitmapHeight Then y-#BitmapHeight
    ; Repair broken tile if needed (tile above current drawn)
    If scroll_dir_prev=#DirLeft 
      If (mapy-1) > 0 AND (mapy-1) < #BitmapTilesY-1
        y2=y-#TileHeight
        If y2<0 Then y2+#BitmapHeight
        !DrawTileBottom{mapx, mapy+mapblocky-1, x+#BitmapWidth, y2 * #BufferDepth}
      EndIf
    EndIf
    ; Blit one block
    If stepx >= #NoBlocks ; Don't draw tiles every step, it's not needed/wanted
      !DrawTile{mapx, mapy+mapblocky, x+#BitmapWidth, y * #BufferDepth}
    EndIf
    ; Increase position
    mapposx+1
    mapblockx=mapposx LSR #TileXShift
    stepx=!ModNumXSteps{mapposx}
    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+#BitmapTilesX-1
      mapy=mapblocky
      x=!RoundToBlockWidth{videoposx}+(#BitmapTilesX-1) LSL #TileXShift
      y=block_videoposy
      !DrawTile{mapx, mapy, x, y * #BufferDepth}
      ; Step 2: blit the (new) rightmost fillup-block
      mapx=stepy
      If mapx > 0
        ; There is a fill up block
        If mapx >= #TwoBlocks
          mapx = mapx + (#TwoBlocks-1)
        Else
          mapx = mapx LSL 1 - 1
        EndIf
        x=!RoundToBlockWidth{videoposx} + (mapx LSL #TileXShift)
        y=block_videoposy
        mapx+mapblockx
        !DrawTile{mapx, mapy+#BitmapTilesY, x, y * #BufferDepth}
      EndIf
    EndIf
    If stepx > 0
      scroll_dir_prev=#DirRight
    Else
      scroll_dir_prev=#DirNone
    EndIf
  EndIf 
  RTS
Changelog
2019-03-12
- Added MIT license.txt
2019-03-11
- Initial version
Attached Files
File Type: zip ScrollXY.zip (48.2 KB, 106 views)

Last edited by MickGyver; 12 March 2019 at 11:48. Reason: Added MIT license.txt
MickGyver is offline  
Old 11 March 2019, 18:38   #32
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
I also updated the horisontal and vertical scrolling examples, they can be found in previous posts in this thread. All examples now use interleaved bitmaps and the blockscroll function for drawing tiles (instead of shapes).
MickGyver is offline  
Old 11 March 2019, 19:17   #33
carrion
Registered User
 
carrion's Avatar
 
Join Date: Dec 2016
Location: Warsaw area
Posts: 153
This is really great job you do here.
I'll test it when back at home but looking at your previous X and Y scrollers this will be perfect, I'm sure.

Now I wanted to ask this for long time, and forgive me if the question is ... strange but:

What is the "license" for this code examples? Can I (we) use it in our games? Can we make commercial products with this code? I'm thinking of using these procedures in my production hence the question.
TIA
carrion is offline  
Old 12 March 2019, 07:38   #34
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by carrion View Post
This is really great job you do here.
I'll test it when back at home but looking at your previous X and Y scrollers this will be perfect, I'm sure.

Now I wanted to ask this for long time, and forgive me if the question is ... strange but:

What is the "license" for this code examples? Can I (we) use it in our games? Can we make commercial products with this code? I'm thinking of using these procedures in my production hence the question.
TIA
Thanks, and not a strange question at all. I have been hoping for an fully open source license like MIT or CC0 (or an attribution license). My demos use coppersplit and interleaved code by @earok and are to large extent a Blitz Basic conversion of the ScrollingTrick demos by @aros-sg. earok has posted some demos under the MIT license, including the interleaved demo, but I can't find the license for ScrollingTrick. Are you, @earok and @aros-sg ok with an open source license for these demos?

The aim with my Blitz Basic work has been to make BB2 more accessible so we could see less Backbone etc. games and hopefully more better quality games for our beloved Amigas.
MickGyver is offline  
Old 12 March 2019, 08:44   #35
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by MickGyver View Post
Are you, @earok and @aros-sg ok with an open source license for these demos?

Yes. Anyone can do whatever he wants with any part (docs/sources) of ScrollingTrick.lha. Consider it public domain.
aros-sg is offline  
Old 12 March 2019, 08:48   #36
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,543
Also OK with whatever code I've posted online being in the public domain
earok is offline  
Old 12 March 2019, 11:53   #37
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by aros-sg View Post
Yes. Anyone can do whatever he wants with any part (docs/sources) of ScrollingTrick.lha. Consider it public domain.
Quote:
Originally Posted by earok View Post
Also OK with whatever code I've posted online being in the public domain
That is just superb, cheers guys!

I have now added the MIT license to all the demos. If you (read BB2 programmers) end up using one of these algorithms, please post any improvements / optimisations if at all possible.
MickGyver is offline  
Old 12 March 2019, 21:29   #38
carrion
Registered User
 
carrion's Avatar
 
Join Date: Dec 2016
Location: Warsaw area
Posts: 153
Gentleman
Thank you very much. I started sharing my code because of the same reasons as MickGyver (to make BB2 more accessible. I'm not an expert by any means but I had chance to code few simple things and sharing is crucial to Amiga community nowadays IMO.

So again thanks a lot for your work on these very important assets. Now we don't have any excuses. Example code and demos are here - let's use them
I hope to share with you soon(ish) some info of little project I work on.

[edit]
@MickGyver
You said you use Earok's interleaved bitmap trick for latest XY demos. Is it also used in other X and Y demos?
carrion is offline  
Old 13 March 2019, 07:34   #39
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Quote:
Originally Posted by carrion View Post
@MickGyver
You said you use Earok's interleaved bitmap trick for latest XY demos. Is it also used in other X and Y demos?
Interleaved bitmaps are used in all the demos in this thread. Earok mentioned earlier that "normal" shapes can still be used with the blit functions. The tiles are drawn using blockscroll so they don't need any extra memory.
MickGyver is offline  
Old 13 March 2019, 09:03   #40
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,543
Quote:
Originally Posted by MickGyver View Post
Earok mentioned earlier that "normal" shapes can still be used with the blit functions. The tiles are drawn using blockscroll so they don't need any extra memory.
Yes, that's correct. Blitz can blit non-interleaved Bobs to an interleaved bitmap.

The advantage with using interleaved bitmaps is you only need to do one blitter operation to hit all bitplanes. With a non-interleaved five bitplane bitmap, Blitz would need to do five individual blitter operations "under the hood" to hit all five bitplanes.

So it makes sense to have your tileset as interleaved, although it's a bit more complicated to set up.

It is possible to also have interleaved Bobs of course, but it's very memory intensive - the cookie mask for a five bitplane interleaved shape is five times the size of the mask of a non-interleaved version.
earok 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 11:31.

Top

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