fullscreen.cc (6558B)
1 #include "game.h" 2 #include "intrinsics.h" 3 #include "linear_algebra.h" 4 #include "gl.h" 5 #include "renderer.h" 6 #include "shaders.h" 7 #include "immediate.h" 8 #include "text_renderer.h" 9 #include "log.h" 10 #include "obj.h" 11 12 static Mesh square; 13 static FB shadow_fb; 14 static FB gbuffer; 15 static Mesh tree_mesh; 16 17 static const u32 SHADOW_SIZE = 1024; 18 19 static v3 light_pos( -0, -10, 15 ); 20 static v3 light_dir = v3_forward( -60, 90 ); 21 22 static void draw_scene( RenderState render_state, bool draw_light = false ) { 23 m4 I = m4_identity(); 24 render_state.set_uniform( "model", renderer_uniforms( I ) ); 25 26 immediate_sphere( v3( 0, 0, 2 ), 2, v4( 1, 0, 0, 1 ) ); 27 immediate_sphere( v3( -3, 7, 2 ), 2, v4( 0, 1, 0, 1 ) ); 28 29 immediate_aabb( v3( 3, 3, 0 ), v3( 5, 5, 2 ), v4( 0, 0, 1, 1 ) ); 30 immediate_aabb( v3( 3, 0, 0 ), v3( 5, 2, 2 ), v4( 0, 0, 1, 1 ) ); 31 immediate_aabb( v3( 3, -3, 0 ), v3( 5, -1, 2 ), v4( 0, 0, 1, 1 ) ); 32 immediate_aabb( v3( 3, -6, 0 ), v3( 5, -4, 2 ), v4( 0, 0, 1, 1 ) ); 33 34 if( draw_light ) { 35 immediate_sphere( light_pos, 0.1f, v4( 1, 1, 1, 1 ) ); 36 immediate_arrow( light_pos, light_dir, 0.5f, v4( 1, 1, 1, 1 ) ); 37 } 38 39 v3 tl( -50, 50, 0 ); 40 v3 tr( 50, 50, 0 ); 41 v3 bl( -50, -50, 0 ); 42 v3 br( 50, -50, 0 ); 43 immediate_triangle( tr, tl, bl, v4( 0.5, 0.5, 0.5, 1.0 ) ); 44 immediate_triangle( bl, br, tr, v4( 0.5, 0.5, 0.5, 1.0 ) ); 45 46 immediate_render( render_state ); 47 48 m4 M = m4_translation( v3( -7, -2, 0 ) ) * m4_rotx( deg_to_rad( 90 ) ); 49 render_state.set_uniform( "model", renderer_uniforms( M ) ); 50 renderer_draw_mesh( tree_mesh, render_state ); 51 } 52 53 GAME_INIT( game_init ) { 54 { 55 TextureConfig config; 56 config.width = SHADOW_SIZE; 57 config.height = SHADOW_SIZE; 58 config.format = TEXFMT_DEPTH; 59 config.wrap = TEXWRAP_BORDER; 60 config.border_colour = v4( 1, 1, 1, 1 ); 61 shadow_fb = renderer_new_fb( config, FB_DEPTH ); 62 } 63 64 gbuffer = { }; 65 66 game->pos = v3( -10, -10, 5 ); 67 game->pitch = 0; 68 game->yaw = 45; 69 70 { 71 float verts[] = { 72 -1.0f, -1.0f, 0.0f, 73 -0.8f, -1.0f, 0.0f, 74 -1.0f, -0.7f, 0.0f, 75 -0.8f, -0.7f, 0.0f, 76 }; 77 MeshConfig config; 78 config.positions = renderer_new_vb( verts, sizeof( verts ) ); 79 config.num_vertices = 4; 80 config.primitive_type = PRIMITIVETYPE_TRIANGLE_STRIP; 81 square = renderer_new_mesh( config ); 82 } 83 84 tree_mesh = load_obj( "models/trees/PineTree.obj", &mem->persistent_arena ); 85 } 86 87 static void recreate_framebuffers() { 88 renderer_delete_fb( gbuffer ); 89 90 v2u32 window_size = get_window_size(); 91 92 TextureConfig texture_config; 93 texture_config.width = window_size.x; 94 texture_config.height = window_size.y; 95 96 FramebufferConfig fb_config; 97 98 texture_config.format = TEXFMT_RGB_U8; 99 fb_config.textures[ OUTPUT_ALBEDO ].config = texture_config; 100 fb_config.textures[ OUTPUT_ALBEDO ].attachment = FB_COLOUR; 101 102 texture_config.format = TEXFMT_RGB_HALF; 103 fb_config.textures[ OUTPUT_NORMAL ].config = texture_config; 104 fb_config.textures[ OUTPUT_NORMAL ].attachment = FB_NORMAL; 105 106 texture_config.format = TEXFMT_DEPTH; 107 fb_config.textures[ OUTPUT_DEPTH ].config = texture_config; 108 fb_config.textures[ OUTPUT_DEPTH ].attachment = FB_DEPTH; 109 110 gbuffer = renderer_new_fb( fb_config ); 111 } 112 113 GAME_FRAME( game_frame ) { 114 if( input->resized ) { 115 recreate_framebuffers(); 116 } 117 118 const float speed = 6.0f; 119 const float angular_speed = 100.0f; 120 121 float fb = float( input->keys[ KEY_W ] - input->keys[ KEY_S ] ); 122 float lr = float( input->keys[ KEY_D ] - input->keys[ KEY_A ] ); 123 float dz = float( input->keys[ KEY_SPACE ] - input->keys[ KEY_LEFTSHIFT ] ); 124 125 float dpitch = float( input->keys[ KEY_DOWNARROW ] - input->keys[ KEY_UPARROW ] ); 126 float dyaw = float( input->keys[ KEY_LEFTARROW ] - input->keys[ KEY_RIGHTARROW ] ); 127 128 dpitch += input->keys[ KEY_K ] - input->keys[ KEY_I ]; 129 dyaw += input->keys[ KEY_J ] - input->keys[ KEY_L ]; 130 131 game->pitch += dpitch * dt * angular_speed; 132 game->yaw += dyaw * dt * angular_speed; 133 134 const v3 world_up = v3( 0, 0, 1 ); 135 v3 forward = v3_forward( game->pitch, game->yaw ); 136 v3 right = normalize( cross( forward, world_up ) ); 137 v3 up = normalize( cross( right, forward ) ); 138 139 game->pos += forward * dt * fb * speed; 140 game->pos += right * dt * lr * speed; 141 game->pos.z += dt * dz * speed; 142 143 const m4 P = m4_perspective( VERTICAL_FOV, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); 144 m4 V = m4_view( forward, right, up, game->pos ); 145 146 light_pos = v3( float( cos( current_time ) * 10 ), float( sin( current_time ) * 10 ), 10 ); 147 148 renderer_begin_frame(); 149 150 u8 shadowmap_pass = renderer_add_pass( "Write shadowmap", shadow_fb, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DO ); 151 u8 gbuffer_pass = renderer_add_pass( "Write gbuffer", gbuffer, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); 152 u8 compose_pass = renderer_add_pass( "Compose" ); 153 u8 ui_pass = renderer_add_pass( "Render UI" ); 154 155 UniformBinding light_view_uniforms; 156 157 { 158 m4 lightVP; 159 v3 target( 0, 0, 0 ); 160 light_dir = normalize( target - light_pos ); 161 const m4 lightP = m4_perspective( 90, 1, NEAR_PLANE_DEPTH, 500.0f ); 162 m4 lightV = m4_lookat( light_pos, target, world_up ); 163 164 light_view_uniforms = renderer_uniforms( lightP * lightV, light_pos ); 165 } 166 167 // fill shadow map 168 { 169 RenderState render_state; 170 render_state.pass = shadowmap_pass; 171 render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); 172 render_state.set_uniform( "light_view", light_view_uniforms ); 173 174 draw_scene( render_state ); 175 } 176 177 // fill gbuffers 178 { 179 RenderState render_state; 180 render_state.pass = gbuffer_pass; 181 render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ); 182 render_state.set_uniform( "view", renderer_uniforms( V, P, game->pos ) ); 183 render_state.set_uniform( "light_view", light_view_uniforms ); 184 render_state.set_texture( "shadowmap", shadow_fb.textures[ OUTPUT_DEPTH ] ); 185 render_state.set_texture( "dither_noise", renderer_blue_noise() ); 186 187 draw_scene( render_state, true ); 188 } 189 190 // final pass 191 { 192 RenderState render_state; 193 render_state.pass = compose_pass; 194 render_state.shader = get_shader( SHADER_GBUFFER ); 195 render_state.depth_func = DEPTHFUNC_DISABLED; 196 render_state.set_texture( "outline_depth", gbuffer.textures[ OUTPUT_ALBEDO ] ); 197 render_state.set_texture( "world_normal", gbuffer.textures[ OUTPUT_NORMAL ] ); 198 render_state.set_texture( "world_depth", gbuffer.textures[ OUTPUT_DEPTH ] ); 199 render_state.set_texture( "blue_noise", renderer_blue_noise() ); 200 201 renderer_draw_fullscreen_triangle( render_state ); 202 } 203 204 { 205 const str< 128 > status( "Frame time: {.1}ms FPS: {.1}", dt * 1000.0f, 1.0f / dt ); 206 draw_text( ui_pass, status.c_str(), 2, 2, 16 ); 207 } 208 209 renderer_end_frame(); 210 }