diff --git a/lib/bc b/lib/bc index 367b814..b9dd205 160000 --- a/lib/bc +++ b/lib/bc @@ -1 +1 @@ -Subproject commit 367b8149f36a1e4c2aad066e0cf9cd1e07ae7d88 +Subproject commit b9dd205765782a44afc03740f3047ab2be5f1c4f diff --git a/storm/Big.cpp b/storm/Big.cpp index 5822bec..29b5dcf 100644 --- a/storm/Big.cpp +++ b/storm/Big.cpp @@ -1,17 +1,18 @@ #include "storm/Big.hpp" +#include "storm/big/BigData.hpp" #include "storm/big/Ops.hpp" #include #include -void SBigAdd(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigAdd(BigData* a, BigData* b, BigData* c) { Add(a->Primary(), b->Primary(), c->Primary()); } -void SBigAnd(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigAnd(BigData* a, BigData* b, BigData* c) { And(a->Primary(), b->Primary(), c->Primary()); } -void SBigBitLen(BigData* num, uint32_t* len) { +void STORMAPI SBigBitLen(BigData* num, uint32_t* len) { auto& buffer = num->Primary(); buffer.Trim(); @@ -28,24 +29,23 @@ void SBigBitLen(BigData* num, uint32_t* len) { *len = (index * 32) + bitIndex + 1; } -int32_t SBigCompare(BigData* a, BigData* b) { +int32_t STORMAPI SBigCompare(BigData* a, BigData* b) { return Compare(a->Primary(), b->Primary()); } -void SBigCopy(BigData* a, BigData* b) { +void STORMAPI SBigCopy(BigData* a, BigData* b) { a->m_primary = b->m_primary; } -void SBigDec(BigData* a, BigData* b) { +void STORMAPI SBigDec(BigData* a, BigData* b) { Sub(a->m_primary, b->m_primary, 1); } -void SBigDel(BigData* num) { - num->~BigData(); - SMemFree(num); +void STORMAPI SBigDel(BigData* num) { + delete num; } -void SBigDiv(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigDiv(BigData* a, BigData* b, BigData* c) { uint32_t allocCount = 0; BigBuffer& buf = a->Stack().Alloc(&allocCount); @@ -54,39 +54,39 @@ void SBigDiv(BigData* a, BigData* b, BigData* c) { a->Stack().Free(allocCount); } -void SBigFromBinary(BigData* num, const void* data, uint32_t bytes) { +void STORMAPI SBigFromBinary(BigData* num, const void* data, uint32_t bytes) { FromBinary(num->Primary(), data, bytes); } -void SBigFromStr(BigData* num, const char *str) { +void STORMAPI SBigFromStr(BigData* num, const char *str) { FromStr(num->Primary(), str); } -void SBigFromUnsigned(BigData* num, uint32_t val) { +void STORMAPI SBigFromUnsigned(BigData* num, uint32_t val) { FromUnsigned(num->Primary(), val); } -void SBigInc(BigData* a, BigData* b) { +void STORMAPI SBigInc(BigData* a, BigData* b) { Add(a->Primary(), b->Primary(), 1); } -int32_t SBigIsEven(BigData* a) { +int32_t STORMAPI SBigIsEven(BigData* a) { return IsEven(a->Primary()); } -int32_t SBigIsOdd(BigData* a) { +int32_t STORMAPI SBigIsOdd(BigData* a) { return IsOdd(a->Primary()); } -int32_t SBigIsOne(BigData* a) { +int32_t STORMAPI SBigIsOne(BigData* a) { return IsOne(a->Primary()); } -int32_t SBigIsZero(BigData* a) { +int32_t STORMAPI SBigIsZero(BigData* a) { return IsZero(a->Primary()); } -void SBigMod(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigMod(BigData* a, BigData* b, BigData* c) { uint32_t allocCount = 0; auto& scratch = a->Stack().Alloc(&allocCount); @@ -95,44 +95,43 @@ void SBigMod(BigData* a, BigData* b, BigData* c) { a->Stack().Free(allocCount); } -void SBigMul(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigMul(BigData* a, BigData* b, BigData* c) { Mul(a->Primary(), b->Primary(), c->Primary(), a->Stack()); } -void SBigNew(BigData** num) { - auto m = SMemAlloc(sizeof(BigData), __FILE__, __LINE__, 0x0); - *num = new (m) BigData(); +void STORMAPI SBigNew(BigData** num) { + *num = STORM_NEW(BigData); } -void SBigNot(BigData* a, BigData* b) { +void STORMAPI SBigNot(BigData* a, BigData* b) { Not(a->Primary(), b->Primary()); } -void SBigOr(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigOr(BigData* a, BigData* b, BigData* c) { Or(a->Primary(), b->Primary(), c->Primary()); } -void SBigPowMod(BigData* a, BigData* b, BigData* c, BigData* d) { +void STORMAPI SBigPowMod(BigData* a, BigData* b, BigData* c, BigData* d) { PowMod(a->Primary(), b->Primary(), c->Primary(), d->Primary(), a->Stack()); } -void SBigShl(BigData* a, BigData* b, uint32_t shift) { +void STORMAPI SBigShl(BigData* a, BigData* b, uint32_t shift) { Shl(a->Primary(), b->Primary(), shift); } -void SBigShr(BigData* a, BigData* b, uint32_t shift) { +void STORMAPI SBigShr(BigData* a, BigData* b, uint32_t shift) { Shr(a->Primary(), b->Primary(), shift); } -void SBigSquare(BigData* a, BigData* b) { +void STORMAPI SBigSquare(BigData* a, BigData* b) { Square(a->Primary(), b->Primary(), a->Stack()); } -void SBigSub(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigSub(BigData* a, BigData* b, BigData* c) { Sub(a->Primary(), b->Primary(), c->Primary()); } -void SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes) { +void STORMAPI SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes) { auto& output = num->Output(); ToBinary(output, num->Primary()); @@ -144,6 +143,10 @@ void SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t } } -void SBigXor(BigData* a, BigData* b, BigData* c) { +void STORMAPI SBigToUnsigned(BigData* num, uint32_t* val) { + ToUnsigned(val, num->Primary()); +} + +void STORMAPI SBigXor(BigData* a, BigData* b, BigData* c) { Xor(a->Primary(), b->Primary(), c->Primary()); } diff --git a/storm/Big.hpp b/storm/Big.hpp index f39a90e..c056078 100644 --- a/storm/Big.hpp +++ b/storm/Big.hpp @@ -1,63 +1,66 @@ #ifndef STORM_BIG_HPP #define STORM_BIG_HPP -#include "storm/big/BigData.hpp" -#include +#include "Core.hpp" -void SBigAdd(BigData* a, BigData* b, BigData* c); +class BigData; -void SBigAnd(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigAdd(BigData* a, BigData* b, BigData* c); -void SBigBitLen(BigData* num, uint32_t* len); +void STORMAPI SBigAnd(BigData* a, BigData* b, BigData* c); -int32_t SBigCompare(BigData* a, BigData* b); +void STORMAPI SBigBitLen(BigData* num, uint32_t* len); -void SBigCopy(BigData* a, BigData* b); +int32_t STORMAPI SBigCompare(BigData* a, BigData* b); -void SBigDec(BigData* a, BigData* b); +void STORMAPI SBigCopy(BigData* a, BigData* b); -void SBigDel(BigData* num); +void STORMAPI SBigDec(BigData* a, BigData* b); -void SBigDiv(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigDel(BigData* num); -void SBigFromBinary(BigData* num, const void* data, uint32_t bytes); +void STORMAPI SBigDiv(BigData* a, BigData* b, BigData* c); -void SBigFromStr(BigData* num, const char* str); +void STORMAPI SBigFromBinary(BigData* num, const void* data, uint32_t bytes); -void SBigFromUnsigned(BigData* num, uint32_t val); +void STORMAPI SBigFromStr(BigData* num, const char* str); -void SBigInc(BigData* a, BigData* b); +void STORMAPI SBigFromUnsigned(BigData* num, uint32_t val); -int32_t SBigIsEven(BigData* a); +void STORMAPI SBigInc(BigData* a, BigData* b); -int32_t SBigIsOdd(BigData* a); +int32_t STORMAPI SBigIsEven(BigData* a); -int32_t SBigIsOne(BigData* a); +int32_t STORMAPI SBigIsOdd(BigData* a); -int32_t SBigIsZero(BigData* a); +int32_t STORMAPI SBigIsOne(BigData* a); -void SBigMod(BigData* a, BigData* b, BigData* c); +int32_t STORMAPI SBigIsZero(BigData* a); -void SBigMul(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigMod(BigData* a, BigData* b, BigData* c); -void SBigNew(BigData** num); +void STORMAPI SBigMul(BigData* a, BigData* b, BigData* c); -void SBigNot(BigData* a, BigData* b); +void STORMAPI SBigNew(BigData** num); -void SBigOr(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigNot(BigData* a, BigData* b); -void SBigPowMod(BigData* a, BigData* b, BigData* c, BigData* d); +void STORMAPI SBigOr(BigData* a, BigData* b, BigData* c); -void SBigShl(BigData* a, BigData* b, uint32_t shift); +void STORMAPI SBigPowMod(BigData* a, BigData* b, BigData* c, BigData* d); -void SBigShr(BigData* a, BigData* b, uint32_t shift); +void STORMAPI SBigShl(BigData* a, BigData* b, uint32_t shift); -void SBigSquare(BigData* a, BigData* b); +void STORMAPI SBigShr(BigData* a, BigData* b, uint32_t shift); -void SBigSub(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigSquare(BigData* a, BigData* b); -void SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes); +void STORMAPI SBigSub(BigData* a, BigData* b, BigData* c); -void SBigXor(BigData* a, BigData* b, BigData* c); +void STORMAPI SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes); + +void STORMAPI SBigXor(BigData* a, BigData* b, BigData* c); + +void STORMAPI SBigToUnsigned(BigData* num, uint32_t* val); #endif diff --git a/storm/CMakeLists.txt b/storm/CMakeLists.txt index e381544..34c9d48 100644 --- a/storm/CMakeLists.txt +++ b/storm/CMakeLists.txt @@ -7,7 +7,7 @@ file(GLOB STORM_SOURCES "crypto/*.cpp" "error/*.cpp" "hash/*.cpp" - "option*/*.cpp" + "option/*.cpp" "queue/*.cpp" "string/*.cpp" "thread/*.cpp" diff --git a/storm/Core.cpp b/storm/Core.cpp new file mode 100644 index 0000000..0a4df63 --- /dev/null +++ b/storm/Core.cpp @@ -0,0 +1,31 @@ +#include "Core.hpp" +#include "Event.hpp" +#include "Region.hpp" +#include "String.hpp" +#include "Transparency.hpp" + +int32_t STORMAPI StormDestroy() { + // Combined list of all destroy calls found in every game (as documentation) + + // SErrSetBlizzardErrorFunction(nullptr); // SC 1.17 + // SDlgDestroy(); // SC 1.17 + // SGdiDestroy(); // SC 1.17 + // SVidDestroy(); // SC 1.17 + // SDrawDestroy(); // SC 1.17 + SRgnDestroy(); // WoW 3.3.5 (win), SC 1.17 + // SMsgDestroy(); // WoW 3.3.5 (win), SC 1.17 + // SNetDestroy(); // SC 1.17 + SEvtDestroy(); // WoW 3.3.5 (win) + // SBltDestroy(); // SC 1.17 + // SCodeDestroy(); // SC 1.17 + // SCmdDestroy(); // WoW 3.3.5 (win+mac), SC 1.17 + // SFileDestroy(); // WoW 3.3.5 (mac)?, SC 1.17 + // SFile::Destroy(); // WoW 0.5.3 (win)? + // SCompDestroy(); // WoW 3.3.5 (win)? + SStrDestroy(); // WoW 3.3.5 (mac), SC 1.17 + // SRegDestroy(); // WoW 3.3.5 (mac) + // SErrDestroy(); // WoW 3.3.5 (mac) + // SLogDestroy(); // WoW 3.3.5 (mac) + STransDestroy(); // SC 1.17 + return 1; +} diff --git a/storm/Core.hpp b/storm/Core.hpp new file mode 100644 index 0000000..50834ce --- /dev/null +++ b/storm/Core.hpp @@ -0,0 +1,23 @@ +#ifndef STORM_CORE_HPP +#define STORM_CORE_HPP + +#include + +#ifndef STORMAPI +#if defined(_MSC_VER) + #define STORMAPI __stdcall + #define STORMCDECL __cdecl +#else + #define STORMAPI + #define STORMCDECL +#endif +#endif + +#if !defined(WHOA_SYSTEM_WIN) +typedef void* HANDLE; +typedef void* LPOVERLAPPED; +#endif + +int32_t STORMAPI StormDestroy(); + +#endif diff --git a/storm/Event.cpp b/storm/Event.cpp new file mode 100644 index 0000000..ed27168 --- /dev/null +++ b/storm/Event.cpp @@ -0,0 +1,420 @@ +#include "Event.hpp" + +#include + +#include "list/TSList.hpp" +#include "thread/CCritSect.hpp" +#include "Atomic.hpp" +#include "Error.hpp" +#include + +struct BREAKCMD : public TSLinkedNode { + void* data; +}; + +static CCritSect s_critsect; +static TSList> s_breakcmdlist; +static int32_t s_modified; +static ATOMIC32 s_dispatchesinprogress; + +struct _IDHASHENTRY { + uint32_t id; + uint32_t sequence; + SEVTHANDLER handler; + _IDHASHENTRY* next; +}; + +struct _IDHASHTABLE { + _IDHASHENTRY** data; + uint32_t size; + uint32_t used; + _IDHASHTABLE* next; +}; + +struct _TYPEHASHENTRY { + uint32_t type; + uint32_t subtype; + uint32_t sequence; + _IDHASHTABLE* idhashtable; + _TYPEHASHENTRY* next; +}; + +static _TYPEHASHENTRY **s_typehashtable; +static uint32_t s_typehashtablesize; +static uint32_t s_typehashtableused; + +// Fake function to make tests not bleed into each other +void SEvtCleanExtraDataForTests() { + s_breakcmdlist.Clear(); +} + +void DeleteIdHashTable(_IDHASHTABLE* pTable) { + for (uint32_t i = 0; i < pTable->size; i++) { + for (_IDHASHENTRY* pEntry = pTable->data[i]; pEntry; pEntry = pTable->data[i]) { + pTable->data[i] = pEntry->next; + delete pEntry; + } + } + STORM_FREE(pTable->data); + delete pTable; +} + +_TYPEHASHENTRY* FindTypeHashEntry(uint32_t type, uint32_t subtype) { + if (!s_typehashtable || s_typehashtablesize == 0) { + return nullptr; + } + + for (_TYPEHASHENTRY* pEntry = s_typehashtable[(s_typehashtablesize - 1) & (subtype ^ type)]; pEntry; pEntry = pEntry->next) { + if (pEntry->type == type && pEntry->subtype == subtype) { + return pEntry; + } + } + return nullptr; +} + +uint32_t ComputeNewTableSize(uint32_t size) { + uint32_t result = 1; + while (result <= size * 2 + 2) { + result *= 2; + } + return result; +} + +void CopyIdHashTable(_IDHASHTABLE *dest, _IDHASHTABLE *source) { + dest->size = source->size; + dest->used = source->used; + dest->data = (_IDHASHENTRY**)STORM_ALLOC(sizeof(_IDHASHENTRY*) * dest->size); + + for (uint32_t i = 0; i < source->size; i++) { + _IDHASHENTRY* pSourceData = source->data[i]; + _IDHASHENTRY** ppDestData = &dest->data[i]; + for (; pSourceData; pSourceData = pSourceData->next) { + _IDHASHENTRY* pNewEntry = STORM_NEW(_IDHASHENTRY); + + *ppDestData = pNewEntry; + *pNewEntry = *pSourceData; + ppDestData = &(*ppDestData)->next; + } + *ppDestData = nullptr; + } +} + +int32_t STORMAPI SEvtBreakHandlerChain(void* data) { + s_critsect.Enter(); + s_breakcmdlist.NewNode(2, 0, 0)->data = data; + s_critsect.Leave(); + return 1; +} + +int32_t STORMAPI SEvtDestroy() { + s_critsect.Enter(); + + for (uint32_t i = 0; i < s_typehashtablesize; i++) { + for (_TYPEHASHENTRY* pTypeEntry = s_typehashtable[i]; pTypeEntry; pTypeEntry = s_typehashtable[i]) { + for (_IDHASHTABLE* pTable = pTypeEntry->idhashtable; pTable; pTable = pTypeEntry->idhashtable) { + pTypeEntry->idhashtable = pTable->next; + DeleteIdHashTable(pTable); + } + s_typehashtable[i] = pTypeEntry->next; + delete pTypeEntry; + } + } + + if (s_typehashtable) { + delete s_typehashtable; + } + s_typehashtable = nullptr; + s_typehashtablesize = 0; + s_typehashtableused = 0; + + s_modified = 1; + + s_critsect.Leave(); + return 1; +} + +int32_t STORMAPI SEvtDispatch(uint32_t type, uint32_t subtype, uint32_t id, void* data) { + SInterlockedIncrement(&s_dispatchesinprogress); + + int32_t success = 0; + uint32_t currsequence = -1; + _IDHASHENTRY *currptr = nullptr; + + do { + s_critsect.Enter(); + + bool breakcmd = false; + for (BREAKCMD* curr = s_breakcmdlist.Head(); reinterpret_cast(curr) > 0; curr = s_breakcmdlist.RawNext(curr)) { + if (curr->data == data) { + breakcmd = true; + s_breakcmdlist.DeleteNode(curr); + break; + } + } + if (breakcmd) { + s_critsect.Leave(); + break; + } + + if (!currptr || s_modified) { + currptr = nullptr; + auto typeentry = FindTypeHashEntry(type, subtype); + if (typeentry) { + _IDHASHTABLE* idhash = typeentry->idhashtable; + if (idhash->data && idhash->size != 0) { + for (currptr = idhash->data[id & (idhash->size - 1)]; currptr; currptr = currptr->next) { + if (currptr->id == id && currptr->sequence < currsequence) { + break; + } + } + + if (s_dispatchesinprogress == 1) { + s_modified = 0; + } + } + } + } + + SEVTHANDLER handler = nullptr; + + if (currptr) { + handler = currptr->handler; + currsequence = currptr->sequence; + do { + currptr = currptr->next; + } while (currptr && currptr->id != id); + } + + s_critsect.Leave(); + + if (handler) { + success = 1; + handler(data); + } + } while(currptr); + + SInterlockedDecrement(&s_dispatchesinprogress); + + if (s_breakcmdlist.Head()) { + s_critsect.Enter(); + + for (BREAKCMD* curr = s_breakcmdlist.Head(); reinterpret_cast(curr) > 0;) { + if (curr->data == data) { + curr = s_breakcmdlist.DeleteNode(curr); + } + else { + curr = s_breakcmdlist.RawNext(curr); + } + } + + s_critsect.Leave(); + } + return success; +} + +int32_t STORMAPI SEvtPopState(uint32_t type, uint32_t subtype) { + int32_t success = 0; + s_critsect.Enter(); + + _TYPEHASHENTRY* typeentry = FindTypeHashEntry(type, subtype); + if (typeentry) { + _IDHASHTABLE *next = typeentry->idhashtable->next; + if (next) { + DeleteIdHashTable(typeentry->idhashtable); + typeentry->idhashtable = next; + } + else { + // This WILL hang if called without recursive CCritSect. + // Provide a hack since it never gets called in WoW anyway. + // It also doesn't get called by SC for that matter. Nothing calls it. Classic. + #if !defined(WHOA_STORM_C_CRIT_SECT_RECURSIVE) + s_critsect.Leave(); + success = SEvtUnregisterType(type, subtype); + s_critsect.Enter(); + #else + success = SEvtUnregisterType(type, subtype); + #endif + } + } + + s_modified = 1; + s_critsect.Leave(); + return success; +} + +int32_t STORMAPI SEvtPushState(uint32_t type, uint32_t subtype) { + int32_t success = 0; + s_critsect.Enter(); + + _TYPEHASHENTRY* pTypeHash = FindTypeHashEntry(type, subtype); + if (pTypeHash) { + _IDHASHTABLE* pNewTable = STORM_NEW(_IDHASHTABLE); + + CopyIdHashTable(pNewTable, pTypeHash->idhashtable); + pNewTable->next = pTypeHash->idhashtable; + pTypeHash->idhashtable = pNewTable; + + success = 1; + s_modified = 1; + } + + s_critsect.Leave(); + return success; +} + +int32_t STORMAPI SEvtRegisterHandler(uint32_t type, uint32_t subtype, uint32_t id, uint32_t flags, SEVTHANDLER handler) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handler); + STORM_VALIDATE(!flags); + STORM_VALIDATE_END; + + s_critsect.Enter(); + + _TYPEHASHENTRY* pTypeHash = FindTypeHashEntry(type, subtype); + if (!pTypeHash) { + if (s_typehashtableused >= s_typehashtablesize / 2) { + uint32_t newsize = ComputeNewTableSize(s_typehashtableused); + _TYPEHASHENTRY** pNewTable = static_cast<_TYPEHASHENTRY**>(STORM_ALLOC_ZERO(sizeof(_TYPEHASHENTRY*) * newsize)); + + if (s_typehashtable) { + for (uint32_t i = 0; i < s_typehashtablesize; i++) { + _TYPEHASHENTRY* pNext; + for (_TYPEHASHENTRY* pTable = s_typehashtable[i]; pTable; pTable = pNext) { + pNext = pTable->next; + + uint32_t idx = (newsize - 1) & (pTable->type ^ pTable->subtype); + pTable->next = pNewTable[idx]; + pNewTable[idx] = pTable; + } + } + if (s_typehashtable) { + STORM_FREE(s_typehashtable); + } + } + s_typehashtable = pNewTable; + s_typehashtablesize = newsize; + } + + uint32_t idx = (s_typehashtablesize - 1) & (type ^ subtype); + + _TYPEHASHENTRY* pNewTypeHash = STORM_NEW_ZERO(_TYPEHASHENTRY); + + pNewTypeHash->type = type; + pNewTypeHash->subtype = subtype; + pNewTypeHash->idhashtable = STORM_NEW_ZERO(_IDHASHTABLE); + pNewTypeHash->next = s_typehashtable[idx]; + + s_typehashtable[idx] = pNewTypeHash; + s_typehashtableused++; + + pTypeHash = pNewTypeHash; + } + + if (pTypeHash->idhashtable->used >= pTypeHash->idhashtable->size / 2) { + uint32_t newsize = ComputeNewTableSize(pTypeHash->idhashtable->size); + _IDHASHENTRY** pNewTable = static_cast<_IDHASHENTRY**>(STORM_ALLOC_ZERO(sizeof(_IDHASHENTRY*) * newsize)); + _IDHASHENTRY*** pTempTable = static_cast<_IDHASHENTRY***>(STORM_ALLOC_ZERO(sizeof(_IDHASHENTRY*) * newsize)); + + for (uint32_t i = 0; i < newsize; i++) { + pTempTable[i] = &pNewTable[i]; + } + + if (pTypeHash->idhashtable->data && pTypeHash->idhashtable->size != 0) { + for (uint32_t i = 0; i < pTypeHash->idhashtable->size; i++) { + _IDHASHENTRY* pNext; + for (_IDHASHENTRY* pEntry = pTypeHash->idhashtable->data[i]; pEntry; pEntry = pNext) { + uint32_t idx = (newsize - 1) & pEntry->id; + pNext = pEntry->next; + pEntry->next = nullptr; + + *pTempTable[idx] = pEntry; + pTempTable[idx] = &pEntry->next; + } + } + } + + STORM_FREE(pTempTable); + if (pTypeHash->idhashtable->data) { + STORM_FREE(pTypeHash->idhashtable->data); + } + pTypeHash->idhashtable->data = pNewTable; + pTypeHash->idhashtable->size = newsize; + } + + uint32_t idx = (pTypeHash->idhashtable->size - 1) & id; + _IDHASHENTRY* pNewIdHash = STORM_NEW_ZERO(_IDHASHENTRY); + + pNewIdHash->id = id; + pNewIdHash->sequence = ++pTypeHash->sequence; + pNewIdHash->handler = handler; + + pNewIdHash->next = pTypeHash->idhashtable->data[idx]; + pTypeHash->idhashtable->data[idx] = pNewIdHash; + + pTypeHash->idhashtable->used++; + + s_modified = 1; + s_critsect.Leave(); + return 1; +} + +int32_t STORMAPI SEvtUnregisterHandler(uint32_t type, uint32_t subtype, uint32_t id, SEVTHANDLER handler) { + int32_t success = 0; + s_critsect.Enter(); + + _TYPEHASHENTRY* pTypeEntry = FindTypeHashEntry(type, subtype); + if (pTypeEntry) { + _IDHASHTABLE* pTable = pTypeEntry->idhashtable; + if (pTable->data && pTable->size != 0) { + _IDHASHENTRY** ppNextEntry = &pTable->data[id & (pTable->size - 1)]; + for (_IDHASHENTRY* pEntry = *ppNextEntry; pEntry; pEntry = *ppNextEntry) { + if (pEntry->id == id && (!handler || pEntry->handler == handler)) { + *ppNextEntry = pEntry->next; + delete pEntry; + + success = 1; + s_modified = 1; + pTable->used--; + } + else { + ppNextEntry = &pEntry->next; + } + } + } + } + + s_critsect.Leave(); + return success; +} + +int32_t STORMAPI SEvtUnregisterType(uint32_t type, uint32_t subtype) { + int32_t success = 0; + s_critsect.Enter(); + + _TYPEHASHENTRY *pTypeEntry = FindTypeHashEntry(type, subtype); + if (pTypeEntry) { + for (auto pTable = pTypeEntry->idhashtable; pTable; pTable = pTypeEntry->idhashtable) { + pTypeEntry->idhashtable = pTable->next; + DeleteIdHashTable(pTable); + } + + uint32_t idx = (s_typehashtablesize - 1) & (subtype ^ type); + _TYPEHASHENTRY** ppNextEntry = &s_typehashtable[idx]; + for (_TYPEHASHENTRY* pEntry = *ppNextEntry; pEntry; pEntry = *ppNextEntry) { + if (pEntry == pTypeEntry) { + *ppNextEntry = pEntry->next; + delete pEntry; + s_typehashtableused--; + } + else { + ppNextEntry = &pEntry->next; + } + } + + success = 1; + s_modified = 1; + } + + s_critsect.Leave(); + return success; +} diff --git a/storm/Event.hpp b/storm/Event.hpp new file mode 100644 index 0000000..eb574d6 --- /dev/null +++ b/storm/Event.hpp @@ -0,0 +1,25 @@ +#ifndef STORM_EVENT_HPP +#define STORM_EVENT_HPP + +#include +#include "Core.hpp" + +typedef void (STORMAPI* SEVTHANDLER)(void*); + +int32_t STORMAPI SEvtBreakHandlerChain(void* data); + +int32_t STORMAPI SEvtDestroy(); + +int32_t STORMAPI SEvtDispatch(uint32_t type, uint32_t subtype, uint32_t id, void* data); + +int32_t STORMAPI SEvtPopState(uint32_t type, uint32_t subtype); + +int32_t STORMAPI SEvtPushState(uint32_t type, uint32_t subtype); + +int32_t STORMAPI SEvtRegisterHandler(uint32_t type, uint32_t subtype, uint32_t id, uint32_t flags, SEVTHANDLER handler); + +int32_t STORMAPI SEvtUnregisterHandler(uint32_t type, uint32_t subtype, uint32_t id, SEVTHANDLER handler); + +int32_t STORMAPI SEvtUnregisterType(uint32_t type, uint32_t subtype); + +#endif diff --git a/storm/Handle.hpp b/storm/Handle.hpp index 462dc70..d365515 100644 --- a/storm/Handle.hpp +++ b/storm/Handle.hpp @@ -1,24 +1,21 @@ #ifndef STORM_HANDLE_HPP #define STORM_HANDLE_HPP -#if !defined(DECLARE_HANDLE) -#define DECLARE_HANDLE(name) \ - struct name##__; \ +#define DECLARE_STORM_HANDLE(name) \ + struct name##__ { \ + int32_t unused; \ + }; \ typedef struct name##__* name -#endif -#if !defined(DECLARE_STRICT_HANDLE) -#define DECLARE_STRICT_HANDLE(name) \ +#define DECLARE_STORM_STRICT_HANDLE(name) \ typedef struct name##__ { \ int unused; \ }* name -#endif -#if !defined(DECLARE_DERIVED_HANDLE) -#define DECLARE_DERIVED_HANDLE(name, base) \ - typedef struct name##__ : public base##__ { \ - int unused; \ - }* name -#endif +#define DECLARE_STORM_CHILD_HANDLE(name, super) \ + struct name##__ : public super##__ { \ + int32_t unused; \ + }; \ + typedef struct name##__* name #endif diff --git a/storm/Log.hpp b/storm/Log.hpp index f1053ca..2cf486e 100644 --- a/storm/Log.hpp +++ b/storm/Log.hpp @@ -12,8 +12,8 @@ #define STORM_LOG_FLAG_NO_FILE 2 // Don't use log file (use OutputDebugString or console only) #define STORM_LOG_FLAG_APPEND 4 // Don't truncate existing log file -DECLARE_STRICT_HANDLE(HSLOG); -DECLARE_STRICT_HANDLE(HLOCKEDLOG); +DECLARE_STORM_STRICT_HANDLE(HSLOG); +DECLARE_STORM_STRICT_HANDLE(HLOCKEDLOG); void SLogInitialize(); int32_t SLogIsInitialized(); diff --git a/storm/Region.cpp b/storm/Region.cpp index 9ff47bc..cbf1054 100644 --- a/storm/Region.cpp +++ b/storm/Region.cpp @@ -3,10 +3,21 @@ #include "storm/Error.hpp" #include "storm/Hash.hpp" #include "storm/Thread.hpp" + #include static TSExportTableSyncReuse s_rgntable; +void DeleteCombinedRect(TSGrowableArray* combinedArray, uint32_t index); +void DeleteRect(RECTF* rect); +void DeleteSourceRect(TSGrowableArray* sourceArray, uint32_t index); +int32_t IsNullRect(const RECTF* rect); + +void AddCombinedRect(TSGrowableArray* combinedArray, const RECTF* rect) { + RECTF* newRect = combinedArray->New(); + *newRect = *rect; +} + void AddSourceRect(TSGrowableArray* sourceArray, const RECTF* rect, void* param, int32_t sequence, uint32_t flags) { auto source = sourceArray->New(); @@ -17,10 +28,91 @@ void AddSourceRect(TSGrowableArray* sourceArray, const RECTF* rect, void } int32_t CheckForIntersection(const RECTF* sourceRect, const RECTF* targetRect) { +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + return sourceRect->left < targetRect->right + && sourceRect->top < targetRect->bottom + && sourceRect->right > targetRect->left + && sourceRect->bottom > targetRect->top; +#else return sourceRect->left < targetRect->right && sourceRect->bottom < targetRect->top && sourceRect->right > targetRect->left && sourceRect->top > targetRect->bottom; +#endif +} + +void CombineRectangles(TSGrowableArray* combinedArray) { + for (uint32_t i = 1; i < combinedArray->Count(); i++) { + for (uint32_t j = 0; j < i; j++) { + RECTF* rctA = &(*combinedArray)[i]; + RECTF* rctB = &(*combinedArray)[j]; + + if (rctA->left == rctB->left && rctA->right == rctB->right) { + if (rctA->bottom == rctB->top || rctB->bottom == rctA->top) { +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + rctA->top = std::min(rctB->top, rctA->top); + rctA->bottom = std::max(rctB->bottom, rctA->bottom); +#else + rctA->bottom = std::min(rctB->bottom, rctA->bottom); + rctA->top = std::max(rctB->top, rctA->top); +#endif + DeleteRect(rctB); + break; + } + } + + if (rctA->left == rctB->right || rctB->left == rctA->right) { + if (rctA->bottom == rctB->bottom && rctA->top == rctB->top) { + rctA->left = std::min(rctB->left, rctA->left); + rctA->right = std::max(rctB->right, rctA->right); + DeleteRect(rctB); + break; + } + } + + if (rctA->left == rctB->right || rctB->left == rctA->right) { + RECTF newrect[5]; + +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + if (rctA->top < rctB->bottom && rctB->top < rctA->bottom) { + newrect[0] = { rctA->left, rctA->top, rctA->right, rctB->top }; + newrect[1] = { rctB->left, rctB->top, rctB->right, rctA->top }; + newrect[2] = { rctA->left, rctB->bottom, rctA->right, rctA->bottom }; + newrect[3] = { rctB->left, rctA->bottom, rctB->right, rctB->bottom }; + + newrect[4] = { + std::min(rctB->left, rctA->left), + std::max(rctB->top, rctA->top), + std::max(rctB->right, rctA->right), + std::min(rctB->bottom, rctA->bottom) + }; +#else + if (rctA->bottom < rctB->top && rctB->bottom < rctA->top) { + newrect[0] = { rctA->left, rctA->bottom, rctA->right, rctB->bottom }; + newrect[1] = { rctB->left, rctB->bottom, rctB->right, rctA->bottom }; + newrect[2] = { rctA->left, rctB->top, rctA->right, rctA->top }; + newrect[3] = { rctB->left, rctA->top, rctB->right, rctB->top }; + + newrect[4] = { + std::min(rctB->left, rctA->left), + std::max(rctB->bottom, rctA->bottom), + std::max(rctB->right, rctA->right), + std::min(rctB->top, rctA->top) + }; +#endif + + for (uint32_t k = 0; k < 5; k++) { + if (!IsNullRect(&newrect[k])) { + AddCombinedRect(combinedArray, &newrect[k]); + } + } + DeleteCombinedRect(combinedArray, i); + DeleteCombinedRect(combinedArray, j); + break; + } + } + } + } } int32_t CompareRects(const RECTF* rect1, const RECTF* rect2) { @@ -30,6 +122,10 @@ int32_t CompareRects(const RECTF* rect1, const RECTF* rect2) { && rect1->top == rect2->top; } +void DeleteCombinedRect(TSGrowableArray* combinedArray, uint32_t index) { + DeleteRect(&(*combinedArray)[index]); +} + void DeleteRect(RECTF* rect) { rect->left = std::numeric_limits::max(); rect->bottom = std::numeric_limits::max(); @@ -37,37 +133,249 @@ void DeleteRect(RECTF* rect) { rect->top = std::numeric_limits::max(); } -void FragmentSourceRectangles(TSGrowableArray* sourceArray, uint32_t firstIndex, uint32_t lastIndex, int32_t previousOverlap, const RECTF* rect, void* param, int32_t sequence) { - if (firstIndex >= lastIndex) { - AddSourceRect(sourceArray, rect, param, sequence, 0x1 | (previousOverlap ? 0x2 : 0x0)); +int SortFoundParamsCallback(const void* elem1, const void* elem2) { + const FOUNDPARAM* param1 = static_cast(elem1); + const FOUNDPARAM* param2 = static_cast(elem2); + + return param1->sequence - param2->sequence; +} + +void FindSourceParams(RGN* rgnptr, const RECTF* rect) { + if (CompareRects(rect, &rgnptr->foundparamsrect)) { return; } - auto overlapsExisting = previousOverlap; + rgnptr->foundparams.SetCount(0); + uint32_t sourceRects = rgnptr->source.Count(); + uint32_t params = 0; - for (uint32_t i = firstIndex; i < lastIndex; i++) { - auto source = &(*sourceArray)[i]; - - if (CheckForIntersection(rect, &source->rect)) { - if (!CompareRects(rect, &source->rect)) { - break; - } - - source->flags |= 0x2; - overlapsExisting = 1; + for (uint32_t i = 0; i < sourceRects; i++) { + if (!CheckForIntersection(rect, &rgnptr->source[i].rect)) { + continue; } - if (i + 1 == lastIndex) { - AddSourceRect(sourceArray, rect, param, sequence, 0x1 | (previousOverlap ? 0x2 : 0x0)); + int32_t sequence = rgnptr->source[i].sequence; + int32_t found = 0; + + for (uint32_t j = 0; j < params; j++) { + if (rgnptr->foundparams[j].sequence == sequence) { + found = 1; + break; + } + } + + if (!found) { + FOUNDPARAM* newParam = rgnptr->foundparams.New(); + newParam->param = rgnptr->source[i].param; + newParam->sequence = sequence; + params++; + } + } + + std::qsort(rgnptr->foundparams.Ptr(), rgnptr->foundparams.Count(), sizeof(FOUNDPARAM), SortFoundParamsCallback); + rgnptr->foundparamsrect = *rect; +} + +void FragmentCombinedRectangles(TSGrowableArray* combinedArray, uint32_t firstIndex, uint32_t lastIndex, const RECTF* rect) { + uint32_t index; + RECTF* checkRect; + + for (index = firstIndex; index < lastIndex; index++) { + checkRect = &(*combinedArray)[index]; + if (CheckForIntersection(rect, checkRect)) { + break; + } + } + if (index >= lastIndex) { + AddCombinedRect(combinedArray, rect); + return; + } + + RECTF newrect[4]; + +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + newrect[0] = { rect->left, rect->top, rect->right, checkRect->top }; + newrect[1] = { rect->left, checkRect->bottom, rect->right, rect->bottom }; + newrect[2] = { + rect->left, + std::max(checkRect->top, rect->top), + checkRect->left, + std::min(checkRect->bottom, rect->bottom) + }; + newrect[3] = { + checkRect->right, + std::max(checkRect->top, rect->top), + rect->right, + std::min(checkRect->bottom, rect->bottom) + }; +#else + newrect[0] = { rect->left, rect->bottom, rect->right, checkRect->bottom }; + newrect[1] = { rect->left, checkRect->top, rect->right, rect->top }; + newrect[2] = { + rect->left, + std::max(checkRect->bottom, rect->bottom), + checkRect->left, + std::min(checkRect->top, rect->top) + }; + newrect[3] = { + checkRect->right, + std::max(checkRect->bottom, rect->bottom), + rect->right, + std::min(checkRect->top, rect->top) + }; +#endif + + for (uint32_t i = 0; i < 4; i++) { + if (!IsNullRect(&newrect[i])) { + FragmentCombinedRectangles(combinedArray, index + 1, lastIndex, &newrect[i]); + } + } +} + +void FragmentSourceRectangles(TSGrowableArray* sourceArray, uint32_t firstIndex, uint32_t lastIndex, int32_t previousOverlap, const RECTF* rect, void* param, int32_t sequence) { + auto overlapsExisting = previousOverlap; + + for (uint32_t index = firstIndex; index < lastIndex; index++) { + RECTF* checkRect = &(*sourceArray)[index].rect; + + if (CheckForIntersection(rect, checkRect)) { + if (CompareRects(rect, checkRect)) { + (*sourceArray)[index].flags |= SF_OVERLAPS; + overlapsExisting = 1; + continue; + } + + const RECTF* overlapRect[2] = { rect, checkRect }; + + uint32_t minLeft = rect->left > checkRect->left ? 1 : 0; + uint32_t maxLeft = checkRect->left > rect->left ? 1 : 0; + uint32_t minBottom = rect->bottom > checkRect->bottom ? 1 : 0; + uint32_t maxBottom = checkRect->bottom > rect->bottom ? 1 : 0; + uint32_t minRight = rect->right > checkRect->right ? 1 : 0; + uint32_t maxRight = checkRect->right > rect->right ? 1 : 0; + uint32_t minTop = rect->top > checkRect->top ? 1 : 0; + uint32_t maxTop = checkRect->top > rect->top ? 1 : 0; + + RECTF newRect[5]; + +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + newRect[0] = { + overlapRect[minTop]->left, + overlapRect[minTop]->top, + overlapRect[minTop]->right, + overlapRect[maxTop]->top, + }; + + newRect[1] = { + overlapRect[maxBottom]->left, + overlapRect[minBottom]->bottom, + overlapRect[maxBottom]->right, + overlapRect[maxBottom]->bottom, + }; + + newRect[2] = { + overlapRect[minLeft]->left, + overlapRect[maxTop]->top, + overlapRect[maxLeft]->left, + overlapRect[minBottom]->bottom, + }; + + newRect[3] = { + overlapRect[minRight]->right, + overlapRect[maxTop]->top, + overlapRect[maxRight]->right, + overlapRect[minBottom]->bottom, + }; + + newRect[4] = { + overlapRect[maxLeft]->left, + overlapRect[maxTop]->top, + overlapRect[minRight]->right, + overlapRect[minBottom]->bottom, + }; +#else + newRect[0] = { + overlapRect[minBottom]->left, + overlapRect[minBottom]->bottom, + overlapRect[minBottom]->right, + overlapRect[maxBottom]->bottom, + }; + + newRect[1] = { + overlapRect[maxTop]->left, + overlapRect[minTop]->top, + overlapRect[maxTop]->right, + overlapRect[maxTop]->top, + }; + + newRect[2] = { + overlapRect[minLeft]->left, + overlapRect[maxBottom]->bottom, + overlapRect[maxLeft]->left, + overlapRect[minTop]->top, + }; + + newRect[3] = { + overlapRect[minRight]->right, + overlapRect[maxBottom]->bottom, + overlapRect[maxRight]->right, + overlapRect[minTop]->top, + }; + + newRect[4] = { + overlapRect[maxLeft]->left, + overlapRect[maxBottom]->bottom, + overlapRect[minRight]->right, + overlapRect[minTop]->top, + }; +#endif + + int32_t overlaps[5][2]; + for (uint32_t j = 0; j < 5; j++) { + if (IsNullRect(&newRect[j])) { + overlaps[j][1] = 0; + overlaps[j][0] = 0; + } + else { + for (uint32_t k = 0; k < 2; k++) { + overlaps[j][k] = CheckForIntersection(&newRect[j], overlapRect[k]); + } + } + } + + for (uint32_t j = 0; j < 5; j++) { + if (overlaps[j][0]) { + FragmentSourceRectangles( + sourceArray, + index + 1, + lastIndex, + overlapsExisting || overlaps[j][1], + &newRect[j], + param, + sequence); + } + + if (overlaps[j][1]) { + uint32_t newFlags = (*sourceArray)[index].flags & ~SF_TEMPMASK; + newFlags |= overlaps[j][0] ? SF_OVERLAPS : SF_NONE; + + AddSourceRect(sourceArray, &newRect[j], (*sourceArray)[index].param, (*sourceArray)[index].sequence, newFlags); + } + } + DeleteSourceRect(sourceArray, index); return; } } - // TODO + AddSourceRect(sourceArray, rect, param, sequence, SF_ADDING | (overlapsExisting ? SF_OVERLAPS : SF_NONE)); } -int32_t IsNullRect(RECTF* rect) { +int32_t IsNullRect(const RECTF* rect) { +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + return rect->left >= rect->right || rect->top >= rect->bottom; +#else return rect->left >= rect->right || rect->bottom >= rect->top; +#endif } void ClearRegion(RGN* rgn) { @@ -92,24 +400,24 @@ void DeleteSourceRect(TSGrowableArray* sourceArray, uint32_t index) { DeleteRect(&source->rect); source->param = nullptr; source->sequence = -1; - source->flags = 0x0; + source->flags = SF_NONE; } void OptimizeSource(TSGrowableArray* sourceArray) { - for (uint32_t i = 0; i < sourceArray->Count(); i++) { - auto source = &(*sourceArray)[i]; + for (uint32_t index = 0; index < sourceArray->Count(); ) { + auto source = &(*sourceArray)[index]; if (IsNullRect(&source->rect)) { // Set current (null) element to last element auto last = &(*sourceArray)[sourceArray->Count() - 1]; - (*sourceArray)[i] = *last; - - // Decrement index by 1 to force null check on copied last element on next tick - i--; + (*sourceArray)[index] = *last; // Shrink by 1 (to account for the removal of the null element) sourceArray->SetCount(sourceArray->Count() - 1); } + else { + index++; + } } } @@ -117,81 +425,142 @@ void ProcessBooleanOperation(TSGrowableArray* sourceArray, int32_t combi for (uint32_t i = 0; i < sourceArray->Count(); i++) { auto source = &(*sourceArray)[i]; + int32_t remove = 0; switch (combineMode) { - case 1: { - if ((~source->flags >> 1) & 0x1) { - DeleteSourceRect(sourceArray, i); - } - + case SRGN_AND: + remove = !(source->flags & SF_OVERLAPS); + break; + case SRGN_XOR: + remove = source->flags & SF_OVERLAPS; + break; + case SRGN_DIFF: + remove = source->flags & (SF_ADDING | SF_OVERLAPS); + break; + case SRGN_COPY: + remove = source->flags & SF_ADDING; break; } - case 3: { - if (source->flags & 0x2) { - DeleteSourceRect(sourceArray, i); - } - - break; + if (remove) { + DeleteSourceRect(sourceArray, i); } - case 4: { - if (source->flags & (0x1 | 0x2)) { - DeleteSourceRect(sourceArray, i); - } - - break; - } - - case 5: { - if (source->flags & 0x1) { - DeleteSourceRect(sourceArray, i); - } - - break; - } - - default: - break; - } - - source->flags = 0x0; + source->flags = SF_NONE; } } -void SRgnCombineRectf(HSRGN handle, RECTF* rect, void* param, int32_t combineMode) { - STORM_ASSERT(handle); - STORM_ASSERT(rect); - STORM_ASSERT(combineMode >= 1); - STORM_ASSERT(combineMode <= 6); +int SortRectCallback(const void* elem1, const void* elem2) { + const RECTF* rct1 = static_cast(elem1); + const RECTF* rct2 = static_cast(elem2); + +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + double result = rct1->bottom == rct2->bottom ? rct1->left - rct2->left : rct1->bottom - rct2->bottom; +#else + double result = rct1->top == rct2->top ? rct1->left - rct2->left : rct1->top - rct2->top; +#endif + + if (result > 0.0) { + return 1; + } + + if (result < 0.0) { + return -1; + } + + return 0; +} + +void ProduceCombinedRectangles(RGN* rgn) { + rgn->combined.SetCount(0); + + uint32_t sourcerects = rgn->source.Count(); + SOURCE* sourcearray = rgn->source.Ptr(); + for (uint32_t i = 0; i < sourcerects; i++) { + if (!(sourcearray[i].flags & SF_PARAMONLY)) { + FragmentCombinedRectangles(&rgn->combined, 0, rgn->combined.Count(), &sourcearray[i].rect); + } + } + + CombineRectangles(&rgn->combined); + + std::qsort(rgn->combined.Ptr(), rgn->combined.Count(), sizeof(RECTF), SortRectCallback); + + for (uint32_t i = rgn->combined.Count(); i > 0; i = rgn->combined.Count()) { + if (!IsNullRect(&rgn->combined[i-1])) { + break; + } + + rgn->combined.SetCount(i - 1); + } +} + +void STORMAPI SRgnCombineRectf(HSRGN handle, const RECTF* rect, void* param, int32_t combineMode) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(rect); + STORM_VALIDATE(combineMode >= 1); + STORM_VALIDATE(combineMode <= 6); + STORM_VALIDATE_END_VOID; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + return; + } + + if (combineMode == SRGN_OR || combineMode == SRGN_PARAMONLY) { + if (!IsNullRect(rect)) { + rgn->sequence++; + AddSourceRect(&rgn->source, rect, param, rgn->sequence, combineMode == SRGN_PARAMONLY ? SF_PARAMONLY : SF_NONE); + } + } else { + if (!IsNullRect(rect)) { + rgn->sequence++; + FragmentSourceRectangles(&rgn->source, 0, rgn->source.Count(), 0, rect, param, rgn->sequence); + } + + ProcessBooleanOperation(&rgn->source, combineMode); + OptimizeSource(&rgn->source); + } + + InvalidateRegion(rgn); + s_rgntable.Unlock(lockedHandle); +} + +void STORMAPI SRgnCombineRecti(HSRGN handle, const RECT* rect, void* param, int32_t combineMode) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(rect); + STORM_VALIDATE_END_VOID; + + // NOTE: top and bottom get flipped, this is a bug in Storm + RECTF rectf = { + static_cast(rect->left), + static_cast(rect->top), + static_cast(rect->right), + static_cast(rect->bottom) + }; + SRgnCombineRectf(handle, &rectf, param, combineMode); +} + +void STORMAPI SRgnClear(HSRGN handle) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE_END_VOID; HLOCKEDRGN lockedHandle; auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); if (rgn) { - if (combineMode == 2 || combineMode == 6) { - if (!IsNullRect(rect)) { - rgn->sequence++; - AddSourceRect(&rgn->source, rect, param, rgn->sequence, combineMode == 6 ? 0x10000 : 0x0); - } - } else { - if (!IsNullRect(rect)) { - rgn->sequence++; - FragmentSourceRectangles(&rgn->source, 0, rgn->source.Count(), 0, rect, param, rgn->sequence); - } - - ProcessBooleanOperation(&rgn->source, combineMode); - OptimizeSource(&rgn->source); - } - - InvalidateRegion(rgn); + ClearRegion(rgn); + s_rgntable.Unlock(lockedHandle); } - - s_rgntable.Unlock(lockedHandle); } -void SRgnCreate(HSRGN* handlePtr, uint32_t reserved) { - STORM_ASSERT(handlePtr); - STORM_ASSERT(!reserved); +void STORMAPI SRgnCreate(HSRGN* handlePtr, uint32_t reserved) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handlePtr); + STORM_VALIDATE(!reserved); + STORM_VALIDATE_END_VOID; HLOCKEDRGN lockedHandle = nullptr; auto rgn = s_rgntable.NewLock(handlePtr, &lockedHandle); @@ -201,37 +570,81 @@ void SRgnCreate(HSRGN* handlePtr, uint32_t reserved) { s_rgntable.Unlock(lockedHandle); } -void SRgnDelete(HSRGN handle) { - STORM_ASSERT(handle); +void STORMAPI SRgnDelete(HSRGN handle) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE_END_VOID; s_rgntable.Delete(handle); } -void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) { - STORM_ASSERT(handle); - STORM_ASSERT(rect); +void STORMAPI SRgnDestroy() { + s_rgntable.Destroy(); +} - rect->left = std::numeric_limits::max(); - rect->bottom = std::numeric_limits::max(); - rect->right = std::numeric_limits::min(); - rect->top = std::numeric_limits::min(); +void STORMAPI SRgnDuplicate(HSRGN origHandle, HSRGN* handle, uint32_t reserved) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + *handle = nullptr; + + STORM_VALIDATE(origHandle); + STORM_VALIDATE(reserved == 0); + STORM_VALIDATE_END_VOID; + + HLOCKEDRGN origlockedhandle; + auto rgn = s_rgntable.Lock(origHandle, &origlockedhandle, 0); + + if (!rgn) { + return; + } + +#if defined(WHOA_STORM_C_CRIT_SECT_RECURSIVE) + HLOCKEDRGN newlockedhandle; + + auto newrgn = s_rgntable.NewLock(handle, &newlockedhandle); + *newrgn = *rgn; + s_rgntable.Unlock(newlockedhandle); +#else + auto newrgn = s_rgntable.New(handle); + *newrgn = *rgn; +#endif + + s_rgntable.Unlock(origlockedhandle); +} + +void STORMAPI SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(rect); + STORM_VALIDATE_END_VOID; + + *rect = { + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::min(), + std::numeric_limits::min(), + }; HLOCKEDRGN lockedHandle; auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); - if (!rgn) { - s_rgntable.Unlock(lockedHandle); return; } for (uint32_t i = 0; i < rgn->source.Count(); i++) { auto source = &rgn->source[i]; - if (!(source->flags & 0x10000)) { + if (!(source->flags & SF_PARAMONLY)) { rect->left = std::min(source->rect.left, rect->left); - rect->bottom = std::min(source->rect.bottom, rect->bottom); rect->right = std::max(source->rect.right, rect->right); + +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + rect->top = std::min(source->rect.top, rect->top); + rect->bottom = std::max(source->rect.bottom, rect->bottom); +#else + rect->bottom = std::min(source->rect.bottom, rect->bottom); rect->top = std::max(source->rect.top, rect->top); +#endif } } @@ -244,3 +657,239 @@ void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect) { rect->top = 0.0f; } } + +void STORMAPI SRgnGetBoundingRecti(HSRGN handle, RECT* rect) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(rect); + STORM_VALIDATE_END_VOID; + + RECTF rectf; + SRgnGetBoundingRectf(handle, &rectf); + + rect->left = static_cast(rectf.left); + rect->right = static_cast(rectf.right); +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + rect->top = static_cast(rectf.top); + rect->bottom = static_cast(rectf.bottom); +#else + // NOTE: top and bottom get flipped, this is a bug in Storm + rect->top = static_cast(rectf.bottom); + rect->bottom = static_cast(rectf.top); +#endif +} + +void STORMAPI SRgnGetRectParamsf(HSRGN handle, const RECTF* rect, uint32_t* numParams, void** buffer) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(rect); + STORM_VALIDATE(numParams); + STORM_VALIDATE_END_VOID; + + if (IsNullRect(rect)) { + *numParams = 0; + return; + } + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + *numParams = 0; + return; + } + + if (rgn->dirty) { + ProduceCombinedRectangles(rgn); + rgn->dirty = 0; + } + + FindSourceParams(rgn, rect); + + if (buffer) { + *numParams = std::min(*numParams, rgn->foundparams.Count()); + FOUNDPARAM* foundArray = rgn->foundparams.Ptr(); + + for (uint32_t i = 0; i < *numParams; i++) { + buffer[i] = foundArray[i].param; + } + } + else { + *numParams = rgn->foundparams.Count(); + } + + s_rgntable.Unlock(lockedHandle); +} + +void STORMAPI SRgnGetRectParamsi(HSRGN handle, const RECT* rect, uint32_t* numParams, void** buffer) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(rect); + STORM_VALIDATE_END_VOID; + + // NOTE: top and bottom get flipped, this is a bug in Storm + RECTF rectf = { + static_cast(rect->left), + static_cast(rect->top), + static_cast(rect->right), + static_cast(rect->bottom) + }; + SRgnGetRectParamsf(handle, &rectf, numParams, buffer); +} + +void STORMAPI SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(numRects); + STORM_VALIDATE_END_VOID; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + *numRects = 0; + return; + } + + if (rgn->dirty) { + ProduceCombinedRectangles(rgn); + rgn->dirty = 0; + } + + if (buffer) { + *numRects = std::min(*numRects, rgn->combined.Count()); + memcpy(buffer, rgn->combined.Ptr(), sizeof(rgn->combined.Ptr()[0]) * *numRects); + } + else { + *numRects = rgn->combined.Count(); + } + + s_rgntable.Unlock(lockedHandle); +} + +void STORMAPI SRgnGetRectsi(HSRGN handle, uint32_t* numRects, RECT* buffer) { + RECTF* bufferf = reinterpret_cast(buffer); + SRgnGetRectsf(handle, numRects, bufferf); + if (buffer) { + for (uint32_t i = 0; i < *numRects; i++) { +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + buffer[i].top = static_cast(bufferf[i].top); + buffer[i].bottom = static_cast(bufferf[i].bottom); +#else + float bottom = bufferf[i].bottom; + float top = bufferf[i].top; + + buffer[i].bottom = static_cast(bottom); + buffer[i].top = static_cast(top); +#endif + buffer[i].left = static_cast(bufferf[i].left); + buffer[i].right = static_cast(bufferf[i].right); + } + } +} + +int32_t STORMAPI SRgnIsPointInRegionf(HSRGN handle, float x, float y) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + return 0; + } + + int32_t result = 0; + + SOURCE* sourceArray = rgn->source.Ptr(); + uint32_t sourceRects = rgn->source.Count(); + for (uint32_t i = 0; i < sourceRects; i++) { + if (!(sourceArray[i].flags & SF_PARAMONLY)) { +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) + if (x >= sourceArray[i].rect.left && y >= sourceArray[i].rect.top && + x < sourceArray[i].rect.right && y < sourceArray[i].rect.bottom) { +#else + if (x >= sourceArray[i].rect.left && y >= sourceArray[i].rect.bottom && + x < sourceArray[i].rect.right && y < sourceArray[i].rect.top) { +#endif + result = 1; + break; + } + } + } + + s_rgntable.Unlock(lockedHandle); + return result; +} + +int32_t STORMAPI SRgnIsPointInRegioni(HSRGN handle, int32_t x, int32_t y) { + return SRgnIsPointInRegionf(handle, static_cast(x), static_cast(y)); +} + +int32_t STORMAPI SRgnIsRectInRegionf(HSRGN handle, const RECTF* rect) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE(rect); + STORM_VALIDATE_END; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + return 0; + } + + int32_t result = 0; + + SOURCE* sourceArray = rgn->source.Ptr(); + uint32_t sourceRects = rgn->source.Count(); + for (uint32_t i = 0; i < sourceRects; i++) { + if (!(sourceArray[i].flags & SF_PARAMONLY)) { + if (CheckForIntersection(rect, &sourceArray[i].rect)) { + result = 1; + break; + } + } + } + + s_rgntable.Unlock(lockedHandle); + return result; +} + +int32_t STORMAPI SRgnIsRectInRegioni(HSRGN handle, const RECT* rect) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(rect); + STORM_VALIDATE_END; + + // NOTE: top and bottom get flipped, this is a bug in Storm + RECTF rectf = { + static_cast(rect->left), + static_cast(rect->top), + static_cast(rect->right), + static_cast(rect->bottom) + }; + return SRgnIsRectInRegionf(handle, &rectf); +} + +void STORMAPI SRgnOffsetf(HSRGN handle, float xoffset, float yoffset) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(handle); + STORM_VALIDATE_END_VOID; + + HLOCKEDRGN lockedHandle; + auto rgn = s_rgntable.Lock(handle, &lockedHandle, 0); + if (!rgn) { + return; + } + + SOURCE* sourceArray = rgn->source.Ptr(); + uint32_t sourceRects = rgn->source.Count(); + for (uint32_t i = 0; i < sourceRects; i++) { + sourceArray[i].rect.left += xoffset; + sourceArray[i].rect.bottom += yoffset; + sourceArray[i].rect.right += xoffset; + sourceArray[i].rect.top += yoffset; + } + InvalidateRegion(rgn); + + s_rgntable.Unlock(lockedHandle); +} + +void STORMAPI SRgnOffseti(HSRGN handle, int32_t xoffset, int32_t yoffset) { + SRgnOffsetf(handle, static_cast(xoffset), static_cast(yoffset)); +} diff --git a/storm/Region.hpp b/storm/Region.hpp index e156141..020bb7a 100644 --- a/storm/Region.hpp +++ b/storm/Region.hpp @@ -2,14 +2,44 @@ #define STORM_REGION_HPP #include "storm/region/Types.hpp" -#include +#include "Core.hpp" -void SRgnCombineRectf(HSRGN handle, RECTF* rect, void* param, int32_t combineMode); +void STORMAPI SRgnClear(HSRGN handle); -void SRgnCreate(HSRGN* handlePtr, uint32_t reserved); +void STORMAPI SRgnCombineRectf(HSRGN handle, const RECTF* rect, void* param, int32_t combineMode); -void SRgnDelete(HSRGN handle); +void STORMAPI SRgnCombineRecti(HSRGN handle, const RECT* rect, void* param, int32_t combineMode); -void SRgnGetBoundingRectf(HSRGN handle, RECTF* rect); +void STORMAPI SRgnCreate(HSRGN* handlePtr, uint32_t reserved = 0); + +void STORMAPI SRgnDelete(HSRGN handle); + +void STORMAPI SRgnDestroy(); + +void STORMAPI SRgnDuplicate(HSRGN origHandle, HSRGN* handle, uint32_t reserved = 0); + +void STORMAPI SRgnGetBoundingRectf(HSRGN handle, RECTF* rect); + +void STORMAPI SRgnGetBoundingRecti(HSRGN handle, RECT* rect); + +void STORMAPI SRgnGetRectParamsf(HSRGN handle, const RECTF* rect, uint32_t* numParams, void** buffer); + +void STORMAPI SRgnGetRectParamsi(HSRGN handle, const RECT* rect, uint32_t* numParams, void** buffer); + +void STORMAPI SRgnGetRectsf(HSRGN handle, uint32_t* numRects, RECTF* buffer); + +void STORMAPI SRgnGetRectsi(HSRGN handle, uint32_t* numRects, RECT* buffer); + +int32_t STORMAPI SRgnIsPointInRegionf(HSRGN handle, float x, float y); + +int32_t STORMAPI SRgnIsPointInRegioni(HSRGN handle, int32_t x, int32_t y); + +int32_t STORMAPI SRgnIsRectInRegionf(HSRGN handle, const RECTF* rect); + +int32_t STORMAPI SRgnIsRectInRegioni(HSRGN handle, const RECT* rect); + +void STORMAPI SRgnOffsetf(HSRGN handle, float xoffset, float yoffset); + +void STORMAPI SRgnOffseti(HSRGN handle, int32_t xoffset, int32_t yoffset); #endif diff --git a/storm/String.cpp b/storm/String.cpp index 034c512..b6dc1f5 100644 --- a/storm/String.cpp +++ b/storm/String.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #if defined(WHOA_SYSTEM_WIN) #include @@ -51,6 +50,20 @@ int32_t s_initialized; double s_realDigit[20][10]; +const uint32_t s_hashtable[16] = { + 0x486E26EE, 0xDCAA16B3, 0xE1918EEF, 0x202DAFDB, + 0x341C7DC7, 0x1C365303, 0x40EF2D37, 0x65FD5E49, + 0xD6057177, 0x904ECE93, 0x1C38024F, 0x98FD323B, + 0xE3061AE7, 0xA39B0FA1, 0x9797F25F, 0xE4444563, +}; + +const uint64_t s_hashtable64[16] = { + 0x486E26EEDCAA16B3ULL, 0xE1918EEF202DAFDBULL, 0x341C7DC71C365303ULL, 0x40EF2D3765FD5E49ULL, + 0xD6057177904ECE93ULL, 0x1C38024F98FD323BULL, 0xE3061AE7A39B0FA1ULL, 0x9797F25FE4444563ULL, + 0xCD2EC20C8DC1B898ULL, 0x31759633799A306DULL, 0x8C2063852E6E9627ULL, 0x79237D9973922C66ULL, + 0x8728628D28628824ULL, 0x8F1F7E9625887795ULL, 0x296E3281389C0D60ULL, 0x6F4893CA61636542ULL, +}; + void GetNextTextUpper(uint32_t* orig, const char** string, uint32_t* upper) { uint8_t byte = **string; int32_t v3 = bytesFromUTF8[byte]; @@ -177,7 +190,7 @@ void InitializeFloatDigits() { } } -size_t ISStrVPrintf(const char* format, va_list va, char* dest, size_t maxchars) { +size_t ISStrVPrintf(char* dest, size_t maxchars, const char* format, va_list va) { if (!maxchars) { return 0; } @@ -200,14 +213,14 @@ size_t ISStrVPrintf(const char* format, va_list va, char* dest, size_t maxchars) return result; } -void SStrInitialize() { +void STORMAPI SStrInitialize() { if (!s_initialized) { InitializeFloatDigits(); s_initialized = 1; } } -char* SStrChr(char* string, char search) { +char* STORMAPI SStrChr(char* string, char search) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -227,7 +240,7 @@ char* SStrChr(char* string, char search) { return string; } -const char* SStrChr(const char* string, char search) { +const char* STORMAPI SStrChr(const char* string, char search) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -247,7 +260,20 @@ const char* SStrChr(const char* string, char search) { return string; } -char* SStrChrR(char* string, char search) { +const char* STORMAPI SStrChrBidir(const char* string, char search, int32_t reverse) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + + if (reverse) { + return SStrChrR(string, search); + } + else { + return SStrChr(string, search); + } +} + +char* STORMAPI SStrChrR(char* string, char search) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -263,7 +289,7 @@ char* SStrChrR(char* string, char search) { return result; } -const char* SStrChrR(const char* string, char search) { +const char* STORMAPI SStrChrR(const char* string, char search) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -279,11 +305,21 @@ const char* SStrChrR(const char* string, char search) { return result; } -int32_t SStrCmp(const char* string1, const char* string2, size_t maxchars) { +int32_t STORMAPI SStrCmp(const char* string1, const char* string2, size_t maxchars) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string1); + STORM_VALIDATE(string2); + STORM_VALIDATE_END; + return strncmp(string1, string2, maxchars); } -int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars) { +int32_t STORMAPI SStrCmpI(const char* string1, const char* string2, size_t maxchars) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string1); + STORM_VALIDATE(string2); + STORM_VALIDATE_END; + #if defined(WHOA_SYSTEM_WIN) return _strnicmp(string1, string2, maxchars); #endif @@ -293,7 +329,7 @@ int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars) { #endif } -size_t SStrCopy(char* dest, const char* source, size_t destsize) { +size_t STORMAPI SStrCopy(char* dest, const char* source, size_t destsize) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(dest); STORM_VALIDATE(source); @@ -328,22 +364,15 @@ size_t SStrCopy(char* dest, const char* source, size_t destsize) { return static_cast(destbuf - dest); } -size_t SStrNCopy(char* dest, const char* source, size_t maxchars, size_t destsize) { - STORM_VALIDATE_BEGIN; - STORM_VALIDATE(dest); - STORM_VALIDATE(source); - STORM_VALIDATE_END; - - auto length = strnlen(source, maxchars); - if (destsize) { - auto count = std::min(length, destsize - 1); - memcpy(dest, source, count); - dest[count] = '\0'; - } - return length; +void STORMAPI SStrDestroy() { + // nothing to do } -char* SStrDupA(const char* string, const char* filename, uint32_t linenumber) { +char* STORMAPI SStrDupA(const char* string, const char* filename, uint32_t linenumber) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + size_t len = SStrLen(string) + 1; char* dup = static_cast(SMemAlloc(len, filename, linenumber, 0x0)); memcpy(dup, string, len); @@ -351,7 +380,43 @@ char* SStrDupA(const char* string, const char* filename, uint32_t linenumber) { return dup; } -uint32_t SStrHashHT(const char* string) { +uint32_t STORMAPI SStrHash(const char* string, uint32_t flags, uint32_t seed) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + + uint32_t result = seed ? seed : 0x7FED7FED; + uint32_t adjust = 0xEEEEEEEE; + uint32_t ch; + + if (flags & SSTR_HASH_CASESENSITIVE) { + for (; *string; string++) { + ch = *string; + + result = (s_hashtable[ch / 16] - s_hashtable[ch % 16]) ^ (adjust + result); + adjust = 33 * adjust + result + ch + 3; + } + } + else { + for (; *string; string++) { + ch = *string; + + if (ch >= 'a' && ch <= 'z') { + ch -= 32; + } + + if (ch == '/') { + ch = '\\'; + } + + result = (s_hashtable[ch / 16] - s_hashtable[ch % 16]) ^ (adjust + result); + adjust = 33 * adjust + result + ch + 3; + } + } + return result ? result : 1; +} + +uint32_t STORMAPI SStrHashHT(const char* string) { char normalized[0x400]; char* buf = normalized; @@ -382,7 +447,51 @@ uint32_t SStrHashHT(const char* string) { return bjhash((uint8_t*)&normalized, length, 0); } -size_t SStrLen(const char* string) { +int64_t STORMAPI SStrHash64(const char* string, uint32_t flags, int64_t seed) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + + int64_t result = seed ? seed : 0x7FED7FED7FED7FEDLL; + int64_t adjust = 0xEEEEEEEEEEEEEEEELL; + uint32_t ch; + + if (flags & SSTR_HASH_CASESENSITIVE) { + for (; *string; string++) { + ch = static_cast(*string); + +#if defined(WHOA_SSTRHASH64_SUBTRACTS) + result = (s_hashtable64[ch / 16] - s_hashtable64[ch % 16]) ^ (adjust + result); +#else + result = (s_hashtable64[ch / 16] + s_hashtable64[ch % 16]) ^ (adjust + result); +#endif + adjust = 33 * adjust + result + ch + 3; + } + } + else { + for (; *string; string++) { + ch = static_cast(*string); + + if (ch >= 'a' && ch <= 'z') { + ch -= 32; + } + + if (ch == '/') { + ch = '\\'; + } + +#if defined(WHOA_SSTRHASH64_SUBTRACTS) + result = (s_hashtable64[ch / 16] - s_hashtable64[ch % 16]) ^ (adjust + result); +#else + result = (s_hashtable64[ch / 16] + s_hashtable64[ch % 16]) ^ (adjust + result); +#endif + adjust = 33 * adjust + result + ch + 3; + } + } + return result ? result : 1LL; +} + +size_t STORMAPI SStrLen(const char* string) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -395,16 +504,18 @@ size_t SStrLen(const char* string) { return stringEnd - string; } -void SStrLower(char* string) { +void STORMAPI SStrLower(char* string) { while (*string) { *string = static_cast(tolower(*string)); string++; } } -uint32_t SStrPack(char* dest, const char* source, uint32_t destsize) { - STORM_ASSERT(dest); - STORM_ASSERT(source); +uint32_t STORMAPI SStrPack(char* dest, const char* source, uint32_t destsize) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(dest); + STORM_VALIDATE(source); + STORM_VALIDATE_END; if (!destsize) { return 0; @@ -445,137 +556,159 @@ uint32_t SStrPack(char* dest, const char* source, uint32_t destsize) { return static_cast(i - dest); } -size_t SStrPrintf(char* dest, size_t maxchars, const char* format, ...) { +size_t STORMCDECL SStrPrintf(char* dest, size_t maxchars, const char* format, ...) { va_list va; va_start(va, format); - STORM_ASSERT(dest); - STORM_ASSERT(format); + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(dest); + STORM_VALIDATE(format); + STORM_VALIDATE_END; - return ISStrVPrintf(format, va, dest, maxchars); + return ISStrVPrintf(dest, maxchars, format, va); } -const char* SStrStr(const char* string, const char* search) { - STORM_ASSERT(string); - STORM_ASSERT(search); +size_t STORMCDECL SStrVPrintf(char* dest, size_t maxchars, const char* format, va_list arglist) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(dest); + STORM_VALIDATE(format); + STORM_VALIDATE_END; - if (!*string) { - return nullptr; - } + return ISStrVPrintf(dest, maxchars, format, arglist); +} - auto searchEnd = search; - while (*searchEnd) { - searchEnd++; - } - size_t searchLength = searchEnd - search; +char* STORMAPI SStrStr(char* string, const char* search) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE(search); + STORM_VALIDATE_END; - auto substring = string; + size_t searchLength = SStrLen(search); - while (SStrCmp(substring, search, searchLength)) { - substring++; - - if (!*substring) { - return nullptr; + for (; *string; string++) { + if (!SStrCmp(string, search, searchLength)) { + return string; } } - - return substring; + return nullptr; } -void SStrTokenize(const char** string, char* buffer, size_t bufferchars, const char* whitespace, int32_t* quoted) { +const char* STORMAPI SStrStr(const char* string, const char* search) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE(search); + STORM_VALIDATE_END; + + size_t searchLength = SStrLen(search); + + for (; *string; string++) { + if (!SStrCmp(string, search, searchLength)) { + return string; + } + } + return nullptr; +} + +char* STORMAPI SStrStrI(char* string, const char* search) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE(search); + STORM_VALIDATE_END; + + size_t searchLength = SStrLen(search); + + for (; *string; string++) { + if (!SStrCmpI(string, search, searchLength)) { + return string; + } + } + return nullptr; +} + +const char* STORMAPI SStrStrI(const char* string, const char* search) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE(search); + STORM_VALIDATE_END; + + size_t searchLength = SStrLen(search); + + for (; *string; string++) { + if (!SStrCmpI(string, search, searchLength)) { + return string; + } + } + return nullptr; +} + +void STORMAPI SStrTokenize(const char** string, char* buffer, size_t bufferchars, const char* whitespace, int32_t* quoted) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE(*string); - STORM_VALIDATE(buffer || !bufferchars); + STORM_VALIDATE(buffer || bufferchars == 0); STORM_VALIDATE(whitespace); STORM_VALIDATE_END_VOID; + int32_t checkquotes = SStrChr(whitespace, '"') != nullptr; + int32_t inquotes = 0; int32_t usedquotes = 0; - auto curstring = *string; + const char* currsource = *string; - auto v17 = false; - for (const char* w = whitespace; w && *w; w++) { - if (*w == '"') { - v17 = true; - break; - } - } - - while (*curstring && SStrChr(whitespace, *curstring)) { - if (v17 && *curstring == '"') { - inquotes = 1; + while (*currsource && SStrChr(whitespace, *currsource)) { + if (checkquotes && *currsource == '"') { usedquotes = 1; - curstring++; + inquotes = 1; + currsource++; break; } - curstring++; + currsource++; } - uint32_t bufferlen = 0; + uint32_t destchars = 0; - if (*curstring) { - auto curbuffer = buffer; - - while (v17 && *curstring == '"') { - if (bufferlen && !inquotes) { - goto LABEL_35; + while(*currsource) { + if (checkquotes && *currsource == '"') { + if (destchars && !inquotes) { + break; } - curstring++; usedquotes = 1; - inquotes = inquotes == 0; + inquotes = !inquotes; + currsource++; if (!inquotes) { - goto LABEL_35; - } -LABEL_32: - if (!*curstring) { - goto LABEL_35; + break; } } - - if (inquotes) { -LABEL_29: - if (curbuffer - buffer < bufferchars) { - bufferlen++; - *curbuffer = *curstring; - curbuffer++; + else { + if (!inquotes && SStrChr(whitespace, *currsource)) { + currsource++; + break; } - curstring++; - - goto LABEL_32; + if (destchars + 1 < bufferchars) { + buffer[destchars] = *currsource; + destchars++; + } + currsource++; } - - auto v14 = SStrChr(whitespace, *curstring); - - if (!v14) { - goto LABEL_29; - } - - curstring++; } -LABEL_35: - if (bufferlen < bufferchars) { - buffer[bufferlen] = 0; + if (destchars < bufferchars) { + buffer[destchars] = 0; } - *string = curstring; + *string = currsource; if (quoted) { *quoted = usedquotes; } } -float SStrToFloat(const char* string) { - STORM_VALIDATE_BEGIN; - STORM_VALIDATE(string); - STORM_VALIDATE_END; - +static inline double ISStrToDouble(const char* string) { SStrInitialize(); double result; @@ -630,6 +763,7 @@ float SStrToFloat(const char* string) { int32_t v24 = 0; if (v23 < 10) { + int32_t v25 = 0; int32_t v26 = -1; double v31; @@ -637,7 +771,7 @@ float SStrToFloat(const char* string) { string++; if (v24 < 20) { - v31 = s_realDigit[v24][v23]; + v31 = s_realDigit[0][v25 + v23]; } else { v31 = pow(v16, v26) * v23; } @@ -647,6 +781,7 @@ float SStrToFloat(const char* string) { v23 = *string - '0'; v24++; v26--; + v25 += 10; } while (v23 < 10); } } @@ -665,10 +800,26 @@ float SStrToFloat(const char* string) { result = -result; } - return static_cast(result); + return result; } -int32_t SStrToInt(const char* string) { +double STORMAPI SStrToDouble(const char* string) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + + return ISStrToDouble(string); +} + +float STORMAPI SStrToFloat(const char* string) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(string); + STORM_VALIDATE_END; + + return static_cast(ISStrToDouble(string)); +} + +int32_t STORMAPI SStrToInt(const char* string) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -694,7 +845,7 @@ int32_t SStrToInt(const char* string) { return result; } -uint32_t SStrToUnsigned(const char* string) { +uint32_t STORMAPI SStrToUnsigned(const char* string) { STORM_VALIDATE_BEGIN; STORM_VALIDATE(string); STORM_VALIDATE_END; @@ -710,7 +861,7 @@ uint32_t SStrToUnsigned(const char* string) { return result; } -void SStrUpper(char* string) { +void STORMAPI SStrUpper(char* string) { while (*string) { *string = static_cast(toupper(*string)); string++; diff --git a/storm/String.hpp b/storm/String.hpp index 6fcd551..b0f4ba3 100644 --- a/storm/String.hpp +++ b/storm/String.hpp @@ -1,50 +1,69 @@ #ifndef STORM_STRING_HPP #define STORM_STRING_HPP -#include +#include #include +#include "Core.hpp" #define STORM_MAX_PATH 260 #define STORM_MAX_STR 0x7FFFFFFF -char* SStrChr(char* string, char search); +#define SSTR_HASH_CASESENSITIVE 1 -const char* SStrChr(const char* string, char search); +char* STORMAPI SStrChr(char* string, char search); -char* SStrChrR(char* string, char search); +const char* STORMAPI SStrChr(const char* string, char search); -const char* SStrChrR(const char* string, char search); +const char* STORMAPI SStrChrBidir(const char* string, char search, int32_t reverse); -int32_t SStrCmp(const char* string1, const char* string2, size_t maxchars); +char* STORMAPI SStrChrR(char* string, char search); -int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars); +const char* STORMAPI SStrChrR(const char* string, char search); -size_t SStrCopy(char* dest, const char* source, size_t destsize); +int32_t STORMAPI SStrCmp(const char* string1, const char* string2, size_t maxchars = STORM_MAX_STR); -size_t SStrNCopy(char* dest, const char* source, size_t maxchars, size_t destsize); +int32_t STORMAPI SStrCmpI(const char* string1, const char* string2, size_t maxchars = STORM_MAX_STR); -char* SStrDupA(const char* string, const char* filename, uint32_t linenumber); +size_t STORMAPI SStrCopy(char* dest, const char* source, size_t destsize = STORM_MAX_STR); -uint32_t SStrHashHT(const char* string); +void STORMAPI SStrDestroy(); -size_t SStrLen(const char* string); +char* STORMAPI SStrDupA(const char* string, const char* filename, uint32_t linenumber); -void SStrLower(char* string); +uint32_t STORMAPI SStrHash(const char* string, uint32_t flags = 0, uint32_t seed = 0); -uint32_t SStrPack(char* dest, const char* source, uint32_t destsize); +uint32_t STORMAPI SStrHashHT(const char* string); -size_t SStrPrintf(char* dest, size_t maxchars, const char* format, ...); +int64_t STORMAPI SStrHash64(const char* string, uint32_t flags = 0, int64_t seed = 0); -const char* SStrStr(const char* string, const char* search); +size_t STORMAPI SStrLen(const char* string); -void SStrTokenize(const char** string, char* buffer, size_t bufferchars, const char* whitespace, int32_t* quoted); +void STORMAPI SStrLower(char* string); -float SStrToFloat(const char* string); +uint32_t STORMAPI SStrPack(char* dest, const char* source, uint32_t destsize); -int32_t SStrToInt(const char* string); +size_t STORMCDECL SStrPrintf(char* dest, size_t maxchars, const char* format, ...); -uint32_t SStrToUnsigned(const char* string); +size_t STORMCDECL SStrVPrintf(char* dest, size_t maxchars, const char* format, va_list arglist); -void SStrUpper(char* string); +char* STORMAPI SStrStr(char* string, const char* search); + +const char* STORMAPI SStrStr(const char* string, const char* search); + +char* STORMAPI SStrStrI(char* string, const char* search); + +const char* STORMAPI SStrStrI(const char* string, const char* search); + +void STORMAPI SStrTokenize(const char** string, char* buffer, size_t bufferchars, const char* whitespace, int32_t* quoted); + +double STORMAPI SStrToDouble(const char* string); + +float STORMAPI SStrToFloat(const char* string); + +int32_t STORMAPI SStrToInt(const char* string); + +uint32_t STORMAPI SStrToUnsigned(const char* string); + +void STORMAPI SStrUpper(char* string); #endif diff --git a/storm/Transparency.cpp b/storm/Transparency.cpp new file mode 100644 index 0000000..649720f --- /dev/null +++ b/storm/Transparency.cpp @@ -0,0 +1,804 @@ +#include "storm/Transparency.hpp" +#include "storm/List.hpp" +#include "storm/Error.hpp" + +#include +#include +#include + +#define COPY 0 +#define SKIP 1 +#define NUM_OPS 2 + +#define MAXSPANLENGTH 0xFC +#define TRANS_CHUNKSIZE 4096 + +struct TRANS : TSLinkedNode { + uint8_t* data; + uint32_t dataalloc; + uint32_t databytes; + uint32_t instructionoffset; + int32_t width; + int32_t height; + RECT boundrect; +}; + +// Replacing windows struct +struct WHOA_SIZE { + int32_t cx, cy; +}; + +struct BUFFER { + uint8_t* data; + uint32_t bytesalloc; + uint32_t bytesused; + uint32_t chunksize; +}; + +// Defaults from SC 1.17's storm.dll +WHOA_SIZE s_dirtysize = { 40, 30 }; +int32_t s_dirtyxshift = 4; +int32_t s_dirtyxsize = 16; +int32_t s_dirtyyshift = 4; +int32_t s_dirtyysize = 16; + +uint32_t* s_dirtyoffset; +uint8_t* s_savedata; +uint32_t s_savedataalloc; +STORM_LIST(TRANS) s_translist; + +void BufferCreate(BUFFER* buffer) { + buffer->chunksize = TRANS_CHUNKSIZE; + buffer->bytesused = 0; + if (s_savedata) { + buffer->data = s_savedata; + buffer->bytesalloc = s_savedataalloc; + s_savedata = nullptr; + s_savedataalloc = 0; + } + else { + buffer->bytesalloc = TRANS_CHUNKSIZE; + buffer->data = static_cast(STORM_ALLOC(buffer->bytesalloc)); + } +} + +void BufferReserve(BUFFER* buffer, uint32_t bytes, uint8_t** adjptr1, uint8_t** adjptr2) { + uint32_t newalloc = buffer->bytesalloc; + while (newalloc < bytes + buffer->bytesused) { + newalloc += buffer->chunksize; + } + + if (newalloc != buffer->bytesalloc) { + uint8_t* newdata = static_cast(STORM_ALLOC(newalloc)); + SMemCopy(newdata, buffer->data, buffer->bytesused); + STORM_FREE(buffer->data); + + if (adjptr1 && *adjptr1) { + *adjptr1 = &newdata[*adjptr1 - buffer->data]; + } + if (adjptr2 && *adjptr2) { + *adjptr2 = &newdata[*adjptr2 - buffer->data]; + } + buffer->bytesalloc = newalloc; + buffer->data = newdata; + } +} + +void ConvertBitmapToTransparency(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, RECT* boundrect, uint8_t colorkey, int32_t maskonly, uint8_t* data, uint32_t* databytes, uint32_t* instructionoffset) { + uint32_t size = 0; + int32_t start = rect ? rect->left + width * rect->top : 0; + int32_t cx = rect ? rect->right - rect->left : width; + int32_t cy = rect ? rect->bottom - rect->top : height; + + int32_t adjust = width - cx; + + *boundrect = { INT_MAX, INT_MAX, 0, 0 }; + + if (!maskonly) { + uint8_t* source = &bits[start]; + for (int32_t y = 0; y < cy; y++) { + bool found = false; + for (int32_t x = 0; x < cx; x++) { + if (*source != colorkey) { + size++; + if (data) *data++ = *source; + + if (x < boundrect->left) boundrect->left = x; + if (x >= boundrect->right) boundrect->right = x + 1; + found = true; + } + source++; + } + + if (found) { + if (y < boundrect->top) boundrect->top = y; + if (y >= boundrect->bottom) boundrect->bottom = y + 1; + } + + source += adjust; + } + } + + if (boundrect->left > boundrect->right) boundrect->left = boundrect->right; + if (boundrect->top > boundrect->bottom) boundrect->top = boundrect->bottom; + + if (size % 4 != 0) { + if (data) data += 4 - (size % 4); + size += 4 - (size % 4); + } + + if (instructionoffset) *instructionoffset = size; + + uint8_t* source = &bits[start]; + while (cy--) { + uint8_t copybytes = 0; + uint8_t skipbytes = 0; + bool copymode = true; + + for (int32_t x = cx; x--;) { + bool output = false; + bool expectedcopymode = *source++ != colorkey; + if (expectedcopymode == copymode) { + if (copymode) { + copybytes++; + } + else { + skipbytes++; + } + } + else if (copymode) { + copymode = false; + skipbytes++; + } + else { + output = true; + source--; + x++; + } + + if (output || copybytes == MAXSPANLENGTH || skipbytes == MAXSPANLENGTH || x == 0) { + size += 2; + if (data) { + *data++ = copybytes; + *data++ = skipbytes; + } + copybytes = 0; + skipbytes = 0; + copymode = true; + } + } + + size += 2; + if (data) { + *data++ = 0; + *data++ = 0; + } + + source += adjust; + } + + if (databytes) *databytes = size; +} + +int32_t ConvertColorRefToColorData(uint32_t colorref) { + if (colorref & STRANS_COLORKEY_VALID) { + return colorref & STRANS_COLORKEY_MASK; + } + return 0; +} + +HSTRANS CreateTransparencyRecord(HSTRANS baseptr) { + HSTRANS transptr = s_translist.NewNode(STORM_LIST_TAIL, 0, 0); + if (baseptr) { + transptr->dataalloc = baseptr->dataalloc; + transptr->databytes = baseptr->databytes; + transptr->instructionoffset = baseptr->instructionoffset; + transptr->width = baseptr->width; + transptr->height = baseptr->height; + transptr->boundrect = baseptr->boundrect; + } + return transptr; +} + +int32_t DetermineShift(int32_t value, int32_t* shift) { + int32_t bits = 0, curr = 1; + while (curr < value) { + bits++; + curr <<= 1; + } + + *shift = bits; + return curr == value; +} + +int32_t InternalCreateTransparency(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, int32_t maskonly, HSTRANS* handle) { + if (bitdepth != 8) return 0; + + uint8_t paletteindex = ConvertColorRefToColorData(colorkey); + uint32_t transbytes = 0; + uint32_t instructionoffset = 0; + RECT boundrect; + + ConvertBitmapToTransparency(bits, width, height, bitdepth, rect, &boundrect, paletteindex, maskonly, nullptr, &transbytes, &instructionoffset); + + uint8_t* transdata = static_cast(STORM_ALLOC(transbytes)); + ConvertBitmapToTransparency(bits, width, height, bitdepth, rect, &boundrect, paletteindex, maskonly, transdata, nullptr, nullptr); + + HSTRANS newptr = CreateTransparencyRecord(nullptr); + newptr->boundrect = boundrect; + newptr->data = transdata; + newptr->dataalloc = transbytes; + newptr->databytes = transbytes; + newptr->instructionoffset = instructionoffset; + newptr->width = rect ? rect->right - rect->left : width; + newptr->height = rect ? rect->bottom - rect->top : height; + + *handle = newptr; + return 1; +} + +void InternalDrawTransparency(HSTRANS trans, uint8_t* dest, int32_t destadjust) { + uint8_t* sourceinst = &trans->data[trans->instructionoffset]; + uint8_t* sourcedata = trans->data; + int32_t cy = trans->height; + while (cy--) { + uint8_t copybytes = *sourceinst++; + uint8_t skipbytes = *sourceinst++; + while (copybytes || skipbytes) { + while(copybytes) { + *dest++ = *sourcedata++; + copybytes--; + } + dest += skipbytes; + + copybytes = *sourceinst++; + skipbytes = *sourceinst++; + } + dest += destadjust; + } +} + +void InternalDrawTransparencyFromSource(HSTRANS trans, uint8_t* dest, uint8_t* source, int32_t destadjust, int32_t sourceadjust) { + uint8_t* sourceinst = &trans->data[trans->instructionoffset]; + for (int32_t y = 0; y < trans->height; y++) { + uint8_t copybytes = *(sourceinst++); + uint8_t skipbytes = *(sourceinst++); + while (copybytes || skipbytes) { + std::memcpy(dest, source, copybytes); + source += copybytes; + dest += copybytes; + + dest += skipbytes; + source += skipbytes; + + copybytes = *(sourceinst++); + skipbytes = *(sourceinst++); + } + dest += destadjust; + source += sourceadjust; + } +} + +int32_t STORMAPI STransBlt(uint8_t* dest, int32_t destx, int32_t desty, int32_t destpitch, HSTRANS transparency) { + STORM_ASSERT(dest); + STORM_ASSERT(destpitch > 0); + STORM_ASSERT(transparency); + STORM_ASSERT(transparency->instructionoffset); + + InternalDrawTransparency(transparency, &dest[destpitch * desty + destx], destpitch - transparency->width); + return 1; +} + +int32_t STORMAPI STransBltUsingMask(uint8_t* dest, uint8_t* source, int32_t destpitch, int32_t sourcepitch, HSTRANS mask) { + STORM_ASSERT(dest); + STORM_ASSERT(source); + STORM_ASSERT(destpitch > 0); + STORM_ASSERT(mask); + + int32_t sourceadjust = sourcepitch ? sourcepitch - mask->width : 0; + int32_t destadjust = destpitch - mask->width; + InternalDrawTransparencyFromSource(mask, dest, source, destadjust, sourceadjust); + return 1; +} + +int32_t STORMAPI STransCombineMasks(HSTRANS basemask, HSTRANS secondmask, int32_t offsetx, int32_t offsety, uint32_t flags, HSTRANS* handle) { + if (handle) *handle = nullptr; + + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(basemask); + STORM_VALIDATE(secondmask); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + bool intersect = (flags & STRANS_CF_INTERSECT) != 0; + bool invertsecond = (flags & STRANS_CF_INVERTSECOND) != 0; + + bool usespan[NUM_OPS][NUM_OPS][NUM_OPS]; + for (int32_t spantype0 = 0; spantype0 < NUM_OPS; spantype0++) { + for (int32_t spantypedest = 0; spantypedest < NUM_OPS; spantypedest++) { + if (intersect) { + usespan[spantype0][spantypedest][invertsecond ? SKIP : COPY] = (spantype0 == spantypedest); + usespan[spantype0][spantypedest][invertsecond ? COPY : SKIP] = (spantypedest == SKIP); + } + else { + usespan[spantype0][spantypedest][invertsecond ? SKIP : COPY] = (spantypedest == COPY); + usespan[spantype0][spantypedest][invertsecond ? COPY : SKIP] = (spantype0 == spantypedest); + } + } + } + + uint8_t* baseptr = &basemask->data[basemask->instructionoffset]; + uint8_t* secondptr = &secondmask->data[secondmask->instructionoffset]; + + uint8_t copybytes, skipbytes; + + for (int32_t i = offsety; i < 0; i++) { + do { + copybytes = *secondptr++; + skipbytes = *secondptr++; + } while (copybytes || skipbytes); + } + + BUFFER buffer; + BufferCreate(&buffer); + uint8_t* dest = buffer.data; + for (int32_t line = 0; line < basemask->height; line++) { + BufferReserve(&buffer, 2 * (basemask->width + 1), &dest, nullptr); + + if (line >= offsety && line <= offsety + secondmask->height - 1) { + int32_t span[2][NUM_OPS] = {}; + span[1][SKIP] = std::max(0, offsetx); + bool hitend = false; + + if (offsetx < 0) { + int32_t bytesleft = -offsetx; + while (bytesleft) { + span[1][COPY] = *secondptr++; + span[1][SKIP] = *secondptr++; + + if (span[1][COPY] == 0 && span[1][SKIP] == 0) { + span[1][SKIP] = INT_MAX; + hitend = true; + break; + } + + for (int32_t adjustremaining = 0; adjustremaining < NUM_OPS; adjustremaining++) { + int32_t adjustment = std::min(bytesleft, span[1][adjustremaining]); + span[1][adjustremaining] -= adjustment; + bytesleft -= adjustment; + } + } + } + + while(1) { + span[0][COPY] = *baseptr++; + span[0][SKIP] = *baseptr++; + if (span[0][COPY] == 0 && span[0][SKIP] == 0) break; + + for (int32_t j = 0; j < NUM_OPS; j++) { + while(span[0][j]) { + if (span[1][COPY] == 0 && span[1][SKIP] == 0) { + span[1][COPY] = *secondptr++; + span[1][SKIP] = *secondptr++; + if (span[1][COPY] == 0 && span[1][SKIP] == 0) { + span[1][SKIP] = INT_MAX; + hitend = true; + } + } + + uint8_t inst[NUM_OPS]; + for (int32_t k = 0; k < NUM_OPS; k++) { + int32_t spanlength = 0; + if (usespan[j][k][COPY]) { + spanlength = span[1][COPY]; + } + + if (usespan[j][k][SKIP] && (usespan[j][k][COPY] || !span[1][COPY])) { + spanlength += span[1][SKIP]; + } + + spanlength = std::min(span[0][j], spanlength); + inst[k] = spanlength; + span[0][j] -= spanlength; + for (int32_t m = 0; m < NUM_OPS; m++) { + int32_t v11 = std::min(span[1][m], spanlength); + span[1][m] -= v11; + spanlength -= v11; + } + } + + if (inst[COPY] || inst[SKIP]) { + *dest++ = inst[COPY]; + *dest++ = inst[SKIP]; + buffer.bytesused += 2; + } + } + } + } + + *dest++ = 0; + *dest++ = 0; + buffer.bytesused += 2; + + if (!hitend) { + do { + copybytes = *secondptr++; + skipbytes = *secondptr++; + } while (copybytes || skipbytes); + } + } + else if (intersect == invertsecond) { + do { + buffer.bytesused += 2; + copybytes = *baseptr++; + skipbytes = *baseptr++; + + *dest++ = copybytes; + *dest++ = skipbytes; + } while (copybytes || skipbytes); + } + else { + int32_t width = basemask->width; + while (width) { + int32_t skipspan = std::min(width, MAXSPANLENGTH); + *dest++ = 0; + *dest++ = skipspan; + buffer.bytesused += 2; + + width -= skipspan; + } + *dest++ = 0; + *dest++ = 0; + buffer.bytesused += 2; + + do { + copybytes = *baseptr++; + skipbytes = *baseptr++; + } while (copybytes || skipbytes); + } + } + + HSTRANS newptr = CreateTransparencyRecord(basemask); + newptr->data = buffer.data; + newptr->dataalloc = buffer.bytesalloc; + newptr->databytes = buffer.bytesused; + newptr->instructionoffset = 0; + *handle = newptr; + return 1; +} + +int32_t STORMAPI STransCreateE(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle) { + if (handle) *handle = nullptr; + + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(bits); + STORM_VALIDATE(width); + STORM_VALIDATE(height); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + return InternalCreateTransparency(bits, width, height, bitdepth, rect, colorkey, 0, handle); +} + +int32_t STORMAPI STransCreateI(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle) { + RECT exclrect; + RECT* exclrectptr = rect; + if (rect) { + exclrect = { rect->left, rect->top, rect->right + 1, rect->bottom + 1 }; + exclrectptr = &exclrect; + } + return STransCreateE(bits, width, height, bitdepth, exclrectptr, colorkey, handle); +} + +int32_t STORMAPI STransCreateMaskE(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle) { + if (handle) *handle = nullptr; + + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(bits); + STORM_VALIDATE(width); + STORM_VALIDATE(height); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + return InternalCreateTransparency(bits, width, height, bitdepth, rect, colorkey, 1, handle); +} + +int32_t STORMAPI STransCreateMaskI(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle) { + RECT exclrect; + RECT* exclrectptr = rect; + if (rect) { + exclrect = { rect->left, rect->top, rect->right + 1, rect->bottom + 1 }; + exclrectptr = &exclrect; + } + return STransCreateMaskE(bits, width, height, bitdepth, exclrectptr, colorkey, handle); +} + +int32_t STORMAPI STransDelete(HSTRANS handle) { + if (handle->data) { + if (s_savedata) { + STORM_FREE(s_savedata); + } + + s_savedata = handle->data; + s_savedataalloc = handle->dataalloc; + + handle->data = nullptr; + handle->dataalloc = 0; + } + + s_translist.DeleteNode(handle); + return 1; +} + +int32_t STORMAPI STransDestroy() { + while (TRANS* curr = s_translist.Head()) { + //SErrReportResourceLeak("HSTRANS"); + STransDelete(curr); + } + + if (s_dirtyoffset) { + STORM_FREE(s_dirtyoffset); + s_dirtyoffset = nullptr; + } + + if (s_savedata) { + STORM_FREE(s_savedata); + s_savedata = nullptr; + s_savedataalloc = 0; + } + return 1; +} + +int32_t STORMAPI STransDuplicate(HSTRANS source, HSTRANS* handle) { + if (handle) *handle = nullptr; + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(source); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + uint8_t* data = static_cast(STORM_ALLOC(source->dataalloc)); + SMemCopy(data, source->data, source->databytes); + + HSTRANS newtrans = CreateTransparencyRecord(source); + newtrans->data = data; + + *handle = newtrans; + return 1; +} + +int32_t STORMAPI STransIntersectDirtyArray(HSTRANS sourcemask, uint8_t* dirtyarray, uint8_t dirtyarraymask, HSTRANS* handle) { + if (handle) *handle = nullptr; + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(sourcemask); + STORM_VALIDATE(dirtyarray); + STORM_VALIDATE(dirtyarraymask); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + if (s_dirtyoffset == 0) return 0; + + BUFFER buffer; + BufferCreate(&buffer); + + uint8_t* source = &sourcemask->data[sourcemask->instructionoffset]; + uint8_t* dest = buffer.data; + uint8_t* lastsource = source; + uint8_t* lastdest = dest; + + for (int32_t y = 0; y < sourcemask->height; y++) { + BufferReserve(&buffer, 2 * (sourcemask->width + 1), &dest, &lastdest); + + // wtf? + if (((s_dirtyysize - 1) & y) != 0 && !memcmp(source, lastsource, source - lastsource)) { + ptrdiff_t sourcebytes = source - lastsource; + ptrdiff_t destbytes = dest - lastdest; + memcpy(dest, lastdest, dest - lastdest); + + lastsource = source; + lastdest = dest; + source += sourcebytes; + dest += destbytes; + buffer.bytesused += static_cast(destbytes); + } + else { + uint8_t copybytes, skipbytes; + + lastsource = source; + lastdest = dest; + uint8_t* dirty = &dirtyarray[s_dirtyoffset[y >> s_dirtyyshift]]; + uint32_t xoffset = 0; + do { + copybytes = *source++; + skipbytes = *source++; + + if (copybytes) { + uint8_t bytesleft = copybytes; + uint8_t length = 0; + bool copymode = true; + + while (bytesleft != 0 || length != 0) { + if (bytesleft != 0 && ((dirtyarraymask & *dirty) != 0) == copymode) { + uint8_t cellleft = s_dirtyxsize - xoffset; + if (bytesleft >= cellleft) { + length += cellleft; + bytesleft -= cellleft; + xoffset = 0; + dirty++; + } + else { + length += bytesleft; + xoffset += bytesleft; + bytesleft = 0; + } + } + else { + *dest++ = length; + buffer.bytesused++; + length = 0; + copymode = !copymode; + } + } + + if (skipbytes || !copymode) { + if (copymode) { + *dest++ = 0; + buffer.bytesused++; + } + *dest++ = skipbytes; + buffer.bytesused++; + } + } + else { + *dest++ = 0; + *dest++ = skipbytes; + buffer.bytesused += 2; + } + + if (skipbytes) { + xoffset += skipbytes; + dirty += xoffset >> s_dirtyxshift; + xoffset &= s_dirtyxsize - 1; + } + + } while (copybytes || skipbytes); + } + } + + HSTRANS newptr = CreateTransparencyRecord(sourcemask); + newptr->data = buffer.data; + newptr->dataalloc = buffer.bytesalloc; + newptr->databytes = buffer.bytesused; + newptr->instructionoffset = 0; + *handle = newptr; + return 1; +} + +int32_t STORMAPI STransInvertMask(HSTRANS sourcemask, HSTRANS* handle) { + if (handle) *handle = nullptr; + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(sourcemask); + STORM_VALIDATE(handle); + STORM_VALIDATE_END; + + uint32_t dataalloc = sourcemask->databytes - sourcemask->instructionoffset + 2 * sourcemask->height; + uint8_t* data = static_cast(STORM_ALLOC(dataalloc)); + uint32_t bytes = 0; + + uint8_t* source = &sourcemask->data[sourcemask->instructionoffset]; + uint8_t* dest = data; + + for (int32_t cy = sourcemask->height; cy--;) { + uint8_t copybytes = 0, skipbytes = 0; + do { + skipbytes = *source++; + if (copybytes || skipbytes) { + *dest++ = copybytes; + *dest++ = skipbytes; + bytes += 2; + } + copybytes = *source++; + } while (copybytes || skipbytes); + + *dest++ = 0; + *dest++ = 0; + bytes += 2; + } + + HSTRANS newptr = CreateTransparencyRecord(sourcemask); + newptr->data = data; + newptr->dataalloc = dataalloc; + newptr->databytes = bytes; + newptr->instructionoffset = 0; + + *handle = newptr; + return 1; +} + +int32_t STORMAPI STransIsPixelInMask(HSTRANS mask, int32_t offsetx, int32_t offsety) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(mask); + STORM_VALIDATE_END; + + if (offsetx < 0 || offsety < 0 || offsetx >= mask->width || offsety >= mask->height) { + return 0; + } + + uint8_t copybytes, skipbytes; + uint8_t* instptr = &mask->data[mask->instructionoffset]; + while(offsety--) { + do { + copybytes = *instptr++; + skipbytes = *instptr++; + } while (copybytes || skipbytes); + } + + copybytes = *instptr++; + skipbytes = *instptr++; + while(copybytes || skipbytes) { + if (copybytes > offsetx) return 1; + offsetx -= copybytes; + + if (skipbytes > offsetx) return 0; + offsetx -= skipbytes; + + copybytes = *instptr++; + skipbytes = *instptr++; + } + return 0; +} + +int32_t STORMAPI STransSetDirtyArrayInfo(int32_t screencx, int32_t screency, int32_t cellcx, int32_t cellcy) { + if (s_dirtyoffset) { + STORM_FREE(s_dirtyoffset); + s_dirtyoffset = nullptr; + } + + if (!DetermineShift(cellcx, &s_dirtyxshift)) { + return 0; + } + + if (!DetermineShift(cellcy, &s_dirtyyshift)) { + return 0; + } + + s_dirtysize = { + (screencx + (1 << s_dirtyxshift) - 1) >> s_dirtyxshift, + (screency + (1 << s_dirtyyshift) - 1) >> s_dirtyyshift, + }; + + s_dirtyxsize = cellcx; + s_dirtyysize = cellcy; + + s_dirtyoffset = static_cast(STORM_ALLOC(sizeof(s_dirtyoffset[0]) * s_dirtysize.cy)); + + uint32_t offset = 0; + for (int32_t i = 0; i < s_dirtysize.cy; i++) { + s_dirtyoffset[i] = offset; + offset += s_dirtysize.cx; + } + return 1; +} + +int32_t STORMAPI STransUpdateDirtyArray(uint8_t* dirtyarray, uint8_t dirtyvalue, int32_t destx, int32_t desty, HSTRANS transparency, int32_t tracecontour) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(dirtyarray); + STORM_VALIDATE(dirtyvalue); + STORM_VALIDATE(transparency); + STORM_VALIDATE_END; + + if (!s_dirtyoffset) return 0; + if (transparency->width <= 0 || transparency->height <= 0) return 0; + if (tracecontour) return 0; + + int32_t lastx = (transparency->boundrect.right + destx) >> s_dirtyxshift; + int32_t lasty = (transparency->boundrect.bottom + desty) >> s_dirtyyshift; + int32_t firstx = (transparency->boundrect.left + destx) >> s_dirtyxshift; + int32_t firsty = (transparency->boundrect.top + desty) >> s_dirtyyshift; + + for (int32_t y = firsty; y < lasty; y++) { + for (int32_t x = firstx; x < lastx; x++) { + dirtyarray[s_dirtyoffset[y] + x] |= dirtyvalue; + } + } + return 1; +} diff --git a/storm/Transparency.hpp b/storm/Transparency.hpp new file mode 100644 index 0000000..e7e5cf4 --- /dev/null +++ b/storm/Transparency.hpp @@ -0,0 +1,51 @@ +#ifndef STORM_TRANSPARENCY_HPP +#define STORM_TRANSPARENCY_HPP + +#include +#include "storm/Core.hpp" +#include "storm/region/Types.hpp" + +#define STRANS_CF_INTERSECT 1 +#define STRANS_CF_INVERTSECOND 2 +#define STRANS_CF_SUBTRACT 3 + +#define STRANS_COLORKEY_VALID 0x1000000 +#define STRANS_COLORKEY_MASK 0xFFFFFF +#define STRANS_COLORKEY(x) (((x) & STRANS_COLORKEY_MASK) | STRANS_COLORKEY_VALID) + +struct TRANS; +typedef TRANS* HSTRANS; + +int32_t STORMAPI STransBlt(uint8_t* dest, int32_t destx, int32_t desty, int32_t destpitch, HSTRANS transparency); + +int32_t STORMAPI STransBltUsingMask(uint8_t* dest, uint8_t* source, int32_t destpitch, int32_t sourcepitch, HSTRANS mask); + +int32_t STORMAPI STransCombineMasks(HSTRANS basemask, HSTRANS secondmask, int32_t offsetx, int32_t offsety, uint32_t flags, HSTRANS* handle); + +// Exclusive rect - [left,right), [top,bottom) +int32_t STORMAPI STransCreateE(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle); + +// Inclusive rect - [left,right], [top,bottom] +int32_t STORMAPI STransCreateI(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle); + +int32_t STORMAPI STransCreateMaskE(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle); + +int32_t STORMAPI STransCreateMaskI(uint8_t* bits, int32_t width, int32_t height, int32_t bitdepth, RECT* rect, uint32_t colorkey, HSTRANS* handle); + +int32_t STORMAPI STransDelete(HSTRANS handle); + +int32_t STORMAPI STransDestroy(); + +int32_t STORMAPI STransDuplicate(HSTRANS source, HSTRANS* handle); + +int32_t STORMAPI STransIntersectDirtyArray(HSTRANS sourcemask, uint8_t* dirtyarray, uint8_t dirtyarraymask, HSTRANS* handle); + +int32_t STORMAPI STransInvertMask(HSTRANS sourcemask, HSTRANS* handle); + +int32_t STORMAPI STransIsPixelInMask(HSTRANS mask, int32_t offsetx, int32_t offsety); + +int32_t STORMAPI STransSetDirtyArrayInfo(int32_t screencx, int32_t screency, int32_t cellcx, int32_t cellcy); + +int32_t STORMAPI STransUpdateDirtyArray(uint8_t* dirtyarray, uint8_t dirtyvalue, int32_t destx, int32_t desty, HSTRANS transparency, int32_t tracecontour = 0); + +#endif diff --git a/storm/array/TSBaseArray.hpp b/storm/array/TSBaseArray.hpp index 417ee9c..0a95d86 100644 --- a/storm/array/TSBaseArray.hpp +++ b/storm/array/TSBaseArray.hpp @@ -19,6 +19,7 @@ class TSBaseArray { // Member functions T& operator[](uint32_t index); + const T& operator[](uint32_t index) const; void CheckArrayBounds(uint32_t index) const; void Constructor(); uint32_t Count() const; @@ -33,6 +34,12 @@ T& TSBaseArray::operator[](uint32_t index) { return this->m_data[index]; } +template +const T& TSBaseArray::operator[](uint32_t index) const { + this->CheckArrayBounds(index); + return this->m_data[index]; +} + template void TSBaseArray::CheckArrayBounds(uint32_t index) const { if (index < this->Count()) { @@ -40,14 +47,15 @@ void TSBaseArray::CheckArrayBounds(uint32_t index) const { } SErrDisplayErrorFmt( - 0x85100080, + STORM_ERROR_ACCESS_OUT_OF_BOUNDS, this->MemFileName(), this->MemLineNo(), 1, 1, "index (0x%08X), array size (0x%08X)", index, - this->Count()); + this->Count() + ); } template diff --git a/storm/array/TSFixedArray.hpp b/storm/array/TSFixedArray.hpp index e212a03..d2e1516 100644 --- a/storm/array/TSFixedArray.hpp +++ b/storm/array/TSFixedArray.hpp @@ -8,9 +8,11 @@ template class TSFixedArray : public TSBaseArray { public: + // Member functions TSFixedArray(); + TSFixedArray(const TSFixedArray& source); ~TSFixedArray(); - TSFixedArray& operator=(const TSFixedArray& source); + TSFixedArray& operator=(const TSFixedArray& source); void Clear(); void ReallocAndClearData(uint32_t count); void ReallocData(uint32_t count); @@ -23,6 +25,12 @@ TSFixedArray::TSFixedArray() { this->Constructor(); } +template +TSFixedArray::TSFixedArray(const TSFixedArray& source) { + this->Constructor(); + this->Set(source.Count(), source.Ptr()); +} + template TSFixedArray::~TSFixedArray() { for (uint32_t i = 0; i < this->Count(); i++) { @@ -41,22 +49,31 @@ TSFixedArray& TSFixedArray::operator=(const TSFixedArray& source) { this->Set(source.Count(), source.Ptr()); } - return *this; + return *this; } template void TSFixedArray::Clear() { - this->~TSFixedArray(); - this->Constructor(); + this->~TSFixedArray(); + this->Constructor(); } template void TSFixedArray::ReallocAndClearData(uint32_t count) { - this->m_alloc = count; + // Destruct existing array elements + for (uint32_t i = 0; i < this->Count(); i++) { + auto element = &this->operator[](i); + element->~T(); + } - if (this->m_data || count) { - void* m = SMemReAlloc(this->m_data, sizeof(T) * count, this->MemFileName(), this->MemLineNo(), 0x0); - this->m_data = static_cast(m); + // Reallocate if count changed + if (count != this->m_count) { + this->m_alloc = count; + + if (this->m_data || count) { + void* m = SMemReAlloc(this->m_data, sizeof(T) * count, this->MemFileName(), this->MemLineNo(), 0x0); + this->m_data = static_cast(m); + } } } diff --git a/storm/array/TSGrowableArray.hpp b/storm/array/TSGrowableArray.hpp index 867f6f6..691f5af 100644 --- a/storm/array/TSGrowableArray.hpp +++ b/storm/array/TSGrowableArray.hpp @@ -6,17 +6,20 @@ #include #include #include +#include template class TSGrowableArray : public TSFixedArray { public: + // Member variables uint32_t m_chunk = 0; + // Member functions uint32_t Add(uint32_t count, const T* data); uint32_t Add(uint32_t count, uint32_t incr, const T* data); uint32_t CalcChunkSize(uint32_t count); void GrowToFit(uint32_t index, int32_t zero); - T* New(void); + T* New(); void Reserve(uint32_t count, int32_t round); uint32_t Reserved() const; uint32_t RoundToChunk(uint32_t count, uint32_t chunk); diff --git a/storm/big/Ops.cpp b/storm/big/Ops.cpp index b40623f..a78cb1a 100644 --- a/storm/big/Ops.cpp +++ b/storm/big/Ops.cpp @@ -483,6 +483,11 @@ void ToStream(TSGrowableArray& output, const BigBuffer& buffer) { ToBinaryAppend(output, buffer); } +void ToUnsigned(uint32_t* a, const BigBuffer& b) { + *a = 0; + *a = b[0]; +} + void Xor(BigBuffer& a, const BigBuffer& b, const BigBuffer& c) { uint32_t i = 0; for (; b.IsUsed(i) || c.IsUsed(i); i++) { diff --git a/storm/big/Ops.hpp b/storm/big/Ops.hpp index 3f38596..c8b20dc 100644 --- a/storm/big/Ops.hpp +++ b/storm/big/Ops.hpp @@ -75,6 +75,8 @@ void ToBinary(TSGrowableArray& output, const BigBuffer& buffer); void ToStream(TSGrowableArray& output, const BigBuffer& buffer); +void ToUnsigned(uint32_t* a, const BigBuffer& b); + void Xor(BigBuffer& a, const BigBuffer& b, const BigBuffer& c); #endif diff --git a/storm/error/Defines.hpp b/storm/error/Defines.hpp index b1f12a4..a98c979 100644 --- a/storm/error/Defines.hpp +++ b/storm/error/Defines.hpp @@ -167,6 +167,48 @@ #endif +#define STORM_ERROR_ASSERTION 0x85100000 +#define STORM_ERROR_BAD_ARGUMENT 0x85100065 +#define STORM_ERROR_GAME_ALREADY_STARTED 0x85100066 +#define STORM_ERROR_GAME_FULL 0x85100067 +#define STORM_ERROR_GAME_NOT_FOUND 0x85100068 +#define STORM_ERROR_GAME_TERMINATED 0x85100069 +#define STORM_ERROR_INVALID_PLAYER 0x8510006A +#define STORM_ERROR_NO_MESSAGES_WAITING 0x8510006B +#define STORM_ERROR_NOT_ARCHIVE 0x8510006C +#define STORM_ERROR_NOT_ENOUGH_ARGUMENTS 0x8510006D +#define STORM_ERROR_NOT_IMPLEMENTED 0x8510006E +#define STORM_ERROR_NOT_IN_ARCHIVE 0x8510006F +#define STORM_ERROR_NOT_IN_GAME 0x85100070 +#define STORM_ERROR_NOT_INITIALIZED 0x85100071 +#define STORM_ERROR_NOT_PLAYING 0x85100072 +#define STORM_ERROR_NOT_REGISTERED 0x85100073 +#define STORM_ERROR_REQUIRES_CODEC 0x85100074 +#define STORM_ERROR_REQUIRES_DDRAW 0x85100075 +#define STORM_ERROR_REQUIRES_DSOUND 0x85100076 +#define STORM_ERROR_REQUIRES_UPGRADE 0x85100077 +#define STORM_ERROR_STILL_ACTIVE 0x85100078 +#define STORM_ERROR_VERSION_MISMATCH 0x85100079 +#define STORM_ERROR_MEMORY_ALREADY_FREED 0x8510007A +#define STORM_ERROR_MEMORY_CORRUPT 0x8510007B +#define STORM_ERROR_MEMORY_INVALID_BLOCK 0x8510007C +#define STORM_ERROR_MEMORY_MANAGER_INACTIVE 0x8510007D +#define STORM_ERROR_MEMORY_NEVER_RELEASED 0x8510007E +#define STORM_ERROR_HANDLE_NEVER_RELEASED 0x8510007F +#define STORM_ERROR_ACCESS_OUT_OF_BOUNDS 0x85100080 +#define STORM_ERROR_MEMORY_NULL_POINTER 0x85100081 +#define STORM_ERROR_CDKEY_MISMATCH 0x85100082 +#define STORM_ERROR_DATA_FILE_CORRUPT 0x85100083 +#define STORM_ERROR_FATAL_EXCEPTION 0x85100084 +#define STORM_ERROR_GAME_TYPE_UNAVAILABLE 0x85100085 +#define STORM_ERROR_FATAL_CONDITION 0x85100086 + +#define SERR_LINECODE_FUNCTION -1 +#define SERR_LINECODE_OBJECT -2 +#define SERR_LINECODE_HANDLE -3 +#define SERR_LINECODE_FILE -4 +#define SERR_LINECODE_EXCEPTION -5 // exception handler + #define STORM_NO_ERROR 0x85100000 #define STORM_ERROR(id) (STORM_NO_ERROR | (id & 0xFFFF)) diff --git a/storm/hash/Hashkey.cpp b/storm/hash/Hashkey.cpp index 7bae99a..f55d83a 100644 --- a/storm/hash/Hashkey.cpp +++ b/storm/hash/Hashkey.cpp @@ -7,20 +7,45 @@ bool HASHKEY_NONE::operator==(const HASHKEY_NONE& key) { return true; } -bool HASHKEY_PTR::operator==(const HASHKEY_PTR& key) { +HASHKEY_PTR::HASHKEY_PTR() { + this->m_key = nullptr; +} + +HASHKEY_PTR::HASHKEY_PTR(void* key) { + this->m_key = key; +} + +HASHKEY_PTR& HASHKEY_PTR::operator=(const HASHKEY_PTR& key) { + this->m_key = key.m_key; + return *this; +} + +bool HASHKEY_PTR::operator==(const HASHKEY_PTR& key) const { return this->m_key == key.m_key; } +void* HASHKEY_PTR::GetPtr() const { + return this->m_key; +} + +HASHKEY_STR::HASHKEY_STR() { + this->m_str = nullptr; +} + +HASHKEY_STR::HASHKEY_STR(const char* str) { + this->m_str = SStrDupA(str, __FILE__, __LINE__); +} + HASHKEY_STR::~HASHKEY_STR() { if (this->m_str) { - SMemFree(this->m_str, __FILE__, __LINE__, 0x0); + STORM_FREE(this->m_str); } } HASHKEY_STR& HASHKEY_STR::operator=(const char* str) { if (this->m_str != str) { if (this->m_str) { - SMemFree(this->m_str, __FILE__, __LINE__, 0x0); + STORM_FREE(this->m_str); } this->m_str = SStrDupA(str, __FILE__, __LINE__); @@ -29,15 +54,91 @@ HASHKEY_STR& HASHKEY_STR::operator=(const char* str) { return *this; } -bool HASHKEY_STR::operator==(const char* str) { - return SStrCmp(this->m_str, str, STORM_MAX_STR) == 0; +HASHKEY_STR& HASHKEY_STR::operator=(const HASHKEY_STR& key) { + this->operator=(key.m_str); + + return *this; +} + +bool HASHKEY_STR::operator==(const char* str) const { + return SStrCmp(this->m_str, str) == 0; +} + +bool HASHKEY_STR::operator==(const HASHKEY_STR& key) const { + return this->operator==(key.m_str); +} + +const char* HASHKEY_STR::GetString() const { + return this->m_str; } HASHKEY_STRI& HASHKEY_STRI::operator=(const char* str) { static_cast(*this) = str; + return *this; } -bool HASHKEY_STRI::operator==(const char* str) { - return SStrCmpI(this->m_str, str, STORM_MAX_STR) == 0; +HASHKEY_STRI& HASHKEY_STRI::operator=(const HASHKEY_STRI& key) { + static_cast(*this) = key.m_str; + + return *this; +} + +bool HASHKEY_STRI::operator==(const char* str) const { + return SStrCmpI(this->m_str, str) == 0; +} + +bool HASHKEY_STRI::operator==(const HASHKEY_STRI& key) const { + return this->operator==(key.m_str); +} + +HASHKEY_CONSTSTR::HASHKEY_CONSTSTR() { + this->m_str = nullptr; +} + +HASHKEY_CONSTSTR::HASHKEY_CONSTSTR(const char* str) { + this->m_str = str; +} + +HASHKEY_CONSTSTR::~HASHKEY_CONSTSTR() { +} + +HASHKEY_CONSTSTR& HASHKEY_CONSTSTR::operator=(const char* str) { + this->m_str = str; + return *this; +} + +HASHKEY_CONSTSTR& HASHKEY_CONSTSTR::operator=(const HASHKEY_CONSTSTR& key) { + this->operator=(key.m_str); + return *this; +} + +bool HASHKEY_CONSTSTR::operator==(const char* str) const { + return this->m_str == str || SStrCmp(this->m_str, str) == 0; +} + +bool HASHKEY_CONSTSTR::operator==(const HASHKEY_CONSTSTR& key) const { + return this->operator==(key.m_str); +} + +const char* HASHKEY_CONSTSTR::GetString() const { + return this->m_str; +} + +HASHKEY_CONSTSTRI& HASHKEY_CONSTSTRI::operator=(const char* str) { + static_cast(*this) = str; + return *this; +} + +HASHKEY_CONSTSTRI& HASHKEY_CONSTSTRI::operator=(const HASHKEY_CONSTSTRI& key) { + static_cast(*this) = key.m_str; + return *this; +} + +bool HASHKEY_CONSTSTRI::operator==(const char* str) const { + return this->m_str == str || SStrCmpI(this->m_str, str) == 0; +} + +bool HASHKEY_CONSTSTRI::operator==(const HASHKEY_CONSTSTRI& key) const { + return this->operator==(key.m_str); } diff --git a/storm/hash/Hashkey.hpp b/storm/hash/Hashkey.hpp index 6fc5419..39877c7 100644 --- a/storm/hash/Hashkey.hpp +++ b/storm/hash/Hashkey.hpp @@ -1,37 +1,80 @@ #ifndef STORM_HASH_HASHKEY_HPP #define STORM_HASH_HASHKEY_HPP -class HASHKEY_PTR { - public: - // Member variables - void* m_key; - - // Member functions - bool operator==(const HASHKEY_PTR& key); -}; - -class HASHKEY_STR { - public: - // Member variables - char* m_str; - - // Member functions - ~HASHKEY_STR(); - HASHKEY_STR& operator=(const char* str); - bool operator==(const char* str); -}; - -class HASHKEY_STRI : public HASHKEY_STR { - public: - // Member functions - HASHKEY_STRI& operator=(const char* str); - bool operator==(const char* str); -}; - class HASHKEY_NONE { public: // Member functions bool operator==(const HASHKEY_NONE& key); }; +class HASHKEY_PTR { + public: + // Member functions + HASHKEY_PTR(); + HASHKEY_PTR(void* key); + HASHKEY_PTR& operator=(const HASHKEY_PTR& key); + bool operator==(const HASHKEY_PTR& key) const; + void* GetPtr() const; + + private: + // Member variables + void* m_key; +}; + +class HASHKEY_STR { + public: + // Member functions + HASHKEY_STR(); + HASHKEY_STR(const char* str); + ~HASHKEY_STR(); + HASHKEY_STR& operator=(const char* str); + HASHKEY_STR& operator=(const HASHKEY_STR& key); + bool operator==(const char* str) const; + bool operator==(const HASHKEY_STR& key) const; + const char* GetString() const; + + protected: + // Member variables + char* m_str; +}; + +class HASHKEY_STRI : public HASHKEY_STR { + public: + // Member functions + HASHKEY_STRI() : HASHKEY_STR() {}; + HASHKEY_STRI(const char* str) : HASHKEY_STR(str) {}; + HASHKEY_STRI& operator=(const char* str); + HASHKEY_STRI& operator=(const HASHKEY_STRI& key); + bool operator==(const char* str) const; + bool operator==(const HASHKEY_STRI& key) const; +}; + +class HASHKEY_CONSTSTR { + public: + // Member functions + HASHKEY_CONSTSTR(); + HASHKEY_CONSTSTR(const char* str); + ~HASHKEY_CONSTSTR(); + HASHKEY_CONSTSTR& operator=(const char* str); + HASHKEY_CONSTSTR& operator=(const HASHKEY_CONSTSTR& key); + bool operator==(const char* str) const; + bool operator==(const HASHKEY_CONSTSTR& key) const; + const char* GetString() const; + + protected: + // Member variables + const char* m_str; +}; + +class HASHKEY_CONSTSTRI : public HASHKEY_CONSTSTR { + public: + // Member functions + HASHKEY_CONSTSTRI() : HASHKEY_CONSTSTR() {}; + HASHKEY_CONSTSTRI(const char* str) : HASHKEY_CONSTSTR(str) {}; + HASHKEY_CONSTSTRI& operator=(const char* str); + HASHKEY_CONSTSTRI& operator=(const HASHKEY_CONSTSTRI& key); + bool operator==(const char* str) const; + bool operator==(const HASHKEY_CONSTSTRI& key) const; +}; + #endif diff --git a/storm/hash/TSExportTableSimpleReuse.hpp b/storm/hash/TSExportTableSimpleReuse.hpp index f2a1854..e44203a 100644 --- a/storm/hash/TSExportTableSimpleReuse.hpp +++ b/storm/hash/TSExportTableSimpleReuse.hpp @@ -43,12 +43,12 @@ THandle TSExportTableSimpleReuse::GenerateUniqueHandle() { this->m_wrapped = 1; } - if (!this->m_wrapped || !this->Ptr(reinterpret_cast(this->m_sequence))) { + if (!this->m_wrapped || !this->Ptr(reinterpret_cast(static_cast(this->m_sequence)))) { break; } } - return reinterpret_cast(this->m_sequence); + return reinterpret_cast(static_cast(this->m_sequence)); } template diff --git a/storm/hash/TSExportTableSyncReuse.hpp b/storm/hash/TSExportTableSyncReuse.hpp index 21fdb64..5194ba4 100644 --- a/storm/hash/TSExportTableSyncReuse.hpp +++ b/storm/hash/TSExportTableSyncReuse.hpp @@ -69,7 +69,7 @@ T* TSExportTableSyncReuse::NewLock(THandle* ha template void TSExportTableSyncReuse::SyncEnterLock(TLockedHandle* lockedHandlePtr, int32_t forWriting) { this->m_sync.Enter(forWriting); - *lockedHandlePtr = reinterpret_cast(forWriting ? 1 : -1); + *lockedHandlePtr = reinterpret_cast(static_cast(forWriting ? 1 : -1)); } template diff --git a/storm/hash/TSHashObject.hpp b/storm/hash/TSHashObject.hpp index 4d38763..f8da9d3 100644 --- a/storm/hash/TSHashObject.hpp +++ b/storm/hash/TSHashObject.hpp @@ -12,6 +12,10 @@ class TSHashObject { TSLink m_linktoslot; TSLink m_linktofull; TKey m_key; + + TSHashObject & operator=(const TSHashObject &source) { + return *this; + } }; #endif diff --git a/storm/hash/TSHashTable.hpp b/storm/hash/TSHashTable.hpp index a737ed5..4a1a839 100644 --- a/storm/hash/TSHashTable.hpp +++ b/storm/hash/TSHashTable.hpp @@ -44,6 +44,7 @@ class TSHashTable { // Member functions uint32_t ComputeSlot(uint32_t hashval); + void GrowListArray(uint32_t newarraysize); void Initialize(); bool Initialized(); void InternalClear(int32_t warn); @@ -86,6 +87,31 @@ int32_t TSHashTable::GetLinkOffset() { return offsetof(T, m_linktoslot); } +template +void TSHashTable::GrowListArray(uint32_t newarraysize) { + uint32_t slotmask = this->m_slotmask + 1; + int32_t linkOffset = this->GetLinkOffset(); + + TSExplicitList templist; + templist.ChangeLinkOffset(linkOffset); + for (uint32_t i = 0; i < slotmask; i++) { + while (T* ptr = this->m_slotlistarray[i].Head()) { + templist.LinkToTail(ptr); + } + } + + this->m_slotlistarray.SetCount(newarraysize); + for (uint32_t i = 0; i < newarraysize; i++) { + this->m_slotlistarray[i].ChangeLinkOffset(linkOffset); + } + + this->m_slotmask = newarraysize - 1; + while (T* ptr = templist.Head()) { + auto& slot = this->m_slotlistarray[this->ComputeSlot(ptr->m_hashval)]; + slot.LinkToTail(ptr); + } +} + template T* TSHashTable::Head() { return this->m_fulllist.Head(); @@ -94,17 +120,13 @@ T* TSHashTable::Head() { template void TSHashTable::Initialize() { this->m_slotmask = 3; - this->m_slotlistarray.SetCount(4); + this->m_slotlistarray.SetCount(this->m_slotmask + 1); - int32_t linkOfs = this->GetLinkOffset(); - uint32_t v3 = 0; - STORM_EXPLICIT_LIST(T, m_linktoslot)* v4; + auto linkOffset = this->GetLinkOffset(); - do { - v4 = &this->m_slotlistarray[v3]; - v4->ChangeLinkOffset(linkOfs); - ++v3; - } while (v3 < this->m_slotmask); + for (uint32_t slot = 0; slot <= this->m_slotmask; slot++) { + this->m_slotlistarray[slot].ChangeLinkOffset(linkOffset); + } } template @@ -141,7 +163,7 @@ void TSHashTable::InternalClear(int32_t warn) { template void TSHashTable::InternalDelete(T* ptr) { ptr->~T(); - SMemFree(ptr, __FILE__, __LINE__, 0x0); + STORM_FREE(ptr); } template @@ -187,8 +209,26 @@ T* TSHashTable::InternalNewNode(uint32_t hashval, size_t extrabytes, ui template int32_t TSHashTable::MonitorFullness(uint32_t slot) { - // TODO + if (this->m_slotmask >= 0x1FFF) { + return 0; + } + if (this->m_fullnessIndicator > 3) { + this->m_fullnessIndicator -= 3; + } + else { + this->m_fullnessIndicator = 0; + } + + for (T* ptr = this->m_slotlistarray[slot].Head(); reinterpret_cast(ptr) > 0; ptr = this->m_slotlistarray[slot].RawNext(ptr)) { + this->m_fullnessIndicator++; + if (this->m_fullnessIndicator > 13) { + uint32_t grow_amt = 2 * this->m_slotmask + 2; + this->m_fullnessIndicator = 0; + this->GrowListArray(grow_amt); + return 1; + } + } return 0; } @@ -231,32 +271,12 @@ T* TSHashTable::Ptr(const char* str) { uint32_t hashval = SStrHashHT(str); - uint32_t slot = this->ComputeSlot(hashval); - auto slotlist = &this->m_slotlistarray[slot]; - - T* v7; - - v7 = slotlist->Head(); - - if (!v7) { - return nullptr; - } - - while (v7->m_hashval != hashval) { - uint32_t v8 = this->ComputeSlot(hashval); - auto v9 = &this->m_slotlistarray[v8]; - v7 = v9->RawNext(v7); - - if (reinterpret_cast(v7) <= 0) { - return nullptr; + for (T* ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].Head(); reinterpret_cast(ptr) > 0; ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].RawNext(ptr)) { + if (ptr->m_hashval == hashval && ptr->m_key == str) { + return ptr; } } - - if (!(v7->m_key == str)) { - // TODO Handle collisions - } - - return v7; + return nullptr; } template @@ -265,24 +285,12 @@ T* TSHashTable::Ptr(uint32_t hashval, const TKey& key) { return nullptr; } - uint32_t slot = this->ComputeSlot(hashval); - auto slotlist = &this->m_slotlistarray[slot]; - - T* ptr = slotlist->Head(); - - if (!ptr) { - return nullptr; - } - - while (ptr->m_hashval != hashval || !(ptr->m_key == key)) { - ptr = slotlist->RawNext(ptr); - - if (reinterpret_cast(ptr) <= 0) { - return nullptr; + for (T* ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].Head(); reinterpret_cast(ptr) > 0; ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].RawNext(ptr)) { + if (ptr->m_hashval == hashval && ptr->m_key == key) { + return ptr; } } - - return ptr; + return nullptr; } template diff --git a/storm/list/TSList.hpp b/storm/list/TSList.hpp index 4147911..ede49a7 100644 --- a/storm/list/TSList.hpp +++ b/storm/list/TSList.hpp @@ -9,23 +9,32 @@ #include #include +#define STORM_LIST_LINK_AFTER 1 +#define STORM_LIST_LINK_BEFORE 2 +#define STORM_LIST_HEAD STORM_LIST_LINK_AFTER +#define STORM_LIST_TAIL STORM_LIST_LINK_BEFORE + #define STORM_LIST(T) TSList> template class TSList { public: // Member variables - ptrdiff_t m_linkoffset = 0; + ptrdiff_t m_linkoffset; TSLink m_terminator; // Member functions TSList(); + TSList(const TSList& source); ~TSList(); void ChangeLinkOffset(ptrdiff_t linkoffset); void Clear(); + void Constructor(); + void CopyConstructor(const TSList& source); T* DeleteNode(T* ptr); T* Head(); void InitializeTerminator(); + bool IsEmpty(); bool IsLinked(T* ptr); TSLink* Link(const T* ptr); void LinkNode(T* ptr, uint32_t linktype, T* existingptr); @@ -44,7 +53,12 @@ class TSList { template TSList::TSList() { - this->InitializeTerminator(); + this->Constructor(); +} + +template +TSList::TSList(const TSList& source) { + this->CopyConstructor(source); } template @@ -69,12 +83,22 @@ void TSList::Clear() { } } +template +void TSList::Constructor() { + this->SetLinkOffset(0); +} + +template +void TSList::CopyConstructor(const TSList& source) { + this->SetLinkOffset(source.m_linkoffset); +} + template T* TSList::DeleteNode(T* ptr) { T* next = this->Next(ptr); ptr->~T(); - SMemFree(ptr, __FILE__, __LINE__, 0); + STORM_FREE(ptr); return next; } @@ -92,6 +116,11 @@ void TSList::InitializeTerminator() { this->m_terminator.m_next = reinterpret_cast(~reinterpret_cast(&this->m_terminator)); } +template +bool TSList::IsEmpty() { + return this->Head() == nullptr; +} + template bool TSList::IsLinked(T* ptr) { return TGetLink::Link(ptr, this->m_linkoffset)->IsLinked(); @@ -125,7 +154,7 @@ void TSList::LinkNode(T* ptr, uint32_t linktype, T* existingptr) { TSLink* v8; switch (linktype) { - case 1: + case STORM_LIST_LINK_AFTER: // After existingptr v5->m_prevlink = v7; v5->m_next = v7->m_next; @@ -134,7 +163,7 @@ void TSList::LinkNode(T* ptr, uint32_t linktype, T* existingptr) { break; - case 2: + case STORM_LIST_LINK_BEFORE: // Before existingptr v8 = v7->m_prevlink; v5->m_prevlink = v7->m_prevlink; @@ -152,12 +181,12 @@ void TSList::LinkNode(T* ptr, uint32_t linktype, T* existingptr) { template void TSList::LinkToHead(T* ptr) { - this->LinkNode(ptr, 1, nullptr); + this->LinkNode(ptr, STORM_LIST_HEAD, nullptr); } template void TSList::LinkToTail(T* ptr) { - this->LinkNode(ptr, 2, nullptr); + this->LinkNode(ptr, STORM_LIST_TAIL, nullptr); } template diff --git a/storm/queue/CSBasePriority.hpp b/storm/queue/CSBasePriority.hpp index 2c53ad1..c8c2a80 100644 --- a/storm/queue/CSBasePriority.hpp +++ b/storm/queue/CSBasePriority.hpp @@ -8,8 +8,8 @@ class CSBasePriorityQueue; class CSBasePriority { public: // Member variables - CSBasePriorityQueue* m_queue; - uint32_t m_index; + CSBasePriorityQueue* m_queue = nullptr; + uint32_t m_index = 0; // Member functions virtual bool Compare(CSBasePriority* a) = 0; diff --git a/storm/region/RGN.hpp b/storm/region/RGN.hpp index 2958d5c..6a5a199 100644 --- a/storm/region/RGN.hpp +++ b/storm/region/RGN.hpp @@ -6,6 +6,13 @@ #include "storm/Hash.hpp" #include +// Region flags +#define SF_NONE 0x00000000 +#define SF_ADDING 0x00000001 +#define SF_OVERLAPS 0x00000002 +#define SF_TEMPMASK 0x00000003 +#define SF_PARAMONLY 0x00010000 + struct SOURCE { RECTF rect; void* param; diff --git a/storm/region/Types.hpp b/storm/region/Types.hpp index 116cf30..b0a0454 100644 --- a/storm/region/Types.hpp +++ b/storm/region/Types.hpp @@ -3,16 +3,36 @@ #include "storm/Handle.hpp" #include +#include -DECLARE_HANDLE(HSRGN); - -DECLARE_HANDLE(HLOCKEDRGN); +DECLARE_STORM_HANDLE(HSRGN); +DECLARE_STORM_HANDLE(HLOCKEDRGN); +#if defined(WHOA_RECT_USES_SCREEN_COORDINATES) struct RECTF { - float left; - float bottom; - float right; - float top; + float left, top, right, bottom; }; +#else +struct RECTF { + float left, bottom, right, top; +}; +#endif + +#if defined(WHOA_SYSTEM_WIN) +// NOTE: WINAPI's RECT uses `long`. +#include +#else +struct RECT { + int32_t left, top, right, bottom; +}; +#endif + +// Combine modes +#define SRGN_AND 1 +#define SRGN_OR 2 +#define SRGN_XOR 3 +#define SRGN_DIFF 4 +#define SRGN_COPY 5 +#define SRGN_PARAMONLY 6 #endif diff --git a/storm/thread/CCritSect.cpp b/storm/thread/CCritSect.cpp index ea3b0af..baa6752 100644 --- a/storm/thread/CCritSect.cpp +++ b/storm/thread/CCritSect.cpp @@ -6,8 +6,19 @@ CCritSect::CCritSect() { #endif #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) +#if defined(WHOA_STORM_C_CRIT_SECT_RECURSIVE) + // Use of SRgnDuplicate on systems with pthreads needs recursive locking (inside s_rgntable) to prevent deadlocks. + // This behavior doesn't appear to have carried forward to World of Warcraft, probably because SCritSect was + // preferred. + pthread_mutexattr_t mutex_attr; + pthread_mutexattr_init(&mutex_attr); + pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_init(&this->m_critsect, &mutex_attr); +#else pthread_mutex_init(&this->m_critsect, nullptr); #endif +#endif } CCritSect::~CCritSect() { diff --git a/storm/thread/CSRWLock.cpp b/storm/thread/CSRWLock.cpp index 21e380d..69da98f 100644 --- a/storm/thread/CSRWLock.cpp +++ b/storm/thread/CSRWLock.cpp @@ -1,5 +1,27 @@ #include "storm/thread/CSRWLock.hpp" +CSRWLock::CSRWLock() { +#if defined(WHOA_SYSTEM_WIN) + // TODO + SRWLock::SURWLockInitialize(&this->m_opaqueData); +#endif + +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + pthread_rwlock_init(&this->m_lock, nullptr); +#endif +} + +CSRWLock::~CSRWLock() { +#if defined(WHOA_SYSTEM_WIN) + SRWLock::SURWLockDelete(&this->m_opaqueData); + // TODO +#endif + +#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) + pthread_rwlock_destroy(&this->m_lock); +#endif +} + void CSRWLock::Enter(int32_t forwriting) { #if defined(WHOA_SYSTEM_WIN) SRWLock::SURWLockEnter(&this->m_opaqueData, forwriting); diff --git a/storm/thread/CSRWLock.hpp b/storm/thread/CSRWLock.hpp index bcdd5f2..0644238 100644 --- a/storm/thread/CSRWLock.hpp +++ b/storm/thread/CSRWLock.hpp @@ -23,6 +23,8 @@ class CSRWLock { #endif // Member functions + CSRWLock(); + ~CSRWLock(); void Enter(int32_t forwriting); void Leave(int32_t fromwriting); }; diff --git a/storm/thread/SSyncObject.cpp b/storm/thread/SSyncObject.cpp index 4df43b0..0aec97c 100644 --- a/storm/thread/SSyncObject.cpp +++ b/storm/thread/SSyncObject.cpp @@ -8,7 +8,7 @@ SSyncObject::SSyncObject() { #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) - pthread_mutex_init(&this->m_mutex, 0); + pthread_mutex_init(&this->m_mutex, nullptr); #endif } diff --git a/storm/thread/linux/S_Thread.cpp b/storm/thread/linux/S_Thread.cpp index d8a3735..80c0d48 100644 --- a/storm/thread/linux/S_Thread.cpp +++ b/storm/thread/linux/S_Thread.cpp @@ -20,7 +20,7 @@ void* S_Thread::s_SLaunchThread(void* threadParam) { pthread_cond_signal(¶ms->syncObject->m_cond); } - SMemFree(threadParam); + STORM_FREE(threadParam); return nullptr; } diff --git a/storm/thread/linux/Thread.cpp b/storm/thread/linux/Thread.cpp index 58f92bb..4879cf8 100644 --- a/storm/thread/linux/Thread.cpp +++ b/storm/thread/linux/Thread.cpp @@ -40,8 +40,7 @@ void* SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, uint32_t threadId = S_Thread::s_threadID++; - void* m = SMemAlloc(sizeof(SThreadParmBlock), __FILE__, __LINE__, 0x8); - auto params = new (m) SThreadParmBlock(); + auto params = STORM_NEW_ZERO(SThreadParmBlock); params->threadProc = threadProc; params->threadParam = threadParam; params->threadID = threadId; diff --git a/storm/thread/mac/S_Thread.mm b/storm/thread/mac/S_Thread.mm index 5926f42..ea131e5 100644 --- a/storm/thread/mac/S_Thread.mm +++ b/storm/thread/mac/S_Thread.mm @@ -37,7 +37,7 @@ uint32_t S_Thread::s_SLaunchThread(void* threadParam) { pthread_cond_signal(¶ms->syncObject->m_cond); } - SMemFree(threadParam); + STORM_FREE(threadParam); return 0; } diff --git a/storm/thread/mac/Thread.mm b/storm/thread/mac/Thread.mm index d722bb8..e06653d 100644 --- a/storm/thread/mac/Thread.mm +++ b/storm/thread/mac/Thread.mm @@ -40,8 +40,7 @@ void* SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, uint32_t threadId = S_Thread::s_threadID++; - void* m = SMemAlloc(sizeof(SThreadParmBlock), __FILE__, __LINE__, 0x8); - auto params = new (m) SThreadParmBlock(); + auto params = STORM_NEW_ZERO(SThreadParmBlock); params->threadProc = threadProc; params->threadParam = threadParam; params->threadID = threadId; diff --git a/storm/thread/win/SRWLock.cpp b/storm/thread/win/SRWLock.cpp index 4359f85..7f18769 100644 --- a/storm/thread/win/SRWLock.cpp +++ b/storm/thread/win/SRWLock.cpp @@ -8,6 +8,14 @@ void SRWLock::SUNNLockLeave(volatile SUNNLOCK* sunnlock) { // TODO } +void SRWLock::SURWLockInitialize(volatile SRWLock::SURWLOCK* surwlock) { + // TODO +} + +void SRWLock::SURWLockDelete(volatile SRWLock::SURWLOCK* surwlock) { + // TODO +} + void SRWLock::SURWLockEnter(volatile SURWLOCK* surwlock, int32_t forwriting) { // TODO } diff --git a/storm/thread/win/SRWLock.hpp b/storm/thread/win/SRWLock.hpp index e556271..56706e8 100644 --- a/storm/thread/win/SRWLock.hpp +++ b/storm/thread/win/SRWLock.hpp @@ -19,6 +19,8 @@ class SRWLock { // Static functions static void SUNNLockEnter(volatile SUNNLOCK* sunnlock); static void SUNNLockLeave(volatile SUNNLOCK* sunnlock); + static void SURWLockInitialize(volatile SURWLOCK* surwlock); + static void SURWLockDelete(volatile SURWLOCK* surwlock); static void SURWLockEnter(volatile SURWLOCK* surwlock, int32_t forwriting); static void SURWLockLeave(volatile SURWLOCK* surwlock, int32_t fromwriting); }; diff --git a/storm/thread/win/S_Thread.cpp b/storm/thread/win/S_Thread.cpp index b12a064..52e4c27 100644 --- a/storm/thread/win/S_Thread.cpp +++ b/storm/thread/win/S_Thread.cpp @@ -6,7 +6,7 @@ DWORD WINAPI S_Thread::s_SLaunchThread(void* threadParam) { auto proc = params->threadProc; auto param = params->threadParam; - SMemFree(threadParam); + STORM_FREE(threadParam); auto val = proc(param); diff --git a/storm/thread/win/Thread.cpp b/storm/thread/win/Thread.cpp index c0b70bb..3f2ed4d 100644 --- a/storm/thread/win/Thread.cpp +++ b/storm/thread/win/Thread.cpp @@ -38,8 +38,7 @@ void* SCreateThread(uint32_t (*threadProc)(void*), void* threadParam, void* a3, */ } - void* m = SMemAlloc(sizeof(SThreadParmBlock), __FILE__, __LINE__, 0x8); - auto params = new (m) SThreadParmBlock(); + auto params = STORM_NEW(SThreadParmBlock); params->threadProc = threadProc; params->threadParam = threadParam; diff --git a/test/Big.cpp b/test/Big.cpp index 7902b31..9cead82 100644 --- a/test/Big.cpp +++ b/test/Big.cpp @@ -1,4 +1,5 @@ #include "storm/Big.hpp" +#include "storm/big/BigData.hpp" #include "test/Test.hpp" #include "test/big/BigDataTest.hpp" #include diff --git a/test/big/Ops.cpp b/test/big/Ops.cpp index 3e9bd3f..b5f4f97 100644 --- a/test/big/Ops.cpp +++ b/test/big/Ops.cpp @@ -1,4 +1,5 @@ #include "storm/Big.hpp" +#include "storm/big/BigData.hpp" #include "storm/big/Ops.hpp" #include "test/Test.hpp" #include "test/big/BigDataTest.hpp"