Files
2026-06-14 19:09:18 +01:00

213 lines
10 KiB
Python

# Copyright (c) 2023, Shukant Pal and Contributors
# SPDX-License-Identifier: Apache-2.0
from .ktx_astc_params import KtxAstcParams
from .ktx_basis_params import KtxBasisParams
from .ktx_error_code import KtxErrorCode, KtxError
from .ktx_supercmp_scheme import KtxSupercmpScheme
from .ktx_texture import KtxTexture, KtxVersionMismatchError
from .ktx_texture_create_flag_bits import KtxTextureCreateFlagBits
from .ktx_texture_create_info import KtxTextureCreateInfo
from .ktx_texture_create_storage import KtxTextureCreateStorage
from .ktx_transcode_fmt import KtxTranscodeFmt
from pyktx.native import ffi, lib
from typing import Union
from .vk_format import VkFormat
class KtxTexture2(KtxTexture):
"""Class representing a KTX version 2 format texture."""
@staticmethod
def create(create_info: KtxTextureCreateInfo, storage_allocation: KtxTextureCreateStorage) -> 'KtxTexture2':
"""Create a new empty KtxTexture2."""
result = lib.PY_ktxTexture2_Create(0,
create_info.vk_format.value,
ffi.NULL,
create_info.base_width,
create_info.base_height,
create_info.base_depth,
create_info.num_dimensions,
create_info.num_levels,
create_info.num_layers,
create_info.num_faces,
create_info.is_array,
create_info.generate_mipmaps,
storage_allocation.value)
if int(result.error) != KtxErrorCode.SUCCESS:
raise KtxError('ktxTexture2_Create', KtxErrorCode(result.error))
return KtxTexture2(result.texture)
@staticmethod
def create_from_named_file(filename: str,
create_flags: int = KtxTextureCreateFlagBits.LOAD_IMAGE_DATA_BIT) -> 'KtxTexture2':
"""Create a KtxTexture2 from a named KTX file."""
result = lib.PY_ktxTexture_CreateFromNamedFile(filename.encode("ascii"), int(create_flags))
if int(result.error) != KtxErrorCode.SUCCESS:
raise KtxError('ktxTexture2_CreateFromNamedFile', KtxErrorCode(result.error))
texture = KtxTexture2(result.texture)
if texture.class_id != 2:
raise KtxVersionMismatchError('The provided file ' + filename + ' is not a KTX2 file')
return texture
@property
def vk_format(self) -> VkFormat:
"""VkFormat for texture."""
return VkFormat(lib.PY_ktxTexture2_get_vkFormat(self._ptr))
@property
def supercompression_scheme(self) -> KtxSupercmpScheme:
"""The supercompression scheme used to compress the texture data."""
return KtxSupercmpScheme(lib.PY_ktxTexture2_get_supercompressionScheme(self._ptr))
@property
def oetf(self) -> int:
"""The opto-electrical transfer function of the images."""
return lib.ktxTexture2_GetOETF(self._ptr)
@property
def premultipled_alpha(self) -> bool:
"""Whether the RGB components have been premultiplied by the alpha component."""
return lib.ktxTexture2_GetPremultipliedAlpha(self._ptr)
@property
def needs_transcoding(self) -> bool:
"""If the images are in a transcodable format."""
return lib.ktxTexture2_NeedsTranscoding(self._ptr)
def compress_astc(self, params: Union[int, KtxAstcParams]) -> None:
"""
Encode and compress a ktx texture with uncompressed images to ASTC.
The images are either encoded to ASTC block-compressed format. The
encoded images replace the original images and the texture's fields
including the dfd are modified to reflect the new state.
Such textures can be directly uploaded to a GPU via a graphics API.
"""
if isinstance(params, int):
quality = params
params = KtxAstcParams()
params.quality_level = quality
error = lib.PY_ktxTexture2_CompressAstcEx(self._ptr,
params.verbose,
params.thread_count,
int(params.block_dimension),
int(params.mode),
params.quality_level,
params.normal_map,
params.perceptual,
params.input_swizzle)
if int(error) != KtxErrorCode.SUCCESS:
raise KtxError('ktxTexture2_compressAstcEx', KtxErrorCode(error))
def compress_basis(self, params: Union[int, KtxBasisParams]) -> None:
"""
Supercompress a KTX2 texture with uncompressed images.
The images are either encoded to ETC1S block-compressed format and supercompressed
with Basis LZ or they are encoded to UASTC block-compressed format. UASTC format is
selected by setting the uastc field of params to true. The encoded images replace
the original images and the texture's fields including the DFD are modified to reflect
the new state. Such textures must be transcoded to a desired target block compressed
format before they can be uploaded to a GPU via a graphics API.
"""
if isinstance(params, int):
quality = params
params = KtxBasisParams()
params.quality_level = quality
error = lib.PY_ktxTexture2_CompressBasisEx(self._ptr,
params.uastc,
params.verbose,
params.no_sse,
params.thread_count,
params.compression_level,
params.quality_level,
params.max_endpoints,
params.endpoint_rdo_threshold,
params.max_selectors,
params.selector_rdo_threshold,
params.input_swizzle,
params.normal_map,
params.pre_swizzle,
params.separate_rg_to_rgb_a,
params.no_endpoint_rdo,
params.no_selector_rdo,
params.uastc_flags,
params.uastc_rdo,
params.uastc_rdo_quality_scalar,
params.uastc_rdo_dict_size,
params.uastc_rdo_max_smooth_block_error_scale,
params.uastc_rdo_max_smooth_block_std_dev,
params.uastc_rdo_dont_favor_simpler_modes,
params.uastc_rdo_no_multithreading)
if int(error) != KtxErrorCode.SUCCESS:
raise KtxError('ktxTexture2_CompressBasisEx', KtxErrorCode(error))
def deflate_zstd(self, compression_level: int) -> None:
"""
Deflate the data in a ktxTexture2 object using Zstandard.
The texture's level_index, data_size, dfd and supercompression_scheme will all
be updated after successful deflation to reflect the deflated data.
"""
if not 1 <= compression_level <= 22:
raise ValueError("compression_level must be between 1 and 22")
error = lib.ktxTexture2_DeflateZstd(self._ptr, compression_level)
if int(error) != KtxErrorCode.SUCCESS:
raise KtxError('ktx2_DeflateZstd', KtxErrorCode(error))
def transcode_basis(self, output_format: KtxTranscodeFmt, transcode_flags: int = 0) -> None:
"""
Transcode a KTX2 texture with BasisLZ/ETC1S or UASTC images.
If the texture contains BasisLZ supercompressed images, inflates them from back to
ETC1S then transcodes them to the specified block-compressed format. If the texture
contains UASTC images, inflates them, if they have been supercompressed with zstd, then
transcodes then to the specified format, The transcoded images replace the original images
and the texture's fields including the dfd are modified to reflect the new format.
These types of textures must be transcoded to a desired target block-compressed format
before they can be uploaded to a GPU via a graphics API.
The following block compressed transcode targets (KtxTranscodeFmt) are available: ETC1_RGB,
ETC2_RGBA, BC1_RGB, BC3_RGBA, BC4_R, BC5_RG, BC7_RGBA, PVRTC1_4_RGB, PVRTC1_4_RGBA,
PVRTC2_4_RGB, PVRTC2_4_RGBA, ASTC_4x4_RGBA, ETC2_EAC_R11, ETC2_EAC_RG11, ETC and BC1_OR_3.
ETC automatically selects between ETC1_RGB and ETC2_RGBA according to whether an alpha
channel is available. BC1_OR_3 does likewise between BC1_RGB and BC3_RGBA. Note that if
PVRTC1_4_RGBA or PVRTC2_4_RGBA is specified and there is no alpha channel PVRTC1_4_RGB
or PVRTC2_4_RGB respectively will be selected.
Transcoding to ATC & FXT1 formats is not supported by libktx as there are no equivalent Vulkan formats.
The following uncompressed transcode targets are also available: RGBA32, RGB565, BGR565 and RGBA4444.
"""
error = lib.ktxTexture2_TranscodeBasis(self._ptr, output_format, transcode_flags)
if int(error) != KtxErrorCode.SUCCESS:
raise KtxError('ktx2_TranscodeBasis', KtxErrorCode(error))