2 # Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
8 from mathutils
import *
9 from gpu_extras
.batch
import batch_for_shader
12 "name":"Carve exporter",
13 "author": "Harry Godden (hgn)",
20 "category":"Import/Export",
23 class mdl_vert(Structure
):
25 _fields_
= [("co",c_float
*3),
29 ("weights",c_uint16
*4),
32 class mdl_submesh(Structure
):
34 _fields_
= [("indice_start",c_uint32
),
35 ("indice_count",c_uint32
),
36 ("vertex_start",c_uint32
),
37 ("vertex_count",c_uint32
),
38 ("bbx",(c_float
*3)*2),
39 ("material_id",c_uint32
)] # index into the material array
41 class mdl_material(Structure
):
43 _fields_
= [("pstr_name",c_uint32
)]
45 class mdl_node(Structure
):
47 _fields_
= [("co",c_float
*3),
50 ("sub_uid",c_uint32
), # dont use
51 ("submesh_start",c_uint32
),
52 ("submesh_count",c_uint32
),
53 ("classtype",c_uint32
),
56 ("pstr_name",c_uint32
)]
58 class mdl_header(Structure
):
60 _fields_
= [("identifier",c_uint32
),
62 ("file_length",c_uint32
),
65 ("vertex_count",c_uint32
),
66 ("vertex_offset",c_uint32
),
68 ("indice_count",c_uint32
),
69 ("indice_offset",c_uint32
),
71 ("submesh_count",c_uint32
),
72 ("submesh_offset",c_uint32
),
74 ("material_count",c_uint32
),
75 ("material_offset",c_uint32
),
77 ("node_count",c_uint32
),
78 ("node_offset",c_uint32
),
80 ("anim_count",c_uint32
),
81 ("anim_offset",c_uint32
),
83 ("strings_length",c_uint32
),
84 ("strings_offset",c_uint32
),
86 ("entdata_length",c_uint32
),
87 ("entdata_offset",c_uint32
),
89 ("keyframe_count",c_uint32
),
90 ("keyframe_offset",c_uint32
)]
93 class mdl_animation(Structure
):
95 _fields_
= [("pstr_name",c_uint32
),
100 class mdl_keyframe(Structure
):
102 _fields_
= [("co",c_float
*3),
107 # ==========================================
109 class classtype_gate(Structure
):
111 _fields_
= [("target",c_uint32
),
114 class classtype_block(Structure
):
116 _fields_
= [("bbx",(c_float
*3)*2)]
118 class classtype_spawn(Structure
):
120 _fields_
= [("temp",c_uint32
)]
122 class classtype_water(Structure
):
124 _fields_
= [("temp",c_uint32
)]
126 class classtype_car_path(Structure
):
128 _fields_
= [("target",c_uint32
),
129 ("target1",c_uint32
)]
131 class classtype_instance(Structure
):
133 _fields_
= [("pstr_file",c_uint32
)]
135 class classtype_capsule(Structure
):
137 _fields_
= [("height",c_float
),
140 class classtype_route_node(Structure
):
142 _fields_
= [("target",c_uint32
),
143 ("target1",c_uint32
)]
145 class classtype_route(Structure
):
147 _fields_
= [("id_start",c_uint32
),
148 ("colour",c_float
*3)]
150 class classtype_skin(Structure
):
152 _fields_
= [("skeleton",c_uint32
)]
154 class classtype_skeleton(Structure
):
156 _fields_
= [("channels",c_uint32
),
157 ("ik_count",c_uint32
),
158 ("collider_count",c_uint32
),
159 ("anim_start",c_uint32
),
160 ("anim_count",c_uint32
)]
162 class classtype_bone(Structure
):
164 _fields_
= [("deform",c_uint32
),
165 ("ik_target",c_uint32
),
166 ("ik_pole",c_uint32
),
167 ("collider",c_uint32
),
168 ("use_limits",c_uint32
),
169 ("angle_limits",(c_float
*3)*2),
170 ("hitbox",(c_float
*3)*2)]
172 class classtype_achievement_box(Structure
):
174 _fields_
= [("pstr_name",c_uint32
),
175 ("trigger",c_uint32
)]
177 class classtype_audio(Structure
):
179 _fields_
= [("pstr_file",c_uint32
),
184 # ==============================================================================
186 def write_model(collection_name
):
187 print( F
"Model graph | Create mode '{collection_name}'" )
189 header
= mdl_header()
190 header
.identifier
= 0xABCD0000
192 header
.vertex_count
= 0
193 header
.indice_count
= 0
194 header
.submesh_count
= 0
195 header
.node_count
= 0
196 header
.material_count
= 0
197 header
.file_length
= 0
199 header
.strings_length
= 0
200 header
.entdata_length
= 0
201 header
.keyframe_count
= 0
219 def emplace_string( s
):
220 nonlocal string_cache
, strings_buffer
222 if s
in string_cache
:
223 return string_cache
[s
]
225 string_cache
[s
] = len( strings_buffer
)
226 strings_buffer
+= (s
+'\0').encode('utf-8')
227 return string_cache
[s
]
229 def emplace_material( mat
):
230 nonlocal material_cache
, material_buffer
235 if mat
.name
in material_cache
:
236 return material_cache
[mat
.name
]
238 material_cache
[mat
.name
] = header
.material_count
239 dest
= mdl_material()
240 dest
.pstr_name
= emplace_string( mat
.name
)
241 material_buffer
+= [dest
]
243 header
.material_count
+= 1
244 return material_cache
[mat
.name
]
246 # Create root or empty node and materials
247 # this is to designate id 0 as 'NULL'
249 none_material
= c_uint32(69)
250 none_material
.name
= ""
251 emplace_material( none_material
)
264 root
.pstr_name
= emplace_string('')
265 root
.submesh_start
= 0
266 root
.submesh_count
= 0
269 node_buffer
+= [root
]
273 print( " assigning ids" )
274 collection
= bpy
.data
.collections
[collection_name
]
277 # ==========================================
279 header
.node_count
= 0
282 uid
= header
.node_count
283 header
.node_count
+= 1
286 print( " creating scene graph" )
290 graph
["children"] = []
291 graph
["uid"] = _uid()
292 graph
["parent"] = None
294 graph_lookup
= {} # object can lookup its graph def here
296 for obj
in collection
.all_objects
:
299 def _extend( p
, n
, d
):
303 tree
["children"] = []
309 if n
.type == 'ARMATURE':
310 tree
["bones"] = [None] # None is the root transform
312 tree
["collider_count"] = 0
314 def _extendb( p
, n
, d
):
319 btree
["uid"] = _uid()
320 btree
["children"] = []
323 tree
["bones"] += [n
.name
]
326 _extendb( btree
, c
, d
+1 )
328 for c
in tree
['obj'].pose
.bones
[n
.name
].constraints
:
330 btree
["target"] = c
.subtarget
331 btree
["pole"] = c
.pole_subtarget
332 tree
["ik_count"] += 1
334 if n
.cv_data
.collider
:
335 tree
['collider_count'] += 1
337 btree
['deform'] = n
.use_deform
338 p
['children'] += [btree
]
340 for b
in n
.data
.bones
:
342 _extendb( tree
, b
, d
+1 )
344 for obj1
in n
.children
:
346 for c1
in obj1
.users_collection
:
348 _extend( tree
, obj1
, d
+1 )
351 p
["children"] += [tree
]
352 graph_lookup
[n
] = tree
354 _extend( graph
, obj
, 1 )
358 for c
in p
['children']:
360 yield from _graph_iter(c
)
362 it
= _graph_iter(graph
)
364 root
.parent
= 0xffffffff
367 # ==============================================
368 it
= _graph_iter(graph
)
369 print( " compiling data" )
371 if 'obj' in node_def
:
372 obj
= node_def
['obj']
375 elif 'bone' in node_def
:
376 obj
= node_def
['bone']
378 objco
= obj
.head_local
380 depth
= node_def
['depth']
381 uid
= node_def
['uid']
384 node
.co
[0] = objco
[0]
385 node
.co
[1] = objco
[2]
386 node
.co
[2] = -objco
[1]
388 # Convert rotation quat to our space type
389 quat
= obj
.matrix_local
.to_quaternion()
396 node
.s
[0] = obj
.tail_local
[0] - node
.co
[0]
397 node
.s
[1] = obj
.tail_local
[2] - node
.co
[1]
398 node
.s
[2] = -obj
.tail_local
[1] - node
.co
[2]
400 node
.s
[0] = obj
.scale
[0]
401 node
.s
[1] = obj
.scale
[2]
402 node
.s
[2] = obj
.scale
[1]
404 node
.pstr_name
= emplace_string( obj
.name
)
406 if node_def
["parent"]:
407 node
.parent
= node_def
["parent"]["uid"]
410 classtype
= 'k_classtype_bone'
411 elif objt
== 'ARMATURE':
412 classtype
= 'k_classtype_skeleton'
414 classtype
= obj
.cv_data
.classtype
417 # =================================================================
420 # Dont use the cache if we have modifiers that affect the normals
428 for mod
in obj
.modifiers
:
429 if mod
.type == 'DATA_TRANSFER' or mod
.type == 'SHRINKWRAP' or \
430 mod
.type == 'BOOLEAN' or mod
.type == 'CURVE' or \
432 can_use_cache
= False
434 if mod
.type == 'ARMATURE':
435 classtype
= 'k_classtype_skin'
436 armature_def
= graph_lookup
[mod
.object]
437 POSE_OR_REST_CACHE
= armature_def
['obj'].data
.pose_position
439 armature_def
['obj'].data
.pose_position
= 'REST'
441 if can_use_cache
and obj
.data
.name
in mesh_cache
:
442 ref
= mesh_cache
[obj
.data
.name
]
443 node
.submesh_start
= ref
.submesh_start
444 node
.submesh_count
= ref
.submesh_count
448 node
.submesh_start
= header
.submesh_count
449 node
.submesh_count
= 0
451 default_mat
= c_uint32(69)
452 default_mat
.name
= ""
454 dgraph
= bpy
.context
.evaluated_depsgraph_get()
455 data
= obj
.evaluated_get(dgraph
).data
456 data
.calc_loop_triangles()
457 data
.calc_normals_split()
459 mat_list
= data
.materials
if len(data
.materials
) > 0 else [default_mat
]
460 for material_id
, mat
in enumerate(mat_list
):
464 sm
.indice_start
= header
.indice_count
465 sm
.vertex_start
= header
.vertex_count
468 sm
.material_id
= emplace_material( mat
)
471 sm
.bbx
[0][i
] = 999999
472 sm
.bbx
[1][i
] = -999999
476 # Write the vertex / indice data
478 for tri_index
, tri
in enumerate(data
.loop_triangles
):
479 if tri
.material_index
!= material_id
:
483 vert
= data
.vertices
[tri
.vertices
[j
]]
485 vi
= data
.loops
[li
].vertex_index
488 norm
= data
.loops
[li
].normal
490 colour
= (255,255,255,255)
495 uv
= data
.uv_layers
.active
.data
[li
].uv
497 if data
.vertex_colors
:
498 colour
= data
.vertex_colors
.active
.data
[li
].color
499 colour
= (int(colour
[0]*255.0),\
500 int(colour
[1]*255.0),\
501 int(colour
[2]*255.0),\
502 int(colour
[3]*255.0))
507 src_groups
= [_
for _
in data
.vertices
[vi
].groups \
508 if obj
.vertex_groups
[_
.group
].name
in \
509 armature_def
['bones']]
511 weight_groups
= sorted( src_groups
, key
= \
512 lambda a
: a
.weight
, reverse
=True )
515 if len(weight_groups
) > ml
:
516 g
= weight_groups
[ml
]
517 name
= obj
.vertex_groups
[g
.group
].name
521 groups
[ml
] = armature_def
['bones'].index(name
)
524 if len(weight_groups
) > 0:
525 inv_norm
= (1.0/tot
) * 65535.0
527 weights
[ml
] = int( weights
[ml
] * inv_norm
)
528 weights
[ml
] = min( weights
[ml
], 65535 )
529 weights
[ml
] = max( weights
[ml
], 0 )
532 m
= float(10**TOLERENCE
)
534 key
= (int(co
[0]*m
+0.5),\
556 indice_buffer
+= [boffa
[key
]]
558 index
= c_uint32(sm
.vertex_count
)
562 indice_buffer
+= [index
]
573 v
.colour
[0] = colour
[0]
574 v
.colour
[1] = colour
[1]
575 v
.colour
[2] = colour
[2]
576 v
.colour
[3] = colour
[3]
577 v
.weights
[0] = weights
[0]
578 v
.weights
[1] = weights
[1]
579 v
.weights
[2] = weights
[2]
580 v
.weights
[3] = weights
[3]
581 v
.groups
[0] = groups
[0]
582 v
.groups
[1] = groups
[1]
583 v
.groups
[2] = groups
[2]
584 v
.groups
[3] = groups
[3]
589 sm
.bbx
[0][i
] = min( sm
.bbx
[0][i
], v
.co
[i
] )
590 sm
.bbx
[1][i
] = max( sm
.bbx
[1][i
], v
.co
[i
] )
594 if sm
.vertex_count
== 0:
599 submesh_buffer
+= [sm
]
600 node
.submesh_count
+= 1
601 header
.submesh_count
+= 1
602 header
.vertex_count
+= sm
.vertex_count
603 header
.indice_count
+= sm
.indice_count
605 mesh_cache
[obj
.data
.name
] = node
607 # Process entity data
608 # ==================================================================
609 node
.offset
= header
.entdata_length
611 if classtype
!= 'k_classtype_none':
616 s000
= F
" [{uid: 3}/{header.node_count-1}]" + " |"*(depth
-1)
617 s001
= F
" L {obj.name}"
620 s004
= F
"{node.parent: 3}"
623 if classtype
== 'k_classtype_skin':
624 armature_def
['obj'].data
.pose_position
= POSE_OR_REST_CACHE
625 s005
= F
" [armature -> {armature_def['obj'].cv_data.uid}]"
627 scmp
= F
"{s002:<32} {s003:<22} {s004} {s005}"
630 if classtype
== 'k_classtype_INSTANCE' or \
631 classtype
== 'k_classtype_BONE' or \
632 classtype
== 'k_classtype_SKELETON' or \
633 classtype
== 'k_classtype_SKIN':
634 print( "ERROR: user classtype cannot be _INSTANCE or _BONE" )
638 elif classtype
== 'k_classtype_skin':
641 armature
= armature_def
['obj']
642 header
.entdata_length
+= sizeof( classtype_skin
)
644 skin
= classtype_skin()
645 skin
.skeleton
= armature
.cv_data
.uid
646 entdata_buffer
+= [skin
]
648 elif classtype
== 'k_classtype_skeleton':
650 header
.entdata_length
+= sizeof( classtype_skeleton
)
651 skeleton
= classtype_skeleton()
653 armature_def
= graph_lookup
[obj
]
655 bones
= armature_def
['bones']
656 skeleton
.channels
= len(bones
)
657 skeleton
.ik_count
= armature_def
["ik_count"]
658 skeleton
.collider_count
= armature_def
["collider_count"]
660 if armature
.animation_data
:
661 previous_frame
= bpy
.context
.scene
.frame_current
662 previous_action
= armature
.animation_data
.action
664 skeleton
.anim_start
= len(anim_buffer
)
665 skeleton
.anim_count
= 0
667 for NLALayer
in obj
.animation_data
.nla_tracks
:
668 for NLAStrip
in NLALayer
.strips
:
670 for a
in bpy
.data
.actions
:
671 if a
.name
== NLAStrip
.name
:
672 armature
.animation_data
.action
= a
675 anim_start
= int(NLAStrip
.action_frame_start
)
676 anim_end
= int(NLAStrip
.action_frame_end
)
679 anim
= mdl_animation()
680 anim
.pstr_name
= emplace_string( NLAStrip
.action
.name
)
682 anim
.offset
= header
.keyframe_count
683 anim
.length
= anim_end
-anim_start
685 # Export the fucking keyframes
686 for frame
in range(anim_start
,anim_end
):
687 bpy
.context
.scene
.frame_set(frame
)
689 for bone_name
in bones
:
690 for pb
in armature
.pose
.bones
:
691 if pb
.name
== bone_name
:
692 rb
= armature
.data
.bones
[ bone_name
]
694 # relative bone matrix
695 if rb
.parent
is not None:
696 offset_mtx
= rb
.parent
.matrix_local
697 offset_mtx
= offset_mtx
.inverted_safe() @ \
700 inv_parent
= pb
.parent
.matrix
@ offset_mtx
701 inv_parent
.invert_safe()
702 fpm
= inv_parent
@ pb
.matrix
704 bone_mtx
= rb
.matrix
.to_4x4()
705 local_inv
= rb
.matrix_local
.inverted_safe()
706 fpm
= bone_mtx
@ local_inv
@ pb
.matrix
708 loc
, rot
, sca
= fpm
.decompose()
711 final_pos
= Vector(( loc
[0], loc
[2], -loc
[1] ))
714 lc_m
= pb
.matrix_channel
.to_3x3()
715 if pb
.parent
is not None:
716 smtx
= pb
.parent
.matrix_channel
.to_3x3()
717 lc_m
= smtx
.inverted() @ lc_m
718 rq
= lc_m
.to_quaternion()
721 kf
.co
[0] = final_pos
[0]
722 kf
.co
[1] = final_pos
[1]
723 kf
.co
[2] = final_pos
[2]
735 animdata_buffer
+= [kf
]
736 header
.keyframe_count
+= 1
739 anim_buffer
+= [anim
]
740 skeleton
.anim_count
+= 1
742 s000
= F
" [{uid: 3}/{header.node_count-1}]" + " |"*(depth
-1)
743 print( F
"{s000} | *anim: {NLAStrip.action.name}" )
745 bpy
.context
.scene
.frame_set( previous_frame
)
746 armature
.animation_data
.action
= previous_action
748 entdata_buffer
+= [skeleton
]
750 elif classtype
== 'k_classtype_bone':
752 header
.entdata_length
+= sizeof( classtype_bone
)
754 bone
= classtype_bone()
755 bone
.deform
= node_def
['deform']
757 if 'target' in node_def
:
758 bone
.ik_target
= armature_def
['bones'].index( node_def
['target'] )
759 bone
.ik_pole
= armature_def
['bones'].index( node_def
['pole'] )
764 bone
.collider
= 1 if obj
.cv_data
.collider
else 0
765 if obj
.cv_data
.collider
:
766 bone
.hitbox
[0][0] = obj
.cv_data
.v0
[0]
767 bone
.hitbox
[0][1] = obj
.cv_data
.v0
[2]
768 bone
.hitbox
[0][2] = -obj
.cv_data
.v1
[1]
769 bone
.hitbox
[1][0] = obj
.cv_data
.v1
[0]
770 bone
.hitbox
[1][1] = obj
.cv_data
.v1
[2]
771 bone
.hitbox
[1][2] = -obj
.cv_data
.v0
[1]
773 bone
.hitbox
[0][0] = 0.0
774 bone
.hitbox
[0][1] = 0.0
775 bone
.hitbox
[0][2] = 0.0
776 bone
.hitbox
[1][0] = 0.0
777 bone
.hitbox
[1][1] = 0.0
778 bone
.hitbox
[1][2] = 0.0
782 bone
.angle_limits
[0][0] = obj
.cv_data
.mins
[0]
783 bone
.angle_limits
[0][1] = obj
.cv_data
.mins
[2]
784 bone
.angle_limits
[0][2] = -obj
.cv_data
.maxs
[1]
785 bone
.angle_limits
[1][0] = obj
.cv_data
.maxs
[0]
786 bone
.angle_limits
[1][1] = obj
.cv_data
.maxs
[2]
787 bone
.angle_limits
[1][2] = -obj
.cv_data
.mins
[1]
790 bone
.angle_limits
[0][0] = 0.0
791 bone
.angle_limits
[0][1] = 0.0
792 bone
.angle_limits
[0][2] = 0.0
793 bone
.angle_limits
[1][0] = 0.0
794 bone
.angle_limits
[1][1] = 0.0
795 bone
.angle_limits
[1][2] = 0.0
797 bone
.deform
= node_def
['deform']
798 entdata_buffer
+= [bone
]
800 elif classtype
== 'k_classtype_gate':
802 header
.entdata_length
+= sizeof( classtype_gate
)
804 gate
= classtype_gate()
806 if obj
.cv_data
.target
!= None:
807 gate
.target
= obj
.cv_data
.target
.cv_data
.uid
809 if obj
.type == 'MESH':
810 gate
.dims
[0] = obj
.data
.cv_data
.v0
[0]
811 gate
.dims
[1] = obj
.data
.cv_data
.v0
[1]
812 gate
.dims
[2] = obj
.data
.cv_data
.v0
[2]
814 gate
.dims
[0] = obj
.cv_data
.v0
[0]
815 gate
.dims
[1] = obj
.cv_data
.v0
[1]
816 gate
.dims
[2] = obj
.cv_data
.v0
[2]
818 entdata_buffer
+= [gate
]
820 elif classtype
== 'k_classtype_block':
822 header
.entdata_length
+= sizeof( classtype_block
)
824 source
= obj
.data
.cv_data
826 block
= classtype_block()
827 block
.bbx
[0][0] = source
.v0
[0]
828 block
.bbx
[0][1] = source
.v0
[2]
829 block
.bbx
[0][2] = -source
.v1
[1]
831 block
.bbx
[1][0] = source
.v1
[0]
832 block
.bbx
[1][1] = source
.v1
[2]
833 block
.bbx
[1][2] = -source
.v0
[1]
834 entdata_buffer
+= [block
]
836 elif classtype
== 'k_classtype_achievement_box':
839 header
.entdata_length
+= sizeof( classtype_achievement_box
)
840 ach
= classtype_achievement_box()
841 ach
.pstr_name
= emplace_string( obj
.cv_data
.strp
)
844 if obj
.cv_data
.target
!= None:
845 ach
.trigger
= obj
.cv_data
.target
.cv_data
.uid
847 entdata_buffer
+= [ach
]
849 elif classtype
== 'k_classtype_audio':
852 header
.entdata_length
+= sizeof( classtype_audio
)
853 aud
= classtype_audio()
854 aud
.pstr_file
= emplace_string( obj
.cv_data
.strp
)
855 aud
.flags
= obj
.cv_data
.intp
856 aud
.volume
= obj
.cv_data
.fltp
858 entdata_buffer
+= [aud
]
860 elif classtype
== 'k_classtype_spawn':
863 elif classtype
== 'k_classtype_water':
866 elif classtype
== 'k_classtype_car_path':
868 header
.entdata_length
+= sizeof( classtype_car_path
)
870 pn
= classtype_car_path()
874 if obj
.cv_data
.target
!= None:
875 pn
.target
= obj
.cv_data
.target
.cv_data
.uid
876 if obj
.cv_data
.target1
!= None:
877 pn
.target1
= obj
.cv_data
.target1
.cv_data
.uid
879 entdata_buffer
+= [pn
]
881 elif obj
.is_instancer
:
882 target
= obj
.instance_collection
885 header
.entdata_length
+= sizeof( classtype_instance
)
887 inst
= classtype_instance()
888 inst
.pstr_file
= emplace_string( F
"models/{target.name}.mdl" )
889 entdata_buffer
+= [inst
]
891 elif classtype
== 'k_classtype_capsule':
894 elif classtype
== 'k_classtype_route_node':
896 header
.entdata_length
+= sizeof( classtype_route_node
)
898 rn
= classtype_route_node()
899 if obj
.cv_data
.target
!= None:
900 rn
.target
= obj
.cv_data
.target
.cv_data
.uid
901 if obj
.cv_data
.target1
!= None:
902 rn
.target1
= obj
.cv_data
.target1
.cv_data
.uid
904 entdata_buffer
+= [rn
]
906 elif classtype
== 'k_classtype_route':
908 header
.entdata_length
+= sizeof( classtype_route
)
909 r
= classtype_route()
910 r
.colour
[0] = obj
.cv_data
.colour
[0]
911 r
.colour
[1] = obj
.cv_data
.colour
[1]
912 r
.colour
[2] = obj
.cv_data
.colour
[2]
914 if obj
.cv_data
.target
!= None:
915 r
.id_start
= obj
.cv_data
.target
.cv_data
.uid
917 entdata_buffer
+= [r
]
919 # classtype == 'k_classtype_none':
924 node_buffer
+= [node
]
927 # TODO: 8 BYTE ALIGNMENT
929 print( "Writing data" )
930 fpos
= sizeof(header
)
932 print( F
"Nodes: {header.node_count}" )
933 header
.node_offset
= fpos
934 fpos
+= sizeof(mdl_node
)*header
.node_count
936 print( F
"Submeshes: {header.submesh_count}" )
937 header
.submesh_offset
= fpos
938 fpos
+= sizeof(mdl_submesh
)*header
.submesh_count
940 print( F
"Materials: {header.material_count}" )
941 header
.material_offset
= fpos
942 fpos
+= sizeof(mdl_material
)*header
.material_count
944 print( F
"Animation count: {len(anim_buffer)}" )
945 header
.anim_count
= len(anim_buffer
)
946 header
.anim_offset
= fpos
947 fpos
+= sizeof(mdl_animation
)*header
.anim_count
949 print( F
"Entdata length: {header.entdata_length}" )
950 header
.entdata_offset
= fpos
951 fpos
+= header
.entdata_length
953 print( F
"Strings length: {len(strings_buffer)}" )
954 header
.strings_offset
= fpos
955 header
.strings_length
= len(strings_buffer
)
956 fpos
+= header
.strings_length
958 # Optional array things
959 print( F
"Keyframe count: {header.keyframe_count}" )
960 header
.keyframe_offset
= fpos
961 fpos
+= sizeof(mdl_keyframe
)*header
.keyframe_count
963 print( F
"Vertex count: {header.vertex_count}" )
964 header
.vertex_offset
= fpos
965 fpos
+= sizeof(mdl_vert
)*header
.vertex_count
967 print( F
"Indice count: {header.indice_count}" )
968 header
.indice_offset
= fpos
969 fpos
+= sizeof(c_uint32
)*header
.indice_count
971 header
.file_length
= fpos
973 path
= F
"/home/harry/Documents/carve/models_src/{collection_name}.mdl"
974 fp
= open( path
, "wb" )
976 fp
.write( bytearray( header
) )
978 for node
in node_buffer
:
979 fp
.write( bytearray(node
) )
980 for sm
in submesh_buffer
:
981 fp
.write( bytearray(sm
) )
982 for mat
in material_buffer
:
983 fp
.write( bytearray(mat
) )
984 for a
in anim_buffer
:
985 fp
.write( bytearray(a
) )
986 for ed
in entdata_buffer
:
987 fp
.write( bytearray(ed
) )
989 fp
.write( strings_buffer
)
991 for kf
in animdata_buffer
:
992 fp
.write( bytearray(kf
) )
994 for v
in vertex_buffer
:
995 fp
.write( bytearray(v
) )
996 for i
in indice_buffer
:
997 fp
.write( bytearray(i
) )
1001 print( F
"Completed {collection_name}.mdl" )
1004 # ------------------------------------------------------------------------------
1006 cv_view_draw_handler
= None
1007 cv_view_shader
= gpu
.shader
.from_builtin('3D_SMOOTH_COLOR')
1010 global cv_view_shader
1011 cv_view_shader
.bind()
1012 gpu
.state
.depth_mask_set(False)
1013 gpu
.state
.line_width_set(2.0)
1014 gpu
.state
.face_culling_set('BACK')
1015 gpu
.state
.depth_test_set('LESS')
1016 gpu
.state
.blend_set('NONE')
1021 #def drawbezier(p0,h0,p1,h1,c0,c1):
1022 # nonlocal verts, colours
1026 # colours += [(0.5,0.5,0.5,1.0),(0.5,0.5,0.5,1)]
1029 # colours += [(1.0,1.0,1,1),(1,1,1,1)]
1032 # for i in range(10):
1038 # p=ttt*p1+(3*tt-3*ttt)*h1+(3*ttt-6*tt+3*t)*h0+(3*tt-ttt-3*t+1)*p0
1039 # verts += [(last[0],last[1],last[2])]
1040 # verts += [(p[0],p[1],p[2])]
1041 # colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)]
1046 def drawbhandle(obj
, direction
, colour
):
1047 nonlocal verts
, colours
1049 h0
= obj
.matrix_world
@ Vector((0,direction
,0))
1052 colours
+= [colour
,colour
]
1054 def drawbezier(p0
,h0
,p1
,h1
,c0
,c1
):
1055 nonlocal verts
, colours
1064 p
=ttt
*p1
+(3*tt
-3*ttt
)*h1
+(3*ttt
-6*tt
+3*t
)*h0
+(3*tt
-ttt
-3*t
+1)*p0
1065 verts
+= [(last
[0],last
[1],last
[2])]
1066 verts
+= [(p
[0],p
[1],p
[2])]
1067 colours
+= [c0
*a0
+c1
*(1-a0
),c0
*a0
+c1
*(1-a0
)]
1070 def drawsbpath(o0
,o1
,c0
,c1
,s0
,s1
):
1071 nonlocal course_count
1073 offs
= ((course_count
% 2)*2-1) * course_count
* 0.02
1075 p0
= o0
.matrix_world
@ Vector((offs
, 0,0))
1076 h0
= o0
.matrix_world
@ Vector((offs
, s0
,0))
1077 p1
= o1
.matrix_world
@ Vector((offs
, 0,0))
1078 h1
= o1
.matrix_world
@ Vector((offs
,-s1
,0))
1079 drawbezier(p0
,h0
,p1
,h1
,c0
,c1
)
1081 def drawbpath(o0
,o1
,c0
,c1
):
1082 drawsbpath(o0
,o1
,c0
,c1
,1.0,1.0)
1084 def drawbline(p0
,p1
,c0
,c1
):
1085 nonlocal verts
, colours
1089 for obj
in bpy
.context
.collection
.objects
:
1090 if obj
.type == 'ARMATURE':
1091 for bone
in obj
.data
.bones
:
1092 if bone
.cv_data
.collider
and obj
.data
.pose_position
== 'REST':
1098 vs
[0]=obj
.matrix_world
@Vector((c
[0]+a
[0],c
[1]+a
[1],c
[2]+a
[2]))
1099 vs
[1]=obj
.matrix_world
@Vector((c
[0]+a
[0],c
[1]+b
[1],c
[2]+a
[2]))
1100 vs
[2]=obj
.matrix_world
@Vector((c
[0]+b
[0],c
[1]+b
[1],c
[2]+a
[2]))
1101 vs
[3]=obj
.matrix_world
@Vector((c
[0]+b
[0],c
[1]+a
[1],c
[2]+a
[2]))
1102 vs
[4]=obj
.matrix_world
@Vector((c
[0]+a
[0],c
[1]+a
[1],c
[2]+b
[2]))
1103 vs
[5]=obj
.matrix_world
@Vector((c
[0]+a
[0],c
[1]+b
[1],c
[2]+b
[2]))
1104 vs
[6]=obj
.matrix_world
@Vector((c
[0]+b
[0],c
[1]+b
[1],c
[2]+b
[2]))
1105 vs
[7]=obj
.matrix_world
@Vector((c
[0]+b
[0],c
[1]+a
[1],c
[2]+b
[2]))
1107 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\
1108 (0,4),(1,5),(2,6),(3,7)]
1113 verts
+= [(v0
[0],v0
[1],v0
[2])]
1114 verts
+= [(v1
[0],v1
[1],v1
[2])]
1115 colours
+= [(0.5,0.5,0.5,0.5),(0.5,0.5,0.5,0.5)]
1117 center
=obj
.matrix_world
@c
1119 def _angle_lim( major
, minor
, amin
, amax
, colour
):
1120 nonlocal verts
, colours
1128 a0
= amin
*(1.0-t0
)+amax
*t0
1129 a1
= amin
*(1.0-t1
)+amax
*t1
1131 p0
= c
+ major
*f
*math
.cos(a0
) + minor
*f
*math
.sin(a0
)
1132 p1
= c
+ major
*f
*math
.cos(a1
) + minor
*f
*math
.sin(a1
)
1134 p0
=obj
.matrix_world
@ p0
1135 p1
=obj
.matrix_world
@ p1
1137 colours
+= [colour
,colour
]
1141 colours
+= [colour
,colour
]
1144 colours
+= [colour
,colour
]
1146 verts
+= [c
+major
*1.2*f
,c
+major
*f
*0.8]
1147 colours
+= [colour
,colour
]
1149 if bone
.cv_data
.con0
:
1150 _angle_lim( Vector((0,1,0)),Vector((0,0,1)), \
1151 bone
.cv_data
.mins
[0], bone
.cv_data
.maxs
[0], \
1153 _angle_lim( Vector((0,0,1)),Vector((1,0,0)), \
1154 bone
.cv_data
.mins
[1], bone
.cv_data
.maxs
[1], \
1156 _angle_lim( Vector((1,0,0)),Vector((0,1,0)), \
1157 bone
.cv_data
.mins
[2], bone
.cv_data
.maxs
[2], \
1161 if obj
.cv_data
.classtype
== 'k_classtype_gate':
1162 if obj
.type == 'MESH':
1163 dims
= obj
.data
.cv_data
.v0
1165 dims
= obj
.cv_data
.v0
1168 c
= Vector((0,0,dims
[2]))
1170 vs
[0] = obj
.matrix_world
@ Vector((-dims
[0],0.0,-dims
[1]+dims
[2]))
1171 vs
[1] = obj
.matrix_world
@ Vector((-dims
[0],0.0, dims
[1]+dims
[2]))
1172 vs
[2] = obj
.matrix_world
@ Vector(( dims
[0],0.0, dims
[1]+dims
[2]))
1173 vs
[3] = obj
.matrix_world
@ Vector(( dims
[0],0.0,-dims
[1]+dims
[2]))
1174 vs
[4] = obj
.matrix_world
@ (c
+Vector((-1,0,-2)))
1175 vs
[5] = obj
.matrix_world
@ (c
+Vector((-1,0, 2)))
1176 vs
[6] = obj
.matrix_world
@ (c
+Vector(( 1,0, 2)))
1177 vs
[7] = obj
.matrix_world
@ (c
+Vector((-1,0, 0)))
1178 vs
[8] = obj
.matrix_world
@ (c
+Vector(( 1,0, 0)))
1180 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)]
1185 verts
+= [(v0
[0],v0
[1],v0
[2])]
1186 verts
+= [(v1
[0],v1
[1],v1
[2])]
1187 colours
+= [(1,1,0,1),(1,1,0,1)]
1189 sw
= (0.4,0.4,0.4,0.2)
1190 if obj
.cv_data
.target
!= None:
1191 drawbline( obj
.location
, obj
.cv_data
.target
.location
, sw
,sw
)
1193 elif obj
.cv_data
.classtype
== 'k_classtype_route_node':
1194 sw
= Vector((0.4,0.4,0.4,0.2))
1195 sw2
= Vector((1.5,0.2,0.2,0.0))
1196 if obj
.cv_data
.target
!= None:
1197 drawbpath( obj
, obj
.cv_data
.target
, sw
, sw
)
1198 if obj
.cv_data
.target1
!= None:
1199 drawbpath( obj
, obj
.cv_data
.target1
, sw
, sw
)
1201 drawbhandle( obj
, 1.0, (0.8,0.8,0.8,1.0) )
1202 drawbhandle( obj
, -1.0, (0.4,0.4,0.4,1.0) )
1204 p1
= obj
.location
+ \
1205 obj
.matrix_world
.to_quaternion() @ Vector((0,0,-6+1.5))
1206 drawbline( obj
.location
, p1
, sw
,sw2
)
1208 elif obj
.cv_data
.classtype
== 'k_classtype_achievement_box':
1209 a
= Vector((-1,-1,-1))
1213 vs
[0] = obj
.matrix_world
@ Vector((a
[0], a
[1], a
[2]))
1214 vs
[1] = obj
.matrix_world
@ Vector((a
[0], b
[1], a
[2]))
1215 vs
[2] = obj
.matrix_world
@ Vector((b
[0], b
[1], a
[2]))
1216 vs
[3] = obj
.matrix_world
@ Vector((b
[0], a
[1], a
[2]))
1217 vs
[4] = obj
.matrix_world
@ Vector((a
[0], a
[1], b
[2]))
1218 vs
[5] = obj
.matrix_world
@ Vector((a
[0], b
[1], b
[2]))
1219 vs
[6] = obj
.matrix_world
@ Vector((b
[0], b
[1], b
[2]))
1220 vs
[7] = obj
.matrix_world
@ Vector((b
[0], a
[1], b
[2]))
1222 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\
1223 (0,4),(1,5),(2,6),(3,7)]
1228 verts
+= [(v0
[0],v0
[1],v0
[2])]
1229 verts
+= [(v1
[0],v1
[1],v1
[2])]
1230 colours
+= [(0,1,0,1),(0,1,0,1)]
1232 if obj
.cv_data
.target
!= None:
1234 vs
[0] = obj
.location
1235 vs
[1] = obj
.cv_data
.target
.location
1240 verts
+= [(v0
[0],v0
[1],v0
[2])]
1241 verts
+= [(v1
[0],v1
[1],v1
[2])]
1242 colours
+= [(0,1,1,1),(0,1,1,1)]
1245 elif obj
.cv_data
.classtype
== 'k_classtype_block':
1246 a
= obj
.data
.cv_data
.v0
1247 b
= obj
.data
.cv_data
.v1
1250 vs
[0] = obj
.matrix_world
@ Vector((a
[0], a
[1], a
[2]))
1251 vs
[1] = obj
.matrix_world
@ Vector((a
[0], b
[1], a
[2]))
1252 vs
[2] = obj
.matrix_world
@ Vector((b
[0], b
[1], a
[2]))
1253 vs
[3] = obj
.matrix_world
@ Vector((b
[0], a
[1], a
[2]))
1254 vs
[4] = obj
.matrix_world
@ Vector((a
[0], a
[1], b
[2]))
1255 vs
[5] = obj
.matrix_world
@ Vector((a
[0], b
[1], b
[2]))
1256 vs
[6] = obj
.matrix_world
@ Vector((b
[0], b
[1], b
[2]))
1257 vs
[7] = obj
.matrix_world
@ Vector((b
[0], a
[1], b
[2]))
1259 indices
= [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\
1260 (0,4),(1,5),(2,6),(3,7)]
1265 verts
+= [(v0
[0],v0
[1],v0
[2])]
1266 verts
+= [(v1
[0],v1
[1],v1
[2])]
1267 colours
+= [(1,1,0,1),(1,1,0,1)]
1269 elif obj
.cv_data
.classtype
== 'k_classtype_capsule':
1270 h
= obj
.data
.cv_data
.v0
[0]
1271 r
= obj
.data
.cv_data
.v0
[1]
1274 vs
[0] = obj
.matrix_world
@ Vector((0.0,0.0, h
*0.5 ))
1275 vs
[1] = obj
.matrix_world
@ Vector((0.0,0.0,-h
*0.5 ))
1276 vs
[2] = obj
.matrix_world
@ Vector(( r
,0.0, h
*0.5-r
))
1277 vs
[3] = obj
.matrix_world
@ Vector(( -r
,0.0, h
*0.5-r
))
1278 vs
[4] = obj
.matrix_world
@ Vector(( r
,0.0,-h
*0.5+r
))
1279 vs
[5] = obj
.matrix_world
@ Vector(( -r
,0.0,-h
*0.5+r
))
1280 vs
[6] = obj
.matrix_world
@ Vector((0.0, r
, h
*0.5-r
))
1281 vs
[7] = obj
.matrix_world
@ Vector((0.0,-r
, h
*0.5-r
))
1282 vs
[8] = obj
.matrix_world
@ Vector((0.0, r
,-h
*0.5+r
))
1283 vs
[9] = obj
.matrix_world
@ Vector((0.0,-r
,-h
*0.5+r
))
1285 indices
= [(0,1),(2,3),(4,5),(6,7),(8,9)]
1290 verts
+= [(v0
[0],v0
[1],v0
[2])]
1291 verts
+= [(v1
[0],v1
[1],v1
[2])]
1292 colours
+= [(0.5,1,0,1),(0.5,1,0,1)]
1294 elif obj
.cv_data
.classtype
== 'k_classtype_spawn':
1296 vs
[0] = obj
.matrix_world
@ Vector((0,0,0))
1297 vs
[1] = obj
.matrix_world
@ Vector((0,2,0))
1298 vs
[2] = obj
.matrix_world
@ Vector((0.5,1,0))
1299 vs
[3] = obj
.matrix_world
@ Vector((-0.5,1,0))
1300 indices
= [(0,1),(1,2),(1,3)]
1304 verts
+= [(v0
[0],v0
[1],v0
[2])]
1305 verts
+= [(v1
[0],v1
[1],v1
[2])]
1306 colours
+= [(0,1,1,1),(0,1,1,1)]
1308 elif obj
.cv_data
.classtype
== 'k_classtype_route':
1310 vs
[0] = obj
.location
1311 vs
[1] = obj
.cv_data
.target
.location
1316 verts
+= [(v0
[0],v0
[1],v0
[2])]
1317 verts
+= [(v1
[0],v1
[1],v1
[2])]
1318 colours
+= [(0,1,1,1),(0,1,1,1)]
1322 stack
[0] = obj
.cv_data
.target
1324 loop_complete
= False
1327 if stack_i
[si
-1] == 2:
1331 if si
== 0: # Loop failed to complete
1336 targets
= [None,None]
1337 targets
[0] = node
.cv_data
.target
1339 if node
.cv_data
.classtype
== 'k_classtype_route_node':
1340 targets
[1] = node
.cv_data
.target1
1342 nextnode
= targets
[stack_i
[si
-1]]
1345 if nextnode
!= None: # branch
1346 if nextnode
== stack
[0]: # Loop completed
1347 loop_complete
= True
1351 for sj
in range(si
):
1352 if stack
[sj
] == nextnode
: # invalidated path
1358 stack
[si
] = nextnode
1363 cc
= Vector((obj
.cv_data
.colour
[0],\
1364 obj
.cv_data
.colour
[1],\
1365 obj
.cv_data
.colour
[2],\
1368 for sj
in range(si
):
1371 if stack
[sj
].cv_data
.classtype
== 'k_classtype_gate' and \
1372 stack
[sk
].cv_data
.classtype
== 'k_classtype_gate':
1373 dist
= (stack
[sj
].location
-stack
[sk
].location
).magnitude
1374 drawsbpath( stack
[sj
], stack
[sk
], cc
*0.4, cc
, dist
, dist
)
1377 drawbpath( stack
[sj
], stack
[sk
], cc
, cc
)
1381 elif obj
.cv_data
.classtype
== 'k_classtype_car_path':
1382 v0
= obj
.matrix_world
.to_quaternion() @ Vector((0,1,0))
1383 c0
= Vector((v0
.x
*0.5+0.5, v0
.y
*0.5+0.5, 0.0, 1.0))
1384 drawbhandle( obj
, 1.0, (0.9,0.9,0.9,1.0) )
1386 if obj
.cv_data
.target
!= None:
1387 v1
= obj
.cv_data
.target
.matrix_world
.to_quaternion()@Vector((0,1,0))
1388 c1
= Vector((v1
.x
*0.5+0.5, v1
.y
*0.5+0.5, 0.0, 1.0))
1390 drawbhandle( obj
.cv_data
.target
, -1.0, (0.5,0.5,0.5,1.0) )
1391 drawbpath( obj
, obj
.cv_data
.target
, c0
, c1
)
1393 if obj
.cv_data
.target1
!= None:
1394 v1
= obj
.cv_data
.target1
.matrix_world
.to_quaternion()@Vector((0,1,0))
1395 c1
= Vector((v1
.x
*0.5+0.5, v1
.y
*0.5+0.5, 0.0, 1.0))
1397 drawbhandle( obj
.cv_data
.target1
, -1.0, (0.5,0.5,0.5,1.0) )
1398 drawbpath( obj
, obj
.cv_data
.target1
, c0
, c1
)
1400 lines
= batch_for_shader(\
1401 cv_view_shader
, 'LINES', \
1402 { "pos":verts
, "color":colours
})
1404 lines
.draw( cv_view_shader
)
1406 def cv_poll_target(scene
, obj
):
1407 if obj
== bpy
.context
.active_object
:
1409 if obj
.cv_data
.classtype
== 'k_classtype_none':
1413 class CV_MESH_SETTINGS(bpy
.types
.PropertyGroup
):
1414 v0
: bpy
.props
.FloatVectorProperty(name
="v0",size
=3)
1415 v1
: bpy
.props
.FloatVectorProperty(name
="v1",size
=3)
1416 v2
: bpy
.props
.FloatVectorProperty(name
="v2",size
=3)
1417 v3
: bpy
.props
.FloatVectorProperty(name
="v3",size
=3)
1419 class CV_OBJ_SETTINGS(bpy
.types
.PropertyGroup
):
1420 uid
: bpy
.props
.IntProperty( name
="" )
1422 strp
: bpy
.props
.StringProperty( name
="strp" )
1423 intp
: bpy
.props
.IntProperty( name
="intp" )
1424 fltp
: bpy
.props
.FloatProperty( name
="fltp" )
1426 target
: bpy
.props
.PointerProperty( type=bpy
.types
.Object
, name
="target", \
1427 poll
=cv_poll_target
)
1428 target1
: bpy
.props
.PointerProperty( type=bpy
.types
.Object
, name
="target1", \
1429 poll
=cv_poll_target
)
1431 colour
: bpy
.props
.FloatVectorProperty(name
="colour",subtype
='COLOR',\
1434 classtype
: bpy
.props
.EnumProperty(
1437 ('k_classtype_none', "k_classtype_none", "", 0),
1438 ('k_classtype_gate', "k_classtype_gate", "", 1),
1439 ('k_classtype_block', "k_classtype_block", "", 2),
1440 ('k_classtype_spawn', "k_classtype_spawn", "", 3),
1441 ('k_classtype_water', "k_classtype_water", "", 4),
1442 ('k_classtype_car_path', "k_classtype_car_path", "", 5),
1443 ('k_classtype_INSTANCE', "","", 6 ),
1444 ('k_classtype_capsule', "k_classtype_capsule", "", 7 ),
1445 ('k_classtype_route_node', "k_classtype_route_node", "", 8 ),
1446 ('k_classtype_route', "k_classtype_route", "", 9 ),
1447 ('k_classtype_bone',"k_classtype_bone","",10),
1448 ('k_classtype_SKELETON', "","", 11 ),
1449 ('k_classtype_SKIN',"","",12),
1450 ('k_classtype_achievement_box',"k_classtype_achievement_box","",13),
1451 ('k_classtype_audio',"k_classtype_audio","",14),
1454 class CV_BONE_SETTINGS(bpy
.types
.PropertyGroup
):
1455 collider
: bpy
.props
.BoolProperty(name
="Collider",default
=False)
1456 v0
: bpy
.props
.FloatVectorProperty(name
="v0",size
=3)
1457 v1
: bpy
.props
.FloatVectorProperty(name
="v1",size
=3)
1459 con0
: bpy
.props
.BoolProperty(name
="Constriant 0",default
=False)
1460 mins
: bpy
.props
.FloatVectorProperty(name
="mins",size
=3)
1461 maxs
: bpy
.props
.FloatVectorProperty(name
="maxs",size
=3)
1463 class CV_BONE_PANEL(bpy
.types
.Panel
):
1464 bl_label
="Bone Config"
1465 bl_idname
="SCENE_PT_cv_bone"
1466 bl_space_type
='PROPERTIES'
1467 bl_region_type
='WINDOW'
1470 def draw(_
,context
):
1471 active_object
= context
.active_object
1472 if active_object
== None: return
1474 bone
= active_object
.data
.bones
.active
1475 if bone
== None: return
1477 _
.layout
.prop( bone
.cv_data
, "collider" )
1478 _
.layout
.prop( bone
.cv_data
, "v0" )
1479 _
.layout
.prop( bone
.cv_data
, "v1" )
1481 _
.layout
.label( text
="Angle Limits" )
1482 _
.layout
.prop( bone
.cv_data
, "con0" )
1483 _
.layout
.prop( bone
.cv_data
, "mins" )
1484 _
.layout
.prop( bone
.cv_data
, "maxs" )
1486 class CV_SCENE_SETTINGS(bpy
.types
.PropertyGroup
):
1487 use_hidden
: bpy
.props
.BoolProperty( name
="use hidden", default
=False )
1489 class CV_OBJ_PANEL(bpy
.types
.Panel
):
1490 bl_label
="Entity Config"
1491 bl_idname
="SCENE_PT_cv_entity"
1492 bl_space_type
='PROPERTIES'
1493 bl_region_type
='WINDOW'
1496 def draw(_
,context
):
1497 active_object
= bpy
.context
.active_object
1498 if active_object
== None: return
1499 _
.layout
.prop( active_object
.cv_data
, "classtype" )
1501 if active_object
.cv_data
.classtype
== 'k_classtype_gate':
1502 _
.layout
.prop( active_object
.cv_data
, "target" )
1504 mesh
= active_object
.data
1505 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1506 _
.layout
.prop( mesh
.cv_data
, "v0" )
1508 elif active_object
.cv_data
.classtype
== 'k_classtype_car_path' or \
1509 active_object
.cv_data
.classtype
== 'k_classtype_route_node':
1510 _
.layout
.prop( active_object
.cv_data
, "target" )
1511 _
.layout
.prop( active_object
.cv_data
, "target1" )
1513 elif active_object
.cv_data
.classtype
== 'k_classtype_route':
1514 _
.layout
.prop( active_object
.cv_data
, "target" )
1515 _
.layout
.prop( active_object
.cv_data
, "colour" )
1517 elif active_object
.cv_data
.classtype
== 'k_classtype_block':
1518 mesh
= active_object
.data
1520 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1521 _
.layout
.prop( mesh
.cv_data
, "v0" )
1522 _
.layout
.prop( mesh
.cv_data
, "v1" )
1523 _
.layout
.prop( mesh
.cv_data
, "v2" )
1524 _
.layout
.prop( mesh
.cv_data
, "v3" )
1525 elif active_object
.cv_data
.classtype
== 'k_classtype_capsule':
1526 mesh
= active_object
.data
1527 _
.layout
.label( text
=F
"(i) Data is stored in {mesh.name}" )
1528 _
.layout
.prop( mesh
.cv_data
, "v0" )
1529 elif active_object
.cv_data
.classtype
== 'k_classtype_achievement_box':
1530 _
.layout
.prop( active_object
.cv_data
, "strp" )
1531 _
.layout
.prop( active_object
.cv_data
, "target" )
1532 elif active_object
.cv_data
.classtype
== 'k_classtype_audio':
1533 _
.layout
.prop( active_object
.cv_data
, "strp" )
1534 _
.layout
.prop( active_object
.cv_data
, "intp" )
1535 _
.layout
.prop( active_object
.cv_data
, "fltp" )
1537 class CV_INTERFACE(bpy
.types
.Panel
):
1538 bl_idname
= "VIEW3D_PT_carve"
1540 bl_space_type
= 'VIEW_3D'
1541 bl_region_type
= 'UI'
1542 bl_category
= "Carve"
1544 def draw(_
, context
):
1546 layout
.prop( context
.scene
.cv_data
, "use_hidden")
1547 layout
.operator( "carve.compile_all" )
1550 view_layer
= bpy
.context
.view_layer
1551 for col
in view_layer
.layer_collection
.children
["export"].children
:
1552 if not col
.hide_viewport
or bpy
.context
.scene
.cv_data
.use_hidden
:
1553 write_model( col
.name
)
1555 class CV_COMPILE(bpy
.types
.Operator
):
1556 bl_idname
="carve.compile_all"
1557 bl_label
="Compile All"
1559 def execute(_
,context
):
1561 #cProfile.runctx("test_compile()",globals(),locals(),sort=1)
1562 #for col in bpy.data.collections["export"].children:
1563 # write_model( col.name )
1567 classes
= [CV_OBJ_SETTINGS
,CV_OBJ_PANEL
,CV_COMPILE
,CV_INTERFACE
,\
1568 CV_MESH_SETTINGS
, CV_SCENE_SETTINGS
, CV_BONE_SETTINGS
,\
1572 global cv_view_draw_handler
1575 bpy
.utils
.register_class(c
)
1577 bpy
.types
.Object
.cv_data
= bpy
.props
.PointerProperty(type=CV_OBJ_SETTINGS
)
1578 bpy
.types
.Mesh
.cv_data
= bpy
.props
.PointerProperty(type=CV_MESH_SETTINGS
)
1579 bpy
.types
.Scene
.cv_data
= bpy
.props
.PointerProperty(type=CV_SCENE_SETTINGS
)
1580 bpy
.types
.Bone
.cv_data
= bpy
.props
.PointerProperty(type=CV_BONE_SETTINGS
)
1582 cv_view_draw_handler
= bpy
.types
.SpaceView3D
.draw_handler_add(\
1583 cv_draw
,(),'WINDOW','POST_VIEW')
1586 global cv_view_draw_handler
1589 bpy
.utils
.unregister_class(c
)
1591 bpy
.types
.SpaceView3D
.draw_handler_remove(cv_view_draw_handler
,'WINDOW')