2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 VG_STATIC
void world_load( world_instance
*world
, const char *path
);
12 VG_STATIC
void world_add_all_if_material( m4x3f transform
, scene
*pscene
,
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( pscene
, mdl
, sm
, transform2
);
31 VG_STATIC
void world_add_blob( world_instance
*world
,
32 scene
*pscene
, 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_randf()*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( pscene
->vertex_count
+ vg_list_size(verts
) > pscene
->max_vertices
)
60 vg_fatal_exit_loop( "Scene vertex buffer overflow" );
62 if( pscene
->indice_count
+ vg_list_size(indices
) > pscene
->max_indices
)
63 vg_fatal_exit_loop( "Scene index buffer overflow" );
65 scene_vert
*dst_verts
= &pscene
->arrvertices
[ pscene
->vertex_count
];
66 u32
*dst_indices
= &pscene
->arrindices
[ pscene
->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
] + pscene
->vertex_count
;
84 pscene
->vertex_count
+= vg_list_size(verts
);
85 pscene
->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
,
90 struct world_surface
*mat
)
92 if( vg
.quality_profile
== k_quality_profile_low
)
95 vg_info( "Applying foliage (%u)\n", mat
->info
.pstr_name
);
98 v3_sub( world
->scene_geo
->bbx
[1], world
->scene_geo
->bbx
[0], volume
);
103 float area
= volume
[0]*volume
[2];
104 u32 particles
= 0.08f
* area
;
106 vg_info( "Map area: %f. Max particles: %u\n", area
, particles
);
108 for( u32 i
=0; i
<particles
; i
++ ){
110 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
112 v3_add( pos
, world
->scene_geo
->bbx
[0], pos
);
117 if( ray_world( world
, pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
)){
118 struct world_surface
*m1
= ray_hit_surface( world
, &hit
);
119 if((hit
.normal
[1] > 0.8f
) && (m1
== mat
) && (hit
.pos
[1] > 0.0f
+10.0f
)){
120 world_add_blob( world
, world
->scene_no_collide
, &hit
);
126 vg_info( "%d foliage models added\n", count
);
130 VG_STATIC
void world_ents_allocate( world_instance
*world
)
132 vg_info( "Allocating entities\n" );
134 /* --count entites to allocate buffers for them.--
135 * --maybe in the future we just store these numbers in the model file...--
137 * ... 16.03.23: I HOPE YOUR FUCKING HAPPY
138 * ... 22.03.23: incomprehensible pain
140 * -- use this in world_routes too --
146 enum classtype ct
, ct1
;
156 (void*)&world
->spawns
,
157 sizeof(struct respawn_point
)
162 (void*)&world
->audio_things
,
163 sizeof(struct world_audio_thing
)
166 k_classtype_world_light
,
168 (void*)&world
->lights
,
169 sizeof(struct world_light
)
172 k_classtype_nonlocal_gate
,
174 (void*)&world
->nonlocal_gates
,
175 sizeof(struct nonlocal_gate
)
179 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
180 entity_counts
[i
].count
= 0;
182 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
184 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
186 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
188 if( (pnode
->classtype
== entity_counts
[j
].ct
) ||
189 (pnode
->classtype
== entity_counts
[j
].ct1
) )
191 pnode
->sub_uid
= entity_counts
[j
].count
;
192 entity_counts
[j
].count
++;
198 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
200 struct countable
*counter
= &entity_counts
[i
];
202 u32 bufsize
= counter
->item_size
*counter
->count
;
203 *counter
->to_allocate
= vg_linear_alloc( world_global
.generic_heap
,
205 memset( *counter
->to_allocate
, 0, bufsize
);
208 world
->volume_bh
= bh_create( world_global
.generic_heap
,
217 VG_STATIC
void world_pct_spawn( world_instance
*world
, mdl_node
*pnode
)
219 struct respawn_point
*rp
= &world
->spawns
[ world
->spawn_count
++ ];
221 v3_copy( pnode
->co
, rp
->co
);
222 v4_copy( pnode
->q
, rp
->q
);
223 rp
->name
= mdl_pstr( world
->meta
, pnode
->pstr_name
);
226 VG_STATIC
void world_pct_water( world_instance
*world
, mdl_node
*pnode
)
228 if( world
->water
.enabled
)
230 vg_warn( "Multiple water surfaces in level! ('%s')\n",
231 mdl_pstr( world
->meta
, pnode
->pstr_name
));
235 world
->water
.enabled
= 1;
236 water_set_surface( world
, pnode
->co
[1] );
239 VG_STATIC
void world_pct_audio( world_instance
*world
, mdl_node
*pnode
)
241 struct world_audio_thing
*thing
= &world
->audio_things
[
242 world
->audio_things_count
];
244 memset( thing
, 0, sizeof(struct world_audio_thing
) );
245 struct classtype_audio
*aud
= mdl_get_entdata( world
->meta
, pnode
);
247 v3_copy( pnode
->co
, thing
->pos
);
249 thing
->volume
= aud
->volume
;
250 thing
->range
= pnode
->s
[0];
252 thing
->flags
= aud
->flags
;
253 thing
->temp_embedded_clip
.path
= mdl_pstr( world
->meta
, aud
->pstr_file
);
254 thing
->temp_embedded_clip
.flags
= aud
->flags
;
256 audio_clip_load( &thing
->temp_embedded_clip
, world_global
.generic_heap
);
258 pnode
->sub_uid
= world
->audio_things_count
;
259 world
->audio_things_count
++;
262 VG_STATIC
void world_pct_world_light( world_instance
*world
, mdl_node
*pnode
)
264 struct world_light
*light
= &world
->lights
[ world
->light_count
++ ];
266 light
->inf
= mdl_get_entdata( world
->meta
, pnode
);
268 q_m3x3( pnode
->q
, light
->inverse_world
);
269 v3_copy( pnode
->co
, light
->inverse_world
[3] );
270 m4x3_invert_affine( light
->inverse_world
, light
->inverse_world
);
272 light
->angle_sin_cos
[0] = sinf( light
->inf
->angle
* 0.5f
);
273 light
->angle_sin_cos
[1] = cosf( light
->inf
->angle
* 0.5f
);
276 VG_STATIC
void world_pct_nonlocal_gate( world_instance
*world
, mdl_node
*pnode
)
278 struct nonlocal_gate
*gate
= &world
->nonlocal_gates
[
279 world
->nonlocalgate_count
++ ];
280 struct classtype_gate
*inf
= mdl_get_entdata( world
->meta
, pnode
);
284 gate
->target_map_index
= 0;
285 v2_copy( inf
->dims
, gate
->gate
.dims
);
288 VG_STATIC
void world_entities_process( world_instance
*world
)
290 struct entity_instruction
293 void (*process
)( world_instance
*world
, mdl_node
*pnode
);
295 entity_instructions
[] =
297 { k_classtype_spawn
, world_pct_spawn
},
298 { k_classtype_water
, world_pct_water
},
299 { k_classtype_audio
, world_pct_audio
},
300 { k_classtype_world_light
, world_pct_world_light
},
301 { k_classtype_nonlocal_gate
, world_pct_nonlocal_gate
}
304 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
306 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
308 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
310 struct entity_instruction
*instr
= &entity_instructions
[j
];
312 if( pnode
->classtype
== instr
->ct
)
314 instr
->process( world
, pnode
);
320 VG_STATIC
void world_link_nonlocal_gates( int index_a
, int index_b
)
322 vg_info( "Linking non-local gates\n" );
323 world_instance
*a
= &world_global
.worlds
[ index_a
],
324 *b
= &world_global
.worlds
[ index_b
];
326 for( int i
=0; i
<a
->nonlocalgate_count
; i
++ )
328 struct nonlocal_gate
*ga
= &a
->nonlocal_gates
[i
];
329 struct classtype_gate
*ga_inf
= mdl_get_entdata( a
->meta
, ga
->node
);
330 const char *ga_name
= mdl_pstr( a
->meta
, ga_inf
->target
);
332 for( int j
=0; j
<b
->nonlocalgate_count
; j
++ )
334 struct nonlocal_gate
*gb
= &b
->nonlocal_gates
[j
];
335 struct classtype_gate
*gb_inf
= mdl_get_entdata( b
->meta
, gb
->node
);
336 const char *gb_name
= mdl_pstr( b
->meta
, gb_inf
->target
);
338 if( !strcmp( ga_name
, gb_name
) )
340 vg_success( "Created longjump for ID '%s'\n", ga_name
);
343 q_axis_angle( qYflip
, (v3f
){0.0f
,1.0f
,0.0f
}, VG_PIf
);
345 /* TODO: Gates are created very wonkily. refactor. */
346 ga
->target_map_index
= index_b
;
347 gb
->target_map_index
= index_a
;
351 v4_copy( ga
->node
->q
, ga
->gate
.q
[0] );
352 v4_copy( gb
->node
->q
, ga
->gate
.q
[1] );
353 v3_copy( ga
->node
->co
, ga
->gate
.co
[0] );
354 v3_copy( gb
->node
->co
, ga
->gate
.co
[1] );
356 v4_copy( gb
->node
->q
, gb
->gate
.q
[0] );
357 v4_copy( ga
->node
->q
, gb
->gate
.q
[1] );
358 v3_copy( gb
->node
->co
, gb
->gate
.co
[0] );
359 v3_copy( ga
->node
->co
, gb
->gate
.co
[1] );
361 /* reverse B's direction */
362 q_mul( gb
->gate
.q
[0], qYflip
, gb
->gate
.q
[0] );
363 q_mul( gb
->gate
.q
[1], qYflip
, gb
->gate
.q
[1] );
364 q_normalize( gb
->gate
.q
[0] );
365 q_normalize( gb
->gate
.q
[1] );
367 gate_transform_update( &ga
->gate
);
368 gate_transform_update( &gb
->gate
);
376 VG_STATIC
float colour_luminance( v3f v
)
378 return v3_dot( v
, (v3f
){0.2126f
, 0.7152f
, 0.0722f
} );
381 VG_STATIC
float calc_light_influence( world_instance
*world
, v3f position
,
384 struct world_light
*world_light
= &world
->lights
[ light
];
385 struct classtype_world_light
*inf
= world_light
->inf
;
388 v3_sub( world_light
->node
->co
, position
, light_delta
);
389 v3_muls( light_delta
, 10.0f
, light_delta
);
391 float quadratic
= v3_dot( light_delta
, light_delta
),
392 attenuation
= 1.0f
/( 1.0f
+ quadratic
);
394 float quadratic_light
= attenuation
* colour_luminance( inf
->colour
);
396 if( (inf
->type
== k_light_type_point
) ||
397 (inf
->type
== k_light_type_point_nighttime_only
) )
399 return quadratic_light
;
401 else if( (inf
->type
== k_light_type_spot
) ||
402 (inf
->type
== k_light_type_spot_nighttime_only
) )
405 q_mulv( world_light
->node
->q
, (v3f
){0.0f
,1.0f
,0.0f
}, dir
);
407 float spot_theta
= vg_maxf( 0.0f
, v3_dot( light_delta
, dir
) ),
408 falloff
= spot_theta
>= 0.0f
? 1.0f
: 0.0f
;
410 return quadratic_light
* falloff
;
417 VG_STATIC
void world_generate( world_instance
*world
)
420 * Compile meshes into the world scenes
422 world
->scene_geo
= scene_init( world_global
.generic_heap
, 320000, 1200000 );
425 m4x3_identity( midentity
);
428 * Generate scene: collidable geometry
429 * ----------------------------------------------------------------
432 vg_info( "Generating collidable geometry\n" );
434 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
435 struct world_surface
*surf
= &world
->surfaces
[ i
];
437 if( surf
->info
.flags
& k_material_flag_collision
)
438 world_add_all_if_material( midentity
, world
->scene_geo
,
441 scene_copy_slice( world
->scene_geo
, &surf
->sm_geo
);
444 /* compress that bad boy */
445 world
->scene_geo
= scene_fix( world_global
.generic_heap
, world
->scene_geo
);
447 vg_acquire_thread_sync();
449 scene_upload( world
->scene_geo
, &world
->mesh_geo
);
451 vg_release_thread_sync();
453 /* setup spacial mapping and rigidbody */
454 world
->geo_bh
= scene_bh_create( world_global
.generic_heap
,
457 v3_zero( world
->rb_geo
.co
);
458 q_identity( world
->rb_geo
.q
);
460 world
->rb_geo
.type
= k_rb_shape_scene
;
461 world
->rb_geo
.inf
.scene
.bh_scene
= world
->geo_bh
;
462 world
->rb_geo
.is_world
= 1;
463 rb_init( &world
->rb_geo
);
466 * Generate scene: non-collidable geometry
467 * ----------------------------------------------------------------
469 vg_info( "Generating non-collidable geometry\n" );
471 world
->scene_no_collide
= scene_init( world_global
.generic_heap
,
474 for( u32 i
=0; i
<world
->surface_count
; i
++ ){
475 struct world_surface
*mat
= &world
->surfaces
[ i
];
477 if( !(mat
->info
.flags
& k_material_flag_collision
) ){
478 world_add_all_if_material( midentity
, world
->scene_no_collide
,
482 if( mat
->info
.flags
& k_material_flag_grow_grass
)
483 world_apply_procedural_foliage( world
, mat
);
485 scene_copy_slice( world
->scene_no_collide
, &mat
->sm_no_collide
);
488 /* upload and free that */
489 vg_acquire_thread_sync();
491 scene_upload( world
->scene_no_collide
, &world
->mesh_no_collide
);
493 vg_release_thread_sync();
495 vg_linear_del( world_global
.generic_heap
, world
->scene_no_collide
);
496 world
->scene_no_collide
= NULL
;
499 float fsd_cone_infinite( v3f p
, v2f c
)
501 v2f q
= { v2_length( (v2f
){ p
[0], p
[2] } ), -p
[1] };
502 float s
= vg_maxf( 0.0f
, v2_dot( q
, c
) );
508 float d
= v2_length( v0
);
509 return d
* ((q
[0]*c
[1]-q
[1]*c
[0]<0.0f
)?-1.0f
:1.0f
);
512 VG_STATIC
void world_compute_light_indices( world_instance
*world
)
515 v3f cubes_min
, cubes_max
;
516 v3_muls( world
->scene_geo
->bbx
[0], 1.0f
/k_light_cube_size
, cubes_min
);
517 v3_muls( world
->scene_geo
->bbx
[1], 1.0f
/k_light_cube_size
, cubes_max
);
519 v3_sub( cubes_min
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_min
);
520 v3_add( cubes_max
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_max
);
522 v3_floor( cubes_min
, cubes_min
);
523 v3_floor( cubes_max
, cubes_max
);
525 v3i icubes_min
, icubes_max
;
527 for( int i
=0; i
<3; i
++ ){
528 icubes_min
[i
] = cubes_min
[i
];
529 icubes_max
[i
] = cubes_max
[i
];
533 v3i_sub( icubes_max
, icubes_min
, icubes_count
);
535 for( int i
=0; i
<3; i
++ ){
536 icubes_count
[i
] = VG_MIN( 128, icubes_count
[i
]+1 );
537 cubes_max
[i
] = icubes_min
[i
] + icubes_count
[i
];
540 v3_muls( cubes_min
, k_light_cube_size
, cubes_min
);
541 v3_muls( cubes_max
, k_light_cube_size
, cubes_max
);
543 for( int i
=0; i
<3; i
++ ){
544 float range
= cubes_max
[i
]-cubes_min
[i
];
545 world
->ub_lighting
.g_cube_inv_range
[i
] = 1.0f
/ range
;
546 world
->ub_lighting
.g_cube_inv_range
[i
] *= (float)icubes_count
[i
];
548 vg_info( "cubes[%d]: %d\n", i
, icubes_count
[i
] );
551 int total_cubes
= icubes_count
[0]*icubes_count
[1]*icubes_count
[2];
553 u32
*cubes_index
= vg_linear_alloc( world_global
.generic_heap
,
554 total_cubes
* sizeof(u32
) * 2.0f
);
556 vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n",
557 total_cubes
, cubes_min
[0], -cubes_min
[2], cubes_min
[1],
558 cubes_max
[0], -cubes_max
[2], cubes_max
[1] );
560 v3_copy( cubes_min
, world
->ub_lighting
.g_cube_min
);
563 v3_div( (v3f
){1.0f
,1.0f
,1.0f
}, world
->ub_lighting
.g_cube_inv_range
,
565 float bound_radius
= v3_length( cube_size
);
567 for( int iz
= 0; iz
<icubes_count
[2]; iz
++ ){
568 for( int iy
= 0; iy
<icubes_count
[1]; iy
++ ){
569 for( int ix
= 0; ix
<icubes_count
[0]; ix
++ ){
571 v3_div( (v3f
){ ix
, iy
, iz
}, world
->ub_lighting
.g_cube_inv_range
,
573 v3_div( (v3f
){ ix
+1, iy
+1, iz
+1 },
574 world
->ub_lighting
.g_cube_inv_range
,
577 v3_add( bbx
[0], world
->ub_lighting
.g_cube_min
, bbx
[0] );
578 v3_add( bbx
[1], world
->ub_lighting
.g_cube_min
, bbx
[1] );
581 v3_add( bbx
[0], bbx
[1], center
);
582 v3_muls( center
, 0.5f
, center
);
584 u32 indices
[6] = { 0, 0, 0, 0, 0, 0 };
587 float influences
[6] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
588 const int N
= vg_list_size( influences
);
590 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
591 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
593 closest_point_aabb( light
->transform
.co
, bbx
, closest
);
595 float dist
= v3_dist( closest
, light
->transform
.co
),
596 influence
= 1.0f
/(dist
+1.0f
);
598 if( dist
> light
->range
)
601 if( light
->type
== k_light_type_spot
){
603 m4x3_mulv( light
->inverse_world
, center
, local
);
605 float r
= fsd_cone_infinite( local
, light
->angle_sin_cos
);
607 if( r
> bound_radius
)
612 for( int k
=best_pos
-1; k
>=0; k
-- )
613 if( influence
> influences
[k
] )
617 for( int k
=N
-1; k
>best_pos
; k
-- ){
618 influences
[k
] = influences
[k
-1];
619 indices
[k
] = indices
[k
-1];
622 influences
[best_pos
] = influence
;
623 indices
[best_pos
] = j
;
627 for( int j
=0; j
<N
; j
++ )
628 if( influences
[j
] > 0.0f
)
631 int base_index
= iz
* (icubes_count
[0]*icubes_count
[1]) +
632 iy
* (icubes_count
[0]) +
635 int lower_count
= VG_MIN( 3, count
);
636 u32 packed_index_lower
= lower_count
;
637 packed_index_lower
|= indices
[0]<<2;
638 packed_index_lower
|= indices
[1]<<12;
639 packed_index_lower
|= indices
[2]<<22;
641 int upper_count
= VG_MAX( 0, count
- lower_count
);
642 u32 packed_index_upper
= upper_count
;
643 packed_index_upper
|= indices
[3]<<2;
644 packed_index_upper
|= indices
[4]<<12;
645 packed_index_upper
|= indices
[5]<<22;
647 cubes_index
[ base_index
*2 + 0 ] = packed_index_lower
;
648 cubes_index
[ base_index
*2 + 1 ] = packed_index_upper
;
653 vg_acquire_thread_sync();
655 glGenTextures( 1, &world
->tex_light_cubes
);
656 glBindTexture( GL_TEXTURE_3D
, world
->tex_light_cubes
);
657 glTexImage3D( GL_TEXTURE_3D
, 0, GL_RG32UI
,
658 icubes_count
[0], icubes_count
[1], icubes_count
[2],
659 0, GL_RG_INTEGER
, GL_UNSIGNED_INT
, cubes_index
);
660 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
661 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
663 vg_linear_del( world_global
.generic_heap
, cubes_index
);
665 vg_release_thread_sync();
668 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
669 VG_STATIC
void world_post_process( world_instance
*world
)
671 /* initialize audio if need be */
674 for( int i
=0; i
<world
->audio_things_count
; i
++ )
676 struct world_audio_thing
*thingy
= &world
->audio_things
[ i
];
678 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
681 audio_request_channel( &thingy
->temp_embedded_clip
, thingy
->flags
);
683 audio_channel_edit_volume( ch
, thingy
->volume
, 1 );
684 audio_channel_set_spacial( ch
, thingy
->pos
, thingy
->range
);
686 if( !(ch
->flags
& AUDIO_FLAG_LOOP
) )
687 ch
= audio_relinquish_channel( ch
);
693 world_compute_light_indices( world
);
695 vg_acquire_thread_sync();
697 /* create scene lighting buffer */
699 u32 size
= VG_MAX(mdl_arrcount(&world
->ent_light
),1) * sizeof(float)*12;
700 vg_info( "Upload %ubytes (lighting)\n", size
);
702 glGenBuffers( 1, &world
->tbo_light_entities
);
703 glBindBuffer( GL_TEXTURE_BUFFER
, world
->tbo_light_entities
);
704 glBufferData( GL_TEXTURE_BUFFER
, size
, NULL
, GL_DYNAMIC_DRAW
);
708 * colour position direction (spots)
709 * | . . . . | . . . . | . . . . |
710 * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da |
714 v4f
*light_dst
= glMapBuffer( GL_TEXTURE_BUFFER
, GL_WRITE_ONLY
);
715 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_light
); i
++ ){
716 ent_light
*light
= mdl_arritm( &world
->ent_light
, i
);
719 v3_muls( light
->colour
, light
->colour
[3] * 2.0f
, light_dst
[i
*3+0] );
720 light_dst
[i
*3+0][3] = -1.0f
;
722 if( !light
->daytime
){
723 u32 hash
= (i
* 29986577) & 0xff;
724 float switch_on
= hash
;
725 switch_on
*= (1.0f
/255.0f
);
727 light_dst
[i
*3+0][3] = 0.44f
+ switch_on
* 0.015f
;
730 /* position + 1/range^2 */
731 v3_copy( light
->transform
.co
, light_dst
[i
*3+1] );
732 light_dst
[i
*3+1][3] = 1.0f
/(light
->range
*light
->range
);
734 /* direction + angle */
735 q_mulv( light
->transform
.q
, (v3f
){0.0f
,-1.0f
,0.0f
}, light_dst
[i
*3+2]);
736 light_dst
[i
*3+2][3] = cosf( light
->angle
);
739 glUnmapBuffer( GL_TEXTURE_BUFFER
);
741 glGenTextures( 1, &world
->tex_light_entities
);
742 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
743 glTexBuffer( GL_TEXTURE_BUFFER
, GL_RGBA32F
, world
->tbo_light_entities
);
745 /* Upload lighting uniform buffer */
746 if( world
->water
.enabled
)
747 v4_copy( world
->water
.plane
, world
->ub_lighting
.g_water_plane
);
750 v3f
*bounds
= world
->scene_geo
->bbx
;
752 info_vec
[0] = bounds
[0][0];
753 info_vec
[1] = bounds
[0][2];
754 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
755 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
756 v4_copy( info_vec
, world
->ub_lighting
.g_depth_bounds
);
759 * Rendering the depth map
764 v3_sub( world
->scene_geo
->bbx
[1], world
->scene_geo
->bbx
[0], extent
);
766 float fl
= world
->scene_geo
->bbx
[0][0],
767 fr
= world
->scene_geo
->bbx
[1][0],
768 fb
= world
->scene_geo
->bbx
[0][2],
769 ft
= world
->scene_geo
->bbx
[1][2],
773 m4x4_zero( ortho
.mtx
.p
);
774 ortho
.mtx
.p
[0][0] = 2.0f
* rl
;
775 ortho
.mtx
.p
[2][1] = 2.0f
* tb
;
776 ortho
.mtx
.p
[3][0] = (fr
+ fl
) * -rl
;
777 ortho
.mtx
.p
[3][1] = (ft
+ fb
) * -tb
;
778 ortho
.mtx
.p
[3][3] = 1.0f
;
779 m4x3_identity( ortho
.transform
);
780 camera_update_view( &ortho
);
781 camera_finalize( &ortho
);
783 glDisable(GL_DEPTH_TEST
);
785 glDisable(GL_CULL_FACE
);
786 render_fb_bind( &world
->heightmap
);
787 shader_blitcolour_use();
788 shader_blitcolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
792 glBlendFunc(GL_ONE
, GL_ONE
);
793 glBlendEquation(GL_MAX
);
795 render_world_position( world
, &ortho
);
797 glEnable(GL_DEPTH_TEST
);
798 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
800 /* upload full buffer */
801 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
802 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
803 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
806 vg_release_thread_sync();
810 * Setup scene collider
812 reset_player( 1, (const char *[]){"start"} );
816 VG_STATIC
void world_process_resources( world_instance
*world
)
818 vg_info( "Loading textures\n" );
820 world
->texture_count
= 0;
822 world
->texture_count
= world
->meta
.textures
.count
+1;
823 world
->textures
= vg_linear_alloc( world_global
.generic_heap
,
824 sizeof(GLuint
)*world
->texture_count
);
826 vg_acquire_thread_sync();
829 world
->textures
[0] = vg_tex2d_new();
830 vg_tex2d_set_error();
834 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.textures
); i
++ ){
835 mdl_texture
*tex
= mdl_arritm( &world
->meta
.textures
, i
);
837 if( !tex
->file
.pack_size
){
838 vg_release_thread_sync();
839 vg_fatal_exit_loop( "World models must have packed textures!" );
842 vg_linear_clear( vg_mem
.scratch
);
843 world
->textures
[i
+1] = vg_tex2d_new();
844 vg_tex2d_set_error();
845 vg_tex2d_qoi( mdl_arritm( &world
->meta
.pack
, tex
->file
.pack_offset
),
847 mdl_pstr( &world
->meta
, tex
->file
.pstr_path
));
852 vg_release_thread_sync();
854 vg_info( "Loading materials\n" );
856 world
->surface_count
= world
->meta
.materials
.count
+1;
857 world
->surfaces
= vg_linear_alloc( world_global
.generic_heap
,
858 sizeof(struct world_surface
)*world
->surface_count
);
861 struct world_surface
*errmat
= &world
->surfaces
[0];
862 memset( errmat
, 0, sizeof(struct world_surface
) );
864 for( u32 i
=0; i
<mdl_arrcount(&world
->meta
.materials
); i
++ ){
865 world
->surfaces
[i
+1].info
=
866 *(mdl_material
*)mdl_arritm( &world
->meta
.materials
, i
);
870 VG_STATIC
void world_unload( world_instance
*world
)
872 vg_acquire_thread_sync();
875 mesh_free( &world
->mesh_route_lines
);
876 mesh_free( &world
->mesh_geo
);
877 mesh_free( &world
->mesh_no_collide
);
879 glDeleteBuffers( 1, &world
->tbo_light_entities
);
880 glDeleteTextures( 1, &world
->tex_light_entities
);
881 glDeleteTextures( 1, &world
->tex_light_cubes
);
883 /* FIXME: CANT DO THIS HERE */
885 world_global
.time
= 0.0;
886 world_global
.rewind_from
= 0.0;
887 world_global
.rewind_to
= 0.0;
888 world_global
.last_use
= 0.0;
889 world_global
.sfd
.active_route_board
= 0;
891 /* delete textures and meshes */
892 glDeleteTextures( world
->texture_count
, world
->textures
);
894 /* delete the entire block of memory */
895 /* FIXME: WE CANT DO THIS SHIT ANYMORE, NEED TO DEALLOC FROM ABOVE */
897 vg_linear_clear( world
->dynamic_vgl
);
898 vg_linear_clear( world
->audio_vgl
);
902 vg_release_thread_sync();
905 VG_STATIC
void world_clean( world_instance
*world
)
907 memset( &world
->meta
, 0, sizeof(mdl_context
) );
910 * TODO: Theres probably a better way to do this?
913 world
->textures
= NULL
;
914 world
->texture_count
= 0;
915 world
->surfaces
= NULL
;
916 world
->surface_count
= 0;
918 world
->scene_geo
= NULL
;
919 world
->scene_no_collide
= NULL
;
920 world
->scene_lines
= NULL
;
922 world
->geo_bh
= NULL
;
923 world
->volume_bh
= NULL
;
924 world
->audio_bh
= NULL
;
926 world
->water
.enabled
= 0;
928 /* default lighting conditions
929 * -------------------------------------------------------------*/
930 struct ub_world_lighting
*state
= &world
->ub_lighting
;
932 state
->g_light_preview
= 0;
933 state
->g_shadow_samples
= 8;
934 state
->g_water_fog
= 0.04f
;
936 v4_zero( state
->g_water_plane
);
937 v4_zero( state
->g_depth_bounds
);
939 state
->g_shadow_length
= 9.50f
;
940 state
->g_shadow_spread
= 0.65f
;
942 v3_copy( (v3f
){0.37f
, 0.54f
, 0.97f
}, state
->g_daysky_colour
);
943 v3_copy( (v3f
){0.03f
, 0.05f
, 0.20f
}, state
->g_nightsky_colour
);
944 v3_copy( (v3f
){1.00f
, 0.32f
, 0.01f
}, state
->g_sunset_colour
);
945 v3_copy( (v3f
){0.13f
, 0.17f
, 0.35f
}, state
->g_ambient_colour
);
946 v3_copy( (v3f
){0.25f
, 0.17f
, 0.51f
}, state
->g_sunset_ambient
);
947 v3_copy( (v3f
){1.10f
, 0.89f
, 0.35f
}, state
->g_sun_colour
);
950 VG_STATIC
void world_entities_init( world_instance
*world
)
953 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
954 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
957 q_m3x3( light
->transform
.q
, to_world
);
958 v3_copy( light
->transform
.co
, to_world
[3] );
959 m4x3_invert_affine( to_world
, light
->inverse_world
);
961 light
->angle_sin_cos
[0] = sinf( light
->angle
* 0.5f
);
962 light
->angle_sin_cos
[1] = cosf( light
->angle
* 0.5f
);
966 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
967 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
968 gate_transform_update( gate
);
972 VG_STATIC
void world_load( world_instance
*world
, const char *path
)
974 world_unload( world
);
975 world_clean( world
);
977 vg_info( "Loading world: %s\n", path
);
979 mdl_open( &world
->meta
, path
, world_global
.generic_heap
);
980 mdl_load_metadata_block( &world
->meta
, world_global
.generic_heap
);
981 mdl_load_animation_block( &world
->meta
, world_global
.generic_heap
);
982 mdl_load_mesh_block( &world
->meta
, world_global
.generic_heap
);
983 mdl_load_pack_block( &world
->meta
, world_global
.generic_heap
);
985 mdl_load_array( &world
->meta
, &world
->ent_gate
,
986 "ent_gate", world_global
.generic_heap
);
987 mdl_load_array( &world
->meta
, &world
->ent_spawn
,
988 "ent_spawn", world_global
.generic_heap
);
989 mdl_load_array( &world
->meta
, &world
->ent_light
,
990 "ent_light", world_global
.generic_heap
);
992 mdl_load_array( &world
->meta
, &world
->ent_route_node
,
993 "ent_route_node", world_global
.generic_heap
);
994 mdl_load_array( &world
->meta
, &world
->ent_path_index
,
995 "ent_path_index", world_global
.generic_heap
);
996 mdl_load_array( &world
->meta
, &world
->ent_checkpoint
,
997 "ent_checkpoint", world_global
.generic_heap
);
998 mdl_load_array( &world
->meta
, &world
->ent_route
,
999 "ent_route", world_global
.generic_heap
);
1001 mdl_close( &world
->meta
);
1003 /* process resources from pack */
1004 world_process_resources( world
);
1007 /* dynamic allocations */
1008 world_ents_allocate( world
);
1009 world_routes_allocate( world
);
1011 /* meta processing */
1013 world_routes_ent_init( world
);
1014 world_entities_init( world
);
1017 world_generate( world
);
1018 world_routes_generate( world
);
1019 world_post_process( world
);
1022 #endif /* WORLD_GEN_H */