Browse Source

Scene refactoring

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
c96ef302ac

+ 1 - 1
include/anki/physics/RigidBody.h

@@ -36,7 +36,7 @@ public:
 	/// Unregister. Only the PhysicsWorld can destroy it
 	~RigidBody();
 
-	void syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime);
+	Bool syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime);
 
 private:
 	MotionState motionState;

+ 18 - 11
include/anki/scene/FrustumComponent.h

@@ -4,6 +4,7 @@
 #include "anki/collision/Frustum.h"
 #include "anki/scene/SpatialComponent.h"
 #include "anki/scene/Common.h"
+#include "anki/scene/SceneComponent.h"
 
 namespace anki {
 
@@ -15,7 +16,7 @@ struct VisibilityTestResults;
 
 /// Frustum component interface for scene nodes. Useful for nodes that are 
 /// frustums like cameras and lights
-class FrustumComponent
+class FrustumComponent: public SceneComponent
 {
 public:
 	/// @name Constructors
@@ -23,9 +24,10 @@ public:
 
 	/// Pass the frustum here so we can avoid the virtuals
 	FrustumComponent(Frustum* fr)
-		: frustum(fr)
+		: SceneComponent(this), frustum(fr)
 	{
 		ANKI_ASSERT(frustum);
+		markForUpdate();
 	}
 	/// @}
 
@@ -36,11 +38,6 @@ public:
 		return *frustum;
 	}
 
-	Timestamp getTimestamp() const
-	{
-		return timestamp;
-	}
-
 	const Mat4& getProjectionMatrix() const
 	{
 		return projectionMat;
@@ -74,7 +71,7 @@ public:
 
 	void markForUpdate()
 	{
-		timestamp = getGlobTimestamp();
+		markedForUpdate = true;
 	}
 
 	/// Is a spatial inside the frustum?
@@ -89,10 +86,20 @@ public:
 		return frustum->insideFrustum(cs);
 	}
 
-	void resetFrame()
+	/// @name SceneComponent overrides
+	/// @{
+	Bool update(SceneNode&, F32, F32)
+	{
+		Bool out = markedForUpdate;
+		markedForUpdate = false;
+		return out;
+	}
+
+	void reset()
 	{
 		visible = nullptr;
 	}
+	/// @}
 
 protected:
 	Frustum* frustum = nullptr;
@@ -101,11 +108,11 @@ protected:
 	Mat4 viewProjectionMat = Mat4::getIdentity();
 
 private:
-	Timestamp timestamp = getGlobTimestamp();
-
 	/// Visibility stuff. It's per frame so the pointer is invalid on the next 
 	/// frame and before any visibility tests are run
 	VisibilityTestResults* visible = nullptr;
+
+	Bool8 markedForUpdate;
 };
 /// @}
 

+ 17 - 20
include/anki/scene/MoveComponent.h

@@ -1,10 +1,10 @@
 #ifndef ANKI_SCENE_MOVE_COMPONENT_H
 #define ANKI_SCENE_MOVE_COMPONENT_H
 
+#include "anki/scene/Common.h"
+#include "anki/scene/SceneComponent.h"
 #include "anki/util/Bitset.h"
 #include "anki/Math.h"
-#include "anki/core/Timestamp.h"
-#include "anki/scene/Common.h"
 
 namespace anki {
 
@@ -13,6 +13,7 @@ namespace anki {
 
 /// Interface for movable scene nodes
 class MoveComponent: 
+	public SceneComponent,
 	public SceneHierarchicalObject<MoveComponent>, 
 	public Bitset<U8>
 {
@@ -77,11 +78,17 @@ public:
 	{
 		return prevWTrf;
 	}
+	/// @}
 
-	Timestamp getTimestamp() const
-	{
-		return timestamp;
-	}
+	/// @name SceneComponent overrides
+	/// @{
+
+	/// Update self and children world transform recursively, if root node.
+	/// Need to call this at every frame.
+	/// @note Don't update if child because we start from roots and go to
+	///       children and we don't want a child to be updated before the
+	///       parent
+	Bool update(SceneNode&, F32, F32);
 	/// @}
 
 	/// @name Mess with the local transform
@@ -131,13 +138,6 @@ public:
 	virtual void moveUpdate()
 	{}
 
-	/// Update self and children world transform recursively, if root node.
-	/// Need to call this at every frame.
-	/// @note Don't update if child because we start from roots and go to
-	///       children and we don't want a child to be updated before the
-	///       parent
-	void update();
-
 private:
 	/// The transformation in local space
 	Transform lTrf = Transform::getIdentity();
@@ -149,17 +149,14 @@ private:
 	/// Keep the previous transformation for checking if it moved
 	Transform prevWTrf = Transform::getIdentity();
 
-	/// The frame where it was last moved
-	Timestamp timestamp = getGlobTimestamp();
-
-	/// Called every frame. It updates the @a wTrf if @a shouldUpdateWTrf
-	/// is true. Then it moves to the children.
-	void updateWorldTransform();
-
 	void markForUpdate()
 	{
 		enableBits(MF_MARKED_FOR_UPDATE);
 	}
+
+	/// Called every frame. It updates the @a wTrf if @a shouldUpdateWTrf
+	/// is true. Then it moves to the children.
+	Bool updateWorldTransform();
 };
 /// @}
 

+ 2 - 5
include/anki/scene/RenderComponent.h

@@ -3,6 +3,7 @@
 
 #include "anki/scene/Property.h"
 #include "anki/scene/Common.h"
+#include "anki/scene/SceneComponent.h"
 #include "anki/gl/BufferObject.h"
 #include "anki/resource/Material.h"
 #include "anki/resource/Model.h"
@@ -159,7 +160,7 @@ private:
 };
 
 /// RenderComponent interface. Implemented by renderable scene nodes
-class RenderComponent
+class RenderComponent: public SceneComponent
 {
 public:
 	typedef SceneVector<RenderComponentVariable*> Variables;
@@ -222,10 +223,6 @@ public:
 		}
 	}
 
-	/// Reset on frame start
-	void resetFrame()
-	{}
-
 protected:
 	/// The derived class needs to call that
 	void init();

+ 45 - 8
include/anki/scene/SceneComponent.h

@@ -3,26 +3,63 @@
 
 #include "anki/scene/Common.h"
 #include "anki/core/Timestamp.h"
+#include "anki/util/Visitor.h"
 
 namespace anki {
 
+// Forward of all components
+class FrustumComponent;
+class MoveComponent;
+class RenderComponent;
+class SpatialComponent;
+class RigidBody;
+
+class SceneComponent;
+
+typedef VisitableCommonBase<
+	SceneComponent, // Base
+	FrustumComponent,
+	MoveComponent,
+	RenderComponent,
+	SpatialComponent,
+	RigidBody> SceneComponentVisitable;
+
 /// Scene node component
-class SceneComponent
+class SceneComponent: public SceneComponentVisitable
 {
 public:
-	/// Do some updating on the thread safe sync section
-	virtual void syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
+	/// Construct the scene component. The x is bogus
+	template<typename T>
+	SceneComponent(const T* x)
+	{
+		setupVisitable<T>(x);
+	}
+
+	/// Do some reseting before frame starts
+	virtual void reset()
 	{}
 
+	/// Do some updating on the thread safe sync section
+	/// @return true if an update happened
+	virtual Bool syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
+	{
+		return false;
+	}
+
 	/// Do some updating
-	virtual void update(SceneNode& node, F32 prevTime, F32 crntTime)
-	{}
+	/// @return true if an update happened
+	virtual Bool update(SceneNode& node, F32 prevTime, F32 crntTime)
+	{
+		return false;
+	}
 
 	/// Called only by the SceneGraph
 	void updateReal(SceneNode& node, F32 prevTime, F32 crntTime)
 	{
-		update(node, prevTime, crntTime);
-		timestamp = getTimestamp();
+		if(update(node, prevTime, crntTime))
+		{
+			timestamp = getGlobTimestamp();
+		}
 	}
 
 	Timestamp getTimestamp() const
@@ -30,7 +67,7 @@ public:
 		return timestamp;
 	}
 
-private:
+protected:
 	Timestamp timestamp;
 };
 

+ 57 - 0
include/anki/scene/SceneNode.h

@@ -3,6 +3,7 @@
 
 #include "anki/scene/Property.h"
 #include "anki/scene/Common.h"
+#include "anki/scene/SceneComponent.h"
 #include "anki/util/Object.h"
 
 namespace anki {
@@ -151,6 +152,45 @@ public:
 		return markedForDeletion;
 	}
 
+	/// Iterate all components
+	template<typename Func>
+	void iterateComponents(Func func)
+	{
+		for(auto comp : components)
+		{
+			func(*comp);
+		}
+	}
+
+	/// Iterate all components of a specific type
+	template<typename Component, typename Func>
+	void iterateComponentsOfType(Func func)
+	{
+		I id = SceneComponent::getVariadicTypeId<Component>();
+		for(auto comp : components)
+		{
+			if(comp->getVisitableTypeId() == id)
+			{
+				func(*comp);
+			}
+		}
+	}
+
+	/// Get a pointer to the first component of the requested type
+	template<typename Component>
+	Component* getComponent()
+	{
+		I id = SceneComponent::getVariadicTypeId<Component>();
+		for(auto comp : components)
+		{
+			if(comp->getVisitableTypeId() == id)
+			{
+				return comp;
+			}
+		}
+		return nullptr;
+	}
+
 protected:
 	struct
 	{
@@ -167,6 +207,23 @@ private:
 	SceneGraph* scene = nullptr;
 	SceneString name; ///< A unique name
 	Bool8 markedForDeletion;
+
+protected:
+	SceneVector<SceneComponent*> components;
+
+	/// Create a new component and append it to the components container
+	template<typename T, typename... Args>
+	T* newComponent(Args&&... args)
+	{
+		T* comp = nullptr;
+		SceneAllocator<T> al = getSceneAllocator();
+
+		comp = al.allocate(1);
+		al.construct(comp, std::forward<Args>(args)...);
+
+		components.push_back(comp);
+		return comp;
+	}
 };
 /// @}
 

+ 7 - 9
include/anki/scene/SpatialComponent.h

@@ -2,6 +2,7 @@
 #define ANKI_SCENE_SPATIAL_COMPONENT_H
 
 #include "anki/scene/Common.h"
+#include "anki/scene/SceneComponent.h"
 #include "anki/Collision.h"
 #include "anki/util/Bitset.h"
 #include "anki/core/Timestamp.h"
@@ -14,6 +15,7 @@ namespace anki {
 /// Spatial component for scene nodes. It indicates scene nodes that need to 
 /// be placed in the a sector and they participate in the visibility tests
 class SpatialComponent: 
+	public SceneComponent,
 	public SceneHierarchicalObject<SpatialComponent>, 
 	public Bitset<U8>
 {
@@ -74,11 +76,6 @@ public:
 		}
 	}
 
-	Timestamp getTimestamp() const
-	{
-		return timestamp;
-	}
-
 	/// Used for sorting spatials. In most object the origin is the center of
 	/// the bounding volume but for cameras the origin is the eye point
 	virtual const Vec3& getSpatialOrigin() const
@@ -115,11 +112,13 @@ public:
 		enableBits(SF_MARKED_FOR_UPDATE);
 	}
 
-	/// Update
-	void update();
+	/// @name SceneComponent overrides
+	/// @{
+	Bool update(SceneNode&, F32, F32);
 
 	/// Disable some flags
-	void resetFrame();
+	void reset();
+	/// @}
 
 protected:
 	const CollisionShape* spatialCs = nullptr;
@@ -127,7 +126,6 @@ protected:
 private:
 	Aabb aabb; ///< A faster shape
 	Vec3 origin; ///< Cached value
-	Timestamp timestamp = getGlobTimestamp();
 
 	void updateInternal();
 };

+ 11 - 6
src/physics/RigidBody.cpp

@@ -9,7 +9,8 @@ namespace anki {
 RigidBody::RigidBody(PhysicsWorld* world, const Initializer& init)
 	:	PhysicsObject(world),
 		btRigidBody(btRigidBody::btRigidBodyConstructionInfo(0.0, nullptr, 
-			nullptr, btVector3(0.0, 0.0, 0.0))) // dummy init
+			nullptr, btVector3(0.0, 0.0, 0.0))), // dummy init
+		SceneComponent(this)
 {
 	ANKI_ASSERT(init.shape != nullptr 
 		&& init.shape->getShapeType() != INVALID_SHAPE_PROXYTYPE);
@@ -62,19 +63,21 @@ RigidBody::~RigidBody()
 }
 
 //==============================================================================
-void RigidBody::syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
+Bool RigidBody::syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
 {
 	MoveComponent* move = node.getMoveComponent();
 	if(ANKI_UNLIKELY(move == nullptr))
 	{
-		return;
+		return false;
 	}
 
-	Bool updated = move->bitsEnabled(MoveComponent::MF_MARKED_FOR_UPDATE);
+	Bool moveUpdated = move->bitsEnabled(MoveComponent::MF_MARKED_FOR_UPDATE);
 	Transform oldTrf = move->getLocalTransform();
 
+	Bool mstateUpdated = motionState.getUpdated();
+
 	// Sync from motion state to move component
-	if(motionState.getUpdated())
+	if(mstateUpdated)
 	{
 		// Set local transform and preserve scale
 		Transform newTrf;
@@ -91,7 +94,7 @@ void RigidBody::syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
 	}
 
 	// Sync from move component to motion state
-	if(updated)
+	if(moveUpdated)
 	{
 		std::cout << "Activating again " << oldTrf.getOrigin().toString() << std::endl;
 
@@ -105,6 +108,8 @@ void RigidBody::syncUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
 
 		//setGravity(getPhysicsWorld().dynamicsWorld->getGravity());
 	}
+
+	return mstateUpdated;
 }
 
 } // end namespace anki

+ 13 - 6
src/scene/MoveComponent.cpp

@@ -5,7 +5,8 @@ namespace anki {
 
 //==============================================================================
 MoveComponent::MoveComponent(SceneNode* node, U32 flags)
-	:	Base(nullptr, node->getSceneAllocator()),
+	:	SceneComponent(this),
+		Base(nullptr, node->getSceneAllocator()),
 		Bitset<U8>(flags)
 {
 	markForUpdate();
@@ -16,18 +17,20 @@ MoveComponent::~MoveComponent()
 {}
 
 //==============================================================================
-void MoveComponent::update()
+Bool MoveComponent::update(SceneNode&, F32, F32)
 {
 	// Call this only on roots
 	if(getParent() == nullptr)
 	{
 		// If root begin updating
-		updateWorldTransform();
+		return updateWorldTransform();
 	}
+
+	return false;
 }
 
 //==============================================================================
-void MoveComponent::updateWorldTransform()
+Bool MoveComponent::updateWorldTransform()
 {
 	prevWTrf = wTrf;
 	const Bool dirty = bitsEnabled(MF_MARKED_FOR_UPDATE);
@@ -58,7 +61,6 @@ void MoveComponent::updateWorldTransform()
 
 		// Now it's a good time to cleanse parent
 		disableBits(MF_MARKED_FOR_UPDATE);
-		timestamp = getGlobTimestamp();
 	}
 
 	// Update the children
@@ -70,8 +72,13 @@ void MoveComponent::updateWorldTransform()
 			mov.markForUpdate();
 		}
 
-		mov.updateWorldTransform();
+		if(mov.updateWorldTransform())
+		{
+			mov.timestamp = getGlobTimestamp();
+		}
 	});
+
+	return dirty;
 }
 
 } // end namespace anki

+ 1 - 1
src/scene/RenderComponent.cpp

@@ -83,7 +83,7 @@ RenderComponentVariable::~RenderComponentVariable()
 
 //==============================================================================
 RenderComponent::RenderComponent(SceneNode* node)
-	: vars(node->getSceneAllocator())
+	: SceneComponent(this), vars(node->getSceneAllocator())
 {}
 
 //==============================================================================

+ 24 - 42
src/scene/SceneGraph.cpp

@@ -21,7 +21,7 @@ struct UpdateMoveComponentsJob: ThreadpoolTask
 
 	void operator()(ThreadId threadId, U threadsCount)
 	{
-		U64 start, end;
+		/*U64 start, end;
 		ANKI_ASSERT(scene);
 		choseStartEnd(
 			threadId, threadsCount, scene->getSceneNodesCount(), start, end);
@@ -33,7 +33,7 @@ struct UpdateMoveComponentsJob: ThreadpoolTask
 			{
 				m->update();
 			}
-		});
+		});*/
 	}
 };
 
@@ -43,26 +43,36 @@ static void updateSceneNode(SceneNode& sn, F32 prevUpdateTime,
 {
 	sn.frameUpdate(prevUpdateTime, crntTime, getGlobTimestamp());
 
+	// Movable
+	MoveComponent* m = sn.getMoveComponent();
+	if(m)
+	{
+		m->reset();
+		m->updateReal(sn, prevUpdateTime, crntTime);
+	}
+
 	// Do some spatial stuff
 	SpatialComponent* sp = sn.getSpatialComponent();
 	if(sp)
 	{
-		sp->update();
-		sp->resetFrame();
+		sp->reset();
+		sp->updateReal(sn, prevUpdateTime, crntTime);
 	}
 
 	// Do some frustumable stuff
 	FrustumComponent* fr = sn.getFrustumComponent();
 	if(fr)
 	{
-		fr->resetFrame();
+		fr->reset();
+		fr->updateReal(sn, prevUpdateTime, crntTime);
 	}
 
 	// Do some renderable stuff
 	RenderComponent* r = sn.getRenderComponent();
 	if(r)
 	{
-		r->resetFrame();
+		r->reset();
+		r->updateReal(sn, prevUpdateTime, crntTime);
 	}
 }
 
@@ -225,26 +235,22 @@ void SceneGraph::update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer)
 	// Sync point. Here we wait for all scene's threads
 	//
 
+	// Reset the framepool
+	frameAlloc.reset();
+
+	// Delete nodes
+	deleteNodesMarkedForDeletion();
+
+	// Sync updates
 	iterateSceneNodes([&](SceneNode& sn)
 	{
 		RigidBody* body = sn.getRigidBody();
 		if(body)
 		{
-			MoveComponent* move = sn.getMoveComponent();
-			if(move)
-			{
-				body->syncUpdate(sn, prevUpdateTime, crntTime);
-			}
+			body->syncUpdate(sn, prevUpdateTime, crntTime);
 		}
 	});
 
-	//
-	// Reset the frame mem pool
-	//
-	frameAlloc.reset();
-
-	deleteNodesMarkedForDeletion();
-
 	Threadpool& threadPool = ThreadpoolSingleton::get();
 	(void)threadPool;
 
@@ -253,30 +259,6 @@ void SceneGraph::update(F32 prevUpdateTime, F32 crntTime, Renderer& renderer)
 	renderer.getTiler().updateTiles(*mainCam);
 	events.updateAllEvents(prevUpdateTime, crntTime);
 
-#if 0
-	// First do the movable updates
-	for(SceneNode* n : nodes)
-	{
-		MoveComponent* m = n->getMoveComponent();
-
-		if(m)
-		{
-			m->update();
-		}
-	}
-#else
-	UpdateMoveComponentsJob jobs[Threadpool::MAX_THREADS];
-
-	for(U i = 0; i < threadPool.getThreadsCount(); i++)
-	{
-		jobs[i].scene = this;
-
-		threadPool.assignNewTask(i, &jobs[i]);
-	}
-
-	threadPool.waitForAllThreadsToFinish();
-#endif
-
 	// Then the rest
 #if 0
 	for(SceneNode* n : nodes)

+ 11 - 2
src/scene/SceneNode.cpp

@@ -10,10 +10,13 @@ namespace anki {
 SceneNode::SceneNode(const char* name_, SceneGraph* scene_)
 	:	scene(scene_),
 		name(getSceneAllocator()),
-		markedForDeletion(false)
+		markedForDeletion(false),
+		components(getSceneAllocator())
 {
 	ANKI_ASSERT(scene);
 
+	components.reserve(2);
+
 	if(name_)
 	{
 		name = SceneString(name_, scene->getAllocator());
@@ -22,7 +25,13 @@ SceneNode::SceneNode(const char* name_, SceneGraph* scene_)
 
 //==============================================================================
 SceneNode::~SceneNode()
-{}
+{
+	SceneAllocator<SceneComponent*> alloc = getSceneAllocator();
+	for(auto comp : components)
+	{
+		alloc.deleteInstance(comp);
+	}
+}
 
 //==============================================================================
 SceneAllocator<U8> SceneNode::getSceneAllocator() const

+ 6 - 3
src/scene/SpatialComponent.cpp

@@ -6,7 +6,8 @@ namespace anki {
 //==============================================================================
 SpatialComponent::SpatialComponent(SceneNode* node, const CollisionShape* cs,
 	U32 flags)
-	:	Base(nullptr, node->getSceneAllocator()), 
+	:	SceneComponent(this),
+		Base(nullptr, node->getSceneAllocator()), 
 		Bitset<U8>(flags),
 		spatialCs(cs)
 {
@@ -19,7 +20,7 @@ SpatialComponent::~SpatialComponent()
 {}
 
 //==============================================================================
-void SpatialComponent::update()
+Bool SpatialComponent::update(SceneNode&, F32, F32)
 {
 	if(getParent() == nullptr)
 	{
@@ -28,6 +29,8 @@ void SpatialComponent::update()
 			sp.updateInternal();
 		});	
 	}
+
+	return false;
 }
 
 //==============================================================================
@@ -44,7 +47,7 @@ void SpatialComponent::updateInternal()
 }
 
 //==============================================================================
-void SpatialComponent::resetFrame()
+void SpatialComponent::reset()
 {
 	// Call this only on roots
 	if(getParent() == nullptr)