rework scene 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 "shaders/terrain.h"
19 #include "shaders/sky.h"
20 #include "shaders/planeinf.h"
21 #include "shaders/standard.h"
22 #include "shaders/vblend.h"
23 #include "shaders/gpos.h"
24 #include "shaders/fscolour.h"
25
26 static struct gworld
27 {
28 /* gameplay */
29 struct respawn_point
30 {
31 v3f co;
32 v4f q;
33 char name[32];
34 }
35 spawns[32];
36 u32 spawn_count;
37
38 teleport_gate gates[64];
39 u32 gate_count;
40
41 /* Physics */
42 rigidbody temp_rbs[128];
43 u32 rb_count;
44 bh_tree bhcubes;
45
46 /* Rendering & geometry */
47 scene geo, foliage, props;
48 mdl_submesh sm_surface;
49
50 glmesh skybox, skydome;
51 mdl_submesh dome_upper, dome_lower;
52 }
53 world;
54
55 vg_tex2d tex_terrain_colours = { .path = "textures/gradients.qoi",
56 .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST };
57
58 vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi",
59 .flags = VG_TEXTURE_NEAREST };
60
61 static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
62 {
63 for( int i=0; i<3; i++ )
64 v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
65 }
66
67 static int ray_world( v3f pos, v3f dir, ray_hit *hit )
68 {
69 return scene_raycast( &world.geo, pos, dir, hit );
70 }
71
72 static int ray_hit_is_ramp( ray_hit *hit )
73 {
74 return hit->tri[0] < world.sm_surface.vertex_count;
75 }
76
77 static void world_register(void)
78 {
79 shader_terrain_register();
80 shader_sky_register();
81 shader_planeinf_register();
82 shader_gpos_register();
83 shader_fscolour_register();
84 }
85
86 static void world_free(void)
87 {
88 /* TODO.. */
89 }
90
91 static void render_world_depth( m4x4f projection, m4x3f camera );
92
93 static void add_all_if_material( scene *pscene, mdl_header *mdl, u32 id )
94 {
95 for( int i=0; i<mdl->node_count; i++ )
96 {
97 mdl_node *pnode = mdl_node_from_id( mdl, i );
98
99 for( int j=0; j<pnode->submesh_count; j++ )
100 {
101 mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
102
103 if( sm->material_id == id )
104 {
105 m4x3f transform;
106 mdl_node_transform( pnode, transform );
107 scene_add_submesh( pscene, mdl, sm, transform );
108 }
109 }
110 }
111 }
112
113 static void world_apply_foliage(void)
114 {
115 scene_init( &world.foliage );
116 mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
117
118 v3f volume;
119 v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
120 volume[1] = 1.0f;
121
122 m4x3f transform;
123 mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
124 mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
125
126 for( int i=0;i<100000;i++ )
127 {
128 v3f pos;
129 v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
130 pos[1] = 1000.0f;
131 v3_add( pos, world.geo.bbx[0], pos );
132
133 ray_hit hit;
134 hit.dist = INFINITY;
135
136 if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
137 {
138 if( hit.normal[1] > 0.8f && !ray_hit_is_ramp(&hit) &&
139 hit.pos[1] > water_height()+10.0f )
140 {
141 v4f qsurface, qrandom;
142 v3f axis;
143
144 v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis );
145
146 float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f});
147 q_axis_angle( qsurface, axis, angle );
148 q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf );
149 q_mul( qsurface, qrandom, qsurface );
150 q_m3x3( qsurface, transform );
151
152 v3_copy( hit.pos, transform[3] );
153 scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
154 }
155 }
156 }
157
158 scene_upload( &world.foliage );
159 free( mfoliage );
160 }
161
162 static void world_load(void)
163 {
164 mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
165
166 world.spawn_count = 0;
167 world.gate_count = 0;
168 world.rb_count = 0;
169
170 scene_init( &world.geo );
171 scene_init( &world.props );
172
173 /*
174 * Compile meshes into the world scenes
175 */
176 u32 mat_surf = 0,
177 mat_surf_oob = 0,
178 mat_vertex_blend = 0;
179
180 for( int i=1; i<mworld->material_count; i++ )
181 {
182 mdl_material *mat = mdl_material_from_id( mworld, i );
183 const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
184
185 vg_info( "%d %s\n", mat->pstr_name, mat_name );
186
187 if( !strcmp( "surf", mat_name ))
188 mat_surf = i;
189 else if( !strcmp( "surf_oob", mat_name ))
190 mat_surf_oob = i;
191 else if( !strcmp( "vertex_blend", mat_name ))
192 mat_vertex_blend = i;
193 }
194
195 if( mat_surf )
196 add_all_if_material( &world.geo, mworld, mat_surf );
197
198 scene_copy_slice( &world.geo, &world.sm_surface );
199
200 if( mat_surf_oob )
201 add_all_if_material( &world.geo, mworld, mat_surf_oob );
202 else
203 vg_warn( "No OOB surface\n" );
204
205 scene_bh_create( &world.geo );
206 scene_upload( &world.geo );
207
208 if( mat_vertex_blend )
209 add_all_if_material( &world.props, mworld, mat_vertex_blend );
210
211 /* TODO bvh? */
212
213 /*
214 * Process entities
215 */
216 for( int i=0; i<mworld->node_count; i++ )
217 {
218 mdl_node *pnode = mdl_node_from_id( mworld, i );
219
220 if( pnode->classtype == k_classtype_none )
221 {}
222 else if( pnode->classtype == k_classtype_gate )
223 {
224 struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode );
225 mdl_node *pother = mdl_node_from_id( mworld, entgate->target );
226
227 teleport_gate *gate = &world.gates[ world.gate_count ++ ];
228
229 v3_copy( pnode->co, gate->co[0] );
230 v3_copy( pother->co, gate->co[1] );
231 v4_copy( pnode->q, gate->q[0] );
232 v4_copy( pother->q, gate->q[1] );
233 v2_copy( pnode->s, gate->dims );
234
235 gate_transform_update( gate );
236 }
237 else if( pnode->classtype == k_classtype_block )
238 {
239 struct classtype_block *block = mdl_get_entdata( mworld, pnode );
240
241 m4x3f transform;
242 mdl_node_transform( pnode, transform );
243
244 rigidbody *rb = &world.temp_rbs[ world.rb_count ++ ];
245
246 box_copy( block->bbx, rb->bbx ); /* TODO: apply scale */
247 v3_copy( pnode->co, rb->co );
248 rb_init( rb );
249 v4_copy( pnode->q, rb->q );
250 rb_update_transform( rb );
251 }
252 else if( pnode->classtype == k_classtype_spawn )
253 {
254 struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
255
256 v3_copy( pnode->co, rp->co );
257 v4_copy( pnode->q, rp->q );
258 strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
259 }
260 else if( pnode->classtype == k_classtype_water )
261 {
262 if( wrender.enabled )
263 {
264 vg_warn( "Multiple water surfaces in level! ('%s')\n",
265 mdl_pstr( mworld, pnode->pstr_name ));
266 continue;
267 }
268
269 mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
270
271 if( sm )
272 {
273 glmesh surf;
274 mdl_unpack_submesh( mworld, &surf, sm );
275 water_init();
276 water_set_surface( &surf, pnode->co[1] );
277 }
278 }
279 }
280
281 scene_upload( &world.props );
282
283 bh_create( &world.bhcubes,
284 &bh_system_rigidbodies, world.temp_rbs, world.rb_count );
285
286 world_apply_foliage();
287 free( mworld );
288
289 /*
290 * Rendering the depth map
291 */
292 m4x4f ortho;
293 m4x3f camera;
294
295 v3f extent;
296 v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
297
298 float fl = world.geo.bbx[0][0],
299 fr = world.geo.bbx[1][0],
300 fb = world.geo.bbx[0][2],
301 ft = world.geo.bbx[1][2],
302 rl = 1.0f / (fr-fl),
303 tb = 1.0f / (ft-fb);
304
305 m4x4_zero( ortho );
306 ortho[0][0] = 2.0f * rl;
307 ortho[2][1] = 2.0f * tb;
308 ortho[3][0] = (fr + fl) * -rl;
309 ortho[3][1] = (ft + fb) * -tb;
310 ortho[3][3] = 1.0f;
311 m4x3_identity( camera );
312
313 glViewport( 0, 0, 1024, 1024 );
314 glDisable(GL_DEPTH_TEST);
315 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
316 shader_fscolour_use();
317 shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} );
318 render_fsquad();
319
320 glEnable(GL_BLEND);
321 glBlendFunc(GL_ONE, GL_ONE);
322 glBlendEquation(GL_MAX);
323 render_world_depth( ortho, camera );
324 glDisable(GL_BLEND);
325 glEnable(GL_DEPTH_TEST);
326
327 /*
328 * TODO: World settings entity
329 */
330 struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
331 v4_copy( wrender.plane, winfo->g_water_plane );
332
333 v4f bounds;
334 bounds[0] = world.geo.bbx[0][0];
335 bounds[1] = world.geo.bbx[0][2];
336 bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
337 bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
338 v4_copy( bounds, winfo->g_depth_bounds );
339
340 winfo->g_water_fog = 0.04f;
341 render_update_lighting_ub();
342 }
343
344 static void world_init(void)
345 {
346 vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours,
347 &tex_terrain_noise }, 2 );
348
349
350 mdl_header *msky = mdl_load("models/rs_skydome.mdl");
351 mdl_unpack_glmesh( msky, &world.skydome );
352
353 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
354 *nupper = mdl_node_from_name( msky, "dome_upper" );
355
356 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
357 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
358 free(msky);
359 }
360
361 /*
362 * Rendering
363 */
364
365 static void bind_terrain_textures(void)
366 {
367 vg_tex2d_bind( &tex_terrain_noise, 0 );
368 vg_tex2d_bind( &tex_terrain_colours, 1 );
369 }
370
371 static void render_props( m4x4f projection, v3f camera )
372 {
373 m4x3f identity_matrix;
374 m4x3_identity( identity_matrix );
375
376 shader_vblend_use();
377 shader_vblend_uTexGarbage(0);
378 shader_vblend_uTexGradients(1);
379 shader_link_standard_ub( _shader_vblend.id, 2 );
380 bind_terrain_textures();
381
382 shader_vblend_uPv( projection );
383 shader_vblend_uMdl( identity_matrix );
384 shader_vblend_uCamera( camera );
385
386 scene_bind( &world.props );
387 scene_draw( &world.props );
388 }
389
390 static void render_terrain( m4x4f projection, v3f camera )
391 {
392 m4x3f identity_matrix;
393 m4x3_identity( identity_matrix );
394
395 shader_terrain_use();
396 shader_terrain_uTexGarbage(0);
397 shader_terrain_uTexGradients(1);
398 shader_link_standard_ub( _shader_terrain.id, 2 );
399 bind_terrain_textures();
400
401 shader_terrain_uPv( projection );
402 shader_terrain_uMdl( identity_matrix );
403 shader_terrain_uCamera( camera );
404
405 scene_bind( &world.geo );
406 scene_draw( &world.geo );
407
408 glDisable(GL_CULL_FACE);
409 scene_bind( &world.foliage );
410 scene_draw( &world.foliage );
411 glEnable(GL_CULL_FACE);
412 }
413
414 static void render_lowerdome( m4x3f camera )
415 {
416 m4x4f projection, full;
417 pipeline_projection( projection, 0.4f, 1000.0f );
418
419 m4x3f inverse;
420 m3x3_transpose( camera, inverse );
421 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
422 m4x3_expand( inverse, full );
423 m4x4_mul( projection, full, full );
424
425 m4x3f identity_matrix;
426 m4x3_identity( identity_matrix );
427
428 shader_planeinf_use();
429 shader_planeinf_uMdl(identity_matrix);
430 shader_planeinf_uPv(full);
431 shader_planeinf_uCamera(camera[3]);
432 shader_planeinf_uPlane( (v4f){0.0f,1.0f,0.0f, water_height()} );
433
434 mdl_draw_submesh( &world.dome_lower );
435 }
436
437 static void render_sky(m4x3f camera)
438 {
439 m4x4f projection, full;
440 pipeline_projection( projection, 0.4f, 1000.0f );
441
442 m4x3f inverse;
443 m3x3_transpose( camera, inverse );
444 v3_copy((v3f){0.0f,0.0f,0.0f}, inverse[3]);
445 m4x3_expand( inverse, full );
446 m4x4_mul( projection, full, full );
447
448 m4x3f identity_matrix;
449 m4x3_identity( identity_matrix );
450
451 shader_sky_use();
452 shader_sky_uMdl(identity_matrix);
453 shader_sky_uPv(full);
454 shader_sky_uTexGarbage(0);
455 shader_sky_uTime( vg_time );
456
457 vg_tex2d_bind( &tex_terrain_noise, 0 );
458
459 glDepthMask( GL_FALSE );
460 glDisable( GL_DEPTH_TEST );
461
462 mesh_bind( &world.skydome );
463 mdl_draw_submesh( &world.dome_upper );
464
465 glEnable( GL_DEPTH_TEST );
466 glDepthMask( GL_TRUE );
467 }
468
469 static void render_world( m4x4f projection, m4x3f camera )
470 {
471 render_sky( camera );
472 render_props( projection, camera[3] );
473 render_terrain( projection, camera[3] );
474 }
475
476 static void render_world_depth( m4x4f projection, m4x3f camera )
477 {
478 m4x3f identity_matrix;
479 m4x3_identity( identity_matrix );
480
481 shader_gpos_use();
482 shader_gpos_uCamera( camera[3] );
483 shader_gpos_uPv( projection );
484 shader_gpos_uMdl( identity_matrix );
485
486 scene_bind( &world.geo );
487 scene_draw( &world.geo );
488
489 #if 0
490 glDisable(GL_CULL_FACE);
491 scene_bind( &world.foliage );
492 scene_draw( &world.foliage );
493 glEnable(GL_CULL_FACE);
494 #endif
495
496 scene_bind( &world.props );
497 scene_draw( &world.props );
498 }
499
500 #endif /* WORLD_H */