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