aboutsummaryrefslogtreecommitdiff
path: root/src/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics')
-rw-r--r--src/graphics/vertex_buffer.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/graphics/vertex_buffer.c b/src/graphics/vertex_buffer.c
new file mode 100644
index 0000000..415f574
--- /dev/null
+++ b/src/graphics/vertex_buffer.c
@@ -0,0 +1,111 @@
+#include "../../include/mgl/graphics/vertex_buffer.h"
+#include "../../include/mgl/graphics/texture.h"
+#include "../../include/mgl/mgl.h"
+
+/* TODO: Cache vertex buffer */
+/*
+ TODO: Add option to only use vertices and color or vertices and texture coordinates.
+ In such cases we should call glEnableClientState/glDisableClientState(GL_COLOR_ARRAY/GL_TEXTURE_COORD_ARRAY) and others.
+*/
+
+static unsigned int mgl_vertex_buffer_usage_to_gl_usage(mgl_vertex_buffer_usage usage) {
+ switch(usage) {
+ case MGL_USAGE_STREAM: return GL_STREAM_DRAW;
+ case MGL_USAGE_DYNAMIC: return GL_DYNAMIC_DRAW;
+ case MGL_USAGE_STATIC: return GL_STATIC_DRAW;
+ }
+ return GL_STREAM_DRAW;
+}
+
+static unsigned int mgl_primitive_type_to_gl_mode(mgl_primitive_type primitive_type) {
+ switch(primitive_type) {
+ case MGL_PRIMITIVE_POINTS: return GL_POINTS;
+ case MGL_PRIMITIVE_LINES: return GL_LINES;
+ case MGL_PRIMITIVE_LINE_STRIP: return GL_LINE_STRIP;
+ case MGL_PRIMITIVE_TRIANGLES: return GL_TRIANGLES;
+ case MGL_PRIMITIVE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
+ case MGL_PRIMITIVE_TRIANGLE_FAN: return GL_TRIANGLE_FAN;
+ case MGL_PRIMITIVE_QUADS: return GL_QUADS;
+ case MGL_PRIMITIVE_QUAD_STRIP: return GL_QUAD_STRIP;
+ case MGL_PRIMITIVE_POLYGON: return GL_POLYGON;
+ }
+ return MGL_PRIMITIVE_QUADS;
+}
+
+int mgl_vertex_buffer_init(mgl_vertex_buffer *self, mgl_primitive_type primitive_type, mgl_vertex_buffer_usage usage) {
+ self->id = 0;
+ self->vertex_count = 0;
+ self->primitive_type = primitive_type;
+ self->usage = usage;
+ self->position = (mgl_vec2f){ 0.0f, 0.0f };
+
+ mgl_context *context = mgl_get_context();
+ context->gl.glGenBuffers(1, &self->id);
+ if(self->id == 0)
+ return -1;
+
+ return 0;
+}
+
+void mgl_vertex_buffer_deinit(mgl_vertex_buffer *self) {
+ mgl_context *context = mgl_get_context();
+ if(self->id) {
+ context->gl.glDeleteBuffers(1, &self->id);
+ self->id = 0;
+ }
+ self->vertex_count = 0;
+ self->primitive_type = 0;
+ self->usage = 0;
+}
+
+static void mgl_vertex_buffer_set_gl_buffer_pointers(mgl_context *context) {
+ context->gl.glVertexPointer(2, GL_FLOAT, sizeof(mgl_vertex), (void*)offsetof(mgl_vertex, position));
+ context->gl.glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(mgl_vertex), (void*)offsetof(mgl_vertex, color));
+ context->gl.glTexCoordPointer(2, GL_FLOAT, sizeof(mgl_vertex), (void*)offsetof(mgl_vertex, texcoords));
+}
+
+/* TODO: Check for glBufferData error */
+static int mgl_vertex_buffer_resize(mgl_vertex_buffer *self, mgl_vertex *vertices, size_t vertex_count) {
+ mgl_context *context = mgl_get_context();
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, self->id);
+ context->gl.glBufferData(GL_ARRAY_BUFFER, sizeof(mgl_vertex) * vertex_count, vertices, mgl_vertex_buffer_usage_to_gl_usage(self->usage));
+ mgl_vertex_buffer_set_gl_buffer_pointers(context);
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ self->vertex_count = vertex_count;
+ return 0;
+}
+
+void mgl_vertex_buffer_set_position(mgl_vertex_buffer *self, mgl_vec2f position) {
+ self->position = position;
+}
+
+/* TODO: Check for glBufferSubData error */
+int mgl_vertex_buffer_update(mgl_vertex_buffer *self, mgl_vertex *vertices, size_t vertex_count) {
+ if(vertex_count != self->vertex_count)
+ return mgl_vertex_buffer_resize(self, vertices, vertex_count);
+
+ mgl_context *context = mgl_get_context();
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, self->id);
+ context->gl.glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mgl_vertex) * vertex_count, vertices);
+ mgl_vertex_buffer_set_gl_buffer_pointers(context);
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ return 0;
+}
+
+/* TODO: Optimize bind texture */
+void mgl_vertex_buffer_draw(mgl_context *context, mgl_vertex_buffer *self, mgl_texture *texture) {
+ if(self->vertex_count == 0 || self->id == 0)
+ return;
+
+ /* TODO: Optimize this */
+ context->gl.glPushMatrix();
+ context->gl.glTranslatef(self->position.x, self->position.y, 0.0f);
+
+ context->gl.glBindTexture(GL_TEXTURE_2D, texture ? texture->id : 0);
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, self->id);
+ context->gl.glDrawArrays(mgl_primitive_type_to_gl_mode(self->primitive_type), 0, self->vertex_count);
+ context->gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ context->gl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ context->gl.glPopMatrix();
+}