This video demonstrates how to optimize tilemap rendering by converting 4-color tile patterns to 16 colors using lookup tables, reducing memory usage from 32 bytes to 16 bytes per tile. The technique involves creating lookup tables that map each source byte (representing 4 pixels) to two destination bytes (representing 2 pixels each), enabling efficient color conversion while maintaining visual quality. The tutorial covers various tile types including basic tiles, X-flipped tiles, Y-flipped tiles, double-height stretched tiles, solid fill tiles, and transparent tiles, all implemented using the same lookup table approach for color conversion and X-flipping.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Z80 Lesson P103 - Sam Coupe MaxTile software tilemap in 4 colorsAdded:
hello it's Keith here and this is lesson 103 of the platform specific series of my zh assembly programming tutorials we're back on the Sam Coupe for the second time today and we're looking at the alternate Four Color version of Max tile so here's Max tile running on this system now the screen is still in 16 color mode but each of the tile patterns is just four colors and it's been converted with a tint so you can see the background is all basically green the characters are either the sort of chibico kind of colors the purple and um and Silent white or the eurita colors of magenta cyan and yellow here um and you've got those sort of Fire TV comes there for some strange reason I don't know what that's all about but so basically we're using a tint so we're still getting the benefit of 16 colors but the important thing is our source pattern data rather than being 32 bytes per tire is now just 16 bytes per tile now one exception is the filled tiles which are still a full 16 colors but generally speaking everything else has been converted so that's what we're doing today so we've got all of the same functionality we're just saving some memory via conversion of our Graphics let's go to the code let's check it out okay so we're using the same sound max style mid um Source example here this time we've got this option enabled here and we'll be using this alternate term bitmap drawing routine here okay so the first thing is the pattern data so our pattern data is down here and you'll notice that the offsets for the um 16 um color patterns are very different to the Four Color patterns and and that's the point we are we're using half half the memory for the bitmap pattern saving an awful lot of memory and um personally the chibi ackermans games was just down to around four colors so they get the characters are all those four colors anyway so for me I think this is a real benefit if you prefer 16 colors and can spare the memory obviously please go ahead and do whatever is appropriate for you but that's not what this tutorial is about today now as before we've got our lookup table that we use for our xflip but the lookup table has an extra function today with the mint tile series originally I was converting the data in real time shifting all the bits around it was very slow though so for max style I I adopted the later version of vintile's idea of using a lookup table to actually convert four color data to 16 colors as well so that's what we're doing today so basically um The Source bytes of the Four Color data contain four pixels per byte but the screen contains two pixels per byte so basically One Source byte is converted in our source patterns it's converted to two bytes for our screen so what we're going to do is we're going to create a lookup table that converts the One Source byte into the two screen bytes we're also going to create a second lookup table that X flips the data so um each lookup table will be 512 bytes because one source bytes two destination bytes so we're converting 256 bytes into 512 bytes and as I say the second one will make a total of 1024. so the HL payout points to our lookup table the L byte of that HR pair will be the byte that we want to convert now if we increment the H component basically this will shift us to the second byte which is the 16 color converted equivalent of the Four Color Source data so the first um the first five twelve are the unflipped data so what we're doing basically here is we're taking two pixels and we're shifting them out and we're converting that into 16 colors we've done 116 kilobyte there we're incrementing H and then we're doing the other two pixels here and incrementing H there and then here we've got almost the same thing using the same Source byte but this time we're shifting them the other way effectively X flipping the data here so we're writing our four four bytes here we're then decrementing H moving back that H back to the first entry we're then incrementing L and we're repeating until we've done all 256 possible Source bytes that are building up that lookup table for conversion now in our 16 color mode our screen base is at memory address eight triple zero our program is running from the um the the quadruple zero range and we're actually executing from one triple zero loaded into take triple zero and we shift to quadruple zero and so we've got some banking there to do that and but by the time this actually executed would be one double zero um when we actually want to draw the simulated Sprites that are actually miniature tile Maps we actually have to calculate the VM destination we use get screen pause to do this in all of my tutorials these days I use logical units which are pairs of pixels so um basically a 256 pixel wide screens 128 logical units and makes it nice and easy for working in one byte coordinates and having cropping and things like that but this is actually very convenient for the same could pay because each um each byte of the screen is two pixels and so the logical units actually becomes the number of bytes quite handy really so um the X offset in bytes is actually just the X offset in logical units and the the Y offset um because each line is 128 bytes um basically for each pair of lines we need to add 2256 and so we just load the y coordinate into their H part of the HR V1 destination we're just all in eight the eight o part of the a triple zero V run base and that's calculated our VM destination very nice indeed so nice and convenient for the Sam coupe the only disadvantage of the sum could pay screen the like the memory layer it's fantastic it's just quite big it's um it's 24K so it will come for its 16 color screen rather than the 12K that the cpc's equivalent screen would be a lot of data to shift it unfortunately does end up a little bit slower than the amstrad CPC even though the process is faster anyway now what I'm not going to do today is I'm not going to discuss the multi-platform maxstar code or the example code that's leading in the joystick and moving around the characters all I'm discussing is the bitmap drawing routines today of the draw tile routine now the calling routine to this will actually have shifted out the least significant bit of the first byte that was read into the accumulator the reason for that is the least significant bit is the update flag that says that this byte this by tile of the tile map needs to be updated so that bit will have already gone and it would have been a one because otherwise we would have never executed this routine so now we're testing the next bit which is the program bit if this is a one then this is an advanced tile with some kind of special effect otherwise it's the most basic tile kind possible which is just a regular tile now um we're shifting a zero back in and we're writing that to tile number back to the tile map in BC and that's to clear the update flag that we popped out before so we're shifting a zero in and writing that we're then adding e which is the pattern date database that pointed to our pattern data and we're writing that into our and then we're loading a second byte and we're adding the deeper and adding writing that to H you see our tile numbers use two bytes and the bottom four bits is a minus missing there the bottom four bits of the um of the first byte are actually the commands saying what what kind of tile it is and things like that and then the remaining bits the top four bits there and the second byte those are the tile numbers so this is effectively already pre-multiplied by 16 because we're designed with it's designed for um four color tiles you see so it's fastest at four colors so that is effectively calculated our view uh Source tile map data and that's now in HL and we push that onto the stack here we're loading the L register with four because we're going to work in pairs of lines here um and then what we're doing here we've actually got a it's actually a fix here I was having some problems with the the lines getting jumbled up I think it was some kind of wrap around problem when the when the tile gets to the end of the when the Sprites get to the end of the screen I think sometimes there's a carry being occurring so that's a sort of Correction there for that but but then basically what we're going to do next is we're going to draw a basic unflipped tile now we're going to use ixh as the number that's added to the um destination data this is effectively The Tint that allows the different characters to be different colors within the four color range so even though we've only got four colors we can use a different four color for different characters so that's what what's that's what we're going to be doing and that's being that's ixh doing that now B is going to have to be our lookup table we're going to use the lookup table even if we're not X flipping because we're going to use it for color conversion so what we're doing here is we're loading in the first byte of our source data into C here so that is basically priming it for conversion we're then moving to the next Source byte and we're loading the the equivalent flipped byte from the BC lookup table by loading C with the byte we want to flip if we load from BC we get the flipped equivalent we then ore in the color shift here and we write that to the screen data which isn't the vrm destination which is now in De because of this flipping here so it's in De in this case now what we need to do next is we need to move across the screen here so we're incrementing e but we also need to move to the second byte in our lookup table the second converted byte for the value that we read in and so we're incrementing B and we're reading in another byte from BC and writing that to the screen again we repeat this until we've done a full four bytes or eight pixels to the screen we then move down a line and we move back to the left hand side that's what that is doing there and we repeat again doing the same for the next line once we've done this the second line we're then moving back but this time we need to increment the D part this is the high part of our VM destination and then we've done a pair of lines and we simply repeat that four times and we've done our unflipped tile so that's that's kind of the template that the others are based on we've not used stack misuse this time there was so many complicated commands here uh it wasn't really beneficial and I needed some way to back up the IX register being as we're using IX as well here and it's used in other parts of the code so that's why I've not used stack misuse this time here's the advanced routine which handles them things like flipping if the flipping bits are both zero though this is some kind of custom tile which do special things otherwise we must be doing some kind of flip so what we're doing here is we are reading in our source pattern data address here calculating that we're then setting up our Loop count here and setting up our lookup table here and we're getting our registers into the correct positions and backing up the ones we need to restore later we're then checking the the bits and seeing if the Y flip flag is set now if it's not we've already established that some kind of flipping flag is set up here so we must just be X flipping and that's what's going to happen here to to do X flipping basically we do the exact same thing before as pretty much we're just using the expert lookup table so we move to the second 512 bytes here of our lookup table here and the only other thing is we start from the right hand side of the tiles and we move left out each time so um we we increment e to move to the right and we document e to move back to the left but apart from that it's pretty much the same we're reading from our source um Source pattern data into C we then read in the flip flipped and converted equivalent from BC we then draw that to the screen after oring in our tint we then do the second byte here by incrementing B writing that we're decrementing e after each time and then we're adding three this time along with our 128 to move down a line and moving back to the right hand side of the tile we just repeat until we've done the entire tile drawn to the screen X flipped so very straightforward the Y flipping pretty straightforward as well so here's the wife looking routine first we're checking if we're X and Y flipping but if we're y flipping basically all we do is we move to the bottom of the tile and then we move back up so we're moving down um three pairs of lines and then we are moving to the last line there and then basically we're just going to um we're just going to read in our source data and we just move up the screen instead of moving down the screen as we draw it to the screen here but as I say basically basically the same as before and X flipping and Y flipping we just do both things so we're using the x-floop lookup table so we're adding 512 to our source lookup table here we're moving to the right hand side of the tile moving to the bottom of the tile and then we just draw the data to the screen there so that is the X and Y flipped version there those lookup tables doing both the color conversion and the X flipping the Y flipping is simply done by drawing backwards to bottom to top okay so that's the um that's the x-foping and Y flipping the final one is the so-called custom tiles which are designed to do um special things and to do it's essentially designed for things like space saving so we've got these solid fill tiles these just use a pair of bytes for all of the lines so less reading and converting of data the other one that we have is the double height tiles um these basically stretch the tiles so that they fill twice the height so you can see um if you just look back here these have been stretched to twice the height here like maybe you can tell maybe can't but they have and then the final one if it'll come onto the screen is the transparent one which uses zero byte transparency it'll come in any moment here it is so this one you'll notice that around the edges there's a slight Blackboard but there's not this blocky horrible nasty effect that you've got there and that's the transparency effect and I call that zero byte transparency okay so that's what this code is doing so in this mode basically um these two bits of the low byte are now the program code and so these two bits are the only ones spare for our tile number um I've decided to use those as the High bits instead of the low bits so we're shifting them to here and basically we're then deciding which one of these routines to run we've also got to clear that update flag and we're doing that at this point here so that's um that's what's going on there now what we're going to do next is we're going to look at each of these so the first one we'll look at is the double drawing routine so this is going to draw basically each Source line twice to the screen so we're calculating our source pattern data here this time we're only multiplying it by eight though there's 16 bytes per um unstretched tile but we're stretching the tile so now that becomes eight this was designed though for them it was designed for saving pattern data my um suck Hunt game you had a silly introduction and I didn't have enough memory left to use um useful tiles but I realized by stretching the tiles to twice the height basically using half the bytes for the source pattern data I could get almost the exact same effect and it saved all the memory and I had lots of spare memory still so that was definitely worth doing and that's why I've included it here so all we're doing here is all the same stuff as we've got before working in pairs of lines here getting our tile to getting our unflipped lookup table but this time when we're reading in a byte from our source pattern and then reading converting that into um into 16 color data here we're writing that to the screen but we're then setting the seventh bit adding 128 to the E part and then writing it again and then resetting e and that's effectively moving down the line filling and moving back up a line so that that's what that's doing that that's effectively filling two lines with one read and one conversion so a little bit faster hopefully there so we're reading one byte in from our source button data converting it via the lookup table writing it to two lines on the screen reading the second byte after incrementing the lookup table entry reading the second by writing it to two lines on the screen moving the lookup table back reading in the next byte from the pattern data and that's effectively done a full line twice on the screen and so then we repeat four times and then we've done our entire um entire stretch tile The Fill routine is very similar in a lot of ways so we've got pattern data again but this time we're actually only using two two different bytes all together so basically um we are loading in our first byte and these are actually 16 colors so we're not doing any conversion here but we're loading that into e here in the shadow registers and then we're loading the second one and we're loading that into D in the shadow registers L is being loaded with four here and then the which flipping to the shadow edges so that's our L count being decremented there but basically all we need to do is we just write the e-bite four times to the screen moving across the screen each time we then move down the screen we're pre-calculating the two possible values for L and loading them into B and C because we don't need B and C this time for our conversion table because we're actually working in 16 colors here so we're loading CL with C here moving down to the second line we're loading l h o with d here and then we're loading L with b and then we're moving incrementing H moving down to the next pair and we're just repeating after we've done that so that's how we do the fill very straightforward the final one and the most complicated one is the transparency now the most simple transparency is simply a completely empty tile the ureter character there that's a miniature Square Tile map but you can see there's some tiles that simply have no content around the feeds and things and so these are transparent tiles and that's just defined by a value of 255 as the tile number and we're incrementing a if a was 255 now becomes zero and that sets the zero flag in that case we're just returning otherwise what we're doing though is we're multiplying the turn number by 16 we're using our regular tile pattern data here we're going to work in pairs of lines again because that's the most effective way to work on this system and once again we need that precious lookup table so we're loading the transplant byte into IXL here and this is the byte that we're going to use as the comparison for when we're going to skip so what we're going to do next is we're loading our lookup table into B and we're going to read in a source byte from our patent data into C we're then incrementing that Source pattern we are then going to compare the byte that we've read in from our source pattern with the with the transparent byte which is of course a zero in this case and if it matches we're going to skip over the next draw and that is going to basically skip two bytes of the screen and so we're skipping basically four pixels if the if it's not zero though we're going to draw these to the screen so we're converting them via the lookup table and writing them to the screen in the same way as we usually do now in that case we've already incremented e once and so we're skipping this command here and we're jumping down to this position here so that's what's going on there now what we're doing then is we're simply repeating this for all of the remaining pairs of bytes are in this pair of lines so we're doing a pair of lines here again so there's two bytes per lines two lines so that's four four cases we're doing this and then we're simply moving down a pair of lines here and we're repeating until we're done so as I say that that's the transparency effect it's it's a crude one but it is um it does give a pleasant effect at least for sort of cartoony characters where you really can't tell if there's a black border around the character and this was the kind of transparency that chibiakum has used it I thought it was perfectly adequate for that game and I there's there's clever things you can do with and masks and all masks and awing and things but um it uses more memory it's going to be slightly slower I think and I personally think think it's excessive for this kind of game but anyway um so there you go and that's this example if you like what you've seen please like And subscribe um there's an entire series on the max time multi-platform code if you're interested in that but if you're not then I'd suggest you just download the example um bitmap drawing routines you saw today maybe just use bits of them in your own programs because what you've seen in today's example is really just a single tile ongoing routine various versions X flips and Y flips and faster versions and stretch versions and things but you're welcome to take those and use bits of them in your own code in any way you can as I always say if you somehow manage to make a million dollars while it's a commercial game you're welcome to do so you don't need to give me credit for it and anything I just hope you'll get some benefit from it anyway I hope you've enjoyed what you've seen today thanks for watching and goodbye
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
So What's Odin Lang Even Good For
TechOverTea
131 views•2026-06-01











