commit 642c19d3bf46adc77918b8cee7adf068d46ca1cb
parent 19e837898397527fff66fd4d2e956b73ed4bbe02
Author: Alexey Kutepov <reximkut@gmail.com>
Date: Mon, 5 Jul 2021 03:44:51 +0700
Merge pull request #11 from tsoding/opengl-renderer
Quick and rough implementation of the OpenGL renderer
Diffstat:
17 files changed, 616 insertions(+), 48 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
@@ -12,10 +12,10 @@ jobs:
- name: install dependencies
run: |
sudo apt-get update
- sudo apt-get install -qq libsdl2-dev
+ sudo apt-get install -qq libsdl2-dev libglew-dev
- name: build te
run: |
- make
+ ./build.sh
env:
CC: gcc
build-linux-clang:
@@ -25,10 +25,10 @@ jobs:
- name: install dependencies
run: |
sudo apt-get update
- sudo apt-get install -qq libsdl2-dev
+ sudo apt-get install -qq libsdl2-dev libglew-dev
- name: build te
run: |
- make
+ ./build.sh
env:
CC: clang
build-macos:
@@ -36,35 +36,35 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: install dependencies
- run: brew install sdl2 pkg-config
+ run: brew install sdl2 pkg-config glew
- name: build te
run: |
- make
+ ./build.sh
env:
CC: clang
- build-windows-msvc:
- runs-on: windows-2019
- steps:
- - uses: actions/checkout@v1
- # this runs vcvarsall for us, so we get the MSVC toolchain in PATH.
- - uses: seanmiddleditch/gha-setup-vsdevenv@master
- - name: download sdl2
- run: |
- curl -fsSL -o SDL2-devel-2.0.14-VC.zip https://www.libsdl.org/release/SDL2-devel-2.0.14-VC.zip
- tar -xf SDL2-devel-2.0.14-VC.zip
- mv SDL2-2.0.14 SDL2
- - name: build te
- shell: cmd
- run: |
- ./build_msvc.bat
- - name: Prepare WindowsBinaries artifacts
- shell: cmd
- run: |
- mkdir winbin
- copy /B *.exe winbin
- copy /B *.png winbin
- - name: Upload WindowsBinaries artifacts
- uses: actions/upload-artifact@v2
- with:
- name: WindowsBinaries
- path: ./winbin/
+ # TODO(#12): Windows MSVC build is broken
+ # ---
+ # build-windows-msvc:
+ # runs-on: windows-2019
+ # steps:
+ # - uses: actions/checkout@v1
+ # # this runs vcvarsall for us, so we get the MSVC toolchain in PATH.
+ # - uses: seanmiddleditch/gha-setup-vsdevenv@master
+ # - name: Install dependencies
+ # run: |
+ # ./setup_dependencies.bat
+ # - name: build te
+ # shell: cmd
+ # run: |
+ # ./build_msvc.bat
+ # - name: Prepare WindowsBinaries artifacts
+ # shell: cmd
+ # run: |
+ # mkdir winbin
+ # copy /B *.exe winbin
+ # copy /B *.png winbin
+ # - name: Upload WindowsBinaries artifacts
+ # uses: actions/upload-artifact@v2
+ # with:
+ # name: WindowsBinaries
+ # path: ./winbin/
diff --git a/Makefile b/Makefile
@@ -1,6 +0,0 @@
-CFLAGS=-Wall -Wextra -std=c11 -pedantic -ggdb `pkg-config --cflags sdl2`
-LIBS=`pkg-config --libs sdl2` -lm
-SRCS=src/main.c src/la.c src/editor.c src/font.c src/sdl_extra.c
-
-te: $(SRCS)
- $(CC) $(CFLAGS) -o te $(SRCS) $(LIBS)
diff --git a/README.md b/README.md
@@ -1,8 +1,18 @@
# Text Editor
-# Quick Start
+# Quick Start
+
+## POSIX
+
+```console
+$ ./build.sh
+$ ./te src\main.c
+```
+
+## Windows MSVC
```console
-$ make
-$ ./te main.c
+> .\setup_dependencies.bat
+> .\build_msvc.bat
+> .\te src\main.c
```
diff --git a/build.sh b/build.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -xe
+
+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/font.c src/sdl_extra.c src/file.c src/gl_extra.c"
+
+if [ `uname` = "Darwin" ]; then
+ CFLAGS+=" -framework OpenGL"
+fi
+
+$CC $CFLAGS `pkg-config --cflags $PKGS` -o te $SRC $LIBS `pkg-config --libs $PKGS`
diff --git a/build_msvc.bat b/build_msvc.bat
@@ -1,8 +1,12 @@
@echo off
rem launch this from msvc-enabled console
-set CFLAGS=/W4 /WX /std:c11 /wd4996 /FC /TC /Zi /nologo
-set INCLUDES=/I SDL2\include
-set LIBS=SDL2\lib\x64\SDL2.lib SDL2\lib\x64\SDL2main.lib Shell32.lib
+set CFLAGS=/W4 /WX /std:c11 /wd4996 /wd5105 /FC /TC /Zi /nologo
+set INCLUDES=/I dependencies\SDL2\include /I dependencies\GLFW\include /I dependencies\GLEW\include
+set LIBS=dependencies\SDL2\lib\x64\SDL2.lib ^
+ dependencies\SDL2\lib\x64\SDL2main.lib ^
+ dependencies\GLFW\lib\glfw3.lib ^
+ dependencies\GLEW\lib\glew32s.lib ^
+ opengl32.lib User32.lib Gdi32.lib Shell32.lib
-cl.exe %CFLAGS% %INCLUDES% /Fete src\main.c src\la.c src\editor.c src\font.c src\sdl_extra.c /link %LIBS% -SUBSYSTEM:windows
+cl.exe %CFLAGS% %INCLUDES% /Fete src\main.c src\la.c src\editor.c src\font.c src\sdl_extra.c src\file.c src\gl_extra.c /link %LIBS% -SUBSYSTEM:windows
diff --git a/setup_dependencies.bat b/setup_dependencies.bat
@@ -0,0 +1,28 @@
+@echo off
+
+curl -fsSL -o SDL2-devel-2.0.12-VC.zip https://www.libsdl.org/release/SDL2-devel-2.0.12-VC.zip
+tar -xf SDL2-devel-2.0.12-VC.zip
+if not exist dependencies\ mkdir dependencies\
+move SDL2-2.0.12 dependencies\SDL2
+del SDL2-devel-2.0.12-VC.zip
+if not exist dependencies\SDL2\temp\ mkdir dependencies\SDL2\temp\
+move dependencies\SDL2\include dependencies\SDL2\temp\SDL2
+move dependencies\SDL2\temp dependencies\SDL2\include
+
+curl -fsSL -o glfw-3.3.2.bin.WIN64.zip https://github.com/glfw/glfw/releases/download/3.3.2/glfw-3.3.2.bin.WIN64.zip
+tar -xf glfw-3.3.2.bin.WIN64.zip
+if not exist dependencies\GLFW\lib\ mkdir dependencies\GLFW\lib\
+move glfw-3.3.2.bin.WIN64\lib-vc2019\glfw3.lib dependencies\GLFW\lib\glfw3.lib
+if not exist dependencies\GLFW\include\GLFW mkdir dependencies\GLFW\include\GLFW
+move glfw-3.3.2.bin.WIN64\include\GLFW\glfw3.h dependencies\GLFW\include\GLFW\glfw3.h
+del glfw-3.3.2.bin.WIN64.zip
+rmdir /s /q glfw-3.3.2.bin.WIN64
+
+curl -fsSL -o glew-2.1.0-win32.zip https://sourceforge.net/projects/glew/files/glew/2.1.0/glew-2.1.0-win32.zip/download
+tar -xf glew-2.1.0-win32.zip
+if not exist dependencies\GLEW\lib\ mkdir dependencies\GLEW\lib\
+move glew-2.1.0\lib\Release\x64\glew32s.lib dependencies\GLEW\lib\glew32s.lib
+if not exist dependencies\GLEW\include\GL\ mkdir dependencies\GLEW\include\GL\
+move glew-2.1.0\include\GL\glew.h dependencies\GLEW\include\GL\glew.h
+del glew-2.1.0-win32.zip
+rmdir /s /q glew-2.1.0
diff --git a/shaders/font.frag b/shaders/font.frag
@@ -0,0 +1,36 @@
+#version 330 core
+
+#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)
+#define FONT_CHAR_WIDTH_UV (float(FONT_CHAR_WIDTH) / float(FONT_WIDTH))
+#define FONT_CHAR_HEIGHT_UV (float(FONT_CHAR_HEIGHT) / float(FONT_HEIGHT))
+
+#define ASCII_DISPLAY_LOW 32
+#define ASCII_DISPLAY_HIGH 126
+
+uniform sampler2D font;
+uniform float time;
+
+in vec2 uv;
+in float glyph_ch;
+in vec4 glyph_color;
+
+void main() {
+ int ch = int(glyph_ch);
+ if (!(ASCII_DISPLAY_LOW <= ch && ch <= ASCII_DISPLAY_HIGH)) {
+ ch = 63;
+ }
+
+ int index = ch - 32;
+ float x = float(index % FONT_COLS) * FONT_CHAR_WIDTH_UV;
+ float y = float(index / FONT_COLS) * FONT_CHAR_HEIGHT_UV;
+ vec2 pos = vec2(x, y + FONT_CHAR_HEIGHT_UV);
+ vec2 size = vec2(FONT_CHAR_WIDTH_UV, -FONT_CHAR_HEIGHT_UV);
+ vec2 t = pos + size * uv;
+
+ gl_FragColor = texture(font, t)* glyph_color;
+}
diff --git a/shaders/font.vert b/shaders/font.vert
@@ -0,0 +1,32 @@
+#version 330 core
+
+#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)
+
+uniform vec2 resolution;
+
+layout(location = 0) in vec2 pos;
+layout(location = 1) in float scale;
+layout(location = 2) in float ch;
+layout(location = 3) in vec4 color;
+
+out vec2 uv;
+out float glyph_ch;
+out vec4 glyph_color;
+
+vec2 project_point(vec2 point)
+{
+ return 2.0 * point / resolution;
+}
+
+void main() {
+ uv = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));
+ vec2 char_size = vec2(float(FONT_CHAR_WIDTH), float(FONT_CHAR_HEIGHT));
+ gl_Position = vec4(project_point(uv * char_size * scale + pos), 0.0, 1.0);
+ glyph_ch = ch;
+ glyph_color = color;
+}
diff --git a/src/file.c b/src/file.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "./file.h"
+
+char *slurp_file(const char *file_path)
+{
+#define SLURP_FILE_PANIC \
+ do { \
+ fprintf(stderr, "Could not read file `%s`: %s\n", file_path, strerror(errno)); \
+ exit(1); \
+ } while (0)
+
+ FILE *f = fopen(file_path, "r");
+ if (f == NULL) SLURP_FILE_PANIC;
+ if (fseek(f, 0, SEEK_END) < 0) SLURP_FILE_PANIC;
+
+ long size = ftell(f);
+ if (size < 0) SLURP_FILE_PANIC;
+
+ char *buffer = malloc(size + 1);
+ if (buffer == NULL) SLURP_FILE_PANIC;
+
+ if (fseek(f, 0, SEEK_SET) < 0) SLURP_FILE_PANIC;
+
+ fread(buffer, 1, size, f);
+ if (ferror(f) < 0) SLURP_FILE_PANIC;
+
+ buffer[size] = '\0';
+
+ if (fclose(f) < 0) SLURP_FILE_PANIC;
+
+ return buffer;
+#undef SLURP_FILE_PANIC
+}
diff --git a/src/file.h b/src/file.h
@@ -0,0 +1,6 @@
+#ifndef FILE_H_
+#define FILE_H_
+
+char *slurp_file(const char *file_path);
+
+#endif // FILE_H_
diff --git a/src/font.h b/src/font.h
@@ -1,7 +1,7 @@
#ifndef FONT_H_
#define FONT_H_
-#include <SDL.h>
+#include <SDL2/SDL.h>
#include "./la.h"
diff --git a/src/gl_extra.c b/src/gl_extra.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "file.h"
+#include "gl_extra.h"
+
+const char *shader_type_as_cstr(GLuint shader)
+{
+ switch (shader) {
+ case GL_VERTEX_SHADER:
+ return "GL_VERTEX_SHADER";
+ case GL_FRAGMENT_SHADER:
+ return "GL_FRAGMENT_SHADER";
+ default:
+ return "(Unknown)";
+ }
+}
+
+bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader)
+{
+ *shader = glCreateShader(shader_type);
+ glShaderSource(*shader, 1, &source, NULL);
+ glCompileShader(*shader);
+
+ GLint compiled = 0;
+ glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled);
+
+ if (!compiled) {
+ GLchar message[1024];
+ GLsizei message_size = 0;
+ glGetShaderInfoLog(*shader, sizeof(message), &message_size, message);
+ fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type));
+ fprintf(stderr, "%.*s\n", message_size, message);
+ return false;
+ }
+
+ return true;
+}
+
+bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader)
+{
+ char *source = slurp_file(file_path);
+ bool ok = compile_shader_source(source, shader_type, shader);
+ if (!ok) {
+ fprintf(stderr, "ERROR: failed to compile `%s` shader file\n", file_path);
+ }
+ free(source);
+ return ok;
+}
+
+bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program)
+{
+ *program = glCreateProgram();
+
+ glAttachShader(*program, vert_shader);
+ glAttachShader(*program, frag_shader);
+ glLinkProgram(*program);
+
+ GLint linked = 0;
+ glGetProgramiv(*program, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ GLsizei message_size = 0;
+ GLchar message[1024];
+
+ glGetProgramInfoLog(*program, sizeof(message), &message_size, message);
+ fprintf(stderr, "Program Linking: %.*s\n", message_size, message);
+ }
+
+ glDeleteShader(vert_shader);
+ glDeleteShader(frag_shader);
+
+ return program;
+}
diff --git a/src/gl_extra.h b/src/gl_extra.h
@@ -0,0 +1,13 @@
+#ifndef GL_EXTRA_H_
+#define GL_EXTRA_H_
+
+#define GL_GLEXT_PROTOTYPES
+#include <SDL2/SDL_opengl.h>
+
+#include <stdbool.h>
+
+bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader);
+bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader);
+bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program);
+
+#endif // GL_EXTRA_H_
diff --git a/src/la.c b/src/la.c
@@ -28,8 +28,47 @@ Vec2f vec2f_mul(Vec2f a, Vec2f b)
return vec2f(a.x * b.x, a.y * b.y);
}
+Vec2f vec2f_mul3(Vec2f a, Vec2f b, Vec2f c)
+{
+ return vec2f_mul(vec2f_mul(a, b), c);
+}
+
Vec2f vec2f_div(Vec2f a, Vec2f b)
{
return vec2f(a.x / b.x, a.y / b.y);
}
+Vec4f vec4f(float x, float y, float z, float w)
+{
+ return (Vec4f) {
+ .x = x,
+ .y = y,
+ .z = z,
+ .w = w,
+ };
+}
+
+Vec4f vec4fs(float x)
+{
+ return vec4f(x, x, x, x);
+}
+
+Vec4f vec4f_add(Vec4f a, Vec4f b)
+{
+ return vec4f(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
+
+Vec4f vec4f_sub(Vec4f a, Vec4f b)
+{
+ return vec4f(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
+
+Vec4f vec4f_mul(Vec4f a, Vec4f b)
+{
+ return vec4f(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+}
+
+Vec4f vec4f_div(Vec4f a, Vec4f b)
+{
+ return vec4f(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
+}
diff --git a/src/la.h b/src/la.h
@@ -10,6 +10,18 @@ Vec2f vec2fs(float x);
Vec2f vec2f_add(Vec2f a, Vec2f b);
Vec2f vec2f_sub(Vec2f a, Vec2f b);
Vec2f vec2f_mul(Vec2f a, Vec2f b);
+Vec2f vec2f_mul3(Vec2f a, Vec2f b, Vec2f c);
Vec2f vec2f_div(Vec2f a, Vec2f b);
+typedef struct {
+ float x, y, z, w;
+} Vec4f;
+
+Vec4f vec4f(float x, float y, float z, float w);
+Vec4f vec4fs(float x);
+Vec4f vec4f_add(Vec4f a, Vec4f b);
+Vec4f vec4f_sub(Vec4f a, Vec4f b);
+Vec4f vec4f_mul(Vec4f a, Vec4f b);
+Vec4f vec4f_div(Vec4f a, Vec4f b);
+
#endif // LA_H_
diff --git a/src/main.c b/src/main.c
@@ -2,7 +2,11 @@
#include <stdlib.h>
#include <stdbool.h>
-#include <SDL.h>
+#include <SDL2/SDL.h>
+#define GLEW_STATIC
+#include <GL/glew.h>
+#define GL_GLEXT_PROTOTYPES
+#include <SDL2/SDL_opengl.h>
#define STB_IMAGE_IMPLEMENTATION
#include "./stb_image.h"
@@ -13,6 +17,7 @@
#include "./editor.h"
#include "./la.h"
#include "./sdl_extra.h"
+#include "./gl_extra.h"
#include "./font.h"
#define SCREEN_WIDTH 800
@@ -70,6 +75,271 @@ void usage(FILE *stream)
// TODO: Delete line
// TODO: Split the line on Enter
+// #define OPENGL_RENDERER
+
+#ifdef OPENGL_RENDERER
+void MessageCallback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam)
+{
+ (void) source;
+ (void) id;
+ (void) length;
+ (void) userParam;
+ fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
+ (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
+ type, severity, message);
+}
+
+typedef struct {
+ Vec2f pos;
+ float scale;
+ float ch;
+ Vec4f color;
+} Glyph;
+
+typedef enum {
+ GLYPH_ATTR_POS = 0,
+ GLYPH_ATTR_SCALE,
+ GLYPH_ATTR_CH,
+ GLYPH_ATTR_COLOR,
+ COUNT_GLYPH_ATTRS,
+} Glyph_Attr;
+
+typedef struct {
+ size_t offset;
+ size_t comps;
+} Glyph_Attr_Def;
+
+static const Glyph_Attr_Def glyph_attr_defs[COUNT_GLYPH_ATTRS] = {
+ [GLYPH_ATTR_POS] = {
+ .offset = offsetof(Glyph, pos),
+ .comps = 2,
+ },
+ [GLYPH_ATTR_SCALE] = {
+ .offset = offsetof(Glyph, scale),
+ .comps = 1,
+ },
+ [GLYPH_ATTR_CH] = {
+ .offset = offsetof(Glyph, ch),
+ .comps = 1,
+ },
+ [GLYPH_ATTR_COLOR] = {
+ .offset = offsetof(Glyph, color),
+ .comps = 4,
+ },
+};
+static_assert(COUNT_GLYPH_ATTRS == 4, "The amount of glyph vertex attributes have changed");
+
+#define GLYPH_BUFFER_CAP 1024
+
+Glyph glyph_buffer[GLYPH_BUFFER_CAP];
+size_t glyph_buffer_count = 0;
+
+void glyph_buffer_push(Glyph glyph)
+{
+ assert(glyph_buffer_count < GLYPH_BUFFER_CAP);
+ glyph_buffer[glyph_buffer_count++] = glyph;
+}
+
+void glyph_buffer_sync(void)
+{
+ glBufferSubData(GL_ARRAY_BUFFER,
+ 0,
+ glyph_buffer_count * sizeof(Glyph),
+ glyph_buffer);
+}
+
+void gl_render_text(const char *text, size_t text_size,
+ Vec2f pos, float scale, Vec4f color)
+{
+ for (size_t i = 0; i < text_size; ++i) {
+ const Vec2f char_size = vec2f(FONT_CHAR_WIDTH, FONT_CHAR_HEIGHT);
+ const Glyph glyph = {
+ .pos = vec2f_add(pos, vec2f_mul3(char_size,
+ vec2f((float) i, 0.0f),
+ vec2fs(scale))),
+ .scale = scale,
+ .ch = (float) text[i],
+ .color = color
+ };
+ glyph_buffer_push(glyph);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ (void) argc;
+ (void) argv;
+
+ scc(SDL_Init(SDL_INIT_VIDEO));
+
+ SDL_Window *window =
+ scp(SDL_CreateWindow("Text Editor",
+ 0, 0,
+ SCREEN_WIDTH, SCREEN_HEIGHT,
+ SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL));
+
+ {
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+ int major;
+ int minor;
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
+ printf("GL version %d.%d\n", major, minor);
+ }
+
+ scp(SDL_GL_CreateContext(window));
+
+ if (GLEW_OK != glewInit()) {
+ fprintf(stderr, "Could not initialize GLEW!");
+ exit(1);
+ }
+
+ if (!GLEW_ARB_draw_instanced) {
+ fprintf(stderr, "ARB_draw_instanced is not supported; game may not work properly!!\n");
+ exit(1);
+ }
+
+ if (!GLEW_ARB_instanced_arrays) {
+ fprintf(stderr, "ARB_instanced_arrays is not supported; game may not work properly!!\n");
+ exit(1);
+ }
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ if (GLEW_ARB_debug_output) {
+ glEnable(GL_DEBUG_OUTPUT);
+ glDebugMessageCallback(MessageCallback, 0);
+ } else {
+ fprintf(stderr, "WARNING! GLEW_ARB_debug_output is not available");
+ }
+
+ GLint time_uniform;
+ GLint resolution_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");
+
+ glUniform2f(resolution_uniform, SCREEN_WIDTH, SCREEN_HEIGHT);
+ }
+
+ // Init Font Texture
+ {
+ const char *file_path = "charmap-oldschool_white.png";
+ int width, height, n;
+ unsigned char *pixels = stbi_load(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(glyph_buffer),
+ glyph_buffer,
+ GL_DYNAMIC_DRAW);
+
+ for (Glyph_Attr attr = 0; attr < COUNT_GLYPH_ATTRS; ++attr) {
+ glEnableVertexAttribArray(attr);
+ glVertexAttribPointer(
+ attr,
+ glyph_attr_defs[attr].comps,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(Glyph),
+ (void*) glyph_attr_defs[attr].offset);
+ glVertexAttribDivisor(attr, 1);
+ }
+ }
+
+ const char *text = "Hello, World";
+ Vec4f color = vec4f(1.0f, 0.0f, 0.0f, 1.0f);
+ gl_render_text(text, strlen(text), vec2fs(0.0f), 5.0f, color);
+ glyph_buffer_sync();
+
+ bool quit = false;
+ while (!quit) {
+ SDL_Event event = {0};
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT: {
+ quit = true;
+ }
+ break;
+ }
+ }
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glUniform1f(time_uniform, (float) SDL_GetTicks() / 1000.0f);
+
+ glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, glyph_buffer_count);
+
+ SDL_GL_SwapWindow(window);
+ }
+
+ return 0;
+}
+#else
int main(int argc, char **argv)
{
const char *file_path = NULL;
@@ -205,3 +475,4 @@ int main(int argc, char **argv)
return 0;
}
+#endif // OPENGL_RENDERER
diff --git a/src/sdl_extra.h b/src/sdl_extra.h
@@ -1,7 +1,7 @@
#ifndef SDL_EXTRA_H_
#define SDL_EXTRA_H_
-#include <SDL.h>
+#include <SDL2/SDL.h>
#include "./la.h"