//ROMTEAM WorldEditor
////////////////////////////////////////////////////////////////////////////////////////
// File        : Indexed Triangular Mesh editor 
// Author      : Nicolae Suparatu
// Date        : 
// Description :
////////////////////////////////////////////////////////////////////////////////////////
#define MAXLIN 40
#define MAXUNDOSTACK 32

typedef float (*pfArr3)[3];
typedef WORD (*pwArr3)[3];

class CVertex
{	
friend class CMatrix3;
public:
	float x;
	float y;
	float z;

	CVertex(float px, float py, float pz){x=px; y=py; z=pz;}
	CVertex(){};
	CVertex operator =(CVertex &v){x=v.x; y=v.y; z=v.z; return v;}
	CVertex operator *(CMatrix3& m);
	CVertex operator /(CMatrix3& m);
	float operator -(CVertex &v);
};


class CMatrix3
{
	float m[3][3];
public:
	CMatrix3();
	void SetRot(float ux, float uy);
	float operator()(int x, int y){ return m[x][y];}
};		


class CMesh
{	
public:
	static CMesh *s_me;
	CVertex *m_v;					// vertex list
	WORD (*m_edge)[2];		// edges list
	pwArr3 m_face;				// faces list
	char *m_sel;					// vertex selection status
	int *m_sort;					// sorted faces	
	CVertex *m_prj;				// projections list
	int m_iDimx, m_iDimy;
	int m_iVerts;
	int m_iFaces;
	int m_iEdges;

	CMesh(int x, int y);
	CMesh(CMesh &m);
	~CMesh();
	static int Compare(const void *p1, const void *p2);
	void SortZ();
	void ComputePrj(RECT &r, CMatrix3 &m);
	void Select(int i, BOOL is){ m_sel[i] = (m_sel[i] & ~1)	| (is != 0);}
	BOOL Selected(int i){ return m_sel[i] & 1;}
	void Toggle(int i){ m_sel[i] ^= 1; }
	void Or(int i, int is) { m_sel[i] |= is != 0;}
	void operator =(CMesh &m);
};


class CTriEdit
{
	CMesh *m_mesh;				// mesh
	HWND m_hwnd;					// window handle
	float m_ux, m_uy;			// rotation angles
	CMatrix3 m_mrot;			// rotation matrix
	RECT m_r;							// client rect
	int m_iUnderCursor;		// vertex index under cursor
	int m_iCrtVertex;			// current moved vertex index
	RECT m_SelRect;				// selection rectangle
	float m_fLinearity;
	BOOL m_bVisibility;
	HDC hdcmem;						// back buffer HDC
	HBITMAP bmp;					// back buffer
	HPEN m_GreenPen, m_RedPen;

	CMesh* m_UndoStack[MAXUNDOSTACK];	// Undo/Redo stack
	int m_iUndoSP;					// Undo/Redo stack pointer
	int m_iUndoCnt;					// Undo counter
	int m_iRedoCnt;					// redo counter
	BOOL m_bStackTopOK;
//*******************

protected:
	void NormalizeRect(RECT &s, RECT &d);
	float Effect(float distance);
	void Select(HDC hdc, int x, int y, HPEN pen);
	void AddModulo(int &i, int inc, int mod = MAXUNDOSTACK);
	void Invalidate(){ InvalidateRect(m_hwnd, NULL, TRUE); }

public:
	CTriEdit();								// constructor
	~CTriEdit();							// destructor
	int OnSetCursor(int x, int y);							// WM_SETCURSOR	 handle
	void OnLButtonDown(UINT flags, POINT p);		// WM_LBUTTONDOWN	 handle
	void OnLButtonUp(UINT flags, POINT p);			// WM_LBUTTONUP handle
	void OnMouseMove(POINT p);									// WM_MOUSEMOVE handle
	void SetHWnd(HWND hwnd);
	void Resize(int cx, int cy);
	void OnUndo();
	void OnRedo();
	void OnPaint(HDC hdc);
	void InitMesh(int x, int y);
	void Rotate(float dux, float duy);
	void SetLinearity(float l);
//ANNECY Shaitan Correction 03/03/98 {
	void SetVisibility(BOOL b) { m_bVisibility = b; if (m_mesh) m_mesh->SortZ(); Invalidate(); }
//ENDANNECY Shaitan Correction }
	int CanUndo(){ return m_iUndoCnt; }
	int CanRedo(){ return m_iRedoCnt; }
	pfArr3 GetVerts() { return m_mesh ? (pfArr3)m_mesh->m_v : NULL; }
	pwArr3 GetFaces(){ return m_mesh ? m_mesh->m_face : NULL; }
	int GetXVertsNumber(){ return m_mesh ? m_mesh->m_iDimx + 1 : 0; }
	int GetYVertsNumber(){ return m_mesh ? m_mesh->m_iDimy + 1 : 0; }
	int GetFacesNumber(){ return m_mesh ? m_mesh->m_iFaces : 0; }
};
