//================================================================
// E3D
//
// - Basic type definitions
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Feb-23 00:07:16
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef	_E3D_Types_h
#define	_E3D_Types_h

#define E3D  1

#include <float.h>

#include <ETypes.h>
#include <Color/Color.h>

#define E3dWARN_PRECISION   1
#define E3dOBJECT_THREADS   1


#define E3dMAX_PRINTF_BUFFER_SIZE  4096

#define E3dSTARTF  -99999999.9
#define E3dENDF     99999999.9

//#define E3d64BIT_INTS

// Timer resolution
#define E3d_GetTime  E_GetMicroseconds


//----------------------------------------------------------------
// If the symbol E3dFLOAT_BITS is defined as 64, the 3D library
// will use double precision for all computations.
//----------------------------------------------------------------

#define E3dFLOAT_BITS     32
#define E3dGL_FLOAT_BITS  32

typedef int32_t   E3dVertexSize;
typedef int32_t   E3dVertexNodeSize;

typedef uint16_t  E3dEdgeFlags;
typedef uint16_t  E3dVertexFlags;


#define E3dREFLECTION    0x01
#define E3dTRANSMISSION  0x02


// Basic operations
//
#define E3dADD  0x01
#define E3dSUB  0x02
#define E3dMUL  0x04
#define E3dDIV  0x08

enum
{
	E3dCOLOR = 1,
	E3dVECTOR
};


// Blending modes
enum
{
	E3dBlendZERO = 0,
	E3dBlendONE,
	E3dBlendSRC_ALPHA,
	E3dBlendONE_MINUS_SRC_ALPHA
};


// Transformation modes
//
enum
{
	E3dTmNONE = 0,
	E3dTmVIEW,
	E3dTmLOCAL,
	E3dTmGLOBAL,
	E3dTmPLANE,
	E3dTmREFERENCE,
	E3dTmMANIPULATOR
};


// Action codes for E3dLayers_SetFromScene() etc.
enum
{
	E3dUPDATE = 0,  // Just update state
	E3dINSERT,
	E3dDELETE,
	E3dREORDER
};


//================================================================
// Set the value of a Resource in an EObject, from an E3dCoord3
//================================================================
#define E3d_SetResourceCoord3_s(pObject, pName,  pValue) do\
{\
	EResource*  lResource = EResource_ByName(&pObject->Class->Resources, pName);if(lResource)\
	{\
		switch(lResource->Type)\
		{\
			case E3dCOORD3_TYPE:\
				{\
					uint8_t*    lVariableAddress = (EPointerUInt)((uint8_t*)pObject) + (uint8_t*)(lResource->Address);\
					E3dCoord3*  lAddress = (E3dCoord3*)lVariableAddress;\
					*lAddress = pValue;\
				}\
			break;\
		}\
	}\
} while(0)


#define _E3d_PointSize(pIn, pOut) do\
{\
	pOut = pIn | 1;if(pOut > 25) pOut = 25;\
} while(0)



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

typedef EIndex    E3dID;
typedef int16_t   E3dTextureMapperIndex;
EList_t(E3dTextureMapperIndex);
typedef uint32_t  E3dDisplayFlags;
typedef uint32_t  E3dViewModeFlags;
typedef uint32_t  E3dItemFlags;

// General overlays
typedef struct
{
	EBool  GridXYOn, GridXZOn, GridYZOn, GridOn, AxesOn;
} E3dOverlaySettings;

// Overlays for regular 3D windows
typedef struct
{
	EBool  Splines, Faces;
	EBool  MeshVertices, SplineCVs, SplineTangents, SplineNormals;

	EBool  HiddenObjectWireframe;      // E3dDM_Wireframe flags pulled out from HiddenObjectDisplayFlags, so it can be saved/loaded.
	EBool  UnselectedObjectWireframe, SelectedObjectWireframe;

	EBool  NodeOrigins, Skeletons, BBoxes;

	EBool  RPolyGroupBBoxes;
} E3dShow;

#define E3dMAX_GRID_DEPTH  3   // 1-unit grid, 10-unit, 100-unit

typedef struct
{
	uint16_t  BlendFuncSrcFactor, BlendFuncDstFactor;    // E3dBlendZERO, E3dBlendONE, E3dBlendSRC_ALPHA etc.
	EBool     DepthWrite, DepthTest;
} E3dDrawState;

typedef struct
{
	EcRGBAf32Color      BackgroundRGBAfColor,
	                    GridRGBAfColors[E3dMAX_GRID_DEPTH],
	                    AxisRGBAfColor,

	                    VertexRGBAfColor, HVertexRGBAfColor,
	                    SelectedPointRGBAfColor, ActivePointRGBAfColor,

	                    WireRGBAfColor, HWireRGBAfColor, SelGeoWireRGBAfColor, SelSubGeoWireRGBAfColor, SelPolyGroupWireRGBAfColor,

	                    ActiveEdgeRGBAfColor, SelectedEdgeRGBAfColor,
	                    Line1RGBAfColor, Line2RGBAfColor,
	                    SelectedPolygonRGBAfColor, ShadedSelectedPolygonRGBAfColor,
	                    NormalRGBAfColor,
	                    TangentRGBAfColor,

	                    LockedItemRGBAfColor, TextureProjectorRGBAfColor,

	                    BoneRGBAfColor;

	E3dOverlaySettings  Overlay;
	E3dShow             Show;

	int                 AAMult;

	E3dDisplayFlags     DisplayFlags;
	uint16_t            OpaqueTransparent;

// From preferences
	int                 SelectedPointSize;
} E3dDrawContext;


// Verbosity flags
enum
{
	E3dVbTEXTURES       = 0x0001,
	E3dVbTEXTUREMAPPING = 0x0002,
	E3dVbPOLYGONS       = 0x0004,
	E3dVbOPENGL         = 0x0008,
};

#define E3dVbALL (E3dVbTEXTURES|E3dVbTEXTUREMAPPING|E3dVbPOLYGONS|E3dVbOPENGL)

extern uint32_t  E3d_Verbosity;


// Some broken GLX implementations:
// - need a call to glXMakeCurrent before glXSwapBuffers
// - don't have glXMakeContextCurrent implemented (it's there, but it doesn't do anything)
//
#define E3dSUPPORT_BROKEN_GLX		1


// A generic NOTHING, NONE etc. value
//
#define E3dNONE			0

typedef int32_t  E3dVertexIndex;
//typedef int    E3dVertexNodeIndex;  // The number of VertexNodes per Polygon is limited by this type if necessary. Change it to EIndex (EIndex is 64-bit if EIndex_BITS == 64).
typedef EIndex   E3dVertexNodeIndex;  // The number of VertexNodes per Polygon is limited by this type if necessary. Change it to EIndex (EIndex is 64-bit if EIndex_BITS == 64).


#if E3dGL_FLOAT_BITS == 64
typedef double               E3dGLCoordinate;
#define E3dGLCoordinateType  GL_DOUBLE
#else
typedef float                E3dGLCoordinate;
#define E3dGLCoordinateType  GL_FLOAT
#endif


#if E3dFLOAT_BITS == 64
#define E3dEPSILON        0.00000001  // TEST THIS
#define E3dMACHINE_ERROR  0.00000001

typedef double  E3dCoordinate;
typedef double  E3dWeight;
typedef double  E3dFColorComponent;

#define E3dCOORDINATE_TYPE  EResFLOAT64
#define E3dCOORD2_TYPE      EResFLOAT64_2
#define E3dCOORD3_TYPE      EResFLOAT64_3
#define E3dCOORD4_TYPE      EResFLOAT64_4

#define	E3dRADIANS_TO_NORMALIZED   0.15915494309189533577		// 1/(2 * PI)
#define	E3dRADIANS_TO_DEGREES     57.295779513082320877
#define E3dDEGREES_TO_RADIANS      0.017453292519943295769
#define E3dPI       3.14159265358979323846264
#define E3dSQRT2    1.4142135623730950488
#define E3dE        2.718281828459045091  // The basis for the "natural" logarithm
#define E3dINV_PI  (1.0 / E3dPI)

#define E3dHUGE		1e36

#else

#define E3dEPSILON          0.00001f
#define E3dMACHINE_ERROR    0.00001f

typedef float  E3dCoordinate;
typedef float  E3dWeight;
typedef float  E3dFColorComponent;

#define E3dCOORDINATE_TYPE  EResFLOAT32
#define E3dCOORD2_TYPE      EResFLOAT32_2
#define E3dCOORD3_TYPE      EResFLOAT32_3
#define E3dCOORD4_TYPE      EResFLOAT32_4

#define	E3dRADIANS_TO_NORMALIZED   0.15915494f			// 1 / (2 * PI)
#define	E3dRADIANS_TO_DEGREES     57.2957795f
#define E3dDEGREES_TO_RADIANS	     0.017453292f
#define E3dPI       3.141592653
#define E3dSQRT2    1.414213562
#define E3dE        2.718281828  // The basis for the "natural" logarithm
#define E3dINV_PI  (1.0 / E3dPI)

#define E3dHUGE  1e30

#endif // DOUBLE_PRECISION


#define E3dELEMENTS_IN_MATRIX	16

typedef E3dCoordinate  E3dMatrix[E3dELEMENTS_IN_MATRIX];

typedef E3dGLCoordinate  E3dGLMatrix[E3dELEMENTS_IN_MATRIX];

static inline void E3dMatrix_ToGL(const E3dCoordinate* PMatrix, E3dGLCoordinate* PGLMatrix)
{
	EIndex  LI = 0;for(;LI < E3dELEMENTS_IN_MATRIX;LI++)
	{
		PGLMatrix[LI] = PMatrix[LI];
	}
}

static inline void E3dMatrix_FromGL(const E3dGLCoordinate* PGLMatrix, E3dCoordinate* PMatrix)
{
	EIndex  LI = 0;for(;LI < E3dELEMENTS_IN_MATRIX;LI++)
	{
		PMatrix[LI] = PGLMatrix[LI];
	}
}


#define E3dOPAQUE       0x01
#define E3dTRANSPARENT  0x02


#define E3dSCALING      0x01
#define E3dROTATION     0x02
#define E3dTRANSLATION  0x04


// Callback reasons
//
enum
{
	E3dCR_HIERARCHY_ADDED = 1,
	E3dCR_HIERARCHY_REMOVED,
	E3dCR_HIERARCHY_CHANGED,
	E3dCR_NODE_SCALE,
	E3dCR_NODE_ROTATE,
	E3dCR_NODE_TRANSLATE,
	E3dCR_BRANCH_SCALE,
	E3dCR_BRANCH_ROTATE,
	E3dCR_BRANCH_TRANSLATE,
	E3dCR_TREE_SCALE,
	E3dCR_TREE_ROTATE,
	E3dCR_TREE_TRANSLATE,
	E3dCR_MATERIAL_ADDED,
	E3dCR_MATERIAL_REMOVED,
	E3dCR_MATERIAL_CHANGED,
	E3dCR_MATERIAL_NAME_CHANGED,
	E3dCR_2DTEXTURE_ADDED,
	E3dCR_2DTEXTURE_REMOVED,
	E3dCR_2DTEXTURE_CHANGED,
	E3dCR_2DTEXTURE_NAME_CHANGED,
	E3dCR_GEOMETRY_CHANGED,

	E3dCR_SELECTION_CHANGED,
	E3dCR_POLYGON_SELECTION,
	E3dCR_EDGE_SELECTION,
	E3dCR_POINTS_SELECTION,
	E3dCR_SPLINE_SEGMENT_SELECTED,

	E3dCR_HIDE_UNHIDE,
	E3dCR_WIREFRAME_CHANGED,        // Mesh, Polygroup etc. Wireframe mode changed
	E3dCR_LIGHT_CHANGED,
	E3dCR_CAMERA_CHANGED,
	E3dCR_WINDOW_REDRAW_START,
	E3dCR_WINDOW_REDRAW_END
};


#define E3dCR_ORIGIN_TRANSFORM  0x1000  // Flag, used in conjunction with E3dCR_NODE_SCALE etc.


#define E3dFRONT  0x01
#define E3dBACK   0x02

// EUpdateFlags values
// These flags tell E3dObject_UpdateForDisplay() what should
// be updated in the rendering-specific internal structures.
//
#define	E3dUpdateITEM_NAME             0x00000001
#define	E3dUpdateSELECTION             0x00000002
#define	E3dUpdateLOCK_UNLOCK           0x00000004
#define	E3dUpdateWIREFRAME             0x00000008  // Wireframe symbol, e.g. bone width

#define	E3dUpdateHIDE_UNHIDE           0x00000010

#define	E3dUpdateLIGHT                 0x00000020
#define	E3dUpdateLIGHT_SAMPLING        0x00000040

#define	E3dUpdateCAMERA                0x00000080

#define	E3dUpdateNodeTRANSFORM         0x00000100
#define	E3dUpdateHIERARCHY             0x00000200

#define E3dUpdatePointSetALL           0x00000400

#define	E3dUpdateSplineSHAPE           0x00000800
#define	E3dUpdateSplineCONNECTIVITY    0x00001000
#define E3dUpdateSplineALL             (E3dUpdateSplineSHAPE|E3dUpdateSplineCONNECTIVITY)
#define	E3dUpdateFACE                  0x00002000

#define E3dUpdateMeshCONNECTIVITY      0x00004000    // Mesh Polygon count/vertex list etc.
#define E3dUpdateMeshSHAPE             0x00008000
#define	E3dUpdateMeshTRANSFORM         0x00010000    // A Mesh instance was rigidly (rotated/translated) transformed by a Node that instatiates it, but the Mesh shape may not have changed
#define E3dUpdateVERTEX_NORMAL         0x00020000    // Vertex normals changed the don't necessitate rebuilding KDTrees etc., but need in-place updates for RTriangles
#define E3dUpdateVERTEX_ATTRIBUTE      0x00040000    // Color, Tangent or custom vertex attributes changed - things that don't necessitate rebuilding KDTrees etc., but need in-place updates for RTriangles

#define E3dUpdateREMOVE_STRIPS         0x00080000    // Remove triangle strips
#define E3dUpdateEDGES                 0x00100000    // (Re)create Edge list
#define E3dUpdateTRIANGULATE           0x00200000    // (Re)create triangles
#define E3dUpdateMeshALL               (E3dUpdateMeshSHAPE|E3dUpdateMeshCONNECTIVITY|E3dUpdateREMOVE_STRIPS|E3dUpdateEDGES|E3dUpdateTRIANGULATE)

#define	E3dUpdateMaterialTYPE          0x00400000
#define	E3dUpdateMaterialPARAM         0x00800000

#define	E3dUpdateTextureIMAGE          0x01000000
#define	E3dUpdateTextureMAPPING        0x02000000
#define	E3dUpdateTextureFILTERING      0x04000000
#define	E3dUpdateTextureALL            (E3dUpdateTextureIMAGE|E3dUpdateTextureMAPPING|E3dUpdateTextureFILTERING)
#define E3dUpdateMaterialALL           (E3dUpdateMaterialTYPE|E3dUpdateMaterialPARAM|E3dUpdateTextureALL)

#define	E3dUpdateATTRIBUTES            0x40000000

#define E3dUpdateALL                   0x47FFFFFF

#define E3duf_FULLGEO    (E3dUpdatePointSetALL|E3dUpdateSplineSHAPE|E3dUpdateMeshSHAPE|E3dUpdateVERTEX_NORMAL|E3dUpdateREMOVE_STRIPS|E3dUpdateEDGES|E3dUpdateTRIANGULATE|E3dUpdateTextureMAPPING)
#define E3duf_SHAPE      (E3dUpdateMeshSHAPE|E3dUpdateSplineSHAPE|E3dUpdateVERTEX_NORMAL|E3dUpdateTextureMAPPING)


#define E3dCallCHANGEPROCS       0x000001    // Call ChangeProcs
#define E3dCallOUTPUTS           0x000002    // Call Geometry Outputs
#define E3dCallNODE_UPDATEPROCS  0x000004    // Call Update methods on Components of Nodes instantiating the Object
#define E3dCallSCENE_CALLBACKS   0x000008    // Call Scene CallBacks
#define E3dCallALL               0x00000F    // Call Scene CallBacks

#define E3dCallCALLBACKS         (E3dCallCHANGEPROCS|E3dCallNODE_UPDATEPROCS)



// E3dWindows_RedrawByChangeFlags() uses these flags that determine
// which windows should be redrawn and what the renderer should update.
// These should be set by:
// - SetFrameProcs of Animations
// - (undo/redo) operators
//

// Scene change flags
//
#define	E3dChgITEM_NAME             0x00000001
#define	E3dChgSELECTION             0x00000002
#define	E3dChgLOCK_UNLOCK           0x00000004
#define	E3dChgWIREFRAME             0x00000008  // Wireframe symbol, e.g. bone width

#define	E3dChgHIDE_UNHIDE           0x00000010

#define	E3dChgLIGHT                 0x00000020
#define	E3dChgLIGHT_SAMPLING        0x00000040

#define	E3dChgCAMERA                0x00000080

#define	E3dChgNodeTRANSFORM         0x00000100
#define	E3dChgHIERARCHY             0x00000200

#define	E3dChgPointSetALL           0x00000400

#define	E3dChgSplineSHAPE           0x00000800
#define	E3dChgSplineCONNECTIVITY    0x00001000
#define E3dChgSplineALL             (E3dChgSplineSHAPE|E3dChgSplineCONNECTIVITY)
#define	E3dChgFACE                  0x00002000

#define E3dChgMeshCONNECTIVITY      0x00004000    // Mesh Polygon count/vertex list etc.
#define	E3dChgMeshSHAPE             0x00008000
#define	E3dChgMeshTRANSFORM         0x00010000    // A Mesh instance was rigidly (rotated/translated) transformed by a Node that instatiates it, but the Mesh shape may not have changed
#define E3dChgVERTEX_NORMAL         0x00020000    // Vertex normals changed the don't necessitate rebuilding KDTrees etc., but need in-place updates for RTriangles
#define	E3dChgVERTEX_ATTRIBUTE      0x00040000    // Color, Tangent or custom vertex attributes changed - things that don't necessitate rebuilding KDTrees etc., but need in-place updates for RTriangles

#define	E3dChgMaterialTYPE          0x00080000
#define	E3dChgMaterialPARAM         0x00100000

#define	E3dChgTextureIMAGE          0x00200000
#define	E3dChgTextureMAPPING        0x00400000
#define	E3dChgTextureFILTERING      0x00800000
#define	E3dChgTextureALL            (E3dChgTextureIMAGE|E3dChgTextureMAPPING|E3dChgTextureFILTERING)
#define E3dChgMaterialALL           (E3dChgMaterialTYPE|E3dChgMaterialPARAM|E3dChgTextureALL)


#define	E3dChgREAD_TEXTURES         0x01000000
#define	E3dChgSCHEMATICS            0x02000000

#define	E3dChgANIMATION             0x04000000
#define	E3dChgAnimationTIME         0x08000000
#define	E3dChgAnimationSUBFRAME     0x10000000
#define	E3dChgAnimationSELECTION    0x20000000

#define	E3dChgATTRIBUTES            0x40000000

#define E3dSceneChgALL              0x7FFFFFFF

// This is not a true "changed" flag. I's only used for E3dWindow_Redraw()
#define	E3dChgPRE_VISUALIZE         0x80000000



// Flags specific to a Renderer
// These are not propagated by E3dRendererSet_MarkChanges to other Renderers within the RendererSet
//
#define	E3dRendererChgWINDOW_SIZE           0x00000001
#define	E3dRendererChgWINDOW_EXPOSE         0x00000002

#define	E3dRendererChgEXPOSURE              0x00000004
#define	E3dRendererChgRAY_SETTINGS          0x00000008
#define	E3dRendererChgACCELERATOR_SETTINGS  0x00000010
#define	E3dRendererChgPHOTONMAP_SETTINGS    0x00000020

#define	E3dRendererChgATTRIBUTES            0x00000040

#define	E3dRendererChgALL                   0x0000007F



#define	E3dChgGEOMETRY  (E3dChgPointSetALL|E3dChgSplineSHAPE|E3dChgSplineCONNECTIVITY|E3dChgFACE|E3dChgMeshSHAPE)



//--------------------------------
// Node / Object clone flags
//--------------------------------
// Continues after ECopyNAME
#define E3dCopyMODEL_UNIQUE_NAME                 0x0002  // Generate unique names for Models
#define E3dCopyOBJECT_UNIQUE_NAME                0x0004  // Generate unique names for Objects
#define E3dCopyMATERIALS                         0x0008
#define E3dCopyEDGES                             0x0010
#define E3dCopyPOLYGONS                          0x0020
#define E3dCopyCOMPONENTS                        0x0040
#define E3dCopyLODS                              0x0080
#define E3dCopyNODE_COMPONENTS                   0x0100
#define E3dCopyANIMATIONS                        0x0200
#define ECopyCONVERT_TEXTUREMAPPERS_TO_FREEHAND  0x0400


#ifdef E3d64BIT_INTS
typedef long long           E3dIndex;
typedef unsigned long long  E3dCount;
typedef long long           E3dInt;
typedef unsigned long long  E3dUInt;
#define E3dBitMaskBITS  64
#else
typedef int             E3dIndex;
typedef unsigned int    E3dCount;
typedef int             E3dInt;
typedef unsigned int    E3dUInt;
#define E3dBitMaskBITS  32
#endif  // E3d64BIT_INTS


//----------------------------------------------------------------
// If this symbol is defined, the 3D library uses GUI
// (Creates/manages pseudo models for lights, cameras etc.)
//----------------------------------------------------------------
#define _E3dGUI



#define	E3dMAX_HIERARCHY_DEPTH		256


//--------------------------------------------------------
// Type definitions
//--------------------------------------------------------

#define	E3dNOMODEL	-1


enum { E3dGLSHORT = 0, E3dGLLONG, E3dGLSINGLE, E3dGLDOUBLE };


#define E3dMtxPos(r, c)	(r * 4 + c)


// What to include in bounding box calculations
//
#define E3dBB_NONE               0x00
#define E3dBB_SELECTED_GEOMETRY  0x01
#define E3dBB_SHADOW_CASTERS     0x02
#define E3dBB_SHADOW_RECEIVERS   0x04
#define E3dBB_SELECTED_POINTS    0x08
#define E3dBB_ALL                0x0F



enum
{
	E3dX = 0, E3dY, E3dZ, E3dW,  // Principal axes
	E3dXY, E3dXZ, E3dYZ,         // Principal planes
	E3dARBITRARY
};

#define E3dS	E3dX
#define E3dT	E3dY
#define E3dR	E3dZ
#define E3dQ	E3dW


// Rotation types
//
enum
{
	E3dXYZ = 1,
	E3dXZY,
	E3dYXZ,
	E3dYZX,
	E3dZXY,
	E3dZYX,
	E3dQUATERNION
};



#define E3dTRI_ERR		-1
#define E3dCOLINERR	3 * E3dMACHINE_ERROR	// One for each subtraction



#define E3dGLPIXELFORMAT	GL_ABGR_EXT
#define E3dGLPIXELTYPE		GL_UNSIGNED_BYTE

#define E3dALLOCQUICK	1
#define E3dALLOCFORGL	2

#define	E3dNO	0
#define	E3dYES	1


#define E3dFlagX	0x01
#define E3dFlagY	0x02
#define E3dFlagZ	0x04
#define E3dDoALL	0x07


#define E3dDoX		0x01
#define E3dDoY		0x02
#define E3dDoZ		0x04
#define E3dDoALL	0x07



#define E3dPOLY_DIRECTION	1  // 1: Exterior contours are defined counter-clockwise


typedef struct
{
	EBool  X, Y, Z;
} E3dBool3;


// Quaternion:
// X = AxisX * sin(angle * 0.5), Y = AxisY * sin(angle * 0.5), Z = AxisZ * sin(angle * 0.5), W = cos(angle*0.5)


#define _E3d_GenerateTangent_vp(pNormal, pDst) do\
{\
	const E3dCoord3  lNormal = pNormal;\
\
/* If there's no tangent given, generate one that:  */\
/* - is perpendicular to the normal                 */\
/* - lies in the X-Z plane                          */\
\
	if(E3d_Abs(lNormal.Y) > 0.75)\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 0.0, 1.0);\
		E_Cross3_vvp(lNormal, lHelperTangent, pDst);\
	}\
	else\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 1.0, 0.0);\
		E_Cross3_vvp(lNormal, lHelperTangent, pDst);\
	}\
	E3d_Normalize3_p(pDst);\
} while(0)


#define _E3d_GenerateTangent_vv(pNormal, pDst) do\
{\
	const E3dCoord3  lNormal = pNormal;\
\
/* If there's no tangent given, generate one that:  */\
/* - is perpendicular to the normal                 */\
/* - lies in the X-Z plane                          */\
\
	if(E3d_Abs(lNormal.Y) > 0.75)\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 0.0, 1.0);\
		E_Cross3_vvv(lNormal, lHelperTangent, pDst);\
	}\
	else\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 1.0, 0.0);\
		E_Cross3_vvv(lNormal, lHelperTangent, pDst);\
	}\
	E3d_Normalize3_v(pDst);\
} while(0)


#define _E3d_GenerateTangent_pp(pNormal, pDst) do\
{\
	const E3dCoord3  lNormal = *pNormal;\
\
/* If there's no tangent given, generate one that:  */\
/* - is perpendicular to the normal                 */\
/* - lies in the X-Z plane                          */\
\
	if(E3d_Abs(lNormal.Y) > 0.75)\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 0.0, 1.0);\
		E_Cross3_vvp(lNormal, lHelperTangent, pDst);\
	}\
	else\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 1.0, 0.0);\
		E_Cross3_vvp(lNormal, lHelperTangent, pDst);\
	}\
	E3d_Normalize3_p(pDst);\
} while(0)


#define _E3d_GenerateTangent_pv(pNormal, pDst) do\
{\
	const E3dCoord3  lNormal = *pNormal;\
\
/* If there's no tangent given, generate one that:  */\
/* - is perpendicular to the normal                 */\
/* - lies in the X-Z plane                          */\
\
	if(E3d_Abs(lNormal.Y) > 0.75)\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 0.0, 1.0);\
		E_Cross3_vvv(lNormal, lHelperTangent, pDst);\
	}\
	else\
	{\
		const E3dCoord3  lHelperTangent = E3dCoord3_s(0.0, 1.0, 0.0);\
		E_Cross3_vvv(lNormal, lHelperTangent, pDst);\
	}\
	E3d_Normalize3_v(pDst);\
} while(0)


#ifdef USEOpenGL
typedef struct E3dGLVertex_S  E3dGLVertex;

struct E3dGLVertex_S
{
	E3dGLCoordinate  X, Y, Z;
};
#endif  // USEOpenGL


#if ESIMD

#define E3dCoord2_v(p)                   E3dCoord2  p;p.unused2 = 0.0;p.unused3 = 0.0
#define E3dCoord3_v(p)                   E3dCoord3  p;p.unused3 = 0.0

typedef struct
{
	union { E3dCoordinate  X;E3dCoordinate  x;E3dCoordinate  U; };
	union { E3dCoordinate  Y;E3dCoordinate  y;E3dCoordinate  V; };
	E3dCoordinate  unused2, unused3;
} E3dCoord2;

typedef struct
{
	union { E3dCoordinate  X;E3dCoordinate  x;E3dCoordinate  R;E3dCoordinate  r; };
	union { E3dCoordinate  Y;E3dCoordinate  y;E3dCoordinate  G;E3dCoordinate  g; };
	union { E3dCoordinate  Z;E3dCoordinate  z;E3dCoordinate  B;E3dCoordinate  b; };
	E3dCoordinate  unused3;
} E3dCoord3;
//} E3dCoord3 __attribute__((aligned(16)));


#else	// E3dSIMD


#define E3dCoord2_v(p)                   E3dCoord2  p
#define E3dCoord3_v(p)                   E3dCoord3  p


typedef struct
{
	union { E3dCoordinate  X;E3dCoordinate  x;E3dCoordinate  U; };
	union { E3dCoordinate  Y;E3dCoordinate  y;E3dCoordinate  V; };
} E3dCoord2;

typedef struct
{
	union { E3dCoordinate  X;E3dCoordinate  x;E3dCoordinate  R;E3dCoordinate  r; };
	union { E3dCoordinate  Y;E3dCoordinate  y;E3dCoordinate  G;E3dCoordinate  g; };
	union { E3dCoordinate  Z;E3dCoordinate  z;E3dCoordinate  B;E3dCoordinate  b; };
} E3dCoord3;


typedef struct
{
	union { E3dGLCoordinate  X;E3dGLCoordinate  x;E3dGLCoordinate  R;E3dGLCoordinate  r; };
	union { E3dGLCoordinate  Y;E3dGLCoordinate  y;E3dGLCoordinate  G;E3dGLCoordinate  g; };
	union { E3dGLCoordinate  Z;E3dGLCoordinate  z;E3dGLCoordinate  B;E3dGLCoordinate  b; };
} E3dGLCoord3;

typedef struct
{
	union { E3dCoordinate  X;E3dCoordinate  x;E3dCoordinate  R;E3dCoordinate  r; };
	union { E3dCoordinate  Y;E3dCoordinate  y;E3dCoordinate  G;E3dCoordinate  g; };
	union { E3dCoordinate  Z;E3dCoordinate  z;E3dCoordinate  B;E3dCoordinate  b; };
	union { E3dCoordinate  W;E3dCoordinate  w;E3dCoordinate  A;E3dCoordinate  a; };
} E3dCoord4;

#endif	// E3dSIMD

EList_t(E3dCoord4);
EListA_t(E3dCoord4);
EList_t(E3dCoord3);
EListA_t(E3dCoord3);
EList_t(E3dCoord2);
EListA_t(E3dCoord2);


//----------------------------------------
// Vector type constructors
//----------------------------------------
static inline E3dCoord2 E3dCoord2_s(const E3dCoordinate PX, const E3dCoordinate PY)
{
	const E3dCoord2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}

static inline E3dCoord3 E3dCoord3_s(const E3dCoordinate PX, const E3dCoordinate PY, const E3dCoordinate PZ)
{
#if ESIMD
	const E3dCoord3  LResult = { .X= PX, .Y= PY, .Z= PZ, .unused3= 0.0 };
#else
	const E3dCoord3  LResult = { .X= PX, .Y= PY, .Z= PZ };
#endif
	return(LResult);
}


static inline E3dGLCoord3 E3dGLCoord3_s(const E3dCoordinate PX, const E3dCoordinate PY, const E3dCoordinate PZ)
{
	const E3dGLCoord3  LResult = { .X= (E3dGLCoordinate)PX, .Y= (E3dGLCoordinate)PY, .Z= (E3dGLCoordinate)PZ };
	return(LResult);
}

static inline E3dCoord4 E3dCoord4_s(const E3dCoordinate PX, const E3dCoordinate PY, const E3dCoordinate PZ, const E3dCoordinate PW)
{
	const E3dCoord4  LResult = { .X= PX, .Y= PY, .Z= PZ, .W= PW };
	return(LResult);
}



#define E3dSTCore\
	E3dCoordinate  S, T;\
	E3dCoord3      Tangent;  /* Texture-space tangent (used for bump/normal mapping)	 */\
	uint16_t       Flags     /* For ST (UV) editing  E3dVtxSELECTED, E3dVtxTMPSELECTED */

// Texture coordinates
//
typedef struct
{
	E3dSTCore;
} E3dST;

#define ST_s(pV)    (pV).S,  (pV).T
#define ST_p(pV)    (pV)->S,  (pV)->T


static inline void E3dST_Init(E3dST* PST)
{
	PST->Flags = 0;
	PST->Tangent = E3dCoord3_s(0.0, 0.0, 0.0);
}


#define E3dVertexCore\
	union { E3dCoord3  Position;E3dCoordinate  Position_3[3]; };\
	E3dVertexFlags  Flags  /* E3dVtxSELECTED, E3dVtxTMPSELECTED etc. */

typedef struct
{
	E3dVertexCore;
} E3dVertex;
EListA_t(E3dVertex);

#define E3dCoord3SumCore\
	E3dCoord3  Vector;\
	int        Count

typedef struct
{
	E3dCoord3SumCore;
} E3dCoord3Sum;

#define E3dMAX_TEXTURE_ANISOTROPY	16


// Texture coordinates with MIP-mapping and anisotropic sampling support
//
typedef struct
{
	E3dSTCore;

	E3dST          STs[E3dMAX_TEXTURE_ANISOTROPY];int	NumOfSTs;    // Anisotropic filtering
	E3dCoordinate  dS, dT;
} E3dSTWithDiff;



#define	E3dMAX_NUM_OF_2DTEXTURES        16  // Max # of Textures per Material
#define	E3dMAX_NUM_OF_2DTEXTUREMAPPERS   8  // Max # of TextureMappers per Shadeable (e.g. PolyGroup)


#define E3dSurfacePointCore\
	E3dCoord3       Position,\
	                Normal;\
	E3dSTWithDiff   STs[E3dMAX_NUM_OF_2DTEXTUREMAPPERS];       /* Texture coordinates for each TextureMapper          */\
	EcRGBAf32Color  TextureColors[E3dMAX_NUM_OF_2DTEXTURES]    /* Texture colors resulting from sampling the textures */

// Point used for shading surfaces and for TextureMappers
//
typedef struct
{
	E3dSurfacePointCore;
} E3dSurfacePointBase;


typedef struct
{
	E3dCoord4  AxisAngle;   // Exact axis (e.g. the X axis is (1.0, 0.0, 0.0)) and angle in degrees
	E3dCoord4  Quaternion;  // Quaternion equivalent for fast conversion to a matrix
} E3dRotation;

typedef struct
{
	E3dCoord3  Angles;    // Exact axis (e.g. the X axis is (1.0, 0.0, 0.0)) and angle in degrees
	uint8_t    Order;     // E.g. E3dZYX
} E3dEulerRotation;

typedef struct
{
	E3dCoordinate  A, B, C, D;    // Plane coefficients for the implicit formula (Ax+By+Cz+D=0)
} E3dPlane;


typedef union
{
	E3dPlane   Plane;
	E3dCoord4  Coord4;
} E3dCoordinate4;


#define E3dBBoxCore\
	union { E3dCoord3	Min;E3dCoordinate	Min4[4]; };\
	union { E3dCoord3	Max;E3dCoordinate	Max4[4]; }


typedef struct
{
	E3dBBoxCore;

	union { E3dCoord3  Center; E3dCoordinate  Center4[4];  };
	union { E3dCoord3  Extents;E3dCoordinate  Extents4[4]; };
} E3dBBoxCenterExtents;


typedef struct
{
	E3dBBoxCore;
} E3dBBox;


#define MAX_HIERARCHYDEPTH	 32

#define MAX_MODELWINDOWNUM	4


enum
{
	E3dBINARY = 1,
	E3dASCII
};



// Callback reasons
//
enum
{
	E3dCR_PICK = 1,
	E3dCR_ABORT    // E.g. Esc was pressed
};


// Interface call reasons
//
enum
{
	E3dICR_POINT_CHANGED = 1,
	E3dICR_POINTS_CHANGED
};


// EditProc return values
//
enum
{
	E3dEDITP_INFO_ADDED = 0,
	E3dEDITP_IN_USE,
	E3dEDITP_EDITING,
	E3dEDITP_NOTHING
};


// Orientations
//
#define E3dHORIZONTAL  0x01
#define E3dVERTICAL    0x02


// Schematics view connector types
//
enum
{
	E3dSHORTEST = 1,
	E3dPERPENDICULAR,
	E3dCURVED,
};


// Item (Model, Geometry etc.), action code
//
typedef int		(*E3dLockFunc)(void*, short);

typedef struct
{
	char*        Name;
	E3dLockFunc  LockFunc;
} E3dLock;


enum
{
	E3dCENTER = 0,
	E3dMIN,
	E3dMAX,
	E3dBOTTOM,
	E3dVAL
};


#define	E3dGETRED        0x01
#define	E3dGETGREEN      0x02
#define	E3dGETBLUE       0x04
#define	E3dGETALPHA      0x08
#define	E3dGETINTENSITY  0x10


// Sub-camera indices for stereo and cube-map rendering
enum
{
	E3dCameraLEFT       = 0x01,
	E3dCameraRIGHT      = 0x02,
	E3dCameraPOSITIVE_X = 0x04,
	E3dCameraNEGATIVE_X = 0x08,
	E3dCameraPOSITIVE_Y = 0x10,
	E3dCameraNEGATIVE_Y = 0x20,
	E3dCameraPOSITIVE_Z = 0x40,
	E3dCameraNEGATIVE_Z = 0x80,
	E3dCameraALL        = 0xFF
};


#define E3dNORMALIZE  -999999.0


#define E3dOperatorModifyPointsCore\
	EOperatorCore;\
	EList(, E3dShapeSnapshot*, ShapeSnapshots)


// Return flags for GLDraw and VkDraw methods / E3dNodeComponentClass  GLDrawFlags
//
typedef uint16_t  E3dHWDrawFlags;
#define E3dDrawDO_NOT_DRAW_GEOMETRY  0x0001  // Don't draw Mesh surface etc.
#define E3dDrawDO_NOT_DRAW_NODE      0x0002  // Don't draw Node Geometries
#define E3dDrawLAST                  0x0004  // GLDraw() etc. must be done after everything else had been drawn (e.g. requiers no Z-test overdraw, transparency etc.)
#define E3dDrawALWAYS_ON_TOP         0x0008


extern char*       E3d_LaunchPath;
extern ECodePoint  E3d_CodePoint;




// Feature classes
//
enum
{
	E3dFEATURE_HARDWARE_RENDERER = 1,
};

typedef struct
{
	int    Type;
	char*  Name;
} E3dFeature, *E3dFeaturePtr;
EListA_t(E3dFeaturePtr);

extern void    App_Log(const int PType, const char* PPrefix, const char* PMessage, ...);

extern void   E3dOverlaySettings_Init(E3dOverlaySettings* PSettings);
extern void   E3dShow_Init(E3dShow* PShow);
extern EBool  E3d_EnableBlankMessages;  // Enable warning message for "blank" functions

extern EUpdateFlags  E3dSceneChangeFlags_ToUpdateFlags(const EChangeFlags PChangeFlags);
extern char*         E3dSceneChangeFlags_ToString(const EChangeFlags PChangeFlags, const uint16_t PFlags,  char* POutString);
extern char*         E3dRendererChangeFlags_ToString(const EChangeFlags PChangeFlags, const uint16_t PFlags,  char* POutString);
extern EChangeFlags  E3dUpdateFlags_ToChangeFlags(const EUpdateFlags PUpdateFlags);
extern char*         E3dUpdateFlags_ToString(const EUpdateFlags PUpdateFlags, const uint16_t PFlags,  char* PString);


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


#endif	// _E3D_Types_h
