diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sword25/kernel/inputpersistenceblock.cpp | 110 | ||||
-rw-r--r-- | engines/sword25/kernel/inputpersistenceblock.h | 5 | ||||
-rw-r--r-- | engines/sword25/kernel/kernel.h | 12 | ||||
-rw-r--r-- | engines/sword25/math/geometry_script.cpp | 249 | ||||
-rw-r--r-- | engines/sword25/math/line.h | 165 | ||||
-rw-r--r-- | engines/sword25/math/polygon.cpp | 339 | ||||
-rw-r--r-- | engines/sword25/math/polygon.h | 273 | ||||
-rw-r--r-- | engines/sword25/math/rect.h | 303 | ||||
-rw-r--r-- | engines/sword25/math/region.cpp | 194 | ||||
-rw-r--r-- | engines/sword25/math/region.h | 229 | ||||
-rw-r--r-- | engines/sword25/math/regionregistry.cpp | 46 | ||||
-rw-r--r-- | engines/sword25/math/regionregistry.h | 29 | ||||
-rw-r--r-- | engines/sword25/math/vertex.cpp | 26 | ||||
-rw-r--r-- | engines/sword25/math/vertex.h | 107 | ||||
-rw-r--r-- | engines/sword25/math/walkregion.cpp | 277 | ||||
-rw-r--r-- | engines/sword25/math/walkregion.h | 84 | ||||
-rw-r--r-- | engines/sword25/script/luascript.cpp | 2 |
17 files changed, 1018 insertions, 1432 deletions
diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp index 377b0bd994..6528d041ad 100644 --- a/engines/sword25/kernel/inputpersistenceblock.cpp +++ b/engines/sword25/kernel/inputpersistenceblock.cpp @@ -40,23 +40,21 @@ #include "sword25/kernel/inputpersistenceblock.h" -using namespace std; +namespace Sword25 { // ----------------------------------------------------------------------------- -// Construction / Destruction +// Constructor / Destructor // ----------------------------------------------------------------------------- BS_InputPersistenceBlock::BS_InputPersistenceBlock(const void * Data, unsigned int DataLength) : - m_Data(static_cast<const unsigned char *>(Data), static_cast<const unsigned char *>(Data) + DataLength), - m_ErrorState(NONE) -{ + m_Data(static_cast<const unsigned char *>(Data), DataLength), + m_ErrorState(NONE) { m_Iter = m_Data.begin(); } // ----------------------------------------------------------------------------- -BS_InputPersistenceBlock::~BS_InputPersistenceBlock() -{ +BS_InputPersistenceBlock::~BS_InputPersistenceBlock() { if (m_Iter != m_Data.end()) BS_LOG_WARNINGLN("Persistence block was not read to the end."); } @@ -64,80 +62,69 @@ BS_InputPersistenceBlock::~BS_InputPersistenceBlock() // Reading // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(signed int & Value) -{ - if (CheckMarker(SINT_MARKER)) - { +void BS_InputPersistenceBlock::Read(int16 &Value) { + signed int v; + Read(v); + Value = static_cast<int16>(v); +} + +// ----------------------------------------------------------------------------- + +void BS_InputPersistenceBlock::Read(signed int &Value) { + if (CheckMarker(SINT_MARKER)) { RawRead(&Value, sizeof(signed int)); Value = ConvertEndianessFromStorageToSystem(Value); - } - else - { + } else { Value = 0; } } // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(unsigned int & Value) -{ - if (CheckMarker(UINT_MARKER)) - { +void BS_InputPersistenceBlock::Read(unsigned int &Value) { + if (CheckMarker(UINT_MARKER)) { RawRead(&Value, sizeof(unsigned int)); Value = ConvertEndianessFromStorageToSystem(Value); - } - else - { + } else { Value = 0; } } // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(float & Value) -{ - if (CheckMarker(FLOAT_MARKER)) - { +void BS_InputPersistenceBlock::Read(float &Value) { + if (CheckMarker(FLOAT_MARKER)) { RawRead(&Value, sizeof(float)); Value = ConvertEndianessFromStorageToSystem(Value); - } - else - { + } else { Value = 0.0f; } } // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(bool & Value) -{ - if (CheckMarker(BOOL_MARKER)) - { +void BS_InputPersistenceBlock::Read(bool &Value) { + if (CheckMarker(BOOL_MARKER)) { unsigned int UIntBool; RawRead(&UIntBool, sizeof(float)); UIntBool = ConvertEndianessFromStorageToSystem(UIntBool); Value = UIntBool == 0 ? false : true; - } - else - { + } else { Value = 0.0f; } } // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(std::string & Value) -{ +void BS_InputPersistenceBlock::Read(Common::String &Value) { Value = ""; - if (CheckMarker(STRING_MARKER)) - { + if (CheckMarker(STRING_MARKER)) { unsigned int Size; Read(Size); - if (CheckBlockSize(Size)) - { - Value = std::string(reinterpret_cast<const char *>(&*m_Iter), Size); + if (CheckBlockSize(Size)) { + Value = Common::String(reinterpret_cast<const char *>(&*m_Iter), Size); m_Iter += Size; } } @@ -145,16 +132,13 @@ void BS_InputPersistenceBlock::Read(std::string & Value) // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::Read(vector<unsigned char> & Value) -{ - if (CheckMarker(BLOCK_MARKER)) - { +void BS_InputPersistenceBlock::Read(Common::Array<unsigned char> &Value) { + if (CheckMarker(BLOCK_MARKER)) { unsigned int Size; Read(Size); - if (CheckBlockSize(Size)) - { - Value = vector<unsigned char>(m_Iter, m_Iter + Size); + if (CheckBlockSize(Size)) { + Value = Common::Array<unsigned char>(m_Iter, Size); m_Iter += Size; } } @@ -162,10 +146,8 @@ void BS_InputPersistenceBlock::Read(vector<unsigned char> & Value) // ----------------------------------------------------------------------------- -void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size) -{ - if (CheckBlockSize(Size)) - { +void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size) { + if (CheckBlockSize(Size)) { memcpy(DestPtr, &*m_Iter, Size); m_Iter += Size; } @@ -173,14 +155,10 @@ void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size) // ----------------------------------------------------------------------------- -bool BS_InputPersistenceBlock::CheckBlockSize(int Size) -{ - if (m_Data.end() - m_Iter >= Size) - { +bool BS_InputPersistenceBlock::CheckBlockSize(int Size) { + if (m_Data.end() - m_Iter >= Size) { return true; - } - else - { + } else { m_ErrorState = END_OF_DATA; BS_LOG_ERRORLN("Unexpected end of persistence block."); return false; @@ -189,18 +167,16 @@ bool BS_InputPersistenceBlock::CheckBlockSize(int Size) // ----------------------------------------------------------------------------- -bool BS_InputPersistenceBlock::CheckMarker(unsigned char Marker) -{ +bool BS_InputPersistenceBlock::CheckMarker(unsigned char Marker) { if (!IsGood() || !CheckBlockSize(1)) return false; - if (*m_Iter++ == Marker) - { + if (*m_Iter++ == Marker) { return true; - } - else - { + } else { m_ErrorState = OUT_OF_SYNC; BS_LOG_ERRORLN("Wrong type marker found in persistence block."); return false; } } + +} // End of namespace Sword25 diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h index 6e1ec39943..b30429771b 100644 --- a/engines/sword25/kernel/inputpersistenceblock.h +++ b/engines/sword25/kernel/inputpersistenceblock.h @@ -62,12 +62,13 @@ public: BS_InputPersistenceBlock(const void *Data, unsigned int DataLength); virtual ~BS_InputPersistenceBlock(); + void Read(int16 &Value); void Read(signed int &Value); void Read(unsigned int &Value); void Read(float &Value); void Read(bool &Value); - void Read(std::string &Value); - void Read(std::vector<unsigned char> &Value); + void Read(Common::String &Value); + void Read(Common::Array<unsigned char> &Value); bool IsGood() const { return m_ErrorState == NONE; } ErrorState GetErrorState() const { return m_ErrorState; } diff --git a/engines/sword25/kernel/kernel.h b/engines/sword25/kernel/kernel.h index 692a4a215d..d09cf68ab6 100644 --- a/engines/sword25/kernel/kernel.h +++ b/engines/sword25/kernel/kernel.h @@ -339,6 +339,18 @@ public: BS_Service* (*CreateMethod)(BS_Kernel *); }; +template<class T> +void ReverseArray(Common::Array<T> Arr) { + if (Arr.size() < 2) + return; + + for (uint i = 0; i < (Arr.size() / 2 - 1); ++i) { + T temp = Arr[i]; + Arr[i] = Arr[Arr.size() - i - 1]; + Arr[Arr.size() - i - 1] = temp; + } } +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/geometry_script.cpp b/engines/sword25/math/geometry_script.cpp index 96606a7206..e656e5f548 100644 --- a/engines/sword25/math/geometry_script.cpp +++ b/engines/sword25/math/geometry_script.cpp @@ -36,11 +36,7 @@ // Includes // ----------------------------------------------------------------------------- -#include "sword25/kernel/memlog_off.h" -#include <memory> -#include <vector> -#include "sword25/kernel/memlog_on.h" - +#include "common/array.h" #include "sword25/gfx/graphicengine.h" #include "sword25/kernel/common.h" #include "sword25/kernel/kernel.h" @@ -55,21 +51,20 @@ // ----------------------------------------------------------------------------- -using namespace std; +namespace Sword25 { // ----------------------------------------------------------------------------- // Constants // ----------------------------------------------------------------------------- -// Die Strings werden als #defines definiert um Stringkomposition zur Compilezeit zu ermöglichen. +// These strings are defined as #defines to enable compile-time string composition #define REGION_CLASS_NAME "Geo.Region" #define WALKREGION_CLASS_NAME "Geo.WalkRegion" // ----------------------------------------------------------------------------- -// Wie luaL_checkudata, nur ohne dass kein Fehler erzeugt wird. -static void * my_checkudata (lua_State *L, int ud, const char *tname) -{ +// How luaL_checkudata, only without that no error is generated. +static void *my_checkudata(::lua_State *L, int ud, const char *tname) { int top = lua_gettop(L); void * p = lua_touserdata(L, ud); @@ -79,8 +74,8 @@ static void * my_checkudata (lua_State *L, int ud, const char *tname) { // lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ BS_LuaBindhelper::GetMetatable(L, tname); - if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */ - { + /* does it have the correct mt? */ + if (lua_rawequal(L, -1, -2)) { lua_settop(L, top); return p; } @@ -93,50 +88,43 @@ static void * my_checkudata (lua_State *L, int ud, const char *tname) // ----------------------------------------------------------------------------- -static void NewUintUserData(lua_State * L, unsigned int Value) -{ +static void NewUintUserData(::lua_State *L, unsigned int Value) { void * UserData = lua_newuserdata(L, sizeof(Value)); memcpy(UserData, &Value, sizeof(Value)); } // ----------------------------------------------------------------------------- -static bool IsValidPolygonDefinition(lua_State * L) -{ +static bool IsValidPolygonDefinition(::lua_State *L) { #ifdef DEBUG int __startStackDepth = lua_gettop(L); #endif - // Sicherstellen, dass wir wirklich eine Tabelle betrachten - if (!lua_istable(L, -1)) - { + // Ensure that we actually consider a table + if (!lua_istable(L, -1)) { luaL_error(L, "Invalid polygon definition. Unexpected type, \"table\" needed."); return false; } int TableSize = luaL_getn(L, -1); - // Sicherstellen, dass mindestens 3 Vertecies existieren. - if (TableSize < 6) - { + // Make sure that there are at least three Vertecies + if (TableSize < 6) { luaL_error(L, "Invalid polygon definition. At least three vertecies needed."); return false; } - // Sicherstellen, dass die Anzahl der Tabellenelemente durch zwei teilbar ist. - // Da je zwei Elemente ein Vertex definieren, ist eine ungerade Anzahl an Elementen nicht zulässig. - if ((TableSize % 2) != 0) - { + // Make sure that the number of table elements is divisible by two. + // Since any two elements is a vertex, an odd number of elements is not allowed + if ((TableSize % 2) != 0) { luaL_error(L, "Invalid polygon definition. Even number of table elements needed."); return false; } - // Sicherstellen, dass alle Elemente der Tabelle vom Typ Number sind. - for (int i = 1; i <= TableSize; i += 1) - { + // Ensure that all elements in the table are of type Number + for (int i = 1; i <= TableSize; i += 1) { lua_rawgeti(L, -1, i); - if (!lua_isnumber(L, -1)) - { + if (!lua_isnumber(L, -1)) { luaL_error(L, "Invalid polygon definition. All table elements have to be numbers."); return false; } @@ -152,32 +140,31 @@ static bool IsValidPolygonDefinition(lua_State * L) // ----------------------------------------------------------------------------- -static void TablePolygonToPolygon(lua_State * L, BS_Polygon & Polygon) -{ +static void TablePolygonToPolygon(::lua_State *L, BS_Polygon &Polygon) { #ifdef DEBUG int __startStackDepth = lua_gettop(L); #endif - // Sicherstellen, dass eine gültige Polygon-Definition auf dem Stack liegt. - // Es ist nicht notwendig den Rückgabewert abzufangen, da alle Fehler über luaL_error ausgegeben werden und somit die Ausführung des - // Skriptes beenden. + // Ensure that a valid polygon definition is on the stack. + // It is not necessary to catch the return value, since all errors are reported on luaL_error + // End script. IsValidPolygonDefinition(L); int VertexCount = luaL_getn(L, -1) / 2; - // Speicher für Vertecies reservieren - vector<BS_Vertex> Vertecies; + // Memory is reserved for Vertecies + Common::Array<BS_Vertex> Vertecies; Vertecies.reserve(VertexCount); - // Vertecies erstellen + // Create Vertecies for (int i = 0; i < VertexCount; i++) { - // X-Wert + // X Value lua_rawgeti(L, -1, (i * 2) + 1); int X = static_cast<int>(lua_tonumber(L, -1)); lua_pop(L, 1); - // Y-Wert + // Y Value lua_rawgeti(L, -1, (i * 2) + 2); int Y = static_cast<int>(lua_tonumber(L, -1)); lua_pop(L, 1); @@ -185,72 +172,63 @@ static void TablePolygonToPolygon(lua_State * L, BS_Polygon & Polygon) // Vertex Vertecies.push_back(BS_Vertex(X, Y)); } - BS_ASSERT(Vertecies.size() == VertexCount); + BS_ASSERT((int)Vertecies.size() == VertexCount); #ifdef DEBUG BS_ASSERT(__startStackDepth == lua_gettop(L)); #endif - // Polygon erstellen + // Create polygon Polygon.Init(VertexCount, &Vertecies[0]); } // ----------------------------------------------------------------------------- -static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName) -{ +static unsigned int TableRegionToRegion(::lua_State *L, const char *ClassName) { #ifdef DEBUG int __startStackDepth = lua_gettop(L); #endif - // Man kann eine Region in Lua auf zwei Arten definieren: - // 1. Eine Tabelle, die ein Polygon definiert (Polygon = Tabelle mit Zahlen, wobei je zwei aufeinander folgende Zahlen ein Vertex definieren) - // Das eine Polygon definiert die Region vollständig (=> keine Löcher möglich) - // 2. Eine Tabelle, die mehrere Polygondefinitionen (wiederum Tabellen (siehe 1.)) enthält. - // Dann definiert das erste Polygon den Umriss der Region und die folgenden Löcher im ersten Polygon. + // You can define a region in Lua in two ways: + // 1. A table that defines a polygon (polgon = table with numbers, which define + // two consecutive numbers per vertex) + // 2. A table containing more polygon definitions + // Then the first polygon is the contour of the region, and the following are holes + // defined in the first polygon. - // Es darf nur ein Parameter übergeben werden und dieser muss eine Tabelle sein. - if (lua_gettop(L) != 1 || !lua_istable(L, -1)) - { + // It may be passed only one parameter, and this must be a table + if (lua_gettop(L) != 1 || !lua_istable(L, -1)) { luaL_error(L, "First and only parameter has to be of type \"table\"."); return 0; } unsigned int RegionHandle; - if (ClassName == REGION_CLASS_NAME) - { + if (ClassName == REGION_CLASS_NAME) { RegionHandle = BS_Region::Create(BS_Region::RT_REGION); - } - else if (ClassName == WALKREGION_CLASS_NAME) - { + } else if (ClassName == WALKREGION_CLASS_NAME) { RegionHandle = BS_WalkRegion::Create(BS_Region::RT_WALKREGION); - } - else - { + } else { BS_ASSERT(false); } BS_ASSERT(RegionHandle); - // Wenn das erste Element des Parameters eine Zahl ist, wird der 1. Fall angenommen. - // Wenn das erste Element des Parameters eine Tabelle ist, wird der 2. Fall angenommen. - // Wenn das erste Element des Parameters einen anderen Typ hat, liegt ein Fehler vor. + // If the first element of the parameter is a number, then case 1 is accepted + // If the first element of the parameter is a table, then case 2 is accepted + // If the first element of the parameter has a different type, there is an error lua_rawgeti(L, -1, 1); int FirstElementType = lua_type(L, -1); lua_pop(L, 1); - switch(FirstElementType) - { - case LUA_TNUMBER: - { + switch(FirstElementType) { + case LUA_TNUMBER: { BS_Polygon Polygon; TablePolygonToPolygon(L, Polygon); BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon); } break; - case LUA_TTABLE: - { + case LUA_TTABLE: { lua_rawgeti(L, -1, 1); BS_Polygon Polygon; TablePolygonToPolygon(L, Polygon); @@ -259,19 +237,17 @@ static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName) int PolygonCount = luaL_getn(L, -1); if (PolygonCount == 1) BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon); - else - { - vector<BS_Polygon> Holes; + else { + Common::Array<BS_Polygon> Holes; Holes.reserve(PolygonCount - 1); - for (int i = 2; i <= PolygonCount; i++) - { + for (int i = 2; i <= PolygonCount; i++) { lua_rawgeti(L, -1, i); Holes.resize(Holes.size() + 1); TablePolygonToPolygon(L, Holes.back()); lua_pop(L, 1); } - BS_ASSERT(Holes.size() == PolygonCount - 1); + BS_ASSERT((int)Holes.size() == PolygonCount - 1); BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon, &Holes); } @@ -292,10 +268,10 @@ static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName) // ----------------------------------------------------------------------------- -static void NewUserdataRegion(lua_State * L, const char * ClassName) +static void NewUserdataRegion(::lua_State *L, const char *ClassName) { - // Region aufgrund des Lua-Codes erstellen. - // Fehler treten nicht auf, sondern werden von der Funktion über luaL_error abgefangen. + // Region due to the Lua code to create + // Any errors that occur will be intercepted to the luaL_error unsigned int RegionHandle = TableRegionToRegion(L, ClassName); BS_ASSERT(RegionHandle); @@ -308,26 +284,23 @@ static void NewUserdataRegion(lua_State * L, const char * ClassName) // ----------------------------------------------------------------------------- -static int NewRegion(lua_State * L) -{ +static int NewRegion(::lua_State *L) { NewUserdataRegion(L, REGION_CLASS_NAME); return 1; } // ----------------------------------------------------------------------------- -static int NewWalkRegion(lua_State * L) -{ +static int NewWalkRegion(::lua_State *L) { NewUserdataRegion(L, WALKREGION_CLASS_NAME); return 1; } // ----------------------------------------------------------------------------- -static const char * GEO_LIBRARY_NAME = "Geo"; +static const char *GEO_LIBRARY_NAME = "Geo"; -static const luaL_reg GEO_FUNCTIONS[] = -{ +static const luaL_reg GEO_FUNCTIONS[] = { "NewRegion", NewRegion, "NewWalkRegion", NewWalkRegion, 0, 0, @@ -335,28 +308,23 @@ static const luaL_reg GEO_FUNCTIONS[] = // ----------------------------------------------------------------------------- -static BS_Region * CheckRegion(lua_State * L) -{ - // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Geo.Region oder Geo.WalkRegion - unsigned int * RegionHandlePtr; +static BS_Region * CheckRegion(::lua_State *L) { + // The first parameter must be of type 'userdata', and the Metatable class Geo.Region or Geo.WalkRegion + unsigned int *RegionHandlePtr; if ((RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, REGION_CLASS_NAME))) != 0 || - (RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) - { + (RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { return BS_RegionRegistry::GetInstance().ResolveHandle(*RegionHandlePtr); - } - else - { + } else { luaL_argcheck(L, 0, 1, "'" REGION_CLASS_NAME "' expected"); } - // Compiler ruhigstellen. Ausführung kommt nie an diesem Punkt an. + // Compilation fix. Execution never reaches this point return 0; } // ----------------------------------------------------------------------------- -static int R_IsValid(lua_State * L) -{ +static int R_IsValid(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -366,8 +334,7 @@ static int R_IsValid(lua_State * L) // ----------------------------------------------------------------------------- -static int R_GetX(lua_State * L) -{ +static int R_GetX(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -377,8 +344,7 @@ static int R_GetX(lua_State * L) // ----------------------------------------------------------------------------- -static int R_GetY(lua_State * L) -{ +static int R_GetY(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -388,8 +354,7 @@ static int R_GetY(lua_State * L) // ----------------------------------------------------------------------------- -static int R_GetPos(lua_State * L) -{ +static int R_GetPos(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -399,8 +364,7 @@ static int R_GetPos(lua_State * L) // ----------------------------------------------------------------------------- -static int R_IsPointInRegion(lua_State * L) -{ +static int R_IsPointInRegion(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -412,8 +376,7 @@ static int R_IsPointInRegion(lua_State * L) // ----------------------------------------------------------------------------- -static int R_SetPos(lua_State * L) -{ +static int R_SetPos(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -426,8 +389,7 @@ static int R_SetPos(lua_State * L) // ----------------------------------------------------------------------------- -static int R_SetX(lua_State * L) -{ +static int R_SetX(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -438,8 +400,7 @@ static int R_SetX(lua_State * L) // ----------------------------------------------------------------------------- -static int R_SetY(lua_State * L) -{ +static int R_SetY(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); @@ -450,9 +411,8 @@ static int R_SetY(lua_State * L) // ----------------------------------------------------------------------------- -static void DrawPolygon(const BS_Polygon & Polygon, unsigned int Color, const BS_Vertex & Offset) -{ - BS_GraphicEngine * pGE = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx")); +static void DrawPolygon(const BS_Polygon &Polygon, unsigned int Color, const BS_Vertex &Offset) { + BS_GraphicEngine *pGE = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx")); BS_ASSERT(pGE); for (int i = 0; i < Polygon.VertexCount - 1; i++) @@ -463,8 +423,7 @@ static void DrawPolygon(const BS_Polygon & Polygon, unsigned int Color, const BS // ----------------------------------------------------------------------------- -static void DrawRegion(const BS_Region & Region, unsigned int Color, const BS_Vertex & Offset) -{ +static void DrawRegion(const BS_Region &Region, unsigned int Color, const BS_Vertex &Offset) { DrawPolygon(Region.GetContour(), Color, Offset); for (int i = 0; i < Region.GetHoleCount(); i++) DrawPolygon(Region.GetHole(i), Color, Offset); @@ -472,15 +431,12 @@ static void DrawRegion(const BS_Region & Region, unsigned int Color, const BS_Ve // ----------------------------------------------------------------------------- -static int R_Draw(lua_State * L) -{ +static int R_Draw(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); - switch (lua_gettop(L)) - { - case 3: - { + switch (lua_gettop(L)) { + case 3: { BS_Vertex Offset; BS_Vertex::LuaVertexToVertex(L, 3, Offset); DrawRegion(*pR, BS_GraphicEngine::LuaColorToARGBColor(L, 2), Offset); @@ -500,8 +456,7 @@ static int R_Draw(lua_State * L) // ----------------------------------------------------------------------------- -static int R_GetCentroid(lua_State * L) -{ +static int R_GetCentroid(::lua_State *L) { BS_Region * RPtr = CheckRegion(L); BS_ASSERT(RPtr); @@ -512,8 +467,7 @@ static int R_GetCentroid(lua_State * L) // ----------------------------------------------------------------------------- -static int R_Delete(lua_State * L) -{ +static int R_Delete(::lua_State *L) { BS_Region * pR = CheckRegion(L); BS_ASSERT(pR); delete pR; @@ -522,8 +476,7 @@ static int R_Delete(lua_State * L) // ----------------------------------------------------------------------------- -static const luaL_reg REGION_METHODS[] = -{ +static const luaL_reg REGION_METHODS[] = { "SetPos", R_SetPos, "SetX", R_SetX, "SetY", R_SetY, @@ -539,28 +492,23 @@ static const luaL_reg REGION_METHODS[] = // ----------------------------------------------------------------------------- -static BS_WalkRegion * CheckWalkRegion(lua_State * L) -{ - // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Geo.WalkRegion +static BS_WalkRegion *CheckWalkRegion(::lua_State *L) { + // The first parameter must be of type 'userdate', and the Metatable class Geo.WalkRegion unsigned int RegionHandle; - if ((RegionHandle = *reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) - { + if ((RegionHandle = *reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { return reinterpret_cast<BS_WalkRegion *>(BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)); - } - else - { + } else { luaL_argcheck(L, 0, 1, "'" WALKREGION_CLASS_NAME "' expected"); } - // Compiler ruhigstellen. Ausführung kommt nie an diesem Punkt an. + // Compilation fix. Execution never reaches this point return 0; } // ----------------------------------------------------------------------------- -static int WR_GetPath(lua_State * L) -{ - BS_WalkRegion * pWR = CheckWalkRegion(L); +static int WR_GetPath(::lua_State *L) { + BS_WalkRegion *pWR = CheckWalkRegion(L); BS_ASSERT(pWR); BS_Vertex Start; @@ -568,18 +516,15 @@ static int WR_GetPath(lua_State * L) BS_Vertex End; BS_Vertex::LuaVertexToVertex(L, 3, End); BS_Path Path; - if (pWR->QueryPath(Start, End, Path)) - { + if (pWR->QueryPath(Start, End, Path)) { lua_newtable(L); BS_Path::const_iterator it = Path.begin(); - for (; it != Path.end(); it++) - { + for (; it != Path.end(); it++) { lua_pushnumber(L, (it - Path.begin()) + 1); BS_Vertex::VertexToLuaVertex(L, *it); lua_settable(L, -3); } - } - else + } else lua_pushnil(L); return 1; @@ -587,21 +532,19 @@ static int WR_GetPath(lua_State * L) // ----------------------------------------------------------------------------- -static const luaL_reg WALKREGION_METHODS[] = -{ +static const luaL_reg WALKREGION_METHODS[] = { "GetPath", WR_GetPath, 0, 0, }; // ----------------------------------------------------------------------------- -bool BS_Geometry::_RegisterScriptBindings() -{ +bool BS_Geometry::_RegisterScriptBindings() { BS_Kernel * pKernel = BS_Kernel::GetInstance(); BS_ASSERT(pKernel); BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script")); BS_ASSERT(pScript); - lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject()); + ::lua_State *L = static_cast< ::lua_State *>(pScript->GetScriptObject()); BS_ASSERT(L); if (!BS_LuaBindhelper::AddMethodsToClass(L, REGION_CLASS_NAME, REGION_METHODS)) return false; @@ -615,3 +558,5 @@ bool BS_Geometry::_RegisterScriptBindings() return true; } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/line.h b/engines/sword25/math/line.h index 3dd178adb5..86bcbd6537 100644 --- a/engines/sword25/math/line.h +++ b/engines/sword25/math/line.h @@ -35,11 +35,11 @@ /* BS_Line ------- - Diese Klasse enthält nur statische Methoden, die mit Geradensegmenten zu tun haben. - Es gibt keine wirkliche Geradensegment-Klasse, da diese Klasse vor allem zu - Berechnungen mit Polygonen herangezogen wird und es dabei wichtig ist, Start- und - Endpunkte der Linien dynamisch wählen zu können. Dieses würde sich verbieten, wenn - ein Polygon aus einer Menge von festen Geradensegmenten gebildet wäre. + This class contains only static methods, which have to do with straight line + segments. There is no real straight line segment class. Calculations will be + used with polygons, and it is important the process of starting and selecting + endpoints of lines is dynamic. This would prhobit a polygon from a set + being formed by fixed line segments Autor: Malte Thiesen */ @@ -55,77 +55,69 @@ // ----------------------------------------------------------------------------- -class BS_Line -{ +namespace Sword25 { + +class BS_Line { public: /** - @brief Bestimmt ob sich ein Punkt links von einer Linie befindet. - @param a der Startpunkt der Linie - @param b der Endpunkt der Linie - @param c der Testpunkt - @return Gibt true zurück, wenn sich der Punkt links von der Linie befindet.<br> - Falls sich der Punkt rechts von der Linie oder auf der Linie befindet wird false zurückgegeben.<br> - @remark Ein Punkt liegt links von einer Linie, wenn er vom Startpunkt aus betrachtet links neben der Linie liegt. - */ - static bool IsVertexLeft(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + * Determines whether a piont is left of a line + * @param a The start point of a line + * @param b The end point of a line + * @param c The test point + * @return Returns true if the point is to the left of the line. + * If the point is to the right of the line or on the line, false is returned. + */ + static bool IsVertexLeft(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return _TriangleArea2(a, b, c) > 0; } - static bool IsVertexLeftOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + static bool IsVertexLeftOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return _TriangleArea2(a, b, c) >= 0; } /** - @brief Bestimmt ob sich ein Punkt rechts von einer Linie befindet. - @param a der Startpunkt der Linie - @param b der Endpunkt der Linie - @param c der Testpunkt - @return Gibt true zurück, wenn sich der Punkt recht von der Linie befindet.<br> - Falls sich der Punkt links von der Linie oder auf der Linie befindet wird false zurückgegeben.<br> - @remark Ein Punkt liegt rechts von einer Linie, wenn er vom Startpunkt aus betrachtet rechts neben der Linie liegt. - */ - static bool IsVertexRight(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + * Determines whether a piont is right of a line + * @param a The start point of a line + * @param b The end point of a line + * @param c The test point + * @return Returns true if the point is to the right of the line. + * If the point is to the right of the line or on the line, false is returned. + */ + static bool IsVertexRight(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return _TriangleArea2(a, b, c) < 0; } - static bool IsVertexRightOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + static bool IsVertexRightOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return _TriangleArea2(a, b, c) <= 0; } /** - @brief Bestimmt ob sich ein Punkt auf einer Linie befindet. - @param a der Startpunkt der Linie - @param b der Endpunkt der Linie - @param c der Testpunkt - @return Gibt true zurück, wenn sich der Punkt auf der Linie befindet. - */ - static bool IsVertexOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + * Determines whether a piont is on a line + * @param a The start point of a line + * @param b The end point of a line + * @param c The test point + * @return Returns true if the point is on the line, false otherwise. + */ + static bool IsVertexOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return _TriangleArea2(a, b, c) == 0; } - enum VERTEX_CLASSIFICATION - { + enum VERTEX_CLASSIFICATION { LEFT, RIGHT, ON }; /** - @brief Bestimmt wo sich ein Punkt relativ zu einer Linie befindet. - @param a der Startpunkt der Linie - @param b der Endpunkt der Linie - @param c der Testpunkt - @return Gibt LEFT zurück, wenn sich der Punkt links von der Line befindet.<br> - Gibt RIGHT zurück, wenn sich der Punkt links von der Line befindet.<br> - Gibt ON zurück, wenn sich der Punkt auf der Linie befindet. - */ - static VERTEX_CLASSIFICATION ClassifyVertexToLine(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + * Determines where a point is relative to a line. + * @param a The start point of a line + * @param b The end point of a line + * @param c The test point + * @return LEFT is returned if the point is to the left of the line. + * RIGHT is returned if the point is to the right of the line. + * ON is returned if the point is on the line. + */ + static VERTEX_CLASSIFICATION ClassifyVertexToLine(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { int Area = _TriangleArea2(a, b, c); if (Area > 0) return LEFT; if (Area < 0) return RIGHT; @@ -133,15 +125,14 @@ public: } /** - @brief Bestimmt ob sich zwei Linien schneiden. - @param a der Startpunkt der ersten Linie - @param b der Endpunkt der ersten Linie - @param c der Startpunkt der zweiten Linie - @param d der Endpunkt der zweiten Linie - @remark In den Fällen in denen eine Linie die andere nur berührt, wird false zurückgegeben (improper intersection). - */ - static bool DoesIntersectProperly(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c, const BS_Vertex & d) - { + * Determines whether two lines intersect + * @param a The start point of the first line + * @param b The end point of the first line + * @param c The start point of the second line + * @param d The end point of the second line + * @remark In cases where a line only touches the other, false is returned (improper intersection) + */ + static bool DoesIntersectProperly(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c, const BS_Vertex &d) { VERTEX_CLASSIFICATION Class1 = ClassifyVertexToLine(a, b, c); VERTEX_CLASSIFICATION Class2 = ClassifyVertexToLine(a, b, d); VERTEX_CLASSIFICATION Class3 = ClassifyVertexToLine(c, d, a); @@ -153,26 +144,22 @@ public: } /** - @brief Bestimmt ob sich ein Punkt auf einem Liniensegment befindet - @param a der Startpunkt der Liniensegmentes - @param b der Endpunkt der Liniensegmentes - @param c der Testpunkt - */ - static bool IsOnLine(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { - // Die Punkte müssen alle Kollinear sein, sonst liegt der Testpunkt nicht auf dem Liniensegment + * Determines whether a point is on a line segment + * @param a The start point of a line + * @param b The end point of a line + * @param c The test point + */ + static bool IsOnLine(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { + // The items must all be Collinear, otherwise don't bothering testing the point if (_TriangleArea2(a, b, c) != 0) return false; - // Falls das Liniensegment nicht vertikal ist prüfe auf der X-Achse, ansonsten auf der Y-Achse - if (a.X != b.X) - { + // If the line segment is not vertical, check on the x-axis, otherwise the y-axis + if (a.X != b.X) { return ((a.X <= c.X) && (c.X <= b.X)) || ((a.X >= c.X) && (c.X >= b.X)); - } - else - { + } else { return ((a.Y <= c.Y) && (c.Y <= b.Y)) || ((a.Y >= c.Y) && @@ -180,21 +167,17 @@ public: } } - static bool IsOnLineStrict(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { - // Die Punkte müssen alle Kollinear sein, sonst liegt der Testpunkt nicht auf dem Liniensegment + static bool IsOnLineStrict(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { + // The items must all be Collinear, otherwise don't bothering testing the point if (_TriangleArea2(a, b, c) != 0) return false; - // Falls das Liniensegment nicht vertikal ist prüfe auf der X-Achse, ansonsten auf der Y-Achse - if (a.X != b.X) - { + // If the line segment is not vertical, check on the x-axis, otherwise the y-axis + if (a.X != b.X) { return ((a.X < c.X) && (c.X < b.X)) || ((a.X > c.X) && (c.X > b.X)); - } - else - { + } else { return ((a.Y < c.Y) && (c.Y < b.Y)) || ((a.Y > c.Y) && @@ -203,19 +186,19 @@ public: } private: - /** - @brief Gibt die doppelte Größe des durch a, b und c definierten Dreiecks zurück. - - Das Ergebnis ist positiv wenn die Punkte entgegen dem Uhrzeigersinn angeordnet sind und negativ wenn sie mit dem - Uhrzeigersinn angeordnet sind. - */ - static int _TriangleArea2(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c) - { + * Return double the size of the triangle defined by the three passed points. + * + * The result is positive if the points are arrange counterclockwise, + * and negative if they are arranged counter-clockwise. + */ + static int _TriangleArea2(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) { return a.X * b.Y - a.Y * b.X + a.Y * c.X - a.X * c.Y + b.X * c.Y - c.X * b.Y; } }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/polygon.cpp b/engines/sword25/math/polygon.cpp index ab5ce0d96d..6d416ea080 100644 --- a/engines/sword25/math/polygon.cpp +++ b/engines/sword25/math/polygon.cpp @@ -32,11 +32,6 @@ * */ -#include "sword25/kernel/memlog_off.h" -#include <utility> -#include <vector> -#include "sword25/kernel/memlog_on.h" - #include <math.h> #include "sword25/kernel/outputpersistenceblock.h" @@ -45,58 +40,52 @@ #include "sword25/math/polygon.h" #include "sword25/math/line.h" +namespace Sword25 { + #define max(a,b) (((a) > (b)) ? (a) : (b)) -// Konstruktion / Destruktion +// Constructor / Destructor // -------------------------- -BS_Polygon::BS_Polygon() : VertexCount(0), Vertecies(NULL) -{ +BS_Polygon::BS_Polygon() : VertexCount(0), Vertecies(NULL) { } -BS_Polygon::BS_Polygon(int VertexCount, const BS_Vertex* Vertecies) : VertexCount(0), Vertecies(NULL) -{ +BS_Polygon::BS_Polygon(int VertexCount, const BS_Vertex *Vertecies) : VertexCount(0), Vertecies(NULL) { Init(VertexCount, Vertecies); } -BS_Polygon::BS_Polygon(const BS_Polygon& Other) : VertexCount(0), Vertecies(NULL) -{ +BS_Polygon::BS_Polygon(const BS_Polygon &Other) : VertexCount(0), Vertecies(NULL) { Init(Other.VertexCount, Other.Vertecies); } -BS_Polygon::BS_Polygon(BS_InputPersistenceBlock & Reader) : VertexCount(0), Vertecies(NULL) -{ +BS_Polygon::BS_Polygon(BS_InputPersistenceBlock &Reader) : VertexCount(0), Vertecies(NULL) { Unpersist(Reader); } -BS_Polygon::~BS_Polygon() -{ +BS_Polygon::~BS_Polygon() { delete[] Vertecies; } -// Initialisierung +// Initialisation // --------------- -bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies) -{ - // Alten Objektzustand merken um ihn wieder herstellen zu können, falls beim Initialisieren mit den neuen Daten ein Fehler auftreten - // sollte. +bool BS_Polygon::Init(int VertexCount, const BS_Vertex *Vertecies) { + // Rember the old obstate to restore it if an error occurs whilst initialising it with the new data int OldVertexCount = this->VertexCount; - BS_Vertex* OldVertecies = this->Vertecies; + BS_Vertex *OldVertecies = this->Vertecies; this->VertexCount = VertexCount; this->Vertecies = new BS_Vertex[VertexCount + 1]; memcpy(this->Vertecies, Vertecies, sizeof(BS_Vertex) * VertexCount); // TODO: - // Doppelte und überflüssige Vertecies entfernen (überflüssig = 3 Verts kollinear) + // Duplicate and remove redundant vertecies (Superflous = 3 co-linear verts) // _WeedRepeatedVertecies(); - // Das erste Vertex wird am Ende des Vertex-Arrays wiederholt, dieses vereinfacht einige Algorithmen, die alle Edges durchgehen und - // sich so die Überlaufkontrolle sparen können. + // The first vertex is repeated at the end of the vertex array; this simplifies + // some algorithms, running through the edges and thus can save the overflow control. this->Vertecies[VertexCount] = this->Vertecies[0]; - // Falls das Polygon selbstüberschneidend ist, wird der alte Objektzustand wieder hergestellt und ein Fehler signalisiert. - if (CheckForSelfIntersection()) - { + // If the polygon is self-intersecting, the object state is restore, and an error signalled + if (CheckForSelfIntersection()) { delete[] this->Vertecies; this->Vertecies = OldVertecies; this->VertexCount = OldVertexCount; @@ -105,10 +94,10 @@ bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies) return false; } - // Alte Vertexliste freigeben + // Release old vertex list delete[] OldVertecies; - // Eigenschaften des Polygons berechnen. + // Calculate properties of the polygon m_IsCW = ComputeIsCW(); m_IsConvex = ComputeIsConvex(); m_Centroid = ComputeCentroid(); @@ -116,52 +105,44 @@ bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies) return true; } -// Überprüfung der Reihenfolge der Vertecies -// ----------------------------------------- +// Review the order of the Vertecies +// --------------------------------- -bool BS_Polygon::IsCW() const -{ +bool BS_Polygon::IsCW() const { return m_IsCW; } -bool BS_Polygon::IsCCW() const -{ +bool BS_Polygon::IsCCW() const { return !IsCW(); } -bool BS_Polygon::ComputeIsCW() const -{ - if (VertexCount) - { - // Vertex finden, dass am weitesten rechts unten liegt. +bool BS_Polygon::ComputeIsCW() const { + if (VertexCount) { + // Find the vertex on extreme bottom right int V2Index = FindLRVertexIndex(); - // Vertex vorher und nachher finden. + // Find the vertex before and after it int V1Index = (V2Index + (VertexCount - 1)) % VertexCount; int V3Index = (V2Index + 1) % VertexCount; - // Kreuzprodukt bilden. - // Wenn das Kreuzprodukt des am weitesten unten links liegenden Vertex positiv ist, sind die Vertecies im Uhrzeigersinn angeordnet - // ansonsten entgegen des Uhrzeigersinns. + // Cross product form + // If the cross product of the vertex lying fartherest bottom left is positive, + // the vertecies arrranged in a clockwise order. Otherwise counter-clockwise if (CrossProduct(Vertecies[V1Index], Vertecies[V2Index], Vertecies[V3Index]) >= 0) return true; } return false; } -int BS_Polygon::FindLRVertexIndex() const -{ - if (VertexCount) - { +int BS_Polygon::FindLRVertexIndex() const { + if (VertexCount) { int CurIndex = 0; int MaxX = Vertecies[0].X; int MaxY = Vertecies[0].Y; - for (int i = 1; i < VertexCount; i++) - { + for (int i = 1; i < VertexCount; i++) { if (Vertecies[i].Y > MaxY || - (Vertecies[i].Y == MaxY && Vertecies[i].X > MaxX)) - { + (Vertecies[i].Y == MaxY && Vertecies[i].X > MaxX)) { MaxX = Vertecies[i].X; MaxY = Vertecies[i].Y; CurIndex = i; @@ -174,109 +155,101 @@ int BS_Polygon::FindLRVertexIndex() const return -1; } -// Testen auf Konvex/Konkav +// Testing for Convex / Concave // ------------------------ -bool BS_Polygon::IsConvex() const -{ +bool BS_Polygon::IsConvex() const { return m_IsConvex; } -bool BS_Polygon::IsConcave() const -{ +bool BS_Polygon::IsConcave() const { return !IsConvex(); } -bool BS_Polygon::ComputeIsConvex() const -{ - // Polygone mit 3 oder weniger Vertecies können nur Konvex sein. +bool BS_Polygon::ComputeIsConvex() const { + // Polygons with three or less Vertecies can only be convex if (VertexCount <= 3) return true; - // Alle Winkel im Polygon berechnen, wenn das Polygon Konvex ist, müssen alle Winkel das selbe Vorzeichen haben. + // All angles in the polygon computed will have the same direction sign if the polygon is convex int Flag = 0; - for (int i = 0; i < VertexCount; i++) - { - // Die Indizies der beiden nächsten Vertecies nach i bestimmen. + for (int i = 0; i < VertexCount; i++) { + // Determine the next two vertecies to check int j = (i + 1) % VertexCount; int k = (i + 2) % VertexCount; - // Kreuzprodukt der drei Vertecies berechnen. + // Calculate the cross product of the three vertecies int Cross = CrossProduct(Vertecies[i], Vertecies[j], Vertecies[k]); - // Die unteren beiden Bits von Flag haben folgende Bedeutung: - // 0 : negativer Winkel ist aufgetreten - // 1 : positiver Winkel ist aufgetreten + // The lower two bits of the flag represent the following: + // 0: negative angle occurred + // 1: positive angle occurred - // Vorzeichen des aktuellen Winkels in Flag vermerken. + // The sign of the current angle is recorded in Flag if (Cross < 0) Flag |= 1; else if (Cross > 0) Flag |= 2; - // Falls Flag 3 ist, sind sowohl positive als auch negative Winkel vorhanden -> Polygon ist Konkav. + // If flag is 3, there are both positive and negative angles; so the polygon is concave if (Flag == 3) return false; } - // Polygon ist Konvex. + // Polygon is convex return true; } -// Sicherstellen einer bestimmen Vertexordnung -// ------------------------------------------- +// Make a determine vertex order +// ----------------------------- -void BS_Polygon::EnsureCWOrder() -{ +void BS_Polygon::EnsureCWOrder() { if (!IsCW()) ReverseVertexOrder(); } -void BS_Polygon::EnsureCCWOrder() -{ +void BS_Polygon::EnsureCCWOrder() { if (!IsCCW()) ReverseVertexOrder(); } -// Umkehren der Reihenfolge der Vertecies -// -------------------------------------- +// Reverse the order of vertecies +// ------------------------------ -void BS_Polygon::ReverseVertexOrder() -{ - // Vertecies paarweise vertauschen, bis die Liste komplett umgekehrt wurde. - for (int i = 0; i < VertexCount / 2; i++) - std::swap(Vertecies[i], Vertecies[VertexCount - i - 1]); +void BS_Polygon::ReverseVertexOrder() { + // Vertecies are exchanged in pairs, until the list has been completely reversed + for (int i = 0; i < VertexCount / 2; i++) { + BS_Vertex tempVertex = Vertecies[i]; + Vertecies[i] = Vertecies[VertexCount - i - 1]; + Vertecies[VertexCount - i - 1] = tempVertex; + } // Vertexordnung neu berechnen. m_IsCW = ComputeIsCW(); } -// Kreuzprodukt -// ------------ +// Cross Product +// ------------- -int BS_Polygon::CrossProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const -{ +int BS_Polygon::CrossProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const { return (V2.X - V1.X) * (V3.Y - V2.Y) - (V2.Y - V1.Y) * (V3.X - V2.X); } -// Skalarproduct -// ------------- +// Scalar Product +// -------------- -int BS_Polygon::DotProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const -{ +int BS_Polygon::DotProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const { return (V1.X - V2.X) * (V3.X - V2.X) + (V1.Y - V2.Y) * (V3.X - V2.Y); } -// Überprüfen auf Selbstüberschneidung -// ----------------------------------- +// Check for self-intersections +// ---------------------------- -bool BS_Polygon::CheckForSelfIntersection() const -{ - // TODO: Fertigstellen +bool BS_Polygon::CheckForSelfIntersection() const { + // TODO: Finish this /* float AngleSum = 0.0f; - for (int i = 0; i < VertexCount; i++) - { + for (int i = 0; i < VertexCount; i++) { int j = (i + 1) % VertexCount; int k = (i + 2) % VertexCount; @@ -289,8 +262,7 @@ bool BS_Polygon::CheckForSelfIntersection() const (Vertecies[k].Y - Vertecies[j].Y) * (Vertecies[k].Y - Vertecies[j].Y)); float Norm = Length1 * Length2; - if (Norm > 0.0f) - { + if (Norm > 0.0f) { Dot /= Norm; AngleSum += acos(Dot); } @@ -300,46 +272,43 @@ bool BS_Polygon::CheckForSelfIntersection() const return false; } -// Verschieben -// ----------- +// Move +// ---- -void BS_Polygon::operator+=(const BS_Vertex& Delta) -{ - // Alle Vetecies verschieben +void BS_Polygon::operator+=(const BS_Vertex &Delta) { + // Move all vertecies for (int i = 0; i < VertexCount; i++) Vertecies[i] += Delta; - // Den Schwerpunkt verschieben. + // Shift the focus m_Centroid += Delta; } -// Sichtlinie -// ---------- +// Line of Sight +// ------------- -bool BS_Polygon::IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const -{ - // Beide Punkte müssen im Polygon sein +bool BS_Polygon::IsLineInterior(const BS_Vertex &a, const BS_Vertex &b) const { + // Both points have to be in the polygon if (!IsPointInPolygon(a, true) || !IsPointInPolygon(b, true)) return false; - // Falls die Punkte identisch sind, ist die Linie trivialerweise innerhalb des Polygons + // If the points are identical, the line is trivially within the polygon if (a == b) return true; - // Testen, ob die Linie ein Liniensegment strikt schneidet (proper intersection) - for (int i = 0; i < VertexCount; i++) - { + // Test whether the line intersects a line segment strictly (proper intersection) + for (int i = 0; i < VertexCount; i++) { int j = (i + 1) % VertexCount; - const BS_Vertex & VS = Vertecies[i]; - const BS_Vertex & VE = Vertecies[j]; + const BS_Vertex &VS = Vertecies[i]; + const BS_Vertex &VE = Vertecies[j]; - // Falls die Linie ein Liniensegment strikt schneidet (proper intersection) ist die Linie nicht innerhalb des Polygons + // If the line intersects a line segment strictly (proper cross section) the line is not in the polygon if (BS_Line::DoesIntersectProperly(a, b, VS, VE)) return false; - // Falls einer der beiden Linienpunkte auf der Kante liegt und der andere rechts der Kante liegt, befindet sich die Linie nicht - // vollständig innerhalb des Polygons. + // If one of the two line items is on the edge and the other is to the right of the edge, + // then the line is not completely within the polygon if (BS_Line::IsOnLineStrict(VS, VE, a) && BS_Line::IsVertexRight(VS, VE, b)) return false; if (BS_Line::IsOnLineStrict(VS, VE, b) && BS_Line::IsVertexRight(VS, VE, a)) return false; - // Falls einer der beiden Linienpunkte auf einem Vertex liegt muss die Linie in das Polygon hinein verlaufen + // If one of the two line items is on a vertex, the line traces into the polygon if ((a == VS) && !IsLineInCone(i, b, true)) return false; if ((b == VS) && !IsLineInCone(i, a, true)) return false; } @@ -347,37 +316,34 @@ bool BS_Polygon::IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const return true; } -bool BS_Polygon::IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const -{ - // Keiner der beiden Punkte darf strikt im Polygon sein (auf der Kante ist erlaubt) +bool BS_Polygon::IsLineExterior(const BS_Vertex &a, const BS_Vertex &b) const { + // Neither of the two points must be strictly in the polygon (on the edge is allowed) if (IsPointInPolygon(a, false) || IsPointInPolygon(b, false)) return false; - // Falls die Punkte identisch sind, ist die Linie trivialerweise ausserhalb des Polygons + // If the points are identical, the line is trivially outside of the polygon if (a == b) return true; - // Testen, ob die Linie ein Liniensegment strikt schneidet (proper intersection) - for (int i = 0; i < VertexCount; i++) - { + // Test whether the line intersects a line segment strictly (proper intersection) + for (int i = 0; i < VertexCount; i++) { int j = (i + 1) % VertexCount; - const BS_Vertex & VS = Vertecies[i]; - const BS_Vertex & VE = Vertecies[j]; + const BS_Vertex &VS = Vertecies[i]; + const BS_Vertex &VE = Vertecies[j]; - // Falls die Linie ein Liniensegment strikt schneidet (proper intersection) ist die Linie teilweise innerhalb des Polygons + // If the line intersects a line segment strictly (proper intersection), then + // the line is partially inside the polygon if (BS_Line::DoesIntersectProperly(a, b, VS, VE)) return false; - // Falls einer der beiden Linienpunkte auf der Kante liegt und der andere rechts der Kante liegt, befindet sich die Linie nicht vollständig - // ausserhalb des Polygons. + // If one of the two line items is on the edge and the other is to the right of the edge, + // the line is not completely outside the polygon if (BS_Line::IsOnLineStrict(VS, VE, a) && BS_Line::IsVertexLeft(VS, VE, b)) return false; if (BS_Line::IsOnLineStrict(VS, VE, b) && BS_Line::IsVertexLeft(VS, VE, a)) return false; - // Falls einer der beiden Linienpunkte auf einem Vertex liegt, darf die Linie nicht in das Polygon hinein verlaufen + // If one of the lwo line items is on a vertex, the line must not run into the polygon if ((a == VS) && IsLineInCone(i, b, false)) return false; if ((b == VS) && IsLineInCone(i, a, false)) return false; - // Falls das Vertex mit Start- und Zielpunkt kollinear ist, dürfen die beiden Liniensegmente (a, VS) und (b, VS) nicht in das Polygon hinein - // verlaufen - if (BS_Line::IsOnLine(a, b, VS)) - { + // If the vertex with start and end point is collinear, (a VS) and (b, VS) is not in the polygon + if (BS_Line::IsOnLine(a, b, VS)) { if (IsLineInCone(i, a, false)) return false; if (IsLineInCone(i, b, false)) return false; } @@ -386,23 +352,19 @@ bool BS_Polygon::IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const return true; } -bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex, bool IncludeEdges) const -{ - const BS_Vertex & StartVertex = Vertecies[StartVertexIndex]; - const BS_Vertex & NextVertex = Vertecies[(StartVertexIndex + 1) % VertexCount]; - const BS_Vertex & PrevVertex = Vertecies[(StartVertexIndex + VertexCount - 1) % VertexCount]; +bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex &EndVertex, bool IncludeEdges) const { + const BS_Vertex &StartVertex = Vertecies[StartVertexIndex]; + const BS_Vertex &NextVertex = Vertecies[(StartVertexIndex + 1) % VertexCount]; + const BS_Vertex &PrevVertex = Vertecies[(StartVertexIndex + VertexCount - 1) % VertexCount]; - if (BS_Line::IsVertexLeftOn(PrevVertex, StartVertex, NextVertex)) - { + if (BS_Line::IsVertexLeftOn(PrevVertex, StartVertex, NextVertex)) { if (IncludeEdges) return BS_Line::IsVertexLeftOn(EndVertex, StartVertex, NextVertex) && BS_Line::IsVertexLeftOn(StartVertex, EndVertex, PrevVertex); else return BS_Line::IsVertexLeft(EndVertex, StartVertex, NextVertex) && BS_Line::IsVertexLeft(StartVertex, EndVertex, PrevVertex); - } - else - { + } else { if (IncludeEdges) return !(BS_Line::IsVertexLeft(EndVertex, StartVertex, PrevVertex) && BS_Line::IsVertexLeft(StartVertex, EndVertex, NextVertex)); @@ -412,56 +374,49 @@ bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex, } } -// Punkt-Polygon Tests +// Point-Polygon Tests // ------------------- -bool BS_Polygon::IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon) const -{ +bool BS_Polygon::IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon) const { return IsPointInPolygon(BS_Vertex(X, Y), BorderBelongsToPolygon); } -bool BS_Polygon::IsPointInPolygon(const BS_Vertex & Point, bool EdgesBelongToPolygon) const -{ - int Rcross = 0; // Anzahl der rechtsseitigen Überschneidungen - int Lcross = 0; // Anzahl der linksseitigen Überschneidungen +bool BS_Polygon::IsPointInPolygon(const BS_Vertex &Point, bool EdgesBelongToPolygon) const { + int Rcross = 0; // Number of right-side overlaps + int Lcross = 0; // Number of left-side overlaps - // Jede Kante wird überprüft ob sie den vom Punkt ausgehenden Strahl schneidet - for (int i = 0; i < VertexCount; i++) - { - const BS_Vertex & EdgeStart = Vertecies[i]; - const BS_Vertex & EdgeEnd = Vertecies[(i + 1) % VertexCount]; + // Each edge is checked whether it cuts the outgoing stream from the point + for (int i = 0; i < VertexCount; i++) { + const BS_Vertex &EdgeStart = Vertecies[i]; + const BS_Vertex &EdgeEnd = Vertecies[(i + 1) % VertexCount]; - // Ist der Punkt ein Vertex? Dann liegt er auf einer Kante des Polygons + // A vertex is a point? Then it lies on one edge of the polygon if (Point == EdgeStart) return EdgesBelongToPolygon; - if ((EdgeStart.Y > Point.Y) != (EdgeEnd.Y > Point.Y)) - { + if ((EdgeStart.Y > Point.Y) != (EdgeEnd.Y > Point.Y)) { int Term1 = (EdgeStart.X - Point.X) * (EdgeEnd.Y - Point.Y) - (EdgeEnd.X - Point.X) * (EdgeStart.Y - Point.Y); int Term2 = (EdgeEnd.Y - Point.Y) - (EdgeStart.Y - EdgeEnd.Y); if ((Term1 > 0) == (Term2 >= 0)) Rcross++; } - if ((EdgeStart.Y < Point.Y) != (EdgeEnd.Y < Point.Y)) - { + if ((EdgeStart.Y < Point.Y) != (EdgeEnd.Y < Point.Y)) { int Term1 = (EdgeStart.X - Point.X) * (EdgeEnd.Y - Point.Y) - (EdgeEnd.X - Point.X) * (EdgeStart.Y - Point.Y); int Term2 = (EdgeEnd.Y - Point.Y) - (EdgeStart.Y - EdgeEnd.Y); if ((Term1 < 0) == (Term2 <= 0)) Lcross++; } } - // Der Punkt befindet sich auf einer Kante, wenn die Anzahl der linken und rechten Überschneidungen nicht die gleiche Geradzahligkeit haben + // The point is on an adge, if the number of left and right intersections have the same even numbers if ((Rcross % 2 ) != (Lcross % 2 )) return EdgesBelongToPolygon; - // Der Punkt befindet sich genau dann strikt innerhalb des Polygons, wenn die Anzahl der Überschneidungen ungerade ist + // The point is strictly inside the polygon if and only if the number of overlaps is odd if ((Rcross % 2) == 1) return true; else return false; } -bool BS_Polygon::Persist(BS_OutputPersistenceBlock & Writer) -{ +bool BS_Polygon::Persist(BS_OutputPersistenceBlock &Writer) { Writer.Write(VertexCount); - for (int i = 0; i < VertexCount; ++i) - { + for (int i = 0; i < VertexCount; ++i) { Writer.Write(Vertecies[i].X); Writer.Write(Vertecies[i].Y); } @@ -469,16 +424,16 @@ bool BS_Polygon::Persist(BS_OutputPersistenceBlock & Writer) return true; } -bool BS_Polygon::Unpersist(BS_InputPersistenceBlock & Reader) -{ +bool BS_Polygon::Unpersist(BS_InputPersistenceBlock &Reader) { int StoredVertexCount; Reader.Read(StoredVertexCount); - std::vector<BS_Vertex> StoredVertecies(StoredVertexCount); - for (int i = 0; i < StoredVertexCount; ++i) - { - Reader.Read(StoredVertecies[i].X); - Reader.Read(StoredVertecies[i].Y); + Common::Array<BS_Vertex> StoredVertecies; + for (int i = 0; i < StoredVertexCount; ++i) { + int x, y; + Reader.Read(x); + Reader.Read(y); + StoredVertecies.push_back(BS_Vertex(x, y)); } Init(StoredVertexCount, &StoredVertecies[0]); @@ -486,30 +441,26 @@ bool BS_Polygon::Unpersist(BS_InputPersistenceBlock & Reader) return Reader.IsGood(); } -// Schwerpunkt -// ----------- +// Main Focus +// ---------- -BS_Vertex BS_Polygon::GetCentroid() const -{ +BS_Vertex BS_Polygon::GetCentroid() const { return m_Centroid; } -BS_Vertex BS_Polygon::ComputeCentroid() const -{ - // Flächeninhalt des Polygons berechnen. +BS_Vertex BS_Polygon::ComputeCentroid() const { + // Area of the polygon is calculated int DoubleArea = 0; - for (int i = 0; i < VertexCount; ++i) - { + for (int i = 0; i < VertexCount; ++i) { DoubleArea += Vertecies[i].X * Vertecies[i + 1].Y - Vertecies[i + 1].X * Vertecies[i].Y; } - // Division durch 0 beim nächsten Schritt vermeiden. + // Avoid division by zero in the next step if (DoubleArea == 0) return BS_Vertex(); - // Schwerpunkt berechnen. + // Calculate centroid BS_Vertex Centroid; - for (int i = 0; i < VertexCount; ++i) - { + for (int i = 0; i < VertexCount; ++i) { int Area = Vertecies[i].X * Vertecies[i + 1].Y - Vertecies[i + 1].X * Vertecies[i].Y; Centroid.X += (Vertecies[i].X + Vertecies[i + 1].X) * Area; Centroid.Y += (Vertecies[i].Y + Vertecies[i + 1].Y) * Area; @@ -519,3 +470,5 @@ BS_Vertex BS_Polygon::ComputeCentroid() const return Centroid; } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/polygon.h b/engines/sword25/math/polygon.h index 73de386917..d435c9746b 100644 --- a/engines/sword25/math/polygon.h +++ b/engines/sword25/math/polygon.h @@ -40,6 +40,8 @@ #include "sword25/kernel/persistable.h" #include "sword25/math/vertex.h" +namespace Sword25 { + // ----------------------------------------------------------------------------- // Forward Declarations // ----------------------------------------------------------------------------- @@ -49,158 +51,151 @@ class BS_Vertex; /** @brief Eine Polygonklasse. */ -class BS_Polygon : public BS_Persistable -{ +class BS_Polygon : public BS_Persistable { public: /** - @brief Erzeugt ein Objekt vom Typ #BS_Polygon, das 0 Vertecies enthält. - - Mit der Methode Init() können dem Polygon später Vertecies hinzugefügt werden. - */ + * Creates an object of type #BS_Polygon, containing 0 Vertecies. + * + * With the method Init(), Vertices can be added in later + */ BS_Polygon(); /** - @brief Copy-Constructor - */ - BS_Polygon(const BS_Polygon& Other); + * Copy constructor + */ + BS_Polygon(const BS_Polygon &Other); /** - @brief Erstellt ein Polygon anhand persistierter Daten. - */ - BS_Polygon(BS_InputPersistenceBlock & Reader); + * Creates a polygon using persisted data + */ + BS_Polygon(BS_InputPersistenceBlock &Reader); /** - @brief Erzeugt ein Objekt vom Typ #BS_Polygon und ordnet ihm Vertecies zu. - @param VertexCount die Anzahl der Vertecies im Vertex Array. - @param Vertecies ein Array, das Objekte vom Typ BS_Vertex enthält, die die Vertecies des Polygons darstellen. - @remark Die Vertecies müssen ein nicht selbstüberschneidendes Polygon definieren. - Falls das Polygon selbstüberschneidend sein sollte wird ein leeres BS_Polygon Objekt erzeugt. - */ - BS_Polygon(int VertexCount, const BS_Vertex* Vertecies); + * Creaes an object of type #BS_Polygon, and assigns Vertices to it + * @param VertexCount The number of vertices being passed + * @param Vertecies An array of BS_Vertex objects representing the vertices in the polygon. + * @remark The Vertecies that define a polygon must not have any self-intersections. + * If the polygon does have self-intersections, then an empty polygon object is created. + */ + BS_Polygon(int VertexCount, const BS_Vertex *Vertecies); /** - @brief Löscht das BS_Polygon Objekt. - */ + * Deletes the BS_Polygon object + */ virtual ~BS_Polygon(); /** - @brief Initialisiert das BS_Polygon mit einer Liste von Vertecies. - - Die Vertecies müssen ein nicht selbstüberschneidendes Polygon definieren. - Es kann auch einem Polygon, welches bereits Vertecies enthält, mit einer neue Vertexliste initialisiert werden, dabei gehen die - alten Vertecies verloren. - - @param VertexCount die Anzahl der Vertecies im Vertecies Array. - @param Vertecies ein Array, das Objekte vom Typ BS_Vertex enthält, die die Vertecies des Polygons darstellen. - @return Gibt false zurück, falls die Vertecies ein selbstüberschneidendes Polygon definiert haben. - In diesem Fall wird das Objekt nicht initialisiert. - */ - bool Init(int VertexCount, const BS_Vertex* Vertecies); - - //@{ - /** @name Sondierende Methoden */ + * Initialises the BS_Polygon with a list of Vertecies. + * + * The Vertices need to define a polygon must not have self-intersections. + * If a polygon already has verticies, this will re-initialise it with the new list. + * + * @param VertexCount The number of vertices being passed + * @param Vertecies An array of BS_Vertex objects representing the vertices in the polygon. + * @return Returns false if the Vertecies have self-intersections. In this case, + * the object is not initialised. + */ + bool Init(int VertexCount, const BS_Vertex *Vertecies); + + // + // ** Exploratory methods ** + // /** - @brief Überprüft, ob die Vertecies des Polygons im Uhrzeigersinn angeordnet sind. - @return Gibt true zurück, wenn die Vertecies des Polygons im Uhrzeigersinn angeordnet sind oder Koplanar sind.<br> - Gibt false zurück, wenn die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind. - @remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat. - */ + * Checks whether the Vertecies of the polygon are arranged in a clockwise direction. + * @return Returns true if the Vertecies of the polygon are arranged clockwise or co-planar. + * Returns false if the Vertecies of the polygon are arrange counter-clockwise. + * @remark This method only returns a meaningful result if the polygon has at least three Vertecies. + */ bool IsCW() const; /** - @brief Überprüft, ob die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind. - @return Gibt true zurück, wenn die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind.<br> - Gibt false zurück, wenn die Vertecies des Polygons im Uhrzeigersinn angeordnet sind oder Koplanar sind. - @remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat. - - */ + * Checks whether the Vertices of the polygon are arranged in a counter-clockwise direction. + * @return Returns true if the Vertecies of the polygon are arranged counter-clockwise. + * Returns false if the Vertecies of the polygon are arranged clockwise or co-planar. + * @remark This method only returns a meaningful result if the polygon has at least three Vertecies. + */ bool IsCCW() const; /** - @brief Überprüft, ob das Polygon konvex ist. - @return Gibt true zurück, wenn das Polygon konvex ist.<br> - Gibt false zurück, wenn das Polygon konkav ist. - @remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat. - */ + * Checks whether the polygon is convex. + * @return Returns true if the polygon is convex. Returns false if the polygon is concave. + * @remark This method only returns a meaningful result if the polygon has at least three Vertecies. + */ bool IsConvex() const; /** - @brief Überprüft, ob das Polygon konkav ist. - @return Gibt true zurück, wenn das Polygon konkav ist.<br> - Gibt false zurück, wenn das Polygon konvex ist. - @remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat. - */ + * Checks whether the polygon is concave. + * @return Returns true if the polygon is concave. Returns false if the polygon is convex. + * @remark This method only returns a meaningful result if the polygon has at least three Vertecies. + */ bool IsConcave() const; /** - @brief Überprüft, ob sich ein Punkt innerhalb des Polygons befindet. - @param Vertex ein Vertex, mit den Koordinaten des zu testenden Punktes. - @param BorderBelongsToPolygon gibt an, ob der Rand des Polygons als Teil des Polygons betrachtet werden soll.<br> - Der Standardwert ist true. - @return Gibt true zurück, wenn sich der Punkt innerhalb des Polygons befindet.<br> - Gibt false zurück, wenn sich der Punkt außerhalb des Polygons befindet. - */ - bool IsPointInPolygon(const BS_Vertex& Vertex, bool BorderBelongsToPolygon = true) const; + * Checks whether a point is inside the polygon + * @param Vertex A Vertex with the co-ordinates of the point to be tested. + * @param BorderBelongsToPolygon Specifies whether the edge of the polygon should be considered + * @return Returns true if the point is inside the polygon, false if it is outside. + */ + bool IsPointInPolygon(const BS_Vertex &Vertex, bool BorderBelongsToPolygon = true) const; /** - @brief Überprüft, ob sich ein Punkt innerhalb des Polygons befindet. - @param X die Position des Punktes auf der X-Achse. - @param Y die Position des Punktes auf der Y-Achse. - @param BorderBelongsToPolygon gibt an, ob der Rand des Polygons als Teil des Polygons betrachtet werden soll.<br> - Der Standardwert ist true. - @return Gibt true zurück, wenn sich der Punkt innerhalb des Polygons befindet.<br> - Gibt false zurück, wenn sich der Punkt außerhalb des Polygons befindet. - */ + * Checks whether a point is inside the polygon + * @param X The X position of the point + * @param Y The Y position of the point + * @param BorderBelongsToPolygon Specifies whether the edge of the polygon should be considered + * @return Returns true if the point is inside the polygon, false if it is outside. + */ bool IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon = true) const; /** - @brief Gibt den Schwerpunkt des Polygons zurück. - */ + * Returns the focus/centroid of the polygon + */ BS_Vertex GetCentroid() const; - // Rand gehört zum Polygon - // Polygon muss CW sein - bool IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const; - // Rand gehört nicht zum Polygon - // Polygon muss CW sein - bool IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const; - - //@} + // Edge belongs to the polygon + // Polygon must be CW + bool IsLineInterior(const BS_Vertex &a, const BS_Vertex &b) const; + // Edge does not belong to the polygon + // Polygon must be CW + bool IsLineExterior(const BS_Vertex &a, const BS_Vertex &b) const; - //@{ - /** @name Manipulierende Methoden */ + // + // Manipulation methods + // /** - @brief Stellt sicher, dass die Vertecies des Polygons im Uhrzeigersinn angeordnet sind. - */ + * Ensures that the Vertecies of the polygon are arranged in a clockwise direction + */ void EnsureCWOrder(); /** - @brief Stellt sicher, dass die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind. - */ + * Ensures that the Vertecies of the polygon are arranged in a counter-clockwise direction + */ void EnsureCCWOrder(); /** - @brief Kehrt die Reihenfolge der Vertecies um. - */ + * Reverses the Vertecies order. + */ void ReverseVertexOrder(); /** - @brief Verschiebt das Polygon. - @param Delta das Vertex um das das Polygon verschoben werden soll. - */ - void operator+=(const BS_Vertex& Delta); + * Moves the polygon. + * @param Delta The vertex around the polygon to be moved. + */ + void operator+=(const BS_Vertex &Delta); - //@} + // + //------------------ + // - /// Gibt die Anzahl an Vertecies im Vertecies-Array an. + /// Specifies the number of Vertecies in the Vertecies array. int VertexCount; - /// Enthält die Vertecies des Polygons. - BS_Vertex* Vertecies; + /// COntains the Vertecies of the polygon + BS_Vertex *Vertecies; - virtual bool Persist(BS_OutputPersistenceBlock & Writer); - virtual bool Unpersist(BS_InputPersistenceBlock & Reader); + virtual bool Persist(BS_OutputPersistenceBlock &Writer); + virtual bool Unpersist(BS_InputPersistenceBlock &Reader); private: bool m_IsCW; @@ -208,60 +203,64 @@ private: BS_Vertex m_Centroid; /** - @brief Berechnet den Schwerpunkt des Polygons. - */ + * Computes the centroid of the polygon. + */ BS_Vertex ComputeCentroid() const; /** - @brief Bestimmt wie die Vertecies des Polygon angeordnet sind. - @return Gibt true zurück, wenn die Vertecies im Uhrzeigersinn angeordnet sind, ansonsten false. - */ + * Determines how the Vertecies of the polygon are arranged. + * @return Returns true if the Vertecies are arranged in a clockwise + * direction, otherwise false. + */ bool ComputeIsCW() const; /** - @brief Bestimmt ob das Polygon Konvex oder Konkav ist. - @return Gibt true zurück, wenn das Polygon Konvex ist, ansonsten false. - */ + * Determines whether the polygon is convex or concave. + * @return Returns true if the polygon is convex, otherwise false. + */ bool ComputeIsConvex() const; /** - @brief Berechnet das Kreuzprodukt dreier Vertecies. - @param V1 das erste Vertex - @param V2 des zweite Vertex - @param V3 das dritte Vertex - @return Gibt das Kreuzprodukt der drei Vertecies zurück. - @todo Diese Methode sollte an geeigneter Stelle in die BS_Vertex Klasse integriert werden. - */ - int CrossProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const; + * Calculates the cross product of three Vertecies + * @param V1 The first Vertex + * @param V2 The second Vertex + * @param V3 The third Vertex + * @return Returns the cross-product of the three vertecies + * @todo This method would be better as a method of the BS_Vertex class + */ + int CrossProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const; /** - @brief Berechnet des Skalarprodukt der beiden von drei Vertecies aufgespannten Vektoren. - - Die Vektoren werden von V2 -> V1 und V2 -> V3 aufgespannt. - - @param V1 das erste Vertex - @param V2 des zweite Vertex - @param V3 das dritte Vertex - @return Gibt das Skalarprodukt der drei Vertecies zurück. - @todo Diese Methode sollte an geeigneter Stelle in die BS_Vertex Klasse integriert werden. - */ - int DotProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const; + * Computes the scalar product of two vectors spanning three vertecies + * + * The vectors are spanned by V2->V1 and V2->V3 + * + * @param V1 The first Vertex + * @param V2 The second Vertex + * @param V3 The third Vertex + * @return Returns the dot product of the three Vertecies. + * @todo This method would be better as a method of the BS_Vertex class + */ + int DotProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const; /** - @brief Überprüft ob das Polygon selbstüberschneidend ist. - @return Gibt true zurück, wenn das Polygon selbstüberschneidend ist.<br> - Gibt false zurück, wenn das Polygon nicht selbstüberschneidend ist. - */ + * Checks whether the polygon is self-intersecting + * @return Returns true if the polygon is self-intersecting. + * Returns false if the polygon is not self-intersecting. + */ bool CheckForSelfIntersection() const; /** - @brief Findet das Vertex des Polygons das am weitesten rechts unten liegt und gibt dessen Index im Vertex-Array zurück. - @return Gibt den Index des Vertex zurück das am weiteesten rechts unten liegt.<br> - Gibt -1 zurück, wenn die Vertexliste leer ist. - */ + * Find the vertex of the polygon that is located below the right-most point, + * and returns it's index in the vertex array. + * @return Returns the index of the vertex at the bottom-right of the polygon. + * Returns -1 if the vertex list is empty. + */ int FindLRVertexIndex() const; - bool IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex, bool IncludeEdges) const; + bool IsLineInCone(int StartVertexIndex, const BS_Vertex &EndVertex, bool IncludeEdges) const; }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/rect.h b/engines/sword25/math/rect.h index a39c4de25f..849839aeec 100644 --- a/engines/sword25/math/rect.h +++ b/engines/sword25/math/rect.h @@ -36,278 +36,57 @@ #define SWORD25_RECT_H // Includes +#include "common/rect.h" #include "sword25/kernel/common.h" #include "sword25/math/vertex.h" -// Klassendefinition +namespace Sword25 { + +// Class definitions + /** - @brief Diese Klasse beschreibt ein Rechteck und einige nützliche Operationen auf Rechtecken. + * Rect class. Currently this encapsultes the ScummVM Rect class. Eventually all usage of this + * class should be replaced with Common::Rect directly. */ -class BS_Rect -{ +class BS_Rect: public Common::Rect { public: - /// Das linke Extrem des Rechteckes. - int left; - /// Das obere Extrem des Rechteckes. - int top; - /// Das rechte Extrem des Rechteckes + 1. - int right; - /// Das untere Extrem des Rechteckes + 1. - int bottom; + BS_Rect() : Common::Rect() {} + BS_Rect(int16 w, int16 h) : Common::Rect(w, h) {} + BS_Rect(int16 x1, int16 y1, int16 x2, int16 y2) : Common::Rect(x1, y1, x2, y2) {} - /** - @brief Konstruktor, der alle Werte des Rechteckes mit 0 initialisiert. - */ - BS_Rect() - { - left = 0; - top = 0; - right = 0; - bottom = 0; - } - /** - @brief Konstruktor, der das Rechteck mit den übergebenen Werten initialisiert. - @param left das linke Extrem des Rechteckes - @param top das obere Extrem des Rechteckes - @param right das rechte Extrem des Rechteckes + 1 - @param bottom des untere Extrem des Rechteckes + 1 - */ - BS_Rect(int left_, int top_, int right_, int bottom_) - { - this->left = left_; - this->top = top_; - this->right = right_; - this->bottom = bottom_; - } - /** - @brief Verschiebt das Rechteck. - @param DeltaX der Wert um den das Rechteck auf der X-Achse verschoben werden soll. - @param DeltaY der Wert um den das Rechteck auf der Y-Achse verschoben werden soll. - */ - void Move(int DeltaX, int DeltaY) - { - left += DeltaX; - right += DeltaX; - top += DeltaY; - bottom += DeltaY; - } - /** - @brief Testet ob sich zwei Rechtecke schneiden. - @return Gibt true zurück, wenn sich die Rechtecke schneiden. - */ - bool DoesIntersect(const BS_Rect& Rect) const - { - int Dist; - - // Intersektion auf der X-Achse - Dist = left - Rect.left; - if (Dist < 0) - { - Dist = abs(Dist); - - // Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht - if (Dist >= GetWidth()) - return false; - } - else - { - // Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht - if (Dist >= Rect.right - Rect.left) - return false; - } - - // Intersektion auf der Y-Achse - Dist = top - Rect.top; - if (Dist < 0) - { - Dist = abs(Dist); - - // Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht - if (Dist >= GetHeight()) - return false; - } - else - { - // Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht - if (Dist >= Rect.bottom - Rect.top) - return false; - } - - return true; - } + void Move(int DeltaX, int DeltaY) { translate(DeltaX, DeltaY); } - /** - @brief Bildet den Durchschnitt zweier Rechtecke - @param Rect das Rechteck, dass mit dem Objekt geschnitter werden soll. - @param Result das Rechteck, dass das Ergebnisrechteck enthalten soll. - @return Gibt false zurück, falls Result undefiniert ist.<br> - Dies ist der Fall, wenn sich die Rechtecke nicht schneiden. - */ - bool Intersect(const BS_Rect& Rect, BS_Rect& Result) const - { - int Dist; - - // Intersektion auf der X-Achse - Dist = left - Rect.left; - if (Dist < 0) - { - Dist = abs(Dist); - - // Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht - if (Dist >= GetWidth()) - { - Result = BS_Rect(0, 0, 0, 0); - return false; - } - - // Die Abmessungen des Rect auf der X-Achse berechnen - Result.left = Rect.left; - } - else - { - // Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht - if (Dist >= Rect.right - Rect.left) - { - Result = BS_Rect(0, 0, 0, 0); - return false; - } - - // Die Abmessungen des Rect auf der X-Achse berechnen - Result.left = left; - } - Result.right = right < Rect.right ? right : Rect.right; - - // Intersektion auf der Y-Achse - Dist = top - Rect.top; - if (Dist < 0) - { - Dist = abs(Dist); - - // Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht - if (Dist >= GetHeight()) - { - Result = BS_Rect(0, 0, 0, 0); - return false; - } - - // Die Abmessungen des Rect auf der Y-Achse berechnen - Result.top = Rect.top; - } - else - { - // Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht - if (Dist >= Rect.bottom - Rect.top) - { - Result = BS_Rect(0, 0, 0, 0); - return false; - } - - // Die Abmessungen des Rect auf der Y-Achse berechnen - Result.top = top; - } - Result.bottom = bottom < Rect.bottom ? bottom : Rect.bottom; - - return true; - } - /** - @brief Bildet die Bounding-Box zweier Rechtecke. - @param Rect das Rechteck, dass mit dem Objekt verbunden werden soll. - @remark Das Ergebnis ist nicht ein Join in eigentlichen Sinne, sondern vielmehr die Bounding-Box um die Beiden - Rechtecke. - */ - void Join(const BS_Rect& Rect, BS_Rect& Result) const - { - Result.left = left < Rect.left ? left : Rect.left; - Result.top = top < Rect.top ? top : Rect.top; - Result.right = right > Rect.right ? right : Rect.right; - Result.bottom = bottom > Rect.bottom ? bottom : Rect.bottom; - return; - } - /** - @brief Gibt die Breite des Rechteckes zurück. - @return Die Breite des Rechteckes. - */ - int GetWidth() const - { - return right - left; - } - /** - @brief Gibt die Höhe des Rechteckes zurück. - @return Die Höhe des Rechteckes. - */ - int GetHeight() const - { - return bottom - top; - } - /** @brief Gibt den Flächeninhalt des Rechteckes zurück. - @return Der Flächeninhalt des Rechteckes. - */ - int GetArea() const - { - return GetWidth() * GetHeight(); - } - /** - @brief Vergleichsoperator zum Überprüfen der Gleichheit zweier BS_Rect Objekte. - @return Gibt true zurück, wenn die Objekte die gleichen Werte haben, ansonsten false. - */ - bool operator== (const BS_Rect& rhs) - { - return (left == rhs.left) && - (top == rhs.top) && - (right == rhs.right) && - (bottom == rhs.bottom); - } - /** - @brief Vergleichsoperator zum Überprüfen der Ungleichheit zweier BS_Rect Objekte. - @return Gibt true zurück, wenn die Objekte ungleiche Werte haben, ansonsten false. - */ - bool operator!= (const BS_Rect& rhs) - { - return !(*this == rhs); - } - /** - @brief Überprüft, ob das Objekt einen gültigen Zustand hat. - @return Gibt false zurück, wenn das Objekt einen ungültigen Zustand hat. - */ - bool IsValid() const - { - if (left < right && top < bottom) return true; - return false; - } - /** - @brief Testet, ob sich ein Vertex innerhalb des Rechteckes befindet. - @param Vertex das Vertex, dass mit dem Rechteckes getestet werden soll - @return Gibt true zurück, wenn sich das Vertex innerhalb des Rechteckes befindet.<br> - Gibt false zurück, wenn sich das Vertex außerhalb des Rechteckes befindet. - */ - bool IsPointInRect(const BS_Vertex& Vertex) const - { - if (Vertex.X >= left && Vertex.X < right && - Vertex.Y >= top && Vertex.Y < bottom) - return true; - return false; - } - /** - @brief Testet, ob sich ein Punkt innerhalb des Rechteckes befindet. - @param X die Position des Punktes auf der X-Achse. - @param Y die Position des Punktes auf der Y-Achse. - @return Gibt true zurück, wenn sich der Punkt innerhalb des Rechteckes befindet.<br> - Gibt false zurück, wenn sich der Punkt außerhalb des Rechteckes befindet. - */ - bool IsPointInRect(int X, int Y) const - { - return IsPointInRect(BS_Vertex(X, Y)); + bool DoesIntersect(const BS_Rect &Rect) const { return intersects(Rect); } + + bool Intersect(const BS_Rect &Rect, BS_Rect &Result) const { + Result = Rect; + Result.clip(*this); } - /** - @brief Testet, ob ein andere Rechteck komplett in den Rechteck enthalten ist. - @param OtherRect das zu testende Rechteck - @brief Gibt true zurück, wenn sich das andere Rechteck komplett im Rechteck enthalten ist, ansonsten false. - */ - bool ContainsRect(const BS_Rect & OtherRect) const - { - return IsPointInRect(OtherRect.left, OtherRect.top) && - IsPointInRect(OtherRect.right - 1, OtherRect.bottom - 1); + + void Join(const BS_Rect &Rect, BS_Rect &Result) const { + Result = Rect; + Result.extend(*this); } + + int GetWidth() const { return width(); } + + int GetHeight() const { return height(); } + + int GetArea() const { return width() * height(); } + + bool operator==(const BS_Rect &rhs) const { return equals(rhs); } + + bool operator!= (const BS_Rect &rhs) const { return !equals(rhs); } + + bool IsValid() const { return isValidRect(); } + + bool IsPointInRect(const BS_Vertex &Vertex) const { return contains(Vertex.X, Vertex.Y); } + + bool IsPointInRect(int X, int Y) const { return contains(X, Y); } + + bool ContainsRect(const BS_Rect &OtherRect) const { return contains(OtherRect); } }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/region.cpp b/engines/sword25/math/region.cpp index 323164435f..4999a4340e 100644 --- a/engines/sword25/math/region.cpp +++ b/engines/sword25/math/region.cpp @@ -41,29 +41,27 @@ #define BS_LOG_PREFIX "REGION" -// Konstruktion/Destruktion +namespace Sword25 { + +// Constructor / Destructor // ------------------------ -BS_Region::BS_Region() : m_Valid(false), m_Type(RT_REGION) -{ +BS_Region::BS_Region() : m_Valid(false), m_Type(RT_REGION) { BS_RegionRegistry::GetInstance().RegisterObject(this); } // ----------------------------------------------------------------------------- -BS_Region::BS_Region(BS_InputPersistenceBlock & Reader, unsigned int Handle) : m_Valid(false), m_Type(RT_REGION) -{ +BS_Region::BS_Region(BS_InputPersistenceBlock &Reader, unsigned int Handle) : m_Valid(false), m_Type(RT_REGION) { BS_RegionRegistry::GetInstance().RegisterObject(this, Handle); Unpersist(Reader); } // ----------------------------------------------------------------------------- -unsigned int BS_Region::Create(REGION_TYPE Type) -{ +unsigned int BS_Region::Create(REGION_TYPE Type) { BS_Region * RegionPtr; - switch (Type) - { + switch (Type) { case RT_REGION: RegionPtr = new BS_Region(); break; @@ -81,24 +79,18 @@ unsigned int BS_Region::Create(REGION_TYPE Type) // ----------------------------------------------------------------------------- -unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int Handle) -{ - // Typ einlesen. +unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int Handle) { + // Read type unsigned int Type; Reader.Read(Type); - // Je nach Typ ein neues BS_Region oder BS_WalkRegion Objekt erstellen. + // Depending on the type, create a new BS_Region or BS_WalkRegion object BS_Region * RegionPtr; - if (Type == RT_REGION) - { + if (Type == RT_REGION) { RegionPtr = new BS_Region(Reader, Handle); - } - else if (Type == RT_WALKREGION) - { + } else if (Type == RT_WALKREGION) { RegionPtr = new BS_WalkRegion(Reader, Handle); - } - else - { + } else { BS_ASSERT(false); } @@ -107,37 +99,33 @@ unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int H // ----------------------------------------------------------------------------- -BS_Region::~BS_Region() -{ +BS_Region::~BS_Region() { BS_RegionRegistry::GetInstance().DeregisterObject(this); } // ----------------------------------------------------------------------------- -bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* pHoles) -{ - // Objektzustand zurücksetzen. +bool BS_Region::Init(const BS_Polygon& Contour, const Common::Array<BS_Polygon> *pHoles) { + // Reset object state m_Valid = false; m_Position = BS_Vertex(0, 0); m_Polygons.clear(); - // Genügend Platz für Kontur und Löcher im Polygon-Vektor reservieren + // Reserve sufficient space for countour and holes in the polygon list if (pHoles) m_Polygons.reserve(1 + pHoles->size()); else m_Polygons.reserve(1); - // Kontur an die erste Position im Polygon-Vektor kopieren + // The first polygon will be the contour m_Polygons.push_back(BS_Polygon()); m_Polygons[0].Init(Contour.VertexCount, Contour.Vertecies); - // Sicherstellen, dass die Vertecies der Contour im Uhrzeigersinn angeordnet sind. + // Make sure that the Vertecies in the Contour are arranged in a clockwise direction m_Polygons[0].EnsureCWOrder(); - // Übergebene Lochpolygone an die folgenden Positionen im Polygon-Vektor kopieren - if (pHoles) - { - for (unsigned int i = 0; i< pHoles->size(); ++i) - { + // Place the hole polygons in the following positions + if (pHoles) { + for (unsigned int i = 0; i< pHoles->size(); ++i) { m_Polygons.push_back(BS_Polygon()); m_Polygons[i + 1].Init((*pHoles)[i].VertexCount, (*pHoles)[i].Vertecies); m_Polygons[i + 1].EnsureCWOrder(); @@ -145,7 +133,7 @@ bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* p } - // Bounding-Box initialisieren. + // Initialise bounding box UpdateBoundingBox(); m_Valid = true; @@ -154,17 +142,14 @@ bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* p // ----------------------------------------------------------------------------- -void BS_Region::UpdateBoundingBox() -{ - if (m_Polygons[0].VertexCount) - { +void BS_Region::UpdateBoundingBox() { + if (m_Polygons[0].VertexCount) { int MinX = m_Polygons[0].Vertecies[0].X; int MaxX = m_Polygons[0].Vertecies[0].X; int MinY = m_Polygons[0].Vertecies[0].Y; int MaxY = m_Polygons[0].Vertecies[0].Y; - for (int i = 1; i < m_Polygons[0].VertexCount; i++) - { + for (int i = 1; i < m_Polygons[0].VertexCount; i++) { if (m_Polygons[0].Vertecies[i].X < MinX) MinX = m_Polygons[0].Vertecies[i].X; else if (m_Polygons[0].Vertecies[i].X > MaxX) MaxX = m_Polygons[0].Vertecies[i].X; if (m_Polygons[0].Vertecies[i].Y < MinY) MinY = m_Polygons[0].Vertecies[i].Y; @@ -175,55 +160,47 @@ void BS_Region::UpdateBoundingBox() } } -// Positionsänderungen -// ------------------- +// Position Changes +// ---------------- -void BS_Region::SetPos(int X, int Y) -{ - // Unterschied zwischen alter und neuer Position berechnen. +void BS_Region::SetPos(int X, int Y) { + // Calculate the difference between the old and new position BS_Vertex Delta(X - m_Position.X, Y - m_Position.Y); - // Neue Position im internen Zustand merken. + // Save the new position m_Position = BS_Vertex(X, Y); - // Alle Vertecies verschieben. - for (unsigned int i = 0; i < m_Polygons.size(); ++i) - { + // Move all the vertecies + for (unsigned int i = 0; i < m_Polygons.size(); ++i) { m_Polygons[i] += Delta; } - // Bounding-Box aktualisieren + // Update the bounding box UpdateBoundingBox(); } // ----------------------------------------------------------------------------- -void BS_Region::SetPosX(int X) -{ +void BS_Region::SetPosX(int X) { SetPos(X, m_Position.Y); } // ----------------------------------------------------------------------------- -void BS_Region::SetPosY(int Y) -{ +void BS_Region::SetPosY(int Y) { SetPos(m_Position.X, Y); } -// Punkt-Region Tests +// Point-Region Tests // ------------------ -bool BS_Region::IsPointInRegion(int X, int Y) const -{ - // Testen, ob der Punkt in der Bounding-Box ist. - if (m_BoundingBox.IsPointInRect(X, Y)) - { - // Testen, ob der Punkt in der Contour ist. - if (m_Polygons[0].IsPointInPolygon(X, Y, true)) - { - // Testen, ob der Punkt in einem Loch ist. - for (unsigned int i = 1; i < m_Polygons.size(); i++) - { +bool BS_Region::IsPointInRegion(int X, int Y) const { + // Test whether the point is in the bounding box + if (m_BoundingBox.IsPointInRect(X, Y)) { + // Test whether the point is in the contour + if (m_Polygons[0].IsPointInPolygon(X, Y, true)) { + // Test whether the point is in a hole + for (unsigned int i = 1; i < m_Polygons.size(); i++) { if (m_Polygons[i].IsPointInPolygon(X,Y, false)) return false; } @@ -237,22 +214,19 @@ bool BS_Region::IsPointInRegion(int X, int Y) const // ----------------------------------------------------------------------------- -bool BS_Region::IsPointInRegion(const BS_Vertex& Vertex) const -{ +bool BS_Region::IsPointInRegion(const BS_Vertex &Vertex) const { return IsPointInRegion(Vertex.X, Vertex.Y); } // ----------------------------------------------------------------------------- -BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const -{ - // Feststellen, ob sich der Punkt innerhalb eines Loches befindet, falls dies der Fall ist wird der dichteste Punkt am Rand des Loches gesucht +BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex &Point) const { + // Determine whether the point is inside a hole. If that is the case, the closest + // point on the edge of the hole is determined int PolygonIdx = 0; { - for (unsigned int i = 1; i < m_Polygons.size(); ++i) - { - if (m_Polygons[i].IsPointInPolygon(Point)) - { + for (unsigned int i = 1; i < m_Polygons.size(); ++i) { + if (m_Polygons[i].IsPointInPolygon(Point)) { PolygonIdx = i; break; } @@ -263,30 +237,27 @@ BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const BS_ASSERT(Polygon.VertexCount > 1); - // Für jede Linie des Polygons wird der Punkt berechnet, der dem übergebenen am nächsten ist. - // Der Punkt dieser Menge mit dem gerigsten Abstand zum übergebenen Punkt ist das Ergebnis. + // For each line of the polygon, calculate the point that is cloest to the given point + // The point of this set with the smallest distance to the given point is the result. BS_Vertex ClosestVertex = FindClosestPointOnLine(Polygon.Vertecies[0], Polygon.Vertecies[1], Point); int ClosestVertexDistance2 = ClosestVertex.Distance(Point); - for (int i = 1; i < Polygon.VertexCount; ++i) - { + for (int i = 1; i < Polygon.VertexCount; ++i) { int j = (i + 1) % Polygon.VertexCount; BS_Vertex CurVertex = FindClosestPointOnLine(Polygon.Vertecies[i], Polygon.Vertecies[j], Point); - if (CurVertex.Distance(Point) < ClosestVertexDistance2) - { + if (CurVertex.Distance(Point) < ClosestVertexDistance2) { ClosestVertex = CurVertex; ClosestVertexDistance2 = CurVertex.Distance(Point); } } - // Feststellen, ob der konstruierte Punkt wirklich von der Methode IsPointInRegion als innerhalb der Region liegend erkannt wird. - // Dies muss nicht so sein, da aufgrund von Rundungsfehlern am Rand der Polygone Ungenauigkeiten auftreten. + // Determine whether the point is really within the region. This must not be so, as a result of rounding + // errors can occur at the edge of polygons if (IsPointInRegion(ClosestVertex)) return ClosestVertex; - else - { - // Es wird versucht einen Punkt innerhalb der Region zu konstruieren indem 8 Punkte getestet werden, die in unmittelbarer Umgebung des - // berechneten Punktes liegen + else { + // Try to construct a point within the region - 8 points are tested in the immediate vacinity + // of the point if (IsPointInRegion(ClosestVertex + BS_Vertex(-2, -2))) return ClosestVertex + BS_Vertex(-2, -2); else if (IsPointInRegion(ClosestVertex + BS_Vertex(0, -2))) @@ -304,30 +275,27 @@ BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const else if (IsPointInRegion(ClosestVertex + BS_Vertex(2, 2))) return ClosestVertex + BS_Vertex(2, 2); - // Falls auch auf diese Weise kein Punkt gefunden werden konnte, der innerhalb der Region liegt wird das Vertex genommen, welches am - // nächst an dem Punkt liegt. + // If no point could be found that way that lies within the region, find the next point ClosestVertex = Polygon.Vertecies[0]; int ShortestVertexDistance2 = Polygon.Vertecies[0].Distance2(Point); { - for (int i = 1; i < Polygon.VertexCount; i++) - { + for (int i = 1; i < Polygon.VertexCount; i++) { int CurDistance2 = Polygon.Vertecies[i].Distance2(Point); - if (CurDistance2 < ShortestVertexDistance2) - { + if (CurDistance2 < ShortestVertexDistance2) { ClosestVertex = Polygon.Vertecies[i]; ShortestVertexDistance2 = CurDistance2; } } } - BS_LOG_WARNINGLN("Clostest vertex forced because edgepoint was outside region."); - return ClosestVertex; + + BS_LOG_WARNINGLN("Clostest vertex forced because edgepoint was outside region."); + return ClosestVertex; } } // ----------------------------------------------------------------------------- -BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex & LineStart, const BS_Vertex & LineEnd, const BS_Vertex Point) const -{ +BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex &LineStart, const BS_Vertex &LineEnd, const BS_Vertex Point) const { float Vector1X = static_cast<float>(Point.X - LineStart.X); float Vector1Y = static_cast<float>(Point.Y - LineStart.Y); float Vector2X = static_cast<float>(LineEnd.X - LineStart.X); @@ -347,15 +315,14 @@ BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex & LineStart, const B } // ----------------------------------------------------------------------------- -// Sichtlinie +// Line of Sight // ----------------------------------------------------------------------------- -bool BS_Region::IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const -{ +bool BS_Region::IsLineOfSight(const BS_Vertex &a, const BS_Vertex &b) const { BS_ASSERT(m_Polygons.size()); - // Die Linie muss innerhalb des Kontur-Polygons und ausserhalb aller Loch-Polygone sein - std::vector<BS_Polygon>::const_iterator iter = m_Polygons.begin(); + // The line must be within the contour polygon, and outside of any hole polygons + Common::Array<BS_Polygon>::const_iterator iter = m_Polygons.begin(); if (!(*iter).IsLineInterior(a, b)) return false; for (iter++; iter != m_Polygons.end(); iter++) if (!(*iter).IsLineExterior(a, b)) return false; @@ -364,11 +331,10 @@ bool BS_Region::IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const } // ----------------------------------------------------------------------------- -// Persistenz +// Persistence // ----------------------------------------------------------------------------- -bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer) -{ +bool BS_Region::Persist(BS_OutputPersistenceBlock &Writer) { bool Result = true; Writer.Write(static_cast<unsigned int>(m_Type)); @@ -377,9 +343,8 @@ bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer) Writer.Write(m_Position.Y); Writer.Write(m_Polygons.size()); - std::vector<BS_Polygon>::iterator It = m_Polygons.begin(); - while (It != m_Polygons.end()) - { + Common::Array<BS_Polygon>::iterator It = m_Polygons.begin(); + while (It != m_Polygons.end()) { Result &= It->Persist(Writer); ++It; } @@ -394,8 +359,7 @@ bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer) // ----------------------------------------------------------------------------- -bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader) -{ +bool BS_Region::Unpersist(BS_InputPersistenceBlock &Reader) { Reader.Read(m_Valid); Reader.Read(m_Position.X); Reader.Read(m_Position.Y); @@ -403,8 +367,7 @@ bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader) m_Polygons.clear(); unsigned int PolygonCount; Reader.Read(PolygonCount); - for (unsigned int i = 0; i < PolygonCount; ++i) - { + for (unsigned int i = 0; i < PolygonCount; ++i) { m_Polygons.push_back(BS_Polygon(Reader)); } @@ -418,10 +381,11 @@ bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader) // ----------------------------------------------------------------------------- -BS_Vertex BS_Region::GetCentroid() const -{ +BS_Vertex BS_Region::GetCentroid() const { if (m_Polygons.size() > 0) return m_Polygons[0].GetCentroid(); return BS_Vertex(); } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/region.h b/engines/sword25/math/region.h index 90d6613aca..577da94fac 100644 --- a/engines/sword25/math/region.h +++ b/engines/sword25/math/region.h @@ -35,192 +35,188 @@ #ifndef SWORD25_REGION_H #define SWORD25_REGION_H -#include "sword25/kernel/memlog_off.h" -#include <vector> -#include "sword25/kernel/memlog_on.h" - #include "sword25/kernel/common.h" #include "sword25/kernel/persistable.h" #include "sword25/math/vertex.h" #include "sword25/math/polygon.h" #include "sword25/math/rect.h" +namespace Sword25 { + /** - @brief Diese Klasse ist die Basisklasse aller Regionen. - - Mit der Methode IsValid() lässt sich abfragen, ob sich das Objekt in einem gültigen Zustand befindet.<br> - Sollte dies nicht der Fall sein, ist die Methode Init() die einzige Methode die aufgerufen werden darf. - Diese Klasse garantiert, dass die Vertecies der die Umriss- und die Lochpolygone im Uhrzeigersinn angeordnet sind, so dass auf den Polygonen - arbeitende Algorithmen nur für diese Anordnung implementiert werden müssen. -*/ -class BS_Region : public BS_Persistable -{ + * This class is the base class of all regions. + * + * The IsValid() method can be queried to see whether the object is in a valid state. + * If this is not the case, the method Init() is the only method that may be invoked. + * This class guarantees that the Vertecies outline of the hole, and the polygons are + * arranged in a clockwise direction, so that the polygon working algorithms will + * work properly. + */ +class BS_Region : public BS_Persistable { protected: /** - @brief Erzeugt ein uninitialisiertes #BS_Region Objekt. - - Nach dem Erzeugen ist das Objekt noch ungültig (IsValid() gibt false zurück), allerdings kann das Objekt nachträglich über - einen Aufruf von Init() in einen gültigen Zustand versetzt werden. - */ + * Creates a new BS_Region object + * + * After creation the object is invaild (IsValid() return false), but a call can + * be made later on to Init() to set up the region into a valid state. + */ BS_Region(); - BS_Region(BS_InputPersistenceBlock & Reader, unsigned int Handle); + BS_Region(BS_InputPersistenceBlock &Reader, unsigned int Handle); public: - enum REGION_TYPE - { + enum REGION_TYPE { RT_REGION, RT_WALKREGION }; static unsigned int Create(REGION_TYPE Type); - static unsigned int Create(BS_InputPersistenceBlock & Reader, unsigned int Handle = 0); + static unsigned int Create(BS_InputPersistenceBlock &Reader, unsigned int Handle = 0); virtual ~BS_Region(); /** - @brief Initialisiert ein BS_Region Objekt. - @param Contour ein Polygon das den Umriss der Region angibt. - @param pHoles ein Pointer auf einen Vector von Polygonen, die Löcher in der Region angeben.<br> - Falls die Region keine Löcher hat, muss NULL übergeben werden.<br> - Der Standardwert ist NULL. - @return Gibt true zurück, wenn die Initialisierung erfolgreich war.<br> - Gibt false zurück, wenn die Intialisierung fehlgeschlagen ist. - @remark Falls die Region bereits initialisiert war, wird der alte Zustand gelöscht. - */ - virtual bool Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* pHoles = NULL); - - //@{ - /** @name Sondierende Methoden */ - - /** - @brief Gibt an, ob das Objekt in einem gültigen Zustand ist. - @return Gibt true zurück, wenn sich das Objekt in einem gültigen Zustand befindet. - Gibt false zurück, wenn sich das Objekt in einem ungültigen Zustand befindet. - @remark Ungültige Objekte können durch einen Aufruf von Init() in einen gültigen Zustand versetzt werden. - */ + * Initialises a BS_Region object + * @param Contour A polygon indicating the outline of the region + * @param pHoles A pointer to an array of polygons representing the hole state in the region. + * If the region has no holes, it must be passed as NULL. The default value is NULL. + * @return Returns true if the initialisation was successful, otherwise false. + * @remark If the region was already initialised, the old state will be deleted. + */ + virtual bool Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles = NULL); + + // + // Exploratory Methods + // + + /** + * Specifies whether the object is in a valid state + * @return Returns true if the object is in a valid state, otherwise false. + * @remark Invalid objects can be made valid by calling Init with a valid state. + */ bool IsValid() const { return m_Valid; } /** - @brief Gibt die Position der Region zurück. - */ - const BS_Vertex& GetPosition() const { return m_Position; } + * Returns the position of the region + */ + const BS_Vertex &GetPosition() const { return m_Position; } /** - @brief Gibt die Position des Region auf der X-Achse zurück. - */ + * Returns the X position of the region + */ int GetPosX() const { return m_Position.X; } /** - @brief Gibt die Position des Region auf der Y-Achse zurück. - */ + * Returns the Y position of the region + */ int GetPosY() const { return m_Position.Y; } /** - @brief Gibt an, ob sich ein Punkt innerhalb der Region befindet. - @param Vertex ein Vertex, mit den Koordinaten des zu testenden Punktes. - @return Gibt true zurück, wenn sich der Punkt innerhalb der Region befindet.<br> - Gibt false zurück, wenn sich der Punkt außerhalb der Region befindet. - */ - bool IsPointInRegion(const BS_Vertex& Vertex) const; + * Indicates whether a point is inside the region + * @param Vertex A verex with the co-ordinates of the test point + * @return Returns true if the point is within the region, otherwise false. + */ + bool IsPointInRegion(const BS_Vertex &Vertex) const; /** - @brief Gibt an, ob sich ein Punkt innerhalb der Region befindet. - @param X die Position des Punktes auf der X-Achse. - @param Y die Position des Punktes auf der Y-Achse. - @return Gibt true zurück, wenn sich der Punkt innerhalb der Region befindet.<br> - Gibt false zurück, wenn sich der Punkt außerhalb der Region befindet. - */ + * Indicates whether a point is inside the region + * @param X The X position + * @param Y The Y position + * @return Returns true if the point is within the region, otherwise false. + */ bool IsPointInRegion(int X, int Y) const; /** - @brief Gibt das Umrisspolygon der Region zurück. - */ - const BS_Polygon& GetContour() const { return m_Polygons[0]; } + * Returns the countour of the region + */ + const BS_Polygon &GetContour() const { return m_Polygons[0]; } /** - @brief Gibt die Anzahl der Lochpolygone in der Region zurück. - */ + * Returns the number of polygons in the hole region + */ int GetHoleCount() const { return static_cast<int>(m_Polygons.size() - 1); } /** - @brief Gibt ein bestimmtes Lochpolygon in der Region zurück. - @param i die Nummer des zurückzugebenen Loches.<br> - Dieser Wert muss zwischen 0 und GetHoleCount() - 1 liegen. - @return Gibt das gewünschte Lochpolygon zurück. - */ - inline const BS_Polygon& GetHole(unsigned int i) const; + * Returns a specific hole polygon in the region + * @param i The number of the hole to return. + * The index must be between 0 and GetHoleCount() - 1. + * @return Returns the desired hole polygon + */ + inline const BS_Polygon &GetHole(unsigned int i) const; /** - @brief Findet für einen Punkt ausserhalb der Region den nächsten Punkt, der sich innerhalb der Region befindet. - @param Point der Punkt, der sich ausserhalb der Region befindet - @return Gibt den Punkt innerhalb der Region zurück, der den geringsten Abstand zum übergebenen Punkt hat. - @remark Diese Methode arbeitet nicht immer Pixelgenau. Man sollte sich also nicht darauf verlassen, dass es wirklich keine Punkt innerhalb der - Region gibt, der dichter am übergebenen Punkt liegt. - */ - BS_Vertex FindClosestRegionPoint(const BS_Vertex& Point) const; + * For a point outside the region, finds the closest point inside the region + * @param Point The point that is outside the region + * @return Returns the point within the region which is closest + * @remark This method does not always work with pixel accuracy. + * One should not therefore rely on the fact that there is really no point in + * the region which is closer to the given point. + */ + BS_Vertex FindClosestRegionPoint(const BS_Vertex &Point) const; /** - @brief Gibt den Schwerpunkt des Umrisspolygons zurück. - */ + * Returns the centroid for the region + */ BS_Vertex GetCentroid() const; - bool IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const; + bool IsLineOfSight(const BS_Vertex &a, const BS_Vertex &b) const; - //@} - - //@{ - /** @name Manipulierende Methoden */ + // + // Manipulation Methods + // /** - @brief Setzt die Position der Region. - @param X die neue Position der Region auf der X-Achse. - @param Y die neue Position der Region auf der Y-Achse. - */ + * Sets the position of the region + * @param X The new X psoition of the region + * @param Y The new Y psoition of the region + */ virtual void SetPos(int X, int Y); /** - @brief Setzt die Position der Region auf der X-Achse. - @param X die neue Position der Region auf der X-Achse. - */ + * Sets the X position of the region + * @param X The new X position of the region + */ void SetPosX(int X); /** - @brief Setzt die Position der Region auf der Y-Achse. - @param Y die neue Position der Region auf der Y-Achse. - */ + * Sets the Y position of the region + * @param Y The new Y position of the region + */ void SetPosY(int Y); - //@} + // + // Manipulation Methods + // - virtual bool Persist(BS_OutputPersistenceBlock & Writer); - virtual bool Unpersist(BS_InputPersistenceBlock & Reader); + virtual bool Persist(BS_OutputPersistenceBlock &Writer); + virtual bool Unpersist(BS_InputPersistenceBlock &Reader); protected: - /// Diese Variable gibt den Typ des Objektes an. + /// This specifies the type of object REGION_TYPE m_Type; - /// Diese Variable gibt an, ob der aktuelle Objektzustand gültig ist. + /// This variable indicates whether the current object state is valid bool m_Valid; - /// Dieses Vertex gibt die Position der Region an. + /// This vertex is the position of the region BS_Vertex m_Position; - /// Dieser Vector enthält alle Polygone die die Region definieren. Das erste Element des Vectors ist die Kontur, alle weiteren sind die Löcher. - std::vector<BS_Polygon> m_Polygons; - /// Die Bounding-Box der Region. + /// This array contains all the polygons that define the region. The first element of + // the array is the contour, all others are the holes + Common::Array<BS_Polygon> m_Polygons; + /// The bounding box for the region BS_Rect m_BoundingBox; /** - @brief Aktualisiert die Bounding-Box der Region. - */ + * Updates the bounding box of the region. + */ void UpdateBoundingBox(); /** - @brief Findet den Punkt auf einer Linie, der einem anderen Punkt am nächsten ist. - @param LineStart der Startpunkt der Linie - @param LineEnd der Endpunkt der Linie - @param Point der Punkt, zu dem der nächste Punkt auf der Linie konstruiert werden soll. - @return Gibt den Punkt auf der Linie zurück, der dem übergebenen Punkt am nächsten ist. - */ - BS_Vertex FindClosestPointOnLine(const BS_Vertex & LineStart, const BS_Vertex & LineEnd, const BS_Vertex Point) const; + * Find the point on a line which is closest to another point + * @param LineStart The start of the line + * @param LineEnd The end of the line + * @param Point The point to be compared against + * @return Returns the point on the line which is cloest to the passed point. + */ + BS_Vertex FindClosestPointOnLine(const BS_Vertex &LineStart, const BS_Vertex &LineEnd, const BS_Vertex Point) const; }; @@ -228,10 +224,11 @@ protected: // Inlines // ----------------------------------------------------------------------------- -inline const BS_Polygon& BS_Region::GetHole(unsigned int i) const -{ +inline const BS_Polygon &BS_Region::GetHole(unsigned int i) const { BS_ASSERT(i < m_Polygons.size() - 1); return m_Polygons[i + 1]; } +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/regionregistry.cpp b/engines/sword25/math/regionregistry.cpp index 3af871b1e7..1611f228ea 100644 --- a/engines/sword25/math/regionregistry.cpp +++ b/engines/sword25/math/regionregistry.cpp @@ -47,46 +47,44 @@ #include "sword25/math/regionregistry.h" #include "sword25/math/region.h" +namespace Sword25 { + // ----------------------------------------------------------------------------- // Implementation // ----------------------------------------------------------------------------- -std::auto_ptr<BS_RegionRegistry> BS_RegionRegistry::m_InstancePtr; +Common::SharedPtr<BS_RegionRegistry> BS_RegionRegistry::m_InstancePtr; // ----------------------------------------------------------------------------- -void BS_RegionRegistry::LogErrorLn(const char * Message) const -{ +void BS_RegionRegistry::LogErrorLn(const char *Message) const { BS_LOG_ERRORLN(Message); } // ----------------------------------------------------------------------------- -void BS_RegionRegistry::LogWarningLn(const char * Message) const -{ +void BS_RegionRegistry::LogWarningLn(const char *Message) const { BS_LOG_WARNINGLN(Message); } // ----------------------------------------------------------------------------- -bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock & Writer) -{ +bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock &Writer) { bool Result = true; - // Das nächste zu vergebene Handle schreiben. + // Write out the next handle Writer.Write(m_NextHandle); - // Anzahl an BS_Regions schreiben. + // Number of regions to write Writer.Write(m_Handle2PtrMap.size()); - // Alle BS_Regions persistieren. + // Persist all the BS_Regions HANDLE2PTR_MAP::const_iterator Iter = m_Handle2PtrMap.begin(); - while (Iter != m_Handle2PtrMap.end()) - { - // Handle persistieren. + while (Iter != m_Handle2PtrMap.end()) { + // Handle persistence Writer.Write(Iter->first); - // Objekt persistieren. + // Persist object Result &= Iter->second->Persist(Writer); ++Iter; @@ -97,30 +95,30 @@ bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock & Writer) // ----------------------------------------------------------------------------- -bool BS_RegionRegistry::Unpersist(BS_InputPersistenceBlock & Reader) -{ +bool BS_RegionRegistry::Unpersist(BS_InputPersistenceBlock &Reader) { bool Result = true; - // Das nächste zu vergebene Handle wieder herstellen. + // Read in the next handle Reader.Read(m_NextHandle); - // Alle vorhandenen BS_Regions zerstören. + // Destroy all existing BS_Regions while (!m_Handle2PtrMap.empty()) delete m_Handle2PtrMap.begin()->second; - // Anzahl an BS_Regions einlesen. + // Read in the number of BS_Regions unsigned int RegionCount; Reader.Read(RegionCount); - // Alle gespeicherten BS_Regions wieder herstellen. - for (unsigned int i = 0; i < RegionCount; ++i) - { - // Handle lesen. + // Restore all the BS_Regions objects + for (unsigned int i = 0; i < RegionCount; ++i) { + // Handle read unsigned int Handle; Reader.Read(Handle); - // BS_Region wieder herstellen. + // BS_Region restore Result &= BS_Region::Create(Reader, Handle) != 0; } return Reader.IsGood() && Result; } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/regionregistry.h b/engines/sword25/math/regionregistry.h index f1af5dc1b7..3c4771df5f 100644 --- a/engines/sword25/math/regionregistry.h +++ b/engines/sword25/math/regionregistry.h @@ -39,41 +39,40 @@ // Includes // ----------------------------------------------------------------------------- +#include "common/ptr.h" #include "sword25/kernel/common.h" #include "sword25/kernel/persistable.h" #include "sword25/kernel/objectregistry.h" -#include "sword25/kernel/memlog_off.h" -#include <memory> -#include "sword25/kernel/memlog_on.h" +namespace Sword25 { // ----------------------------------------------------------------------------- -// Forward Deklarationen +// Forward Declarations // ----------------------------------------------------------------------------- class BS_Region; // ----------------------------------------------------------------------------- -// Klassendeklaration +// Class definitions // ----------------------------------------------------------------------------- -class BS_RegionRegistry : public BS_ObjectRegistry<BS_Region>, public BS_Persistable -{ +class BS_RegionRegistry : public BS_ObjectRegistry<BS_Region>, public BS_Persistable { public: - static BS_RegionRegistry & GetInstance() - { - if (!m_InstancePtr.get()) m_InstancePtr.reset(new BS_RegionRegistry); + static BS_RegionRegistry & GetInstance() { + if (!m_InstancePtr.get()) m_InstancePtr = Common::SharedPtr<BS_RegionRegistry>(new BS_RegionRegistry()); return *m_InstancePtr.get(); } - virtual bool Persist(BS_OutputPersistenceBlock & Writer); - virtual bool Unpersist(BS_InputPersistenceBlock & Reader); + virtual bool Persist(BS_OutputPersistenceBlock &Writer); + virtual bool Unpersist(BS_InputPersistenceBlock &Reader); private: - virtual void LogErrorLn(const char * Message) const; - virtual void LogWarningLn(const char * Message) const; + virtual void LogErrorLn(const char *Message) const; + virtual void LogWarningLn(const char *Message) const; - static std::auto_ptr<BS_RegionRegistry> m_InstancePtr; + static Common::SharedPtr<BS_RegionRegistry> m_InstancePtr; }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/vertex.cpp b/engines/sword25/math/vertex.cpp index 5dbf99402e..61d21b58d8 100644 --- a/engines/sword25/math/vertex.cpp +++ b/engines/sword25/math/vertex.cpp @@ -34,31 +34,36 @@ #include "sword25/math/vertex.h" +namespace { + extern "C" { #include "sword25/util/lua/lua.h" #include "sword25/util/lua/lauxlib.h" } +} + // ----------------------------------------------------------------------------- -BS_Vertex & BS_Vertex::LuaVertexToVertex(lua_State * L, int StackIndex, BS_Vertex & Vertex) -{ +namespace Sword25 { + +BS_Vertex &BS_Vertex::LuaVertexToVertex(lua_State *L, int StackIndex, BS_Vertex &Vertex) { #ifdef DEBUG int __startStackDepth = lua_gettop(L); #endif - // Sicherstellen, dass wir wirklich eine Tabelle betrachten + // Ensure that we actually consider a table luaL_checktype(L, StackIndex, LUA_TTABLE); - // X Komponente auslesen + // Read X Component lua_pushstring(L, "X"); lua_gettable(L, StackIndex); if (!lua_isnumber(L, -1)) luaL_argcheck(L, 0, StackIndex, "the X component has to be a number"); Vertex.X = static_cast<int>(lua_tonumber(L, -1)); lua_pop(L, 1); - // Y Komponente auslesen + // Read Y Component lua_pushstring(L, "Y"); lua_gettable(L, StackIndex); if (!lua_isnumber(L, -1)) luaL_argcheck(L, 0, StackIndex, "the Y component has to be a number"); @@ -74,18 +79,19 @@ BS_Vertex & BS_Vertex::LuaVertexToVertex(lua_State * L, int StackIndex, BS_Verte // ----------------------------------------------------------------------------- -void BS_Vertex::VertexToLuaVertex(lua_State * L, const BS_Vertex & Vertex) -{ - // Neue Tabelle erstellen +void BS_Vertex::VertexToLuaVertex(lua_State * L, const BS_Vertex &Vertex) { + // Create New Table lua_newtable(L); - // X-Wert in die Tabelle schreiben + // X value is written to table lua_pushstring(L, "X"); lua_pushnumber(L, Vertex.X); lua_settable(L, -3); - // Y-Wert in die Tabelle schreiben + // Y value is written to table lua_pushstring(L, "Y"); lua_pushnumber(L, Vertex.Y); lua_settable(L, -3); } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/vertex.h b/engines/sword25/math/vertex.h index bb7a84abb9..5b4e6da0f8 100644 --- a/engines/sword25/math/vertex.h +++ b/engines/sword25/math/vertex.h @@ -46,14 +46,19 @@ #include <math.h> #include "sword25/kernel/common.h" -// Forward-Declarations +namespace { + +// Forward declarations struct lua_State; +} + +namespace Sword25 { + /** - @brief Ein 2D-Vertex. -*/ -class BS_Vertex -{ + * Defines a 2-D Vertex + */ +class BS_Vertex { public: BS_Vertex() : X(0), Y(0) {}; BS_Vertex(int X_, int Y_) { this->X = X_; this->Y = Y_; } @@ -62,91 +67,87 @@ public: int Y; /** - @brief Vergleicht zwei Vertecies. - */ + * Compares two Vertecies. + */ inline bool operator==(const BS_Vertex& rhs) const { if (X == rhs.X && Y == rhs.Y) return true; return false; } /** - @brief Vergleicht zwei Vertecies. - */ + * Compares two Vertecies. + */ inline bool operator!=(const BS_Vertex& rhs) const { if (X != rhs.X || Y != rhs.Y) return true; return false; } /** - @brief Addiert ein Vertex zum Vertex. - */ + * Adds a vertex to vertex + */ inline void operator+=(const BS_Vertex& Delta) { X += Delta.X; Y += Delta.Y; } /** - @brief Subtrahiert ein Vertex vom Vertex. - */ + * Subtracts a vertex from a vertex + */ inline void operator-=(const BS_Vertex& Delta) { X -= Delta.X; Y -= Delta.Y; } /** - @brief Addiert zwei Vertecies - */ + * Adds two vertecies + */ inline BS_Vertex operator+(const BS_Vertex& Delta) const { return BS_Vertex(X + Delta.X, Y + Delta.Y); } /** - @brief Subtrahiert zwei Vertecies - */ + * Subtracts two vertecies + */ inline BS_Vertex operator-(const BS_Vertex& Delta) const { return BS_Vertex(X - Delta.X, Y - Delta.Y); } /** - @brief Berechnet das Quadrat des Abstandes zweier Vertecies. - @param Vertex das Vertex zu dem der Abstand berechnet werden soll. - @return Gibt das Quadrat des Abstandes zwischen diesem Objekt und Vertex zurück. - @remark Falls nur Abstände verglichen werden sollen, sollte diese Methode benutzt werden, da sie schneller ist, als Distance(). - */ - inline int Distance2(const BS_Vertex& Vertex) const - { + * Calculates the square of the distance between two Vertecies. + * @param Vertex The vertex for which the distance is to be calculated + * @return Returns the square of the distance between itself and the passed vertex + * @remark If only distances should be compared, this method should be used because + * it is faster than Distance() + */ + inline int Distance2(const BS_Vertex& Vertex) const { return (X - Vertex.X) * (X - Vertex.X) + (Y - Vertex.Y) * (Y - Vertex.Y); } /** - @brief Berechnet den Abstand zweier Vertecies. - @param Vertex das Vertex zu dem der Abstand berechnet werden soll. - @return Gibt den Abstand zwischen diesem Objekt und Vertex zurück. - @remark Falls nur Abstände verglichen werden sollen, sollte diese Methode Distance2(), die das Quadrat des Abstandes berechnet. - Sie ist schneller. - */ - inline int Distance(const BS_Vertex& Vertex) const - { + * Calculates the square of the distance between two Vertecies. + * @param Vertex The vertex for which the distance is to be calculated + * @return Returns the square of the distance between itself and the passed vertex + * @remark If only distances should be compared, Distance2() should be used, since it is faster. + */ + inline int Distance(const BS_Vertex& Vertex) const { return (int)(sqrtf(static_cast<float>(Distance2(Vertex))) + 0.5); } /** - @brief Berechnet das Kreuzprodukt dieses Vertex mit einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst. - @param Vertex das zweite Vertex - @return Gibt das Kreuzprodukt von diesem Vertex und dem Parameter Vertex zurück. - */ - inline int ComputeCrossProduct(const BS_Vertex& Vertex) const - { + * Calculates the cross product of the vertex with another vertex. Here the Vertecies will be + * interpreted as vectors. + * @param Vertex The second vertex + * @return Returns the cross product of this vertex and the passed vertex. + */ + inline int ComputeCrossProduct(const BS_Vertex& Vertex) const { return X * Vertex.Y - Vertex.X * Y; } /** - @brief Berechnet das Skalarprodukt dieses Vertex mit einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst. - @param Vertex das zweite Vertex - @return Gibt das Skalarprodukt von diesem Vertex und dem Parameter Vertex zurück. - */ + * Returns the dot product of this vertex with another vertex. Here the Vertecies are interpreted as vectors. + * @param Vertex The second vertex + * @return Returns the dot product of this vertex and the passed vertex. + */ inline int ComputeDotProduct(const BS_Vertex& Vertex) const { return X * Vertex.X + Y * Vertex.Y; } /** - @brief Berechnet den Winkel zwischen diesem Vertex und einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst. - @param Vertex das zweite Vertex - @return Gibt den Winkel zwischen diesem Vertex und dem Parameter Vertex im Bogenmaß zurück. - */ - inline float ComputeAngle(const BS_Vertex& Vertex) const - { + * Calculates the angle between this vertex and another vertex. Here the Vertecies are interpreted as vectors. + * @param Vertex The second vertex + * @return Returns the angle between this vertex and the passed vertex in radians. + */ + inline float ComputeAngle(const BS_Vertex& Vertex) const { return atan2f(static_cast<float>(ComputeCrossProduct(Vertex)), static_cast<float>(ComputeDotProduct(Vertex))); } /** - @brief Berechnet die Länge des Vektors - */ - inline float ComputeLength() const - { + * Calculates the length of the vector + */ + inline float ComputeLength() const { return sqrtf(static_cast<float>(X * X + Y * Y)); } @@ -154,4 +155,6 @@ public: static void VertexToLuaVertex(lua_State * L, const BS_Vertex & Vertex); }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/math/walkregion.cpp b/engines/sword25/math/walkregion.cpp index 58d5bc45ba..70b84da3b9 100644 --- a/engines/sword25/math/walkregion.cpp +++ b/engines/sword25/math/walkregion.cpp @@ -32,8 +32,7 @@ * */ -#include <list> -#include <algorithm> +#include "sword25/kernel/kernel.h" #include "sword25/kernel/inputpersistenceblock.h" #include "sword25/kernel/outputpersistenceblock.h" #include "sword25/math/walkregion.h" @@ -41,65 +40,62 @@ #define BS_LOG_PREFIX "WALKREGION" +namespace Sword25 { + // ----------------------------------------------------------------------------- -// Konstanten +// Constants // ----------------------------------------------------------------------------- static const int infinity = INT_MAX; // ----------------------------------------------------------------------------- -// Konstruktion / Destruktion +// Constructor / Destructor // ----------------------------------------------------------------------------- -BS_WalkRegion::BS_WalkRegion() -{ +BS_WalkRegion::BS_WalkRegion() { m_Type = RT_WALKREGION; } // ----------------------------------------------------------------------------- BS_WalkRegion::BS_WalkRegion(BS_InputPersistenceBlock &Reader, unsigned int Handle) : - BS_Region(Reader, Handle) -{ + BS_Region(Reader, Handle) { m_Type = RT_WALKREGION; Unpersist(Reader); } // ----------------------------------------------------------------------------- -BS_WalkRegion::~BS_WalkRegion() -{ +BS_WalkRegion::~BS_WalkRegion() { } // ----------------------------------------------------------------------------- -bool BS_WalkRegion::Init(const BS_Polygon & Contour, const std::vector<BS_Polygon> * pHoles) -{ - // Standard-Initialisierungen der Region vornehmen. +bool BS_WalkRegion::Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles) { + // Default initialisation of the region if (!BS_Region::Init(Contour, pHoles)) return false; - // Datenstrukturen fürs Pathfinding vorbereiten + // Prepare structures for pathfinding InitNodeVector(); ComputeVisibilityMatrix(); - // Erfolg signalisieren. + // Signal success return true; } // ----------------------------------------------------------------------------- -bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path & Path) -{ +bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path &Path) { BS_ASSERT(Path.empty()); - // Falls Start und Ziel identisch sind, muss trivialerweise kein Pfad gefunden werden. + // If the start and finish are identical, no path can be found trivially if (StartPoint == EndPoint) return true; - // Sicherstellen, dass Start und Ziel gültig sind und neuen Start- und Zielpunkt finden, falls sie ausserhalb des Polygons liegen. + // Ensure that the start and finish are valid and find new start points if either + // are outside the polygon if (!CheckAndPrepareStartAndEnd(StartPoint, EndPoint)) return false; - // Wenn zwischen Start- und Endpunkt eine Sichtlinie besteht, muss kein Pathfindung durchgeführt werden und als Ergebnis wird die - // direkte Verbindungslinie zwischen Start- und Endpunkt zurückgegeben. + // If between the start and point a line of sight exists, then it can be returned. if (IsLineOfSight(StartPoint, EndPoint)) { Path.push_back(StartPoint); @@ -112,9 +108,8 @@ bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path // ----------------------------------------------------------------------------- -struct DijkstraNode -{ - typedef std::vector<DijkstraNode> Container; +struct DijkstraNode { + typedef Common::Array<DijkstraNode> Container; typedef Container::iterator Iter; typedef Container::const_iterator ConstIter; @@ -124,30 +119,27 @@ struct DijkstraNode bool Chosen; }; -static void InitDijkstraNodes(DijkstraNode::Container & DijkstraNodes, const BS_Region & Region, const BS_Vertex & Start, const std::vector<BS_Vertex> & Nodes) -{ - // Ausreichend Platz im Vector reservieren +static void InitDijkstraNodes(DijkstraNode::Container &DijkstraNodes, const BS_Region &Region, + const BS_Vertex &Start, const Common::Array<BS_Vertex> &Nodes) { + // Allocate sufficient space in the array DijkstraNodes.resize(Nodes.size()); - // Alle Randknoten initialisieren, die vom Startknoten sichtbar sind + // Initialise all the nodes which are visible from the starting node DijkstraNode::Iter DijkstraIter = DijkstraNodes.begin(); - for (std::vector<BS_Vertex>::const_iterator NodesIter = Nodes.begin(); NodesIter != Nodes.end(); NodesIter++, DijkstraIter++) - { + for (Common::Array<BS_Vertex>::const_iterator NodesIter = Nodes.begin(); + NodesIter != Nodes.end(); NodesIter++, DijkstraIter++) { (*DijkstraIter).ParentIter = DijkstraNodes.end(); if (Region.IsLineOfSight(*NodesIter, Start)) (*DijkstraIter).Cost = (*NodesIter).Distance(Start); } BS_ASSERT(DijkstraIter == DijkstraNodes.end()); } -static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes) -{ +static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes) { DijkstraNode::Iter ClosestNodeInter = Nodes.end(); int MinCost = infinity; - for (DijkstraNode::Iter iter = Nodes.begin(); iter != Nodes.end(); iter++) - { - if (!(*iter).Chosen && (*iter).Cost < MinCost) - { + for (DijkstraNode::Iter iter = Nodes.begin(); iter != Nodes.end(); iter++) { + if (!(*iter).Chosen && (*iter).Cost < MinCost) { MinCost = (*iter).Cost; ClosestNodeInter = iter; } @@ -156,22 +148,19 @@ static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes) return ClosestNodeInter; } -static void RelaxNodes(DijkstraNode::Container & Nodes, - const std::vector< std::vector<int> > & VisibilityMatrix, - const DijkstraNode::ConstIter & CurNodeIter) -{ - // Alle Nachfolger vom aktuellen Knoten, die noch nicht gewählt wurden, werden in die Randknotenliste eingefügt und die Kosten werden - // aktualisiert, wenn ein kürzerer Pfad zu ihnen gefunden wurde. +static void RelaxNodes(DijkstraNode::Container &Nodes, + const Common::Array< Common::Array<int> > &VisibilityMatrix, + const DijkstraNode::ConstIter &CurNodeIter) { + // All the successors of the current node that have not been chosen will be + // inserted into the boundary node list, and the cost will be updated if + // a shorter path has been found to them. int CurNodeIndex = CurNodeIter - Nodes.begin(); - for (unsigned int i = 0; i < Nodes.size(); i++) - { + for (unsigned int i = 0; i < Nodes.size(); i++) { int Cost = VisibilityMatrix[CurNodeIndex][i]; - if (!Nodes[i].Chosen && Cost != infinity) - { + if (!Nodes[i].Chosen && Cost != infinity) { int TotalCost = (*CurNodeIter).Cost + Cost; - if (TotalCost < Nodes[i].Cost) - { + if (TotalCost < Nodes[i].Cost) { Nodes[i].ParentIter = CurNodeIter; Nodes[i].Cost = TotalCost; } @@ -179,90 +168,82 @@ static void RelaxNodes(DijkstraNode::Container & Nodes, } } -static void RelaxEndPoint(const BS_Vertex & CurNodePos, - const DijkstraNode::ConstIter & CurNodeIter, - const BS_Vertex & EndPointPos, - DijkstraNode & EndPoint, - const BS_Region & Region) -{ - if (Region.IsLineOfSight(CurNodePos, EndPointPos)) - { +static void RelaxEndPoint(const BS_Vertex &CurNodePos, + const DijkstraNode::ConstIter &CurNodeIter, + const BS_Vertex &EndPointPos, + DijkstraNode &EndPoint, + const BS_Region &Region) { + if (Region.IsLineOfSight(CurNodePos, EndPointPos)) { int TotalCost = (*CurNodeIter).Cost + CurNodePos.Distance(EndPointPos); - if (TotalCost < EndPoint.Cost) - { + if (TotalCost < EndPoint.Cost) { EndPoint.ParentIter = CurNodeIter; EndPoint.Cost = TotalCost; } } } -bool BS_WalkRegion::FindPath(const BS_Vertex & Start, const BS_Vertex & End, BS_Path & Path) const -{ - // Dies ist eine Implementation des Dijkstra-Algorithmus +bool BS_WalkRegion::FindPath(const BS_Vertex &Start, const BS_Vertex &End, BS_Path &Path) const { + // This is an implementation of Dijkstra's algorithm - // Randknotenliste initialisieren + // Initialise edge node list DijkstraNode::Container DijkstraNodes; InitDijkstraNodes(DijkstraNodes, *this, Start, m_Nodes); - // Der Endpunkt wird gesondert behandelt, da er im Sichtbarkeitsgraphen nicht vorhanden ist + // The end point is treated separately, since it does not exist in the visibility graph DijkstraNode EndPoint; - // Da in jedem Durchgang ein Knoten aus der Knotenliste gewählt wird, und danach nie wieder gewählt werden kann, ist die maximale Anzahl der - // Schleifendurchläufe durch die Anzahl der Knoten begrenzt. - for (unsigned int i = 0; i < m_Nodes.size(); i++) - { - // Bestimme nächstgelegenen Knoten in der Randknotenliste + // Since a node is selected each round from the node list, and can never be selected again + // after that, the maximum number of loop iterations is limited by the number of nodes + for (unsigned int i = 0; i < m_Nodes.size(); i++) { + // Determine the nearest edge node in the node list DijkstraNode::Iter NodeInter = ChooseClosestNode(DijkstraNodes); (*NodeInter).Chosen = true; - // Falls kein freier Knoten mehr in der Randknotenliste vorhanden ist, gibt es keinen Weg vom Start- zum Endknoten. - // Dieser Fall sollte nie auftreten, da die Anzahl der Schleifendurchgänge begrenzt ist, aber sicher ist sicher. + // If no free nodes are absent from the edge node list, there is no path from start + // to end node. This case should never occur, since the number of loop passes is + // limited, but etter safe than sorry if (NodeInter == DijkstraNodes.end()) return false; - // Wenn der Zielpunkt noch näher liegt als der nächte Punkt, ist die Suche beendet - if (EndPoint.Cost <= (*NodeInter).Cost) - { - // Ergebnispfad extrahieren - - // Den Endpunkt in den Ergebnispfad einfügen + // If the destination point is closer than the point cost, scan can stop + if (EndPoint.Cost <= (*NodeInter).Cost) { + // Insert the end point in the list Path.push_back(End); - // Die Wegknoten in umgekehrter Reihenfolge ablaufen und in den Ergebnispfad einfügen + // The list is done in reverse order and inserted into the path DijkstraNode::ConstIter CurNode = EndPoint.ParentIter; - while (CurNode != DijkstraNodes.end()) - { + while (CurNode != DijkstraNodes.end()) { BS_ASSERT((*CurNode).Chosen); Path.push_back(m_Nodes[CurNode - DijkstraNodes.begin()]); CurNode = (*CurNode).ParentIter; } - // Den Startpunkt in den Ergebnispfad einfügen + // The starting point is inserted into the path Path.push_back(Start); - // Die Knoten des Pfades müssen ungedreht werden, da sie in umgekehrter Reihenfolge extrahiert wurden. - // Diesen Schritt könnte man sich sparen, wenn man den Pfad vom Ende zum Anfang sucht. - std::reverse(Path.begin(), Path.end()); + // The nodes of the path must be untwisted, as they were extracted in reverse order. + // This step could be saved if the path from end to the beginning was desired + ReverseArray<BS_Vertex>(Path); return true; } - // Relaxation-Schritt für die Knoten des Graphen und für den Endknoten durchführen + // Relaxation step for nodes of the graph, and perform the end nodes RelaxNodes(DijkstraNodes, m_VisibilityMatrix, NodeInter); RelaxEndPoint(m_Nodes[NodeInter - DijkstraNodes.begin()], NodeInter, End, EndPoint, *this); } - // Falls die Schleife komplett durchlaufen wurde, wurden alle Knoten gewählt und es wurde trotzdem kein Pfad gefunden. Es existiert also keiner. + // If the loop has been completely run through, all the nodes have been chosen, and still + // no path was found. There is therefore no path available return false; } // ----------------------------------------------------------------------------- -void BS_WalkRegion::InitNodeVector() -{ - // Knoten-Vector leeren. +void BS_WalkRegion::InitNodeVector() { + // Empty the Node list m_Nodes.clear(); - // Anzahl der Knoten bestimmen. + // Determine the number of nodes int NodeCount = 0; { for (unsigned int i = 0; i < m_Polygons.size(); i++) @@ -280,26 +261,27 @@ void BS_WalkRegion::InitNodeVector() // ----------------------------------------------------------------------------- -void BS_WalkRegion::ComputeVisibilityMatrix() -{ - // Sichtbarkeitsmatrix initialisieren - m_VisibilityMatrix = std::vector< std::vector <int> >(m_Nodes.size(), std::vector<int>(m_Nodes.size(), infinity)); +void BS_WalkRegion::ComputeVisibilityMatrix() { + // Initialise visibility matrix + m_VisibilityMatrix = Common::Array< Common::Array <int> >(); + for (uint idx = 0; idx < m_Nodes.size(); ++idx) { + Common::Array<int> arr; + for (uint idx2 = 0; idx2 < m_Nodes.size(); ++idx2) + arr.push_back(infinity); - // Sichtbarkeiten zwischen Vertecies berechnen und in die Sichbarkeitsmatrix eintragen. - for (unsigned int j = 0; j < m_Nodes.size(); ++j) - { - for (unsigned int i = j; i < m_Nodes.size(); ++i) - { - if (IsLineOfSight(m_Nodes[i], m_Nodes[j])) - { - // Wenn eine Sichtlinie besteht wird die Entfernung der Knoten eingetragen + m_VisibilityMatrix.push_back(arr); + } + + // Calculate visibility been vertecies + for (unsigned int j = 0; j < m_Nodes.size(); ++j) { + for (unsigned int i = j; i < m_Nodes.size(); ++i) { + if (IsLineOfSight(m_Nodes[i], m_Nodes[j])) { + // There is a line of sight, so save the distance between the two int Distance = m_Nodes[i].Distance(m_Nodes[j]); m_VisibilityMatrix[i][j] = Distance; m_VisibilityMatrix[j][i] = Distance; - } - else - { - // Wenn keine Sichtlinie besteht wird die Entfernung "unendlich" eingetragen + } else { + // There is no line of sight, so save infinity as the distance m_VisibilityMatrix[i][j] = infinity; m_VisibilityMatrix[j][i] = infinity; } @@ -309,15 +291,12 @@ void BS_WalkRegion::ComputeVisibilityMatrix() // ----------------------------------------------------------------------------- -bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & End) const -{ - if (!IsPointInRegion(Start)) - { +bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex &Start, BS_Vertex &End) const { + if (!IsPointInRegion(Start)) { BS_Vertex NewStart = FindClosestRegionPoint(Start); - // Sicherstellen, dass der ermittelte Punkt wirklich innerhalb der Region liegt und Notfalls abbrechen. - if (!IsPointInRegion(NewStart)) - { + // Check to make sure the point is really in the region. If not, stop with an error + if (!IsPointInRegion(NewStart)) { BS_LOG_ERRORLN("Constructed startpoint ((%d,%d) from (%d,%d)) is not inside the region.", NewStart.X, NewStart.Y, Start.X, Start.Y); @@ -327,14 +306,13 @@ bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & En Start = NewStart; } - // Falls der Zielpunkt außerhalb der Region liegt, wird der nächste Punkt innerhalb der Region bestimmt und als Endpunkt benutzt. - if (!IsPointInRegion(End)) - { + // If the destination is outside the region, a point is determined that is within the region, + // and that is used as an endpoint instead + if (!IsPointInRegion(End)) { BS_Vertex NewEnd = FindClosestRegionPoint(End); - // Sicherstellen, dass der ermittelte Punkt wirklich innerhalb der Region liegt und Notfalls abbrechen. - if (!IsPointInRegion(NewEnd)) - { + // Make sure that the determined point is really within the region + if (!IsPointInRegion(NewEnd)) { BS_LOG_ERRORLN("Constructed endpoint ((%d,%d) from (%d,%d)) is not inside the region.", NewEnd.X, NewEnd.Y, End.X, End.Y); @@ -344,52 +322,47 @@ bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & En End = NewEnd; } - // Erfolg signalisieren + // Signal success return true; } // ----------------------------------------------------------------------------- -void BS_WalkRegion::SetPos(int X, int Y) -{ - // Unterschied zwischen alter und neuer Position berechnen. +void BS_WalkRegion::SetPos(int X, int Y) { + // Calculate the difference between old and new position BS_Vertex Delta(X - m_Position.X, Y - m_Position.Y); - // Alle Nodes verschieben. + // Move all the nodes for (unsigned int i = 0; i < m_Nodes.size(); i++) m_Nodes[i] += Delta; - // Region verschieben + // Move regions BS_Region::SetPos(X, Y); } // ----------------------------------------------------------------------------- -bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock & Writer) -{ +bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock &Writer) { bool Result = true; - // Elternobjekt persistieren. + // Persist the parent region Result &= BS_Region::Persist(Writer); - // Knoten persistieren. + // Persist the nodes Writer.Write(m_Nodes.size()); - std::vector<BS_Vertex>::const_iterator It = m_Nodes.begin(); - while (It != m_Nodes.end()) - { + Common::Array<BS_Vertex>::const_iterator It = m_Nodes.begin(); + while (It != m_Nodes.end()) { Writer.Write(It->X); Writer.Write(It->Y); ++It; } - // Sichtbarkeitsmatrix persistieren. + // Persist the visibility matrix Writer.Write(m_VisibilityMatrix.size()); - std::vector< std::vector<int> >::const_iterator RowIter = m_VisibilityMatrix.begin(); - while (RowIter != m_VisibilityMatrix.end()) - { + Common::Array< Common::Array<int> >::const_iterator RowIter = m_VisibilityMatrix.begin(); + while (RowIter != m_VisibilityMatrix.end()) { Writer.Write(RowIter->size()); - std::vector<int>::const_iterator ColIter = RowIter->begin(); - while (ColIter != RowIter->end()) - { + Common::Array<int>::const_iterator ColIter = RowIter->begin(); + while (ColIter != RowIter->end()) { Writer.Write(*ColIter); ++ColIter; } @@ -402,40 +375,36 @@ bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock & Writer) // ----------------------------------------------------------------------------- -bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock & Reader) -{ +bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock &Reader) { bool Result = true; - // Das Elternobjekt wurde schon über den Konstruktor von BS_Region geladen, daher müssen an dieser Stelle nur noch die zusätzlichen Daten von - // BS_WalkRegion geladen werden. + // The parent object was already loaded in the constructor of BS_Region, so at + // this point only the additional data from BS_WalkRegion needs to be loaded - // Knoten laden. + // Node load unsigned int NodeCount; Reader.Read(NodeCount); m_Nodes.clear(); m_Nodes.resize(NodeCount); - std::vector<BS_Vertex>::iterator It = m_Nodes.begin(); - while (It != m_Nodes.end()) - { + Common::Array<BS_Vertex>::iterator It = m_Nodes.begin(); + while (It != m_Nodes.end()) { Reader.Read(It->X); Reader.Read(It->Y); ++It; } - // Sichtbarkeitsmatrix laden. + // Visibility matrix load unsigned int RowCount; Reader.Read(RowCount); m_VisibilityMatrix.clear(); m_VisibilityMatrix.resize(RowCount); - std::vector< std::vector<int> >::iterator RowIter = m_VisibilityMatrix.begin(); - while (RowIter != m_VisibilityMatrix.end()) - { + Common::Array< Common::Array<int> >::iterator RowIter = m_VisibilityMatrix.begin(); + while (RowIter != m_VisibilityMatrix.end()) { unsigned int ColCount; Reader.Read(ColCount); RowIter->resize(ColCount); - std::vector<int>::iterator ColIter = RowIter->begin(); - while (ColIter != RowIter->end()) - { + Common::Array<int>::iterator ColIter = RowIter->begin(); + while (ColIter != RowIter->end()) { Reader.Read(*ColIter); ++ColIter; } @@ -445,3 +414,5 @@ bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock & Reader) return Result && Reader.IsGood(); } + +} // End of namespace Sword25 diff --git a/engines/sword25/math/walkregion.h b/engines/sword25/math/walkregion.h index 8c61720a12..6b06c8ed30 100644 --- a/engines/sword25/math/walkregion.h +++ b/engines/sword25/math/walkregion.h @@ -35,83 +35,83 @@ #ifndef SWORD25_WALKREGION_H #define SWORD25_WALKREGION_H -#include "sword25/kernel/memlog_off.h" -#include <vector> -#include "sword25/kernel/memlog_on.h" - +#include "common/array.h" #include "sword25/kernel/common.h" #include "sword25/math/region.h" +namespace Sword25 { + // ----------------------------------------------------------------------------- -// Typdefinitionen +// Type definitions // ----------------------------------------------------------------------------- -typedef std::vector<BS_Vertex> BS_Path; +typedef Common::Array<BS_Vertex> BS_Path; // ----------------------------------------------------------------------------- -// Klassendefinition +// Class definitions // ----------------------------------------------------------------------------- /** - @brief Diese Klasse stellt die Region dar, in der sich der Hauptcharakter bewegen kann. -*/ -class BS_WalkRegion : public BS_Region -{ + * This class represents the region in which the main character can move + */ +class BS_WalkRegion : public BS_Region { friend class BS_Region; protected: BS_WalkRegion(); - BS_WalkRegion(BS_InputPersistenceBlock & Reader, unsigned int Handle); + BS_WalkRegion(BS_InputPersistenceBlock &Reader, unsigned int Handle); public: virtual ~BS_WalkRegion(); - virtual bool Init(const BS_Polygon & Contour, const std::vector<BS_Polygon> * pHoles = 0); + virtual bool Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles = 0); /** - @brief Ermittelt den kürzesten Weg zwischen zwei Punkten in der Region. - - Diese Methode verlangt, dass der Startpunkt innerhalb der Region liegt. Der Endpunkt darf außerhalb der Region liegen. In diesem - Fall wählt die Methode als Endpunkt den Punkt innerhalb der Region, der am dichtesten am Endpunkt liegt. - - @param X1 X-Koordinate des Startpunktes - @param Y1 Y-Koordinate des Startpunktes - @param X2 X-Koordinate des Zielpunktes - @param Y2 Y-Koordinate des Zielpunktes - @param Path ein leerer BS_Path, der den Ergebnispfad aufnehmen soll - @return Gibt false zurück, fall die Eingaben ungültig waren, ansonsten wird true zurückgegeben. + * Get the shortest path between two points in the region + * + * This method requires that the starting point lies within the region. The end point + * may lie outside the region. Int his case, the end is chosen as the cloest point to it + * that lies within the region. + * + * @param X1 X Co-ordinate of the start point + * @param Y1 Y Co-ordinate of the start point + * @param X2 X Co-ordinate of the end point + * @param Y2 Y Co-ordinate of the end point + * @param Path An empty BS_Path that will be set to the resulting path + * @return Returns false if the result is invalid, otherwise returns true. */ - bool QueryPath(int X1, int Y1, int X2, int Y2, BS_Path & Path) { return QueryPath(BS_Vertex(X1, Y1), BS_Vertex(X2, Y2), Path); } + bool QueryPath(int X1, int Y1, int X2, int Y2, BS_Path &Path) { + return QueryPath(BS_Vertex(X1, Y1), BS_Vertex(X2, Y2), Path); + } /** - @brief Ermittelt den kürzesten Weg zwischen zwei Punkten in der Region. - - Diese Methode verlangt, dass der Startpunkt innerhalb der Region liegt. Der Endpunkt darf außerhalb der Region liegen. In diesem - Fall wählt die Methode als Endpunkt den Punkt innerhalb der Region, der am dichtesten am Endpunkt liegt. - - @param StartPoint der Startpunkt - @param EndPoint der Endpunkt - @param Path ein leerer BS_Path, der den Ergebnispfad aufnehmen soll - @return Gibt false zurück, fall die Eingaben ungültig waren, ansonsten wird true zurückgegeben. + * Get the shortest path between two points in the region. + * + * @param StartPoint The start point + * @param EndPoint The end point + * @param Path An empty BS_Path that will be set to the resulting path + * @return Returns false if the result is invalid, otherwise returns true. */ bool QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path & Path); virtual void SetPos(int X, int Y); - const std::vector<BS_Vertex> & GetNodes() const { return m_Nodes; } - const std::vector< std::vector<int> > & GetVisibilityMatrix() const { return m_VisibilityMatrix; } + const Common::Array<BS_Vertex> &GetNodes() const { return m_Nodes; } + const Common::Array< Common::Array<int> > &GetVisibilityMatrix() const { return m_VisibilityMatrix; } - virtual bool Persist(BS_OutputPersistenceBlock & Writer); - virtual bool Unpersist(BS_InputPersistenceBlock & Reader); + virtual bool Persist(BS_OutputPersistenceBlock &Writer); + virtual bool Unpersist(BS_InputPersistenceBlock &Reader); private: - std::vector<BS_Vertex> m_Nodes; - std::vector< std::vector<int> > m_VisibilityMatrix; + Common::Array<BS_Vertex> m_Nodes; + Common::Array< Common::Array<int> > m_VisibilityMatrix; void InitNodeVector(); void ComputeVisibilityMatrix(); - bool CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & End) const; - bool FindPath(const BS_Vertex & Start, const BS_Vertex & End, BS_Path & Path) const; + bool CheckAndPrepareStartAndEnd(BS_Vertex &Start, BS_Vertex &End) const; + bool FindPath(const BS_Vertex &Start, const BS_Vertex &End, BS_Path &Path) const; }; +} // End of namespace Sword25 + #endif diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp index 22d2a28072..8af0128c72 100644 --- a/engines/sword25/script/luascript.cpp +++ b/engines/sword25/script/luascript.cpp @@ -540,7 +540,7 @@ bool BS_LuaScriptEngine::Unpersist(BS_InputPersistenceBlock &Reader) { ClearGlobalTable(m_State, ClearExceptionsSecondPass); // Persisted Lua data - vector<unsigned char> chunkData; + Common::Array<unsigned char> chunkData; Reader.Read(chunkData); // Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data |