101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
#include <psemek/ui/bmfont.hpp>
|
|
#include <psemek/util/to_string.hpp>
|
|
|
|
#include <boost/preprocessor/stringize.hpp>
|
|
|
|
#define RAPIDJSON_ASSERT(x) if (!(x)) throw ::std::runtime_error("Error parsing font description: " BOOST_PP_STRINGIZE(x));
|
|
|
|
#include <rapidjson/document.h>
|
|
#include <rapidjson/istreamwrapper.h>
|
|
|
|
namespace psemek::ui
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
std::string_view to_string(rapidjson::ParseErrorCode const & code)
|
|
{
|
|
using namespace rapidjson;
|
|
|
|
switch (code)
|
|
{
|
|
case kParseErrorNone: return "no error";
|
|
case kParseErrorDocumentEmpty: return "document is empty";
|
|
case kParseErrorDocumentRootNotSingular: return "document root must not be followed by other values";
|
|
case kParseErrorValueInvalid: return "invalid value";
|
|
case kParseErrorObjectMissName: return "missing a name for object member";
|
|
case kParseErrorObjectMissColon: return "missing a colon after a name of object member";
|
|
case kParseErrorObjectMissCommaOrCurlyBracket: return "missing a comma or '}' after an object member";
|
|
case kParseErrorArrayMissCommaOrSquareBracket: return "missing a comma or ']' after an array element";
|
|
case kParseErrorStringUnicodeEscapeInvalidHex: return R"(Incorrect hex digit after \\u escape in string)";
|
|
case kParseErrorStringUnicodeSurrogateInvalid: return "surrogate pair in string is invalid";
|
|
case kParseErrorStringEscapeInvalid: return "invalid escape character in string";
|
|
case kParseErrorStringMissQuotationMark: return "missing a closing quotation mark in string";
|
|
case kParseErrorStringInvalidEncoding: return "invalid encoding in string";
|
|
case kParseErrorNumberTooBig: return "number too big to be stored in double";
|
|
case kParseErrorNumberMissFraction: return "missing fraction part in number";
|
|
case kParseErrorNumberMissExponent: return "missing exponent in number";
|
|
case kParseErrorTermination: return "parsing was terminated";
|
|
case kParseErrorUnspecificSyntaxError: return "unspecific syntax error";
|
|
default: return "(unknown error)";
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
bmfont_data bmfont_data::parse(io::istream && stream)
|
|
{
|
|
auto description_str = io::read_full(std::move(stream));
|
|
description_str.push_back(0);
|
|
|
|
rapidjson::Document document;
|
|
document.ParseInsitu(description_str.data());
|
|
|
|
if (document.HasParseError())
|
|
throw std::runtime_error(util::to_string("Error msdf font description: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset()));
|
|
|
|
bmfont_data result;
|
|
|
|
{
|
|
auto const & info = document["info"];
|
|
result.name = info["face"].GetString();
|
|
int size = info["size"].GetInt();
|
|
result.size = {size, size};
|
|
}
|
|
|
|
if (document.HasMember("distanceField"))
|
|
{
|
|
auto const & sdf = document["distanceField"];
|
|
result.sdf_scale = sdf["distanceRange"].GetFloat();
|
|
}
|
|
|
|
{
|
|
auto const & sdf = document["common"];
|
|
result.baseline = sdf["base"].GetInt();
|
|
}
|
|
|
|
{
|
|
auto chars = document["chars"].GetArray();
|
|
|
|
for (auto const & charInfo : chars)
|
|
{
|
|
char32_t id = charInfo["id"].GetUint();
|
|
|
|
auto & data = result.glyphs[id];
|
|
data.start_x = charInfo["x"].GetInt();
|
|
data.start_y = charInfo["y"].GetInt();
|
|
data.size_x = charInfo["width"].GetInt();
|
|
data.size_y = charInfo["height"].GetInt();
|
|
data.offset_x = charInfo["xoffset"].GetInt();
|
|
data.offset_y = charInfo["yoffset"].GetInt();
|
|
data.advance = charInfo["xadvance"].GetInt();
|
|
|
|
data.offset_y = - data.offset_y - data.size_y;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
}
|