Skip to content

Commit

Permalink
Rendering text successfully!
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCherno committed Feb 20, 2023
1 parent 97d3ee3 commit d32b9a2
Show file tree
Hide file tree
Showing 8 changed files with 377 additions and 13 deletions.
45 changes: 38 additions & 7 deletions Hazel/src/Hazel/Renderer/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,10 @@
#include "FontGeometry.h"
#include "GlyphGeometry.h"

namespace Hazel {
#include "MSDFData.h"

struct MSDFData
{
std::vector<msdf_atlas::GlyphGeometry> Glyphs;
msdf_atlas::FontGeometry FontGeometry;
namespace Hazel {

};

template<typename T, typename S, int N, msdf_atlas::GeneratorFunction<S, N> GenFunc>
static Ref<Texture2D> CreateAndCacheAtlas(const std::string& fontName, float fontSize, const std::vector<msdf_atlas::GlyphGeometry>& glyphs,
const msdf_atlas::FontGeometry& fontGeometry, uint32_t width, uint32_t height)
Expand Down Expand Up @@ -96,6 +91,32 @@ namespace Hazel {
atlasPacker.getDimensions(width, height);
emSize = atlasPacker.getScale();

#define DEFAULT_ANGLE_THRESHOLD 3.0
#define LCG_MULTIPLIER 6364136223846793005ull
#define LCG_INCREMENT 1442695040888963407ull
#define THREAD_COUNT 8
// if MSDF || MTSDF

uint64_t coloringSeed = 0;
bool expensiveColoring = false;
if (expensiveColoring)
{
msdf_atlas::Workload([&glyphs = m_Data->Glyphs, &coloringSeed](int i, int threadNo) -> bool {
unsigned long long glyphSeed = (LCG_MULTIPLIER * (coloringSeed ^ i) + LCG_INCREMENT) * !!coloringSeed;
glyphs[i].edgeColoring(msdfgen::edgeColoringInkTrap, DEFAULT_ANGLE_THRESHOLD, glyphSeed);
return true;
}, m_Data->Glyphs.size()).finish(THREAD_COUNT);
}
else {
unsigned long long glyphSeed = coloringSeed;
for (msdf_atlas::GlyphGeometry& glyph : m_Data->Glyphs)
{
glyphSeed *= LCG_MULTIPLIER;
glyph.edgeColoring(msdfgen::edgeColoringInkTrap, DEFAULT_ANGLE_THRESHOLD, glyphSeed);
}
}


m_AtlasTexture = CreateAndCacheAtlas<uint8_t, float, 3, msdf_atlas::msdfGenerator>("Test", (float)emSize, m_Data->Glyphs, m_Data->FontGeometry, width, height);


Expand Down Expand Up @@ -123,4 +144,14 @@ namespace Hazel {
delete m_Data;
}


Ref<Font> Font::GetDefault()
{
static Ref<Font> DefaultFont;
if (!DefaultFont)
DefaultFont = CreateRef<Font>("assets/fonts/opensans/OpenSans-Regular.ttf");

return DefaultFont;
}

}
3 changes: 3 additions & 0 deletions Hazel/src/Hazel/Renderer/Font.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ namespace Hazel {
Font(const std::filesystem::path& font);
~Font();

const MSDFData* GetMSDFData() const { return m_Data; }
Ref<Texture2D> GetAtlasTexture() const { return m_AtlasTexture; }

static Ref<Font> GetDefault();
private:
MSDFData* m_Data;
Ref<Texture2D> m_AtlasTexture;
Expand Down
17 changes: 17 additions & 0 deletions Hazel/src/Hazel/Renderer/MSDFData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <vector>

#undef INFINITE
#include "msdf-atlas-gen.h"

namespace Hazel {

struct MSDFData
{
std::vector<msdf_atlas::GlyphGeometry> Glyphs;
msdf_atlas::FontGeometry FontGeometry;
};


}
152 changes: 150 additions & 2 deletions Hazel/src/Hazel/Renderer/Renderer2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "MSDFData.h"

namespace Hazel {

struct QuadVertex
Expand Down Expand Up @@ -44,6 +46,18 @@ namespace Hazel {
int EntityID;
};

struct TextVertex
{
glm::vec3 Position;
glm::vec4 Color;
glm::vec2 TexCoord;

// TODO: bg color for outline/bg

// Editor-only
int EntityID;
};

struct Renderer2DData
{
static const uint32_t MaxQuads = 20000;
Expand All @@ -62,7 +76,11 @@ namespace Hazel {

Ref<VertexArray> LineVertexArray;
Ref<VertexBuffer> LineVertexBuffer;
Ref<Shader> LineShader;
Ref<Shader> LineShader;

Ref<VertexArray> TextVertexArray;
Ref<VertexBuffer> TextVertexBuffer;
Ref<Shader> TextShader;

uint32_t QuadIndexCount = 0;
QuadVertex* QuadVertexBufferBase = nullptr;
Expand All @@ -76,10 +94,16 @@ namespace Hazel {
LineVertex* LineVertexBufferBase = nullptr;
LineVertex* LineVertexBufferPtr = nullptr;

uint32_t TextIndexCount = 0;
TextVertex* TextVertexBufferBase = nullptr;
TextVertex* TextVertexBufferPtr = nullptr;

float LineWidth = 2.0f;

std::array<Ref<Texture2D>, MaxTextureSlots> TextureSlots;
uint32_t TextureSlotIndex = 1; // 0 = white texture

Ref<Texture2D> FontAtlasTexture;

glm::vec4 QuadVertexPositions[4];

Expand Down Expand Up @@ -162,6 +186,20 @@ namespace Hazel {
s_Data.LineVertexArray->AddVertexBuffer(s_Data.LineVertexBuffer);
s_Data.LineVertexBufferBase = new LineVertex[s_Data.MaxVertices];

// Text
s_Data.TextVertexArray = VertexArray::Create();

s_Data.TextVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(TextVertex));
s_Data.TextVertexBuffer->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float4, "a_Color" },
{ ShaderDataType::Float2, "a_TexCoord" },
{ ShaderDataType::Int, "a_EntityID" }
});
s_Data.TextVertexArray->AddVertexBuffer(s_Data.TextVertexBuffer);
s_Data.TextVertexArray->SetIndexBuffer(quadIB);
s_Data.TextVertexBufferBase = new TextVertex[s_Data.MaxVertices];

s_Data.WhiteTexture = Texture2D::Create(TextureSpecification());
uint32_t whiteTextureData = 0xffffffff;
s_Data.WhiteTexture->SetData(&whiteTextureData, sizeof(uint32_t));
Expand All @@ -173,6 +211,7 @@ namespace Hazel {
s_Data.QuadShader = Shader::Create("assets/shaders/Renderer2D_Quad.glsl");
s_Data.CircleShader = Shader::Create("assets/shaders/Renderer2D_Circle.glsl");
s_Data.LineShader = Shader::Create("assets/shaders/Renderer2D_Line.glsl");
s_Data.TextShader = Shader::Create("assets/shaders/Renderer2D_Text.glsl");

// Set first texture slot to 0
s_Data.TextureSlots[0] = s_Data.WhiteTexture;
Expand Down Expand Up @@ -238,7 +277,10 @@ namespace Hazel {
s_Data.CircleVertexBufferPtr = s_Data.CircleVertexBufferBase;

s_Data.LineVertexCount = 0;
s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase;
s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase;

s_Data.TextIndexCount = 0;
s_Data.TextVertexBufferPtr = s_Data.TextVertexBufferBase;

s_Data.TextureSlotIndex = 1;
}
Expand Down Expand Up @@ -279,6 +321,19 @@ namespace Hazel {
RenderCommand::DrawLines(s_Data.LineVertexArray, s_Data.LineVertexCount);
s_Data.Stats.DrawCalls++;
}

if (s_Data.TextIndexCount)
{
uint32_t dataSize = (uint32_t)((uint8_t*)s_Data.TextVertexBufferPtr - (uint8_t*)s_Data.TextVertexBufferBase);
s_Data.TextVertexBuffer->SetData(s_Data.TextVertexBufferBase, dataSize);

auto buf = s_Data.TextVertexBufferBase;
s_Data.FontAtlasTexture->Bind(0);

s_Data.TextShader->Bind();
RenderCommand::DrawIndexed(s_Data.TextVertexArray, s_Data.TextIndexCount);
s_Data.Stats.DrawCalls++;
}
}

void Renderer2D::NextBatch()
Expand Down Expand Up @@ -495,6 +550,99 @@ namespace Hazel {
DrawQuad(transform, src.Color, entityID);
}

void Renderer2D::DrawString(const std::string& string, Ref<Font> font, const glm::mat4& transform, const glm::vec4& color)
{
const auto& fontGeometry = font->GetMSDFData()->FontGeometry;
const auto& metrics = fontGeometry.getMetrics();
Ref<Texture2D> fontAtlas = font->GetAtlasTexture();

s_Data.FontAtlasTexture = fontAtlas;

double x = 0.0;
double fsScale = 1.0 / (metrics.ascenderY - metrics.descenderY);
double y = 0.0;
float lineHeightOffset = 0.0f;

for (size_t i = 0; i < string.size(); i++)
{
char character = string[i];
if (character == '\r')
continue;

if (character == '\n')
{
x = 0;
y -= fsScale * metrics.lineHeight + lineHeightOffset;
continue;
}
auto glyph = fontGeometry.getGlyph(character);
if (!glyph)
glyph = fontGeometry.getGlyph('?');
if (!glyph)
return;

if (character == '\t')
glyph = fontGeometry.getGlyph(' ');

double al, ab, ar, at;
glyph->getQuadAtlasBounds(al, ab, ar, at);
glm::vec2 texCoordMin((float)al, (float)ab);
glm::vec2 texCoordMax((float)ar, (float)at);

double pl, pb, pr, pt;
glyph->getQuadPlaneBounds(pl, pb, pr, pt);
glm::vec2 quadMin((float)pl, (float)pb);
glm::vec2 quadMax((float)pr, (float)pt);

quadMin *= fsScale, quadMax *= fsScale;
quadMin += glm::vec2(x, y);
quadMax += glm::vec2(x, y);

float texelWidth = 1.0f / fontAtlas->GetWidth();
float texelHeight = 1.0f / fontAtlas->GetHeight();
texCoordMin *= glm::vec2(texelWidth, texelHeight);
texCoordMax *= glm::vec2(texelWidth, texelHeight);

// render here
s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMin, 0.0f, 1.0f);
s_Data.TextVertexBufferPtr->Color = color;
s_Data.TextVertexBufferPtr->TexCoord = texCoordMin;
s_Data.TextVertexBufferPtr->EntityID = 0; // TODO
s_Data.TextVertexBufferPtr++;

s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMin.x, quadMax.y, 0.0f, 1.0f);
s_Data.TextVertexBufferPtr->Color = color;
s_Data.TextVertexBufferPtr->TexCoord = { texCoordMin.x, texCoordMax.y };
s_Data.TextVertexBufferPtr->EntityID = 0; // TODO
s_Data.TextVertexBufferPtr++;

s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMax, 0.0f, 1.0f);
s_Data.TextVertexBufferPtr->Color = color;
s_Data.TextVertexBufferPtr->TexCoord = texCoordMax;
s_Data.TextVertexBufferPtr->EntityID = 0; // TODO
s_Data.TextVertexBufferPtr++;

s_Data.TextVertexBufferPtr->Position = transform * glm::vec4(quadMax.x, quadMin.y, 0.0f, 1.0f);
s_Data.TextVertexBufferPtr->Color = color;
s_Data.TextVertexBufferPtr->TexCoord = { texCoordMax.x, texCoordMin.y };
s_Data.TextVertexBufferPtr->EntityID = 0; // TODO
s_Data.TextVertexBufferPtr++;

s_Data.TextIndexCount += 6;
s_Data.Stats.QuadCount++;

if (i < string.size() - 1)
{
double advance = glyph->getAdvance();
char nextCharacter = string[i + 1];
fontGeometry.getAdvance(advance, character, nextCharacter);

float kerningOffset = 0.0f;
x += fsScale * advance + kerningOffset;
}
}
}

float Renderer2D::GetLineWidth()
{
return s_Data.LineWidth;
Expand Down
3 changes: 3 additions & 0 deletions Hazel/src/Hazel/Renderer/Renderer2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "Hazel/Renderer/Camera.h"
#include "Hazel/Renderer/EditorCamera.h"
#include "Hazel/Renderer/Font.h"

#include "Hazel/Scene/Components.h"

Expand Down Expand Up @@ -46,6 +47,8 @@ namespace Hazel {

static void DrawSprite(const glm::mat4& transform, SpriteRendererComponent& src, int entityID);

static void DrawString(const std::string& string, Ref<Font> font, const glm::mat4& transform, const glm::vec4& color);

static float GetLineWidth();
static void SetLineWidth(float width);

Expand Down
Loading

0 comments on commit d32b9a2

Please sign in to comment.