2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 VG_STATIC
void world_load( u32 index
, const char *path
);
12 VG_STATIC
void world_add_all_if_material( m4x3f transform
, scene_context
*scene
,
13 mdl_context
*mdl
, u32 id
)
15 for( u32 i
=0; i
<mdl_arrcount(&mdl
->meshs
); i
++ ){
16 mdl_mesh
*mesh
= mdl_arritm( &mdl
->meshs
, i
);
18 for( u32 j
=0; j
<mesh
->submesh_count
; j
++ ){
19 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, mesh
->submesh_start
+j
);
20 if( sm
->material_id
== id
){
22 mdl_transform_m4x3( &mesh
->transform
, transform2
);
23 m4x3_mul( transform
, transform2
, transform2
);
25 scene_add_mdl_submesh( scene
, mdl
, sm
, transform2
);
31 VG_STATIC
void world_add_blob( world_instance
*world
,
32 scene_context
*scene
, ray_hit
*hit
)
35 v4f qsurface
, qrandom
;
38 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
->normal
, axis
);
40 float angle
= v3_dot(hit
->normal
,(v3f
){0.0f
,1.0f
,0.0f
});
41 q_axis_angle( qsurface
, axis
, angle
);
42 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf64()*VG_TAUf
);
43 q_mul( qsurface
, qrandom
, qsurface
);
44 q_m3x3( qsurface
, transform
);
45 v3_copy( hit
->pos
, transform
[3] );
49 { .co
= { -1.00f
, 0.0f
, 0.0f
} },
50 { .co
= { 1.00f
, 0.0f
, 0.0f
} },
51 { .co
= { -1.00f
, 1.2f
, 0.0f
} },
52 { .co
= { 1.00f
, 1.2f
, 0.0f
} },
53 { .co
= { -0.25f
, 2.0f
, 0.0f
} },
54 { .co
= { 0.25f
, 2.0f
, 0.0f
} }
57 const u32 indices
[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 };
59 if( scene
->vertex_count
+ vg_list_size(verts
) > scene
->max_vertices
)
60 vg_fatal_error( "Scene vertex buffer overflow" );
62 if( scene
->indice_count
+ vg_list_size(indices
) > scene
->max_indices
)
63 vg_fatal_error( "Scene index buffer overflow" );
65 scene_vert
*dst_verts
= &scene
->arrvertices
[ scene
->vertex_count
];
66 u32
*dst_indices
= &scene
->arrindices
[ scene
->indice_count
];
68 scene_vert
*ref
= &world
->scene_geo
.arrvertices
[ hit
->tri
[0] ];
70 for( u32 i
=0; i
<vg_list_size(verts
); i
++ )
72 scene_vert
*pvert
= &dst_verts
[ i
],
75 m4x3_mulv( transform
, src
->co
, pvert
->co
);
76 scene_vert_pack_norm( pvert
, transform
[1] );
78 v2_copy( ref
->uv
, pvert
->uv
);
81 for( u32 i
=0; i
<vg_list_size(indices
); i
++ )
82 dst_indices
[i
] = indices
[i
] + scene
->vertex_count
;
84 scene
->vertex_count
+= vg_list_size(verts
);
85 scene
->indice_count
+= vg_list_size(indices
);
88 /* Sprinkle foliage models over the map on terrain material */
89 VG_STATIC
void world_apply_procedural_foliage( world_instance
*world
,
91 struct world_surface
*mat
)
93 if( vg
.quality_profile
== k_quality_profile_low
)
96 vg_info( "Applying foliage (%u)\n", mat
->info
.pstr_name
);
99 v3_sub( world
->scene_geo
.bbx
[1], world
->scene_geo
.bbx
[0], volume
);
104 float area
= volume
[0]*volume
[2];
105 u32 particles
= 0.08f
* area
;
107 /* TODO: Quasirandom? */
108 vg_info( "Map area: %f. Max particles: %u\n", area
, particles
);
110 for( u32 i
=0; i
<particles
; i
++ ){
112 v3_mul( volume
, (v3f
){ vg_randf64(), 1000.0f
, vg_randf64() }, pos
);
114 v3_add( pos
, world
->scene_geo
.bbx
[0], pos
);
119 if( ray_world( world
, pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
)){
120 struct world_surface
*m1
= ray_hit_surface( world
, &hit
);
121 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) && (hit
.pos
[1] > 0.0f
+10.0f
)){
122 world_add_blob( world
, scene
, &hit
);
128 vg_info( "%d foliage models added\n", count
);
131 VG_STATIC
void world_generate( world_instance
*world
)
134 * Compile meshes into the world scenes
136 scene_init( &world
->scene_geo
, 320000, 1200000 );
137 u32 buf_size
= scene_mem_required( &world
->scene_geo
);
138 u8
*buffer
= vg_linear_alloc( world
->heap
, buf_size
);
139 scene_supply_buffer( &world
->scene_geo
, buffer
);
142 m4x3_identity( midentity
);
145 * Generate scene: collidable geometry
146 * ----------------------------------------------------------------
149 vg_info( "Generating collidable geometry\n" );
151 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
152 struct world_surface
*surf
= &world
->surfaces
[ i
];
154 if( surf
->info
.flags
& k_material_flag_collision
)
155 world_add_all_if_material( midentity
, &world
->scene_geo
,
158 scene_copy_slice( &world
->scene_geo
, &surf
->sm_geo
);
161 /* compress that bad boy */
162 u32 new_vert_max
= world
->scene_geo
.vertex_count
,
163 new_vert_size
= vg_align8(new_vert_max
*sizeof(scene_vert
)),
164 new_indice_len
= world
->scene_geo
.indice_count
*sizeof(u32
);
166 u32
*src_indices
= world
->scene_geo
.arrindices
,
167 *dst_indices
= (u32
*)(buffer
+ new_vert_size
);
169 memmove( dst_indices
, src_indices
, new_indice_len
);
171 world
->scene_geo
.max_indices
= world
->scene_geo
.indice_count
;
172 world
->scene_geo
.max_vertices
= world
->scene_geo
.vertex_count
;
173 buf_size
= scene_mem_required( &world
->scene_geo
);
175 buffer
= vg_linear_resize( world
->heap
, buffer
, buf_size
);
177 world
->scene_geo
.arrvertices
= (scene_vert
*)(buffer
);
178 world
->scene_geo
.arrindices
= (u32
*)(buffer
+ new_vert_size
);
180 scene_upload_async( &world
->scene_geo
, &world
->mesh_geo
);
182 /* need send off the memory to the gpu before we can create the bvh. */
184 vg_info( "creating bvh\n" );
186 /* setup spacial mapping and rigidbody */
187 world
->geo_bh
= scene_bh_create( world
->heap
, &world
->scene_geo
);
189 v3_zero( world
->rb_geo
.rb
.co
);
190 v3_zero( world
->rb_geo
.rb
.v
);
191 q_identity( world
->rb_geo
.rb
.q
);
192 v3_zero( world
->rb_geo
.rb
.w
);
194 world
->rb_geo
.type
= k_rb_shape_scene
;
195 world
->rb_geo
.inf
.scene
.bh_scene
= world
->geo_bh
;
196 rb_init_object( &world
->rb_geo
);
199 * Generate scene: non-collidable geometry
200 * ----------------------------------------------------------------
202 vg_info( "Generating non-collidable geometry\n" );
204 vg_async_item
*call
= scene_alloc_async( &world
->scene_no_collide
,
205 &world
->mesh_no_collide
,
208 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
209 struct world_surface
*surf
= &world
->surfaces
[ i
];
211 if( !(surf
->info
.flags
& k_material_flag_collision
) ){
212 world_add_all_if_material( midentity
,
213 &world
->scene_no_collide
, &world
->meta
, i
);
216 if( surf
->info
.flags
& k_material_flag_grow_grass
)
217 world_apply_procedural_foliage( world
,
218 &world
->scene_no_collide
, surf
);
220 scene_copy_slice( &world
->scene_no_collide
, &surf
->sm_no_collide
);
223 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_traffic
); i
++ ){
224 ent_traffic
*vehc
= mdl_arritm( &world
->ent_traffic
, i
);
226 for( u32 j
=0; j
<vehc
->submesh_count
; j
++ ){
227 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
228 vehc
->submesh_start
+j
);
230 if( sm
->flags
& k_submesh_flag_consumed
){
235 m4x3_identity( identity
);
236 scene_add_mdl_submesh( &world
->scene_no_collide
,
237 &world
->meta
, sm
, identity
);
239 scene_copy_slice( &world
->scene_no_collide
, sm
);
240 sm
->flags
|= k_submesh_flag_consumed
;
244 vg_async_dispatch( call
, async_scene_upload
);
247 float fsd_cone_infinite( v3f p
, v2f c
)
249 v2f q
= { v2_length( (v2f
){ p
[0], p
[2] } ), -p
[1] };
250 float s
= vg_maxf( 0.0f
, v2_dot( q
, c
) );
256 float d
= v2_length( v0
);
257 return d
* ((q
[0]*c
[1]-q
[1]*c
[0]<0.0f
)?-1.0f
:1.0f
);
260 struct light_indices_upload_info
{
261 world_instance
*world
;
267 VG_STATIC
void async_upload_light_indices( void *payload
, u32 size
)
269 struct light_indices_upload_info
*info
= payload
;
271 glGenTextures( 1, &info
->world
->tex_light_cubes
);
272 glBindTexture( GL_TEXTURE_3D
, info
->world
->tex_light_cubes
);
273 glTexImage3D( GL_TEXTURE_3D
, 0, GL_RG32UI
,
274 info
->count
[0], info
->count
[1], info
->count
[2],
275 0, GL_RG_INTEGER
, GL_UNSIGNED_INT
, info
->data
);
276 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
277 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
280 VG_STATIC
void world_compute_light_indices( world_instance
*world
)
283 v3f cubes_min
, cubes_max
;
284 v3_muls( world
->scene_geo
.bbx
[0], 1.0f
/k_light_cube_size
, cubes_min
);
285 v3_muls( world
->scene_geo
.bbx
[1], 1.0f
/k_light_cube_size
, cubes_max
);
287 v3_sub( cubes_min
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_min
);
288 v3_add( cubes_max
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_max
);
290 v3_floor( cubes_min
, cubes_min
);
291 v3_floor( cubes_max
, cubes_max
);
293 v3i icubes_min
, icubes_max
;
295 for( int i
=0; i
<3; i
++ ){
296 icubes_min
[i
] = cubes_min
[i
];
297 icubes_max
[i
] = cubes_max
[i
];
303 v3i_sub( icubes_max
, icubes_min
, icubes_count
);
305 for( int i
=0; i
<3; i
++ ){
306 int clamped_count
= VG_MIN( 128, icubes_count
[i
]+1 );
307 float clamped_max
= icubes_min
[i
] + clamped_count
,
308 max
= icubes_min
[i
] + icubes_count
[i
]+1;
310 icubes_count
[i
] = clamped_count
;
311 cube_size
[i
] = (max
/ clamped_max
) * k_light_cube_size
;
312 cubes_max
[i
] = clamped_max
;
315 v3_mul( cubes_min
, cube_size
, cubes_min
);
316 v3_mul( cubes_max
, cube_size
, cubes_max
);
318 for( int i
=0; i
<3; i
++ ){
319 float range
= cubes_max
[i
]-cubes_min
[i
];
320 world
->ub_lighting
.g_cube_inv_range
[i
] = 1.0f
/ range
;
321 world
->ub_lighting
.g_cube_inv_range
[i
] *= (float)icubes_count
[i
];
323 vg_info( "cubes[%d]: %d\n", i
, icubes_count
[i
] );
326 int total_cubes
= icubes_count
[0]*icubes_count
[1]*icubes_count
[2];
328 u32 data_size
= vg_align8(total_cubes
*sizeof(u32
)*2),
329 hdr_size
= vg_align8(sizeof(struct light_indices_upload_info
));
331 vg_async_item
*call
= vg_async_alloc( data_size
+ hdr_size
);
332 struct light_indices_upload_info
*info
= call
->payload
;
333 info
->data
= ((u8
*)call
->payload
) + hdr_size
;
335 u32
*cubes_index
= info
->data
;
337 for( int i
=0; i
<3; i
++ )
338 info
->count
[i
] = icubes_count
[i
];
340 vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n",
341 total_cubes
, cubes_min
[0], -cubes_min
[2], cubes_min
[1],
342 cubes_max
[0], -cubes_max
[2], cubes_max
[1] );
343 v3_copy( cubes_min
, world
->ub_lighting
.g_cube_min
);
345 float bound_radius
= v3_length( cube_size
);
347 for( int iz
= 0; iz
<icubes_count
[2]; iz
++ ){
348 for( int iy
= 0; iy
<icubes_count
[1]; iy
++ ){
349 for( int ix
= 0; ix
<icubes_count
[0]; ix
++ ){
351 v3_div( (v3f
){ ix
, iy
, iz
}, world
->ub_lighting
.g_cube_inv_range
,
353 v3_div( (v3f
){ ix
+1, iy
+1, iz
+1 },
354 world
->ub_lighting
.g_cube_inv_range
,
357 v3_add( bbx
[0], world
->ub_lighting
.g_cube_min
, bbx
[0] );
358 v3_add( bbx
[1], world
->ub_lighting
.g_cube_min
, bbx
[1] );
361 v3_add( bbx
[0], bbx
[1], center
);
362 v3_muls( center
, 0.5f
, center
);
364 u32 indices
[6] = { 0, 0, 0, 0, 0, 0 };
367 float influences
[6] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
368 const int N
= vg_list_size( influences
);
370 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
371 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
373 closest_point_aabb( light
->transform
.co
, bbx
, closest
);
375 float dist
= v3_dist( closest
, light
->transform
.co
),
376 influence
= 1.0f
/(dist
+1.0f
);
378 if( dist
> light
->range
)
381 if( light
->type
== k_light_type_spot
){
383 m4x3_mulv( light
->inverse_world
, center
, local
);
385 float r
= fsd_cone_infinite( local
, light
->angle_sin_cos
);
387 if( r
> bound_radius
)
392 for( int k
=best_pos
-1; k
>=0; k
-- )
393 if( influence
> influences
[k
] )
397 for( int k
=N
-1; k
>best_pos
; k
-- ){
398 influences
[k
] = influences
[k
-1];
399 indices
[k
] = indices
[k
-1];
402 influences
[best_pos
] = influence
;
403 indices
[best_pos
] = j
;
407 for( int j
=0; j
<N
; j
++ )
408 if( influences
[j
] > 0.0f
)
411 int base_index
= iz
* (icubes_count
[0]*icubes_count
[1]) +
412 iy
* (icubes_count
[0]) +
415 int lower_count
= VG_MIN( 3, count
);
416 u32 packed_index_lower
= lower_count
;
417 packed_index_lower
|= indices
[0]<<2;
418 packed_index_lower
|= indices
[1]<<12;
419 packed_index_lower
|= indices
[2]<<22;
421 int upper_count
= VG_MAX( 0, count
- lower_count
);
422 u32 packed_index_upper
= upper_count
;
423 packed_index_upper
|= indices
[3]<<2;
424 packed_index_upper
|= indices
[4]<<12;
425 packed_index_upper
|= indices
[5]<<22;
427 cubes_index
[ base_index
*2 + 0 ] = packed_index_lower
;
428 cubes_index
[ base_index
*2 + 1 ] = packed_index_upper
;
433 vg_async_dispatch( call
, async_upload_light_indices
);
436 VG_STATIC
void async_world_postprocess_render( void *payload
, u32 _size
)
438 /* create scene lighting buffer */
439 world_instance
*world
= payload
;
441 u32 size
= VG_MAX(mdl_arrcount(&world
->ent_light
),1) * sizeof(float)*12;
442 vg_info( "Upload %ubytes (lighting)\n", size
);
444 glGenBuffers( 1, &world
->tbo_light_entities
);
445 glBindBuffer( GL_TEXTURE_BUFFER
, world
->tbo_light_entities
);
446 glBufferData( GL_TEXTURE_BUFFER
, size
, NULL
, GL_DYNAMIC_DRAW
);
450 * colour position direction (spots)
451 * | . . . . | . . . . | . . . . |
452 * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da |
456 v4f
*light_dst
= glMapBuffer( GL_TEXTURE_BUFFER
, GL_WRITE_ONLY
);
457 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_light
); i
++ ){
458 ent_light
*light
= mdl_arritm( &world
->ent_light
, i
);
461 v3_muls( light
->colour
, light
->colour
[3] * 2.0f
, light_dst
[i
*3+0] );
462 light_dst
[i
*3+0][3] = 2.0f
;
464 if( !light
->daytime
){
465 u32 hash
= (i
* 29986577u) & 0xffu
;
466 float switch_on
= hash
;
467 switch_on
*= (1.0f
/255.0f
);
469 light_dst
[i
*3+0][3] = 0.44f
+ switch_on
* 0.015f
;
472 /* position + 1/range^2 */
473 v3_copy( light
->transform
.co
, light_dst
[i
*3+1] );
474 light_dst
[i
*3+1][3] = 1.0f
/(light
->range
*light
->range
);
476 /* direction + angle */
477 q_mulv( light
->transform
.q
, (v3f
){0.0f
,-1.0f
,0.0f
}, light_dst
[i
*3+2]);
478 light_dst
[i
*3+2][3] = cosf( light
->angle
);
481 glUnmapBuffer( GL_TEXTURE_BUFFER
);
483 glGenTextures( 1, &world
->tex_light_entities
);
484 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
485 glTexBuffer( GL_TEXTURE_BUFFER
, GL_RGBA32F
, world
->tbo_light_entities
);
487 /* Upload lighting uniform buffer */
488 if( world
->water
.enabled
)
489 v4_copy( world
->water
.plane
, world
->ub_lighting
.g_water_plane
);
492 v3f
*bounds
= world
->scene_geo
.bbx
;
494 info_vec
[0] = bounds
[0][0];
495 info_vec
[1] = bounds
[0][2];
496 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
497 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
498 v4_copy( info_vec
, world
->ub_lighting
.g_depth_bounds
);
501 * Rendering the depth map
506 v3_sub( world
->scene_geo
.bbx
[1], world
->scene_geo
.bbx
[0], extent
);
508 float fl
= world
->scene_geo
.bbx
[0][0],
509 fr
= world
->scene_geo
.bbx
[1][0],
510 fb
= world
->scene_geo
.bbx
[0][2],
511 ft
= world
->scene_geo
.bbx
[1][2],
515 m4x4_zero( ortho
.mtx
.p
);
516 ortho
.mtx
.p
[0][0] = 2.0f
* rl
;
517 ortho
.mtx
.p
[2][1] = 2.0f
* tb
;
518 ortho
.mtx
.p
[3][0] = (fr
+ fl
) * -rl
;
519 ortho
.mtx
.p
[3][1] = (ft
+ fb
) * -tb
;
520 ortho
.mtx
.p
[3][3] = 1.0f
;
521 m4x3_identity( ortho
.transform
);
522 camera_update_view( &ortho
);
523 camera_finalize( &ortho
);
525 glDisable(GL_DEPTH_TEST
);
527 glDisable(GL_CULL_FACE
);
528 render_fb_bind( &world
->heightmap
, 0 );
529 shader_blitcolour_use();
530 shader_blitcolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
534 glBlendFunc(GL_ONE
, GL_ONE
);
535 glBlendEquation(GL_MAX
);
537 render_world_position( world
, &ortho
);
539 glEnable(GL_DEPTH_TEST
);
540 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
542 /* upload full buffer */
543 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
544 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
545 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
548 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
549 VG_STATIC
void world_post_process( world_instance
*world
)
551 world_compute_light_indices( world
);
552 vg_async_call( async_world_postprocess_render
, world
, 0 );
555 VG_STATIC
void world_process_resources( world_instance
*world
)
557 vg_info( "Loading textures\n" );
559 world
->texture_count
= 0;
561 world
->texture_count
= world
->meta
.textures
.count
+1;
562 world
->textures
= vg_linear_alloc( world
->heap
,
563 vg_align8(sizeof(GLuint
)*world
->texture_count
) );
565 vg_tex2d_replace_with_error( &world
->textures
[0] );
567 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.textures
); i
++ ){
568 mdl_texture
*tex
= mdl_arritm( &world
->meta
.textures
, i
);
570 if( !tex
->file
.pack_size
){
571 vg_fatal_error( "World models must have packed textures!" );
574 vg_linear_clear( vg_mem
.scratch
);
575 void *src_data
= vg_linear_alloc( vg_mem
.scratch
,
576 tex
->file
.pack_size
);
577 mdl_fread_pack_file( &world
->meta
, &tex
->file
, src_data
);
579 vg_tex2d_load_qoi_async( src_data
, tex
->file
.pack_size
,
580 VG_TEX2D_NEAREST
|VG_TEX2D_REPEAT
,
581 &world
->textures
[i
+1] );
584 vg_info( "Loading materials\n" );
586 world
->surface_count
= world
->meta
.materials
.count
+1;
587 world
->surfaces
= vg_linear_alloc( world
->heap
,
588 vg_align8(sizeof(struct world_surface
)*world
->surface_count
) );
591 struct world_surface
*errmat
= &world
->surfaces
[0];
592 memset( errmat
, 0, sizeof(struct world_surface
) );
594 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.materials
); i
++ ){
595 world
->surfaces
[i
+1].info
=
596 *(mdl_material
*)mdl_arritm( &world
->meta
.materials
, i
);
600 VG_STATIC
void world_free( world_instance
*world
)
602 vg_info( "Free world @%p\n", world
);
605 mesh_free( &world
->mesh_route_lines
);
606 mesh_free( &world
->mesh_geo
);
607 mesh_free( &world
->mesh_no_collide
);
608 mesh_free( &world
->mesh_water
);
610 /* glDeleteBuffers silently ignores 0's and names that do not correspond to
611 * existing buffer objects.
613 glDeleteBuffers( 1, &world
->tbo_light_entities
);
614 glDeleteTextures( 1, &world
->tex_light_entities
);
615 glDeleteTextures( 1, &world
->tex_light_cubes
);
617 /* delete textures and meshes */
618 glDeleteTextures( world
->texture_count
, world
->textures
);
620 u32 world_index
= world
- world_global
.worlds
;
622 vg_linear_del( world_global
.worlds
[world_index
-1].heap
,
623 vg_linear_header(world
->heap
) );
626 world
->status
= k_world_status_unloaded
;
631 * 1. to see if all audios owned by the world have been stopped
632 * 2. that this is the least significant world
634 VG_STATIC
int world_freeable( world_instance
*world
)
636 if( world
->status
!= k_world_status_unloading
) return 0;
637 u8 world_id
= (world
- world_global
.worlds
) + 1;
639 for( u32 i
=world_id
; i
<vg_list_size(world_global
.worlds
); i
++ ){
640 if( world_global
.worlds
[i
].status
!= k_world_status_unloaded
){
647 for( u32 i
=0; i
<AUDIO_CHANNELS
; i
++ ){
648 audio_channel
*ch
= &vg_audio
.channels
[i
];
650 if( ch
->allocated
&& (ch
->world_id
== world_id
)){
651 if( !audio_channel_finished( ch
) ){
661 VG_STATIC
void world_init_blank( world_instance
*world
)
663 memset( &world
->meta
, 0, sizeof(mdl_context
) );
665 world
->textures
= NULL
;
666 world
->texture_count
= 0;
667 world
->surfaces
= NULL
;
668 world
->surface_count
= 0;
670 world
->geo_bh
= NULL
;
671 world
->volume_bh
= NULL
;
672 world
->audio_bh
= NULL
;
673 world
->rendering_gate
= NULL
;
675 world
->water
.enabled
= 0;
678 /* default lighting conditions
679 * -------------------------------------------------------------*/
680 struct ub_world_lighting
*state
= &world
->ub_lighting
;
682 state
->g_light_preview
= 0;
683 state
->g_shadow_samples
= 8;
684 state
->g_water_fog
= 0.04f
;
686 v4_zero( state
->g_water_plane
);
687 v4_zero( state
->g_depth_bounds
);
689 state
->g_shadow_length
= 9.50f
;
690 state
->g_shadow_spread
= 0.65f
;
692 v3_copy( (v3f
){0.37f
, 0.54f
, 0.97f
}, state
->g_daysky_colour
);
693 v3_copy( (v3f
){0.03f
, 0.05f
, 0.20f
}, state
->g_nightsky_colour
);
694 v3_copy( (v3f
){1.00f
, 0.32f
, 0.01f
}, state
->g_sunset_colour
);
695 v3_copy( (v3f
){0.13f
, 0.17f
, 0.35f
}, state
->g_ambient_colour
);
696 v3_copy( (v3f
){0.25f
, 0.17f
, 0.51f
}, state
->g_sunset_ambient
);
697 v3_copy( (v3f
){1.10f
, 0.89f
, 0.35f
}, state
->g_sun_colour
);
700 /* detatches any nonlocal gates */
701 VG_STATIC
void world_unlink_nonlocal( world_instance
*world
)
703 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
704 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
706 if( gate
->type
== k_gate_type_nonlocel
){
707 gate
->type
= k_gate_type_nonlocal_unlinked
;
712 /* attatches nonlocal gates, to be called from main thread ONLY! */
713 VG_STATIC
void world_link_nonlocal_async( void *payload
, u32 size
)
715 world_instance
*world
= payload
;
716 u32 world_id
= world
- world_global
.worlds
;
718 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
719 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
721 if( gate
->type
== k_gate_type_nonlocal_unlinked
){
722 const char *key
= mdl_pstr( &world
->meta
, gate
->key
);
723 vg_info( "key: %s\n", key
);
725 for( u32 i
=0; i
<vg_list_size(world_global
.worlds
); i
++ ){
726 world_instance
*other
= &world_global
.worlds
[i
];
727 if( other
== world
) continue;
728 if( other
->status
!= k_world_status_loaded
) continue;
729 vg_info( "Checking world %u for key matches\n", i
);
731 for( u32 j
=0; j
<mdl_arrcount( &other
->ent_gate
); j
++ ){
732 ent_gate
*gate2
= mdl_arritm( &other
->ent_gate
, j
);
733 if( gate2
->type
!= k_gate_type_nonlocal_unlinked
) continue;
735 const char *key2
= mdl_pstr( &other
->meta
, gate2
->key
);
736 vg_info( " key2: %s\n", key2
);
738 if( strcmp( key
, key2
) ) continue;
740 vg_success( "Non-local matching pair '%s' found. (%u:%u)\n",
743 gate
->type
= k_gate_type_nonlocel
;
744 gate2
->type
= k_gate_type_nonlocel
;
746 gate2
->target
= world_id
;
748 v3_copy( gate
->co
[0], gate2
->co
[1] );
749 v3_copy( gate2
->co
[0], gate
->co
[1] );
750 v4_copy( gate
->q
[0], gate2
->q
[1] );
751 v4_copy( gate2
->q
[0], gate
->q
[1] );
754 q_axis_angle( qflip
, (v3f
){0.0f
,1.0f
,0.0f
}, VG_PIf
);
755 q_mul( gate
->q
[0], qflip
, gate
->q
[0] );
756 q_mul( gate
->q
[1], qflip
, gate
->q
[1] );
758 gate_transform_update( gate
);
759 gate_transform_update( gate2
);
769 VG_STATIC
void world_entities_init( u32 world_id
)
771 world_instance
*world
= &world_global
.worlds
[world_id
];
774 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
775 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
778 q_m3x3( light
->transform
.q
, to_world
);
779 v3_copy( light
->transform
.co
, to_world
[3] );
780 m4x3_invert_affine( to_world
, light
->inverse_world
);
782 light
->angle_sin_cos
[0] = sinf( light
->angle
* 0.5f
);
783 light
->angle_sin_cos
[1] = cosf( light
->angle
* 0.5f
);
787 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
788 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
790 if( gate
->type
== k_gate_type_teleport
){
791 gate_transform_update( gate
);
794 vg_async_call( world_link_nonlocal_async
, world
, 0 );
797 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_water
); j
++ ){
798 ent_water
*water
= mdl_arritm( &world
->ent_water
, j
);
799 if( world
->water
.enabled
){
800 vg_warn( "Multiple water surfaces in level!\n" );
804 world
->water
.enabled
= 1;
805 water_set_surface( world
, water
->transform
.co
[1] );
809 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_volume
); j
++ ){
810 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, j
);
811 mdl_transform_m4x3( &volume
->transform
, volume
->to_world
);
812 m4x3_invert_full( volume
->to_world
, volume
->to_local
);
816 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_audio
); j
++ ){
817 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, j
);
819 for( u32 k
=0; k
<audio
->clip_count
; k
++ ){
820 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
821 audio
->clip_start
+k
);
823 if( clip
->file
.pack_size
){
824 u32 size
= clip
->file
.pack_size
,
825 offset
= clip
->file
.pack_offset
;
827 /* embedded files are fine to clear the scratch buffer, only
828 * external audio uses it */
830 vg_linear_clear( vg_mem
.scratch
);
831 void *data
= vg_linear_alloc( vg_mem
.scratch
,
832 clip
->file
.pack_size
);
834 mdl_fread_pack_file( &world
->meta
, &clip
->file
, data
);
836 clip
->clip
.path
= NULL
;
837 clip
->clip
.flags
= audio
->flags
;
838 clip
->clip
.data
= data
;
839 clip
->clip
.size
= size
;
842 clip
->clip
.path
= mdl_pstr( &world
->meta
, clip
->file
.pstr_path
);
843 clip
->clip
.flags
= audio
->flags
;
844 clip
->clip
.data
= NULL
;
848 audio_clip_load( &clip
->clip
, world
->heap
);
853 VG_STATIC
void world_load( u32 index
, const char *path
)
855 vg_rand_seed( 9001 );
857 world_instance
*world
= &world_global
.worlds
[index
];
858 world_init_blank( world
);
859 world
->status
= k_world_status_loading
;
861 vg_info( "Loading world: %s\n", path
);
863 void *allocator
= NULL
;
864 if( index
== 0 ) allocator
= world_global
.heap
;
865 else allocator
= world_global
.worlds
[index
-1].heap
;
867 u32 heap_availible
= vg_linear_remaining( allocator
);
868 u32 min_overhead
= sizeof(vg_linear_allocator
);
870 if( heap_availible
< (min_overhead
+1024) ){
871 vg_fatal_error( "out of memory" );
874 u32 size
= heap_availible
- min_overhead
;
875 void *heap
= vg_create_linear_allocator( allocator
, size
, VG_MEMORY_SYSTEM
);
878 mdl_context
*meta
= &world
->meta
;
880 mdl_open( meta
, path
, world
->heap
);
881 mdl_load_metadata_block( meta
, world
->heap
);
882 mdl_load_animation_block( meta
, world
->heap
);
883 mdl_load_mesh_block( meta
, world
->heap
);
885 mdl_load_array( meta
, &world
->ent_gate
, "ent_gate", heap
);
886 mdl_load_array( meta
, &world
->ent_camera
, "ent_camera", heap
);
887 mdl_load_array( meta
, &world
->ent_spawn
, "ent_spawn", heap
);
888 mdl_load_array( meta
, &world
->ent_light
, "ent_light", heap
);
889 mdl_load_array( meta
, &world
->ent_route_node
,"ent_route_node", heap
);
890 mdl_load_array( meta
, &world
->ent_path_index
,"ent_path_index", heap
);
891 mdl_load_array( meta
, &world
->ent_checkpoint
,"ent_checkpoint", heap
);
892 mdl_load_array( meta
, &world
->ent_route
, "ent_route", heap
);
893 mdl_load_array( meta
, &world
->ent_water
, "ent_water", heap
);
894 mdl_load_array( meta
, &world
->ent_audio_clip
,"ent_audio_clip", heap
);
895 mdl_load_array( meta
, &world
->ent_audio
, "ent_audio", heap
);
896 mdl_load_array( meta
, &world
->ent_volume
, "ent_volume", heap
);
897 mdl_load_array( meta
, &world
->ent_traffic
, "ent_traffic", heap
);
898 mdl_load_array( meta
, &world
->ent_marker
, "ent_marker", heap
);
899 mdl_load_array( meta
, &world
->ent_skateshop
, "ent_skateshop", heap
);
900 mdl_load_array( meta
, &world
->ent_swspreview
,"ent_swspreview", heap
);
903 mdl_load_array( meta
, &infos
, "ent_worldinfo", vg_mem
.scratch
);
905 if( mdl_arrcount(&infos
) ){
906 world
->info
= *((ent_worldinfo
*)mdl_arritm(&infos
,0));
909 world
->info
.pstr_author
= 0;
910 world
->info
.pstr_desc
= 0;
911 world
->info
.pstr_name
= 0;
912 world
->info
.timezone
= 0.0f
;
919 world
->time
= (float)tm
->tm_min
/20.0f
+ (world
->info
.timezone
/24.0f
);
921 /* process resources from pack */
922 world_process_resources( world
);
924 world_routes_ent_init( world
);
925 world_entities_init( index
);
926 world
->volume_bh
= bh_create( heap
, &bh_system_volumes
, world
,
927 mdl_arrcount( &world
->ent_volume
), 1 );
930 world_generate( world
);
931 world_routes_generate( world
);
932 world_post_process( world
);
935 world
->status
= k_world_status_loaded
;
938 #endif /* WORLD_GEN_H */