afb0f78c41c3432db71699bcdb87044aa6604ce4
3 from gpu_extras
.batch
import batch_for_shader
6 "name":"Carve exporter",
7 "author": "Harry Godden (hgn)",
14 "category":"Import/Export",
17 class model(Structure
):
19 _fields_
= [("identifier",c_uint32
),
20 ("vertex_count",c_uint32
),
21 ("indice_count",c_uint32
),
22 ("layer_count",c_uint32
),
23 ("marker_count",c_uint32
)]
25 class submodel(Structure
):
27 _fields_
= [("indice_start",c_uint32
),
28 ("indice_count",c_uint32
),
29 ("vertex_start",c_uint32
),
30 ("vertex_count",c_uint32
),
31 ("bbx",(c_float
*3)*2),
35 ("material",c_char
*32)]
37 class classtype_gate(Structure
):
39 _fields_
= [("target",c_uint32
)]
41 class marker(Structure
):
43 _fields_
= [("co",c_float
*3),
46 ("classtype",c_uint32
),
50 class model_vert(Structure
):
52 _fields_
= [("co",c_float
*3),
57 def submesh_set_transform( sm
, obj
):
58 sm
.pivot
[0] = obj
.matrix_world
.translation
[0]
59 sm
.pivot
[1] = obj
.matrix_world
.translation
[2]
60 sm
.pivot
[2] = -obj
.matrix_world
.translation
[1]
62 quat
= obj
.matrix_world
.to_quaternion()
68 def write_model(name
):
69 fp
= open(F
"/home/harry/Documents/carve/models/{name}.mdl", "wb")
70 collection
= bpy
.data
.collections
[name
]
73 header
.identifier
= 0xABCD0000
74 header
.vertex_count
= 0
75 header
.indice_count
= 0
76 header
.layer_count
= 0
77 header
.marker_count
= 1
84 print( F
"Create mode {name}" )
97 rootmarker
.name
= "".encode('utf-8')
99 rootmarker
.classtype
= 0
101 markers
= [ rootmarker
] # aka entities
107 for obj
in collection
.objects
:
108 if obj
.type == 'EMPTY':
109 obj
.cv_data
.uid
= entity_count
112 for obj
in collection
.objects
:
113 if obj
.type == 'EMPTY':
115 mk
.co
[0] = obj
.location
[0]
116 mk
.co
[1] = obj
.location
[2]
117 mk
.co
[2] = -obj
.location
[1]
119 # Convert rotation quat to our space type
120 quat
= obj
.matrix_world
.to_quaternion()
126 mk
.s
[0] = obj
.scale
[0]
127 mk
.s
[1] = obj
.scale
[2]
128 mk
.s
[2] = obj
.scale
[1]
129 mk
.name
= obj
.name
.encode('utf-8')
130 mk
.offset
= entdata_offset
132 classtype
= obj
.cv_data
.classtype
134 if classtype
== 'k_classtype_gate':
136 entdata_offset
+= sizeof( classtype_gate
)
138 gate
= classtype_gate()
140 if obj
.cv_data
.target
!= None:
141 gate
.target
= obj
.cv_data
.target
.cv_data
.uid
143 entdata_structs
+= [gate
]
145 elif classtype
== 'k_thingummybob':
149 header
.marker_count
+= 1
151 elif obj
.type == 'MESH':
152 default_mat
= c_uint32(69)
153 default_mat
.name
= ""
155 if obj
.data
.name
in mesh_cache
:
156 ref
= mesh_cache
[obj
.data
.name
]
157 for material_id
, mref
in enumerate(ref
['sm']):
158 print(F
" Link submesh({ref['users']}) '{obj.name}:{mat.name}'")
161 sm
.indice_start
= mref
['indice_start']
162 sm
.indice_count
= mref
['indice_count']
163 sm
.vertex_start
= mref
['vertex_start']
164 sm
.vertex_count
= mref
['vertex_count']
165 sm
.name
= obj
.name
.encode('utf-8')
166 sm
.material
= mref
['material']
168 submesh_set_transform( sm
, obj
)
170 header
.layer_count
+= 1
175 ref
= mesh_cache
[obj
.data
.name
] = {}
179 dgraph
= bpy
.context
.evaluated_depsgraph_get()
180 data
= obj
.evaluated_get(dgraph
).data
181 data
.calc_loop_triangles()
182 data
.calc_normals_split()
184 mat_list
= data
.materials
if len(data
.materials
) > 0 else [default_mat
]
185 for material_id
, mat
in enumerate(mat_list
):
189 sm
.indice_start
= header
.indice_count
190 sm
.vertex_start
= header
.vertex_count
193 submesh_set_transform( sm
, obj
)
196 sm
.bbx
[0][i
] = 999999
197 sm
.bbx
[1][i
] = -999999
199 sm
.name
= obj
.name
.encode('utf-8')
200 sm
.material
= mat
.name
.encode('utf-8')
201 print( F
" Creating submesh '{obj.name}:{mat.name}'" )
207 # Write the vertex / indice data
209 for tri_index
, tri
in enumerate(data
.loop_triangles
):
210 if tri
.material_index
!= material_id
:
214 vert
= data
.vertices
[tri
.vertices
[j
]]
217 norm
= data
.loops
[tri
.loops
[j
]].normal
220 uv
= data
.uv_layers
.active
.data
[tri
.loops
[j
]].uv
222 key
= (round(co
[0],4),round(co
[1],4),round(co
[2],4),\
223 round(norm
[0],4),round(norm
[1],4),round(norm
[2],4),\
224 round(uv
[0],4),round(uv
[1],4))
227 indice_buffer
+= [boffa
[key
]]
231 index
= c_uint32(sm
.vertex_count
)
236 indice_buffer
+= [index
]
254 sm
.bbx
[0][i
] = min( sm
.bbx
[0][i
], v
.co
[i
] )
255 sm
.bbx
[1][i
] = max( sm
.bbx
[1][i
], v
.co
[i
] )
260 header
.layer_count
+= 1
261 header
.vertex_count
+= sm
.vertex_count
262 header
.indice_count
+= sm
.indice_count
264 mref
['indice_start'] = sm
.indice_start
265 mref
['indice_count'] = sm
.indice_count
266 mref
['vertex_start'] = sm
.vertex_start
267 mref
['vertex_count'] = sm
.vertex_count
269 mref
['material'] = sm
.material
272 fp
.write( bytearray( header
) )
274 fp
.write( bytearray(l
) )
276 fp
.write( bytearray(m
) )
277 for v
in vertex_buffer
:
278 fp
.write( bytearray(v
) )
279 for i
in indice_buffer
:
280 fp
.write( bytearray(i
) )
281 for ed
in entdata_structs
:
282 fp
.write( bytearray(ed
) )
287 # ------------------------------------------------------------------------------
289 cv_view_draw_handler
= None
290 cv_view_shader
= gpu
.shader
.from_builtin('3D_SMOOTH_COLOR')
293 global cv_view_shader
294 cv_view_shader
.bind()
295 gpu
.state
.depth_mask_set(False)
296 gpu
.state
.line_width_set(2.0)
297 gpu
.state
.face_culling_set('BACK')
298 gpu
.state
.depth_test_set('NONE')
299 gpu
.state
.blend_set('ADDITIVE')
304 for obj
in bpy
.context
.collection
.all_objects
:
305 if obj
.cv_data
.classtype
== 'k_classtype_gate':
306 if obj
.cv_data
.target
!= None:
308 p1
= obj
.cv_data
.target
.location
309 verts
+= [(p0
[0],p0
[1],p0
[2])]
310 verts
+= [(p1
[0],p1
[1],p1
[2])]
311 colours
+= [(0,1,0,1.0),(1,0,0,1.0)]
313 lines
= batch_for_shader(\
314 cv_view_shader
, 'LINES', \
315 { "pos":verts
, "color":colours
})
317 lines
.draw( cv_view_shader
)
319 def cv_poll_target(scene
, obj
):
320 if obj
== bpy
.context
.active_object
:
322 if obj
.cv_data
.classtype
== 'k_classtype_none':
326 class CV_OBJ_SETTINGS(bpy
.types
.PropertyGroup
):
327 uid
: bpy
.props
.IntProperty( name
="" )
329 target
: bpy
.props
.PointerProperty( type=bpy
.types
.Object
, name
="target", \
330 poll
=cv_poll_target
)
332 classtype
: bpy
.props
.EnumProperty(
335 ('k_classtype_none', "k_classtype_none", "", 0),
336 ('k_classtype_gate', "k_classtype_gate", "", 1),
339 class CV_OBJ_PANEL(bpy
.types
.Panel
):
340 bl_label
="Entity Config"
341 bl_idname
="SCENE_PT_cv_entity"
342 bl_space_type
='PROPERTIES'
343 bl_region_type
='WINDOW'
347 active_object
= bpy
.context
.active_object
348 if active_object
== None: return
349 _
.layout
.prop( active_object
.cv_data
, "classtype" )
350 _
.layout
.prop( active_object
.cv_data
, "target" )
352 class CV_INTERFACE(bpy
.types
.Panel
):
353 bl_idname
= "VIEW3D_PT_carve"
355 bl_space_type
= 'VIEW_3D'
356 bl_region_type
= 'UI'
357 bl_category
= "Carve"
359 def draw(_
, context
):
361 layout
.operator( "carve.compile_all" )
363 class CV_COMPILE(bpy
.types
.Operator
):
364 bl_idname
="carve.compile_all"
365 bl_label
="Compile All"
367 def execute(_
,context
):
368 for col
in bpy
.data
.collections
["export"].children
:
369 write_model( col
.name
)
373 classes
= [CV_OBJ_SETTINGS
,CV_OBJ_PANEL
,CV_COMPILE
,CV_INTERFACE
]
376 global cv_view_draw_handler
379 bpy
.utils
.register_class(c
)
381 bpy
.types
.Object
.cv_data
= bpy
.props
.PointerProperty(type=CV_OBJ_SETTINGS
)
382 cv_view_draw_handler
= bpy
.types
.SpaceView3D
.draw_handler_add(\
383 cv_draw
,(),'WINDOW','POST_VIEW')
386 global cv_view_draw_handler
389 bpy
.utils
.unregister_class(c
)
391 bpy
.types
.SpaceView3D
.draw_handler_remove(cv_view_draw_handler
,'WINDOW')