News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Tetris DX (Gameboy Color) - Tiles have straightforward RLE  (Read 2626 times)

Ed101

  • Jr. Member
  • **
  • Posts: 4
    • View Profile
Tetris DX (Gameboy Color) - Tiles have straightforward RLE
« on: April 26, 2020, 07:56:31 pm »
Hi there  :)

I am trying to edit the graphics in Tetris DX for the Gameboy Color (I am using Tetris DX (JU) [C][!]).

When viewed with a tile editor, the graphics can be found, but they are garbled.

Example of the tiles in a Tile Editor (image):

https://drive.google.com/open?id=1oK4ret0hGxHxQ8hXLKY46BNd3o0ivuuh

I have found that the tiles use a simple Run-Length Encoding method (that I haven't fully worked it out, nor made a tool for it):
e.g. to display 8 pixels of color #3 the game uses 04 FF 8B instead of FF FF FF FF, the 04 and FF seem's to refer to 4 lots of FF, the third byte states that B(11) bytes of uncompressed 2bpp graphics will follow. This third byte has a mask (not sure this is the correct term) of 0x80 to indicate uncompressed data (it seems), with the rest of this third byte indicating the length of uncompressed graphics to follow (i.e. where the next compressed data will start). Although, this might not be exactly right.

The graphics are duplicated in the ROM, each duplicate used by a separate game mode (or so it seems).

Compressed tiles for the tetrominos (image):

https://drive.google.com/open?id=1ToyvMB1Ei5L5CVJma7-TjPAnpnV0F9KG

Uncompressed tiles for the tetrominos (image):

https://drive.google.com/open?id=1qfSi50yTsUCce93eDcMyWuzHx_x4LS0Q


Here is a copy of the compressed tile data for the tetrominos:
03 FF 8B 81 FF BD FF BD FF BD FF BD FF 81 04 FF
8B
F1 8F C1 BF 99 FF 99 FF 81 FF 81 05 FF 8B F9
87 C1 BF 81 FF 81 FF 81 FF 81 05 FF 8B E1 9F FD
BF BD E7 BD E7 BD FF 81 05 FF 8B F1 8F FD BF BD
E7 BD E7 BD FF 81 05 FF 8B 81 FF BD C7 A5 DF A5
DF BD FF 81 05 FF 8B 91 FF 80 FF C2 FF 80 FF 88
FF BF 05 FF 89 11 FF 00 FF 84 FF 00 FF 11 07 FF
89
05 FF 13 FF 03 FF 43 FF 03 07 FF AB 89 FF C3
FF 83 FF A3 FF 83 FF 8B FF 83 FF C7 FF 83 FF 93
FF 83 FF C7 FF 83 FF 83 FF 93 FF C3 FF 93 FF 83
FF 87 FF C3 FF 83 FF BF 04 FF 9E               


Here is a copy of the hand un-compressed tile data for the tetrominos:
FF FF FF 81 FF BD FF BD FF BD FF BD FF 81 FF FF
FF FF
F1 8F C1 BF 99 FF 99 FF 81 FF 81 FF FF FF
FF FF
F9 87 C1 BF 81 FF 81 FF 81 FF 81 FF FF FF
FF FF
E1 9F FD BF BD E7 BD E7 BD FF 81 FF FF FF
FF FF
F1 8F FD BF BD E7 BD E7 BD FF 81 FF FF FF
FF FF
81 FF BD C7 A5 DF A5 DF BD FF 81 FF FF FF
FF FF
91 FF 80 FF C2 FF 80 FF 88 FF BF FF FF FF
FF FF
11 FF 00 FF 84 FF 00 FF 11 FF FF FF FF FF
FF FF
05 FF 13 FF 03 FF 43 FF 03 FF FF FF FF FF
FF FF
89 FF C3 FF 83 FF A3 FF 83 FF 8B FF 83 FF
C7 FF 83 FF 93 FF 83 FF C7 FF 83 FF 83 FF 93 FF
C3 FF 93 FF 83 FF 87 FF C3 FF 83 FF BF FF FF FF {FF}*
*Start of the next tile


You can see the RLE in action.

Does this match up with any the compression/RLE method used by any other games?

April 28, 2020, 09:14:48 am - (Auto Merged - Double Posts are not allowed before 7 days.)
OK, I have figured out how it is working :)

This appears to be the RLE method:
Hex ValueMeaning
00End of data.
01-7FRead another byte, and write it to the output n times.
80Invalid.
81-FFCopy n - 128 bytes from input to output.

Sample Decoder in C#:
Code: [Select]
public byte[] RLEDecodeGraphics(byte[] data)
{
// Decode a byte array according to the following table.
// Note: Valid data must be found at array index 0.

// Value Meaning
// -----    ----------------------------------------------------------
// 00       End of data.
// 01 - 7F  Read another byte, and write it to the output n times.
// 80       Invalid.
// 81 - FF  Copy n -128 bytes from input to output.

int startingSize = 10000000; // maximum size of uncompresed data (truncated later)
byte[] decodedData = new byte[startingSize];

byte mask = 0x80; //-128 bytes

int dataLength = 0; // length of data to process
byte packedCharacter = 0x00; // currect character to output n times.
int byteCompressedCount = 0; // how far through the compressed data are we?
int byteUncompressedCount = 0; // how large has the uncompressed data gotten?

while (byteCompressedCount < data.Length) // go through all data
{
dataLength = data[byteCompressedCount]; // get current byte

if (dataLength == 0x00) //end of data block
{
byteCompressedCount += 1; // skip to next block if available, otherwise ends while loop (for valid data).
}
else if (dataLength > 0x80) // a block of raw (uncompressed) data follows
{
byteCompressedCount += 1; // move to data

dataLength = dataLength & ~mask; // (length n - 128)

for (int j = 0; j < dataLength; j++) // populate the decompressed data array
{
if (byteCompressedCount < data.Length)
{
decodedData[byteUncompressedCount] = data[byteCompressedCount];
byteUncompressedCount++;
byteCompressedCount++;
}
}
}
else if (dataLength < 0x80) // copy the following byte dataLength times
{
packedCharacter = data[byteCompressedCount + 1]; // get target byte to write

for (int j = 0; j < dataLength; j++) // populate the uncompressed data array
{
decodedData[byteUncompressedCount] = packedCharacter;
byteUncompressedCount++;
}

byteCompressedCount += 2; // move to next piece of data
}
else
{
//dataLength == 0x80 - do nothing...
}

}
Array.Resize(ref decodedData, byteUncompressedCount); // truncate uncompressed data byte array

return decodedData;
}

It is very similar to many other RLE's featured here: https://wiki.nesdev.com/w/index.php/Tile_compression, but it seems to be distinct. I have not vigorously tested the above, but it seems to hold true.

Sample decompressed tile data (image):

https://drive.google.com/open?id=1FgUPAgCHd6DulEbLq9MU2AzhLr8dHPTW

This entire 16x24 tilemap is loaded into VRAM (whilst in the Marathon mode).


I intend to modify the colours of the tetrominoes to match the "new" standard, and I will attempt to match the tiles to a more modern look too. I will try to do somthing similar to the original GB version too. Here's a sample of NES tiles in Tetris on original Gameboy, using an inverted palette (the only easy way to make the background black - palette ID 0 seems to be translucent, and other ID's are opaque, and drawn on top of the rest of the graphics...):
« Last Edit: April 28, 2020, 09:14:50 am by Ed101 »

Ed101

  • Jr. Member
  • **
  • Posts: 4
    • View Profile
Re: Tetris DX (Gameboy Color) - Tiles have straightforward RLE
« Reply #1 on: May 06, 2020, 09:47:20 pm »
I have made some good progress with this project, and I am able to change the pixels of the tiles, and the colours used within palettes...

I now have an encoding routine in C# (using .net), that can check the length of the encoded data, and can scrap the tiles at the end of the data to "squeeze" the new tiles within the space of the old tiles (useful for testing, before being able to change the references to the graphics data/following code).

Pastebin of RLE.cs:
https://pastebin.com/ABVsF4tB
This includes all the functions required to encode and decode graphics data (certain parameters must be set correctly). See the Program script, listed below, for more details on the parameters I have been using to edit the graphics for Marathon mode in Tetris DX.

This is an example of the side-effect of "squeezing" the graphics: (Image)


The black square is the lost data, most of this tile has be converted to "FF"'s, as this can be compressed easily to save space. You can see that this corrupted tile is the last tile in the VRAM block - look at the screen shot in my previous post (titled "Sample decompressed tile data"). This shouldn't be left in any final release, but while testing it makes it easier to see the changes in the tiles I have edited, without corrupting the layout of the ROM.

My code is not ready to release as a compiled version for general use yet, but here is my quick and dirty Main function (that is great for my needs) if you want to give it a go, and don't know C# very well:
Pastebin of Program.cs:
https://pastebin.com/qa2c3hzV



I have found Tile Molester to be a good tool for tile editing, allowing easy copy and pasting of tiles between files, and nice zoom and paint tools. Another tile editor with a very useful feature is YY-CHR: you can invert the palette, or otherwise swap the 4 "colours" (i.e. palette index) around. This can be used for a "palette swap" within 1 palette, or for swapping the palette index around for a set of tiles that use differently ordered palettes to each other. This palette swapping tool gets around issues you will encounter if trying to use the paint fill tool to "swap colours" in a tile.

I am still hunting down the references to which palette is used by the tetrominos in Tetris DX. However, it does seem that for the tiles representing the tetrominos that are locked in place (these are on the GBC's background layer): the index of the tile in the tilemap is used to generate the palette number. i.e. Tile's A0 and A8 use BG palette #2 because the first 3 bits of the first byte ("A" or 1010 in binary) are 010, which indicates palette 2.

Hopefully, if I change the tile that is used, I will get the results I need. I haven't worked out how the palettes are assigned to the "falling" pieces (the sprite versions) yet though.


BGB is a great emulator for debugging the assembly (ASM) as it runs, although I don't really understand ASM yet, I am slowly learning. I have only really used a hex editor before, relying on the concept of "tables", which requires a lot of stabbing in the dark! Seeing data in RAM is very helpful, which is why BGB is great. BGB is also handy for viewing the currently loaded palettes (and the colours in use), along with the tiles in VRAM.


Sprites on the GBC (which use the OBJ palettes) are technically limited to 3 colours, as colour index #0 is always transparent. Currently 6 palettes are used for the falling tetrominos, so I am currently limited on the number of colours available. The background tiles can use all 4 colours in a palette, however many other parts of the screen are coloured in Tetris DX, so currently not all colours can be changed freely. Also black and white are not "free", and will take up a slot in the palette, so this can also limit options if these colours are needed/used.

I used Photoshop's pipette and an image of the current tetrominos, and then put the 24-bit HTML colour code in Bud Melvin's online 15-bit colour converter to produce a 15-bit colour code. I then edited the ROM in a Hex Editor to swap out the old colours for the new ones (after finding the list of colours within the ROM). I had to alter the tiles for the tetrominos so that they were using different palette indexes (to accommodate the new colours in the palettes).

For Marathon mode (running on a GBC rather than a DMG):
  • The 16 palettes are at offset 0xA747 in the ROM
  • The encoded tilemap starts at offset 0x8179 in the ROM (and has a length of 0x9FC)
  • The background colours for each of the 5(?) level increments are stored at offset 0x4903 in the ROM

I used RGBTuner (part of the bmp2cgb package) to fine-tune the colours in BGB, on my DS Lite, and on my Game Boy Color (with added frontlight turned on and off). RGBTuner is a really useful tool, as it allows you to see what the colours actually look like on specific hardware, rather than what they "should" look like. You can save your changes to the SRAM of the "game" and extract them for your own use (or run the ROM with the new save in BGB to copy and paste from the palette there).


This is my current version of the tetrominos in Tetris DX (slightly modified block design, colours are a reasonable match of the current standard colours): (2 Images)



The goal is to have 2 use-able colours for each piece (excluding black; which is a 3rd colour used by all pieces), but that is not possible with the current palette arrangement. Even if the references to which palette is used can be changes, some pieces will still need to share a colour. If light blue and green share a colour, and orange and yellow share a colour, and purple and dark blue share a colour (or some equivalent variation), then this will work, as long as 7 OBJ palettes can be used (otherwise 2 pieces will have to share both colours - either 1 each or both use both).

At the moment: orange and yellow share a colour, and purple and dark blue share a colour. Green can only use red or white as a second colour (as the BG palette used is shared with the "heart" on the pause screen). Light blue uses its own two colours. Red and yellow have only one colour each (as they share an OBJ palette).



And a cheeky bonus (as this was easy to achieve): I present Magic Tetris Challenge with Tetris Guideline coloured tetrominos:
(Image)


You can patch the ROM with the following IPS to play it for yourself: https://drive.google.com/open?id=17LWy0dhwEdjSfiJF_J941oYkhZgVHRNZ

  • There is a limit of 1 colour per tetromino [other than them all sharing black]). It is very unlikely that more colours can be made available for use, as the rest of the screen's graphics use the remaining palettes.
  • I removed the "white" highlight from the tetrominos, as it is actually transparent, and is not always "pretty" as a result. I also did this to the grey "Magical" polyominos for the same reason.
  • The pips that make up the grid (and the "A" and "S" on the pause screen) are now orange, instead of pink, as a result of changing the colour of the L piece. I may change the reference to purple, if possible.
  • The pieces do not dim when locked in place (like in the original) I will probably rectify this in v1.1
  • I should probably tweak the colours to be more pastel, like the original. (coming in v1.1)



I will make a patch for the NES tiles in GB Tetris too, now that I can use YY-CHR to invert the graphics easily. I should be able to select the Space Invaders palette by default too for GBC (this is the only inbuilt one that is inverted). Custom palettes suit this best though. It would be amazing to change this in to a Super Game Boy game, and have the palette change every 10 levels :thumbsup: But surely far too much work!



I hope this is useful to those embarking on their own GBC graphic hacking endeavours.

Useful Links:
Game Boy Color - tile maps and palettes: https://www.chibiakumas.com/z80/platform.php#LessonP9
Game Boy Color - colour tweaking (RGBTuner, part of bmp2cgb): https://github.com/gitendo/bmp2cgb
24-bit -> 15-bit Colour converter: http://www.budmelvin.com/dev/15bitconverter.html
Emulator - BGB: https://bgb.bircd.org/
Tile Editor - Tile Molestor: https://www.romhacking.net/utilities/991/
Tile Editor - YY-CHR: https://www.romhacking.net/utilities/119/ (C++, older) OR http://www.romhacking.net/utilities/958/ (C# .net, newer) - both have the "colour swap" feature
Game Boy Header fixing - RGBDB (part of RGBDB): https://github.com/rednex/rgbds (rgbfix -f g game.gbc - to fix global checksum after making edits to rom)
Create and Apply IPS patches - Lunar IPS: https://www.romhacking.net/utilities/240/ (make sure only your patches, and no random errors or other hacks, are included before you create an IPS patch 8))

Rob2048

  • Newbie
  • *
  • Posts: 1
    • View Profile
Re: Tetris DX (Gameboy Color) - Tiles have straightforward RLE
« Reply #2 on: January 23, 2021, 07:42:14 am »
I have made some good progress with this project, and I am able to change the pixels of the tiles, and the colours used within palettes...

I now have an encoding routine in C# (using .net), that can check the length of the encoded data, and can scrap the tiles at the end of the data to "squeeze" the new tiles within the space of the old tiles (useful for testing, before being able to change the references to the graphics data/following code).

Pastebin of RLE.cs:
https://pastebin.com/ABVsF4tB
This includes all the functions required to encode and decode graphics data (certain parameters must be set correctly). See the Program script, listed below, for more details on the parameters I have been using to edit the graphics for Marathon mode in Tetris DX.

This is an example of the side-effect of "squeezing" the graphics: (Image)


The black square is the lost data, most of this tile has be converted to "FF"'s, as this can be compressed easily to save space. You can see that this corrupted tile is the last tile in the VRAM block - look at the screen shot in my previous post (titled "Sample decompressed tile data"). This shouldn't be left in any final release, but while testing it makes it easier to see the changes in the tiles I have edited, without corrupting the layout of the ROM.

My code is not ready to release as a compiled version for general use yet, but here is my quick and dirty Main function (that is great for my needs) if you want to give it a go, and don't know C# very well:
Pastebin of Program.cs:
https://pastebin.com/qa2c3hzV



I have found Tile Molester to be a good tool for tile editing, allowing easy copy and pasting of tiles between files, and nice zoom and paint tools. Another tile editor with a very useful feature is YY-CHR: you can invert the palette, or otherwise swap the 4 "colours" (i.e. palette index) around. This can be used for a "palette swap" within 1 palette, or for swapping the palette index around for a set of tiles that use differently ordered palettes to each other. This palette swapping tool gets around issues you will encounter if trying to use the paint fill tool to "swap colours" in a tile.

I am still hunting down the references to which palette is used by the tetrominos in Tetris DX. However, it does seem that for the tiles representing the tetrominos that are locked in place (these are on the GBC's background layer): the index of the tile in the tilemap is used to generate the palette number. i.e. Tile's A0 and A8 use BG palette #2 because the first 3 bits of the first byte ("A" or 1010 in binary) are 010, which indicates palette 2.

Hopefully, if I change the tile that is used, I will get the results I need. I haven't worked out how the palettes are assigned to the "falling" pieces (the sprite versions) yet though.


BGB is a great emulator for debugging the assembly (ASM) as it runs, although I don't really understand ASM yet, I am slowly learning. I have only really used a hex editor before, relying on the concept of "tables", which requires a lot of stabbing in the dark! Seeing data in RAM is very helpful, which is why BGB is great. BGB is also handy for viewing the currently loaded palettes (and the colours in use), along with the tiles in VRAM.


Sprites on the GBC (which use the OBJ palettes) are technically limited to 3 colours, as colour index #0 is always transparent. Currently 6 palettes are used for the falling tetrominos, so I am currently limited on the number of colours available. The background tiles can use all 4 colours in a palette, however many other parts of the screen are coloured in Tetris DX, so currently not all colours can be changed freely. Also black and white are not "free", and will take up a slot in the palette, so this can also limit options if these colours are needed/used.

I used Photoshop's pipette and an image of the current tetrominos, and then put the 24-bit HTML colour code in Bud Melvin's online 15-bit colour converter to produce a 15-bit colour code. I then edited the ROM in a Hex Editor to swap out the old colours for the new ones (after finding the list of colours within the ROM). I had to alter the tiles for the tetrominos so that they were using different palette indexes (to accommodate the new colours in the palettes).

For Marathon mode (running on a GBC rather than a DMG):
  • The 16 palettes are at offset 0xA747 in the ROM
  • The encoded tilemap starts at offset 0x8179 in the ROM (and has a length of 0x9FC)
  • The background colours for each of the 5(?) level increments are stored at offset 0x4903 in the ROM

I used RGBTuner (part of the bmp2cgb package) to fine-tune the colours in BGB, on my DS Lite, and on my Game Boy Color (with added frontlight turned on and off). RGBTuner is a really useful tool, as it allows you to see what the colours actually look like on specific hardware, rather than what they "should" look like. You can save your changes to the SRAM of the "game" and extract them for your own use (or run the ROM with the new save in BGB to copy and paste from the palette there).


This is my current version of the tetrominos in Tetris DX (slightly modified block design, colours are a reasonable match of the current standard colours): (2 Images)



The goal is to have 2 use-able colours for each piece (excluding black; which is a 3rd colour used by all pieces), but that is not possible with the current palette arrangement. Even if the references to which palette is used can be changes, some pieces will still need to share a colour. If light blue and green share a colour, and orange and yellow share a colour, and purple and dark blue share a colour (or some equivalent variation), then this will work, as long as 7 OBJ palettes can be used (otherwise 2 pieces will have to share both colours - either 1 each or both use both).

At the moment: orange and yellow share a colour, and purple and dark blue share a colour. Green can only use red or white as a second colour (as the BG palette used is shared with the "heart" on the pause screen). Light blue uses its own two colours. Red and yellow have only one colour each (as they share an OBJ palette).



And a cheeky bonus (as this was easy to achieve): I present Magic Tetris Challenge with Tetris Guideline coloured tetrominos:
(Image)


You can patch the ROM with the following IPS to play it for yourself: https://drive.google.com/open?id=17LWy0dhwEdjSfiJF_J941oYkhZgVHRNZ

  • There is a limit of 1 colour per tetromino [other than them all sharing black]). It is very unlikely that more colours can be made available for use, as the rest of the screen's graphics use the remaining palettes.
  • I removed the "white" highlight from the tetrominos, as it is actually transparent, and is not always "pretty" as a result. I also did this to the grey "Magical" polyominos for the same reason.
  • The pips that make up the grid (and the "A" and "S" on the pause screen) are now orange, instead of pink, as a result of changing the colour of the L piece. I may change the reference to purple, if possible.
  • The pieces do not dim when locked in place (like in the original) I will probably rectify this in v1.1
  • I should probably tweak the colours to be more pastel, like the original. (coming in v1.1)



I will make a patch for the NES tiles in GB Tetris too, now that I can use YY-CHR to invert the graphics easily. I should be able to select the Space Invaders palette by default too for GBC (this is the only inbuilt one that is inverted). Custom palettes suit this best though. It would be amazing to change this in to a Super Game Boy game, and have the palette change every 10 levels :thumbsup: But surely far too much work!



I hope this is useful to those embarking on their own GBC graphic hacking endeavours.

Useful Links:
Game Boy Color - tile maps and palettes: https://www.chibiakumas.com/z80/platform.php#LessonP9
Game Boy Color - colour tweaking (RGBTuner, part of bmp2cgb): https://github.com/gitendo/bmp2cgb
24-bit -> 15-bit Colour converter: http://www.budmelvin.com/dev/15bitconverter.html
Emulator - BGB: https://bgb.bircd.org/
Tile Editor - Tile Molestor: https://www.romhacking.net/utilities/991/
Tile Editor - YY-CHR: https://www.romhacking.net/utilities/119/ (C++, older) OR http://www.romhacking.net/utilities/958/ (C# .net, newer) - both have the "colour swap" feature
Game Boy Header fixing - RGBDB (part of RGBDB): https://github.com/rednex/rgbds (rgbfix -f g game.gbc - to fix global checksum after making edits to rom)
Create and Apply IPS patches - Lunar IPS: https://www.romhacking.net/utilities/240/ (make sure only your patches, and no random errors or other hacks, are included before you create an IPS patch 8))


Is there any way I can download the room for Tetris DX with the guideline tetrominoes?