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
|
# Copyright 2018-2019 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ctypes import *
from io_scene_gltf2.io.com.gltf2_io import BufferView
from io_scene_gltf2.io.imp.gltf2_io_binary import BinaryData
from ...io.com.gltf2_io_debug import print_console
from io_scene_gltf2.io.com.gltf2_io_draco_compression_extension import dll_path
def decode_primitive(gltf, prim):
"""
Handles draco compression.
Moves decoded data into new buffers and buffer views held by the accessors of the given primitive.
"""
# Load DLL and setup function signatures.
dll = cdll.LoadLibrary(str(dll_path().resolve()))
dll.decoderCreate.restype = c_void_p
dll.decoderCreate.argtypes = []
dll.decoderRelease.restype = None
dll.decoderRelease.argtypes = [c_void_p]
dll.decoderDecode.restype = c_bool
dll.decoderDecode.argtypes = [c_void_p, c_void_p, c_size_t]
dll.decoderReadAttribute.restype = c_bool
dll.decoderReadAttribute.argtypes = [c_void_p, c_uint32, c_size_t, c_char_p]
dll.decoderGetVertexCount.restype = c_uint32
dll.decoderGetVertexCount.argtypes = [c_void_p]
dll.decoderGetIndexCount.restype = c_uint32
dll.decoderGetIndexCount.argtypes = [c_void_p]
dll.decoderAttributeIsNormalized.restype = c_bool
dll.decoderAttributeIsNormalized.argtypes = [c_void_p, c_uint32]
dll.decoderGetAttributeByteLength.restype = c_size_t
dll.decoderGetAttributeByteLength.argtypes = [c_void_p, c_uint32]
dll.decoderCopyAttribute.restype = None
dll.decoderCopyAttribute.argtypes = [c_void_p, c_uint32, c_void_p]
dll.decoderReadIndices.restype = c_bool
dll.decoderReadIndices.argtypes = [c_void_p, c_size_t]
dll.decoderGetIndicesByteLength.restype = c_size_t
dll.decoderGetIndicesByteLength.argtypes = [c_void_p]
dll.decoderCopyIndices.restype = None
dll.decoderCopyIndices.argtypes = [c_void_p, c_void_p]
decoder = dll.decoderCreate()
extension = prim.extensions['KHR_draco_mesh_compression']
name = prim.name if hasattr(prim, 'name') else '[unnamed]'
# Create Draco decoder.
draco_buffer = bytes(BinaryData.get_buffer_view(gltf, extension['bufferView']))
if not dll.decoderDecode(decoder, draco_buffer, len(draco_buffer)):
print_console('ERROR', 'Draco Decoder: Unable to decode. Skipping primitive {}.'.format(name))
return
# Choose a buffer index which does not yet exist, skipping over existing glTF buffers yet to be loaded
# and buffers which were generated and did not exist in the initial glTF file, like this decoder does.
base_buffer_idx = len(gltf.data.buffers)
for existing_buffer_idx in gltf.buffers:
if base_buffer_idx <= existing_buffer_idx:
base_buffer_idx = existing_buffer_idx + 1
# Read indices.
index_accessor = gltf.data.accessors[prim.indices]
if dll.decoderGetIndexCount(decoder) != index_accessor.count:
print_console('WARNING', 'Draco Decoder: Index count of accessor and decoded index count does not match. Updating accessor.')
index_accessor.count = dll.decoderGetIndexCount(decoder)
if not dll.decoderReadIndices(decoder, index_accessor.component_type):
print_console('ERROR', 'Draco Decoder: Unable to decode indices. Skipping primitive {}.'.format(name))
return
indices_byte_length = dll.decoderGetIndicesByteLength(decoder)
decoded_data = bytes(indices_byte_length)
dll.decoderCopyIndices(decoder, decoded_data)
# Generate a new buffer holding the decoded indices.
gltf.buffers[base_buffer_idx] = decoded_data
# Create a buffer view referencing the new buffer.
gltf.data.buffer_views.append(BufferView.from_dict({
'buffer': base_buffer_idx,
'byteLength': indices_byte_length
}))
# Update accessor to point to the new buffer view.
index_accessor.buffer_view = len(gltf.data.buffer_views) - 1
# Read each attribute.
for attr_idx, attr in enumerate(extension['attributes']):
dracoId = extension['attributes'][attr]
if attr not in prim.attributes:
print_console('ERROR', 'Draco Decoder: Draco attribute {} not in primitive attributes. Skipping primitive {}.'.format(attr, name))
return
accessor = gltf.data.accessors[prim.attributes[attr]]
if dll.decoderGetVertexCount(decoder) != accessor.count:
print_console('WARNING', 'Draco Decoder: Vertex count of accessor and decoded vertex count does not match for attribute {}. Updating accessor.'.format(attr, name))
accessor.count = dll.decoderGetVertexCount(decoder)
if not dll.decoderReadAttribute(decoder, dracoId, accessor.component_type, accessor.type.encode()):
print_console('ERROR', 'Draco Decoder: Could not decode attribute {}. Skipping primitive {}.'.format(attr, name))
return
byte_length = dll.decoderGetAttributeByteLength(decoder, dracoId)
decoded_data = bytes(byte_length)
dll.decoderCopyAttribute(decoder, dracoId, decoded_data)
# Generate a new buffer holding the decoded vertex data.
buffer_idx = base_buffer_idx + 1 + attr_idx
gltf.buffers[buffer_idx] = decoded_data
# Create a buffer view referencing the new buffer.
gltf.data.buffer_views.append(BufferView.from_dict({
'buffer': buffer_idx,
'byteLength': byte_length
}))
# Update accessor to point to the new buffer view.
accessor.buffer_view = len(gltf.data.buffer_views) - 1
dll.decoderRelease(decoder)
|