cbf47287f9d1de2881a4a60de7b0287119281e74
[carveJwlIkooP6JGAAIwe30JlM.git] / world_gen.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef WORLD_GEN_H
6 #define WORLD_GEN_H
7
8 #include "world.h"
9
10 VG_STATIC void world_load( world_instance *world, const char *path );
11
12 VG_STATIC void world_add_all_if_material( m4x3f transform, scene *pscene,
13 mdl_context *mdl, u32 id )
14 {
15 for( int i=0; i<mdl->info.node_count; i++ )
16 {
17 mdl_node *pnode = mdl_node_from_id( mdl, i );
18
19 for( int j=0; j<pnode->submesh_count; j++ )
20 {
21 mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
22 if( sm->material_id == id )
23 {
24 m4x3f transform2;
25 mdl_node_transform( pnode, transform2 );
26 m4x3_mul( transform, transform2, transform2 );
27
28 scene_add_mdl_submesh( pscene, mdl, sm, transform2 );
29 }
30 }
31 }
32 }
33
34 VG_STATIC void world_add_blob( world_instance *world,
35 scene *pscene, ray_hit *hit )
36 {
37 m4x3f transform;
38 v4f qsurface, qrandom;
39 v3f axis;
40
41 v3_cross( (v3f){0.0f,1.0f,0.0f}, hit->normal, axis );
42
43 float angle = v3_dot(hit->normal,(v3f){0.0f,1.0f,0.0f});
44 q_axis_angle( qsurface, axis, angle );
45 q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf );
46 q_mul( qsurface, qrandom, qsurface );
47 q_m3x3( qsurface, transform );
48 v3_copy( hit->pos, transform[3] );
49
50 scene_vert verts[] =
51 {
52 { .co = { -1.00f, 0.0f, 0.0f } },
53 { .co = { 1.00f, 0.0f, 0.0f } },
54 { .co = { -1.00f, 1.2f, 0.0f } },
55 { .co = { 1.00f, 1.2f, 0.0f } },
56 { .co = { -0.25f, 2.0f, 0.0f } },
57 { .co = { 0.25f, 2.0f, 0.0f } }
58 };
59
60 const u32 indices[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 };
61
62 if( pscene->vertex_count + vg_list_size(verts) > pscene->max_vertices )
63 vg_fatal_exit_loop( "Scene vertex buffer overflow" );
64
65 if( pscene->indice_count + vg_list_size(indices) > pscene->max_indices )
66 vg_fatal_exit_loop( "Scene index buffer overflow" );
67
68 scene_vert *dst_verts = &pscene->arrvertices[ pscene->vertex_count ];
69 u32 *dst_indices = &pscene->arrindices [ pscene->indice_count ];
70
71 scene_vert *ref = &world->scene_geo->arrvertices[ hit->tri[0] ];
72
73 for( u32 i=0; i<vg_list_size(verts); i++ )
74 {
75 scene_vert *pvert = &dst_verts[ i ],
76 *src = &verts[ i ];
77
78 m4x3_mulv( transform, src->co, pvert->co );
79 scene_vert_pack_norm( pvert, transform[1] );
80
81 v2_copy( ref->uv, pvert->uv );
82 }
83
84 for( u32 i=0; i<vg_list_size(indices); i++ )
85 dst_indices[i] = indices[i] + pscene->vertex_count;
86
87 pscene->vertex_count += vg_list_size(verts);
88 pscene->indice_count += vg_list_size(indices);
89 }
90
91 /* Sprinkle foliage models over the map on terrain material */
92 VG_STATIC void world_apply_procedural_foliage( world_instance *world,
93 struct world_material *mat )
94 {
95 if( vg.quality_profile == k_quality_profile_low )
96 return;
97
98 vg_info( "Applying foliage (%u)\n", mat->info.pstr_name );
99
100 vg_linear_clear( vg_mem.scratch );
101
102 mdl_context *mfoliage =
103 mdl_load_full( vg_mem.scratch, "models/rs_foliage.mdl");
104
105 v3f volume;
106 v3_sub( world->scene_geo->bbx[1], world->scene_geo->bbx[0], volume );
107 volume[1] = 1.0f;
108
109 mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
110 mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
111
112 int count = 0;
113
114 float area = volume[0]*volume[2];
115 u32 particles = 0.08f * area;
116
117 vg_info( "Map area: %f. Max particles: %u\n", area, particles );
118
119 for( int i=0;i<particles;i++ )
120 {
121 v3f pos;
122 v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
123 pos[1] = 1000.0f;
124 v3_add( pos, world->scene_geo->bbx[0], pos );
125
126 ray_hit hit;
127 hit.dist = INFINITY;
128
129 if( ray_world( world, pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
130 {
131 struct world_material *m1 = ray_hit_material( world, &hit );
132 if((hit.normal[1] > 0.8f) && (m1 == mat) && (hit.pos[1] > 0.0f+10.0f))
133 {
134 world_add_blob( world, world->scene_no_collide, &hit );
135 count ++;
136 }
137 }
138 }
139
140 vg_info( "%d foliage models added\n", count );
141 }
142
143 VG_STATIC void world_ents_allocate( world_instance *world )
144 {
145 vg_info( "Allocating entities\n" );
146
147 /* count entites to allocate buffers for them.
148 * maybe in the future we just store these numbers in the model file...
149 *
150 * TODO: use this in world_routes too */
151
152 struct countable
153 {
154 enum classtype ct, ct1;
155 void **to_allocate;
156 u32 item_size;
157 int count;
158 }
159 entity_counts[] =
160 {
161 {
162 k_classtype_spawn,
163 k_classtype_none,
164 (void*)&world->spawns,
165 sizeof(struct respawn_point)
166 },
167 {
168 k_classtype_audio,
169 k_classtype_none,
170 (void*)&world->audio_things,
171 sizeof(struct world_audio_thing)
172 },
173 {
174 k_classtype_trigger,
175 k_classtype_particle_box,
176 (void*)&world->triggers,
177 sizeof(struct trigger_zone)
178 },
179
180 #if 0
181 {
182 k_classtype_logic_relay,
183 (void*)&world->logic_relays,
184 sizeof(struct logic_relay)
185 },
186 #endif
187
188 {
189 k_classtype_logic_achievement,
190 k_classtype_none,
191 (void*)&world->logic_achievements,
192 sizeof(struct logic_achievement)
193 },
194 {
195 k_classtype_world_light,
196 k_classtype_none,
197 (void*)&world->lights,
198 sizeof(struct world_light)
199 },
200 {
201 k_classtype_nonlocal_gate,
202 k_classtype_none,
203 (void*)&world->nonlocal_gates,
204 sizeof(struct nonlocal_gate)
205 },
206 {
207 k_classtype_soundscape,
208 k_classtype_none,
209 (void*)&world->soundscapes,
210 sizeof(struct soundscape)
211 }
212 };
213
214 for( int i=0; i<vg_list_size(entity_counts); i++ )
215 entity_counts[i].count = 0;
216
217 for( int i=0; i<world->meta->info.node_count; i++ )
218 {
219 mdl_node *pnode = mdl_node_from_id( world->meta, i );
220
221 for( int j=0; j<vg_list_size(entity_counts); j ++ )
222 {
223 if( (pnode->classtype == entity_counts[j].ct) ||
224 (pnode->classtype == entity_counts[j].ct1) )
225 {
226 pnode->sub_uid = entity_counts[j].count;
227 entity_counts[j].count ++;
228 break;
229 }
230 }
231 }
232
233 for( int i=0; i<vg_list_size(entity_counts); i++ )
234 {
235 struct countable *counter = &entity_counts[i];
236
237 u32 bufsize = counter->item_size*counter->count;
238 *counter->to_allocate = vg_linear_alloc( world_global.generic_heap,
239 bufsize );
240 memset( *counter->to_allocate, 0, bufsize );
241 }
242
243 logic_bricks_world_gen_allocate( world );
244 }
245
246 VG_STATIC void world_pct_spawn( world_instance *world, mdl_node *pnode )
247 {
248 struct respawn_point *rp = &world->spawns[ world->spawn_count ++ ];
249
250 v3_copy( pnode->co, rp->co );
251 v4_copy( pnode->q, rp->q );
252 rp->name = mdl_pstr( world->meta, pnode->pstr_name );
253 }
254
255 VG_STATIC void world_pct_water( world_instance *world, mdl_node *pnode )
256 {
257 if( world->water.enabled )
258 {
259 vg_warn( "Multiple water surfaces in level! ('%s')\n",
260 mdl_pstr( world->meta, pnode->pstr_name ));
261 return;
262 }
263
264 world->water.enabled = 1;
265 water_set_surface( world, pnode->co[1] );
266 }
267
268 VG_STATIC void world_pct_audio( world_instance *world, mdl_node *pnode )
269 {
270 struct world_audio_thing *thing = &world->audio_things[
271 world->audio_things_count ];
272
273 memset( thing, 0, sizeof(struct world_audio_thing) );
274 struct classtype_audio *aud = mdl_get_entdata( world->meta, pnode );
275
276 v3_copy( pnode->co, thing->pos );
277
278 thing->volume = aud->volume;
279 thing->range = pnode->s[0];
280
281 thing->flags = aud->flags;
282 thing->temp_embedded_clip.path = mdl_pstr( world->meta, aud->pstr_file );
283 thing->temp_embedded_clip.flags = aud->flags;
284
285 audio_clip_load( &thing->temp_embedded_clip, world_global.generic_heap );
286
287 pnode->sub_uid = world->audio_things_count;
288 world->audio_things_count ++;
289 }
290
291 #if 0
292 VG_STATIC void world_pct_relay( world_instance *world, mdl_node *pnode )
293 {
294 struct logic_relay *relay = &world->logic_relays[ world->relay_count ];
295 struct classtype_logic_relay *inf = mdl_get_entdata( world->meta, pnode );
296
297 relay->target_count = 0;
298
299 for( int i=0; i<vg_list_size(relay->targets); i++ )
300 {
301 if( inf->targets[i] )
302 {
303 struct relay_target *target = &relay->targets[relay->target_count ++];
304 mdl_node *other = mdl_node_from_id( world->meta, inf->targets[i] );
305
306 target->classtype = other->classtype;
307 target->sub_id = other->sub_uid;
308 }
309 }
310
311 v3_copy( pnode->co, relay->pos );
312 world->relay_count ++;
313 }
314 #endif
315
316
317 VG_STATIC void world_pct_achievement( world_instance *world, mdl_node *pnode )
318 {
319 struct logic_achievement *ach =
320 &world->logic_achievements[ world->achievement_count ];
321 struct classtype_logic_achievement *inf =
322 mdl_get_entdata( world->meta, pnode );
323
324 v3_copy( pnode->co, ach->pos );
325 ach->achievement_id = mdl_pstr( world->meta, inf->pstr_name );
326 ach->achieved = 0;
327
328 world->achievement_count ++;
329 }
330
331 VG_STATIC void world_pct_world_light( world_instance *world, mdl_node *pnode )
332 {
333 struct world_light *light = &world->lights[ world->light_count ++ ];
334 light->node = pnode;
335 light->inf = mdl_get_entdata( world->meta, pnode );
336
337 q_m3x3( pnode->q, light->inverse_world );
338 v3_copy( pnode->co, light->inverse_world[3] );
339 m4x3_invert_affine( light->inverse_world, light->inverse_world );
340
341 light->angle_sin_cos[0] = sinf( light->inf->angle * 0.5f );
342 light->angle_sin_cos[1] = cosf( light->inf->angle * 0.5f );
343 }
344
345 VG_STATIC void world_pct_nonlocal_gate( world_instance *world, mdl_node *pnode )
346 {
347 struct nonlocal_gate *gate = &world->nonlocal_gates[
348 world->nonlocalgate_count ++ ];
349 struct classtype_gate *inf = mdl_get_entdata( world->meta, pnode );
350
351 gate->working = 0;
352 gate->node = pnode;
353 gate->target_map_index = 0;
354 v2_copy( inf->dims, gate->gate.dims );
355 }
356
357 VG_STATIC void world_entities_process( world_instance *world )
358 {
359 struct entity_instruction
360 {
361 enum classtype ct;
362 void (*process)( world_instance *world, mdl_node *pnode );
363 }
364 entity_instructions[] =
365 {
366 { k_classtype_spawn, world_pct_spawn },
367 { k_classtype_water, world_pct_water },
368 { k_classtype_audio, world_pct_audio },
369 #if 0
370 { k_classtype_logic_relay, world_pct_relay },
371 #endif
372 { k_classtype_logic_achievement, world_pct_achievement },
373 { k_classtype_world_light, world_pct_world_light },
374 { k_classtype_nonlocal_gate, world_pct_nonlocal_gate }
375 };
376
377 for( int i=0; i<world->meta->info.node_count; i++ )
378 {
379 mdl_node *pnode = mdl_node_from_id( world->meta, i );
380
381 for( int j=0; j<vg_list_size(entity_instructions); j++ )
382 {
383 struct entity_instruction *instr = &entity_instructions[j];
384
385 if( pnode->classtype == instr->ct )
386 {
387 instr->process( world, pnode );
388 break;
389 }
390 }
391 }
392 }
393
394 VG_STATIC void world_link_nonlocal_gates( int index_a, int index_b )
395 {
396 vg_info( "Linking non-local gates\n" );
397 world_instance *a = &world_global.worlds[ index_a ],
398 *b = &world_global.worlds[ index_b ];
399
400 for( int i=0; i<a->nonlocalgate_count; i++ )
401 {
402 struct nonlocal_gate *ga = &a->nonlocal_gates[i];
403 struct classtype_gate *ga_inf = mdl_get_entdata( a->meta, ga->node );
404 const char *ga_name = mdl_pstr( a->meta, ga_inf->target );
405
406 for( int j=0; j<b->nonlocalgate_count; j++ )
407 {
408 struct nonlocal_gate *gb = &b->nonlocal_gates[j];
409 struct classtype_gate *gb_inf = mdl_get_entdata( b->meta, gb->node );
410 const char *gb_name = mdl_pstr( b->meta, gb_inf->target );
411
412 if( !strcmp( ga_name, gb_name ) )
413 {
414 vg_success( "Created longjump for ID '%s'\n", ga_name );
415
416 v4f qYflip;
417 q_axis_angle( qYflip, (v3f){0.0f,1.0f,0.0f}, VG_PIf );
418
419 /* TODO: Gates are created very wonkily. refactor. */
420 ga->target_map_index = index_b;
421 gb->target_map_index = index_a;
422 ga->working = 1;
423 gb->working = 1;
424
425 v4_copy( ga->node->q, ga->gate.q[0] );
426 v4_copy( gb->node->q, ga->gate.q[1] );
427 v3_copy( ga->node->co, ga->gate.co[0] );
428 v3_copy( gb->node->co, ga->gate.co[1] );
429
430 v4_copy( gb->node->q, gb->gate.q[0] );
431 v4_copy( ga->node->q, gb->gate.q[1] );
432 v3_copy( gb->node->co, gb->gate.co[0] );
433 v3_copy( ga->node->co, gb->gate.co[1] );
434
435 /* reverse B's direction */
436 q_mul( gb->gate.q[0], qYflip, gb->gate.q[0] );
437 q_mul( gb->gate.q[1], qYflip, gb->gate.q[1] );
438 q_normalize( gb->gate.q[0] );
439 q_normalize( gb->gate.q[1] );
440
441 gate_transform_update( &ga->gate );
442 gate_transform_update( &gb->gate );
443 }
444 }
445 }
446 }
447
448 VG_STATIC float colour_luminance( v3f v )
449 {
450 return v3_dot( v, (v3f){0.2126f, 0.7152f, 0.0722f} );
451 }
452
453 VG_STATIC float calc_light_influence( world_instance *world, v3f position,
454 int light )
455 {
456 struct world_light *world_light = &world->lights[ light ];
457 struct classtype_world_light *inf = world_light->inf;
458
459 v3f light_delta;
460 v3_sub( world_light->node->co, position, light_delta );
461 v3_muls( light_delta, 10.0f, light_delta );
462
463 float quadratic = v3_dot( light_delta, light_delta ),
464 attenuation = 1.0f/( 1.0f + quadratic );
465
466 float quadratic_light = attenuation * colour_luminance( inf->colour );
467
468 if( (inf->type == k_light_type_point) ||
469 (inf->type == k_light_type_point_nighttime_only) )
470 {
471 return quadratic_light;
472 }
473 else if( (inf->type == k_light_type_spot) ||
474 (inf->type == k_light_type_spot_nighttime_only) )
475 {
476 v3f dir;
477 q_mulv( world_light->node->q, (v3f){0.0f,1.0f,0.0f}, dir );
478
479 float spot_theta = vg_maxf( 0.0f, v3_dot( light_delta, dir ) ),
480 falloff = spot_theta >= 0.0f? 1.0f: 0.0f;
481
482 return quadratic_light * falloff;
483 }
484 else
485 return 0.0f;
486 }
487
488 VG_STATIC void world_generate( world_instance *world )
489 {
490 /*
491 * Compile meshes into the world scenes
492 */
493 world->scene_geo = scene_init( world_global.generic_heap, 320000, 1200000 );
494
495 m4x3f midentity;
496 m4x3_identity( midentity );
497
498 /*
499 * Generate scene: collidable geometry
500 * ----------------------------------------------------------------
501 */
502
503 vg_info( "Generating collidable geometry\n" );
504
505
506 for( int i=0; i<world->material_count; i++ )
507 {
508 struct world_material *mat = &world->materials[ i ];
509
510 if( mat->info.flags & k_material_flag_collision )
511 world_add_all_if_material( midentity, world->scene_geo, world->meta, i );
512
513 scene_copy_slice( world->scene_geo, &mat->sm_geo );
514 }
515
516 /* compress that bad boy */
517 world->scene_geo = scene_fix( world_global.generic_heap, world->scene_geo );
518
519 vg_acquire_thread_sync();
520 {
521 scene_upload( world->scene_geo, &world->mesh_geo );
522 }
523 vg_release_thread_sync();
524
525 /* setup spacial mapping and rigidbody */
526 world->geo_bh = scene_bh_create( world_global.generic_heap,
527 world->scene_geo );
528
529 v3_zero( world->rb_geo.co );
530 q_identity( world->rb_geo.q );
531
532 world->rb_geo.type = k_rb_shape_scene;
533 world->rb_geo.inf.scene.bh_scene = world->geo_bh;
534 world->rb_geo.is_world = 1;
535 rb_init( &world->rb_geo );
536
537 /*
538 * Generate scene: non-collidable geometry
539 * ----------------------------------------------------------------
540 */
541 vg_info( "Generating non-collidable geometry\n" );
542
543 world->scene_no_collide = scene_init( world_global.generic_heap,
544 200000, 500000 );
545
546 for( int i=0; i<world->material_count; i++ )
547 {
548 struct world_material *mat = &world->materials[ i ];
549
550 if( !(mat->info.flags & k_material_flag_collision) )
551 {
552 world_add_all_if_material( midentity, world->scene_no_collide,
553 world->meta, i );
554 }
555
556 if( mat->info.flags & k_material_flag_grow_grass )
557 world_apply_procedural_foliage( world, mat );
558
559 scene_copy_slice( world->scene_no_collide, &mat->sm_no_collide );
560 }
561
562 /* upload and free that */
563 vg_acquire_thread_sync();
564 {
565 scene_upload( world->scene_no_collide, &world->mesh_no_collide );
566 }
567 vg_release_thread_sync();
568
569 vg_linear_del( world_global.generic_heap, world->scene_no_collide );
570 world->scene_no_collide = NULL;
571 }
572
573 float fsd_cone_infinite( v3f p, v2f c )
574 {
575 v2f q = { v2_length( (v2f){ p[0], p[2] } ), -p[1] };
576 float s = vg_maxf( 0.0f, v2_dot( q, c ) );
577
578 v2f v0;
579 v2_muls( c, s, v0 );
580 v2_sub( q, v0, v0 );
581
582 float d = v2_length( v0 );
583 return d * ((q[0]*c[1]-q[1]*c[0]<0.0f)?-1.0f:1.0f);
584 }
585
586 VG_STATIC void world_compute_light_indices( world_instance *world )
587 {
588 /* light cubes */
589 v3f cubes_min, cubes_max;
590 v3_muls( world->scene_geo->bbx[0], 1.0f/k_light_cube_size, cubes_min );
591 v3_muls( world->scene_geo->bbx[1], 1.0f/k_light_cube_size, cubes_max );
592
593 v3_sub( cubes_min, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_min );
594 v3_add( cubes_max, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_max );
595
596 v3_floor( cubes_min, cubes_min );
597 v3_floor( cubes_max, cubes_max );
598
599 v3i icubes_min, icubes_max;
600
601 for( int i=0; i<3; i++ )
602 {
603 icubes_min[i] = cubes_min[i];
604 icubes_max[i] = cubes_max[i];
605 }
606
607 v3i icubes_count;
608 v3i_sub( icubes_max, icubes_min, icubes_count );
609
610 for( int i=0; i<3; i++ )
611 {
612 icubes_count[i] = VG_MIN( 128, icubes_count[i]+1 );
613 cubes_max[i] = icubes_min[i] + icubes_count[i];
614 }
615
616 v3_muls( cubes_min, k_light_cube_size, cubes_min );
617 v3_muls( cubes_max, k_light_cube_size, cubes_max );
618
619 for( int i=0; i<3; i++ )
620 {
621 float range = cubes_max[i]-cubes_min[i];
622 world->ub_lighting.g_cube_inv_range[i] = 1.0f / range;
623 world->ub_lighting.g_cube_inv_range[i] *= (float)icubes_count[i];
624
625 vg_info( "cubes[%d]: %d\n", i, icubes_count[i] );
626 }
627
628 int total_cubes = icubes_count[0]*icubes_count[1]*icubes_count[2];
629
630 u32 *cubes_index = vg_linear_alloc( world_global.generic_heap,
631 total_cubes * sizeof(u32) * 2.0f );
632
633 vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n",
634 total_cubes, cubes_min[0], -cubes_min[2], cubes_min[1],
635 cubes_max[0], -cubes_max[2], cubes_max[1] );
636
637 v3_copy( cubes_min, world->ub_lighting.g_cube_min );
638
639 v3f cube_size;
640 v3_div( (v3f){1.0f,1.0f,1.0f}, world->ub_lighting.g_cube_inv_range,
641 cube_size );
642 float bound_radius = v3_length( cube_size );
643
644 for( int iz = 0; iz<icubes_count[2]; iz ++ )
645 {
646 for( int iy = 0; iy<icubes_count[1]; iy++ )
647 {
648 for( int ix = 0; ix<icubes_count[0]; ix++ )
649 {
650 boxf bbx;
651 v3_div( (v3f){ ix, iy, iz }, world->ub_lighting.g_cube_inv_range,
652 bbx[0] );
653 v3_div( (v3f){ ix+1, iy+1, iz+1 },
654 world->ub_lighting.g_cube_inv_range,
655 bbx[1] );
656
657 v3_add( bbx[0], world->ub_lighting.g_cube_min, bbx[0] );
658 v3_add( bbx[1], world->ub_lighting.g_cube_min, bbx[1] );
659
660 v3f center;
661 v3_add( bbx[0], bbx[1], center );
662 v3_muls( center, 0.5f, center );
663
664 u32 indices[6] = { 0, 0, 0, 0, 0, 0 };
665 u32 count = 0;
666
667 float influences[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
668 const int N = vg_list_size( influences );
669
670 for( int j=0; j<world->light_count; j ++ )
671 {
672 struct world_light *light = &world->lights[j];
673 v3f closest;
674 closest_point_aabb( light->node->co, bbx, closest );
675
676 float dist = v3_dist( closest, light->node->co ),
677 influence = 1.0f/(dist+1.0f);
678
679 if( dist > light->inf->range )
680 continue;
681
682 if( (light->inf->type == k_light_type_spot) ||
683 (light->inf->type == k_light_type_spot_nighttime_only) )
684 {
685 v3f local;
686 m4x3_mulv( light->inverse_world, center, local );
687
688 float r = fsd_cone_infinite( local, light->angle_sin_cos );
689
690 if( r > bound_radius )
691 continue;
692 }
693
694 int best_pos = N;
695 for( int k=best_pos-1; k>=0; k -- )
696 if( influence > influences[k] )
697 best_pos = k;
698
699 if( best_pos < N )
700 {
701 for( int k=N-1; k>best_pos; k -- )
702 {
703 influences[k] = influences[k-1];
704 indices[k] = indices[k-1];
705 }
706
707 influences[best_pos] = influence;
708 indices[best_pos] = j;
709 }
710 }
711
712 for( int j=0; j<N; j++ )
713 if( influences[j] > 0.0f )
714 count ++;
715
716 int base_index = iz * (icubes_count[0]*icubes_count[1]) +
717 iy * (icubes_count[0]) +
718 ix;
719
720 int lower_count = VG_MIN( 3, count );
721 u32 packed_index_lower = lower_count;
722 packed_index_lower |= indices[0]<<2;
723 packed_index_lower |= indices[1]<<12;
724 packed_index_lower |= indices[2]<<22;
725
726 int upper_count = VG_MAX( 0, count - lower_count );
727 u32 packed_index_upper = upper_count;
728 packed_index_upper |= indices[3]<<2;
729 packed_index_upper |= indices[4]<<12;
730 packed_index_upper |= indices[5]<<22;
731
732 cubes_index[ base_index*2 + 0 ] = packed_index_lower;
733 cubes_index[ base_index*2 + 1 ] = packed_index_upper;
734 }
735 }
736 }
737
738 vg_acquire_thread_sync();
739
740 glGenTextures( 1, &world->tex_light_cubes );
741 glBindTexture( GL_TEXTURE_3D, world->tex_light_cubes );
742 glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI,
743 icubes_count[0], icubes_count[1], icubes_count[2],
744 0, GL_RG_INTEGER, GL_UNSIGNED_INT, cubes_index );
745 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
746 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
747
748 vg_linear_del( world_global.generic_heap, cubes_index );
749
750 vg_release_thread_sync();
751 }
752
753 VG_STATIC int reset_player( int argc, char const *argv[] );
754 VG_STATIC void world_post_process( world_instance *world )
755 {
756 /* initialize audio if need be */
757 audio_lock();
758 for( int i=0; i<world->audio_things_count; i++ )
759 {
760 struct world_audio_thing *thingy = &world->audio_things[ i ];
761
762 if( thingy->flags & AUDIO_FLAG_AUTO_START )
763 {
764 audio_channel *ch =
765 audio_request_channel( &thingy->temp_embedded_clip, thingy->flags );
766
767 audio_channel_edit_volume( ch, thingy->volume, 1 );
768 audio_channel_set_spacial( ch, thingy->pos, thingy->range );
769
770 if( !(ch->flags & AUDIO_FLAG_LOOP) )
771 ch = audio_relinquish_channel( ch );
772 }
773 }
774 audio_unlock();
775
776 world_compute_light_indices( world );
777
778 vg_acquire_thread_sync();
779 {
780 /* create scene lighting buffer */
781
782 u32 size = VG_MAX(world->light_count,1) * sizeof(float)*12;
783
784 vg_info( "Upload %ubytes (lighting)\n", size );
785
786 glGenBuffers( 1, &world->tbo_light_entities );
787 glBindBuffer( GL_TEXTURE_BUFFER, world->tbo_light_entities );
788 glBufferData( GL_TEXTURE_BUFFER, size, NULL, GL_DYNAMIC_DRAW );
789
790 /* buffer layout
791 *
792 * colour position direction (spots)
793 * | . . . . | . . . . | . . . . |
794 * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da |
795 *
796 */
797
798 v4f *light_dst = glMapBuffer( GL_TEXTURE_BUFFER, GL_WRITE_ONLY );
799
800 for( int i=0; i<world->light_count; i++ )
801 {
802 struct world_light *light = &world->lights[i];
803 struct classtype_world_light *inf = light->inf;
804
805 /* colour + night */
806 v3_muls( inf->colour, inf->colour[3] * 2.0f, light_dst[i*3+0] );
807 light_dst[i*3+0][3] = -1.0f;
808
809 if( (inf->type == k_light_type_spot_nighttime_only) ||
810 (inf->type == k_light_type_point_nighttime_only ) )
811 {
812 u32 hash = (i * 29986577) & 0xff;
813 float switch_on = hash;
814 switch_on *= (1.0f/255.0f);
815
816 light_dst[i*3+0][3] = 0.44f + switch_on * 0.015f;
817 }
818
819 /* position + 1/range^2 */
820 v3_copy( light->node->co, light_dst[i*3+1] );
821 light_dst[i*3+1][3] = 1.0f/(inf->range*inf->range);
822
823 /* direction + angle */
824 q_mulv( light->node->q, (v3f){0.0f,-1.0f,0.0f}, light_dst[i*3+2]);
825 light_dst[i*3+2][3] = cosf( inf->angle );
826 }
827
828 glUnmapBuffer( GL_TEXTURE_BUFFER );
829
830 glGenTextures( 1, &world->tex_light_entities );
831 glBindTexture( GL_TEXTURE_BUFFER, world->tex_light_entities );
832 glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, world->tbo_light_entities );
833
834
835 /* Upload lighting uniform buffer */
836 if( world->water.enabled )
837 v4_copy( world->water.plane, world->ub_lighting.g_water_plane );
838
839 v4f info_vec;
840 v3f *bounds = world->scene_geo->bbx;
841
842 info_vec[0] = bounds[0][0];
843 info_vec[1] = bounds[0][2];
844 info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]);
845 info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]);
846 v4_copy( info_vec, world->ub_lighting.g_depth_bounds );
847
848
849 /*
850 * Rendering the depth map
851 */
852 camera ortho;
853
854 v3f extent;
855 v3_sub( world->scene_geo->bbx[1], world->scene_geo->bbx[0], extent );
856
857 float fl = world->scene_geo->bbx[0][0],
858 fr = world->scene_geo->bbx[1][0],
859 fb = world->scene_geo->bbx[0][2],
860 ft = world->scene_geo->bbx[1][2],
861 rl = 1.0f / (fr-fl),
862 tb = 1.0f / (ft-fb);
863
864 m4x4_zero( ortho.mtx.p );
865 ortho.mtx.p[0][0] = 2.0f * rl;
866 ortho.mtx.p[2][1] = 2.0f * tb;
867 ortho.mtx.p[3][0] = (fr + fl) * -rl;
868 ortho.mtx.p[3][1] = (ft + fb) * -tb;
869 ortho.mtx.p[3][3] = 1.0f;
870 m4x3_identity( ortho.transform );
871 camera_update_view( &ortho );
872 camera_finalize( &ortho );
873
874 glDisable(GL_DEPTH_TEST);
875 glDisable(GL_BLEND);
876 glDisable(GL_CULL_FACE);
877 render_fb_bind( &world->heightmap );
878 shader_blitcolour_use();
879 shader_blitcolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
880 render_fsquad();
881
882 glEnable(GL_BLEND);
883 glBlendFunc(GL_ONE, GL_ONE);
884 glBlendEquation(GL_MAX);
885
886 render_world_position( world, &ortho );
887 glDisable(GL_BLEND);
888 glEnable(GL_DEPTH_TEST);
889 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
890
891 /* upload full buffer */
892 glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
893 glBufferSubData( GL_UNIFORM_BUFFER, 0,
894 sizeof(struct ub_world_lighting), &world->ub_lighting );
895 }
896
897 vg_release_thread_sync();
898
899 #if 0
900 /*
901 * Setup scene collider
902 */
903 reset_player( 1, (const char *[]){"start"} );
904 #endif
905 }
906
907 VG_STATIC void world_process_resources( world_instance *world )
908 {
909 vg_info( "Loading textures\n" );
910 world->texture_count = world->meta->info.texture_count;
911 world->textures = vg_linear_alloc( world_global.generic_heap,
912 sizeof(GLuint)*world->texture_count );
913
914 vg_acquire_thread_sync();
915 {
916 /* error texture */
917 world->textures[0] = vg_tex2d_new();
918 vg_tex2d_set_error();
919 vg_tex2d_nearest();
920 vg_tex2d_repeat();
921
922 for( int i=1; i<world->texture_count; i++ )
923 {
924 mdl_texture *tex = &world->meta->texture_buffer[i];
925
926 if( !tex->pack_offset )
927 {
928 vg_release_thread_sync();
929 vg_fatal_exit_loop( "World models must have packed textures!" );
930 }
931
932 vg_linear_clear( vg_mem.scratch );
933 world->textures[i] = vg_tex2d_new();
934 vg_tex2d_set_error();
935 vg_tex2d_qoi( world->meta->pack + tex->pack_offset, tex->pack_length,
936 mdl_pstr( world->meta, tex->pstr_name ));
937 vg_tex2d_nearest();
938 vg_tex2d_repeat();
939 }
940 }
941 vg_release_thread_sync();
942
943 vg_info( "Loading materials\n" );
944
945 u32 size = sizeof(struct world_material) * world->meta->info.material_count;
946 world->materials = vg_linear_alloc( world_global.generic_heap, size );
947
948 world->material_count = world->meta->info.material_count;
949 memset( world->materials, 0, size );
950
951 for( int i=1; i<world->material_count; i++ )
952 world->materials[i].info = world->meta->material_buffer[i];
953
954 /* error material */
955 struct world_material *errmat = &world->materials[0];
956 v4_copy( (v4f){ 1.0f,0.0f,0.0f,1.0f }, errmat->info.colour );
957 v4_copy( (v4f){ 1.0f,0.0f,0.0f,1.0f }, errmat->info.colour1 );
958 errmat->info.flags = 0x00;
959 errmat->info.pstr_name = 0; /* useless? */
960 errmat->info.shader = -1;
961 errmat->info.tex_decal = 0;
962 errmat->info.tex_diffuse = 0;
963 errmat->info.tex_normal = 0;
964 }
965
966 VG_STATIC void world_unload( world_instance *world )
967 {
968 vg_acquire_thread_sync();
969
970 /* free meshes */
971 mesh_free( &world->mesh_route_lines );
972 mesh_free( &world->mesh_geo );
973 mesh_free( &world->mesh_no_collide );
974
975 glDeleteBuffers( 1, &world->tbo_light_entities );
976 glDeleteTextures( 1, &world->tex_light_entities );
977 glDeleteTextures( 1, &world->tex_light_cubes );
978
979 /* FIXME: CANT DO THIS HERE */
980 world_global.time = 0.0;
981 world_global.rewind_from = 0.0;
982 world_global.rewind_to = 0.0;
983 world_global.last_use = 0.0;
984 world_global.active_gate = 0;
985 world_global.current_run_version = 2;
986 world_global.active_route_board = 0;
987
988 for( int i=0; i<vg_list_size(world_global.ui_bars); i++ )
989 {
990 struct route_ui_bar *uib = &world_global.ui_bars[i];
991 uib->segment_start = 0;
992 uib->segment_count = 0;
993 uib->fade_start = 0;
994 uib->fade_count = 0;
995 uib->fade_timer_start = 0.0;
996 uib->xpos = 0.0f;
997 }
998
999 /* delete textures and meshes */
1000 glDeleteTextures( world->texture_count, world->textures );
1001
1002 /* delete the entire block of memory */
1003 /* FIXME: WE CANT DO THIS SHIT ANYMORE, NEED TO DEALLOC FROM ABOVE */
1004 #if 0
1005 vg_linear_clear( world->dynamic_vgl );
1006 vg_linear_clear( world->audio_vgl );
1007 #endif
1008
1009
1010 vg_release_thread_sync();
1011 }
1012
1013 VG_STATIC void world_clean( world_instance *world )
1014 {
1015 /* clean dangling pointers */
1016 world->meta = NULL;
1017
1018 /*
1019 * TODO: Theres probably a better way to do this?
1020 */
1021
1022 world->textures = NULL;
1023 world->texture_count = 0;
1024 world->materials = NULL;
1025 world->material_count = 0;
1026
1027 world->scene_geo = NULL;
1028 world->scene_no_collide = NULL;
1029 world->scene_lines = NULL;
1030
1031 world->geo_bh = NULL;
1032 world->trigger_bh = NULL;
1033 world->audio_bh = NULL;
1034
1035 world->spawns = NULL;
1036 world->spawn_count = 0;
1037
1038 world->audio_things = NULL;
1039 world->audio_things_count = 0;
1040
1041 world->triggers = NULL;
1042 world->trigger_count = 0;
1043
1044 world->lights = NULL;
1045 world->light_count = 0;
1046
1047 #if 0
1048 world->logic_relays = NULL;
1049 world->relay_count = 0;
1050 #endif
1051
1052 world->logic_achievements = NULL;
1053 world->achievement_count = 0;
1054
1055 world->nodes = NULL;
1056 world->node_count = 0;
1057
1058 world->routes = NULL;
1059 world->route_count = 0;
1060
1061 world->gates = NULL;
1062 world->gate_count = 0;
1063
1064 world->collectors = NULL;
1065 world->collector_count = 0;
1066
1067 world->soundscapes = NULL;
1068 world->soundscape_count = 0;
1069
1070 world->logic_bricks = NULL;
1071 world->logic_brick_count = 0;
1072
1073 world->nonlocal_gates = NULL;
1074 world->nonlocalgate_count = 0;
1075
1076 world->water.enabled = 0;
1077
1078
1079 /* default lighting conditions
1080 * -------------------------------------------------------------*/
1081 struct ub_world_lighting *state = &world->ub_lighting;
1082
1083 state->g_light_preview = 0;
1084 state->g_shadow_samples = 8;
1085 state->g_water_fog = 0.04f;
1086
1087 v4_zero( state->g_water_plane );
1088 v4_zero( state->g_depth_bounds );
1089
1090 state->g_shadow_length = 9.50f;
1091 state->g_shadow_spread = 0.65f;
1092
1093 v3_copy( (v3f){0.37f, 0.54f, 0.97f}, state->g_daysky_colour );
1094 v3_copy( (v3f){0.03f, 0.05f, 0.20f}, state->g_nightsky_colour );
1095 v3_copy( (v3f){1.00f, 0.32f, 0.01f}, state->g_sunset_colour );
1096 v3_copy( (v3f){0.13f, 0.17f, 0.35f}, state->g_ambient_colour );
1097 v3_copy( (v3f){0.25f, 0.17f, 0.51f}, state->g_sunset_ambient );
1098 v3_copy( (v3f){1.10f, 0.89f, 0.35f}, state->g_sun_colour );
1099 }
1100
1101 VG_STATIC void world_load( world_instance *world, const char *path )
1102 {
1103 world_unload( world );
1104 world_clean( world );
1105
1106 world->meta = mdl_load_full( world_global.generic_heap, path );
1107 vg_info( "Loading world: %s\n", path );
1108
1109 /* process resources from pack */
1110 world_process_resources( world );
1111
1112 /* dynamic allocations */
1113 world_ents_allocate( world );
1114 world_routes_allocate( world );
1115
1116 /* meta processing */
1117 world_routes_process( world );
1118 world_entities_process( world );
1119
1120 /* main bulk */
1121 world_generate( world );
1122 world_routes_generate( world );
1123 world_post_process( world );
1124 }
1125
1126 #endif /* WORLD_GEN_H */