//================================================================
// E3D
//
// PolyGroups and Polygons
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Dec-08 01:07:08
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Polygon_h
#define _E3D_Polygon_h


#ifndef _EMath_h
#include <EMath.h>
#endif

#ifndef _E3D_Light_h
#include <E3D/Light.h>
#endif

#ifndef _E3D_Material_h
#include <E3D/Material.h>
#endif

#ifndef _E3D_Math_h
#include <E3D/Math.h>
#endif

#ifndef _E3D_VertexNode_h
#include <E3D/VertexNode.h>
#endif
#ifndef _E3D_VertexGeometry_h
#include <E3D/VertexGeometry.h>
#endif


#define E3dRAY_DIFFERENTIALS	1


// Vertex flags
//
#define	E3dVtxSELECTED          0x0001  // Vertex is selected for transforms
#define	E3dVtxACTIVE            0x0002  // Vertex is being moved etc.
#define	E3dVtxTMPSELECTED       0x0004  // Vertex is temporarily selected (e.g. when adding a new Polygon)
#define	E3dVtxVISIBLE           0x0008

#define E3dSTFlagsDEFAULT       E3dVtxVISIBLE

// Used by subdivision surfaces to annotate Vertices
//
#define	E3dVtxORIGINAL          0x0020
#define	E3dVtxON_ORIGINAL_EDGE  0x0040

// Temporary flags, used to mark Vertices for faster/more memory-efficient algorithms
//
#define	E3dVtxMARK0             0x0100
#define	E3dVtxMARK1             0x0200


#define	E3dVtxDEFAULT           E3dVtxVISIBLE  // Default flags for new Vertices
#define	E3dVtxSAVE_THESE_FLAGS	(E3dVtxSELECTED|E3dVtxTMPSELECTED|E3dVtxVISIBLE|E3dVtxORIGINAL|E3dVtxON_ORIGINAL_EDGE)

#define E3dPointSnapshotCore\
	EIndex  Index    /* Index in the original array */


typedef struct
{
	E3dPointSnapshotCore;
} E3dPointSnapshot;

// This structure is used for taking "snapshots" of Vertices for interactive
// transforming and for Undo/Redo of transforming and deleting Vertices
//
typedef struct
{
	E3dPointSnapshotCore;

	E3dVertexCore;
} E3dVertexSnapshot;



#define E3dPOLYALLOC_INCREMENT       32
#define E3dPOLYGROUPALLOC_INCREMENT   4


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


// Polygon flags
//
#define E3dPolygonSELECTED        0x0001
#define E3dPolygonSHARP           0x0010  // Only subdivide the Edges of this Polygon
#define E3dPolygonMARK0           0x0100  // Temporary marker
#define E3dPolygonMARK1           0x0200  // Temporary marker
#define E3dPolygonHAS_TRIANGLES		0x1000  // Used only by file I/O!

#define E3dPolygonFlagCOPY        E3dPolygonSHARP  // Only copy these Polygon flags when copying a Polygon

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


#ifndef E3dPolyGroup_DEF
#define E3dPolyGroup_DEF
typedef struct E3dPolyGroup_S   E3dPolyGroup;
typedef struct E3dPolyGroup_S*  E3dPolyGroupPtr;
EList_t(E3dPolyGroupPtr);
#endif

typedef struct E3dRPolyGroup_S  E3dRPolyGroup;

#define	E3dRTUVDEBUG      0

#define E3dRayTriMOLLER      1  // Moller-Trumbore
#define E3dRayTriORI_DET     2  // Orientation determinants, by akpeters
#define E3dRayTriBARYPLANES  3  // Charles Bloom's barycentric planes (needs precomputation)

// This is the most robust one. E3dRayTriBARYPLANES is not as watertight. There are spots on the globe LOD along edges where rays get through.
#define E3dRAY_TRIANGLE_INTERSECTOR  E3dRayTriMOLLER

//#define E3dRAY_TRIANGLE_INTERSECTOR  E3dRayTriBARYPLANES

//#define E3dRAY_TRIANGLE_INTERSECTOR  E3dRayTriORI_DET


//#if E3dRAY_TRIANGLE_INTERSECTOR == E3dRayTriBARYPLANES || E3dRAY_TRIANGLE_INTERSECTOR == E3dRayTriORI_DET
// Always store the triangle's plane because it's needed for fast sampling of area lights, even though ray-triangle intersecors line Moller-Trumbore don't use it.
#define E3dRTriangleHasPlane  1
//#endif


#if E3dRTriangleHasPlane
#define  E3dTriPlane  E3dCoord4  Plane;
#else   
#define  E3dTriPlane
#endif

#if E3dRAY_TRIANGLE_INTERSECTOR == E3dRayTriBARYPLANES
#define  E3dTriBaryPlanes  E3dCoord4  BaryPlane1, BaryPlane2
#else   
#define  E3dTriBaryPlanes
#endif

typedef union
{
	E3dCoord3      Position;
	E3dCoordinate  Position_4[4];
} E3dRVertex;

// Triangle type used by ray-tracing-based renderers
//
#define _E3dRTriangleICore\
	E3dRVertex  Vertices[3];\
	E3dCoord3   Edge1, Edge2;    /* Vectors V0->V1 and V0->V2 to speed up the ray/triangle intersection tests  */\
\
	E3dTriPlane\
	E3dTriBaryPlanes


#define _E3dRTriangleCore\
	_E3dRTriangleICore;\
\
	void*   Face;          /* The E3dPolygon or E3dFace that contains this RTriangle        */\
	EIndex  GlobalIndex    /* Used for looking up TriangleMailbox in Renderer->Accelerator  */


typedef struct
{
	_E3dRTriangleICore;
} E3dRTriangleICore;

typedef struct
{
	_E3dRTriangleCore;
} E3dRTriangleCore;

typedef struct
{
	E3dCoord3       Normal, Tangent;
	EcRGBAf32Color  Color;
	E3dST           STs[E3dMAX_NUM_OF_2DTEXTUREMAPPERS];
} E3dRTriangleVertexNode;


#define E3dPASS  1
#define E3dFAIL  2


     // Planes, used by ray-differential-based texture filtering
#if E3dRAY_DIFFERENTIALS
#define E3dRTriangleRayDiffPlanes\
	E3dCoord4       L0, L1, L2;
#else
#define E3dRTriangleRayDiffPlanes
#endif	// E3dRAY_DIFFERENTIALS

#define _E3dRTriangleBase\
	_E3dRTriangleCore;\
\
	E3dRTriangleRayDiffPlanes\
\
	E3dCoord3       Normal;         /* Triangle normal */\
\
	E3dRPolyGroup*  RPolyGroup;\
\
	uint32_t        PreppedForRayTracing : 2,  /* 0: Not tested, E3dPASS, E3dFAIL */\
	                FaceSelected : 1,\
	                HasTextureTransparency : 1

/*                NormalPrincipalAxis : 2; */


typedef struct
{
	_E3dRTriangleBase;

	E3dRTriangleVertexNode  RVertexNodes[3];
} E3dRTriangle;
EList_t(E3dRTriangle);

typedef struct
{
	_E3dRTriangleBase;
} E3dRTriangleBase;


typedef struct
{
	EIndex         LastRayNumber,    // These fields are to make sure we don't ray-test a triangle more than once, from separate voxels
	               LastRayHitVoxelIndex;
	E3dCoord2      HitUV;
	E3dCoordinate  HitT;
} E3dRTriangleMailbox;



// PolyGroup Flags
//
#define E3dUSE_VERTEX_NORMALS        0x001
#define E3dUSE_MESH_VERTEX_NORMALS   0x002

// PolyGroup UptodateFlags
//
#define E3dPOLYGON_NORMALS_UPTODATE  0x001
#define E3dVERTEX_NORMALS_UPTODATE   0x002
#define E3dNORMALS_UPTODATE          (E3dPOLYGON_NORMALS_UPTODATE|E3dVERTEX_NORMALS_UPTODATE)


#define E3dPolyGroupCore\
	EObjectCore(EObject);\
	E3dShaderRendererBinding**  ShaderRendererBindings;  /* For each RendererClass                                                      */\
\
/* Textura Mappers. This must match the number of ST sets on the PolyGroup. On an RPolyGroup, this contains both the PolyGroup and the Mesh TextureMappers   */\
	EList_s(, E3dTextureMapperPtr, TextureMappers);\
\
/* VertexNode Components. This EResource array specifies the layout of each VertexNode in this PolyGroup. It's completely flexible, */\
/* including the support for custom elements.  */\
	EResourceList               VertexAttributes;\
\
	E3dVertexNodeSize           VertexNodeSize;          /* In bytes                                                                    */\
\
	uint16_t                    Flags;                   /* E3dUSE_VERTEX_NORMALS, E3dUSE_MESH_VERTEX_NORMALS, E3dVERTEX_NORMALS_UPTODATE;  */\
	EBool                       DoubleSided;             /* Show back-facing Polygons (if the Mesh is not a solid, it may be necessary  */\
	uint16_t                    UptodateFlags            /* E3dPOLYGON_NORMALS_UPTODATE, E3dVERTEX_NORMALS_UPTODATE */


typedef struct
{
	E3dPolyGroupCore;
} E3dPolyGroupBase;


typedef struct	E3dPolyGroupComponent_S        E3dPolyGroupComponent;
typedef struct	E3dPolyGroupComponentClass_S   E3dPolyGroupComponentClass;
typedef struct	E3dPolyGroupComponentClass_S*  E3dPolyGroupComponentClassPtr;
EList_t(E3dPolyGroupComponentClassPtr);

typedef struct
{
	EIndex  TextureMappingChangeCount;
} E3dPGChange;


typedef struct
{
	E3dBBoxGPUData  BBox;
} E3dRPolyGroupGPUData;

//
// RenderPolyGroup, used for Renderers / accelerators, collision detection, Boolean operations, etc.
//
struct E3dRPolyGroup_S
{
	E3dPolyGroupCore;

	E3dMaterial*   Material;
	E3dPolyGroup*  PolyGroup;
	EObjectID      PolyGroupID;
	EObjectID      ModelID;

// For each Texture on the Material, this array points to the texcoords in E3dRTriangle's STs array. Note that E3dRTriangle's STs array already has STs
// collected from both the Mesh and the PolyGroup. 
	EList_s(, E3dTextureMapperIndex, STIndices);

	E3dAreaLight*  AreaLight;                     // Used if the RPolyGroup is a light emitter

// Custom shapes (implicit surfaces, SDFs etc.) are also represented as RPolyGroups with possibly no RTRiangles, but with a non-NULL RenderCustomShapeComponent
	E3dPolyGroupComponent*  RenderCustomShapeComponent;

// In bytes.
	EIndex             RTriangleSize;

	EList_s(, E3dRTriangle, TrianglesNew);       // Note that RTriangles have a variable size (depending on the size of their VertexNodes, as indicated by RVertexNodeSize)

// The size of VertexNodes in the E3dRTriangles of this E3dRPolyGroup. This is separate from VertexNodeSize in E3dPolyGroupCore, until we make E3dRTriangle VertexNodes flexible-size
	E3dVertexNodeSize  RVertexNodeSize;

	E3dBBox        BBox;                    // Bounding box (viewer-, or world-aligned)

	EIndex         PolyGroupIndexInMesh;    // Indicates which PolyGroup in the Mesh this RPolyGroup came from (if it came from a Face, this field is 0)

	E3dMatrix      PointLocalToWorldMatrix, VectorLocalToWorldMatrix;
	E3dMatrix      PointWorldToLocalMatrix, VectorWorldToLocalMatrix;

	uint32_t       CastsShadows : 1, ReceivesShadows : 1, Inverted : 1,

// Already transformed by PointLocalToWorldMatrix/VectorLocalToWorldMatrix. Custom shapes like implicit surfaces, SDFs are not pre-transformed
	               Transformed : 1;

// Offsets of fields in the RTriangles' VertexNodes (unlike Polygon VertexNodes, they are fixed-size structs for now, but we treat them as flexible during transition to a flex-size)
	E3dVertexNodeSize  NormalOffsetNew, TangentOffsetNew, ColorOffsetNew, ST0OffsetNew;

// Intelligent updates
//
// This ID allows us to tell if the original PolyGroup's drawing Material was switched to another Material.
// (freed pointers might be reused for new allocations, plus we need to transmit this through the network for cloud-rendering, etc. And, it's one less pointer reference...).
// 0 means no Material.
//
	EID            MaterialID;

	EIndex         AreaLightChangeCount;

	E3dPGChange    PGChange;                // Intelligent update data (compared to PGChange in E3dPolyGroup)

	E3dRPolyGroupGPUData  GPUData;
};



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


typedef uint16_t  E3dPolygonFlags;


typedef struct
{
	EIndex*  EdgeIndices;  // Original Edges. Counts and contour structure match original Polygon's VertexNodes array.
} E3dEPolygon;

#ifndef E3dPolygon_DEF
#define E3dPolygon_DEF  1
typedef struct E3dPolygon_S   E3dPolygon;
EListA_t(E3dPolygon);
typedef struct E3dPolygon_S*  E3dPolygonPtr;
EListA_t(E3dPolygonPtr);
#endif

struct E3dPolygon_S
{
	E3dCoord3           Normal;
	E3dCoord3           Center;                 // For displaying the normal and the center of the Polygon
	E3dVertexNodeIndex	NumOfVertices;          // # of Vertices (excluding the contour separator '-1's)
	E3dVertexNodeIndex	NumOfVertexNodes;       // # of VertexNodes (including the contour separator '-1's)
	E3dVertexNodeIndex	NumOfExteriorVertices;  // # of vertices in the exterior contour of the polygon (if the polygon has no holes, same as NumOfVertices)
	E3dVertexNode*      VertexNodes;            // Variable-size VertexNode array

	EList(, E3dITriangle, ITriangles);

	E3dPolygonFlags     Flags;                  // E3dPolygonSELECTED, etc.
};

typedef struct E3dTriangleStrip
{
	EIndex          NumOfVertices;  // # of Vertices
	E3dVertexNode*  VertexNodes;    // Variable-size VertexNodes
	uint16_t        Flags;
} E3dTriangleStrip;
EListA_t(E3dTriangleStrip);


typedef int   (*E3dPolyGroupComponentFunc)(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponent* PInfo);

typedef int   (*E3dPolyGroupComponentCopyFunc)(const E3dPolyGroup* PSrcPolyGroup, const E3dPolyGroupComponent* PSrcInfo,
               E3dPolyGroup* PDstPolyGroup, E3dPolyGroupComponent* PDstInfo);

typedef void  (*E3dPolyGroupComponentChangeFunc)(E3dModel* PModel, E3dObject* PObject, E3dPolyGroup* PPolyGroup, E3dPolyGroupComponent* PInfo, const EChangeFlags PChangeFlags);
typedef int   (*E3dPolyGroupComponentGUIFunc)(E3dObject* PObject, E3dPolyGroup* PPolyGroup, E3dPolyGroupComponent* PInfo, void*, void*, int);

struct E3dPolyGroupComponentClass_S
{
	ECoreClassCore(E3dPolyGroupComponent);

	E3dPolyGroupComponentFunc        Init;
	E3dPolyGroupComponentCopyFunc    Copy;
	E3dPolyGroupComponentFunc        Free;

	E3dPolyGroupComponentChangeFunc  Change;
	E3dPolyGroupComponentGUIFunc     GUI;

// Flags of EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc. E.g. some components are generated internally and are not supposed to be saved to files.
// This may be overwritten per instance. This field is used for creating the GUI etc. when there's no instance available.
// If the EComponentSET is 0, it means this field was not initialized when registering the class, so it will be defaulted by ..ClassRegister()
//
	uint16_t                InternalFlags;
};


#define E3dPolyGroupComponentCore\
	EObjectCore(E3dPolyGroupComponent);\
/* Or-ed flags of EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc. E.g. some components are generated internally and are not supposed to be saved to files etc.  */\
/* These flags are set by code, in the class' constructor, etc. and are not saved into files.  */\
	uint16_t     InternalFlags;\
/* Or-ed flags of EComponentANIMATABLE, EComponentRESPOND_TO_INPUT_CHANGE. These flags may be user-settable (depending on the class) and are saved to files, etc. */\
	uint16_t     Flags;\
	EIndex  AttributeChangeCount, InputChangeCount


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


// E3dPolyGroup VertexNormalType. Describes the way the normals were created.
//
enum
{
	E3dNormalPROCESS = 1,    // Creation process generated vertex normals (e.g. Extrude)
	E3dNormalRESERVED,
	E3dNormalFROM_SMOOTHING_ANGLE
};

enum
{
	E3dIndexArrayNO_INDICES = 0,

// TriangleVertexIndices points to Mesh Vertices. Used when all VertexAttributes match at PolyGroup VertexNodes for each Polygon that share that Vertex
	E3dIndexArrayMESH_VERTICES,

// TriangleVertexIndices points to PolyGroup VertexNodess. Even when the above case is not true, VertexNodes can be still shared between triangles on 4+ Vertex Polygons
	E3dIndexArrayPOLYGROUP_VERTICES,
};

typedef struct
{
	unsigned int*  Indices;unsigned int  Count;
} E3dGLIndexList;


// GPU vertexArrays etc. for a PolyGroup
//
typedef struct
{
	EListA_s(, uint8_t,      VertexArray);               // GPU vertex array
	unsigned int             VertexArrayStride;          // VertexNode size (stride) for GLArray, in bytes

// How VertexArray should be accessed. 0: don't use indices. Just draw e.g. with glDrawArray(). E3dIndexArrayPOLYGROUP_VERTICES: use the TriangleVertexIndices field.
// E3dIndexArrayMESH_VERTICES: use the MeshVertexTriangleVertexIndices field.
	uint8_t                  VertexArrayIndexingMode;

	EListA_s(, EResource,    VertexAttributes);          // Custom Vertex attributes available to GPU shaders (collected both from the Mesh and the PolyGroup)

	unsigned int*            GLArrayEdgeVertexIndices;
	unsigned int*            GLArrayVisibleEdgeVertexIndices;EIndex  GLArrayVisibleEdgesCount;

	EIndex                   NTriangles;                          // Number of triangles in the vertex array (if VertexArrayIndexingMode is 0, this is the only way to know)

// If SmoothingAngle == 180 or VertexNormalType == AVERAGE and all other VertexNodeAttributes match between triangles
// that share a Vertex, we use indexed arrays (so GL transforms each Mesh Vertex within a PolyGroup only once).
// In this case, GLArray contains these uniqie Vertices (with normals etc.) and GLArrayTriangleVertexIndices is used with glDrawElements() etc. (vs. glDrawArrays())
// This is also used for Mesh Vertex attribute visualization.
//
	EListA_s(, EUnsignedInt, TriangleVertexIndices);
	uint8_t                  TriangleVertexIndicesType;           // 0: don't use TriangleVertexIndices (e.g. because it's not up-to-date), E3dIndexArrayPOLYGROUP_VERTICES

// E3dIndexArrayMESH_VERTICES-mode index array is separate because may also be used for visualizing Mesh VertexAttributes,
// so it needs to exist at the same time as TriangleVertexIndices
	EListA_s(, EUnsignedInt, MeshVertexTriangleVertexIndices);

// For visualizing VertexAttributes
	EListA_s(, E3dVertexAttributeVisualization, VertexAttributeVisualization);
} E3dPolyGroupGPUData;


struct E3dPolyGroup_S
{
	E3dPolyGroupCore;

	EObjectID                ID;
	E3dSchemObject           SchemObject;

	E3dVertexGeometry*       VertexGeometry;            // Mesh, Face etc. that this PolyGroup belongs to
	E3dMaterial*             Material;
	EIndex                   LockCnt;                   // E.g.: the PolyGroup is being modified...

// This array has a TextureMapper pointer for each Texture in the Material. Each of those TextureMappers may be in the TextureMappers array of either the PolyGroup of the Mesh.
	EList_s(, E3dTextureMapperPtr,  TextureMapperRefs);

// When there are no Textures on the Material, show the Mapper(s) from the VertexGeometry (Mesh/Face etc.) in the UI instead of from the PolyGroup
	EBool                           ShowMapperFromGeometry;

	EList(, E3dPolyGroupComponent*, Components);

	EListA_s(, E3dPolygon, Polygons);
	EListA_s(, E3dTriangleStrip,  TriangleStrips);

	char                          VertexNormalType;         // 0, E3dNormalPROCESS or E3dNormalFROM_SMOOTHING_ANGLE
	float                         SmoothingAngle;           // Below this angle, two neighboring normals will be averaged

	EList_s(, EIndex, Edges);                          // Edge indices (from the Mesh) for wireframe rendering


// Intelligent updates (esp. for ray-tracers)
//
	EIndex                   LightChangeCount;        // Just like a ray-counter. Used for RTGI
	E3dPGChange              PGChange;

	EIndex                   NumOfVertices;           // Total number of Vertices (VertexNodes with non- '-1' VertexIDs in this PolyGroup. Updated in E3dMesh_CreateRenderablePolygons

	EBool                    CastsShadows, ReceivesShadows;
	EBool                    Selected;
	EBool                    Visible;

	uint16_t                 TexturesMapped : 1,      // Texture-mapping is up-to-date
	                         Highlighted : 1;
	E3dDisplayFlags          DisplayFlags;            // If not 0, always draw in this mode (e.g. wireframe, even in solid modes. Useful for editing objects inside of this one.)

	uint16_t                 EdgeFlags;               // OR-ed flags: E3dACTIVE_EDGES, E3dSELECTED_EDGES, E3dHARD_EDGES (same as on Mesh)

	EIndex                   TmpIndex0, TmpIndex1;    // Temporary user-data

	float                    VectorDrawScale;         // For drawing normals, tangents etc.
	float                    OverlayOpacity;          // For drawing VertexAttributes as colors

	E3dPolyGroupGPUData      GPUData;
};


// Voxel for uniform-grid spatial subdivision
//
typedef struct
{
	EList(, E3dRTriangle*, Triangles);
	int  NeighbourStep;
} E3dVoxel;




//----------------------------------------------------------------
// Macros
//----------------------------------------------------------------

#define E3dM_PolygonFreeContents(pPolygon) do\
{\
	EFreeChk((pPolygon)->VertexNodes);\
	EFreeChk((pPolygon)->ITriangles);\
} while(0)


#define E_StructByIndex(pType, pArray, pIndex, pStride)  (pType*)(((char*)pArray) + pStride * pIndex)


//================================================
// Initialize a Polygon
//
// Argument
//  PPolygon   Pointer to the Polygon
//
// Description
//  Initializes a Polygon structure
//================================================
static inline void E3dPolygon_Init(E3dPolygon* PPolygon)
{
	memset(PPolygon, 0, sizeof(E3dPolygon));

/*
	PPolygon->NumOfVertices = 0;
	PPolygon->NumOfVertexNodes = 0;
	PPolygon->NumOfExteriorVertices = 0;
	PPolygon->VertexNodes = NULL;
	EList_Init(PPolygon->ITriangles);
	PPolygon->Flags = 0;
*/
}


//================================================
// Compute the normal vector for a Polygon
// Supports concave n-gons.
//================================================
static inline void E3dPolygon_ComputeNormal(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,
 const E3dCoord3* PVertexPositions, const EIndex PNVertices, const EPointerInt PVertexStride,  E3dCoord3* PNormal)
{
	EIndex  LVN = PPolygon->NumOfExteriorVertices;if(LVN > 2)
	{
		const E3dVertexNode*  LVertexNodes = PPolygon->VertexNodes;
		E3dCoord3             L0, L1, L2, LNormal;

		const E3dVertexNode*	LVertexNode = LVertexNodes;
		if(LVN == 3)
		{
			{
				const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
				L0 = *LVertexPosition;
				EStruct_Inc(LVertexNode, PVertexNodeSize);
			}
			{
				const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
				L1 = *LVertexPosition;
				EStruct_Inc(LVertexNode, PVertexNodeSize);
			}
			{
				const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
				L2 = *LVertexPosition;
			}

			LNormal.X = -((L2.Y - L1.Y) * (L2.Z - L0.Z) - (L2.Z - L1.Z) * (L2.Y - L0.Y));
			LNormal.Y =   (L2.X - L1.X) * (L2.Z - L0.Z) - (L2.Z - L1.Z) * (L2.X - L0.X);
			LNormal.Z = -((L2.X - L1.X) * (L2.Y - L0.Y) - (L2.Y - L1.Y) * (L2.X - L0.X));
		}
		else
		{
//----------------------------------------------------------------------------------------------------------------
// If the Polygon has more than 3 vertices, it can be concave, so to make sure we don't pick 3 vertices for
// the normal calculation that create an inverted Polygon. We have to run trough all the triangles of 3
// connected vertices and sum the normals of them, because even if a Polygon is "strongly" concave, there are
// always more triangles with the right orientation than ones with the wrong one.
//----------------------------------------------------------------------------------------------------------------
			LNormal.X = LNormal.Y = LNormal.Z = 0.0;

			LVN--;
			EIndex  LVC = 0;for(;LVC < LVN;LVC++)
			{
				{
					const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
					L0 = *LVertexPosition;
					EStruct_Inc(LVertexNode, PVertexNodeSize);
				}

				{
					const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
					L1 = *LVertexPosition;
				}

				LNormal.X -= (L0.Z + L1.Z) * (L1.Y - L0.Y);
				LNormal.Y += (L0.Z + L1.Z) * (L1.X - L0.X);
				LNormal.Z -= (L0.Y + L1.Y) * (L1.X - L0.X);
			}

// The last Vertex pair is the last one and the 0th one
//
			{
				const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNode->VertexID, PVertexStride);
				L0 = *LVertexPosition;
			}

			{
				const E3dCoord3*  LVertexPosition = E_StructByIndex(const E3dCoord3, PVertexPositions, LVertexNodes->VertexID, PVertexStride);
				L1 = *LVertexPosition;
			}

			LNormal.X -= (L0.Z + L1.Z) * (L1.Y - L0.Y);
			LNormal.Y += (L0.Z + L1.Z) * (L1.X - L0.X);
			LNormal.Z -= (L0.Y + L1.Y) * (L1.X - L0.X);
		}

		E3d_Normalize3_v(LNormal);*PNormal = LNormal;
	}
	else
	{
		PNormal->X = PNormal->Y = PNormal->Z = (E3dCoordinate)0.0;
	}
}

#undef _Normalize3_v


#define E3d_RTriangleArea(pRTriangle, pArea)\
{\
	E3dCoord3  lCross;E_Cross3_vvv(pRTriangle->Edge1, pRTriangle->Edge2, lCross);\
\
	pArea = E3d_Sqrt(lCross.X * lCross.X + lCross.Y * lCross.Y + lCross.Z * lCross.Z) * 0.5;\
}


//----------------------------------------------------------------
// Surface construction macros
//----------------------------------------------------------------


//========================================================================
// Build Polygons for toroid topology (e.g. revolve)
// The shape may be open or closed in either the U and V directions
//========================================================================
#define E3d_ToroidBuildPolygons(pQuadFunc,  pVertexStartOffset, pPathSegmentCount, pPathClosed,\
 pProfilePointCount, pProfileSegmentCount, pProfileClosed, pProfileSegmentVisibleFlags) do\
{\
	EIndex         lColumnA = pVertexStartOffset, lNextColumnA = pVertexStartOffset + pProfilePointCount;\
	E3dCoordinate  lU = 0.0;\
	const EIndex   lProfileN = pProfileSegmentCount - 1;\
	const EBool    lPathClosed = pPathClosed;(void)lPathClosed;\
	const EIndex   lProfilePointCount = pProfilePointCount;(void)lProfilePointCount;\
	const EIndex   lPathLastSegment = pPathSegmentCount - 1;(void)lPathLastSegment;\
	const EBool    lProfileClosed = pProfileClosed;(void)lProfileClosed;\
	const EIndex   lProfileLastSegment = pProfileSegmentCount - 1;(void)lProfileLastSegment;\
	if(pPathClosed)\
	{\
		EIndex  lUI = 0;const EIndex  lUN = pPathSegmentCount - 1;for(;lUI < lUN;lUI++, lColumnA += pProfilePointCount, lNextColumnA += pProfilePointCount, lU += LUStep)\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			if(lProfileClosed)\
			{\
				EIndex  lVI = 0;for(;lVI < lProfileN;lVI++)\
				{\
					const EIndex  lNextRow = lVI + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lNextRow, lColumnA + lNextRow,  lUI, lVI);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA, lColumnA,  lUI, lVI);\
			}\
			else\
			{\
				EIndex  lVI = 0;for(;lVI < pProfileSegmentCount;lVI++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lVI + 1, lColumnA + lVI + 1,  lUI, lVI);\
				}\
			}\
		}\
\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			lNextColumnA = pVertexStartOffset;\
			if(lProfileClosed)\
			{\
				EIndex  lVI = 0;for(;lVI < lProfileN;lVI++)\
				{\
					const EIndex  lNextRow = lVI + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lNextRow, lColumnA + lNextRow,  lUI, lVI);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA, lColumnA,  lUI, lVI);\
			}\
			else\
			{\
				EIndex  lVI = 0;for(;lVI < pProfileSegmentCount;lVI++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lVI + 1, lColumnA + lVI + 1,  lUI, lVI);\
				}\
			}\
		}\
	}\
	else\
	{\
		EIndex  lUI = 0;for(;lUI < pPathSegmentCount;lUI++, lColumnA += pProfilePointCount, lNextColumnA += pProfilePointCount, lU += LUStep)\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			if(lProfileClosed)\
			{\
				EIndex  lVI = 0;for(;lVI < lProfileN;lVI++)\
				{\
					const EIndex  lNextRow = lVI + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lNextRow, lColumnA + lNextRow,  lUI, lVI);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA, lColumnA,  lUI, lVI);\
			}\
			else\
			{\
if(0)\
{\
	printf("%s() %s:%d  lProfileClosed %lld  pProfileSegmentCount %lld  lProfileN %lld\n",  __FUNCTION__, __FILE__, __LINE__,\
	 (long long)lProfileClosed, (long long)pProfileSegmentCount, (long long)lProfileN);\
	fflush(stdout);\
}\
				EIndex  lVI = 0;for(;lVI < pProfileSegmentCount;lVI++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVI]) pQuadFunc(lColumnA + lVI, lNextColumnA + lVI, lNextColumnA + lVI + 1, lColumnA + lVI + 1,  lUI, lVI);\
				}\
			}\
		}\
	}\
} while(0)




typedef struct
{
	EIndex  VertexIndex, EdgeIndex;
} E3dEdgeEnd;
EListA_t(E3dEdgeEnd);

#define E3dVertexLinkCore\
/* Mesh Vertex indices of the other ends of Edges that are coincident at this Vertex  */\
	EListA_s(, E3dEdgeEnd, EdgeEnds)

// For creating Edge lists
// It specifies, to which other Vertices a Vertex is connected via Edges
//
typedef struct
{
	E3dVertexLinkCore;
} E3dVertexLinkNew;


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


//========================================
// Correct hole VertexNode counts
//========================================
static inline void E3d_PolygonCorrectHoleVertexCounts(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize)
{
	E3dVertexNode*  LContourStartVertexNode = NULL;
	EIndex          LVertexNodesInContour = 0;
//printf("%s() %s:%d %s<%s",  __FUNCTION__, __FILE__, __LINE__,  ECodeCyan, ECodeNormal);fflush(stdout);
	EIndex  LVC = 0;const EIndex  LVN = PPolygon->NumOfVertexNodes;E3dVertexNode*  LVertexNode = PPolygon->VertexNodes;for(;LVC < LVN;LVC++, EStruct_Inc(LVertexNode, PVertexNodeSize))
	{
		if(LVertexNode->VertexID < 0 || LVC == LVN - 1)
		{
//if(LVertexNode->VertexID < 0) printf("%s><%d%s ", ECodeCyan, (int)LVertexNode->VertexID, ECodeNormal);
//else
//{
//	if(LVertexNodesInContour) printf(" ");
//	printf("%d", (int)LVertexNode->VertexID);
//	printf("%s>%s", ECodeCyan, ECodeNormal);fflush(stdout);
//}

			if(LVC == LVN - 1) LVertexNodesInContour++;

			if(LContourStartVertexNode) LContourStartVertexNode->VertexID = -LVertexNodesInContour;
			LContourStartVertexNode = LVertexNode;

			LVertexNodesInContour = 0;
		}
		else
		{
//if(LVertexNodesInContour) printf(" ");
//printf("%d", (int)LVertexNode->VertexID);
			LVertexNodesInContour++;
		}
	}
//printf("\n");fflush(stdout);
}


static inline void E3d_RTriangleGetBBox(const E3dRTriangle* PTriangle, E3dBBox* PBBox)
{
  PBBox->Min.X = E_MinOf3(PTriangle->Vertices[0].Position.X, PTriangle->Vertices[1].Position.X, PTriangle->Vertices[2].Position.X);
  PBBox->Min.Y = E_MinOf3(PTriangle->Vertices[0].Position.Y, PTriangle->Vertices[1].Position.Y, PTriangle->Vertices[2].Position.Y);
  PBBox->Min.Z = E_MinOf3(PTriangle->Vertices[0].Position.Z, PTriangle->Vertices[1].Position.Z, PTriangle->Vertices[2].Position.Z);
  PBBox->Max.X = E_MaxOf3(PTriangle->Vertices[0].Position.X, PTriangle->Vertices[1].Position.X, PTriangle->Vertices[2].Position.X);
  PBBox->Max.Y = E_MaxOf3(PTriangle->Vertices[0].Position.Y, PTriangle->Vertices[1].Position.Y, PTriangle->Vertices[2].Position.Y);
  PBBox->Max.Z = E_MaxOf3(PTriangle->Vertices[0].Position.Z, PTriangle->Vertices[1].Position.Z, PTriangle->Vertices[2].Position.Z);
}


static inline void E3dBBox_2b(const E3dBBox* PSrc, E3dBBox* PResult)
{
  PResult->Min.X = E_Min(PResult->Min.X, PSrc->Min.X);
  PResult->Min.Y = E_Min(PResult->Min.Y, PSrc->Min.Y);
  PResult->Min.Z = E_Min(PResult->Min.Z, PSrc->Min.Z);
  PResult->Max.X = E_Max(PResult->Max.X, PSrc->Max.X);
  PResult->Max.Y = E_Max(PResult->Max.Y, PSrc->Max.Y);
  PResult->Max.Z = E_Max(PResult->Max.Z, PSrc->Max.Z);
}


static inline void E3d_MapTexture(const E3dRTriangle* PRTriangle,  const E3dMaterial* PMaterial, const EIndex PTextureIndex,
 const E3dCoord3* LPosition, const E3dCoord3* PNormal, const E3dCoord2* PUV,  E3dSTWithDiff* PST)
{
	const E3dRPolyGroup*  LRPolyGroup = PRTriangle->RPolyGroup;
	const E3dCoordinate   LU = PUV->X, LV = PUV->Y, LNUV = 1.0 - LU - LV;

	{
		const E3dTextureMapperIndex   LTextureMapperIndex = LRPolyGroup->STIndices.Items[PTextureIndex];
		const E3dTextureMapper*       LTextureMapper = LRPolyGroup->TextureMappers.Items[LTextureMapperIndex];
		const E3dTextureMapperClass*  LTextureMapperClass = LTextureMapper->Class;

		if(LTextureMapperClass->MapPoint)
		{
			LTextureMapperClass->MapPoint(LTextureMapper,  LPosition, PNormal,  (E3dST*)PST);
_E3dCheckST_p(PST);
		}
		else
		{
			const E3dVertexNodeSize  LRVertexNodeSize = LRPolyGroup->RVertexNodeSize;
			const E3dVertexNodeSize  LST0Offset = LRPolyGroup->ST0OffsetNew;
			const E3dST*  LST0 = (const E3dST*)((uint8_t*)PRTriangle->RVertexNodes + LRVertexNodeSize * 0 + LST0Offset) + LTextureMapperIndex;
			const E3dST*  LST1 = (const E3dST*)((uint8_t*)PRTriangle->RVertexNodes + LRVertexNodeSize * 1 + LST0Offset) + LTextureMapperIndex;
			const E3dST*  LST2 = (const E3dST*)((uint8_t*)PRTriangle->RVertexNodes + LRVertexNodeSize * 2 + LST0Offset) + LTextureMapperIndex;

_E3dCheckST_p(LST0);
_E3dCheckST_p(LST1);
_E3dCheckST_p(LST2);

			PST->S = LNUV * LST0->S + LST1->S * LU + LST2->S * LV;
			PST->T = LNUV * LST0->T + LST1->T * LU + LST2->T * LV;
		}

// Indicate that no MIP-mapping should be used
//
		PST->dS = PST->dT = 0.0;
	}
}



//--------------------------------
// E3D/Accelerator.c
//--------------------------------
extern EIndex  _E3dPolyGroup_TriangulateForRendering(const E3dPolyGroup* PPolyGroup, E3dRPolyGroup* PRPolyGroup,
 const EBool PUpdateVertexPositions, const E3dVertex* PTransformedVertices,  const E3dCoordinate* PNormalMatrix,
 const EBool PInverted, EIndex PGlobalTriangleIndex, const EBool PPrepForRayTracing,  E3dRTriangle** PRTrianglesPtr);

//--------------------------------
// E3D/Polygon.c
//--------------------------------
extern void   E3dAttributes_Interpolate1D(const EResourceList* PAttributes,  const void* PA, const void* PB, const E3dCoordinate PU,  void* PD);
extern void   E3dAttributes_InterpolateCentroid(const EResourceList* PAttributes,  const void* PSrc, const EIndex PStructSize, const EIndex PSrcCount,  void* PD);
extern EBool  E3dAttributes_CompareValues(const EResourceList* PAttributes, const void* P0, const void* P1, const E3dCoordinate PEpsilon);

static inline void E3dVertex_Copy(const E3dVertex* PSrcVertex, const E3dVertexSize PSrcVertexSize, const EResourceList* PSrcAttributes,
 E3dVertex* PDstVertex, const E3dVertexSize PDstVertexSize, const EResourceList* PDstAttributes)
{
	const E3dVertexSize  LVertexCoreSize = E3dVertexCore_Size();
	if(PDstVertexSize == PSrcVertexSize && PSrcVertexSize == LVertexCoreSize)
	{
		memcpy(PDstVertex, PSrcVertex, PSrcVertexSize);
	}
	else
	{
		const E3dVertexSize  LDstVertexSizeAboveCore = PDstVertexSize - LVertexCoreSize;
		{
			PDstVertex->Position = PSrcVertex->Position;
			PDstVertex->Flags = PSrcVertex->Flags;
			if(LDstVertexSizeAboveCore > 0) memset((uint8_t*)PDstVertex + LVertexCoreSize, 0, LDstVertexSizeAboveCore);
		}

// We may need to deep-copy some members
//
#if ERELEASE_BUILD
printf("%s() %s:%d  %sIMPLEMENT ME%s\n",  __FUNCTION__, __FILE__, __LINE__,  ECodeYellow, ECodeNormal);fflush(stdout);
#endif
	}
}

extern void    E3dVertices_FreeContents(E3dVertex* PVertices, const E3dVertexSize PVertexSize, const EIndex PVN, const EResourceList* PAttributes);
extern void    E3dVertices_Free(E3dVertex* PVertices, const EIndex PVN, const E3dVertexSize PVertexSize,  const EResourceList* PAttributes);

extern void    E3dVertices_Copy(const E3dVertex* PSrcVertices, const E3dVertexSize PSrcVertexSize, const EResourceList* PSrcAttributes,
 E3dVertex* PDstVertices, const E3dVertexSize PDstVertexSize, const EResourceList* PDstAttributes,  const EIndex PN);

extern E3dCoordinate  E3d_2DPolygonNormal(const E3dCoord2* PVertices, const EIndex PVertNum);

extern void            E3dPolygons_Init(E3dPolygon* PPolygons, const EIndex PCount);
extern void            E3dPolygon_FreeContents(E3dPolygon* PPolygon);

extern E3dVertexNode*  E3dPolygon_AddVertexNode(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const EIndex PVIdx, EIndex PWhere);

extern E3dPolygon*     E3dPolygons_New(const EIndex PCount);

extern void            E3dPolygon_Invert(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const int PNormalOffse);

extern void            E3dPolygon_RemapAndCreateInverse(const E3dPolygon* PSPolygon, E3dPolygon* PDPolygon, const E3dVertexNodeSize PVertexNodeSize,
                        const int PNormalOffset, const EIndex* PVertexIndexLUT, const E3dCoord3* PMirrorAxis);

extern EBool           E3dPolygon_HasVertexIndex(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, EIndex PVertexIndex);
extern EBool           E3dPolygon_HasEdge(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dEdge* PEdge);

extern E3dVertexNode*  E3dPolygon_InsertVertexNode(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, EIndex PVertexIndex,
                        EIndex PStartNodeIndex, EIndex PEndNodeIndex);

extern E3dTriangleStrip*  E3dTriangleStrips_New(const EIndex PNumOfStrips);
extern E3dVertexNode*     E3dTriangleStrip_VertexNodesNew(E3dTriangleStrip* PTriangleStrip, const E3dVertexNodeSize PVertexNodeSize, const EIndex PNumOfVertices);

extern E3dPolygon*        E3dPolygon_AddOneToArray(E3dPolygon* PPolygons, const EIndex PNumOfPolys, EIndex* PNumOfPolysAllocatedPtr);
extern E3dPolygon*        E3dPolygon_AddNToArray(E3dPolygon* PPolygons, const EIndex PNumOfNewPolys, EIndex PNumOfPolys, EIndex* PNumOfPolysAllocatedPtr);

extern EBool           E3dPolygon_InitAsTriangle(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const EIndex PVtx0, const EIndex PVtx1, const EIndex PVtx2);
extern EBool           E3dPolygon_SetAsTriangle(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const EIndex PVtx0, const EIndex PVtx1, EIndex const PVtx2);

extern int             E3dPolygon_InitAsQuad(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,
                        const EIndex PVtx0, const EIndex PVtx1, const EIndex PVtx2, const EIndex PVtx3);

extern EBool           E3dPolygon_InitVa(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const EIndex PNumOfVertexNodes, ...);
extern EBool           E3dPolygon_SetVa(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, EIndex PNumOfVertexNodes, ...);


extern EBool           E3dPolygon_TrGetPlane(E3dPolygon* PPolygon,  E3dVertex* PVertices, const E3dVertexSize PVertexSize,  const E3dMatrix PMatrix, E3dPlane* PPlane);

extern void            E3dPolygon_UpdateNormal(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,
                        const E3dVertex* PVertices, const EIndex PNVertices, const E3dVertexSize PVertexSize);


//--------------------------------
// E3D/PolyGroup.c
//--------------------------------
extern const int     E3dPolyGroup_DefaultVertexAttributes_Count;

extern EObjectClass  E3dPolyGroupBase_class[];
extern EObjectClass  E3dPolyGroup_class[];
extern EObjectClass  E3dRPolyGroup_class[];
extern const E3dPolyGroupComponentClass  E3dPolyGroupComponent_class[];

EList_s(extern, E3dPolyGroupComponentClassPtr, E3dPolyGroupComponent_Classes);

extern EResource     E3d_DefaultVertexNodeAttributes[];



extern int           E3dPolyGroupComponent_Remove(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponent* PInfo);
extern int           E3dPolyGroupComponent_RemoveAll(E3dPolyGroup* PPolyGroup);
extern E3dPolyGroupComponent*  E3dPolyGroupComponent_Add(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponentClass* PClass);
extern E3dPolyGroupComponent*  E3dPolyGroupComponent_ByClass(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponentClass* PClass, const EBool PAdd);
extern E3dPolyGroupComponent*  E3dPolyGroupComponent_BySubClass(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponentClass* PClass);

extern int           E3dPolyGroup_CallChangeFuns(E3dObject* PObject, E3dPolyGroup* PPolyGroup, const unsigned int PChangeFlags);
extern int           E3dPolyGroup_CallFreeFuncs(E3dPolyGroup* PPolyGroup);

extern E3dPolyGroupComponentClass*  E3dPolyGroupComponent_ClassByName(const char* PName);
extern E3dPolyGroupComponentClass*  E3dPolyGroupComponent_ClassRegister(E3dPolyGroupComponentClass* PClassTemplate);
extern void           E3dPolyGroupComponent_ClassDeactivate(E3dPolyGroupComponentClass* PClass);
extern void           E3dPolyGroupComponent_ClassesFree(void);

extern void           E3dRPolyGroup_FreeContents(E3dRPolyGroup* RPolyGroup);

extern void           E3dPolyGroup_CopyCore(const E3dPolyGroup* PSrcPolyGroup, E3dPolyGroup* PDstPolyGroup);

extern E3dPolygon*    E3dPolyGroup_AddPolygon(E3dPolyGroup* PPolyGroup);
extern E3dPolygon*    E3dPolyGroup_AddPolygons(E3dPolyGroup* PPolyGroup, const EIndex PNumOfNewPolys);
extern void           E3dPolyGroup_FreePolygons(E3dPolyGroup* PPolyGroup);

extern void           E3dPolyGroup_FreeTriangleStrips(E3dPolyGroup* PPolyGroup);
extern void           E3dPolyGroup_FreeContents(E3dPolyGroup* PPolyGroup);
extern E3dPolyGroup*  E3dPolyGroup_Copy(const E3dPolyGroup* PSrcPolyGroup, E3dPolyGroup* PDstPolyGroup,  const E3dMatrix PVectorMatrix,  const uint16_t PFlags,  E3dScene* PScene);

extern int            E3dPolyGroup_Invert(E3dPolyGroup* PPolyGroup);

extern void           E3dPolyGroup_PrintInfo(E3dPolyGroup* PPolyGroup, const EIndex PPGI,  const E3dVertex* PVertices, const EIndex PNVertices, const EIndex PVertexSize,
                       EIndex* PSelectedPolyNumP,  const int PIndent);


extern EBool          E3dPolyGroup_HasSelectedPolygons(const E3dPolyGroup* PPolyGroup);
extern EIndex         E3dPolyGroup_NumOfSelectedPolygons(const E3dPolyGroup* PPolyGroup);
extern EIndex         E3dPolyGroup_GetMarkedPolygonIndices(const E3dPolyGroup* PPolyGroup, const E3dPolygonFlags PFlag, EIndex** PIndicesP);

extern EIndex         E3dPolyGroup_DeletePolygon(E3dPolyGroup* PPolyGroup, E3dPolygon* PPolygon);
extern EIndex         E3dPolyGroup_DeletePolygonsByIndex(E3dPolyGroup* PPolyGroup, const EIndex* PPolygonIndices, const EIndex PNPolygonsToDelete);

extern int            E3d_PolyGroupFreeAllInfo(E3dPolyGroup* PPolyGroup);
extern E3dPolyGroupComponent*  E3d_PolyGroupAddInfo(E3dPolyGroup* PPolyGroup, E3dPolyGroupComponentClass* PClass);


extern EIndex         E3dPolyGroup_AppendPolygon(E3dPolyGroup* PPolyGroup, E3dPolygon* PPolygon);

extern EIndex*        E3dPolyGroup_CreateTriangleVtxToPolyVtxTable(E3dPolyGroup* PPolyGroup, const EIndex PNumOfRTriangles);
extern EIndex         E3dPolyGroup_CreateRenderablePolygons(E3dPolyGroup* PPolyGroup,  const E3dVertex* PVertices, const EIndex PNVertices, const E3dVertexSize PVertexSize,
                       const EBool PDoConvex,  const EIndex PNThreads);

extern void           E3dPolygons_Triangulate(const E3dPolygon* PSrcPolygons, const EIndex PPN, const E3dVertexNodeSize PVertexNodeSize,
                       const EBool PDoOnlySelectedPolys, E3dPolygon* PDstPolygons);

extern void           E3dPolyGroup_RemapVertexIndices(E3dPolyGroup* PPolyGroup, const EIndex* PInToNewVertexIndexTable);
extern void           E3dPolyGroup_OffsetVertexIndices(E3dPolyGroup* PPolyGroup, const EIndex POffset);
extern EIndex         E3dPolyGroup_CountTriangles(const E3dPolyGroup* PPolyGroup, EIndex* PTriangleStartIndices);

extern int            E3dPolyGroup_VertexAttributeAdd(E3dPolyGroup* PPolyGroup,  const char* PName, const char* PSemantic, const int PIndex,  const EResource* PCustomAttr);
extern int            E3dPolyGroup_VertexAttributeDel(E3dPolyGroup* PPolyGroup,  const char* PSemantic, const EIndex PIndex);
extern int            E3dPolyGroup_VertexAttributeDelByIndex(E3dPolyGroup* PPolyGroup,  const EIndex PIndex);

extern void           E3dPolyGroup_VertexAttributesSet(E3dPolyGroup* PPolyGroup, EResourceList* PVertexAttributes);

extern void           E3dPolyGroup_VertexAttributesSetFromFlags(E3dPolyGroup* PPolyGroup, const E3dVertexAttributeFlags PVertexAttributeFlags);

extern int            E3dPolyGroup_STXtoUV(E3dPolyGroup* LPolyGroup, const int LTextureIndex);

extern void           E3dPolyGroups_MatchVertexAttributes(E3dPolyGroup* PPolyGroup1, E3dPolyGroup* PPolyGroup2);
extern uint8_t        E3dPolyGroup_IsIndexable(const E3dPolyGroup* PPolyGroup);


extern E3dCoordinate  E3dRPolyGroup_Area(const E3dRPolyGroup* PRPolyGroup);

extern void           E3d_FlattenPolygonInit(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const E3dVertexSize PVertexSize,
                       E3dCoordinate* PCtrXPtr, E3dCoordinate* PCtrYPtr, E3dCoordinate* PCtrZPtr);

extern void           E3dPolygon_Copy(const E3dPolygon* PSrcPolygon, E3dPolygon* PDstPolygon, const E3dVertexNodeSize PVertexNodeSize);

extern void           E3dPolygon_Print(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize);

extern void           E3dPolyGroup_TextureMappersCopy(const E3dPolyGroup* PSrcPolyGroup, E3dPolyGroup* PDstPolyGroup);
extern void           E3dPolyGroup_TextureMappersCopyToFreehand(const E3dPolyGroup* PSrcPolyGroup, E3dPolyGroup* PDstPolyGroup);


//--------------------------------
// PolygonAdv.c
//--------------------------------
extern int			      E3d_2DPolygonTriangulate(E3dCoord2* PVertices, E3dTTriangle* PTris, const int* PContours);

extern E3dCoord2*     E3dPolygon_Flatten(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const E3dVertexSize PVertexSize);

extern E3dCoord2*     E3dPolygon_FlattenScaled(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const E3dVertexSize PVertexSize,
                       const E3dCoordinate PScale);

extern EIndex         E3dPolygon_Triangulate(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,
                       const E3dVertex* PVertices, const EIndex PNVertices, const E3dVertexSize PVertexSize,  const EBool PDoConvex);

extern EIndex         E3dPolygon_TriangulateM(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const EIndex PNVertices,
                       const E3dVertexSize PVertexSize,  uint8_t** PTmpBufferP, EIndex* PTmpBufferSizeP,  const EBool PDoConvex);

extern EIndex         E3dPolygon_TriangulateForRendering(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const E3dVertexSize PVertexSize,
                       E3dVertex* PTransformedVertices,  const EIndex PRTriangleSize, E3dRTriangle** PRTrianglesRet, EIndex PNumOfRTriangles, EIndex* PMaxNumOfRTriangles);

extern int            E3dPolygon_TestTriangulate(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize,  const E3dVertex* PVertices, const E3dVertexSize PVertexSize,
                       const EBool PDoConvex);

extern EIndex         E3d_GridBuildEdges(const EIndex PUCells, const EIndex PVCells,  const EIndex PRowA,  E3dEdge** PEdgesP, EIndex* PNumOfEdgesP,  const EBool PTriangles);
extern E3dPolygon*    E3d_GridBuildPolygons(E3dPolyGroup* PPolyGroup, E3dPolygon* PPolygons, const EIndex PUSubdiv, const EIndex PVSubdiv, EIndex PRowA,
                       E3dEdge** PEdgesP, EIndex* PNumOfEdgesP,  const EBool PTriangles, const EBool PInverse);


extern E3dVertexNode*  E3d_PolygonContourNextVertexNode(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNode* PVertexNode);
extern E3dVertexNode*  E3d_PolygonContourNextVertexNodeI(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNodeIndex PVC);
extern int             E3d_PolygonContourNextVertexNodeIndex(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNodeIndex PVC);
extern E3dVertexNode*  E3d_PolygonContourPrevVertexNodeI(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNodeIndex PVC);
extern int             E3d_PolygonContourPrevVertexNodeIndex(const E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNodeIndex PVC);

//--------------------------------
// VertexNode.c
//--------------------------------
extern int               E3dPolyGroup_VertexAttributeOffset(const E3dPolyGroup* PPolyGroup, const char* PSemantic, const int PIndex);
extern const EResource*  E3dPolyGroup_VertexAttributeResource(const E3dPolyGroup* PPolyGroup, const char* PSemantic, const int PIndex);



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

#endif	// _E3D_Polygon_h
