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
);
36 /* Sprinkle foliage models over the map on terrain material */
37 VG_STATIC
void world_apply_procedural_foliage(void)
39 vg_linear_clear( vg_mem
.scratch
);
41 mdl_context
*mfoliage
=
42 mdl_load_full( vg_mem
.scratch
, "models/rs_foliage.mdl");
45 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], volume
);
49 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
50 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
52 for( int i
=0;i
<100000;i
++ )
55 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
57 v3_add( pos
, world
.scene_geo
->bbx
[0], pos
);
62 if( ray_world( pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
64 if( (hit
.normal
[1] > 0.8f
) && ray_hit_is_terrain(&hit
) &&
65 (hit
.pos
[1] > 0.0f
+10.0f
) )
67 v4f qsurface
, qrandom
;
70 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
.normal
, axis
);
72 float angle
= v3_dot(hit
.normal
,(v3f
){0.0f
,1.0f
,0.0f
});
73 q_axis_angle( qsurface
, axis
, angle
);
74 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf()*VG_TAUf
);
75 q_mul( qsurface
, qrandom
, qsurface
);
76 q_m3x3( qsurface
, transform
);
78 v3_copy( hit
.pos
, transform
[3] );
79 scene_add_submesh( world
.scene_no_collide
, mfoliage
,
86 VG_STATIC
void world_ents_allocate(void)
88 vg_info( "Allocating entities\n" );
90 /* count entites to allocate buffers for them.
91 * maybe in the future we just store these numbers in the model file...
93 * TODO: use this in world_routes too */
106 (void*)&world
.spawns
,
107 sizeof(struct respawn_point
)
111 (void*)&world
.audio_things
,
112 sizeof(struct world_audio_thing
)
116 (void*)&world
.triggers
,
117 sizeof(struct trigger_zone
)
120 k_classtype_logic_relay
,
121 (void*)&world
.logic_relays
,
122 sizeof(struct logic_relay
)
125 k_classtype_logic_achievement
,
126 (void*)&world
.logic_achievements
,
127 sizeof(struct logic_achievement
)
131 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
132 entity_counts
[i
].count
= 0;
134 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
136 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
138 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
140 if( pnode
->classtype
== entity_counts
[j
].ct
)
142 pnode
->sub_uid
= entity_counts
[j
].count
;
143 entity_counts
[j
].count
++;
149 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
151 struct countable
*counter
= &entity_counts
[i
];
153 u32 bufsize
= counter
->item_size
*counter
->count
;
154 *counter
->to_allocate
= vg_linear_alloc( world
.dynamic_vgl
, bufsize
);
158 VG_STATIC
void world_pct_spawn( mdl_node
*pnode
)
160 struct respawn_point
*rp
= &world
.spawns
[ world
.spawn_count
++ ];
162 v3_copy( pnode
->co
, rp
->co
);
163 v4_copy( pnode
->q
, rp
->q
);
164 rp
->name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
167 VG_STATIC
void world_pct_water( mdl_node
*pnode
)
169 if( world
.water
.enabled
)
171 vg_warn( "Multiple water surfaces in level! ('%s')\n",
172 mdl_pstr( world
.meta
, pnode
->pstr_name
));
176 mdl_submesh
*sm
= mdl_node_submesh( world
.meta
, pnode
, 0 );
180 vg_acquire_thread_sync();
182 mdl_unpack_submesh( world
.meta
, &world
.mesh_water
, sm
);
183 world
.water
.enabled
= 1;
184 water_set_surface( pnode
->co
[1] );
186 vg_release_thread_sync();
190 vg_warn( "Water entity has no submeshes!\n" );
194 VG_STATIC
void world_pct_audio( mdl_node
*pnode
)
196 struct world_audio_thing
*thing
= &world
.audio_things
[
197 world
.audio_things_count
];
199 memset( thing
, 0, sizeof(struct world_audio_thing
) );
200 struct classtype_audio
*aud
= mdl_get_entdata( world
.meta
, pnode
);
202 v3_copy( pnode
->co
, thing
->pos
);
204 if( aud
->flags
& AUDIO_FLAG_SPACIAL_3D
)
205 thing
->volume
= aud
->volume
* pnode
->s
[0];
207 thing
->volume
= aud
->volume
;
209 thing
->flags
= aud
->flags
;
210 thing
->temp_embedded_clip
.path
= mdl_pstr( world
.meta
, aud
->pstr_file
);
211 thing
->temp_embedded_clip
.source_mode
= k_audio_source_mono
;
213 audio_clip_load( &thing
->temp_embedded_clip
, world
.audio_vgl
);
214 thing
->player
.name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
215 thing
->player
.enqued
= 0;
217 pnode
->sub_uid
= world
.audio_things_count
;
218 world
.audio_things_count
++;
222 VG_STATIC
void world_pct_trigger( mdl_node
*pnode
)
224 struct trigger_zone
*trigger
= &world
.triggers
[ world
.trigger_count
];
225 struct classtype_trigger
*inf
= mdl_get_entdata( world
.meta
, pnode
);
229 mdl_node
*target_node
= mdl_node_from_id( world
.meta
, inf
->target
);
231 trigger
->target
.sub_id
= target_node
->sub_uid
;
232 trigger
->target
.classtype
= target_node
->classtype
;
236 vg_warn( "Trigger with no target...\n" );
240 mdl_node_transform( pnode
, trigger
->transform
);
241 m4x3_invert_full( trigger
->transform
, trigger
->inv_transform
);
243 world
.trigger_count
++;
247 VG_STATIC
void world_pct_relay( mdl_node
*pnode
)
249 struct logic_relay
*relay
= &world
.logic_relays
[ world
.relay_count
];
250 struct classtype_logic_relay
*inf
= mdl_get_entdata( world
.meta
, pnode
);
252 relay
->target_count
= 0;
254 for( int i
=0; i
<vg_list_size(relay
->targets
); i
++ )
256 if( inf
->targets
[i
] )
258 struct relay_target
*target
= &relay
->targets
[relay
->target_count
++];
259 mdl_node
*other
= mdl_node_from_id( world
.meta
, inf
->targets
[i
] );
261 target
->classtype
= other
->classtype
;
262 target
->sub_id
= other
->sub_uid
;
266 v3_copy( pnode
->co
, relay
->pos
);
267 world
.relay_count
++;
271 VG_STATIC
void world_pct_achievement( mdl_node
*pnode
)
273 struct logic_achievement
*ach
=
274 &world
.logic_achievements
[ world
.achievement_count
];
275 struct classtype_logic_achievement
*inf
=
276 mdl_get_entdata( world
.meta
, pnode
);
278 v3_copy( pnode
->co
, ach
->pos
);
279 ach
->achievement_id
= mdl_pstr( world
.meta
, inf
->pstr_name
);
282 world
.achievement_count
++;
286 VG_STATIC
void world_entities_process(void)
288 struct entity_instruction
291 void (*process
)( mdl_node
*pnode
);
293 entity_instructions
[] =
295 { k_classtype_spawn
, world_pct_spawn
},
296 { k_classtype_water
, world_pct_water
},
297 { k_classtype_audio
, world_pct_audio
},
298 { k_classtype_trigger
, world_pct_trigger
},
299 { k_classtype_logic_relay
, world_pct_relay
},
300 { k_classtype_logic_achievement
, world_pct_achievement
}
303 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
305 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
307 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
309 struct entity_instruction
*instr
= &entity_instructions
[j
];
311 if( pnode
->classtype
== instr
->ct
)
313 instr
->process( pnode
);
320 VG_STATIC
void world_generate(void)
323 * Compile meshes into the world scenes
325 world
.scene_geo
= scene_init( world
.dynamic_vgl
, 350000, 1200000 );
328 * TODO: System to dynamically allocate these
332 mat_vertex_blend
= 0,
338 for( int i
=1; i
<world
.meta
->info
.material_count
; i
++ )
340 mdl_material
*mat
= &world
.meta
->material_buffer
[ i
];
341 const char *mat_name
= mdl_pstr( world
.meta
, mat
->pstr_name
);
343 if( !strcmp( "surf", mat_name
))
345 else if( !strcmp( "surf_oob", mat_name
))
347 else if( !strcmp( "vertex_blend", mat_name
))
348 mat_vertex_blend
= i
;
349 else if( !strcmp( "alphatest", mat_name
))
351 else if( !strcmp( "graffitibox", mat_name
))
353 else if( !strcmp( "terrain", mat_name
) )
358 m4x3_identity( midentity
);
361 * Generate scene: collidable geometry
362 * ----------------------------------------------------------------
365 vg_info( "Generating collidable geometry\n" );
366 vg_info( "terrain...\n" );
369 world_add_all_if_material( midentity
, world
.scene_geo
,
370 world
.meta
, mat_terrain
);
371 scene_copy_slice( world
.scene_geo
, &world
.sm_terrain
);
374 vg_info( "oob...\n" );
376 world_add_all_if_material( midentity
, world
.scene_geo
,
377 world
.meta
, mat_surf_oob
);
379 vg_warn( "No OOB surface\n" );
380 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_std_oob
);
384 vg_info( "surface...\n" );
386 world_add_all_if_material( midentity
, world
.scene_geo
,
387 world
.meta
, mat_surf
);
388 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_std
);
391 vg_info( "vertex blend...\n" );
392 if( mat_vertex_blend
)
393 world_add_all_if_material( midentity
, world
.scene_geo
,
394 world
.meta
, mat_vertex_blend
);
395 scene_copy_slice( world
.scene_geo
, &world
.sm_geo_vb
);
397 /* compress that bad boy */
398 world
.scene_geo
= scene_fix( world
.dynamic_vgl
, world
.scene_geo
);
400 vg_acquire_thread_sync();
402 scene_upload( world
.scene_geo
, &world
.mesh_geo
);
404 vg_release_thread_sync();
406 /* setup spacial mapping and rigidbody */
407 world
.geo_bh
= scene_bh_create( world
.dynamic_vgl
, world
.scene_geo
);
409 v3_zero( world
.rb_geo
.co
);
410 q_identity( world
.rb_geo
.q
);
412 world
.rb_geo
.type
= k_rb_shape_scene
;
413 world
.rb_geo
.inf
.scene
.bh_scene
= world
.geo_bh
;
414 world
.rb_geo
.is_world
= 1;
415 rb_init( &world
.rb_geo
);
418 * Generate scene: non-collidable geometry
419 * ----------------------------------------------------------------
421 vg_info( "Generating non-collidable geometry\n" );
423 world
.scene_no_collide
= scene_init( world
.dynamic_vgl
, 200000, 500000 );
425 vg_info( "Applying foliage\n" );
427 world_apply_procedural_foliage();
428 scene_copy_slice( world
.scene_no_collide
, &world
.sm_foliage_main
);
430 vg_info( "alphatest...\n" );
431 world_add_all_if_material( midentity
, world
.scene_no_collide
,
432 world
.meta
, mat_alphatest
);
433 scene_copy_slice( world
.scene_no_collide
, &world
.sm_foliage_alphatest
);
435 vg_info( "graffiti...\n" );
436 world_add_all_if_material( midentity
, world
.scene_no_collide
,
437 world
.meta
, mat_graffiti
);
438 scene_copy_slice( world
.scene_no_collide
, &world
.sm_graffiti
);
441 /* upload and free that */
442 vg_acquire_thread_sync();
444 scene_upload( world
.scene_no_collide
, &world
.mesh_no_collide
);
446 vg_release_thread_sync();
448 vg_linear_del( world
.dynamic_vgl
, world
.scene_no_collide
);
449 world
.scene_no_collide
= NULL
;
452 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
453 VG_STATIC
void world_post_process(void)
455 /* initialize audio if need be */
457 for( int i
=0; i
<world
.audio_things_count
; i
++ )
459 struct world_audio_thing
*thingy
= &world
.audio_things
[ i
];
461 audio_player_init( &thingy
->player
);
462 audio_player_set_flags( &thingy
->player
, thingy
->flags
);
463 audio_player_set_vol( &thingy
->player
, thingy
->volume
);
464 audio_player_set_pan( &thingy
->player
, 0.0f
);
466 if( thingy
->flags
& AUDIO_FLAG_SPACIAL_3D
)
467 audio_player_set_position( &thingy
->player
, thingy
->pos
);
469 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
470 audio_player_playclip( &thingy
->player
, &thingy
->temp_embedded_clip
);
474 vg_acquire_thread_sync();
477 * Rendering the depth map
483 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], extent
);
485 float fl
= world
.scene_geo
->bbx
[0][0],
486 fr
= world
.scene_geo
->bbx
[1][0],
487 fb
= world
.scene_geo
->bbx
[0][2],
488 ft
= world
.scene_geo
->bbx
[1][2],
493 ortho
[0][0] = 2.0f
* rl
;
494 ortho
[2][1] = 2.0f
* tb
;
495 ortho
[3][0] = (fr
+ fl
) * -rl
;
496 ortho
[3][1] = (ft
+ fb
) * -tb
;
498 m4x3_identity( camera
);
500 glDisable(GL_DEPTH_TEST
);
502 glDisable(GL_CULL_FACE
);
503 glBindFramebuffer( GL_FRAMEBUFFER
, gpipeline
.fb_depthmap
);
504 glViewport( 0, 0, 1024, 1024 );
505 shader_fscolour_use();
506 shader_fscolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
511 glBlendFunc(GL_ONE
, GL_ONE
);
512 glBlendEquation(GL_MAX
);
513 render_world_depth( ortho
, camera
);
515 glEnable(GL_DEPTH_TEST
);
516 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
520 * TODO: World settings entity
522 struct ub_world_lighting
*winfo
= &gpipeline
.ub_world_lighting
;
524 if( world
.water
.enabled
)
525 v4_copy( world
.water
.plane
, winfo
->g_water_plane
);
528 v3f
*bounds
= world
.scene_geo
->bbx
;
530 info_vec
[0] = bounds
[0][0];
531 info_vec
[1] = bounds
[0][2];
532 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
533 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
534 v4_copy( info_vec
, winfo
->g_depth_bounds
);
536 winfo
->g_water_fog
= 0.04f
;
537 render_update_lighting_ub();
540 vg_release_thread_sync();
543 * Setup scene collider
546 reset_player( 1, (const char *[]){"start"} );
550 VG_STATIC
void world_unload(void)
553 mesh_free( &world
.mesh_geo
);
554 mesh_free( &world
.mesh_no_collide
);
555 mesh_free( &world
.mesh_route_lines
);
556 mesh_free( &world
.mesh_water
);
559 world
.rewind_from
= 0.0;
560 world
.rewind_to
= 0.0;
561 world
.last_use
= 0.0;
562 world
.active_gate
= 0;
563 world
.current_run_version
= 2;
564 world
.active_route_board
= 0;
565 v3_zero( world
.render_gate_pos
);
567 for( int i
=0; i
<vg_list_size(world
.ui_bars
); i
++ )
569 struct route_ui_bar
*uib
= &world
.ui_bars
[i
];
570 uib
->segment_start
= 0;
571 uib
->segment_count
= 0;
574 uib
->fade_timer_start
= 0.0;
578 /* delete the entire block of memory */
579 vg_linear_clear( world
.dynamic_vgl
);
580 vg_linear_clear( world
.audio_vgl
);
582 /* clean dangling pointers */
585 world
.scene_geo
= NULL
;
586 world
.scene_lines
= NULL
;
587 world
.scene_no_collide
= NULL
;
590 world
.trigger_bh
= NULL
;
591 world
.audio_bh
= NULL
;
594 world
.spawn_count
= 0;
596 world
.audio_things
= NULL
;
597 world
.audio_things_count
= 0;
599 world
.triggers
= NULL
;
600 world
.trigger_count
= 0;
602 world
.logic_relays
= NULL
;
603 world
.relay_count
= 0;
605 world
.logic_achievements
= NULL
;
606 world
.achievement_count
= 0;
609 world
.node_count
= 0;
612 world
.route_count
= 0;
615 world
.gate_count
= 0;
617 world
.collectors
= NULL
;
618 world
.collector_count
= 0;
620 world
.water
.enabled
= 0;
623 VG_STATIC
void world_load(void)
627 world
.meta
= mdl_load_full( world
.dynamic_vgl
, world
.world_name
);
628 vg_info( "Loading world: %s\n", world
.world_name
);
630 /* dynamic allocations */
631 world_ents_allocate();
632 world_routes_allocate();
634 /* meta processing */
635 world_routes_process();
636 world_entities_process();
640 world_routes_generate();
641 world_post_process();
644 #endif /* WORLD_GEN_H */