| 
   
 MinTile
            - Minimal Software/Hardware Tilemap
 Introduction to the MinTile
          Series... 
 
      
        
          
            | MinTile is a simple Tilemap demo it was used to create the Z80
              based 'ChibiFighter' Game. 
 While Mintile is designed for a tilemap, small tile grids can be
              used to simulate 'sprites', and supports X flip with these
              sprites.
 
 Where hardware tile support is available (eg SMS) it will be used,
              where it is not (eg CPC) sofware tiles will be used, however both
              work in the exact same way to allow a game to be ported more
              easily
 |  |  
 
      
        
          
            | Lesson
                MinTile1 - Basic Tilemap Drawing The CLS routine is the basic screen redraw function.
 
 This redraws all changed parts of the Tilemap, after which any
              sprites will need to be redrawn.
 |  | V1_MinimalTile.asm | 
 |  |  
 
      
        
          
            | MinTile is a simple tile
              drawing routine, it's designed to work in the same way on all
              systems, whether they have hardware tilemap or not! 
 It provides 256 patterns per tilemap, and X-flip for sprites, but
              not Y-flip
 A future version called MaxTile is planned to expand the
              functionality.
 |  |  
 
      
        
          
            |  | We actually have
                two background tilemaps! The main one is 36 tiles wide (32 + 4 for scrolling) and stores
                the current background tiles
 The other is the Cache, which is 32 tiles wide, a Zero tile is
                an unchanged tile which doesn't need drawing.
 
 |  
 CLS to redraw the map 
      
        
          
            | A2 points to the tilemap Cache, the Tile cache should be 32 tiles
              wide
 A5 points to the Tile Pattern Data, this needs to be correct for
              the platform specific drawing routine
 
 We shift these into the shadow registers, and point A6 to the
              start of the screen VRAM,
 We set D7 to the height of the tilemap - assumed to be 24 for a
              normal sized 256x192 screen.
 
 |  |  
            | The DoStrip routine draws a sequence of D7 tiles to vram
              destination A6 
 This is a platform specific routine which will draw the single 8
              pixel tall horizontal strip
 
 |   |  
            | When DoStrip returns, HL will point to the end of a
              line, however we may need to make a correction to HL to point it
              to the following line before we continue. 
 This is platform specific, as how the screen memory layout works
              varies on each system
 
 |   |  
            | We repeat until all 24 horizontal strips are drawn to the screen 
 |   |  
 DrawTilemap for irregular sized maps 
      
        
          
            | Mintile has no real sprite
              support, however a small tilemap can be drawn to the screen at an
              irregular offset to simulate a sprite 
 DrawTilemap will perform the draw
 |  |  
            | A2 will point to the tilemap A5 should point to the Tile Pattern data
 D3 is the tilemap width to draw
 D6 is tilemap height to draw
 D7  is the uncropped  Tilemap Width
 A6  is the Vram Dest
 
 We have two strip drawing routines.
 DoStrip Will draw normally.
 
 DoStripRev Will draw the tilemap in reverse, moving backwards
              through the lines of thetilemap, and flipping the pattern data.
 |   |  
            | We restored A6, so the VRAM destination is pointing
              to the start of the tilemap. 
 We need do move down 8 pixels to do the next line - how we do this
              depends on the platform.
 
 |   |  
            | After the line has been drawn, we move down one line in the
              tilemap. 
 If the 'sprite' are partially offscreen, we may have cropped it,
              so we add the width of the whole tilemap before continuing.
 
 |   |  
            | DrawTilemapRev Will enable the
              alternative tilemap drawing routine, before switching the function
              back on completion. |  |  
 
 
      
        
          | Lesson
              MinTile2 - Sprites As mentioned, Mintile can use small tilemaps to simulate sprites.
 
 However before we can draw a tile sprite, we need to handle
            cropping, and maybe flipping
 
 |  | V1_MinimalTile.asm | 
 |  |  Sprites  
      
        
          | Before we actually try to draw a sprite we first check if it's
            'flagged' 
 The flag marks that a sprite has actually changed, so needs drawing
            back to the screen.
 
 |  |  
          | When using Drawsprite, A4 should should point to the object with
            the sprite parameters. 
 We load the sprites attributes in. Co-ordinates are in Logical units
            (2 pixels per 1 Logical unit)
 
 We load the address of the bitmap pattern data, on some systems we
            need an alternative address for flipped data
 
 |   |  
          | We need to crop the sprite object so it can go partially
            offscreen. 
 If the sprite is entirely offscreen, the carry will be set and we
            just return
 
 |   |  
          | We need to calculate our VRAM destination with platform specific
            function GetScreenPos 
 We draw the sprite to the screen, flipped if required by the flags.
 |  |  Cropping  
      
        
          | Our cropping routine will work out the X,Y pos in bytes, and width
            and height + any skipped tiles from the source data 
 registers D1,D4 is the X,Y co-ordinate in logical units
 registers D3,D6 is the Width,Height in logical units
 register A2 is the address of the source bitmap data.
 
 The drawing routines can't actually support flipping very well, so
            we actually flip the X co-ordinate before performing the crop if
            Xflip is enabled
 
 
 |  |  
          | First we zero D2,D5 - they are used for temp values 
 Ok... lets crop the top of the sprite...
 First we remove the ypos of the first visible pixel from the draw
            ypos (D4)... if the result is greater than zero, then nothing is off
            the screen at the top.
 
 if the result is less than zero we need to crop... we convert the
            negative to a positive and compare to the height of our sprite (D6),
            if the amount to crop is not less than the height then the sprite is
            completely offscreen.
 
 Anything else is the number of lines we need to remove from the top,
            we store this in D5 and set the new 'draw position' to Ypos (D4) =0
 |   |  
          | Next we do the same for the bottom, 
 We add the height to the Ypos, and subtract the height of the
            logical screen, if it's over the screen height (greater than zero)
            we need to crop again - the result is the amount to crop
 
 We AND with %11111100 to convert to a tile count
 
 |   |  
          | We've calculated the top (D5) and bottom (D2) crop... we now use
            these to calculate the new height of the sprite (D6). |  |  
          | We then skip over any tiles in the source tilemap (A2) based on
            the number of lines of tiles we need to remove from the top. 
 |   |  
          | Now we do the same for the X axis First we remove the xpos of the first visible tile from the draw
            Xpos (D1) ... if the result is greater than zero, then nothing is
            off the screen at the left.
 
 if the result is less than zero we need to crop... we convert the
            negative to a positive and compare to the width of our sprite (D3),
            if the amount to crop is not less than the width then the sprite is
            completely offscreen.
 
 Anything else is the number of lines we need to remove from the
            left, we store this in E and set the new 'draw position' to the
            correct partial tile offset for the draw position, via an EOR and
            AND
 
 |   |  
          | Next we do the same for the right, 
 We add the width (H) to the Xpos, and subtract the width of the
            logical screen, if it's over the screen width (greater than zero) we
            need to crop again - the result is the amount to crop from the right
            (D2)
 |  |  
          | We've calculated the left and right crop... If this is zero,
            there's no horizontal crop 
 Otherwise We need to crop, so we calculate the new width in
            D3.
 |  |  
          | We need to alter the start Tile to compensate for any left hand
            clipping 
 We clear the carry to record that the crop resulted in something to
            draw!
 |  |  
          | If the sprite is completely offscreen, there's no point trying to
            draw, so we set the carry and return |   |      
      
        
          |  | MinTile has
              to crop to a whole number of 8x8 pixel tiles. 
 This is because the draw routines are hard coded to an 8x8 limit
              for efficiency.
 
 |    
      
        Sprite Removal
          | Lesson
              MinTile3 - Sprites Redraw When a sprite moves we need to redraw it!
 
 We need to work out what was under the sprite, and update it the
            cache
 
 |  | V1_MinimalTile.asm | 
 |  |  
      
        
          | Before we do anything with the sprite we load in the previous
            position and size (the one we need to redraw with the background) 
 We round to a number of tiles.
 
 |  |  
          | To work out the correct area We crop the sprite, then convert the
            size and position to a number of tiles. 
 |   |  
          | We need to update the Tile Cache with the tiles that need
            redrawing. 
 ShiftTilemap will shift the position in the cache so A3 points to
            the first tile under the sprite.
 
 Tilemap2 contains the tilemap for the background, we add the scroll
            Offset (the leftmost visible tile), and shift the tilemap to get the
            top left tile under our sprite.
 
 |  |  
          | Ok! We have our source tilemap pos in A3, and our destination in
            A2 
 We now copy all the tiles under our sprite into the Cache for redraw
            next time.
 |  |  Helper functions 
      
        
          | ShiftTilemap will shift tilemap
            A2 to (X,Y) position D1,D4 
 the width of tilemap DE should be loaded into D7
 |  |  
          | DoCropLogicalToTile converts an
            X,Y position and a Width,Height from logical units to tiles. 
 There is 2 pixels per logical unit
 there is 8 pixels per tile
 So we just divide by 4!
 
 We set the Z flag if the result is zero (nothing to do)
 
 |   |  
          | It's not related to sprites, but ChangeScroll
              is another little routine. 
 When we want to scroll the background, we need to update the Cache
            with the tiles for the new tilemap position.
 
 However, assuming there are repeating areas in the tilemap and we
            move in whole tiles, there may be no need to draw anything! - The
            new tile, and the old tile may be exactly the same!
 
 ChangeScroll checks this, only updating where the tile for the new
            scroll position is different.
 
 |   |  
      
        
          |  | As we have no
              double buffer, Redrawing the sprite causes it to flicker. 
 We can reduce this, by working out what tiles will be covered by
              the new sprite position, and not redrawing those, but we'll cover
              that next time!
 
 |  
 
 
 
 
      
        
          | Lesson
              MinTile4 - Zeroing Sprites in Cache When we move a sprite we redraw the background before drawing the
            new sprite.
 However, because we don't have a double buffer this causes flicker.
 
 To reduce the flicker we zero the tiles which do not need redrawing,
            as the new sprite position will overlap them... here we go!
 
 |  | V1_MinimalTile.asm | 
 |  |    ZeroSpriteInCache
 
      
        
          | First we check the flag to see if we actually need to redraw
            anything. 
 |  |  
          | If we are offset by a half tile, the edges will need to be
            redrawn, 
 In this case we increase the X/Y pos by 1/2 tile, and decrease the
            Width/Height by 1/2 tile.
 
 |   |  
          | We need to load in our Tilemap address (of our sprite) 
 Next we need to perform the Docrop routine to work out the area of
            the sprite actually onscreen.
 
 We convert our co-ordinates to tile numbers
 
 |   |  
          | 
 We need to offset the cache, so we're pointing DE to the address of
            the tile under the topleft corner of the sprite.
 
 |   |  
          | If we're X-flipped we need to use self modifying code (or
            variables if running from ROM) 
 These switch how the 'Zero' routine works, reversing the order we
            move through the sprite tilemap.
 
 |  |  
          | We now need to actually perform the Zero. 
 For the range decided, we load in each tilenumber of the sprite, and
            if it's not zero (something to draw), we zero the entry in the cache
            for the matching area.
 
 This ensures that anything which will be covered by the new sprite
            will not have it's background redrawn, reducing the flicker.
 |  |  
 
      
        
          | The Zeroing
              routine is rather crude, it doesn't do a great job of coping with
              sprites with 'holes' in them, causing graphical glitches. 
 The planned successor MaxTile will have a 'Smarter' zeroing
              routine which will stop this!
 |  |    
 |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Buy my Assembly programming book
 on Amazon in Print or Kindle!
 
 
  
 
  
 
  
 Available worldwide!
 Search 'ChibiAkumas' on
 your local Amazon website!
 Click here for more info!
 
 
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Buy my Assembly programming book
 on Amazon in Print or Kindle!
 
 
  
 
  
 
  
 Available worldwide!
 Search 'ChibiAkumas' on
 your local Amazon website!
 Click here for more info!
 
 
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Buy my Assembly programming book
 on Amazon in Print or Kindle!
 
 
  
 
  
 
  
 Available worldwide!
 Search 'ChibiAkumas' on
 your local Amazon website!
 Click here for more info!
 
 
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
   
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 |