oh yeah mr crabs
[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 /*
9 * FUTURE:
10 * If we have multiple levels, write an unloader
11 */
12
13 #include "world.h"
14
15 static void world_add_all_if_material( m4x3f transform, scene *pscene,
16 mdl_header *mdl, u32 id )
17 {
18 for( int i=0; i<mdl->node_count; i++ )
19 {
20 mdl_node *pnode = mdl_node_from_id( mdl, i );
21
22 for( int j=0; j<pnode->submesh_count; j++ )
23 {
24 mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
25
26 if( sm->material_id == id )
27 {
28 m4x3f transform2;
29 mdl_node_transform( pnode, transform2 );
30 m4x3_mul( transform, transform2, transform2 );
31
32 scene_add_submesh( pscene, mdl, sm, transform2 );
33 }
34 }
35
36 if( pnode->classtype == k_classtype_instance )
37 {
38 if( pnode->sub_uid )
39 {
40 u32 instance_id = pnode->sub_uid -1;
41 struct instance_cache *cache = &world.instance_cache[instance_id];
42 mdl_header *mdl2 = cache->mdl;
43
44 m4x3f transform2;
45 mdl_node_transform( pnode, transform2 );
46 m4x3_mul( transform, transform2, transform2 );
47
48 world_add_all_if_material( transform2, pscene, mdl2, id );
49 }
50 }
51 }
52 }
53
54 static void world_apply_procedural_foliage(void)
55 {
56 mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
57
58 v3f volume;
59 v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
60 volume[1] = 1.0f;
61
62 m4x3f transform;
63 mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
64 mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
65
66 for( int i=0;i<100000;i++ )
67 {
68 v3f pos;
69 v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
70 pos[1] = 1000.0f;
71 v3_add( pos, world.geo.bbx[0], pos );
72
73 ray_hit hit;
74 hit.dist = INFINITY;
75
76 if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
77 {
78 if( (hit.normal[1] > 0.8f) && ray_hit_is_terrain(&hit) &&
79 (hit.pos[1] > 0.0f+10.0f) )
80 {
81 v4f qsurface, qrandom;
82 v3f axis;
83
84 v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis );
85
86 float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f});
87 q_axis_angle( qsurface, axis, angle );
88 q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf );
89 q_mul( qsurface, qrandom, qsurface );
90 q_m3x3( qsurface, transform );
91
92 v3_copy( hit.pos, transform[3] );
93 scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
94 }
95 }
96 }
97
98 vg_free( mfoliage );
99 }
100
101 static void world_load(void)
102 {
103 mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
104 vg_info( "Loading world: models/mp_dev.mdl\n" );
105
106 world.spawn_count = 0;
107 world.traffic_count = 0;
108 world.instance_cache = NULL;
109
110 /*
111 * Process entities
112 */
113 for( int i=0; i<mworld->node_count; i++ )
114 {
115 mdl_node *pnode = mdl_node_from_id( mworld, i );
116
117 if( pnode->classtype == k_classtype_none )
118 {}
119 else if( pnode->classtype == k_classtype_spawn )
120 {
121 struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
122
123 v3_copy( pnode->co, rp->co );
124 v4_copy( pnode->q, rp->q );
125 strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
126 }
127 else if( pnode->classtype == k_classtype_water )
128 {
129 if( wrender.enabled )
130 {
131 vg_warn( "Multiple water surfaces in level! ('%s')\n",
132 mdl_pstr( mworld, pnode->pstr_name ));
133 continue;
134 }
135
136 mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
137
138 if( sm )
139 {
140 vg_acquire_thread_sync();
141 {
142 glmesh surf;
143 mdl_unpack_submesh( mworld, &surf, sm );
144 water_set_surface( &surf, pnode->co[1] );
145 }
146 vg_release_thread_sync();
147 }
148 }
149 else if( pnode->classtype == k_classtype_car_path )
150 {
151 struct classtype_car_path *p = mdl_get_entdata( mworld, pnode );
152 traffic_node *tn = &world.traffic[ world.traffic_count ];
153 tn->mn_next = NULL;
154 tn->mn_next1 = NULL;
155
156 if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target );
157 if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 );
158
159 m4x3f transform;
160 mdl_node_transform( pnode, transform );
161 m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h );
162 v3_copy( transform[3], tn->co );
163
164 pnode->sub_uid = world.traffic_count ++;
165 }
166 else if( pnode->classtype == k_classtype_instance )
167 {
168 struct classtype_instance *inst = mdl_get_entdata( mworld, pnode );
169 pnode->sub_uid = 0;
170
171 int cached = 0;
172 for( int i=0; i<world.instance_cache_count; i++ )
173 {
174 struct instance_cache *cache = &world.instance_cache[i];
175 if( inst->pstr_file == cache->pstr_file )
176 {
177 cached = 1;
178 pnode->sub_uid = i+1;
179 break;
180 }
181 }
182
183 if( !cached )
184 {
185 world.instance_cache = buffer_reserve(
186 world.instance_cache, world.instance_cache_count,
187 &world.instance_cache_cap, 1,
188 sizeof(struct instance_cache) );
189
190 struct instance_cache *cache =
191 &world.instance_cache[world.instance_cache_count];
192
193 const char *filename = mdl_pstr(mworld, inst->pstr_file);
194
195 cache->pstr_file = inst->pstr_file;
196 cache->mdl = mdl_load( filename );
197
198 if( cache->mdl )
199 {
200 world.instance_cache_count ++;
201 pnode->sub_uid = world.instance_cache_count;
202 mdl_link_materials( mworld, cache->mdl );
203 vg_success( "Cached %s\n", filename );
204 }
205 else
206 {
207 vg_warn( "Failed to cache %s\n", filename );
208 }
209 }
210 }
211 else if( pnode->classtype == k_classtype_achievement_box )
212 {
213 world.achievement_zones =
214 buffer_reserve( world.achievement_zones,
215 world.achievement_zones_count,
216 &world.achievement_zones_cap, 1,
217 sizeof(struct achievement_zone) );
218
219 struct achievement_zone *zone = &world.achievement_zones[
220 world.achievement_zones_count ++ ];
221
222
223 struct classtype_achievement_box *box = mdl_get_entdata(mworld,pnode);
224
225 mdl_node_transform( pnode, zone->transform );
226 m4x3_invert_full( zone->transform, zone->inv_transform );
227 vg_strncpy( mdl_pstr(mworld, box->pstr_name), zone->name, 31 );
228 zone->name[31] = 0x00;
229 zone->triggered = 0;
230
231 if( box->trigger )
232 zone->ptarget_delegated = mdl_node_from_id( mworld, box->trigger );
233 else
234 zone->ptarget_delegated = NULL;
235 }
236 else if( pnode->classtype == k_classtype_audio )
237 {
238 world.audio_things =
239 buffer_reserve( world.audio_things,
240 world.audio_things_count,
241 &world.audio_things_cap, 1,
242 sizeof(struct world_audio_thing) );
243
244 struct world_audio_thing *thing = &world.audio_things[
245 world.audio_things_count ];
246 memset( thing, 0, sizeof(struct world_audio_thing) );
247 struct classtype_audio *aud = mdl_get_entdata(mworld,pnode);
248
249 v3_copy( pnode->co, thing->pos );
250
251 if( aud->flags & AUDIO_FLAG_SPACIAL_3D )
252 thing->volume = aud->volume * pnode->s[0];
253 else
254 thing->volume = aud->volume;
255
256 thing->flags = aud->flags;
257 const char *fp = mdl_pstr( mworld, aud->pstr_file );
258 char *path2 = vg_alloc( strlen(fp)+1 );
259 strcpy( path2, fp );
260 thing->temp_embedded_clip.path = path2;
261 thing->temp_embedded_clip.source_mode = k_audio_source_compressed;
262 audio_clip_load( &thing->temp_embedded_clip );
263 thing->player.name = "[temp]";
264 thing->player.enqued = 0;
265
266 pnode->sub_uid = world.audio_things_count;
267 world.audio_things_count ++;
268 }
269 }
270
271 /* fixup links */
272 for( int i=0; i<world.achievement_zones_count; i ++ )
273 {
274 struct achievement_zone *ach = &world.achievement_zones[ i ];
275 if( ach->ptarget_delegated )
276 {
277 u32 id = ach->ptarget_delegated->sub_uid;
278 ach->ptarget = &world.audio_things[ id ];
279 }
280 else
281 ach->ptarget = NULL;
282 }
283
284 /* initialize audio if need be */
285 audio_lock();
286 for( int i=0; i<world.audio_things_count; i++ )
287 {
288 struct world_audio_thing *thingy = &world.audio_things[ i ];
289
290 audio_player_init( &thingy->player );
291 audio_player_set_flags( &thingy->player, thingy->flags );
292 audio_player_set_vol( &thingy->player, thingy->volume );
293 audio_player_set_pan( &thingy->player, 0.0f );
294
295 if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
296 audio_player_set_position( &thingy->player, thingy->pos );
297
298 if( thingy->flags & AUDIO_FLAG_AUTO_START )
299 audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
300 }
301 audio_unlock();
302
303 world.instance_cache = buffer_fix( world.instance_cache,
304 world.instance_cache_count,
305 &world.instance_cache_cap,
306 sizeof( struct instance_cache ) );
307
308 #if 0
309 traffic_finalize( world.traffic, world.traffic_count );
310 for( int i=0; i<vg_list_size(world.van_man); i++ )
311 world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
312 #endif
313
314 /*
315 * Compile meshes into the world scenes
316 */
317 scene_init( &world.geo );
318
319 u32 mat_surf = 0,
320 mat_surf_oob = 0,
321 mat_vertex_blend = 0,
322 mat_alphatest = 0,
323 mat_graffiti = 0,
324 mat_subworld = 0,
325 mat_terrain = 0;
326
327 for( int i=1; i<mworld->material_count; i++ )
328 {
329 mdl_material *mat = mdl_material_from_id( mworld, i );
330 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
331
332 if( !strcmp( "surf", mat_name ))
333 mat_surf = i;
334 else if( !strcmp( "surf_oob", mat_name ))
335 mat_surf_oob = i;
336 else if( !strcmp( "vertex_blend", mat_name ))
337 mat_vertex_blend = i;
338 else if( !strcmp( "alphatest", mat_name ))
339 mat_alphatest = i;
340 else if( !strcmp( "graffitibox", mat_name ))
341 mat_graffiti = i;
342 else if( !strcmp( "terrain", mat_name ) )
343 mat_terrain = i;
344 }
345
346 m4x3f midentity;
347 m4x3_identity( midentity );
348
349 if( mat_terrain )
350 world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain );
351 scene_copy_slice( &world.geo, &world.sm_terrain );
352
353 if( mat_surf_oob )
354 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
355 else
356 vg_warn( "No OOB surface\n" );
357 scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
358
359 if( mat_surf )
360 world_add_all_if_material( midentity, &world.geo, mworld, mat_surf );
361 scene_copy_slice( &world.geo, &world.sm_geo_std );
362
363 if( mat_vertex_blend )
364 world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend);
365 scene_copy_slice( &world.geo, &world.sm_geo_vb );
366
367 vg_acquire_thread_sync();
368 scene_upload( &world.geo );
369 vg_release_thread_sync();
370
371 scene_bh_create( &world.geo );
372
373
374 /* Foliage /nocollide layer.
375 * TODO: Probably should have material traits for this
376 */
377 scene_init( &world.foliage );
378
379 world_apply_procedural_foliage();
380 scene_copy_slice( &world.foliage, &world.sm_foliage_main );
381
382 world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest);
383 scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
384
385 world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
386 scene_copy_slice( &world.foliage, &world.sm_graffiti );
387
388
389 vg_acquire_thread_sync();
390 {
391 scene_upload( &world.foliage );
392
393 /*
394 * Rendering the depth map
395 */
396 m4x4f ortho;
397 m4x3f camera;
398
399 v3f extent;
400 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
401
402 float fl = world.geo.bbx[0][0],
403 fr = world.geo.bbx[1][0],
404 fb = world.geo.bbx[0][2],
405 ft = world.geo.bbx[1][2],
406 rl = 1.0f / (fr-fl),
407 tb = 1.0f / (ft-fb);
408
409 m4x4_zero( ortho );
410 ortho[0][0] = 2.0f * rl;
411 ortho[2][1] = 2.0f * tb;
412 ortho[3][0] = (fr + fl) * -rl;
413 ortho[3][1] = (ft + fb) * -tb;
414 ortho[3][3] = 1.0f;
415 m4x3_identity( camera );
416
417 glViewport( 0, 0, 1024, 1024 );
418 glDisable(GL_DEPTH_TEST);
419 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
420 shader_fscolour_use();
421 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
422 render_fsquad();
423
424 glEnable(GL_BLEND);
425 glBlendFunc(GL_ONE, GL_ONE);
426 glBlendEquation(GL_MAX);
427 render_world_depth( ortho, camera );
428 glDisable(GL_BLEND);
429 glEnable(GL_DEPTH_TEST);
430 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
431
432
433 /*
434 * TODO: World settings entity
435 */
436 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
437 v4_copy( wrender.plane, winfo->g_water_plane );
438
439 v4f bounds;
440 bounds[0] = world.geo.bbx[0][0];
441 bounds[1] = world.geo.bbx[0][2];
442 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
443 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
444 v4_copy( bounds, winfo->g_depth_bounds );
445
446 winfo->g_water_fog = 0.04f;
447 render_update_lighting_ub();
448 }
449
450 vg_release_thread_sync();
451
452 world_routes_loadfrom( mworld );
453
454 for( int i=0; i<world.instance_cache_count; i++ )
455 vg_free( world.instance_cache[i].mdl );
456
457 vg_free( world.instance_cache );
458 vg_free( mworld );
459 scene_free_offline_buffers( &world.foliage );
460
461 /*
462 * Setup scene collider
463 */
464 v3_zero( world.rb_geo.co );
465 q_identity( world.rb_geo.q );
466
467 world.rb_geo.type = k_rb_shape_scene;
468 world.rb_geo.inf.scene.pscene = &world.geo;
469 world.rb_geo.is_world = 1;
470 rb_init( &world.rb_geo );
471 }
472
473 #endif /* WORLD_GEN_H */