Hum, so I was about to suggest extracting the whole script from the PS2 version and automatically inserting it in the PSP version. Even if file names and text distribution are different in both versions, one can always sort everything using some brute force coding with text comparing. Even if the Japanese text is a little bit different in both versions, we have the Levensthein distance algorithm for that (Yeah, I've done automatic "translations" in the scene, using official localizations from different versions of a same game xD).
BUT... Looks like everything one could get from the PS2 versions is already on PSP so nvm xD.
Now on IMY format...
***In the beginning they were all regular graphics (like any PNG one can come across), more specifically, RGBA8888 images.
***Then they were reduced to 8, or 4 bit indexed images (depending of the image size and color count), keeping the alpha channel, and coded in a custom (very simple) format:
---A header with some information such as signature and resolution.
---A color palette that can be either 16 or 256 colors (4/8 bits pixels respectively)
---The pixels themselves, each one being an index to the color palette, which actually holds RGBA8888 colors.
***Then they were compressed adding some compression flags to the header.
And that's an IMY. Now all that has to be reverted... It actually sounds harder that it is.
First step... Decompression! Well, this can be done looking at the game's ASM code in a MIPS debugger (PPSSPP/JPCSP). You can also use a dissembler, but it's kind of a pain to find anything just with it. Monitoring the ram we can tell when an image is being decompressed and look the routine writing to the output buffer (the decompressiion routine).
In our specific case, the color palette is uncompressed in IMY files, so we trace the pixels decompression routine. An here we have it:
Code:
z_un_08825b14:
addiu sp,sp,-0x10
li a0,-0x2
mult t0,a3
subu t1,zero,a3
sw a0,0x0(sp)
addiu a0,t1,-0x2
sw t1,0x4(sp)
addiu a3,t1,0x2
sw a0,0x8(sp)
sw a3,0xC(sp)
lhu a3,0x0(a2)
mflo a0
addu a0,a1,a0
bne zero,a3,pos_08825B68
addiu a2,a2,0x2
addiu a3,a2,0x2
lhu t0,0x0(a2)
lhu t1,0x0(a3)
addiu a2,a3,0x2
sll a3,t1,0x10
or a3,t0,a3
pos_08825B68:
addu t0,a3,a2
lbu a3,0x0(a2)
pos_08825B70:
addiu t1,a3,-0x10
bgez t1,pos_08825BAC
addiu a2,a2,0x1
addiu a3,a3,0x1
pos_08825B80:
lh t1,0x0(t0)
addiu t0,t0,0x2
sh t1,0x0(a1)
addiu a3,a3,-0x1
bne zero,a3,pos_08825B80
addiu a1,a1,0x2
sltu a3,a1,a0
bnel zero,a3,pos_08825B70
lbu a3,0x0(a2)
b pos_08825C24
nop
pos_08825BAC:
addiu a3,a3,-0xC0
bgezl a3,pos_08825BE8
sra t1,a3,0x4
addu a3,t1,t1
subu a3,zero,a3
addu a3,t0,a3
lh a3,-0x2(a3)
sh a3,0x0(a1)
addiu a1,a1,0x2
sltu a3,a1,a0
bnel zero,a3,pos_08825B70
lbu a3,0x0(a2)
b pos_08825C24
nop
sra t1,a3,0x4
pos_08825BE8:
sll t1,t1,0x2
addu t1,sp,t1
lw t1,0x0(t1)
andi a3,a3,0xF
addiu a3,a3,0x1
addu t1,a1,t1
pos_08825C00:
lh t2,0x0(t1)
addiu t1,t1,0x2
sh t2,0x0(a1)
addiu a3,a3,-0x1
bne zero,a3,pos_08825C00
addiu a1,a1,0x2
sltu a3,a1,a0
bnel zero,a3,pos_08825B70
lbu a3,0x0(a2)
pos_08825C24:
jr ra
addiu sp,sp,0x10
The important registers you must take into account are:
--- a1 -> Output buffer (obviously empty at the beginning of the routine xD)
--- a2 -> input buffer (the one with the compressed pixel data)
--- a3 -> image width (from the IMY header)
--- t0 -> image height (from the IMY header as well)
Once the routine returns the output buffer contains the pixels decompressed.
Now we have color palette, pixels and dimensions, we can reproduce an image right? Yeah... but no, reproducing the image just like that would result in garbage, as both parts (pixels and palette) are interlaced. There is no standard way of interlacing and depending on the image color depth, color count, and dimensions you may need different interlacing implementations. There is no way to get the interlacing algorithm out of the game's data, since this is done at hardware level, and no one is gonna code a PSP graphic memory simulator just for this
...
...Mainly because for 100% of cases you can tweak this code and get a perfectly deinterlaced pixel matrix:
Code:
public static void UnSwizzle(ref byte[] Buf, int Pointer, int Width, int Height)
{
// Make a copy of the unswizzled input
byte[] Swizzled = new byte[Buf.Length - Pointer];
Array.Copy(Buf, Pointer, Swizzled, 0, Swizzled.Length);
int rowblocks = (Width / 16);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int blockx = x / 16;
int blocky = y / 8;
int block_index = blockx + (blocky * rowblocks);
int block_address = block_index * 16 * 8;
Buf[Pointer + x + (y * Width)] = Swizzled[block_address + (x - blockx * 16) + ((y - blocky * 8) * 16)];
}
}
}
No you can reproduce the graphic using the unswizzled pixels and the color palette right? Yeah... but... kinda no, as color would be incorrect (see the comparison in my previous post), so yeah, time to do the same to the color palette. This is due to the fact that both sections are loaded in graphic memory before being "decompressed" to a full color texture (then the graphic pipeline rasterizes everything and the PSP's screen shows the result)
In general, one does not treat the color palette as another image, so an alternative is to simply rearrange colors on it. Note that only 256 color-palettes are interlaced; 16 color ones are two small and fit in a single memory block (thus no interlacing needed). I use this code to rearrange colors (each color is supposed to be a 4bytes structure containing RGBA values, 8 bits per channel):
Code:
private void sort(Color[] colors)
{
if (colors.Length != 0x100)
return;
int ptr = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Color temp = colors[ptr + 8 + j];
colors[ptr + 8 + j] = colors[ptr + 16 + j];
colors[ptr + 16 + j] = temp;
}
ptr += 32;
}
}
And that's it, now you can recreate the image with both the pixels and the palette deinterlaced, right? RIGHT!.
Keep in mind that when editing you'll have to either:
---Limit the edition to the already existing colors
---Convert the image to full color and then quantize back to 256 / 16 colors (depending on the original color count), always keeping the alpha channel (there are a lot of programs that have problems quantizing alpha channels, it's just a matter of choosing the right ones).
Then, when reinserting everything, you'll notice that there is a step where we'll have to re-compress the data, but we have no compression algorithm, reverting the decompression one would be much of a pain and the game does not contain an IMY compression algorithm (it only needs to decompress them).
However, if you get the idea behind the compression scheme, you'll notice that there are some uncompressed blocks. We can simply put the whole edited file in uncompressed blocks, the resulting file will be bigger (since it has decompressed data plus some block descriptors), but it should work in-game just fine. This is known as Fake-Compression ^^"
But that's... another story ^^
~Sky