/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Mesh-related functions						*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Dec-19 23:04:10					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#ifndef _E3DMesh_h
#define _E3DMesh_h


#ifndef _E3DPolygon_h
#include <E3D/Polygon.h>
#endif


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

#define E3dVTXALLOC_INCREMENT		32

#ifdef USEOpenGL


// An array of this structure tells for each Mesh vertex,
// which Polygon VertexNodes use that Vertex
// Usually used for operations needing unique VertexNode identification, such as
// - DiscontinuityAngle-based normal computation
// - Global Illumination processing with per-Polygon VertexNode normals
// etc.
//
typedef struct
{
 E3dVertexNode**	VertexNodes;		// VertexNodes that refer to this Mesh Vertex
 E3dPolygon**		Polygons;		// Corresponding Polygons for the VertexNodes
 unsigned int		NumOfVertexNodes, NumOfVertexNodesAllocated;
} E3dVertexUsageList;



#define E3dMeshCore()\
 unsigned int		NumOfVertices;\
 E3dVertex*		Vertices;\
 E3dVertexUsageList*	VertexUsageList;	/* This might be kept temporarily to avoid repeated calls to E3d_MeshGetVertexUsageList() when processing PolyGroups of the same Mesh	*/\
 E3dUV*			UVs;			/* U and V parameters for the Vertices (some primitives, such as Sphere store it	*/\
 unsigned int		NumOfEdges;		/* For wireframe displaying*/\
 E3dEdge*		Edges;\
 unsigned int		NumOfPolyGroups;	/* Polygon groups				*/\
 E3dPolyGroup**		PolyGroups;\
\
 int			GLDisplayListShaded;		/* OpenGL display list Id		*/\
 int			GLDisplayListShaded2DTextured;	/* OpenGL display list Id		*/\
\
 E3dGLVertex*		GLArrayVertex;			/* OpenGL vertex array			*/\
 unsigned int		GLArraySizeVertex;		/* Size of above OpenGL vertex array	*/\
\
 unsigned int*		GLEdgeVertexIndexArray		/* For fast wireframe displaying	*/\

#else

#define E3dMeshCore()\
 unsigned int		NumOfVertices;\
 E3dVertex*		Vertices;\
 unsigned int		NumOfEdges;		/* For wireframe displaying*/\
 E3dEdge*		Edges;\
 unsigned int		NumOfClosedPolyLines;	/* For faster wireframe displaying (recommended for holes)*/\
 E3dPolyLine*		ClosedPolyLines;\
 unsigned int		NumOfPolyGroups;	/* Polygon groups*/\
 E3dPolyGroup**		PolyGroups
#endif // USEOpenGL


// Polygon Mesh
//
typedef struct
{
// E3dGeometry part
//
 E3dGeometryCore();

// E3dMesh part
//
 E3dMeshCore();
} E3dMesh;



// Skinned Mesh
//
typedef struct
{
// E3dGeometry part
//
 E3dGeometryCore();

// E3dMesh part
//
 E3dMeshCore();

// E3dSkinMesh part
//
 E3dSkinVertex*		SkinVertices;
 E3dModel*		Skeleton;
 int			NumBones;
 int			UpdateCnt;	// When a bone changes, it increases this and when we update the skin we reset this
} E3dSkinMesh;




// Subdivision methods
//
enum
{
 E3dMSH_NONE=0,
 E3dMSH_DOO_SABIN,
 E3dMSH_LOOP,
 E3dMSH_CATMULL_CLARK,
 E3dMSH_SQR3
};


// Subdivision surface
//
typedef struct
{
// E3dGeometry part
//
 E3dGeometryCore();

// E3dMesh part
//
 E3dMeshCore();

// E3dSubdivMesh part
//
// Control-Mesh data
//
 int			SubdivType;
 unsigned int		CMNumOfVertices;	// Control-mesh vertices
 E3dVertex*		CMVertices;
 unsigned int		CMNumOfEdges;		// For wireframe displaying
 E3dEdge*		CMEdges;
 unsigned int		CMNumOfPolyGroups;	// Polygon groups
 E3dPolyGroup**		CMPolyGroups;
} E3dSubdivMesh;




//--------------------------------
// Mesh.c
//--------------------------------
extern EBool			E3dNV_AGPInitialized;

extern void			E3d_VertexInit(E3dVertex* LVertex, double LX, double LY, double LZ);
extern void			E3d_VertexCopy(E3dVertex* LSrcVertex, E3dVertex* LDstVertex);

extern E3dVertex*		E3d_VerticesAllocate(unsigned int LNumOfVertices, EBool LInitialize);
extern E3dVertex*		E3d_VerticesReallocate(E3dVertex* LOldVertices, unsigned int LNumOfVertices, EBool LInitialize);
extern E3dSkinVertex*		E3d_SkinVerticesAllocate(unsigned int LNumOfVertices, EBool LInitialize);

extern void			E3d_VertexNormal(E3dVector* LNormal, E3dVertex* LPoint0,  E3dVertex* LPoint1, E3dVertex* LPoint2);
extern void			E3d_VertexTransformByMatrix(E3dMatrix LMatrix, E3dVertex* LVertex);



extern unsigned int		E3d_MeshFilterVertices(E3dMesh* LMesh, unsigned int LWhatToInclude);

extern unsigned int		E3d_MeshNumOfTaggedVertices(E3dMesh* LMesh);

extern EBool			E3d_MeshGetBoundingBox(E3dMesh* LMesh, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);
extern EBool			E3d_MeshGetTransformedBoundingBox(E3dMesh* LMesh, E3dMatrix LMatrix, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);
extern EBool			E3d_MeshGetPerspectiveProjectedBoundingBox(E3dMesh* LMesh, E3dMatrix LMatrix, E3d2DPosition* LBBMin, E3d2DPosition* LBBMax, E3dHPosition* LMaxProjectedXYAbsValPoint, unsigned int LWhatToInclude);

extern E3dVertex*		E3d_MeshAddVertex(E3dMesh* LMesh);

extern unsigned int		E3d_MeshEdgeGetPolygons(E3dMesh* LMesh, E3dEdge* LEdge, E3dPolygon*** LPolygonsPtr);
extern unsigned int		E3d_MeshVertexGetPolygons(E3dMesh* LMesh, int LVertexIndex, E3dPolygon*** LPolygonsPtr, E3dVertexNode*** LVertexNodesPtr);


extern E3dPolygon*		E3d_MeshAddPolygon(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);
extern E3dPolygon*		E3d_MeshAddPolygons(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, unsigned int LNumOfPolys);
extern E3dPolygon*		E3d_MeshAddAndInitPolygon(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, int LFlags, unsigned int LNumOfVertexNodes,...);
extern void			E3d_MeshRemovePolygon(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, E3dPolygon* LPolygon);

extern E3dTriangleStrip*	E3d_MeshAddTriangleStrip(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);
extern E3dTriangleStrip*	E3d_MeshAddTriangleStrips(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup,  unsigned int LNumOfStrips);
extern void			E3d_MeshFreeVertices(E3dMesh* LMesh);

extern E3dPolyGroup*		E3d_MeshAppendPolyGroup(E3dMesh* LMesh,  E3dPolyGroup* LPolyGroup);
extern E3dPolyGroup*		E3d_MeshAddPolyGroup(E3dMesh* LMesh);

extern void			E3d_MeshRemoveAndFreePolyGroup(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);
extern void			E3d_MeshRemovePolyGroup(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);

extern void			E3d_MeshDefault(E3dMesh* LMesh);
extern E3dMesh*			E3d_MeshAllocate(void);

extern void			E3d_MeshFreeRenderData(E3dMesh* LMesh);
extern void			E3d_MeshFree(E3dMesh* LMesh);



extern E3dMesh*			E3d_MeshClone(E3dMesh* LMesh, int LFlags);

extern void			E3d_MeshFreePolygons(E3dMesh* LMesh);

extern unsigned int		E3d_MeshPolyGroupDeleteSelection(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);


extern E3dVertexUsageList*	E3d_MeshGetVertexUsageList(E3dMesh* LMesh);
extern void			E3d_MeshFreeVertexUsageList(E3dMesh* LMesh);

extern E3d3DPosition*		E3d_MeshGetRayDisplacements(E3dMesh* LMesh, E3dCoordinate LDistance);


extern void			E3d_MeshPolyGroupRefreshPolygonNormals(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);
extern void			E3d_MeshPolyGroupRefreshNormals(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, int LPolyVertexNormalType, EBool LRefreshPolygonNormals);

extern void			E3d_MeshRefreshPolygonNormals(E3dMesh* LMesh);
extern void			E3d_MeshRefreshNormals(E3dMesh* LMesh, EBool LRefreshPolygonNormals);

extern void			E3d_MeshPolyGroupUpdateDrawingMaterial(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);

extern void			E3d_MeshCreateEdgesFromPolyData(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);


extern void			E3d_MeshRemapVertexIndices(E3dMesh* LMesh, int* LInToNewVertexIndexTable);

extern void			E3d_MeshPolyGroupUpdateForDisplay(E3dMesh* Lmesh, E3dPolyGroup* LPolyGroup, unsigned int LFlags);


extern int			E3d_MeshPolyGroupMap2DTexture(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, E3d2DTexture* L2DTexture);
extern int			E3d_MeshPolyGroupMap2DTexturesBB(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax);


// Skinning
//
extern E3dSkinMesh*		E3d_SkinMeshAllocate();
extern void			E3d_SkinMeshFree(E3dSkinMesh* LSkinMesh);
extern void			E3d_SkinMeshUpdateShape(E3dSkinMesh* LSkinMesh, EBool LDoNormals);
extern void			E3d_SkinMeshBindPose(E3dSkinMesh* LSkinMesh);




// This one is actually in Panel/3DPanel.h, because it uses the progress-bar
//
extern int			E3d_MeshSeparateSelectedPolyGroups(E3dMesh* LMesh, E3dModel* LAddToModel, int LFlags, EBool LKeepOriginalPolyGroups);




#ifdef USEOpenGL
extern void			E3d_MeshRefreshGLEdges(E3dMesh* LMesh, E3dMatrix LMatrix);
extern void			E3d_MeshRefreshGLPolyVertices(E3dMesh* LMesh, E3dMatrix LLocalToWorldMatrix, EBool LDoNormals);
extern void			E3d_MeshPolyGroupRefreshGLPolyVertices(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, E3dMatrix LLocalToWorldMatrix, EBool LDoNormals);

extern void			E3d_MeshRefreshGLNormals(E3dMesh* LMesh, E3dMatrix LMatrix);
extern void			E3d_MeshRemoveGLDisplayLists(E3dMesh* LMesh);
#endif // USEOpenGL


//--------------------------------
// PolygonAdv.c
//--------------------------------
extern int			E3d_MeshPolyGroupCreateRenderablePolygons(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup);
extern int			E3d_MeshCreateRenderablePolygons(E3dMesh* LMesh);
extern int			E3d_MeshCreateITriangles(E3dMesh* LMesh);


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

#endif	// _E3DMesh_h
