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