Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F96991
Text.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
Text.cpp
View Options
#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
Details
Attached
Mime Type
text/x-c++
Expires
Thu, Dec 5, 6:28 PM (23 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
61679
Default Alt Text
Text.cpp (9 KB)
Attached To
Mode
rEE Echo 3
Attached
Detach File
Event Timeline
Log In to Comment