('ent_font', 'Font', '', 9 ),
('ent_font_variant', 'Font:Variant', '', 10 ),
('ent_traffic', 'Traffic Model', '', 11 ),
+ ('ent_skateshop', 'Skate Shop', '', 12 )
]
def get_entity_enum_id( alias ):
("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)]
#}
("index",c_uint32)]
#}
+class ent_skateshop(Structure):
+#{
+ _fields_ = [("transform",mdl_transform),
+ ("id_display",c_uint32),
+ ("id_info",c_uint32),
+ ("id_rack",c_uint32)]
+#}
+
def obj_ent_type( obj ):
#{
if obj.type == 'ARMATURE': return 'mdl_armature'
yield from _recurse_bone( b )
#}
+def sr_entity_id( obj ):
+#{
+ tipo = get_entity_enum_id( obj_ent_type(obj) )
+ index = sr_compile.entity_ids[ obj.name ]
+
+ return (tipo&0xffff)<<16 | (index&0xffff)
+#}
+
# Returns submesh_start,count and armature_id
def sr_compile_mesh_internal( obj ):
#{
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 )
#}
sr_ent_push(volume)
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.id_display = sr_entity_id( obj_data.mark_display )
+ skateshop.id_info = sr_entity_id( obj_data.mark_info )
+ skateshop.id_rack = sr_entity_id( obj_data.mark_rack )
+ compile_obj_transform( obj, skateshop.transform )
+ sr_ent_push(skateshop)
+ #}
#}
#}
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']))
@staticmethod
def sr_inspector( layout, data ):
speed: bpy.props.FloatProperty(default=1.0)
#}
+class SR_OBJECT_ENT_SKATESHOP(bpy.types.PropertyGroup):
+#{
+ 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']))
+#}
+
class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
#{
ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
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_type: bpy.props.EnumProperty(
name="Type",
items=sr_entity_list,
#}
#}
#}
+ elif ent_type == 'ent_skateshop':#{
+ cc = (0.0,0.9,0.6)
+ cc1 = (0.4,0.9,0.2)
+ cc2 = (0.9,0.6,0.1)
+
+ data = obj.SR_data.ent_skateshop[0]
+ display = data.mark_display
+ info = data.mark_info
+ 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.2,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
+
+ 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 )
+ #}
#}
#}
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_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES,
SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \
_S( "model_menu", "model.vs", "model_menu.fs" );
_S( "model_character_view", "model_skinned.vs", "model_character_view.fs" );
_S( "model_board_view", "model.vs", "model_character_view.fs" );
+ _S( "model_entity", "model.vs", "model_entity.fs" );
_S( "model_gate", "model_gate.vs", "model_gate_lq.fs" );
_S( "model_font", "model_font.vs", "model_font.fs" );
--- /dev/null
+#ifndef ENT_SKATESHOP_C
+#define ENT_SKATESHOP_C
+
+#include "world.h"
+#include "player.h"
+
+#define MAX_LOCAL_BOARDS 64
+#define BILL_TIN_BOARDS 1
+#define MAX_DYNAMIC_BOARDS 9
+
+struct{
+ v3f look_target;
+ mdl_transform rack_root,
+ display_root,
+ info_root;
+
+ enum camera_mode prev_camera_mode;
+
+ int active;
+ float factive;
+
+ enum skateshop_loc{
+ k_skateshop_loc_page__viewing,
+
+ k_skateshop_loc_select_use,
+ k_skateshop_loc_select_cancel,
+ k_skateshop_loc_select_upload,
+ k_skateshop_loc_page__selected,
+
+ k_skateshop_loc_page__upload,
+ }
+ interface_loc;
+
+ struct dynamic_board
+ {
+ enum dynamic_board_state{
+ k_dynamic_board_state_none,
+ k_dynamic_board_state_loaded,
+ k_dynamic_board_state_loading,
+ }
+ state;
+
+ u32 ref_count;
+
+ struct player_board board;
+
+ u32 registry_id;
+
+ double last_use_time;
+ }
+ *dynamic_boards,
+ *localplayer_slot;
+
+ struct shop_view_slot
+ {
+ struct dynamic_board *db;
+ float view_blend;
+ }
+ shop_view_slots[6];
+
+ struct board_registry
+ {
+ int workshop;
+ u64 uid;
+
+ struct dynamic_board *dynamic;
+
+ char filename[64]; /* if workshop, string version of uid. */
+ u32 filename_hash;
+
+ int ghost;
+ }
+ *registry;
+ u32 registry_count;
+
+ int loading;
+ float interaction_cooldown;
+
+ u32 selected_registry_id;
+}
+static global_skateshop;
+
+static inline int const_str_eq( u32 hash, const char *str, const char *cmp )
+{
+ if( hash == vg_strdjb2(cmp) )
+ if( !strcmp( str, cmp ) )
+ return 1;
+ return 0;
+}
+
+static int skateshop_workshop_name_blacklisted( u32 hash, const char *name )
+{
+ if( const_str_eq( hash, name, "skaterift_fish.mdl" ) ) return 1;
+ return 0;
+}
+
+VG_STATIC void skateshop_loader_start( void (*pfn)(void) )
+{
+ if( global_skateshop.loading )
+ vg_fatal_error( "skateshop thread sync failure\n" );
+
+ global_skateshop.loading = 1;
+ vg_loader_start( pfn );
+}
+
+VG_STATIC void skateshop_async_post( void *payload, u32 size )
+{
+ global_skateshop.loading = 0;
+}
+
+VG_STATIC
+struct dynamic_board *skateshop_lru_alloc( u32 id )
+{
+ double min_time = 1e300;
+ struct dynamic_board *min_board = NULL;
+
+ for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+ struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
+
+ if( db->state == k_dynamic_board_state_loading )
+ continue;
+
+ if( db->ref_count )
+ continue;
+
+ if( db->last_use_time < min_time ){
+ min_time = db->last_use_time;
+ min_board = db;
+ }
+ }
+
+ if( min_board ){
+ localplayer.board = NULL; /* temp */
+
+ if( min_board->state == k_dynamic_board_state_loaded ){
+ struct board_registry *other =
+ &global_skateshop.registry[min_board->registry_id];
+
+ vg_info( "Deallocating board: '%s'\n", min_board, other->filename );
+
+ player_board_unload( &min_board->board );
+ other->dynamic = NULL;
+ }
+
+ struct board_registry *reg = &global_skateshop.registry[id];
+
+ vg_info( "Allocating board '%s' @%p\n", reg->filename, min_board );
+
+ min_board->state = k_dynamic_board_state_loading;
+ min_board->registry_id = id;
+ min_board->last_use_time = vg.time;
+ min_board->ref_count = 0;
+ }
+ else{
+ vg_error( "No free boards to load registry!\n" );
+ }
+
+ return min_board;
+}
+
+VG_STATIC
+void skateshop_board_registry_path( struct board_registry *reg, char path[256] )
+{
+ if( reg->workshop ){
+ snprintf( path, 256, "models/boards/workshop/%s/something.mdl",
+ reg->filename );
+ }
+ else{
+ snprintf( path, 256, "models/boards/%s", reg->filename );
+ }
+}
+
+VG_STATIC void skateshop_async_board_complete( void *payload, u32 size )
+{
+ struct dynamic_board *db = payload;
+
+ if( db == global_skateshop.localplayer_slot ){
+ localplayer.board = &db->board;
+ db->ref_count ++;
+ }
+ else{
+ for( u32 i=0; i<vg_list_size(global_skateshop.shop_view_slots); i++ ){
+ if( global_skateshop.shop_view_slots[i].db == db ){
+ db->ref_count ++;
+ }
+ }
+ }
+
+ db->last_use_time = vg.time;
+ db->state = k_dynamic_board_state_loaded;
+
+ struct board_registry *reg = &global_skateshop.registry[ db->registry_id ];
+ reg->dynamic = db;
+
+ vg_success( "Async board loaded (%s)\n", reg->filename );
+}
+
+VG_STATIC void skateshop_load_requested_boards(void)
+{
+ char path[256];
+ for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+ struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
+
+ if( db->state == k_dynamic_board_state_loading ){
+ struct board_registry *reg =
+ &global_skateshop.registry[ db->registry_id ];
+
+ skateshop_board_registry_path( reg, path );
+ player_board_load( &db->board, path );
+ vg_async_call( skateshop_async_board_complete, db, 0 );
+ }
+ }
+}
+
+VG_STATIC void skateshop_thread1_refresh(void)
+{
+ skateshop_load_requested_boards();
+ vg_async_call( skateshop_async_post, NULL, 0 );
+}
+
+VG_STATIC int skateshop_use_board( int argc, const char *argv[] )
+{
+ if( global_skateshop.loading ){
+ vg_error( "Cannot use skateshop currently (loader thread missing)\n" );
+ return 0;
+ }
+
+ if( argc == 1 ){
+ u32 hash = vg_strdjb2( argv[0] );
+
+ for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+ struct board_registry *reg = &global_skateshop.registry[i];
+
+ if( const_str_eq( hash, argv[0], reg->filename ) ){
+
+ if( reg->dynamic ){
+ struct dynamic_board *db = reg->dynamic;
+
+ if( db->state == k_dynamic_board_state_loaded ){
+ localplayer.board = &db->board;
+ db->last_use_time = vg.time;
+ }
+ else{
+ vg_fatal_error( "Invalid state while loading board\n" );
+ }
+ }
+ else{
+ struct dynamic_board *db = skateshop_lru_alloc( i );
+ db->state = k_dynamic_board_state_loading;
+ skateshop_loader_start( skateshop_thread1_refresh );
+ }
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+VG_STATIC void skateshop_use_board_suggest( int argc, const char *argv[] )
+{
+ if( argc == 1 ){
+ for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+ struct board_registry *reg = &global_skateshop.registry[i];
+
+ if( reg->ghost ) continue; /* we probably can't load these */
+
+ console_suggest_score_text( reg->filename, argv[0], 0 );
+ }
+ }
+}
+
+VG_STATIC void skateshop_scan_for_items(void)
+{
+ vg_linear_clear( vg_mem.scratch );
+
+ for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+ struct board_registry *reg = &global_skateshop.registry[i];
+ reg->ghost = 1;
+ }
+
+ tinydir_dir dir;
+ tinydir_open( &dir, "models/boards" );
+
+ while( dir.has_next ){
+ tinydir_file file;
+ tinydir_readfile( &dir, &file );
+
+ if( file.is_reg ){
+ u32 hash = vg_strdjb2( file.name );
+
+ for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+ struct board_registry *reg = &global_skateshop.registry[i];
+
+ if( const_str_eq( hash, file.name, reg->filename ) ){
+ reg->ghost = 0;
+ goto next_file;
+ }
+ }
+
+ if( global_skateshop.registry_count == MAX_LOCAL_BOARDS ){
+ vg_error( "You have too many boards installed!\n" );
+ break;
+ }
+
+ vg_info( "new listing!: %s\n", file.name );
+
+ struct board_registry *reg = &global_skateshop.registry[
+ global_skateshop.registry_count ++ ];
+
+ reg->dynamic = NULL;
+ vg_strncpy( file.name, reg->filename, 64, k_strncpy_always_add_null );
+ reg->filename_hash = hash;
+ reg->uid = 0;
+ reg->workshop = 0;
+ reg->ghost = 0;
+ }
+
+next_file: tinydir_next( &dir );
+ }
+
+ tinydir_close(&dir);
+
+ skateshop_load_requested_boards();
+ vg_async_call( skateshop_async_post, NULL, 0 );
+}
+
+VG_STATIC void global_skateshop_exit(void)
+{
+ global_skateshop.active = 0;
+ localplayer.camera_mode = global_skateshop.prev_camera_mode;
+}
+
+VG_STATIC void skateshop_request_viewpage( u32 page )
+{
+ u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
+ u32 start = page * slot_count;
+
+ for( u32 i=0; i<slot_count; i++ ){
+ struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
+
+ if( slot->db ){
+ slot->db->ref_count --;
+ slot->db = NULL;
+ }
+
+ u32 reg_index = start+i;
+ if( reg_index < global_skateshop.registry_count ){
+ struct board_registry *reg = &global_skateshop.registry[ reg_index ];
+
+ if( reg->dynamic ){
+ struct dynamic_board *db = reg->dynamic;
+
+ if( db->state == k_dynamic_board_state_loaded ){
+ db->last_use_time = vg.time;
+ db->ref_count ++;
+ slot->db = db;
+ }
+ else{
+ vg_fatal_error( "Invalid state while loading page\n" );
+ }
+ }
+ else{
+ struct dynamic_board *db = skateshop_lru_alloc( reg_index );
+
+ if( db ){
+ db->ref_count ++;
+ slot->db = db;
+ }
+ }
+ }
+ }
+}
+
+VG_STATIC void ent_skateshop_call( world_instance *world, ent_call *call )
+{
+ u32 index = mdl_entity_id_id( call->id );
+ ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, index );
+ vg_info( "skateshop_call\n" );
+
+ if( global_skateshop.loading ){
+ vg_error( "Cannot enter skateshop currently (loader thread missing)\n" );
+ return;
+ }
+
+ if( call->function == k_ent_function_trigger ){
+ if( localplayer.subsystem != k_player_subsystem_walk ){
+ return;
+ }
+
+ vg_info( "Entering skateshop\n" );
+
+ localplayer.immobile = 1;
+ global_skateshop.prev_camera_mode = localplayer.camera_mode;
+ localplayer.camera_mode = k_cam_firstperson;
+ global_skateshop.active = 1;
+ global_skateshop.interface_loc = k_skateshop_loc_page__viewing;
+
+ v3_zero( localplayer.rb.v );
+ v3_zero( localplayer.rb.w );
+ localplayer._walk.move_speed = 0.0f;
+
+ struct{
+ mdl_transform *transform;
+ u32 id;
+ }
+ targets[] = {
+ { &global_skateshop.rack_root, shop->id_rack, },
+ { &global_skateshop.info_root, shop->id_info, },
+ { &global_skateshop.display_root, shop->id_display, },
+ };
+
+ v3_copy( shop->transform.co, global_skateshop.look_target );
+
+ for( u32 i=0; i<vg_list_size(targets); i++ ){
+
+ u32 type = mdl_entity_id_type( targets[i].id ),
+ index = mdl_entity_id_id( targets[i].id );
+
+ if( type == k_ent_marker ){
+ ent_marker *m = mdl_arritm( &world->ent_marker, index );
+
+ *targets[i].transform = m->transform;
+ }
+ else{
+ transform_identity( targets[i].transform );
+ }
+ }
+
+ skateshop_request_viewpage(0);
+ skateshop_loader_start( skateshop_scan_for_items );
+ }
+}
+
+VG_STATIC void global_skateshop_preupdate(void)
+{
+ float rate = vg_minf( 1.0f, vg.time_frame_delta * 2.0f );
+ global_skateshop.factive = vg_lerpf( global_skateshop.factive,
+ global_skateshop.active, rate );
+
+
+ if( !global_skateshop.active ) return;
+
+ v3f delta;
+ v3_sub( global_skateshop.look_target, localplayer.cam.pos, delta );
+ v3_normalize( delta );
+
+ v3f target;
+ player_vector_angles( target, delta, 1.0f, 0.0f );
+
+ camera_lerp_angles( localplayer.angles, target,
+ global_skateshop.factive, localplayer.angles);
+
+ if( global_skateshop.interaction_cooldown > 0.0f ){
+ global_skateshop.interaction_cooldown -= vg.time_delta;
+ return;
+ }
+
+ float h = localplayer.input_js1h->axis.value;
+
+ if( global_skateshop.interface_loc <= k_skateshop_loc_page__viewing ){
+ if( fabsf(h) > 0.25f ){
+ if( h < 0.0f ){
+ if( global_skateshop.selected_registry_id > 0 )
+ global_skateshop.selected_registry_id --;
+ }
+ else{
+ if( global_skateshop.selected_registry_id <
+ global_skateshop.registry_count-1 )
+ {
+ global_skateshop.selected_registry_id ++;
+ }
+ }
+
+ vg_info( "Select registry: %u\n",
+ global_skateshop.selected_registry_id );
+ global_skateshop.interaction_cooldown = 0.125f;
+ return;
+ }
+
+ if( vg_input_button_down( &input_menu_back ) ){
+ global_skateshop.active = 0;
+ return;
+ }
+ }
+ else if( global_skateshop.interface_loc <= k_skateshop_loc_page__selected ){
+ if( vg_input_button_down( &input_menu_back ) ){
+ global_skateshop.interface_loc = k_skateshop_loc_page__viewing;
+ return;
+ }
+
+ if( fabsf(h) > 0.25f ){
+ if( global_skateshop.interface_loc == k_skateshop_loc_select_use ){
+ global_skateshop.interface_loc = k_skateshop_loc_select_cancel;
+ return;
+ }
+ }
+ else{
+ if( global_skateshop.interface_loc == k_skateshop_loc_select_cancel ){
+ global_skateshop.interface_loc = k_skateshop_loc_select_use;
+ return;
+ }
+ }
+ }
+}
+
+VG_STATIC void skateshop_init(void)
+{
+ global_skateshop.registry =
+ vg_linear_alloc( vg_mem.rtmemory,
+ sizeof(struct board_registry)*MAX_LOCAL_BOARDS );
+ global_skateshop.registry_count = 0;
+ global_skateshop.dynamic_boards =
+ vg_linear_alloc( vg_mem.rtmemory,
+ sizeof(struct dynamic_board)*MAX_DYNAMIC_BOARDS );
+
+ memset( global_skateshop.dynamic_boards, 0,
+ sizeof(struct dynamic_board)*MAX_DYNAMIC_BOARDS );
+
+ for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+ struct dynamic_board *board = &global_skateshop.dynamic_boards[i];
+ board->state = k_dynamic_board_state_none;
+ board->registry_id = 0xffffffff;
+ board->last_use_time = -99999.9;
+ board->ref_count = 0;
+ }
+
+ vg_console_reg_cmd( "use_board",
+ skateshop_use_board, skateshop_use_board_suggest );
+
+ skateshop_scan_for_items();
+}
+
+VG_STATIC void skateshop_render(void)
+{
+ if( !global_skateshop.active ) return;
+
+ world_instance *world = get_active_world();
+
+ u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
+
+ for( u32 i=0; i<slot_count; i++ ){
+ struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
+
+ float selected = 0.0f;
+
+ if( !slot->db )
+ goto set_fade_amt;
+
+ if( slot->db->state != k_dynamic_board_state_loaded )
+ goto set_fade_amt;
+
+ mdl_transform rack_xform;
+ transform_identity( &rack_xform );
+
+ rack_xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
+
+ mdl_transform_mul( &global_skateshop.rack_root,
+ &rack_xform, &rack_xform );
+
+ if( slot->db->registry_id == global_skateshop.selected_registry_id ){
+ selected = 1.0f;
+ }
+
+ float t = slot->view_blend;
+ v3_lerp( rack_xform.co, global_skateshop.display_root.co,
+ t, rack_xform.co );
+ q_nlerp( rack_xform.q, global_skateshop.display_root.q,
+ t, rack_xform.q );
+ v3_lerp( rack_xform.s, global_skateshop.display_root.s,
+ t, rack_xform.s );
+
+ m4x3f mmdl;
+ mdl_transform_m4x3( &rack_xform, mmdl );
+ render_board( &main_camera, world, &slot->db->board, mmdl,
+ k_board_shader_entity );
+
+set_fade_amt:;
+ float rate = 5.0f*vg.time_delta;
+ slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
+ }
+
+ m4x3f mtext;
+ mdl_transform_m4x3( &global_skateshop.info_root, mtext );
+
+ m4x3f mlocal = {{0.2f,0.0f,0.0f},{0.0f,0.2f,0.0f},{0.0f,0.0f,0.03f},
+ {-font3d_string_width( &world_global.font,0,
+ "Made by... Bob man 123" )*0.2f*0.5f,0.0f,0.0f}
+ };
+
+ m4x3_mul( mtext, mlocal, mtext );
+
+ font3d_bind( &world_global.font, &main_camera );
+
+ shader_model_font_uColour( (v4f){1.0f,0.5f,0.1f,1.0f} );
+ font3d_simple_draw( &world_global.font, 0, "Made by... Bob man 123",
+ &main_camera, mtext );
+}
+
+#endif /* ENT_SKATESHOP_C */
--- /dev/null
+#ifndef ENTITY_C
+#define ENTITY_C
+
+#include "entity.h"
+#include "world.h"
+
+#include "ent_skateshop.c"
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call )
+{
+ u32 type = mdl_entity_id_type( call->id );
+
+ if( type == k_ent_volume ){
+ ent_volume_call( world, call );
+ } else if( type == k_ent_audio ){
+ ent_audio_call( world, call );
+ } else if( type == k_ent_skateshop ){
+ ent_skateshop_call( world, call );
+ }
+}
+
+#endif /* ENTITY_C */
typedef struct volume_trigger volume_trigger;
typedef struct ent_volume ent_volume;
typedef struct ent_audio ent_audio;
-typedef struct ent_index ent_index;
typedef struct ent_marker ent_marker;
typedef struct ent_traffic ent_traffic;
typedef struct ent_font ent_font;
typedef struct ent_font_variant ent_font_variant;
typedef struct ent_glyph ent_glyph;
+typedef struct ent_skateshop ent_skateshop;
enum entity_alias{
k_ent_none = 0,
k_ent_marker = 8,
k_ent_font = 9,
k_ent_font_variant= 10,
- k_ent_traffic = 11
+ k_ent_traffic = 11,
+ k_ent_skateshop = 12
};
static u32 mdl_entity_id_type( u32 entity_id )
return entity_id & 0x0000ffff;
}
-struct ent_index{
- u32 type,
- index;
-};
+static u32 mdl_entity_id( u32 type, u32 index )
+{
+ return (type & 0xfffff)<<16 | (index & 0xfffff);
+}
enum entity_function{
k_ent_function_trigger,
m4x3f to_world, to_local;
u32 type;
- ent_index target;
+ u32 target;
union{
volume_trigger trigger;
u32 pstr_alias;
};
+struct ent_skateshop{
+ mdl_transform transform;
+ u32 id_display,
+ id_info,
+ id_rack;
+};
+
struct ent_traffic{
mdl_transform transform;
u32 submesh_start,
indice_count;
};
+
+typedef struct ent_call ent_call;
+struct ent_call{
+ u32 id, function;
+ void *data;
+};
+
+#include "world.h"
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call );
+
#endif /* ENTITY_H */
--- /dev/null
+#ifndef GUI_H
+#define GUI_H
+
+#include "font.h"
+
+VG_STATIC void gui_example( void )
+{
+
+}
+
+#endif /* GUI_H */
#include "shaders/model_menu.h"
#include "vg_steam_friends.h"
-#include "submodules/tinydir/tinydir.h"
VG_STATIC mdl_context menu_model;
VG_STATIC mdl_array_ptr menu_markers;
struct menu_map_file *mf = &game_menu.maps_list[ game_menu.map_count ];
vg_strncpy( file.name, mf->name,
- vg_list_size(game_menu.maps_list[0].name)-1 );
+ vg_list_size(game_menu.maps_list[0].name),
+ k_strncpy_always_add_null );
game_menu.map_count ++;
if( game_menu.map_count == vg_list_size(game_menu.maps_list) )
v4f q;
};
+static void transform_identity( mdl_transform *transform )
+{
+ v3_zero( transform->co );
+ q_identity( transform->q );
+ v3_fill( transform->s, 1.0f );
+}
+
+static void mdl_transform_vector( mdl_transform *transform, v3f vec, v3f dest )
+{
+ v3_mul( transform->s, vec, dest );
+ q_mulv( transform->q, dest, dest );
+}
+
+static void mdl_transform_point( mdl_transform *transform, v3f co, v3f dest )
+{
+ mdl_transform_vector( transform, co, dest );
+ v3_add( transform->co, dest, dest );
+}
+
+static void mdl_transform_mul( mdl_transform *a, mdl_transform *b,
+ mdl_transform *d )
+{
+ mdl_transform_point( a, b->co, d->co );
+ q_mul( a->q, b->q, d->q );
+ q_normalize( d->q );
+ v3_mul( a->s, b->s, d->s );
+}
+
struct mdl_material
{
u32 pstr_name,
nick.inetmsg_id = k_inetmsg_set_nickname;
memset( nick.nickname, 0, 16 );
- vg_strncpy( steam_username_at_startup, nick.nickname, 16 );
+ vg_strncpy( steam_username_at_startup, nick.nickname, 16,
+ k_strncpy_allow_cutoff );
SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
hSteamNetworkingSockets, cremote, &nick, sizeof(netmsg_set_nickname),
player->playermodel = mdl;
}
-PLAYER_API
-void player__use_board( player_instance *player, struct player_board *mdl )
-{
- player->playerboard = mdl;
-}
-
PLAYER_API
void player__bind( player_instance *player )
{
return;
}
- if( vg_input_button_down( player->input_reset ) ){
+ if( vg_input_button_down( player->input_reset ) && !player->immobile ){
double delta = world_global.time - world_global.last_use;
if( (delta <= RESET_MAX_TIME) && (world_global.last_use != 0.0) ){
}
}
- if( vg_input_button_down( player->input_camera ) ){
+ if( vg_input_button_down( player->input_camera ) && !player->immobile ){
if( player->camera_mode == k_cam_firstperson )
player->camera_mode = k_cam_thirdperson;
else
b[3].co[1] = vg_uictx.cursor[1];
}
+VG_STATIC void global_skateshop_exit(void);
PLAYER_API void player__spawn( player_instance *player,
ent_spawn *rp )
{
m3x3_identity( player->invbasis );
player->subsystem = k_player_subsystem_walk;
+ player->immobile = 0;
player->gate_waiting = NULL;
+ global_skateshop_exit();
+
if( _player_reset[ player->subsystem ] )
_player_reset[ player->subsystem ]( player, rp );
}
*input_grab,
*input_camera;
+ int immobile;
+
/*
* Animation
* --------------------------------------------------
*/
-
struct player_avatar *playeravatar;
struct player_model *playermodel;
- struct player_board *playerboard;
struct player_ragdoll ragdoll;
+ struct player_board *board;
player_pose holdout_pose;
float holdout_time;
#include "shaders/model_character_view.h"
#include "shaders/model_board_view.h"
+#include "shaders/model_entity.h"
VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
{
for( u32 i=0; i<mdl_arrcount(&ctx.meshs); i++ ){
mdl_mesh *mesh = mdl_arritm( &ctx.meshs, i );
- vg_info( "[%u]=%u:%u\n", mesh->entity_id,
- mdl_entity_id_type( mesh->entity_id ),
- mdl_entity_id_id( mesh->entity_id ) );
-
if( mdl_entity_id_type( mesh->entity_id ) != k_ent_marker )
continue;
}
}
+VG_STATIC void player_board_unload( struct player_board *mdl )
+{
+ mesh_free( &mdl->mesh );
+ glDeleteTextures( 1, &mdl->texture );
+}
+
VG_STATIC void player__pre_render( player_instance *player )
{
if( _player_animate[ player->subsystem ] ){
struct player_avatar *av = player->playeravatar;
- v3f vp0 = {0.0f,0.1f, player->playerboard->truck_positions[0][2]},
- vp1 = {0.0f,0.1f, player->playerboard->truck_positions[1][2]};
+ struct player_board *board = player->board;
+
+ v3f vp0, vp1;
+
+ if( board ){
+ v3_copy((v3f){0.0f,0.1f, board->truck_positions[0][2]}, vp0 );
+ v3_copy((v3f){0.0f,0.1f, board->truck_positions[1][2]}, vp1 );
+ }
+ else{
+ v3_zero( vp0 );
+ v3_zero( vp1 );
+ }
struct ub_world_lighting *ubo = &get_active_world()->ub_lighting;
m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, ubo->g_board_0 );
player__cam_iterate( player );
}
-PLAYER_API void player__render( camera *cam, player_instance *player )
+enum board_shader{
+ k_board_shader_player,
+ k_board_shader_entity
+};
+
+VG_STATIC void render_board( camera *cam, world_instance *world,
+ struct player_board *board, m4x3f root,
+ enum board_shader shader )
{
- shader_model_character_view_use();
+ if( !board ) return;
- glActiveTexture( GL_TEXTURE0 );
- glBindTexture( GL_TEXTURE_2D, player->playermodel->texture );
- shader_model_character_view_uTexMain( 0 );
- shader_model_character_view_uCamera( cam->transform[3] );
- shader_model_character_view_uPv( cam->mtx.pv );
- shader_model_character_view_uTexSceneDepth( 1 );
- render_fb_bind_texture( gpipeline.fb_main, 2, 1 );
v3f inverse;
- render_fb_inverse_ratio( gpipeline.fb_main, inverse );
- inverse[2] = main_camera.farz-main_camera.nearz;
-
- shader_model_character_view_uInverseRatioDepth( inverse );
- render_fb_inverse_ratio( NULL, inverse );
- inverse[2] = cam->farz-cam->nearz;
- shader_model_character_view_uInverseRatioMain( inverse );
-
- world_instance *world = get_active_world();
- world_link_lighting_ub( world, _shader_model_character_view.id );
- world_bind_position_texture( world, _shader_model_character_view.id,
- _uniform_model_character_view_g_world_depth, 2 );
- world_bind_light_array( world, _shader_model_character_view.id,
- _uniform_model_character_view_uLightsArray, 3 );
- world_bind_light_index( world, _shader_model_character_view.id,
- _uniform_model_character_view_uLightsIndex, 4 );
-
- glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
- player->playeravatar->sk.bone_count,
- 0,
- (float *)player->playeravatar->sk.final_mtx );
-
- mesh_bind( &player->playermodel->mesh );
- mesh_draw( &player->playermodel->mesh );
-
- /* draw skateboard */
- shader_model_board_view_use();
- glActiveTexture( GL_TEXTURE0 );
- glBindTexture( GL_TEXTURE_2D, player->playerboard->texture );
- shader_model_board_view_uTexMain( 0 );
- shader_model_board_view_uCamera( cam->transform[3] );
- shader_model_board_view_uPv( cam->mtx.pv );
- shader_model_board_view_uTexSceneDepth( 1 );
-
- render_fb_inverse_ratio( gpipeline.fb_main, inverse );
- inverse[2] = main_camera.farz-main_camera.nearz;
-
- shader_model_board_view_uInverseRatioDepth( inverse );
- render_fb_inverse_ratio( NULL, inverse );
- inverse[2] = cam->farz-cam->nearz;
- shader_model_board_view_uInverseRatioMain( inverse );
-
- world_link_lighting_ub( world, _shader_model_board_view.id );
- world_bind_position_texture( world, _shader_model_board_view.id,
- _uniform_model_board_view_g_world_depth, 2 );
- world_bind_light_array( world, _shader_model_board_view.id,
- _uniform_model_board_view_uLightsArray, 3 );
- world_bind_light_index( world, _shader_model_board_view.id,
- _uniform_model_board_view_uLightsIndex, 4 );
- m4x3f root;
- m4x3_copy( player->playeravatar->sk.final_mtx[player->playeravatar->id_board]
- , root );
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, board->texture );
+
+ if( shader == k_board_shader_player ){
+ shader_model_board_view_use();
+ shader_model_board_view_uTexMain( 0 );
+ shader_model_board_view_uCamera( cam->transform[3] );
+ shader_model_board_view_uPv( cam->mtx.pv );
+ shader_model_board_view_uTexSceneDepth( 1 );
+
+ render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+ inverse[2] = main_camera.farz-main_camera.nearz;
+
+ shader_model_board_view_uInverseRatioDepth( inverse );
+ render_fb_inverse_ratio( NULL, inverse );
+ inverse[2] = cam->farz-cam->nearz;
+ shader_model_board_view_uInverseRatioMain( inverse );
+
+ world_link_lighting_ub( world, _shader_model_board_view.id );
+ world_bind_position_texture( world, _shader_model_board_view.id,
+ _uniform_model_board_view_g_world_depth, 2 );
+ world_bind_light_array( world, _shader_model_board_view.id,
+ _uniform_model_board_view_uLightsArray, 3 );
+ world_bind_light_index( world, _shader_model_board_view.id,
+ _uniform_model_board_view_uLightsIndex, 4 );
+ }
+ else if( shader == k_board_shader_entity ){
+ shader_model_entity_use();
+ shader_model_entity_uTexMain( 0 );
+ shader_model_entity_uCamera( cam->transform[3] );
+ shader_model_entity_uPv( cam->mtx.pv );
+
+ world_link_lighting_ub( world, _shader_model_entity.id );
+ world_bind_position_texture( world, _shader_model_entity.id,
+ _uniform_model_entity_g_world_depth, 2 );
+ world_bind_light_array( world, _shader_model_entity.id,
+ _uniform_model_entity_uLightsArray, 3 );
+ world_bind_light_index( world, _shader_model_entity.id,
+ _uniform_model_entity_uLightsIndex, 4 );
+ }
- struct player_board *board = player->playerboard;
mesh_bind( &board->mesh );
+ m4x4f m4mdl;
+
if( board->board.indice_count ){
m4x3f mlocal;
m3x3_identity( mlocal );
v3_copy( board->board_position, mlocal[3] );
m4x3_mul( root, mlocal, mlocal );
- shader_model_board_view_uMdl( mlocal );
+ if( shader == k_board_shader_entity ){
+ /* TODO: provide a way to supply previous mdl mtx? */
+ m4x3_expand( mlocal, m4mdl );
+ m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+ shader_model_entity_uPvmPrev( m4mdl );
+ shader_model_entity_uMdl( mlocal );
+ }
+ else
+ shader_model_board_view_uMdl( mlocal );
+
mdl_draw_submesh( &board->board );
}
v3_copy( board->truck_positions[i], mlocal[3] );
m4x3_mul( root, mlocal, mlocal );
- shader_model_board_view_uMdl( mlocal );
+ if( shader == k_board_shader_entity ){
+ m4x3_expand( mlocal, m4mdl );
+ m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+ shader_model_entity_uPvmPrev( m4mdl );
+ shader_model_entity_uMdl( mlocal );
+ }
+ else
+ shader_model_board_view_uMdl( mlocal );
+
mdl_draw_submesh( &board->trucks[i] );
}
v3_copy( board->wheel_positions[i], mlocal[3] );
m4x3_mul( root, mlocal, mlocal );
- shader_model_board_view_uMdl( mlocal );
+ if( shader == k_board_shader_entity ){
+ m4x3_expand( mlocal, m4mdl );
+ m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+ shader_model_entity_uPvmPrev( m4mdl );
+ shader_model_entity_uMdl( mlocal );
+ }
+ else
+ shader_model_board_view_uMdl( mlocal );
+
mdl_draw_submesh( &board->wheels[i] );
}
}
+PLAYER_API void player__render( camera *cam, player_instance *player )
+{
+ shader_model_character_view_use();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, player->playermodel->texture );
+ shader_model_character_view_uTexMain( 0 );
+ shader_model_character_view_uCamera( cam->transform[3] );
+ shader_model_character_view_uPv( cam->mtx.pv );
+ shader_model_character_view_uTexSceneDepth( 1 );
+ render_fb_bind_texture( gpipeline.fb_main, 2, 1 );
+ v3f inverse;
+ render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+ inverse[2] = main_camera.farz-main_camera.nearz;
+
+ shader_model_character_view_uInverseRatioDepth( inverse );
+ render_fb_inverse_ratio( NULL, inverse );
+ inverse[2] = cam->farz-cam->nearz;
+ shader_model_character_view_uInverseRatioMain( inverse );
+
+ world_instance *world = get_active_world();
+ world_link_lighting_ub( world, _shader_model_character_view.id );
+ world_bind_position_texture( world, _shader_model_character_view.id,
+ _uniform_model_character_view_g_world_depth, 2 );
+ world_bind_light_array( world, _shader_model_character_view.id,
+ _uniform_model_character_view_uLightsArray, 3 );
+ world_bind_light_index( world, _shader_model_character_view.id,
+ _uniform_model_character_view_uLightsIndex, 4 );
+
+ glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
+ player->playeravatar->sk.bone_count,
+ 0,
+ (float *)player->playeravatar->sk.final_mtx );
+
+ mesh_bind( &player->playermodel->mesh );
+ mesh_draw( &player->playermodel->mesh );
+
+ struct player_board *board = player->board;
+
+ render_board( cam, world, board, player->playeravatar->sk.final_mtx[
+ player->playeravatar->id_board],
+ k_board_shader_player );
+}
+
#endif /* PLAYER_RENDER_C */
q_mul( kf_board->q, qtrick, kf_board->q );
q_normalize( kf_board->q );
- struct player_board *board = player->playerboard;
-
- /* foot weight distribution */
- if( s->blend_weight > 0.0f ){
- kf_foot_l->co[2] =
- vg_lerpf( kf_foot_l->co[2],
- board->truck_positions[k_board_truck_back][2]+0.3f,
- 0.5f*s->blend_weight );
- }
- else{
- kf_foot_r->co[2] =
- vg_lerpf( kf_foot_r->co[2],
- board->truck_positions[k_board_truck_front][2]-0.3f,
- -0.5f*s->blend_weight );
+ struct player_board *board = player->board;
+
+ if( board ){
+ /* foot weight distribution */
+ if( s->blend_weight > 0.0f ){
+ kf_foot_l->co[2] =
+ vg_lerpf( kf_foot_l->co[2],
+ board->truck_positions[k_board_truck_back][2]+0.3f,
+ 0.5f*s->blend_weight );
+ }
+ else{
+ kf_foot_r->co[2] =
+ vg_lerpf( kf_foot_r->co[2],
+ board->truck_positions[k_board_truck_front][2]-0.3f,
+ -0.5f*s->blend_weight );
+ }
}
float slapm = vg_maxf( 1.0f-v3_length2( s->state.trick_vel ), 0.0f );
{
struct player_walk *w = &player->_walk;
- if( w->state.activity != k_walk_activity_immobile )
+ if( !player->immobile )
player_look( player, player->angles );
if( w->state.outro_anim ){
return;
}
}
- else if( vg_input_button_down( player->input_use ) ){
+ else if( vg_input_button_down( player->input_use ) && !player->immobile ){
if( v3_dist2( player->rb.co, gzoomer.obj.rb.co ) <= 4.0f*4.0f ){
player->subsystem = k_player_subsystem_drive;
}
w->state.outro_type = k_walk_outro_drop_in;
w->state.outro_anim = w->anim_drop_in;
w->state.outro_start_time = vg.time;
- w->state.activity = k_walk_activity_immobile;
+ player->immobile = 1;
struct player_avatar *av = player->playeravatar;
m4x3_mulv( av->sk.final_mtx[ av->id_ik_foot_r ],
enum walk_activity prev_state = w->state.activity;
- if( w->state.activity == k_walk_activity_immobile )
+ if( player->immobile )
return;
w->collider.height = 2.0f;
(const char *[]){ "k_walk_activity_air",
"k_walk_activity_ground",
"k_walk_activity_sleep",
- "k_walk_activity_immobile",
"k_walk_activity_lockedmove" }
[w->state.activity] );
player__debugtext( 1, "surface: %s\n",
#define PLAYER_WALK_H
#include "player_api.h"
+#include "rigidbody.h"
struct player_walk{
rb_capsule collider;
k_walk_activity_air,
k_walk_activity_ground,
k_walk_activity_sleep,
- k_walk_activity_immobile,
k_walk_activity_lockedmove
}
activity;
--- /dev/null
+uniform sampler2D uTexMain;
+uniform vec3 uCamera;
+
+in vec4 aColour;
+in vec2 aUv;
+in vec3 aNorm;
+in vec3 aCo;
+in vec3 aWorldCo;
+
+#include "common_world.glsl"
+#include "motion_vectors_fs.glsl"
+
+void main()
+{
+ compute_motion_vectors();
+
+ vec3 qnorm = normalize(floor(aNorm*2.0)*0.5) + vec3(0.001,0.0,0.0);
+ vec3 diffuse = texture( uTexMain, aUv ).rgb;
+ vec3 composite = world_compute_lighting( diffuse, qnorm, aWorldCo, 1.0 );
+
+ oColour = vec4( composite, 1.0 );
+}
--- /dev/null
+#ifndef SHADER_model_entity_H
+#define SHADER_model_entity_H
+static void shader_model_entity_link(void);
+static void shader_model_entity_register(void);
+static struct vg_shader _shader_model_entity = {
+ .name = "model_entity",
+ .link = shader_model_entity_link,
+ .vs =
+{
+.orig_file = "shaders/model.vs",
+.static_src =
+"layout (location=0) in vec3 a_co;\n"
+"layout (location=1) in vec3 a_norm;\n"
+"layout (location=2) in vec2 a_uv;\n"
+"layout (location=3) in vec4 a_colour;\n"
+"layout (location=4) in vec4 a_weights;\n"
+"layout (location=5) in ivec4 a_groups;\n"
+"\n"
+"#line 1 1 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line 2 0 \n"
+"\n"
+"out vec3 aMotionVec0;\n"
+"out vec3 aMotionVec1;\n"
+"\n"
+"void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
+"{\n"
+" // This magically solves some artifacting errors!\n"
+" //\n"
+" vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
+"\n"
+" aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
+" aMotionVec1 = vec3( vproj1.xy, vproj1.w );\n"
+"}\n"
+"\n"
+"#line 9 0 \n"
+"\n"
+"uniform mat4x3 uMdl;\n"
+"uniform mat4 uPv;\n"
+"uniform mat4 uPvmPrev;\n"
+"\n"
+"out vec4 aColour;\n"
+"out vec2 aUv;\n"
+"out vec3 aNorm;\n"
+"out vec3 aCo;\n"
+"out vec3 aWorldCo;\n"
+"\n"
+"void main()\n"
+"{\n"
+" vec3 world_pos0 = uMdl * vec4( a_co, 1.0 );\n"
+" vec4 vproj0 = uPv * vec4( world_pos0, 1.0 );\n"
+" vec4 vproj1 = uPvmPrev * vec4( a_co, 1.0 );\n"
+"\n"
+" vs_motion_out( vproj0, vproj1 );\n"
+"\n"
+" gl_Position = vproj0;\n"
+" aWorldCo = world_pos0;\n"
+" aColour = a_colour;\n"
+" aUv = a_uv;\n"
+" aNorm = mat3(uMdl) * a_norm;\n"
+" aCo = a_co;\n"
+"}\n"
+""},
+ .fs =
+{
+.orig_file = "shaders/model_entity.fs",
+.static_src =
+"uniform sampler2D uTexMain;\n"
+"uniform vec3 uCamera;\n"
+"\n"
+"in vec4 aColour;\n"
+"in vec2 aUv;\n"
+"in vec3 aNorm;\n"
+"in vec3 aCo;\n"
+"in vec3 aWorldCo;\n"
+"\n"
+"#line 1 1 \n"
+"layout (location = 0) out vec4 oColour;\n"
+"\n"
+"// OpenGL wiki: Recommends do not use vec3 because of drivers. hence the v4s...\n"
+"layout (std140) uniform ub_world_lighting\n"
+"{\n"
+" vec4 g_cube_min;\n"
+" vec4 g_cube_inv_range;\n"
+"\n"
+" vec4 g_water_plane;\n"
+" vec4 g_depth_bounds;\n"
+"\n"
+" vec4 g_daysky_colour;\n"
+" vec4 g_nightsky_colour;\n"
+" vec4 g_sunset_colour;\n"
+" vec4 g_ambient_colour;\n"
+" vec4 g_sunset_ambient;\n"
+" vec4 g_sun_colour;\n"
+" vec4 g_sun_dir;\n"
+" vec4 g_board_0;\n"
+" vec4 g_board_1;\n"
+"\n"
+" float g_water_fog;\n"
+" float g_time;\n"
+" float g_realtime;\n"
+" float g_shadow_length;\n"
+" float g_shadow_spread;\n"
+"\n"
+" float g_time_of_day;\n"
+" float g_day_phase;\n"
+" float g_sunset_phase;\n"
+"\n"
+" int g_light_preview;\n"
+" int g_shadow_samples;\n"
+"\n"
+" int g_debug_indices;\n"
+" int g_debug_complexity;\n"
+"};\n"
+"\n"
+"uniform sampler2D g_world_depth;\n"
+"uniform samplerBuffer uLightsArray;\n"
+"uniform usampler3D uLightsIndex;\n"
+"\n"
+"#line 1 1 \n"
+"//const vec3 DAYSKY_COLOUR = vec3( 0.37, 0.54, 0.97 );\n"
+"//const vec3 NIGHTSKY_COLOUR = vec3( 0.03, 0.05, 0.20 );\n"
+"//const vec3 SUNSET_COLOUR = vec3( 1.00, 0.32, 0.01 );\n"
+"//const vec3 AMBIENT_COLOUR = vec3( 0.13, 0.17, 0.35 );\n"
+"//const vec3 SUNSET_AMBIENT = vec3( 0.25, 0.17, 0.51 );\n"
+"//const vec3 SUN_COLOUR = vec3( 1.10, 0.89, 0.35 );\n"
+"\n"
+"const float SUN_ANGLE = 0.0001;\n"
+"const float PI = 3.14159265;\n"
+"\n"
+"//struct world_info\n"
+"//{\n"
+"// float time,\n"
+"// time_of_day,\n"
+"// day_phase,\n"
+"// sunset_phase;\n"
+"// \n"
+"// vec3 sun_dir;\n"
+"//};\n"
+"\n"
+"float luminance( vec3 v )\n"
+"{\n"
+" return dot( v, vec3(0.2126, 0.7152, 0.0722) );\n"
+"}\n"
+"\n"
+"vec3 clearskies_ambient( vec3 dir )\n"
+"{\n"
+" float sun_azimuth = g_sunset_phase * (dot( dir.xz, g_sun_dir.xz )*0.4+0.6);\n"
+" float sky_gradient = dir.y;\n"
+" \n"
+" /* Blend phase colours */\n"
+" vec3 ambient = g_daysky_colour.rgb * (g_day_phase-g_sunset_phase*0.1);\n"
+" ambient += g_sunset_colour.rgb * (1.0-dir.y*0.5)*sun_azimuth;\n"
+" ambient += g_nightsky_colour.rgb * (1.0-g_day_phase);\n"
+" \n"
+" /* Add gradient */\n"
+" ambient -= sky_gradient * luminance(ambient);\n"
+" \n"
+" return ambient;\n"
+"}\n"
+"\n"
+"vec3 clearskies_sky( vec3 ray_dir )\n"
+"{\n"
+" ray_dir.y = abs( ray_dir.y );\n"
+" vec3 sky_colour = clearskies_ambient( ray_dir );\n"
+" \n"
+" /* Sun */\n"
+" float sun_theta = dot( ray_dir, g_sun_dir.xyz );\n"
+" float sun_size = max( 0.0, sun_theta * 0.5 + 0.5 + SUN_ANGLE );\n"
+" float sun_shape = pow( sun_size, 2000.0 );\n"
+" sun_shape += sun_size * max(g_sun_dir.y,0.0) * 0.5;\n"
+" \n"
+" vec3 sun_colour = mix( vec3(1.0), g_sunset_colour.rgb, g_sunset_phase*0.5 );\n"
+" sun_colour *= sun_shape;\n"
+" \n"
+" vec3 composite = sky_colour + sun_colour;\n"
+" return composite;\n"
+"}\n"
+"\n"
+"vec3 clearskies_lighting( vec3 normal, float shadow, vec3 halfview )\n"
+"{\n"
+" float fresnel = 1.0 - abs(dot(normal,halfview));\n"
+"\n"
+" vec3 reflect_colour = mix( g_daysky_colour.rgb, g_sunset_colour.rgb, \n"
+" g_sunset_phase );\n"
+"\n"
+" vec3 sky_reflection = 0.5 * fresnel * reflect_colour;\n"
+" vec3 light_sun = max(0.0,dot(normal,g_sun_dir.xyz)*0.75+0.25) \n"
+" * g_sun_colour.rgb * g_day_phase;\n"
+"\n"
+" float scaled_shadow = max( shadow, 1.0 - max(g_sun_dir.y,0.0) );\n"
+" vec3 ambient = mix( g_ambient_colour.rgb, g_sunset_ambient.rgb, \n"
+" g_sunset_phase );\n"
+"\n"
+" return ambient + (light_sun + sky_reflection) * shadow;\n"
+"}\n"
+"\n"
+"#line 44 0 \n"
+"\n"
+"float world_depth_sample( vec3 pos )\n"
+"{\n"
+" vec2 depth_coord = (pos.xz - g_depth_bounds.xy) * g_depth_bounds.zw; \n"
+" return texture( g_world_depth, depth_coord ).r;\n"
+"}\n"
+"\n"
+"float world_water_depth( vec3 pos )\n"
+"{\n"
+" float ref_depth = g_water_plane.y*g_water_plane.w;\n"
+" return world_depth_sample( pos ) - ref_depth;\n"
+"}\n"
+"\n"
+"float shadow_sample( vec3 vdir )\n"
+"{\n"
+" vec3 sample_pos = aWorldCo + vdir;\n"
+" float height_sample = world_depth_sample( sample_pos );\n"
+"\n"
+" float fdelta = height_sample - sample_pos.y;\n"
+" return clamp( fdelta, 0.2, 0.4 )-0.2;\n"
+"}\n"
+"\n"
+"float newlight_compute_sun_shadow( vec3 dir )\n"
+"{\n"
+" if( g_shadow_samples == 0 )\n"
+" {\n"
+" return 1.0;\n"
+" }\n"
+"\n"
+" float fspread = g_shadow_spread;\n"
+" float flength = g_shadow_length;\n"
+"\n"
+" float famt = 0.0;\n"
+" famt += shadow_sample((dir+vec3(-0.56,0.55, 0.30)*fspread)*flength*0.1);\n"
+" famt += shadow_sample((dir+vec3( 0.80,0.68, 0.34)*fspread)*flength*0.2);\n"
+" famt += shadow_sample((dir+vec3( 0.78,0.07,-0.06)*fspread)*flength*0.3);\n"
+" famt += shadow_sample((dir+vec3(-0.59,0.07,-0.42)*fspread)*flength*0.4);\n"
+"\n"
+" //famt+=shadow_sample((dir+vec3(-0.790,-0.933,-0.875)*fspread)*flength*0.5);\n"
+" //famt+=shadow_sample((dir+vec3( 0.807,-0.690, 0.472)*fspread)*flength*0.6);\n"
+" //famt+=shadow_sample((dir+vec3( 0.522,-0.379, 0.350)*fspread)*flength*0.7);\n"
+" //famt+=shadow_sample((dir+vec3( 0.483, 0.201, 0.306)*fspread)*flength*0.8);\n"
+"\n"
+" return 1.0 - famt;\n"
+"}\n"
+"\n"
+"float newlight_specular( vec3 wnormal, vec3 dir, vec3 halfview, float exponent )\n"
+"{\n"
+" vec3 specdir = reflect( -dir, wnormal );\n"
+" return pow(max(dot( halfview, specdir ), 0.0), exponent);\n"
+"}\n"
+"\n"
+"vec3 scene_apply_fog( vec3 vfrag, vec3 colour, float fdist )\n"
+"{\n"
+" float dist = pow(fdist*0.0010,0.78);\n"
+" return mix( vfrag, colour, min( 1.0, dist ) );\n"
+"}\n"
+"\n"
+"vec3 rand33(vec3 p3)\n"
+"{\n"
+" p3 = fract(p3 * vec3(.1031, .1030, .0973));\n"
+" p3 += dot(p3, p3.yxz+33.33);\n"
+" return fract((p3.xxy + p3.yxx)*p3.zyx);\n"
+"}\n"
+"\n"
+"vec3 scene_calculate_light( int light_index, \n"
+" vec3 halfview, vec3 co, vec3 normal )\n"
+"{\n"
+" vec4 light_colour = texelFetch( uLightsArray, light_index+0 );\n"
+" vec4 light_co = texelFetch( uLightsArray, light_index+1 );\n"
+" vec4 light_dir = texelFetch( uLightsArray, light_index+2 );\n"
+"\n"
+" vec3 light_delta = light_co.xyz-co;\n"
+" float dist2 = dot(light_delta,light_delta);\n"
+"\n"
+" light_delta = normalize( light_delta );\n"
+"\n"
+" float quadratic = dist2*100.0;\n"
+" float attenuation = 1.0f/( 1.0f + quadratic );\n"
+" attenuation *= max( dot( light_delta, normal ), 0.0 );\n"
+"\n"
+" float falloff = max( 0.0, 1.0-(dist2*light_co.w) );\n"
+"\n"
+" if( light_dir.w < 0.999999 ){\n"
+" float spot_theta = max( 0.0, dot( light_delta, -light_dir.xyz ) );\n"
+" falloff *= max( 0.0, (spot_theta - light_dir.w) / (1.0-light_dir.w) );\n"
+" }\n"
+"\n"
+" return light_colour.rgb * attenuation * falloff \n"
+" * step( g_day_phase, light_colour.w );\n"
+"}\n"
+"\n"
+"vec3 scene_calculate_packed_light_patch( uint packed_index, \n"
+" vec3 halfview, vec3 co, vec3 normal )\n"
+"{\n"
+" uint light_count = packed_index & 0x3u;\n"
+"\n"
+" vec3 l = vec3(0.0);\n"
+"\n"
+" if( light_count >= 1u ){\n"
+" int index_0 = int( ((packed_index >> 2u) & 0x3ffu) * 3u );\n"
+" int index_1 = int( ((packed_index >> 12u) & 0x3ffu) * 3u );\n"
+" int index_2 = int( ((packed_index >> 22u) & 0x3ffu) * 3u );\n"
+"\n"
+" l += scene_calculate_light( index_0, halfview, co, normal );\n"
+"\n"
+" if( light_count >= 2u ){\n"
+" l += scene_calculate_light( index_1, halfview, co, normal );\n"
+"\n"
+" if( light_count >= 3u ){\n"
+" l += scene_calculate_light( index_2, halfview, co, normal );\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+" return l;\n"
+"}\n"
+"\n"
+"vec3 world_compute_lighting( vec3 diffuse, vec3 normal, vec3 co,\n"
+" float light_mask )\n"
+"{\n"
+" if( g_light_preview == 1 )\n"
+" diffuse = vec3(0.75);\n"
+"\n"
+" // Lighting\n"
+" vec3 halfview = uCamera - co;\n"
+" float fdist = length(halfview);\n"
+" halfview /= fdist;\n"
+"\n"
+" float world_shadow = newlight_compute_sun_shadow( g_sun_dir.xyz \n"
+" * (1.0/(max(g_sun_dir.y,0.0)+0.2)) );\n"
+"\n"
+" vec3 total_light = clearskies_lighting( \n"
+" normal, min( light_mask, world_shadow ), halfview );\n"
+"\n"
+" vec3 cube_coord = (co - g_cube_min.xyz) * g_cube_inv_range.xyz;\n"
+" cube_coord = floor( cube_coord );\n"
+"\n"
+" if( g_debug_indices == 1 )\n"
+" {\n"
+" return rand33(cube_coord);\n"
+" }\n"
+"\n"
+" if( g_debug_complexity == 1 )\n"
+" {\n"
+" ivec3 coord = ivec3( cube_coord );\n"
+" uvec4 index_sample = texelFetch( uLightsIndex, coord, 0 );\n"
+"\n"
+" uint light_count = (index_sample.x & 0x3u) + (index_sample.y & 0x3u);\n"
+" return vec3( float(light_count)*(1.0/6.0), 0.0, 0.5 );\n"
+" }\n"
+"\n"
+" // FIXME: this coord should absolutely must be clamped!\n"
+" \n"
+" ivec3 coord = ivec3( cube_coord );\n"
+" uvec4 index_sample = texelFetch( uLightsIndex, coord, 0 );\n"
+"\n"
+" total_light += \n"
+" scene_calculate_packed_light_patch( index_sample.x,\n"
+" halfview, co, normal ) \n"
+" * light_mask;\n"
+" total_light += \n"
+" scene_calculate_packed_light_patch( index_sample.y,\n"
+" halfview, co, normal )\n"
+" * light_mask;\n"
+"\n"
+" // Take a section of the sky function to give us a matching fog colour\n"
+"\n"
+" vec3 fog_colour = clearskies_ambient( -halfview );\n"
+" float sun_theta = dot( -halfview, g_sun_dir.xyz );\n"
+" float sun_size = max( 0.0, sun_theta * 0.5 + 0.5 );\n"
+" float sun_shape = sun_size * max(g_sun_dir.y,0.0) * 0.5;\n"
+" \n"
+" vec3 sun_colour = mix( vec3(1.0), g_sunset_colour.rgb, g_sunset_phase*0.5 );\n"
+" sun_colour *= sun_shape;\n"
+"\n"
+" fog_colour += sun_colour;\n"
+" return scene_apply_fog( diffuse * total_light, fog_colour, fdist );\n"
+"}\n"
+"\n"
+"#line 11 0 \n"
+"#line 1 2 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line 2 0 \n"
+"\n"
+"layout (location = 1) out vec2 oMotionVec;\n"
+"\n"
+"in vec3 aMotionVec0;\n"
+"in vec3 aMotionVec1;\n"
+"\n"
+"void compute_motion_vectors()\n"
+"{\n"
+" // Write motion vectors\n"
+" vec2 vmotion0 = aMotionVec0.xy / aMotionVec0.z;\n"
+" vec2 vmotion1 = aMotionVec1.xy / aMotionVec1.z;\n"
+"\n"
+" oMotionVec = (vmotion1-vmotion0) * (1.0/k_motion_lerp_amount);\n"
+"}\n"
+"\n"
+"#line 12 0 \n"
+"\n"
+"void main()\n"
+"{\n"
+" compute_motion_vectors();\n"
+"\n"
+" vec3 qnorm = normalize(floor(aNorm*2.0)*0.5) + vec3(0.001,0.0,0.0);\n"
+" vec3 diffuse = texture( uTexMain, aUv ).rgb;\n"
+" vec3 composite = world_compute_lighting( diffuse, qnorm, aWorldCo, 1.0 );\n"
+"\n"
+" oColour = vec4( composite, 1.0 );\n"
+"}\n"
+""},
+};
+
+static GLuint _uniform_model_entity_uMdl;
+static GLuint _uniform_model_entity_uPv;
+static GLuint _uniform_model_entity_uPvmPrev;
+static GLuint _uniform_model_entity_uTexMain;
+static GLuint _uniform_model_entity_uCamera;
+static GLuint _uniform_model_entity_g_world_depth;
+static GLuint _uniform_model_entity_uLightsArray;
+static GLuint _uniform_model_entity_uLightsIndex;
+static void shader_model_entity_uMdl(m4x3f m){
+ glUniformMatrix4x3fv(_uniform_model_entity_uMdl,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uPv(m4x4f m){
+ glUniformMatrix4fv(_uniform_model_entity_uPv,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uPvmPrev(m4x4f m){
+ glUniformMatrix4fv(_uniform_model_entity_uPvmPrev,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uTexMain(int i){
+ glUniform1i(_uniform_model_entity_uTexMain,i);
+}
+static void shader_model_entity_uCamera(v3f v){
+ glUniform3fv(_uniform_model_entity_uCamera,1,v);
+}
+static void shader_model_entity_g_world_depth(int i){
+ glUniform1i(_uniform_model_entity_g_world_depth,i);
+}
+static void shader_model_entity_register(void){
+ vg_shader_register( &_shader_model_entity );
+}
+static void shader_model_entity_use(void){ glUseProgram(_shader_model_entity.id); }
+static void shader_model_entity_link(void){
+ _uniform_model_entity_uMdl = glGetUniformLocation( _shader_model_entity.id, "uMdl" );
+ _uniform_model_entity_uPv = glGetUniformLocation( _shader_model_entity.id, "uPv" );
+ _uniform_model_entity_uPvmPrev = glGetUniformLocation( _shader_model_entity.id, "uPvmPrev" );
+ _uniform_model_entity_uTexMain = glGetUniformLocation( _shader_model_entity.id, "uTexMain" );
+ _uniform_model_entity_uCamera = glGetUniformLocation( _shader_model_entity.id, "uCamera" );
+ _uniform_model_entity_g_world_depth = glGetUniformLocation( _shader_model_entity.id, "g_world_depth" );
+ _uniform_model_entity_uLightsArray = glGetUniformLocation( _shader_model_entity.id, "uLightsArray" );
+ _uniform_model_entity_uLightsIndex = glGetUniformLocation( _shader_model_entity.id, "uLightsIndex" );
+}
+#endif /* SHADER_model_entity_H */
#include "font.h"
#include "player.h"
+#include "entity.c"
+
VG_STATIC struct player_avatar localplayer_avatar;
VG_STATIC struct player_model localplayer_models[3];
-VG_STATIC struct player_board localplayer_boards[1];
VG_STATIC int skaterift_status = 0;
#include "network.h"
player_model_load( &localplayer_models[1], "models/ch_outlaw.mdl" );
player_model_load( &localplayer_models[2], "models/ch_jordan.mdl" );
- player_board_load( &localplayer_boards[0], "models/board_fish.mdl" );
+ /* load default board */
+#if 0
+ player_board_load( &localplayer_boards[0],
+ "models/boards/skaterift_fish.mdl" );
+#endif
/* FIXME: hack */
shader_model_character_view_register();
shader_model_board_view_register();
+ shader_model_entity_register();
}
void temp_update_playermodel(void){
vg_loader_step( player_init, NULL );
vg_loader_step( player_ragdoll_init, NULL );
+ vg_loader_step( skateshop_init, NULL );
/* ----------------- */
vg_loader_step( load_playermodels, NULL );
player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" );
player__use_avatar( &localplayer, &localplayer_avatar );
player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] );
- player__use_board( &localplayer, &localplayer_boards[0] );
+ //localplayer.board = &localplayer_boards[0];
player__bind( &localplayer );
/* --------------------- */
network_update();
player__pre_update( &localplayer );
+ global_skateshop_preupdate();
world_update( get_active_world(), localplayer.rb.co );
audio_ambient_sprites_update( get_active_world(), localplayer.rb.co );
main_camera.fov = vg_lerpf( localplayer.cam.fov, menu_smooth_fov,
menu_opacity );
+
+ main_camera.fov = vg_lerpf( main_camera.fov, 90.0f,
+ global_skateshop.factive );
main_camera.nearz = 0.1f;
main_camera.farz = 2100.0f;
ent_audio_clip,
ent_audio,
ent_volume,
- ent_traffic;
+ ent_traffic,
+ ent_skateshop,
+ ent_marker;
ent_gate *rendering_gate;
VG_MEMORY_SYSTEM );
}
-typedef struct ent_call ent_call;
-struct ent_call{
- ent_index ent;
- u32 function;
- void *data;
-};
-
-VG_STATIC void entity_call( world_instance *world, ent_call *call );
-
VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
{
- ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index );
- if( !volume->target.type ) return;
+ u32 index = mdl_entity_id_id( call->id );
+ ent_volume *volume = mdl_arritm( &world->ent_volume, index );
+ if( !volume->target ) return;
if( call->function == k_ent_function_trigger ){
- call->ent = volume->target;
+ call->id = volume->target;
if( volume->type == k_volume_subtype_particle ){
float *co = alloca( sizeof(float)*3 );
call->data = co;
entity_call( world, call );
}
- else
+ else{
entity_call( world, call );
+ }
}
}
VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
{
- ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index );
+ u32 index = mdl_entity_id_id( call->id );
+ ent_audio *audio = mdl_arritm( &world->ent_audio, index );
v3f sound_co;
}
}
-VG_STATIC void entity_call( world_instance *world, ent_call *call )
-{
- if( call->ent.type == k_ent_volume ){
- ent_volume_call( world, call );
- } else if( call->ent.type == k_ent_audio ){
- ent_audio_call( world, call );
- }
-}
-
VG_STATIC void world_update( world_instance *world, v3f pos )
{
world_global.sky_time += world_global.sky_rate * vg.time_delta;
if( !world_global.in_volume ){
ent_call basecall;
- basecall.ent.index = idx;
- basecall.ent.type = k_ent_volume;
basecall.function = k_ent_function_trigger;
+ basecall.id = mdl_entity_id( k_ent_volume, idx );
basecall.data = NULL;
entity_call( world, &basecall );
for( int j=0; j<random_ticks; j++ ){
ent_call basecall;
- basecall.ent.index = idx;
- basecall.ent.type = k_ent_volume;
- basecall.function = k_ent_function_trigger;
+ basecall.id = mdl_entity_id( k_ent_volume, idx );
basecall.data = NULL;
entity_call( world, &basecall );
mdl_load_array( meta, &world->ent_audio, "ent_audio", heap );
mdl_load_array( meta, &world->ent_volume, "ent_volume", heap );
mdl_load_array( meta, &world->ent_traffic, "ent_traffic", heap );
+ mdl_load_array( meta, &world->ent_marker, "ent_marker", heap );
+ mdl_load_array( meta, &world->ent_skateshop, "ent_skateshop", heap );
/* process resources from pack */
world_process_resources( world );
+++ /dev/null
-#include "common.h"
-
-#ifndef WORLD_LOGIC_BRICKS_H
-#define WORLD_LOGIC_BRICKS_H
-
-#include "world.h"
-
-#if 0
-
-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 pos )
-{
- 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;
-
- if( v3_dist2( node->co, pos ) > 50.0f*50.0f )
- continue;
-
- 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) ||
- (pnext->classtype == k_classtype_logic_chances) ||
- (pnext->classtype == k_classtype_signal_splitter) )
- {
- 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
-
-
-
-
-
-#endif /* WORLD_LOGIC_BRICKS_H */
sizeof(struct ub_world_lighting), &world->ub_lighting );
}
+VG_STATIC void skateshop_render(void);
VG_STATIC void render_world( world_instance *world, camera *cam,
int layer_depth )
{
render_world_alphatest( world, cam );
render_terrain( world, cam );
- /* Render SFD's */
- u32 closest = 0;
- float min_dist = INFINITY;
+ if( layer_depth == 0 ){
+ skateshop_render();
- if( !mdl_arrcount( &world->ent_route ) )
- return;
+ /* Render SFD's */
+ u32 closest = 0;
+ float min_dist = INFINITY;
- for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
- ent_route *route = mdl_arritm( &world->ent_route, i );
- float dist = v3_dist2( route->board_transform[3], cam->pos );
+ if( !mdl_arrcount( &world->ent_route ) )
+ return;
- if( dist < min_dist ){
- min_dist = dist;
- closest = i;
+ for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
+ ent_route *route = mdl_arritm( &world->ent_route, i );
+ float dist = v3_dist2( route->board_transform[3], cam->pos );
+
+ if( dist < min_dist ){
+ min_dist = dist;
+ closest = i;
+ }
}
- }
- ent_route *route = mdl_arritm( &world->ent_route, closest );
- sfd_render( world, cam, route->board_transform );
+ ent_route *route = mdl_arritm( &world->ent_route, closest );
+ sfd_render( world, cam, route->board_transform );
+ }
}
VG_STATIC void render_world_depth( world_instance *world, camera *cam )