Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,29 @@ jobs:
./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: Install dependencies
run: |
./setup_dependencies.bat
- name: build ded
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(#29): build-windows-msvc 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 ded
# 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/
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ $ ./ded src\main.c
> .\build_msvc.bat
> .\ded.exe src\main.c
```

# Font

Victor Mono: https://rubjo.github.io/victor-mono/
Binary file added VictorMono-Regular.ttf
Binary file not shown.
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
set -xe

CC="${CXX:-cc}"
PKGS="sdl2 glew"
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="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"

if [ `uname` = "Darwin" ]; then
CFLAGS+=" -framework OpenGL"
Expand Down
24 changes: 24 additions & 0 deletions shaders/free_glyph.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#version 330 core

uniform sampler2D font;
uniform float time;
uniform vec2 resolution;

in vec2 uv;
in vec2 glyph_uv_pos;
in vec2 glyph_uv_size;
in vec4 glyph_fg_color;
in vec4 glyph_bg_color;

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() {
vec2 t = glyph_uv_pos + glyph_uv_size * uv;
vec4 tc = texture(font, t);
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 = glyph_bg_color * (1.0 - tc.x) + tc.x * glyph_fg_color * rainbow;
}
31 changes: 31 additions & 0 deletions shaders/free_glyph.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#version 330 core

uniform vec2 resolution;
uniform vec2 camera;

layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 size;
layout(location = 2) in vec2 uv_pos;
layout(location = 3) in vec2 uv_size;
layout(location = 4) in vec4 fg_color;
layout(location = 5) in vec4 bg_color;

out vec2 uv;
out vec2 glyph_uv_pos;
out vec2 glyph_uv_size;
out vec4 glyph_fg_color;
out vec4 glyph_bg_color;

vec2 camera_project(vec2 point)
{
return 2.0 * (point - camera) / resolution;
}

void main() {
uv = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));
gl_Position = vec4(camera_project(uv * size + pos), 0.0, 1.0);
glyph_uv_pos = uv_pos;
glyph_uv_size = uv_size;
glyph_fg_color = fg_color;
glyph_bg_color = bg_color;
}
File renamed without changes.
File renamed without changes.
238 changes: 238 additions & 0 deletions src/free_glyph.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#include <assert.h>
#include <stdbool.h>
#include "./free_glyph.h"
#include "./gl_extra.h"

#include "./stb_image_write.h"
#include "./stb_image.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)
{
// 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 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);

fgb->time_uniform = glGetUniformLocation(program, "time");
fgb->resolution_uniform = glGetUniformLocation(program, "resolution");
fgb->camera_uniform = glGetUniformLocation(program, "camera");
}

// 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, &fgb->glyphs_texture);
glBindTexture(GL_TEXTURE_2D, fgb->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) fgb->atlas_width,
(GLsizei) fgb->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);
}

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;
}
}
}

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);
}

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) {
Glyph_Metric metric = fgb->metrics[(int) text[i]];
float x2 = pos.x + metric.bl;
float y2 = -pos.y - metric.bt;
float w = metric.bw;
float h = metric.bh;

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.fg_color = fg_color;
glyph.bg_color = bg_color;
free_glyph_buffer_push(fgb, glyph);
}
}

void free_glyph_buffer_render_line(Free_Glyph_Buffer *fgb, const char *text, Vec2f pos, Vec4f fg_color, Vec4f bg_color)
{
free_glyph_buffer_render_line_sized(fgb, text, strlen(text), pos, fg_color, bg_color);
}
Loading