diff --git a/src/ui/CSimpleFontScript.cpp b/src/ui/CSimpleFontScript.cpp index f8068a2..5b0030c 100644 --- a/src/ui/CSimpleFontScript.cpp +++ b/src/ui/CSimpleFontScript.cpp @@ -1,4 +1,5 @@ #include "ui/CSimpleFontScript.hpp" +#include "ui/CSimpleFontString.hpp" #include "util/Unimplemented.hpp" #include diff --git a/src/ui/CSimpleFontString.cpp b/src/ui/CSimpleFontString.cpp index 5d58631..7fc13bf 100644 --- a/src/ui/CSimpleFontString.cpp +++ b/src/ui/CSimpleFontString.cpp @@ -15,10 +15,12 @@ #include "util/StringTo.hpp" #include #include +#include int32_t CSimpleFontString::s_count; int32_t CSimpleFontString::s_metatable; int32_t CSimpleFontString::s_objectType; +const char* CSimpleFontString::s_objectTypeName = "FontString"; void CSimpleFontString::CreateScriptMetaTable() { lua_State* L = FrameScript_GetContext(); @@ -127,6 +129,16 @@ bool CSimpleFontString::IsA(int32_t type) { || type == CScriptObject::s_objectType; } +bool CSimpleFontString::IsA(const char* typeName) { + return !SStrCmpI(typeName, CSimpleFontString::s_objectTypeName, STORM_MAX_STR) + || !SStrCmpI(typeName, CScriptRegion::s_objectTypeName, STORM_MAX_STR) + || !SStrCmpI(typeName, CScriptObject::s_objectTypeName, STORM_MAX_STR); +} + +const char* CSimpleFontString::GetObjectTypeName() { + return CSimpleFontString::s_objectTypeName; +} + void CSimpleFontString::FontObjectUpdated(CSimpleFontStringAttributes& attributes) { attributes.Update(this, this->m_fontableFlags); } @@ -936,3 +948,39 @@ void CSimpleFontString::UpdateString() { this->OnRegionChanged(); } + +bool CSimpleFontString::SetAlphaGradient(int32_t startChar, int32_t length) { + this->m_alphaGradientStart = startChar; + this->m_alphaGradientLength = length; + if (this->m_string) { + // TODO: return TextBlockSetGradient() + } + return false; +} + +void CSimpleFontString::SetShadowColor(const CImVector& color) { + if (this->m_shadowColor != color) { + this->m_shadowColor = color; + this->UpdateString(); + } +} + +void CSimpleFontString::SetShadowOffset(const C2Vector& offset) { +} + +void CSimpleFontString::SetTextHeight(float height) { + if (CMath::fequal(height, this->m_fontHeight)) { + return; + } + + this->m_styleFlags &= ~0x200u; + this->m_fontHeight = height; + this->m_cachedWidth = 0.0; + this->m_cachedHeight = 0.0; + if (this->m_string) { + HandleClose(this->m_string); + this->m_string = nullptr; + } + // TODO: Unset some flag + this->Resize(0); +} diff --git a/src/ui/CSimpleFontString.hpp b/src/ui/CSimpleFontString.hpp index a8a538d..cccbb5a 100644 --- a/src/ui/CSimpleFontString.hpp +++ b/src/ui/CSimpleFontString.hpp @@ -14,6 +14,7 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable { static int32_t s_count; static int32_t s_metatable; static int32_t s_objectType; + static const char* s_objectTypeName; // Static functions static void CreateScriptMetaTable(); @@ -43,6 +44,8 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable { // Virtual member functions virtual ~CSimpleFontString(); virtual bool IsA(int32_t type); + virtual bool IsA(const char* typeName); + virtual const char* GetObjectTypeName(); virtual int32_t GetScriptMetaTable(); virtual void LoadXML(XMLNode* node, CStatus* status); virtual void OnColorChanged(bool a2); @@ -84,6 +87,10 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable { void SetTextLength(uint32_t a2); int32_t Sub482AC0(); void UpdateString(); + bool SetAlphaGradient(int32_t startChar, int32_t length); + void SetShadowColor(const CImVector& color); + void SetShadowOffset(const C2Vector& offset); + void SetTextHeight(float height); }; #endif diff --git a/src/ui/CSimpleFontStringScript.cpp b/src/ui/CSimpleFontStringScript.cpp index 0032ef2..dcad7ac 100644 --- a/src/ui/CSimpleFontStringScript.cpp +++ b/src/ui/CSimpleFontStringScript.cpp @@ -1,40 +1,119 @@ #include "ui/CSimpleFontStringScript.hpp" #include "ui/CSimpleFont.hpp" #include "ui/CSimpleFontString.hpp" +#include "ui/Util.hpp" #include "util/Lua.hpp" #include "util/Unimplemented.hpp" -#include +#include "util/StringTo.hpp" +#include "gx/Coordinate.hpp" + int32_t CSimpleFontString_IsObjectType(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isstring(L, 2)) { + return luaL_error(L, "Usage: %s:IsObjectType(\"TYPE\")", string->GetDisplayName()); + } + + if (string->IsA(lua_tolstring(L, 2, nullptr))) { + lua_pushnumber(L, 1.0); + } else { + lua_pushnil(L); + } + return 1; } int32_t CSimpleFontString_GetObjectType(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + lua_pushstring(L, string->GetObjectTypeName()); + return 1; } int32_t CSimpleFontString_GetDrawLayer(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + auto layer = DrawLayerToString(string->m_drawlayer); + lua_pushstring(L, layer); + return 1; } int32_t CSimpleFontString_SetDrawLayer(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + const char* strlayer = lua_isstring(L, 2) ? lua_tostring(L, 2) : nullptr; + + int32_t layer = 0; + if (!strlayer || !StringToDrawLayer(strlayer, layer)) { + return luaL_error(L, "Usage: %s:SetDrawLayer(\"layer\")", string->GetDisplayName()); + } + + string->SetFrame(string->m_parent, layer, string->m_shown); + return 0; } int32_t CSimpleFontString_SetVertexColor(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color; + string->GetVertexColor(color); + + CImVector newColor; + FrameScript_GetColor(L, 2, newColor); + if (!lua_isnumber(L, 5)) { + newColor.a = color.a; + } + + string->SetVertexColor(newColor); + // TODO: Some flag should be set + return 0; } int32_t CSimpleFontString_GetAlpha(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color; + string->GetVertexColor(color); + lua_pushnumber(L, color.a / 255.0); + return 1; } int32_t CSimpleFontString_SetAlpha(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isnumber(L, 2)) { + return luaL_error(L, "Usage: %s:SetAlpha(alpha)", string->GetDisplayName()); + } + + CImVector color; + string->GetVertexColor(color); + + color.a = lua_tonumber(L, 2) * 255.0; + string->SetVertexColor(color); + return 0; } int32_t CSimpleFontString_SetAlphaGradient(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) { + return luaL_error(L, "Usage: %s:SetAlphaGradient(start, length)", string->GetDisplayName()); + } + + auto start = lua_tonumber(L, 2); + auto length = lua_tonumber(L, 3); + if (string->SetAlphaGradient(start, length)) { + lua_pushnumber(L, 1.0); + } else { + lua_pushnil(L); + } + return 1; } int32_t CSimpleFontString_Show(lua_State* L) { @@ -78,7 +157,17 @@ int32_t CSimpleFontString_IsShown(lua_State* L) { } int32_t CSimpleFontString_GetFontObject(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + if (string->m_fontObject) { + if (!string->m_fontObject->lua_registered) { + string->m_fontObject->RegisterScriptObject(nullptr); + } + lua_rawgeti(L, LUA_REGISTRYINDEX, string->m_fontObject->lua_objectRef); + } else { + lua_pushnil(L); + } + return 1; } int32_t CSimpleFontString_SetFontObject(lua_State* L) { @@ -116,19 +205,66 @@ int32_t CSimpleFontString_SetFontObject(lua_State* L) { } int32_t CSimpleFontString_GetFont(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + lua_pushstring(L, string->GetFontName()); + + auto height = string->GetFontHeight(false); + height *= CoordinateGetAspectCompensation() * 1024.0f; + height = DDCToNDCWidth(height); + lua_pushnumber(L, height); + + auto flags = FontFlagsToString(string->GetFontFlags()); + lua_pushstring(L, flags); + + return 3; } int32_t CSimpleFontString_SetFont(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isstring(L, 2) || !lua_isnumber(L, 3)) { + return luaL_error(L, "Usage: %s:SetFont(\"font\", fontHeight [, flags])", string->GetDisplayName()); + } + + auto fontName = lua_tostring(L, 2); + auto fontHeight = lua_tonumber(L, 3); + fontHeight /= CoordinateGetAspectCompensation() * 1024.0; + fontHeight = NDCToDDCWidth(fontHeight); + if (fontHeight <= 0.00000011920929) { + return luaL_error(L, "ERROR: %s:SetFont(): invalid fontHeight: %f, height must be > 0", string->GetDisplayName(), fontHeight); + } + + if (!*fontName) { + return 0; + } + + uint32_t fontFlags = 0; + if (lua_isstring(L, 4)) { + fontFlags = StringToFontFlags(lua_tostring(L, 4)); + } + + if (string->SetFont(fontName, fontHeight, fontFlags, false)) { + // TODO: Set some object flag + lua_pushnumber(L, 1.0); + } else { + lua_pushnil(L); + } + return 1; } int32_t CSimpleFontString_GetText(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + lua_pushstring(L, string->m_text); + return 1; } int32_t CSimpleFontString_GetFieldSize(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + lua_pushnumber(L, 8191.0); + return 1; } int32_t CSimpleFontString_SetText(lua_State* L) { @@ -160,39 +296,124 @@ int32_t CSimpleFontString_SetFormattedText(lua_State* L) { } int32_t CSimpleFontString_GetTextColor(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color; + string->GetVertexColor(color); + lua_pushnumber(L, color.r / 255.0); + lua_pushnumber(L, color.g / 255.0); + lua_pushnumber(L, color.b / 255.0); + lua_pushnumber(L, color.a / 255.0); + return 4; } int32_t CSimpleFontString_SetTextColor(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color; + FrameScript_GetColor(L, 2, color); + string->SetVertexColor(color); + + // TODO: Some flag should be set + return 0; } int32_t CSimpleFontString_GetShadowColor(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color = string->m_shadowColor; + lua_pushnumber(L, color.r / 255.0); + lua_pushnumber(L, color.g / 255.0); + lua_pushnumber(L, color.b / 255.0); + lua_pushnumber(L, color.a / 255.0); + return 4; } int32_t CSimpleFontString_SetShadowColor(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + CImVector color; + FrameScript_GetColor(L, 2, color); + string->SetShadowColor(color); + // TODO: Some flag should be set + return 0; } int32_t CSimpleFontString_GetShadowOffset(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + auto offset = string->m_shadowOffset; + offset *= CoordinateGetAspectCompensation() * 1024.0f; + lua_pushnumber(L, DDCToNDCWidth(offset.x)); + lua_pushnumber(L, DDCToNDCWidth(offset.y)); + return 2; } int32_t CSimpleFontString_SetShadowOffset(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) { + return luaL_error(L, "Usage: %s:SetShadowOffset(x, y)", string->GetDisplayName()); + } + + C2Vector offset; + offset.x = lua_tonumber(L, 2); + offset.y = lua_tonumber(L, 3); + offset /= CoordinateGetAspectCompensation() * 1024.0f; + offset.x = NDCToDDCWidth(offset.x); + offset.y = NDCToDDCWidth(offset.y); + + string->SetShadowOffset(offset); + // TODO: Some flag should be set + return 0; } int32_t CSimpleFontString_GetSpacing(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + float value = string->m_spacing; + value *= CoordinateGetAspectCompensation() * 1024.0f; + lua_pushnumber(L, DDCToNDCWidth(value)); + return 1; } int32_t CSimpleFontString_SetSpacing(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isnumber(L, 2)) { + return luaL_error(L, "Usage: %s:SetSpacing(spacing)", string->GetDisplayName()); + } + + float value = lua_tonumber(L, 2); + value /= CoordinateGetAspectCompensation() * 1024.0f; + string->SetSpacing(NDCToDDCWidth(value)); + // TODO: Some flag should be set + return 0; } int32_t CSimpleFontString_SetTextHeight(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + auto type = CSimpleFontString::GetObjectType(); + auto string = static_cast(FrameScript_GetObjectThis(L, type)); + + if (!lua_isstring(L, 2)) { + return luaL_error(L, "Usage: %s:SetTextHeight(pixelHeight)", string->GetDisplayName()); + } + + auto height = lua_tonumber(L, 3); + if (height <= 0.00000011920929) { + return luaL_error(L, "%s:SetTextHeight(): invalid texHeight: %f, height must be > 0", string->GetDisplayName(), height); + } + height /= CoordinateGetAspectCompensation() * 1024.0f; + height = NDCToDDCWidth(height); + string->SetTextHeight(height); + return 0; } int32_t CSimpleFontString_GetStringWidth(lua_State* L) { diff --git a/src/ui/CSimpleFrame.cpp b/src/ui/CSimpleFrame.cpp index 6859567..53e5cbe 100644 --- a/src/ui/CSimpleFrame.cpp +++ b/src/ui/CSimpleFrame.cpp @@ -25,6 +25,7 @@ int32_t CSimpleFrame::s_metatable; int32_t CSimpleFrame::s_objectType; +const char* CSimpleFrame::s_objectTypeName = "Frame"; int32_t CSimpleFrame::GetObjectType() { if (!CSimpleFrame::s_objectType) { @@ -654,6 +655,16 @@ bool CSimpleFrame::IsA(int32_t type) { || type == CScriptObject::s_objectType; } +bool CSimpleFrame::IsA(const char* typeName) { + return !SStrCmpI(typeName, CSimpleFrame::s_objectTypeName, STORM_MAX_STR) + || !SStrCmpI(typeName, CScriptRegion::s_objectTypeName, STORM_MAX_STR) + || !SStrCmpI(typeName, CScriptObject::s_objectTypeName, STORM_MAX_STR); +} + +const char* CSimpleFrame::GetObjectTypeName() { + return CSimpleFrame::s_objectTypeName; +} + void CSimpleFrame::EnableEvent(CSimpleEventType eventType, int32_t priority) { if ((1 << eventType) & this->m_eventmask) { return; diff --git a/src/ui/CSimpleFrame.hpp b/src/ui/CSimpleFrame.hpp index fcc9d55..cf895f2 100644 --- a/src/ui/CSimpleFrame.hpp +++ b/src/ui/CSimpleFrame.hpp @@ -27,6 +27,7 @@ class CSimpleFrame : public CScriptRegion { // Static members static int32_t s_metatable; static int32_t s_objectType; + static const char* s_objectTypeName; // Static functions static void CreateScriptMetaTable(); @@ -91,6 +92,8 @@ class CSimpleFrame : public CScriptRegion { virtual ~CSimpleFrame(); virtual ScriptIx* GetScriptByName(const char* name, ScriptData& data); virtual bool IsA(int32_t type); + virtual bool IsA(const char* typeName); + virtual const char* GetObjectTypeName(); virtual int32_t GetScriptMetaTable(); virtual void LoadXML(XMLNode* node, CStatus* status); virtual void PreOnAnimUpdate(); diff --git a/src/ui/Util.cpp b/src/ui/Util.cpp index 837a3ee..6e57f2a 100644 --- a/src/ui/Util.cpp +++ b/src/ui/Util.cpp @@ -126,3 +126,45 @@ const char* AnchorPointToString(int32_t point) { return "ANCHOR_NONE"; } } + +const char* DrawLayerToString(int32_t layer) { + switch (layer) { + case 0: + return "BACKGROUND"; + case 1: + return "BORDER"; + case 2: + return "ARTWORK"; + case 3: + return "OVERLAY"; + case 4: + return "HIGHLIGHT"; + default: + return "UNKNOWN"; + } +} + +const char* FontFlagsToString(uint32_t flags) { + struct FlagEntry { + uint32_t flag; + const char* string; + }; + + static FlagEntry table[3] = { + { 1, "OUTLINE" }, + { 4, "THICKOUTLINE" }, + { 2, "MONOCHROME" }, + }; + + static char result[64] = {}; + result[0] = '\0'; + for (size_t i = 0; i < 3; ++i) { + if (flags & table[i].flag) { + if (result[0]) { + SStrPack(result, ", ", sizeof(result)); + } + SStrPack(result, table[i].string, sizeof(result)); + } + } + return result; +} diff --git a/src/ui/Util.hpp b/src/ui/Util.hpp index cdbd2a4..341e6b4 100644 --- a/src/ui/Util.hpp +++ b/src/ui/Util.hpp @@ -17,4 +17,8 @@ const char* OrientationToString(uint32_t orientation); const char* AnchorPointToString(int32_t point); +const char* DrawLayerToString(int32_t layer); + +const char* FontFlagsToString(uint32_t flags); + #endif diff --git a/src/util/StringTo.cpp b/src/util/StringTo.cpp index edcd744..5630ca9 100644 --- a/src/util/StringTo.cpp +++ b/src/util/StringTo.cpp @@ -199,3 +199,20 @@ bool StringToAnchorPoint(const char* string, int32_t& point) { return false; } + +uint32_t StringToFontFlags(const char* string) { + static std::pair table[3] = { + { 1, "OUTLINE" }, + { 4, "THICKOUTLINE" }, + { 2, "MONOCHROME" } + }; + + uint32_t result = 0; + for (size_t i = 0; i < 3; ++i) { + if (!SStrCmpI(string, table[i].second, STORM_MAX_STR)) { + result |= table[i].first; + } + } + + return result; +} diff --git a/src/util/StringTo.hpp b/src/util/StringTo.hpp index 4b698ae..1a50593 100644 --- a/src/util/StringTo.hpp +++ b/src/util/StringTo.hpp @@ -21,4 +21,6 @@ bool StringToOrientation(const char* string, uint32_t& orientation); bool StringToAnchorPoint(const char* string, int32_t& point); +uint32_t StringToFontFlags(const char* string); + #endif