diff options
Diffstat (limited to 'src/graphics')
-rw-r--r-- | src/graphics/vertex_buffer.c | 111 |
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(); +} |