/*
  Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd.
  All rights reserved.
  Copyright (C) 2007-2008, Gabriel Dos Reis.
  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.
*/

#define _VOLUME3D_C
#include "openaxiom-c-macros.h"

#include <math.h>
#include <string.h>

#include "header.h"
#include "cpanel.h"
#include "process.h"
#include "volume.h"
#include "../include/purty/volume.bitmap"
#include "../include/purty/volume.mask"



#include "XSpadFill.H1"
#include "Gfun.H1"
#include "all_3d.H1"

#define eyeDistMessX (frusX(eyeWinX+27))
#define eyeDistMessY (frusY(eyeWinY-5))
#define hitherMessX (frusX(hitherWinX+15))
#define hitherMessY (frusY(hitherWinY))

#define clipXMessX (control->buttonQueue[clipXBut].buttonX + \
                    control->buttonQueue[clipXBut].xHalf)
#define clipXMessY (control->buttonQueue[clipXBut].buttonY + 2)
#define clipYMessX (control->buttonQueue[clipYBut].buttonX + \
                    control->buttonQueue[clipYBut].buttonWidth-2)
#define clipYMessY (control->buttonQueue[clipYBut].buttonY + \
                    control->buttonQueue[clipYBut].yHalf)
#define clipZMessX (control->buttonQueue[clipZBut].buttonX + \
                    control->buttonQueue[clipZBut].xHalf+4)
#define clipZMessY (control->buttonQueue[clipZBut].buttonY + \
                    control->buttonQueue[clipZBut].yHalf-4)

#define volumeCursorForeground monoColor(68)
#define volumeCursorBackground monoColor(197)

#define hitherBoxColor  monoColor(141)
#define hitherBoxTop    (frustrumMidY - 10)
#define hitherBoxHeight 20

#define clipButtonColor 144
#define toggleColor 42
#define arcColor 75

#define arcSize   6
#define tinyArc   5
#define blank 4
#define toggleX 190
#define toggleY 280

#define oldWay

#define frusX(x) (control->buttonQueue[frustrumBut].buttonX + x)
#define frusY(y) (control->buttonQueue[frustrumBut].buttonY + y)

#define clipMessX 7
#define clipMessY (control->buttonQueue[clipXBut].buttonY + 15)
   /* someotherFont holds title font (see main.c) */
#define clipMessDy (globalFont->max_bounds.ascent/2 + \
                    globalFont->max_bounds.descent)
static char *clipMess = "Clip Volume";

#define eyeMess1Dy clipMessDy
#define eyeMess1X 7
#define eyeMess1Y (frustrumY + 40 + 3*eyeMess1Dy)
static char *eyeMess1 = "Eye";

#define eyeMess2X (globalFont->max_bounds.width + 14)
#define eyeMess2Y (frustrumY + 40)
#define eyeMess2Dy eyeMess1Dy
static char *eyeMess2 = "Reference";


 /*  global stuff  */
int flatClipBoxX[8], flatClipBoxY[8];




/******************* volume buttons **********************/

int
initVolumeButtons (buttonStruct *volumeButtons)
{
  int ii, num = 0;

  ii = volumeReturn;
  volumeButtons[ii].buttonX      = 154;
  volumeButtons[ii].buttonY      = 370;
  volumeButtons[ii].buttonWidth  = 110;
  volumeButtons[ii].buttonHeight = 24;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = no;
  volumeButtons[ii].mask         = buttonMASK;
  volumeButtons[ii].text         = "Return";
  volumeButtons[ii].textColor    = 52;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = volumeAbort;
  volumeButtons[ii].buttonX      = 36;
  volumeButtons[ii].buttonY      = 370;
  volumeButtons[ii].buttonWidth  = 110;
  volumeButtons[ii].buttonHeight = 24;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = no;
  volumeButtons[ii].mask         = buttonMASK;
  volumeButtons[ii].text         = "Abort";
  volumeButtons[ii].textColor    = 28;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = frustrumBut;
  volumeButtons[ii].buttonX      = frustrumWindowX;
  volumeButtons[ii].buttonY      = frustrumWindowY;
  volumeButtons[ii].buttonWidth  = frustrumWindowWidth;
  volumeButtons[ii].buttonHeight = frustrumWindowHeight;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = yes;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Frustrum Window";
  volumeButtons[ii].textColor    = frustrumColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = perspectiveBut;
  volumeButtons[ii].buttonX      = toggleX;
  volumeButtons[ii].buttonY      = toggleY;
  volumeButtons[ii].buttonWidth  = 10;
  volumeButtons[ii].buttonHeight = 10;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = no;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Perspective";
  volumeButtons[ii].textColor    = arcColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = clipRegionBut;
  volumeButtons[ii].buttonX      = toggleX;
  volumeButtons[ii].buttonY      = toggleY+20;
  volumeButtons[ii].buttonWidth  = 10;
  volumeButtons[ii].buttonHeight = 10;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = no;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Show Region";
  volumeButtons[ii].textColor    = arcColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = clipSurfaceBut;
  volumeButtons[ii].buttonX      = toggleX;
  volumeButtons[ii].buttonY      = toggleY+40;
  volumeButtons[ii].buttonWidth  = 10;
  volumeButtons[ii].buttonHeight = 10;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = no;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Clipping On";
  volumeButtons[ii].textColor    = arcColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = clipXBut;
  volumeButtons[ii].buttonX      = clipXButX;
  volumeButtons[ii].buttonY      = clipXButY;
  volumeButtons[ii].buttonWidth  = majorAxis;
  volumeButtons[ii].buttonHeight = minorAxis;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = yes;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Clip X";
  volumeButtons[ii].textColor    = clipButtonColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = clipYBut;
  volumeButtons[ii].buttonX      = clipYButX;
  volumeButtons[ii].buttonY      = clipYButY;
  volumeButtons[ii].buttonWidth  = minorAxis;
  volumeButtons[ii].buttonHeight = majorAxis;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = yes;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Clip Y";
  volumeButtons[ii].textColor    = clipButtonColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  ii = clipZBut;
  volumeButtons[ii].buttonX      = clipZButX;
  volumeButtons[ii].buttonY      = clipZButY;
  volumeButtons[ii].buttonWidth  = midAxis;
  volumeButtons[ii].buttonHeight = midAxis;
  volumeButtons[ii].buttonKey    = ii;
  volumeButtons[ii].pot          = yes;
  volumeButtons[ii].mask         = potMASK;
  volumeButtons[ii].text         = "Clip Z";
  volumeButtons[ii].textColor    = clipButtonColor;
  volumeButtons[ii].xHalf        = volumeButtons[ii].buttonWidth/2;
  volumeButtons[ii].yHalf        = volumeButtons[ii].buttonHeight/2;
  ++num;

  return(num);
}


/*************************
 * int makeVolumePanel() *
 *************************/

void
makeVolumePanel (void)
{

  int i;
  XSetWindowAttributes cwAttrib, controlAttrib;
  XSizeHints sizehint;
  Pixmap volumebits, volumemask;
  XColor foreColor, backColor;

  volumebits = XCreateBitmapFromData(dsply,rtWindow,volumeBitmap_bits,
                                     volumeBitmap_width,volumeBitmap_height);
  volumemask = XCreateBitmapFromData(dsply,rtWindow,volumeMask_bits,
                                     volumeMask_width,volumeMask_height);
  cwAttrib.background_pixel = backgroundColor;
  cwAttrib.border_pixel = foregroundColor;
  cwAttrib.event_mask = volumeMASK;
  cwAttrib.colormap = colorMap;
  cwAttrib.override_redirect = overrideManager;
  foreColor.pixel = volumeCursorForeground;
  XQueryColor(dsply,colorMap,&foreColor);
  backColor.pixel = volumeCursorBackground;
  XQueryColor(dsply,colorMap,&backColor);
  cwAttrib.cursor = XCreatePixmapCursor(dsply,volumebits,volumemask,
                                        &foreColor,&backColor,
                                        volumeBitmap_x_hot,
                                        volumeBitmap_y_hot);
  volumeWindow = XCreateWindow(dsply,control->controlWindow,
                               -3,-3,controlWidth,controlHeight,3,
                               CopyFromParent,InputOutput,CopyFromParent,
                               controlCreateMASK,&cwAttrib);

  sizehint.flags  = USPosition | USSize;
  sizehint.x      = 0;
  sizehint.y      = 0;
  sizehint.width  = controlWidth;
  sizehint.height = controlHeight;
          /*** the None stands for icon pixmap ***/
  XSetNormalHints(dsply,volumeWindow,&sizehint);
  XSetStandardProperties(dsply,volumeWindow,"Volume Panel 3D",
                         "View Volume",None,NULL,0,&sizehint);

      /*** volume frustrum window ***/

    /*** do volume buttons ***/
  initVolumeButtons(control->buttonQueue);
  for (i=volumeButtonsStart; i<(volumeButtonsEnd); i++) {
    controlAttrib.event_mask = (control->buttonQueue[i]).mask;
    (control->buttonQueue[i]).self =
                XCreateWindow(dsply,volumeWindow,
                              (control->buttonQueue[i]).buttonX,
                              (control->buttonQueue[i]).buttonY,
                              (control->buttonQueue[i]).buttonWidth,
                              (control->buttonQueue[i]).buttonHeight,
                              0,0,InputOnly,CopyFromParent,
                              buttonCreateMASK,&controlAttrib);
    XMakeAssoc(dsply,table,(control->buttonQueue[i]).self,
               &((control->buttonQueue[i]).buttonKey));
    XMapWindow(dsply,(control->buttonQueue[i]).self);
  }

}  /* makeVolumePanel() */


void
drawClipXBut (void)
{

  XClearArea(dsply,volumeWindow,clipXButX,clipXButY,
             majorAxis+blank,minorAxis+blank,False);
  GSetForeground(trashGC,(float)monoColor(toggleColor),Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipXBut]).buttonX,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,
            (control->buttonQueue[clipXBut]).buttonX +
            (control->buttonQueue[clipXBut]).buttonWidth,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipXBut]).buttonX-3,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf-3,
            (control->buttonQueue[clipXBut]).buttonX,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipXBut]).buttonX-3,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf+3,
            (control->buttonQueue[clipXBut]).buttonX,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipXBut]).buttonX +
            (control->buttonQueue[clipXBut]).buttonWidth+3,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf-3,
            (control->buttonQueue[clipXBut]).buttonX +
            (control->buttonQueue[clipXBut]).buttonWidth,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipXBut]).buttonX +
            (control->buttonQueue[clipXBut]).buttonWidth+3,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf+3,
            (control->buttonQueue[clipXBut]).buttonX +
            (control->buttonQueue[clipXBut]).buttonWidth,
            (control->buttonQueue[clipXBut]).buttonY +
            (control->buttonQueue[clipXBut]).yHalf,Xoption);

  GSetForeground(trashGC,(float)monoColor(arcColor),Xoption);
  GFillArc(trashGC,volumeWindow,
           (int)(xClipMinN * (majorAxis-tinyArc) + clipXButX),  /* x value */
           (int)(clipXButY + minorAxis/2 + 1),                  /* y value */
           arcSize,arcSize,0,360*64,Xoption);               /* 64 units per degree */
  GFillArc(trashGC,volumeWindow,
           (int)(xClipMaxN * (majorAxis-tinyArc) + clipXButX),  /* x value */
           (int)(clipXButY + minorAxis/2 - 7),                  /* y value */
           arcSize,arcSize,0,360*64,Xoption);               /* 64 units per degree */

  GSetForeground(volumeGC,(float)monoColor(toggleColor),Xoption);
  GDrawString(volumeGC,volumeWindow,clipXMessX,clipXMessY,"X",1,Xoption);

}

void
drawClipYBut (void)
{

  XClearArea(dsply,volumeWindow,clipYButX,clipYButY,
             minorAxis+blank,majorAxis+blank,False);
  GSetForeground(trashGC,(float)monoColor(toggleColor),Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY +
            (control->buttonQueue[clipYBut]).buttonHeight,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf-3,
            (control->buttonQueue[clipYBut]).buttonY-3,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf+3,
            (control->buttonQueue[clipYBut]).buttonY-3,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf-3,
            (control->buttonQueue[clipYBut]).buttonY +
            (control->buttonQueue[clipYBut]).buttonHeight+3,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY +
            (control->buttonQueue[clipYBut]).buttonHeight,Xoption);
  GDrawLine(trashGC,volumeWindow,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf+3,
            (control->buttonQueue[clipYBut]).buttonY +
            (control->buttonQueue[clipYBut]).buttonHeight+3,
            (control->buttonQueue[clipYBut]).buttonX +
            (control->buttonQueue[clipYBut]).xHalf,
            (control->buttonQueue[clipYBut]).buttonY +
            (control->buttonQueue[clipYBut]).buttonHeight,Xoption);

  GSetForeground(trashGC,(float)monoColor(arcColor),Xoption);

  /* note: minimum buttons closer to the box */
  GFillArc(trashGC,volumeWindow,
           (int)(clipYButX + minorAxis/2 - 8),
           (int)(yClipMinN * (majorAxis-tinyArc) + clipYButY),
           arcSize,arcSize,90*64,360*64,Xoption);       /* 64 units per degree */
  GFillArc(trashGC,volumeWindow,
           (int)(clipYButX + minorAxis/2 + 3),
           (int)(yClipMaxN * (majorAxis-tinyArc) + clipYButY),
           arcSize,arcSize,90*64,360*64,Xoption);       /* 64 units per degree */

  GSetForeground(volumeGC,(float)monoColor(toggleColor),Xoption);
  GDrawString(volumeGC,volumeWindow,clipYMessX,clipYMessY,"Y",1,Xoption);

}


void
drawClipZBut (void)
{

  XClearArea(dsply,volumeWindow,clipZButX,clipZButY,
             midAxis+blank,midAxis+blank,False);
  GSetForeground(trashGC,(float)monoColor(toggleColor),Xoption);
  GDrawLine(trashGC,volumeWindow,clipZButTopEndX,clipZButTopEndY,
            clipZButBotEndX,clipZButBotEndY,Xoption);
  GDrawLine(trashGC,volumeWindow,clipZButTopEndX-4,clipZButTopEndY,
            clipZButTopEndX,clipZButTopEndY,Xoption);

  GDrawLine(trashGC,volumeWindow,clipZButTopEndX,clipZButTopEndY-4,
            clipZButTopEndX,clipZButTopEndY,Xoption);

  GDrawLine(trashGC,volumeWindow,clipZButBotEndX+4,clipZButBotEndY,
            clipZButBotEndX,clipZButBotEndY,Xoption);

  GDrawLine(trashGC,volumeWindow,clipZButBotEndX,clipZButBotEndY+4,
            clipZButBotEndX,clipZButBotEndY,Xoption);


  GSetForeground(trashGC,(float)monoColor(arcColor),Xoption);
  GFillArc(trashGC,volumeWindow,
           (int)(zClipMinN * midAxis * zFactor + clipZButTopEndX - 3),
           (int)(zClipMinN * midAxis * zFactor + clipZButTopEndY + 3),
           arcSize,arcSize,45*64,360*64,Xoption);       /* 64 units per degree */
  GFillArc(trashGC,volumeWindow,
           (int)(zClipMaxN * midAxis * zFactor + clipZButTopEndX + 3),
           (int)(zClipMaxN * midAxis * zFactor + clipZButTopEndY - 5),
           arcSize,arcSize,45*64,360*64,Xoption);       /* 64 units per degree */

  GSetForeground(volumeGC,(float)monoColor(toggleColor),Xoption);
  GDrawString(volumeGC,volumeWindow,clipZMessX,clipZMessY,"Z",1,Xoption);

}


void
drawClipVolume (void)
{

  float xminL,xmaxL,yminL,ymaxL,zminL,zmaxL;

  XClearArea(dsply,volumeWindow,backFaceX-1,backFaceY,
             lengthFace+deltaFace+2,lengthFace+deltaFace+1,False);

  GSetForeground(trashGC,(float)boxInline,Xoption);     /*boxOutline=133*/
  GSetLineAttributes(trashGC,0,LineSolid,CapButt,JoinMiter,Xoption);

  /* define corners of volume, clockwise, back to front */
  xminL = xClipMinN*lengthFace;
  xmaxL = xClipMaxN*lengthFace;
  yminL = yClipMinN*lengthFace;
  ymaxL = yClipMaxN*lengthFace;
  zminL = zClipMinN*zLength;
  zmaxL = (1-zClipMaxN)*zLength;  /* percentage upwards from bottom */

  flatClipBoxX[0]   = backFaceX + xminL + zminL;
  flatClipBoxY[0]   = backFaceY + yminL + zminL;
  flatClipBoxX[1]   = backFaceX + xmaxL + zminL;
  flatClipBoxY[1]   = flatClipBoxY[0];
  flatClipBoxX[2]   = flatClipBoxX[1];
  flatClipBoxY[2]   = backFaceY + ymaxL + zminL;
  flatClipBoxX[3]   = flatClipBoxX[0];
  flatClipBoxY[3]   = flatClipBoxY[2];
  flatClipBoxX[4]   = frontFaceX + xminL - zmaxL;
  flatClipBoxY[4]   = frontFaceY + yminL - zmaxL;
  flatClipBoxX[5]   = frontFaceX + xmaxL - zmaxL;
  flatClipBoxY[5]   = flatClipBoxY[4];
  flatClipBoxX[6]   = flatClipBoxX[5];
  flatClipBoxY[6]   = frontFaceY + ymaxL - zmaxL;
  flatClipBoxX[7]   = flatClipBoxX[4];
  flatClipBoxY[7]   = flatClipBoxY[6];

  /* now draw the volume */
  GDrawRectangle(trashGC,volumeWindow,
                 flatClipBoxX[0],flatClipBoxY[0],
                 flatClipBoxX[2]-flatClipBoxX[0],
                 flatClipBoxY[2]-flatClipBoxY[0],Xoption);
  GDrawLine(trashGC,volumeWindow,
            flatClipBoxX[0],flatClipBoxY[0],flatClipBoxX[4],flatClipBoxY[4],Xoption);
  GDrawLine(trashGC,volumeWindow,
            flatClipBoxX[1],flatClipBoxY[1],flatClipBoxX[5],flatClipBoxY[5],Xoption);
  GDrawLine(trashGC,volumeWindow,
            flatClipBoxX[2],flatClipBoxY[2],flatClipBoxX[6],flatClipBoxY[6],Xoption);
  GDrawLine(trashGC,volumeWindow,
            flatClipBoxX[3],flatClipBoxY[3],flatClipBoxX[7],flatClipBoxY[7],Xoption);
  GSetForeground(trashGC,(float)boxOutline,Xoption);
  GDrawRectangle(trashGC,volumeWindow,
                 flatClipBoxX[4],flatClipBoxY[4],
                 flatClipBoxX[6]-flatClipBoxX[4],
                 flatClipBoxY[6]-flatClipBoxY[4],Xoption);
  /* make sure volumeGC is set properly before calling these functions */

} /* drawClipVolume() */


void
drawHitherControl (void)
{

  float xx,b,slope;
  int hitherTop, hitherBot;

  float b0x,b1x;

   /* draw box indicating minimum and maximum distance of projection */
  GSetForeground(trashGC,(float)hitherBoxColor,Xoption);
  b0x = (pzMin - clipPlaneMin)/(clipPlaneMax-clipPlaneMin);
  b0x = hitherMaxX - b0x*(hitherMaxX - hitherMinX);  /* screen x */
  b1x = (pzMax - clipPlaneMin)/(clipPlaneMax-clipPlaneMin);
  b1x = hitherMaxX - b1x*(hitherMaxX - hitherMinX);  /* screen x */
  GDraw3DButtonOut(trashGC,volumeWindow,
                 (int)(b0x),frusY(hitherBoxTop),
                 (int)fabs(b1x-b0x),hitherBoxHeight,Xoption);

    /* draw the hither plane */
  GSetForeground(trashGC,(float)hitherColor,Xoption);

  /* percentage x */
  xx = ((viewData.clipPlane-clipPlaneMin)/(clipPlaneMax-clipPlaneMin));
  xx = hitherMaxX - xx*(hitherMaxX - hitherMinX);  /* screen x */
  slope = ((float)frustrumY - frustrumMidY)/(frustrumX - frustrumVertex);
  b = ((float)frustrumX*frustrumMidY - frustrumVertex*frustrumY) /
      (frustrumX - frustrumVertex);
  hitherTop = slope * xx + b + 0.5;
  slope = (float)(frustrumBotY - frustrumMidY)/(frustrumX - frustrumVertex);
  b = ((float)frustrumX*frustrumMidY - frustrumVertex*frustrumBotY) /
      (frustrumX - frustrumVertex);
  hitherBot = slope * xx + b + 0.5;
  GDrawLine(trashGC,volumeWindow, frusX((int)xx),frusY(hitherTop),
            frusX((int)xx),frusY(hitherBot),Xoption);

  /* draw hither control box and bar */
  GDraw3DButtonOut(trashGC,volumeWindow,
                 frusX(hitherWinX),frusY(hitherWinY+5),
                 hitherWidth,hitherHeight,Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(hitherMinX),frusY(hitherBarY+5),
            frusX(hitherMaxX),frusY(hitherBarY+5),Xoption);
  /* draw hither plane I/O pointer arrow */

  GDrawLine(trashGC,volumeWindow,
            frusX((int)xx),frusY(hitherBarY+2),
            frusX((int)xx),frusY(hitherBarY+8),Xoption);

   /* print string label */
  GSetForeground(volumeGC,(float)hitherColor,Xoption);
  GDrawString(volumeGC,volumeWindow,hitherMessX,hitherMessY,"Hither",6,Xoption);

}

void
drawEyeControl (void)
{

  float here;
  int there;

  GSetForeground(trashGC,(float)eyeColor,Xoption);

    /* draw the eyeDistance box & slide bar */
  GDraw3DButtonOut(trashGC,volumeWindow,
                 frusX(eyeWinX),frusY(eyeWinY+5),eyeWidth,eyeHeight,Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(eyeMinX),frusY(eyeBarY+5),frusX(eyeMaxX),frusY(eyeBarY+5),Xoption);
  here = (viewData.eyeDistance - minEyeDistance) /
         (maxEyeDistance - minEyeDistance);
  here = pow((double)here,0.333333);
  there = here * (eyeMaxX - eyeMinX) + eyeMinX;  /* screen x */
  GDrawLine(trashGC,volumeWindow,
            frusX(there),frusY(eyeBarY+2),frusX(there),frusY(eyeBarY+8),Xoption);

    /* draw the eye */
  GSetLineAttributes(trashGC,2,LineSolid,CapButt,JoinMiter,Xoption);
  GSetForeground(trashGC,(float)monoColor(52),Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(there),frusY(frustrumMidY-5),
            frusX(there+8),frusY(frustrumMidY),Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(there+2),frusY(frustrumMidY+4),
            frusX(there+8),frusY(frustrumMidY-1),Xoption);
  GSetForeground(trashGC,(float)frustrumColor,Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(there+4),frusY(frustrumMidY-3),
            frusX(there+2),frusY(frustrumMidY),Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(there+4),frusY(frustrumMidY+2),
            frusX(there+3),frusY(frustrumMidY),Xoption);
  GSetLineAttributes(trashGC,0,LineSolid,CapButt,JoinMiter,Xoption);

  /* draw string label */
  GSetForeground(volumeGC,(float)eyeColor,Xoption);
  GDrawString(volumeGC,volumeWindow,eyeDistMessX,eyeDistMessY,
              "Eye Distance",strlen("eye distance"),Xoption);

}


/**************************
 * void drawFrustrum() *
 **************************/

void
drawFrustrum (void)
{

  float normalizedEyeDistance;

  XClearArea(dsply,volumeWindow,
             control->buttonQueue[frustrumBut].buttonX,
             control->buttonQueue[frustrumBut].buttonY,
             control->buttonQueue[frustrumBut].buttonWidth+9,
             control->buttonQueue[frustrumBut].buttonHeight,False);
  GSetForeground(trashGC,(float)frustrumColor,Xoption);
  normalizedEyeDistance = (viewData.eyeDistance - minEyeDistance) /
                          (maxEyeDistance - minEyeDistance);
  normalizedEyeDistance = pow((double)normalizedEyeDistance,0.333333333);
  frustrumVertex = normalizedEyeDistance * (frustrumMax - frustrumMin) +
                   frustrumMin - 4;
  GDrawLine(trashGC,volumeWindow,
            frusX(frustrumX),frusY(frustrumY),
            frusX(frustrumX),frusY(frustrumY+frustrumLength),Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(frustrumX),frusY(frustrumY),
            frusX(frustrumVertex),frusY(frustrumMidY),Xoption);
  GDrawLine(trashGC,volumeWindow,
            frusX(frustrumX),frusY(frustrumBotY),
            frusX(frustrumVertex),frusY(frustrumMidY),Xoption);

  /* draw controls */
  drawHitherControl();
  drawEyeControl();

} /* drawFrustrum() */



/**************************
 * void drawVolumePanel() *
 **************************/

void
drawVolumePanel (void)
{

  int i,strlength;


            /* Draw some lines for volume panel. */
  GSetForeground(trashGC,(float)foregroundColor,Xoption);
  GSetLineAttributes(trashGC,3,LineSolid,CapButt,JoinMiter,Xoption);
  GDrawLine(trashGC, volumeWindow, 0, potA, controlWidth, potA, Xoption);

  GSetLineAttributes(trashGC,2,LineSolid,CapButt,JoinMiter,Xoption);
  GDrawLine(trashGC, volumeWindow, 0, volumeTitleA, controlWidth,
            volumeTitleA, Xoption);
  GDrawLine(trashGC, volumeWindow, 0, volumeTitleB, controlWidth,
            volumeTitleB, Xoption);

  writeControlTitle(volumeWindow);
  s = "Viewing Volume Panel";
  strlength = strlen(s);
  GSetForeground(anotherGC,(float)volumeTitleColor,Xoption);
  GDrawString(anotherGC,volumeWindow,
              centerX(anotherGC,s,strlength,controlWidth),
              volumeTitleA+18,s,strlength,Xoption);

  GSetForeground(anotherGC,(float)monoColor(toggleColor),Xoption);
  GDrawString(anotherGC,volumeWindow,
              control->buttonQueue[perspectiveBut].buttonX + 4,
              control->buttonQueue[perspectiveBut].buttonY - 17,
              "Settings", 8, Xoption);

  GSetForeground(trashGC,(float)monoColor(toggleColor),Xoption);
  GDraw3DButtonOut(trashGC,volumeWindow,
                 control->buttonQueue[perspectiveBut].buttonX - 7,
                 control->buttonQueue[perspectiveBut].buttonY - 36,
                 100,100,Xoption);


  for (i=0; i<strlen(clipMess); i++)
    GDrawString(trashGC,volumeWindow,clipMessX,clipMessY + i*clipMessDy,
                &(clipMess[i]),1,Xoption);
  for (i=0; i<strlen(eyeMess1); i++)
    GDrawString(trashGC,volumeWindow,eyeMess1X,eyeMess1Y + i*eyeMess1Dy,
                &(eyeMess1[i]),1,Xoption);
  for (i=0; i<strlen(eyeMess2); i++)
    GDrawString(trashGC,volumeWindow,eyeMess2X,eyeMess2Y + i*eyeMess2Dy,
                &(eyeMess2[i]),1,Xoption);

  GSetLineAttributes(trashGC,0,LineSolid,CapButt,JoinMiter,Xoption);
  GSetForeground(trashGC,(float)volumeButtonColor,Xoption);
  for (i=volumeButtonsStart; i<(volumeButtonsEnd); i++) {
    GSetForeground(trashGC,
                   (float)monoColor((control->buttonQueue[i]).textColor),Xoption);
    switch (i) {
    case perspectiveBut:
    case clipRegionBut:
    case clipSurfaceBut:
      GSetForeground(volumeGC,(float)monoColor(toggleColor),Xoption);
      GDraw3DButtonOut(volumeGC,volumeWindow,
                     (control->buttonQueue[i]).buttonX,
                     (control->buttonQueue[i]).buttonY,
                     (control->buttonQueue[i]).buttonWidth,
                     (control->buttonQueue[i]).buttonHeight,Xoption);
      GSetForeground(volumeGC,
                     (float)monoColor((control->buttonQueue[i]).textColor),Xoption);
      GDrawString(volumeGC,volumeWindow,
                  (control->buttonQueue[i]).buttonX +
                  (control->buttonQueue[i]).buttonWidth + 4,
                  (control->buttonQueue[i]).buttonY +
                  centerY(volumeGC,(control->buttonQueue[i]).buttonHeight),
                  (control->buttonQueue[i]).text,
                  strlen(control->buttonQueue[i].text),Xoption);
      if (i==perspectiveBut && viewData.perspective)
        GDrawString(volumeGC,volumeWindow,
                    (control->buttonQueue[i]).buttonX +
                    centerX(volumeGC,"x",1,
                            (control->buttonQueue[i]).buttonWidth),
                    (control->buttonQueue[i]).buttonY +
                    centerY(volumeGC,(control->buttonQueue[i]).buttonHeight),
                    "x",1,Xoption);
      else if (i==clipRegionBut && viewData.clipbox)
        GDrawString(volumeGC,volumeWindow,
                    (control->buttonQueue[i]).buttonX +
                    centerX(volumeGC,"x",1,
                            (control->buttonQueue[i]).buttonWidth),
                    (control->buttonQueue[i]).buttonY +
                    centerY(volumeGC,(control->buttonQueue[i]).buttonHeight),
                    "x",1,Xoption);
      else if (i==clipSurfaceBut && viewData.clipStuff)
        GDrawString(volumeGC,volumeWindow,
                    (control->buttonQueue[i]).buttonX +
                    centerX(volumeGC,"x",1,
                            (control->buttonQueue[i]).buttonWidth),
                    (control->buttonQueue[i]).buttonY +
                    centerY(volumeGC,(control->buttonQueue[i]).buttonHeight),
                    "x",1,Xoption);

      break;

    case clipXBut:
      drawClipXBut();
      break;

    case clipYBut:
      drawClipYBut();
      break;

    case clipZBut:
      drawClipZBut();
      break;

    case frustrumBut:
      break;

    default:
      GDraw3DButtonOut(trashGC,volumeWindow,
                     (control->buttonQueue[i]).buttonX,
                     (control->buttonQueue[i]).buttonY,
                     (control->buttonQueue[i]).buttonWidth,
                     (control->buttonQueue[i]).buttonHeight,Xoption);
      s = (control->buttonQueue[i]).text;
      strlength = strlen(s);
      GSetForeground(trashGC,
                     (float)monoColor((control->buttonQueue[i]).textColor),Xoption);
      GDrawString(trashGC,volumeWindow,
                  (control->buttonQueue[i]).buttonX +
                  centerX(processGC,s,strlength,
                          (control->buttonQueue[i]).buttonWidth),
                  (control->buttonQueue[i]).buttonY +
                  centerY(processGC,(control->buttonQueue[i]).buttonHeight),
                  s,strlen(s),Xoption);
    }  /* switch */
  }  /* for i in volumeButtons */

  drawFrustrum();
  drawClipVolume();   /*** put in header ***/
  drawClipXBut();
  drawClipYBut();
  drawClipZBut();

} /* drawVolumePanel() */