X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=blender_export.py;h=f9b8f6925120eb57da1fd0760681f93d44153e7a;hb=4b8fc63f926737ca0593a4e471550f9f4995c538;hp=a7698e9bf2fa6f33334d1d2d31de574286b6c873;hpb=1b522daa02f28128498b04def4d60b63e590d1f3;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/blender_export.py b/blender_export.py index a7698e9..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", @@ -30,8 +31,21 @@ sr_entity_list = [ ('ent_font', 'Font', '', 9 ), ('ent_font_variant', 'Font:Variant', '', 10 ), ('ent_traffic', 'Traffic Model', '', 11 ), + ('ent_skateshop', 'Skate Shop', '', 12 ), + ('ent_camera', 'Camera', '', 13 ), + ('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:#{ @@ -68,7 +82,8 @@ class mdl_submesh(Structure): ("vertex_start",c_uint32), ("vertex_count",c_uint32), ("bbx",(c_float*3)*2), - ("material_id",c_uint32)] # index into the material array + ("material_id",c_uint16), # index into the material array + ("flags",c_uint16)] #} class mdl_material(Structure): @@ -178,8 +193,9 @@ 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), ("co", (c_float*3)*2), ("q", (c_float*4)*2), @@ -188,7 +204,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): @@ -270,19 +290,13 @@ class volume_union(Union): ("particles",volume_particles)] #} -class ent_index(Structure): -#{ - _fields_ = [("type",c_uint32), - ("index",c_uint32)] -#} - class ent_volume(Structure): #{ _fields_ = [("transform",mdl_transform), ("to_world",(c_float*3)*4), ("to_local",(c_float*3)*4), ("type",c_uint32), - ("target",ent_index), + ("target",c_uint32), ("_anon",volume_union)] #} @@ -329,10 +343,152 @@ class ent_font(Structure): ("glyph_utf32_base",c_uint32)] #} +class ent_traffic(Structure): +#{ + _fields_ = [("transform",mdl_transform), + ("submesh_start",c_uint32), + ("submesh_count",c_uint32), + ("start_node",c_uint32), + ("node_count",c_uint32), + ("speed",c_float), + ("t",c_float), + ("index",c_uint32)] +#} + +# Skateshop +# --------------------------------------------------------------- +class ent_skateshop_characters(Structure): +#{ + _fields_ = [("id_display",c_uint32), + ("id_info",c_uint32)] +#} +class ent_skateshop_boards(Structure): +#{ + _fields_ = [("id_display",c_uint32), + ("id_info",c_uint32), + ("id_rack",c_uint32)] +#} +class ent_skateshop_worlds(Structure): +#{ + _fields_ = [("id_display",c_uint32), + ("id_info",c_uint32)] +#} +class ent_skateshop_anon_union(Union): +#{ + _fields_ = [("boards",ent_skateshop_boards), + ("character",ent_skateshop_characters), + ("worlds",ent_skateshop_worlds)] +#} +class ent_skateshop(Structure): +#{ + _fields_ = [("transform",mdl_transform), ("type",c_uint32), + ("id_camera",c_uint32), + ("_anonymous_union",ent_skateshop_anon_union)] +#} + +class ent_swspreview(Structure): +#{ + _fields_ = [("id_camera",c_uint32), + ("id_display",c_uint32), + ("id_display1",c_uint32)] +#} + +# Menu +# ----------------------------------------------------------------- +class ent_menuitem_slider(Structure): +#{ + _fields_ = [("id_min",c_uint32), + ("id_max",c_uint32), + ("id_handle",c_uint32), + ("pstr_data",c_uint32)] +#} +class ent_menuitem_button(Structure): +#{ + _fields_ = [("pstr",c_uint32)] +#} +class ent_menuitem_checkmark(Structure): +#{ + _fields_ = [("id_check",c_uint32), + ("pstr_data",c_uint32), + ("offset",c_float*3)] +#} +class ent_menuitem_page(Structure): +#{ + _fields_ = [("pstr_name",c_uint32), + ("id_entrypoint",c_uint32), + ("id_viewpoint",c_uint32)] +#} +class ent_menuitem_anon_union(Union): +#{ + _fields_ = [("slider",ent_menuitem_slider), + ("button",ent_menuitem_button), + ("checkmark",ent_menuitem_checkmark), + ("page",ent_menuitem_page)] +#} +class ent_menuitem(Structure): +#{ + _fields_ = [("type",c_uint32), ("groups",c_uint32), + ("id_links",c_uint32*4), + ("factive",c_float), ("fvisible",c_float), + #-- TODO: Refactor this into a simple mesh structure + ("transform",mdl_transform), + ("submesh_start",c_uint32),("submesh_count",c_uint32), + ("_u64",c_uint64), + #-- end + ("_anonymous_union", ent_menuitem_anon_union)] +#} + +class ent_camera(Structure): +#{ + _fields_ = [("transform",mdl_transform), + ("fov",c_float)] +#} + +class ent_worldinfo(Structure): +#{ + _fields_ = [("pstr_name",c_uint32), + ("pstr_author",c_uint32), # unused + ("pstr_desc",c_uint32), # unused + ("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), + ("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' elif obj.type == 'LIGHT': return 'ent_light' + elif obj.type == 'CAMERA': return 'ent_camera' else: return obj.SR_data.ent_type #} @@ -351,11 +507,39 @@ 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)) - q = obj.matrix_local.to_quaternion() + + # This was changed from matrix_local on 09.05.23 + q = obj.matrix_world.to_quaternion() s = obj.scale + q_normalize( q ) # Setup transform # @@ -401,6 +585,7 @@ def sr_compile_string( s ): index = len( sr_compile.string_data ) sr_compile.string_cache[s] = index + sr_compile.string_data.extend( c_uint32(hash_djb2(s)) ) sr_compile.string_data.extend( s.encode('utf-8') ) sr_compile.string_data.extend( b'\0' ) @@ -442,6 +627,10 @@ cxr_graph_mapping = \ "Color": material_tex_image("tex_normal") } } + }, + "Emission": + { + "Color": material_tex_image("tex_diffuse") } } @@ -585,6 +774,7 @@ def sr_compile_material( mat ): if mat.SR_data.skate_surface: flags |= 0x1 if mat.SR_data.grow_grass: flags |= 0x4 if mat.SR_data.grind_surface: flags |= 0x8 + if mat.SR_data.preview_visibile: flags |= 0x40 #} if mat.SR_data.shader == 'invisible': flags |= 0x10 if mat.SR_data.shader == 'boundary': flags |= (0x10|0x20) @@ -635,14 +825,18 @@ def sr_compile_material( mat ): if mat.SR_data.shader == 'boundary':#{ m.shader = 6 #} + + if mat.SR_data.shader == 'fxglow':#{ + m.shader = 7 + #} 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': - #{ + mat.SR_data.shader == 'vertex_blend' or \ + mat.SR_data.shader == 'fxglow': #{ if 'tex_diffuse' in inf: m.tex_diffuse = sr_compile_texture(inf['tex_diffuse']) #} @@ -664,25 +858,25 @@ def sr_armature_bones( armature ): yield from _recurse_bone( b ) #} -def sr_compile_mesh( obj ): -#{ - node=mdl_mesh() - compile_obj_transform(obj, node.transform) - node.pstr_name = sr_compile_string(obj.name) - ent_type = obj_ent_type( obj ) - - node.entity_id = 0 +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 ] - if ent_type != 'none':#{ - ent_id_lwr = sr_compile.entity_ids[obj.name] - ent_id_upr = get_entity_enum_id( obj_ent_type(obj) ) - node.entity_id = (ent_id_upr << 16) | ent_id_lwr - #} - print( node.entity_id ) + return (tipo&0xffff)<<16 | (index&0xffff) +#} +# Returns submesh_start,count and armature_id +def sr_compile_mesh_internal( obj ): +#{ can_use_cache = True armature = None + submesh_start = 0 + submesh_count = 0 + armature_id = 0 + for mod in obj.modifiers:#{ if mod.type == 'DATA_TRANSFER' or mod.type == 'SHRINKWRAP' or \ mod.type == 'BOOLEAN' or mod.type == 'CURVE' or \ @@ -695,7 +889,7 @@ def sr_compile_mesh( obj ): armature = mod.object rig_weight_groups = \ ['0 [ROOT]']+[_.name for _ in sr_armature_bones(mod.object)] - node.armature_id = sr_compile.entity_ids[armature.name] + armature_id = sr_compile.entity_ids[armature.name] POSE_OR_REST_CACHE = armature.data.pose_position armature.data.pose_position = 'REST' @@ -706,16 +900,15 @@ def sr_compile_mesh( obj ): # if can_use_cache and (obj.data.name in sr_compile.mesh_cache):#{ ref = sr_compile.mesh_cache[obj.data.name] - node.submesh_start = ref[0] - node.submesh_count = ref[1] - sr_compile.mesh_data.extend(bytearray(node)) - return + submesh_start = ref[0] + submesh_count = ref[1] + return (submesh_start,submesh_count,armature_id) #} # Compile a whole new mesh # - node.submesh_start = len(sr_compile.submesh_data)//sizeof(mdl_submesh) - node.submesh_count = 0 + submesh_start = len(sr_compile.submesh_data)//sizeof(mdl_submesh) + submesh_count = 0 dgraph = bpy.context.evaluated_depsgraph_get() data = obj.evaluated_get(dgraph).data @@ -899,16 +1092,37 @@ def sr_compile_mesh( obj ): # Add submesh to encoder # sr_compile.submesh_data.extend( bytearray(sm) ) - node.submesh_count += 1 + submesh_count += 1 #} if armature:#{ armature.data.pose_position = POSE_OR_REST_CACHE #} - # Save a reference to this node since we want to reuse the submesh indices + # Save a reference to this mesh since we want to reuse the submesh indices # later. - sr_compile.mesh_cache[obj.data.name]=(node.submesh_start,node.submesh_count) + sr_compile.mesh_cache[obj.data.name]=(submesh_start,submesh_count) + return (submesh_start,submesh_count,armature_id) +#} + +def sr_compile_mesh( obj ): +#{ + node=mdl_mesh() + compile_obj_transform(obj, node.transform) + node.pstr_name = sr_compile_string(obj.name) + ent_type = obj_ent_type( obj ) + + node.entity_id = 0 + + if ent_type != 'none':#{ + ent_id_lwr = sr_compile.entity_ids[obj.name] + ent_id_upr = get_entity_enum_id( obj_ent_type(obj) ) + node.entity_id = (ent_id_upr << 16) | ent_id_lwr + #} + + node.submesh_start, node.submesh_count, node.armature_id = \ + sr_compile_mesh_internal( obj ) + sr_compile.mesh_data.extend(bytearray(node)) #} @@ -931,7 +1145,7 @@ def sr_compile_fonts( collection ): font.glyph_start = glyph_count glyph_base = data.glyphs[0].utf32 - glyph_range = data.glyphs[-1].utf32 - glyph_base + glyph_range = data.glyphs[-1].utf32+1 - glyph_base font.glyph_utf32_base = glyph_base font.glyph_count = glyph_range @@ -1042,6 +1256,75 @@ def sr_compile_fonts( collection ): #} #} +def sr_compile_menus( collection ): +#{ + print( "[SR1] Compiling menus" ) + groups = [] + + for obj in collection.all_objects:#{ + if obj_ent_type(obj) != 'ent_menuitem': continue + obj_data = obj.SR_data.ent_menuitem[0] + + bitmask = 0x00000000 + + for col in obj.users_collection:#{ + name = col.name + if name not in groups: groups.append( name ) + bitmask |= (0x1 << groups.index(name)) + #} + + item = ent_menuitem() + item.type = int( obj_data.tipo ) + item.groups = bitmask + + compile_obj_transform( obj, item.transform ) + if obj.type == 'MESH':#{ + item.submesh_start, item.submesh_count, _ = \ + sr_compile_mesh_internal( obj ) + #} + + if item.type == 1 or item.type == 2:#{ + item_button = item._anonymous_union.button + item_button.pstr = sr_compile_string( obj_data.string ) + #} + elif item.type == 3:#{ + item_checkmark = item._anonymous_union.checkmark + item_checkmark.pstr_data = sr_compile_string( obj_data.string ) + item_checkmark.id_check = sr_entity_id( obj_data.checkmark ) + delta = obj_data.checkmark.location - obj.location + item_checkmark.offset[0] = delta[0] + item_checkmark.offset[1] = delta[2] + item_checkmark.offset[2] = -delta[1] + #} + elif item.type == 4:#{ + item_slider = item._anonymous_union.slider + item_slider.id_min = sr_entity_id( obj_data.slider_minloc ) + item_slider.id_max = sr_entity_id( obj_data.slider_maxloc ) + item_slider.id_handle = sr_entity_id( obj_data.slider_handle ) + item_slider.pstr_data = sr_compile_string( obj_data.string ) + #} + elif item.type == 5:#{ + item_page = item._anonymous_union.page + item_page.pstr_name = sr_compile_string( obj_data.string ) + item_page.id_entrypoint = sr_entity_id( obj_data.newloc ) + item_page.id_viewpoint = sr_entity_id( obj_data.camera ) + #} + + if obj_data.link0: + item.id_links[0] = sr_entity_id( obj_data.link0 ) + if obj_data.link1: + item.id_links[1] = sr_entity_id( obj_data.link1 ) + if item.type != 4:#{ + if obj_data.link2: + item.id_links[2] = sr_entity_id( obj_data.link2 ) + if obj_data.link3: + item.id_links[3] = sr_entity_id( obj_data.link3 ) + #} + + sr_ent_push( item ) + #} +#} + def sr_compile_armature( obj ): #{ node = mdl_armature() @@ -1171,6 +1454,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] @@ -1234,6 +1518,15 @@ def sr_array_title( arr, name, count, size, offset ): arr.item_size = size #} +def hash_djb2(s): +#{ + picadillo = 5381 + for x in s:#{ + picadillo = (((picadillo << 5) + picadillo) + ord(x)) & 0xFFFFFFFF + #} + return picadillo +#} + def sr_compile( collection ): #{ print( F"[SR] compiler begin ({collection.name}.mdl)" ) @@ -1272,9 +1565,16 @@ def sr_compile( collection ): sr_compile.entities = {} sr_compile.entity_ids = {} + # begin + # ------------------------------------------------------- + + sr_compile_string( "null" ) + mesh_count = 0 for obj in collection.all_objects: #{ - if obj.type == 'MESH': mesh_count += 1 + if obj.type == 'MESH':#{ + mesh_count += 1 + #} ent_type = obj_ent_type( obj ) if ent_type == 'none': continue @@ -1289,6 +1589,24 @@ def sr_compile( collection ): for obj in collection.all_objects:#{ if obj.type == 'MESH':#{ i+=1 + + ent_type = obj_ent_type( obj ) + + # entity ignore mesh list + # + if ent_type == 'ent_traffic': continue + 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' ) sr_compile_mesh( obj ) #} @@ -1323,22 +1641,39 @@ def sr_compile( collection ): light.colour[3] = obj.data.energy sr_ent_push( light ) #} + elif ent_type == 'ent_camera': #{ + cam = ent_camera() + compile_obj_transform( obj, cam.transform ) + cam.fov = obj.data.angle * 45.0 + sr_ent_push(cam) + #} elif ent_type == 'ent_gate': #{ gate = ent_gate() 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 = sr_compile_string(obj_data.key) - gate.type = 2 + gate.target = 0 + gate.key = sr_compile_string(obj_data.key) + 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] @@ -1434,9 +1769,8 @@ def sr_compile( collection ): compile_obj_transform( obj, volume.transform ) if obj_data.target:#{ - target = obj_data.target - volume.target.type = get_entity_enum_id( obj_ent_type(target) ) - volume.target.index = sr_compile.entity_ids[ target.name ] + volume.target = sr_entity_id( obj_data.target ) + volume._anon.trigger.event = obj_data.target_event #} sr_ent_push(volume) @@ -1447,10 +1781,95 @@ def sr_compile( collection ): compile_obj_transform( obj, marker.transform ) sr_ent_push(marker) #} + elif ent_type == 'ent_skateshop':#{ + skateshop = ent_skateshop() + obj_data = obj.SR_data.ent_skateshop[0] + skateshop.type = int(obj_data.tipo) + if skateshop.type == 0:#{ + boardshop = skateshop._anonymous_union.boards + boardshop.id_display = sr_entity_id( obj_data.mark_display ) + boardshop.id_info = sr_entity_id( obj_data.mark_info ) + boardshop.id_rack = sr_entity_id( obj_data.mark_rack ) + #} + elif skateshop.type == 1:#{ + charshop = skateshop._anonymous_union.character + charshop.id_display = sr_entity_id( obj_data.mark_display ) + charshop.id_info = sr_entity_id( obj_data.mark_info ) + #} + elif skateshop.type == 2:#{ + worldshop = skateshop._anonymous_union.worlds + worldshop.id_display = sr_entity_id( obj_data.mark_display ) + worldshop.id_info = sr_entity_id( obj_data.mark_info ) + #} + skateshop.id_camera = sr_entity_id( obj_data.cam ) + compile_obj_transform( obj, skateshop.transform ) + sr_ent_push(skateshop) + #} + elif ent_type == 'ent_swspreview':#{ + workshop_preview = ent_swspreview() + obj_data = obj.SR_data.ent_swspreview[0] + workshop_preview.id_display = sr_entity_id( obj_data.mark_display ) + workshop_preview.id_display1 = sr_entity_id( obj_data.mark_display1) + workshop_preview.id_camera = sr_entity_id( obj_data.cam ) + sr_ent_push( workshop_preview ) + #} + elif ent_type == 'ent_worldinfo':#{ + worldinfo = ent_worldinfo() + obj_data = obj.SR_data.ent_worldinfo[0] + worldinfo.pstr_name = sr_compile_string( obj_data.name ) + worldinfo.pstr_author = sr_compile_string( obj_data.author ) + worldinfo.pstr_desc = sr_compile_string( obj_data.desc ) + 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 = 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] + 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 ) + #} #} #} - sr_compile_fonts(collection) + sr_compile_menus( collection ) + sr_compile_fonts( collection ) def _children( col ):#{ yield col @@ -1468,6 +1887,7 @@ def sr_compile( collection ): route_gates = [] route_curves = [] routes = [] + traffics = [] for obj in col.objects:#{ if obj.type == 'ARMATURE': pass @@ -1483,6 +1903,8 @@ def sr_compile( collection ): #} elif ent_type == 'ent_route': routes += [obj] + elif ent_type == 'ent_traffic': + traffics += [obj] #} #} @@ -1541,6 +1963,52 @@ def sr_compile( collection ): sr_ent_push( route ) #} + for obj in traffics:#{ + traffic = ent_traffic() + compile_obj_transform( obj, traffic.transform ) + traffic.submesh_start, traffic.submesh_count, _ = \ + sr_compile_mesh_internal( obj ) + + # find best subsection + + graph_keys = list(dij.graph) + min_dist = 100.0 + best_point = 0 + + for j in range(len(dij.points)):#{ + point = dij.points[j] + dist = (point-obj.location).magnitude + + if dist < min_dist:#{ + min_dist = dist + best_point = j + #} + #} + + # scan to each edge + best_begin = best_point + best_end = best_point + + while True:#{ + map0 = dij.subsections[best_begin] + if map0[1] == -1: break + best_begin = map0[1] + #} + while True:#{ + map1 = dij.subsections[best_end] + if map1[2] == -1: break + best_end = map1[2] + #} + + traffic.start_node = routenode_count + best_begin + traffic.node_count = best_end - best_begin + traffic.index = best_point - best_begin + traffic.speed = obj.SR_data.ent_traffic[0].speed + traffic.t = 0.0 + + sr_ent_push(traffic) + #} + for point in dij.points:#{ rn = ent_route_node() rn.co[0] = point[0] @@ -1552,7 +2020,6 @@ def sr_compile( collection ): routenode_count += len(dij.points) #} - print( F"[SR] Writing file" ) file_array_instructions = {} @@ -1593,9 +2060,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 = 40 + header.version = MDL_VERSION_NR sr_array_title( header.arrays, \ 'index', len(file_array_instructions), \ sizeof(mdl_array), header_size ) @@ -1809,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() @@ -1819,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 ) @@ -1845,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() @@ -1856,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 ) #} #} #} @@ -1909,6 +2390,7 @@ class SR_MATERIAL_PANEL(bpy.types.Panel): row.prop( active_mat.SR_data, "skate_surface" ) row.prop( active_mat.SR_data, "grind_surface" ) row.prop( active_mat.SR_data, "grow_grass" ) + row.prop( active_mat.SR_data, "preview_visibile" ) #} #} @@ -1978,7 +2460,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 ): @@ -1988,6 +2474,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' ) #} #} @@ -2291,7 +2782,8 @@ class SR_UL_FONT_GLYPH_LIST(bpy.types.UIList): s1 = c.split(factor=0.3) c = s1.column() row = c.row() - lbl = chr(item.utf32) if item.utf32 >= 32 and item.utf32 <= 126 else 'ERR' + lbl = chr(item.utf32) if item.utf32 >= 32 and item.utf32 <= 126 else \ + f'x{item.utf32:x}' row.label(text=lbl) c = s1.column() c.prop( item, 'utf32', text='', emboss=True ) @@ -2334,8 +2826,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',''), @@ -2344,14 +2835,43 @@ 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'])) + poll=lambda self,obj: sr_filter_ent_type(obj,\ + ['ent_audio','ent_skateshop','ent_ccmd',\ + 'ent_challenge'])) + 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' ) #} #} @@ -2415,16 +2935,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' ) @@ -2492,9 +3011,206 @@ class SR_OBJECT_ENT_FONT(bpy.types.PropertyGroup): class SR_OBJECT_ENT_TRAFFIC(bpy.types.PropertyGroup): #{ - track: bpy.props.PointerProperty(\ - type=bpy.types.Object, name='track', \ - poll=lambda self,obj: sr_filter_ent_type(obj,['ent_route_node'])) + speed: bpy.props.FloatProperty(default=1.0) +#} + +class SR_OBJECT_ENT_SKATESHOP(bpy.types.PropertyGroup): +#{ + tipo: bpy.props.EnumProperty( name='Type', + items=[('0','boards',''), + ('1','character',''), + ('2','world','')] ) + mark_rack: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Board Rack", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + mark_display: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Selected Board Display", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + mark_info: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Selected Board Info", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + cam: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Viewpoint", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera'])) +#} + +class SR_OBJECT_ENT_WORKSHOP_PREVIEW(bpy.types.PropertyGroup): +#{ + mark_display: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Board Display", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + mark_display1: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Board Display (other side)", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + cam: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Viewpoint", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera'])) +#} + +class SR_OBJECT_ENT_MENU_ITEM(bpy.types.PropertyGroup): +#{ + link0: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Link 0", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + link1: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Link 1", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + link2: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Link 2", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + link3: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Link 3", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + + newloc: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="New location", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + camera: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Camera", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera'])) + + slider_minloc: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Slider min", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + slider_maxloc: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Slider max", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + slider_handle: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Slider handle", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + + checkmark: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Checked", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem'])) + + string: bpy.props.StringProperty( name="String" ) + tipo: bpy.props.EnumProperty( name='Type', + items=[('0','visual',''), + ('1','event button',''), + ('2','page button',''), + ('3','toggle', ''), + ('4','slider',''), + ('5','page','')]) + + @staticmethod + def sr_inspector( layout, data ): + #{ + data = data[0] + box = layout.box() + box.prop( data, 'tipo' ) + + if data.tipo == '0':#{ + return + #} + elif data.tipo == '1':#{ + box.prop( data, 'string', text='Event' ) + #} + elif data.tipo == '2':#{ + box.prop( data, 'string', text='Page' ) + box.prop( data, 'newloc' ) + #} + elif data.tipo == '3':#{ + box.prop( data, 'string', text='Data (i32)' ) + box.prop( data, 'checkmark' ) + #} + elif data.tipo == '4':#{ + box.prop( data, 'string', text='Data (f32)' ) + box.prop( data, 'slider_minloc' ) + box.prop( data, 'slider_maxloc' ) + box.prop( data, 'slider_handle' ) + box = box.box() + box.label( text="Links" ) + box.prop( data, 'link0', text='v0' ) + box.prop( data, 'link1', text='v1' ) + return + #} + elif data.tipo == '5':#{ + box.prop( data, 'string', text='Page Name' ) + box.prop( data, 'newloc', text='Entry Point' ) + box.prop( data, 'camera', text='Viewpoint' ) + return + #} + + box = box.box() + box.label( text="Links" ) + box.prop( data, 'link0' ) + box.prop( data, 'link1' ) + box.prop( data, 'link2' ) + box.prop( data, 'link3' ) + #} +#} + +class SR_OBJECT_ENT_WORLD_INFO(bpy.types.PropertyGroup): +#{ + name: bpy.props.StringProperty(name="Name") + desc: bpy.props.StringProperty(name="Description") + author: bpy.props.StringProperty(name="Author") + 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 ) + + @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): @@ -2508,6 +3224,16 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): ent_glyph: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GLYPH) ent_font: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_FONT) ent_traffic: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_TRAFFIC) + ent_skateshop: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_SKATESHOP) + ent_swspreview: \ + 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", items=sr_entity_list, @@ -2581,7 +3307,8 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): ('vertex_blend', "vertex_blend", ''), ('water',"water",''), ('invisible','Invisible',''), - ('boundary','Boundary','') + ('boundary','Boundary',''), + ('fxglow','FX Glow',''), ]) surface_prop: bpy.props.EnumProperty( @@ -2614,6 +3341,11 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): default=False,\ description = "Spawn grass sprites on this surface?" \ ) + preview_visibile: bpy.props.BoolProperty( \ + name="Preview visibile", \ + default=True,\ + description = "Show this material in preview models?" \ + ) blend_offset: bpy.props.FloatVectorProperty( \ name="Blend Offset", \ size=2, \ @@ -2651,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 = [] @@ -2806,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 @@ -2910,7 +3643,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 = [] @@ -2987,8 +3721,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 ] @@ -3145,14 +3879,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) ) #} #} #} @@ -3387,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 @@ -3431,6 +4164,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) ) @@ -3458,6 +4215,134 @@ def cv_draw(): #} #} #} + elif ent_type == 'ent_skateshop':#{ + data = obj.SR_data.ent_skateshop[0] + display = data.mark_display + info = data.mark_info + + if data.tipo == '0':#{ + cc = (0.0,0.9,0.6) + cc1 = (0.4,0.9,0.2) + cc2 = (0.9,0.6,0.1) + + rack = data.mark_rack + + rack_cu = Vector((3.15,2.0,0.1))*0.5 + rack_co = Vector((0.0,0.0,0.0)) + display_cu = Vector((0.3,1.2,0.1))*0.5 + display_co = Vector((0.0,0.0,0.1))*0.5 + info_cu = Vector((1.2,0.01,0.3))*0.5 + info_co = Vector((0.0,0.0,0.0))*0.5 + #} + elif data.tipo == '1':#{ + rack = None + cc1 = (1.0,0.0,0.0) + cc2 = (1.0,0.5,0.0) + display_cu = Vector((0.4,0.4,2.0))*0.5 + display_co = Vector((0.0,0.0,1.0))*0.5 + info_cu = Vector((1.2,0.01,0.3))*0.5 + info_co = Vector((0.0,0.0,0.0))*0.5 + #} + elif data.tipo == '2':#{ + rack = None + cc1 = (1.0,0.0,0.0) + cc2 = (1.0,0.5,0.0) + display_cu = Vector((1.0,1.0,0.5))*0.5 + display_co = Vector((0.0,0.0,0.5))*0.5 + info_cu = Vector((1.2,0.01,0.3))*0.5 + info_co = Vector((0.0,0.0,0.0))*0.5 + #} + + if rack: + cv_draw_ucube( rack.matrix_world, cc, rack_cu, rack_co ) + if display: + cv_draw_ucube( display.matrix_world, cc1, display_cu, display_co) + if info: + cv_draw_ucube( info.matrix_world, cc2, info_cu, info_co ) + #} + elif ent_type == 'ent_swspreview':#{ + cc1 = (0.4,0.9,0.2) + data = obj.SR_data.ent_swspreview[0] + display = data.mark_display + display1 = data.mark_display1 + display_cu = Vector((0.3,1.2,0.1))*0.5 + display_co = Vector((0.0,0.0,0.1))*0.5 + if display: + cv_draw_ucube( display.matrix_world, cc1, display_cu, display_co) + if display1: + cv_draw_ucube(display1.matrix_world, cc1, display_cu, display_co) + #} + elif ent_type == 'ent_menuitem':#{ + for i,col in enumerate(obj.users_collection):#{ + colour32 = hash_djb2( col.name ) + r = pow(((colour32 ) & 0xff) / 255.0, 2.2 ) + g = pow(((colour32>>8 ) & 0xff) / 255.0, 2.2 ) + b = pow(((colour32>>16) & 0xff) / 255.0, 2.2 ) + cc = (r,g,b) + vs = [None for _ in range(8)] + scale = i*0.02 + for j in range(8):#{ + v0 = Vector([(obj.bound_box[j][z]+\ + ((-1.0 if obj.bound_box[j][z]<0.0 else 1.0)*scale)) \ + for z in range(3)]) + vs[j] = obj.matrix_world @ v0 + #} + indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ + (0,4),(1,5),(2,6),(3,7)] + for l in indices:#{ + v0 = vs[l[0]] + v1 = vs[l[1]] + cv_view_verts += [(v0[0],v0[1],v0[2])] + cv_view_verts += [(v1[0],v1[1],v1[2])] + cv_view_colours += [cc,cc] + #} + #} + cv_draw_lines() + cc = (1.0,1.0,1.0) + data = obj.SR_data.ent_menuitem[0] + if data.tipo == '4':#{ + if data.slider_minloc and data.slider_maxloc:#{ + v0 = data.slider_minloc.location + v1 = data.slider_maxloc.location + cv_draw_line( v0, v1, cc ) + #} + #} + + colour32 = hash_djb2(obj.name) + r = ((colour32 ) & 0xff) / 255.0 + g = ((colour32>>8 ) & 0xff) / 255.0 + b = ((colour32>>16) & 0xff) / 255.0 + cc = (r,g,b) + origin = obj.location + (Vector((r,g,b))*2.0-Vector((1.0,1.0,1.0)))\ + * 0.04 + + size = 0.01 + + if data.tipo != '0':#{ + if data.tipo == '4':#{ + if data.link0:#{ + cv_draw_arrow( origin, data.link0.location, cc, size ) + #} + if data.link1:#{ + cv_draw_arrow( origin, data.link1.location, cc, size ) + #} + #} + else:#{ + if data.link0:#{ + cv_draw_arrow( origin, data.link0.location, cc, size ) + #} + if data.link1:#{ + cv_draw_arrow( origin, data.link1.location, cc, size ) + #} + if data.link2:#{ + cv_draw_arrow( origin, data.link2.location, cc, size ) + #} + if data.link3:#{ + cv_draw_arrow( origin, data.link3.location, cc, size ) + #} + #} + #} + #} #} #} @@ -3469,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,\ @@ -3491,7 +4400,10 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ SR_OBJECT_ENT_FONT_VARIANT, SR_OBJECT_ENT_GLYPH_ENTRY,\ SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\ - SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,\ + 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_UNLOCK,SR_OBJECT_ENT_RELAY,\ \ SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \ @@ -3518,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(): @@ -3528,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') #} # ---------------------------------------------------------------------------- #