medfall

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 50223ff960d63d667227467230788d1d1f580f85
parent ae5240315858456303a240543432b8a44134760b
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sat Oct 29 13:43:07 +0300

Write a proper GL API wrapper

Diffstat:
renderer.cc | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
renderer.h | 152++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
2 files changed, 338 insertions(+), 123 deletions(-)
diff --git a/renderer.cc b/renderer.cc @@ -1,118 +1,269 @@ #include "glad.h" -#include <glm/glm.hpp> -#include <glm/gtc/type_ptr.hpp> +#include <GLFW/glfw3.h> #include "intrinsics.h" #include "renderer.h" +#include "log.h" +// #include "nonblocking_fixed_spsc_queue.h" -void renderer_init( Renderer * const renderer ) { - renderer->num_draw_calls = 0; -} +/* + * TODO: rename all these functions to _impl and make them push to this pipe + * instead + */ +// static NonblockingFixedSPSCQueue< DrawCall, 512 > render_queue; -void renderer_push( - Renderer * const renderer, - const GLenum mode, const GLuint vao, const GLuint shader, const bool has_ebo, - const u32 count, const u32 first, const GLuint texture -) { - assert( renderer->num_draw_calls < MAX_DRAW_CALLS - 1 ); +static const u32 ATTR_POSITION = 0; +static const u32 ATTR_NORMAL = 1; +static const u32 ATTR_TEX_COORD0 = 2; +static const u32 ATTR_TEX_COORD1 = 3; +static const u32 ATTR_COLOUR = 4; - DrawCall call = { }; - call.mode = mode; +static_assert( sizeof( VB ) == sizeof( GLuint ) ); +static_assert( sizeof( IB ) == sizeof( GLuint ) ); +static_assert( sizeof( UB ) == sizeof( GLuint ) ); +static_assert( sizeof( VAO ) == sizeof( GLuint ) ); +static_assert( sizeof( Shader ) == sizeof( GLuint ) ); +static_assert( sizeof( Texture ) == sizeof( GLuint ) ); - call.vao = vao; - call.shader = shader; - call.texture = texture; +void renderer_begin_frame( ClearColourBool clear_colour, ClearDepthBool clear_depth ) { + if( clear_colour == CLEARCOLOUR_DO || clear_depth == CLEARDEPTH_DO ) { + GLbitfield clear_mask = 0; + clear_mask |= clear_colour == CLEARCOLOUR_DO ? GL_COLOR_BUFFER_BIT : 0; + clear_mask |= clear_depth == CLEARDEPTH_DO ? GL_DEPTH_BUFFER_BIT : 0; + glClear( clear_mask ); + } +} - call.has_ebo = has_ebo; - call.first = first; - call.count = count; +void renderer_end_frame( GLFWwindow * window ) { + glfwSwapBuffers( window ); +} - renderer->draw_calls[ renderer->num_draw_calls ] = call; - renderer->num_draw_calls++; +static GLenum bufferusage_to_glenum( BufferUsage usage ) { + switch( usage ) { + case BUFFERUSAGE_STATIC: return GL_STATIC_DRAW; + case BUFFERUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW; + case BUFFERUSAGE_STREAM: return GL_STREAM_DRAW; + + default: + FATAL( "unsupported BufferUsage: %d", usage ); + return 0; + } } -void renderer_uniform( Renderer * const renderer, const Uniform uniform ) { - assert( renderer->num_draw_calls > 0 ); +VB renderer_new_vb( const void * data, size_t len, BufferUsage usage ) { + GLuint vbo; + glGenBuffers( 1, &vbo ); + glBindBuffer( GL_ARRAY_BUFFER, vbo ); + glBufferData( GL_ARRAY_BUFFER, len, data, bufferusage_to_glenum( usage ) ); + + return checked_cast< VB >( vbo ); +} - DrawCall * const call = &renderer->draw_calls[ renderer->num_draw_calls - 1 ]; - assert( call->num_uniforms < MAX_UNIFORMS - 1 ); +IB renderer_new_ib( const void * data, size_t len, BufferUsage usage ) { + GLuint ebo; + glGenBuffers( 1, &ebo ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, len, data, bufferusage_to_glenum( usage ) ); - call->uniforms[ call->num_uniforms ] = uniform; - call->num_uniforms++; + return checked_cast< IB >( ebo ); } -void renderer_uniform_i( Renderer * const renderer, const int i ) { - Uniform uniform = { }; - uniform.type = UNIFORM_INT; - uniform.i = i; +UB renderer_new_ub( const void * data, size_t len ) { + GLuint ub; + glGenBuffers( 1, &ub ); + + if( data != NULL ) { + glBindBuffer( GL_UNIFORM_BUFFER, ub ); + glBufferData( GL_UNIFORM_BUFFER, len, data, GL_DYNAMIC_DRAW ); + } - renderer_uniform( renderer, uniform ); + return checked_cast< UB >( ub ); } -void renderer_uniform_f( Renderer * const renderer, const float f ) { - Uniform uniform = { }; - uniform.type = UNIFORM_INT; - uniform.f = f; +void renderer_ub_data( UB ub, const void * data, size_t len ) { + glBindBuffer( GL_UNIFORM_BUFFER, ub ); + glBufferData( GL_UNIFORM_BUFFER, len, data, GL_DYNAMIC_DRAW ); +} - renderer_uniform( renderer, uniform ); +void renderer_delete_vb( VB vb ) { + GLuint vbo = checked_cast< GLuint >( vb ); + glDeleteBuffers( 1, &vbo ); } -void renderer_uniform_v3( Renderer * const renderer, const glm::vec3 v3 ) { - Uniform uniform = { }; - uniform.type = UNIFORM_INT; - uniform.v3 = v3; +void renderer_delete_ib( IB ib ) { + GLuint ebo = checked_cast< GLuint >( ib ); + glDeleteBuffers( 1, &ebo ); +} - renderer_uniform( renderer, uniform ); +void renderer_delete_ub( UB ub ) { + GLuint ubo = checked_cast< GLuint >( ub ); + glDeleteBuffers( 1, &ubo ); } -void renderer_uniform_m4( Renderer * const renderer, const glm::mat4 m4 ) { - Uniform uniform = { }; - uniform.type = UNIFORM_INT; - uniform.m4 = m4; +static GLuint new_gl_shader( GLenum type, const char * src ) { + GLuint shader = glCreateShader( type ); + glShaderSource( shader, 1, &src, 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 ); - renderer_uniform( renderer, uniform ); + char * buf = ( char * ) malloc( len ); + if( buf == NULL ) { + FATAL( "and so did malloc" ); + } + glGetShaderInfoLog( shader, len, NULL, buf ); + + FATAL( "%s", buf ); + } + + return shader; } -void renderer_render( const Renderer * const renderer ) { - // TODO: sort draw calls - for( u32 i = 0; i < renderer->num_draw_calls; i++ ) { - const DrawCall * call = &renderer->draw_calls[ i ]; +// TODO: glBindAttribLocation +Shader renderer_new_shader( ShaderConfig config ) { + ASSERT( config.vertex_src != NULL ); + ASSERT( config.fragment_src != NULL ); - glUseProgram( call->shader ); - glBindVertexArray( call->vao ); + GLuint vs = new_gl_shader( GL_VERTEX_SHADER, config.vertex_src ); + GLuint fs = new_gl_shader( GL_FRAGMENT_SHADER, config.fragment_src ); + GLuint gs = 0; - for( u8 u = 0; u < call->num_uniforms; u++ ) { - const Uniform * uniform = &call->uniforms[ i ]; + if( config.geometry_src != NULL ) { + gs = new_gl_shader( GL_GEOMETRY_SHADER, config.geometry_src ); + } - switch( uniform->type ) { - case UNIFORM_INT: { - glUniform1i( uniform->location, uniform->i ); - } break; + GLuint program = glCreateProgram(); + glAttachShader( program, vs ); + glAttachShader( program, fs ); + if( gs != 0 ) { + glAttachShader( program, gs ); + } - case UNIFORM_FLOAT: { - glUniform1f( uniform->location, uniform->f ); - } break; + glBindAttribLocation( program, ATTR_POSITION, "position" ); + glBindAttribLocation( program, ATTR_NORMAL, "normal" ); + glBindAttribLocation( program, ATTR_TEX_COORD0, "tex_coord0" ); + glBindAttribLocation( program, ATTR_TEX_COORD1, "tex_coord1" ); + glBindAttribLocation( program, ATTR_COLOUR, "colour" ); + glEnableVertexAttribArray( ATTR_POSITION ); + glEnableVertexAttribArray( ATTR_NORMAL ); + glEnableVertexAttribArray( ATTR_TEX_COORD0 ); + glEnableVertexAttribArray( ATTR_TEX_COORD1 ); + glEnableVertexAttribArray( ATTR_COLOUR ); - case UNIFORM_VEC3: { - glUniform3fv( uniform->location, 1, glm::value_ptr( uniform->v3 ) ); - } break; + glLinkProgram( program ); - case UNIFORM_MAT4: { - glUniformMatrix4fv( uniform->location, 1, GL_FALSE, glm::value_ptr( uniform->m4 ) ); - } break; - } - } + glDeleteShader( vs ); + glDeleteShader( fs ); + if( gs != 0 ) { + glDeleteShader( gs ); + } - if( call->has_ebo ) { - glDrawElements( call->mode, call->count, GL_UNSIGNED_INT, 0 ); - } - else { - glDrawArrays( call->mode, call->first, call->count ); + 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 ); - // TODO: remove these if we aren't debugging - glBindVertexArray( 0 ); - glUseProgram( 0 ); - glterrible(); + FATAL( "%s", buf ); } + + return checked_cast< Shader >( program ); +} + +Shader renderer_new_shader( const char * vertex_src, const char * fragment_src ) { + ShaderConfig config = { }; + config.vertex_src = vertex_src; + config.fragment_src = fragment_src; + return renderer_new_shader( config ); +} + +Mesh renderer_new_mesh( MeshConfig config ) { + // TODO: assert num_vertices is sane for this primitive type + GLuint vao; + glGenVertexArrays( 1, &vao ); + glBindVertexArray( vao ); + + ASSERT( config.positions != 0 ); + glBindBuffer( GL_ARRAY_BUFFER, checked_cast< GLuint >( config.positions ) ); + glEnableVertexAttribArray( ATTR_POSITION ); + glVertexAttribPointer( ATTR_POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0 ); + + if( config.normals != 0 ) { + // TODO + } + + if( config.tex_coords0 != 0 ) { + // TODO + } + + if( config.tex_coords1 != 0 ) { + // TODO + } + + if( config.colours != 0 ) { + glBindBuffer( GL_ARRAY_BUFFER, checked_cast< GLuint >( config.colours ) ); + glEnableVertexAttribArray( ATTR_COLOUR ); + glVertexAttribPointer( ATTR_COLOUR, 3, GL_FLOAT, GL_FALSE, 0, 0 ); + } + + if( config.indices != 0 ) { + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, checked_cast< GLuint >( config.indices ) ); + } + + glBindVertexArray( 0 ); + + // TODO(mike): delete the VBOs so they don't leak? + + Mesh mesh; + mesh.vao = vao; + mesh.num_vertices = config.num_vertices; + mesh.primitive_type = config.primitive_type; + mesh.indexed = config.indices != 0; + return mesh; +} + +void renderer_delete_mesh( const Mesh & mesh ) { + glDeleteVertexArrays( 1, &mesh.vao ); +} + +static GLenum primitivetype_to_glenum( PrimitiveType primitive_type ) { + switch( primitive_type ) { + case PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES; + case PRIMITIVETYPE_POINTS: return GL_POINTS; + case PRIMITIVETYPE_LINES: return GL_LINES; + + default: + FATAL( "unsupported PrimitiveType: %d", primitive_type ); + return 0; + } +} + +void renderer_draw_mesh( Mesh mesh, RenderState state ) { + // TODO: check vs OpenGLState if these binds are really necessary + glUseProgram( state.shader ); + glBindVertexArray( mesh.vao ); + // TODO: set depth func, bind textures, etc + + GLenum primitive = primitivetype_to_glenum( mesh.primitive_type ); + if( mesh.indexed ) { + glDrawElements( primitive, mesh.num_vertices, GL_UNSIGNED_INT, 0 ); + } + else { + glDrawArrays( primitive, 0, mesh.num_vertices ); + } + + glBindVertexArray( 0 ); } diff --git a/renderer.h b/renderer.h @@ -1,67 +1,131 @@ #ifndef _RENDERER_H_ #define _RENDERER_H_ -#include "glad.h" -#include <glm/glm.hpp> +#include <GLFW/glfw3.h> #include "intrinsics.h" -#define MAX_DRAW_CALLS 65536 -#define MAX_UNIFORMS 8 +#define GLSL( shader ) "#version 330\n" #shader -enum UniformType { - UNIFORM_INT, - UNIFORM_FLOAT, - UNIFORM_VEC3, - UNIFORM_MAT4, +/* + * forward declare things so only the implementation includes the full GL headers + */ + +typedef u32 VB; +typedef u32 IB; +typedef u32 UB; +typedef u32 VAO; +typedef u32 Shader; +typedef u32 Texture; + +enum DrawCallType { + DRAWCALL_NEW_VB, + DRAWCALL_NEW_IB, + DRAWCALL_NEW_UB, + DRAWCALL_NEW_MESH, + DRAWCALL_BUFFER_DATA, + DRAWCALL_DRAW_MESH, + DRAWCALL_FINISH_FRAME, }; -struct Uniform { - UniformType type; - GLint location; - union { - GLint i; - GLfloat f; - glm::vec3 v3; - glm::mat4 m4; - }; +enum DepthFunc { + DEPTHFUNC_LESS, + DEPTHFUNC_EQUAL, + DEPTHFUNC_ALWAYS, }; -// TODO: badly packed -struct DrawCall { - GLenum mode; +enum BufferUsage { + BUFFERUSAGE_STATIC, + BUFFERUSAGE_DYNAMIC, // TODO: remove dynamic? + BUFFERUSAGE_STREAM, +}; + +#define MAX_TEXTURES 4 +#define MAX_UBS 4 + +struct RenderState { + Texture textures[ MAX_TEXTURES ]; + UB ubs[ MAX_UBS ]; + Shader shader; + DepthFunc depth_func; + bool disable_depth_writes; + bool disable_colour_writes; +}; + +enum PrimitiveType { + PRIMITIVETYPE_TRIANGLES, + PRIMITIVETYPE_POINTS, + PRIMITIVETYPE_LINES, +}; - GLuint vao; - GLuint shader; - GLuint texture; +struct Mesh { + VAO vao; + size_t num_vertices; + PrimitiveType primitive_type; + bool indexed; +}; - u8 num_uniforms; - Uniform uniforms[ MAX_UNIFORMS ]; +struct MeshConfig { + VB positions; + VB normals; + VB tex_coords0; + VB tex_coords1; + VB colours; + IB indices; + size_t num_vertices; + PrimitiveType primitive_type; +}; - bool has_ebo; - u32 first; - u32 count; +struct ShaderConfig { + const char * vertex_src; + const char * fragment_src; + const char * geometry_src; }; -struct Renderer { - u32 num_draw_calls; - DrawCall draw_calls[ MAX_DRAW_CALLS ]; +struct DrawCall { + DrawCallType type; + union { + struct { + void * data; + size_t len; + }; + // or Array< u8 >( data, len ); + + MeshConfig mesh_config; + ShaderConfig shader_config; + RenderState render_state; + }; }; -void renderer_init( Renderer * const renderer ); +struct OpenGLState { + RenderState render_state; + // VB bound_vbo; + // IB bound_ebo; + UB bound_ub; + Texture bound_texture; +}; + +enum ClearColourBool { CLEARCOLOUR_DONT, CLEARCOLOUR_DO }; +enum ClearDepthBool { CLEARDEPTH_DONT, CLEARDEPTH_DO }; + +void renderer_begin_frame( ClearColourBool clear_colour = CLEARCOLOUR_DO, ClearDepthBool clear_depth = CLEARDEPTH_DO ); +void renderer_end_frame( GLFWwindow * window ); + +VB renderer_new_vb( const void * data, size_t len, BufferUsage usage = BUFFERUSAGE_STATIC ); // specify type/layout +IB renderer_new_ib( const void * data, size_t len, BufferUsage usage = BUFFERUSAGE_STATIC ); // specify u16/u32 +UB renderer_new_ub( const void * data = NULL, size_t len = 0 ); + +void renderer_delete_vb( VB vb ); +void renderer_delete_ib( IB ib ); +void renderer_delete_ub( UB ub ); -void renderer_push( Renderer * const renderer, - const GLenum mode, const GLuint vao, const GLuint shader, const bool has_ebo, - const u32 count, const u32 first = 0, - const GLuint texture = 0 -); +void renderer_ub_data( UB ub, const void * data, size_t len ); -void renderer_uniform( Renderer * const renderer, const Uniform uniform ); -void renderer_uniform_i( Renderer * const renderer, const int i ); -void renderer_uniform_f( Renderer * const renderer, const float f ); -void renderer_uniform_v3( Renderer * const renderer, const glm::vec3 v3 ); -void renderer_uniform_m4( Renderer * const renderer, const glm::mat4 m4 ); +Shader renderer_new_shader( ShaderConfig config ); +Shader renderer_new_shader( const char * vertex_src, const char * fragment_src ); +void renderer_delete_shader(); -void renderer_render( const Renderer * const renderer ); +Mesh renderer_new_mesh( MeshConfig config ); +void renderer_draw_mesh( Mesh mesh, RenderState state ); #endif // _RENDERER_H_