/*======================================================================================================*/
/* Create a grid and change it interactively								*/
/*													*/
/* Plugin for EQUINOX-3D										*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-17 22:43:27									*/
/*													*/
/* 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/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>

#include <E3D/StatusPanel.h>


static EPlugin*		_Plugin=NULL;

enum
{
 E3dPO_XY=0,
 E3dPO_XZ
};

enum
{
 E3dCR_ULENGHT=EguiCUSTOM0,
 E3dCR_VLENGHT,
 E3dCR_THICKNESS,
 E3dCR_XSUBDIV,
 E3dCR_YSUBDIV,
 E3dCR_UCURVATURE,
 E3dCR_VCURVATURE,
 E3dCR_HORIZONTAL,
 E3dCR_SMOOTH,
 E3dCR_TRIANGLES,
 E3dCR_BACKSIDE,
 E3dCR_SIDES
};

static EguiItem		_Dialog=NULL;
static Widget		_HorizontalBW=NULL, _SmoothBW=NULL,
			_TrianglesBW=NULL, _BackSideBW=NULL, _SidesBW=NULL,
			_UEdgeLengthScaleW=NULL, _VEdgeLengthScaleW=NULL, _ThicknessScaleW=NULL,
			_USubdivScaleW=NULL, _VSubdivScaleW=NULL,
			_UCurvatureScaleW=NULL, _VCurvatureScaleW=NULL;

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_Grid;
extern EpCImage		Image_GridActive;
extern EpCImage		Image_GridArm;
extern EpCImage		Image_GridBig;


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

// E3dGridInfo part
//
 float		UCurvature, VCurvature;
 float		UEdgeLength, VEdgeLength, Thickness;
 int		USubdivisions, VSubdivisions, Orientation;
 EBool		Smooth, BackSide, Sides, Triangles;
} E3dGridInfo;


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

static EResource _Resources[]=
{
 { "UCurvature",	EResFLOAT32,	ROffset(UCurvature), NULL },
 { "VCurvature",	EResFLOAT32,	ROffset(VCurvature), NULL },
 { "UEdgeLength",	EResFLOAT32,	ROffset(UEdgeLength), NULL },
 { "VEdgeLength",	EResFLOAT32,	ROffset(VEdgeLength), NULL },
 { "Thickness",		EResFLOAT32,	ROffset(Thickness), NULL },

 { "USubdivisions",	EResINT,	ROffset(USubdivisions), NULL },
 { "VSubdivisions",	EResINT,	ROffset(VSubdivisions), NULL },
 { "Orientation",	EResINT,	ROffset(Orientation), NULL },

 { "Smooth",		EResBOOLEAN,	ROffset(Smooth), NULL },
 { "BackSide",		EResBOOLEAN,	ROffset(BackSide), NULL },
 { "Sides",		EResBOOLEAN,	ROffset(Sides), NULL },
 { "Triangles",		EResBOOLEAN,	ROffset(Triangles), NULL },
 { "",			EResNULL,	NULL, NULL }
};


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



void _GetDEM(char* LFileName, unsigned int LMapXSize, unsigned int LMapYSize, unsigned int LInUOffset, unsigned int LInVOffset, E3dVertex* LVertex, unsigned int LUSubdiv, unsigned int LVSubdiv, E3dCoordinate LUEdgeLength, E3dCoordinate LVEdgeLength)
{
 FILE*		LInFile;
 E3dCoordinate	LUStep=LUEdgeLength/(E3dCoordinate)LUSubdiv;
 E3dCoordinate	LVStep=LVEdgeLength/(E3dCoordinate)LVSubdiv;
 E3dCoordinate	LULenH=LUEdgeLength*0.5;
 E3dCoordinate	LVLenH=LVEdgeLength*0.5,
		LU, LV;
 unsigned int	LUCnt, LVCnt;
 short		LSV;
 unsigned char*	LRowBuffer=EMalloc((LUSubdiv+1)*2);

 if(LRowBuffer)
 {
  if((LInFile=fopen(LFileName, "r"))!=NULL)
  {
   unsigned char*	LPtr;

// Front side
//

   E3dp_SetProgressIndicator(0, NULL, NULL);

   for(LVCnt=0, LV=-LVLenH;LVCnt<=LVSubdiv;LVCnt++, LV+=LVStep)
   {
    fseek(LInFile, ((LInVOffset+LVCnt)*LMapXSize+LInUOffset)*2, SEEK_SET);

    fread(LRowBuffer, (LUSubdiv+1)*2, 1, LInFile);
    LPtr=LRowBuffer;


    for(LUCnt=0, LU=-LULenH;LUCnt<=LUSubdiv;LUCnt++, LU+=LUStep)
    {
     EM_GetShortI(LSV, LPtr);
if(LSV==-9999) LSV=-1000;
     E3d_VertexInit(LVertex++, LU, ((E3dCoordinate)LSV*0.00032), LV);
    }

    E3dp_SetProgressIndicator((LVCnt*1000)/LVSubdiv, NULL, NULL);

   }

   E3dp_SetProgressIndicator(-1, NULL, NULL);E3dp_SyncGUI();
   fclose(LInFile);
  }
  EFree(LRowBuffer);
 }
}




/*======================================*/
/* Set vertex coordinates		*/
/*======================================*/
static void _SetVertices(E3dVertex* LVertices, E3dGridInfo* LGridInfo)
{
 register E3dVertex*	LVertex=LVertices;
 register E3dCoordinate	LULenH, LVLenH, LUEdgeLength, LVEdgeLength, LThicknessH,
			LX, LUStep, LV, LVStep;
 E3dCoordinate		LUCurvature, LVCurvature;
 int			LUSubdiv, LVSubdiv;
 unsigned int		LUCnt, LVCnt;

 LUSubdiv=LGridInfo->USubdivisions;
 LVSubdiv=LGridInfo->VSubdivisions;

 LUEdgeLength=LGridInfo->UEdgeLength;
 LVEdgeLength=LGridInfo->VEdgeLength;

 LULenH=LUEdgeLength*0.5;
 LVLenH=LVEdgeLength*0.5;
 LThicknessH=LGridInfo->Thickness*0.5;

 LUStep=LUEdgeLength/(E3dCoordinate)LUSubdiv;
 LVStep=LVEdgeLength/(E3dCoordinate)LVSubdiv;

 LUCurvature=LGridInfo->UCurvature;
 LVCurvature=LGridInfo->VCurvature;



 switch(LGridInfo->Orientation)
 {
  case E3dPO_XY:
// Front side
//
   for(LVCnt=0, LV=LVLenH;LVCnt<=LVSubdiv;LVCnt++, LV-=LVStep)
   {
    for(LUCnt=0, LX=-LULenH;LUCnt<=LUSubdiv;LUCnt++, LX+=LUStep)
    {
     E3d_VertexInit(LVertex++, LX, LV, LThicknessH+LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LV/LVEdgeLength*3.1415));
    }
   }


   if(LGridInfo->BackSide)
   {
// Back side
//
    for(LVCnt=0, LV=LVLenH;LVCnt<=LVSubdiv;LVCnt++, LV-=LVStep)
    {
     for(LUCnt=0, LX=-LULenH;LUCnt<=LUSubdiv;LUCnt++, LX+=LUStep)
     {
      E3d_VertexInit(LVertex++, LX, LV, -LThicknessH+LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LV/LVEdgeLength*3.1415));
     }
    }
   }
  break;

  case E3dPO_XZ:
//   _GetDEM("/usr1/u/gnagy/dem/W140N40.DEM", 4800, 6000, 2000, 100, LVertex, LUSubdiv, LVSubdiv, LUEdgeLength, LVEdgeLength);

// Front side
//
   for(LVCnt=0, LV=-LVLenH;LVCnt<=LVSubdiv;LVCnt++, LV+=LVStep)
   {
    for(LUCnt=0, LX=-LULenH;LUCnt<=LUSubdiv;LUCnt++, LX+=LUStep)
    {
     E3d_VertexInit(LVertex++, LX, -(-LThicknessH+LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LV/LVEdgeLength*3.1415)), LV);
    }
   }


   if(LGridInfo->BackSide)
   {
// Back side
//
    for(LVCnt=0, LV=-LVLenH;LVCnt<=LVSubdiv;LVCnt++, LV+=LVStep)
    {
     for(LUCnt=0, LX=-LULenH;LUCnt<=LUSubdiv;LUCnt++, LX+=LUStep)
     {
      E3d_VertexInit(LVertex++, LX, -(LThicknessH+LUCurvature*LUEdgeLength*cos(LX/LUEdgeLength*3.1415)+LVCurvature*LVEdgeLength*cos(LV/LVEdgeLength*3.1415)), LV);
     }
    }
   }
  break;
 }
}


/*======================================*/
/* Get a grid				*/
/*======================================*/
static E3dModel* _Get(E3dModel* LModel, E3dGeometry* LGeometry, E3dGridInfo* LGridInfoV, unsigned int LFlags)
{
 E3dGridInfo*		LGridInfo;
 E3dMesh*		LMesh;
 E3dCoordinate		LUEdgeLength, LVEdgeLength;
 E3dPolyGroup*		LPolyGroup;
 E3dPolygon*		LPolygon;
 E3dPolygon*		LPolygons;
 E3dVertex*		LVertices;
 unsigned int		LUSubdiv, LVSubdiv;
 unsigned int		LUCnt, LVCnt, LVNum, LPNum;
 unsigned int		LRowA, LNextRowA;


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

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

 LUEdgeLength=LGridInfo->UEdgeLength;
 LVEdgeLength=LGridInfo->VEdgeLength;
 LUSubdiv=LGridInfo->USubdivisions;
 LVSubdiv=LGridInfo->VSubdivisions;

 LVNum=(LUSubdiv+1)*(LVSubdiv+1);
 if(LGridInfo->BackSide) LVNum*=2;

 LPNum=LUSubdiv*LVSubdiv;

 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(LGridInfo->BackSide) LPNum*=2;
  if(LGridInfo->Sides) LPNum+=LUSubdiv*2+LVSubdiv*2;
  if(LGridInfo->Triangles) LPNum*=2;

  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;
   }
  }

// Set up the Mesh vertices
//
  _SetVertices(LMesh->Vertices, LGridInfo);


// Build the Polygons
//
// Front side
//
  LPolygon=E3d_GridBuildPolygons(LPolyGroup->Polygons, LUSubdiv, LVSubdiv, 0, LGridInfo->Triangles);

//  E3d_GridBuildPolygons(LPolyGroup->Polygons, LUSubdiv, LVSubdiv, (LUSubdiv+1)*(LVSubdiv+1), LGridInfo->Triangles);


// Rear side
//
  if(LGridInfo->BackSide)
  {
   LRowA=(LUSubdiv+1)*(LVSubdiv+1);LNextRowA=LRowA+LUSubdiv+1;

   if(LGridInfo->Triangles)
   {
    for(LVCnt=0;LVCnt<LVSubdiv;LVCnt++, LRowA+=LUSubdiv+1, LNextRowA+=LUSubdiv+1)
    {
     for(LUCnt=0;LUCnt<LUSubdiv;LUCnt++)
     {
      E3d_PolygonSetAsTriangle(LPolygon++, LNextRowA+LUCnt, LRowA+LUCnt, LRowA+LUCnt+1);
      E3d_PolygonSetAsTriangle(LPolygon++, LRowA+LUCnt+1, LNextRowA+LUCnt+1, LNextRowA+LUCnt);
     }
    }
   }
   else
   {
    for(LVCnt=0;LVCnt<LVSubdiv;LVCnt++, LRowA+=LUSubdiv+1, LNextRowA+=LUSubdiv+1)
    {
     for(LUCnt=0;LUCnt<LUSubdiv;LUCnt++)
     {
      E3d_PolygonSet(LPolygon++, 4, LRowA+LUCnt+1, LNextRowA+LUCnt+1, LNextRowA+LUCnt, LRowA+LUCnt);
     }
    }
   }

  }


  if(LGridInfo->Smooth)
  {
   LPolyGroup->VertexNormalType=E3dNormalAVERAGED;
   LPolyGroup->Flags|=E3dUSE_VERTEX_NORMALS;
   E3d_MeshRefreshNormals(LMesh, TRUE);
  }
  else
  {
   LPolyGroup->VertexNormalType=E3dNONE;
   LPolyGroup->Flags&=E3dALL-E3dUSE_VERTEX_NORMALS;
   E3d_MeshRefreshPolygonNormals(LMesh);
  }

//Printf("GeoDone\n");fflush(stdout);
  E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, LFlags&(E3dGF_ALL-E3dGF_CALL_DESTROYPROCS));
//  E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, (LFlags&(E3dGF_ALL-E3dGF_TOPOLOGY))|E3dGF_VERTEX_POSITION);
//Printf(" .\n");fflush(stdout);
  return(LModel);
 }
 return(NULL);
}


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

 XeToggleButtonSetState(_HorizontalBW, LGridInfo->Orientation==E3dPO_XZ, False);
 XeToggleButtonSetState(_SmoothBW, LGridInfo->Smooth, False);
 XeToggleButtonSetState(_TrianglesBW, LGridInfo->Triangles, False);
 XeToggleButtonSetState(_BackSideBW, LGridInfo->BackSide, False);
 XeToggleButtonSetState(_SidesBW, LGridInfo->Sides, False);

 XeScaleSetValueD(_UEdgeLengthScaleW, LGridInfo->UEdgeLength, False);
 XeScaleSetValueD(_VEdgeLengthScaleW, LGridInfo->VEdgeLength, False);
 XeScaleSetValueD(_ThicknessScaleW, LGridInfo->Thickness, False);

 XeScaleSetValue(_USubdivScaleW, LGridInfo->USubdivisions, False);
 XeScaleSetValue(_VSubdivScaleW, LGridInfo->VSubdivisions, False);

 XeScaleSetValueD(_UCurvatureScaleW, LGridInfo->UCurvature, False);
 XeScaleSetValueD(_VCurvatureScaleW, LGridInfo->VCurvature, False);
}


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

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

  case EguiADD:
   E3dTpl_GeoDoneEditing(_);

   _CreateMode=TRUE;

   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);
  break;
 }
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _DCB_Settings(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dMesh*	LMesh=(E3dMesh*)_Geometry;
 E3dPolyGroup*	LPolyGroup;
 E3dGridInfo*	LGridInfo=(E3dGridInfo*)E3d_GeometryInfoByClass(_Geometry, _Info.Class);


 switch((int)LClientData)
 {
  case E3dCR_SMOOTH:
   LPolyGroup=LMesh->PolyGroups[0];
   LGridInfo->Smooth=((XeToggleButtonCallbackStruct*)LCallData)->set;
   if(LGridInfo->Smooth)
   {
    LPolyGroup->VertexNormalType=E3dNormalAVERAGED;
    E3d_MeshPolyGroupRefreshNormals(LMesh, LPolyGroup, LPolyGroup->VertexNormalType, TRUE);
    LPolyGroup->Flags|=E3dUSE_VERTEX_NORMALS;
    E3d_MeshRefreshGLNormals(LMesh, _Model->LocalToWorldMatrix);
   }
   else
   {
    LPolyGroup->VertexNormalType=E3dNONE;
    LPolyGroup->Flags&=E3dALL-E3dUSE_VERTEX_NORMALS;
   }
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_HORIZONTAL:
   if(((XeToggleButtonCallbackStruct*)LCallData)->set) LGridInfo->Orientation=E3dPO_XZ;
   else LGridInfo->Orientation=E3dPO_XY;
   _SetVertices(LMesh->Vertices, LGridInfo);
   LPolyGroup=LMesh->PolyGroups[0];
   E3d_MeshPolyGroupRefreshNormals(LMesh, LPolyGroup, LPolyGroup->VertexNormalType, TRUE);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_TRIANGLES:
   LGridInfo->Triangles=((XeToggleButtonCallbackStruct*)LCallData)->set;
   _Get(_Model, _Geometry, LGridInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_BACKSIDE:
   LGridInfo->BackSide=((XeToggleButtonCallbackStruct*)LCallData)->set;
   _Get(_Model, _Geometry, LGridInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_SIDES:
//   LGridInfo->Sides=((XeToggleButtonCallbackStruct*)LCallData)->set;
   _Get(_Model, _Geometry, LGridInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_ULENGHT:
   LGridInfo->UEdgeLength=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(((E3dMesh*)_Geometry)->Vertices, LGridInfo);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_VLENGHT:
   LGridInfo->VEdgeLength=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(((E3dMesh*)_Geometry)->Vertices, LGridInfo);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_THICKNESS:
   LGridInfo->Thickness=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(((E3dMesh*)_Geometry)->Vertices, LGridInfo);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_XSUBDIV:
   LGridInfo->USubdivisions=((XeScaleCallbackStruct*)LCallData)->IntValue;
   _Get(_Model, _Geometry, LGridInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_YSUBDIV:
   LGridInfo->VSubdivisions=((XeScaleCallbackStruct*)LCallData)->IntValue;
   _Get(_Model, _Geometry, LGridInfo, E3dGF_ALL);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_UCURVATURE:
   LGridInfo->UCurvature=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(((E3dMesh*)_Geometry)->Vertices, LGridInfo);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;

  case E3dCR_VCURVATURE:
   LGridInfo->VCurvature=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   _SetVertices(((E3dMesh*)_Geometry)->Vertices, LGridInfo);
   E3d_GeometryUpdateForDisplay(_Geometry, E3dGF_SHAPE);
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  break;
 }
}


/*======================================*/
/* Pop up the dialog			*/
/*======================================*/
static void _PopupDialog(E3dGridInfo* LGridInfo)
{
 if(_Dialog==NULL)
 {
  Widget	LTopMatrixW, LMatrixW;
  Widget	LIndentWs[7];
  Widget	LTraverseWs[8];
  unsigned int	LTraverseN, LIndentN;
  EguiItem	LDialog=E3d_GeometryDialogCreate("Grid", _MainGeometry, &_GeometryPanel, _DCB, &Image_GridBig);


  _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, 8);
  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(XeNmarginLeft, 0);EXtSetArg(XeNmarginRight, 0);EXtSetArg(XeNmarginTop, 0);
  EXtSetArg(XeNmarginBottom, 0);
  EXtSetArg(XeNrecomputeSize, False);
  EXtSetArg(XeNfontList, EGUI_LabelFontList);
  EXtSetArg(XeNset, LGridInfo->Orientation==E3dPO_XZ);
  _HorizontalBW=XtCreateManagedWidget("Horizontal", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_HorizontalBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_HORIZONTAL);

  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, LGridInfo->Smooth);
  _SmoothBW=XtCreateManagedWidget("Smooth", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_SmoothBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_SMOOTH);

  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, LGridInfo->Triangles);
  _TrianglesBW=XtCreateManagedWidget("Triangles", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_TrianglesBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_TRIANGLES);

  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, LGridInfo->BackSide);
  _BackSideBW=XtCreateManagedWidget("Back", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_BackSideBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_BACKSIDE);

  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, LGridInfo->Sides);
  _SidesBW=XtCreateManagedWidget("Sides", xeToggleButtonWidgetClass, LMatrixW, Args, ArgCnt);
  XtAddCallback(_SidesBW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_SIDES);

  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, 7);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, LGridInfo->UEdgeLength*10000);
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_UEdgeLengthScaleW=XtCreateManagedWidget("U Edge length:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_UEdgeLengthScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_ULENGHT);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, LGridInfo->VEdgeLength*10000);
  EXtSetArg(XeNscaleMinimum, 10000);EXtSetArg(XeNscaleMaximum, 1000000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_VEdgeLengthScaleW=XtCreateManagedWidget("V Edge length:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_VEdgeLengthScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_VLENGHT);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, 0);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, LGridInfo->Thickness*10000);
  EXtSetArg(XeNscaleMinimum, 0);EXtSetArg(XeNscaleMaximum, 100000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_ThicknessScaleW=XtCreateManagedWidget("Thickness:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_ThicknessScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_THICKNESS);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 0);


  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 5);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 10000);EXtSetArg(XeNvalue, LGridInfo->USubdivisions);
  EXtSetArg(XeNscaleMinimum, 1);EXtSetArg(XeNscaleMaximum, 100);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_USubdivScaleW=XtCreateManagedWidget("U Subdivisions:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_USubdivScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_XSUBDIV);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 5);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 10000);EXtSetArg(XeNvalue, LGridInfo->VSubdivisions);
  EXtSetArg(XeNscaleMinimum, 1);EXtSetArg(XeNscaleMaximum, 100);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_VSubdivScaleW=XtCreateManagedWidget("V Subdivisions:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_VSubdivScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_YSUBDIV);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


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

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, -10000);EXtSetArg(XeNmaximum, 10000);EXtSetArg(XeNvalue, LGridInfo->UCurvature*10000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_UCurvatureScaleW=XtCreateManagedWidget("U Curvature:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_UCurvatureScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_UCURVATURE);

  EXtStart;
  EXtSetArg(XeNscaleLengthInPixels, 200);
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 4);
  EXtSetArg(XeNminimum, -10000);EXtSetArg(XeNmaximum, 10000);EXtSetArg(XeNvalue, LGridInfo->VCurvature*10000);
  EXtSetArg(XeNincrement, 10);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_VCurvatureScaleW=XtCreateManagedWidget("V Curvature:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_VCurvatureScaleW, XeNvalueChangedCallback, (XtCallbackProc)_DCB_Settings, (XtPointer)E3dCR_VCURVATURE);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


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

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


/*==============================================*/
/* Menu callback				*/
/*==============================================*/
static void _MCB(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dTpl_ACB_CHist(E3dGrid, _);
}


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


/*======================================*/
/* Entry point of the plugin		*/
/*======================================*/
int Plugin_Init(EPlugin* LPlugin)
{
 E3dGeometryClass	LGeoClass=
   {
    "Grid",			// Name
    sizeof(E3dGridInfo),	// 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_Grid);
  EpM_RGBA8ImageFromCStruct(LActiveImage, Image_GridActive);
  EpM_RGBA8ImageFromCStruct(LArmImage, Image_GridArm);
  _ToolPanelButton=EGUI_AddPushButtonImg("Tool->Create", "Grid", '\0', NULL, NULL, TRUE, "Create grid\nRight button:  dialog box for this tool", _MCB, (EPointer)0, LImage, LActiveImage, LArmImage);

  _Info.USubdivisions=4;_Info.VSubdivisions=4;
  _Info.Orientation=E3dPO_XY;
  _Info.UCurvature=0.0;_Info.VCurvature=0.0;
  _Info.UEdgeLength=2.0;
  _Info.VEdgeLength=2.0;
  _Info.Thickness=0.0;

  _Info.Smooth=TRUE;
  _Info.Triangles=TRUE;
  _Info.BackSide=FALSE;
  _Info.Sides=FALSE;

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

 return(0);
}


/*======================================*/
/* Exit method of the plugin		*/
/*======================================*/
int Plugin_Exit()
{
 if(_MenuButton!=NULL) EGUI_DestroyItem(_MenuButton);
 if(_ToolPanelButton!=NULL) EGUI_DestroyItem(_ToolPanelButton);

 if(_Info.Class!=NULL) E3d_GeometryClassDeactivate(_Info.Class);

 return(0);
}
