Page MenuHomePhorge

Text.cpp
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

Text.cpp

#include <echo/Graphics/Text.h>
#include <echo/Graphics/Font.h>
#include <echo/Graphics/Mesh.h>
#include <echo/Maths/Vector2.h>
#include <echo/Graphics/SubMesh.h>
#include <echo/Resource/MeshManager.h>
#include <echo/UTF8String.h>
namespace Echo
{
Text::Text(const UTF8String& content, shared_ptr<Font> font) : mFont(font), mString(content),
mSpaceWidth(0.5f),
mTextScale(1.f),
mMaxWidth(100.f), //Just an arbitrary size.'
mFixedLineSpacing(1.f),
mUseFixedLineSpacing(false),
mUseMaxWidth(false),
mMeshOutOfDate(true)
{
SetMesh(make_shared<Mesh>());
GetMesh()->CreateSubMesh();
}
Text::Text() : mSpaceWidth(0.5f), mMeshOutOfDate(true)
{
SetMesh(make_shared<Mesh>());
GetMesh()->CreateSubMesh();
}
Text::Text(MeshManager& meshManager, const std::string resourceName) : mSpaceWidth(0.5f), mMeshOutOfDate(true)
{
SetMesh(meshManager.CreateMesh(resourceName));
GetMesh()->CreateSubMesh();
}
Text::~Text()
{
}
void Text::SetFont(shared_ptr<Font> font)
{
mFont = font;
mMeshOutOfDate=true;
NeedUpdate();
}
void Text::Set(const UTF8String& content)
{
if(mString!=content)
{
mString = content;
mMeshOutOfDate=true;
NeedUpdate(true);
}
}
void Text::Append(const UTF8String& content)
{
mString += content;
mMeshOutOfDate=true;
NeedUpdate(true);
}
void Text::BuildMesh(const UTF8String& utf8String)
{
if(!mFont || !GetMesh())
{
return;
}
shared_ptr<SubMesh> subMesh = GetMesh()->GetSubMesh(0);
if(!subMesh)
{
return;
}
subMesh->Clear();
UTF8String::iterator it = utf8String.begin();
UTF8String::iterator itEnd = utf8String.end();
Glyph* previousGlyph = 0;
Vector2 currentPosition(0,0);
f32 currentWidth=0; //Current height is the cursor y position.
f32 currentWordWidth=0;
f32 currentWordHeight=0;
f32 currentWordYBearing=0;
f32 currentLineHeight=0;
f32 currentLineMaxYBearing=0;
f32 lineHeight;
f32 spaceWidth = mSpaceWidth*mFont->GetMaxWidth();
if(mUseFixedLineSpacing)
{
lineHeight = mFixedLineSpacing * mFont->GetMaxHeight();
currentLineHeight = mFixedLineSpacing * mFont->GetMaxHeight();
}else
{
lineHeight = mFont->GetMaxHeight();
}
// Determine the length of the current word.
// If the current width plus word width is less than the specified object width
// Add the word.
// Else
// Add new line
// Add the word.
UTF8String currentWord;
bool lastCharacter=false;
while(!lastCharacter)
{
UTF32Code code;
if(it==itEnd)
{
lastCharacter=true;
code=0;
}else
{
code = *it;
it++;
}
Glyph* glyph= mFont->GetGlyph(code);
if(!glyph || lastCharacter)
{
//When dealing with the last character in a word we want to adjust the width so that it
//doesn't include advance space of the last character.
if(previousGlyph)
{
currentWordWidth-=previousGlyph->mAdvanceX;
currentWordWidth+=previousGlyph->mWidth;
}
//We don't apply the scale while we're calculating the word width because we may need to adjust it if it exceeds max width.
f32 wordScale = mTextScale;
f32 scaledWordWidth=currentWordWidth*wordScale;
f32 scaledWordHeight=currentWordHeight*wordScale;
f32 scaledWordYBearing=currentWordYBearing*wordScale;
//End of word as far as we are concerned.
if(mUseMaxWidth && (currentWidth+scaledWordWidth)>mMaxWidth)
{
//If the word is larger than the width we need to scale it so it will fit.
if(scaledWordWidth>mMaxWidth)
{
//Update the scaled values.
wordScale = mMaxWidth/currentWordWidth; //Find the new scale, use the unscaled word with.
scaledWordWidth=currentWordWidth*wordScale;
scaledWordHeight=currentWordHeight*wordScale;
scaledWordYBearing=currentWordYBearing*wordScale;
if(mUseFixedLineSpacing)
{
currentPosition.y-=lineHeight;
}else
{
//Calculate the next line position. This takes into account the max y bearing of both
//lines (the single word line and the one preceeding it).
currentPosition.y-=(currentLineHeight - currentLineMaxYBearing) + scaledWordYBearing;
currentLineHeight=lineHeight*wordScale;
}
currentLineMaxYBearing=0;
currentPosition.x=0;
currentWidth=0;
}else
{
//Create a new line if the current width is not 0.
if(currentWidth>0)
{
currentPosition.x=0;
currentWidth=0;
if(mUseFixedLineSpacing)
{
currentPosition.y-=lineHeight*wordScale;
}else
{
//This is a best guess as to what the next line position will be based on the next word.
//Unless we scan the whole line we can't know what the next line max Y bearing is.
currentPosition.y-=(currentLineHeight - currentLineMaxYBearing) + scaledWordYBearing;
currentLineHeight=0;
}
}
}
}
if(scaledWordHeight>currentLineHeight)
{
currentLineHeight=scaledWordHeight;
}
if(scaledWordYBearing>currentLineMaxYBearing)
{
currentLineMaxYBearing=scaledWordYBearing;
}
if(currentWord.Length()>0)
{
AddWordToMesh(currentPosition,currentWord,wordScale);
}
//Move the cursor over
currentPosition.x+=scaledWordWidth;
currentPosition.x+=spaceWidth*wordScale;
currentWidth+=scaledWordWidth + spaceWidth*wordScale;
currentWordWidth=0;
currentWordYBearing=0;
currentWordHeight=0;
currentWord.clear();
previousGlyph = 0;
continue;
}else
{
currentWord+=code;
currentWordWidth+=glyph->mAdvanceX;
if(previousGlyph && code)
{
s32 kerning = previousGlyph->GetKerning(code);
currentWordWidth+=kerning;
}
if(glyph->mHeight>currentWordHeight)
{
currentWordHeight=glyph->mHeight;
}
if(glyph->mYBearing>currentWordYBearing)
{
currentWordYBearing=glyph->mYBearing;
}
previousGlyph = glyph;
}
}
//Now centre the mesh
shared_ptr<Mesh> mesh = GetMesh();
mesh->CentreMeshToOrigin();
mDimensions = mesh->GetMax() - mesh->GetMin();
mesh->SetMaterial(mFont->GetMaterial()->Clone());
SetColour(mColour);
mMeshOutOfDate = false;
}
void Text::AddWordToMesh(Vector2 position, const UTF8String& word, f32 scale)
{
f32 spaceWidth = mSpaceWidth*mFont->GetMaxWidth();
UTF8String::iterator it = word.begin();
UTF8String::iterator itEnd = word.end();
Glyph* previousGlyph=0;
while(it!=itEnd)
{
UTF32Code code = *it;
Glyph* glyph= mFont->GetGlyph(code);
if(!glyph)
{
position.x+=spaceWidth * scale;
it++;
previousGlyph = 0;
continue;
}
if(previousGlyph && code)
{
f32 kerning = static_cast<f32>(previousGlyph->GetKerning(code));
position.x+=kerning * scale;
}
AddCharacterToMesh(position,*glyph,scale);
position.x+=static_cast<f32>(glyph->mAdvanceX) * scale;
previousGlyph = glyph;
it++;
}
}
void Text::AddCharacterToMesh(const Vector2& position, const Glyph& glyph, f32 scale)
{
shared_ptr<SubMesh> subMesh = GetMesh()->GetSubMesh(0);
if(!subMesh)
{
return;
}
//Vertices
f32 left = position.x + static_cast<f32>(glyph.mXBearing) * scale;
f32 right = left + static_cast<f32>(glyph.mWidth) * scale;
f32 top = position.y + static_cast<f32>(glyph.mYBearing) * scale;
f32 bottom = top - static_cast<f32>(glyph.mHeight) * scale;
shared_ptr< std::vector<Vector3> > vertices = subMesh->GetVertices();
size_t indexBase = vertices ? vertices->size() : 0;
subMesh->AddVertex(Vector3(left,top,0));
subMesh->AddVertex(Vector3(right,top,0));
subMesh->AddVertex(Vector3(left,bottom,0));
subMesh->AddVertex(Vector3(right,bottom,0));
//Texture coordinates
TextureUV uv(glyph.mTextureCoordinates.first);
TextureUV st(glyph.mTextureCoordinates.second);
subMesh->AddTextureUV(uv);
subMesh->AddTextureUV(TextureUV(st.u, uv.v));
subMesh->AddTextureUV(TextureUV(uv.u, st.v));
subMesh->AddTextureUV(st);
//Triangles
subMesh->AddFace(IndexedTriangle(indexBase,indexBase+1,indexBase+2));
subMesh->AddFace(IndexedTriangle(indexBase+1,indexBase+3,indexBase+2));
}
AxisAlignedBox Text::GetAxisAlignedBox(bool applyLocalTransform)
{
if(mMeshOutOfDate)
{
UpdateMesh();
}
return SceneEntity::GetAxisAlignedBox(applyLocalTransform);
}
const Vector3& Text::GetTextDimensions() const {return mDimensions;}
void Text::UpdateMesh()
{
BuildMesh(mString);
}
void Text::Render(const Matrix4& transform, RenderTarget& renderTarget)
{
if(mMeshOutOfDate)
{
UpdateMesh();
}
SceneEntity::Render(transform,renderTarget);
}
void Text::SetColour(const Colour& colour)
{
mColour = colour;
if(GetMesh())
{
GetMesh()->SetDiffuseColour(mColour);
}
}
void Text::SetMaxWidth(f32 maxWidth)
{
if(maxWidth!=mMaxWidth && mUseMaxWidth)
{
mMeshOutOfDate=true;
NeedUpdate();
}
mMaxWidth=maxWidth;
}
void Text::SetUseMaxWidth(bool useMaxWidth)
{
if(useMaxWidth!=mUseMaxWidth)
{
mMeshOutOfDate=true;
NeedUpdate();
}
mUseMaxWidth=useMaxWidth;
}
void Text::SetTextScale(f32 textScale)
{
if(mTextScale!=textScale)
{
mTextScale = textScale;
mMeshOutOfDate=true;
NeedUpdate(true);
}
}
void Text::SetFixedLineSpacing(f32 fixedLineSpacing)
{
if(fixedLineSpacing!=mFixedLineSpacing && mUseMaxWidth)
{
mMeshOutOfDate=true;
NeedUpdate();
}
mFixedLineSpacing = fixedLineSpacing;
}
void Text::SetUseFixedLineSpacing(bool useFixedLineSpacing)
{
if(useFixedLineSpacing!=mUseFixedLineSpacing && mUseMaxWidth)
{
mMeshOutOfDate=true;
NeedUpdate(true);
}
mUseFixedLineSpacing=useFixedLineSpacing;
}
}

File Metadata

Mime Type
text/x-c++
Expires
Thu, Dec 5, 6:28 PM (12 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
61679
Default Alt Text
Text.cpp (9 KB)

Event Timeline