/*======================================================================================================*/
/* 3DPanel												*/
/*													*/
/* GUI													*/
/*													*/
/*  - 3DPanel creation											*/
/*  - Callbacks and event handlers									*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-17 23:17:05									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>

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

#include <X11/cursorfont.h>
#include <X11/IntrinsicP.h>

#include <Xe/Frame.h>
#include <Xe/Label.h>
#include <Xe/Layout.h>
#include <Xe/Matrix.h>
#include <Xe/Scale.h>
#include <Xe/PushButton.h>
#include <Xe/ToggleButton.h>

#ifdef _XeUSEXm
#include <Xm/DragDrop.h>
#endif


#include <Color/XColor.h>
#include <EGUI/Dialog.h>
#include <EGUI/Menu.h>

#include <Image/Panel.h>
#include <Image/TimePanel.h>

#include <E3D/E3D.h>

#include <E3D/IO.h>

#include <E3D/Panel.h>

#include <E3D/Pick.h>

#include <E3D/Scene.h>

#include <E3D/StatusPanel.h>


#include "Pixmaps.h"


extern EpCImage		Image_NoTexture;


/*----------------------------------------------*/
/* From Pick.c					*/
/*----------------------------------------------*/
extern E3dPickCallbackProc	E3d_PickCallback;


/*----------------------------------------------*/
/* From Display.c				*/
/*----------------------------------------------*/
extern int	_RenderOpenGL(E3dWindow* L3DWindow, E3dScene* LScene, E3dRenderInfo* LRenderInfo, EBool LStartFromFirstIteration, EBool LFirstPassAbortable);


EUndoStack	E3dp_UndoStack;



// OpenGL renderer
//
typedef struct
{
 E3dRendererCore();
} E3dOpenGL;

static E3dOpenGL*	_Renderer=NULL;





/*--------------------------------------*/
/* From the application main		*/
/*--------------------------------------*/
extern Pixel	MenuBackgroundColor, MenuForegroundColor, MenuTroughColor, MenuTopShadowColor, MenuBottomShadowColor,
		PanelBackgroundColor;


Pixel		E3dp_RedPixel, E3dp_GreenPixel, E3dp_BluePixel;


int		E3d_ToolIconXSize=ICON_XSIZE,		// For the ToolPanel
		E3d_ToolIconYSize=ICON_YSIZE,
		E3d_ToolBigIconXSize=ICONBIG_XSIZE,	// For tool dialogs
		E3d_ToolBigIconYSize=ICONBIG_YSIZE;

/*----------------------*/
/* 3D icons		*/
/*----------------------*/
// 3D Icon models
//
E3dModel*	E3d_3DCursorModel=NULL;
E3dModel*	E3d_SpotlightModel=NULL;
E3dModel*	E3d_WireCameraModel=NULL;
E3dModel*	E3d_SolidCameraModel=NULL;
E3dModel*	E3d_CameraInterestModel=NULL;

E3dMesh*	E3d_BulbMesh=NULL;


/*--------------------------------------*/
/* Externs from TimePanel.c		*/
/*--------------------------------------*/
extern EaTimePanel*	E3dp_TimePanel;


/*--------------------------------------*/
/* Externs from E3DPMenuF.c		*/
/*--------------------------------------*/
extern void		E3dp_AddBuiltInFunctionsGUI();
extern void		E3dp_RemoveBuiltInFunctionsGUI();


/*--------------------------------------*/
/* From PanelLayout.c			*/
/*--------------------------------------*/
extern void		E3d_3DWindowsLayout(XeLayoutWidget LEW, Dimension LXSize, Dimension LYSize);
extern void		E3d_3DWindowsGetPreferredSize(XeLayoutWidget LEW, XtWidgetGeometry* LGeo);


/*----------------------------------------------*/
/* Externs from the application's Plugins.c	*/
/*----------------------------------------------*/
extern int	E3dp_LoadPlugins(char* LPath, char* LFileName);



E3d3DPosition	E3d_3DCursorPos;
E3dRotation	E3d_3DCursorRot;
E3dMatrix	E3d_3DCursorMatrix;

EcRGBAiColor E3dpSTEREO_WIRECOLOR		= { 0x9000, 0x9000, 0x9000, 0xFFFF };
EcRGBAiColor E3dpSTEREO_HWIRECOLOR		= { 0xFF00, 0xFF00, 0xFF00, 0xFFFF };
EcRGBAiColor E3dpSTEREO_VERTEXCOLOR		= { 0x9900, 0x9900, 0x9900, 0xFFFF };
EcRGBAiColor E3dpSTEREO_HVERTEXCOLOR		= { 0xBB00, 0xBB00, 0xBB00, 0xFFFF };
EcRGBAiColor E3dpSTEREO_LOCKEDITEMCOLOR		= { 0x5000, 0x7000, 0xBB00, 0xFFFF };
EcRGBAiColor E3dpSTEREO_TAGGEDVERTEXCOLOR	= { 0xFF00, 0xEE00, 0xEE00, 0xFFFF };
EcRGBAiColor E3dpSTEREO_LINE1COLOR		= { 0x9900, 0x9900, 0x9900, 0xFFFF };
EcRGBAiColor E3dpSTEREO_LINE2COLOR		= { 0xDD00, 0xDD00, 0xDD00, 0xFFFF };


E3dDrawContext	E3dp_NormalDrawContext, E3dp_LeftEyeDrawContext, E3dp_RightEyeDrawContext;


// X11-specific stuff
//

Pixmap			E3d_SettingsPixmap=(Pixmap)NULL, E3d_SettingsPixmapMask=(Pixmap)NULL;


XtTranslations		E3dp_3DTransTable;

static Arg		Args[256];
static Cardinal		ArgCnt;


// X-Visual used for OpenGL windows
//
XVisualInfo*		E3dp_GLVisualId=NULL;

GC			E3dp_TmpGC;

Widget			E3dp_TopWidget=NULL, E3dp_ParentW=NULL;



#define USE_RGB	1

static int E3dp_GLVisualAttrs[]=
{
 GLX_DOUBLEBUFFER,
 GLX_RGBA,
 GLX_RED_SIZE, 1,
 GLX_GREEN_SIZE, 1,
 GLX_BLUE_SIZE, 1,
 GLX_DEPTH_SIZE, 8,
// GLX_STEREO,
 None
};


enum
{
 E3dCR_TOGGLE_HEADERS,
 E3dCR_TOGGLE_STATUSPANEL
};



EguiItem		E3dp_TopShell=NULL;
EguiItem		E3dp_ErrorDialog=NULL;

int			E3dp_ModelPanelColumns, E3dp_ModelPanelRows;

void			(*E3dp_ExitFunction)()=NULL;
void			(*E3dp_EventLoopFunction)(EguiEvent*)=NULL;
EBool			E3dp_ModelPanelCreated=FALSE, E3dp_GoOn=FALSE;
EBool			E3dp_DoubleBuffer=FALSE, E3d_ZBufferOk;


void _Tst()
{
}


//========================================================
// Set the pointer
//========================================================
void E3dp_SetPointerMode(int LPointerMode)
{
 Window	LWindow;
 Cursor	LCursor;

 if(E3dp_PointerMode!=LPointerMode)
 {
//assert((LPointerMode!=25)||(E3dp_PointerMode!=28));

  if((LPointerMode==25)&&(E3dp_PointerMode==28))
  {
printf("E3dp_SetPointerMode() 25 to 28\n");fflush(stdout);
   _Tst();
  }

  switch(LPointerMode)
  {
   case E3dpPTR_TRACK_ZOOM_STANDBY:	LCursor=E3dp_TrackZoomCursor;break;

   case E3dpPTR_TRACK:
   case E3dpPTR_TRACK_OTD:
   case E3dpPTR_TRACK_ODT:
    LCursor=E3dp_TrackCursor;
   break;

   case E3dpPTR_ZOOM:
   case E3dpPTR_ZOOM_BZ:
    LCursor=E3dp_ZoomCursor;
   break;

   case E3dpPTR_DOLLY:
   case E3dpPTR_DOLLY_ODT:
    LCursor=E3dp_DollyCursor;
   break;

   case E3dpPTR_BANK:			LCursor=E3dp_RollCursor;break;
   default:				LCursor=(Cursor)NULL;break;
  }
  if((LWindow=XtWindow(E3dp_TopWidget))!=(Window)NULL)
  {
   if(LCursor!=(Cursor)NULL) XDefineCursor(E3dp_Display, LWindow, LCursor);
   else XUndefineCursor(E3dp_Display, LWindow);
  }
  E3dp_PointerMode=LPointerMode;
 }
}


//================================================================================
// Push current pointer mode to the stack and overwrite it with the given mode
//================================================================================
void E3dp_PushPointerMode(int LPointerMode)
{
 E3dp_PointerModeStack[E3dp_PointerModeStackPtr]=E3dp_PointerMode;
 if(E3dp_PointerModeStackPtr<=E3dpPOINTERMODE_STACKDEPTH) E3dp_PointerModeStackPtr++;
 else { printf("PointerMode stack overflow!\n");fflush(stdout); }
 E3dp_SetPointerMode(LPointerMode);
}


//========================================================
// Get back pointer mode from the stack
//========================================================
void E3dp_PopPointerMode()
{
 if(E3dp_PointerModeStackPtr>0)
 {
  if(E3dp_PointerModeStackPtr>0) E3dp_PointerModeStackPtr--;
  else { printf("PointerMode stack underflow!\n");fflush(stdout); }

  E3dp_SetPointerMode(E3dp_PointerModeStack[E3dp_PointerModeStackPtr]);
 }
}


//================================================================
// Reset pointer mode and message stack and abort picking
//================================================================
void E3dp_ResetWorkModes()
{
 E3dp_PickAbort();

 E3dp_ResetMessageStack();
 E3dp_PointerModeStackPtr=0;
 E3dp_SetPointerMode(E3dpPTR_NONE);
}


//========================================
// Read 2D texture images for GL
//========================================
void E3dp_SceneRead2DTextures(E3dScene* LScene, EBool LForceReread)
{
 E3dMaterial*	LMaterial;
 E3d2DTexture*	L2DTexture;
 E3d2DTexture**	L2DTextures;
 unsigned int	LMCnt, LMNum, LTotalC, LNumOf2DTextures;
 EBool		LTextureRead=FALSE;

 if((LMNum=LScene->NumOfMaterials)>0)
 {
// Get total # of 2D textures
//
  LNumOf2DTextures=0;
  for(LMCnt=0;LMCnt<LMNum;LMCnt++)
  {
   LMaterial=LScene->Materials[LMCnt];

   if((L2DTextures=LMaterial->Textures2D)!=NULL)
   {
    unsigned int	LTCnt, LTNum;

//printf("Mtl: %08x [%s]  2DTxt: %08x %08x [%s]\n", LMaterial, LMaterial->Name, L2DTextures, L2DTextures[0], L2DTextures[0]->Name);fflush(stdout);

    LTNum=LMaterial->NumOf2DTextures;
    for(LTCnt=0;LTCnt<LTNum;LTCnt++)
    {
     if((L2DTexture=L2DTextures[LTCnt])!=NULL) LNumOf2DTextures++;
    }
   }
  }

  LTotalC=0;
  for(LMCnt=0;LMCnt<LMNum;LMCnt++)
  {
   LMaterial=LScene->Materials[LMCnt];

   if((L2DTextures=LMaterial->Textures2D)!=NULL)
   {
    unsigned int	LTCnt, LTNum;

    LTNum=LMaterial->NumOf2DTextures;

    E3dp_SetProgressMessage("Reading textures");

    for(LTCnt=0;LTCnt<LTNum;LTCnt++)
    {
     L2DTexture=L2DTextures[LTCnt];
     LTextureRead=E3d_Scene2DTextureReadImage(E3d_Scene, L2DTexture, E3dp_Prefs.TexturePath, LForceReread, TRUE);
     LTotalC++;

     if((LTotalC&0x3)==0) E3dp_SetProgressIndicator((LTotalC*1000)/LNumOf2DTextures, NULL, NULL);
    }
   }
  }

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



//========================================
// Sync GUI events
//========================================
void E3dp_SyncGUI()
{
 EGUI_Sync(E3dp_EventLoopFunction);
}


Atom		E3dp_ImportTypes[1], E3dp_STRING;
//========================================
// Transfer callback
//========================================
void E3dpCB_Transfer(Widget LW, XtPointer LClientData, Atom* LSelection, Atom* LType, XtPointer LValue, unsigned long* LLength, int* LFormat)
{
 char*		LStringPtr;
 char		LFileNames[32][256];
 int		LSCCnt, LCCnt, LNumOfFiles, LFileCnt;
 E3dModel*	LModel;

 if(*LType==E3dp_STRING)
 {
  LStringPtr=(char*)LValue;
  LNumOfFiles=0;LSCCnt=0;
  while((LSCCnt<((*LLength)-2))&&(LNumOfFiles<32))
  {
   for(LCCnt=0;(LSCCnt<(*LLength))&&(LCCnt<256)&&(LStringPtr[LSCCnt]!=' ');LSCCnt++, LCCnt++) LFileNames[LNumOfFiles][LCCnt]=LStringPtr[LSCCnt];
   LFileNames[LNumOfFiles][LCCnt]='\0';
   if(LCCnt>0) LNumOfFiles++;
   if(LStringPtr[LSCCnt]==' ') LSCCnt++;
  }
  for(LFileCnt=0;LFileCnt<LNumOfFiles;LFileCnt++)
  {
   if((E3d_HierarchyReadFromFile(LFileNames[LFileCnt], E3dFileFormatAUTOMATIC, NULL, &LModel))==EIO_SUCCESS)
   {
    if(LModel)
    {
     E3d_ModelHrcRefreshMatrices(LModel);
     E3d_ModelHrcRefreshMaterialInheritance(LModel);
     E3d_ModelHrcUpdateMaterialsForDisplay(LModel);
     E3d_SceneAddMaterialsFromModelHrc(E3d_Scene, LModel);

     E3d_ModelHrcUpdateForDisplay(LModel, E3dGF_ALL-E3dGF_REMOVE_STRIPS);

     E3d_SceneAddModelHrc(E3d_Scene, LModel);
    }
   }
   else LModel=NULL;
  }
  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 }
}


//========================================
// Drop callback
//========================================
void E3dpCB_Drop(Widget LW, XtPointer LClientData, XtPointer LCallData)
{
#ifdef _XeUSEXm
 XmDropProcCallbackStruct*	LDropProcData;
 XmDropTransferEntryRec		LDropTransfers[2];

 LDropProcData=(XmDropProcCallbackStruct*)LCallData;
 EXtStart;
 if((LDropProcData->dropAction)!=XmDROP)
 {
  EXtSetArg(XmNtransferStatus, XmTRANSFER_FAILURE);
 }
 else
 {
  LDropTransfers[0].client_data=(XtPointer)NULL;
  LDropTransfers[0].target=E3dp_STRING;

  EXtSetArg(XmNdropTransfers, LDropTransfers);
  EXtSetArg(XmNnumDropTransfers, 1);
  EXtSetArg(XmNtransferStatus, XmTRANSFER_SUCCESS);
  EXtSetArg(XmNtransferProc, (XtSelectionCallbackProc)E3dpCB_Transfer);
  XmDropTransferStart(LDropProcData->dragContext, Args, ArgCnt);
 }
#endif // _XeUSEXm
}


//========================================
// 3DPanel EventHandler
//========================================
static void _EH_Init3DPanel(Widget LW, XtPointer LClientData, XEvent* LXEv, Boolean* LCdr)
{
 XGCValues	LGCValues;

 switch (LXEv->type)
 {
  case MapNotify:
   if(E3dp_TmpGC==NULL) { E3dp_TmpGC=XCreateGC(E3dp_Display, XtWindow(LW), 0L, &LGCValues); }
  break;
 }
}


//========================================
// Remove error message dialog
//========================================
static void _CB_CloseErrorMessageDialog(EguiItem LW, EPointer LClientData, EPointer LCallData)
{
 EGUI_UndisplayShell(E3dp_ErrorDialog);
}


//========================================
// Read a special purpose 3D Model
//========================================
E3dModel* E3dp_Read3DIconModel(char* LFileName)
{
 E3dModel*	LModel;

 if((E3d_HierarchyReadFromFile(LFileName, E3dFileFormatAUTOMATIC, NULL, &LModel))==EIO_SUCCESS)
 {
  if(LModel)
  {
   E3d_ModelHrcRefreshMaterialInheritance(LModel);
   E3d_ModelHrcUpdateMaterialsForDisplay(LModel);

   E3d_ModelHrcUpdateForDisplay(LModel, E3dGF_ALL-E3dGF_REMOVE_STRIPS-E3dGF_CALL_DESTROYPROCS);

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


//========================================
// Key callbacks
//========================================
static void _KCB_3DPanel(unsigned short LKey, unsigned int LModifiers, int LKeyEventType, EPointer LClientData)
{
 unsigned int	LC, LN;

 switch((int)LClientData)
 {
  case E3dCR_TOGGLE_HEADERS:
   LN=E3dp_NumOf3DWindows;
   if(E3dp_Prefs.HeadersOn)
   {
    E3dp_Prefs.HeadersOn=FALSE;
    for(LC=0;LC<LN;LC++) XtUnmanageChild(E3dp_3DWindows[LC]->HeaderFormW);
   }
   else
   {
    E3dp_Prefs.HeadersOn=TRUE;
    for(LC=0;LC<LN;LC++) XtManageChild(E3dp_3DWindows[LC]->HeaderFormW);
   }
  break;
 }
}

//========================================
// Create 3DPanel
//========================================
E3dPanel* E3dp_Create3DPanel(E3dScene* LScene, EguiItem LTopShell, Widget LParentW, int LCols, int LRows, void (*LExitFunction)(), void (*LEventLoopFunction)(EguiEvent*))
{
 E3dOpenGL	LRendererTemplate=
   {
    "OpenGL",			// Name
    sizeof(E3dOpenGL),		// StructSize
    _RenderOpenGL		// RenderProc
   };

 Widget		LTopWidget;
 char		LTmpStr[512], LTmpStr1[512];
 EcRGBAiColor	LColor;
 E3dModel*	LModel;
 E3dMesh*	LMesh;
 Pixmap		LPixmap0, LPixmap1;
 XColor		LXColor0, LXColor1;
 E3dPanel*	L3DPanel;
 EguiArg	LArgs[32];
 int		LArgCnt;
 unsigned int	LC;
 EguiItem	LDialog, LTI;
 XKeyboardState	LKeyboardState;
 E3dModel*	LCameraModel=NULL;
 int		LImageIOReadStatus;


// Initialize the rendering-hardware information
//
 E3dp_RenderingHWInfo.Vendor=NULL;
 E3dp_RenderingHWInfo.Model=NULL;

 E3dp_RenderingHWInfo.VertexArrays=E3dVtxArrNONE;
 E3dp_RenderingHWInfo.Shadows=E3dShadowNONE;


// Register OpenGL renderer
//
 if((_Renderer=(E3dOpenGL*)E3d_RendererRegister((E3dRenderer*)(&LRendererTemplate)))!=NULL)
 {
 }


 EOp_UndoStackInit(&E3dp_UndoStack);


// Clear PointerMode stack
//
 for(LC=0;LC<E3dpPOINTERMODE_STACKDEPTH;LC++)
 {
  E3dp_PointerModeStack[LC]=E3dpPTR_NONE;
  E3dp_PointerModeStackPtr=0;
 }

 E3dp_Display=XtDisplay(LParentW);
 E3dp_Screen=DefaultScreen(E3dp_Display);
 E3dp_AppContext=XtWidgetToApplicationContext(LParentW);

 E3dp_RedPixel=Ec_XGetColor(E3dp_Display, LParentW->core.colormap, "red");
 E3dp_GreenPixel=Ec_XGetColor(E3dp_Display, LParentW->core.colormap, "green");
 E3dp_BluePixel=Ec_XGetColor(E3dp_Display, LParentW->core.colormap, "blue");

 E3dp_TopShell=LTopShell;

 if((L3DPanel=(E3dPanel*)EMalloc(sizeof(E3dPanel)))==NULL) return(NULL);

 L3DPanel->ToolPanelW=NULL;
 L3DPanel->StatusPanelW=NULL;
 L3DPanel->TimePanelW=NULL;

 E_KeySetCallback("Toggle 3DWindow headers", (unsigned short)'h', 0, EKeyPRESS, _KCB_3DPanel, (EPointer)E3dCR_TOGGLE_HEADERS);

 E3d_Scene=LScene;
 L3DPanel->MenuBar=NULL;
 if(E3dp_GLVisualId==NULL) E3dp_GLVisualId=glXChooseVisual(E3dp_Display, E3dp_Screen, E3dp_GLVisualAttrs);

 if(E3dp_GLVisualId)
 {
  E3dp_DoubleBuffer=TRUE;

  L3DPanel->EGLXContext=glXCreateContext(EGUI_Display, E3dp_GLVisualId, None, GL_TRUE);

  if(L3DPanel->EGLXContext==NULL)
  {
   EFree(L3DPanel);

  printf("Couldn't create GLX context\n");fflush(stdout);
//    assert(0);
   return(NULL);
  }
 }
 else
 {
  printf("glXChooseVisual() Couldn't find appropriate visual\n");fflush(stdout);
  return(NULL);
 }


// Set up image file I/O
//
 LImageIOReadStatus=E3dp_LoadPlugins(E3dp_Prefs.ImageFileIOPluginPath, "Formats.list");

// Read default 2DTexture image
//
 if((E3d_NotFound2DTextureImage=Ep_ImageAllocate(0, 0, 0))!=NULL)
 {
  E3d_NotFound2DTextureImage->RGBA8Image=(EpRGBA8Pixel*)(Image_NoTexture.RGBA8Image);
  E3d_NotFound2DTextureImage->XSize=Image_NoTexture.XSize;
  E3d_NotFound2DTextureImage->YSize=Image_NoTexture.YSize;
  E3d_NotFound2DTextureImage->PixelFormats=EpPixelRGBX8;

  E3d_NotFound2DTextureImage->RefCnt=1;
 }

 E3dp_ExitFunction=LExitFunction;
 E3dp_EventLoopFunction=LEventLoopFunction;
 E3dp_ModelPanelColumns=LCols;
 E3dp_ModelPanelRows=LRows;

 LTopWidget=LParentW;
 while(XtParent(LTopWidget)) LTopWidget=XtParent(LTopWidget);
 E3dp_TopWidget=LTopWidget;
 E3dp_ParentW=LParentW;
 E3dp_TmpGC=NULL;
 XGetKeyboardControl(E3dp_Display, &LKeyboardState);

 E3dp_STRING=XInternAtom(E3dp_Display, "STRING", False);	// For DropSite functions
 E3dp_ImportTypes[0]=E3dp_STRING;

 if(E3d_SettingsPixmap==(Pixmap)NULL) E3d_SettingsPixmap=EGUI_VaXPMToPixmap(Layout_pm, EguiNbackground, MenuBackgroundColor, EguiNbottomShadowColor, MenuBottomShadowColor, NULL);
 if(E3d_SettingsPixmapMask==(Pixmap)NULL) E3d_SettingsPixmapMask=EGUI_VaXPMToPixmap(LayoutMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

 if(E3dp_OrbitCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(OrbitCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(OrbitCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_OrbitCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }

 if(E3dp_TrackZoomCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(TrackZoomCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(TrackZoomCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_TrackZoomCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }

 if(E3dp_TrackCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(TrackCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(TrackCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_TrackCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }

 if(E3dp_ZoomCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(ZoomCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(ZoomCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_ZoomCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }

 if(E3dp_DollyCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(DollyCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(DollyCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_DollyCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }

 if(E3dp_RollCursor==(Cursor)NULL)
 {
  LPixmap0=EGUI_VaXPMToPixmap(RollCursor_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);
  LPixmap1=EGUI_VaXPMToPixmap(RollCursorMask_pm, EguiNbackground, 0, EguiNforeground, 1, EguiNpixmapDepth, 1, NULL);

  LXColor0.red=0x0000;
  LXColor0.green=0x0000;
  LXColor0.blue=0x0000;
  LXColor0.flags=DoRed|DoGreen|DoBlue;

  LXColor1.red=0xFFFF;
  LXColor1.green=0xFFFF;
  LXColor1.blue=0x0000;
  LXColor1.flags=DoRed|DoGreen|DoBlue;

  if((LPixmap0!=(Pixmap)NULL)&&(LPixmap1!=(Pixmap)NULL)) E3dp_RollCursor=XCreatePixmapCursor(E3dp_Display, LPixmap0, LPixmap1, &LXColor0, &LXColor1, 15, 15);
  if(LPixmap0!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap0);
  if(LPixmap1!=(Pixmap)NULL) XFreePixmap(E3dp_Display, LPixmap1);
 }


 E3dp_BusyCursor=XCreateFontCursor(E3dp_Display, XC_watch);
 E3dp_Colormap=DefaultColormap(E3dp_Display, E3dp_Screen);

 if(E3dp_ProgressIndicatorColor==0) E3dp_ProgressIndicatorColor=Ec_XGetColor(E3dp_Display, E3dp_Colormap, "sky blue");

// if(E3dp_ProgressIndicatorColor==0) E3dp_ProgressIndicatorColor=Ec_XGetRGBAColor(E3dp_Display, E3dp_Colormap, 0x32, 0xC8, 0xD4);


 if(/*getgdesc(GD_BITS_NORM_ZBUFFER)==0*/0)
 {
  printf("Sorry, no ZBuffer on this machine!\n");fflush(stdout);
  E3d_ZBufferOk=FALSE;
 }
 else E3d_ZBufferOk=TRUE;

 EXtStart;
 EXtSetArg(XeNshadowThickness, 0);
// EXtSetArg(XeNbackground, PanelBackgroundColor);
 EXtSetArg(XeNorientation, XeVERTICAL);
 EXtSetArg(XeNadjustEntryWidths, True);
 EXtSetArg(XeNadjustEntryHeights, True);
 EXtSetArg(XeNmarginWidth, 0);EXtSetArg(XeNmarginHeight, 0);
 L3DPanel->TopMatrixW=XtCreateManagedWidget("TopMatrixW", xeMatrixWidgetClass, LParentW, Args, ArgCnt);


 EXtStart;
 EXtSetArg(XeNshadowThickness, 0);
 EXtSetArg(XeNbackground, PanelBackgroundColor);
 EXtSetArg(XeNorientation, XeHORIZONTAL);
 EXtSetArg(XeNadjustEntryWidths, True);
 EXtSetArg(XeNadjustEntryHeights, True);
 EXtSetArg(XeNmarginWidth, 0);EXtSetArg(XeNmarginHeight, 0);
 L3DPanel->MiddleMatrixW=XtCreateManagedWidget("Menu3DWindowsTransformPanelMatrixW", xeMatrixWidgetClass, L3DPanel->TopMatrixW, Args, ArgCnt);


 XtAddEventHandler(L3DPanel->MiddleMatrixW, StructureNotifyMask, True, _EH_Init3DPanel, (XtPointer)NULL);



#ifdef _XeUSEXm
 EXtStart;
 EXtSetArg(XmNdropSiteOperations, XmDROP_COPY|XmDROP_MOVE);
 EXtSetArg(XmNdropProc, (XtCallbackProc)E3dpCB_Drop);
 EXtSetArg(XmNimportTargets, E3dp_ImportTypes);
 EXtSetArg(XmNnumImportTargets, 1);
 EXtSetArg(XmNdropSiteType, XmDROP_SITE_COMPOSITE);
 EXtSetArg(XmNanimationStyle, XmDRAG_UNDER_HIGHLIGHT);
 XmDropSiteRegister(L3DPanel->MiddleMatrixW, Args, ArgCnt);
#endif // _XeUSEXm


// Initialize the scene
//
 E3d_3DInit();

 E3dp_AddBuiltInFunctionsGUI();

 E3dp_LoadPlugins(E3dp_Prefs.FileIOPluginPath, "Formats.list");

 E3dp_LoadPlugins(E3dp_Prefs.PluginPath, "Plugins.list");

 E3dp_SetMenuBar(L3DPanel, E3dp_Prefs.MenuBarOn);

 EXtStart;
 EXtSetArg(XeNleftAttachment, XeATTACH_FORM);EXtSetArg(XeNleftOffset, 0);
 EXtSetArg(XeNrightAttachment, XeATTACH_FORM);EXtSetArg(XeNrightOffset, 0);
 EXtSetArg(XeNtopAttachment, XeATTACH_FORM);EXtSetArg(XeNtopOffset, 0);
 EXtSetArg(XeNbottomAttachment, XeATTACH_FORM);EXtSetArg(XeNbottomOffset, 0);
 EXtSetArg(XeNshadowThickness, 0);
 EXtSetArg(XeNmarginWidth, 0);EXtSetArg(XeNmarginHeight, 0);
 EXtSetArg(XeNbackground, PanelBackgroundColor);
 EXtSetArg(XeNadjustEntryWidths, True);
 EXtSetArg(XeNadjustEntryHeights, True);
 EXtSetArg(XeNnumOfColumns, 2);
 EXtSetArg(XeNlayoutProc, E3d_3DWindowsLayout);
 EXtSetArg(XeNpreferredSizeProc, E3d_3DWindowsGetPreferredSize);
 L3DPanel->M3DWindowLayoutW=XtCreateManagedWidget("3DWindowsMatrixW", xeLayoutWidgetClass, L3DPanel->MiddleMatrixW, Args, ArgCnt);


// Create sub-panels
//
 E3dp_TransformPanelToggle(L3DPanel, E3dp_Prefs.TransformPanelOn);
 E3dp_SetToolPanel(L3DPanel, E3dp_Prefs.ToolPanelOn);
 E3dp_SetStatusPanel(L3DPanel, E3dp_Prefs.StatusPanelOn);
 E3dp_SetTimePanel(L3DPanel, E3dp_Prefs.TimePanelOn, E3dp_Prefs.TimeExtPanelOn);

 E3dp_ModelPanelCreated=TRUE;


//--------------------------------
// Read 3D icons
//--------------------------------
 E3d_3DPositionInit(&E3d_3DCursorPos, 0.0, 0.0, 0.0);
 E3d_RotationInit(&E3d_3DCursorRot, 0.0, 0.0, 0.0);
 E3d_MatrixLoadIdentity(E3d_3DCursorMatrix);
 sprintf(LTmpStr, "%s/Data/%s", E3dp_Prefs.ResourcePath, "E3DCursor.hrc");
 if((E3d_3DCursorModel=E3dp_Read3DIconModel(LTmpStr))==NULL) E3dp_Log(ELOG_WARNING, "reading 3D icons", "Could not read file: %s", LTmpStr);

 sprintf(LTmpStr, "%s/Data/%s", E3dp_Prefs.ResourcePath, "EBulb.hrc");

 if((LModel=E3dp_Read3DIconModel(LTmpStr))!=NULL)
 {
  E3d_BulbMesh=(E3dMesh*)(LModel->Geometries[0]);E3d_BulbMesh->RefCnt+=1;
  E3d_BulbMesh->Name=EStrDup("LightBulbMesh");
  E3d_ModelHrcFree(LModel, TRUE);
 }
 else E3dp_Log(ELOG_WARNING, "reading 3D icons", "Could not read file: %s", LTmpStr);

 sprintf(LTmpStr, "%s/Data/%s", E3dp_Prefs.ResourcePath, "EWireCamera.hrc");
 if((E3d_WireCameraModel=E3dp_Read3DIconModel(LTmpStr))==NULL)
 {
  E3d_WireCameraModel=E3d_ModelAllocate("Camera");
  E3dp_Log(ELOG_WARNING, "reading 3D icons", "Could not read file: %s", LTmpStr);
 }

 E3d_WireCameraModel->Type=E3dMDL_CAMERA;

 LCameraModel=E3d_WireCameraModel;

/*
 sprintf(LTmpStr, "%s/Data/%s", E3dp_Prefs.ResourcePath, "ESolidCamera.hrc");

 if((E3d_SolidCameraModel=E3dp_Read3DIconModel(LTmpStr))!=NULL) E3d_ModelHrcCreateRenderablePolygons(E3d_SolidCameraModel, FALSE);
 else E3dp_Log(ELOG_WARNING, "reading 3D icons", "Could not read file: %s", LTmpStr);
*/

// Create Model for the Camera interest point
//
 if((E3d_CameraInterestModel=E3d_ModelAllocate("Camera_I"))!=NULL)
 {
  LMesh=(E3dMesh*)E3d_ModelAddGeometry(E3d_CameraInterestModel, E3dGEO_MESH, "camera_i");
  LMesh->Vertices=E3d_VerticesAllocate(LMesh->NumOfVertices=6, TRUE);
  (LMesh->Vertices)[0].X=-1.0;(LMesh->Vertices)[0].Y=0.0;(LMesh->Vertices)[0].Z=0.0;
  (LMesh->Vertices)[1].X=1.0;(LMesh->Vertices)[1].Y=0.0;(LMesh->Vertices)[1].Z=0.0;
  (LMesh->Vertices)[2].X=0.0;(LMesh->Vertices)[2].Y=-1.0;(LMesh->Vertices)[2].Z=0.0;
  (LMesh->Vertices)[3].X=0.0;(LMesh->Vertices)[3].Y=1.0;(LMesh->Vertices)[3].Z=0.0;
  (LMesh->Vertices)[4].X=0.0;(LMesh->Vertices)[4].Y=0.0;(LMesh->Vertices)[4].Z=-1.0;
  (LMesh->Vertices)[5].X=0.0;(LMesh->Vertices)[5].Y=0.0;(LMesh->Vertices)[5].Z=1.0;
  LMesh->Edges=E3d_EdgesAllocate(LMesh->NumOfEdges=3);
  (LMesh->Edges)[0].Start=0;(LMesh->Edges)[0].End=1;
  (LMesh->Edges)[1].Start=2;(LMesh->Edges)[1].End=3;
  (LMesh->Edges)[2].Start=4;(LMesh->Edges)[2].End=5;
  E3d_MeshRefreshGLEdges(LMesh, E3d_IdentityMatrix);

  LCameraModel->Child=E3d_CameraInterestModel;
  E3d_CameraInterestModel->Parent=LCameraModel;
  E3d_CameraInterestModel->Type=E3dMDL_CAMERA_INTEREST;
  E3d_ModelHrcRefreshHierarchy(LCameraModel);

  E3d_SceneAddModelHrc(LScene, LCameraModel);
 }


// GL Material indices of normal models (after 3D icons)
//
 E3d_MatOffsetModels=E3d_Scene->NumOfMaterials;

 {
  E3dDrawContext*	LDrawContext;

  LDrawContext=&E3dp_NormalDrawContext;

  LDrawContext->BackgroundRGBAiColor=E3dp_Prefs.BackgroundRGBAiColor;
  LDrawContext->GridRGBAiColor=E3dp_Prefs.GridRGBAiColor;
  LDrawContext->SubGridRGBAiColor=E3dp_Prefs.SubGridRGBAiColor;
  LDrawContext->ShadedGridRGBAiColor=E3dp_Prefs.ShadedGridRGBAiColor;
  LDrawContext->ShadedSubGridRGBAiColor=E3dp_Prefs.ShadedSubGridRGBAiColor;
  LDrawContext->AxisRGBAiColor=E3dp_Prefs.AxisRGBAiColor;
  LDrawContext->ShadedAxisRGBAiColor=E3dp_Prefs.ShadedAxisRGBAiColor;
  LDrawContext->VertexRGBAiColor=E3dp_Prefs.VertexRGBAiColor;
  LDrawContext->HVertexRGBAiColor=E3dp_Prefs.HVertexRGBAiColor;
  LDrawContext->LockedItemRGBAiColor=E3dp_Prefs.LockedItemRGBAiColor;
  LDrawContext->ActivePointRGBAiColor=E3dp_Prefs.ActivePointRGBAiColor;
  LDrawContext->TaggedPointRGBAiColor=E3dp_Prefs.TaggedPointRGBAiColor;
  LDrawContext->ActiveEdgeRGBAiColor=E3dp_Prefs.ActiveEdgeRGBAiColor;
  LDrawContext->SelectedEdgeRGBAiColor=E3dp_Prefs.SelectedEdgeRGBAiColor;

  LDrawContext->WireRGBAiColor=E3dp_Prefs.WireRGBAiColor;
  LDrawContext->HWireRGBAiColor=E3dp_Prefs.HWireRGBAiColor;
  LDrawContext->SelGeoWireRGBAiColor=E3dp_Prefs.SelGeoWireRGBAiColor;
  LDrawContext->SelSubGeoWireRGBAiColor=E3dp_Prefs.SelSubGeoWireRGBAiColor;
  LDrawContext->Line1RGBAiColor=E3dp_Prefs.Line1RGBAiColor;
  LDrawContext->Line2RGBAiColor=E3dp_Prefs.Line2RGBAiColor;
  LDrawContext->SelectedPolygonRGBAiColor=E3dp_Prefs.SelectedPolygonRGBAiColor;
  LDrawContext->ShadedSelectedPolygonRGBAiColor=E3dp_Prefs.ShadedSelectedPolygonRGBAiColor;
  LDrawContext->NormalRGBAiColor=E3dp_Prefs.NormalRGBAiColor;
  LDrawContext->TextureProjectorRGBAiColor=E3dp_Prefs.TextureProjectorRGBAiColor;

  LDrawContext->BackgroundRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->BackgroundRGBAiColor);
  LDrawContext->SelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->SelectedPolygonRGBAiColor);
  LDrawContext->ShadedSelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->ShadedSelectedPolygonRGBAiColor);



  LDrawContext=&E3dp_LeftEyeDrawContext;

  LColor=E3dp_Prefs.LeftEyeRGBAiColor;
  E3d_ColorShadeByLuma(&(E3dp_Prefs.BackgroundRGBAiColor), &LColor, &(LDrawContext->BackgroundRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.GridRGBAiColor), &LColor, &(LDrawContext->GridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SubGridRGBAiColor), &LColor, &(LDrawContext->SubGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedGridRGBAiColor), &LColor, &(LDrawContext->ShadedGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedSubGridRGBAiColor), &LColor, &(LDrawContext->ShadedSubGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.AxisRGBAiColor), &LColor, &(LDrawContext->AxisRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedAxisRGBAiColor), &LColor, &(LDrawContext->ShadedAxisRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_VERTEXCOLOR), &LColor, &(LDrawContext->VertexRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_HVERTEXCOLOR), &LColor, &(LDrawContext->HVertexRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LOCKEDITEMCOLOR), &LColor, &(LDrawContext->LockedItemRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_TAGGEDVERTEXCOLOR), &LColor, &(LDrawContext->ActivePointRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_TAGGEDVERTEXCOLOR), &LColor, &(LDrawContext->TaggedPointRGBAiColor));

  E3d_ColorShadeByLuma(&(E3dpSTEREO_WIRECOLOR), &LColor, &(LDrawContext->WireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelGeoWireRGBAiColor), &LColor, &(LDrawContext->SelGeoWireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelSubGeoWireRGBAiColor), &LColor, &(LDrawContext->SelSubGeoWireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LINE1COLOR), &LColor, &(LDrawContext->Line1RGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LINE2COLOR), &LColor, &(LDrawContext->Line2RGBAiColor));

  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelectedPolygonRGBAiColor), &LColor, &(LDrawContext->SelectedPolygonRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedSelectedPolygonRGBAiColor), &LColor, &(LDrawContext->ShadedSelectedPolygonRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.NormalRGBAiColor), &LColor, &(LDrawContext->NormalRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.TextureProjectorRGBAiColor), &LColor, &(LDrawContext->TextureProjectorRGBAiColor));

  LDrawContext->BackgroundRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->BackgroundRGBAiColor);
  LDrawContext->SelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->SelectedPolygonRGBAiColor);
  LDrawContext->ShadedSelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->ShadedSelectedPolygonRGBAiColor);


  LDrawContext=&E3dp_RightEyeDrawContext;
  LColor=E3dp_Prefs.RightEyeRGBAiColor;
  E3d_ColorShadeByLuma(&(E3dp_Prefs.BackgroundRGBAiColor), &LColor, &(LDrawContext->BackgroundRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.GridRGBAiColor), &LColor, &(LDrawContext->GridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SubGridRGBAiColor), &LColor, &(LDrawContext->SubGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedGridRGBAiColor), &LColor, &(LDrawContext->ShadedGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedSubGridRGBAiColor), &LColor, &(LDrawContext->ShadedSubGridRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.AxisRGBAiColor), &LColor, &(LDrawContext->AxisRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedAxisRGBAiColor), &LColor, &(LDrawContext->ShadedAxisRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_VERTEXCOLOR), &LColor, &(LDrawContext->VertexRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_HVERTEXCOLOR), &LColor, &(LDrawContext->HVertexRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LOCKEDITEMCOLOR), &LColor, &(LDrawContext->LockedItemRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_TAGGEDVERTEXCOLOR), &LColor, &(LDrawContext->ActivePointRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_TAGGEDVERTEXCOLOR), &LColor, &(LDrawContext->TaggedPointRGBAiColor));

  E3d_ColorShadeByLuma(&(E3dpSTEREO_WIRECOLOR), &LColor, &(LDrawContext->WireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_HWIRECOLOR), &LColor, &(LDrawContext->HWireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelGeoWireRGBAiColor), &LColor, &(LDrawContext->SelGeoWireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelSubGeoWireRGBAiColor), &LColor, &(LDrawContext->SelSubGeoWireRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LINE1COLOR), &LColor, &(LDrawContext->Line1RGBAiColor));
  E3d_ColorShadeByLuma(&(E3dpSTEREO_LINE2COLOR), &LColor, &(LDrawContext->Line2RGBAiColor));

  E3d_ColorShadeByLuma(&(E3dp_Prefs.SelectedPolygonRGBAiColor), &LColor, &(LDrawContext->SelectedPolygonRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.ShadedSelectedPolygonRGBAiColor), &LColor, &(LDrawContext->ShadedSelectedPolygonRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.NormalRGBAiColor), &LColor, &(LDrawContext->NormalRGBAiColor));
  E3d_ColorShadeByLuma(&(E3dp_Prefs.TextureProjectorRGBAiColor), &LColor, &(LDrawContext->TextureProjectorRGBAiColor));

  LDrawContext->BackgroundRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->BackgroundRGBAiColor);
  LDrawContext->SelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->SelectedPolygonRGBAiColor);
  LDrawContext->ShadedSelectedPolygonRGBAp8Color=EcM_RGBAi_to_RGBAp8(LDrawContext->ShadedSelectedPolygonRGBAiColor);
 }


 if(Ep_NumOfImageFileFormats==0)
 {
  switch(LImageIOReadStatus)
  {
   case ESetFILE_OPEN_ERROR:
    sprintf(LTmpStr1, "Could not read file: %s/%s", E3dp_Prefs.ImageFileIOPluginPath, "Formats.list");
   break;

   default:
    sprintf(LTmpStr1, "See log file");
   break;
  }

  sprintf(LTmpStr, "Couldn't read any image-file I/O modules, you won't be able to use 2D textures and icons!\n\nReason:\n\n %s", LTmpStr1);

  EGUI_Sync(E3dp_EventLoopFunction);

// Pop up error dialog
//
  if(E3dp_ErrorDialog==NULL)
  {
   EGUI_VaChangeDialogColors(0, EguiNbackground, MenuBackgroundColor, EguiNtroughColor, MenuTroughColor, EguiNforeground, MenuForegroundColor, EguiNtopShadowColor, MenuTopShadowColor, EguiNbottomShadowColor, MenuBottomShadowColor, NULL);

   LArgCnt=0;
   EguiSetArg(EguiNallowShellResize, True, LArgs, LArgCnt);
   EguiSetArg(EguiNmessageString, LTmpStr, LArgs, LArgCnt);
   EguiSetArg(EguiNstretchButtons, FALSE, LArgs, LArgCnt);
   EguiSetArg(EguiNworkAreaType, EguiFORM, LArgs, LArgCnt);
   EguiSetArg(EguiNwmDecorations, EguiWM_DECOR_BORDER|EguiWM_DECOR_TITLE, LArgs, LArgCnt);
   EguiSetArg(EguiNtitle, "EQUINOX-3D: Error", LArgs, LArgCnt);EguiSetArg(EguiNiconName, "Error", LArgs, LArgCnt);
   if((LDialog=EGUI_CreateDialog(EguiDIALOG_ERROR, "Error", E3dp_TopShell, LArgs, LArgCnt))!=NULL)
   {
    E3dp_ErrorDialog=LDialog;
    LArgCnt=0;
    EguiSetArg(EguiNshowAsDefault, TRUE, LArgs, LArgCnt);
    LTI=EGUI_CreatePushButton("Ok", LDialog, LArgs, LArgCnt);
    EGUI_AddCallback(LTI, EguiNactivateCallback, _CB_CloseErrorMessageDialog, (EPointer)EguiOK);

    EGUI_ShellSetStackingPriority(LDialog, EguiSTACKING_PRIORITY1);
    EGUI_RaiseShell(LDialog);
   }
   EGUI_RestoreDialogColors();
  }
  else
  {
   EGUI_VaSetDialogValues(E3dp_ErrorDialog, EguiNmessageString, LTmpStr1, NULL);
   EGUI_RaiseShell(E3dp_ErrorDialog);
  }

  EGUI_CenterShellToItem(E3dp_ErrorDialog, LTopShell);
 }

 return(L3DPanel);
}


//================================================================
// Separate or duplicate the selected PolyGroups of a Mesh
//================================================================
int E3d_MeshSeparateSelectedPolyGroups(E3dMesh* LMesh, E3dModel* LAddToModel, int LFlags, EBool LKeepOriginalPolyGroups)
{
 E3dMesh*	LNewMesh=NULL;
 E3dPolyGroup*	LPolyGroup;
 unsigned int	LGCnt;
 int		LPolyGroupsSeparated=0;


 if(LMesh->NumOfPolyGroups==0) return(LPolyGroupsSeparated);

 for(LGCnt=0;LGCnt<LMesh->NumOfPolyGroups;)
 {
  LPolyGroup=LMesh->PolyGroups[LGCnt];

  if(LKeepOriginalPolyGroups)
  {
   if(LPolyGroup->Selected)
   {
    if(LNewMesh==NULL) LNewMesh=E3d_MeshAllocate();
    LPolyGroup=E3d_PolyGroupClone(LPolyGroup, LFlags);
    E3d_MeshAppendPolyGroup(LNewMesh, LPolyGroup);
   }
   LGCnt++;
  }
  else
  {
   if(LPolyGroup->Selected)
   {
    if(LNewMesh==NULL) LNewMesh=E3d_MeshAllocate();
    E3d_MeshAppendPolyGroup(LNewMesh, LPolyGroup);
    E3d_MeshRemovePolyGroup(LMesh, LPolyGroup);
   }
   else LGCnt++;
  }
 }

 if(LNewMesh)
 {
  E3dVertex*		LVertices=LMesh->Vertices;
  E3dVertex*		LVertex;
  E3dPolygon*		LPolygon;
  E3dVertexNode*	LVertexNode;
  unsigned int		LPGC, LPGN, LPC,
			LVC, LNumOfNewVertices=0;

// Mark Vertices that are used on the selected PolyGroups
//

  E3dp_PrintMessage(0, 0, "Analyzing selection");
  E3dp_SetProgressIndicator(0, NULL, NULL);

// Clear Vertex E3dVTX_PASSED flags
//
  LVertex=LVertices;
  LVC=LMesh->NumOfVertices;
  do
  {
   LVertex->Flags&=(E3dVTXF_ALL-E3dVTXF_PASSED);
   LVertex++;
  } while(--LVC);

// Mark and count Vertices that are used by NewMesh
//
  LPGN=LNewMesh->NumOfPolyGroups;
  for(LPGC=0;LPGC<LPGN;LPGC++)
  {
   LPolyGroup=LNewMesh->PolyGroups[LPGC];

Printf("NewMesh PolyGroup %d of %d\n", LPGC, LPGN);fflush(stdout);

   LPC=LPolyGroup->NumOfPolygons;
   LPolygon=LPolyGroup->Polygons;
   do
   {
    LVertexNode=LPolygon->VertexNodes;
    LVC=LPolygon->NumOfVertexNodes;

    do
    {
     if(LVertexNode->VertexID>=0)
     {
      LVertex=LVertices+LVertexNode->VertexID;
      if((LVertex->Flags&E3dVTXF_PASSED)==0) { LVertex->Flags|=E3dVTXF_PASSED;LNumOfNewVertices++; }
     }
     LVertexNode++;
    } while(--LVC);

    LPolygon++;
   } while(--LPC);
  }

  if(LNumOfNewVertices>0)
  {
   if((LNewMesh->Vertices=E3d_VerticesAllocate(LNumOfNewVertices, FALSE))!=NULL)
   {
    int*		LInToNewVertexIndexTable=NULL;		// Tells which NewVertex maps to an InVertex
    E3dVertex*		LNewVertex=LNewMesh->Vertices;
    unsigned int	LVN=LMesh->NumOfVertices;
    int			LNewVC=0;

    LVertex=LVertices;
    if((LInToNewVertexIndexTable=(int*)EMalloc(sizeof(int)*LVN))!=NULL)
    {
// Re-map new PolyGroup's Vertices to the new Mesh
//
     LNewMesh->NumOfVertices=LNumOfNewVertices;
     LVertex=LVertices;
     for(LVC=0;LVC<LVN;LVC++, LVertex++)
     {
      if(LVertex->Flags&E3dVTXF_PASSED)
      {
       LInToNewVertexIndexTable[LVC]=LNewVC;LNewVC++;
       *LNewVertex=*LVertex;
       LNewVertex++;
      }
      else LInToNewVertexIndexTable[LVC]=-1;
     }

     E3d_MeshRemapVertexIndices(LNewMesh, LInToNewVertexIndexTable);


// Remove unused Vertices from the old Mesh
//

// Clear Vertex E3dVTX_PASSED flags
//
     LVertex=LVertices;
     LVC=LMesh->NumOfVertices;
     do
     {
      LVertex->Flags&=(E3dVTXF_ALL-E3dVTXF_PASSED);
      LVertex++;
     } while(--LVC);

// Mark and count Vertices that are used by the old Mesh without the selected PolyGroups
//
     LNumOfNewVertices=0;
     LPGN=LMesh->NumOfPolyGroups;
     for(LPGC=0;LPGC<LPGN;LPGC++)
     {
      LPolyGroup=LMesh->PolyGroups[LPGC];

      LPC=LPolyGroup->NumOfPolygons;
      if(LPC)
      {
       LPolygon=LPolyGroup->Polygons;
       do
       {
	LVertexNode=LPolygon->VertexNodes;
	LVC=LPolygon->NumOfVertexNodes;

	do
	{
	 if(LVertexNode->VertexID>=0)
	 {
	  LVertex=LVertices+LVertexNode->VertexID;
	  if((LVertex->Flags&E3dVTXF_PASSED)==0) { LVertex->Flags|=E3dVTXF_PASSED;LNumOfNewVertices++; }
	 }
	 LVertexNode++;
	} while(--LVC);

	LPolygon++;
       } while(--LPC);
      }
     }

     if(LNumOfNewVertices>0)
     {
      E3dVertex*	LNVertices;

      if((LNVertices=E3d_VerticesAllocate(LNumOfNewVertices, FALSE))!=NULL)
      {
       E3dVertex*	LNVertex=LNVertices;

       LVertex=LVertices;
       LNewVC=0;

       LVertex=LVertices;
       for(LVC=0;LVC<LVN;LVC++, LVertex++)
       {
	if(LVertex->Flags&E3dVTXF_PASSED)
	{
	 LInToNewVertexIndexTable[LVC]=LNewVC;LNewVC++;
	 *LNVertex=*LVertex;
	 LNVertex++;
	}
	else LInToNewVertexIndexTable[LVC]=-1;
       }

       E3d_MeshRemapVertexIndices(LMesh, LInToNewVertexIndexTable);
       EFree(LMesh->Vertices);
       LMesh->Vertices=LNVertices;
       LMesh->NumOfVertices=LNumOfNewVertices;
      }
     }


     EFree(LInToNewVertexIndexTable);
     E3d_ModelAppendGeometry(LAddToModel, (E3dGeometry*)LNewMesh);
    }
   }
  }


  E3dp_SetProgressMessage("RefreshForDisplay old Mesh");
  E3dp_SetProgressIndicator((1*1000)/3, NULL, NULL);

  E3d_GeometryUpdateForDisplay((E3dGeometry*)LMesh, E3dGF_ALL-E3dGF_REMOVE_STRIPS);

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

  E3dp_SetProgressMessage("RefreshForDisplay new Mesh");
  E3d_GeometryUpdateForDisplay((E3dGeometry*)LNewMesh, E3dGF_ALL-E3dGF_REMOVE_STRIPS);
  E3dp_SetProgressIndicator(-1, NULL, NULL);
  E3dp_SetProgressMessage(NULL);
 }

 return(LPolyGroupsSeparated);
}


//========================================
// Free 3DPanel
//========================================
void E3dp_Free3DPanel(E3dPanel* L3DPanel)
{
 E3dWindow*	L3DWindow;
 unsigned int	LC, LN;


 if(E3dp_ModelPanelCreated)
 {
  if(_Renderer) E3d_RendererDeactivate((E3dRenderer*)_Renderer);


//--------------------------------
// Free 3D icons
//--------------------------------

  if(E3d_3DCursorModel) E3d_ModelHrcFree(E3d_3DCursorModel, TRUE);
  if(E3d_SpotlightModel) E3d_ModelHrcFree(E3d_SpotlightModel, TRUE);


  if(E3d_BulbMesh) E3d_MeshFree(E3d_BulbMesh);


  E3dp_SetBackKeyboardControl();
  if(E3dp_BusyCursor) XFreeCursor(E3dp_Display, E3dp_BusyCursor);

  LN=E3dp_NumOf3DWindows;
  for(LC=0;LC<LN;LC++)
  {
   L3DWindow=E3dp_3DWindows[LC];

   if(L3DWindow->WindowFlags&E3dWF_CREATED)
   {
    if(L3DWindow->GLXW) XtDestroyWidget(L3DWindow->GLXW);
    if(L3DWindow->FrameW) XtDestroyWidget(L3DWindow->FrameW);
    if(L3DWindow->SizeButtonW) XtDestroyWidget(L3DWindow->SizeButtonW);
    if(L3DWindow->DisplayModeMenuBar) EGUI_FreeMenuBar(L3DWindow->DisplayModeMenuBar);
    if(L3DWindow->ViewModeMenuBar) EGUI_FreeMenuBar(L3DWindow->ViewModeMenuBar);
    if(L3DWindow->MatrixW) XtDestroyWidget(L3DWindow->MatrixW);
   }
  }

  glXDestroyContext(E3dp_Display, L3DPanel->EGLXContext);

  if(L3DPanel->M3DWindowLayoutW) { XtDestroyWidget(L3DPanel->M3DWindowLayoutW);L3DPanel->M3DWindowLayoutW=(Widget)NULL; }
  if(E3dp_TmpGC) { XFreeGC(E3dp_Display, E3dp_TmpGC);E3dp_TmpGC=NULL; }
  if(E3dp_TimePanel) Ea_TimePanelFree(E3dp_TimePanel);
 }

 EFree(L3DPanel);
 E3d_Free();
}


void E3dp_AppendOps1Operator(EOperator* LOperator)
{
 EOp_AppendOps1Operator(&E3dp_UndoStack, LOperator);

// Update undo-stack indicator
//
 XeScaleSetValue(E3d_UndoBufferDisplayW, E3dp_UndoStack.Ptr, False);
}


void E3dp_Undo(E3dPanel* LPanel)
{
 EUndoStack*	LStack=&E3dp_UndoStack;
 EOps*		LOps=EOp_Undo(LStack);

 if(LOps)
 {
  E3dp_PrintMessage(0, 5000, "Undo: %s", LOps->Operators[0]->Name);

  E3dp_WindowsRedrawByChangeFlags(LStack->Changed);
  XeScaleSetValue(E3d_UndoBufferDisplayW, E3dp_UndoStack.Ptr, False);

  E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, TRUE);
 }
 else E3dp_PrintMessage(0, 5000, "Nothing to undo!");
}


void E3dp_Redo(E3dPanel* LPanel)
{
 EUndoStack*	LStack=&E3dp_UndoStack;
 EOps*		LOps=EOp_Redo(LStack);

 if(LOps)
 {
  E3dp_PrintMessage(0, 5000, "Redo: %s", LOps->Operators[0]->Name);

  E3dp_WindowsRedrawByChangeFlags(LStack->Changed);
  XeScaleSetValue(E3d_UndoBufferDisplayW, E3dp_UndoStack.Ptr, False);

  E3dp_TransformPanelUpdate(E3dDO_ALL, E3dDO_ALL, E3dDO_ALL, TRUE);
 }
 else E3dp_PrintMessage(0, 5000, "Nothing to redo!");
}
