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( int i
=0; i
<mdl
->info
.node_count
; i
++ )
17 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
19 for( int j
=0; j
<pnode
->submesh_count
; j
++ )
21 mdl_submesh
*sm
= mdl_node_submesh( mdl
, pnode
, j
);
22 if( sm
->material_id
== id
)
25 mdl_node_transform( pnode
, transform2
);
26 m4x3_mul( transform
, transform2
, transform2
);
28 scene_add_mdl_submesh( pscene
, mdl
, sm
, transform2
);
34 VG_STATIC
void world_add_blob( world_instance
*world
,
35 scene
*pscene
, ray_hit
*hit
)
38 v4f qsurface
, qrandom
;
41 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, hit
->normal
, axis
);
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] );
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
} }
60 const u32 indices
[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 };
62 if( pscene
->vertex_count
+ vg_list_size(verts
) > pscene
->max_vertices
)
63 vg_fatal_exit_loop( "Scene vertex buffer overflow" );
65 if( pscene
->indice_count
+ vg_list_size(indices
) > pscene
->max_indices
)
66 vg_fatal_exit_loop( "Scene index buffer overflow" );
68 scene_vert
*dst_verts
= &pscene
->arrvertices
[ pscene
->vertex_count
];
69 u32
*dst_indices
= &pscene
->arrindices
[ pscene
->indice_count
];
71 scene_vert
*ref
= &world
->scene_geo
->arrvertices
[ hit
->tri
[0] ];
73 for( u32 i
=0; i
<vg_list_size(verts
); i
++ )
75 scene_vert
*pvert
= &dst_verts
[ i
],
78 m4x3_mulv( transform
, src
->co
, pvert
->co
);
79 scene_vert_pack_norm( pvert
, transform
[1] );
81 v2_copy( ref
->uv
, pvert
->uv
);
84 for( u32 i
=0; i
<vg_list_size(indices
); i
++ )
85 dst_indices
[i
] = indices
[i
] + pscene
->vertex_count
;
87 pscene
->vertex_count
+= vg_list_size(verts
);
88 pscene
->indice_count
+= vg_list_size(indices
);
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
)
95 if( vg
.quality_profile
== k_quality_profile_low
)
98 vg_info( "Applying foliage (%u)\n", mat
->info
.pstr_name
);
100 vg_linear_clear( vg_mem
.scratch
);
102 mdl_context
*mfoliage
=
103 mdl_load_full( vg_mem
.scratch
, "models/rs_foliage.mdl");
106 v3_sub( world
->scene_geo
->bbx
[1], world
->scene_geo
->bbx
[0], volume
);
109 mdl_node
*mblob
= mdl_node_from_name( mfoliage
, "blob" );
110 mdl_submesh
*sm_blob
= mdl_node_submesh( mfoliage
, mblob
, 0 );
114 float area
= volume
[0]*volume
[2];
115 u32 particles
= 0.08f
* area
;
117 vg_info( "Map area: %f. Max particles: %u\n", area
, particles
);
119 for( int i
=0;i
<particles
;i
++ )
122 v3_mul( volume
, (v3f
){ vg_randf(), 1000.0f
, vg_randf() }, pos
);
124 v3_add( pos
, world
->scene_geo
->bbx
[0], pos
);
129 if( ray_world( world
, pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
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
))
134 world_add_blob( world
, world
->scene_no_collide
, &hit
);
140 vg_info( "%d foliage models added\n", count
);
143 VG_STATIC
void world_ents_allocate( world_instance
*world
)
145 vg_info( "Allocating entities\n" );
147 /* count entites to allocate buffers for them.
148 * maybe in the future we just store these numbers in the model file...
150 * TODO: use this in world_routes too */
163 (void*)&world
->spawns
,
164 sizeof(struct respawn_point
)
168 (void*)&world
->audio_things
,
169 sizeof(struct world_audio_thing
)
173 (void*)&world
->triggers
,
174 sizeof(struct trigger_zone
)
177 k_classtype_logic_relay
,
178 (void*)&world
->logic_relays
,
179 sizeof(struct logic_relay
)
182 k_classtype_logic_achievement
,
183 (void*)&world
->logic_achievements
,
184 sizeof(struct logic_achievement
)
187 k_classtype_world_light
,
188 (void*)&world
->lights
,
189 sizeof(struct world_light
)
192 k_classtype_nonlocal_gate
,
193 (void*)&world
->nonlocal_gates
,
194 sizeof(struct nonlocal_gate
)
198 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
199 entity_counts
[i
].count
= 0;
201 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
203 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
205 for( int j
=0; j
<vg_list_size(entity_counts
); j
++ )
207 if( pnode
->classtype
== entity_counts
[j
].ct
)
209 pnode
->sub_uid
= entity_counts
[j
].count
;
210 entity_counts
[j
].count
++;
216 for( int i
=0; i
<vg_list_size(entity_counts
); i
++ )
218 struct countable
*counter
= &entity_counts
[i
];
220 u32 bufsize
= counter
->item_size
*counter
->count
;
221 *counter
->to_allocate
= vg_linear_alloc( world_global
.generic_heap
,
226 VG_STATIC
void world_pct_spawn( world_instance
*world
, mdl_node
*pnode
)
228 struct respawn_point
*rp
= &world
->spawns
[ world
->spawn_count
++ ];
230 v3_copy( pnode
->co
, rp
->co
);
231 v4_copy( pnode
->q
, rp
->q
);
232 rp
->name
= mdl_pstr( world
->meta
, pnode
->pstr_name
);
235 VG_STATIC
void world_pct_water( world_instance
*world
, mdl_node
*pnode
)
237 if( world
->water
.enabled
)
239 vg_warn( "Multiple water surfaces in level! ('%s')\n",
240 mdl_pstr( world
->meta
, pnode
->pstr_name
));
244 world
->water
.enabled
= 1;
245 water_set_surface( world
, pnode
->co
[1] );
248 VG_STATIC
void world_pct_audio( world_instance
*world
, mdl_node
*pnode
)
250 struct world_audio_thing
*thing
= &world
->audio_things
[
251 world
->audio_things_count
];
253 memset( thing
, 0, sizeof(struct world_audio_thing
) );
254 struct classtype_audio
*aud
= mdl_get_entdata( world
->meta
, pnode
);
256 v3_copy( pnode
->co
, thing
->pos
);
258 if( aud
->flags
& AUDIO_FLAG_SPACIAL_3D
)
259 thing
->volume
= aud
->volume
* pnode
->s
[0];
261 thing
->volume
= aud
->volume
;
263 thing
->flags
= aud
->flags
;
264 thing
->temp_embedded_clip
.path
= mdl_pstr( world
->meta
, aud
->pstr_file
);
265 thing
->temp_embedded_clip
.flags
= aud
->flags
;
267 audio_clip_load( &thing
->temp_embedded_clip
, world_global
.generic_heap
);
268 thing
->player
.name
= mdl_pstr( world
->meta
, pnode
->pstr_name
);
269 thing
->player
.enqued
= 0;
271 pnode
->sub_uid
= world
->audio_things_count
;
272 world
->audio_things_count
++;
275 VG_STATIC
void world_pct_trigger( world_instance
*world
, mdl_node
*pnode
)
277 struct trigger_zone
*trigger
= &world
->triggers
[ world
->trigger_count
];
278 struct classtype_trigger
*inf
= mdl_get_entdata( world
->meta
, pnode
);
282 mdl_node
*target_node
= mdl_node_from_id( world
->meta
, inf
->target
);
284 trigger
->target
.sub_id
= target_node
->sub_uid
;
285 trigger
->target
.classtype
= target_node
->classtype
;
289 vg_warn( "Trigger with no target...\n" );
293 mdl_node_transform( pnode
, trigger
->transform
);
294 m4x3_invert_full( trigger
->transform
, trigger
->inv_transform
);
296 world
->trigger_count
++;
300 VG_STATIC
void world_pct_relay( world_instance
*world
, mdl_node
*pnode
)
302 struct logic_relay
*relay
= &world
->logic_relays
[ world
->relay_count
];
303 struct classtype_logic_relay
*inf
= mdl_get_entdata( world
->meta
, pnode
);
305 relay
->target_count
= 0;
307 for( int i
=0; i
<vg_list_size(relay
->targets
); i
++ )
309 if( inf
->targets
[i
] )
311 struct relay_target
*target
= &relay
->targets
[relay
->target_count
++];
312 mdl_node
*other
= mdl_node_from_id( world
->meta
, inf
->targets
[i
] );
314 target
->classtype
= other
->classtype
;
315 target
->sub_id
= other
->sub_uid
;
319 v3_copy( pnode
->co
, relay
->pos
);
320 world
->relay_count
++;
324 VG_STATIC
void world_pct_achievement( world_instance
*world
, mdl_node
*pnode
)
326 struct logic_achievement
*ach
=
327 &world
->logic_achievements
[ world
->achievement_count
];
328 struct classtype_logic_achievement
*inf
=
329 mdl_get_entdata( world
->meta
, pnode
);
331 v3_copy( pnode
->co
, ach
->pos
);
332 ach
->achievement_id
= mdl_pstr( world
->meta
, inf
->pstr_name
);
335 world
->achievement_count
++;
338 VG_STATIC
void world_pct_world_light( world_instance
*world
, mdl_node
*pnode
)
340 struct world_light
*light
= &world
->lights
[ world
->light_count
++ ];
342 light
->inf
= mdl_get_entdata( world
->meta
, pnode
);
344 q_m3x3( pnode
->q
, light
->inverse_world
);
345 v3_copy( pnode
->co
, light
->inverse_world
[3] );
346 m4x3_invert_affine( light
->inverse_world
, light
->inverse_world
);
348 light
->angle_sin_cos
[0] = sinf( light
->inf
->angle
* 0.5f
);
349 light
->angle_sin_cos
[1] = cosf( light
->inf
->angle
* 0.5f
);
352 VG_STATIC
void world_pct_nonlocal_gate( world_instance
*world
, mdl_node
*pnode
)
354 struct nonlocal_gate
*gate
= &world
->nonlocal_gates
[
355 world
->nonlocalgate_count
++ ];
356 struct classtype_gate
*inf
= mdl_get_entdata( world
->meta
, pnode
);
360 gate
->target_map_index
= 0;
361 v2_copy( inf
->dims
, gate
->gate
.dims
);
364 VG_STATIC
void world_entities_process( world_instance
*world
)
366 struct entity_instruction
369 void (*process
)( world_instance
*world
, mdl_node
*pnode
);
371 entity_instructions
[] =
373 { k_classtype_spawn
, world_pct_spawn
},
374 { k_classtype_water
, world_pct_water
},
375 { k_classtype_audio
, world_pct_audio
},
376 { k_classtype_trigger
, world_pct_trigger
},
377 { k_classtype_logic_relay
, world_pct_relay
},
378 { k_classtype_logic_achievement
, world_pct_achievement
},
379 { k_classtype_world_light
, world_pct_world_light
},
380 { k_classtype_nonlocal_gate
, world_pct_nonlocal_gate
}
383 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
385 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
387 for( int j
=0; j
<vg_list_size(entity_instructions
); j
++ )
389 struct entity_instruction
*instr
= &entity_instructions
[j
];
391 if( pnode
->classtype
== instr
->ct
)
393 instr
->process( world
, pnode
);
400 VG_STATIC
void world_link_nonlocal_gates( int index_a
, int index_b
)
402 vg_info( "Linking non-local gates\n" );
403 world_instance
*a
= &world_global
.worlds
[ index_a
],
404 *b
= &world_global
.worlds
[ index_b
];
406 for( int i
=0; i
<a
->nonlocalgate_count
; i
++ )
408 struct nonlocal_gate
*ga
= &a
->nonlocal_gates
[i
];
409 struct classtype_gate
*ga_inf
= mdl_get_entdata( a
->meta
, ga
->node
);
410 const char *ga_name
= mdl_pstr( a
->meta
, ga_inf
->target
);
412 for( int j
=0; j
<b
->nonlocalgate_count
; j
++ )
414 struct nonlocal_gate
*gb
= &b
->nonlocal_gates
[j
];
415 struct classtype_gate
*gb_inf
= mdl_get_entdata( b
->meta
, gb
->node
);
416 const char *gb_name
= mdl_pstr( b
->meta
, gb_inf
->target
);
418 if( !strcmp( ga_name
, gb_name
) )
420 vg_success( "Created longjump for ID '%s'\n", ga_name
);
423 q_axis_angle( qYflip
, (v3f
){0.0f
,1.0f
,0.0f
}, VG_PIf
);
425 /* TODO: Gates are created very wonkily. refactor. */
426 ga
->target_map_index
= index_b
;
427 gb
->target_map_index
= index_a
;
431 v4_copy( ga
->node
->q
, ga
->gate
.q
[0] );
432 v4_copy( gb
->node
->q
, ga
->gate
.q
[1] );
433 v3_copy( ga
->node
->co
, ga
->gate
.co
[0] );
434 v3_copy( gb
->node
->co
, ga
->gate
.co
[1] );
436 v4_copy( gb
->node
->q
, gb
->gate
.q
[0] );
437 v4_copy( ga
->node
->q
, gb
->gate
.q
[1] );
438 v3_copy( gb
->node
->co
, gb
->gate
.co
[0] );
439 v3_copy( ga
->node
->co
, gb
->gate
.co
[1] );
441 /* reverse B's direction */
442 q_mul( gb
->gate
.q
[0], qYflip
, gb
->gate
.q
[0] );
443 q_mul( gb
->gate
.q
[1], qYflip
, gb
->gate
.q
[1] );
444 q_normalize( gb
->gate
.q
[0] );
445 q_normalize( gb
->gate
.q
[1] );
447 gate_transform_update( &ga
->gate
);
448 gate_transform_update( &gb
->gate
);
454 VG_STATIC
float colour_luminance( v3f v
)
456 return v3_dot( v
, (v3f
){0.2126f
, 0.7152f
, 0.0722f
} );
459 VG_STATIC
float calc_light_influence( world_instance
*world
, v3f position
,
462 struct world_light
*world_light
= &world
->lights
[ light
];
463 struct classtype_world_light
*inf
= world_light
->inf
;
466 v3_sub( world_light
->node
->co
, position
, light_delta
);
467 v3_muls( light_delta
, 10.0f
, light_delta
);
469 float quadratic
= v3_dot( light_delta
, light_delta
),
470 attenuation
= 1.0f
/( 1.0f
+ quadratic
);
472 float quadratic_light
= attenuation
* colour_luminance( inf
->colour
);
474 if( (inf
->type
== k_light_type_point
) ||
475 (inf
->type
== k_light_type_point_nighttime_only
) )
477 return quadratic_light
;
479 else if( (inf
->type
== k_light_type_spot
) ||
480 (inf
->type
== k_light_type_spot_nighttime_only
) )
483 q_mulv( world_light
->node
->q
, (v3f
){0.0f
,1.0f
,0.0f
}, dir
);
485 float spot_theta
= vg_maxf( 0.0f
, v3_dot( light_delta
, dir
) ),
486 falloff
= spot_theta
>= 0.0f
? 1.0f
: 0.0f
;
488 return quadratic_light
* falloff
;
494 VG_STATIC
void world_generate( world_instance
*world
)
497 * Compile meshes into the world scenes
499 world
->scene_geo
= scene_init( world_global
.generic_heap
, 320000, 1200000 );
502 m4x3_identity( midentity
);
505 * Generate scene: collidable geometry
506 * ----------------------------------------------------------------
509 vg_info( "Generating collidable geometry\n" );
512 for( int i
=0; i
<world
->material_count
; i
++ )
514 struct world_material
*mat
= &world
->materials
[ i
];
516 if( mat
->info
.flags
& k_material_flag_collision
)
517 world_add_all_if_material( midentity
, world
->scene_geo
, world
->meta
, i
);
519 scene_copy_slice( world
->scene_geo
, &mat
->sm_geo
);
522 /* compress that bad boy */
523 world
->scene_geo
= scene_fix( world_global
.generic_heap
, world
->scene_geo
);
525 vg_acquire_thread_sync();
527 scene_upload( world
->scene_geo
, &world
->mesh_geo
);
529 vg_release_thread_sync();
531 /* setup spacial mapping and rigidbody */
532 world
->geo_bh
= scene_bh_create( world_global
.generic_heap
,
535 v3_zero( world
->rb_geo
.co
);
536 q_identity( world
->rb_geo
.q
);
538 world
->rb_geo
.type
= k_rb_shape_scene
;
539 world
->rb_geo
.inf
.scene
.bh_scene
= world
->geo_bh
;
540 world
->rb_geo
.is_world
= 1;
541 rb_init( &world
->rb_geo
);
544 * Generate scene: non-collidable geometry
545 * ----------------------------------------------------------------
547 vg_info( "Generating non-collidable geometry\n" );
549 world
->scene_no_collide
= scene_init( world_global
.generic_heap
,
552 for( int i
=0; i
<world
->material_count
; i
++ )
554 struct world_material
*mat
= &world
->materials
[ i
];
556 if( !(mat
->info
.flags
& k_material_flag_collision
) )
558 world_add_all_if_material( midentity
, world
->scene_no_collide
,
562 if( mat
->info
.flags
& k_material_flag_grow_grass
)
563 world_apply_procedural_foliage( world
, mat
);
565 scene_copy_slice( world
->scene_no_collide
, &mat
->sm_no_collide
);
568 /* upload and free that */
569 vg_acquire_thread_sync();
571 scene_upload( world
->scene_no_collide
, &world
->mesh_no_collide
);
573 vg_release_thread_sync();
575 vg_linear_del( world_global
.generic_heap
, world
->scene_no_collide
);
576 world
->scene_no_collide
= NULL
;
579 float fsd_cone_infinite( v3f p
, v2f c
)
581 v2f q
= { v2_length( (v2f
){ p
[0], p
[2] } ), -p
[1] };
582 float s
= vg_maxf( 0.0f
, v2_dot( q
, c
) );
588 float d
= v2_length( v0
);
589 return d
* ((q
[0]*c
[1]-q
[1]*c
[0]<0.0f
)?-1.0f
:1.0f
);
592 VG_STATIC
void world_compute_light_indices( world_instance
*world
)
595 v3f cubes_min
, cubes_max
;
596 v3_muls( world
->scene_geo
->bbx
[0], 1.0f
/k_light_cube_size
, cubes_min
);
597 v3_muls( world
->scene_geo
->bbx
[1], 1.0f
/k_light_cube_size
, cubes_max
);
599 v3_sub( cubes_min
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_min
);
600 v3_add( cubes_max
, (v3f
){ 0.5f
, 0.5f
, 0.5f
}, cubes_max
);
602 v3_floor( cubes_min
, cubes_min
);
603 v3_floor( cubes_max
, cubes_max
);
605 v3i icubes_min
, icubes_max
;
607 for( int i
=0; i
<3; i
++ )
609 icubes_min
[i
] = cubes_min
[i
];
610 icubes_max
[i
] = cubes_max
[i
];
614 v3i_sub( icubes_max
, icubes_min
, icubes_count
);
616 for( int i
=0; i
<3; i
++ )
618 icubes_count
[i
] = VG_MIN( 128, icubes_count
[i
]+1 );
619 cubes_max
[i
] = icubes_min
[i
] + icubes_count
[i
];
622 v3_muls( cubes_min
, k_light_cube_size
, cubes_min
);
623 v3_muls( cubes_max
, k_light_cube_size
, cubes_max
);
625 for( int i
=0; i
<3; i
++ )
627 float range
= cubes_max
[i
]-cubes_min
[i
];
628 world
->ub_lighting
.g_cube_inv_range
[i
] = 1.0f
/ range
;
629 world
->ub_lighting
.g_cube_inv_range
[i
] *= (float)icubes_count
[i
];
631 vg_info( "cubes[%d]: %d\n", i
, icubes_count
[i
] );
634 int total_cubes
= icubes_count
[0]*icubes_count
[1]*icubes_count
[2];
636 u32
*cubes_index
= vg_linear_alloc( world_global
.generic_heap
,
637 total_cubes
* sizeof(u32
) * 2.0f
);
639 vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n",
640 total_cubes
, cubes_min
[0], -cubes_min
[2], cubes_min
[1],
641 cubes_max
[0], -cubes_max
[2], cubes_max
[1] );
643 v3_copy( cubes_min
, world
->ub_lighting
.g_cube_min
);
646 v3_div( (v3f
){1.0f
,1.0f
,1.0f
}, world
->ub_lighting
.g_cube_inv_range
,
648 float bound_radius
= v3_length( cube_size
);
650 for( int iz
= 0; iz
<icubes_count
[2]; iz
++ )
652 for( int iy
= 0; iy
<icubes_count
[1]; iy
++ )
654 for( int ix
= 0; ix
<icubes_count
[0]; ix
++ )
657 v3_div( (v3f
){ ix
, iy
, iz
}, world
->ub_lighting
.g_cube_inv_range
,
659 v3_div( (v3f
){ ix
+1, iy
+1, iz
+1 },
660 world
->ub_lighting
.g_cube_inv_range
,
663 v3_add( bbx
[0], world
->ub_lighting
.g_cube_min
, bbx
[0] );
664 v3_add( bbx
[1], world
->ub_lighting
.g_cube_min
, bbx
[1] );
667 v3_add( bbx
[0], bbx
[1], center
);
668 v3_muls( center
, 0.5f
, center
);
670 u32 indices
[6] = { 0, 0, 0, 0, 0, 0 };
673 float influences
[6] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
674 const int N
= vg_list_size( influences
);
676 for( int j
=0; j
<world
->light_count
; j
++ )
678 struct world_light
*light
= &world
->lights
[j
];
680 closest_point_aabb( light
->node
->co
, bbx
, closest
);
682 float dist
= v3_dist( closest
, light
->node
->co
),
683 influence
= 1.0f
/(dist
+1.0f
);
685 if( dist
> light
->inf
->range
)
688 if( (light
->inf
->type
== k_light_type_spot
) ||
689 (light
->inf
->type
== k_light_type_spot_nighttime_only
) )
692 m4x3_mulv( light
->inverse_world
, center
, local
);
694 float r
= fsd_cone_infinite( local
, light
->angle_sin_cos
);
696 if( r
> bound_radius
)
701 for( int k
=best_pos
-1; k
>=0; k
-- )
702 if( influence
> influences
[k
] )
707 for( int k
=N
-1; k
>best_pos
; k
-- )
709 influences
[k
] = influences
[k
-1];
710 indices
[k
] = indices
[k
-1];
713 influences
[best_pos
] = influence
;
714 indices
[best_pos
] = j
;
718 for( int j
=0; j
<N
; j
++ )
719 if( influences
[j
] > 0.0f
)
722 int base_index
= iz
* (icubes_count
[0]*icubes_count
[1]) +
723 iy
* (icubes_count
[0]) +
726 int lower_count
= VG_MIN( 3, count
);
727 u32 packed_index_lower
= lower_count
;
728 packed_index_lower
|= indices
[0]<<2;
729 packed_index_lower
|= indices
[1]<<12;
730 packed_index_lower
|= indices
[2]<<22;
732 int upper_count
= VG_MAX( 0, count
- lower_count
);
733 u32 packed_index_upper
= upper_count
;
734 packed_index_upper
|= indices
[3]<<2;
735 packed_index_upper
|= indices
[4]<<12;
736 packed_index_upper
|= indices
[5]<<22;
738 cubes_index
[ base_index
*2 + 0 ] = packed_index_lower
;
739 cubes_index
[ base_index
*2 + 1 ] = packed_index_upper
;
744 vg_acquire_thread_sync();
746 glGenTextures( 1, &world
->tex_light_cubes
);
747 glBindTexture( GL_TEXTURE_3D
, world
->tex_light_cubes
);
748 glTexImage3D( GL_TEXTURE_3D
, 0, GL_RG32UI
,
749 icubes_count
[0], icubes_count
[1], icubes_count
[2],
750 0, GL_RG_INTEGER
, GL_UNSIGNED_INT
, cubes_index
);
751 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
752 glTexParameteri( GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
754 vg_linear_del( world_global
.generic_heap
, cubes_index
);
756 vg_release_thread_sync();
759 VG_STATIC
int reset_player( int argc
, char const *argv
[] );
760 VG_STATIC
void world_post_process( world_instance
*world
)
762 /* initialize audio if need be */
764 for( int i
=0; i
<world
->audio_things_count
; i
++ )
766 struct world_audio_thing
*thingy
= &world
->audio_things
[ i
];
768 audio_player_init( &thingy
->player
);
769 audio_player_set_flags( &thingy
->player
, thingy
->flags
);
770 audio_player_set_vol( &thingy
->player
, thingy
->volume
);
771 audio_player_set_pan( &thingy
->player
, 0.0f
);
773 if( thingy
->flags
& AUDIO_FLAG_SPACIAL_3D
)
774 audio_player_set_position( &thingy
->player
, thingy
->pos
);
776 if( thingy
->flags
& AUDIO_FLAG_AUTO_START
)
777 audio_player_playclip( &thingy
->player
, &thingy
->temp_embedded_clip
);
781 world_compute_light_indices( world
);
783 vg_acquire_thread_sync();
785 /* create scene lighting buffer */
787 u32 size
= VG_MAX(world
->light_count
,1) * sizeof(float)*12;
789 vg_info( "Upload %ubytes (lighting)\n", size
);
791 glGenBuffers( 1, &world
->tbo_light_entities
);
792 glBindBuffer( GL_TEXTURE_BUFFER
, world
->tbo_light_entities
);
793 glBufferData( GL_TEXTURE_BUFFER
, size
, NULL
, GL_DYNAMIC_DRAW
);
797 * colour position direction (spots)
798 * | . . . . | . . . . | . . . . |
799 * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da |
803 v4f
*light_dst
= glMapBuffer( GL_TEXTURE_BUFFER
, GL_WRITE_ONLY
);
805 for( int i
=0; i
<world
->light_count
; i
++ )
807 struct world_light
*light
= &world
->lights
[i
];
808 struct classtype_world_light
*inf
= light
->inf
;
811 v3_muls( inf
->colour
, inf
->colour
[3] * 2.0f
, light_dst
[i
*3+0] );
812 light_dst
[i
*3+0][3] = -1.0f
;
814 if( (inf
->type
== k_light_type_spot_nighttime_only
) ||
815 (inf
->type
== k_light_type_point_nighttime_only
) )
817 u32 hash
= (i
* 29986577) & 0xff;
818 float switch_on
= hash
;
819 switch_on
*= (1.0f
/255.0f
);
821 light_dst
[i
*3+0][3] = 0.44f
+ switch_on
* 0.015f
;
824 /* position + 1/range^2 */
825 v3_copy( light
->node
->co
, light_dst
[i
*3+1] );
826 light_dst
[i
*3+1][3] = 1.0f
/(inf
->range
*inf
->range
);
828 /* direction + angle */
829 q_mulv( light
->node
->q
, (v3f
){0.0f
,-1.0f
,0.0f
}, light_dst
[i
*3+2]);
830 light_dst
[i
*3+2][3] = cosf( inf
->angle
);
833 glUnmapBuffer( GL_TEXTURE_BUFFER
);
835 glGenTextures( 1, &world
->tex_light_entities
);
836 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
837 glTexBuffer( GL_TEXTURE_BUFFER
, GL_RGBA32F
, world
->tbo_light_entities
);
840 /* Upload lighting uniform buffer */
841 if( world
->water
.enabled
)
842 v4_copy( world
->water
.plane
, world
->ub_lighting
.g_water_plane
);
845 v3f
*bounds
= world
->scene_geo
->bbx
;
847 info_vec
[0] = bounds
[0][0];
848 info_vec
[1] = bounds
[0][2];
849 info_vec
[2] = 1.0f
/ (bounds
[1][0]-bounds
[0][0]);
850 info_vec
[3] = 1.0f
/ (bounds
[1][2]-bounds
[0][2]);
851 v4_copy( info_vec
, world
->ub_lighting
.g_depth_bounds
);
855 * Rendering the depth map
860 v3_sub( world
->scene_geo
->bbx
[1], world
->scene_geo
->bbx
[0], extent
);
862 float fl
= world
->scene_geo
->bbx
[0][0],
863 fr
= world
->scene_geo
->bbx
[1][0],
864 fb
= world
->scene_geo
->bbx
[0][2],
865 ft
= world
->scene_geo
->bbx
[1][2],
869 m4x4_zero( ortho
.mtx
.p
);
870 ortho
.mtx
.p
[0][0] = 2.0f
* rl
;
871 ortho
.mtx
.p
[2][1] = 2.0f
* tb
;
872 ortho
.mtx
.p
[3][0] = (fr
+ fl
) * -rl
;
873 ortho
.mtx
.p
[3][1] = (ft
+ fb
) * -tb
;
874 ortho
.mtx
.p
[3][3] = 1.0f
;
875 m4x3_identity( ortho
.transform
);
876 camera_update_view( &ortho
);
877 camera_finalize( &ortho
);
879 glDisable(GL_DEPTH_TEST
);
881 glDisable(GL_CULL_FACE
);
882 render_fb_bind( &world
->heightmap
);
883 shader_blitcolour_use();
884 shader_blitcolour_uColour( (v4f
){-9999.0f
,-9999.0f
,-9999.0f
,-9999.0f
} );
888 glBlendFunc(GL_ONE
, GL_ONE
);
889 glBlendEquation(GL_MAX
);
891 render_world_position( world
, &ortho
);
893 glEnable(GL_DEPTH_TEST
);
894 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
896 /* upload full buffer */
897 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
898 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
899 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
902 vg_release_thread_sync();
906 * Setup scene collider
908 reset_player( 1, (const char *[]){"start"} );
912 VG_STATIC
void world_process_resources( world_instance
*world
)
914 vg_info( "Loading textures\n" );
915 world
->texture_count
= world
->meta
->info
.texture_count
;
916 world
->textures
= vg_linear_alloc( world_global
.generic_heap
,
917 sizeof(GLuint
)*world
->texture_count
);
919 vg_acquire_thread_sync();
922 world
->textures
[0] = vg_tex2d_new();
923 vg_tex2d_set_error();
927 for( int i
=1; i
<world
->texture_count
; i
++ )
929 mdl_texture
*tex
= &world
->meta
->texture_buffer
[i
];
931 if( !tex
->pack_offset
)
933 vg_release_thread_sync();
934 vg_fatal_exit_loop( "World models must have packed textures!" );
937 vg_linear_clear( vg_mem
.scratch
);
938 world
->textures
[i
] = vg_tex2d_new();
939 vg_tex2d_set_error();
940 vg_tex2d_qoi( world
->meta
->pack
+ tex
->pack_offset
, tex
->pack_length
,
941 mdl_pstr( world
->meta
, tex
->pstr_name
));
946 vg_release_thread_sync();
948 vg_info( "Loading materials\n" );
950 u32 size
= sizeof(struct world_material
) * world
->meta
->info
.material_count
;
951 world
->materials
= vg_linear_alloc( world_global
.generic_heap
, size
);
953 world
->material_count
= world
->meta
->info
.material_count
;
954 memset( world
->materials
, 0, size
);
956 for( int i
=1; i
<world
->material_count
; i
++ )
957 world
->materials
[i
].info
= world
->meta
->material_buffer
[i
];
960 struct world_material
*errmat
= &world
->materials
[0];
961 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour
);
962 v4_copy( (v4f
){ 1.0f
,0.0f
,0.0f
,1.0f
}, errmat
->info
.colour1
);
963 errmat
->info
.flags
= 0x00;
964 errmat
->info
.pstr_name
= 0; /* useless? */
965 errmat
->info
.shader
= -1;
966 errmat
->info
.tex_decal
= 0;
967 errmat
->info
.tex_diffuse
= 0;
968 errmat
->info
.tex_normal
= 0;
971 VG_STATIC
void world_unload( world_instance
*world
)
973 vg_acquire_thread_sync();
976 mesh_free( &world
->mesh_route_lines
);
977 mesh_free( &world
->mesh_geo
);
978 mesh_free( &world
->mesh_no_collide
);
980 glDeleteBuffers( 1, &world
->tbo_light_entities
);
981 glDeleteTextures( 1, &world
->tex_light_entities
);
982 glDeleteTextures( 1, &world
->tex_light_cubes
);
984 /* FIXME: CANT DO THIS HERE */
985 world_global
.time
= 0.0;
986 world_global
.rewind_from
= 0.0;
987 world_global
.rewind_to
= 0.0;
988 world_global
.last_use
= 0.0;
989 world_global
.active_gate
= 0;
990 world_global
.current_run_version
= 2;
991 world_global
.active_route_board
= 0;
993 for( int i
=0; i
<vg_list_size(world_global
.ui_bars
); i
++ )
995 struct route_ui_bar
*uib
= &world_global
.ui_bars
[i
];
996 uib
->segment_start
= 0;
997 uib
->segment_count
= 0;
1000 uib
->fade_timer_start
= 0.0;
1004 /* delete textures and meshes */
1005 glDeleteTextures( world
->texture_count
, world
->textures
);
1007 /* delete the entire block of memory */
1008 /* FIXME: WE CANT DO THIS SHIT ANYMORE, NEED TO DEALLOC FROM ABOVE */
1010 vg_linear_clear( world
->dynamic_vgl
);
1011 vg_linear_clear( world
->audio_vgl
);
1015 vg_release_thread_sync();
1018 VG_STATIC
void world_clean( world_instance
*world
)
1020 /* clean dangling pointers */
1023 world
->textures
= NULL
;
1024 world
->texture_count
= 0;
1025 world
->materials
= NULL
;
1026 world
->material_count
= 0;
1028 world
->scene_geo
= NULL
;
1029 world
->scene_no_collide
= NULL
;
1030 world
->scene_lines
= NULL
;
1032 world
->geo_bh
= NULL
;
1033 world
->trigger_bh
= NULL
;
1034 world
->audio_bh
= NULL
;
1036 world
->spawns
= NULL
;
1037 world
->spawn_count
= 0;
1039 world
->audio_things
= NULL
;
1040 world
->audio_things_count
= 0;
1042 world
->triggers
= NULL
;
1043 world
->trigger_count
= 0;
1045 world
->lights
= NULL
;
1046 world
->light_count
= 0;
1048 world
->logic_relays
= NULL
;
1049 world
->relay_count
= 0;
1051 world
->logic_achievements
= NULL
;
1052 world
->achievement_count
= 0;
1054 world
->nodes
= NULL
;
1055 world
->node_count
= 0;
1057 world
->routes
= NULL
;
1058 world
->route_count
= 0;
1060 world
->gates
= NULL
;
1061 world
->gate_count
= 0;
1063 world
->collectors
= NULL
;
1064 world
->collector_count
= 0;
1066 world
->nonlocal_gates
= NULL
;
1067 world
->nonlocalgate_count
= 0;
1069 world
->water
.enabled
= 0;
1072 /* default lighting conditions
1073 * -------------------------------------------------------------*/
1074 struct ub_world_lighting
*state
= &world
->ub_lighting
;
1076 state
->g_light_preview
= 0;
1077 state
->g_shadow_samples
= 8;
1078 state
->g_water_fog
= 0.04f
;
1080 v4_zero( state
->g_water_plane
);
1081 v4_zero( state
->g_depth_bounds
);
1083 state
->g_shadow_length
= 9.50f
;
1084 state
->g_shadow_spread
= 0.65f
;
1086 v3_copy( (v3f
){0.37f
, 0.54f
, 0.97f
}, state
->g_daysky_colour
);
1087 v3_copy( (v3f
){0.03f
, 0.05f
, 0.20f
}, state
->g_nightsky_colour
);
1088 v3_copy( (v3f
){1.00f
, 0.32f
, 0.01f
}, state
->g_sunset_colour
);
1089 v3_copy( (v3f
){0.13f
, 0.17f
, 0.35f
}, state
->g_ambient_colour
);
1090 v3_copy( (v3f
){0.25f
, 0.17f
, 0.51f
}, state
->g_sunset_ambient
);
1091 v3_copy( (v3f
){1.10f
, 0.89f
, 0.35f
}, state
->g_sun_colour
);
1094 VG_STATIC
void world_load( world_instance
*world
, const char *path
)
1096 world_unload( world
);
1097 world_clean( world
);
1099 world
->meta
= mdl_load_full( world_global
.generic_heap
, path
);
1100 vg_info( "Loading world: %s\n", path
);
1102 /* process resources from pack */
1103 world_process_resources( world
);
1105 /* dynamic allocations */
1106 world_ents_allocate( world
);
1107 world_routes_allocate( world
);
1109 /* meta processing */
1110 world_routes_process( world
);
1111 world_entities_process( world
);
1114 world_generate( world
);
1115 world_routes_generate( world
);
1116 world_post_process( world
);
1119 #endif /* WORLD_GEN_H */