2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 /* load world TODO: Put back vg back in loading state while this happens */
11 VG_STATIC
void world_load(void);
14 VG_STATIC
void world_add_all_if_material( m4x3f transform
, scene
*pscene
,
15 mdl_context
*mdl
, u32 id
)
17 for( int i
=0; i
<mdl
->info
.node_count
; i
++ )
19 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
21 for( int j
=0; j
<pnode
->submesh_count
; j
++ )
23 mdl_submesh
*sm
= mdl_node_submesh( mdl
, pnode
, j
);
24 if( sm
->material_id
== id
)
27 mdl_node_transform( pnode
, transform2
);
28 m4x3_mul( transform
, transform2
, transform2
);
30 scene_add_submesh( pscene
, mdl
, sm
, transform2
);
35 if( pnode
->classtype
== k_classtype_instance
)
39 u32 instance_id
= pnode
->sub_uid
-1;
40 struct instance_cache
*cache
= &world
.instance_cache
[instance_id
];
41 mdl_context
*mdl2
= cache
->mdl
;
44 mdl_node_transform( pnode
, transform2
);
45 m4x3_mul( transform
, transform2
, transform2
);
47 world_add_all_if_material( transform2
, pscene
, mdl2
, id
);
54 /* Sprinkle foliage models over the map on terrain material */
55 VG_STATIC
void world_apply_procedural_foliage(void)
57 vg_linear_clear( vg_mem
.scratch
);
59 mdl_context
*mfoliage
=
60 mdl_load_full( vg_mem
.scratch
, "models/rs_foliage.mdl");
63 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], volume
);
67 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
68 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
70 for( int i
=0;i
<100000;i
++ )
73 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
75 v3_add( pos
, world
.scene_geo
->bbx
[0], pos
);
80 if( ray_world( pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
82 if( (hit
.normal
[1] > 0.8f
) && ray_hit_is_terrain(&hit
) &&
83 (hit
.pos
[1] > 0.0f
+10.0f
) )
85 v4f qsurface
, qrandom
;
88 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
.normal
, axis
);
90 float angle
= v3_dot(hit
.normal
,(v3f
){0.0f
,1.0f
,0.0f
});
91 q_axis_angle( qsurface
, axis
, angle
);
92 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf()*VG_TAUf
);
93 q_mul( qsurface
, qrandom
, qsurface
);
94 q_m3x3( qsurface
, transform
);
96 v3_copy( hit
.pos
, transform
[3] );
97 scene_add_submesh( world
.scene_no_collide
, mfoliage
,
104 VG_STATIC
void world_ents_allocate(void)
106 vg_info( "Allocating entities\n" );
108 /* count entites to allocate buffers for them.
109 * maybe in the future we just store these numbers in the model file...
111 * TODO: use this in world_routes too */
124 (void*)&world
.spawns
,
125 sizeof(struct respawn_point
)
129 (void*)&world
.audio_things
,
130 sizeof(struct world_audio_thing
)
134 (void*)&world
.triggers
,
135 sizeof(struct trigger_zone
)
139 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
140 entity_counts
[i
].count
= 0;
142 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
144 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
146 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
148 if( pnode
->classtype
== entity_counts
[j
].ct
)
150 entity_counts
[j
].count
++;
156 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
158 struct countable
*counter
= &entity_counts
[i
];
160 u32 bufsize
= counter
->item_size
*counter
->count
;
161 *counter
->to_allocate
= vg_linear_alloc( world
.dynamic_vgl
, bufsize
);
165 VG_STATIC
void world_pct_spawn( mdl_node
*pnode
)
167 struct respawn_point
*rp
= &world
.spawns
[ world
.spawn_count
++ ];
169 v3_copy( pnode
->co
, rp
->co
);
170 v4_copy( pnode
->q
, rp
->q
);
171 rp
->name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
174 VG_STATIC
void world_pct_water( mdl_node
*pnode
)
176 if( world
.water
.enabled
)
178 vg_warn( "Multiple water surfaces in level! ('%s')\n",
179 mdl_pstr( world
.meta
, pnode
->pstr_name
));
183 mdl_submesh
*sm
= mdl_node_submesh( world
.meta
, pnode
, 0 );
187 vg_acquire_thread_sync();
189 mdl_unpack_submesh( world
.meta
, &world
.mesh_water
, sm
);
190 world
.water
.enabled
= 1;
191 water_set_surface( pnode
->co
[1] );
193 vg_release_thread_sync();
197 vg_warn( "Water entity has no submeshes!\n" );
201 VG_STATIC
void world_pct_instance( mdl_node
*pnode
)
203 struct classtype_instance
*inst
= mdl_get_entdata( world
.meta
, pnode
);
207 for( int i
=0; i
<world
.instance_cache_count
; i
++ )
209 struct instance_cache
*cache
= &world
.instance_cache
[i
];
210 if( inst
->pstr_file
== cache
->pstr_file
)
213 pnode
->sub_uid
= i
+1;
220 if( world
.instance_cache_count
== vg_list_size(world
.instance_cache
) )
221 vg_fatal_exit_loop( "Instance cache is full!" );
223 struct instance_cache
*cache
=
224 &world
.instance_cache
[world
.instance_cache_count
++ ];
226 cache
->pstr_file
= inst
->pstr_file
;
229 cache
->mdl
= mdl_load( filename
);
233 world
.instance_cache_count
++;
234 pnode
->sub_uid
= world
.instance_cache_count
;
235 mdl_link_materials( mworld
, cache
->mdl
);
236 vg_success( "Cached %s\n", filename
);
240 vg_warn( "Failed to cache %s\n", filename
);
246 VG_STATIC
void world_pct_audio( mdl_node
*pnode
)
248 struct world_audio_thing
*thing
= &world
.audio_things
[
249 world
.audio_things_count
];
251 memset( thing
, 0, sizeof(struct world_audio_thing
) );
252 struct classtype_audio
*aud
= mdl_get_entdata( world
.meta
, pnode
);
254 v3_copy( pnode
->co
, thing
->pos
);
256 if( aud
->flags
& AUDIO_FLAG_SPACIAL_3D
)
257 thing
->volume
= aud
->volume
* pnode
->s
[0];
259 thing
->volume
= aud
->volume
;
261 thing
->flags
= aud
->flags
;
262 thing
->temp_embedded_clip
.path
= mdl_pstr( world
.meta
, aud
->pstr_file
);
263 audio_clip_load( &thing
->temp_embedded_clip
);
264 thing
->player
.name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
265 thing
->player
.enqued
= 0;
267 pnode
->sub_uid
= world
.audio_things_count
;
268 world
.audio_things_count
++;
271 VG_STATIC
void world_entities_process(void)
273 struct entity_instruction
276 void (*process
)( mdl_node
*pnode
);
278 entity_instructions
[] =
280 { k_classtype_spawn
, world_pct_spawn
},
281 { k_classtype_water
, world_pct_water
},
282 { k_classtype_instance
, world_pct_instance
},
283 { k_classtype_audio
, world_pct_audio
},
286 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
288 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
290 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
292 struct entity_instruction
*instr
= &entity_instructions
[j
];
294 if( pnode
->classtype
== instr
->ct
)
296 instr
->process( pnode
);
302 else if( pnode
->classtype
== k_classtype_achievement_box
)
304 world
.achievement_zones
=
305 buffer_reserve( world
.achievement_zones
,
306 world
.achievement_zones_count
,
307 &world
.achievement_zones_cap
, 1,
308 sizeof(struct achievement_zone
) );
310 struct achievement_zone
*zone
= &world
.achievement_zones
[
311 world
.achievement_zones_count
++ ];
314 struct classtype_achievement_box
*box
= mdl_get_entdata(mworld
,pnode
);
316 mdl_node_transform( pnode
, zone
->transform
);
317 m4x3_invert_full( zone
->transform
, zone
->inv_transform
);
318 vg_strncpy( mdl_pstr(mworld
, box
->pstr_name
), zone
->name
, 31 );
319 zone
->name
[31] = 0x00;
323 zone
->ptarget_delegated
= mdl_node_from_id( mworld
, box
->trigger
);
325 zone
->ptarget_delegated
= NULL
;
332 for( int i
=0; i
<world
.achievement_zones_count
; i
++ )
334 struct achievement_zone
*ach
= &world
.achievement_zones
[ i
];
335 if( ach
->ptarget_delegated
)
337 u32 id
= ach
->ptarget_delegated
->sub_uid
;
338 ach
->ptarget
= &world
.audio_things
[ id
];
346 VG_STATIC
void world_load_instance_cache(void)
348 vg_linear_clear( vg_mem
.scratch
);
350 for( int i
=0; i
<world
.instance_cache_count
; i
++ )
352 struct instance_cache
*inst
= &world
.instance_cache
[i
];
354 const char *filename
= mdl_pstr( world
.meta
, inst
->pstr_file
);
355 inst
->mdl
= mdl_load_full( vg_mem
.scratch
, filename
);
359 VG_STATIC
void world_generate(void)
362 * Compile meshes into the world scenes
364 world
.scene_geo
= scene_init( world
.dynamic_vgl
, 500000, 1200000 );
367 * TODO: System to dynamically allocate these
371 mat_vertex_blend
= 0,
377 for( int i
=1; i
<world
.meta
->info
.material_count
; i
++ )
379 mdl_material
*mat
= &world
.meta
->material_buffer
[ i
];
380 const char *mat_name
= mdl_pstr( world
.meta
, mat
->pstr_name
);
382 if( !strcmp( "surf", mat_name
))
384 else if( !strcmp( "surf_oob", mat_name
))
386 else if( !strcmp( "vertex_blend", mat_name
))
387 mat_vertex_blend
= i
;
388 else if( !strcmp( "alphatest", mat_name
))
390 else if( !strcmp( "graffitibox", mat_name
))
392 else if( !strcmp( "terrain", mat_name
) )
397 m4x3_identity( midentity
);
399 world_load_instance_cache();
402 * Generate scene: collidable geometry
403 * ----------------------------------------------------------------
406 vg_info( "Generating collidable geometry\n" );
407 vg_info( "terrain...\n" );
410 world_add_all_if_material( midentity
, world
.scene_geo
,
411 world
.meta
, mat_terrain
);
412 scene_copy_slice( world
.scene_geo
, &world
.sm_terrain
);
415 vg_info( "oob...\n" );
417 world_add_all_if_material( midentity
, world
.scene_geo
,
418 world
.meta
, mat_surf_oob
);
420 vg_warn( "No OOB surface\n" );
421 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_std_oob
);
425 vg_info( "surface...\n" );
427 world_add_all_if_material( midentity
, world
.scene_geo
,
428 world
.meta
, mat_surf
);
429 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_std
);
432 vg_info( "vertex blend...\n" );
433 if( mat_vertex_blend
)
434 world_add_all_if_material( midentity
, world
.scene_geo
,
435 world
.meta
, mat_vertex_blend
);
436 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_vb
);
438 /* compress that bad boy */
439 world
.scene_geo
= scene_fix( world
.dynamic_vgl
, world
.scene_geo
);
441 vg_acquire_thread_sync();
443 scene_upload( world
.scene_geo
, &world
.mesh_geo
);
445 vg_release_thread_sync();
447 /* setup spacial mapping and rigidbody */
448 world
.geo_bh
= scene_bh_create( world
.dynamic_vgl
, world
.scene_geo
);
450 v3_zero( world
.rb_geo
.co
);
451 q_identity( world
.rb_geo
.q
);
453 world
.rb_geo
.type
= k_rb_shape_scene
;
454 world
.rb_geo
.inf
.scene
.bh_scene
= world
.geo_bh
;
455 world
.rb_geo
.is_world
= 1;
456 rb_init( &world
.rb_geo
);
459 * Generate scene: non-collidable geometry
460 * ----------------------------------------------------------------
462 vg_info( "Generating non-collidable geometry\n" );
464 world
.scene_no_collide
= scene_init( world
.dynamic_vgl
, 200000, 500000 );
466 vg_info( "Applying foliage\n" );
467 world_apply_procedural_foliage();
468 scene_copy_slice( world
.scene_no_collide
, &world
.sm_foliage_main
);
470 vg_info( "alphatest...\n" );
471 world_add_all_if_material( midentity
, world
.scene_no_collide
,
472 world
.meta
, mat_alphatest
);
473 scene_copy_slice( world
.scene_no_collide
, &world
.sm_foliage_alphatest
);
475 vg_info( "graffiti...\n" );
476 world_add_all_if_material( midentity
, world
.scene_no_collide
,
477 world
.meta
, mat_graffiti
);
478 scene_copy_slice( world
.scene_no_collide
, &world
.sm_graffiti
);
481 /* upload and free that */
482 vg_acquire_thread_sync();
484 scene_upload( world
.scene_no_collide
, &world
.mesh_no_collide
);
486 vg_release_thread_sync();
488 vg_linear_del( world
.dynamic_vgl
, world
.scene_no_collide
);
489 world
.scene_no_collide
= NULL
;
492 VG_STATIC
void world_post_process(void)
494 /* initialize audio if need be */
496 for( int i
=0; i
<world
.audio_things_count
; i
++ )
498 struct world_audio_thing
*thingy
= &world
.audio_things
[ i
];
500 audio_player_init( &thingy
->player
);
501 audio_player_set_flags( &thingy
->player
, thingy
->flags
);
502 audio_player_set_vol( &thingy
->player
, thingy
->volume
);
503 audio_player_set_pan( &thingy
->player
, 0.0f
);
505 if( thingy
->flags
& AUDIO_FLAG_SPACIAL_3D
)
506 audio_player_set_position( &thingy
->player
, thingy
->pos
);
508 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
509 audio_player_playclip( &thingy
->player
, &thingy
->temp_embedded_clip
);
513 vg_acquire_thread_sync();
516 * Rendering the depth map
522 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], extent
);
524 float fl
= world
.scene_geo
->bbx
[0][0],
525 fr
= world
.scene_geo
->bbx
[1][0],
526 fb
= world
.scene_geo
->bbx
[0][2],
527 ft
= world
.scene_geo
->bbx
[1][2],
532 ortho
[0][0] = 2.0f
* rl
;
533 ortho
[2][1] = 2.0f
* tb
;
534 ortho
[3][0] = (fr
+ fl
) * -rl
;
535 ortho
[3][1] = (ft
+ fb
) * -tb
;
537 m4x3_identity( camera
);
539 glDisable(GL_DEPTH_TEST
);
541 glDisable(GL_CULL_FACE
);
542 glBindFramebuffer( GL_FRAMEBUFFER
, gpipeline
.fb_depthmap
);
543 glViewport( 0, 0, 1024, 1024 );
544 shader_fscolour_use();
545 shader_fscolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
550 glBlendFunc(GL_ONE
, GL_ONE
);
551 glBlendEquation(GL_MAX
);
552 render_world_depth( ortho
, camera
);
554 glEnable(GL_DEPTH_TEST
);
555 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
559 * TODO: World settings entity
561 struct ub_world_lighting
*winfo
= &gpipeline
.ub_world_lighting
;
563 if( world
.water
.enabled
)
564 v4_copy( world
.water
.plane
, winfo
->g_water_plane
);
567 v3f
*bounds
= world
.scene_geo
->bbx
;
569 info_vec
[0] = bounds
[0][0];
570 info_vec
[1] = bounds
[0][2];
571 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
572 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
573 v4_copy( info_vec
, winfo
->g_depth_bounds
);
575 winfo
->g_water_fog
= 0.04f
;
576 render_update_lighting_ub();
579 vg_release_thread_sync();
582 * Setup scene collider
587 VG_STATIC
void world_unload(void)
590 mesh_free( &world
.mesh_geo
);
591 mesh_free( &world
.mesh_no_collide
);
592 mesh_free( &world
.mesh_route_lines
);
593 mesh_free( &world
.mesh_water
);
596 world
.rewind_from
= 0.0;
597 world
.rewind_to
= 0.0;
598 world
.last_use
= 0.0;
599 world
.active_gate
= 0;
600 world
.current_run_version
= 2;
601 world
.active_route_board
= 0;
602 v3_zero( world
.render_gate_pos
);
604 for( int i
=0; i
<vg_list_size(world
.ui_bars
); i
++ )
606 struct route_ui_bar
*uib
= &world
.ui_bars
[i
];
607 uib
->segment_start
= 0;
608 uib
->segment_count
= 0;
611 uib
->fade_timer_start
= 0.0;
615 /* delete the entire block of memory */
616 memset( world
.dynamic_vgl
, 0xff, 72*1024*1024 );
618 vg_linear_clear( world
.dynamic_vgl
);
620 for( u32 i
=0; i
<72*1024*1024; i
++ )
621 ((u8
*)world
.dynamic_vgl
)[i
] = 0xff^i
;
623 /* clean dangling pointers */
626 world
.scene_geo
= NULL
;
627 world
.scene_lines
= NULL
;
628 world
.scene_no_collide
= NULL
;
631 world
.trigger_bh
= NULL
;
632 world
.audio_bh
= NULL
;
635 world
.spawn_count
= 0;
637 world
.audio_things
= NULL
;
638 world
.audio_things_count
= 0;
640 world
.logic_entities
= NULL
;
641 world
.logic_entity_count
= 0;
643 world
.logic_actions
= NULL
;
644 world
.logic_action_count
= 0;
646 world
.triggers
= NULL
;
647 world
.trigger_count
= 0;
650 world
.node_count
= 0;
653 world
.route_count
= 0;
656 world
.gate_count
= 0;
658 world
.collectors
= NULL
;
659 world
.collector_count
= 0;
661 world
.instance_cache_count
= 0;
662 world
.water
.enabled
= 0;
665 VG_STATIC
void world_load(void)
669 world
.meta
= mdl_load_full( world
.dynamic_vgl
, world
.world_name
);
670 vg_info( "Loading world: %s\n", world
.world_name
);
672 /* dynamic allocations */
673 world_ents_allocate();
674 world_routes_allocate();
676 /* meta processing */
677 world_routes_process();
678 world_entities_process();
682 world_routes_generate();
683 world_post_process();
686 #endif /* WORLD_GEN_H */