// ### OpenGTA3 ###
// Object Models
// TODO: пока здесь же размещаются и СColModel* - возможно, стоит вынести ее в отдельный файл

#pragma pack(push, 1)
//=============================================================================
//	CColModel

// file header
struct ColFileHeader {
	DWORD	fourcc;			// file type: COLL/COLL2/COLL3
	int		dataSize;		// size of data beyond this field
	char	modelName[20];	// 
	DWORD	_pad;			
};

// version 1
struct ColModelCOLL {	// 40 bytes
	RwBBox		bbox;				// +0
	RwSphere	sphere;				// +24
};

// old v1 format
struct ColModelCOL1 {	// 40 bytes
	float		radius;
	D3DVECTOR	center;
	RwBBox		bbox;
};

// version 2
struct ColModelCOL2 : public ColModelCOLL {	// 76 bytes
	WORD		numberOfSpheres;	// +40
	WORD		numberOfBoxes;		// +42
	DWORD		numberOfFaces;		// +44
	DWORD		flags;				// +48
	DWORD		offsetSpheres;		// +52
	DWORD		offsetBoxes;		// +56
	DWORD		offset1;			// +60
	DWORD		offsetMeshVertices;	// +64
	DWORD		offsetMeshFaces;	// +68
	DWORD		offset2;			// +72
};

// version 3
struct ColModelCOL3 : public ColModelCOL2 {	// 88 bytes
	DWORD		numberOfShadowMeshFaces;	// +76
	DWORD		offsetShadowMeshVertices;	// +80
	DWORD		offsetShadowMeshFaces;		// +84
};

struct ColDataHeader;
// структура для связывания блоков в CColData
struct ColLink {
	ColDataHeader *	ptr;
	ColLink *	next;
	ColLink *	prev;
};

struct ColDataHeader {	// 48 bytes
	WORD		numberOfSpheres;		// +0
	WORD		numberOfBoxes;			// +2
	WORD		numberOfFaces;			// +4
	BYTE		number1;				// +6
	BYTE		flags;					// +7
	BYTE *		spheres;				// +8
	BYTE *		boxes;					// +12
	BYTE *		ptr1;					// +16 from offset1
	BYTE *		meshVertices;			// +20
	BYTE *		meshFaces;				// +24
	BYTE *		ptr2;					// +28
	DWORD		numberOfShadowMeshFaces;	// +32
	DWORD		numberOfShadowMeshVertices;	// +36
	BYTE *		shadowMeshVertices;			// +40
	BYTE *		shadowMeshFaces;			// +44

	ColLink *	getColLink ();	// >> 40F6E0 (3)
	void		unlink ();	// >> 416400 (4)
	DWORD		calculateNumberOfShadowMeshVertices ();
};



// extern CColLink freeColLinks;	// TODO: сделать после того, как будут полностью разобраны коллизии; объявить внутри модуля, как static

// обертка вокруг ColDataHeader с конструктором и деструктором
// NOTE: как правило, ColDataHeader инициализируется именно как заголовок прочитаных данных коллизий 
//	и указатели - ссылаются на этот блок данных (т.е., для освобождения памяти достаточно освободить 
//	весь блок "одним куском". В CColData - каждый указатель ссылается на отдельный блок данных, и,
//	при осмобожденни объекта, каждый блок должен быть освобожден отдельно.
// TODO: куча мелких, отдельно выделяемых кусков - это неэффективно. Оптимально - переделать все
//	на один блок и смещения, переопределив new и delete. Возможно, также стоит выровнять секции внутри 
//	блока на границу 16 байт
class CColData : public ColDataHeader {
public:
	CColData ();	// >> 40F030 (5)
	~CColData ();	// >> 40F070 (2)

	void		initFromRawData (ColDataHeader * data);	// >> 40F120 (2)
};

struct ColSurface {
	BYTE	material;
	BYTE	flags;
	BYTE	_f2;
	BYTE	light;
};

struct ColSphere {
	RwSphere	sphere;
	ColSurface	surface;
};

struct ColSphere1 {	// COLL v.1 sphere
	float		radius;
	D3DVECTOR	center;
	BYTE		material;
	BYTE		flags;
	BYTE		_f12;
	BYTE		_f2;	// light ?
};
struct ColBox {
	RwBBox		box;
	ColSurface	surface;
};

struct ColFace {
	WORD	a;
	WORD	b;
	WORD	c;
	BYTE	material;
	BYTE	light;
};

struct ColFace1 {
	DWORD	a;
	DWORD	b;
	DWORD	c;
	BYTE	material;
	BYTE	pad[2];
	BYTE	light;
};

struct ColVertice {
	short	x;
	short	y;
	short	z;
};

struct ColInitData {
	DWORD		_f0;
	DWORD		animID;
	DWORD		flags;
	D3DVECTOR	center;
	float		radius;
};

class CColModel {
public:
	CColModel ();
	~CColModel ();	// >> 40F700 (34)

	void initModelData (int numSpheres, int numBoxes, int num1, int numMeshVertices, int numFaces, BYTE flags);
	void initBBox ();
	void releaseData ();	// >> 40F9E0 (20)
	void createColData ();	// >> 40F810 (1)
	void createColDataFromRawData ();	// >> 40F740 (1)

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

	RwBBox			bbox;
	RwSphere		sphere;
	BYTE			_f28;
	BYTE			flags;
	BYTE			_f2A;
	BYTE			_f2B;
	union {
		ColDataHeader *	colDataHeader;	// flags&2 - used raw collision data
		CColData *		colData;
	};
};

class CModelBase;

// TODO: с этой функцией надо что-то сделать
void collisionPlugin_setCurrentModel (CModelBase * model);	// >> 41B350 (2)
// TODO: после того, как будет готов стриминг, стоит переделать две следующие функции на работу через memory map, и убрать несколько копирований
// TODO: эта функция будет сделана как конструктор CColModel с потоком, передаваемым как параметр (после того, как будет полностью сделано чтение CClump)
CRwStream * collisionPlugin_read (CRwStream * stream, int length);	// >> 41B1D0 (1)
// TODO: хорошо бы сделать эту функцию тоже конструктором, но, скорее всего, она будет методом colModelPool (т.к. читает все модели из файла)
void loadColFile (char * filename); // >> 5B4E60 (1)	
// TODO: аналогично, эти три функции должны стать методами CColModel
void processCOLL (BYTE * aData, CColModel * model, char * modelName);	// >> 537580 (4)
void processCOL2 (BYTE * aData, int length, CColModel * model, char * modelName);	// >> 537EE0 (4)
void processCOL3 (BYTE * aData, int length, CColModel * model, char * modelName);	// >> 537CE0 (4)
//=============================================================================
// handling
#define VEHICLE_COUNT	210
#define BIKE_COUNT		13
#define	FLYING_COUNT	24
#define	BOAT_COUNT		12

struct TransmissionData {
	DWORD	_f00;
	DWORD	_f04;
	DWORD	_f08;
	DWORD	_f0C;
	DWORD	_f10;
	DWORD	_f14;
	DWORD	_f18;
	DWORD	_f1C;
	DWORD	_f20;
	DWORD	_f24;
	DWORD	_f28;
	DWORD	_f2C;
	DWORD	_f30;
	DWORD	_f34;
	DWORD	_f38;
	DWORD	_f3C;
	DWORD	_f40;
	DWORD	_f44;
	BYTE	nDriveType;
	BYTE	nEngineType;
	BYTE	nNumberOfGears;
	BYTE	_f4B;
	DWORD	_f4C;
	float	fEngineAcceleration;
	float	fEngineInertia;
	float	fMaxVelocity;
	DWORD	_f5C;
	DWORD	_f60;
};

struct HandlingVehicle {
	int			index;
	float		fMass;
	float		_f8;	// 1.0/fMass
	float		fTurnMass;
	float		fDragMult;
	D3DVECTOR	centreOfMass;
	BYTE		nPercentSubmerged;
	BYTE		_f21;
	BYTE		_f22;
	BYTE		_f23;
	DWORD		_f24;
	float		fTractionMultiplier;
	TransmissionData	transmissionData;
	DWORD		_f90;
	float		fBrakeDeceleration;
	float		fBrakeBias;
	BYTE		bABS;
	BYTE		_f9D;
	BYTE		_f9E;
	BYTE		_f9F;
	float		fSteeringLock;
	float		fTractionLoss;
	float		fTractionBias;
	float		fSuspensionForceLevel;
	float		fSuspensionDampingLevel;
	float		fSuspensionHighSpdComDamp;
	float		fSuspensionUpperLimit;
	float		fSuspensionLowerLimit;
	float		fSuspensionBiasBetweenFrontAndRear;
	float		fSuspensionAntiDiveMultiplier;
	float		fCollisionDamageMultiplier;
	DWORD		modelFlags;
	DWORD		handlingFlags;
	float		fSeatOffsetDistance;
	int			nMonetaryValue;
	BYTE		frontLight;
	BYTE		rearLight;
	BYTE		animGroup;
	BYTE		_fDF;
};

struct HandlingBike {
	int		index;
	float	leanFwdCOM;
	float	leanFwdForce;
	float	leanBakCOM;
	float	leanBakForce;
	float	maxLean;
	float	fullAnimLean;
	float	desLean;
	float	speedSteer;
	float	slipSteer;
	float	noPlayerCOMz;
	float	wheelieAng;
	float	stoppieAng;
	float	wheelieSteer;
	float	wheelieStabMult;
	float	stoppieStabMult;
};

struct HandlingFlying {
	int			index;
	float		thrust;
	float		thrustFallOff;
	float		yaw;
	float		yawStab;
	float		sideSlip;
	float		roll;
	float		rollStab;
	float		pitch;
	float		pitchStab;
	float		formLift;
	float		attackLift;
	float		gearUpR;
	float		gearDownL;
	float		windMult;
	float		moveRes;
	D3DVECTOR	turnRes;
	D3DVECTOR	speedRes;
};

struct HandlingBoat {
	int			index;
	float		thrustY;
	float		thrustZ;
	float		thrustAppZ;
	float		aqPlaneForce;
	float		aqPlaneLimit;
	float		aqPlaneOffset;
	float		waveAudioMiult;
	float		look_L_R_BehindCamHeight;
	D3DVECTOR	moveRes;
	D3DVECTOR	turnRes;
};

struct CHandling {
	DWORD	_f00;
	DWORD	_f04;
	DWORD	_f08;
	DWORD	_f0C;
	DWORD	_f10;
	HandlingVehicle	vehicleHandling[VEHICLE_COUNT];
	HandlingBike	bikeHandling[BIKE_COUNT];
	HandlingFlying	flyingHandling[FLYING_COUNT];
	HandlingBoat	boatHandling[BOAT_COUNT];

	// static methods
	static int	findVehicleIndex2 (char * name);	// >> 6F4FD0	-- find vehicle name in carNames table
};

extern CHandling * handling;
extern char * carNames;
//=============================================================================
// animation // TODO: move to IFP-related stuff

struct CIfpFile {	
	char	name[16];
	BYTE	loaded;
	BYTE	_f11;
	short	usageCount;
	DWORD	startAnimation;	// first index in ifpAnimations
	int	animationCount;
	DWORD	animationStyle;
};

struct FrameDataKRTS {	// 38 bytes	Keyframe/Rotation/Translation/Scale
	float	_f0;	// RX
	float	_f4;	// RY
	float	_f8;	// RZ
	float	_fC;	// RW
	float	_f10;
	float	_f14;
	float	_f18;
	float	_f1C;
	float	_f20;
	float	_f24;
	float	_f28;
};

struct FrameDataKRT0 {	// 32 bytes	Keyframe/Rotation/Translation
	float	_f0;	// RX
	float	_f4;	// RY
	float	_f8;	// RZ
	float	_fC;	// RW
	float	_f10;	// TX
	float	_f14;	// TY
	float	_f18;	// TZ
	float	_f1C;	// time
};

struct FrameDataKR00 {	// 20 bytes	Keyframe/Rotation
	float	_f0;	// RX
	float	_f4;	// RY
	float	_f8;	// RZ
	float	_fC;	// RW
	float	_f10;	// time
};

struct SAnimFrame1 {	// 10 bytes	(SAnimFrameKR)
	short	_f0;	// RX
	short	_f2;	// RY
	short	_f4;	// RZ
	short	_f6;	// RW
	short	_f8;	// time
};

struct SAnimFrame2 {	// 16 bytes (SAnimFrameKRT)
	short	_f0;	// RX
	short	_f2;	// RY
	short	_f4;	// RZ
	short	_f6;	// RW
	short	_f8;	// time
	short	_fA;	// TX
	short	_fC;	// TY
	short	_fE;	// TZ
};

struct SAnimFrame3 {	// 20 bytes (SAnimFrameKRf)
	float	_f0;	// RX
	float	_f4;	// RY
	float	_f8;	// RZ
	float	_fC;	// RW
	float	_f10;	// time
};

struct SAnimFrame4 {	// 32 bytes (SAnimFrameKRTf)
	float	_f0;	// RX
	float	_f4;	// RY
	float	_f8;	// RZ
	float	_fC;	// RW
	float	_f10;	// time
	float	_f14;	// TX
	float	_f18;	// TY
	float	_f1C;	// TZ
};

struct CAnimBlendSequence {
	DWORD	hash;
	WORD	flags;
	WORD	frameCount;
	void *	frames;

	CAnimBlendSequence () {
		hash = 0xFFFF;
		flags = 0;
		frameCount = 0;
		frames = NULL;
	}

	~CAnimBlendSequence () {
		if (!(flags & 8) && frames)
			free (frames);
	}

	void setNumFrames (int num, BYTE _a4, BYTE _a8, void * frameData);	
};

struct CIfpAnimations {
	DWORD	hash;
	CAnimBlendSequence *	objects;	
	WORD	seqCount;
	BYTE	_fA;
	BYTE	_fB;
	int		ifpFileIndex;
	DWORD	_f10;
	DWORD	_f14;
};

struct CAnimationStyle {
	char	name[16];
	char	baseName[16];
	DWORD	_f20;
	int		nameCount;
	char **	namesPtr;
	DWORD *	dataPtr;
};
//=============================================================================
// model classes

// Структура, описывающая параметры переключения объектов с активацией по времени
struct CModelTimeinfo {
	BYTE	timeOn;			// time to activate (only hours)
	BYTE	timeOff;		// time to deactivate (only hours)
	short	pairedModel;	// night model for daytime object or day model for nighttime objest

	CModelTimeinfo * initPairedModel (char * modelName);
};

// базовый класс для всех моделей
class CModelBase {
public:
	DWORD		modelNameHash;	// +04
	WORD		usageCount;		// +08
	short		txdIndex;		// +10
	BYTE		_f0C;			// +12
	BYTE		count2dfx;		// +13
	short		index2dfx;		// +14
	short		objectInfoIndex;// +16 индекс соответствующего этой модели objectInfo
	WORD		flags;			// +18	0x80 - при освобождении данных, нужно освободить colModel
	CColModel *	colModel;		// +20 
	float		drawDistance;	// +24
	RwObject *	rwObject;		// +28 CAtomic or CClump

	CModelBase () { usageCount = 0; txdIndex = -1; }
	virtual ~CModelBase () {}

	virtual CModelBase * _m04 () { return NULL; }
	virtual CModelBase * _m08 () { return NULL; }
	virtual int _m0C () { return 0; }
	virtual const BYTE getType () const = 0;
	virtual CModelTimeinfo * getTimeinfo () { return NULL; }
	virtual void init ();
	virtual void clear();
	virtual void deleteRwObject () = 0;		// _m20 was clearData
	virtual int  getRwObjectType () = 0;	// _m24 getDataType (): 1 - atomic, 2 - clump
	virtual RwObject * createInstanceWithMM (RwMatrix *) = 0;		// _m28
	virtual RwObject * createInstance () = 0;	// _m2C
	virtual void initIfpName (char * name) {}	// _m30
	virtual void initIfp () {}					// _m34
	virtual int getIfpIndex () { return -1; }	// _m38

	void setComponentFlags (char * componentName);	// >> 4C4570 -- car mods processing

	void setTxd (char * txdName);
	void unsetTdx () { txdIndex = -1; }
	void addRef ();
	void release ();

	// назначить модели collision data
	// если выставлен initPairedModel, то для timed модели, collision data назначается и для второй модели в паре
	void setColModel (CColModel * colModel, bool initPairedModel);	// >> 4C4BC0 (19)
	void unsetColModel ();	// >> 4C4C40 (3)
};

class CModelObjs : public CModelBase {
public:
	CModelObjs () : CModelBase () {}
	static CModelObjs *	allocate (int objID);	

	virtual CModelBase * _m04 () { return this; }			// m04
	virtual const BYTE getType () const { return 1; }		// m10 'objs'
	virtual void deleteRwObject ();							// m20
	virtual int getRwObjectType () { return 1; }			// m24
	virtual RwObject * createInstanceWithMM (RwMatrix *);	// m28
	virtual RwObject * createInstance ();					// m2C
	virtual void setAtomic (CAtomic * _atomic);				// m3C

};

class CModelObjs2c : public CModelObjs {
public:
	CModelObjs2c () : CModelObjs () {}
	static CModelObjs2c * allocate (int objID);

	virtual CModelBase * _m08 () { return this; }
	virtual void init ();
	virtual void deleteRwObject ();
	virtual RwObject * createInstanceWithMM (RwMatrix *);
	virtual RwObject * createInstance ();

	RwObject * rwObject2;		
};

class CModelTobj : public CModelObjs {
public:
	CModelTobj () : CModelObjs () { timeinfo.pairedModel = -1; }
	static CModelTobj *	allocate (int objID);	

	virtual const BYTE getType () const { return 3; }
	virtual CModelTimeinfo * getTimeinfo () { return &timeinfo; }

	CModelTimeinfo	timeinfo;
};


// описатель компонента в иерархии модели
struct ModelComponent {	
	char *	name;	// component name
	DWORD	hierId;	// frame hierarchyID
	DWORD	flags;	// component flags		
};

class CModelHier : public CModelBase {	// originally CClumpModelInfo
public:

	CModelHier () : CModelBase () {}
	static CModelHier *	allocate (int objID);	

	virtual const BYTE getType () const { return 5; }
	virtual void init () { CModelBase::init (); ifpIndex = -1; }
	virtual void deleteRwObject ();
	virtual int	getRwObjectType () { return 2; }	// CLUMP
	virtual RwObject * createInstanceWithMM (RwMatrix *);
	virtual RwObject * createInstance ();
	virtual void initIfpName (char * name);
	virtual void initIfp ();
	virtual int getIfpIndex () { return ifpIndex; }
	virtual CColModel * getColModel () { return colModel; }		
	virtual void setClump (CClump * c);

	void initComponents (ModelComponent * components);

	union {	// _f20
		char *	ifpName;
		int		ifpIndex;
	};	
};

class CModelWeap : public CModelHier {
public:
	CModelWeap () : CModelHier () {}
	static CModelWeap *	allocate (int objID);	

	virtual const BYTE getType () const { return 4; }
	virtual void init () { CModelHier::init (); _f24 = 0; }
	virtual void setClump (CClump * c);

	DWORD	_f24;
};

class CModelPeds : public CModelHier {
public:
	CModelPeds () : CModelHier () { pedColModel = NULL; }
	static CModelPeds * allocate (int objID);
	virtual ~CModelPeds ();

	virtual const BYTE getType () const { return 7; }
	virtual void deleteRwObject ();
	virtual void setClump (CClump * c);

	void initPedColModel (CClump * c);

	DWORD	animType;
	DWORD	pedType;
	DWORD	statType;
	WORD	carMask;
	WORD	flags;
	CColModel * pedColModel;
	BYTE	radio1;
	BYTE	radio2;
	BYTE	pedModel;
	BYTE	__align;
	short	voiceType;
	short	voice1;
	short	voice2;
	short	voice3;
};

struct VehicleStruct_2 {
	D3DVECTOR	_f0;
	CQuaternion	q;
	int			_f1C;
};

struct CVehicleStruct {
	CVehicleStruct ();
	~CVehicleStruct ();

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

	D3DVECTOR		_f00[15];
	VehicleStruct_2	_fB4[18];
	CAtomic *		atomics[6];
	BYTE			atomicCount;
	BYTE			_f30D;
	WORD			_f30E;
	DWORD			_f310;	// component present or component renderable mask
};

// TODO: original name CVehicleModelInfo
class CModelCars : public CModelHier {	
public:
	CModelCars ();
	static CModelCars * allocate (int objID);

	virtual const BYTE	getType () const { return 6; }	
	virtual void		init ();
	virtual void		deleteRwObject ();
	virtual RwObject *	createInstance ();
	virtual void		initIfpName (char * name);
	virtual void		initIfp ();
	virtual int			getIfpIndex () { return carIfpIndex; }
	virtual void		setClump (CClump * clump);

	int	getCarVariation1 ();
	int getCarVariation2 ();

	void setVehicleRenderCallbacks ();
	void _4C8900 ();
	void preprocessHierarchy ();	
	void _4C8BD0 ();	// some debug + clear visibility flags for all atomics in the model
	void setVehicleComponentFlags  (CFrame * f, DWORD flags);	// set component visibility flags
	void prepareLicenseplate ();

	RpMaterial *licenseplateMaterial;	// _f24
	char		licenseplateText[8];
	BYTE		_f30;
	BYTE		_f31;
	char		gamename[8];
	WORD		_f3A;
	int			type;
	float		_p2;
	float		_p3;
	short		_p1;
	WORD		handlingIndex;
	BYTE		_f4C;
	BYTE		vclass;	// vehicle class
	BYTE		vflags;	// vehicle flags
	BYTE		_p4;
	WORD		_f50;
	WORD		frq;
	DWORD		comprules;
	float		_f58;
	CVehicleStruct *	vehicleStruct;
	BYTE		__fill[0x250];	// 060
	BYTE		primaryColors[8];
	BYTE		secondaryColors[8];
	BYTE		tertiaryColors[8];
	BYTE		quaternaryColors[8];
	BYTE		carColorCount;
	BYTE		_f2D1;
	BYTE		_f2D2;
	BYTE		_f2D3;
	BYTE		_f2D4;
	BYTE		_f2D5;
	short		carMods[18];
	int			_f2FA;
	int			_f2FE;
	WORD		_f302;
	union {	// _f304
		char *	carIfpName;
		int		carIfpIndex;
	};	
};

extern CModelBase ** modelPtrs;	// TODO: пока этот указатель размещается в gtaInterface. Учитывая количество мест, где он используется, там он пробудет почти до самого конца

struct ComponentLinks {
	WORD	component1[30];
	WORD	component2[30];
	DWORD	componentCount;

	void setLink (WORD first, WORD second);
};
extern ComponentLinks * componentLinks;

// helpers
extern CModelBase * getModelIndexByName (char * name, int * pIndex); // >> 4C5940 (31)

// физические свойства объектов
struct CObjectInfo {	// object.dat contents
	float	fMass;	
	float	fTurnMass;
	float	fAirResistance;
	float	fElasticity;
	float	_f10;
	float	fUprootLimit;
	float	fColDamageMultiplier;
	BYTE	colDamageEffect;	// 0 - none, 1 - change model, 20 - smash completely, 21 - change, then smash, 200 - breakable, 202 - breakable then removed
	BYTE	specColResponseCase;
	BYTE	cameraAvoidObject;
	BYTE	causesExplosion;
	BYTE	fxType;
	BYTE	_f21;
	BYTE	_f22;
	BYTE	_f23;
	D3DVECTOR	fxOffset;
	void *	particleData;	// particles object
	float	_f34;
	D3DVECTOR	breakVelocity;
	float	fBreakVelocityRand;
	int		smashMultiplier;
	int		sparksOnImpact;
};
extern CObjectInfo * objectInfo;	// >> BB4A90 CObjectInfo objectInfo[160];

// структура, содержащая индексы объектов 
// TODO: возможно, стоит от нее отказаться и ввести константы (все равно, большая часть кода так и делает)
// TODO: указать #pragma pack(push, 4) и убрать padding
struct PredefinedObjects {	// >> 8CD4F4: indices of some objects
	short miTrafficlight1;
	short _pad1;
	short miMTraffic4;
	short _pad2;
	short miMTraffic1;
	short _pad3;
	short miVgsstriplights1;
	short _pad4;
	short miMtraffic2;
	short _pad5;
	short miCjTrafficLight3;
	short _pad6;
	short miCjTrafficLight4;
	short _pad7;
	short miCjTrafficLight5;
	short _pad8;
	short miGayTrafficLight;
	short _pad9;
	short miLamppost1;
	short _pad10;
	short miLamppost2;
	short _pad11;
	short miLamppost3;
	short _pad12;
	short miDoublestreetlight1;
	short _pad13;
	short miStreetlamp1;
	short _pad14;
	short miStreetlamp2;
	short _pad15;
	short miDocCraneCab0;
	short _pad16;
	short miDocCraneCab01;
	short _pad17;
	short miDocCraneCab02;
	short _pad18;
	short miDocCraneCab03;
	short _pad19;
	short miBoatcraneleg0;
	short _pad20;
	short miLODnetopa0;
	short _pad21;
	short miParkingmeter;
	short _pad22;
	short miParkingmeterG;
	short _pad23;
	short miMallFans;
	short _pad24;
	short miHtlFanRotateNt;
	short _pad25;
	short miHtlFanRotateDy;
	short _pad26;
	short miHotroomfan;
	short _pad27;
	short miPhonebooth1;
	short _pad28;
	short miWastebin;
	short _pad29;
	short miBin1;
	short _pad30;
	short miPostbox1;
	short _pad31;
	short miNewsstand1;
	short _pad32;
	short miTrafficcone;
	short _pad33;
	short miDump1;
	short _pad34;
	short miDynRoadbarrier6;
	short _pad35;
	short miLaFuckcar1;
	short _pad36;
	short miLaFuckcar2;
	short _pad37;
	short miBussign1;
	short _pad38;
	short miNoparkingsign;
	short _pad39;
	short miPhonesign;
	short _pad40;
	short miFireHydrant;
	short _pad41;
	short miPackage1;
	short _pad42;
	short miMoney;
	short _pad43;
	short miBarrel1;
	short _pad44;
	short miBarrel2;
	short _pad45;
	short miBDynTv2;
	short _pad46;
	short miBriefcase;
	short _pad47;
	short miWglasssmash;
	short _pad48;
	short miGlassfxComposh;
	short _pad49;
	short _8CD5B8;
	short _pad50;
	short miAdrenaline;
	short _pad51;
	short miBodyarmor;
	short _pad52;
	short miInfo;
	short _pad53;
	short miHealth;
	short _pad54;
	short miBonus;
	short _pad55;
	short miBribe;
	short _pad56;
	short miKillfrenzy;
	short _pad57;
	short miCamerapickup;
	short _pad58;
	short miGunPara;
	short _pad59;
	short miBigdollar;
	short _pad60;
	short miPickupsave;
	short _pad61;
	short miPropertyLocked;
	short _pad62;
	short miPropertyFsale;
	short _pad63;
	short miClosesp;
	short _pad64;
	short miKillfrenzy2plyr;
	short _pad65;
	short mi2player;
	short _pad66;
	short miBollardlight;
	short _pad67;
	short miBarBarrier10;
	short _pad68;
	short miBarBarrier12;
	short _pad69;
	short miBouy;
	short _pad70;
	short miParktable1;
	short _pad71;
	short miLamppost1_1;
	short _pad72;
	short miMlamppost;
	short _pad73;
	short miRoadworkbarrier;
	short _pad74;
	short miLittlehaPolice;
	short _pad75;
	short miTelgrphpole02;
	short _pad76;
	short miTrafficlight1_0;
	short _pad77;
	short miParkbench1;
	short _pad78;
	short miOdLightbeam;
	short _pad79;
	short miApRadar101;
	short _pad80;
	short miRcbomb;
	short _pad81;
	short miBeachball;
	short _pad82;
	short miSandcastle1;
	short _pad83;
	short miSandcastle2;
	short _pad84;
	short miJellyfish;
	short _pad85;
	short miJellyfish01;
	short _pad86;
	short miFish1single;
	short _pad87;
	short miFish1s;
	short _pad88;
	short miFish2single;
	short _pad89;
	short miFish2s;
	short _pad90;
	short miFish3single;
	short _pad91;
	short miFish3s;
	short _pad92;
	short miTurtle;
	short _pad93;
	short miDolphin;
	short _pad94;
	short miShark;
	short _pad95;
	short miSubmarine;
	short _pad96;
	short miEscStep;
	short _pad97;
	short miEscStep8;
	short _pad98;
	short miLoungeWoodUp;
	short _pad99;
	short miLoungeTowelUp;
	short _pad100;
	short miLoungeWoodDn;
	short _pad101;
	short miLotion;
	short _pad102;
	short miBeachtowel01;
	short _pad103;
	short miBeachtowel02;
	short _pad104;
	short miBeachtowel03;
	short _pad105;
	short miBeachtowel04;
	short _pad106;
	short miBlimpNight;
	short _pad107;
	short miBlimpDay;
	short _pad108;
	short miYtMainBody;
	short _pad109;
	short miYtMainBody2;
	short _pad110;
	short miMilSamsite;
	short _pad111;
	short miMilSamsiteSFXRF;
	short _pad112;
	short miTraincross2;
	short _pad113;
	short miTraincross1;
	short _pad114;
	short miMagnoCrane03;
	short _pad115;
	short miTwrCraneM02;
	short _pad116;
	short miQuarryCranearm;
	short _pad117;
	short miKmbContainerRed;
	short _pad118;
	short miKmbContainerYel;
	short _pad119;
	short miKmbContainerBlue;
	short _pad120;
	short miBarrel4;
	short _pad121;
	short miKmbContainerOpen;
	short _pad122;
	short miBlockpallet;
	short _pad123;
	short miMagnocrane5SFS;
	short _pad124;
	short miKmbDeadarm;
	short _pad125;
	short miKmbDeadleg;
	short _pad126;
	short miKmbDeadhead;
	short _pad127;
	short miKmbDeadtorso;
	short _pad128;
	short miGrasshouse;
	short _pad129;
	short miGrassplant;
	short _pad130;
	short miCjPlayerHarness;
	short _pad131;
	short miIndusMagnet;
	short _pad132;
	short miDynQuarryrock01;
	short _pad133;
	short miDynQuarryrock02;
	short _pad134;
	short miDynQuarryrock03;
	short _pad135;
	short miKmbAtm3;
	short _pad136;
	short miDeadTiedCop;
	short _pad137;
	short miBonyrdwindsock;
	short _pad138;
	short mimDynWrekingBall;
	short _pad139;
	short miBomb;
	short _pad140;
	short miWongDish;
	short _pad141;
	short miCjBearBottle;
	short _pad142;
	short miCjCiggy;
	short _pad143;
	short _8CD730;
	short _pad144;
	short _8CD734;
	short _pad145;
	short _8CD738;
	short _pad146;
	short _8CD73C;
	short _pad147;
	short miMiniMagnet;
	short _pad148;
	short miAbCarcass;
	short _pad149;
	short miImyShashWall;
	short _pad150;
	short miParaPack;
	short _pad151;
	short miCjOyster;
	short _pad152;
	short miCjHorseShoe;
	short _pad153;
	short miWheelOr1;
	short _pad154;
	short miFlare;
	short _pad155;
	short miNtoBS;
	short _pad156;
	short miNtoBL;
	short _pad157;
	short miNtoBTw;
	short _pad158;
	short miHydralics;
	short _pad159;
	short miStereo;
	short _pad160;
	short miBballCol;
	short _pad161;
	short miKPoolballcue;
	short _pad162;
	short miPunchbagnu;
	short _pad163;
	short miImyBbox;
};


extern PredefinedObjects * objectIndices;

// cull zones
struct CullZoneBase {
	short	x;
	short	y;
	short	_f4;		// left ?
	short	ywidth;		// top ?
	short	xwidth;		// right ?
	short	_fA;		// bottom ?
	short	zbottom;
	short	ztop;
};

struct CullZone : public CullZoneBase {
	WORD	flags;
};

struct CullZoneReflection : public CullZoneBase {
	float	cm;
	char	vx;
	char	vy;
	char	vz;
	BYTE	flags;
};

struct OcclusionBox {
	short	midX;
	short	midY;
	short	midZ;
	short	widthY;
	short	widthX;
	short	height;
	BYTE	rotation;
	BYTE	rotation2;
	BYTE	rotation3;
	BYTE	__align;
	WORD	flags;
};

struct CGarage {
	D3DVECTOR	lowerLeft;
	float		dir1x;
	float		dir1y;
	float		dir2x;
	float		dir2y;
	float		topZ;
	float		normalizedWidth;
	float		normalizedHeight;
	float		left;
	float		right;
	float		front;
	float		back;
	float		_f38;
	float		_f3C;
	float		_f40;
	char		name[8];
	BYTE		_f4C;
	BYTE		status;
	BYTE		_f4E;
	BYTE		_f4F;
	DWORD		_f50;
	DWORD		_f54;
	DWORD		_f58;
	DWORD		_f5C;
	DWORD		_f60;
	DWORD		_f64;
	DWORD		_f68;
	DWORD		_f6C;
	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;
	DWORD		_fB8;
	DWORD		_fBC;
	DWORD		_fC0;
	DWORD		_fC4;
	DWORD		_fC8;
	DWORD		_fCC;
	DWORD		_fD0;
	DWORD		_fD4;
};

// ### animations ###
CIfpFile * findIfpFileByName (char * name);	// >> 4D3940 (27)
void readIfpFile (CRwStream * stream, int _a4, int _a8);	// >> 4D47F0 (4)	CAnimManager::LoadAnimFile

#pragma pack(pop)