medfall

A super great game engine
Log | Files | Refs

commit 795f836126f2fed1cec1e4844aa7472c6e4ec758
parent 9569cab05acbab7265789a651a6db859f9e6be19
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Fri,  2 Aug 2019 17:01:45 +0300

Set uniforms/textures by name

Diffstat:
Mbsp.cc | 28++++++++++++++--------------
Mclipmap.cc | 54+++++++++++++++++++++++++++---------------------------
Mfnv.h | 10++++++++++
Mfullscreen.cc | 22+++++++++++-----------
Mgltf.cc | 11+++++------
Mimmediate.cc | 9+--------
Mimmediate.h | 1-
Mmake.lua | 4++--
Mmsdf.cc | 2+-
Mrenderer.cc | 177++++++++++++++++++++++++++++++-------------------------------------------------
Mrenderer.h | 92++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mshaders.cc | 43++++++++++---------------------------------
Mshaders.h | 2+-
Mshadow_map.cc | 16++++++++--------
Mskybox.cc | 6+++---
Mstringhash.h | 11+++--------
Mtext_renderer.cc | 4++--
17 files changed, 217 insertions(+), 275 deletions(-)

diff --git a/bsp.cc b/bsp.cc @@ -353,7 +353,7 @@ static v2 screen_pos( const m4 & P, const m4 & V, v3 camera_pos, v3 target, v2 c } GAME_INIT( game_init ) { - bsp_init( &game->bsp, "assets/cocaine_b2.bsp" ); + bsp_init( &game->bsp, "assets/acidwdm2.bsp" ); game->pos = v3( 0, -100, 450 ); game->pitch = 0; @@ -448,8 +448,8 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_MODEL ] = world_model_uniforms; + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "model", world_model_uniforms ); render_state.cull_face = CULLFACE_FRONT; bspr_render( &game->bspr, render_state ); @@ -475,7 +475,7 @@ GAME_FRAME( game_frame ) { // // immediate_render( render_state ); // - render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); renderer_end_pass(); @@ -492,8 +492,8 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); render_state.depth_func = DEPTHFUNC_ALWAYS; - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); @@ -507,7 +507,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_DEPTH_EDGE ); render_state.depth_func = DEPTHFUNC_ALWAYS; - render_state.textures[ 0 ] = model_depth.textures[ OUTPUT_DEPTH ]; + render_state.set_texture( "model_depth", model_depth.textures[ OUTPUT_DEPTH ] ); renderer_draw_fullscreen_triangle( render_state ); @@ -520,14 +520,14 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_GBUFFER ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_MODEL ] = world_model_uniforms; + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "model", world_model_uniforms ); render_state.cull_face = CULLFACE_FRONT; // render_state.depth_func = DEPTHFUNC_EQUAL; - render_state.textures[ 0 ] = world_depth_and_normals.textures[ OUTPUT_NORMAL ]; - render_state.textures[ 1 ] = world_depth_and_normals.textures[ OUTPUT_DEPTH ]; - render_state.textures[ 2 ] = model_depth_outline.textures[ OUTPUT_DEPTH ]; - render_state.textures[ 3 ] = renderer_blue_noise(); + render_state.set_texture( "world_normal", world_depth_and_normals.textures[ OUTPUT_NORMAL ] ); + render_state.set_texture( "world_depth", world_depth_and_normals.textures[ OUTPUT_DEPTH ] ); + render_state.set_texture( "outline_depth", model_depth_outline.textures[ OUTPUT_DEPTH ] ); + render_state.set_texture( "blue_noise", renderer_blue_noise() ); bspr_render( &game->bspr, render_state ); @@ -552,7 +552,7 @@ GAME_FRAME( game_frame ) { // // immediate_render( render_state ); - render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + render_state.set_uniform( "model", tree_model_uniforms ); renderer_draw_mesh( tree_mesh, render_state ); renderer_end_pass(); diff --git a/clipmap.cc b/clipmap.cc @@ -775,19 +775,19 @@ GAME_FRAME( game_frame ) { { RenderState render_state; render_state.shader = get_shader( SHADER_CLIPMAP ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_SUN ] = sun_uniforms; - render_state.textures[ 0 ] = clipmap.gpu.heightmap; - render_state.textures[ 1 ] = clipmap.gpu.normalmap; - render_state.textures[ 2 ] = clipmap.gpu.horizonmap; - render_state.textures[ 3 ] = renderer_blue_noise(); + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "sun", sun_uniforms ); + render_state.set_texture( "heightmap", clipmap.gpu.heightmap ); + render_state.set_texture( "normalmap", clipmap.gpu.normalmap ); + render_state.set_texture( "horizonmap", clipmap.gpu.horizonmap ); + render_state.set_texture( "blue_noise", renderer_blue_noise() ); render_state.wireframe = game->draw_wireframe; // draw cross { v2 snapped_pos = floorf( game->frozen_pos.xy() ); - render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; - render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( snapped_pos, 1.0f ); + render_state.set_uniform( "model", rotation_uniforms[ 0 ] ); + render_state.set_uniform( "clipmap", renderer_uniforms( snapped_pos, 1.0f ) ); renderer_draw_mesh( clipmap.gpu.cross, render_state ); } @@ -818,16 +818,16 @@ GAME_FRAME( game_frame ) { inside = false; Mesh mesh = inside ? clipmap.gpu.tile : clipmap.gpu.empty_tile; - render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; - render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale ); + render_state.set_uniform( "model", rotation_uniforms[ 0 ] ); + render_state.set_uniform( "clipmap", renderer_uniforms( tile_tl, scale ) ); renderer_draw_mesh( mesh, render_state ); } } // draw filler { - render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; - render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( snapped_pos, scale ); + render_state.set_uniform( "model", rotation_uniforms[ 0 ] ); + render_state.set_uniform( "clipmap", renderer_uniforms( snapped_pos, scale ) ); renderer_draw_mesh( clipmap.gpu.filler, render_state ); } @@ -844,8 +844,8 @@ GAME_FRAME( game_frame ) { r |= d.x >= scale ? 0 : 2; r |= d.y >= scale ? 0 : 1; - render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ r ]; - render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_centre, scale ); + render_state.set_uniform( "model", rotation_uniforms[ r ] ); + render_state.set_uniform( "clipmap", renderer_uniforms( tile_centre, scale ) ); renderer_draw_mesh( clipmap.gpu.trim, render_state ); } @@ -853,8 +853,8 @@ GAME_FRAME( game_frame ) { { v2 next_base = next_snapped_pos - v2( checked_cast< float >( TILE_RESOLUTION << ( l + 1 ) ) ); - render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; - render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( next_base, scale ); + render_state.set_uniform( "model", rotation_uniforms[ 0 ] ); + render_state.set_uniform( "clipmap", renderer_uniforms( next_base, scale ) ); renderer_draw_mesh( clipmap.gpu.seam, render_state ); } } @@ -867,10 +867,10 @@ GAME_FRAME( game_frame ) { RenderState skirt_render_state; skirt_render_state.shader = get_shader( SHADER_CLIPMAP_SKIRT ); - skirt_render_state.uniforms[ UNIFORMS_VIEW ] = inf_view_uniforms; - skirt_render_state.uniforms[ UNIFORMS_SUN ] = sun_uniforms; - skirt_render_state.uniforms[ UNIFORMS_CLIPMAP_SKIRT ] = renderer_uniforms( scale ); - skirt_render_state.textures[ 0 ] = renderer_blue_noise(); + skirt_render_state.set_uniform( "view", inf_view_uniforms ); + skirt_render_state.set_uniform( "sun", sun_uniforms ); + skirt_render_state.set_uniform( "clipmap_skirt", renderer_uniforms( scale ) ); + skirt_render_state.set_texture( "blue_noise", renderer_blue_noise() ); skirt_render_state.wireframe = game->draw_wireframe; renderer_draw_mesh( clipmap.gpu.skirt, skirt_render_state ); } @@ -879,9 +879,9 @@ GAME_FRAME( game_frame ) { { RenderState render_state; render_state.shader = get_shader( SHADER_TREE ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_SUN ] = renderer_uniforms( sun_dir ); - render_state.textures[ 0 ] = renderer_blue_noise(); + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "sun", renderer_uniforms( sun_dir ) ); + render_state.set_texture( "blue_noise", renderer_blue_noise() ); renderer_draw_instances( tree_mesh, render_state, num_trees, trees_instance_data ); } @@ -961,7 +961,7 @@ GAME_FRAME( game_frame ) { RenderState fireball_render_state; fireball_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - fireball_render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + fireball_render_state.set_uniform( "view", view_uniforms ); immediate_render( fireball_render_state ); for( size_t i = 0; i < explosions.elems.n; i++ ) { @@ -978,7 +978,7 @@ GAME_FRAME( game_frame ) { RenderState explosion_render_state; explosion_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - explosion_render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + explosion_render_state.set_uniform( "view", view_uniforms ); immediate_render( explosion_render_state ); } @@ -1082,7 +1082,7 @@ GAME_FRAME( game_frame ) { RenderState impact_render_state; impact_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - impact_render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + impact_render_state.set_uniform( "view", view_uniforms ); immediate_render( impact_render_state ); } @@ -1093,7 +1093,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_WIREFRAME ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + render_state.set_uniform( "view", view_uniforms ); render_state.wireframe = true; immediate_render( render_state ); } diff --git a/fnv.h b/fnv.h @@ -3,6 +3,16 @@ #include "intrinsics.h" #include "array.h" +u32 fnv1a32( const void * data, size_t n, u32 hash = UINT32_C( 2166136261 ) ) { + const u32 prime = U32( 16777619 ); + + const char * cdata = ( const char * ) data; + for( size_t i = 0; i < n; i++ ) { + hash = ( hash ^ cdata[ i ] ) * prime; + } + return hash; +} + forceinline u64 fnv1a( const void * data, size_t n ) { const u64 basis = U64( 14695981039346656037 ); const u64 prime = U64( 1099511628211 ); diff --git a/fullscreen.cc b/fullscreen.cc @@ -21,7 +21,7 @@ static v3 light_dir = v3_forward( -60, 90 ); static void draw_scene( RenderState render_state, bool draw_light = false ) { m4 I = m4_identity(); - render_state.uniforms[ UNIFORMS_MODEL ] = renderer_uniforms( I ); + render_state.set_uniform( "model", renderer_uniforms( I ) ); immediate_sphere( v3( 0, 0, 2 ), 2, v4( 1, 0, 0, 1 ) ); immediate_sphere( v3( -3, 7, 2 ), 2, v4( 0, 1, 0, 1 ) ); @@ -46,7 +46,7 @@ static void draw_scene( RenderState render_state, bool draw_light = false ) { immediate_render( render_state ); m4 M = m4_translation( v3( -7, -2, 0 ) ) * m4_rotx( deg_to_rad( 90 ) ); - render_state.uniforms[ UNIFORMS_MODEL ] = renderer_uniforms( M ); + render_state.set_uniform( "model", renderer_uniforms( M ) ); renderer_draw_mesh( tree_mesh, render_state ); } @@ -157,7 +157,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); - render_state.uniforms[ UNIFORMS_LIGHT_VIEW ] = light_view_uniforms; + render_state.set_uniform( "light_view", light_view_uniforms ); draw_scene( render_state ); @@ -170,10 +170,10 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ); - render_state.uniforms[ UNIFORMS_VIEW ] = renderer_uniforms( V, P, game->pos ); - render_state.uniforms[ UNIFORMS_LIGHT_VIEW ] = light_view_uniforms; - render_state.textures[ 0 ] = shadow_fb.textures[ OUTPUT_DEPTH ]; - render_state.textures[ 1 ] = renderer_blue_noise(); + render_state.set_uniform( "view", renderer_uniforms( V, P, game->pos ) ); + render_state.set_uniform( "light_view", light_view_uniforms ); + render_state.set_texture( "shadowmap", shadow_fb.textures[ OUTPUT_DEPTH ] ); + render_state.set_texture( "dither_noise", renderer_blue_noise() ); draw_scene( render_state, true ); @@ -187,10 +187,10 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_GBUFFER ); render_state.depth_func = DEPTHFUNC_DISABLED; - render_state.textures[ 0 ] = gbuffer.textures[ OUTPUT_ALBEDO ]; - render_state.textures[ 1 ] = gbuffer.textures[ OUTPUT_NORMAL ]; - render_state.textures[ 2 ] = gbuffer.textures[ OUTPUT_DEPTH ]; - render_state.textures[ 3 ] = renderer_blue_noise(); + render_state.set_texture( "outline_depth", gbuffer.textures[ OUTPUT_ALBEDO ] ); + render_state.set_texture( "world_normal", gbuffer.textures[ OUTPUT_NORMAL ] ); + render_state.set_texture( "world_depth", gbuffer.textures[ OUTPUT_DEPTH ] ); + render_state.set_texture( "blue_noise", renderer_blue_noise() ); renderer_draw_fullscreen_triangle( render_state ); diff --git a/gltf.cc b/gltf.cc @@ -553,10 +553,9 @@ GAME_FRAME( game_frame ) { { RenderState render_state; render_state.shader = get_shader( SHADER_SKINNED_FLAT_VERTEX_COLOURS ); - render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - render_state.uniforms[ UNIFORMS_MODEL ] = model_uniforms; - render_state.uniforms[ UNIFORMS_JOINT_POSES ] = joints_uniforms; - render_state.textures[ 0 ] = renderer_blue_noise(); + render_state.set_uniform( "view", view_uniforms ); + render_state.set_uniform( "model", model_uniforms ); + render_state.set_uniform( "animation", joints_uniforms ); render_state.wireframe = input->keys[ KEY_M ]; for( u32 i = 0; i < model.num_meshes; i++ ) { @@ -574,7 +573,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - render_state.uniforms[ UNIFORMS_VIEW ] = renderer_uniforms( V, P ); + render_state.set_uniform( "view", renderer_uniforms( V, P ) ); immediate_render( render_state ); } } @@ -593,7 +592,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - render_state.uniforms[ UNIFORMS_VIEW ] = renderer_uniforms( V, P ); + render_state.set_uniform( "view", renderer_uniforms( V, P ) ); immediate_render( render_state ); } diff --git a/immediate.cc b/immediate.cc @@ -190,13 +190,6 @@ void immediate_arrow( v3 origin, v3 direction, float length, v4 colour ) { } } -void immediate_render( Shader shader, Texture texture ) { - RenderState render_state; - render_state.shader = shader; - render_state.textures[ 0 ] = texture; - immediate_render( render_state ); -} - void immediate_render( const RenderState & render_state ) { if( triangles.size() == 0 ) { return; @@ -211,7 +204,7 @@ void immediate_render( const RenderState & render_state ) { mesh_config.normals_offset = checked_cast< u32 >( offsetof( ImmediateVertex, normal ) ); mesh_config.colours_offset = checked_cast< u32 >( offsetof( ImmediateVertex, colour ) ); mesh_config.num_vertices = triangles.size() * 3; - if( render_state.textures[ 0 ] != 0 ) { + if( render_state.num_textures > 0 ) { mesh_config.tex_coords0_offset = checked_cast< u32 >( offsetof( ImmediateVertex, uv ) ); } diff --git a/immediate.h b/immediate.h @@ -17,5 +17,4 @@ void immediate_sphere( v3 centre, float radius, v4 colour, u32 subdivisions = 16 void immediate_aabb( v3 mins, v3 maxs, v4 colour ); void immediate_arrow( v3 origin, v3 direction, float length, v4 colour ); -void immediate_render( Shader shader, Texture texture = 0 ); void immediate_render( const RenderState & render_state ); diff --git a/make.lua b/make.lua @@ -50,8 +50,8 @@ end require( "libs/squish" ) --- bin( "bsp", { "main", "bsp", "bsp_renderer", game_objs }, { game_libs } ) --- bin( "sm", { "main", "shadow_map", game_objs }, { game_libs } ) +bin( "bsp", { "main", "bsp", "bsp_renderer", game_objs }, { game_libs } ) +bin( "sm", { "main", "shadow_map", game_objs }, { game_libs } ) bin( "gltf", { "main", "gltf", game_objs }, { "cgltf", game_libs } ) bin( "msdf", { "main", "msdf", game_objs }, game_libs ) bin( "fullscreen", { "main", "fullscreen", game_objs }, { game_libs } ) diff --git a/msdf.cc b/msdf.cc @@ -91,7 +91,7 @@ static void msdf_text( const char * str, int x, int y, float scale ) { RenderState render_state; render_state.shader = get_shader( SHADER_MSDF ); - render_state.textures[ 0 ] = atlas; + render_state.set_texture( "atlas", atlas ); render_state.depth_func = DEPTHFUNC_DISABLED; render_state.enable_alpha_blending = true; render_state.disable_depth_writes = true; diff --git a/renderer.cc b/renderer.cc @@ -8,12 +8,11 @@ #include "linear_algebra.h" #include "blue_noise.h" #include "obj.h" +#include "fnv.h" STATIC_ASSERT( SAME_TYPE( VB, GLuint ) ); STATIC_ASSERT( SAME_TYPE( IB, GLuint ) ); -STATIC_ASSERT( SAME_TYPE( Shader, GLuint ) ); STATIC_ASSERT( SAME_TYPE( Texture, GLuint ) ); -STATIC_ASSERT( SAME_TYPE( TextureBufferObject, GLuint ) ); STATIC_ASSERT( SAME_TYPE( FramebufferObject, GLuint ) ); STATIC_ASSERT( SAME_TYPE( u32, GLuint ) ); @@ -38,7 +37,6 @@ struct DrawCall { enum DeleteCommandType { DELETE_VB, DELETE_IB, - DELETE_TB, DELETE_TEXTURE, DELETE_MESH, }; @@ -48,7 +46,6 @@ struct DeleteCommand { union { VB vb; IB ib; - TB tb; Shader shader; Texture texture; Mesh mesh; @@ -161,41 +158,45 @@ static GLenum primitivetype_to_glenum( PrimitiveType primitive_type ) { return GL_INVALID_ENUM; } -static bool operator!=( UniformBinding a, UniformBinding b ) { - return a.offset != b.offset || a.size != b.size; -} - static void set_render_state( const RenderState & state ) { if( state.shader != previous_render_state.shader ) { - glUseProgram( state.shader ); + glUseProgram( state.shader->program ); } // uniforms - for( GLuint i = 0; i < UNIFORMS_COUNT; i++ ) { - if( state.uniforms[ i ] != previous_render_state.uniforms[ i ] ) { - UniformBinding binding = state.uniforms[ i ]; - if( binding.size == 0 ) { - glBindBufferBase( GL_UNIFORM_BUFFER, i, 0 ); - } - else { + // TODO: maybe these shouldn't always get rebound + for( size_t i = 0; i < ARRAY_COUNT( state.shader->uniforms ); i++ ) { + bool found = false; + for( size_t j = 0; j < state.num_uniforms; j++ ) { + UniformBinding binding = state.uniforms[ j ].binding; + if( state.uniforms[ j ].name_hash == state.shader->uniforms[ i ] && binding.size > 0 ) { glBindBufferRange( GL_UNIFORM_BUFFER, i, uniforms, binding.offset, binding.size ); + found = true; + break; } } + + if( !found ) { + glBindBufferBase( GL_UNIFORM_BUFFER, i, 0 ); + } } // textures - for( GLuint i = 0; i < RENDERER_MAX_TEXTURES; i++ ) { - if( state.textures[ i ] != previous_render_state.textures[ i ] ) { - glActiveTexture( GL_TEXTURE0 + i ); - glBindTexture( GL_TEXTURE_2D, state.textures[ i ] ); + for( size_t i = 0; i < ARRAY_COUNT( state.shader->textures ); i++ ) { + glActiveTexture( GL_TEXTURE0 + i ); + // ggprint( "shader texture = {}\n", state.shader->textures[ i ] ); + + bool found = false; + for( size_t j = 0; j < state.num_textures; j++ ) { + if( state.textures[ j ].name_hash == state.shader->textures[ i ] ) { + glBindTexture( GL_TEXTURE_2D, state.textures[ j ].texture ); + found = true; + break; + } } - } - // texture buffers - for( GLuint i = 0; i < RENDERER_MAX_TEXTURE_BUFFERS; i++ ) { - if( state.tbs[ i ].texture != previous_render_state.tbs[ i ].texture ) { - glActiveTexture( GL_TEXTURE0 + i + RENDERER_MAX_TEXTURES ); - glBindTexture( GL_TEXTURE_BUFFER, state.tbs[ i ].texture ); + if( !found ) { + glBindTexture( GL_TEXTURE_2D, 0 ); } } @@ -364,11 +365,6 @@ void renderer_end_frame() { glDeleteBuffers( 1, &del.ib ); break; - case DELETE_TB: - glDeleteBuffers( 1, &del.tb.tbo ); - glDeleteTextures( 1, &del.tb.texture ); - break; - case DELETE_TEXTURE: glDeleteTextures( 1, &del.texture ); break; @@ -444,6 +440,7 @@ UniformBinding renderer_upload_uniforms( const void * data, size_t size, size_t alignment = max( alignment, ubo_offset_alignment ); UniformBinding binding; + binding.ubo = uniforms; binding.offset = checked_cast< u32 >( align_power_of_2( uniforms_offset, alignment ) ); binding.size = checked_cast< u32 >( size ); @@ -590,41 +587,6 @@ void renderer_delete_ib( IB ib ) { glDeleteBuffers( 1, &ib ); } -TB renderer_new_tb( TextureFormat format, const void * data, u32 len, BufferUsage usage ) { - ASSERT( len < S32_MAX ); - ASSERT( !is_compressed( format ) ); - - GLuint tbo, texture; - glGenBuffers( 1, &tbo ); - glGenTextures( 1, &texture ); - - glBindBuffer( GL_TEXTURE_BUFFER, tbo ); - glBindTexture( GL_TEXTURE_BUFFER, texture ); - glTexBuffer( GL_TEXTURE_BUFFER, texfmt_to_internal_format( format ), tbo ); - - if( data != NULL ) { - glBufferData( GL_TEXTURE_BUFFER, len, data, bufferusage_to_glenum( usage ) ); - } - - TB tb = { }; - tb.tbo = tbo; - tb.texture = texture; - return tb; -} - -void renderer_tb_data( TB tb, const void * data, u32 len, BufferUsage usage ) { - ASSERT( len < S32_MAX ); - - glBindBuffer( GL_TEXTURE_BUFFER, tb.tbo ); - glBufferData( GL_TEXTURE_BUFFER, len, NULL, bufferusage_to_glenum( usage ) ); - glBufferData( GL_TEXTURE_BUFFER, len, data, bufferusage_to_glenum( usage ) ); -} - -void renderer_delete_tb( TB tb ) { - glDeleteBuffers( 1, &tb.tbo ); - glDeleteTextures( 1, &tb.texture ); -} - static GLenum framebufferattachment_to_glenum( FramebufferAttachment attachment ) { switch( attachment ) { case FB_COLOUR: return GL_COLOR_ATTACHMENT0; @@ -737,25 +699,26 @@ static GLuint new_gl_shader( GLenum type, array< const char * > srcs ) { char buf[ 1024 ]; glGetShaderInfoLog( shader, sizeof( buf ), NULL, buf ); WARN( "shader compilation failed: {}", buf ); + glDeleteShader( shader ); // static char src[ 65536 ]; // glGetShaderSource( shader, sizeof( src ), NULL, src ); // printf( "%s\n", src ); - return INVALID_SHADER; + return 0; } return shader; } -Shader renderer_new_shader( ShaderConfig config ) { - GLuint vs = new_gl_shader( GL_VERTEX_SHADER, config.srcs ); - GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, config.srcs ); +Shader renderer_new_shader( array< const char * > srcs ) { + Shader shader = { }; + + GLuint vs = new_gl_shader( GL_VERTEX_SHADER, srcs ); + GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, srcs ); if( vs == 0 || fs == 0 ) { - if( vs != 0 ) glDeleteShader( vs ); - if( fs != 0 ) glDeleteShader( fs ); - return INVALID_SHADER; + return shader; } GLuint program = glCreateProgram(); @@ -786,55 +749,51 @@ Shader renderer_new_shader( ShaderConfig config ) { glGetProgramInfoLog( program, sizeof( buf ), NULL, buf ); WARN( "shader linking failed: {}", buf ); - return INVALID_SHADER; + return shader; } - const char * ubo_names[] = { "debug", "view", "model", "light_view", "window", "sun", "sky", "clipmap", "clipmap_skirt", "animation" }; - STATIC_ASSERT( ARRAY_COUNT( ubo_names ) == UNIFORMS_COUNT ); - for( GLuint i = 0; i < ARRAY_COUNT( ubo_names ); i++ ) { - GLuint idx = glGetUniformBlockIndex( program, ubo_names[ i ] ); - if( idx != GL_INVALID_INDEX ) { - glUniformBlockBinding( program, idx, i ); - } - } glUseProgram( program ); - for( GLint i = 0; i < RENDERER_MAX_TEXTURES; i++ ) { - if( config.texture_uniform_names[ i ] != NULL ) { - GLuint uniform = glGetUniformLocation( program, config.texture_uniform_names[ i ] ); - if( uniform == GLuint( -1 ) ) { - WARN( "couldn't find texture uniform: {}", config.texture_uniform_names[ i ] ); - glDeleteProgram( program ); - return INVALID_SHADER; - } - glUniform1i( uniform, i ); + shader.program = program; + + GLint count, maxlen; + glGetProgramiv( program, GL_ACTIVE_UNIFORMS, &count ); + glGetProgramiv( program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen ); + + size_t numtextures = 0; + for( GLint i = 0; i < count; i++ ) { + char name[ 128 ]; + GLint size, len; + GLenum type; + glGetActiveUniform( program, i, sizeof( name ), &len, &size, &type, name ); + + if( type == GL_SAMPLER_2D ) { + glUniform1i( i, numtextures ); + shader.textures[ numtextures ] = fnv1a32( name, len ); + numtextures++; } } - for( GLint i = 0; i < RENDERER_MAX_TEXTURE_BUFFERS; i++ ) { - if( config.texture_buffer_uniform_names[ i ] != NULL ) { - GLuint uniform = glGetUniformLocation( program, config.texture_buffer_uniform_names[ i ] ); - if( uniform == GLuint( -1 ) ) { - WARN( "couldn't find texturebuffer uniform: {}", config.texture_buffer_uniform_names[ i ] ); - glDeleteProgram( program ); - return INVALID_SHADER; - } - glUniform1i( uniform, i + RENDERER_MAX_TEXTURES ); - } + glGetProgramiv( program, GL_ACTIVE_UNIFORM_BLOCKS, &count ); + glGetProgramiv( program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxlen ); + + size_t numubos = 0; + for( GLint i = 0; i < count; i++ ) { + char name[ 128 ]; + GLint len; + glGetActiveUniformBlockName( program, i, sizeof( name ), &len, name ); + glUniformBlockBinding( program, i, numubos ); + shader.uniforms[ numubos ] = fnv1a32( name, len ); + numubos++; } - glUseProgram( 0 ); - return program; -} + glUseProgram( 0 ); -Shader renderer_new_shader( const char * src ) { - ShaderConfig config; - config.srcs[ 0 ] = src; - return renderer_new_shader( config ); + return shader; } void renderer_delete_shader( Shader shader ) { - glDeleteProgram( shader ); + glDeleteProgram( shader.program ); } static u32 mipmap_dim( u32 dim, u32 level ) { diff --git a/renderer.h b/renderer.h @@ -3,6 +3,7 @@ #include "intrinsics.h" #include "array.h" #include "linear_algebra.h" +#include "stringhash.h" /* * forward declare things so only the implementation includes the full GL headers @@ -10,26 +11,9 @@ typedef u32 VB; typedef u32 IB; -typedef u32 Shader; typedef u32 Texture; -typedef u32 TextureBufferObject; typedef u32 FramebufferObject; -enum UniformSlots { - UNIFORMS_DEBUG, - UNIFORMS_VIEW, - UNIFORMS_MODEL, - UNIFORMS_LIGHT_VIEW, - UNIFORMS_WINDOW, - UNIFORMS_SUN, - UNIFORMS_SKY, - UNIFORMS_CLIPMAP, - UNIFORMS_CLIPMAP_SKIRT, - UNIFORMS_JOINT_POSES, - - UNIFORMS_COUNT, -}; - enum OutputSlots { OUTPUT_ALBEDO, OUTPUT_NORMAL, @@ -42,8 +26,6 @@ enum OutputSlots { #define RENDERER_MAX_TEXTURES 4 #define RENDERER_MAX_TEXTURE_BUFFERS 4 -const u32 INVALID_SHADER = 0; - enum CullFace { CULLFACE_BACK, CULLFACE_FRONT, @@ -113,9 +95,10 @@ enum FramebufferAttachment { FB_NORMAL, }; -struct TB { - TextureBufferObject tbo; - Texture texture; +struct Shader { + u32 program; + u32 uniforms[ 16 ]; + u32 textures[ RENDERER_MAX_TEXTURES ]; }; struct FB { @@ -125,22 +108,60 @@ struct FB { }; struct UniformBinding { - // TODO: might be able to make these u16 - u32 offset; - u32 size; + u32 ubo; + u16 offset; + u16 size; }; struct RenderState { - StaticArray< UniformBinding, UNIFORMS_COUNT > uniforms = { }; - StaticArray< Texture, RENDERER_MAX_TEXTURES > textures = { }; - StaticArray< TB, RENDERER_MAX_TEXTURE_BUFFERS > tbs = { }; - Shader shader = INVALID_SHADER; + struct Uniform { + u32 name_hash; + UniformBinding binding; + }; + + struct T { + u32 name_hash; + Texture texture; + }; + + Uniform uniforms[ 16 ]; + T textures[ RENDERER_MAX_TEXTURES ]; + size_t num_uniforms = 0; + size_t num_textures = 0; + + const Shader * shader = NULL; DepthFunc depth_func = DEPTHFUNC_LESS; CullFace cull_face = CULLFACE_BACK; bool disable_depth_writes = false; bool disable_colour_writes = false; bool enable_alpha_blending = false; bool wireframe = false; + + void set_uniform( StringHash name, UniformBinding binding ) { + for( size_t i = 0; i < num_uniforms; i++ ) { + if( uniforms[ i ].name_hash == name.hash ) { + uniforms[ i ].binding = binding; + return; + } + } + + uniforms[ num_uniforms ].name_hash = name.hash; + uniforms[ num_uniforms ].binding = binding; + num_uniforms++; + } + + void set_texture( StringHash name, Texture texture ) { + for( size_t i = 0; i < num_textures; i++ ) { + if( textures[ i ].name_hash == name.hash ) { + textures[ i ].texture = texture; + return; + } + } + + textures[ num_textures ].name_hash = name.hash; + textures[ num_textures ].texture = texture; + num_textures++; + } }; enum VertexFormat { @@ -228,12 +249,6 @@ struct MeshConfig { PrimitiveType primitive_type = PRIMITIVETYPE_TRIANGLES; }; -struct ShaderConfig { - StaticArray< const char *, 8 > srcs = { }; - StaticArray< const char *, RENDERER_MAX_TEXTURES > texture_uniform_names = { }; - StaticArray< const char *, RENDERER_MAX_TEXTURE_BUFFERS > texture_buffer_uniform_names = { }; -}; - struct TextureConfig { u32 width = 0; u32 height = 0; @@ -294,16 +309,11 @@ void renderer_delete_vb( VB vb ); IB renderer_new_ib( const void * data = NULL, u32 len = 0, BufferUsage usage = BUFFERUSAGE_STATIC ); void renderer_delete_ib( IB ib ); -TB renderer_new_tb( TextureFormat format, const void * data = NULL, u32 len = 0, BufferUsage usage = BUFFERUSAGE_DYNAMIC ); -void renderer_tb_data( TB tb, const void * data, u32 len, BufferUsage usage = BUFFERUSAGE_DYNAMIC ); -void renderer_delete_tb( TB tb ); - FB renderer_new_fb( TextureConfig texture_format, FramebufferAttachment attachment ); FB renderer_new_fb( const FramebufferConfig & config ); void renderer_delete_fb( FB fb ); -Shader renderer_new_shader( ShaderConfig config ); -Shader renderer_new_shader( const char * src ); +Shader renderer_new_shader( array< const char * > srcs ); void renderer_delete_shader( Shader shader ); Texture renderer_new_texture( TextureConfig config ); diff --git a/shaders.cc b/shaders.cc @@ -8,10 +8,8 @@ struct HotloadShader { const char * path = NULL; - Shader shader = 0; + Shader shader = { }; time_t last_modified = 0; - StaticArray< const char *, RENDERER_MAX_TEXTURES > texture_uniform_names = { }; - StaticArray< const char *, RENDERER_MAX_TEXTURE_BUFFERS > texture_buffer_uniform_names = { }; }; struct ShaderInclude { @@ -37,58 +35,38 @@ void shaders_init() { includes[ 1 ].path = "shaders/pbr.glsl"; shaders[ SHADER_TEXT ].path = "shaders/text.glsl"; - shaders[ SHADER_TEXT ].texture_uniform_names[ 0 ] = "atlas"; shaders[ SHADER_MSDF ].path = "shaders/msdf.glsl"; - shaders[ SHADER_MSDF ].texture_uniform_names[ 0 ] = "atlas"; shaders[ SHADER_SKYBOX ].path = "shaders/skybox.glsl"; - shaders[ SHADER_SKYBOX ].texture_uniform_names[ 0 ] = "blue_noise"; 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_UI ].path = "shaders/ui.glsl"; shaders[ SHADER_TREE ].path = "shaders/tree.glsl"; - shaders[ SHADER_TREE ].texture_uniform_names[ 0 ] = "blue_noise"; shaders[ SHADER_WRITE_SHADOW_MAP ].path = "shaders/write_shadow_map.glsl"; shaders[ SHADER_DEBUG_RENDER_SHADOW_MAP ].path = "shaders/debug_render_shadow_map.glsl"; - shaders[ SHADER_DEBUG_RENDER_SHADOW_MAP ].texture_uniform_names[ 0 ] = "tex"; shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].path = "shaders/shadowed_vertex_colours.glsl"; - shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].texture_uniform_names[ 0 ] = "shadowmap"; - shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].texture_uniform_names[ 1 ] = "dither_noise"; shaders[ SHADER_WIREFRAME ].path = "shaders/wireframe.glsl"; shaders[ SHADER_CLIPMAP ].path = "shaders/clipmap.glsl"; - shaders[ SHADER_CLIPMAP ].texture_uniform_names[ 0 ] = "heightmap"; - shaders[ SHADER_CLIPMAP ].texture_uniform_names[ 1 ] = "normalmap"; - shaders[ SHADER_CLIPMAP ].texture_uniform_names[ 2 ] = "horizonmap"; - shaders[ SHADER_CLIPMAP ].texture_uniform_names[ 3 ] = "blue_noise"; shaders[ SHADER_CLIPMAP_SKIRT ].path = "shaders/clipmap_skirt.glsl"; - shaders[ SHADER_CLIPMAP_SKIRT ].texture_uniform_names[ 0 ] = "blue_noise"; shaders[ SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ].path = "shaders/shadowed_vertex_colours_to_gbuffer.glsl"; - shaders[ SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ].texture_uniform_names[ 0 ] = "shadowmap"; - shaders[ SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ].texture_uniform_names[ 1 ] = "dither_noise"; shaders[ SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ].path = "shaders/flat_vertex_colours_to_gbuffer.glsl"; shaders[ SHADER_GBUFFER ].path = "shaders/gbuffer.glsl"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 0 ] = "world_normal"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 1 ] = "world_depth"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 2 ] = "outline_depth"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 3 ] = "blue_noise"; shaders[ SHADER_DEPTH_EDGE ].path = "shaders/depth_edge.glsl"; - shaders[ SHADER_DEPTH_EDGE ].texture_uniform_names[ 0 ] = "model_depth"; shaders[ SHADER_SKINNED_FLAT_VERTEX_COLOURS ].path = "shaders/skinned_flat_vertex_colours.glsl"; @@ -98,13 +76,13 @@ void shaders_init() { } } -Shader get_shader( ShaderID id ) { - return shaders[ id ].shader; +const Shader * get_shader( ShaderID id ) { + return &shaders[ id ].shader; } void shaders_term() { for( HotloadShader & shader : shaders ) { - if( shader.shader != INVALID_SHADER ) { + if( shader.shader.program != 0 ) { renderer_delete_shader( shader.shader ); } } @@ -123,21 +101,20 @@ static bool reload_shader( HotloadShader & shader, time_t t ) { INFO( "loading {}", shader.path ); char * contents = ( char * ) file_get_contents( shader.path ); - ShaderConfig shader_config; - shader_config.texture_uniform_names = shader.texture_uniform_names; - shader_config.texture_buffer_uniform_names = shader.texture_buffer_uniform_names; + StaticArray< const char *, 8 > srcs; size_t n = 0; for( ShaderInclude & include : includes ) { if( include.contents == NULL ) break; - shader_config.srcs[ n ] = include.contents; + srcs[ n ] = include.contents; n++; } - shader_config.srcs[ n ] = contents; + srcs[ n ] = contents; + n++; - Shader new_shader = renderer_new_shader( shader_config ); + Shader new_shader = renderer_new_shader( srcs.slice( 0, n ) ); - if( new_shader != INVALID_SHADER ) { + if( new_shader.program != 0 ) { renderer_delete_shader( shader.shader ); shader.shader = new_shader; } diff --git a/shaders.h b/shaders.h @@ -29,7 +29,7 @@ enum ShaderID { }; void shaders_init(); -Shader get_shader( ShaderID id ); +const Shader * get_shader( ShaderID id ); void shaders_term(); int hotload_shaders(); diff --git a/shadow_map.cc b/shadow_map.cc @@ -20,7 +20,7 @@ static v3 light_dir = v3_forward( -60, 90 ); static void draw_scene( RenderState render_state, bool draw_light = false ) { m4 I = m4_identity(); - render_state.uniforms[ UNIFORMS_MODEL ] = renderer_uniforms( I ); + render_state.set_uniform( "model", renderer_uniforms( I ) ); immediate_sphere( v3( 0, 0, 2 ), 2, v4( 1, 0, 0, 1 ) ); immediate_sphere( v3( -3, 7, 2 ), 2, v4( 0, 1, 0, 1 ) ); @@ -45,7 +45,7 @@ static void draw_scene( RenderState render_state, bool draw_light = false ) { immediate_render( render_state ); m4 M = m4_translation( v3( -7, -2, 0 ) ) * m4_rotx( deg_to_rad( 90 ) ); - render_state.uniforms[ UNIFORMS_MODEL ] = renderer_uniforms( M ); + render_state.set_uniform( "model", renderer_uniforms( M ) ); renderer_draw_mesh( tree_mesh, render_state ); } @@ -132,7 +132,7 @@ GAME_FRAME( game_frame ) { RenderState render_state; render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); - render_state.uniforms[ UNIFORMS_LIGHT_VIEW ] = light_view_uniforms; + render_state.set_uniform( "light_view", light_view_uniforms ); draw_scene( render_state ); @@ -145,7 +145,7 @@ GAME_FRAME( game_frame ) { { RenderState state; state.shader = get_shader( SHADER_DEBUG_RENDER_SHADOW_MAP ); - state.textures[ 0 ] = shadow_fb.textures[ OUTPUT_DEPTH ]; + state.set_texture( "tex", shadow_fb.textures[ OUTPUT_DEPTH ] ); renderer_draw_mesh( square, state ); } @@ -153,10 +153,10 @@ GAME_FRAME( game_frame ) { { RenderState render_state; render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS ); - render_state.uniforms[ UNIFORMS_VIEW ] = renderer_uniforms( V, P, game->pos ); - render_state.uniforms[ UNIFORMS_LIGHT_VIEW ] = light_view_uniforms; - render_state.textures[ 0 ] = shadow_fb.textures[ OUTPUT_DEPTH ]; - render_state.textures[ 1 ] = renderer_blue_noise(); + render_state.set_uniform( "view", renderer_uniforms( V, P, game->pos ) ); + render_state.set_uniform( "light_view", light_view_uniforms ); + render_state.set_texture( "shadowmap", shadow_fb.textures[ OUTPUT_DEPTH ] ); + render_state.set_texture( "dither_noise", renderer_blue_noise() ); draw_scene( render_state, true ); } diff --git a/skybox.cc b/skybox.cc @@ -121,9 +121,9 @@ void skybox_render( const Skybox * skybox, const m4 & Vsky, const m4 & P, float RenderState render_state; render_state.shader = get_shader( SHADER_SKYBOX ); - render_state.uniforms[ UNIFORMS_VIEW ] = renderer_uniforms( Vsky, P ); - render_state.uniforms[ UNIFORMS_SKY ] = renderer_uniforms( hosek.A, hosek.B, hosek.C, hosek.D, hosek.E, hosek.F, hosek.G, hosek.H, hosek.I, hosek.Z, sun_dir ); - render_state.textures[ 0 ] = renderer_blue_noise(); + render_state.set_uniform( "view", renderer_uniforms( Vsky, P ) ); + render_state.set_uniform( "sky", renderer_uniforms( hosek.A, hosek.B, hosek.C, hosek.D, hosek.E, hosek.F, hosek.G, hosek.H, hosek.I, hosek.Z, sun_dir ) ); + render_state.set_texture( "blue_noise", renderer_blue_noise() ); render_state.cull_face = CULLFACE_FRONT; renderer_draw_mesh( skybox->mesh, render_state ); diff --git a/stringhash.h b/stringhash.h @@ -2,13 +2,8 @@ #include "intrinsics.h" -constexpr static inline u32 fnv1a( const char * str, size_t n ) { - return n == 0 ? 0x811C9DC5 : ( fnv1a( str + 1, n - 1 ) ^ u32( u8( str[ 0 ] ) ) ) * 0x01000193; -} - -template< size_t N > -constexpr static inline u32 fnv1a( const char ( & str )[ N ] ) { - return fnv1a( str, N ); +constexpr u32 fnv1a_ct( const char * str, size_t n, u32 basis = U32( 2166136261 ) ) { + return n == 0 ? basis : fnv1a_ct( str + 1, n - 1, ( basis ^ str[ 0 ] ) * U32( 16777619 ) ); } struct StringHash { @@ -20,7 +15,7 @@ struct StringHash { template< size_t N > StringHash( const char ( & s )[ N ] ) { str = s; - hash = fnv1a( s ); + hash = fnv1a_ct( s, N - 1 ); } }; diff --git a/text_renderer.cc b/text_renderer.cc @@ -147,8 +147,8 @@ void draw_text( const char * str, int x, int y, float pixel_size ) { RenderState render_state; render_state.shader = get_shader( SHADER_TEXT ); - render_state.textures[ 0 ] = atlas; - render_state.uniforms[ UNIFORMS_WINDOW ] = renderer_uniforms( get_window_size() ); + render_state.set_uniform( "window", renderer_uniforms( get_window_size() ) ); + render_state.set_texture( "atlas", atlas ); render_state.depth_func = DEPTHFUNC_DISABLED; render_state.enable_alpha_blending = true; // render_state.disable_depth_writes = true;