2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
9 #include "world_render.h"
14 static int ccmd_set_time( int argc
, const char *argv
[] ){
15 world_instance
*world
= world_current_instance();
17 world
->time
= atof( argv
[0] );
19 vg_error( "Usage set_time <0-1.0> (current time: %f)\n", world
->time
);
23 static void async_world_render_init( void *payload
, u32 size
)
25 vg_info( "Allocate uniform buffers\n" );
26 for( int i
=0; i
<k_world_max
; i
++ ){
27 world_instance
*world
= &world_static
.instances
[i
];
28 world
->ubo_bind_point
= i
;
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
);
35 glBindBufferBase( GL_UNIFORM_BUFFER
, i
, world
->ubo_lighting
);
39 vg_info( "Allocate frame buffers\n" );
40 for( int i
=0; i
<k_world_max
; i
++ ){
41 world_instance
*world
= &world_static
.instances
[i
];
42 struct framebuffer
*fb
= &world
->heightmap
;
44 fb
->display_name
= NULL
;
48 fb
->resolution_div
= 0;
50 fb
->attachments
[0].display_name
= NULL
;
51 fb
->attachments
[0].purpose
= k_framebuffer_attachment_type_texture
;
52 fb
->attachments
[0].internalformat
= GL_RG16F
;
53 fb
->attachments
[0].format
= GL_RG
;
54 fb
->attachments
[0].type
= GL_FLOAT
;
55 fb
->attachments
[0].attachment
= GL_COLOR_ATTACHMENT0
;
57 fb
->attachments
[1].purpose
= k_framebuffer_attachment_type_none
;
58 fb
->attachments
[2].purpose
= k_framebuffer_attachment_type_none
;
59 fb
->attachments
[3].purpose
= k_framebuffer_attachment_type_none
;
60 fb
->attachments
[4].purpose
= k_framebuffer_attachment_type_none
;
62 render_fb_allocate( fb
);
66 static void world_render_init(void)
68 VG_VAR_F32( k_day_length
);
69 VG_VAR_I32( k_debug_light_indices
);
70 VG_VAR_I32( k_debug_light_complexity
);
71 VG_VAR_I32( k_light_preview
);
72 vg_console_reg_cmd( "set_time", ccmd_set_time
, NULL
);
74 world_render
.sky_rate
= 1.0;
75 world_render
.sky_target_rate
= 1.0;
77 shader_scene_standard_register();
78 shader_scene_standard_alphatest_register();
79 shader_scene_override_register();
80 shader_scene_cubemapped_register();
81 shader_scene_fxglow_register();
82 shader_scene_vertex_blend_register();
83 shader_scene_terrain_register();
84 shader_scene_depth_register();
85 shader_scene_position_register();
86 shader_model_sky_register();
87 shader_model_sky_space_register();
89 vg_info( "Loading world resources\n" );
90 vg_linear_clear( vg_mem
.scratch
);
93 mdl_open( &msky
, "models/rs_skydome.mdl", vg_mem
.scratch
);
94 mdl_load_metadata_block( &msky
, vg_mem
.scratch
);
95 mdl_async_load_glmesh( &msky
, &world_render
.skydome
);
98 vg_info( "Loading default world textures\n" );
99 vg_tex2d_load_qoi_async_file( "textures/garbage.qoi",
100 VG_TEX2D_NEAREST
|VG_TEX2D_REPEAT
,
101 &world_render
.tex_terrain_noise
);
103 vg_async_call( async_world_render_init
, NULL
, 0 );
106 static void world_link_lighting_ub( world_instance
*world
, GLuint shader
){
107 GLuint idx
= glGetUniformBlockIndex( shader
, "ub_world_lighting" );
108 glUniformBlockBinding( shader
, idx
, world
->ubo_bind_point
);
111 static void world_bind_position_texture( world_instance
*world
,
112 GLuint shader
, GLuint location
,
114 render_fb_bind_texture( &world
->heightmap
, 0, slot
);
115 glUniform1i( location
, slot
);
118 static void world_bind_light_array( world_instance
*world
,
119 GLuint shader
, GLuint location
,
121 glActiveTexture( GL_TEXTURE0
+ slot
);
122 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
123 glUniform1i( location
, slot
);
126 static void world_bind_light_index( world_instance
*world
,
127 GLuint shader
, GLuint location
,
129 glActiveTexture( GL_TEXTURE0
+ slot
);
130 glBindTexture( GL_TEXTURE_3D
, world
->tex_light_cubes
);
131 glUniform1i( location
, slot
);
134 static void render_world_depth( world_instance
*world
, camera
*cam
);
140 static void bind_terrain_noise(void){
141 glActiveTexture( GL_TEXTURE0
);
142 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
147 enum mdl_shader shader
;
148 enum world_geo_type geo_type
;
150 void (*fn_bind_textures
)( world_instance
*world
,
151 struct world_surface
*mat
);
152 void (*fn_set_mdl
)( m4x3f mdl
);
153 void (*fn_set_uPvmPrev
)( m4x4f pvm
);
154 void (*fn_set_uNormalMtx
)( m3x3f mnorm
);
158 void world_render_traffic( world_instance
*world
, u32 material_id
,
159 struct world_pass
*pass
){
160 if( !mdl_arrcount( &world
->ent_traffic
) ) return;
162 /* HACK: use the first material for every traffic entity */
163 ent_traffic
*first
= mdl_arritm( &world
->ent_traffic
, 0 );
164 if( !first
->submesh_count
) return;
166 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
, first
->submesh_start
);
167 if( sm
->material_id
!= material_id
) return;
169 struct world_surface
*mat
= &world
->surfaces
[ material_id
];
170 pass
->fn_bind_textures( world
, mat
);
172 for( u32 j
=0; j
<mdl_arrcount( &world
->ent_traffic
); j
++ ){
173 ent_traffic
*traffic
= mdl_arritm( &world
->ent_traffic
, j
);
175 for( u32 k
=0; k
<traffic
->submesh_count
; k
++ ){
176 sm
= mdl_arritm( &world
->meta
.submeshs
,
177 traffic
->submesh_start
+k
);
180 q_m3x3( traffic
->transform
.q
, mmdl
);
181 v3_copy( traffic
->transform
.co
, mmdl
[3] );
184 m4x3_expand( mmdl
, m4mdl
);
185 m4x4_mul( pass
->cam
->mtx_prev
.pv
, m4mdl
, m4mdl
);
187 pass
->fn_set_mdl( mmdl
);
188 pass
->fn_set_uPvmPrev( m4mdl
);
190 mdl_draw_submesh( sm
);
196 void world_render_pass( world_instance
*world
, struct world_pass
*pass
){
197 for( int i
=0; i
<world
->surface_count
; i
++ ){
198 struct world_surface
*mat
= &world
->surfaces
[i
];
200 if( mat
->info
.shader
== pass
->shader
){
203 if( pass
->geo_type
== k_world_geo_type_solid
){
207 world_render_traffic( world
, i
, pass
);
208 sm
= &mat
->sm_no_collide
;
211 if( !sm
->indice_count
)
215 m4x3_identity( mmdl
);
216 pass
->fn_set_mdl( mmdl
);
217 pass
->fn_set_uPvmPrev( pass
->cam
->mtx_prev
.pv
);
219 pass
->fn_bind_textures( world
, mat
);
220 mdl_draw_submesh( sm
);
226 void world_render_both_stages( world_instance
*world
, struct world_pass
*pass
)
228 mesh_bind( &world
->mesh_geo
);
229 pass
->geo_type
= k_world_geo_type_solid
;
230 world_render_pass( world
, pass
);
232 glDisable( GL_CULL_FACE
);
233 mesh_bind( &world
->mesh_no_collide
);
234 pass
->geo_type
= k_world_geo_type_nonsolid
;
235 world_render_pass( world
, pass
);
236 glEnable( GL_CULL_FACE
);
239 static void bindpoint_diffuse_texture1( world_instance
*world
,
240 struct world_surface
*mat
)
243 glActiveTexture( GL_TEXTURE1
);
244 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
247 static void bindpoint_diffuse1_and_cubemap10( world_instance
*world
,
248 struct world_surface
*mat
){
249 glActiveTexture( GL_TEXTURE1
);
250 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
252 u32 cubemap_id
= mat
->info
.tex_none0
,
255 if( mdl_entity_id_type( cubemap_id
) == k_ent_cubemap
){
256 cubemap_index
= mdl_entity_id_id( cubemap_id
);
259 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, cubemap_index
);
260 glActiveTexture( GL_TEXTURE10
);
261 glBindTexture( GL_TEXTURE_CUBE_MAP
, cm
->texture_id
);
263 shader_scene_cubemapped_uColour( mat
->info
.colour
);
266 static void render_world_vb( world_instance
*world
, camera
*cam
){
267 shader_scene_vertex_blend_use();
268 shader_scene_vertex_blend_uTexGarbage(0);
269 shader_scene_vertex_blend_uTexGradients(1);
270 world_link_lighting_ub( world
, _shader_scene_vertex_blend
.id
);
271 world_bind_position_texture( world
, _shader_scene_vertex_blend
.id
,
272 _uniform_scene_vertex_blend_g_world_depth
, 2 );
273 world_bind_light_array( world
, _shader_scene_vertex_blend
.id
,
274 _uniform_scene_vertex_blend_uLightsArray
, 3 );
275 world_bind_light_index( world
, _shader_scene_vertex_blend
.id
,
276 _uniform_scene_vertex_blend_uLightsIndex
, 4 );
278 glActiveTexture( GL_TEXTURE0
);
279 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
281 shader_scene_vertex_blend_uPv( cam
->mtx
.pv
);
282 shader_scene_vertex_blend_uCamera( cam
->transform
[3] );
284 struct world_pass pass
= {
285 .shader
= k_shader_standard_vertex_blend
,
287 .fn_bind_textures
= bindpoint_diffuse_texture1
,
288 .fn_set_mdl
= shader_scene_vertex_blend_uMdl
,
289 .fn_set_uPvmPrev
= shader_scene_vertex_blend_uPvmPrev
,
292 world_render_both_stages( world
, &pass
);
295 static void world_shader_standard_bind( world_instance
*world
, camera
*cam
){
296 shader_scene_standard_use();
297 shader_scene_standard_uTexGarbage(0);
298 shader_scene_standard_uTexMain(1);
299 shader_scene_standard_uPv( cam
->mtx
.pv
);
301 world_link_lighting_ub( world
, _shader_scene_standard
.id
);
302 world_bind_position_texture( world
, _shader_scene_standard
.id
,
303 _uniform_scene_standard_g_world_depth
, 2 );
304 world_bind_light_array( world
, _shader_scene_standard
.id
,
305 _uniform_scene_standard_uLightsArray
, 3 );
306 world_bind_light_index( world
, _shader_scene_standard
.id
,
307 _uniform_scene_standard_uLightsIndex
, 4 );
309 bind_terrain_noise();
310 shader_scene_standard_uCamera( cam
->transform
[3] );
313 static void render_world_standard( world_instance
*world
, camera
*cam
){
314 world_shader_standard_bind( world
, cam
);
315 struct world_pass pass
= {
316 .shader
= k_shader_standard
,
318 .fn_bind_textures
= bindpoint_diffuse_texture1
,
319 .fn_set_mdl
= shader_scene_standard_uMdl
,
320 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
323 world_render_both_stages( world
, &pass
);
326 static void render_world_cubemapped( world_instance
*world
, camera
*cam
,
328 if( !mdl_arrcount( &world
->ent_cubemap
) )
331 if( layer_depth
== -1 ){
332 world_shader_standard_bind( world
, cam
);
334 struct world_pass pass
= {
335 .shader
= k_shader_cubemap
,
337 .fn_bind_textures
= bindpoint_diffuse_texture1
,
338 .fn_set_mdl
= shader_scene_standard_uMdl
,
339 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
342 world_render_both_stages( world
, &pass
);
345 shader_scene_cubemapped_use();
346 shader_scene_cubemapped_uTexGarbage(0);
347 shader_scene_cubemapped_uTexMain(1);
348 shader_scene_cubemapped_uTexCubemap(10);
349 shader_scene_cubemapped_uPv( cam
->mtx
.pv
);
351 world_link_lighting_ub( world
, _shader_scene_cubemapped
.id
);
352 world_bind_position_texture( world
, _shader_scene_cubemapped
.id
,
353 _uniform_scene_cubemapped_g_world_depth
, 2 );
354 world_bind_light_array( world
, _shader_scene_cubemapped
.id
,
355 _uniform_scene_cubemapped_uLightsArray
, 3 );
356 world_bind_light_index( world
, _shader_scene_cubemapped
.id
,
357 _uniform_scene_cubemapped_uLightsIndex
, 4 );
359 bind_terrain_noise();
360 shader_scene_cubemapped_uCamera( cam
->transform
[3] );
362 struct world_pass pass
= {
363 .shader
= k_shader_cubemap
,
365 .fn_bind_textures
= bindpoint_diffuse1_and_cubemap10
,
366 .fn_set_mdl
= shader_scene_cubemapped_uMdl
,
367 .fn_set_uPvmPrev
= shader_scene_cubemapped_uPvmPrev
,
370 world_render_both_stages( world
, &pass
);
374 static void render_world_alphatest( world_instance
*world
, camera
*cam
){
375 shader_scene_standard_alphatest_use();
376 shader_scene_standard_alphatest_uTexGarbage(0);
377 shader_scene_standard_alphatest_uTexMain(1);
378 shader_scene_standard_alphatest_uPv( cam
->mtx
.pv
);
380 world_link_lighting_ub( world
, _shader_scene_standard_alphatest
.id
);
381 world_bind_position_texture( world
, _shader_scene_standard_alphatest
.id
,
382 _uniform_scene_standard_alphatest_g_world_depth
, 2 );
383 world_bind_light_array( world
, _shader_scene_standard_alphatest
.id
,
384 _uniform_scene_standard_alphatest_uLightsArray
, 3 );
385 world_bind_light_index( world
, _shader_scene_standard_alphatest
.id
,
386 _uniform_scene_standard_alphatest_uLightsIndex
, 4 );
389 bind_terrain_noise();
392 shader_scene_standard_alphatest_uCamera( cam
->transform
[3] );
394 glDisable(GL_CULL_FACE
);
396 struct world_pass pass
= {
397 .shader
= k_shader_standard_cutout
,
399 .fn_bind_textures
= bindpoint_diffuse_texture1
,
400 .fn_set_mdl
= shader_scene_standard_alphatest_uMdl
,
401 .fn_set_uPvmPrev
= shader_scene_standard_alphatest_uPvmPrev
,
404 world_render_both_stages( world
, &pass
);
406 glEnable(GL_CULL_FACE
);
410 void world_render_challenges( world_instance
*world
, struct world_pass
*pass
,
411 v3f pos
, int layer_depth
){
413 if( skaterift
.activity
== k_skaterift_replay
) return;
414 if( world
!= world_current_instance() ) return;
419 u32 objective_list
[ 32 ],
420 challenge_list
[ 16 ];
422 v2f objective_uv_offsets
[ 32 ];
424 u32 objective_count
= 0,
427 ent_challenge
*active_challenge
= NULL
;
429 if( mdl_entity_id_type( world_static
.focused_entity
) == k_ent_challenge
){
430 if( (skaterift
.activity
== k_skaterift_default
) &&
431 world_static
.challenge_target
){
435 if( !((skaterift
.activity
!= k_skaterift_ent_focus
) &&
436 !world_static
.challenge_target
) ){
437 world_instance
*challenge_world
= world_current_instance();
438 u32 index
= mdl_entity_id_id( world_static
.focused_entity
);
439 active_challenge
= mdl_arritm(&challenge_world
->ent_challenge
, index
);
443 if( active_challenge
){
444 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
445 challenge_list
[ challenge_count
++ ] = world_static
.focused_entity
;
447 u32 next
= active_challenge
->first
;
448 while( mdl_entity_id_type(next
) == k_ent_objective
){
449 u32 index
= mdl_entity_id_id( next
);
450 objective_list
[ objective_count
++ ] = index
;
452 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
453 next
= objective
->id_next
;
459 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
461 bh_iter_init_range( 0, &it
, pos
, radius
+10.0f
);
463 while( bh_next( world
->entity_bh
, &it
, &idx
) ){
464 u32 id
= world
->entity_list
[ idx
],
465 type
= mdl_entity_id_type( id
),
466 index
= mdl_entity_id_id( id
);
468 if( type
== k_ent_objective
) {
469 if( objective_count
< vg_list_size(objective_list
) )
470 objective_list
[ objective_count
++ ] = index
;
472 else if( type
== k_ent_challenge
){
473 if( challenge_count
< vg_list_size(challenge_list
) )
474 challenge_list
[ challenge_count
++ ] = index
;
479 /* render objectives */
480 glDisable( GL_CULL_FACE
);
481 mesh_bind( &world
->mesh_no_collide
);
482 u32 last_material
= 0;
483 for( u32 i
=0; i
<objective_count
; i
++ ){
484 u32 index
= objective_list
[ i
];
485 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
486 if( (objective
->flags
& k_ent_objective_hidden
) &&
487 !active_challenge
) continue;
492 u32 passed
= objective
->flags
& k_ent_objective_passed
;
493 f32 target
= passed
? 0.0f
: 1.0f
;
494 vg_slewf(&objective
->transform
.s
[0], target
, vg
.time_frame_delta
*4.0f
);
495 scale
= vg_smoothstepf( objective
->transform
.s
[0] );
497 if( (objective
== world_static
.challenge_target
) || passed
)
498 shader_scene_fxglow_uUvOffset( (v2f
){ 16.0f
/256.0f
, 0.0f
} );
500 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
503 f32 dist
= v3_dist( objective
->transform
.co
, pos
) * (1.0f
/radius
);
504 scale
= vg_smoothstepf( vg_clampf( 5.0f
-dist
*5.0f
, 0.0f
,1.0f
) );
508 q_m3x3( objective
->transform
.q
, mmdl
);
509 m3x3_scalef( mmdl
, scale
);
510 v3_copy( objective
->transform
.co
, mmdl
[3] );
511 shader_scene_fxglow_uMdl( mmdl
);
513 for( u32 j
=0; j
<objective
->submesh_count
; j
++ ){
514 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
515 objective
->submesh_start
+ j
);
517 if( sm
->material_id
!= last_material
){
518 last_material
= sm
->material_id
;
519 pass
->fn_bind_textures( world
, &world
->surfaces
[sm
->material_id
] );
521 mdl_draw_submesh( sm
);
526 font3d_bind( &gui
.font
, k_font_shader_world
, 0, world
, &skaterift
.cam
);
531 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
532 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, i
);
533 if( challenge
->status
) count
++;
537 c
+=highscore_intl( buf
+c
, count
, 3 );
539 c
+=highscore_intl( buf
+c
, mdl_arrcount(&world
->ent_challenge
), 3 );
542 f32 w
= font3d_string_width( 1, buf
);
544 m3x3_identity( mlocal
);
545 mlocal
[3][0] = -w
*0.5f
;
549 for( u32 i
=0; i
<challenge_count
; i
++ ){
550 u32 index
= challenge_list
[ i
];
551 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
553 mdl_transform_m4x3( &challenge
->transform
, mmdl
);
554 m4x3_mul( mmdl
, mlocal
, mmdl
);
556 vg_line_point( challenge
->transform
.co
, 0.25f
, VG__RED
);
558 f32 dist
= v3_dist( challenge
->transform
.co
, pos
) * (1.0f
/radius
),
559 scale
= vg_smoothstepf( vg_clampf( 10.0f
-dist
*10.0f
, 0.0f
,1.0f
) ),
562 if( challenge
->status
)
565 shader_scene_font_uOpacity( scale
);
566 shader_scene_font_uColourize( colour
);
567 font3d_simple_draw( 1, buf
, &skaterift
.cam
, mmdl
);
571 static void render_world_fxglow( world_instance
*world
, camera
*cam
,
573 shader_scene_fxglow_use();
574 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
575 shader_scene_fxglow_uTexMain(1);
576 shader_scene_fxglow_uPv( cam
->mtx
.pv
);
578 world_link_lighting_ub( world
, _shader_scene_fxglow
.id
);
579 world_bind_position_texture( world
, _shader_scene_fxglow
.id
,
580 _uniform_scene_fxglow_g_world_depth
, 2 );
581 world_bind_light_array( world
, _shader_scene_fxglow
.id
,
582 _uniform_scene_fxglow_uLightsArray
, 3 );
583 world_bind_light_index( world
, _shader_scene_fxglow
.id
,
584 _uniform_scene_fxglow_uLightsIndex
, 4 );
586 shader_scene_fxglow_uCamera( cam
->transform
[3] );
587 glDisable(GL_CULL_FACE
);
589 struct world_pass pass
= {
590 .shader
= k_shader_fxglow
,
592 .fn_bind_textures
= bindpoint_diffuse_texture1
,
593 .fn_set_mdl
= shader_scene_fxglow_uMdl
,
594 .fn_set_uPvmPrev
= shader_scene_fxglow_uPvmPrev
,
597 world_render_both_stages( world
, &pass
);
598 world_render_challenges( world
, &pass
, cam
->pos
, layer_depth
);
600 glEnable(GL_CULL_FACE
);
603 static void bindpoint_terrain( world_instance
*world
,
604 struct world_surface
*mat
)
606 glActiveTexture( GL_TEXTURE1
);
607 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
609 shader_scene_terrain_uSandColour( mat
->info
.colour
);
610 shader_scene_terrain_uBlendOffset( mat
->info
.colour1
);
613 static void bindpoint_override( world_instance
*world
,
614 struct world_surface
*mat
){
615 if( mat
->info
.flags
& k_material_flag_collision
){
616 shader_scene_override_uAlphatest(0);
619 glActiveTexture( GL_TEXTURE1
);
620 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
621 shader_scene_override_uAlphatest(1);
625 static void render_terrain( world_instance
*world
, camera
*cam
){
626 shader_scene_terrain_use();
627 shader_scene_terrain_uTexGarbage(0);
628 shader_scene_terrain_uTexGradients(1);
630 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world
, scene_terrain
);
631 glActiveTexture( GL_TEXTURE0
);
632 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
634 shader_scene_terrain_uPv( cam
->mtx
.pv
);
635 shader_scene_terrain_uCamera( cam
->transform
[3] );
637 struct world_pass pass
= {
638 .shader
= k_shader_terrain_blend
,
640 .fn_bind_textures
= bindpoint_terrain
,
641 .fn_set_mdl
= shader_scene_terrain_uMdl
,
642 .fn_set_uPvmPrev
= shader_scene_terrain_uPvmPrev
,
645 world_render_both_stages( world
, &pass
);
648 static void render_sky( world_instance
*world
, camera
*cam
){
650 * Modify matrix to remove clipping and view translation
657 m4x4_copy( cam
->mtx
.v
, v
);
658 m4x4_copy( cam
->mtx_prev
.v
, v_prev
);
660 v3_zero( v_prev
[3] );
662 m4x4_copy( cam
->mtx
.p
, pv
);
663 m4x4_copy( cam
->mtx_prev
.p
, pv_prev
);
664 m4x4_reset_clipping( pv
, cam
->farz
, cam
->nearz
);
665 m4x4_reset_clipping( pv_prev
, cam
->farz
, cam
->nearz
);
667 m4x4_mul( pv
, v
, pv
);
668 m4x4_mul( pv_prev
, v_prev
, pv_prev
);
670 m4x3f identity_matrix
;
671 m4x3_identity( identity_matrix
);
676 if( world
->skybox
== k_skybox_default
){
677 shader_model_sky_use();
678 shader_model_sky_uMdl( identity_matrix
);
679 shader_model_sky_uPv( pv
);
680 shader_model_sky_uPvmPrev( pv_prev
);
681 shader_model_sky_uTexGarbage(0);
682 world_link_lighting_ub( world
, _shader_model_sky
.id
);
684 glActiveTexture( GL_TEXTURE0
);
685 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
687 else if( world
->skybox
== k_skybox_space
){
688 shader_model_sky_space_use();
690 shader_model_sky_space_uMdl( identity_matrix
);
691 shader_model_sky_space_uPv( pv
);
692 shader_model_sky_space_uPvmPrev( pv_prev
);
693 shader_model_sky_space_uTexGarbage(0);
694 world_link_lighting_ub( world
, _shader_model_sky_space
.id
);
696 glActiveTexture( GL_TEXTURE0
);
697 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
703 glDepthMask( GL_FALSE
);
704 glDisable( GL_DEPTH_TEST
);
706 mesh_bind( &world_render
.skydome
);
707 mesh_draw( &world_render
.skydome
);
709 glEnable( GL_DEPTH_TEST
);
710 glDepthMask( GL_TRUE
);
713 static void render_world_gates( world_instance
*world
, camera
*cam
,
716 float closest
= INFINITY
;
717 struct ent_gate
*gate
= NULL
;
719 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_gate
); i
++ ){
720 ent_gate
*gi
= mdl_arritm( &world
->ent_gate
, i
);
722 if( !(gi
->flags
& (k_ent_gate_linked
|k_ent_gate_nonlocal_DELETED
|
723 k_ent_gate_locked
)) )
726 float dist
= v3_dist2( gi
->co
[0], cam
->transform
[3] );
728 vg_line_point( gi
->co
[0], 0.25f
, VG__BLUE
);
730 if( dist
< closest
){
736 world
->rendering_gate
= gate
;
738 render_gate( world
, world
, gate
, cam
, layer_depth
);
741 static void world_prerender( world_instance
*world
){
742 if( mdl_arrcount( &world
->ent_light
) ){
743 f32 rate
= vg_maxf(0.1f
, fabsf(k_day_length
)) * vg_signf(k_day_length
);
744 world
->time
+= vg
.time_frame_delta
* (1.0/(rate
*60.0));
750 struct ub_world_lighting
*state
= &world
->ub_lighting
;
752 state
->g_time
= world
->time
;
753 state
->g_realtime
= vg
.time_real
;
754 state
->g_debug_indices
= k_debug_light_indices
;
755 state
->g_light_preview
= k_light_preview
;
756 state
->g_debug_complexity
= k_debug_light_complexity
;
758 if( skaterift
.activity
== k_skaterift_respawning
)
759 state
->g_time_of_day
= 0.1f
;
761 state
->g_time_of_day
= vg_fractf( world
->time
);
763 state
->g_day_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 2.0f
);
764 state
->g_sunset_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 4.0f
+ VG_PIf
);
766 state
->g_day_phase
= state
->g_day_phase
* 0.5f
+ 0.5f
;
767 state
->g_sunset_phase
= powf( state
->g_sunset_phase
* 0.5f
+ 0.5f
, 6.0f
);
769 float a
= state
->g_time_of_day
* VG_PIf
* 2.0f
;
770 state
->g_sun_dir
[0] = sinf( a
);
771 state
->g_sun_dir
[1] = cosf( a
);
772 state
->g_sun_dir
[2] = 0.2f
;
773 v3_normalize( state
->g_sun_dir
);
775 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
776 float dp
= state
->g_day_phase
;
778 world
->probabilities
[ k_probability_curve_wildlife_day
] =
779 (dp
*dp
*0.8f
+state
->g_sunset_phase
)*0.8f
;
780 world
->probabilities
[ k_probability_curve_wildlife_night
] =
781 1.0f
-powf(fabsf((state
->g_time_of_day
-0.5f
)*5.0f
),5.0f
);
783 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
784 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
785 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
788 static void render_world( world_instance
*world
, camera
*cam
,
791 render_sky( world
, cam
);
793 render_world_routes( world
, cam
, layer_depth
);
794 render_world_standard( world
, cam
);
795 render_world_cubemapped( world
, cam
, layer_depth
);
797 render_world_vb( world
, cam
);
798 render_world_alphatest( world
, cam
);
799 render_terrain( world
, cam
);
801 if( layer_depth
== -1 ) return;
802 if( layer_depth
== 0 ){
803 world_entity_focus_render();
807 float min_dist
= INFINITY
;
809 if( mdl_arrcount( &world
->ent_route
) ){
810 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_route
); i
++ ){
811 ent_route
*route
= mdl_arritm( &world
->ent_route
, i
);
812 float dist
= v3_dist2( route
->board_transform
[3], cam
->pos
);
814 if( dist
< min_dist
){
820 ent_route
*route
= mdl_arritm( &world
->ent_route
, closest
);
821 sfd_render( world
, cam
, route
->board_transform
);
826 if( mdl_entity_id_type(world_static
.focused_entity
) == k_ent_challenge
)
827 greyout
= world_static
.focus_strength
;
829 if( greyout
> 0.0f
){
830 glDrawBuffers( 1, (GLenum
[]){ GL_COLOR_ATTACHMENT0
} );
832 glDisable(GL_DEPTH_TEST
);
833 glDepthMask(GL_FALSE
);
834 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
835 glBlendEquation(GL_FUNC_ADD
);
837 shader_blitcolour_use();
838 shader_blitcolour_uColour( (v4f
){ 0.5f
, 0.5f
, 0.5f
, greyout
*0.56f
} );
842 glEnable(GL_DEPTH_TEST
);
843 glDepthMask(GL_TRUE
);
844 glDrawBuffers( 2, (GLenum
[]){ GL_COLOR_ATTACHMENT0
,
845 GL_COLOR_ATTACHMENT1
} );
848 render_world_fxglow( world
, cam
, layer_depth
);
852 static void render_world_override_pass( world_instance
*world
,
853 struct world_pass
*pass
,
854 m4x3f mmdl
, m3x3f mnormal
,
856 for( int i
=0; i
<world
->surface_count
; i
++ ){
857 struct world_surface
*mat
= &world
->surfaces
[i
];
859 if( mat
->info
.flags
& k_material_flag_ghosts
) continue;
862 if( pass
->geo_type
== k_world_geo_type_solid
)
865 sm
= &mat
->sm_no_collide
;
867 if( !sm
->indice_count
)
870 pass
->fn_set_mdl( mmdl
);
871 pass
->fn_set_uNormalMtx( mnormal
);
872 pass
->fn_set_uPvmPrev( mpvm_prev
);
873 pass
->fn_bind_textures( world
, mat
);
874 mdl_draw_submesh( sm
);
878 static void render_world_override( world_instance
*world
,
879 world_instance
*lighting_source
,
881 struct world_pass pass
= {
882 .cam
= &skaterift
.cam
,
883 .fn_bind_textures
= bindpoint_override
,
884 .fn_set_mdl
= shader_scene_override_uMdl
,
885 .fn_set_uPvmPrev
= shader_scene_override_uPvmPrev
,
886 .fn_set_uNormalMtx
= shader_scene_override_uNormalMtx
,
887 .shader
= k_shader_override
890 shader_scene_override_use();
892 respawn_chooser_shader_uniforms();
894 shader_scene_override_uTexGarbage(0);
895 shader_scene_override_uTexMain(1);
896 shader_scene_override_uPv( pass
.cam
->mtx
.pv
);
898 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( lighting_source
, scene_override
);
899 bind_terrain_noise();
901 shader_scene_override_uCamera( pass
.cam
->transform
[3] );
904 m4x3_expand( mmdl
, mpvm_prev
);
905 m4x4_mul( skaterift
.cam
.mtx_prev
.pv
, mpvm_prev
, mpvm_prev
);
908 m3x3_inv( mmdl
, mnormal
);
909 m3x3_transpose( mnormal
, mnormal
);
910 v3_normalize( mnormal
[0] );
911 v3_normalize( mnormal
[1] );
912 v3_normalize( mnormal
[2] );
914 v4f uPlayerPos
, uSpawnPos
;
915 v4_zero( uPlayerPos
);
916 v4_zero( uSpawnPos
);
918 v3_copy( world
->player_co
, uPlayerPos
);
921 m4x3_invert_full( mmdl
, mmdl_inv
);
923 m4x3_mulv( mmdl_inv
, localplayer
.rb
.co
, localized
);
924 ent_spawn
*spawn
= world_find_closest_spawn( world
, localized
);
926 v3_copy( spawn
->transform
.co
, uSpawnPos
);
928 uPlayerPos
[3] = v3_dist(uPlayerPos
,uSpawnPos
);
929 uSpawnPos
[3] = 1.0f
/uPlayerPos
[3];
931 shader_scene_override_uPlayerPos( uPlayerPos
);
932 shader_scene_override_uSpawnPos( uSpawnPos
);
936 glDisable( GL_CULL_FACE
);
937 mesh_bind( &world
->mesh_geo
);
938 pass
.geo_type
= k_world_geo_type_solid
;
939 render_world_override_pass( world
, &pass
, mmdl
, mnormal
, mpvm_prev
);
940 mesh_bind( &world
->mesh_no_collide
);
941 pass
.geo_type
= k_world_geo_type_nonsolid
;
942 render_world_override_pass( world
, &pass
, mmdl
, mnormal
, mpvm_prev
);
943 glEnable( GL_CULL_FACE
);
946 static void render_cubemap_side( world_instance
*world
, ent_cubemap
*cm
,
949 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
950 GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ side
, cm
->texture_id
, 0 );
951 glClear( GL_DEPTH_BUFFER_BIT
);
954 { -1.0f
, 0.0f
, 0.0f
},
955 { 1.0f
, 0.0f
, 0.0f
},
956 { 0.0f
, -1.0f
, 0.0f
},
957 { 0.0f
, 1.0f
, 0.0f
},
958 { 0.0f
, 0.0f
, -1.0f
},
962 { 0.0f
, -1.0f
, 0.0f
},
963 { 0.0f
, -1.0f
, 0.0f
},
964 { 0.0f
, 0.0f
, 1.0f
},
965 { 0.0f
, 0.0f
, -1.0f
},
966 { 0.0f
, -1.0f
, 0.0f
},
967 { 0.0f
, -1.0f
, 0.0f
}
970 v3_zero( cam
.angles
);
971 v3_copy( cm
->co
, cam
.pos
);
973 v3_copy( forward
[side
], cam
.transform
[2] );
974 v3_copy( up
[side
], cam
.transform
[1] );
975 v3_cross( up
[side
], forward
[side
], cam
.transform
[0] );
976 v3_copy( cm
->co
, cam
.transform
[3] );
977 m4x3_invert_affine( cam
.transform
, cam
.transform_inverse
);
979 camera_update_view( &cam
);
984 m4x4_copy( cam
.mtx
.p
, cam
.mtx_prev
.p
);
985 m4x4_projection( cam
.mtx
.p
, cam
.fov
, 1.0f
, cam
.nearz
, cam
.farz
);
986 camera_finalize( &cam
);
987 camera_finalize( &cam
);
989 render_world( world
, &cam
, -1 );
992 static void render_world_cubemaps( world_instance
*world
){
993 if( world
->cubemap_cooldown
)
994 world
->cubemap_cooldown
--;
996 world
->cubemap_cooldown
= 60;
998 glViewport( 0, 0, WORLD_CUBEMAP_RES
, WORLD_CUBEMAP_RES
);
999 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_cubemap
); i
++ ){
1000 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, i
);
1001 glBindFramebuffer( GL_FRAMEBUFFER
, cm
->framebuffer_id
);
1003 world
->cubemap_side
++;
1004 if( world
->cubemap_side
>= 6 )
1005 world
->cubemap_side
= 0;
1007 render_cubemap_side( world
, cm
, world
->cubemap_side
);
1012 static void render_world_depth( world_instance
*world
, camera
*cam
){
1013 m4x3f identity_matrix
;
1014 m4x3_identity( identity_matrix
);
1016 shader_scene_depth_use();
1017 shader_scene_depth_uCamera( cam
->transform
[3] );
1018 shader_scene_depth_uPv( cam
->mtx
.pv
);
1019 shader_scene_depth_uPvmPrev( cam
->mtx_prev
.pv
);
1020 shader_scene_depth_uMdl( identity_matrix
);
1021 world_link_lighting_ub( world
, _shader_scene_depth
.id
);
1023 mesh_bind( &world
->mesh_geo
);
1024 mesh_draw( &world
->mesh_geo
);
1027 static void render_world_position( world_instance
*world
, camera
*cam
){
1028 m4x3f identity_matrix
;
1029 m4x3_identity( identity_matrix
);
1031 shader_scene_position_use();
1032 shader_scene_position_uCamera( cam
->transform
[3] );
1033 shader_scene_position_uPv( cam
->mtx
.pv
);
1034 shader_scene_position_uPvmPrev( cam
->mtx_prev
.pv
);
1035 shader_scene_position_uMdl( identity_matrix
);
1036 world_link_lighting_ub( world
, _shader_scene_position
.id
);
1038 mesh_bind( &world
->mesh_geo
);
1039 mesh_draw( &world
->mesh_geo
);