new model modes
[carveJwlIkooP6JGAAIwe30JlM.git] / blender_export.py
1 import bpy, math
2 from ctypes import *
3
4 class model(Structure):
5 _pack_ = 1
6 _fields_ = [("identifier",c_uint32),
7 ("vertex_count",c_uint32),
8 ("indice_count",c_uint32),
9 ("layer_count",c_uint32),
10 ("marker_count",c_uint32)]
11
12 class submodel(Structure):
13 _pack_ = 1
14 _fields_ = [("indice_start",c_uint32),
15 ("indice_count",c_uint32),
16 ("vertex_start",c_uint32),
17 ("vertex_count",c_uint32),
18 ("bbx",(c_float*3)*2),
19 ("pivot",c_float*3),
20 ("q",c_float*4),
21 ("name",c_char*32),
22 ("material",c_char*32)]
23
24 class marker(Structure):
25 _pack_ = 1
26 _fields_ = [("co",c_float*3),
27 ( "q",c_float*4),
28 ( "s",c_float*3),
29 ("name",c_char*32)]
30
31 class model_vert(Structure):
32 _pack_ = 1
33 _fields_ = [("co",c_float*3),
34 ("norm",c_float*3),
35 ("colour",c_float*4),
36 ("uv",c_float*2)]
37
38 def v4_dot( a, b ):
39 return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*a[3]
40
41 def v4_length( a ):
42 return math.sqrt( v4_dot(a,a) )
43
44 def v2_eq( a, b ):
45 if abs(a[0]-b[0]) < 0.0001:
46 if abs(a[1]-b[1]) < 0.0001:
47 return True
48 return False
49
50 def v3_eq( a, b ):
51 if abs(a[0]-b[0]) < 0.0001:
52 if abs(a[1]-b[1]) < 0.0001:
53 if abs(a[2]-b[2]) < 0.0001:
54 return True
55 return False
56
57 def v4_eq( a, b ):
58 if abs(a[0]-b[0]) < 0.0001:
59 if abs(a[1]-b[1]) < 0.0001:
60 if abs(a[2]-b[2]) < 0.0001:
61 if abs(a[3]-b[3]) < 0.0001:
62 return True
63 return False
64
65 def m3x3_mul( a, b, d ):
66 a00 = a[0][0]
67 a01 = a[0][1]
68 a02 = a[0][2]
69 a10 = a[1][0]
70 a11 = a[1][1]
71 a12 = a[1][2]
72 a20 = a[2][0]
73 a21 = a[2][1]
74 a22 = a[2][2]
75 b00 = b[0][0]
76 b01 = b[0][1]
77 b02 = b[0][2]
78 b10 = b[1][0]
79 b11 = b[1][1]
80 b12 = b[1][2]
81 b20 = b[2][0]
82 b21 = b[2][1]
83 b22 = b[2][2]
84 d[0][0] = a00*b00 + a10*b01 + a20*b02
85 d[0][1] = a01*b00 + a11*b01 + a21*b02
86 d[0][2] = a02*b00 + a12*b01 + a22*b02
87 d[1][0] = a00*b10 + a10*b11 + a20*b12
88 d[1][1] = a01*b10 + a11*b11 + a21*b12
89 d[1][2] = a02*b10 + a12*b11 + a22*b12
90 d[2][0] = a00*b20 + a10*b21 + a20*b22
91 d[2][1] = a01*b20 + a11*b21 + a21*b22
92 d[2][2] = a02*b20 + a12*b21 + a22*b22
93
94 def q_m3x3( q, d ):
95 l = v4_length(q)
96 s = 2.0 if l > 0.0 else 0.0
97 xx = s*q[0]*q[0]
98 xy = s*q[0]*q[1]
99 wx = s*q[3]*q[0]
100 yy = s*q[1]*q[1]
101 yz = s*q[1]*q[2]
102 wy = s*q[3]*q[1]
103 zz = s*q[2]*q[2]
104 xz = s*q[0]*q[2]
105 wz = s*q[3]*q[2]
106 d[0][0] = 1.0 - yy - zz
107 d[1][1] = 1.0 - xx - zz
108 d[2][2] = 1.0 - xx - yy
109 d[0][1] = xy + wz
110 d[1][2] = yz + wx
111 d[2][0] = xz + wy
112 d[1][0] = xy - wz
113 d[2][1] = yz - wx
114 d[0][2] = xz - wy
115
116 def m3x3_q( m, q ):
117 diag = m[0][0] + m[1][1] + m[2][2]
118 if diag >= 0.0:
119 r = math.sqrt( 1.0 + diag )
120 rinv = 0.5 / r
121 q[0] = rinv * (m[1][2] - m[2][1])
122 q[1] = rinv * (m[2][0] - m[0][2])
123 q[2] = rinv * (m[0][1] - m[1][0])
124 q[3] = r * 0.5
125 elif m[0][0] >= m[1][1] and m[0][0] >= m[2][2]:
126 r = math.sqrt( 1.0 - m[1][1] - m[2][2] + m[0][0] )
127 rinv = 0.5 / r
128 q[0] = r * 0.5
129 q[1] = rinv * (m[0][1] + m[1][0])
130 q[2] = rinv * (m[0][2] + m[2][0])
131 q[3] = rinv * (m[1][2] - m[2][1])
132 elif m[1][1] >= m[2][2]:
133 r = math.sqrt( 1.0 - m[0][0] - m[2][2] + m[1][1] )
134 rinv = 0.5 / r
135 q[0] = rinv * (m[0][1] + m[1][0])
136 q[1] = r * 0.5
137 q[2] = rinv * (m[1][2] + m[2][1])
138 q[3] = rinv * (m[2][0] - m[0][2])
139 else:
140 r = math.sqrt( 1.0 - m[0][0] - m[1][1] + m[2][2] )
141 rinv = 0.5 / r
142 q[0] = rinv * (m[0][2] + m[2][0])
143 q[1] = rinv * (m[1][2] + m[2][1])
144 q[2] = r * 0.5
145 q[3] = rinv * (m[0][1] - m[1][0])
146
147 def write_model(name):
148 fp = open(F"/home/harry/Documents/carve/models/{name}.mdl", "wb")
149 collection = bpy.data.collections[name]
150
151 header = model()
152 header.identifier = 0xABCD0000
153 header.vertex_count = 0
154 header.indice_count = 0
155 header.layer_count = 0
156
157 layers = []
158 markers = []
159 vertex_buffer = []
160 indice_buffer = []
161
162 print( F"Create mode {name}" )
163
164 for obj in collection.objects:
165 if obj.type == 'EMPTY':
166 mk = marker()
167 mk.co[0] = obj.location[0]
168 mk.co[1] = obj.location[2]
169 mk.co[2] = -obj.location[1]
170
171 # Convert rotation quat to our space type
172 quat = obj.matrix_world.to_quaternion()
173 mk.q[0] = quat[1]
174 mk.q[1] = quat[3]
175 mk.q[2] = -quat[2]
176 mk.q[3] = quat[0]
177
178 mk.s[0] = obj.scale[0]
179 mk.s[1] = obj.scale[2]
180 mk.s[2] = obj.scale[1]
181 mk.name = obj.name.encode('utf-8')
182
183 markers += [mk]
184 header.marker_count += 1
185
186 elif obj.type == 'MESH':
187 dgraph = bpy.context.evaluated_depsgraph_get()
188 data = obj.evaluated_get(dgraph).data
189 data.calc_loop_triangles()
190 data.calc_normals_split()
191
192 for material_id, mat in enumerate(data.materials):
193 sm = submodel()
194 sm.indice_start = header.indice_count
195 sm.vertex_start = header.vertex_count
196 sm.vertex_count = 0
197 sm.indice_count = 0
198 sm.pivot[0] = obj.matrix_world.translation[0]
199 sm.pivot[1] = obj.matrix_world.translation[2]
200 sm.pivot[2] = -obj.matrix_world.translation[1]
201
202 quat = obj.matrix_world.to_quaternion()
203 sm.q[0] = quat[1]
204 sm.q[1] = quat[3]
205 sm.q[2] = -quat[2]
206 sm.q[3] = quat[0]
207
208 for i in range(3):
209 sm.bbx[0][i] = 999999
210 sm.bbx[1][i] = -999999
211
212 sm.name = obj.name.encode('utf-8')
213 sm.material = mat.name.encode('utf-8')
214 print( F" Creating submesh '{obj.name}:{mat.name}'" )
215 boffa = {}
216
217 hit_count = 0
218 miss_count = 0
219
220 # Write the vertex / indice data
221 #
222 for tri_index, tri in enumerate(data.loop_triangles):
223 if tri.material_index != material_id:
224 continue
225
226 for j in range(3):
227 vert = data.vertices[tri.vertices[j]]
228
229 co = vert.co
230 norm = data.loops[tri.loops[j]].normal
231 uv = (0,0)
232 if data.uv_layers:
233 uv = data.uv_layers.active.data[tri.loops[j]].uv
234
235 key = (round(co[0],4),round(co[1],4),round(co[2],4),\
236 round(norm[0],4),round(norm[1],4),round(norm[2],4),\
237 round(uv[0],4),round(uv[1],4))
238
239 if key in boffa:
240 indice_buffer += [boffa[key]]
241 hit_count += 1
242 else:
243 miss_count += 1
244 index = c_uint32(sm.vertex_count)
245 sm.vertex_count += 1
246
247 boffa[key] = index
248
249 indice_buffer += [index]
250
251 v = model_vert()
252 v.co[0] = co[0]
253 v.co[1] = co[2]
254 v.co[2] = -co[1]
255 v.norm[0] = norm[0]
256 v.norm[1] = norm[2]
257 v.norm[2] = -norm[1]
258 v.uv[0] = uv[0]
259 v.uv[1] = uv[1]
260 v.colour[0] = 1.0
261 v.colour[1] = 1.0
262 v.colour[2] = 1.0
263 v.colour[3] = 1.0
264 vertex_buffer += [v]
265
266 for i in range(3):
267 sm.bbx[0][i] = min( sm.bbx[0][i], v.co[i] )
268 sm.bbx[1][i] = max( sm.bbx[1][i], v.co[i] )
269
270 sm.indice_count += 1
271
272 layers += [sm]
273 header.layer_count += 1
274 header.vertex_count += sm.vertex_count
275 header.indice_count += sm.indice_count
276
277 fp.write( bytearray( header ) )
278 for l in layers:
279 fp.write( bytearray(l) )
280 for m in markers:
281 fp.write( bytearray(m) )
282 for v in vertex_buffer:
283 fp.write( bytearray(v) )
284 for i in indice_buffer:
285 fp.write( bytearray(i) )
286
287 fp.close()
288
289 for col in bpy.data.collections["export"].children:
290 write_model( col.name )