/*======================================================================================================*/
/* Camera functions											*/
/*													*/
/* Plugin for EQUINOX-3D										*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Nov-12 23:00:55									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <stdio.h>
#include <math.h>

#include <EPlugins.h>

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

#include <Xe/Label.h>
#include <Xe/Scale.h>

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

static EPlugin*		_Plugin=NULL;

static EguiItem		_SettingsDialog=NULL;
static Widget		_FieldOfViewScaleW, _FarPlaneScaleW,
			_OrbitingStepScaleW, _FrameToTimeScaleW;


static EguiItem		_MenuButtons[16];

static unsigned int	_NumOfMenuButtons=0;


static E3d3DPosition	_StartInterest, _StartPosition,
			_EndInterest, _EndPosition,
			_InterestStep, _PositionStep;

static float		_FrameToTimeLeft=0.0;
static E3dWindow*	_FramingWindow=NULL;


static Arg		Args[256];
static Cardinal		ArgCnt;


enum
{
 CR_FIELD_OF_VIEW=EguiCUSTOM0,
 CR_FAR_PLANE,
 CR_FRAME_TO_TIME,
 CR_ORBITING_STEP
};


/*------------------------------*/
/* From main.c			*/
/*------------------------------*/
extern EguiItem		Eqx_TopShell;


// Operations
//
enum
{
 CR_RESET_CAMERA_ON_ALL_WINDOWS=1,
 CR_RESET_WINDOW_CAMERA,
 CR_ATTACH_CAMERA,
 CR_DETACH_CAMERA,
 CR_FRAME_ALL_ON_CURRENT_WINDOW,
 CR_FRAME_ALL_ON_ALL_WINDOWS,
 CR_FRAME_SELECTION_ON_CURRENT_WINDOW,
 CR_FRAME_SELECTION_ON_ALL_WINDOWS,
 CR_FRAME_TAG_ON_CURRENT_WINDOW,
 CR_FRAME_TAG_ON_ALL_WINDOWS
};



/*==============================================================================*/
/* Compute the bounding box of a Model in Screen coordinates			*/
/*										*/
/* Arguments									*/
/*  E3dModel*      LModel      Pointer to the Model structure			*/
/*  E3d2DPosition* LBBMin      First corner of bounding box			*/
/*  E3d2DPosition* LBBMax      Opposite corner of bounding box			*/
/*										*/
/* Description									*/
/*  Computes the world-relative bounding box of a Model and returns it in	*/
/*  LBBMin and LBBMax.								*/
/*										*/
/* Return value									*/
/*  TRUE if there is a valid bounding box, FALSE if there isn't one (e.g. the	*/
/*  Model has no geometry attached to it).					*/
/*==============================================================================*/
EBool E3d_ModelGetPerspectiveProjectedBoundingBox(E3dModel* LModel, E3dMatrix LMatrix, E3d2DPosition* LBBMin, E3d2DPosition* LBBMax, E3dHPosition* LMaxProjectedXYAbsValPoint, unsigned int LWhatToInclude)
{
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 E3d2DPosition	LTBBMin, LTBBMax;
 E3dHPosition	LTMaxProjectedXYAbsValPoint;
 E3dCoordinate	LMaxXYAbsVal=0.0;
 unsigned int	LGmCnt, LGmNum;
 EBool		LResult=FALSE, LFirst=TRUE;


 LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
 for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
 {
  LGeometry=LGeometries[LGmCnt];
  if(LGeometry)
  {
   if(LFirst)
   {
    E3d_GeometryGetPerspectiveProjectedBoundingBox(LGeometry, LMatrix, LBBMin, LBBMax, LMaxProjectedXYAbsValPoint, LWhatToInclude);LResult=TRUE;

    LMaxXYAbsVal=LMaxProjectedXYAbsValPoint->W;
    LFirst=FALSE;
   }
   else
   {
    if(E3d_GeometryGetPerspectiveProjectedBoundingBox(LGeometry, LMatrix, &LTBBMin, &LTBBMax, &LTMaxProjectedXYAbsValPoint, LWhatToInclude))
    {
     if(LTBBMin.X < LBBMin->X) LBBMin->X = LTBBMin.X;
     if(LTBBMax.X > LBBMax->X) LBBMax->X = LTBBMax.X;

     if(LTBBMin.Y < LBBMin->Y) LBBMin->Y = LTBBMin.Y;
     if(LTBBMax.Y > LBBMax->Y) LBBMax->Y = LTBBMax.Y;

     if(LTMaxProjectedXYAbsValPoint.W>LMaxXYAbsVal)
     {
      LMaxProjectedXYAbsValPoint->X=LTMaxProjectedXYAbsValPoint.X;
      LMaxProjectedXYAbsValPoint->Y=LTMaxProjectedXYAbsValPoint.Y;
      LMaxProjectedXYAbsValPoint->Z=LTMaxProjectedXYAbsValPoint.Z;
      LMaxProjectedXYAbsValPoint->W=LTMaxProjectedXYAbsValPoint.W;
      LMaxXYAbsVal=LTMaxProjectedXYAbsValPoint.W;
     }

     LResult=TRUE;
    }
   }
  }

 }

 return(LResult);
}


/*======================================================*/
/* Get projected bounds of the selection		*/
/*======================================================*/
EBool E3d_SceneGetProjectedBounds(E3dScene* LScene, E3dCamera* LCamera, float LAspectRatio, E3d2DPosition* LAllBBMin, E3d2DPosition* LAllBBMax, E3dHPosition* LAllMaxProjectedXYAbsValPoint, unsigned int LWhatToInclude)
{
 E3dModel**	LRootModels;
 E3dModel*	LModel;
 unsigned int	LC, LN, LTWhatToInclude;
 E3dMatrix	LMatrix;
 E3d2DPosition	LBBMin, LBBMax;
 E3dMatrix	LWorldToScreenMatrix;
 E3dMatrix	LLocalToViewerMatrix;
 E3dType	mX, mY, mZ, LXF=0.0, LYF=0.0, LZF=0.0, LMaxXYAbsVal=0.0;
 E3dHPosition	LMaxProjectedXYAbsValPoint;
 EBool		LSelFound=FALSE, LFirst=TRUE;

 E3d_MatrixCopy(LCamera->ProjectionMatrix, LWorldToScreenMatrix);
 E3d_MatrixMult(LCamera->WorldToViewerMatrix, LWorldToScreenMatrix);

// Go through all the selected Models in the scene and get their common bounding box
//
 LRootModels=LScene->RootModels;
 for(LC=0, LN=LScene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModels[LC];

  for(;LModel;LModel=LModel->Next)
  {
   LTWhatToInclude=E3dBB_NONE;
   switch(LModel->Selection)
   {
    case E3dSEL_NONE:	if(LWhatToInclude==E3dBB_ALL) LTWhatToInclude=E3dBB_ALL;break;

    case E3dSEL_NODE:
    case E3dSEL_BRANCH:
    case E3dSEL_BRANCH_ROOT:
     if(LWhatToInclude&E3dBB_SELECTED_GEOMETRY) LTWhatToInclude=E3dBB_ALL;
    break;

    case E3dSEL_GEOMETRY:
     LTWhatToInclude=LWhatToInclude;
    break;
   }

   if(LTWhatToInclude)
   {
    E3d_MatrixCopy(LWorldToScreenMatrix, LMatrix);
    E3d_MatrixMult(LModel->LocalToWorldMatrix, LMatrix);

    E3d_MatrixCopy(LCamera->WorldToViewerMatrix, LLocalToViewerMatrix);
    E3d_MatrixMult(LModel->LocalToWorldMatrix, LLocalToViewerMatrix);

    if(LFirst)
    {
     if(E3d_ModelGetPerspectiveProjectedBoundingBox(LModel, LMatrix, LAllBBMin, LAllBBMax, LAllMaxProjectedXYAbsValPoint, LTWhatToInclude))
     {
      LSelFound=TRUE;
      LMaxXYAbsVal=LAllMaxProjectedXYAbsValPoint->W;

// Transform this point into Viewer-space
//
      mX=LAllMaxProjectedXYAbsValPoint->X;mY=LAllMaxProjectedXYAbsValPoint->Y;mZ=LAllMaxProjectedXYAbsValPoint->Z;
      E3dM_MatrixTransform3x4(LLocalToViewerMatrix, LXF, LYF, LZF);

      LFirst=FALSE;
     }
    }
    else
    {
     if(E3d_ModelGetPerspectiveProjectedBoundingBox(LModel, LMatrix, &LBBMin, &LBBMax, &LMaxProjectedXYAbsValPoint, LTWhatToInclude))
     {
      if(LBBMin.X < LAllBBMin->X) LAllBBMin->X = LBBMin.X;
      if(LBBMax.X > LAllBBMax->X) LAllBBMax->X = LBBMax.X;

      if(LBBMin.Y < LAllBBMin->Y) LAllBBMin->Y = LBBMin.Y;
      if(LBBMax.Y > LAllBBMax->Y) LAllBBMax->Y = LBBMax.Y;

      if(LMaxProjectedXYAbsValPoint.W>LMaxXYAbsVal)
      {
// Transform this point into Viewer-space
//
       mX=LMaxProjectedXYAbsValPoint.X;mY=LMaxProjectedXYAbsValPoint.Y;mZ=LMaxProjectedXYAbsValPoint.Z;
       E3dM_MatrixTransform3x4(LLocalToViewerMatrix, LXF, LYF, LZF);

       LMaxXYAbsVal=LMaxProjectedXYAbsValPoint.W;
      }

      LSelFound=TRUE;
     }
    }

   }
  }
 }

 if(LSelFound)
 {
  LAllMaxProjectedXYAbsValPoint->X=LXF;
  LAllMaxProjectedXYAbsValPoint->Y=LYF;
  LAllMaxProjectedXYAbsValPoint->Z=LZF;
  LAllMaxProjectedXYAbsValPoint->W=LMaxXYAbsVal;
 }

 return(LSelFound);
}


/*======================================*/
/* Reset camera				*/
/*======================================*/
static void _MCB_ResetCamera(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dp_ResetCameraOn3DWindows();
}


/*======================================*/
/* Attach camera to selected Model	*/
/*======================================*/
static void _MCB_AttachCamera(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dModel*	LModel;
 E3dModel**	LSelectedModels=NULL;
 unsigned int	LN;

 if((LN=E3d_SceneGetSelectedModels(E3d_Scene, &LSelectedModels, FALSE))>0)
 {
  LModel=LSelectedModels[0];

  switch((int)LClientData)
  {
   case CR_ATTACH_CAMERA:
    E3dp_Main3DWindow->PerspectiveCamera.PositionConstraint=LModel;
    E3dp_Main3DWindow->PerspectiveCamera.AlignmentConstraint=LModel;
   break;

   case CR_DETACH_CAMERA:
    E3dp_Main3DWindow->PerspectiveCamera.PositionConstraint=NULL;
    E3dp_Main3DWindow->PerspectiveCamera.AlignmentConstraint=NULL;
   break;
  }
 }
}



/*======================================*/
/* Update settings dialog box		*/
/*======================================*/
static void _UpdateDialog()
{
 E3dCamera*		LCamera=&(E3dp_Main3DWindow->PerspectiveCamera);


 XeScaleSetValueD(_FieldOfViewScaleW, LCamera->FieldOfView, False);
 XeScaleSetValueD(_FarPlaneScaleW, LCamera->ZFar, False);

 XeScaleSetValueD(_OrbitingStepScaleW, E3dp_Prefs.OrbitStepLongitude, False);
 XeScaleSetValueD(_FrameToTimeScaleW, E3dp_Prefs.FrameToTime, False);
}


/*======================================*/
/* Camera changed callback		*/
/*======================================*/
static void _CB_Camera(void* LCam, EPointer LClientData, EPointer LCallData)
{
 if(_SettingsDialog) _UpdateDialog();
}


/*======================================*/
/* Dialog callback			*/
/*======================================*/
static void _CB_Settings(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dWindow*	L3DWindow=E3dp_Main3DWindow;
 E3dCamera*	LCamera=&(L3DWindow->PerspectiveCamera);


 switch((int)LClientData)
 {
  case EguiCANCEL:
   EGUI_UndisplayShell(_SettingsDialog);

   E3d_CameraRemoveCallback(LCamera, _CB_Camera, (EPointer)0);
   _Plugin->LockCount-=1;
  break;

  case CR_FIELD_OF_VIEW:
   LCamera->FieldOfView=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   E3dp_Redraw3DWindow(L3DWindow);
  break;

  case CR_FAR_PLANE:
   LCamera->ZFar=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   E3d_CameraRefreshMatrices(LCamera);
   E3dp_Redraw3DWindow(L3DWindow);
  break;

  case CR_ORBITING_STEP:
   E3dp_Prefs.OrbitStepLongitude=((XeScaleCallbackStruct*)LCallData)->FloatValue;
   E3dp_Prefs.OrbitStepLatitude=E3dp_Prefs.OrbitStepLongitude;
  break;

  case CR_FRAME_TO_TIME:
   E3dp_Prefs.FrameToTime=((XeScaleCallbackStruct*)LCallData)->FloatValue;
  break;
 }
}


/*======================================*/
/* Create settings dialog box		*/
/*======================================*/
static void _MCB_CameraSettings(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 if(_SettingsDialog)
 {
  if(EGUI_ShellDisplayStatus(_SettingsDialog)==EguiNOT_DISPLAYED)
  {
   E3dCamera*		LCamera=&(E3dp_Main3DWindow->PerspectiveCamera);

   _Plugin->LockCount+=1;
   E3d_CameraAddCallback(LCamera, _CB_Camera, (EPointer)0);
  }
  EGUI_RaiseShell(_SettingsDialog);
 }
 else
 {
  E3dCamera*		LCamera=&(E3dp_Main3DWindow->PerspectiveCamera);
  Widget		LTopMatrixW;
  EguiArg		LArgs[32];
  int			LArgCnt;
  EguiItem		LDialog, LI;
  Widget		LIndentWs[16];
  Widget		LTraverseWs[8];
  unsigned int		LIndentN, LTraverseN=0;


  LArgCnt=0;
  EguiSetArg(EguiNallowShellResize, True, LArgs, LArgCnt);
  EguiSetArg(EguiNstretchButtons, False, LArgs, LArgCnt);
  EguiSetArg(EguiNwmDecorations, EguiWM_DECOR_BORDER|EguiWM_DECOR_TITLE, LArgs, LArgCnt);
  EguiSetArg(EguiNtitle, "Camera settings v0.1.0", LArgs, LArgCnt);EguiSetArg(EguiNiconName, "Camera", LArgs, LArgCnt);
  EguiSetArg(EguiNcustomItemType, EguiMATRIX, LArgs, LArgCnt);
  if((LDialog=EGUI_CreateDialog(EguiDIALOG_TEMPLATE, "Camera settings", Eqx_TopShell, LArgs, LArgCnt))==NULL) return;

  _SettingsDialog=LDialog;
  LArgCnt=0;
  EguiSetArg(EguiNshowAsDefault, True, LArgs, LArgCnt);

  LI=EGUI_CreatePushButton("Close", LDialog, LArgs, LArgCnt);
  EGUI_AddCallback(LI, EguiNactivateCallback, _CB_Settings, (EPointer)EguiCANCEL);

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


  EXtStart;
  EXtSetArg(XeNforeground, EGUI_ForegroundColor);
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNlabelXAlignment, XeALIGN_BEGINNING);
  EXtSetArg(XeNfontList, EGUI_NumFontList);
  EXtSetArg(XeNmarginTop, 5);
  XtCreateManagedWidget("Properties", xeLabelWidgetClass, LTopMatrixW, Args, ArgCnt);

  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 2);
  EXtSetArg(XeNminimum, 1);EXtSetArg(XeNmaximum, 17999);EXtSetArg(XeNvalue, (int)(LCamera->FieldOfView*100.0));
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_FieldOfViewScaleW=XtCreateManagedWidget("Field of view:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_FieldOfViewScaleW, XeNvalueChangedCallback, (XtCallbackProc)_CB_Settings, (XtPointer)CR_FIELD_OF_VIEW);

  EXtStart;
  EXtSetArg(XeNtextFieldDigits, 7);EXtSetArg(XeNdecimalPoints, 1);
  EXtSetArg(XeNminimum, 20);EXtSetArg(XeNmaximum, 2000000000);EXtSetArg(XeNvalue, (int)(LCamera->ZFar*10.0));
  EXtSetArg(XeNvalueType, XeDOUBLE);
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_FarPlaneScaleW=XtCreateManagedWidget("Far plane:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_FarPlaneScaleW, XeNvalueChangedCallback, (XtCallbackProc)_CB_Settings, (XtPointer)CR_FAR_PLANE);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);


  LIndentN=0;
  EXtStart;
  EXtSetArg(XeNforeground, EGUI_ForegroundColor);
  EXtSetArg(XeNbackground, EGUI_BackgroundColor);
  EXtSetArg(XeNlabelXAlignment, XeALIGN_BEGINNING);
  EXtSetArg(XeNfontList, EGUI_NumFontList);
  EXtSetArg(XeNmarginTop, 5);
  XtCreateManagedWidget("Control", xeLabelWidgetClass, LTopMatrixW, Args, ArgCnt);

  EXtStart;
  EXtSetArg(XeNmarginLeft, 4);
  EXtSetArg(XeNtextFieldDigits, 4);EXtSetArg(XeNdecimalPoints, 2);
  EXtSetArg(XeNminimum, 5);EXtSetArg(XeNmaximum, 100);EXtSetArg(XeNvalue, (int)(E3dp_Prefs.OrbitStepLongitude*100.0));
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  EXtSetArg(XeNactivateOnLeave, True);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_OrbitingStepScaleW=XtCreateManagedWidget("Orbiting speed:", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_OrbitingStepScaleW, XeNvalueChangedCallback, (XtCallbackProc)_CB_Settings, (XtPointer)CR_ORBITING_STEP);

  EXtStart;
  EXtSetArg(XeNmarginLeft, 4);
  EXtSetArg(XeNtextFieldDigits, 4);EXtSetArg(XeNdecimalPoints, 2);
  EXtSetArg(XeNminimum, 0);EXtSetArg(XeNmaximum, 500);EXtSetArg(XeNvalue, (int)(E3dp_Prefs.FrameToTime*100.0));
  EXtSetArg(XeNorientation, XeHORIZONTAL);
  EXtSetArg(XeNactivateOnTextChange, True);
  E3dp_SetScaleArgs(Args, &ArgCnt);
  LIndentWs[LIndentN++]=LTraverseWs[LTraverseN++]=_FrameToTimeScaleW=XtCreateManagedWidget("'Frame-to' time (s):", xeScaleWidgetClass, LTopMatrixW, Args, ArgCnt);
  XtAddCallback(_FrameToTimeScaleW, XeNvalueChangedCallback, (XtCallbackProc)_CB_Settings, (XtPointer)CR_FRAME_TO_TIME);

  XeIndentWidgetsFromLeft(LIndentWs, LIndentN, 4);

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


  _Plugin->LockCount+=1;
  EGUI_RaiseShell(_SettingsDialog);
  EGUI_CenterShellToItem(_SettingsDialog, Eqx_TopShell);

  E3d_CameraAddCallback(LCamera, _CB_Camera, (EPointer)0);
 }
}



/*======================================*/
/* Frame Camera to objects		*/
/*======================================*/
static void _SceneDoFraming(E3dScene* LScene, E3dWindow* L3DWindow, E3d3DPosition* LAllBBMinIn, E3d3DPosition* LAllBBMaxIn, unsigned int LWhatToInclude)
{
 E3dCamera*	LCamera;
 E3d3DPosition	LBBMiddle;
 E3dCoordinate	LZoom;
 E3d3DPosition	LAllBBMin, LAllBBMax;


 LBBMiddle.X=(LAllBBMinIn->X+LAllBBMaxIn->X)*0.5;
 LBBMiddle.Y=(LAllBBMinIn->Y+LAllBBMaxIn->Y)*0.5;
 LBBMiddle.Z=(LAllBBMinIn->Z+LAllBBMaxIn->Z)*0.5;

 switch(L3DWindow->ViewMode)
 {
  case E3dVM_PERSPECTIVE:
   LCamera=&(L3DWindow->PerspectiveCamera);


   _StartInterest=LCamera->InterestPoint;
   _StartPosition=LCamera->Position;
   _FrameToTimeLeft=E3dp_Prefs.FrameToTime;

   E3d_CameraSetInterest(LCamera, &LBBMiddle);

// Set view-distance to 1.0 (A)
//
   E3d_CameraSetViewDistance(LCamera, 1.0);
   E3d_CameraRefreshMatrices(LCamera);

   

// Go through all the selected Models in the scene and get their common, viewer-aligned bounding box
//
   {
    E3dModel**		LRootModels;
    E3dModel*		LModel;
    E3dMatrix		LWorldToViewerMatrix, LMatrix;
    E3d3DPosition	LBBMin, LBBMax;
    E3dCoordinate	LMaxXYAbsVal, mX, mY, mZ;
    unsigned int	LC, LN, LTWhatToInclude;
    EBool		LFirst=TRUE, LSelFound=FALSE;


// Transform the
//
    mX=LBBMiddle.X;mY=LBBMiddle.Y;mZ=LBBMiddle.Z;

    E3d_MatrixCopy(LCamera->WorldToViewerMatrix, LWorldToViewerMatrix);

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

     if(LModel->Type!=E3dMDL_CAMERA)
     {
      for(;LModel;LModel=LModel->Next)
      {
       LTWhatToInclude=E3dBB_NONE;
       switch(LModel->Selection)
       {
	case E3dSEL_NONE:	if(LWhatToInclude==E3dBB_ALL) LTWhatToInclude=E3dBB_ALL;break;

	case E3dSEL_NODE:
	case E3dSEL_BRANCH:
	case E3dSEL_BRANCH_ROOT:
	 if(LWhatToInclude&E3dBB_SELECTED_GEOMETRY) LTWhatToInclude=E3dBB_ALL;
	break;

	case E3dSEL_GEOMETRY:
	 LTWhatToInclude=LWhatToInclude;
	break;
       }

       if(LTWhatToInclude)
       {
	E3d_MatrixCopy(LWorldToViewerMatrix, LMatrix);
	E3d_MatrixMult(LModel->LocalToWorldMatrix, LMatrix);

	if(LFirst)
	{
	 if(E3d_ModelGetTransformedBoundingBox(LModel, LMatrix, &LAllBBMin, &LAllBBMax, LTWhatToInclude)) LSelFound=TRUE;

//printf("First   %s %f %f %f   %f %f %f\n", LModel->Name, LAllBBMin.X, LAllBBMin.Y, LAllBBMin.Z, LAllBBMax.X, LAllBBMax.Y, LAllBBMax.Z);fflush(stdout);
	 LFirst=FALSE;
	}
	else
	{
	 if(E3d_ModelGetTransformedBoundingBox(LModel, LMatrix, &LBBMin, &LBBMax, LTWhatToInclude))
	 {
	  if(LBBMin.X < LAllBBMin.X) LAllBBMin.X = LBBMin.X;
	  if(LBBMax.X > LAllBBMax.X) LAllBBMax.X = LBBMax.X;

	  if(LBBMin.Y < LAllBBMin.Y) LAllBBMin.Y = LBBMin.Y;
	  if(LBBMax.Y > LAllBBMax.Y) LAllBBMax.Y = LBBMax.Y;

	  if(LBBMin.Z < LAllBBMin.Z) LAllBBMin.Z = LBBMin.Z;
	  if(LBBMax.Z > LAllBBMax.Z) LAllBBMax.Z = LBBMax.Z;
	  LSelFound=TRUE;
	 }
	}
       }
      }
     }
    }


    LAllBBMin.X/=L3DWindow->AspectRatio;
    LAllBBMax.X/=L3DWindow->AspectRatio;

    LMaxXYAbsVal=E3dM_ABS(LAllBBMin.X);
    mX=E3dM_ABS(LAllBBMax.X);if(mX>LMaxXYAbsVal) LMaxXYAbsVal=mX;
    mX=E3dM_ABS(LAllBBMin.Y);if(mX>LMaxXYAbsVal) LMaxXYAbsVal=mX;
    mX=E3dM_ABS(LAllBBMax.Y);if(mX>LMaxXYAbsVal) LMaxXYAbsVal=mX;



//printf("X  %f - %f  Y %f -  %f   ZRange %f-%f  Asp: %f \n", LAllBBMin->X, LAllBBMax->X, LAllBBMin->Y, LAllBBMax->Y, LAllBBMin->Z, LAllBBMax->Z, L3DWindow->AspectRatio);fflush(stdout);
//printf("Max %f\n", LMaxXYAbsVal);fflush(stdout);
// LAllBBMax->Z+1.0 is the distance of the interest point from the front-plane of the selection's
// view-aligned bounding box
// See (A) for the 1.0
//
    E3d_CameraSetViewDistance(LCamera, LMaxXYAbsVal*1.2/tan(LCamera->FieldOfView*E3dDEGREES_TO_RADIANS*0.5)+LAllBBMax.Z+1.0);
    E3d_CameraRefreshMatrices(LCamera);

    _EndInterest=LCamera->InterestPoint;
    _EndPosition=LCamera->Position;
   }
  break;

  case E3dVM_TOP:
   LCamera=&(L3DWindow->TopCamera);

   LCamera->Position.X=LBBMiddle.X;
   LCamera->Position.Z=LBBMiddle.Z;
   LCamera->InterestPoint.X=LBBMiddle.X;
   LCamera->InterestPoint.Z=LBBMiddle.Z;

   LZoom=(LAllBBMaxIn->Z-LAllBBMinIn->Z)*L3DWindow->AspectRatio;
   if((LAllBBMaxIn->X-LAllBBMinIn->X)>LZoom) LZoom=LAllBBMaxIn->X-LAllBBMinIn->X;

// 0.5 with a little "margin"
//
   LCamera->XZoom=LCamera->YZoom=LZoom*0.64;

   E3d_CameraRefreshMatrices(LCamera);
  break;

  case E3dVM_FRONT:
   LCamera=&(L3DWindow->FrontCamera);

   LCamera->Position.X=LBBMiddle.X;
   LCamera->Position.Y=LBBMiddle.Y;
   LCamera->InterestPoint.X=LBBMiddle.X;
   LCamera->InterestPoint.Y=LBBMiddle.Y;

   LZoom=(LAllBBMaxIn->Y-LAllBBMinIn->Y)*L3DWindow->AspectRatio;
   if((LAllBBMaxIn->X-LAllBBMinIn->X)>LZoom) LZoom=LAllBBMaxIn->X-LAllBBMinIn->X;

// 0.5 with a little "margin"
//
   LCamera->XZoom=LCamera->YZoom=LZoom*0.64;

   E3d_CameraRefreshMatrices(LCamera);
  break;

  case E3dVM_RIGHT:
   LCamera=&(L3DWindow->RightCamera);

   LCamera->Position.Z=LBBMiddle.Z;
   LCamera->Position.Y=LBBMiddle.Y;
   LCamera->InterestPoint.Z=LBBMiddle.Z;
   LCamera->InterestPoint.Y=LBBMiddle.Y;

   LZoom=(LAllBBMaxIn->Y-LAllBBMinIn->Y)*L3DWindow->AspectRatio;
   if((LAllBBMaxIn->Z-LAllBBMinIn->Z)>LZoom) LZoom=LAllBBMaxIn->Z-LAllBBMinIn->Z;

// 0.5 with a little "margin"
//
   LCamera->XZoom=LCamera->YZoom=LZoom*0.64;

   E3d_CameraRefreshMatrices(LCamera);
  break;

  case E3dVM_SCHEMATICS:
   LCamera=&(L3DWindow->SchematicsCamera);

   LCamera->Position.X=LBBMiddle.X;
   LCamera->Position.Y=LBBMiddle.Y;
   LCamera->InterestPoint.X=LBBMiddle.X;
   LCamera->InterestPoint.Y=LBBMiddle.Y;

   LZoom=(LAllBBMaxIn->Y-LAllBBMinIn->Y)*L3DWindow->AspectRatio;
   if((LAllBBMaxIn->X-LAllBBMinIn->X)>LZoom) LZoom=LAllBBMaxIn->X-LAllBBMinIn->X;

// 0.5 with a little "margin"
//
   LCamera->XZoom=LCamera->YZoom=LZoom*0.56;

   E3d_CameraRefreshMatrices(LCamera);
  break;
 }
}


/*======================================*/
/* Xt timer callback			*/
/*======================================*/
static void _XtTimerFrameTo(XtPointer LClientData, XtIntervalId* LTID)
{
 E3dWindow*	L3DWindow=_FramingWindow;


 if(L3DWindow)
 {
  E3dCamera*	LCamera=E3dp_WindowGetActiveCamera(L3DWindow);
  float		LT, LInvT;


  _FrameToTimeLeft-=E3dp_Prefs.FrameToTimeStep;
  if(_FrameToTimeLeft<0.0) _FrameToTimeLeft=0.0;

  LT=(E3dp_Prefs.FrameToTime-_FrameToTimeLeft)/E3dp_Prefs.FrameToTime;

// Accelerate-decelarate
//
  if(LT<0.5) LT=(LT*LT*2.0);
  else { LT=1.0-LT;LT=1.0-(LT*LT*2.0); }

  LInvT=1.0-LT;
  LCamera->InterestPoint.X=_StartInterest.X*LInvT+_EndInterest.X*LT;
  LCamera->InterestPoint.Y=_StartInterest.Y*LInvT+_EndInterest.Y*LT;
  LCamera->InterestPoint.Z=_StartInterest.Z*LInvT+_EndInterest.Z*LT;

  LCamera->Position.X=_StartPosition.X*LInvT+_EndPosition.X*LT;
  LCamera->Position.Y=_StartPosition.Y*LInvT+_EndPosition.Y*LT;
  LCamera->Position.Z=_StartPosition.Z*LInvT+_EndPosition.Z*LT;

  E3d_CameraRefreshMatrices(LCamera);
  E3dp_Redraw3DWindow(L3DWindow);


  if(_FrameToTimeLeft>0.0) XtAppAddTimeOut(EGUI_AppContext, (int)(E3dp_Prefs.FrameToTimeStep*1000.0), _XtTimerFrameTo, 0);
 }
}


/*======================================*/
/* Frame selection or tagged points	*/
/*======================================*/
static void _MCB_FrameCameraTo(EguiItem LI, EPointer LClientData, EPointer LCallData)
{
 E3dWindow*	L3DWindow;
 E3dModel*	LModel;
 E3dModel**	LRootModels;
 unsigned int	LC, LN, LWhatToInclude, LTWhatToInclude;
 E3dCoordinate	LF;
 E3d3DPosition	LBBMin, LBBMax, LAllBBMin, LAllBBMax,
		LSchemAllBBMin, LSchemAllBBMax;
 EBool		LSelFound=FALSE,
		LFirst3D=TRUE, LFirstSchem=TRUE,
		LDo3D, LDoSchematics=FALSE, LSchemSelFound=FALSE;


 switch((int)LClientData)
 {
  case CR_FRAME_ALL_ON_CURRENT_WINDOW:		// Frame all
  case CR_FRAME_ALL_ON_ALL_WINDOWS:
   LWhatToInclude=E3dBB_ALL;
  break;

  case CR_FRAME_SELECTION_ON_CURRENT_WINDOW:		// Frame selection
  case CR_FRAME_SELECTION_ON_ALL_WINDOWS:
   LWhatToInclude=E3dBB_SELECTED_GEOMETRY;
  break;

  case CR_FRAME_TAG_ON_CURRENT_WINDOW:		// Frame tag
  case CR_FRAME_TAG_ON_ALL_WINDOWS:
   LWhatToInclude=E3dBB_TAGGED_POINT;
  break;

  default:
   LWhatToInclude=E3dBB_NONE;
  break;
 }


 switch((int)LClientData)
 {
  case CR_FRAME_ALL_ON_CURRENT_WINDOW:
  case CR_FRAME_SELECTION_ON_CURRENT_WINDOW:
  case CR_FRAME_TAG_ON_CURRENT_WINDOW:
   if((L3DWindow=E3dp_Active3DWindow)!=NULL)
   {
    if(L3DWindow->ViewMode==E3dVM_SCHEMATICS) LDoSchematics=TRUE;
   }
  break;

  case CR_FRAME_ALL_ON_ALL_WINDOWS:
  case CR_FRAME_SELECTION_ON_ALL_WINDOWS:
  case CR_FRAME_TAG_ON_ALL_WINDOWS:
   for(LC=0;LC<E3dp_NumOf3DWindows;LC++)
   {
    if(E3dp_3DWindows[LC]->ViewMode==E3dVM_SCHEMATICS) LDoSchematics=TRUE;
   }
  break;
 }


// Go through all the selected Models in the scene and get their common bounding box
//
 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModels[LC];

  for(;LModel;LModel=LModel->Next)
  {
   LTWhatToInclude=E3dBB_NONE;
   switch(LModel->Selection)
   {
    case E3dSEL_NONE:	if(LWhatToInclude==E3dBB_ALL) LTWhatToInclude=E3dBB_ALL;break;

    case E3dSEL_NODE:
    case E3dSEL_BRANCH:
    case E3dSEL_BRANCH_ROOT:
     if(LWhatToInclude&E3dBB_SELECTED_GEOMETRY) LTWhatToInclude=E3dBB_ALL;
    break;

    case E3dSEL_GEOMETRY:
     LTWhatToInclude=LWhatToInclude;
    break;
   }

   if(LTWhatToInclude)
   {
    LDo3D=TRUE;

    switch(LModel->Type)
    {
     case E3dMDL_CAMERA:
     case E3dMDL_CAMERA_INTEREST:
      LDo3D=FALSE;
     break;
    }


// Model's 3D BBox
//
    if(LDo3D)
    {
     if(LFirst3D)
     {
// Initialize BBox on first Model
//
      if(E3d_ModelGetTransformedBoundingBox(LModel, LModel->LocalToWorldMatrix, &LAllBBMin, &LAllBBMax, LTWhatToInclude)) LSelFound=TRUE;
      LFirst3D=FALSE;
//printf("First   %s %f %f %f   %f %f %f\n", LModel->Name, LAllBBMin.X, LAllBBMin.Y, LAllBBMin.Z, LAllBBMax.X, LAllBBMax.Y, LAllBBMax.Z);fflush(stdout);
     }
     else
     {
      if(E3d_ModelGetTransformedBoundingBox(LModel, LModel->LocalToWorldMatrix, &LBBMin, &LBBMax, LTWhatToInclude))
      {
       if(LBBMin.X < LAllBBMin.X) LAllBBMin.X = LBBMin.X;
       if(LBBMax.X > LAllBBMax.X) LAllBBMax.X = LBBMax.X;

       if(LBBMin.Y < LAllBBMin.Y) LAllBBMin.Y = LBBMin.Y;
       if(LBBMax.Y > LAllBBMax.Y) LAllBBMax.Y = LBBMax.Y;

       if(LBBMin.Z < LAllBBMin.Z) LAllBBMin.Z = LBBMin.Z;
       if(LBBMax.Z > LAllBBMax.Z) LAllBBMax.Z = LBBMax.Z;
       LSelFound=TRUE;
      }
     }
    }

// Model's Schematics view BBox
//
    if(LDoSchematics)
    {
     if(LFirstSchem)
     {
// Initialize BBox on first Model
//
      LSchemAllBBMin.X=LModel->SchemPosition.X-E3dSCHEM_MODEL_XSIZE*0.5;
      LSchemAllBBMin.Y=LModel->SchemPosition.Y-E3dSCHEM_MODEL_YSIZE*0.5;
      LSchemAllBBMin.Z=LModel->SchemPosition.Z-E3dSCHEM_MODEL_ZSIZE*0.5;
      LSchemAllBBMax.X=LModel->SchemPosition.X+E3dSCHEM_MODEL_XSIZE*0.5;
      LSchemAllBBMax.Y=LModel->SchemPosition.Y+E3dSCHEM_MODEL_YSIZE*0.5;
      LSchemAllBBMax.Z=LModel->SchemPosition.Z+E3dSCHEM_MODEL_ZSIZE*0.5;
      LSchemSelFound=TRUE;
      LFirstSchem=FALSE;
     }
     else
     {
      LF=LModel->SchemPosition.X-E3dSCHEM_MODEL_XSIZE*0.5;if(LF<LSchemAllBBMin.X) LSchemAllBBMin.X=LF;
      LF=LModel->SchemPosition.Y-E3dSCHEM_MODEL_YSIZE*0.5;if(LF<LSchemAllBBMin.Y) LSchemAllBBMin.Y=LF;
      LF=LModel->SchemPosition.Z-E3dSCHEM_MODEL_ZSIZE*0.5;if(LF<LSchemAllBBMin.Z) LSchemAllBBMin.Z=LF;

      LF=LModel->SchemPosition.X+E3dSCHEM_MODEL_XSIZE*0.5;if(LF>LSchemAllBBMax.X) LSchemAllBBMax.X=LF;
      LF=LModel->SchemPosition.Y+E3dSCHEM_MODEL_YSIZE*0.5;if(LF>LSchemAllBBMax.Y) LSchemAllBBMax.Y=LF;
      LF=LModel->SchemPosition.Z+E3dSCHEM_MODEL_ZSIZE*0.5;if(LF>LSchemAllBBMax.Z) LSchemAllBBMax.Z=LF;
      LSchemSelFound=TRUE;
     }
    }
   }
  }

 }

//printf("Frame to %f %f %f   %f %f %f\n", LAllBBMin.X, LAllBBMin.Y, LAllBBMin.Z, LAllBBMax.X, LAllBBMax.Y, LAllBBMax.Z);fflush(stdout);

 if(LSelFound||LSchemSelFound)
 {
  switch((int)LClientData)
  {
   case CR_FRAME_ALL_ON_CURRENT_WINDOW:
   case CR_FRAME_SELECTION_ON_CURRENT_WINDOW:
   case CR_FRAME_TAG_ON_CURRENT_WINDOW:
    if((L3DWindow=E3dp_Active3DWindow)!=NULL)
    {
     if(L3DWindow->ViewMode==E3dVM_SCHEMATICS)
     {
      if(LSchemSelFound)
      {
       _SceneDoFraming(E3d_Scene, L3DWindow, &LSchemAllBBMin, &LSchemAllBBMax, LWhatToInclude);

       if(_FrameToTimeLeft==0.0) E3dp_Redraw3DWindow(L3DWindow);
      }
     }
     else if(LSelFound)
          {
	   _SceneDoFraming(E3d_Scene, L3DWindow, &LAllBBMin, &LAllBBMax, LWhatToInclude);

	   if(_FrameToTimeLeft==0.0) E3dp_Redraw3DWindow(L3DWindow);
	  }
    }
   break;

   case CR_FRAME_ALL_ON_ALL_WINDOWS:
   case CR_FRAME_SELECTION_ON_ALL_WINDOWS:
   case CR_FRAME_TAG_ON_ALL_WINDOWS:
    for(LC=0;LC<E3dp_NumOf3DWindows;LC++)
    {
     L3DWindow=E3dp_3DWindows[LC];

     if(L3DWindow->ViewMode==E3dVM_SCHEMATICS)
     {
      if(LSchemSelFound)
      {
       _SceneDoFraming(E3d_Scene, L3DWindow, &LSchemAllBBMin, &LSchemAllBBMax, LWhatToInclude);
       if(_FrameToTimeLeft==0.0) E3dp_Redraw3DWindow(L3DWindow);
      }
     }
     else if(LSelFound)
	  {
	   _SceneDoFraming(E3d_Scene, L3DWindow, &LAllBBMin, &LAllBBMax, LWhatToInclude);
	   if(_FrameToTimeLeft==0.0) E3dp_Redraw3DWindow(L3DWindow);
	  }
    }
   break;
  }


  if(_FrameToTimeLeft>0.0)
  {
   float	LSteps=E3dp_Prefs.FrameToTime/E3dp_Prefs.FrameToTimeStep, LInvSteps=1.0/LSteps;

   _FramingWindow=E3dp_Active3DWindow;

   if(_FramingWindow)
   {
    E3dWindow*	L3DWindow=_FramingWindow;
    E3dCamera*	LCamera=E3dp_WindowGetActiveCamera(L3DWindow);


    _InterestStep.X=(_EndInterest.X-_StartInterest.X)*LInvSteps;
    _InterestStep.Y=(_EndInterest.Y-_StartInterest.Y)*LInvSteps;
    _InterestStep.Z=(_EndInterest.Z-_StartInterest.Z)*LInvSteps;

    _PositionStep.X=(_EndPosition.X-_StartPosition.X)*LInvSteps;
    _PositionStep.Y=(_EndPosition.Y-_StartPosition.Y)*LInvSteps;
    _PositionStep.Z=(_EndPosition.Z-_StartPosition.Z)*LInvSteps;

    LCamera->InterestPoint.X=_StartInterest.X;
    LCamera->InterestPoint.Y=_StartInterest.Y;
    LCamera->InterestPoint.Z=_StartInterest.Z;

    LCamera->Position.X=_StartPosition.X;
    LCamera->Position.Y=_StartPosition.Y;
    LCamera->Position.Z=_StartPosition.Z;

    XtAppAddTimeOut(EGUI_AppContext, (int)(E3dp_Prefs.FrameToTimeStep*1000.0), _XtTimerFrameTo, 0);
   }
  }


 }
 else E3dp_PrintMessage(0, 2500, "Nothing is selected!");
}


/*======================================*/
/* Key callback				*/
/*======================================*/
static void _KCB_FrameCameraTo(unsigned short LKey, unsigned int LModifiers, int LKeyEventType, EPointer LClientData)
{
 _MCB_FrameCameraTo((EguiItem)NULL, LClientData, (EPointer)NULL);
}


/*======================================*/
/* Key callback				*/
/*======================================*/
static void _KCB_ResetCamera(unsigned short LKey, unsigned int LModifiers, int LKeyEventType, EPointer LClientData)
{
 switch((int)LClientData)
 {
  case CR_RESET_WINDOW_CAMERA:
   if(E3dp_Active3DWindow)
   {
    E3dp_3DWindowResetCameras(E3dp_Active3DWindow);
    E3dp_Redraw3DWindows(E3dDF_ALL, E3dVM_ALL);
   }
  break;

  case CR_RESET_CAMERA_ON_ALL_WINDOWS:
   E3dp_ResetCameraOn3DWindows();
  break;
 }
}


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

 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Reset", '\0', "Shift ~Ctrl <Key>Home", "Home / Shft+Home", FALSE, NULL, _MCB_ResetCamera, (EPointer)CR_RESET_CAMERA_ON_ALL_WINDOWS);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Frame all", '\0', "~Shift ~Ctrl <Key>A", "A / Shift+A", FALSE, NULL, _MCB_FrameCameraTo, (EPointer)CR_FRAME_ALL_ON_ALL_WINDOWS);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Frame selection", '\0', "~Shift ~Ctrl <Key>F", "F / Shift+F", FALSE, NULL, _MCB_FrameCameraTo, (EPointer)CR_FRAME_SELECTION_ON_ALL_WINDOWS);
// E3dp_FrameTagMenuButton=EGUI_AddPushButton("Menu->Camera", "Frame tag", '\0', "~Shift Ctrl <Key>F", "F", FALSE, NULL, _MCB_FrameCameraTo, (EPointer)CR_FRAME_TAG_ON_ALL_WINDOWS);

 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Attach to selection", '\0', NULL, NULL, FALSE, NULL, _MCB_AttachCamera, (EPointer)CR_ATTACH_CAMERA);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Detach from selection", '\0', NULL, NULL, FALSE, NULL, _MCB_AttachCamera, (EPointer)CR_DETACH_CAMERA);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Camera", "Settings", '\0', NULL, NULL, FALSE, NULL, _MCB_CameraSettings, (EPointer)0);

 E_KeySetCallback("Reset camera", EKeyHOME, 0, EKeyPRESS, _KCB_ResetCamera, (EPointer)CR_RESET_WINDOW_CAMERA);
 E_KeySetCallback("Reset cameras", EKeyHOME, EShiftMask, EKeyPRESS, _KCB_ResetCamera, (EPointer)CR_RESET_CAMERA_ON_ALL_WINDOWS);
 E_KeySetCallback("Frame all", (unsigned short)'a', 0, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_ALL_ON_CURRENT_WINDOW);
 E_KeySetCallback("Frame all on all windows", (unsigned short)'a', EShiftMask, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_ALL_ON_ALL_WINDOWS);
 E_KeySetCallback("Frame selection", (unsigned short)'f', 0, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_SELECTION_ON_CURRENT_WINDOW);
 E_KeySetCallback("Frame selection on all windows", (unsigned short)'f', EShiftMask, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_SELECTION_ON_ALL_WINDOWS);
 return(0);
}


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

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


 E_KeyRemoveCallback(EKeyHOME, 0, EKeyPRESS, _KCB_ResetCamera, (EPointer)CR_RESET_WINDOW_CAMERA);
 E_KeyRemoveCallback(EKeyHOME, EShiftMask, EKeyPRESS, _KCB_ResetCamera, (EPointer)CR_RESET_CAMERA_ON_ALL_WINDOWS);
 E_KeyRemoveCallback((unsigned short)'a', 0, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_ALL_ON_CURRENT_WINDOW);
 E_KeyRemoveCallback((unsigned short)'a', EShiftMask, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_ALL_ON_ALL_WINDOWS);
 E_KeyRemoveCallback((unsigned short)'f', 0, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_SELECTION_ON_CURRENT_WINDOW);
 E_KeyRemoveCallback((unsigned short)'f', EShiftMask, EKeyPRESS, _KCB_FrameCameraTo, (EPointer)CR_FRAME_SELECTION_ON_ALL_WINDOWS);

 return(0);
}
