Export_3ds: Improved distance cue node search
[blender-addons.git] / io_scene_gltf2 / blender / imp / gltf2_io_draco_compression_extension.py
blob105c4ed404681c1ee63fdabfb2419e721487d78f
1 # SPDX-FileCopyrightText: 2018-2021 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
5 from ctypes import *
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):
13 """
14 Handles draco compression.
15 Moves decoded data into new buffers and buffer views held by the accessors of the given primitive.
16 """
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))
66 return
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
75 # Read indices.
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))
82 return
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
95 }))
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))
105 return
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))
113 return
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)