Source code for scfile.formats.dds.encoder
from scfile.consts import FileSignature
from scfile.core import FileEncoder, TextureContent
from scfile.enums import ByteOrder, F, FileFormat
from scfile.formats.dds.enums import DXGIDimension, DXGIFormat
from scfile.structures.textures import TextureType
from .enums import BGRA8, RGBA8
from .header import DDS
[docs]
class DdsEncoder(FileEncoder[TextureContent[TextureType]]):
format = FileFormat.DDS
signature = FileSignature.DDS
order = ByteOrder.LITTLE
[docs]
def serialize(self):
self._add_header()
self._add_pixelformat()
self._add_caps()
if self.data.fourcc == b"DX10":
self._add_dxgi()
self.write(self.data.texture.image)
def _add_header(self):
self._writeb(
f"{7}{F.U32}",
DDS.HEADER.SIZE, # dwSize
self._flags, # dwFlags
self.data.height, # dwHeight
self.data.width, # dwWidth
self._pitch_or_linear_size, # dwPitchOrLinearSize
0, # dwDepth
self.data.mipmap_count, # dwMipMapCount
)
self._writenull(size=4 * 11) # dwReserved1[11]
def _add_pixelformat(self):
self._writeb(F.U32, DDS.PF.SIZE) # dwSize
if self.data.is_compressed:
self._add_pf_fourcc()
else:
self._add_pf_rgb()
def _add_pf_fourcc(self):
self._writeb(F.U32, DDS.PF.FLAG.FOURCC) # dwFlags
self.write(self.data.fourcc) # dwFourCC
self._writenull(size=4 * 5) # dwRGBBitCount, RGBA bit masks (unused)
def _add_pf_rgb(self):
self._writeb(F.U32, DDS.PF.RGB) # dwFlags
self._writenull(size=4) # dwFourCC (unused)
self._writeb(F.U32, DDS.PF.BIT_COUNT) # dwRGBBitCount
bitmask = BGRA8 if self.data.fourcc == b"BGRA8" else RGBA8
self._writeb(F.U32 * 4, *bitmask) # RGBA bit masks
def _add_caps(self):
self._writeb(
f"{2}{F.U32}",
DDS.CAPS1, # dwCaps1
self._caps2, # dwCaps2
)
self._writenull(size=4 * 3) # dwCaps3, dwCaps4, Reserved
def _add_dxgi(self):
self._writeb(
f"{5}{F.U32}",
DXGIFormat.FLOAT_R32G32B32A32, # dxgiFormat
DXGIDimension.TEXTURE2D, # resourceDimension
0, # miscFlag
1, # arraySize
0, # miscFlags2
)
@property
def _flags(self) -> int:
if self.data.is_compressed:
return DDS.HEADER.FLAGS | DDS.HEADER.FLAG.LINEARSIZE
return DDS.HEADER.FLAGS | DDS.HEADER.FLAG.PITCH
@property
def _pitch(self) -> int:
bytes_per_pixel = 4
aligned_width = (self.data.width * bytes_per_pixel + 3) & ~3
return aligned_width
@property
def _pitch_or_linear_size(self) -> int:
if self.data.is_compressed:
return self.data.texture.linear_size
return self._pitch
@property
def _caps2(self) -> int:
if self.data.is_cubemap:
return DDS.CUBEMAPS
return 0