Hi, I'm having a problem to design my project. I'm using open scene graph to render the 3D representation. I have an osg:Group (eg. MyGroup) object that will become a leaf node / child of the root node. Inside the osg::Group object, I've got multiple osg::Node objects (eg. MyNodeA, MyNodeB, etc) as the leaf nodes / children. Now, one of the osg::Node objects depends on another osg::Node's attribute for rendering. I need some of the attributes of the other osg::Node to be sent as a uniform value of the shader.
My question is, how do I design this? I've got a few ideas. The first one that came out of my mind is by doing cyclic dependencies like this pseudo code:
Code:
MyGroup.h
#include "MyNodeA.h"
#include "MyNodeB.h"
#include ...
class MyGroup:: public osg::Group
{
...
public:
//Mutators & accessors
void setNodeA(const MyNodeA* node);
MyNodeA* getNodeA( ) const;
void setNodeB(const MyNodeB* node);
MyNodeB* getNodeB( ) const;
void setNodeB(const MyNodeC* node);
MyNodeB* getNodeC( ) const;
private:
MyNodeA* mNodeA;
MyNodeB* mNodeB;
MyNodeC* mNodeC;
}
----------------------
MyGroup.cpp
#include "MyGroup.h"
#include ...
...
----------------------
MyNodeA.h
#include "MyNodeB.h"
#include "MyNodeC.h"
class MyGroup; //< Forward decl
class MyNodeA:: public osg::Node
{
public:
//Mutators & accessors
void setGroup(const MyGroup* group);
MyGroup* getGroup( ) const;
void checkNodeB();
void updateUniformVals(const MyNodeB* nodeB);
void checkNodeC();
void updateUniformVals(const MyNodeC* nodeC);
private:
MyGroup* mGroup;
}
----------------------
MyNodeA.cpp
#include "MyGroup.h"
#include "MyNodeA.h"
#include ...
...
void MyNodeA::checkNodeB()
{
updateUniformVals(getGroup()->getNodeB());
}
void MyNodeA::updateUniformVals(const MyNodeB* nodeB)
{
....
}
void MyNodeA::checkNodeC()
{
updateUniformVals(getGroup()->getNodeC());
}
void MyNodeA::updateUniformVals(const MyNodeC* nodeC)
{
....
}
The second one is by using the observer pattern:
Code:
Observer.h
class Subject;
class iObserver
{
public:
virtual void update(Subject* subject) = 0;
}
----------------------
Subject.h
#include <vector>
#include "Observer.h"
class Subject
{
private:
vector<iObserver*> vecObservers;
public:
attach(iObserver& obs);
detach(iObserver& obs);
void notify(); //calls vecObservers[i]->update(this);
}
----------------------
MyGroup.h
#include "MyNodeA.h"
#include "MyNodeB.h"
#include "MyNodeC.h"
#include ...
class MyGroup: public osg::Group
{
...
public:
MyGroup(MyNodeA* nodeA, MyNodeB* nodeA, MyNodeC* nodeA)
{
mObserverAB = new RenderStateObserverAB(nodeA, nodeB);
mObserverAC = new RenderStateObserverAB(nodeA, nodeC);
nodeA->attach(mObserverAB);
nodeA->attach(mObserverAC);
nodeB->attach(mObserverAB);
nodeC->attach(mObserverAC);
}
private:
RenderStateObserverAB *mObserverAB; //< observer between AB
RenderStateObserverAC *mObserverAC; //< observer between AC
}
----------------------
MyGroup.cpp
#include "MyGroup.h"
#include ...
....
-----------------
RenderStateObserverAB.h
#include "Observer.h"
#include "MyNodeA.h"
#include "MyNodeB.h"
class RenderStateObserverAB: public iObserver
{
...
public:
RenderStateObserverAB(MyNodeA* nodeA, MyNodeB* nodeA)
{
mNodeA = nodeA;
mNodeB = nodeB;
}
virtual void update(Subject* subject)
{
MyNodeA->updateUniformVals(mNodeB);
}
private:
MyNodeA *mNodeA;
MyNodeB *mNodeB;
}
-----------------
RenderStateObserverAB.h
#include "Observer.h"
#include "MyNodeA.h"
#include "MyNodeB.h"
class RenderStateObserverAB: public iObserver
{
...
public:
RenderStateObserverAC(MyNodeA* nodeA, MyNodeC* nodeC)
{
mNodeA = nodeA;
mNodeC = nodeC;
}
virtual void update(Subject* subject)
{
MyNodeA->updateUniformVals(mNodeC);
}
private:
MyNodeA *mNodeA;
MyNodeC *mNodeC;
}
----------------------
MyNodeA.h
#include "Subject.h"
#include "MyNodeB.h"
#include "MyNodeC.h"
class MyGroup; //< Forward decl
class MyNodeA:: public osg::Node, Subject
{
...
public:
void updateUniformVals(const MyNodeB* nodeB);
void updateUniformVals(const MyNodeC* nodeC);
private:
...
}
----------------------
MyNodeA.cpp
#include "MyNodeA.h"
#include ...
...
void MyNodeA::updateUniformVals(const MyNodeB* nodeB)
{
....
}
void MyNodeA::updateUniformVals(const MyNodeC* nodeC)
{
....
}
I know that those two approach is not entirely good. Heck, I don't even know if I've used the Observer pattern right or not here. Or even is it the right thing to do to use the pattern. So can you guys give me some suggestions if you happen to know how to design it better. Thanks.