#include <X11/Xlib.h>
#include <Xm/XmAll.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <gl.h>
#include <device.h>
#include "globals.h"
#include "states.h"
#include "util.h"
#include "link.h"
#include "render.h"
#include "event.h"
#include "init.h"
#include "lights.h"
#include "menu.h"
#include "geom.h"
#include "geom_menu.h"
#include "render_menu.h"

/* dialogs */
Widget dialog, dialog2;
/* buttons */
Widget quitW, snapshotW, imageW;
/* labels */
Widget labelr, labelg, labelb, labeli;
Widget label_wobble_amp, label_wobble_per;
/* scroll bars */
Widget scrollr, scrollg, scrollb, scrolli;
Widget scroll_wobble_amp, scroll_wobble_per;
/* separators */
Widget sep, sepr, sepg, sepb, sepi;
/* toggles */
Widget shadingW, wireframeW, perspW, stereoW, backfaceW;
Widget zbufferW, alphaW, eyemodeW, bgW;
Widget lightsW, depth_cueW, fogW, smoothW, twosideW;
Widget auto_rotW, auto_wobW, texmapW, envmapW;

/* call back function prototypes */
void TimeoutCB(char *client_data, unsigned long *id);
void ExitCB(Widget w, char *client_data, int call_data);
void LoadBackgroundImageCB(Widget w, char *client_data, int call_data);
void LoadTextureCB(Widget w, char *client_data, int call_data);
void QuitCB(Widget w, char *client_data, int call_data);
void SnapshotCB(Widget w, char *client_data, int call_data);
void ShadingToggleCB(Widget w, char *client_data, int call_data);
void WireframeToggleCB(Widget w, char *client_data, int call_data);
void PerspectiveToggleCB(Widget w, char *client_data, int call_data);
void StereoToggleCB(Widget w, char *client_data, int call_data);
void ZbufferToggleCB(Widget w, char *client_data, int call_data);
void AlphaToggleCB(Widget w, char *client_data, int call_data);
void EyemodeToggleCB(Widget w, char *client_data, int call_data);
void LightToggleCB(Widget w, char *client_data, int call_data);
void DepthCueToggleCB(Widget w, char *client_data, int call_data);
void FogToggleCB(Widget w, char *client_data, int call_data);
void AntiAliasToggleCB(Widget w, char *client_data, int call_data);
void BackfaceCullToggleCB(Widget w, char *client_data, int call_data);
void TwoSidedToggleCB(Widget w, char *client_data, int call_data);
void AutoRotationToggleCB(Widget w, char *client_data, int call_data);
void AutoWobbleToggleCB(Widget w, char *client_data, int call_data);
void TexMapToggleCB(Widget w, char *client_data, int call_data);
void BackgroundToggleCB(Widget w, char *client_data, int call_data);
void ScherkEnvMapToggleCB(Widget w, char *client_data, int call_data);
void BackgroundRedCB(Widget w, char *client_data, int call_data);
void BackgroundGreenCB(Widget w, char *client_data, int call_data);
void BackgroundBlueCB(Widget w, char *client_data, int call_data);
void BackgroundIntensityCB(Widget w, char *client_data, int call_data);
void WobbleAmplitudeCB(Widget w, char *client_data, int call_data);
void WobblePeriodCB(Widget w, char *client_data, int call_data);

/* this is the main if we are in motif mode,
   this sets up the motif menus, bottuns, sliders, etc. and calls
   render on timeout */
void motif_main(int argc, char *argv[])
{
  /*  create  the  root_shell  */
  /* the height of the window needs to be adjusted based on
     the number of sliders/buttons on the geom_menu window */
  MakeRootShell(argc, argv, 500, 600);

  /* create and position the render menu widgets on the main form */
  CurrentForm(0);
  make_render_widgets();
  place_render_widgets();
  /* initialize the geometry variables */
  init_geom_data();
  /* create and position the geometry menu widgets on the form_dialog */
/*  CurrentForm(1);*/
  make_geom_widgets();
  place_geom_widgets();

  /* initially give a large timeout so that there's time
     for the motif window to initialize itself */
  RunMainLoop(500, TimeoutCB);
}

void make_render_widgets()
{
  char s[MAX_STR];

  /* create (but don't manage) the message dialogs */
  dialog = MakeMessageDialog("exit?", ExitCB, "1", ExitCB, "0");
  dialog2 = MakeFileSelectionDialog("file name:", LoadBackgroundImageCB, "1", LoadBackgroundImageCB, "0");

  /* create  a push button to quit */
  quitW = MakeButton("quit", QuitCB, NULL);
  /* create  a push button to fork snapshot */
  snapshotW = MakeButton("snapshot", SnapshotCB, NULL);
  /* create  a push button to load a background image */
  imageW = MakeButton("image", LoadTextureCB, NULL);

  /* create  a  separator between the toggles and the rgb sliders */
  sep = MakeSeparator();

  /* create the toggles to control rendering type */
  shadingW = MakeToggle("shading", ShadingToggleCB, "shading", gstate.shading);
  SetWidgetFont(&shadingW, "*times*12*");

  wireframeW = MakeToggle("wireframe", WireframeToggleCB, "wireframe", gstate.wire_frame);
  SetWidgetFont(&wireframeW, "*times*12*");

  perspW = MakeToggle("perspective", PerspectiveToggleCB, "perspective",  gstate.persp);
  SetWidgetFont(&perspW, "*times*12*");

  stereoW = MakeToggle("stereo", StereoToggleCB, "stereo", gstate.stereo_on);
  SetWidgetFont(&stereoW, "*times*12*");

  zbufferW = MakeToggle("zbuffer", ZbufferToggleCB, "zbuffer", gstate.zbuffer_on);
  SetWidgetFont(&zbufferW, "*times*12*");

  alphaW = MakeToggle("alpha", AlphaToggleCB, "alpha", gstate.alpha_on);
  SetWidgetFont(&alphaW, "*times*12*");

  eyemodeW = MakeToggle("eyemode", EyemodeToggleCB, "eyemode", gstate.eyemode);
  SetWidgetFont(&eyemodeW, "*times*12*");

  lightsW = MakeToggle("lights", LightToggleCB, "lights", gstate.lights_on);
  SetWidgetFont(&lightsW, "*times*12*");

  depth_cueW = MakeToggle("depth_cue", DepthCueToggleCB, "depth_cue", gstate.depth_cue_on);
  SetWidgetFont(&depth_cueW, "*times*12*");

  fogW = MakeToggle("fog", FogToggleCB, "fog", gstate.fog_on);
  SetWidgetFont(&fogW, "*times*12*");

  smoothW = MakeToggle("smooth", AntiAliasToggleCB, "smooth", gstate.smooth_on);
  SetWidgetFont(&smoothW, "*times*12*");

  backfaceW = MakeToggle("backface", BackfaceCullToggleCB, "backface", gstate.backface_on);
  SetWidgetFont(&backfaceW, "*times*12*");

  twosideW = MakeToggle("twoside", TwoSidedToggleCB, "twoside", gstate.twoside);
  SetWidgetFont(&twosideW, "*times*12*");

  auto_rotW = MakeToggle("auto_rot", AutoRotationToggleCB, "auto_rot", gstate.auto_rotate);
  SetWidgetFont(&auto_rotW, "*times*12*");

  auto_wobW = MakeToggle("auto_wob", AutoWobbleToggleCB, "auto_wob", gstate.auto_wobble);
  SetWidgetFont(&auto_wobW, "*times*12*");

  texmapW = MakeToggle("texmap", TexMapToggleCB, "texmap", gstate.texmap);
  SetWidgetFont(&texmapW, "*times*12*");

  bgW = MakeToggle("background", BackgroundToggleCB, "background", gstate.bg_on);
  SetWidgetFont(&bgW, "*times*12*");

  envmapW = MakeToggle("envmap", ScherkEnvMapToggleCB, NULL, gstate.envmap);
  SetWidgetFont(&envmapW, "*times*12*");

  /* 4 rgb (and intensity) sliders to control the background color */
  scrollr = MakeScrollbar(1, BackgroundRedCB, NULL, 0, 255, gstate.bg_r);
  sprintf(s, "%9s = %3d   ", "RED", gstate.bg_r);
  labelr = MakeLabel(s);
  sepr = MakeSeparator();

  scrollg = MakeScrollbar(1, BackgroundGreenCB, NULL, 0, 255, gstate.bg_g);
  sprintf(s, "%9s = %3d   ", "GREEN", gstate.bg_g); 
  labelg = MakeLabel(s);
  sepg = MakeSeparator();

  scrollb = MakeScrollbar(1, BackgroundBlueCB, NULL, 0, 255, gstate.bg_b);
  sprintf(s, "%9s = %3d   ", "BLUE", gstate.bg_b);
  labelb = MakeLabel(s);
  sepb = MakeSeparator();

  scrolli = MakeScrollbar(1, BackgroundIntensityCB, NULL, 0, 255, 0);
  sprintf(s, "%9s = %3d   ", "INTENSITY", 0);
  labeli = MakeLabel(s);
  sepi = MakeSeparator();

  /* wobble scroll bars and labels */
  scroll_wobble_amp = MakeScrollbar(1, WobbleAmplitudeCB, NULL, 0, 90, (int)gstate.wobble_amplitude);
  sprintf(s, "amp.=%.0f", gstate.wobble_amplitude);
  label_wobble_amp = MakeLabel(s);

  scroll_wobble_per = MakeScrollbar(1, WobblePeriodCB, NULL, 1, 50, (int)gstate.wobble_period);
  sprintf(s, "per.=%.0f", gstate.wobble_period);
  label_wobble_per = MakeLabel(s);
}

void place_render_widgets()
{
  /*  attach  the children  to  the form  */
  /* place the buttons */
  WidgetPosition(&quitW,      5, 10, 20,  2);
  WidgetPosition(&snapshotW,  5, 20, 20, 12);
  WidgetPosition(&imageW,    25, 10, 40,  2);

  WidgetPosition(&auto_rotW,  2, 30, 20, 25);
  WidgetPosition(&auto_wobW, 22, 30, 40, 25);

  /* place the toggles in two columns ... */
  /* ... left column */
  WidgetPosition(&eyemodeW,     45,  7, 70,  2);
  WidgetPosition(&lightsW,      45, 12, 70,  7);
  WidgetPosition(&depth_cueW,   45, 17, 70, 12);
  WidgetPosition(&fogW,         45, 22, 70, 17);
  WidgetPosition(&smoothW,      45, 27, 70, 22);
  WidgetPosition(&backfaceW,    45, 32, 70, 27);
  WidgetPosition(&twosideW,     45, 37, 70, 32);
  WidgetPosition(&envmapW,      45, 42, 70, 37);
  /* ... right column */
  WidgetPosition(&shadingW,     75,  7, 100,  2);
  WidgetPosition(&wireframeW,   75, 12, 100,  7);
  WidgetPosition(&perspW,       75, 17, 100, 12);
  WidgetPosition(&stereoW,      75, 22, 100, 17);
  WidgetPosition(&texmapW,      75, 27, 100, 22);
  WidgetPosition(&bgW,          75, 32, 100, 27);
  WidgetPosition(&zbufferW,     75, 37, 100, 32);
  WidgetPosition(&alphaW,       75, 42, 100, 37);

  /* wobble amplitude slider and label */
  WidgetLeftPosition(&scroll_wobble_amp, 2);
  WidgetBottomAttachment(&scroll_wobble_amp, NULL);
  WidgetRightPosition(&scroll_wobble_amp, 30);
  WidgetTopAttachment(&scroll_wobble_amp, &auto_wobW);
  /* label */
  WidgetLeftAttachment(&label_wobble_amp, &scroll_wobble_amp);
  WidgetBottomAttachment(&label_wobble_amp, NULL);
  WidgetRightAttachment(&label_wobble_amp, NULL);
  WidgetTopAttachment(&label_wobble_amp, &auto_wobW);
  
  /* wobble period slider and label */
  WidgetLeftPosition(&scroll_wobble_per, 2);
  WidgetBottomAttachment(&scroll_wobble_per, NULL);
  WidgetRightPosition(&scroll_wobble_per, 30);
  WidgetTopAttachment(&scroll_wobble_per, &scroll_wobble_amp);
  /* label */
  WidgetLeftAttachment(&label_wobble_per, &scroll_wobble_per);
  WidgetBottomAttachment(&label_wobble_per, NULL);
  WidgetRightAttachment(&label_wobble_per, NULL);
  WidgetTopAttachment(&label_wobble_per, &label_wobble_amp);
  
  /* button separator */
  WidgetLeftAttachedToForm(&sep);
  WidgetBottomAttachment(&sep, NULL);
  WidgetRightAttachedToForm(&sep);
  WidgetTopAttachment(&sep, &envmapW);

  /* red bar */
  WidgetLeftPosition(&scrollr, 10);
  WidgetBottomAttachment(&scrollr, NULL);
  WidgetRightPosition(&scrollr, 60);
  WidgetTopAttachment(&scrollr, &sep);

  /* red label */
  WidgetLeftPosition(&labelr, 60);
  WidgetBottomAttachment(&labelr, NULL);
  WidgetRightPosition(&labelr, 90);
  WidgetTopAttachment(&labelr, &sep);

  /* red separator */
  WidgetLeftAttachedToForm(&sepr);
  WidgetBottomAttachment(&sepr, NULL);
  WidgetRightAttachedToForm(&sepr);
  WidgetTopAttachment(&sepr, &labelr);

  /* green bar */
  WidgetLeftPosition(&scrollg, 10);
  WidgetBottomAttachment(&scrollg, NULL);
  WidgetRightPosition(&scrollg, 60);
  WidgetTopAttachment(&scrollg, &sepr);

  /* green label */
  WidgetLeftPosition(&labelg, 60);
  WidgetBottomAttachment(&labelg, NULL);
  WidgetRightPosition(&labelg, 90);
  WidgetTopAttachment(&labelg, &sepr);

  /* green separator */
  WidgetLeftAttachedToForm(&sepg);
  WidgetBottomAttachment(&sepg, NULL);
  WidgetRightAttachedToForm(&sepg);
  WidgetTopAttachment(&sepg, &labelg);

  /* blue bar */
  WidgetLeftPosition(&scrollb, 10);
  WidgetBottomAttachment(&scrollb, NULL);
  WidgetRightPosition(&scrollb, 60);
  WidgetTopAttachment(&scrollb, &sepg);

  /* blue label */
  WidgetLeftPosition(&labelb, 60);
  WidgetBottomAttachment(&labelb, NULL);
  WidgetRightPosition(&labelb, 90);
  WidgetTopAttachment(&labelb, &sepg);

  /* blue separator */
  WidgetLeftAttachedToForm(&sepb);
  WidgetBottomAttachment(&sepb, NULL);
  WidgetRightAttachedToForm(&sepb);
  WidgetTopAttachment(&sepb, &labelb);

  /* intenisty bar */
  WidgetLeftPosition(&scrolli, 10);
  WidgetBottomAttachment(&scrolli, NULL);
  WidgetRightPosition(&scrolli, 60);
  WidgetTopAttachment(&scrolli, &sepb);

  /* intensity label */
  WidgetLeftPosition(&labeli, 60);
  WidgetBottomAttachment(&labeli, NULL);
  WidgetRightPosition(&labeli, 90);
  WidgetTopAttachment(&labeli, &sepb);

  /* intensity separator */
  WidgetLeftAttachedToForm(&sepi);
  WidgetBottomAttachment(&sepi, NULL);
  WidgetRightAttachedToForm(&sepi);
  WidgetTopAttachment(&sepi, &labeli);
}

/* ALL CALL BACK FUNCTIONS GO HERE */
/* callback for the timeouts */
/* this is called for every timeout */
void TimeoutCB(char *client_data, unsigned long *id)
{
  XRectangle rect;
  Device mdev[2] = {MOUSEX, MOUSEY};
  short mpos[2];
  int resx, resy;

  /* handles the user events if any */
  if (qtest())
    {
      handle_events(&gevents, &gstate);
    }

  /* applies the user events */
  handle_event_changes(&gevents, &gstate);

  /* call a timeout again */
  AddTimeOut(gstate.timeout, TimeoutCB);

  /* leave a small timeout if on the motif window so
     that the widgets get refreshed */
  if (gevents.cursor_on_main)
    {
      gstate.timeout = 0;
    }
  else
    {
      if (GetDisplayRect(&rect))
	{
	  getdev(2, mdev, mpos);
	  GetResolution(&resx, &resy);
	  /* check to see if the mouse is outside of the motif window
	     note that the motif window's origin is its top-left corner,
	     not its bottom-left corner, so I'll convert my mouse
	     device coordinates for this check to the motif window's */
	  mpos[Y] = resy - mpos[Y];
	  if (mpos[X] < rect.x || mpos[X] > rect.x+rect.width || mpos[Y] < rect.y || mpos[Y] > rect.y+rect.height)
	    {
	      /* if we're leaving the menu window, create the new display list */
	      if (gevents.cursor_on_menu)
		{
		  gstate.num_polygons = make_display_list(CurrObj, geometry_display_list);
		}
	      gevents.cursor_on_menu = 0;
	      gstate.timeout = 0;
	    }
	  else
	    {
	      gevents.cursor_on_menu = 1;
	      gstate.timeout = 10;
	    }
	}
      else
	{
	  gstate.timeout = 10;
	}
    }
}

void ExitCB(Widget w, char *client_data, int call_data)
{
  if (client_data[0] == '1')
    {
      gexit();
      exit(0);
    }

  /* make the dialog box invisible */
  UNMANAGE(w);
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void LoadBackgroundImageCB(Widget w, char *client_data, int call_data)
{
  char *s;
  XmSelectionBoxCallbackStruct *callback;

  callback = (XmSelectionBoxCallbackStruct *)call_data;

  if (client_data[0] == '1')
    {
      XmStringGetLtoR(callback->value, *GetCharSet(), &s);

      strcpy(gstate.bg_file, s);
      gstate.bg_data = longimagedata(gstate.bg_file);
      sizeofimage(gstate.bg_file, &gstate.bg_size[X], &gstate.bg_size[Y]);
      rectzoom((float)(gstate.sizeview[X])/(float)gstate.bg_size[X],
	       (float)(gstate.sizeview[Y])/(float)gstate.bg_size[Y]);
      XtFree(s);
    }

  /* make the dialog box invisible */
  UNMANAGE(w);
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void LoadTextureCB(Widget w, char *client_data, int call_data)
{
  Widget list;
  XmString xs;
  link_handle l;
  char buf[1024];

  link_open(&l, "ls", "-F");

  list = (Widget)XmSelectionBoxGetChild(dialog2, XmDIALOG_LIST);
  XmListDeleteAllItems(list);

  while(!link_read(&l, buf))
    {
      xs = XmStringCreateLtoR(buf, *GetCharSet());
      if (strcmp(&buf[strlen(buf)-4], ".rgb") == 0)
	XmListAddItem(list, xs, 0);
      XmStringFree(xs);
    }
  link_close(&l);

  /* make the dialog box for background image loading visible */
  MANAGE(dialog2);

  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void QuitCB(Widget w, char *client_data, int call_data)
{
  /* make the dialog box visible */
  MANAGE(dialog);
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void SnapshotCB(Widget w, char *client_data, int call_data)
{
  int snap_id;
  
  if ((snap_id = fork()) == -1)
    {
      fprintf(stderr, "Fatal Error: fork failed!\n");
      exit(-1);
    }
  if (snap_id == 0)
    {
      execl("/usr/sbin/snapshot", "snapshot", NULL);
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void ShadingToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);

  gstate.shading = set ? 1 : 0;
  shademodel(gstate.shading ? GOURAUD : FLAT);
  if (isobj((long)CurrObj))
    {
      editobj((long)CurrObj);
      closeobj();
    }
  gevents.redraw = 1;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void WireframeToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.wire_frame = set ? 1 : 0;

  polymode(gstate.wire_frame ? PYM_LINE : PYM_FILL);
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void PerspectiveToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.persp = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void StereoToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);

  if (set)
    {
      gstate.stereo_on = 1;
      gstate.num_polygons = (gstate.num_polygons)<<1;
    }
  else
    {
      gstate.stereo_on = 0;
      gstate.num_polygons = (gstate.num_polygons)>>1;
    }
  if (gstate.stereo_on)
    {
      rectzoom((float)(gstate.sizeview[X])/(float)gstate.bg_size[X],
	       (float)gstate.sizeview[Y]/(float)gstate.bg_size[Y]);
      prefsize(gstate.sizeview[X]<<1, gstate.sizeview[Y]);
    }
  else
    {
      rectzoom((float)(gstate.sizeview[X]>>1)/(float)gstate.bg_size[X],
	       (float)gstate.sizeview[Y]/(float)gstate.bg_size[Y]);
      prefsize(gstate.sizeview[X]>>1, gstate.sizeview[Y]);
    }
  winconstraints(); /* to set the new window size */
  winconstraints(); /* to allow manual resizing later */
  win_stat(gstate.winview, gstate.orgview, gstate.sizeview);
  gevents.redraw = 1;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void ZbufferToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.zbuffer_on = set ? 1 : 0;

  zbuffer(gstate.zbuffer_on);
  if (isobj((long)CurrObj))
    {
      editobj((long)CurrObj);
      closeobj();
    }
  gevents.redraw = 1;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void AlphaToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.alpha_on = 1;
      blendfunction(BF_SA, BF_MSA);
    }
  else
    {
      gstate.alpha_on = 0;
      blendfunction(BF_ONE, BF_ZERO);
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void EyemodeToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.eyemode = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void LightToggleCB(Widget w, char *client_data, int call_data)
{
  int i;
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.lights_on = 1;
      lmbind(LMODEL, 1);
      init_lights();
    }
  else
    {
      gstate.lights_on = 0;
      lmbind(LMODEL, 0);
      for (i=0; i<(gstate.num_lights); i++)
	{
	  lmbind(LIGHT0+i, 0);
	}
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void DepthCueToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.depth_cue_on = 1;
      /* reset the fog */
      gstate.fog_on = 0;
      XtSetArg(args[0], XmNset, 0);
      XtSetValues(fogW, args, 1);
      define_fog(0.0, 0.0, 25.0, 0.01, 0.01, 0.01);
      fogvertex(FG_ON, NULL);
      /*depthcue(TRUE);*/
    }
  else
    {
      gstate.depth_cue_on = 0;
      fogvertex(FG_OFF, NULL);
      /*depthcue(FALSE);*/
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void FogToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.fog_on = 1;
      /* reset the depth cue */
      gstate.depth_cue_on = 0;
      XtSetArg(args[0], XmNset, 0);
      XtSetValues(depth_cueW, args, 1);
      define_fog(0.0, 0.0, 25.0, 0.4, 0.4, 0.4);
      fogvertex(FG_ON, NULL);
    }
  else
    {
      gstate.fog_on = 0;
      fogvertex(FG_OFF, NULL);
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void AntiAliasToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.smooth_on = 1;
      subpixel(TRUE);
      pntsmooth(SMP_ON);
      linesmooth(SML_ON);
      polysmooth(PYSM_ON);
    }
  else
    {
      gstate.smooth_on = 0;
      subpixel(FALSE);
      pntsmooth(SMP_OFF);
      linesmooth(SML_OFF);
      polysmooth(PYSM_OFF);
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void BackfaceCullToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.backface_on = set ? 1 : 0;

  backface(gstate.backface_on);
  if (isobj((long)CurrObj))
    {
      editobj((long)CurrObj);
      closeobj();
    }
  gevents.redraw = 1;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void TwoSidedToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.twoside = set ? 1 : 0;

  init_lights();
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void AutoRotationToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.auto_rotate = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void AutoWobbleToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  if (set)
    {
      gstate.auto_wobble = 1;
      /* reset the initial wobble_angle to the current angle */
      gstate.init_wobble_angle = gstate.wobble_amplitude*sin(elapsed_time(&gstate.run_time)/gstate.wobble_period);
    }
  else
    {
      gstate.auto_wobble = 0;
    }
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void TexMapToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.texmap = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void BackgroundToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.bg_on = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void ScherkEnvMapToggleCB(Widget w, char *client_data, int call_data)
{
  Arg args[1];
  Boolean set;

  XtSetArg(args[0], XmNset, &set);
  XtGetValues(w, args, 1);
  gstate.envmap = set ? 1 : 0;
  gstate.timeout = SHORT_TIMEOUT_DELAY;
}

void BackgroundRedCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];

  gstate.bg_r = ((XmScrollBarCallbackStruct *)call_data)->value;
  sprintf(s, "%9s = %3d   ", "RED", gstate.bg_r);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelr, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}

void BackgroundGreenCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];

  gstate.bg_g = ((XmScrollBarCallbackStruct *)call_data)->value;
  sprintf(s, "%9s = %3d   ", "GREEN", gstate.bg_g);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelg, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}

void BackgroundBlueCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];

  gstate.bg_b = ((XmScrollBarCallbackStruct *)call_data)->value;
  sprintf(s, "%9s = %3d   ", "BLUE", gstate.bg_b);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelb, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}

void BackgroundIntensityCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];
  int di;

  di = ((XmScrollBarCallbackStruct *)call_data)->value - gstate.intensity;
  gstate.intensity = ((XmScrollBarCallbackStruct *)call_data)->value;

  sprintf(s, "%9s = %3d   ", "INTENSITY", gstate.intensity);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labeli, args, 1);

  gstate.bg_r = max(0, min(255, gstate.bg_r+di));
  XtVaSetValues(scrollr, XmNvalue, gstate.bg_r, 0);
  sprintf(s, "%9s = %3d   ", "RED", gstate.bg_r);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelr, args, 1);

  gstate.bg_g = max(0, min(255, gstate.bg_g+di));
  XtVaSetValues(scrollg, XmNvalue, gstate.bg_g, 0);
  sprintf(s, "%9s = %3d   ", "GREEN", gstate.bg_g);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelg, args, 1);

  gstate.bg_b = max(0, min(255, gstate.bg_b+di));
  XtVaSetValues(scrollb, XmNvalue, gstate.bg_b, 0);
  sprintf(s, "%9s = %3d   ", "BLUE", gstate.bg_b);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(labelb, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}

void WobbleAmplitudeCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];

  gstate.wobble_amplitude = (float)((XmScrollBarCallbackStruct *)call_data)->value;
  sprintf(s, "amp.=%.0f", gstate.wobble_amplitude);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(label_wobble_amp, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}

void WobblePeriodCB(Widget w, char *client_data, int call_data)
{
  char s[256];
  Arg args[1];

  gstate.wobble_period = (float)((XmScrollBarCallbackStruct *)call_data)->value;
  sprintf(s, "per.=%.0f", gstate.wobble_period);
  XtSetArg(args[0], XmNlabelString, XmStringCreate(s, *GetCharSet()));
  XtSetValues(label_wobble_per, args, 1);
  gstate.timeout = TIMEOUT_DELAY;
}