#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 0; } 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 0; } 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(); }