Engineer h3x3r Posted March 5, 2024 Engineer Share Posted March 5, 2024 Hello there! Can somebody please help update my noesis script to support this format? SCE_GS_PSMT8 = 19, // 8-bit indexed, packing 4 pixels per 32-bit. So far I came across 4 formats and this one is something... Don't know how to process it in noesis. Here is 010 Template from Nenkai Spoiler //------------------------------------------------ //--- 010 Editor v10.0.2 Binary Template // // File: PGLUTexSet // Authors: Nenkai#9075 // Version: // Purpose: Texture Set for PS2 PDI Games // Category: Game Sprites // File Mask: // ID Bytes: // History: //------------------------------------------------ BitfieldDisablePadding(); string PrintBufferSize(int64 val) { string s; SPrintf(s, "Same as tbp/cbp, gets remapped at runtime - offset: 0x%x (0x%x * 64)", val * 64, val); return s; } typedef enum <byte> { SCE_GS_NEAREST = 0, SCE_GS_LINEAR = 1, SCE_GS_NEAREST_MIPMAP_NEAREST = 2, SCE_GS_NEAREST_MIPMAP_LINEAR = 3, SCE_GS_LINEAR_MIPMAP_NEAREST = 4, SCE_GS_LINEAR_MIPMAP_LINEAR = 5, } SCE_GS_MAG; typedef enum <byte> { SCE_GS_PSMCT32 = 0, // RGBA32, uses 32-bit per pixel. SCE_GS_PSMCT24 = 1, // RGB24, uses 24-bit per pixel with the upper 8 bit unused. SCE_GS_PSMCT16 = 2, // RGBA16 unsigned, pack two pixels in 32-bit in little endian order. SCE_GS_PSMCT16S = 10, // RGBA16 signed, pack two pixels in 32-bit in little endian order. SCE_GS_PSMT8 = 19, // 8-bit indexed, packing 4 pixels per 32-bit. SCE_GS_PSMT4 = 20, // 4-bit indexed, packing 8 pixels per 32-bit. SCE_GS_PSMT8H = 27, // 8-bit indexed, but the upper 24-bit are unused. SCE_GS_PSMT4HL = 36, // 4-bit indexed, but the upper 24-bit are unused. SCE_GS_PSMT4HH = 44, SCE_GS_PSMZ32 = 48, // 32-bit Z buffer SCE_GS_PSMZ24 = 49, // 24-bit Z buffer with the upper 8-bit unused SCE_GS_PSMZ16 = 50, // 16-bit unsigned Z buffer, pack two pixels in 32-bit in little endian order. SCE_GS_PSMZ16S = 58, // 16-bit signed Z buffer, pack two pixels in 32-bit in little endian order. } SCE_GS_PSM; typedef enum <byte> { SCE_GS_REPEAT = 0, SCE_GS_CLAMP = 1, SCE_GS_REGION_CLAMP = 2, SCE_GS_REGION_REPEAT = 3, } SCE_GS_CLAMP_PARAMS; typedef enum <byte> { CSM1, CSM2 } SCE_GS_CSM; typedef struct { struct { int64 TBP0_TextureBasePointer : 14 <format=hex, comment="address / 64 (words aka 4) - this is the block offset to the texture">; int64 TBW_TextureBufferWidth : 6 <format=hex, comment="Texel Unit Width / 64 (words aka 4)">; SCE_GS_PSM PSM_TexturePixelStorageFormat : 6 <comment="Texture pixel storage format">; int64 TW_TextureWidth : 4 <comment="Texture width - Actual size will be 2^w and 2^h">; int64 TH_TextureHeight : 4 <comment="Texture height - Actual size will be 2^w and 2^h">; int64 TCC_TextureColorComponent : 1 <comment="Texture color component, 0 = RGB, 1 = RGBA">; int64 TFX_TextureFunction : 2 <comment="Texture function">; int64 CBP_CLUTBufferBasePointer : 14 <format=hex, comment="Base address of CLUT data (actual address will be cbp x 64)">; SCE_GS_PSM CPSM_ClutPixelStorageFormat : 4 <comment="Format in which CLUT entries are saved">; SCE_GS_CSM CSM_ClutStorageMode : 1 <comment="CLUT storage mode">; int64 CSA_ClutEntryOffset : 5 <comment="CLUT entry offset - CSA = Offset / 16, In CSM2, CSA must be 0">; // 0 = Temporary buffer contents not changed // 1 = Load performed to CSA position of buffer // 2 = Load is performed to CSA position of buffer and CBP is copied to CBP0. (*2) // 3 = Load is performed to CSA position of buffer and CBP is copied to CBP1. (*2) // 4 = If CBP0 != CBP, load is performed and CBP is copied to CBP0. (*2) // 5 = If CBP1 != CBP, load is performed and CBP is copied to CBP1. (*2) int64 CLD_ClutBufferLoadControl : 3 <comment="Check template comment">; } sceGsTex0; struct { int64 LCM_LODCalculationMethod : 1 <comment="0 = (LOD = (log2(1/|Q|)<<L+K), 1 = Fixed value (LOD = K)">; int64 pad01 : 1; int64 MXL_MaximumMIPLevel : 3 <comment="0-6">; SCE_GS_MAG MMAG : 1 <comment="Filter when Texture is Expanded (LOD < 0) - Max LINEAR">; SCE_GS_MAG MMIN : 3 <comment="Filter when Texture is Reduced (LOD >= 0)">; // 0 = Value specified by MIPTBP1 and MIPTBP2 is used // 1 = Base address of TBP1 - TBP3 is automatically set int64 MTBA_unknown : 1 <comment="Base Address specification of Mipmap Texture of Level 1 or more">; int64 pad10 : 9; int64 L : 2 <comment="LOD Parameter Value L">; int64 pad21 : 11; int64 K : 12 <comment="LOD Parameter Value K">; int64 pad44 :20; } sceGsTex1; struct sceGsMiptbp1 { unsigned long TBP1:14; unsigned long TBW1:6; unsigned long TBP2:14; unsigned long TBW2:6; unsigned long TBP3:14; unsigned long TBW3:6; unsigned long pad60:4; } MipTable1; struct sceGsMiptbp2 { unsigned long TBP4:14; unsigned long TBW4:6; unsigned long TBP5:14; unsigned long TBW5:6; unsigned long TBP6:14; unsigned long TBW6:6; unsigned long pad60:4; } MipTable2; struct { SCE_GS_CLAMP_PARAMS WMS_WrapModeS:2 <comment="Wrap Mode in Horizontal (S) Direction">; SCE_GS_CLAMP_PARAMS WMT_VrapModeT:2 <comment="Wrap Mode in Horizontal (T) Direction">; unsigned long MINU:10 <comment="Clamp U Direction - Lower Limit">; unsigned long MAXU:10 <comment="Clamp U Direction - Upper Limit">; unsigned long MINV:10 <comment="Clamp Y Direction - Lower Limit">; unsigned long MAXV:10 <comment="Clamp Y Direction - Upper Limit">; Printf("%dx%d (%s, %s)\n", MAXU+1, MAXV+1, EnumToString(WMS_WrapModeS), EnumToString(WMT_VrapModeT)); unsigned long pad44:20; } sceGsClamp <optimize=false>; } PGLUTexture <optimize=false>; typedef struct { int FileDataOffset <format=hex, fgcolor=cRed>; struct { short BlockOffset <format=hex, comment=PrintBufferSize>; byte BufferWidth <comment="Same as TBW">; SCE_GS_PSM PixelFormat; } Params; short Width; short Height; } TransferInfo <optimize=false, comment="Declares a buffer for textures or palettes to use">; // GS's Users Manual - Page 161 to 170 are useful for understanding blocks and pages typedef struct TextureSet1 { local int BasePos = FTell(); struct { char Magic[4]; int RelocPtr; int unkptr; int FileSize <format=hex>; short BaseTBPOffset <comment="Remapped at runtime, multiplied by 64 for absolute">; short TotalBlockSize <format=hex, comment="Total blocks taken by all textures">; short PGLUTextureCount <fgcolor=cGreen>; short TransferCount <fgcolor=cGreen>; int PGLUTextureMapOffset <format=hex, fgcolor=cRed>; int TransferInfosOffset <format=hex, fgcolor=cRed>; int ClutPatchesOffset <format=hex, fgcolor=cRed, comment="Used for cars">; int clutAnimationOffset <format=hex, fgcolor=cRed>; // TODO - havent seen any texture that uses that yet int unkOffset4 <format=hex, fgcolor=cRed>; } Header <size=0x30 , bgcolor=cPurple>; FSeek(BasePos + Header.PGLUTextureMapOffset); PGLUTexture Textures[Header.PGLUTextureCount]; FSeek(BasePos + Header.TransferInfosOffset); TransferInfo Transfers[Header.TransferCount]; if (Header.ClutPatchesOffset != 0) { FSeek(BasePos + Header.ClutPatchesOffset); struct { int ClutPatchCount; int ClutPatchOffsets[ClutPatchCount] <format=hex>; local int i = 0; for (i = 0; i < ClutPatchCount; i++) { FSeek(BasePos + ClutPatchOffsets); struct { int NumPGLUTexturesToPatch; struct { int CSA_ClutEntryOffset : 5; int CBP_CLUTBufferBasePointer : 14 <format=hex>; SCE_GS_PSM Format : 4; int PGLUTextureIndex : 9; } PGLUTex0TexturePatch[NumPGLUTexturesToPatch] <optimize=false>; } ClutPatch; } } ClutPatches; } }; local int LastTexSetOffset; typedef struct Images { char Magic[4]; int RelocPtr; int TextureCount; int TextureDataOffset; LastTexSetOffset = TextureDataOffset; struct { char Name[0x3C]; int TexSetIndex; local int texSetSize = ReadInt(LastTexSetOffset + 0x0C); local int lastPos = FTell(); FSeek(LastTexSetOffset); TextureSet1 TexSet; LastTexSetOffset += texSetSize; FSeek(lastPos); } TextureName[TextureCount] <optimize=false>; }; // GT3 'imgs' if (ReadInt(0x00) == 0x53474D49) Images imgs; else if (ReadInt(0x00) == 0x31786554) TextureSet1 tex1; And here is my noesis script... Thanks in advance! from inc_noesis import * import noesis import rapi import os def registerNoesisTypes(): handle = noesis.register("Gran Turismo 4 - Texture", ".img") noesis.setHandlerTypeCheck(handle, noepyCheckType) noesis.setHandlerLoadRGBA(handle, noepyLoadRGBA) noesis.logPopup() return 1 def noepyCheckType(data): bs = NoeBitStream(data) if len(data) < 20: return 0 if bs.readUInt() != 0x31786554: return 0 return 1 def noepyLoadRGBA(data, texList): bs = NoeBitStream(data) baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName())) print(baseName) Magic = bs.readUInt() bs.readBytes(8) FileSize = bs.readUInt() bs.readBytes(2) TotalBlockSize = bs.readUShort() PGLUTextureCount = bs.readUShort() TransferCount = bs.readUShort() PGLUTextureMapOffset = bs.readUInt() TransferInfosOffset = bs.readUInt() ClutPatchesOffset = bs.readUInt() ClutAnimationOffset = bs.readUInt() UnknownOffset = bs.readUInt() bs.readBytes(4) # End of Header # Texture Table for i in range(PGLUTextureCount): bs.readBytes(40) # Transfer Table bs.seek(TransferInfosOffset, NOESEEK_ABS) if TransferCount == 1: TexDataOffset = bs.readUInt() BlockOffset = bs.readUShort() BufferWidth = bs.readUByte() PixelFormat = bs.readUByte() TexWidth = bs.readUShort() TexHeight = bs.readUShort() else: TexDataOffset = bs.readUInt() BlockOffset = bs.readUShort() BufferWidth = bs.readUByte() PixelFormat = bs.readUByte() TexWidth = bs.readUShort() TexHeight = bs.readUShort() PalDataOffset = bs.readUInt() PalBlockOffset = bs.readUShort() PalBufferWidth = bs.readUByte() PalPixelFormat = bs.readUByte() PalTexWidth = bs.readUShort() PalTexHeight = bs.readUShort() if PixelFormat == 20: bs.seek(PalDataOffset, NOESEEK_ABS) Palette = bs.readBytes(64) elif PixelFormat == 19: bs.seek(PalDataOffset, NOESEEK_ABS) Palette = bs.readBytes(1024) if TransferCount == 2: TexSize = PalDataOffset - TexDataOffset else: TexSize = FileSize - TexDataOffset bs.seek(TexDataOffset, NOESEEK_ABS) data = bs.readBytes(TexSize) if PixelFormat == 20: data = rapi.imageDecodeRawPal(data, Palette, TexWidth, TexHeight, 4, "r8 g8 b8 a8") texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 19: data = rapi.imageDecodeRawPal(data, Palette, TexWidth, TexHeight, 8, "r8 g8 b8 a8") # I have no idea how to process texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 0: texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 1: texFmt = noesis.NOESISTEX_RGB24 texList.append(NoeTexture(rapi.getInputName(), TexWidth, TexHeight, data, texFmt)) return 1 gt4img.7z Link to comment Share on other sites More sharing options...
Solution DKDave Posted March 5, 2024 Solution Share Posted March 5, 2024 1 hour ago, h3x3r said: Hello there! Can somebody please help update my noesis script to support this format? SCE_GS_PSMT8 = 19, // 8-bit indexed, packing 4 pixels per 32-bit. So far I came across 4 formats and this one is something... Don't know how to process it in noesis. Here is 010 Template from Nenkai Reveal hidden contents //------------------------------------------------ //--- 010 Editor v10.0.2 Binary Template // // File: PGLUTexSet // Authors: Nenkai#9075 // Version: // Purpose: Texture Set for PS2 PDI Games // Category: Game Sprites // File Mask: // ID Bytes: // History: //------------------------------------------------ BitfieldDisablePadding(); string PrintBufferSize(int64 val) { string s; SPrintf(s, "Same as tbp/cbp, gets remapped at runtime - offset: 0x%x (0x%x * 64)", val * 64, val); return s; } typedef enum <byte> { SCE_GS_NEAREST = 0, SCE_GS_LINEAR = 1, SCE_GS_NEAREST_MIPMAP_NEAREST = 2, SCE_GS_NEAREST_MIPMAP_LINEAR = 3, SCE_GS_LINEAR_MIPMAP_NEAREST = 4, SCE_GS_LINEAR_MIPMAP_LINEAR = 5, } SCE_GS_MAG; typedef enum <byte> { SCE_GS_PSMCT32 = 0, // RGBA32, uses 32-bit per pixel. SCE_GS_PSMCT24 = 1, // RGB24, uses 24-bit per pixel with the upper 8 bit unused. SCE_GS_PSMCT16 = 2, // RGBA16 unsigned, pack two pixels in 32-bit in little endian order. SCE_GS_PSMCT16S = 10, // RGBA16 signed, pack two pixels in 32-bit in little endian order. SCE_GS_PSMT8 = 19, // 8-bit indexed, packing 4 pixels per 32-bit. SCE_GS_PSMT4 = 20, // 4-bit indexed, packing 8 pixels per 32-bit. SCE_GS_PSMT8H = 27, // 8-bit indexed, but the upper 24-bit are unused. SCE_GS_PSMT4HL = 36, // 4-bit indexed, but the upper 24-bit are unused. SCE_GS_PSMT4HH = 44, SCE_GS_PSMZ32 = 48, // 32-bit Z buffer SCE_GS_PSMZ24 = 49, // 24-bit Z buffer with the upper 8-bit unused SCE_GS_PSMZ16 = 50, // 16-bit unsigned Z buffer, pack two pixels in 32-bit in little endian order. SCE_GS_PSMZ16S = 58, // 16-bit signed Z buffer, pack two pixels in 32-bit in little endian order. } SCE_GS_PSM; typedef enum <byte> { SCE_GS_REPEAT = 0, SCE_GS_CLAMP = 1, SCE_GS_REGION_CLAMP = 2, SCE_GS_REGION_REPEAT = 3, } SCE_GS_CLAMP_PARAMS; typedef enum <byte> { CSM1, CSM2 } SCE_GS_CSM; typedef struct { struct { int64 TBP0_TextureBasePointer : 14 <format=hex, comment="address / 64 (words aka 4) - this is the block offset to the texture">; int64 TBW_TextureBufferWidth : 6 <format=hex, comment="Texel Unit Width / 64 (words aka 4)">; SCE_GS_PSM PSM_TexturePixelStorageFormat : 6 <comment="Texture pixel storage format">; int64 TW_TextureWidth : 4 <comment="Texture width - Actual size will be 2^w and 2^h">; int64 TH_TextureHeight : 4 <comment="Texture height - Actual size will be 2^w and 2^h">; int64 TCC_TextureColorComponent : 1 <comment="Texture color component, 0 = RGB, 1 = RGBA">; int64 TFX_TextureFunction : 2 <comment="Texture function">; int64 CBP_CLUTBufferBasePointer : 14 <format=hex, comment="Base address of CLUT data (actual address will be cbp x 64)">; SCE_GS_PSM CPSM_ClutPixelStorageFormat : 4 <comment="Format in which CLUT entries are saved">; SCE_GS_CSM CSM_ClutStorageMode : 1 <comment="CLUT storage mode">; int64 CSA_ClutEntryOffset : 5 <comment="CLUT entry offset - CSA = Offset / 16, In CSM2, CSA must be 0">; // 0 = Temporary buffer contents not changed // 1 = Load performed to CSA position of buffer // 2 = Load is performed to CSA position of buffer and CBP is copied to CBP0. (*2) // 3 = Load is performed to CSA position of buffer and CBP is copied to CBP1. (*2) // 4 = If CBP0 != CBP, load is performed and CBP is copied to CBP0. (*2) // 5 = If CBP1 != CBP, load is performed and CBP is copied to CBP1. (*2) int64 CLD_ClutBufferLoadControl : 3 <comment="Check template comment">; } sceGsTex0; struct { int64 LCM_LODCalculationMethod : 1 <comment="0 = (LOD = (log2(1/|Q|)<<L+K), 1 = Fixed value (LOD = K)">; int64 pad01 : 1; int64 MXL_MaximumMIPLevel : 3 <comment="0-6">; SCE_GS_MAG MMAG : 1 <comment="Filter when Texture is Expanded (LOD < 0) - Max LINEAR">; SCE_GS_MAG MMIN : 3 <comment="Filter when Texture is Reduced (LOD >= 0)">; // 0 = Value specified by MIPTBP1 and MIPTBP2 is used // 1 = Base address of TBP1 - TBP3 is automatically set int64 MTBA_unknown : 1 <comment="Base Address specification of Mipmap Texture of Level 1 or more">; int64 pad10 : 9; int64 L : 2 <comment="LOD Parameter Value L">; int64 pad21 : 11; int64 K : 12 <comment="LOD Parameter Value K">; int64 pad44 :20; } sceGsTex1; struct sceGsMiptbp1 { unsigned long TBP1:14; unsigned long TBW1:6; unsigned long TBP2:14; unsigned long TBW2:6; unsigned long TBP3:14; unsigned long TBW3:6; unsigned long pad60:4; } MipTable1; struct sceGsMiptbp2 { unsigned long TBP4:14; unsigned long TBW4:6; unsigned long TBP5:14; unsigned long TBW5:6; unsigned long TBP6:14; unsigned long TBW6:6; unsigned long pad60:4; } MipTable2; struct { SCE_GS_CLAMP_PARAMS WMS_WrapModeS:2 <comment="Wrap Mode in Horizontal (S) Direction">; SCE_GS_CLAMP_PARAMS WMT_VrapModeT:2 <comment="Wrap Mode in Horizontal (T) Direction">; unsigned long MINU:10 <comment="Clamp U Direction - Lower Limit">; unsigned long MAXU:10 <comment="Clamp U Direction - Upper Limit">; unsigned long MINV:10 <comment="Clamp Y Direction - Lower Limit">; unsigned long MAXV:10 <comment="Clamp Y Direction - Upper Limit">; Printf("%dx%d (%s, %s)\n", MAXU+1, MAXV+1, EnumToString(WMS_WrapModeS), EnumToString(WMT_VrapModeT)); unsigned long pad44:20; } sceGsClamp <optimize=false>; } PGLUTexture <optimize=false>; typedef struct { int FileDataOffset <format=hex, fgcolor=cRed>; struct { short BlockOffset <format=hex, comment=PrintBufferSize>; byte BufferWidth <comment="Same as TBW">; SCE_GS_PSM PixelFormat; } Params; short Width; short Height; } TransferInfo <optimize=false, comment="Declares a buffer for textures or palettes to use">; // GS's Users Manual - Page 161 to 170 are useful for understanding blocks and pages typedef struct TextureSet1 { local int BasePos = FTell(); struct { char Magic[4]; int RelocPtr; int unkptr; int FileSize <format=hex>; short BaseTBPOffset <comment="Remapped at runtime, multiplied by 64 for absolute">; short TotalBlockSize <format=hex, comment="Total blocks taken by all textures">; short PGLUTextureCount <fgcolor=cGreen>; short TransferCount <fgcolor=cGreen>; int PGLUTextureMapOffset <format=hex, fgcolor=cRed>; int TransferInfosOffset <format=hex, fgcolor=cRed>; int ClutPatchesOffset <format=hex, fgcolor=cRed, comment="Used for cars">; int clutAnimationOffset <format=hex, fgcolor=cRed>; // TODO - havent seen any texture that uses that yet int unkOffset4 <format=hex, fgcolor=cRed>; } Header <size=0x30 , bgcolor=cPurple>; FSeek(BasePos + Header.PGLUTextureMapOffset); PGLUTexture Textures[Header.PGLUTextureCount]; FSeek(BasePos + Header.TransferInfosOffset); TransferInfo Transfers[Header.TransferCount]; if (Header.ClutPatchesOffset != 0) { FSeek(BasePos + Header.ClutPatchesOffset); struct { int ClutPatchCount; int ClutPatchOffsets[ClutPatchCount] <format=hex>; local int i = 0; for (i = 0; i < ClutPatchCount; i++) { FSeek(BasePos + ClutPatchOffsets); struct { int NumPGLUTexturesToPatch; struct { int CSA_ClutEntryOffset : 5; int CBP_CLUTBufferBasePointer : 14 <format=hex>; SCE_GS_PSM Format : 4; int PGLUTextureIndex : 9; } PGLUTex0TexturePatch[NumPGLUTexturesToPatch] <optimize=false>; } ClutPatch; } } ClutPatches; } }; local int LastTexSetOffset; typedef struct Images { char Magic[4]; int RelocPtr; int TextureCount; int TextureDataOffset; LastTexSetOffset = TextureDataOffset; struct { char Name[0x3C]; int TexSetIndex; local int texSetSize = ReadInt(LastTexSetOffset + 0x0C); local int lastPos = FTell(); FSeek(LastTexSetOffset); TextureSet1 TexSet; LastTexSetOffset += texSetSize; FSeek(lastPos); } TextureName[TextureCount] <optimize=false>; }; // GT3 'imgs' if (ReadInt(0x00) == 0x53474D49) Images imgs; else if (ReadInt(0x00) == 0x31786554) TextureSet1 tex1; And here is my noesis script... Thanks in advance! from inc_noesis import * import noesis import rapi import os def registerNoesisTypes(): handle = noesis.register("Gran Turismo 4 - Texture", ".img") noesis.setHandlerTypeCheck(handle, noepyCheckType) noesis.setHandlerLoadRGBA(handle, noepyLoadRGBA) noesis.logPopup() return 1 def noepyCheckType(data): bs = NoeBitStream(data) if len(data) < 20: return 0 if bs.readUInt() != 0x31786554: return 0 return 1 def noepyLoadRGBA(data, texList): bs = NoeBitStream(data) baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName())) print(baseName) Magic = bs.readUInt() bs.readBytes(8) FileSize = bs.readUInt() bs.readBytes(2) TotalBlockSize = bs.readUShort() PGLUTextureCount = bs.readUShort() TransferCount = bs.readUShort() PGLUTextureMapOffset = bs.readUInt() TransferInfosOffset = bs.readUInt() ClutPatchesOffset = bs.readUInt() ClutAnimationOffset = bs.readUInt() UnknownOffset = bs.readUInt() bs.readBytes(4) # End of Header # Texture Table for i in range(PGLUTextureCount): bs.readBytes(40) # Transfer Table bs.seek(TransferInfosOffset, NOESEEK_ABS) if TransferCount == 1: TexDataOffset = bs.readUInt() BlockOffset = bs.readUShort() BufferWidth = bs.readUByte() PixelFormat = bs.readUByte() TexWidth = bs.readUShort() TexHeight = bs.readUShort() else: TexDataOffset = bs.readUInt() BlockOffset = bs.readUShort() BufferWidth = bs.readUByte() PixelFormat = bs.readUByte() TexWidth = bs.readUShort() TexHeight = bs.readUShort() PalDataOffset = bs.readUInt() PalBlockOffset = bs.readUShort() PalBufferWidth = bs.readUByte() PalPixelFormat = bs.readUByte() PalTexWidth = bs.readUShort() PalTexHeight = bs.readUShort() if PixelFormat == 20: bs.seek(PalDataOffset, NOESEEK_ABS) Palette = bs.readBytes(64) elif PixelFormat == 19: bs.seek(PalDataOffset, NOESEEK_ABS) Palette = bs.readBytes(1024) if TransferCount == 2: TexSize = PalDataOffset - TexDataOffset else: TexSize = FileSize - TexDataOffset bs.seek(TexDataOffset, NOESEEK_ABS) data = bs.readBytes(TexSize) if PixelFormat == 20: data = rapi.imageDecodeRawPal(data, Palette, TexWidth, TexHeight, 4, "r8 g8 b8 a8") texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 19: data = rapi.imageDecodeRawPal(data, Palette, TexWidth, TexHeight, 8, "r8 g8 b8 a8") # I have no idea how to process texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 0: texFmt = noesis.NOESISTEX_RGBA32 elif PixelFormat == 1: texFmt = noesis.NOESISTEX_RGB24 texList.append(NoeTexture(rapi.getInputName(), TexWidth, TexHeight, data, texFmt)) return 1 gt4img.7z 51.28 kB · 2 downloads If you change your line in the script to: data = rapi.imageDecodeRawPal(data, Palette, TexWidth, TexHeight, 8, "r8 g8 b8 a8", noesis.DECODEFLAG_PS2SHIFT) Seems to look correct with that flag enabled. 1 1 Link to comment Share on other sites More sharing options...
Engineer h3x3r Posted March 5, 2024 Author Engineer Share Posted March 5, 2024 Woaw thank you so much DKDave! Link to comment Share on other sites More sharing options...
Engineer h3x3r Posted March 25, 2024 Author Engineer Share Posted March 25, 2024 Well seems like i can't get over these. It looks like they are stored as blocks. I noticed that file 0x0005da40.img is constructed from 2 images leads to single one. Also can't believe it that file 0x0002cb40.img store over 70+ textures. But maybe yes since they are all low res. Use template to show more info. If anyone know a way please post a solution. Noesis script would be perfect but anything else also. Thanks in advance! gt4_tex.7z Link to comment Share on other sites More sharing options...
Engineer Nenkai Posted April 19, 2024 Engineer Share Posted April 19, 2024 (edited) Late answer, but I have already gone through PS2 textures myself. They're an extreme pain (multiple ps2 transfers for many textures all arranged for size optimizations, & more). It's not perfect, but code is here. https://github.com/Nenkai/PDTools/tree/master/PDTools.Files/Textures Edited April 19, 2024 by Nenkai Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now