Jump to content

Crimson Skies: High Road to Revenge (*.tga)


Go to solution Solved by h3x3r,

Recommended Posts

Was previously reversed (not completely) on XenTaX many years ago..long lost now.

 

Looking for someone that's capable of figuring out what's done to the .tga files, and how to make them readable again. There's different types as well, which further complicates things.

cin hr dev.7z

Link to comment
Share on other sites

A bit of investigation on my end which I hope helps anyone that might work on this:

devastatorHR.tga appears to work in TextureFinder with an offset of 7 set to DXT1. I believe it's supposed to be 1024x1024. Mipmaps (which aren't needed or wanted) appear but are still swizzled. Offset 3 fixes them but swizzles the main texture.

 

image.thumb.png.45bbf611ceb3d05e00d9c0fc18e4bbf2.png

Link to comment
Share on other sites

> but swizzles the main texture

If TextureFinder by Iceberg can show devastatorHR.tga, then it is not a case of swizzling (at least for that texture), since TextureFinder does not include any swizzling patterns (others do, like Texture Finder by Durik, Raw Texture Cooker, and Kuriimu2). So, this is just a case of finding the right base offset, whereas actual "swizzling" in graphics means either:

a. Channel swizzling - remapping/repeating certain channels. This is often found in pixel shaders (e.g. outputVector.rgba = inputVector.bgra).

b. Memory layout swizzling - a rearrangement of the pixels (like z-curve Morton order or simpler subtiling like 8x8 blocks) to increase memory locality and thus boost rasterization throughput. This is handled directly by the hardware for the shader when sampling textures. It is also called "twiddling" on Dreamcast.

It looks like you are already on the right path to figuring it out anyway, but I can look at the other files tomorrow evening (if nobody else does first or you figure them out first ).

Edited by piken
Link to comment
Share on other sites

010 Template:

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i;

typedef struct {
    uint16 ImgWidth,ImgHeight;
    ubyte MipMap,Unknown_0,Unknown_1;
    uint32 PixelFormat,ImgSize;
}Header;

typedef struct {
    byte ImgRawData[header.ImgSize];
}ImgData;

Header header;
ImgData imgData;

And noesis python script. Not sure about one format tho... b5 g6 r5.

EDiT: Ok now i know. It's PS3 swizzled. So you'll be better to use Raw Texture Cooker.

It covers all provided samples.

from inc_noesis import *
import noesis
import rapi
import os

def registerNoesisTypes():
   handle = noesis.register("Crimson Skies: High Road to Revenge (*.tga)", ".tga")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadRGBA(handle, noepyLoadRGBA)
   noesis.logPopup()
   return 1
        
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 20:
      return 0
   return 1
   
def noepyLoadRGBA(data, texList):
    bs = NoeBitStream(data)
    baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
    print(baseName)
    ImgWidth = bs.readUShort()
    ImgHeight = bs.readUShort()
    MipMap = bs.readUByte()
    bs.readBytes(2)
    PixelFormat = bs.readUInt()
    ImgSize = bs.readUInt()
    
    data = bs.readBytes(ImgSize)
    if PixelFormat == 1:
        texFmt = noesis.NOESISTEX_DXT1
    elif PixelFormat == 3:
        texFmt = noesis.NOESISTEX_DXT3
    elif PixelFormat == 5:
        texFmt = noesis.NOESISTEX_DXT5
    elif PixelFormat == 6:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r0 g0 b0 a8")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 14:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "b5 g6 r5 a0")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 15:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r8 g8 b8 a8")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 16:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r8 g8 b8 a8")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 19:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r0 g0 b0 a8")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 20:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r8 g8 b8 a8")
        data = rapi.imageFromMortonOrder(data, ImgWidth, ImgHeight, 4)
        texFmt = noesis.NOESISTEX_RGBA32
    texList.append(NoeTexture(rapi.getInputName(), ImgWidth, ImgHeight, data, texFmt))
    return 1

 

Edited by h3x3r
  • Like 1
Link to comment
Share on other sites

6 hours ago, h3x3r said:

010 Template:

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i;

typedef struct {
    uint16 ImgWidth,ImgHeight;
    ubyte MipMap,Unknown_0,Unknown_1;
    uint32 PixelFormat,ImgSize;
}Header;

typedef struct {
    byte ImgRawData[header.ImgSize];
}ImgData;

Header header;
ImgData imgData;

And noesis python script. Not sure about one format tho... b5 g6 r5.

EDiT: Ok now i know. It's PS3 swizzled. So you'll be better to use Raw Texture Cooker.

It covers all provided samples.

from inc_noesis import *
import noesis
import rapi
import os

def registerNoesisTypes():
   handle = noesis.register("Crimson Skies: High Road to Revenge (*.tga)", ".tga")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadRGBA(handle, noepyLoadRGBA)
   noesis.logPopup()
   return 1
        
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 20:
      return 0
   return 1
   
def noepyLoadRGBA(data, texList):
    bs = NoeBitStream(data)
    baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
    print(baseName)
    ImgWidth = bs.readUShort()
    ImgHeight = bs.readUShort()
    MipMap = bs.readUByte()
    bs.readBytes(2)
    PixelFormat = bs.readUInt()
    ImgSize = bs.readUInt()
    
    data = bs.readBytes(ImgSize)
    if PixelFormat == 1:
        texFmt = noesis.NOESISTEX_DXT1
    elif PixelFormat == 5:
        texFmt = noesis.NOESISTEX_DXT5
    elif PixelFormat == 6:
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "r0 g0 b0 a8")
        texFmt = noesis.NOESISTEX_RGBA32
    elif PixelFormat == 14: # PS3 Swizzle
        data = rapi.imageDecodeRaw(data, ImgWidth, ImgHeight, "b5 g6 r5 a0")
        texFmt = noesis.NOESISTEX_RGBA32
    texList.append(NoeTexture(rapi.getInputName(), ImgWidth, ImgHeight, data, texFmt))
    return 1

 

Appreciate it a ton!

 

Building on this, I noticed that strobe_green and strobe_yellow.tga do not display correctly with the current script version - but for some reason strobe_red works? It's a lower file size than the rest.

Link to comment
Share on other sites

15 hours ago, notameowcelot said:

Appreciate it a ton!

 

Building on this, I noticed that strobe_green and strobe_yellow.tga do not display correctly with the current script version - but for some reason strobe_red works? It's a lower file size than the rest.

I already said that. These are PS3 swizzled. Noesis doesn't have such a function to un-swizzle unfortunetely.

Link to comment
Share on other sites

13 hours ago, h3x3r said:

I already said that. These are PS3 swizzled. Noesis doesn't have such a function to un-swizzle unfortunetely.

Fair enough.

 

Can you check another tex in that case? Got a few that are straight up not opening - not sure what format they are.

Specifically sh_redsky.dds seems to be broken, probably more. Zipped upt he whole folder's contents as a precaution

sh tutorial.7z

Link to comment
Share on other sites

Posted (edited)

I've rediscovered the official documentation on what I'm assuming is all of the game's texture types, present in the data.zip folder.


 

Quote

 

//
// Textures.dat
//
// Use to specify texture format.
//
// Valid formats:
//
//    [none]  -- don't compress
//    dxt1    -- use dxt1 compression (opaque and one bit alpha)
//    dxt2    -- (don't use -- same as dxt3)
//    dxt3    -- use dxt3 compression (explicit alpha)
//    dxt4    -- (don't use -- same as dxt5)
//    dxt5    -- use dxt5 compression (interpolated alpha)
//
// If a file is specified here without a compression format, then 565 will be used if
// the texture does not have an alpha channel, or 8888 if it does.
//
// If a file is not specified here, then dtx1 will be used if the texture does not have
// an alpha channel, or dxt5 if it does.
//
// Note: Dxt1/dxt5 is now automatically determined if not explicitly specified in this
// file. If the texture has over 90% black or white in alpha channel, then dxt1 is
// used.
//
// Wildcards are supported.
//

//Planes
BanditoPF~n.tga=dxt5
bipe_PF~n.tga=dxt5
Brigand_RedSkulls_PF~n.tga=dxt5
CajunSeaplanePF~n.tga=dxt5
copPlane_PF~n.tga=dxt5
desertfox_PF~n.tga=dxt5
devastator~n.tga=dxt5
DopplegangerPF~n.tga=dxt5
GangsterPF~n.tga=dxt5
PiranhaPF~n.tga=dxt5

pf_bandito_mp_*.tga=dxt5
pf_biplane_mp_*.tga=dxt5
pf_brigand_mp_*.tga=dxt5
pf_copPlane_mp_*.tga=dxt5
pf_desertfox_mp_*.tga=dxt5
pf_devastator_mp_*.tga=dxt5
pf_doppleganger_mp_*.tga=dxt5
pf_gangster_mp_*.tga=dxt5
pf_minigyro_mp_*.tga=dxt5
pf_piranha_mp_*.tga=dxt5
pf_seaplane_mp_*.tga=dxt5

//Sky
all_sh_skyNight.tga=skybox
all_sh_skyNightbase.tga
AZ_Skymorning.tga=skybox
CA_skyStorm.tga=skybox
CH_Sky_Twilight.tga=skybox
CH_Sky_TwilightBase.tga
CH_SkyNight.tga=skybox
CH_SkyNightBase.tga
MP_Redsky.tga=skybox
MP_RedskyBase.tga
mpl_az_skySunnyDay.tga=skybox
mpl_az_skySunnyDayBase.tga
SH_cloud1.tga=dxt5
sh_Redsky.tga=skybox
sh_RedskyBase.tga
SH_Skystorm.tga=skybox
SH_SkystormBase.tga
SH_StormyDay.tga=skybox
SH_StormyDayBase.tga

CH_Sky_Twilight_ui.tga
CH_Moon.tga
CH_MoonGlow.tga

//Terrain
A_SH_Shore2.tga
AZ_dirt_runway.tga=dxt5
AZ_terrain_Boss.tga=dxt5
AZ_terrain_Maria.tga=dxt5
AZ_terrain_Navajo.tga=dxt5
AZ_terrain_Scouting.tga=dxt5
CH_FinalCin.tga
CH_FinalCinBase.tga
mpl_az_terrain.tga=dxt5
SH_ShoreMask1.tga
sh_valcano.tga=dxt5

//Effects
rocketflare.tga
rocketflare_blue.tga
rocketflare_red.tga
strob_red.tga
strobe_blue.tga
strobe_green.tga
strobe_white.tga
strobe_yellow.tga
tracer!0.tga=dxt5
tracer!1.tga=dxt5
tracer!2.tga=dxt5
tracer!3.tga=dxt5
tracer_aagun_flak.tga=dxt5
blast4.tga=dxt5

//HUD
hud_reticule_*.tga

//Signs
CH_sgn_forbidden.tga
CH_sgn_service1.tga
CHn_neonSignsArrow.tga
CHn_neonSigns01.tga
CHn_neonBlue.tga
CHn_neonRed.tga
SH_neonSigns.tga
ch_sgn_riviera.tga

//Miss.
droplets~b.tga
Expedition_Trans.tga=dxt5
SH_Boss_Zep_Logo.tga=dxt5

 

Interestingly, I discovered that .dds files are present, but seemingly not documented in this. Like the TGA files, I cannot open or preview them. Although it's possible they were accidentally created by me when fiddling with attempting to reverse the textures initially..I need to investigate more.

 

I'm starting to wonder if the inability to open these files is a result of the .bin BMS that's being used. I remember that when it was first made, audio could not be played back - which an update fixed. But the other formats remained unpreviewable.

 

If I'm correct, what breaks the .TGAs is the lack of header information right? The wavs in the BMS version I have do have it, but every other format seems to miss it - although this might be dwelling more into archive territory now.

Edited by notameowcelot
Link to comment
Share on other sites

Posted (edited)

I've investigated and confirmed there are indeed .dds files present as well alongside .tga. I'm not sure what formats these are, if they are swizzled or not - I can't figure out anything 100% from initial tests, but they don't appear swizzled.

 

sh_redsky_morning.dds is one I do remember having successfully reversed in past, although it looked different shape-wise than what I've been able to achieve so far, plus what I'm assuming is incorrect reversing, as pixels appear to be shifted into places they shouldn't be. Hard for me to explain..something like dithering?

Screenshot2024-04-06162835.png.dd1546945a55d95d33268cd6790f3186.png

Screenshot2024-04-06162943.png.30f075a408c7bc285e019ef2481b20ad.png

 

 

SH Scouting.7z

Edited by notameowcelot
Link to comment
Share on other sites

Wait.... this game is xbox only?  So why is there PS3 swizzle at all... I bet it will be morton order.

EDiT: Sure it was morton. I updated script in my first post.

Edited by h3x3r
Link to comment
Share on other sites

Posted (edited)
16 minutes ago, h3x3r said:

Wait.... this game is xbox only?  So why is there PS3 swizzle at all... I bet it will be morton order.

That was something I was confused by as well. I don't know much about swizzling at all, so I just assumed that there's common types of swizzling that can still end up being used regardless like the Vita/PS3 type. Honestly, I'm surprised the game has any swizzling at all..at least it's only for the larger textures, it seems. It also doesn't seem to be documented at all in the texture.dat, which could mean it's outdated (especially given there's no documentation on the .dds stuff)

Edited by notameowcelot
Link to comment
Share on other sites

There isn't any swizzling as far as I can see.  The images in sh_redsky_morning are broken up into blocks of 256 x 256 and DXT3 encoding, with some short header between each section.  A couple of examples (no swizzling needed).  Looks like there are 6 of these in that file.  First image data starts at 0x14 after some header info.

 

sh_Redsky_morning1.jpg.93aeb735e5762bd998f96e5a65879055.jpg            sh_Redsky_morning2.jpg.51aad964b3e4152c261f83753a745f56.jpg

 

 

  • Like 1
Link to comment
Share on other sites

Posted (edited)
12 minutes ago, DKDave said:

There isn't any swizzling as far as I can see.  The images in sh_redsky_morning are broken up into blocks of 256 x 256 and DXT3 encoding, with some short header between each section.  A couple of examples (no swizzling needed).  Looks like there are 6 of these in that file.  First image data starts at 0x14 after some header info.

 

sh_Redsky_morning1.jpg.93aeb735e5762bd998f96e5a65879055.jpg            sh_Redsky_morning2.jpg.51aad964b3e4152c261f83753a745f56.jpg

 

 

Oh..wow! Appreciate you figuring this out. What about the strobe_yellow and strobe_green images? Those seem to be swizzled for sure.

It looks like sh_redsky_morning is likely the cubemap for environment reflections in that case, or the skybox. Any chance you can process the full thing and send it over?

Also, can you take a look at the other .dds files, specifically the water ones? I've not been able to reverse those as well, so I'm wondering if those are set up similarly.

Edited by notameowcelot
Link to comment
Share on other sites

Posted (edited)
57 minutes ago, h3x3r said:

I solved them. They used morton order.

appreciate it! noticed colors aren't correct on the morton order stuff though it looks like, specifically sh_Redsky is the only one maybe that does it?

image.thumb.png.51b2b55304fea65aca9007aa86619fe7.png

Edited by notameowcelot
Link to comment
Share on other sites

Posted (edited)
7 minutes ago, notameowcelot said:

appreciate it! noticed colors aren't correct on the morton order stuff though it looks like, specifically sh_Redsky is the only one maybe that does it?

 

this I fixed by changing pixel format 16 to b8 g8 r8 a8, though not sure if it might affect others in a bad wayimage.thumb.png.1b5a045ba3c4c7f9bd22f626464708b0.png

 

also..check out SH_ZepFin~a.tga. i don't think that's how it's supposed to look...

image.png.b1dc52a8d948590b104c365ca8932ef4.png

Edited by notameowcelot
Link to comment
Share on other sites

SH_ZepFin~a.tga. Not sure what format is this. I doesn't use morton order. Size is equal to 2 channels. So anything from 8 + 8  or 6 + 5 + 6 or 5 + 5 + 5 +1 or single 16.

Link to comment
Share on other sites

2 hours ago, h3x3r said:

SH_ZepFin~a.tga. Not sure what format is this. I doesn't use morton order. Size is equal to 2 channels. So anything from 8 + 8  or 6 + 5 + 6 or 5 + 5 + 5 +1 or single 16.

Thankfully it's probably not too important at least. Would you be willing to take a look at some of the dds files? I'm wondering what sh_interior.dds is supposed to be or look like, but Kuriimu2's raw image tool stopped working after a day - keeps spewing errors.

Link to comment
Share on other sites

I wrote noesis script but can't figure out how to save it as cubemap. I know there is a flag but not sure where to use it.

Anyway here's struct...

local uint32 i;

struct {
    uint32 ImgWidth,ImgHeight,PixelFormat,MipMap;
}Header;

for (i=0; i < 6; i++)
struct {
    uint32 ImgSize;
    byte ImgData[ImgSize];
}RawData[Header.MipMap]<optimize=false>;

 

  • Like 2
Link to comment
Share on other sites

On 4/18/2024 at 4:47 PM, h3x3r said:

I wrote noesis script but can't figure out how to save it as cubemap. I know there is a flag but not sure where to use it.

Anyway here's struct...

local uint32 i;

struct {
    uint32 ImgWidth,ImgHeight,PixelFormat,MipMap;
}Header;

for (i=0; i < 6; i++)
struct {
    uint32 ImgSize;
    byte ImgData[ImgSize];
}RawData[Header.MipMap]<optimize=false>;

 

all good! if it's not possible to do it through noesis, some sort of plugin to extract the individual 'faces' from the cubemap would work just fine too, I'd think?

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...