Ondo
Smash Apprentice
- Joined
- Jun 20, 2007
- Messages
- 160
So when doing CSPs that are just recolors of each other, it's possible to store them much more efficiently, as a single set of indexed image data, with each image having a different palette, since it's only the colors that differ.
I've figured out how to implement this in brres files, and written a program that converts images appropriately, and added support to BrawlBox.
As an example of what can be done, using this technique with SJS's CSPs let me reduce the size of sc_selcharacter.pac from 2,811 KB (starting from my compact CSS) to 2,088 KB, while increasing the quality of the CSPs. You can download that here.
CSP preparation
Before using this technique on CSPs, I suggest masking out the parts of the CSP that can't be seen - this saves space, and reduces the number of colors in the image, so the final quality will be higher. (Ideally I'd like to see this done for all CSPs before they are distributed.)
The batch file and masks I use are available here. It requires ImageMagick. Running it works like "MaskCSPs Mask.gif", to convert every PNG file in the directory you're in, and all sub-directories (recursively), with the pixels that are black in Mask.gif converted to transparent.
For most characters, I included pixels that are not directly visible, but cast a shadow that is visible. For portraits that fill the bottom left corner where the shadow would be visible, like those of Ganondorf and Ike's default costume in the Brawl pose, or SJS's pose of Bowser, Marth, or Ike, I have another mask (MaskPotentialShadowCovered.gif) that only includes the pixels that are directly visible. (Using the main mask saves around 972 bytes per CMPR CSP; using the shadow covered mask saves an average of 36 more bytes, so it's not a big deal, but it is a little free space.)
If you want to do it in a safer way, you can just run "convert INPUTFILE Mask.gif -compose DstOut -composite OUTPUTFILE". (Replace INPUTFILE with the file you want to convert, and OUTPUTFILE with whatever you want to name the result. Same as INPUTFILE if you just want to overwrite, which is what the batch file does but probably not what you want to do if you're doing them one at a time.)
Step 1: Convert to 256 colors
First use the ColorSmash tool (available here) to convert the images to 256 colors in such a way that the indexed image data can be shared. An example of the command for this looks like this:
..\color_smash -c RGB5A3 -s " (main)" 1.png 2-brawlfire.png 3-brawlblue.png 4-brawlgreen.png 5-brawlblack.png
(I have the tool in my main directory, along with a directory for each character with their CSPs. So I preface the command with '..\'; if you're directory structure is different, that will be different for you.)
To break that down: -c RGB5A3 is always wanted; it tells it to output in the RGB5A3 colorspace, which is what Brawl will use. (If we use RGBA8 when quantizing, we may end up with some of our 256 colors converting to the same color when BrawlBox converts it to RGB5A3.) After -s is the suffix that is added to the file name, so you can use whatever you want. In my example, the results will be "1 (main).png", and so on. I use " (main)" when doing the standard version of a costume and all its recolors, " (alt)" when doing an alt costume and its recolors, " (solo)" when doing a single image by itself, " (all)" when doing every CSP together, and something descriptive when doing something else.
It's particularly helpful to set different suffixes when trying out multiple different ways to group CSPs, in order to try and balance quality and size.
After the suffix is just the list of files to convert; all of them will be quantized together, so they can be stored with shared index data.
Step 2: Add to BrawlBox
Make sure you have BrawlBox 0.77 (or newer). Import each image into BrawlBox as CI8, and check the "Import Palette" box. Make sure the images in the group are all next to each other, reordering if needed. (For example, for Yoshi I found doing the darker colors - the 2nd, 3rd, 7th, and 9th costumes - together worked best, so I needed to reorder those to be next to each other.) Then, for each group, update the ShareData property from false to true for all but the last costume in the group.
Let me know if you have any questions, or encounter any issues.
(Just for the record, here's the original method I posted back before BrawlBox support was added in 0.77. It was harder then.)
I've figured out how to implement this in brres files, and written a program that converts images appropriately, and added support to BrawlBox.
As an example of what can be done, using this technique with SJS's CSPs let me reduce the size of sc_selcharacter.pac from 2,811 KB (starting from my compact CSS) to 2,088 KB, while increasing the quality of the CSPs. You can download that here.
CSP preparation
Before using this technique on CSPs, I suggest masking out the parts of the CSP that can't be seen - this saves space, and reduces the number of colors in the image, so the final quality will be higher. (Ideally I'd like to see this done for all CSPs before they are distributed.)
The batch file and masks I use are available here. It requires ImageMagick. Running it works like "MaskCSPs Mask.gif", to convert every PNG file in the directory you're in, and all sub-directories (recursively), with the pixels that are black in Mask.gif converted to transparent.
For most characters, I included pixels that are not directly visible, but cast a shadow that is visible. For portraits that fill the bottom left corner where the shadow would be visible, like those of Ganondorf and Ike's default costume in the Brawl pose, or SJS's pose of Bowser, Marth, or Ike, I have another mask (MaskPotentialShadowCovered.gif) that only includes the pixels that are directly visible. (Using the main mask saves around 972 bytes per CMPR CSP; using the shadow covered mask saves an average of 36 more bytes, so it's not a big deal, but it is a little free space.)
If you want to do it in a safer way, you can just run "convert INPUTFILE Mask.gif -compose DstOut -composite OUTPUTFILE". (Replace INPUTFILE with the file you want to convert, and OUTPUTFILE with whatever you want to name the result. Same as INPUTFILE if you just want to overwrite, which is what the batch file does but probably not what you want to do if you're doing them one at a time.)
Step 1: Convert to 256 colors
First use the ColorSmash tool (available here) to convert the images to 256 colors in such a way that the indexed image data can be shared. An example of the command for this looks like this:
..\color_smash -c RGB5A3 -s " (main)" 1.png 2-brawlfire.png 3-brawlblue.png 4-brawlgreen.png 5-brawlblack.png
(I have the tool in my main directory, along with a directory for each character with their CSPs. So I preface the command with '..\'; if you're directory structure is different, that will be different for you.)
To break that down: -c RGB5A3 is always wanted; it tells it to output in the RGB5A3 colorspace, which is what Brawl will use. (If we use RGBA8 when quantizing, we may end up with some of our 256 colors converting to the same color when BrawlBox converts it to RGB5A3.) After -s is the suffix that is added to the file name, so you can use whatever you want. In my example, the results will be "1 (main).png", and so on. I use " (main)" when doing the standard version of a costume and all its recolors, " (alt)" when doing an alt costume and its recolors, " (solo)" when doing a single image by itself, " (all)" when doing every CSP together, and something descriptive when doing something else.
It's particularly helpful to set different suffixes when trying out multiple different ways to group CSPs, in order to try and balance quality and size.
After the suffix is just the list of files to convert; all of them will be quantized together, so they can be stored with shared index data.
Step 2: Add to BrawlBox
Make sure you have BrawlBox 0.77 (or newer). Import each image into BrawlBox as CI8, and check the "Import Palette" box. Make sure the images in the group are all next to each other, reordering if needed. (For example, for Yoshi I found doing the darker colors - the 2nd, 3rd, 7th, and 9th costumes - together worked best, so I needed to reorder those to be next to each other.) Then, for each group, update the ShareData property from false to true for all but the last costume in the group.
Let me know if you have any questions, or encounter any issues.
(Just for the record, here's the original method I posted back before BrawlBox support was added in 0.77. It was harder then.)
Preparation
You can download the tools for doing this here. They're all command line tools, and hex editing will also be required - I use HxD (http://mh-nexus.de/en/hxd/).
I have the tools together in one directory, and also a directory for each character with their CSPs. So I'll be prefacing each command with '..\'; if you're directory structure is different, that will be different for you.
Step 1: Convert to 256 colors
The first step is using ColorSmash to convert the images to 256, in such a way that the indexed image data can be shared. An example of the command for this looks like this:
..\color_smash -c RGB5A3 -s " (main group)" 1.png 2-brawlfire.png 3-brawlblue.png 4-brawlgreen.png 5-brawlblack.png
To break that down: -c RGB5A3 is always wanted; it tells it to output in the RGB5A3 colorspace, which is what Brawl will use. (If we use RGBA8 when quantizing, we may end up with some of our 256 colors converting to the same color when BrawlBox converts it to RGB5A3.) After -s is the suffix that is added to the file name, so you can use whatever you want. In my example, the results will be "1 (main group).png", and so on. I use " (main group)" when doing the standard version of a costume and all its recolors, " (alt group)" when doing an alt costume and its recolors, " (solo)" when doing a single image by itself, " (all)" when doing every CSP together, and something descriptive when doing something else.
It's particularly helpful to set different suffixes when trying out multiple different ways to group CSPs, in order to try and balance quality and size.
After the suffix is just the list of files to convert; all of them will be quantized together, so they can be stored with shared index data.
Step 2: Convert to Brawl format
The second step is using to_tex0 to convert the images to the tex0 and plt0 files that Brawl uses. (If you have a solo image that's not part of a group, you can skip this step, since BrawlBox will handle it for you.) Example command:
..\to_tex0 "1 (main group).png" "2-brawlfire (main group).png" "3-brawlblue (main group).png" "4-brawlgreen (main group).png" "5-brawlblack (main group).png"
Note that order is important - the order they're given to to_tex0 should be the same order they'll be in the BRRES file in BrawlBox.
Step 3: Add to BrawlBox
First, make sure every CSP that is in a group has an associated palette, re-encoding the current CSP to CI8 if necessary. That will let us replace the palette later, rather than having to add it.
If necessary, reorder the images so that images that will share data are next to each other. For example, when I grouped Zero Suit Samus's images, I grouped together the 1st, 2nd, 3rd, 5th, and 6th CSPs, but not the 4th (because it has a somewhat different pattern), so at this point I move the 4th CSP down beneath the 5th and 6th.
Then, for each CSPs Texture, replace it with the appropriate tex0 file (or just the PNG, if it was a solo image). Do the same with the palettes and the plt0 files. Within each group, every tex0 except the last is set to 0 width and height, so don't be surprised when the BrawlBox preview disappears when you've replaced the images.
Once that's done, switch the compression for the BRRES containing the images to None (from ExtendedLZ77), and export the BRRES.
Step 4: Hex edit the BRRES
We're going to want to edit the TEX0 header of each image in a group, except the last, to increase the size of the image from 0x0 to the proper 128x160, and increase the size from 0x40 to 0x5000 plus the size of the header, which is 0x40 for the last image, 0x80 for the one before it, and so on, increasing by 0x40 each time. (That is, each header's size is the length from it to the start of the shared image data.)
Seach for TEX0 in the file - each one marks the start of a TEX0 header, and if there is another one 0x40 bytes after the first, this is a group that you'll want to edit.
For each header, the length is the four bytes directly after the TEX0 marker. The last one in the group should already be set to 00 00 50 40. You'll want to set the one before that to 00 00 50 80 (from 00 00 00 40), then the prior one to 00 00 50 C0, then 00 00 51 00, and so on. The length of each header is stored 16 bytes after the TEX0 marker (so on the next line, if you're showing 16 bytes per line), and should be set correctly already (0x40 for the last, 0x80 for the prior one, and so on), so you can check against that - the length you're setting should be 0x5000 more than that number.
The width and height are 0x1C bytes after TEX0, and should be set to 00 80 00 A0. It should already be set to that for the last one, for the others you'll need to switch it from 00 00 00 00.
Here's a screenshot of the changes I made for one group of 5:
Once you've done that for every group, save the file.
Step 5: Compress the BRRES
Next step is to compress the BRRES again. If BrawlBox does this, it'll split apart the shared data, so I made a tool specifically for this. Example command:
..\SmashLZ77 MiscData[0].brres
This will output MiscData[0]-lz77.brres.
Step 6: Import the new BRRES
In BrawlBox again, just replace the BRRES with the edited and compressed version. That's it! Check how it looks - in BrawlBox 0.76b, it doesn't skip the header properly when it's more than the standard 0x40 bytes, so there'll be extra junk at the start of the image, but this won't show up in game, and it does let you tell when images are in groups.
Note that any change that causes BrawlBox to recompress the BRRES will also split apart the shared data, so avoid doing that...
You can download the tools for doing this here. They're all command line tools, and hex editing will also be required - I use HxD (http://mh-nexus.de/en/hxd/).
I have the tools together in one directory, and also a directory for each character with their CSPs. So I'll be prefacing each command with '..\'; if you're directory structure is different, that will be different for you.
Step 1: Convert to 256 colors
The first step is using ColorSmash to convert the images to 256, in such a way that the indexed image data can be shared. An example of the command for this looks like this:
..\color_smash -c RGB5A3 -s " (main group)" 1.png 2-brawlfire.png 3-brawlblue.png 4-brawlgreen.png 5-brawlblack.png
To break that down: -c RGB5A3 is always wanted; it tells it to output in the RGB5A3 colorspace, which is what Brawl will use. (If we use RGBA8 when quantizing, we may end up with some of our 256 colors converting to the same color when BrawlBox converts it to RGB5A3.) After -s is the suffix that is added to the file name, so you can use whatever you want. In my example, the results will be "1 (main group).png", and so on. I use " (main group)" when doing the standard version of a costume and all its recolors, " (alt group)" when doing an alt costume and its recolors, " (solo)" when doing a single image by itself, " (all)" when doing every CSP together, and something descriptive when doing something else.
It's particularly helpful to set different suffixes when trying out multiple different ways to group CSPs, in order to try and balance quality and size.
After the suffix is just the list of files to convert; all of them will be quantized together, so they can be stored with shared index data.
Step 2: Convert to Brawl format
The second step is using to_tex0 to convert the images to the tex0 and plt0 files that Brawl uses. (If you have a solo image that's not part of a group, you can skip this step, since BrawlBox will handle it for you.) Example command:
..\to_tex0 "1 (main group).png" "2-brawlfire (main group).png" "3-brawlblue (main group).png" "4-brawlgreen (main group).png" "5-brawlblack (main group).png"
Note that order is important - the order they're given to to_tex0 should be the same order they'll be in the BRRES file in BrawlBox.
Step 3: Add to BrawlBox
First, make sure every CSP that is in a group has an associated palette, re-encoding the current CSP to CI8 if necessary. That will let us replace the palette later, rather than having to add it.
If necessary, reorder the images so that images that will share data are next to each other. For example, when I grouped Zero Suit Samus's images, I grouped together the 1st, 2nd, 3rd, 5th, and 6th CSPs, but not the 4th (because it has a somewhat different pattern), so at this point I move the 4th CSP down beneath the 5th and 6th.
Then, for each CSPs Texture, replace it with the appropriate tex0 file (or just the PNG, if it was a solo image). Do the same with the palettes and the plt0 files. Within each group, every tex0 except the last is set to 0 width and height, so don't be surprised when the BrawlBox preview disappears when you've replaced the images.
Once that's done, switch the compression for the BRRES containing the images to None (from ExtendedLZ77), and export the BRRES.
Step 4: Hex edit the BRRES
We're going to want to edit the TEX0 header of each image in a group, except the last, to increase the size of the image from 0x0 to the proper 128x160, and increase the size from 0x40 to 0x5000 plus the size of the header, which is 0x40 for the last image, 0x80 for the one before it, and so on, increasing by 0x40 each time. (That is, each header's size is the length from it to the start of the shared image data.)
Seach for TEX0 in the file - each one marks the start of a TEX0 header, and if there is another one 0x40 bytes after the first, this is a group that you'll want to edit.
For each header, the length is the four bytes directly after the TEX0 marker. The last one in the group should already be set to 00 00 50 40. You'll want to set the one before that to 00 00 50 80 (from 00 00 00 40), then the prior one to 00 00 50 C0, then 00 00 51 00, and so on. The length of each header is stored 16 bytes after the TEX0 marker (so on the next line, if you're showing 16 bytes per line), and should be set correctly already (0x40 for the last, 0x80 for the prior one, and so on), so you can check against that - the length you're setting should be 0x5000 more than that number.
The width and height are 0x1C bytes after TEX0, and should be set to 00 80 00 A0. It should already be set to that for the last one, for the others you'll need to switch it from 00 00 00 00.
Here's a screenshot of the changes I made for one group of 5:

Once you've done that for every group, save the file.
Step 5: Compress the BRRES
Next step is to compress the BRRES again. If BrawlBox does this, it'll split apart the shared data, so I made a tool specifically for this. Example command:
..\SmashLZ77 MiscData[0].brres
This will output MiscData[0]-lz77.brres.
Step 6: Import the new BRRES
In BrawlBox again, just replace the BRRES with the edited and compressed version. That's it! Check how it looks - in BrawlBox 0.76b, it doesn't skip the header properly when it's more than the standard 0x40 bytes, so there'll be extra junk at the start of the image, but this won't show up in game, and it does let you tell when images are in groups.
Note that any change that causes BrawlBox to recompress the BRRES will also split apart the shared data, so avoid doing that...
Last edited: