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