OpenKH / OpenKh

Kingdom Hearts libraries, tools, game engine and documentation
https://openkh.dev
Apache License 2.0
293 stars 83 forks source link

OpenKh.Tools.ImageViewer Improvements #78

Closed Vladabdf closed 4 years ago

Vladabdf commented 4 years ago

Given a recent discovery by Topaz and I that KH2 does in fact support custom color palette sizes, it's important to note that two things lead to problems when using these custom IMD files in the viewer:

  1. The viewer does not read the size directly from the header, expecting a palette size of 16, 256, or 16,777,215, causing the viewer to crash. This happens only when a palette size is between but not equal to the aforementioned values.
  2. For blank pixels, PNGQuant is setting the RGBA values to 47 70 4C 00. Crazycatz' editor changes the format due to using nQuant instead. If OpenKH is changing the expected image format to match Crazycatz' algorithm, it might be responsible for the attached image looking how it does.

Edit: The second point has been discovered to be wrong, but Crazycatz' generation is still incorrect and should not be used as a basis. KH2 does accept images with less than or equal to 128 colors (perhaps 256 too) without Red and Blue channel obfuscation.

Attached is also an archive with three IMD files and two PNG images with their limited color palettes.

image

Custom IMDs + Images.zip - Download

kenjiuno commented 4 years ago

crashes the viewer.imd should be fine.

2020-02-25_23h53_25

ImageViewer will be able to open it with slight changes...

 OpenKh.Kh2/Imgd.cs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/OpenKh.Kh2/Imgd.cs b/OpenKh.Kh2/Imgd.cs
index f13d60b..e1f27de 100644
--- a/OpenKh.Kh2/Imgd.cs
+++ b/OpenKh.Kh2/Imgd.cs
@@ -153,14 +153,18 @@ namespace OpenKh.Kh2

         private byte[] GetClut8()
         {
+            var maxClutIndex = Clut.Length / 4;
             var data = new byte[256 * 4];
             for (var i = 0; i < 256; i++)
             {
                 var srcIndex = Ps2.Repl(i);
-                data[i * 4 + 0] = Clut[srcIndex * 4 + 0];
-                data[i * 4 + 1] = Clut[srcIndex * 4 + 1];
-                data[i * 4 + 2] = Clut[srcIndex * 4 + 2];
-                data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[srcIndex * 4 + 3]);
+                if (srcIndex < maxClutIndex)
+                {
+                    data[i * 4 + 0] = Clut[srcIndex * 4 + 0];
+                    data[i * 4 + 1] = Clut[srcIndex * 4 + 1];
+                    data[i * 4 + 2] = Clut[srcIndex * 4 + 2];
+                    data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[srcIndex * 4 + 3]);
+                }
             }

             return data;
Xeeynamo commented 4 years ago

@kenjiuno I was into this issue too. So far I solved it in a similar way you did. You can see my commit here: https://github.com/Xeeynamo/OpenKh/commit/ca655ecf5e24d97541effd2c7680ef2281d5bac7

Still there is the problem of the texture with the wrong palette. I honestly have no idea how to fix it at the moment :/

kenjiuno commented 4 years ago

@kenjiuno I was into this issue too. So far I solved it in a similar way you did. You can see my commit here: ca655ec

Thanks for checking about it! I'll check it later

Still there is the problem of the texture with the wrong palette. I honestly have no idea how to fix it at the moment :/

I have tested these 3 IMD files upon my pcsx2. By injecting each IMD into P_EX100.a.fm.

crashes the viewer.imd

crashes the viewer

face 6-bit 48 colors.imd

face 6-bit 48 colors

face 8-bit 256 colors.imd

face 8-bit 256 colors

I'm just interested in how face 6-bit 48 colors.imd and face 8-bit 256 colors.imd are generated.

Vladabdf commented 4 years ago

The game either doesn't run a check at all or only checks if the color palette size is >= 16. (Not sure which but both are possible since the game only chooses to not accept images if their color count is < 16.) As a result, if the target image's color count is only 128 instead of 256, 128 4= 512 bytes for the palette size instead of the usual 1024. In short, the formula being used to generate these IMDs is as simple as _(target color count) 4 = (palette size)_

Edit: The face 8-bit 256 colors.imd in the archive I provided has an incorrectly generated colore palette, hence the messed up colors even in the game. It's an issue with the generator Topaz created, but the game still accepts it as it follows IMD specifications. It should never crash the game. I'm also not sure why GSDx is throwing those errors in your screenshots. I did not receive them upon testing countless of these custom IMDs.

Rikux3 commented 4 years ago

@Vladabdf The error message in the second and third image are only thrown if you use pcsx2 with a debugger or from within visual studio.

Xeeynamo commented 4 years ago

Fixed the crash on #93

Rikux3 commented 4 years ago

crashes the viewer.imd works now.