diff --git a/src/renderer/text_renderer.cpp b/src/renderer/text_renderer.cpp index a53cb34..5325ec9 100644 --- a/src/renderer/text_renderer.cpp +++ b/src/renderer/text_renderer.cpp @@ -7,6 +7,7 @@ ******************************************************************************/ #include "text_renderer.h" +#include "renderer2D.h" #include #include "texture.h" @@ -99,6 +100,8 @@ namespace lunarium u32 max_width = 0; u32 max_height = 0; + u32 running_width = 0; + for (u8 c = 0; c < 128; c++) { // Load character glyph @@ -115,7 +118,7 @@ namespace lunarium Character character = Character { - c, pixel_data, 0, 0, Sizeu { width, height }, + c, pixel_data, 0, 0, Sizei { (i32)width, (i32)height }, glm::vec2((float)face->glyph->bitmap_left, (float)face->glyph->bitmap_top), // bearing (int)face->glyph->bitmap.rows - face->glyph->bitmap_top, // downshift (unsigned int)face->glyph->advance.x // advance @@ -147,6 +150,13 @@ namespace lunarium } } + // Set the character's texture offsets to the max values + for (int i = 0; i < mFonts.back().CharSet.size(); i++) + { + mFonts.back().CharSet[i].TextureDataWidthOffset = max_width * i; + mFonts.back().CharSet[i].TextureDataHeightOffset = 0; // TEXTURE IS ONE ROW SO THIS IS ALWAYS ZERO + } + // Put the font texture together u32 single_row_width = f.CharSet.size() * max_width; if (single_row_width > Texture::GetMaxSize()) @@ -190,9 +200,85 @@ namespace lunarium return fontIdx; } - void TextRenderer::DrawString(Renderer2D& r, u32 font_id, const char* str, Rectangle bounding_box, Color c, float scale) + void TextRenderer::DrawString(Renderer2D& r, u32 font_id, const char* str, Rectangle bounding_box, Color color, float scale) { - + if (font_id < 0 || font_id >= mFonts.size()) + { + Logger::Error(LogCategory::GRAPHICS, "Invalid font ID specified for DrawString: %d", font_id); + return; + } + + float lineSize = (mFonts[font_id].MaxHeight + mFonts[font_id].MaxDownShift) * scale; + + float curX = bounding_box.left(); //topLeft.x; + float curY = bounding_box.top(); //topLeft.y; + + // Iterate through all characters + int len = (int)strlen(str); + for (int c = 0; c < len; c++) + { + // if the last character was a space then we must + // be starting a new word + if (c > 0 && ' ' == str[c - 1]) + { + // check the total advance of this word to see if + // it would go beyond the right boundry + float totalAdvance = 0; + for (int i = c; str[i] != ' ' && str[i] != '\0'; i++) + { + Character ch = mFonts[font_id].CharSet[str[c]]; + + totalAdvance += (ch.Advance >> 6) * scale; + } + + + if (curX + totalAdvance > bounding_box.right()) + { + curX = bounding_box.left(); + curY += lineSize; + } + + if (curY + lineSize > bounding_box.bottom()) + { + break; + } + } + + + Character ch = mFonts[font_id].CharSet[str[c]]; + + float xpos = curX + ch.Bearing.x * scale; + float ypos = curY + (mFonts[font_id].MaxHeight - ch.Size.Height) * scale; + + // Apply a down offset if the char should go below the baseline + ypos += (ch.DownShift * scale); + + // NOTE: The following code does not work because it assumes that positive y is the upward direction + // + //GLfloat test_ypos = curY + (ch.Size.Height - ch.Bearing.Y) * scale; + // + + float w = ch.Size.Width * scale; + float h = ch.Size.Height * scale; + // Update VBO for each character + // float vertices[6][4] = { + // { xpos, ypos + h, 0.0, 1.0 }, + // { xpos + w, ypos, 1.0, 0.0 }, + // { xpos, ypos, 0.0, 0.0 }, + + // { xpos, ypos + h, 0.0, 1.0 }, + // { xpos + w, ypos + h, 1.0, 1.0 }, + // { xpos + w, ypos, 1.0, 0.0 } + // }; + // Now advance cursors for next glyph (note that advance is number of 1/64 pixels) + curX += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64) + + // DrawQuad + float offset_x = ch.TextureDataWidthOffset; + float offset_y = ch.TextureDataHeightOffset; + Rectangle tex_region = Rectangle::MakeFromTopLeft(offset_x, offset_y, ch.Size.Width, ch.Size.Height); + r.DrawQuad(Rectangle::MakeFromTopLeft(xpos, ypos, w, h), color, mFonts[font_id].FontTexture, 0.0f, tex_region); + } } diff --git a/src/renderer/text_renderer.h b/src/renderer/text_renderer.h index 25aa61e..9de1a8b 100644 --- a/src/renderer/text_renderer.h +++ b/src/renderer/text_renderer.h @@ -53,7 +53,7 @@ namespace lunarium u8* PixelDataBuffer; // Temporary storage for the character's pixel data - this should be cleanup after the font texture is created u32 TextureDataWidthOffset; // how far into the row does this chars texture data begin u32 TextureDataHeightOffset; // how far into the col does this chars texture data begin - Sizeu Size; // Size of glyph + Sizei Size; // Size of glyph glm::vec2 Bearing; // Offset from baseline to left/top of glyph int DownShift; // Size/Amount of glyph below the baseline unsigned int Advance; // Offset to advance to next glyph @@ -65,7 +65,7 @@ namespace lunarium std::string Name; // The tallest character that does not go below the base line // This is also the distance from the string Y position to the baseline - u32 MaxHeight; + i32 MaxHeight; // This is the max distance a char will go below the baseline u32 MaxDownShift; diff --git a/src/run_modes/testbed/scenes/simple_render_scene.cpp b/src/run_modes/testbed/scenes/simple_render_scene.cpp index a4e1114..d9ef506 100644 --- a/src/run_modes/testbed/scenes/simple_render_scene.cpp +++ b/src/run_modes/testbed/scenes/simple_render_scene.cpp @@ -27,7 +27,7 @@ namespace lunarium { SimpleRenderScene::SimpleRenderScene(uint32_t logCat) - : BaseScene(logCat), mTestMode(TestMode::String), mFrameTime(0.0), mNumFrames(0) + : BaseScene(logCat), mTestMode(TestMode::Basic), mFrameTime(0.0), mNumFrames(0), mpTestImageLoad3(nullptr) { srand((u32)time(0)); } @@ -65,9 +65,10 @@ namespace lunarium mSrcWidth = w; mSrcHeight = h; - //delete[] buffer; + delete[] buffer; stbi_set_flip_vertically_on_load(0); buffer = stbi_load("debug_texture.jpeg", &w, &h, &n, 0); + //buffer = stbi_load("lunarium_text_test.png", &w, &h, &n, 0); format = TextureFormat::RGBA; if (n == 3) @@ -80,7 +81,23 @@ namespace lunarium } mpTestImageLoad2 = Texture::Create(buffer, w, h, format); - //delete[] buffer; + delete[] buffer; + + stbi_set_flip_vertically_on_load(0); + buffer = stbi_load("lunarium_text_test.png", &w, &h, &n, 0); + + format = TextureFormat::RGBA; + if (n == 3) + { + format = TextureFormat::RGB; + } + else if (n == 1) + { + format = TextureFormat::RED; + } + + mpTestImageLoad3 = Texture::Create(buffer, w, h, format); + delete[] buffer; mQuads = new Rectangle[NUM_QUADS]; for (int i = 0; i < NUM_QUADS; i++) @@ -181,10 +198,16 @@ namespace lunarium mTestMode = TestMode::Stress; else if (mTestMode == TestMode::Stress) + { + mSubTex = Rectangle::MakeFromTopLeft(2858, 0, 32, 32); mTestMode = TestMode::String; + } else if (mTestMode == TestMode::String) + { mTestMode = TestMode::Basic; + mSubTex = Rectangle::MakeFromTopLeft(0, 0, 256, 256); + } } if (Core::Input().IsKeyPressed(KeyCode::Q)) @@ -331,9 +354,13 @@ namespace lunarium void SimpleRenderScene::RenderStringTest(Renderer2D& g) { Texture* dt = g.GetTextDebugTexture(); - g.DrawQuad(Rectangle(mTextDebugPosX, 400, dt->GetWidth() , dt->GetHeight() ), Color::Blue(), dt); + g.DrawQuad(Rectangle(mTextDebugPosX, 300, dt->GetWidth() , dt->GetHeight() ), Color::Blue(), dt); + g.DrawQuad(Rectangle(200, 100, 32, 32), Color(0.25f, 0.75f, 0.6f, 1.0f), mpTestImageLoad3, 0.0f, mSubTex); + + g.DrawString("A", Rectangle(200, 170, 32, 32), Color(0.25f, 0.75f, 0.6f, 1.0f)); - //g.DrawString("This is a test string!", Rectangle(100, 400, 200, 50), Color::Green()); + g.DrawString("This is a test string!", Rectangle::MakeFromTopLeft(100, 500, 500, 50), Color::Green()); + g.DrawString("This is a very long string that should end up on more than one line when printed out test string!", Rectangle::MakeFromTopLeft(300, 50, 400, 500), Color::Red()); } diff --git a/src/run_modes/testbed/scenes/simple_render_scene.h b/src/run_modes/testbed/scenes/simple_render_scene.h index fe6d0c7..b23de54 100644 --- a/src/run_modes/testbed/scenes/simple_render_scene.h +++ b/src/run_modes/testbed/scenes/simple_render_scene.h @@ -43,6 +43,7 @@ namespace lunarium Texture* mpRenderedImage; Texture* mpTestImageLoad; Texture* mpTestImageLoad2; + Texture* mpTestImageLoad3; FrameBuffer* mFrameBufferOne; FrameBuffer* mFrameBufferTwo; float angle; @@ -60,12 +61,14 @@ namespace lunarium TestMode mTestMode; + // STRESS TEST MODE int mNumQuadsToRender = 500; bool mUseTextures = false; const int NUM_QUADS = 50000; Color* mQuadColors; Rectangle* mQuads; Texture** mQuadTexures; + // struct GridTestObj {