/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Polygon and PolyGroup related functions header file			*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Jan-03 23:42:32					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#ifndef _E3DPolygon_h
#define _E3DPolygon_h


#ifndef _E3DSpline_h
#include <E3D/Spline.h>
#endif


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif





// Vertex flags
//
#define	E3dVTXF_TAGGED		0x01
#define	E3dVTXF_ACTIVE		0x02		// Vertex is being moved etc.
#define	E3dVTXF_SELECTED	0x04

#define	E3dVTXF_PASSED		0x10		// Temporary flag used by E3d_MeshFilterVertices() to indicate that the Vertex passed the filter
#define E3dVTXF_ALL		0x1F

#ifdef USEOpenGL
typedef struct
{
 E3dGLCoordinate	X, Y, Z;
} E3dGLVertex;



typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 unsigned char		R, G, B, A;
} E3dGLRGBA8Vertex;

typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 unsigned char		R, G, B, A;
 GLfloat		S, T;
} E3dGLRGBA8STVertex;


typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 unsigned char		R, G, B, A;
} E3dGLRGBAf32Vertex;

typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 unsigned char		R, G, B, A;
 GLfloat		S, T;
} E3dGLRGBAf32STVertex;


typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 GLfloat		NX, NY, NZ;
} E3dGLShadedVertex;

typedef struct
{
 E3dGLCoordinate	X, Y, Z;
 GLfloat		NX, NY, NZ;
 GLfloat		S, T;
} E3dGLShadedSTVertex;
#endif	// USEOpenGL



typedef struct
{
 E3dCoordinate	X, Y, Z;
 unsigned int	Flags;
} E3dVertex;


// This structure is used for taking "snapshots" of Vertices for interactive
// transforming and for Undo/Redo of transforming and deleting Vertices
//
typedef struct
{
 E3dCoordinate	X, Y, Z;
 unsigned int	Flags;
 unsigned int	Index;		// Index in the original array
} E3dSnapshotVertex;


// For subdivision surfaces
//
typedef struct
{
 E3dCoordinate	X, Y, Z;
 unsigned int	Flags;
 E3dWeight	Curvature;
} E3dSubdivVertex;



// SkinVertex flags
//
#define	E3dSVTXF_BONESOK	1
#define E3dSVTXF_ALL		0x1

typedef struct
{
 E3dCoordinate	X, Y, Z;		// Original position of the Vertex
 unsigned int	NumOfBones;		// Number of bones (joints) that affect this SkinVertex
 E3dModel**	Bones;			// Bones (joints) that affect this SkinVertex
 E3dWeight*	Weights;		// Weight values for the bones affecting this SkinVertex
 unsigned int	Flags;
} E3dSkinVertex;









#define E3dPOLYALLOC_INCREMENT		32
#define E3dPOLYGROUPALLOC_INCREMENT	4

#define		MANYVERTICES	7



// Where to add Vertex node special values
//
#define E3dVNODE_END	-1


typedef struct
{
 int		VertexID;	// Mesh Vertex index. Negative numbers separate the contours. E.g. -3 means that there's a hole coming up with 3 Vertices
 E3dVector	Normal;		// Normal vector
 float		S, T;		// Texture coordinates

#ifdef USEOpenGL
 E3dGLCoordinate	GLVertex[3];
 E3dGLCoordinate	GLNormal[3];
 E3dGLCoordinate	GLST[2];
#endif // USEOpenGL
} E3dVertexNode;


#define E3dMAT_GLOBALMAT	0

#define E3dPolyFlagSELECTED	1
#define E3dPolyFlagALL		1



// Triangle type used by the tesselators
//
typedef struct
{
 int	A, B, C;
} E3dTTriangle;


typedef struct E3dPolyGroup_S	E3dPolyGroup;


// Triangle type used by renderers
//
typedef struct
{
 E3dCoordinate	V0[3], V1[3], V2[3];
 E3dCoordinate	Edge1[3], Edge2[3];		// Vectors V0->V1 and V0->V2 to speed up the ray/triangle intersection tests
 E3dVector	Normal;				// Triangle normal
 E3dVector	Normal0, Normal1, Normal2;	// Vertex normals
 E3dCoordinate	S[3], T[3];			// Texture coordinates for the vertices
 int		LastRayNumber;			// To make sure we don't ray-test a triangle more than once, from separate voxels
 void*		Face;				// The E3dPolygon or E3dFace that contains this RTriangle
 E3dPolyGroup*	PolyGroup;
} E3dRTriangle;





// Triangle with self-contained VertexNodes
//
typedef struct E3dTriangle
{
 E3dVertexNode		VertexNodes[3];
} E3dTriangle;


// Triangle with indexed VertexNodes
//
typedef struct E3dITriangle
{
 E3dVertexNode*		VertexNodes[3];
} E3dITriangle;


typedef struct E3dRPolygon
{
 unsigned int		NumOfVertices;
 E3dVertexNode**	VertexNodes;
} E3dRPolygon;


typedef struct E3dPolygon
{
 E3dVector		Normal;
#ifdef USEOpenGL
 E3dGLType		GLNormal[3];
 E3dGLType		GLCenter[3];		// To display the normal
#endif // USEOpenGL
 unsigned int		NumOfVertices;		// # of Vertices (excluding the contour separator '-1's)
 unsigned int		NumOfVertexNodes;	// # of VertexNodes (including the contour separator '-1's)
 unsigned int		NumOfExteriorVertices;	// # of vertices in the exterior contour of the polygon (if the polygon has no holes, same as NumOfVertices)
 E3dVertexNode*		VertexNodes;
 E3dITriangle*		ITriangles;
 unsigned int		NumOfTriangles;
 unsigned short		Flags;			// Polygon selected etc.
} E3dPolygon;


typedef struct E3dTriangleStrip
{
 unsigned int		NumOfVertices;		// # of Vertices
 E3dVertexNode*		VertexNodes;
 unsigned short		Flags;
} E3dTriangleStrip;



// The way the normals were created
//
enum
{
 E3dNormalNONE=0,
 E3dNormalPROCESS,
 E3dNormalAVERAGED,
 E3dNormalFROM_DISCONTINUITY_ANGLE
};

// PolyGroup flags
//
#define E3dUSE_VERTEX_NORMALS		0x001
#define E3dPOLY_NORMALS_UPTODATE	0x002
#define E3dVERTEX_NORMALS_UPTODATE	0x004
#define E3dNORMALS_UPTODATE		(E3dPOLY_NORMAL_UPTODATE|E3dVERTEX_NORMALS_UPTODATE)
#define E3dACTIVE_EDGES			0x100
#define E3dSELECTED_EDGES		0x200


typedef struct	E3dPolyGroupInfo_S	E3dPolyGroupInfo;

typedef int			(*E3dPolyGroupProc)(E3dModel*, E3dGeometry*, E3dPolyGroup*, E3dPolyGroupInfo*);
typedef E3dPolyGroupInfo*	(*E3dPolyGroupEditProc)(E3dModel*, E3dGeometry*, E3dPolyGroup*, E3dPolyGroupInfo*, int);

typedef struct
{
 char*			Name;
 unsigned int		StructSize;
 E3dPolyGroupEditProc	EditProc;
 E3dPolyGroupProc	DestroyProc;
 EResource*		Resources;	// Resource list
} E3dPolyGroupClass;


#define E3dPolyGroupInfoCore()\
 E3dPolyGroupClass*	Class


// General PolyGroupInfo structure (these are the first fields in all PolyGroupInfo structures)
//
struct E3dPolyGroupInfo_S
{
 E3dPolyGroupInfoCore();
};



struct E3dPolyGroup_S
{
 unsigned int		RefCnt;			// Reference count
 unsigned int		LockCnt;		// E.g.: the PolyGroup is being modified...

 char*			Name;

 unsigned int		NumOfInfoRecords;
 E3dPolyGroupInfo**	Info;

 E3dMaterial*		Material;		// The E3dPolyGroup's Material
 E3dMaterial*		DrawingMaterial;	// The Material we use for drawing 'Material' corrected with inheriting etc.


 unsigned int		NumOfTextureMappers;	// For each 2DTexture in the Material and the PolyGroup, there is a Mapper
 E3d2DTextureMapper*	TextureMappers;
 unsigned int		NumOf2DTextures;	// In addition to the 2DTextures in the Material, a PolyGroup can have its own 2DTextures...
 E3d2DTexture**		Textures2D;		// ...that way we can share Materials without sharing their 2DTextures

 unsigned int		NumOfPolygons;		// Number of Polygons in the group
 E3dPolygon*		Polygons;		// Array of Polygons

 unsigned int		NumOfTriangleStrips;
 E3dTriangleStrip*	TriangleStrips;

 int			VertexNormalType;	// E3dPolyGroup is FACETED (no per-vertex normals on polygons), polygon vertex normals
						// were computed in the Geometry creation PROCESS, are ALL AVERAGED from the
						// polygons using a given vertex or computed from the DISCONTINUITY ANGLE
 unsigned int		Flags;			// See above
 float			DiscontinuityAngle;	// Discontinuity angle (for averaged normals)

 unsigned int		NumOfEdges;		// For wireframe displaying
 E3dEdge*		Edges;


#ifdef USEOpenGL
// E3dGLMaterial*		GLMaterial;		// OpenGL Material

// AGP arrays
//
 E3dGLRGBA8Vertex*	GLArrayVertexRGBA;		// OpenGL vertex array with (unique [XYZ, RGB])
 unsigned int		GLArraySizeVertexRGBA;		// Size of above OpenGL vertex array

 E3dGLRGBA8STVertex*	GLArrayVertexRGBAST;		// OpenGL vertex array with (unique [XYZ, RGB, ST])
 unsigned int		GLArraySizeVertexRGBAST;	// Size of above OpenGL vertex array

 E3dGLShadedVertex*	GLArrayVertexNormal;		// OpenGL vertex array with (unique [XYZ, Normal])
 unsigned int		GLArraySizeVertexNormal;	// Size of above OpenGL vertex array

 E3dGLShadedSTVertex*	GLArrayVertexNormalST;		// OpenGL vertex array with (unique [XYZ, Normal, ST])
 unsigned int		GLArraySizeVertexNormalST;	// Size of above OpenGL vertex array

 unsigned int*		GLEdgeVertexIndexArray;
 unsigned int*		GLTriangleVertexIndexArray;
 unsigned int		GLTriangleCount;
#endif // USEOpenGL


 int			LightChangeCount;		// Just like a ray-counter

// For rendering
//
 E3dRTriangle*		Triangles;
 unsigned int		NumOfTriangles;
 E3d3DPosition		BBoxMin, BBoxMax;		// Bounding box (viewer-, or world-aligned)
 unsigned int		PolygonsBase, TrianglesBase;

 unsigned int		NumOfVertices;			// Total number of vertices (VertexNodes with non- '-1' VertexIDs in this PolyGroup. Updated in E3d_MeshCreateRenderablePolygons
 EcRGBAfColor*		VertexColors;


 EBool			CastsShadows, ReceivesShadows;
 EBool			TexturesMapped;			// Texture mapping is up-to-date
 EBool			Selected;
 EBool			DoubleSided;			// Show backfacing Polygons (if the Mesh is not a solid, it may be necessary
 EBool			Visible;
};




// Voxel for uniform-grid spatial subdivision
//
typedef struct
{
 E3dRTriangle**		Triangles;
 unsigned int		NumOfTriangles;
 unsigned int		Padding0;			// This makes E3d_RayIntersectVoxels() faster...
} E3dVoxel;




//----------------------------------------------------------------
// Function prototypes
//----------------------------------------------------------------
#define E3dM_PolygonFree(MPolygon)\
 {\
  if(MPolygon->VertexNodes) EFree(LPolygon->VertexNodes);\
  if(MPolygon->ITriangles) EFree(MPolygon->ITriangles);\
 }


#define MAX_VLINKNUM	73
// For creating edge lists
//
typedef struct
{
 unsigned int	LinkedToNum;
 unsigned int	Vertices[MAX_VLINKNUM];
} E3dVertexLink;



extern void			E3d_PolygonDefault(E3dPolygon* LPolygon);

extern E3dVertexNode*		E3d_PolygonVertexNodesAllocate(E3dPolygon* LPolygon, unsigned int LNumOfVertexNodes);
extern E3dVertexNode**		E3d_RPolygonVertexNodesAllocate(E3dRPolygon* LPolygon, unsigned int LNumOfVertexNodes);
extern E3dVertexNode*		E3d_PolygonAddVertexNode(E3dPolygon* LPolygon, int LVIdx, int LWhere);
extern E3dPolygon*		E3d_PolygonsAllocate(unsigned int LNumOfPolys);

extern E3dPolygon*		E3d_PolyGroupAddPolygon(E3dPolyGroup* LPolyGroup);

extern E3dPolygon*		E3d_PolygonAddOneToArray(E3dPolygon* LPolygons, unsigned int LNumOfPolys, unsigned int* LNumOfPolysAllocatedPtr);
extern E3dPolygon*		E3d_PolygonAddNToArray(E3dPolygon* LPolygons, unsigned int LNumOfNewPolys, unsigned int LNumOfPolys, unsigned int* LNumOfPolysAllocatedPtr);

extern E3dRPolygon*		E3d_RPolygonsAllocate(unsigned int LNumOfPolys);

extern EBool			E3d_PolygonInit(E3dPolygon* LPolygon, unsigned int LNumOfVertexNodes, ...);
extern EBool			E3d_PolygonInitAsTriangle(E3dPolygon* LPolygon, int LVtx0, int LVtx1, int LVtx2);
extern EBool			E3d_PolygonSet(E3dPolygon* LPolygon, unsigned int LNumOfVertexNodes, ...);
extern EBool			E3d_PolygonSetAsTriangle(E3dPolygon* LPolygon, int LVtx0, int LVtx1, int LVtx2);

extern void			E3d_PolygonRefreshNormal(E3dVertex* LVertexArray, E3dPolygon* LPolygon);
extern void			E3d_PolygonFlattenVertexNormals(E3dPolygon* LPolygon);

extern void			E3d_PolygonInvert(E3dPolygon* LPolygon);

extern void			E3d_PolygonCreateTriangles(E3dVertex* LVertices, E3dPolygon* LPolygon, EBool LDoConvex);
extern EBool			E3d_PolygonHasVertexIndex(E3dPolygon* LPolygon, int LVertexIndex);
extern EBool			E3d_PolygonHasEdge(E3dPolygon* LPolygon, E3dEdge* LEdge);




extern E3dTriangleStrip*	E3d_TriangleStripsAllocate(unsigned int LNumOfStrips);
extern E3dVertexNode*		E3d_TriangleStripVertexNodeAllocate(E3dTriangleStrip* LTriangleStrip, int LNumOfVertices);



extern int			E3d_PolyGroupInfoRemove(E3dPolyGroup* LPolyGroup, E3dPolyGroupInfo* LInfo);
extern int			E3d_PolyGroupInfoRemoveAll(E3dPolyGroup* LPolyGroup);
extern E3dPolyGroupInfo*	E3d_PolyGroupInfoAdd(E3dPolyGroup* LPolyGroup, E3dPolyGroupClass* LClass);
extern E3dPolyGroupInfo*	E3d_PolyGroupInfoByClass(E3dPolyGroup* LPolyGroup, E3dPolyGroupClass* LClass);

extern E3dPolyGroupClass*	E3d_PolyGroupClassFindByName(char* LName);
extern E3dPolyGroupClass*	E3d_PolyGroupClassRegister(E3dPolyGroupClass* LClassTemplate);
extern void			E3d_PolyGroupClassRemove(E3dPolyGroupClass* LClass);
extern void			E3d_PolyGroupClassDeactivate(E3dPolyGroupClass* LClass);



extern E3dPolyGroup*		E3d_PolyGroupAllocate();
extern void			E3d_PolyGroupFree(E3dPolyGroup* LPolyGroup);
extern E3dPolyGroup*		E3d_PolyGroupClone(E3dPolyGroup* LOrigPolyGroup, int LFlags);

extern int			E3d_PolyGroupNumOfSelectedPolygons(E3dPolyGroup* LPolyGroup);
extern int			E3d_PolyGroupDeleteSelectedPolygons(E3dPolyGroup* LPolyGroup);

extern int			E3d_PolyGroupFreeAllInfo(E3dPolyGroup* LPolyGroup);
extern E3dPolyGroupInfo*	E3d_PolyGroupAddInfo(E3dPolyGroup* LPolyGroup, E3dPolyGroupClass* LClass);


extern void			E3d_PolyGroupFreePolygons(E3dPolyGroup* LPolyGroup);
extern void			E3d_PolyGroupFreeTriangleStrips(E3dPolyGroup* LPolyGroup);
extern void			E3d_PolyGroupFreeRenderTriangles(E3dPolyGroup* LPolyGroup);

extern int			E3d_PolyGroupAppendPolygon(E3dPolyGroup* LPolyGroup, E3dPolygon* LPolygon);

extern int			E3d_PolyGroupCreateRenderablePolygons(E3dVertex* LVertices, E3dPolyGroup* LPolyGroup);

extern void			E3d_PolyGroupCreateEdgesFromPolyData(E3dPolyGroup* LPolyGroup, E3dVertexLink* LVertexLinks);


extern void			E3d_PolyGroupRemapVertexIndices(E3dPolyGroup* LPolyGroup, int* LInToNewVertexIndexTable);
extern void			E3d_PolyGroupOffsetVertexIndices(E3dPolyGroup* LPolyGroup, int LOffset);
extern int			E3d_PolyGroupTriangulateForRendering(E3dPolyGroup* LPolyGroup, E3dVertex* LVertices, E3dVertex* LNewVertices, E3dRTriangle** LRTrianglesPtr);



//--------------------------------
// PolygonAdv.c
//--------------------------------

extern int			E3d_Triangulate2DPolygon(E3d2DPosition* LVertices, E3dTTriangle* LTris, int* LContourData);
extern int			E3d_TriangulatePolygon(E3dVertex* LVertices, E3dPolygon* LPolygon, EBool LDoConvex);
extern int			E3d_TriangulatePolygonForRendering(E3dVertex* LVertices, E3dVertex* LTransformedVertices, E3dPolygon* LPolygon, E3dRTriangle** LRTrianglesRet, unsigned int LNumOfRTriangles, unsigned int* LMaxNumOfRTriangles);
extern int			E3d_TestTriangulatePolygon(E3dVertex* LVertices, E3dPolygon* LPolygon, EBool LDoConvex);
extern E3dPolygon*		E3d_GridBuildPolygons(E3dPolygon* LPolygons, int LUSubdiv, int LVSubdiv, unsigned int LRowA, EBool LTriangles);




//--------------------------------
// Macro functions
//--------------------------------
#define E3dM_NextVertexNode(mVertexNodes, mVertexNode, mVC, mVN)	(mVC<(mVN-1)) ? (mVertexNode+1) : (mVertexNodes)
#define E3dM_PrevVertexNode(mVertexNodes, mVertexNode, mVC, mVN)	(mVC>0) ? (mVertexNode-1) : (mVertexNodes+mVN-1)



#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration which encloses file.
#endif

#endif	// _E3DPolygon_h
