|
|
@@ -14,22 +14,24 @@ import copy
|
|
|
import tempfile
|
|
|
import shutil
|
|
|
|
|
|
+
|
|
|
#
|
|
|
# Config
|
|
|
#
|
|
|
class Config:
|
|
|
- in_files = []
|
|
|
- out_file = ""
|
|
|
- fast = False
|
|
|
- type = 0
|
|
|
- normal = False
|
|
|
- convert_path = ""
|
|
|
- no_alpha = False
|
|
|
- compressed_formats = 0
|
|
|
- store_uncompressed = True
|
|
|
- to_linear_rgb = False
|
|
|
-
|
|
|
- tmp_dir = ""
|
|
|
+ in_files = []
|
|
|
+ out_file = ""
|
|
|
+ fast = False
|
|
|
+ type = 0
|
|
|
+ normal = False
|
|
|
+ convert_path = ""
|
|
|
+ no_alpha = False
|
|
|
+ compressed_formats = 0
|
|
|
+ store_uncompressed = True
|
|
|
+ to_linear_rgb = False
|
|
|
+
|
|
|
+ tmp_dir = ""
|
|
|
+
|
|
|
|
|
|
#
|
|
|
# AnKi texture
|
|
|
@@ -63,653 +65,657 @@ TF_NEAREST = 2
|
|
|
#
|
|
|
|
|
|
# dwFlags of DDSURFACEDESC2
|
|
|
-DDSD_CAPS = 0x00000001
|
|
|
-DDSD_HEIGHT = 0x00000002
|
|
|
-DDSD_WIDTH = 0x00000004
|
|
|
-DDSD_PITCH = 0x00000008
|
|
|
-DDSD_PIXELFORMAT = 0x00001000
|
|
|
-DDSD_MIPMAPCOUNT = 0x00020000
|
|
|
-DDSD_LINEARSIZE = 0x00080000
|
|
|
-DDSD_DEPTH = 0x00800000
|
|
|
+DDSD_CAPS = 0x00000001
|
|
|
+DDSD_HEIGHT = 0x00000002
|
|
|
+DDSD_WIDTH = 0x00000004
|
|
|
+DDSD_PITCH = 0x00000008
|
|
|
+DDSD_PIXELFORMAT = 0x00001000
|
|
|
+DDSD_MIPMAPCOUNT = 0x00020000
|
|
|
+DDSD_LINEARSIZE = 0x00080000
|
|
|
+DDSD_DEPTH = 0x00800000
|
|
|
|
|
|
# ddpfPixelFormat of DDSURFACEDESC2
|
|
|
-DDPF_ALPHAPIXELS = 0x00000001
|
|
|
-DDPF_FOURCC = 0x00000004
|
|
|
-DDPF_RGB = 0x00000040
|
|
|
+DDPF_ALPHAPIXELS = 0x00000001
|
|
|
+DDPF_FOURCC = 0x00000004
|
|
|
+DDPF_RGB = 0x00000040
|
|
|
|
|
|
# dwCaps1 of DDSCAPS2
|
|
|
-DDSCAPS_COMPLEX = 0x00000008
|
|
|
-DDSCAPS_TEXTURE = 0x00001000
|
|
|
-DDSCAPS_MIPMAP = 0x00400000
|
|
|
+DDSCAPS_COMPLEX = 0x00000008
|
|
|
+DDSCAPS_TEXTURE = 0x00001000
|
|
|
+DDSCAPS_MIPMAP = 0x00400000
|
|
|
|
|
|
# dwCaps2 of DDSCAPS2
|
|
|
-DDSCAPS2_CUBEMAP = 0x00000200
|
|
|
-DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400
|
|
|
-DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800
|
|
|
-DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000
|
|
|
-DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000
|
|
|
-DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000
|
|
|
-DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000
|
|
|
-DDSCAPS2_VOLUME = 0x00200000
|
|
|
+DDSCAPS2_CUBEMAP = 0x00000200
|
|
|
+DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400
|
|
|
+DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800
|
|
|
+DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000
|
|
|
+DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000
|
|
|
+DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000
|
|
|
+DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000
|
|
|
+DDSCAPS2_VOLUME = 0x00200000
|
|
|
+
|
|
|
|
|
|
class DdsHeader:
|
|
|
- """ The header of a dds file """
|
|
|
-
|
|
|
- _fields = [
|
|
|
- ('dwMagic', '4s'),
|
|
|
- ('dwSize', 'I'),
|
|
|
- ('dwFlags', 'I'),
|
|
|
- ('dwHeight', 'I'),
|
|
|
- ('dwWidth', 'I'),
|
|
|
- ('dwPitchOrLinearSize', 'I'),
|
|
|
- ('dwDepth', 'I'),
|
|
|
- ('dwMipMapCount', 'I'),
|
|
|
- ('dwReserved1', '44s'),
|
|
|
-
|
|
|
- # Pixel format
|
|
|
- ('dwSize', 'I'),
|
|
|
- ('dwFlags', 'I'),
|
|
|
- ('dwFourCC', '4s'),
|
|
|
- ('dwRGBBitCount', 'I'),
|
|
|
- ('dwRBitMask', 'I'),
|
|
|
- ('dwGBitMask', 'I'),
|
|
|
- ('dwBBitMask', 'I'),
|
|
|
- ('dwRGBAlphaBitMask', 'I'),
|
|
|
-
|
|
|
- ('dwCaps1', 'I'),
|
|
|
- ('dwCaps2', 'I'),
|
|
|
- ('dwCapsReserved', '8s'),
|
|
|
- ('dwReserved2', 'I')]
|
|
|
-
|
|
|
- def __init__(self, buff):
|
|
|
- buff_format = self.get_format()
|
|
|
- items = struct.unpack(buff_format, buff)
|
|
|
- for field, value in map(None, self._fields, items):
|
|
|
- setattr(self, field[0], value)
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def get_format(cls):
|
|
|
- return '<' + ''.join([f[1] for f in cls._fields])
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def get_size(cls):
|
|
|
- return struct.calcsize(cls.get_format())
|
|
|
+ """ The header of a dds file """
|
|
|
+
|
|
|
+ _fields = [
|
|
|
+ ('dwMagic', '4s'),
|
|
|
+ ('dwSize', 'I'),
|
|
|
+ ('dwFlags', 'I'),
|
|
|
+ ('dwHeight', 'I'),
|
|
|
+ ('dwWidth', 'I'),
|
|
|
+ ('dwPitchOrLinearSize', 'I'),
|
|
|
+ ('dwDepth', 'I'),
|
|
|
+ ('dwMipMapCount', 'I'),
|
|
|
+ ('dwReserved1', '44s'),
|
|
|
+
|
|
|
+ # Pixel format
|
|
|
+ ('dwSize', 'I'),
|
|
|
+ ('dwFlags', 'I'),
|
|
|
+ ('dwFourCC', '4s'),
|
|
|
+ ('dwRGBBitCount', 'I'),
|
|
|
+ ('dwRBitMask', 'I'),
|
|
|
+ ('dwGBitMask', 'I'),
|
|
|
+ ('dwBBitMask', 'I'),
|
|
|
+ ('dwRGBAlphaBitMask', 'I'),
|
|
|
+ ('dwCaps1', 'I'),
|
|
|
+ ('dwCaps2', 'I'),
|
|
|
+ ('dwCapsReserved', '8s'),
|
|
|
+ ('dwReserved2', 'I')
|
|
|
+ ]
|
|
|
+
|
|
|
+ def __init__(self, buff):
|
|
|
+ buff_format = self.get_format()
|
|
|
+ items = struct.unpack(buff_format, buff)
|
|
|
+ for field, value in map(None, self._fields, items):
|
|
|
+ setattr(self, field[0], value)
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def get_format(cls):
|
|
|
+ return '<' + ''.join([f[1] for f in cls._fields])
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def get_size(cls):
|
|
|
+ return struct.calcsize(cls.get_format())
|
|
|
+
|
|
|
|
|
|
#
|
|
|
# ETC2
|
|
|
#
|
|
|
class PkmHeader:
|
|
|
- """ The header of a pkm file """
|
|
|
-
|
|
|
- _fields = [
|
|
|
- ("magic", "6s"),
|
|
|
- ("type", "H"),
|
|
|
- ("width", "H"),
|
|
|
- ("height", "H"),
|
|
|
- ("origWidth", "H"),
|
|
|
- ("origHeight", "H")]
|
|
|
-
|
|
|
- def __init__(self, buff):
|
|
|
- buff_format = self.get_format()
|
|
|
- items = struct.unpack(buff_format, buff)
|
|
|
- for field, value in map(None, self._fields, items):
|
|
|
- setattr(self, field[0], value)
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def get_format(cls):
|
|
|
- return ">" + "".join([f[1] for f in cls._fields])
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def get_size(cls):
|
|
|
- return struct.calcsize(cls.get_format())
|
|
|
-
|
|
|
-#
|
|
|
-# Functions
|
|
|
-#
|
|
|
-def printi(s):
|
|
|
- print("[I] %s" % s)
|
|
|
-
|
|
|
-def printw(s):
|
|
|
- print("[W] %s" % s)
|
|
|
-
|
|
|
-def is_power2(num):
|
|
|
- """ Returns true if a number is a power of two """
|
|
|
- return num != 0 and ((num & (num - 1)) == 0)
|
|
|
-
|
|
|
-def get_base_fname(path):
|
|
|
- """ From path/to/a/file.ext return the "file" """
|
|
|
- return os.path.splitext(os.path.basename(path))[0]
|
|
|
-
|
|
|
-def parse_commandline():
|
|
|
- """ Parse the command line arguments """
|
|
|
-
|
|
|
- parser = argparse.ArgumentParser(description = "This program converts a single image or a number " \
|
|
|
- "of images (for 3D and 2DArray textures) to AnKi texture format. " \
|
|
|
- "It requires 4 different applications/executables to " \
|
|
|
- "operate: convert, identify, nvcompress and etcpack. These " \
|
|
|
- "applications should be in PATH except the convert where you " \
|
|
|
- "need to define the executable explicitly",
|
|
|
- formatter_class = argparse.ArgumentDefaultsHelpFormatter)
|
|
|
-
|
|
|
- parser.add_argument("-i", "--input", nargs = "+", required = True,
|
|
|
- help = "specify the image(s) to convert. Seperate with space")
|
|
|
-
|
|
|
- parser.add_argument("-o", "--output", required = True, help = "specify output AnKi image.")
|
|
|
+ """ The header of a pkm file """
|
|
|
|
|
|
- parser.add_argument("-t", "--type", default = "2D", choices = ["2D", "3D", "2DArray"],
|
|
|
- help = "type of the image (2D or cube or 3D or 2DArray)")
|
|
|
+ _fields = [("magic", "6s"), ("type", "H"), ("width", "H"), ("height", "H"), ("origWidth", "H"), ("origHeight", "H")]
|
|
|
|
|
|
- parser.add_argument("-f", "--fast", type = int, default = 0, help = "run the fast version of the converters")
|
|
|
+ def __init__(self, buff):
|
|
|
+ buff_format = self.get_format()
|
|
|
+ items = struct.unpack(buff_format, buff)
|
|
|
+ for field, value in map(None, self._fields, items):
|
|
|
+ setattr(self, field[0], value)
|
|
|
|
|
|
- parser.add_argument("-n", "--normal", type = int, default = 0, help = "assume the texture is normal")
|
|
|
+ @classmethod
|
|
|
+ def get_format(cls):
|
|
|
+ return ">" + "".join([f[1] for f in cls._fields])
|
|
|
|
|
|
- parser.add_argument("-c", "--convert-path", default = "/usr/bin/convert",
|
|
|
- help = "the executable where convert tool is located. Stupid etcpack cannot get it from PATH")
|
|
|
+ @classmethod
|
|
|
+ def get_size(cls):
|
|
|
+ return struct.calcsize(cls.get_format())
|
|
|
|
|
|
- parser.add_argument("--no-alpha", type = int, default = 0, help = "remove alpha channel")
|
|
|
|
|
|
- parser.add_argument("--store-uncompressed", type = int, default = 0, help = "store or not uncompressed data")
|
|
|
-
|
|
|
- parser.add_argument("--store-etc", type = int, default = 0, help = "store or not etc compressed data")
|
|
|
-
|
|
|
- parser.add_argument("--store-s3tc", type = int, default = 1, help = "store or not S3TC compressed data")
|
|
|
-
|
|
|
- parser.add_argument("--to-linear-rgb", type = int, default = 0,
|
|
|
- help = "assume the input textures are sRGB. If this option is true then convert them to linear RGB")
|
|
|
-
|
|
|
- parser.add_argument("--filter", default = "default", choices = ["default", "linear", "nearest"],
|
|
|
- help = "texture filtering. Can be: default, linear, nearest")
|
|
|
+#
|
|
|
+# Functions
|
|
|
+#
|
|
|
+def printi(s):
|
|
|
+ print("[I] %s" % s)
|
|
|
|
|
|
- parser.add_argument("--mips-count", type = int, default = 0xFFFF, help = "Max number of mipmaps")
|
|
|
|
|
|
- args = parser.parse_args()
|
|
|
+def printw(s):
|
|
|
+ print("[W] %s" % s)
|
|
|
|
|
|
- if args.type == "2D":
|
|
|
- typ = TT_2D
|
|
|
- elif args.type == "cube":
|
|
|
- typ = TT_CUBE
|
|
|
- elif args.type == "3D":
|
|
|
- typ = TT_3D
|
|
|
- elif args.type == "2DArray":
|
|
|
- typ = TT_2D_ARRAY
|
|
|
- else:
|
|
|
- assert 0, "See file"
|
|
|
|
|
|
- if args.filter == "default":
|
|
|
- filter = TF_DEFAULT
|
|
|
- elif args.filter == "linear":
|
|
|
- filter = TF_LINEAR
|
|
|
- elif args.filter == "nearest":
|
|
|
- filter = TF_NEAREST
|
|
|
- else:
|
|
|
- assert 0, "See file"
|
|
|
+def is_power2(num):
|
|
|
+ """ Returns true if a number is a power of two """
|
|
|
+ return num != 0 and ((num & (num - 1)) == 0)
|
|
|
|
|
|
- if args.mips_count <= 0:
|
|
|
- parser.error("Wrong number of mipmaps")
|
|
|
|
|
|
- config = Config()
|
|
|
- config.in_files = args.input
|
|
|
- config.out_file = args.output
|
|
|
- config.fast = args.fast
|
|
|
- config.type = typ
|
|
|
- config.normal = args.normal
|
|
|
- config.convert_path = args.convert_path
|
|
|
- config.no_alpha = args.no_alpha
|
|
|
- config.store_uncompressed = args.store_uncompressed
|
|
|
- config.to_linear_rgb = args.to_linear_rgb
|
|
|
- config.filter = filter
|
|
|
- config.mips_count = args.mips_count
|
|
|
+def get_base_fname(path):
|
|
|
+ """ From path/to/a/file.ext return the "file" """
|
|
|
+ return os.path.splitext(os.path.basename(path))[0]
|
|
|
|
|
|
- if args.store_etc:
|
|
|
- config.compressed_formats = config.compressed_formats | DC_ETC2
|
|
|
|
|
|
- if args.store_s3tc:
|
|
|
- config.compressed_formats = config.compressed_formats | DC_S3TC
|
|
|
+def parse_commandline():
|
|
|
+ """ Parse the command line arguments """
|
|
|
+
|
|
|
+ parser = argparse.ArgumentParser(description = "This program converts a single image or a number " \
|
|
|
+ "of images (for 3D and 2DArray textures) to AnKi texture format. " \
|
|
|
+ "It requires 4 different applications/executables to " \
|
|
|
+ "operate: convert, identify, nvcompress and etcpack. These " \
|
|
|
+ "applications should be in PATH except the convert where you " \
|
|
|
+ "need to define the executable explicitly",
|
|
|
+ formatter_class = argparse.ArgumentDefaultsHelpFormatter)
|
|
|
+
|
|
|
+ parser.add_argument(
|
|
|
+ "-i", "--input", nargs="+", required=True, help="specify the image(s) to convert. Seperate with space")
|
|
|
+
|
|
|
+ parser.add_argument("-o", "--output", required=True, help="specify output AnKi image.")
|
|
|
+
|
|
|
+ parser.add_argument(
|
|
|
+ "-t",
|
|
|
+ "--type",
|
|
|
+ default="2D",
|
|
|
+ choices=["2D", "3D", "2DArray"],
|
|
|
+ help="type of the image (2D or cube or 3D or 2DArray)")
|
|
|
+
|
|
|
+ parser.add_argument("-f", "--fast", type=int, default=0, help="run the fast version of the converters")
|
|
|
+
|
|
|
+ parser.add_argument("-n", "--normal", type=int, default=0, help="assume the texture is normal")
|
|
|
+
|
|
|
+ parser.add_argument(
|
|
|
+ "-c",
|
|
|
+ "--convert-path",
|
|
|
+ default="/usr/bin/convert",
|
|
|
+ help="the executable where convert tool is located. Stupid etcpack cannot get it from PATH")
|
|
|
+
|
|
|
+ parser.add_argument("--no-alpha", type=int, default=0, help="remove alpha channel")
|
|
|
+
|
|
|
+ parser.add_argument("--store-uncompressed", type=int, default=0, help="store or not uncompressed data")
|
|
|
+
|
|
|
+ parser.add_argument("--store-etc", type=int, default=0, help="store or not etc compressed data")
|
|
|
+
|
|
|
+ parser.add_argument("--store-s3tc", type=int, default=1, help="store or not S3TC compressed data")
|
|
|
+
|
|
|
+ parser.add_argument(
|
|
|
+ "--to-linear-rgb",
|
|
|
+ type=int,
|
|
|
+ default=0,
|
|
|
+ help="assume the input textures are sRGB. If this option is true then convert them to linear RGB")
|
|
|
+
|
|
|
+ parser.add_argument(
|
|
|
+ "--filter",
|
|
|
+ default="default",
|
|
|
+ choices=["default", "linear", "nearest"],
|
|
|
+ help="texture filtering. Can be: default, linear, nearest")
|
|
|
+
|
|
|
+ parser.add_argument("--mips-count", type=int, default=0xFFFF, help="Max number of mipmaps")
|
|
|
+
|
|
|
+ args = parser.parse_args()
|
|
|
+
|
|
|
+ if args.type == "2D":
|
|
|
+ typ = TT_2D
|
|
|
+ elif args.type == "cube":
|
|
|
+ typ = TT_CUBE
|
|
|
+ elif args.type == "3D":
|
|
|
+ typ = TT_3D
|
|
|
+ elif args.type == "2DArray":
|
|
|
+ typ = TT_2D_ARRAY
|
|
|
+ else:
|
|
|
+ assert 0, "See file"
|
|
|
+
|
|
|
+ if args.filter == "default":
|
|
|
+ filter = TF_DEFAULT
|
|
|
+ elif args.filter == "linear":
|
|
|
+ filter = TF_LINEAR
|
|
|
+ elif args.filter == "nearest":
|
|
|
+ filter = TF_NEAREST
|
|
|
+ else:
|
|
|
+ assert 0, "See file"
|
|
|
+
|
|
|
+ if args.mips_count <= 0:
|
|
|
+ parser.error("Wrong number of mipmaps")
|
|
|
+
|
|
|
+ config = Config()
|
|
|
+ config.in_files = args.input
|
|
|
+ config.out_file = args.output
|
|
|
+ config.fast = args.fast
|
|
|
+ config.type = typ
|
|
|
+ config.normal = args.normal
|
|
|
+ config.convert_path = args.convert_path
|
|
|
+ config.no_alpha = args.no_alpha
|
|
|
+ config.store_uncompressed = args.store_uncompressed
|
|
|
+ config.to_linear_rgb = args.to_linear_rgb
|
|
|
+ config.filter = filter
|
|
|
+ config.mips_count = args.mips_count
|
|
|
+
|
|
|
+ if args.store_etc:
|
|
|
+ config.compressed_formats = config.compressed_formats | DC_ETC2
|
|
|
+
|
|
|
+ if args.store_s3tc:
|
|
|
+ config.compressed_formats = config.compressed_formats | DC_S3TC
|
|
|
+
|
|
|
+ return config
|
|
|
|
|
|
- return config
|
|
|
|
|
|
def identify_image(in_file):
|
|
|
- """ Return the size of the input image and the internal format """
|
|
|
+ """ Return the size of the input image and the internal format """
|
|
|
+
|
|
|
+ color_format = CF_NONE
|
|
|
|
|
|
- color_format = CF_NONE
|
|
|
- width = 0
|
|
|
- height = 0
|
|
|
+ proc = subprocess.Popen(["identify", "-verbose", in_file], stdout=subprocess.PIPE)
|
|
|
|
|
|
- proc = subprocess.Popen(["identify", "-verbose" , in_file], stdout=subprocess.PIPE)
|
|
|
+ stdout_str = proc.stdout.read()
|
|
|
|
|
|
- stdout_str = proc.stdout.read()
|
|
|
+ # Make sure the colorspace is what we want
|
|
|
+ """reg = re.search(r"Colorspace: (.*)", stdout_str)
|
|
|
+ if not reg or (reg.group(1) != "RGB" and reg.group(1) != "sRGB"):
|
|
|
+ raise Exception("Something is wrong with the colorspace")"""
|
|
|
|
|
|
- # Make sure the colorspace is what we want
|
|
|
- """reg = re.search(r"Colorspace: (.*)", stdout_str)
|
|
|
- if not reg or reg.group(1) != "RGB":
|
|
|
- raise Exception("Something is wrong with the colorspace")"""
|
|
|
+ # Get the size of the iamge
|
|
|
+ reg = re.search(r"Geometry: ([0-9]*)x([0-9]*)\+", stdout_str)
|
|
|
|
|
|
- # Get the size of the iamge
|
|
|
- reg = re.search(r"Geometry: ([0-9]*)x([0-9]*)\+", stdout_str)
|
|
|
+ if not reg:
|
|
|
+ raise Exception("Cannot extract size")
|
|
|
|
|
|
- if not reg:
|
|
|
- raise Exception("Cannot extract size")
|
|
|
+ # Identify the color space
|
|
|
+ """if not re.search(r"red: 8-bit", stdout_str) or not re.search(r"green: 8-bit", stdout_str) or not re.search(
|
|
|
+ r"blue: 8-bit", stdout_str):
|
|
|
+ raise Exception("Incorrect channel depths")"""
|
|
|
|
|
|
- # Identify the color space
|
|
|
- """if not re.search(r"red: 8-bit", stdout_str) \
|
|
|
- or not re.search(r"green: 8-bit", stdout_str) \
|
|
|
- or not re.search(r"blue: 8-bit", stdout_str): \
|
|
|
- raise Exception("Incorrect channel depths")"""
|
|
|
+ if re.search(r"alpha: 8-bit", stdout_str):
|
|
|
+ color_format = CF_RGBA8
|
|
|
+ color_format_str = "RGBA"
|
|
|
+ else:
|
|
|
+ color_format = CF_RGB8
|
|
|
+ color_format_str = "RGB"
|
|
|
|
|
|
- if re.search(r"alpha: 8-bit", stdout_str):
|
|
|
- color_format = CF_RGBA8
|
|
|
- color_format_str = "RGBA"
|
|
|
- else:
|
|
|
- color_format = CF_RGB8
|
|
|
- color_format_str = "RGB"
|
|
|
+ # print some stuff and return
|
|
|
+ printi("width: %s, height: %s color format: %s" % \
|
|
|
+ (reg.group(1), reg.group(2), color_format_str))
|
|
|
|
|
|
- # print some stuff and return
|
|
|
- printi("width: %s, height: %s color format: %s" % \
|
|
|
- (reg.group(1), reg.group(2), color_format_str))
|
|
|
+ return (color_format, int(reg.group(1)), int(reg.group(2)))
|
|
|
|
|
|
- return (color_format, int(reg.group(1)), int(reg.group(2)))
|
|
|
|
|
|
def create_mipmaps(in_file, tmp_dir, width_, height_, color_format, to_linear_rgb, max_mip_count):
|
|
|
- """ Create a number of images for all mipmaps """
|
|
|
+ """ Create a number of images for all mipmaps """
|
|
|
|
|
|
- printi("Generate mipmaps")
|
|
|
+ printi("Generate mipmaps")
|
|
|
|
|
|
- width = width_
|
|
|
- height = height_
|
|
|
+ width = width_
|
|
|
+ height = height_
|
|
|
|
|
|
- mips_fnames = []
|
|
|
+ mips_fnames = []
|
|
|
|
|
|
- while width >= 4 and height >= 4:
|
|
|
- size_str = "%dx%d" % (width, height)
|
|
|
- out_file_str = os.path.join(tmp_dir, get_base_fname(in_file)) + "." + size_str
|
|
|
+ while width >= 4 and height >= 4:
|
|
|
+ size_str = "%dx%d" % (width, height)
|
|
|
+ out_file_str = os.path.join(tmp_dir, get_base_fname(in_file)) + "." + size_str
|
|
|
|
|
|
- printi(" %s.tga" % out_file_str)
|
|
|
+ mips_fnames.append(out_file_str)
|
|
|
|
|
|
- mips_fnames.append(out_file_str)
|
|
|
+ args = ["convert", in_file]
|
|
|
|
|
|
- args = ["convert", in_file]
|
|
|
+ # to linear
|
|
|
+ if to_linear_rgb:
|
|
|
+ if color_format != CF_RGB8:
|
|
|
+ raise Exception("to linear RGB only supported for RGB textures")
|
|
|
|
|
|
- # to linear
|
|
|
- if to_linear_rgb:
|
|
|
- if color_format != CF_RGB8:
|
|
|
- raise Exception("to linear RGB only supported for RGB textures")
|
|
|
+ args.append("-set")
|
|
|
+ args.append("colorspace")
|
|
|
+ args.append("sRGB")
|
|
|
+ args.append("-colorspace")
|
|
|
+ args.append("RGB")
|
|
|
|
|
|
- args.append("-set")
|
|
|
- args.append("colorspace")
|
|
|
- args.append("sRGB")
|
|
|
- args.append("-colorspace")
|
|
|
- args.append("RGB")
|
|
|
+ # Add this because it will automatically convert gray-like images to grayscale TGAs
|
|
|
+ args.append("-type")
|
|
|
+ args.append("TrueColor")
|
|
|
|
|
|
- # Add this because it will automatically convert gray-like images to grayscale TGAs
|
|
|
- args.append("-type")
|
|
|
- args.append("TrueColor")
|
|
|
+ # resize
|
|
|
+ args.append("-resize")
|
|
|
+ args.append(size_str)
|
|
|
|
|
|
- # resize
|
|
|
- args.append("-resize")
|
|
|
- args.append(size_str)
|
|
|
+ # alpha
|
|
|
+ args.append("-alpha")
|
|
|
+ if color_format == CF_RGB8:
|
|
|
+ args.append("deactivate")
|
|
|
+ else:
|
|
|
+ args.append("activate")
|
|
|
|
|
|
- # alpha
|
|
|
- args.append("-alpha")
|
|
|
- if color_format == CF_RGB8:
|
|
|
- args.append("deactivate")
|
|
|
- else:
|
|
|
- args.append("activate")
|
|
|
+ args.append(out_file_str + ".png")
|
|
|
+ printi(" " + " ".join(args))
|
|
|
+ subprocess.check_call(args)
|
|
|
|
|
|
- args.append(out_file_str + ".tga")
|
|
|
- subprocess.check_call(args)
|
|
|
+ if (len(mips_fnames) == max_mip_count):
|
|
|
+ break
|
|
|
|
|
|
- if(len(mips_fnames) == max_mip_count):
|
|
|
- break;
|
|
|
+ width = width / 2
|
|
|
+ height = height / 2
|
|
|
|
|
|
- width = width / 2
|
|
|
- height = height / 2
|
|
|
+ return mips_fnames
|
|
|
|
|
|
- return mips_fnames
|
|
|
|
|
|
def create_etc_images(mips_fnames, tmp_dir, fast, color_format, convert_path):
|
|
|
- """ Create the etc files """
|
|
|
+ """ Create the etc files """
|
|
|
|
|
|
- printi("Creating ETC images")
|
|
|
+ printi("Creating ETC images")
|
|
|
|
|
|
- # Copy the convert tool to the working dir so that etcpack will see it
|
|
|
- shutil.copy2(convert_path, \
|
|
|
- os.path.join(tmp_dir, os.path.basename(convert_path)))
|
|
|
+ # Copy the convert tool to the working dir so that etcpack will see it
|
|
|
+ shutil.copy2(convert_path, \
|
|
|
+ os.path.join(tmp_dir, os.path.basename(convert_path)))
|
|
|
|
|
|
- for fname in mips_fnames:
|
|
|
- # Unfortunately we need to flip the image. Use convert again
|
|
|
- in_fname = fname + ".tga"
|
|
|
- flipped_fname = fname + "_flip.tga"
|
|
|
- args = ["convert", in_fname, "-flip", flipped_fname]
|
|
|
- subprocess.check_call(args)
|
|
|
- in_fname = flipped_fname
|
|
|
+ for fname in mips_fnames:
|
|
|
+ # Unfortunately we need to flip the image. Use convert again
|
|
|
+ in_fname = fname + ".tga"
|
|
|
+ flipped_fname = fname + "_flip.tga"
|
|
|
+ args = ["convert", in_fname, "-flip", flipped_fname]
|
|
|
+ subprocess.check_call(args)
|
|
|
+ in_fname = flipped_fname
|
|
|
|
|
|
- printi(" %s" % in_fname)
|
|
|
+ printi(" %s" % in_fname)
|
|
|
|
|
|
- args = ["etcpack", in_fname, tmp_dir, "-c", "etc2"]
|
|
|
+ args = ["etcpack", in_fname, tmp_dir, "-c", "etc2"]
|
|
|
|
|
|
- if fast:
|
|
|
- args.append("-s")
|
|
|
- args.append("fast")
|
|
|
+ if fast:
|
|
|
+ args.append("-s")
|
|
|
+ args.append("fast")
|
|
|
|
|
|
- args.append("-f")
|
|
|
- if color_format == CF_RGB8:
|
|
|
- args.append("RGB")
|
|
|
- else:
|
|
|
- args.append("RGBA")
|
|
|
+ args.append("-f")
|
|
|
+ if color_format == CF_RGB8:
|
|
|
+ args.append("RGB")
|
|
|
+ else:
|
|
|
+ args.append("RGBA")
|
|
|
|
|
|
- # Call the executable AND change the working directory so that etcpack will find convert
|
|
|
- subprocess.check_call(args, stdout = subprocess.PIPE, cwd = tmp_dir)
|
|
|
+ # Call the executable AND change the working directory so that etcpack will find convert
|
|
|
+ subprocess.check_call(args, stdout=subprocess.PIPE, cwd=tmp_dir)
|
|
|
|
|
|
-def create_dds_images(mips_fnames, tmp_dir, fast, color_format, normal):
|
|
|
- """ Create the dds files """
|
|
|
|
|
|
- printi("Creating DDS images")
|
|
|
+def create_dds_images(mips_fnames, tmp_dir, fast, color_format, normal):
|
|
|
+ """ Create the dds files """
|
|
|
|
|
|
- for fname in mips_fnames:
|
|
|
- # Unfortunately we need to flip the image. Use convert again
|
|
|
- in_fname = fname + ".tga"
|
|
|
- """
|
|
|
- flipped_fname = fname + "_flip.tga"
|
|
|
- args = ["convert", in_fname, "-flip", flipped_fname]
|
|
|
- subprocess.check_call(args)
|
|
|
- in_fname = flipped_fname
|
|
|
- """
|
|
|
+ printi("Creating DDS images")
|
|
|
|
|
|
- # Continue
|
|
|
- out_fname = os.path.join(tmp_dir, os.path.basename(fname) + ".dds")
|
|
|
+ for fname in mips_fnames:
|
|
|
+ # Unfortunately we need to flip the image. Use convert again
|
|
|
+ in_fname = fname + ".png"
|
|
|
+ """
|
|
|
+ flipped_fname = fname + "_flip.tga"
|
|
|
+ args = ["convert", in_fname, "-flip", flipped_fname]
|
|
|
+ subprocess.check_call(args)
|
|
|
+ in_fname = flipped_fname
|
|
|
+ """
|
|
|
|
|
|
- printi(" %s" % out_fname)
|
|
|
+ # Continue
|
|
|
+ out_fname = os.path.join(tmp_dir, os.path.basename(fname) + ".dds")
|
|
|
|
|
|
- args = ["nvcompress", "-silent", "-nomips"]
|
|
|
+ args = ["CompressonatorCLI", "-nomipmap"]
|
|
|
|
|
|
- if fast:
|
|
|
- args.append("-fast")
|
|
|
+ if color_format == CF_RGB8:
|
|
|
+ args.append("-fd")
|
|
|
+ args.append("BC1")
|
|
|
+ elif color_format == CF_RGBA8:
|
|
|
+ args.append("-fd")
|
|
|
+ args.append("BC3")
|
|
|
|
|
|
- if color_format == CF_RGB8:
|
|
|
- if not normal:
|
|
|
- args.append("-bc1")
|
|
|
- else:
|
|
|
- args.append("-bc1n")
|
|
|
- elif color_format == CF_RGBA8:
|
|
|
- args.append("-alpha")
|
|
|
- if not normal:
|
|
|
- args.append("-bc3")
|
|
|
- else:
|
|
|
- args.append("-bc3n")
|
|
|
+ args.append(in_fname)
|
|
|
+ args.append(out_fname)
|
|
|
|
|
|
- args.append(in_fname)
|
|
|
- args.append(out_fname)
|
|
|
+ printi(" " + " ".join(args))
|
|
|
+ subprocess.check_call(args, stdout=subprocess.PIPE)
|
|
|
|
|
|
- subprocess.check_call(args, stdout = subprocess.PIPE)
|
|
|
|
|
|
def write_raw(tex_file, fname, width, height, color_format):
|
|
|
- """ Append raw data to the AnKi texture file """
|
|
|
+ """ Append raw data to the AnKi texture file """
|
|
|
|
|
|
- printi(" Appending %s" % fname)
|
|
|
+ printi(" Appending %s" % fname)
|
|
|
|
|
|
- # Read and check the header
|
|
|
- uncompressed_tga_header = struct.pack("BBBBBBBBBBBB", 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
|
+ # Read and check the header
|
|
|
+ uncompressed_tga_header = struct.pack("BBBBBBBBBBBB", 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
|
|
|
|
- in_file = open(fname, "rb")
|
|
|
- tga_header = in_file.read(12)
|
|
|
+ in_file = open(fname, "rb")
|
|
|
+ tga_header = in_file.read(12)
|
|
|
|
|
|
- if len(tga_header) != 12:
|
|
|
- raise Exception("Failed reading TGA header")
|
|
|
+ if len(tga_header) != 12:
|
|
|
+ raise Exception("Failed reading TGA header")
|
|
|
|
|
|
- if uncompressed_tga_header != tga_header:
|
|
|
- raise Exception("Incorrect TGA header")
|
|
|
+ if uncompressed_tga_header != tga_header:
|
|
|
+ raise Exception("Incorrect TGA header")
|
|
|
|
|
|
- # Read the size and bpp
|
|
|
- header6_buff = in_file.read(6)
|
|
|
+ # Read the size and bpp
|
|
|
+ header6_buff = in_file.read(6)
|
|
|
|
|
|
- if len(header6_buff) != 6:
|
|
|
- raise Exception("Failed reading TGA header #2")
|
|
|
+ if len(header6_buff) != 6:
|
|
|
+ raise Exception("Failed reading TGA header #2")
|
|
|
|
|
|
- header6 = struct.unpack("BBBBBB", header6_buff)
|
|
|
+ header6 = struct.unpack("BBBBBB", header6_buff)
|
|
|
|
|
|
- img_width = header6[1] * 256 + header6[0]
|
|
|
- img_height = header6[3] * 256 + header6[2]
|
|
|
- img_bpp = header6[4];
|
|
|
+ img_width = header6[1] * 256 + header6[0]
|
|
|
+ img_height = header6[3] * 256 + header6[2]
|
|
|
+ img_bpp = header6[4]
|
|
|
|
|
|
- if (color_format != CF_RGB8 or img_bpp != 24) and (color_format != CF_RGBA8 or img_bpp != 32):
|
|
|
- raise Exception("Unexpected bpp")
|
|
|
+ if (color_format != CF_RGB8 or img_bpp != 24) and (color_format != CF_RGBA8 or img_bpp != 32):
|
|
|
+ raise Exception("Unexpected bpp")
|
|
|
|
|
|
- if img_width != width or img_height != height:
|
|
|
- raise Exception("Unexpected width or height")
|
|
|
+ if img_width != width or img_height != height:
|
|
|
+ raise Exception("Unexpected width or height")
|
|
|
|
|
|
- # Read the data
|
|
|
- data_size = width * height
|
|
|
- if color_format == CF_RGB8:
|
|
|
- data_size *= 3
|
|
|
- else:
|
|
|
- data_size *= 4
|
|
|
+ # Read the data
|
|
|
+ data_size = width * height
|
|
|
+ if color_format == CF_RGB8:
|
|
|
+ data_size *= 3
|
|
|
+ else:
|
|
|
+ data_size *= 4
|
|
|
|
|
|
- data = bytearray(in_file.read(data_size))
|
|
|
+ data = bytearray(in_file.read(data_size))
|
|
|
|
|
|
- if len(data) != data_size:
|
|
|
- raise Exception("Failed to read all data")
|
|
|
+ if len(data) != data_size:
|
|
|
+ raise Exception("Failed to read all data")
|
|
|
|
|
|
- tmp = in_file.read(128)
|
|
|
- if len(tmp) != 0:
|
|
|
- printw(" File shouldn't contain more data")
|
|
|
+ tmp = in_file.read(128)
|
|
|
+ if len(tmp) != 0:
|
|
|
+ printw(" File shouldn't contain more data")
|
|
|
|
|
|
- # Swap colors
|
|
|
- bpp = img_bpp / 8
|
|
|
- for i in xrange(0, data_size, bpp):
|
|
|
- temp = data[i];
|
|
|
- data[i] = data[i + 2];
|
|
|
- data[i + 2] = temp;
|
|
|
+ # Swap colors
|
|
|
+ bpp = img_bpp / 8
|
|
|
+ for i in xrange(0, data_size, bpp):
|
|
|
+ temp = data[i]
|
|
|
+ data[i] = data[i + 2]
|
|
|
+ data[i + 2] = temp
|
|
|
+
|
|
|
+ # Write data to tex_file
|
|
|
+ tex_file.write(data)
|
|
|
|
|
|
- # Write data to tex_file
|
|
|
- tex_file.write(data)
|
|
|
|
|
|
def write_s3tc(out_file, fname, width, height, color_format):
|
|
|
- """ Append s3tc data to the AnKi texture file """
|
|
|
+ """ Append s3tc data to the AnKi texture file """
|
|
|
+
|
|
|
+ # Read header
|
|
|
+ printi(" Appending %s" % fname)
|
|
|
+ in_file = open(fname, "rb")
|
|
|
|
|
|
- # Read header
|
|
|
- printi(" Appending %s" % fname)
|
|
|
- in_file = open(fname, "rb")
|
|
|
+ header = in_file.read(DdsHeader.get_size())
|
|
|
|
|
|
- header = in_file.read(DdsHeader.get_size())
|
|
|
+ if len(header) != DdsHeader.get_size():
|
|
|
+ raise Exception("Failed to read DDS header")
|
|
|
|
|
|
- if len(header) != DdsHeader.get_size():
|
|
|
- raise Exception("Failed to read DDS header")
|
|
|
+ dds_header = DdsHeader(header)
|
|
|
|
|
|
- dds_header = DdsHeader(header)
|
|
|
+ if dds_header.dwWidth != width or dds_header.dwHeight != height:
|
|
|
+ raise Exception("Incorrect width")
|
|
|
|
|
|
- if dds_header.dwWidth != width or dds_header.dwHeight != height:
|
|
|
- raise Exception("Incorrect width")
|
|
|
+ if color_format == CF_RGB8 and dds_header.dwFourCC != "DXT1":
|
|
|
+ raise Exception("Incorrect format. Expecting DXT1")
|
|
|
|
|
|
- if color_format == CF_RGB8 and dds_header.dwFourCC != "DXT1":
|
|
|
- raise Exception("Incorrect format. Expecting DXT1")
|
|
|
+ if color_format == CF_RGBA8 and dds_header.dwFourCC != "DXT5":
|
|
|
+ raise Exception("Incorrect format. Expecting DXT5")
|
|
|
|
|
|
- if color_format == CF_RGBA8 and dds_header.dwFourCC != "DXT5":
|
|
|
- raise Exception("Incorrect format. Expecting DXT5")
|
|
|
+ # Read and write the data
|
|
|
+ if color_format == CF_RGB8:
|
|
|
+ block_size = 8
|
|
|
+ else:
|
|
|
+ block_size = 16
|
|
|
|
|
|
- # Read and write the data
|
|
|
- if color_format == CF_RGB8:
|
|
|
- block_size = 8
|
|
|
- else:
|
|
|
- block_size = 16
|
|
|
+ data_size = (width / 4) * (height / 4) * block_size
|
|
|
|
|
|
- data_size = (width / 4) * (height / 4) * block_size
|
|
|
+ data = in_file.read(data_size)
|
|
|
|
|
|
- data = in_file.read(data_size)
|
|
|
+ if len(data) != data_size:
|
|
|
+ raise Exception("Failed to read DDS data")
|
|
|
|
|
|
- if len(data) != data_size:
|
|
|
- raise Exception("Failed to read DDS data")
|
|
|
+ # Make sure that the file doesn't contain any more data
|
|
|
+ tmp = in_file.read(1)
|
|
|
+ if len(tmp) != 0:
|
|
|
+ printw(" File shouldn't contain more data")
|
|
|
|
|
|
- # Make sure that the file doesn't contain any more data
|
|
|
- tmp = in_file.read(1)
|
|
|
- if len(tmp) != 0:
|
|
|
- printw(" File shouldn't contain more data")
|
|
|
+ out_file.write(data)
|
|
|
|
|
|
- out_file.write(data)
|
|
|
|
|
|
def write_etc(out_file, fname, width, height, color_format):
|
|
|
- """ Append etc2 data to the AnKi texture file """
|
|
|
+ """ Append etc2 data to the AnKi texture file """
|
|
|
+
|
|
|
+ printi(" Appending %s" % fname)
|
|
|
|
|
|
- printi(" Appending %s" % fname)
|
|
|
+ # Read header
|
|
|
+ in_file = open(fname, "rb")
|
|
|
|
|
|
- # Read header
|
|
|
- in_file = open(fname, "rb")
|
|
|
+ header = in_file.read(PkmHeader.get_size())
|
|
|
|
|
|
- header = in_file.read(PkmHeader.get_size())
|
|
|
+ if len(header) != PkmHeader.get_size():
|
|
|
+ raise Exception("Failed to read PKM header")
|
|
|
|
|
|
- if len(header) != PkmHeader.get_size():
|
|
|
- raise Exception("Failed to read PKM header")
|
|
|
+ pkm_header = PkmHeader(header)
|
|
|
|
|
|
- pkm_header = PkmHeader(header)
|
|
|
+ if pkm_header.magic != "PKM 20":
|
|
|
+ raise Exception("Incorrect PKM header")
|
|
|
|
|
|
- if pkm_header.magic != "PKM 20":
|
|
|
- raise Exception("Incorrect PKM header")
|
|
|
+ if width != pkm_header.width or height != pkm_header.height:
|
|
|
+ raise Exception("Incorrect PKM width or height")
|
|
|
|
|
|
- if width != pkm_header.width or height != pkm_header.height:
|
|
|
- raise Exception("Incorrect PKM width or height")
|
|
|
+ # Read and write the data
|
|
|
+ data_size = (pkm_header.width / 4) * (pkm_header.height / 4) * 8
|
|
|
|
|
|
- # Read and write the data
|
|
|
- data_size = (pkm_header.width / 4) * (pkm_header.height / 4) * 8
|
|
|
+ data = in_file.read(data_size)
|
|
|
|
|
|
- data = in_file.read(data_size)
|
|
|
+ if len(data) != data_size:
|
|
|
+ raise Exception("Failed to read PKM data")
|
|
|
|
|
|
- if len(data) != data_size:
|
|
|
- raise Exception("Failed to read PKM data")
|
|
|
+ # Make sure that the file doesn't contain any more data
|
|
|
+ tmp = in_file.read(1)
|
|
|
+ if len(tmp) != 0:
|
|
|
+ printw(" File shouldn't contain more data")
|
|
|
|
|
|
- # Make sure that the file doesn't contain any more data
|
|
|
- tmp = in_file.read(1)
|
|
|
- if len(tmp) != 0:
|
|
|
- printw(" File shouldn't contain more data")
|
|
|
+ out_file.write(data)
|
|
|
|
|
|
- out_file.write(data)
|
|
|
|
|
|
def convert(config):
|
|
|
- """ This is the function that does all the work """
|
|
|
+ """ This is the function that does all the work """
|
|
|
|
|
|
- # Invoke app named "identify" to get internal format and width and height
|
|
|
- (color_format, width, height) = identify_image(config.in_files[0])
|
|
|
+ # Invoke app named "identify" to get internal format and width and height
|
|
|
+ (color_format, width, height) = identify_image(config.in_files[0])
|
|
|
|
|
|
- if not is_power2(width) or not is_power2(height):
|
|
|
- raise Exception("Image width and height should power of 2")
|
|
|
+ if not is_power2(width) or not is_power2(height):
|
|
|
+ raise Exception("Image width and height should power of 2")
|
|
|
|
|
|
- if color_format == CF_RGBA8 and config.normal:
|
|
|
- raise Exception("RGBA image and normal does not make much sense")
|
|
|
+ if color_format == CF_RGBA8 and config.normal:
|
|
|
+ raise Exception("RGBA image and normal does not make much sense")
|
|
|
|
|
|
- for i in range(1, len(config.in_files)):
|
|
|
- (color_format_2, width_2, height_2) = identify_image(config.in_files[i])
|
|
|
+ for i in range(1, len(config.in_files)):
|
|
|
+ (color_format_2, width_2, height_2) = identify_image(config.in_files[i])
|
|
|
|
|
|
- if width != width_2 or height != height_2 \
|
|
|
- or color_format != color_format_2:
|
|
|
- raise Exception("Images are not same size and color space")
|
|
|
+ if width != width_2 or height != height_2 \
|
|
|
+ or color_format != color_format_2:
|
|
|
+ raise Exception("Images are not same size and color space")
|
|
|
|
|
|
- if config.no_alpha:
|
|
|
- color_format = CF_RGB8
|
|
|
+ if config.no_alpha:
|
|
|
+ color_format = CF_RGB8
|
|
|
|
|
|
- # Create images
|
|
|
- for in_file in config.in_files:
|
|
|
- mips_fnames = create_mipmaps(in_file, config.tmp_dir, width, height, color_format, config.to_linear_rgb,
|
|
|
- config.mips_count)
|
|
|
+ # Create images
|
|
|
+ for in_file in config.in_files:
|
|
|
+ mips_fnames = create_mipmaps(in_file, config.tmp_dir, width, height, color_format, config.to_linear_rgb,
|
|
|
+ config.mips_count)
|
|
|
|
|
|
- # Create etc images
|
|
|
- if config.compressed_formats & DC_ETC2:
|
|
|
- create_etc_images(mips_fnames, config.tmp_dir, config.fast, color_format, config.convert_path)
|
|
|
+ # Create etc images
|
|
|
+ if config.compressed_formats & DC_ETC2:
|
|
|
+ create_etc_images(mips_fnames, config.tmp_dir, config.fast, color_format, config.convert_path)
|
|
|
|
|
|
- # Create dds images
|
|
|
- if config.compressed_formats & DC_S3TC:
|
|
|
- create_dds_images(mips_fnames, config.tmp_dir, config.fast, color_format, config.normal)
|
|
|
+ # Create dds images
|
|
|
+ if config.compressed_formats & DC_S3TC:
|
|
|
+ create_dds_images(mips_fnames, config.tmp_dir, config.fast, color_format, config.normal)
|
|
|
|
|
|
- # Open file
|
|
|
- fname = config.out_file
|
|
|
- printi("Writing %s" % fname)
|
|
|
- tex_file = open(fname, "wb")
|
|
|
+ # Open file
|
|
|
+ fname = config.out_file
|
|
|
+ printi("Writing %s" % fname)
|
|
|
+ tex_file = open(fname, "wb")
|
|
|
|
|
|
- # Write header
|
|
|
- ak_format = "8sIIIIIIII"
|
|
|
+ # Write header
|
|
|
+ ak_format = "8sIIIIIIII"
|
|
|
|
|
|
- data_compression = config.compressed_formats
|
|
|
+ data_compression = config.compressed_formats
|
|
|
|
|
|
- if config.store_uncompressed:
|
|
|
- data_compression = data_compression | DC_RAW
|
|
|
+ if config.store_uncompressed:
|
|
|
+ data_compression = data_compression | DC_RAW
|
|
|
|
|
|
- buff = struct.pack(ak_format,
|
|
|
- b"ANKITEX1",
|
|
|
- width,
|
|
|
- height,
|
|
|
- len(config.in_files),
|
|
|
- config.type,
|
|
|
- color_format,
|
|
|
- data_compression,
|
|
|
- config.normal,
|
|
|
- len(mips_fnames))
|
|
|
+ buff = struct.pack(ak_format, b"ANKITEX1", width, height, len(config.in_files), config.type, color_format,
|
|
|
+ data_compression, config.normal, len(mips_fnames))
|
|
|
|
|
|
- tex_file.write(buff)
|
|
|
+ tex_file.write(buff)
|
|
|
|
|
|
- # Write header padding
|
|
|
- header_padding_size = 128 - struct.calcsize(ak_format)
|
|
|
+ # Write header padding
|
|
|
+ header_padding_size = 128 - struct.calcsize(ak_format)
|
|
|
|
|
|
- if header_padding_size != 88:
|
|
|
- raise Exception("Check the header")
|
|
|
+ if header_padding_size != 88:
|
|
|
+ raise Exception("Check the header")
|
|
|
|
|
|
- for i in range(0, header_padding_size):
|
|
|
- tex_file.write('\0')
|
|
|
+ for i in range(0, header_padding_size):
|
|
|
+ tex_file.write('\0')
|
|
|
|
|
|
- # For each compression
|
|
|
- for compression in range(0, 3):
|
|
|
+ # For each compression
|
|
|
+ for compression in range(0, 3):
|
|
|
|
|
|
- tmp_width = width
|
|
|
- tmp_height = height
|
|
|
+ tmp_width = width
|
|
|
+ tmp_height = height
|
|
|
|
|
|
- # For each level
|
|
|
- for i in range(0, len(mips_fnames)):
|
|
|
+ # For each level
|
|
|
+ for i in range(0, len(mips_fnames)):
|
|
|
|
|
|
- # For each image
|
|
|
- for in_file in config.in_files:
|
|
|
- size_str = "%dx%d" % (tmp_width, tmp_height)
|
|
|
- in_base_fname = os.path.join(config.tmp_dir, get_base_fname(in_file)) + "." + size_str
|
|
|
+ # For each image
|
|
|
+ for in_file in config.in_files:
|
|
|
+ size_str = "%dx%d" % (tmp_width, tmp_height)
|
|
|
+ in_base_fname = os.path.join(config.tmp_dir, get_base_fname(in_file)) + "." + size_str
|
|
|
|
|
|
- # Write RAW
|
|
|
- if compression == 0 and config.store_uncompressed:
|
|
|
- write_raw(tex_file, in_base_fname + ".tga", tmp_width, tmp_height, color_format)
|
|
|
- # Write S3TC
|
|
|
- elif compression == 1 and (config.compressed_formats & DC_S3TC):
|
|
|
- write_s3tc(tex_file, in_base_fname + ".dds", tmp_width, tmp_height, color_format)
|
|
|
- # Write ETC
|
|
|
- elif compression == 2 and (config.compressed_formats & DC_ETC2):
|
|
|
- write_etc(tex_file, in_base_fname + "_flip.pkm", tmp_width, tmp_height, color_format)
|
|
|
+ # Write RAW
|
|
|
+ if compression == 0 and config.store_uncompressed:
|
|
|
+ write_raw(tex_file, in_base_fname + ".tga", tmp_width, tmp_height, color_format)
|
|
|
+ # Write S3TC
|
|
|
+ elif compression == 1 and (config.compressed_formats & DC_S3TC):
|
|
|
+ write_s3tc(tex_file, in_base_fname + ".dds", tmp_width, tmp_height, color_format)
|
|
|
+ # Write ETC
|
|
|
+ elif compression == 2 and (config.compressed_formats & DC_ETC2):
|
|
|
+ write_etc(tex_file, in_base_fname + "_flip.pkm", tmp_width, tmp_height, color_format)
|
|
|
+
|
|
|
+ tmp_width = tmp_width / 2
|
|
|
+ tmp_height = tmp_height / 2
|
|
|
|
|
|
- tmp_width = tmp_width / 2
|
|
|
- tmp_height = tmp_height / 2
|
|
|
|
|
|
def main():
|
|
|
- """ The main """
|
|
|
+ """ The main """
|
|
|
+
|
|
|
+ # Parse cmd line args
|
|
|
+ config = parse_commandline()
|
|
|
|
|
|
- # Parse cmd line args
|
|
|
- config = parse_commandline();
|
|
|
+ if config.type == TT_CUBE and len(config.in_files) != 6:
|
|
|
+ raise Exception("Not enough images for cube generation")
|
|
|
|
|
|
- if config.type == TT_CUBE and len(config.in_files) != 6:
|
|
|
- raise Exception("Not enough images for cube generation")
|
|
|
+ if (config.type == TT_3D or config.type == TT_2D_ARRAY) and len(config.in_files) < 2:
|
|
|
+ #raise Exception("Not enough images for 2DArray/3D texture")
|
|
|
+ printw("Not enough images for 2DArray/3D texture")
|
|
|
+ printi("Number of images %u" % len(config.in_files))
|
|
|
|
|
|
- if (config.type == TT_3D or config.type == TT_2D_ARRAY) and len(config.in_files) < 2:
|
|
|
- #raise Exception("Not enough images for 2DArray/3D texture")
|
|
|
- printw("Not enough images for 2DArray/3D texture")
|
|
|
- printi("Number of images %u" % len(config.in_files))
|
|
|
+ if config.type == TT_2D and len(config.in_files) != 1:
|
|
|
+ raise Exception("Only one image for 2D textures needed")
|
|
|
|
|
|
- if config.type == TT_2D and len(config.in_files) != 1:
|
|
|
- raise Exception("Only one image for 2D textures needed")
|
|
|
+ if not os.path.isfile(config.convert_path):
|
|
|
+ raise Exception("Tool convert not found: " + config.convert_path)
|
|
|
|
|
|
- if not os.path.isfile(config.convert_path):
|
|
|
- raise Exception("Tool convert not found: " + config.convert_path)
|
|
|
+ # Setup the temp dir
|
|
|
+ config.tmp_dir = tempfile.mkdtemp("_ankitex")
|
|
|
|
|
|
- # Setup the temp dir
|
|
|
- config.tmp_dir = tempfile.mkdtemp("_ankitex")
|
|
|
+ # Do the work
|
|
|
+ try:
|
|
|
+ convert(config)
|
|
|
+ finally:
|
|
|
+ #shutil.rmtree(config.tmp_dir)
|
|
|
+ i = 0
|
|
|
|
|
|
- # Do the work
|
|
|
- try:
|
|
|
- convert(config)
|
|
|
- finally:
|
|
|
- shutil.rmtree(config.tmp_dir)
|
|
|
+ # Done
|
|
|
+ printi("Done!")
|
|
|
|
|
|
- # Done
|
|
|
- printi("Done!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
- main()
|
|
|
+ main()
|