#include "stdafx.h"
#include "ogEngine.h"

#include <stdlib.h>

static void (*__rwStringOpen) () = (void (__cdecl *)())0x80A240;


bool CEngine::init(DWORD _resArenaSize) {
////////////////////////////////////////////
	return true;
}


struct CPluginRegEntry {	// TODO: make class (with methods)
	int		offset;
	int		size;
	DWORD	pluginID;
	pluginWriteCB		writeCB;
	pluginReadCB		readCB;
	pluginGetSizeCB		getSizeCB;
	pluginAlwaysCB		alwaysCB;
	pluginRightsCB		rightsCB;
	pluginConstructCB	constructCB;
	pluginDestructCB	destructCB;
	pluginCopyCB		copyCB;
/*	pluginErrStrCB		errStrCB;
	CPluginRegEntry		*next;
	CPluginRegEntry		*prev;
	CPluginRegEntry		*parent;*/
};

#define PLUGIN_REGISTRY_SIZE 32
class CPluginRegistry {
public:
	CPluginRegistry (int initialSize);
	~CPluginRegistry ();

	int		addPlugin (DWORD pluginID, int size, pluginConstructCB constructCB, pluginDestructCB destructCB, pluginCopyCB copyCB);
	int		getOffset (DWORD pluginID);
	bool	initObject (void * object);
	bool	deinitObject (void * object);
	bool	copyObject (void * dstObject, const void * srcObject);
	int		getSize (void * object);

	int		addPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB);
	int		addPluginAlwaysCB (DWORD pluginID, pluginAlwaysCB alwaysCB);

protected:
	int		entryCount;	// number of allocated registry entries
	CPluginRegEntry		entries[PLUGIN_REGISTRY_SIZE];

	int		totalSize;
	int		originalSize;
	int		maxSize;
	bool	staticAlloc;
};
// ############################################################################

static CBlockAllocator * __allocatorsList = NULL;	// list of all allocators

CBlockAllocator::CBlockAllocator(DWORD _entrySize, DWORD _entriesPerBlock, DWORD preallocateBlocks, DWORD _alignment) {
	alignment = (_alignment != 1 && _alignment != 4) ? 16 : _alignment;	
		 
	entrySize = (_entrySize + alignment - 1) & ~(alignment-1);
	entriesPerBlock = _entriesPerBlock ? _entriesPerBlock : 1;
	blocks = NULL;
	link = NULL;
	flags = 2;	// release blocks ASAP

	int mapSize = (entriesPerBlock+31) >> 5;	// element count in block map
	blockHeadSize = (sizeof(BlockHead)+(mapSize-1)*4 + alignment-1) & ~(alignment-1);
	
	debug ("CBlockAllocator created: entrySize = %d, entriesPerBlock = %d, alignment = %d, preallocated = %d\n",
		entrySize, entriesPerBlock, alignment, preallocateBlocks);

	while (preallocateBlocks-- > 0) 
		allocateBlock (); // TODO: check error!

	// TODO2: для многопоточной системы нужны блокировки!
	link = __allocatorsList;
	__allocatorsList = this;
}

CBlockAllocator::~CBlockAllocator() {
	while (blocks)
		freeBlock (NULL);

	if (__allocatorsList == this) 
		__allocatorsList = link;
	else 
		for (CBlockAllocator * ba = __allocatorsList; ba != NULL; ba = ba->link) 		
			if (ba->link == this) {
				ba->link = ba->link->link;
				break;
			}
	debug ("CBlockAllocator destroyed\n");
}

bool CBlockAllocator::allocateBlock() {
	BlockHead * b = (BlockHead *)new BYTE[blockHeadSize+entrySize*entriesPerBlock];
	memset (b, 0, blockHeadSize);
	b->next = blocks;	// add block to the block list
	blocks = b;
	return true;
}

void CBlockAllocator::freeBlock(CBlockAllocator::BlockHead *prevBlock) {
	if (flags & 0x10000) {
		debug ("CBlockAllocator::freeBlock - ERROR: attempt to free block while iterating\n");
		return;
	}
	if (prevBlock) {
		if (!prevBlock->next)
			return;	// bad parameter
		BlockHead * next = prevBlock->next->next;
		delete prevBlock->next;
		prevBlock->next = next;
	} else if (blocks) {	// release first block
		BlockHead * next = blocks->next;
		delete blocks;
		blocks = next;
	}
}

BYTE * CBlockAllocator::allocateEntry() {
	for (BlockHead * b = blocks; b; b = b->next) {
		if (b->allocated >= entriesPerBlock)
			continue;
		
		int entryCount = entriesPerBlock;
		int mapIndex = 0;
		while (entryCount > 0) {
			DWORD mask = entryCount > 32 ? 0xFFFFFFFF : (1 << entryCount)-1;
			if (b->usageMap[mapIndex] != mask) {
				for (int i = 0; i < 32; i++) 
					if (!(b->usageMap[mapIndex] & (1 << i))) {	// free entry found
						b->usageMap[mapIndex] |= (1 << i);
						b->allocated++;
						return ((BYTE *)b)+blockHeadSize+(mapIndex*32+i)*entrySize;
					}				
				// TODO: blocks integrity corrupted
					debug ("CBlockAllocator::allocateEntry: integrity error: usageMap and allocated count mismatch\n");
			}
			entryCount -= 32;
			mapIndex++;
		}
	}
	// all block allocated. allocate new block
	allocateBlock ();
	blocks->usageMap[0] = 1;	// allocate first entry
	blocks->allocated = 1;
	return ((BYTE *)blocks)+blockHeadSize;
}

void CBlockAllocator::freeEntry(BYTE *ptr) {
	BlockHead * prev = NULL;
	DWORD pp = (DWORD)ptr;
	for (BlockHead * b = blocks; b; prev = b, b = b->next) {		
		DWORD bp = ((DWORD)b)+blockHeadSize;
		if (pp >= bp && pp < bp+entrySize*entriesPerBlock) {
			int i = (pp-bp)/entrySize;
			// TODO: для отладки было бы неплохо проверить, что делится нацело.			
			// TODO:  а также, что allocated > 0
			if ((pp-bp)%entrySize || b->allocated == 0) {
				debug ("CBlockAllocator::freeEntry - memory integrity error: block = %08x, allocated = %d,  entry=%08x\n", bp, b->allocated, pp);
				return;
			}
			b->usageMap[i >> 5] &= ~(1 << (i&31));			
			b->allocated--;
			if ((flags & 2) && b->allocated == 0)
				freeBlock (prev);
			return;
		}
	}
	debug ("CBlockAllocator::freeEntry - error: entry %08x not found\n", pp);
}

void CBlockAllocator::forAllUsed (cbaCallback cb, void * param) {
	
	flags |= 0x10000;	// prevent block releasing

	int mapSize = (entriesPerBlock+31) >> 5;
	for (BlockHead * b = blocks; b; b = b->next) {		
		if (b->allocated == 0)
			continue;
		for (int i = 0; i < mapSize; i++) {
			DWORD m = b->usageMap[i];
			for (int j = 0; j < 32; j++) 
				if (m & (1<<j)) 
					cb (((BYTE *)b)+blockHeadSize, param);	// главное, чтобы здесь в цикле блоки не удалялись (это, конечно, можно учесть, но все же...)
		}
	}

	flags &= ~0x10000;
}

int CBlockAllocator::purge() {
	BlockHead * prev = NULL;
	BlockHead * cur = blocks;
	int purged = 0;
	while (cur) {
		if (cur->allocated) {
			prev = cur;
			cur = cur->next;
		} else {
			freeBlock (prev);
			cur = prev ? prev->next : blocks;
			purged++;
		}
	}
	return purged;
}

int CBlockAllocator::purgeAll() {
	int purged = 0;
	for (CBlockAllocator * cur = __allocatorsList; cur; cur = cur->link)
		purged += cur->purge();
	return purged;
}

// ############################################################################
CPluginRegistry::CPluginRegistry(int initialSize) {
	entryCount = 0;
	totalSize = originalSize = initialSize;
	maxSize = 0;
	staticAlloc = false;
}

CPluginRegistry::~CPluginRegistry() {
}

static void * __defaultPluginConstructor (void * object, int offset, int size) {
	return object;
}
static void * __defaultPluginDestructor (void * object, int offset, int size) {
	return object;
}
static void * __defaultPluginCopy (void * object, const void * srcObject, int offset, int size) {
	return object;
}

int CPluginRegistry::addPlugin(DWORD pluginID, int size, pluginConstructCB constructCB, pluginDestructCB destructCB, pluginCopyCB copyCB) {
	// NOTE: здесь должна быть проверка на то, что engine еще не проинициализирован
	if (entryCount >= PLUGIN_REGISTRY_SIZE) {
		debug ("CPluginRegistry::addPlugin - error: out of free slots\n");
		return -1;
	}
	// NOTE: здесь пропущена проверка на то, что такой плагин уже добавлен. 
	//		для данного случая, это не нужно, но вообще, стоило бы добавить
	CPluginRegEntry * entry = entries+entryCount;	
	
	entry->offset = totalSize;	
	entry->size = size;
	entry->pluginID = pluginID;
	entry->constructCB = constructCB ? constructCB : __defaultPluginConstructor;
	entry->destructCB = destructCB ? destructCB : __defaultPluginDestructor;
	entry->copyCB = copyCB ? copyCB : __defaultPluginCopy;
	entry->readCB = NULL;
	entry->writeCB = NULL;
	entry->getSizeCB = NULL;
	entry->alwaysCB = NULL;
	entry->rightsCB = NULL;

	totalSize += (size+3)&~3;
	// NOTE: здесь была проверка на maxSize. Что с ней делать - пока непонятно

	entryCount++;
	return entry->offset;
}

int CPluginRegistry::getOffset (DWORD pluginID) {
	for (int i = 0; i < entryCount; i++)
		if (entries[i].pluginID == pluginID)
			return entries[i].offset;
	return -1;
}

bool CPluginRegistry::initObject(void *object) {	
	for (int i = 0; i < entryCount; i++) {
		void * obj = entries[i].constructCB(object, entries[i].offset, entries[i].size);
		if (!obj) {
			for (i--; i >= 0; i--)
				entries[i].destructCB(object, entries[i].offset, entries[i].size);
			return false;
		}		
	}
	return true;
}

bool CPluginRegistry::deinitObject(void *object) {
	for (int i = entryCount-1; i >= 0; i--) 
		entries[i].destructCB(object, entries[i].offset, entries[i].size);
	return true;
}

bool CPluginRegistry::copyObject(void *dstObject, const void *srcObject) {
	for (int i = 0; i < entryCount; i++)
		entries[i].copyCB (dstObject, srcObject, entries[i].offset, entries[i].size);
	return true;
}

int CPluginRegistry::getSize(void *object) {
	int size = 0;
	for (int i = entryCount-1; i >= 0; i--) 
		if (entries[i].getSizeCB) {
			int s = entries[i].getSizeCB(object, entries[i].offset, entries[i].size);
			if (s > 0)
				size += s+12;
		}
	
	return size;
}

int CPluginRegistry::addPluginStream(DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {
	for (int i = 0; i < entryCount; i++) 
		if (entries[i].pluginID == pluginID) {
			entries[i].readCB = readCB;
			entries[i].writeCB = writeCB;
			entries[i].getSizeCB = getSizeCB;
			return entries[i].offset;
		}
	return -1;
}

int CPluginRegistry::addPluginAlwaysCB(DWORD pluginID, pluginAlwaysCB alwaysCB) {
	for (int i = 0; i < entryCount; i++) 
		if (entries[i].pluginID == pluginID) {
			entries[i].alwaysCB = alwaysCB;
			return entries[i].offset;
		}
	return -1;
}
// ############################################################################
// RWG compatibility layer
// bamemory

// _rwFreeListEnable (801970) - можно не трогать: она меняет флаг, который я не использую
// _rwFreeListCreate (801980) - вызывает FreeListCreate c бОльшин набором параметров
// RwFreeListCreateAndPreallocateSpace (801B70) - переход на FreeListCreate
// 

void * FreeListCreate (int entrySize,int entriesPerBlock,int alignment,
										   int numBlocksToPreallocate,void *inPlaceSpaceForFreeListStruct,int hint) {	// 8019B0
	return new CBlockAllocator (entrySize, entriesPerBlock, numBlocksToPreallocate, alignment);
}

int RwFreeListDestroy (void * freelist) { // >> 801B80
	delete ((CBlockAllocator *)freelist);
	return 1;
}

BYTE * _rwFreeListAllocReal (void * freelist, int hint) {	// 801C30
	return ((CBlockAllocator *)freelist)->allocateEntry ();
}
void * _rwFreeListFreeReal (void * freelist, BYTE * ptr) { // >> 801D50
	((CBlockAllocator *)freelist)->freeEntry (ptr);
	return freelist;
}

int RwFreeListPurge (void * freelist) { // 801E00
	return ((CBlockAllocator *)freelist)->purge ();
}

void * RwFreeListForAllUsed (void * freelist, cbaCallback cb, void * param) { // >> 801E90
	((CBlockAllocator *)freelist)->forAllUsed (cb, param);
	return freelist;
}

int RwPurgeAllFreeLists () { // >> 801F90
	return CBlockAllocator::purgeAll ();
}

static void * hmalloc (size_t size, DWORD hint) {
	return malloc (size);
}
static void * hrealloc (void * ptr, size_t newsize, DWORD hint) {
	return realloc (ptr, newsize);
}
static void * hcalloc (size_t count, size_t size, DWORD hint) {
	return calloc (count, size);
}

bool _rwMemoryOpen (rwMemoryFunctions * mem) {	// >> 801FD0
	if (mem)
		(*engine)->mem = *mem;
	else {
		(*engine)->mem.rwmalloc = hmalloc;
		(*engine)->mem.rwfree = free;
		(*engine)->mem.rwrealloc = hrealloc;
		(*engine)->mem.rwcalloc = hcalloc;
	}
	debug ("_rwMemoryOpen\n");
	return true;
}

void _rwMemoryClose () { // >> 8020F0
	while (__allocatorsList)
		delete __allocatorsList;
	debug ("_rwMemoryClose\n");
}
// ############################################################################
// # bastring
// TODO: никакого смысла в этой функции нет. После того, как не останется мест, в которых она используется - ее нужно просто убрать
/*
bool	_rwStringOpen () {	
	CEngine * e = *engine;
	e->_rwsprintf = (void *)sprintf;
	e->_rwvsprintf = (void *)vsprintf;
	e->_rwstrcpy = (void *)strcpy;
	e->_rwstrncpy = (void *)strncpy;
	e->_rwstrcat = (void *)strcat;
	e->_rwstrncat = (void *)strncat;
	e->_rwstrrchr = (void *)strrchr;
	e->_rwstrchr = (void *)strchr;
	e->_rwstrstr = (void *)strstr;
	e->_rwstrcmp = (void *)strcmp;
	e->_rwstrncmp = (void *)strncmp;
	e->_rwstricmp = (void *)stricmp;
	e->_rwstrlen = (void *)strlen;
	e->_rwstrupr = (void *)strupr;
	e->_rwstrlwr =  (void *)strlwr;
	e->_rwstrtok =  (void *)strtok;
	e->_rwsscanf = (void *)sscanf;
	return true;
}
*/
// ############################################################################
CPluginRegistry		__enginePlugins(0x158);		// TODO: sizeof (CEngine)	(XREF:20)
CPluginRegistry		__atomicPlugins(0x70);		// TODO: sizeof (RpAtomic)	(XREF:25)
CPluginRegistry		__clumpPlugins(0x2C);		// TODO: sizeof (RpClump)	(XREF:20)
CPluginRegistry		__geometryPlugins (0x60);	// TODO: sizeof ? (XREF:18)
CPluginRegistry		__materialPlugins (0x1C);	// TODO: sizeof ? (XREF:20)
CPluginRegistry		__worldPlugins (0x70);		// TODO: sizeof ? (XREF:21)
CPluginRegistry		__lightPlugins (0x40);		// TODO: sizeof ? (XREF:12)
CPluginRegistry		__sectorPlugins (0x88);		// TODO: sizeof ? (XREF:27)
CPluginRegistry		__cameraPlugins (0x184);	// TODO: sizeof ? (XREF:12)
CPluginRegistry		__framePlugins (0xA4);		// TODO: sizeof ? (XREF:19)
CPluginRegistry		__texturePlugins (0x58);	// TODO: sizeof ? (XREF:18)
CPluginRegistry		__texdictPlugins (0x18);	// TODO: sizeof ? (XREF:12)
CPluginRegistry		__rasterPlugins (0x34);		// TODO: sizeof ? (XREF:5)

bool _rwPluginRegistryOpen () {	// TODO: предположительно, не понадобится, если объявить статически engine plugin registry
	return 1;
}
void _rwPluginRegistryClose () {	// TODO: аналогично. И, если переписать RwEngineInit - они вообще не понадобятся
}
// rwDestroyEntry - не требуется, т.к. вызывается только из _rwPluginRegistryClose (да и чистить нечего - все выделяется статически)
int	_rwPluginRegistryAddPlugin (void * registry, DWORD size, DWORD offset, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destructCB, pluginCopyCB copyCB) {
	return ((CPluginRegistry *)registry)->addPlugin (pluginID, size, constructCB, destructCB, copyCB);
}

int _rwPluginRegistryGetPluginOffset (void * registry, DWORD pluginID) {
	return ((CPluginRegistry *)registry)->getOffset (pluginID);
}

void *_rwPluginRegistryInitObject(void * reg, void *object) {
	return ((CPluginRegistry *)reg)->initObject (object) ? reg : NULL;
}

void *_rwPluginRegistryDeInitObject(void * reg, void *object) {
	return ((CPluginRegistry *)reg)->deinitObject (object) ? reg : NULL;
}

void *_rwPluginRegistryCopyObject(void * reg, void *dstObject, const void *srcObject) {
	return ((CPluginRegistry *)reg)->copyObject (dstObject, srcObject) ? reg : NULL;
}

int _rwPluginRegistryAddPluginStream(void *reg, DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {
	return ((CPluginRegistry *)reg)->addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}

int _rwPluginRegistryAddPlgnStrmlwysCB (void * reg, DWORD pluginID, pluginAlwaysCB alwaysCB) {
	return ((CPluginRegistry *)reg)->addPluginAlwaysCB (pluginID, alwaysCB);
}
// ############################################################################
int RpAtomicRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 74BDA0 (7)
	return __atomicPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RpAtomicGetPluginOffset (DWORD pluginID) {	// >> 74BEC0
	return __atomicPlugins.getOffset (pluginID);
}
int RpClumpRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) { // >> 74BDD0 (4)
	return __clumpPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB); 
}
int RpClumpRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 74BE70
	return __clumpPlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RpGeometryRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) { // >> 74CD70 (7)
	return __geometryPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB); 
}
int RpGeometryRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 74CDA0 (6)
	return __geometryPlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RpMaterialRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 74BDA0 (7)
	return __materialPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RpMaterialRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 
	return __materialPlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RpWorldRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 74FCD0 (1)
	return __worldPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RpWorldRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 74FD00 (1)
	return __worldPlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RpLightRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 751D60 (3)
	return __lightPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RpLightStreamGetSize (void * object) {
	return __lightPlugins.getSize (object);
}
int RpWorldSectorRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 761C90 (5)
	return __sectorPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RpWorldSectorRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 761CC0 (4)
	return __sectorPlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RwCameraRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7EE450 (2)
	return __cameraPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RwCameraGetSize (void * object) { // >> 808CE0 (2)
	return __cameraPlugins.getSize (object);
}
int RwFrameRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7F1260 (3)
	return __framePlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RwFrameRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 807580 (2)
	return __framePlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RwEngineRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7F2BB0 (16)
	return __enginePlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RwEngineGetPluginOffset (DWORD pluginID) { // >> 7F2BE0 (9)
	return __enginePlugins.getOffset (pluginID);
}
int RwTextureRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7F3BB0 (1)
	return __texturePlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RwTextureRegisterPluginStream (DWORD pluginID, pluginReadCB readCB, pluginWriteCB writeCB, pluginGetSizeCB getSizeCB) {	// >> 804550 (1)
	return __texturePlugins.addPluginStream (pluginID, readCB, writeCB, getSizeCB);
}
int RwTexDictionaryRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7F3BB0 (1)
	return __texdictPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
int RwRasterRegisterPlugin (int size, DWORD pluginID, pluginConstructCB constructCB, pluginDestructCB destrictCB, pluginCopyCB copyCB) {	// >> 7FB0B0 (1)
	return __rasterPlugins.addPlugin (pluginID, size, constructCB, destrictCB, copyCB);
}
// _ClumpTidyDestroyClump
// _ClumpTidyDestroyAtomic
// __rpClumpOpen
// _RpAtomicCreate
// _RpAtomicDestroy
// _RpAtomicClone
// _RpClumpClone
// _RpClumpDestroy
// _ClumpAtomicStreamRead
// _DestroyClumpAtomic
// _RpAtomicRegisterPluginStream
// _RpAtomicSetStreamAlwaysCallBack
// _RpAtomicSetStreamRightsCallBack
// _RpClumpCreate
// _RpClumpStreamRead
// _RpGeometryCreate
// _RpGeometryDestroy
// _RpGeometryStreamGetSize
// _RpGeometryStreamRead
// _RpGeometryStreamRead__internal
// __rpMaterialOpen
// _RpMaterialCreate
// _RpMaterialDestroy
// _RpMaterialStreamRead
// _RpMaterialStreamGetSize
// _RpWorldDestroy
// _RpWorldCreate
// _RpLightStreamRead
// _RpLightDestroy
// _RpLightCreate
// _LightTidyDestroyLight
// __rpLightOpen
// __rpWorldSectorDeinstanceAll
// __rpWorldSectorDestroyRecurse
// _RpWorldCreate
// __rwCameraOpen
// _RwCameraDestroy
// _RwCameraCreate
// _RwCameraStreamRead
// __rwFrameOpen
// _rwFrameCloneRecurse
// _rwFrameInternalInit
// _rwFrameDestroy
// _rwFrameDestroyRecurse
// _RwFrameDestroyHierarchy
// __rwFrameListStreamGetSize
// __rwFrameListStreamRead
// _RwEngineStop
// _RwEngineStart
// _RwEngineOpen
// _RwEngineInit
// _RwTextureCreate
// _RwTextureDestroy
// __rwTextureOpen
// _TextureDefaultRead
// _TextureDefaultMipmapRead
// _RwTextureStreamGetSize
// _RwTextureStreamRead
// _RwTexDictionaryCreate
// _RwTexDictionaryDestroy
// __rwTextureClose
// __rwTextureOpen
// _RwRasterDestroy
// _RwRasterCreate
// __rwRasterOpen
// ############################################################################
extern void injectFunction (DWORD, DWORD);
void engineInject () {
	// # bamemory
	injectFunction (0x801FD0, (DWORD)_rwMemoryOpen);
	injectFunction (0x8020F0, (DWORD)_rwMemoryClose);
	injectFunction (0x801F90, (DWORD)RwPurgeAllFreeLists);
	injectFunction (0x801E00, (DWORD)RwFreeListPurge);
	injectFunction (0x801E90, (DWORD)RwFreeListForAllUsed);
	injectFunction (0x801C30, (DWORD)_rwFreeListAllocReal);
	injectFunction (0x801D50, (DWORD)_rwFreeListFreeReal);
	injectFunction (0x8019B0, (DWORD)FreeListCreate);
	injectFunction (0x801B80, (DWORD)RwFreeListDestroy);
	// # bastream
	injectFunction (0x7EC780, (DWORD)_rwStreamModuleOpen);
	injectFunction (0x7EC7E0, (DWORD)_rwStreamModuleClose);
	injectFunction (0x7ECEF0, (DWORD)RwStreamOpen);
	injectFunction (0x7ECB30, (DWORD)RwStreamWrite);
	injectFunction (0x7EC9D0, (DWORD)RwStreamRead);
	injectFunction (0x7ECD00, (DWORD)RwStreamSkip);
	injectFunction (0x7ECE20, (DWORD)RwStreamClose);
	injectFunction (0x7EC810, (DWORD)_rwStreamInitialize);

	injectFunction (0x7ED0F0, (DWORD)_rwStreamReadChunkHeader);
	injectFunction (0x7ED4F0, (DWORD)_rwStreamReadData);
	injectFunction (0x7ED540, (DWORD)_rwStreamReadData);
	injectFunction (0x7ED590, (DWORD)RwStreamReadChunkHeaderInfo);
	injectFunction (0x7ED2D0, (DWORD)RwStreamFindChunk);
	// # rwstring
	injectFunction (0x80A470, (DWORD)_rwStringStreamGetSize);
	injectFunction (0x80A510, (DWORD)_rwStringStreamFindAndRead);
	// # p2core
	injectFunction (0x807C40, (DWORD)_rwRenderPipelineOpen);
	injectFunction (0x807C60, (DWORD)_rwRenderPipelineClose);
	injectFunction (0x805710, (DWORD)RxPipelineExecute);
	injectFunction (0x8057B0, (DWORD)RxPipelineCreate);
	injectFunction (0x805820, (DWORD)RxPipelineDestroy);

	// injectFunction (0x, (DWORD));

	// injectFunction (0x7F18B0, (DWORD)RwMatrixMultiply);
}