1+ ## TODO: use dictionary as cells is going to be deprecated, should use list instead
2+
13head = b" MZD-File-Format \x00 " # c string has \x00 as end
24end = b" >> END OF FILE << \x00 " # c string has \x00 as end
5+ import bpy
36import numpy as np
47import meshio
58from .table import table
@@ -85,6 +88,168 @@ def readMZD_to_meshio(filepath):
8588 start_polyVIndices = end_polyVIndices
8689 start_polyVIndicesNum = b
8790
91+ faces_copy = np .copy (cells ['triangle' ])
92+ faces_copy .sort (axis = 1 )
93+ _ , indxs , count = np .unique (faces_copy , axis = 0 , return_index = True , return_counts = True )
94+ faces = cells ['triangle' ][indxs ]
95+ cells ['triangle' ] = faces
96+
97+ faces_copy = np .copy (cells ['quad' ])
98+ faces_copy .sort (axis = 1 )
99+ _ , indxs , count = np .unique (faces_copy , axis = 0 , return_index = True , return_counts = True )
100+ faces = cells ['quad' ][indxs ]
101+ cells ['quad' ] = faces
102+
103+ elif chunkID == 0xDA7A0001 : # vertex normals.
104+ byte = file .read (4 )
105+ out_numVerticeAttributes = int .from_bytes (byte , byteorder = 'little' )
106+ if out_numVerticeAttributes != out_numVertices :
107+ return - 127
108+
109+ byte = file .read (out_numVerticeAttributes * 6 )
110+ out_vertAttribute = np .frombuffer (byte , dtype = np .uint16 )
111+ out_vertAttribute = table [out_vertAttribute ]
112+ point_data ['normal' ] = out_vertAttribute .reshape ((out_numVerticeAttributes , 3 ))
113+
114+ elif chunkID == 0xDA7A0002 : # vertex motions
115+ byte = file .read (4 )
116+ out_numVerticeAttributes = int .from_bytes (byte , byteorder = 'little' )
117+ if out_numVerticeAttributes != out_numVertices :
118+ return - 127
119+
120+ byte = file .read (out_numVerticeAttributes * 6 )
121+ out_vertAttribute = np .frombuffer (byte , dtype = np .uint16 )
122+ out_vertAttribute = table [out_vertAttribute ]
123+ point_data ['velocity' ] = out_vertAttribute .reshape ((out_numVerticeAttributes , 3 ))
124+
125+ elif chunkID == 0xDA7A0003 : # vertex colors
126+ byte = file .read (4 )
127+ out_numVerticeAttributes = int .from_bytes (byte , byteorder = 'little' )
128+ if out_numVerticeAttributes != out_numVertices :
129+ return - 127
130+
131+ byte = file .read (out_numVerticeAttributes * 8 )
132+ out_vertAttribute = np .frombuffer (byte , dtype = np .uint16 )
133+ out_vertAttribute = table [out_vertAttribute ]
134+ point_data ['color' ] = out_vertAttribute .reshape ((out_numVerticeAttributes , 3 ))
135+
136+ elif chunkID == 0xDA7A0004 : # vertex UVWs.
137+ byte = file .read (4 )
138+ out_numVerticeAttributes = int .from_bytes (byte , byteorder = 'little' )
139+ if out_numVerticeAttributes != out_numVertices :
140+ return - 127
141+
142+ byte = file .read (out_numVerticeAttributes * 12 )
143+ out_vertAttribute = np .frombuffer (byte , dtype = np .float32 )
144+ point_data ['uvw_map' ] = out_vertAttribute .reshape ((out_numVerticeAttributes , 3 ))
145+
146+ # For the rest of attributes, because meshio doest not support attributes on nodes, (equivalent to face cornder in blender)
147+ # So the attributes data will be skipped
148+ elif chunkID == 0xDA7A0011 : # node normals.
149+ file .seek (size , 1 )
150+ pass
151+ elif chunkID == 0xDA7A0013 : # node colors.
152+ file .seek (size , 1 )
153+ pass
154+ elif chunkID == 0xDA7A0014 : # node UVWs.
155+ file .seek (size , 1 )
156+ pass
157+ else :
158+ file .seek (size , 1 )
159+ pass
160+ return meshio .Mesh (out_vertPositions .reshape ((out_numVertices , 3 )), cells , point_data )
161+
162+
163+ def readMZD_to_meshio_with_split_norm (filepath ):
164+ out_numVertices = None
165+ out_numPolygons = None
166+ out_vertPositions = None
167+ out_numNodes = None # number of loops
168+ out_polyVIndicesNum = None # faces_loop_total
169+ out_polyVIndices = None #loops_vert_idx
170+ cells = {}
171+ point_data = {}
172+
173+ with open (filepath , 'rb' ) as file :
174+ byte = file .read (24 )
175+ if byte != head :
176+ return - 4
177+ while 1 :
178+ # check if it reach the end
179+ byte = file .read (24 )
180+ if byte == end :
181+ break
182+ else :
183+ # if not reach the end, rewind the pointer back 24 bytes
184+ file .seek (- 24 , 1 )
185+
186+ byte = file .read (4 )
187+ chunkID = int .from_bytes (byte , byteorder = 'little' )
188+
189+ byte = file .read (24 )
190+ name = byte
191+
192+ byte = file .read (4 )
193+ size = int .from_bytes (byte , byteorder = 'little' )
194+
195+ if chunkID == 0x0ABC0001 : # vertices and polygons.
196+
197+ byte = file .read (4 )
198+ out_numVertices = int .from_bytes (byte , byteorder = 'little' )
199+ if out_numVertices < 0 :
200+ return - 127
201+ if out_numVertices == 0 :
202+ break
203+
204+ byte = file .read (12 * out_numVertices )
205+ out_vertPositions = np .frombuffer (byte , dtype = np .float32 )
206+
207+ byte = file .read (4 )
208+ out_numPolygons = int .from_bytes (byte , byteorder = 'little' )
209+
210+ byte = file .read (out_numPolygons )
211+ out_polyVIndicesNum = np .frombuffer (byte , dtype = np .uint8 )
212+ out_numNodes = out_polyVIndicesNum .sum (dtype = np .int32 )
213+
214+ byte = file .read (4 )
215+ numBytesPerPolyVInd = int .from_bytes (byte , byteorder = 'little' )
216+
217+ if numBytesPerPolyVInd == 4 :
218+ # int
219+ byte = file .read (out_numNodes * numBytesPerPolyVInd )
220+ out_polyVIndices = np .frombuffer (byte , dtype = np .int32 )
221+ elif numBytesPerPolyVInd == 2 :
222+ # unsigned short
223+ byte = file .read (out_numNodes * numBytesPerPolyVInd )
224+ # WARNING: not sure if it's correct
225+ # uncovered branch from test data
226+ out_polyVIndices = np .frombuffer (byte , dtype = np .uint16 )
227+ else :
228+ return - 127
229+ start_polyVIndicesNum = 0
230+ start_polyVIndices = 0
231+ breaks = np .where (out_polyVIndicesNum [:- 1 ] != out_polyVIndicesNum [1 :])[0 ] + 1
232+ breaks = np .append (breaks , len (out_polyVIndicesNum ))
233+ for b in breaks :
234+ poly_nodes_num = out_polyVIndicesNum [start_polyVIndices ] # 3(triangle) or 4 (quad)
235+ end_polyVIndices = start_polyVIndices + poly_nodes_num * (b - start_polyVIndicesNum )
236+ cells [num_nodes_to_name [poly_nodes_num ]] = out_polyVIndices [start_polyVIndices :end_polyVIndices ].reshape (
237+ ((b - start_polyVIndicesNum ), poly_nodes_num ))
238+ start_polyVIndices = end_polyVIndices
239+ start_polyVIndicesNum = b
240+
241+ faces_copy = np .copy (cells ['triangle' ])
242+ faces_copy .sort (axis = 1 )
243+ _ , indxs = np .unique (faces_copy , axis = 0 , return_index = True )
244+ faces = cells ['triangle' ][indxs ]
245+ cells ['triangle' ] = faces
246+
247+ faces_copy = np .copy (cells ['quad' ])
248+ faces_copy .sort (axis = 1 )
249+ _ , indxs = np .unique (faces_copy , axis = 0 , return_index = True )
250+ faces = cells ['quad' ][indxs ]
251+ cells ['quad' ] = faces
252+
88253 elif chunkID == 0xDA7A0001 : # vertex normals.
89254 byte = file .read (4 )
90255 out_numVerticeAttributes = int .from_bytes (byte , byteorder = 'little' )
@@ -129,7 +294,7 @@ def readMZD_to_meshio(filepath):
129294 point_data ['uvw_map' ] = out_vertAttribute .reshape ((out_numVerticeAttributes , 3 ))
130295
131296 # For the rest of attributes, because meshio doest not support attributes on nodes, (equivalent to face cornder in blender)
132- # So the attributes data will be skipped
297+ # So the attributes data will be skipped
133298 elif chunkID == 0xDA7A0011 : # node normals.
134299 file .seek (size , 1 )
135300 pass
@@ -144,12 +309,13 @@ def readMZD_to_meshio(filepath):
144309 pass
145310 return meshio .Mesh (out_vertPositions .reshape ((out_numVertices , 3 )), cells , point_data )
146311
312+
147313def readMZD_to_bpymesh (filepath , mesh ):
148314 shade_scheme = False
149315 if mesh .polygons :
150316 shade_scheme = mesh .polygons [0 ].use_smooth
151317
152- if len (mesh .vertices )> 0 :
318+ if len (mesh .vertices ) > 0 :
153319 mesh .clear_geometry ()
154320
155321 out_numVertices = None
@@ -217,20 +383,20 @@ def readMZD_to_bpymesh(filepath, mesh):
217383 return - 127
218384
219385 mesh .vertices .add (out_numVertices )
220- mesh .vertices .foreach_set ('co' ,out_vertPositions )
386+ mesh .vertices .foreach_set ('co' , out_vertPositions )
221387
222388 mesh .loops .add (out_numNodes )
223- mesh .loops .foreach_set ('vertex_index' ,out_polyVIndices )
389+ mesh .loops .foreach_set ('vertex_index' , out_polyVIndices )
224390
225391 mesh .polygons .add (out_numPolygons )
226- mesh .polygons .foreach_set ('loop_total' ,out_polyVIndicesNum )
392+ mesh .polygons .foreach_set ('loop_total' , out_polyVIndicesNum )
227393 faces_loop_start = None
228394
229395 if out_polyVIndicesNum .size > 0 :
230396 faces_loop_start = np .cumsum (out_polyVIndicesNum )
231397 faces_loop_start = np .roll (faces_loop_start , 1 )
232398 faces_loop_start [0 ] = 0
233- mesh .polygons .foreach_set ('loop_start' ,faces_loop_start )
399+ mesh .polygons .foreach_set ('loop_start' , faces_loop_start )
234400 mesh .polygons .foreach_set ("use_smooth" , [shade_scheme ] * out_numPolygons )
235401 mesh .update ()
236402 mesh .validate ()
0 commit comments