File: [Development] / inventor / libSoXt / src / mixedMode / SoXtColWheel.c++ (download)
Revision 1.2, Sun Sep 17 07:53:27 2000 UTC (17 years, 1 month ago) by jlim
Branch: MAIN
Changes since 1.1: +17 -5
lines
Workaround for glXChooseVisual() bug on some systems where a doublebuffer
visual is returned even when not requested. This occasionally prevented sliders
from being displayed (identified by Dennis Mikkelson).
|
/*
*
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/*
* Copyright (C) 1990-93 Silicon Graphics, Inc.
*
_______________________________________________________________________
______________ S I L I C O N G R A P H I C S I N C . ____________
|
| $Revision: 1.2 $
|
| Classes:
| _SoXtColorWheel
|
| Author(s) : Alain Dumesny
|
______________ S I L I C O N G R A P H I C S I N C . ____________
_______________________________________________________________________
*/
#if DEBUG
#include <stream.h>
#endif
#include <inttypes.h>
#include <Inventor/Xt/devices/SoXtMouse.h>
#include "_SoXtColorWheel.h"
#include "_SoXtUIRegion.h"
#include <malloc.h>
#include <math.h>
#include <GL/gl.h>
#ifndef __sgi
#define fcos cos
#define fsin sin
#define fsqrt sqrt
#endif
/*
* Defines
*/
#define CIRCLE 5
#define STRIPES 32
#define SPACE 3
#define MARKER_SLOT 3
#define myMapcolor(i, r, g, b) \
XColor col; \
col.red = r << 8; \
col.green = g << 8; \
col.blue = b << 8; \
col.flags = DoRed | DoGreen | DoBlue; \
col.pixel = i; \
XStoreColor(getDisplay(), overlayColorMap, &col);
////////////////////////////////////////////////////////////////////////
//
// Public constructor - build the widget right now
//
_SoXtColorWheel::_SoXtColorWheel(
Widget parent,
const char *name,
SbBool buildInsideParent)
: SoXtGLWidget(
parent,
name,
buildInsideParent,
SO_GLX_RGB | SO_GLX_OVERLAY,
FALSE) // tell GLWidget not to build just yet
//
////////////////////////////////////////////////////////////////////////
{
// In this case, this component is what the app wants, so buildNow = TRUE
constructorCommon(TRUE);
}
////////////////////////////////////////////////////////////////////////
//
// SoEXTENDER constructor - the subclass tells us whether to build or not
//
_SoXtColorWheel::_SoXtColorWheel(
Widget parent,
const char *name,
SbBool buildInsideParent,
SbBool buildNow)
: SoXtGLWidget(
parent,
name,
buildInsideParent,
SO_GLX_RGB | SO_GLX_OVERLAY,
FALSE) // tell GLWidget not to build just yet
//
////////////////////////////////////////////////////////////////////////
{
// In this case, this component may be what the app wants,
// or it may want a subclass of this component. Pass along buildNow
// as it was passed to us.
constructorCommon(buildNow);
}
////////////////////////////////////////////////////////////////////////
//
// Called by the constructors
//
// private
//
void
_SoXtColorWheel::constructorCommon(SbBool buildNow)
//
//////////////////////////////////////////////////////////////////////
{
mouse = new SoXtMouse(ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
// init local vars
WYSIWYGmode = FALSE;
hsvColor[0] = hsvColor[1] = 0.0;
hsvColor[2] = 1.0;
setGlxSize( SbVec2s(100, 100) ); // default size
// callback lists
startCallbacks = new SoCallbackList;
changedCallbacks = new SoCallbackList;
finishCallbacks = new SoCallbackList;
interactive = FALSE;
// allocate memory for the geometry/colors
int num = 1 + CIRCLE * (STRIPES + 1);
geometry = (SbVec2f *)malloc(num * sizeof(SbVec2f));
defaultColors = (SbColor *)malloc(num * sizeof(SbColor));
colors = (SbColor *)malloc(num * sizeof(SbColor));
// ??? reset the geometry to prevent the window manager under PI a362
// ??? to be killed (redrawing occurs even when window hasn't been
// ??? mapped yet so those values would be bogus)
for (int i=0; i<num; i++)
geometry[i].setValue(0,0);
// make the full intensity colors
makeWheelColors(defaultColors, 1.0);
// Build the widget tree, and let SoXtComponent know about our base widget.
if (buildNow) {
Widget w = buildWidget(getParentWidget());
setBaseWidget(w);
}
}
////////////////////////////////////////////////////////////////////////
//
// Destructor.
//
_SoXtColorWheel::~_SoXtColorWheel()
//
////////////////////////////////////////////////////////////////////////
{
if (geometry != NULL)
free(geometry);
if (defaultColors != NULL)
free(defaultColors);
if (colors != NULL)
free(colors);
delete startCallbacks;
delete changedCallbacks;
delete finishCallbacks;
delete mouse;
}
////////////////////////////////////////////////////////////////////////
//
// This routine redraws the normal plane color wheel region.
//
// Use: virtual public
void
_SoXtColorWheel::redraw()
//
////////////////////////////////////////////////////////////////////////
{
if (! isVisible())
return;
glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
// make a complete drawing
drawWheelSurrounding();
drawWheelColors();
if (isDoubleBuffer())
glXSwapBuffers(getDisplay(), getNormalWindow());
else
glFlush();
}
////////////////////////////////////////////////////////////////////////
//
// This routine redraws the color wheel overlay region (marker).
//
// Use: virtual public
void
_SoXtColorWheel::redrawOverlay()
//
////////////////////////////////////////////////////////////////////////
{
drawWheelMarker();
}
////////////////////////////////////////////////////////////////////////
//
// Process the passed X event.
//
// Use: virtual public
void
_SoXtColorWheel::processEvent(XAnyEvent *xe)
//
////////////////////////////////////////////////////////////////////////
{
short x, y;
XButtonEvent *be;
XMotionEvent *me;
SbVec2s size = getGlxSize();
switch (xe->type) {
case ButtonPress:
be = (XButtonEvent *) xe;
if (be->button == Button1) {
// check if click is in color wheel
x = short(be->x) - cx;
y = short(size[1] - be->y) - cy;
if ((x*x + y*y) < ((radius+5)*(radius+5))) {
startCallbacks->invokeCallbacks(hsvColor);
interactive = TRUE;
moveWheelMarker(x, y);
}
}
break;
case ButtonRelease:
be = (XButtonEvent *) xe;
if (be->button == Button1 && interactive) {
interactive = FALSE;
finishCallbacks->invokeCallbacks(hsvColor);
}
break;
case MotionNotify:
me = (XMotionEvent *) xe;
if (me->state & Button1Mask)
moveWheelMarker(short(me->x) - cx, short(size[1] - me->y) - cy);
break;
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine sets the color wheel current color.
//
// usage: public
void
_SoXtColorWheel::setBaseColor(
const float hsv[3])
//
////////////////////////////////////////////////////////////////////////
{
// check for redraw needs first
SbBool valueChanged = (hsvColor[2] != hsv[2]);
SbBool redrawColors = (WYSIWYGmode && valueChanged);
SbBool redrawMarker = (hsvColor[0]!=hsv[0] || hsvColor[1]!=hsv[1]);
// assign new color
hsvColor[0] = hsv[0];
hsvColor[1] = hsv[1];
hsvColor[2] = hsv[2];
// do wheel colors redraw
if (redrawColors) {
makeWheelColors(colors, hsv[2]);
if (! isVisible())
return;
glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
drawWheelColors();
if (isDoubleBuffer())
glXSwapBuffers(getDisplay(), getNormalWindow());
else
glFlush();
checkMarkerColor();
}
// do marker redraw
if (redrawMarker)
drawWheelMarker();
if (redrawMarker || valueChanged)
changedCallbacks->invokeCallbacks(hsvColor);
}
////////////////////////////////////////////////////////////////////////
//
// This routine sets the WYSIWYG mode.
//
// usage: public
void
_SoXtColorWheel::setWYSIWYG(SbBool flag)
//
////////////////////////////////////////////////////////////////////////
{
if (WYSIWYGmode == flag)
return;
WYSIWYGmode = flag;
// build WYSIWYG colors
if (WYSIWYGmode)
makeWheelColors(colors, hsvColor[2]);
// now check if a redraw is needed
if (hsvColor[2] != 1.0) {
if (! isVisible())
return;
glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
drawWheelColors();
if (isDoubleBuffer())
glXSwapBuffers(getDisplay(), getNormalWindow());
else
glFlush();
checkMarkerColor();
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This builds the parent Glx widget, then registers interest
// in mouse events.
//
// Use: protected
Widget
_SoXtColorWheel::buildWidget(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
Widget mgr = SoXtGLWidget::buildWidget(parent);
Widget w = getOverlayWidget() ? getOverlayWidget() : getNormalWidget();
mouse->enable(w,
(XtEventHandler) SoXtGLWidget::eventHandler,
(XtPointer) this);
return mgr;
}
////////////////////////////////////////////////////////////////////////
//
// This routine is called at window creation time to init the GL state
//
// Use: virtual protected
void
_SoXtColorWheel::initOverlayGraphic()
//
////////////////////////////////////////////////////////////////////////
{
myMapcolor(MARKER_SLOT, 0, 0, 0);
blackMarker = TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// This routine is called when window changed size.
//
// Use: virtual private
void
_SoXtColorWheel::sizeChanged(const SbVec2s &newSize)
//
////////////////////////////////////////////////////////////////////////
{
//
// recompute things that depend on window size
//
short min = (newSize[0] < newSize[1]) ? newSize[0] : newSize[1];
radius = (min - (4*UI_THICK + 2*SPACE)) / 2;
cx = newSize[0] / 2;
cy = newSize[1] / 2;
makeWheelGeometry();
// reset projection
glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
glViewport(0, 0, newSize[0], newSize[1]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, newSize[0], 0, newSize[1], -1, 1);
if (getOverlayWindow() != 0) {
glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
glViewport(0, 0, newSize[0], newSize[1]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, newSize[0], 0, newSize[1], -1, 1);
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine computes the color wheel geometry.
//
// Use: private
void
_SoXtColorWheel::makeWheelGeometry()
//
////////////////////////////////////////////////////////////////////////
{
SbVec2f *v = geometry;
float c[STRIPES+1][2];
int i, j;
// makes the master circle
float r = radius / float(CIRCLE);
float angle = 2.0 * M_PI / float(STRIPES);
c[0][0] = c[STRIPES][0] = r;
c[0][1] = c[STRIPES][1] = 0.0;
for (i=1; i<STRIPES; i++) {
c[i][0] = r * fcos(i*angle);
c[i][1] = r * fsin(i*angle);
}
//
// now build the color wheel geometry
//
// center point
(*v)[0] = cx;
(*v++)[1] = cy;
for (j=1; j<=CIRCLE; j++) {
for (i=0; i<=STRIPES; i++) {
(*v)[0] = cx + j * c[i][0];
(*v++)[1] = cy + j * c[i][1];
}
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine computes the color wheel colors given a color
// intensity.
//
// Use: private
void
_SoXtColorWheel::makeWheelColors(
SbColor *c,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
float hsv[3];
float Hinc, Sinc;
int i, j;
hsv[2] = intensity;
Hinc = 1.0 / float(STRIPES);
Sinc = 1.0 / float(CIRCLE);
// center color
(*c)[0] = (*c)[1] = (*c)[2] = intensity; c++;
//
// now make the wheel colors
//
for (j=1; j<=CIRCLE; j++) {
hsv[1] = j * Sinc;
for (i=0; i<STRIPES; i++) {
hsv[0] = i * Hinc;
(c++)->setHSVValue(hsv);
}
// last color is same as first color
(*c)[0] = (*(c-STRIPES))[0];
(*c)[1] = (*(c-STRIPES))[1];
(*c)[2] = (*(c-STRIPES))[2];
c++;
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine draws the color wheel surroundings.
//
// Use: private
void
_SoXtColorWheel::drawWheelSurrounding()
//
////////////////////////////////////////////////////////////////////////
{
glClearColor(.66, .66, .66, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// draw outer border
SbVec2s size = getGlxSize();
SoDrawDownUIBorders(0, 0, size[0]-1, size[1]-1);
}
////////////////////////////////////////////////////////////////////////
//
// This routine draws the color wheel top part (colors).
//
// Use: private
void
_SoXtColorWheel::drawWheelColors()
//
////////////////////////////////////////////////////////////////////////
{
SbColor *c1, *c2;
SbVec2f *v1, *v2;
int i, j;
//
// draw center circle as triangle fan
//
c1 = (WYSIWYGmode) ? colors : defaultColors;
v1 = geometry;
glBegin(GL_TRIANGLE_FAN);
for (i=0; i<(STRIPES+2); i++) {
glColor3fv((c1++)->getValue());
glVertex2fv((v1++)->getValue());
}
glEnd();
//
// draw the remaining stripes as quad meshes
//
c1 = (WYSIWYGmode) ? colors : defaultColors;
v1 = geometry;
c1++; v1++;
c2 = c1 + STRIPES + 1;
v2 = v1 + STRIPES + 1;
for (j=1; j<CIRCLE; j++) {
glBegin(GL_QUAD_STRIP);
for (i=0; i<=STRIPES; i++) {
glColor3fv((c1++)->getValue());
glVertex2fv((v1++)->getValue());
glColor3fv((c2++)->getValue());
glVertex2fv((v2++)->getValue());
}
glEnd();
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine checks the marker color and changes it if needed.
//
// Use: private
void
_SoXtColorWheel::checkMarkerColor()
//
////////////////////////////////////////////////////////////////////////
{
if (getOverlayWindow() == 0)
return;
// map a black or white color depending on background
if (WYSIWYGmode && hsvColor[2]<0.6) { // should be white
if (blackMarker) {
glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
myMapcolor(MARKER_SLOT, 255, 255, 255);
blackMarker = FALSE;
}
}
else { // should be black
if (!blackMarker) {
glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
myMapcolor(MARKER_SLOT, 0, 0, 0);
blackMarker = TRUE;
}
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine draws the color marker feedback (in overlay).
//
// Use: private
void
_SoXtColorWheel::drawWheelMarker()
//
////////////////////////////////////////////////////////////////////////
{
if (getOverlayWindow() == 0 || ! isVisible())
return;
glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
// find radius and angle from hsv color, from which position is determined.
short x, y;
float rad = hsvColor[1] * radius;
float angle = 2.0 * M_PI * hsvColor[0];
x = cx + short(rad * fcos(angle));
y = cy + short(rad * fsin(angle));
//
// now draw dot in overlay plane
//
glClearIndex(0);
glClear(GL_COLOR_BUFFER_BIT);
glIndexi(MARKER_SLOT);
// ??? doing a GL_LINE_LOOP seems to be missing the top right
// ??? pixel due to subpixel == TRUE in openGL.
glBegin(GL_LINE_STRIP);
glVertex2s(x+3, y+3); glVertex2s(x+3, y-3);
glVertex2s(x-3, y-3); glVertex2s(x-3, y+3);
glVertex2s(x+3+1, y+3);
glEnd();
if (isDoubleBuffer())
glXSwapBuffers(getDisplay(), getNormalWindow());
else
glFlush();
}
////////////////////////////////////////////////////////////////////////
//
// This routine moves the color maker based of mouse position.
//
// Use: private
//
void
_SoXtColorWheel::moveWheelMarker(
short x, short y) // wheel center relative coordinates
//
////////////////////////////////////////////////////////////////////////
{
// find the saturation based on distance
float s = fsqrt(x*x + y*y) / float(radius);
if (s > 1.0)
s = 1.0;
// now find the hue based on the angle
float angle = atan2(float(y), float(x));
if (angle < 0.0)
angle += 2.0 * M_PI;
float h = angle / (2.0 * M_PI);
// check if redraw and callback are needed
if (hsvColor[0] != h || hsvColor[1] != s) {
hsvColor[0] = h;
hsvColor[1] = s;
drawWheelMarker();
changedCallbacks->invokeCallbacks(hsvColor);
}
}