X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=blender_export.py;h=52f674f73ba4042a0b308ce01822e23daeb42bb5;hb=5bfb36032928ba9f8d12e72961af68bfab9ea648;hp=8c1eaace97da36bdd8f3831d403f8521a9c86e8c;hpb=0310bab3c018e23f5516c3e3c3653b844a8106ed;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/blender_export.py b/blender_export.py index 8c1eaac..52f674f 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", @@ -35,8 +36,16 @@ sr_entity_list = [ ('ent_swspreview', 'Workshop Preview', '', 14 ), ('ent_menuitem', 'Menu Item', '', 15 ), ('ent_worldinfo', 'World Info', '', 16 ), + ('ent_ccmd', 'CCmd', '', 17 ), + ('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 ): #{ for et in sr_entity_list:#{ @@ -45,6 +54,8 @@ def get_entity_enum_id( alias ): #} #} + if alias == 'ent_cubemap': return 21 + return 0 #} @@ -184,7 +195,7 @@ class version_refcount_union(Union): class ent_gate(Structure): #{ - _fields_ = [("type",c_uint32), + _fields_ = [("flags",c_uint32), ("target", c_uint32), ("key",c_uint32), ("dimensions", c_float*3), @@ -195,7 +206,11 @@ class ent_gate(Structure): ("_anonymous_union",version_refcount_union), ("timing_time",c_double), ("routes",c_uint16*4), - ("route_count",c_uint8)] + ("route_count",c_uint8), + ("submesh_start",c_uint32), # v102+ + ("submesh_count",c_uint32), # v102+ (can be 0) + ] + sr_functions = { 0: 'unlock' } #} class ent_route_node(Structure): @@ -439,11 +454,59 @@ class ent_worldinfo(Structure): ("timezone",c_float)] #} +class ent_ccmd(Structure): +#{ + _fields_ = [("pstr_command",c_uint32)] +#} + +class ent_challenge(Structure):#{ + _fields_ = [("transform",mdl_transform), + ("submesh_start",c_uint32), ("submesh_count",c_uint32), + ("flags",c_uint32), + ("id_next",c_uint32), + ("filter",c_uint32),("filter2",c_uint32), + ("id_win",c_uint32), + ("win_event",c_uint32), + ("time_limit",c_float)] + + sr_functions = { 0: 'trigger', + 1: 'start_challenge', + 2: 'show', + 3: 'hide' } +#} + +class ent_unlock(Structure):#{ + _fields_ = [("transform",mdl_transform), + ("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' } +#} + +class ent_cubemap(Structure):#{ + _fields_ = [("co",c_float*3), + ("resolution",c_uint32), #placeholder + ("live",c_uint32), #placeholder + ("texture_id",c_uint32), #engine + ("framebuffer_id",c_uint32),#engine + ("renderbuffer_id",c_uint32),#engine + ("placeholder",c_uint32*2)] +#} + def obj_ent_type( obj ): #{ if obj.type == 'ARMATURE': return 'mdl_armature' elif obj.type == 'LIGHT': return 'ent_light' elif obj.type == 'CAMERA': return 'ent_camera' + elif obj.type == 'LIGHT_PROBE' and obj.data.type == 'CUBEMAP': + return 'ent_cubemap' else: return obj.SR_data.ent_type #} @@ -462,6 +525,31 @@ def sr_filter_ent_type( obj, ent_types ): return False #} +def v4_dot( a, b ):#{ + return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3] +#} + +def q_identity( q ):#{ + q[0] = 0.0 + q[1] = 0.0 + q[2] = 0.0 + q[3] = 1.0 +#} + +def q_normalize( q ):#{ + l2 = v4_dot(q,q) + if( l2 < 0.00001 ):#{ + q_identity( q ) + #} + else:#{ + s = 1.0/math.sqrt(l2) + q[0] *= s + q[1] *= s + q[2] *= s + q[3] *= s + #} +#} + def compile_obj_transform( obj, transform ): #{ co = obj.matrix_world @ Vector((0,0,0)) @@ -469,6 +557,7 @@ def compile_obj_transform( obj, transform ): # This was changed from matrix_local on 09.05.23 q = obj.matrix_world.to_quaternion() s = obj.scale + q_normalize( q ) # Setup transform # @@ -682,8 +771,7 @@ def sr_compile_texture( img ): return texture_index #} -def sr_compile_material( mat ): -#{ +def sr_compile_material( mat ):#{ if mat == None: return 0 if mat.name in sr_compile.material_cache: @@ -707,11 +795,13 @@ def sr_compile_material( mat ): #} if mat.SR_data.shader == 'invisible': flags |= 0x10 if mat.SR_data.shader == 'boundary': flags |= (0x10|0x20) + if mat.SR_data.shader == 'walking': flags |= (0x10|0x80) #} m.flags = flags m.surface_prop = int(mat.SR_data.surface_prop) + inf = material_info( mat ) if mat.SR_data.shader == 'standard': m.shader = 0 if mat.SR_data.shader == 'standard_cutout': m.shader = 1 @@ -754,14 +844,27 @@ def sr_compile_material( mat ): if mat.SR_data.shader == 'boundary':#{ m.shader = 6 #} - - inf = material_info( mat ) - if mat.SR_data.shader == 'standard' or \ - mat.SR_data.shader == 'standard_cutout' or \ - mat.SR_data.shader == 'terrain_blend' or \ - mat.SR_data.shader == 'vertex_blend': - #{ + if mat.SR_data.shader == 'fxglow':#{ + m.shader = 7 + #} + + if mat.SR_data.shader == 'cubemap':#{ + m.shader = 8 + m.tex_none0 = sr_entity_id( mat.SR_data.cubemap ) + + m.colour[0] = pow( mat.SR_data.tint[0], 1.0/2.2 ) + m.colour[1] = pow( mat.SR_data.tint[1], 1.0/2.2 ) + m.colour[2] = pow( mat.SR_data.tint[2], 1.0/2.2 ) + m.colour[3] = pow( mat.SR_data.tint[3], 1.0/2.2 ) + #} + + if mat.SR_data.shader == 'walking':#{ + m.shader = 9 + #} + + if mat.SR_data.shader in ['standard', 'standard_cutout', 'terrain_blend', \ + 'vertex_blend', 'fxglow', 'cubemap' ]: #{ if 'tex_diffuse' in inf: m.tex_diffuse = sr_compile_texture(inf['tex_diffuse']) #} @@ -783,8 +886,9 @@ def sr_armature_bones( armature ): yield from _recurse_bone( b ) #} -def sr_entity_id( obj ): -#{ +def sr_entity_id( obj ):#{ + if not obj: return 0 + tipo = get_entity_enum_id( obj_ent_type(obj) ) index = sr_compile.entity_ids[ obj.name ] @@ -1378,6 +1482,7 @@ def sr_compile_armature( obj ): lc_m = smtx.inverted() @ lc_m #} rq = lc_m.to_quaternion() + q_normalize( rq ) kf = mdl_transform() kf.co[0] = loc[0] @@ -1521,6 +1626,13 @@ def sr_compile( collection ): if ent_type == 'ent_font': continue if ent_type == 'ent_font_variant': continue if ent_type == 'ent_menuitem': continue + if ent_type == 'ent_challenge': continue + + #TODO: This is messy. + if ent_type == 'ent_gate':#{ + obj_data = obj.SR_data.ent_gate[0] + if obj_data.custom: continue + #} #-------------------------- print( F'[SR] {i: 3}/{mesh_count} {obj.name:<40}', end='\r' ) @@ -1568,18 +1680,28 @@ def sr_compile( collection ): obj_data = obj.SR_data.ent_gate[0] mesh_data = obj.data.SR_data.ent_gate[0] + flags = 0x0000 + if obj_data.tipo == 'default':#{ if obj_data.target:#{ gate.target = sr_compile.entity_ids[obj_data.target.name] - gate.type = 1 + flags |= 0x0001 #} #} elif obj_data.tipo == 'nonlocal':#{ gate.target = 0 gate.key = sr_compile_string(obj_data.key) - gate.type = 2 + flags |= 0x0002 #} - else: gate.type = 0 + + if obj_data.flip: flags |= 0x0004 + if obj_data.custom:#{ + flags |= 0x0008 + 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] gate.dimensions[1] = mesh_data.dimensions[1] @@ -1676,6 +1798,7 @@ def sr_compile( collection ): if obj_data.target:#{ volume.target = sr_entity_id( obj_data.target ) + volume._anon.trigger.event = obj_data.target_event #} sr_ent_push(volume) @@ -1727,6 +1850,61 @@ def sr_compile( collection ): worldinfo.timezone = obj_data.timezone sr_ent_push( worldinfo ) #} + elif ent_type == 'ent_ccmd':#{ + ccmd = ent_ccmd() + obj_data = obj.SR_data.ent_ccmd[0] + ccmd.pstr_command = sr_compile_string( obj_data.command ) + sr_ent_push( ccmd ) + #} + elif ent_type == 'ent_challenge':#{ + 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 = int(obj_data.filtrar) + challenge.filter2 = 0 + challenge.time_limit = obj_data.time_limit + + compile_obj_transform( obj, challenge.transform ) + challenge.submesh_start, challenge.submesh_count, _ = \ + sr_compile_mesh_internal( obj ) + + sr_ent_push( challenge ) + #} + elif ent_type == 'ent_unlock':#{ + unlock = ent_unlock() + obj_data = obj.SR_data.ent_unlock[0] + compile_obj_transform( obj, unlock.transform ) + 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 ) + #} + elif ent_type == 'ent_cubemap':#{ + cubemap = ent_cubemap() + co = obj.matrix_world @ Vector((0,0,0)) + cubemap.co[0] = co[0] + cubemap.co[1] = co[2] + cubemap.co[2] = -co[1] + cubemap.resolution = 0 + cubemap.live = 60 + sr_ent_push( cubemap ) + #} #} #} @@ -1922,9 +2100,10 @@ def sr_compile( collection ): path = F"{folder}{collection.name}.mdl" print( path ) + os.makedirs(os.path.dirname(path),exist_ok=True) fp = open( path, "wb" ) header = mdl_header() - header.version = 101 + header.version = MDL_VERSION_NR sr_array_title( header.arrays, \ 'index', len(file_array_instructions), \ sizeof(mdl_array), header_size ) @@ -2138,9 +2317,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() @@ -2148,13 +2330,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 ) @@ -2174,7 +2356,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() @@ -2185,18 +2369,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 ) #} #} #} @@ -2234,7 +2426,8 @@ class SR_MATERIAL_PANEL(bpy.types.Panel): row = box.row() if (active_mat.SR_data.shader != 'invisible') and \ - (active_mat.SR_data.shader != 'boundary'):#{ + (active_mat.SR_data.shader != 'boundary') and \ + (active_mat.SR_data.shader != 'walking'):#{ row.prop( active_mat.SR_data, "skate_surface" ) row.prop( active_mat.SR_data, "grind_surface" ) row.prop( active_mat.SR_data, "grow_grass" ) @@ -2258,6 +2451,11 @@ class SR_MATERIAL_PANEL(bpy.types.Panel): box.prop( active_mat.SR_data, "shore_colour" ) box.prop( active_mat.SR_data, "ocean_colour" ) #} + elif active_mat.SR_data.shader == "cubemap":#{ + box = _.layout.box() + box.prop( active_mat.SR_data, "cubemap" ) + box.prop( active_mat.SR_data, "tint" ) + #} #} #} @@ -2308,7 +2506,11 @@ class SR_OBJECT_ENT_GATE(bpy.types.PropertyGroup): key: bpy.props.StringProperty() tipo: bpy.props.EnumProperty(items=(('default', 'Default', ""), - ('nonlocal', 'Non-Local', ""),)) + ('nonlocal', 'Non-Local', ""))) + + 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 ): @@ -2318,6 +2520,11 @@ class SR_OBJECT_ENT_GATE(bpy.types.PropertyGroup): if data[0].tipo == 'default': box.prop( data[0], 'target' ) elif data[0].tipo == 'nonlocal': box.prop( data[0], 'key' ) + + flags = box.box() + flags.prop( data[0], 'flip' ) + flags.prop( data[0], 'custom' ) + flags.prop( data[0], 'locked' ) #} #} @@ -2665,8 +2872,7 @@ class SR_OBJECT_ENT_ROUTE(bpy.types.PropertyGroup): #} #} -class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup): -#{ +class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup):#{ subtype: bpy.props.EnumProperty( name="Subtype", items=[('0','Trigger',''), @@ -2675,15 +2881,41 @@ class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup): target: bpy.props.PointerProperty( \ type=bpy.types.Object, name="Target", \ - poll=lambda self,obj: sr_filter_ent_type(obj,\ - ['ent_audio','ent_skateshop'])) + 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 ): - #{ - data = data[0] - layout.prop( data, 'subtype' ) - layout.prop( data, 'target' ) + def inspect_target( layout, data, propname ):#{ + box = layout.box() + box.prop( data[0], propname ) + + row = box.row() + row.prop( data[0], propname + '_event') + + target = getattr( data[0], propname ) + if target:#{ + tipo = target.SR_data.ent_type + cls = globals()[ tipo ] + + table = getattr( cls, 'sr_functions', None ) + if table:#{ + 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' ) #} #} @@ -2747,16 +2979,15 @@ class SR_OBJECT_ENT_AUDIO(bpy.types.PropertyGroup): box.prop( data[0], 'flag_loop' ) box.prop( data[0], 'flag_auto' ) + layout.prop( data[0], 'probability_curve' ) + split = layout.split(factor=0.7) c = split.column() c.label( text='Filepath' ) c = split.column() - c.label( text='Chance (0.1s)' ) - - layout.prop( data[0], 'probability_curve' ) - + c.label( text='Chance' ) layout.template_list('SR_UL_AUDIO_LIST', 'Files', \ - data[0], 'files', data[0], 'file_index', rows=5) + data[0], 'files', data[0], 'files_index', rows=5) row = layout.row() row.operator( 'skaterift.al_new_entry', text='Add' ) @@ -2961,6 +3192,86 @@ class SR_OBJECT_ENT_WORLD_INFO(bpy.types.PropertyGroup): timezone: bpy.props.FloatProperty(name="Timezone(hrs) (UTC0 +hrs)") #} +class SR_OBJECT_ENT_CCMD(bpy.types.PropertyGroup): +#{ + command: bpy.props.StringProperty(name="Command Line") +#} + +class SR_OBJECT_ENT_CHALLENGE(bpy.types.PropertyGroup):#{ + proxima: bpy.props.PointerProperty( \ + 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="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 ) + filtrar: bpy.props.EnumProperty( name='Filter',\ + items=[('0','none',''), + (str(0x1),'trick_shuvit',''), + (str(0x2),'trick_kickflip',''), + (str(0x4),'trick_treflip',''), + (str(0x1|0x2|0x4),'trick_any',''), + (str(0x8),'flip_back',''), + (str(0x10),'flip_front',''), + (str(0x8|0x10),'flip_any',''), + (str(0x20),'grind_truck_any',''), + (str(0x40),'grind_board_any',''), + (str(0x20|0x40),'grind_any',''), + (str(0x80),'footplant','') + ]) + + @staticmethod + def sr_inspector( layout, data ):#{ + layout.prop( data[0], 'proxima' ) + layout.prop( data[0], 'time_limit' ) + layout.prop( data[0], 'filtrar' ) + 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): #{ ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE) @@ -2977,6 +3288,10 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): bpy.props.CollectionProperty(type=SR_OBJECT_ENT_WORKSHOP_PREVIEW) ent_menuitem: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MENU_ITEM) 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", @@ -3051,7 +3366,10 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): ('vertex_blend', "vertex_blend", ''), ('water',"water",''), ('invisible','Invisible',''), - ('boundary','Boundary','') + ('boundary','Boundary',''), + ('fxglow','FX Glow',''), + ('cubemap','Cubemap',''), + ('walking','Walking','') ]) surface_prop: bpy.props.EnumProperty( @@ -3117,6 +3435,18 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): default=Vector((0.0,0.006,0.03)),\ description="Water colour in the deep bits"\ ) + tint: bpy.props.FloatVectorProperty( \ + name="Tint",\ + subtype='COLOR',\ + min=0.0,max=1.0,\ + size=4,\ + default=Vector((1.0,1.0,1.0,1.0)),\ + description="Reflection tint"\ + ) + + cubemap: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="cubemap", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_cubemap'])) #} # ---------------------------------------------------------------------------- # @@ -3126,6 +3456,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 = [] @@ -3281,7 +3612,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 @@ -3385,7 +3716,8 @@ def cv_draw_lines(): cv_view_shader, 'LINES', \ { "pos":cv_view_verts, "color":cv_view_colours }) - lines.draw( cv_view_shader ) + if bpy.context.scene.SR_data.gizmos: + lines.draw( cv_view_shader ) cv_view_verts = [] cv_view_colours = [] @@ -3462,8 +3794,8 @@ def draw_cone_twist( center, vx, vy, va ): p0 = center + (axis + vx*c0 + vy*s0).normalized() * size p1 = center + (axis + vx*c1 + vy*s1).normalized() * size - col0 = ( abs(c0), abs(s0), 0.0, 1.0 ) - col1 = ( abs(c1), abs(s1), 0.0, 1.0 ) + col0 = ( abs(c0), abs(s0), 0.0 ) + col1 = ( abs(c1), abs(s1), 0.0 ) cv_view_verts += [center, p0, p0, p1] cv_view_colours += [ (0,0,0), col0, col0, col1 ] @@ -3620,14 +3952,14 @@ def cv_ent_volume( obj ): cv_draw_ucube( obj.matrix_world, (0,1,0) ) if data.target:#{ - cv_draw_line( obj.location, data.target.location, (0,1,0) ) + cv_draw_arrow( obj.location, data.target.location, (0,1,0) ) #} #} elif data.subtype == '1':#{ cv_draw_ucube( obj.matrix_world, (1,1,0) ) if data.target:#{ - cv_draw_line( obj.location, data.target.location, (1,1,0) ) + cv_draw_arrow( obj.location, data.target.location, (1,1,0) ) #} #} #} @@ -3862,8 +4194,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 @@ -3906,6 +4237,30 @@ def cv_draw(): elif ent_type == 'ent_volume':#{ cv_ent_volume( obj ) #} + elif ent_type == 'ent_challenge':#{ + data = obj.SR_data.ent_challenge[0] + 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: cv_draw_sphere( obj.location, obj.scale[0], (1,1,0) ) @@ -4072,7 +4427,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,\ @@ -4096,7 +4475,8 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\ 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_WORLD_INFO,SR_OBJECT_ENT_CCMD,\ + 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 \ @@ -4123,9 +4503,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(): @@ -4133,8 +4515,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') #} # ---------------------------------------------------------------------------- #