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