mirror of
https://github.com/IllusionMan1212/cudoku.git
synced 2026-10-24 02:12:25 +00:00
implemented unicode support and generation of font atlas texture
This commit is contained in:
Vendored
+2
@@ -1,2 +1,4 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
#define STB_DS_IMPLEMENTATION
|
||||||
|
#include "stb_ds.h"
|
||||||
|
|||||||
Vendored
+1895
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ CC=gcc
|
|||||||
CFLAGS=-Wall -Wextra -O3 -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
CFLAGS=-Wall -Wextra -O3 -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
||||||
OBJ=main.o x11.o cudoku.o shader.o font.o helper.o audio.o timer.o ui.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
OBJ=main.o x11.o cudoku.o shader.o font.o helper.o audio.o timer.o ui.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
||||||
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
||||||
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h 3rdparty/fmod/include/fmod.h
|
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h 3rdparty/stb/stb_ds.h 3rdparty/fmod/include/fmod.h
|
||||||
|
|
||||||
%.o: %.c $(DEPS)
|
%.o: %.c $(DEPS)
|
||||||
$(CC) -c -o $@ $< $(CFLAGS)
|
$(CC) -c -o $@ $< $(CFLAGS)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ static const int quad_indices[] = {
|
|||||||
|
|
||||||
static const Color mistake_color = {1.f, 0.f, 0.f, 0.5f};
|
static const Color mistake_color = {1.f, 0.f, 0.f, 0.5f};
|
||||||
|
|
||||||
static const char *win_text = "You won!";
|
static const wide_str *win_text = U"You won!";
|
||||||
|
|
||||||
static const char *help_texts[HELP_TEXT_SIZE] = {
|
static const char *help_texts[HELP_TEXT_SIZE] = {
|
||||||
"F1 - Toggle help",
|
"F1 - Toggle help",
|
||||||
@@ -52,7 +52,7 @@ void draw_win() {
|
|||||||
Color bg_color = {233.f, 84.f, 32.f, 200.f};
|
Color bg_color = {233.f, 84.f, 32.f, 200.f};
|
||||||
Color text_color = {237.f, 225.f, 215.f, 255.f};
|
Color text_color = {237.f, 225.f, 215.f, 255.f};
|
||||||
|
|
||||||
UIConstraints constraints;
|
UIConstraints constraints = {0};
|
||||||
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
||||||
/* set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
/* set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
||||||
/* set_width_constraint(&constraints, window.width, UI_CONSTRAINT_FIXED); */
|
/* set_width_constraint(&constraints, window.width, UI_CONSTRAINT_FIXED); */
|
||||||
@@ -61,13 +61,13 @@ void draw_win() {
|
|||||||
Alignment align = ALIGN_CENTER;
|
Alignment align = ALIGN_CENTER;
|
||||||
int font_size = 72.0f;
|
int font_size = 72.0f;
|
||||||
|
|
||||||
Sizef text_size = calculate_text_size(win_text, font_size);
|
/* Sizef text_size = calculate_text_size(win_text, font_size); */
|
||||||
|
|
||||||
set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
||||||
set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
||||||
set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED);
|
/* set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED); */
|
||||||
set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED);
|
/* set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED); */
|
||||||
set_rotation_constraint(&constraints, get_time() * 50.f);
|
/* set_rotation_constraint(&constraints, 0); */
|
||||||
|
|
||||||
/* UIConstraints circle_const; */
|
/* UIConstraints circle_const; */
|
||||||
/* set_x_constraint(&circle_const, 50, UI_CONSTRAINT_FIXED); */
|
/* set_x_constraint(&circle_const, 50, UI_CONSTRAINT_FIXED); */
|
||||||
@@ -76,7 +76,7 @@ void draw_win() {
|
|||||||
/* set_height_constraint(&circle_const, 90, UI_CONSTRAINT_FIXED); */
|
/* set_height_constraint(&circle_const, 90, UI_CONSTRAINT_FIXED); */
|
||||||
|
|
||||||
/* draw_circle(circle_const, NULL, ALIGN_LEFT_CENTER); */
|
/* draw_circle(circle_const, NULL, ALIGN_LEFT_CENTER); */
|
||||||
draw_quad(constraints, &bg_color, 0.0, align);
|
/* draw_quad(constraints, &bg_color, 0.0, align); */
|
||||||
/* set_x_constraint(&constraints, -50, UI_CONSTRAINT_FIXED); */
|
/* set_x_constraint(&constraints, -50, UI_CONSTRAINT_FIXED); */
|
||||||
/* draw_quad(constraints, &bg_color, 25.0, ALIGN_TOP_RIGHT); */
|
/* draw_quad(constraints, &bg_color, 25.0, ALIGN_TOP_RIGHT); */
|
||||||
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, floa
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint wide_str_len(const wide_str *text) {
|
||||||
|
uint len = 0;
|
||||||
|
for (uint i = 0; text[i] != '\0'; i++) {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
int max(int a, int b) {
|
int max(int a, int b) {
|
||||||
return a > b ? a : b;
|
return a > b ? a : b;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "z_math.h"
|
#include "z_math.h"
|
||||||
|
|
||||||
|
typedef unsigned int wide_str;
|
||||||
|
|
||||||
Matrix4x4 identity();
|
Matrix4x4 identity();
|
||||||
void mult_4x4(Matrix4x4 *multiplicant, Matrix4x4 *multiplier);
|
void mult_4x4(Matrix4x4 *multiplicant, Matrix4x4 *multiplier);
|
||||||
void apply_scale(Matrix4x4 *matrix, Sizef scale);
|
void apply_scale(Matrix4x4 *matrix, Sizef scale);
|
||||||
void apply_rotation(Matrix4x4 *model, float angle);
|
void apply_rotation(Matrix4x4 *model, float angle);
|
||||||
void apply_translation(Matrix4x4 *matrix, Vec2f pos);
|
void apply_translation(Matrix4x4 *matrix, Vec2f pos);
|
||||||
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top);
|
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top);
|
||||||
|
uint wide_str_len(const wide_str *text);
|
||||||
int max(int a, int b);
|
int max(int a, int b);
|
||||||
float maxf(float a, float b);
|
float maxf(float a, float b);
|
||||||
float clampf(float value, float min, float max);
|
float clampf(float value, float min, float max);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
#include "3rdparty/stb/stb_image.h"
|
#include <stb_image.h>
|
||||||
|
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|||||||
@@ -5,7 +5,17 @@ out vec4 FragColor;
|
|||||||
uniform sampler2D text;
|
uniform sampler2D text;
|
||||||
uniform vec4 textColor;
|
uniform vec4 textColor;
|
||||||
|
|
||||||
|
const float smoothness = 0.05;
|
||||||
|
const float outlineDistance = 0.50;
|
||||||
|
const vec4 outlineColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
//float distance = texture(text, v_TexCoords).r;
|
||||||
|
//float outlineFactor = smoothstep(0.5 - smoothness, 0.5 + smoothness, distance);
|
||||||
|
//vec4 color = mix(outlineColor, textColor, outlineFactor);
|
||||||
|
//float alpha = smoothstep(outlineDistance - smoothness, outlineDistance + smoothness, distance);
|
||||||
|
|
||||||
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, v_TexCoords).r);
|
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, v_TexCoords).r);
|
||||||
FragColor = textColor * sampled;
|
FragColor = textColor * sampled;
|
||||||
|
//FragColor = vec4(color.rgb, textColor.a * alpha);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
- maybe force the window to be a specific resolution
|
- maybe force the window to be a specific resolution
|
||||||
- border decorations for shapes
|
- border decorations for shapes
|
||||||
- look into SDF/vector text
|
- remove the hardcoded 1920 and 1080 values when applying relative pixel constraints
|
||||||
- unicode support?
|
and replace them with the screen's currently active resolution
|
||||||
|
|
||||||
|
text rendering improvements
|
||||||
|
- [x] unicode support (allows for non-ascii characters)
|
||||||
|
- [x] atlas texture for text glyphs (this means we only load in one texture for all text)
|
||||||
|
|
||||||
|
- SDF generation allowing for better text scaling (slower but visually better)
|
||||||
|
- SDF is too slow if we want to support unicode. it's acceptably fast for ascii only though.
|
||||||
|
- An alternative is to use MSDF at a much lower pixel height (e.g 16) which results in
|
||||||
|
better scaling than SDF (almost perfect) and is fast enough to include unicode.
|
||||||
|
- Another alternative is using a pre-baked SDF texture atlas. This is the fastest
|
||||||
|
but it's also the least flexible because we can't load arbitrary fonts
|
||||||
|
- Maybe also rendering text as vector using bezier curves. Sounds like a lot of work though.
|
||||||
|
|
||||||
|
Will probably end up using MSDF (if I can get it to work with C lol)
|
||||||
|
|
||||||
|
- instanced rendering for text (this means we only have to do one draw call for all text)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <freetype/ftmm.h>
|
#include <freetype/ftmm.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
@@ -19,7 +20,6 @@ Display *display;
|
|||||||
Window window;
|
Window window;
|
||||||
|
|
||||||
Context zephr_context;
|
Context zephr_context;
|
||||||
Character characters[128];
|
|
||||||
Shader font_shader;
|
Shader font_shader;
|
||||||
Shader ui_shader;
|
Shader ui_shader;
|
||||||
unsigned int font_vao;
|
unsigned int font_vao;
|
||||||
@@ -40,43 +40,97 @@ int init_fonts(const char *font_path) {
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
|
// sets the variable font to be bold
|
||||||
printf("[INFO] Got a variable font\n");
|
/* if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { */
|
||||||
FT_MM_Var *mm;
|
/* printf("[INFO] Got a variable font\n"); */
|
||||||
FT_Get_MM_Var(face, &mm);
|
/* FT_MM_Var *mm; */
|
||||||
|
/* FT_Get_MM_Var(face, &mm); */
|
||||||
|
|
||||||
FT_Set_Var_Design_Coordinates(face, mm->num_namedstyles, mm->namedstyle[mm->num_namedstyles - 4].coords);
|
/* FT_Set_Var_Design_Coordinates(face, mm->num_namedstyles, mm->namedstyle[mm->num_namedstyles - 4].coords); */
|
||||||
|
|
||||||
FT_Done_MM_Var(ft, mm);
|
/* FT_Done_MM_Var(ft, mm); */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(face, 0, FONT_PIXEL_SIZE);
|
FT_Set_Pixel_Sizes(face, 0, FONT_PIXEL_SIZE);
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
for (int c = 0; c < 128; c++) {
|
uint max_dim = (1 + (face->size->metrics.height >> 6)) * ceilf(sqrtf(face->num_glyphs));
|
||||||
|
uint tex_width = 1;
|
||||||
|
while (tex_width < max_dim) {
|
||||||
|
tex_width <<= 1;
|
||||||
|
}
|
||||||
|
uint tex_height = tex_width;
|
||||||
|
|
||||||
|
char *pixels = (char *)calloc(tex_width * tex_height, 1);
|
||||||
|
int pen_x = 0, pen_y = 0;
|
||||||
|
|
||||||
|
FT_UInt glyph_idx;
|
||||||
|
FT_ULong c = FT_Get_First_Char(face, &glyph_idx);
|
||||||
|
|
||||||
|
while (glyph_idx) {
|
||||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
||||||
printf("[ERROR]: failed to load glyph for char '%c'\n", c);
|
printf("[ERROR]: failed to load glyph for char '0x%lx'\n", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int texture;
|
/* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */
|
||||||
glGenTextures(1, &texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
|
|
||||||
face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
|
|
||||||
face->glyph->bitmap.buffer);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
FT_Bitmap *bmp = &face->glyph->bitmap;
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
characters[c].texture_id = texture;
|
if (pen_x + bmp->width >= tex_width) {
|
||||||
characters[c].advance = face->glyph->advance.x;
|
pen_x = 0;
|
||||||
characters[c].size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
pen_y += (1 + (face->size->metrics.height >> 6));
|
||||||
characters[c].bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
}
|
||||||
|
|
||||||
|
for (uint row = 0; row < bmp->rows; row++) {
|
||||||
|
for (uint col = 0; col < bmp->width; col++) {
|
||||||
|
int x = pen_x + col;
|
||||||
|
int y = pen_y + row;
|
||||||
|
pixels[y * tex_width + x] = bmp->buffer[row * bmp->pitch + col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float atlas_x0 = (float)pen_x / (float)tex_width;
|
||||||
|
float atlas_y0 = (float)pen_y / (float)tex_height;
|
||||||
|
float atlas_x1 = (float)(pen_x + bmp->width) / (float)tex_width;
|
||||||
|
float atlas_y1 = (float)(pen_y + bmp->rows) / (float)tex_height;
|
||||||
|
|
||||||
|
Vec2f top_left = (Vec2f){ .x = atlas_x0, .y = atlas_y1 };
|
||||||
|
Vec2f top_right = (Vec2f){ .x = atlas_x1, .y = atlas_y1 };
|
||||||
|
Vec2f bottom_right = (Vec2f){ .x = atlas_x1, .y = atlas_y0 };
|
||||||
|
Vec2f bottom_left = (Vec2f){ .x = atlas_x0, .y = atlas_y0 };
|
||||||
|
|
||||||
|
Character character;
|
||||||
|
|
||||||
|
character.tex_coords[0] = top_left;
|
||||||
|
character.tex_coords[1] = top_right;
|
||||||
|
character.tex_coords[2] = bottom_right;
|
||||||
|
character.tex_coords[3] = bottom_left;
|
||||||
|
character.advance = face->glyph->advance.x;
|
||||||
|
character.size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
||||||
|
character.bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
||||||
|
|
||||||
|
hmput(zephr_context.font.characters, c, character);
|
||||||
|
|
||||||
|
pen_x += bmp->width + 1;
|
||||||
|
|
||||||
|
c = FT_Get_Next_Char(face, c, &glyph_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int texture;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, tex_width,
|
||||||
|
tex_height, 0, GL_RED, GL_UNSIGNED_BYTE,
|
||||||
|
pixels);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
zephr_context.font.atlas_texture_id = texture;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
FT_Done_Face(face);
|
FT_Done_Face(face);
|
||||||
@@ -213,7 +267,7 @@ Size zephr_get_window_size() {
|
|||||||
return zephr_context.window_size;
|
return zephr_context.window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sizef calculate_text_size(const char *text, int font_size) {
|
Sizef calculate_text_size(const wide_str *text, int font_size) {
|
||||||
float scale = (float)font_size / FONT_PIXEL_SIZE;
|
float scale = (float)font_size / FONT_PIXEL_SIZE;
|
||||||
Sizef size = { .width = 0, .height = 0 };
|
Sizef size = { .width = 0, .height = 0 };
|
||||||
int w = 0;
|
int w = 0;
|
||||||
@@ -221,27 +275,29 @@ Sizef calculate_text_size(const char *text, int font_size) {
|
|||||||
int max_bearing_h = 0;
|
int max_bearing_h = 0;
|
||||||
|
|
||||||
// NOTE: I don't like looping through the characters twice, but it's fine for now
|
// NOTE: I don't like looping through the characters twice, but it's fine for now
|
||||||
for (uint i = 0; i < strlen(text); i++) {
|
for (uint i = 0; (i < text[i]) != '\0'; i++) {
|
||||||
Character ch = characters[(uint)text[i]];
|
Character ch = hmget(zephr_context.font.characters, (uint)text[i]);
|
||||||
|
/* Character ch = characters[(uint)text[i]]; */
|
||||||
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i = 0; i < strlen(text); i++) {
|
for (uint i = 0; (i < text[i]) != '\0'; i++) {
|
||||||
Character ch = characters[(uint)text[i]];
|
Character ch = hmget(zephr_context.font.characters, (uint)text[i]);
|
||||||
|
/* Character ch = characters[(uint)text[i]]; */
|
||||||
w += ch.advance / 64;
|
w += ch.advance / 64;
|
||||||
|
|
||||||
// remove bearing of first character
|
// remove bearing of first character
|
||||||
if (i == 0 && strlen(text) > 1) {
|
if (i == 0 && wide_str_len(text) > 1) {
|
||||||
w -= ch.bearing.width;
|
w -= ch.bearing.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the trailing width of the last character
|
// remove the trailing width of the last character
|
||||||
if (i == strlen(text) - 1) {
|
if (i == wide_str_len(text) - 1) {
|
||||||
w -= ((ch.advance / 64) - (ch.bearing.width + ch.size.width));
|
w -= ((ch.advance / 64) - (ch.bearing.width + ch.size.width));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we only have one character in the text, then remove the bearing width
|
// if we only have one character in the text, then remove the bearing width
|
||||||
if (strlen(text) == 1) {
|
if (wide_str_len(text) == 1) {
|
||||||
w -= (ch.bearing.width);
|
w -= (ch.bearing.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +525,7 @@ void draw_triangle(UIConstraints constraints, Color *color, Alignment align) {
|
|||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_text(const char* text, int font_size, UIConstraints constraints, Color *color, Alignment alignment) {
|
void draw_text(const wide_str* text, int font_size, UIConstraints constraints, Color *color, Alignment alignment) {
|
||||||
use_shader(font_shader);
|
use_shader(font_shader);
|
||||||
if (color) {
|
if (color) {
|
||||||
set_vec4f(font_shader, "textColor", color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f);
|
set_vec4f(font_shader, "textColor", color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f);
|
||||||
@@ -500,14 +556,16 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
|
|||||||
set_mat4f(font_shader, "model", (float *)model.m);
|
set_mat4f(font_shader, "model", (float *)model.m);
|
||||||
|
|
||||||
int max_bearing_h = 0;
|
int max_bearing_h = 0;
|
||||||
for (uint i = 0; i < strlen(text); i++) {
|
for (uint i = 0; (i < text[i]) != '\0'; i++) {
|
||||||
Character ch = characters[(int)text[i]];
|
Character ch = hmget(zephr_context.font.characters, text[i]);
|
||||||
|
/* Character ch = characters[(int)text[i]]; */
|
||||||
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
float first_char_bearing_w = characters[(int)text[0]].bearing.width;
|
float first_char_bearing_w = hmget(zephr_context.font.characters, (int)text[0]).bearing.width;
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, zephr_context.font.atlas_texture_id);
|
||||||
glBindVertexArray(font_vao);
|
glBindVertexArray(font_vao);
|
||||||
|
|
||||||
// we use the original text and character sizes in the loop and then we just
|
// we use the original text and character sizes in the loop and then we just
|
||||||
@@ -517,24 +575,23 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
|
|||||||
int c = 0;
|
int c = 0;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
while (text[c] != '\0') {
|
while (text[c] != '\0') {
|
||||||
Character ch = characters[(int)text[c]];
|
Character ch = hmget(zephr_context.font.characters, text[c]);
|
||||||
|
/* Character ch = characters[(int)text[c]]; */
|
||||||
// subtract the bearing width of the first character to remove the extra space
|
// subtract the bearing width of the first character to remove the extra space
|
||||||
// at the start of the text and move every char to the left by that width
|
// at the start of the text and move every char to the left by that width
|
||||||
float xpos = (x + (ch.bearing.width - first_char_bearing_w));
|
float xpos = (x + (ch.bearing.width - first_char_bearing_w));
|
||||||
float ypos = (text_size.height - ch.bearing.height - (text_size.height - max_bearing_h));
|
float ypos = (text_size.height - ch.bearing.height - (text_size.height - max_bearing_h));
|
||||||
|
|
||||||
float vertices[6][4] = {
|
float vertices[6][4] = {
|
||||||
{xpos, ypos + ch.size.height, 0.0, 1.0},
|
{xpos, ypos + ch.size.height, ch.tex_coords[0].x, ch.tex_coords[0].y},
|
||||||
{xpos, ypos, 0.0, 0.0},
|
{xpos, ypos, ch.tex_coords[3].x, ch.tex_coords[3].y},
|
||||||
{xpos + ch.size.width, ypos, 1.0, 0.0},
|
{xpos + ch.size.width, ypos, ch.tex_coords[2].x, ch.tex_coords[2].y},
|
||||||
|
|
||||||
{xpos, ypos + ch.size.height, 0.0, 1.0},
|
{xpos, ypos + ch.size.height, ch.tex_coords[0].x, ch.tex_coords[0].y},
|
||||||
{xpos + ch.size.width, ypos, 1.0, 0.0},
|
{xpos + ch.size.width, ypos, ch.tex_coords[2].x, ch.tex_coords[2].y},
|
||||||
{xpos + ch.size.width, ypos + ch.size.height, 1.0, 1.0},
|
{xpos + ch.size.width, ypos + ch.size.height, ch.tex_coords[1].x, ch.tex_coords[1].y},
|
||||||
};
|
};
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|||||||
@@ -1,20 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "z_math.h"
|
#include "z_math.h"
|
||||||
|
|
||||||
typedef struct Character {
|
typedef struct Character {
|
||||||
unsigned int texture_id;
|
|
||||||
Size size;
|
Size size;
|
||||||
Size bearing;
|
Size bearing;
|
||||||
unsigned int advance;
|
unsigned int advance;
|
||||||
|
Vec2f tex_coords[4]; // the 4 corners of the character quad
|
||||||
} Character;
|
} Character;
|
||||||
|
|
||||||
|
typedef struct Characters {
|
||||||
|
uint key;
|
||||||
|
Character value;
|
||||||
|
} Characters;
|
||||||
|
|
||||||
|
typedef struct ZephFont {
|
||||||
|
Characters *characters;
|
||||||
|
unsigned int atlas_texture_id;
|
||||||
|
} ZephFont;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool should_quit;
|
bool should_quit;
|
||||||
Color clear_color;
|
Color clear_color;
|
||||||
Size window_size;
|
Size window_size;
|
||||||
|
ZephFont font;
|
||||||
|
|
||||||
Matrix4x4 projection;
|
Matrix4x4 projection;
|
||||||
} Context;
|
} Context;
|
||||||
@@ -59,5 +71,5 @@ void set_rotation_constraint(UIConstraints *constraints, float angle_d);
|
|||||||
void draw_quad(UIConstraints constraints, Color *color, float border_radius, Alignment align);
|
void draw_quad(UIConstraints constraints, Color *color, float border_radius, Alignment align);
|
||||||
void draw_circle(UIConstraints constraints, Color *color, Alignment align);
|
void draw_circle(UIConstraints constraints, Color *color, Alignment align);
|
||||||
void draw_triangle(UIConstraints constraints, Color *color, Alignment align);
|
void draw_triangle(UIConstraints constraints, Color *color, Alignment align);
|
||||||
void draw_text(const char* text, int font_size, UIConstraints constraints, Color *color, Alignment align);
|
void draw_text(const uint* text, int font_size, UIConstraints constraints, Color *color, Alignment align);
|
||||||
Sizef calculate_text_size(const char *text, int font_size);
|
Sizef calculate_text_size(const uint *text, int font_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user