mirror of
https://github.com/IllusionMan1212/cudoku.git
synced 2026-10-24 18:12:25 +00:00
delay text rendering until end of frame which renders ALL text in one draw call
This commit is contained in:
Vendored
-2
@@ -1,4 +1,2 @@
|
|||||||
#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
@@ -59,14 +59,14 @@ void draw_win() {
|
|||||||
/* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */
|
/* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */
|
||||||
|
|
||||||
Alignment align = ALIGN_TOP_LEFT;
|
Alignment align = ALIGN_TOP_LEFT;
|
||||||
int font_size = 84.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, 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); */
|
||||||
@@ -89,15 +89,6 @@ void draw_win() {
|
|||||||
set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED);
|
set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED);
|
||||||
/* set_rotation_constraint(&constraints, 0); */
|
/* 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) {
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ int main(int argc, char *argv[]) {
|
|||||||
/* float x = clampf(500.0f * timer_elapsed(&my_time), 0.0, window_size.width - size.width); */
|
/* float x = clampf(500.0f * timer_elapsed(&my_time), 0.0, window_size.width - size.width); */
|
||||||
/* draw_text("Bruh", 1.0f, (Vec2){0.0, size.height}, &(Color){255.f, 0.f, 0.f, 255.f}); */
|
/* draw_text("Bruh", 1.0f, (Vec2){0.0, size.height}, &(Color){255.f, 0.f, 0.f, 255.f}); */
|
||||||
|
|
||||||
|
|
||||||
|
zephr_batch_text_draw();
|
||||||
zephr_swap_buffers();
|
zephr_swap_buffers();
|
||||||
}
|
}
|
||||||
/* while (!quit) { */
|
/* while (!quit) { */
|
||||||
|
|||||||
+1
-1
@@ -4,10 +4,10 @@ layout (location = 0) in vec2 vertex;
|
|||||||
// per instance
|
// per instance
|
||||||
layout (location = 1) in vec4 offset;
|
layout (location = 1) in vec4 offset;
|
||||||
layout (location = 2) in int tex_index;
|
layout (location = 2) in int tex_index;
|
||||||
|
layout (location = 3) in mat4 model; // this takes locations 3,4,5,6
|
||||||
|
|
||||||
out vec2 v_TexCoords;
|
out vec2 v_TexCoords;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
uniform mat4 model;
|
|
||||||
// buffer for all the 96 ascii characters' texcoords
|
// buffer for all the 96 ascii characters' texcoords
|
||||||
uniform vec2 texcoords[96 * 4];
|
uniform vec2 texcoords[96 * 4];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- maybe force the window to be a specific resolution
|
- "premade" (but also customizable) ui elements (buttons, text boxes, etc) with instanced rendering
|
||||||
- border decorations for shapes
|
- maybe force the window to be a specific resolution (for cudoku only? or all games?)
|
||||||
|
- border decorations for shapes (maybe. or maybe only for ui elements)
|
||||||
- remove the hardcoded 1920 and 1080 values when applying relative pixel constraints
|
- remove the hardcoded 1920 and 1080 values when applying relative pixel constraints
|
||||||
and replace them with the screen's currently active resolution
|
and replace them with the screen's currently active resolution
|
||||||
|
|
||||||
@@ -28,17 +29,3 @@ text rendering improvements
|
|||||||
instances of text in one draw call without exceeding any buffer limits. Of course this does mean that if we were to support
|
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
|
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)
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#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,11 +18,6 @@
|
|||||||
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;
|
||||||
@@ -32,8 +26,6 @@ unsigned int ui_vao;
|
|||||||
unsigned int font_instance_vbo;
|
unsigned int font_instance_vbo;
|
||||||
unsigned int ui_vbo;
|
unsigned int ui_vbo;
|
||||||
|
|
||||||
// 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;
|
||||||
if (FT_Init_FreeType(&ft)) {
|
if (FT_Init_FreeType(&ft)) {
|
||||||
@@ -60,17 +52,10 @@ 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 tex_width = 1; */
|
|
||||||
/* while (tex_width < max_dim) { */
|
|
||||||
/* tex_width <<= 1; */
|
|
||||||
/* } */
|
|
||||||
/* uint tex_height = tex_width; */
|
|
||||||
|
|
||||||
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); */
|
||||||
|
|
||||||
uint tex_width = 0, tex_height = 0;
|
uint tex_width = 0, tex_height = 0;
|
||||||
for (uint i = 32; i < 128; i++) {
|
for (uint i = 32; i < 128; i++) {
|
||||||
@@ -166,6 +151,9 @@ int init_ui(const char* font_path, Size window_size) {
|
|||||||
|
|
||||||
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);
|
||||||
|
zephr_context.texts.instance_count = 0;
|
||||||
|
zephr_context.texts.instance_capacity = 16;
|
||||||
|
zephr_context.texts.instance_data = malloc(sizeof(TextInstance) * zephr_context.texts.instance_capacity);
|
||||||
|
|
||||||
int res = init_fonts(font_path);
|
int res = init_fonts(font_path);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
@@ -209,11 +197,23 @@ int init_ui(const char* font_path, Size window_size) {
|
|||||||
// font instance vbo
|
// font instance vbo
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void *)0);
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)0);
|
||||||
glVertexAttribDivisor(1, 1);
|
glVertexAttribDivisor(1, 1);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
glVertexAttribIPointer(2, 1, GL_INT, sizeof(InstanceData), (void *)sizeof(Vec4f));
|
glVertexAttribIPointer(2, 1, GL_INT, sizeof(TextInstance), (void *)sizeof(Vec4f));
|
||||||
glVertexAttribDivisor(2, 1);
|
glVertexAttribDivisor(2, 1);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
glEnableVertexAttribArray(4);
|
||||||
|
glEnableVertexAttribArray(5);
|
||||||
|
glEnableVertexAttribArray(6);
|
||||||
|
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) + sizeof(int)));
|
||||||
|
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 2 + sizeof(int)));
|
||||||
|
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 3 + sizeof(int)));
|
||||||
|
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 4 + sizeof(int)));
|
||||||
|
glVertexAttribDivisor(3, 1);
|
||||||
|
glVertexAttribDivisor(4, 1);
|
||||||
|
glVertexAttribDivisor(5, 1);
|
||||||
|
glVertexAttribDivisor(6, 1);
|
||||||
|
|
||||||
// font ebo
|
// font ebo
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_ebo);
|
||||||
@@ -325,9 +325,17 @@ bool zephr_should_quit() {
|
|||||||
|
|
||||||
// example of how to batch all text drawing in one drawcall
|
// example of how to batch all text drawing in one drawcall
|
||||||
// this should be called at the end of the frame
|
// this should be called at the end of the frame
|
||||||
/* void batch_text_draw(&zephr_context.texts) {
|
void zephr_batch_text_draw() {
|
||||||
* do something with zephr_context.texts
|
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
||||||
}*/
|
glBufferData(GL_ARRAY_BUFFER, sizeof(TextInstance) * zephr_context.texts.instance_count, zephr_context.texts.instance_data, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, zephr_context.texts.instance_count);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
zephr_context.texts.instance_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void zephr_swap_buffers() {
|
void zephr_swap_buffers() {
|
||||||
glXSwapBuffers(display, window);
|
glXSwapBuffers(display, window);
|
||||||
@@ -621,8 +629,6 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
|
|||||||
|
|
||||||
apply_translation(&model, pos);
|
apply_translation(&model, pos);
|
||||||
|
|
||||||
set_mat4f(font_shader, "model", (float *)model.m);
|
|
||||||
|
|
||||||
int max_bearing_h = 0;
|
int max_bearing_h = 0;
|
||||||
for (int i = 0; (i < text[i]) != '\0'; i++) {
|
for (int i = 0; (i < text[i]) != '\0'; i++) {
|
||||||
Character ch = zephr_context.font.characters[(int)text[i]];
|
Character ch = zephr_context.font.characters[(int)text[i]];
|
||||||
@@ -635,45 +641,39 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
|
|||||||
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 = zephr_context.font.characters[(int)text[c]];
|
Character ch = zephr_context.font.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 = /*(line * text_size.height) + */(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));
|
||||||
|
|
||||||
/* if (text[c] == '\n') { */
|
zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height};
|
||||||
/* line++; */
|
zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].tex_coords_index = (int)text[c] - 32;
|
||||||
/* x = 0; */
|
memcpy(zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].model, model.m, sizeof(float[4][4]));
|
||||||
/* c++; */
|
|
||||||
/* continue; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
instance_data[c].position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height};
|
|
||||||
instance_data[c].tex_coords_index = (int)text[c] - 32;
|
|
||||||
|
|
||||||
x += (ch.advance >> 6);
|
x += (ch.advance >> 6);
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
zephr_context.texts.instance_count += strlen(text);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceData) * strlen(text), instance_data, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, strlen(text));
|
if (zephr_context.texts.instance_count >= zephr_context.texts.instance_capacity) {
|
||||||
|
zephr_context.texts.instance_capacity *= 2;
|
||||||
free(instance_data);
|
TextInstance* new_ptr = realloc(zephr_context.texts.instance_data, sizeof(TextInstance) * zephr_context.texts.instance_capacity);
|
||||||
|
if (!new_ptr) {
|
||||||
glBindVertexArray(0);
|
printf("Failed to reallocate memory for text instances\n");
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
exit(1);
|
||||||
|
} else {
|
||||||
|
zephr_context.texts.instance_data = new_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enum Element { */
|
/* enum Element { */
|
||||||
|
|||||||
@@ -17,11 +17,24 @@ typedef struct ZephFont {
|
|||||||
unsigned int atlas_texture_id;
|
unsigned int atlas_texture_id;
|
||||||
} ZephFont;
|
} ZephFont;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct TextInstance {
|
||||||
|
Vec4f position;
|
||||||
|
int tex_coords_index;
|
||||||
|
float model[4][4];
|
||||||
|
} TextInstance;
|
||||||
|
|
||||||
|
typedef struct Text {
|
||||||
|
TextInstance *instance_data;
|
||||||
|
int instance_count;
|
||||||
|
int instance_capacity;
|
||||||
|
} Text;
|
||||||
|
|
||||||
|
typedef struct Context {
|
||||||
bool should_quit;
|
bool should_quit;
|
||||||
Color clear_color;
|
Color clear_color;
|
||||||
Size window_size;
|
Size window_size;
|
||||||
ZephFont font;
|
ZephFont font;
|
||||||
|
Text texts;
|
||||||
|
|
||||||
Matrix4x4 projection;
|
Matrix4x4 projection;
|
||||||
} Context;
|
} Context;
|
||||||
@@ -58,6 +71,7 @@ void deinit_zephr();
|
|||||||
bool zephr_should_quit();
|
bool zephr_should_quit();
|
||||||
void zephr_swap_buffers();
|
void zephr_swap_buffers();
|
||||||
Size zephr_get_window_size();
|
Size zephr_get_window_size();
|
||||||
|
void zephr_batch_text_draw();
|
||||||
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
void set_width_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
void set_width_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
|
|||||||
Reference in New Issue
Block a user