commit 74d8f392326f8a022f095c65f8600169062ab1d5
parent 63849dae94251bd96ae1c552d9a2bb79b997ec18
Author: rexim <reximkut@gmail.com>
Date: Sat, 10 Jul 2021 21:29:23 +0700
Factor out the Tile_Glyph renderer
Diffstat:
6 files changed, 265 insertions(+), 214 deletions(-)
diff --git a/build.sh b/build.sh
@@ -6,7 +6,7 @@ CC="${CXX:-cc}"
PKGS="sdl2 glew"
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="src/main.c src/la.c src/editor.c src/sdl_extra.c src/file.c src/gl_extra.c src/tile_glyph.c"
if [ `uname` = "Darwin" ]; then
CFLAGS+=" -framework OpenGL"
diff --git a/shaders/font.frag b/shaders/tile_glyph.frag
diff --git a/shaders/font.vert b/shaders/tile_glyph.vert
diff --git a/src/main.c b/src/main.c
@@ -18,19 +18,13 @@
#include "./la.h"
#include "./sdl_extra.h"
#include "./gl_extra.h"
+#include "./tile_glyph.h"
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define FPS 60
#define DELTA_TIME (1.0f / FPS)
-#define FONT_SCALE 5
-#define FONT_WIDTH 128
-#define FONT_HEIGHT 64
-#define FONT_COLS 18
-#define FONT_ROWS 7
-#define FONT_CHAR_WIDTH (FONT_WIDTH / FONT_COLS)
-#define FONT_CHAR_HEIGHT (FONT_HEIGHT / FONT_ROWS)
Editor editor = {0};
Vec2f camera_pos = {0};
@@ -66,99 +60,15 @@ void MessageCallback(GLenum source,
type, severity, message);
}
-typedef struct {
- Vec2i tile;
- int ch;
- Vec4f fg_color;
- Vec4f bg_color;
-} Tile_Glyph;
-
-typedef enum {
- TILE_GLYPH_ATTR_TILE = 0,
- TILE_GLYPH_ATTR_CH,
- TILE_GLYPH_ATTR_FG_COLOR,
- TILE_GLYPH_ATTR_BG_COLOR,
- COUNT_TILE_GLYPH_ATTRS,
-} Tile_Glyph_Attr;
-
-typedef struct {
- size_t offset;
- GLint comps;
- GLenum type;
-} Attr_Def;
-
-static const Attr_Def glyph_attr_defs[COUNT_TILE_GLYPH_ATTRS] = {
- [TILE_GLYPH_ATTR_TILE] = {
- .offset = offsetof(Tile_Glyph, tile),
- .comps = 2,
- .type = GL_INT
- },
- [TILE_GLYPH_ATTR_CH] = {
- .offset = offsetof(Tile_Glyph, ch),
- .comps = 1,
- .type = GL_INT
- },
- [TILE_GLYPH_ATTR_FG_COLOR] = {
- .offset = offsetof(Tile_Glyph, fg_color),
- .comps = 4,
- .type = GL_FLOAT
- },
- [TILE_GLYPH_ATTR_BG_COLOR] = {
- .offset = offsetof(Tile_Glyph, bg_color),
- .comps = 4,
- .type = GL_FLOAT
- },
-};
-static_assert(COUNT_TILE_GLYPH_ATTRS == 4, "The amount of glyph vertex attributes have changed");
-
-#define TILE_GLYPH_BUFFER_CAP (640 * 1024)
-
-Tile_Glyph tile_glyph_buffer[TILE_GLYPH_BUFFER_CAP];
-size_t tile_glyph_buffer_count = 0;
-
-void tile_glyph_buffer_clear(void)
-{
- tile_glyph_buffer_count = 0;
-}
-
-void tile_glyph_buffer_push(Tile_Glyph glyph)
-{
- assert(tile_glyph_buffer_count < TILE_GLYPH_BUFFER_CAP);
- tile_glyph_buffer[tile_glyph_buffer_count++] = glyph;
-}
-
-void tile_glyph_buffer_sync(void)
-{
- glBufferSubData(GL_ARRAY_BUFFER,
- 0,
- tile_glyph_buffer_count * sizeof(Tile_Glyph),
- tile_glyph_buffer);
-}
-
-void gl_render_text_sized(const char *text, size_t text_size, Vec2i tile, Vec4f fg_color, Vec4f bg_color)
-{
- for (size_t i = 0; i < text_size; ++i) {
- tile_glyph_buffer_push((Tile_Glyph) {
- .tile = vec2i_add(tile, vec2i((int) i, 0)),
- .ch = text[i],
- .fg_color = fg_color,
- .bg_color = bg_color,
- });
- }
-}
-
-void gl_render_text(const char *text, Vec2i tile, Vec4f fg_color, Vec4f bg_color)
-{
- gl_render_text_sized(text, strlen(text), tile, fg_color, bg_color);
-}
-
-void gl_render_cursor()
+void gl_render_cursor(Tile_Glyph_Buffer *tgb)
{
const char *c = editor_char_under_cursor(&editor);
Vec2i tile = vec2i((int) editor.cursor_col, -(int) editor.cursor_row);
- gl_render_text_sized(c ? c : " ", 1, tile, vec4fs(0.0f), vec4fs(1.0f));
+ tile_glyph_render_line_sized(tgb, c ? c : " ", 1, tile, vec4fs(0.0f), vec4fs(1.0f));
}
+static Tile_Glyph_Buffer tgb = {0};
+
// OPENGL
int main(int argc, char **argv)
{
@@ -223,113 +133,10 @@ int main(int argc, char **argv)
fprintf(stderr, "WARNING! GLEW_ARB_debug_output is not available");
}
- GLint time_uniform;
- GLint resolution_uniform;
- GLint scale_uniform;
- GLint camera_uniform;
-
- // Initialize Shaders
- {
- GLuint vert_shader = 0;
- if (!compile_shader_file("./shaders/font.vert", GL_VERTEX_SHADER, &vert_shader)) {
- exit(1);
- }
- GLuint frag_shader = 0;
- if (!compile_shader_file("./shaders/font.frag", GL_FRAGMENT_SHADER, &frag_shader)) {
- exit(1);
- }
-
- GLuint program = 0;
- if (!link_program(vert_shader, frag_shader, &program)) {
- exit(1);
- }
-
- glUseProgram(program);
-
- time_uniform = glGetUniformLocation(program, "time");
- resolution_uniform = glGetUniformLocation(program, "resolution");
- scale_uniform = glGetUniformLocation(program, "scale");
- camera_uniform = glGetUniformLocation(program, "camera");
-
- glUniform2f(scale_uniform, FONT_SCALE, FONT_SCALE);
- }
-
- // Init Font Texture
- {
- const char *font_file_path = "charmap-oldschool_white.png";
- int width, height, n;
- unsigned char *pixels = stbi_load(font_file_path, &width, &height, &n, STBI_rgb_alpha);
- if (pixels == NULL) {
- fprintf(stderr, "ERROR: could not load file %s: %s\n",
- file_path, stbi_failure_reason());
- exit(1);
- }
-
- glActiveTexture(GL_TEXTURE0);
-
- GLuint font_texture = 0;
- glGenTextures(1, &font_texture);
- glBindTexture(GL_TEXTURE_2D, font_texture);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- width,
- height,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- pixels);
- }
-
- // Init Buffers
- {
- GLuint vao = 0;
- glGenVertexArrays(1, &vao);
- glBindVertexArray(vao);
-
- GLuint vbo = 0;
- glGenBuffers(1, &vbo);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER,
- sizeof(tile_glyph_buffer),
- tile_glyph_buffer,
- GL_DYNAMIC_DRAW);
-
- for (Tile_Glyph_Attr attr = 0; attr < COUNT_TILE_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(Tile_Glyph),
- (void*) glyph_attr_defs[attr].offset);
- break;
-
- case GL_INT:
- glVertexAttribIPointer(
- attr,
- glyph_attr_defs[attr].comps,
- glyph_attr_defs[attr].type,
- sizeof(Tile_Glyph),
- (void*) glyph_attr_defs[attr].offset);
- break;
-
- default:
- assert(false && "unreachable");
- exit(1);
- }
- glVertexAttribDivisor(attr, 1);
- }
- }
+ tile_glyph_buffer_init(&tgb,
+ "./charmap-oldschool_white.png",
+ "./shaders/tile_glyph.vert",
+ "./shaders/tile_glyph.frag");
bool quit = false;
while (!quit) {
@@ -435,33 +242,33 @@ int main(int argc, char **argv)
SDL_GetWindowSize(window, &w, &h);
// TODO(#19): update the viewport and the resolution only on actual window change
glViewport(0, 0, w, h);
- glUniform2f(resolution_uniform, (float) w, (float) h);
+ glUniform2f(tgb.resolution_uniform, (float) w, (float) h);
}
- tile_glyph_buffer_clear();
+ tile_glyph_buffer_clear(&tgb);
{
for (size_t row = 0; row < editor.size; ++row) {
const Line *line = editor.lines + row;
- gl_render_text_sized(line->chars, line->size, vec2i(0, -(int)row), vec4fs(1.0f), vec4fs(0.0f));
+ tile_glyph_render_line_sized(&tgb, line->chars, line->size, vec2i(0, -(int)row), vec4fs(1.0f), vec4fs(0.0f));
}
}
- tile_glyph_buffer_sync();
+ tile_glyph_buffer_sync(&tgb);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
- glUniform1f(time_uniform, (float) SDL_GetTicks() / 1000.0f);
- glUniform2f(camera_uniform, camera_pos.x, camera_pos.y);
+ glUniform1f(tgb.time_uniform, (float) SDL_GetTicks() / 1000.0f);
+ glUniform2f(tgb.camera_uniform, camera_pos.x, camera_pos.y);
- glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei) tile_glyph_buffer_count);
+ tile_glyph_buffer_draw(&tgb);
- tile_glyph_buffer_clear();
+ tile_glyph_buffer_clear(&tgb);
{
- gl_render_cursor();
+ gl_render_cursor(&tgb);
}
- tile_glyph_buffer_sync();
+ tile_glyph_buffer_sync(&tgb);
- glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei) tile_glyph_buffer_count);
+ tile_glyph_buffer_draw(&tgb);
SDL_GL_SwapWindow(window);
diff --git a/src/tile_glyph.c b/src/tile_glyph.c
@@ -0,0 +1,171 @@
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+#include "./stb_image.h"
+#include "./tile_glyph.h"
+#include "./gl_extra.h"
+
+static const Attr_Def glyph_attr_defs[COUNT_TILE_GLYPH_ATTRS] = {
+ [TILE_GLYPH_ATTR_TILE] = {
+ .offset = offsetof(Tile_Glyph, tile),
+ .comps = 2,
+ .type = GL_INT
+ },
+ [TILE_GLYPH_ATTR_CH] = {
+ .offset = offsetof(Tile_Glyph, ch),
+ .comps = 1,
+ .type = GL_INT
+ },
+ [TILE_GLYPH_ATTR_FG_COLOR] = {
+ .offset = offsetof(Tile_Glyph, fg_color),
+ .comps = 4,
+ .type = GL_FLOAT
+ },
+ [TILE_GLYPH_ATTR_BG_COLOR] = {
+ .offset = offsetof(Tile_Glyph, bg_color),
+ .comps = 4,
+ .type = GL_FLOAT
+ },
+};
+static_assert(COUNT_TILE_GLYPH_ATTRS == 4, "The amount of glyph vertex attributes have changed");
+
+void tile_glyph_buffer_clear(Tile_Glyph_Buffer *tgb)
+{
+ tgb->glyphs_count = 0;
+}
+
+void tile_glyph_buffer_push(Tile_Glyph_Buffer *tgb, Tile_Glyph glyph)
+{
+ assert(tgb->glyphs_count < TILE_GLYPH_BUFFER_CAP);
+ tgb->glyphs[tgb->glyphs_count++] = glyph;
+}
+
+void tile_glyph_buffer_sync(Tile_Glyph_Buffer *tgb)
+{
+ glBufferSubData(GL_ARRAY_BUFFER,
+ 0,
+ tgb->glyphs_count * sizeof(Tile_Glyph),
+ tgb->glyphs);
+}
+
+void tile_glyph_render_line_sized(Tile_Glyph_Buffer *tgb, const char *text, size_t text_size, Vec2i tile, Vec4f fg_color, Vec4f bg_color)
+{
+ for (size_t i = 0; i < text_size; ++i) {
+ tile_glyph_buffer_push(tgb, (Tile_Glyph) {
+ .tile = vec2i_add(tile, vec2i((int) i, 0)),
+ .ch = text[i],
+ .fg_color = fg_color,
+ .bg_color = bg_color,
+ });
+ }
+}
+
+void tile_glyph_render_line(Tile_Glyph_Buffer *tgb, const char *text, Vec2i tile, Vec4f fg_color, Vec4f bg_color)
+{
+ tile_glyph_render_line_sized(tgb, text, strlen(text), tile, fg_color, bg_color);
+}
+
+void tile_glyph_buffer_init(Tile_Glyph_Buffer *tgb, const char *texture_file_path, const char *vert_file_path, const char *frag_file_path)
+{
+ // Init Vertex Attributes
+ {
+ glGenVertexArrays(1, &tgb->vao);
+ glBindVertexArray(tgb->vao);
+
+ glGenBuffers(1, &tgb->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, tgb->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(tgb->glyphs), tgb->glyphs, GL_DYNAMIC_DRAW);
+
+ for (Tile_Glyph_Attr attr = 0; attr < COUNT_TILE_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(Tile_Glyph),
+ (void*) glyph_attr_defs[attr].offset);
+ break;
+
+ case GL_INT:
+ glVertexAttribIPointer(
+ attr,
+ glyph_attr_defs[attr].comps,
+ glyph_attr_defs[attr].type,
+ sizeof(Tile_Glyph),
+ (void*) glyph_attr_defs[attr].offset);
+ break;
+
+ default:
+ assert(false && "unreachable");
+ exit(1);
+ }
+ glVertexAttribDivisor(attr, 1);
+ }
+ }
+
+ // 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);
+ }
+
+ GLuint program = 0;
+ if (!link_program(vert_shader, frag_shader, &program)) {
+ exit(1);
+ }
+
+ glUseProgram(program);
+
+ tgb->time_uniform = glGetUniformLocation(program, "time");
+ tgb->resolution_uniform = glGetUniformLocation(program, "resolution");
+ tgb->scale_uniform = glGetUniformLocation(program, "scale");
+ tgb->camera_uniform = glGetUniformLocation(program, "camera");
+
+ glUniform2f(tgb->scale_uniform, FONT_SCALE, FONT_SCALE);
+ }
+
+ // Init Texture
+ {
+ int width, height, n;
+ unsigned char *pixels = stbi_load(texture_file_path, &width, &height, &n, STBI_rgb_alpha);
+ if (pixels == NULL) {
+ fprintf(stderr, "ERROR: could not load file %s: %s\n",
+ texture_file_path, stbi_failure_reason());
+ exit(1);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &tgb->font_texture);
+ glBindTexture(GL_TEXTURE_2D, tgb->font_texture);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ width,
+ height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ pixels);
+
+ stbi_image_free(pixels);
+ }
+}
+
+void tile_glyph_buffer_draw(Tile_Glyph_Buffer *tgb)
+{
+ glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei) tgb->glyphs_count);
+}
diff --git a/src/tile_glyph.h b/src/tile_glyph.h
@@ -0,0 +1,73 @@
+#ifndef TILE_GLYPH_H_
+#define TILE_GLYPH_H_
+
+#include <stdlib.h>
+#include "./la.h"
+
+#define GLEW_STATIC
+#include <GL/glew.h>
+
+#define GL_GLEXT_PROTOTYPES
+#include <SDL2/SDL_opengl.h>
+
+#define FONT_SCALE 5
+#define FONT_WIDTH 128
+#define FONT_HEIGHT 64
+#define FONT_COLS 18
+#define FONT_ROWS 7
+#define FONT_CHAR_WIDTH (FONT_WIDTH / FONT_COLS)
+#define FONT_CHAR_HEIGHT (FONT_HEIGHT / FONT_ROWS)
+
+typedef struct {
+ Vec2i tile;
+ int ch;
+ Vec4f fg_color;
+ Vec4f bg_color;
+} Tile_Glyph;
+
+typedef enum {
+ TILE_GLYPH_ATTR_TILE = 0,
+ TILE_GLYPH_ATTR_CH,
+ TILE_GLYPH_ATTR_FG_COLOR,
+ TILE_GLYPH_ATTR_BG_COLOR,
+ COUNT_TILE_GLYPH_ATTRS,
+} Tile_Glyph_Attr;
+
+typedef struct {
+ size_t offset;
+ GLint comps;
+ GLenum type;
+} Attr_Def;
+
+#define TILE_GLYPH_BUFFER_CAP (640 * 1024)
+
+typedef struct {
+ GLuint vao;
+ GLuint vbo;
+
+ GLuint font_texture;
+
+ GLint time_uniform;
+ GLint resolution_uniform;
+ GLint scale_uniform;
+ GLint camera_uniform;
+
+ size_t glyphs_count;
+ Tile_Glyph glyphs[TILE_GLYPH_BUFFER_CAP];
+} Tile_Glyph_Buffer;
+
+void tile_glyph_buffer_init(Tile_Glyph_Buffer *buffer,
+ const char *texture_file_path,
+ const char *vert_file_path,
+ const char *frag_file_path);
+
+void tile_glyph_buffer_clear(Tile_Glyph_Buffer *buffer);
+void tile_glyph_buffer_push(Tile_Glyph_Buffer *buffer, Tile_Glyph glyph);
+void tile_glyph_buffer_sync(Tile_Glyph_Buffer *buffer);
+
+void tile_glyph_render_line_sized(Tile_Glyph_Buffer *buffer, const char *text, size_t text_size, Vec2i tile, Vec4f fg_color, Vec4f bg_color);
+void tile_glyph_render_line(Tile_Glyph_Buffer *buffer, const char *text, Vec2i tile, Vec4f fg_color, Vec4f bg_color);
+
+void tile_glyph_buffer_draw(Tile_Glyph_Buffer *buffer);
+
+#endif // TILE_GLYPH_H_