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
[] ){
16 world_instance
*world
= world_current_instance();
17 world
->time
= atof( argv
[0] );
20 vg_error( "Usage set_time <0-1.0>\n" );
25 VG_STATIC
void async_world_render_init( void *payload
, u32 size
)
27 vg_info( "Allocate uniform buffers\n" );
28 for( int i
=0; i
<4; i
++ ){
29 world_instance
*world
= &world_static
.instances
[i
];
30 world
->ubo_bind_point
= i
;
32 glGenBuffers( 1, &world
->ubo_lighting
);
33 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
34 glBufferData( GL_UNIFORM_BUFFER
, sizeof(struct ub_world_lighting
),
35 NULL
, GL_DYNAMIC_DRAW
);
37 glBindBufferBase( GL_UNIFORM_BUFFER
, i
, world
->ubo_lighting
);
41 vg_info( "Allocate frame buffers\n" );
42 for( int i
=0; i
<4; i
++ ){
43 world_instance
*world
= &world_static
.instances
[i
];
44 struct framebuffer
*fb
= &world
->heightmap
;
46 fb
->display_name
= NULL
;
50 fb
->resolution_div
= 0;
52 fb
->attachments
[0].display_name
= NULL
;
53 fb
->attachments
[0].purpose
= k_framebuffer_attachment_type_texture
;
54 fb
->attachments
[0].internalformat
= GL_RG16F
;
55 fb
->attachments
[0].format
= GL_RG
;
56 fb
->attachments
[0].type
= GL_FLOAT
;
57 fb
->attachments
[0].attachment
= GL_COLOR_ATTACHMENT0
;
59 fb
->attachments
[1].purpose
= k_framebuffer_attachment_type_none
;
60 fb
->attachments
[2].purpose
= k_framebuffer_attachment_type_none
;
61 fb
->attachments
[3].purpose
= k_framebuffer_attachment_type_none
;
62 fb
->attachments
[4].purpose
= k_framebuffer_attachment_type_none
;
64 render_fb_allocate( fb
);
68 VG_STATIC
void world_render_init(void)
70 VG_VAR_F32( k_day_length
);
71 VG_VAR_I32( k_debug_light_indices
);
72 VG_VAR_I32( k_debug_light_complexity
);
73 VG_VAR_I32( k_light_preview
);
74 vg_console_reg_cmd( "set_time", ccmd_set_time
, NULL
);
76 world_render
.sky_rate
= 1.0;
77 world_render
.sky_target_rate
= 1.0;
79 shader_scene_standard_register();
80 shader_scene_standard_alphatest_register();
81 shader_scene_override_register();
82 shader_scene_cubemapped_register();
83 shader_scene_fxglow_register();
84 shader_scene_vertex_blend_register();
85 shader_scene_terrain_register();
86 shader_scene_depth_register();
87 shader_scene_position_register();
88 shader_model_sky_register();
90 vg_info( "Loading world resources\n" );
91 vg_linear_clear( vg_mem
.scratch
);
94 mdl_open( &msky
, "models/rs_skydome.mdl", vg_mem
.scratch
);
95 mdl_load_metadata_block( &msky
, vg_mem
.scratch
);
96 mdl_async_load_glmesh( &msky
, &world_render
.skydome
);
99 vg_info( "Loading default world textures\n" );
100 vg_tex2d_load_qoi_async_file( "textures/garbage.qoi",
101 VG_TEX2D_NEAREST
|VG_TEX2D_REPEAT
,
102 &world_render
.tex_terrain_noise
);
104 vg_async_call( async_world_render_init
, NULL
, 0 );
107 VG_STATIC
void world_link_lighting_ub( world_instance
*world
, GLuint shader
)
109 GLuint idx
= glGetUniformBlockIndex( shader
, "ub_world_lighting" );
110 glUniformBlockBinding( shader
, idx
, world
->ubo_bind_point
);
113 VG_STATIC
void world_bind_position_texture( world_instance
*world
,
114 GLuint shader
, GLuint location
,
117 render_fb_bind_texture( &world
->heightmap
, 0, slot
);
118 glUniform1i( location
, slot
);
121 VG_STATIC
void world_bind_light_array( world_instance
*world
,
122 GLuint shader
, GLuint location
,
125 glActiveTexture( GL_TEXTURE0
+ slot
);
126 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
127 glUniform1i( location
, slot
);
130 VG_STATIC
void world_bind_light_index( world_instance
*world
,
131 GLuint shader
, GLuint location
,
134 glActiveTexture( GL_TEXTURE0
+ slot
);
135 glBindTexture( GL_TEXTURE_3D
, world
->tex_light_cubes
);
136 glUniform1i( location
, slot
);
139 VG_STATIC
void render_world_depth( world_instance
*world
, camera
*cam
);
145 VG_STATIC
void bind_terrain_noise(void)
147 glActiveTexture( GL_TEXTURE0
);
148 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
153 enum mdl_shader shader
;
154 enum world_geo_type geo_type
;
156 void (*fn_bind_textures
)( world_instance
*world
,
157 struct world_surface
*mat
);
158 void (*fn_set_mdl
)( m4x3f mdl
);
159 void (*fn_set_uPvmPrev
)( m4x4f pvm
);
163 void world_render_traffic( world_instance
*world
, u32 material_id
,
164 struct world_pass
*pass
){
165 if( !mdl_arrcount( &world
->ent_traffic
) ) return;
167 /* HACK: use the first material for every traffic entity */
168 ent_traffic
*first
= mdl_arritm( &world
->ent_traffic
, 0 );
169 if( !first
->submesh_count
) return;
171 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
, first
->submesh_start
);
172 if( sm
->material_id
!= material_id
) return;
174 struct world_surface
*mat
= &world
->surfaces
[ material_id
];
175 pass
->fn_bind_textures( world
, mat
);
177 for( u32 j
=0; j
<mdl_arrcount( &world
->ent_traffic
); j
++ ){
178 ent_traffic
*traffic
= mdl_arritm( &world
->ent_traffic
, j
);
180 for( u32 k
=0; k
<traffic
->submesh_count
; k
++ ){
181 sm
= mdl_arritm( &world
->meta
.submeshs
,
182 traffic
->submesh_start
+k
);
185 q_m3x3( traffic
->transform
.q
, mmdl
);
186 v3_copy( traffic
->transform
.co
, mmdl
[3] );
189 m4x3_expand( mmdl
, m4mdl
);
190 m4x4_mul( pass
->cam
->mtx_prev
.pv
, m4mdl
, m4mdl
);
192 pass
->fn_set_mdl( mmdl
);
193 pass
->fn_set_uPvmPrev( m4mdl
);
195 mdl_draw_submesh( sm
);
201 void world_render_pass( world_instance
*world
, struct world_pass
*pass
){
202 for( int i
=0; i
<world
->surface_count
; i
++ ){
203 struct world_surface
*mat
= &world
->surfaces
[i
];
205 if( mat
->info
.shader
== pass
->shader
){
208 if( pass
->geo_type
== k_world_geo_type_solid
){
212 world_render_traffic( world
, i
, pass
);
213 sm
= &mat
->sm_no_collide
;
216 if( !sm
->indice_count
)
220 m4x3_identity( mmdl
);
221 pass
->fn_set_mdl( mmdl
);
222 pass
->fn_set_uPvmPrev( pass
->cam
->mtx_prev
.pv
);
224 pass
->fn_bind_textures( world
, mat
);
225 mdl_draw_submesh( sm
);
231 void world_render_both_stages( world_instance
*world
, struct world_pass
*pass
)
233 mesh_bind( &world
->mesh_geo
);
234 pass
->geo_type
= k_world_geo_type_solid
;
235 world_render_pass( world
, pass
);
237 glDisable( GL_CULL_FACE
);
238 mesh_bind( &world
->mesh_no_collide
);
239 pass
->geo_type
= k_world_geo_type_nonsolid
;
240 world_render_pass( world
, pass
);
241 glEnable( GL_CULL_FACE
);
244 VG_STATIC
void bindpoint_diffuse_texture1( world_instance
*world
,
245 struct world_surface
*mat
)
248 glActiveTexture( GL_TEXTURE1
);
249 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
252 VG_STATIC
void bindpoint_diffuse1_and_cubemap10( world_instance
*world
,
253 struct world_surface
*mat
){
254 glActiveTexture( GL_TEXTURE1
);
255 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
257 u32 cubemap_id
= mat
->info
.tex_none0
,
260 if( mdl_entity_id_type( cubemap_id
) == k_ent_cubemap
){
261 cubemap_index
= mdl_entity_id_id( cubemap_id
);
264 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, cubemap_index
);
265 glActiveTexture( GL_TEXTURE10
);
266 glBindTexture( GL_TEXTURE_CUBE_MAP
, cm
->texture_id
);
268 shader_scene_cubemapped_uColour( mat
->info
.colour
);
271 VG_STATIC
void render_world_vb( world_instance
*world
, camera
*cam
)
273 shader_scene_vertex_blend_use();
274 shader_scene_vertex_blend_uTexGarbage(0);
275 shader_scene_vertex_blend_uTexGradients(1);
276 world_link_lighting_ub( world
, _shader_scene_vertex_blend
.id
);
277 world_bind_position_texture( world
, _shader_scene_vertex_blend
.id
,
278 _uniform_scene_vertex_blend_g_world_depth
, 2 );
279 world_bind_light_array( world
, _shader_scene_vertex_blend
.id
,
280 _uniform_scene_vertex_blend_uLightsArray
, 3 );
281 world_bind_light_index( world
, _shader_scene_vertex_blend
.id
,
282 _uniform_scene_vertex_blend_uLightsIndex
, 4 );
284 glActiveTexture( GL_TEXTURE0
);
285 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
287 shader_scene_vertex_blend_uPv( cam
->mtx
.pv
);
288 shader_scene_vertex_blend_uCamera( cam
->transform
[3] );
290 struct world_pass pass
= {
291 .shader
= k_shader_standard_vertex_blend
,
293 .fn_bind_textures
= bindpoint_diffuse_texture1
,
294 .fn_set_mdl
= shader_scene_vertex_blend_uMdl
,
295 .fn_set_uPvmPrev
= shader_scene_vertex_blend_uPvmPrev
,
298 world_render_both_stages( world
, &pass
);
301 VG_STATIC
void world_shader_standard_bind( world_instance
*world
, camera
*cam
){
302 shader_scene_standard_use();
303 shader_scene_standard_uTexGarbage(0);
304 shader_scene_standard_uTexMain(1);
305 shader_scene_standard_uPv( cam
->mtx
.pv
);
307 world_link_lighting_ub( world
, _shader_scene_standard
.id
);
308 world_bind_position_texture( world
, _shader_scene_standard
.id
,
309 _uniform_scene_standard_g_world_depth
, 2 );
310 world_bind_light_array( world
, _shader_scene_standard
.id
,
311 _uniform_scene_standard_uLightsArray
, 3 );
312 world_bind_light_index( world
, _shader_scene_standard
.id
,
313 _uniform_scene_standard_uLightsIndex
, 4 );
315 bind_terrain_noise();
316 shader_scene_standard_uCamera( cam
->transform
[3] );
319 VG_STATIC
void render_world_standard( world_instance
*world
, camera
*cam
){
320 world_shader_standard_bind( world
, cam
);
321 struct world_pass pass
= {
322 .shader
= k_shader_standard
,
324 .fn_bind_textures
= bindpoint_diffuse_texture1
,
325 .fn_set_mdl
= shader_scene_standard_uMdl
,
326 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
329 world_render_both_stages( world
, &pass
);
332 VG_STATIC
void render_world_cubemapped( world_instance
*world
, camera
*cam
,
334 if( !mdl_arrcount( &world
->ent_cubemap
) )
337 if( layer_depth
== -1 ){
338 world_shader_standard_bind( world
, cam
);
340 struct world_pass pass
= {
341 .shader
= k_shader_cubemap
,
343 .fn_bind_textures
= bindpoint_diffuse_texture1
,
344 .fn_set_mdl
= shader_scene_standard_uMdl
,
345 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
348 world_render_both_stages( world
, &pass
);
351 shader_scene_cubemapped_use();
352 shader_scene_cubemapped_uTexGarbage(0);
353 shader_scene_cubemapped_uTexMain(1);
354 shader_scene_cubemapped_uTexCubemap(10);
355 shader_scene_cubemapped_uPv( cam
->mtx
.pv
);
357 world_link_lighting_ub( world
, _shader_scene_cubemapped
.id
);
358 world_bind_position_texture( world
, _shader_scene_cubemapped
.id
,
359 _uniform_scene_cubemapped_g_world_depth
, 2 );
360 world_bind_light_array( world
, _shader_scene_cubemapped
.id
,
361 _uniform_scene_cubemapped_uLightsArray
, 3 );
362 world_bind_light_index( world
, _shader_scene_cubemapped
.id
,
363 _uniform_scene_cubemapped_uLightsIndex
, 4 );
365 bind_terrain_noise();
366 shader_scene_cubemapped_uCamera( cam
->transform
[3] );
368 struct world_pass pass
= {
369 .shader
= k_shader_cubemap
,
371 .fn_bind_textures
= bindpoint_diffuse1_and_cubemap10
,
372 .fn_set_mdl
= shader_scene_cubemapped_uMdl
,
373 .fn_set_uPvmPrev
= shader_scene_cubemapped_uPvmPrev
,
376 world_render_both_stages( world
, &pass
);
380 VG_STATIC
void render_world_alphatest( world_instance
*world
, camera
*cam
){
381 shader_scene_standard_alphatest_use();
382 shader_scene_standard_alphatest_uTexGarbage(0);
383 shader_scene_standard_alphatest_uTexMain(1);
384 shader_scene_standard_alphatest_uPv( cam
->mtx
.pv
);
386 world_link_lighting_ub( world
, _shader_scene_standard_alphatest
.id
);
387 world_bind_position_texture( world
, _shader_scene_standard_alphatest
.id
,
388 _uniform_scene_standard_alphatest_g_world_depth
, 2 );
389 world_bind_light_array( world
, _shader_scene_standard_alphatest
.id
,
390 _uniform_scene_standard_alphatest_uLightsArray
, 3 );
391 world_bind_light_index( world
, _shader_scene_standard_alphatest
.id
,
392 _uniform_scene_standard_alphatest_uLightsIndex
, 4 );
395 bind_terrain_noise();
398 shader_scene_standard_alphatest_uCamera( cam
->transform
[3] );
400 glDisable(GL_CULL_FACE
);
402 struct world_pass pass
= {
403 .shader
= k_shader_standard_cutout
,
405 .fn_bind_textures
= bindpoint_diffuse_texture1
,
406 .fn_set_mdl
= shader_scene_standard_alphatest_uMdl
,
407 .fn_set_uPvmPrev
= shader_scene_standard_alphatest_uPvmPrev
,
410 world_render_both_stages( world
, &pass
);
412 glEnable(GL_CULL_FACE
);
416 void world_render_challenges( world_instance
*world
, struct world_pass
*pass
,
417 v3f pos
, int layer_depth
){
419 if( skaterift
.activity
== k_skaterift_replay
) return;
424 u32 objective_list
[ 32 ],
425 challenge_list
[ 16 ];
427 v2f objective_uv_offsets
[ 32 ];
429 u32 objective_count
= 0,
432 ent_challenge
*active_challenge
= NULL
;
434 if( mdl_entity_id_type( world_static
.focused_entity
) == k_ent_challenge
){
435 if( (skaterift
.activity
== k_skaterift_default
) &&
436 world_static
.challenge_target
){
440 if( !((skaterift
.activity
!= k_skaterift_ent_focus
) &&
441 !world_static
.challenge_target
) ){
442 world_instance
*challenge_world
= world_current_instance();
443 u32 index
= mdl_entity_id_id( world_static
.focused_entity
);
444 active_challenge
= mdl_arritm(&challenge_world
->ent_challenge
, index
);
448 if( active_challenge
){
449 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
450 challenge_list
[ challenge_count
++ ] = world_static
.focused_entity
;
452 u32 next
= active_challenge
->first
;
453 while( mdl_entity_id_type(next
) == k_ent_objective
){
454 u32 index
= mdl_entity_id_id( next
);
455 objective_list
[ objective_count
++ ] = index
;
457 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
458 next
= objective
->id_next
;
464 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
466 bh_iter_init_range( 0, &it
, pos
, radius
+10.0f
);
468 while( bh_next( world
->entity_bh
, &it
, &idx
) ){
469 u32 id
= world
->entity_list
[ idx
],
470 type
= mdl_entity_id_type( id
),
471 index
= mdl_entity_id_id( id
);
473 if( type
== k_ent_objective
) {
474 if( objective_count
< vg_list_size(objective_list
) )
475 objective_list
[ objective_count
++ ] = index
;
477 else if( type
== k_ent_challenge
){
478 if( challenge_count
< vg_list_size(challenge_list
) )
479 challenge_list
[ challenge_count
++ ] = index
;
484 /* render objectives */
485 glDisable( GL_CULL_FACE
);
486 mesh_bind( &world
->mesh_no_collide
);
487 u32 last_material
= 0;
488 for( u32 i
=0; i
<objective_count
; i
++ ){
489 u32 index
= objective_list
[ i
];
490 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
491 if( (objective
->flags
& k_ent_objective_hidden
) &&
492 !active_challenge
) continue;
497 u32 passed
= objective
->flags
& k_ent_objective_passed
;
498 f32 target
= passed
? 0.0f
: 1.0f
;
499 vg_slewf(&objective
->transform
.s
[0], target
, vg
.time_frame_delta
*4.0f
);
500 scale
= vg_smoothstepf( objective
->transform
.s
[0] );
502 if( (objective
== world_static
.challenge_target
) || passed
)
503 shader_scene_fxglow_uUvOffset( (v2f
){ 16.0f
/256.0f
, 0.0f
} );
505 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
508 f32 dist
= v3_dist( objective
->transform
.co
, pos
) * (1.0f
/radius
);
509 scale
= vg_smoothstepf( vg_clampf( 5.0f
-dist
*5.0f
, 0.0f
,1.0f
) );
513 q_m3x3( objective
->transform
.q
, mmdl
);
514 m3x3_scalef( mmdl
, scale
);
515 v3_copy( objective
->transform
.co
, mmdl
[3] );
516 shader_scene_fxglow_uMdl( mmdl
);
518 for( u32 j
=0; j
<objective
->submesh_count
; j
++ ){
519 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
520 objective
->submesh_start
+ j
);
522 if( sm
->material_id
!= last_material
){
523 last_material
= sm
->material_id
;
524 pass
->fn_bind_textures( world
, &world
->surfaces
[sm
->material_id
] );
526 mdl_draw_submesh( sm
);
531 shader_scene_font_use();
532 shader_scene_font_uTexGarbage(0);
533 shader_scene_font_uTexMain(1);
535 shader_scene_font_uPv( skaterift
.cam
.mtx
.pv
);
536 shader_scene_font_uTime( vg
.time
);
538 /* TODO: Code dupe... */
539 world_link_lighting_ub( world
, _shader_scene_font
.id
);
540 world_bind_position_texture( world
, _shader_scene_font
.id
,
541 _uniform_scene_font_g_world_depth
, 2 );
542 world_bind_light_array( world
, _shader_scene_font
.id
,
543 _uniform_scene_font_uLightsArray
, 3 );
544 world_bind_light_index( world
, _shader_scene_font
.id
,
545 _uniform_scene_font_uLightsIndex
, 4 );
547 bind_terrain_noise();
548 shader_scene_font_uCamera( skaterift
.cam
.transform
[3] );
550 //shader_scene_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
551 glActiveTexture( GL_TEXTURE1
);
552 glBindTexture( GL_TEXTURE_2D
, gui
.font
.texture
);
554 mesh_bind( &gui
.font
.mesh
);
559 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
560 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, i
);
561 if( challenge
->status
) count
++;
565 c
+=highscore_intl( buf
+c
, count
, 3 );
567 c
+=highscore_intl( buf
+c
, mdl_arrcount(&world
->ent_challenge
), 3 );
570 f32 w
= font3d_string_width( &gui
.font
, 1, buf
);
572 m3x3_identity( mlocal
);
573 mlocal
[3][0] = -w
*0.5f
;
577 for( u32 i
=0; i
<challenge_count
; i
++ ){
578 u32 index
= challenge_list
[ i
];
579 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
581 mdl_transform_m4x3( &challenge
->transform
, mmdl
);
582 m4x3_mul( mmdl
, mlocal
, mmdl
);
584 vg_line_point( challenge
->transform
.co
, 0.25f
, VG__RED
);
586 f32 dist
= v3_dist( challenge
->transform
.co
, pos
) * (1.0f
/radius
),
587 scale
= vg_smoothstepf( vg_clampf( 10.0f
-dist
*10.0f
, 0.0f
,1.0f
) ),
590 if( challenge
->status
)
593 shader_scene_font_uOpacity( scale
);
594 shader_scene_font_uColourize( colour
);
596 struct font3d_render render
= {
599 .shader
= k_font_shader_world
602 font3d_begin( buf
, &skaterift
.cam
, mmdl
, &render
);
603 font3d_draw( &render
);
607 VG_STATIC
void render_world_fxglow( world_instance
*world
, camera
*cam
,
609 shader_scene_fxglow_use();
610 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
611 shader_scene_fxglow_uTexMain(1);
612 shader_scene_fxglow_uPv( cam
->mtx
.pv
);
614 world_link_lighting_ub( world
, _shader_scene_fxglow
.id
);
615 world_bind_position_texture( world
, _shader_scene_fxglow
.id
,
616 _uniform_scene_fxglow_g_world_depth
, 2 );
617 world_bind_light_array( world
, _shader_scene_fxglow
.id
,
618 _uniform_scene_fxglow_uLightsArray
, 3 );
619 world_bind_light_index( world
, _shader_scene_fxglow
.id
,
620 _uniform_scene_fxglow_uLightsIndex
, 4 );
622 shader_scene_fxglow_uCamera( cam
->transform
[3] );
623 glDisable(GL_CULL_FACE
);
625 struct world_pass pass
= {
626 .shader
= k_shader_fxglow
,
628 .fn_bind_textures
= bindpoint_diffuse_texture1
,
629 .fn_set_mdl
= shader_scene_fxglow_uMdl
,
630 .fn_set_uPvmPrev
= shader_scene_fxglow_uPvmPrev
,
633 world_render_both_stages( world
, &pass
);
634 world_render_challenges( world
, &pass
, cam
->pos
, layer_depth
);
636 glEnable(GL_CULL_FACE
);
639 VG_STATIC
void bindpoint_terrain( world_instance
*world
,
640 struct world_surface
*mat
)
642 glActiveTexture( GL_TEXTURE1
);
643 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
645 shader_scene_terrain_uSandColour( mat
->info
.colour
);
646 shader_scene_terrain_uBlendOffset( mat
->info
.colour1
);
649 VG_STATIC
void bindpoint_override( world_instance
*world
,
650 struct world_surface
*mat
){
651 if( mat
->info
.flags
& k_material_flag_collision
){
652 shader_scene_override_uAlphatest(0);
655 glActiveTexture( GL_TEXTURE1
);
656 glBindTexture( GL_TEXTURE_2D
, world
->textures
[ mat
->info
.tex_diffuse
] );
657 shader_scene_override_uAlphatest(1);
661 VG_STATIC
void render_terrain( world_instance
*world
, camera
*cam
)
663 shader_scene_terrain_use();
664 shader_scene_terrain_uTexGarbage(0);
665 shader_scene_terrain_uTexGradients(1);
667 world_link_lighting_ub( world
, _shader_scene_terrain
.id
);
668 world_bind_position_texture( world
, _shader_scene_terrain
.id
,
669 _uniform_scene_terrain_g_world_depth
, 2 );
670 world_bind_light_array( world
, _shader_scene_terrain
.id
,
671 _uniform_scene_terrain_uLightsArray
, 3 );
672 world_bind_light_index( world
, _shader_scene_terrain
.id
,
673 _uniform_scene_terrain_uLightsIndex
, 4 );
675 glActiveTexture( GL_TEXTURE0
);
676 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
678 shader_scene_terrain_uPv( cam
->mtx
.pv
);
679 shader_scene_terrain_uCamera( cam
->transform
[3] );
681 struct world_pass pass
= {
682 .shader
= k_shader_terrain_blend
,
684 .fn_bind_textures
= bindpoint_terrain
,
685 .fn_set_mdl
= shader_scene_terrain_uMdl
,
686 .fn_set_uPvmPrev
= shader_scene_terrain_uPvmPrev
,
689 world_render_both_stages( world
, &pass
);
692 VG_STATIC
void render_sky( world_instance
*world
, camera
*cam
)
695 * Modify matrix to remove clipping and view translation
702 m4x4_copy( cam
->mtx
.v
, v
);
703 m4x4_copy( cam
->mtx_prev
.v
, v_prev
);
705 v3_zero( v_prev
[3] );
707 m4x4_copy( cam
->mtx
.p
, pv
);
708 m4x4_copy( cam
->mtx_prev
.p
, pv_prev
);
709 m4x4_reset_clipping( pv
, cam
->farz
, cam
->nearz
);
710 m4x4_reset_clipping( pv_prev
, cam
->farz
, cam
->nearz
);
712 m4x4_mul( pv
, v
, pv
);
713 m4x4_mul( pv_prev
, v_prev
, pv_prev
);
715 m4x3f identity_matrix
;
716 m4x3_identity( identity_matrix
);
721 shader_model_sky_use();
722 shader_model_sky_uMdl( identity_matrix
);
723 shader_model_sky_uPv( pv
);
724 shader_model_sky_uPvmPrev( pv_prev
);
725 shader_model_sky_uTexGarbage(0);
726 world_link_lighting_ub( world
, _shader_model_sky
.id
);
728 glActiveTexture( GL_TEXTURE0
);
729 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
731 glDepthMask( GL_FALSE
);
732 glDisable( GL_DEPTH_TEST
);
734 mesh_bind( &world_render
.skydome
);
735 mesh_draw( &world_render
.skydome
);
737 glEnable( GL_DEPTH_TEST
);
738 glDepthMask( GL_TRUE
);
741 VG_STATIC
void render_world_gates( world_instance
*world
, camera
*cam
,
744 float closest
= INFINITY
;
745 struct ent_gate
*gate
= NULL
;
747 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_gate
); i
++ ){
748 ent_gate
*gi
= mdl_arritm( &world
->ent_gate
, i
);
750 if( !(gi
->flags
& k_ent_gate_linked
) )
753 float dist
= v3_dist2( gi
->co
[0], cam
->transform
[3] );
755 vg_line_point( gi
->co
[0], 0.25f
, VG__BLUE
);
757 if( dist
< closest
){
763 world
->rendering_gate
= gate
;
765 if( gate
->flags
& k_ent_gate_locked
) return;
767 if( gate
->flags
& k_ent_gate_nonlocal
){
768 if( world_static
.load_state
!= k_world_loader_none
){
769 world
->rendering_gate
= NULL
;
773 world_instance
*dest_world
= &world_static
.instances
[ gate
->target
];
774 render_gate( world
, dest_world
, gate
, cam
, layer_depth
);
777 render_gate( world
, world
, gate
, cam
, layer_depth
);
782 VG_STATIC
void world_prerender( world_instance
*world
)
785 if( mdl_arrcount( &world
->ent_light
) ){
786 f32 rate
= vg_maxf(0.1f
, fabsf(k_day_length
)) * vg_signf(k_day_length
);
787 world
->time
+= vg
.time_delta
* (1.0/(rate
*60.0));
793 struct ub_world_lighting
*state
= &world
->ub_lighting
;
795 state
->g_time
= world
->time
;
796 state
->g_realtime
= vg
.time_real
;
797 state
->g_debug_indices
= k_debug_light_indices
;
798 state
->g_light_preview
= k_light_preview
;
799 state
->g_debug_complexity
= k_debug_light_complexity
;
801 if( skaterift
.activity
== k_skaterift_respawning
)
802 state
->g_time_of_day
= 0.1f
;
804 state
->g_time_of_day
= vg_fractf( world
->time
);
806 state
->g_day_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 2.0f
);
807 state
->g_sunset_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 4.0f
+ VG_PIf
);
809 state
->g_day_phase
= state
->g_day_phase
* 0.5f
+ 0.5f
;
810 state
->g_sunset_phase
= powf( state
->g_sunset_phase
* 0.5f
+ 0.5f
, 6.0f
);
812 float a
= state
->g_time_of_day
* VG_PIf
* 2.0f
;
813 state
->g_sun_dir
[0] = sinf( a
);
814 state
->g_sun_dir
[1] = cosf( a
);
815 state
->g_sun_dir
[2] = 0.2f
;
816 v3_normalize( state
->g_sun_dir
);
818 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
819 float dp
= state
->g_day_phase
;
821 world
->probabilities
[ k_probability_curve_wildlife_day
] =
822 (dp
*dp
*0.8f
+state
->g_sunset_phase
)*0.8f
;
823 world
->probabilities
[ k_probability_curve_wildlife_night
] =
824 1.0f
-powf(fabsf((state
->g_time_of_day
-0.5f
)*5.0f
),5.0f
);
826 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
827 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
828 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
831 VG_STATIC
void render_world( world_instance
*world
, camera
*cam
,
834 render_sky( world
, cam
);
836 render_world_routes( world
, cam
, layer_depth
);
837 render_world_standard( world
, cam
);
838 render_world_cubemapped( world
, cam
, layer_depth
);
840 render_world_vb( world
, cam
);
841 render_world_alphatest( world
, cam
);
842 render_terrain( world
, cam
);
844 if( layer_depth
== -1 ) return;
845 if( layer_depth
== 0 ){
846 world_entity_focus_render();
850 float min_dist
= INFINITY
;
852 if( mdl_arrcount( &world
->ent_route
) ){
853 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_route
); i
++ ){
854 ent_route
*route
= mdl_arritm( &world
->ent_route
, i
);
855 float dist
= v3_dist2( route
->board_transform
[3], cam
->pos
);
857 if( dist
< min_dist
){
863 ent_route
*route
= mdl_arritm( &world
->ent_route
, closest
);
864 sfd_render( world
, cam
, route
->board_transform
);
869 if( mdl_entity_id_type(world_static
.focused_entity
) == k_ent_challenge
)
870 greyout
= world_static
.focus_strength
;
872 if( greyout
> 0.0f
){
873 glDrawBuffers( 1, (GLenum
[]){ GL_COLOR_ATTACHMENT0
} );
875 glDisable(GL_DEPTH_TEST
);
876 glDepthMask(GL_FALSE
);
877 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
878 glBlendEquation(GL_FUNC_ADD
);
880 shader_blitcolour_use();
881 shader_blitcolour_uColour( (v4f
){ 0.5f
, 0.5f
, 0.5f
, greyout
*0.56f
} );
885 glEnable(GL_DEPTH_TEST
);
886 glDepthMask(GL_TRUE
);
887 glDrawBuffers( 2, (GLenum
[]){ GL_COLOR_ATTACHMENT0
,
888 GL_COLOR_ATTACHMENT1
} );
891 render_world_fxglow( world
, cam
, layer_depth
);
896 void render_world_override_pass( world_instance
*world
,
897 struct world_pass
*pass
){
898 for( int i
=0; i
<world
->surface_count
; i
++ ){
899 struct world_surface
*mat
= &world
->surfaces
[i
];
901 if( mat
->info
.flags
& k_material_flag_ghosts
) continue;
904 if( pass
->geo_type
== k_world_geo_type_solid
)
907 sm
= &mat
->sm_no_collide
;
909 if( !sm
->indice_count
)
913 m4x3_identity( mmdl
);
914 pass
->fn_set_mdl( mmdl
);
915 pass
->fn_set_uPvmPrev( pass
->cam
->mtx_prev
.pv
);
916 pass
->fn_bind_textures( world
, mat
);
917 mdl_draw_submesh( sm
);
921 VG_STATIC
void render_world_override( world_instance
*world
){
922 struct world_pass pass
= {
923 .cam
= &skaterift
.cam
,
924 .fn_bind_textures
= bindpoint_override
,
925 .fn_set_mdl
= shader_scene_override_uMdl
,
926 .fn_set_uPvmPrev
= shader_scene_override_uPvmPrev
,
927 .shader
= k_shader_override
930 shader_scene_override_use();
931 respawn_chooser_shader_uniforms();
932 shader_scene_override_uTexGarbage(0);
933 shader_scene_override_uTexMain(1);
934 shader_scene_override_uPv( pass
.cam
->mtx
.pv
);
936 world_link_lighting_ub( world
, _shader_scene_override
.id
);
937 world_bind_position_texture( world
, _shader_scene_override
.id
,
938 _uniform_scene_override_g_world_depth
, 2 );
939 world_bind_light_array( world
, _shader_scene_override
.id
,
940 _uniform_scene_override_uLightsArray
, 3 );
941 world_bind_light_index( world
, _shader_scene_override
.id
,
942 _uniform_scene_override_uLightsIndex
, 4 );
944 bind_terrain_noise();
945 shader_scene_override_uCamera( pass
.cam
->transform
[3] );
947 glDisable( GL_CULL_FACE
);
948 mesh_bind( &world
->mesh_geo
);
949 pass
.geo_type
= k_world_geo_type_solid
;
950 render_world_override_pass( world
, &pass
);
951 mesh_bind( &world
->mesh_no_collide
);
952 pass
.geo_type
= k_world_geo_type_nonsolid
;
953 render_world_override_pass( world
, &pass
);
954 glEnable( GL_CULL_FACE
);
957 VG_STATIC
void render_cubemap_side( world_instance
*world
, ent_cubemap
*cm
,
960 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
961 GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ side
, cm
->texture_id
, 0 );
962 glClear( GL_DEPTH_BUFFER_BIT
);
965 { -1.0f
, 0.0f
, 0.0f
},
966 { 1.0f
, 0.0f
, 0.0f
},
967 { 0.0f
, -1.0f
, 0.0f
},
968 { 0.0f
, 1.0f
, 0.0f
},
969 { 0.0f
, 0.0f
, -1.0f
},
973 { 0.0f
, -1.0f
, 0.0f
},
974 { 0.0f
, -1.0f
, 0.0f
},
975 { 0.0f
, 0.0f
, 1.0f
},
976 { 0.0f
, 0.0f
, -1.0f
},
977 { 0.0f
, -1.0f
, 0.0f
},
978 { 0.0f
, -1.0f
, 0.0f
}
981 v3_zero( cam
.angles
);
982 v3_copy( cm
->co
, cam
.pos
);
984 v3_copy( forward
[side
], cam
.transform
[2] );
985 v3_copy( up
[side
], cam
.transform
[1] );
986 v3_cross( up
[side
], forward
[side
], cam
.transform
[0] );
987 v3_copy( cm
->co
, cam
.transform
[3] );
988 m4x3_invert_affine( cam
.transform
, cam
.transform_inverse
);
990 camera_update_view( &cam
);
995 m4x4_copy( cam
.mtx
.p
, cam
.mtx_prev
.p
);
996 m4x4_projection( cam
.mtx
.p
, cam
.fov
, 1.0f
, cam
.nearz
, cam
.farz
);
997 camera_finalize( &cam
);
998 camera_finalize( &cam
);
1000 render_world( world
, &cam
, -1 );
1003 VG_STATIC
void render_world_cubemaps( world_instance
*world
){
1004 if( world
->cubemap_cooldown
)
1005 world
->cubemap_cooldown
--;
1007 world
->cubemap_cooldown
= 60;
1009 glViewport( 0, 0, WORLD_CUBEMAP_RES
, WORLD_CUBEMAP_RES
);
1010 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_cubemap
); i
++ ){
1011 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, i
);
1012 glBindFramebuffer( GL_FRAMEBUFFER
, cm
->framebuffer_id
);
1014 world
->cubemap_side
++;
1015 if( world
->cubemap_side
>= 6 )
1016 world
->cubemap_side
= 0;
1018 render_cubemap_side( world
, cm
, world
->cubemap_side
);
1023 VG_STATIC
void render_world_depth( world_instance
*world
, camera
*cam
)
1025 m4x3f identity_matrix
;
1026 m4x3_identity( identity_matrix
);
1028 shader_scene_depth_use();
1029 shader_scene_depth_uCamera( cam
->transform
[3] );
1030 shader_scene_depth_uPv( cam
->mtx
.pv
);
1031 shader_scene_depth_uPvmPrev( cam
->mtx_prev
.pv
);
1032 shader_scene_depth_uMdl( identity_matrix
);
1033 world_link_lighting_ub( world
, _shader_scene_depth
.id
);
1035 mesh_bind( &world
->mesh_geo
);
1036 mesh_draw( &world
->mesh_geo
);
1039 VG_STATIC
void render_world_position( world_instance
*world
, camera
*cam
)
1041 m4x3f identity_matrix
;
1042 m4x3_identity( identity_matrix
);
1044 shader_scene_position_use();
1045 shader_scene_position_uCamera( cam
->transform
[3] );
1046 shader_scene_position_uPv( cam
->mtx
.pv
);
1047 shader_scene_position_uPvmPrev( cam
->mtx_prev
.pv
);
1048 shader_scene_position_uMdl( identity_matrix
);
1049 world_link_lighting_ub( world
, _shader_scene_position
.id
);
1051 mesh_bind( &world
->mesh_geo
);
1052 mesh_draw( &world
->mesh_geo
);