sound_src/rtj3_01_down.ogg
sound_src/song.ogg
+sound_src/rtj3_02_talktome.ogg
+sound_src/rtj3_02_talktome.ogg.reapeaks
+sound_src/song1.ogg
+sound_src/memes.ogg
+sound_src/memes.ogg.reapeaks
+sound_src/delta.ogg
audio_clip audio_board[] =
{
- { .path="sound/skate.ogg" },
+ { .path="sound/skate_hpf.ogg" },
{ .path="sound/wheel.ogg" },
{ .path="sound/slide.ogg" },
{ .path="sound/reverb.ogg" },
.path = "sound/gate_ambient.ogg"
};
+#if 0
audio_player ambient_player =
{
.name = "Ambience"
{
.name = "Rewind"
};
+#endif
audio_clip audio_rewind[] = {
{ .path = "sound/rewind_start.ogg" },
{ .path = "sound/ui_ding.ogg" },
};
+audio_clip audio_music[] = {
+ { .path = "sound/song.ogg", .flags = AUDIO_FLAG_VORBIS },
+ { .path = "sound/skate.ogg", .flags = AUDIO_FLAG_VORBIS },
+};
+
+#if 0
audio_player ambient_sprites[4] =
{
{ .name = "Ambient Sprites 0" },
{
.name = "Gate"
};
+#endif
VG_STATIC void audio_init(void)
{
+#if 0
audio_player_init( &audio_player0 );
audio_player_init( &audio_player1 );
audio_player_init( &audio_player2 );
audio_player_init( &ambient_sprites[3] );
audio_player_init( &audio_player_extra );
audio_player_init( &audio_rewind_player );
+#endif
audio_clip_loadn( audio_board, vg_list_size(audio_board), NULL );
audio_clip_loadn( audio_ambience, vg_list_size(audio_ambience), NULL );
audio_clip_loadn( &audio_gate_pass, 1, NULL );
audio_clip_loadn( &audio_gate_lap, 1, NULL );
audio_clip_loadn( &audio_gate_ambient, 1, NULL );
+ audio_clip_loadn( audio_music, vg_list_size(audio_music), NULL );
+
audio_clip_loadn( audio_jumps, vg_list_size(audio_jumps), NULL );
audio_clip_loadn( audio_lands, vg_list_size(audio_lands), NULL );
audio_clip_loadn( audio_water, vg_list_size(audio_water), NULL );
audio_clip_loadn( audio_rewind, vg_list_size(audio_rewind), NULL );
audio_clip_loadn( audio_ui, vg_list_size(audio_ui), NULL );
+#if 0
audio_lock();
u32 flags = AUDIO_FLAG_LOOP|AUDIO_FLAG_SPACIAL_3D;
audio_player_set_flags( &ambient_sprites[1], AUDIO_FLAG_SPACIAL_3D );
audio_player_set_flags( &ambient_sprites[2], AUDIO_FLAG_SPACIAL_3D );
audio_player_set_flags( &ambient_sprites[3], AUDIO_FLAG_SPACIAL_3D );
+
audio_player_set_vol( &ambient_player, 1.0f );
audio_player_set_vol( &audio_player_gate, 0.0f );
audio_player_set_vol( &audio_player_extra, 1.0f );
audio_player_playclip( &audio_player_gate, &audio_gate_ambient );
audio_unlock();
+#endif
vg_var_push( (struct vg_var){
.name = "aud_debug_soundscape",
.opt_f32 = { .clamp = 0 },
.persistent = 1
});
+
+ audio_lock();
+ audio_set_lfo_wave( 0, k_lfo_polynomial_bipolar, 80.0f );
+ audio_set_lfo_frequency( 0, 20.0f );
+ audio_unlock();
+}
+
+VG_STATIC void audio_update(void)
+{
+#if 0
+ static u32 flapflop = 0x00;
+ static audio_channel *channel = NULL;
+
+ u32 next = floorf( vg.time / 0.1f );
+
+ if( flapflop != next )
+ {
+ flapflop = next;
+
+ audio_lock();
+ channel = audio_channel_crossfade( channel,
+ &audio_music[ next & 0x1 ], 0.05f,
+ AUDIO_FLAG_LOOP|AUDIO_FLAG_SPACIAL_3D
+ );
+ channel = audio_channel_set_spacial( channel,
+ (v3f){ -22.3f, 60.1f, -52.7f },
+ 50.0f );
+
+ audio_channel_sidechain_lfo( channel, 0, 1.0f );
+ audio_unlock();
+ }
+#endif
}
VG_STATIC void audio_free(void)
global cv_view_verts, cv_view_colours
cv_draw_ucube( obj.matrix_world, [0,1,0,1] )
+ white = (1,1,1,1)
+
if obj.cv_data.target:
- cv_draw_arrow( obj.location, obj.cv_data.target.location, [1,1,1,1] )
+ cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
#}
@staticmethod
#}
#}
-# Classtype 102
+class union_128bit_data(Union):
+#{
+ _pack_ = 1
+ _fields_ = [("f32",c_float),
+ ("u32",c_uint32),
+ ("i32",c_int32),
+ ("v4f",c_float*4)]
+#}
+
+# Class type 105
+#
+# Purpose:
+#
+class classtype_logic_wire(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("next",c_uint32),
+ ("function",c_uint32),
+ ("data",union_128bit_data),
+ ("data_type",c_uint32),
+ ("enabled",c_uint32)]
+
+ function_enum = [('0',"pass along",""),
+ ('1',"enable",""),
+ ('2',"disable",""),
+ ('3',"","")]
+
+ def encode_obj(_,node,node_def):
+ #{
+ node.classtype = 105
+
+ obj = node_def['obj']
+
+ if obj.cv_data.target: _.next = obj.cv_data.target.cv_data.uid
+
+ _.data_type = obj.cv_data.intp1
+ _.function = int(obj.cv_data.function)
+ _.enabled = obj.cv_data.bp0
+
+ if _.data_type == 1: # an integer
+ _.data.i32 = obj.cv_data.intp
+ elif _.data_type == 2: # a number
+ _.data.f32 = obj.cv_data.fltp
+ elif _.data_type == 3: # a target
+ if obj.cv_data.target2:
+ _.data.u32 = obj.cv_data.target2.cv_data.uid
+ elif _.data_type == 4: # a string
+ _.data.u32 = encoder_process_pstr( obj.cv_data.strp )
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ layout.prop( obj.cv_data, "bp0", text="Start disabled" )
+ box = layout.box()
+ box.label( text="Target" )
+ box.prop( obj.cv_data, "target", text="connection" )
+
+ row = box.row()
+ if not obj.cv_data.target:
+ row.enabled=False
+ row.prop( obj.cv_data, "function", text="function" )
+
+ box = layout.box()
+ box.label( text="Data packet" )
+ box.prop( obj.cv_data, "intp1", text="type" )
+
+ if obj.cv_data.intp1 == 1:
+ box.prop( obj.cv_data, "intp", text="Signed Integer" )
+ elif obj.cv_data.intp1 == 2:
+ box.prop( obj.cv_data, "fltp", text="Float" )
+ elif obj.cv_data.intp1 == 3:
+ box.prop( obj.cv_data, "target2", text="Object reference" )
+ elif obj.cv_data.intp1 == 4:
+ box.prop( obj.cv_data, "strp", text="String" )
+ else:
+ #{
+ row = box.row()
+ row.enabled=False
+ row.label( text="this wire will not impart any data" )
+ #}
+ #}
+
+ @staticmethod
+ def draw_scene_helpers( obj ):
+ #{
+ global cv_view_verts, cv_view_colours
+
+ white = (1,1,1,1)
+ purple = (0.5,0.2,1,1)
+
+ if obj.cv_data.target:
+ cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
+ if (obj.cv_data.target2) and (obj.cv_data.intp1 == 3):
+ cv_draw_arrow( obj.cv_data.target2.location, obj.location,purple, 0.7 )
+ #}
+
+ @staticmethod
+ def get_targeted_methods( scene, context ):
+ #{
+ obj = context.object
+ invalid = [('0',"","")]
+
+ if obj.cv_data.target:
+ #{
+ classtype = obj.cv_data.target.cv_data.classtype
+ if classtype == 'classtype_none' or classtype not in globals():
+ #{
+ return invalid
+ #}
+ else:
+ #{
+ cl = globals()[ classtype ]
+ if getattr( cl, "function_enum", None ):
+ #{
+ return cl.function_enum
+ #}
+ else:
+ #{
+ return invalid
+ #}
+ #}
+ #}
+ else:
+ #{
+ return invalid
+ #}
+ #}
+#}
+
+# Class type 108
+#
+# Purpose:
+#
+class classtype_particle_box(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("target",c_uint32),
+ ("rate",c_float)]
+
+ function_enum = [('0',"set rate",""),
+ ('1',"",""),
+ ('2',"",""),
+ ('3',"","")]
+
+ def encode_obj(_, node,node_def ):
+ #{
+ node.classtype = 108
+
+ obj = node_def['obj']
+
+ _.rate = obj.cv_data.fltp
+ if obj.cv_data.target:
+ _.target = obj.cv_data.target.cv_data.uid
+ #}
+
+ @staticmethod
+ def draw_scene_helpers( obj ):
+ #{
+ global cv_view_verts, cv_view_colours
+ cv_draw_ucube( obj.matrix_world, [1,0.8,0,1] )
+
+ white = (1,1,1,1)
+ if obj.cv_data.target:
+ cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ layout.prop( obj.cv_data, "target", text="Triggers" )
+ layout.prop( obj.cv_data, "fltp", text="count per second" )
+ #}
+#}
+
+# Class type 109
+#
+# Purpose:
+#
+class classtype_signal_splitter(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("next",c_uint32*4)]
+
+ function_enum = [('0',"pass along",""),
+ ('1',"",""),
+ ('2',"",""),
+ ('3',"","")]
+
+ def encode_obj(_,node,node_def):
+ #{
+ node.classtype = 109
+
+ obj = node_def['obj']
+
+ if obj.cv_data.target: _.next[0] = obj.cv_data.target.cv_data.uid
+ if obj.cv_data.target1: _.next[1] = obj.cv_data.target1.cv_data.uid
+ if obj.cv_data.target2: _.next[2] = obj.cv_data.target2.cv_data.uid
+ if obj.cv_data.target3: _.next[3] = obj.cv_data.target3.cv_data.uid
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ layout.label( text="The split signals will run in order" )
+ layout.prop( obj.cv_data, "target", text="#0" )
+ layout.prop( obj.cv_data, "target1", text="#1" )
+ layout.prop( obj.cv_data, "target2", text="#2" )
+ layout.prop( obj.cv_data, "target3", text="#3" )
+ #}
+
+ @staticmethod
+ def draw_scene_helpers( obj ):
+ #{
+ global cv_view_verts, cv_view_colours
+
+ c0 = (1,0.5,0.2,1)
+ c1 = (0.8,1,0.1,1)
+ c2 = (0.3,0.9,0.4,1)
+ c3 = (0.1,0.4,1.0,1)
+
+ if obj.cv_data.target:
+ cv_draw_arrow( obj.location, obj.cv_data.target.location, c0, 0.7 )
+ if obj.cv_data.target1:
+ cv_draw_arrow( obj.location, obj.cv_data.target1.location, c1, 0.7 )
+ if obj.cv_data.target2:
+ cv_draw_arrow( obj.location, obj.cv_data.target2.location, c2, 0.7 )
+ if obj.cv_data.target3:
+ cv_draw_arrow( obj.location, obj.cv_data.target3.location, c3, 0.7 )
+ #}
+#}
+
+# Class type 106
+#
+# Purpose:
+#
+class classtype_soundscape(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("max_instances",c_uint32),
+ ("allow_transitions",c_uint32),
+ ("transition_duration",c_float),
+ ("label",c_uint32)]
+
+ function_enum = [('0',"play",""),
+ ('1',"set position",""),
+ ('2',"",""),
+ ('3',"","")]
+
+ def encode_obj(_,node,node_def):
+ #{
+ node.classtype = 106
+
+ obj = node_def['obj']
+
+ _.max_instances = obj.cv_data.intp
+ _.allow_transitions = obj.cv_data.bp0
+ _.transition_duration = obj.cv_data.fltp
+ _.label = encoder_process_pstr( obj.cv_data.strp )
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ layout.prop( obj.cv_data, "intp", text="max instances" )
+ layout.prop( obj.cv_data, "strp", text="label" )
+
+ box = layout.box()
+ box.label( text="If its a 3d sound, where can it spawn?" )
+ box.prop( obj.cv_data, "bp1", text="Only in water" )
+ box.prop( obj.cv_data, "bp2", text="Only on grass" )
+ box.prop( obj.cv_data, "bp3", text="Only on wood" )
+
+ box = layout.box()
+ box.prop( obj.cv_data, "bp0", text="allow transitions" )
+
+ row = box.row()
+ if not obj.cv_data.bp0:
+ row.enabled=False
+ row.prop( obj.cv_data, "fltp", text="transition duration" )
+ #}
+#}
+
+class classtype_logic_chances(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("targets",c_uint32*2),
+ ("p",c_float)]
+
+ function_enum = [('0',"pass along",""),
+ ('1',"set ratio",""),
+ ('2',"",""),
+ ('3',"","")]
+
+ def encode_obj(_,node,node_def):
+ #{
+ node.classtype = 107
+
+ obj = node_def['obj']
+
+ if obj.cv_data.target: _.targets[0] = obj.cv_data.target.cv_data.uid
+ if obj.cv_data.target1: _.targets[1] = obj.cv_data.target1.cv_data.uid
+
+ _.p = obj.cv_data.fltp
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ box = layout.box()
+ box.prop( obj.cv_data, "target", text="red" )
+ box.prop( obj.cv_data, "target1", text="black" )
+ box.prop( obj.cv_data, "fltp", text="p(red)" )
+ #}
+
+ @staticmethod
+ def draw_scene_helpers( obj ):
+ #{
+ global cv_view_verts, cv_view_colours
+
+ red = (1,0,0,1)
+ black = (0,0,0,1)
+
+ if obj.cv_data.target:
+ cv_draw_arrow( obj.location, obj.cv_data.target.location, red, 0.7 )
+ if obj.cv_data.target1:
+ cv_draw_arrow( obj.location, obj.cv_data.target1.location, black, 0.7 )
+ #}
+#}
+
+# Classtype 102 [ DEPRECATED ]
#
# Purpose: sends a signal to another entity
#
# volume: not used if has 3D flag
# flags:
# AUDIO_FLAG_LOOP 0x1
-# AUDIO_FLAG_ONESHOT 0x2 (DONT USE THIS, it breaks semaphores)
+# AUDIO_FLAG_SPACIAL_3D 0x4 (Probably what you want)
+# AUDIO_FLAG_AUTO_START 0x8 (Play when the world starts)
+# ......
+# the rest are just internal flags, only use the above 3.
+#
+class classtype_audio(Structure):
+#{
+ _pack_ = 1
+ _fields_ = [("pstr_file",c_uint32),
+ ("flags",c_uint32),
+ ("volume",c_float)]
+
+ def encode_obj(_, node,node_def ):
+ #{
+ node.classtype = 14
+
+ obj = node_def['obj']
+
+ _.pstr_file = encoder_process_pstr( obj.cv_data.strp )
+
+ flags = 0x00
+ if obj.cv_data.bp0: flags |= 0x1
+ if obj.cv_data.bp1: flags |= 0x4
+ if obj.cv_data.bp2: flags |= 0x8
+
+ if obj.cv_data.audio_format == 'stereo':
+ flags |= 0x200
+ if obj.cv_data.audio_format == 'remain compressed':
+ flags |= 0x400
+
+ _.flags = flags
+ _.volume = obj.cv_data.fltp
+ #}
+
+ @staticmethod
+ def editor_interface( layout, obj ):
+ #{
+ layout.prop( obj.cv_data, "strp", text = "File (.ogg)" )
+
+ layout.prop( obj.cv_data, "bp0", text = "Looping" )
+ layout.prop( obj.cv_data, "bp1", text = "3D Audio" )
+ layout.prop( obj.cv_data, "bp2", text = "Auto Start" )
+ layout.prop( obj.cv_data, "audio_format" )
+
+ layout.prop( obj.cv_data, "fltp", text = "Volume (0-1)" )
+ #}
+
+ @staticmethod
+ def draw_scene_helpers( obj ):
+ #{
+ global cv_view_verts, cv_view_colours
+
+ cv_draw_sphere( obj.location, obj.scale[0], [1,1,0,1] )
+ #}
+#}
+
+# Classtype 14
+#
+# Purpose: Plays some audio (44100hz .ogg vorbis only)
+# NOTE: There is a 32mb limit on the audio buffer, world audio is
+# decompressed and stored in signed 16 bit integers (2 bytes)
+# per sample.
+#
+# volume: not used if has 3D flag
+# flags:
+# AUDIO_FLAG_LOOP 0x1
# AUDIO_FLAG_SPACIAL_3D 0x4 (Probably what you want)
# AUDIO_FLAG_AUTO_START 0x8 (Play when the world starts)
# ......
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 += [(0,1,0,1),(0,1,0,1)]
+ cv_view_colours += [colour, colour]
#}
cv_draw_lines()
#}
# Draw coloured arrow
#
-def cv_draw_arrow( p0, p1, c0 ):
+def cv_draw_arrow( p0, p1, c0, size=0.15 ):
#{
global cv_view_verts, cv_view_colours
ty = Vector((1,0,0))
cv_tangent_basis( n, tx, ty )
- cv_view_verts += [p0,p1, midpt+(tx-n)*0.15,midpt, midpt+(-tx-n)*0.15,midpt ]
+ 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()
#}
strp: bpy.props.StringProperty( name="strp" )
intp: bpy.props.IntProperty( name="intp" )
+ intp1: bpy.props.IntProperty( name="intp1" )
fltp: bpy.props.FloatProperty( name="fltp" )
bp0: bpy.props.BoolProperty( name="bp0" )
bp1: bpy.props.BoolProperty( name="bp1" )
colour: bpy.props.FloatVectorProperty( name="colour",subtype='COLOR',\
min=0.0,max=1.0)
+ function: bpy.props.EnumProperty(
+ name="Function",
+ items= classtype_logic_wire.get_targeted_methods
+ )
+
classtype: bpy.props.EnumProperty(
name="Format",
items = [
('classtype_trigger',"classtype_trigger","",100),
('classtype_logic_achievement',"classtype_logic_achievement","",101),
('classtype_logic_relay',"classtype_logic_relay","",102),
+ ('classtype_logic_wire',"classtype_logic_wire","",105),
+ ('classtype_soundscape',"classtype_soundscape","",106),
+ ('classtype_logic_chances',"classtype_logic_chances","",107),
+ ('classtype_particle_box',"classtype_particle_box","",108),
+ ('classtype_signal_splitter',"classtype_signal_splitter","",109),
('classtype_spawn_link',"classtype_spawn_link","",150),
('classtype_nonlocal_gate', "classtype_nonlocal_gate", "", 300)
])
k_light_preview = 0;
VG_STATIC int freecam = 0;
+VG_STATIC int debug_logic_bricks = 0;
VG_STATIC int walk_grid_iterations = 1;
VG_STATIC float fc_speed = 10.0f;
VG_STATIC int cl_thirdperson = 0;
VG_VAR_F32( k_walk_accel );
VG_VAR_I32( freecam );
+ VG_VAR_F32_PERSISTENT( debug_logic_bricks );
VG_VAR_I32( cl_thirdperson );
VG_VAR_F32_PERSISTENT( fc_speed );
k_classtype_trigger = 100,
k_classtype_logic_achievement = 101,
k_classtype_logic_relay = 102,
+ k_classtype_logic_script = 103,
+
+ k_classtype_logic_wire = 105,
+ k_classtype_soundscape = 106,
+ k_classtype_logic_chances = 107,
+ k_classtype_particle_box = 108,
+ k_classtype_signal_splitter = 109,
+
k_classtype_world_light = 200,
k_classtype_nonlocal_gate = 300
};
u32 target;
};
+struct classtype_particle_box
+{
+ u32 target;
+ float rate;
+};
+
+struct classtype_signal_splitter
+{
+ u32 next[4];
+};
+
struct classtype_logic_relay
{
u32 targets[4];
float angle, range;
};
+struct classtype_logic_wire
+{
+ u32 next,
+ function;
+
+ union mdl_128bit_union
+ {
+ float _f32;
+ u32 _u32;
+ i32 _i32;
+ v4f _v4f;
+ }
+ data;
+
+ enum mdl_128bit_datatype
+ {
+ k_mdl_128bit_datatype_nothing = 0u,
+ k_mdl_128bit_datatype_integer = 1u,
+ k_mdl_128bit_datatype_number = 2u,
+ k_mdl_128bit_datatype_target = 3u,
+ k_mdl_128bit_datatype_string = 4u,
+ k_mdl_128bit_datatype_vec2 = 5u,
+ k_mdl_128bit_datatype_vec3 = 6u,
+ k_mdl_128bit_datatype_vec4 = 7u
+ }
+ data_type;
+
+ u32 enabled;
+};
+
+struct classtype_soundscape
+{
+ u32 max_instances,
+ allow_transitions;
+
+ float transition_duration;
+ u32 label;
+};
+
+struct classtype_logic_chances
+{
+ u32 targets[2];
+ float p;
+};
+
#pragma pack(pop)
#define PLAYER_SKATE_C
#include "player.h"
+#include "audio.h"
VG_STATIC void player__skate_bind( player_instance *player )
{
s->state.lift_frames ++;
#endif
- /* FIXME audio events */
-#if 0
audio_lock();
- audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
- audio_player_set_position( &audio_player_extra, player.rb.co );
- audio_player_set_vol( &audio_player_extra, 20.0f );
- audio_player_playclip( &audio_player_extra, &audio_jumps[rand()%2] );
+ audio_oneshot_3d( &audio_jumps[rand()%2], player->rb.co, 40.0f, 1.0f );
audio_unlock();
-#endif
}
}
#if 0
vg_line_pt3( s->state.apex, 0.030f, 0xff0000ff );
#endif
+
+ audio_lock();
+
+ float air = s->state.activity == k_skate_activity_air? 1.0f: 0.0f,
+ speed = v3_length( player->rb.v ),
+ attn = vg_minf( 1.0f, speed*0.1f ),
+ slide = vg_clampf( fabsf(s->state.slip), 0.0f, 1.0f ),
+
+ vol_main = sqrtf( (1.0f-air)*attn*(1.0f-slide) * 0.4f ),
+ vol_air = sqrtf( air *attn * 0.5f ),
+ vol_slide = sqrtf( (1.0f-air)*attn*slide * 0.25f );
+
+ const u32 flags = AUDIO_FLAG_SPACIAL_3D|AUDIO_FLAG_LOOP;
+ if( !s->aud_main )
+ s->aud_main = audio_request_channel( &audio_board[0], flags );
+
+ if( !s->aud_air )
+ s->aud_air = audio_request_channel( &audio_board[1], flags );
+
+ if( !s->aud_slide )
+ s->aud_slide = audio_request_channel( &audio_board[2], flags );
+
+
+ /* brrrrrrrrrrrt sound for tiles and stuff
+ * --------------------------------------------------------*/
+ float sidechain_amt = 0.0f,
+ hz = speed * 2.0f;
+
+ if( s->surface == k_surface_prop_tiles )
+ sidechain_amt = 1.0f;
+ else
+ sidechain_amt = 0.0f;
+
+ audio_set_lfo_frequency( 0, hz );
+ audio_set_lfo_wave( 0, k_lfo_polynomial_bipolar,
+ vg_lerpf( 250.0f, 80.0f, attn ) );
+
+ if( s->aud_main )
+ {
+ s->aud_main->colour = 0x00103efe;
+ audio_channel_set_spacial( s->aud_main, player->rb.co, 40.0f );
+ audio_channel_slope_volume( s->aud_main, 0.05f, vol_main );
+ audio_channel_sidechain_lfo( s->aud_main, 0, sidechain_amt );
+
+ float rate = 1.0f + (attn-0.5f)*0.2f;
+ audio_channel_set_sampling_rate( s->aud_main, rate );
+ }
+
+ if( s->aud_slide )
+ {
+ s->aud_slide->colour = 0x00103efe;
+ audio_channel_set_spacial( s->aud_slide, player->rb.co, 40.0f );
+ audio_channel_slope_volume( s->aud_slide, 0.05f, vol_slide );
+ audio_channel_sidechain_lfo( s->aud_slide, 0, sidechain_amt );
+ }
+
+ if( s->aud_air )
+ {
+ s->aud_air->colour = 0x00103efe;
+ audio_channel_set_spacial( s->aud_air, player->rb.co, 40.0f );
+ audio_channel_slope_volume( s->aud_air, 0.05f, vol_air );
+ }
+
+ audio_unlock();
}
/*
* --------------------------------------------------------------------------
*/
+ s->surface = k_surface_prop_concrete;
+
+ for( int i=0; i<manifold_len; i++ )
+ {
+ rb_ct *ct = &manifold[i];
+ struct world_material *surface_mat = world_contact_material( world, ct );
+
+ if( surface_mat->info.surface_prop != k_surface_prop_concrete )
+ s->surface = surface_mat->info.surface_prop;
+ }
+
for( int i=0; i<k_wheel_count; i++ )
{
m4x3f mtx;
s->state_gate_storage = s->state;
player__pass_gate( player, &hit );
}
+
+ /* FIXME: Rate limit */
+ static int stick_frames = 0;
+
+ if( s->state.activity == k_skate_activity_ground )
+ stick_frames ++;
+ else
+ stick_frames = 0;
+
+
+ if( stick_frames == 4 )
+ {
+ audio_lock();
+ if( (fabsf(s->state.slip) > 0.75f) )
+ {
+ audio_oneshot_3d( &audio_lands[rand()%2+3], player->rb.co,
+ 40.0f, 1.0f );
+ }
+ else
+ {
+ audio_oneshot_3d( &audio_lands[rand()%3], player->rb.co,
+ 40.0f, 1.0f );
+ }
+ audio_unlock();
+ }
}
VG_STATIC void player__skate_im_gui( player_instance *player )
v3f truckv0[2];
v2f wobble;
+ audio_channel *aud_main, *aud_slide, *aud_air;
+ enum mdl_surface_prop surface, audio_surface;
+
/*
* Physics
* ----------------------------------------------------
player__pre_update( &localplayer );
world_update( get_active_world(), localplayer.rb.co );
+
+ audio_update();
}
}
player__post_update( &localplayer );
+
+ float inr3 = 0.57735027,
+ inr2 = 0.70710678118;
+
+ v3f sample_directions[] = {
+ { -1.0f, 0.0f, 0.0f },
+ { 1.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f },
+ { 0.0f, 0.0f, -1.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, -1.0f, 0.0f },
+ { -inr3, inr3, inr3 },
+ { inr3, inr3, inr3 },
+ { -inr3, inr3, -inr3 },
+ { inr3, inr3, -inr3 },
+ { -inr2, 0.0f, inr2 },
+ { inr2, 0.0f, inr2 },
+ { -inr2, 0.0f, -inr2 },
+ { inr2, 0.0f, -inr2 },
+ };
+
+ static int si = 0;
+ static float distances[16];
+
+ ray_hit ray;
+ ray.dist = 5.0f;
+
+ v3f rc, rd, ro;
+ v3_copy( sample_directions[ si ], rd );
+ v3_add( localplayer.rb.co, (v3f){0.0f,1.5f,0.0f}, ro );
+ v3_copy( ro, rc );
+
+ float dist = 200.0f;
+
+ for( int i=0; i<10; i++ )
+ {
+ if( ray_world( get_active_world(), rc, rd, &ray ) )
+ {
+ dist = (float)i*5.0f + ray.dist;
+ break;
+ }
+ else
+ {
+ v3_muladds( rc, rd, ray.dist, rc );
+ }
+ }
+
+ distances[si] = dist;
+
+
+ for( int i=0; i<14; i++ )
+ {
+ if( distances[i] != 200.0f )
+ {
+ u32 colours[] = { VG__RED, VG__BLUE, VG__GREEN,
+ VG__CYAN, VG__YELOW, VG__PINK,
+ VG__WHITE };
+
+ u32 colour = colours[i%7];
+
+ v3f p1;
+ v3_muladds( ro, sample_directions[i], distances[i], p1 );
+ vg_line( ro, p1, colour );
+ vg_line_pt3( p1, 0.1f, colour );
+ }
+ }
+
+ si ++;
+ if( si >= 14 )
+ si = 0;
+
+
/* FIXME: TEMP */
audio_lock();
+ vg_dsp.echo_distances[si] = dist;
+
v3f ears = { 1.0f,0.0f,0.0f };
m3x3_mulv( main_camera.transform, ears, ears );
v3_copy( ears, vg_audio.listener_ears );
struct world_audio_thing
{
v3f pos;
- float volume;
+ float volume, range;
u32 flags;
+#if 0
audio_player player;
+#endif
+
audio_clip temp_embedded_clip;
}
* audio_things;
u32 audio_things_count;
+#if 0
/*
- * Relays
+ * Relays [ DEPRECATED ]
*/
struct logic_relay
{
}
* logic_relays;
u32 relay_count;
+#endif
+
+ struct soundscape
+ {
+ /* locking */
+ audio_channel *channels[4];
+
+ /* accessable without locking */
+ v3f spawn_position;
+
+ u32 usage_count;
+ u32 max_instances;
+ u32 allow_transitions;
+ float transition_duration;
+ const char *label;
+ }
+ * soundscapes;
+ u32 soundscape_count;
+
+ struct logic_brick_ref
+ {
+ mdl_node *node;
+ float usage;
+ u32 internal_id; /* used for things like soundscapes where another
+ allocation is made on top */
+ }
+ * logic_bricks;
+ u32 logic_brick_count;
/*
* Box trigger entities
struct trigger_zone
{
m4x3f transform, inv_transform;
-
- struct relay_target target;
+
+ u32 target_logic_brick;
+ enum classtype classtype;
}
* triggers;
u32 trigger_count;
#include "world_sfd.h"
#include "world_render.h"
#include "world_water.h"
+#include "world_logic_bricks.h"
#include "world_gen.h"
#include "world_gate.h"
* Therefore it is safe to delete clip data after the players are
* disconnected
*/
+#if 0
audio_lock();
for( int i=0; i<world->audio_things_count; i++ )
{
}
}
audio_unlock();
+#endif
return 0;
}
#endif
}
+#if 0
VG_STATIC void world_trigger_achievement( world_instance *world, u32 uid )
{
struct logic_achievement *ach = &world->logic_achievements[ uid ];
ach->achieved = 1;
}
+#endif
+#if 0
VG_STATIC void world_run_relay( world_instance *world,
struct relay_target *rt );
world_run_relay( world, &relay->targets[i] );
}
}
+#endif
+#if 0
VG_STATIC void world_trigger_audio( world_instance *world, u32 uid )
{
struct world_audio_thing *wat = &world->audio_things[ uid ];
&wat->temp_embedded_clip );
audio_unlock();
}
+#endif
+#if 0
VG_STATIC void world_run_relay( world_instance *world,
struct relay_target *rt )
{
{
{ k_classtype_logic_achievement, world_trigger_achievement },
{ k_classtype_logic_relay, world_trigger_relay },
- { k_classtype_audio, world_trigger_audio }
+ { k_classtype_audio, world_trigger_audio },
+ { k_classtype_logic_wire, logic_bricks_trigger_brick }
};
for( int i=0; i<vg_list_size(entity_instructions); i++ )
vg_error( "Don't know how to trigger classtype %d\n", rt->classtype );
}
+#endif
VG_STATIC void world_update( world_instance *world, v3f pos )
{
}
}
}
+
+ /* TODO: Bvh */
+
+ static float random_accum = 0.0f;
+ random_accum += vg.time_delta;
+
+ u32 random_ticks = 0;
+
+ while( random_accum > 0.1f )
+ {
+ random_accum -= 0.1f;
+ random_ticks ++;
+ }
int in_trigger = 0;
for( int i=0; i<world->trigger_count; i++ )
{
struct trigger_zone *zone = &world->triggers[i];
+ for( int j=0; j<random_ticks; j++ )
+ {
+ logic_packet packet;
+ packet.location = zone->target_logic_brick;
+ packet.function = 0;
+
+ packet.type = k_mdl_128bit_datatype_vec3;
+ packet.data._v4f[0] = vg_randf()*2.0f-1.0f;
+ packet.data._v4f[1] = vg_randf()*2.0f-1.0f;
+ packet.data._v4f[2] = vg_randf()*2.0f-1.0f;
+ m4x3_mulv( zone->transform, packet.data._v4f, packet.data._v4f );
+
+ logic_bricks_send_packet( world, &packet );
+ continue;
+ }
+
v3f local;
m4x3_mulv( zone->inv_transform, pos, local );
if( !world_global.in_trigger )
{
- world_run_relay( world, &zone->target );
+ logic_packet packet;
+ packet.location = zone->target_logic_brick;
+ packet.function = 0;
+
+ packet.type = k_mdl_128bit_datatype_vec3;
+ v3_copy( pos, packet.data._v4f );
+
+ logic_bricks_send_packet( world, &packet );
}
}
world_global.in_trigger = in_trigger;
sfd_update();
+
+ if( debug_logic_bricks )
+ logic_bricks_debug( world );
+
+ /* process soundscape transactions */
+ audio_lock();
+ for( int i=0; i<world->soundscape_count; i++ )
+ {
+ struct soundscape *s = &world->soundscapes[i];
+ s->usage_count = 0;
+
+ for( int j=0; j<s->max_instances; j++ )
+ {
+ if( s->channels[j] )
+ {
+ if( audio_channel_finished(s->channels[j]) )
+ s->channels[j] = audio_relinquish_channel( s->channels[j] );
+ else
+ s->usage_count ++;
+ }
+ }
+ }
+ audio_unlock();
}
/*
struct countable
{
- enum classtype ct;
+ enum classtype ct, ct1;
void **to_allocate;
u32 item_size;
int count;
{
{
k_classtype_spawn,
+ k_classtype_none,
(void*)&world->spawns,
sizeof(struct respawn_point)
},
{
k_classtype_audio,
+ k_classtype_none,
(void*)&world->audio_things,
sizeof(struct world_audio_thing)
},
{
k_classtype_trigger,
+ k_classtype_particle_box,
(void*)&world->triggers,
sizeof(struct trigger_zone)
},
+
+#if 0
{
k_classtype_logic_relay,
(void*)&world->logic_relays,
sizeof(struct logic_relay)
},
+#endif
+
{
k_classtype_logic_achievement,
+ k_classtype_none,
(void*)&world->logic_achievements,
sizeof(struct logic_achievement)
},
{
k_classtype_world_light,
+ k_classtype_none,
(void*)&world->lights,
sizeof(struct world_light)
},
{
k_classtype_nonlocal_gate,
+ k_classtype_none,
(void*)&world->nonlocal_gates,
sizeof(struct nonlocal_gate)
+ },
+ {
+ k_classtype_soundscape,
+ k_classtype_none,
+ (void*)&world->soundscapes,
+ sizeof(struct soundscape)
}
};
for( int j=0; j<vg_list_size(entity_counts); j ++ )
{
- if( pnode->classtype == entity_counts[j].ct )
+ if( (pnode->classtype == entity_counts[j].ct) ||
+ (pnode->classtype == entity_counts[j].ct1) )
{
pnode->sub_uid = entity_counts[j].count;
entity_counts[j].count ++;
u32 bufsize = counter->item_size*counter->count;
*counter->to_allocate = vg_linear_alloc( world_global.generic_heap,
bufsize );
+ memset( *counter->to_allocate, 0, bufsize );
}
+
+ logic_bricks_world_gen_allocate( world );
}
VG_STATIC void world_pct_spawn( world_instance *world, mdl_node *pnode )
v3_copy( pnode->co, thing->pos );
- if( aud->flags & AUDIO_FLAG_SPACIAL_3D )
- thing->volume = aud->volume * pnode->s[0];
- else
- thing->volume = aud->volume;
+ thing->volume = aud->volume;
+ thing->range = pnode->s[0];
thing->flags = aud->flags;
thing->temp_embedded_clip.path = mdl_pstr( world->meta, aud->pstr_file );
thing->temp_embedded_clip.flags = aud->flags;
audio_clip_load( &thing->temp_embedded_clip, world_global.generic_heap );
- thing->player.name = mdl_pstr( world->meta, pnode->pstr_name );
- thing->player.enqued = 0;
pnode->sub_uid = world->audio_things_count;
world->audio_things_count ++;
}
-VG_STATIC void world_pct_trigger( world_instance *world, mdl_node *pnode )
-{
- struct trigger_zone *trigger = &world->triggers[ world->trigger_count ];
- struct classtype_trigger *inf = mdl_get_entdata( world->meta, pnode );
-
- if( inf->target )
- {
- mdl_node *target_node = mdl_node_from_id( world->meta, inf->target );
-
- trigger->target.sub_id = target_node->sub_uid;
- trigger->target.classtype = target_node->classtype;
- }
- else
- {
- vg_warn( "Trigger with no target...\n" );
- return;
- }
-
- mdl_node_transform( pnode, trigger->transform );
- m4x3_invert_full( trigger->transform, trigger->inv_transform );
-
- world->trigger_count ++;
-}
-
-
+#if 0
VG_STATIC void world_pct_relay( world_instance *world, mdl_node *pnode )
{
struct logic_relay *relay = &world->logic_relays[ world->relay_count ];
v3_copy( pnode->co, relay->pos );
world->relay_count ++;
}
+#endif
VG_STATIC void world_pct_achievement( world_instance *world, mdl_node *pnode )
{ k_classtype_spawn, world_pct_spawn },
{ k_classtype_water, world_pct_water },
{ k_classtype_audio, world_pct_audio },
- { k_classtype_trigger, world_pct_trigger },
+#if 0
{ k_classtype_logic_relay, world_pct_relay },
+#endif
{ k_classtype_logic_achievement, world_pct_achievement },
{ k_classtype_world_light, world_pct_world_light },
{ k_classtype_nonlocal_gate, world_pct_nonlocal_gate }
for( int i=0; i<world->audio_things_count; i++ )
{
struct world_audio_thing *thingy = &world->audio_things[ i ];
-
- audio_player_init( &thingy->player );
- audio_player_set_flags( &thingy->player, thingy->flags );
- audio_player_set_vol( &thingy->player, thingy->volume );
- audio_player_set_pan( &thingy->player, 0.0f );
-
- if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
- audio_player_set_position( &thingy->player, thingy->pos );
if( thingy->flags & AUDIO_FLAG_AUTO_START )
- audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
+ {
+ audio_channel *ch =
+ audio_request_channel( &thingy->temp_embedded_clip, thingy->flags );
+
+ audio_channel_edit_volume( ch, thingy->volume, 1 );
+ audio_channel_set_spacial( ch, thingy->pos, thingy->range );
+
+ if( !(ch->flags & AUDIO_FLAG_LOOP) )
+ ch = audio_relinquish_channel( ch );
+ }
}
audio_unlock();
/* clean dangling pointers */
world->meta = NULL;
+ /*
+ * TODO: Theres probably a better way to do this?
+ */
+
world->textures = NULL;
world->texture_count = 0;
world->materials = NULL;
world->lights = NULL;
world->light_count = 0;
+#if 0
world->logic_relays = NULL;
world->relay_count = 0;
+#endif
world->logic_achievements = NULL;
world->achievement_count = 0;
world->collectors = NULL;
world->collector_count = 0;
+ world->soundscapes = NULL;
+ world->soundscape_count = 0;
+
+ world->logic_bricks = NULL;
+ world->logic_brick_count = 0;
+
world->nonlocal_gates = NULL;
world->nonlocalgate_count = 0;
--- /dev/null
+#include "common.h"
+
+#ifndef WORLD_LOGIC_BRICKS_H
+#define WORLD_LOGIC_BRICKS_H
+
+#include "world.h"
+
+typedef struct logic_packet logic_packet;
+struct logic_packet
+{
+ u32 location, function;
+ union mdl_128bit_union data;
+ enum mdl_128bit_datatype type;
+};
+
+VG_STATIC void logic_bricks_debug_connection( world_instance *world,
+ mdl_node *from, u32 next,
+ v3f colour )
+{
+ if( next == 0 )
+ return;
+
+ mdl_node *to = mdl_node_from_id( world->meta, next );
+
+ v3f c;
+ float brightness = 0.8f + world->logic_bricks[ from->sub_uid ].usage * 4.0f;
+ v3_muls( colour, brightness, c );
+
+ u32 clamped = 0xff000000;
+
+ for( int i=0; i<3; i++ )
+ {
+ u8 byte = vg_minf( 1.0f, c[i] ) * 255.0f;
+ clamped |= byte << (i*8);
+ }
+
+ vg_line( from->co, to->co, clamped );
+}
+
+VG_STATIC void logic_bricks_debug( world_instance *world )
+{
+ v3f white = {1.0f,1.0f,1.0f},
+ red = {1.0f,0.2f,0.1f},
+ black = {0.2f,0.2f,0.2f};
+
+ glLineWidth( 2.0f );
+
+ for( int i=0; i<world->logic_brick_count; i++ )
+ {
+ struct logic_brick_ref *ref = &world->logic_bricks[i];
+ mdl_node *node = ref->node;
+
+ void *entdata = mdl_get_entdata( world->meta, node );
+
+ if( ref->node->classtype == k_classtype_logic_wire )
+ {
+ struct classtype_logic_wire *wire = entdata;
+
+ logic_bricks_debug_connection( world, node, wire->next, white );
+ }
+ else if( ref->node->classtype == k_classtype_logic_chances )
+ {
+ struct classtype_logic_chances *chances = entdata;
+
+ logic_bricks_debug_connection(world, node, chances->targets[0], red );
+ logic_bricks_debug_connection(world, node, chances->targets[1], black);
+ }
+ else if( ref->node->classtype == k_classtype_signal_splitter )
+ {
+ struct classtype_signal_splitter *splitter = entdata;
+ logic_bricks_debug_connection( world, node, splitter->next[0], white );
+ logic_bricks_debug_connection( world, node, splitter->next[1], white );
+ logic_bricks_debug_connection( world, node, splitter->next[2], white );
+ logic_bricks_debug_connection( world, node, splitter->next[3], white );
+ }
+ else if( ref->node->classtype == k_classtype_soundscape )
+ {
+ struct classtype_soundscape *inf = entdata;
+ struct soundscape *s = &world->soundscapes[ ref->internal_id ];
+
+ v3f co;
+ v3_copy( ref->node->co, co );
+
+ boxf box;
+ box[0][0] = co[0]-0.12f;
+ box[0][1] = co[1]-0.12f;
+ box[0][2] = co[2]-0.12f;
+ box[1][0] = co[0]+0.12f;
+ box[1][1] = co[1]+0.12f + 0.1f*(float)inf->max_instances;
+ box[1][2] = co[2]+0.12f;
+
+ vg_line_boxf( box, VG__WHITE );
+
+ for( int i=0; i<s->usage_count; i++ )
+ {
+ vg_line_pt3( co, 0.09f, VG__GREEN );
+ co[1] += 0.2f;
+ }
+ }
+ else if( ref->node->classtype == k_classtype_trigger )
+ {
+ struct classtype_trigger *trigger = entdata;
+ logic_bricks_debug_connection( world, node, trigger->target, white );
+ }
+ else if( ref->node->classtype == k_classtype_particle_box )
+ {
+ struct classtype_particle_box *pb = entdata;
+ logic_bricks_debug_connection( world, node, pb->target, white );
+ }
+
+ ref->usage *= vg_maxf( 0.0f, 1.0f-vg.time_delta*5.0f );
+ }
+}
+
+VG_STATIC void logic_packet_terminate( logic_packet *packet )
+{
+ packet->location = 0xffffffff;
+}
+
+VG_STATIC void logic_wire_call( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_logic_wire *inf = mdl_get_entdata( world->meta, ref->node );
+
+ if( packet->function == 0 ) /* pass onwards */
+ {
+ if( inf->next )
+ {
+ if( inf->data_type != k_mdl_128bit_datatype_nothing )
+ {
+ packet->data = inf->data;
+ packet->type = inf->data_type;
+ }
+
+ mdl_node *next = mdl_node_from_id( world->meta, inf->next );
+ packet->location = next->sub_uid;
+ packet->function = inf->function;
+ }
+ else
+ logic_packet_terminate( packet );
+ }
+ else if( packet->function == 1 ) /* TODO enable */
+ {
+ logic_packet_terminate( packet );
+ }
+ else if( packet->function == 2 ) /* TODO disable */
+ {
+ logic_packet_terminate( packet );
+ }
+ else
+ {
+ vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void logic_chances_call( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_logic_chances *inf =
+ mdl_get_entdata( world->meta, ref->node );
+
+ if( packet->function == 0 ) /* pass along */
+ {
+ int red = 1;
+
+ if( vg_randf() > inf->p )
+ red = 0;
+
+ if( inf->targets[red] )
+ {
+ mdl_node *pnext = mdl_node_from_id( world->meta, inf->targets[red] );
+
+ if( pnext->classtype == k_classtype_logic_wire )
+ {
+ packet->location = pnext->sub_uid;
+ }
+ else
+ {
+ vg_error( "[INVALID TARGET] logic_chances:pass( ... )\n" );
+ vg_warn( " target[%d] must be classtype logic_wire\n", red );
+ logic_packet_terminate( packet );
+ }
+ }
+ else
+ {
+ logic_packet_terminate( packet );
+ }
+ }
+ else if( packet->function == 1 ) /* set ratio */
+ {
+ if( packet->type == k_mdl_128bit_datatype_number )
+ {
+ inf->p = packet->data._f32;
+ }
+ else
+ {
+ vg_error( "[INVALID ARGUMENT] logic_chances:set_ratio( f32 p )\n" );
+ }
+
+ logic_packet_terminate( packet );
+ }
+ else
+ {
+ vg_error( "[INVALID FUNCTION] logic_chances:[%u]\n", packet->function );
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void logic_soundscape_call( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_soundscape *inf = mdl_get_entdata( world->meta, ref->node );
+ struct soundscape *soundscape = &world->soundscapes[ ref->internal_id ];
+
+ if( packet->function == 0 ) /* play */
+ {
+ /* TODO: Only spawn within certain range of player */
+
+ if( packet->type != k_mdl_128bit_datatype_target )
+ {
+ vg_error( "[INVALID ARGUMENT] logic_soundscape:play( ref sound )\n" );
+ vg_warn( " got datatype: %u\n", packet->type );
+ logic_packet_terminate( packet );
+ return;
+ }
+
+ mdl_node *data = mdl_node_from_id( world->meta, packet->data._u32 );
+
+ if( data->classtype != k_classtype_audio )
+ {
+ vg_error( "[INVALID TARGET] logic_soundscape:play( ref sound )\n" );
+ logic_packet_terminate( packet );
+ return;
+ }
+
+ if( soundscape->usage_count < soundscape->max_instances )
+ {
+ struct world_audio_thing *audio = &world->audio_things[data->sub_uid];
+
+
+ for( int i=0; i<soundscape->max_instances; i++ )
+ {
+ if( !soundscape->channels[i] )
+ {
+ audio_lock();
+ soundscape->channels[i] = audio_request_channel(
+ &audio->temp_embedded_clip,
+ audio->flags );
+
+ if( soundscape->channels[i] )
+ {
+ if( audio->flags & AUDIO_FLAG_SPACIAL_3D )
+ {
+ audio_channel_set_spacial( soundscape->channels[i],
+ soundscape->spawn_position,
+ audio->range );
+ }
+
+ audio_channel_edit_volume( soundscape->channels[i],
+ audio->volume,
+ 1 );
+ }
+
+ audio_unlock();
+
+ soundscape->usage_count ++;
+ break;
+ }
+ }
+
+ }
+
+ logic_packet_terminate( packet );
+ }
+ else if( packet->function == 1 ) /* set position */
+ {
+ if( packet->type != k_mdl_128bit_datatype_vec3 )
+ {
+ vg_error( "[INVALID ARGUMENT] logic_soundscape:position( v3f co )\n" );
+ logic_packet_terminate( packet );
+ return;
+ }
+
+ v3_copy( packet->data._v4f, soundscape->spawn_position );
+ logic_packet_terminate( packet );
+ }
+ else
+ {
+ vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void _logic_trigger_base_call( world_instance *world, u32 target,
+ logic_packet *packet )
+{
+ if( packet->function == 0 ) /* pass onwards */
+ {
+ if( target )
+ {
+ mdl_node *next = mdl_node_from_id( world->meta, target );
+ packet->location = next->sub_uid;
+ packet->function = 0; /* always call the default function */
+ }
+ else
+ logic_packet_terminate( packet );
+ }
+ else
+ {
+ vg_error( "[INVALID FUNCTION] logic_trigger:[%u]\n", packet->function );
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void logic_trigger_call( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_trigger *inf = mdl_get_entdata( world->meta, ref->node );
+ _logic_trigger_base_call( world, inf->target, packet );
+}
+
+VG_STATIC void logic_particle_call( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_particle_box *inf =
+ mdl_get_entdata( world->meta, ref->node );
+
+ /* rate of 1.0 means we get one a second or 0.1 per tick */
+
+ if( vg_randf() < inf->rate * 0.1f )
+ {
+ ref->usage += 1.0f;
+ _logic_trigger_base_call( world, inf->target, packet );
+ }
+ else
+ {
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void logic_bricks_send_packet( world_instance *world,
+ logic_packet *packet );
+
+VG_STATIC void logic_splitter( world_instance *world,
+ struct logic_brick_ref *ref,
+ logic_packet *packet )
+{
+ struct classtype_signal_splitter *inf
+ = mdl_get_entdata( world->meta, ref->node );
+
+ if( packet->function == 0 ) /* pass onwards */
+ {
+ for( int i=0; i<4; i++ )
+ {
+ if( inf->next[i] )
+ {
+ logic_packet copy = *packet;
+
+ mdl_node *next = mdl_node_from_id( world->meta, inf->next[i] );
+ copy.location = next->sub_uid;
+ copy.function = 0; /* always call the default function */
+
+ logic_bricks_send_packet( world, © );
+ }
+ }
+
+ logic_packet_terminate( packet );
+ }
+ else
+ {
+ vg_error( "[INVALID FUNCTION] logic_splitter:[%u]\n", packet->function );
+ logic_packet_terminate( packet );
+ }
+}
+
+VG_STATIC void logic_bricks_send_packet( world_instance *world,
+ logic_packet *packet )
+{
+ while( packet->location != 0xffffffff )
+ {
+ struct logic_brick_ref *ref = &world->logic_bricks[ packet->location ];
+ enum classtype type = ref->node->classtype;
+
+ if( type == k_classtype_logic_wire )
+ {
+ logic_wire_call( world, ref, packet );
+ }
+ else if( type == k_classtype_logic_chances )
+ {
+ logic_chances_call( world, ref, packet );
+ }
+ else if( type == k_classtype_soundscape )
+ {
+ logic_soundscape_call( world, ref, packet );
+ }
+ else if( type == k_classtype_trigger )
+ {
+ logic_trigger_call( world, ref, packet );
+ }
+ else if( type == k_classtype_particle_box )
+ {
+ logic_particle_call( world, ref, packet );
+ continue;
+ }
+ else if( type == k_classtype_signal_splitter )
+ {
+ logic_splitter( world, ref, packet );
+ }
+ else
+ {
+ vg_error( "Undefined logic brick (entity type %d)\n", type );
+ logic_packet_terminate( packet );
+ }
+
+ ref->usage += 1.0f;
+ }
+}
+
+VG_STATIC void logic_bricks_world_gen_allocate( world_instance *world )
+{
+ /* REVISION: unify allocations, loaders and extensions for entities.
+ * we currently seem to do every which entity a different way */
+
+ world->logic_brick_count = 0;
+ world->logic_bricks = NULL;
+ world->soundscape_count = 0;
+ world->trigger_count = 0;
+
+ for( int i=0; i<world->meta->info.node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id( world->meta, i );
+
+ if( pnode->classtype == k_classtype_logic_wire ||
+ pnode->classtype == k_classtype_logic_chances ||
+ pnode->classtype == k_classtype_soundscape ||
+ pnode->classtype == k_classtype_trigger ||
+ pnode->classtype == k_classtype_particle_box ||
+ pnode->classtype == k_classtype_signal_splitter )
+ {
+ world->logic_bricks =
+ vg_linear_extend( world_global.generic_heap,
+ world->logic_bricks,
+ sizeof( struct logic_brick_ref ) );
+
+ pnode->sub_uid = world->logic_brick_count;
+
+ struct logic_brick_ref *ref =
+ &world->logic_bricks[ world->logic_brick_count ];
+ ref->node = pnode;
+ ref->internal_id = 0;
+
+ if( pnode->classtype == k_classtype_soundscape )
+ {
+ u32 id = world->soundscape_count;
+
+ struct soundscape *soundscape = &world->soundscapes[ id ];
+
+ struct classtype_soundscape *inf =
+ mdl_get_entdata( world->meta, pnode );
+
+ soundscape->label = mdl_pstr( world->meta, inf->label );
+ soundscape->max_instances = inf->max_instances;
+ soundscape->allow_transitions = inf->allow_transitions;
+ soundscape->transition_duration = inf->transition_duration;
+ v3_copy( pnode->co, soundscape->spawn_position );
+
+ ref->internal_id = id;
+ world->soundscape_count ++;
+ }
+ else if( pnode->classtype == k_classtype_trigger ||
+ pnode->classtype == k_classtype_particle_box )
+ {
+ u32 id = world->trigger_count;
+ struct trigger_zone *trigger = &world->triggers[ id ];
+
+ mdl_node_transform( pnode, trigger->transform );
+ m4x3_invert_full( trigger->transform, trigger->inv_transform );
+ trigger->target_logic_brick = world->logic_brick_count;
+ trigger->classtype = pnode->classtype;
+
+ world->trigger_count ++;
+ }
+
+ world->logic_brick_count ++;
+ }
+ }
+}
+
+#endif /* WORLD_LOGIC_BRICKS_H */