diff options
Diffstat (limited to 'src/render/gl_batch.h')
| -rw-r--r-- | src/render/gl_batch.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/render/gl_batch.h b/src/render/gl_batch.h new file mode 100644 index 0000000..944521f --- /dev/null +++ b/src/render/gl_batch.h @@ -0,0 +1,193 @@ +#pragma once +#include "gl.h" + +// this is maybe a bit too much c++ voodoo for my liking + +const U32 BATCH_VERTICES_MAX = 16384; + +template <typename VERTEX> +struct GL_BATCH; + +// func for setting sampler idx inside of vertex data +template <typename VERTEX> +using GL_BATCH_VERTEX_SAMPLER_IDX_FN = void (*)(VERTEX* vertex, U8 idx); + +template <typename VERTEX> +using GL_BATCH_SETUP_FN = void (*)(GL_BATCH<VERTEX>* batch); + +template <typename VERTEX> +struct GL_BATCH_CALL { + LIST<VERTEX> vertices{}; + VEC2 clip_start; + VEC2 clip_dim; + + VEC2 viewport_start; + VEC2 viewport_dim; + + U16 primitive; + LIST<GL_TEX2D*> textures{}; +}; + +template <typename VERTEX> +struct GL_BATCH { + GL_DATA* gl; + GL_SHADER_PROGRAM* shader; + + VEC2 clip_start; + VEC2 clip_dim; + + VEC2 viewport_start; + VEC2 viewport_dim; + + GLuint vbuffer; + + LIST<GL_BATCH_CALL<VERTEX>> calls{}; + + // func for setting up vertex attribs + GL_BATCH_SETUP_FN<VERTEX> setup_cb; +}; + +/* + * takes in a callback func that gets called before the batch is drawn + * + * should set up vertex attribs correctly according to vertex fmt + */ +template <typename VERTEX> +inline GL_BATCH<VERTEX>* gl_batch_create( + GL_DATA* gl, + GL_SHADER_PROGRAM* shader, + GL_BATCH_SETUP_FN<VERTEX> setup_cb +) { + GL_BATCH<VERTEX>* batch = new GL_BATCH<VERTEX>; + batch->gl = gl; + batch->shader = shader; + + batch->clip_start = gl->clip_start; + batch->clip_dim = gl->clip_dim; + + batch->viewport_start = gl->viewport_start; + batch->viewport_dim = gl->viewport_dim; + + batch->setup_cb = setup_cb; + + glGenBuffers( 1, &batch->vbuffer ); + glBindBuffer( GL_ARRAY_BUFFER, batch->vbuffer ); + // make sure we have enough vram + glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * BATCH_VERTICES_MAX, 0, GL_DYNAMIC_DRAW ); + return batch; +} + +template <typename VERTEX> +inline void gl_batch_destroy( GL_BATCH<VERTEX>* batch ) { + glDeleteBuffers( &batch->vbuffer ); + delete batch; +} + +template <typename VERTEX> +inline void gl_batch_empty( GL_BATCH<VERTEX>* batch ) { + batch->calls.clear(); +} + +template <typename VERTEX> +inline void gl_batch_draw( GL_BATCH<VERTEX>* batch ) { + glUseProgram( batch->shader->id ); + + VEC2 vp_start, vp_dim, clip_start, clip_dim; + gl_get_viewport( batch->gl, &vp_start, &vp_dim ); + gl_get_clip( batch->gl, &clip_start, &clip_dim ); + + batch->setup_cb( batch ); + batch->calls.each( fn( GL_BATCH_CALL<VERTEX>* call ) { + for( U32 i = 0; i < call->textures.size; ++i ) { + glActiveTexture( GL_TEXTURE0 + i ); + glBindTexture( GL_TEXTURE_2D, call->textures.data[i] ? call->textures.data[i]->id : 0 ); + } + + glBindBuffer( GL_ARRAY_BUFFER, batch->vbuffer ); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(VERTEX) * call->vertices.size, + call->vertices.data, + GL_DYNAMIC_DRAW + ); + + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + glDrawArrays( call->primitive, 0, call->vertices.size ); + } ); + + gl_set_viewport( batch->gl, vp_start, vp_dim ); + gl_set_clip( batch->gl, clip_start, clip_dim ); +} + +template <typename VERTEX> +inline GL_BATCH_CALL<VERTEX>* gl_batch_get_call( GL_BATCH<VERTEX>* batch, GL_TEX2D* tex, U16 primitive, I32* texid ) { + U32 n = batch->calls.size; + VEC2 vp_start = batch->viewport_start; + VEC2 vp_dim = batch->viewport_dim; + VEC2 clip_start = batch->clip_start; + VEC2 clip_dim = batch->clip_dim; + + if( n ) { + GL_BATCH_CALL<VERTEX>* last = &batch->calls.data[n - 1]; + if( last->primitive == primitive + && vp_start == last->clip_start && vp_dim == last->viewport_dim + && clip_start == last->clip_start && clip_dim == last->clip_dim + ) { + I32 idx = last->textures.idx_of( tex ); + if( idx != -1 ) { + *texid = idx; + return last; + } + else if( last->textures.size < batch->gl->shader_texture_limit ) { + *texid = last->textures.size; + last->textures.push( tex ); + return last; + } + } + } + + + GL_BATCH_CALL<VERTEX> call{ + .vertices = {}, + .clip_start = batch->clip_start, + .clip_dim = batch->clip_dim, + .viewport_start = batch->viewport_start, + .viewport_dim = batch->viewport_dim, + .primitive = primitive, + .textures = {}, + }; + + *texid = 0; + call.textures.push( tex ); + return batch->calls.push( call ); +} + +template <typename VERTEX> +inline void gl_batch_insert( + GL_BATCH<VERTEX>* batch, + VERTEX* vertices, + U32 count, + GL_TEX2D* tex, + U16 primitive = GL_TRIANGLES +) { + if( !count ) + return; + + GL_BATCH_CALL<VERTEX>* call; + I32 texid; + VEC2 vp_start, vp_dim; + VEC2 clip_start, clip_dim; + + gl_get_viewport( batch->gl, &vp_start, &vp_dim ); + gl_get_clip( batch->gl, &clip_start, &clip_dim ); + + batch->viewport_start = vp_start; batch->viewport_dim = vp_dim; + batch->clip_start = clip_start; batch->clip_dim = clip_dim; + + call = gl_batch_get_call( batch, tex, primitive, &texid ); + + for( U32 i = 0; i < count; ++i ) { + vertices[i].sampler = (!!tex)? texid : SAMPLER_ID_NONE; + call->vertices.push( vertices[i] ); + } +} |
