Kaynağa Gözat

Merge pull request #30 from tsoding/27

(#27) Add cursor rendering to Free_Glyph
Alexey Kutepov 4 yıl önce
ebeveyn
işleme
b4b6f8dca5
8 değiştirilmiş dosya ile 223 ekleme ve 24 silme
  1. 1 1
      build.sh
  2. 14 0
      shaders/cursor.frag
  3. 23 0
      shaders/cursor.vert
  4. 48 0
      src/cursor_renderer.c
  5. 31 0
      src/cursor_renderer.h
  6. 27 6
      src/free_glyph.c
  7. 4 0
      src/free_glyph.h
  8. 75 17
      src/main.c

+ 1 - 1
build.sh

@@ -6,7 +6,7 @@ CC="${CXX:-cc}"
 PKGS="sdl2 glew freetype2"
 CFLAGS="-Wall -Wextra -std=c11 -pedantic -ggdb"
 LIBS=-lm
-SRC="src/main.c src/la.c src/editor.c src/sdl_extra.c src/file.c src/gl_extra.c src/tile_glyph.c src/free_glyph.c"
+SRC="src/main.c src/la.c src/editor.c src/sdl_extra.c src/file.c src/gl_extra.c src/tile_glyph.c src/free_glyph.c src/cursor_renderer.c"
 
 if [ `uname` = "Darwin" ]; then
     CFLAGS+=" -framework OpenGL"

+ 14 - 0
shaders/cursor.frag

@@ -0,0 +1,14 @@
+#version 330 core
+
+#define PERIOD 1.0
+#define BLINK_THRESHOLD 0.5
+
+uniform float time;
+uniform float last_stroke;
+
+void main() {
+    float t = time - last_stroke;
+    float threshold = float(t < BLINK_THRESHOLD);
+    float blink = mod(floor(t / PERIOD), 2);
+    gl_FragColor = vec4(1.0) * min(threshold + blink, 1.0);
+}

+ 23 - 0
shaders/cursor.vert

@@ -0,0 +1,23 @@
+#version 330 core
+
+uniform vec2 resolution;
+uniform vec2 camera;
+uniform vec2 pos;
+uniform float height;
+
+#define WIDTH 5.0
+
+out vec2 uv;
+
+vec2 project_point(vec2 point)
+{
+    return 2.0 * (point - camera) / resolution;
+}
+
+void main() {
+    uv = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));
+    gl_Position = vec4(
+        project_point(uv * vec2(WIDTH, height) + pos),
+        0.0,
+        1.0);
+}

+ 48 - 0
src/cursor_renderer.c

@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include "./gl_extra.h"
+#include "./cursor_renderer.h"
+
+void cursor_renderer_init(Cursor_Renderer *cr,
+                          const char *vert_file_path,
+                          const char *frag_file_path)
+{
+    // Init Shaders
+    {
+        GLuint vert_shader = 0;
+        if (!compile_shader_file(vert_file_path, GL_VERTEX_SHADER, &vert_shader)) {
+            exit(1);
+        }
+        GLuint frag_shader = 0;
+        if (!compile_shader_file(frag_file_path, GL_FRAGMENT_SHADER, &frag_shader)) {
+            exit(1);
+        }
+
+        if (!link_program(vert_shader, frag_shader, &cr->program)) {
+            exit(1);
+        }
+
+        glUseProgram(cr->program);
+
+        cr->time_uniform = glGetUniformLocation(cr->program, "time");
+        cr->resolution_uniform = glGetUniformLocation(cr->program, "resolution");
+        cr->camera_uniform = glGetUniformLocation(cr->program, "camera");
+        cr->pos_uniform = glGetUniformLocation(cr->program, "pos");
+        cr->height_uniform = glGetUniformLocation(cr->program, "height");
+        cr->last_stroke_uniform = glGetUniformLocation(cr->program, "last_stroke");
+    }
+}
+
+void cursor_renderer_use(const Cursor_Renderer *cr)
+{
+    glUseProgram(cr->program);
+}
+
+void cursor_renderer_move_to(const Cursor_Renderer *cr, Vec2f pos)
+{
+    glUniform2f(cr->pos_uniform, pos.x, pos.y);
+}
+
+void cursor_renderer_draw()
+{
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}

+ 31 - 0
src/cursor_renderer.h

@@ -0,0 +1,31 @@
+#ifndef CURSOR_RENDERER_H_
+#define CURSOR_RENDERER_H_
+
+#define GLEW_STATIC
+#include <GL/glew.h>
+
+#define GL_GLEXT_PROTOTYPES
+#include <SDL2/SDL_opengl.h>
+
+#include "./la.h"
+
+typedef struct {
+    GLuint program;
+
+    GLint time_uniform;
+    GLint resolution_uniform;
+    GLint camera_uniform;
+    GLint pos_uniform;
+    GLint height_uniform;
+    GLint last_stroke_uniform;
+} Cursor_Renderer;
+
+void cursor_renderer_init(Cursor_Renderer *cr,
+                          const char *vert_file_path,
+                          const char *frag_file_path);
+
+void cursor_renderer_use(const Cursor_Renderer *cr);
+void cursor_renderer_move_to(const Cursor_Renderer *cr, Vec2f pos);
+void cursor_renderer_draw(void);
+
+#endif // CURSOR_RENDERER_H_

+ 27 - 6
src/free_glyph.c

@@ -102,16 +102,15 @@ void free_glyph_buffer_init(Free_Glyph_Buffer *fgb,
             exit(1);
         }
 
-        GLuint program = 0;
-        if (!link_program(vert_shader, frag_shader, &program)) {
+        if (!link_program(vert_shader, frag_shader, &fgb->program)) {
             exit(1);
         }
 
-        glUseProgram(program);
+        glUseProgram(fgb->program);
 
-        fgb->time_uniform = glGetUniformLocation(program, "time");
-        fgb->resolution_uniform = glGetUniformLocation(program, "resolution");
-        fgb->camera_uniform = glGetUniformLocation(program, "camera");
+        fgb->time_uniform = glGetUniformLocation(fgb->program, "time");
+        fgb->resolution_uniform = glGetUniformLocation(fgb->program, "resolution");
+        fgb->camera_uniform = glGetUniformLocation(fgb->program, "camera");
     }
 
     // Glyph Texture Atlas
@@ -185,6 +184,13 @@ void free_glyph_buffer_init(Free_Glyph_Buffer *fgb,
     }
 }
 
+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;
@@ -209,6 +215,21 @@ 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)
+{
+    for (size_t i = 0; i < text_size; ++i) {
+        if (i == col) {
+            return pos.x;
+        }
+
+        Glyph_Metric metric = fgb->metrics[(int) text[i]];
+        pos.x += metric.ax;
+        pos.y += metric.ay;
+    }
+
+    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)
 {
     for (size_t i = 0; i < text_size; ++i) {

+ 4 - 0
src/free_glyph.h

@@ -52,6 +52,7 @@ typedef struct {
 typedef struct {
     GLuint vao;
     GLuint vbo;
+    GLuint program;
 
     FT_UInt atlas_width;
     FT_UInt atlas_height;
@@ -72,11 +73,14 @@ 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);
 void free_glyph_buffer_render_line(Free_Glyph_Buffer *fgb, const char *text, Vec2f pos, Vec4f fg_color, Vec4f bg_color);
 

+ 75 - 17
src/main.c

@@ -26,6 +26,7 @@
 #include "./gl_extra.h"
 #include "./tile_glyph.h"
 #include "./free_glyph.h"
+#include "./cursor_renderer.h"
 
 #define SCREEN_WIDTH 800
 #define SCREEN_HEIGHT 600
@@ -80,6 +81,7 @@ void gl_render_cursor(Tile_Glyph_Buffer *tgb)
 static Tile_Glyph_Buffer tgb = {0};
 #else
 static Free_Glyph_Buffer fgb = {0};
+static Cursor_Renderer cr = {0};
 #endif
 
 void render_editor_into_tgb(SDL_Window *window, Tile_Glyph_Buffer *tgb, Editor *editor)
@@ -119,31 +121,51 @@ void render_editor_into_tgb(SDL_Window *window, Tile_Glyph_Buffer *tgb, Editor *
 // TODO(#27): Free_Glyph renderer does not support cursor
 // TODO(#28): Camera location is broken in Free_Glyph Renderer
 
-void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Editor *editor)
+void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Cursor_Renderer *cr, Editor *editor)
 {
+    int w, h;
+    SDL_GetWindowSize(window, &w, &h);
+
+    free_glyph_buffer_use(fgb);
     {
-        int w, h;
-        SDL_GetWindowSize(window, &w, &h);
         glUniform2f(fgb->resolution_uniform, (float) w, (float) h);
-    }
+        glUniform1f(fgb->time_uniform, (float) SDL_GetTicks() / 1000.0f);
+        glUniform2f(fgb->camera_uniform, camera_pos.x, camera_pos.y);
+
+        free_glyph_buffer_clear(fgb);
 
-    glUniform1f(fgb->time_uniform, (float) SDL_GetTicks() / 1000.0f);
-    glUniform2f(fgb->camera_uniform, camera_pos.x, camera_pos.y);
+        {
+            for (size_t row = 0; row < editor->size; ++row) {
+                const Line *line = editor->lines + row;
+                free_glyph_buffer_render_line_sized(
+                    fgb, line->chars, line->size,
+                    vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE),
+                    vec4fs(1.0f), vec4fs(0.0f));
+            }
+        }
 
-    free_glyph_buffer_clear(fgb);
+        free_glyph_buffer_sync(fgb);
+        free_glyph_buffer_draw(fgb);
+    }
 
+    cursor_renderer_use(cr);
     {
-        for (size_t row = 0; row < editor->size; ++row) {
-            const Line *line = editor->lines + row;
-            free_glyph_buffer_render_line_sized(
-                fgb, line->chars, line->size,
-                vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE),
-                vec4fs(1.0f), vec4fs(0.0f));
+        glUniform2f(cr->resolution_uniform, (float) w, (float) h);
+        glUniform1f(cr->time_uniform, (float) SDL_GetTicks() / 1000.0f);
+        glUniform2f(cr->camera_uniform, camera_pos.x, camera_pos.y);
+        glUniform1f(cr->height_uniform, FREE_GLYPH_FONT_SIZE);
+
+        float y = -(float) editor->cursor_row * FREE_GLYPH_FONT_SIZE;
+
+        float x = 0.0f;
+        if (editor->cursor_row < editor->size) {
+            Line *line = &editor->lines[editor->cursor_row];
+            x = free_glyph_buffer_cursor_pos(fgb, line->chars, line->size, vec2f(0.0, y), editor->cursor_col);
         }
-    }
 
-    free_glyph_buffer_sync(fgb);
-    free_glyph_buffer_draw(fgb);
+        cursor_renderer_move_to(cr, vec2f(x, y));
+        cursor_renderer_draw();
+    }
 }
 
 int main(int argc, char **argv)
@@ -246,6 +268,9 @@ int main(int argc, char **argv)
                            face,
                            "./shaders/free_glyph.vert",
                            "./shaders/free_glyph.frag");
+    cursor_renderer_init(&cr,
+                         "./shaders/cursor.vert",
+                         "./shaders/cursor.frag");
 #endif
 
     bool quit = false;
@@ -263,6 +288,10 @@ int main(int argc, char **argv)
                 switch (event.key.keysym.sym) {
                 case SDLK_BACKSPACE: {
                     editor_backspace(&editor);
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                 }
                 break;
 
@@ -275,11 +304,19 @@ int main(int argc, char **argv)
 
                 case SDLK_RETURN: {
                     editor_insert_new_line(&editor);
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                 }
                 break;
 
                 case SDLK_DELETE: {
                     editor_delete(&editor);
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                 }
                 break;
 
@@ -287,23 +324,40 @@ int main(int argc, char **argv)
                     if (editor.cursor_row > 0) {
                         editor.cursor_row -= 1;
                     }
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                 }
                 break;
 
                 case SDLK_DOWN: {
                     editor.cursor_row += 1;
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                 }
                 break;
 
                 case SDLK_LEFT: {
                     if (editor.cursor_col > 0) {
                         editor.cursor_col -= 1;
+#ifndef TILE_GLYPH_RENDER
+                        cursor_renderer_use(&cr);
+                        glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
                     }
                 }
                 break;
 
                 case SDLK_RIGHT: {
                     editor.cursor_col += 1;
+#ifndef TILE_GLYPH_RENDER
+                    cursor_renderer_use(&cr);
+                    glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
+
                 }
                 break;
                 }
@@ -312,6 +366,10 @@ int main(int argc, char **argv)
 
             case SDL_TEXTINPUT: {
                 editor_insert_text_before_cursor(&editor, event.text.text);
+#ifndef TILE_GLYPH_RENDER
+                cursor_renderer_use(&cr);
+                glUniform1f(cr.last_stroke_uniform, (float) SDL_GetTicks() / 1000.0f);
+#endif
             }
             break;
 
@@ -360,7 +418,7 @@ int main(int argc, char **argv)
 #ifdef TILE_GLYPH_RENDER
         render_editor_into_tgb(window, &tgb, &editor);
 #else
-        render_editor_into_fgb(window, &fgb, &editor);
+        render_editor_into_fgb(window, &fgb, &cr, &editor);
 #endif // TILE_GLYPH_RENDER
 
         SDL_GL_SwapWindow(window);