routes
[carveJwlIkooP6JGAAIwe30JlM.git] / world.h
1 #include "common.h"
2
3 static int ray_world( v3f pos, v3f dir, ray_hit *hit );
4
5 #ifndef WORLD_H
6 #define WORLD_H
7
8 #include "scene.h"
9 #include "terrain.h"
10 #include "render.h"
11 #include "water.h"
12 #include "rigidbody.h"
13 #include "gate.h"
14 #include "bvh.h"
15 #include "lighting.h"
16 #include "model.h"
17
18 #include "traffic.h" /*TODO: -> world_traffic.h */
19 #include "world_routes.h"
20
21 #include "shaders/terrain.h"
22 #include "shaders/sky.h"
23 #include "shaders/planeinf.h"
24 #include "shaders/standard.h"
25 #include "shaders/vblend.h"
26 #include "shaders/gpos.h"
27 #include "shaders/fscolour.h"
28 #include "shaders/alphatest.h"
29
30 static struct gworld
31 {
32 /* gameplay */
33 struct respawn_point
34 {
35 v3f co;
36 v4f q;
37 char name[32];
38 }
39 spawns[32];
40 u32 spawn_count;
41
42 struct subworld_routes routes;
43
44 /* ...
45 struct subworld_spawns system_spawns;
46 struct subworld_physics system_physics;
47 */
48
49 teleport_gate gates[64];
50 u32 gate_count;
51
52 /* Paths */
53 traffic_node traffic[128];
54 u32 traffic_count;
55
56 #if 0
57 traffic_driver van_man[6];
58 #endif
59
60 /* Physics */
61
62 /* Rendering & geometry */
63 scene geo, foliage;
64 rigidbody rb_geo;
65
66 mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
67 sm_foliage_main, sm_foliage_alphatest;
68
69 glmesh skybox, skydome;
70 mdl_submesh dome_upper, dome_lower;
71
72 glmesh cars;
73 mdl_submesh car_holden;
74
75 rigidbody mr_ball;
76
77 /* Load time */
78
79 struct instance_cache
80 {
81 mdl_header *mdl;
82 u32 pstr_file;
83 }
84 * instance_cache;
85 u32 instance_cache_count,
86 instance_cache_cap;
87 }
88 world;
89
90 static struct subworld_routes *subworld_routes(void) { return &world.routes; }
91
92
93 vg_tex2d tex_terrain_colours = { .path = "textures/gradients.qoi",
94 .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST };
95
96 vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi",
97 .flags = VG_TEXTURE_NEAREST };
98
99 vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi",
100 .flags = VG_TEXTURE_NEAREST };
101
102 static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
103 {
104 for( int i=0; i<3; i++ )
105 v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
106 }
107
108 static int ray_world( v3f pos, v3f dir, ray_hit *hit )
109 {
110 return scene_raycast( &world.geo, pos, dir, hit );
111 }
112
113 static int ray_hit_is_ramp( ray_hit *hit )
114 {
115 return hit->tri[0] > world.sm_geo_std_oob.vertex_count;
116 }
117
118 static void world_register(void)
119 {
120 shader_terrain_register();
121 shader_sky_register();
122 shader_planeinf_register();
123 shader_gpos_register();
124 shader_fscolour_register();
125 shader_alphatest_register();
126 }
127
128 static void world_free(void)
129 {
130 /* TODO.. */
131 }
132
133 static void render_world_depth( m4x4f projection, m4x3f camera );
134
135 static void add_all_if_material( m4x3f transform, scene *pscene,
136 mdl_header *mdl, u32 id )
137 {
138 for( int i=0; i<mdl->node_count; i++ )
139 {
140 mdl_node *pnode = mdl_node_from_id( mdl, i );
141
142 for( int j=0; j<pnode->submesh_count; j++ )
143 {
144 mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
145
146 if( sm->material_id == id )
147 {
148 m4x3f transform2;
149 mdl_node_transform( pnode, transform2 );
150 m4x3_mul( transform, transform2, transform2 );
151
152 scene_add_submesh( pscene, mdl, sm, transform2 );
153 }
154 }
155
156 if( pnode->classtype == k_classtype_instance )
157 {
158 if( pnode->sub_uid )
159 {
160 u32 instance_id = pnode->sub_uid -1;
161 struct instance_cache *cache = &world.instance_cache[instance_id];
162 mdl_header *mdl2 = cache->mdl;
163
164 m4x3f transform2;
165 mdl_node_transform( pnode, transform2 );
166 m4x3_mul( transform, transform2, transform2 );
167
168 add_all_if_material( transform2, pscene, mdl2, id );
169 }
170 }
171 }
172 }
173
174 static void world_apply_procedural_foliage(void)
175 {
176 mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
177
178 v3f volume;
179 v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
180 volume[1] = 1.0f;
181
182 m4x3f transform;
183 mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
184 mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
185
186 for( int i=0;i<100000;i++ )
187 {
188 v3f pos;
189 v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
190 pos[1] = 1000.0f;
191 v3_add( pos, world.geo.bbx[0], pos );
192
193 ray_hit hit;
194 hit.dist = INFINITY;
195
196 if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
197 {
198 if( hit.normal[1] > 0.8f && !ray_hit_is_ramp(&hit) &&
199 hit.pos[1] > water_height()+10.0f )
200 {
201 v4f qsurface, qrandom;
202 v3f axis;
203
204 v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis );
205
206 float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f});
207 q_axis_angle( qsurface, axis, angle );
208 q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf );
209 q_mul( qsurface, qrandom, qsurface );
210 q_m3x3( qsurface, transform );
211
212 v3_copy( hit.pos, transform[3] );
213 scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
214 }
215 }
216 }
217 free( mfoliage );
218 }
219
220 static void world_load(void)
221 {
222 mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
223
224 world.spawn_count = 0;
225 world.gate_count = 0;
226 world.traffic_count = 0;
227 world.instance_cache = NULL;
228
229 /*
230 * Process entities
231 */
232 for( int i=0; i<mworld->node_count; i++ )
233 {
234 mdl_node *pnode = mdl_node_from_id( mworld, i );
235
236 if( pnode->classtype == k_classtype_none )
237 {}
238 #if 0
239 else if( pnode->classtype == k_classtype_gate )
240 {
241 struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode );
242
243 if( entgate->target )
244 {
245 mdl_node *pother = mdl_node_from_id( mworld, entgate->target );
246
247 teleport_gate *gate = &world.gates[ world.gate_count ++ ];
248
249 v3_copy( pnode->co, gate->co[0] );
250 v3_copy( pother->co, gate->co[1] );
251 v4_copy( pnode->q, gate->q[0] );
252 v4_copy( pother->q, gate->q[1] );
253 v2_copy( pnode->s, gate->dims );
254
255 gate_transform_update( gate );
256 }
257 }
258 #endif
259 else if( pnode->classtype == k_classtype_spawn )
260 {
261 struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
262
263 v3_copy( pnode->co, rp->co );
264 v4_copy( pnode->q, rp->q );
265 strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
266 }
267 else if( pnode->classtype == k_classtype_water )
268 {
269 if( wrender.enabled )
270 {
271 vg_warn( "Multiple water surfaces in level! ('%s')\n",
272 mdl_pstr( mworld, pnode->pstr_name ));
273 continue;
274 }
275
276 mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
277
278 if( sm )
279 {
280 glmesh surf;
281 mdl_unpack_submesh( mworld, &surf, sm );
282 water_init();
283 water_set_surface( &surf, pnode->co[1] );
284 }
285 }
286 else if( pnode->classtype == k_classtype_car_path )
287 {
288 struct classtype_car_path *p = mdl_get_entdata( mworld, pnode );
289 traffic_node *tn = &world.traffic[ world.traffic_count ];
290 tn->mn_next = NULL;
291 tn->mn_next1 = NULL;
292
293 if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target );
294 if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 );
295
296 m4x3f transform;
297 mdl_node_transform( pnode, transform );
298 m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h );
299 v3_copy( transform[3], tn->co );
300
301 pnode->sub_uid = world.traffic_count ++;
302 }
303 else if( pnode->classtype == k_classtype_instance )
304 {
305 struct classtype_instance *inst = mdl_get_entdata( mworld, pnode );
306 pnode->sub_uid = 0;
307
308 int cached = 0;
309 for( int i=0; i<world.instance_cache_count; i++ )
310 {
311 struct instance_cache *cache = &world.instance_cache[i];
312 if( inst->pstr_file == cache->pstr_file )
313 {
314 cached = 1;
315 pnode->sub_uid = i+1;
316 break;
317 }
318 }
319
320 if( !cached )
321 {
322 world.instance_cache = buffer_reserve(
323 world.instance_cache, world.instance_cache_count,
324 &world.instance_cache_cap, 1,
325 sizeof(struct instance_cache) );
326
327 struct instance_cache *cache =
328 &world.instance_cache[world.instance_cache_count];
329
330 const char *filename = mdl_pstr(mworld, inst->pstr_file);
331
332 cache->pstr_file = inst->pstr_file;
333 cache->mdl = mdl_load( filename );
334
335 if( cache->mdl )
336 {
337 world.instance_cache_count ++;
338 pnode->sub_uid = world.instance_cache_count;
339 mdl_link_materials( mworld, cache->mdl );
340 vg_success( "Cached %s\n", filename );
341 }
342 else
343 {
344 vg_warn( "Failed to cache %s\n", filename );
345 }
346 }
347 }
348 }
349
350 world.instance_cache = buffer_fix( world.instance_cache,
351 world.instance_cache_count,
352 &world.instance_cache_cap,
353 sizeof( struct instance_cache ) );
354
355 #if 0
356 traffic_finalize( world.traffic, world.traffic_count );
357 for( int i=0; i<vg_list_size(world.van_man); i++ )
358 world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
359 #endif
360
361 /*
362 * Compile meshes into the world scenes
363 */
364 scene_init( &world.geo );
365
366 u32 mat_surf = 0,
367 mat_surf_oob = 0,
368 mat_vertex_blend = 0,
369 mat_alphatest = 0;
370
371 for( int i=1; i<mworld->material_count; i++ )
372 {
373 mdl_material *mat = mdl_material_from_id( mworld, i );
374 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
375
376 if( !strcmp( "surf", mat_name ))
377 mat_surf = i;
378 else if( !strcmp( "surf_oob", mat_name ))
379 mat_surf_oob = i;
380 else if( !strcmp( "vertex_blend", mat_name ))
381 mat_vertex_blend = i;
382 else if( !strcmp( "alphatest", mat_name ))
383 mat_alphatest = i;
384 }
385
386 m4x3f midentity;
387 m4x3_identity( midentity );
388
389 if( mat_surf_oob )
390 add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
391 else
392 vg_warn( "No OOB surface\n" );
393 scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
394
395 if( mat_surf )
396 add_all_if_material( midentity, &world.geo, mworld, mat_surf );
397 scene_copy_slice( &world.geo, &world.sm_geo_std );
398
399 if( mat_vertex_blend )
400 add_all_if_material( midentity, &world.geo, mworld, mat_vertex_blend );
401 scene_copy_slice( &world.geo, &world.sm_geo_vb );
402
403 scene_upload( &world.geo );
404 scene_bh_create( &world.geo );
405
406
407 /* Foliage /nocollide layer.
408 * TODO: Probably should have material traits for this
409 */
410 scene_init( &world.foliage );
411
412 world_apply_procedural_foliage();
413 scene_copy_slice( &world.foliage, &world.sm_foliage_main );
414
415 add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest );
416 scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
417
418 scene_upload( &world.foliage );
419 world_routes_init( mworld );
420
421 for( int i=0; i<world.instance_cache_count; i++ )
422 free( world.instance_cache[i].mdl );
423
424 free( world.instance_cache );
425 free( mworld );
426
427 /*
428 * Rendering the depth map
429 */
430 m4x4f ortho;
431 m4x3f camera;
432
433 v3f extent;
434 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
435
436 float fl = world.geo.bbx[0][0],
437 fr = world.geo.bbx[1][0],
438 fb = world.geo.bbx[0][2],
439 ft = world.geo.bbx[1][2],
440 rl = 1.0f / (fr-fl),
441 tb = 1.0f / (ft-fb);
442
443 m4x4_zero( ortho );
444 ortho[0][0] = 2.0f * rl;
445 ortho[2][1] = 2.0f * tb;
446 ortho[3][0] = (fr + fl) * -rl;
447 ortho[3][1] = (ft + fb) * -tb;
448 ortho[3][3] = 1.0f;
449 m4x3_identity( camera );
450
451 glViewport( 0, 0, 1024, 1024 );
452 glDisable(GL_DEPTH_TEST);
453 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
454 shader_fscolour_use();
455 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
456 render_fsquad();
457
458 glEnable(GL_BLEND);
459 glBlendFunc(GL_ONE, GL_ONE);
460 glBlendEquation(GL_MAX);
461 render_world_depth( ortho, camera );
462 glDisable(GL_BLEND);
463 glEnable(GL_DEPTH_TEST);
464
465 /*
466 * TODO: World settings entity
467 */
468 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
469 v4_copy( wrender.plane, winfo->g_water_plane );
470
471 v4f bounds;
472 bounds[0] = world.geo.bbx[0][0];
473 bounds[1] = world.geo.bbx[0][2];
474 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
475 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
476 v4_copy( bounds, winfo->g_depth_bounds );
477
478 winfo->g_water_fog = 0.04f;
479 render_update_lighting_ub();
480
481
482 world.mr_ball.type = k_rb_shape_sphere;
483 world.mr_ball.inf.sphere.radius = 2.0f;
484 v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co );
485
486 q_identity(world.mr_ball.q);
487 rb_init( &world.mr_ball );
488
489 /*
490 * Setup scene collider
491 */
492 v3_zero( world.rb_geo.co );
493 q_identity( world.rb_geo.q );
494
495 world.rb_geo.type = k_rb_shape_scene;
496 world.rb_geo.inf.scene.pscene = &world.geo;
497 world.rb_geo.is_world = 1;
498 rb_init( &world.rb_geo );
499 }
500
501 static void world_init(void)
502 {
503 vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours,
504 &tex_terrain_noise,
505 &tex_alphatest }, 3 );
506
507 mdl_header *mcars = mdl_load( "models/rs_cars.mdl" );
508 mdl_unpack_glmesh( mcars, &world.cars );
509 mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
510 world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
511 free(mcars);
512
513
514 mdl_header *msky = mdl_load("models/rs_skydome.mdl");
515 mdl_unpack_glmesh( msky, &world.skydome );
516
517 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
518 *nupper = mdl_node_from_name( msky, "dome_upper" );
519
520 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
521 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
522 free(msky);
523 }
524
525 static void world_update(void)
526 {
527 world_routes_debug();
528
529 #if 0
530 rb_solver_reset();
531 rb_build_manifold_terrain_sphere( &world.mr_ball );
532
533 for( int i=0; i<5; i++ )
534 rb_solve_contacts( rb_contact_buffer, rb_contact_count );
535
536 rb_iter( &world.mr_ball );
537 rb_update_transform( &world.mr_ball );
538 rb_debug( &world.mr_ball, 0 );
539
540 for( int i=0; i<vg_list_size(world.van_man); i++ )
541 {
542 traffic_drive( &world.van_man[i] );
543 traffic_visualize_car( &world.van_man[i] );
544 }
545 #endif
546 }
547
548 /*
549 * Rendering
550 */
551
552 static void bind_terrain_textures(void)
553 {
554 vg_tex2d_bind( &tex_terrain_noise, 0 );
555 vg_tex2d_bind( &tex_terrain_colours, 1 );
556 }
557
558 static void render_world_vb( m4x4f projection, v3f camera )
559 {
560 m4x3f identity_matrix;
561 m4x3_identity( identity_matrix );
562
563 shader_vblend_use();
564 shader_vblend_uTexGarbage(0);
565 shader_vblend_uTexGradients(1);
566 shader_link_standard_ub( _shader_vblend.id, 2 );
567 bind_terrain_textures();
568
569 shader_vblend_uPv( projection );
570 shader_vblend_uMdl( identity_matrix );
571 shader_vblend_uCamera( camera );
572
573 scene_bind( &world.geo );
574 mdl_draw_submesh( &world.sm_geo_vb );
575
576 mesh_bind( &world.cars );
577
578 #if 0
579 for( int i=0; i<vg_list_size(world.van_man); i++ )
580 {
581 shader_vblend_uMdl( world.van_man[i].transform );
582 mdl_draw_submesh( &world.car_holden );
583 }
584 #endif
585 }
586
587 static void render_world_alphatest( m4x4f projection, v3f camera )
588 {
589 m4x3f identity_matrix;
590 m4x3_identity( identity_matrix );
591
592 shader_alphatest_use();
593 shader_alphatest_uTexGarbage(0);
594 shader_alphatest_uTexMain(1);
595 shader_link_standard_ub( _shader_alphatest.id, 2 );
596
597 vg_tex2d_bind( &tex_terrain_noise, 0 );
598 vg_tex2d_bind( &tex_alphatest, 1 );
599
600 shader_alphatest_uPv( projection );
601 shader_alphatest_uMdl( identity_matrix );
602 shader_alphatest_uCamera( camera );
603
604 glDisable(GL_CULL_FACE);
605 scene_bind( &world.foliage );
606 mdl_draw_submesh( &world.sm_foliage_alphatest );
607 glEnable(GL_CULL_FACE);
608 }
609
610 static void render_terrain( m4x4f projection, v3f camera )
611 {
612 m4x3f identity_matrix;
613 m4x3_identity( identity_matrix );
614
615 shader_terrain_use();
616 shader_terrain_uTexGarbage(0);
617 shader_terrain_uTexGradients(1);
618 shader_link_standard_ub( _shader_terrain.id, 2 );
619 bind_terrain_textures();
620
621 shader_terrain_uPv( projection );
622 shader_terrain_uMdl( identity_matrix );
623 shader_terrain_uCamera( camera );
624
625 scene_bind( &world.geo );
626 mdl_draw_submesh( &world.sm_geo_std_oob );
627 mdl_draw_submesh( &world.sm_geo_std );
628
629 /* TODO: Dont draw in reflection */
630 glDisable(GL_CULL_FACE);
631 scene_bind( &world.foliage );
632 mdl_draw_submesh( &world.sm_foliage_main );
633 glEnable(GL_CULL_FACE);
634 }
635
636 static void render_lowerdome( m4x3f camera )
637 {
638 m4x4f projection, full;
639 pipeline_projection( projection, 0.4f, 1000.0f );
640
641 m4x3f inverse;
642 m3x3_transpose( camera, inverse );
643 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
644 m4x3_expand( inverse, full );
645 m4x4_mul( projection, full, full );
646
647 m4x3f identity_matrix;
648 m4x3_identity( identity_matrix );
649
650 shader_planeinf_use();
651 shader_planeinf_uMdl(identity_matrix);
652 shader_planeinf_uPv(full);
653 shader_planeinf_uCamera(camera[3]);
654 shader_planeinf_uPlane( (v4f){0.0f,1.0f,0.0f, water_height()} );
655
656 mdl_draw_submesh( &world.dome_lower );
657 }
658
659 static void render_sky(m4x3f camera)
660 {
661 m4x4f projection, full;
662 pipeline_projection( projection, 0.4f, 1000.0f );
663
664 m4x3f inverse;
665 m3x3_transpose( camera, inverse );
666 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
667 m4x3_expand( inverse, full );
668 m4x4_mul( projection, full, full );
669
670 m4x3f identity_matrix;
671 m4x3_identity( identity_matrix );
672
673 shader_sky_use();
674 shader_sky_uMdl(identity_matrix);
675 shader_sky_uPv(full);
676 shader_sky_uTexGarbage(0);
677 shader_sky_uTime( vg_time );
678
679 vg_tex2d_bind( &tex_terrain_noise, 0 );
680
681 glDepthMask( GL_FALSE );
682 glDisable( GL_DEPTH_TEST );
683
684 mesh_bind( &world.skydome );
685 mdl_draw_submesh( &world.dome_upper );
686
687 glEnable( GL_DEPTH_TEST );
688 glDepthMask( GL_TRUE );
689 }
690
691 static void render_world( m4x4f projection, m4x3f camera )
692 {
693 render_sky( camera );
694 render_world_vb( projection, camera[3] );
695 render_world_alphatest( projection, camera[3] );
696 render_terrain( projection, camera[3] );
697 }
698
699 static void render_world_depth( m4x4f projection, m4x3f camera )
700 {
701 m4x3f identity_matrix;
702 m4x3_identity( identity_matrix );
703
704 shader_gpos_use();
705 shader_gpos_uCamera( camera[3] );
706 shader_gpos_uPv( projection );
707 shader_gpos_uMdl( identity_matrix );
708
709 scene_bind( &world.geo );
710 scene_draw( &world.geo );
711
712 #if 0
713 glDisable(GL_CULL_FACE);
714 scene_bind( &world.foliage );
715 scene_draw( &world.foliage );
716 glEnable(GL_CULL_FACE);
717 #endif
718 }
719
720 #endif /* WORLD_H */