2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
4 * World generation/population. Different to regular loading, since it needs to
5 * create geometry, apply procedural stuff and save that image to files etc.
12 #include "world_gen.h"
13 #include "world_load.h"
14 #include "world_volumes.h"
15 #include "world_gate.h"
18 * Add all triangles from the model, which match the material ID
19 * applies affine transform to the model
21 static void world_add_all_if_material( m4x3f transform
, scene_context
*scene
,
22 mdl_context
*mdl
, u32 id
)
24 for( u32 i
=0; i
<mdl_arrcount(&mdl
->meshs
); i
++ ){
25 mdl_mesh
*mesh
= mdl_arritm( &mdl
->meshs
, i
);
27 for( u32 j
=0; j
<mesh
->submesh_count
; j
++ ){
28 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, mesh
->submesh_start
+j
);
29 if( sm
->material_id
== id
){
31 mdl_transform_m4x3( &mesh
->transform
, transform2
);
32 m4x3_mul( transform
, transform2
, transform2
);
34 scene_add_mdl_submesh( scene
, mdl
, sm
, transform2
);
41 * Adds a small blob shape to the world at a raycast location. This is for the
49 static void world_gen_add_blob( vg_rand
*rand
, world_instance
*world
,
50 scene_context
*scene
, ray_hit
*hit
)
53 v4f qsurface
, qrandom
;
56 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
->normal
, axis
);
58 float angle
= v3_dot(hit
->normal
,(v3f
){0.0f
,1.0f
,0.0f
});
59 q_axis_angle( qsurface
, axis
, angle
);
60 q_axis_angle( qrandom
, (v3f
){0.0f
,1.0f
,0.0f
}, vg_randf64(rand
)*VG_TAUf
);
61 q_mul( qsurface
, qrandom
, qsurface
);
62 q_m3x3( qsurface
, transform
);
63 v3_copy( hit
->pos
, transform
[3] );
67 { .co
= { -1.00f
, 0.0f
, 0.0f
} },
68 { .co
= { 1.00f
, 0.0f
, 0.0f
} },
69 { .co
= { -1.00f
, 1.2f
, 0.0f
} },
70 { .co
= { 1.00f
, 1.2f
, 0.0f
} },
71 { .co
= { -0.25f
, 2.0f
, 0.0f
} },
72 { .co
= { 0.25f
, 2.0f
, 0.0f
} }
75 const u32 indices
[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 };
77 if( scene
->vertex_count
+ vg_list_size(verts
) > scene
->max_vertices
)
78 vg_fatal_error( "Scene vertex buffer overflow" );
80 if( scene
->indice_count
+ vg_list_size(indices
) > scene
->max_indices
)
81 vg_fatal_error( "Scene index buffer overflow" );
83 scene_vert
*dst_verts
= &scene
->arrvertices
[ scene
->vertex_count
];
84 u32
*dst_indices
= &scene
->arrindices
[ scene
->indice_count
];
86 scene_vert
*ref
= &world
->scene_geo
.arrvertices
[ hit
->tri
[0] ];
88 for( u32 i
=0; i
<vg_list_size(verts
); i
++ ){
89 scene_vert
*pvert
= &dst_verts
[ i
],
92 m4x3_mulv( transform
, src
->co
, pvert
->co
);
93 scene_vert_pack_norm( pvert
, transform
[1], 0.0f
);
95 v2_copy( ref
->uv
, pvert
->uv
);
98 for( u32 i
=0; i
<vg_list_size(indices
); i
++ )
99 dst_indices
[i
] = indices
[i
] + scene
->vertex_count
;
101 scene
->vertex_count
+= vg_list_size(verts
);
102 scene
->indice_count
+= vg_list_size(indices
);
106 * Sprinkle foliage models over the map on terrain material
108 static void world_apply_procedural_foliage( world_instance
*world
,
109 scene_context
*scene
,
110 struct world_surface
*mat
)
112 if( vg
.quality_profile
== k_quality_profile_low
)
115 vg_info( "Applying foliage (%u)\n", mat
->info
.pstr_name
);
118 v3_sub( world
->scene_geo
.bbx
[1], world
->scene_geo
.bbx
[0], volume
);
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 u64 t0
= SDL_GetPerformanceCounter();
130 for( u32 i
=0; i
<particles
; i
++ ){
132 v3_mul( volume
, (v3f
){ vg_randf64(), 1000.0f
, vg_randf64() }, pos
);
134 v3_add( pos
, world
->scene_geo
.bbx
[0], pos
);
139 if( ray_world( world
, pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
,
140 k_material_flag_ghosts
)){
141 struct world_surface
*m1
= ray_hit_surface( world
, &hit
);
142 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) && (hit
.pos
[1] > 0.0f
+10.0f
)){
143 world_gen_add_blob( world
, scene
, &hit
);
151 vg_rand_seed( &rand
, 3030 );
153 const f32 tile_scale
= 16.0f
;
154 v2i tiles
= { volume
[0]/tile_scale
, volume
[2]/tile_scale
};
156 u32 per_tile
= particles
/(tiles
[0]*tiles
[1]);
158 for( i32 x
=0; x
<tiles
[0]; x
++ ){
159 for( i32 z
=0; z
<tiles
[1]; z
++ ){
160 for( u32 i
=0; i
<per_tile
; i
++ ){
161 v3f co
= { (f32
)x
+vg_randf64(&rand
), 0, (f32
)z
+vg_randf64(&rand
) };
162 v3_muls( co
, tile_scale
, co
);
164 v3_add( co
, world
->scene_geo
.bbx
[0], co
);
169 if( ray_world( world
, co
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
,
170 k_material_flag_ghosts
)){
171 struct world_surface
*m1
= ray_hit_surface( world
, &hit
);
172 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) &&
173 (hit
.pos
[1] > 0.0f
+10.0f
)){
174 world_gen_add_blob( &rand
, world
, scene
, &hit
);
187 u64 t1
= SDL_GetPerformanceCounter(),
189 ufreq
= SDL_GetPerformanceFrequency();
190 f64 ftime_blobs
= ((f64
)utime_blobs
/ (f64
)ufreq
)*1000.0;
192 vg_info( "%d foliage models added. %f%% (%fms)\n", count
,
193 100.0*((f64
)count
/(f64
)particles
), ftime_blobs
);
197 void world_unpack_submesh_dynamic( world_instance
*world
,
198 scene_context
*scene
, mdl_submesh
*sm
){
199 if( sm
->flags
& k_submesh_flag_consumed
) return;
202 m4x3_identity( identity
);
203 scene_add_mdl_submesh( scene
, &world
->meta
, sm
, identity
);
205 scene_copy_slice( scene
, sm
);
206 sm
->flags
|= k_submesh_flag_consumed
;
210 * Create the main meshes for the world
212 static void world_gen_generate_meshes( world_instance
*world
){
214 * Compile meshes into the world scenes
216 scene_init( &world
->scene_geo
, 320000, 1200000 );
217 u32 buf_size
= scene_mem_required( &world
->scene_geo
);
218 u8
*buffer
= vg_linear_alloc( world
->heap
, buf_size
);
219 scene_supply_buffer( &world
->scene_geo
, buffer
);
222 m4x3_identity( midentity
);
225 * Generate scene: collidable geometry
226 * ----------------------------------------------------------------
229 vg_info( "Generating collidable geometry\n" );
231 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
232 struct world_surface
*surf
= &world
->surfaces
[ i
];
234 if( surf
->info
.flags
& k_material_flag_collision
)
235 world_add_all_if_material( midentity
, &world
->scene_geo
,
238 scene_copy_slice( &world
->scene_geo
, &surf
->sm_geo
);
239 scene_set_vertex_flags( &world
->scene_geo
,
240 surf
->sm_geo
.vertex_start
,
241 surf
->sm_geo
.vertex_count
,
242 (u16
)(surf
->info
.flags
& 0xffff) );
245 /* compress that bad boy */
246 u32 new_vert_max
= world
->scene_geo
.vertex_count
,
247 new_vert_size
= vg_align8(new_vert_max
*sizeof(scene_vert
)),
248 new_indice_len
= world
->scene_geo
.indice_count
*sizeof(u32
);
250 u32
*src_indices
= world
->scene_geo
.arrindices
,
251 *dst_indices
= (u32
*)(buffer
+ new_vert_size
);
253 memmove( dst_indices
, src_indices
, new_indice_len
);
255 world
->scene_geo
.max_indices
= world
->scene_geo
.indice_count
;
256 world
->scene_geo
.max_vertices
= world
->scene_geo
.vertex_count
;
257 buf_size
= scene_mem_required( &world
->scene_geo
);
259 buffer
= vg_linear_resize( world
->heap
, buffer
, buf_size
);
261 world
->scene_geo
.arrvertices
= (scene_vert
*)(buffer
);
262 world
->scene_geo
.arrindices
= (u32
*)(buffer
+ new_vert_size
);
264 scene_upload_async( &world
->scene_geo
, &world
->mesh_geo
);
266 /* need send off the memory to the gpu before we can create the bvh. */
268 vg_info( "creating bvh\n" );
270 /* setup spacial mapping and rigidbody */
271 world
->geo_bh
= scene_bh_create( world
->heap
, &world
->scene_geo
);
273 v3_zero( world
->rb_geo
.rb
.co
);
274 v3_zero( world
->rb_geo
.rb
.v
);
275 q_identity( world
->rb_geo
.rb
.q
);
276 v3_zero( world
->rb_geo
.rb
.w
);
278 world
->rb_geo
.type
= k_rb_shape_scene
;
279 world
->rb_geo
.inf
.scene
.bh_scene
= world
->geo_bh
;
280 rb_init_object( &world
->rb_geo
, 0.0f
);
283 * Generate scene: non-collidable geometry
284 * ----------------------------------------------------------------
286 vg_info( "Generating non-collidable geometry\n" );
288 vg_async_item
*call
= scene_alloc_async( &world
->scene_no_collide
,
289 &world
->mesh_no_collide
,
292 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
293 struct world_surface
*surf
= &world
->surfaces
[ i
];
295 if( !(surf
->info
.flags
& k_material_flag_collision
) ){
296 world_add_all_if_material( midentity
,
297 &world
->scene_no_collide
, &world
->meta
, i
);
300 if( surf
->info
.flags
& k_material_flag_grow_grass
){
301 world_apply_procedural_foliage( world
, &world
->scene_no_collide
,
305 scene_copy_slice( &world
->scene_no_collide
, &surf
->sm_no_collide
);
308 /* unpack traffic models.. TODO: should we just put all these submeshes in a
309 * dynamic models list? and then the actual entitities point to the
310 * models. we only have 2 types at the moment which need dynamic models but
311 * would make sense to do this when/if we have more.
313 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_traffic
); i
++ ){
314 ent_traffic
*vehc
= mdl_arritm( &world
->ent_traffic
, i
);
316 for( u32 j
=0; j
<vehc
->submesh_count
; j
++ ){
317 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
318 vehc
->submesh_start
+j
);
319 world_unpack_submesh_dynamic( world
, &world
->scene_no_collide
, sm
);
320 world
->surfaces
[ sm
->material_id
].flags
|= WORLD_SURFACE_HAS_TRAFFIC
;
324 /* unpack challenge models */
325 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_objective
); i
++ ){
326 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, i
);
328 for( u32 j
=0; j
<objective
->submesh_count
; j
++ ){
329 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
330 objective
->submesh_start
+j
);
331 world_unpack_submesh_dynamic( world
, &world
->scene_no_collide
, sm
);
335 /* unpack region models */
336 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_region
); i
++ ){
337 ent_region
*region
= mdl_arritm( &world
->ent_region
, i
);
339 for( u32 j
=0; j
<region
->submesh_count
; j
++ ){
340 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
341 region
->submesh_start
+j
);
342 world_unpack_submesh_dynamic( world
, &world
->scene_no_collide
, sm
);
346 /* unpack gate models */
347 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_gate
); i
++ ){
348 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, i
);
350 if( !(gate
->flags
& k_ent_gate_custom_mesh
) ) continue;
352 for( u32 j
=0; j
<gate
->submesh_count
; j
++ ){
353 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
354 gate
->submesh_start
+j
);
355 world_unpack_submesh_dynamic( world
, &world
->scene_no_collide
, sm
);
359 /* unpack prop models */
360 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_prop
); i
++ ){
361 ent_prop
*prop
= mdl_arritm( &world
->ent_prop
, i
);
363 for( u32 j
=0; j
<prop
->submesh_count
; j
++ ){
364 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
365 prop
->submesh_start
+j
);
366 world
->surfaces
[ sm
->material_id
].flags
|= WORLD_SURFACE_HAS_PROPS
;
367 world_unpack_submesh_dynamic( world
, &world
->scene_no_collide
, sm
);
371 vg_async_dispatch( call
, async_scene_upload
);
374 /* signed distance function for cone */
375 static f32
fsd_cone_infinite( v3f p
, v2f c
){
376 v2f q
= { v2_length( (v2f
){ p
[0], p
[2] } ), -p
[1] };
377 float s
= vg_maxf( 0.0f
, v2_dot( q
, c
) );
383 float d
= v2_length( v0
);
384 return d
* ((q
[0]*c
[1]-q
[1]*c
[0]<0.0f
)?-1.0f
:1.0f
);
387 struct light_indices_upload_info
{
388 world_instance
*world
;
395 * Async reciever to buffer light index data
397 static void async_upload_light_indices( void *payload
, u32 size
){
398 struct light_indices_upload_info
*info
= payload
;
400 glGenTextures( 1, &info
->world
->tex_light_cubes
);
401 glBindTexture( GL_TEXTURE_3D
, info
->world
->tex_light_cubes
);
402 glTexImage3D( GL_TEXTURE_3D
, 0, GL_RG32UI
,
403 info
->count
[0], info
->count
[1], info
->count
[2],
404 0, GL_RG_INTEGER
, GL_UNSIGNED_INT
, info
->data
);
405 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
406 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
410 * Computes light indices for world
412 static void world_gen_compute_light_indices( world_instance
*world
){
414 v3f cubes_min
, cubes_max
;
415 v3_muls( world
->scene_geo
.bbx
[0], 1.0f
/k_world_light_cube_size
, cubes_min
);
416 v3_muls( world
->scene_geo
.bbx
[1], 1.0f
/k_world_light_cube_size
, cubes_max
);
418 v3_sub( cubes_min
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_min
);
419 v3_add( cubes_max
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_max
);
421 v3_floor( cubes_min
, cubes_min
);
422 v3_floor( cubes_max
, cubes_max
);
424 v3i icubes_min
, icubes_max
;
426 for( int i
=0; i
<3; i
++ ){
427 icubes_min
[i
] = cubes_min
[i
];
428 icubes_max
[i
] = cubes_max
[i
];
434 v3i_sub( icubes_max
, icubes_min
, icubes_count
);
436 for( int i
=0; i
<3; i
++ ){
437 int clamped_count
= VG_MIN( 128, icubes_count
[i
]+1 );
438 float clamped_max
= icubes_min
[i
] + clamped_count
,
439 max
= icubes_min
[i
] + icubes_count
[i
]+1;
441 icubes_count
[i
] = clamped_count
;
442 cube_size
[i
] = (max
/ clamped_max
) * k_world_light_cube_size
;
443 cubes_max
[i
] = clamped_max
;
446 v3_mul( cubes_min
, cube_size
, cubes_min
);
447 v3_mul( cubes_max
, cube_size
, cubes_max
);
449 for( int i
=0; i
<3; i
++ ){
450 float range
= cubes_max
[i
]-cubes_min
[i
];
451 world
->ub_lighting
.g_cube_inv_range
[i
] = 1.0f
/ range
;
452 world
->ub_lighting
.g_cube_inv_range
[i
] *= (float)icubes_count
[i
];
454 vg_info( "cubes[%d]: %d\n", i
, icubes_count
[i
] );
457 int total_cubes
= icubes_count
[0]*icubes_count
[1]*icubes_count
[2];
459 u32 data_size
= vg_align8(total_cubes
*sizeof(u32
)*2),
460 hdr_size
= vg_align8(sizeof(struct light_indices_upload_info
));
462 vg_async_item
*call
= vg_async_alloc( data_size
+ hdr_size
);
463 struct light_indices_upload_info
*info
= call
->payload
;
464 info
->data
= ((u8
*)call
->payload
) + hdr_size
;
466 u32
*cubes_index
= info
->data
;
468 for( int i
=0; i
<3; i
++ )
469 info
->count
[i
] = icubes_count
[i
];
471 vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n",
472 total_cubes
, cubes_min
[0], -cubes_min
[2], cubes_min
[1],
473 cubes_max
[0], -cubes_max
[2], cubes_max
[1] );
474 v3_copy( cubes_min
, world
->ub_lighting
.g_cube_min
);
476 float bound_radius
= v3_length( cube_size
);
478 for( int iz
= 0; iz
<icubes_count
[2]; iz
++ ){
479 for( int iy
= 0; iy
<icubes_count
[1]; iy
++ ){
480 for( int ix
= 0; ix
<icubes_count
[0]; ix
++ ){
482 v3_div( (v3f
){ ix
, iy
, iz
}, world
->ub_lighting
.g_cube_inv_range
,
484 v3_div( (v3f
){ ix
+1, iy
+1, iz
+1 },
485 world
->ub_lighting
.g_cube_inv_range
,
488 v3_add( bbx
[0], world
->ub_lighting
.g_cube_min
, bbx
[0] );
489 v3_add( bbx
[1], world
->ub_lighting
.g_cube_min
, bbx
[1] );
492 v3_add( bbx
[0], bbx
[1], center
);
493 v3_muls( center
, 0.5f
, center
);
495 u32 indices
[6] = { 0, 0, 0, 0, 0, 0 };
498 float influences
[6] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
499 const int N
= vg_list_size( influences
);
501 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
502 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
504 closest_point_aabb( light
->transform
.co
, bbx
, closest
);
506 f32 dist2
= v3_dist2( closest
, light
->transform
.co
);
508 if( dist2
> light
->range
*light
->range
)
511 f32 dist
= sqrtf(dist2
),
512 influence
= 1.0f
/(dist
+1.0f
);
514 if( light
->type
== k_light_type_spot
){
516 m4x3_mulv( light
->inverse_world
, center
, local
);
518 float r
= fsd_cone_infinite( local
, light
->angle_sin_cos
);
520 if( r
> bound_radius
)
525 for( int k
=best_pos
-1; k
>=0; k
-- )
526 if( influence
> influences
[k
] )
530 for( int k
=N
-1; k
>best_pos
; k
-- ){
531 influences
[k
] = influences
[k
-1];
532 indices
[k
] = indices
[k
-1];
535 influences
[best_pos
] = influence
;
536 indices
[best_pos
] = j
;
540 for( int j
=0; j
<N
; j
++ )
541 if( influences
[j
] > 0.0f
)
544 int base_index
= iz
* (icubes_count
[0]*icubes_count
[1]) +
545 iy
* (icubes_count
[0]) +
548 int lower_count
= VG_MIN( 3, count
);
549 u32 packed_index_lower
= lower_count
;
550 packed_index_lower
|= indices
[0]<<2;
551 packed_index_lower
|= indices
[1]<<12;
552 packed_index_lower
|= indices
[2]<<22;
554 int upper_count
= VG_MAX( 0, count
- lower_count
);
555 u32 packed_index_upper
= upper_count
;
556 packed_index_upper
|= indices
[3]<<2;
557 packed_index_upper
|= indices
[4]<<12;
558 packed_index_upper
|= indices
[5]<<22;
560 cubes_index
[ base_index
*2 + 0 ] = packed_index_lower
;
561 cubes_index
[ base_index
*2 + 1 ] = packed_index_upper
;
566 vg_async_dispatch( call
, async_upload_light_indices
);
570 * Rendering pass needed to complete the world
572 static void async_world_postprocess( void *payload
, u32 _size
){
573 /* create scene lighting buffer */
574 world_instance
*world
= payload
;
576 u32 size
= VG_MAX(mdl_arrcount(&world
->ent_light
),1) * sizeof(float)*12;
577 vg_info( "Upload %ubytes (lighting)\n", size
);
579 glGenBuffers( 1, &world
->tbo_light_entities
);
580 glBindBuffer( GL_TEXTURE_BUFFER
, world
->tbo_light_entities
);
581 glBufferData( GL_TEXTURE_BUFFER
, size
, NULL
, GL_DYNAMIC_DRAW
);
585 * colour position direction (spots)
586 * | . . . . | . . . . | . . . . |
587 * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da |
591 v4f
*light_dst
= glMapBuffer( GL_TEXTURE_BUFFER
, GL_WRITE_ONLY
);
592 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_light
); i
++ ){
593 ent_light
*light
= mdl_arritm( &world
->ent_light
, i
);
596 v3_muls( light
->colour
, light
->colour
[3] * 2.0f
, light_dst
[i
*3+0] );
597 light_dst
[i
*3+0][3] = 2.0f
;
599 if( !light
->daytime
){
600 u32 hash
= (i
* 29986577u) & 0xffu
;
601 float switch_on
= hash
;
602 switch_on
*= (1.0f
/255.0f
);
604 light_dst
[i
*3+0][3] = 0.44f
+ switch_on
* 0.015f
;
607 /* position + 1/range^2 */
608 v3_copy( light
->transform
.co
, light_dst
[i
*3+1] );
609 light_dst
[i
*3+1][3] = 1.0f
/(light
->range
*light
->range
);
611 /* direction + angle */
612 q_mulv( light
->transform
.q
, (v3f
){0.0f
,-1.0f
,0.0f
}, light_dst
[i
*3+2]);
613 light_dst
[i
*3+2][3] = cosf( light
->angle
);
616 glUnmapBuffer( GL_TEXTURE_BUFFER
);
618 glGenTextures( 1, &world
->tex_light_entities
);
619 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
620 glTexBuffer( GL_TEXTURE_BUFFER
, GL_RGBA32F
, world
->tbo_light_entities
);
622 /* Upload lighting uniform buffer */
623 if( world
->water
.enabled
)
624 v4_copy( world
->water
.plane
, world
->ub_lighting
.g_water_plane
);
627 v3f
*bounds
= world
->scene_geo
.bbx
;
629 info_vec
[0] = bounds
[0][0];
630 info_vec
[1] = bounds
[0][2];
631 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
632 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
633 v4_copy( info_vec
, world
->ub_lighting
.g_depth_bounds
);
636 * Rendering the depth map
641 v3_sub( world
->scene_geo
.bbx
[1], world
->scene_geo
.bbx
[0], extent
);
643 float fl
= world
->scene_geo
.bbx
[0][0],
644 fr
= world
->scene_geo
.bbx
[1][0],
645 fb
= world
->scene_geo
.bbx
[0][2],
646 ft
= world
->scene_geo
.bbx
[1][2],
650 m4x4_zero( ortho
.mtx
.p
);
651 ortho
.mtx
.p
[0][0] = 2.0f
* rl
;
652 ortho
.mtx
.p
[2][1] = 2.0f
* tb
;
653 ortho
.mtx
.p
[3][0] = (fr
+ fl
) * -rl
;
654 ortho
.mtx
.p
[3][1] = (ft
+ fb
) * -tb
;
655 ortho
.mtx
.p
[3][3] = 1.0f
;
656 m4x3_identity( ortho
.transform
);
657 camera_update_view( &ortho
);
658 camera_finalize( &ortho
);
660 glDisable(GL_DEPTH_TEST
);
662 glDisable(GL_CULL_FACE
);
663 render_fb_bind( &world
->heightmap
, 0 );
664 shader_blitcolour_use();
665 shader_blitcolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
669 glBlendFunc(GL_ONE
, GL_ONE
);
670 glBlendEquation(GL_MAX
);
672 render_world_position( world
, &ortho
);
674 glEnable(GL_DEPTH_TEST
);
675 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
677 /* upload full buffer */
678 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
679 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
680 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
685 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_cubemap
); i
++ ){
686 ent_cubemap
*cm
= mdl_arritm(&world
->ent_cubemap
,i
);
688 glGenTextures( 1, &cm
->texture_id
);
689 glBindTexture( GL_TEXTURE_CUBE_MAP
, cm
->texture_id
);
690 glTexParameteri(GL_TEXTURE_CUBE_MAP
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
691 glTexParameteri(GL_TEXTURE_CUBE_MAP
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
692 glTexParameteri(GL_TEXTURE_CUBE_MAP
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
693 glTexParameteri(GL_TEXTURE_CUBE_MAP
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
694 glTexParameteri(GL_TEXTURE_CUBE_MAP
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
696 for( u32 j
=0; j
<6; j
++ ) {
697 glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ j
, 0, GL_RGB
,
698 WORLD_CUBEMAP_RES
, WORLD_CUBEMAP_RES
,
699 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
702 glGenFramebuffers( 1, &cm
->framebuffer_id
);
703 glBindFramebuffer( GL_FRAMEBUFFER
, cm
->framebuffer_id
);
704 glGenRenderbuffers(1, &cm
->renderbuffer_id
);
705 glBindRenderbuffer( GL_RENDERBUFFER
, cm
->renderbuffer_id
);
706 glRenderbufferStorage( GL_RENDERBUFFER
, GL_DEPTH_COMPONENT24
,
707 WORLD_CUBEMAP_RES
, WORLD_CUBEMAP_RES
);
709 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
710 GL_TEXTURE_CUBE_MAP_POSITIVE_X
, cm
->texture_id
, 0 );
711 glFramebufferRenderbuffer( GL_FRAMEBUFFER
, GL_DEPTH_ATTACHMENT
,
712 GL_RENDERBUFFER
, cm
->renderbuffer_id
);
714 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
715 GL_TEXTURE_CUBE_MAP_POSITIVE_X
, cm
->texture_id
, 0 );
717 if( glCheckFramebufferStatus(GL_FRAMEBUFFER
) != GL_FRAMEBUFFER_COMPLETE
){
718 vg_error( "Cubemap framebuffer incomplete.\n" );
722 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
725 /* Loads textures from the pack file */
726 static void world_gen_load_surfaces( world_instance
*world
){
727 vg_info( "Loading textures\n" );
728 world
->texture_count
= 0;
730 world
->texture_count
= world
->meta
.textures
.count
+1;
731 world
->textures
= vg_linear_alloc( world
->heap
,
732 vg_align8(sizeof(GLuint
)*world
->texture_count
) );
733 world
->textures
[0] = vg
.tex_missing
;
735 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.textures
); i
++ ){
736 mdl_texture
*tex
= mdl_arritm( &world
->meta
.textures
, i
);
738 if( !tex
->file
.pack_size
){
739 vg_fatal_error( "World models must have packed textures!" );
742 vg_linear_clear( vg_mem
.scratch
);
743 void *src_data
= vg_linear_alloc( vg_mem
.scratch
,
744 tex
->file
.pack_size
);
745 mdl_fread_pack_file( &world
->meta
, &tex
->file
, src_data
);
747 vg_tex2d_load_qoi_async( src_data
, tex
->file
.pack_size
,
748 VG_TEX2D_NEAREST
|VG_TEX2D_REPEAT
,
749 &world
->textures
[i
+1] );
752 vg_info( "Loading materials\n" );
754 world
->surface_count
= world
->meta
.materials
.count
+1;
755 world
->surfaces
= vg_linear_alloc( world
->heap
,
756 vg_align8(sizeof(struct world_surface
)*world
->surface_count
) );
759 struct world_surface
*errmat
= &world
->surfaces
[0];
760 memset( errmat
, 0, sizeof(struct world_surface
) );
762 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.materials
); i
++ ){
763 struct world_surface
*surf
= &world
->surfaces
[i
+1];
764 surf
->info
= *(mdl_material
*)mdl_arritm( &world
->meta
.materials
, i
);
769 #endif /* WORLD_GEN_C */