f970b0a3204f68152656d8fa366db6f9817aad44
[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;
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 mat_subworld = 0;
360
361 for( int i=1; i<mworld->material_count; i++ )
362 {
363 mdl_material *mat = mdl_material_from_id( mworld, i );
364 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
365
366 if( !strcmp( "surf", mat_name ))
367 mat_surf = i;
368 else if( !strcmp( "surf_oob", mat_name ))
369 mat_surf_oob = i;
370 else if( !strcmp( "vertex_blend", mat_name ))
371 mat_vertex_blend = i;
372 else if( !strcmp( "alphatest", mat_name ))
373 mat_alphatest = i;
374 else if( !strcmp( "graffitibox", mat_name ))
375 mat_graffiti = i;
376 else if( !strcmp( "subworld", mat_name ))
377 mat_subworld = i;
378 }
379
380 m4x3f midentity;
381 m4x3_identity( midentity );
382
383 if( mat_surf_oob )
384 add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
385 else
386 vg_warn( "No OOB surface\n" );
387 scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
388
389 if( mat_surf )
390 add_all_if_material( midentity, &world.geo, mworld, mat_surf );
391 scene_copy_slice( &world.geo, &world.sm_geo_std );
392
393 if( mat_subworld )
394 add_all_if_material( midentity, &world.geo, mworld, mat_subworld );
395 scene_copy_slice( &world.geo, &world.sm_subworld );
396
397 if( mat_vertex_blend )
398 add_all_if_material( midentity, &world.geo, mworld, mat_vertex_blend );
399 scene_copy_slice( &world.geo, &world.sm_geo_vb );
400
401 scene_upload( &world.geo );
402 scene_bh_create( &world.geo );
403
404
405 /* Foliage /nocollide layer.
406 * TODO: Probably should have material traits for this
407 */
408 scene_init( &world.foliage );
409
410 world_apply_procedural_foliage();
411 scene_copy_slice( &world.foliage, &world.sm_foliage_main );
412
413 add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest );
414 scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
415
416 add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
417 scene_copy_slice( &world.foliage, &world.sm_graffiti );
418
419 scene_upload( &world.foliage );
420 world_routes_loadfrom( mworld );
421
422 for( int i=0; i<world.instance_cache_count; i++ )
423 free( world.instance_cache[i].mdl );
424
425 free( world.instance_cache );
426 free( mworld );
427
428 /*
429 * Rendering the depth map
430 */
431 m4x4f ortho;
432 m4x3f camera;
433
434 v3f extent;
435 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
436
437 float fl = world.geo.bbx[0][0],
438 fr = world.geo.bbx[1][0],
439 fb = world.geo.bbx[0][2],
440 ft = world.geo.bbx[1][2],
441 rl = 1.0f / (fr-fl),
442 tb = 1.0f / (ft-fb);
443
444 m4x4_zero( ortho );
445 ortho[0][0] = 2.0f * rl;
446 ortho[2][1] = 2.0f * tb;
447 ortho[3][0] = (fr + fl) * -rl;
448 ortho[3][1] = (ft + fb) * -tb;
449 ortho[3][3] = 1.0f;
450 m4x3_identity( camera );
451
452 glViewport( 0, 0, 1024, 1024 );
453 glDisable(GL_DEPTH_TEST);
454 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
455 shader_fscolour_use();
456 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
457 render_fsquad();
458
459 glEnable(GL_BLEND);
460 glBlendFunc(GL_ONE, GL_ONE);
461 glBlendEquation(GL_MAX);
462 render_world_depth( ortho, camera );
463 glDisable(GL_BLEND);
464 glEnable(GL_DEPTH_TEST);
465
466 /*
467 * TODO: World settings entity
468 */
469 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
470 v4_copy( wrender.plane, winfo->g_water_plane );
471
472 v4f bounds;
473 bounds[0] = world.geo.bbx[0][0];
474 bounds[1] = world.geo.bbx[0][2];
475 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
476 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
477 v4_copy( bounds, winfo->g_depth_bounds );
478
479 winfo->g_water_fog = 0.04f;
480 render_update_lighting_ub();
481
482
483 world.mr_ball.type = k_rb_shape_sphere;
484 world.mr_ball.inf.sphere.radius = 2.0f;
485 v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co );
486
487 q_identity(world.mr_ball.q);
488 rb_init( &world.mr_ball );
489
490 /*
491 * Setup scene collider
492 */
493 v3_zero( world.rb_geo.co );
494 q_identity( world.rb_geo.q );
495
496 world.rb_geo.type = k_rb_shape_scene;
497 world.rb_geo.inf.scene.pscene = &world.geo;
498 world.rb_geo.is_world = 1;
499 rb_init( &world.rb_geo );
500 }
501
502 static void world_init(void)
503 {
504 vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours,
505 &tex_terrain_noise,
506 &tex_alphatest,
507 &tex_graffiti }, 4 );
508
509 mdl_header *mcars = mdl_load( "models/rs_cars.mdl" );
510 mdl_unpack_glmesh( mcars, &world.cars );
511 mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
512 world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
513 free(mcars);
514
515
516 mdl_header *msky = mdl_load("models/rs_skydome.mdl");
517 mdl_unpack_glmesh( msky, &world.skydome );
518
519 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
520 *nupper = mdl_node_from_name( msky, "dome_upper" );
521
522 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
523 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
524 free(msky);
525
526
527 /* Other systems */
528 world_sfd_init();
529 }
530
531 static void world_update(void)
532 {
533 world_routes_update();
534 world_routes_debug();
535 sfd_update( &world.sfd.tester );
536
537 #if 0
538 rb_solver_reset();
539 rb_build_manifold_terrain_sphere( &world.mr_ball );
540
541 for( int i=0; i<5; i++ )
542 rb_solve_contacts( rb_contact_buffer, rb_contact_count );
543
544 rb_iter( &world.mr_ball );
545 rb_update_transform( &world.mr_ball );
546 rb_debug( &world.mr_ball, 0 );
547
548 for( int i=0; i<vg_list_size(world.van_man); i++ )
549 {
550 traffic_drive( &world.van_man[i] );
551 traffic_visualize_car( &world.van_man[i] );
552 }
553 #endif
554 }
555
556 /*
557 * Rendering
558 */
559
560 static void bind_terrain_textures(void)
561 {
562 vg_tex2d_bind( &tex_terrain_noise, 0 );
563 vg_tex2d_bind( &tex_terrain_colours, 1 );
564 }
565
566 static void render_world_vb( m4x4f projection, v3f camera )
567 {
568 m4x3f identity_matrix;
569 m4x3_identity( identity_matrix );
570
571 shader_vblend_use();
572 shader_vblend_uTexGarbage(0);
573 shader_vblend_uTexGradients(1);
574 shader_link_standard_ub( _shader_vblend.id, 2 );
575 bind_terrain_textures();
576
577 shader_vblend_uPv( projection );
578 shader_vblend_uMdl( identity_matrix );
579 shader_vblend_uCamera( camera );
580
581 scene_bind( &world.geo );
582 mdl_draw_submesh( &world.sm_geo_vb );
583
584 mesh_bind( &world.cars );
585
586 #if 0
587 for( int i=0; i<vg_list_size(world.van_man); i++ )
588 {
589 shader_vblend_uMdl( world.van_man[i].transform );
590 mdl_draw_submesh( &world.car_holden );
591 }
592 #endif
593 }
594
595 static void render_world_alphatest( m4x4f projection, v3f camera )
596 {
597 m4x3f identity_matrix;
598 m4x3_identity( identity_matrix );
599
600 shader_alphatest_use();
601 shader_alphatest_uTexGarbage(0);
602 shader_alphatest_uTexMain(1);
603 shader_link_standard_ub( _shader_alphatest.id, 2 );
604
605 vg_tex2d_bind( &tex_terrain_noise, 0 );
606 vg_tex2d_bind( &tex_alphatest, 1 );
607
608 shader_alphatest_uPv( projection );
609 shader_alphatest_uMdl( identity_matrix );
610 shader_alphatest_uCamera( camera );
611
612 glDisable(GL_CULL_FACE);
613 scene_bind( &world.foliage );
614 mdl_draw_submesh( &world.sm_foliage_alphatest );
615
616 vg_tex2d_bind( &tex_graffiti, 1 );
617 mdl_draw_submesh( &world.sm_graffiti );
618
619 glEnable(GL_CULL_FACE);
620 }
621
622 static void render_terrain( m4x4f projection, v3f camera )
623 {
624 m4x3f identity_matrix;
625 m4x3_identity( identity_matrix );
626
627 shader_terrain_use();
628 shader_terrain_uTexGarbage(0);
629 shader_terrain_uTexGradients(1);
630 shader_link_standard_ub( _shader_terrain.id, 2 );
631 bind_terrain_textures();
632
633 shader_terrain_uPv( projection );
634 shader_terrain_uMdl( identity_matrix );
635 shader_terrain_uCamera( camera );
636
637 scene_bind( &world.geo );
638 mdl_draw_submesh( &world.sm_geo_std_oob );
639 mdl_draw_submesh( &world.sm_geo_std );
640 mdl_draw_submesh( &world.sm_subworld );
641
642 /* TODO: Dont draw in reflection */
643 glDisable(GL_CULL_FACE);
644 scene_bind( &world.foliage );
645 mdl_draw_submesh( &world.sm_foliage_main );
646 glEnable(GL_CULL_FACE);
647 }
648
649 static void render_lowerdome( m4x3f camera )
650 {
651 m4x4f projection, full;
652 pipeline_projection( projection, 0.4f, 1000.0f );
653
654 m4x3f inverse;
655 m3x3_transpose( camera, inverse );
656 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
657 m4x3_expand( inverse, full );
658 m4x4_mul( projection, full, full );
659
660 m4x3f identity_matrix;
661 m4x3_identity( identity_matrix );
662
663 shader_planeinf_use();
664 shader_planeinf_uMdl(identity_matrix);
665 shader_planeinf_uPv(full);
666 shader_planeinf_uCamera(camera[3]);
667 shader_planeinf_uPlane( (v4f){0.0f,1.0f,0.0f, water_height()} );
668
669 mdl_draw_submesh( &world.dome_lower );
670 }
671
672 static void render_sky(m4x3f camera)
673 {
674 m4x4f projection, full;
675 pipeline_projection( projection, 0.4f, 1000.0f );
676
677 m4x3f inverse;
678 m3x3_transpose( camera, inverse );
679 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
680 m4x3_expand( inverse, full );
681 m4x4_mul( projection, full, full );
682
683 m4x3f identity_matrix;
684 m4x3_identity( identity_matrix );
685
686 shader_sky_use();
687 shader_sky_uMdl(identity_matrix);
688 shader_sky_uPv(full);
689 shader_sky_uTexGarbage(0);
690 shader_sky_uTime( vg_time );
691
692 vg_tex2d_bind( &tex_terrain_noise, 0 );
693
694 glDepthMask( GL_FALSE );
695 glDisable( GL_DEPTH_TEST );
696
697 mesh_bind( &world.skydome );
698 mdl_draw_submesh( &world.dome_upper );
699
700 glEnable( GL_DEPTH_TEST );
701 glDepthMask( GL_TRUE );
702 }
703
704 static void render_world_gates( m4x4f projection, m4x3f camera )
705 {
706 float closest = INFINITY;
707 int id = 0;
708
709 for( int i=0; i<world.routes.gate_count; i++ )
710 {
711 struct route_gate *rg = &world.routes.gates[i];
712 float dist = v3_dist2( rg->gate.co[0], camera[3] );
713
714 if( dist < closest )
715 {
716 closest = dist;
717 id = i;
718 }
719 }
720
721 render_gate( &world.routes.gates[id].gate, camera );
722 }
723
724 static void render_world( m4x4f projection, m4x3f camera )
725 {
726 render_sky( camera );
727 render_world_routes( projection, camera[3] );
728 render_world_vb( projection, camera[3] );
729 render_world_alphatest( projection, camera[3] );
730 render_terrain( projection, camera[3] );
731
732 m4x3f identity_matrix;
733 m4x3_identity( identity_matrix );
734 identity_matrix[3][1] = 125.0f;
735
736 v4f t;
737 q_axis_angle( t, (v3f){0.0f,1.0f,0.0f}, 2.3f );
738 q_m3x3( t, identity_matrix );
739
740 sfd_render( &world.sfd.tester, projection, camera[3], identity_matrix );
741 }
742
743 static void render_world_depth( m4x4f projection, m4x3f camera )
744 {
745 m4x3f identity_matrix;
746 m4x3_identity( identity_matrix );
747
748 shader_gpos_use();
749 shader_gpos_uCamera( camera[3] );
750 shader_gpos_uPv( projection );
751 shader_gpos_uMdl( identity_matrix );
752
753 scene_bind( &world.geo );
754 scene_draw( &world.geo );
755
756 #if 0
757 glDisable(GL_CULL_FACE);
758 scene_bind( &world.foliage );
759 scene_draw( &world.foliage );
760 glEnable(GL_CULL_FACE);
761 #endif
762 }
763
764 #endif /* WORLD_H */