/*======================================================================================================*/
/* Add a box to the scene and change it interactively							*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-17 23:08:21									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <math.h>
#include <stdio.h>

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

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

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

#include <E3D/3DWindow.h>


static EPlugin*		_Plugin=NULL;

static EguiItem		_Dialog = NULL;
static Widget		_CenterAtBottomBW = NULL,
			_XEdgeLengthScaleW, _YEdgeLengthScaleW, _ZEdgeLengthScaleW,
			_XSubdivisionsScaleW, _YSubdivisionsScaleW, _ZSubdivisionsScaleW;


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

static EguiItem		_MenuButton=NULL, _ToolPanelButton=NULL;


static Arg		Args[256];
static Cardinal		ArgCnt;

extern EpCImage		Image_Cube;
extern EpCImage		Image_CubeActive;
extern EpCImage		Image_CubeArm;
extern EpCImage		Image_CubeBig;


enum
{
 E3dCR_SET_X_LENGTH=EguiCUSTOM0,
 E3dCR_SET_Y_LENGTH,
 E3dCR_SET_Z_LENGTH,
 E3dCR_SET_X_SUBDIVISIONS,
 E3dCR_SET_Y_SUBDIVISIONS,
 E3dCR_SET_Z_SUBDIVISIONS,
 E3dCR_SET_CENTER_AT_BOTTOM
};


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

// E3dBoxInfo part
//
 float		XEdgeLength, YEdgeLength, ZEdgeLength;
 int		XSubdivisions, YSubdivisions, ZSubdivisions;
 EBool		CenterAtBottom, Triangles;
} E3dBoxInfo;


#define ROffset(field) (void*)(EPtrOffset(E3dBoxInfo, field))
EResource _Resources[]=
{
 { "XEdgeLength",	EResFLOAT32,	ROffset(XEdgeLength), NULL },
 { "YEdgeLength",	EResFLOAT32,	ROffset(YEdgeLength), NULL },
 { "ZEdgeLength",	EResFLOAT32,	ROffset(ZEdgeLength), NULL },

 { "XSubdivisions",	EResINT,	ROffset(XSubdivisions), NULL },
 { "YSubdivisions",	EResINT,	ROffset(YSubdivisions), NULL },
 { "ZSubdivisions",	EResINT,	ROffset(ZSubdivisions), NULL },

 { "CenterAtBottom",	EResBOOLEAN,	ROffset(CenterAtBottom), NULL },
 { "Triangles",		EResBOOLEAN,	ROffset(Triangles), NULL },
 { "",			EResNULL,	NULL, NULL }
};


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



/*======================================*/
/* Set vertex coordinates		*/
/*======================================*/
static void _SetVertices(E3dVertex* LVertices, E3dBoxInfo* LInfo)
{
 register E3dVertex*	LVertex=LVertices;
 register E3dCoordinate	LXLenH, LYLenH, LZLenH, LX, LXStep, LY, LYStep, LZ, LZStep, LYMax, LYMin;
 int			LXSubdiv, LYSubdiv, LZSubdiv;
 unsigned int		LXCnt, LYCnt, LZCnt;

 LXSubdiv=LInfo->XSubdivisions;
 LYSubdiv=LInfo->YSubdivisions;
 LZSubdiv=LInfo->ZSubdivisions;

 LXLenH=LInfo->XEdgeLength*0.5;
 LYLenH=LInfo->YEdgeLength*0.5;
 LZLenH=LInfo->ZEdgeLength*0.5;


 if(LInfo->CenterAtBottom) { LYMax=LInfo->YEdgeLength;LYMin=0.0; }
 else { LYMax=LYLenH;LYMin=-LYLenH; }

 LXStep=LInfo->XEdgeLength/(E3dCoordinate)LXSubdiv;
 LYStep=LInfo->YEdgeLength/(E3dCoordinate)LYSubdiv;
 LZStep=LInfo->ZEdgeLength/(E3dCoordinate)LZSubdiv;

// Front side
//
 for(LYCnt=0, LY=LYMax;LYCnt<=LYSubdiv;LYCnt++, LY-=LYStep)
 {
  for(LXCnt=0, LX=-LXLenH;LXCnt<=LXSubdiv;LXCnt++, LX+=LXStep)
  {
//    E3d_VertexInit(LVertex++, LX, LY, LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LY/LVEdgeLength*3.1415));
   E3d_VertexInit(LVertex++, LX, LY, LZLenH);
  }
 }

  
// Sides
//
  for(LZCnt=1, LZ=LZLenH-LZStep;LZCnt<LZSubdiv;LZCnt++, LZ-=LZStep)
  {
   LY=LYMax;
// Top edge
//
   for(LXCnt=0, LX=-LXLenH;LXCnt<=LXSubdiv;LXCnt++, LX+=LXStep)
   {
    E3d_VertexInit(LVertex++, LX, LY, LZ);
   }

   LY=LYMax-LYStep;
// Side points
//
   for(LYCnt=1;LYCnt<LYSubdiv;LYCnt++, LY-=LYStep)
   {
    E3d_VertexInit(LVertex++, -LXLenH, LY, LZ);
    E3d_VertexInit(LVertex++,  LXLenH, LY, LZ);
   }

// Bottom edge
//
   LY=LYMin;
   for(LXCnt=0, LX=-LXLenH;LXCnt<=LXSubdiv;LXCnt++, LX+=LXStep)
   {
    E3d_VertexInit(LVertex++, LX, LY, LZ);
   }
  }

// Back side
//
 for(LYCnt=0, LY=LYMax;LYCnt<=LYSubdiv;LYCnt++, LY-=LYStep)
 {
  for(LXCnt=0, LX=-LXLenH;LXCnt<=LXSubdiv;LXCnt++, LX+=LXStep)
  {
//    E3d_VertexInit(LVertex++, LX, LY, LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LY/LVEdgeLength*3.1415));
   E3d_VertexInit(LVertex++, LX, LY, -LZLenH);
  }
 }
}


/*======================================*/
/* Get a box				*/
/*======================================*/
static E3dModel* _Get(E3dModel* LModel, E3dGeometry* LGeometry, E3dBoxInfo* LInfoV, unsigned int LFlags)
{
 E3dBoxInfo*		LInfo;
 E3dMesh*		LMesh;
 E3dPolyGroup*		LPolyGroup;
 E3dVertex*		LVertices;
 E3dPolygon*		LPolygons;
 E3dPolygon*		LPolygon;
 int			LXSubdiv, LYSubdiv, LZSubdiv, LVNum, LPNum,
			LRowA, LNextRowA, LRowAStep, LNextRowAStep,
			LV0, LV1, LV2, LV3;
 unsigned int		LXCnt, LYCnt, LZCnt;


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

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

//printf("Geo %p->%p\n", LGeometry, LInfo);fflush(stdout);


 LXSubdiv=LInfo->XSubdivisions;
 LYSubdiv=LInfo->YSubdivisions;
 LZSubdiv=LInfo->ZSubdivisions;

 LVNum=(LXSubdiv+1)*(LYSubdiv+1)*2+(LZSubdiv-1)*(LXSubdiv+LYSubdiv)*2;
 LPNum=LXSubdiv*LYSubdiv*2+LXSubdiv*LZSubdiv*2+LZSubdiv*LYSubdiv*2;

 if(LMesh)
 {
// Allocate Vertices for the Mesh
//
  if(LVNum==LMesh->NumOfVertices) LVertices=LMesh->Vertices;
  else
  {
   if(LMesh->Vertices) E3d_MeshFreeVertices(LMesh);
   if((LVertices=E3d_VerticesAllocate(LVNum, TRUE))!=NULL)
   {
    LMesh->Vertices=LVertices;LMesh->NumOfVertices=LVNum;
   }
   else LMesh->NumOfVertices=0;
  }

// Allocate Polygons for the Mesh
//
  if(LPNum==LPolyGroup->NumOfPolygons) LPolygons=LPolyGroup->Polygons;
  else
  {
   if(LPolyGroup->Polygons) E3d_PolyGroupFreePolygons(LPolyGroup);
   if((LPolygons=E3d_PolygonsAllocate(LPNum))!=NULL)
   {
    LPolyGroup->Polygons=LPolygons;LPolyGroup->NumOfPolygons=LPNum;
   }
  }

  LPolygon=LPolygons;

  _SetVertices(LVertices, LInfo);

// Build the Polygons
//

  LPolygon=LPolyGroup->Polygons;

// Front face
//
  LRowA=0;LNextRowA=LXSubdiv+1;

  if(LInfo->Triangles)
  {
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++, LRowA+=LXSubdiv+1, LNextRowA+=LXSubdiv+1)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSetAsTriangle(LPolygon++, LRowA+LXCnt+1, LRowA+LXCnt, LNextRowA+LXCnt);
     E3d_PolygonSetAsTriangle(LPolygon++, LNextRowA+LXCnt, LNextRowA+LXCnt+1, LRowA+LXCnt+1);
    }
   }
  }
  else
  {
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++, LRowA+=LXSubdiv+1, LNextRowA+=LXSubdiv+1)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LRowA+LXCnt, LNextRowA+LXCnt, LNextRowA+LXCnt+1, LRowA+LXCnt+1);
    }
   }
  }


  if(LZSubdiv<2)
  {
// Top side
//
   LRowA=(LXSubdiv+1)*(LYSubdiv+1)+(LZSubdiv-1)*(LXSubdiv+LYSubdiv)*2;
   for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LXCnt, LXCnt+1, LRowA+LXCnt+1, LRowA+LXCnt);
   }

// Bottom side
//
   LRowA=(LXSubdiv+1)*LYSubdiv;
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1)+(LXSubdiv+1)*LYSubdiv;
   for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LNextRowA+LXCnt, LNextRowA+LXCnt+1, LRowA+LXCnt+1, LRowA+LXCnt);
   }

// Left side
//
   LV0=0;
   LV1=(LXSubdiv+1)*(LYSubdiv+1);
   LV2=(LXSubdiv+1)*(LYSubdiv+1)+LXSubdiv+1;
   LV3=LXSubdiv+1;
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LV0, LV1, LV2, LV3);
    LV1=LV2;
    LV2+=LXSubdiv+1;
    LV0=LV3;
    LV3+=LXSubdiv+1;
   }

// Right side
//
   LV0=LXSubdiv;
   LV1=LXSubdiv+(LXSubdiv+1)*(LYSubdiv+1);
   LV2=(LXSubdiv+1)*(LYSubdiv+1)+LXSubdiv*2+1;
   LV3=LXSubdiv+LXSubdiv+1;
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
    LV1=LV2;
    LV2+=LXSubdiv+1;
    LV0=LV3;
    LV3+=LXSubdiv+1;
   }
  }
  else
  {
// Top side
//
   LRowA=0;
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1);
   for(LZCnt=0;LZCnt<(LZSubdiv-1);LZCnt++)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LRowA+LXCnt, LRowA+LXCnt+1, LNextRowA+LXCnt+1, LNextRowA+LXCnt);
    }
    LRowA=LNextRowA;
    LNextRowA+=((LXSubdiv+1)+(LYSubdiv-1))*2;
   }
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1)+(LZSubdiv-1)*(LXSubdiv+LYSubdiv)*2;
   for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LRowA+LXCnt, LRowA+LXCnt+1, LNextRowA+LXCnt+1, LNextRowA+LXCnt);
   }


// Bottom side
//
   LRowA=(LXSubdiv+1)*LYSubdiv;
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1)+LXSubdiv+1+(LYSubdiv-1)*2;
   for(LZCnt=1;LZCnt<LZSubdiv;LZCnt++)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LNextRowA+LXCnt, LNextRowA+LXCnt+1, LRowA+LXCnt+1, LRowA+LXCnt);
    }
    LRowA=LNextRowA;
    LNextRowA+=((LXSubdiv+1)+(LYSubdiv-1))*2;
   }
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1)+(LZSubdiv-1)*(LXSubdiv+LYSubdiv)*2+(LXSubdiv+1)*LYSubdiv;
   for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LNextRowA+LXCnt, LNextRowA+LXCnt+1, LRowA+LXCnt+1, LRowA+LXCnt);
   }


// Left side
//
   LRowA=0;LRowAStep=LXSubdiv+1;
   LNextRowA=(LXSubdiv+1)*(LYSubdiv+1);
   LNextRowAStep=2;

   for(LZCnt=1;LZCnt<LZSubdiv;LZCnt++)
   {
    LV0=LRowA;
    LV1=LNextRowA;
    LV2=LNextRowA+LXSubdiv+1;
    LV3=LRowA+LXSubdiv+1;
    for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LV0, LV1, LV2, LV3);
     LV1=LV2;
     LV2+=LNextRowAStep;
     LV0=LV3;
     LV3+=LRowAStep;
    }
    LRowA=LNextRowA;LRowAStep=2;
    LNextRowA+=(LXSubdiv+LYSubdiv)*2;
   }

   LV0=LRowA;
   LV1=LNextRowA;
   LV2=LNextRowA+LXSubdiv+1;
   LV3=LRowA+LXSubdiv+1;
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LV0, LV1, LV2, LV3);
    LV1=LV2;
    LV2+=LXSubdiv+1;
    LV0=LV3;
    LV3+=2;
   }

// Right side
//
   LRowA=LXSubdiv;LRowAStep=LXSubdiv+1;
   LNextRowA=LRowA+(LXSubdiv+1)*(LYSubdiv+1);

   LV0=LRowA;
   LV1=LNextRowA;
   LV2=LNextRowA+2;
   LV3=LRowA+LRowAStep;
   for(LYCnt=1;LYCnt<LYSubdiv;LYCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
    LV1=LV2;
    LV2+=2;
    LV0=LV3;
    LV3+=LRowAStep;
   }
   LV2+=(LXSubdiv-1);
   E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
   LRowA=LNextRowA;
   LNextRowA+=(LXSubdiv+LYSubdiv)*2;
   LRowAStep=2;

   for(LZCnt=2;LZCnt<LZSubdiv;LZCnt++)
   {
    LV0=LRowA;
    LV1=LNextRowA;
    LV2=LNextRowA+2;
    LV3=LRowA+LRowAStep;
    for(LYCnt=1;LYCnt<LYSubdiv;LYCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
     LV1=LV2;
     LV2+=2;
     LV0=LV3;
     LV3+=LRowAStep;
    }
    LV2+=(LXSubdiv-1);
    LV3+=(LXSubdiv-1);
    E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);

    LRowA=LNextRowA;
    LNextRowA+=(LXSubdiv+LYSubdiv)*2;
   }

   LV0=LRowA;
   LV1=LNextRowA;
   LV2=LNextRowA+LXSubdiv+1;
   LV3=LRowA+2;
   for(LYCnt=1;LYCnt<LYSubdiv;LYCnt++)
   {
    E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
    LV1=LV2;
    LV2+=LXSubdiv+1;
    LV0=LV3;
    LV3+=2;
   }
   LV3+=(LXSubdiv-1);
   E3d_PolygonSet(LPolygon++, 4, LV3, LV2, LV1, LV0);
  }


// Rear side
//
  LRowA=(LXSubdiv+1)*(LYSubdiv+1)+(LZSubdiv-1)*(LXSubdiv+LYSubdiv)*2;
  LNextRowA=LRowA+LXSubdiv+1;

  if(LInfo->Triangles)
  {
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++, LRowA+=LXSubdiv+1, LNextRowA+=LXSubdiv+1)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSetAsTriangle(LPolygon++, LNextRowA+LXCnt, LRowA+LXCnt, LRowA+LXCnt+1);
     E3d_PolygonSetAsTriangle(LPolygon++, LRowA+LXCnt+1, LNextRowA+LXCnt+1, LNextRowA+LXCnt);
    }
   }
  }
  else
  {
   for(LYCnt=0;LYCnt<LYSubdiv;LYCnt++, LRowA+=LXSubdiv+1, LNextRowA+=LXSubdiv+1)
   {
    for(LXCnt=0;LXCnt<LXSubdiv;LXCnt++)
    {
     E3d_PolygonSet(LPolygon++, 4, LRowA+LXCnt+1, LNextRowA+LXCnt+1, LNextRowA+LXCnt, LRowA+LXCnt);
    }
   }
  }


/*
  E3d_VertexInit(LVertex++, -LXLen,  LYLen,  LZLen);
  E3d_VertexInit(LVertex++,  LXLen,  LYLen,  LZLen);
  E3d_VertexInit(LVertex++,  LXLen, -LYLen,  LZLen);
  E3d_VertexInit(LVertex++, -LXLen, -LYLen,  LZLen);
  E3d_VertexInit(LVertex++, -LXLen,  LYLen, -LZLen);
  E3d_VertexInit(LVertex++,  LXLen,  LYLen, -LZLen);
  E3d_VertexInit(LVertex++,  LXLen, -LYLen, -LZLen);
  E3d_VertexInit(LVertex,   -LXLen, -LYLen, -LZLen);
*/

/*
  E3d_PolygonSet(LPolygon++, 4, 3, 2, 1, 0);
  E3d_PolygonSet(LPolygon++, 4, 1, 2, 6, 5);
  E3d_PolygonSet(LPolygon++, 4, 4, 5, 6, 7);
  E3d_PolygonSet(LPolygon++, 4, 0, 4, 7, 3);
  E3d_PolygonSet(LPolygon++, 4, 0, 1, 5, 4);
  E3d_PolygonSet(LPolygon, 4, 3, 7, 6, 2);
*/

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

  return(LModel);
 }
 return(NULL);
}


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

 XeToggleButtonSetState(_CenterAtBottomBW, LInfo->CenterAtBottom, False);
 XeScaleSetValueD(_XEdgeLengthScaleW, LInfo->XEdgeLength, False);
 XeScaleSetValueD(_YEdgeLengthScaleW, LInfo->YEdgeLength, False);
 XeScaleSetValueD(_ZEdgeLengthScaleW, LInfo->ZEdgeLength, False);

 XeScaleSetValue(_XSubdivisionsScaleW, LInfo->XSubdivisions, False);
 XeScaleSetValue(_YSubdivisionsScaleW, LInfo->YSubdivisions, False);
 XeScaleSetValue(_ZSubdivisionsScaleW, LInfo->ZSubdivisions, False);
}


/*======================================*/
/* GetBox dialog callback		*/
/*======================================*/
static void _DCB(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dMesh*	LMesh=(E3dMesh*)_Geometry;

 switch((int)LClientData)
 {
  case EguiOK:
   E3dTpl_GeoOK(_);
  break;

  case EguiADD:
   E3dTpl_GeoADD(_);
  break;

  case EguiCANCEL:
   E3dTpl_GeoCANCEL(_);
  break;

  case E3dCR_SET_CENTER_AT_BOTTOM:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->CenterAtBottom=(EBool)(((XeToggleButtonCallbackStruct*)LCallData)->set);

    _SetVertices(LMesh->Vertices, LInfo);

    E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_X_LENGTH:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->XEdgeLength=((XeScaleCallbackStruct*)LCallData)->FloatValue;

    _SetVertices(LMesh->Vertices, LInfo);

    E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_Y_LENGTH:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->YEdgeLength=((XeScaleCallbackStruct*)LCallData)->FloatValue;

    _SetVertices(LMesh->Vertices, LInfo);

    E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;
 
  case E3dCR_SET_Z_LENGTH:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->ZEdgeLength=((XeScaleCallbackStruct*)LCallData)->FloatValue;

    _SetVertices(LMesh->Vertices, LInfo);

    E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_X_SUBDIVISIONS:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->XSubdivisions=((XeScaleCallbackStruct*)LCallData)->IntValue;

    _Get(_Model, _Geometry, LInfo, E3dGF_ALL);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_Y_SUBDIVISIONS:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->YSubdivisions=((XeScaleCallbackStruct*)LCallData)->IntValue;

    _Get(_Model, _Geometry, LInfo, E3dGF_ALL);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case E3dCR_SET_Z_SUBDIVISIONS:
   {
    E3dBoxInfo*	LInfo=(E3dBoxInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);

    LInfo->ZSubdivisions=((XeScaleCallbackStruct*)LCallData)->IntValue;

    _Get(_Model, _Geometry, LInfo, E3dGF_ALL);

    E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;
 }
}


/*======================================*/
/* Pop up the dialog			*/
/*======================================*/
static void _PopupDialog(E3dBoxInfo* LInfo)
{
 if(_Dialog==NULL)
 {
  Widget	LTopMatrixW;
  Widget	LIndentWs[7];		// For indenting the ScaleWidgets
  Widget	LTraverseWs[7];		// For TextField traversal
  EguiItem	LDialog=E3d_GeometryDialogCreate("Cube / box", _MainGeometry, &_GeometryPanel, _DCB, &Image_CubeBig);
  int		LIndentN, LTraverseN;


  _Dialog=LDialog;

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



  EXtStart;
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNselectColor, EGUI_HighlightColor);
  EXtSetArg(XeNshadowThickness, 0);
  EXtSetArg(XeNhighlightThickness, 0);
  EXtSetArg(XeNmarginTop, 0);EXtSetArg(XeNmarginBottom, 4);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LInfo->CenterAtBottom);
  EXtSetArg(XeNwidthAdjustable, False);EXtSetArg(XeNxAlignment, XeALIGN_BEGINNING);
  _CenterAtBottomBW=XtCreateManagedWidget("Center at bottom", xeToggleButtonWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_CenterAtBottomBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_CENTER_AT_BOTTOM);

  LTraverseN=0;
  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 120);
  EXtSetArg(XeNtextFieldDigits, 9);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, (int)(LInfo->XEdgeLength*10000.0));
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_XEdgeLengthScaleW=XtCreateManagedWidget("Width (X):", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_XEdgeLengthScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_X_LENGTH);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 120);
  EXtSetArg(XeNtextFieldDigits, 9);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, (int)(LInfo->YEdgeLength*10000.0));
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_YEdgeLengthScaleW=XtCreateManagedWidget("Height (Y):", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_YEdgeLengthScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_Y_LENGTH);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 120);
  EXtSetArg(XeNtextFieldDigits, 9);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, (int)(LInfo->ZEdgeLength*10000.0));
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_ZEdgeLengthScaleW=XtCreateManagedWidget("Depth (Z):", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_ZEdgeLengthScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_Z_LENGTH);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 3);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100);
  EXtSetArg(XeNscaleMaximum, 20);
  EXtSetArg(XeNvalue, LInfo->XSubdivisions);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_XSubdivisionsScaleW=XtCreateManagedWidget("X subdivisions:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_XSubdivisionsScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_X_SUBDIVISIONS);

  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 3);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100);
  EXtSetArg(XeNscaleMaximum, 20);
  EXtSetArg(XeNvalue, LInfo->YSubdivisions);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_YSubdivisionsScaleW=XtCreateManagedWidget("Y subdivisions:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_YSubdivisionsScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_Y_SUBDIVISIONS);

  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 3);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 100);
  EXtSetArg(XeNscaleMaximum, 20);
  EXtSetArg(XeNvalue, LInfo->ZSubdivisions);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_ZSubdivisionsScaleW=XtCreateManagedWidget("Z subdivisions:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_ZSubdivisionsScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB, (XtPointer)E3dCR_SET_Z_SUBDIVISIONS);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


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

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


/*==============================================*/
/* Main callback (create new box)		*/
/*==============================================*/
static void _MCB(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dTpl_ACB_CHist(E3dBox, _);
}


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


/*======================================*/
/* Entry point of the plugin		*/
/*======================================*/
int Plugin_Init(EPlugin* LPlugin)
{
 E3dGeometryClass	LGeoClass=
   {
    "Box",			// Name
    sizeof(E3dBoxInfo),		// 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_Cube);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_CubeActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_CubeArm);
  _ToolPanelButton=EGUI_AddPushButtonImg("Tool->Create", "Box", '\0', NULL, NULL, TRUE, "Left button: Create cube or box with optional subdivisions\nRight button: dialog box for this tool", _MCB, (EPointer)0, LImage, LActiveImage, LArmImage);

  _Info.XEdgeLength=1.0;
  _Info.YEdgeLength=1.0;
  _Info.ZEdgeLength=1.0;
  _Info.XSubdivisions=1;
  _Info.YSubdivisions=1;
  _Info.ZSubdivisions=1;
  _Info.CenterAtBottom=FALSE;
  _Info.Triangles=FALSE;

  _MenuButton=EGUI_AddPushButton("Menu->Create", "Cube/Box", '\0', NULL, NULL, TRUE, NULL, _MCB, (EPointer)0);
 }
 return(0);
}


/*======================================*/
/* Exit method of the plugin		*/
/*======================================*/
int Plugin_Exit()
{
 if(_Dialog) E3d_GeometryPanelFree(&_GeometryPanel, FALSE);

 if(_MenuButton) EGUI_DestroyItem(_MenuButton);
 if(_ToolPanelButton) EGUI_DestroyItem(_ToolPanelButton);

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

 return(0);
}
