//================================================================
// EQUINOX-3D plugin
//
// Create a box and change it interactively
//
// AUTHOR:  Gabor Nagy, Ron Rimon
// DATE:    2025-Sep-15 15:37:28
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#include <math.h>
#include <stdio.h>

#include <EMalloc.h>
#include <EPlugins.h>

#include <Xe/Label.h>
#include <Xe/Matrix.h>
#include <Xe/Scale.h>
#include <Xe/Separator.h>
#include <Xe/ToggleButton.h>


#include <E3D/UI/CreateMacros.h>
#include <E3D/UI/Panel.h>
#include <E3D/UI/Panels.h>

// Import our icons
// In EQUINOX-3D, icon images are compiled inlined in the main and the plugin binaries (rather than loading hundreds of .png / .jpg etc. files on startup).
// This is one of the reasons EQX starts orders of magnitude faster than other large 3D applications.
//
EpIconDef3I(static, Box);

#define E3dDebugSIDES  0

char*             E_PluginInfo = "Box primitive";    // This shows up in the information dialog box of the plugin manager (System->Plugins)

static EPlugin*  _Plugin = NULL;

typedef struct
{
	XeWidget  CenterAtBottomBW, UVsBW,
	          MinMaxBW, SizeBW,
            EdgeLengthXW, EdgeLengthYW, EdgeLengthZW,

	          MinXW, MinYW, MinZW,
	          MaxXW, MaxYW, MaxZW,

	          SubdivisionsXW, SubdivisionsYW, SubdivisionsZW,

            BevelRadiusW, BevelStepsW;
} E3dResourcesGUI;


static XeDWidget  _MenuButton = NULL, _ToolBarButton = NULL;


enum
{
	ModeSIZE = 1,
	ModeMIN_MAX
};


typedef struct
{
	E3dObjectComponentCore;  // E3dInfo is the sub-class of the E3dObjectComponent class. This is how class inheritance works in EQX

// E3dInfo part
//
	E3dCoord3       EdgeLengths;

	E3dCoord3       Min, Max;

	E3dCoordinate   BevelRadius;int  BevelSteps;

	EInt32_3        Subdivisions;
	unsigned short  CoordinateMode;
	EBool           CenterAtBottom, Triangles, GenerateUVs;
} E3dInfo;


// Resources for the "Box" ObjectComponent class
// These are saved / restored when you save a 3D file that supports Resources (e.g. .dae)
//
#define ROffset(field)  (void*)(EPtrOffset(E3dInfo, field))
static EResource  _Resources[]=
{
	{ "EdgeLengthX",     E3dCOORDINATE_TYPE,  ROffset(EdgeLengths.X) },
	{ "EdgeLengthY",     E3dCOORDINATE_TYPE,  ROffset(EdgeLengths.Y) },
	{ "EdgeLengthZ",     E3dCOORDINATE_TYPE,  ROffset(EdgeLengths.Z) },

	{ "Min",             E3dCOORD3_TYPE,      ROffset(Min) },
	{ "Max",             E3dCOORD3_TYPE,      ROffset(Max) },

	{ "SubdivisionsX",   EResINT32,           ROffset(Subdivisions.X) },
	{ "SubdivisionsY",   EResINT32,           ROffset(Subdivisions.Y) },
	{ "SubdivisionsZ",   EResINT32,           ROffset(Subdivisions.Z) },

	{ "CoordinateMode",  EResUINT16,          ROffset(CoordinateMode) },

	{ "CenterAtBottom",  EResBOOLEAN,         ROffset(CenterAtBottom) },
	{ "Triangles",       EResBOOLEAN,         ROffset(Triangles) },
	{ "UVs",             EResBOOLEAN,         ROffset(GenerateUVs) },

	{ "BevelRadius",     E3dCOORDINATE_TYPE,  ROffset(BevelRadius) },
	{ "BevelSteps",      EResINT32,           ROffset(BevelSteps) },
};
#undef ROffset


static E3dObjectComponentClass*  _ComponentClass = NULL;

typedef struct
{
	E3dPolyGroup*  PolyGroup;
	EIndex         Current;
	E3dInfo*       Info;
	E3dPolygon**   Polygon;
} E3dMyTmpState;


//This Function can be used to Bevel any Corner given a starting point Current and a state of the Mesh. PSide is decided by if we are above the mid point of the circle or below above = 1 below = PRow1-3 are the beveled edges used to create the corner and PEdgeIndices is a Matrix that contains all the needed vertices to bevel a corner
static inline void _BevelCorners(E3dMyTmpState* PState, int PSide, EIndex PRow1, EIndex PRow2, EIndex PRow3, EIndex PBevelSteps, EIndex PCornerPoints[3], EIndex PEdgeIndices[24][PBevelSteps - 1])
{
	if(PSide == 1)
	{
// Use *(PState->Polygon) to get the actual pointer value
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PCornerPoints[0], PEdgeIndices[PRow1][PState->Info->BevelSteps - 2], PEdgeIndices[PRow3][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PCornerPoints[1], PEdgeIndices[PRow2][0], PEdgeIndices[PRow1][0]);
		(*(PState->Polygon))++;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PCornerPoints[2], PEdgeIndices[PRow3][0], PEdgeIndices[PRow2][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;
	}
	else if(PSide == 0)
	{
// Use *(PState->Polygon) to get the actual pointer value
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PCornerPoints[0], PEdgeIndices[PRow1][PState->Info->BevelSteps - 2], PEdgeIndices[PRow3][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PCornerPoints[1], PEdgeIndices[PRow2][PState->Info->BevelSteps - 2], PEdgeIndices[PRow1][0]);
		(*(PState->Polygon))++;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PCornerPoints[2], PEdgeIndices[PRow3][0], PEdgeIndices[PRow2][0]);
		(*(PState->Polygon))++;
	}

	if(PState->Info->BevelSteps == 2)
	{
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PEdgeIndices[PRow3][0], PEdgeIndices[PRow1][0], PEdgeIndices[PRow2][0]);
		(*(PState->Polygon))++;
	}
	else if(PSide == 1)
	{
		EIndex  LSeperator = PState->Info->BevelSteps - 2;
		EIndex  LCreator = 0;
		EIndex  LPrevious = PState->Current;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow1][0], PEdgeIndices[PRow2][0]);
		(*(PState->Polygon))++;

		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow1][LCreator + 1], PEdgeIndices[PRow1][LCreator]);
			(*(PState->Polygon))++;

			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PState->Current, PState->Current + LSeperator, PEdgeIndices[PRow1][LCreator + 1]);
				(*(PState->Polygon))++;
			}
			PState->Current = PState->Current + LSeperator;
			LSeperator = LSeperator - 1;
			LCreator++;
		}
// This loop exits with LCurrent being the starting point of the Left Front corner which is 1 too far

// This creates the Bottom Teeth of the Top right triangle
// This brings LCurrent back to the first point of the Right Top Front Corner
		PState->Current = LPrevious;
		LCreator = 0;

		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow2][LCreator], PEdgeIndices[PRow2][LCreator + 1]);
			(*(PState->Polygon))++;

			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow2][LCreator + 1], PState->Current + 1);
				(*(PState->Polygon))++;
			}
			PState->Current++;
			LCreator++;
		}

// This moves LCurrent back to the bottom right most point which is where it is needed to fill the gap there
		PState->Current = PState->Current - 1;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow2][PState->Info->BevelSteps - 2], PEdgeIndices[PRow3][0]);
		(*(PState->Polygon))++;

// This creates the Right Teeth
// This loop ends and leaves LCurrent at Last point of our Right corner
		LCreator = 0;
		LSeperator = PState->Info->BevelSteps - 3;
		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow3][LCreator], PEdgeIndices[PRow3][LCreator + 1]);
			(*(PState->Polygon))++;
			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PEdgeIndices[PRow3][LCreator + 1], PState->Current + LSeperator, PState->Current);
				(*(PState->Polygon))++;
			}

			PState->Current = PState->Current + LSeperator;
			LCreator++;
			LSeperator = LSeperator - 1;
		}

// This fills the top gap of the Right Top Front Corner
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow3][PState->Info->BevelSteps - 2], PEdgeIndices[PRow1][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;

// This brings the LCurrent back to the second bottom left point of the corner
		PState->Current = LPrevious + 1;
		PState->Current = LPrevious + 1;
		LCreator =  0;
		LSeperator = PState->Info->BevelSteps - 3;
		int Looper = PState->Info->BevelSteps - 3;
		int Controller = (PState->Info->BevelSteps-3) * (PState->Info->BevelSteps-2) / 2;
		while(LCreator < Controller)
		{
			EIndex  LSteps = 0;
// This loop does all the upright triangles in the center
			while(LSteps < Looper)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PState->Current + LSeperator, PState->Current - 1);
				(*(PState->Polygon))++;
// This if does the downwards triangles in the center
				if(LSteps < Looper - 1)
				{
					E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize, PState->Current, PState->Current + LSeperator + 1, PState->Current + LSeperator);
					(*(PState->Polygon))++;
				}

				LCreator++;
				LSteps++;
				PState->Current++;
			}
//We need another LCurrent++ since we need to get to the second to left vertex in the corner
			PState->Current++;
			LSeperator = LSeperator - 1;
			Looper = Looper - 1;
		}
// This loop ends with LCurrent being the first vertice of the next corner

	}
	else if(PSide == 0)
	{

		EIndex  LSeperator = PState->Info->BevelSteps - 2;
		EIndex  LCreator = 0;
		EIndex  LPrevious = PState->Current;

// This triangle is the gap in the bottom right corner
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow2][0], PEdgeIndices[PRow3][0]);
		(*(PState->Polygon))++;

// This loop Creates The Left Teeth
		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow3][LCreator], PEdgeIndices[PRow3][LCreator + 1]);
			(*(PState->Polygon))++;
			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow3][LCreator + 1], PState->Current + LSeperator);
				(*(PState->Polygon))++;
			}
			PState->Current = PState->Current + LSeperator;
			LSeperator = LSeperator - 1;
			LCreator++;
		}


// This creates the Bottom Teeth
// This brings LCurrent back to the first point of the Right Top Front Corner

		PState->Current = LPrevious;
		LCreator = 0;

		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow2][LCreator + 1], PEdgeIndices[PRow2][LCreator]);
			(*(PState->Polygon))++;
			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PState->Current + 1, PEdgeIndices[PRow2][LCreator + 1]);
				(*(PState->Polygon))++;
			}
			PState->Current++;
			LCreator++;
		}

// This moves LCurrent back to the bottom right most point which is where it is needed to fill the gap there
		PState->Current = PState->Current - 1;

		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow1][0], PEdgeIndices[PRow2][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;

// This creates the Right Teeth

		LCreator = 0;
		LSeperator = PState->Info->BevelSteps - 3;
		while((LCreator + 2) < PState->Info->BevelSteps)
		{
			E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow1][LCreator + 1], PEdgeIndices[PRow1][LCreator]);
			(*(PState->Polygon))++;
			if(LCreator + 3 < PState->Info->BevelSteps)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PEdgeIndices[PRow1][LCreator + 1], PState->Current, PState->Current + LSeperator);
				(*(PState->Polygon))++;
			}

			PState->Current = PState->Current + LSeperator;
			LCreator++;
			LSeperator = LSeperator - 1;
		}

// This fills the top gap
		E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PEdgeIndices[PRow3][PState->Info->BevelSteps - 2], PEdgeIndices[PRow1][PState->Info->BevelSteps - 2]);
		(*(PState->Polygon))++;

// This brings the LCurrent back to the second bottom left point of the corner
		PState->Current = LPrevious + 1;
		LCreator =  0;
		LSeperator = PState->Info->BevelSteps - 3;
		int Looper = PState->Info->BevelSteps - 3;
		int Controller = (PState->Info->BevelSteps-3) * (PState->Info->BevelSteps-2) / 2;
		while(LCreator < Controller)
		{
			EIndex  LSteps = 0;
// This loop does all the upright triangles in the center
			while(LSteps < Looper)
			{
				E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PState->Current - 1, PState->Current + LSeperator);
				(*(PState->Polygon))++;
// This if does the downwards triangles in the center
				if(LSteps < Looper - 1)
				{
					E3dPolygon_InitAsTriangle(*(PState->Polygon), PState->PolyGroup->VertexNodeSize,  PState->Current, PState->Current + LSeperator, PState->Current + LSeperator + 1);
					(*(PState->Polygon))++;
				}
				LCreator++;
				LSteps++;
				PState->Current++;
			}
//We need another LCurrent++ since we need to get to the second to left vertex in the corner
			PState->Current++;
			LSeperator = LSeperator - 1;
			Looper = Looper - 1;
		}
// This loop ends with LCurrent being the first vertice of the next corner
	}
}

static void _Builder(E3dMyTmpState* PState, EIndex PCurrent, E3dPolygon** PPolygon)
{
	PState->Current = PCurrent;
	PState->Polygon = PPolygon;
}


//========================================
// Set vertex coordinates
//========================================
static void _SetVertices(E3dVertex* PVertices, const E3dVertexSize PVertexSize,  E3dInfo* PInfo)
{
	const EIndex     LSubdivX = PInfo->Subdivisions.X, LSubdivY = PInfo->Subdivisions.Y, LSubdivZ = PInfo->Subdivisions.Z;
	E3dCoordinate    LMinX, LMinY, LMinZ,  LMaxX, LMaxY, LMaxZ;
	const E3dCoord3  LEdgeLengths = PInfo->EdgeLengths;

	switch(PInfo->CoordinateMode)
	{
		case ModeSIZE:
			LMinX = -LEdgeLengths.X * 0.5;LMaxX = LEdgeLengths.X * 0.5;
			LMinY = -LEdgeLengths.Y * 0.5;
			LMinZ = -LEdgeLengths.Z * 0.5;LMaxZ = LEdgeLengths.Z * 0.5;

			if(PInfo->CenterAtBottom) { LMinY = 0.0;LMaxY = LEdgeLengths.Y; }
			else LMaxY = LEdgeLengths.Y * 0.5;
		break;

		case ModeMIN_MAX:
		default:
			LMinX = PInfo->Min.X;LMaxX = PInfo->Max.X;
			LMinY = PInfo->Min.Y;LMaxY = PInfo->Max.Y;
			LMinZ = PInfo->Min.Z;LMaxZ = PInfo->Max.Z;
		break;
	}

//printf("%s() %s:%d  %f %f  %f\n", __FUNCTION__, __FILE__, __LINE__, PInfo->Min.X, PInfo->Max.X, LEdgeLengths.X);fflush(stdout);

	const E3dCoordinate  LStepX = LEdgeLengths.X / (E3dCoordinate)LSubdivX, LStepY = LEdgeLengths.Y / (E3dCoordinate)LSubdivY, LStepZ = LEdgeLengths.Z / (E3dCoordinate)LSubdivZ;

	E3dVertex*  LVertex = PVertices;

	if(PInfo->BevelSteps == 0)
	{
// Front side
//
		{
			EIndex  LYI = 0;E3dCoordinate  LY = LMaxY;for(;LYI <= LSubdivY;LYI++, LY -= LStepY)
			{
				EIndex  LXI = 0;E3dCoordinate  LX = LMinX;for(;LXI <= LSubdivX;LXI++, LX += LStepX)
				{
					E3dVertex_Init(LVertex, PVertexSize,  LX, LY, LMaxZ);EStruct_Inc(LVertex, PVertexSize);
				}
			}
		}

// Sides
//
		{
			EIndex  LZCnt = 1;E3dCoordinate  LZ = LMaxZ - LStepZ;for(;LZCnt < LSubdivZ;LZCnt++, LZ -= LStepZ)
			{
// Top edge
//
				{
					EIndex  LXI = 0;E3dCoordinate  LX = LMinX, LY = LMaxY;;for(;LXI <= LSubdivX;LXI++, LX += LStepX)
					{
						E3dVertex_Init(LVertex, PVertexSize,  LX, LY, LZ);EStruct_Inc(LVertex, PVertexSize);
					}
				}

// Side points
//
				{
					EIndex  LYI = 1;E3dCoordinate  LY = LMaxY - LStepY;for(;LYI < LSubdivY;LYI++, LY -= LStepY)
					{
						E3dVertex_Init(LVertex, PVertexSize,  LMinX, LY, LZ);EStruct_Inc(LVertex, PVertexSize);
						E3dVertex_Init(LVertex, PVertexSize,  LMaxX, LY, LZ);EStruct_Inc(LVertex, PVertexSize);
					}
				}

// Bottom edge
//
				EIndex  LXI = 0;E3dCoordinate  LX = LMinX, LY = LMinY;for(;LXI <= LSubdivX;LXI++, LX += LStepX)
				{
					E3dVertex_Init(LVertex, PVertexSize,  LX, LY, LZ);EStruct_Inc(LVertex, PVertexSize);
				}
			}
		}

// Back side
//
		{
			EIndex  LYI = 0;E3dCoordinate  LY = LMaxY;for(;LYI <= LSubdivY;LYI++, LY -= LStepY)
			{
				EIndex  LXI = 0;E3dCoordinate  LX = LMinX;for(;LXI <= LSubdivX;LXI++, LX += LStepX)
				{
					E3dVertex_Init(LVertex, PVertexSize,  LX, LY, LMinZ);EStruct_Inc(LVertex, PVertexSize);
				}
			}
		}
	}
	else
	{
		const E3dCoordinate  LFaceSep = PInfo->BevelRadius;
		const int            LBevelSteps = PInfo->BevelSteps;

// Front face 0-3
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY, LMaxZ + LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY, LMaxZ + LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY, LMaxZ + LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY, LMaxZ + LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);

// Back face 4-7
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY, LMinZ - LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY, LMinZ - LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY, LMinZ - LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY, LMinZ - LFaceSep);
		EStruct_Inc(LVertex, PVertexSize);

// Top face 8-11
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY + LFaceSep, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY + LFaceSep, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY + LFaceSep, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY + LFaceSep, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);

// Bottom face 12-15
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY - LFaceSep, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY - LFaceSep, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY - LFaceSep, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY - LFaceSep, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);

// Right side 16-19
		E3dVertex_Init(LVertex, PVertexSize, LMaxX + LFaceSep, LMaxY, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX + LFaceSep, LMaxY, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX + LFaceSep, LMinY, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMaxX + LFaceSep, LMinY, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);

// Left side 20-23
		E3dVertex_Init(LVertex, PVertexSize, LMinX - LFaceSep, LMaxY, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX - LFaceSep, LMaxY, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX - LFaceSep, LMinY, LMinZ);
		EStruct_Inc(LVertex, PVertexSize);
		E3dVertex_Init(LVertex, PVertexSize, LMinX - LFaceSep, LMinY, LMaxZ);
		EStruct_Inc(LVertex, PVertexSize);

// BevelStep creates vertices
// Beveling has differenct formulas for when X Y or Z stay constant examples shown below as Top Face with Front face X stays constant Top Face with Left face Z stays constant and Front Face with Right Face Y stays constant
		const double  LTheta = M_PI / (2.0 * LBevelSteps);

// Top face with Front Face vertices for Bevel
// Point from which calculation occurs is (LMaxX, LMaxY + sin(angle) * LFaceSep , LMaxZ)
// Finished

		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY + sin(LAngle) * LFaceSep, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY + sin(LAngle) * LFaceSep, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Top Face with Back Face Vertices for Bevel
// Finished
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMaxY + sin(LAngle) * LFaceSep, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX, LMaxY + sin(LAngle) * LFaceSep, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Top Face with Left Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMinX + cos(LAngle) * LFaceSep, LMaxY + sin(LAngle) * LFaceSep, LMaxZ);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX + cos(LAngle) * LFaceSep, LMaxY + sin(LAngle) * LFaceSep, LMinZ);
			EStruct_Inc(LVertex, PVertexSize);

		}

// Top Face with Right Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI  * LTheta;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + cos(LAngle) * LFaceSep, LMaxY + sin(LAngle) * LFaceSep, LMaxZ);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + cos(LAngle) * LFaceSep, LMaxY + sin(LAngle) * LFaceSep, LMinZ);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Front Face with Right Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + sin(LAngle) * LFaceSep, LMaxY, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + sin(LAngle) * LFaceSep, LMinY, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Front Face with Left Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta - M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMinX + sin(LAngle) * LFaceSep, LMaxY, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX + sin(LAngle) * LFaceSep, LMinY, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Back Face with Right Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + sin(LAngle) * LFaceSep, LMaxY, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + sin(LAngle) * LFaceSep, LMinY, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Back Face with Left Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI;
			E3dVertex_Init(LVertex, PVertexSize, LMinX + sin(LAngle) * LFaceSep, LMaxY, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX + sin(LAngle) * LFaceSep, LMinY, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Front Face with Bottom Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + 3 * M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY + sin(LAngle) * LFaceSep, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY + sin(LAngle) * LFaceSep, LMaxZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Back Face with Bottom Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX, LMinY + sin(LAngle) * LFaceSep, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX, LMinY + sin(LAngle) * LFaceSep, LMinZ + cos(LAngle) * LFaceSep);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Right Face with Bottom Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + 3 * M_PI / 2;
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + cos(LAngle) * LFaceSep, LMinY + sin(LAngle) * LFaceSep, LMaxZ);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMaxX + cos(LAngle) * LFaceSep, LMinY + sin(LAngle) * LFaceSep, LMinZ);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Left Face with Bottom Face Vertices for Bevel
		for(int LI = 1;LI < LBevelSteps;LI++)
		{
			const double  LAngle = LI * LTheta + M_PI;
			E3dVertex_Init(LVertex, PVertexSize, LMinX + cos(LAngle) * LFaceSep, LMinY + sin(LAngle) * LFaceSep, LMaxZ);
			EStruct_Inc(LVertex, PVertexSize);
			E3dVertex_Init(LVertex, PVertexSize, LMinX + cos(LAngle) * LFaceSep, LMinY + sin(LAngle) * LFaceSep, LMinZ);
			EStruct_Inc(LVertex, PVertexSize);
		}

// Vertices for Corners
		const double  LRadius = LFaceSep;


// Top Right Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMaxX, LMaxY, LMaxZ);

// Top Right Corner (+X,+Y,+Z), SAME ORDER as your original loop
			for(int LI = 1;LI < LBevelSteps;++LI)                          // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                            // Remaining share for X + Z
				for(int  LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition. LCounter goes 1 .. LS-1 in this loop
				{
// Front -> right within the row:
//   First vertex has big Z (front), small X
//   Last vertex has small Z, big X

// LShare X,Y,Z : Toward right face, this row's vertical share, toward front face
					const EIndex3  LShare = EIndex3_s(LCounter, LI, LS - LCounter);

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

					const E3dCoord3  LV = E3dCoord3_s(LCn.X + LD.X * LRadius, LCn.Y + LD.Y * LRadius, LCn.Z + LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);
					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                    // Advances front -> right
				}
			}
		}


// Top Left Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMinX, LMaxY, LMaxZ);

			for(int LI = 1;LI < LBevelSteps;++LI)             // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;
				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)
				{
// Right -> left within the row:
//   first vertex has big Z (front), big X
//   last vertex has small Z, small X

					const EIndex3  LShare = EIndex3_s(LS - LCounter, LI, LCounter);

// Scale + translate to the corner

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

					const E3dCoord3  LV = E3dCoord3_s(LCn.X - LD.X * LRadius, LCn.Y + LD.Y * LRadius, LCn.Z + LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);

					EStruct_Inc(LVertex, PVertexSize);
					++LCounter;                                  // Advances front -> right
				}
			}
		}


// Back Right Top Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMaxX, LMaxY, LMinZ);

			for(int LI = 1;LI < LBevelSteps;++LI)                         // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                            // Remaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition
				{
// Right -> back within the row:
//   first vertex has big Z (front), big X
//   last vertex has small Z, small X

					const EIndex3  LShare = EIndex3_s(LS - LCounter, LI, LCounter);
					E3dCoord3      LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);

					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner

					const E3dCoord3  LV = E3dCoord3_s(LCn.X + LD.X * LRadius, LCn.Y + LD.Y * LRadius, LCn.Z - LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);
					EStruct_Inc(LVertex, PVertexSize);


					++LCounter;                                  // Advances right -> back
				}
			}
		}


// Back Left Top Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMinX, LMaxY, LMinZ);

			for(int LI = 1;LI < LBevelSteps;++LI)                         // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                                  // Remaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition
				{
// Back -> left within the row:
//   first vertex has small Z (back), big X
//   last vertex has big Z, small X

					const EIndex3  LShare = EIndex3_s(LCounter, LI, LS - LCounter);
					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);

					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner

					const E3dCoord3  LV = E3dCoord3_s(LCn.X - LD.X * LRadius, LCn.Y + LD.Y * LRadius, LCn.Z - LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);
					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                  // Advances back -> left
				}
			}
		}


// Right Bottom Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMaxX, LMinY, LMaxZ);


			for(int LI = 1;LI < LBevelSteps;++LI)                         // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                           // Remaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition
				{
// Front -> right within the row:
//   first vertex has big Z (front), small X
//   last vertex has small Z, big X

					const EIndex3  LShare = EIndex3_s(LCounter, LI, LS - LCounter);

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner
					const E3dCoord3  LV = E3dCoord3_s(LCn.X + LD.X * LRadius, LCn.Y - LD.Y * LRadius, LCn.Z + LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);

					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                  // advances front -> right
				}
			}
		}


// Left Bottom Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMinX, LMinY, LMaxZ);

			for(int LI = 1;LI < LBevelSteps;++LI)                         // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                           // Remaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition
				{
// left -> front within the row:
//   first vertex has small Z (front), small X
//   last vertex has big Z, big X
					const EIndex3  LShare = EIndex3_s(LS - LCounter, LI, LCounter);

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner
					const E3dCoord3  LV = E3dCoord3_s(LCn.X - LD.X * LRadius, LCn.Y - LD.Y * LRadius, LCn.Z + LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);

					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                  // Advances left -> front
				}
			}
		}


// Back Right Bottom Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMaxX, LMinY, LMinZ);

			for(int LI = 1;LI < LBevelSteps;++LI)                        // vertical sweep: bottom -> top
			{
				int LS = LBevelSteps - LI;                         // remaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)                         // same stopping condition
				{
// Right -> back within the row:
//   first vertex has big Z (front), big X
//   last vertex has small Z, small X

					const EIndex3  LShare = EIndex3_s(LS - LCounter, LI, LCounter);

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner

					const E3dCoord3  LV = E3dCoord3_s(LCn.X + LD.X * LRadius, LCn.Y - LD.Y * LRadius, LCn.Z - LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);

					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                  // Advances right -> back
				}
			}
		}


// Back Left Bottom Corner
		{
			const E3dCoord3  LCn = E3dCoord3_s(LMinX, LMinY, LMinZ);

			for(int LI = 1;LI < LBevelSteps;++LI)                         // Vertical sweep: bottom -> top
			{
				const int  LS = LBevelSteps - LI;                           // Rremaining share for X+Z

				for(int LJ = LBevelSteps, LCounter = 1;LJ > LI + 1;--LJ)    // Same stopping condition
				{
// Back -> left within the row:
//   first vertex has small Z (back), larger X
//   last vertex has large Z, small X

					const EIndex3  LShare = EIndex3_s(LCounter, LI, LS - LCounter);

					E3dCoord3  LD = E3dCoord3_s((E3dCoordinate)LShare.X, (E3dCoordinate)LShare.Y, (E3dCoordinate)LShare.Z);
					E3d_Normalize3_v(LD);  // Normalize to unit sphere

// Scale + translate to the corner

					const E3dCoord3  LV = E3dCoord3_s(LCn.X - LD.X * LRadius, LCn.Y - LD.Y * LRadius, LCn.Z - LD.Z * LRadius);

					E3dVertex_Init(LVertex, PVertexSize,  LV.X, LV.Y, LV.Z);

					EStruct_Inc(LVertex, PVertexSize);

					++LCounter;                                  // Advances front -> right
				}
			}
		}
	}
}


//========================================================
// Polygon-building macro functions
//========================================================
#define _M_AddQuad(pPolygon, pVertexNodeSize,  pV0, pV1, pV2, pV3) do\
{\
	E3dPolygon_InitAsQuad(pPolygon, pVertexNodeSize,  pV0, pV1, pV2, pV3);\
	ENewN(2, pPolygon->ITriangles);\
	E3dITriangle*  lITriangle = pPolygon->ITriangles;\
	pPolygon->ITriangles_Count = 2;\
	lITriangle->VertexNodes[0] = 0;lITriangle->VertexNodes[1] = 1;lITriangle->VertexNodes[2] = 2;lITriangle++;\
	lITriangle->VertexNodes[0] = 2;lITriangle->VertexNodes[1] = 3;lITriangle->VertexNodes[2] = 0;\
	pPolygon++;\
} while(0)


#define _M_AddQuadTris(pPolygon, pVertexNodeSize,  pV0, pV1, pV2, pV3) do\
{\
	pPolygon->ITriangles = NULL;\
	E3dPolygon_SetAsTriangle(pPolygon, pVertexNodeSize,  pV0, pV1, pV2);\
	pPolygon++;\
\
	pPolygon->ITriangles = NULL;\
	E3dPolygon_SetAsTriangle(pPolygon, pVertexNodeSize,  pV2, pV3, pV0);\
	pPolygon++;\
} while(0)


#define _M_AddQuadUV(pPolygon, pVertexNodeSize, pUVOffsetInVtxNode,  pV0, pV1, pV2, pV3) do\
{\
	E3dVertexNode*  lVertexNode;\
	E3dITriangle*   lITriangle;\
	E3dCoord2*      lUV;\
\
	E3dPolygon_SetVa(pPolygon, pVertexNodeSize, 4,  pV0, pV1, pV2, pV3);\
	ENewN(2, pPolygon->ITriangles);\
	lITriangle = pPolygon->ITriangles;\
	pPolygon->ITriangles_Count = 2;\
	lITriangle->VertexNodes[0] = 0;lITriangle->VertexNodes[1] = 1;lITriangle->VertexNodes[2] = 2;lITriangle++;\
	lITriangle->VertexNodes[0] = 2;lITriangle->VertexNodes[1] = 3;lITriangle->VertexNodes[2] = 0;\
	lVertexNode = pPolygon->VertexNodes;\
\
	lUV = (E3dCoord2*)EOffsetToPtr(lVertexNode, pUVOffsetInVtxNode);\
	lUV->X = LU;lUV->Y = LV;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU;lUV->Y = LV + LVStep;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU + LUStep;lUV->Y = LV + LVStep;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU + LUStep;lUV->Y = LV;\
	pPolygon++;\
} while(0)


#define _M_AddQuadUVTris(pPolygon, pVertexNodeSize, pUVOffsetInVtxNode,  pV0, pV1, pV2, pV3) do\
{\
	E3dVertexNode*  lVertexNode;\
	E3dCoord2*      lUV;\
\
	pPolygon->ITriangles = NULL;\
	E3dPolygon_SetAsTriangle(pPolygon, pVertexNodeSize,  pV0, pV1, pV2);\
\
	lVertexNode = pPolygon->VertexNodes;\
	lUV = (E3dCoord2*)EOffsetToPtr(lVertexNode, pUVOffsetInVtxNode);\
	lUV->X = LU;lUV->Y = LV;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU;lUV->Y = LV + LVStep;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU + LUStep;lUV->Y = LV + LVStep;\
	pPolygon++;\
\
\
	pPolygon->ITriangles = NULL;\
	E3dPolygon_SetAsTriangle(pPolygon, pVertexNodeSize,  pV2, pV3, pV0);\
\
	lVertexNode = pPolygon->VertexNodes;\
	lUV = (E3dCoord2*)EOffsetToPtr(lVertexNode, pUVOffsetInVtxNode);\
	lUV->X = LU + LUStep;lUV->Y = LV + LVStep;EStruct_Inc(lUV, pVertexNodeSize);\
	lUV->X = LU + LUStep;lUV->Y = LV;EStruct_Inc(lUV, LVertexNodeSize);\
	lUV->X = LU;lUV->Y = LV;\
	pPolygon++;\
} while(0)


//========================================================
// Create a grid of rectangles for a side of a box
//========================================================
static E3dPolygon* _SideUV(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const E3dVertexNodeSize PUVOffsetInVtxNode,
 const int PUSubdiv, const E3dCoordinate PU, const E3dCoordinate LUStep,
 const int PVSubdiv, E3dCoordinate LV, const E3dCoordinate LVStep,
 int PRowA,
 const int LRowAStep, const int LLastRowAStepCorrection)
{
	EIndex  LVI = 1;E3dVertexIndex  LNextRowA = PRowA + LRowAStep;for(;LVI < PVSubdiv;LVI++, LV += LVStep)
	{
		E3dCoordinate   LU = PU;
		E3dVertexIndex  LV00 = PRowA, LV10 = PRowA + 1, LV01 = LNextRowA, LV11 = LNextRowA + 1;
		EIndex  LUI = 0;for(;LUI < PUSubdiv;LUI++, LU += LUStep)
		{
			_M_AddQuadUV(PPolygon, PVertexNodeSize, PUVOffsetInVtxNode,  LV00, LV01, LV11, LV10);
			LV00 = LV10;
			LV01 = LV11;
			LV10 += 1;
			LV11 += 1;
		}
		PRowA = LNextRowA;
		LNextRowA += LRowAStep;
	}

	LNextRowA += LLastRowAStepCorrection;

	{
		E3dCoordinate   LU = PU;
		E3dVertexIndex  LV00 = PRowA, LV10 = PRowA + 1, LV01 = LNextRowA, LV11 = LNextRowA + 1;
		EIndex  LUI = 0;for(;LUI < PUSubdiv;LUI++, LU += LUStep)
		{
			_M_AddQuadUV(PPolygon, PVertexNodeSize, PUVOffsetInVtxNode,  LV00, LV01, LV11, LV10);
			LV00 = LV10;
			LV01 = LV11;
			LV10 += 1;
			LV11 += 1;
		}
		PRowA = LNextRowA;
		LNextRowA += LRowAStep;
	}

	return(PPolygon);
}


//========================================================
// Create a grid of rectangles for a side of a box
//========================================================
static E3dPolygon* _SideUVr(E3dPolygon* PPolygon, const E3dVertexNodeSize PVertexNodeSize, const int PUVOffsetInVtxNode,
 const int PUSubdiv, const E3dCoordinate PU, const E3dCoordinate LUStep,
 const int PVSubdiv, E3dCoordinate LV, const E3dCoordinate LVStep,
 const int PWSubdiv,
 const int PRow,
 const int PColStepMatrix[3][3][2], const int POneVDivStep,
 const int PRowStep00,
 const int PRowStep01,
 const int PRowStep02,
const EBool PFullEnable)
{
	int             LRow = PRow;
	E3dVertexIndex  LNextRow = LRow + PVSubdiv > 1 ? LRow + PRowStep00 : LRow + PRowStep02;

	EIndex  LVI = 0;for(;LVI < PVSubdiv;LVI++, LV += LVStep)
	{
		EIndex  LUCode, LVCode, LNextRowVCode;

		if(PVSubdiv > 1)
		{
			if(LVI == 0) LVCode = 0;
			else if(LVI < PVSubdiv) LVCode = 1;
			else LVCode = 2;

			if(LVI < (PVSubdiv - 1)) LNextRowVCode = 1;
			else LNextRowVCode = 2;
		}
		else { LVCode = 0;LNextRowVCode = 2; }

		E3dVertexIndex  LV00 = LRow, LV01 = LNextRow;
		EIndex          LThisRowColStep, LNextRowColStep;
		if(PUSubdiv > 1)
		{
			LUCode = 0;
			LThisRowColStep = PColStepMatrix[LVCode][LUCode][0] + PColStepMatrix[LVCode][LUCode][1] * (LVI - 1) * (PWSubdiv - 1);
			LNextRowColStep = PColStepMatrix[LNextRowVCode][LUCode][0] + PColStepMatrix[LNextRowVCode][LUCode][1] * LVI * (PWSubdiv - 1);
		}
		else
		{
			LThisRowColStep = LNextRowColStep = POneVDivStep * (PWSubdiv + 1) * (PVSubdiv + 1);
			LUCode = 2;
		}

		if(E3dDebugSIDES)
		{
			static EBool	LFirst = TRUE;if(LFirst)
			{
				printf("%s() %s:%d  %d %d  %d %d  %d %d\n", __FUNCTION__, __FILE__, __LINE__,  PColStepMatrix[0][0][0],  PColStepMatrix[0][1][0],  PColStepMatrix[0][1][0], PColStepMatrix[0][1][1],  PColStepMatrix[0][2][0], PColStepMatrix[0][2][1]);fflush(stdout);
				printf("  %lld %lld  LNextRowVCode %lld\n", (long long)LThisRowColStep, (long long)LNextRowColStep, (long long)LNextRowVCode);fflush(stdout);
				LFirst = FALSE;
			}
		}

		E3dVertexIndex  LV10 = LRow + LThisRowColStep, LV11 = LNextRow + LNextRowColStep;
		EIndex  LUI = 0;E3dCoordinate  LU = PU;for(;LUI < PUSubdiv;LUI++, LU += LUStep)
		{
			if(PFullEnable || LVI == 0)
			{
				_M_AddQuadUV(PPolygon, PVertexNodeSize, PUVOffsetInVtxNode,  LV00, LV01, LV11, LV10);
//printf("  %s()  %lld %lld %lld %lld", __FUNCTION__,  (long long)LRow, (long long)(LRow + LThisRowColStep), (long long)LNextRow, (long long)(LNextRow + LNextRowColStep));fflush(stdout);
			}
			else { _M_AddQuadUV(PPolygon, PVertexNodeSize, PUVOffsetInVtxNode,  0, 0, 0, 0); }

			LV00 = LV10;
			LV01 = LV11;

			if(LUI < (PUSubdiv - 2)) LUCode = 1;
			else LUCode = 2;

			LThisRowColStep = PColStepMatrix[LVCode][LUCode][0] + PColStepMatrix[LVCode][LUCode][1] * (LVI - 1) * (PWSubdiv - 1);
			LNextRowColStep = PColStepMatrix[LNextRowVCode][LUCode][0] + PColStepMatrix[LNextRowVCode][LUCode][1] * LVI * (PWSubdiv - 1);

			LV10 += LThisRowColStep;
			LV11 += LNextRowColStep;
		}

		LRow = LNextRow;
		if(LVI < (PVSubdiv - 2))
		{
			LNextRow += PRowStep01;
		}
		else LNextRow += PRowStep02;
	}

	return(PPolygon);
}


static void _CheckConsistency(E3dInfo* PInfo)
{
	switch(PInfo->CoordinateMode)
	{
		case ModeSIZE:
			PInfo->Min.X = -PInfo->EdgeLengths.X * 0.5;
			PInfo->Max.X =  PInfo->EdgeLengths.X * 0.5;

			PInfo->Min.Y = -PInfo->EdgeLengths.Y * 0.5;
			PInfo->Max.Y =  PInfo->EdgeLengths.Y * 0.5;

			PInfo->Min.Z = -PInfo->EdgeLengths.Z * 0.5;
			PInfo->Max.Z =  PInfo->EdgeLengths.Z * 0.5;
		break;

		case ModeMIN_MAX:
			E_Sub3_vvv(PInfo->Max, PInfo->Min, PInfo->EdgeLengths);
		break;
	}
}


//================================================
// Copy editable fields
//================================================
static void _CopyFields(const E3dInfo* PSrc, E3dInfo* PDst)
{
#define _CopyField(p)  PDst->p = PSrc->p
	_CopyField(Min);
	_CopyField(Max);
	_CopyField(EdgeLengths);
	_CopyField(Subdivisions);
	_CopyField(CenterAtBottom);
	_CopyField(Triangles);
	_CopyField(GenerateUVs);
	_CopyField(CoordinateMode);
	_CopyField(BevelSteps);
	_CopyField(BevelRadius);
#undef _CopyField
}


//========================================
// Update() (create/change) method
//========================================
static E3dObject* _Update1(E3dObject* PObject, E3dObjectComponent* PComponentTemplate,  EUpdateFlags* PTriggeredUpdateFlags, EChangeFlags* PTriggeredSceneChangeFlags,  const EBool PCheckOnly)
{
	E3dInfo*       LInfo;
	E3dPolyGroup*  LPolyGroup;

	if(PCheckOnly)
	{
		if(PObject)
		{
			LInfo = (E3dInfo*)E3dObjectComponent_ByClass(PObject, _ComponentClass, FALSE);

			_CheckConsistency(LInfo);
		}
		return(NULL);
	}

	E3dMesh*  LMesh;
	if(PObject == NULL)
	{
		E_New(E3dMesh, LMesh);
		PObject = (E3dObject*)LMesh;

		LInfo = (E3dInfo*)E3dObjectComponent_Add((E3dObject*)LMesh, _ComponentClass);
		if(PComponentTemplate && PComponentTemplate->Class == _ComponentClass) _CopyFields((E3dInfo*)PComponentTemplate, LInfo);

		_CheckConsistency(LInfo);

		LPolyGroup = E3dMesh_PolyGroupAdd(LMesh);
		if(LPolyGroup == NULL)
		{
			E_Delete(LMesh);return(NULL);
		}
		EObject_SetName(LPolyGroup, EStrDup("BoxPG"), FALSE);
		LPolyGroup->Flags &= ~E3dUSE_VERTEX_NORMALS;
//printf("%s() %s:%d  %sGREEN%s  %08x\n", __FUNCTION__, __FILE__, __LINE__, ECodeGreen, ECodeNormal, LPolyGroup->Flags);fflush(stdout);
	}
	else
	{
// If no attributes changed, bail
//
		if(!EObject_IsSubClass(PObject, E3dMesh)) return(NULL);

		LMesh = (E3dMesh*)PObject;
		LInfo = (E3dInfo*)E3dObjectComponent_ByClass(PObject, _ComponentClass, FALSE);

		if(!PCheckOnly && LInfo->AttributeChangeCount == 0 && LInfo->InputChangeCount == 0) return(NULL);    // If no attributes or inputs changed, bail

		LPolyGroup = LMesh->PolyGroups.Items[0];
	}

	if(LMesh)
	{
		E3dMesh_FreeCaches(LMesh);
		E3dMesh_EdgesFree(LMesh);

		LPolyGroup->VertexNormalType |= E3dNormalFROM_SMOOTHING_ANGLE;
		LPolyGroup->SmoothingAngle = 0.0;

		const EIndex  LSubdivX = LInfo->Subdivisions.X, LSubdivY = LInfo->Subdivisions.Y, LSubdivZ = LInfo->Subdivisions.Z;

// Allocate Vertices for the Mesh
//
		{
			EIndex  LVNum;

			if(LInfo->BevelSteps != 0)
			{
// Calculation for the number of Vertices (without corners being beveled) 24+24 is for bevelstep=2 24 + 24 (BevelStep - 1)
				LVNum = 24 + 24 * (LInfo->BevelSteps - 1);
				if(LInfo->BevelSteps >= 3)
				{
					LVNum = 24 + 24 * (LInfo->BevelSteps - 1) + ((LInfo->BevelSteps - 2) * (LInfo->BevelSteps - 1) / 2) * 8;
				}
			}
			else
			{
				LVNum = (LSubdivX + 1) * (LSubdivY + 1) * 2 + (LSubdivZ - 1) * (LSubdivX + LSubdivY) * 2;
			}

			if(LMesh->Vertices.Count != LVNum)
			{
				E3dMesh_EdgesFree(LMesh);
				E3dMesh_VerticesFree(LMesh);
				E3dMesh_VerticesAdd(LMesh, LVNum);
			}
		}

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);

// Allocate Polygons for the Mesh/PolyGroup
//
		if(LInfo->BevelSteps != 0)
		{
			E3dPolyGroup_FreePolygons(LPolyGroup);
			{
// When adding corners the formula for a corner LNum_Polygons is pow((LInfo->BevelSteps), 2) so add to the current LNum_Polygons to get total with corners
				const EIndex  LNum_Polygons = 6 + (12 * LInfo->BevelSteps) + LInfo->BevelSteps * LInfo->BevelSteps * 8;
				const EIndex  LVertexNodeSize = LPolyGroup->VertexNodeSize;
				E3dPolygon*   LPolygon = E3dPolyGroup_AddPolygons(LPolyGroup, LNum_Polygons);

				EIndex  LEdgeIndices[24][LInfo->BevelSteps-1]; // This matrix is built to store the values of the Beveling edges this stores each indivudual edges vertices from bottom to top and indice 0 is the top front edge going around the top in counter clockwise order and then going to the lower sectoin

// Front Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  0, 1, 2, 3);

// Back Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  7, 6, 5, 4);

// Top Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  11, 10, 9, 8);


// Bottom Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  15, 14, 13, 12);

// Right Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  19, 18, 17, 16);

// Left Face of Cube
				_M_AddQuad(LPolygon, LVertexNodeSize,  20, 21, 22, 23);


				if(LInfo->BevelSteps == 1)
				{
// Connects Front and Top Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  8, 9, 1, 0);

// Connects Top and Back Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  10, 11, 4, 5);


// Connects Top and Left Face when LBevelSteps = 1


					_M_AddQuad(LPolygon, LVertexNodeSize,  9, 10, 21, 20);


// Connects Top and Right Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  11, 8, 16, 17);

// Connects Front and Right Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  16, 0, 3, 19);

// Connects Front and Left Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  1, 20, 23, 2);

// Connects Back and Right Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  4, 17, 18, 7);


// Connects Back and Left Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  21, 5, 6, 22);

// Connects Front and Bottom Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  3, 2, 12, 13);

// Connects Back and Bottom Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  6, 7, 14, 15);

// Connects Right and Bottom Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  18, 19, 13, 14);

// Connects Left and Bottom Face when LBevelSteps = 1

					_M_AddQuad(LPolygon, LVertexNodeSize,  23, 22, 15, 12);


// Connects Top and Right Corner when LBevelSteps = 1

					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  8, 0, 16);
					LPolygon++;


// Connects Top and Left Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  1, 9, 20);
					LPolygon++;

// Connects Top and Back Right Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  11, 17, 4);
					LPolygon++;

// Connects Top and Back Left Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  10, 5, 21);
					LPolygon++;

// Connects Front and Bottom Right Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  19, 3, 13);
					LPolygon++;

// Connects Front and Bottom Left Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  2, 23, 12);
					LPolygon++;

// Connects Back and Bottom Right Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  14, 7, 18);
					LPolygon++;

// Connects Back and Bottom Left Corner when LBevelSteps = 1
					E3dPolygon_InitAsTriangle(LPolygon, LVertexNodeSize,  15, 22, 6);
					LPolygon++;
				}
				else
				{
// Since we will always need to connect the Beveling edges to the face this quad is always needed for the Front bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  24, 25, 1, 0);

					EIndex  LMyIndex = 0;
					LEdgeIndices[0][LMyIndex] = 25;
					LEdgeIndices[1][LMyIndex] = 24;

// Connects the inner Front Bevel vertices into quads
					EIndex  LCurrent = 25;
					EIndex  LPrevious = LCurrent;

					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							{
								LPrevious = LCurrent;

								LCurrent = LCurrent + 2;

								_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LCurrent, LPrevious, LPrevious - 1);
							}

							LMyIndex++;
							LEdgeIndices[0][LMyIndex] = LCurrent;
							LEdgeIndices[1][LMyIndex] = LCurrent - 1;

							LCounter++;
						}
					}

// Does the last connection connecting the upper most inner vertices to the top face as a quad
					_M_AddQuad(LPolygon, LVertexNodeSize,  8, 9, LCurrent, LCurrent - 1);

// Jumps to Back Bevel Vertices using +2
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = LInfo->BevelSteps - 2;

					LEdgeIndices[4][LMyIndex] = LCurrent - 1;
					LEdgeIndices[5][LMyIndex] = LCurrent;


// Always needed since the vertices for bevel are being built downwards this connects the top face to the bevel edge in the top back
					_M_AddQuad(LPolygon, LVertexNodeSize,  10, 11, LCurrent - 1, LCurrent);


// inner loop that connects Bevel vertices in back top edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LPrevious, LPrevious - 1, LCurrent - 1, LCurrent);
							LCounter++;

							LMyIndex = LMyIndex - 1;

							LEdgeIndices[4][LMyIndex] = LCurrent - 1;
							LEdgeIndices[5][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Back face to the Bevel finally

					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, 4, 5);


// Jumps to Left Top Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = LInfo->BevelSteps - 2;

					LEdgeIndices[6][LMyIndex] = LCurrent;
					LEdgeIndices[7][LMyIndex] = LCurrent - 1;

// Always needed since the vertices for bevel are being built downwards this connects the top face to the bevel edge in the Left
					_M_AddQuad(LPolygon, LVertexNodeSize,  9, 10, LCurrent, LCurrent - 1);


// Inner loop that connects Bevel vertices in Left Top edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LPrevious - 1, LPrevious, LCurrent, LCurrent - 1);

							LCounter++;

							LMyIndex = LMyIndex - 1;

							LEdgeIndices[6][LMyIndex] = LCurrent;
							LEdgeIndices[7][LMyIndex] = LCurrent - 1;
						}
					}

// Always needed since we need to connect the Left face to the Bevel finally
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LCurrent, 21, 20);

// Jumps to Right Top Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[2][LMyIndex] = LCurrent - 1;
					LEdgeIndices[3][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built upwards this connects the right face to the bevel edge in the Right
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, 16, 17);


// Inner loop that connects Bevel vertices in Right Top edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, LPrevious - 1, LPrevious);
							LMyIndex++;
							LEdgeIndices[2][LMyIndex] = LCurrent - 1;
							LEdgeIndices[3][LMyIndex] = LCurrent;

							LCounter++;
						}
					}

// Always needed since we need to connect the Top face to the Bevel finally
					_M_AddQuad(LPolygon, LVertexNodeSize,  11, 8, LCurrent - 1, LCurrent);

// Jumps to Right Front Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[8][LMyIndex] = LCurrent - 1;
					LEdgeIndices[9][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the front Face to the right for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, 0, 3, LCurrent);


// Inner loop that connects Bevel vertices in Front Right edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LPrevious- 1, LPrevious, LCurrent);
							LMyIndex++;
							LEdgeIndices[8][LMyIndex] = LCurrent - 1;
							LEdgeIndices[9][LMyIndex] = LCurrent;

							LCounter++;
						}
					}

// Always needed since we need to connect the Top face to the Bevel finally
					_M_AddQuad(LPolygon, LVertexNodeSize,  16, LCurrent - 1, LCurrent, 19);

// Jumps to Left Front Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[14][LMyIndex] = LCurrent - 1;
					LEdgeIndices[15][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Left Face to the Front for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, 20, 23, LCurrent);


// Inner loop that connects Bevel vertices in Front Left edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LPrevious - 1, LPrevious, LCurrent);
							LCounter++;
							LMyIndex++;

							LEdgeIndices[14][LMyIndex] = LCurrent - 1;
							LEdgeIndices[15][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Front face to the Bevel finally as the Bevel goes from Left to Front
					_M_AddQuad(LPolygon, LVertexNodeSize,  1, LCurrent - 1, LCurrent, 2);

// Jumps to Back Right Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[10][LMyIndex] = LCurrent - 1;
					LEdgeIndices[11][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Right Face to the Back for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, 17, 18, LCurrent);


// Inner loop that connects Bevel vertices in Back Right edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;
							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LPrevious - 1, LPrevious, LCurrent);
							LCounter++;

							LMyIndex++;

							LEdgeIndices[10][LMyIndex] = LCurrent - 1;
							LEdgeIndices[11][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Back face to the Bevel finally as the Bevel goes from Right to Back
					_M_AddQuad(LPolygon, LVertexNodeSize, 4, LCurrent - 1, LCurrent, 7);

// Jumps to Back Left Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[12][LMyIndex] = LCurrent - 1;
					LEdgeIndices[13][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Back Face to the Left for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, 5, 6, LCurrent);


// Inner loop that connects Bevel vertices in Back Left edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;
							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LPrevious - 1, LPrevious, LCurrent);
							LCounter++;

							LMyIndex++;

							LEdgeIndices[12][LMyIndex] = LCurrent - 1;
							LEdgeIndices[13][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Left face to the Bevel finally as the Bevel goes from Back to Left
					_M_AddQuad(LPolygon, LVertexNodeSize,  21, LCurrent - 1, LCurrent, 22);

// Jumps to Front Bottom Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = LInfo->BevelSteps - 2;

					LEdgeIndices[16][LMyIndex] = LCurrent - 1;
					LEdgeIndices[17][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Bottom Face to the Front for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LCurrent, 12, 13);


// Inner loop that connects Bevel vertices in Front Bottom edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;

							LCurrent = LCurrent + 2;
							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LCurrent, LPrevious, LPrevious - 1);
							LCounter++;

							LMyIndex = LMyIndex - 1;

							LEdgeIndices[16][LMyIndex] = LCurrent - 1;
							LEdgeIndices[17][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Front face to the Bevel finally as the Bevel goes from Bottom to Front
					_M_AddQuad(LPolygon, LVertexNodeSize,  3, 2, LCurrent, LCurrent - 1);


// Jumps to Back Bottom Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[20][LMyIndex] = LCurrent - 1;
					LEdgeIndices[21][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Back Face to the Bottom for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  6, 7, LCurrent - 1, LCurrent);


// Inner loop that connects Bevel vertices in Back Bottom edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LPrevious, LPrevious - 1, LCurrent - 1, LCurrent);
							LCounter++;

							LMyIndex++;

							LEdgeIndices[20][LMyIndex] = LCurrent - 1;
							LEdgeIndices[21][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Bottom face to the Bevel finally as the Bevel goes from Back to Bottom
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, 14, 15);

// Jumps to Right Bottom Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = LInfo->BevelSteps - 2;

					LEdgeIndices[18][LMyIndex] = LCurrent - 1;
					LEdgeIndices[19][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Bottom Face to the Right for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, 13, 14);


// inner loop that connects Bevel vertices in Right Bottom edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;


							_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent, LCurrent - 1, LPrevious - 1, LPrevious);

							LCounter++;

							LMyIndex = LMyIndex - 1;

							LEdgeIndices[18][LMyIndex] = LCurrent - 1;
							LEdgeIndices[19][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Right face to the Bevel finally as the Bevel goes from Bottom to Right
					_M_AddQuad(LPolygon, LVertexNodeSize,  18, 19, LCurrent - 1, LCurrent);

// Jumps to Left Bottom Face Vertices
					LCurrent = LCurrent + 2;
					LPrevious = LCurrent;

					LMyIndex = 0;

					LEdgeIndices[22][LMyIndex] = LCurrent - 1;
					LEdgeIndices[23][LMyIndex] = LCurrent;

// Always needed since the vertices for bevel are being built from the Left Face to the Bottom for bevel
					_M_AddQuad(LPolygon, LVertexNodeSize,  23, 22, LCurrent, LCurrent - 1);


// Inner loop that connects Bevel vertices in Left Bottom edge
					{
						int  LCounter = 2;while(LCounter < LInfo->BevelSteps)
						{
							LPrevious = LCurrent;
							LCurrent = LCurrent + 2;

							_M_AddQuad(LPolygon, LVertexNodeSize,  LPrevious - 1, LPrevious, LCurrent, LCurrent - 1);

							LCounter++;

							LMyIndex++;

							LEdgeIndices[22][LMyIndex] = LCurrent - 1;
							LEdgeIndices[23][LMyIndex] = LCurrent;
						}
					}

// Always needed since we need to connect the Bottom face to the Bevel finally as the Bevel goes from Left to Bottom
					_M_AddQuad(LPolygon, LVertexNodeSize,  LCurrent - 1, LCurrent, 15, 12);

					E3dMyTmpState LState;
					LState.PolyGroup = LPolyGroup;
					LState.Info = LInfo;

					LCurrent++;

					_Builder(&LState, LCurrent, &LPolygon);

					EIndex LCornerPoints[3] = {8, 0, 16};

//This creates the Top Right Corner
					_BevelCorners(&LState, 1, 1, 8, 2, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
//This creates the Top Left Corner
					LCornerPoints[0] = 9;LCornerPoints[1] = 20;LCornerPoints[2] = 1;
					_BevelCorners(&LState, 1, 7, 14, 0, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
//This creates the Top Back Right Corner
					LCornerPoints[0] = 11;LCornerPoints[1] = 17;LCornerPoints[2] = 4;
					_BevelCorners(&LState, 1, 3, 10, 4, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
//This creates the Top Back Left Corner
					LCornerPoints[0] = 10;LCornerPoints[1] = 5;LCornerPoints[2] = 21;
					_BevelCorners(&LState, 1, 5, 12, 6, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
//This creates the Bottom Right Corner
					LCornerPoints[0] = 13;LCornerPoints[1] = 19;LCornerPoints[2] = 3;
					_BevelCorners(&LState, 0, 18, 9, 16, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
//This creates the Bottom Left Corner
					LCornerPoints[0] = 12;LCornerPoints[1] = 2;LCornerPoints[2] = 23;
					_BevelCorners(&LState, 0, 17, 15, 22, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);

//This creates the Bottom Right Back Corner
					LCornerPoints[0] = 14;LCornerPoints[1] = 7;LCornerPoints[2] = 18;
					_BevelCorners(&LState, 0, 20, 11, 19, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);

//This creates the Bottom Left Back Corner
					LCornerPoints[0] = 15;LCornerPoints[1] = 22;LCornerPoints[2] = 6;
					_BevelCorners(&LState, 0, 23, 13, 21, LInfo->BevelSteps, LCornerPoints, LEdgeIndices);
				}
			}
		}
		else
		{
			const EIndex  LPNum = LSubdivX * LSubdivY * 2 + LSubdivX * LSubdivZ * 2 + LSubdivZ * LSubdivY * 2;
			E3dPolygon*   LPolygons;
			if(LPNum == LPolyGroup->Polygons.Count) LPolygons = LPolyGroup->Polygons.Items;
			else
			{
				if(LPolyGroup->Polygons.Items) E3dPolyGroup_FreePolygons(LPolyGroup);

				LPolygons = E3dPolygons_New(LPNum);if(LPolygons)
				{
					LPolyGroup->Polygons.Items = LPolygons;LPolyGroup->Polygons.Count = LPolyGroup->Polygons.CountAllocated = LPNum;
				}
			}

// Build the Polygons
//
			E3dPolygon*  LPolygon = LPolyGroup->Polygons.Items;

			if(LInfo->GenerateUVs) E3dPolyGroup_VertexAttributeAdd(LPolyGroup,  NULL, E3dVtxAttribute_UV, 0,  NULL);

			const int                LUVOffsetInVtxNode = E3dPolyGroup_VertexAttributeOffset(LPolyGroup, E3dVtxAttribute_UV, 0);
			const E3dVertexNodeSize  LVertexNodeSize = LPolyGroup->VertexNodeSize;

// Left side (-X)
//
			if(LInfo->GenerateUVs)
			{
				const int  LColStep = -((LSubdivX + 1) + (LSubdivY - 1)) * 2, LColStepL = LColStep - (LSubdivX - 1) * (LSubdivY - 1);
				const int  LColStepMatrix[3][3][2] = 
				{
					{ { LColStep,  0 },  { LColStep, 0 },  { LColStepL,                                  0 }  },
					{ { LColStep, -1 },  { LColStep, 0 },  { LColStep - (LSubdivX - 1) * (LSubdivY - 1), 1 }  },
					{ { LColStepL, 0 },  { LColStep, 0 },  { LColStep,                                   0 }  }
				};

				LPolygon = _SideUVr(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,
				                    LSubdivZ, 0.0, 1.0 / (E3dCoordinate)LSubdivZ / 3.0,
				                    LSubdivY, 0.0, 1.0 / (E3dCoordinate)LSubdivY / 2.0, LSubdivX,
				                    (LSubdivX + 1) * (LSubdivY + 1) + ((LSubdivX + 1) + (LSubdivY - 1)) * 2 * (LSubdivZ - 1),

				                    LColStepMatrix, -1,

				                    (LSubdivX + 1),
				                    (LSubdivX + 1),
				                    (LSubdivX + 1), TRUE);
			}


// Right side (+X)
//
			if(LInfo->GenerateUVs)
			{
				const int  LColStepF = (LSubdivX + 1) * (LSubdivY + 1);
				const int  LColStep = ((LSubdivX + 1) + (LSubdivY - 1)) * 2, LColStepL = LColStep + (LSubdivX - 1) * (LSubdivY - 1);
				const int  LColStepMatrix[3][3][2] = 
				{
					{ { LColStepL,                                   0 },  { LColStep, 0 },  { LColStep,                0 }  },
					{ { LColStep + (LSubdivX - 1) * (LSubdivY - 2), -1 },  { LColStep, 0 },  { LColStep + LSubdivX - 1, 1 }  },
					{ { LColStep,                                    0 },  { LColStep, 0 },  { LColStepF,               0 }  }
				};

				LPolygon = _SideUVr(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,
				                    LSubdivZ, 0.0, 1.0 / (E3dCoordinate)LSubdivZ / 3.0,
				                    LSubdivY, 0.5, 1.0 / (E3dCoordinate)LSubdivY / 2.0,
				                    LSubdivX,
			  	                  LSubdivX,

				                    LColStepMatrix, 1,

				                    (LSubdivX + 1),
				                    (LSubdivX + 1),
				                    (LSubdivX + 1), TRUE);
			}


// Bottom side (-Y)
//
			if(LInfo->GenerateUVs)
			{
				LPolygon = _SideUV(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,
				                   LSubdivX, 1.0 / 3.0, 1.0 / (E3dCoordinate)LSubdivX / 3.0,  LSubdivZ, 0.0, 1.0 / (E3dCoordinate)LSubdivZ / 2.0,
				                   (LSubdivX + 1) * LSubdivY,
				                   ((LSubdivX + 1) + (LSubdivY - 1)) * 2,  LSubdivY > 1 ? (LSubdivX - 1) * (LSubdivY - 1) : 0);
			}


// Top side (+Y)
//
			if(LInfo->GenerateUVs)
			{
				LPolygon = _SideUV(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,
				                   LSubdivX, 1.0 / 3.0, 1.0 / (E3dCoordinate)LSubdivX / 3.0,  LSubdivZ, 0.5, 1.0 / (E3dCoordinate)LSubdivZ / 2.0,
				                   (LSubdivX + 1) * (LSubdivY + 1) + (LSubdivX + LSubdivY) * 2 * (LSubdivZ - 1),
				                   -((LSubdivX + 1) + (LSubdivY - 1)) * 2,  LSubdivY > 1 ? -(LSubdivX - 1) * (LSubdivY - 1) : 0);
			}


// Rear side (-Z)
//
			EIndex  LRowA = (LSubdivX + 1) * (LSubdivY + 1) + (LSubdivZ - 1) * (LSubdivX + LSubdivY) * 2;
			EIndex  LNextRowA = LRowA + LSubdivX + 1;
			if(LInfo->GenerateUVs)
			{
				if(LInfo->Triangles)
				{
					E3dCoordinate  LV = 0.0, LVStep = 1.0 / (E3dCoordinate)LSubdivY / 2.0;
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1, LV += LVStep)
					{
						const E3dCoordinate  LUStep = 1.0 / (E3dCoordinate)LSubdivX / 3.0;E3dCoordinate	LU = 2.0 / 3.0 - LUStep;
						EIndex  LXI = 0;for(;LXI < LSubdivX;LXI++, LU -= LUStep)
						{
							_M_AddQuadUVTris(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,  LRowA + LXI + 1, LNextRowA + LXI + 1, LNextRowA + LXI, LRowA + LXI);
						}
					}
				}
				else
				{
					E3dCoordinate  LV = 0.0, LVStep = 1.0 / (E3dCoordinate)LSubdivY / 2.0;
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1, LV += LVStep)
					{
						const E3dCoordinate  LUStep = 1.0 / (E3dCoordinate)LSubdivX / 3.0;E3dCoordinate	LU = 2.0 / 3.0;
						EIndex  LXI = LSubdivX - 1;for(;LXI >= 0;LXI--, LU += LUStep)
						{
							_M_AddQuadUV(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,  LRowA + LXI + 1, LNextRowA + LXI + 1, LNextRowA + LXI, LRowA + LXI);
						}
					}
				}
			}
			else
			{
				if(LInfo->Triangles)
				{
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX+1, LNextRowA += LSubdivX + 1)
					{
						EIndex  LXI = LSubdivX - 1;for(;LXI >= 0;LXI--)
						{
							_M_AddQuadTris(LPolygon, LVertexNodeSize,  LRowA + LXI + 1, LNextRowA + LXI + 1, LNextRowA + LXI, LRowA + LXI);
						}
					}
				}
				else
				{
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1)
					{
						EIndex  LXI = LSubdivX - 1;for(;LXI >= 0;LXI--)
						{
							_M_AddQuad(LPolygon, LVertexNodeSize,  LRowA + LXI + 1, LNextRowA + LXI + 1, LNextRowA + LXI, LRowA + LXI);
						}
					}
				}
			}


// Front side (+Z)
//
			LRowA = 0;LNextRowA = LSubdivX + 1;
			if(LInfo->GenerateUVs)
			{
				if(LInfo->Triangles)
				{
					E3dCoordinate  LV = 0.5, LVStep = 1.0 / (E3dCoordinate)LSubdivY / 2.0;
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1, LV += LVStep)
					{
						E3dCoordinate  LU = 2.0 / 3.0, LUStep = 1.0 / (E3dCoordinate)LSubdivX / 3.0;
						EIndex  LXI = 0;for(;LXI < LSubdivX;LXI++, LU += LUStep)
						{
							_M_AddQuadUVTris(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,  LRowA + LXI, LNextRowA + LXI, LNextRowA + LXI + 1, LRowA + LXI + 1);
						}
					}
				}
				else
				{
					E3dCoordinate  LV = 0.5, LVStep = 1.0 / (E3dCoordinate)LSubdivY / 2.0;
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1, LV += LVStep)
					{
						E3dCoordinate  LU = 2.0 / 3.0, LUStep = 1.0 / (E3dCoordinate)LSubdivX / 3.0;
						EIndex  LXI = 0;for(;LXI < LSubdivX;LXI++, LU += LUStep)
						{
							_M_AddQuadUV(LPolygon, LVertexNodeSize, LUVOffsetInVtxNode,  LRowA + LXI, LNextRowA + LXI, LNextRowA + LXI + 1, LRowA + LXI + 1);
						}
					}
				}
			}
			else
			{
				if(LInfo->Triangles)
				{
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1)
					{
						EIndex  LXI = 0;for(;LXI < LSubdivX;LXI++)
						{
							_M_AddQuadTris(LPolygon, LVertexNodeSize,  LRowA + LXI, LNextRowA + LXI, LNextRowA + LXI + 1, LRowA + LXI + 1);
						}
					}
				}
				else
				{
					EIndex  LYI = 0;for(;LYI < LSubdivY;LYI++, LRowA += LSubdivX + 1, LNextRowA += LSubdivX + 1)
					{
						EIndex  LXI = 0;for(;LXI < LSubdivX;LXI++)
						{
							_M_AddQuad(LPolygon, LVertexNodeSize,  LRowA + LXI, LNextRowA + LXI, LNextRowA + LXI + 1, LRowA + LXI + 1);
						}
					}
				}
			}
		}

		EChangeFlags  LUpdateFlags = E3dUpdateALL & ~E3dChgTextureMAPPING;
		if(LInfo->GenerateUVs) LUpdateFlags |= E3dChgTextureMAPPING;
		if(PTriggeredUpdateFlags) *PTriggeredUpdateFlags = LUpdateFlags;

		LInfo->AttributeChangeCount = LInfo->InputChangeCount = 0;
	}

	return(PObject);
}


//================================================================
// Enable / disable GUI widgets, based on the coordinate mode
//================================================================
static void _SetGUIByMode(E3dObjectPanel* PPanel)
{
	E3dObject*               LObject = PPanel->Object;
	XeChangeManage           LWidgetsToManageUnmanage[10];
	XeChangeManage*          LChild = LWidgetsToManageUnmanage;
	EBool                    LSizeMode, LMinMaxMode;
	E3dInfo*                 LInfo = (E3dInfo*)E3dObjectComponent_ByClass(LObject, _ComponentClass, FALSE);
	XeComponentClassDrawer*  LDrawer = XeInfoPanel_GetFolderByClass((XeInfoPanel*)PPanel, _ComponentClass);
	E3dResourcesGUI*         LGUI = (E3dResourcesGUI*)LDrawer->ResourcesGUI;

	switch(LInfo->CoordinateMode)
	{
		case ModeSIZE:  LSizeMode = TRUE;LMinMaxMode = FALSE;break;
		default:        LSizeMode = FALSE;LMinMaxMode = TRUE;break;
	}

	LChild = LWidgetsToManageUnmanage;
	LChild->W = LGUI->CenterAtBottomBW;LChild->Manage = LSizeMode;LChild++;
	XeWidgets_ChangeManage(LWidgetsToManageUnmanage, LChild - LWidgetsToManageUnmanage);

	LChild = LWidgetsToManageUnmanage;
	LChild->W = LGUI->EdgeLengthXW;LChild->Manage = LSizeMode;LChild++;
	LChild->W = LGUI->EdgeLengthYW;LChild->Manage = LSizeMode;LChild++;
	LChild->W = LGUI->EdgeLengthZW;LChild->Manage = LSizeMode;LChild++;

	LChild->W = LGUI->MinXW;LChild->Manage = LMinMaxMode;LChild++;
	LChild->W = LGUI->MinYW;LChild->Manage = LMinMaxMode;LChild++;
	LChild->W = LGUI->MinZW;LChild->Manage = LMinMaxMode;LChild++;

	LChild->W = LGUI->MaxXW;LChild->Manage = LMinMaxMode;LChild++;
	LChild->W = LGUI->MaxYW;LChild->Manage = LMinMaxMode;LChild++;
	LChild->W = LGUI->MaxZW;LChild->Manage = LMinMaxMode;LChild++;

	XeWidgets_ChangeManage(LWidgetsToManageUnmanage, LChild - LWidgetsToManageUnmanage);

	XeScale_SetValue_Coord(LGUI->EdgeLengthXW, LInfo->EdgeLengths.X, FALSE);
	XeScale_SetValue_Coord(LGUI->EdgeLengthYW, LInfo->EdgeLengths.Y, FALSE);
	XeScale_SetValue_Coord(LGUI->EdgeLengthZW, LInfo->EdgeLengths.Z, FALSE);

	XeScale_SetValue_Coord(LGUI->MinXW, LInfo->Min.X, FALSE);
	XeScale_SetValue_Coord(LGUI->MinYW, LInfo->Min.Y, FALSE);
	XeScale_SetValue_Coord(LGUI->MinZW, LInfo->Min.Z, FALSE);

	XeScale_SetValue_Coord(LGUI->MaxXW, LInfo->Max.X, FALSE);
	XeScale_SetValue_Coord(LGUI->MaxYW, LInfo->Max.Y, FALSE);
	XeScale_SetValue_Coord(LGUI->MaxZW, LInfo->Max.Z, FALSE);
}


//========================================
// Dialog box callback handler
//========================================
static void _DCB(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	E3dScene*                LScene = E3d_Scene;
	E3dObjectPanel*          LPanel = (E3dObjectPanel*)PClientData;
	E3dObject*               LObject = LPanel->Object;
	E3dMesh*                 LMesh = (E3dMesh*)LObject;
	E3dInfo*                 LInfo = (E3dInfo*)E3dObjectComponent_ByClass(LObject, _ComponentClass, FALSE);
	XeComponentClassDrawer*  LDrawer = XeInfoPanel_GetFolderByClass((XeInfoPanel*)LPanel, _ComponentClass);
	E3dResourcesGUI*         LGUI = (E3dResourcesGUI*)(LDrawer->ResourcesGUI);
	EChangeFlags             LChanged = 0;

	if(PW == LGUI->SizeBW)
	{
		if(((XeToggleButtonCallbackStruct*)PCallData)->Set)
		{
			LInfo->CoordinateMode = ModeSIZE;

			_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);

			LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);

			_SetGUIByMode(LPanel);
		}
	}
	else if(PW == LGUI->MinMaxBW)
	{
		if(((XeToggleButtonCallbackStruct*)PCallData)->Set)
		{
			LInfo->CoordinateMode = ModeMIN_MAX;

			_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);

			LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);

			_SetGUIByMode(LPanel);
		}
	}
	else if(PW == LGUI->CenterAtBottomBW)
	{
		LInfo->CenterAtBottom = (EBool)(((XeToggleButtonCallbackStruct*)PCallData)->Set);
		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->SubdivisionsXW)
	{
		LInfo->Subdivisions.X = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->SubdivisionsYW)
	{
		LInfo->Subdivisions.Y = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->SubdivisionsZW)
	{
		LInfo->Subdivisions.Z = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->EdgeLengthXW)
	{
		LInfo->EdgeLengths.X = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		LInfo->Min.X = -LInfo->EdgeLengths.X * 0.5;
		LInfo->Max.X =  LInfo->EdgeLengths.X * 0.5;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->EdgeLengthYW)
	{
		LInfo->EdgeLengths.Y = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		LInfo->Min.Y = -LInfo->EdgeLengths.Y * 0.5;
		LInfo->Max.Y =  LInfo->EdgeLengths.Y * 0.5;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->EdgeLengthZW)
	{
		LInfo->EdgeLengths.Z = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		LInfo->Min.Z = -LInfo->EdgeLengths.Z * 0.5;
		LInfo->Max.Z =  LInfo->EdgeLengths.Z * 0.5;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MinXW)
	{
		LInfo->Min.X = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Max.X < LInfo->Min.X)
		{
			LInfo->Max.X = LInfo->Min.X;XeScale_SetValue_Coord(LGUI->MaxXW, LInfo->Max.X, FALSE);
		}

		LInfo->EdgeLengths.X = LInfo->Max.X - LInfo->Min.X;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MinYW)
	{
		LInfo->Min.Y = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Max.Y < LInfo->Min.Y)
		{
			LInfo->Max.Y = LInfo->Min.Y;XeScale_SetValue_Coord(LGUI->MaxYW, LInfo->Max.Y, FALSE);
		}

		LInfo->EdgeLengths.Y = LInfo->Max.Y - LInfo->Min.Y;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MinZW)
	{
		LInfo->Min.Z = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Max.Z < LInfo->Min.Z)
		{
			LInfo->Max.Z = LInfo->Min.Z;XeScale_SetValue_Coord(LGUI->MaxZW, LInfo->Max.Z, FALSE);
		}

		LInfo->EdgeLengths.Z = LInfo->Max.Z - LInfo->Min.Z;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MaxXW)
	{
		LInfo->Max.X = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Min.X > LInfo->Max.X)
		{
			LInfo->Min.X = LInfo->Max.X;XeScale_SetValue_Coord(LGUI->MinXW, LInfo->Min.X, FALSE);
		}

		LInfo->EdgeLengths.X = LInfo->Max.X - LInfo->Min.X;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MaxYW)
	{
		LInfo->Max.Y = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Min.Y > LInfo->Max.Y)
		{
			LInfo->Min.Y = LInfo->Max.Y;XeScale_SetValue_Coord(LGUI->MinYW, LInfo->Min.Y, FALSE);
		}

		LInfo->EdgeLengths.Y = LInfo->Max.Y - LInfo->Min.Y;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->MaxZW)
	{
		LInfo->Max.Z = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		if(LInfo->Min.Z > LInfo->Max.Z)
		{
			LInfo->Min.Z = LInfo->Max.Z;XeScale_SetValue_Coord(LGUI->MinZW, LInfo->Min.Z, FALSE);
		}

		LInfo->EdgeLengths.Z = LInfo->Max.Z - LInfo->Min.Z;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE|E3dUpdateTextureMAPPING, E3dCallALL,  LScene);
	}
/*
	else if(PW == LGUI->UVsBW)
	{
		LInfo->GenerateUVs = ((XeToggleButtonCallbackStruct*)PCallData)->Set;LInfo->AttributeChangeCount++;

		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
*/
	else if(PW == LGUI->BevelRadiusW)
	{
		LInfo->BevelRadius = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;

		_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE, E3dCallALL,  LScene);
	}
	else if(PW == LGUI->BevelStepsW)
	{
// LInfo->BevelSteps = ((XeScaleCallbackStruct*)PCallData)->Value.i32;_SetVertices(LMesh->Vertices.Items, LMesh->VertexSize,  LInfo);
		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateMeshSHAPE, E3dCallALL,  LScene);
		LInfo->BevelSteps = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}

	E3dWindows_RedrawByChangeFlags(LScene, LChanged);
}


//========================================================
// GUI method for the "Box" ObjectComponent class
//========================================================
static void _GUI(E3dObject* PObject, E3dObjectComponent* PInfo, void* PPanel, void* PDrawer, const int PAction)
{
	E3dObjectPanel*          LPanel = (E3dObjectPanel*)PPanel;
	XeComponentClassDrawer*  LDrawer = (XeComponentClassDrawer*)PDrawer;
	E3dInfo*                 LInfo = (E3dInfo*)PInfo;

	switch(PAction)
	{
		case E_UPDATE:
			if(LDrawer->ResourcesGUI)
			{
				E3dResourcesGUI*  LGUI = (E3dResourcesGUI*)(LDrawer->ResourcesGUI);

				_SetGUIByMode(LPanel);

				XeToggleButton_SetState(LGUI->CenterAtBottomBW, LInfo->CenterAtBottom, FALSE);
//				XeToggleButton_SetState(LGUI->TrianglesBW, LInfo->Triangles, FALSE);
//				XeToggleButton_SetState(LGUI->UVsBW, LInfo->GenerateUVs, FALSE);

				switch(LInfo->CoordinateMode)
				{
					case ModeSIZE:
						XeToggleButton_SetState(LGUI->SizeBW, TRUE, FALSE);
						XeToggleButton_SetState(LGUI->MinMaxBW, FALSE, FALSE);
					break;

					case ModeMIN_MAX:
						XeToggleButton_SetState(LGUI->SizeBW, FALSE, FALSE);
						XeToggleButton_SetState(LGUI->MinMaxBW, TRUE, FALSE);
					break;
				}

				XeScale_SetValue_Coord(LGUI->EdgeLengthXW, LInfo->EdgeLengths.X, FALSE);
				XeScale_SetValue_Coord(LGUI->EdgeLengthYW, LInfo->EdgeLengths.Y, FALSE);
				XeScale_SetValue_Coord(LGUI->EdgeLengthZW, LInfo->EdgeLengths.Z, FALSE);

				XeScale_SetValue_Coord(LGUI->MinXW, LInfo->Min.X, FALSE);
				XeScale_SetValue_Coord(LGUI->MaxXW, LInfo->Max.X, FALSE);

				XeScale_SetValue_Coord(LGUI->MinYW, LInfo->Min.Y, FALSE);
				XeScale_SetValue_Coord(LGUI->MaxYW, LInfo->Max.Y, FALSE);

				XeScale_SetValue_Coord(LGUI->MinZW, LInfo->Min.Z, FALSE);
				XeScale_SetValue_Coord(LGUI->MaxZW, LInfo->Max.Z, FALSE);

				XeScale_SetValue(LGUI->SubdivisionsXW, LInfo->Subdivisions.X, FALSE);
				XeScale_SetValue(LGUI->SubdivisionsYW, LInfo->Subdivisions.Y, FALSE);
				XeScale_SetValue(LGUI->SubdivisionsZW, LInfo->Subdivisions.Z, FALSE);

				XeScale_SetValue_Coord(LGUI->BevelRadiusW, LInfo->BevelRadius, FALSE);
				XeScale_SetValue(LGUI->BevelStepsW, LInfo->BevelSteps, FALSE);
			}
			else
			{
				XeWidget          LTopMatrixW = LDrawer->Drawer.DrawerW, LW;
				XeWidget          LIndentWs[7];int  LIndentN;       // For indenting the Scale Widgets
				XeWidget          LTraverseWs[16];int  LTraverseN;  // For TextField traversal
				EArg              Args[256];int  ArgCnt;
				E3dResourcesGUI*  LGUI;ENew(LGUI);

				LDrawer->ResourcesGUI = LGUI;

				EXeStart;
				EXeSetArg(XeNSpacingLeft, XeDrawer_LeftIndent);
				EXeSetArg(XeNSpacingRight, 4);
				EXeSetArg(XeNSpacingBottom, 4);
				Xe_SetValues(LTopMatrixW,  Args, ArgCnt);

				{
					EXeStart;
					EXeSetArg(XeNRadioBehavior, TRUE);
					EXeSetArg(XeNOrientation, XeHORIZONTAL);
					EXeSetArg(XeNSpacingX, 6);
					EXeSetArg(XeNMarginSizeY, 0);
					EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNMarginSizeY, 0);
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);
					EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
					EXeSetArg(XeNResizableY, FALSE);
					XeWidget  LTypeMatrixW;LTypeMatrixW = XeWidget_ManagedNew("", XeMatrixWidget_class, LTopMatrixW,  Args, ArgCnt);

					EXeStart;
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
					EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
					XeWidget_ManagedNew("Shape by:", XeLabelWidget_class, LTypeMatrixW,  Args, ArgCnt);

					EXeStart;
					EXeSetArg(XeNShadowThickness, 0);
					EXeSetArg(XeNHighlightThickness, 0);
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
					EXeSetArg(XeNSelectColorPtr, &Xe_HighlightRGBAiColor);
					EXeSetArg(XeNSet, (EBool)(LInfo->CoordinateMode == ModeSIZE));
					LGUI->SizeBW = LW = XeWidget_ManagedNew("Size", XeToggleButton_class, LTypeMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNShadowThickness, 0);
					EXeSetArg(XeNHighlightThickness, 0);
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
					EXeSetArg(XeNSelectColorPtr, &Xe_HighlightRGBAiColor);
					EXeSetArg(XeNSet, (EBool)(LInfo->CoordinateMode == ModeMIN_MAX));
					LGUI->MinMaxBW = LW = XeWidget_ManagedNew("Min-Max", XeToggleButton_class, LTypeMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);
				}

				{
					EXeStart;
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);
					EXeSetArg(XeNOrientation, XeHORIZONTAL);
					EXeSetArg(XeNSpacingX, 16);
					EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
					EXeSetArg(XeNResizableY, FALSE);
					XeWidget  LMatrixW = XeWidget_ManagedNew("MatrixW", XeMatrixWidget_class, LTopMatrixW,  Args, ArgCnt);

					EXeStart;
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
					EXeSetArg(XeNSelectColorPtr, &Xe_HighlightRGBAiColor);
					EXeSetArg(XeNShadowThickness, 0);
					EXeSetArg(XeNHighlightThickness, 0);
					EXeSetArg(XeNMarginTop, 0);EXeSetArg(XeNMarginBottom, 4);
					EXeSetArg(XeNSet, LInfo->CenterAtBottom);
					EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
					EXeSetArg(XeNResizableY, FALSE);
					LGUI->CenterAtBottomBW = LW = XeWidget_ManagedNew("Center at bottom", XeToggleButton_class, LMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

/*
					EXeStart;
					EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);
					EXeSetArg(XeNSelectColor, &Xe_HighlightRGBAiColor);
					EXeSetArg(XeNShadowThickness, 0);
					EXeSetArg(XeNHighlightThickness, 0);
					EXeSetArg(XeNMarginTop, 0);EXeSetArg(XeNMarginBottom, 4);
					EXeSetArg(XeNSet, LInfo->GenerateUVs);
					EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
					EXeSetArg(XeNResizableY, FALSE);
					LGUI->UVsBW = LW = XeWidget_ManagedNew("GenerateUVs", XeToggleButton_class, LMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB_GenerateUVs, (EPointer)LPanel);
*/
				}

				{
					LTraverseN = 0;
					LIndentN = 0;
					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->EdgeLengthXW = LW = XeScale_New_Coord(LTopMatrixW, "Width (X)",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->EdgeLengths.X,  0.0001, 200000.0,  1.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->EdgeLengthYW = LW = XeScale_New_Coord(LTopMatrixW, "Height (Y)",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->EdgeLengths.Y,  0.0001, 200000.0,  1.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->EdgeLengthZW = LW = XeScale_New_Coord(LTopMatrixW, "Depth (Z)",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->EdgeLengths.Z,  0.0001, 200000.0,  1.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					XeWidgets_IndentFromLeft(LIndentWs, LIndentN, 4);

					LIndentN = 0;
					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MinXW = LW = XeScale_New_Coord(LTopMatrixW, "Min X",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Min.X,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MaxXW = LW = XeScale_New_Coord(LTopMatrixW, "Max X",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Max.X,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MinYW = LW = XeScale_New_Coord(LTopMatrixW, "Min Y",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Min.Y,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MaxYW = LW = XeScale_New_Coord(LTopMatrixW, "Max Y",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Max.Y,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MinZW = LW = XeScale_New_Coord(LTopMatrixW, "Min Z",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Min.Z,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MaxZW = LW = XeScale_New_Coord(LTopMatrixW, "Max Z",  Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->Max.X,  -100000.0, 100000.0,  -100.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					XeWidgets_IndentFromLeft(LIndentWs, LIndentN, XeDrawer_LeftIndent);

					_SetGUIByMode(LPanel);

					LIndentN = 0;
					EXeStart;
					EXeSetArg(XeNTextFieldDigits, 3);
					EXeSetArg(XeNMinimum, 1);EXeSetArg(XeNMaximum, 100);
					EXeSetArg(XeNScaleMaximum, 20);
					EXeSetArg(XeNValue, LInfo->Subdivisions.X);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->SubdivisionsXW = LW = XeWidget_ManagedNew("X subdivisions", XeScaleWidget_class, LTopMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNTextFieldDigits, 3);
					EXeSetArg(XeNMinimum, 1);EXeSetArg(XeNMaximum, 100);
					EXeSetArg(XeNScaleMaximum, 20);
					EXeSetArg(XeNValue, LInfo->Subdivisions.Y);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->SubdivisionsYW = LW = XeWidget_ManagedNew("Y subdivisions", XeScaleWidget_class, LTopMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

					EXeStart;
					EXeSetArg(XeNTextFieldDigits, 3);
					EXeSetArg(XeNMinimum, 1);EXeSetArg(XeNMaximum, 100);
					EXeSetArg(XeNScaleMaximum, 20);
					EXeSetArg(XeNValue, LInfo->Subdivisions.Z);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->SubdivisionsZW = LW = XeWidget_ManagedNew("Z subdivisions", XeScaleWidget_class, LTopMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);
				}

				{
					EXeStart;
					EXeSetArg(XeNScaleLengthInPixels, 120);
					EXeSetArg(XeNTextFieldDigits, 9);
					EXeSetArg(XeNDecimalPoints, 4);
					EXeSetArg(XeNIncrement, 10);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->BevelRadiusW = LW = XeScale_New_Coord(LTopMatrixW,"BevelRadius", Args, ArgCnt);
					XeScale_SetValueAndRanges_Coord(LW,  LInfo->BevelRadius,  0.0, 200000.0,  0.0, 100.0,  FALSE);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer) LPanel);

					EXeStart;
					EXeSetArg(XeNTextFieldDigits, 3);
					EXeSetArg(XeNMinimum, 0);
					EXeSetArg(XeNMaximum, 1000);
					EXeSetArg(XeNScaleMaximum, 200);
					EXeSetArg(XeNValue, LInfo->BevelSteps);
					EXeSetArg(XeNResizableY, FALSE);
					LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->BevelStepsW = LW = XeWidget_ManagedNew("LBevelSteps", XeScaleWidget_class, LTopMatrixW, Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer) LPanel);
				}

// Indent the Scale Widgets, so they line up nicely
//
				XeWidgets_IndentFromLeft(LIndentWs, LIndentN, 0);

// Set up TextField traversal between the TextFields of the Scale Widgets
//
				XeTraversal_SetRing(LTraverseWs, LTraverseN);
			}
		break;
	}
}


//========================================
// Main callback (create new box)
//========================================
static void _MCB(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	E3dTpl_ObjectComponentActivateCB_Geometry(_ComponentClass);
}


//========================================================
// Constructor of the "Box" ObjectComponent class
//========================================================
static int _Init(E3dObject* LObject, E3dObjectComponent* PInfo)
{
	E3dInfo*  LThis = (E3dInfo*)PInfo;

	LThis->BevelRadius = 0.1;LThis->BevelSteps = 0;

	LThis->Min = E3dCoord3_s(-0.5, -0.5, -0.5);
	LThis->Max = E3dCoord3_s(0.5,  0.5,  0.5);

	LThis->EdgeLengths = E3dCoord3_s(1.0, 1.0, 1.0);

	LThis->Subdivisions = EInt32_3_s(1, 1, 1);

	LThis->CenterAtBottom = FALSE;
	LThis->Triangles = FALSE;
	LThis->GenerateUVs = TRUE;

	LThis->CoordinateMode = ModeSIZE;

	return(E_SUCCESS);
}


//========================================================
// Copy-constructor of the "Box" ObjectComponent class
//========================================================
static void _Copy(const E3dObject* PSObject, const E3dObjectComponent* PSInfo, E3dObject* LDObject, E3dObjectComponent* PDInfo)
{
	const E3dInfo*  LSInfo = (E3dInfo*)PSInfo;E3dInfo*  LDInfo = (E3dInfo*)PDInfo;

	_CopyFields(LSInfo, LDInfo);
}


//========================================================================
// No destructor for the "Box" ObjectComponent class, as we don't store
// any dynamically allocatied data in the ObjectComponent instances.
//========================================================================


//========================================
// Entry point of the plugin
//========================================
int E_PluginInit(EPlugin* PPlugin)
{
	_Plugin = PPlugin;

	{
		E3dObjectComponentClass  LClass=
		{
			.Name=        "Box",
			.StructSize=  sizeof(E3dInfo),
			.Resources=   EListS_s(_Resources),

			.Init=        _Init,
			.Copy=        _Copy,
			.Update1=      _Update1,
			.GUI=         _GUI
		};
		_ComponentClass = E3dObjectComponent_ClassRegister(&LClass);
	}

	EpM_CreateIconStates3_sp(Box);

// This is another way of adding information to the plugin
// You can also just define the symbol:
// char*	E_PluginInfo ...
//
	EFreeChkClr(PPlugin->Info);                // First, free any existing text
	PPlugin->Info = EStrDup("Box primitive");  // This will be freed when EQUINOX-3D unloads the plugin (at exit, or when the user unloads it in the plugin manager)

	if(_ComponentClass)
	{
		E_Assign(_Image_Box, _ComponentClass->Icon);
		XePushButton_AddImg3(_ToolBarButton, Box, "Tool->Create", "Box", '\0', NULL, NULL, TRUE, "Left button: Create cube or box with optional subdivisions\nRight button: dialog box for this tool", _MCB, (EPointer)0);
		_MenuButton = XePushButton_Add(Xe_App, "Menu->Create", "Cube / Box", '\0', NULL, NULL, TRUE, NULL, _MCB, (EPointer)0);
	}

	return(E_SUCCESS);
}


//========================================
// Exit method of the plugin
//========================================
int E_PluginExit(const EBool PExiting)
{
// If the plugin is being unloaded while EQX is still running, destroy the buttons we created.
// When EQX is exiting, everything will be freed automatically, so we can skip this to speed up the exit process.
//
	if(!PExiting || Xe_GUIFreeOnExit)
	{
		XeItemFree(_MenuButton);
		XeItemFree(_ToolBarButton);
	}

// Deactivate the ObjectComponent class we registered.
// We deactivate classes, rather than destroying them, because this way the user can unload / recompile and reload plugins,
// while retaining Objects in the Scene that use classes defined by that plugin!
// When the plugin is reloaded, E3dObjectComponent_ClassRegister will find and reactivate the same class.
//
	if(_ComponentClass)
	{
// If the app is exiting, it will do two passes of trying to unload plugins. In the first pass, there may be instances of _ComponentClass, so we'll defer deactivating the class to pass-2
		if(PExiting && _ComponentClass->Instances.Count > 0) return(E_BUSY);
		E3dObjectComponent_ClassDeactivate(_ComponentClass);_ComponentClass = NULL;
	}

	EpIconFree3(Box);

	return(E_SUCCESS);
}
