
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993-1995 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */

#include "glos.h"

#ifdef GLX_MOTIF
#include <X11/keysym.h>

#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/ToggleB.h>
#include <GL/glx.h>
#include <GLwMDrawA.h>
#include <sys/time.h>
#endif

#include <GL/glu.h>
#include <GL/gl.h>
extern "C" {
#include <GL/glaux.h>
}

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include "scene.hxx"
#include "cbacks.hxx"
#include "menu.h"

#ifdef GLX_MOTIF
extern Widget glw;
extern XtAppContext app_context;
GLXContext glx_con1005text;
#endif

extern light lights[];
extern int quick_moves;
extern int auto_motion;
static float dtheta[nlights];
static float last_motion_update;

//struct timeval starttime;
SYSTEMTIME starttime;

static int button_down;
static int winx, winy;
GLint mouse_x, mouse_y;

static int name_selected;

#ifdef GLX_MOTIF
static XtWorkProcId workproc = NULL;
#endif

const float time_fudge = .0001;

inline
float current_time()
{
  //struct timeval time;
  SYSTEMTIME time;

  //gettimeofday(&time, NULL);
  GetSystemTime(&time);

  //return ((double)(time.tv_sec - starttime.tv_sec) +
  //	  (double)(time.tv_usec - starttime.tv_usec) / 1000000.0);

  return ((float)(time.wSecond - starttime.wSecond) +
        (float)(time.wMilliseconds - starttime.wMilliseconds) / (float)1000.0);

}

inline float rand(float min, float max) 
{
  double r;
  r = (double)rand() / (double)RAND_MAX;
  return (float)(min + r * (max - min));
}

/******************************Public*Routine******************************\
*
* void draw(void)
*
* History:
*  29-Nov-1993                      Replaced with wgl and aux calls
*
\**************************************************************************/

void CALLBACK draw(void)
{

#ifdef GLX_MOTIF
  GLwDrawingAreaMakeCurrent(glw, glx_context);
//#else
  //wglMakeCurrent(auxGetHDC(), auxGetHGLRC());
#endif

  scene_draw();

#ifdef GLX_MOTIF
  GLwDrawingAreaSwapBuffers(glw);
#else
  // Win32's SwapBuffers takes HDC
  // SwapBuffers(auxGetHDC);
  auxSwapBuffers();
#endif

}

/******************************Public*Routine******************************\
*
* vQuickMove(void)
*
* //void intToggleCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  set or reset the global flag quick_moves
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vQuickMove(void)
{
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());

#ifdef GLX_MOTIF
  int *data;
  XmToggleButtonCallbackStruct *ptr;

  ptr = (XmToggleButtonCallbackStruct *)call_data;
  data = (int *)client_data;
  *data = ptr->set;
#endif

  quick_moves = quick_moves ? 0 : 1;

  if (quick_moves)
    CheckMenuItem(hmenu, IDM_QUICK, MF_BYCOMMAND | MF_CHECKED);
  else
    CheckMenuItem(hmenu, IDM_QUICK, MF_BYCOMMAND | MF_UNCHECKED);

  // This redraw may or may not be needed - do it to be safe
  draw();
}

/******************************Public*Routine******************************\
*
* vResetLights(void)
*
* // void resetLightsCB(Widget w)
*
* Effects:
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vResetLights(void)
{
  scene_reset_lights();
  draw();
}

/******************************Public*Routine******************************\
*
* vAutoMotion(void)
*
* // void autoMotionCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  !!! turns on/off the timer?
*           (Re)set the global auto_moves
*
* Warnings:
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vAutoMotion(void)
{
  int i;
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());


#ifdef GLX_MOTIF
  XmToggleButtonCallbackStruct *ptr;

  ptr = (XmToggleButtonCallbackStruct *)call_data;

  auto_motion = ptr->set;
#endif

  auto_motion = auto_motion ? 0 : 1;
  SendMessage(auxGetHWND(), WM_USER, 0L, 0L);

  if (auto_motion) {
    CheckMenuItem(hmenu, IDM_AUTO, MF_BYCOMMAND | MF_CHECKED);

    for (i = 0; i < nlights; i++)
        dtheta[i] = rand(-1, 1);
    last_motion_update = current_time();
  } else {
    CheckMenuItem(hmenu, IDM_AUTO, MF_BYCOMMAND | MF_UNCHECKED);
  }

#ifdef GLX_MOTIF
  if (auto_motion) {
    workproc = XtAppAddWorkProc(app_context, drawWP, NULL);
    for (i = 0; i < nlights; i++) dtheta[i] = rand(-1, 1);
    last_motion_update = current_time();
  } else {
    XtRemoveWorkProc(workproc);
  }
#endif

}


/******************************Public*Routine******************************\
*
* vInit(void)
*
* // void initCB(Widget w)
*
* Effects:
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void vInit(void)
{
  RECT  rect;
  HMENU hmenu;
  HWND  hWnd;
  int   i;

#ifdef GLX_MOTIF
  Arg args[1];
  XVisualInfo *vi;

  XtSetArg(args[0], GLwNvisualInfo, &vi);
  XtGetValues(w, args, 1);
 
  // !!! creating indirect context, make current
  //
  glx_context = glXCreateContext(XtDisplay(w), vi, 0, GL_FALSE);
  GLwDrawingAreaMakeCurrent(w, glx_context);
#endif

#ifdef TESTTEST
  PIXELFORMATDESCRIPTOR pfd;
  HDC                   hDC;
  HGLRC                 hRC;
  INT                   iPixelFormat;

  hDC = auxGetHDC();

  iPixelFormat = GetPixelFormat(hDC);
  DescribePixelFormat(hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

  if ((pfd.dwFlags & PFD_SUPPORT_GDI) == 0) {

    OutputDebugString("PFD_SUPPORT_GDI not supported!\n");

    pfd.dwFlags |= PFD_SUPPORT_GDI;

  }

  if (!SetPixelFormat(hDC, iPixelFormat, &pfd))
    OutputDebugString("PFD_SUPPORT_GDI still not supported!\n");


  //
  // Maynot need this
  //
  hRC = wglCreateContext(hDC);
  if (!wglMakeCurrent(hDC, hRC))
    OutputDebugString("MakeCurrentFailed!\n");
#endif



  scene_init(); 

  //gettimeofday(&starttime, NULL);
  //srand(starttime.tv_usec);

  GetSystemTime(&starttime);
  srand(starttime.wMilliseconds);

  hWnd = auxGetHWND();
  GetClientRect(hWnd, &rect);

  glViewport(0, 0, rect.right, rect.bottom);
  glClear(GL_COLOR_BUFFER_BIT);

  //
  // this is for initizating the menu items
  //
  hmenu = GetMenu(hWnd);

  for (i=0; i < nlights; i++) {
    if (lights[i].on)
      CheckMenuItem(hmenu, IDM_RED+i, MF_BYCOMMAND | MF_CHECKED);
    else
      CheckMenuItem(hmenu, IDM_RED+i, MF_BYCOMMAND | MF_UNCHECKED);
  }

  if (draw_square)
    CheckMenuItem(hmenu, IDM_SQUARE, MF_BYCOMMAND | MF_CHECKED);
  if (draw_shadows)
    CheckMenuItem(hmenu, IDM_SHADOW, MF_BYCOMMAND | MF_CHECKED);
  if (draw_refraction)
    CheckMenuItem(hmenu, IDM_REFRACTION, MF_BYCOMMAND | MF_CHECKED);
  if (draw_lights)
    CheckMenuItem(hmenu, IDM_LIGHTS, MF_BYCOMMAND | MF_CHECKED);
  if (draw_sphere)
    CheckMenuItem(hmenu, IDM_SPHERE, MF_BYCOMMAND | MF_CHECKED);
  if (draw_texture)
    CheckMenuItem(hmenu, IDM_TEXTURE, MF_BYCOMMAND | MF_CHECKED);

  CheckMenuItem(hmenu, IDM_AIR+def_refraction_index, MF_BYCOMMAND | MF_CHECKED);
  CheckMenuItem(hmenu, IDM_10+def_divisions_index, MF_BYCOMMAND | MF_CHECKED);

}

/******************************Public*Routine******************************\
*
* vExpose
*
* // !!! void exposeCB(Widget w)
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void vExpose(int x, int y)
{
  draw();
}

/******************************Public*Routine******************************\
*
* vResize
*
* // void resizeCB(Widget w, XtPointer client_data, XtPointer call)
*
* Effects:  changes globals winx, winy and aspect
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vResize(GLsizei width, GLsizei height)
{
#ifdef GLX_MOTIF
  GLwDrawingAreaCallbackStruct *call_data;
  call_data = (GLwDrawingAreaCallbackStruct *)call;

  GLwDrawingAreaMakeCurrent(w, glx_context);
  winx = call_data->width;
  winy = call_data->height;
#endif

  winx = width;
  winy = height;

  glViewport(0, 0, winx, winy);

  aspect = (GLfloat)winx / (GLfloat)winy;
}

#ifdef GLX_MOTIF
//
// !!! mouse down/up function??
//
void inputCB(Widget w, XtPointer client_data, XtPointer call_data)
{
  int picked;
  GLwDrawingAreaCallbackStruct *call;

  char buffer[5];
  int bufsize = 5;
  KeySym key;
  XComposeStatus compose;

  static int mousex, mousey;
  /* Just to confuse everybody, I've made these go from 0-1. */
  float dmousex, dmousey;
  float r1, r2;

  call = (GLwDrawingAreaCallbackStruct *)call_data;
  
  GLwDrawingAreaMakeCurrent(w, glx_context);
  switch(call->event->type) {
  case ButtonPress:
    button_down = call->event->xbutton.button;
    mousex = call->event->xbutton.x;
    mousey = call->event->xbutton.y;
    picked = scene_pick(mousex, mousey);
    if (picked >= name_lights) name_selected = picked;
    break;
  case ButtonRelease:
    if (quick_moves) 
      scene_move_update(name_selected, button_down == Button2, 
			button_down == Button3, button_down = Button1);
    button_down = 0; 
    break;
  case MotionNotify:
    if (button_down == Button1) {
      /* This is the "default" mouse button - moves things in theta
       * since this is easy and computationally cheap */
      dmousex = (double)(call->event->xmotion.x - mousex) / (double)winx;
      scene_move(name_selected, 0, 0, dmousex, quick_moves ? 0 : 1);
    } else if (button_down == Button2) {
      /* Change the radius - figue out the component of the mouse motion
       * that's going toward the center of the screen */
      mousex = (winx / 2) - mousex;
      mousey = (winy / 2) - mousey;
      r1 = sqrt((float)(mousex*mousex) / (float)(winx*winx) + 
		(float)(mousey*mousey) / (float)(winy*winy));
      mousex = call->event->xmotion.x;
      mousey = call->event->xmotion.y;
      mousex = (winx / 2) - mousex;
      mousey = (winy / 2) - mousey;
      r2 = sqrt((float)(mousex*mousex) / (float)(winx*winx) + 
		(float)(mousey*mousey) / (float)(winy*winy));
      scene_move(name_selected, r2 - r1, 0, 0, quick_moves ? 0 : 1);
    } else if (button_down == Button3) {
      /* Change phi - this is expensive */
      dmousex = (double)(call->event->xmotion.x - mousex) / (double)winx;
      scene_move(name_selected, 0, dmousex, 0, quick_moves ? 0 : 1);
    }
    mousex = call->event->xmotion.x;
    mousey = call->event->xmotion.y;
    break;
  case KeyPress:
    XLookupString(&(call->event->xkey), buffer, bufsize, &key, &compose);
    if (key == XK_Escape) exit(0);
    break;                            
  default:
    break;
  }

  draw();
}
#endif

/******************************Public*Routine******************************\
*
* vDrawAll(void)
*
* //void drawAllCB(Widget w)
*
* Effects:
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vDrawAll(void)
{
  HMENU hmenu;
  int       i;
  static int fAll=0;

  hmenu = GetMenu(auxGetHWND());

  fAll = fAll ? 0 : 1;

  if (fAll) {
    for (i=0; i < 6; i++)
       CheckMenuItem(hmenu, IDM_SQUARE+i, MF_BYCOMMAND | MF_CHECKED);

    CheckMenuItem(hmenu, IDM_ALL, MF_BYCOMMAND | MF_CHECKED);
    draw_square = 1;
    draw_shadows = 1;
    draw_refraction = 1;
    draw_sphere = 1;
    draw_lights = 1;

  } else {
    CheckMenuItem(hmenu, IDM_ALL, MF_BYCOMMAND | MF_UNCHECKED);
  }

  draw();
}

/******************************Public*Routine******************************\
*
* //void drawSomethingCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  functions for auxKeyFunc can't have parameters so we have
*           these similar functions here.
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vDrawSquare(void)
{
#ifdef GLX_MOTIF
  XmToggleButtonCallbackStruct *ptr;
  int *data;
  int i;

  ptr = (XmToggleButtonCallbackStruct *)call_data;
  data = (int *)client_data;
  *data = ptr->set;
#endif
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_square = draw_square ? 0 : 1;
  if (draw_square)
      CheckMenuItem(hmenu, IDM_SQUARE, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_SQUARE, MF_BYCOMMAND | MF_UNCHECKED);

  draw();
}

void CALLBACK vDrawShadow(void)
{
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_shadows = draw_shadows ? 0 : 1;
  if (draw_shadows)
      CheckMenuItem(hmenu, IDM_SHADOW, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_SHADOW, MF_BYCOMMAND | MF_UNCHECKED);
  draw();
}

void CALLBACK vDrawRefraction(void)
{
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_refraction = draw_refraction ? 0 : 1;
  if (draw_refraction)
      CheckMenuItem(hmenu, IDM_REFRACTION, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_REFRACTION, MF_BYCOMMAND | MF_UNCHECKED);
  draw();
}
void CALLBACK vDrawSphere(void)
{
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_sphere = draw_sphere ? 0 : 1;
  if (draw_sphere)
      CheckMenuItem(hmenu, IDM_SPHERE, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_SPHERE, MF_BYCOMMAND | MF_UNCHECKED);
  draw();
}
void CALLBACK vDrawLight(void)
{
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_lights = draw_lights ? 0 : 1;
  if (draw_lights)
      CheckMenuItem(hmenu, IDM_LIGHTS, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_LIGHTS, MF_BYCOMMAND | MF_UNCHECKED);
  draw();
}
void CALLBACK vDrawTexture(void)
{
  HMENU hmenu;

  hmenu = GetMenu(auxGetHWND());

  draw_texture = draw_texture ? 0 : 1;
  if (draw_texture)
      CheckMenuItem(hmenu, IDM_TEXTURE, MF_BYCOMMAND | MF_CHECKED);
  else
      CheckMenuItem(hmenu, IDM_TEXTURE, MF_BYCOMMAND | MF_UNCHECKED);
  draw();
}

void vDrawStuff(int *what)
{
  *what = *what ? 0 : 1;
  draw();
}

/******************************Public*Routine******************************\
*
* //void refractionCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  functions for auxKeyFunc can't have parameters so we have
*           these similar functions here.
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vRefractionAIR(void)
{
#ifdef GLX_MOTIF
  XmToggleButtonCallbackStruct *ptr;
  GLfloat refraction;

  ptr = (XmToggleButtonCallbackStruct *)call_data;
  if (!ptr->set) return;
  refraction = *((GLfloat *)client_data);
#endif

  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+0, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[0].index;
  refraction_change(refraction);
  draw();
}

void CALLBACK vRefractionICE(void)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+1, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[1].index;
  refraction_change(refraction);
  draw();
}

void CALLBACK vRefractionWATER(void)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+2, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[2].index;
  refraction_change(refraction);
  draw();
}

void CALLBACK vRefractionZincGLASS(void)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+3, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[3].index;
  refraction_change(refraction);
  draw();
}
void CALLBACK vRefractionLightGLASS(void)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+4, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[4].index;
  refraction_change(refraction);
  draw();
}
void CALLBACK vRefractionHeavyGLASS(void)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+5, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[5].index;
  refraction_change(refraction);
  draw();
}

void vRefraction(int type)
{
  GLfloat refraction;
  HMENU   hmenu;
  int         i;

  hmenu = GetMenu(auxGetHWND());
  for (i = 0; i < nindices; i++)
    CheckMenuItem(hmenu, IDM_AIR+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_AIR+type, MF_BYCOMMAND | MF_CHECKED);
  refraction = indices[type].index;
  refraction_change(refraction);
  draw();
}

/******************************Public*Routine******************************\
*
* vSubdivision
*
* //void subdivisionCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  functions for auxKeyFunc can't have parameters so we have
*           these similar functions here.
* History:
*  30-Nov-1993
*
\**************************************************************************/

void CALLBACK vSubdivision10(void)
{
#ifdef GLX_MOTIF
  XmToggleButtonCallbackStruct *ptr;
  int subdivisions;

  ptr = (XmToggleButtonCallbackStruct *)call_data;
  if (!ptr->set) return;
  subdivisions = *((int *)client_data);
#endif

  HMENU hmenu;
  int       i;

  hmenu = GetMenu(auxGetHWND());

  for (i = 0; i < npossible_divisions; i++)
    CheckMenuItem(hmenu, IDM_10+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_10, MF_BYCOMMAND | MF_CHECKED);
  divisions_change(possible_divisions[0]);

  draw();
}

void CALLBACK vSubdivision20(void)
{
  HMENU hmenu;
  int       i;

  hmenu = GetMenu(auxGetHWND());

  for (i = 0; i < npossible_divisions; i++)
    CheckMenuItem(hmenu, IDM_10+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_20, MF_BYCOMMAND | MF_CHECKED);
  divisions_change(possible_divisions[1]);

  draw();
}

void CALLBACK vSubdivision30(void)
{
  HMENU hmenu;
  int       i;

  hmenu = GetMenu(auxGetHWND());

  for (i = 0; i < npossible_divisions; i++)
    CheckMenuItem(hmenu, IDM_10+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_30, MF_BYCOMMAND | MF_CHECKED);
  divisions_change(possible_divisions[2]);

  draw();
}

void CALLBACK vSubdivision40(void)
{
  HMENU hmenu;
  int       i;

  hmenu = GetMenu(auxGetHWND());

  for (i = 0; i < npossible_divisions; i++)
    CheckMenuItem(hmenu, IDM_10+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_40, MF_BYCOMMAND | MF_CHECKED);
  divisions_change(possible_divisions[3]);

  draw();
}


void vSubdivision(int which)
{
  HMENU hmenu;
  int       i;

  hmenu = GetMenu(auxGetHWND());

  for (i = 0; i < npossible_divisions; i++)
    CheckMenuItem(hmenu, IDM_10+i, MF_BYCOMMAND | MF_UNCHECKED);

  CheckMenuItem(hmenu, IDM_10+which, MF_BYCOMMAND | MF_CHECKED);

  divisions_change(possible_divisions[which]);
  draw();
}

/******************************Public*Routine******************************\
*
* v[RGB]Light_on
*
* //void light_onCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects:  functions for auxKeyFunc can't have parameters so we have
*           these similar functions here.
* History:
*  30-Nov-1993
*
\**************************************************************************/
#define RED_LIGHT   0
#define GREEN_LIGHT 1
#define BLUE_LIGHT  2

void CALLBACK vRLight_on(void)
{
#ifdef GLX_MOTIF
  XmToggleButtonCallbackStruct *ptr;

  ptr = (XmToggleButtonCallbackStruct *)call_data;
  lights_onoff((light *)client_data - lights, ptr->set);
#endif

  int fOn;
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());

  fOn = lights[RED_LIGHT].on ? 0 : 1;
  if (fOn)
    CheckMenuItem(hmenu, IDM_RED, MF_BYCOMMAND | MF_CHECKED);
  else
    CheckMenuItem(hmenu, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
  lights_onoff(RED_LIGHT, fOn);
  draw();
}

void CALLBACK vGLight_on(void)
{
  int fOn;
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());

  fOn = lights[GREEN_LIGHT].on ? 0 : 1;
  if (fOn)
    CheckMenuItem(hmenu, IDM_GREEN, MF_BYCOMMAND | MF_CHECKED);
  else
    CheckMenuItem(hmenu, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
  lights_onoff(GREEN_LIGHT, fOn);
  draw();
}

void CALLBACK vBLight_on(void)
{
  int fOn;
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());

  fOn = lights[BLUE_LIGHT].on ? 0 : 1;
  if (fOn)
    CheckMenuItem(hmenu, IDM_BLUE, MF_BYCOMMAND | MF_CHECKED);
  else
    CheckMenuItem(hmenu, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
  lights_onoff(BLUE_LIGHT, fOn);
  draw();
}

void vLight_on(int which)
{
  int fOn;
  HMENU   hmenu;

  hmenu = GetMenu(auxGetHWND());

  fOn = lights[which].on ? 0 : 1;

  if (fOn)
    CheckMenuItem(hmenu, IDM_RED+which, MF_BYCOMMAND | MF_CHECKED);
  else
    CheckMenuItem(hmenu, IDM_RED+which, MF_BYCOMMAND | MF_UNCHECKED);

  lights_onoff(which, fOn);
  draw();
}




/******************************Public*Routine******************************\
*
* vExit
*
* //void exitCB(Widget w, XtPointer client_data, XtPointer call_data)
*
* Effects: !!! this is redundant unless we do stuff other than auxQuit
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

void vExit(void)
{
#ifdef GLX_MOTIF
  exit(0);
#endif

    auxQuit();
}

/******************************Public*Routine******************************\
*
* bAutoMotion(void)
*
* // Boolean drawWP(XtPointer data)
*
* Effects:  !!! for WM_TIMER ?
*
* History:
*  30-Nov-1993
*
\**************************************************************************/

GLboolean bAutoMotion(void)
{
  float t, dt;
  int i;

  t = current_time();
  dt = t - last_motion_update;
  dt = (dt < 0) ? -dt : dt;

  if (dt < time_fudge) {

    //wsprintf(text, "dt = %lx\n", dt);
    //OutputDebugString(text);
    return FALSE;
  }

  for (i = 0; i < nlights; i++) {
    scene_move(name_lights + i, 0, 0, dtheta[i] * dt, 1);
  }

  last_motion_update = t;

  draw();
  return FALSE;
}



void CALLBACK vMouseDown(AUX_EVENTREC *event)
{
  int    picked;

  mouse_x = event->data[AUX_MOUSEX];
  mouse_y = event->data[AUX_MOUSEY];

  picked = scene_pick(mouse_x, mouse_y);
  if (picked >= name_lights)
     name_selected = picked;

  return;
}

void CALLBACK vLeftMouseUp(AUX_EVENTREC *event)
{
  if (quick_moves)
    scene_move_update(name_selected, 0,     // dr
		                     0,     // dphi
                                     1);    // dtheta

  return;
}

void CALLBACK vMiddleMouseUp(AUX_EVENTREC *event)
{
  if (quick_moves)
    scene_move_update(name_selected, 1,     // dr
		                     0,     // dphi
                                     0);    // dtheta

  return;
}

void CALLBACK vRightMouseUp(AUX_EVENTREC *event)
{
  if (quick_moves)
    scene_move_update(name_selected, 0,     // dr
		                     1,     // dphi
                                     0);    // dtheta

  return;
}

GLenum MouseMove(int x, int y, GLenum mask)
{
  float dmousex;
  float r1, r2;

  /* This is the "default" mouse button - moves things in theta
   * since this is easy and computationally cheap */
  if (mask & AUX_LEFTBUTTON) {
    dmousex = (float)((double)(x - mouse_x) / (double)winx);
    scene_move(name_selected, 0, 0, dmousex, quick_moves ? 0 : 1);
  } else if (mask & AUX_MIDDLEBUTTON) {
    /* Change the radius - figue out the component of the mouse motion
     * that's going toward the center of the screen */
    mouse_x = (winx / 2) - mouse_x;
    mouse_y = (winy / 2) - mouse_y;
    r1 = (float)sqrt((double)(mouse_x*mouse_x) / (double)(winx*winx) +
	(double)(mouse_y*mouse_y) / (double)(winy*winy));
    mouse_x = x;
    mouse_y = y;
    mouse_x = (winx / 2) - mouse_x;
    mouse_y = (winy / 2) - mouse_y;
    r2 = (float)sqrt((double)(mouse_x*mouse_x) / (double)(winx*winx) +
	(double)(mouse_y*mouse_y) / (double)(winy*winy));
    scene_move(name_selected, r2 - r1, 0, 0, quick_moves ? 0 : 1);
  } else if (mask & AUX_RIGHTBUTTON) {
    /* Change phi - this is expensive */
    dmousex = (float)((double)(x - mouse_x) / (double)winx);
    scene_move(name_selected, 0, dmousex, 0, quick_moves ? 0 : 1);
  }
    mouse_x = x;
    mouse_y = y;

  return GL_TRUE;

}


//
// hack these since cfront generates these...
//
PVOID __nw(unsigned int ui)
{
    return LocalAlloc(LMEM_FIXED, ui);
}


VOID __dl(PVOID pv)
{

    LocalFree(pv);
    return;
}

PVOID __vec_new(void *p, int x, int y, void *q)
{
    return LocalAlloc(LMEM_FIXED, x*y);
}
