diff --git a/Scripts/dds.py b/Scripts/dds.py index 792e2fd..4176fce 100644 --- a/Scripts/dds.py +++ b/Scripts/dds.py @@ -73,67 +73,65 @@ class DDSPixelFlags(enum.IntFlag): YUV = 0x200 LUMINANCE = 0x20000 -class DDSHeader: - def __init__(self, f): - self.read(f) +class DDSFile: + def __init__(self, file = None): + if (file): + self.read_header(file) - def read(self, f): - if f.read(4).decode() != "DDS ": - raise ValueError( - "File is not a valid DDS f: Incorrect magic bytes") + def read_header(self, file): + # read magic bytes + if file.read(4).decode() != 'DDS ': + raise ValueError("File is not a valid DDS file: Incorrect magic bytes") - dwords = struct.unpack('20I4s10I', f.read(124)) + # read header + header = struct.unpack('7I44x', file.read(72)) - # 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") + # check constant + if header[0] != 124: + raise ValueError("File is not a valid DDS file: Incorrect header size") # read basic info - self.flags = DDSFlags(dwords[1]) - self.height, self.width = dwords[2:4] + self.flags = DDSFlags(header[1]) + self.height, self.width, self.linear_size, self.depth, self.mipmapcount = header[2:7] - 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] + # read pixelformat + pixelformat = struct.unpack('2I4s5I', file.read(32)) - if DDSFlags.MIPMAPCOUNT in self.flags: - self.mipmapcount = dwords[6] + # check constant + if pixelformat[0] != 32: + raise ValueError("File is not a valid DDS file: Incorrect pixelformat size") - # 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] + self.pixel_flags = DDSPixelFlags(pixelformat[1]) + self.four_cc = pixelformat[2].decode() + self.rgb_bit_count, self.r_bitmask, self.g_bitmask, self.b_bitmask, self.a_bitmask = pixelformat[3:8] # read caps - self.dw_caps, self.dw_caps2, self.dw_caps3, self.dw_caps4 = dwords[26:30] # read dwCaps flags + self.dw_caps, self.dw_caps2, self.dw_caps3, self.dw_caps4 = struct.unpack('4I', file.read(16)) + + # read DX10 header + self.is_DX10 = (self.four_cc == 'DX10') + if self.is_DX10: + self.read_dx10header(file) + + def read_dx10header(self, file): + dx10header = file.read(20) + #TODO: actually do something with the DX10 data + + def write_header(self, file): + file.write('DDS ') + + # write header + file.write(struct.pack( + '7I44x', 124, int(self.flags), self.height, self.width, + self.linear_size, self.depth, self.mipmapcount)) + + # write pixelformat + file.write(struct.pack( + '2I4s5I', 32, int(self.pixel_flags), self.four_cc, self.rgb_bit_count, + self.r_bitmask, self.g_bitmask, self.b_bitmask, self.a_bitmask)) + + # write caps + file.write(struct.pack( + '4I', self.dw_caps, self.dw_caps2, self.dw_caps3, self.dw_caps4)) - if self.format == 'DX10': - dwords = f.read(20) - #TODO: actually read the DX10 data \ No newline at end of file + #TODO: handle DX10 data \ No newline at end of file diff --git a/Scripts/ddsck.py b/Scripts/ddsck.py index 9ae5d2d..9edd432 100755 --- a/Scripts/ddsck.py +++ b/Scripts/ddsck.py @@ -13,8 +13,8 @@ modes = parser.add_mutually_exclusive_group() modes.add_argument('--transparency', '-t', dest='mode', action='store_const', const="transparency", default="none", help = "Generate a list of files that fail the transparency check") modes.add_argument('--format', '-f', dest='mode', action='store_const', const="format", default="none", help = "Generate a list of files that fail the format check") -parser.add_argument('--convertcmd', type=str, metavar='CMD', default="convert", help="name of imagemagick's convert tool (default: %(default)s)") -parser.add_argument('--infocmd', type=str, metavar='CMD', default="nvddsinfo", help="name of the nvidia dds info tool (default: %(default)s)") +parser.add_argument('--convertcmd', type=str, metavar='CMD', default=dds.convertcmd, help="name of imagemagick's convert tool (default: %(default)s)") +parser.add_argument('--infocmd', type=str, metavar='CMD', default=dds.infocmd, help="name of the nvidia dds info tool (default: %(default)s)") args = parser.parse_args() diff --git a/Scripts/ddscompress.py b/Scripts/ddscompress.py index d26a466..71195fd 100755 --- a/Scripts/ddscompress.py +++ b/Scripts/ddscompress.py @@ -14,8 +14,8 @@ parser.add_argument('--format', type=str, choices=['auto', 'DXT1', 'DXT5'], defa parser.add_argument('--nomips', '-m', dest='mips', action='store_false', help = "Do not generate mipmaps") parser.add_argument('--noflip', '-f', dest='flip', action='store_false', help = "Do not flip the image") parser.add_argument('--keep', '-k', dest='delete', action='store_false', help = "Do not delete originals") -parser.add_argument('--convertcmd', type=str, metavar='CMD', default="convert", help="name of imagemagick's convert tool (default: %(default)s)") -parser.add_argument('--compresscmd', type=str, metavar='CMD', default="nvcompress", help="name of the nvidia dds compress tool (default: %(default)s)") +parser.add_argument('--convertcmd', type=str, metavar='CMD', default=dds.convertcmd, help="name of imagemagick's convert tool (default: %(default)s)") +parser.add_argument('--compresscmd', type=str, metavar='CMD', default=dds.compresscmd, help="name of the nvidia dds compress tool (default: %(default)s)") args = parser.parse_args() @@ -33,7 +33,7 @@ with tempfile.TemporaryDirectory() as tempDir: dds.flip(file, tmpOutput) else: tmpOutput = file - + if (args.format == "auto" and dds.alpha(file) < 255) or args.format == "DXT5": format = "-bc3" else: diff --git a/Scripts/ddsdecompress.py b/Scripts/ddsdecompress.py index 1865e29..a3152ee 100755 --- a/Scripts/ddsdecompress.py +++ b/Scripts/ddsdecompress.py @@ -8,7 +8,7 @@ import dds parser = argparse.ArgumentParser(description="Converts any number of files from dds to tga.") parser.add_argument('files', type=str, nargs='*', help = "input dds files") -parser.add_argument('--decompresscmd', type=str, metavar='CMD', default="nvdecompress", help="name of the nvidia dds decompress tool (default: %(default)s)") +parser.add_argument('--decompresscmd', type=str, metavar='CMD', default=dds.decompresscmd, help="name of the nvidia dds decompress tool (default: %(default)s)") args = parser.parse_args()