194 lines
5.0 KiB
C++
194 lines
5.0 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "core/raster_font.h"
|
|
#include "core/render_resource_factory.h"
|
|
#include "metafile/nml.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS;
|
|
using namespace GS::Render;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
float RasterFont::GetHeight(bool normalized) const
|
|
{
|
|
if (normalized)
|
|
return height;
|
|
return GetPage(0) ? height * GetPage(0)->GetWidth() : -1;
|
|
}
|
|
float RasterFont::GetBaseline(bool normalized) const
|
|
{
|
|
if (normalized)
|
|
return baseline;
|
|
return GetPage(0) ? baseline * GetPage(0)->GetWidth() : -1;
|
|
}
|
|
Vector2 RasterFont::ComputeLineRect(const char *s, bool normalized) const
|
|
{
|
|
Vector2 r(0, height);
|
|
for ( ; s[0] && s[0] != '\n'; ++s)
|
|
if (const Glyph *c = GetGlyphInfos(s[0]))
|
|
r.x += c->step;
|
|
|
|
if (!normalized)
|
|
{
|
|
if (GetPage(0))
|
|
{
|
|
r.x *= GetPage(0)->GetWidth();
|
|
r.y *= GetPage(0)->GetHeight();
|
|
}
|
|
else
|
|
r.Set(-1, -1);
|
|
}
|
|
return r;
|
|
}
|
|
Vector2 RasterFont::ComputeStringRect(const char *s, bool normalized) const
|
|
{
|
|
Vector2 r(0, 0);
|
|
|
|
forever
|
|
{
|
|
float w = 0; // Line width.
|
|
for ( ; s[0] && s[0] != '\n'; ++s)
|
|
if (const Glyph *c = GetGlyphInfos(s[0]))
|
|
w += c->step;
|
|
|
|
if (w > r.x) // Largest width.
|
|
r.x = w;
|
|
r.y += height; // Line height.
|
|
|
|
if (!s[0])
|
|
break;
|
|
++s; // Jump over the line feed.
|
|
}
|
|
|
|
if (!normalized)
|
|
{
|
|
if (GetPage(0))
|
|
{
|
|
r.x *= GetPage(0)->GetWidth();
|
|
r.y *= GetPage(0)->GetHeight();
|
|
}
|
|
else
|
|
r.Set(-1, -1);
|
|
}
|
|
return r;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
Texture *RasterFont::GetPage(uint page) const
|
|
{ return (page < pages.GetCount()) ? pages.ObjectAt(page) : NULL; }
|
|
const RasterFont::Glyph *RasterFont::GetGlyphInfos(uchar index) const
|
|
{ return glyph[index].available ? &glyph[index] : NULL; }
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool RasterFont::Load(ResourceFactory &rf, const char *nml, const char *base)
|
|
{
|
|
Unload();
|
|
|
|
//-----------------------------------------------------------
|
|
#define RFL_ERROR(l) { (l); Unload(); return false; }
|
|
//-----------------------------------------------------------
|
|
|
|
using namespace GS::NML;
|
|
|
|
File file;
|
|
if (!Parser::Load(nml, file))
|
|
RFL_ERROR(__LOG_E__ << "Failed to load raster font description file '" << nml << "'.\n")
|
|
|
|
// Load font settings.
|
|
Tag *root = file.GetTag("Font:Common;");
|
|
if (!root)
|
|
RFL_ERROR(__LOG_E__ << "Missing base tag in font description ('" << nml << "').\n")
|
|
|
|
uint page_count = 1;
|
|
|
|
NMLTagForeach(tag, *root)
|
|
{
|
|
if (tag->name == "Height")
|
|
height = tag->GetReal();
|
|
else if (tag->name == "BaseLine")
|
|
baseline = tag->GetReal();
|
|
else if (tag->name == "PageCount")
|
|
page_count = tag->GetInteger();
|
|
else __LOG_W__ << "Unexpected tag in font description header ('" << tag->name << "').\n";
|
|
}
|
|
|
|
// Parse glyphs...
|
|
root = file.GetTag("Font;");
|
|
|
|
NMLTagForeach(tag, *root)
|
|
if (tag->name == "Char")
|
|
{
|
|
Tag *wrk = tag->GetTag("Id;");
|
|
if (!wrk || (wrk->GetType() != Variant::VariantInteger))
|
|
{
|
|
__LOG_W__ << "Glyph with no or invalid ID in font '" << nml << "', skipping.\n";
|
|
continue;
|
|
}
|
|
|
|
int glyphidx = wrk->GetInteger();
|
|
if (glyphidx > 255)
|
|
continue;
|
|
|
|
Glyph *pglyph = &glyph[glyphidx];
|
|
pglyph->page = 0;
|
|
pglyph->available = true;
|
|
|
|
NMLTagForeach(wrk, *tag)
|
|
{
|
|
if (wrk->name == "U")
|
|
pglyph->u = wrk->GetReal();
|
|
else if (wrk->name == "V")
|
|
pglyph->v = wrk->GetReal();
|
|
else if (wrk->name == "W")
|
|
pglyph->w = wrk->GetReal();
|
|
else if (wrk->name == "H")
|
|
pglyph->h = wrk->GetReal();
|
|
else if (wrk->name == "OffsetU")
|
|
pglyph->offx = wrk->GetReal();
|
|
else if (wrk->name == "OffsetV")
|
|
pglyph->offy = wrk->GetReal();
|
|
else if (wrk->name == "Step")
|
|
pglyph->step = wrk->GetReal();
|
|
else if (wrk->name == "Page")
|
|
{
|
|
if ((wrk->GetType() == Variant::VariantInteger) && ((uint)wrk->GetInteger() < page_count))
|
|
pglyph->page = wrk->GetInteger();
|
|
|
|
else
|
|
{
|
|
__LOG_W__ << "Invalid glyph page in font '" << nml << "' (Glyph #" << glyphidx << "), skipping.\n";
|
|
pglyph->available = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sanity check...
|
|
if (!glyph[' '].available)
|
|
__LOG_W__ << "No space character in font '" << nml << "'.\n";
|
|
|
|
// Load font pages.
|
|
for (uint n = 0; n < page_count; n++)
|
|
if (Texture *t = rf.LoadTexture(String::Format("%s_%02d.tga", base, n)))
|
|
pages.Add(t);
|
|
|
|
name = nml;
|
|
return true;
|
|
}
|
|
void RasterFont::Unload()
|
|
{
|
|
pages.Clear();
|
|
for (uint n = 0; n < 256; n++)
|
|
glyph[n].Reset();
|
|
}
|
|
//------------------------------------------------------------------------------
|