"category":"Import/Export",
}
-sr_entity_alias = {
- 'ent_gate': 1,
- 'ent_spawn': 2,
- 'ent_route_node': 3,
- 'ent_route': 4,
- 'ent_water': 5,
- 'ent_volume': 6,
- 'ent_audio': 7,
- 'ent_marker': 8,
- 'ent_glyph': 9
-}
+sr_entity_list = [
+ ('none', 'None', '', 0 ),
+ ('ent_gate', 'Gate', '', 1 ),
+ ('ent_spawn', 'Spawn Point', '', 2 ),
+ ('ent_route_node', 'Routing Path', '', 3 ),
+ ('ent_route', 'Skate Course', '', 4 ),
+ ('ent_water', 'Water Surface', '', 5 ),
+ ('ent_volume', 'Volume/Trigger', '', 6 ),
+ ('ent_audio', 'Audio', '', 7 ),
+ ('ent_marker', 'Marker', '', 8 ),
+ ('ent_font', 'Font', '', 9 ),
+ ('ent_font_variant', 'Font:Variant', '', 10 ),
+ ('ent_traffic', 'Traffic Model', '', 11 ),
+]
+
+def get_entity_enum_id( alias ):
+#{
+ for et in sr_entity_list:#{
+ if et[0] == alias:#{
+ return et[3]
+ #}
+ #}
+
+ return 0
+#}
class mdl_vert(Structure): # 48 bytes. Quite large. Could compress
#{ # the normals and uvs to i16s. Not an
("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):
("submesh_start",c_uint32),
("submesh_count",c_uint32),
("pstr_name",c_uint32),
- ("flags",c_uint32),
+ ("entity_id",c_uint32),
("armature_id",c_uint32)]
#}
class mdl_texture(Structure):
#{
_fields_ = [("file",mdl_file),
- ("type",c_uint32)]
+ ("glname",c_uint32)]
#}
class mdl_array(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)]
+#}
+
def obj_ent_type( obj ):
#{
if obj.type == 'ARMATURE': return 'mdl_armature'
texture_index = (len(sr_compile.texture_data)//sizeof(mdl_texture)) +1
tex = mdl_texture()
- tex.type = 0
+ tex.glname = 0
if sr_compile.pack_textures:#{
filedata = qoi_encode( img )
flags = 0x00
if mat.SR_data.collision:#{
- flags |= 0x2
- if mat.SR_data.skate_surface: flags |= 0x1
- if mat.SR_data.grind_surface: flags |= (0x8|0x1)
+ flags |= 0x2 # collision flag
+ if (mat.SR_data.shader != 'invisible') and \
+ (mat.SR_data.shader != 'boundary'):#{
+ 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.shader == 'invisible': flags |= 0x10
+ if mat.SR_data.shader == 'boundary': flags |= (0x10|0x20)
#}
- if mat.SR_data.grow_grass: flags |= 0x4
m.flags = flags
m.surface_prop = int(mat.SR_data.surface_prop)
m.colour1[2] = pow( mat.SR_data.ocean_colour[2], 1.0/2.2 )
m.colour1[3] = 1.0
#}
+
+ if mat.SR_data.shader == 'invisible':#{
+ m.shader = 5
+ #}
+
+ if mat.SR_data.shader == 'boundary':#{
+ m.shader = 6
+ #}
inf = material_info( mat )
yield from _recurse_bone( b )
#}
-def sr_compile_mesh( obj ):
+# Returns submesh_start,count and armature_id
+def sr_compile_mesh_internal( obj ):
#{
- node=mdl_mesh()
- compile_obj_transform(obj, node.transform)
- node.pstr_name = sr_compile_string(obj.name)
- node.flags = 0
-
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 \
#}
if mod.type == 'ARMATURE': #{
- node.flags = 1
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'
#
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
# 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))
#}
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
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
+ #--------------------------
+
print( F'[SR] {i: 3}/{mesh_count} {obj.name:<40}', end='\r' )
sr_compile_mesh( obj )
#}
#}
elif ent_type == 'ent_gate': #{
gate = ent_gate()
- gate.type = 0
obj_data = obj.SR_data.ent_gate[0]
mesh_data = obj.data.SR_data.ent_gate[0]
- if obj_data.target:#{
- gate.target = sr_compile.entity_ids[obj_data.target.name]
- gate.type = 1
+
+ if obj_data.tipo == 'default':#{
+ if obj_data.target:#{
+ gate.target = sr_compile.entity_ids[obj_data.target.name]
+ gate.type = 1
+ #}
+ #}
+ elif obj_data.tipo == 'nonlocal':#{
+ gate.target = sr_compile_string(obj_data.key)
+ gate.type = 2
#}
+ else: gate.type = 0
+
gate.dimensions[0] = mesh_data.dimensions[0]
gate.dimensions[1] = mesh_data.dimensions[1]
gate.dimensions[2] = mesh_data.dimensions[2]
if obj_data.target:#{
target = obj_data.target
- volume.target.type = sr_entity_alias[obj_ent_type(target)]
+ volume.target.type = get_entity_enum_id( obj_ent_type(target) )
volume.target.index = sr_compile.entity_ids[ target.name ]
#}
route_gates = []
route_curves = []
routes = []
+ traffics = []
for obj in col.objects:#{
if obj.type == 'ARMATURE': pass
#}
elif ent_type == 'ent_route':
routes += [obj]
+ elif ent_type == 'ent_traffic':
+ traffics += [obj]
#}
#}
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]
routenode_count += len(dij.points)
#}
-
print( F"[SR] Writing file" )
file_array_instructions = {}
fp = open( path, "wb" )
header = mdl_header()
- header.version = 40
+ header.version = 100
sr_array_title( header.arrays, \
'index', len(file_array_instructions), \
sizeof(mdl_array), header_size )
_.layout.prop( active_mat.SR_data, "collision" )
if active_mat.SR_data.collision:#{
- _.layout.prop( active_mat.SR_data, "skate_surface" )
- _.layout.prop( active_mat.SR_data, "grind_surface" )
- _.layout.prop( active_mat.SR_data, "grow_grass" )
+ box = _.layout.box()
+ row = box.row()
+
+ if (active_mat.SR_data.shader != 'invisible') and \
+ (active_mat.SR_data.shader != 'boundary'):#{
+ row.prop( active_mat.SR_data, "skate_surface" )
+ row.prop( active_mat.SR_data, "grind_surface" )
+ row.prop( active_mat.SR_data, "grow_grass" )
+ #}
#}
if active_mat.SR_data.shader == "terrain_blend":#{
target: bpy.props.PointerProperty( \
type=bpy.types.Object, name="destination", \
poll=lambda self,obj: sr_filter_ent_type(obj,['ent_gate']))
+
+ key: bpy.props.StringProperty()
+ tipo: bpy.props.EnumProperty(items=(('default', 'Default', ""),
+ ('nonlocal', 'Non-Local', ""),))
+
+ @staticmethod
+ def sr_inspector( layout, data ):
+ #{
+ box = layout.box()
+ box.prop( data[0], 'tipo', text="subtype" )
+
+ if data[0].tipo == 'default': box.prop( data[0], 'target' )
+ elif data[0].tipo == 'nonlocal': box.prop( data[0], 'key' )
+ #}
#}
class SR_MESH_ENT_GATE(bpy.types.PropertyGroup):
@classmethod
def poll(cls, context):#{
active_object = context.active_object
- if obj_ent_type(active_object) == 'ent_gate':#{
+ if obj_ent_type(active_object) == 'ent_route':#{
return active_object.SR_data.ent_route[0].gates
#}
else: return False
#}
#}
+class SR_OBJECT_ENT_TRAFFIC(bpy.types.PropertyGroup):
+#{
+ speed: bpy.props.FloatProperty(default=1.0)
+#}
+
class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
#{
ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
ent_marker: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MARKER)
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_type: bpy.props.EnumProperty(
name="Type",
- items=[('none', 'None', '', 0),
- ('ent_gate','Gate','', 1),
- ('ent_spawn','Spawn','', 2),
- ('ent_route_node', 'Route Node', '', 3 ),
- ('ent_route', 'Route', '', 4),
- ('ent_water', 'Water Surface', '', 5),
- ('ent_volume', 'Volume', '', 6 ),
- ('ent_audio', 'Audio Files', '', 7),
- ('ent_marker', 'Marker', '', 8),
- ('ent_font', 'Font', '', 9),
- ('ent_font_variant','Font variant','',10)],
+ items=sr_entity_list,
update=sr_on_type_change
)
#}
('standard_cutout', "standard_cutout", ''),
('terrain_blend', "terrain_blend", ''),
('vertex_blend', "vertex_blend", ''),
- ('water',"water",'')
+ ('water',"water",''),
+ ('invisible','Invisible',''),
+ ('boundary','Boundary','')
])
surface_prop: bpy.props.EnumProperty(
collision: bpy.props.BoolProperty( \
name="Collisions Enabled",\
default=True,\
- description = "Can the player collide with this material"\
+ description = "Can the player collide with this material?"\
)
skate_surface: bpy.props.BoolProperty( \
- name="Skate Surface", \
+ name="Skate Target", \
default=True,\
description = "Should the game try to target this surface?" \
)
grind_surface: bpy.props.BoolProperty( \
- name="Grind Surface", \
- default=False,\
- description = "Grind face?" \
+ name="Grindable", \
+ default=True,\
+ description = "Can you grind on this surface?" \
)
grow_grass: bpy.props.BoolProperty( \
name="Grow Grass", \
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_FONT,SR_OBJECT_ENT_TRAFFIC,\
\
SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES,
SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \