Extremely bad hardcoded DDS file reading

hotfix/mipmap-alpha-fix
Andrew Cassidy 3 years ago
parent dae82c0662
commit 5f13b841ad

@ -230,7 +230,8 @@ class DDSFile:
self.header: DDSHeader = DDSHeader()
"""The DDS file's header object"""
self.textures = []
self.textures: typing.List[bytes] = []
"""A list of bytes objects for each texture in the file"""
@staticmethod
def from_file(file: typing.BinaryIO) -> DDSFile:
@ -246,7 +247,18 @@ class DDSFile:
dds = DDSFile()
dds.header = DDSHeader.from_file(file)
# TODO: read file contents
four_cc = dds.header.pixel_format.four_cc
assert four_cc == 'DXT1' or four_cc == 'DXT5'
block_size = 8 if four_cc == 'DXT1' else 16
mip_count = dds.header.mipmap_count if DDSHeader.Flags.MIPMAPCOUNT in dds.header.flags else 1
dds.textures = []
for mip in range(mip_count):
block_dimensions = dds.image_block_dimensions()
blocks = block_dimensions[0] * block_dimensions[1]
size = blocks * block_size
dds.textures.append(file.read(size))
return dds
@ -261,4 +273,40 @@ class DDSFile:
file.write(DDSFile.magic)
file.write(self.header.to_bytes())
# TODO: write file contents
for texture in self.textures:
file.write(texture)
def mipmap_count(self) -> int:
"""
Get the number of mipmaps in the dds file.
:return: The number of mipmaps
"""
if DDSHeader.Flags.MIPMAPCOUNT in self.header.flags:
mips = self.header.mipmap_count
assert mips > 0
return mips
else:
return 1
def image_dimensions(self, mip: int = 0) -> typing.Tuple[int, int]:
"""
Calculate the dimensions of a mip level in pixels.
:param int mip: which mip level to calculate the dimensions of, between 0 and :py:attr:`~DDSHeader.mipmap_count` exclusive.
:return: the dimensions of the selected mipmap in pixels
"""
assert self.mipmap_count() > mip >= 0, "Invalid mip level"
return tuple([max(size // (2 ** mip), 1) for size in self.header.dimensions])
def image_block_dimensions(self, mip: int = 0) -> typing.Tuple[int, int]:
"""
Calculate the dimensions of a mip level in 4x4 blocks. Only relevent for compressed textures.
:param int mip: Whick mip level to calculate the dimensions of, between 0 and :py:attr:`~DDSHeader.mipmap_count` exclusive.
:return: the dimensions of the selected mipmap in blocks
"""
dimensions = self.image_dimensions(mip)
assert all(size > 0 for size in dimensions)
return tuple([max((size + 3) // 4, 1) for size in dimensions])

Loading…
Cancel
Save