From 936b9b3e0f09edf92a17fcbacc43098c61728d9d Mon Sep 17 00:00:00 2001 From: talha Date: Sat, 22 Feb 2025 20:46:25 +0500 Subject: WIP: replacing freetype with stb_truetype --- source/main.cpp | 464 +++++++++++++++++++++-------------------- source/shaders/ui_text.vs.glsl | 1 + 2 files changed, 243 insertions(+), 222 deletions(-) (limited to 'source') diff --git a/source/main.cpp b/source/main.cpp index b20465e..c0e6b70 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,13 +1,20 @@ #include #include -#define MINIAUDIO_IMPLEMENTATION -#include "miniaudio.h" - #include +#include +#define FREETYPE 0 +#if FREETYPE #include #include FT_FREETYPE_H +#endif + +#define STB_TT 1 +#if STB_TT +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" +#endif #include @@ -87,11 +94,14 @@ enum PlatformKey { struct TextChar { s64 advance; Vec2 size; + Vec2 box0; + Vec2 box1; Vec2 bearing; }; struct TextState { u32 pixel_size; + r32 scale; u32 texture_atlas_id; u32 sp; u32 vao; @@ -161,8 +171,8 @@ struct EntityInfoArr { const int level_count = 2; static const char* base_level_path = "./levels/"; static const char *level_names[20] = { - "level0.txt", "level1.txt", + "level0.txt", }; struct Level0x1 { @@ -506,182 +516,6 @@ void setup_level(GameState *state, GLRenderer *renderer, Arena *arena) renderer->cam_update = 1; } -void gl_setup_text(TextState* state, FT_Face font_face) -{ - FT_Set_Pixel_Sizes(font_face, state->pixel_size, state->pixel_size); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glGenTextures(1, &(state->texture_atlas_id)); - glBindTexture(GL_TEXTURE_2D_ARRAY, state->texture_atlas_id); - - // generate texture - glTexImage3D( - GL_TEXTURE_2D_ARRAY, - 0, - GL_R8, - state->pixel_size, - state->pixel_size, - 128, - 0, - GL_RED, - GL_UNSIGNED_BYTE, - 0 - ); - - // generate characters - for (u32 c = 0; c < 128; c++) - { - if (FT_Load_Char(font_face, c, FT_LOAD_RENDER)) - { - printf("ERROR :: Freetype failed to load glyph: %c", c); - } - else - { - glTexSubImage3D( - GL_TEXTURE_2D_ARRAY, - 0, - 0, 0, // x, y offset - int(c), - font_face->glyph->bitmap.width, - font_face->glyph->bitmap.rows, - 1, - GL_RED, - GL_UNSIGNED_BYTE, - font_face->glyph->bitmap.buffer - ); - - // set texture options - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - TextChar tc; - tc.size = Vec2{ - (r32)font_face->glyph->bitmap.width, - (r32)font_face->glyph->bitmap.rows - }; - tc.bearing = Vec2{ - (r32)font_face->glyph->bitmap_left, - (r32)font_face->glyph->bitmap_top - }; - tc.advance = font_face->glyph->advance.x; - - state->char_map[c] = tc; - } - } - - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); - - // @note: this data is used for GL_TRIANGLE_STRIP - // as such the order for vertices for this is AntiCW -> CW -> AntiCW - // that can be seen in this array as it goes from ACW -> CW - r32 vertices[] = { - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 1.0f, - 1.0f, 0.0f - }; - - glGenVertexArrays(1, &(state->vao)); - glGenBuffers(1, &(state->vbo)); - - glBindVertexArray(state->vao); - glBindBuffer(GL_ARRAY_BUFFER, state->vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -void gl_render_text(GLRenderer *renderer, char* text, Vec2 position, r32 size, Vec3 color) -{ - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glUseProgram(renderer->ui_text.sp); - if (renderer->ui_cam_update) { - glUniformMatrix4fv(glGetUniformLocation(renderer->ui_text.sp, "View"), - 1, GL_FALSE, renderer->ui_cam_view.buffer); - glUniformMatrix4fv(glGetUniformLocation(renderer->ui_text.sp, "Projection"), - 1, GL_FALSE, renderer->cam_proj.buffer); - renderer->ui_cam_update = 0; - } - glUniform3fv(glGetUniformLocation(renderer->ui_text.sp, "TextColor"), 1, color.data); - glBindVertexArray(renderer->ui_text.vao); - glBindTexture(GL_TEXTURE_2D_ARRAY, renderer->ui_text.texture_atlas_id); - glBindBuffer(GL_ARRAY_BUFFER, renderer->ui_text.vbo); - glActiveTexture(GL_TEXTURE0); - - u32 running_index = 0; - r32 startx = position.x; - r32 starty = position.y; - r32 linex = startx; - r32 scale = size/renderer->ui_text.pixel_size; - memset(renderer->ui_text.transforms, 0, renderer->ui_text.chunk_size); - memset(renderer->ui_text.char_indexes, 0, renderer->ui_text.chunk_size); - - char *char_iter = text; - while (*char_iter != '\0') - { - TextChar render_char = renderer->ui_text.char_map[*char_iter]; - if (*char_iter == '\n') - { - linex = startx; - starty = starty - (render_char.size.y * 1.5 * scale); - } - else if (*char_iter == ' ') - { - linex += (render_char.advance >> 6) * scale; - } - else - { - r32 xpos = linex + (scale * render_char.bearing.x); - r32 ypos = starty - (renderer->ui_text.pixel_size - render_char.bearing.y) * scale; - - r32 w = scale * renderer->ui_text.pixel_size; - r32 h = scale * renderer->ui_text.pixel_size; - - Mat4 sm = scaling_matrix4m(w, h, 0); - Mat4 tm = translation_matrix4m(xpos, ypos, 0); - Mat4 model = multiply4m(tm, sm); - renderer->ui_text.transforms[running_index] = model; - renderer->ui_text.char_indexes[running_index] = int(*char_iter); - - linex += (render_char.advance >> 6) * scale; - running_index++; - if (running_index > renderer->ui_text.chunk_size - 1) - { - r32 transform_loc = glGetUniformLocation(renderer->ui_text.sp, "LetterTransforms"); - glUniformMatrix4fv(transform_loc, renderer->ui_text.chunk_size, - GL_FALSE, &(renderer->ui_text.transforms[0].buffer[0])); - r32 texture_map_loc = glGetUniformLocation(renderer->ui_text.sp, "TextureMap"); - glUniform1iv(texture_map_loc, renderer->ui_text.chunk_size, renderer->ui_text.char_indexes); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, renderer->ui_text.chunk_size); - running_index = 0; - memset(renderer->ui_text.transforms, 0, renderer->ui_text.chunk_size); - memset(renderer->ui_text.char_indexes, 0, renderer->ui_text.chunk_size); - } - } - char_iter++; - } - if (running_index > 0) - { - u32 render_count = running_index < renderer->ui_text.chunk_size ? running_index : renderer->ui_text.chunk_size; - r32 transform_loc = glGetUniformLocation(renderer->ui_text.sp, "LetterTransforms"); - glUniformMatrix4fv(transform_loc, render_count, - GL_FALSE, &(renderer->ui_text.transforms[0].buffer[0])); - r32 texture_map_loc = glGetUniformLocation(renderer->ui_text.sp, "TextureMap"); - glUniform1iv(texture_map_loc, render_count, renderer->ui_text.char_indexes); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, render_count); - running_index = 0; - memset(renderer->ui_text.transforms, 0, render_count); - memset(renderer->ui_text.char_indexes, 0, render_count); - } -} Vec2 get_move_dir(Controller c) { Vec2 dir = {}; @@ -823,48 +657,148 @@ int main(int argc, char* argv[]) r32 render_scale = 1.0f; //(r32)scr_width / (r32)base_scr_width; - // ========== - // setup text - // 1. setup free type library stuff - FT_Library ft_lib; - FT_Face roboto_font_face; - if (FT_Init_FreeType(&ft_lib)) - { - printf("ERROR :: Could not init freetype library\n"); - return -1; - } - - FT_Error error = FT_New_Face( - ft_lib, - "assets/fonts/Roboto.ttf", - 0, &roboto_font_face - ); - if (error == FT_Err_Unknown_File_Format) - { - printf("ERROR :: Font Loading Failed. The font format is unsupported\n"); - return -1; - } - else if (error) - { - printf("ERROR :: Font Loading Failed. Unknown error code: %d\n", error); - return -1; - } - // 2. setup gl text - // @note: we only support 128 characters, which is the basic ascii set - renderer.ui_text.chunk_size = 32; - renderer.ui_text.pixel_size = 32*render_scale; - renderer.ui_text.sp = ui_text_sp; - renderer.ui_text.transforms = (Mat4*)malloc( - renderer.ui_text.chunk_size*sizeof(Mat4) - ); - renderer.ui_text.char_indexes = (s32*)malloc( - renderer.ui_text.chunk_size*sizeof(s32) - ); - renderer.ui_text.char_map = (TextChar*)malloc( - 128*sizeof(TextChar) - ); - gl_setup_text(&(renderer.ui_text), roboto_font_face); - +{ + // ========== + // setup text + // setup stb_truetype stuff + stbtt_fontinfo font; + + size_t fsize = 0; + unsigned char *font_buffer = (unsigned char*)SDL_LoadFile("./assets/fonts/Roboto.ttf", &fsize); + stbtt_InitFont(&font, font_buffer, 0); + renderer.ui_text.pixel_size = 32*render_scale; + renderer.ui_text.sp = ui_text_sp; + renderer.ui_text.chunk_size = 32; + renderer.ui_text.transforms = (Mat4*)malloc( + renderer.ui_text.chunk_size*sizeof(Mat4) + ); + renderer.ui_text.char_indexes = (s32*)malloc( + renderer.ui_text.chunk_size*sizeof(s32) + ); + renderer.ui_text.char_map = (TextChar*)malloc( + 128*sizeof(TextChar) + ); + + // setup_text + TextState *uistate = &(renderer.ui_text); + + uistate->scale = stbtt_ScaleForPixelHeight(&font, uistate->pixel_size); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &(uistate->texture_atlas_id)); + glBindTexture(GL_TEXTURE_2D_ARRAY, uistate->texture_atlas_id); + + // generate texture + glTexImage3D( + GL_TEXTURE_2D_ARRAY, + 0, + GL_R8, + uistate->pixel_size, + uistate->pixel_size, + 128, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + 0); + + s32 ascent, descent, linegap = 0; + stbtt_GetFontVMetrics(&font, &ascent, &descent, &linegap); + s32 x0, x1, y0, y1; + stbtt_GetFontBoundingBox(&font, &x0, &y0, &x1, &y1); + for (u32 c = 0; c < 128; c++) + { + // @resume: working on replicating the + // freetype gl_setup_text function + s32 advance, lsb = 0; + stbtt_GetCodepointHMetrics(&font, c, &advance, &lsb); + s32 width, height, xoff, yoff = 0; + s32 bx0, bx1, by0, by1 = 0; + stbtt_GetCodepointBitmapBox( + &font, c, + uistate->scale, uistate->scale, + &bx0, &by0, + &bx1, &by1 + ); + + unsigned char *data = stbtt_GetCodepointBitmap( + &font, + uistate->scale, + uistate->scale, + c, + &width, + &height, + &xoff, + &yoff); + + glTexSubImage3D( + GL_TEXTURE_2D_ARRAY, + 0, + 0, 0, // x, y offset + int(c), + width, + height, + 1, + GL_RED, + GL_UNSIGNED_BYTE, + data + ); + // set texture options + glTexParameteri( + GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE + ); + glTexParameteri( + GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE + ); + glTexParameteri( + GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR + ); + glTexParameteri( + GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR + ); + + TextChar tc; + tc.size = Vec2{ + (r32)width, (r32)height + }; + tc.bearing = Vec2{ + (r32)(lsb + xoff), (r32)yoff + }; + tc.box0 = Vec2{ + (r32)bx0, (r32)by0 + }; + tc.box1 = Vec2{ + (r32)bx1, (r32)by1 + }; + tc.advance = advance; + uistate->char_map[c] = tc; + } + + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + + r32 vertices[] = { + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 1.0f, + 1.0f, 0.0f + }; + + glGenVertexArrays(1, &(uistate->vao)); + glGenBuffers(1, &(uistate->vbo)); + + glBindVertexArray(uistate->vao); + glBindBuffer(GL_ARRAY_BUFFER, uistate->vbo); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(vertices), + vertices, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + // ============ // setup camera @@ -1696,6 +1630,7 @@ int main(int argc, char* argv[]) gl_line_flush(&renderer); } +#if 0 // render_entities for (int i = 0; i < state.game_level.entity_count; i++) { Entity entity = state.game_level.entities[i]; @@ -1714,13 +1649,97 @@ int main(int argc, char* argv[]) } gl_cq_flush(&renderer); +#endif array_clear(&renderer.cq_pos_batch); array_clear(&renderer.cq_color_batch); renderer.cq_batch_count = 0; // render ui text + { + Vec3 color = Vec3{1.0f, 1.0f, 1.0f}; + // render_text + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(renderer.ui_text.sp); + if (renderer.ui_cam_update) { + glUniformMatrix4fv( + glGetUniformLocation( + renderer.ui_text.sp, "View"), + 1, GL_FALSE, renderer.ui_cam_view.buffer); + glUniformMatrix4fv( + glGetUniformLocation( + renderer.ui_text.sp, "Projection"), + 1, GL_FALSE, renderer.cam_proj.buffer); + renderer.ui_cam_update = 0; + } + glUniform3fv( + glGetUniformLocation( + renderer.ui_text.sp, "TextColor"), + 1, color.data); + glBindVertexArray(renderer.ui_text.vao); + glBindTexture( + GL_TEXTURE_2D_ARRAY, + renderer.ui_text.texture_atlas_id); + glBindBuffer(GL_ARRAY_BUFFER, renderer.ui_text.vbo); + glActiveTexture(GL_TEXTURE0); + + u32 running_index = 0; + r32 startx = 0.0f; + r32 starty = 0.0f; + r32 linex = startx; + r32 scale = renderer.ui_text.scale; + memset( + renderer.ui_text.transforms, + 0, + renderer.ui_text.chunk_size); + memset( + renderer.ui_text.char_indexes, + 0, + renderer.ui_text.chunk_size); + char *text = "qhick brown jumps over lazy dog"; + char *char_iter = text; + r32 baseline = -500.0f*scale; + while (*char_iter != '\0') { + TextChar render_char = renderer.ui_text.char_map[*char_iter]; + r32 xpos = linex + (scale * render_char.bearing.x); + r32 ypos = starty + (baseline - render_char.box0.y); + + Mat4 sc = scaling_matrix4m(32.0f, 32.0f, 1.0f); + Mat4 tr = translation_matrix4m(xpos, ypos, 0); + Mat4 model = multiply4m(tr, sc); + renderer.ui_text.transforms[running_index] = model; + renderer.ui_text.char_indexes[running_index] = + int(*char_iter); + + linex += (scale * render_char.advance); + running_index++; + char_iter++; + } + u32 render_count = running_index; + r32 transform_loc = glGetUniformLocation( + renderer.ui_text.sp, "LetterTransforms"); + glUniformMatrix4fv( + transform_loc, + render_count, + GL_FALSE, + &(renderer.ui_text.transforms[0].buffer[0]) + ); + r32 texture_map_loc = glGetUniformLocation( + renderer.ui_text.sp, "TextureMap"); + glUniform1iv( + texture_map_loc, + render_count, + renderer.ui_text.char_indexes); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, render_count); + running_index = 0; + memset(renderer.ui_text.transforms, 0, render_count); + memset(renderer.ui_text.char_indexes, 0, render_count); + } +#if FREETYPE char level_state_output[50]; sprintf(level_state_output, "is level clear = %d", state.level_state); gl_render_text( @@ -1787,6 +1806,7 @@ int main(int argc, char* argv[]) Vec2{0.0f, 40.0f}, 28.0f*render_scale, Vec3{0.0f, 0.0f, 0.0f}); +#endif SDL_GL_SwapWindow(window); diff --git a/source/shaders/ui_text.vs.glsl b/source/shaders/ui_text.vs.glsl index 9bba904..d33cdbe 100755 --- a/source/shaders/ui_text.vs.glsl +++ b/source/shaders/ui_text.vs.glsl @@ -11,6 +11,7 @@ void main() { gl_Position = Projection * View * LetterTransforms[gl_InstanceID] * vec4(aPos, 0.0, 1.0); vec2 tex = aPos; TexCoords = tex; + // flip texture coordinates TexCoords.y = 1.0 - TexCoords.y; Index = gl_InstanceID; } -- cgit v1.2.3