Jump to content
NHL'94 Forums

HOW TO: "Decompress" Graphics in Sega Genesis


Recommended Posts

When we say the hacked ROMs for Genesis had the graphics "decompressed", that's not exactly the right terminology.  The graphics that are used, at least in the EA series that I've looked at, have shared tiles.  They are not "compressed" as you can still see all the graphics when you open Tile Molester, but it won't look exactly like the "what you see is what you get (WYSIWYG)" in the game.  That's due to the use of shared tiles.  Back in the 90's, chip size was important/expensive, so the smaller you can make the game work the better.  Graphic data by far takes up the most space on the ROM, so if you can re-use certain tiles for an image, that would help reduce the size without impacting the game.  

I'll explain how this works, and how @wboy and others fixed this.  I won't go into how to find the locations/palettes as this can be found elsewhere in the forums.  I'd also like to thank @slapshot67 for explaining this to me a while back.

A few basics:

  • Everything uses Hex values.  This means each digit goes to F instead of 9 (base 16 instead of 10).  Google for more info separately, but it's not that hard to grasp.
  • Graphics in Genesis are broken down into tiles.  Each tile is 8x8 pixels, or 64 pixels in total.
    • Tiles are basically a "paint by number"  - I explain that here
  • Each tile can use one 16 color palette.  
    • There can be 4 different palettes to choose from


First, let's take a look at how the data structure works in Hex for MOST graphics.  There are instances where this may not be the same, but for the vast majority of graphics work this way.

Let's start with the Anaheim Ducks team selection logo.  This is a 6x6 (tiles) logo.  The location of the information for the Anaheim logo is BF8D0 in the original ROM.   Here's how everything looks in Hex.  I'll break down each section and explain.

Anaheim Logo - Original Hex - Colors.png

The start of the graphic is always a 10 byte header, which I highlighted in green.  I think it will make more sense to explain the header later. 

The purple highlighted section is the graphic tile data.  This is the data that is much better viewed in Tile Molester.  I'll explain and show you how TM translates this data to a user friendly interface. 

As I mentioned earlier, graphic tiles are 8x8 pixels.  Each tile is represented in hex by 32 bytes, with each byte representing 2 pixels ,for a total of 64.  Each digit is simply what color on the palette to load, starting on the top of the tile, working from left to right.  For example, here is the first tile (first section of purple) translated from hex in TM:

Hex to TM.png

Not the greatest example, but it's easy to follow.  When you see a bunch of "5555", that's the 6th color (starts at 0) in the palette, in this case white throughout the first tile. 

So the purple section is all the tile information for 34 total tiles (explained later).  

After all the graphic data, you'll see the tile layout information begin with the orange section.  The orange section tells you what the layout is in the number of tiles in length x width.  In our logo example, this is 6x6.  That's pretty straightforward. 

The last highlighted section is the tile layout.  Each 2 bytes represents which tile to use, and you'll find 36 tile layouts for the 6x6 logo graphic.  

The first digit is the palette being used:

0 - Palette 1
2 - Palette 2
4 - Palette 3
6 - Palette 4

If the tile is flipped vertically, the number is 1 higher (1,3,5,7).  The next byte will show the horizontal flip.  0 is normal and 8 will flip horizontal.  You're likely not going to be flipping tiles vertically or horizontally for your new image, so don't worry too much about that.  

The next byte is the tile number used.  In our example, you'll see the tile layout starts with 2000, 2001, 2002...until all 36 are listed.  This means the logo is using palette 2, tile 00, tile 01, etc. 

Now back to the header!  The first 4 bytes of the header is the length of the data.  This is usually just adding the header (10 bytes) and the graphic data (tiles).  Remember, the graphic data is 32 bytes for every tile.  

The next 4 bytes is usually the length of the data plus the palette if it's located.  A lot of times a graphic will have the palette located right after the tiles, and these bytes will account for the extra palette information. Our team logos do not, and as such the 4 bytes will both be the same.  I'll show another example that has a palette later.  

The final two bytes is the number of tiles represented in hex.  

So in our Anaheim logo example header reads as follows "0000 044A 0000 044A 0022"

Starting at the end - "0022" says that this graphic has 34 tiles (22 is hex for 34).

The beginning and middle both have "000 044A".  That represents a data length of 1,098 bytes (044A is hex for 1,098).  Here's the math --  34 tiles x 32 bytes equals 1,088.  Add 10 for the header and you have 1,098!  

This is important to understand because when we expand the graphic, we will have to adjust the header accordingly for the game to understand.

SO NOW, how do we "decompress" or make the graphics more hacking-friendly?

Using our logo example, the first thing we need to do is make each graphic 36 tiles.  You may have picked up that our Anaheim logo in the game has 34 tiles, which means that 2 tiles are used more than once in the graphic. If you looked closely at the layout, you will see that tile 17 is used 3x.  This actually the blank tile, which is pretty common.  

Anaheim Logo - Original TM w tile number.png


So let's "decompress" Anaheim's logo to fix the shared tiles problem.  The first thing we need to do is find some room in the ROM for the new logo!  Wboy expanded the original ROM from 1MB to 2MB, thereby giving him plenty of space to put in some new graphics.  Expanding from 1MB to 2MB is pretty easy, but I won't cover that here.  Just know you need to find some space.  The 95 ROM actually had enough blank space already for new graphics.  

Use TM to paste in the new picture in the empty part of the ROM, say location 1C85B8, and that picture is now 36 full tiles for Anaheim logo, not 34.  Right before the tile data, we need to update the header for the graphic.  The new size will be 36 tiles x 32 bytes or 1,152 bytes.  Add 10 for the header and our data length is 1,162, or 048A in hex.  We also know we are using 36 tiles, and that is 0024 in Hex. 

Our new header should read "0000 048A 0000 048A 0024

Immediately after the TM data, we need to now put the tile layout in Hex.  The logo remains 0006 0006 (6x6) and the tile layout will be sequential since we are not using any shared tiles.  The layout will be 2000, 2001, 2002....all the way to tile 36 (2023).  

This is how it looks like in the 30 team ROM:

30 team Anaheim Hex -colors.png

I highlighted the header and tile layout.  

Anaheim Logo -  30 team.png


So now that you have the full "uncompressed" graphic loaded, the final step is to change the pointers in the game to the new graphic.  A pointer is just what it sounds like -- it points the ROM to the new graphic.  You can typically find the pointer by looking for the header location in the ROM itself.  

So in our example, the Anaheim logo header for the original game was BF8D0.  If you search for hex values "000B F8D0" in the ROM you'll find that the pointer is located at F86F2.  If you change F86F2 to your new location (1C85AE), the game will now read the new logo.  


NOTE: In wboy's 30 team ROM, he also changed the location of the pointer table, so this particular part of our example won't be 1:1.

I hope this was a helpful crash course into how graphics work and how we "decompress", or get rid of shared tiles.  

I'll give another example of a graphic that has the palette information within the data structure as a response to this post.  This took me a little longer than I thought, lol.  But basically every graphic that was hacked followed this procedure.  

In short:

* Make or find room in the ROM for a new graphic
* Make sure the header and layout information reflects that graphic correctly.
* Change the pointer to the new graphic

  • Thanks 5
Link to comment
Share on other sites

@kingraph that's why your one of the best. This will help me with so many other games to better understand the graphics components. Here is a few that this will majorly help.

NBA Live 98 - Already hacking the images and have the palettes, but this will allow it to look clean. 

Tecmo Super Bowl 3 (Sega) - will help to find and update the logos.

World Series Baseball - Already hacked the logos on the Nationals and Orioles ( They are a 7x7 graphics and are played out top row of 1x4 seven times and than 1x3 for the bottom row seven times. This is the same for NBA Live 98)

A tip of the hat is always well deserved for acknowledgment and respect. You get both my friend. 

  • Thanks 1
Link to comment
Share on other sites

  • 1 year later...
On 8/6/2020 at 6:23 PM, kingraph said:
  • Graphics in Genesis are broken down into tiles.  Each tile is 8x8 pixels, or 64 pixels in total.
    • Tiles are basically a "paint by number"  - I explain that here
  • Each tile can use one 16 color palette.  
    • There can be 4 different palettes to choose from

@kingraphVery interesting post! Do you know if this same logic can be applied when looking at SNES graphics? Is SNES also broken into tiles with 8x8 pixels and do we know if SNES also has 4 different palettes of 16 colors? Are SNES logos also 6 X 6 tiles?

Link to comment
Share on other sites

49 minutes ago, dangler said:

@kingraphVery interesting post! Do you know if this same logic can be applied when looking at SNES graphics? Is SNES also broken into tiles with 8x8 pixels and do we know if SNES also has 4 different palettes of 16 colors? Are SNES logos also 6 X 6 tiles?

The graphics in SNES are way more advanced than Sega, and I can't even comment on how it actually works as I haven't done much SNES hacking.  This article summarizes the graphic differences nicely: nicely: https://en.wikipedia.org/wiki/List_of_video_game_console_palettes

So tiles are 8x8, but the palettes are more complex (see article).  As far as logos, I venture to guess they are 7x7 solely based on the screenshots I've taken of logos (56x56 pixels)

The big issue with SNES is that the graphics are actually compressed.  Meaning, you won't find any graphics if you open up a SNES '94 ROM in Tile Molester.  There is some algorithm that the SNES applies to translate pieces of code into the graphics we see.  Even more difficult, those compression routines are unique to each game (or my understanding is some games have similar compression routines), so it's not like a piece of software exists that decompresses ALL SNES graphics for you to edit, and then recompress to the ROM.  You basically have to figure out the routine for '94 yourself.  My understanding is it's complicated too.  And that's why we haven't had any progress on SNES graphic hacks. 

Recently, on the '94 Discord Server (#rom-hacking), and I think you've seen this, there was a Microsoft Direct X developer who gave some good advice on how to possibly think about this differently for SNES (thanks for sharing @INDIO)

"I haven't tried to edit logos yet. I had some notes and observations when doing stuff for the player profile photos that might help

For editing player profile photos, I went with a "path of least resistance". I didn't try to reverse-engineer the whole decompression mechanism. Instead I put full decompressed images into the ROM and changed the decompress into a very dumb copy. I have a thing of "work smarter not harder" given I want only a certain end result, doesn't matter how elegant it is or whether it requires ROM expansion. For purposes of this project I treat ROM expansion as free. If you have the same priorities, you might want to do the same thing.

Why do the same thing? Because the decompression code is organized weirdly and is complicated. Although I didn't strictly have to I looked at it out of curiosity for profile images. And team logos use the same thing, from what I can tell. But if you still want to know about it:

I disassembled most of the decompression code, added some labels, factored out some loops. See here: https://github.com/clandrew/nhl94e/blob/main/docs/rough/DecompressProfileMain.asm

There is a bunch of code with data sprinkled in. That data is jump tables. Each element of the jump tables in general is short offset.
The real meat of the decompression is in this function: DecompressFB30(). To get started you would probably want to set a breakpoint there at 0x80BBB3. That's a common path between profile images and team logos.

General vibe is the compression optimizes for sequential series of like numbers. So like, if there's a sea of 99 0s, rather than store 0 repeatedly it will just store "99" "0" so to speak."



Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Who's Online   0 Members, 0 Anonymous, 16 Guests (See full list)

    • There are no registered users currently online
  • Create New...