+/*
+ * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ */
+
#ifndef WORLD_GEN_H
#define WORLD_GEN_H
#include "world.h"
+/* load world TODO: Put back vg back in loading state while this happens */
+VG_STATIC void world_load(void);
+
-static void world_add_all_if_material( m4x3f transform, scene *pscene,
- mdl_header *mdl, u32 id )
+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);
}
}
}
- 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( "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 )
- {
- glmesh surf;
- mdl_unpack_submesh( mworld, &surf, sm );
- world_water_init();
- water_set_surface( &surf, pnode->co[1] );
- }
+ 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 );
- if( !cached )
+ 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;
+
+ 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 =
+ buffer_reserve( world.achievement_zones,
+ world.achievement_zones_count,
+ &world.achievement_zones_cap, 1,
+ sizeof(struct achievement_zone) );
+
+ struct achievement_zone *zone = &world.achievement_zones[
+ world.achievement_zones_count ++ ];
+
+
+ struct classtype_achievement_box *box = mdl_get_entdata(mworld,pnode);
- world.instance_cache = buffer_fix( world.instance_cache,
- world.instance_cache_count,
- &world.instance_cache_cap,
- sizeof( struct instance_cache ) );
+ mdl_node_transform( pnode, zone->transform );
+ m4x3_invert_full( zone->transform, zone->inv_transform );
+ vg_strncpy( mdl_pstr(mworld, box->pstr_name), zone->name, 31 );
+ zone->name[31] = 0x00;
+ zone->triggered = 0;
+
+ if( box->trigger )
+ zone->ptarget_delegated = mdl_node_from_id( mworld, box->trigger );
+ else
+ zone->ptarget_delegated = NULL;
+ }
+#endif
+ }
#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)];
+ /* fixup links */
+ for( int i=0; i<world.achievement_zones_count; i ++ )
+ {
+ struct achievement_zone *ach = &world.achievement_zones[ i ];
+ if( ach->ptarget_delegated )
+ {
+ u32 id = ach->ptarget_delegated->sub_uid;
+ ach->ptarget = &world.audio_things[ id ];
+ }
+ else
+ ach->ptarget = NULL;
+ }
#endif
+}
+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 instance_cache *inst = &world.instance_cache[i];
+
+ const char *filename = mdl_pstr( world.meta, inst->pstr_file );
+ inst->mdl = mdl_load_full( vg_mem.scratch, filename );
+ }
+}
+
+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 );
- scene_upload( &world.geo );
- scene_bh_create( &world.geo );
+ vg_acquire_thread_sync();
+ {
+ scene_upload( world.scene_geo, &world.mesh_geo );
+ }
+ vg_release_thread_sync();
+
+ /* 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 );
+ 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 );
- /* Foliage /nocollide layer.
- * TODO: Probably should have material traits for this
+ /*
+ * 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 );
- scene_upload( &world.foliage );
- world_routes_loadfrom( mworld );
- for( int i=0; i<world.instance_cache_count; i++ )
- free( world.instance_cache[i].mdl );
+ /* upload and free that */
+ vg_acquire_thread_sync();
+ {
+ scene_upload( world.scene_no_collide, &world.mesh_no_collide );
+ }
+ vg_release_thread_sync();
- free( world.instance_cache );
- free( mworld );
+ vg_linear_del( world.dynamic_vgl, world.scene_no_collide );
+ world.scene_no_collide = NULL;
+}
- /*
- * Rendering the depth map
- */
- m4x4f ortho;
- m4x3f camera;
-
- v3f extent;
- v3_sub( world.geo.bbx[1], world.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],
- rl = 1.0f / (fr-fl),
- tb = 1.0f / (ft-fb);
-
- m4x4_zero( ortho );
- ortho[0][0] = 2.0f * rl;
- ortho[2][1] = 2.0f * tb;
- ortho[3][0] = (fr + fl) * -rl;
- ortho[3][1] = (ft + fb) * -tb;
- ortho[3][3] = 1.0f;
- m4x3_identity( camera );
-
- glViewport( 0, 0, 1024, 1024 );
- glDisable(GL_DEPTH_TEST);
- glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
- shader_fscolour_use();
- shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
- render_fsquad();
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- glBlendEquation(GL_MAX);
- render_world_depth( ortho, camera );
- glDisable(GL_BLEND);
- glEnable(GL_DEPTH_TEST);
+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 );
- /*
- * 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 );
-
- winfo->g_water_fog = 0.04f;
- render_update_lighting_ub();
-
+ if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
+ audio_player_set_position( &thingy->player, thingy->pos );
- world.mr_ball.type = k_rb_shape_sphere;
- world.mr_ball.inf.sphere.radius = 2.0f;
- v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co );
+ if( thingy->flags & AUDIO_FLAG_AUTO_START )
+ audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
+ }
+ audio_unlock();
- q_identity(world.mr_ball.q);
- rb_init( &world.mr_ball );
+ vg_acquire_thread_sync();
+ {
+ /*
+ * Rendering the depth map
+ */
+ m4x4f ortho;
+ m4x3f camera;
+
+ v3f extent;
+ v3_sub( world.scene_geo->bbx[1], world.scene_geo->bbx[0], extent );
+
+ 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);
+
+ m4x4_zero( ortho );
+ ortho[0][0] = 2.0f * rl;
+ ortho[2][1] = 2.0f * tb;
+ ortho[3][0] = (fr + fl) * -rl;
+ ortho[3][1] = (ft + fb) * -tb;
+ ortho[3][3] = 1.0f;
+ m4x3_identity( camera );
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
+ glViewport( 0, 0, 1024, 1024 );
+ shader_fscolour_use();
+ shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
+ render_fsquad();
+
+ /* todo: hmm?? */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ glBlendEquation(GL_MAX);
+ render_world_depth( ortho, camera );
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+
+ /*
+ * TODO: World settings entity
+ */
+ struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
+
+ 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();
/*
* 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 );
+
+ world.time = 0.0;
+ world.rewind_from = 0.0;
+ world.rewind_to = 0.0;
+ world.last_use = 0.0;
+ world.active_gate = 0;
+ world.current_run_version = 2;
+ world.active_route_board = 0;
+ v3_zero( world.render_gate_pos );
+
+ for( int i=0; i<vg_list_size(world.ui_bars); i++ )
+ {
+ struct route_ui_bar *uib = &world.ui_bars[i];
+ uib->segment_start = 0;
+ uib->segment_count = 0;
+ uib->fade_start = 0;
+ uib->fade_count = 0;
+ uib->fade_timer_start = 0.0;
+ uib->xpos = 0.0f;
+ }
+
+ /* delete the entire block of memory */
+ memset( world.dynamic_vgl, 0xff, 72*1024*1024 );
+
+ vg_linear_clear( world.dynamic_vgl );
+
+ for( u32 i=0; i<72*1024*1024; i++ )
+ ((u8 *)world.dynamic_vgl)[i] = 0xff^i;
+
+ /* 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(void)
+{
+ world_unload();
+
+ world.meta = mdl_load_full( world.dynamic_vgl, world.world_name );
+ vg_info( "Loading world: %s\n", world.world_name );
+
+ /* 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 */