X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=world_logic_bricks.h;fp=world_logic_bricks.h;h=2df236a6457b670fd4e520f0083488c34a592327;hb=a9e3181f697ab37fc74f072cfcfdf44e2d659468;hp=0000000000000000000000000000000000000000;hpb=0136a935c00e3ea1f231fd88b38b44982fd409ac;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/world_logic_bricks.h b/world_logic_bricks.h new file mode 100644 index 0000000..2df236a --- /dev/null +++ b/world_logic_bricks.h @@ -0,0 +1,495 @@ +#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; ilogic_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; iusage_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; imax_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; imeta->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 */