Resident Evil 4 PS2 swizzled textures

Textures, recreate headers, conversions, algorithms and parsing of image files
HardRain
Posts: 4
Joined: Mon Aug 23, 2021 3:08 pm

Resident Evil 4 PS2 swizzled textures

Post by HardRain »

Hi everyone, I am creating a simple tool for rendering textures of Resident Evil 4 game, from PS2 version.
However, there are some swizzled textures which I can't understand in which order the pixels are being read, they appear like this:
Image

And here are the main header bytes (just for faster understanding):
Image

I also have this texture unswizzled, just in case someone wants to compare.
All unswizzled textures pixels points to a color in the palette.
I just need an algorithm to render them correctly, if someone can help me, I will be very grateful.

BGR (no swizzle):
https://drive.google.com/file/d/1VuEoPU ... share_link
PS2 swizzled:
https://drive.google.com/file/d/1VWrUVY ... share_link
h3x3r
Posts: 165
Joined: Wed Jun 01, 2016 5:53 pm

Re: Resident Evil 4 PS2 swizzled textures

Post by h3x3r »

Well my try. Need more samples to make it clear.

Code: Select all

uint texMagic;
uint texNum;
uint texPalColors;
uint null;
ushort texWidth;
ushort texHeight;
ushort texFlag0;
ushort texFlag1;
uint texPaletteSize;
uint texPaletteTotalSize;
uint texDummy[4];
uint texMainLayerOffset;
uint texPaletteOffset;
uint texFileId; //Not sure
ushort texMips; //Not sure
ushort texMainLayerSize;
And here's Noesis script. Sorry I can't provide anything about untwiddle or how palette are applied. Everything is processed by Noesis api code.

Code: Select all

from inc_noesis import *
import noesis
import rapi
import os

def registerNoesisTypes():
   handle = noesis.register("RE4 - Texture", ".tpl")
   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() != 0x00001000:
      return 0
   return 1
   
def noepyLoadRGBA(data, texList):
    bs = NoeBitStream(data)
    texBaseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
    texMagic = bs.readUInt()
    texNum = bs.readUInt()
    texPalColors = bs.readUInt()
    bs.readBytes(4)
    texWidth = bs.readUShort()
    texHeight = bs.readUShort()
    texFlag0 = bs.readUShort()
    texFlag1 = bs.readUShort()
    texPalSize = bs.readUInt() * texPalColors
    texTotalPalSize = bs.readUInt()
    bs.readBytes(16)
    texMainLayerOffset = bs.readUInt()
    texPalOffset = bs.readUInt()
    texFileId = bs.readUInt()
    texMips = bs.readUShort()
    texMainLayerSize = bs.readUShort()
    
    bs.seek(texPalOffset, NOESEEK_ABS)
    texPalette = bs.readBytes(texPalSize)
    bs.texPalette = texPalette
        
    bs.seek(texMainLayerOffset, NOESEEK_ABS)        
    data = bs.readBytes(texMainLayerSize)
    if texFlag1 == 0:
        data = rapi.imageDecodeRawPal(data, bs.texPalette, texWidth, texHeight, 8, "r8 g8 b8 a8")
        texFmt = noesis.NOESISTEX_RGBA32
    elif texFlag1 == 2:
        data = rapi.imageUntwiddlePS2(data, texWidth, texHeight, 8)
        data = rapi.imageDecodeRawPal(data, bs.texPalette, texWidth, texHeight, 8, "r8 g8 b8 a8", noesis.DECODEFLAG_PS2SHIFT)
        texFmt = noesis.NOESISTEX_RGBA32
    texList.append(NoeTexture(rapi.getInputName(), texWidth, texHeight, data, texFmt))
    return 1
Result:
RGB
Image
PS2 with noesis.DECODEFLAG_PS2SHIFT
Image

At PS2 i added noesis.DECODEFLAG_PS2SHIFT just to see how it will be different. You can remove that code.
HardRain
Posts: 4
Joined: Mon Aug 23, 2021 3:08 pm

Re: Resident Evil 4 PS2 swizzled textures

Post by HardRain »

Ooh too bad we can't see what happens underneath then :(
I needed that because my tool is being made using JavaScript, so I would just adapt the code, but that's okay.
Thank you for the tip with python!