add dds header parsing and info tool
This commit is contained in:
parent
e410f0c15c
commit
cdea4674f8
126
Scripts/dds.py
126
Scripts/dds.py
@ -1,33 +1,139 @@
|
||||
import subprocess
|
||||
import os
|
||||
import typing
|
||||
import struct
|
||||
import re
|
||||
import io
|
||||
import enum
|
||||
|
||||
if os.name == 'nt':
|
||||
convertcmd = "convert.exe"
|
||||
compresscmd = "nvcompress.exe"
|
||||
decompresscmd = "nvdecompress.exe"
|
||||
infocmd = "nvddsinfo.exe"
|
||||
else:
|
||||
convertcmd = "convert"
|
||||
compresscmd = "nvcompress"
|
||||
decompresscmd = "nvdecompress"
|
||||
infocmd = "nvddsinfo"
|
||||
|
||||
def alpha(file):
|
||||
result = subprocess.run([convertcmd, file, "-resize", "1x1", "-format", "%[fx:int(255*a+.5)]", "info:-"], capture_output=True)
|
||||
result = subprocess.run([convertcmd, file, "-resize", "1x1",
|
||||
"-format", "%[fx:int(255*a+.5)]", "info:-"], capture_output=True)
|
||||
result.check_returncode()
|
||||
return int(result.stdout)
|
||||
|
||||
|
||||
def flip(file, output):
|
||||
result = subprocess.run([convertcmd, '-flip', file, output], capture_output=True)
|
||||
result = subprocess.run(
|
||||
[convertcmd, '-flip', file, output], capture_output=True)
|
||||
result.check_returncode()
|
||||
|
||||
def nvcompress(format, file, output, mips = True):
|
||||
|
||||
|
||||
def nvcompress(format, file, output, mips=True):
|
||||
args = [format]
|
||||
if not mips:
|
||||
args.append('-nomips')
|
||||
|
||||
result = subprocess.run([compresscmd] + args + [file, output], capture_output=True)
|
||||
|
||||
result = subprocess.run([compresscmd] + args +
|
||||
[file, output], capture_output=True)
|
||||
result.check_returncode()
|
||||
|
||||
|
||||
|
||||
def nvdecompress(file, output):
|
||||
result = subprocess.run([decompresscmd, file, output], capture_output=True)
|
||||
result.check_returncode()
|
||||
|
||||
|
||||
def nvinfo(file):
|
||||
result = subprocess.run([infocmd, file], capture_output=True)
|
||||
result.check_returncode()
|
||||
|
||||
|
||||
info = {
|
||||
"format": re.search(r"FourCC: '(.{4})'", str(result.stdout)).group(1)
|
||||
}
|
||||
|
||||
return info
|
||||
|
||||
return info
|
||||
|
||||
class DDSFlags(enum.IntFlag):
|
||||
CAPS = 0x1
|
||||
HEIGHT = 0x2
|
||||
WIDTH = 0x4
|
||||
PITCH = 0x8
|
||||
PIXEL_FORMAT = 0x1000
|
||||
MIPMAPCOUNT = 0x20000
|
||||
LINEAR_SIZE = 0x80000
|
||||
DEPTH = 0x800000
|
||||
|
||||
class DDSPixelFlags(enum.IntFlag):
|
||||
ALPHAPIXELS = 0x1
|
||||
ALPHA = 0x2
|
||||
FOURCC = 0x4
|
||||
RGB = 0x40
|
||||
YUV = 0x200
|
||||
LUMINANCE = 0x20000
|
||||
|
||||
class DDSHeader:
|
||||
def __init__(self, f):
|
||||
self.read(f)
|
||||
|
||||
def read(self, f):
|
||||
if f.read(4).decode() != "DDS ":
|
||||
raise ValueError(
|
||||
"File is not a valid DDS f: Incorrect magic bytes")
|
||||
|
||||
dwords = struct.unpack('20I4s10I', f.read(124))
|
||||
|
||||
# check constants
|
||||
if dwords[0] != 124:
|
||||
raise ValueError(
|
||||
"File is not a valid DDS file: Incorrect header size")
|
||||
if dwords[18] != 32:
|
||||
raise ValueError(
|
||||
"File is not a valid DDS file: Incorrect pixelformat size")
|
||||
|
||||
# read basic info
|
||||
self.flags = DDSFlags(dwords[1])
|
||||
self.height, self.width = dwords[2:4]
|
||||
|
||||
if DDSFlags.PITCH in self.flags:
|
||||
self.pitch = dwords[4]
|
||||
else:
|
||||
self.linear_size = dwords[4]
|
||||
|
||||
if DDSFlags.DEPTH in self.flags:
|
||||
self.depth = dwords[5]
|
||||
|
||||
if DDSFlags.MIPMAPCOUNT in self.flags:
|
||||
self.mipmapcount = dwords[6]
|
||||
|
||||
# read pixelformat
|
||||
self.pixel_flags = DDSPixelFlags(dwords[19])
|
||||
|
||||
if DDSPixelFlags.ALPHAPIXELS in self.pixel_flags:
|
||||
# texture has alpha data
|
||||
self.a_bitmask = dwords[25]
|
||||
|
||||
if DDSPixelFlags.FOURCC in self.pixel_flags:
|
||||
# texture is compressed, four_cc contains the format
|
||||
self.format = dwords[20].decode()
|
||||
else:
|
||||
self.format = 'uncompressed'
|
||||
if (DDSPixelFlags.RGB | DDSPixelFlags.YUV) & self.pixel_flags:
|
||||
# uncompressed RGB texture
|
||||
self.rgb_bit_count, self.r_bitmask, self.g_bitmask, self.b_bitmask = dwords[21:25]
|
||||
elif DDSPixelFlags.ALPHA in self.pixel_flags:
|
||||
# uncompressed alpha-only texture
|
||||
self.rgb_bit_count = dwords[21]
|
||||
self.a_bitmask = dwords[25]
|
||||
elif DDSPixelFlags.LUMINANCE in self.pixel_flags:
|
||||
# uncompressed luminance-only texture
|
||||
self.rgb_bit_count = dwords[21]
|
||||
self.r_bitmask = dwords[22]
|
||||
|
||||
# read caps
|
||||
self.dw_caps, self.dw_caps2, self.dw_caps3, self.dw_caps4 = dwords[26:30] # read dwCaps flags
|
||||
|
||||
if self.format == 'DX10':
|
||||
dwords = f.read(20)
|
||||
#TODO: actually read the DX10 data
|
Loading…
Reference in New Issue
Block a user