/*======================================================================================================*/
/* Create a tetrahedron, an icosahedron or a dodecahedron						*/
/*													*/
/* Plugin for 3DPanel/EQUINOX-3D									*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-17 23:46:04									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <stdio.h>
#include <math.h>


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


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

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

#include <E3D/3DWindow.h>


static EPlugin*		_Plugin=NULL;

static EguiItem		_TetraDialog=NULL, _IcosaDialog=NULL, _DodecaDialog=NULL;

static Widget		_TetraCenterAtBottomW=NULL, _TetraEdgeLengthScaleW=NULL, _TetraRadiusScaleW=NULL;

static Widget		_IcosaVerticalBW=NULL, _IcosaEdgeLengthScaleW=NULL, _IcosaRadiusScaleW=NULL;

static Widget		_DodecaCenterAtBottomW=NULL, _DodecaEdgeLengthScaleW=NULL, _DodecaRadiusScaleW=NULL;


static E3dModel*	_TetraModel=NULL;
static E3dGeometry*	_TetraMainGeometry=NULL;
static E3dGeometry*	_TetraGeometry=NULL;

static E3dModel*	_IcosaModel=NULL;
static E3dGeometry*	_IcosaMainGeometry=NULL;
static E3dGeometry*	_IcosaGeometry=NULL;

static E3dModel*	_DodecaModel=NULL;
static E3dGeometry*	_DodecaMainGeometry=NULL;
static E3dGeometry*	_DodecaGeometry=NULL;


static EguiItem		_MenuButtons[3],
			_ToolPanelButtons[3];

static unsigned int	_NumOfMenuButtons=0,
			_NumOfToolPanelButtons=0;


static Arg		Args[256];
static Cardinal		ArgCnt;


extern EpCImage		Image_Tetra;
extern EpCImage		Image_TetraActive;
extern EpCImage		Image_TetraArm;
extern EpCImage		Image_TetraBig;

extern EpCImage		Image_Icosa;
extern EpCImage		Image_IcosaActive;
extern EpCImage		Image_IcosaArm;
extern EpCImage		Image_IcosaBig;

extern EpCImage		Image_Dodeca;
extern EpCImage		Image_DodecaActive;
extern EpCImage		Image_DodecaArm;
extern EpCImage		Image_DodecaBig;


#define M3TETRARADIUSFACTOR	0.61237243568762955874	// sqrt(0.375)
#define M3TETRAHEIGHTFACTOR	0.81649658092772603273	// sqrt(2/3)


#define E3dpICOSA_X 0.525731112119133606
#define E3dpICOSA_Z 0.850650808352039932

static E3d3DPosition _IcosaVertices[12]=
{    
 { -E3dpICOSA_X, 0.0, E3dpICOSA_Z}, {E3dpICOSA_X, 0.0, E3dpICOSA_Z}, {-E3dpICOSA_X, 0.0, -E3dpICOSA_Z}, {E3dpICOSA_X, 0.0, -E3dpICOSA_Z},    
 { 0.0, E3dpICOSA_Z, E3dpICOSA_X }, {0.0, E3dpICOSA_Z, -E3dpICOSA_X}, {0.0, -E3dpICOSA_Z, E3dpICOSA_X}, {0.0, -E3dpICOSA_Z, -E3dpICOSA_X},    
 { E3dpICOSA_Z, E3dpICOSA_X, 0.0 }, {-E3dpICOSA_Z, E3dpICOSA_X, 0.0}, {E3dpICOSA_Z, -E3dpICOSA_X, 0.0}, {-E3dpICOSA_Z, -E3dpICOSA_X, 0.0} 
}; 


static E3d3DPosition _IcosaVerticalVertices[12]=
{    
 { -0.525731, -0.447209, 0.723610 },
 { 0.525731, -0.447209, 0.723610 },
 { -0.525731, 0.447209, -0.723610 },
 { 0.525731, 0.447209, -0.723610 },
 { 0.000000, 0.447219, 0.894424 },
 { 0.000000, 1.000000, -0.000007 },
 { 0.000000, -1.000000, 0.000007 },
 { 0.000000, -0.447219, -0.894424 },
 { 0.850651, 0.447215, 0.276390 },
 { -0.850651, 0.447215, 0.276390 },
 { 0.850651, -0.447215, -0.276390 },
 { -0.850651, -0.447215, -0.276390 }
}; 



enum
{
 E3dCR_SET_CENTERATBOTTOM=EguiCUSTOM0,
 E3dCR_SET_RADIUS,
 E3dCR_SET_EDGELENGTH,
 E3dCR_SET_VERTICAL
};


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

// E3dTetraInfo part
//
 E3dCoordinate	EdgeLength;
 EBool		CenterAtBottom;
} E3dTetraInfo;

#define ROffset(field) (void*)(EPtrOffset(E3dTetraInfo, field))
EResource _TetraResources[]=
{
 { "EdgeLength",	EResFLOAT32,	ROffset(EdgeLength), NULL },
 { "CenterAtBottom",	EResBOOLEAN,	ROffset(CenterAtBottom), NULL },
 { "",			EResNULL,	NULL, NULL }
};
#undef ROffset


static E3dTetraInfo	_TetraInfo;
static EBool		_TetraCreateMode=FALSE;
static E3dGeometryPanel	_TetraGeometryPanel;



#define	ICOSA_EDGELENGTH_TO_RADIUSFACTOR	0.95105655

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

// E3dIcosaInfo part
//
 E3dCoordinate	Radius;
 EBool		Vertical;
} E3dIcosaInfo;


#define ROffset(field) (void*)(EPtrOffset(E3dIcosaInfo, field))
EResource _IcosaResources[]=
{
 { "Radius",	EResFLOAT32,	ROffset(Radius), NULL },
 { "Vertical",	EResBOOLEAN,	ROffset(Vertical), NULL },
 { "",		EResNULL,	NULL, NULL }
};
#undef ROffset

static E3dIcosaInfo	_IcosaInfo;
static EBool		_IcosaCreateMode=FALSE;
static E3dGeometryPanel	_IcosaGeometryPanel;




#define	DODECA_EDGELENGTH_TO_RADIUSFACTOR	1.4012585


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

// E3dDodecaInfo part
//
 E3dCoordinate	Radius;
 EBool		CenterAtBottom;
} E3dDodecaInfo;

#define ROffset(field) (void*)(EPtrOffset(E3dDodecaInfo, field))
EResource _DodecaResources[]=
{
 { "Radius",		EResFLOAT32,	ROffset(Radius), NULL },
 { "CenterAtBottom",	EResBOOLEAN,	ROffset(CenterAtBottom), NULL },
 { "",			EResNULL,	NULL, NULL }
};
#undef ROffset


static E3dDodecaInfo	_DodecaInfo;
static EBool		_DodecaCreateMode=FALSE;
static E3dGeometryPanel	_DodecaGeometryPanel;



/*==============================================*/
/* Set vertex coordinates of a tetrahedron	*/
/*==============================================*/
static void _TetraSetVertices(E3dTetraInfo* LTetraInfo, register E3dVertex* LVertex)
{
 float	LLenH, LCo0, LCo1, LCo2;
 E3dCoordinate	LLen;

 LLen=LTetraInfo->EdgeLength;
 LLenH=LLen*0.5;
 LCo0=0.57735026918962576451;		// 1.0/sqrt(3)
 LCo1=-0.288675134*LLen;		// LLen*(sqrt(3)/2-1/sqrt(3))
 if(LTetraInfo->CenterAtBottom) 
 {
  LCo2=0.0;
  LVertex[3].X=0.0;LVertex[3].Y=LLen*M3TETRAHEIGHTFACTOR;LVertex[3].Z=0.0;
 }
 else
 {
  LCo2=LCo1*0.7071067811865;		// LCo1*sqrt(2)/2
  LVertex[3].X=0.0;LVertex[3].Y=LLen*M3TETRAHEIGHTFACTOR+LCo2;LVertex[3].Z=0.0;
 }
 LVertex[0].X=   0.0;LVertex[0].Y=LCo2;LVertex[0].Z=LLen*LCo0;
 LVertex[1].X= LLenH;LVertex[1].Y=LCo2;LVertex[1].Z=LCo1;
 LVertex[2].X=-LLenH;LVertex[2].Y=LCo2;LVertex[2].Z=LCo1;
}



/*======================================*/
/* Get a tetrahedron			*/
/*======================================*/
static E3dModel* _TetraGet(E3dModel* LModel, E3dGeometry* LGeometry, E3dTetraInfo* LInfoV, unsigned int LFlags)
{
 E3dTetraInfo*		LInfo;
 E3dMesh*		LMesh;
 E3dPolyGroup*		LPolyGroup;
 E3dPolygon*		LPolygon;
 E3dVertex*		LVertex;
 E3dCoordinate		LEdgeLen;
 unsigned int		LN;


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

  LInfo=(E3dTetraInfo*)E3d_GeometryInfoAdd((E3dGeometry*)LMesh, LInfoV->Class);
  if(LInfo)
  {
   memcpy(LInfo, LInfoV, sizeof(E3dTetraInfo));
  }

  if((LPolyGroup=E3d_MeshAddPolyGroup(LMesh))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }

  LEdgeLen=LInfo->EdgeLength;

  LN=LMesh->NumOfVertices=4;
  if((LVertex=LMesh->Vertices=E3d_VerticesAllocate(LN, TRUE))!=NULL)
  {
   _TetraSetVertices(LInfo, LVertex);

   LN=LPolyGroup->NumOfPolygons=4;
   if((LPolygon=LPolyGroup->Polygons=E3d_PolygonsAllocate(LN))!=NULL)
   {
    E3d_PolygonSetAsTriangle(LPolygon++, 2, 1, 0);
    E3d_PolygonSetAsTriangle(LPolygon++, 0, 1, 3);
    E3d_PolygonSetAsTriangle(LPolygon++, 1, 2, 3);
    E3d_PolygonSetAsTriangle(LPolygon, 0, 3, 2);
   }

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


/*======================================*/
/* Update the dialog			*/
/*======================================*/
static void _TetraUpdateDialog(E3dTetraInfo* LTetraInfo)
{
 E3d_GeometryPanelUpdate(&_TetraGeometryPanel, _TetraMainGeometry);

 XeToggleButtonSetState(_TetraCenterAtBottomW, LTetraInfo->CenterAtBottom, False);

 XeScaleSetValueD(_TetraEdgeLengthScaleW, LTetraInfo->EdgeLength, False);
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _DCB_Tetra(EguiItem LW, EPointer LClientData, EPointer LCallData)
{
 switch((int)LClientData)
 {
  case EguiOK:
   E3dTpl_GeoOK(_Tetra);
  break;

  case EguiADD:
   E3dTpl_GeoADD(_Tetra);
  break;

  case EguiCANCEL:
   E3dTpl_GeoCANCEL(_Tetra);
  break;
 }
}


/*======================================*/
/* Dialog Xt callback			*/
/*======================================*/
static void _XtDCB_Tetra(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
 E3dMesh*	LMesh=(E3dMesh*)_TetraGeometry;
 E3dVertex*	LVertex;
 float		LLen;
 E3dTetraInfo*	LTetraInfo=(E3dTetraInfo*)E3d_GeometryInfoByClass(_TetraGeometry, _TetraInfo.Class);


 LVertex=LMesh->Vertices;

 switch((int)LClientData)
 {
  case E3dCR_SET_CENTERATBOTTOM:	// Toggle CenterAtBottom
    LTetraInfo->CenterAtBottom=((XeToggleButtonCallbackStruct*)LCallData)->set;
    _TetraSetVertices(LTetraInfo, LVertex);

    E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_EDGELENGTH:		// Set edge length
   LTetraInfo->EdgeLength=LLen=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _TetraSetVertices(LTetraInfo, LVertex);

   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_TetraRadiusScaleW, LLen*M3TETRARADIUSFACTOR, False);
  break;

  case E3dCR_SET_RADIUS:		// Set radius
   LTetraInfo->EdgeLength=LLen=(((XeScaleCallbackStruct*)LCallData)->FloatValue)/M3TETRARADIUSFACTOR;
   _TetraSetVertices(LTetraInfo, LVertex);

   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_TetraEdgeLengthScaleW, LLen, False);
  break;
 }
}


/*======================================*/
/* Pop up the dialog			*/
/*======================================*/
static void _TetraPopupDialog(E3dTetraInfo* LTetraInfo)
{
 if(_TetraDialog==NULL)
 {
  Widget	LTraverseWs[2];
  Widget	LIndentWs[7];
  Widget	LTopMatrixW;
  EguiItem	LDialog=E3d_GeometryDialogCreate("Tetrahedron", _TetraMainGeometry, &_TetraGeometryPanel, _DCB_Tetra, &Image_TetraBig);
  int		LIndentN, LTraverseN;


  _TetraDialog=LDialog;

  LTopMatrixW=EGUI_DialogGetChild(LDialog, EguiDIALOG_WORK_AREA);
  EXtStart;
  EXtSetArg(XeNySpacing, 4);
  XtSetValues(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(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LTetraInfo->CenterAtBottom);
  EXtSetArg(XeNheightAdjustable, False);
  _TetraCenterAtBottomW=XtCreateManagedWidget("Center at bottom", xeToggleButtonWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_TetraCenterAtBottomW, XeNvalueChangedCallback, _XtDCB_Tetra, (XtPointer)E3dCR_SET_CENTERATBOTTOM);

  EXtStart;
  EXtSetArg(XeNshadowThickness, 2);
  EXtSetArg(XeNshadowType, XeSHADOW_ETCHED_IN);
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  XtCreateManagedWidget("", xeSeparatorWidgetClass, LTopMatrixW, Args, ArgCnt);

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

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 1000000);EXtSetArg(XeNvalue, (int)(LTetraInfo->EdgeLength*10000.0));
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_TetraEdgeLengthScaleW=XtCreateManagedWidget("Edge length:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_TetraEdgeLengthScaleW, XeNvalueChangedCallback, _XtDCB_Tetra, (XtPointer)E3dCR_SET_EDGELENGTH);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


// Set up TextField traversal
//
  XeRingTraversal(LTraverseWs, LTraverseN);
 }
 else _TetraUpdateDialog(LTetraInfo);

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


/*==============================================*/
/* Menu callback (create new Tetrahedron)	*/
/*==============================================*/
static void _MCB_Tetra(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dTpl_ACB_CHist(E3dTetra, _Tetra);
}


/*==============================================*/
/* EditProc for the "Tetrahedron" Geometry type	*/
/*==============================================*/
static int _TetraEditProc(E3dModel* LModel, E3dGeometry* LGeometry, E3dGeometryInfo* LInfo, int LLODIndex)
{
 E3dTplEditProc_LODCHist(E3dTetra, _Tetra);
}



/*==============================================*/
/* Set vertex coordinates of an icosahedron	*/
/*==============================================*/
static void _IcosaSetVertices(E3dIcosaInfo* LInfo, register E3dVertex* LVertex)
{
 E3d3DPosition*		LPoints;
 register E3dCoordinate	LRadius=LInfo->Radius;
 unsigned int		LC;

 if(LInfo->Vertical) LPoints=_IcosaVerticalVertices;
 else LPoints=_IcosaVertices;
 for(LC=0;LC<12;LC++, LVertex++)
 {
  LVertex->X=LPoints[LC].X*LRadius;
  LVertex->Y=LPoints[LC].Y*LRadius;
  LVertex->Z=LPoints[LC].Z*LRadius;
 }
}



/*======================================*/
/* Get an icosahedron			*/
/*======================================*/
static E3dModel* _IcosaGet(E3dModel* LModel, E3dGeometry* LGeometry, E3dIcosaInfo* LInfoV, unsigned int LFlags)
{
 E3dMesh*		LMesh;
 E3dPolyGroup*		LPolyGroup;
 register E3dVertex*	LVertex;
 E3dPolygon*		LPolygon;
 E3dIcosaInfo*		LInfo;

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

  LInfo=(E3dIcosaInfo*)E3d_GeometryInfoAdd((E3dGeometry*)LMesh, LInfoV->Class);
  if(LInfo)
  {
   memcpy(LInfo, LInfoV, sizeof(E3dIcosaInfo));
  }
  if((LPolyGroup=E3d_MeshAddPolyGroup(LMesh))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
  LPolyGroup->VertexNormalType=E3dNormalPROCESS;
 }
 else
 {
  LMesh=(E3dMesh*)LGeometry;
  LInfo=LInfoV;
  LPolyGroup=LMesh->PolyGroups[0];
 }

 if((LVertex=LMesh->Vertices=E3d_VerticesAllocate(LMesh->NumOfVertices=12, TRUE))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
 if((LPolygon=LPolyGroup->Polygons=E3d_PolygonsAllocate(LPolyGroup->NumOfPolygons=20))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }

 _IcosaSetVertices(LInfo, LVertex);

 E3d_PolygonSetAsTriangle(LPolygon++, 1, 4, 0);
 E3d_PolygonSetAsTriangle(LPolygon++, 4, 9, 0);
 E3d_PolygonSetAsTriangle(LPolygon++, 4, 5, 9);
 E3d_PolygonSetAsTriangle(LPolygon++, 8, 5, 4);
 E3d_PolygonSetAsTriangle(LPolygon++, 1, 8, 4);
 E3d_PolygonSetAsTriangle(LPolygon++, 1, 10, 8);
 E3d_PolygonSetAsTriangle(LPolygon++, 10, 3, 8);
 E3d_PolygonSetAsTriangle(LPolygon++, 8, 3, 5);
 E3d_PolygonSetAsTriangle(LPolygon++, 3, 2, 5);
 E3d_PolygonSetAsTriangle(LPolygon++, 3, 7, 2);
 E3d_PolygonSetAsTriangle(LPolygon++, 3, 10, 7);
 E3d_PolygonSetAsTriangle(LPolygon++, 10, 6, 7);
 E3d_PolygonSetAsTriangle(LPolygon++, 6, 11, 7);
 E3d_PolygonSetAsTriangle(LPolygon++, 6, 0, 11);
 E3d_PolygonSetAsTriangle(LPolygon++, 6, 1, 0);
 E3d_PolygonSetAsTriangle(LPolygon++, 10, 1, 6);
 E3d_PolygonSetAsTriangle(LPolygon++, 11, 0, 9);
 E3d_PolygonSetAsTriangle(LPolygon++, 2, 11, 9);
 E3d_PolygonSetAsTriangle(LPolygon++, 5, 2, 9);
 E3d_PolygonSetAsTriangle(LPolygon, 11, 2, 7);

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


/*======================================*/
/* Update the dialog			*/
/*======================================*/
static void _IcosaUpdateDialog(E3dIcosaInfo* LInfo)
{
 E3d_GeometryPanelUpdate(&_IcosaGeometryPanel, _IcosaMainGeometry);

 XeToggleButtonSetState(_IcosaVerticalBW, LInfo->Vertical, False);

 XeScaleSetValueD(_IcosaRadiusScaleW, LInfo->Radius, False);
 XeScaleSetValueD(_IcosaEdgeLengthScaleW, LInfo->Radius/ICOSA_EDGELENGTH_TO_RADIUSFACTOR, False);
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _DCB_Icosa(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 switch((int)LClientData)
 {
  case EguiOK:
   E3dTpl_GeoOK(_Icosa);
  break;

  case EguiADD:
   E3dTpl_GeoADD(_Icosa);
  break;

  case EguiCANCEL:
   E3dTpl_GeoCANCEL(_Icosa);
  break;
 }
}


/*======================================*/
/* Icosahedron dialog callback		*/
/*======================================*/
static void _XtDCB_Icosa(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
 E3dMesh*	LMesh=(E3dMesh*)_IcosaGeometry;
 E3dIcosaInfo*	LInfo=(E3dIcosaInfo*)E3d_GeometryInfoByClass(_IcosaGeometry, _IcosaInfo.Class);


 switch((int)LClientData)
 {
  case E3dCR_SET_VERTICAL:		// Toggle CenterAtBottom
   LInfo->Vertical=((XeToggleButtonCallbackStruct*)LCallData)->set;

   _IcosaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_EDGELENGTH:		// Set edge length
   LInfo->Radius=((XeScaleCallbackStruct*)LCallData)->FloatValue*ICOSA_EDGELENGTH_TO_RADIUSFACTOR;

   _IcosaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_IcosaRadiusScaleW, LInfo->Radius, False);
  break;

  case E3dCR_SET_RADIUS:		// Set radius
   LInfo->Radius=(((XeScaleCallbackStruct*)LCallData)->FloatValue);

   _IcosaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_IcosaEdgeLengthScaleW, LInfo->Radius/ICOSA_EDGELENGTH_TO_RADIUSFACTOR, False);
  break;
 }
}


/*======================================*/
/* Pop up the dialog			*/
/*======================================*/
static void _IcosaPopupDialog(E3dIcosaInfo* LInfo)
{
 if(_IcosaDialog==NULL)
 {
  Widget	LIndentWs[7];			// For indenting the ScaleWidgets
  Widget	LTraverseWs[42];		// For TextField traversal
  Widget	LTopMatrixW;
  EguiItem	LDialog=E3d_GeometryDialogCreate("Icosahedron", _IcosaMainGeometry, &_IcosaGeometryPanel, _DCB_Icosa, &Image_IcosaBig);
  int		LIndentN, LTraverseN;


  _IcosaDialog=LDialog;

  LTopMatrixW=EGUI_DialogGetChild(LDialog, EguiDIALOG_WORK_AREA);


  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginTop, 0);EXtSetArg(XeNmarginBottom, 4);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LInfo->Vertical);
  EXtSetArg(XeNwidthAdjustable, False);EXtSetArg(XeNxAlignment, XeALIGN_BEGINNING);
  _IcosaVerticalBW=XtCreateManagedWidget("Vertical", xeToggleButtonWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_IcosaVerticalBW, XeNvalueChangedCallback, _XtDCB_Icosa, (XtPointer)E3dCR_SET_VERTICAL);

  EXtStart;
  EXtSetArg(XeNshadowThickness, 2);
  EXtSetArg(XeNshadowType, XeSHADOW_ETCHED_IN);
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  XtCreateManagedWidget("", xeSeparatorWidgetClass, LTopMatrixW, Args, ArgCnt);

  LTraverseN=0;
  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, 10000);
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_IcosaRadiusScaleW=XtCreateManagedWidget("Radius:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_IcosaRadiusScaleW, XeNvalueChangedCallback, _XtDCB_Icosa, (XtPointer)E3dCR_SET_EDGELENGTH);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, 10000/ICOSA_EDGELENGTH_TO_RADIUSFACTOR);
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_IcosaEdgeLengthScaleW=XtCreateManagedWidget("Edge length:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_IcosaEdgeLengthScaleW, XeNvalueChangedCallback, _XtDCB_Icosa, (XtPointer)E3dCR_SET_EDGELENGTH);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


// Set up TextField traversal
//
  XeRingTraversal(LTraverseWs, LTraverseN);
 }
 else _IcosaUpdateDialog(LInfo);

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


/*==============================================*/
/* Menu callback (create new Icosahedron)	*/
/*==============================================*/
static void _MCB_Icosa(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dTpl_ACB_CHist(E3dIcosa, _Icosa);
}


/*==============================================*/
/* EditProc for the "Icosahedron" Geometry type	*/
/*==============================================*/
static int _IcosaEditProc(E3dModel* LModel, E3dGeometry* LGeometry, E3dGeometryInfo* LInfo, int LLODIndex)
{
 E3dTplEditProc_LODCHist(E3dIcosa, _Icosa);
}



static int _DodecaPolys[12][5] =
{
 { 2,1,0,4,3 },
 { 3,7,8,18,2 },
 { 2,18,17,16,1 },
 { 3,4,5,6,7 },
 { 18,8,9,19,17 },
 { 7,6,10,9,8 },
 { 1,16,13,14,0 },
 { 4,0,14,15,5 },
 { 17,19,12,13,16 },
 { 5,15,11,10,6 },
 { 14,13,12,11,15 },
 { 9,10,11,12,19 }
};


static int _IcosaPolys[20][3]=
{
 { 1,4,0 },
 { 4,9,0 },
 { 4,5,9 },
 { 8,5,4 },
 { 1,8,4 },
 { 1,10,8 },
 { 10,3,8 },
 { 8,3,5 },
 { 3,2,5 },
 { 3,7,2 },
 { 3,10,7 },
 { 10,6,7 },
 { 6,11,7 },
 { 6,0,11 },
 { 6,1,0 },
 { 10,1,6 },
 { 11,0,9 },
 { 2,11,9 },
 { 5,2,9 },
 { 11,2,7 }
};


/*==============================================*/
/* Set vertex coordinates of a dodecahedron	*/
/*==============================================*/
static void _DodecaSetVertices(E3dDodecaInfo* LInfo, register E3dVertex* LVertex)
{
 unsigned int		LCn, LA, LB, LC;
 double			LX, LY, LZ, LXA, LYA, LZA, LXB, LYB, LZB, LXC, LYC, LZC, LL;
 register E3dCoordinate	LRadius=LInfo->Radius;


 for(LCn=0;LCn<20;LCn++)
 {
  LA=_IcosaPolys[LCn][0];
  LB=_IcosaPolys[LCn][1];
  LC=_IcosaPolys[LCn][2];
  LXA=_IcosaVertices[LA].X;LYA=_IcosaVertices[LA].Y;LZA=_IcosaVertices[LA].Z;
  LXB=_IcosaVertices[LB].X;LYB=_IcosaVertices[LB].Y;LZB=_IcosaVertices[LB].Z;
  LXC=_IcosaVertices[LC].X;LYC=_IcosaVertices[LC].Y;LZC=_IcosaVertices[LC].Z;

// The dodecahedron vertex is the centroid of the icosahedron face.
//
  LX=(LXA+LXB+LXC)*0.33333333;
  LY=(LYA+LYB+LYC)*0.33333333;
  LZ=(LZA+LZB+LZC)*0.33333333;
  LL=1.0/sqrt(LX*LX+LY*LY+LZ*LZ)*LRadius;

  LVertex[LCn].X=LX*LL;
  LVertex[LCn].Y=LY*LL;
  LVertex[LCn].Z=LZ*LL;
 }
}


/*======================================*/
/* Get a dodecahedron			*/
/*======================================*/
static E3dModel* _DodecaGet(E3dModel* LModel, E3dGeometry* LGeometry, E3dDodecaInfo* LInfoV, unsigned int LFlags)
{
 unsigned long		LC;
 E3dMesh*		LMesh;
 E3dPolyGroup*		LPolyGroup;
 register E3dVertex*	LVertex;
 E3dPolygon*		LPolygon;
 E3dDodecaInfo*		LInfo;

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

  LInfo=(E3dDodecaInfo*)E3d_GeometryInfoAdd((E3dGeometry*)LMesh, LInfoV->Class);
  if(LInfo)
  {
   memcpy(LInfo, LInfoV, sizeof(E3dDodecaInfo));
  }
  if((LPolyGroup=E3d_MeshAddPolyGroup(LMesh))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
 }
 else
 {
  LMesh=(E3dMesh*)LGeometry;
  LInfo=LInfoV;
  LPolyGroup=LMesh->PolyGroups[0];
 }

 if((LVertex=LMesh->Vertices=E3d_VerticesAllocate(LMesh->NumOfVertices=20, TRUE))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }
 if((LPolygon=LPolyGroup->Polygons=E3d_PolygonsAllocate(LPolyGroup->NumOfPolygons=12))==NULL) { E3d_ModelHrcFree(LModel, TRUE);return(NULL); }

 _DodecaSetVertices(LInfo, LVertex);

 for(LC=0;LC<12;LC++)
 {
  E3d_PolygonSet(LPolygon++, 5, _DodecaPolys[LC][0], _DodecaPolys[LC][1], _DodecaPolys[LC][2], _DodecaPolys[LC][3], _DodecaPolys[LC][4]);
 }

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


/*======================================*/
/* Update the dialog			*/
/*======================================*/
static void _DodecaUpdateDialog(E3dDodecaInfo* LInfo)
{
 E3d_GeometryPanelUpdate(&_DodecaGeometryPanel, _DodecaMainGeometry);

 XeToggleButtonSetState(_DodecaCenterAtBottomW, LInfo->CenterAtBottom, False);

 XeScaleSetValueD(_DodecaRadiusScaleW, LInfo->Radius, False);
 XeScaleSetValueD(_DodecaEdgeLengthScaleW, LInfo->Radius/DODECA_EDGELENGTH_TO_RADIUSFACTOR, False);
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _DCB_Dodeca(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 switch((int)LClientData)
 {
  case EguiOK:
   E3dTpl_GeoOK(_Dodeca);
  break;

  case EguiADD:
   E3dTpl_GeoADD(_Dodeca);
  break;

  case EguiCANCEL:
   E3dTpl_GeoCANCEL(_Dodeca);
  break;
 }
}



/*======================================*/
/* Dodecahedron dialog callback		*/
/*======================================*/
static void _XtDCB_Dodeca(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
 E3dMesh*	LMesh=(E3dMesh*)_DodecaGeometry;
 E3dDodecaInfo*	LInfo=(E3dDodecaInfo*)E3d_GeometryInfoByClass(_DodecaGeometry, _DodecaInfo.Class);
 E3dCoordinate	LRadius;


 switch((int)LClientData)
 {
  case E3dCR_SET_CENTERATBOTTOM:	// Toggle CenterAtBottom
   LInfo->CenterAtBottom=((XeToggleButtonCallbackStruct*)LCallData)->set;

   _DodecaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE-E3dGF_NORMALS);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SET_EDGELENGTH:			// Set edge length
   LInfo->Radius=((XeScaleCallbackStruct*)LCallData)->FloatValue*DODECA_EDGELENGTH_TO_RADIUSFACTOR;

   _DodecaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE-E3dGF_NORMALS);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_DodecaRadiusScaleW, LInfo->Radius, False);
  break;

  case E3dCR_SET_RADIUS:		// Set radius
   LInfo->Radius=LRadius=(((XeScaleCallbackStruct*)LCallData)->FloatValue);

   _DodecaSetVertices(LInfo, LMesh->Vertices);
   E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_SHAPE-E3dGF_NORMALS);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   XeScaleSetValueD(_DodecaEdgeLengthScaleW, LRadius/DODECA_EDGELENGTH_TO_RADIUSFACTOR, False);
  break;
 }
}


/*======================================*/
/* Pop up the Dodecahedron dialog	*/
/*======================================*/
static void _DodecaPopupDialog(E3dDodecaInfo* LInfo)
{
 if(_DodecaDialog==NULL)
 {
  Widget	LIndentWs[7];			// For indenting the ScaleWidgets
  Widget	LTraverseWs[42];		// For TextField traversal
  Widget	LTopMatrixW;
  EguiItem	LDialog=E3d_GeometryDialogCreate("Dodecahedron", _DodecaMainGeometry, &_DodecaGeometryPanel, _DCB_Dodeca, &Image_DodecaBig);
  int		LIndentN, LTraverseN;


  _DodecaDialog=LDialog;

  LTopMatrixW=EGUI_DialogGetChild(LDialog, EguiDIALOG_WORK_AREA);

  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginTop, 0);EXtSetArg(XeNmarginBottom, 4);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LInfo->CenterAtBottom);
  _DodecaCenterAtBottomW=XtCreateManagedWidget("Center at bottom", xeToggleButtonWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_DodecaCenterAtBottomW, XeNvalueChangedCallback, _XtDCB_Dodeca, (XtPointer)E3dCR_SET_CENTERATBOTTOM);

  EXtStart;
  EXtSetArg(XeNshadowThickness, 2);
  EXtSetArg(XeNshadowType, XeSHADOW_ETCHED_IN);
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  XtCreateManagedWidget("", xeSeparatorWidgetClass, LTopMatrixW, Args, ArgCnt);

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

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 8);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, 10000/DODECA_EDGELENGTH_TO_RADIUSFACTOR);
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_DodecaEdgeLengthScaleW=XtCreateManagedWidget("Edge length:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_DodecaEdgeLengthScaleW, XeNvalueChangedCallback, _XtDCB_Dodeca, (XtPointer)E3dCR_SET_EDGELENGTH);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);

// Set up TextField traversal
//
  XeRingTraversal(LTraverseWs, LTraverseN);
 }
 else _DodecaUpdateDialog(LInfo);

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


/*==============================================*/
/* Menu callback (create new Dodecahedron)	*/
/*==============================================*/
static void _MCB_Dodeca(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dTpl_ACB_CHist(E3dDodeca, _Dodeca);
}


/*======================================================*/
/* EditProc for the "Dodecahedron" Geometry type	*/
/*======================================================*/
static int _DodecaEditProc(E3dModel* LModel, E3dGeometry* LGeometry, E3dGeometryInfo* LInfo, int LLODIndex)
{
 E3dTplEditProc_LODCHist(E3dDodeca, _Dodeca);
}




/*======================================*/
/* Entry point of the plugin		*/
/*======================================*/
int Plugin_Init(EPlugin* LPlugin)
{
 E3dGeometryClass	LTetraGeoClass=
   {
    "Tetrahedron",		// Name
    sizeof(E3dTetraInfo),	// StructSize
    _TetraEditProc,		// EditProc
    NULL,			// DestroyProc
    _TetraResources		// Resources
   };

 E3dGeometryClass	LIcosaGeoClass=
   {
    "Icosahedron",		// Name
    sizeof(E3dIcosaInfo),	// StructSize
    _IcosaEditProc,		// EditProc
    NULL,			// DestroyProc
    _IcosaResources		// Resources
   };

 E3dGeometryClass	LDodecaGeoClass=
   {
    "Dodecahedron",		// Name
    sizeof(E3dIcosaInfo),	// StructSize
    _DodecaEditProc,		// EditProc
    NULL,			// DestroyProc
    _DodecaResources		// Resources
   };


 _Plugin=LPlugin;

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

  EpM_RGBA8ImageFromCStruct(LImage, Image_Tetra);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_TetraActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_TetraArm);
  _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButtonImg("Tool->Create", "Tetrahedron", '\0', NULL, NULL, TRUE, "Create tetrahedron\nRight button:  dialog box for this tool", _MCB_Tetra, (EPointer)0, LImage, LActiveImage, LArmImage);


  _TetraInfo.CenterAtBottom=FALSE;
  _TetraInfo.EdgeLength=1.0;
  _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Create", "Tetrahedron", '\0', NULL, NULL, TRUE, NULL, _MCB_Tetra, (EPointer)0);
 }

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

  EpM_RGBA8ImageFromCStruct(LImage, Image_Icosa);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_IcosaActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_IcosaArm);
  _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButtonImg("Tool->Create", "Icosahedron", '\0', NULL, NULL, TRUE, "Creae icosahedron\nRight button:  dialog box for this tool", _MCB_Icosa, (EPointer)0, LImage, LActiveImage, LArmImage);

  _IcosaInfo.Vertical=TRUE;
  _IcosaInfo.Radius=1.0;
  _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Create", "Icosahedron", '\0', NULL, NULL, TRUE, NULL, _MCB_Icosa, (EPointer)0);
 }

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

  EpM_RGBA8ImageFromCStruct(LImage, Image_Dodeca);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_DodecaActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_DodecaArm);
  _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButtonImg("Tool->Create", "Dodecahedron", '\0', NULL, NULL, TRUE, "Create dodecahedron\nRight button:  dialog box for this tool", _MCB_Dodeca, (EPointer)0, LImage, LActiveImage, LArmImage);

  _DodecaInfo.CenterAtBottom=FALSE;
  _DodecaInfo.Radius=1.0;
  _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Create", "Dodecahedron", '\0', NULL, NULL, TRUE, NULL, _MCB_Dodeca, (EPointer)0);
 }

 return(0);
}


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

 for(LC=0;LC<_NumOfMenuButtons;LC++)
 {
  if(_MenuButtons[LC]) EGUI_DestroyItem(_MenuButtons[LC]);
 }

 for(LC=0;LC<_NumOfToolPanelButtons;LC++)
 {
  if(_ToolPanelButtons[LC]) EGUI_DestroyItem(_ToolPanelButtons[LC]);
 }

 if(_TetraInfo.Class) E3d_GeometryClassDeactivate(_TetraInfo.Class);
 if(_IcosaInfo.Class) E3d_GeometryClassDeactivate(_IcosaInfo.Class);
 if(_DodecaInfo.Class) E3d_GeometryClassDeactivate(_DodecaInfo.Class);

 return(0);
}
