feat: sync with Whoa implementation

This commit is contained in:
VDm 2026-04-26 17:10:11 +04:00
parent 12ab8f7721
commit 6928bf3f0c
46 changed files with 2980 additions and 441 deletions

2
lib/bc

@ -1 +1 @@
Subproject commit 367b8149f36a1e4c2aad066e0cf9cd1e07ae7d88
Subproject commit b9dd205765782a44afc03740f3047ab2be5f1c4f

View file

@ -1,17 +1,18 @@
#include "storm/Big.hpp"
#include "storm/big/BigData.hpp"
#include "storm/big/Ops.hpp"
#include <bc/Memory.hpp>
#include <cstring>
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());
}

View file

@ -1,63 +1,66 @@
#ifndef STORM_BIG_HPP
#define STORM_BIG_HPP
#include "storm/big/BigData.hpp"
#include <cstdint>
#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

View file

@ -7,7 +7,7 @@ file(GLOB STORM_SOURCES
"crypto/*.cpp"
"error/*.cpp"
"hash/*.cpp"
"option*/*.cpp"
"option/*.cpp"
"queue/*.cpp"
"string/*.cpp"
"thread/*.cpp"

31
storm/Core.cpp Normal file
View file

@ -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;
}

23
storm/Core.hpp Normal file
View file

@ -0,0 +1,23 @@
#ifndef STORM_CORE_HPP
#define STORM_CORE_HPP
#include <cstdint>
#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

420
storm/Event.cpp Normal file
View file

@ -0,0 +1,420 @@
#include "Event.hpp"
#include <cstdint>
#include "list/TSList.hpp"
#include "thread/CCritSect.hpp"
#include "Atomic.hpp"
#include "Error.hpp"
#include <bc/Memory.hpp>
struct BREAKCMD : public TSLinkedNode<BREAKCMD> {
void* data;
};
static CCritSect s_critsect;
static TSList<BREAKCMD, TSGetLink<BREAKCMD>> 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<intptr_t>(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<intptr_t>(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;
}

25
storm/Event.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef STORM_EVENT_HPP
#define STORM_EVENT_HPP
#include <cstdint>
#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

View file

@ -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

View file

@ -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();

View file

@ -3,10 +3,21 @@
#include "storm/Error.hpp"
#include "storm/Hash.hpp"
#include "storm/Thread.hpp"
#include <limits>
static TSExportTableSyncReuse<RGN, HSRGN, HLOCKEDRGN, CCritSect> s_rgntable;
void DeleteCombinedRect(TSGrowableArray<RECTF>* combinedArray, uint32_t index);
void DeleteRect(RECTF* rect);
void DeleteSourceRect(TSGrowableArray<SOURCE>* sourceArray, uint32_t index);
int32_t IsNullRect(const RECTF* rect);
void AddCombinedRect(TSGrowableArray<RECTF>* combinedArray, const RECTF* rect) {
RECTF* newRect = combinedArray->New();
*newRect = *rect;
}
void AddSourceRect(TSGrowableArray<SOURCE>* sourceArray, const RECTF* rect, void* param, int32_t sequence, uint32_t flags) {
auto source = sourceArray->New();
@ -17,10 +28,91 @@ void AddSourceRect(TSGrowableArray<SOURCE>* 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<RECTF>* 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<RECTF>* combinedArray, uint32_t index) {
DeleteRect(&(*combinedArray)[index]);
}
void DeleteRect(RECTF* rect) {
rect->left = std::numeric_limits<float>::max();
rect->bottom = std::numeric_limits<float>::max();
@ -37,37 +133,249 @@ void DeleteRect(RECTF* rect) {
rect->top = std::numeric_limits<float>::max();
}
void FragmentSourceRectangles(TSGrowableArray<SOURCE>* 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<const FOUNDPARAM*>(elem1);
const FOUNDPARAM* param2 = static_cast<const FOUNDPARAM*>(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<RECTF>* 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<SOURCE>* 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<SOURCE>* sourceArray, uint32_t index) {
DeleteRect(&source->rect);
source->param = nullptr;
source->sequence = -1;
source->flags = 0x0;
source->flags = SF_NONE;
}
void OptimizeSource(TSGrowableArray<SOURCE>* 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<SOURCE>* 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<const RECTF*>(elem1);
const RECTF* rct2 = static_cast<const RECTF*>(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<float>(rect->left),
static_cast<float>(rect->top),
static_cast<float>(rect->right),
static_cast<float>(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<float>::max();
rect->bottom = std::numeric_limits<float>::max();
rect->right = std::numeric_limits<float>::min();
rect->top = std::numeric_limits<float>::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<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::min(),
std::numeric_limits<float>::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<int32_t>(rectf.left);
rect->right = static_cast<int32_t>(rectf.right);
#if defined(WHOA_RECT_USES_SCREEN_COORDINATES)
rect->top = static_cast<int32_t>(rectf.top);
rect->bottom = static_cast<int32_t>(rectf.bottom);
#else
// NOTE: top and bottom get flipped, this is a bug in Storm
rect->top = static_cast<int32_t>(rectf.bottom);
rect->bottom = static_cast<int32_t>(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<float>(rect->left),
static_cast<float>(rect->top),
static_cast<float>(rect->right),
static_cast<float>(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<RECTF*>(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<int32_t>(bufferf[i].top);
buffer[i].bottom = static_cast<int32_t>(bufferf[i].bottom);
#else
float bottom = bufferf[i].bottom;
float top = bufferf[i].top;
buffer[i].bottom = static_cast<int32_t>(bottom);
buffer[i].top = static_cast<int32_t>(top);
#endif
buffer[i].left = static_cast<int32_t>(bufferf[i].left);
buffer[i].right = static_cast<int32_t>(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<float>(x), static_cast<float>(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<float>(rect->left),
static_cast<float>(rect->top),
static_cast<float>(rect->right),
static_cast<float>(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<float>(xoffset), static_cast<float>(yoffset));
}

View file

@ -2,14 +2,44 @@
#define STORM_REGION_HPP
#include "storm/region/Types.hpp"
#include <cstdint>
#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

View file

@ -7,7 +7,6 @@
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <algorithm>
#if defined(WHOA_SYSTEM_WIN)
#include <string.h>
@ -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<size_t>(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<char*>(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<uint8_t>(*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<uint8_t>(*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<char>(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<uint32_t>(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<float>(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<float>(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<char>(toupper(*string));
string++;

View file

@ -1,50 +1,69 @@
#ifndef STORM_STRING_HPP
#define STORM_STRING_HPP
#include <cstdint>
#include <cstdarg>
#include <cstdlib>
#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

804
storm/Transparency.cpp Normal file
View file

@ -0,0 +1,804 @@
#include "storm/Transparency.hpp"
#include "storm/List.hpp"
#include "storm/Error.hpp"
#include <algorithm>
#include <climits>
#include <cstring>
#define COPY 0
#define SKIP 1
#define NUM_OPS 2
#define MAXSPANLENGTH 0xFC
#define TRANS_CHUNKSIZE 4096
struct TRANS : TSLinkedNode<TRANS> {
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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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<uint32_t>(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<uint8_t*>(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<uint32_t*>(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;
}

51
storm/Transparency.hpp Normal file
View file

@ -0,0 +1,51 @@
#ifndef STORM_TRANSPARENCY_HPP
#define STORM_TRANSPARENCY_HPP
#include <cstdint>
#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

View file

@ -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<T>::operator[](uint32_t index) {
return this->m_data[index];
}
template <class T>
const T& TSBaseArray<T>::operator[](uint32_t index) const {
this->CheckArrayBounds(index);
return this->m_data[index];
}
template <class T>
void TSBaseArray<T>::CheckArrayBounds(uint32_t index) const {
if (index < this->Count()) {
@ -40,14 +47,15 @@ void TSBaseArray<T>::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 <class T>

View file

@ -8,9 +8,11 @@
template <class T>
class TSFixedArray : public TSBaseArray<T> {
public:
// Member functions
TSFixedArray();
TSFixedArray(const TSFixedArray& source);
~TSFixedArray();
TSFixedArray<T>& operator=(const TSFixedArray<T>& source);
TSFixedArray& operator=(const TSFixedArray& source);
void Clear();
void ReallocAndClearData(uint32_t count);
void ReallocData(uint32_t count);
@ -23,6 +25,12 @@ TSFixedArray<T>::TSFixedArray() {
this->Constructor();
}
template <class T>
TSFixedArray<T>::TSFixedArray(const TSFixedArray<T>& source) {
this->Constructor();
this->Set(source.Count(), source.Ptr());
}
template <class T>
TSFixedArray<T>::~TSFixedArray() {
for (uint32_t i = 0; i < this->Count(); i++) {
@ -41,22 +49,31 @@ TSFixedArray<T>& TSFixedArray<T>::operator=(const TSFixedArray<T>& source) {
this->Set(source.Count(), source.Ptr());
}
return *this;
return *this;
}
template <class T>
void TSFixedArray<T>::Clear() {
this->~TSFixedArray<T>();
this->Constructor();
this->~TSFixedArray<T>();
this->Constructor();
}
template <class T>
void TSFixedArray<T>::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<T*>(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<T*>(m);
}
}
}

View file

@ -6,17 +6,20 @@
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <new>
template <class T>
class TSGrowableArray : public TSFixedArray<T> {
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);

View file

@ -483,6 +483,11 @@ void ToStream(TSGrowableArray<uint8_t>& 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++) {

View file

@ -75,6 +75,8 @@ void ToBinary(TSGrowableArray<uint8_t>& output, const BigBuffer& buffer);
void ToStream(TSGrowableArray<uint8_t>& output, const BigBuffer& buffer);
void ToUnsigned(uint32_t* a, const BigBuffer& b);
void Xor(BigBuffer& a, const BigBuffer& b, const BigBuffer& c);
#endif

View file

@ -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))

View file

@ -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<HASHKEY_STR&>(*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<HASHKEY_STR&>(*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<HASHKEY_CONSTSTR&>(*this) = str;
return *this;
}
HASHKEY_CONSTSTRI& HASHKEY_CONSTSTRI::operator=(const HASHKEY_CONSTSTRI& key) {
static_cast<HASHKEY_CONSTSTR&>(*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);
}

View file

@ -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

View file

@ -43,12 +43,12 @@ THandle TSExportTableSimpleReuse<T, THandle>::GenerateUniqueHandle() {
this->m_wrapped = 1;
}
if (!this->m_wrapped || !this->Ptr(reinterpret_cast<THandle>(this->m_sequence))) {
if (!this->m_wrapped || !this->Ptr(reinterpret_cast<THandle>(static_cast<uintptr_t>(this->m_sequence)))) {
break;
}
}
return reinterpret_cast<THandle>(this->m_sequence);
return reinterpret_cast<THandle>(static_cast<uintptr_t>(this->m_sequence));
}
template <class T, class THandle>

View file

@ -69,7 +69,7 @@ T* TSExportTableSyncReuse<T, THandle, TLockedHandle, TSync>::NewLock(THandle* ha
template <class T, class THandle, class TLockedHandle, class TSync>
void TSExportTableSyncReuse<T, THandle, TLockedHandle, TSync>::SyncEnterLock(TLockedHandle* lockedHandlePtr, int32_t forWriting) {
this->m_sync.Enter(forWriting);
*lockedHandlePtr = reinterpret_cast<TLockedHandle>(forWriting ? 1 : -1);
*lockedHandlePtr = reinterpret_cast<TLockedHandle>(static_cast<intptr_t>(forWriting ? 1 : -1));
}
template <class T, class THandle, class TLockedHandle, class TSync>

View file

@ -12,6 +12,10 @@ class TSHashObject {
TSLink<T> m_linktoslot;
TSLink<T> m_linktofull;
TKey m_key;
TSHashObject & operator=(const TSHashObject &source) {
return *this;
}
};
#endif

View file

@ -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<T, TKey>::GetLinkOffset() {
return offsetof(T, m_linktoslot);
}
template <class T, class TKey>
void TSHashTable<T, TKey>::GrowListArray(uint32_t newarraysize) {
uint32_t slotmask = this->m_slotmask + 1;
int32_t linkOffset = this->GetLinkOffset();
TSExplicitList<T, 0xDDDDDDDD> 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 <class T, class TKey>
T* TSHashTable<T, TKey>::Head() {
return this->m_fulllist.Head();
@ -94,17 +120,13 @@ T* TSHashTable<T, TKey>::Head() {
template <class T, class TKey>
void TSHashTable<T, TKey>::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 <class T, class TKey>
@ -141,7 +163,7 @@ void TSHashTable<T, TKey>::InternalClear(int32_t warn) {
template <class T, class TKey>
void TSHashTable<T, TKey>::InternalDelete(T* ptr) {
ptr->~T();
SMemFree(ptr, __FILE__, __LINE__, 0x0);
STORM_FREE(ptr);
}
template <class T, class TKey>
@ -187,8 +209,26 @@ T* TSHashTable<T, TKey>::InternalNewNode(uint32_t hashval, size_t extrabytes, ui
template <class T, class TKey>
int32_t TSHashTable<T, TKey>::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<intptr_t>(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<T, TKey>::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<intptr_t>(v7) <= 0) {
return nullptr;
for (T* ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].Head(); reinterpret_cast<intptr_t>(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 <class T, class TKey>
@ -265,24 +285,12 @@ T* TSHashTable<T, TKey>::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<intptr_t>(ptr) <= 0) {
return nullptr;
for (T* ptr = this->m_slotlistarray[this->ComputeSlot(hashval)].Head(); reinterpret_cast<intptr_t>(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 <class T, class TKey>

View file

@ -9,23 +9,32 @@
#include <typeinfo>
#include <new>
#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<T, TSGetLink<T>>
template <class T, class TGetLink>
class TSList {
public:
// Member variables
ptrdiff_t m_linkoffset = 0;
ptrdiff_t m_linkoffset;
TSLink<T> 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<T>* Link(const T* ptr);
void LinkNode(T* ptr, uint32_t linktype, T* existingptr);
@ -44,7 +53,12 @@ class TSList {
template <class T, class TGetLink>
TSList<T, TGetLink>::TSList() {
this->InitializeTerminator();
this->Constructor();
}
template <class T, class TGetLink>
TSList<T, TGetLink>::TSList(const TSList& source) {
this->CopyConstructor(source);
}
template <class T, class TGetLink>
@ -69,12 +83,22 @@ void TSList<T, TGetLink>::Clear() {
}
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::Constructor() {
this->SetLinkOffset(0);
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::CopyConstructor(const TSList& source) {
this->SetLinkOffset(source.m_linkoffset);
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::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<T, TGetLink>::InitializeTerminator() {
this->m_terminator.m_next = reinterpret_cast<T*>(~reinterpret_cast<uintptr_t>(&this->m_terminator));
}
template <class T, class TGetLink>
bool TSList<T, TGetLink>::IsEmpty() {
return this->Head() == nullptr;
}
template <class T, class TGetLink>
bool TSList<T, TGetLink>::IsLinked(T* ptr) {
return TGetLink::Link(ptr, this->m_linkoffset)->IsLinked();
@ -125,7 +154,7 @@ void TSList<T, TGetLink>::LinkNode(T* ptr, uint32_t linktype, T* existingptr) {
TSLink<T>* 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<T, TGetLink>::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<T, TGetLink>::LinkNode(T* ptr, uint32_t linktype, T* existingptr) {
template <class T, class TGetLink>
void TSList<T, TGetLink>::LinkToHead(T* ptr) {
this->LinkNode(ptr, 1, nullptr);
this->LinkNode(ptr, STORM_LIST_HEAD, nullptr);
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::LinkToTail(T* ptr) {
this->LinkNode(ptr, 2, nullptr);
this->LinkNode(ptr, STORM_LIST_TAIL, nullptr);
}
template <class T, class TGetLink>

View file

@ -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;

View file

@ -6,6 +6,13 @@
#include "storm/Hash.hpp"
#include <cstdint>
// 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;

View file

@ -3,16 +3,36 @@
#include "storm/Handle.hpp"
#include <cstdint>
#include <limits>
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 <Windows.h>
#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

View file

@ -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() {

View file

@ -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);

View file

@ -23,6 +23,8 @@ class CSRWLock {
#endif
// Member functions
CSRWLock();
~CSRWLock();
void Enter(int32_t forwriting);
void Leave(int32_t fromwriting);
};

View file

@ -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
}

View file

@ -20,7 +20,7 @@ void* S_Thread::s_SLaunchThread(void* threadParam) {
pthread_cond_signal(&params->syncObject->m_cond);
}
SMemFree(threadParam);
STORM_FREE(threadParam);
return nullptr;
}

View file

@ -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;

View file

@ -37,7 +37,7 @@ uint32_t S_Thread::s_SLaunchThread(void* threadParam) {
pthread_cond_signal(&params->syncObject->m_cond);
}
SMemFree(threadParam);
STORM_FREE(threadParam);
return 0;
}

View file

@ -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;

View file

@ -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
}

View file

@ -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);
};

View file

@ -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);

View file

@ -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;

View file

@ -1,4 +1,5 @@
#include "storm/Big.hpp"
#include "storm/big/BigData.hpp"
#include "test/Test.hpp"
#include "test/big/BigDataTest.hpp"
#include <string>

View file

@ -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"