2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
9 #include "world_render.h"
13 #include "ent_miniworld.h"
14 #include "player_remote.h"
15 #include "ent_skateshop.h"
17 static int ccmd_set_time( int argc
, const char *argv
[] ){
18 world_instance
*world
= world_current_instance();
20 world
->time
= atof( argv
[0] );
22 vg_error( "Usage set_time <0-1.0> (current time: %f)\n", world
->time
);
26 static void async_world_render_init( void *payload
, u32 size
)
28 vg_info( "Allocate uniform buffers\n" );
29 for( int i
=0; i
<k_world_max
; i
++ ){
30 world_instance
*world
= &world_static
.instances
[i
];
31 world
->ubo_bind_point
= i
;
33 glGenBuffers( 1, &world
->ubo_lighting
);
34 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
35 glBufferData( GL_UNIFORM_BUFFER
, sizeof(struct ub_world_lighting
),
36 NULL
, GL_DYNAMIC_DRAW
);
38 glBindBufferBase( GL_UNIFORM_BUFFER
, i
, world
->ubo_lighting
);
42 vg_info( "Allocate frame buffers\n" );
43 for( int i
=0; i
<k_world_max
; i
++ ){
44 world_instance
*world
= &world_static
.instances
[i
];
45 struct framebuffer
*fb
= &world
->heightmap
;
47 fb
->display_name
= NULL
;
51 fb
->resolution_div
= 0;
53 fb
->attachments
[0].display_name
= NULL
;
54 fb
->attachments
[0].purpose
= k_framebuffer_attachment_type_texture
;
55 fb
->attachments
[0].internalformat
= GL_RG16F
;
56 fb
->attachments
[0].format
= GL_RG
;
57 fb
->attachments
[0].type
= GL_FLOAT
;
58 fb
->attachments
[0].attachment
= GL_COLOR_ATTACHMENT0
;
60 fb
->attachments
[1].purpose
= k_framebuffer_attachment_type_none
;
61 fb
->attachments
[2].purpose
= k_framebuffer_attachment_type_none
;
62 fb
->attachments
[3].purpose
= k_framebuffer_attachment_type_none
;
63 fb
->attachments
[4].purpose
= k_framebuffer_attachment_type_none
;
65 render_fb_allocate( fb
);
69 static void world_render_init(void)
71 VG_VAR_F32( k_day_length
);
72 VG_VAR_I32( k_debug_light_indices
);
73 VG_VAR_I32( k_debug_light_complexity
);
74 VG_VAR_I32( k_light_preview
);
75 vg_console_reg_cmd( "set_time", ccmd_set_time
, NULL
);
77 world_render
.sky_rate
= 1.0;
78 world_render
.sky_target_rate
= 1.0;
80 shader_scene_standard_register();
81 shader_scene_standard_alphatest_register();
82 shader_scene_override_register();
83 shader_scene_cubemapped_register();
84 shader_scene_fxglow_register();
85 shader_scene_vertex_blend_register();
86 shader_scene_terrain_register();
87 shader_scene_depth_register();
88 shader_scene_position_register();
89 shader_model_sky_register();
90 shader_model_sky_space_register();
92 vg_info( "Loading world resources\n" );
93 vg_linear_clear( vg_mem
.scratch
);
96 mdl_open( &msky
, "models/rs_skydome.mdl", vg_mem
.scratch
);
97 mdl_load_metadata_block( &msky
, vg_mem
.scratch
);
98 mdl_async_load_glmesh( &msky
, &world_render
.skydome
);
101 vg_info( "Loading default world textures\n" );
102 vg_tex2d_load_qoi_async_file( "textures/garbage.qoi",
103 VG_TEX2D_NEAREST
|VG_TEX2D_REPEAT
,
104 &world_render
.tex_terrain_noise
);
106 vg_async_call( async_world_render_init
, NULL
, 0 );
109 static void world_link_lighting_ub( world_instance
*world
, GLuint shader
){
110 GLuint idx
= glGetUniformBlockIndex( shader
, "ub_world_lighting" );
111 glUniformBlockBinding( shader
, idx
, world
->ubo_bind_point
);
114 static void world_bind_position_texture( world_instance
*world
,
115 GLuint shader
, GLuint location
,
117 render_fb_bind_texture( &world
->heightmap
, 0, slot
);
118 glUniform1i( location
, slot
);
121 static void world_bind_light_array( world_instance
*world
,
122 GLuint shader
, GLuint location
,
124 glActiveTexture( GL_TEXTURE0
+ slot
);
125 glBindTexture( GL_TEXTURE_BUFFER
, world
->tex_light_entities
);
126 glUniform1i( location
, slot
);
129 static void world_bind_light_index( world_instance
*world
,
130 GLuint shader
, GLuint location
,
132 glActiveTexture( GL_TEXTURE0
+ slot
);
133 glBindTexture( GL_TEXTURE_3D
, world
->tex_light_cubes
);
134 glUniform1i( location
, slot
);
137 static void render_world_depth( world_instance
*world
, camera
*cam
);
143 static void bind_terrain_noise(void){
144 glActiveTexture( GL_TEXTURE0
);
145 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
150 enum mdl_shader shader
;
151 enum world_geo_type geo_type
;
153 void (*fn_bind_textures
)( world_instance
*world
,
154 struct world_surface
*mat
);
155 void (*fn_set_mdl
)( m4x3f mdl
);
156 void (*fn_set_uPvmPrev
)( m4x4f pvm
);
157 void (*fn_set_uNormalMtx
)( m3x3f mnorm
);
160 /* FIXME: we gotta do something about this crap, maybe batch lists. something..
161 * anything but this. */
163 void world_render_props( world_instance
*world
, u32 material_id
,
164 struct world_pass
*pass
){
165 if( !mdl_arrcount( &world
->ent_prop
) ) return;
167 /* HACK: use the first material for every prop entity */
168 ent_prop
*first
= mdl_arritm( &world
->ent_prop
, 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_prop
); j
++ ){
178 ent_prop
*prop
= mdl_arritm( &world
->ent_prop
, j
);
179 if( prop
->flags
& 0x1 ) continue;
181 for( u32 k
=0; k
<prop
->submesh_count
; k
++ ){
182 sm
= mdl_arritm( &world
->meta
.submeshs
, prop
->submesh_start
+k
);
185 mdl_transform_m4x3( &prop
->transform
, mmdl
);
188 m4x3_expand( mmdl
, m4mdl
);
189 m4x4_mul( pass
->cam
->mtx_prev
.pv
, m4mdl
, m4mdl
);
191 pass
->fn_set_mdl( mmdl
);
192 pass
->fn_set_uPvmPrev( m4mdl
);
194 mdl_draw_submesh( sm
);
200 void world_render_traffic( world_instance
*world
, u32 material_id
,
201 struct world_pass
*pass
){
202 if( !mdl_arrcount( &world
->ent_traffic
) ) return;
204 /* HACK: use the first material for every traffic entity */
205 ent_traffic
*first
= mdl_arritm( &world
->ent_traffic
, 0 );
206 if( !first
->submesh_count
) return;
208 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
, first
->submesh_start
);
209 if( sm
->material_id
!= material_id
) return;
211 struct world_surface
*mat
= &world
->surfaces
[ material_id
];
212 pass
->fn_bind_textures( world
, mat
);
214 for( u32 j
=0; j
<mdl_arrcount( &world
->ent_traffic
); j
++ ){
215 ent_traffic
*traffic
= mdl_arritm( &world
->ent_traffic
, j
);
217 for( u32 k
=0; k
<traffic
->submesh_count
; k
++ ){
218 sm
= mdl_arritm( &world
->meta
.submeshs
,
219 traffic
->submesh_start
+k
);
222 q_m3x3( traffic
->transform
.q
, mmdl
);
223 v3_copy( traffic
->transform
.co
, mmdl
[3] );
226 m4x3_expand( mmdl
, m4mdl
);
227 m4x4_mul( pass
->cam
->mtx_prev
.pv
, m4mdl
, m4mdl
);
229 pass
->fn_set_mdl( mmdl
);
230 pass
->fn_set_uPvmPrev( m4mdl
);
232 mdl_draw_submesh( sm
);
238 void world_render_pass( world_instance
*world
, struct world_pass
*pass
){
239 for( int i
=0; i
<world
->surface_count
; i
++ ){
240 struct world_surface
*mat
= &world
->surfaces
[i
];
242 if( mat
->info
.shader
== pass
->shader
){
245 if( pass
->geo_type
== k_world_geo_type_solid
){
249 world_render_traffic( world
, i
, pass
);
250 world_render_props( world
, i
, pass
);
251 sm
= &mat
->sm_no_collide
;
254 if( !sm
->indice_count
)
258 m4x3_identity( mmdl
);
259 pass
->fn_set_mdl( mmdl
);
260 pass
->fn_set_uPvmPrev( pass
->cam
->mtx_prev
.pv
);
262 pass
->fn_bind_textures( world
, mat
);
263 mdl_draw_submesh( sm
);
269 void world_render_both_stages( world_instance
*world
, struct world_pass
*pass
)
271 mesh_bind( &world
->mesh_geo
);
272 pass
->geo_type
= k_world_geo_type_solid
;
273 world_render_pass( world
, pass
);
275 glDisable( GL_CULL_FACE
);
276 mesh_bind( &world
->mesh_no_collide
);
277 pass
->geo_type
= k_world_geo_type_nonsolid
;
278 world_render_pass( world
, pass
);
279 glEnable( GL_CULL_FACE
);
282 static GLuint
world_get_texture( world_instance
*world
, u32 id
){
283 if( id
& 0x80000000 )
284 return skaterift
.rt_textures
[id
& ~0x80000000];
286 return world
->textures
[ id
];
289 static void bindpoint_diffuse_texture1( world_instance
*world
,
290 struct world_surface
*mat
){
291 glActiveTexture( GL_TEXTURE1
);
292 glBindTexture( GL_TEXTURE_2D
,
293 world_get_texture(world
,mat
->info
.tex_diffuse
) );
296 static void bindpoint_diffuse1_and_cubemap10( world_instance
*world
,
297 struct world_surface
*mat
){
298 glActiveTexture( GL_TEXTURE1
);
299 glBindTexture( GL_TEXTURE_2D
,
300 world_get_texture(world
,mat
->info
.tex_diffuse
) );
302 u32 cubemap_id
= mat
->info
.tex_none0
,
305 if( mdl_entity_id_type( cubemap_id
) == k_ent_cubemap
){
306 cubemap_index
= mdl_entity_id_id( cubemap_id
);
309 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, cubemap_index
);
310 glActiveTexture( GL_TEXTURE10
);
311 glBindTexture( GL_TEXTURE_CUBE_MAP
, cm
->texture_id
);
313 shader_scene_cubemapped_uColour( mat
->info
.colour
);
316 static void render_world_vb( world_instance
*world
, camera
*cam
){
317 shader_scene_vertex_blend_use();
318 shader_scene_vertex_blend_uTexGarbage(0);
319 shader_scene_vertex_blend_uTexGradients(1);
320 world_link_lighting_ub( world
, _shader_scene_vertex_blend
.id
);
321 world_bind_position_texture( world
, _shader_scene_vertex_blend
.id
,
322 _uniform_scene_vertex_blend_g_world_depth
, 2 );
323 world_bind_light_array( world
, _shader_scene_vertex_blend
.id
,
324 _uniform_scene_vertex_blend_uLightsArray
, 3 );
325 world_bind_light_index( world
, _shader_scene_vertex_blend
.id
,
326 _uniform_scene_vertex_blend_uLightsIndex
, 4 );
328 glActiveTexture( GL_TEXTURE0
);
329 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
331 shader_scene_vertex_blend_uPv( cam
->mtx
.pv
);
332 shader_scene_vertex_blend_uCamera( cam
->transform
[3] );
334 struct world_pass pass
= {
335 .shader
= k_shader_standard_vertex_blend
,
337 .fn_bind_textures
= bindpoint_diffuse_texture1
,
338 .fn_set_mdl
= shader_scene_vertex_blend_uMdl
,
339 .fn_set_uPvmPrev
= shader_scene_vertex_blend_uPvmPrev
,
342 world_render_both_stages( world
, &pass
);
345 static void world_shader_standard_bind( world_instance
*world
, camera
*cam
){
346 shader_scene_standard_use();
347 shader_scene_standard_uTexGarbage(0);
348 shader_scene_standard_uTexMain(1);
349 shader_scene_standard_uPv( cam
->mtx
.pv
);
351 world_link_lighting_ub( world
, _shader_scene_standard
.id
);
352 world_bind_position_texture( world
, _shader_scene_standard
.id
,
353 _uniform_scene_standard_g_world_depth
, 2 );
354 world_bind_light_array( world
, _shader_scene_standard
.id
,
355 _uniform_scene_standard_uLightsArray
, 3 );
356 world_bind_light_index( world
, _shader_scene_standard
.id
,
357 _uniform_scene_standard_uLightsIndex
, 4 );
359 bind_terrain_noise();
360 shader_scene_standard_uCamera( cam
->transform
[3] );
363 static void render_world_standard( world_instance
*world
, camera
*cam
){
364 world_shader_standard_bind( world
, cam
);
365 struct world_pass pass
= {
366 .shader
= k_shader_standard
,
368 .fn_bind_textures
= bindpoint_diffuse_texture1
,
369 .fn_set_mdl
= shader_scene_standard_uMdl
,
370 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
373 world_render_both_stages( world
, &pass
);
376 static void render_world_cubemapped( world_instance
*world
, camera
*cam
,
378 if( !mdl_arrcount( &world
->ent_cubemap
) )
382 world_shader_standard_bind( world
, cam
);
384 struct world_pass pass
= {
385 .shader
= k_shader_cubemap
,
387 .fn_bind_textures
= bindpoint_diffuse_texture1
,
388 .fn_set_mdl
= shader_scene_standard_uMdl
,
389 .fn_set_uPvmPrev
= shader_scene_standard_uPvmPrev
,
392 world_render_both_stages( world
, &pass
);
395 shader_scene_cubemapped_use();
396 shader_scene_cubemapped_uTexGarbage(0);
397 shader_scene_cubemapped_uTexMain(1);
398 shader_scene_cubemapped_uTexCubemap(10);
399 shader_scene_cubemapped_uPv( cam
->mtx
.pv
);
401 world_link_lighting_ub( world
, _shader_scene_cubemapped
.id
);
402 world_bind_position_texture( world
, _shader_scene_cubemapped
.id
,
403 _uniform_scene_cubemapped_g_world_depth
, 2 );
404 world_bind_light_array( world
, _shader_scene_cubemapped
.id
,
405 _uniform_scene_cubemapped_uLightsArray
, 3 );
406 world_bind_light_index( world
, _shader_scene_cubemapped
.id
,
407 _uniform_scene_cubemapped_uLightsIndex
, 4 );
409 bind_terrain_noise();
410 shader_scene_cubemapped_uCamera( cam
->transform
[3] );
412 struct world_pass pass
= {
413 .shader
= k_shader_cubemap
,
415 .fn_bind_textures
= bindpoint_diffuse1_and_cubemap10
,
416 .fn_set_mdl
= shader_scene_cubemapped_uMdl
,
417 .fn_set_uPvmPrev
= shader_scene_cubemapped_uPvmPrev
,
420 world_render_both_stages( world
, &pass
);
424 static void render_world_alphatest( world_instance
*world
, camera
*cam
){
425 shader_scene_standard_alphatest_use();
426 shader_scene_standard_alphatest_uTexGarbage(0);
427 shader_scene_standard_alphatest_uTexMain(1);
428 shader_scene_standard_alphatest_uPv( cam
->mtx
.pv
);
430 world_link_lighting_ub( world
, _shader_scene_standard_alphatest
.id
);
431 world_bind_position_texture( world
, _shader_scene_standard_alphatest
.id
,
432 _uniform_scene_standard_alphatest_g_world_depth
, 2 );
433 world_bind_light_array( world
, _shader_scene_standard_alphatest
.id
,
434 _uniform_scene_standard_alphatest_uLightsArray
, 3 );
435 world_bind_light_index( world
, _shader_scene_standard_alphatest
.id
,
436 _uniform_scene_standard_alphatest_uLightsIndex
, 4 );
439 bind_terrain_noise();
442 shader_scene_standard_alphatest_uCamera( cam
->transform
[3] );
444 glDisable(GL_CULL_FACE
);
446 struct world_pass pass
= {
447 .shader
= k_shader_standard_cutout
,
449 .fn_bind_textures
= bindpoint_diffuse_texture1
,
450 .fn_set_mdl
= shader_scene_standard_alphatest_uMdl
,
451 .fn_set_uPvmPrev
= shader_scene_standard_alphatest_uPvmPrev
,
454 world_render_both_stages( world
, &pass
);
456 glEnable(GL_CULL_FACE
);
460 void world_render_challenges( world_instance
*world
, struct world_pass
*pass
,
463 if( skaterift
.activity
== k_skaterift_replay
) return;
464 if( world
!= world_current_instance() ) return;
469 u32 objective_list
[ 32 ],
470 challenge_list
[ 16 ];
472 v2f objective_uv_offsets
[ 32 ];
474 u32 objective_count
= 0,
477 ent_challenge
*active_challenge
= NULL
;
479 if( mdl_entity_id_type( world_static
.focused_entity
) == k_ent_challenge
){
480 if( (skaterift
.activity
== k_skaterift_default
) &&
481 world_static
.challenge_target
){
485 if( !((skaterift
.activity
!= k_skaterift_ent_focus
) &&
486 !world_static
.challenge_target
) ){
487 world_instance
*challenge_world
= world_current_instance();
488 u32 index
= mdl_entity_id_id( world_static
.focused_entity
);
489 active_challenge
= mdl_arritm(&challenge_world
->ent_challenge
, index
);
493 if( active_challenge
){
494 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
495 challenge_list
[ challenge_count
++ ] = world_static
.focused_entity
;
497 u32 next
= active_challenge
->first
;
498 while( mdl_entity_id_type(next
) == k_ent_objective
){
499 u32 index
= mdl_entity_id_id( next
);
500 objective_list
[ objective_count
++ ] = index
;
502 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
503 next
= objective
->id_next
;
509 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
511 bh_iter_init_range( 0, &it
, pos
, radius
+10.0f
);
513 while( bh_next( world
->entity_bh
, &it
, &idx
) ){
514 u32 id
= world
->entity_list
[ idx
],
515 type
= mdl_entity_id_type( id
),
516 index
= mdl_entity_id_id( id
);
518 if( type
== k_ent_objective
) {
519 if( objective_count
< vg_list_size(objective_list
) )
520 objective_list
[ objective_count
++ ] = index
;
522 else if( type
== k_ent_challenge
){
523 if( challenge_count
< vg_list_size(challenge_list
) )
524 challenge_list
[ challenge_count
++ ] = index
;
529 /* render objectives */
530 glDisable( GL_CULL_FACE
);
531 mesh_bind( &world
->mesh_no_collide
);
532 u32 last_material
= 0;
533 for( u32 i
=0; i
<objective_count
; i
++ ){
534 u32 index
= objective_list
[ i
];
535 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
536 if( (objective
->flags
& k_ent_objective_hidden
) &&
537 !active_challenge
) continue;
542 u32 passed
= objective
->flags
& k_ent_objective_passed
;
543 f32 target
= passed
? 0.0f
: 1.0f
;
544 vg_slewf(&objective
->transform
.s
[0], target
, vg
.time_frame_delta
*4.0f
);
545 scale
= vg_smoothstepf( objective
->transform
.s
[0] );
547 if( (objective
== world_static
.challenge_target
) || passed
)
548 shader_scene_fxglow_uUvOffset( (v2f
){ 16.0f
/256.0f
, 0.0f
} );
550 shader_scene_fxglow_uUvOffset( (v2f
){ 8.0f
/256.0f
, 0.0f
} );
553 f32 dist
= v3_dist( objective
->transform
.co
, pos
) * (1.0f
/radius
);
554 scale
= vg_smoothstepf( vg_clampf( 5.0f
-dist
*5.0f
, 0.0f
,1.0f
) );
558 q_m3x3( objective
->transform
.q
, mmdl
);
559 m3x3_scalef( mmdl
, scale
);
560 v3_copy( objective
->transform
.co
, mmdl
[3] );
561 shader_scene_fxglow_uMdl( mmdl
);
563 for( u32 j
=0; j
<objective
->submesh_count
; j
++ ){
564 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
565 objective
->submesh_start
+ j
);
567 if( sm
->material_id
!= last_material
){
568 last_material
= sm
->material_id
;
569 pass
->fn_bind_textures( world
, &world
->surfaces
[sm
->material_id
] );
571 mdl_draw_submesh( sm
);
576 font3d_bind( &gui
.font
, k_font_shader_world
, 0, world
, &skaterift
.cam
);
581 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
582 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, i
);
583 if( challenge
->status
) count
++;
587 c
+=highscore_intl( buf
+c
, count
, 3 );
589 c
+=highscore_intl( buf
+c
, mdl_arrcount(&world
->ent_challenge
), 3 );
592 f32 w
= font3d_string_width( 1, buf
);
594 m3x3_identity( mlocal
);
595 mlocal
[3][0] = -w
*0.5f
;
599 for( u32 i
=0; i
<challenge_count
; i
++ ){
600 u32 index
= challenge_list
[ i
];
601 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
603 mdl_transform_m4x3( &challenge
->transform
, mmdl
);
604 m4x3_mul( mmdl
, mlocal
, mmdl
);
606 vg_line_point( challenge
->transform
.co
, 0.25f
, VG__RED
);
608 f32 dist
= v3_dist( challenge
->transform
.co
, pos
) * (1.0f
/radius
),
609 scale
= vg_smoothstepf( vg_clampf( 10.0f
-dist
*10.0f
, 0.0f
,1.0f
) ),
612 if( challenge
->status
)
615 shader_scene_font_uOpacity( scale
);
616 shader_scene_font_uColourize( colour
);
617 font3d_simple_draw( 1, buf
, &skaterift
.cam
, mmdl
);
621 static void render_world_fxglow( world_instance
*world
, camera
*cam
){
622 shader_scene_fxglow_use();
623 shader_scene_fxglow_uUvOffset( (v2f
){ 0.0f
, 0.0f
} );
624 shader_scene_fxglow_uTexMain(1);
625 shader_scene_fxglow_uPv( cam
->mtx
.pv
);
627 world_link_lighting_ub( world
, _shader_scene_fxglow
.id
);
628 world_bind_position_texture( world
, _shader_scene_fxglow
.id
,
629 _uniform_scene_fxglow_g_world_depth
, 2 );
630 world_bind_light_array( world
, _shader_scene_fxglow
.id
,
631 _uniform_scene_fxglow_uLightsArray
, 3 );
632 world_bind_light_index( world
, _shader_scene_fxglow
.id
,
633 _uniform_scene_fxglow_uLightsIndex
, 4 );
635 shader_scene_fxglow_uCamera( cam
->transform
[3] );
636 glDisable(GL_CULL_FACE
);
638 struct world_pass pass
= {
639 .shader
= k_shader_fxglow
,
641 .fn_bind_textures
= bindpoint_diffuse_texture1
,
642 .fn_set_mdl
= shader_scene_fxglow_uMdl
,
643 .fn_set_uPvmPrev
= shader_scene_fxglow_uPvmPrev
,
646 world_render_both_stages( world
, &pass
);
647 world_render_challenges( world
, &pass
, cam
->pos
);
649 glEnable(GL_CULL_FACE
);
652 static void bindpoint_terrain( world_instance
*world
,
653 struct world_surface
*mat
)
655 glActiveTexture( GL_TEXTURE1
);
656 glBindTexture( GL_TEXTURE_2D
,
657 world_get_texture(world
,mat
->info
.tex_diffuse
) );
659 shader_scene_terrain_uSandColour( mat
->info
.colour
);
660 shader_scene_terrain_uBlendOffset( mat
->info
.colour1
);
663 static void bindpoint_override( world_instance
*world
,
664 struct world_surface
*mat
){
665 if( mat
->info
.flags
& k_material_flag_collision
){
666 shader_scene_override_uAlphatest(0);
669 glActiveTexture( GL_TEXTURE1
);
670 glBindTexture( GL_TEXTURE_2D
,
671 world_get_texture(world
,mat
->info
.tex_diffuse
) );
672 shader_scene_override_uAlphatest(1);
676 static void render_terrain( world_instance
*world
, camera
*cam
){
677 shader_scene_terrain_use();
678 shader_scene_terrain_uTexGarbage(0);
679 shader_scene_terrain_uTexGradients(1);
681 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world
, scene_terrain
);
682 glActiveTexture( GL_TEXTURE0
);
683 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
685 shader_scene_terrain_uPv( cam
->mtx
.pv
);
686 shader_scene_terrain_uCamera( cam
->transform
[3] );
688 struct world_pass pass
= {
689 .shader
= k_shader_terrain_blend
,
691 .fn_bind_textures
= bindpoint_terrain
,
692 .fn_set_mdl
= shader_scene_terrain_uMdl
,
693 .fn_set_uPvmPrev
= shader_scene_terrain_uPvmPrev
,
696 world_render_both_stages( world
, &pass
);
699 static void render_sky( world_instance
*world
, camera
*cam
){
701 * Modify matrix to remove clipping and view translation
708 m4x4_copy( cam
->mtx
.v
, v
);
709 m4x4_copy( cam
->mtx_prev
.v
, v_prev
);
711 for( int i
=0; i
<3; i
++ ){
713 v3_normalize(v_prev
[i
]);
716 v3_zero( v_prev
[3] );
718 m4x4_copy( cam
->mtx
.p
, pv
);
719 m4x4_copy( cam
->mtx_prev
.p
, pv_prev
);
720 m4x4_reset_clipping( pv
, 100.0f
, 0.1f
);
721 m4x4_reset_clipping( pv_prev
, 100.0f
, 0.1f
);
723 m4x4_mul( pv
, v
, pv
);
724 m4x4_mul( pv_prev
, v_prev
, pv_prev
);
726 m4x3f identity_matrix
;
727 m4x3_identity( identity_matrix
);
732 if( world
->skybox
== k_skybox_default
){
733 shader_model_sky_use();
734 shader_model_sky_uMdl( identity_matrix
);
735 shader_model_sky_uPv( pv
);
736 shader_model_sky_uPvmPrev( pv_prev
);
737 shader_model_sky_uTexGarbage(0);
738 world_link_lighting_ub( world
, _shader_model_sky
.id
);
740 glActiveTexture( GL_TEXTURE0
);
741 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
743 else if( world
->skybox
== k_skybox_space
){
744 shader_model_sky_space_use();
746 shader_model_sky_space_uMdl( identity_matrix
);
747 shader_model_sky_space_uPv( pv
);
748 shader_model_sky_space_uPvmPrev( pv_prev
);
749 shader_model_sky_space_uTexGarbage(0);
750 world_link_lighting_ub( world
, _shader_model_sky_space
.id
);
752 glActiveTexture( GL_TEXTURE0
);
753 glBindTexture( GL_TEXTURE_2D
, world_render
.tex_terrain_noise
);
759 glDepthMask( GL_FALSE
);
760 glDisable( GL_DEPTH_TEST
);
762 mesh_bind( &world_render
.skydome
);
763 mesh_draw( &world_render
.skydome
);
765 glEnable( GL_DEPTH_TEST
);
766 glDepthMask( GL_TRUE
);
769 static void render_world_gates( world_instance
*world
, camera
*cam
){
770 float closest
= INFINITY
;
771 struct ent_gate
*gate
= NULL
;
773 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_gate
); i
++ ){
774 ent_gate
*gi
= mdl_arritm( &world
->ent_gate
, i
);
775 if( !(gi
->flags
& k_ent_gate_linked
) )
778 float dist
= v3_dist2( gi
->co
[0], cam
->transform
[3] );
780 vg_line_point( gi
->co
[0], 0.25f
, VG__BLUE
);
782 if( dist
< closest
){
788 world
->rendering_gate
= gate
;
791 if( gate
->flags
& k_ent_gate_locked
){
792 world
->rendering_gate
= NULL
;
796 if( gate
->flags
& k_ent_gate_nonlocal
){
797 if( world_static
.load_state
!= k_world_loader_none
){
798 world
->rendering_gate
= NULL
;
802 world_instance
*dest_world
= &world_static
.instances
[ gate
->target
];
803 render_gate( world
, dest_world
, gate
, cam
);
806 render_gate( world
, world
, gate
, cam
);
810 static void world_prerender( world_instance
*world
){
811 if( mdl_arrcount( &world
->ent_light
) ){
812 f32 rate
= vg_maxf(0.1f
, fabsf(k_day_length
)) * vg_signf(k_day_length
);
813 world
->time
+= vg
.time_frame_delta
* (1.0/(rate
*60.0));
819 struct ub_world_lighting
*state
= &world
->ub_lighting
;
821 state
->g_time
= world
->time
;
822 state
->g_realtime
= vg
.time_real
;
823 state
->g_debug_indices
= k_debug_light_indices
;
824 state
->g_light_preview
= k_light_preview
;
825 state
->g_debug_complexity
= k_debug_light_complexity
;
826 state
->g_time_of_day
= vg_fractf( world
->time
);
828 state
->g_day_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 2.0f
);
829 state
->g_sunset_phase
= cosf( state
->g_time_of_day
* VG_PIf
* 4.0f
+ VG_PIf
);
831 state
->g_day_phase
= state
->g_day_phase
* 0.5f
+ 0.5f
;
832 state
->g_sunset_phase
= powf( state
->g_sunset_phase
* 0.5f
+ 0.5f
, 6.0f
);
834 float a
= state
->g_time_of_day
* VG_PIf
* 2.0f
;
835 state
->g_sun_dir
[0] = sinf( a
);
836 state
->g_sun_dir
[1] = cosf( a
);
837 state
->g_sun_dir
[2] = 0.2f
;
838 v3_normalize( state
->g_sun_dir
);
840 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
841 float dp
= state
->g_day_phase
;
843 world
->probabilities
[ k_probability_curve_wildlife_day
] =
844 (dp
*dp
*0.8f
+state
->g_sunset_phase
)*0.8f
;
845 world
->probabilities
[ k_probability_curve_wildlife_night
] =
846 1.0f
-powf(fabsf((state
->g_time_of_day
-0.5f
)*5.0f
),5.0f
);
848 glBindBuffer( GL_UNIFORM_BUFFER
, world
->ubo_lighting
);
849 glBufferSubData( GL_UNIFORM_BUFFER
, 0,
850 sizeof(struct ub_world_lighting
), &world
->ub_lighting
);
853 static void render_world( world_instance
*world
, camera
*cam
,
854 int stenciled
, int viewing_from_gate
,
855 int with_water
, int with_cubemaps
){
857 glClear( GL_DEPTH_BUFFER_BIT
);
858 glStencilFunc( GL_EQUAL
, 1, 0xFF );
859 glStencilMask( 0x00 );
860 glEnable( GL_CULL_FACE
);
861 glEnable( GL_STENCIL_TEST
);
864 glStencilMask( 0xFF );
865 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
866 glDisable( GL_STENCIL_TEST
);
869 render_sky( world
, cam
);
872 m4x3_identity(identity
);
873 render_world_routes( world
, world
, identity
, cam
, viewing_from_gate
, 0 );
874 render_world_standard( world
, cam
);
875 render_world_cubemapped( world
, cam
, with_cubemaps
);
877 render_world_vb( world
, cam
);
878 render_world_alphatest( world
, cam
);
879 render_terrain( world
, cam
);
881 if( !viewing_from_gate
){
882 world_entity_focus_render();
886 float min_dist
= INFINITY
;
888 if( mdl_arrcount( &world
->ent_route
) ){
889 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_route
); i
++ ){
890 ent_route
*route
= mdl_arritm( &world
->ent_route
, i
);
891 float dist
= v3_dist2( route
->board_transform
[3], cam
->pos
);
893 if( dist
< min_dist
){
899 ent_route
*route
= mdl_arritm( &world
->ent_route
, closest
);
900 sfd_render( world
, cam
, route
->board_transform
);
904 if( !viewing_from_gate
){
906 if( mdl_entity_id_type(world_static
.focused_entity
) == k_ent_challenge
)
907 greyout
= world_static
.focus_strength
;
909 if( greyout
> 0.0f
){
910 glDrawBuffers( 1, (GLenum
[]){ GL_COLOR_ATTACHMENT0
} );
912 glDisable(GL_DEPTH_TEST
);
913 glDepthMask(GL_FALSE
);
914 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
915 glBlendEquation(GL_FUNC_ADD
);
917 shader_blitcolour_use();
918 shader_blitcolour_uColour( (v4f
){ 0.5f
, 0.5f
, 0.5f
, greyout
*0.56f
} );
922 glEnable(GL_DEPTH_TEST
);
923 glDepthMask(GL_TRUE
);
924 glDrawBuffers( 2, (GLenum
[]){ GL_COLOR_ATTACHMENT0
,
925 GL_COLOR_ATTACHMENT1
} );
928 render_world_fxglow( world
, cam
);
932 render_water_texture( world
, cam
);
933 render_fb_bind( gpipeline
.fb_main
, 1 );
937 glStencilFunc( GL_EQUAL
, 1, 0xFF );
938 glStencilMask( 0x00 );
939 glEnable( GL_CULL_FACE
);
940 glEnable( GL_STENCIL_TEST
);
944 render_water_surface( world
, cam
);
947 render_remote_players( world
, cam
);
948 ent_miniworld_render( world
, cam
);
951 glStencilMask( 0xFF );
952 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
953 glDisable( GL_STENCIL_TEST
);
958 static void render_world_override_pass( world_instance
*world
,
959 struct world_pass
*pass
,
960 m4x3f mmdl
, m3x3f mnormal
,
962 for( int i
=0; i
<world
->surface_count
; i
++ ){
963 struct world_surface
*mat
= &world
->surfaces
[i
];
965 if( mat
->info
.flags
& k_material_flag_ghosts
) continue;
968 if( pass
->geo_type
== k_world_geo_type_solid
)
971 sm
= &mat
->sm_no_collide
;
973 if( !sm
->indice_count
)
976 pass
->fn_set_mdl( mmdl
);
977 pass
->fn_set_uNormalMtx( mnormal
);
978 pass
->fn_set_uPvmPrev( mpvm_prev
);
979 pass
->fn_bind_textures( world
, mat
);
980 mdl_draw_submesh( sm
);
984 static void render_world_override( world_instance
*world
,
985 world_instance
*lighting_source
,
988 ent_spawn
*dest_spawn
, v4f map_info
){
989 struct world_pass pass
= {
991 .fn_bind_textures
= bindpoint_override
,
992 .fn_set_mdl
= shader_scene_override_uMdl
,
993 .fn_set_uPvmPrev
= shader_scene_override_uPvmPrev
,
994 .fn_set_uNormalMtx
= shader_scene_override_uNormalMtx
,
995 .shader
= k_shader_override
998 shader_scene_override_use();
999 shader_scene_override_uTexGarbage(0);
1000 shader_scene_override_uTexMain(1);
1001 shader_scene_override_uPv( pass
.cam
->mtx
.pv
);
1002 shader_scene_override_uMapInfo( map_info
);
1004 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( lighting_source
, scene_override
);
1005 bind_terrain_noise();
1007 shader_scene_override_uCamera( pass
.cam
->transform
[3] );
1010 m4x3_expand( mmdl
, mpvm_prev
);
1011 m4x4_mul( cam
->mtx_prev
.pv
, mpvm_prev
, mpvm_prev
);
1014 m3x3_inv( mmdl
, mnormal
);
1015 m3x3_transpose( mnormal
, mnormal
);
1016 v3_normalize( mnormal
[0] );
1017 v3_normalize( mnormal
[1] );
1018 v3_normalize( mnormal
[2] );
1020 v4f uPlayerPos
, uSpawnPos
;
1021 v4_zero( uPlayerPos
);
1022 v4_zero( uSpawnPos
);
1024 v3_copy( world
->player_co
, uPlayerPos
);
1026 if( dest_spawn
&& (v3_dist2(dest_spawn
->transform
.co
,uPlayerPos
) > 0.1f
) )
1027 v3_copy( dest_spawn
->transform
.co
, uSpawnPos
);
1029 v3_add( uPlayerPos
, (v3f
){0,-1,0}, uSpawnPos
);
1031 uPlayerPos
[3] = v3_dist(uPlayerPos
,uSpawnPos
);
1032 uSpawnPos
[3] = 1.0f
/uPlayerPos
[3];
1034 shader_scene_override_uPlayerPos( uPlayerPos
);
1035 shader_scene_override_uSpawnPos( uSpawnPos
);
1038 glDisable( GL_CULL_FACE
);
1039 mesh_bind( &world
->mesh_geo
);
1040 pass
.geo_type
= k_world_geo_type_solid
;
1041 render_world_override_pass( world
, &pass
, mmdl
, mnormal
, mpvm_prev
);
1042 mesh_bind( &world
->mesh_no_collide
);
1043 pass
.geo_type
= k_world_geo_type_nonsolid
;
1044 render_world_override_pass( world
, &pass
, mmdl
, mnormal
, mpvm_prev
);
1045 glEnable( GL_CULL_FACE
);
1048 static void render_cubemap_side( world_instance
*world
, ent_cubemap
*cm
,
1051 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
1052 GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ side
, cm
->texture_id
, 0 );
1053 glClear( GL_DEPTH_BUFFER_BIT
);
1056 { -1.0f
, 0.0f
, 0.0f
},
1057 { 1.0f
, 0.0f
, 0.0f
},
1058 { 0.0f
, -1.0f
, 0.0f
},
1059 { 0.0f
, 1.0f
, 0.0f
},
1060 { 0.0f
, 0.0f
, -1.0f
},
1061 { 0.0f
, 0.0f
, 1.0f
}
1064 { 0.0f
, -1.0f
, 0.0f
},
1065 { 0.0f
, -1.0f
, 0.0f
},
1066 { 0.0f
, 0.0f
, 1.0f
},
1067 { 0.0f
, 0.0f
, -1.0f
},
1068 { 0.0f
, -1.0f
, 0.0f
},
1069 { 0.0f
, -1.0f
, 0.0f
}
1072 v3_zero( cam
.angles
);
1073 v3_copy( cm
->co
, cam
.pos
);
1075 v3_copy( forward
[side
], cam
.transform
[2] );
1076 v3_copy( up
[side
], cam
.transform
[1] );
1077 v3_cross( up
[side
], forward
[side
], cam
.transform
[0] );
1078 v3_copy( cm
->co
, cam
.transform
[3] );
1079 m4x3_invert_affine( cam
.transform
, cam
.transform_inverse
);
1081 camera_update_view( &cam
);
1086 m4x4_copy( cam
.mtx
.p
, cam
.mtx_prev
.p
);
1087 m4x4_projection( cam
.mtx
.p
, cam
.fov
, 1.0f
, cam
.nearz
, cam
.farz
);
1088 camera_finalize( &cam
);
1089 camera_finalize( &cam
);
1091 render_world( world
, &cam
, 0, 1, 1, 0 );
1094 static void render_world_cubemaps( world_instance
*world
){
1095 if( world
->cubemap_cooldown
)
1096 world
->cubemap_cooldown
--;
1098 world
->cubemap_cooldown
= 60;
1100 glViewport( 0, 0, WORLD_CUBEMAP_RES
, WORLD_CUBEMAP_RES
);
1101 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_cubemap
); i
++ ){
1102 ent_cubemap
*cm
= mdl_arritm( &world
->ent_cubemap
, i
);
1103 glBindFramebuffer( GL_FRAMEBUFFER
, cm
->framebuffer_id
);
1105 world
->cubemap_side
++;
1106 if( world
->cubemap_side
>= 6 )
1107 world
->cubemap_side
= 0;
1109 render_cubemap_side( world
, cm
, world
->cubemap_side
);
1114 static void render_world_depth( world_instance
*world
, camera
*cam
){
1115 m4x3f identity_matrix
;
1116 m4x3_identity( identity_matrix
);
1118 shader_scene_depth_use();
1119 shader_scene_depth_uCamera( cam
->transform
[3] );
1120 shader_scene_depth_uPv( cam
->mtx
.pv
);
1121 shader_scene_depth_uPvmPrev( cam
->mtx_prev
.pv
);
1122 shader_scene_depth_uMdl( identity_matrix
);
1123 world_link_lighting_ub( world
, _shader_scene_depth
.id
);
1125 mesh_bind( &world
->mesh_geo
);
1126 mesh_draw( &world
->mesh_geo
);
1129 static void render_world_position( world_instance
*world
, camera
*cam
){
1130 m4x3f identity_matrix
;
1131 m4x3_identity( identity_matrix
);
1133 shader_scene_position_use();
1134 shader_scene_position_uCamera( cam
->transform
[3] );
1135 shader_scene_position_uPv( cam
->mtx
.pv
);
1136 shader_scene_position_uPvmPrev( cam
->mtx_prev
.pv
);
1137 shader_scene_position_uMdl( identity_matrix
);
1138 world_link_lighting_ub( world
, _shader_scene_position
.id
);
1140 mesh_bind( &world
->mesh_geo
);
1141 mesh_draw( &world
->mesh_geo
);