Files
Webcam/include/engine/core/raster_font.cpp

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();
}
//------------------------------------------------------------------------------