1// @configure_input@ 2 3/**************************************************************************\ 4 * Copyright (c) Kongsberg Oil & Gas Technologies AS 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of the copyright holder nor the names of its 19 * contributors may be used to endorse or promote products derived from 20 * this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33\**************************************************************************/ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif // HAVE_CONFIG_H 38 39#include <Inventor/SbLinear.h> 40#include <Inventor/errors/SoDebugError.h> 41#include <Inventor/bundles/SoMaterialBundle.h> 42#include <Inventor/actions/SoGLRenderAction.h> 43#include <Inventor/actions/SoRayPickAction.h> 44#include <Inventor/actions/SoGetMatrixAction.h> 45#include <Inventor/actions/SoGetBoundingBoxAction.h> 46#include <Inventor/actions/SoHandleEventAction.h> 47#include <Inventor/elements/SoModelMatrixElement.h> 48#include <Inventor/elements/SoViewVolumeElement.h> 49#include <Inventor/misc/SoState.h> 50#include <Inventor/misc/SoChildList.h> 51 52#include <Inventor/@Gui@/common/gl.h> 53 54#include <Inventor/@Gui@/nodes/SoGuiPane.h> 55 56#define ZSCALE (1.0f) 57 58// ************************************************************************* 59 60// FIXME: can't cache model matrix like this - use in multiple scene 61// graphs doesn't work then... 62 63class Pane { 64public: 65 SbMatrix modelmatrix; 66 SbVec3f position; 67 SbVec2f raypickpos; 68 69}; 70 71// ************************************************************************* 72 73#define PRIVATE(obj) ((Pane *) obj->internals) 74 75SO_NODE_SOURCE(SoGuiPane); 76 77void 78SoGuiPane::initClass(void) 79{ 80 SO_NODE_INIT_CLASS(SoGuiPane, SoSeparator, "Separator"); 81} 82 83SoGuiPane::SoGuiPane(void) 84{ 85 this->internals = (void *) new Pane; 86 SO_NODE_CONSTRUCTOR(SoGuiPane); 87 SO_NODE_ADD_FIELD(worldSize, (SbVec3f(1.0f, 1.0f, 0.0f))); 88 SO_NODE_ADD_FIELD(objectSize, (SbVec3f(100.0f, 100.0f, 0.0f))); 89} 90 91SoGuiPane::~SoGuiPane(void) 92{ 93 Pane * obj = PRIVATE(this); 94 delete obj; 95 this->internals = NULL; 96} 97 98void 99SoGuiPane::doAction(SoAction * action) 100{ 101 SoState * state = action->getState(); 102 103 state->push(); 104 105 if ( state->isElementEnabled(SoModelMatrixElement::getClassStackIndex()) ) { 106 SbVec3f world = this->worldSize.getValue(); 107 SbVec3f object = this->objectSize.getValue(); 108 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 109 SoModelMatrixElement::scaleBy(state, this, scalefactor); 110 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 111 } 112 113 SbBool backface = FALSE; 114 if ( state->isElementEnabled(SoViewVolumeElement::getClassStackIndex()) ) { 115 SbVec3f normal(0.0f, 0.0f, 1.0f); 116 PRIVATE(this)->modelmatrix.multDirMatrix(normal, normal); 117 normal.normalize(); 118 SbVec3f campos = SoViewVolumeElement::get(state).getProjectionPoint(); 119 SbVec3f center = (SbVec3f(0.0f, 0.0f, 0.0f) + this->objectSize.getValue()) / 2.0f; 120 PRIVATE(this)->modelmatrix.multVecMatrix(center, center); 121 SbVec3f camdir = center - campos; 122 camdir.normalize(); 123 backface = (normal.dot(camdir) >= 0.0f) ? TRUE : FALSE; 124 } 125 126 if ( action->isOfType(SoHandleEventAction::getClassTypeId()) ) { 127 if ( backface ) { 128 // we don't react to events when facing away 129 goto culled; 130 } 131 } 132 133 if ( action->isOfType(SoRayPickAction::getClassTypeId()) ) { 134 SoRayPickAction * rpaction = (SoRayPickAction *) action; 135 rpaction->setObjectSpace(); 136 137 SbPlane plane(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f); 138 SbLine line(rpaction->getLine()); 139 // find intersection with SbPlane 140 SbVec3f point; 141 PRIVATE(this)->raypickpos.setValue(-1.0f, -1.0f); 142 if ( plane.intersect(line, point) ) { 143 SbVec3f object = this->objectSize.getValue(); 144 SbVec2f pos(point[0], point[1]); 145 if ( pos[0] < 0.0f || pos[1] < 0.0f || pos[0] > object[0] || pos[1] > object[1] ) { 146 goto culled; 147 } else { 148 PRIVATE(this)->raypickpos = pos; 149 } 150 } 151 else goto culled; 152 } 153 inherited::doAction(action); 154culled: 155 state->pop(); 156} 157 158void 159SoGuiPane::GLRenderBelowPath(SoGLRenderAction * action) 160{ 161 SoState * state = action->getState(); 162 state->push(); 163 164 SbVec3f world = this->worldSize.getValue(); 165 SbVec3f object = this->objectSize.getValue(); 166 167 // adjust scale for new object space 168 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 169 SoModelMatrixElement::scaleBy(state, this, scalefactor); 170 171 // store current model matrix 172 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 173 PRIVATE(this)->position = SbVec3f(0.0f, 0.0f, 0.0f); 174 175 176 SbVec3f normal(0.0f, 0.0f, 1.0f); 177 PRIVATE(this)->modelmatrix.multDirMatrix(normal, normal); 178 normal.normalize(); 179 180 SbVec3f campos = SoViewVolumeElement::get(state).getProjectionPoint(); 181 SbVec3f center = (SbVec3f(0.0f, 0.0f, 0.0f) + this->objectSize.getValue()) / 2.0f; 182 PRIVATE(this)->modelmatrix.multVecMatrix(center, center); 183 184 SbVec3f camdir = SoViewVolumeElement::get(state).getProjectionDirection(); 185 camdir = center - campos; 186 camdir.normalize(); 187 188 const float dot = normal.dot(camdir); 189 190 const SbBool backface = (dot >= 0.0f) ? TRUE : FALSE; 191 192 SoMaterialBundle mb(action); 193 mb.sendFirst(); 194 195 if ( object[0] != 0.0f && object[1] != 0.0f ) { // draw pane 196 if ( backface ) glNormal3f(0.0f, 0.0f, -1.0f); 197 else glNormal3f(0.0f, 0.0f, 1.0f); 198 glBegin(GL_QUADS); 199 glVertex3f(0.0f, 0.0f, 0.0f); 200 glVertex3f(0.0f, object[1], 0.0f); 201 glVertex3f(object[0], object[1], 0.0f); 202 glVertex3f(object[0], 0.0f, 0.0f); 203 glEnd(); // GL_QUADS 204 } 205 206 if ( backface ) goto finish; 207 208 glDisable(GL_DEPTH_TEST); 209 glDepthMask(FALSE); 210 211 // TODO: it would probably be a good idea to set up clipping around the pane 212 inherited::GLRenderBelowPath(action); 213 214 glDepthMask(TRUE); 215 glEnable(GL_DEPTH_TEST); 216 217finish: 218 state->pop(); 219} 220 221void 222SoGuiPane::GLRenderInPath(SoGLRenderAction * action) 223{ 224 SoDebugError::postInfo("SoGuiPane::GLRenderInPath", "implementation is out of date"); 225 SoState * state = action->getState(); 226 state->push(); 227 228 SbVec3f world = this->worldSize.getValue(); 229 SbVec3f object = this->objectSize.getValue(); 230 231 SoMaterialBundle mb(action); 232 mb.sendFirst(); 233 234 // draw pane 235 glBegin(GL_QUADS); 236 glVertex3f(0.0f, 0.0f, 0.0f); 237 glVertex3f(0.0f, world[1], 0.0f); 238 glVertex3f(world[0], world[1], 0.0f); 239 glVertex3f(world[0], 0.0f, 0.0f); 240 glEnd(); // GL_QUADS 241 242 // adjust scale for new object space 243 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 244 SoModelMatrixElement::scaleBy(state, this, scalefactor); 245 246 // store current model matrix 247 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 248 PRIVATE(this)->position = SbVec3f(0.0f, 0.0f, 0.0f); 249 250 GLint olddepthfunc = 0; 251 glGetIntegerv(GL_DEPTH_FUNC, &olddepthfunc); 252 glDepthFunc(GL_LEQUAL); 253 254 // FIXME: set up clipping around pane 255 inherited::GLRenderInPath(action); 256 257 glDepthFunc((GLenum) olddepthfunc); 258 state->pop(); 259} 260 261void 262SoGuiPane::GLRenderOffPath(SoGLRenderAction * action) 263{ 264 // is this one ever invoked? 265 SoDebugError::postInfo("SoGuiPane::GLRenderOffPath", "no implementation yet"); 266 inherited::GLRenderOffPath(action); 267} 268 269void 270SoGuiPane::pick(SoPickAction * action) 271{ 272 this->doAction(action); 273} 274 275void 276SoGuiPane::rayPick(SoRayPickAction * action) 277{ 278 this->doAction(action); 279} 280 281void 282SoGuiPane::getMatrix(SoGetMatrixAction * action) 283{ 284 SoDebugError::postInfo("SoGuiPane::getMatrix", "invoked"); 285 SbVec3f world = this->worldSize.getValue(); 286 SbVec3f object = this->objectSize.getValue(); 287 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 288 SbMatrix matrix = SbMatrix::identity(); 289 matrix.setScale(scalefactor); 290 action->getMatrix().multLeft(matrix); 291 // FIXME: update inverse matrix 292 inherited::getMatrix(action); 293} 294 295void 296SoGuiPane::handleEvent(SoHandleEventAction * action) 297{ 298 this->doAction(action); 299} 300 301void 302SoGuiPane::getBoundingBox(SoGetBoundingBoxAction * action) 303{ 304 SbVec3f min = SbVec3f(0.0f, 0.0f, 0.0f); 305 SbVec3f max = this->worldSize.getValue(); 306 min[2] = 0.0f; // -0.001f; 307 max[2] = 0.0f; // 0.001f; 308 SbBox3f box(min, max); 309 action->extendBy(box); 310} 311 312SbVec2f 313SoGuiPane::getRayPickIntersectionPoint(void) const 314{ 315 return PRIVATE(this)->raypickpos; 316} 317 318void 319SoGuiPane::moveTo(SoState * state, SbVec3f position) 320{ 321 SbVec3f object = this->objectSize.getValue(); 322 if ( position[0] < 0.0f ) position[0] = object[0] + position[0]; 323 if ( position[1] < 0.0f ) position[1] = object[1] + position[1]; 324 PRIVATE(this)->position = position; 325 SbVec3f translation(0.0f, 0.0f, 0.0f); 326 translation[0] = PRIVATE(this)->position[0]; 327 translation[1] = PRIVATE(this)->position[1]; 328 SoModelMatrixElement::set(state, this, PRIVATE(this)->modelmatrix); 329 // SoDebugError::postInfo("SoGuiPane::moveTo", "origo in %g %g", translation[0], translation[1]); 330 SoModelMatrixElement::translateBy(state, this, translation); 331} 332 333void 334SoGuiPane::applyMoveTo(SoGetMatrixAction * action, SbVec3f position) 335{ 336 // FIXME: support negative coordinates 337 SoDebugError::postInfo("SoGuiPane::applyMoveTo", "target %g %g", position[0], position[1]); 338 action->getMatrix() = PRIVATE(this)->modelmatrix; 339 SbMatrix matrix = SbMatrix::identity(); 340 matrix.setTranslate(position); 341 action->getMatrix().multLeft(matrix); 342 // FIXME: update inverse matrix 343} 344 345void 346SoGuiPane::moveBy(SoState * state, SbVec3f offset) 347{ 348 PRIVATE(this)->position += offset; 349 SbVec3f translation(0.0f, 0.0f, 0.0f); 350 translation[0] = PRIVATE(this)->position[0]; 351 translation[1] = PRIVATE(this)->position[1]; 352 SoModelMatrixElement::set(state, this, PRIVATE(this)->modelmatrix); 353 // SoDebugError::postInfo("SoGuiPane::moveBy", "origo in %g %g", translation[0], translation[1]); 354 SoModelMatrixElement::translateBy(state, this, translation); 355} 356 357void 358SoGuiPane::applyMoveBy(SoGetMatrixAction * action, SbVec3f offset) 359{ 360 SoDebugError::postInfo("SoGuiPane::applyMoveBy", "offset %g %g", offset[0], offset[1]); 361 action->getMatrix() = PRIVATE(this)->modelmatrix; 362 SbMatrix matrix = SbMatrix::identity(); 363 SbVec3f position = PRIVATE(this)->position + offset; 364 matrix.setTranslate(position); 365 action->getMatrix().multLeft(matrix); 366 // FIXME: update inverse matrix 367} 368 369#undef ZSCALE 370#undef PRIVATE 371 372