diff options
Diffstat (limited to 'renderer.c')
| -rw-r--r-- | renderer.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/renderer.c b/renderer.c new file mode 100644 index 0000000..487d92d --- /dev/null +++ b/renderer.c @@ -0,0 +1,185 @@ +#include <SDL2/SDL.h> +#include <SDL2/SDL_opengl.h> +#include <assert.h> +#include "renderer.h" +#include "atlas.inl" + +#define BUFFER_SIZE 16384 + +static GLfloat tex_buf[BUFFER_SIZE * 8]; +static GLfloat vert_buf[BUFFER_SIZE * 8]; +static GLubyte color_buf[BUFFER_SIZE * 16]; +static GLuint index_buf[BUFFER_SIZE * 6]; + +static int width = 800; +static int height = 600; +static int buf_idx; + +static SDL_Window *window; + + +void r_init(void) { + /* init SDL window */ + window = SDL_CreateWindow( + NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + width, height, SDL_WINDOW_OPENGL); + SDL_GL_CreateContext(window); + + /* init gl */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + /* init texture */ + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ATLAS_WIDTH, ATLAS_HEIGHT, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, atlas_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + assert(glGetError() == 0); +} + + +static void flush(void) { + if (buf_idx == 0) { return; } + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glTexCoordPointer(2, GL_FLOAT, 0, tex_buf); + glVertexPointer(2, GL_FLOAT, 0, vert_buf); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, color_buf); + glDrawElements(GL_TRIANGLES, buf_idx * 6, GL_UNSIGNED_INT, index_buf); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + buf_idx = 0; +} + + +static void push_quad(mu_Rect dst, mu_Rect src, mu_Color color) { + if (buf_idx == BUFFER_SIZE) { flush(); } + + int texvert_idx = buf_idx * 8; + int color_idx = buf_idx * 16; + int element_idx = buf_idx * 4; + int index_idx = buf_idx * 6; + buf_idx++; + + /* update texture buffer */ + float x = src.x / (float) ATLAS_WIDTH; + float y = src.y / (float) ATLAS_HEIGHT; + float w = src.w / (float) ATLAS_WIDTH; + float h = src.h / (float) ATLAS_HEIGHT; + tex_buf[texvert_idx + 0] = x; + tex_buf[texvert_idx + 1] = y; + tex_buf[texvert_idx + 2] = x + w; + tex_buf[texvert_idx + 3] = y; + tex_buf[texvert_idx + 4] = x; + tex_buf[texvert_idx + 5] = y + h; + tex_buf[texvert_idx + 6] = x + w; + tex_buf[texvert_idx + 7] = y + h; + + /* update vertex buffer */ + vert_buf[texvert_idx + 0] = dst.x; + vert_buf[texvert_idx + 1] = dst.y; + vert_buf[texvert_idx + 2] = dst.x + dst.w; + vert_buf[texvert_idx + 3] = dst.y; + vert_buf[texvert_idx + 4] = dst.x; + vert_buf[texvert_idx + 5] = dst.y + dst.h; + vert_buf[texvert_idx + 6] = dst.x + dst.w; + vert_buf[texvert_idx + 7] = dst.y + dst.h; + + /* update color buffer */ + memcpy(color_buf + color_idx + 0, &color, 4); + memcpy(color_buf + color_idx + 4, &color, 4); + memcpy(color_buf + color_idx + 8, &color, 4); + memcpy(color_buf + color_idx + 12, &color, 4); + + /* update index buffer */ + index_buf[index_idx + 0] = element_idx + 0; + index_buf[index_idx + 1] = element_idx + 1; + index_buf[index_idx + 2] = element_idx + 2; + index_buf[index_idx + 3] = element_idx + 2; + index_buf[index_idx + 4] = element_idx + 3; + index_buf[index_idx + 5] = element_idx + 1; +} + + +void r_draw_rect(mu_Rect rect, mu_Color color) { + push_quad(rect, atlas[ATLAS_WHITE], color); +} + + +void r_draw_text(const char *text, mu_Vec2 pos, mu_Color color) { + mu_Rect dst = { pos.x, pos.y, 0, 0 }; + for (const char *p = text; *p; p++) { + if ((*p & 0xc0) == 0x80) { continue; } + int chr = mu_min((unsigned char) *p, 127); + mu_Rect src = atlas[ATLAS_FONT + chr]; + dst.w = src.w; + dst.h = src.h; + push_quad(dst, src, color); + dst.x += dst.w; + } +} + + +void r_draw_icon(int id, mu_Rect rect, mu_Color color) { + mu_Rect src = atlas[id]; + int x = rect.x + (rect.w - src.w) / 2; + int y = rect.y + (rect.h - src.h) / 2; + push_quad(mu_rect(x, y, src.w, src.h), src, color); +} + + +int r_get_text_width(const char *text, int len) { + int res = 0; + for (const char *p = text; *p && len--; p++) { + if ((*p & 0xc0) == 0x80) { continue; } + int chr = mu_min((unsigned char) *p, 127); + res += atlas[ATLAS_FONT + chr].w; + } + return res; +} + + +int r_get_text_height(void) { + return 18; +} + + +void r_set_clip_rect(mu_Rect rect) { + flush(); + glScissor(rect.x, height - (rect.y + rect.h), rect.w, rect.h); +} + + +void r_clear(mu_Color clr) { + flush(); + glClearColor(clr.r / 255., clr.g / 255., clr.b / 255., clr.a / 255.); + glClear(GL_COLOR_BUFFER_BIT); +} + + +void r_present(void) { + flush(); + SDL_GL_SwapWindow(window); +} |