/* * * 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.1 $ | | 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 #endif #include #include #include "_SoXtColorWheel.h" #include "_SoXtUIRegion.h" #include #include #include #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; itype) { 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(); 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(); 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; isetHSVValue(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; jgetValue()); 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(); 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); } }