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

#ifndef _LIB_NGON_H_
#define _LIB_NGON_H_

#include "c4d_library.h"

class iNgonBase;
class NgonCache;
class HyperFile;
struct VariableChanged;
class PolygonObject;

//////////////////////////////////////////////////////////////////////////

class Ngon
{
public:

	Ngon();
	~Ngon();
	Ngon(const CPolygon &ply);
	Ngon(const Ngon &src);

	Ngon &operator=(const Ngon &src);

	Bool Alloc(LONG cnt, LONG scnt);
	void Free();
	Bool CopyFrom(const Ngon *src);
	Bool CopyFrom(LONG cnt, LONG scnt, LONG* pts, LONG* segs);
	void Release();

	Real CalcArea(LONG seg, const Vector* p, Matrix& m);

	//

	LONG	*points;
	LONG	*segments;
	LONG	count;
	LONG	segcount;
};

//////////////////////////////////////////////////////////////////////////

#ifndef NOTINDEX
#define NOTINDEX				(MAXLONGl)
#endif

#define PGONEDGE_REPEAT			(0x80000000)
#define PGONEDGE_RESET			(0x7FFFFFFF)
#define PGONEDGE_NOEDGES		(0x40000000)
#define PGONEDGE_EDGEINDEX		(0x1FFFFFFF)
#define PGONEDGE_ENDSEGMENT		(0x20000000)

class PgonEdge
{
public:
	inline Bool IsFirst()	// TRUE if this is the first occurrence of a polygon in the group
	{
		return !(edge_index&PGONEDGE_REPEAT);
	}
	inline Bool IsSegmentEnd()
	{
		return (edge_index&PGONEDGE_ENDSEGMENT);
	}
	inline LONG ID()
	{
		return (edge_index&PGONEDGE_EDGEINDEX)/4;
	}
	inline LONG State()
	{
		LONG edge=Edge();
		if (edge==NOTOK) return 0;
		return 1<<edge;
	}
	inline LONG Edge()
	{
		if (edge_index&PGONEDGE_NOEDGES) return NOTOK;
		return (edge_index&PGONEDGE_EDGEINDEX)%4;
	}
	inline LONG EdgeIndex()
	{
		if (edge_index&PGONEDGE_NOEDGES) return NOTOK;
		return (edge_index&PGONEDGE_EDGEINDEX);
	}
	void GetEdge(const CPolygon *vadr, LONG &p1, LONG &p2);
	void RemapPolygon(LONG new_poly, LONG new_edge);

	ULONG edge_index;
};

#ifndef __KERNEL_NGONBASE__
class Pgon
{
public:

	Vector CalcNormal(const Vector* padr, const CPolygon* polys) const;
	void GetMpRad(const Vector* padr, const CPolygon* polys, Vector &mp, Vector &rad) const;
	inline LONG GetCount() const { return m_Count; }
	inline PgonEdge *GetEdge(LONG i) { if (m_Edge) return &m_Edge[i]; else return NULL; }
	inline LONG ID(LONG i) const { return m_Edge[i].ID(); }
	inline LONG State(LONG i) const { return m_Edge[i].State(); }
	inline LONG Edge(LONG i) const { return m_Edge[i].Edge(); }
	inline LONG EdgeIndex(LONG i) const { return m_Edge[i].EdgeIndex(); }
	inline LONG IsFirst(LONG i) const { return m_Edge[i].IsFirst(); }
	inline LONG IsSegmentEnd(LONG i) const { return m_Edge[i].IsSegmentEnd(); }
	inline LONG GetIdentity() const { return (m_Count>0)?m_Edge[0].ID():NOTOK; }
	LONG GetSegmentCount() const;
	LONG GetSegmentLen(LONG startedge) const;
	void GetEdge(LONG i, const CPolygon *vadr, LONG &p1, LONG &p2) { m_Edge[i].GetEdge(vadr,p1,p2); }
	LONG FindPolygon(LONG id) const;
	UCHAR GetEdgeState(LONG id) const;
	LONG GetPointCount() const;
	LONG GetPolygonCount() const;
	void UpdateStates();

private:

	PgonEdge	*m_Edge;
	LONG		m_Count;
	ULONG		m_CRC;
};
#endif

//////////////////////////////////////////////////////////////////////////

#define NGON_TOSELECTION_POLYGONS	1
#define NGON_TOSELECTION_OUTLINE	2
#define NGON_TOSELECTION_OUTEREDGES	3
#define NGON_TOSELECTION_INNEREDGES	4
#define NGON_TOSELECTION_HOLES		5

#define NGON_FLAG_NOVALIDATION	(1<<0)	// block ngons from validating when you know their polygon indexes have no changed
										// or you are going to be changing this immediately so don't want them validated
										// this flag is auto removed when the ngons try to validate

#define NGON_FLAG_NOCHANGE		(1<<1)	// (same as _NOVALIDATION) does not auto remove so must be manually removed when not needed (WARNING: DO NOT LEAVE IT SET BEYOND YOUR FUNCTION)

#define NGON_FLAG_NOTRANSLATE	(1<<2)	// block the ngons from translating their polygon indexes when resizeobject is called
										// this flag is not auto remove so must be manually it when not needed (WARNING: DO NOT LEAVE IT SET BEYOND YOUR FUNCTION)

#define NGON_FLAG_SETASVALID	(1<<3)	// block ngons from validating completely but let them update their validation data
										// set ONLY if the polygon indexes might have changed but are known to be valid ngons
										// this flag is auto removed once used

#define NGON_VERIFY_FLAG_REPAIR	(1<<0)	// repair any illegal ngons (removes them)

class NgonBase
{
	friend class ModelingKernelBase;

private:

	NgonBase();
	~NgonBase();

	NgonCache *m_pNgonBase;

public:

	static NgonBase *Alloc();
	static void Free(NgonBase *&p);

	Bool CopyTo(NgonBase *dst);
	Bool Write(HyperFile *hf);
	Bool Read(HyperFile *hf, LONG id, LONG level);
	Bool Translate(VariableChanged *vc);
	Bool Changed(PolygonObject *op);

	UCHAR GetEdgeStates(LONG id) const;
	LONG GetCount() const;
	Pgon *GetNgons();

	Bool Resize(LONG cnt);
	LONG FindPolygon(LONG id, LONG l=-1) const;
	Bool CompactPgons();
	void CheckPoints(PolygonObject *op);
	void UpdateNgons(PolygonObject *op);

	Bool ResetPoints(PolygonObject *op);
	void SetFlags(LONG flgs);
	LONG GetFlags() const;
	LONG GetDirtyCount() const;

	void Dirty();

	void InitMap();
	void FreeMap();

	Bool Remove(LONG id, Bool force);
	Bool ToSelect(BaseSelect *pSelect, LONG mode);
	void GetCenter(LONG id, const CPolygon *vadr, const Vector *padr, Vector *ip, Vector *in);
	Bool RemapEdge(LONG oedge, LONG *nedges, LONG ncnt);
	Bool Create(ULONG *nedges, LONG ncnt);
	Bool RemapPolygon(LONG oply, LONG nply);
	Bool Copy(Pgon *src, Pgon *dst);

	Bool Validate(PolygonObject *op);
	Bool IsValidNgon(Pgon *pgon, const CPolygon *vadr);

	LONG BuildNgon(LONG *inner, LONG *outer, LONG icnt, LONG ocnt, const CPolygon *vadr, const Vector *padr);
	LONG BuildNgonFromPolys(LONG *polys, LONG *outer, LONG pcnt, LONG ocnt, const CPolygon *vadr, const Vector *padr);

	Bool Verify(const CPolygon *vadr, LONG vcnt, ULONG flags, Pgon *pgon=NULL);

	Pgon *AllocNgon(LONG edge_cnt);
	void FreeNgon(Pgon *&pgon);

	Bool SetNgon(LONG index, Pgon *src);
	Bool SetNgon(LONG index, ULONG *edges, LONG edge_cnt);
};

// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

#define LIBRARY_NGON	1015903

struct NgonBaseLib : public C4DLibrary
{
	iNgonBase *(*Alloc)();
	void (*Free)(iNgonBase *&p);

	Bool (*CopyTo)(iNgonBase *this_ptr, iNgonBase *dst);
	Bool (*Write)(iNgonBase *this_ptr, HyperFile *hf);
	Bool (*Read)(iNgonBase *this_ptr, HyperFile *hf, LONG id, LONG level);
	Bool (*Translate)(iNgonBase *this_ptr, VariableChanged *vc);
	Bool (*Changed)(iNgonBase *this_ptr, PolygonObject *op);

	UCHAR (*GetEdgeStates)(const iNgonBase *this_ptr, LONG id) ;
	LONG (*GetCount)(const iNgonBase *this_ptr);
	Pgon *(*GetNgons)(iNgonBase *this_ptr );

	Bool (*Resize)(iNgonBase *this_ptr, LONG cnt);
	LONG (*FindPolygon)(const iNgonBase *this_ptr, LONG id, LONG l) ;
	Bool (*CompactPgons)(iNgonBase *this_ptr );
	void (*CheckPoints)(iNgonBase *this_ptr, PolygonObject *op);
	void (*UpdateNgons)(iNgonBase *this_ptr, PolygonObject *op);

	Bool (*ResetPoints)(iNgonBase *this_ptr, PolygonObject *op);
	void (*SetFlags)(iNgonBase *this_ptr, LONG flgs);
	LONG (*GetFlags)(const iNgonBase *this_ptr);
	LONG (*GetDirtyCount)(const iNgonBase *this_ptr);

	void (*Dirty)(iNgonBase *this_ptr );

	void (*InitMap)(iNgonBase *this_ptr );
	void (*FreeMap)(iNgonBase *this_ptr );

	Bool (*Remove)(iNgonBase *this_ptr, LONG id, Bool force);
	Bool (*ToSelect)(iNgonBase *this_ptr, BaseSelect *pSelect, LONG mode);
	void (*GetCenter)(iNgonBase *this_ptr, LONG id, const CPolygon *vadr, const Vector *padr, Vector *ip, Vector *in);
	Bool (*RemapEdge)(iNgonBase *this_ptr, LONG oedge, LONG *nedges, LONG ncnt);
	Bool (*Create)(iNgonBase *this_ptr, ULONG *nedges, LONG ncnt);
	Bool (*RemapPolygon)(iNgonBase *this_ptr, LONG oply, LONG nply);
	Bool (*Copy)(iNgonBase *this_ptr, Pgon *src, Pgon *dst);

	Bool (*Validate)(iNgonBase *this_ptr, PolygonObject *op);
	Bool (*IsValidNgon)(iNgonBase *this_ptr, Pgon *pgon, const CPolygon *vadr);

	LONG (*BuildNgon)(iNgonBase *this_ptr, LONG *inner, LONG *outer, LONG icnt, LONG ocnt, const CPolygon *vadr, const Vector *padr);
	LONG (*BuildNgonFromPolys)(iNgonBase *this_ptr, LONG *polys, LONG *outer, LONG pcnt, LONG ocnt, const CPolygon *vadr, const Vector *padr);

	Bool (*Verify)(iNgonBase *this_ptr, const CPolygon *vadr, LONG vcnt, ULONG flags, Pgon *pgon);

	Pgon *(*AllocNgon)(iNgonBase *this_ptr, LONG edge_cnt);
	void (*FreeNgon)(iNgonBase *this_ptr, Pgon *&pgon);
	Bool (*SetNgon)(iNgonBase *this_ptr, LONG index, Pgon *src);
	Bool (*SetNgonE)(iNgonBase *this_ptr, LONG index, ULONG *edges, LONG edge_cnt);
};

// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

#endif	// _LIB_NGON_H_
