'ent_route': 4,
'ent_water': 5,
'ent_volume': 6,
- 'ent_audio': 7
+ 'ent_audio': 7,
+ 'ent_marker': 8
}
class mdl_vert(Structure): # 48 bytes. Quite large. Could compress
("max_channels",c_uint32)]
#}
+class ent_marker(Structure):
+#{
+ _fields_ = [("transform",mdl_transform),
+ ("name",c_uint32)]
+#}
+
def obj_ent_type( obj ):
#{
if obj.type == 'ARMATURE': return 'mdl_armature'
#}
#}
- checkpoint_count = 0
- pathindice_count = 0
audio_clip_count = 0
for ent_type, arr in sr_compile.entities.items():#{
spawn = ent_spawn()
compile_obj_transform( obj, spawn.transform )
obj_data = obj.SR_data.ent_spawn[0]
- spawn.pstr_name = sr_compile_string( obj_data.name )
+ spawn.pstr_name = sr_compile_string( obj_data.alias )
sr_ent_push( spawn )
#}
- elif ent_type == 'ent_route': #{
- obj_data = obj.SR_data.ent_route[0]
- route = ent_route()
- route.pstr_name = sr_compile_string( obj_data.alias )
- route.checkpoints_start = checkpoint_count
- route.checkpoints_count = 0
-
- for ci in range(3):
- route.colour[ci] = obj_data.colour[ci]
- route.colour[3] = 1.0
-
- compile_obj_transform( obj, route.transform )
-
- checkpoints = obj_data.gates
- route_nodes = []
-
- for uc in obj.users_collection[0].objects:#{
- uc_type = obj_ent_type( uc )
- if uc_type == 'ent_gate' or uc_type == 'ent_route_node':
- route_nodes += [uc]
- #}
- graph = node_graph( route_nodes )
-
- for i in range(len(checkpoints)):#{
- gi = checkpoints[i].target
- gj = checkpoints[(i+1)%len(checkpoints)].target
- gate = gi
-
- if gi:#{
- dest = gi.SR_data.ent_gate[0].target
- gi = dest
- #}
-
- if gi==gj: continue # error?
- if not gi or not gj: continue
-
- checkpoint = ent_checkpoint()
- checkpoint.gate_index = sr_compile.entity_ids[gate.name]
- checkpoint.path_start = pathindice_count
- checkpoint.path_count = 0
-
- path = dijkstra( graph, gj.name, gi.name )
- if path:#{
- for pi in range(1,len(path)-1):#{
- pathindice = ent_path_index()
- pathindice.index = sr_compile.entity_ids[path[pi]]
- sr_ent_push( pathindice )
-
- checkpoint.path_count += 1
- pathindice_count += 1
- #}
- #}
-
- sr_ent_push( checkpoint )
- route.checkpoints_count += 1
- checkpoint_count += 1
- #}
-
- sr_ent_push( route )
- #}
- elif ent_type == 'ent_route_node':#{
- rn = ent_route_node()
- rn.co[0] = obj.location[0]
- rn.co[1] = obj.location[2]
- rn.co[2] = -obj.location[1]
- sr_ent_push( rn )
- #}
elif ent_type == 'ent_water':#{
water = ent_water()
compile_obj_transform( obj, water.transform )
compile_obj_transform( obj, audio.transform )
audio.clip_start = audio_clip_count
audio.clip_count = len(obj_data.files)
+ audio_clip_count += audio.clip_count
audio.max_channels = obj_data.max_channels
audio.volume = obj_data.volume
elif obj_data.formato == '1': audio.flags |= 0x400
elif obj_data.formato == '2': audio.flags |= 0x1000
+ audio.channel_behaviour = int(obj_data.channel_behaviour)
+ if audio.channel_behaviour >= 1:#{
+ audio.group = obj_data.group
+ #}
+ if audio.channel_behaviour == 2:#{
+ audio.crossfade = obj_data.transition_duration
+ #}
+ audio.probability_curve = int(obj_data.probability_curve)
+
for ci in range(audio.clip_count):#{
entry = obj_data.files[ci]
clip = ent_audio_clip()
sr_ent_push(volume)
#}
+ elif ent_type == 'ent_marker':#{
+ marker = ent_marker()
+ marker.name = sr_compile_string( obj.SR_data.ent_marker[0].alias )
+ compile_obj_transform( obj, marker.transform )
+ sr_ent_push(marker)
+ #}
#}
#}
-
+
+ def _children( col ):#{
+ yield col
+ for c in col.children:#{
+ yield from _children(c)
+ #}
+ #}
+
+ checkpoint_count = 0
+ pathindice_count = 0
+ routenode_count = 0
+
+ for col in _children(collection):#{
+ print( F"Adding routes for subcollection: {col.name}" )
+ route_gates = []
+ route_curves = []
+ routes = []
+
+ for obj in col.objects:#{
+ if obj.type == 'ARMATURE': pass
+ else:#{
+ ent_type = obj_ent_type( obj )
+
+ if ent_type == 'ent_gate':
+ route_gates += [obj]
+ elif ent_type == 'ent_route_node':#{
+ if obj.type == 'CURVE':#{
+ route_curves += [obj]
+ #}
+ #}
+ elif ent_type == 'ent_route':
+ routes += [obj]
+ #}
+ #}
+
+ dij = create_node_graph( route_curves, route_gates )
+
+ for obj in routes:#{
+ obj_data = obj.SR_data.ent_route[0]
+ route = ent_route()
+ route.pstr_name = sr_compile_string( obj_data.alias )
+ route.checkpoints_start = checkpoint_count
+ route.checkpoints_count = 0
+
+ for ci in range(3):
+ route.colour[ci] = obj_data.colour[ci]
+ route.colour[3] = 1.0
+
+ compile_obj_transform( obj, route.transform )
+ checkpoints = obj_data.gates
+
+ for i in range(len(checkpoints)):#{
+ gi = checkpoints[i].target
+ gj = checkpoints[(i+1)%len(checkpoints)].target
+ gate = gi
+
+ if gi:#{
+ dest = gi.SR_data.ent_gate[0].target
+ gi = dest
+ #}
+
+ if gi==gj: continue # error?
+ if not gi or not gj: continue
+
+ checkpoint = ent_checkpoint()
+ checkpoint.gate_index = sr_compile.entity_ids[gate.name]
+ checkpoint.path_start = pathindice_count
+ checkpoint.path_count = 0
+
+ path = solve_graph( dij, gi.name, gj.name )
+
+ if path:#{
+ for pi in range(len(path)):#{
+ pathindice = ent_path_index()
+ pathindice.index = routenode_count + path[pi]
+ sr_ent_push( pathindice )
+
+ checkpoint.path_count += 1
+ pathindice_count += 1
+ #}
+ #}
+
+ sr_ent_push( checkpoint )
+ route.checkpoints_count += 1
+ checkpoint_count += 1
+ #}
+
+ sr_ent_push( route )
+ #}
+
+ for point in dij.points:#{
+ rn = ent_route_node()
+ rn.co[0] = point[0]
+ rn.co[1] = point[2]
+ rn.co[2] = -point[1]
+ sr_ent_push( rn )
+ #}
+
+ routenode_count += len(dij.points)
+ #}
+
+
print( F"[SR] Writing file" )
file_array_instructions = {}
elif active_object.type == 'LIGHT': #{
_draw_prop_collection( [active_object.data.SR_data] )
#}
- elif active_object.type == 'EMPTY' or active_object.type == 'MESH': #{
+ elif active_object.type in ['EMPTY','CURVE','MESH']:#{
box.prop( active_object.SR_data, "ent_type" )
ent_type = active_object.SR_data.ent_type
flag_loop: bpy.props.BoolProperty( name="Loop",default=False )
flag_auto: bpy.props.BoolProperty( name="Play at start",default=False )
flag_nodoppler: bpy.props.BoolProperty( name="No Doppler",default=False )
+
+ group: bpy.props.IntProperty( name="Group ID", default=0 )
formato: bpy.props.EnumProperty(
name="Format",
items=[('0','Uncompressed Mono',''),
c.prop( data[0], 'max_channels' )
c = split.column()
c.prop( data[0], 'channel_behaviour', text='Behaviour' )
+ if data[0].channel_behaviour >= '1':
+ box.prop( data[0], 'group' )
if data[0].channel_behaviour == '2':
box.prop( data[0], 'transition_duration' )
#}
#}
+class SR_OBJECT_ENT_MARKER(bpy.types.PropertyGroup):
+#{
+ alias: bpy.props.StringProperty()
+#}
+
class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
#{
ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
ent_route: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_ROUTE)
ent_volume: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_VOLUME)
ent_audio: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_AUDIO)
+ ent_marker: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MARKER)
ent_type: bpy.props.EnumProperty(
name="Type",
('ent_route', 'Route', '', 4),
('ent_water', 'Water Surface', '', 5),
('ent_volume', 'Volume', '', 6 ),
- ('ent_audio', 'Audio Files', '', 7)],
+ ('ent_audio', 'Audio Files', '', 7),
+ ('ent_marker', 'Marker', '', 8)],
update=sr_on_type_change
)
#}
pi = 3.14159265358979323846264
- for i in range(16):
- #{
+ for i in range(16):#{
t = ((i+1.0) * 1.0/16.0) * pi * 2.0
s = math.sin(t)
c = math.cos(t)
pi = 3.14159265358979323846264
- for i in range(16):
- #{
+ for i in range(16):#{
t = ((i+1.0) * 1.0/16.0) * pi
s = math.sin(t)
c = math.cos(t)
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:
- #{
+ for l in indices:#{
v0 = vs[l[0]]
v1 = vs[l[1]]
cv_view_verts += [(v0[0],v0[1],v0[2])]
#
def cv_tangent_basis( n, tx, ty ):
#{
- if abs( n[0] ) >= 0.57735027:
- #{
+ if abs( n[0] ) >= 0.57735027:#{
tx[0] = n[1]
tx[1] = -n[0]
tx[2] = 0.0
#}
- else:
- #{
+ else:#{
tx[0] = 0.0
tx[1] = n[2]
tx[2] = -n[1]
cv_view_verts += [p0,p1, midpt+(tx-n)*size,midpt, midpt+(-tx-n)*size,midpt ]
cv_view_colours += [c0,c0,c0,c0,c0,c0]
- cv_draw_lines()
+ #cv_draw_lines()
#}
def cv_draw_line_dotted( p0, p1, c0, dots=10 ):
cv_view_verts += [p2,p3]
cv_view_colours += [c0,c0]
#}
- cv_draw_lines()
+ #cv_draw_lines()
#}
# Drawhandles of a bezier control point
global cv_view_verts, cv_view_colours
last = p0
- for i in range(10):
- #{
+ for i in range(10):#{
t = (i+1)/10
a0 = 1-t
size = 0.12
cv_view_verts += [center, center+va*size]
- cv_view_colours += [ (1,1,1,1), (1,1,1,1) ]
+ cv_view_colours += [ (1,1,1), (1,1,1) ]
for x in range(32):#{
t0 = (x/32) * math.tau
col1 = ( abs(c1), abs(s1), 0.0, 1.0 )
cv_view_verts += [center, p0, p0, p1]
- cv_view_colours += [ (0,0,0,0), col0, col0, col1 ]
+ cv_view_colours += [ (0,0,0), col0, col0, col1 ]
#}
cv_draw_lines()
cv_view_verts += [(v0[0],v0[1],v0[2])]
cv_view_verts += [(v1[0],v1[1],v1[2])]
- cv_view_colours += [(0.5,0.5,0.5,0.5),(0.5,0.5,0.5,0.5)]
+ cv_view_colours += [(0.5,0.5,0.5),(0.5,0.5,0.5)]
#}
#}
elif bone.SR_data.collider == '2':#{
p0 = obj.matrix_world@Vector( c + (a+b)*0.5 + v1*l*-0.5 )
p1 = obj.matrix_world@Vector( c + (a+b)*0.5 + v1*l* 0.5 )
- colour = [0.2,0.2,0.2,1.0]
+ colour = [0.2,0.2,0.2]
colour[major_axis] = 0.5
cv_draw_halfsphere( p0, -v1, ty, tx, r, colour )
indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)]
+ r3d = bpy.context.area.spaces.active.region_3d
+
+ p0 = r3d.view_matrix.inverted().translation
+ v0 = (obj.matrix_world@Vector((0,0,0))) - p0
+ v1 = obj.matrix_world.to_3x3() @ Vector((0,1,0))
+
+ if v0.dot(v1) > 0.0: cc = (0,1,0)
+ else: cc = (1,0,0)
+
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 += [(1,1,0,1),(1,1,0,1)]
+ cv_view_colours += [cc,cc]
#}
- sw = (0.4,0.4,0.4,0.2)
+ sw = (0.4,0.4,0.4)
if data.target != None:
cv_draw_arrow( obj.location, data.target.location, sw )
#}
return path
#}
-def node_graph( route_nodes ):
+class dij_graph():
+#{
+ def __init__(_,points,graph,subsections):#{
+ _.points = points
+ _.graph = graph
+ _.subsections = subsections
+ #}
+#}
+
+def create_node_graph( curves, gates ):
#{
+ # add endpoints of curves
graph = {}
- for n in route_nodes:
- graph[n.name] = {}
+ route_points = []
+ subsections = []
+ point_count = 0
+ spline_count = 0
+
+ for c in range(len(curves)):#{
+ for s in range(len(curves[c].data.splines)):#{
+ spline = curves[c].data.splines[s]
+ l = len(spline.points)
+ if l < 2: continue
- for i in range(len(route_nodes)-1):#{
- for j in range(i+1, len(route_nodes)):#{
- ni = route_nodes[i]
- nj = route_nodes[j]
+ dist = round(spline.calc_length(),2)
- v0 = ni.location - nj.location
+ ia = point_count
+ ib = point_count+l-1
+
+ graph[ia] = { ib: dist }
+ graph[ib] = { ia: dist }
+
+ for i in range(len(spline.points)):#{
+ wco = curves[c].matrix_world @ spline.points[i].co
+ route_points.append(Vector((wco[0],wco[1],wco[2]+0.5)))
- gate = None
+ previous = ia+i-1
+ proxima = ia+i+1
- if ni.SR_data.ent_type == 'ent_gate':
- gate = ni
+ if i == 0: previous = -1
+ if i == len(spline.points)-1: proxima = -1
- if nj.SR_data.ent_type == 'ent_gate':#{
- if gate: continue
- gate = nj
+ subsections.append((spline_count,previous,proxima))
+ point_count += 1
#}
- if gate:#{
- v1 = gate.matrix_world.to_3x3() @ Vector((0,-1,0))
- if gate.SR_data.ent_gate[0].target:
- if v1.dot(v0) > 0.0: continue
- else:
- if v1.dot(v0) < 0.0: continue
+ spline_count += 1
+ #}
+ #}
+
+ # link endpoints
+ graph_keys = list(graph)
+ for i in range(len(graph_keys)-1):#{
+ for j in range(i+1, len(graph_keys)):#{
+ if i%2==0 and i+1==j: continue
+
+ ni = graph_keys[i]
+ nj = graph_keys[j]
+ pi = route_points[ni]
+ pj = route_points[nj]
+
+ dist = round((pj-pi).magnitude,2)
+
+ if dist < 10.0:#{
+ graph[ni][nj] = dist
+ graph[nj][ni] = dist
#}
+ #}
+ #}
+
+ # add and link gates( by name )
+ for gate in gates:#{
+ v1 = gate.matrix_world.to_3x3() @ Vector((0,1,0))
+ if gate.SR_data.ent_gate[0].target:
+ v1 = v1 * -1.0
+
+ graph[ gate.name ] = {}
- dist = v0.magnitude
+ for i in range(len(graph_keys)):#{
+ ni = graph_keys[i]
+ pi = route_points[ni]
- if dist > 25.0: continue
- graph[route_nodes[i].name][route_nodes[j].name] = dist
- graph[route_nodes[j].name][route_nodes[i].name] = dist
+ v0 = pi-gate.location
+ if v0.dot(v1) < 0.0: continue
+
+ dist = round(v0.magnitude,2)
+
+ if dist < 10.0:#{
+ graph[ gate.name ][ ni ] = dist
+ graph[ ni ][ gate.name ] = dist
+ #}
#}
#}
- return graph
+ return dij_graph(route_points,graph,subsections)
+#}
+
+def solve_graph( dij, start, end ):
+#{
+ path = dijkstra( dij.graph, end, start )
+ full = []
+
+ if path:#{
+ for sj in range(1,len(path)-2):#{
+ i0 = path[sj]
+ i1 = path[sj+1]
+ map0 = dij.subsections[i0]
+ map1 = dij.subsections[i1]
+
+ if map0[0] == map1[0]:#{
+ if map0[1] == -1: direction = 2
+ else: direction = 1
+ sent = 0
+
+ while True:#{
+ map0 = dij.subsections[i0]
+ i1 = map0[direction]
+ if i1 == -1: break
+
+ full.append( i0 )
+ sent += 1
+ i0 = i1
+ if sent > 50: break
+ #}
+ #}
+ else:#{
+ full.append( i0 )
+ #}
+ #}
+
+ full.append( path[-2] )
+ #}
+ return full
#}
-def cv_draw_route( route, route_nodes ):
+def cv_draw_route( route, dij ):
#{
pole = Vector((0.2,0.2,10))
hat = Vector((1,8,0.2))
- cc = route.SR_data.ent_route[0].colour
+ cc = (route.SR_data.ent_route[0].colour[0],
+ route.SR_data.ent_route[0].colour[1],
+ route.SR_data.ent_route[0].colour[2])
cv_draw_ucube(route.matrix_world,cc,Vector((0.5,-7.5,6)),\
Vector((0,-6.5,5.5)))
cv_draw_ucube(route.matrix_world,cc,hat, Vector((-0.5,-6.5,-1)) )
checkpoints = route.SR_data.ent_route[0].gates
- graph = node_graph( route_nodes )
for i in range(len(checkpoints)):#{
gi = checkpoints[i].target
if gi==gj: continue # error?
if not gi or not gj: continue
- path = dijkstra( graph, gj.name, gi.name )
+ path = solve_graph( dij, gi.name, gj.name )
if path:#{
- for sj in range(len(path)-1):#{
- o0 = bpy.data.objects[ path[sj] ]
- o1 = bpy.data.objects[ path[sj+1] ]
- cv_draw_arrow(o0.location,o1.location,cc,1.5)
+ cv_draw_arrow(gi.location,dij.points[path[0]],cc,1.5)
+ cv_draw_arrow(dij.points[path[len(path)-1]],gj.location,cc,1.5)
+ for j in range(len(path)-1):#{
+ i0 = path[j]
+ i1 = path[j+1]
+ o0 = dij.points[ i0 ]
+ o1 = dij.points[ i1 ]
+ cv_draw_arrow(o0,o1,cc,1.5)
#}
#}
else:#{
gpu.state.depth_test_set('LESS')
gpu.state.blend_set('NONE')
- route_nodes = []
+ route_gates = []
+ route_curves = []
routes = []
for obj in bpy.context.collection.objects:#{
if ent_type == 'ent_gate':#{
cv_ent_gate( obj )
- route_nodes += [obj]
+ route_gates += [obj]
+ #}
+ elif ent_type == 'ent_route_node':#{
+ if obj.type == 'CURVE':#{
+ route_curves += [obj]
+ #}
#}
- elif ent_type == 'ent_route_node':
- route_nodes += [obj]
elif ent_type == 'ent_route':
routes += [obj]
elif ent_type == 'ent_volume':#{
cv_ent_volume( obj )
#}
elif ent_type == 'ent_audio':#{
- cv_draw_sphere( obj.location, obj.scale[0], (1,1,0) )
+ if obj.SR_data.ent_audio[0].flag_3d:
+ cv_draw_sphere( obj.location, obj.scale[0], (1,1,0) )
#}
#}
#}
+
+ dij = create_node_graph( route_curves, route_gates )
#cv_draw_route_map( route_nodes )
for route in routes:#{
- cv_draw_route( route, route_nodes )
+ cv_draw_route( route, dij )
#}
cv_draw_lines()
SR_OBJECT_ENT_VOLUME,
SR_UL_AUDIO_LIST, SR_OBJECT_ENT_AUDIO_FILE_ENTRY,\
SR_OT_ROUTE_LIST_DEL_ITEM,\
- SR_OBJECT_ENT_AUDIO,\
+ SR_OBJECT_ENT_AUDIO,SR_OBJECT_ENT_MARKER,\
\
SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES,
SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \