diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | include/mgl/gl.h | 14 | ||||
-rw-r--r-- | include/mgl/gl_macro.h | 20 | ||||
-rw-r--r-- | include/mgl/graphics/vertex.h | 13 | ||||
-rw-r--r-- | include/mgl/graphics/vertex_buffer.h | 44 | ||||
-rw-r--r-- | src/gl.c | 15 | ||||
-rw-r--r-- | src/graphics/vertex_buffer.c | 111 | ||||
-rw-r--r-- | src/window/window.c | 3 | ||||
-rw-r--r-- | tests/main.c | 39 |
9 files changed, 260 insertions, 3 deletions
@@ -1,5 +1,5 @@ # Minimal Graphics Library -Written in C and uses legacy OpenGL to support as many platforms as possible.\ +Written in C and uses OpenGL 2.0 to support as many platforms as possible.\ Right now mgl only supports x11. # Dependencies ## Build @@ -10,4 +10,4 @@ Right now mgl only supports x11. Handle window close (window destroyed event, disconnected from server and socket becomes invalid (check select return?)).\ Bind texture and cache the bound texture to reduce calls to opengl. Use gl triangle instead of quad. -Fix crash on exit.
\ No newline at end of file +Fix crash on exit. diff --git a/include/mgl/gl.h b/include/mgl/gl.h index 6de98d9..8a09e3e 100644 --- a/include/mgl/gl.h +++ b/include/mgl/gl.h @@ -3,6 +3,7 @@ #include "gl_macro.h" #include <stdint.h> +#include <sys/types.h> typedef struct _XVisualInfo _XVisualInfo; typedef struct _XDisplay Display; @@ -37,7 +38,20 @@ typedef struct { void (*glTexCoord2f)(float s, float t); void (*glOrtho)(double left, double right, double bottom, double top, double near_val, double far_val); void (*glMatrixMode)(unsigned int mode); + void (*glPushMatrix)(void); + void (*glPopMatrix)(void); void (*glLoadIdentity)(void); + void (*glTranslatef)(float x, float y, float z); + void (*glGenBuffers)(int n, unsigned int *buffers); + void (*glBindBuffer)(unsigned int target, unsigned int buffer); + void (*glDeleteBuffers)(int n, const unsigned int *buffers); + void (*glBufferData)(unsigned int target, ssize_t size, const void *data, unsigned int usage); + void (*glBufferSubData)(unsigned int target, ssize_t offset, ssize_t size, const void *data); + void (*glDrawArrays)(unsigned int mode, int first, int count); + void (*glEnableClientState)(unsigned int cap); + void (*glVertexPointer)(int size, unsigned int type, int stride, const void *ptr); + void (*glColorPointer)(int size, unsigned int type, int stride, const void *ptr); + void (*glTexCoordPointer)(int size, unsigned int type, int stride, const void *ptr); /* Optional*/ void (*glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval); diff --git a/include/mgl/gl_macro.h b/include/mgl/gl_macro.h index a0bb16c..a3be960 100644 --- a/include/mgl/gl_macro.h +++ b/include/mgl/gl_macro.h @@ -49,8 +49,28 @@ #define GL_CLAMP_TO_EDGE 0x812F #define GL_LINEAR 0x2601 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 #define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 #define GL_PROJECTION 0x1701 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 + +#define GL_ARRAY_BUFFER 0x8892 + +#define GL_FLOAT 0x1406 + +#define GL_VERTEX_ARRAY 0x8074 +#define GL_COLOR_ARRAY 0x8076 +#define GL_TEXTURE_COORD_ARRAY 0x8078 + #endif /* MGL_GL_MACRO_H */ diff --git a/include/mgl/graphics/vertex.h b/include/mgl/graphics/vertex.h new file mode 100644 index 0000000..b4a5830 --- /dev/null +++ b/include/mgl/graphics/vertex.h @@ -0,0 +1,13 @@ +#ifndef MGL_VERTEX_H +#define MGL_VERTEX_H + +#include "color.h" +#include "../system/vec.h" + +typedef struct { + mgl_vec2f position; + mgl_color color; + mgl_vec2f texcoords; +} mgl_vertex; + +#endif /* MGL_VERTEX_H */ diff --git a/include/mgl/graphics/vertex_buffer.h b/include/mgl/graphics/vertex_buffer.h new file mode 100644 index 0000000..c1e4af1 --- /dev/null +++ b/include/mgl/graphics/vertex_buffer.h @@ -0,0 +1,44 @@ +#ifndef MGL_VERTEX_BUFFER_H +#define MGL_VERTEX_BUFFER_H + +#include "vertex.h" +#include <stddef.h> + +typedef struct mgl_context mgl_context; +typedef struct mgl_texture mgl_texture; + +typedef enum { + MGL_PRIMITIVE_POINTS, + MGL_PRIMITIVE_LINES, + MGL_PRIMITIVE_LINE_STRIP, + MGL_PRIMITIVE_TRIANGLES, + MGL_PRIMITIVE_TRIANGLE_STRIP, + MGL_PRIMITIVE_TRIANGLE_FAN, + MGL_PRIMITIVE_QUADS, + MGL_PRIMITIVE_QUAD_STRIP, + MGL_PRIMITIVE_POLYGON, +} mgl_primitive_type; + +typedef enum { + MGL_USAGE_STREAM, + MGL_USAGE_DYNAMIC, + MGL_USAGE_STATIC +} mgl_vertex_buffer_usage; + +typedef struct { + unsigned int id; + size_t vertex_count; + mgl_primitive_type primitive_type; + mgl_vertex_buffer_usage usage; + mgl_vec2f position; +} mgl_vertex_buffer; + +int mgl_vertex_buffer_init(mgl_vertex_buffer *self, mgl_primitive_type primitive_type, mgl_vertex_buffer_usage usage); +void mgl_vertex_buffer_deinit(mgl_vertex_buffer *self); + +void mgl_vertex_buffer_set_position(mgl_vertex_buffer *self, mgl_vec2f position); +int mgl_vertex_buffer_update(mgl_vertex_buffer *self, mgl_vertex *vertices, size_t vertex_count); +/* |texture| can be NULL to not use any texture */ +void mgl_vertex_buffer_draw(mgl_context *context, mgl_vertex_buffer *self, mgl_texture *texture); + +#endif /* MGL_VERTEX_BUFFER_H */ @@ -1,6 +1,6 @@ #include "../include/mgl/gl.h" #include <dlfcn.h> -#include <GL/gl.h> +/*#include <GL/gl.h>*/ #include <stdio.h> typedef struct { @@ -53,7 +53,20 @@ int mgl_gl_load(mgl_gl *self) { { &self->glTexCoord2f, "glTexCoord2f" }, { &self->glOrtho, "glOrtho" }, { &self->glMatrixMode, "glMatrixMode" }, + { &self->glPushMatrix, "glPushMatrix" }, + { &self->glPopMatrix, "glPopMatrix" }, { &self->glLoadIdentity, "glLoadIdentity" }, + { &self->glTranslatef, "glTranslatef" }, + { &self->glGenBuffers, "glGenBuffers" }, + { &self->glBindBuffer, "glBindBuffer" }, + { &self->glDeleteBuffers, "glDeleteBuffers" }, + { &self->glBufferData, "glBufferData" }, + { &self->glBufferSubData, "glBufferSubData" }, + { &self->glDrawArrays, "glDrawArrays" }, + { &self->glEnableClientState, "glEnableClientState" }, + { &self->glVertexPointer, "glVertexPointer" }, + { &self->glColorPointer, "glColorPointer" }, + { &self->glTexCoordPointer, "glTexCoordPointer" }, { NULL, NULL } }; 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(); +} diff --git a/src/window/window.c b/src/window/window.c index 80c3ccf..691a647 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -84,6 +84,9 @@ int mgl_window_create_with_params(mgl_window *self, const char *title, int width context->gl.glEnable(GL_TEXTURE_2D); context->gl.glEnable(GL_BLEND); context->gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + context->gl.glEnableClientState(GL_VERTEX_ARRAY); + context->gl.glEnableClientState(GL_COLOR_ARRAY); + context->gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY); XWindowAttributes gwa; gwa.width = 0; diff --git a/tests/main.c b/tests/main.c index 1675439..8631c35 100644 --- a/tests/main.c +++ b/tests/main.c @@ -7,10 +7,12 @@ #include <mgl/graphics/sprite.h> #include <mgl/graphics/font.h> #include <mgl/graphics/text.h> +#include <mgl/graphics/vertex_buffer.h> typedef struct { mgl_texture *texture; mgl_font *font; + mgl_vertex_buffer *vertex_buffer; } Userdata; static void draw(mgl_window *window, void *userdata) { @@ -33,6 +35,9 @@ static void draw(mgl_window *window, void *userdata) { mgl_text_init(&text, u->font, "hello world!\nGood bye world!", 0.0f, 0.0f); mgl_text_draw(context, &text); mgl_text_deinit(&text); + + mgl_vertex_buffer_set_position(u->vertex_buffer, (mgl_vec2f){ window->cursor_position.x, window->cursor_position.y }); + mgl_vertex_buffer_draw(context, u->vertex_buffer, &u->font->texture); } int main(int argc, char **argv) { @@ -41,10 +46,12 @@ int main(int argc, char **argv) { mgl_texture texture; mgl_font font; + mgl_vertex_buffer vertex_buffer; Userdata userdata; userdata.texture = &texture; userdata.font = &font; + userdata.vertex_buffer = &vertex_buffer; mgl_window window; if(mgl_window_create(&window, "mgl", 1280, 720) != 0) @@ -56,6 +63,37 @@ int main(int argc, char **argv) { if(mgl_font_load_from_file(&font, "/usr/share/fonts/noto/NotoSans-Regular.ttf", 32) != 0) return 1; + if(mgl_vertex_buffer_init(&vertex_buffer, MGL_PRIMITIVE_QUADS, MGL_USAGE_STATIC) != 0) + return 1; + + mgl_vertex vertices[4] = { + (mgl_vertex){ + .position = {0.0f, 0.0f}, + .color = {255, 0, 0, 100}, + .texcoords = {0.0f, 0.0f} + }, + (mgl_vertex){ + .position = {font.texture.width, 0.0f}, + .color = {0, 255, 0, 100}, + .texcoords = {1.0f, 0.0f} + }, + (mgl_vertex){ + .position = {font.texture.width, font.texture.height}, + .color = {0, 0, 255, 100}, + .texcoords = {1.0f, 1.0f} + }, + (mgl_vertex){ + .position = {0.0f, font.texture.height}, + .color = {255, 0, 255, 100}, + .texcoords = {0.0f, 1.0f} + } + }; + + if(mgl_vertex_buffer_update(&vertex_buffer, vertices, 4) != 0) + return 1; + + fprintf(stderr, "Font texture width: %d, texture height: %d\n", font.texture.width, font.texture.height); + mgl_event event; for(;;) { while(mgl_window_poll_event(&window, &event)) { @@ -67,6 +105,7 @@ int main(int argc, char **argv) { mgl_window_display(&window); } + mgl_vertex_buffer_deinit(&vertex_buffer); mgl_font_unload(&font); mgl_texture_unload(&texture); mgl_window_deinit(&window); |