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