Hi Yücel,

On Sun, 2006-03-05 at 15:18 +0100, Yücel Ahi wrote:
> Hi,
> 
> I am using OpenSG V1.6.0 with the latest qt release 4.1.1 on my windows xp
> sp 2 machine and visual studio 2005. The problem that i have is, that the
> traverse() routine does not work for objects that are derived from QWidget.
> Here is my sample code:
> 
...
> 
> Please note that the class travstate is derived from Qwidget. Now i call the
> traverse() routine like this:
> 
> travstate t;
> traverse(some_node, osgTypedMethodFunctor1ObjPtrCPtrRef<Action::ResultE,
> travstate, NodePtr>(&t, &travstate::enterme));
> 
> But the enterme() method of t (of type travstate) is never invoked. When i
> for example derive from QObject instead of Qwidget than enterm() gets
> invoked.
> 
> Can anybody reproduce this ? Is this a problem of qt-4 or is it the same
> with qt-3 ?

I can't reproduce it on Linux with the attached code using Qt3. Can you
try that? It really makes very little sense that the baseclass would
make a difference...

        Dirk

// OpenSG Tutorial Example: Traverse & Attachments
//
// This example shows how to traverse the graph and work on each node. 
// The traverse() functions can be used for that. They need functors to pass
// the functions to be called around, which are also introduced here.
//
// It also shows how to downcast pointers in OpenSG to get from a generic
// pointer, e.g. a NodeCorePtr to the specific class, e.g. GeometryPtr.
//
// The graphical display is just for show, the interesting stuff is 
// printed to the console. ;)
//

// Headers
#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGSimpleGeometry.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGSimpleSceneManager.h>
#include <OpenSG/OSGBaseFunctions.h>
#include <OpenSG/OSGTransform.h>
#include <OpenSG/OSGGroup.h>

#include <qwidget.h>
#include <qobject.h>
#include <qapplication.h>

// new headers: 

// the Action header, containing the traverse() functions
#include <OpenSG/OSGAction.h>


// Activate the OpenSG namespace
OSG_USING_NAMESPACE

// a separate transformation for every object
TransformPtr cyltrans, tortrans;


// The SimpleSceneManager to manage simple applications
SimpleSceneManager *mgr;

// forward declaration so we can have the interesting stuff upfront
int setupGLUT( int *argc, char *argv[] );

// redraw the window
void display( void )
{
    // create the matrix
    Matrix m;
    Real32 t = glutGet(GLUT_ELAPSED_TIME );
    
    // set the transforms' matrices
    m.setTransform(Vec3f(      0,
                               0, 
                               osgsin(t / 1000.f) * 1.5),
                   Quaternion( Vec3f (1, 0, 0), 
                                      t / 500.f));

    beginEditCP(cyltrans, Transform::MatrixFieldMask);
    {
        cyltrans->setMatrix(m);
    }
    endEditCP  (cyltrans, Transform::MatrixFieldMask);
    
    
    m.setTransform(Vec3f(      osgsin(t / 2000.f), 
                               0, 
                               0),
                   Quaternion( Vec3f (0, 0, 1), 
                                      t / 2000.f));

    beginEditCP(tortrans, Transform::MatrixFieldMask);
    {
        tortrans->setMatrix(m);
    }
    endEditCP  (tortrans, Transform::MatrixFieldMask);
    
    mgr->redraw();
}


/* 
    The traverse() functions used below need a function that is called for
    every node encountered. There are two variants.
    
    One just calls one function when it enters the node. The other in addition
    calls another function when it leaves the node on the way up, i.e. after
    all children of the node have been processed.
    
    The return values define how the traversal continues after this function.
    
    Returning Action::Continue will just continue the traversal. Action::Skip
    will not go deeper but skip all children of this node (and their children
    etc.). Action::Quit will abort the traversal on the spot and just unwind
    the enters on the way up.
*/

// these are the trivial traversal function, they just print and return
Action::ResultE enter(NodePtr& node)
{   
    SLOG << "entering " << node << endLog;

    return Action::Continue; 
}

Action::ResultE leave(NodePtr& node, Action::ResultE res) 
{ 
    SLOG << "leaving " << node << ", got code " << res << endLog;

    // you should return the result that you're passed, to propagate Quits
    return res; 
}

// This is an example of a traversal state object

class travstate : public QWidget
{
  public:
  
    travstate( void ) : _indent(0) {}
    
    Action::ResultE enter(NodePtr& node)
    {
        for(UInt16 i = 0; i < _indent; i++)
            SLOG << "    ";

        SLOG << "entering " << node << endLog;

        ++_indent;
        return Action::Continue;        
    }
    
    Action::ResultE leave(NodePtr& node, Action::ResultE res)
    {
        --_indent;
        
        for(UInt16 i = 0; i < _indent; i++)
            SLOG << "    ";

        SLOG << "leaving " << node << endLog;

        // you should return the result that you're passed, to propagate Quits
        return res;        
    }
    
  private:
  
    UInt16 _indent;
};

// a traversal functions that does not descend below transformations

/*
    It also shows how to access the node core of a given node. After making
    sure that the core is indeed the expected type (using the isDerivedFrom())
    call use <FieldContainerTyep>Ptr::dcast() to downcast the core. ::dcast()
    acts comparable to dynamic_cast. dcast() works for all kinds of field
    containers and is not restricted to Nodes or NodeCores.
*/

Action::ResultE dontEnterTrans(NodePtr& node)
{   
    SLOG << "entering " << node << endLog;

    if(node->getCore()->getType().isDerivedFrom( Transform::getClassType()))
    {
        TransformPtr t = TransformPtr::dcast(node->getCore());
        
        SLOG << "derived from transform, skipping children" << endLog;
        SLOG << "Matrix: " << endLog << t->getMatrix();
        return Action::Skip;
    }   
    return Action::Continue; 
}


// a traversal functions that quits as soon as it finds a Geometry

/*
    This function uses the fact that ::dcast() acts like dynamic_cast. It tries
    to dcast the core to a GeometryPtr, and tests the result to see if it
    actually was derived from Geometry.
*/

Action::ResultE quitGeo(NodePtr& node)
{   
    SLOG << "entering " << node << endLog;

    GeometryPtr geo = GeometryPtr::dcast(node->getCore());
    
    if(geo!=NullFC)
    {
        SLOG << "derived from geometry, quitting" << endLog;
        return Action::Quit;
    }   
    return Action::Continue; 
}



// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
    QApplication qapp(argc,argv);
    
    // OSG init
    osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // the connection between GLUT and OpenSG
    GLUTWindowPtr gwin= GLUTWindow::create();
    gwin->setId(winid);
    gwin->init();

    // create the scene
    
    // create a pretty simple graph: a Group with two Transforms as children,
    // each of which carries a single Geometry.
    
    // The scene group
    
    NodePtr  scene = Node::create();
    GroupPtr g     = Group::create();
    
    beginEditCP(scene, Node::CoreFieldMask | Node::ChildrenFieldMask);
    scene->setCore(g);
    
    // The cylinder and its transformation
    NodePtr cyl = makeCylinder( 1.4, .3, 8, true, true, true );
        
    cyltrans = Transform::create();

    NodePtr cyltransnode = Node::create();
    beginEditCP(cyltransnode, Node::CoreFieldMask | Node::ChildrenFieldMask);
    {
        cyltransnode->setCore (cyltrans);
        cyltransnode->addChild(cyl     );
    }
    endEditCP  (cyltransnode, Node::CoreFieldMask | Node::ChildrenFieldMask);
    
    // add it to the scene
    scene->addChild(cyltransnode);
    
    // The torus and its transformation
    NodePtr torus = makeTorus( .2, 1, 8, 12 );
        
    tortrans = Transform::create();

    NodePtr tortransnode = Node::create();
    beginEditCP(tortransnode, Node::CoreFieldMask | Node::ChildrenFieldMask);
    {
        tortransnode->setCore (tortrans);
        tortransnode->addChild(torus   );
    }
    endEditCP  (tortransnode, Node::CoreFieldMask | Node::ChildrenFieldMask);
    
    // add it to the scene
    scene->addChild(tortransnode);

    // ok, scene done
    endEditCP(scene, Node::CoreFieldMask | Node::ChildrenFieldMask);
    
         
    // now traverse the scene
    
    /*
        There are four variants of the traverse() function.
        
        It can either be called for a single node or for a vector nodes. And
        they can either call a function just when entering the node, or in
        addition when leaving the node. The signatures of the functions are:
        
        enter functions: 
            Action::ResultE enter(NodePtr& node);
            
        leave functions: 
            Action::ResultE leave(NodePtr& node, Action::ResultE res);
       
        The functions that are called are wrapped in functors. A functor is an
        object that contains a function or method, which can be called through
        the functor. OpenSG supports two kinds of user functors: the function
        and method functors.
        
        A function functor is created using osgFunctionFunctorX(function),
        where X is the number of parameters of the function. 
        
        A method functor is a wrapped call to a method of a specific instance
        of a class. It is created using osgMethodFunctorXPtr(instance,
        method), again X being the number of parameters of the function. It's
        harder to explain than to understand what a method functor does, so
        just take a look at the examples below.
    */
/*     
    SLOG << "Variant 1: just print every encountered node" << endLog;
    traverse(scene, 
             osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
                                             NodePtr        >(enter));
     
    SLOG << endLog 
              << "Variant 2: just print every encountered node, using a" 
              << " vector of nodes" << endLog;
         
    std::vector<NodePtr> nodevec;
    nodevec.push_back(tortransnode);
    nodevec.push_back(cyltransnode);
    
    traverse(nodevec, 
             osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
                                             NodePtr        >(enter));
      
    SLOG << endLog 
              << "Variant 3: just print every encountered node on entering"
              << " and leaving" << endLog;

    traverse(scene, 
             osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
                                             NodePtr        >(enter), 
             osgTypedFunctionFunctor2CPtrRef<Action::ResultE,
                                             NodePtr,
                                             Action::ResultE>(leave));
*/       
    // now use a travstate object to hold additional data   
    travstate t;
    
    SLOG << endLog 
              << "Variant 4: use an object to hold state for indentation" 
              << endLog;
    traverse(scene, 
             osgTypedMethodFunctor1ObjPtrCPtrRef<Action::ResultE,
                                                 travstate,
                                                 NodePtr>(
                                                     &t, 
                                                     &travstate::enter));
 
/*      
    SLOG << endLog 
              << "Variant 5: don't descend into transforms" << endLog;
    traverse(scene, 
             osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
                                             NodePtr        >(dontEnterTrans), 
             osgTypedFunctionFunctor2CPtrRef<Action::ResultE,
                                             NodePtr,
                                             Action::ResultE>(leave         ));
      
    SLOG << endLog 
              << "Variant 6: quit when you find a geometry" << endLog;
    traverse(scene, 
             osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
                                             NodePtr        >(quitGeo), 
             osgTypedFunctionFunctor2CPtrRef<Action::ResultE,
                                             NodePtr,
                                             Action::ResultE>(leave  ));
    
*/ 
    // create the SimpleSceneManager helper
    mgr = new SimpleSceneManager;

    // tell the manager what to manage
    mgr->setWindow(gwin );
    mgr->setRoot  (scene);

    // show the whole scene
    mgr->showAll();

    // GLUT main loop
    glutMainLoop();

    return 0;
}

//
// GLUT callback functions
//

// react to size changes
void reshape(int w, int h)
{
    mgr->resize(w, h);
    glutPostRedisplay();
}

// react to mouse button presses
void mouse(int button, int state, int x, int y)
{
    if (state)
        mgr->mouseButtonRelease(button, x, y);
    else
        mgr->mouseButtonPress(button, x, y);
        
    glutPostRedisplay();
}

// react to mouse motions with pressed buttons
void motion(int x, int y)
{
    mgr->mouseMove(x, y);
    glutPostRedisplay();
}

// react to keys
void keyboard(unsigned char k, int x, int y)
{
    switch(k)
    {
        case 27:    
        {
            OSG::osgExit();
            exit(0);
        }
        break;
    }
}

// setup the GLUT library which handles the windows for us
int setupGLUT(int *argc, char *argv[])
{
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    
    int winid = glutCreateWindow("OpenSG");
    
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutKeyboardFunc(keyboard);

    // call the redraw function whenever there's nothing else to do
    glutIdleFunc(display);

    return winid;
}

Reply via email to