SceneGraph.hh 24.8 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1 2 3
/*===========================================================================*\
 *                                                                           *
 *                              OpenFlipper                                  *
Jan Möbius's avatar
Jan Möbius committed
4
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
Jan Möbius's avatar
Jan Möbius committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *                           www.openflipper.org                             *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenFlipper.                                        *
 *                                                                           *
 *  OpenFlipper 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 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenFlipper 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.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenFlipper. If not,                                  *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
37
 *   $Revision$                                                       *
Jan Möbius's avatar
Jan Möbius committed
38 39 40 41
 *   $Author$                                                      *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/
Jan Möbius's avatar
 
Jan Möbius committed
42

Jan Möbius's avatar
Jan Möbius committed
43 44 45 46 47
/** \file SceneGraph.hh
 *
 *   This file contains the traversal functions used to apply actions to the SceneGraph.
 *
 */
Jan Möbius's avatar
 
Jan Möbius committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65


//=============================================================================
//
//  CLASS SceneGraph
//
//=============================================================================

#ifndef ACG_SCENEGRAPH_HH
#define ACG_SCENEGRAPH_HH


//== INCLUDES =================================================================

#include "BaseNode.hh"
#include "DrawModes.hh"
#include "../GL/gl.hh"
#include "../Math/VectorT.hh"
66
#include <cfloat>
Jan Möbius's avatar
 
Jan Möbius committed
67 68 69 70 71 72 73 74 75 76 77

#include <QMouseEvent>

//== NAMESPACES ===============================================================

namespace ACG {
namespace SceneGraph {


//== CLASS DEFINITION =========================================================

Jan Möbius's avatar
Dennis:  
Jan Möbius committed
78 79
/** Template functions to check if an action has enter or leave member functions
**/
Jan Möbius's avatar
 
Jan Möbius committed
80

Jan Möbius's avatar
Dennis:  
Jan Möbius committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
template<bool C, typename T = void>
struct enable_if {
  typedef T type;
};

template<typename T>
struct enable_if<false, T> { };

#define HAS_MEM_FUNC(func) \
    template<typename T, typename Sign>                                               \
    struct has_##func {                                                               \
        template <typename U, U> struct type_check;                                   \
        template <typename _1> static char (& chk(type_check<Sign, &_1::func> *))[1]; \
        template <typename   > static char (& chk(...))[2];                           \
        static bool const value = sizeof(chk<T>(0)) == 1;                             \
    };

HAS_MEM_FUNC(enter)

// if the enter function is implemented
101
template<typename Action>
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
102 103 104 105
typename enable_if<has_enter <Action, void (Action::*) (BaseNode *) >::value, void>::type
if_has_enter(Action &_action, BaseNode *_node) {
  _action.enter (_node);
}
Jan Möbius's avatar
 
Jan Möbius committed
106

Jan Möbius's avatar
Dennis:  
Jan Möbius committed
107
// if the enter function isn't implemented
108
template<typename Action>
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
109 110 111
typename enable_if<!has_enter <Action, void (Action::*) (BaseNode *) >::value, void>::type
if_has_enter(Action &, BaseNode *) {
}
Jan Möbius's avatar
 
Jan Möbius committed
112

Jan Möbius's avatar
Dennis:  
Jan Möbius committed
113 114 115
HAS_MEM_FUNC(leave)

// if the enter function is implemented
116
template<typename Action>
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
117 118 119 120 121 122
typename enable_if<has_leave <Action, void (Action::*) (BaseNode *) >::value, void>::type
if_has_leave(Action &_action, BaseNode *_node) {
  _action.leave (_node);
}

// if the enter function isn't implemented
123
template<typename Action>
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
124 125 126 127 128 129 130 131 132 133 134
typename enable_if<!has_enter <Action, void (Action::*) (BaseNode *) >::value, void>::type
if_has_leave(Action &, BaseNode *) {
}

//----------------------------------------------------------------------------


/** Traverse the scenegraph starting at the node \c _node and apply
    the action \c _action to each node. This traversal function will call the
    enter/leave functions of the action if they have been implemented.
**/
Jan Möbius's avatar
 
Jan Möbius committed
135 136
template <class Action>
void
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
137
traverse( BaseNode* _node, Action& _action )
Jan Möbius's avatar
 
Jan Möbius committed
138 139 140 141 142 143
{
  if (_node)
  {
    BaseNode::StatusMode status(_node->status());
    bool process_children(status != BaseNode::HideChildren);

Jan Möbius's avatar
Jan Möbius committed
144
    // If the subtree is hidden, ignore this node and its children while rendering
Jan Möbius's avatar
 
Jan Möbius committed
145 146 147
    if (status != BaseNode::HideSubtree)
    {

Jan Möbius's avatar
Jan Möbius committed
148
      // If the node itself is hidden, ignore it but continue with its children
Jan Möbius's avatar
 
Jan Möbius committed
149 150
      if (_node->status() != BaseNode::HideNode)
      {
Jan Möbius's avatar
Jan Möbius committed
151
        // Executes this nodes enter function (if available)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
152
        if_has_enter (_action, _node);
153

Jan Möbius's avatar
Jan Möbius committed
154
        // Test rendering order. If NodeFirst, execute this node and the children later.
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
155
        if (_node->traverseMode() & BaseNode::NodeFirst)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
156
          process_children &= _action(_node);
Jan Möbius's avatar
 
Jan Möbius committed
157 158 159 160
      }

      if (process_children)
      {
161

Jan Möbius's avatar
Dennis:  
Jan Möbius committed
162
        BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
163

Jan Möbius's avatar
Jan Möbius committed
164
        // Process all children which are not second pass
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
165
        for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
166
          if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
167
            traverse(*cIt, _action);
168

Jan Möbius's avatar
Jan Möbius committed
169
        // Process all children which are second pass
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
170 171
        for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
          if ((*cIt)->traverseMode() & BaseNode::SecondPass)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
172
            traverse(*cIt, _action);
173

Jan Möbius's avatar
 
Jan Möbius committed
174 175
      }

Jan Möbius's avatar
Jan Möbius committed
176
      // If the node is not hidden
Jan Möbius's avatar
 
Jan Möbius committed
177 178
      if (_node->status() != BaseNode::HideNode)
      {
179

Jan Möbius's avatar
Jan Möbius committed
180
        // If the children had to be rendered first, we now render the node afterwards
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
181
        if (_node->traverseMode() & BaseNode::ChildrenFirst)
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
182
          _action(_node);
183

Jan Möbius's avatar
Jan Möbius committed
184
        // Call the leave function of the node.
Jan Möbius's avatar
Dennis:  
Jan Möbius committed
185
        if_has_leave (_action, _node);
Jan Möbius's avatar
 
Jan Möbius committed
186
      }
187

Jan Möbius's avatar
 
Jan Möbius committed
188 189 190 191
    }
  }
}

192 193 194 195 196 197 198
//---------------------------------------------------------------------------------

/** Traverse the scenegraph starting at the node \c _node and apply
    the action \c _action to each node. This traversal function will call the
    enter/leave functions of the action if they have been implemented.
    This function traverses the scene graph multiple times if multipass
    rendering is turned on. GLState holds attributes to control
199 200 201 202 203
    render passes. Attention: Render passes are 1-indexed.\n
    
    !!! You should ot use this function directly. Use the traverse_multipass function
    which controls the glstate too. This function will also manage the passes for you!!!
    
204 205 206
**/
template <class Action>
void
207
traverse_multipass ( BaseNode* _node, Action& _action, const unsigned int& _pass )
208
{
209
  
210 211 212 213 214 215 216 217
    // Process node if it exists
    if (_node) {
        BaseNode::StatusMode status(_node->status());
        bool process_children(status != BaseNode::HideChildren);

        // If the subtree is hidden, ignore this node and its children while rendering
        if (status != BaseNode::HideSubtree) {

218
            // Executes this nodes enter function (if available and active in multipass)
219
            if ( _node->multipassStatusActive(_pass) ) {
220
              if_has_enter(_action, _node);
221
            }
222

223 224 225 226 227
            // If the node itself is hidden, don't call the action on it.
            // Additionally check if rendering order is node first. otherwise, we will call it after the children.
            // And check if it should be called in this rendering pass.
            if ( (_node->status() != BaseNode::HideNode )  && ( _node->traverseMode() & BaseNode::NodeFirst ) && _node->multipassNodeActive(_pass))
                process_children &= _action(_node);
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

            if (process_children) {

                BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());

                // Process all children
                for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
                    if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
                        traverse_multipass(*cIt, _action, _pass);

                // Process all children which are second pass
                for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
                    if ((*cIt)->traverseMode() & BaseNode::SecondPass)
                        traverse_multipass(*cIt, _action, _pass);

            }

245 246 247 248 249 250
            
            // If we are in childrenfirst node, the children have been painted andwe now check, if we can draw this node.
            // If its hidden, ignore it.
            // If it should not be rendered in this pass, ignore it too.
            if ( (_node->traverseMode() & BaseNode::ChildrenFirst ) && (_node->status() != BaseNode::HideNode) && _node->multipassNodeActive(_pass) )
                _action(_node);
251

252 253 254
            // Call the leave function of the node (if available and active in multipass).
            if ( _node->multipassStatusActive(_pass) )
              if_has_leave(_action, _node);
255 256 257 258 259

        } // if (status != BaseNode::HideSubtree)
    } // if(node_)
}

Jan Möbius's avatar
 
Jan Möbius committed
260 261 262

//----------------------------------------------------------------------------

263 264 265 266 267
/** Traverse the scenegraph starting at the node \c _node and apply
    the action \c action to each node. When arriving at a node, its
    BaseNode::enter() function is called, then \c _action is applied
    and the node's children are traversed. After that the
    BaseNode::leave() method is called. Do this in multiple passes.
268 269 270 271 272 273
    
    <b>You have to initialize glstate before doing this:</b>\n
    In the state you give here use GLState::set_max_render_passes to
    set the maximum number of renderpasses that should be performed.
    This is not computed here, as the number only changes if the scenegraph
    is changed and not for all render calls.
274 275 276 277 278 279

    \see ACG::SceneGraph::BaseNode
**/

template <class Action>
void
Jan Möbius's avatar
Jan Möbius committed
280 281 282
traverse_multipass( BaseNode*           _node,
                    Action&             _action,
                    GLState&            _state,
Dirk Wilden's avatar
Dirk Wilden committed
283
                    DrawModes::DrawMode /*_drawmode*/=DrawModes::DEFAULT)
284 285 286 287 288 289 290 291
{
    // Reset render pass counter
    _state.reset_render_pass();

    // Get max render passes
    unsigned int max_passes = _state.max_render_passes();

    // Render all passes
Jan Möbius's avatar
Jan Möbius committed
292
    for(unsigned int pass = BaseNode::PASS_1; pass <= (BaseNode::PASS_1 + max_passes); ++pass) {
293 294

        // Traverse scenegraph
295
        traverse_multipass (_node, _action, pass);
296 297 298 299 300 301 302 303 304
        // Increment render pass counter by 1
        _state.next_render_pass();
    }

    // Reset render pass counter
    _state.reset_render_pass();
}

//--------------------------------------------------------------------------------
Jan Möbius's avatar
 
Jan Möbius committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318

/** Collect bounding box information from all nodes, using the
    BaseNode::boundingBox() method. The result can be accessed by
    bbMin() and bbMax(), yielding the 2 extreme corners of the bounding box.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/
class BoundingBoxAction
{
public:

  BoundingBoxAction() :
    bbMin_( FLT_MAX,  FLT_MAX,  FLT_MAX),
319 320 321
    bbMax_(-FLT_MAX, -FLT_MAX, -FLT_MAX),
    state_(false)
  { }
Jan Möbius's avatar
 
Jan Möbius committed
322 323 324

  bool operator()(BaseNode* _node)
  {
325 326
    Vec3d bbMin( FLT_MAX,  FLT_MAX,  FLT_MAX);
    Vec3d bbMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
Jan Möbius's avatar
Jan Möbius committed
327 328 329 330 331 332 333 334 335 336 337
    _node->boundingBox(bbMin, bbMax);

    if ((bbMin[0] > bbMax[0]) ||
        (bbMin[1] > bbMax[1]) ||
        (bbMin[2] > bbMax[2]))
      return true;

    bbMin_.minimize(state_.modelview().transform_point (bbMin));
    bbMin_.minimize(state_.modelview().transform_point (bbMax));
    bbMax_.maximize(state_.modelview().transform_point (bbMin));
    bbMax_.maximize(state_.modelview().transform_point (bbMax));
Jan Möbius's avatar
 
Jan Möbius committed
338 339 340
    return true;
  }

Jan Möbius's avatar
Jan Möbius committed
341 342 343 344 345 346 347 348 349 350
  void enter (BaseNode *_node)
  {
    _node->enter(state_, DrawModes::DEFAULT);
  }

  void leave (BaseNode *_node)
  {
    _node->leave(state_, DrawModes::DEFAULT);
  }

Jan Möbius's avatar
 
Jan Möbius committed
351
  /// Returns minimum point of the bounding box
352
  const Vec3d& bbMin() const { return bbMin_; }
Jan Möbius's avatar
 
Jan Möbius committed
353
  /// Returns maximum point of the bounding box
354
  const Vec3d& bbMax() const { return bbMax_; }
Jan Möbius's avatar
 
Jan Möbius committed
355 356 357

private:

358
  Vec3d        bbMin_, bbMax_;
Jan Möbius's avatar
Jan Möbius committed
359
  GLState      state_;
Jan Möbius's avatar
 
Jan Möbius committed
360 361 362
};


363 364 365 366
//-----------------------------------------------------------------------------


/** Get the maximum number of render passes that will be used
367 368 369
    to render the scene graph. multipassStatus() and multipassNode return
    a bit mask of length 32 that holds 1 at position i if the node will be 
    i-th drawn in the i-th render pass.
370 371 372 373 374 375 376

    So if renderPass() == 0x00...001011, the node will be drawn
    during render pass 1, 2 and 4.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/
377
class MultiPassInfoAction
378 379 380
{
public:

381
  MultiPassInfoAction() :
Jan Möbius's avatar
Jan Möbius committed
382 383
    statusPasses_(BaseNode::ALLPASSES),
    nodePasses_(BaseNode::ALLPASSES)
384
  {}
385 386 387

  bool operator()(BaseNode* _node) {

388 389 390 391 392 393 394 395 396
      // Get status pass 
      BaseNode::MultipassBitMask statusPass = _node->multipassStatus();

      // Ignore if set to ALLPASSES as we want to get the real maximum pass number
      if ( statusPass != BaseNode::ALLPASSES) {
        // Convert render pass bit mask to
        // decimal value (0x001011 -> 4)
        // Note: Same as (int)log2(bitmask)
        unsigned int c = 0;
Jan Möbius's avatar
Jan Möbius committed
397 398 399 400 401
        
        // Skip the first one as this is the ALLPASSES flag
        statusPass = statusPass >> 1;
        
        while( statusPass != 0u ) {
402 403 404
          statusPass = statusPass >> 1;
          ++c;
        }
405
        statusPasses_ = c > statusPasses_ ? c : statusPasses_;
406 407
      }
      
408
      
409 410 411 412 413 414 415 416 417
      // Get Node pass 
      BaseNode::MultipassBitMask nodePass = _node->multipassNode();
      
      // Ignore if set to ALLPASSES as we want to get the real maximum pass number
      if ( nodePass != BaseNode::ALLPASSES) {
        // Convert render pass bit mask to
        // decimal value (0x001011 -> 4)
        // Note: Same as (int)log2(bitmask)
        unsigned int c = 0;
Jan Möbius's avatar
Jan Möbius committed
418 419 420 421
        
        // Skip the first one as this is the ALLPASSES flag
        nodePass = nodePass >> 1;
        
422 423
        while(nodePass != 0u) {
          nodePass = nodePass >> 1;
424
          ++c;
425
        }
426
        nodePasses_ = c > nodePasses_ ? c : nodePasses_;
427 428 429 430 431
      }

      return true;
  }

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
  /** \brief Get the number of required traverse passes from Scenegraph
  *
  * This number is the maximum of status and node passes required.
  */
  unsigned int getMaxPasses() const { 
    unsigned int maxpasses = std::max(statusPasses_,nodePasses_);
    
    // if maxpasses is 0 we have all nodes in ALLPASSES mode so we render only once
    return maxpasses == 0 ? 1 : maxpasses; 
  }

  /** \brief Get the number of required status traversals from Scenegraph
  *
  * This number is the number of requried status passes required.
  */
  unsigned int getStatusPasses() { return statusPasses_ == 0 ? 1 : statusPasses_; };
  
  /** \brief Get the number of required node traversals from Scenegraph
  *
  * This number is the of required node passes.
  */
  unsigned int getNodePasses() { return nodePasses_ == 0 ? 1 : nodePasses_; };
454 455 456

private:

457 458 459
  unsigned int statusPasses_;
  unsigned int nodePasses_;
  
460 461 462
};


Jan Möbius's avatar
 
Jan Möbius committed
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
//----------------------------------------------------------------------------


/** This action is used to find the node specified by \c _node_id in a
    scenegraph. The result can be accessed by node_ptr() and is 0 if
    no node with BaseNode::id() equal to \c _node_id has been found.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class FindNodeAction
{
public:

  /// constructor: _node_id is the node to be searched for
  FindNodeAction(unsigned int _node_id) :
    node_id_(_node_id), node_ptr_(0)  {}

  bool operator()(BaseNode* _node)
  {
    if (_node->id() == node_id_)
    {
      node_ptr_ = _node;
      return false;
    }
    return true;
  }

  /// Get the pointer of the node (is 0 if node was not found)
  BaseNode*  node_ptr() { return node_ptr_; }

private:

  unsigned int  node_id_;
  BaseNode*     node_ptr_;
};


Jan Möbius's avatar
Jan Möbius committed
502
ACGDLLEXPORT
Jan Möbius's avatar
 
Jan Möbius committed
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
BaseNode* find_node( BaseNode* _root, unsigned int _node_idx );


//----------------------------------------------------------------------------


/** This action collects the draw modes available in a scenegraph.
    The result is the logical \c OR of all nodes'
    BaseNode::availableDrawModes() and can be accessed by drawModes().

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class CollectDrawModesAction
{
public:

Jan Möbius's avatar
Jan Möbius committed
521
  CollectDrawModesAction() : drawModes_(DrawModes::NONE) {}
Jan Möbius's avatar
 
Jan Möbius committed
522 523 524 525 526 527 528 529

  bool operator()(BaseNode* _node)
  {
    drawModes_ |= _node->availableDrawModes();
    return true;
  }

  /// Get the collected draw modes
Jan Möbius's avatar
Jan Möbius committed
530
  DrawModes::DrawMode drawModes() const { return drawModes_; }
Jan Möbius's avatar
 
Jan Möbius committed
531 532 533

private:

Jan Möbius's avatar
Jan Möbius committed
534
  DrawModes::DrawMode drawModes_;
Jan Möbius's avatar
 
Jan Möbius committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
};

//----------------------------------------------------------------------------


/** This action collects the activated draw modes available in a scenegraph.
    The result is the logical \c OR of all activated draw modes in the nodes'
    BaseNode::drawMode() and can be accessed by drawMode().

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class CollectActiveDrawModesAction
{
public:

Jan Möbius's avatar
Jan Möbius committed
552
  CollectActiveDrawModesAction() : drawMode_(DrawModes::NONE) {}
Jan Möbius's avatar
 
Jan Möbius committed
553 554 555 556 557 558 559 560

  bool operator()(BaseNode* _node)
  {
    drawMode_ |= _node->drawMode();
    return true;
  }

  /// Get the collected draw modes
Jan Möbius's avatar
Jan Möbius committed
561
  DrawModes::DrawMode drawMode() const { return drawMode_; }
Jan Möbius's avatar
 
Jan Möbius committed
562 563 564

private:

Jan Möbius's avatar
Jan Möbius committed
565
  DrawModes::DrawMode drawMode_;
Jan Möbius's avatar
 
Jan Möbius committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
};

//----------------------------------------------------------------------------


/** This action sets the draw mode on all nodes in a scenegraph.
    If the drawMode is not supported by the node, it will set it to default
    draw mode. If the given mode is the default mode it will be set on all
    nodes.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class SetDrawModesAction
{
public:

584 585 586 587 588 589 590 591 592
  /** \brief Set draw modes for all nodes traversed with this action
  *
  * This action can be used to set the drawmodes for all nodes which
  * are traversed using this action. 
  *
  * @param _mode  The draw mode set for the traversed nodes
  * @param _force If true, the mode is set ignoring if its supported by the nodes
  */
  SetDrawModesAction(DrawModes::DrawMode _mode, bool _force = false ) : newModes_(_mode),force_(_force) {}
Jan Möbius's avatar
 
Jan Möbius committed
593 594 595 596 597 598

  bool operator()(BaseNode* _node)
  {
    if ( newModes_ == DrawModes::DEFAULT )
      _node->drawMode( DrawModes::DEFAULT );

Jan Möbius's avatar
Jan Möbius committed
599
    DrawModes::DrawMode availableModes = _node->availableDrawModes();
Jan Möbius's avatar
 
Jan Möbius committed
600

601 602 603 604 605
    if ( force_ ) {
      // if force, we ignore if the mode is supported by the node and set it
      _node->drawMode( newModes_ );
    } else if ( availableModes & newModes_ ) {
      // If its supported, we set it
Jan Möbius's avatar
 
Jan Möbius committed
606
      _node->drawMode( availableModes & newModes_ );
607 608
    } else {
      // otherwise we switch the node to default draw mode (which will use the global mode)
Jan Möbius's avatar
 
Jan Möbius committed
609
      _node->drawMode( DrawModes::DEFAULT );
610 611 612
    }
    
    
Jan Möbius's avatar
 
Jan Möbius committed
613 614 615 616
    return true;
  }

private:
Jan Möbius's avatar
Jan Möbius committed
617
  DrawModes::DrawMode newModes_;
618 619
  bool                force_; 
  
Jan Möbius's avatar
 
Jan Möbius committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
};


//----------------------------------------------------------------------------


/** This action is used to traverse and draw a scenegraph using the
    draw mode specified in the constructor.
    Specify if you want to draw solid or transparent objects.
    Needs GLState.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class DrawAction
{
public:

  /// Constructor: draws the scenegraph using _drawMode
640 641 642 643
  DrawAction(DrawModes::DrawMode _drawMode, GLState& _state, bool _blending) : 
     state_(_state),
     drawMode_(_drawMode), 
     blending_(_blending) {}
Jan Möbius's avatar
 
Jan Möbius committed
644

645
  bool operator()( BaseNode* _node )
Jan Möbius's avatar
 
Jan Möbius committed
646 647
  {
    // draw only if Material status == DrawAction status
648
    if(state_.blending() == blending_)
Jan Möbius's avatar
 
Jan Möbius committed
649 650 651
    {
      _node->setDirty (false);
      if (_node->drawMode() == DrawModes::DEFAULT)
652
        _node->draw(state_, drawMode_);
Jan Möbius's avatar
 
Jan Möbius committed
653
      else
654
        _node->draw(state_, _node->drawMode());
Jan Möbius's avatar
 
Jan Möbius committed
655 656 657
    }
    return true;
  }
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
  
  void enter(BaseNode* _node)
  {
    if (_node->drawMode() == DrawModes::DEFAULT)
      _node->enter(state_, drawMode_);
    else
      _node->enter(state_, _node->drawMode());
  }
  
  void leave(BaseNode* _node)
  {
    if (_node->drawMode() == DrawModes::DEFAULT)
      _node->leave(state_, drawMode_);
    else
      _node->leave(state_, _node->drawMode());
  }
Jan Möbius's avatar
 
Jan Möbius committed
674 675 676

private:

677
  GLState&            state_;
Jan Möbius's avatar
Jan Möbius committed
678 679
  DrawModes::DrawMode drawMode_;
  bool                blending_;
Jan Möbius's avatar
 
Jan Möbius committed
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
};


//----------------------------------------------------------------------------


/** This action is used to pick an object in a scene. All GL states
    for picking must be set before using this action. It merely draws the
    scene AND uses the picking name stack. Needs GLState.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class ACGDLLEXPORT PickAction
{
public:

  /// constructor: what picking target to use
Jan Möbius's avatar
Jan Möbius committed
699
  PickAction(GLState &_state, PickTarget _target, DrawModes::DrawMode _drawmode) :
Jan Möbius's avatar
Jan Möbius committed
700 701
    state_(_state),
    pickTarget_(_target),
702
    drawmode_(_drawmode) {}
Jan Möbius's avatar
 
Jan Möbius committed
703

704 705
  /** Action applied to the node
  */
Jan Möbius's avatar
Jan Möbius committed
706
  bool operator()(BaseNode* _node);
707 708 709 710 711
  
  /** Action applied to the node
   *  Convenience operator which is used to handle calls with internal/external stack with the same operator
   */
  bool operator()(BaseNode* _node, GLState& _state);
Jan Möbius's avatar
Jan Möbius committed
712 713 714 715 716 717

  void enter(BaseNode* _node)
  {
    if (_node->drawMode() == DrawModes::DEFAULT)
        _node->enterPick(state_, pickTarget_, drawmode_);
      else
718
        _node->enterPick(state_, pickTarget_, _node->drawMode());
Jan Möbius's avatar
Jan Möbius committed
719 720 721 722 723 724 725 726 727
  }

  void leave(BaseNode* _node)
  {
    if (_node->drawMode() == DrawModes::DEFAULT)
        _node->leavePick(state_, pickTarget_, drawmode_);
      else
        _node->leavePick(state_, pickTarget_, _node->drawMode());
  }
Jan Möbius's avatar
 
Jan Möbius committed
728 729 730

private:

Jan Möbius's avatar
Jan Möbius committed
731 732 733
  GLState             &state_;
  PickTarget          pickTarget_;
  DrawModes::DrawMode drawmode_;
Jan Möbius's avatar
 
Jan Möbius committed
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
};


//----------------------------------------------------------------------------


/** This action is used to give mouse events to scenegraph nodes like e.g.
    the manipulator nodes.

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class MouseEventAction
{
public:


752 753 754
  MouseEventAction(QMouseEvent* _event, GLState& _state) : 
    state_(_state),
    event_(_event) {}
Jan Möbius's avatar
 
Jan Möbius committed
755

756
  bool operator()(BaseNode* _node )
Jan Möbius's avatar
 
Jan Möbius committed
757
  {
758
    _node->mouseEvent(state_, event_);
Jan Möbius's avatar
 
Jan Möbius committed
759 760 761 762
    return true;
  }

private:
763
  GLState&     state_;
Jan Möbius's avatar
 
Jan Möbius committed
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
  QMouseEvent* event_;
};

//----------------------------------------------------------------------------


/** This action is used to check if one or more does of the scenegraph need
    to be redrawn

    \note This class implements an action that should be used as a
    parameter for the traverse() functions.
**/

class CheckDirtyAction
{
public:


  CheckDirtyAction() : dirty_(false) {}

  bool operator()(BaseNode* _node)
  {
    dirty_ |= _node->isDirty();
    // don't traverse children if current node is _dirty
    return !dirty_;
  }

  bool isDirty() const { return dirty_; };

private:

  bool dirty_;
};


//=============================================================================
} // namespace SceneGraph
} // namespace ACG
//=============================================================================
#endif // ACG_SCENEGRAPH_HH defined
//=============================================================================