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 VG_STATIC
void world_add_blob( scene
*pscene
, ray_hit
*hit
)
39 v4f qsurface
, qrandom
;
42 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
->normal
, axis
);
44 float angle
= v3_dot(hit
->normal
,(v3f
){0.0f
,1.0f
,0.0f
});
45 q_axis_angle( qsurface
, axis
, angle
);
46 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf()*VG_TAUf
);
47 q_mul( qsurface
, qrandom
, qsurface
);
48 q_m3x3( qsurface
, transform
);
49 v3_copy( hit
->pos
, transform
[3] );
53 { .co
= { -1.00f
, 0.0f
, 0.0f
} },
54 { .co
= { 1.00f
, 0.0f
, 0.0f
} },
55 { .co
= { -1.00f
, 1.2f
, 0.0f
} },
56 { .co
= { 1.00f
, 1.2f
, 0.0f
} },
57 { .co
= { -0.25f
, 2.0f
, 0.0f
} },
58 { .co
= { 0.25f
, 2.0f
, 0.0f
} }
61 const u32 indices
[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 };
63 if( pscene
->vertex_count
+ vg_list_size(verts
) > pscene
->max_vertices
)
64 vg_fatal_exit_loop( "Scene vertex buffer overflow" );
66 if( pscene
->indice_count
+ vg_list_size(indices
) > pscene
->max_indices
)
67 vg_fatal_exit_loop( "Scene index buffer overflow" );
69 mdl_vert
*dst_verts
= &pscene
->arrvertices
[ pscene
->vertex_count
];
70 u32
*dst_indices
= &pscene
->arrindices
[ pscene
->indice_count
];
72 mdl_vert
*ref
= &world
.scene_geo
->arrvertices
[ hit
->tri
[0] ];
74 for( u32 i
=0; i
<vg_list_size(verts
); i
++ )
76 mdl_vert
*pvert
= &dst_verts
[ i
],
79 m4x3_mulv( transform
, src
->co
, pvert
->co
);
80 v3_copy( transform
[1], pvert
->norm
);
86 pvert
->weights
[0] = 0;
87 pvert
->weights
[1] = 0;
88 pvert
->weights
[2] = 0;
89 pvert
->weights
[3] = 0;
91 v2_copy( ref
->uv
, pvert
->uv
);
94 for( u32 i
=0; i
<vg_list_size(indices
); i
++ )
95 dst_indices
[i
] = indices
[i
] + pscene
->vertex_count
;
97 pscene
->vertex_count
+= vg_list_size(verts
);
98 pscene
->indice_count
+= vg_list_size(indices
);
101 /* Sprinkle foliage models over the map on terrain material */
102 VG_STATIC
void world_apply_procedural_foliage( struct world_material
*mat
)
104 if( vg
.quality_profile
== k_quality_profile_low
)
107 vg_info( "Applying foliage (%u)\n", mat
->info
.pstr_name
);
109 vg_linear_clear( vg_mem
.scratch
);
111 mdl_context
*mfoliage
=
112 mdl_load_full( vg_mem
.scratch
, "models/rs_foliage.mdl");
115 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], volume
);
118 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
119 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
123 float area
= volume
[0]*volume
[2];
124 u32 particles
= 0.08f
* area
;
126 vg_info( "Map area: %f. Max particles: %u\n", area
, particles
);
128 for( int i
=0;i
<particles
;i
++ )
131 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
133 v3_add( pos
, world
.scene_geo
->bbx
[0], pos
);
138 if( ray_world( pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
140 struct world_material
*m1
= ray_hit_material( &hit
);
141 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) && (hit
.pos
[1] > 0.0f
+10.0f
))
143 world_add_blob( world
.scene_no_collide
, &hit
);
149 vg_info( "%d foliage models added\n", count
);
152 VG_STATIC
void world_ents_allocate(void)
154 vg_info( "Allocating entities\n" );
156 /* count entites to allocate buffers for them.
157 * maybe in the future we just store these numbers in the model file...
159 * TODO: use this in world_routes too */
172 (void*)&world
.spawns
,
173 sizeof(struct respawn_point
)
177 (void*)&world
.audio_things
,
178 sizeof(struct world_audio_thing
)
182 (void*)&world
.triggers
,
183 sizeof(struct trigger_zone
)
186 k_classtype_logic_relay
,
187 (void*)&world
.logic_relays
,
188 sizeof(struct logic_relay
)
191 k_classtype_logic_achievement
,
192 (void*)&world
.logic_achievements
,
193 sizeof(struct logic_achievement
)
197 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
198 entity_counts
[i
].count
= 0;
200 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
202 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
204 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
206 if( pnode
->classtype
== entity_counts
[j
].ct
)
208 pnode
->sub_uid
= entity_counts
[j
].count
;
209 entity_counts
[j
].count
++;
215 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
217 struct countable
*counter
= &entity_counts
[i
];
219 u32 bufsize
= counter
->item_size
*counter
->count
;
220 *counter
->to_allocate
= vg_linear_alloc( world
.dynamic_vgl
, bufsize
);
224 VG_STATIC
void world_pct_spawn( mdl_node
*pnode
)
226 struct respawn_point
*rp
= &world
.spawns
[ world
.spawn_count
++ ];
228 v3_copy( pnode
->co
, rp
->co
);
229 v4_copy( pnode
->q
, rp
->q
);
230 rp
->name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
233 VG_STATIC
void world_pct_water( mdl_node
*pnode
)
235 if( world
.water
.enabled
)
237 vg_warn( "Multiple water surfaces in level! ('%s')\n",
238 mdl_pstr( world
.meta
, pnode
->pstr_name
));
242 world
.water
.enabled
= 1;
243 water_set_surface( pnode
->co
[1] );
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 thing
->temp_embedded_clip
.source_mode
= k_audio_source_mono
;
265 audio_clip_load( &thing
->temp_embedded_clip
, world
.audio_vgl
);
266 thing
->player
.name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
267 thing
->player
.enqued
= 0;
269 pnode
->sub_uid
= world
.audio_things_count
;
270 world
.audio_things_count
++;
274 VG_STATIC
void world_pct_trigger( mdl_node
*pnode
)
276 struct trigger_zone
*trigger
= &world
.triggers
[ world
.trigger_count
];
277 struct classtype_trigger
*inf
= mdl_get_entdata( world
.meta
, pnode
);
281 mdl_node
*target_node
= mdl_node_from_id( world
.meta
, inf
->target
);
283 trigger
->target
.sub_id
= target_node
->sub_uid
;
284 trigger
->target
.classtype
= target_node
->classtype
;
288 vg_warn( "Trigger with no target...\n" );
292 mdl_node_transform( pnode
, trigger
->transform
);
293 m4x3_invert_full( trigger
->transform
, trigger
->inv_transform
);
295 world
.trigger_count
++;
299 VG_STATIC
void world_pct_relay( mdl_node
*pnode
)
301 struct logic_relay
*relay
= &world
.logic_relays
[ world
.relay_count
];
302 struct classtype_logic_relay
*inf
= mdl_get_entdata( world
.meta
, pnode
);
304 relay
->target_count
= 0;
306 for( int i
=0; i
<vg_list_size(relay
->targets
); i
++ )
308 if( inf
->targets
[i
] )
310 struct relay_target
*target
= &relay
->targets
[relay
->target_count
++];
311 mdl_node
*other
= mdl_node_from_id( world
.meta
, inf
->targets
[i
] );
313 target
->classtype
= other
->classtype
;
314 target
->sub_id
= other
->sub_uid
;
318 v3_copy( pnode
->co
, relay
->pos
);
319 world
.relay_count
++;
323 VG_STATIC
void world_pct_achievement( mdl_node
*pnode
)
325 struct logic_achievement
*ach
=
326 &world
.logic_achievements
[ world
.achievement_count
];
327 struct classtype_logic_achievement
*inf
=
328 mdl_get_entdata( world
.meta
, pnode
);
330 v3_copy( pnode
->co
, ach
->pos
);
331 ach
->achievement_id
= mdl_pstr( world
.meta
, inf
->pstr_name
);
334 world
.achievement_count
++;
338 VG_STATIC
void world_entities_process(void)
340 struct entity_instruction
343 void (*process
)( mdl_node
*pnode
);
345 entity_instructions
[] =
347 { k_classtype_spawn
, world_pct_spawn
},
348 { k_classtype_water
, world_pct_water
},
349 { k_classtype_audio
, world_pct_audio
},
350 { k_classtype_trigger
, world_pct_trigger
},
351 { k_classtype_logic_relay
, world_pct_relay
},
352 { k_classtype_logic_achievement
, world_pct_achievement
}
355 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
357 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
359 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
361 struct entity_instruction
*instr
= &entity_instructions
[j
];
363 if( pnode
->classtype
== instr
->ct
)
365 instr
->process( pnode
);
372 VG_STATIC
void world_generate(void)
375 * Compile meshes into the world scenes
377 world
.scene_geo
= scene_init( world
.dynamic_vgl
, 320000, 1200000 );
380 m4x3_identity( midentity
);
383 * Generate scene: collidable geometry
384 * ----------------------------------------------------------------
387 vg_info( "Generating collidable geometry\n" );
390 for( int i
=0; i
<world
.material_count
; i
++ )
392 struct world_material
*mat
= &world
.materials
[ i
];
394 if( mat
->info
.flags
& k_material_flag_collision
)
395 world_add_all_if_material( midentity
, world
.scene_geo
, world
.meta
, i
);
397 scene_copy_slice( world
.scene_geo
, &mat
->sm_geo
);
403 /* compress that bad boy */
404 world
.scene_geo
= scene_fix( world
.dynamic_vgl
, world
.scene_geo
);
406 vg_acquire_thread_sync();
408 scene_upload( world
.scene_geo
, &world
.mesh_geo
);
410 vg_release_thread_sync();
412 /* setup spacial mapping and rigidbody */
413 world
.geo_bh
= scene_bh_create( world
.dynamic_vgl
, world
.scene_geo
);
415 v3_zero( world
.rb_geo
.co
);
416 q_identity( world
.rb_geo
.q
);
418 world
.rb_geo
.type
= k_rb_shape_scene
;
419 world
.rb_geo
.inf
.scene
.bh_scene
= world
.geo_bh
;
420 world
.rb_geo
.is_world
= 1;
421 rb_init( &world
.rb_geo
);
424 * Generate scene: non-collidable geometry
425 * ----------------------------------------------------------------
427 vg_info( "Generating non-collidable geometry\n" );
429 world
.scene_no_collide
= scene_init( world
.dynamic_vgl
, 200000, 500000 );
431 for( int i
=0; i
<world
.material_count
; i
++ )
433 struct world_material
*mat
= &world
.materials
[ i
];
435 if( !(mat
->info
.flags
& k_material_flag_collision
) )
437 world_add_all_if_material( midentity
, world
.scene_no_collide
,
441 if( mat
->info
.flags
& k_material_flag_grow_grass
)
442 world_apply_procedural_foliage( mat
);
444 scene_copy_slice( world
.scene_no_collide
, &mat
->sm_no_collide
);
447 /* upload and free that */
448 vg_acquire_thread_sync();
450 scene_upload( world
.scene_no_collide
, &world
.mesh_no_collide
);
452 vg_release_thread_sync();
454 vg_linear_del( world
.dynamic_vgl
, world
.scene_no_collide
);
455 world
.scene_no_collide
= NULL
;
458 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
459 VG_STATIC
void world_post_process(void)
461 /* initialize audio if need be */
463 for( int i
=0; i
<world
.audio_things_count
; i
++ )
465 struct world_audio_thing
*thingy
= &world
.audio_things
[ i
];
467 audio_player_init( &thingy
->player
);
468 audio_player_set_flags( &thingy
->player
, thingy
->flags
);
469 audio_player_set_vol( &thingy
->player
, thingy
->volume
);
470 audio_player_set_pan( &thingy
->player
, 0.0f
);
472 if( thingy
->flags
& AUDIO_FLAG_SPACIAL_3D
)
473 audio_player_set_position( &thingy
->player
, thingy
->pos
);
475 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
476 audio_player_playclip( &thingy
->player
, &thingy
->temp_embedded_clip
);
480 vg_acquire_thread_sync();
483 * Rendering the depth map
488 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], extent
);
490 float fl
= world
.scene_geo
->bbx
[0][0],
491 fr
= world
.scene_geo
->bbx
[1][0],
492 fb
= world
.scene_geo
->bbx
[0][2],
493 ft
= world
.scene_geo
->bbx
[1][2],
497 m4x4_zero( ortho
.mtx
.p
);
498 ortho
.mtx
.p
[0][0] = 2.0f
* rl
;
499 ortho
.mtx
.p
[2][1] = 2.0f
* tb
;
500 ortho
.mtx
.p
[3][0] = (fr
+ fl
) * -rl
;
501 ortho
.mtx
.p
[3][1] = (ft
+ fb
) * -tb
;
502 ortho
.mtx
.p
[3][3] = 1.0f
;
503 m4x3_identity( ortho
.transform
);
504 camera_update_view( &ortho
);
505 camera_finalize( &ortho
);
507 glDisable(GL_DEPTH_TEST
);
509 glDisable(GL_CULL_FACE
);
510 render_fb_bind( gpipeline
.fb_heightmap
);
511 shader_blitcolour_use();
512 shader_blitcolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
517 glBlendFunc(GL_ONE
, GL_ONE
);
518 glBlendEquation(GL_MAX
);
520 render_world_depth( &ortho
);
522 glEnable(GL_DEPTH_TEST
);
523 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
526 * TODO: World settings entity
528 struct ub_world_lighting
*winfo
= &gpipeline
.ub_world_lighting
;
530 if( world
.water
.enabled
)
531 v4_copy( world
.water
.plane
, winfo
->g_water_plane
);
534 v3f
*bounds
= world
.scene_geo
->bbx
;
536 info_vec
[0] = bounds
[0][0];
537 info_vec
[1] = bounds
[0][2];
538 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
539 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
540 v4_copy( info_vec
, winfo
->g_depth_bounds
);
542 winfo
->g_water_fog
= 0.04f
;
543 render_update_lighting_ub();
546 vg_release_thread_sync();
550 * Setup scene collider
552 reset_player( 1, (const char *[]){"start"} );
556 VG_STATIC
void world_process_resources(void)
558 vg_info( "Loading textures\n" );
559 world
.texture_count
= world
.meta
->info
.texture_count
;
561 vg_linear_alloc( world
.dynamic_vgl
, sizeof(GLuint
)*world
.texture_count
);
563 vg_acquire_thread_sync();
566 world
.textures
[0] = vg_tex2d_new();
567 vg_tex2d_set_error();
571 for( int i
=1; i
<world
.texture_count
; i
++ )
573 mdl_texture
*tex
= &world
.meta
->texture_buffer
[i
];
575 if( !tex
->pack_offset
)
577 vg_release_thread_sync();
578 vg_fatal_exit_loop( "World models must have packed textures!" );
581 vg_linear_clear( vg_mem
.scratch
);
582 world
.textures
[i
] = vg_tex2d_new();
583 vg_tex2d_set_error();
584 vg_tex2d_qoi( world
.meta
->pack
+ tex
->pack_offset
, tex
->pack_length
,
585 mdl_pstr( world
.meta
, tex
->pstr_name
));
590 vg_release_thread_sync();
592 vg_info( "Loading materials\n" );
594 u32 size
= sizeof(struct world_material
) * world
.meta
->info
.material_count
;
595 world
.materials
= vg_linear_alloc( world
.dynamic_vgl
, size
);
597 world
.material_count
= world
.meta
->info
.material_count
;
598 memset( world
.materials
, 0, size
);
600 for( int i
=1; i
<world
.material_count
; i
++ )
601 world
.materials
[i
].info
= world
.meta
->material_buffer
[i
];
604 struct world_material
*errmat
= &world
.materials
[0];
605 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour
);
606 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour1
);
607 errmat
->info
.flags
= 0x00;
608 errmat
->info
.pstr_name
= 0; /* useless? */
609 errmat
->info
.shader
= -1;
610 errmat
->info
.tex_decal
= 0;
611 errmat
->info
.tex_diffuse
= 0;
612 errmat
->info
.tex_normal
= 0;
615 VG_STATIC
void world_unload(void)
617 vg_acquire_thread_sync();
620 mesh_free( &world
.mesh_route_lines
);
621 mesh_free( &world
.mesh_geo
);
622 mesh_free( &world
.mesh_no_collide
);
625 world
.rewind_from
= 0.0;
626 world
.rewind_to
= 0.0;
627 world
.last_use
= 0.0;
628 world
.active_gate
= 0;
629 world
.current_run_version
= 2;
630 world
.active_route_board
= 0;
631 v3_zero( world
.render_gate_pos
);
633 for( int i
=0; i
<vg_list_size(world
.ui_bars
); i
++ )
635 struct route_ui_bar
*uib
= &world
.ui_bars
[i
];
636 uib
->segment_start
= 0;
637 uib
->segment_count
= 0;
640 uib
->fade_timer_start
= 0.0;
644 /* delete textures and meshes */
645 glDeleteTextures( world
.texture_count
, world
.textures
);
647 /* delete the entire block of memory */
648 vg_linear_clear( world
.dynamic_vgl
);
649 vg_linear_clear( world
.audio_vgl
);
651 /* clean dangling pointers */
654 world
.textures
= NULL
;
655 world
.texture_count
= 0;
656 world
.materials
= NULL
;
657 world
.material_count
= 0;
659 world
.scene_geo
= NULL
;
660 world
.scene_no_collide
= NULL
;
661 world
.scene_lines
= NULL
;
664 world
.trigger_bh
= NULL
;
665 world
.audio_bh
= NULL
;
668 world
.spawn_count
= 0;
670 world
.audio_things
= NULL
;
671 world
.audio_things_count
= 0;
673 world
.triggers
= NULL
;
674 world
.trigger_count
= 0;
676 world
.logic_relays
= NULL
;
677 world
.relay_count
= 0;
679 world
.logic_achievements
= NULL
;
680 world
.achievement_count
= 0;
683 world
.node_count
= 0;
686 world
.route_count
= 0;
689 world
.gate_count
= 0;
691 world
.collectors
= NULL
;
692 world
.collector_count
= 0;
694 world
.water
.enabled
= 0;
696 vg_release_thread_sync();
699 VG_STATIC
void world_load(void)
703 world
.meta
= mdl_load_full( world
.dynamic_vgl
, world
.world_name
);
704 vg_info( "Loading world: %s\n", world
.world_name
);
706 /* process resources from pack */
707 world_process_resources();
709 /* dynamic allocations */
710 world_ents_allocate();
711 world_routes_allocate();
713 /* meta processing */
714 world_routes_process();
715 world_entities_process();
719 world_routes_generate();
720 world_post_process();
723 #endif /* WORLD_GEN_H */