1 # SPDX-FileCopyrightText: 2018-2021 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
7 from ...io
.com
.gltf2_io
import BufferView
8 from ...io
.imp
.gltf2_io_binary
import BinaryData
9 from ...io
.com
.gltf2_io_draco_compression_extension
import dll_path
12 def decode_primitive(gltf
, prim
):
14 Handles draco compression.
15 Moves decoded data into new buffers and buffer views held by the accessors of the given primitive.
18 # Load DLL and setup function signatures.
19 dll
= cdll
.LoadLibrary(str(dll_path().resolve()))
21 dll
.decoderCreate
.restype
= c_void_p
22 dll
.decoderCreate
.argtypes
= []
24 dll
.decoderRelease
.restype
= None
25 dll
.decoderRelease
.argtypes
= [c_void_p
]
27 dll
.decoderDecode
.restype
= c_bool
28 dll
.decoderDecode
.argtypes
= [c_void_p
, c_void_p
, c_size_t
]
30 dll
.decoderReadAttribute
.restype
= c_bool
31 dll
.decoderReadAttribute
.argtypes
= [c_void_p
, c_uint32
, c_size_t
, c_char_p
]
33 dll
.decoderGetVertexCount
.restype
= c_uint32
34 dll
.decoderGetVertexCount
.argtypes
= [c_void_p
]
36 dll
.decoderGetIndexCount
.restype
= c_uint32
37 dll
.decoderGetIndexCount
.argtypes
= [c_void_p
]
39 dll
.decoderAttributeIsNormalized
.restype
= c_bool
40 dll
.decoderAttributeIsNormalized
.argtypes
= [c_void_p
, c_uint32
]
42 dll
.decoderGetAttributeByteLength
.restype
= c_size_t
43 dll
.decoderGetAttributeByteLength
.argtypes
= [c_void_p
, c_uint32
]
45 dll
.decoderCopyAttribute
.restype
= None
46 dll
.decoderCopyAttribute
.argtypes
= [c_void_p
, c_uint32
, c_void_p
]
48 dll
.decoderReadIndices
.restype
= c_bool
49 dll
.decoderReadIndices
.argtypes
= [c_void_p
, c_size_t
]
51 dll
.decoderGetIndicesByteLength
.restype
= c_size_t
52 dll
.decoderGetIndicesByteLength
.argtypes
= [c_void_p
]
54 dll
.decoderCopyIndices
.restype
= None
55 dll
.decoderCopyIndices
.argtypes
= [c_void_p
, c_void_p
]
57 decoder
= dll
.decoderCreate()
58 extension
= prim
.extensions
['KHR_draco_mesh_compression']
60 name
= prim
.name
if hasattr(prim
, 'name') else '[unnamed]'
62 # Create Draco decoder.
63 draco_buffer
= bytes(BinaryData
.get_buffer_view(gltf
, extension
['bufferView']))
64 if not dll
.decoderDecode(decoder
, draco_buffer
, len(draco_buffer
)):
65 gltf
.log
.error('Draco Decoder: Unable to decode. Skipping primitive {}.'.format(name
))
68 # Choose a buffer index which does not yet exist, skipping over existing glTF buffers yet to be loaded
69 # and buffers which were generated and did not exist in the initial glTF file, like this decoder does.
70 base_buffer_idx
= len(gltf
.data
.buffers
)
71 for existing_buffer_idx
in gltf
.buffers
:
72 if base_buffer_idx
<= existing_buffer_idx
:
73 base_buffer_idx
= existing_buffer_idx
+ 1
76 index_accessor
= gltf
.data
.accessors
[prim
.indices
]
77 if dll
.decoderGetIndexCount(decoder
) != index_accessor
.count
:
78 gltf
.log
.warning('Draco Decoder: Index count of accessor and decoded index count does not match. Updating accessor.')
79 index_accessor
.count
= dll
.decoderGetIndexCount(decoder
)
80 if not dll
.decoderReadIndices(decoder
, index_accessor
.component_type
):
81 gltf
.log
.error('Draco Decoder: Unable to decode indices. Skipping primitive {}.'.format(name
))
84 indices_byte_length
= dll
.decoderGetIndicesByteLength(decoder
)
85 decoded_data
= bytes(indices_byte_length
)
86 dll
.decoderCopyIndices(decoder
, decoded_data
)
88 # Generate a new buffer holding the decoded indices.
89 gltf
.buffers
[base_buffer_idx
] = decoded_data
91 # Create a buffer view referencing the new buffer.
92 gltf
.data
.buffer_views
.append(BufferView
.from_dict({
93 'buffer': base_buffer_idx
,
94 'byteLength': indices_byte_length
97 # Update accessor to point to the new buffer view.
98 index_accessor
.buffer_view
= len(gltf
.data
.buffer_views
) - 1
100 # Read each attribute.
101 for attr_idx
, attr
in enumerate(extension
['attributes']):
102 dracoId
= extension
['attributes'][attr
]
103 if attr
not in prim
.attributes
:
104 gltf
.log
.error('Draco Decoder: Draco attribute {} not in primitive attributes. Skipping primitive {}.'.format(attr
, name
))
107 accessor
= gltf
.data
.accessors
[prim
.attributes
[attr
]]
108 if dll
.decoderGetVertexCount(decoder
) != accessor
.count
:
109 gltf
.log
.warning('Draco Decoder: Vertex count of accessor and decoded vertex count does not match for attribute {}. Updating accessor.'.format(attr
, name
))
110 accessor
.count
= dll
.decoderGetVertexCount(decoder
)
111 if not dll
.decoderReadAttribute(decoder
, dracoId
, accessor
.component_type
, accessor
.type.encode()):
112 gltf
.log
.error('Draco Decoder: Could not decode attribute {}. Skipping primitive {}.'.format(attr
, name
))
115 byte_length
= dll
.decoderGetAttributeByteLength(decoder
, dracoId
)
116 decoded_data
= bytes(byte_length
)
117 dll
.decoderCopyAttribute(decoder
, dracoId
, decoded_data
)
119 # Generate a new buffer holding the decoded vertex data.
120 buffer_idx
= base_buffer_idx
+ 1 + attr_idx
121 gltf
.buffers
[buffer_idx
] = decoded_data
123 # Create a buffer view referencing the new buffer.
124 gltf
.data
.buffer_views
.append(BufferView
.from_dict({
125 'buffer': buffer_idx
,
126 'byteLength': byte_length
129 # Update accessor to point to the new buffer view.
130 accessor
.buffer_view
= len(gltf
.data
.buffer_views
) - 1
132 dll
.decoderRelease(decoder
)