audio_clip audio_board[] =
{
- {.path="sound/skate.ogg", .source_mode=k_audio_source_compressed },
- {.path="sound/wheel.ogg", .source_mode=k_audio_source_compressed },
- {.path="sound/slide.ogg", .source_mode=k_audio_source_compressed },
- {.path="sound/reverb.ogg",.source_mode=k_audio_source_compressed }
+ { .path="sound/skate.ogg" },
+ { .path="sound/wheel.ogg" },
+ { .path="sound/slide.ogg" },
+ { .path="sound/reverb.ogg" }
};
audio_clip audio_splash =
-{ .path = "sound/splash.ogg", .source_mode=k_audio_source_compressed };
+{ .path = "sound/splash.ogg" };
audio_clip audio_jumps[] = {
- { .path = "sound/jump0.ogg", .source_mode=k_audio_source_compressed, },
- { .path = "sound/jump1.ogg", .source_mode=k_audio_source_compressed, },
+ { .path = "sound/jump0.ogg" },
+ { .path = "sound/jump1.ogg" },
};
audio_clip audio_footsteps[] = {
- {.path = "sound/step_concrete0.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete1.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete2.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete3.ogg", .source_mode=k_audio_source_compressed,}
+ {.path = "sound/step_concrete0.ogg" },
+ {.path = "sound/step_concrete1.ogg" },
+ {.path = "sound/step_concrete2.ogg" },
+ {.path = "sound/step_concrete3.ogg" }
};
audio_clip audio_lands[] = {
- { .path = "sound/land0.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/land1.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/land2.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/landsk0.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/landsk1.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/onto.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/outo.ogg", .source_mode=k_audio_source_compressed },
+ { .path = "sound/land0.ogg" },
+ { .path = "sound/land1.ogg" },
+ { .path = "sound/land2.ogg" },
+ { .path = "sound/landsk0.ogg" },
+ { .path = "sound/landsk1.ogg" },
+ { .path = "sound/onto.ogg" },
+ { .path = "sound/outo.ogg" },
};
audio_clip audio_water[] = {
- { .path = "sound/wave0.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/wave1.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/wave2.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/wave3.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/wave4.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/wave5.ogg", .source_mode=k_audio_source_compressed }
+ { .path = "sound/wave0.ogg" },
+ { .path = "sound/wave1.ogg" },
+ { .path = "sound/wave2.ogg" },
+ { .path = "sound/wave3.ogg" },
+ { .path = "sound/wave4.ogg" },
+ { .path = "sound/wave5.ogg" }
};
audio_clip audio_grass[] = {
- { .path = "sound/grass0.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/grass1.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/grass2.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/grass3.ogg", .source_mode=k_audio_source_compressed },
+ { .path = "sound/grass0.ogg" },
+ { .path = "sound/grass1.ogg" },
+ { .path = "sound/grass2.ogg" },
+ { .path = "sound/grass3.ogg" },
};
audio_clip audio_ambience[] =
{
- {.path="sound/town_generic.ogg",
- .source_mode=k_audio_source_compressed }
+ { .path="sound/town_generic.ogg" }
};
audio_clip audio_gate_pass = {
- .path = "sound/gate_pass.ogg", .source_mode=k_audio_source_compressed
+ .path = "sound/gate_pass.ogg"
};
audio_clip audio_gate_lap = {
- .path = "sound/gate_lap.ogg", .source_mode=k_audio_source_compressed
+ .path = "sound/gate_lap.ogg"
};
audio_clip audio_gate_ambient = {
-.path = "sound/gate_ambient.ogg", .source_mode=k_audio_source_compressed
+.path = "sound/gate_ambient.ogg"
};
audio_player ambient_player =
};
audio_clip audio_rewind[] = {
-{ .path = "sound/rewind_start.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_end_1.5.ogg", .source_mode=k_audio_source_compressed},
-{ .path = "sound/rewind_end_2.5.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_end_6.5.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_clack.ogg", .source_mode=k_audio_source_compressed },
+{ .path = "sound/rewind_start.ogg" },
+{ .path = "sound/rewind_end_1.5.ogg" },
+{ .path = "sound/rewind_end_2.5.ogg" },
+{ .path = "sound/rewind_end_6.5.ogg" },
+{ .path = "sound/rewind_clack.ogg" },
};
audio_clip audio_ui[] = {
- { .path = "sound/ui_click.ogg", .source_mode=k_audio_source_compressed },
- { .path = "sound/ui_ding.ogg", .source_mode=k_audio_source_compressed },
+ { .path = "sound/ui_click.ogg" },
+ { .path = "sound/ui_ding.ogg" },
};
audio_player ambient_sprites[4] =
char buf[64];
snprintf( buf, 31, "occlusion: %.5f", audio_occlusion_current );
- ui_global_ctx.cursor[0] = 450;
- ui_global_ctx.cursor[1] = 10;
- ui_global_ctx.cursor[2] = audio_occlusion_current * 200.0f;
- ui_global_ctx.cursor[3] = 20;
+ vg_uictx.cursor[0] = 450;
+ vg_uictx.cursor[1] = 10;
+ vg_uictx.cursor[2] = audio_occlusion_current * 200.0f;
+ vg_uictx.cursor[3] = 20;
- gui_fill_rect( ui_global_ctx.cursor, 0x55cccccc );
- gui_text( ui_global_ctx.cursor, buf, 1, 0 );
+ ui_fill_rect( vg_uictx.cursor, 0x55cccccc );
+ ui_text( vg_uictx.cursor, buf, 1, 0 );
}
#endif /* AUDIO_H */
_fields_ = [("co",c_float*3),
( "q",c_float*4),
( "s",c_float*3),
+ ("sub_uid",c_uint32), # dont use
("submesh_start",c_uint32),
("submesh_count",c_uint32),
("classtype",c_uint32),
_fields_ = [("identifier",c_uint32),
("version",c_uint32),
("file_length",c_uint32),
+ ("pad0",c_uint32),
+
("vertex_count",c_uint32),
("vertex_offset",c_uint32),
("anim_count",c_uint32),
("anim_offset",c_uint32),
-
+
+ ("strings_length",c_uint32),
("strings_offset",c_uint32),
+
+ ("entdata_length",c_uint32),
("entdata_offset",c_uint32),
- ("animdata_offset",c_uint32)
- ]
+
+ ("keyframe_count",c_uint32),
+ ("keyframe_offset",c_uint32)]
+
class mdl_animation(Structure):
_pack_ = 1
header.node_count = 0
header.material_count = 0
header.file_length = 0
+
+ header.strings_length = 0
+ header.entdata_length = 0
+ header.keyframe_count = 0
mesh_cache = {}
string_cache = {}
indice_buffer = []
node_buffer = []
entdata_buffer = []
- entdata_length = 0
anim_buffer = []
- animdata_length = 0
animdata_buffer = []
def emplace_string( s ):
# Process entity data
# ==================================================================
- node.offset = entdata_length
+ node.offset = header.entdata_length
if classtype != 'k_classtype_none':
disptype = classtype
node.classtype = 12
armature = armature_def['obj']
- entdata_length += sizeof( classtype_skin )
+ header.entdata_length += sizeof( classtype_skin )
skin = classtype_skin()
skin.skeleton = armature.cv_data.uid
elif classtype == 'k_classtype_skeleton':
node.classtype = 11
- entdata_length += sizeof( classtype_skeleton )
+ header.entdata_length += sizeof( classtype_skeleton )
skeleton = classtype_skeleton()
armature_def = graph_lookup[obj]
anim = mdl_animation()
anim.pstr_name = emplace_string( NLAStrip.action.name )
anim.rate = 30.0
- anim.offset = animdata_length
+ anim.offset = header.keyframe_count
anim.length = anim_end-anim_start
# Export the fucking keyframes
kf.s[2] = sca[1]
animdata_buffer += [kf]
- animdata_length += sizeof(mdl_keyframe)
+ header.keyframe_count += 1
break
anim_buffer += [anim]
elif classtype == 'k_classtype_bone':
node.classtype = 10
- entdata_length += sizeof( classtype_bone )
+ header.entdata_length += sizeof( classtype_bone )
bone = classtype_bone()
bone.deform = node_def['deform']
elif classtype == 'k_classtype_gate':
node.classtype = 1
- entdata_length += sizeof( classtype_gate )
+ header.entdata_length += sizeof( classtype_gate )
gate = classtype_gate()
gate.target = 0
elif classtype == 'k_classtype_block':
node.classtype = 2
- entdata_length += sizeof( classtype_block )
+ header.entdata_length += sizeof( classtype_block )
source = obj.data.cv_data
elif classtype == 'k_classtype_achievement_box':
node.classtype = 13
- entdata_length += sizeof( classtype_achievement_box )
+ header.entdata_length += sizeof( classtype_achievement_box )
ach = classtype_achievement_box()
ach.pstr_name = emplace_string( obj.cv_data.strp )
ach.trigger = 0
elif classtype == 'k_classtype_audio':
node.classtype = 14
- entdata_length += sizeof( classtype_audio )
+ header.entdata_length += sizeof( classtype_audio )
aud = classtype_audio()
aud.pstr_file = emplace_string( obj.cv_data.strp )
aud.flags = obj.cv_data.intp
elif classtype == 'k_classtype_car_path':
node.classtype = 5
- entdata_length += sizeof( classtype_car_path )
+ header.entdata_length += sizeof( classtype_car_path )
pn = classtype_car_path()
pn.target = 0
target = obj.instance_collection
node.classtype = 6
- entdata_length += sizeof( classtype_instance )
+ header.entdata_length += sizeof( classtype_instance )
inst = classtype_instance()
inst.pstr_file = emplace_string( F"models/{target.name}.mdl" )
elif classtype == 'k_classtype_route_node':
node.classtype = 8
- entdata_length += sizeof( classtype_route_node )
+ header.entdata_length += sizeof( classtype_route_node )
rn = classtype_route_node()
if obj.cv_data.target != None:
elif classtype == 'k_classtype_route':
node.classtype = 9
- entdata_length += sizeof( classtype_route )
+ header.entdata_length += sizeof( classtype_route )
r = classtype_route()
r.colour[0] = obj.cv_data.colour[0]
r.colour[1] = obj.cv_data.colour[1]
node_buffer += [node]
# Write data arrays
- #
- header.anim_count = len(anim_buffer)
+ # TODO: 8 BYTE ALIGNMENT
print( "Writing data" )
fpos = sizeof(header)
header.material_offset = fpos
fpos += sizeof(mdl_material)*header.material_count
- print( F"Animation count: {header.anim_count}" )
+ print( F"Animation count: {len(anim_buffer)}" )
+ header.anim_count = len(anim_buffer)
header.anim_offset = fpos
fpos += sizeof(mdl_animation)*header.anim_count
- print( F"Entdata length: {entdata_length}" )
+ print( F"Entdata length: {header.entdata_length}" )
header.entdata_offset = fpos
- fpos += entdata_length
+ fpos += header.entdata_length
+
+ print( F"Strings length: {len(strings_buffer)}" )
+ header.strings_offset = fpos
+ header.strings_length = len(strings_buffer)
+ fpos += header.strings_length
+
+ # Optional array things
+ print( F"Keyframe count: {header.keyframe_count}" )
+ header.keyframe_offset = fpos
+ fpos += sizeof(mdl_keyframe)*header.keyframe_count
print( F"Vertex count: {header.vertex_count}" )
header.vertex_offset = fpos
header.indice_offset = fpos
fpos += sizeof(c_uint32)*header.indice_count
- print( F"Keyframe count: {animdata_length}" )
- header.animdata_offset = fpos
- fpos += animdata_length
-
- print( F"Strings length: {len(strings_buffer)}" )
- header.strings_offset = fpos
- fpos += len(strings_buffer)
-
header.file_length = fpos
path = F"/home/harry/Documents/carve/models_src/{collection_name}.mdl"
fp.write( bytearray(a) )
for ed in entdata_buffer:
fp.write( bytearray(ed) )
+
+ fp.write( strings_buffer )
+
+ for kf in animdata_buffer:
+ fp.write( bytearray(kf) )
+
for v in vertex_buffer:
fp.write( bytearray(v) )
for i in indice_buffer:
fp.write( bytearray(i) )
- for kf in animdata_buffer:
- fp.write( bytearray(kf) )
- fp.write( strings_buffer )
fp.close()
print( F"Completed {collection_name}.mdl" )
_windows_linksteam="vg/dep/steam/steam_api.dll"
_windows_folder="bin/win32"
-_options_debugmode="-O0 -ggdb3 -fno-omit-frame-pointer"
+_options_debugmode="-O0 -ggdb3 -fno-omit-frame-pointer -rdynamic"
_options_release="-O3 -DVG_RELEASE"
# Compiler lines
test)
run_game
;;
+ gdb)
+ cd $_linux_folder
+ gdb -tui ./skaterift
+ cd ./../
+ ;;
testserver)
run_server
;;
* system: the system we created above which will deal with the data
*
* call bh_create( bh_tree *bh, u32 item_count )
- * static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
- * static int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
+ * VG_STATIC int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
+ * VG_STATIC int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
*/
typedef struct bh_node bh_node;
typedef struct bh_tree bh_tree;
typedef struct bh_system bh_system;
-struct bh_node
-{
- boxf bbx;
-
- /* if il is 0, this is a leaf */
- u32 il, count;
- union{ u32 ir, start; };
-};
-
struct bh_tree
{
- bh_node *nodes;
u32 node_count;
bh_system *system;
void *user;
+
+ struct bh_node
+ {
+ boxf bbx;
+
+ /* if il is 0, this is a leaf */
+ u32 il, count;
+ union{ u32 ir, start; };
+ }
+ nodes[];
};
struct bh_system
int (*cast_ray)( void *user, u32 index, v3f co, v3f dir, ray_hit *hit );
};
-static void bh_update_bounds( bh_tree *bh, u32 inode )
+VG_STATIC void bh_update_bounds( bh_tree *bh, u32 inode )
{
bh_node *node = &bh->nodes[ inode ];
}
}
-static void bh_subdivide( bh_tree *bh, u32 inode )
+VG_STATIC void bh_subdivide( bh_tree *bh, u32 inode )
{
bh_node *node = &bh->nodes[ inode ];
node->ir = ir;
node->count = 0;
- /* TODO: Implement max depth, or stack */
bh_update_bounds( bh, il );
bh_update_bounds( bh, ir );
bh_subdivide( bh, il );
bh_subdivide( bh, ir );
}
-static void bh_create( bh_tree *bh, bh_system *sys, void *user, u32 item_count )
+VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system,
+ void *user, u32 item_count )
{
- bh->system = sys;
+ u32 totsize = sizeof(bh_tree) + sizeof(bh_node)*(item_count*2-1);
+ bh_tree *bh = vg_linear_alloc( lin_alloc, totsize );
+ bh->system = system;
bh->user = user;
- bh->nodes = vg_alloc( sizeof(bh_node) * (item_count*2-1) );
bh_node *root = &bh->nodes[0];
bh->node_count = 1;
bh_update_bounds( bh, 0 );
bh_subdivide( bh, 0 );
- bh->nodes = vg_realloc( bh->nodes, sizeof(bh_node) * bh->node_count );
- vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) );
-
-#if 0
- vg_fatal_exit_loop( "Test crash from loader" );
-#endif
-}
+ totsize = sizeof(bh_tree) + sizeof(bh_node) * bh->node_count;
+ bh = vg_linear_resize( lin_alloc, bh, totsize );
-static void bh_free( bh_tree *bh )
-{
- vg_free( bh->nodes );
+ vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) );
+ return bh;
}
-static void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
+VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
{
bh_node *node = &bh->nodes[ inode ];
}
}
-static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit )
{
int count = 0;
u32 stack[100];
return count;
}
-static int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
+VG_STATIC int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
{
int count = 0;
u32 stack[100];
#include "common.h"
-static v2f camera_angles;
-static v3f camera_pos;
+VG_STATIC v2f camera_angles;
+VG_STATIC v3f camera_pos;
-static m4x3f camera_mtx,
- camera_mtx_inverse;
+VG_STATIC m4x3f camera_mtx,
+ camera_mtx_inverse;
-static void camera_update(void)
+VG_STATIC void camera_update(void)
{
/* Update camera matrices */
v4f qyaw, qpitch, qcam;
v3f pos, normal;
};
-static int network_scores_updated = 0;
+VG_STATIC int network_scores_updated = 0;
-static u32 utf8_byte0_byte_count( u8 char0 )
+VG_STATIC u32 utf8_byte0_byte_count( u8 char0 )
{
for( u32 k=2; k<4; k++ )
{
return 0;
}
-static void str_utf8_collapse( const char *str, char *buf, u32 length )
+VG_STATIC void str_utf8_collapse( const char *str, char *buf, u32 length )
{
u8 *ustr = (u8 *)str;
u32 utf32_code = 0x00000000;
#pragma pack(pop)
-static struct highscore_system
+VG_STATIC struct highscore_system
{
highscore_database dbheader;
aatree aainfo,
aainfo_playerinfo_playerid,
aainfo_playerinfo;
- void *data, *playerinfo_data;
+ void *data,
+ *playerinfo_data;
u32 pool_size, playerinfo_pool_size;
}
highscore_system;
-static int highscore_cmp_points( void *a, void *b )
+VG_STATIC int highscore_cmp_points( void *a, void *b )
{
highscore_record *pa = a, *pb = b;
return (int)pa->points - (int)pb->points;
}
-static int highscore_cmp_datetime( void *a, void *b )
+VG_STATIC int highscore_cmp_datetime( void *a, void *b )
{
highscore_record *pa = a, *pb = b;
return pa->datetime < pb->datetime? 1: -1;
}
-static int highscore_cmp_time( void *a, void *b )
+VG_STATIC int highscore_cmp_time( void *a, void *b )
{
highscore_record *pa = a, *pb = b;
return (int)pb->time - (int)pa->time;
}
-static int highscore_cmp_playerid( void *a, void *b )
+VG_STATIC int highscore_cmp_playerid( void *a, void *b )
{
highscore_record *pa = a, *pb = b;
if( pa->playerid == pb->playerid ) return 0;
return pa->playerid < pb->playerid? -1: 1;
}
-static int highscore_cmp_playerinfo_playerid( void *a, void *b )
+VG_STATIC int highscore_cmp_playerinfo_playerid( void *a, void *b )
{
highscore_playerinfo *pa = a, *pb = b;
if( pa->playerid == pb->playerid ) return 0;
return pa->playerid < pb->playerid? -1: 1;
}
-static void *highscore_malloc( u32 count, u32 size )
-{
- size_t requested_mem = size * count;
- void *data = vg_alloc( requested_mem );
-
- requested_mem /= 1024;
- requested_mem /= 1024;
-
- if( !data )
- {
- vg_error( "Could not allocated %dmb of memory\n", requested_mem );
- return NULL;
- }
- else
- vg_success( "Allocated %dmb for %u records\n", requested_mem, count );
-
- return data;
-}
-
-static void highscores_free(void)
-{
- vg_free( highscore_system.data );
- vg_free( highscore_system.playerinfo_data );
-}
-
-static void highscores_create_db(void)
+VG_STATIC void highscores_create_db(void)
{
struct highscore_system *sys = &highscore_system;
sys->dbheader.playerinfo_root = AATREE_PTR_NIL;
}
-static int highscores_read(void)
+VG_STATIC int highscores_read(void)
{
struct highscore_system *sys = &highscore_system;
return 0;
}
- count = fread( sys->data, sizeof(highscore_record), sys->pool_size, fp );
+ count = fread( sys->data, sizeof(highscore_record),
+ sys->pool_size, fp );
+
if( count != sys->pool_size )
{
vg_error( "Unexpected EOF reading database contents;"
}
}
-static void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
+VG_STATIC void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
{
struct highscore_system *sys = &highscore_system;
- sys->data = highscore_malloc( pool_size, sizeof(highscore_record) );
- sys->playerinfo_data = highscore_malloc( playerinfo_pool_size,
- sizeof(highscore_playerinfo));
+ sys->data = vg_linear_alloc( vg_mem.rtmemory,
+ pool_size*sizeof(highscore_record) );
+
+ sys->playerinfo_data =
+ vg_linear_alloc( vg_mem.rtmemory,
+ playerinfo_pool_size * sizeof(highscore_playerinfo) );
+
/* This is ugly.. too bad! */
sys->aainfo.base = highscore_system.data;
sys->pool_size = pool_size;
}
-static int highscores_serialize_all(void)
+VG_STATIC int highscores_serialize_all(void)
{
struct highscore_system *sys = &highscore_system;
vg_info( "Serializing database\n" );
return 1;
}
-static highscore_record *highscore_find_user_record( u64 playerid, u32 trackid )
+VG_STATIC highscore_record *highscore_find_user_record( u64 playerid, u32 trackid )
{
struct highscore_system *sys = &highscore_system;
return aatree_get_data( &sys->aainfo_playerid, find );
}
-static aatree_ptr highscores_push_record( highscore_record *record )
+VG_STATIC aatree_ptr highscores_push_record( highscore_record *record )
{
struct highscore_system *sys = &highscore_system;
return index;
}
-static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
+VG_STATIC aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
{
char name[17];
for( int i=0; i<16; i++ )
info->playerid = steamid;
sys->dbheader.playerinfo_root = aatree_insert(
&sys->aainfo_playerinfo_playerid,
- sys->dbheader.playerinfo_root,
- record );
+ sys->dbheader.playerinfo_root, record );
}
for( int i=0; i<16; i++ )
}
/* Get the length of a string, bounded by '\0' or len, whichever is first */
-static int highscore_strlen( const char *str, int len )
+VG_STATIC int highscore_strlen( const char *str, int len )
{
int str_length;
for( str_length=0; str_length<len; str_length++ )
}
/* Print the string(max length:len) centered into buf (has width:width) */
-static void highscore_strc( char *buf, const char *str, int len, int width )
+VG_STATIC void highscore_strc( char *buf, const char *str, int len, int width )
{
int str_length = highscore_strlen( str, len ),
offs = (width-str_length)/2;
}
/* Print the string(max length:len) left aligned into buf */
-static void highscore_strl( char *buf, const char *str, int len )
+VG_STATIC void highscore_strl( char *buf, const char *str, int len )
{
for( int i=0; i<len; i++ )
{
}
/* Print the string (max length:len) right aligned into buf (has width:width) */
-static void highscore_strr( char *buf, const char *str, int len, int width )
+VG_STATIC void highscore_strr( char *buf, const char *str, int len, int width )
{
int str_length = highscore_strlen( str, len );
}
/* Print integer (padded with: alt), right aligned into buf(width: len) */
-static void highscore_intr( char *buf, int value, int len, char alt )
+VG_STATIC void highscore_intr( char *buf, int value, int len, char alt )
{
int i=0;
while(value)
}
/* Print integer into buffer with max length len */
-static void highscore_intl( char *buf, int value, int len )
+VG_STATIC void highscore_intl( char *buf, int value, int len )
{
char temp[32];
}
/* Clear buffer with length using clr character */
-static void highscore_clear( char *buf, char clr, int length )
+VG_STATIC void highscore_clear( char *buf, char clr, int length )
{
for( int i=0; i<length; i++ )
buf[i] = clr;
/* Generate a highscores board in text form, the width is always 27. Buffer
* must be (count+3)*27 in size. */
-static void highscores_board_generate( char *buf, u32 id, u32 count )
+VG_STATIC void highscores_board_generate( char *buf, u32 id, u32 count )
{
int w=27;
highscore_clear( buf, ' ', (count+3)*w );
/* Print string out to file using newlines. Count is number of records
* ( this requires a buffer of (count+3)*27 size */
-static void highscores_board_printf( FILE *fp, const char *buf, u32 count )
+VG_STATIC void highscores_board_printf( FILE *fp, const char *buf, u32 count )
{
int w=27;
*
*/
-#define SR_NETWORKED
#define VG_3D
+#define VG_STATIC static
+
+//#define VG_MINIMAL_TEST
+#ifndef VG_MINIMAL_TEST
+
+#define SR_NETWORKED
+
#include "common.h"
#include "steam.h"
#include "render.h"
int main( int argc, char *argv[] )
{
+ vg_prealloc_quota( 128*1024*1024 );
vg_enter( argc, argv, "Voyager Game Engine" );
}
-static void highscores_save_at_exit(void*_)
+VG_STATIC void highscores_save_at_exit(void*_)
{
highscores_serialize_all();
- highscores_free();
}
-void vg_preload(void)
+VG_STATIC void vg_preload(void)
{
vg_convar_push( (struct vg_convar){
.name = "cl_ui",
vg_loader_highwater( network_init, network_end, NULL );
}
-void vg_load(void)
+VG_STATIC void vg_load(void)
{
- vg_loader_highwater( render_init, render_free, NULL );
- vg_loader_highwater( menu_init, menu_free, NULL );
- vg_loader_highwater( world_init, world_free, NULL );
+ vg_loader_highwater( render_init, NULL, NULL );
+ vg_loader_highwater( menu_init, NULL, NULL );
+ vg_loader_highwater( world_init, NULL, NULL );
vg_loader_highwater( player_init, NULL, NULL );
- if( !vg_bake_shaders() )
- vg_fatal_exit_loop( "Did not load all shaders" );
-
+ vg_bake_shaders();
vg_loader_highwater( audio_init, audio_free, NULL );
- /* FInal step */
- world_load();
+ /* 'systems' are completely loaded now */
+ world_load( "models/mp_dev.mdl" );
vg_console_load_autos();
}
-static void vg_start(void)
+VG_STATIC void vg_start(void)
{
- player_load_model( "ch_jordan", 0 );
reset_player( 1, (const char *[]){ "start" } );
}
-static void draw_origin_axis(void)
+VG_STATIC void draw_origin_axis(void)
{
vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
}
-void vg_update( int loaded )
+VG_STATIC void vg_update( int loaded )
{
steam_update();
}
}
-static void vg_update_fixed( int loaded )
+VG_STATIC void vg_update_fixed( int loaded )
{
if( loaded )
{
}
}
-static void vg_update_post( int loaded )
+VG_STATIC void vg_update_post( int loaded )
{
if( loaded )
{
}
}
-static void vg_framebuffer_resize( int w, int h )
+VG_STATIC void vg_framebuffer_resize( int w, int h )
{
render_fb_resize();
- gate_fb_resize();
water_fb_resize();
}
-static void render_main_game(void)
+VG_STATIC void render_main_game(void)
{
m4x4f world_4x4;
m4x3_expand( camera_mtx_inverse, world_4x4 );
render_fsquad();
}
-void vg_render(void)
+VG_STATIC void vg_render(void)
{
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glViewport( 0,0, vg.window_x, vg.window_y );
glViewport( 0,0, vg.window_x, vg.window_y );
}
-void vg_ui(void)
+VG_STATIC void vg_ui(void)
{
#if 0
if( cl_menu )
}
#if 0
-static void run_light_widget( struct light_widget *lw )
+VG_STATIC void run_light_widget( struct light_widget *lw )
{
struct ui_checkbox c1 = { .data=&lw->enabled };
}
#endif
-static void run_debug_info(void)
+VG_STATIC void run_debug_info(void)
{
char buf[40];
snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
- gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
+ ui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
snprintf( buf, 40, "%.2f %.2f %.2f m/s",
player.phys.a[0], player.phys.a[1], player.phys.a[2] );
- gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
+ ui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
snprintf( buf, 40, "pos %.2f %.2f %.2f",
player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
- gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
+ ui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
if( vg.gamepad_ready )
{
for( int i=0; i<6; i++ )
{
snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
- gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
+ ui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
}
}
else
{
- gui_text( (ui_px [2]){ 0, 60 },
+ ui_text( (ui_px [2]){ 0, 60 },
"Gamepad not ready", 1, k_text_align_left );
}
}
+
+#else
+
+#define VG_TIMESTEP_FIXED (1.0/60.0)
+#define VG_3D
+#define VG_FRAMEBUFFER_RESIZE 1
+#include "vg/vg.h"
+
+int main( int argc, char *argv[] )
+{
+ vg_prealloc_quota( 512*1024*1024 );
+ vg_enter( argc, argv, "Voyager Game Engine" );
+}
+
+VG_STATIC void vg_preload(void)
+{
+vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" );
+vg_info(" 2021-2022 |\\ /| | / | | | | /| \n" );
+vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
+vg_info(" | \\ / | | / | | \\ | / | \n" );
+vg_info(" | \\/ | | / | | \\ | / | \n" );
+vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
+ "SOFTWARE\n" );
+}
+
+VG_STATIC void vg_load(void)
+{
+ vg_bake_shaders();
+ vg_console_load_autos();
+}
+
+VG_STATIC void vg_start(void)
+{
+}
+
+VG_STATIC void vg_update( int loaded )
+{
+}
+
+VG_STATIC void vg_update_fixed( int loaded )
+{
+}
+
+VG_STATIC void vg_update_post( int loaded )
+{
+}
+
+VG_STATIC void vg_framebuffer_resize( int w, int h )
+{
+}
+
+VG_STATIC void vg_render(void)
+{
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+ glViewport( 0,0, vg.window_x, vg.window_y );
+ glDisable( GL_DEPTH_TEST );
+
+ glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+
+ /* Other shite */
+ glDisable(GL_BLEND);
+ glDisable( GL_DEPTH_TEST );
+ vg_lines_drawall( (float *)vg.pv );
+ glViewport( 0,0, vg.window_x, vg.window_y );
+}
+
+VG_STATIC void vg_ui(void)
+{
+}
+
+#endif
#include "shaders/menu.h"
-static mdl_header *menu_model;
-static glmesh menu_glmesh;
-static m4x3f menu_mdl_mtx;
-static float menu_opacity = 0.0f;
-static float menu_input_cooldown = 0.0f;
-static float menu_fov_target = 97.0f;
-static v2f menu_extra_angles;
-
-static int menu_loc = 1,
+VG_STATIC mdl_context menu_model;
+VG_STATIC glmesh menu_glmesh;
+VG_STATIC m4x3f menu_mdl_mtx;
+VG_STATIC float menu_opacity = 0.0f;
+VG_STATIC float menu_input_cooldown = 0.0f;
+VG_STATIC float menu_fov_target = 97.0f;
+VG_STATIC v2f menu_extra_angles;
+
+VG_STATIC int menu_loc = 1,
menu_loc_last = 1;
-static u32 menu_page = 0;
+VG_STATIC u32 menu_page = 0;
-static int cl_menu = 0,
+VG_STATIC int cl_menu = 0,
cl_menu_go_away = 0;
-static int cl_playermdl_id = 0;
-static const char *playermodels[] = { "ch_new", "ch_jordan", "ch_outlaw" };
+VG_STATIC const char *playermodels[] = { "ch_new", "ch_jordan", "ch_outlaw" };
-static void menu_btn_paused( int event );
-static void menu_btn_quit( int event );
-static void menu_btn_skater( int event );
-static void menu_btn_map( int event );
-static void menu_btn_map_a( int event );
-static void menu_btn_map_b( int event );
-static void menu_btn_map_c( int event );
-static void menu_btn_fuckoff( int event );
+VG_STATIC void menu_btn_paused( int event );
+VG_STATIC void menu_btn_quit( int event );
+VG_STATIC void menu_btn_skater( int event );
+VG_STATIC void menu_btn_map( int event );
+VG_STATIC void menu_btn_map_a( int event );
+VG_STATIC void menu_btn_map_b( int event );
+VG_STATIC void menu_btn_map_c( int event );
+VG_STATIC void menu_btn_fuckoff( int event );
struct menu_button
{
float falpha, fsize;
}
-static menu_buttons[] =
+VG_STATIC menu_buttons[] =
{
/*0*/{"text_paused", 1, menu_btn_paused },
/*1*/{"text_quit", 9, menu_btn_quit, {3,-1,4,2}},
/*d*/{"text_yes", 8, menu_btn_fuckoff,{-1,-1,-1,-1} },
};
-static void menu_btn_map_a( int event ){}
-static void menu_btn_map_b( int event ){}
-static void menu_btn_map_c( int event ){}
+VG_STATIC void menu_btn_map_a( int event ){}
+VG_STATIC void menu_btn_map_b( int event ){}
+VG_STATIC void menu_btn_map_c( int event ){}
-static void menu_btn_paused( int event )
+VG_STATIC void menu_btn_paused( int event )
{
}
-static void menu_btn_fuckoff( int event )
+VG_STATIC void menu_btn_fuckoff( int event )
{
glfwSetWindowShouldClose( vg.window, 1 );
}
-static void menu_btn_quit( int event )
+VG_STATIC void menu_btn_quit( int event )
{
menu_page = 0x8;
menu_loc = 0xd;
}
-static void menu_btn_map( int event )
+VG_STATIC void menu_btn_map( int event )
{
menu_page = 0x4;
menu_loc = 7;
}
-static void menu_btn_skater( int event )
+VG_STATIC void menu_btn_skater( int event )
{
menu_page = 0x2;
}
-static void menu_init(void)
+VG_STATIC void menu_init(void)
{
- menu_model = mdl_load( "models/rs_menu.mdl" );
+ vg_linear_clear( vg_mem.scratch );
- if( !menu_model )
- vg_fatal_exit_loop( "No menu model" );
+ mdl_open( &menu_model, "models/rs_menu.mdl" );
+ mdl_load_metadata( &menu_model, vg_mem.rtmemory );
+ mdl_load_mesh_data( &menu_model, vg_mem.scratch );
+ mdl_close( &menu_model );
+
+ vg_acquire_thread_sync();
+ mdl_unpack_glmesh( &menu_model, &menu_glmesh );
+ vg_release_thread_sync();
for( int i=0; i<vg_list_size(menu_buttons); i++ )
{
struct menu_button *btn = &menu_buttons[i];
- btn->pnode = mdl_node_from_name( menu_model, btn->name );
+ btn->pnode = mdl_node_from_name( &menu_model, btn->name );
if( !btn->pnode )
vg_fatal_exit_loop( "Menu programming error" );
}
- vg_convar_push( (struct vg_convar){
- .name = "cl_playermdl_id",
- .data = &cl_playermdl_id,
- .data_type = k_convar_dtype_i32,
- .opt_i32 = { .min=0, .max=2, .clamp=1 },
- .persistent = 1
- });
-
- vg_acquire_thread_sync();
- mdl_unpack_glmesh( menu_model, &menu_glmesh );
- vg_release_thread_sync();
-
shader_menu_register();
}
-static void menu_run_directional(void)
+VG_STATIC void menu_run_directional(void)
{
struct menu_button *btn = &menu_buttons[ menu_loc ];
}
}
-static int menu_page_should_backout(void)
+VG_STATIC int menu_page_should_backout(void)
{
return vg_get_button_down( "break" );
}
-static void menu_close(void)
+VG_STATIC void menu_close(void)
{
cl_menu_go_away = 1;
menu_page = 0;
}
-static void menu_page_main(void)
+VG_STATIC void menu_page_main(void)
{
if( menu_page_should_backout() )
{
menu_run_directional();
}
-static void menu_page_map(void)
+VG_STATIC void menu_page_map(void)
{
if( menu_page_should_backout() )
{
menu_run_directional();
}
-static void menu_page_quit(void)
+VG_STATIC void menu_page_quit(void)
{
if( menu_page_should_backout() )
{
menu_run_directional();
}
-static void menu_page_skater(void)
+VG_STATIC void menu_page_skater(void)
{
float h = vg_get_axis( "lookh" );
menu_fov_target = 97.0f;
menu_buttons[5].falpha = 1.0f;
menu_input_cooldown = 0.25f;
- player_load_model( playermodels[ cl_playermdl_id ], 1 );
}
else
{
menu_buttons[6].falpha = 1.0f;
menu_input_cooldown = 0.25f;
- player_load_model( playermodels[ cl_playermdl_id ], 1 );
}
}
}
-static void menu_update(void)
+VG_STATIC void menu_update(void)
{
if( vg_get_button_down( "menu" ) )
{
return fminf( x*x/(f*f), 1.0f+(2.0f/f)*s*expf(-k*s));
}
-static void menu_render( m4x4f projection )
+VG_STATIC void menu_render( m4x4f projection )
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
for( int j=0; j<btn->pnode->submesh_count; j++ )
{
mdl_submesh *sm =
- mdl_submesh_from_id( menu_model, btn->pnode->submesh_start+j );
+ &menu_model.submesh_buffer[ btn->pnode->submesh_start+j ];
mdl_draw_submesh( sm );
}
}
*/
}
-static void menu_free(void *_)
-{
- mesh_free( &menu_glmesh );
-}
-
#endif /* MENU_H */
typedef struct mdl_submesh mdl_submesh;
typedef struct mdl_material mdl_material;
typedef struct mdl_node mdl_node;
-typedef struct mdl_header mdl_header;
+typedef struct mdl_file_header mdl_file_header;
typedef struct mdl_animation mdl_animation;
typedef struct mdl_keyframe mdl_keyframe;
+typedef struct mdl_context mdl_context;
#define MDL_SIZE_MAX 0x1000000
#define MDL_VERT_MAX 1000000
k_classtype_skeleton = 11,
k_classtype_skin = 12,
k_classtype_achievement_box = 13,
- k_classtype_audio = 14
+ k_classtype_audio = 14,
+ k_classtype_trigger = 15
};
v4f q;
v3f s;
- union{ u32 submesh_start, sub_uid; };
-
- u32
+ u32 sub_uid, /* allocated in-file... too bad. */
+ submesh_start,
submesh_count,
classtype,
offset,
u32 offset;
};
-struct mdl_header
+struct mdl_file_header
{
- u32 identifier, version, file_length;
+ u32 identifier, version, file_length, pad0;
u32 vertex_count, vertex_offset,
indice_count, indice_offset,
material_count, material_offset,
node_count, node_offset,
anim_count, anim_offset,
- strings_offset, entdata_offset, animdata_offset;
+ strings_length, strings_offset,
+ entdata_length, entdata_offset,
+ keyframe_count, keyframe_offset;
};
/*
#pragma pack(pop)
+
+struct mdl_context
+{
+ FILE *file;
+ mdl_file_header info;
+
+ /* each buffer becomes availible after each _load function is called */
+ mdl_node *node_buffer; /* mdl_load_metadata() */
+ mdl_submesh *submesh_buffer;
+ mdl_material *material_buffer;
+ mdl_animation *anim_buffer;
+ void *entdata_buffer;
+ const char *string_buffer;
+
+ mdl_keyframe *keyframe_buffer; /* mdl_load_anim_data() */
+
+ mdl_vert *vertex_buffer; /* mdl_load_mesh_data() */
+ u32 *index_buffer;
+};
+
/*
* Simple mesh interface for OpenGL
*/
u32 loaded;
};
-static void mesh_upload( glmesh *mesh,
+VG_STATIC void mesh_upload( glmesh *mesh,
mdl_vert *verts, u32 vert_count,
u32 *indices, u32 indice_count )
{
mesh->loaded = 1;
}
-static void mesh_bind( glmesh *mesh )
+VG_STATIC void mesh_bind( glmesh *mesh )
{
glBindVertexArray( mesh->vao );
}
-static void mesh_drawn( u32 start, u32 count )
+VG_STATIC void mesh_drawn( u32 start, u32 count )
{
glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT,
(void *)(start*sizeof(u32)) );
}
-static void mesh_draw( glmesh *mesh )
+VG_STATIC void mesh_draw( glmesh *mesh )
{
mesh_drawn( 0, mesh->indice_count );
}
-static void mesh_free( glmesh *mesh )
+VG_STATIC void mesh_free( glmesh *mesh )
{
if( mesh->loaded )
{
}
}
+VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
+{
+ fclose( mdl->file );
+ vg_file_print_invalid( mdl->file );
+ vg_fatal_exit_loop( "Corrupt model" );
+}
/*
* Model implementation
+ *
+ * TODO.
+ *
+ * you have two api options for loading a model, first, the easy way:
+ * mdl_load ...
+ * will put the entire model straight into the linear_alloc
+ *
+ * or, to target different allocators:
+ *
+ * mdl_open
+ * mdl_load_metadata
+ * mdl_load_vertex_data
+ * mdl_load_indice_data
+ * mdl_close
+ *
+ * these should ideally be called in quick succession to limit stalls.
*/
-static mdl_header *mdl_load( const char *path )
+/*
+ * if calling mdl_open, and the file does not exist, the game will fatal quit
+ */
+VG_STATIC void mdl_open( mdl_context *mdl, const char *path )
{
- i64 size;
- mdl_header *header = vg_asset_read_s( path, &size );
+ memset( mdl, 0, sizeof( mdl_context ) );
+ mdl->file = fopen( path, "rb" );
- /*
- * Check file is valid
- */
- if( !header )
+ if( !mdl->file )
{
- vg_error( "Could not open '%s'\n", path );
- return NULL;
+ vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) );
+ vg_fatal_exit_loop( "see above for details" );
}
- if( size < sizeof(mdl_header) )
- {
- vg_free( header );
- vg_error( "Invalid file '%s' (too small for header)\n", path );
- return NULL;
- }
+ u64 l = fread( &mdl->info, sizeof(mdl_file_header), 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+}
- if( header->file_length != size )
- {
- vg_error( "Invalid file '%s'"
- "(wrong .file_length, %ub != real file size %ub)\n",
- path, header->file_length, size );
- vg_free( header );
- return NULL;
- }
+/*
+ * Load all metadata (everything up until the large buffers). Probs at most 50k
+ */
+VG_STATIC void mdl_load_metadata( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
+
+ u64 lheader = sizeof(mdl_file_header),
+ ldata = mdl->info.keyframe_offset - lheader;
- /*
- * Validate offsets and memory sections, to ensure all arrays are in-bounds,
- * and that they do not overlap.
- */
+ void *all_data = vg_linear_alloc( lin_alloc, ldata );
- struct memregion
+ fseek( mdl->file, lheader, SEEK_SET );
+ u64 l = fread( all_data, ldata, 1, mdl->file );
+
+ if( l != 1 )
{
- const char *desc;
- u32 count, max_count, size, offset;
+ vg_file_print_invalid( mdl->file );
+ vg_fatal_exit_loop( "Corrupt model" );
}
- regions[] = {
- {
- "Vertices",
- header->vertex_count, MDL_VERT_MAX,
- sizeof(mdl_vert), header->vertex_offset
- },
- {
- "Indices",
- header->indice_count, MDL_INDICE_MAX,
- sizeof(u32), header->indice_offset
- },
- {
- "Submesh",
- header->submesh_count, MDL_SUBMESH_MAX,
- sizeof(mdl_submesh), header->submesh_offset
- },
- {
- "Materials",
- header->material_count, MDL_MATERIAL_MAX,
- sizeof(mdl_material), header->material_offset
- },
- {
- "Nodes",
- header->node_count, MDL_NODE_MAX,
- sizeof(mdl_node), header->node_count
- }
- };
- for( int i=0; i<vg_list_size(regions); i++ )
- {
- struct memregion *ri = ®ions[i];
+ mdl->node_buffer = all_data + (mdl->info.node_offset - lheader);
+ mdl->submesh_buffer = all_data + (mdl->info.submesh_offset - lheader);
+ mdl->material_buffer = all_data + (mdl->info.material_offset - lheader);
+ mdl->anim_buffer = all_data + (mdl->info.anim_offset - lheader);
+ mdl->entdata_buffer = all_data + (mdl->info.entdata_offset - lheader);
+ mdl->string_buffer = all_data + (mdl->info.strings_offset - lheader);
+}
- if( ri->count == 0 )
- continue;
+/*
+ * Load just the mesh data
+ */
+VG_STATIC void mdl_load_mesh_data( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
+
+ u64 size_verts = mdl->info.vertex_count * sizeof(mdl_vert),
+ size_index = mdl->info.indice_count * sizeof(u32);
- if( ri->count > ri->max_count )
- {
- vg_free( header );
- vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
- path, ri->desc, ri->count, ri->max_count );
- return NULL;
- }
+ mdl->vertex_buffer = vg_linear_alloc( lin_alloc, size_verts );
+ mdl->index_buffer = vg_linear_alloc( lin_alloc, size_index );
+
+ {
+ fseek( mdl->file, mdl->info.vertex_offset, SEEK_SET );
+ u64 l = fread( mdl->vertex_buffer, size_verts, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+ }
+ {
+ fseek( mdl->file, mdl->info.indice_offset, SEEK_SET );
+ u64 l = fread( mdl->index_buffer, size_index, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+ }
+}
- if( ri->offset >= header->file_length )
- {
- vg_free( header );
- vg_error( "'%s': '%s' buffer offset is out of range\n",
- path, ri->desc );
- return NULL;
- }
+/*
+ * Load animation data
+ */
+VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
- if( ri->offset + ri->size*ri->count > header->file_length )
- {
- vg_free( header );
- vg_error( "'%s': '%s' buffer size is out of range\n",
- path, ri->desc );
- return NULL;
- }
+ if( mdl->info.keyframe_count == 0 )
+ return;
+
+ u64 size_kf = mdl->info.keyframe_count * sizeof(mdl_keyframe);
+ mdl->keyframe_buffer = vg_linear_alloc( lin_alloc, size_kf );
+
+ fseek( mdl->file, mdl->info.keyframe_offset, SEEK_SET );
+ u64 l = fread( mdl->keyframe_buffer, size_kf, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+}
- for( int j=0; j<vg_list_size(regions); j++ )
- {
- struct memregion *rj = ®ions[j];
- if( rj->count == 0 )
- continue;
+/*
+ * close file handle
+ */
+VG_STATIC void mdl_close( mdl_context *mdl )
+{
+ fclose( mdl->file );
+ mdl->file = NULL;
+}
- if( ri->offset >= rj->offset &&
- (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count))
- {
- vg_free( header );
- vg_error( "'%s': '%s' buffer overlaps '%s'\n",
- path, ri->desc, rj->desc );
- return NULL;
- }
- }
- }
+/* open a model */
+VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path )
+{
+ /* Inspect the header by opening it, give us the size needed */
+ mdl_context temp_ctx;
+ mdl_open( &temp_ctx, path );
- /*
- * Pointer validation TODO(workshop)
- */
+ /* create allocator */
+ u32 tot_size = temp_ctx.info.file_length + sizeof( mdl_context );
+ void *data = vg_create_linear_allocator( lin_alloc, tot_size );
- /*
- * strings TODO(workshop)
- */
+ /* copy context and load all other data */
+ mdl_context *ctx = vg_linear_alloc( data, sizeof(mdl_context) );
+ memcpy( ctx, &temp_ctx, sizeof(mdl_context) );
- return header;
-}
+ mdl_load_metadata( ctx, data );
+ mdl_load_anim_data( ctx, data );
+ mdl_load_mesh_data( ctx, data );
+ mdl_close( ctx );
-static void *mdl_baseptr( mdl_header *mdl, u32 offset )
-{
- return (void *)mdl + offset;
+ return ctx;
}
-static const char *mdl_pstr( mdl_header *mdl, u32 pstr )
+/*
+ * Item getters
+ * ----------------------------------------------------------------------------
+ * TODO: Clamp access and oob errors
+ */
+VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr )
{
- return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr;
+ return mdl->string_buffer + pstr;
}
-static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id )
+VG_STATIC mdl_node *mdl_node_from_id( mdl_context *mdl, u32 id )
{
- return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id;
+ return &mdl->node_buffer[id];
}
-static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name )
+VG_STATIC mdl_node *mdl_node_from_name( mdl_context *mdl, const char *name )
{
- for( int i=0; i<mdl->node_count; i++ )
+ for( int i=0; i < mdl->info.node_count; i++ )
{
mdl_node *pnode = mdl_node_from_id( mdl, i );
return NULL;
}
-static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id )
-{
- if( id >= mdl->submesh_count )
- return NULL;
-
- return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id;
-}
-
-static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i )
-{
- if( i >= node->submesh_count )
- return NULL;
-
- return mdl_submesh_from_id( mdl, node->submesh_start+i );
-}
-
-static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm )
+VG_STATIC mdl_submesh *mdl_node_submesh( mdl_context *mdl,
+ mdl_node *node, u32 i )
{
- return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start;
+ return &mdl->submesh_buffer[ node->submesh_start+i ];
}
-static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm )
+VG_STATIC u32 *mdl_submesh_indices( mdl_context *mdl, mdl_submesh *sm )
{
- return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start;
+ return &mdl->index_buffer[ sm->indice_start ];
}
-static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id )
+VG_STATIC mdl_vert *mdl_submesh_vertices( mdl_context *mdl, mdl_submesh *sm )
{
- return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id;
+ return &mdl->vertex_buffer[ sm->vertex_start ];
}
-static mdl_animation *mdl_animation_from_id( mdl_header *mdl, u32 id )
-{
- return ((mdl_animation *)mdl_baseptr(mdl,mdl->anim_offset)) + id;
-}
-
-static void mdl_node_transform( mdl_node *pnode, m4x3f transform )
+VG_STATIC void mdl_node_transform( mdl_node *pnode, m4x3f transform )
{
q_m3x3( pnode->q, transform );
v3_muls( transform[0], pnode->s[0], transform[0] );
v3_copy( pnode->co, transform[3] );
}
-static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm )
+/* upload a mesh based on file submesh */
+VG_STATIC void mdl_unpack_submesh( mdl_context *mdl, glmesh *mesh,
+ mdl_submesh *sm )
{
mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count,
mdl_submesh_indices( mdl, sm ), sm->indice_count );
}
-static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh )
+/* upload entire mesh from model */
+VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh )
{
- u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count;
+ u32 offset = mdl->submesh_buffer[0].vertex_count;
- for( int i=1; i< mdl->submesh_count; i++ )
+ for( int i=1; i< mdl->info.submesh_count; i++ )
{
- mdl_submesh *sm = mdl_submesh_from_id( mdl, i );
- u32 *indices = mdl_submesh_indices( mdl, sm );
+ mdl_submesh *sm = &mdl->submesh_buffer[i];
+ u32 *indices = mdl_submesh_indices( mdl, sm );
for( u32 j=0; j<sm->indice_count; j++ )
indices[j] += offset;
offset += sm->vertex_count;
}
- mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset );
- u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset );
-
- mesh_upload( mesh, vertex_base, mdl->vertex_count,
- indice_base, mdl->indice_count );
+ mesh_upload( mesh, mdl->vertex_buffer, mdl->info.vertex_count,
+ mdl->index_buffer, mdl->info.indice_count );
}
-static void mdl_draw_submesh( mdl_submesh *sm )
+VG_STATIC void mdl_draw_submesh( mdl_submesh *sm )
{
mesh_drawn( sm->indice_start, sm->indice_count );
}
-static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode )
+VG_STATIC void *mdl_get_entdata( mdl_context *mdl, mdl_node *pnode )
{
- return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset;
+ return mdl->entdata_buffer + pnode->offset;
}
-static mdl_keyframe *mdl_get_animdata( mdl_header *mdl, mdl_animation *anim )
+VG_STATIC mdl_keyframe *mdl_get_animdata( mdl_context *mdl, mdl_animation *anim )
{
- return mdl_baseptr( mdl, mdl->animdata_offset ) + anim->offset;
+ return mdl->keyframe_buffer + anim->offset;
}
-static void mdl_link_materials( mdl_header *root, mdl_header *child )
+VG_STATIC void mdl_link_materials( mdl_context *root, mdl_context *child )
{
u32 lookup[MDL_MATERIAL_MAX];
- for( int i=0; i<child->material_count; i++ )
+ for( int i=0; i<child->info.material_count; i++ )
{
- mdl_material *mi = mdl_material_from_id( child, i );
+ mdl_material *mi = &child->material_buffer[i];
const char *si = mdl_pstr( child, mi->pstr_name );
lookup[i] = 0;
- for( int j=0; j<root->material_count; j++ )
+ for( int j=0; j<root->info.material_count; j++ )
{
- mdl_material *mj = mdl_material_from_id( root, j );
+ mdl_material *mj = &root->material_buffer[j];
const char *sj = mdl_pstr( root, mj->pstr_name );
if( !strcmp( si, sj ) )
}
}
- for( int i=0; i<child->submesh_count; i++ )
+ for( int i=0; i<child->info.submesh_count; i++ )
{
- mdl_submesh *sm = mdl_submesh_from_id( child, i );
- sm->material_id = lookup[sm->material_id];
+ mdl_submesh *sm = &child->submesh_buffer[i];
+ sm->material_id = lookup[sm->material_id];
}
}
//#define SR_USE_LOCALHOST
/* Call it at start; Connects us to the gameserver */
-static void network_init(void);
+VG_STATIC void network_init(void);
/* Run this from main loop */
-static void network_update(void);
+VG_STATIC void network_update(void);
/* Call it at shutdown */
-static void network_end(void*_);
+VG_STATIC void network_end(void*_);
/*
* Can buffer up a bunch of these by calling many times, they will be
* sent at the next connection
*/
-static void network_submit_highscore( u32 trackid, u16 points, u16 time );
+VG_STATIC void network_submit_highscore( u32 trackid, u16 points, u16 time );
/*
* Game endpoints are provided with the same names to allow running without a
/*
* Runtime connection stuff
*/
-static u8 steam_app_ticket[ 1024 ];
-static u32 steam_app_ticket_length;
-static int network_name_update = 1;
+VG_STATIC u8 steam_app_ticket[ 1024 ];
+VG_STATIC u32 steam_app_ticket_length;
+VG_STATIC int network_name_update = 1;
-static HSteamNetConnection cremote;
-static ESteamNetworkingConnectionState cremote_state =
+VG_STATIC HSteamNetConnection cremote;
+VG_STATIC ESteamNetworkingConnectionState cremote_state =
k_ESteamNetworkingConnectionState_None;
/*
* Implementation
*/
-static void scores_update(void);
+VG_STATIC void scores_update(void);
-static void on_auth_ticket_recieved( void *result, void *context )
+VG_STATIC void on_auth_ticket_recieved( void *result, void *context )
{
EncryptedAppTicketResponse_t *response = result;
}
}
-static void request_auth_ticket(void)
+VG_STATIC void request_auth_ticket(void)
{
/*
* TODO Check for one thats cached on the disk and load it.
NULL, 0 );
}
-static void send_auth_ticket(void)
+VG_STATIC void send_auth_ticket(void)
{
u32 size = sizeof(netmsg_auth) + steam_app_ticket_length;
netmsg_auth *auth = alloca(size);
k_nSteamNetworkingSend_Reliable, NULL );
}
-static void send_score_request(void)
+VG_STATIC void send_score_request(void)
{
vg_info( "Requesting scores\n" );
netmsg_scores_request req;
k_nSteamNetworkingSend_Reliable, NULL );
}
-static void send_score_update(void)
+VG_STATIC void send_score_update(void)
{
vg_info( "Sending scores\n" );
u32 size = sizeof(netmsg_set_score) +
k_nSteamNetworkingSend_Reliable, NULL );
}
-static void send_nickname(void)
+VG_STATIC void send_nickname(void)
{
netmsg_set_nickname nick;
nick.inetmsg_id = k_inetmsg_set_nickname;
network_name_update = 0;
}
-static void server_routine_update(void)
+VG_STATIC void server_routine_update(void)
{
send_auth_ticket();
send_score_request();
}
-static void on_server_connect_status( CallbackMsg_t *msg )
+VG_STATIC void on_server_connect_status( CallbackMsg_t *msg )
{
SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
vg_info( " Connection status changed for %lu\n", info->m_hConn );
}
}
-static void network_connect_gc(void)
+VG_STATIC void network_connect_gc(void)
{
/* Connect to server if not connected */
SteamNetworkingIPAddr remoteAddr;
hSteamNetworkingSockets, &remoteAddr, 0, NULL );
}
-static void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
+VG_STATIC void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
{
netmsg_scoreboard *sb = msg->m_pData;
network_scores_updated = 1;
}
-static void poll_connection(void)
+VG_STATIC void poll_connection(void)
{
SteamNetworkingMessage_t *messages[32];
int len;
/*
* Subroutine to be connected to main game loop, runs all routines on timers
*/
-static void network_update(void)
+VG_STATIC void network_update(void)
{
if( steam_ready )
{
}
}
-static void network_init(void)
+VG_STATIC void network_init(void)
{
if( steam_ready )
{
}
}
-static void network_end(void*_)
+VG_STATIC void network_end(void*_)
{
/* TODO: Fire off any buffered highscores that need to be setn */
if( cremote_state == k_ESteamNetworkingConnectionState_Connected ||
#else /* SR_NETWORKED */
-static void network_init(void){}
-static void network_update(void){}
-static void network_end(void*_){}
+VG_STATIC void network_init(void){}
+VG_STATIC void network_update(void){}
+VG_STATIC void network_end(void*_){}
#endif /* SR_NETWORKED */
#endif /* NETWORK_H */
}
boards[ vg_list_size(track_infos) ];
}
-static scoreboard_client_data = {
+VG_STATIC scoreboard_client_data = {
.inetmsg_id = k_inetmsg_scoreboard,
.board_count = vg_list_size(track_infos)
};
#include "skeleton.h"
#include "bvh.h"
-static float
+VG_STATIC float
k_walkspeed = 20.0f, /* no longer used */
k_runspeed = 20.0f,
k_board_radius = 0.3f,
k_walk_accel = 150.0f,
k_walk_friction = 8.0f;
-static int freecam = 0;
-static int walk_grid_iterations = 1;
-static float fc_speed = 10.0f;
+VG_STATIC int cl_playermdl_id = 0;
+VG_STATIC int freecam = 0;
+VG_STATIC int walk_grid_iterations = 1;
+VG_STATIC float fc_speed = 10.0f;
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
-static struct gplayer
+VG_STATIC struct gplayer
{
/* Physics */
rigidbody collide_front, collide_back;
/* player model */
struct player_model
{
- glmesh mesh;
+ glmesh player_meshes[3];
+
+ mdl_context meta;
struct skeleton sk;
struct skeleton_anim *anim_stand,
*anim_highg,
rigidbody rb;
u32 parent;
}
- *ragdoll;
+ ragdoll[32];
u32 ragdoll_count;
int shoes[2];
/*
* API
*/
-static float *player_get_pos(void);
-static void player_kill(void);
-static float *player_cam_pos(void);
-static void player_save_frame(void);
-static void player_restore_frame(void);
-static void player_save_rewind_frame(void);
+VG_STATIC float *player_get_pos(void);
+VG_STATIC void player_kill(void);
+VG_STATIC float *player_cam_pos(void);
+VG_STATIC void player_save_frame(void);
+VG_STATIC void player_restore_frame(void);
+VG_STATIC void player_save_rewind_frame(void);
/*
* Submodules
* -----------------------------------------------------------------------------
*/
-static void player_init(void) /* 1 */
+VG_STATIC void player_init(void) /* 1 */
{
rb_init( &player.phys.rb );
rb_init( &player.collide_front );
rb_init( &player.collide_back );
+ vg_convar_push( (struct vg_convar){
+ .name = "cl_playermdl_id",
+ .data = &cl_playermdl_id,
+ .data_type = k_convar_dtype_i32,
+ .opt_i32 = { .min=0, .max=2, .clamp=1 },
+ .persistent = 1
+ });
+
vg_convar_push( (struct vg_convar){
.name = "walk_speed",
.data = &k_walkspeed,
});
player.rewind_length = 0;
- player.rewind_buffer = vg_alloc( sizeof(struct rewind_frame)
- * PLAYER_REWIND_FRAMES );
+ player.rewind_buffer =
+ vg_linear_alloc( vg_mem.rtmemory,
+ sizeof(struct rewind_frame) * PLAYER_REWIND_FRAMES );
- /* other systems */
- vg_loader_highwater( player_model_init, player_model_free, NULL );
+ player_model_init();
}
-static void player_save_rewind_frame(void)
+VG_STATIC void player_save_rewind_frame(void)
{
if( player.rewind_length < PLAYER_REWIND_FRAMES )
{
}
/* Deal with input etc */
-static void player_update_pre(void)
+VG_STATIC void player_update_pre(void)
{
struct player_phys *phys = &player.phys;
if( vg_get_button_down( "reset" ) )
{
- double delta = world_routes.time - world_routes.last_use;
+ double delta = world.time - world.last_use;
if( delta <= RESET_MAX_TIME )
{
}
}
-static void player_update_fixed(void) /* 2 */
+VG_STATIC void player_update_fixed(void) /* 2 */
{
if( player.rewinding )
return;
}
}
-static void player_update_post(void)
+VG_STATIC void player_update_post(void)
{
for( int i=0; i<player.land_log_count; i++ )
vg_line_cross( player.land_target_log[i],
player_audio();
}
-static void draw_player( m4x3f cam )
+VG_STATIC void draw_player( m4x3f cam )
{
if( player.is_dead )
player_model_copy_ragdoll();
0,
(float *)player.mdl.sk.final_mtx );
- mesh_bind( &player.mdl.mesh );
- mesh_draw( &player.mdl.mesh );
+ mesh_bind( &player.mdl.player_meshes[cl_playermdl_id] );
+ mesh_draw( &player.mdl.player_meshes[cl_playermdl_id] );
}
/*
* -----------------------------------------------------------------------------
*/
-static float *player_get_pos(void)
+VG_STATIC float *player_get_pos(void)
{
return player.phys.rb.co;
}
-static void player_kill(void)
+VG_STATIC void player_kill(void)
{
if( player.death_tick_allowance == 0 )
{
}
}
-static float *player_cam_pos(void)
+VG_STATIC float *player_cam_pos(void)
{
return player.camera_pos;
}
#include "player.h"
-static void player_animate_offboard(void)
+VG_STATIC void player_animate_offboard(void)
{
{
float fly = player.phys.in_air,
skeleton_debug( &player.mdl.sk );
}
-static void player_animate(void)
+VG_STATIC void player_animate(void)
{
struct player_phys *phys = &player.phys;
rb_extrapolate_transform( &player.phys.rb, player.visual_transform );
skeleton_debug( &player.mdl.sk );
}
-static void player_animate_death_cam(void)
+VG_STATIC void player_animate_death_cam(void)
{
v3f delta;
v3f head_pos;
if( ray_world( sample, (v3f){0.0f,-1.0f,0.0f}, &hit ))
v3_add( hit.pos, min_height, player.camera_pos );
- player.camera_pos[1] =
- vg_maxf( wrender.height + 2.0f, player.camera_pos[1] );
+ if( world.water.enabled )
+ {
+ player.camera_pos[1] =
+ vg_maxf( world.water.height + 2.0f, player.camera_pos[1] );
+ }
player.angles[0] = atan2f( delta[0], -delta[2] );
player.angles[1] = -asinf( delta[1] );
}
-static void player_animate_camera(void)
+VG_STATIC void player_animate_camera(void)
{
struct player_phys *phys = &player.phys;
/*
* Audio
*/
-static void player_audio(void)
+VG_STATIC void player_audio(void)
{
struct player_phys *phys = &player.phys;
vg_tex2d tex_characters = { .path = "textures/ch_gradient.qoi" };
-static void player_model_init(void)
+VG_STATIC void player_model_init(void)
{
shader_viewchar_register();
vg_acquire_thread_sync();
vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 );
}
vg_release_thread_sync();
-}
-
-static void player_model_free(void *_)
-{
- mesh_free( &player.mdl.mesh );
- vg_tex2d_free( (vg_tex2d *[]){ &tex_characters }, 1 );
-}
-
-/*
- * Load model from file (.mdl)
- */
-static void player_load_model( const char *name, int replace_mode )
-{
- char buf[64];
-
- snprintf( buf, sizeof(buf)-1, "models/%s.mdl", name );
- mdl_header *src = mdl_load( buf );
- if( !src )
+ /* load in reference player model, with animations and such */
+ mdl_open( &player.mdl.meta, "models/ch_new.mdl" );
+ mdl_load_metadata( &player.mdl.meta, vg_mem.rtmemory );
+ mdl_load_anim_data( &player.mdl.meta, vg_mem.rtmemory );
+
+ vg_linear_clear( vg_mem.scratch );
+ mdl_load_mesh_data( &player.mdl.meta, vg_mem.scratch );
+ mdl_close( &player.mdl.meta );
+
+ /*
+ * load in other player models. This may need to be more sophisticated in
+ * the futre if we have more of these guys
+ */
+ mdl_context ctx_outlaw,
+ ctx_jordan;
+
+ mdl_open( &ctx_outlaw, "models/ch_outlaw.mdl" );
+ mdl_load_metadata( &ctx_outlaw, vg_mem.scratch );
+ mdl_load_mesh_data( &ctx_outlaw, vg_mem.scratch );
+ mdl_close( &ctx_outlaw );
+
+ mdl_open( &ctx_jordan, "models/ch_jordan.mdl" );
+ mdl_load_metadata( &ctx_jordan, vg_mem.scratch );
+ mdl_load_mesh_data( &ctx_jordan, vg_mem.scratch );
+ mdl_close( &ctx_jordan );
+
+ vg_acquire_thread_sync();
{
- vg_error( "Could not load model\n" );
- return;
+ mdl_unpack_glmesh( &player.mdl.meta, &player.mdl.player_meshes[0] );
+ mdl_unpack_glmesh( &ctx_outlaw, &player.mdl.player_meshes[1] );
+ mdl_unpack_glmesh( &ctx_jordan, &player.mdl.player_meshes[2] );
}
+ vg_release_thread_sync();
- mesh_free( &player.mdl.mesh );
- mdl_unpack_glmesh( src, &player.mdl.mesh );
+ skeleton_setup( &player.mdl.sk, vg_mem.rtmemory, &player.mdl.meta );
+ player_init_ragdoll();
- if( !replace_mode )
+ /*
+ * Link animations
+ */
+ struct _load_anim
{
- if( !skeleton_setup( &player.mdl.sk, src ) )
- {
- vg_error( "Model: %s\n", buf );
- vg_fatal_exit_loop( "No skeleton" );
- }
-
- /*
- * Link animations
- */
- struct _load_anim
- {
- const char *name;
- struct skeleton_anim **anim;
- }
- anims[] = {
- { "pose_stand", &player.mdl.anim_stand },
- { "pose_highg", &player.mdl.anim_highg },
- { "pose_slide", &player.mdl.anim_slide },
- { "pose_air", &player.mdl.anim_air },
- { "push", &player.mdl.anim_push },
- { "push_reverse", &player.mdl.anim_push_reverse },
- { "ollie", &player.mdl.anim_ollie },
- { "ollie_reverse",&player.mdl.anim_ollie_reverse },
- { "grabs", &player.mdl.anim_grabs },
- { "walk", &player.mdl.anim_walk },
- { "run", &player.mdl.anim_run },
- { "idle_cycle", &player.mdl.anim_idle },
- { "jump", &player.mdl.anim_jump }
- };
+ const char *name;
+ struct skeleton_anim **anim;
+ }
+ anims[] = {
+ { "pose_stand", &player.mdl.anim_stand },
+ { "pose_highg", &player.mdl.anim_highg },
+ { "pose_slide", &player.mdl.anim_slide },
+ { "pose_air", &player.mdl.anim_air },
+ { "push", &player.mdl.anim_push },
+ { "push_reverse", &player.mdl.anim_push_reverse },
+ { "ollie", &player.mdl.anim_ollie },
+ { "ollie_reverse",&player.mdl.anim_ollie_reverse },
+ { "grabs", &player.mdl.anim_grabs },
+ { "walk", &player.mdl.anim_walk },
+ { "run", &player.mdl.anim_run },
+ { "idle_cycle", &player.mdl.anim_idle },
+ { "jump", &player.mdl.anim_jump }
+ };
+
+ for( int i=0; i<vg_list_size(anims); i++ )
+ {
+ *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
- for( int i=0; i<vg_list_size(anims); i++ )
+ if( !(*anims[i].anim) )
{
- *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
-
- if( !(*anims[i].anim) )
- {
- vg_error( "Animation '%s' is missing from character '%s'\n",
- anims[i].name, name );
- vg_free( src );
- return;
- }
+ vg_error( "Animation '%s' is missing\n", anims[i].name );
+ vg_fatal_exit_loop( "Invalid character file" );
}
+ }
- /*
- * Link bones
- */
- struct _load_bone
- {
- const char *name;
- u32 *bone_id;
- }
- bones[] = {
- { "hips", &player.mdl.id_hip },
- { "hand.IK.L", &player.mdl.id_ik_hand_l },
- { "hand.IK.R", &player.mdl.id_ik_hand_r },
- { "elbow.L", &player.mdl.id_ik_elbow_l },
- { "elbow.R", &player.mdl.id_ik_elbow_r },
- { "head", &player.mdl.id_head }
- };
+ /*
+ * Link bones
+ */
+ struct _load_bone
+ {
+ const char *name;
+ u32 *bone_id;
+ }
+ bones[] = {
+ { "hips", &player.mdl.id_hip },
+ { "hand.IK.L", &player.mdl.id_ik_hand_l },
+ { "hand.IK.R", &player.mdl.id_ik_hand_r },
+ { "elbow.L", &player.mdl.id_ik_elbow_l },
+ { "elbow.R", &player.mdl.id_ik_elbow_r },
+ { "head", &player.mdl.id_head }
+ };
+
+ for( int i=0; i<vg_list_size(bones); i++ )
+ {
+ *bones[i].bone_id = skeleton_bone_id( &player.mdl.sk, bones[i].name );
- for( int i=0; i<vg_list_size(bones); i++ )
+ if( !(*bones[i].bone_id) )
{
- *bones[i].bone_id = skeleton_bone_id( &player.mdl.sk, bones[i].name );
-
- if( !(*bones[i].bone_id) )
- {
- vg_error( "Required bone '%s' is missing from character '%s'\n",
- bones[i].name, name );
- vg_free( src );
- return;
- }
+ vg_error( "Required bone '%s' is missing\n", bones[i].name );
+ vg_fatal_exit_loop( "Invalid character file" );
}
-
- player_init_ragdoll( src );
}
-
- vg_free( src );
}
#endif
#include "player.h"
#include "camera.h"
-static void apply_gravity( v3f vel, float const timestep )
+VG_STATIC void apply_gravity( v3f vel, float const timestep )
{
v3f gravity = { 0.0f, -9.6f, 0.0f };
v3_muladds( vel, gravity, timestep, vel );
/*
* Called when launching into the air to predict and adjust trajectories
*/
-static void player_start_air(void)
+VG_STATIC void player_start_air(void)
{
struct player_phys *phys = &player.phys;
/*
* Main friction interface model
*/
-static void player_physics_control(void)
+VG_STATIC void player_physics_control(void)
{
struct player_phys *phys = &player.phys;
/*
* Air control, no real physics
*/
-static void player_physics_control_air(void)
+VG_STATIC void player_physics_control_air(void)
{
struct player_phys *phys = &player.phys;
* Entire Walking physics model
* TODO: sleep when under certain velotiy
*/
-static void player_walk_physics(void)
+VG_STATIC void player_walk_physics(void)
{
struct player_phys *phys = &player.phys;
rigidbody *rbf = &player.collide_front,
/*
* Physics collision detection, and control
*/
-static void player_physics(void)
+VG_STATIC void player_physics(void)
{
struct player_phys *phys = &player.phys;
/*
phys->jump = vg_clampf( phys->jump, 0.0f, 1.0f );
}
-static void player_save_frame(void)
+VG_STATIC void player_save_frame(void)
{
player.phys_gate_frame = player.phys;
}
-static void player_restore_frame(void)
+VG_STATIC void player_restore_frame(void)
{
player.phys = player.phys_gate_frame;
rb_update_transform( &player.phys.rb );
}
-static void player_do_motion(void)
+VG_STATIC void player_do_motion(void)
{
struct player_phys *phys = &player.phys;
/*
* Gate intersection, by tracing a line over the gate planes
*/
- for( int i=0; i<world_routes.gate_count; i++ )
+ for( int i=0; i<world.gate_count; i++ )
{
- struct route_gate *rg = &world_routes.gates[i];
+ struct route_gate *rg = &world.gates[i];
teleport_gate *gate = &rg->gate;
if( gate_intersect( gate, phys->rb.co, prevco ) )
/*
* Free camera movement
*/
-static void player_mouseview(void)
+VG_STATIC void player_mouseview(void)
{
- if( gui_want_mouse() )
+ if( ui_want_mouse() )
return;
static v2f mouse_last,
player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
}
-static void player_freecam(void)
+VG_STATIC void player_freecam(void)
{
player_mouseview();
v3_add( move_vel, player.camera_pos, player.camera_pos );
}
-static int reset_player( int argc, char const *argv[] )
+VG_STATIC int reset_player( int argc, char const *argv[] )
{
struct player_phys *phys = &player.phys;
struct respawn_point *rp = NULL, *r;
#include "player.h"
-static float k_ragdoll_floatyiness = 20.0f,
+VG_STATIC float k_ragdoll_floatyiness = 20.0f,
k_ragdoll_floatydrag = 1.0f;
/*
* Setup ragdoll colliders
*/
-static void player_init_ragdoll( mdl_header *src )
+VG_STATIC void player_init_ragdoll(void)
{
struct player_model *mdl = &player.mdl;
+ mdl_context *src = &mdl->meta;
if( !mdl->sk.collider_count )
{
return;
}
- mdl->ragdoll = vg_alloc(sizeof(struct ragdoll_part)*mdl->sk.collider_count);
mdl->ragdoll_count = 0;
for( u32 i=0; i<mdl->sk.bone_count; i ++ )
if( bone->collider )
{
+ if( mdl->ragdoll_count > vg_list_size(player.mdl.ragdoll) )
+ vg_fatal_exit_loop( "Playermodel has too many colliders" );
+
struct ragdoll_part *rp = &mdl->ragdoll[ mdl->ragdoll_count ++ ];
rp->bone_id = i;
/*
* Make the player model copy the ragdoll
*/
-static void player_model_copy_ragdoll(void)
+VG_STATIC void player_model_copy_ragdoll(void)
{
struct player_model *mdl = &player.mdl;
/*
* Make the ragdoll copy the player model
*/
-static void player_ragdoll_copy_model( v3f v )
+VG_STATIC void player_ragdoll_copy_model( v3f v )
{
struct player_model *mdl = &player.mdl;
/*
* Draw rigidbody colliders for ragdoll
*/
-static void player_debug_ragdoll(void)
+VG_STATIC void player_debug_ragdoll(void)
{
struct player_model *mdl = &player.mdl;
/*
* Ragdoll physics step
*/
-static void player_ragdoll_iter(void)
+VG_STATIC void player_ragdoll_iter(void)
{
struct player_model *mdl = &player.mdl;
rb_solver_reset();
#include "shaders/standard.h"
#include "shaders/vblend.h"
-static void render_water_texture( m4x3f camera );
-static void render_water_surface( m4x4f pv, m4x3f camera );
-static void render_world( m4x4f projection, m4x3f camera );
-static void shader_link_standard_ub( GLuint shader, int texture_id );
-static void render_world_depth( m4x4f projection, m4x3f camera );
+VG_STATIC void render_water_texture( m4x3f camera );
+VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera );
+VG_STATIC void render_world( m4x4f projection, m4x3f camera );
+VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id );
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera );
#ifndef RENDER_H
#define RENDER_H
int allocated;
};
-static struct pipeline
+VG_STATIC struct pipeline
{
float fov;
glmesh fsquad;
/*
* http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
*/
-static void plane_clip_projection( m4x4f mat, v4f plane )
+VG_STATIC void plane_clip_projection( m4x4f mat, v4f plane )
{
v4f c =
{
mat[3][2] = c[3];
}
-static void pipeline_projection( m4x4f mat, float nearz, float farz )
+VG_STATIC void pipeline_projection( m4x4f mat, float nearz, float farz )
{
m4x4_projection( mat,
gpipeline.fov,
/*
* Shaders
*/
-static void shader_link_standard_ub( GLuint shader, int texture_id )
+VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id )
{
GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
glUniformBlockBinding( shader, idx, 0 );
glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
}
-static void render_update_lighting_ub(void)
+VG_STATIC void render_update_lighting_ub(void)
{
struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
int c = 0;
* Framebuffers
*/
-static void fb_use( struct framebuffer *fb )
+VG_STATIC void fb_use( struct framebuffer *fb )
{
if( !fb )
{
}
}
-static void fb_init( struct framebuffer *fb )
+VG_STATIC void fb_init( struct framebuffer *fb )
{
i32 ix = vg.window_x / fb->div,
iy = vg.window_y / fb->div;
fb->allocated = 1;
}
-static void fb_free( struct framebuffer *fb )
+VG_STATIC void fb_free( struct framebuffer *fb )
{
glDeleteTextures( 1, &fb->colour );
glDeleteFramebuffers( 1, &fb->fb );
}
-static void fb_bindtex( struct framebuffer *fb, int texture )
+VG_STATIC void fb_bindtex( struct framebuffer *fb, int texture )
{
glActiveTexture( GL_TEXTURE0 + texture );
glBindTexture( GL_TEXTURE_2D, fb->colour );
}
-static void fb_resize( struct framebuffer *fb )
+VG_STATIC void fb_resize( struct framebuffer *fb )
{
if( !fb->allocated )
return;
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
}
-static void render_fb_resize(void)
+VG_STATIC void render_fb_resize(void)
{
if( gpipeline.ready )
{
}
/* used for drawing player onto */
-static void render_init_temp_buffer(void)
+VG_STATIC void render_init_temp_buffer(void)
{
vg_info( "[render] Allocate temporary framebuffer\n" );
/* used for drawing world depth from the top view, used in our water and
* lighting calculations */
-static void render_init_depthmap_buffer(void)
+VG_STATIC void render_init_depthmap_buffer(void)
{
vg_info( "[render] Allocate depth map buffer\n" );
VG_CHECK_GL_ERR();
}
-static void render_init_fs_quad(void)
+VG_STATIC void render_init_fs_quad(void)
{
vg_info( "[render] Allocate quad\n" );
VG_CHECK_GL_ERR();
}
-static void render_init_uniform_buffers(void)
+VG_STATIC void render_init_uniform_buffers(void)
{
vg_info( "[render] Allocate uniform buffer\n" );
VG_CHECK_GL_ERR();
}
-static void render_init(void)
+VG_STATIC void render_init(void)
{
shader_blit_register();
shader_standard_register();
vg_release_thread_sync();
}
-static void render_free(void *_)
-{
- glDeleteBuffers( 1, &gpipeline.ubo_world_lighting );
-
- glDeleteVertexArrays( 1, &gpipeline.fsquad.vao );
- glDeleteBuffers( 1, &gpipeline.fsquad.vbo );
-
- glDeleteFramebuffers( 1, &gpipeline.fb_depthmap );
- glDeleteTextures( 1, &gpipeline.rgb_depthmap );
-
- glDeleteFramebuffers( 1, &gpipeline.fb_background );
- glDeleteTextures( 1, &gpipeline.rgb_background );
-}
-
/*
* Utility
*/
-static void render_fsquad(void)
+VG_STATIC void render_fsquad(void)
{
glBindVertexArray( gpipeline.fsquad.vao );
glDrawArrays( GL_TRIANGLES, 0, 6 );
#include "bvh.h"
#include "scene.h"
-static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
-static bh_system bh_system_rigidbodies;
+VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty );
+VG_STATIC bh_system bh_system_rigidbodies;
#ifndef RIGIDBODY_H
#define RIGIDBODY_H
* -----------------------------------------------------------------------------
*/
-static const float
+VG_STATIC const float
k_rb_rate = (1.0/VG_TIMESTEP_FIXED),
k_rb_delta = (1.0/k_rb_rate),
k_friction = 0.6f,
struct rb_scene
{
- scene *pscene;
+ bh_tree *bh_scene;
}
scene;
}
m4x3f to_world, to_local;
};
-static struct contact
+VG_STATIC struct contact
{
rigidbody *rba, *rbb;
v3f co, n;
u32 element_id;
}
rb_contact_buffer[256];
-static int rb_contact_count = 0;
+VG_STATIC int rb_contact_count = 0;
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
-static float sphere_volume( float radius )
+VG_STATIC float sphere_volume( float radius )
{
float r3 = radius*radius*radius;
return (4.0f/3.0f) * VG_PIf * r3;
}
-static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
+VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty )
{
/* Compute tangent basis (box2d) */
if( fabsf( n[0] ) >= 0.57735027f )
* -----------------------------------------------------------------------------
*/
-static void rb_debug_contact( rb_ct *ct )
+VG_STATIC void rb_debug_contact( rb_ct *ct )
{
v3f p1;
v3_muladds( ct->co, ct->n, 0.1f, p1 );
vg_line( ct->co, p1, 0xffffffff );
}
-static void debug_sphere( m4x3f m, float radius, u32 colour )
+VG_STATIC void debug_sphere( m4x3f m, float radius, u32 colour )
{
v3f ly = { 0.0f, 0.0f, radius },
lx = { 0.0f, radius, 0.0f },
}
}
-static void debug_capsule( m4x3f m, float radius, float h, u32 colour )
+VG_STATIC void debug_capsule( m4x3f m, float radius, float h, u32 colour )
{
v3f ly = { 0.0f, 0.0f, radius },
lx = { 0.0f, radius, 0.0f },
}
}
-static void rb_debug( rigidbody *rb, u32 colour )
+VG_STATIC void rb_debug( rigidbody *rb, u32 colour )
{
if( rb->type == k_rb_shape_box )
{
/*
* Update world space bounding box based on local one
*/
-static void rb_update_bounds( rigidbody *rb )
+VG_STATIC void rb_update_bounds( rigidbody *rb )
{
box_copy( rb->bbx, rb->bbx_world );
m4x3_transform_aabb( rb->to_world, rb->bbx_world );
/*
* Commit transform to rigidbody. Updates matrices
*/
-static void rb_update_transform( rigidbody *rb )
+VG_STATIC void rb_update_transform( rigidbody *rb )
{
q_normalize( rb->q );
q_m3x3( rb->q, rb->to_world );
* Extrapolate rigidbody into a transform based on vg accumulator.
* Useful for rendering
*/
-static void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
+VG_STATIC void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
{
float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f );
/*
* Initialize rigidbody and calculate masses, inertia
*/
-static void rb_init( rigidbody *rb )
+VG_STATIC void rb_init( rigidbody *rb )
{
float volume = 1.0f;
else if( rb->type == k_rb_shape_scene )
{
rb->is_world = 1;
- box_copy( rb->inf.scene.pscene->bbx, rb->bbx );
+ box_copy( rb->inf.scene.bh_scene->nodes[0].bbx, rb->bbx );
}
if( rb->is_world )
rb_update_transform( rb );
}
-static void rb_iter( rigidbody *rb )
+VG_STATIC void rb_iter( rigidbody *rb )
{
v3f gravity = { 0.0f, -9.8f, 0.0f };
v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
* These closest point tests were learned from Real-Time Collision Detection by
* Christer Ericson
*/
-static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
+VG_STATIC float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
float *s, float *t, v3f c1, v3f c2)
{
v3f d1,d2,r;
return v3_length2( v0 );
}
-static void closest_point_aabb( v3f p, boxf box, v3f dest )
+VG_STATIC void closest_point_aabb( v3f p, boxf box, v3f dest )
{
v3_maxv( p, box[0], dest );
v3_minv( dest, box[1], dest );
}
-static void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
+VG_STATIC void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
{
v3f local;
m4x3_mulv( rb->to_local, p, local );
m4x3_mulv( rb->to_world, local, dest );
}
-static float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
+VG_STATIC float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
{
v3f v0, v1;
v3_sub( b, a, v0 );
return t;
}
-static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
+VG_STATIC void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
{
v3f ab, ac, ap;
float d1, d2;
v3_muladds( dest, ac, w, dest );
}
-static void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
+VG_STATIC void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
{
v3f ab, ac, ap;
float d1, d2;
/*
* Project AABB, and triangle interval onto axis to check if they overlap
*/
-static int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
+VG_STATIC int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
{
float
/*
* Seperating axis test box vs triangle
*/
-static int rb_box_triangle_sat( rigidbody *rba, v3f tri_src[3] )
+VG_STATIC int rb_box_triangle_sat( rigidbody *rba, v3f tri_src[3] )
{
v3f tri[3];
* Expand a line manifold with a new pair. t value is the time along segment
* on the oriented object which created this pair.
*/
-static void rb_capsule_manifold( v3f pa, v3f pb, float t, float r,
+VG_STATIC void rb_capsule_manifold( v3f pa, v3f pb, float t, float r,
capsule_manifold *manifold )
{
v3f delta;
}
}
-static void rb_capsule_manifold_init( capsule_manifold *manifold )
+VG_STATIC void rb_capsule_manifold_init( capsule_manifold *manifold )
{
manifold->t0 = INFINITY;
manifold->t1 = -INFINITY;
}
-static int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb,
+VG_STATIC int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb,
capsule_manifold *manifold, rb_ct *buf )
{
float h = rba->inf.capsule.height,
return count;
}
-static int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
float h = rba->inf.capsule.height,
ra = rba->inf.capsule.radius,
return 0;
}
-static int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
float ha = rba->inf.capsule.height,
hb = rbb->inf.capsule.height,
/*
* Generates up to two contacts; optimised for the most stable manifold
*/
-static int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
float h = rba->inf.capsule.height,
r = rba->inf.capsule.radius;
return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
}
-static int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
v3f co, delta;
return 0;
}
-static int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
v3f delta;
v3_sub( rba->co, rbb->co, delta );
return 0;
}
-static int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
+VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
v3f tri[3], rb_ct *buf )
{
v3f delta, co;
return 0;
}
-static int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
- scene *sc = rbb->inf.scene.pscene;
+ scene *sc = rbb->inf.scene.bh_scene->user;
u32 geo[128];
v3f tri[3];
- int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+ int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
int count = 0;
for( int i=0; i<len; i++ )
{
- u32 *ptri = &sc->indices[ geo[i]*3 ];
+ u32 *ptri = &sc->arrindices[ geo[i]*3 ];
for( int j=0; j<3; j++ )
- v3_copy( sc->verts[ptri[j]].co, tri[j] );
+ v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
vg_line(tri[0],tri[1],0xff00ff00 );
vg_line(tri[1],tri[2],0xff00ff00 );
return count;
}
-static int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
- scene *sc = rbb->inf.scene.pscene;
+ scene *sc = rbb->inf.scene.bh_scene->user;
u32 geo[128];
v3f tri[3];
- int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+ int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
int count = 0;
for( int i=0; i<len; i++ )
{
- u32 *ptri = &sc->indices[ geo[i]*3 ];
+ u32 *ptri = &sc->arrindices[ geo[i]*3 ];
for( int j=0; j<3; j++ )
- v3_copy( sc->verts[ptri[j]].co, tri[j] );
+ v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
if( rb_box_triangle_sat( rba, tri ) )
{
return count;
}
-static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
vg_error( "Collision type is unimplemented between types %d and %d\n",
rba->type, rbb->type );
return 0;
}
-static int rb_sphere_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
return rb_capsule_sphere( rbb, rba, buf );
}
-static int rb_box_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
return rb_capsule_box( rbb, rba, buf );
}
-static int rb_box_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
return rb_sphere_box( rbb, rba, buf );
}
-static int rb_scene_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_scene_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
return rb_box_scene( rbb, rba, buf );
}
-static int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) =
+VG_STATIC int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) =
{
/* box */ /* Sphere */ /* Capsule */ /* Mesh */
{ RB_MATRIX_ERROR, rb_box_sphere, rb_box_capsule, rb_box_scene },
{ rb_scene_box, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
};
-static int rb_collide( rigidbody *rba, rigidbody *rbb )
+VG_STATIC int rb_collide( rigidbody *rba, rigidbody *rbb )
{
int (*collider_jump)(rigidbody *rba, rigidbody *rbb, rb_ct *buf )
= rb_jump_table[rba->type][rbb->type];
* -----------------------------------------------------------------------------
*/
-static void rb_solver_reset(void)
+VG_STATIC void rb_solver_reset(void)
{
rb_contact_count = 0;
}
-static rb_ct *rb_global_ct(void)
+VG_STATIC rb_ct *rb_global_ct(void)
{
return rb_contact_buffer + rb_contact_count;
}
/*
* Initializing things like tangent vectors
*/
-static void rb_presolve_contacts( rb_ct *buffer, int len )
+VG_STATIC void rb_presolve_contacts( rb_ct *buffer, int len )
{
for( int i=0; i<len; i++ )
{
/*
* Creates relative contact velocity vector, and offsets between each body
*/
-static void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
+VG_STATIC void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
{
rigidbody *rba = ct->rba,
*rbb = ct->rbb;
/*
* Apply impulse to object
*/
-static void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
+VG_STATIC void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
{
/* linear */
v3_muladds( rb->v, impulse, rb->inv_mass, rb->v );
/*
* One iteration to solve the contact constraint
*/
-static void rb_solve_contacts( rb_ct *buf, int len )
+VG_STATIC void rb_solve_contacts( rb_ct *buf, int len )
{
for( int i=0; i<len; i++ )
{
* -----------------------------------------------------------------------------
*/
-static void draw_angle_limit( v3f c, v3f major, v3f minor,
+VG_STATIC void draw_angle_limit( v3f c, v3f major, v3f minor,
float amin, float amax, float measured,
u32 colour )
{
vg_line( c, p2, colour );
}
-static void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
+VG_STATIC void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
v3f limits[2] )
{
v3f ax, ay, az, bx, by, bz;
draw_angle_limit( c, ax, ay, limits[0][2], limits[1][2], r2, 0xffff0000 );
}
-static void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
+VG_STATIC void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
{
if( d != 0.0f )
{
}
}
-static void rb_constraint_limits( rigidbody *ra, v3f lca,
+VG_STATIC void rb_constraint_limits( rigidbody *ra, v3f lca,
rigidbody *rb, v3f lcb, v3f limits[2] )
{
v3f ax, ay, az, bx, by, bz;
rb_limit_cure( ra, rb, az, dz );
}
-static void rb_debug_constraint_position( rigidbody *ra, v3f lca,
+VG_STATIC void rb_debug_constraint_position( rigidbody *ra, v3f lca,
rigidbody *rb, v3f lcb )
{
v3f wca, wcb;
vg_line( p0, p1, 0xffffff00 );
}
-static void rb_constraint_position( rigidbody *ra, v3f lca,
+VG_STATIC void rb_constraint_position( rigidbody *ra, v3f lca,
rigidbody *rb, v3f lcb )
{
/* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
* Effectors
*/
-static void rb_effect_simple_bouyency( rigidbody *ra, v4f plane,
+VG_STATIC void rb_effect_simple_bouyency( rigidbody *ra, v4f plane,
float amt, float drag )
{
/* float */
/*
* -----------------------------------------------------------------------------
- * BVH implementation, this is ONLY for static rigidbodies, its to slow for
+ * BVH implementation, this is ONLY for VG_STATIC rigidbodies, its to slow for
* realtime use.
* -----------------------------------------------------------------------------
*/
-static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
+VG_STATIC void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
{
rigidbody *rb = &((rigidbody *)user)[ item_index ];
box_concat( bound, rb->bbx_world );
}
-static float rb_bh_centroid( void *user, u32 item_index, int axis )
+VG_STATIC float rb_bh_centroid( void *user, u32 item_index, int axis )
{
rigidbody *rb = &((rigidbody *)user)[ item_index ];
return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
}
-static void rb_bh_swap( void *user, u32 ia, u32 ib )
+VG_STATIC void rb_bh_swap( void *user, u32 ia, u32 ib )
{
rigidbody temp, *rba, *rbb;
rba = &((rigidbody *)user)[ ia ];
*rbb = temp;
}
-static void rb_bh_debug( void *user, u32 item_index )
+VG_STATIC void rb_bh_debug( void *user, u32 item_index )
{
rigidbody *rb = &((rigidbody *)user)[ item_index ];
rb_debug( rb, 0xff00ffff );
}
-static bh_system bh_system_rigidbodies =
+VG_STATIC bh_system bh_system_rigidbodies =
{
.expand_bound = rb_bh_expand_bound,
.item_centroid = rb_bh_centroid,
struct scene
{
- glmesh mesh;
+ mdl_vert *arrvertices;
+ u32 *arrindices;
- mdl_vert *verts;
- u32 *indices;
-
- bh_tree bhtris;
- u32 vertex_count,
- indice_count,
- vertex_cap,
- indice_cap;
+ u32 vertex_count, indice_count,
+ max_vertices, max_indices;
boxf bbx;
-
- u32 shadower_count,
- shadower_cap;
-
mdl_submesh submesh;
};
-static void scene_init( scene *pscene )
+/* Initialize a scene description with bounded buffers */
+VG_STATIC scene *scene_init( void *lin_alloc, u32 max_verts, u32 max_indices )
{
- pscene->verts = NULL;
- pscene->indices = NULL;
+ u32 vertex_length = max_verts * sizeof(mdl_vert),
+ index_length = max_indices * sizeof(u32),
+ tot_size = sizeof(scene) + vertex_length + index_length;
+
+ scene *pscene = vg_linear_alloc( lin_alloc, tot_size );
+
+ pscene->arrvertices = (mdl_vert *)(pscene+1);
+ pscene->arrindices = (u32 *)( pscene->arrvertices + max_verts );
+
pscene->vertex_count = 0;
pscene->indice_count = 0;
- pscene->shadower_count = 0;
- pscene->shadower_cap = 0;
+ pscene->max_vertices = max_verts;
+ pscene->max_indices = max_indices;
+
pscene->submesh.indice_start = 0;
pscene->submesh.indice_count = 0;
v3_fill( pscene->bbx[0], 999999.9f );
v3_fill( pscene->bbx[1], -999999.9f );
+
+ return pscene;
}
/*
* Append a model into the scene with a given transform
*/
-static void scene_add_submesh( scene *pscene, mdl_header *mdl,
- mdl_submesh *sm, m4x3f transform )
+VG_STATIC void scene_add_submesh( scene *pscene, mdl_context *mdl,
+ mdl_submesh *sm, m4x3f transform )
{
- pscene->verts = buffer_reserve( pscene->verts, pscene->vertex_count,
- &pscene->vertex_cap, sm->vertex_count, sizeof(mdl_vert) );
+ if( pscene->vertex_count + sm->vertex_count > pscene->max_vertices )
+ {
+ vg_error( "%u(current) + %u > %u\n", pscene->vertex_count,
+ sm->vertex_count,
+ pscene->max_vertices );
- pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count,
- &pscene->indice_cap, sm->indice_count, sizeof(u32) );
+ vg_warn( "%p ... %p\n", pscene, sm );
+ vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+ }
- m3x3f normal_matrix;
- m3x3_copy( transform, normal_matrix );
- v3_normalize( normal_matrix[0] );
- v3_normalize( normal_matrix[1] );
- v3_normalize( normal_matrix[2] );
+ if( pscene->indice_count + sm->indice_count > pscene->max_indices )
+ {
+ vg_error( "%u(current) + %u > %u\n", pscene->indice_count,
+ sm->indice_count,
+ pscene->max_indices );
+ vg_warn( "%p ... %p\n", pscene, sm );
+
+ vg_fatal_exit_loop( "Scene index buffer overflow" );
+ }
+
+ mdl_vert *src_verts = mdl_submesh_vertices( mdl, sm ),
+ *dst_verts = &pscene->arrvertices[ pscene->vertex_count ];
+
+ u32 *src_indices = mdl_submesh_indices( mdl, sm ),
+ *dst_indices = &pscene->arrindices[ pscene->indice_count ];
/* Transform and place vertices */
- mdl_vert *src_verts = mdl_submesh_vertices( mdl, sm );
- u32 *src_indices = mdl_submesh_indices( mdl, sm );
-
boxf bbxnew;
box_copy( sm->bbx, bbxnew );
m4x3_transform_aabb( transform, bbxnew );
box_concat( pscene->bbx, bbxnew );
+
+ m3x3f normal_matrix;
+ m3x3_copy( transform, normal_matrix );
+ v3_normalize( normal_matrix[0] );
+ v3_normalize( normal_matrix[1] );
+ v3_normalize( normal_matrix[2] );
for( u32 i=0; i<sm->vertex_count; i++ )
{
- mdl_vert *pvert = &pscene->verts[ pscene->vertex_count+i ],
+ mdl_vert *pvert = &dst_verts[ i ],
*src = &src_verts[ i ];
m4x3_mulv( transform, src->co, pvert->co );
for( u32 i=0; i<sm->indice_count; i++ )
{
- u32 *pidx = &pscene->indices[ pscene->indice_count+i ];
- *pidx = src_indices[i] + pscene->vertex_count;
+ dst_indices[i] = src_indices[i] + pscene->vertex_count;
}
pscene->vertex_count += sm->vertex_count;
pscene->indice_count += sm->indice_count;
+
}
/*
* One by one adders for simplified access (mostly procedural stuff)
*/
-static void scene_push_tri( scene *pscene, u32 tri[3] )
+VG_STATIC void scene_push_tri( scene *pscene, u32 tri[3] )
{
- pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count,
- &pscene->indice_cap, 3, sizeof(u32) );
+ if( pscene->indice_count + 3 > pscene->max_indices )
+ vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+
+ u32 *dst = &pscene->arrindices[ pscene->indice_count ];
- u32 *dst = &pscene->indices[pscene->indice_count];
dst[0] = tri[0];
dst[1] = tri[1];
dst[2] = tri[2];
pscene->indice_count += 3;
}
-static void scene_push_vert( scene *pscene, mdl_vert *v )
+VG_STATIC void scene_push_vert( scene *pscene, mdl_vert *v )
{
- pscene->verts = buffer_reserve( pscene->verts, pscene->vertex_count,
- &pscene->vertex_cap, 1, sizeof(mdl_vert) );
- pscene->verts[pscene->vertex_count ++] = *v;
+ if( pscene->vertex_count + 1 > pscene->max_vertices )
+ vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+
+ mdl_vert *dst = &pscene->arrvertices[ pscene->vertex_count ];
+ *dst = *v;
+
+ pscene->vertex_count ++;
}
-static void scene_copy_slice( scene *pscene, mdl_submesh *sm )
+VG_STATIC void scene_copy_slice( scene *pscene, mdl_submesh *sm )
{
sm->indice_start = pscene->submesh.indice_start;
sm->indice_count = pscene->indice_count - sm->indice_start;
pscene->submesh.vertex_start = pscene->vertex_count;
}
-static void scene_fix( scene *pscene )
+/* finalization: tightly pack data */
+__attribute__((warn_unused_result))
+VG_STATIC scene *scene_fix( void *lin_alloc, scene *pscene )
{
- buffer_fix( pscene->verts, pscene->vertex_count,
- &pscene->vertex_cap, sizeof( mdl_vert ));
+ u32 vertex_length = pscene->vertex_count * sizeof(mdl_vert),
+ index_length = pscene->indice_count * sizeof(u32),
+ tot_size = sizeof(scene) + vertex_length + index_length;
- buffer_fix( pscene->indices, pscene->indice_count,
- &pscene->indice_cap, sizeof( mdl_vert ));
-}
+ scene *src_scene = pscene;
+ mdl_vert *src_verts = pscene->arrvertices;
+ u32 *src_indices = pscene->arrindices;
-static void scene_upload( scene *pscene )
-{
- mesh_upload( &pscene->mesh,
- pscene->verts, pscene->vertex_count,
- pscene->indices, pscene->indice_count );
+ scene *dst_scene = vg_linear_resize( lin_alloc, pscene, tot_size );
+ memcpy( dst_scene, src_scene, sizeof(scene) );
- vg_info( "Scene upload\n" );
- vg_info( " indices:%u\n", pscene->indice_count );
- vg_info( " verts:%u\n", pscene->vertex_count );
-}
+ void *dst_verts = dst_scene+1,
+ *dst_indices = dst_verts + vertex_length;
-static void scene_bind( scene *pscene )
-{
- mesh_bind( &pscene->mesh );
-}
+ memcpy( dst_verts, src_verts, vertex_length );
+ memcpy( dst_indices, src_indices, index_length );
-static void scene_draw( scene *pscene )
-{
- mesh_drawn( 0, pscene->indice_count );
+ dst_scene->arrvertices = dst_verts;
+ dst_scene->arrindices = dst_indices;
+ dst_scene->max_vertices = pscene->vertex_count;
+ dst_scene->max_indices = pscene->indice_count;
+
+ return dst_scene;
}
-static void scene_free_offline_buffers( scene *pscene )
+#if 0
+/* finalization: delete any offline buffers and reduce size */
+__attribute__((warn_unused_result))
+VG_STATIC scene *scene_free_offline_buffers( void *lin_alloc, scene *pscene )
{
- vg_free( pscene->verts );
- vg_free( pscene->indices );
+ u32 tot_size = sizeof(scene);
+
+ scene *src_scene = pscene;
+ mdl_vert *src_verts = pscene->arrvertices;
+ u32 *src_indices = pscene->arrindices;
+
+ scene *dst_scene = vg_linear_resize( lin_alloc, pscene, tot_size );
+ memcpy( dst_scene, src_scene, sizeof(scene) );
+
+ dst_scene->arrindices = NULL;
+ dst_scene->arrvertices = NULL;
+
+ return dst_scene;
}
+#endif
-static void scene_free( scene *pscene )
+VG_STATIC void scene_upload( scene *pscene, glmesh *mesh )
{
- scene_free_offline_buffers( pscene );
+ mesh_upload( mesh,
+ pscene->arrvertices, pscene->vertex_count,
+ pscene->arrindices, pscene->indice_count );
+
+ vg_info( "Scene upload\n" );
+ vg_info( " indices:%u\n", pscene->indice_count );
+ vg_info( " verts:%u\n", pscene->vertex_count );
}
/*
* BVH implementation
*/
-static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index )
+VG_STATIC void scene_bh_expand_bound( void *user, boxf bound, u32 item_index )
{
scene *s = user;
- mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ],
- *pb = &s->verts[ s->indices[item_index*3+1] ],
- *pc = &s->verts[ s->indices[item_index*3+2] ];
+ mdl_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ],
+ *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ],
+ *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ];
box_addpt( bound, pa->co );
box_addpt( bound, pb->co );
box_addpt( bound, pc->co );
}
-static float scene_bh_centroid( void *user, u32 item_index, int axis )
+VG_STATIC float scene_bh_centroid( void *user, u32 item_index, int axis )
{
scene *s = user;
- mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ],
- *pb = &s->verts[ s->indices[item_index*3+1] ],
- *pc = &s->verts[ s->indices[item_index*3+2] ];
+ mdl_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ],
+ *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ],
+ *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ];
return (pa->co[axis] + pb->co[axis] + pc->co[axis]) * (1.0f/3.0f);
}
-static void scene_bh_swap( void *user, u32 ia, u32 ib )
+VG_STATIC void scene_bh_swap( void *user, u32 ia, u32 ib )
{
scene *s = user;
- u32 *ti = &s->indices[ia*3];
- u32 *tj = &s->indices[ib*3];
+ u32 *ti = &s->arrindices[ia*3];
+ u32 *tj = &s->arrindices[ib*3];
u32 temp[3];
temp[0] = ti[0];
tj[2] = temp[2];
}
-static void scene_bh_debug( void *user, u32 item_index )
+VG_STATIC void scene_bh_debug( void *user, u32 item_index )
{
scene *s = user;
u32 idx = item_index*3;
- mdl_vert *pa = &s->verts[ s->indices[ idx+0 ] ],
- *pb = &s->verts[ s->indices[ idx+1 ] ],
- *pc = &s->verts[ s->indices[ idx+2 ] ];
+ mdl_vert *pa = &s->arrvertices[ s->arrindices[ idx+0 ] ],
+ *pb = &s->arrvertices[ s->arrindices[ idx+1 ] ],
+ *pc = &s->arrvertices[ s->arrindices[ idx+2 ] ];
vg_line( pa->co, pb->co, 0xff0000ff );
vg_line( pb->co, pc->co, 0xff0000ff );
vg_line( pc->co, pa->co, 0xff0000ff );
}
-static int scene_bh_ray( void *user, u32 index, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int scene_bh_ray( void *user, u32 index, v3f co,
+ v3f dir, ray_hit *hit )
{
scene *s = user;
v3f positions[3];
- u32 *tri = &s->indices[ index*3 ];
+ u32 *tri = &s->arrindices[ index*3 ];
for( int i=0; i<3; i++ )
- v3_copy( s->verts[tri[i]].co, positions[i] );
+ v3_copy( s->arrvertices[tri[i]].co, positions[i] );
float t;
if(ray_tri( positions, co, dir, &t ))
return 0;
}
-static bh_system bh_system_scene =
+VG_STATIC bh_system bh_system_scene =
{
.expand_bound = scene_bh_expand_bound,
.item_centroid = scene_bh_centroid,
/*
* An extra step is added onto the end to calculate the hit normal
*/
-static int scene_raycast( scene *s, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int scene_raycast( scene *s, bh_tree *bh,
+ v3f co, v3f dir, ray_hit *hit )
{
- int count = bh_ray( &s->bhtris, 0, co, dir, hit );
+ int count = bh_ray( bh, co, dir, hit );
if( count )
{
v3f v0, v1;
- float *pa = s->verts[hit->tri[0]].co,
- *pb = s->verts[hit->tri[1]].co,
- *pc = s->verts[hit->tri[2]].co;
+ float *pa = s->arrvertices[hit->tri[0]].co,
+ *pb = s->arrvertices[hit->tri[1]].co,
+ *pc = s->arrvertices[hit->tri[2]].co;
v3_sub( pa, pb, v0 );
v3_sub( pc, pb, v1 );
return count;
}
-static void scene_bh_create( scene *s )
+VG_STATIC bh_tree *scene_bh_create( void *lin_alloc, scene *s )
{
u32 triangle_count = s->indice_count / 3;
- bh_create( &s->bhtris, &bh_system_scene, s, triangle_count );
+ return bh_create( lin_alloc, &bh_system_scene, s, triangle_count );
}
#endif
static u8 steam_symetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ];
static HSteamNetPollGroup client_pollgroup;
+#if 0
static void recieve_http( void *callresult, void *context )
{
HTTPRequestCompleted_t *result = callresult;
vg_free( buffer );
SteamAPI_ISteamHTTP_ReleaseHTTPRequest( hSteamHTTP, result->m_hRequest );
}
+#endif
static u64_steamid get_connection_authsteamid( SteamNetworkingMessage_t *msg )
{
/* TODO: Options to override, ammend, remove etc */
+ vg_prealloc_quota( 80*1024*1024 );
highscores_init( 250000, 10000 );
+
if( !highscores_read() )
highscores_create_db();
}
highscores_serialize_all();
- highscores_free();
SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
client_pollgroup );
int collider;
boxf hitbox;
- char name[16];
+ const char *name;
}
*bones;
+ u32 bone_count;
+
+ struct skeleton_anim
+ {
+ const char *name;
+ u32 length;
+
+ float rate;
+ mdl_keyframe *anim_data;
+ }
+ *anims;
+ u32 anim_count;
+
m4x3f *final_mtx;
struct skeleton_ik
m3x3f ia, ib;
}
*ik;
+ u32 ik_count;
- struct skeleton_anim
- {
- float rate;
- u32 length;
- struct mdl_keyframe *anim_data;
- char name[32];
- }
- *anims;
-
- u32 bone_count,
- ik_count,
+ u32
collider_count,
- anim_count,
- bindable_count; /* TODO: try to place IK last in the rig from export
- so that we dont always upload transforms for
- useless cpu IK bones. */
+ bindable_count;
};
-static u32 skeleton_bone_id( struct skeleton *skele, const char *name )
+VG_STATIC u32 skeleton_bone_id( struct skeleton *skele, const char *name )
{
- for( u32 i=0; i<skele->bone_count; i++ )
+ for( u32 i=1; i<skele->bone_count; i++ )
{
if( !strcmp( skele->bones[i].name, name ))
return i;
return 0;
}
-static void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
+VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
{
for( int i=0; i<num; i++ )
kfb[i] = kfa[i];
/*
* Lerp between two sets of keyframes and store in dest. Rotations use Nlerp.
*/
-static void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
+VG_STATIC void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
mdl_keyframe *kfd, int count )
{
if( t <= 0.01f )
}
}
-static void skeleton_lerp_pose( struct skeleton *skele,
+VG_STATIC void skeleton_lerp_pose( struct skeleton *skele,
mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
mdl_keyframe *kfd )
{
* Sample animation between 2 closest frames using time value. Output is a
* keyframe buffer that is allocated with an appropriate size
*/
-static void skeleton_sample_anim( struct skeleton *skele,
+VG_STATIC void skeleton_sample_anim( struct skeleton *skele,
struct skeleton_anim *anim,
float time,
mdl_keyframe *output )
skeleton_lerp_pose( skele, base, nbase, t, output );
}
-static int skeleton_sample_anim_clamped( struct skeleton *skele,
+VG_STATIC int skeleton_sample_anim_clamped( struct skeleton *skele,
struct skeleton_anim *anim,
float time,
mdl_keyframe *output )
}
anim_apply;
-static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
+VG_STATIC int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
{
struct skeleton_bone *sb = &skele->bones[ id ],
*sp = &skele->bones[ sb->parent ];
/*
* Apply block of keyframes to skeletons final pose
*/
-static void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
anim_apply passtype )
{
m4x3_identity( skele->final_mtx[0] );
* creates the reference inverse matrix for an IK bone, as it has an initial
* intrisic rotation based on the direction that the IK is setup..
*/
-static void skeleton_inverse_for_ik( struct skeleton *skele,
+VG_STATIC void skeleton_inverse_for_ik( struct skeleton *skele,
v3f ivaxis,
u32 id, m3x3f inverse )
{
/*
* Creates inverse rotation matrices which the IK system uses.
*/
-static void skeleton_create_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_create_inverses( struct skeleton *skele )
{
/* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */
for( int i=0; i<skele->ik_count; i++ )
m4x3f inverse;
v3f iv0, iv1, ivaxis;
v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 );
- v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 );
+ v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 );
v3_cross( iv0, iv1, ivaxis );
v3_normalize( ivaxis );
/*
* Apply a model matrix to all bones, should be done last
*/
-static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
+VG_STATIC void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
{
for( int i=0; i<skele->bone_count; i++ )
{
* Apply an inverse matrix to all bones which maps vertices from bind space into
* bone relative positions
*/
-static void skeleton_apply_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_apply_inverses( struct skeleton *skele )
{
for( int i=0; i<skele->bone_count; i++ )
{
/*
* Apply all IK modifiers (2 bone ik reference from blender is supported)
*/
-static void skeleton_apply_ik_pass( struct skeleton *skele )
+VG_STATIC void skeleton_apply_ik_pass( struct skeleton *skele )
{
for( int i=0; i<skele->ik_count; i++ )
{
* Applies the typical operations that you want for an IK rig:
* Pose, IK, Pose(deferred), Inverses, Transform
*/
-static void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
m4x3f transform )
{
skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik );
/*
* Get an animation by name
*/
-static struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
+VG_STATIC struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
const char *name )
{
for( int i=0; i<skele->anim_count; i++ )
return NULL;
}
-/* Setup an animated skeleton from model */
-static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
+VG_STATIC void skeleton_alloc_from( struct skeleton *skele,
+ void *lin_alloc,
+ struct classtype_skeleton *inf )
+{
+ skele->bone_count = inf->channels;
+ skele->ik_count = inf->ik_count;
+ skele->collider_count = inf->collider_count;
+ skele->anim_count = inf->anim_count;
+
+ u32 bone_size = sizeof(struct skeleton_bone) * skele->bone_count,
+ ik_size = sizeof(struct skeleton_ik) * skele->ik_count,
+ mtx_size = sizeof(m4x3f) * skele->bone_count,
+ anim_size = sizeof(struct skeleton_anim) * skele->anim_count;
+
+ skele->bones = vg_linear_alloc( lin_alloc, bone_size );
+ skele->ik = vg_linear_alloc( lin_alloc, ik_size );
+ skele->final_mtx = vg_linear_alloc( lin_alloc, mtx_size );
+ skele->anims = vg_linear_alloc( lin_alloc, anim_size );
+}
+
+VG_STATIC void skeleton_fatal_err(void)
+{
+ vg_fatal_exit_loop( "Skeleton setup failed" );
+}
+
+/* Setup an animated skeleton from model. mdl's metadata should stick around */
+VG_STATIC void skeleton_setup( struct skeleton *skele,
+ void *lin_alloc, mdl_context *mdl )
{
u32 bone_count = 1, skeleton_root = 0, ik_count = 0, collider_count = 0;
skele->bone_count = 0;
struct classtype_skeleton *inf = NULL;
- for( u32 i=0; i<mdl->node_count; i++ )
+ for( u32 i=0; i<mdl->info.node_count; i++ )
{
mdl_node *pnode = mdl_node_from_id( mdl, i );
if( pnode->classtype == k_classtype_skeleton )
{
inf = mdl_get_entdata( mdl, pnode );
- if( skele->bone_count )
- {
- vg_error( "Multiple skeletons in model file\n" );
- goto error_dealloc;
- }
-
- skele->bone_count = inf->channels;
- skele->ik_count = inf->ik_count;
- skele->collider_count = inf->collider_count;
- skele->bones =vg_alloc(sizeof(struct skeleton_bone)*skele->bone_count);
- skele->ik = vg_alloc(sizeof(struct skeleton_ik)*skele->ik_count);
+ skeleton_alloc_from( skele, lin_alloc, inf );
skeleton_root = i;
}
else if( skele->bone_count )
bone_count, skele->bone_count,
mdl_pstr( mdl, pnode->pstr_name ));
- goto error_dealloc;
+ skeleton_fatal_err();
}
struct skeleton_bone *sb = &skele->bones[bone_count];
v3_copy( pnode->co, sb->co );
v3_copy( pnode->s, sb->end );
sb->parent = pnode->parent-skeleton_root;
- strncpy( sb->name, mdl_pstr(mdl,pnode->pstr_name), 15 );
+ sb->name = mdl_pstr( mdl, pnode->pstr_name );
sb->deform = bone_inf->deform;
if( is_ik )
if( ik_count == skele->ik_count )
{
vg_error( "Too many ik bones, corrupt model file\n" );
- goto error_dealloc;
+ skeleton_fatal_err();
}
struct skeleton_ik *ik = &skele->ik[ ik_count ++ ];
if( collider_count == skele->collider_count )
{
vg_error( "Too many collider bones\n" );
- goto error_dealloc;
+ skeleton_fatal_err();
}
collider_count ++;
if( !inf )
{
vg_error( "No skeleton in model\n" );
- return 0;
+ skeleton_fatal_err();
}
if( collider_count != skele->collider_count )
{
vg_error( "Loaded %u colliders out of %u\n", collider_count,
- skele->collider_count );
- goto error_dealloc;
+ skele->collider_count );
+ skeleton_fatal_err();
}
if( bone_count != skele->bone_count )
{
vg_error( "Loaded %u bones out of %u\n", bone_count, skele->bone_count );
- goto error_dealloc;
+ vg_fatal_exit_loop( "Skeleton setup failed" );
+ skeleton_fatal_err();
}
if( ik_count != skele->ik_count )
{
vg_error( "Loaded %u ik bones out of %u\n", ik_count, skele->ik_count );
- goto error_dealloc;
+ skeleton_fatal_err();
}
/* fill in implicit root bone */
v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end );
skele->bones[0].parent = 0xffffffff;
skele->bones[0].collider = 0;
+ skele->bones[0].name = "[root]";
- skele->final_mtx = vg_alloc( sizeof(m4x3f) * skele->bone_count );
- skele->anim_count = inf->anim_count;
- skele->anims = vg_alloc( sizeof(struct skeleton_anim) * inf->anim_count);
-
- for( int i=0; i<inf->anim_count; i++ )
+ /* process animation quick refs */
+ for( int i=0; i<skele->anim_count; i++ )
{
- mdl_animation *anim =
- mdl_animation_from_id( mdl, inf->anim_start+i );
-
- skele->anims[i].rate = anim->rate;
- skele->anims[i].length = anim->length;
- strncpy( skele->anims[i].name, mdl_pstr(mdl, anim->pstr_name), 31 );
+ mdl_animation *anim = &mdl->anim_buffer[ inf->anim_start + i ];
- u32 total_keyframes = (skele->bone_count-1)*anim->length;
- size_t block_size = sizeof(mdl_keyframe) * total_keyframes;
- mdl_keyframe *dst = vg_alloc( block_size );
+ skele->anims[i].rate = anim->rate;
+ skele->anims[i].length = anim->length;
+ skele->anims[i].name = mdl_pstr(mdl, anim->pstr_name);
+ skele->anims[i].anim_data = &mdl->keyframe_buffer[ anim->offset ];
- skele->anims[i].anim_data = dst;
- memcpy( dst, mdl_get_animdata( mdl, anim ), block_size );
+ vg_info( "animation[ %f, %u ] '%s'\n", anim->rate,
+ anim->length,
+ skele->anims[i].name );
}
skeleton_create_inverses( skele );
vg_success( "Loaded skeleton with %u bones\n", skele->bone_count );
vg_success( " %u colliders\n", skele->collider_count );
- return 1;
-
-error_dealloc:
- vg_free( skele->bones );
- vg_free( skele->ik );
- return 0;
}
-static void skeleton_debug( struct skeleton *skele )
+VG_STATIC void skeleton_debug( struct skeleton *skele )
{
for( int i=0; i<skele->bone_count; i ++ )
{
* nothing.
*/
-static char steam_username_at_startup[128];
+VG_STATIC char steam_username_at_startup[128];
-static void recv_steam_warning( int severity, const char *msg )
+VG_STATIC void recv_steam_warning( int severity, const char *msg )
{
if( severity == 0 )
vg_low( "%s\n", msg );
vg_info( "%s\n", msg );
}
-static int steam_ready = 0,
+VG_STATIC int steam_ready = 0,
steam_stats_ready = 0;
-static void *hSteamNetworkingSockets,
+VG_STATIC void *hSteamNetworkingSockets,
*hSteamUser;
-static ISteamUserStats *hSteamUserStats;
-static HSteamPipe hSteamClientPipe;
+VG_STATIC ISteamUserStats *hSteamUserStats;
+VG_STATIC HSteamPipe hSteamClientPipe;
-static const char *steam_achievement_names[] =
+VG_STATIC const char *steam_achievement_names[] =
{
"ALBERT", "MARC",
"ROUTE_MPY", "ROUTE_MPG", "ROUTE_MPB", "ROUTE_MPR",
"ROUTE_TO", "ROUTE_TC"
};
-static void steam_store_achievements(void)
+VG_STATIC void steam_store_achievements(void)
{
if( steam_ready && steam_stats_ready )
{
}
}
-static void steam_set_achievement( const char *name )
+VG_STATIC void steam_set_achievement( const char *name )
{
if( steam_ready && steam_stats_ready )
{
}
}
-static void steam_clear_achievement( const char *name )
+VG_STATIC void steam_clear_achievement( const char *name )
{
if( steam_ready && steam_stats_ready )
{
}
-static int steam_list_achievements( int argc, char const *argv[] )
+VG_STATIC int steam_list_achievements( int argc, char const *argv[] )
{
vg_info( "Achievements: \n" );
return 0;
}
-static int steam_clear_all_achievements( int argc, char const *argv[] )
+VG_STATIC int steam_clear_all_achievements( int argc, char const *argv[] )
{
if( steam_ready && steam_stats_ready )
{
return 0;
}
-static int steam_set_achievemnt_test( int argc, char const *argv[] )
+VG_STATIC int steam_set_achievemnt_test( int argc, char const *argv[] )
{
if( argc < 2 )
return 0;
return 0;
}
-static void steam_on_recieve_current_stats( CallbackMsg_t *msg )
+VG_STATIC void steam_on_recieve_current_stats( CallbackMsg_t *msg )
{
UserStatsReceived_t *rec = (UserStatsReceived_t *)msg->m_pubParam;
}
}
-static int steam_init(void)
+VG_STATIC int steam_init(void)
{
const char *username = NULL;
return 1;
}
-static void steam_update(void)
+VG_STATIC void steam_update(void)
{
if( steam_ready )
steamworks_event_loop( hSteamClientPipe );
}
-static void steam_end(void *nothing)
+VG_STATIC void steam_end(void *nothing)
{
if( steam_ready )
{
#define VG_CONFIG
#include "vg/vg.h"
-static struct button_binding vg_button_binds[] =
+VG_STATIC struct button_binding vg_button_binds[] =
{
{ .name = "primary", .bind = GLFW_MOUSE_BUTTON_LEFT },
{ .name = "secondary", .bind = GLFW_MOUSE_BUTTON_RIGHT },
{ .name = "menu", .bind = GLFW_KEY_ESCAPE }
};
-static struct button_binding vg_controller_binds[] =
+VG_STATIC struct button_binding vg_controller_binds[] =
{
{ "jump", GLFW_GAMEPAD_BUTTON_A },
{ "break", GLFW_GAMEPAD_BUTTON_B },
{ "menu", GLFW_GAMEPAD_BUTTON_BACK }
};
-static struct axis_binding vg_axis_binds[] =
+VG_STATIC struct axis_binding vg_axis_binds[] =
{
{ .name = "lookh", .axis = GLFW_GAMEPAD_AXIS_LEFT_X },
{ .name = "lookv", .axis = GLFW_GAMEPAD_AXIS_LEFT_Y },
{ .name = "grab", .axis = GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER },
};
-static struct vg_achievement vg_achievements[] =
+VG_STATIC struct vg_achievement vg_achievements[] =
{
};
#include "common.h"
-static int ray_world( v3f pos, v3f dir, ray_hit *hit );
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
#ifndef WORLD_H
#define WORLD_H
#include "bvh.h"
#include "model.h"
-#include "traffic.h" /*TODO: -> world_traffic.h */
-
#include "shaders/terrain.h"
#include "shaders/sky.h"
#include "shaders/planeinf.h"
#include "shaders/fscolour.h"
#include "shaders/alphatest.h"
+typedef struct teleport_gate teleport_gate;
+
enum { k_max_ui_segments = 8 };
-enum { k_max_ui_splits_per_segment = 16 };
-enum { k_max_ui_elements = k_max_ui_segments*k_max_ui_splits_per_segment };
+enum { k_max_ui_elements = k_max_ui_segments };
enum { k_max_element_verts = 10 };
enum { k_max_element_indices = 20 };
enum { k_route_ui_max_verts = k_max_ui_elements*k_max_element_verts };
enum { k_route_ui_max_indices = k_max_ui_elements*k_max_element_indices };
-static struct gworld
+enum logic_type
+{
+ k_logic_type_relay = 1,
+ k_logic_type_chance = 2,
+ k_logic_type_achievement = 3
+};
+
+VG_STATIC struct gworld
{
- /* gameplay */
+ /*
+ * Allocated as system memory
+ * --------------------------------------------------------------------------
+ */
+
+ /* rendering */
+ glmesh skydome;
+ mdl_submesh dome_upper, dome_lower;
+
+ glmesh mesh_gate_surface;
+
+ double sky_time, sky_rate, sky_target_rate;
+
+ /* water rendering */
+ struct
+ {
+ struct framebuffer fbreflect, fbdepth;
+
+ boxf depthbounds;
+ int depth_computed;
+
+ float height;
+ int enabled;
+ v4f plane;
+ }
+ water;
+
+ /* split flap display */
+ struct
+ {
+ mdl_submesh *sm_module, *sm_card;
+ glmesh mesh_base, mesh_display;
+
+ u32 w, h;
+ float *buffer;
+ }
+ sfd;
+
+ /* timing bars, fixed maximum amount */
+ struct route_ui_bar
+ {
+ GLuint vao, vbo, ebo;
+
+ u32 indices_head;
+ u32 vertex_head;
+
+ float last_notch;
+
+ struct route_ui_segment
+ {
+ float length;
+ u32 vertex_start, vertex_count,
+ index_start, index_count, notches;
+ }
+ segments[k_max_ui_segments];
+
+ u32 segment_start, segment_count, fade_start, fade_count;
+ double fade_timer_start;
+ float xpos;
+ }
+ ui_bars[16];
+
+ v3f render_gate_pos;
+ int active_route_board;
+
+ /*
+ * Dynamically allocated when world_load is called.
+ *
+ * the following arrays index somewhere into this linear
+ * allocator
+ *
+ * (world_gen.h)
+ * --------------------------------------------------------------------------
+ */
+ void *dynamic_vgl;
+
+ /*
+ * Main world .mdl
+ */
+ mdl_context *meta;
+
+ /*
+ * Named safe places to respawn
+ */
struct respawn_point
{
v3f co;
v4f q;
- char name[32];
+ const char *name;
}
- spawns[32];
+ * spawns;
u32 spawn_count;
+ /*
+ * Audio player entities
+ */
struct world_audio_thing
{
v3f pos;
audio_clip temp_embedded_clip;
}
* audio_things;
-
- u32 audio_things_count,
- audio_things_cap;
+ u32 audio_things_count;
- struct achievement_zone
+ /*
+ * Relays, random, etc
+ */
+ struct logic_entity
{
- m4x3f transform, inv_transform;
- char name[32];
- int triggered;
+ v3f pos;
+ enum logic_type logic_type;
+ int enabled;
- union
- {
- mdl_node *ptarget_delegated;
- struct world_audio_thing *ptarget;
- };
+ /* indexes the action array */
+ u32 action_start, action_count;
}
- * achievement_zones;
+ * logic_entities;
+ u32 logic_entity_count;
- u32 achievement_zones_count,
- achievement_zones_cap;
-
- struct subworld_sfd
+ /*
+ * Action array
+ */
+ struct logic_action
{
- scene mesh;
- mdl_submesh *sm_module, *sm_card;
- glmesh temp;
+ u32 event, /* on trigger, on enable, etc (TODO: Enum) */
+ target_id; /* thing to target, 0: self */
- struct sfd_instance
- {
- float *buffer;
-
- u32 w,h;
- }
- tester;
}
- sfd;
-
- /* Paths */
- traffic_node traffic[128];
- u32 traffic_count;
-
-#if 0
- traffic_driver van_man[6];
-#endif
-
- double sky_time, sky_rate, sky_target_rate;
-
- /* Physics */
-
- /* Rendering & geometry */
- scene geo, foliage;
- rigidbody rb_geo;
+ * logic_actions;
+ u32 logic_action_count;
- /* TODO Maybe make this less hardcoded */
- mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
- sm_foliage_main, sm_foliage_alphatest,
- sm_graffiti, sm_subworld, sm_terrain;
-
- glmesh skybox, skydome;
- mdl_submesh dome_upper, dome_lower;
-
- glmesh cars;
- mdl_submesh car_holden;
-
- /* Load time */
-
- struct instance_cache
+ /*
+ * Box trigger entities
+ */
+ struct trigger_zone
{
- mdl_header *mdl;
- u32 pstr_file;
+ m4x3f transform, inv_transform;
+ u32 trigger_entity;
}
- * instance_cache;
- u32 instance_cache_count,
- instance_cache_cap;
+ * triggers;
+ u32 trigger_count;
- v3f render_gate_pos;
- int active_route_board;
-}
-world ;
-
-typedef struct teleport_gate teleport_gate;
-struct teleport_gate
-{
- v3f co[2];
- v4f q[2];
- v2f dims;
- m4x3f to_world, recv_to_world, transport;
-};
-
-struct subworld_routes
-{
+ /*
+ * Routes (world_routes.h)
+ * --------------------------------------------------------------------------
+ */
struct route_node
{
v3f co, right, up, h;
u32 route_ids[4]; /* Gates can be linked into up to four routes */
}
*nodes;
-
- u32 node_count,
- node_cap;
+ u32 node_count;
struct route
{
double best_lap, latest_pass; /* Session */
- struct
- {
- GLuint vao, vbo, ebo;
-
- u32 indices_head;
- u32 vertex_head;
-
- float last_notch;
-
- struct route_ui_segment
- {
- float length;
- u32 vertex_start, vertex_count,
- index_start, index_count, notches;
- }
- segments[k_max_ui_segments];
-
- u32 segment_start, segment_count, fade_start, fade_count;
- double fade_timer_start;
- float xpos;
- }
- ui;
-
m4x3f scoreboard_transform;
}
*routes;
-
- double time, rewind_from, rewind_to, last_use;
-
- u32 route_count,
- route_cap;
+ u32 route_count;
struct route_gate
{
- teleport_gate gate;
+ struct teleport_gate
+ {
+ v3f co[2];
+ v4f q[2];
+ v2f dims;
+
+ m4x3f to_world, recv_to_world, transport;
+ }
+ gate;
+
u32 node_id;
struct route_timing
timing;
}
*gates;
+ u32 gate_count;
struct route_collector
{
struct route_timing timing;
}
*collectors;
+ u32 collector_count;
+
- u32 gate_count,
- gate_cap,
- collector_count,
- collector_cap;
+ /* logic
+ * ----------------------------------------------------
+ */
u32 active_gate,
current_run_version;
+ double time, rewind_from, rewind_to, last_use;
+
+ /* world geometry */
+ scene *scene_geo,
+ *scene_no_collide,
+ *scene_lines;
+
+ /* spacial mappings */
+ bh_tree *audio_bh,
+ *trigger_bh,
+ *geo_bh;
+
+ /* graphics */
+ glmesh mesh_geo,
+ mesh_no_collide,
+ mesh_route_lines,
+ mesh_water;
+
+ rigidbody rb_geo;
+
+ /* TODO Maybe make this less hardcoded */
+ mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
+ sm_foliage_main, sm_foliage_alphatest,
+ sm_graffiti, sm_subworld, sm_terrain;
- scene scene_lines;
+ /*
+ * Allocated AFTER all previous buffers are done
+ * --------------------------------------------------------------------------
+ */
+
+ struct instance_cache
+ {
+ mdl_context *mdl;
+ u32 pstr_file;
+ }
+ instance_cache[32];
+ u32 instance_cache_count;
}
-static world_routes;
+world;
/*
* API
*/
-static int ray_hit_is_ramp( ray_hit *hit );
-static int ray_hit_is_terrain( ray_hit *hit );
-static void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
-static int ray_world( v3f pos, v3f dir, ray_hit *hit );
+VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
+VG_STATIC int ray_hit_is_terrain( ray_hit *hit );
+VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
/*
* Submodules
* -----------------------------------------------------------------------------
*/
-static void world_init(void)
+VG_STATIC void world_init(void)
{
+ vg_convar_push( (struct vg_convar){
+ .name = "water_enable",
+ .data = &world.water.enabled,
+ .data_type = k_convar_dtype_i32,
+ .opt_i32 = { .min=0, .max=1, .clamp=1 },
+ .persistent = 0
+ });
+
world.sky_rate = 1.0;
world.sky_target_rate = 1.0;
shader_alphatest_register();
vg_info( "Loading world resources\n" );
-
- VG_REQUIRED_ASSET( mdl_header*, mcars, mdl_load, "models/rs_cars.mdl" );
- VG_REQUIRED_ASSET( mdl_header*, msky, mdl_load, "models/rs_skydome.mdl" );
-
- mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
- world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
+
+ vg_linear_clear( vg_mem.scratch );
+ mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
*nupper = mdl_node_from_name( msky, "dome_upper" );
vg_acquire_thread_sync();
{
- mdl_unpack_glmesh( mcars, &world.cars );
mdl_unpack_glmesh( msky, &world.skydome );
}
vg_release_thread_sync();
- vg_free(mcars);
- vg_free(msky);
-
/* Other systems */
vg_info( "Loading other world systems\n" );
- vg_loader_highwater( world_render_init, world_render_free, NULL );
- vg_loader_highwater( world_sfd_init, world_sfd_free, NULL );
- vg_loader_highwater( world_water_init, world_water_free, NULL );
- vg_loader_highwater( world_gates_init, world_gates_free, NULL );
- vg_loader_highwater( world_routes_init, world_routes_free, NULL );
-}
-
-static void world_free( void *_ )
-{
- mesh_free( &world.cars );
- mesh_free( &world.skydome );
- vg_free( world.achievement_zones );
+ vg_loader_highwater( world_render_init, NULL, NULL );
+ vg_loader_highwater( world_sfd_init, NULL, NULL );
+ vg_loader_highwater( world_water_init, NULL, NULL );
+ vg_loader_highwater( world_gates_init, NULL, NULL );
+ vg_loader_highwater( world_routes_init, NULL, NULL );
- /* FIXME: This fucks with the audio player. Use-after-free */
-#if 0
- vg_free( world.audio_things );
-#endif
+ /* Allocate dynamic world memory arena */
+ u32 max_size = 72*1024*1024;
+ world.dynamic_vgl = vg_create_linear_allocator( vg_mem.rtmemory, max_size );
}
-static void world_update( v3f pos )
+VG_STATIC void world_update( v3f pos )
{
world.sky_time += world.sky_rate * vg.time_delta;
world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
int closest = 0;
float min_dist = INFINITY;
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- float d = v3_dist2( world_routes.routes[i].scoreboard_transform[3], pos );
+ float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
if( d < min_dist )
{
{
network_scores_updated = 0;
world.active_route_board = closest;
- struct subworld_sfd *sfd = &world.sfd;
- struct route *route = &world_routes.routes[closest];
+ struct route *route = &world.routes[closest];
u32 id = route->track_id;
for( int i=0; i<13; i++ )
{
- sfd_encode( &sfd->tester, i, &local_board->data[27*i] );
+ sfd_encode( i, &local_board->data[27*i] );
}
}
}
- static int in_zone = 0;
+#if 0
+ VG_STATIC int in_zone = 0;
int in_zone_this_time = 0;
}
in_zone = in_zone_this_time;
+#endif
- sfd_update( &world.sfd.tester );
+ sfd_update();
}
/*
* -----------------------------------------------------------------------------
*/
-static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
+VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
{
for( int i=0; i<3; i++ )
- v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
+ v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
}
-static int ray_world( v3f pos, v3f dir, ray_hit *hit )
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
{
- return scene_raycast( &world.geo, pos, dir, hit );
+ return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
}
-static int ray_hit_is_terrain( ray_hit *hit )
+VG_STATIC int ray_hit_is_terrain( ray_hit *hit )
{
u32 valid_start = 0,
valid_end = world.sm_terrain.vertex_count;
(hit->tri[0] < valid_end);
}
-static int ray_hit_is_ramp( ray_hit *hit )
+VG_STATIC int ray_hit_is_ramp( ray_hit *hit )
{
u32 valid_start = world.sm_geo_std.vertex_start,
valid_end = world.sm_geo_vb.vertex_start;
#ifndef WORLD_GATE_H
#define WORLD_GATE_H
-#define GATE_RENDER_PERFORMANCE
-
#include "common.h"
#include "model.h"
#include "render.h"
-#ifndef GATE_RENDER_PERFORMANCE
- #include "shaders/gate.h"
-#else
- #include "shaders/gatelq.h"
-#endif
-
+#include "shaders/gatelq.h"
#include "world_water.h"
-static struct
-{
- struct framebuffer fb;
- glmesh mdl;
-}
-grender =
-{
- .fb = {
- .format = GL_RGB,
- .div = 1
- }
-};
-
-static void gate_transform_update( teleport_gate *gate )
+VG_STATIC void gate_transform_update( teleport_gate *gate )
{
m4x3f to_local;
m4x3_mul( gate->recv_to_world, to_local, gate->transport );
}
-static void world_gates_init(void)
+VG_STATIC void world_gates_init(void)
{
vg_info( "world_gates_init\n" );
-#ifndef GATE_RENDER_PERFORMANCE
- shader_gate_register();
-#else
shader_gatelq_register();
-#endif
- mdl_header *mgate = mdl_load( "models/rs_gate.mdl" );
+ vg_linear_clear( vg_mem.scratch );
+ mdl_context *mgate = mdl_load_full( vg_mem.scratch, "models/rs_gate.mdl" );
vg_acquire_thread_sync();
{
- fb_init( &grender.fb );
- mdl_unpack_glmesh( mgate, &grender.mdl );
+ mdl_unpack_glmesh( mgate, &world.mesh_gate_surface );
}
vg_release_thread_sync();
}
-static void world_gates_free(void*_)
-{
- fb_free( &grender.fb );
-}
-
-static void gate_fb_resize(void)
-{
- fb_resize( &grender.fb );
-}
-
-static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
+VG_STATIC int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
{
v3f viewdir, gatedir;
m3x3_mulv( camera, (v3f){0.0f,0.0f,-1.0f}, viewdir );
m4x4_mul( projection, view, projection );
-#ifndef GATE_RENDER_PERFORMANCE
- fb_use( &grender.fb );
- glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
- glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
-#else
+ {
shader_gatelq_use();
shader_gatelq_uPv( vg.pv );
shader_gatelq_uMdl( gate_xform );
glStencilFunc( GL_ALWAYS, 1, 0xFF );
glStencilMask( 0xFF );
- mesh_bind( &grender.mdl );
- mesh_draw( &grender.mdl );
+ mesh_bind( &world.mesh_gate_surface );
+ mesh_draw( &world.mesh_gate_surface );
glClear( GL_DEPTH_BUFFER_BIT );
glStencilFunc( GL_EQUAL, 1, 0xFF );
glStencilMask( 0x00 );
-#endif
+ }
render_world( projection, cam_new );
-#ifndef GATE_RENDER_PERFORMANCE
-
- /*
- * NOTE: Need to find a way to draw a stencil buffer into the water
- * rendering
- */
-
- render_water_texture( cam_new );
- fb_use( &grender.fb );
-
- render_water_surface( projection, cam_new );
- fb_use( NULL );
-
- shader_gate_use();
-
- shader_gate_uPv( vg_pv );
- shader_gate_uMdl( gate_xform );
-
- fb_bindtex( &grender.fb, 0 );
-
- shader_gate_uCam( viewpos );
- shader_gate_uTexMain( 0 );
- shader_gate_uTexWater( 1 );
- shader_gate_uTime( vg_time*0.25f );
- shader_gate_uInvRes( (v2f){
- 1.0f / (float)vg_window_x,
- 1.0f / (float)vg_window_y });
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- glBlendEquation(GL_FUNC_ADD);
-
- mesh_bind( &grender.mdl );
- mesh_draw( &grender.mdl );
-
- glDisable(GL_BLEND);
-#else
+ {
glDisable( GL_STENCIL_TEST );
render_water_texture( cam_new );
glStencilMask( 0xFF );
glStencilFunc( GL_ALWAYS, 1, 0xFF );
glDisable( GL_STENCIL_TEST );
-#endif
+ }
return 1;
}
-static int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
+VG_STATIC int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
{
v4f surface;
m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
#ifndef WORLD_GEN_H
#define WORLD_GEN_H
-/*
- * FUTURE:
- * If we have multiple levels, write an unloader
- */
-
#include "world.h"
-static void world_add_all_if_material( m4x3f transform, scene *pscene,
- mdl_header *mdl, u32 id )
+/* load world TODO: Put back vg back in loading state while this happens */
+VG_STATIC void world_load( const char *mdl_file );
+
+
+
+VG_STATIC void world_add_all_if_material( m4x3f transform, scene *pscene,
+ mdl_context *mdl, u32 id )
{
- for( int i=0; i<mdl->node_count; i++ )
+ for( int i=0; i<mdl->info.node_count; i++ )
{
mdl_node *pnode = mdl_node_from_id( mdl, i );
for( int j=0; j<pnode->submesh_count; j++ )
{
mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
-
if( sm->material_id == id )
{
m4x3f transform2;
}
}
+#if 0
if( pnode->classtype == k_classtype_instance )
{
if( pnode->sub_uid )
{
u32 instance_id = pnode->sub_uid -1;
struct instance_cache *cache = &world.instance_cache[instance_id];
- mdl_header *mdl2 = cache->mdl;
+ mdl_context *mdl2 = cache->mdl;
m4x3f transform2;
mdl_node_transform( pnode, transform2 );
world_add_all_if_material( transform2, pscene, mdl2, id );
}
}
+#endif
}
}
-static void world_apply_procedural_foliage(void)
+/* Sprinkle foliage models over the map on terrain material */
+VG_STATIC void world_apply_procedural_foliage(void)
{
- mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
+ vg_linear_clear( vg_mem.scratch );
+
+ mdl_context *mfoliage =
+ mdl_load_full( vg_mem.scratch, "models/rs_foliage.mdl");
v3f volume;
- v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
+ v3_sub( world.scene_geo->bbx[1], world.scene_geo->bbx[0], volume );
volume[1] = 1.0f;
m4x3f transform;
v3f pos;
v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
pos[1] = 1000.0f;
- v3_add( pos, world.geo.bbx[0], pos );
+ v3_add( pos, world.scene_geo->bbx[0], pos );
ray_hit hit;
hit.dist = INFINITY;
q_m3x3( qsurface, transform );
v3_copy( hit.pos, transform[3] );
- scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
+ scene_add_submesh( world.scene_no_collide, mfoliage,
+ sm_blob, transform);
}
}
}
-
- vg_free( mfoliage );
}
-static void world_load(void)
+VG_STATIC void world_ents_allocate(void)
{
- mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
- vg_info( "Loading world: models/mp_dev.mdl\n" );
+ vg_info( "Allocating entities\n" );
- world.spawn_count = 0;
- world.traffic_count = 0;
- world.instance_cache = NULL;
-
- /*
- * Process entities
- */
- for( int i=0; i<mworld->node_count; i++ )
+ /* count entites to allocate buffers for them.
+ * maybe in the future we just store these numbers in the model file...
+ *
+ * TODO: use this in world_routes too */
+
+ struct countable
{
- mdl_node *pnode = mdl_node_from_id( mworld, i );
-
- if( pnode->classtype == k_classtype_none )
- {}
- else if( pnode->classtype == k_classtype_spawn )
+ enum classtype ct;
+ void **to_allocate;
+ u32 item_size;
+ int count;
+ }
+ entity_counts[] =
+ {
+ {
+ k_classtype_spawn,
+ (void*)&world.spawns,
+ sizeof(struct respawn_point)
+ },
+ {
+ k_classtype_audio,
+ (void*)&world.audio_things,
+ sizeof(struct world_audio_thing)
+ },
{
- struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
-
- v3_copy( pnode->co, rp->co );
- v4_copy( pnode->q, rp->q );
- strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
+ k_classtype_trigger,
+ (void*)&world.triggers,
+ sizeof(struct trigger_zone)
}
- else if( pnode->classtype == k_classtype_water )
+ };
+
+ for( int i=0; i<vg_list_size(entity_counts); i++ )
+ entity_counts[i].count = 0;
+
+ for( int i=0; i<world.meta->info.node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id( world.meta, i );
+
+ for( int j=0; j<vg_list_size(entity_counts); j ++ )
{
- if( wrender.enabled )
+ if( pnode->classtype == entity_counts[j].ct )
{
- vg_warn( "Multiple water surfaces in level! ('%s')\n",
- mdl_pstr( mworld, pnode->pstr_name ));
- continue;
+ entity_counts[j].count ++;
+ break;
}
+ }
+ }
- mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
-
- if( sm )
- {
- vg_acquire_thread_sync();
- {
- glmesh surf;
- mdl_unpack_submesh( mworld, &surf, sm );
- water_set_surface( &surf, pnode->co[1] );
- }
- vg_release_thread_sync();
- }
+ for( int i=0; i<vg_list_size(entity_counts); i++ )
+ {
+ struct countable *counter = &entity_counts[i];
+
+ u32 bufsize = counter->item_size*counter->count;
+ *counter->to_allocate = vg_linear_alloc( world.dynamic_vgl, bufsize );
+ }
+}
+
+VG_STATIC void world_pct_spawn( mdl_node *pnode )
+{
+ struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
+
+ v3_copy( pnode->co, rp->co );
+ v4_copy( pnode->q, rp->q );
+ rp->name = mdl_pstr( world.meta, pnode->pstr_name );
+}
+
+VG_STATIC void world_pct_water( mdl_node *pnode )
+{
+ if( world.water.enabled )
+ {
+ vg_warn( "Multiple water surfaces in level! ('%s')\n",
+ mdl_pstr( world.meta, pnode->pstr_name ));
+ return;
+ }
+
+ mdl_submesh *sm = mdl_node_submesh( world.meta, pnode, 0 );
+
+ if( sm )
+ {
+ vg_acquire_thread_sync();
+ {
+ mdl_unpack_submesh( world.meta, &world.mesh_water, sm );
+ world.water.enabled = 1;
+ water_set_surface( pnode->co[1] );
+ }
+ vg_release_thread_sync();
+ }
+ else
+ {
+ vg_warn( "Water entity has no submeshes!\n" );
+ }
+}
+
+VG_STATIC void world_pct_instance( mdl_node *pnode )
+{
+ struct classtype_instance *inst = mdl_get_entdata( world.meta, pnode );
+ pnode->sub_uid = 0;
+
+ int cache_entry = 0;
+ for( int i=0; i<world.instance_cache_count; i++ )
+ {
+ struct instance_cache *cache = &world.instance_cache[i];
+ if( inst->pstr_file == cache->pstr_file )
+ {
+ cache_entry = 1;
+ pnode->sub_uid = i+1;
+ break;
}
- else if( pnode->classtype == k_classtype_car_path )
+ }
+
+ if( !cache_entry )
+ {
+ if( world.instance_cache_count == vg_list_size(world.instance_cache) )
+ vg_fatal_exit_loop( "Instance cache is full!" );
+
+ struct instance_cache *cache =
+ &world.instance_cache[world.instance_cache_count ++ ];
+
+ cache->pstr_file = inst->pstr_file;
+
+#if 0
+ cache->mdl = mdl_load( filename );
+
+ if( cache->mdl )
{
- struct classtype_car_path *p = mdl_get_entdata( mworld, pnode );
- traffic_node *tn = &world.traffic[ world.traffic_count ];
- tn->mn_next = NULL;
- tn->mn_next1 = NULL;
-
- if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target );
- if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 );
-
- m4x3f transform;
- mdl_node_transform( pnode, transform );
- m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h );
- v3_copy( transform[3], tn->co );
-
- pnode->sub_uid = world.traffic_count ++;
+ world.instance_cache_count ++;
+ pnode->sub_uid = world.instance_cache_count;
+ mdl_link_materials( mworld, cache->mdl );
+ vg_success( "Cached %s\n", filename );
}
- else if( pnode->classtype == k_classtype_instance )
+ else
{
- struct classtype_instance *inst = mdl_get_entdata( mworld, pnode );
- pnode->sub_uid = 0;
-
- int cached = 0;
- for( int i=0; i<world.instance_cache_count; i++ )
- {
- struct instance_cache *cache = &world.instance_cache[i];
- if( inst->pstr_file == cache->pstr_file )
- {
- cached = 1;
- pnode->sub_uid = i+1;
- break;
- }
- }
+ vg_warn( "Failed to cache %s\n", filename );
+ }
+#endif
+ }
+}
+
+VG_STATIC void world_pct_audio( mdl_node *pnode )
+{
+ struct world_audio_thing *thing = &world.audio_things[
+ world.audio_things_count ];
+
+ memset( thing, 0, sizeof(struct world_audio_thing) );
+ struct classtype_audio *aud = mdl_get_entdata( world.meta, 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->flags = aud->flags;
+ thing->temp_embedded_clip.path = mdl_pstr( world.meta, aud->pstr_file );
+ audio_clip_load( &thing->temp_embedded_clip );
+ thing->player.name = mdl_pstr( world.meta, pnode->pstr_name );
+ thing->player.enqued = 0;
- if( !cached )
+ pnode->sub_uid = world.audio_things_count;
+ world.audio_things_count ++;
+}
+
+VG_STATIC void world_entities_process(void)
+{
+ struct entity_instruction
+ {
+ enum classtype ct;
+ void (*process)( mdl_node *pnode );
+ }
+ entity_instructions[] =
+ {
+ { k_classtype_spawn, world_pct_spawn },
+ { k_classtype_water, world_pct_water },
+ { k_classtype_instance, world_pct_instance },
+ { k_classtype_audio, world_pct_audio },
+ };
+
+ for( int i=0; i<world.meta->info.node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id( world.meta, i );
+
+ for( int j=0; j<vg_list_size(entity_instructions); j++ )
+ {
+ struct entity_instruction *instr = &entity_instructions[j];
+
+ if( pnode->classtype == instr->ct )
{
- world.instance_cache = buffer_reserve(
- world.instance_cache, world.instance_cache_count,
- &world.instance_cache_cap, 1,
- sizeof(struct instance_cache) );
-
- struct instance_cache *cache =
- &world.instance_cache[world.instance_cache_count];
-
- const char *filename = mdl_pstr(mworld, inst->pstr_file);
-
- cache->pstr_file = inst->pstr_file;
- cache->mdl = mdl_load( filename );
-
- if( cache->mdl )
- {
- world.instance_cache_count ++;
- pnode->sub_uid = world.instance_cache_count;
- mdl_link_materials( mworld, cache->mdl );
- vg_success( "Cached %s\n", filename );
- }
- else
- {
- vg_warn( "Failed to cache %s\n", filename );
- }
+ instr->process( pnode );
+ break;
}
}
+
+#if 0
else if( pnode->classtype == k_classtype_achievement_box )
{
world.achievement_zones =
else
zone->ptarget_delegated = NULL;
}
- else if( pnode->classtype == k_classtype_audio )
- {
- world.audio_things =
- buffer_reserve( world.audio_things,
- world.audio_things_count,
- &world.audio_things_cap, 1,
- sizeof(struct world_audio_thing) );
-
- struct world_audio_thing *thing = &world.audio_things[
- world.audio_things_count ];
- memset( thing, 0, sizeof(struct world_audio_thing) );
- struct classtype_audio *aud = mdl_get_entdata(mworld,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->flags = aud->flags;
- const char *fp = mdl_pstr( mworld, aud->pstr_file );
- char *path2 = vg_alloc( strlen(fp)+1 );
- strcpy( path2, fp );
- thing->temp_embedded_clip.path = path2;
- thing->temp_embedded_clip.source_mode = k_audio_source_compressed;
- audio_clip_load( &thing->temp_embedded_clip );
- thing->player.name = "[temp]";
- thing->player.enqued = 0;
-
- pnode->sub_uid = world.audio_things_count;
- world.audio_things_count ++;
- }
+#endif
}
+#if 0
/* fixup links */
for( int i=0; i<world.achievement_zones_count; i ++ )
{
else
ach->ptarget = NULL;
}
+#endif
+}
- /* initialize audio if need be */
- audio_lock();
- for( int i=0; i<world.audio_things_count; i++ )
+VG_STATIC void world_load_instance_cache(void)
+{
+ vg_linear_clear( vg_mem.scratch );
+
+ for( int i=0; i<world.instance_cache_count; i++ )
{
- struct world_audio_thing *thingy = &world.audio_things[ i ];
+ struct instance_cache *inst = &world.instance_cache[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 );
+ const char *filename = mdl_pstr( world.meta, inst->pstr_file );
+ inst->mdl = mdl_load_full( vg_mem.scratch, filename );
}
- audio_unlock();
-
- world.instance_cache = buffer_fix( world.instance_cache,
- world.instance_cache_count,
- &world.instance_cache_cap,
- sizeof( struct instance_cache ) );
-
-#if 0
- traffic_finalize( world.traffic, world.traffic_count );
- for( int i=0; i<vg_list_size(world.van_man); i++ )
- world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
-#endif
+}
+VG_STATIC void world_generate(void)
+{
/*
* Compile meshes into the world scenes
*/
- scene_init( &world.geo );
-
- u32 mat_surf = 0,
- mat_surf_oob = 0,
+ world.scene_geo = scene_init( world.dynamic_vgl, 500000, 1200000 );
+
+ /*
+ * TODO: System to dynamically allocate these
+ */
+ u32 mat_surf = 0,
+ mat_surf_oob = 0,
mat_vertex_blend = 0,
- mat_alphatest = 0,
- mat_graffiti = 0,
- mat_subworld = 0,
- mat_terrain = 0;
+ mat_alphatest = 0,
+ mat_graffiti = 0,
+ mat_subworld = 0,
+ mat_terrain = 0;
- for( int i=1; i<mworld->material_count; i++ )
+ for( int i=1; i<world.meta->info.material_count; i++ )
{
- mdl_material *mat = mdl_material_from_id( mworld, i );
- const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
+ mdl_material *mat = &world.meta->material_buffer[ i ];
+ const char *mat_name = mdl_pstr( world.meta, mat->pstr_name );
if( !strcmp( "surf", mat_name ))
mat_surf = i;
m4x3f midentity;
m4x3_identity( midentity );
+ world_load_instance_cache();
+
+ /*
+ * Generate scene: collidable geometry
+ * ----------------------------------------------------------------
+ */
+
+ vg_info( "Generating collidable geometry\n" );
+ vg_info( "terrain...\n" );
+ /* terrain */
if( mat_terrain )
- world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain );
- scene_copy_slice( &world.geo, &world.sm_terrain );
+ world_add_all_if_material( midentity, world.scene_geo,
+ world.meta, mat_terrain );
+ scene_copy_slice( world.scene_geo, &world.sm_terrain );
+ /* oob */
+ vg_info( "oob...\n" );
if( mat_surf_oob )
- world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
+ world_add_all_if_material( midentity, world.scene_geo,
+ world.meta, mat_surf_oob );
else
vg_warn( "No OOB surface\n" );
- scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
+ scene_copy_slice( world.scene_geo, &world.sm_geo_std_oob );
+
+ /* surface */
+ vg_info( "surface...\n" );
if( mat_surf )
- world_add_all_if_material( midentity, &world.geo, mworld, mat_surf );
- scene_copy_slice( &world.geo, &world.sm_geo_std );
+ world_add_all_if_material( midentity, world.scene_geo,
+ world.meta, mat_surf );
+ scene_copy_slice( world.scene_geo, &world.sm_geo_std );
+ /* vertex_blend */
+ vg_info( "vertex blend...\n" );
if( mat_vertex_blend )
- world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend);
- scene_copy_slice( &world.geo, &world.sm_geo_vb );
+ world_add_all_if_material( midentity, world.scene_geo,
+ world.meta, mat_vertex_blend);
+ scene_copy_slice( world.scene_geo, &world.sm_geo_vb );
+
+ /* compress that bad boy */
+ world.scene_geo = scene_fix( world.dynamic_vgl, world.scene_geo );
vg_acquire_thread_sync();
- scene_upload( &world.geo );
+ {
+ scene_upload( world.scene_geo, &world.mesh_geo );
+ }
vg_release_thread_sync();
- scene_bh_create( &world.geo );
+ /* setup spacial mapping and rigidbody */
+ world.geo_bh = scene_bh_create( world.dynamic_vgl, world.scene_geo );
+ v3_zero( world.rb_geo.co );
+ q_identity( world.rb_geo.q );
- /* Foliage /nocollide layer.
- * TODO: Probably should have material traits for this
+ world.rb_geo.type = k_rb_shape_scene;
+ world.rb_geo.inf.scene.bh_scene = world.geo_bh;
+ world.rb_geo.is_world = 1;
+ rb_init( &world.rb_geo );
+
+ /*
+ * Generate scene: non-collidable geometry
+ * ----------------------------------------------------------------
*/
- scene_init( &world.foliage );
+ vg_info( "Generating non-collidable geometry\n" );
+
+ world.scene_no_collide = scene_init( world.dynamic_vgl, 200000, 500000 );
+ vg_info( "Applying foliage\n" );
world_apply_procedural_foliage();
- scene_copy_slice( &world.foliage, &world.sm_foliage_main );
+ scene_copy_slice( world.scene_no_collide, &world.sm_foliage_main );
- world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest);
- scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
+ vg_info( "alphatest...\n" );
+ world_add_all_if_material( midentity, world.scene_no_collide,
+ world.meta, mat_alphatest );
+ scene_copy_slice( world.scene_no_collide, &world.sm_foliage_alphatest );
- world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
- scene_copy_slice( &world.foliage, &world.sm_graffiti );
+ vg_info( "graffiti...\n" );
+ world_add_all_if_material( midentity, world.scene_no_collide,
+ world.meta, mat_graffiti );
+ scene_copy_slice( world.scene_no_collide, &world.sm_graffiti );
+ /* upload and free that */
vg_acquire_thread_sync();
{
- scene_upload( &world.foliage );
+ scene_upload( world.scene_no_collide, &world.mesh_no_collide );
+ }
+ vg_release_thread_sync();
+
+ vg_linear_del( world.dynamic_vgl, world.scene_no_collide );
+ world.scene_no_collide = NULL;
+}
+VG_STATIC void world_post_process(void)
+{
+ /* initialize audio if need be */
+ audio_lock();
+ 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_unlock();
+
+ vg_acquire_thread_sync();
+ {
/*
* Rendering the depth map
*/
m4x3f camera;
v3f extent;
- v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
+ v3_sub( world.scene_geo->bbx[1], world.scene_geo->bbx[0], extent );
- float fl = world.geo.bbx[0][0],
- fr = world.geo.bbx[1][0],
- fb = world.geo.bbx[0][2],
- ft = world.geo.bbx[1][2],
+ float fl = world.scene_geo->bbx[0][0],
+ fr = world.scene_geo->bbx[1][0],
+ fb = world.scene_geo->bbx[0][2],
+ ft = world.scene_geo->bbx[1][2],
rl = 1.0f / (fr-fl),
tb = 1.0f / (ft-fb);
* TODO: World settings entity
*/
struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
- v4_copy( wrender.plane, winfo->g_water_plane );
- v4f bounds;
- bounds[0] = world.geo.bbx[0][0];
- bounds[1] = world.geo.bbx[0][2];
- bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
- bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
- v4_copy( bounds, winfo->g_depth_bounds );
+ if( world.water.enabled )
+ v4_copy( world.water.plane, winfo->g_water_plane );
+
+ v4f info_vec;
+ v3f *bounds = world.scene_geo->bbx;
+
+ info_vec[0] = bounds[0][0];
+ info_vec[1] = bounds[0][2];
+ info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]);
+ info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]);
+ v4_copy( info_vec, winfo->g_depth_bounds );
winfo->g_water_fog = 0.04f;
render_update_lighting_ub();
vg_release_thread_sync();
- world_routes_loadfrom( mworld );
-
- for( int i=0; i<world.instance_cache_count; i++ )
- vg_free( world.instance_cache[i].mdl );
-
- vg_free( world.instance_cache );
- vg_free( mworld );
- scene_free_offline_buffers( &world.foliage );
-
/*
* Setup scene collider
*/
- v3_zero( world.rb_geo.co );
- q_identity( world.rb_geo.q );
+}
- world.rb_geo.type = k_rb_shape_scene;
- world.rb_geo.inf.scene.pscene = &world.geo;
- world.rb_geo.is_world = 1;
- rb_init( &world.rb_geo );
+
+VG_STATIC void world_unload(void)
+{
+ /* free meshes */
+ mesh_free( &world.mesh_geo );
+ mesh_free( &world.mesh_no_collide );
+ mesh_free( &world.mesh_route_lines );
+ mesh_free( &world.mesh_water );
+
+ /* delete the entire block of memory */
+ vg_linear_clear( world.dynamic_vgl );
+
+ /* clean dangling pointers */
+ world.meta = NULL;
+
+ world.scene_geo = NULL;
+ world.scene_lines = NULL;
+ world.scene_no_collide = NULL;
+
+ world.geo_bh = NULL;
+ world.trigger_bh = NULL;
+ world.audio_bh = NULL;
+
+ world.spawns = NULL;
+ world.spawn_count = 0;
+
+ world.audio_things = NULL;
+ world.audio_things_count = 0;
+
+ world.logic_entities = NULL;
+ world.logic_entity_count = 0;
+
+ world.logic_actions = NULL;
+ world.logic_action_count = 0;
+
+ world.triggers = NULL;
+ world.trigger_count = 0;
+
+ world.nodes = NULL;
+ world.node_count = 0;
+
+ world.routes = NULL;
+ world.route_count = 0;
+
+ world.gates = NULL;
+ world.gate_count = 0;
+
+ world.collectors = NULL;
+ world.collector_count = 0;
+
+ world.instance_cache_count = 0;
+ world.water.enabled = 0;
+}
+
+VG_STATIC void world_load( const char *mdl_file )
+{
+ world_unload();
+
+ world.meta = mdl_load_full( world.dynamic_vgl, mdl_file );
+ vg_info( "Loading world: %s\n", mdl_file );
+
+ /* dynamic allocations */
+ world_ents_allocate();
+ world_routes_allocate();
+
+ /* meta processing */
+ world_routes_process();
+ world_entities_process();
+
+ /* main bulk */
+ world_generate();
+ world_routes_generate();
+ world_post_process();
}
#endif /* WORLD_GEN_H */
vg_tex2d tex_graffiti = { .path = "textures/graffitibox.qoi",
.flags = VG_TEXTURE_NEAREST };
-static void world_render_init(void)
+VG_STATIC void world_render_init(void)
{
vg_info( "Loading default world textures\n" );
vg_release_thread_sync();
}
-static void world_render_free(void*_)
-{
- vg_tex2d_free( (vg_tex2d *[]){ &tex_terrain_colours,
- &tex_terrain_noise,
- &tex_alphatest,
- &tex_graffiti }, 4 );
-}
-
-
-
-static void render_world_depth( m4x4f projection, m4x3f camera );
-
-
-
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera );
/*
* Rendering
*/
-static void bind_terrain_textures(void)
+VG_STATIC void bind_terrain_textures(void)
{
vg_tex2d_bind( &tex_terrain_noise, 0 );
vg_tex2d_bind( &tex_terrain_colours, 1 );
}
-static void render_world_vb( m4x4f projection, v3f camera )
+VG_STATIC void render_world_vb( m4x4f projection, v3f camera )
{
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
shader_vblend_uMdl( identity_matrix );
shader_vblend_uCamera( camera );
- scene_bind( &world.geo );
+ mesh_bind( &world.mesh_geo );
mdl_draw_submesh( &world.sm_geo_vb );
-
- mesh_bind( &world.cars );
-
-#if 0
- for( int i=0; i<vg_list_size(world.van_man); i++ )
- {
- shader_vblend_uMdl( world.van_man[i].transform );
- mdl_draw_submesh( &world.car_holden );
- }
-#endif
}
-static void render_world_alphatest( m4x4f projection, v3f camera )
+VG_STATIC void render_world_alphatest( m4x4f projection, v3f camera )
{
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
shader_alphatest_uCamera( camera );
glDisable(GL_CULL_FACE);
- scene_bind( &world.foliage );
+ mesh_bind( &world.mesh_no_collide );
mdl_draw_submesh( &world.sm_foliage_alphatest );
vg_tex2d_bind( &tex_graffiti, 1 );
glEnable(GL_CULL_FACE);
}
-static void render_terrain( m4x4f projection, v3f camera )
+VG_STATIC void render_terrain( m4x4f projection, v3f camera )
{
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
shader_terrain_uMdl( identity_matrix );
shader_terrain_uCamera( camera );
- scene_bind( &world.geo );
+ mesh_bind( &world.mesh_geo );
mdl_draw_submesh( &world.sm_terrain );
mdl_draw_submesh( &world.sm_geo_std_oob );
mdl_draw_submesh( &world.sm_geo_std );
mdl_draw_submesh( &world.sm_subworld );
/* TODO: Dont draw in reflection */
- glDisable(GL_CULL_FACE);
- scene_bind( &world.foliage );
+ glDisable( GL_CULL_FACE );
+ mesh_bind( &world.mesh_no_collide );
mdl_draw_submesh( &world.sm_foliage_main );
- glEnable(GL_CULL_FACE);
+ glEnable( GL_CULL_FACE );
}
-static void render_lowerdome( m4x3f camera )
+VG_STATIC void render_lowerdome( m4x3f camera )
{
m4x4f projection, full;
pipeline_projection( projection, 0.4f, 1000.0f );
mdl_draw_submesh( &world.dome_lower );
}
-static void render_sky(m4x3f camera)
+VG_STATIC void render_sky(m4x3f camera)
{
m4x4f projection, full;
pipeline_projection( projection, 0.4f, 1000.0f );
glDepthMask( GL_TRUE );
}
-static void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera )
+VG_STATIC void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera )
{
float closest = INFINITY;
int id = 0;
- for( int i=0; i<world_routes.gate_count; i++ )
+ for( int i=0; i<world.gate_count; i++ )
{
- struct route_gate *rg = &world_routes.gates[i];
+ struct route_gate *rg = &world.gates[i];
float dist = v3_dist2( rg->gate.co[0], camera[3] );
if( dist < closest )
}
}
- render_gate( &world_routes.gates[id].gate, playerco, camera );
+ render_gate( &world.gates[id].gate, playerco, camera );
v3_lerp( world.render_gate_pos,
- world_routes.gates[id].gate.co[0],
+ world.gates[id].gate.co[0],
1.0f,
world.render_gate_pos );
}
-static void render_world( m4x4f projection, m4x3f camera )
+VG_STATIC void render_world( m4x4f projection, m4x3f camera )
{
render_sky( camera );
render_world_routes( projection, camera[3] );
int closest = 0;
float min_dist = INFINITY;
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- float dist = v3_dist2( world_routes.routes[i].scoreboard_transform[3],
+ float dist = v3_dist2( world.routes[i].scoreboard_transform[3],
camera[3] );
if( dist < min_dist )
}
}
- sfd_render( &world.sfd.tester, projection, camera[3],
- world_routes.routes[closest].scoreboard_transform );
+ sfd_render( projection, camera[3],
+ world.routes[closest].scoreboard_transform );
}
-static void render_world_depth( m4x4f projection, m4x3f camera )
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera )
{
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
shader_gpos_uPv( projection );
shader_gpos_uMdl( identity_matrix );
- scene_bind( &world.geo );
- scene_draw( &world.geo );
+ mesh_bind( &world.mesh_geo );
+ mesh_draw( &world.mesh_geo );
#if 0
glDisable(GL_CULL_FACE);
enum route_special_type
{
+ k_route_special_type_none = 0,
k_route_special_type_gate = 1,
k_route_special_type_collector = 2
};
-static void debug_sbpath( struct route_node *rna, struct route_node *rnb,
+VG_STATIC void debug_sbpath( struct route_node *rna, struct route_node *rnb,
u32 colour, float xoffset )
{
v3f p0, h0, p1, h1, l, p;
/*
* Get a list of node ids in stack, and return how many there is
*/
-static u32 world_routes_get_path( u32 starter, u32 stack[64] )
+VG_STATIC u32 world_routes_get_path( u32 starter, u32 stack[64] )
{
u32 stack_i[64];
continue;
}
- struct route_node *rn = &world_routes.nodes[stack[si-1]];
+ struct route_node *rn = &world.nodes[stack[si-1]];
u32 nextid = rn->next[stack_i[si-1]];
stack_i[si-1] ++;
/*
* Free a segment from the UI bar to be reused later
*/
-static void world_routes_ui_popfirst( u32 route )
+VG_STATIC void world_routes_ui_popfirst( struct route_ui_bar *pui )
{
- struct route *pr = &world_routes.routes[route];
-
- if( pr->ui.segment_count )
+ if( pui->segment_count )
{
- pr->ui.segment_start ++;
+ pui->segment_start ++;
- if( pr->ui.segment_start == 32 )
- pr->ui.segment_start = 0;
+ if( pui->segment_start == 32 )
+ pui->segment_start = 0;
- pr->ui.segment_count --;
+ pui->segment_count --;
}
}
/*
* Reset ui bar completely
*/
-static void world_routes_ui_clear( u32 route )
+VG_STATIC void world_routes_ui_clear( struct route_ui_bar *pui )
{
- struct route *pr = &world_routes.routes[route];
- pr->ui.segment_start = (pr->ui.segment_start + pr->ui.segment_count) %
- k_max_ui_segments;
- pr->ui.segment_count = 0;
+ pui->segment_start = (pui->segment_start + pui->segment_count) %
+ k_max_ui_segments;
+ pui->segment_count = 0;
}
/*
* Break a index range into two pieces over the edge of the maximum it can
* store. s1 is 0 always, so its a ring buffer.
*/
-static void world_routes_ui_split_indices( u32 s0, u32 count, u32 *c0, u32 *c1 )
+VG_STATIC void world_routes_ui_split_indices( u32 s0, u32 count,
+ u32 *c0, u32 *c1 )
{
*c0 = (VG_MIN( s0+count, k_route_ui_max_indices )) - s0;
*c1 = count-(*c0);
* Place a set of indices into gpu array automatically splits
* across bounds
*/
-static void world_routes_ui_set_indices( struct route *pr,
- u16 *indices, u32 count )
+VG_STATIC void world_routes_ui_set_indices( struct route_ui_bar *pui,
+ u16 *indices, u32 count )
{
u32 c0, c1;
- world_routes_ui_split_indices( pr->ui.indices_head, count, &c0, &c1 );
+ world_routes_ui_split_indices( pui->indices_head, count, &c0, &c1 );
- glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pr->ui.ebo );
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pui->ebo );
if( c0 )
{
- glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pr->ui.indices_head*sizeof(u16),
+ glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pui->indices_head*sizeof(u16),
c0*sizeof(u16), indices );
}
if( c1 )
{
glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, c1*sizeof(u16), indices+c0 );
- pr->ui.indices_head = c1;
+ pui->indices_head = c1;
}
else
- pr->ui.indices_head += c0;
+ pui->indices_head += c0;
}
/*
* Place a set of vertices into gpu array
*/
-static u32 world_routes_ui_set_verts( struct route *pr, v2f *verts, u32 count )
+VG_STATIC u32 world_routes_ui_set_verts( struct route_ui_bar *pui,
+ v2f *verts, u32 count )
{
- if( pr->ui.vertex_head + count >= k_route_ui_max_verts )
- pr->ui.vertex_head = 0;
+ if( pui->vertex_head + count >= k_route_ui_max_verts )
+ pui->vertex_head = 0;
- u32 vert_start = pr->ui.vertex_head;
- pr->ui.vertex_head += count;
+ u32 vert_start = pui->vertex_head;
+ pui->vertex_head += count;
- glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+ glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
sizeof(v2f)*count, verts );
* Update the last (count) vertices positions, does not add any.
* Data must already be written to, and not cross either array boundaries.
*/
-static u32 world_routes_ui_update_verts( struct route *pr,
+VG_STATIC u32 world_routes_ui_update_verts( struct route_ui_bar *pui,
v2f *verts, u32 count )
{
- u32 vert_start = pr->ui.vertex_head-count;
+ u32 vert_start = pui->vertex_head-count;
- glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+ glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
sizeof(v2f)*count, verts );
/*
* Current/active segment of this UI bar
*/
-static struct route_ui_segment *world_routes_ui_curseg( struct route *pr )
+VG_STATIC struct route_ui_segment *world_routes_ui_curseg(
+ struct route_ui_bar *pui )
{
- u32 index = (pr->ui.segment_start+pr->ui.segment_count-1)%k_max_ui_segments;
- return &pr->ui.segments[ index ];
+ u32 index = (pui->segment_start+pui->segment_count-1)%k_max_ui_segments;
+ return &pui->segments[ index ];
}
/*
* Start a new segment in the UI bar, will create a split on the last one if
* there is one active currently. (api)
*/
-static void world_routes_ui_newseg( u32 route )
+VG_STATIC void world_routes_ui_newseg( u32 route )
{
- struct route *pr = &world_routes.routes[route];
+ struct route_ui_bar *pui = &world.ui_bars[route];
- pr->ui.last_notch = 0.0;
+ pui->last_notch = 0.0;
- glBindVertexArray( pr->ui.vao );
- if( pr->ui.segment_count )
+ glBindVertexArray( pui->vao );
+ if( pui->segment_count )
{
float const k_gap_width = 1.0f;
- struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
+ struct route_ui_segment *cseg = world_routes_ui_curseg( pui );
v2f verts[2];
verts[0][0] = cseg->length-k_gap_width;
verts[1][0] = cseg->length-k_gap_width;
verts[1][1] = -0.5f;
- world_routes_ui_update_verts( pr, verts, 2 );
+ world_routes_ui_update_verts( pui, verts, 2 );
}
- pr->ui.segment_count ++;
- struct route_ui_segment *segment = world_routes_ui_curseg(pr);
+ pui->segment_count ++;
+ struct route_ui_segment *segment = world_routes_ui_curseg( pui );
v2f verts[4];
verts[0][0] = 0.0f;
verts[3][0] = 0.0f;
verts[3][1] = -0.5f;
- u32 vert_start = world_routes_ui_set_verts( pr, verts, 4 );
+ u32 vert_start = world_routes_ui_set_verts( pui, verts, 4 );
u16 indices[6];
indices[0] = vert_start + 0;
segment->vertex_start = vert_start;
segment->vertex_count = 4;
- segment->index_start = pr->ui.indices_head;
+ segment->index_start = pui->indices_head;
segment->index_count = 6;
segment->notches = 0;
- world_routes_ui_set_indices( pr, indices, 6 );
+ world_routes_ui_set_indices( pui, indices, 6 );
}
/*
* Extend the end of the bar
*/
-static void world_routes_ui_updatetime( u32 route, float time )
+VG_STATIC void world_routes_ui_updatetime( u32 route, float time )
{
- struct route *pr = &world_routes.routes[route];
+ struct route_ui_bar *pui = &world.ui_bars[route];
v2f verts[2];
verts[0][0] = time;
verts[1][0] = time;
verts[1][1] = -0.5f;
- u32 vert_start = pr->ui.vertex_head-2;
+ u32 vert_start = pui->vertex_head-2;
- glBindVertexArray( pr->ui.vao );
- world_routes_ui_update_verts( pr, verts, 2 );
+ glBindVertexArray( pui->vao );
+ world_routes_ui_update_verts( pui, verts, 2 );
- struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
+ struct route_ui_segment *cseg = world_routes_ui_curseg( pui );
cseg->length = time;
}
-/*
- * Create a notch in the bar, used when a reset is triggered by the user
- */
-static void world_routes_ui_notch( u32 route, float time )
-{
- return; /* FIXME: Temporarily disabled */
-
- struct route *pr = &world_routes.routes[route];
-
- if( (time - pr->ui.last_notch) > 1.0 )
- {
- struct route_ui_segment *segment = world_routes_ui_curseg(pr);
- if( segment->notches == k_max_ui_splits_per_segment )
- return;
-
- segment->notches ++;
-
- v2f verts[8];
-
- float const k_notch_width = 1.0f;
-
- float xa = time-k_notch_width,
- xb = time-k_notch_width * 0.5f,
- xc = time;
-
- verts[0][0] = xa;
- verts[0][1] = 0.5f;
- verts[1][0] = xa;
- verts[1][1] = -0.5f;
-
- verts[2][0] = xb;
- verts[2][1] = 0.25f;
- verts[3][0] = xb;
- verts[3][1] = -0.25f;
-
- verts[4][0] = xc;
- verts[4][1] = 0.5f;
- verts[5][0] = xc;
- verts[5][1] = -0.5f;
-
- verts[6][0] = xc;
- verts[6][1] = 0.5f;
- verts[7][0] = xc;
- verts[7][1] = -0.5f;
-
- glBindVertexArray( pr->ui.vao );
- u32 vert_start_mod = world_routes_ui_update_verts( pr, verts, 2 ),
- vert_start_new = world_routes_ui_set_verts( pr, verts+2, 6 );
-
- u16 indices[18];
- indices[ 0] = vert_start_mod+1;
- indices[ 1] = vert_start_new+0;
- indices[ 2] = vert_start_mod+0;
- indices[ 3] = vert_start_mod+1;
- indices[ 4] = vert_start_new+1;
- indices[ 5] = vert_start_new+0;
-
- indices[ 6] = vert_start_new+0;
- indices[ 7] = vert_start_new+1;
- indices[ 8] = vert_start_new+3;
- indices[ 9] = vert_start_new+0;
- indices[10] = vert_start_new+3;
- indices[11] = vert_start_new+2;
-
- indices[12] = vert_start_new+3;
- indices[13] = vert_start_new+4;
- indices[14] = vert_start_new+2;
- indices[15] = vert_start_new+3;
- indices[16] = vert_start_new+5;
- indices[17] = vert_start_new+4;
-
- world_routes_ui_set_indices( pr, indices, 18 );
-
- pr->ui.last_notch = time;
-
- segment->vertex_count += 6;
- segment->index_count += 18;
- }
-}
-
-static void world_routes_ui_draw_segment( struct route_ui_segment *segment )
+VG_STATIC void world_routes_ui_draw_segment( struct route_ui_segment *segment )
{
u32 c0, c1;
world_routes_ui_split_indices( segment->index_start,
/*
* Draws full bar at Y offset(offset).
*/
-static void world_routes_ui_draw( u32 route, v4f colour, float offset )
+VG_STATIC void world_routes_ui_draw( u32 route, v4f colour, float offset )
{
float const k_bar_height = 0.05f,
k_bar_scale_x = 0.005f;
- struct route *pr = &world_routes.routes[route];
+ struct route *pr = &world.routes[route];
+ struct route_ui_bar *pui = &world.ui_bars[route];
- float cx = pr->ui.xpos;
+ float cx = pui->xpos;
shader_routeui_use();
- glBindVertexArray( pr->ui.vao );
+ glBindVertexArray( pui->vao );
- float fade_amt = world_routes.time - pr->ui.fade_timer_start;
+ float fade_amt = world.time - pui->fade_timer_start;
fade_amt = vg_clampf( fade_amt / 1.0f, 0.0f, 1.0f );
float fade_block_size = 0.0f,
main_block_size = 0.0f;
- for( u32 i=0; i<pr->ui.fade_count; i++ )
+ for( u32 i=0; i<pui->fade_count; i++ )
{
- u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
- struct route_ui_segment *segment = &pr->ui.segments[j];
+ u32 j = (pui->fade_start + i) % k_max_ui_segments;
+ struct route_ui_segment *segment = &pui->segments[j];
fade_block_size += segment->length;
}
fade_colour[3] *= 1.0f-fade_amt;
/* 1 minute timer */
- float timer_delta = (world_routes.time - world_routes.last_use) * (1.0/45.0),
+ float timer_delta = (world.time - world.last_use) * (1.0/45.0),
timer_scale = 1.0f - vg_minf( timer_delta, 1.0f );
/*
base = -1.0f + (offset+0.5f)*k_bar_height * timer_scale;
shader_routeui_uColour( fade_colour );
- for( u32 i=0; i<pr->ui.fade_count; i++ )
+ for( u32 i=0; i<pui->fade_count; i++ )
{
- u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
- struct route_ui_segment *segment = &pr->ui.segments[j];
+ u32 j = (pui->fade_start + i) % k_max_ui_segments;
+ struct route_ui_segment *segment = &pui->segments[j];
shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
k_bar_scale_x, height } );
* Draw main bar
*/
shader_routeui_uColour( colour );
- for( u32 i=0; i<pr->ui.segment_count; i++ )
+ for( u32 i=0; i<pui->segment_count; i++ )
{
- u32 j = (pr->ui.segment_start + i) % k_max_ui_segments;
- struct route_ui_segment *segment = &pr->ui.segments[j];
+ u32 j = (pui->segment_start + i) % k_max_ui_segments;
+ struct route_ui_segment *segment = &pui->segments[j];
shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
k_bar_scale_x, height } );
main_block_size += segment->length;
}
- pr->ui.xpos = vg_lerpf( pr->ui.xpos, -main_block_size * 0.5f, 0.03f );
+ pui->xpos = vg_lerpf( pui->xpos, -main_block_size * 0.5f, 0.03f );
}
-static void world_routes_local_set_record( u32 route, double lap_time )
+VG_STATIC void world_routes_local_set_record( u32 route, double lap_time )
{
vg_success( " NEW LAP TIME: %f\n", lap_time );
- struct route *pr = &world_routes.routes[route];
+ struct route *pr = &world.routes[route];
if( pr->track_id != 0xffffffff )
{
* 2: the time of each segment will be recorded into the data buffer
* (not implemented: TODO)
*/
-static void world_routes_verify_run( u32 route )
+VG_STATIC void world_routes_verify_run( u32 route )
{
- struct route *pr = &world_routes.routes[route];
+ struct route *pr = &world.routes[route];
+ struct route_ui_bar *pui = &world.ui_bars[route];
u32 stack[64];
- u32 si = world_routes_get_path( world_routes.routes[route].start, stack );
+ u32 si = world_routes_get_path( world.routes[route].start, stack );
/*
* we only care about gates that ref gates, so shuffle down the array
u32 sj = 0, maxv = 0, begin = 0;
for( u32 i=0; i<si; i++ )
{
- struct route_node *inode = &world_routes.nodes[stack[i]];
+ struct route_node *inode = &world.nodes[stack[i]];
if( inode->special_type == k_route_special_type_collector )
{
- timings[sj ++] = &world_routes.collectors[ inode->special_id ].timing;
+ timings[sj ++] = &world.collectors[ inode->special_id ].timing;
}
else if( inode->special_type == k_route_special_type_gate )
{
- timings[sj ++] = &world_routes.gates[inode->special_id].timing;
+ timings[sj ++] = &world.gates[inode->special_id].timing;
}
}
}
vg_info( "== begin verification (%u) ==\n", route );
- vg_info( " current version: %u\n", world_routes.current_run_version );
+ vg_info( " current version: %u\n", world.current_run_version );
int verified = 0;
- if( timings[begin]->version == world_routes.current_run_version )
+ if( timings[begin]->version == world.current_run_version )
verified = 1;
int valid_segment_count = 0;
if( verified )
vg_success( " [ %u %f ] %f\n", timings[j1]->time,
- timings[j1]->version, diff );
+ timings[j1]->version, diff );
else
vg_warn( " [ %u %f ]\n", timings[j1]->time, timings[j1]->version );
}
- pr->ui.fade_start = pr->ui.segment_start;
- pr->ui.fade_count = 0;
- pr->ui.fade_timer_start = world_routes.time;
+ pui->fade_start = pui->segment_start;
+ pui->fade_count = 0;
+ pui->fade_timer_start = world.time;
- int orig_seg_count = pr->ui.segment_count;
+ int orig_seg_count = pui->segment_count;
world_routes_ui_newseg( route );
if( verified )
{
world_routes_local_set_record( route, lap_time );
- world_routes_ui_popfirst(route);
- pr->ui.fade_count ++;
+ world_routes_ui_popfirst( pui );
+ pui->fade_count ++;
}
else
vg_info( " ctime: %f\n", lap_time );
int to_remove = orig_seg_count-valid_segment_count;
for( int i=0; i<to_remove; i++ )
{
- world_routes_ui_popfirst(route);
- pr->ui.fade_count ++;
+ world_routes_ui_popfirst( pui );
+ pui->fade_count ++;
}
- world_routes.routes[route].latest_pass = world_routes.time;
+ world.routes[route].latest_pass = world.time;
}
/*
* When going through a gate this is called for bookkeeping purposes
*/
-static void world_routes_activate_gate( u32 id )
+VG_STATIC void world_routes_activate_gate( u32 id )
{
- struct route_gate *rg = &world_routes.gates[id];
- struct route_node *pnode = &world_routes.nodes[rg->node_id],
- *pdest = &world_routes.nodes[pnode->next[0]];
+ struct route_gate *rg = &world.gates[id];
+ struct route_node *pnode = &world.nodes[rg->node_id],
+ *pdest = &world.nodes[pnode->next[0]];
+
+ world.last_use = world.time;
- world_routes.last_use = world_routes.time;
+ struct route_collector *rc = &world.collectors[ pdest->special_id ];
- struct route_collector *rc = &world_routes.collectors[ pdest->special_id ];
+ world.active_gate = id;
+ rg->timing.version = world.current_run_version;
+ rg->timing.time = world.time;
- world_routes.active_gate = id;
- rg->timing.version = world_routes.current_run_version;
- rg->timing.time = world_routes.time;
- for( u32 i=0; i<world_routes.route_count; i++ )
+ for( u32 i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
int was_active = route->active;
if( was_active && !route->active )
{
- route->ui.fade_start = route->ui.segment_start;
- route->ui.fade_count = route->ui.segment_count;
- route->ui.fade_timer_start = world_routes.time;
- world_routes_ui_clear(i);
-
- vg_success( "CLEARING -> %u %u \n", route->ui.fade_start,
- route->ui.fade_count );
+ struct route_ui_bar *pui = &world.ui_bars[i];
+ pui->fade_start = pui->segment_start;
+ pui->fade_count = pui->segment_count;
+ pui->fade_timer_start = world.time;
+
+ world_routes_ui_clear( pui );
+ vg_success( "CLEARING -> %u %u \n", pui->fade_start,
+ pui->fade_count );
}
}
- world_routes.current_run_version ++;
+ world.current_run_version ++;
- rc->timing.version = world_routes.current_run_version;
- rc->timing.time = world_routes.time;
- world_routes.current_run_version ++;
+ rc->timing.version = world.current_run_version;
+ rc->timing.time = world.time;
+ world.current_run_version ++;
}
/*
* Notify the UI system that we've reset the player
*/
-static void world_routes_notify_reset(void)
+VG_STATIC void world_routes_notify_reset(void)
{
- world_routes.rewind_from = world_routes.time;
- world_routes.rewind_to = world_routes.last_use;
+ world.rewind_from = world.time;
+ world.rewind_to = world.last_use;
#if 0
for( int i=0; i<r->route_count; i++ )
}
/* Rewind between the saved points in time */
-static void world_routes_rollback_time( double t )
+VG_STATIC void world_routes_rollback_time( double t )
{
- world_routes.time =
- vg_lerp( world_routes.rewind_to, world_routes.rewind_from, t );
+ world.time = vg_lerp( world.rewind_to, world.rewind_from, t );
}
/* draw lines along the paths */
-static void world_routes_debug(void)
+VG_STATIC void world_routes_debug(void)
{
-
- for( int i=0; i<world_routes.node_count; i++ )
+ for( int i=0; i<world.node_count; i++ )
{
- struct route_node *rn = &world_routes.nodes[i];
+ struct route_node *rn = &world.nodes[i];
vg_line_pt3( rn->co, 1.0f, rn->special_type? 0xffffff00: 0xff00b2ff );
}
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
u32 stack[64];
u32 si = world_routes_get_path( route->start, stack );
{
int sk = (sj+1)%si;
- struct route_node *pj = &world_routes.nodes[stack[sj]],
- *pk = &world_routes.nodes[stack[sk]];
+ struct route_node *pj = &world.nodes[stack[sj]],
+ *pk = &world.nodes[stack[sk]];
debug_sbpath( pj, pk, cc, (float)i );
}
}
- for( int i=0; i<world_routes.node_count; i++ )
+ for( int i=0; i<world.node_count; i++ )
{
- struct route_node *ri = &world_routes.nodes[i],
+ struct route_node *ri = &world.nodes[i],
*rj = NULL;
for( int j=0; j<2; j++ )
{
if( ri->next[j] != 0xffffffff )
{
- rj = &world_routes.nodes[ri->next[j]];
+ rj = &world.nodes[ri->next[j]];
vg_line( ri->co, rj->co, 0x20ffffff );
}
}
}
}
-static void world_id_fixup( u32 *uid, mdl_header *mdl )
+VG_STATIC void world_routes_create_mesh( u32 route_id )
{
- if( *uid )
- *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
- else
- *uid = 0xffffffff;
-}
-
-static void world_routes_create_mesh( u32 route_id )
-{
- struct route *route = &world_routes.routes[ route_id ];
+ struct route *route = &world.routes[ route_id ];
u32 stack[64];
u32 si = world_routes_get_path( route->start, stack );
{
int sk=(sj+1)%si;
- struct route_node *rnj = &world_routes.nodes[ stack[sj] ],
- *rnk = &world_routes.nodes[ stack[sk] ],
+ struct route_node *rnj = &world.nodes[ stack[sj] ],
+ *rnk = &world.nodes[ stack[sk] ],
*rnl;
if( rnj->special_type && rnk->special_type )
if( rnk->special_type )
{
- rnl = &world_routes.nodes[ rnk->next[0] ];
+ rnl = &world.nodes[ rnk->next[0] ];
base_x1 = (float)rnl->ref_count*-0.5f + (float)rnl->current_refs;
}
v2_zero( va.uv );
v2_zero( vb.uv );
- scene_push_vert( &world_routes.scene_lines, &va );
- scene_push_vert( &world_routes.scene_lines, &vb );
+ scene_push_vert( world.scene_lines, &va );
+ scene_push_vert( world.scene_lines, &vb );
if( last_valid )
{
/* Connect them with triangles */
- scene_push_tri( &world_routes.scene_lines, (u32[3]){
+ scene_push_tri( world.scene_lines, (u32[3]){
last_valid+0-2, last_valid+1-2, last_valid+2-2} );
- scene_push_tri( &world_routes.scene_lines, (u32[3]){
+ scene_push_tri( world.scene_lines, (u32[3]){
last_valid+1-2, last_valid+3-2, last_valid+2-2} );
}
- last_valid = world_routes.scene_lines.vertex_count;
+ last_valid = world.scene_lines->vertex_count;
}
else
last_valid = 0;
rnj->current_refs ++;
}
- scene_copy_slice( &world_routes.scene_lines, &route->sm );
+ scene_copy_slice( world.scene_lines, &route->sm );
}
/*
* Create the strips of colour that run through the world along course paths
*/
-static int world_routes_create_all_meshes(void)
+VG_STATIC void world_routes_generate(void)
{
vg_info( "Generating route meshes\n" );
+ world.scene_lines = scene_init( world.dynamic_vgl, 200000, 300000 );
- scene_init( &world_routes.scene_lines );
-
- for( u32 i=0; i<world_routes.route_count; i++ )
+ for( u32 i=0; i<world.route_count; i++ )
world_routes_create_mesh( i );
vg_acquire_thread_sync();
{
- scene_upload( &world_routes.scene_lines );
+ scene_upload( world.scene_lines, &world.mesh_route_lines );
+ }
+ vg_release_thread_sync();
+ vg_linear_del( world.dynamic_vgl, world.scene_lines );
+}
+
+/* determine if special type is required for this gate */
+VG_STATIC enum route_special_type world_route_node_type( mdl_node *pnode )
+{
+ if( pnode->classtype == k_classtype_gate )
+ {
+ struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
- /* UI buffers */
- for( int i=0; i<world_routes.route_count; i++ )
+ if( inf->target )
{
- /* OpenGL strips */
- struct route *route = &world_routes.routes[i];
+ mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+
+ if( pother->classtype == k_classtype_gate )
+ {
+ return k_route_special_type_gate;
+ }
+ }
- glGenVertexArrays( 1, &route->ui.vao );
- glGenBuffers( 1, &route->ui.vbo );
- glGenBuffers( 1, &route->ui.ebo );
- glBindVertexArray( route->ui.vao );
+ return k_route_special_type_collector;
+ }
- size_t stride = sizeof(v2f);
+ return k_route_special_type_none;
+}
- glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo );
- glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride,
- NULL, GL_DYNAMIC_DRAW );
+/* count entities and allocate correct amount of memory in advance */
+VG_STATIC void world_routes_allocate(void)
+{
+ vg_info( "Allocating routes\n" );
- glBindVertexArray( route->ui.vao );
- glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, route->ui.ebo );
- glBufferData( GL_ELEMENT_ARRAY_BUFFER,
- k_route_ui_max_indices*sizeof(u16), NULL,
- GL_DYNAMIC_DRAW );
+ /* count */
+ u32 node_count = 0,
+ route_count = 0,
+ gate_count = 0,
+ collector_count = 0;
+
+ for( int i=0; i<world.meta->info.node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id( world.meta, i );
- glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 );
- glEnableVertexAttribArray( 0 );
- VG_CHECK_GL_ERR();
+ if( pnode->classtype == k_classtype_route_node ||
+ pnode->classtype == k_classtype_gate )
+ {
+ pnode->sub_uid = node_count;
+
+ enum route_special_type type = world_route_node_type( pnode );
+
+ if( type == k_route_special_type_gate )
+ gate_count ++;
+ else if( type == k_route_special_type_collector )
+ collector_count ++;
+
+ node_count ++;
+ }
+ else if( pnode->classtype == k_classtype_route )
+ {
+ route_count ++;
}
}
- vg_release_thread_sync();
- scene_free_offline_buffers( &world_routes.scene_lines );
- return 1;
-}
+ /* allocate */
+ u32 node_size = node_count * sizeof(struct route_node),
+ route_size = route_count * sizeof(struct route),
+ gate_size = gate_count * sizeof(struct route_gate),
+ collector_size = collector_count * sizeof(struct route_collector);
+ world.nodes = vg_linear_alloc( world.dynamic_vgl, node_size );
+ world.routes = vg_linear_alloc( world.dynamic_vgl, route_size );
+ world.gates = vg_linear_alloc( world.dynamic_vgl, gate_size );
+ world.collectors = vg_linear_alloc( world.dynamic_vgl, collector_size );
+}
-static void world_routes_loadfrom( mdl_header *mdl )
+/* create node from mdl node */
+VG_STATIC struct route_node *world_routes_create_node( mdl_node *pnode )
{
- vg_info( "Initializing routes\n" );
+ struct route_node *rn = &world.nodes[ world.node_count ++ ];
- world_routes.nodes = NULL;
- world_routes.node_count = 0;
- world_routes.node_cap = 0;
- world_routes.routes = NULL;
- world_routes.route_count = 0;
- world_routes.route_cap = 0;
- world_routes.gates = NULL;
- world_routes.gate_count = 0;
- world_routes.gate_cap = 0;
-
- /* TODO Break this up */
- for( int i=0; i<mdl->node_count; i++ )
- {
- mdl_node *pnode = mdl_node_from_id(mdl,i);
- m4x3f transform;
+ m4x3f transform;
+ mdl_node_transform( pnode, transform );
- if( pnode->classtype == k_classtype_route_node ||
- pnode->classtype == k_classtype_gate )
- {
- mdl_node_transform( pnode, transform );
- pnode->sub_uid = world_routes.node_count;
-
- world_routes.nodes = buffer_reserve( world_routes.nodes,
- world_routes.node_count,
- &world_routes.node_cap, 1,
- sizeof( struct route_node ) );
-
- struct route_node *rn = &world_routes.nodes[world_routes.node_count];
-
- v3_copy( transform[0], rn->right );
- v3_normalize( rn->right );
- v3_copy( transform[1], rn->up );
- v3_normalize( rn->up );
- v3_muls( transform[2], -1.0f, rn->h );
- v3_copy( transform[3], rn->co );
- rn->ref_count = 0;
- rn->current_refs = 0;
- rn->special_type = 0;
- rn->special_id = 0;
+ v3_copy( transform[3], rn->co );
+ v3_copy( transform[0], rn->right );
+ v3_copy( transform[1], rn->up );
+ v3_muls( transform[2], -1.0f, rn->h );
+ v3_normalize( rn->right );
+ v3_normalize( rn->up );
- if( pnode->classtype == k_classtype_gate )
- {
- struct classtype_gate *inf = mdl_get_entdata( mdl, pnode );
+ rn->next[0] = 0xffffffff;
+ rn->next[1] = 0xffffffff;
- /* H is later scaled based on link distance */
- v3_normalize( rn->h );
- rn->next[0] = inf->target;
- rn->next[1] = 0;
+ rn->special_type = 0;
+ rn->special_id = 0;
+ rn->current_refs = 0;
+ rn->ref_count = 0;
- /* TODO */
- if( inf->target )
- {
- mdl_node *pother = mdl_node_from_id( mdl, inf->target );
-
- if( pother->classtype == k_classtype_gate )
- {
- world_routes.gates = buffer_reserve( world_routes.gates,
- world_routes.gate_count,
- &world_routes.gate_cap,
- 1, sizeof( struct route_gate ) );
-
- struct route_gate *rg =
- &world_routes.gates[world_routes.gate_count];
-
- rg->node_id = world_routes.node_count;
- rg->timing.time = 0.0;
- rg->timing.version = 0;
-
- v3_copy( pnode->co, rg->gate.co[0] );
- v3_copy( pother->co, rg->gate.co[1] );
- v4_copy( pnode->q, rg->gate.q[0] );
- v4_copy( pother->q, rg->gate.q[1] );
- v2_copy( inf->dims, rg->gate.dims );
-
- gate_transform_update( &rg->gate );
- rn->special_type = k_route_special_type_gate;
- rn->special_id = world_routes.gate_count;
-
- world_routes.gate_count ++;
- }
- }
+ return rn;
+}
- if( rn->special_type == 0 )
- {
- world_routes.collectors = buffer_reserve(
- world_routes.collectors,
- world_routes.collector_count,
- &world_routes.collector_cap,
- 1, sizeof( struct route_collector ));
+/* retrieve the correct node id from mdl subuid */
+VG_STATIC u32 world_routes_get_subuid( u32 target )
+{
+ if( target == 0 )
+ return 0xffffffff;
+ else
+ return mdl_node_from_id( world.meta, target )->sub_uid;
+}
+
+#if 0
+VG_STATIC void world_id_fixup( u32 *uid, mdl_context *mdl )
+{
+ if( *uid )
+ *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
+ else
+ *uid = 0xffffffff;
+}
+#endif
- struct route_collector *rc =
- &world_routes.collectors[world_routes.collector_count];
- rc->timing.time = 0.0;
- rc->timing.version = 0;
+/* process gate attachement onto node */
+VG_STATIC void world_routes_process_gate( struct route_node *rn,
+ mdl_node *pnode )
+{
+ struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
- rn->special_type = k_route_special_type_collector;
- rn->special_id = world_routes.collector_count;
+ /* H is later scaled based on link distance */
+ v3_normalize( rn->h );
- world_routes.collector_count ++;
- }
- }
- else
- {
- struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
- rn->next[0] = inf->target;
- rn->next[1] = inf->target1;
- }
+ rn->next[0] = world_routes_get_subuid( inf->target );
+ rn->next[1] = 0xffffffff;
+ rn->special_type = world_route_node_type( pnode );
- world_routes.node_count ++;
- }
- else if( pnode->classtype == k_classtype_route )
- {
- struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
- world_routes.routes = buffer_reserve( world_routes.routes,
- world_routes.route_count,
- &world_routes.route_cap,
- 1, sizeof( struct route ) );
+ /* process gate type */
+ if( rn->special_type == k_route_special_type_gate )
+ {
+ mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+
+ struct route_gate *rg = &world.gates[ world.gate_count ];
- struct route *route = &world_routes.routes[world_routes.route_count];
- memset( route, 0, sizeof(struct route) );
+ rg->node_id = world.node_count-1;
+ rg->timing.time = 0.0;
+ rg->timing.version = 0;
- v3_copy( inf->colour, route->colour );
- route->colour[3] = 1.0f;
+ v3_copy( pnode->co, rg->gate.co[0] );
+ v3_copy( pother->co, rg->gate.co[1] );
+ v4_copy( pnode->q, rg->gate.q[0] );
+ v4_copy( pother->q, rg->gate.q[1] );
+ v2_copy( inf->dims, rg->gate.dims );
+ gate_transform_update( &rg->gate );
+ rn->special_id = world.gate_count;
- route->track_id = 0xffffffff;
- for( u32 j=0; j<vg_list_size(track_infos); j++ )
- {
- if( !strcmp( mdl_pstr(mdl,pnode->pstr_name), track_infos[j].name ))
- {
- route->track_id = j;
- break;
- }
- }
+ world.gate_count ++;
+ }
- route->start = inf->id_start;
- route->active = 0;
- route->factive = 0.0f;
- mdl_node_transform( pnode, route->scoreboard_transform );
-
- route->ui.indices_head = k_route_ui_max_indices - 9;
- route->ui.vertex_head = k_route_ui_max_verts - 200;
- route->ui.segment_start = 0;
- route->ui.segment_count = 0;
- route->ui.last_notch = 0.0;
- route->ui.fade_start = 0;
- route->ui.fade_count = 0;
- route->ui.fade_timer_start = 0.0;
-
- world_routes.route_count ++;
- }
+ /* process collector type */
+ else if( rn->special_type == k_route_special_type_collector )
+ {
+ struct route_collector *rc =
+ &world.collectors[ world.collector_count ];
+
+ rc->timing.time = 0.0;
+ rc->timing.version = 0;
+
+ rn->special_id = world.collector_count;
+ world.collector_count ++;
}
+ else
+ vg_fatal_exit_loop( "Invalid state" );
+}
- /*
- * Apply correct system-local ids
- */
- for( int i=0; i<world_routes.node_count; i++ )
+/* create route from node description */
+VG_STATIC void world_routes_create_route( mdl_node *pnode )
+{
+ mdl_context *mdl = world.meta;
+
+ struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
+ struct route *route = &world.routes[ world.route_count ];
+ memset( route, 0, sizeof(struct route) );
+
+ v3_copy( inf->colour, route->colour );
+ route->colour[3] = 1.0f;
+ route->track_id = 0xffffffff;
+
+ for( u32 j=0; j<vg_list_size(track_infos); j++ )
{
- struct route_node *rn = &world_routes.nodes[i];
-
- for( int j=0; j<2; j++ )
- world_id_fixup( &rn->next[j], mdl );
+ if( !strcmp( mdl_pstr(mdl,pnode->pstr_name), track_infos[j].name ))
+ {
+ route->track_id = j;
+ break;
+ }
}
- for( int i=0; i<world_routes.route_count; i++ )
+ route->start = world_routes_get_subuid( inf->id_start );
+ route->active = 0;
+ route->factive = 0.0f;
+ mdl_node_transform( pnode, route->scoreboard_transform );
+
+ struct route_ui_bar *pui = &world.ui_bars[ world.route_count ];
+ pui->indices_head = k_route_ui_max_indices - 9;
+ pui->vertex_head = k_route_ui_max_verts - 200;
+ pui->segment_start = 0;
+ pui->segment_count = 0;
+ pui->last_notch = 0.0;
+ pui->fade_start = 0;
+ pui->fade_count = 0;
+ pui->fade_timer_start = 0.0;
+
+ world.route_count ++;
+}
+
+/* load all routes from model header */
+VG_STATIC void world_routes_process(void)
+{
+ vg_info( "Initializing routes\n" );
+ mdl_context *mdl = world.meta;
+
+ for( int i=0; i<mdl->info.node_count; i++ )
{
- struct route *route = &world_routes.routes[i];
- world_id_fixup( &route->start, mdl );
+ mdl_node *pnode = mdl_node_from_id(mdl,i);
+
+ if( pnode->classtype == k_classtype_route_node ||
+ pnode->classtype == k_classtype_gate )
+ {
+ struct route_node *rn = world_routes_create_node( pnode );
+
+ if( pnode->classtype == k_classtype_gate )
+ {
+ world_routes_process_gate( rn, pnode );
+ }
+ else
+ {
+ struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
+ rn->next[0] = world_routes_get_subuid( inf->target );
+ rn->next[1] = world_routes_get_subuid( inf->target1 );
+ }
+ }
+ else if( pnode->classtype == k_classtype_route )
+ {
+ world_routes_create_route( pnode );
+ }
}
/*
* Gather references
*/
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
u32 stack[64];
u32 si = world_routes_get_path( route->start, stack );
for( int sj=0; sj<si; sj++ )
{
- struct route_node *rn = &world_routes.nodes[ stack[sj] ];
+ struct route_node *rn = &world.nodes[ stack[sj] ];
rn->route_ids[ rn->ref_count ++ ] = i;
if( rn->ref_count > 4 )
vg_warn( "Too many references on route node %i\n", i );
}
}
-
- world_routes_create_all_meshes();
}
/*
* -----------------------------------------------------------------------------
*/
-static void world_routes_init(void)
+VG_STATIC void world_routes_init(void)
{
- world_routes.current_run_version = 2;
- world_routes.time = RESET_MAX_TIME*2.0;
- world_routes.last_use = 0.0;
+ world.current_run_version = 2;
+ world.time = RESET_MAX_TIME*2.0;
+ world.last_use = 0.0;
shader_route_register();
shader_routeui_register();
-}
-static void world_routes_free(void*_)
-{
- vg_free( world_routes.nodes );
- vg_free( world_routes.routes );
- vg_free( world_routes.gates );
+ vg_acquire_thread_sync();
+ {
+ /* UI buffers */
+ for( int i=0; i<vg_list_size(world.ui_bars); i++ )
+ {
+ /* OpenGL strips */
+ struct route_ui_bar *pui = &world.ui_bars[i];
+
+ glGenVertexArrays( 1, &pui->vao );
+ glGenBuffers( 1, &pui->vbo );
+ glGenBuffers( 1, &pui->ebo );
+ glBindVertexArray( pui->vao );
+
+ size_t stride = sizeof(v2f);
+
+ glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
+ glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride,
+ NULL, GL_DYNAMIC_DRAW );
+
+ glBindVertexArray( pui->vao );
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pui->ebo );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER,
+ k_route_ui_max_indices*sizeof(u16), NULL,
+ GL_DYNAMIC_DRAW );
+
+ glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 );
+ glEnableVertexAttribArray( 0 );
+ VG_CHECK_GL_ERR();
+ }
+ }
+ vg_release_thread_sync();
}
-static void world_routes_update(void)
+VG_STATIC void world_routes_update(void)
{
- world_routes.time += vg.time_delta;
+ world.time += vg.time_delta;
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
route->factive = vg_lerpf( route->factive, route->active,
0.6f*vg.time_delta );
if( route->active )
{
- world_routes_ui_updatetime(i, world_routes.time - route->latest_pass );
+ world_routes_ui_updatetime(i, world.time - route->latest_pass );
}
}
}
-static void bind_terrain_textures(void);
-static void render_world_routes( m4x4f projection, v3f camera )
+VG_STATIC void bind_terrain_textures(void);
+VG_STATIC void render_world_routes( m4x4f projection, v3f camera )
{
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
shader_route_uMdl( identity_matrix );
shader_route_uCamera( camera );
- scene_bind( &world_routes.scene_lines );
+ mesh_bind( &world.mesh_route_lines );
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
v4f colour;
v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour );
}
}
-static void render_world_routes_ui(void)
+VG_STATIC void render_world_routes_ui(void)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
float active_offset = 0.0f;
- for( int i=0; i<world_routes.route_count; i++ )
+ for( int i=0; i<world.route_count; i++ )
{
- struct route *route = &world_routes.routes[i];
+ struct route *route = &world.routes[i];
world_routes_ui_draw( i, route->colour, active_offset );
active_offset += route->factive;
}
return (float)value;
}
-static void sfd_encode( struct sfd_instance *display, u32 row, const char *str )
+VG_STATIC void sfd_encode( u32 row, const char *str )
{
int end=0;
- u32 row_h = display->h-1-row;
+ u32 row_h = world.sfd.h -1 -row;
- for( int i=0; i<display->w; i++ )
+ for( int i=0; i<world.sfd.w; i++ )
{
if( end )
{
- display->buffer[display->w*row_h + i] = 0.0f;
+ world.sfd.buffer[world.sfd.w*row_h + i] = 0.0f;
}
else
{
if( !str[i] )
end = 1;
- display->buffer[display->w*row_h + i] = sfd_encode_glyph( str[i] );
+ world.sfd.buffer[world.sfd.w*row_h + i] = sfd_encode_glyph( str[i] );
}
}
}
-static void sfd_new( struct sfd_instance *display, u32 w, u32 h )
+VG_STATIC void sfd_init( u32 w, u32 h )
{
- display->w = w;
- display->h = h;
- display->buffer = vg_alloc( w*h*sizeof(float)*2 );
-
- for( int i=0; i<w*h*2; i++ )
- display->buffer[i] = 0.0f;
}
-static void sfd_update( struct sfd_instance *display )
+VG_STATIC void sfd_update(void)
{
- for( int i=0; i<display->w*display->h; i++ )
+ for( int i=0; i<world.sfd.w*world.sfd.h; i++ )
{
- float *target = &display->buffer[i],
- *cur = target+display->w*display->h;
+ float *target = &world.sfd.buffer[i*2+0],
+ *cur = &world.sfd.buffer[i*2+1];
float const rate = vg.time_delta * 15.2313131414f;
float d1 = *target-*cur;
}
}
-static void sfd_render( struct sfd_instance *display,
- m4x4f projection, v3f camera, m4x3f transform )
+VG_STATIC void sfd_render( m4x4f projection, v3f camera, m4x3f transform )
{
- struct subworld_sfd *sfd = &world.sfd;
- scene_bind( &sfd->mesh );
+ mesh_bind( &world.sfd.mesh_display );
shader_scoretext_use();
shader_scoretext_uTexGarbage(0);
shader_scoretext_uMdl( transform );
shader_scoretext_uCamera( camera );
- for( int y=0;y<display->h; y++ )
+ for( int y=0;y<world.sfd.h; y++ )
{
- for( int x=0; x<display->w; x++ )
+ for( int x=0; x<world.sfd.w; x++ )
{
- float value = display->buffer[display->h*display->w+y*display->w+x];
+ float value = world.sfd.buffer[(y*world.sfd.w+x)*2+1];
shader_scoretext_uInfo( (v3f){ x,y, value } );
- scene_draw( &sfd->mesh );
+ mesh_draw( &world.sfd.mesh_display );
}
}
shader_vblend_uMdl( transform );
shader_vblend_uCamera( camera );
- mesh_bind( &sfd->temp );
- mesh_draw( &sfd->temp );
+ mesh_bind( &world.sfd.mesh_base );
+ mesh_draw( &world.sfd.mesh_base );
}
-static int world_sfd_test( int argc, const char *argv[] )
+VG_STATIC int world_sfd_test( int argc, const char *argv[] )
{
- struct subworld_sfd *sfd = &world.sfd;
-
if( argc == 2 )
{
- int row = vg_min(vg_max(atoi(argv[0]),0),sfd->tester.h);
- sfd_encode( &sfd->tester, row, argv[1] );
+ int row = vg_min( vg_max(atoi(argv[0]),0), world.sfd.h);
+ sfd_encode( row, argv[1] );
}
return 0;
}
-static void world_sfd_init(void)
+VG_STATIC void world_sfd_init(void)
{
vg_info( "world_sfd_init\n" );
shader_scoretext_register();
- struct subworld_sfd *sfd = &world.sfd;
-
vg_function_push( (struct vg_cmd){
.name = "sfd",
.function = world_sfd_test
});
- mdl_header *mboard = mdl_load( "models/rs_scoretext.mdl" );
- scene_init( &sfd->mesh );
+ vg_linear_clear( vg_mem.scratch );
+ mdl_context *mboard =
+ mdl_load_full( vg_mem.scratch, "models/rs_scoretext.mdl" );
+
+ scene *sc = scene_init( vg_mem.scratch, 3000, 8000 );
mdl_node *pn_backer = mdl_node_from_name( mboard, "backer" );
- mdl_submesh *backer = mdl_submesh_from_id( mboard, pn_backer->submesh_start);
+ mdl_submesh *backer = &mboard->submesh_buffer[ pn_backer->submesh_start ];
mdl_node *pn_card = mdl_node_from_name( mboard, "score_card" );
- mdl_submesh *card = mdl_submesh_from_id( mboard, pn_card->submesh_start );
+ mdl_submesh *card = &mboard->submesh_buffer[ pn_card->submesh_start ];
m4x3f identity;
m4x3_identity( identity );
for( int i=4;i<6;i++ )
{
- u32 vert_start = sfd->mesh.vertex_count;
- scene_add_submesh( &sfd->mesh, mboard, card, identity );
+ u32 vert_start = sc->vertex_count;
+ scene_add_submesh( sc, mboard, card, identity );
for( int j=0; j<card->vertex_count; j++ )
{
- mdl_vert *vert = &sfd->mesh.verts[ vert_start+j ];
+ mdl_vert *vert = &sc->arrvertices[ vert_start+j ];
float const k_glyph_uvw = 1.0f/64.0f;
vert->uv[0] -= k_glyph_uvw * (float)(i-4);
vg_acquire_thread_sync();
{
- vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 );
+ scene_upload( sc, &world.sfd.mesh_display );
+ mdl_unpack_submesh( mboard, &world.sfd.mesh_base, backer );
- scene_upload( &sfd->mesh );
- mdl_unpack_submesh( mboard, &sfd->temp, backer );
+ vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 );
}
vg_release_thread_sync();
- scene_free_offline_buffers( &sfd->mesh );
- sfd_new( &sfd->tester, 27, 13 );
- vg_free( mboard );
-}
+ int w = 27,
+ h = 13;
+ world.sfd.w = w;
+ world.sfd.h = h;
+ world.sfd.buffer = vg_linear_alloc( vg_mem.rtmemory, 2*w*h*sizeof(float) );
-static void world_sfd_free(void *_)
-{
- mesh_free( &world.sfd.mesh.mesh );
- vg_tex2d_free( (vg_tex2d *[]){ &tex_scoretext }, 1 );
+ for( int i=0; i<w*h*2; i++ )
+ world.sfd.buffer[i] = 0.0f;
}
#endif /* SFD_H */
vg_tex2d tex_water_surf = { .path = "textures/water_surf.qoi" };
-static struct
-{
- struct framebuffer fbreflect, fbdepth;
- glmesh mdl;
-
- boxf depthbounds;
- int depth_computed;
-
- float height;
- int enabled;
- v4f plane;
-}
-wrender =
-{
- .fbreflect = { .format = GL_RGB, .div = 3 },
- .fbdepth = { .format = GL_RGBA, .div = 4 }
-};
-
-static void world_water_init(void)
+VG_STATIC void world_water_init(void)
{
vg_info( "world_water_init\n" );
shader_water_register();
-
+
vg_acquire_thread_sync();
{
- fb_init( &wrender.fbreflect );
- fb_init( &wrender.fbdepth );
+ world.water.fbreflect.format = GL_RGB;
+ world.water.fbreflect.div = 3;
+ world.water.fbdepth.format = GL_RGBA;
+ world.water.fbdepth.div = 4;
+
+ fb_init( &world.water.fbreflect );
+ fb_init( &world.water.fbdepth );
vg_tex2d_init( (vg_tex2d *[]){&tex_water_surf}, 1 );
- vg_success( "done\n" );
}
vg_release_thread_sync();
-}
-static void world_water_free(void *_)
-{
- vg_tex2d_free( (vg_tex2d *[]){&tex_water_surf}, 1 );
- fb_free( &wrender.fbreflect );
- fb_free( &wrender.fbdepth );
+ vg_success( "done\n" );
}
-static void water_fb_resize(void)
+VG_STATIC void water_fb_resize(void)
{
- if( !wrender.enabled )
+ if( !world.water.enabled )
return;
- fb_resize( &wrender.fbreflect );
- fb_resize( &wrender.fbdepth );
+ fb_resize( &world.water.fbreflect );
+ fb_resize( &world.water.fbdepth );
}
-static void water_set_surface( glmesh *surf, float height )
+VG_STATIC void water_set_surface( float height )
{
- wrender.mdl = *surf;
- wrender.height = height;
- wrender.enabled = 1;
-
- v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, wrender.plane );
+ world.water.height = height;
+ v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, world.water.plane );
}
-static void render_water_texture( m4x3f camera )
+VG_STATIC void render_water_texture( m4x3f camera )
{
- if( !wrender.enabled )
+ if( !world.water.enabled )
return;
/* Draw reflection buffa */
- fb_use( &wrender.fbreflect );
+ fb_use( &world.water.fbreflect );
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
m4x3f new_cam, inverse;
v3_copy( camera[3], new_cam[3] );
- new_cam[3][1] -= 2.0f * (camera[3][1] - wrender.height);
+ new_cam[3][1] -= 2.0f * (camera[3][1] - world.water.height);
m3x3f flip;
m3x3_identity( flip );
m4x3_invert_affine( new_cam, inverse );
m4x3_expand( inverse, view );
- v4f clippa = { 0.0f, 1.0f, 0.0f, wrender.height-0.1f };
+ v4f clippa = { 0.0f, 1.0f, 0.0f, world.water.height-0.1f };
m4x3_mulp( inverse, clippa, clippa );
clippa[3] *= -1.0f;
/* Draw beneath texture */
- fb_use( &wrender.fbdepth );
+ fb_use( &world.water.fbdepth );
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
m4x3_invert_affine( camera, inverse );
m4x3_expand( inverse, view );
- float bias = -(camera[3][1]-wrender.height)*0.1f;
- v4f clippb = { 0.0f, -1.0f, 0.0f, -(wrender.height) + bias };
+ float bias = -(camera[3][1]-world.water.height)*0.1f;
+ v4f clippb = { 0.0f, -1.0f, 0.0f, -(world.water.height) + bias };
m4x3_mulp( inverse, clippb, clippb );
clippb[3] *= -1.0f;
glViewport( 0, 0, vg.window_x, vg.window_y );
}
-static void render_water_surface( m4x4f pv, m4x3f camera )
+VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera )
{
- if( !wrender.enabled )
+ if( !world.water.enabled )
return;
/* Draw surface */
shader_water_use();
- fb_bindtex( &wrender.fbreflect, 0 );
+ fb_bindtex( &world.water.fbreflect, 0 );
shader_water_uTexMain( 0 );
vg_tex2d_bind( &tex_water_surf, 1 );
shader_link_standard_ub( _shader_water.id, 2 );
- fb_bindtex( &wrender.fbdepth, 3 );
+ fb_bindtex( &world.water.fbdepth, 3 );
shader_water_uTexBack( 3 );
- shader_water_uTime( world_routes.time );
+ shader_water_uTime( world.time );
shader_water_uCamera( camera[3] );
- shader_water_uSurfaceY( wrender.height );
+ shader_water_uSurfaceY( world.water.height );
shader_water_uPv( pv );
m4x3f full;
m4x3_identity( full );
- full[3][1] = wrender.height;
+ full[3][1] = world.water.height;
shader_water_uMdl( full );
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
- mesh_bind( &wrender.mdl );
- mesh_draw( &wrender.mdl );
+ mesh_bind( &world.mesh_water );
+ mesh_draw( &world.mesh_water );
glDisable(GL_BLEND);
}