// ### OpenGTA3 ###
// RenderWare structures

// ВНИМАНИЕ! Описанные здесь структуры - это не структуры RenderWare!
// CAtomic, CClump, CFrame и т.д. - это RwAtomic, RpClump и т.д. со всеми зарегистрированными в SA плагинами, 
// с учетом порядка регистрации плагинов. Без этого, доступ к данным плагина превращается в кошмар
//
// Соответственно, все методы из классов плагинов перемещаются в эти классы объектов

#pragma pack(push, 1)

// forward declarations
struct CAtomic;
struct CClump;
struct CFrame;
struct CLight;
struct CRwCamera; 
struct CTexture;
struct CTexDictionary;
struct CGeometry;

struct RwRaster;
struct RwImage;
struct RwResEntry;
struct RpGeometry;
struct RxPipeline;
struct RwCamera;
struct RpWorld;
struct RpWorldSector;
struct RpTriangle;
struct RpMaterial;
struct RpWorld;
struct RwTexCoords;
struct RpMeshHeader;
struct RpMorphTarget;
struct RtAnimInterpolator;
struct RtAnimAnimation;
struct RtAnimInterpolatorInfo;
struct RpSkin;

class CModelBase;

struct Vector2D {
	float	x;
	float	y;
};

struct RwObject {	// 8 bytes
	BYTE	type;
	BYTE	subType;
	BYTE	flags;              
	BYTE	privateFlags;       
    CFrame *parent;                                   
};

struct RwLLLink {	// 8 bytes
    RwLLLink *next;
    RwLLLink *prev;

	inline void insertAfter (RwLLLink * link) {
		prev = link;
		next = link->next;
		link->next->prev = this;
		link->next = this;
	}

	inline void remove () {
		next->prev = prev;
		prev->next = next;
	}
};

struct RpInterpolator {	// 20 bytes
	DWORD	flags; 
	WORD	startMorphTarget; 
	WORD	endMorphTarget; 
	float	time; 
	float	recipTime; 
	float	position; 
};

struct RpMorphTarget {
    CGeometry *	parentGeom; 
    RwSphere	boundingSphere;
	D3DVECTOR *	verts;
	D3DVECTOR *	normals;
};

struct RpHAnimNodeInfo {
    int			nodeID;     // +0 User defined ID for this node  
    int			nodeIndex;  // +4 Array index of node  
    DWORD		flags;      // +8 Matrix push/pop flags  
    CFrame *	pFrame;     // +12 Pointer to an attached frame
};

struct RpHAnimHierarchy {
    int					flags;				// +0 Flags for the hierarchy  
    int					numNodes;			// +4 Number of nodes in the hierarchy  

    RwMatrix *			pMatrixArray;		// +8 Pointer to node matrices
    void *				pMatrixArrayUnaligned;	// +12 Pointer to memory used for node matrices from which the aligned pMatrixArray is allocated 
    RpHAnimNodeInfo *	pNodeInfo;			// +16 Array of node information (push/pop flags etc) 
    CFrame *			parentFrame;		// +20 Pointer to the Root RwFrame of the hierarchy this RpHAnimHierarchy represents */
    RpHAnimHierarchy *	parentHierarchy;    // +24            
    int					rootParentOffset;   // +28

    RtAnimInterpolator   *currentAnim;      // +32
};

struct RtAnimAnimation	{
    RtAnimInterpolatorInfo *	interpInfo;		// Pointer to interpolation scheme information 
    int		numFrames;	// Number of keyframes in the animation  
    int		flags;		// Specifies details about animation, relative translation modes etc. 
    float	duration;	// Duration of animation in seconds 
    void *	pFrames;	// Pointer to the animation keyframes  
    void *	customData;	// Pointer to custom data for this animation 
};

struct RwMatrixWeights {
    float	w0;		// The first matrix weight.  
    float	w1;		// The second matrix weight. 
    float	w2;		// The third matrix weight.  
    float	w3;		// The fourth matrix weight. 
};


union RGBA {
	struct {
		BYTE r;
		BYTE g;
		BYTE b;
		BYTE a;
	};
	DWORD	color;

	__inline RGBA () {}
	__inline RGBA (BYTE _r, BYTE _g, BYTE _b, BYTE _a) { r = _r; g = _g; b = _b; a = _a; }
	__inline RGBA (DWORD _color) { color = _color; }
};

struct RGBAReal {
	float	r;
	float	g;
	float	b;
	float	a;
};

struct RwSurfaceProperties {
	float	ambient;	// ambient reflection coefficient 
    float	specular;	// specular reflection coefficient 
    float	diffuse;	// reflection coefficient 
};

struct RpMaterial {
    CTexture *		texture;	// texture 
    RGBA            color;		// color 
    RxPipeline *	pipeline;	// pipeline */
    RwSurfaceProperties surfaceProps;	// surfaceProps 
    short			refCount;          
    WORD			pad;
};


struct RpMaterialList {	// 12 bytes
    RpMaterial **	materials;
    int				numMaterials;
    int				space;
};
struct RpTriangle {
    WORD	vertIndex[3]; 
    WORD	matIndex;   
};

struct RpTie {	// 24 bytes; linked list of atomics inside world sector
	RwLLLink	lAtomicInWorldSector;	// +0
	CAtomic *	atomic;					// +8
	RwLLLink	lWorldSectorInAtomic;	// +12
	RpWorldSector	* worldSector;		// +20
};


struct RwObjectHasFrame;
typedef RwObjectHasFrame * (*RwObjectHasFrameSyncFunction)(RwObjectHasFrame *object);

struct RwObjectHasFrame : public RwObject {	// 20 bytes
	RwLLLink	lFrame;
    RwObjectHasFrameSyncFunction sync;	

	void setFrame (CFrame * frame);	// << _rwObjectHasFrameSetFrame >> 804EF0 (18)
	void releaseFrame (); // << _rwObjectHasFrameReleaseFrame >> 804F40 (12)
};


//=============================================================================
//	
//=============================================================================
// RpAtomic => CAtomic
// 
typedef CAtomic * (*CAtomicCallBackRender)(CAtomic * atomic);

struct CAtomic	: RwObjectHasFrame {	// 140 bytes
    RwResEntry         *repEntry;			// +20 Information for an instance
    CGeometry *			geometry;			// +24 Triangles making the object
    RwSphere            boundingSphere;		// +28 Interpolated bounding sphere (in object space and world space)
    RwSphere            worldBoundingSphere;// +44
    CClump			   *clump;				// +60 Connections to other atomics
    RwLLLink            inClumpLink;		// +64
    CAtomicCallBackRender renderCallBack;	// +72 callbacks
    RpInterpolator      interpolator;		// +76 Interpolation animation pointer
    WORD				renderFrame;		// +96 Counter for checks of "render has occurred already"
    WORD				pad;				// +98
	RwLLLink			llWorldSectorsInAtomic;	// +100 Connections to sectors
    RxPipeline         *pipeline;			// +108 The Atomic object pipeline for this Atomic
	// plugin space		
	RpWorld *			world;				// +112	world atomic (4+4)
	RwObjectHasFrameSyncFunction	oldSync;// +116 previous sync callback, overriden by world atomic plugin
	// NOTE: atomic rights - no data	
	RpHAnimHierarchy *	skinData;			// +120 skin	
	short				visibilityData0;	// +124 visibility
	WORD				visibilityData2;	// +126
	DWORD				matFXdata;			// +128
	void *				reflectionData;		// +132
	DWORD				pl2F3data;			// +136

	// methods 
	CAtomic ();
	CAtomic (CAtomic *);	// << RpAtomicClone >> 749E60 (18)	
	~CAtomic ();

	// methods
	void atomicSetFrame (CFrame * frame) {	// >> 74BF20 (34)
		setFrame (frame);
		privateFlags |= 1;
	}
	bool haveNightColors ();	// >> 5D7F40 (5)
	void setupLighting ();	// >> 5D7F40 (1)
	void setHAnimHierarchy (RpHAnimHierarchy * hh);	// >> 4C4EF0 (3)

	// void setGeometry (CGeometry * _geometry, bool sameBoundingSphere); 

	// operators
	void * operator new (size_t);
	void operator delete (void *);	
};

// miscellaneous callbacks
CAtomic * destroyAtomicAnimationCB (CAtomic * a, void * data);	// >> 534089 (7)

//=============================================================================
//	RpGeometry => CGeometry

// low word of constructor flags parameter (high word contains number of texture coords)
#define rpGEOMETRYTRISTRIP	0x00000001		// This geometry's meshes can be rendered as strips.
#define rpGEOMETRYPOSITIONS 0x00000002		// This geometry has positions 
#define rpGEOMETRYTEXTURED	0x00000004		// This geometry has only one set of texture coordinates. Texture coordinates are specified on a per vertex basis 
#define rpGEOMETRYPRELIT	0x00000008		// This geometry has pre-light colors 
#define rpGEOMETRYNORMALS	0x00000010		// This geometry has vertex normals 
#define rpGEOMETRYLIGHT		0x00000020		// This geometry will be lit 
#define rpGEOMETRYMODULATEMATERIALCOLOR	0x00000040	// Modulate material color with vertex colors (pre-lit + lit) 
#define rpGEOMETRYTEXTURED2	0x00000080		// This geometry has at least 2 sets of texture coordinates. 

struct CGeometry : public RwObject {	// 124 bytes
    DWORD				flags;					// +8 Geometry flags 
    WORD				lockedSinceLastInst;	// +12 What has been locked since we last instanced - for re-instancing 
    short				refCount;				// +14 Reference count (for keeping track of atomics referencing geometry) 
    int					numTriangles;			// +16 Quantity of various things (polys, verts and morph targets) 
    int					numVertices;			// +20
    int					numMorphTargets;		// +24
    int					numTexCoordSets;		// +28
    RpMaterialList      matList;				// +32
    RpTriangle  *		triangles;				// +44 The triangles 
    RGBA *				preLitLum;				// +48 TODO: RGBA *
    RwTexCoords *		texCoords[8];			// +52 Texture coordinates 
    RpMeshHeader *		mesh;					// +84 The mesh - groups polys of the same material 
    RwResEntry  *		repEntry;				// +88 Information for an instance 
    RpMorphTarget *		morphTarget;			// +92 The Morph Target 
	
	// plugin data
	// 0x050E - Geometry Mesh - no data
	// 0x0510 - Geometry Native - no data
	DWORD				plD3DUsageFlag;			// +96	050F - D3D9UsageFlag 
	RpSkin *			skin;					// +100 0116 - skin
	void *				nightColors0;			// +104 .2F9 - night vertex colors: night colors
	void *				nightColors4;			// +108 .2F9 - night vertex colors: day colors
	float				nightColors8;			// +112 .2F9 - night vertex colors: blend ?
	void *				meshExtension;			// +116 .2FD - Mesh Extension
	DWORD *				pl2dfx;					// +120 .2F8 - 2dfx


	// methods
	void addRef () {	refCount++; }	// >> 74CCB0 (9)
	void setAlphaForAllMaterials (BYTE alpha);	// >> 6D2960 (11)
/*
	CGeometry (int numVerts, int numTriangles, DWORD flags);
	~CGeometry ();

	// operators
	void * operator new (size_t);
	void operator delete (void * ptr);
*/
};
//=============================================================================
//	RpClump => CClump
// 
typedef CClump *	(*CClumpCallBack) (CClump * clump, void *data);
typedef bool		(*CClumpVisibilityCallback) (void * data);	// TODO: описать параметр
typedef CAtomic *	(*CAtomicCallback) (CAtomic * atomic, void * data);	

struct CClump : public RwObject {// 64 bytes
	RwLLLink		atomicList;		// +08 Information about all the Atomics 
	RwLLLink		lightList;		// +16 List of lights
	RwLLLink		cameraList;		// +24 List of cameras        
    RwLLLink		inWorldLink;	// +32 The clump in a world 
    CClumpCallBack  callback;		// +40 Clump frustum callback 	
	// plugin space
	RpWorld *		world;			// +44 WorldClump plugin data (4+4)
	void *			pl0509_04;		// +48 WorldClump plugin data
	CClumpVisibilityCallback	visibilityCB;	// +52 Visibility plugin data (.201)
	int				visibilityDistance;			// +56 Visibility plugin data
	void *			plGtaHAnim;		// +60 Overriden HAnim plugin (.2FB)
	// collision plugin (.2FA) - no data	

	CClump ();
	CClump (CClump *);	// >> 749F70 (1)
	// CClump (CRwStream * stream);	// >> 74B420 (9)
	~CClump ();	// >> 74A310 (22)

	// methods
	void addAtomic (CAtomic * atomic);	// >> 74A490 (20)
	void removeAtomic (CAtomic * atomic);	// >> 74A4C0 (7)
	CAtomic * getFirstAtomic ();	// >> 734820 (30)

	void forAllAtomics (CAtomicCallback, void *);	// 749B70 (82)

	// in-game methods
	CAtomic * findFirstAtomicWith2dfx ();
	void setupLighting ();	// call setupLighting() for all atomics
	RpHAnimHierarchy * getHAnimHierarchy ();	// >> 
	void atomicsSetHAnimHierarchy (RpHAnimHierarchy * hh);	// >> 4C4EF0 (3)
	void atomicsSetRenderrCB (CAtomicCallBackRender	cb);	// >> 4C5280

	// operators
	void * operator new (size_t);
	void operator delete (void *);	
};
//=============================================================================
//	RpLight => CLight


#define rpLIGHTPOSITIONINGSTART 0x80	// Beyond this the lights must be positioned 

enum RpLightType	{
    rpNALIGHTTYPE = 0,
    rpLIGHTDIRECTIONAL,		// Directional Light 
    rpLIGHTAMBIENT,			// Ambient Light 
    rpLIGHTPOINT = rpLIGHTPOSITIONINGSTART, // Point Light 
	rpLIGHTSPOT,			// Spot Light 
    rpLIGHTSPOTSOFT,		// Soft Spot Light 
    rpLIGHTTYPEFORCEENUMSIZEINT = 0x7FFFFFFF
};


struct CLight : public RwObjectHasFrame {	// 100 bytes
        float       radius;				// +20 radius
		RGBAReal	color;				// +24 light color
        float		minusCosAngle;		// +40
		RwLLLink	WorldSectorsInLight;// +44
        RwLLLink    inWorld;			// +52
        WORD		lightFrame;			// +60
        WORD		pad;				// +62

		// plugin data
		RpWorld *	world;				// +64 - World Light plugin (0x0509)
		RwObjectHasFrameSyncFunction savedSync;	// +68
		CClump *	clump;				// +72 - Clump Light (0x0010)
		RwLLLink	inClumpLink;		// +76
		int			d3dLight0;			// +84
		float		d3dLight4;			// +88
		void *		d3dLight8;			// +92
		float		d3dLightC;			// +96

		// methods
		CLight (RpLightType lightType);	// >> 752110 (5)
		~CLight ();

		void setRadius (float aRadius);	// >> 751A70 (2)
};

//=============================================================================
//	RwCamera => CRwCamera

enum RwCameraProjection {
    rwNACAMERAPROJECTION = 0,	// Invalid projection 
    rwPERSPECTIVE = 1,          // Perspective projection 
    rwPARALLEL = 2,             // Parallel projection 
    rwCAMERAPROJECTIONFORCEENUMSIZEINT = 0x7FFFFFFF
};

struct RwPlane {	// 16 bytes
	D3DVECTOR	normal;		// Normal to the plane
    float		distance;	// Distance to plane from origin in normal direction
};

struct RwFrustumPlane {	// 20 bytes
        RwPlane plane;
        BYTE	closestX;
        BYTE	closestY;
        BYTE	closestZ;
        BYTE	pad;
};

typedef CRwCamera   *(*CameraBeginUpdateCB) (CRwCamera * camera);
typedef CRwCamera   *(*CameraEndUpdateCB) (CRwCamera * camera);

struct CRwCamera : public RwObjectHasFrame {	// 428 bytes
    
	void setNearClipPlane (float plane);	// >> 7EE1D0 (42)
	void updateZShuftScale ();	// >> 7EE200 (5)	TODO: private

    RwCameraProjection		projectionType;	// +20 Parallel or perspective projection 
        CameraBeginUpdateCB		beginUpdate;	// +24
        CameraEndUpdateCB		endUpdate;		// +28        
        RwMatrix				viewMatrix;		// +32 The view matrix         
        RwRaster *				frameBuffer;	// +96 The cameras image buffer         
        RwRaster *				zBuffer;		// +100 The Z buffer 

        //	Cameras mathematical characteristics 
        Vector2D				viewWindow;		// +104
        Vector2D				recipViewWindow;// +112
        Vector2D				viewOffset;		// +120
        float					nearPlane;		// +128
        float					farPlane;		// +132
        float					fogPlane;		// +136
		// Transformation to turn camera z or 1/z into a Z buffer z
		float					zScale;			// +140	
		float					zShift;			// +144
                
        RwFrustumPlane			frustumPlanes[6];	// +148	The clip-planes making up the viewing frustum 
        RwBBox					frustumBoundBox;	// +268       
		D3DVECTOR				frustumCorners[8];	// +292 Points on the tips of the view frustum 
	
		// plugin data
		BYTE					worldCamera[0x1C];	// +388	pl0509 (world camera)
		CClump *				clump;				// +416 pl0010 (clump)
		RwLLLink				inClumpLink;		// +420
};

//=============================================================================
//	RwFrame => CFrame
struct CFrame : public RwObject {	// 200 bytes
    RwLLLink    inDirtyListLink;// +8
    RwMatrix    modelling;		// +16
    RwMatrix    ltm;			// +80
	RwLLLink	objectList;		// +144 List of objects connected to a frame     
	CFrame *	child;			// +152
    CFrame *	next;			// +156
    CFrame *	root;			// +160 Root of the tree 
	// plugin data
	int			hanimData0;		// +164 HAnim plugin data
	RpHAnimHierarchy * hanimHierarchy;	// +168	
	char		nodeName[24];	// +172
	DWORD		hierarchyId;	// +196

	// constructor/destructor
	CFrame ();
	~CFrame ();	// >> 7F05A0 (30)
	void destroyHierarchy ();	// >> 7F08A0 (8)/7F0830 (3)	удаляет объект со всеми потомками

	// methods
	void updateObject ();	// << RwFrameUpdateObject >> 7F0910 (65)
	void addChild (CFrame * cf);	// << RwFrameAddChild >> 7F0B00 (9) 
	void removeFromParent (); // << RwFrameRemoveChild >> 7F0CD0 (1)
	void setHierarchyRoot (CFrame * _root);	// >> 7F0210 (13)
	RwMatrix * getLTM ();	// << RwFrameGetLTM >> 7F0990 (90)	-- sync hierarchy LTMs and returns the LTM of this frame

	// in-game methods
	RpHAnimHierarchy * getHAnimHierarchy ();	// >> 734A70 (3)/734AB0(3)
	CFrame * findByNodeName (char * nodeName);	// 
	RwObjectHasFrame * getFirstObject () {	// >> 7348C0 (31)
		return objectList.next != &objectList ? (RwObjectHasFrame *)( ((BYTE *)objectList.next)-offsetof (RwObjectHasFrame, lFrame)) : NULL;
	}
	void flattenHierarchy (CFrame * newRoot);	// >> 4C8E30 (3)
	CFrame * findFrameFromNameWithoutId (char * name);
	CFrame * findFrameFromId (DWORD id);	// >> 4C5350 (4) - find frame with specified hierarchy ID

	void setAtomicVisibilityFlags (WORD flags);	// 

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

struct RwFrameList {
	CFrame **	frames;
	int			numFrames;
};
//=============================================================================
// RpWorld
struct RpSector {	// base type for all 'Sector' structs (RpWorldSector/RpPlaneSector/...)
	int type;
};

struct RpVertexNormal {
    signed char	x;
    signed char	y;
    signed char	z;
    signed char	pad; 
};

#define rwMAXTEXTURECOORDS 8
struct RwTexCoords {
    float	u;   
    float	v;   
};

struct RpPlaneSector : public RpSector {
    float       value;			// +4 
    RpSector *	leftSubTree;	// +8 Sector 'left' (less) of the plane 
    RpSector *	rightSubTree;	// +12 Sector 'right' (more) of the plane 
    float		leftValue;
    float		rightValue;
};

struct RpWorldSector : public RpSector{
    RpTriangle *	triangles;						// +4 Triangles 
    D3DVECTOR *		vertices;						// +8 Vertex positions 
    RpVertexNormal *normals;						// +12 Vertex normals 
    RwTexCoords *	texCoords[rwMAXTEXTURECOORDS];	// +16 Texture coordinates 
    RGBA  *		preLitLum;						// +48 Pre lit luminances     
    RwResEntry *	repEntry;						// +52 Pointer to memory allocated for vertex and poly pointers 
	RwLLLink		collAtomicsInWorldSector;		// +56 Coll priority 
	RwLLLink		lightsInWorldSector;			// +64 Lights in an atomic sector 
    RwBBox          boundingBox;					// +72 Outer bounding box of sector based on BSP planes 
    RwBBox          tightBoundingBox;				// +96 Bounding box tightly enclosing geometry 
    RpMeshHeader *	mesh;							// +120 The mesh which groups same material triangles together 
    RxPipeline *	pipeline;						// +124 The WorldSector object pipeline for this WorldSector 
    WORD			matListWindowBase;				// +128 Material list window base
    WORD			numVertices;					// Num vertices 
    WORD			numTriangles;					// Num triangles 
    WORD			pad;
};

typedef RpWorldSector *(*RpWorldSectorCallBackRender) (RpWorldSector * worldSector);

enum RpWorldRenderOrder {
    rpWORLDRENDERNARENDERORDER = 0,
    rpWORLDRENDERFRONT2BACK,		// Renders nearest sectors first 
    rpWORLDRENDERBACK2FRONT,		// Renders furthest sectors first 
    rpWORLDRENDERORDERFORCEENUMSIZEINT = 0x7FFFFFFF
};

struct RpWorld : public RwObject {
    DWORD				flags;				// +8
    RpWorldRenderOrder  renderOrder;		// +12
    RpMaterialList      matList;			// +16 Materials 
    RpSector *			rootSector;			// +28 The world stored as a BSP tree 
    int					numTexCoordSets;	// +32 The number of texture coordinate sets in each sector 
    int					numClumpsInWorld;	// +36
	RwLLLink *			currentClumpLink;	// +40
	RwLLLink			clumpList;			// +44 All the clumps in the world 
	RwLLLink			lightList;			// +52 All of the lights in the world 
	RwLLLink			directionalLightList;	// +60 Directional lights in the world 
    D3DVECTOR			worldOrigin;		// +68 The worlds origin offset 
    RwBBox              boundingBox;		// +80 Bounding box around the whole world 
    RpWorldSectorCallBackRender renderCallBack;	// +104 The callbacks functions 
    RxPipeline *		pipeline;			// +108
};

//=============================================================================
//	object memory management
class CBlockAllocator;
typedef void (*cbaCallback)(void * mem, void * param);

extern CBlockAllocator * __allocatorsList;

// modules allocators (TODO: привести это к какому-то нормальному виду)
extern CBlockAllocator * __atomicAllocator;		// CAtomic
extern CBlockAllocator * __clumpAllocator;		// CClump
extern CBlockAllocator * __frameAllocator;		// CFrame
extern CBlockAllocator * __tieAllocator;		// RwTie
extern CBlockAllocator * __streamAllocator;		// CRwStream
extern CBlockAllocator * __txdAllocator;		// CTexDictionary
extern CBlockAllocator * __textureAllocator;	// CTexture
extern CBlockAllocator * __hanimHierAllocator;	// RpHAnimHierarchy

// TODO: move to internal part
class CBlockAllocator {
public:
	CBlockAllocator (DWORD entrySize, DWORD entriesPerBlock, DWORD preallocateBlocks = 1, DWORD alignment = 4);
	~CBlockAllocator ();

	BYTE * allocateEntry ();
	void freeEntry (BYTE * ptr);
	void forAllUsed (cbaCallback cb, void * param);
	
	int purge ();	// free all empty blocks
	static int purgeAll ();	// free all empty blocks for all allocators

protected:
	struct BlockHead {
		BlockHead * next;		// pointer to the next block (NULL for last block)
		DWORD	allocated;		// number of allocated entries in block
		DWORD	usageMap[1];	// bitmap of the used entries	
	};

	bool	allocateBlock ();	// выделить новый блок и вставить его в начало списка
	void	freeBlock (BlockHead * prevBlock);	// освободить блок, следующий за указанным. Если параметром передан NULL - освободить первый блок

	DWORD entrySize;
	DWORD entriesPerBlock;
	DWORD alignment;
	DWORD blockHeadSize;		// real size of block head
	DWORD flags;				// 2 - release blocks as possible
	BlockHead *		blocks;
	CBlockAllocator * link;		// pointer to the next allocator in chain
};
//=============================================================================
// supplemental data types and values for CEngine
enum RwRenderState {
    rwRENDERSTATENARENDERSTATE = 0,
    rwRENDERSTATETEXTURERASTER = 1,		// Raster used for texturing (normally used in immediate mode). The value is a pointer to an RwRaster.
    rwRENDERSTATETEXTUREADDRESS = 2,	// RwTextureAddressMode: wrap,clamp, mirror or border.
    rwRENDERSTATETEXTUREADDRESSU = 3,	// RwTextureAddressMode in u only.
    rwRENDERSTATETEXTUREADDRESSV = 4,	// RwTextureAddressMode in v only.
    rwRENDERSTATETEXTUREPERSPECTIVE = 5,// Perspective correction on/off (always enabled on many platforms).
    rwRENDERSTATEZTESTENABLE = 6,		// Z-buffer test on/off.
    rwRENDERSTATESHADEMODE = 7,			// RwShadeMode: flat or gouraud shading.
    rwRENDERSTATEZWRITEENABLE = 8,		// Z-buffer write on/off.
    rwRENDERSTATETEXTUREFILTER = 9,		// RwTextureFilterMode: point sample, bilinear, trilinear, etc.
    rwRENDERSTATESRCBLEND = 10,			// RwBlendFunction used to modulate the source pixel color when blending to the frame buffer.
    rwRENDERSTATEDESTBLEND = 11,		// RwBlendFunction used to modulate the destination pixel color in the frame buffer when blending. 
    rwRENDERSTATEVERTEXALPHAENABLE = 12,// Alpha blending on/off (always enabled on some platforms). 
    rwRENDERSTATEBORDERCOLOR = 13,		// Border color for RwTextureAddressMode rwTEXTUREADDRESSBORDER. The value should be a packed DWORD
    rwRENDERSTATEFOGENABLE = 14,		// Fogging on/off (all polygons will be fogged).  
    rwRENDERSTATEFOGCOLOR = 15,			// Color used for fogging. The value should be a packed DWORD
    rwRENDERSTATEFOGTYPE = 16,			// RwFogType, the type of fogging to use. 
    rwRENDERSTATEFOGDENSITY = 17,		// Fog density for RwFogType of rwFOGTYPEEXPONENTIAL or rwFOGTYPEEXPONENTIAL2. (float *)
    rwRENDERSTATECULLMODE = 20,			// RwCullMode, for selecting front/back face culling, or no culling.
    rwRENDERSTATESTENCILENABLE = 21,	// Stenciling on/off.
    rwRENDERSTATESTENCILFAIL = 22,		// RwStencilOperation used when the stencil test passes.
    rwRENDERSTATESTENCILZFAIL = 23,		// RwStencilOperation used when the stencil test passes and the depth test (z-test) fails. 
    rwRENDERSTATESTENCILPASS = 24,		// RwStencilOperation used when both the stencil and the depth (z) tests pass. 
    rwRENDERSTATESTENCILFUNCTION = 25,	// RwStencilFunction for the stencil test. 
    rwRENDERSTATESTENCILFUNCTIONREF = 26,//Integer reference value for the stencil test. 
    rwRENDERSTATESTENCILFUNCTIONMASK = 27,//Mask applied to the reference value and each stencil buffer entry to determine the significant bits for the stencil test. 
    rwRENDERSTATESTENCILFUNCTIONWRITEMASK = 28,//Write mask applied to values written into the stencil buffer. 
    rwRENDERSTATEALPHATESTFUNCTION = 29,// RwAlphaTestFunction for the alpha test. When a pixel fails, neither the frame buffer nor the Z-buffer are updated.
    rwRENDERSTATEALPHATESTFUNCTIONREF = 30, // Integer reference value for the alpha test. 
    rwRENDERSTATEFORCEENUMSIZEINT = 0x7FFFFFFF
};

enum RwPrimitiveType {
    rwPRIMTYPENAPRIMTYPE = 0,   // Invalid primitive type 
    rwPRIMTYPELINELIST = 1,     // Unconnected line segments, each line is specified by both its start and end index
    rwPRIMTYPEPOLYLINE = 2,     // Connected line segments, each line's start index (except the first) is specified by the index of the end of the previous segment 
    rwPRIMTYPETRILIST = 3,      // Unconnected triangles: each triangle is specified by three indices, independently of other triangles 
    rwPRIMTYPETRISTRIP = 4,     // Connected triangles sharing an edge with, at most, one other forming a series 
    rwPRIMTYPETRIFAN = 5 ,      // Connected triangles sharing an edge with, at most, two others forming a fan 
    rwPRIMTYPEPOINTLIST = 6,    // Points 1, 2, 3, etc. 
    rwPRIMITIVETYPEFORCEENUMSIZEINT = 0x7FFFFFFF
};

struct rwMemoryFunctions {
	void *(*rwmalloc)(size_t size, DWORD hint);
	void  (*rwfree)(void *mem);
	void *(*rwrealloc)(void *mem, size_t newSize, DWORD hint);
	void *(*rwcalloc)(size_t numObj, size_t sizeObj, DWORD hint);
};

//=============================================================================
// streams
// На данный момент, с целью упрощения, реализуются только два типа потоков: filename и memory. 
// Аналогично, реализовано только чтение
enum RwStreamType {
    rwNASTREAM = 0,     // Invalid stream type 
    rwSTREAMFILE,       // File 
    rwSTREAMFILENAME,   // File name 
    rwSTREAMMEMORY,     // Memory
    rwSTREAMCUSTOM,		// Custom 
	rwSTREAMLAST = 0x7FFFFFFF
};

enum RwStreamAccessType {
    rwNASTREAMACCESS = 0,   // Invalid stream access 
    rwSTREAMREAD,           // Read 
    rwSTREAMWRITE,          // Write 
    rwSTREAMAPPEND			// Append 
};

// TODO: оставить только необходимое: перенести куски, специфичные для каждого типа в сабклассы
// TODO: сделать виртуальные методы

class CStreamError {
public:
	CStreamError (const char * _description) { description = _description; }

	const char * description;
};

struct ChunkHeaderInfo {
    DWORD	type;		// chunk ID 
    int		length;		// length of the chunk data in bytes 
    DWORD	version;	// version of the chunk data. 
    DWORD	buildNum;	// build number of the RenderWare libraries previously used to stream out the data 
    bool	isComplex;  // Internal Use 
};

class CRwStream {
public:
	CRwStream ();
	virtual ~CRwStream () {}

	virtual int read (void * buffer, int length) = 0;
	virtual bool skip (int bytes) = 0;
	virtual void reinit (bool _owned, BYTE * _block, int _size) {}

	virtual bool isValid () { return true; } 

	bool readChunkHeader (DWORD * type, int * length, DWORD * version, DWORD * build);
	bool readChunkHeaderInfo (ChunkHeaderInfo * info);	// TODO: этот метод используется в одном месте. Возможно, без него можно и обойтись
	bool findChunk (DWORD type, int * outLength, DWORD * outVersion);

	// object readers
	// TODO: сгруппировать по используемым типам (т.е. должны быть те методы только для тех чанков, которые используются извне этого класса)
	CClump * readClump ();	// >> 74B420 (9)

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

// protected:
	RwStreamType		type;	
	// RwStreamAccessType	accessType;	(убрано, чтобы компенсировать VMT)
	int					position;
	union {
		struct {
			int		position;
			int		size;
			BYTE *	block;
		} memory;
		struct {
			FILE * file;
		} file;
		
	};
	DWORD	_fill[2];
	int		owned;
};

class CRwFilenameStream : public CRwStream {	
public:
	CRwFilenameStream (char * filename);
	virtual ~CRwFilenameStream ();

	virtual int read (void * buffer, int length);
	virtual bool skip (int bytes);
	virtual bool isValid () { return file.file != NULL; }

};

class CRwMemoryStream : public CRwStream {
public:
	CRwMemoryStream (BYTE * _block, int _size);

	virtual int read (void * buffer, int length);
	virtual bool skip (int bytes);
	virtual void reinit (bool _owned, BYTE * _block, int _size);
};
//=============================================================================
// the big evil one
struct CEngine {
	
	RwCamera *	curCamera;		// 000
	RpWorld	*	curWorld;		// 004
	WORD		renderFrame;	// 008
	WORD		lightFrame;		// 00A
	DWORD		pad;			// 00C

	// RwDevice begins here
	float	gammaCorrection;	// 010
	DWORD	fpSystem;			// 014 - RwSystemFunc
	float	zBufferNear;		// 018
	float	zBufferFar;			// 01C
	void	(__cdecl * renderStateSet)(RwRenderState state, DWORD param);	// 020
	void * _renderStateGet;		// 024
	void * _im2DRenderLine;		// 028
	void * _im2DRenderTriangle;	// 02C
	void (__cdecl * im2DRenderPrimitive) (RwPrimitiveType type, void * vertices, int count);	// 030
	void * im2DRenderIndexedPrimitive; // 034
	void * _im3DRenderLine;		// 038
	void * _im3DRenderTriangle; // 03C
	void * _im3DRenderPrimitive;		// 040
	void * _im3DRenderIndexedPrimitive; // 044
	// RwDevice ends here
	// standard functions
	DWORD	_f48;
	void *	_cameraBeginUpdate;	// 04C
	DWORD	_f50;
	DWORD	_f54;
	DWORD	_f58;
	DWORD	_f5C;
	void * _getImageFromRaster;	// 060
	void * _setRasterFromImage;	// 064
	DWORD	_f68;
	void * _findRasterFormat;	// 06C
	DWORD	_f70;
	DWORD	_f74;
	DWORD	_f78;
	DWORD	_f7C;
	DWORD	_f80;
	DWORD	_f84;
	DWORD	_f88;
	DWORD	_f8C;
	DWORD	_f90;
	DWORD	_f94;
	DWORD	_f98;
	DWORD	_f9C;
	DWORD	_fA0;
	DWORD	_fA4;
	DWORD	_fA8;
	DWORD	_fAC;
	DWORD	_fB0;
	DWORD	_fB4;
	void *	_rasterGetMipLevels;
	RwLLLink	dirtyFrameList;
	// RwFileFunctions begins here	TODO: от них нужно избавиться как только это будет возможно
	DWORD	_fC4;
	void *	(__cdecl *rwfopen) (char * name, char * mode);	// 0C8
	void	(__cdecl *rwfclose) (void * file);	// 0CC
	void * _rwfread;	// 0D0
	void * _rwfwrite;	// 0D4
	void * _rwfgets;	// 0D8
	void *	_fDC;
	void * _rwfeof;		// 0E0
	void * _rwfseek;	// 0E4
	void *	_fE8;		
	void * _rwftell;	// 0EC
	// RwFileFunctions ends here
	// RwStringFunctions begins here	TODO: от них нужно избавиться как только это будет возможно
	void * _rwsprintf;	// 0F0
	void * _rwvsprintf;	// 0F4
	void * _rwstrcpy;	// 0F8
	void * _rwstrncpy;	// 0FC
	void * _rwstrcat;	// 100
	void * _rwstrncat;	// 104
	void * _rwstrrchr;	// 108
	void * _rwstrchr;	// 10C
	void * _rwstrstr;	// 110
	void * _rwstrcmp;	// 114
	void * _rwstrncmp;	// 118
	void * _rwstricmp;	// 11C
	void * _rwstrlen;	// 120
	void * _rwstrupr;	// 124
	void * _rwstrlwr;	// 128
	void * _rwstrtok;	// 12C
	void * _rwsscanf;	// 130
	// RwStringFunctions ends here
	rwMemoryFunctions mem;
	void *	(__cdecl * alloc) (CBlockAllocator * list, int hint);	// 144
	void	(__cdecl * free) (CBlockAllocator * list, void * ptr);	// 148
	DWORD	metrics;	// 14C
	DWORD	engineStatus;	// 150 TODO: bool
	DWORD	resArenaSize;	// 154

	// инициализация. Возвращает false, если произошла ошибка
	bool	init (DWORD _resArenaSize);	//	TODO: а параметр-то нужен?
};

struct CWorldObject {	// engine plugin 0x0507	(TODO: remove/move to CEngine)
	CBlockAllocator *	tieAllocator;
	CBlockAllocator *	lightTieAllocator;
	void *				_f08;
};	

//	TODO: оптимальный вариант: аллокаторы выносятся в CMemoryManager вместе с txdPool, а остальное - превращается в CTextureManager
//	TODO: впрочем, насчет аллокаторов я полностью не уверен
struct CTextureModule {	// engine plugin 0x408 (TODO: remove/move to CEngine)
	RwLLLink			txdList;			// +00 RwTexDictionary list
	CBlockAllocator	*	textureAllocator;	// +08 texture pool
	CBlockAllocator *	txdAllocator;		// +12 texture dictionary pool
	CTexDictionary *	currentTxd;			// +16
	void *				findCB;				// +20 TODO: определить типы для callback-ов
	void *				readCB;				// +24
	DWORD				enableMipmapping;	// +28
	DWORD				autoMipmapping;		// +32
	DWORD				_f24;				// +36
	DWORD				_f28;				// +40
	DWORD				rasterBuildCB;		// +44
	DWORD				mipmapNameCB;		// +48
};

extern CEngine ** engine;

extern DWORD * worldObjOffset;		// offset of the WorldObject extension in CEngine (TODO: добавить эту структуру в CEngine и убрать переменную)
extern DWORD * textureModuleOffset;
#define __textureModule (CTextureModule *)(((BYTE *)(*engine))+*textureModuleOffset)

//=============================================================================
struct RsInputDevice {
	int		type;
	int		used;
	void *	handler;
};

struct PsGlobalType;

struct RsGlobalType {
	char *	appName;
	int		maximumWidth;
	int		maximumHeight;
	int		frameLimit;
	int		quit;
	PsGlobalType *	ps;
	RsInputDevice	keyboard;
	RsInputDevice	mouse;
	RsInputDevice	pad;
};

extern RsGlobalType * rsGlobal;

#pragma pack (pop)