File size: 10,371 Bytes
41f85e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# 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))