/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __C4DBASEDRAW_H
#define __C4DBASEDRAW_H

#include "ge_matrix.h"
#include "c4d_baselist.h"
#include "c4d_basecontainer.h"
#include "c4d_general.h"

class BaseDrawHelp
{
	private:
		BaseDrawHelp();
		~BaseDrawHelp();
	public:
		BaseDocument	*GetDocument(void) { return C4DOS.Br->BbGetDocument(this); }
		BaseTag				*GetActiveTag(void) { return C4DOS.Br->BbGetActiveTag(this); }
		Matrix				GetMg(void) { return C4DOS.Br->BbGetMg(this); }
		BaseContainer	GetDisplay(void) { BaseContainer bc; C4DOS.Br->BbGetDisplay(this,&bc); return bc; }
		void					SetMg(const Matrix &mg) { C4DOS.Br->BbSetMg(this,mg); }
};

#define SAFEFRAME_NONE				0
#define SAFEFRAME_VERTICAL		1
#define SAFEFRAME_HORIZONTAL	2

#define MAX_Z									1000000

#define VIEW_NEARCLIPPING			0.01

#define OITPASS_OFF			0
#define OITPASS_FIRST		1
#define OITPASS_MIDDLE	2
#define OITPASS_LAST		3
struct OITInfo 
{
	LONG lMode;
	LONG lPass;
	C4DGLuint nDepthTexture;
	Bool bStackedMat;
};

class BaseView : public BaseList2D
{
	private:
		BaseView();
		~BaseView();
	public:
		void GetFrame(LONG *cl, LONG *ct, LONG *cr, LONG *cb);
		void GetSafeFrame(LONG *from, LONG *to, LONG *horizontal);
		void GetViewParameter(Vector *offset, Vector *scale, Vector *scale_z);
		Matrix GetMg(void) { return C4DOS.Bv->GetMg(this); }
		Matrix GetMi(void) { return C4DOS.Bv->GetMi(this); }
		LONG GetProjection(void) { return C4DOS.Bv->GetProjection(this); }
		Bool TestPoint(Real x, Real y) { return C4DOS.Bv->TestPoint(this,x,y); }
		Bool TestPointZ(const Vector &p) { return C4DOS.Bv->TestPointZ(this,p); }
		Bool TestClipping3D(const Vector &mp, const Vector &rad, const Matrix &mg, Bool *clip2d, Bool *clipz);
		Bool ClipLine2D(Vector *p1, Vector *p2) { return C4DOS.Bv->ClipLine2D(this,p1,p2); }
		Bool ClipLineZ(Vector *p1, Vector *p2) { return C4DOS.Bv->ClipLineZ(this,p1,p2); }
		Vector WS(const Vector &p) { return C4DOS.Bv->WS(this,p); }
		Vector SW(const Vector &p) { return C4DOS.Bv->SW(this,p); }
		Vector SW(Real x, Real y, const Vector &wp) { return C4DOS.Bv->SW_R(this,x,y,wp); }
		Vector WC(const Vector &p) { return C4DOS.Bv->WC(this,p); }
		Vector CW(const Vector &p) { return C4DOS.Bv->CW(this,p); }
		Vector SC(const Vector &p) { return C4DOS.Bv->SC(this,p); }
		Vector CS(const Vector &p, Bool z_inverse) { return C4DOS.Bv->CS(this,p,z_inverse); }
		Vector WC_V(const Vector &v) { return C4DOS.Bv->WC_V(this,v); }
		Vector CW_V(const Vector &v) { return C4DOS.Bv->CW_V(this,v); }
		Bool BackfaceCulling(const Vector &n, const Vector &p) { return C4DOS.Bv->BackfaceCulling(this,n,p); }
		Bool ZSensitive(void) { return C4DOS.Bv->ZSensitive(this); }
		Real ZSensitiveNearClipping(void) { return C4DOS.Bv->ZSensitiveNearClipping(this); }
};

class BaseDraw : public BaseView
{
	private:
		BaseDraw();
		~BaseDraw();

		// only access through GetParameter/SetParameter!!!
		BaseContainer GetData(void);
		void SetData(const BaseContainer &bc, Bool add=TRUE);
		BaseContainer* GetDataInstance(void);

	public:
		GeData GetParameterData(LONG id);

	public:
		LONG       GetFrameScreen(LONG *cl, LONG *ct, LONG *cr, LONG *cb); // runs only with activated OpenGL, -2: no OpenGL window, -1: offscreen view, 0: system error, 1: success
		Bool       HasCameraLink(void) { return C4DOS.Br->HasCameraLink(this); }
		void       SetSceneCamera(BaseObject *op)  { C4DOS.Br->SetSceneCamera(this,op); }
		BaseObject *GetSceneCamera(BaseDocument *doc)  { return C4DOS.Br->GetSceneCamera(this,doc); }
		BaseObject *GetEditorCamera(void)  { return C4DOS.Br->GetEditorCamera(this); }
		LONG GetDisplayFilter() { return C4DOS.Br->GetDisplayFilter(this); }
		LONG GetEditState() { return C4DOS.Br->GetEditState(this); }
		Bool IsValidEditState(BaseDocument *doc) { return C4DOS.Br->IsValidEditState(this,doc); }
		Bool IsViewOpen(BaseDocument *doc)  { return C4DOS.Br->IsViewOpen(this,doc); }
		
		Bool AddToPostPass(BaseObject *op, BaseDrawHelp *bh)  { return C4DOS.Br->AddToPostPass(this,op,bh,0); }

		Vector GetObjectColor(BaseDrawHelp *bh, BaseObject *op)  { return C4DOS.Br->GetObjectColor(this,op,bh); }
		Vector CheckColor(const Vector &col)  { return C4DOS.Br->CheckColor(this,col); }
		
		Bool ZBufAvailable(void)  { return C4DOS.Br->ZBufAvailable(this); }
		
		void SetTransparency(LONG trans)  { C4DOS.Br->SetTransparency(this,trans); }
		LONG GetTransparency(void)  { return C4DOS.Br->GetTransparency(this); }
		
		Bool PointInRange(const Vector &p, LONG x, LONG y)  { return C4DOS.Br->PointInRange(this,p,x,y); }
		void SetPen(const Vector &col)  { C4DOS.Br->SetPen(this,col); }
		Real SimpleShade(const Vector &p, const Vector &n)  { return C4DOS.Br->SimpleShade(this,p,n); }
		
		void Point2D(const Vector &p)  { C4DOS.Br->Point2D(this,p); }
		void Line2D(const Vector &p1, const Vector &p2)  { C4DOS.Br->Line2D(this,p1,p2); }
		void Handle2D(const Vector &p, LONG type=HANDLE_SMALL) { C4DOS.Br->Handle2D(this,p,type); }
		void Circle2D(LONG mx, LONG my, Real rad) { C4DOS.Br->Circle2D(this,mx,my,rad); }
		void LineCS(const Vector &p1, const Vector &p2, Bool clip2d, Bool clipz,Bool offset=FALSE) { C4DOS.Br->LineCS(this,p1,p2,clip2d,clipz,offset); }
		void Point3D(const Vector &p) { C4DOS.Br->Point3D(this,p); }
		void Line3D(const Vector &p1, const Vector &p2) { C4DOS.Br->Line3D(this,p1,p2); }
		void Handle3D(const Vector &p, LONG type) { C4DOS.Br->Handle3D(this,p,type); }
		void Circle3D(const Matrix &m) { C4DOS.Br->Circle3D(this,m); }
		void Box3D(const Matrix &m, Real size, const Vector &col) { C4DOS.Br->Box3D(this,m,size,col); }
		void Polygon3D(Vector *p, Vector *f, Bool quad) { C4DOS.Br->Polygon3D(this,p,f,quad); }
		void DrawPolygonObject(BaseDrawHelp *bh, BaseObject *op, LONG flags) { C4DOS.Br->DrawPObject(this,bh,op,flags); }
		Bool DrawObject(BaseDrawHelp *bh, BaseObject *op, LONG drawpass) { return C4DOS.Br->DrawPObject(this,bh,op,drawpass|(1<<30)); }
		void LineZOffset(LONG offset) { C4DOS.Br->LineZOffset(this,offset); }
		void SetMatrix_Projection() { C4DOS.Br->SetMatrix_Projection(this); } // sets the projection matrix
		void SetMatrix_Screen() { C4DOS.Br->SetMatrix_Screen(this); } // sets the transformation matrix to screencoordinates
		void SetMatrix_Screen(LONG zoffset) { C4DOS.Br->SetMatrix_ScreenO(this, zoffset); } // sets the transformation matrix to screencoordinates
		void SetMatrix_Camera() { C4DOS.Br->SetMatrix_Camera(this); } // sets the transformation matrix to camerasystem
		void SetMatrix_Matrix(BaseObject *op,const Matrix &mg) { C4DOS.Br->SetMatrix_Matrix(this, op, mg); } // sets the transformation matrix to the given matrix
		void SetMatrix_Matrix(BaseObject *op,const Matrix &mg, LONG zoffset) { C4DOS.Br->SetMatrix_MatrixO(this, op, mg, zoffset); } // sets the transformation matrix to the given matrix
// flags for LineNew,LineStrip,DrawHandle,DrawPoly,...
#define NOCLIP_D	1	// clip against the view border
#define NOCLIP_Z		2	// z clipping
		void LineNew(const Vector &p1, const Vector &p2,LONG flags) { C4DOS.Br->LineNew(this, p1, p2, flags); }
		void LineStripBegin() { C4DOS.Br->LineStripBegin(this); }
		void LineStrip(const Vector &vp,const Vector &vc,LONG flags) { C4DOS.Br->LineStrip(this, vp, vc, flags); }
		void LineStripEnd() { C4DOS.Br->LineStripEnd(this); }
		void DrawHandle(const Vector &vp,LONG type,LONG flags) { C4DOS.Br->DrawHandle(this, vp, type, flags); }
		void DrawPoly(Vector *vp,Vector *vf,Vector *vn,LONG anz,LONG flags) { C4DOS.Br->DrawPoly(this,vp,vf,vn,anz,flags); }
		void DrawTexture(BaseBitmap *bmp, Vector *padr4, Vector *cadr, Vector *vnadr, Vector *uvadr, LONG pntcnt, Bool interpolation, LONG alphamode) { C4DOS.Br->DrawTexture(this,bmp,padr4,cadr,vnadr,uvadr,pntcnt,interpolation,alphamode); }
		void CircleNew(const Matrix &m) { C4DOS.Br->CircleNew(this,m); }
		void Box3DNew(const Matrix &m, Real size, const Vector &col, Bool wire) { C4DOS.Br->Box3DNew(this,m,size,col,wire); }
		void PolygonNew(Vector *p, Vector *f, Bool quad) { C4DOS.Br->PolygonNew(this,p,f,quad); }
		void DrawSphere(const Vector &off, const Vector &size, const Vector &col, LONG flags) { C4DOS.Br->DrawSphere(this, off, size, col, flags); }
		void DrawArrayEnd() { C4DOS.Br->DrawArrayEnd(this); }

#define DRAW_ALPHA_NONE			10
#define DRAW_ALPHA_INVERTED	11
#define DRAW_ALPHA_NORMAL		12
		void SetLightList(LONG mode) { C4DOS.Br->SetLightList(this,mode); }
#define BDRAW_SETLIGHTLIST_NOLIGHTS				-1
#define BDRAW_SETLIGHTLIST_SCENELIGHTS		0
#define BDRAW_SETLIGHTLIST_QUICKSHADING		1

		LONG GetInitTimer() { return C4DOS.Br->GetInitTimer(this); }
		void InitUndo(BaseDocument *doc) { C4DOS.Br->InitUndo(this,doc); }
		void DoUndo(BaseDocument *doc) { C4DOS.Br->DoUndo(this,doc); }

		void SetDrawParam(LONG id,const GeData &data) { C4DOS.Br->SetDrawParam(this,id,data); }
		GeData GetDrawParam(LONG id) { return C4DOS.Br->GetDrawParam(this,id); }
#define DRAW_PARAMETER_LINEWIDTH				1000	// [SET/GET] Real LineWidth
#define DRAW_PARAMETER_ALPHA_THRESHOLD	1002	// [SET/GET] Real 0 ... 1.0 (make sure to set old value after change!
#define DRAW_PARAMETER_SETZ							2
	#define DRAW_Z_LOWEREQUAL	0
	#define DRAW_Z_GREATER		1
	#define DRAW_Z_ALWAYS			2
#define DRAW_PARAMETER_OGL_CULLING			10
	#define DRAW_PARAMETER_OGL_CULLING_OFF				0
	#define DRAW_PARAMETER_OGL_CULLING_FRONT			1
	#define DRAW_PARAMETER_OGL_CULLING_BACK				2
	#define DRAW_PARAMETER_OGL_CULLING_FRONT_AND_BACK 3
#define DRAW_PARAMETER_USE_Z						11

#define DRAWPORT_TYPE_SOFTWARE					0
#define DRAWPORT_TYPE_OGL								1
#define DRAWPORT_TYPE_OGL_HQ						2

		Bool TestBreak() { return C4DOS.Br->TestBreak(this); }
		OITInfo& GetOITInfo() { return C4DOS.Br->GetOITInfo(this); }

#define DRAW_GET_VIEWMATRIX_PROJECTION						0
#define DRAW_GET_VIEWMATRIX_PROJECTION_LARGE_Z		1
#define DRAW_GET_VIEWMATRIX_INV_CAMERA						2
		const Matrix4& GetViewMatrix(LONG n);
};

struct ViewportPixel
{
	BaseObject* op;   // the object
	Real z;           // z coordinate of current element
	LONG i;           // element index (may be point, polygon, edge (4*polygon+edge) or spline point (segment offset + point))
	ViewportPixel* next; // next element
};

#define VIEWPORT_CLEAR_POINT      1
#define VIEWPORT_CLEAR_POLYGON    2
#define VIEWPORT_CLEAR_EDGE       4

#define VIEWPORT_USE_HN           1
#define VIEWPORT_USE_DEFORMERS    2
#define VIEWPORT_IGNORE_HIDDEN_SEL 8

class ViewportSelect
{
	private:
		ViewportSelect();
		~ViewportSelect();
	public:
		static ViewportSelect* Alloc();
		static void Free(ViewportSelect *&p);

		static Bool PickObject(BaseDraw* bd, BaseDocument* doc, LONG x, LONG y, LONG rad, Bool allowOpenGL, LassoSelection* ls, C4DObjectList* list);

		Bool Init(LONG w, LONG h, BaseDraw* bd, BaseObject* op, LONG mode, Bool onlyvisible, LONG flags = 0);
		Bool Init(LONG w, LONG h, BaseDraw* bd, AtomArray* ar, LONG mode, Bool onlyvisible, LONG flags = 0);
		
		ViewportPixel* GetPixelInfoPoint(LONG x, LONG y);
		ViewportPixel* GetPixelInfoPolygon(LONG x, LONG y);
		ViewportPixel* GetPixelInfoEdge(LONG x, LONG y);
		ViewportPixel* GetNearestPoint(BaseObject* op, LONG &x, LONG &y, LONG maxrad = MAXLONG, Bool onlyselected = FALSE, LONG* ignorelist = NULL, LONG ignorecnt = 0);
		ViewportPixel* GetNearestPolygon(BaseObject* op, LONG &x, LONG &y, LONG maxrad = MAXLONG, Bool onlyselected = FALSE, LONG* ignorelist = NULL, LONG ignorecnt = 0);
		ViewportPixel* GetNearestEdge(BaseObject* op, LONG &x, LONG &y, LONG maxrad = MAXLONG, Bool onlyselected = FALSE, LONG* ignorelist = NULL, LONG ignorecnt = 0);

		// points must be in camera space
		Bool DrawPolygon(const Vector* p, LONG ptcnt, LONG i, BaseObject* op, Bool onlyvisible = -1);
		Bool DrawHandle(const Vector& p, LONG i, BaseObject* op, Bool onlyvisible = -1);

		void ShowHotspot(EditorWindow *bw, LONG x, LONG y);
		void SetBrushRadius(LONG r);
		void ClearPixelInfo(LONG x, LONG y, UCHAR mask);
		Bool GetCameraCoordinates(Real x, Real y, Real z, Vector &v);
};

#endif
