X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=blender_export.py;h=f9b8f6925120eb57da1fd0760681f93d44153e7a;hb=b270d9efa9bedb7ca0813acffc1632f84900c0de;hp=8eb39a365dba70129c69776182175b39a30ea90f;hpb=6ab4435fb19beb6af6c52691793d5ca17a120f69;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/blender_export.py b/blender_export.py index 8eb39a3..f9b8f69 100644 --- a/blender_export.py +++ b/blender_export.py @@ -1,9 +1,10 @@ -import bpy, math, gpu, os +import bpy, blf, math, gpu, os import cProfile from ctypes import * from mathutils import * from gpu_extras.batch import batch_for_shader from bpy_extras import mesh_utils +from bpy_extras import view3d_utils bl_info = { "name":"Skaterift .mdl exporter", @@ -36,10 +37,14 @@ sr_entity_list = [ ('ent_menuitem', 'Menu Item', '', 15 ), ('ent_worldinfo', 'World Info', '', 16 ), ('ent_ccmd', 'CCmd', '', 17 ), - ('ent_challenge', 'Challenge', '', 18 ) + ('ent_challenge', 'Challenge', '', 18 ), + ('ent_unlock', 'Unlockable', '', 19 ), + ('ent_relay', 'Relay', '', 20 ) ] MDL_VERSION_NR = 102 +SR_TRIGGERABLE = [ 'ent_audio', 'ent_ccmd', 'ent_gate', 'ent_unlock', \ + 'ent_relay', 'ent_skateshop', 'ent_challenge' ] def get_entity_enum_id( alias ): #{ @@ -203,6 +208,7 @@ class ent_gate(Structure): ("submesh_start",c_uint32), # v102+ ("submesh_count",c_uint32), # v102+ (can be 0) ] + sr_functions = { 0: 'unlock' } #} class ent_route_node(Structure): @@ -456,12 +462,28 @@ class ent_challenge(Structure):#{ ("submesh_start",c_uint32), ("submesh_count",c_uint32), ("id_next",c_uint32), ("filter",c_uint32), + ("id_win",c_uint32), + ("win_event",c_uint32), ("time_limit",c_float)] sr_functions = { 0: 'trigger', 1: 'start_challenge' } #} +class ent_unlock(Structure):#{ + _fields_ = [("pstr_alias",c_uint32), + ("target",c_uint32), + ("target_event",c_uint32), + ("status",c_uint32)] + sr_functions = { 0: 'unlock' } +#} + +class ent_relay(Structure):#{ + _fields_ = [("targets",(c_uint32*2)*4), + ("targets_events",c_uint32*4)] + sr_functions = { 0: 'trigger' } +#} + def obj_ent_type( obj ): #{ if obj.type == 'ARMATURE': return 'mdl_armature' @@ -1650,6 +1672,7 @@ def sr_compile( collection ): gate.submesh_start, gate.submesh_count, _ = \ sr_compile_mesh_internal( obj ) #} + if obj_data.locked: flags |= 0x0010 gate.flags = flags gate.dimensions[0] = mesh_data.dimensions[0] @@ -1747,7 +1770,7 @@ def sr_compile( collection ): if obj_data.target:#{ volume.target = sr_entity_id( obj_data.target ) - volume._anon.trigger.event = obj_data.event + volume._anon.trigger.event = obj_data.target_event #} sr_ent_push(volume) @@ -1809,6 +1832,8 @@ def sr_compile( collection ): challenge = ent_challenge() obj_data = obj.SR_data.ent_challenge[0] challenge.id_next = sr_entity_id( obj_data.proxima ) + challenge.id_win = sr_entity_id( obj_data.target ) + challenge.win_event = obj_data.target_event challenge.filter = 0 challenge.time_limit = obj_data.time_limit @@ -1818,6 +1843,28 @@ def sr_compile( collection ): sr_ent_push( challenge ) #} + elif ent_type == 'ent_unlock':#{ + unlock = ent_unlock() + obj_data = obj.SR_data.ent_unlock[0] + unlock.pstr_alias = sr_compile_string( obj_data.alias ) + unlock.target = sr_entity_id( obj_data.target ) + unlock.target_event = obj_data.target_event + unlock.status = 0 + sr_ent_push( unlock ) + #} + elif ent_type == 'ent_relay':#{ + relay = ent_relay() + obj_data = obj.SR_data.ent_relay[0] + relay.targets[0][0] = sr_entity_id( obj_data.target0 ) + relay.targets[1][0] = sr_entity_id( obj_data.target1 ) + relay.targets[2][0] = sr_entity_id( obj_data.target2 ) + relay.targets[3][0] = sr_entity_id( obj_data.target3 ) + relay.targets[0][1] = obj_data.target0_event + relay.targets[1][1] = obj_data.target1_event + relay.targets[2][1] = obj_data.target2_event + relay.targets[3][1] = obj_data.target3_event + sr_ent_push( relay ) + #} #} #} @@ -2230,9 +2277,12 @@ class SR_INTERFACE(bpy.types.Panel): active_object = context.active_object if not active_object: return - _.layout.operator( 'skaterift.copy_entity_data', \ - text=F'Copy entity data to {len(context.selected_objects)-1} '+\ - F'other objects' ) + amount = max( 0, len(context.selected_objects)-1 ) + + row = _.layout.row() + row.operator( 'skaterift.copy_entity_data', \ + text=F'Copy entity data to {amount} other objects' ) + if amount == 0: row.enabled=False box = _.layout.box() row = box.row() @@ -2240,13 +2290,13 @@ class SR_INTERFACE(bpy.types.Panel): row.label( text=active_object.name ) row.scale_y = 1.5 - def _draw_prop_collection( data ): #{ + def _draw_prop_collection( source, data ): #{ nonlocal box row = box.row() row.alignment = 'CENTER' row.enabled = False row.scale_y = 1.5 - row.label( text=F'{data[0]}' ) + row.label( text=F'{source}' ) if hasattr(type(data[0]),'sr_inspector'):#{ type(data[0]).sr_inspector( box, data ) @@ -2266,7 +2316,9 @@ class SR_INTERFACE(bpy.types.Panel): text=F'Mirror attributes to {mb.name}' ) #} - _draw_prop_collection( [bones.active.SR_data ] ) + _draw_prop_collection( \ + F'bpy.types.Bone["{bones.active.name}"].SR_data',\ + [bones.active.SR_data ] ) #} else: #{ row = box.row() @@ -2277,18 +2329,26 @@ class SR_INTERFACE(bpy.types.Panel): #} #} elif active_object.type == 'LIGHT': #{ - _draw_prop_collection( [active_object.data.SR_data] ) + _draw_prop_collection( \ + F'bpy.types.Light["{active_object.data.name}"].SR_data', \ + [active_object.data.SR_data] ) #} elif active_object.type in ['EMPTY','CURVE','MESH']:#{ box.prop( active_object.SR_data, "ent_type" ) ent_type = active_object.SR_data.ent_type col = getattr( active_object.SR_data, ent_type, None ) - if col != None and len(col)!=0: _draw_prop_collection( col ) + if col != None and len(col)!=0: + _draw_prop_collection( \ + F'bpy.types.Object["{active_object.name}"].SR_data.{ent_type}[0]', \ + col ) if active_object.type == 'MESH':#{ col = getattr( active_object.data.SR_data, ent_type, None ) - if col != None and len(col)!=0: _draw_prop_collection( col ) + if col != None and len(col)!=0: + _draw_prop_collection( \ + F'bpy.types.Mesh["{active_object.data.name}"].SR_data.{ent_type}[0]', \ + col ) #} #} #} @@ -2404,6 +2464,7 @@ class SR_OBJECT_ENT_GATE(bpy.types.PropertyGroup): flip: bpy.props.BoolProperty( name="Flip exit", default=False ) custom: bpy.props.BoolProperty( name="Mesh is surface", default=False ) + locked: bpy.props.BoolProperty( name="Start Locked", default=False ) @staticmethod def sr_inspector( layout, data ): @@ -2417,6 +2478,7 @@ class SR_OBJECT_ENT_GATE(bpy.types.PropertyGroup): flags = box.box() flags.prop( data[0], 'flip' ) flags.prop( data[0], 'custom' ) + flags.prop( data[0], 'locked' ) #} #} @@ -2776,31 +2838,40 @@ class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup):#{ poll=lambda self,obj: sr_filter_ent_type(obj,\ ['ent_audio','ent_skateshop','ent_ccmd',\ 'ent_challenge'])) - - event: bpy.props.IntProperty( name="Event/Method" ) + target_event: bpy.props.IntProperty( name="Event/Method" ) @staticmethod - def sr_inspector( layout, data ):#{ - layout.prop( data[0], 'subtype' ) - layout.prop( data[0], 'target' ) + def inspect_target( layout, data, propname ):#{ + box = layout.box() + box.prop( data[0], propname ) - row = layout.row() - row.prop( data[0], 'event' ) + row = box.row() + row.prop( data[0], propname + '_event') - if data[0].target:#{ - tipo = data[0].target.SR_data.ent_type + target = getattr( data[0], propname ) + if target:#{ + tipo = target.SR_data.ent_type cls = globals()[ tipo ] table = getattr( cls, 'sr_functions', None ) if table:#{ - if data[0].event in table:#{ - row.label( text=table[data[0].event] ) - #} - else:#{ + index = getattr( data[0], propname+'_event') + if index in table: + row.label( text=table[index] ) + else: row.label( text="undefined function" ) - #} #} #} + else:#{ + row.label( text="..." ) + row.enabled=False + #} + #} + + @staticmethod + def sr_inspector( layout, data ):#{ + layout.prop( data[0], 'subtype' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target' ) #} #} @@ -3087,11 +3158,59 @@ class SR_OBJECT_ENT_CHALLENGE(bpy.types.PropertyGroup):#{ type=bpy.types.Object, name="Next", \ poll=lambda self,obj: sr_filter_ent_type(obj,['ent_challenge'])) target: bpy.props.PointerProperty( \ - type=bpy.types.Object, name="Target", \ - poll=lambda self,obj: sr_filter_ent_type(obj,\ - ['ent_audio','ent_ccmd'])) - event: bpy.props.IntProperty( name="Event/Method" ) + type=bpy.types.Object, name="Win", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + target_event: bpy.props.IntProperty( name="Event/Method" ) time_limit: bpy.props.FloatProperty( name="Time Limit", default=1.0 ) + + @staticmethod + def sr_inspector( layout, data ):#{ + layout.prop( data[0], 'proxima' ) + layout.prop( data[0], 'time_limit' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target' ) + #} +#} + +class SR_OBJECT_ENT_UNLOCK(bpy.types.PropertyGroup):#{ + alias: bpy.props.StringProperty( name="Alias" ) + target: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Target", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + target_event: bpy.props.IntProperty( name="Event/Method" ) + + @staticmethod + def sr_inspector( layout, data ):#{ + layout.prop( data[0], 'alias' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target' ) + #} +#} + +class SR_OBJECT_ENT_RELAY(bpy.types.PropertyGroup):#{ + target0: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Target 0", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + target1: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Target 1", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + target2: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Target 2", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + target3: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Target 3", \ + poll=lambda self,obj: sr_filter_ent_type(obj,SR_TRIGGERABLE)) + + target0_event: bpy.props.IntProperty( name="Event" ) + target1_event: bpy.props.IntProperty( name="Event" ) + target2_event: bpy.props.IntProperty( name="Event" ) + target3_event: bpy.props.IntProperty( name="Event" ) + + @staticmethod + def sr_inspector( layout, data ):#{ + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target0' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target1' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target2' ) + SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target3' ) + #} #} class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): @@ -3112,6 +3231,8 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): ent_worldinfo: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_WORLD_INFO) ent_ccmd: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_CCMD) ent_challenge: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_CHALLENGE) + ent_unlock: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_UNLOCK) + ent_relay: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_RELAY) ent_type: bpy.props.EnumProperty( name="Type", @@ -3262,6 +3383,7 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): # ---------------------------------------------------------------------------- # cv_view_draw_handler = None +cv_view_pixel_handler = None cv_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') cv_view_verts = [] cv_view_colours = [] @@ -3417,7 +3539,7 @@ def cv_tangent_basis( n, tx, ty ): # Draw coloured arrow # -def cv_draw_arrow( p0, p1, c0, size=0.15 ): +def cv_draw_arrow( p0, p1, c0, size=0.25 ): #{ global cv_view_verts, cv_view_colours @@ -3999,8 +4121,7 @@ def cv_draw_route( route, dij ): #} #} -def cv_draw(): -#{ +def cv_draw():#{ global cv_view_shader global cv_view_verts global cv_view_colours @@ -4048,6 +4169,24 @@ def cv_draw(): if data.proxima:#{ cv_draw_arrow( obj.location, data.proxima.location, (0,0.2,1.0) ) #} + if data.target: + cv_draw_arrow( obj.location, data.target.location, (0,1.0,0.0) ) + #} + elif ent_type == 'ent_relay':#{ + data = obj.SR_data.ent_relay[0] + if data.target0: + cv_draw_arrow( obj.location, data.target0.location, (0,1,0) ) + if data.target1: + cv_draw_arrow( obj.location, data.target1.location, (0,1,0) ) + if data.target2: + cv_draw_arrow( obj.location, data.target2.location, (0,1,0) ) + if data.target3: + cv_draw_arrow( obj.location, data.target3.location, (0,1,0) ) + #} + elif ent_type == 'ent_unlock':#{ + data = obj.SR_data.ent_unlock[0] + if data.target: + cv_draw_arrow( obj.location, data.target.location, (0,1.0,0.0) ) #} elif ent_type == 'ent_audio':#{ if obj.SR_data.ent_audio[0].flag_3d: @@ -4215,7 +4354,31 @@ def cv_draw(): #} cv_draw_lines() - return +#} + +def pos3d_to_2d( pos ):#{ + return view3d_utils.location_3d_to_region_2d( \ + bpy.context.region, \ + bpy.context.space_data.region_3d, pos ) +#} + +def cv_draw_pixel():#{ + if not bpy.context.scene.SR_data.gizmos: return + blf.size(0,10) + blf.color(0, 1.0,1.0,1.0,0.9) + blf.enable(0,blf.SHADOW) + blf.shadow(0,3,0.0,0.0,0.0,1.0) + for obj in bpy.context.collection.objects:#{ + ent_type = obj_ent_type( obj ) + + if ent_type != 'none':#{ + co = pos3d_to_2d( obj.location ) + + if not co: continue + blf.position(0,co[0],co[1],0) + blf.draw(0,ent_type) + #} + #} #} classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ @@ -4240,7 +4403,7 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,SR_OBJECT_ENT_SKATESHOP,\ SR_OBJECT_ENT_WORKSHOP_PREVIEW,SR_OBJECT_ENT_MENU_ITEM,\ SR_OBJECT_ENT_WORLD_INFO,SR_OBJECT_ENT_CCMD,\ - SR_OBJECT_ENT_CHALLENGE,\ + SR_OBJECT_ENT_CHALLENGE,SR_OBJECT_ENT_UNLOCK,SR_OBJECT_ENT_RELAY,\ \ SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \ @@ -4267,9 +4430,11 @@ def register(): bpy.types.Material.SR_data = \ bpy.props.PointerProperty(type=SR_MATERIAL_PROPERTIES) - global cv_view_draw_handler + global cv_view_draw_handler, cv_view_pixel_handler cv_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\ cv_draw,(),'WINDOW','POST_VIEW') + cv_view_pixel_handler = bpy.types.SpaceView3D.draw_handler_add(\ + cv_draw_pixel,(),'WINDOW','POST_PIXEL') #} def unregister(): @@ -4277,8 +4442,9 @@ def unregister(): for c in classes: bpy.utils.unregister_class(c) - global cv_view_draw_handler + global cv_view_draw_handler, cv_view_pixel_handler bpy.types.SpaceView3D.draw_handler_remove(cv_view_draw_handler,'WINDOW') + bpy.types.SpaceView3D.draw_handler_remove(cv_view_pixel_handler,'WINDOW') #} # ---------------------------------------------------------------------------- #