Browse Source

Merge branch 'remove-free-glyph-renderer'

rexim 2 years ago
parent
commit
ef90e54187
9 changed files with 211 additions and 301 deletions
  1. 2 0
      shaders/simple.vert
  2. 0 0
      shaders/simple_color.frag
  3. 19 0
      shaders/simple_epic.frag
  4. 10 0
      shaders/simple_image.frag
  5. 65 197
      src/free_glyph.c
  6. 5 48
      src/free_glyph.h
  7. 43 43
      src/main.c
  8. 53 11
      src/simple_renderer.c
  9. 14 2
      src/simple_renderer.h

+ 2 - 0
shaders/simple.vert

@@ -10,6 +10,7 @@ layout(location = 1) in vec4 color;
 layout(location = 2) in vec2 uv;
 
 out vec4 out_color;
+out vec2 out_uv;
 
 vec2 camera_project(vec2 point)
 {
@@ -19,4 +20,5 @@ vec2 camera_project(vec2 point)
 void main() {
     gl_Position = vec4(camera_project(position), 0, 1);
     out_color = color;
+    out_uv = uv;
 }

+ 0 - 0
shaders/simple.frag → shaders/simple_color.frag


+ 19 - 0
shaders/simple_epic.frag

@@ -0,0 +1,19 @@
+#version 330 core
+
+uniform float time;
+uniform vec2 resolution;
+uniform sampler2D image;
+
+in vec2 out_uv;
+
+vec3 hsl2rgb(vec3 c) {
+    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0);
+    return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0));
+}
+
+void main() {
+    vec4 tc = texture(image, out_uv);
+    vec2 frag_uv = gl_FragCoord.xy / resolution;
+    vec4 rainbow = vec4(hsl2rgb(vec3((time + frag_uv.x + frag_uv.y), 0.5, 0.5)), 1.0);
+    gl_FragColor = tc.x * rainbow;
+}

+ 10 - 0
shaders/simple_image.frag

@@ -0,0 +1,10 @@
+#version 330 core
+
+uniform sampler2D image;
+
+in vec2 out_uv;
+
+void main() {
+    gl_FragColor = texture(image, out_uv);
+    // gl_FragColor = vec4(out_uv, 0, 1);
+}

+ 65 - 197
src/free_glyph.c

@@ -3,225 +3,84 @@
 #include "./free_glyph.h"
 #include "./gl_extra.h"
 
-typedef struct {
-    size_t offset;
-    GLint comps;
-    GLenum type;
-} Attr_Def;
-
-static const Attr_Def glyph_attr_defs[COUNT_FREE_GLYPH_ATTRS] = {
-    [FREE_GLYPH_ATTR_POS]   = {
-        .offset = offsetof(Free_Glyph, pos),
-        .comps = 2,
-        .type = GL_FLOAT
-    },
-    [FREE_GLYPH_ATTR_SIZE]   = {
-        .offset = offsetof(Free_Glyph, size),
-        .comps = 2,
-        .type = GL_FLOAT
-    },
-    [FREE_GLYPH_ATTR_UV_POS]    = {
-        .offset = offsetof(Free_Glyph, uv_pos),
-        .comps = 2,
-        .type = GL_FLOAT
-    },
-    [FREE_GLYPH_ATTR_UV_SIZE]    = {
-        .offset = offsetof(Free_Glyph, uv_size),
-        .comps = 2,
-        .type = GL_FLOAT
-    },
-    [FREE_GLYPH_ATTR_FG_COLOR] = {
-        .offset = offsetof(Free_Glyph, fg_color),
-        .comps = 4,
-        .type = GL_FLOAT
-    },
-    [FREE_GLYPH_ATTR_BG_COLOR] = {
-        .offset = offsetof(Free_Glyph, bg_color),
-        .comps = 4,
-        .type = GL_FLOAT
-    },
-};
-static_assert(COUNT_FREE_GLYPH_ATTRS == 6, "The amount of glyph vertex attributes have changed");
-
-
-void free_glyph_buffer_init(Free_Glyph_Buffer *fgb,
-                            FT_Face face,
-                            const char *vert_file_path,
-                            const char *frag_file_path)
+void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face)
 {
-    // Init Vertex Attributes
-    {
-        glGenVertexArrays(1, &fgb->vao);
-        glBindVertexArray(fgb->vao);
-
-        glGenBuffers(1, &fgb->vbo);
-        glBindBuffer(GL_ARRAY_BUFFER, fgb->vbo);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(fgb->glyphs), fgb->glyphs, GL_DYNAMIC_DRAW);
-
-        for (Free_Glyph_Attr attr = 0; attr < COUNT_FREE_GLYPH_ATTRS; ++attr) {
-            glEnableVertexAttribArray(attr);
-            switch (glyph_attr_defs[attr].type) {
-            case GL_FLOAT:
-                glVertexAttribPointer(
-                    attr,
-                    glyph_attr_defs[attr].comps,
-                    glyph_attr_defs[attr].type,
-                    GL_FALSE,
-                    sizeof(Free_Glyph),
-                    (void*) glyph_attr_defs[attr].offset);
-                break;
-
-            case GL_INT:
-                glVertexAttribIPointer(
-                    attr,
-                    glyph_attr_defs[attr].comps,
-                    glyph_attr_defs[attr].type,
-                    sizeof(Free_Glyph),
-                    (void*) glyph_attr_defs[attr].offset);
-                break;
-
-            default:
-                assert(false && "unreachable");
-                exit(1);
-            }
-            glVertexAttribDivisor(attr, 1);
-        }
-    }
-
-    // Init Shaders
-    {
-        GLuint shaders[3] = {0};
-
-        if (!compile_shader_file(vert_file_path, GL_VERTEX_SHADER, &shaders[0])) {
-            exit(1);
-        }
-        if (!compile_shader_file(frag_file_path, GL_FRAGMENT_SHADER, &shaders[1])) {
-            exit(1);
-        }
-        if (!compile_shader_file("./shaders/camera.vert", GL_VERTEX_SHADER, &shaders[2])) {
+    for (int i = 32; i < 128; ++i) {
+        if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
+            fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i);
             exit(1);
         }
 
-        fgb->program = glCreateProgram();
-        attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), fgb->program);
-        if (!link_program(fgb->program, __FILE__, __LINE__)) {
-            exit(1);
+        atlas->atlas_width += face->glyph->bitmap.width;
+        if (atlas->atlas_height < face->glyph->bitmap.rows) {
+            atlas->atlas_height = face->glyph->bitmap.rows;
         }
-
-        glUseProgram(fgb->program);
-        get_uniform_location(fgb->program, fgb->uniforms);
     }
 
-    // Glyph Texture Atlas
-    {
-        for (int i = 32; i < 128; ++i) {
-            if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
-                fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i);
-                exit(1);
-            }
-
-            fgb->atlas_width += face->glyph->bitmap.width;
-            if (fgb->atlas_height < face->glyph->bitmap.rows) {
-                fgb->atlas_height = face->glyph->bitmap.rows;
-            }
+    glActiveTexture(GL_TEXTURE0);
+    glGenTextures(1, &atlas->glyphs_texture);
+    glBindTexture(GL_TEXTURE_2D, atlas->glyphs_texture);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexImage2D(
+        GL_TEXTURE_2D,
+        0,
+        GL_RED,
+        (GLsizei) atlas->atlas_width,
+        (GLsizei) atlas->atlas_height,
+        0,
+        GL_RED,
+        GL_UNSIGNED_BYTE,
+        NULL);
+
+    int x = 0;
+    for (int i = 32; i < 128; ++i) {
+        if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
+            fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i);
+            exit(1);
         }
 
-        glActiveTexture(GL_TEXTURE0);
-        glGenTextures(1, &fgb->glyphs_texture);
-        glBindTexture(GL_TEXTURE_2D, fgb->glyphs_texture);
+        if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
+            fprintf(stderr, "ERROR: could not render glyph of a character with code %d\n", i);
+            exit(1);
+        }
 
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        atlas->metrics[i].ax = face->glyph->advance.x >> 6;
+        atlas->metrics[i].ay = face->glyph->advance.y >> 6;
+        atlas->metrics[i].bw = face->glyph->bitmap.width;
+        atlas->metrics[i].bh = face->glyph->bitmap.rows;
+        atlas->metrics[i].bl = face->glyph->bitmap_left;
+        atlas->metrics[i].bt = face->glyph->bitmap_top;
+        atlas->metrics[i].tx = (float) x / (float) atlas->atlas_width;
 
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        glTexImage2D(
+        glTexSubImage2D(
             GL_TEXTURE_2D,
             0,
-            GL_RED,
-            (GLsizei) fgb->atlas_width,
-            (GLsizei) fgb->atlas_height,
+            x,
             0,
+            face->glyph->bitmap.width,
+            face->glyph->bitmap.rows,
             GL_RED,
             GL_UNSIGNED_BYTE,
-            NULL);
-
-        int x = 0;
-        for (int i = 32; i < 128; ++i) {
-            if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
-                fprintf(stderr, "ERROR: could not load glyph of a character with code %d\n", i);
-                exit(1);
-            }
-
-            if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
-                fprintf(stderr, "ERROR: could not render glyph of a character with code %d\n", i);
-                exit(1);
-            }
-
-            fgb->metrics[i].ax = face->glyph->advance.x >> 6;
-            fgb->metrics[i].ay = face->glyph->advance.y >> 6;
-            fgb->metrics[i].bw = face->glyph->bitmap.width;
-            fgb->metrics[i].bh = face->glyph->bitmap.rows;
-            fgb->metrics[i].bl = face->glyph->bitmap_left;
-            fgb->metrics[i].bt = face->glyph->bitmap_top;
-            fgb->metrics[i].tx = (float) x / (float) fgb->atlas_width;
-
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-            glTexSubImage2D(
-                GL_TEXTURE_2D,
-                0,
-                x,
-                0,
-                face->glyph->bitmap.width,
-                face->glyph->bitmap.rows,
-                GL_RED,
-                GL_UNSIGNED_BYTE,
-                face->glyph->bitmap.buffer);
-            x += face->glyph->bitmap.width;
-        }
+            face->glyph->bitmap.buffer);
+        x += face->glyph->bitmap.width;
     }
 }
 
-void free_glyph_buffer_use(const Free_Glyph_Buffer *fgb)
-{
-    glBindVertexArray(fgb->vao);
-    glBindBuffer(GL_ARRAY_BUFFER, fgb->vbo);
-    glUseProgram(fgb->program);
-}
-
-void free_glyph_buffer_clear(Free_Glyph_Buffer *fgb)
-{
-    fgb->glyphs_count = 0;
-}
-
-void free_glyph_buffer_push(Free_Glyph_Buffer *fgb, Free_Glyph glyph)
-{
-    assert(fgb->glyphs_count < FREE_GLYPH_BUFFER_CAP);
-    fgb->glyphs[fgb->glyphs_count++] = glyph;
-}
-
-void free_glyph_buffer_sync(Free_Glyph_Buffer *fgb)
-{
-    glBufferSubData(GL_ARRAY_BUFFER,
-                    0,
-                    fgb->glyphs_count * sizeof(Free_Glyph),
-                    fgb->glyphs);
-}
-
-void free_glyph_buffer_draw(Free_Glyph_Buffer *fgb)
-{
-    glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei) fgb->glyphs_count);
-}
-
-float free_glyph_buffer_cursor_pos(const Free_Glyph_Buffer *fgb, const char *text, size_t text_size, Vec2f pos, size_t col)
+float free_glyph_atlas_cursor_pos(const Free_Glyph_Atlas *atlas, const char *text, size_t text_size, Vec2f pos, size_t col)
 {
     for (size_t i = 0; i < text_size; ++i) {
         if (i == col) {
             return pos.x;
         }
 
-        Glyph_Metric metric = fgb->metrics[(int) text[i]];
+        Glyph_Metric metric = atlas->metrics[(int) text[i]];
         pos.x += metric.ax;
         pos.y += metric.ay;
     }
@@ -229,10 +88,10 @@ float free_glyph_buffer_cursor_pos(const Free_Glyph_Buffer *fgb, const char *tex
     return pos.x;
 }
 
-void free_glyph_buffer_render_line_sized(Free_Glyph_Buffer *fgb, const char *text, size_t text_size, Vec2f *pos, Vec4f fg_color, Vec4f bg_color)
+void free_glyph_atlas_render_line_sized(Free_Glyph_Atlas *atlas, Simple_Renderer *sr, const char *text, size_t text_size, Vec2f *pos)
 {
     for (size_t i = 0; i < text_size; ++i) {
-        Glyph_Metric metric = fgb->metrics[(int) text[i]];
+        Glyph_Metric metric = atlas->metrics[(int) text[i]];
         float x2 = pos->x + metric.bl;
         float y2 = -pos->y - metric.bt;
         float w  = metric.bw;
@@ -241,13 +100,22 @@ void free_glyph_buffer_render_line_sized(Free_Glyph_Buffer *fgb, const char *tex
         pos->x += metric.ax;
         pos->y += metric.ay;
 
+        /*
         Free_Glyph glyph = {0};
         glyph.pos = vec2f(x2, -y2);
         glyph.size = vec2f(w, -h);
         glyph.uv_pos = vec2f(metric.tx, 0.0f);
-        glyph.uv_size = vec2f(metric.bw / (float) fgb->atlas_width, metric.bh / (float) fgb->atlas_height);
+        glyph.uv_size = vec2f(metric.bw / (float) atlas->atlas_width, metric.bh / (float) atlas->atlas_height);
         glyph.fg_color = fg_color;
         glyph.bg_color = bg_color;
-        free_glyph_buffer_push(fgb, glyph);
+        free_glyph_buffer_push(atlas, glyph);
+        */
+
+        simple_renderer_image_rect(
+            sr,
+            vec2f(x2, -y2),
+            vec2f(w, -h),
+            vec2f(metric.tx, 0.0f),
+            vec2f(metric.bw / (float) atlas->atlas_width, metric.bh / (float) atlas->atlas_height));
     }
 }

+ 5 - 48
src/free_glyph.h

@@ -13,29 +13,10 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
-#include "./uniforms.h"
+#include "simple_renderer.h"
 
 // https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02
 
-typedef struct {
-    Vec2f pos;
-    Vec2f size;
-    Vec2f uv_pos;
-    Vec2f uv_size;
-    Vec4f fg_color;
-    Vec4f bg_color;
-} Free_Glyph;
-
-typedef enum {
-    FREE_GLYPH_ATTR_POS = 0,
-    FREE_GLYPH_ATTR_SIZE,
-    FREE_GLYPH_ATTR_UV_POS,
-    FREE_GLYPH_ATTR_UV_SIZE,
-    FREE_GLYPH_ATTR_FG_COLOR,
-    FREE_GLYPH_ATTR_BG_COLOR,
-    COUNT_FREE_GLYPH_ATTRS,
-} Free_Glyph_Attr;
-
 typedef struct {
   float ax; // advance.x
   float ay; // advance.y
@@ -49,39 +30,15 @@ typedef struct {
   float tx; // x offset of glyph in texture coordinates
 } Glyph_Metric;
 
-#define FREE_GLYPH_BUFFER_CAP (640 * 1000)
-
 typedef struct {
-    GLuint vao;
-    GLuint vbo;
-    GLuint program;
-
     FT_UInt atlas_width;
     FT_UInt atlas_height;
-
     GLuint glyphs_texture;
-
-    GLint uniforms[COUNT_UNIFORM_SLOTS];
-
-    size_t glyphs_count;
-    Free_Glyph glyphs[FREE_GLYPH_BUFFER_CAP];
-    
     Glyph_Metric metrics[128];
-} Free_Glyph_Buffer;
-
-void free_glyph_buffer_init(Free_Glyph_Buffer *fgb,
-                            FT_Face face,
-                            const char *vert_file_path,
-                            const char *frag_file_path);
-void free_glyph_buffer_use(const Free_Glyph_Buffer *fgb);
-void free_glyph_buffer_clear(Free_Glyph_Buffer *fgb);
-void free_glyph_buffer_push(Free_Glyph_Buffer *fgb, Free_Glyph glyph);
-void free_glyph_buffer_sync(Free_Glyph_Buffer *fgb);
-void free_glyph_buffer_draw(Free_Glyph_Buffer *fgb);
-
-float free_glyph_buffer_cursor_pos(const Free_Glyph_Buffer *fgb, const char *text, size_t text_size, Vec2f pos, size_t col);
-
-void free_glyph_buffer_render_line_sized(Free_Glyph_Buffer *fgb, const char *text, size_t text_size, Vec2f *pos, Vec4f fg_color, Vec4f bg_color);
+} Free_Glyph_Atlas;
 
+void free_glyph_atlas_init(Free_Glyph_Atlas *atlas, FT_Face face);
+float free_glyph_atlas_cursor_pos(const Free_Glyph_Atlas *atlas, const char *text, size_t text_size, Vec2f pos, size_t col);
+void free_glyph_atlas_render_line_sized(Free_Glyph_Atlas *atlas, Simple_Renderer *sr, const char *text, size_t text_size, Vec2f *pos);
 
 #endif // FREE_GLYPH_H_

+ 43 - 43
src/main.c

@@ -66,48 +66,46 @@ void MessageCallback(GLenum source,
             type, severity, message);
 }
 
-static Free_Glyph_Buffer fgb = {0};
+static Free_Glyph_Atlas atlas = {0};
 static Simple_Renderer sr = {0};
 
 #define FREE_GLYPH_FONT_SIZE 64
 #define ZOOM_OUT_GLYPH_THRESHOLD 30
 
-void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Simple_Renderer *sr, Editor *editor)
+void render_editor(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr, Editor *editor)
 {
     int w, h;
     SDL_GetWindowSize(window, &w, &h);
 
     float max_line_len = 0.0f;
 
-    free_glyph_buffer_use(fgb);
-    {
-        glUniform2f(fgb->uniforms[UNIFORM_SLOT_RESOLUTION], (float) w, (float) h);
-        glUniform1f(fgb->uniforms[UNIFORM_SLOT_TIME], (float) SDL_GetTicks() / 1000.0f);
-        glUniform2f(fgb->uniforms[UNIFORM_SLOT_CAMERA_POS], camera_pos.x, camera_pos.y);
-        glUniform1f(fgb->uniforms[UNIFORM_SLOT_CAMERA_SCALE], camera_scale);
-
-        free_glyph_buffer_clear(fgb);
+    simple_renderer_use(sr);
 
-        {
-            for (size_t row = 0; row < editor->lines.count; ++row) {
-                Line line = editor->lines.items[row];
-
-                const Vec2f begin = vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE);
-                Vec2f end = begin;
-                free_glyph_buffer_render_line_sized(
-                    fgb, editor->data.items + line.begin, line.end - line.begin,
-                    &end,
-                    vec4fs(1.0f), vec4fs(0.0f));
-                // TODO: the max_line_len should be calculated based on what's visible on the screen right now
-                float line_len = fabsf(end.x - begin.x);
-                if (line_len > max_line_len) {
-                    max_line_len = line_len;
-                }
+    // Render text
+    simple_renderer_set_shader(sr, SHADER_FOR_EPICNESS);
+    glUniform2f(sr->uniforms[UNIFORM_SLOT_RESOLUTION], (float) w, (float) h);
+    glUniform1f(sr->uniforms[UNIFORM_SLOT_TIME], (float) SDL_GetTicks() / 1000.0f);
+    glUniform2f(sr->uniforms[UNIFORM_SLOT_CAMERA_POS], camera_pos.x, camera_pos.y);
+    glUniform1f(sr->uniforms[UNIFORM_SLOT_CAMERA_SCALE], camera_scale);
+    {
+        for (size_t row = 0; row < editor->lines.count; ++row) {
+            Line line = editor->lines.items[row];
+
+            const Vec2f begin = vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE);
+            Vec2f end = begin;
+            free_glyph_atlas_render_line_sized(
+                atlas, sr, editor->data.items + line.begin, line.end - line.begin,
+                &end);
+            // TODO: the max_line_len should be calculated based on what's visible on the screen right now
+            float line_len = fabsf(end.x - begin.x);
+            if (line_len > max_line_len) {
+                max_line_len = line_len;
             }
         }
 
-        free_glyph_buffer_sync(fgb);
-        free_glyph_buffer_draw(fgb);
+        simple_renderer_sync(sr);
+        simple_renderer_draw(sr);
+        sr->verticies_count = 0;
     }
 
     Vec2f cursor_pos = vec2fs(0.0f);
@@ -116,36 +114,40 @@ void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Simple_R
         Line line = editor->lines.items[cursor_row];
         size_t cursor_col = editor->cursor - line.begin;
         cursor_pos.y = -(float) cursor_row * FREE_GLYPH_FONT_SIZE;
-        cursor_pos.x = free_glyph_buffer_cursor_pos(
-                           fgb,
+        cursor_pos.x = free_glyph_atlas_cursor_pos(
+                           atlas,
                            editor->data.items + line.begin, line.end - line.begin,
                            vec2f(0.0, cursor_pos.y),
                            cursor_col
                        );
     }
 
-    simple_renderer_use(sr);
+    // Render cursor
+    simple_renderer_set_shader(sr, SHADER_FOR_COLOR);
+    glUniform2f(sr->uniforms[UNIFORM_SLOT_RESOLUTION], (float) w, (float) h);
+    glUniform1f(sr->uniforms[UNIFORM_SLOT_TIME], (float) SDL_GetTicks() / 1000.0f);
+    glUniform2f(sr->uniforms[UNIFORM_SLOT_CAMERA_POS], camera_pos.x, camera_pos.y);
+    glUniform1f(sr->uniforms[UNIFORM_SLOT_CAMERA_SCALE], camera_scale);
     {
-        glUniform2f(sr->uniforms[UNIFORM_SLOT_RESOLUTION], (float) w, (float) h);
-        glUniform1f(sr->uniforms[UNIFORM_SLOT_TIME], (float) SDL_GetTicks() / 1000.0f);
-        glUniform2f(sr->uniforms[UNIFORM_SLOT_CAMERA_POS], camera_pos.x, camera_pos.y);
-        glUniform1f(sr->uniforms[UNIFORM_SLOT_CAMERA_SCALE], camera_scale);
-
-        sr->verticies_count = 0;
         float CURSOR_WIDTH = 5.0f;
         Uint32 CURSOR_BLINK_THRESHOLD = 500;
         Uint32 CURSOR_BLINK_PERIOD = 1000;
         Uint32 t = SDL_GetTicks() - last_stroke;
+
+        sr->verticies_count = 0;
         if (t < CURSOR_BLINK_THRESHOLD || t/CURSOR_BLINK_PERIOD%2 != 0) {
             simple_renderer_solid_rect(
                 sr,
                 cursor_pos, vec2f(CURSOR_WIDTH, FREE_GLYPH_FONT_SIZE),
                 vec4fs(1));
         }
+
         simple_renderer_sync(sr);
         simple_renderer_draw(sr);
+        sr->verticies_count = 0;
     }
 
+    // Update camera
     {
         float target_scale = 3.0f;
         if (max_line_len > 0.0f) {
@@ -261,14 +263,12 @@ int main(int argc, char **argv)
     }
 
 
-    free_glyph_buffer_init(&fgb,
-                           face,
-                           "./shaders/free_glyph.vert",
-                           "./shaders/free_glyph.frag");
-
     simple_renderer_init(&sr,
                          "./shaders/simple.vert",
-                         "./shaders/simple.frag");
+                         "./shaders/simple_color.frag",
+                         "./shaders/simple_image.frag",
+                         "./shaders/simple_epic.frag");
+    free_glyph_atlas_init(&atlas, face);
 
     bool quit = false;
     while (!quit) {
@@ -357,7 +357,7 @@ int main(int argc, char **argv)
         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
         glClear(GL_COLOR_BUFFER_BIT);
 
-        render_editor_into_fgb(window, &fgb, &sr, &editor);
+        render_editor(window, &atlas, &sr, &editor);
 
         SDL_GL_SwapWindow(window);
 

+ 53 - 11
src/simple_renderer.c

@@ -13,7 +13,9 @@
 
 void simple_renderer_init(Simple_Renderer *sr,
                           const char *vert_file_path,
-                          const char *frag_file_path)
+                          const char *color_frag_file_path,
+                          const char *image_frag_file_path,
+                          const char *epic_frag_file_path)
 {
     {
         glGenVertexArrays(1, &sr->vao);
@@ -55,29 +57,52 @@ void simple_renderer_init(Simple_Renderer *sr,
     }
 
     GLuint shaders[2] = {0};
+
     if (!compile_shader_file(vert_file_path, GL_VERTEX_SHADER, &shaders[0])) {
         exit(1);
     }
-    if (!compile_shader_file(frag_file_path, GL_FRAGMENT_SHADER, &shaders[1])) {
-        exit(1);
-    }
 
-    sr->program = glCreateProgram();
-    attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), sr->program);
-    if (!link_program(sr->program, __FILE__, __LINE__)) {
-        exit(1);
+    // Shader for color
+    {
+        if (!compile_shader_file(color_frag_file_path, GL_FRAGMENT_SHADER, &shaders[1])) {
+            exit(1);
+        }
+        sr->programs[SHADER_FOR_COLOR] = glCreateProgram();
+        attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), sr->programs[SHADER_FOR_COLOR]);
+        if (!link_program(sr->programs[SHADER_FOR_COLOR], __FILE__, __LINE__)) {
+            exit(1);
+        }
     }
 
-    glUseProgram(sr->program);
+    // Shader for image
+    {
+        if (!compile_shader_file(image_frag_file_path, GL_FRAGMENT_SHADER, &shaders[1])) {
+            exit(1);
+        }
+        sr->programs[SHADER_FOR_IMAGE] = glCreateProgram();
+        attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), sr->programs[SHADER_FOR_IMAGE]);
+        if (!link_program(sr->programs[SHADER_FOR_IMAGE], __FILE__, __LINE__)) {
+            exit(1);
+        }
+    }
 
-    get_uniform_location(sr->program, sr->uniforms);
+    // Shader for epicness
+    {
+        if (!compile_shader_file(epic_frag_file_path, GL_FRAGMENT_SHADER, &shaders[1])) {
+            exit(1);
+        }
+        sr->programs[SHADER_FOR_EPICNESS] = glCreateProgram();
+        attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), sr->programs[SHADER_FOR_EPICNESS]);
+        if (!link_program(sr->programs[SHADER_FOR_EPICNESS], __FILE__, __LINE__)) {
+            exit(1);
+        }
+    }
 }
 
 void simple_renderer_use(const Simple_Renderer *sr)
 {
     glBindVertexArray(sr->vao);
     glBindBuffer(GL_ARRAY_BUFFER, sr->vbo);
-    glUseProgram(sr->program);
 }
 
 void simple_renderer_vertex(Simple_Renderer *sr,
@@ -113,6 +138,16 @@ void simple_renderer_quad(Simple_Renderer *sr,
     simple_renderer_triangle(sr, p1, p2, p3, c1, c2, c3, uv1, uv2, uv3);
 }
 
+void simple_renderer_image_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec2f uvp, Vec2f uvs)
+{
+    Vec4f c = vec4fs(0);
+    simple_renderer_quad(
+        sr,
+        p, vec2f_add(p, vec2f(s.x, 0)), vec2f_add(p, vec2f(0, s.y)), vec2f_add(p, s),
+        c, c, c, c,
+        uvp, vec2f_add(uvp, vec2f(uvs.x, 0)), vec2f_add(uvp, vec2f(0, uvs.y)), vec2f_add(uvp, uvs));
+}
+
 void simple_renderer_solid_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec4f c)
 {
     Vec2f uv = vec2fs(0);
@@ -135,3 +170,10 @@ void simple_renderer_draw(Simple_Renderer *sr)
 {
     glDrawArrays(GL_TRIANGLES, 0, sr->verticies_count);
 }
+
+void simple_renderer_set_shader(Simple_Renderer *sr, Simple_Shader shader)
+{
+    sr->current_shader = shader;
+    glUseProgram(sr->programs[sr->current_shader]);
+    get_uniform_location(sr->programs[sr->current_shader], sr->uniforms);
+}

+ 14 - 2
src/simple_renderer.h

@@ -24,10 +24,18 @@ typedef struct {
 
 #define SIMPLE_VERTICIES_CAP (3*640*1000)
 
+typedef enum {
+    SHADER_FOR_COLOR = 0,
+    SHADER_FOR_IMAGE,
+    SHADER_FOR_EPICNESS,
+    COUNT_SIMPLE_SHADERS,
+} Simple_Shader;
+
 typedef struct {
     GLuint vao;
     GLuint vbo;
-    GLuint program;
+    GLuint programs[COUNT_SIMPLE_SHADERS];
+    Simple_Shader current_shader;
 
     GLint uniforms[COUNT_UNIFORM_SLOTS];
     Simple_Vertex verticies[SIMPLE_VERTICIES_CAP];
@@ -36,11 +44,14 @@ typedef struct {
 
 void simple_renderer_init(Simple_Renderer *sr,
                           const char *vert_file_path,
-                          const char *frag_file_path);
+                          const char *color_frag_file_path,
+                          const char *image_frag_file_path,
+                          const char *epic_frag_file_path);
 
 void simple_renderer_use(const Simple_Renderer *sr);
 void simple_renderer_vertex(Simple_Renderer *sr,
                             Vec2f p, Vec4f c, Vec2f uv);
+void simple_renderer_set_shader(Simple_Renderer *sr, Simple_Shader shader);
 void simple_renderer_triangle(Simple_Renderer *sr,
                               Vec2f p0, Vec2f p1, Vec2f p2,
                               Vec4f c0, Vec4f c1, Vec4f c2,
@@ -50,6 +61,7 @@ void simple_renderer_quad(Simple_Renderer *sr,
                           Vec4f c0, Vec4f c1, Vec4f c2, Vec4f c3,
                           Vec2f uv0, Vec2f uv1, Vec2f uv2, Vec2f uv3);
 void simple_renderer_solid_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec4f c);
+void simple_renderer_image_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec2f uvp, Vec2f uvs);
 void simple_renderer_sync(Simple_Renderer *sr);
 void simple_renderer_draw(Simple_Renderer *sr);