the luxuries of a modern C compiler
[carveJwlIkooP6JGAAIwe30JlM.git] / world_render.c
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef WORLD_RENDER_C
6 #define WORLD_RENDER_C
7
8 #include "world.h"
9 #include "world_render.h"
10
11 VG_STATIC void async_world_render_init( void *payload, u32 size )
12 {
13 vg_info( "Allocate uniform buffers\n" );
14 for( int i=0; i<4; i++ ){
15 world_instance *world = &world_static.worlds[i];
16 world->ubo_bind_point = i;
17
18 glGenBuffers( 1, &world->ubo_lighting );
19 glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
20 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
21 NULL, GL_DYNAMIC_DRAW );
22
23 glBindBufferBase( GL_UNIFORM_BUFFER, i, world->ubo_lighting );
24 VG_CHECK_GL_ERR();
25 }
26
27 vg_info( "Allocate frame buffers\n" );
28 for( int i=0; i<4; i++ ){
29 world_instance *world = &world_static.worlds[i];
30 struct framebuffer *fb = &world->heightmap;
31
32 fb->display_name = NULL;
33 fb->link = NULL;
34 fb->fixed_w = 1024;
35 fb->fixed_h = 1024;
36 fb->resolution_div = 0;
37
38 fb->attachments[0].display_name = NULL;
39 fb->attachments[0].purpose = k_framebuffer_attachment_type_texture;
40 fb->attachments[0].internalformat = GL_RG16F;
41 fb->attachments[0].format = GL_RG;
42 fb->attachments[0].type = GL_FLOAT;
43 fb->attachments[0].attachment = GL_COLOR_ATTACHMENT0;
44
45 fb->attachments[1].purpose = k_framebuffer_attachment_type_none;
46 fb->attachments[2].purpose = k_framebuffer_attachment_type_none;
47 fb->attachments[3].purpose = k_framebuffer_attachment_type_none;
48 fb->attachments[4].purpose = k_framebuffer_attachment_type_none;
49
50 render_fb_allocate( fb );
51 }
52 }
53
54 VG_STATIC void world_render_init(void)
55 {
56 shader_scene_standard_register();
57 shader_scene_standard_alphatest_register();
58 shader_scene_vertex_blend_register();
59 shader_scene_terrain_register();
60 shader_scene_depth_register();
61 shader_scene_position_register();
62 shader_model_sky_register();
63
64 vg_info( "Loading default world textures\n" );
65 vg_tex2d_load_qoi_async_file( "textures/garbage.qoi",
66 VG_TEX2D_NEAREST|VG_TEX2D_REPEAT,
67 &world_render.tex_terrain_noise );
68
69 vg_async_call( async_world_render_init, NULL, 0 );
70 }
71
72 VG_STATIC void world_link_lighting_ub( world_instance *world, GLuint shader )
73 {
74 GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
75 glUniformBlockBinding( shader, idx, world->ubo_bind_point );
76 }
77
78 VG_STATIC void world_bind_position_texture( world_instance *world,
79 GLuint shader, GLuint location,
80 int slot )
81 {
82 render_fb_bind_texture( &world->heightmap, 0, slot );
83 glUniform1i( location, slot );
84 }
85
86 VG_STATIC void world_bind_light_array( world_instance *world,
87 GLuint shader, GLuint location,
88 int slot )
89 {
90 glActiveTexture( GL_TEXTURE0 + slot );
91 glBindTexture( GL_TEXTURE_BUFFER, world->tex_light_entities );
92 glUniform1i( location, slot );
93 }
94
95 VG_STATIC void world_bind_light_index( world_instance *world,
96 GLuint shader, GLuint location,
97 int slot )
98 {
99 glActiveTexture( GL_TEXTURE0 + slot );
100 glBindTexture( GL_TEXTURE_3D, world->tex_light_cubes );
101 glUniform1i( location, slot );
102 }
103
104 VG_STATIC void render_world_depth( world_instance *world, camera *cam );
105
106 /*
107 * Rendering
108 */
109
110 VG_STATIC void bind_terrain_noise(void)
111 {
112 glActiveTexture( GL_TEXTURE0 );
113 glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
114 }
115
116 struct world_pass{
117 camera *cam;
118 enum mdl_shader shader;
119 enum world_geo_type geo_type;
120
121 void (*fn_bind_textures)( world_instance *world,
122 struct world_surface *mat );
123 void (*fn_set_mdl)( m4x3f mdl );
124 void (*fn_set_uPvmPrev)( m4x4f pvm );
125 };
126
127 VG_STATIC void world_render_if( world_instance *world, struct world_pass *pass )
128 {
129 for( int i=0; i<world->surface_count; i++ ){
130 struct world_surface *mat = &world->surfaces[i];
131
132 if( mat->info.shader == pass->shader ){
133 mdl_submesh *sm;
134
135 if( pass->geo_type == k_world_geo_type_solid )
136 sm = &mat->sm_geo;
137 else
138 sm = &mat->sm_no_collide;
139
140 if( !sm->indice_count )
141 continue;
142
143 m4x3f mmdl;
144 m4x3_identity( mmdl );
145 pass->fn_set_mdl( mmdl );
146 pass->fn_set_uPvmPrev( pass->cam->mtx_prev.pv );
147
148 pass->fn_bind_textures( world, mat );
149 mdl_draw_submesh( sm );
150
151 for( u32 j=0; j<mdl_arrcount( &world->ent_traffic ); j++ ){
152 ent_traffic *traffic = mdl_arritm( &world->ent_traffic, j );
153
154 for( u32 k=0; k<traffic->submesh_count; k++ ){
155 sm = mdl_arritm( &world->meta.submeshs,
156 traffic->submesh_start+k );
157
158 q_m3x3( traffic->transform.q, mmdl );
159 v3_copy( traffic->transform.co, mmdl[3] );
160
161 m4x4f m4mdl;
162 m4x3_expand( mmdl, m4mdl );
163 m4x4_mul( pass->cam->mtx_prev.pv, m4mdl, m4mdl );
164
165 pass->fn_set_mdl( mmdl );
166 pass->fn_set_uPvmPrev( m4mdl );
167
168 mdl_draw_submesh( sm );
169 }
170 }
171 }
172 }
173 }
174
175 VG_STATIC
176 void world_render_both_stages( world_instance *world, struct world_pass *pass )
177 {
178 mesh_bind( &world->mesh_geo );
179 pass->geo_type = k_world_geo_type_solid;
180 world_render_if( world, pass );
181
182 glDisable( GL_CULL_FACE );
183 mesh_bind( &world->mesh_no_collide );
184 pass->geo_type = k_world_geo_type_nonsolid;
185 world_render_if( world, pass );
186 glEnable( GL_CULL_FACE );
187 }
188
189 VG_STATIC void bindpoint_diffuse_texture1( world_instance *world,
190 struct world_surface *mat )
191
192 {
193 glActiveTexture( GL_TEXTURE1 );
194 glBindTexture( GL_TEXTURE_2D, world->textures[ mat->info.tex_diffuse ] );
195 }
196
197 VG_STATIC void render_world_vb( world_instance *world, camera *cam )
198 {
199 shader_scene_vertex_blend_use();
200 shader_scene_vertex_blend_uTexGarbage(0);
201 shader_scene_vertex_blend_uTexGradients(1);
202 world_link_lighting_ub( world, _shader_scene_vertex_blend.id );
203 world_bind_position_texture( world, _shader_scene_vertex_blend.id,
204 _uniform_scene_vertex_blend_g_world_depth, 2 );
205 world_bind_light_array( world, _shader_scene_vertex_blend.id,
206 _uniform_scene_vertex_blend_uLightsArray, 3 );
207 world_bind_light_index( world, _shader_scene_vertex_blend.id,
208 _uniform_scene_vertex_blend_uLightsIndex, 4 );
209
210 glActiveTexture( GL_TEXTURE0 );
211 glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
212
213 shader_scene_vertex_blend_uPv( cam->mtx.pv );
214 shader_scene_vertex_blend_uCamera( cam->transform[3] );
215
216 struct world_pass pass = {
217 .shader = k_shader_standard_vertex_blend,
218 .cam = cam,
219 .fn_bind_textures = bindpoint_diffuse_texture1,
220 .fn_set_mdl = shader_scene_vertex_blend_uMdl,
221 .fn_set_uPvmPrev = shader_scene_vertex_blend_uPvmPrev,
222 };
223
224 world_render_both_stages( world, &pass );
225 }
226
227 VG_STATIC void render_world_standard( world_instance *world, camera *cam )
228 {
229 shader_scene_standard_use();
230 shader_scene_standard_uTexGarbage(0);
231 shader_scene_standard_uTexMain(1);
232 shader_scene_standard_uPv( cam->mtx.pv );
233
234 world_link_lighting_ub( world, _shader_scene_standard.id );
235 world_bind_position_texture( world, _shader_scene_standard.id,
236 _uniform_scene_standard_g_world_depth, 2 );
237 world_bind_light_array( world, _shader_scene_standard.id,
238 _uniform_scene_standard_uLightsArray, 3 );
239 world_bind_light_index( world, _shader_scene_standard.id,
240 _uniform_scene_standard_uLightsIndex, 4 );
241
242 bind_terrain_noise();
243 shader_scene_standard_uCamera( cam->transform[3] );
244
245 struct world_pass pass = {
246 .shader = k_shader_standard,
247 .cam = cam,
248 .fn_bind_textures = bindpoint_diffuse_texture1,
249 .fn_set_mdl = shader_scene_standard_uMdl,
250 .fn_set_uPvmPrev = shader_scene_standard_uPvmPrev,
251 };
252
253 world_render_both_stages( world, &pass );
254 }
255
256 VG_STATIC void render_world_alphatest( world_instance *world, camera *cam )
257 {
258 shader_scene_standard_alphatest_use();
259 shader_scene_standard_alphatest_uTexGarbage(0);
260 shader_scene_standard_alphatest_uTexMain(1);
261 shader_scene_standard_alphatest_uPv( cam->mtx.pv );
262
263 world_link_lighting_ub( world, _shader_scene_standard_alphatest.id );
264 world_bind_position_texture( world, _shader_scene_standard_alphatest.id,
265 _uniform_scene_standard_alphatest_g_world_depth, 2 );
266 world_bind_light_array( world, _shader_scene_standard_alphatest.id,
267 _uniform_scene_standard_alphatest_uLightsArray, 3 );
268 world_bind_light_index( world, _shader_scene_standard_alphatest.id,
269 _uniform_scene_standard_alphatest_uLightsIndex, 4 );
270
271
272 bind_terrain_noise();
273
274
275 shader_scene_standard_alphatest_uCamera( cam->transform[3] );
276
277 glDisable(GL_CULL_FACE);
278
279 struct world_pass pass = {
280 .shader = k_shader_standard_cutout,
281 .cam = cam,
282 .fn_bind_textures = bindpoint_diffuse_texture1,
283 .fn_set_mdl = shader_scene_standard_alphatest_uMdl,
284 .fn_set_uPvmPrev = shader_scene_standard_alphatest_uPvmPrev,
285 };
286
287 world_render_both_stages( world, &pass );
288
289 glEnable(GL_CULL_FACE);
290 }
291
292 VG_STATIC void bindpoint_terrain( world_instance *world,
293 struct world_surface *mat )
294 {
295 glActiveTexture( GL_TEXTURE1 );
296 glBindTexture( GL_TEXTURE_2D, world->textures[ mat->info.tex_diffuse ] );
297
298 shader_scene_terrain_uSandColour( mat->info.colour );
299 shader_scene_terrain_uBlendOffset( mat->info.colour1 );
300 }
301
302 VG_STATIC void render_terrain( world_instance *world, camera *cam )
303 {
304 shader_scene_terrain_use();
305 shader_scene_terrain_uTexGarbage(0);
306 shader_scene_terrain_uTexGradients(1);
307
308 world_link_lighting_ub( world, _shader_scene_terrain.id );
309 world_bind_position_texture( world, _shader_scene_terrain.id,
310 _uniform_scene_terrain_g_world_depth, 2 );
311 world_bind_light_array( world, _shader_scene_terrain.id,
312 _uniform_scene_terrain_uLightsArray, 3 );
313 world_bind_light_index( world, _shader_scene_terrain.id,
314 _uniform_scene_terrain_uLightsIndex, 4 );
315
316 glActiveTexture( GL_TEXTURE0 );
317 glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
318
319 shader_scene_terrain_uPv( cam->mtx.pv );
320 shader_scene_terrain_uCamera( cam->transform[3] );
321
322 struct world_pass pass = {
323 .shader = k_shader_terrain_blend,
324 .cam = cam,
325 .fn_bind_textures = bindpoint_terrain,
326 .fn_set_mdl = shader_scene_terrain_uMdl,
327 .fn_set_uPvmPrev = shader_scene_terrain_uPvmPrev,
328 };
329
330 world_render_both_stages( world, &pass );
331 }
332
333 VG_STATIC void render_sky( world_instance *world, camera *cam )
334 {
335 /*
336 * Modify matrix to remove clipping and view translation
337 */
338 m4x4f v,
339 v_prev,
340 pv,
341 pv_prev;
342
343 m4x4_copy( cam->mtx.v, v );
344 m4x4_copy( cam->mtx_prev.v, v_prev );
345 v3_zero( v[3] );
346 v3_zero( v_prev[3] );
347
348 m4x4_copy( cam->mtx.p, pv );
349 m4x4_copy( cam->mtx_prev.p, pv_prev );
350 m4x4_reset_clipping( pv, cam->farz, cam->nearz );
351 m4x4_reset_clipping( pv_prev, cam->farz, cam->nearz );
352
353 m4x4_mul( pv, v, pv );
354 m4x4_mul( pv_prev, v_prev, pv_prev );
355
356 m4x3f identity_matrix;
357 m4x3_identity( identity_matrix );
358
359 /*
360 * Draw
361 */
362 shader_model_sky_use();
363 shader_model_sky_uMdl( identity_matrix );
364 shader_model_sky_uPv( pv );
365 shader_model_sky_uPvmPrev( pv_prev );
366 shader_model_sky_uTexGarbage(0);
367 world_link_lighting_ub( world, _shader_model_sky.id );
368
369 glActiveTexture( GL_TEXTURE0 );
370 glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
371
372 glDepthMask( GL_FALSE );
373 glDisable( GL_DEPTH_TEST );
374
375 mesh_bind( &world_render.skydome );
376 mesh_draw( &world_render.skydome );
377
378 glEnable( GL_DEPTH_TEST );
379 glDepthMask( GL_TRUE );
380 }
381
382 VG_STATIC void render_world_gates( world_instance *world, camera *cam,
383 int layer_depth )
384 {
385 float closest = INFINITY;
386 struct ent_gate *gate = NULL;
387
388 for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
389 ent_gate *gi = mdl_arritm( &world->ent_gate, i );
390
391 if( gi->type == k_gate_type_unlinked )
392 continue;
393
394 float dist = v3_dist2( gi->co[0], cam->transform[3] );
395
396 vg_line_pt3( gi->co[0], 0.25f, VG__BLUE );
397
398 if( dist < closest ){
399 closest = dist;
400 gate = gi;
401 }
402 }
403
404 if( gate ){
405 /* should really be set in fixed update since its used in the physics
406 * of most systems. too bad! */
407 world->rendering_gate = gate;
408
409 if( gate->type == k_gate_type_teleport ){
410 render_gate( world, gate, cam, layer_depth );
411 }
412 else if( gate->type == k_gate_type_nonlocel ){
413 if( skaterift.async_op != k_async_op_world_loading &&
414 skaterift.async_op != k_async_op_world_preloading ){
415 world_instance *dest_world = &world_static.worlds[ gate->target ];
416 render_gate( dest_world, gate, cam, layer_depth );
417 }
418 }
419 else
420 world->rendering_gate = NULL;
421 }
422 }
423
424 VG_STATIC void world_prerender( world_instance *world )
425 {
426 world->time += vg.time_delta * (1.0/(k_day_length*60.0));
427
428 struct ub_world_lighting *state = &world->ub_lighting;
429
430 state->g_time = world->time;
431 state->g_realtime = vg.time;
432 state->g_debug_indices = k_debug_light_indices;
433 state->g_light_preview = k_light_preview;
434 state->g_debug_complexity = k_debug_light_complexity;
435 state->g_time_of_day = vg_fractf( world->time );
436 state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f );
437 state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf );
438
439 state->g_day_phase = state->g_day_phase * 0.5f + 0.5f;
440 state->g_sunset_phase = powf( state->g_sunset_phase * 0.5f + 0.5f, 6.0f );
441
442 float a = state->g_time_of_day * VG_PIf * 2.0f;
443 state->g_sun_dir[0] = sinf( a );
444 state->g_sun_dir[1] = cosf( a );
445 state->g_sun_dir[2] = 0.2f;
446 v3_normalize( state->g_sun_dir );
447
448 world->probabilities[ k_probability_curve_constant ] = 1.0f;
449 float dp = state->g_day_phase;
450
451 world->probabilities[ k_probability_curve_wildlife_day ] =
452 (dp*dp*0.8f+state->g_sunset_phase)*0.8f;
453 world->probabilities[ k_probability_curve_wildlife_night ] =
454 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f);
455
456 glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
457 glBufferSubData( GL_UNIFORM_BUFFER, 0,
458 sizeof(struct ub_world_lighting), &world->ub_lighting );
459 }
460
461 VG_STATIC void skateshop_render(void);
462 VG_STATIC void render_world( world_instance *world, camera *cam,
463 int layer_depth )
464 {
465 render_sky( world, cam );
466
467 render_world_routes( world, cam, layer_depth );
468 render_world_standard( world, cam );
469 render_world_vb( world, cam );
470 render_world_alphatest( world, cam );
471 render_terrain( world, cam );
472
473 if( layer_depth == 0 ){
474 skateshop_render();
475
476 /* Render SFD's */
477 u32 closest = 0;
478 float min_dist = INFINITY;
479
480 if( !mdl_arrcount( &world->ent_route ) )
481 return;
482
483 for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
484 ent_route *route = mdl_arritm( &world->ent_route, i );
485 float dist = v3_dist2( route->board_transform[3], cam->pos );
486
487 if( dist < min_dist ){
488 min_dist = dist;
489 closest = i;
490 }
491 }
492
493 ent_route *route = mdl_arritm( &world->ent_route, closest );
494 sfd_render( world, cam, route->board_transform );
495 }
496 }
497
498 VG_STATIC void render_world_depth( world_instance *world, camera *cam )
499 {
500 m4x3f identity_matrix;
501 m4x3_identity( identity_matrix );
502
503 shader_scene_depth_use();
504 shader_scene_depth_uCamera( cam->transform[3] );
505 shader_scene_depth_uPv( cam->mtx.pv );
506 shader_scene_depth_uPvmPrev( cam->mtx_prev.pv );
507 shader_scene_depth_uMdl( identity_matrix );
508 world_link_lighting_ub( world, _shader_scene_depth.id );
509
510 mesh_bind( &world->mesh_geo );
511 mesh_draw( &world->mesh_geo );
512 }
513
514 VG_STATIC void render_world_position( world_instance *world, camera *cam )
515 {
516 m4x3f identity_matrix;
517 m4x3_identity( identity_matrix );
518
519 shader_scene_position_use();
520 shader_scene_position_uCamera( cam->transform[3] );
521 shader_scene_position_uPv( cam->mtx.pv );
522 shader_scene_position_uPvmPrev( cam->mtx_prev.pv );
523 shader_scene_position_uMdl( identity_matrix );
524 world_link_lighting_ub( world, _shader_scene_position.id );
525
526 mesh_bind( &world->mesh_geo );
527 mesh_draw( &world->mesh_geo );
528 }
529
530 #endif