metaforce/Runtime/GuiSys/CTextParser.cpp

370 lines
11 KiB
C++
Raw Normal View History

2016-03-21 00:25:53 +00:00
#include "CTextParser.hpp"
#include "CFontImageDef.hpp"
#include "CTextExecuteBuffer.hpp"
namespace urde
{
2017-01-24 07:41:33 +00:00
static float u16stof(char16_t* str)
{
char cstr[16];
2017-01-24 07:41:33 +00:00
int i;
for (i=0 ; i<15 && str[i] != u'\0' ; ++i)
cstr[i] = str[i];
cstr[i] = '\0';
return strtof(cstr, nullptr);
2017-01-24 07:41:33 +00:00
}
CTextColor CTextParser::ParseColor(const char16_t* str, int len)
2016-03-21 00:25:53 +00:00
{
u8 r = GetColorValue(str + 1);
u8 g = GetColorValue(str + 3);
u8 b = GetColorValue(str + 5);
u8 a = 0xff;
if (len == 9)
a = GetColorValue(str + 7);
2017-02-14 04:27:20 +00:00
CTextColor ret;
ret.fromRGBA8(r, g, b, a);
return ret;
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
u8 CTextParser::GetColorValue(const char16_t* str)
2016-03-21 00:25:53 +00:00
{
return (FromHex(str[0]) << 4) + FromHex(str[1]);
}
2017-01-24 07:41:33 +00:00
u32 CTextParser::FromHex(char16_t ch)
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
if (ch >= u'0' && ch <= u'9')
return ch - u'0';
2016-03-21 00:25:53 +00:00
2017-01-24 07:41:33 +00:00
if (ch >= u'A' && ch <= u'F')
return ch - u'A' + 10;
2016-03-21 00:25:53 +00:00
2017-01-24 07:41:33 +00:00
if (ch >= u'a' && ch <= u'f')
return ch - u'a' + 10;
2016-03-21 00:25:53 +00:00
return 0;
}
2017-01-24 07:41:33 +00:00
s32 CTextParser::ParseInt(const char16_t* str, int len, bool signVal)
2016-03-21 00:25:53 +00:00
{
bool neg = false;
int procCur = 0;
2017-01-24 07:41:33 +00:00
if (signVal && len && *str == u'-')
2016-03-21 00:25:53 +00:00
{
neg = true;
procCur = 1;
}
int val = 0;
while (len > procCur)
{
val *= 10;
wchar_t ch = str[procCur];
2017-01-24 07:41:33 +00:00
val += ch - u'0';
2016-03-21 00:25:53 +00:00
++procCur;
}
return neg ? -val : val;
}
2017-01-24 07:41:33 +00:00
bool CTextParser::Equals(const char16_t* str, int len, const char16_t* other)
2016-03-21 00:25:53 +00:00
{
int i=0;
for (; *other && i<len ; ++i, ++str, ++other)
{
if (*str != *other)
return false;
}
2017-01-24 07:41:33 +00:00
return other[i] == u'\0';
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
bool CTextParser::BeginsWith(const char16_t* str, int len, const char16_t* other)
2016-03-21 00:25:53 +00:00
{
int i=0;
for (; *other && i<len ; ++i, ++str, ++other)
{
if (*str != *other)
return false;
}
return true;
}
2017-05-31 21:26:50 +00:00
void CTextParser::ParseTag(CTextExecuteBuffer& out, const char16_t* str, int len,
const std::vector<std::pair<ResId, ResId>>* txtrMap)
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
if (BeginsWith(str, len, u"font="))
2016-03-21 00:25:53 +00:00
{
TToken<CRasterFont> font = GetFont(str + 5, len - 5);
out.AddFont(font);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"image="))
2016-03-21 00:25:53 +00:00
{
2017-05-31 21:26:50 +00:00
CFontImageDef image = GetImage(str + 6, len - 6, txtrMap);
2016-03-21 00:25:53 +00:00
out.AddImage(image);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"fg-color="))
2016-03-21 00:25:53 +00:00
{
CTextColor color = ParseColor(str + 9, len - 9);
out.AddColor(EColorType::Foreground, color);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"main-color="))
2016-03-21 00:25:53 +00:00
{
CTextColor color = ParseColor(str + 11, len - 11);
out.AddColor(EColorType::Main, color);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"geometry-color="))
2016-03-21 00:25:53 +00:00
{
CTextColor color = ParseColor(str + 15, len - 15);
out.AddColor(EColorType::Geometry, color);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"outline-color="))
2016-03-21 00:25:53 +00:00
{
CTextColor color = ParseColor(str + 14, len - 14);
out.AddColor(EColorType::Outline, color);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"color"))
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
const char16_t* valCur = str + 7;
2016-03-21 00:25:53 +00:00
len -= 7;
2017-01-24 07:41:33 +00:00
int val = str[6] - u'0';
if (str[7] >= u'0' && str[7] <= u'9')
2016-03-21 00:25:53 +00:00
{
++valCur;
--len;
val *= 10;
2017-01-24 07:41:33 +00:00
val += str[7] - u'0';
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
if (Equals(valCur + 10, len - 10, u"no"))
2016-03-21 00:25:53 +00:00
out.AddRemoveColorOverride(val);
else
{
CTextColor color = ParseColor(str + 10, len - 10);
out.AddColorOverride(val, color);
}
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"line-spacing="))
2016-03-21 00:25:53 +00:00
{
out.AddLineSpacing(ParseInt(str + 13, len - 13, true) / 100.0);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"line-extra-space="))
2016-03-21 00:25:53 +00:00
{
out.AddLineSpacing(ParseInt(str + 17, len - 17, true));
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"just="))
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
if (Equals(str + 5, len - 5, u"left"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::Left);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 5, len - 5, u"center"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::Center);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 5, len - 5, u"right"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::Right);
2017-01-26 10:06:18 +00:00
else if (Equals(str + 5, len - 5, u"full"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::Full);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 5, len - 5, u"nleft"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::NLeft);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 5, len - 5, u"ncenter"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::NCenter);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 5, len - 5, u"nright"))
2016-03-21 00:25:53 +00:00
out.AddJustification(EJustification::NRight);
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"vjust="))
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
if (Equals(str + 6, len - 6, u"top"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::Top);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 6, len - 6, u"center"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::Center);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 6, len - 6, u"bottom"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::Bottom);
2017-01-26 10:06:18 +00:00
else if (Equals(str + 6, len - 6, u"full"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::Full);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 6, len - 6, u"ntop"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::NTop);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 6, len - 6, u"ncenter"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::NCenter);
2017-01-24 07:41:33 +00:00
else if (Equals(str + 6, len - 6, u"nbottom"))
2016-03-21 00:25:53 +00:00
out.AddVerticalJustification(EVerticalJustification::NBottom);
}
2017-01-24 07:41:33 +00:00
else if (Equals(str, len, u"push"))
2016-03-21 00:25:53 +00:00
{
out.AddPushState();
}
2017-01-24 07:41:33 +00:00
else if (Equals(str, len, u"pop"))
2016-03-21 00:25:53 +00:00
{
out.AddPopState();
}
}
2017-05-31 21:26:50 +00:00
CFontImageDef CTextParser::GetImage(const char16_t* str, int len,
const std::vector<std::pair<ResId, ResId>>* txtrMap)
2016-03-21 00:25:53 +00:00
{
int commaCount = 0;
for (int i=0 ; i<len ; ++i)
2017-01-24 07:41:33 +00:00
if (str[i] == u',')
2016-03-21 00:25:53 +00:00
++commaCount;
if (commaCount)
{
2017-01-24 07:41:33 +00:00
std::u16string iterable(str, len);
2016-03-21 00:25:53 +00:00
size_t tokenPos;
size_t commaPos;
2017-01-24 07:41:33 +00:00
commaPos = iterable.find(u',');
iterable[commaPos] = u'\0';
2016-03-21 00:25:53 +00:00
tokenPos = commaPos + 1;
auto AdvanceCommaPos = [&]()
{
2017-01-24 07:41:33 +00:00
commaPos = iterable.find(u',', tokenPos);
if (commaPos == std::u16string::npos)
2016-03-21 00:25:53 +00:00
commaPos = iterable.size();
2017-01-24 07:41:33 +00:00
iterable[commaPos] = u'\0';
2016-03-21 00:25:53 +00:00
};
auto AdvanceTokenPos = [&]()
{
tokenPos = commaPos + 1;
};
2017-01-24 07:41:33 +00:00
if (BeginsWith(str, len, u"A"))
2016-03-21 00:25:53 +00:00
{
/* Animated texture array */
AdvanceCommaPos();
2017-01-24 07:41:33 +00:00
float interval = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
std::vector<TToken<CTexture>> texs;
texs.reserve(commaCount - 1);
do
{
AdvanceCommaPos();
texs.push_back(x0_store.GetObj({SBIG('TXTR'),
2017-07-07 12:23:20 +00:00
GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
} while (commaPos != iterable.size());
2017-01-29 03:58:16 +00:00
return CFontImageDef(texs, interval, zeus::CVector2f(1.f, 1.f));
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"SA"))
2016-03-21 00:25:53 +00:00
{
/* Scaled and animated texture array */
AdvanceCommaPos();
2017-01-24 07:41:33 +00:00
float interval = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
AdvanceCommaPos();
2017-01-30 06:58:59 +00:00
float cropX = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
AdvanceCommaPos();
2017-01-30 06:58:59 +00:00
float cropY = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
std::vector<TToken<CTexture>> texs;
texs.reserve(commaCount - 3);
do
{
AdvanceCommaPos();
texs.push_back(x0_store.GetObj({SBIG('TXTR'),
2017-07-07 12:23:20 +00:00
GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
} while (commaPos != iterable.size());
2017-01-30 06:58:59 +00:00
return CFontImageDef(texs, interval, zeus::CVector2f(cropX, cropY));
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
else if (BeginsWith(str, len, u"SI"))
2016-03-21 00:25:53 +00:00
{
/* Scaled single texture */
AdvanceCommaPos();
2017-01-30 06:58:59 +00:00
float cropX = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
AdvanceCommaPos();
2017-01-30 06:58:59 +00:00
float cropY = u16stof(&iterable[tokenPos]);
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
AdvanceCommaPos();
TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'),
2017-07-07 12:23:20 +00:00
GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)});
2016-03-21 00:25:53 +00:00
AdvanceTokenPos();
2017-01-30 06:58:59 +00:00
return CFontImageDef(tex, zeus::CVector2f(cropX, cropY));
2016-03-21 00:25:53 +00:00
}
}
2017-07-07 12:23:20 +00:00
TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(str, len, txtrMap)});
2017-01-29 03:58:16 +00:00
return CFontImageDef(tex, zeus::CVector2f(1.f, 1.f));
2016-03-21 00:25:53 +00:00
}
2017-07-07 12:23:20 +00:00
ResId CTextParser::GetAssetIdFromString(const char16_t* str, int len,
2017-05-31 21:26:50 +00:00
const std::vector<std::pair<ResId, ResId>>* txtrMap)
2016-03-21 00:25:53 +00:00
{
u8 r = GetColorValue(str);
u8 g = GetColorValue(str + 2);
u8 b = GetColorValue(str + 4);
u8 a = GetColorValue(str + 6);
2017-05-31 21:26:50 +00:00
ResId id = ((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff;
2017-07-07 12:23:20 +00:00
if (len == 16)
{
r = GetColorValue(str + 8);
g = GetColorValue(str + 10);
b = GetColorValue(str + 12);
a = GetColorValue(str + 14);
id = (id << 32) | (((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff);
}
2017-05-31 21:26:50 +00:00
if (txtrMap)
{
auto search = rstl::binary_find(txtrMap->begin(), txtrMap->end(), id,
[](const std::pair<ResId, ResId>& a) { return a.first; });
if (search != txtrMap->end())
2017-05-31 21:26:50 +00:00
id = search->second;
}
return id;
2016-03-21 00:25:53 +00:00
}
2017-01-24 07:41:33 +00:00
TToken<CRasterFont> CTextParser::GetFont(const char16_t* str, int len)
2016-03-21 00:25:53 +00:00
{
2017-07-07 12:23:20 +00:00
return x0_store.GetObj({SBIG('FONT'), GetAssetIdFromString(str, len, nullptr)});
2016-03-21 00:25:53 +00:00
}
2017-05-31 21:26:50 +00:00
void CTextParser::ParseText(CTextExecuteBuffer& out, const char16_t* str, int len,
const std::vector<std::pair<ResId, ResId>>* txtrMap)
2016-03-21 00:25:53 +00:00
{
2017-01-29 03:58:16 +00:00
int b=0, e=0;
for (b=0, e=0 ; str[e] && (len == -1 || e < len) ;)
2016-03-21 00:25:53 +00:00
{
2017-01-24 07:41:33 +00:00
if (str[e] != u'&')
2016-03-21 00:25:53 +00:00
{
++e;
continue;
}
2017-01-24 07:41:33 +00:00
if ((len == -1 || e+1 < len) && str[e+1] != u'&')
2016-03-21 00:25:53 +00:00
{
out.AddString(str + b, e - b);
++e;
b = e;
2017-01-24 07:41:33 +00:00
while (str[e] && (len == -1 || e < len) && str[e] != u';')
2016-03-21 00:25:53 +00:00
++e;
2017-05-31 21:26:50 +00:00
ParseTag(out, str + b, e - b, txtrMap);
2016-03-21 00:25:53 +00:00
b = e + 1;
}
else
{
out.AddString(str + b, e + 1 - b);
e += 2;
b = e;
}
}
2017-01-29 03:58:16 +00:00
if (e > b)
out.AddString(str + b, e - b);
2016-03-21 00:25:53 +00:00
}
}