\documentclass{article}
\usepackage{axiom}
\begin{document}
\title{\$SPAD/src/graph/view3D process3d.c}
\author{The Axiom Team}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{License}
<<license>>=
/*
Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    - Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the
      distribution.

    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@
<<*>>=
<<license>>

#define _PROCESS3D_C
#include "axiom-c-macros.h"
#include "useproto.h"

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>


#include "header.h"
#include "cpanel.h"
#include "volume.h"
#include "mode.h"
#include "process.h"
#include "draw.h"
#include "com.h"


#include "util.H1"
#include "Gfun.H1"
#include "pixmap.H1"
#include "XShade.H1"
#include "XSpadFill.H1"
#include "all_3d.H1"

#define inside(A,B) (((XButtonEvent *)event)->x >= A && \
		     ((XButtonEvent *)event)->x <= B)


void
#ifdef _NO_PROTO
buttonAction (bKey)
int bKey;
#else
buttonAction (int bKey)
#endif
{

  char *s1, *s2;
  int strL, strL1, strL2, offShade=14;

  /* Button colors which are offColor, RED, are turned off, and those which
     are onColor, GREEN, indicate the mode is in effect. */

  switch (bKey) {

  case hideControl:
    if (viewport->haveControl) {
      viewport->haveControl = no;
      XUnmapWindow(dsply,control->controlWindow);
    }
    break;

  case region3D:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    if (viewport->regionOn) {
      viewport->regionOn = no;
      (control->buttonQueue[region3D]).textColor = offColor;
      viewData.box = 0;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		   (control->buttonQueue[region3D]).buttonX,
		   (control->buttonQueue[region3D]).buttonY,
		   (control->buttonQueue[region3D]).buttonWidth,
		   (control->buttonQueue[region3D]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[region3D]).buttonX,
		       (control->buttonQueue[region3D]).buttonY,
		       (control->buttonQueue[region3D]).buttonWidth,
		       (control->buttonQueue[region3D]).buttonHeight,Xoption);
      }
    } else {  /* inverted color for region off */
      viewport->regionOn = yes;
      viewData.box = 1;
      (control->buttonQueue[region3D]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[region3D]).buttonX,
		   (control->buttonQueue[region3D]).buttonY,
		   (control->buttonQueue[region3D]).buttonWidth,
		   (control->buttonQueue[region3D]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[region3D]).buttonX,
		       (control->buttonQueue[region3D]).buttonY,
		       (control->buttonQueue[region3D]).buttonWidth,
		       (control->buttonQueue[region3D]).buttonHeight,Xoption);
      }
    }

    s = (control->buttonQueue[region3D]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[region3D]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[region3D]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[region3D]).buttonWidth),
		     (control->buttonQueue[region3D]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[region3D]).buttonHeight),
		     s,strL,Xoption);
    redoSmooth = yes;
    drawViewport(Xoption);
    break;



  case bwColor:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    if (!mono) {
      if (viewport->monoOn) {
	viewport->monoOn = no;
	if (viewport->hueTop == viewport->hueOffset) redoColor = yes;
	else redoDither = yes;
	(control->buttonQueue[bwColor]).textColor = offColor;
	(control->buttonQueue[bwColor]).text = "BW";
      } else {
	viewport->monoOn = yes;
	maxGreyShade = XInitShades(dsply,scrn);
	if (viewport->hueTop == viewport->hueOffset) redoColor = yes;
	else redoDither = yes;
	(control->buttonQueue[bwColor]).textColor = onColor;
	(control->buttonQueue[bwColor]).text = "BW";
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[bwColor]).buttonX,
		   (control->buttonQueue[bwColor]).buttonY,
		   (control->buttonQueue[bwColor]).buttonWidth,
		   (control->buttonQueue[bwColor]).buttonHeight);
	GSetForeground(globalGC1,(float)monoColor(buttonColor),Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[bwColor]).buttonX,
		       (control->buttonQueue[bwColor]).buttonY,
		       (control->buttonQueue[bwColor]).buttonWidth,
		       (control->buttonQueue[bwColor]).buttonHeight,Xoption);
      }

      s = (control->buttonQueue[bwColor]).text;
      strL = strlen(s);

      GSetForeground(processGC,
	     (float)monoColor((control->buttonQueue[bwColor]).textColor),Xoption);
      GDrawImageString(processGC,control->controlWindow,
		       (control->buttonQueue[bwColor]).buttonX +
		       centerX(processGC,s,strL,
			       (control->buttonQueue[bwColor]).buttonWidth),
		       (control->buttonQueue[bwColor]).buttonY +
		       centerY(processGC,
			       (control->buttonQueue[bwColor]).buttonHeight),
		       s,strL,Xoption);
      drawColorMap();
      redoSmooth = yes;
      writeTitle();
      drawViewport(Xoption);
    }
    break;



  case outlineOnOff:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    if (viewData.outlineRenderOn) {
      viewData.outlineRenderOn = 0;
      (control->buttonQueue[outlineOnOff]).textColor = offColor;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		 (control->buttonQueue[outlineOnOff]).buttonX,
		 (control->buttonQueue[outlineOnOff]).buttonY,
		 (control->buttonQueue[outlineOnOff]).buttonWidth,
		 (control->buttonQueue[outlineOnOff]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[outlineOnOff]).buttonX,
		       (control->buttonQueue[outlineOnOff]).buttonY,
		       (control->buttonQueue[outlineOnOff]).buttonWidth,
		       (control->buttonQueue[outlineOnOff]).buttonHeight,Xoption);
      }
    } else {
      viewData.outlineRenderOn = 1;
      (control->buttonQueue[outlineOnOff]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		 (control->buttonQueue[outlineOnOff]).buttonX,
		 (control->buttonQueue[outlineOnOff]).buttonY,
		 (control->buttonQueue[outlineOnOff]).buttonWidth,
		 (control->buttonQueue[outlineOnOff]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[outlineOnOff]).buttonX,
		       (control->buttonQueue[outlineOnOff]).buttonY,
		       (control->buttonQueue[outlineOnOff]).buttonWidth,
		       (control->buttonQueue[outlineOnOff]).buttonHeight,Xoption);
      }
    }
    s = (control->buttonQueue[outlineOnOff]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[outlineOnOff]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[outlineOnOff]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[outlineOnOff]).buttonWidth),
		     (control->buttonQueue[outlineOnOff]).buttonY +
		     centerY(processGC,
		     (control->buttonQueue[outlineOnOff]).buttonHeight),
		     s,strL,Xoption);
    if (viewData.style == render) {
      drawViewport(Xoption);
    }
    break;


  case lighting:
    if (saveFlag) {
      doingPanel = CONTROLpanel;
      XUnmapWindow(dsply,saveWindow);
    }
    doingPanel = LIGHTpanel;
    tempLightPointer[0] = viewport->lightVector[0];
    tempLightPointer[1] = viewport->lightVector[1];
    tempLightPointer[2] = viewport->lightVector[2];
    tempLightIntensity = lightIntensity;
    XMapWindow(dsply,lightingWindow);
    break;


  case viewVolume:
    if (saveFlag) {
      doingPanel = CONTROLpanel;
      XUnmapWindow(dsply,saveWindow);
    }
    doingPanel = VOLUMEpanel;
    XMapWindow(dsply,volumeWindow);
    redrawView = yes;
    drawViewport(Xoption);	/* draw it with doingVolume set to yes */
    break;


  case volumeReturn:
    doingPanel = CONTROLpanel;
    redoSmooth = yes;
    redrawView = yes;
    XUnmapWindow(dsply,volumeWindow);
    break;


  case volumeAbort:
    doingPanel = CONTROLpanel;
    redrawView = yes;
    XUnmapWindow(dsply,volumeWindow);
    break;


  case lightReturn:
    doingPanel = CONTROLpanel;
    viewport->lightVector[0] = lightPointer[0] = tempLightPointer[0];
    viewport->lightVector[1] = lightPointer[1] = tempLightPointer[1];
    viewport->lightVector[2] = lightPointer[2] = tempLightPointer[2];
    lightIntensity = tempLightIntensity;
    normalizeVector(viewport->lightVector);
    redrawView = ((viewData.style == render) || (viewData.style == smooth));
    if (movingLight || changedIntensity) redoSmooth = yes;
    XUnmapWindow(dsply,lightingWindow);
    break;


  case lightAbort:
    movingLight = no;  changedIntensity = no;
    doingPanel = CONTROLpanel;
    XUnmapWindow(dsply,lightingWindow);
    break;


  case resetView:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    viewport->axesOn	   = yes;
    viewport->regionOn	   = no;  viewData.box = 0;
    viewData.outlineRenderOn = 0;
    viewport->monoOn	   = no;
    viewport->zoomXOn	   = viewport->zoomYOn = viewport->zoomZOn = yes;
    viewport->originrOn	   = yes;  viewport->objectrOn	  = no;
    viewport->originFlag   = no;
    viewport->xyOn	   = viewport->xzOn = viewport->yzOn = no;
    viewport->lightVector[0] = -0.5;
    viewport->lightVector[1] = 0.5;
    viewport->lightVector[2] = 0.5;
    viewport->translucency   = viewData.translucency;
    viewport->deltaX	   = viewport->deltaX0;
    viewport->deltaY	   = viewport->deltaY0;
    viewport->deltaY	   = viewport->deltaZ0;
    viewport->scale	   = viewport->scale0;
    viewport->scaleX	   = viewport->scaleY = viewport->scaleZ = 1.0;
    if (!equal(viewport->theta,viewport->theta0) || !equal(viewport->phi,viewport->phi0))
      rotated = yes;
    viewport->theta = viewport->axestheta = viewport->theta0 = viewData.theta;
    viewport->phi   = viewport->axesphi	  = viewport->phi0   = viewData.phi;
    viewport->thetaObj = 0.0;
    viewport->phiObj   = 0.0;
    redoSmooth = yes;
    drawViewport(Xoption);
    if (viewport->haveControl) drawControlPanel();
    writeTitle();
    break;


  case axesOnOff:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    if (viewport->axesOn) {
      viewport->axesOn = no;
      (control->buttonQueue[axesOnOff]).textColor = offColor;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		   (control->buttonQueue[axesOnOff]).buttonX,
		   (control->buttonQueue[axesOnOff]).buttonY,
		   (control->buttonQueue[axesOnOff]).buttonWidth,
		   (control->buttonQueue[axesOnOff]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[axesOnOff]).buttonX,
		       (control->buttonQueue[axesOnOff]).buttonY,
		       (control->buttonQueue[axesOnOff]).buttonWidth,
		       (control->buttonQueue[axesOnOff]).buttonHeight,Xoption);
      }
    } else {   /* draw invert-color button */
      viewport->axesOn = yes;
      (control->buttonQueue[axesOnOff]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[axesOnOff]).buttonX,
		   (control->buttonQueue[axesOnOff]).buttonY,
		   (control->buttonQueue[axesOnOff]).buttonWidth,
		   (control->buttonQueue[axesOnOff]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[axesOnOff]).buttonX,
		       (control->buttonQueue[axesOnOff]).buttonY,
		       (control->buttonQueue[axesOnOff]).buttonWidth,
		       (control->buttonQueue[axesOnOff]).buttonHeight,Xoption);
      }
    }

    s = (control->buttonQueue[axesOnOff]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[axesOnOff]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[axesOnOff]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[axesOnOff]).buttonWidth),
		     (control->buttonQueue[axesOnOff]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[axesOnOff]).buttonHeight),
		     s,strL,Xoption);
    if (viewData.style == smooth) {
      if (multiColorFlag) redoDither = yes;
      else redoColor = yes;
    }
    drawViewport(Xoption);
    break;


  case zoomx:
    if (viewport->zoomXOn) {
      viewport->zoomXOn = no;
      (control->buttonQueue[zoomx]).textColor = offColor;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		   (control->buttonQueue[zoomx]).buttonX,
		   (control->buttonQueue[zoomx]).buttonY,
		   (control->buttonQueue[zoomx]).buttonWidth,
		   (control->buttonQueue[zoomx]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomx]).buttonX,
		       (control->buttonQueue[zoomx]).buttonY,
		       (control->buttonQueue[zoomx]).buttonWidth,
		       (control->buttonQueue[zoomx]).buttonHeight,Xoption);
      }
    } else {
      viewport->zoomXOn = yes;
      (control->buttonQueue[zoomx]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[zoomx]).buttonX,
		   (control->buttonQueue[zoomx]).buttonY,
		   (control->buttonQueue[zoomx]).buttonWidth,
		   (control->buttonQueue[zoomx]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomx]).buttonX,
		       (control->buttonQueue[zoomx]).buttonY,
		       (control->buttonQueue[zoomx]).buttonWidth,
		       (control->buttonQueue[zoomx]).buttonHeight,Xoption);
      }
    }

    s = (control->buttonQueue[zoomx]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[zoomx]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[zoomx]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[zoomx]).buttonWidth),
		     (control->buttonQueue[zoomx]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[zoomx]).buttonHeight),
		     s,strL,Xoption);
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    break;


  case zoomy:
    if (viewport->zoomYOn) {
      viewport->zoomYOn = no;
      (control->buttonQueue[zoomy]).textColor = offColor;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		   (control->buttonQueue[zoomy]).buttonX,
		   (control->buttonQueue[zoomy]).buttonY,
		   (control->buttonQueue[zoomy]).buttonWidth,
		   (control->buttonQueue[zoomy]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomy]).buttonX,
		       (control->buttonQueue[zoomy]).buttonY,
		       (control->buttonQueue[zoomy]).buttonWidth,
		       (control->buttonQueue[zoomy]).buttonHeight,Xoption);
      }
    } else {
      viewport->zoomYOn = yes;
      (control->buttonQueue[zoomy]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[zoomy]).buttonX,
		   (control->buttonQueue[zoomy]).buttonY,
		   (control->buttonQueue[zoomy]).buttonWidth,
		   (control->buttonQueue[zoomy]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomy]).buttonX,
		       (control->buttonQueue[zoomy]).buttonY,
		       (control->buttonQueue[zoomy]).buttonWidth,
		       (control->buttonQueue[zoomy]).buttonHeight,Xoption);
      }
    }

    s = (control->buttonQueue[zoomy]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[zoomy]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[zoomy]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[zoomy]).buttonWidth),
		     (control->buttonQueue[zoomy]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[zoomy]).buttonHeight),
		     s,strL,Xoption);
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    break;


  case zoomz:
    if (viewport->zoomZOn) {
      viewport->zoomZOn = no;
      (control->buttonQueue[zoomz]).textColor = offColor;
      if (mono) {
	XChangeShade(dsply,offShade);
	XShadeRectangle(dsply,control->controlWindow,
		   (control->buttonQueue[zoomz]).buttonX,
		   (control->buttonQueue[zoomz]).buttonY,
		   (control->buttonQueue[zoomz]).buttonWidth,
		   (control->buttonQueue[zoomz]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomz]).buttonX,
		       (control->buttonQueue[zoomz]).buttonY,
		       (control->buttonQueue[zoomz]).buttonWidth,
		       (control->buttonQueue[zoomz]).buttonHeight,Xoption);
      }
    } else {
      viewport->zoomZOn = yes;
      (control->buttonQueue[zoomz]).textColor = onColor;
      if (mono) {
	GSetForeground(globalGC1,(float)backgroundColor,Xoption);
	XFillRectangle(dsply, control->controlWindow, globalGC1,
		   (control->buttonQueue[zoomz]).buttonX,
		   (control->buttonQueue[zoomz]).buttonY,
		   (control->buttonQueue[zoomz]).buttonWidth,
		   (control->buttonQueue[zoomz]).buttonHeight);
	GSetForeground(globalGC1,(float)foregroundColor,Xoption);
	GDrawRectangle(globalGC1, control->controlWindow,
		       (control->buttonQueue[zoomz]).buttonX,
		       (control->buttonQueue[zoomz]).buttonY,
		       (control->buttonQueue[zoomz]).buttonWidth,
		       (control->buttonQueue[zoomz]).buttonHeight,Xoption);
      }
    }

    s = (control->buttonQueue[zoomz]).text;
    strL = strlen(s);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[zoomz]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[zoomz]).buttonX +
		     centerX(processGC,s,strL,
			     (control->buttonQueue[zoomz]).buttonWidth),
		     (control->buttonQueue[zoomz]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[zoomz]).buttonHeight),
		     s,strL,Xoption);
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    break;


  case originr:
    viewport->originrOn = yes;
    (control->buttonQueue[originr]).textColor = onColor;
    viewport->objectrOn = no;
    (control->buttonQueue[objectr]).textColor = offColor;
    viewport->originFlag = yes;
    if (mono) {
      XChangeShade(dsply,offShade);
      XShadeRectangle(dsply,control->controlWindow,
		 (control->buttonQueue[objectr]).buttonX,
		 (control->buttonQueue[objectr]).buttonY,
		 (control->buttonQueue[objectr]).buttonWidth,
		 (control->buttonQueue[objectr]).buttonHeight);
      GSetForeground(globalGC1,(float)foregroundColor,Xoption);
      GDrawRectangle(globalGC1, control->controlWindow,
		     (control->buttonQueue[objectr]).buttonX,
		     (control->buttonQueue[objectr]).buttonY,
		     (control->buttonQueue[objectr]).buttonWidth,
		     (control->buttonQueue[objectr]).buttonHeight,Xoption);
      GSetForeground(globalGC1,(float)backgroundColor,Xoption);
      XFillRectangle(dsply, control->controlWindow, globalGC1,
		 (control->buttonQueue[originr]).buttonX,
		 (control->buttonQueue[originr]).buttonY,
		 (control->buttonQueue[originr]).buttonWidth,
		 (control->buttonQueue[originr]).buttonHeight);
      GSetForeground(globalGC1,(float)foregroundColor,Xoption);
      GDrawRectangle(globalGC1, control->controlWindow,
		     (control->buttonQueue[originr]).buttonX,
		     (control->buttonQueue[originr]).buttonY,
		     (control->buttonQueue[originr]).buttonWidth,
		     (control->buttonQueue[originr]).buttonHeight,Xoption);
    }
    s1 = (control->buttonQueue[objectr]).text;
    strL1 = strlen(s1);
    s2 = (control->buttonQueue[originr]).text;
    strL2 = strlen(s2);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[objectr]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[objectr]).buttonX +
		     centerX(processGC,s1,strL1,
			     (control->buttonQueue[objectr]).buttonWidth),
		     (control->buttonQueue[objectr]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[objectr]).buttonHeight),
		     s1,strL1,Xoption);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[originr]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[originr]).buttonX +
		     centerX(processGC,s2,strL2,
			     (control->buttonQueue[originr]).buttonWidth),
		     (control->buttonQueue[originr]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[originr]).buttonHeight),
		     s2,strL2,Xoption);
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    break;



  case objectr:
    viewport->objectrOn = yes;
    (control->buttonQueue[objectr]).textColor = onColor;
    viewport->originrOn = no;
    (control->buttonQueue[originr]).textColor = offColor;

    viewport->originFlag = no;
    if (mono) {
      XChangeShade(dsply,offShade);
      XShadeRectangle(dsply,control->controlWindow,
		 (control->buttonQueue[originr]).buttonX,
		 (control->buttonQueue[originr]).buttonY,
		 (control->buttonQueue[originr]).buttonWidth,
		 (control->buttonQueue[originr]).buttonHeight);
      GSetForeground(globalGC1,(float)foregroundColor,Xoption);
      GDrawRectangle(globalGC1, control->controlWindow,
		     (control->buttonQueue[originr]).buttonX,
		     (control->buttonQueue[originr]).buttonY,
		     (control->buttonQueue[originr]).buttonWidth,
		     (control->buttonQueue[originr]).buttonHeight,Xoption);
      GSetForeground(globalGC1,(float)backgroundColor,Xoption);
      XFillRectangle(dsply, control->controlWindow, globalGC1,
		 (control->buttonQueue[objectr]).buttonX,
		 (control->buttonQueue[objectr]).buttonY,
		 (control->buttonQueue[objectr]).buttonWidth,
		 (control->buttonQueue[objectr]).buttonHeight);
      GSetForeground(globalGC1,(float)foregroundColor,Xoption);
      GDrawRectangle(globalGC1, control->controlWindow,
		     (control->buttonQueue[objectr]).buttonX,
		     (control->buttonQueue[objectr]).buttonY,
		     (control->buttonQueue[objectr]).buttonWidth,
		     (control->buttonQueue[objectr]).buttonHeight,Xoption);
    }
    s1 = (control->buttonQueue[objectr]).text;
    strL1 = strlen(s1);
    s2 = (control->buttonQueue[originr]).text;
    strL2 = strlen(s2);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[objectr]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[objectr]).buttonX +
		     centerX(processGC,s1,strL1,
			     (control->buttonQueue[objectr]).buttonWidth),
		     (control->buttonQueue[objectr]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[objectr]).buttonHeight),
		     s1,strL1,Xoption);

    GSetForeground(processGC,
	   (float)monoColor((control->buttonQueue[originr]).textColor),Xoption);
    GDrawImageString(processGC,control->controlWindow,
		     (control->buttonQueue[originr]).buttonX +
		     centerX(processGC,s2,strL2,
			     (control->buttonQueue[originr]).buttonWidth),
		     (control->buttonQueue[originr]).buttonY +
		     centerY(processGC,
			     (control->buttonQueue[originr]).buttonHeight),
		     s2,strL2,Xoption);
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    break;



  case ps:
    strcpy(control->message,"   Creating postscript file ...   ");
    writeControlMessage();
    if (PSInit(viewport->viewWindow, viewport->titleWindow) == psError) {
      strcpy(control->message,"    Aborted: PSInit error.    ");
      writeControlMessage();
      return;	/* make new tmpnam for new file */
    }

    redoSmooth = yes;
    drawViewport(PSoption);	/* draw picture in PS; create ps script file */

    if (PSCreateFile(viewBorderWidth, viewport->viewWindow,
	 viewport->titleWindow, viewport->title) == psError) {
      strcpy(control->message,"    Aborted: PSCreateFile error.    ");
      writeControlMessage();
      return;
    }

    clearControlMessage();
    strcpy(control->message,PSfilename);
    strcat(control->message," in working dir ");
    writeControlMessage();
    break;



  case pixmap:
    strcpy(control->message,"   Creating axiom3D.xpm now ...   ");
    writeControlMessage();
      XGetWindowAttributes(dsply,viewport->viewWindow,&vwInfo);
      write_pixmap_file(dsply,scrn,"axiom3D.xpm",
			viewport->titleWindow,0,0,vwInfo.width,
			vwInfo.height+titleHeight);
    clearControlMessage();
    strcpy(control->message,"   axiom3D.xpm in working dir     ");
    writeControlMessage();
    break;



  case transparent:
  case opaqueMesh:
  case render:
  case smooth:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    viewData.style = bKey;
    drawViewport(Xoption);  /* draw picture in viewWindow with X routines */
    break;


  case closeAll:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    doingPanel = QUITpanel;
    viewport->closing = yes;
    XMapWindow(dsply,quitWindow);
    break;


  case quitReturn:
    XUnmapWindow(dsply,quitWindow);
    break;


  case quitAbort:
    doingPanel = CONTROLpanel;
    XUnmapWindow(dsply,quitWindow);
    break;


  case saveit:
    clearControlMessage();
    strcpy(control->message,viewport->title);
    writeControlMessage();
    saveFlag = yes;
    doingPanel = SAVEpanel;
    XMapWindow(dsply,saveWindow);
    break;


  case saveExit:
    saveFlag = no;
    doingPanel = CONTROLpanel;
    XUnmapWindow(dsply,saveWindow);
    break;


  case xy:
    viewport->theta = pi;
    viewport->phi   = 0.0;
    viewport->axestheta = pi;
    viewport->axesphi	= 0.0;
    rotated = yes;
    viewport->yzOn = viewport->xzOn = no;
    viewport->xyOn = yes;
    drawViewport(Xoption);
    break;


  case xz:
    viewport->theta = pi;
    viewport->phi   = -pi_half;
    viewport->axestheta = pi;
    viewport->axesphi	= -pi_half;
    rotated = yes;
    viewport->yzOn = viewport->xyOn = no;
    viewport->xzOn = yes;
    drawViewport(Xoption);
    break;


  case yz:
    viewport->theta = pi_half;
    viewport->phi   = -pi_half;
    viewport->axestheta = pi_half;
    viewport->axesphi	= -pi_half;
    rotated = yes;
    viewport->xzOn = viewport->xyOn = no;
    viewport->yzOn = yes;
    drawViewport(Xoption);
    break;


  default:
    fprintf(stderr,"Received a non-functioning button request: %d \n",bKey);
    break;
  } /* switch (action) */

} /* processEvents() */



/************************** X Event Processing *****************************/
void 
#ifdef _NO_PROTO
processEvents()
#else
processEvents(void)
#endif
{

  XEvent		*event, tempEvent;
  Window		whichWindow;
  buttonStruct		*controlButton;
  mouseCoord		mouseXY, linearMouseXY;
  int			someInt, mouseW4, mouseH4;
  int			toggleReady =yes;
  int                   checkButton = no;
  int                   first_time = yes;
  int			changingColor = yes;
  int			gotEvent = 0, exposeView = no;
  int			tempTW, tempTH, tempVW, tempVH;
  int			buttonTablePtr;
  float			f1, f2;
  int			px, py, lx, ly;
  unsigned int		lbuttons;
  Window		dummy;
  int                   Xcon,externalControl,len;
  fd_set                rd;

  externalControl = 0;
  Xcon = ConnectionNumber(dsply);

  /** assign lightPointer for light panel **/
  lightPointer[0] = tempLightPointer[0] = viewport->lightVector[0];
  lightPointer[1] = tempLightPointer[1] = viewport->lightVector[1];
  lightPointer[2] = tempLightPointer[2] = viewport->lightVector[2];

  if (!(event = (XEvent *)saymem("process.c",1,sizeof(XEvent)))) {
    fprintf(stderr,"Ran out of memory initializing event processing.\n");
    exitWithAck(RootWindow(dsply,scrn),Window,-1);
  }

  controlButton = 0;

  while(1) {

    /* Store old viewport window size attributes for resizing comparison. */
    XGetWindowAttributes(dsply,viewport->titleWindow,&graphWindowAttrib);
    tempTW = graphWindowAttrib.width;
    tempTH = graphWindowAttrib.height;
    XGetWindowAttributes(dsply,viewport->viewWindow,&graphWindowAttrib);
    tempVW = graphWindowAttrib.width;
    tempVH = graphWindowAttrib.height;

    /* Get the next X event. The check for pending events is so that
       a held down mouse button is interpreted as an event
       even if nothing is pending. */

    len=0;
    while(len<=0) {
      FD_ZERO(&rd);
      if (externalControl==0) FD_SET(0, &rd);
      FD_SET(Xcon,&rd);
      
      if (XEventsQueued(dsply, QueuedAlready)) {
	len=1;
	break;
      }
      if (!followMouse) 
	len=select(FD_SETSIZE,(void *)&rd,0,0,0); 
      else 
	len=1;
    }
    
    if (FD_ISSET(Xcon,&rd)|| 
	XEventsQueued(dsply, QueuedAfterFlush) || 
	followMouse) {
     
      if (followMouse) {
	if (XPending(dsply)) 
	  XNextEvent(dsply,event);
	gotEvent++;
      } else {
	XNextEvent(dsply,event);
	gotEvent++;
      }
      
      if (gotToggle || !followMouse) 
	checkButton = no;
      
      if (gotEvent) {
	whichWindow = ((XButtonEvent *)event)->window;
	first_time = no;
	
	switch(((XEvent *)event)->type) {
	case ClientMessage:
	  if (event->xclient.data.l[0] == wm_delete_window) {
	    goodbye(-1);
	  }
	  else {
	    fprintf(stderr,"Unknown Client Message ...\n");
	  }
	  break;
	case Expose:
	  if (whichWindow == viewport->titleWindow) {
	    exposeView = yes;
	    followMouse = no;
	    XSync(dsply,0);
	    /* get rid of redundant exposure events */
	    XCheckWindowEvent(dsply,viewport->titleWindow,
			      ExposureMask,&tempEvent);
	    writeTitle();
	    XGetWindowAttributes(dsply,viewport->titleWindow,
				 &graphWindowAttrib);
	    if ((graphWindowAttrib.width!=tempTW) ||
		((graphWindowAttrib.height)!=tempTH)) {
	      XResizeWindow(dsply,viewport->viewWindow,
			    graphWindowAttrib.width, graphWindowAttrib.height);
	      redoSmooth = yes;  /* recompute smooth image pixmap if resized */
	    }
	  } else if (whichWindow == viewport->viewWindow) {
	    exposeView = yes;
	    followMouse = no;
	    XSync(dsply,0);
	    XCheckWindowEvent(dsply,viewport->viewWindow,ExposureMask,
			      &tempEvent);
	    XGetWindowAttributes(dsply,viewport->viewWindow,&graphWindowAttrib);
	    if ((graphWindowAttrib.width!=tempVW) ||
		((graphWindowAttrib.height)!=tempVH)) {
	      XResizeWindow(dsply,viewport->viewWindow,graphWindowAttrib.width,
			    graphWindowAttrib.height);
	      redoSmooth = yes;  /* recompute smooth image pixmap if resized */
	    }
	    drawViewport(Xoption);
	    XMapWindow(dsply,whichWindow);
	  } else if (whichWindow == lightingWindow) {
	    XGetWindowAttributes(dsply,control->controlWindow,
				 &graphWindowAttrib);
	    /* do not allow resizing of control panel */
	    if ((graphWindowAttrib.width!=controlWidth) ||
		(graphWindowAttrib.height!=controlHeight)) {
	      XResizeWindow(dsply,control->controlWindow,controlWidth,
			    controlHeight);
	    }
	    drawLightingPanel();
	  } else if (whichWindow == volumeWindow) {
	    XGetWindowAttributes(dsply,control->controlWindow,
				 &graphWindowAttrib);
	    /* do not allow resizing of control panel */
	    if ((graphWindowAttrib.width!=controlWidth) ||
		(graphWindowAttrib.height!=controlHeight)) {
	      XResizeWindow(dsply,control->controlWindow,controlWidth,
			    controlHeight);
	    }
	    drawVolumePanel();
	    if (redrawView) {
	      redrawView = no;
	      drawViewport(Xoption);
	    }
	  } else if (whichWindow == quitWindow) {
	    XGetWindowAttributes(dsply,control->controlWindow,
				 &graphWindowAttrib);
	    /* do not allow resizing of control panel */
	    if ((graphWindowAttrib.width!=controlWidth) ||
		(graphWindowAttrib.height!=controlHeight)) {
	      XResizeWindow(dsply,control->controlWindow,controlWidth,
			    controlHeight);
	    }
	    drawQuitPanel();
	  } else if (whichWindow == saveWindow) {
	    XGetWindowAttributes(dsply,control->controlWindow,
				 &graphWindowAttrib);
	    /* do not allow resizing of control panel */
	    if ((graphWindowAttrib.width!=controlWidth) ||
		(graphWindowAttrib.height!=controlHeight)) {
	      XResizeWindow(dsply,control->controlWindow,controlWidth,
			    controlHeight);
	    }
	    drawSavePanel();
	  } else if (whichWindow == control->controlWindow) {
	    XGetWindowAttributes(dsply,control->controlWindow,
				 &graphWindowAttrib);
	    /* do not allow resizing of control panel */
	    if ((graphWindowAttrib.width != controlWidth) ||
		(graphWindowAttrib.height != controlHeight)) {
	      XResizeWindow(dsply,control->controlWindow,
			    controlWidth,controlHeight);
	    }
	    if (viewport->haveControl) drawControlPanel();
	    followMouse = no;
	    if (redrawView || exposeView) {
	      redrawView = no;
	      drawViewport(Xoption);
	    }
	    exposeView = no;
	  } else {
	    fprintf(stderr,"Not a valid window.\n");
	  }
	  
	  XFlush(dsply);
	  while(XCheckTypedWindowEvent(dsply, whichWindow, Expose, &tempEvent));
	  break;
	  
	  
	case MotionNotify:
	  exposeView = no;
	  if (followMouse) {
	    if (whichWindow == control->colormapWindow) {
	      while (XCheckMaskEvent(dsply,ButtonMotionMask,event));
	      first_time = checkButton = followMouse = changingColor = yes;
	      gotToggle	= no;
	    } else if (whichWindow != control->controlWindow) {
	      if (controlButton->pot) {
		while (XCheckMaskEvent(dsply,ButtonMotionMask,event));
		mouseXY = getPotValue(((XButtonEvent *)event)->x,
				      ((XButtonEvent *)event)->y,
				      controlButton->xHalf,
				      controlButton->yHalf);
		linearMouseXY = getLinearPotValue(((XButtonEvent *)event)->x,
						  ((XButtonEvent *)event)->y,
						  controlButton->xHalf,
						  controlButton->yHalf);
		first_time = checkButton = followMouse = yes;
		gotToggle = no;
	      }
	    }
	  }
	  break;
	  
	case ButtonRelease:
	  exposeView = followMouse = no;
	  toggleReady = yes;  gotToggle = yes;
	  break;
	  
	case LeaveNotify:
	  XQueryPointer(dsply,rtWindow,&dummy,&dummy,&px,&py,&lx,&ly,&lbuttons);
	  if ( (controlButton) &&
	       ((whichWindow == control->colormapWindow) ||
		(controlButton->pot)) &&
	       (lbuttons & Button1Mask ||
		lbuttons & Button2Mask ||
		lbuttons & Button3Mask)) {
	    followMouse = yes;
	    if (whichWindow == control->colormapWindow)
	      changingColor = yes;
	  }
	  else {
	    followMouse = no;
	    changingColor = no;
	  }
	  toggleReady = yes;
	  checkButton = exposeView = no;
	  break;
	  
	case ButtonPress:
	  exposeView = no;  changingColor = no;
	  if (whichWindow == viewport->viewWindow) {
	    /* find out where the mouse button is pressed on the viewport,
	       this determines where to put the control panel */
	    XGetWindowAttributes(dsply,whichWindow,&graphWindowAttrib);
	    mouseW4 = graphWindowAttrib.width/4;
	    if (((XButtonEvent *)event)->x > (graphWindowAttrib.width-mouseW4))
	      someInt = 1;
	    else {
	      mouseH4 = graphWindowAttrib.height/4;
	      if (((XButtonEvent *)event)->y >
		  (graphWindowAttrib.height - mouseH4)) someInt = 2;
	      else if (((XButtonEvent *)event)->x < mouseW4) someInt = 3;
	      else if (((XButtonEvent *)event)->y < mouseH4) someInt = 4;
	      else someInt = 0;
	    }
	    if (viewport->haveControl) {
	      XUnmapWindow(dsply,control->controlWindow);
	    }
	    putControlPanelSomewhere(someInt);
	    writeControlMessage();
	    XSync(dsply,0);
	  } else if (whichWindow == control->colormapWindow) {
	    gotToggle = no;
	    first_time = checkButton = followMouse = changingColor = yes;
	  } else if (whichWindow != control->controlWindow) {
	    /* mouse clicked on one of the buttons */
	    if (!controlButton || (controlButton->self != whichWindow)) {
	      buttonTablePtr = *((int *)XLookUpAssoc(dsply,table,whichWindow));
	      /** lighting buttons have indices greater than 100 **/
	      /** all buttons share the same array now **/
	      controlButton = &(control->buttonQueue[buttonTablePtr]);
	    }
	    if (controlButton->pot) {
	      /* figure out [x,y] for this button in the range [-1..1,-1..1] */
	      mouseXY = getPotValue(((XButtonEvent *)event)->x,
				    ((XButtonEvent *)event)->y,
				    controlButton->xHalf,controlButton->yHalf);
	      linearMouseXY = getLinearPotValue(((XButtonEvent *)event)->x,
						((XButtonEvent *)event)->y,
						controlButton->xHalf,
						controlButton->yHalf);
	      followMouse = yes;
	      gotToggle = no;
	    } else {
	      followMouse = no;
	      gotToggle = yes;   /* auto-repeat of toggle buttons not allowed */
	      if (toggleReady) toggleReady = no;
	    }
	    checkButton = yes;
	    first_time  = yes;
	  }
	  break;
	  
	default:
	  toggleReady = gotToggle = yes;
	  exposeView = changingColor = checkButton = followMouse = no;
	  break;
	  
	} /* switch */
	gotEvent--;
      }  /* if gotEvent */
      
      /* Allow a pressed mouse button on a potentiometer to poll repeatedly. */
      if (followMouse && !first_time && (followMouse++ > mouseWait)) {
	/* reset for next timing loop */
	followMouse = yes;
	checkButton = yes;
      }
      if (checkButton) {
	if (viewport->closing && (controlButton->buttonKey == quitReturn)) {
	  goodbye(-1);
	} else if (changingColor) {
	  viewport->closing = no;
	  /* moving top color map pointer */
	  if (((XButtonEvent *)event)->y < colorOffsetY) {
	    if (((XButtonEvent *)event)->x < (colorOffset+colorWidth)) {
	      /* decreasing top hue number */
	      if (viewport->hueTop > 0) viewport->hueTop--;
	    } else if (((XButtonEvent *)event)->x >=
		       (colorOffsetX + totalHues*colorWidth + colorWidth)) {
	      if (viewport->hueTop < totalHues) viewport->hueTop++;
	    } else {
	      viewport->hueTop =
		(((XButtonEvent *)event)->x -
		 colorOffsetX + colorWidth/2 - 13) / colorWidth;
	    }
	  } else if (((XButtonEvent *)event)->y >
		     (colorOffsetY + colorHeight)) {
	    /* moving bottom color map pointer */
	    if (((XButtonEvent *)event)->x < (colorOffset+colorWidth)) {
	      /* decreasing offset number */
	      if (viewport->hueOffset > 0) viewport->hueOffset--;
	    } else if (((XButtonEvent *)event)->x >=
		       (colorOffsetX + totalHues*colorWidth + colorWidth)) {
	      if (viewport->hueOffset < totalHues) viewport->hueOffset++;
	    } else {
	      viewport->hueOffset =
		(((XButtonEvent *)event)->x -
		 colorOffsetX + colorWidth/2 - 13) / colorWidth;
	    }
	  }
	  /* color map pointer does not wrap around */
	  if (viewport->hueOffset < 0) viewport->hueOffset = 0;
	  if (viewport->hueTop < 0) viewport->hueTop = 0;
	  if (viewport->hueOffset >= totalHues)
	    viewport->hueOffset = totalHues-1;
	  if (viewport->hueTop >= totalHues) viewport->hueTop = totalHues-1;
	  viewport->numberOfHues = viewport->hueTop - viewport->hueOffset;
	  if ((viewport->hueTop == viewport->hueOffset) && !viewport->monoOn) {
	    redoColor = yes;
	    redoDither = no;
	  } else {
	    redoColor = no;
	    redoDither = yes;
	  }
	  /* update color map changes on control panel */
	  drawColorMap();
	} else {
	  viewport->closing = no;
	  clearControlMessage();
	  /* reset all the things that might affect a recalculation for
	     redrawing removing hidden surfaces */
	  
	  /* determine what type of button has been pressed */
	  switch(controlButton->buttonKey) {
	    
	    /*** Potentiometers ***/
	  case rotate:
	    if (!((viewport->originrOn) && (viewport->objectrOn))) {
	      /* update the amount of rotation around the object center
		 of volume */
	      if (viewport->objectrOn) {
		viewport->thetaObj += mouseXY.x * rotateFactor;
		viewport->phiObj  -= mouseXY.y * rotateFactor;
		while (viewport->thetaObj >= two_pi) {
		  viewport->thetaObj -= two_pi;
		}
		while (viewport->thetaObj < 0.0) {
		  viewport->thetaObj += two_pi;
		}
		while (viewport->phiObj > pi) {
		  viewport->phiObj -= two_pi;
		}
		while (viewport->phiObj <= -pi) {
		  viewport->phiObj += two_pi;
		}
	      }
	      /* update amount of rotation around the world space origin */
	      if (viewport->originrOn) {
		viewport->theta += mouseXY.x * rotateFactor;
		viewport->phi	-= mouseXY.y * rotateFactor;
		while (viewport->theta >= two_pi) {
		  viewport->theta -= two_pi;
		}
		while (viewport->theta < 0.0) {
		  viewport->theta += two_pi;
		}
		while (viewport->phi > pi) {
		  viewport->phi -= two_pi;
		}
		while (viewport->phi <= -pi) {
		  viewport->phi += two_pi;
		}
		viewport->axestheta += mouseXY.x * rotateFactor;
		viewport->axesphi   -= mouseXY.y * rotateFactor;
		while (viewport->axestheta >= two_pi) {
		  viewport->axestheta -= two_pi;
		}
		while (viewport->axestheta < 0.0) {
		  viewport->axestheta += two_pi;
		}
		while (viewport->axesphi > pi) {
		  viewport->axesphi -= two_pi;
		}
		while (viewport->axesphi <= -pi) {
		  viewport->axesphi += two_pi;
		}
	      }
	      rotated = yes;
	      viewport->yzOn = viewport->xzOn = viewport->xyOn = no;
	      clearControlMessage();
	      strcpy(control->message,viewport->title);
	      writeControlMessage();
	      drawViewport(Xoption);
	    }
	    break;
	    
	  case zoom:
	    /* if uniform scaling */
	    if ((viewport->zoomXOn) &&
		(viewport->zoomYOn) &&
		(viewport->zoomZOn)) {
	      viewport->scale *= 1 - mouseXY.y * scaleFactor;
	    } else { /* else scale axes independently */
	      if (viewport->zoomXOn) viewport->scaleX *= (1 - mouseXY.y);
	      if (viewport->zoomYOn) viewport->scaleY *= (1 - mouseXY.y);
	      if (viewport->zoomZOn) viewport->scaleZ *= (1 - mouseXY.y);
	    }
	    if (viewport->scale > maxScale) viewport->scale = maxScale;
	    else if (viewport->scale < minScale) viewport->scale = minScale;
	    if (viewport->scaleX > maxScale) viewport->scaleX = maxScale;
	    else if (viewport->scaleX < minScale) viewport->scaleX = minScale;
	    if (viewport->scaleY > maxScale) viewport->scaleY = maxScale;
	    else if (viewport->scaleY < minScale) viewport->scaleY = minScale;
	    if (viewport->scaleZ > maxScale) viewport->scaleZ = maxScale;
	    else if (viewport->scaleZ < minScale) viewport->scaleZ = minScale;
	    zoomed = yes;
	    clearControlMessage();
	    strcpy(control->message,viewport->title);
	    writeControlMessage();
	    if ((viewport->zoomXOn) ||
		(viewport->zoomYOn) ||
		(viewport->zoomZOn))
	      drawViewport(Xoption);
	    break;
	    
	  case translate:
	    viewport->deltaX += mouseXY.x * translateFactor;
	    viewport->deltaY += mouseXY.y * translateFactor;
	    if (viewport->deltaX > maxDeltaX) viewport->deltaX = maxDeltaX;
	    else if (viewport->deltaX < -maxDeltaX) viewport->deltaX = -maxDeltaX;
	    
	    if (viewport->deltaY > maxDeltaY) viewport->deltaY = maxDeltaY;
	    else if (viewport->deltaY < -maxDeltaY) viewport->deltaY = -maxDeltaY;
	    translated = yes;
	    clearControlMessage();
	    strcpy(control->message,viewport->title);
	    writeControlMessage();
	    drawViewport(Xoption);
	    break;
	    
	    /*** Lighting panel ***/
	  case lightMoveXY:
	    tempLightPointer[0] = linearMouseXY.x;
	    tempLightPointer[1] = linearMouseXY.y;
	    if (tempLightPointer[0] > 1) tempLightPointer[0] = 1;
	    else if (tempLightPointer[0] < -1) tempLightPointer[0] = -1;
	    if (tempLightPointer[1] > 1) tempLightPointer[1] = 1;
	    else if (tempLightPointer[1] < -1) tempLightPointer[1] = -1;
	    movingLight = yes;
	    drawLightingAxes();
	    break;
	    
	  case lightMoveZ:
	    tempLightPointer[2] = linearMouseXY.y;
	    /* linearMouse => no checking necessary */
	    if (tempLightPointer[2] > 1) tempLightPointer[2] = 1;
	    else if (tempLightPointer[2] < -1) tempLightPointer[2] = -1;
	    movingLight = yes;
	    drawLightingAxes();
	    break;
	    
	    /* changes the light intensity */
	  case lightTranslucent:
	    tempLightIntensity = (linearMouseXY.y+1)/2;
	    if (tempLightIntensity > 1) tempLightIntensity = 1;
	    else if (tempLightIntensity < 0) tempLightIntensity = 0;
	    changedIntensity = yes;
	    drawLightTransArrow();
	    break;
	    
	    /*** volume panel ***/
	  case frustrumBut:
	    screenX = ((XButtonEvent *)event)->x;
	    if inside(eyeMinX,eyeMaxX) {
	      /* object coordinate */
	      f2 = mouseXY.x * (maxEyeDistance - minEyeDistance) +
		minEyeDistance;
	      if (f2 != viewData.eyeDistance) {
		doingVolume = 2;   /* flag for using screenX */
		changedEyeDistance = yes;
		viewData.eyeDistance = f2;
		drawFrustrum();
		drawViewport(Xoption);
	      }
	    }
	    else if inside(hitherMinX,hitherMaxX) {
	      f1 = ((float)hitherMaxX - ((XButtonEvent *)event)->x) /
		(hitherMaxX - hitherMinX);
	      /* object coordinate */
	      f2 = f1 * (clipPlaneMax - clipPlaneMin) + clipPlaneMin;
	      if (f2 != viewData.clipPlane) {
		doingVolume = 3;   /* flag for using screenX */
		viewData.clipPlane = f2;
		drawFrustrum();
		drawViewport(Xoption);
	      }
	    }
	    else {
	      doingVolume = 1;	/* check out doingVolume */
	      doingPanel = VOLUMEpanel;
	    }
	    break;
	    
	  case clipXBut:  /* this is a horizontal button */
	    clipValue = linearMouseXY.x * 0.5 + 0.5;   /* normalize to 0..1 */
	    if (lessThan(clipValue,0.0)) clipValue = 0.0;
	    if (greaterThan(clipValue,1.0)) clipValue = 1.0;
	    if (lessThan(linearMouseXY.y,0.0)) {
	      if (!equal(xClipMinN,clipValue)) {
		if (greaterThan(xClipMaxN-clipValue,minDistXY))
		  xClipMinN = clipValue;
		else
		  xClipMinN = xClipMaxN - minDistXY;
		viewData.clipXmin = xClipMinN *
		  (viewData.xmax - viewData.xmin) +
		  viewData.xmin;
		drawClipXBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    } else {
	      if (!equal(xClipMaxN,clipValue)) {
		if (greaterThan(clipValue-xClipMinN,minDistXY))
		  xClipMaxN = clipValue;
		else
		  xClipMaxN = xClipMinN + minDistXY;
		viewData.clipXmax = xClipMaxN *
		  (viewData.xmax - viewData.xmin) +
		  viewData.xmin;
		drawClipXBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    }
	    break;
	    
	  case clipYBut:  /* this is a vertical button */
	    /* normalize to 0..1, bottom up */
	    clipValue = 1 - (linearMouseXY.y * 0.5 + 0.5);
	    if (lessThan(clipValue,0.0)) clipValue = 0.0;
	    if (greaterThan(clipValue,1.0)) clipValue = 1.0;
	    if (lessThan(linearMouseXY.x,0.0)) {
	      if (!equal(yClipMinN,clipValue)) {
		if (greaterThan(yClipMaxN-clipValue,minDistXY))
		  yClipMinN = clipValue;
		else
		  yClipMinN = yClipMaxN - minDistXY;
		viewData.clipYmin = yClipMinN *
		  (viewData.ymax - viewData.ymin) +
		  viewData.ymin;
		drawClipYBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    } else {
	      if (!equal(yClipMaxN,clipValue)) {
		if (greaterThan(clipValue-yClipMinN,minDistXY))
		  yClipMaxN = clipValue;
		else
		  yClipMaxN = yClipMinN + minDistXY;
		viewData.clipYmax = yClipMaxN *
		  (viewData.ymax - viewData.ymin) +
		  viewData.ymin;
		drawClipYBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    }
	    break;
	    
	  case clipZBut:  /* this is a diagonally aligned button! */
	    /* f1 is the distance from the center of the button along
	       the diagonal line with a slope of -1. If f1 is negative,
	       the direction is downward from the center, if f1 is
	       positive, the direction is upward from the center.
	       Note that there ought to be a constant factor, namely
	       cos(45), multiplied by f1 for the correct normalized value;
	       however, we exploit this by foreshortening the length of the
	       diagonal by that same factor (so instead of normalizing the
	       numbers to, the line we normalize the line to the numbers)
	       since we need to shorten the line at some point anyway
	       (both to match the length of the diagonal side of the box
	       and to allow more area for mouse input. */
	    
	    /* cos(45), etc => 0.4 */
	    f1 = (linearMouseXY.x - linearMouseXY.y) * 0.4 + 0.5;
	    if (lessThan(f1,0.0)) f1 = 0.0;
	    if (greaterThan(f1,1.0)) f1 = 1.0;
	    /* note that x<y => moving upward */
	    if (lessThan(-linearMouseXY.x,linearMouseXY.y)) {
	      if (!equal(zClipMaxN,f1)) {
		if (greaterThan(f1-zClipMinN,minDistZ))
		  zClipMaxN = f1;
		else
		  zClipMaxN = zClipMinN + minDistZ;
		viewData.clipZmax = zClipMaxN *
		  (viewData.zmax - viewData.zmin) +
		  viewData.zmin;
		drawClipZBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    } else {
	      if (!equal(zClipMinN,f1)) {
		if (greaterThan(zClipMaxN-f1,minDistZ))
		  zClipMinN = f1;
		else
		  zClipMinN = zClipMaxN - minDistZ;
		viewData.clipZmin = zClipMinN *
		  (viewData.zmax - viewData.zmin) +
		  viewData.zmin;
		drawClipZBut();
		drawClipVolume();
		if (viewData.clipbox)
		  drawViewport(Xoption);
	      }
	    }	/* if lessThan(x,y) */
	    break;
	    
	  case perspectiveBut:
	    if ((viewData.perspective = !viewData.perspective)) {
	      switchedPerspective = yes;
	      GSetForeground(volumeGC,
			     (float)monoColor((control->buttonQueue[perspectiveBut]).textColor),Xoption);
	      GDrawString(volumeGC,volumeWindow,
			  controlButton->buttonX +
			  centerX(volumeGC,"x",1,controlButton->buttonWidth),
			  controlButton->buttonY +
			  centerY(volumeGC,controlButton->buttonHeight),
			  "x",1,Xoption);
	    }
	    else
	      XClearArea(dsply,volumeWindow,
			 controlButton->buttonX+1,
			 controlButton->buttonY+1,
			 controlButton->buttonHeight-2,
			 controlButton->buttonWidth-2,
			 False);
	    drawViewport(Xoption);
	    break;
	    
	  case clipRegionBut:
	    if ((viewData.clipbox = !viewData.clipbox)) {
	      GSetForeground(volumeGC,
			     (float)monoColor((control->buttonQueue[clipRegionBut]).textColor),Xoption);
	      GDrawString(volumeGC,volumeWindow,
			  controlButton->buttonX +
			  centerX(volumeGC,"x",1,controlButton->buttonWidth),
			  controlButton->buttonY +
			  centerY(volumeGC,controlButton->buttonHeight),
			  "x",1,Xoption);
	    }
	    else
	      XClearArea(dsply,volumeWindow,
			 controlButton->buttonX+1,
			 controlButton->buttonY+1,
			 controlButton->buttonWidth-2,
			 controlButton->buttonHeight-2,
			 False);
	    
	    drawViewport(Xoption);
	    break;
	    
	  case clipSurfaceBut:
	    if ((viewData.clipStuff = !viewData.clipStuff)) {
	      GSetForeground(volumeGC,
			     (float)monoColor((control->buttonQueue[clipSurfaceBut]).textColor),Xoption);
	      GDrawString(volumeGC,volumeWindow,
			  controlButton->buttonX +
			  centerX(volumeGC,"x",1,controlButton->buttonWidth),
			  controlButton->buttonY +
			  centerY(volumeGC,controlButton->buttonHeight),
			  "x",1,Xoption);
	    }
	    else
	      XClearArea(dsply,volumeWindow,
			 controlButton->buttonX+1,
			 controlButton->buttonY+1,
			 controlButton->buttonWidth-2,
			 controlButton->buttonHeight-2,
			 False);
	    break;
	    
	  default:
	    buttonAction(controlButton->buttonKey);
	  } /* switch on buttonKey */
	  
	}  /* else - not closing */
      }	  /* if checkButton */
    } /* if FD_ISSET(Xcon,.. */
    else if FD_ISSET(0,&rd) {
      externalControl = spadAction();
      if (spadDraw && (externalControl==0)) drawViewport(Xoption);
    }
  } 	  /* for (until closed) */
}	  /* processEvents() */



@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}