summaryrefslogtreecommitdiff
path: root/src/render/gl_batch.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/gl_batch.h')
-rw-r--r--src/render/gl_batch.h193
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] );
+ }
+}