#include "ui/CSimpleFont.hpp" #include "gx/Coordinate.hpp" #include "gx/Font.hpp" #include "ui/CSimpleFontScript.hpp" #include "ui/FrameXML.hpp" #include "ui/LoadXML.hpp" #include "ui/Types.hpp" #include "util/CStatus.hpp" #include "util/StringTo.hpp" #include #include TSHashTable CSimpleFont::s_fontList; int32_t CSimpleFont::s_metatable; int32_t CSimpleFont::s_objectType; SIMPLEFONT::SIMPLEFONT() : TSHashObject() { auto m = SMemAlloc(sizeof(CSimpleFont), __FILE__, __LINE__, 0x0); this->font = new (m) CSimpleFont(); } void CSimpleFont::CreateScriptMetaTable() { lua_State* L = FrameScript_GetContext(); int32_t ref = FrameScript_Object::CreateScriptMetaTable(L, &CSimpleFont::RegisterScriptMethods); CSimpleFont::s_metatable = ref; } CSimpleFont* CSimpleFont::GetFont(const char* name, int32_t a2) { SIMPLEFONT* hashed = CSimpleFont::s_fontList.Ptr(name); if (hashed) { return hashed->font; } if (!a2) { return nullptr; } hashed = CSimpleFont::s_fontList.New(name, 0, 0); CSimpleFont* font = hashed->font; if (font->m_name) { font->UnregisterScriptObject(font->m_name); } font->m_name = hashed->m_key.m_str; if (font->m_name) { font->RegisterScriptObject(font->m_name); } return hashed->font; } int32_t CSimpleFont::GetObjectType() { if (!CSimpleFont::s_objectType) { CSimpleFont::s_objectType = ++FrameScript_Object::s_objectTypes; } return CSimpleFont::s_objectType; } void CSimpleFont::RegisterScriptMethods(lua_State* L) { FrameScript_Object::FillScriptMethodTable(L, SimpleFontMethods, NUM_SIMPLE_FONT_SCRIPT_METHODS); } CSimpleFont::CSimpleFont() : FrameScript_Object() { // TODO } void CSimpleFont::FontObjectUpdated(CSimpleFontStringAttributes& attributes) { attributes.Update(this->m_attributes, this->m_fontableFlags); this->UpdateObjects(); } char* CSimpleFont::GetName() { return const_cast(this->m_name); } int32_t CSimpleFont::GetScriptMetaTable() { return CSimpleFont::s_metatable; } bool CSimpleFont::IsA(int32_t type) { return type == CSimpleFont::s_objectType; } void CSimpleFont::LoadXML(XMLNode* node, CStatus* status) { const char* inheritsAttr = node->GetAttributeByName("inherits"); if (inheritsAttr && *inheritsAttr) { auto font = CSimpleFont::GetFont(inheritsAttr, 0); if (font) { this->SetFontObject(font); } else { status->Add( STATUS_WARNING, "Couldn't find inherited font: %s", inheritsAttr ); } } const char* fontAttr = node->GetAttributeByName("font"); if (fontAttr && *fontAttr) { auto font = CSimpleFont::GetFont(fontAttr, 0); if (font) { this->SetFontObject(font); } else { float fontHeight = 0.0f; XMLNode* fontHeightNode = node->GetChildByName("FontHeight"); if (fontHeightNode) { LoadXML_Value(fontHeightNode, fontHeight, status); } if (fontHeight == 0.0f) { status->Add( STATUS_WARNING, "Font %s: Missing font height in %s element", this->GetDisplayName(), node->GetName() ); return; } uint32_t fontFlags = 0; const char* outlineAttr = node->GetAttributeByName("outline"); if (outlineAttr && *outlineAttr) { if (!SStrCmpI(outlineAttr, "NORMAL", STORM_MAX_STR)) { fontFlags |= FONT_OUTLINE; } else if (!SStrCmpI(outlineAttr, "THICK", STORM_MAX_STR)) { fontFlags |= (FONT_OUTLINE | FONT_THICKOUTLINE); } } const char* monochromeAttr = node->GetAttributeByName("monochrome"); if (monochromeAttr && *monochromeAttr && StringToBOOL(monochromeAttr)) { fontFlags |= FONT_MONOCHROME; } if (this->m_attributes.SetFont(fontAttr, fontHeight, fontFlags)) { this->m_fontableFlags &= ~FLAG_FONT_UPDATE; } else { status->Add( STATUS_WARNING, "Font %s: Unable to load font file %s", this->GetDisplayName(), fontAttr ); } } } const char* spacingAttr = node->GetAttributeByName("spacing"); if (spacingAttr && *spacingAttr) { float spacing = SStrToFloat(spacingAttr); float ndcSpacing = spacing / (CoordinateGetAspectCompensation() * 1024.0); float ddcSpacing = NDCToDDCWidth(ndcSpacing); this->m_attributes.SetSpacing(ddcSpacing); this->m_fontableFlags &= ~FLAG_SPACING_UPDATE; } const char* justifyVAttr = node->GetAttributeByName("justifyV"); if (justifyVAttr && *justifyVAttr) { uint32_t justify; if (StringToJustify(justifyVAttr, justify)) { this->m_attributes.SetJustifyV(justify); this->m_fontableFlags &= ~FLAG_STYLE_UPDATE; } } const char* justifyHAttr = node->GetAttributeByName("justifyH"); if (justifyHAttr && *justifyHAttr) { uint32_t justify; if (StringToJustify(justifyHAttr, justify)) { this->m_attributes.SetJustifyH(justify); this->m_fontableFlags &= ~FLAG_STYLE_UPDATE; } } const char* nonspacewrapAttr = node->GetAttributeByName("nonspacewrap"); if (nonspacewrapAttr && *nonspacewrapAttr) { bool nonspacewrap = StringToBOOL(nonspacewrapAttr); this->m_attributes.SetNonSpaceWrap(nonspacewrap); } const char* indentedAttr = node->GetAttributeByName("indented"); if (indentedAttr && *indentedAttr) { bool indented = StringToBOOL(indentedAttr); this->m_attributes.SetIndented(indented); } for (XMLNode* child = node->m_child; child; child = child->m_next) { if (!SStrCmpI(child->GetName(), "Color", STORM_MAX_STR)) { CImVector color; LoadXML_Color(child, color); this->m_attributes.SetColor(color); this->m_fontableFlags &= ~FLAG_COLOR_UPDATE; } else if(!SStrCmpI(child->GetName(), "Shadow", STORM_MAX_STR)) { C2Vector shadowOffset = { 0.001f, -0.001f }; CImVector shadowColor = { 0x00, 0x00, 0x00, 0xFF }; auto colorChild = child->GetChildByName("Color"); if (colorChild) { LoadXML_Color(colorChild, shadowColor); } auto offsetChild = child->GetChildByName("Offset"); if (offsetChild) { LoadXML_Dimensions(offsetChild, shadowOffset.x, shadowOffset.y, status); } this->m_attributes.SetShadow(shadowColor, shadowOffset); this->m_fontableFlags &= ~FLAG_SHADOW_UPDATE; } } } void CSimpleFont::UpdateObjects() { if (this->m_attributes.m_flags) { for (auto node = this->m_fontableList.Head(); node; node = this->m_fontableList.Link(node)->Next()) { node->FontObjectUpdated(this->m_attributes); } this->m_attributes.m_flags &= ~FLAG_COMPLETE_UPDATE; } }