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( struct world_material
*mat
)
39 if( vg
.quality_profile
== k_quality_profile_low
)
42 vg_linear_clear( vg_mem
.scratch
);
44 mdl_context
*mfoliage
=
45 mdl_load_full( vg_mem
.scratch
, "models/rs_foliage.mdl");
48 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], volume
);
52 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
53 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
55 for( int i
=0;i
<100000;i
++ )
58 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
60 v3_add( pos
, world
.scene_geo
->bbx
[0], pos
);
65 if( ray_world( pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
67 struct world_material
*m1
= ray_hit_material( &hit
);
68 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) && (hit
.pos
[1] > 0.0f
+10.0f
))
70 v4f qsurface
, qrandom
;
73 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
.normal
, axis
);
75 float angle
= v3_dot(hit
.normal
,(v3f
){0.0f
,1.0f
,0.0f
});
76 q_axis_angle( qsurface
, axis
, angle
);
77 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf()*VG_TAUf
);
78 q_mul( qsurface
, qrandom
, qsurface
);
79 q_m3x3( qsurface
, transform
);
81 v3_copy( hit
.pos
, transform
[3] );
82 scene_add_submesh( world
.scene_no_collide
, mfoliage
,
89 VG_STATIC
void world_ents_allocate(void)
91 vg_info( "Allocating entities\n" );
93 /* count entites to allocate buffers for them.
94 * maybe in the future we just store these numbers in the model file...
96 * TODO: use this in world_routes too */
109 (void*)&world
.spawns
,
110 sizeof(struct respawn_point
)
114 (void*)&world
.audio_things
,
115 sizeof(struct world_audio_thing
)
119 (void*)&world
.triggers
,
120 sizeof(struct trigger_zone
)
123 k_classtype_logic_relay
,
124 (void*)&world
.logic_relays
,
125 sizeof(struct logic_relay
)
128 k_classtype_logic_achievement
,
129 (void*)&world
.logic_achievements
,
130 sizeof(struct logic_achievement
)
134 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
135 entity_counts
[i
].count
= 0;
137 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
139 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
141 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
143 if( pnode
->classtype
== entity_counts
[j
].ct
)
145 pnode
->sub_uid
= entity_counts
[j
].count
;
146 entity_counts
[j
].count
++;
152 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
154 struct countable
*counter
= &entity_counts
[i
];
156 u32 bufsize
= counter
->item_size
*counter
->count
;
157 *counter
->to_allocate
= vg_linear_alloc( world
.dynamic_vgl
, bufsize
);
161 VG_STATIC
void world_pct_spawn( mdl_node
*pnode
)
163 struct respawn_point
*rp
= &world
.spawns
[ world
.spawn_count
++ ];
165 v3_copy( pnode
->co
, rp
->co
);
166 v4_copy( pnode
->q
, rp
->q
);
167 rp
->name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
170 VG_STATIC
void world_pct_water( mdl_node
*pnode
)
172 if( world
.water
.enabled
)
174 vg_warn( "Multiple water surfaces in level! ('%s')\n",
175 mdl_pstr( world
.meta
, pnode
->pstr_name
));
179 world
.water
.enabled
= 1;
180 water_set_surface( pnode
->co
[1] );
183 VG_STATIC
void world_pct_audio( mdl_node
*pnode
)
185 struct world_audio_thing
*thing
= &world
.audio_things
[
186 world
.audio_things_count
];
188 memset( thing
, 0, sizeof(struct world_audio_thing
) );
189 struct classtype_audio
*aud
= mdl_get_entdata( world
.meta
, pnode
);
191 v3_copy( pnode
->co
, thing
->pos
);
193 if( aud
->flags
& AUDIO_FLAG_SPACIAL_3D
)
194 thing
->volume
= aud
->volume
* pnode
->s
[0];
196 thing
->volume
= aud
->volume
;
198 thing
->flags
= aud
->flags
;
199 thing
->temp_embedded_clip
.path
= mdl_pstr( world
.meta
, aud
->pstr_file
);
200 thing
->temp_embedded_clip
.source_mode
= k_audio_source_mono
;
202 audio_clip_load( &thing
->temp_embedded_clip
, world
.audio_vgl
);
203 thing
->player
.name
= mdl_pstr( world
.meta
, pnode
->pstr_name
);
204 thing
->player
.enqued
= 0;
206 pnode
->sub_uid
= world
.audio_things_count
;
207 world
.audio_things_count
++;
211 VG_STATIC
void world_pct_trigger( mdl_node
*pnode
)
213 struct trigger_zone
*trigger
= &world
.triggers
[ world
.trigger_count
];
214 struct classtype_trigger
*inf
= mdl_get_entdata( world
.meta
, pnode
);
218 mdl_node
*target_node
= mdl_node_from_id( world
.meta
, inf
->target
);
220 trigger
->target
.sub_id
= target_node
->sub_uid
;
221 trigger
->target
.classtype
= target_node
->classtype
;
225 vg_warn( "Trigger with no target...\n" );
229 mdl_node_transform( pnode
, trigger
->transform
);
230 m4x3_invert_full( trigger
->transform
, trigger
->inv_transform
);
232 world
.trigger_count
++;
236 VG_STATIC
void world_pct_relay( mdl_node
*pnode
)
238 struct logic_relay
*relay
= &world
.logic_relays
[ world
.relay_count
];
239 struct classtype_logic_relay
*inf
= mdl_get_entdata( world
.meta
, pnode
);
241 relay
->target_count
= 0;
243 for( int i
=0; i
<vg_list_size(relay
->targets
); i
++ )
245 if( inf
->targets
[i
] )
247 struct relay_target
*target
= &relay
->targets
[relay
->target_count
++];
248 mdl_node
*other
= mdl_node_from_id( world
.meta
, inf
->targets
[i
] );
250 target
->classtype
= other
->classtype
;
251 target
->sub_id
= other
->sub_uid
;
255 v3_copy( pnode
->co
, relay
->pos
);
256 world
.relay_count
++;
260 VG_STATIC
void world_pct_achievement( mdl_node
*pnode
)
262 struct logic_achievement
*ach
=
263 &world
.logic_achievements
[ world
.achievement_count
];
264 struct classtype_logic_achievement
*inf
=
265 mdl_get_entdata( world
.meta
, pnode
);
267 v3_copy( pnode
->co
, ach
->pos
);
268 ach
->achievement_id
= mdl_pstr( world
.meta
, inf
->pstr_name
);
271 world
.achievement_count
++;
275 VG_STATIC
void world_entities_process(void)
277 struct entity_instruction
280 void (*process
)( mdl_node
*pnode
);
282 entity_instructions
[] =
284 { k_classtype_spawn
, world_pct_spawn
},
285 { k_classtype_water
, world_pct_water
},
286 { k_classtype_audio
, world_pct_audio
},
287 { k_classtype_trigger
, world_pct_trigger
},
288 { k_classtype_logic_relay
, world_pct_relay
},
289 { k_classtype_logic_achievement
, world_pct_achievement
}
292 for( int i
=0; i
<world
.meta
->info
.node_count
; i
++ )
294 mdl_node
*pnode
= mdl_node_from_id( world
.meta
, i
);
296 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
298 struct entity_instruction
*instr
= &entity_instructions
[j
];
300 if( pnode
->classtype
== instr
->ct
)
302 instr
->process( pnode
);
309 VG_STATIC
void edge_bh_expand_bound( void *user
, boxf bound
, u32 item_index
)
311 struct grind_edge
*edge_array
= user
,
312 *edge
= &edge_array
[ item_index
];
314 box_addpt( bound
, edge
->p0
);
315 box_addpt( bound
, edge
->p1
);
318 VG_STATIC
float edge_bh_centroid( void *user
, u32 item_index
, int axis
)
320 struct grind_edge
*edge_array
= user
,
321 *edge
= &edge_array
[ item_index
];
323 return (edge
->p0
[axis
] + edge
->p1
[axis
]) * 0.5f
;
326 VG_STATIC
void edge_bh_swap( void *user
, u32 ia
, u32 ib
)
328 struct grind_edge
*edge_array
= user
,
329 *e0
= &edge_array
[ ia
],
330 *e1
= &edge_array
[ ib
],
337 VG_STATIC
void edge_bh_closest( void *user
, u32 index
, v3f point
, v3f closest
)
339 struct grind_edge
*edge_array
= user
,
340 *edge
= &edge_array
[ index
];
342 closest_point_segment( edge
->p0
, edge
->p1
, point
, closest
);
345 VG_STATIC bh_system bh_system_edges
=
347 .expand_bound
= edge_bh_expand_bound
,
348 .item_centroid
= edge_bh_centroid
,
349 .item_closest
= edge_bh_closest
,
350 .item_swap
= edge_bh_swap
,
355 VG_STATIC
void world_generate_edges(void)
357 vg_info( "Generating edge array\n" );
358 world
.grind_edges
= vg_linear_alloc( world
.dynamic_vgl
,
359 5000*sizeof(struct grind_edge
) );
360 world
.grind_edge_count
= 0;
363 for( u32 i
=0; i
<world
.scene_geo
->vertex_count
; i
++ )
364 if( world
.scene_geo
->arrvertices
[i
].weights
[0] )
367 vg_info( "Grind verts: %u\n", fs_count
);
369 for( u32 i
=0; i
<world
.scene_geo
->indice_count
/3; i
++ )
371 u32
*ptri
= &world
.scene_geo
->arrindices
[ i
*3 ];
373 for( int j
=0; j
<3; j
++ )
378 mdl_vert
*v0
= &world
.scene_geo
->arrvertices
[ i0
],
379 *v1
= &world
.scene_geo
->arrvertices
[ i1
];
383 if( world
.grind_edge_count
== 5000 )
384 vg_fatal_exit_loop( "Edge capacity exceeded" );
386 struct grind_edge
*ge
=
387 &world
.grind_edges
[ world
.grind_edge_count
++ ];
389 v3_copy( v0
->co
, ge
->p0
);
390 v3_copy( v1
->co
, ge
->p1
);
395 vg_info( "Grind edge count: %u\n", world
.grind_edge_count
);
397 world
.grind_edges
= vg_linear_resize( world
.dynamic_vgl
, world
.grind_edges
,
398 world
.grind_edge_count
*sizeof(struct grind_edge
) );
400 world
.grind_bh
= bh_create( world
.dynamic_vgl
, &bh_system_edges
,
401 world
.grind_edges
, world
.grind_edge_count
,
405 VG_STATIC
void world_generate(void)
408 * Compile meshes into the world scenes
410 world
.scene_geo
= scene_init( world
.dynamic_vgl
, 320000, 1200000 );
413 m4x3_identity( midentity
);
416 * Generate scene: collidable geometry
417 * ----------------------------------------------------------------
420 vg_info( "Generating collidable geometry\n" );
423 for( int i
=0; i
<world
.material_count
; i
++ )
425 struct world_material
*mat
= &world
.materials
[ i
];
427 if( mat
->info
.flags
& k_material_flag_collision
)
428 world_add_all_if_material( midentity
, world
.scene_geo
, world
.meta
, i
);
430 scene_copy_slice( world
.scene_geo
, &mat
->sm_geo
);
436 /* compress that bad boy */
437 world
.scene_geo
= scene_fix( world
.dynamic_vgl
, world
.scene_geo
);
439 vg_acquire_thread_sync();
441 scene_upload( world
.scene_geo
, &world
.mesh_geo
);
443 vg_release_thread_sync();
445 /* setup spacial mapping and rigidbody */
446 world
.geo_bh
= scene_bh_create( world
.dynamic_vgl
, world
.scene_geo
);
448 v3_zero( world
.rb_geo
.co
);
449 q_identity( world
.rb_geo
.q
);
451 world
.rb_geo
.type
= k_rb_shape_scene
;
452 world
.rb_geo
.inf
.scene
.bh_scene
= world
.geo_bh
;
453 world
.rb_geo
.is_world
= 1;
454 rb_init( &world
.rb_geo
);
457 * Generate scene: non-collidable geometry
458 * ----------------------------------------------------------------
460 vg_info( "Generating non-collidable geometry\n" );
462 world
.scene_no_collide
= scene_init( world
.dynamic_vgl
, 200000, 500000 );
465 vg_info( "Applying foliage\n" );
467 world_apply_procedural_foliage();
468 scene_copy_slice( world
.scene_no_collide
, &world
.sm_foliage_main
);
471 for( int i
=0; i
<world
.material_count
; i
++ )
473 struct world_material
*mat
= &world
.materials
[ i
];
475 if( !(mat
->info
.flags
& k_material_flag_collision
) )
477 world_add_all_if_material( midentity
, world
.scene_no_collide
,
481 if( mat
->info
.flags
& k_material_flag_grow_grass
)
482 world_apply_procedural_foliage( mat
);
484 scene_copy_slice( world
.scene_no_collide
, &mat
->sm_no_collide
);
487 /* upload and free that */
488 vg_acquire_thread_sync();
490 scene_upload( world
.scene_no_collide
, &world
.mesh_no_collide
);
492 vg_release_thread_sync();
494 vg_linear_del( world
.dynamic_vgl
, world
.scene_no_collide
);
495 world
.scene_no_collide
= NULL
;
497 world_generate_edges();
500 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
501 VG_STATIC
void world_post_process(void)
503 /* initialize audio if need be */
505 for( int i
=0; i
<world
.audio_things_count
; i
++ )
507 struct world_audio_thing
*thingy
= &world
.audio_things
[ i
];
509 audio_player_init( &thingy
->player
);
510 audio_player_set_flags( &thingy
->player
, thingy
->flags
);
511 audio_player_set_vol( &thingy
->player
, thingy
->volume
);
512 audio_player_set_pan( &thingy
->player
, 0.0f
);
514 if( thingy
->flags
& AUDIO_FLAG_SPACIAL_3D
)
515 audio_player_set_position( &thingy
->player
, thingy
->pos
);
517 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
518 audio_player_playclip( &thingy
->player
, &thingy
->temp_embedded_clip
);
522 vg_acquire_thread_sync();
525 * Rendering the depth map
531 v3_sub( world
.scene_geo
->bbx
[1], world
.scene_geo
->bbx
[0], extent
);
533 float fl
= world
.scene_geo
->bbx
[0][0],
534 fr
= world
.scene_geo
->bbx
[1][0],
535 fb
= world
.scene_geo
->bbx
[0][2],
536 ft
= world
.scene_geo
->bbx
[1][2],
541 ortho
[0][0] = 2.0f
* rl
;
542 ortho
[2][1] = 2.0f
* tb
;
543 ortho
[3][0] = (fr
+ fl
) * -rl
;
544 ortho
[3][1] = (ft
+ fb
) * -tb
;
546 m4x3_identity( camera
);
548 glDisable(GL_DEPTH_TEST
);
550 glDisable(GL_CULL_FACE
);
551 glBindFramebuffer( GL_FRAMEBUFFER
, gpipeline
.fb_depthmap
);
552 glViewport( 0, 0, 1024, 1024 );
553 shader_fscolour_use();
554 shader_fscolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
559 glBlendFunc(GL_ONE
, GL_ONE
);
560 glBlendEquation(GL_MAX
);
561 render_world_depth( ortho
, camera
);
563 glEnable(GL_DEPTH_TEST
);
564 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
568 * TODO: World settings entity
570 struct ub_world_lighting
*winfo
= &gpipeline
.ub_world_lighting
;
572 if( world
.water
.enabled
)
573 v4_copy( world
.water
.plane
, winfo
->g_water_plane
);
576 v3f
*bounds
= world
.scene_geo
->bbx
;
578 info_vec
[0] = bounds
[0][0];
579 info_vec
[1] = bounds
[0][2];
580 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
581 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
582 v4_copy( info_vec
, winfo
->g_depth_bounds
);
584 winfo
->g_water_fog
= 0.04f
;
585 render_update_lighting_ub();
588 vg_release_thread_sync();
591 * Setup scene collider
594 reset_player( 1, (const char *[]){"start"} );
597 VG_STATIC
void world_process_resources(void)
599 vg_info( "Loading textures\n" );
600 world
.texture_count
= world
.meta
->info
.texture_count
;
602 vg_linear_alloc( world
.dynamic_vgl
, sizeof(GLuint
)*world
.texture_count
);
604 vg_acquire_thread_sync();
607 world
.textures
[0] = vg_tex2d_new();
608 vg_tex2d_set_error();
612 for( int i
=1; i
<world
.texture_count
; i
++ )
614 mdl_texture
*tex
= &world
.meta
->texture_buffer
[i
];
616 if( !tex
->pack_offset
)
618 vg_release_thread_sync();
619 vg_fatal_exit_loop( "World models must have packed textures!" );
622 vg_linear_clear( vg_mem
.scratch
);
623 world
.textures
[i
] = vg_tex2d_new();
624 vg_tex2d_set_error();
625 vg_tex2d_qoi( world
.meta
->pack
+ tex
->pack_offset
, tex
->pack_length
,
626 mdl_pstr( world
.meta
, tex
->pstr_name
));
631 vg_release_thread_sync();
633 vg_info( "Loading materials\n" );
635 u32 size
= sizeof(struct world_material
) * world
.meta
->info
.material_count
;
636 world
.materials
= vg_linear_alloc( world
.dynamic_vgl
, size
);
638 world
.material_count
= world
.meta
->info
.material_count
;
639 memset( world
.materials
, 0, size
);
641 for( int i
=1; i
<world
.material_count
; i
++ )
642 world
.materials
[i
].info
= world
.meta
->material_buffer
[i
];
645 struct world_material
*errmat
= &world
.materials
[0];
646 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour
);
647 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour1
);
648 errmat
->info
.flags
= 0x00;
649 errmat
->info
.pstr_name
= 0; /* useless? */
650 errmat
->info
.shader
= -1;
651 errmat
->info
.tex_decal
= 0;
652 errmat
->info
.tex_diffuse
= 0;
653 errmat
->info
.tex_normal
= 0;
656 VG_STATIC
void world_unload(void)
659 mesh_free( &world
.mesh_route_lines
);
660 mesh_free( &world
.mesh_geo
);
661 mesh_free( &world
.mesh_no_collide
);
664 world
.rewind_from
= 0.0;
665 world
.rewind_to
= 0.0;
666 world
.last_use
= 0.0;
667 world
.active_gate
= 0;
668 world
.current_run_version
= 2;
669 world
.active_route_board
= 0;
670 v3_zero( world
.render_gate_pos
);
672 for( int i
=0; i
<vg_list_size(world
.ui_bars
); i
++ )
674 struct route_ui_bar
*uib
= &world
.ui_bars
[i
];
675 uib
->segment_start
= 0;
676 uib
->segment_count
= 0;
679 uib
->fade_timer_start
= 0.0;
683 /* delete textures and meshes */
684 glDeleteTextures( world
.texture_count
, world
.textures
);
686 /* delete the entire block of memory */
687 vg_linear_clear( world
.dynamic_vgl
);
688 vg_linear_clear( world
.audio_vgl
);
690 /* clean dangling pointers */
693 world
.textures
= NULL
;
694 world
.texture_count
= 0;
695 world
.materials
= NULL
;
696 world
.material_count
= 0;
698 world
.scene_geo
= NULL
;
699 world
.scene_no_collide
= NULL
;
700 world
.scene_lines
= NULL
;
701 world
.grind_edges
= NULL
;
702 world
.grind_edge_count
= 0;
704 world
.grind_bh
= NULL
;
706 world
.trigger_bh
= NULL
;
707 world
.audio_bh
= NULL
;
710 world
.spawn_count
= 0;
712 world
.audio_things
= NULL
;
713 world
.audio_things_count
= 0;
715 world
.triggers
= NULL
;
716 world
.trigger_count
= 0;
718 world
.logic_relays
= NULL
;
719 world
.relay_count
= 0;
721 world
.logic_achievements
= NULL
;
722 world
.achievement_count
= 0;
725 world
.node_count
= 0;
728 world
.route_count
= 0;
731 world
.gate_count
= 0;
733 world
.collectors
= NULL
;
734 world
.collector_count
= 0;
736 world
.water
.enabled
= 0;
739 VG_STATIC
void world_load(void)
743 world
.meta
= mdl_load_full( world
.dynamic_vgl
, world
.world_name
);
744 vg_info( "Loading world: %s\n", world
.world_name
);
746 /* process resources from pack */
747 world_process_resources();
749 /* dynamic allocations */
750 world_ents_allocate();
751 world_routes_allocate();
753 /* meta processing */
754 world_routes_process();
755 world_entities_process();
759 world_routes_generate();
760 world_post_process();
763 #endif /* WORLD_GEN_H */