medfall

A super great game engine
Log | Files | Refs

commit c49225111e461c25dd540ae8dad71b5c4f0e7b1d
parent 9445e376c611796aa96fa3c28e08cd63a6cfca75
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Fri May 12 03:07:32 +0300

Split shaders into their own files and add shader hotloading

Diffstat:
bsp.cc | 72+++---------------------------------------------------------------------
game.h | 4----
hm.cc | 84++++++++++++++------------------------------------------------------------------
main.cc | 7+++++++
make.lua | 2+-
renderer.cc | 62++++++++++++++++++++++++++++++++------------------------------
renderer.h | 7++++---
shaders.cc | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
shaders.h | 21+++++++++++++++++++++
shaders/flat_textured.glsl | 29+++++++++++++++++++++++++++++
shaders/flat_vertex_colours.glsl | 28++++++++++++++++++++++++++++
shaders/shit.glsl | 23+++++++++++++++++++++++
shaders/skybox.glsl | 40++++++++++++++++++++++++++++++++++++++++
shaders/terrain.glsl | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
shaders/text.glsl | 38++++++++++++++++++++++++++++++++++++++
shaders/tree.glsl | 27+++++++++++++++++++++++++++
skybox.cc | 45+++------------------------------------------
skybox.h | 1-
terrain_manager.cc | 111+++----------------------------------------------------------------------------
terrain_manager.h | 1-
text_renderer.cc | 46++--------------------------------------------
21 files changed, 465 insertions(+), 373 deletions(-)
diff --git a/bsp.cc b/bsp.cc @@ -5,6 +5,7 @@ #include "intrinsics.h" #include "log.h" #include "renderer.h" +#include "shaders.h" #include "bsp.h" #include "bsp_renderer.h" #include "text_renderer.h" @@ -16,61 +17,6 @@ static bool fix = false; static v3 fix_start; static v3 fix_end; -static const char * vert_src = GLSL( - in vec3 position; - in vec3 colour; - - out vec3 frag_colour; - - layout( std140 ) uniform v_hot { - mat4 V; - mat4 P; - }; - - void main() { - gl_Position = P * V * vec4( position, 1.0 ); - frag_colour = colour; - } -); - -static const char * frag_src = GLSL( - in vec3 frag_colour; - - out vec4 screen_colour; - - void main() { - screen_colour = vec4( frag_colour, 1.0 ); - } -); - -static const char * textured_vert_src = GLSL( - in vec3 position; - in vec4 colour; - in vec2 tex_coord0; - - out vec4 frag_colour; - out vec2 frag_uv; - - void main() { - gl_Position = vec4( position, 1.0 ); - frag_colour = colour; - frag_uv = tex_coord0; - } -); - -static const char * textured_frag_src = GLSL( - in vec4 frag_colour; - in vec2 frag_uv; - - uniform sampler2D tex; - - out vec4 screen_colour; - - void main() { - screen_colour = texture( tex, frag_uv ) * frag_colour; - } -); - static const float EPSILON = 1.0 / 32.0; // TODO: bit twiddling? @@ -301,7 +247,6 @@ BSP_Leaf & BSP::position_to_leaf( v3 pos ) const { } static UB test_ub; -static Shader texture_shader; extern "C" GAME_INIT( game_init ) { bsp_init( &game->bsp, "acidwdm2.bsp" ); @@ -312,17 +257,6 @@ extern "C" GAME_INIT( game_init ) { game->pitch = 0; game->yaw = 0; - game->test_shader = renderer_new_shader( vert_src, frag_src ); - - { - ShaderConfig config; - config.vertex_src = textured_vert_src; - config.fragment_src = textured_frag_src; - config.texture_uniform_names[ 0 ] = "tex"; - - texture_shader = renderer_new_shader( config ); - } - bspr_init( &game->bspr, &arena, &game->bsp ); test_ub = renderer_new_ub(); @@ -362,7 +296,7 @@ extern "C" GAME_FRAME( game_frame ) { renderer_ub_data( test_ub, &fsdata, sizeof( fsdata ) ); RenderState render_state; - render_state.shader = game->test_shader; + render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); render_state.ubs[ UB_VS_HOT ] = test_ub; bspr_render( &game->bspr, game->pos, render_state ); @@ -385,7 +319,7 @@ extern "C" GAME_FRAME( game_frame ) { } RenderState immediate_render_state; - immediate_render_state.shader = game->test_shader; + render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); immediate_render_state.ubs[ UB_VS_HOT ] = test_ub; immediate_render( &imm, immediate_render_state ); diff --git a/game.h b/game.h @@ -3,7 +3,6 @@ // TODO: this whole file blows #include "intrinsics.h" #include "linear_algebra.h" -#include "renderer.h" #include "terrain_manager.h" #include "btt.h" #include "gpubtt.h" @@ -38,9 +37,6 @@ struct GameState { WorkQueue background_tasks; - Shader test_shader; - Shader test_outline_shader; - Skybox skybox; float test_sun; diff --git a/hm.cc b/hm.cc @@ -8,6 +8,8 @@ #include "terrain_manager.h" #include "linear_algebra.h" #include "skybox.h" +#include "renderer.h" +#include "shaders.h" #include "text_renderer.h" #include "pool.h" #include "hashtable.h" @@ -17,54 +19,6 @@ #include "platform_io.h" #include "platform_network.h" -static const char * vert_src = GLSL( - in vec3 position; - in vec4 colour; - - out vec4 frag_colour; - - void main() { - gl_Position = vec4( position, 1.0 ); - frag_colour = colour; - } -); - -static const char * frag_src = GLSL( - in vec4 frag_colour; - - out vec4 screen_colour; - - void main() { - screen_colour = frag_colour; - } -); - -static const char * vert_outline_src = GLSL( - in vec3 position; - in vec3 colour; - - out vec3 frag_colour; - - layout( std140 ) uniform v_hot { - mat4 vp; - }; - - void main() { - frag_colour = colour; - gl_Position = vp * vec4( position, 1.0 ); - } -); - -static const char * frag_outline_src = GLSL( - in vec3 frag_colour; - - out vec4 screen_colour; - - void main() { - screen_colour = vec4( frag_colour, 1.0 ); - } -); - static v3 angles_to_vector( v3 angles ) { return v3( -sin( angles.y ) * sin( angles.x ), @@ -77,8 +31,6 @@ static v3 angles_to_vector_xy( v3 angles ) { return v3( sin( angles.y ), cos( angles.y ), 0 ); } -static UB ub_sphere; - static Socket sock; static u64 sid; static double last_connection_attempt = -5.0; // TODO @@ -95,11 +47,6 @@ extern "C" GAME_INIT( game_init ) { terrain_init( &game->tm, "terrains/gta.png.parts", &mem->persistent_arena, &game->background_tasks ); terrain_teleport( &game->tm, game->pos ); - game->test_shader = renderer_new_shader( vert_src, frag_src ); - - game->test_outline_shader = renderer_new_shader( vert_outline_src, frag_outline_src ); - ub_sphere = renderer_new_ub(); - game->test_sun = 0.3f; const size_t triangles = 65536; @@ -227,8 +174,11 @@ extern "C" GAME_FRAME( game_frame ) { skybox_render( &game->skybox, Vsky, P, game->test_sun ); terrain_render( &game->tm, V, P, game->test_sun, current_time ); + struct { m4 V; m4 P; } uniforms = { V, P }; + renderer_ub_data( tree_uniforms, &uniforms, sizeof( uniforms ) ); + RenderState immediate_render_state; - immediate_render_state.shader = game->test_shader; + immediate_render_state.shader = get_shader( SHADER_SHIT ); immediate_render_state.depth_func = DEPTHFUNC_DISABLED; immediate_render( &game->test_immediate, immediate_render_state ); @@ -245,12 +195,9 @@ extern "C" GAME_FRAME( game_frame ) { immediate_arrow( &imm, impact, normal, 16, v4( 1, 0, 0, 1 ) ); } - m4 VP = P * V; - renderer_ub_data( ub_sphere, &VP, sizeof( VP ) ); - RenderState impact_render_state; - impact_render_state.shader = game->test_outline_shader; - impact_render_state.ubs[ UB_VS_HOT ] = ub_sphere; + impact_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); + impact_render_state.ubs[ UB_VS_HOT ] = tree_uniforms; immediate_render( &imm, impact_render_state ); } @@ -288,8 +235,8 @@ extern "C" GAME_FRAME( game_frame ) { } RenderState fireball_render_state; - fireball_render_state.shader = game->test_outline_shader; - fireball_render_state.ubs[ UB_VS_HOT ] = ub_sphere; + fireball_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); + fireball_render_state.ubs[ UB_VS_HOT ] = tree_uniforms; immediate_render( &imm, fireball_render_state ); immediate_init( &imm, asdf, ARRAY_COUNT( asdf ) ); @@ -305,8 +252,8 @@ extern "C" GAME_FRAME( game_frame ) { } RenderState explosion_render_state; - explosion_render_state.shader = game->test_outline_shader; - explosion_render_state.ubs[ UB_VS_HOT ] = ub_sphere; + explosion_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); + explosion_render_state.ubs[ UB_VS_HOT ] = tree_uniforms; immediate_render( &imm, explosion_render_state ); } @@ -407,12 +354,9 @@ extern "C" GAME_FRAME( game_frame ) { } } - m4 VP = V * P; - renderer_ub_data( ub_sphere, &VP, sizeof( VP ) ); - RenderState impact_render_state; - impact_render_state.shader = game->test_outline_shader; - impact_render_state.ubs[ UB_VS_HOT ] = ub_sphere; + impact_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); + impact_render_state.ubs[ UB_VS_HOT ] = tree_uniforms; immediate_render( &imm, impact_render_state ); } diff --git a/main.cc b/main.cc @@ -8,6 +8,7 @@ #include "gl.h" #include "keys.h" #include "work_queue.h" +#include "shaders.h" #include "text_renderer.h" #define GLFW_INCLUDE_NONE @@ -40,6 +41,7 @@ int main( int argc, char ** argv ) { mem.state = &state; GLFWwindow * window = gl_init(); + shaders_init(); text_renderer_init(); workqueue_init( &state.background_tasks, &mem.persistent_arena, 2 ); game_init( &state, &mem ); @@ -94,6 +96,10 @@ int main( int argc, char ** argv ) { last_xpos = xpos; last_ypos = ypos; + if( total_frames % 60 == 0 ) { + hotload_shaders(); + } + game_frame( &state, &mem, &input, current_frame_time, dt ); glfwSwapBuffers( window ); @@ -112,6 +118,7 @@ int main( int argc, char ** argv ) { workqueue_term( &state.background_tasks ); text_renderer_term(); + shaders_term(); gl_term(); printf( "FPS: %.1f\n", total_frames / program_run_time ); diff --git a/make.lua b/make.lua @@ -1,7 +1,7 @@ require( "scripts.gen_makefile" ) local common_objs = { "memory_arena", "log", "ggformat", "strlcpy", "strlcat", "strtonum", "profiler", "stats", "rng/well512" } -local game_objs = { "work_queue", "renderer", "gl", "glad", "immediate", "text_renderer", "stb_truetype", common_objs } +local game_objs = { "work_queue", "renderer", "shaders", "gl", "glad", "immediate", "text_renderer", "stb_truetype", common_objs } local game_libs = { "glfw", "tinyobjloader" } bin( "medfall", { "main", "hm", "heightmap", "terrain_manager", "lz4", "btt", "gpubtt", "skybox", "http", game_objs }, { game_libs } ) diff --git a/renderer.cc b/renderer.cc @@ -176,36 +176,41 @@ void renderer_delete_tb( TB tb ) { } static GLuint new_gl_shader( GLenum type, const char * src ) { + const char * srcs[] = { + "#version 330\n", + type == GL_VERTEX_SHADER ? "#define VERTEX_SHADER 1\n" : "#define FRAGMENT_SHADER 1\n", + src + }; + GLuint shader = glCreateShader( type ); - glShaderSource( shader, 1, &src, NULL ); + glShaderSource( shader, ARRAY_COUNT( srcs ), srcs, NULL ); glCompileShader( shader ); GLint status; glGetShaderiv( shader, GL_COMPILE_STATUS, &status ); if( status == GL_FALSE ) { - WARN( "shader compilation failed" ); - GLint len; - glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &len ); - - char * buf = ( char * ) malloc( len ); - if( buf == NULL ) { - FATAL( "and so did malloc" ); - } - glGetShaderInfoLog( shader, len, NULL, buf ); + char buf[ 1024 ]; + glGetShaderInfoLog( shader, sizeof( buf ), NULL, buf ); + WARN( "shader compilation failed: {}", buf ); - FATAL( "{}", buf ); + return INVALID_SHADER; } return shader; } Shader renderer_new_shader( ShaderConfig config ) { - ASSERT( config.vertex_src != NULL ); - ASSERT( config.fragment_src != NULL ); + ASSERT( config.src != NULL ); - GLuint vs = new_gl_shader( GL_VERTEX_SHADER, config.vertex_src ); - GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, config.fragment_src ); + GLuint vs = new_gl_shader( GL_VERTEX_SHADER, config.src ); + GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, config.src ); + + if( vs == 0 || fs == 0 ) { + if( vs != 0 ) glDeleteShader( vs ); + if( fs != 0 ) glDeleteShader( fs ); + return INVALID_SHADER; + } GLuint program = glCreateProgram(); glAttachShader( program, vs ); @@ -225,17 +230,11 @@ Shader renderer_new_shader( ShaderConfig config ) { GLint status; glGetProgramiv( program, GL_LINK_STATUS, &status ); if( status == GL_FALSE ) { - WARN( "shader linking failed" ); - GLint len; - glGetProgramiv( program, GL_INFO_LOG_LENGTH, &len ); - - char * buf = ( char * ) malloc( len ); - if( buf == NULL ) { - FATAL( "and so did malloc" ); - } - glGetProgramInfoLog( program, len, NULL, buf ); + char buf[ 1024 ]; + glGetProgramInfoLog( program, sizeof( buf ), NULL, buf ); + WARN( "shader linking failed: {}", buf ); - FATAL( "{}", buf ); + return INVALID_SHADER; } const char * ubo_names[] = { "v_hot", "v_cold", "f_hot", "f_cold" }; @@ -252,7 +251,9 @@ Shader renderer_new_shader( ShaderConfig config ) { if( config.texture_uniform_names[ i ] != NULL ) { GLuint uniform = glGetUniformLocation( program, config.texture_uniform_names[ i ] ); if( uniform == GLuint( -1 ) ) { - FATAL( "couldn't find texture uniform: {}", config.texture_uniform_names[ i ] ); + WARN( "couldn't find texture uniform: {}", config.texture_uniform_names[ i ] ); + glDeleteProgram( program ); + return INVALID_SHADER; } glUniform1i( uniform, i ); } @@ -262,7 +263,9 @@ Shader renderer_new_shader( ShaderConfig config ) { if( config.texture_buffer_uniform_names[ i ] != NULL ) { GLuint uniform = glGetUniformLocation( program, config.texture_buffer_uniform_names[ i ] ); if( uniform == GLuint( -1 ) ) { - FATAL( "couldn't find texturebuffer uniform: {}", config.texture_buffer_uniform_names[ i ] ); + WARN( "couldn't find texturebuffer uniform: {}", config.texture_buffer_uniform_names[ i ] ); + glDeleteProgram( program ); + return INVALID_SHADER; } glUniform1i( uniform, i + RENDERER_MAX_TEXTURES ); } @@ -272,10 +275,9 @@ Shader renderer_new_shader( ShaderConfig config ) { return program; } -Shader renderer_new_shader( const char * vertex_src, const char * fragment_src ) { +Shader renderer_new_shader( const char * src ) { ShaderConfig config; - config.vertex_src = vertex_src; - config.fragment_src = fragment_src; + config.src = src; return renderer_new_shader( config ); } diff --git a/renderer.h b/renderer.h @@ -20,6 +20,8 @@ const u32 UB_VS_COLD = 1; const u32 UB_FS_HOT = 2; const u32 UB_FS_COLD = 3; +const u32 INVALID_SHADER = 0; + enum CullFace { CULLFACE_BACK, CULLFACE_FRONT, @@ -113,8 +115,7 @@ struct MeshConfig { }; struct ShaderConfig { - const char * vertex_src = NULL; - const char * fragment_src = NULL; + const char * src = NULL; const char * texture_uniform_names[ RENDERER_MAX_TEXTURES ] = { }; const char * texture_buffer_uniform_names[ RENDERER_MAX_TEXTURE_BUFFERS ] = { }; }; @@ -161,7 +162,7 @@ void renderer_ub_data( UB ub, const void * data, u32 len ); void renderer_tb_data( TB tb, const void * data, u32 len, BufferUsage usage = BUFFERUSAGE_DYNAMIC ); Shader renderer_new_shader( ShaderConfig config ); -Shader renderer_new_shader( const char * vertex_src, const char * fragment_src ); +Shader renderer_new_shader( const char * src ); void renderer_delete_shader( Shader shader ); Texture renderer_new_texture( TextureConfig config ); diff --git a/shaders.cc b/shaders.cc @@ -0,0 +1,92 @@ +#include "intrinsics.h" +#include "array.h" +#include "renderer.h" +#include "shaders.h" + +struct HotloadShader { + const char * path = NULL; + Shader shader = 0; + time_t last_modified = 0; + const char * texture_uniform_names[ RENDERER_MAX_TEXTURES ] = { }; + const char * texture_buffer_uniform_names[ RENDERER_MAX_TEXTURE_BUFFERS ] = { }; +}; + +StaticArray< HotloadShader, SHADER_COUNT > shaders; + +static time_t file_last_write_time( const char * path ) { + struct stat buf; + if( stat( path, &buf ) == -1 ) { + return 0; + } + + return buf.st_mtime; +} + +void shaders_init() { + shaders[ SHADER_TEXT ].path = "shaders/text.glsl"; + shaders[ SHADER_TEXT ].texture_uniform_names[ 0 ] = "atlas"; + + shaders[ SHADER_SKYBOX ].path = "shaders/skybox.glsl"; + + shaders[ SHADER_FLAT_VERTEX_COLOURS ].path = "shaders/flat_vertex_colours.glsl"; + + shaders[ SHADER_FLAT_TEXTURED ].path = "shaders/flat_textured.glsl"; + shaders[ SHADER_FLAT_TEXTURED ].texture_uniform_names[ 0 ] = "tex"; + + shaders[ SHADER_SHIT ].path = "shaders/shit.glsl"; + + shaders[ SHADER_TREE ].path = "shaders/tree.glsl"; + + shaders[ SHADER_TERRAIN ].path = "shaders/terrain.glsl"; + shaders[ SHADER_TERRAIN ].texture_uniform_names[ 0 ] = "normals"; + shaders[ SHADER_TERRAIN ].texture_uniform_names[ 1 ] = "horizons"; + shaders[ SHADER_TERRAIN ].texture_buffer_uniform_names[ 0 ] = "point_light_origins"; + shaders[ SHADER_TERRAIN ].texture_buffer_uniform_names[ 1 ] = "point_light_colours"; + + int failed = hotload_shaders(); + if( failed != 0 ) FATAL( "failed to load shaders" ); +} + +Shader get_shader( ShaderID id ) { + return shaders[ id ].shader; +} + +void shaders_term() { + for( HotloadShader & shader : shaders ) { + if( shader.shader != INVALID_SHADER ) { + renderer_delete_shader( shader.shader ); + } + } +} + +int hotload_shaders() { + int failed = 0; + for( HotloadShader & shader : shaders ) { + if( shader.path == NULL ) continue; + + time_t t = file_last_write_time( shader.path ); + if( t > shader.last_modified ) { + INFO( "loading {}", shader.path ); + char * contents = ( char * ) file_get_contents( shader.path ); + + ShaderConfig shader_config; + shader_config.src = contents; + memcpy( shader_config.texture_uniform_names, shader.texture_uniform_names, sizeof( shader.texture_uniform_names ) ); + memcpy( shader_config.texture_buffer_uniform_names, shader.texture_buffer_uniform_names, sizeof( shader.texture_buffer_uniform_names ) ); + Shader new_shader = renderer_new_shader( shader_config ); + + if( new_shader != INVALID_SHADER ) { + renderer_delete_shader( shader.shader ); + shader.shader = new_shader; + } + else { + failed++; + } + + shader.last_modified = t; + + free( contents ); + } + } + return failed; +} diff --git a/shaders.h b/shaders.h @@ -0,0 +1,21 @@ +#pragma once + +#include "renderer.h" + +enum ShaderID { + SHADER_TEXT, + SHADER_SKYBOX, + SHADER_FLAT_VERTEX_COLOURS, + SHADER_FLAT_TEXTURED, + SHADER_SHIT, + SHADER_TREE, + SHADER_TERRAIN, + + SHADER_COUNT, +}; + +void shaders_init(); +Shader get_shader( ShaderID id ); +void shaders_term(); + +int hotload_shaders(); diff --git a/shaders/flat_textured.glsl b/shaders/flat_textured.glsl @@ -0,0 +1,29 @@ +#if VERTEX_SHADER + +in vec3 position; +in vec4 colour; +in vec2 tex_coord0; + +out vec4 frag_colour; +out vec2 frag_uv; + +void main() { + gl_Position = vec4( position, 1.0 ); + frag_colour = colour; + frag_uv = tex_coord0; +} + +#else + +in vec4 frag_colour; +in vec2 frag_uv; + +uniform sampler2D tex; + +out vec4 screen_colour; + +void main() { + screen_colour = texture( tex, frag_uv ) * frag_colour; +} + +#endif diff --git a/shaders/flat_vertex_colours.glsl b/shaders/flat_vertex_colours.glsl @@ -0,0 +1,28 @@ +#ifdef VERTEX_SHADER + +in vec3 position; +in vec3 colour; + +out vec3 frag_colour; + +layout( std140 ) uniform v_hot { + mat4 V; + mat4 P; +}; + +void main() { + gl_Position = P * V * vec4( position, 1.0 ); + frag_colour = colour; +} + +#else + +in vec3 frag_colour; + +out vec4 screen_colour; + +void main() { + screen_colour = vec4( frag_colour, 1.0 ); +} + +#endif diff --git a/shaders/shit.glsl b/shaders/shit.glsl @@ -0,0 +1,23 @@ +#ifdef VERTEX_SHADER + +in vec3 position; +in vec3 colour; + +out vec3 frag_colour; + +void main() { + gl_Position = vec4( position, 1.0 ); + frag_colour = colour; +} + +#else + +in vec3 frag_colour; + +out vec4 screen_colour; + +void main() { + screen_colour = vec4( frag_colour, 1.0 ); +} + +#endif diff --git a/shaders/skybox.glsl b/shaders/skybox.glsl @@ -0,0 +1,40 @@ +#if VERTEX_SHADER + +in vec3 position; +out vec3 pos; + +layout( std140 ) uniform v_hot { + mat4 V; + mat4 P; +}; + +void main() { + gl_Position = P * V * vec4( position, 1.0 ); + pos = position; +} + +#else + +in vec3 pos; +out vec4 colour; + +layout( std140 ) uniform f_hot { + float sun; +}; + +void main() { + vec3 sun_direction = normalize( vec3( -1, 0, sun ) ); + + vec4 horizon = vec4( 0.4, 0.7, 1.0, 1.0 ); + vec4 top = vec4( 0.3, 0.6, 1.0, 1.0 ); + vec4 halo = vec4( 0.7, 0.8, 1.0, 1.0 ); + vec4 sunny = vec4( 0.9, 0.9, 0.2, 1.0 ); + + float scaled_z = smoothstep( 0.0, 0.2, pos.z ); + float sun_dot = smoothstep( 0.99, 1.0, dot( sun_direction, normalize( pos ) ) ); + float halo_dot = smoothstep( 0.9, 1.0, dot( sun_direction, normalize( pos ) ) ); + + colour = mix( mix( mix( horizon, top, scaled_z ), halo, halo_dot ), sunny, sun_dot ); +} + +#endif diff --git a/shaders/terrain.glsl b/shaders/terrain.glsl @@ -0,0 +1,98 @@ +struct VSOut { + vec4 view_position; + vec3 world_position; +}; + +#ifdef VERTEX_SHADER + +in vec3 position; +out VSOut v2f; + +layout( std140 ) uniform v_hot { + mat4 V; + mat4 P; +}; + +void main() { + v2f.world_position = position; + v2f.view_position = V * vec4( position, 1.0 ); + gl_Position = P * v2f.view_position; +} + +#else + +in VSOut v2f; +out vec4 colour; + +layout( std140 ) uniform f_hot { + vec2 dimensions; + float sun; +}; + +uniform sampler2D normals; +uniform sampler2D horizons; + +// uniform usamplerBuffer point_light_counts_and_offsets; +// uniform usamplerBuffer point_light_indices; +uniform samplerBuffer point_light_origins; +uniform samplerBuffer point_light_colours; + +void main() { + vec3 normal = normalize( texture( normals, v2f.world_position.xy / dimensions ).xyz ); + float horizon = texture( horizons, v2f.world_position.xy / dimensions ).r; + + // ground colour + vec3 ground; + if( v2f.world_position.z > 175 ) { + // snow/rocks + if( normal.z > 0.5 ) { + ground = vec3( 0.8, 0.8, 0.8 ); + } + else { + ground = vec3( 0.6, 0.6, 0.6 ); + } + } + else if( v2f.world_position.z < 5 ) { + ground = vec3( 0.0, 0.25, 1.0 ); + } + else { + if( normal.z > 0.8 ) { + ground = vec3( 0.4, 1.0, 0.4 ); + } + else { + ground = vec3( 0.7, 0.7, 0.5 ); + } + } + + // sunlight + sky ambient lighting + // TODO: use formula for area of a chord? + float sun_visible_fraction = smoothstep( 0, 0.2, sun - horizon ); + vec3 sun_direction = normalize( vec3( -1, 0, sun ) ); + float sunlight_lambert = max( 0, dot( normal, sun_direction ) ); + vec3 sunlight = sun_visible_fraction * sunlight_lambert * vec3( 0.9, 0.9, 0.5 ); + vec3 ambient = vec3( 0.05, 0.05, 0.15 ); + + vec3 c = ( sunlight + ambient ) * ground; + + // lights + for( int i = 0; i < 5; i++ ) { + vec3 light_position = texelFetch( point_light_origins, i ).xyz; + vec3 light_colour = texelFetch( point_light_colours, i ).rgb; + float light_sqdistance = dot( light_position - v2f.world_position, light_position - v2f.world_position ); + vec3 light_direction = normalize( light_position - v2f.world_position ); + float lambert_scale = dot( light_direction, normal ); + float distance_scale = 1.0 / light_sqdistance; + c += vec3( light_colour * lambert_scale * distance_scale ) * ground; + } + + // fog + vec3 fog_colour = vec3( 0.5, 0.6, 0.7 ); + float fog_strength = 0.0005; + // don't draw any fog too close to the camera because the banding is quite noticable + float fog_distance_bias = 100.0; + float fog_t = 1.0 - exp( -fog_strength * max( ( length( v2f.view_position ) - fog_distance_bias ), 0.0 ) ); + + colour = vec4( mix( c, fog_colour, fog_t ), 1.0 ); +} + +#endif diff --git a/shaders/text.glsl b/shaders/text.glsl @@ -0,0 +1,38 @@ +struct VSOut { + vec4 colour; + vec2 uv; +}; + +#if VERTEX_SHADER + +in vec3 position; +in vec4 colour; +in vec2 tex_coord0; + +out VSOut v2f; + +void main() { + vec3 screen_position = vec3( + ( position.x / 1024.0 * 2.0 - 1.0 ), + -( position.y / 768.0 * 2.0 - 1.0 ), + position.z + ); + gl_Position = vec4( screen_position, 1.0 ); + v2f.colour = colour; + v2f.uv = tex_coord0; +} + +#else + +in VSOut v2f; + +uniform sampler2D atlas; + +out vec4 screen_colour; + +void main() { + float alpha = texture( atlas, v2f.uv ).r; + screen_colour = vec4( v2f.colour.rgb, v2f.colour.a * alpha ); +} + +#endif diff --git a/shaders/tree.glsl b/shaders/tree.glsl @@ -0,0 +1,27 @@ +#ifdef VERTEX_SHADER + +in vec3 position; + +out vec3 frag_colour; + +layout( std140 ) uniform v_hot { + mat4 V; + mat4 P; +}; + +void main() { + gl_Position = P * V * vec4( position, 1.0 ); + frag_colour = vec3( 0.4, 0.3, 0.0 ); +} + +#else + +in vec3 frag_colour; + +out vec4 screen_colour; + +void main() { + screen_colour = vec4( frag_colour, 1.0 ); +} + +#endif diff --git a/skybox.cc b/skybox.cc @@ -2,45 +2,8 @@ #include "game.h" #include "linear_algebra.h" #include "skybox.h" - -static const char * vert_src = GLSL( - in vec3 position; - out vec3 pos; - - layout( std140 ) uniform v_hot { - mat4 V; - mat4 P; - }; - - void main() { - gl_Position = P * V * vec4( position, 1.0 ); - pos = position; - } -); - -static const char * frag_src = GLSL( - in vec3 pos; - out vec4 colour; - - layout( std140 ) uniform f_hot { - float sun; - }; - - void main() { - vec3 sun_direction = normalize( vec3( -1, 0, sun ) ); - - vec4 horizon = vec4( 0.4, 0.7, 1.0, 1.0 ); - vec4 top = vec4( 0.3, 0.6, 1.0, 1.0 ); - vec4 halo = vec4( 0.7, 0.8, 1.0, 1.0 ); - vec4 sunny = vec4( 0.9, 0.9, 0.2, 1.0 ); - - float scaled_z = smoothstep( 0.0, 0.2, pos.z ); - float sun_dot = smoothstep( 0.99, 1.0, dot( sun_direction, normalize( pos ) ) ); - float halo_dot = smoothstep( 0.9, 1.0, dot( sun_direction, normalize( pos ) ) ); - - colour = mix( mix( mix( horizon, top, scaled_z ), halo, halo_dot ), sunny, sun_dot ); - } -); +#include "renderer.h" +#include "shaders.h" static const v3 cube_verts[] = { v3( -1.0f, 1.0f, 1.0f ), @@ -65,7 +28,6 @@ void skybox_init( Skybox * skybox ) { mesh_config.num_vertices = ARRAY_COUNT( cube_indices ); mesh_config.primitive_type = PRIMITIVETYPE_TRIANGLE_STRIP; - skybox->shader = renderer_new_shader( vert_src, frag_src ); skybox->mesh = renderer_new_mesh( mesh_config ); skybox->vertex_uniforms = renderer_new_ub(); skybox->fragment_uniforms = renderer_new_ub(); @@ -91,7 +53,7 @@ void skybox_render( const Skybox * skybox, const m4 & V, const m4 & P, float sun renderer_ub_data( skybox->fragment_uniforms, &fsdata, sizeof( fsdata ) ); RenderState render_state; - render_state.shader = skybox->shader; + render_state.shader = get_shader( SHADER_SKYBOX ); render_state.cull_face = CULLFACE_FRONT; render_state.disable_depth_writes = true; render_state.ubs[ UB_VS_HOT ] = skybox->vertex_uniforms; @@ -102,7 +64,6 @@ void skybox_render( const Skybox * skybox, const m4 & V, const m4 & P, float sun void skybox_destroy( Skybox * skybox ) { renderer_delete_mesh( skybox->mesh ); - renderer_delete_shader( skybox->shader ); renderer_delete_ub( skybox->vertex_uniforms ); renderer_delete_ub( skybox->fragment_uniforms ); } diff --git a/skybox.h b/skybox.h @@ -4,7 +4,6 @@ #include "renderer.h" struct Skybox { - Shader shader; Mesh mesh; UB vertex_uniforms; UB fragment_uniforms; diff --git a/terrain_manager.cc b/terrain_manager.cc @@ -13,105 +13,11 @@ #include "str.h" #include "nonblocking_fixed_mpsc_queue.h" #include "profiler.h" +#include "renderer.h" +#include "shaders.h" #include "lz4.h" -static const char * vert_src = GLSL( - in vec3 position; - - out vec4 vpos; - out vec3 smooth_position; - - layout( std140 ) uniform v_hot { - mat4 V; - mat4 P; - }; - - void main() { - gl_Position = P * V * vec4( position, 1.0 ); - smooth_position = position; - vpos = V * vec4( position, 1.0 ); - } -); - -static const char * frag_src = GLSL( - in vec4 vpos; - in vec3 smooth_position; - - out vec4 colour; - - layout( std140 ) uniform f_hot { - vec2 dimensions; - float sun; - }; - - uniform sampler2D normals; - uniform sampler2D horizons; - - // uniform usamplerBuffer point_light_counts_and_offsets; - // uniform usamplerBuffer point_light_indices; - uniform samplerBuffer point_light_origins; - uniform samplerBuffer point_light_colours; - - void main() { - vec3 normal = normalize( texture( normals, smooth_position.xy / dimensions ).xyz ); - float horizon = texture( horizons, smooth_position.xy / dimensions ).r; - - // ground colour - vec3 ground; - if( smooth_position.z > 175 ) { - // snow/rocks - if( normal.z > 0.5 ) { - ground = vec3( 0.8, 0.8, 0.8 ); - } - else { - ground = vec3( 0.6, 0.6, 0.6 ); - } - } - else if( smooth_position.z < 5 ) { - ground = vec3( 0.0, 0.25, 1.0 ); - } - else { - if( normal.z > 0.8 ) { - ground = vec3( 0.4, 1.0, 0.4 ); - } - else { - ground = vec3( 0.7, 0.7, 0.5 ); - } - } - - // sunlight + sky ambient lighting - // TODO: use formula for area of a chord? - float sun_visible_fraction = smoothstep( 0, 0.2, sun - horizon ); - vec3 sun_direction = normalize( vec3( -1, 0, sun ) ); - float sunlight_lambert = max( 0, dot( normal, sun_direction ) ); - vec3 sunlight = sun_visible_fraction * sunlight_lambert * vec3( 0.9, 0.9, 0.5 ); - vec3 ambient = vec3( 0.05, 0.05, 0.15 ); - - vec3 c = ( sunlight + ambient ) * ground; - - // lights - for( int i = 0; i < 5; i++ ) { - vec3 light_position = texelFetch( point_light_origins, i ).xyz; - vec3 light_colour = texelFetch( point_light_colours, i ).rgb; - float light_sqdistance = dot( light_position - smooth_position, light_position - smooth_position ); - vec3 light_direction = normalize( light_position - smooth_position ); - float lambert_scale = dot( light_direction, normal ); - float distance_scale = 1.0 / light_sqdistance; - c += vec3( light_colour * lambert_scale * distance_scale ) * ground; - } - - // fog - vec3 fog_colour = vec3( 0.5, 0.6, 0.7 ); - float fog_strength = 0.0005; - // don't draw any fog too close to the camera because the banding is quite noticable - float fog_distance_bias = 100.0; - float fog_t = 1.0 - exp( -fog_strength * max( ( length( vpos ) - fog_distance_bias ), 0.0 ) ); - - colour = vec4( mix( c, fog_colour, fog_t ), 1.0 ); - } -); - struct AsyncLoadTile { TerrainManager * tm; s32 tx, ty; @@ -270,17 +176,6 @@ void terrain_init( } } - { - ShaderConfig config; - config.vertex_src = vert_src; - config.fragment_src = frag_src; - config.texture_uniform_names[ 0 ] = "normals"; - config.texture_uniform_names[ 1 ] = "horizons"; - config.texture_buffer_uniform_names[ 0 ] = "point_light_origins"; - config.texture_buffer_uniform_names[ 1 ] = "point_light_colours"; - tm->shader = renderer_new_shader( config ); - } - tm->vertex_uniforms = renderer_new_ub(); tm->fragment_uniforms = renderer_new_ub(); tm->point_light_origins = renderer_new_tb( TEXFMT_RGB_FLOAT ); @@ -432,7 +327,7 @@ void terrain_render( TerrainManager * tm, const m4 & V, const m4 & P, float sun, /* end lighting */ RenderState render_state; - render_state.shader = tm->shader; + render_state.shader = get_shader( SHADER_TERRAIN ); render_state.ubs[ UB_VS_HOT ] = tm->vertex_uniforms; render_state.ubs[ UB_FS_HOT ] = tm->fragment_uniforms; render_state.tbs[ 0 ] = tm->point_light_origins; diff --git a/terrain_manager.h b/terrain_manager.h @@ -52,7 +52,6 @@ struct TerrainManager { u32 width, height; - Shader shader; UB vertex_uniforms; UB fragment_uniforms; TB point_light_origins; diff --git a/text_renderer.cc b/text_renderer.cc @@ -1,43 +1,10 @@ #include "intrinsics.h" #include "immediate.h" #include "renderer.h" +#include "shaders.h" #include "linear_algebra.h" #include "stb_truetype.h" -static const char * vert_src = GLSL( - in vec3 position; - in vec4 colour; - in vec2 tex_coord0; - - out vec4 frag_colour; - out vec2 frag_uv; - - void main() { - vec3 screen_position = vec3( - ( position.x / 1024.0 * 2.0 - 1.0 ), - -( position.y / 768.0 * 2.0 - 1.0 ), - position.z - ); - gl_Position = vec4( screen_position, 1.0 ); - frag_colour = colour; - frag_uv = tex_coord0; - } -); - -static const char * frag_src = GLSL( - in vec4 frag_colour; - in vec2 frag_uv; - - uniform sampler2D atlas; - - out vec4 screen_colour; - - void main() { - float alpha = texture( atlas, frag_uv ).r; - screen_colour = vec4( frag_colour.rgb, frag_colour.a * alpha ); - } -); - struct FontSize { float pixel_size; float ascent; @@ -51,8 +18,6 @@ static stbtt_fontinfo font_info; static const float pixel_sizes[] = { 16.0f, 32.0f, 48.0f }; static FontSize sizes[ ARRAY_COUNT( pixel_sizes ) ]; -static Shader shader; - void text_renderer_init() { ttf = file_get_contents( "LiberationSans-Regular.ttf" ); @@ -87,12 +52,6 @@ void text_renderer_init() { sizes[ i ].ascent = ascent * scale; sizes[ i ].atlas = renderer_new_texture( texture_config ); } - - ShaderConfig shader_config; - shader_config.vertex_src = vert_src; - shader_config.fragment_src = frag_src; - shader_config.texture_uniform_names[ 0 ] = "atlas"; - shader = renderer_new_shader( shader_config ); } static ImmediateTriangle triangles[ 4096 ]; @@ -152,7 +111,7 @@ void draw_text( const char * str, float x, float y, float pixel_size ) { } RenderState render_state; - render_state.shader = shader; + render_state.shader = get_shader( SHADER_TEXT ); render_state.textures[ 0 ] = sizes[ size_idx ].atlas; render_state.depth_func = DEPTHFUNC_DISABLED; render_state.enable_alpha_blending = true; @@ -163,7 +122,6 @@ void draw_text( const char * str, float x, float y, float pixel_size ) { void text_renderer_term() { free( ttf ); - renderer_delete_shader( shader ); for( size_t i = 0; i < ARRAY_COUNT( sizes ); i++ ) { renderer_delete_texture( sizes[ i ].atlas ); }