-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathb3dm.py
131 lines (99 loc) · 4.23 KB
/
b3dm.py
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
#!/usr/bin/env python3
#--------------------------------------------
# b3dm.py: Component of GLTF to GLB converter
# (c) 2016 Geopipe, Inc.
# All rights reserved. See LICENSE.
#--------------------------------------------
import struct
from batchtable import BatchTable
from featuretable import FeatureTable
B3DM_MAGIC = 'b3dm'
B3DM_VERSION = 1
B3DM_HEADER_LEN = 28
class B3DM:
def __init__(self):
self.batch_table = BatchTable()
self.feature_table = FeatureTable()
self.gltf_bin = bytearray()
def loadJSONBatch(self, data_in, object_wise = True):
self.batch_table.loadJSONBatch(data_in, object_wise)
def loadJSONFeature(self, data_in, object_wise = True):
self.feature_table.loadJSONBatch(data_in, object_wise)
def writeBinary(self, gltf_bin, num_batch_features = 0, num_feature_features = 0):
# Add the required field BATCH_LENGTH to the feature table,
# as well as any other required globals
num_batch_features = max(num_batch_features, self.batch_table.getNumFeatures())
self.feature_table.addGlobal('BATCH_LENGTH', num_batch_features)
num_feature_features = max(num_feature_features, self.feature_table.getNumFeatures())
self.batch_table.finalize()
self.feature_table.finalize()
# Generate the header
output = self.writeHeader(gltf_bin, num_batch_features, num_feature_features)
# Add the feature table JSON to the output
feature_json = self.feature_table.getFeatureJSON()
output.extend(feature_json)
# Add the feature table binary to the output
feature_bin = self.feature_table.getFeatureBin()
output.extend(feature_bin)
# Add the batch table JSON to the output
batch_json = self.batch_table.getBatchJSON()
output.extend(batch_json)
# Add the batch table binary to the output
batch_bin = self.batch_table.getBatchBin()
output.extend(batch_bin)
# Add the GLTF model body to the output
output.extend(gltf_bin)
return output
def writeHeader(self, gltf_bin, num_feature_features, num_batch_features):
len_feature_json = len(self.feature_table.getFeatureJSON())
len_feature_bin = len(self.feature_table.getFeatureBin())
len_batch_json = len(self.batch_table.getBatchJSON())
len_batch_bin = len(self.batch_table.getBatchBin())
length = B3DM_HEADER_LEN + \
len_feature_json + len_feature_bin + \
len_batch_json + len_batch_bin + \
len(gltf_bin)
output = bytearray()
output.extend(B3DM_MAGIC.encode('utf-8'))
output.extend(struct.pack('<I', B3DM_VERSION))
output.extend(struct.pack('<I', length))
output.extend(struct.pack('<I', len_feature_json))
output.extend(struct.pack('<I', len_feature_bin))
output.extend(struct.pack('<I', len_batch_json))
output.extend(struct.pack('<I', len_batch_bin))
# Sanity check
if (len(output) != B3DM_HEADER_LEN):
raise ValueError("Incorrect b3dm header length")
return output
def readBinary(self, data):
self.offset = 0
self.readHeader(data) # What it says on the tin
# Now grab the feature table, batch table, and GLB
self.feature_json = self.unpackString(data, self.len_feature_json)
self.feature_bin = self.unpackString(data, self.len_feature_bin)
self.batch_json = self.unpackString(data, self.len_batch_json)
self.batch_bin = self.unpackString(data, self.len_batch_bin)
self.gltf_bin = self.unpackString(data, self.length - self.offset)
def readHeader(self, data):
self.magic = self.unpack('4s', data).decode('utf-8')
self.version = self.unpack('<I', data)
if self.magic != B3DM_MAGIC or self.version > B3DM_VERSION:
raise IOError("Unrecognized magic %s or bad version %d" % (self.magic, self.version))
self.length = self.unpack('<I', data)
self.len_feature_json = self.unpack('<I', data)
self.len_feature_bin = self.unpack('<I', data)
self.len_batch_json = self.unpack('<I', data)
self.len_batch_bin = self.unpack('<I', data)
def getGLTFBin(self):
return self.gltf_bin
def unpackString(self, data, length):
self.offset += length
return data[self.offset - length : self.offset]
def unpack(self, fmt, data):
calc_len = struct.calcsize(fmt)
self.offset += calc_len
return struct.unpack(fmt, data[self.offset - calc_len : self.offset])[0]
def main():
raise NotImplementedError("This file cannot be used directly!")
if __name__ == "__main__":
main()