text instancing

This commit is contained in:
2023-12-11 23:00:31 +02:00
committed by Illusion
parent 3f4f9c5103
commit f71a9d742c
10 changed files with 197 additions and 77 deletions
+17 -7
View File
@@ -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 wide_str *win_text = U"You won!"; static const char *win_text = "You won!";
static const char *help_texts[HELP_TEXT_SIZE] = { static const char *help_texts[HELP_TEXT_SIZE] = {
"F1 - Toggle help", "F1 - Toggle help",
@@ -58,15 +58,15 @@ void draw_win() {
/* set_width_constraint(&constraints, window.width, UI_CONSTRAINT_FIXED); */ /* set_width_constraint(&constraints, window.width, UI_CONSTRAINT_FIXED); */
/* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */ /* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */
Alignment align = ALIGN_CENTER; Alignment align = ALIGN_TOP_LEFT;
int font_size = 72.0f; int font_size = 84.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, 0); */ /* set_rotation_constraint(&constraints, 0); */
/* UIConstraints circle_const; */ /* UIConstraints circle_const; */
@@ -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); */
@@ -87,7 +87,17 @@ void draw_win() {
set_width_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); set_width_constraint(&constraints, 1, UI_CONSTRAINT_FIXED);
set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED);
/* set_rotation_constraint(&constraints, 0); */
draw_text(win_text, font_size, constraints, &text_color, align); draw_text(win_text, font_size, constraints, &text_color, align);
/* for (int i = 0; i < 100; i++) { */
/* int x = rand() % window.width; */
/* int y = rand() % window.height; */
/* set_x_constraint(&constraints, x, UI_CONSTRAINT_FIXED); */
/* set_y_constraint(&constraints, y, UI_CONSTRAINT_FIXED); */
/* draw_text(win_text, font_size, constraints, &text_color, align); */
/* } */
} }
void set_scale_factor(int width, int height, float *x, float *y) { void set_scale_factor(int width, int height, float *x, float *y) {
-8
View File
@@ -70,14 +70,6 @@ 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;
} }
-3
View File
@@ -4,15 +4,12 @@
#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);
+5
View File
@@ -87,6 +87,11 @@ void set_float(Shader shader, const char *name, float val) {
glUniform1f(loc, val); glUniform1f(loc, val);
} }
void set_vec2f(Shader shader, const char *name, float val1, float val2) {
int loc = glGetUniformLocation(shader.program, name);
glUniform2f(loc, val1, val2);
}
void set_vec3f(Shader shader, const char *name, float val1, float val2, float val3) { void set_vec3f(Shader shader, const char *name, float val1, float val2, float val3) {
int loc = glGetUniformLocation(shader.program, name); int loc = glGetUniformLocation(shader.program, name);
glUniform3f(loc, val1, val2, val3); glUniform3f(loc, val1, val2, val3);
+1
View File
@@ -9,5 +9,6 @@ Shader create_shader(const char *vertex_path, const char *fragment_path);
void use_shader(Shader shader); void use_shader(Shader shader);
void set_mat4f(Shader shader, const char *name, float *mat); void set_mat4f(Shader shader, const char *name, float *mat);
void set_float(Shader shader, const char *name, float val); void set_float(Shader shader, const char *name, float val);
void set_vec2f(Shader shader, const char *name, float val1, float val2);
void set_vec3f(Shader shader, const char *name, float val1, float val2, float val3); void set_vec3f(Shader shader, const char *name, float val1, float val2, float val3);
void set_vec4f(Shader shader, const char *name, float val1, float val2, float val3, float val4); void set_vec4f(Shader shader, const char *name, float val1, float val2, float val3, float val4);
+18
View File
@@ -0,0 +1,18 @@
#version 330 core
layout (location = 0) in vec2 vertex;
// per instance
layout (location = 1) in vec4 offset;
layout (location = 2) in int tex_index;
out vec2 v_TexCoords;
uniform mat4 projection;
uniform mat4 model;
// buffer for all the 96 ascii characters' texcoords
uniform vec2 texcoords[96 * 4];
void main() {
vec2 pos = vec2((vertex.x) * offset.z, (vertex.y) * offset.w);
gl_Position = projection * model * vec4(pos + offset.xy, 0.0, 1.0);
v_TexCoords = texcoords[tex_index * 4 + gl_VertexID];
}
+26 -2
View File
@@ -4,8 +4,12 @@
and replace them with the screen's currently active resolution and replace them with the screen's currently active resolution
text rendering improvements text rendering improvements
- [x] unicode support (allows for non-ascii characters) - [ ] unicode support (allows for non-ascii characters)
- unicode support removed for the foreseeable future
- [x] atlas texture for text glyphs (this means we only load in one texture for all text) - [x] atlas texture for text glyphs (this means we only load in one texture for all text)
- [x] better estimation of atlas width and height (currently the generated atlas texture
has a lot of empty space (over 50% of the texture's height))
- ended up just looping over the ascii glyphs and finding the max width and height
- SDF generation allowing for better text scaling (slower but visually better) - 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. - SDF is too slow if we want to support unicode. it's acceptably fast for ascii only though.
@@ -17,4 +21,24 @@ text rendering improvements
Will probably end up using MSDF (if I can get it to work with C lol) 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) - [x] instanced rendering for text (this means we only have to do one draw call for all text)
running into problems. we got the positions to instance correctly but the texture coordinates
are more difficult to work with because we can't just send a texcoord per vertex per instance
- Ended up passing hardcoded texcoords of all glyphs to the shader using a uniform array which allows us to render infinite
instances of text in one draw call without exceeding any buffer limits. Of course this does mean that if we were to support
unicode we'd have to make the uniform array bigger and its size dynamic. So unicode is dropped for now
text tests / iGPU / Non-instaned rendering
- 10 texts / 72 font size
0.8-0.9ms per frame (1200-1300fps)
- 100 texts / 48 font size
1.2-1.3ms per frame (770-830fps)
- 1000 texts / 28 font size
9-9.5ms per frame (105-110fps)
- 10000 texts / 9 font size
80-85ms per frame (12-13fps)
+119 -49
View File
@@ -19,15 +19,20 @@
Display *display; Display *display;
Window window; Window window;
typedef struct InstanceData {
Vec4f position;
int tex_coords_index;
} InstanceData;
Context zephr_context; Context zephr_context;
Shader font_shader; Shader font_shader;
Shader ui_shader; Shader ui_shader;
unsigned int font_vao; unsigned int font_vao;
unsigned int ui_vao; unsigned int ui_vao;
unsigned int font_vbo; unsigned int font_instance_vbo;
unsigned int ui_vbo; unsigned int ui_vbo;
// TODO: instanced rendering of ui elements and text?? // TODO: instanced rendering of ui elements
int init_fonts(const char *font_path) { int init_fonts(const char *font_path) {
FT_Library ft; FT_Library ft;
@@ -55,22 +60,38 @@ int init_fonts(const char *font_path) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
uint max_dim = (1 + (face->size->metrics.height >> 6)) * ceilf(sqrtf(face->num_glyphs)); /* uint max_dim = (1 + (face->size->metrics.height >> 6)) * ceilf(sqrtf(face->num_glyphs)); */
uint tex_width = 1; /* uint tex_width = 1; */
while (tex_width < max_dim) { /* while (tex_width < max_dim) { */
tex_width <<= 1; /* tex_width <<= 1; */
} /* } */
uint tex_height = tex_width; /* uint tex_height = tex_width; */
char *pixels = (char *)calloc(tex_width * tex_height, 1);
int pen_x = 0, pen_y = 0; int pen_x = 0, pen_y = 0;
FT_UInt glyph_idx; FT_UInt glyph_idx;
FT_ULong c = FT_Get_First_Char(face, &glyph_idx); FT_ULong c = FT_Get_First_Char(face, &glyph_idx);
while (glyph_idx) { uint tex_width = 0, tex_height = 0;
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { for (uint i = 32; i < 128; i++) {
printf("[ERROR]: failed to load glyph for char '0x%lx'\n", c); if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
}
/* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */
tex_width += face->glyph->bitmap.width + 1;
tex_height = max(tex_height, face->glyph->bitmap.rows);
}
printf("[INFO] Texture size: %d,%d\n", tex_width, tex_height);
char *pixels = (char *)calloc(tex_width * tex_height, 1);
for (uint i = 32; i < 128; i++) {
/* while (glyph_idx) { */
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
} }
/* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */ /* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */
@@ -110,11 +131,11 @@ int init_fonts(const char *font_path) {
character.size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows }; 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 }; character.bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
hmput(zephr_context.font.characters, c, character); zephr_context.font.characters[i] = character;
pen_x += bmp->width + 1; pen_x += bmp->width + 1;
c = FT_Get_Next_Char(face, c, &glyph_idx); /* c = FT_Get_Next_Char(face, c, &glyph_idx); */
} }
unsigned int texture; unsigned int texture;
@@ -140,6 +161,9 @@ int init_fonts(const char *font_path) {
} }
int init_ui(const char* font_path, Size window_size) { int init_ui(const char* font_path, Size window_size) {
uint font_vbo;
uint font_ebo;
zephr_context.window_size = window_size; zephr_context.window_size = window_size;
zephr_context.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f); zephr_context.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
@@ -152,19 +176,58 @@ int init_ui(const char* font_path, Size window_size) {
return 1; return 1;
} }
font_shader = create_shader("shaders/ui.vert", "shaders/font.frag"); font_shader = create_shader("shaders/font.vert", "shaders/font.frag");
ui_shader = create_shader("shaders/ui.vert", "shaders/ui.frag"); ui_shader = create_shader("shaders/ui.vert", "shaders/ui.frag");
glGenVertexArrays(1, &font_vao); glGenVertexArrays(1, &font_vao);
glGenVertexArrays(1, &ui_vao); glGenVertexArrays(1, &ui_vao);
glGenBuffers(1, &font_vbo); glGenBuffers(1, &font_vbo);
glGenBuffers(1, &font_instance_vbo);
glGenBuffers(1, &font_ebo);
glGenBuffers(1, &ui_vbo); glGenBuffers(1, &ui_vbo);
float quad_vertices[4][2] = {
{0.0, 1.0}, // top left
{1.0, 1.0}, // top right
{1.0, 0.0}, // bottom right
{0.0, 0.0}, // bottom left
};
int quad_indices[6] = {
0, 1, 2,
2, 3, 0
};
glBindVertexArray(font_vao); glBindVertexArray(font_vao);
// font quad vbo
glBindBuffer(GL_ARRAY_BUFFER, font_vbo); glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 2, quad_vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
// font instance vbo
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void *)0);
glVertexAttribDivisor(1, 1);
glEnableVertexAttribArray(2);
glVertexAttribIPointer(2, 1, GL_INT, sizeof(InstanceData), (void *)sizeof(Vec4f));
glVertexAttribDivisor(2, 1);
// font ebo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_indices), quad_indices, GL_STATIC_DRAW);
use_shader(font_shader);
for (int i = 32; i < 128; i++) {
for (int j = 0; j < 4; j++) {
char text[32];
snprintf(text, 32, "texcoords[%d]", (i - 32) * 4 + j);
set_vec2f(font_shader, text, zephr_context.font.characters[i].tex_coords[j].x, zephr_context.font.characters[i].tex_coords[j].y);
}
}
glBindVertexArray(ui_vao); glBindVertexArray(ui_vao);
glBindBuffer(GL_ARRAY_BUFFER, ui_vbo); glBindBuffer(GL_ARRAY_BUFFER, ui_vbo);
@@ -256,9 +319,16 @@ bool zephr_should_quit() {
/* update_ui(); */ /* update_ui(); */
audio_update(); audio_update();
return zephr_context.should_quit; return zephr_context.should_quit;
} }
// example of how to batch all text drawing in one drawcall
// this should be called at the end of the frame
/* void batch_text_draw(&zephr_context.texts) {
* do something with zephr_context.texts
}*/
void zephr_swap_buffers() { void zephr_swap_buffers() {
glXSwapBuffers(display, window); glXSwapBuffers(display, window);
} }
@@ -267,7 +337,7 @@ Size zephr_get_window_size() {
return zephr_context.window_size; return zephr_context.window_size;
} }
Sizef calculate_text_size(const wide_str *text, int font_size) { Sizef calculate_text_size(const char *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;
@@ -275,29 +345,27 @@ Sizef calculate_text_size(const wide_str *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 < text[i]) != '\0'; i++) { for (int i = 0; text[i] != '\0'; i++) {
Character ch = hmget(zephr_context.font.characters, (uint)text[i]); Character ch = 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 < text[i]) != '\0'; i++) { for (int i = 0; text[i] != '\0'; i++) {
Character ch = hmget(zephr_context.font.characters, (uint)text[i]); Character ch = 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 && wide_str_len(text) > 1) { if (i == 0 && strlen(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 == wide_str_len(text) - 1) { if (i == strlen(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 (wide_str_len(text) == 1) { if (strlen(text) == 1) {
w -= (ch.bearing.width); w -= (ch.bearing.width);
} }
@@ -525,7 +593,7 @@ void draw_triangle(UIConstraints constraints, Color *color, Alignment align) {
glBindVertexArray(0); glBindVertexArray(0);
} }
void draw_text(const wide_str* text, int font_size, UIConstraints constraints, Color *color, Alignment alignment) { void draw_text(const char* 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);
@@ -556,52 +624,54 @@ void draw_text(const wide_str* text, int font_size, UIConstraints constraints, C
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 < text[i]) != '\0'; i++) { for (int i = 0; (i < text[i]) != '\0'; i++) {
Character ch = hmget(zephr_context.font.characters, text[i]); Character ch = zephr_context.font.characters[(int)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 = hmget(zephr_context.font.characters, (int)text[0]).bearing.width; float first_char_bearing_w = 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); glBindTexture(GL_TEXTURE_2D, zephr_context.font.atlas_texture_id);
glBindVertexArray(font_vao); glBindVertexArray(font_vao);
InstanceData* instance_data = malloc(sizeof(InstanceData) * strlen(text));
// 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
// scale up or down the model matrix to get the desired font size. // scale up or down the model matrix to get the desired font size.
// this way everything works out fine and we get to transform the text using the // this way everything works out fine and we get to transform the text using the
// model matrix // model matrix
int c = 0; int c = 0;
int x = 0; int x = 0;
/* int line = 0; */
while (text[c] != '\0') { while (text[c] != '\0') {
Character ch = hmget(zephr_context.font.characters, text[c]); Character ch = zephr_context.font.characters[(int)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 = /*(line * text_size.height) + */(text_size.height - ch.bearing.height - (text_size.height - max_bearing_h));
float vertices[6][4] = { /* if (text[c] == '\n') { */
{xpos, ypos + ch.size.height, ch.tex_coords[0].x, ch.tex_coords[0].y}, /* line++; */
{xpos, ypos, ch.tex_coords[3].x, ch.tex_coords[3].y}, /* x = 0; */
{xpos + ch.size.width, ypos, ch.tex_coords[2].x, ch.tex_coords[2].y}, /* c++; */
/* continue; */
/* } */
{xpos, ypos + ch.size.height, ch.tex_coords[0].x, ch.tex_coords[0].y}, instance_data[c].position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height};
{xpos + ch.size.width, ypos, ch.tex_coords[2].x, ch.tex_coords[2].y}, instance_data[c].tex_coords_index = (int)text[c] - 32;
{xpos + ch.size.width, ypos + ch.size.height, ch.tex_coords[1].x, ch.tex_coords[1].y},
};
glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.advance >> 6); x += (ch.advance >> 6);
c++; c++;
} }
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceData) * strlen(text), instance_data, GL_DYNAMIC_DRAW);
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, strlen(text));
free(instance_data);
glBindVertexArray(0); glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
+3 -8
View File
@@ -12,13 +12,8 @@ typedef struct Character {
Vec2f tex_coords[4]; // the 4 corners of the character quad Vec2f tex_coords[4]; // the 4 corners of the character quad
} Character; } Character;
typedef struct Characters {
uint key;
Character value;
} Characters;
typedef struct ZephFont { typedef struct ZephFont {
Characters *characters; Character characters[128];
unsigned int atlas_texture_id; unsigned int atlas_texture_id;
} ZephFont; } ZephFont;
@@ -71,5 +66,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 uint* text, int font_size, UIConstraints constraints, Color *color, Alignment align); void draw_text(const char* text, int font_size, UIConstraints constraints, Color *color, Alignment align);
Sizef calculate_text_size(const uint *text, int font_size); Sizef calculate_text_size(const char *text, int font_size);
+8
View File
@@ -24,6 +24,14 @@ typedef struct Vec2f {
float y; float y;
} Vec2f; } Vec2f;
typedef struct Vec4f {
float x;
float y;
float z;
float w;
} Vec4f;
typedef struct Color { typedef struct Color {
float r; float r;
float g; float g;