PrimeWorldEditor/Resource/CFont.cpp

183 lines
5.8 KiB
C++

#include "CFont.h"
#include <Core/CDrawUtil.h>
#include <Core/CRenderer.h>
#include <Core/CResCache.h>
#include <Common/AnimUtil.h>
CDynamicVertexBuffer CFont::smGlyphVertices;
CIndexBuffer CFont::smGlyphIndices;
bool CFont::smBuffersInitialized = false;
CFont::CFont() : CResource()
{
}
CFont::~CFont()
{
}
EResType CFont::Type()
{
return eFont;
}
inline float PtsToFloat(s32 pt)
{
// This is a bit of an arbitrary number but it works
// 1 / (1280 / 1.333333f / 2)
return 0.00208333f * pt;
}
CVector2f CFont::RenderString(std::string String, CRenderer *pRenderer, float,
CVector2f, CColor FillColor, CColor StrokeColor, u32 FontSize)
{
// Not using parameter 3 (float - AspectRatio)
// Not using parameter 4 (CVector2f - Position)
// WIP
if (!smBuffersInitialized) InitBuffers();
// Shader setup
CShader *pTextShader = CDrawUtil::GetTextShader();
pTextShader->SetCurrent();
GLuint ModelMtxLoc = pTextShader->GetUniformLocation("ModelMtx");
GLuint ColorLoc = pTextShader->GetUniformLocation("FontColor");
GLuint LayerLoc = pTextShader->GetUniformLocation("RGBALayer");
CVector4f FillColor4f = FillColor.ToVector4f();
CVector4f StrokeColor4f = StrokeColor.ToVector4f();
mpFontTexture->Bind(0);
smGlyphVertices.Bind();
glDisable(GL_DEPTH_TEST);
// Initialize some more stuff before we start the character loop
CVector2f PrintHead(-1.f, 1.f);
CTransform4f PtScale = CTransform4f::ScaleMatrix(PtsToFloat(1));
SGlyph *pPrevGlyph = nullptr;
float Scale;
if (FontSize == CFONT_DEFAULT_SIZE) Scale = 1.f;
else Scale = (float) FontSize / (mDefaultSize != 0 ? mDefaultSize : 18);
for (u32 iChar = 0; iChar < String.length(); iChar++)
{
// Get character, check for newline
char Char = String[iChar];
if (Char == '\n')
{
pPrevGlyph = nullptr;
PrintHead.x = -1;
PrintHead.y -= (PtsToFloat(mLineHeight) + PtsToFloat(mLineMargin) + PtsToFloat(mUnknown)) * Scale;
continue;
}
// Get glyph
auto iGlyph = mGlyphs.find(Char);
if (iGlyph == mGlyphs.end()) continue;
SGlyph *pGlyph = &iGlyph->second;
// Apply left padding and kerning
PrintHead.x += PtsToFloat(pGlyph->LeftPadding) * Scale;
if (pPrevGlyph)
{
if (pPrevGlyph->KerningIndex != -1)
{
for (u32 iKern = pPrevGlyph->KerningIndex; iKern < mKerningTable.size(); iKern++)
{
if (mKerningTable[iKern].CharacterA != pPrevGlyph->Character) break;
if (mKerningTable[iKern].CharacterB == String[iChar])
{
PrintHead.x += PtsToFloat(mKerningTable[iKern].Adjust) * Scale;
break;
}
}
}
}
// Add a newline if this character goes over the right edge of the screen
if (PrintHead.x + ((PtsToFloat(pGlyph->PrintAdvance) + PtsToFloat(pGlyph->RightPadding)) * Scale) > 1)
{
PrintHead.x = -1;
PrintHead.y -= (PtsToFloat(mLineHeight) + PtsToFloat(mLineMargin) + PtsToFloat(mUnknown)) * Scale;
if (Char == ' ') continue;
}
float XTrans = PrintHead.x;
float YTrans = PrintHead.y + ((PtsToFloat(pGlyph->BaseOffset * 2) - PtsToFloat(mVerticalOffset * 2)) * Scale);
CTransform4f GlyphTransform = PtScale;
GlyphTransform.Scale(CVector3f((float) pGlyph->Width / 2, (float) pGlyph->Height, 1.f));
GlyphTransform.Scale(Scale);
GlyphTransform.Translate(CVector3f(XTrans, YTrans, 0.f));
CMatrix4f Glyph4f = GlyphTransform.ToMatrix4f();
// Get glyph layer
u8 GlyphLayer = pGlyph->RGBAChannel;
if (mTextureFormat == 3) GlyphLayer *= 2;
else if (mTextureFormat == 8) GlyphLayer = 3;
// Load shader uniforms, buffer texture
glUniformMatrix4fv(ModelMtxLoc, 1, GL_FALSE, (GLfloat*) &Glyph4f);
smGlyphVertices.BufferAttrib(eTex0, &pGlyph->TexCoords);
// Draw fill
glUniform1i(LayerLoc, GlyphLayer);
glUniform4fv(ColorLoc, 1, &FillColor4f.x);
smGlyphIndices.DrawElements();
// Draw stroke
if ((mTextureFormat == 1) || (mTextureFormat == 3) || (mTextureFormat == 8))
{
u8 StrokeLayer;
if (mTextureFormat == 1) StrokeLayer = 1;
else if (mTextureFormat == 3) StrokeLayer = GlyphLayer + 1;
else if (mTextureFormat == 8) StrokeLayer = GlyphLayer - 2;
glUniform1i(LayerLoc, StrokeLayer);
glUniform4fv(ColorLoc, 1, &StrokeColor4f.x);
smGlyphIndices.DrawElements();
}
// Update print head
PrintHead.x += PtsToFloat(pGlyph->PrintAdvance) * Scale;
PrintHead.x += PtsToFloat(pGlyph->RightPadding) * Scale;
pPrevGlyph = pGlyph;
}
glEnable(GL_DEPTH_TEST);
return PrintHead;
}
void CFont::InitBuffers()
{
smGlyphVertices.SetActiveAttribs(ePosition | eTex0);
smGlyphVertices.SetVertexCount(4);
CVector3f Vertices[4] = {
CVector3f( 0.f, 0.f, 0.f),
CVector3f( 2.f, 0.f, 0.f),
CVector3f( 0.f, -2.f, 0.f),
CVector3f( 2.f, -2.f, 0.f)
};
smGlyphVertices.BufferAttrib(ePosition, Vertices);
CVector2f TexCoords[4] = {
CVector2f(0.f, 0.f),
CVector2f(1.f, 0.f),
CVector2f(0.f, 1.f),
CVector2f(1.f, 1.f)
};
smGlyphVertices.BufferAttrib(eTex0, TexCoords);
smGlyphIndices.Reserve(4);
smGlyphIndices.AddIndex(0);
smGlyphIndices.AddIndex(2);
smGlyphIndices.AddIndex(1);
smGlyphIndices.AddIndex(3);
smGlyphIndices.SetPrimitiveType(GL_TRIANGLE_STRIP);
smBuffersInitialized = true;
}