|
@@ -50,7 +50,7 @@ static const int MAX_POINT_SIZE = 96;
|
|
|
class FreeTypeLibrary : public Object
|
|
class FreeTypeLibrary : public Object
|
|
|
{
|
|
{
|
|
|
OBJECT(FreeTypeLibrary);
|
|
OBJECT(FreeTypeLibrary);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
public:
|
|
public:
|
|
|
/// Construct.
|
|
/// Construct.
|
|
|
FreeTypeLibrary(Context* context) :
|
|
FreeTypeLibrary(Context* context) :
|
|
@@ -60,15 +60,15 @@ public:
|
|
|
if (error)
|
|
if (error)
|
|
|
LOGERROR("Could not initialize FreeType library");
|
|
LOGERROR("Could not initialize FreeType library");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
/// Destruct.
|
|
/// Destruct.
|
|
|
virtual ~FreeTypeLibrary()
|
|
virtual ~FreeTypeLibrary()
|
|
|
{
|
|
{
|
|
|
FT_Done_FreeType(library_);
|
|
FT_Done_FreeType(library_);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FT_Library GetLibrary() const { return library_; }
|
|
FT_Library GetLibrary() const { return library_; }
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
private:
|
|
private:
|
|
|
/// FreeType library.
|
|
/// FreeType library.
|
|
|
FT_Library library_;
|
|
FT_Library library_;
|
|
@@ -100,7 +100,7 @@ FontFace::~FontFace()
|
|
|
FT_Done_Face((FT_Face)face_);
|
|
FT_Done_Face((FT_Face)face_);
|
|
|
face_ = 0;
|
|
face_ = 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (font_)
|
|
if (font_)
|
|
|
{
|
|
{
|
|
|
// When a face is unloaded, deduct the used texture data size from the parent font
|
|
// When a face is unloaded, deduct the used texture data size from the parent font
|
|
@@ -109,7 +109,7 @@ FontFace::~FontFace()
|
|
|
totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
|
|
totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
|
|
|
font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
|
|
font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
|
|
for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
|
|
|
delete *i;
|
|
delete *i;
|
|
|
mutableGlyphs_.Clear();
|
|
mutableGlyphs_.Clear();
|
|
@@ -132,7 +132,7 @@ const FontGlyph* FontFace::GetGlyph(unsigned c)
|
|
|
mutableGlyphs_.PushFront(mutableGlyph);
|
|
mutableGlyphs_.PushFront(mutableGlyph);
|
|
|
glyph.iterator_ = mutableGlyphs_.Begin();
|
|
glyph.iterator_ = mutableGlyphs_.Begin();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
glyph.used_ = true;
|
|
glyph.used_ = true;
|
|
|
return &glyph;
|
|
return &glyph;
|
|
|
}
|
|
}
|
|
@@ -144,10 +144,10 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
|
|
|
{
|
|
{
|
|
|
if (!hasKerning_)
|
|
if (!hasKerning_)
|
|
|
return 0;
|
|
return 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (c == '\n' || d == '\n')
|
|
if (c == '\n' || d == '\n')
|
|
|
return 0;
|
|
return 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
unsigned leftIndex = 0;
|
|
unsigned leftIndex = 0;
|
|
|
unsigned rightIndex = 0;
|
|
unsigned rightIndex = 0;
|
|
|
HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
|
|
HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
|
|
@@ -160,7 +160,7 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
|
|
|
rightIndex = rightIt->second_;
|
|
rightIndex = rightIt->second_;
|
|
|
else
|
|
else
|
|
|
return 0;
|
|
return 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
|
|
HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
|
|
|
if (kerningIt != glyphs_[leftIndex].kerning_.End())
|
|
if (kerningIt != glyphs_[leftIndex].kerning_.End())
|
|
|
return kerningIt->second_;
|
|
return kerningIt->second_;
|
|
@@ -181,9 +181,9 @@ bool FontFace::IsDataLost() const
|
|
|
bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
|
|
bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
|
|
|
{
|
|
{
|
|
|
assert(font_ && face_ && textures_.Empty());
|
|
assert(font_ && face_ && textures_.Empty());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
|
|
allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned i = 0; i < glyphs_.Size(); ++i)
|
|
for (unsigned i = 0; i < glyphs_.Size(); ++i)
|
|
|
{
|
|
{
|
|
|
if (glyphs_[i].width_ && glyphs_[i].height_)
|
|
if (glyphs_[i].width_ && glyphs_[i].height_)
|
|
@@ -211,19 +211,19 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
|
|
|
glyphs_[i].page_ = 0;
|
|
glyphs_[i].page_ = 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Create image for rendering all the glyphs, clear to black
|
|
// Create image for rendering all the glyphs, clear to black
|
|
|
SharedPtr<Image> image(new Image(font_->GetContext()));
|
|
SharedPtr<Image> image(new Image(font_->GetContext()));
|
|
|
image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
|
|
image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
|
|
|
unsigned char* imageData = image->GetData();
|
|
unsigned char* imageData = image->GetData();
|
|
|
memset(imageData, 0, image->GetWidth() * image->GetHeight());
|
|
memset(imageData, 0, image->GetWidth() * image->GetHeight());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
|
|
|
|
|
|
// Render glyphs
|
|
// Render glyphs
|
|
|
for (unsigned i = 0; i < glyphs_.Size(); ++i)
|
|
for (unsigned i = 0; i < glyphs_.Size(); ++i)
|
|
|
RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
|
|
RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Load image into a texture, increment memory usage of the parent font
|
|
// Load image into a texture, increment memory usage of the parent font
|
|
|
SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
|
|
SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
|
|
|
if (!texture)
|
|
if (!texture)
|
|
@@ -232,10 +232,10 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
|
|
|
glyphs_[i].page_ = M_MAX_UNSIGNED;
|
|
glyphs_[i].page_ = M_MAX_UNSIGNED;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
textures_.Push(texture);
|
|
textures_.Push(texture);
|
|
|
font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
|
|
font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
|
|
LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -243,9 +243,9 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
|
|
|
void FontFace::RenderGlyph(unsigned index)
|
|
void FontFace::RenderGlyph(unsigned index)
|
|
|
{
|
|
{
|
|
|
assert(font_ && face_);
|
|
assert(font_ && face_);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FontGlyph& glyph = glyphs_[index];
|
|
FontGlyph& glyph = glyphs_[index];
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// If glyph is empty, just set the current page
|
|
// If glyph is empty, just set the current page
|
|
|
if (!glyph.width_ || !glyph.height_)
|
|
if (!glyph.width_ || !glyph.height_)
|
|
|
{
|
|
{
|
|
@@ -254,7 +254,7 @@ void FontFace::RenderGlyph(unsigned index)
|
|
|
glyph.page_ = textures_.Size() - 1;
|
|
glyph.page_ = textures_.Size() - 1;
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
|
|
|
|
|
|
if (!mutableGlyphs_.Size())
|
|
if (!mutableGlyphs_.Size())
|
|
@@ -267,17 +267,17 @@ void FontFace::RenderGlyph(unsigned index)
|
|
|
// This always succeeds, as it is the first allocation of an empty page
|
|
// This always succeeds, as it is the first allocation of an empty page
|
|
|
allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
|
|
allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
glyph.x_ = x;
|
|
glyph.x_ = x;
|
|
|
glyph.y_ = y;
|
|
glyph.y_ = y;
|
|
|
glyph.page_ = textures_.Size() - 1;
|
|
glyph.page_ = textures_.Size() - 1;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
|
|
if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
|
|
|
{
|
|
{
|
|
|
bitmapSize_ = glyph.width_ * glyph.height_;
|
|
bitmapSize_ = glyph.width_ * glyph.height_;
|
|
|
bitmap_ = new unsigned char[bitmapSize_];
|
|
bitmap_ = new unsigned char[bitmapSize_];
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
|
|
RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
|
|
|
textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
|
|
textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
|
|
|
}
|
|
}
|
|
@@ -293,13 +293,13 @@ void FontFace::RenderGlyph(unsigned index)
|
|
|
glyph.page_ = 0;
|
|
glyph.page_ = 0;
|
|
|
glyph.iterator_ = it;
|
|
glyph.iterator_ = it;
|
|
|
mutableGlyph->glyphIndex_ = index;
|
|
mutableGlyph->glyphIndex_ = index;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!bitmap_)
|
|
if (!bitmap_)
|
|
|
{
|
|
{
|
|
|
bitmapSize_ = cellWidth_ * cellHeight_;
|
|
bitmapSize_ = cellWidth_ * cellHeight_;
|
|
|
bitmap_ = new unsigned char[bitmapSize_];
|
|
bitmap_ = new unsigned char[bitmapSize_];
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Clear the cell bitmap before rendering to ensure padding
|
|
// Clear the cell bitmap before rendering to ensure padding
|
|
|
memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
|
|
memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
|
|
|
RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
|
|
RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
|
|
@@ -312,7 +312,7 @@ void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned p
|
|
|
const FontGlyph& glyph = glyphs_[index];
|
|
const FontGlyph& glyph = glyphs_[index];
|
|
|
if (!glyph.width_ || !glyph.height_)
|
|
if (!glyph.width_ || !glyph.height_)
|
|
|
return;
|
|
return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FT_Face face = (FT_Face)face_;
|
|
FT_Face face = (FT_Face)face_;
|
|
|
FT_GlyphSlot slot = face->glyph;
|
|
FT_GlyphSlot slot = face->glyph;
|
|
|
FT_Load_Glyph(face, index, loadMode);
|
|
FT_Load_Glyph(face, index, loadMode);
|
|
@@ -352,22 +352,22 @@ void FontFace::SetupNextTexture(int width, int height)
|
|
|
SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
|
|
SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
|
|
|
memset(emptyBitmap.Get(), 0, width * height);
|
|
memset(emptyBitmap.Get(), 0, width * height);
|
|
|
texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
|
|
texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
textures_.Push(texture);
|
|
textures_.Push(texture);
|
|
|
font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
|
|
font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
|
|
LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
|
|
void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
|
|
|
{
|
|
{
|
|
|
assert(mutableGlyphs_.Empty());
|
|
assert(mutableGlyphs_.Empty());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SetupNextTexture(textureWidth, textureHeight);
|
|
SetupNextTexture(textureWidth, textureHeight);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
cellWidth_ = maxWidth + 1;
|
|
cellWidth_ = maxWidth + 1;
|
|
|
cellHeight_ = maxHeight + 1;
|
|
cellHeight_ = maxHeight + 1;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Allocate as many mutable glyphs as possible
|
|
// Allocate as many mutable glyphs as possible
|
|
|
int x, y;
|
|
int x, y;
|
|
|
while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
|
|
while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
|
|
@@ -377,7 +377,7 @@ void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWi
|
|
|
glyph->y_ = y;
|
|
glyph->y_ = y;
|
|
|
mutableGlyphs_.Push(glyph);
|
|
mutableGlyphs_.Push(glyph);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
|
|
LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -403,15 +403,15 @@ void Font::RegisterObject(Context* context)
|
|
|
bool Font::Load(Deserializer& source)
|
|
bool Font::Load(Deserializer& source)
|
|
|
{
|
|
{
|
|
|
PROFILE(LoadFont);
|
|
PROFILE(LoadFont);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// In headless mode, do not actually load, just return success
|
|
// In headless mode, do not actually load, just return success
|
|
|
Graphics* graphics = GetSubsystem<Graphics>();
|
|
Graphics* graphics = GetSubsystem<Graphics>();
|
|
|
if (!graphics)
|
|
if (!graphics)
|
|
|
return true;
|
|
return true;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
fontType_ = FONT_NONE;
|
|
fontType_ = FONT_NONE;
|
|
|
faces_.Clear();
|
|
faces_.Clear();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
fontDataSize_ = source.GetSize();
|
|
fontDataSize_ = source.GetSize();
|
|
|
if (fontDataSize_)
|
|
if (fontDataSize_)
|
|
|
{
|
|
{
|
|
@@ -440,9 +440,9 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
FontFace* fontFace = GetFace(pointSize);
|
|
FontFace* fontFace = GetFace(pointSize);
|
|
|
if (!fontFace)
|
|
if (!fontFace)
|
|
|
return false;
|
|
return false;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
PROFILE(FontSaveXML);
|
|
PROFILE(FontSaveXML);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SharedPtr<FontFace> packedFontFace;
|
|
SharedPtr<FontFace> packedFontFace;
|
|
|
if (usedGlyphs)
|
|
if (usedGlyphs)
|
|
|
{
|
|
{
|
|
@@ -453,7 +453,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
else
|
|
else
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SharedPtr<XMLFile> xml(new XMLFile(context_));
|
|
SharedPtr<XMLFile> xml(new XMLFile(context_));
|
|
|
XMLElement rootElem = xml->CreateRoot("font");
|
|
XMLElement rootElem = xml->CreateRoot("font");
|
|
|
|
|
|
|
@@ -462,7 +462,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
String fileName = GetFileName(GetName());
|
|
String fileName = GetFileName(GetName());
|
|
|
childElem.SetAttribute("face", fileName);
|
|
childElem.SetAttribute("face", fileName);
|
|
|
childElem.SetAttribute("size", String(pointSize));
|
|
childElem.SetAttribute("size", String(pointSize));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Common
|
|
// Common
|
|
|
childElem = rootElem.CreateChild("common");
|
|
childElem = rootElem.CreateChild("common");
|
|
|
childElem.SetInt("lineHeight", fontFace->rowHeight_);
|
|
childElem.SetInt("lineHeight", fontFace->rowHeight_);
|
|
@@ -487,11 +487,11 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
pageElem.SetInt("id", i);
|
|
pageElem.SetInt("id", i);
|
|
|
String texFileName = fileName + "_" + String(i) + ".png";
|
|
String texFileName = fileName + "_" + String(i) + ".png";
|
|
|
pageElem.SetAttribute("file", texFileName);
|
|
pageElem.SetAttribute("file", texFileName);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Save the font face texture to image file
|
|
// Save the font face texture to image file
|
|
|
SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
|
|
SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Chars and kernings
|
|
// Chars and kernings
|
|
|
XMLElement charsElem = rootElem.CreateChild("chars");
|
|
XMLElement charsElem = rootElem.CreateChild("chars");
|
|
|
unsigned numGlyphs = fontFace->glyphs_.Size();
|
|
unsigned numGlyphs = fontFace->glyphs_.Size();
|
|
@@ -514,7 +514,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
charElem.SetInt("yoffset", glyph.offsetY_);
|
|
charElem.SetInt("yoffset", glyph.offsetY_);
|
|
|
charElem.SetInt("xadvance", glyph.advanceX_);
|
|
charElem.SetInt("xadvance", glyph.advanceX_);
|
|
|
charElem.SetInt("page", glyph.page_);
|
|
charElem.SetInt("page", glyph.page_);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Kerning
|
|
// Kerning
|
|
|
if (hasKerning)
|
|
if (hasKerning)
|
|
|
{
|
|
{
|
|
@@ -523,7 +523,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
// To conserve space, only write when amount is non zero
|
|
// To conserve space, only write when amount is non zero
|
|
|
if (j->second_ == 0)
|
|
if (j->second_ == 0)
|
|
|
continue;
|
|
continue;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement kerningElem = kerningsElem.CreateChild("kerning");
|
|
XMLElement kerningElem = kerningsElem.CreateChild("kerning");
|
|
|
kerningElem.SetInt("first", i->first_);
|
|
kerningElem.SetInt("first", i->first_);
|
|
|
kerningElem.SetInt("second", j->first_);
|
|
kerningElem.SetInt("second", j->first_);
|
|
@@ -531,7 +531,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return xml->Save(dest);
|
|
return xml->Save(dest);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -541,13 +541,13 @@ FontFace* Font::GetFace(int pointSize)
|
|
|
Graphics* graphics = GetSubsystem<Graphics>();
|
|
Graphics* graphics = GetSubsystem<Graphics>();
|
|
|
if (!graphics)
|
|
if (!graphics)
|
|
|
return 0;
|
|
return 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
|
|
// For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
|
|
|
if (fontType_ == FONT_BITMAP)
|
|
if (fontType_ == FONT_BITMAP)
|
|
|
pointSize = 0;
|
|
pointSize = 0;
|
|
|
else
|
|
else
|
|
|
pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
|
|
pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
|
|
HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
|
|
|
if (i != faces_.End())
|
|
if (i != faces_.End())
|
|
|
{
|
|
{
|
|
@@ -559,9 +559,9 @@ FontFace* Font::GetFace(int pointSize)
|
|
|
faces_.Erase(i);
|
|
faces_.Erase(i);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
PROFILE(GetFontFace);
|
|
PROFILE(GetFontFace);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
switch (fontType_)
|
|
switch (fontType_)
|
|
|
{
|
|
{
|
|
|
case FONT_FREETYPE:
|
|
case FONT_FREETYPE:
|
|
@@ -569,7 +569,7 @@ FontFace* Font::GetFace(int pointSize)
|
|
|
|
|
|
|
|
case FONT_BITMAP:
|
|
case FONT_BITMAP:
|
|
|
return GetFaceBitmap(pointSize);
|
|
return GetFaceBitmap(pointSize);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
default:
|
|
default:
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
@@ -610,26 +610,26 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
|
|
context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
|
|
|
// Ensure the FreeType library is kept alive as long as TTF font resources exist
|
|
// Ensure the FreeType library is kept alive as long as TTF font resources exist
|
|
|
freeType_ = freeType;
|
|
freeType_ = freeType;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
UI* ui = GetSubsystem<UI>();
|
|
UI* ui = GetSubsystem<UI>();
|
|
|
int maxTextureSize = ui->GetMaxFontTextureSize();
|
|
int maxTextureSize = ui->GetMaxFontTextureSize();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FT_Face face;
|
|
FT_Face face;
|
|
|
FT_Error error;
|
|
FT_Error error;
|
|
|
FT_Library library = freeType->GetLibrary();
|
|
FT_Library library = freeType->GetLibrary();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (pointSize <= 0)
|
|
if (pointSize <= 0)
|
|
|
{
|
|
{
|
|
|
LOGERROR("Zero or negative point size");
|
|
LOGERROR("Zero or negative point size");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!fontDataSize_)
|
|
if (!fontDataSize_)
|
|
|
{
|
|
{
|
|
|
LOGERROR("Could not create font face from zero size data");
|
|
LOGERROR("Could not create font face from zero size data");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
|
|
error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
|
|
|
if (error)
|
|
if (error)
|
|
|
{
|
|
{
|
|
@@ -643,13 +643,13 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
LOGERROR("Could not set font point size " + String(pointSize));
|
|
LOGERROR("Could not set font point size " + String(pointSize));
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SharedPtr<FontFace> newFace(new FontFace(this));
|
|
SharedPtr<FontFace> newFace(new FontFace(this));
|
|
|
newFace->face_ = face;
|
|
newFace->face_ = face;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FT_GlyphSlot slot = face->glyph;
|
|
FT_GlyphSlot slot = face->glyph;
|
|
|
unsigned numGlyphs = 0;
|
|
unsigned numGlyphs = 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build glyph mapping
|
|
// Build glyph mapping
|
|
|
FT_UInt glyphIndex;
|
|
FT_UInt glyphIndex;
|
|
|
FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
|
|
FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
|
|
@@ -659,16 +659,16 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
newFace->glyphMapping_[charCode] = glyphIndex;
|
|
newFace->glyphMapping_[charCode] = glyphIndex;
|
|
|
charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
|
|
charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LOGDEBUGF("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs);
|
|
LOGDEBUGF("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Load each of the glyphs to see the sizes & store other information
|
|
// Load each of the glyphs to see the sizes & store other information
|
|
|
int maxWidth = 0;
|
|
int maxWidth = 0;
|
|
|
int maxHeight = 0;
|
|
int maxHeight = 0;
|
|
|
int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
|
|
|
int ascender = face->size->metrics.ascender >> 6;
|
|
int ascender = face->size->metrics.ascender >> 6;
|
|
|
int descender = face->size->metrics.descender >> 6;
|
|
int descender = face->size->metrics.descender >> 6;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Check if the font's OS/2 info gives different (larger) values for ascender & descender
|
|
// Check if the font's OS/2 info gives different (larger) values for ascender & descender
|
|
|
TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
|
TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
|
|
if (os2Info)
|
|
if (os2Info)
|
|
@@ -678,17 +678,17 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
|
|
descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
|
|
|
descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
|
|
descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
|
|
// Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
|
|
|
newFace->pointSize_ = pointSize;
|
|
newFace->pointSize_ = pointSize;
|
|
|
newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
|
|
newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
newFace->glyphs_.Reserve(numGlyphs);
|
|
newFace->glyphs_.Reserve(numGlyphs);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned i = 0; i < numGlyphs; ++i)
|
|
for (unsigned i = 0; i < numGlyphs; ++i)
|
|
|
{
|
|
{
|
|
|
FontGlyph newGlyph;
|
|
FontGlyph newGlyph;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
error = FT_Load_Glyph(face, i, loadMode);
|
|
error = FT_Load_Glyph(face, i, loadMode);
|
|
|
if (!error)
|
|
if (!error)
|
|
|
{
|
|
{
|
|
@@ -698,7 +698,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
|
|
newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
|
|
|
newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
|
|
newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
|
|
|
newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
|
|
newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
maxWidth = Max(maxWidth, newGlyph.width_);
|
|
maxWidth = Max(maxWidth, newGlyph.width_);
|
|
|
maxHeight = Max(maxHeight, newGlyph.height_);
|
|
maxHeight = Max(maxHeight, newGlyph.height_);
|
|
|
}
|
|
}
|
|
@@ -710,10 +710,10 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
newGlyph.offsetY_ = 0;
|
|
newGlyph.offsetY_ = 0;
|
|
|
newGlyph.advanceX_ = 0;
|
|
newGlyph.advanceX_ = 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
newFace->glyphs_.Push(newGlyph);
|
|
newFace->glyphs_.Push(newGlyph);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Store kerning if face has kerning information
|
|
// Store kerning if face has kerning information
|
|
|
if (FT_HAS_KERNING(face))
|
|
if (FT_HAS_KERNING(face))
|
|
|
{
|
|
{
|
|
@@ -756,9 +756,9 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
if (version == 0 && coverage == 1)
|
|
if (version == 0 && coverage == 1)
|
|
|
{
|
|
{
|
|
|
unsigned numKerningPairs = deserializer.ReadUShort();
|
|
unsigned numKerningPairs = deserializer.ReadUShort();
|
|
|
- // Skip searchRange, entrySelector & rangeShift
|
|
|
|
|
|
|
+ // Skip searchRange, entrySelector and rangeShift
|
|
|
deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
|
|
deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned j = 0; j < numKerningPairs; ++j)
|
|
for (unsigned j = 0; j < numKerningPairs; ++j)
|
|
|
{
|
|
{
|
|
|
unsigned leftIndex = deserializer.ReadUShort();
|
|
unsigned leftIndex = deserializer.ReadUShort();
|
|
@@ -780,7 +780,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
else
|
|
else
|
|
|
LOGWARNING("Can not read kerning information: not version 0");
|
|
LOGWARNING("Can not read kerning information: not version 0");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
|
|
// Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
|
|
|
// glyphs are only created as necessary
|
|
// glyphs are only created as necessary
|
|
|
if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
|
|
if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
|
|
@@ -795,7 +795,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
|
|
|
else
|
|
else
|
|
|
newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
|
|
newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
faces_[pointSize] = newFace;
|
|
faces_[pointSize] = newFace;
|
|
|
return newFace;
|
|
return newFace;
|
|
|
}
|
|
}
|
|
@@ -809,7 +809,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
LOGERROR("Could not load XML file");
|
|
LOGERROR("Could not load XML file");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement root = xmlReader->GetRoot("font");
|
|
XMLElement root = xmlReader->GetRoot("font");
|
|
|
if (root.IsNull())
|
|
if (root.IsNull())
|
|
|
{
|
|
{
|
|
@@ -823,13 +823,13 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
LOGERROR("Could not find Pages element");
|
|
LOGERROR("Could not find Pages element");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SharedPtr<FontFace> newFace(new FontFace(this));
|
|
SharedPtr<FontFace> newFace(new FontFace(this));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement infoElem = root.GetChild("info");
|
|
XMLElement infoElem = root.GetChild("info");
|
|
|
if (!infoElem.IsNull())
|
|
if (!infoElem.IsNull())
|
|
|
newFace->pointSize_ = infoElem.GetInt("size");
|
|
newFace->pointSize_ = infoElem.GetInt("size");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement commonElem = root.GetChild("common");
|
|
XMLElement commonElem = root.GetChild("common");
|
|
|
newFace->rowHeight_ = commonElem.GetInt("lineHeight");
|
|
newFace->rowHeight_ = commonElem.GetInt("lineHeight");
|
|
|
unsigned pages = commonElem.GetInt("pages");
|
|
unsigned pages = commonElem.GetInt("pages");
|
|
@@ -850,7 +850,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
|
|
|
|
|
// Assume the font image is in the same directory as the font description file
|
|
// Assume the font image is in the same directory as the font description file
|
|
|
String textureFile = fontPath + pageElem.GetAttribute("file");
|
|
String textureFile = fontPath + pageElem.GetAttribute("file");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Load texture manually to allow controlling the alpha channel mode
|
|
// Load texture manually to allow controlling the alpha channel mode
|
|
|
SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
|
|
SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
|
|
|
SharedPtr<Image> fontImage(new Image(context_));
|
|
SharedPtr<Image> fontImage(new Image(context_));
|
|
@@ -864,15 +864,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
return 0;
|
|
return 0;
|
|
|
newFace->textures_.Push(texture);
|
|
newFace->textures_.Push(texture);
|
|
|
totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
|
|
totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
pageElem = pageElem.GetNext("page");
|
|
pageElem = pageElem.GetNext("page");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement charsElem = root.GetChild("chars");
|
|
XMLElement charsElem = root.GetChild("chars");
|
|
|
int count = charsElem.GetInt("count");
|
|
int count = charsElem.GetInt("count");
|
|
|
newFace->glyphs_.Reserve(count);
|
|
newFace->glyphs_.Reserve(count);
|
|
|
unsigned index = 0;
|
|
unsigned index = 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement charElem = charsElem.GetChild("char");
|
|
XMLElement charElem = charsElem.GetChild("char");
|
|
|
while (!charElem.IsNull())
|
|
while (!charElem.IsNull())
|
|
|
{
|
|
{
|
|
@@ -888,10 +888,10 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
glyph.page_ = charElem.GetInt("page");
|
|
glyph.page_ = charElem.GetInt("page");
|
|
|
newFace->glyphs_.Push(glyph);
|
|
newFace->glyphs_.Push(glyph);
|
|
|
newFace->glyphMapping_[id] = index++;
|
|
newFace->glyphMapping_[id] = index++;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
charElem = charElem.GetNext("char");
|
|
charElem = charElem.GetNext("char");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
XMLElement kerningsElem = root.GetChild("kernings");
|
|
XMLElement kerningsElem = root.GetChild("kernings");
|
|
|
if (kerningsElem.IsNull())
|
|
if (kerningsElem.IsNull())
|
|
|
newFace->hasKerning_ = false;
|
|
newFace->hasKerning_ = false;
|
|
@@ -906,15 +906,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
|
|
|
{
|
|
{
|
|
|
int second = kerningElem.GetInt("second");
|
|
int second = kerningElem.GetInt("second");
|
|
|
int amount = kerningElem.GetInt("amount");
|
|
int amount = kerningElem.GetInt("amount");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FontGlyph& glyph = newFace->glyphs_[i->second_];
|
|
FontGlyph& glyph = newFace->glyphs_[i->second_];
|
|
|
glyph.kerning_[second] = amount;
|
|
glyph.kerning_[second] = amount;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
kerningElem = kerningElem.GetNext("kerning");
|
|
kerningElem = kerningElem.GetNext("kerning");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
|
|
LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
|
|
|
|
|
|
|
|
SetMemoryUse(GetMemoryUse() + totalTextureSize);
|
|
SetMemoryUse(GetMemoryUse() + totalTextureSize);
|
|
@@ -938,22 +938,22 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
|
|
|
{
|
|
{
|
|
|
// Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
|
|
// Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
|
|
|
SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
|
|
SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
|
|
int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Clone properties
|
|
// Clone properties
|
|
|
packedFontFace->pointSize_ = fontFace->pointSize_;
|
|
packedFontFace->pointSize_ = fontFace->pointSize_;
|
|
|
packedFontFace->rowHeight_ = fontFace->rowHeight_;
|
|
packedFontFace->rowHeight_ = fontFace->rowHeight_;
|
|
|
packedFontFace->hasKerning_ = fontFace->hasKerning_;
|
|
packedFontFace->hasKerning_ = fontFace->hasKerning_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Assume that format is the same for all textures and that bitmap font type may have more than one component
|
|
// Assume that format is the same for all textures and that bitmap font type may have more than one component
|
|
|
unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
|
|
unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Save the existing textures as image resources
|
|
// Save the existing textures as image resources
|
|
|
Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
|
|
Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
|
|
|
for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
|
|
for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
|
|
|
images[i] = SaveFaceTexture(fontFace->textures_[i]);
|
|
images[i] = SaveFaceTexture(fontFace->textures_[i]);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Reallocate used glyphs to new texture(s)
|
|
// Reallocate used glyphs to new texture(s)
|
|
|
unsigned page = 0;
|
|
unsigned page = 0;
|
|
|
unsigned index = 0;
|
|
unsigned index = 0;
|
|
@@ -982,18 +982,18 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
|
|
|
else
|
|
else
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
packedFontFace->glyphs_.Push(glyph);
|
|
packedFontFace->glyphs_.Push(glyph);
|
|
|
packedFontFace->glyphMapping_[i->first_] = index++;
|
|
packedFontFace->glyphMapping_[i->first_] = index++;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int texWidth = allocator.GetWidth();
|
|
int texWidth = allocator.GetWidth();
|
|
|
int texHeight = allocator.GetHeight();
|
|
int texHeight = allocator.GetHeight();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Create the image for rendering the fonts
|
|
// Create the image for rendering the fonts
|
|
|
SharedPtr<Image> image(new Image(context_));
|
|
SharedPtr<Image> image(new Image(context_));
|
|
|
image->SetSize(texWidth, texHeight, components);
|
|
image->SetSize(texWidth, texHeight, components);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// First clear the whole image
|
|
// First clear the whole image
|
|
|
unsigned char* imageData = image->GetData();
|
|
unsigned char* imageData = image->GetData();
|
|
|
for (int y = 0; y < texHeight; ++y)
|
|
for (int y = 0; y < texHeight; ++y)
|
|
@@ -1001,22 +1001,22 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
|
|
|
unsigned char* dest = imageData + components * texWidth * y;
|
|
unsigned char* dest = imageData + components * texWidth * y;
|
|
|
memset(dest, 0, components * texWidth);
|
|
memset(dest, 0, components * texWidth);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Then render the glyphs into new image
|
|
// Then render the glyphs into new image
|
|
|
for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
|
|
for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
|
|
|
{
|
|
{
|
|
|
FontGlyph glyph = fontFace->glyphs_[j->second_];
|
|
FontGlyph glyph = fontFace->glyphs_[j->second_];
|
|
|
if (!glyph.used_)
|
|
if (!glyph.used_)
|
|
|
continue;
|
|
continue;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!glyph.width_ || !glyph.height_)
|
|
if (!glyph.width_ || !glyph.height_)
|
|
|
{
|
|
{
|
|
|
++startIndex;
|
|
++startIndex;
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
|
|
FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
Image* image = images[glyph.page_];
|
|
Image* image = images[glyph.page_];
|
|
|
unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
|
|
unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
|
|
|
unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
|
|
unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
|
|
@@ -1027,7 +1027,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
|
|
|
destination += components * texWidth;
|
|
destination += components * texWidth;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Finally load image into the texture
|
|
// Finally load image into the texture
|
|
|
SharedPtr<Texture2D> texture = LoadFaceTexture(image);
|
|
SharedPtr<Texture2D> texture = LoadFaceTexture(image);
|
|
|
if (!texture)
|
|
if (!texture)
|
|
@@ -1038,7 +1038,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
|
|
|
startIter = i;
|
|
startIter = i;
|
|
|
assert(index == startIndex);
|
|
assert(index == startIndex);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return packedFontFace;
|
|
return packedFontFace;
|
|
|
}
|
|
}
|
|
|
|
|
|