/*======================================================================================================*/
/* Transforms												*/
/*													*/
/* Plugin for EQUINOX-3D										*/
/*													*/
/* - Reset Transforms											*/
/* - Freeze Transforms											*/
/* - Freeze Scaling											*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-24 22:37:53									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <stdio.h>

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


#include <EGUI/PushButton.h>


#include <E3D/E3D.h>
#include <E3D/Matrix.h>
#include <E3D/3DWindow.h>
#include <E3D/StatusPanel.h>	// For E3dp_PrintMessage
#include <E3D/Panel.h>
#include <E3D/TagOps.h>



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

static unsigned int	_NumOfMenuButtons=0, _NumOfToolPanelButtons=0;


static EPlugin*	E3d_PluginRec=NULL;


//========================================
// Reset transforms on selection
//========================================
static void _CB_ResetTransforms(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 E3dModel*	LModel;
 unsigned int	LC, LN;


 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModel=LRootModels[LC];

  for(;LModel;LModel=LModel->Next)
  {
   switch(LModel->Selection)
   {
    case E3dSEL_NODE:
     if(LModel->Child==NULL) E3d_ModelResetTransforms(LModel);
    break;

    case E3dSEL_BRANCH_ROOT:
     E3d_ModelResetTransforms(LModel);
    break;
   }
  }

  E3d_ModelHrcRefreshMatrices(LRootModel);

  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
  E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, FALSE);
 }
}


//========================================
// Freeze transforms on selection
//========================================
static void _CB_FreezeTransforms(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 E3dModel*	LModel;
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 E3dMatrix	LMatrix, LNormalMatrix;
 unsigned int	LC, LN;
 unsigned int	LGmCnt, LGmNum;


 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModel=LRootModels[LC];

  do
  {
   if(LModel->Selection!=E3dSEL_NONE)
   {
    E3d_MatrixCopy(LModel->LocalToWorldMatrix, LMatrix);
    E3d_MatrixCopy(LModel->NormalLocalToWorldMatrix, LNormalMatrix);

    LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
    for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
    {
     if((LGeometry=LGeometries[LGmCnt])!=NULL) E3d_GeometryTransform(LGeometry, LMatrix, LNormalMatrix);
    }

    E3d_ModelResetTransforms(LModel);
   }

   LModel=LModel->Next;
  } while(LModel);

  E3d_ModelHrcUpdateForDisplay(LRootModel, E3dGF_SHAPE);
 }

 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, FALSE);
}


//========================================
// Freeze transforms on selections
// - Branch freeze to parent of branch
//========================================
static void _CB_FreezeBranchToItsParent(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 E3dModel*	LBranchRootModel;
 E3dModel*	LModelNextAfterBranch;
 E3dModel*	LModel;
 E3dModel	LTmpModel;
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 E3dMatrix	LMatrix, LNormalMatrix;
 unsigned int	LC, LN, LBranchesFroze;
 unsigned int	LGmCnt, LGmNum;


 LBranchesFroze=0;
 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModel=LRootModels[LC];

  do
  {
// Take care of this branch in one sitting
//
   if(LModel->Selection==E3dSEL_BRANCH_ROOT)
   {
    LBranchRootModel=LModel;

    if((LModelNextAfterBranch=E3d_ModelHrcBranchGetLastNode(LBranchRootModel))!=NULL) LModelNextAfterBranch=LModelNextAfterBranch->Next;
    else LModelNextAfterBranch=NULL;

    memcpy(&LTmpModel, LBranchRootModel, sizeof(E3dModel));	// Back-up transforms and Parent/NextSibling of branch-root

// Disconnect branch from the hierarchy
//
    LBranchRootModel->Parent=NULL;LBranchRootModel->NextSibling=NULL;
    E3d_ModelHrcRefreshHierarchy(LBranchRootModel);
    E3d_ModelHrcRefreshMatrices(LBranchRootModel);
    do
    {
     E3d_MatrixCopy(LModel->LocalToWorldMatrix, LMatrix);
     E3d_MatrixCopy(LModel->NormalLocalToWorldMatrix, LNormalMatrix);

     LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
     for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
     {
      if((LGeometry=LGeometries[LGmCnt])!=NULL) E3d_GeometryTransform(LGeometry, LMatrix, LNormalMatrix);
     }

     E3d_ModelResetTransforms(LModel);

     if((LModel=LModel->Next)==NULL) break;
    } while(LModel);
    LBranchesFroze++;
    memcpy(LBranchRootModel, &LTmpModel, sizeof(E3dModel));	// Restore transforms and Parent/NextSibling of branch-root
    E3d_ModelResetTransforms(LBranchRootModel);

    LModel=LModelNextAfterBranch;
   }
   else LModel=LModel->Next;
  } while(LModel);

  E3d_ModelHrcRefreshHierarchy(LRootModel);
  E3d_ModelHrcRefreshMatrices(LRootModel);

  E3d_ModelHrcUpdateForDisplay(LRootModel, E3dGF_SHAPE);
 }

 if(LBranchesFroze==0) E3dp_PrintMessage(0, 5000, "No branches selected\n");
 else
 {
  if(LBranchesFroze==1) E3dp_PrintMessage(0, 5000, "Froze: 1 branch");
  else E3dp_PrintMessage(0, 5000, "Froze: %d branches", LBranchesFroze);
 }

 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, FALSE);
}


//========================================
// Freeze transforms on selections
// - Branch freeze to root of branch
//========================================
static void _CB_FreezeBranchToItsRoot(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 E3dModel*	LBranchRootModel;
 E3dModel*	LModelNextAfterBranch;
 E3dModel*	LModel;
 E3dModel	LTmpModel;
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 E3dMatrix	LMatrix, LNormalMatrix;
 unsigned int	LC, LN, LBranchesFroze;
 unsigned int	LGmCnt, LGmNum;


 LBranchesFroze=0;LN=E3d_Scene->NumOfRootModels;
 LRootModels=E3d_Scene->RootModels;
 for(LC=0;LC<LN;LC++)
 {
  LModel=LRootModel=LRootModels[LC];

  do
  {
printf("In\n");fflush(stdout);
// Take care of this branch in one sitting
//
   if(LModel->Selection==E3dSEL_BRANCH_ROOT)
   {
    if(LModel->Child)
    {
     LBranchRootModel=LModel;

     if((LModelNextAfterBranch=E3d_ModelHrcBranchGetLastNode(LBranchRootModel))!=NULL) LModelNextAfterBranch=LModelNextAfterBranch->Next;
     else LModelNextAfterBranch=NULL;

     memcpy(&LTmpModel, LBranchRootModel, sizeof(E3dModel));	// Back-up transforms and Parent/NextSibling of branch-root

// Disconnect branch from the hierarchy
//
     E3d_ModelResetTransforms(LBranchRootModel);
     LBranchRootModel->Parent=NULL;LBranchRootModel->NextSibling=NULL;
     E3d_ModelHrcRefreshHierarchy(LBranchRootModel);
     E3d_ModelHrcRefreshMatrices(LBranchRootModel);

     LModel=LModel->Child;
     do
     {
      E3d_MatrixCopy(LModel->LocalToWorldMatrix, LMatrix);
      E3d_MatrixCopy(LModel->NormalLocalToWorldMatrix, LNormalMatrix);

      LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
      for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
      {
       if((LGeometry=LGeometries[LGmCnt])!=NULL) E3d_GeometryTransform(LGeometry, LMatrix, LNormalMatrix);
      }

      E3d_ModelResetTransforms(LModel);

      if((LModel=LModel->Next)==NULL) break;
     } while(LModel);
     LBranchesFroze++;
     memcpy(LBranchRootModel, &LTmpModel, sizeof(E3dModel));	// Restore transforms and Parent/NextSibling of branch-root

     LModel=LModelNextAfterBranch;
    }
    else LModel=LModel->Next;
   }
   else LModel=LModel->Next;
  } while(LModel);

  E3d_ModelHrcRefreshHierarchy(LRootModel);
  E3d_ModelHrcRefreshMatrices(LRootModel);
  E3d_ModelHrcUpdateForDisplay(LRootModel, E3dGF_SHAPE);
 }


 if(LBranchesFroze==0) E3dp_PrintMessage(0, 5000, "No branches selected\n");
 else
 {
  if(LBranchesFroze==1) E3dp_PrintMessage(0, 5000, "Froze: 1 branch");
  else E3dp_PrintMessage(0, 5000, "Froze: %d branches", LBranchesFroze);
 }

 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, TRUE);
}


//========================================
// Freeze scaling on selection
//========================================
static void _CB_FreezeScaling(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 unsigned int	LC, LN;


 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LRootModel=LRootModels[LC];

  if(LRootModel->Selection==E3dSEL_BRANCH_ROOT)
  {
   E3dp_SetProgressIndicator(0*1000/2, NULL, NULL);

   E3d_ModelHrcFreezeScaling(LRootModel);

   E3dp_SetProgressIndicator(1*1000/2, NULL, NULL);

   E3d_ModelHrcUpdateForDisplay(LRootModel, E3dGF_SHAPE);

   E3dp_SetProgressIndicator(2*1000/2, NULL, NULL);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, TRUE);

   E3dp_SetProgressIndicator(-1, NULL, NULL);
  }
 }
}


//========================================================================
// "Move the Model's local origin to the centroid of its Geometries
//========================================================================
static void _CB_OriginToCenter(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dModel**	LRootModels;
 E3dModel*	LRootModel;
 E3dModel*	LModel;
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 E3d3DPosition	LBBMin;
 E3d3DPosition	LBBMax;
 E3dCoordinate	LXOffset, LYOffset, LZOffset;
 E3dMatrix	LMatrix;
 unsigned int	LC, LN, LGmC, LGmN;
 EBool		LModelSelected, LFirst;


 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModel=LRootModels[LC];

  E3dM_IsModelSelected(LModel, LModelSelected);

  if(LModel->Selection!=E3dSEL_NONE)
  {
   E3d_ModelGetBoundingBox(LModel, &LBBMin, &LBBMax, E3dBB_SELECTED_GEOMETRY);

// Get center of bounding box of all selected Geometries on the Model
//
   LXOffset=(LBBMax.X-LBBMin.X)*0.5+LBBMin.X;
   LYOffset=(LBBMax.Y-LBBMin.Y)*0.5+LBBMin.Y;
   LZOffset=(LBBMax.Z-LBBMin.Z)*0.5+LBBMin.Z;

   E3d_MatrixCopy(LModel->LocalToWorldMatrix, LMatrix);
   LMatrix[M30]=0.0;
   LMatrix[M31]=0.0;
   LMatrix[M32]=0.0;
   E3d_MatrixTranslate(LMatrix, LXOffset, LYOffset, LZOffset);
   LModel->Translation.X+=LMatrix[M30];
   LModel->Translation.Y+=LMatrix[M31];
   LModel->Translation.Z+=LMatrix[M32];

   E3d_MatrixLoadIdentity(LMatrix);
   do
   {
    LGmN=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
    LFirst=TRUE;

    for(LGmC=0;LGmC<LGmN;LGmC++)
    {
     LGeometry=LGeometries[LGmC];
     if(LModelSelected||((LModel->Selection==E3dSEL_GEOMETRY)&&(LGeometry->Selection==E3dGSEL_GEOMETRY)))
     {
      E3d_GeometryGetBoundingBox(LGeometry, &LBBMin, &LBBMax, E3dBB_ALL);
//printf("[%s] BB: %f,%f,%f-%f,%f,%f\n", LGeometry->Name, LBBMin.X, LBBMin.Y, LBBMin.Z, LBBMax.X, LBBMax.Y, LBBMax.Z);fflush(stdout);
      LMatrix[M30]=-LXOffset;
      LMatrix[M31]=-LYOffset;
      LMatrix[M32]=-LZOffset;
      E3d_GeometryTransform(LGeometry, LMatrix, LMatrix);
      E3d_GeometryUpdateForDisplay(LGeometry, E3dGF_ALL);
     }
    }
    LModel=LModel->Next;
   } while(LModel);

   E3d_ModelHrcRefreshMatrices(LRootModel);

   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
   E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, TRUE);
  }
 }
}





typedef struct
{
// EOperator part
//
 EOperatorCore();

// E3dOperatorSnapTags part
//
 E3d3DPosition		GridSize;
 unsigned int		TransformAxes;
 unsigned int		NumOfShapeSnapshots;
 E3dShapeSnapshot*	ShapeSnapshots;
} E3dOperatorSnapTags;


//================================================
// Snap tags to grid Operator proc
//================================================
unsigned int E3dOp_SnapTags(EOperator* LOperatorIn, int LOperation)
{
 E3dOperatorSnapTags*	LOperator=(E3dOperatorSnapTags*)LOperatorIn;
 E3dShapeSnapshot*	LShapeSnapshot=LOperator->ShapeSnapshots;
 E3dInterface**		LOutputs=NULL;
 unsigned int		LGmC, LShapeN=LOperator->NumOfShapeSnapshots, LOC, LNumOfOutputs=0, LNumOfOutputsAllocated=0;


 switch(LOperation)
 {
  case EOpDO:
   {
    E3dModel*			LModel;
    E3dGeometry*		LGeometry;
    E3dGeometryCallbackStruct	LCBS;
    E3dMatrix			LLocalToWorldMatrix, LWorldToLocalMatrix;
    E3dCoordinate		mX, mY, mZ, LX, LY, LZ,
				LGridSizeX=LOperator->GridSize.X, LGridSizeY=LOperator->GridSize.Y, LGridSizeZ=LOperator->GridSize.Z;
    EBool			LGridSnapX=FALSE, LGridSnapY=FALSE, LGridSnapZ=FALSE;


    if(LOperator->TransformAxes&E3dDO_X) LGridSnapX=TRUE;
    if(LOperator->TransformAxes&E3dDO_Y) LGridSnapY=TRUE;
    if(LOperator->TransformAxes&E3dDO_Z) LGridSnapZ=TRUE;

    for(LGmC=0;LGmC<LShapeN;LGmC++, LShapeSnapshot++)
    {
     LGeometry=LShapeSnapshot->Geometry;

// Find the Model of this Geometry that has it selected to get the World->Local Matrix
// (by inverting LModel->LocalToWorldMatrix)
//
     LModel=E3d_GeometryGetSelectingModel(LGeometry);

     E3d_MatrixCopy(LModel->LocalToWorldMatrix, LLocalToWorldMatrix);

     if(LModel) E3d_MatrixInvert3x4(LLocalToWorldMatrix, LWorldToLocalMatrix);
     else E3d_MatrixLoadIdentity(LWorldToLocalMatrix);


     switch(LGeometry->GeoType)
     {
      caseE3dMESH():
       {
	E3dSnapshotVertex*	LSnapshotVertex=((E3dMeshVerticesSnapshot*)LShapeSnapshot)->SnapshotVertices;
	E3dVertex*		LVertices=((E3dMesh*)LGeometry)->Vertices;
	E3dVertex*		LVertex;
	unsigned int		LVC=((E3dMeshVerticesSnapshot*)LShapeSnapshot)->NumOfPoints;

// Snap in World space
//
	do
	{
	 LVertex=LVertices+LSnapshotVertex->Index;

         mX=LVertex->X;mY=LVertex->Y;mZ=LVertex->Z;
         E3dM_MatrixTransform3x4(LLocalToWorldMatrix, LX, LY, LZ);

         if(LGridSnapX) LX=E3d_SnapCoordinateTo(LX, LGridSizeX);
         if(LGridSnapY) LY=E3d_SnapCoordinateTo(LY, LGridSizeY);
         if(LGridSnapZ) LZ=E3d_SnapCoordinateTo(LZ, LGridSizeZ);

         mX=LX;mY=LY;mZ=LZ;
         E3dM_MatrixTransform3x4(LWorldToLocalMatrix, LVertex->X, LVertex->Y, LVertex->Z);
	 LSnapshotVertex++;
	} while(--LVC);


	E3d_GeometryUpdateForDisplay(LGeometry, E3dGF_SHAPE|E3dGF_REMAP_TEXTURES);
       }
      break;
     }
    }

    if(LOutputs)
    {
     LCBS.Reasons=E3dGF_SHAPE|E3dGF_NORMALS|E3dGF_REMAP_TEXTURES;
     E3d_CallOutputs(NULL, LOutputs, LNumOfOutputs, &LCBS);
     EFree(LOutputs);
    }
    return(E3dCHG_SHAPE);
   }

  case EOpUNDO:
  _M_UndoTagTransform();

  case EOpFREE:
   if(LShapeN)
   {
    E3d_ShapeSnapshotsFree(LOperator->ShapeSnapshots, LOperator->NumOfShapeSnapshots);
    LOperator->ShapeSnapshots=NULL;LOperator->NumOfShapeSnapshots=0;
   }
  break;
 }
 return(0);
}


//========================================
// Snap tagged points to the grid
//========================================
static void _CB_SnapTags(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 E3dp_ShapeSnapshots=E3d_SceneTaggedPointsToTransformPoints(E3d_Scene, &E3dp_NumOfShapeSnapshots);

 if(E3dp_NumOfShapeSnapshots>0)
 {
  E3dWindow*		L3DWindow=E3dp_Main3DWindow;
  E3dWindowSettings*	L3DWindowSettings=&(L3DWindow->Settings);
  E3dOperatorSnapTags*	LOperator;
  unsigned int		LGmN=E3dp_NumOfShapeSnapshots;
  int			LTranslateAxes=0;


// Store Point (Vertex, Spline key etc.) positions for undo
//
  LOperator=(E3dOperatorSnapTags*)EOp_OperatorAllocate("Snap tagged point(s) to grid", sizeof(E3dOperatorSnapTags), E3dOp_SnapTags);

  if(L3DWindowSettings->GridSnapToX) LTranslateAxes|=E3dDO_X;
  if(L3DWindowSettings->GridSnapToY) LTranslateAxes|=E3dDO_Y;
  if(L3DWindowSettings->GridSnapToZ) LTranslateAxes|=E3dDO_Z;
  LOperator->GridSize=L3DWindowSettings->GridSize;
  LOperator->TransformAxes=LTranslateAxes;
  LOperator->ShapeSnapshots=E3dp_ShapeSnapshots;
  LOperator->NumOfShapeSnapshots=LGmN;
  E3dp_ShapeSnapshots=NULL;E3dp_NumOfShapeSnapshots=0;

  E3dp_AppendOps1Operator((EOperator*)LOperator);


  E3dOp_SnapTags((EOperator*)LOperator, EOpDO);
  E3dp_Redraw3DWindows(E3dDF_ALL, E3dVM_NORMAL3D);
 }
}


//========================================
// Entry point of the plugin
//========================================
int Plugin_Init(EPlugin* LPlugin)
{
 E3d_PluginRec=LPlugin;

 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Reset", '\0', NULL, NULL, FALSE, NULL, _CB_ResetTransforms, (EPointer)0);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Freeze to world", '\0', NULL, NULL, FALSE, NULL, _CB_FreezeTransforms, (EPointer)0);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Freeze branch to its parent", '\0', NULL, NULL, FALSE, NULL, _CB_FreezeBranchToItsParent, (EPointer)0);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Freeze branch to its root", '\0', NULL, NULL, FALSE, NULL, _CB_FreezeBranchToItsRoot, (EPointer)0);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Freeze scaling on branch", '\0', NULL, NULL, FALSE, NULL, _CB_FreezeScaling, (EPointer)0);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Transform", "Snap tagged points to grid", '\0', NULL, NULL, FALSE, NULL, _CB_SnapTags, (EPointer)0);


 _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButton("Tool->Transform", "Reset", '\0', NULL, NULL, FALSE, NULL, _CB_ResetTransforms, (EPointer)0);
 _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButton("Tool->Transform", "Freeze to world", '\0', NULL, NULL, FALSE, "Perform the local->world transformations\n on the selected Models' geometries,\nthen reset the transformation values of the Models", _CB_FreezeTransforms, (EPointer)0);
 _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButton("Tool->Transform", "Freeze scaling", '\0', NULL, NULL, FALSE, NULL, _CB_FreezeScaling, (EPointer)0);
 _ToolPanelButtons[_NumOfToolPanelButtons++]=EGUI_AddPushButton("Tool->Transform", "Origin to ctr", '\0', NULL, NULL, FALSE, "Move the Model's local origin to\nthe center of its selected geometries", _CB_OriginToCenter, (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]);


 return(0);
}
