/*======================================================================================================*/
/* Create a cylinder or a capsule and change it interactively						*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-17 22:33:18									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <assert.h>

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


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

#include <EGUI/Dialog.h>
#include <EGUI/Menu.h>

#include <E3D/E3D.h>
#include <E3D/3DWindow.h>


static EPlugin*		_Plugin=NULL;

static EguiItem		_MenuButtons[16],
			_ToolPanelButtons[2];

static unsigned int	_NumOfMenuButtons=0,
			_NumOfToolPanelButtons=0;

enum
{
 E3dCylinderPOLYGONS=0,
 E3dCylinderNURBS,
 E3dCylinderBEZIER,
};

#define E3dRPI	(1.0/180.0*E3dPI)



static EguiItem		_Dialog=NULL;

//static Widget		_CapsuleBigW=NULL, _CylinderBigW=NULL;
static Widget		_SmoothW,
			_TopW, _BottomW, _OriginAtBottomW, _PieW, _RadiusScaleW, _HeightScaleW,
			_StartAngleScaleW, _EndAngleScaleW,
			_SidesScaleW, _RadialSectionsScaleW, _HeightSectionsScaleW;

static E3dModel*	_Model=NULL;
static E3dGeometry*	_MainGeometry=NULL;
static E3dGeometry*	_Geometry=NULL;

static E3d3DPosition*	_UnitCirclePoints=NULL;


static Arg		Args[256];
static Cardinal		ArgCnt;


extern EpCImage		Image_Cylinder;
extern EpCImage		Image_CylinderActive;
extern EpCImage		Image_CylinderArm;
extern EpCImage		Image_CylinderBig;

extern EpCImage		Image_Capsule;
extern EpCImage		Image_CapsuleActive;
extern EpCImage		Image_CapsuleArm;
extern EpCImage		Image_CapsuleBig;


enum
{
 E3dCR_SMOOTH=EguiCUSTOM0+20,
 E3dCR_TOPCAP,
 E3dCR_BOTTOMCAP,
 E3dCR_ORIGIN_AT_BOTTOM,
 E3dCR_PIE,
 E3dCR_SET_RADIUS,
 E3dCR_SET_HEIGHT,
 E3dCR_SET_START_ANGLE,
 E3dCR_SET_END_ANGLE,
 E3dCR_SET_SIDES,
 E3dCR_SET_RADIAL_SECTIONS,
 E3dCR_SET_HEIGHT_SECTIONS
};


typedef struct
{
// E3dGeometryInfo part
//
 E3dGeometryClass*	Class;

// E3dCylinderInfo part
//
 E3dCoordinate	Radius, Height, TopDomeHeight, BottomDomeHeight;
 E3dAngle	StartAngle, EndAngle;

 unsigned int	Sides, RadialSections, HeightSections;
 unsigned int	Type;

 EBool		Smooth, Side, TopCap, BottomCap, Pie, OriginAtBottom;
} E3dCylinderInfo;


#define ROffset(field) (void*)(EPtrOffset(E3dCylinderInfo, field))

static EResource _Resources[]=
{
 { "Radius",		EResFLOAT32,	ROffset(Radius), NULL },
 { "Height",		EResFLOAT32,	ROffset(Height), NULL },
 { "TopDomeHeight",	EResFLOAT32,	ROffset(TopDomeHeight), NULL },
 { "BottomDomeHeight",	EResFLOAT32,	ROffset(BottomDomeHeight), NULL },
 { "StartAngle",	EResFLOAT32,	ROffset(StartAngle), NULL },
 { "EndAngle",		EResFLOAT32,	ROffset(EndAngle), NULL },
 { "Sides"	,	EResINT,	ROffset(Sides), NULL },
 { "RadialSections",	EResINT,	ROffset(RadialSections), NULL },
 { "HeightSections",	EResINT,	ROffset(HeightSections), NULL },
 { "Type",		EResINT,	ROffset(Type), NULL },
 { "",			EResNULL,	NULL, NULL }
};


static E3dCylinderInfo	_Info;
static EBool		_CreateMode=FALSE;
static E3dGeometryPanel	_GeometryPanel;


static int	_VNum;

/*==============================================================*/
/* Set up the vertices of the unit-radius circle or arc		*/
/*==============================================================*/
static EBool _CreateUnitCircle(int LSides, float LStartAngle, float LEndAngle)
{
 E3d3DPosition*	LPoints;
 float		LAngle, LDeg;
 unsigned int	LC, LSidesN;
 EBool		LFull;

 if(_UnitCirclePoints) { EFree(_UnitCirclePoints);_UnitCirclePoints=NULL; }
 if((_UnitCirclePoints=(E3d3DPosition*)EMalloc(sizeof(E3d3DPosition)*(LSides+1)))==NULL) return(FALSE);

 LDeg=(LEndAngle-LStartAngle)/(double)LSides;

 if((LEndAngle-LStartAngle)==360.0) { LFull=TRUE;LSidesN=LSides; }
 else { LFull=FALSE;LSidesN=LSides+1; }


 for(LC=0, LPoints=_UnitCirclePoints;LC<LSidesN;LC++)
 {
  LAngle=(LDeg*LC+LStartAngle)*E3dRPI;
  LPoints[LC].X=cos(LAngle);LPoints[LC].Y=0.0;LPoints[LC].Z=sin(LAngle);
 }

 return(TRUE);
}


/*==============================================*/
/* Compute vertex coordinates of the cylinder	*/
/*==============================================*/
static void _SetVertices(E3dMesh* LMesh, E3dCylinderInfo* LCylinderInfo)
{
 E3dVertex*		LVertices=LMesh->Vertices;
 E3dVertex*		LVertex=LVertices;
 E3dUV*			LUV;
 E3dCoordinate		LX, LY, LZ, LHStep,
			LU, LV, LUStep, LVStep;
 E3d3DPosition*		LPoint;
 E3dCoordinate		LRadius, LHeight, LTopDomeHeight, LBottomDomeHeight, LRad, LRadStep;
 E3dCoordinate		LTopY, LBottomY;
 unsigned int		LSides, LRadialSections, LHeightSections;
 unsigned int		LC, LC1, LRN;
 EBool			LFull, LPie;

// E3dVertex* LVertexB=LVertex;


 LRadius=LCylinderInfo->Radius;
 LHeight=LCylinderInfo->Height;
 LTopDomeHeight=LCylinderInfo->TopDomeHeight;
 LBottomDomeHeight=LCylinderInfo->BottomDomeHeight;

 LSides=LCylinderInfo->Sides;
 LRadialSections=LCylinderInfo->RadialSections;
 LHeightSections=LCylinderInfo->HeightSections;

 LUStep=1.0/(E3dCoordinate)LSides;
 LVStep=1.0/(E3dCoordinate)LHeightSections;

 LRadStep=LRadius/(E3dCoordinate)LRadialSections;

 if((LCylinderInfo->EndAngle-LCylinderInfo->StartAngle)==360.0) LFull=TRUE;
 else LFull=FALSE;

 if((!LFull)&&(LCylinderInfo->Pie)) LPie=TRUE;
 else LPie=FALSE;


 if(LCylinderInfo->OriginAtBottom) { LY=LHeight;LTopY=LHeight;LBottomY=0.0; }
 else { LY=LHeight*0.5;LTopY=LHeight*0.5;LBottomY=-LHeight*0.5; }

 switch(LCylinderInfo->Type)
 {
  case E3dCylinderPOLYGONS:
   LHStep=LHeight/(double)LHeightSections;

   _CreateUnitCircle(LCylinderInfo->Sides, LCylinderInfo->StartAngle, LCylinderInfo->EndAngle);

   if(LMesh->UVs) LMesh->UVs=(E3dUV*)ERealloc(LMesh->UVs, sizeof(E3dUV) * LMesh->NumOfVertices);
   else LMesh->UVs=(E3dUV*)EMalloc(sizeof(E3dUV) * LMesh->NumOfVertices);

   LUV=LMesh->UVs;

// Sides
//
   if(LPie)
   {
    if(LRadialSections<1) LRadialSections=1;
    LSides++;
   }
   else
   {
    if(!LFull) LSides++;
   }

   LV=0.0;
   for(LC=0;LC<=LHeightSections;LC++, LV+=LVStep)
   {
    LPoint=_UnitCirclePoints;
    LU=0.0;
    for(LC1=0;LC1<LSides;LC1++, LU+=LUStep)
    {
     LVertex->X=LRadius*LPoint->X;LVertex->Y=LY;LVertex->Z=LRadius*LPoint->Z;

     LUV->U=LU;
     LUV->V=LV;
     LUV++;

     LVertex++;LPoint++;
    }
    LY-=LHStep;
   }

   LY=LTopY;
   LRN=LRadialSections-1;

   if(LRadialSections>0)
   {
// Radial segments in top cap
//
    if(LPie||(LCylinderInfo->TopCap)) { LVertex->X=0.0;LVertex->Y=LY+LTopDomeHeight*LRadius;LVertex->Z=0.0;LVertex++; }

    if(LCylinderInfo->TopCap)
    {
     LRad=LRadStep;

     if((LRadialSections>1)&&(E3dM_ABS(LTopDomeHeight)>0.0))
     {
      E3dCoordinate	LAngle, LAngleStep, LHt;

      LAngleStep=E3dPI*0.5/((E3dCoordinate)LRadialSections);
      LAngle=E3dPI*0.5-LAngleStep;

      for(LC=0;LC<LRN;LC++)
      {
       LRad=cos(LAngle)*LRadius;LHt=LRadius*sin(LAngle);
       LPoint=_UnitCirclePoints;
       for(LC1=0;LC1<LSides;LC1++)
       {
	LVertex->X=LRad*LPoint->X;LVertex->Y=LY+LTopDomeHeight*LHt;LVertex->Z=LRad*LPoint->Z;
	LVertex++;LPoint++;
       }
       LAngle-=LAngleStep;
      }
     }
     else
     {
      for(LC=0;LC<LRN;LC++)
      {
       LPoint=_UnitCirclePoints;
       for(LC1=0;LC1<LSides;LC1++)
       {
	LVertex->X=LRad*LPoint->X;LVertex->Y=LY;LVertex->Z=LRad*LPoint->Z;
	LVertex++;LPoint++;
       }
       LRad+=LRadStep;
      }
     }
    }


    LY=LBottomY;

// Radial segments in bottom cap
//
    if(LPie||(LCylinderInfo->BottomCap)) { LVertex->X=0.0;LVertex->Y=LY-LBottomDomeHeight*LRadius;LVertex->Z=0.0;LVertex++; }
    if(LCylinderInfo->BottomCap)
    {
     LRad=LRadStep;

     if((LRadialSections>1)&&(E3dM_ABS(LTopDomeHeight)>0.0))
     {
      E3dCoordinate	LAngle, LAngleStep, LHt;

      LAngleStep=E3dPI*0.5/((E3dCoordinate)LRadialSections);
      LAngle=E3dPI*0.5-LAngleStep;

      for(LC=0;LC<LRN;LC++)
      {
       LRad=cos(LAngle)*LRadius;LHt=LRadius*sin(LAngle);
       LPoint=_UnitCirclePoints;
       for(LC1=0;LC1<LSides;LC1++)
       {
	LVertex->X=LRad*LPoint->X;LVertex->Y=LY-LTopDomeHeight*LHt;LVertex->Z=LRad*LPoint->Z;
	LVertex++;LPoint++;
       }
       LAngle-=LAngleStep;
      }
     }
     else
     {
      for(LC=0;LC<LRN;LC++)
      {
       LPoint=_UnitCirclePoints;
       for(LC1=0;LC1<LSides;LC1++)
       {
	LVertex->X=LRad*LPoint->X;LVertex->Y=LY;LVertex->Z=LRad*LPoint->Z;
	LVertex++;LPoint++;
       }
       LRad+=LRadStep;
      }
     }
    }
   }

// Inner Vertices on the two "pie cut" sides
//
   if((LPie)&&(LHeightSections>1))
   {
    LY=LTopY-LHStep;
    LPoint=_UnitCirclePoints;
    LX=LPoint->X;LZ=LPoint->Z;
    for(LC=1;LC<LHeightSections;LC++)
    {
     LRad=0.0;
     for(LC1=0;LC1<LRadialSections;LC1++)
     {
      LVertex->X=LRad*LX;LVertex->Y=LY;LVertex->Z=LRad*LZ;
      LVertex++;LRad+=LRadStep;
     }
     LY-=LHStep;
    }

    if(LRadialSections>1)
    {
     unsigned LN1=LRadialSections-1;

     LY=LTopY-LHStep;
     LPoint=_UnitCirclePoints+LSides-1;

     LX=LPoint->X;LZ=LPoint->Z;
     for(LC=1;LC<LHeightSections;LC++)
     {
      LRad=LRadStep;
      for(LC1=0;LC1<LN1;LC1++)
      {
       LVertex->X=LRad*LX;LVertex->Y=LY;LVertex->Z=LRad*LZ;
       LVertex++;LRad+=LRadStep;
      }
      LY-=LHStep;
     }
    }
   }

//printf("#D: %d\n", LVertex-LVertexB);fflush(stdout);


// This is for debugging only
// If an existing cylinder is edited, _VNum mignt not be initialized, this is normal!!!
//
//if((LVertex-LVertexB)>_VNum) assert(0);

  break;
 }
}




void _CreatePolygonsForCylinder(E3dCylinderInfo* LCylinderInfo, E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, unsigned int LNSideVertices)
{
 E3dPolygon*	LPolygon=LPolyGroup->Polygons;
 E3dVertex*	LVertices=LMesh->Vertices;
 E3dVertex*	LVertex;
 E3d3DPosition*	LPoints;
 E3dVertexNode*	LVertexNode;
 E3dCoordinate	LSideHeightH, LDomeHeight, LInvR;
 unsigned int	LC, LH, LSides=LNSideVertices, LV, LVC, LRC, LRN,
		LRadialSections=LCylinderInfo->RadialSections,
		LHeightSections=LCylinderInfo->HeightSections;

 LInvR=1.0/LCylinderInfo->Radius;
 LV=0;
// Side
//
 if(LCylinderInfo->Side)
 {
//LMesh->PolyGroups[0]->NumOfPolygons+=LNSideVertices*LHeightSections;

  LPoints=_UnitCirclePoints;
  for(LC=0;LC<LHeightSections;LC++, LV+=LNSideVertices)
  {
// Use last vtx on this section
//
   E3d_PolygonSet(LPolygon, 4, LNSideVertices-1+LV, LV, LV+LNSideVertices, LV+LNSideVertices-1+LNSideVertices);
   LVertexNode=LPolygon->VertexNodes;
   E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

   LVertexNode->Normal.X=LPoints[LNSideVertices-1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LNSideVertices-1].Z;
   LVertexNode++;
   LVertexNode->Normal.X=LPoints[0].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[0].Z;
   LVertexNode++;
   LVertexNode->Normal.X=LPoints[0].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[0].Z;
   LVertexNode++;
   LVertexNode->Normal.X=LPoints[LNSideVertices-1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LNSideVertices-1].Z;
   LPolygon++;

   for(LH=1;LH<LSides;LH++)
   {
    E3d_PolygonSet(LPolygon, 4, LH-1+LV, LH+LV, LV+LH+LNSideVertices, LV+LH-1+LNSideVertices);
    LVertexNode=LPolygon->VertexNodes;
    LVertexNode->Normal.X=LPoints[LH-1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH-1].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH-1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH-1].Z;
    LVertexNode=LPolygon->VertexNodes;
    E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);
    LPolygon++;
   }
  }
 }

 if(LCylinderInfo->TopCap)
 {
  if(LRadialSections==0)
  {
   if((LVertexNode=E3d_PolygonVertexNodesAllocate(LPolygon, LNSideVertices))!=NULL)
   {
    for(LC=0, LH=LNSideVertices-1;LC<LNSideVertices;LC++, LVertexNode++)
    {
     LVertexNode->VertexID=LH;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;

     LH--;
    }
    LPolygon->NumOfVertices=LPolygon->NumOfExteriorVertices=LNSideVertices;
    LPolygon->Normal.X=0.0;LPolygon->Normal.Y=1.0;LPolygon->Normal.Z=0.0;
    LPolygon++;
   }
  }
  else
  {
   unsigned int	LCenterV, LNextCircleV;

   LCenterV=LNSideVertices*(LHeightSections+1);

   if(LRadialSections==1) LNextCircleV=0;
   else LNextCircleV=LCenterV+1;

   LV=LNextCircleV;
   if((LDomeHeight=LCylinderInfo->TopDomeHeight)==0.0)
   {				// Flat top
    for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
    {
     if(LVC<(LNSideVertices-1)) E3d_PolygonSetAsTriangle(LPolygon, LV+1, LV, LCenterV);
     else E3d_PolygonSetAsTriangle(LPolygon, LNextCircleV, LV, LCenterV);
     LPolygon->Normal.X=0.0;LPolygon->Normal.Y=1.0;LPolygon->Normal.Z=0.0;

     LVertexNode=LPolygon->VertexNodes;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;

     LPolygon++;
    }
   }
   else
   {				// Rounded top
    if(LCylinderInfo->OriginAtBottom) LSideHeightH=LCylinderInfo->Height;
    else LSideHeightH=LCylinderInfo->Height*0.5;

    for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
    {
     if(LVC<(LNSideVertices-1)) E3d_PolygonSetAsTriangle(LPolygon, LV+1, LV, LCenterV);
     else E3d_PolygonSetAsTriangle(LPolygon, LNextCircleV, LV, LCenterV);

     LVertexNode=LPolygon->VertexNodes;
     E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;

     LPolygon++;
    }
   }

   if(LRadialSections>1)
   {
    LRN=LRadialSections-1;

    if(LDomeHeight==0.0)
    {				// Flat top
     for(LRC=0;LRC<LRN;LRC++)
     {
      LV=LNextCircleV;
      if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
      else LNextCircleV=0;			// Top outer side vertices start at index 0

      for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
      {
       if(LVC<(LNSideVertices-1)) E3d_PolygonSet(LPolygon, 4, LV+1, LVC+LNextCircleV+1, LVC+LNextCircleV, LV);
       else E3d_PolygonSet(LPolygon, 4, LV-LNSideVertices+1, LVC+LNextCircleV-LNSideVertices+1, LVC+LNextCircleV, LV);

       LPolygon->Normal.X=0.0;LPolygon->Normal.Y=1.0;LPolygon->Normal.Z=0.0;

       LVertexNode=LPolygon->VertexNodes;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;
       LPolygon++;
      }
     }
    }
    else
    {				// Rounded top
     if(LCylinderInfo->OriginAtBottom) LSideHeightH=LCylinderInfo->Height;
     else LSideHeightH=LCylinderInfo->Height*0.5;

     for(LRC=0;LRC<LRN;LRC++)
     {
      LV=LNextCircleV;
      if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
      else LNextCircleV=0;			// Top outer side vertices start at index 0

      for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
      {
       if(LVC<(LNSideVertices-1)) E3d_PolygonSet(LPolygon, 4, LV+1, LVC+LNextCircleV+1, LVC+LNextCircleV, LV);
       else E3d_PolygonSet(LPolygon, 4, LV-LNSideVertices+1, LVC+LNextCircleV-LNSideVertices+1, LVC+LNextCircleV, LV);

       LVertexNode=LPolygon->VertexNodes;
       E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;
       LPolygon++;
      }
     }
    }

   }

  }
 }

 if(LCylinderInfo->BottomCap)
 {
  if(LRadialSections==0)
  {
   if((LVertexNode=E3d_PolygonVertexNodesAllocate(LPolygon, LNSideVertices))!=NULL)
   {
    LV=LNSideVertices*LHeightSections;
    for(LVC=0;LVC<LNSideVertices;LVC++, LV++, LVertexNode++)
    {
     LVertexNode->VertexID=LV;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;
    }
    LPolygon->NumOfVertices=LPolygon->NumOfExteriorVertices=LNSideVertices;
    LPolygon->Normal.X=0.0;LPolygon->Normal.Y=-1.0;LPolygon->Normal.Z=0.0;
    LPolygon++;
   }
  }
  else
  {
   unsigned int	LCenterV, LNextCircleV;

   LCenterV=LNSideVertices*(LHeightSections+1+LRadialSections-1)+1;

   if(LRadialSections==1) LNextCircleV=LNSideVertices*LHeightSections;
   else LNextCircleV=LCenterV+1;

   LV=LNextCircleV;

   if((LDomeHeight=LCylinderInfo->TopDomeHeight)==0.0)
   {				// Flat bottom
    for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
    {
     if(LVC<(LNSideVertices-1)) E3d_PolygonSetAsTriangle(LPolygon, LCenterV, LV, LV+1);
     else E3d_PolygonSetAsTriangle(LPolygon, LCenterV, LV, LNextCircleV);
     LPolygon->Normal.X=0.0;LPolygon->Normal.Y=-1.0;LPolygon->Normal.Z=0.0;

     LVertexNode=LPolygon->VertexNodes;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;

     LPolygon++;
    }
   }
   else
   {				// Rounded bottom
    if(LCylinderInfo->OriginAtBottom) LSideHeightH=0.0;
    else LSideHeightH=-LCylinderInfo->Height*0.5;

    for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
    {
     if(LVC<(LNSideVertices-1)) E3d_PolygonSetAsTriangle(LPolygon, LCenterV, LV, LV+1);
     else E3d_PolygonSetAsTriangle(LPolygon, LCenterV, LV, LNextCircleV);

     LVertexNode=LPolygon->VertexNodes;
     E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;

     LPolygon++;
    }
   }

   if(LRadialSections>1)
   {
    LRN=LRadialSections-1;

    if(LDomeHeight==0.0)
    {				// Flat bottom
     for(LRC=0;LRC<LRN;LRC++)
     {
      LV=LNextCircleV;
      if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
      else LNextCircleV=LNSideVertices*LHeightSections;	// Bottom-outer side vertices start at index LNSideVertices*LHeightSections

      for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
      {
       if(LVC<(LNSideVertices-1)) E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV+1, LV+1);
       else E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV-LNSideVertices+1, LV-LNSideVertices+1);

       LPolygon->Normal.X=0.0;LPolygon->Normal.Y=-1.0;LPolygon->Normal.Z=0.0;

       LVertexNode=LPolygon->VertexNodes;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
       LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;
       LPolygon++;
      }
     }
    }
    else
    {				// Rounded bottom
     if(LCylinderInfo->OriginAtBottom) LSideHeightH=0.0;
     else LSideHeightH=-LCylinderInfo->Height*0.5;

     for(LRC=0;LRC<LRN;LRC++)
     {
      LV=LNextCircleV;
      if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
      else LNextCircleV=LNSideVertices*LHeightSections;	// Bottom-outer side vertices start at index LNSideVertices*LHeightSections

      for(LVC=0;LVC<LNSideVertices;LVC++, LV++)
      {
       if(LVC<(LNSideVertices-1)) E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV+1, LV+1);
       else E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV-LNSideVertices+1, LV-LNSideVertices+1);

       LVertexNode=LPolygon->VertexNodes;
       E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

  
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
       LVertex=LVertices+LVertexNode->VertexID;
       LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;
       LPolygon++;
      }
     }
    }


   }

  }
 }
}



static void _CreatePolygonsForPie(E3dCylinderInfo* LCylinderInfo, E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, unsigned int LSides, unsigned int LNSideVertices)
{
 E3dPolygon*	LPolygon=LPolyGroup->Polygons;
 E3dVertex*	LVertices=LMesh->Vertices;
 E3dVertex*	LVertex;
 E3d3DPosition*	LPoints;
 E3dVertexNode*	LVertexNode;
 E3dCoordinate	LSideHeightH, LDomeHeight, LInvR;
 unsigned int	LC, LH, LV, LVC, LRC, LRN,
		LRadialSections=LCylinderInfo->RadialSections,
		LHeightSections=LCylinderInfo->HeightSections;

 if(LRadialSections<1) LRadialSections=1;

 LInvR=1.0/LCylinderInfo->Radius;
 LV=0;
// Side
//
printf("Pie\n");fflush(stdout);
 if(LCylinderInfo->Side)
 {
  LPoints=_UnitCirclePoints;
  for(LC=0;LC<LHeightSections;LC++, LV+=LNSideVertices)
  {
   for(LH=0;LH<LSides;LH++)
   {
    E3d_PolygonSet(LPolygon, 4, LH+LV, LH+1+LV, LV+LH+1+LNSideVertices, LV+LH+LNSideVertices);
    LVertexNode=LPolygon->VertexNodes;
    LVertexNode->Normal.X=LPoints[LH].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH+1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH+1].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH+1].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH+1].Z;
    LVertexNode++;
    LVertexNode->Normal.X=LPoints[LH].X;LVertexNode->Normal.Y=0.0;LVertexNode->Normal.Z=LPoints[LH].Z;
    LVertexNode=LPolygon->VertexNodes;
    E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);
    LPolygon++;
   }
  }
 }

 if(LCylinderInfo->TopCap)
 {
  unsigned int	LCenterV, LNextCircleV;

  LCenterV=LNSideVertices*(LHeightSections+1);

  if(LRadialSections==1) LNextCircleV=0;
  else LNextCircleV=LCenterV+1;

// Triangles in the middle
//
  LV=LNextCircleV;
  if((LDomeHeight=LCylinderInfo->TopDomeHeight)==0.0)
  {				// Flat top
   for(LVC=0;LVC<LSides;LVC++, LV++)
   {
    E3d_PolygonSetAsTriangle(LPolygon, LV+1, LV, LCenterV);
    LPolygon->Normal.X=0.0;LPolygon->Normal.Y=1.0;LPolygon->Normal.Z=0.0;

    LVertexNode=LPolygon->VertexNodes;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;

    LPolygon++;
   }
  }
  else
  {				// Rounded top
   if(LCylinderInfo->OriginAtBottom) LSideHeightH=LCylinderInfo->Height;
   else LSideHeightH=LCylinderInfo->Height*0.5;

   for(LVC=0;LVC<LSides;LVC++, LV++)
   {
    E3d_PolygonSetAsTriangle(LPolygon, LV+1, LV, LCenterV);

    LVertexNode=LPolygon->VertexNodes;
    E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;

    LPolygon++;
   }
  }

  LRN=LRadialSections-1;

  if(LDomeHeight==0.0)
  {				// Flat top
   for(LRC=0;LRC<LRN;LRC++)
   {
    LV=LNextCircleV;
    if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
    else LNextCircleV=0;			// Top outer side vertices start at index 0

    for(LVC=0;LVC<LSides;LVC++, LV++)
    {
     E3d_PolygonSet(LPolygon, 4, LV+1, LVC+LNextCircleV+1, LVC+LNextCircleV, LV);

     LPolygon->Normal.X=0.0;LPolygon->Normal.Y=1.0;LPolygon->Normal.Z=0.0;

     LVertexNode=LPolygon->VertexNodes;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=1.0;LVertexNode->Normal.Z=0.0;
     LPolygon++;
    }
   }
  }
  else
  {				// Rounded top
   if(LCylinderInfo->OriginAtBottom) LSideHeightH=LCylinderInfo->Height;
   else LSideHeightH=LCylinderInfo->Height*0.5;

   for(LRC=0;LRC<LRN;LRC++)
   {
    LV=LNextCircleV;
    if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
    else LNextCircleV=0;			// Top outer side vertices start at index 0

    for(LVC=0;LVC<LSides;LVC++, LV++)
    {
     E3d_PolygonSet(LPolygon, 4, LV+1, LVC+LNextCircleV+1, LVC+LNextCircleV, LV);

     LVertexNode=LPolygon->VertexNodes;
     E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;
     LPolygon++;
    }
   }
  }
 }

 if(LCylinderInfo->BottomCap)
 {
  unsigned int	LCenterV, LNextCircleV;

  LCenterV=LNSideVertices*(LHeightSections+1+LRadialSections-1)+1;

  if(LRadialSections==1) LNextCircleV=LNSideVertices*LHeightSections;
  else LNextCircleV=LCenterV+1;

  LV=LNextCircleV;

  if((LDomeHeight=LCylinderInfo->TopDomeHeight)==0.0)
  {				// Flat bottom
   for(LVC=0;LVC<LSides;LVC++, LV++)
   {
    E3d_PolygonSet(LPolygon, 3, LCenterV, LV, LV+1);
    LPolygon->Normal.X=0.0;LPolygon->Normal.Y=-1.0;LPolygon->Normal.Z=0.0;

    LVertexNode=LPolygon->VertexNodes;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
    LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;

    LPolygon++;
   }
  }
  else
  {				// Rounded bottom
   if(LCylinderInfo->OriginAtBottom) LSideHeightH=0.0;
   else LSideHeightH=-LCylinderInfo->Height*0.5;

   for(LVC=0;LVC<LSides;LVC++, LV++)
   {
    E3d_PolygonSetAsTriangle(LPolygon, LCenterV, LV, LV+1);

    LVertexNode=LPolygon->VertexNodes;
    E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);

    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
    LVertex=LVertices+LVertexNode->VertexID;
    LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;

    LPolygon++;
   }
  }

  LRN=LRadialSections-1;

  if(LDomeHeight==0.0)
  {				// Flat bottom
   for(LRC=0;LRC<LRN;LRC++)
   {
    LV=LNextCircleV;
    if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
    else LNextCircleV=LNSideVertices*LHeightSections;	// Bottom-outer side vertices start at index LNSideVertices*LHeightSections

    for(LVC=0;LVC<LSides;LVC++, LV++)
    {
     E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV+1, LV+1);

     LPolygon->Normal.X=0.0;LPolygon->Normal.Y=-1.0;LPolygon->Normal.Z=0.0;

     LVertexNode=LPolygon->VertexNodes;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;LVertexNode++;
     LVertexNode->Normal.X=0.0;LVertexNode->Normal.Y=-1.0;LVertexNode->Normal.Z=0.0;
     LPolygon++;
    }
   }
  }
  else
  {				// Rounded bottom
   if(LCylinderInfo->OriginAtBottom) LSideHeightH=0.0;
   else LSideHeightH=-LCylinderInfo->Height*0.5;

   for(LRC=0;LRC<LRN;LRC++)
   {
    LV=LNextCircleV;
    if(LRC<(LRN-1)) LNextCircleV=LV+LNSideVertices;
    else LNextCircleV=LNSideVertices*LHeightSections;	// Bottom-outer side vertices start at index LNSideVertices*LHeightSections

    for(LVC=0;LVC<LSides;LVC++, LV++)
    {
     E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV+1, LV+1);

     LVertexNode=LPolygon->VertexNodes;
     E3d_VertexNormal(&(LPolygon->Normal), LVertices+LVertexNode[0].VertexID, LVertices+LVertexNode[1].VertexID, LVertices+LVertexNode[2].VertexID);


     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;LVertexNode++;
     LVertex=LVertices+LVertexNode->VertexID;
     LVertexNode->Normal.X=LVertex->X*LInvR;LVertexNode->Normal.Y=(LVertex->Y-LSideHeightH)*LInvR;LVertexNode->Normal.Z=LVertex->Z*LInvR;
     LPolygon++;
    }
   }
  }
 }

// Extra sides
//
 {
  int	LNextCircleV;

  LRN=LRadialSections-1;
  LNextCircleV=LNSideVertices;
  for(LRC=0;LRC<LRN;LRC++)
  {
   for(LVC=0;LVC<LHeightSections;LVC++)
   {
//   E3d_PolygonSet(LPolygon, 4, LV, LVC+LNextCircleV, LVC+LNextCircleV+1, LV+1);
   }
  }
 }
}


/*======================================*/
/* Get a cylinder			*/
/*======================================*/
E3dModel* _Get(E3dModel* LModel, E3dGeometry* LGeometry, E3dCylinderInfo* LCylinderInfoV, unsigned int LFlags)
{
 E3dMesh*		LMesh;
 E3dVertex*		LVertex;
 E3dPolyGroup*		LPolyGroup;
 E3dPolygon*		LPolygon;
 unsigned int		LVNum=0, LPNum=0;
 E3dCoordinate		LRadius, LHeight;
 E3dAngle		LStartAngle, LEndAngle;
 int			LSidesN=0;
 int			LSides, LRadialSections, LHeightSections;
 E3dCylinderInfo*	LCylinderInfo;
 EBool			LFull, LPie;


 if(LGeometry==NULL)
 {
  if((LModel=E3d_ModelAllocate("Cylinder"))==NULL) return(NULL);
  if((LMesh=(E3dMesh*)E3d_ModelAddGeometry(LModel, E3dGEO_MESH, "cylinder"))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
  LMesh->LockCount=1;

  LCylinderInfo=(E3dCylinderInfo*)E3d_GeometryInfoAdd((E3dGeometry*)LMesh, LCylinderInfoV->Class);
  if(LCylinderInfo)
  {
   memcpy(LCylinderInfo, LCylinderInfoV, sizeof(E3dCylinderInfo));
  }
  if((LPolyGroup=E3d_MeshAddPolyGroup(LMesh))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
  LPolyGroup->VertexNormalType=E3dNormalPROCESS;
 }
 else
 {
  LMesh=(E3dMesh*)LGeometry;
  LCylinderInfo=LCylinderInfoV;

  LPolyGroup=LMesh->PolyGroups[0];
 }

 LRadius=LCylinderInfo->Radius;
 LHeight=LCylinderInfo->Height;
 LSides=LCylinderInfo->Sides;
 LRadialSections=LCylinderInfo->RadialSections;
 LHeightSections=LCylinderInfo->HeightSections;
 LStartAngle=LCylinderInfo->StartAngle;
 LEndAngle=LCylinderInfo->EndAngle;

 if((LEndAngle-LStartAngle)==360.0) LFull=TRUE;
 else LFull=FALSE;

 if(LFull||(!(LCylinderInfo->Pie))) LPie=FALSE;
 else LPie=TRUE;

 switch(LCylinderInfo->Type)
 {
  case E3dCylinderPOLYGONS:
   LVNum=LPNum=0;

// Get number of Vertices and Polygons and initialize the unit cross-section
//
   if(LFull||(!(LCylinderInfo->Pie)))
   {
    if(LFull) LSidesN=LSides;
    else LSidesN=LSides+1;

    if(LCylinderInfo->Side)
    {
     LVNum+=LSidesN*(LHeightSections+1);
     LPNum+=LSidesN*LHeightSections;
    }

    if(LRadialSections<1)
    {
     if(LCylinderInfo->TopCap) LPNum++;
     if(LCylinderInfo->BottomCap) LPNum++;
    }
    else
    {
     if(LCylinderInfo->TopCap)
     {
      LVNum+=((LRadialSections-1)*LSidesN+1);		// "+1" middle vertex
      LPNum+=LRadialSections*LSidesN;
     }

     if(LCylinderInfo->BottomCap)
     {
      LVNum+=((LRadialSections-1)*LSidesN+1);		// "+1" middle vertex
      LPNum+=LRadialSections*LSidesN;
     }
    }
   }
   else
   {
// "Pie"
//
    LPNum=LSides*LHeightSections;
    LSidesN=LSides+1;

    if(LRadialSections<1) LRadialSections=1;
    LVNum=(LSides+1+(LRadialSections-1)*2+1)*(LHeightSections+1);

    if(LCylinderInfo->TopCap) { LVNum+=(LSides-1)*(LRadialSections-1);LPNum+=LRadialSections*LSides; }
    if(LCylinderInfo->BottomCap) { LVNum+=(LSides-1)*(LRadialSections-1);LPNum+=LRadialSections*LSides; }
   }

   _CreateUnitCircle(LSides, LStartAngle, LEndAngle);

   _VNum=LVNum;
  break;
 }

 if(LVNum==LMesh->NumOfVertices) LVertex=LMesh->Vertices;
 else
 {
  if(LMesh->Vertices) E3d_MeshFreeVertices(LMesh);
  LMesh->Vertices=E3d_VerticesAllocate(LMesh->NumOfVertices=LVNum, TRUE);
 }
 if(LMesh->Vertices)
 {
  switch(LCylinderInfo->Type)
  {
   case E3dCylinderPOLYGONS:
    LVertex=LMesh->Vertices;
    if(LPNum==LPolyGroup->NumOfPolygons) LPolygon=LPolyGroup->Polygons;
    else
    {
     if(LPolyGroup->Polygons) E3d_PolyGroupFreePolygons(LPolyGroup);
     LPolygon=LPolyGroup->Polygons=E3d_PolygonsAllocate(LPolyGroup->NumOfPolygons=LPNum);
    }

    _SetVertices(LMesh, LCylinderInfo);

    if(LPolygon)
    {
     if(!LPie) _CreatePolygonsForCylinder(LCylinderInfo, LMesh, LPolyGroup, LSidesN);
     else _CreatePolygonsForPie(LCylinderInfo, LMesh, LPolyGroup, LSides, LSidesN);

     if(LCylinderInfo->Smooth) LPolyGroup->Flags|=E3dUSE_VERTEX_NORMALS;
     else LPolyGroup->Flags&=0xFFFFFFFF-E3dUSE_VERTEX_NORMALS;
     LPolyGroup->DiscontinuityAngle=60.0;

     E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, LFlags&(E3dGF_ALL-E3dGF_CALL_DESTROYPROCS));
     return(LModel);
    }
   break;
  }
 }
 return(NULL);
}


/*======================================*/
/* Set GUI for cylinder type		*/
/*======================================*/
static void _SetGUIToType(E3dCylinderInfo* LCylinderInfo)
{
 EWidthAlignRec	LWAs[6];
 int		LXSize, LC, LN;

 switch(LCylinderInfo->Type)
 {
  case E3dCylinderNURBS:
  case E3dCylinderPOLYGONS:
   LN=0;
   XtVaGetValues(LWAs[LN].W=_RadiusScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   XtVaGetValues(LWAs[LN].W=_HeightScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   XtVaGetValues(LWAs[LN].W=_StartAngleScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   XtVaGetValues(LWAs[LN].W=_EndAngleScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   for(LC=1, LXSize=LWAs[0].XSize;LC<LN;LC++) { if(LWAs[LC].XSize>LXSize) LXSize=LWAs[LC].XSize; }
   for(LC=0;LC<LN;LC++) { XtVaSetValues(LWAs[LC].W, XeNleftOffset, LXSize-LWAs[LC].XSize+6, NULL); }

   LN=0;
   XtVaGetValues(LWAs[LN].W=_SidesScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   XtVaGetValues(LWAs[LN].W=_RadialSectionsScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   XtVaGetValues(LWAs[LN].W=_HeightSectionsScaleW, XeNlabelWidth, &(LWAs[LN].XSize), NULL);LN++;
   for(LC=1, LXSize=LWAs[0].XSize;LC<LN;LC++) { if(LWAs[LC].XSize>LXSize) LXSize=LWAs[LC].XSize; }
   for(LC=0;LC<LN;LC++) { XtVaSetValues(LWAs[LC].W, XeNleftOffset, LXSize-LWAs[LC].XSize+6, NULL); }
  break;
 }
}


/*======================================*/
/* Set Cylinder type			*/
/*======================================*/
static void _CBSetType(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
 E3dCylinderInfo*	LCylinderInfo=(E3dCylinderInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

 if(LCylinderInfo->Type!=(int)LClientData)
 {
  if(_UnitCirclePoints) { EFree(_UnitCirclePoints);_UnitCirclePoints=NULL; }
  LCylinderInfo->Type=(int)LClientData;
  _SetGUIToType(LCylinderInfo);

  _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);

  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 }
}


/*======================================*/
/* Update the dialog			*/
/*======================================*/
static void _UpdateDialog(E3dCylinderInfo* LCylinderInfo)
{
 E3d_GeometryPanelUpdate(&_GeometryPanel, _MainGeometry);

 XeToggleButtonSetState(_SmoothW, LCylinderInfo->Smooth, False);

/*
 if(LCylinderInfo->TopDomeHeight==0.0) { XtManageChild(_CylinderBigW); XtUnmanageChild(_CapsuleBigW); }
 else { XtUnmanageChild(_CylinderBigW); XtManageChild(_CapsuleBigW); }
*/

 XeToggleButtonSetState(_TopW, LCylinderInfo->TopCap, False);
 XeToggleButtonSetState(_BottomW, LCylinderInfo->BottomCap, False);
 XeToggleButtonSetState(_OriginAtBottomW, LCylinderInfo->OriginAtBottom, False);
 XeToggleButtonSetState(_PieW, LCylinderInfo->Pie, False);

 XeScaleSetValueD(_RadiusScaleW, LCylinderInfo->Radius, False);
 XeScaleSetValueD(_HeightScaleW, LCylinderInfo->Height, False);
 XeScaleSetValueD(_StartAngleScaleW, LCylinderInfo->StartAngle, False);
 XeScaleSetValueD(_EndAngleScaleW, LCylinderInfo->EndAngle, False);
 XeScaleSetValue(_SidesScaleW, LCylinderInfo->Sides, False);
 XeScaleSetValue(_RadialSectionsScaleW, LCylinderInfo->RadialSections, False);
 XeScaleSetValue(_HeightSectionsScaleW, LCylinderInfo->HeightSections, False);

 _SetGUIToType(LCylinderInfo);
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _DCB(EguiItem LW, EPointer LClientData, EPointer LCallData)
{
 switch((int)LClientData)
 {
  case EguiOK:
   E3dTpl_GeoDoneEditing(_);

   EGUI_UndisplayShell(_Dialog);_Plugin->LockCount-=1;
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   if(_UnitCirclePoints) { EFree(_UnitCirclePoints);_UnitCirclePoints=NULL; }
  break;

  case EguiADD:
   E3dTpl_GeoDoneEditing(_);

   _CreateMode=TRUE;
   if(_UnitCirclePoints) { EFree(_UnitCirclePoints);_UnitCirclePoints=NULL; }

   if((_Model=_Get(NULL, NULL, &_Info, E3dGF_ALL))!=NULL)
   {
    _MainGeometry=_Geometry=_Model->Geometries[0];
    _MainGeometry->AutoLOD=FALSE;
    E3d_SceneAddModelHrc(E3d_Scene, _Model);
    E3dp_SceneLayoutOnSchematics(E3d_Scene);
   }
   _UpdateDialog(&_Info);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case EguiCANCEL:
   if(_Geometry->LockCount==1)
   {
    if(_CreateMode) { E3d_SceneRemoveModelHrc(E3d_Scene, _Model);E3d_ModelHrcFree(_Model, TRUE); }
    else E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_LOCKUNLOCK);
   }

   E3dTpl_GeoDoneEditing(_);

   EGUI_UndisplayShell(_Dialog);_Plugin->LockCount-=1;
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);

   if(_UnitCirclePoints) { EFree(_UnitCirclePoints);_UnitCirclePoints=NULL; }
  break;
 }
}


/*======================================*/
/* Dialog Xt callback			*/
/*======================================*/
static void _XtDCB(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
 E3dMesh*		LMesh=(E3dMesh*)_Geometry;
 E3dCylinderInfo*	LCylinderInfo=(E3dCylinderInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);


 switch((int)LClientData)
 {
  case E3dCR_SMOOTH:
   LCylinderInfo->Smooth=((XeToggleButtonCallbackStruct*)LCallData)->set;
   if(LCylinderInfo->Smooth) LMesh->PolyGroups[0]->Flags|=E3dUSE_VERTEX_NORMALS;
   else LMesh->PolyGroups[0]->Flags&=0xFFFFFFFF-E3dUSE_VERTEX_NORMALS;
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_NORMALS);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_TOPCAP:
   LCylinderInfo->TopCap=(((XeToggleButtonCallbackStruct*)LCallData)->set);
   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_BOTTOMCAP:
   LCylinderInfo->BottomCap=(((XeToggleButtonCallbackStruct*)LCallData)->set);
   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_PIE:
   LCylinderInfo->Pie=(((XeToggleButtonCallbackStruct*)LCallData)->set);
   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_ORIGIN_AT_BOTTOM:
   LCylinderInfo->OriginAtBottom=(((XeToggleButtonCallbackStruct*)LCallData)->set);
   _SetVertices(LMesh, LCylinderInfo);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_RADIUS:
   LCylinderInfo->Radius=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(LMesh, LCylinderInfo);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_HEIGHT:
   LCylinderInfo->Height=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(LMesh, LCylinderInfo);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_START_ANGLE:
   {
    EBool		LWasFull, LFull;

    if((LCylinderInfo->EndAngle-LCylinderInfo->StartAngle)==360.0) LWasFull=TRUE;
    else LWasFull=FALSE;

    LCylinderInfo->StartAngle=((XeScaleCallbackStruct*)LCallData)->FloatValue;


    if(LCylinderInfo->StartAngle>LCylinderInfo->EndAngle)
    {
     LCylinderInfo->EndAngle=LCylinderInfo->StartAngle;
     XeScaleSetValueD(_EndAngleScaleW, (double)(LCylinderInfo->EndAngle), False);
    }
    if(LCylinderInfo->StartAngle<(LCylinderInfo->EndAngle-360.0))
    {
     LCylinderInfo->EndAngle=LCylinderInfo->StartAngle+360.0;
     XeScaleSetValueD(_EndAngleScaleW, (double)(LCylinderInfo->EndAngle), False);
    }

    if((LCylinderInfo->EndAngle-LCylinderInfo->StartAngle)==360.0) LFull=TRUE;
    else LFull=FALSE;

    if(LFull==LWasFull) _Get(_Model, _Geometry, LCylinderInfo, E3dGF_SHAPE);
    else _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);


    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_END_ANGLE:
   {
    EBool		LWasFull, LFull;


    if((LCylinderInfo->EndAngle-LCylinderInfo->StartAngle)==360.0) LWasFull=TRUE;
    else LWasFull=FALSE;

    LCylinderInfo->EndAngle=((XeScaleCallbackStruct*)LCallData)->FloatValue;

    if(LCylinderInfo->StartAngle>LCylinderInfo->EndAngle)
    {
     LCylinderInfo->StartAngle=LCylinderInfo->EndAngle;
     XeScaleSetValueD(_StartAngleScaleW, (double)(LCylinderInfo->StartAngle), False);
    }
    if(LCylinderInfo->StartAngle<(LCylinderInfo->EndAngle-360.0))
    {
     LCylinderInfo->StartAngle=LCylinderInfo->EndAngle-360.0;
     XeScaleSetValueD(_StartAngleScaleW, (double)(LCylinderInfo->StartAngle), False);
    }

    if((LCylinderInfo->EndAngle-LCylinderInfo->StartAngle)==360.0) LFull=TRUE;
    else LFull=FALSE;

    if(LFull==LWasFull) _Get(_Model, _Geometry, LCylinderInfo, E3dGF_SHAPE);
    else _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_SIDES:
   LCylinderInfo->Sides=((XeScaleCallbackStruct*)LCallData)->IntValue;

   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_RADIAL_SECTIONS:
   LCylinderInfo->RadialSections=((XeScaleCallbackStruct*)LCallData)->IntValue;

   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_HEIGHT_SECTIONS:
   LCylinderInfo->HeightSections=((XeScaleCallbackStruct*)LCallData)->IntValue;

   _Get(_Model, _Geometry, LCylinderInfo, E3dGF_ALL);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;
 }
}


/*======================================*/
/* Pop up the dialog			*/
/*======================================*/
static void _PopupDialog(E3dCylinderInfo* LCylinderInfo)
{
 if(_Dialog==NULL)
 {
  Widget	LTopMatrixW, LMatrixW;
  Widget	LIndentWs[7];			// For indenting the ScaleWidgets
  Widget	LTraverseWs[7];			// For TextField traversal
  EguiItem	LDialog=E3d_GeometryDialogCreate("Cylinder v0.1.0", _MainGeometry, &_GeometryPanel, _DCB, &Image_CylinderBig);
  int		LIndentN, LTraverseN;


  _Dialog=LDialog;

  LTopMatrixW=EGUI_DialogGetChild(LDialog, EguiDIALOG_WORK_AREA);
  EXtStart;
  EXtSetArg(XeNySpacing, 4);
  XtSetValues(LTopMatrixW, Args, ArgCnt);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  EXtSetArg(XeNxSpacing, 16);
  EXtSetArg(XeNwidthAdjustable, False);EXtSetArg(XeNxAlignment, XeALIGN_BEGINNING);
  LMatrixW=XtCreateManagedWidget("MatrixW", xeMatrixWidgetClass, LTopMatrixW, Args, ArgCnt);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LCylinderInfo->Smooth);
  EXtSetArg(XeNheightAdjustable, False);
  _SmoothW=XtCreateManagedWidget("Smooth", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_SmoothW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SMOOTH);



  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  EXtSetArg(XeNxSpacing, 4);
  EXtSetArg(XeNwidthAdjustable, False);EXtSetArg(XeNxAlignment, XeALIGN_BEGINNING);
  LMatrixW=XtCreateManagedWidget("LMatrixW", xeMatrixWidgetClass, LTopMatrixW, Args, ArgCnt);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginLeft, 0);EXtSetArg(XeNmarginRight, 0);EXtSetArg(XeNmarginTop, 0);
  EXtSetArg(XeNmarginBottom, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LCylinderInfo->TopCap);
  _TopW=XtCreateManagedWidget("Cap top", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_TopW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_TOPCAP);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginLeft, 0);EXtSetArg(XeNmarginRight, 0);EXtSetArg(XeNmarginTop, 0);
  EXtSetArg(XeNmarginBottom, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LCylinderInfo->BottomCap);
  _BottomW=XtCreateManagedWidget("Cap bottom", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_BottomW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_BOTTOMCAP);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginLeft, 0);EXtSetArg(XeNmarginRight, 0);EXtSetArg(XeNmarginTop, 0);
  EXtSetArg(XeNmarginBottom, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LCylinderInfo->OriginAtBottom);
  _OriginAtBottomW=XtCreateManagedWidget("Origin at bottom", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_OriginAtBottomW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_ORIGIN_AT_BOTTOM);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginLeft, 0);EXtSetArg(XeNmarginRight, 0);EXtSetArg(XeNmarginTop, 0);
  EXtSetArg(XeNmarginBottom, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LCylinderInfo->Pie);
  _PieW=XtCreateManagedWidget("Pie", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_PieW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_PIE);

  EXtStart;
  EXtSetArg(XeNshadowThickness, 2);
  EXtSetArg(XeNshadowType, XeSHADOW_ETCHED_IN);
  EXtSetArg(XeNtopShadowColor, EGUI_TopShadowColor);
  EXtSetArg(XeNbottomShadowColor, EGUI_BottomShadowColor);
  XtCreateManagedWidget("", xeSeparatorWidgetClass, LTopMatrixW, Args, ArgCnt);

  LIndentN=0;
  LTraverseN=0;
  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100000000);EXtSetArg(XeNvalue, (int)(LCylinderInfo->Radius*10000.0));
  EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_RadiusScaleW=XtCreateManagedWidget("Radius:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_RadiusScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_RADIUS);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100000000);EXtSetArg(XeNvalue, (int)(LCylinderInfo->Height*10000.0));
  EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_HeightScaleW=XtCreateManagedWidget("Height:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_HeightScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_HEIGHT);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 60);
  EXtSetArg(XeNtextFieldDigits, 6);EXtSetArg(XeNdecimalPoints, 2);
  EXtSetArg(XeNminimum, -36000);EXtSetArg(XeNmaximum, 36000);EXtSetArg(XeNvalue, (int)(LCylinderInfo->StartAngle*100.0));
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_StartAngleScaleW=XtCreateManagedWidget("Start angle:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_StartAngleScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_START_ANGLE);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 60);
  EXtSetArg(XeNtextFieldDigits, 6);EXtSetArg(XeNdecimalPoints, 2);
  EXtSetArg(XeNminimum, -36000);EXtSetArg(XeNmaximum, 36000);EXtSetArg(XeNvalue, (int)(LCylinderInfo->EndAngle*100.0));
  EXtSetArg(XeNincrement, 100);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_EndAngleScaleW=XtCreateManagedWidget("End angle", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_EndAngleScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_END_ANGLE);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 4);
  EXtSetArg(XeNminimum, 3);EXtSetArg(XeNmaximum, 100);EXtSetArg(XeNvalue, LCylinderInfo->Sides);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_SidesScaleW=XtCreateManagedWidget("Sides:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_SidesScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_SIDES);

  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 4);
  EXtSetArg(XeNminimum, 0);EXtSetArg(XeNmaximum, 100);EXtSetArg(XeNvalue, LCylinderInfo->RadialSections);
  EXtSetArg(XeNscaleMinimum, 0);EXtSetArg(XeNscaleMaximum, 24);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_RadialSectionsScaleW=XtCreateManagedWidget("Radial segments:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_RadialSectionsScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_RADIAL_SECTIONS);

  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100);EXtSetArg(XeNvalue, LCylinderInfo->HeightSections);
  EXtSetArg(XeNscaleMinimum, 1);EXtSetArg(XeNscaleMaximum, 20);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_HeightSectionsScaleW=XtCreateManagedWidget("Height sections:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_HeightSectionsScaleW, XeNvalueChangedCallback, _XtDCB, (XtPointer)E3dCR_SET_HEIGHT_SECTIONS);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


// Set up TextField traversal
//
  XeRingTraversal(LTraverseWs, LTraverseN);


  _SetGUIToType(LCylinderInfo);
 }
 else _UpdateDialog(LCylinderInfo);

 EGUI_RaiseShell(_Dialog);_Plugin->LockCount+=1;
}


/*==============================================*/
/* Menu callback for Cylinder			*/
/*==============================================*/
static void _MCB_Cylinder(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 _Info.TopDomeHeight=0.0;_Info.BottomDomeHeight=0.0;
 _Info.RadialSections=0;

 E3dTpl_ACB_CHist(E3dCylinder, _);
}


/*==============================================*/
/* Menu callback for Capsule			*/
/*==============================================*/
static void _MCB_Capsule(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 _Info.TopDomeHeight=1.0;_Info.BottomDomeHeight=1.0;
 _Info.RadialSections=8;

 E3dTpl_ACB_CHist(E3dCylinder, _);
}


/*==============================================*/
/* EditProc for the "Cylinder" geometry type	*/
/*==============================================*/
static int _EditProc(E3dModel* LModel, E3dGeometry* LGeometry, E3dGeometryInfo* LInfo, int LLODIndex)
{
 E3dTplEditProc_LODCHist(E3dCylinder, _);
}


/*======================================*/
/* Entry point of the plugin		*/
/*======================================*/
int Plugin_Init(EPlugin* LPlugin)
{
 E3dGeometryClass	LGeoClass=
   {
    "Cylinder",			// Name
    sizeof(E3dCylinderInfo),	// StructSize
    _EditProc,			// EditProc
    NULL,			// DestroyProc
    _Resources			// Resources
   };


 _Plugin=LPlugin;

 if((_Info.Class=E3d_GeometryClassRegister(&LGeoClass))!=NULL)
 {
  EpImage*	LImage;
  EpImage*	LActiveImage;
  EpImage*	LArmImage;

  EpM_RGBA8ImageFromCStruct(LImage, Image_Cylinder);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_CylinderActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_CylinderArm);
  _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButtonImg("Tool->Create", "Cylinder", '\0', NULL, NULL, FALSE, "Create cylinder\nRight button:  dialog box for this tool", _MCB_Cylinder, (EPointer)0, LImage, LActiveImage, LArmImage);

  EpM_RGBA8ImageFromCStruct(LImage, Image_Capsule);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_CapsuleActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_CapsuleArm);
  _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButtonImg("Tool->Create", "Capsule", '\0', NULL, NULL, FALSE, "Create capsule\nRight button:  dialog box for this tool", _MCB_Capsule, (EPointer)0, LImage, LActiveImage, LArmImage);


  _Info.Radius=3.0;_Info.Height=5.0;

// For "Capsule" shape
//
  _Info.TopDomeHeight=1.0;_Info.BottomDomeHeight=1.0;
  _Info.Sides=10;
  _Info.RadialSections=0;
  _Info.HeightSections=1;

  _Info.Type=E3dCylinderPOLYGONS;

  _Info.StartAngle=0.0;_Info.EndAngle=360.0;
  _Info.Smooth=TRUE;
  _Info.Side=TRUE;_Info.TopCap=TRUE;_Info.BottomCap=TRUE;
  _Info.Pie=TRUE;
  _Info.OriginAtBottom=FALSE;


  _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Create", "Cylinder", '\0', NULL, NULL, TRUE, NULL, _MCB_Cylinder, (EPointer)0);
  _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Create", "Capsule", '\0', NULL, NULL, TRUE, NULL, _MCB_Capsule, (EPointer)0);
 }

 return(0);
}


/*======================================*/
/* Exit method of the plugin		*/
/*======================================*/
int Plugin_Exit()
{
 unsigned int	LC;


 for(LC=0;LC<_NumOfMenuButtons;LC++) EGUI_DestroyItem(_MenuButtons[LC]);
 for(LC=0;LC<_NumOfToolPanelButtons;LC++) EGUI_DestroyItem(_ToolPanelButtons[LC]);

 if(_Info.Class) E3d_GeometryClassDeactivate(_Info.Class);

 return(0);
}
