Group Node Children

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Arclamp
Posts: 71
Joined: Thu Oct 10, 2013 7:45 pm

Group Node Children

Post by Arclamp »

Is there an existing way to distinguish if an ISceneNode has been added as a child or just parented?, e.g. isRealChild(), isChild()...

Code: Select all

 
#include <iostream>
 
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
 
IrrlichtDevice* device;
IVideoDriver* driver;
ISceneManager* smgr;
IGUIEnvironment* env;
 
 
 
namespace irr
{
    namespace scene
    {
        enum ESCENE_NODE_TYPE_EXTRA
        {
            ESNT_GROUP           = MAKE_IRR_ID('g','r','u','p')
        };
    }
}
 
enum RXKeyStates { KSTATE_UP, KSTATE_DOWN, KSTATE_HELD, KSTATE_RELEASED };
 
 
 
//  GROUP NODE (based on CEmptySceneNode)
class CMyGroupSceneNode : public scene::ISceneNode
{
public:
 
    //! constructor
    CMyGroupSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id)
//      : ISceneNode(parent, mgr, id)
        : ISceneNode((parent ? parent : mgr->getRootSceneNode()), mgr, id)  //  Else a NULL parent crashes it
    {
        #ifdef _DEBUG
        setDebugName("CMyGroupSceneNode");
        #endif
        
        setAutomaticCulling(scene::EAC_OFF);
        
        Box.reset(getPosition());   //  Reset size to a single point, a better way?
    }
    
    //! returns the axis aligned bounding box of this node
    virtual const core::aabbox3d<f32>& getBoundingBox() const
    {
        return Box;
    }
    
    //! This method is called just before the rendering process of the whole scene.
    virtual void OnRegisterSceneNode()
    {
        if (IsVisible)
            SceneManager->registerNodeForRendering(this);
 
        ISceneNode::OnRegisterSceneNode();
    }
    
    //! does nothing.
    virtual void render()
    {
        // do nothing
    }
    
    //! Returns type of the scene node
    //virtual ESCENE_NODE_TYPE getType() const { return ESNT_EMPTY; }
    virtual ESCENE_NODE_TYPE getType() const { return (ESCENE_NODE_TYPE)ESNT_GROUP; }
    
    //! Creates a clone of this scene node and its children.
    virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0)
    {
        if (!newParent)
            newParent = Parent;
        if (!newManager)
            newManager = SceneManager;
 
        CMyGroupSceneNode* nb = new CMyGroupSceneNode(newParent, newManager, ID);
 
        nb->cloneMembers(this, newManager);
        nb->Box = Box;
 
        if ( newParent )
            nb->drop();
        return nb;
    }
    
private:
    
    core::aabbox3d<f32> Box;
};
 
 
 
//  EVENT RECEIVER
class MyEventReceiver : public IEventReceiver
{
public:
    MyEventReceiver(scene::ISceneManager* smgr)
        : SceneManager(smgr)
        , SelectedNode(0), LastSelectedNode(0)
    {
        //  GET SCENE MANAGER
        SceneManager->grab();
        
        //  INIT KEY ARRAY
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
            KeyIsDown[i] = KSTATE_UP;
        
    }
 
    virtual ~MyEventReceiver()
    {
        SceneManager->drop();
    }
    
    virtual bool OnEvent(const SEvent& event)
    {
        if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
        {
            //  MOUSE LEFT BUTTON
            const core::position2di pos(event.MouseInput.X, event.MouseInput.Y);
            SelectedNode = SceneManager->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(pos);
            
            std::cout << "Object ID: " << SelectedNode->getID() << std::endl;
            
            ISceneNode *p = SelectedNode->getParent();
            if(p != NULL)
            {
                if(p->getType() == (ESCENE_NODE_TYPE)ESNT_GROUP)
                {
                    std::cout << "Found GROUP CHILD object" << std::endl;
                }
            }
            
            
            if(LastSelectedNode == SelectedNode){
                std::cout << "Clicked current object" << std::endl;
            }
            
            LastSelectedNode = SelectedNode;
            return false;
            
        }
        else if (event.EventType == irr::EET_KEY_INPUT_EVENT){
            //  KEYS... 0=up,1=down,2=hold,3=release
            if(event.KeyInput.PressedDown){ //  PRESSED DOWN
                if(KeyIsDown[event.KeyInput.Key]==KSTATE_UP){   KeyIsDown[event.KeyInput.Key]=KSTATE_DOWN;  }   //  INITIAL DOWN
            }else{  //  PRESSED UP
                KeyIsDown[event.KeyInput.Key]=KSTATE_RELEASED;  //  RELEASED
            }
        }
 
        return false;
    }
    
    virtual void cycle_end(){
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i){
            //KeyIsDown[i] = false;
            if(KeyIsDown[i]==KSTATE_DOWN){ KeyIsDown[i]=KSTATE_HELD;    }
            else if(KeyIsDown[i]==KSTATE_RELEASED){ KeyIsDown[i]=KSTATE_UP; }
        }
    }
    
    // This is used to check whether a key is being held down
    virtual s32 getKey(EKEY_CODE keyCode) const{
        return KeyIsDown[keyCode];      //  KEYS... 0=up,1=down,2=hold,3=release
    }
 
private:
    scene::ISceneManager* SceneManager;
    s32 KeyIsDown[KEY_KEY_CODES_COUNT];
public:
    scene::ISceneNode* SelectedNode;
    scene::ISceneNode* LastSelectedNode;
};
 
 
 
void node_anim(ISceneNode *node, core::vector3df offset=core::vector3df(0,0.5f,0), u32 t=250, bool loop=true, bool ping=true)
{
    if(node)
    {
        scene::ISceneNodeAnimator* anim = NULL;
        anim = smgr->createFlyStraightAnimator(node->getPosition(), node->getPosition()+offset, t, loop, ping);
        if(anim)
        {
            node->addAnimator(anim);
            anim->drop();
        }
    }
}
 
scene::ISceneNode *add_node(io::path s_mesh, io::path s_tex, scene::ISceneNode *parent, vector3df pos=vector3df(0.0f), vector3df scale=vector3df(1.0f), vector3df rot=vector3df(0.0f), s32 id=-1)
{
    
    scene::IAnimatedMesh* mesh = smgr->getMesh(s_mesh);
    //scene::ISceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
    scene::IAnimatedMeshSceneNode *node = smgr->addAnimatedMeshSceneNode(mesh, NULL, id);
    
    node->setMaterialTexture(0, driver->getTexture(s_tex));
    
    if(parent)
    {
        node->setParent(parent);
    }
    
    node->setScale(scale);
    node->setPosition(pos);
    node->setRotation(rot);
    
    node->getMaterial(0).Shininess = 2.0f;
    //node->getMaterial(0).SpecularColor.set(0,0,0,0);
    node->getMaterial(0).Lighting = true;
    
    //  SET SHADOWS
    bool cast_shadows= true;
    if(cast_shadows){
        ((scene::IAnimatedMeshSceneNode*)node)->addShadowVolumeSceneNode();
        ((scene::IAnimatedMeshSceneNode*)node)->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);    //  TODO:   only required if scale not 1,1,1
    }
    
    return node;
}
 
 
 
void test_00()
{
    
    ISceneNode *node0 = new CMyGroupSceneNode(NULL, smgr, 303);
    
    node0->drop();
    
    node0->setPosition(vector3df(0.0f));
    node0->setScale(vector3df(1.0f));
    node0->setRotation(vector3df(0.0f));
    
    
    scene::ISceneNode *node1 = add_node("media/box_a_chamfer2.dae", "media/textures.png", NULL, vector3df(4.0f, 0.0f, 0.0f), vector3df(1.0f), vector3df(0.0f), 304);
    scene::ISceneNode *node2 = add_node("media/box_a_chamfer2.dae", "media/textures.png", NULL, vector3df(4.0f, 0.0f, -4.0f), vector3df(1.0f), vector3df(0.0f), 305);
    
    node0->addChild(node1);
    node0->addChild(node2);
    
    //  BOUNCERS
    node_anim(node0);
    //node_anim(node1);
}
 
 
int main()
{
    
    bool shadows = true;
    bool fullscreen = false;
    device = createDevice(video::EDT_OPENGL, dimension2d<u32>(800, 480), 24, fullscreen, shadows, false);
    if (device == 0)
        return 1; // could not create selected driver.
    driver = device->getVideoDriver();
    smgr = device->getSceneManager();
    env = device->getGUIEnvironment();
    
    MyEventReceiver receiver(smgr);
    device->setEventReceiver(&receiver);
    
    
    IGUISkin* skin = env->getSkin();
    IGUIFont* font = env->getFont("media/fonthaettenschweiler.bmp");
    if (font)
        skin->setFont(font);
 
    skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);
    
    
    //  LIGHTS
    smgr->setShadowColor(video::SColor(150,0,0,0));
    smgr->setAmbientLight(video::SColorf(0.8f,0.8f,0.8f,1));        //  r,g,b,a
    
    smgr->addLightSceneNode(0, core::vector3df(-20,10,-20), video::SColorf(0.3f,0.3f,0.3f), 100.0f, 1);
    
    ILightSceneNode* light1 = smgr->addLightSceneNode(0, core::vector3df(-20,1,20), video::SColorf(1.0f,0.3f,0.3f), 100.0f, 1);
    light1->enableCastShadow(false);
    
    //  GROUND
    //scene::ISceneNode *node0 = 
    add_node("media/box_a_chamfer.dae", "media/textures.png", NULL, vector3df(0.0f, -0.5f, 0.0f), vector3df(20.0f, 0.1f, 20.0f), vector3df(0.0f), 111);
    
    
    //  CAM
    ICameraSceneNode* cam = smgr->addCameraSceneNode();
    cam->setTarget(vector3df(0,0,0));   //  cube->getPosition());
    cam->setPosition(vector3df(5,5,5));
    //cam->setPosition(vector3df(50,50,50));
    
    //  GUI
    //env->addStaticText(L"Hello", core::rect<s32>(10,10,790,50), false, false, NULL, -1, true);
    
    
    //  TEST
    test_00();
    
    
    bool run = true;
    while(device && device->run() && run)
    {
        if(device->isWindowActive())
        {
            
            if(receiver.getKey(irr::KEY_ESCAPE)==KSTATE_RELEASED)
                run = false;
        
            driver->beginScene(true, true, video::SColor(0,55,55,55));
            smgr->drawAll();
            env->drawAll();
            driver->endScene();
            
            receiver.cycle_end();
              
        }else{
            device->yield();
        }
    }
    device->drop();
}
 
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Group Node Children

Post by CuteAlien »

Not sure if I understand the question (and a lot of code - so not sure which part I should look at?).
Parents/childs are about the scenegraph. Once a node is added to the scenegraph it's always at least below the root which you can get with ISceneManager.:getRootSceneNode(). So you can compare the parent of nodes to getRootSceneNode if you want to know if a node is at the top. If that is what you wanted?
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Group Node Children

Post by Mel »

You can check the parent pointer of the node and you can check in a node its child list, so searching there can help you determine what you're looking for. Keep in mind that for scene traversal purposes, every node has, if no other is specified, as parent the scene manager, which is the root node as well.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Arclamp
Posts: 71
Joined: Thu Oct 10, 2013 7:45 pm

Re: Group Node Children

Post by Arclamp »

OK, so the scenario, er, to create a node which has / controls numerous sub nodes, say a chess board. AND when a sub node is clicked, its the "board" node ID which is returned.

Currently, I check to see if the triggering node (or returned node as with ray cast) has a parent of certain type. I was wondering if there was an existing / internal way to distinguish between a node which had been parented and a node which had been added as a child. i.e. distinguish the cuckoo adopted kids who tap their mates parents generosity and the genuine biological article?

Code: Select all

 
void info(ISceneNode *node, core::stringc name)
{
    std::cout << "Node " << name.c_str() << " has " << (node->getParent() ? "a" : "no") << " parent" << std::endl;
    std::cout << "Node " << name.c_str() << " has " << node->getChildren().size() << " children" << std::endl;
    
    core::list<ISceneNode*> c =  node->getParent()->getChildren();
    std::cout << "Node " << name.c_str() << "'s parent has " << c.size() << " children" << std::endl;
    for(core::list<ISceneNode*>::Iterator iter=c.begin (); iter != c.end(); ++iter)
    {
        if(*iter == node)
        {
            std::cout << "Node " << name.c_str() << " is listed as a child" << std::endl;
        }
    }
}
 
void test_00()
{
    ISceneNode *A = smgr->addCubeSceneNode();
    ISceneNode *B = smgr->addCubeSceneNode();
    ISceneNode *C = smgr->addCubeSceneNode();
    ISceneNode *D = smgr->addCubeSceneNode();
    
    //  ADD CHILD
    A->addChild(B);
    
    //  MAKE PARENT
    D->setParent(C);
    
    info(A, "A");
    info(B, "B");
    info(C, "C");
    info(D, "D");
}
 
Too tired, I'll try and make sense soon lol! Thanks
kornwaretm
Competition winner
Posts: 189
Joined: Tue Oct 16, 2007 3:53 am
Location: Indonesia
Contact:

Re: Group Node Children

Post by kornwaretm »

not sure what you want, but to check parent child relation rather than iterating a node's children you can do the opposite compare the pointer to the parent node.

Code: Select all

 
boo isParentChild(ISceneNode *suspectParent, ISceneNode *suspectChild)
{
       return suspectChild->getParent() == suspectParent;
}
 
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Group Node Children

Post by Mel »

Irrlicht supports picking up nodes which match a certain identifier mask, so using masks you can make sure a node is a parent, or a child, for instance. You can give an identifier (ISceneNode::setIdentifier(s32 id);) to your chess board, say 0x800, and give the pieces an identifier which ranges from 0x100 to 0x11f, then, using as mask 0x1ff will always give you a child node.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Post Reply