klensy / wt-tools

War Thunder resource extraction tools
128 stars 39 forks source link

Can't open ddsx files from Cuisine Royale #51

Open Twisted6 opened 4 years ago

Twisted6 commented 4 years ago

Hey klensy, it's me again xD

I'm trying to open the DDSX map images using ddsx_unpack.exe but I can't get it to work. I've tried placing both oo2core_6_win64.dll and the latest oo2core_8_win64.dll in the same folder as ddsx_unpack.exe. The console pops up for a second and then closes. Am I doing something wrong or are these particular files just not supported? I've attached one of the ddsx files. mexico_4x4_minimap.zip

klensy commented 4 years ago

Hi.

  1. You should run tools from command line or powershell, if you want error info.
  2. Fixed, will upload soon.

Need auto upload builds to releases, it's annoying to upload by hands.

klensy commented 4 years ago

Uploaded, check it.

But it looks little broken.

Twisted6 commented 4 years ago

Thanks again for the quick response. It's almost working perfectly but on one of the maps the bottom half is on the top and has been scaled weirdly. I've included examples of a working map and a cut map. https://www.dropbox.com/s/ay7hqqdpbmca02l/Screenshot%202020-05-05%2013.55.18.png?dl=0 https://www.dropbox.com/s/87mkqy1rymah11j/Mexico.jpg?dl=0

jdoe1024 commented 3 years ago

Lots of the DDSX files I've tried from Cuisine Royale had the FLG_REV_MIP_ORDER flag set. That means the mipmaps appear in reverse order, from the smallest mipmap to the biggest. In DDS files, this must be the opposite order (from the biggest mipmap to the smallest). Thus, the mipmaps order must be reversed before writing the content to the DDS file.

I did the following changes to ddsx_unpack.py to reverse the mipmaps order and it works for all the DDSX files I've tried for CRSED:

Reversed mipmap patch for DXT1 ```diff --- wt-tools/ddsx_unpack-original.py 2020-05-28 08:44:30.000000000 +0200 +++ wt-tools/ddsx_unpack.py 2021-01-11 04:57:59.646787500 +0100 @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import struct, sys, ctypes, zlib import os.path import pylzma @@ -61,11 +63,11 @@ dds_packed = compression_type.get(dds_compression_type, "") if dds_packed == "not_packed": - return dds_data.raw + data[0x20:] + d_data = data[0x20:] elif dds_packed == "lzma": - return dds_data.raw + pylzma.decompress(data[0x20:], maxlength=parsed_data.header.memSz) + d_data = pylzma.decompress(data[0x20:], maxlength=parsed_data.header.memSz) elif dds_packed == "zlib": - return dds_data.raw + zlib.decompress(data[0x20:]) + d_data = zlib.decompress(data[0x20:]) elif dds_packed == "oodle": ''' private static extern long OodleLZ_Decompress(byte[] buffer, long bufferSize, byte[] result, @@ -79,7 +81,7 @@ if res == 0: print("Error unpacking oodle compressed texture") return - return dds_data.raw + decompressed_data.raw + d_data = decompressed_data.raw else: print("unsupported compression type: {}".format(dds_packed)) elif dds_packed == "zstd": @@ -88,11 +90,44 @@ if d_data == 0: print("Error unpacking zstd compressed texture") return - return dds_data.raw + d_data else: print("Unknown compression type: {}".format(dds_compression_type)) return + if parsed_data.header.flags.FLG_REV_MIP_ORDER: + # Reverse MIPMAP order (from smallest -> biggest to biggest -> smallest) + if texture_format == b'DXT1': + def get_dxt1_size(width, height): + # Each 4x4 blocks use 8 bytes + # XXX We suppose width and height must be rounded up so that they are multiple of 4 + if (width & 3) != 0: + width += 4 - (width & 3) + if (height & 3) != 0: + height += 4 - (height & 3) + + blocks = (width * height) // (4 * 4) + return blocks * 8 + + pos = 0 + images = [] + for level in range(parsed_data.header.levels - 1, -1, -1): + width = parsed_data.header.w // (2**level) + height = parsed_data.header.h // (2**level) + size = get_dxt1_size(width, height) + # print("%d => %d x %d (%d)" % (level, width, height, size)) + images.append(d_data[pos:pos+size]) + pos += size + + d_data = bytearray() + for image in reversed(images): + d_data.extend(image) + + elif parsed_data.header.levels > 1: + print("Dunno how to re-order mipmaps for format {}".format(texture_format)) + return + + return dds_data.raw + d_data + def unpack_file(filename): # TODO: eliminate copy&paste with blk_unpack ```
klensy commented 3 years ago

@jdoe1024 Thanks for patch! But better send it as attached file or pull request.

build https://github.com/klensy/wt-tools/actions/runs/510036724

klensy commented 3 years ago

I think i'll try https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-file-layout-for-textures to use with non DXT1 textures.