1// @configure_input@ 2 3/**************************************************************************\ 4 * 5 * This file is part of the Coin 3D visualization library. 6 * Copyright (C) by Kongsberg Oil & Gas Technologies. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * ("GPL") version 2 as published by the Free Software Foundation. 11 * See the file LICENSE.GPL at the root directory of this source 12 * distribution for additional information about the GNU GPL. 13 * 14 * For using Coin with software that can not be combined with the GNU 15 * GPL, and for taking advantage of the additional benefits of our 16 * support services, please contact Kongsberg Oil & Gas Technologies 17 * about acquiring a Coin Professional Edition License. 18 * 19 * See http://www.coin3d.org/ for more information. 20 * 21 * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. 22 * http://www.sim.no/ sales@sim.no coin-support@coin3d.org 23 * 24\**************************************************************************/ 25 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif // HAVE_CONFIG_H 29 30#include <Inventor/SbLinear.h> 31#include <Inventor/errors/SoDebugError.h> 32#include <Inventor/bundles/SoMaterialBundle.h> 33#include <Inventor/actions/SoGLRenderAction.h> 34#include <Inventor/actions/SoRayPickAction.h> 35#include <Inventor/actions/SoGetMatrixAction.h> 36#include <Inventor/actions/SoGetBoundingBoxAction.h> 37#include <Inventor/actions/SoHandleEventAction.h> 38#include <Inventor/elements/SoModelMatrixElement.h> 39#include <Inventor/elements/SoViewVolumeElement.h> 40#include <Inventor/misc/SoState.h> 41#include <Inventor/misc/SoChildList.h> 42 43#include <Inventor/@Gui@/common/gl.h> 44 45#include <Inventor/@Gui@/nodes/SoGuiPane.h> 46 47#define ZSCALE (1.0f) 48 49// ************************************************************************* 50 51// FIXME: can't cache model matrix like this - use in multiple scene 52// graphs doesn't work then... 53 54class Pane { 55public: 56 SbMatrix modelmatrix; 57 SbVec3f position; 58 SbVec2f raypickpos; 59 60}; 61 62// ************************************************************************* 63 64#define PRIVATE(obj) ((Pane *) obj->internals) 65 66SO_NODE_SOURCE(SoGuiPane); 67 68void 69SoGuiPane::initClass(void) 70{ 71 SO_NODE_INIT_CLASS(SoGuiPane, SoSeparator, "Separator"); 72} 73 74SoGuiPane::SoGuiPane(void) 75{ 76 this->internals = (void *) new Pane; 77 SO_NODE_CONSTRUCTOR(SoGuiPane); 78 SO_NODE_ADD_FIELD(worldSize, (SbVec3f(1.0f, 1.0f, 0.0f))); 79 SO_NODE_ADD_FIELD(objectSize, (SbVec3f(100.0f, 100.0f, 0.0f))); 80} 81 82SoGuiPane::~SoGuiPane(void) 83{ 84 Pane * obj = PRIVATE(this); 85 delete obj; 86 this->internals = NULL; 87} 88 89void 90SoGuiPane::doAction(SoAction * action) 91{ 92 SoState * state = action->getState(); 93 94 state->push(); 95 96 if ( state->isElementEnabled(SoModelMatrixElement::getClassStackIndex()) ) { 97 SbVec3f world = this->worldSize.getValue(); 98 SbVec3f object = this->objectSize.getValue(); 99 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 100 SoModelMatrixElement::scaleBy(state, this, scalefactor); 101 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 102 } 103 104 SbBool backface = FALSE; 105 if ( state->isElementEnabled(SoViewVolumeElement::getClassStackIndex()) ) { 106 SbVec3f normal(0.0f, 0.0f, 1.0f); 107 PRIVATE(this)->modelmatrix.multDirMatrix(normal, normal); 108 normal.normalize(); 109 SbVec3f campos = SoViewVolumeElement::get(state).getProjectionPoint(); 110 SbVec3f center = (SbVec3f(0.0f, 0.0f, 0.0f) + this->objectSize.getValue()) / 2.0f; 111 PRIVATE(this)->modelmatrix.multVecMatrix(center, center); 112 SbVec3f camdir = center - campos; 113 camdir.normalize(); 114 backface = (normal.dot(camdir) >= 0.0f) ? TRUE : FALSE; 115 } 116 117 if ( action->isOfType(SoHandleEventAction::getClassTypeId()) ) { 118 if ( backface ) { 119 // we don't react to events when facing away 120 goto culled; 121 } 122 } 123 124 if ( action->isOfType(SoRayPickAction::getClassTypeId()) ) { 125 SoRayPickAction * rpaction = (SoRayPickAction *) action; 126 rpaction->setObjectSpace(); 127 128 SbPlane plane(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f); 129 SbLine line(rpaction->getLine()); 130 // find intersection with SbPlane 131 SbVec3f point; 132 PRIVATE(this)->raypickpos.setValue(-1.0f, -1.0f); 133 if ( plane.intersect(line, point) ) { 134 SbVec3f object = this->objectSize.getValue(); 135 SbVec2f pos(point[0], point[1]); 136 if ( pos[0] < 0.0f || pos[1] < 0.0f || pos[0] > object[0] || pos[1] > object[1] ) { 137 goto culled; 138 } else { 139 PRIVATE(this)->raypickpos = pos; 140 } 141 } 142 else goto culled; 143 } 144 inherited::doAction(action); 145culled: 146 state->pop(); 147} 148 149void 150SoGuiPane::GLRenderBelowPath(SoGLRenderAction * action) 151{ 152 SoState * state = action->getState(); 153 state->push(); 154 155 SbVec3f world = this->worldSize.getValue(); 156 SbVec3f object = this->objectSize.getValue(); 157 158 // adjust scale for new object space 159 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 160 SoModelMatrixElement::scaleBy(state, this, scalefactor); 161 162 // store current model matrix 163 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 164 PRIVATE(this)->position = SbVec3f(0.0f, 0.0f, 0.0f); 165 166 167 SbVec3f normal(0.0f, 0.0f, 1.0f); 168 PRIVATE(this)->modelmatrix.multDirMatrix(normal, normal); 169 normal.normalize(); 170 171 SbVec3f campos = SoViewVolumeElement::get(state).getProjectionPoint(); 172 SbVec3f center = (SbVec3f(0.0f, 0.0f, 0.0f) + this->objectSize.getValue()) / 2.0f; 173 PRIVATE(this)->modelmatrix.multVecMatrix(center, center); 174 175 SbVec3f camdir = SoViewVolumeElement::get(state).getProjectionDirection(); 176 camdir = center - campos; 177 camdir.normalize(); 178 179 const float dot = normal.dot(camdir); 180 181 const SbBool backface = (dot >= 0.0f) ? TRUE : FALSE; 182 183 SoMaterialBundle mb(action); 184 mb.sendFirst(); 185 186 if ( object[0] != 0.0f && object[1] != 0.0f ) { // draw pane 187 if ( backface ) glNormal3f(0.0f, 0.0f, -1.0f); 188 else glNormal3f(0.0f, 0.0f, 1.0f); 189 glBegin(GL_QUADS); 190 glVertex3f(0.0f, 0.0f, 0.0f); 191 glVertex3f(0.0f, object[1], 0.0f); 192 glVertex3f(object[0], object[1], 0.0f); 193 glVertex3f(object[0], 0.0f, 0.0f); 194 glEnd(); // GL_QUADS 195 } 196 197 if ( backface ) goto finish; 198 199 glDisable(GL_DEPTH_TEST); 200 glDepthMask(FALSE); 201 202 // TODO: it would probably be a good idea to set up clipping around the pane 203 inherited::GLRenderBelowPath(action); 204 205 glDepthMask(TRUE); 206 glEnable(GL_DEPTH_TEST); 207 208finish: 209 state->pop(); 210} 211 212void 213SoGuiPane::GLRenderInPath(SoGLRenderAction * action) 214{ 215 SoDebugError::postInfo("SoGuiPane::GLRenderInPath", "implementation is out of date"); 216 SoState * state = action->getState(); 217 state->push(); 218 219 SbVec3f world = this->worldSize.getValue(); 220 SbVec3f object = this->objectSize.getValue(); 221 222 SoMaterialBundle mb(action); 223 mb.sendFirst(); 224 225 // draw pane 226 glBegin(GL_QUADS); 227 glVertex3f(0.0f, 0.0f, 0.0f); 228 glVertex3f(0.0f, world[1], 0.0f); 229 glVertex3f(world[0], world[1], 0.0f); 230 glVertex3f(world[0], 0.0f, 0.0f); 231 glEnd(); // GL_QUADS 232 233 // adjust scale for new object space 234 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 235 SoModelMatrixElement::scaleBy(state, this, scalefactor); 236 237 // store current model matrix 238 PRIVATE(this)->modelmatrix = SoModelMatrixElement::get(state); 239 PRIVATE(this)->position = SbVec3f(0.0f, 0.0f, 0.0f); 240 241 GLint olddepthfunc = 0; 242 glGetIntegerv(GL_DEPTH_FUNC, &olddepthfunc); 243 glDepthFunc(GL_LEQUAL); 244 245 // FIXME: set up clipping around pane 246 inherited::GLRenderInPath(action); 247 248 glDepthFunc((GLenum) olddepthfunc); 249 state->pop(); 250} 251 252void 253SoGuiPane::GLRenderOffPath(SoGLRenderAction * action) 254{ 255 // is this one ever invoked? 256 SoDebugError::postInfo("SoGuiPane::GLRenderOffPath", "no implementation yet"); 257 inherited::GLRenderOffPath(action); 258} 259 260void 261SoGuiPane::pick(SoPickAction * action) 262{ 263 this->doAction(action); 264} 265 266void 267SoGuiPane::rayPick(SoRayPickAction * action) 268{ 269 this->doAction(action); 270} 271 272void 273SoGuiPane::getMatrix(SoGetMatrixAction * action) 274{ 275 SoDebugError::postInfo("SoGuiPane::getMatrix", "invoked"); 276 SbVec3f world = this->worldSize.getValue(); 277 SbVec3f object = this->objectSize.getValue(); 278 SbVec3f scalefactor(world[0] / object[0], world[1] / object[1], ZSCALE); 279 SbMatrix matrix = SbMatrix::identity(); 280 matrix.setScale(scalefactor); 281 action->getMatrix().multLeft(matrix); 282 // FIXME: update inverse matrix 283 inherited::getMatrix(action); 284} 285 286void 287SoGuiPane::handleEvent(SoHandleEventAction * action) 288{ 289 this->doAction(action); 290} 291 292void 293SoGuiPane::getBoundingBox(SoGetBoundingBoxAction * action) 294{ 295 SbVec3f min = SbVec3f(0.0f, 0.0f, 0.0f); 296 SbVec3f max = this->worldSize.getValue(); 297 min[2] = 0.0f; // -0.001f; 298 max[2] = 0.0f; // 0.001f; 299 SbBox3f box(min, max); 300 action->extendBy(box); 301} 302 303SbVec2f 304SoGuiPane::getRayPickIntersectionPoint(void) const 305{ 306 return PRIVATE(this)->raypickpos; 307} 308 309void 310SoGuiPane::moveTo(SoState * state, SbVec3f position) 311{ 312 SbVec3f object = this->objectSize.getValue(); 313 if ( position[0] < 0.0f ) position[0] = object[0] + position[0]; 314 if ( position[1] < 0.0f ) position[1] = object[1] + position[1]; 315 PRIVATE(this)->position = position; 316 SbVec3f translation(0.0f, 0.0f, 0.0f); 317 translation[0] = PRIVATE(this)->position[0]; 318 translation[1] = PRIVATE(this)->position[1]; 319 SoModelMatrixElement::set(state, this, PRIVATE(this)->modelmatrix); 320 // SoDebugError::postInfo("SoGuiPane::moveTo", "origo in %g %g", translation[0], translation[1]); 321 SoModelMatrixElement::translateBy(state, this, translation); 322} 323 324void 325SoGuiPane::applyMoveTo(SoGetMatrixAction * action, SbVec3f position) 326{ 327 // FIXME: support negative coordinates 328 SoDebugError::postInfo("SoGuiPane::applyMoveTo", "target %g %g", position[0], position[1]); 329 action->getMatrix() = PRIVATE(this)->modelmatrix; 330 SbMatrix matrix = SbMatrix::identity(); 331 matrix.setTranslate(position); 332 action->getMatrix().multLeft(matrix); 333 // FIXME: update inverse matrix 334} 335 336void 337SoGuiPane::moveBy(SoState * state, SbVec3f offset) 338{ 339 PRIVATE(this)->position += offset; 340 SbVec3f translation(0.0f, 0.0f, 0.0f); 341 translation[0] = PRIVATE(this)->position[0]; 342 translation[1] = PRIVATE(this)->position[1]; 343 SoModelMatrixElement::set(state, this, PRIVATE(this)->modelmatrix); 344 // SoDebugError::postInfo("SoGuiPane::moveBy", "origo in %g %g", translation[0], translation[1]); 345 SoModelMatrixElement::translateBy(state, this, translation); 346} 347 348void 349SoGuiPane::applyMoveBy(SoGetMatrixAction * action, SbVec3f offset) 350{ 351 SoDebugError::postInfo("SoGuiPane::applyMoveBy", "offset %g %g", offset[0], offset[1]); 352 action->getMatrix() = PRIVATE(this)->modelmatrix; 353 SbMatrix matrix = SbMatrix::identity(); 354 SbVec3f position = PRIVATE(this)->position + offset; 355 matrix.setTranslate(position); 356 action->getMatrix().multLeft(matrix); 357 // FIXME: update inverse matrix 358} 359 360#undef ZSCALE 361#undef PRIVATE 362 363