//================================================================
// 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)

#define E3dRAY_TRIANGLE_INTERSECTOR  E3dRayTriMOLLER  // 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  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

typedef struct
{
	_E3dRTriangleCore;

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

	E3dCoord3       Normal;         // Triangle normal

	E3dRTriangleVertexNode  RVertexNodes[3];

	E3dRPolyGroup*  RPolyGroup;
	uint16_t        PreppedForRayTracing : 2,  // 0: Not tested, E3dPASS, E3dFAIL
	                FaceSelected : 1;
//                NormalPrincipalAxis : 2;
} E3dRTriangle;


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                                                      */\
	EList_s(, E3dTextureMapperPtr, TextureMappers);      /* 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                      */\
\
	EResourceList               VertexAttributes;        /* VertexNode Components. This EResource array specifies the layout of each VertexNode in this PolyGroup. It's completely flexible, including the support for custom elements.  */\
	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;

	EList_s(, E3dTextureMapperIndex, STIndices);           // 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. 

	E3dAreaLight*           AreaLight;                     // Used if the RPolyGroup is a light emitter
	E3dPolyGroupComponent*  RenderCustomShapeComponent;    // Custom shapes (implicit surfaces, SDFs etc.) are also represented as RPolyGroups with possibly no RTRiangles, but with a non-NULL RenderCustomShapeComponent

	E3dVertexNodeSize  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

	EList(, E3dRTriangle, Triangles);

	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,
	               Transformed : 1;         // Already transformed by PointLocalToWorldMatrix/VectorLocalToWorldMatrix. Custom shapes like implicit surfaces, SDFs are not pre-transformed

	E3dVertexNodeSize  NormalOffsetNew, TangentOffsetNew, ColorOffsetNew, ST0OffsetNew;  // Offset of a field 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)

// 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,
	E3dIndexArrayMESH_VERTICES,         // TriangleVertexIndices points to Mesh Vertices. Used when all VertexAttributes match at PolyGroup VertexNodes for each Polygon that share that Vertex
	E3dIndexArrayPOLYGROUP_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
};

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
	uint8_t                  VertexArrayIndexingMode;    // 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.

	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

	EListA_s(, EUnsignedInt, MeshVertexTriangleVertexIndices);    // 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

// 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...

	EList_s(, E3dTextureMapperPtr,  TextureMapperRefs);      // 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.
	EBool                           ShowMapperFromGeometry;  // 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 PolyGrou

	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  lUC = 0;const EIndex  lUN = pPathSegmentCount - 1;for(;lUC < lUN;lUC++, lColumnA += pProfilePointCount, lNextColumnA += pProfilePointCount, lU += LUStep)\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			if(lProfileClosed)\
			{\
				EIndex  lVC = 0;for(;lVC < lProfileN;lVC++)\
				{\
					const EIndex  lNextRow = lVC + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lNextRow, lColumnA + lNextRow);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA, lColumnA);\
			}\
			else\
			{\
				EIndex  lVC = 0;for(;lVC < pProfileSegmentCount;lVC++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lVC + 1, lColumnA + lVC + 1);\
				}\
			}\
		}\
\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			lNextColumnA = pVertexStartOffset;\
			if(lProfileClosed)\
			{\
				EIndex  lVC = 0;for(;lVC < lProfileN;lVC++)\
				{\
					const EIndex  lNextRow = lVC + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lNextRow, lColumnA + lNextRow);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA, lColumnA);\
			}\
			else\
			{\
				EIndex  lVC = 0;for(;lVC < pProfileSegmentCount;lVC++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lVC + 1, lColumnA + lVC + 1);\
				}\
			}\
		}\
	}\
	else\
	{\
		EIndex  lUC = 0;for(;lUC < pPathSegmentCount;lUC++, lColumnA += pProfilePointCount, lNextColumnA += pProfilePointCount, lU += LUStep)\
		{\
/*			const E3dCoordinate  lV = 1.0;*/\
			if(lProfileClosed)\
			{\
				EIndex  lVC = 0;for(;lVC < lProfileN;lVC++)\
				{\
					const EIndex  lNextRow = lVC + 1;\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lNextRow, lColumnA + lNextRow);\
				}\
				if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA, lColumnA);\
			}\
			else\
			{\
/*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  lVC = 0;for(;lVC < pProfileSegmentCount;lVC++)\
				{\
					if(pProfileSegmentVisibleFlags == NULL || pProfileSegmentVisibleFlags[lVC]) pQuadFunc(lColumnA + lVC, lNextColumnA + lVC, lNextColumnA + lVC + 1, lColumnA + lVC + 1);\
				}\
			}\
		}\
	}\
} 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,  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
