eec7a49a2a76c81f4aecc76dd8586eddbfb650b8
4 from mathutils
import *
5 from gpu_extras
.batch
import batch_for_shader
8 "name":"Carve exporter",
9 "author": "Harry Godden (hgn)",
16 "category":"Import/Export",
19 class mdl_vert(Structure
):
21 _fields_
= [("co",c_float
*3),
25 ("weights",c_uint16
*4),
28 class mdl_submesh(Structure
):
30 _fields_
= [("indice_start",c_uint32
),
31 ("indice_count",c_uint32
),
32 ("vertex_start",c_uint32
),
33 ("vertex_count",c_uint32
),
34 ("bbx",(c_float
*3)*2),
35 ("material_id",c_uint32
)] # index into the material array
37 class mdl_material(Structure
):
39 _fields_
= [("pstr_name",c_uint32
)]
41 class mdl_node(Structure
):
43 _fields_
= [("co",c_float
*3),
46 ("submesh_start",c_uint32
),
47 ("submesh_count",c_uint32
),
48 ("classtype",c_uint32
),
50 ("children",c_uint32
),
51 ("pstr_name",c_uint32
)]
53 class mdl_header(Structure
):
55 _fields_
= [("identifier",c_uint32
),
57 ("file_length",c_uint32
),
58 ("vertex_count",c_uint32
),
59 ("vertex_offset",c_uint32
),
61 ("indice_count",c_uint32
),
62 ("indice_offset",c_uint32
),
64 ("submesh_count",c_uint32
),
65 ("submesh_offset",c_uint32
),
67 ("material_count",c_uint32
),
68 ("material_offset",c_uint32
),
70 ("node_count",c_uint32
),
71 ("node_offset",c_uint32
),
73 ("strings_offset",c_uint32
),
74 ("entdata_offset",c_uint32
),
76 ("anim_count",c_uint32
),
77 ("anim_offset",c_uint32
)
81 # ==========================================
83 class classtype_gate(Structure
):
85 _fields_
= [("target",c_uint32
),
88 class classtype_block(Structure
):
90 _fields_
= [("bbx",(c_float
*3)*2)]
92 class classtype_spawn(Structure
):
94 _fields_
= [("temp",c_uint32
)]
96 class classtype_water(Structure
):
98 _fields_
= [("temp",c_uint32
)]
100 class classtype_car_path(Structure
):
102 _fields_
= [("target",c_uint32
),
103 ("target1",c_uint32
)]
105 class classtype_instance(Structure
):
107 _fields_
= [("pstr_file",c_uint32
)]
109 class classtype_capsule(Structure
):
111 _fields_
= [("height",c_float
),
114 class classtype_route_node(Structure
):
116 _fields_
= [("target",c_uint32
),
117 ("target1",c_uint32
)]
119 class classtype_route(Structure
):
121 _fields_
= [("pstr_name",c_uint32
),
122 ("id_start",c_uint32
),
123 ("colour",c_float
*3)]
125 class classtype_skin(Structure
):
127 _fields_
= [("skeleton",c_uint32
)]
129 class classtype_skeleton(Structure
):
131 _fields_
= [("anim_start",c_uint32
),
132 ("anim_count",c_uint32
)]
134 class classtype_bone(Structure
):
136 _fields_
= [("deform",c_uint32
)]
139 # ==============================================================================
141 def write_model(collection_name
):
142 print( F
"Model graph | Create mode '{collection_name}'" )
144 header
= mdl_header()
145 header
.identifier
= 0xABCD0000
147 header
.vertex_count
= 0
148 header
.indice_count
= 0
149 header
.submesh_count
= 0
150 header
.node_count
= 0
151 header
.material_count
= 0
152 header
.file_length
= 0
168 def emplace_string( s
):
169 nonlocal string_cache
, strings_buffer
171 if s
in string_cache
:
172 return string_cache
[s
]
174 string_cache
[s
] = len( strings_buffer
)
175 strings_buffer
+= (s
+'\0').encode('utf-8')
176 return string_cache
[s
]
178 def emplace_material( mat
):
179 nonlocal material_cache
, material_buffer
181 if mat
.name
in material_cache
:
182 return material_cache
[mat
.name
]
184 material_cache
[mat
.name
] = header
.material_count
185 dest
= mdl_material()
186 dest
.pstr_name
= emplace_string( mat
.name
)
187 material_buffer
+= [dest
]
189 header
.material_count
+= 1
190 return material_cache
[mat
.name
]
192 # Create root or empty node and materials
193 # this is to designate id 0 as 'NULL'
195 none_material
= c_uint32(69)
196 none_material
.name
= ""
197 emplace_material( none_material
)
210 root
.pstr_name
= emplace_string('')
211 root
.submesh_start
= 0
212 root
.submesh_count
= 0
215 node_buffer
+= [root
]
219 print( " assigning ids" )
220 collection
= bpy
.data
.collections
[collection_name
]
223 # ==========================================
225 header
.node_count
= 0
228 uid
= header
.node_count
229 header
.node_count
+= 1
232 print( " creating scene graph" )
233 graph
= {"obj": None, "depth": 0, "children": [], "uid": _uid()}
234 graph_lookup
= {} # object can lookup its graph def here
236 for obj
in collection
.all_objects
:
239 def _extend( p
, n
, d
):
241 tree
= {"obj":n
, "depth": d
, "children":[], "uid": uid
}
244 if n
.type == 'ARMATURE':
245 tree
["bones"] = [None] # None is the root transform
247 def _extendb( p
, n
, d
):
250 btree
= {"bone":n
, "depth": d
, "children":[], "uid": _uid()}
252 _extendb( btree
, c
, d
+1 )
254 btree
['deform'] = n
.use_deform
255 p
['children'] += [btree
]
258 tree
["bones"] += [n
.name
]
260 for b
in n
.data
.bones
:
262 _extendb( tree
, b
, d
+1 )
264 for obj1
in n
.children
:
265 _extend( tree
, obj1
, d
+1 )
267 p
["children"] += [tree
]
268 graph_lookup
[n
] = tree
270 _extend( graph
, obj
, 1 )
274 for c
in p
['children']:
276 yield from _graph_iter(c
)
278 it
= _graph_iter(graph
)
280 root
.children
= len(graph
['children'])
283 # ==============================================
284 it
= _graph_iter(graph
)
285 print( " compiling data" )
287 if 'obj' in node_def
:
288 obj
= node_def
['obj']
291 elif 'bone' in node_def
:
292 obj
= node_def
['bone']
294 objco
= obj
.head_local
296 depth
= node_def
['depth']
297 uid
= node_def
['uid']
300 node
.co
[0] = objco
[0]
301 node
.co
[1] = objco
[2]
302 node
.co
[2] = -objco
[1]
304 # Convert rotation quat to our space type
305 quat
= obj
.matrix_local
.to_quaternion()
312 node
.s
[0] = obj
.tail
[0]
313 node
.s
[1] = obj
.tail
[2]
314 node
.s
[2] = -obj
.tail
[1]
316 node
.s
[0] = obj
.scale
[0]
317 node
.s
[1] = obj
.scale
[2]
318 node
.s
[2] = obj
.scale
[1]
320 node
.pstr_name
= emplace_string( obj
.name
)
323 classtype
= 'k_classtype_bone'
324 elif objt
== 'ARMATURE':
325 classtype
= 'k_classtype_skeleton'
327 classtype
= obj
.cv_data
.classtype
330 # =================================================================
333 # Dont use the cache if we have modifiers that affect the normals
341 for mod
in obj
.modifiers
:
342 if mod
.type == 'DATA_TRANSFER' or mod
.type == 'SHRINKWRAP':
343 can_use_cache
= False
345 if mod
.type == 'ARMATURE':
346 classtype
= 'k_classtype_skin'
347 armature_def
= graph_lookup
[mod
.object]
349 if can_use_cache
and obj
.data
.name
in mesh_cache
:
350 ref
= mesh_cache
[obj
.data
.name
]
351 node
.submesh_start
= ref
.submesh_start
352 node
.submesh_count
= ref
.submesh_count
356 node
.submesh_start
= header
.submesh_count
357 node
.submesh_count
= 0
359 default_mat
= c_uint32(69)
360 default_mat
.name
= ""
362 dgraph
= bpy
.context
.evaluated_depsgraph_get()
363 data
= obj
.evaluated_get(dgraph
).data
364 data
.calc_loop_triangles()
365 data
.calc_normals_split()
367 mat_list
= data
.materials
if len(data
.materials
) > 0 else [default_mat
]
368 for material_id
, mat
in enumerate(mat_list
):
372 sm
.indice_start
= header
.indice_count
373 sm
.vertex_start
= header
.vertex_count
376 sm
.material_id
= emplace_material( mat
)
379 sm
.bbx
[0][i
] = 999999
380 sm
.bbx
[1][i
] = -999999
384 # Write the vertex / indice data
386 for tri_index
, tri
in enumerate(data
.loop_triangles
):
387 if tri
.material_index
!= material_id
:
391 vert
= data
.vertices
[tri
.vertices
[j
]]
393 vi
= data
.loops
[li
].vertex_index
396 norm
= data
.loops
[li
].normal
398 colour
= (255,255,255,255)
403 uv
= data
.uv_layers
.active
.data
[li
].uv
405 if data
.vertex_colors
:
406 colour
= data
.vertex_colors
.active
.data
[li
].color
407 colour
= (int(colour
[0]*255.0),\
408 int(colour
[1]*255.0),\
409 int(colour
[2]*255.0),\
410 int(colour
[3]*255.0))
415 weight_groups
= sorted( data
.vertices
[vi
].groups
, key
= \
416 lambda a
: a
.weight
, reverse
=True )
419 if len(weight_groups
) > ml
:
420 g
= weight_groups
[ml
]
421 name
= obj
.vertex_groups
[g
.group
].name
425 groups
[ml
] = armature_def
['bones'].index(name
)
428 if len(weight_groups
) > 0:
429 inv_norm
= (1.0/tot
) * 65535.0
431 weights
[ml
] = int( weights
[ml
] * inv_norm
)
432 weights
[ml
] = min( weights
[ml
], 65535 )
433 weights
[ml
] = max( weights
[ml
], 0 )
436 m
= float(10**TOLERENCE
)
438 key
= (int(co
[0]*m
+0.5),\
460 indice_buffer
+= [boffa
[key
]]
462 index
= c_uint32(sm
.vertex_count
)
466 indice_buffer
+= [index
]
477 v
.colour
[0] = colour
[0]
478 v
.colour
[1] = colour
[1]
479 v
.colour
[2] = colour
[2]
480 v
.colour
[3] = colour
[3]
481 v
.weights
[0] = weights
[0]
482 v
.weights
[1] = weights
[1]
483 v
.weights
[2] = weights
[2]
484 v
.weights
[3] = weights
[3]
485 v
.groups
[0] = groups
[0]
486 v
.groups
[1] = groups
[1]
487 v
.groups
[2] = groups
[2]
488 v
.groups
[3] = groups
[3]
493 sm
.bbx
[0][i
] = min( sm
.bbx
[0][i
], v
.co
[i
] )
494 sm
.bbx
[1][i
] = max( sm
.bbx
[1][i
], v
.co
[i
] )
498 if sm
.vertex_count
== 0:
503 submesh_buffer
+= [sm
]
504 node
.submesh_count
+= 1
505 header
.submesh_count
+= 1
506 header
.vertex_count
+= sm
.vertex_count
507 header
.indice_count
+= sm
.indice_count
509 mesh_cache
[obj
.data
.name
] = node
511 # Process entity data
512 # ==================================================================
513 node
.offset
= entdata_length
515 if classtype
!= 'k_classtype_none':
520 s000
= F
" [{uid: 3}/{header.node_count-1}]" + " |"*(depth
-1)
521 s001
= F
" L {obj.name}"
525 if classtype
== 'k_classtype_skin':
526 s004
= F
"-> {armature_def['obj'].cv_data.uid}"
528 scmp
= F
"{s002:<32} {s003:<16} {s004}"
531 if classtype
== 'k_classtype_INSTANCE' or \
532 classtype
== 'k_classtype_BONE' or \
533 classtype
== 'k_classtype_SKELETON' or \
534 classtype
== 'k_classtype_SKIN':
535 print( "ERROR: user classtype cannot be _INSTANCE or _BONE" )
539 elif classtype
== 'k_classtype_skin':
542 armature
= armature_def
['obj']
543 entdata_length
+= sizeof( classtype_skin
)
545 skin
= classtype_skin()
546 skin
.skeleton
= armature
.cv_data
.uid
547 entdata_buffer
+= [skin
]
549 elif classtype
== 'k_classtype_skeleton':
551 entdata_length
+= sizeof( classtype_skeleton
)
553 skeleton
= classtype_skeleton()
554 skeleton
.anim_start
= 0
555 skeleton
.anim_count
= 0
557 entdata_buffer
+= [skeleton
]
559 elif classtype
== 'k_classtype_bone':
561 entdata_length
+= sizeof( classtype_bone
)
563 bone
= classtype_bone()
564 bone
.use_deform
= node_def
['deform']
565 entdata_buffer
+= [bone
]
567 elif classtype
== 'k_classtype_gate':
569 entdata_length
+= sizeof( classtype_gate
)
571 gate
= classtype_gate()
573 if obj
.cv_data
.target
!= None:
574 gate
.target
= obj
.cv_data
.target
.cv_data
.uid
576 if obj
.type == 'MESH':
577 gate
.dims
[0] = obj
.data
.cv_data
.v0
[0]
578 gate
.dims
[1] = obj
.data
.cv_data
.v0
[1]
579 gate
.dims
[2] = obj
.data
.cv_data
.v0
[2]
581 gate
.dims
[0] = obj
.cv_data
.v0
[0]
582 gate
.dims
[1] = obj
.cv_data
.v0
[1]
583 gate
.dims
[2] = obj
.cv_data
.v0
[2]
585 entdata_buffer
+= [gate
]
587 elif classtype
== 'k_classtype_block':
589 entdata_length
+= sizeof( classtype_block
)
591 source
= obj
.data
.cv_data
593 block
= classtype_block()
594 block
.bbx
[0][0] = source
.v0
[0]
595 block
.bbx
[0][1] = source
.v0
[2]
596 block
.bbx
[0][2] = -source
.v1
[1]
598 block
.bbx
[1][0] = source
.v1
[0]
599 block
.bbx
[1][1] = source
.v1
[2]
600 block
.bbx
[1][2] = -source
.v0
[1]
601 entdata_buffer
+= [block
]
603 elif classtype
== 'k_classtype_spawn':
606 elif classtype
== 'k_classtype_water':
609 elif classtype
== 'k_classtype_car_path':
611 entdata_length
+= sizeof( classtype_car_path
)
613 pn
= classtype_car_path()
617 if obj
.cv_data
.target
!= None:
618 pn
.target
= obj
.cv_data
.target
.cv_data
.uid
619 if obj
.cv_data
.target1
!= None:
620 pn
.target1
= obj
.cv_data
.target1
.cv_data
.uid
622 entdata_buffer
+= [pn
]
624 elif obj
.is_instancer
:
625 target
= obj
.instance_collection
628 entdata_length
+= sizeof( classtype_instance
)
630 inst
= classtype_instance()
631 inst
.pstr_file
= emplace_string( F
"models/{target.name}.mdl" )
632 entdata_buffer
+= [inst
]
634 elif classtype
== 'k_classtype_capsule':
637 elif classtype
== 'k_classtype_route_node':
639 entdata_length
+= sizeof( classtype_route_node
)
641 rn
= classtype_route_node()
642 if obj
.cv_data
.target
!= None:
643 rn
.target
= obj
.cv_data
.target
.cv_data
.uid
644 if obj
.cv_data
.target1
!= None:
645 rn
.target1
= obj
.cv_data
.target1
.cv_data
.uid
647 entdata_buffer
+= [rn
]
649 elif classtype
== 'k_classtype_route':
651 entdata_length
+= sizeof( classtype_route
)
652 r
= classtype_route()
653 r
.pstr_name
= emplace_string("not-implemented")
654 r
.colour
[0] = obj
.cv_data
.colour
[0]
655 r
.colour
[1] = obj
.cv_data
.colour
[1]
656 r
.colour
[2] = obj
.cv_data
.colour
[2]
658 if obj
.cv_data
.target
!= None:
659 r
.id_start
= obj
.cv_data
.target
.cv_data
.uid
661 entdata_buffer
+= [r
]
663 # classtype == 'k_classtype_none':
668 node_buffer
+= [node
]
672 print( "Writing data" )
673 fpos
= sizeof(header
)
675 print( F
"Nodes: {header.node_count}" )
676 header
.node_offset
= fpos
677 fpos
+= sizeof(mdl_node
)*header
.node_count
679 print( F
"Submeshes: {header.submesh_count}" )
680 header
.submesh_offset
= fpos
681 fpos
+= sizeof(mdl_submesh
)*header
.submesh_count
683 print( F
"Materials: {header.material_count}" )
684 header
.material_offset
= fpos
685 fpos
+= sizeof(mdl_material
)*header
.material_count
687 print( F
"Entdata length: {entdata_length}" )
688 header
.entdata_offset
= fpos
689 fpos
+= entdata_length
691 print( F
"Vertex count: {header.vertex_count}" )
692 header
.vertex_offset
= fpos
693 fpos
+= sizeof(mdl_vert
)*header
.vertex_count
695 print( F
"Indice count: {header.indice_count}" )
696 header
.indice_offset
= fpos
697 fpos
+= sizeof(c_uint32
)*header
.indice_count
699 print( F
"Strings length: {len(strings_buffer)}" )
700 header
.strings_offset
= fpos
701 fpos
+= len(strings_buffer
)
703 header
.file_length
= fpos
705 path
= F
"/home/harry/Documents/carve/models_src/{collection_name}.mdl"
706 fp
= open( path
, "wb" )
708 fp
.write( bytearray( header
) )
710 for node
in node_buffer
:
711 fp
.write( bytearray(node
) )
712 for sm
in submesh_buffer
:
713 fp
.write( bytearray(sm
) )
714 for mat
in material_buffer
:
715 fp
.write( bytearray(mat
) )
716 for ed
in entdata_buffer
:
717 fp
.write( bytearray(ed
) )
718 for v
in vertex_buffer
:
719 fp
.write( bytearray(v
) )
720 for i
in indice_buffer
:
721 fp
.write( bytearray(i
) )
722 fp
.write( strings_buffer
)
725 print( F
"Completed {collection_name}.mdl" )
728 # ------------------------------------------------------------------------------
730 cv_view_draw_handler
= None
731 cv_view_shader
= gpu
.shader
.from_builtin('3D_SMOOTH_COLOR')
734 global cv_view_shader
735 cv_view_shader
.bind()
736 gpu
.state
.depth_mask_set(False)
737 gpu
.state
.line_width_set(2.0)
738 gpu
.state
.face_culling_set('BACK')
739 gpu
.state
.depth_test_set('LESS')
740 gpu
.state
.blend_set('NONE')
745 #def drawbezier(p0,h0,p1,h1,c0,c1):
746 # nonlocal verts, colours
750 # colours += [(0.5,0.5,0.5,1.0),(0.5,0.5,0.5,1)]
753 # colours += [(1.0,1.0,1,1),(1,1,1,1)]
756 # for i in range(10):
762 # p=ttt*p1+(3*tt-3*ttt)*h1+(3*ttt-6*tt+3*t)*h0+(3*tt-ttt-3*t+1)*p0
763 # verts += [(last[0],last[1],last[2])]
764 # verts += [(p[0],p[1],p[2])]
765 # colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)]
770 def drawbhandle(obj
, direction
, colour
):
771 nonlocal verts
, colours
773 h0
= obj
.matrix_world
@ Vector((0,direction
,0))
776 colours
+= [colour
,colour
]
778 def drawbezier(p0
,h0
,p1
,h1
,c0
,c1
):
779 nonlocal verts
, colours
788 p
=ttt
*p1
+(3*tt
-3*ttt
)*h1
+(3*ttt
-6*tt
+3*t
)*h0
+(3*tt
-ttt
-3*t
+1)*p0
789 verts
+= [(last
[0],last
[1],last
[2])]
790 verts
+= [(p
[0],p
[1],p
[2])]
791 colours
+= [c0
*a0
+c1
*(1-a0
),c0
*a0
+c1
*(1-a0
)]
794 def drawsbpath(o0
,o1
,c0
,c1
,s0
,s1
):
795 nonlocal course_count
797 offs
= ((course_count
% 2)*2-1) * course_count
* 0.02
799 p0
= o0
.matrix_world
@ Vector((offs
, 0,0))
800 h0
= o0
.matrix_world
@ Vector((offs
, s0
,0))
801 p1
= o1
.matrix_world
@ Vector((offs
, 0,0))
802 h1
= o1
.matrix_world
@ Vector((offs
,-s1
,0))
803 drawbezier(p0
,h0
,p1
,h1
,c0
,c1
)
805 def drawbpath(o0
,o1
,c0
,c1
):
806 drawsbpath(o0
,o1
,c0
,c1
,1.0,1.0)
808 def drawbline(p0
,p1
,c0
,c1
):
809 nonlocal verts
, colours
813 for obj
in bpy
.context
.collection
.objects
:
815 if obj
.cv_data
.classtype
== 'k_classtype_gate':
816 if obj
.type == 'MESH':
817 dims
= obj
.data
.cv_data
.v0
819 dims
= obj
.cv_data
.v0
822 c
= Vector((0,0,dims
[2]))
824 vs
[0] = obj
.matrix_world
@ Vector((-dims
[0],0.0,-dims
[1]+dims
[2]))
825 vs
[1] = obj
.matrix_world
@ Vector((-dims
[0],0.0, dims
[1]+dims
[2]))
826 vs
[2] = obj
.matrix_world
@ Vector(( dims
[0],0.0, dims
[1]+dims
[2]))
827 vs
[3] = obj
.matrix_world
@ Vector(( dims
[0],0.0,-dims
[1]+dims
[2]))
828 vs
[4] = obj
.matrix_world
@ (c
+Vector((-1,0,-2)))
829 vs
[5] = obj
.matrix_world
@ (c
+Vector((-1,0, 2)))
830 vs
[6] = obj
.matrix_world
@ (c
+Vector(( 1,0, 2)))
831 vs
[7] = obj
.matrix_world
@ (c
+Vector((-1,0, 0)))
832 vs
[8] = obj
.matrix_world
@ (c
+Vector(( 1,0, 0)))
834 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)]
839 verts
+= [(v0
[0],v0
[1],v0
[2])]
840 verts
+= [(v1
[0],v1
[1],v1
[2])]
841 colours
+= [(1,1,0,1),(1,1,0,1)]
843 sw
= (0.4,0.4,0.4,0.2)
844 if obj
.cv_data
.target
!= None:
845 drawbline( obj
.location
, obj
.cv_data
.target
.location
, sw
,sw
)
847 elif obj
.cv_data
.classtype
== 'k_classtype_route_node':
848 sw
= Vector((0.4,0.4,0.4,0.2))
849 sw2
= Vector((1.5,0.2,0.2,0.0))
850 if obj
.cv_data
.target
!= None:
851 drawbpath( obj
, obj
.cv_data
.target
, sw
, sw
)
852 if obj
.cv_data
.target1
!= None:
853 drawbpath( obj
, obj
.cv_data
.target1
, sw
, sw
)
855 drawbhandle( obj
, 1.0, (0.8,0.8,0.8,1.0) )
856 drawbhandle( obj
, -1.0, (0.4,0.4,0.4,1.0) )
859 obj
.matrix_world
.to_quaternion() @ Vector((0,0,-6+1.5))
860 drawbline( obj
.location
, p1
, sw
,sw2
)
863 elif obj
.cv_data
.classtype
== 'k_classtype_block':
864 a
= obj
.data
.cv_data
.v0
865 b
= obj
.data
.cv_data
.v1
868 vs
[0] = obj
.matrix_world
@ Vector((a
[0], a
[1], a
[2]))
869 vs
[1] = obj
.matrix_world
@ Vector((a
[0], b
[1], a
[2]))
870 vs
[2] = obj
.matrix_world
@ Vector((b
[0], b
[1], a
[2]))
871 vs
[3] = obj
.matrix_world
@ Vector((b
[0], a
[1], a
[2]))
872 vs
[4] = obj
.matrix_world
@ Vector((a
[0], a
[1], b
[2]))
873 vs
[5] = obj
.matrix_world
@ Vector((a
[0], b
[1], b
[2]))
874 vs
[6] = obj
.matrix_world
@ Vector((b
[0], b
[1], b
[2]))
875 vs
[7] = obj
.matrix_world
@ Vector((b
[0], a
[1], b
[2]))
877 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\
878 (0,4),(1,5),(2,6),(3,7)]
883 verts
+= [(v0
[0],v0
[1],v0
[2])]
884 verts
+= [(v1
[0],v1
[1],v1
[2])]
885 colours
+= [(1,1,0,1),(1,1,0,1)]
887 elif obj
.cv_data
.classtype
== 'k_classtype_capsule':
888 h
= obj
.data
.cv_data
.v0
[0]
889 r
= obj
.data
.cv_data
.v0
[1]
892 vs
[0] = obj
.matrix_world
@ Vector((0.0,0.0, h
*0.5 ))
893 vs
[1] = obj
.matrix_world
@ Vector((0.0,0.0,-h
*0.5 ))
894 vs
[2] = obj
.matrix_world
@ Vector(( r
,0.0, h
*0.5-r
))
895 vs
[3] = obj
.matrix_world
@ Vector(( -r
,0.0, h
*0.5-r
))
896 vs
[4] = obj
.matrix_world
@ Vector(( r
,0.0,-h
*0.5+r
))
897 vs
[5] = obj
.matrix_world
@ Vector(( -r
,0.0,-h
*0.5+r
))
898 vs
[6] = obj
.matrix_world
@ Vector((0.0, r
, h
*0.5-r
))
899 vs
[7] = obj
.matrix_world
@ Vector((0.0,-r
, h
*0.5-r
))
900 vs
[8] = obj
.matrix_world
@ Vector((0.0, r
,-h
*0.5+r
))
901 vs
[9] = obj
.matrix_world
@ Vector((0.0,-r
,-h
*0.5+r
))
903 indices
= [(0,1),(2,3),(4,5),(6,7),(8,9)]
908 verts
+= [(v0
[0],v0
[1],v0
[2])]
909 verts
+= [(v1
[0],v1
[1],v1
[2])]
910 colours
+= [(0.5,1,0,1),(0.5,1,0,1)]
912 elif obj
.cv_data
.classtype
== 'k_classtype_spawn':
914 vs
[0] = obj
.matrix_world
@ Vector((0,0,0))
915 vs
[1] = obj
.matrix_world
@ Vector((0,2,0))
916 vs
[2] = obj
.matrix_world
@ Vector((0.5,1,0))
917 vs
[3] = obj
.matrix_world
@ Vector((-0.5,1,0))
918 indices
= [(0,1),(1,2),(1,3)]
922 verts
+= [(v0
[0],v0
[1],v0
[2])]
923 verts
+= [(v1
[0],v1
[1],v1
[2])]
924 colours
+= [(0,1,1,1),(0,1,1,1)]
926 elif obj
.cv_data
.classtype
== 'k_classtype_route':
929 vs
[1] = obj
.cv_data
.target
.location
934 verts
+= [(v0
[0],v0
[1],v0
[2])]
935 verts
+= [(v1
[0],v1
[1],v1
[2])]
936 colours
+= [(0,1,1,1),(0,1,1,1)]
940 stack
[0] = obj
.cv_data
.target
942 loop_complete
= False
945 if stack_i
[si
-1] == 2:
949 if si
== 0: # Loop failed to complete
954 targets
= [None,None]
955 targets
[0] = node
.cv_data
.target
957 if node
.cv_data
.classtype
== 'k_classtype_route_node':
958 targets
[1] = node
.cv_data
.target1
960 nextnode
= targets
[stack_i
[si
-1]]
963 if nextnode
!= None: # branch
964 if nextnode
== stack
[0]: # Loop completed
970 if stack
[sj
] == nextnode
: # invalidated path
981 cc
= Vector((obj
.cv_data
.colour
[0],\
982 obj
.cv_data
.colour
[1],\
983 obj
.cv_data
.colour
[2],\
989 if stack
[sj
].cv_data
.classtype
== 'k_classtype_gate' and \
990 stack
[sk
].cv_data
.classtype
== 'k_classtype_gate':
991 dist
= (stack
[sj
].location
-stack
[sk
].location
).magnitude
992 drawsbpath( stack
[sj
], stack
[sk
], cc
*0.4, cc
, dist
, dist
)
995 drawbpath( stack
[sj
], stack
[sk
], cc
, cc
)
999 elif obj
.cv_data
.classtype
== 'k_classtype_car_path':
1000 v0
= obj
.matrix_world
.to_quaternion() @ Vector((0,1,0))
1001 c0
= Vector((v0
.x
*0.5+0.5, v0
.y
*0.5+0.5, 0.0, 1.0))
1002 drawbhandle( obj
, 1.0, (0.9,0.9,0.9,1.0) )
1004 if obj
.cv_data
.target
!= None:
1005 v1
= obj
.cv_data
.target
.matrix_world
.to_quaternion()@Vector((0,1,0))
1006 c1
= Vector((v1
.x
*0.5+0.5, v1
.y
*0.5+0.5, 0.0, 1.0))
1008 drawbhandle( obj
.cv_data
.target
, -1.0, (0.5,0.5,0.5,1.0) )
1009 drawbpath( obj
, obj
.cv_data
.target
, c0
, c1
)
1011 if obj
.cv_data
.target1
!= None:
1012 v1
= obj
.cv_data
.target1
.matrix_world
.to_quaternion()@Vector((0,1,0))
1013 c1
= Vector((v1
.x
*0.5+0.5, v1
.y
*0.5+0.5, 0.0, 1.0))
1015 drawbhandle( obj
.cv_data
.target1
, -1.0, (0.5,0.5,0.5,1.0) )
1016 drawbpath( obj
, obj
.cv_data
.target1
, c0
, c1
)
1018 lines
= batch_for_shader(\
1019 cv_view_shader
, 'LINES', \
1020 { "pos":verts
, "color":colours
})
1022 lines
.draw( cv_view_shader
)
1024 def cv_poll_target(scene
, obj
):
1025 if obj
== bpy
.context
.active_object
:
1027 if obj
.cv_data
.classtype
== 'k_classtype_none':
1031 class CV_MESH_SETTINGS(bpy
.types
.PropertyGroup
):
1032 v0
: bpy
.props
.FloatVectorProperty(name
="v0",size
=3)
1033 v1
: bpy
.props
.FloatVectorProperty(name
="v1",size
=3)
1034 v2
: bpy
.props
.FloatVectorProperty(name
="v2",size
=3)
1035 v3
: bpy
.props
.FloatVectorProperty(name
="v3",size
=3)
1037 class CV_OBJ_SETTINGS(bpy
.types
.PropertyGroup
):
1038 uid
: bpy
.props
.IntProperty( name
="" )
1040 target
: bpy
.props
.PointerProperty( type=bpy
.types
.Object
, name
="target", \
1041 poll
=cv_poll_target
)
1042 target1
: bpy
.props
.PointerProperty( type=bpy
.types
.Object
, name
="target1", \
1043 poll
=cv_poll_target
)
1045 colour
: bpy
.props
.FloatVectorProperty(name
="colour",subtype
='COLOR',\
1048 classtype
: bpy
.props
.EnumProperty(
1051 ('k_classtype_none', "k_classtype_none", "", 0),
1052 ('k_classtype_gate', "k_classtype_gate", "", 1),
1053 ('k_classtype_block', "k_classtype_block", "", 2),
1054 ('k_classtype_spawn', "k_classtype_spawn", "", 3),
1055 ('k_classtype_water', "k_classtype_water", "", 4),
1056 ('k_classtype_car_path', "k_classtype_car_path", "", 5),
1057 ('k_classtype_INSTANCE', "","", 6 ),
1058 ('k_classtype_capsule', "k_classtype_capsule", "", 7 ),
1059 ('k_classtype_route_node', "k_classtype_route_node", "", 8 ),
1060 ('k_classtype_route', "k_classtype_route", "", 9 ),
1061 ('k_classtype_bone',"k_classtype_bone","",10),
1062 ('k_classtype_SKELETON', "","", 11 ),
1063 ('k_classtype_SKIN',"","",12)
1066 class CV_SCENE_SETTINGS(bpy
.types
.PropertyGroup
):
1067 use_hidden
: bpy
.props
.BoolProperty( name
="use hidden", default
=False )
1069 class CV_OBJ_PANEL(bpy
.types
.Panel
):
1070 bl_label
="Entity Config"
1071 bl_idname
="SCENE_PT_cv_entity"
1072 bl_space_type
='PROPERTIES'
1073 bl_region_type
='WINDOW'
1076 def draw(_
,context
):
1077 active_object
= bpy
.context
.active_object
1078 if active_object
== None: return
1079 _
.layout
.prop( active_object
.cv_data
, "classtype" )
1081 if active_object
.cv_data
.classtype
== 'k_classtype_gate':
1082 _
.layout
.prop( active_object
.cv_data
, "target" )
1084 mesh
= active_object
.data
1085 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1086 _
.layout
.prop( mesh
.cv_data
, "v0" )
1088 elif active_object
.cv_data
.classtype
== 'k_classtype_car_path' or \
1089 active_object
.cv_data
.classtype
== 'k_classtype_route_node':
1090 _
.layout
.prop( active_object
.cv_data
, "target" )
1091 _
.layout
.prop( active_object
.cv_data
, "target1" )
1093 elif active_object
.cv_data
.classtype
== 'k_classtype_route':
1094 _
.layout
.prop( active_object
.cv_data
, "target" )
1095 _
.layout
.prop( active_object
.cv_data
, "colour" )
1097 elif active_object
.cv_data
.classtype
== 'k_classtype_block':
1098 mesh
= active_object
.data
1100 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1101 _
.layout
.prop( mesh
.cv_data
, "v0" )
1102 _
.layout
.prop( mesh
.cv_data
, "v1" )
1103 _
.layout
.prop( mesh
.cv_data
, "v2" )
1104 _
.layout
.prop( mesh
.cv_data
, "v3" )
1105 elif active_object
.cv_data
.classtype
== 'k_classtype_capsule':
1106 mesh
= active_object
.data
1107 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1108 _
.layout
.prop( mesh
.cv_data
, "v0" )
1110 class CV_INTERFACE(bpy
.types
.Panel
):
1111 bl_idname
= "VIEW3D_PT_carve"
1113 bl_space_type
= 'VIEW_3D'
1114 bl_region_type
= 'UI'
1115 bl_category
= "Carve"
1117 def draw(_
, context
):
1119 layout
.prop( context
.scene
.cv_data
, "use_hidden")
1120 layout
.operator( "carve.compile_all" )
1123 view_layer
= bpy
.context
.view_layer
1124 for col
in view_layer
.layer_collection
.children
["export"].children
:
1125 if not col
.hide_viewport
or bpy
.context
.scene
.cv_data
.use_hidden
:
1126 write_model( col
.name
)
1128 class CV_COMPILE(bpy
.types
.Operator
):
1129 bl_idname
="carve.compile_all"
1130 bl_label
="Compile All"
1132 def execute(_
,context
):
1134 #cProfile.runctx("test_compile()",globals(),locals(),sort=1)
1135 #for col in bpy.data.collections["export"].children:
1136 # write_model( col.name )
1140 classes
= [CV_OBJ_SETTINGS
,CV_OBJ_PANEL
,CV_COMPILE
,CV_INTERFACE
,\
1141 CV_MESH_SETTINGS
, CV_SCENE_SETTINGS
]
1144 global cv_view_draw_handler
1147 bpy
.utils
.register_class(c
)
1149 bpy
.types
.Object
.cv_data
= bpy
.props
.PointerProperty(type=CV_OBJ_SETTINGS
)
1150 bpy
.types
.Mesh
.cv_data
= bpy
.props
.PointerProperty(type=CV_MESH_SETTINGS
)
1151 bpy
.types
.Scene
.cv_data
= bpy
.props
.PointerProperty(type=CV_SCENE_SETTINGS
)
1153 cv_view_draw_handler
= bpy
.types
.SpaceView3D
.draw_handler_add(\
1154 cv_draw
,(),'WINDOW','POST_VIEW')
1157 global cv_view_draw_handler
1160 bpy
.utils
.unregister_class(c
)
1162 bpy
.types
.SpaceView3D
.draw_handler_remove(cv_view_draw_handler
,'WINDOW')