// Open SanAndreas
// (c) 2006-2008 Stanislav "listener" Golovin
// 
// all texture related objects and functions

/*	TODO: этот модуль нуждается в значительной переделке.
 *	* после того, как будет написан свой asset manager (в который войдет streaming и вообще, загрузка всех объектов),
 *	та часть, которая загружает текстуры, уйдет туда.
 *	* CTexDictionary и CTxdEntry объединяются. На них, соответственно, делается один аллокатор. Методы CTxdPool 
 *	распределяются между CTexDictionary и CTextureManager. CTxdPool убирается совсем.
 */

// forward declarations
struct CTexture;
struct CTexDictionary;
class CTxdPool;

// callbacks
typedef CTexture *(*textureCB)(CTexture *texture, void *data);
typedef CTexture *(*textureCBRead)(const char *name, const char *maskName);
typedef CTexture *(*textureCBFind)(const char *name);
typedef CTexture *(*textureCB)(CTexture *texture, void *pData);
// typedef CTexDictionary *(*CTexDictionaryCallBack)(CTexDictionary *dict, void *data);
// typedef RwRaster *(*textureCBMipmapGeneration)(RwRaster * raster, RwImage * image);
typedef bool (*textureCBMipmapName)(char *name, char *maskName, BYTE mipLevel, int format);

//=============================================================================
//	CTextureManager
// основной класс для работы с текстурами
// предназначен для замены TextureModule из Renderware
class CTextureManager {
public:
	friend class CTxdPool;	// TODO: временно. (Скорее всего, CTxdPool войдет в состав этого класса) 

	CTextureManager ();
	~CTextureManager ();

	// callback management
	// TODO: прописать коллбэки как методы и избавиться от этих методов
	void setFindCB (textureCBFind cb) {	findCB = cb; }	// >> 7F34D0 (3) - используется два коллбэка
	const textureCBFind getFindCB () const { return findCB; }	// >> 7F34F0 (1)		
	// void setReadCB (textureCBRead cb) { readCB = cb; }	// >> 7F3500 (1) - используется при инициализации. TODO: Можно спокойно убирать	

	void setMipmapping (bool enable) { enableMipmapping = enable; }	// 7F3530 (8)
	const bool getMipmapping () const { return enableMipmapping; } // >> 7F3550 (1) - используется только при чтении текстур. TODO: Убрать
	void setAutoMipmapping (bool enable) { autoMipmapping = enable; } // >> 7F3560 (7)
	const bool getAutoMipmapping () const { return autoMipmapping; } // >> 7F3580 (1) - TODO: убрать (внутренняя функция)

	// set/get default texture dictionary
	void setCurrentTxd (CTexDictionary * txd) { currentTxd = txd; }	// >> 7F3A70 (6) 
	CTexDictionary * getCurrentTxd () const { return currentTxd; }	// >> 7F3A90 (6)

	CTexDictionary * readTxdChunk (CRwStream * stream);	// >> 730FC0 (2)

	CTexture * readTexture (const char *name, const char * maskName);	// >> 7F3AC0 (61)

	short getDefaultTxd (int index);	// >> 7316D0 (1)


	// TODO: после переписывания соответствующих частей, CTexDictionary и CTxdEntry объединяются
	// TODO: либо txdAllocator, либо txdPool, таким образом, уходят, как явление
	CBlockAllocator * texAllocator;	// WARNING! аллокаторы выделяются в конструкторе, но, на текущий момент, не освобождаются в деструкторе
	CBlockAllocator * txdAllocator;	//	_rwMemoryClose освободит их вместе со всеми, а, он вызывается раньше деструкторов статичесих объектов

protected:
	textureCBFind		findCB;	
	textureCBRead		readCB;
	textureCBMipmapName	mipmapNameCB;
	bool				enableMipmapping;
	bool				autoMipmapping;
	CTexDictionary *	currentTxd;	
};

extern CTextureManager	texMan;	// основная (и единственная) точка для всей работы с текстурами
// extern CTxdPool			txdPool;	// TODO: добавить, когда все 56 обращений к txdPool будут переделаны. 
extern CTxdPool **	txdPool;

//=============================================================================
// RwTexDictionary => CTexDictionary
typedef bool TextureCallback (CTexture * texture, void * data);

struct CTexDictionary : public RwObject {	// 28 bytes
	RwLLLink	texturesInDict;		// +08 List of textures in dictionary 
    RwLLLink    lInInstance;		// +16 Link list of all dicts in system 
	// plugin data
	CTexDictionary *	parent;		// +24 link to parent dictionary

	CTexDictionary ();
	~CTexDictionary ();

	void forAllTextures (TextureCallback cb, void * data);	// >> 7F3730 (14)
	void addTexture (CTexture *texture); // >> 7F3980 (16)	
	void addAllTexturesFrom (CTexDictionary * txd);
	CTexture * findNamedTexture (const char * name); // >> 7F39F0 (16)

	void * operator new (size_t);
	void operator delete (void * ptr);
};

//=============================================================================
//	CTxdEntry - внутриигровая обертка вокруг CTexDictionary
//	TODO: объединить с CTexDictionary
class CTxdEntry {
public:
	CTxdEntry (char * name);
	~CTxdEntry ();

	void * operator new (size_t);
	void operator delete (void * ptr);

	CTexDictionary *	txd;
	short				usageCount;
	short				parentIndex;
	DWORD				hash;
};
//=============================================================================
//	CTxdPool
class CTxdPool : public CPoolBase <CTxdEntry> {
public:
	CTxdPool ();

	// entry creation/destruction
	int					createEntry (char * name);	// >> 731C80 (21)
	void				destroyEntry (int index);	// >> 731CD0 (11)

	// reference counting
	void				addRef (int index);	// >> 731A00 (23)
	void				releaseTxd (int index);	// >> 731A30 (8)
	void				releaseWithoutUnload (int index);	// >> 731A70 (4)
	int					getUsageCount (int index);	// >> 731AA0 (4)

	// entry manipulation
	CTexDictionary *	getTxd (int index);	// >> 408340 (1)
	int					getParentIndex (int index);	// >> 408370 (3)
	void				createTxd (int index);	// >> 731990 (2)
	void				setCurrent (int index); // >> 7319C0 (32)
	void				garbageCollect (); // >> 732060 (1)
	void				initParent (int index);	// >> 731D50 (2)

	// создать CTxdEntry с указанным именем
	int					addEntry (char * name);	// >> 731C80 (21)
	// найти индекс элемента txdPool по имени. Если элемент не найден, возвращается -1
	int					indexByName (char * name);	// >> 731850 (47)
	// найти индекс элемента txdPool по имени. Если элемент не найден, создается новый элемент
	int					indexByNameAlways (char * name);
	

	// stream operations
	bool				readEntry (int index, CRwStream * stream); // >> 731930 (1)
	bool				readEntryWithParent (int index, CRwStream * stream);	// 731DD0 (2)	
	bool				load (int index, char * filename); // >> 7320B0 (14)	
};
//=============================================================================
//	CTexture	- TODO: не забыть переименовать собственную структуру GTA в CSprite
struct RwRaster;
struct CTexture {	// 88 bytes
public:
	RwRaster *			raster;			// +00 pointer to RwRaster with data 
    CTexDictionary *	dict;			// +04 Dictionary this texture is in 
    RwLLLink			lInDictionary;	// +08 List of textures in this dictionary 
    char				name[32];		// +12 Name of the texture 
    char				mask[32];		// +44 Name of the textures mask 
    // 31 [xxxxxxxx xxxxxxxx vvvvuuuu ffffffff] 0 
    DWORD				filterAddressing;//+76 Filtering & addressing mode flags 
    int					refCount;		// +80 Reference count, surprisingly enough 

	// plugin data
	DWORD				anisotropic;	// +84 1 - disable anisotropic filtering

	CTexture (RwRaster * raster);
	void destroy ();	// NOTE: этот метод нужно вызывать вместо delete, чтобы обрабатывать refCount

	void setRaster (RwRaster * raster);	// >> 7F35D0 (6)

	void removeFromTxd ();	// >> 7F39C0 (2)

	void setName (char * _name);	// >> 7F38A0 (19)
	void setMaskName (char * _name);	// >> 7F3910 (2)	

	void * operator new (size_t size);
	void operator delete (void * ptr);

private:
	~CTexture ();
};
