瀏覽代碼

Animation and events

Panagiotis Christopoulos Charitos 12 年之前
父節點
當前提交
65a78596a1

+ 12 - 8
bench/Main.cpp

@@ -20,16 +20,13 @@
 #include "anki/core/Logger.h"
 #include "anki/core/Logger.h"
 #include "anki/Util.h"
 #include "anki/Util.h"
 #include "anki/resource/Skin.h"
 #include "anki/resource/Skin.h"
-#include "anki/event/EventManager.h"
-#include "anki/event/MainRendererPpsHdrEvent.h"
 #include "anki/resource/ShaderProgramPrePreprocessor.h"
 #include "anki/resource/ShaderProgramPrePreprocessor.h"
 #include "anki/resource/Material.h"
 #include "anki/resource/Material.h"
 #include "anki/core/ThreadPool.h"
 #include "anki/core/ThreadPool.h"
 #include "anki/core/NativeWindow.h"
 #include "anki/core/NativeWindow.h"
 #include "anki/core/Counters.h"
 #include "anki/core/Counters.h"
 #include "anki/Scene.h"
 #include "anki/Scene.h"
-#include "anki/event/LightEvent.h"
-#include "anki/event/MovableEvent.h"
+#include "anki/Event.h"
 
 
 using namespace anki;
 using namespace anki;
 
 
@@ -174,6 +171,13 @@ void initScene()
 		1.0));
 		1.0));
 	scene.setActiveCamera(cam);
 	scene.setActiveCamera(cam);
 
 
+#if 1
+	AnimationResourcePointer anim;
+	anim.load("maps/sponza/animation_0.ankianim");
+	AnimationEvent* event;
+	scene.getEventManager().newEvent(event, anim, cam);
+#endif
+
 #if 1
 #if 1
 	F32 x = 8.5; 
 	F32 x = 8.5; 
 	F32 y = 2.25;
 	F32 y = 2.25;
@@ -196,18 +200,18 @@ void initScene()
 		point->setLensFlaresAlpha(1.0);
 		point->setLensFlaresAlpha(1.0);
 
 
 		LightEventData eventData;
 		LightEventData eventData;
-		eventData.light = point;
 		eventData.radiusMultiplier = 0.2;
 		eventData.radiusMultiplier = 0.2;
 		eventData.intensityMultiplier = Vec4(-1.2, 0.0, 0.0, 0.0);
 		eventData.intensityMultiplier = Vec4(-1.2, 0.0, 0.0, 0.0);
 		eventData.specularIntensityMultiplier = Vec4(0.1, 0.1, 0.0, 0.0);
 		eventData.specularIntensityMultiplier = Vec4(0.1, 0.1, 0.0, 0.0);
-		auto event = scene.getEventManager().newLightEvent(0.0, 0.8, eventData);
+		LightEvent* event;
+		scene.getEventManager().newEvent(event, 0.0, 0.8, point, eventData);
 		event->enableBits(Event::EF_REANIMATE);
 		event->enableBits(Event::EF_REANIMATE);
 
 
 		MovableEventData moveData;
 		MovableEventData moveData;
-		moveData.movableSceneNode = point;
 		moveData.posMin = Vec3(-0.5, 0.0, -0.5);
 		moveData.posMin = Vec3(-0.5, 0.0, -0.5);
 		moveData.posMax = Vec3(0.5, 0.0, 0.5);
 		moveData.posMax = Vec3(0.5, 0.0, 0.5);
-		auto mevent = scene.getEventManager().newMovableEvent(0.0, 2.0, moveData);
+		MovableEvent* mevent;
+		scene.getEventManager().newEvent(mevent, 0.0, 2.0, point, moveData);
 		mevent->enableBits(Event::EF_REANIMATE);
 		mevent->enableBits(Event::EF_REANIMATE);
 
 
 		ParticleEmitter* pe;
 		ParticleEmitter* pe;

+ 11 - 0
include/anki/Event.h

@@ -0,0 +1,11 @@
+#ifndef ANKI_EVENT_H
+#define ANKI_EVENT_H
+
+#include "anki/event/EventManager.h"
+
+#include "anki/event/SceneAmbientColorEvent.h"
+#include "anki/event/LightEvent.h"
+#include "anki/event/MovableEvent.h"
+#include "anki/event/AnimationEvent.h"
+
+#endif

+ 10 - 9
include/anki/event/Event.h

@@ -24,7 +24,8 @@ public:
 	enum EventFlags
 	enum EventFlags
 	{
 	{
 		EF_NONE = 0,
 		EF_NONE = 0,
-		EF_REANIMATE = 1 << 0
+		EF_REANIMATE = 1 << 0,
+		EF_MARKED_FOR_DELETION = 1 << 1
 	};
 	};
 
 
 	/// @name Constructors/Destructor
 	/// @name Constructors/Destructor
@@ -54,9 +55,6 @@ public:
 		return crntTime >= startTime + duration;
 		return crntTime >= startTime + duration;
 	}
 	}
 
 
-	SceneAllocator<U8> getSceneAllocator() const;
-	SceneAllocator<U8> getSceneFrameAllocator() const;
-
 	EventManager& getEventManager()
 	EventManager& getEventManager()
 	{
 	{
 		return *manager;
 		return *manager;
@@ -68,12 +66,15 @@ public:
 
 
 	SceneNode* getSceneNode()
 	SceneNode* getSceneNode()
 	{
 	{
-		return snode;
+		return node;
 	}
 	}
 	const SceneNode* getSceneNode() const
 	const SceneNode* getSceneNode() const
 	{
 	{
-		return snode;
+		return node;
 	}
 	}
+
+	SceneAllocator<U8> getSceneAllocator() const;
+	SceneAllocator<U8> getSceneFrameAllocator() const;
 	/// @}
 	/// @}
 
 
 	/// This method should be implemented by the derived classes
 	/// This method should be implemented by the derived classes
@@ -95,13 +96,14 @@ public:
 	/// Mark event for deletion
 	/// Mark event for deletion
 	void markForDeletion()
 	void markForDeletion()
 	{
 	{
-		markedForDeletion = true;
+		enableBits(EF_MARKED_FOR_DELETION);
+		node = nullptr;
 	}
 	}
 
 
 	/// Ask if event is marked for deletion
 	/// Ask if event is marked for deletion
 	Bool isMarkedForDeletion() const
 	Bool isMarkedForDeletion() const
 	{
 	{
-		return markedForDeletion;
+		return bitsEnabled(EF_MARKED_FOR_DELETION);
 	}
 	}
 
 
 protected:
 protected:
@@ -150,7 +152,6 @@ protected:
 private:
 private:
 	EventManager* manager = nullptr; ///< Keep it here to access allocators etc
 	EventManager* manager = nullptr; ///< Keep it here to access allocators etc
 	SceneNode* node = nullptr; ///< Optional scene node
 	SceneNode* node = nullptr; ///< Optional scene node
-	Bool8 markedForDeletion = false;
 };
 };
 /// @}
 /// @}
 
 

+ 15 - 16
include/anki/event/EventManager.h

@@ -11,15 +11,6 @@ namespace anki {
 
 
 // Forward
 // Forward
 class SceneGraph;
 class SceneGraph;
-class Path;
-class SceneNode;
-
-class SceneAmbientColorEvent;
-class LightEvent;
-class LightEventData;
-class MovableEvent;
-class MovableEventData;
-class FollowPathEvent;
 
 
 /// @addtogroup Events
 /// @addtogroup Events
 /// @{
 /// @{
@@ -28,16 +19,13 @@ class FollowPathEvent;
 class EventManager
 class EventManager
 {
 {
 public:
 public:
-	typedef SceneVector<Event> EventsContainer;
+	typedef SceneVector<Event*> EventsContainer;
 
 
 	EventManager(SceneGraph* scene);
 	EventManager(SceneGraph* scene);
 	~EventManager();
 	~EventManager();
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
-	SceneAllocator<U8> getSceneAllocator() const;
-	SceneAllocator<U8> getSceneFrameAllocator() const;
-
 	SceneGraph& getScene()
 	SceneGraph& getScene()
 	{
 	{
 		return *scene;
 		return *scene;
@@ -46,11 +34,24 @@ public:
 	{
 	{
 		return *scene;
 		return *scene;
 	}
 	}
+
+	SceneAllocator<U8> getSceneAllocator() const;
+	SceneAllocator<U8> getSceneFrameAllocator() const;
 	/// @}
 	/// @}
 
 
+	/// Iterate events
+	template<typename Func>
+	void iterateEvents(Func func)
+	{
+		for(Event* e : events)
+		{
+			func(*e);
+		}
+	}
+
 	/// Create a new event
 	/// Create a new event
 	template<typename T, typename... Args>
 	template<typename T, typename... Args>
-	void newEvent(T*& event, Args&&.. args)
+	void newEvent(T*& event, Args&&... args)
 	{
 	{
 		SceneAllocator<T> al = getSceneAllocator();
 		SceneAllocator<T> al = getSceneAllocator();
 		event = al.allocate(1);
 		event = al.allocate(1);
@@ -63,7 +64,6 @@ public:
 	void deleteEvent(Event* event)
 	void deleteEvent(Event* event)
 	{
 	{
 		event->markForDeletion();
 		event->markForDeletion();
-		++eventsMarkedForDeletionCount;
 	}
 	}
 
 
 	/// Update
 	/// Update
@@ -74,7 +74,6 @@ private:
 	EventsContainer events;
 	EventsContainer events;
 	F32 prevUpdateTime;
 	F32 prevUpdateTime;
 	F32 crntTime;
 	F32 crntTime;
-	U32 eventsMarkedForDeletionCount = 0;
 
 
 	/// Add an event to the local container
 	/// Add an event to the local container
 	void registerEvent(Event* event);
 	void registerEvent(Event* event);

+ 1 - 1
include/anki/event/LightEvent.h

@@ -29,7 +29,7 @@ public:
 
 
 	/// Constructor
 	/// Constructor
 	LightEvent(EventManager* manager, F32 startTime, F32 duration,
 	LightEvent(EventManager* manager, F32 startTime, F32 duration,
-		U8 flags, Light* light, const LightEventData& data);
+		Light* light, const LightEventData& data);
 	/// @}
 	/// @}
 
 
 	/// Implements Event::update
 	/// Implements Event::update

+ 1 - 1
include/anki/event/MovableEvent.h

@@ -28,7 +28,7 @@ public:
 
 
 	/// Constructor
 	/// Constructor
 	MovableEvent(EventManager* manager, F32 startTime, F32 duration,
 	MovableEvent(EventManager* manager, F32 startTime, F32 duration,
-		U8 flags, SceneNode* movableSceneNode, const MovableEventData& data);
+		SceneNode* movableSceneNode, const MovableEventData& data);
 	/// @}
 	/// @}
 
 
 	/// Implements Event::update
 	/// Implements Event::update

+ 48 - 0
include/anki/math/Functions.h

@@ -123,6 +123,54 @@ inline T toDegrees(const T rad)
 	return rad * (T(180.0) / getPi<T>());
 	return rad * (T(180.0) / getPi<T>());
 }
 }
 
 
+//==============================================================================
+// Interpolation                                                               =
+//==============================================================================
+
+/// Linear interpolation between values
+/// @param[in] from Starting value
+/// @param[in] to Ending value
+/// @param[in] u The percentage from the from "from" value. Values
+///              from [0.0, 1.0]
+template<typename Type>
+static Type linearInterpolate(const Type& from, const Type& to, F32 u)
+{
+	return from * (1.0 - u) + to * u;
+}
+
+/// Cosine interpolation
+/// @param[in] from Starting value
+/// @param[in] to Ending value
+/// @param[in] u The percentage from the from "from" value. Values
+///              from [0.0, 1.0]
+template<typename Type>
+static Type cosInterpolate(const Type& from, const Type& to, F32 u)
+{
+	F32 u2 = (1.0 - cos<F32>(u * getPi<F32>())) / 2.0;
+	return from * (1.0 - u2) + to * u2;
+}
+
+/// Cubic interpolation
+/// @param[in] a Point a
+/// @param[in] b Point b
+/// @param[in] c Point c
+/// @param[in] d Point d
+/// @param[in] u The percentage from the from b point to d point. Value
+///              from [0.0, 1.0]
+template<typename Type>
+static Type cubicInterpolate(
+	const Type& a, const Type& b, const Type& c, 
+	const Type& d, F32 u)
+{
+	F32 u2 = u * u;
+	Type a0 = d - c - a + b;
+	Type a1 = a - b - a0;
+	Type a2 = c - a;
+	Type a3 = b;
+
+	return(a0 * u * u2 + a1 * u2 + a2 * u + a3);
+}
+
 } // end namespace anki
 } // end namespace anki
 
 
 #endif
 #endif

+ 6 - 2
include/anki/resource/Animation.h

@@ -66,14 +66,18 @@ public:
 
 
 	F32 getStartingTime() const
 	F32 getStartingTime() const
 	{
 	{
-		return startingTime;
+		return startTime;
 	}
 	}
 	/// @}
 	/// @}
 
 
+	/// Get the interpolated data
+	void interpolate(U channelIndex, F32 time, 
+		Vec3& position, Quat& rotation, F32& scale) const;
+
 private:
 private:
 	Vector<AnimationChannel> channels;
 	Vector<AnimationChannel> channels;
 	F32 duration;
 	F32 duration;
-	F32 startingTime;
+	F32 startTime;
 
 
 	void loadInternal(const XmlElement& el);
 	void loadInternal(const XmlElement& el);
 };
 };

+ 39 - 0
src/event/AnimationEvent.cpp

@@ -0,0 +1,39 @@
+#include "anki/event/AnimationEvent.h"
+#include "anki/resource/Animation.h"
+#include "anki/scene/SceneNode.h"
+#include "anki/scene/Movable.h"
+
+namespace anki {
+
+//==============================================================================
+AnimationEvent::AnimationEvent(EventManager* manager, 
+	const AnimationResourcePointer& anim_, SceneNode* movableSceneNode)
+	:	Event(manager, 0.0, 0.0, movableSceneNode),
+		anim(anim_)
+{
+	ANKI_ASSERT(movableSceneNode && movableSceneNode->getMovable());
+
+	startTime = anim->getStartingTime();
+	duration = anim->getDuration();
+}
+
+//==============================================================================
+void AnimationEvent::update(F32 prevUpdateTime, F32 crntTime)
+{
+	ANKI_ASSERT(getSceneNode());
+	Movable* mov = getSceneNode()->getMovable();
+	ANKI_ASSERT(mov);
+
+	Vec3 pos;
+	Quat rot;
+	F32 scale = 1.0;
+	anim->interpolate(0, crntTime, pos, rot, scale);
+
+	Transform trf;
+	trf.setOrigin(pos);
+	trf.setRotation(Mat3(rot));
+	trf.setScale(scale);
+	mov->setLocalTransform(trf);
+}
+
+} // end namespace anki

+ 5 - 10
src/event/Event.cpp

@@ -11,11 +11,15 @@ Event::Event(EventManager* manager_, F32 startTime_, F32 duration_,
 		startTime(startTime_),
 		startTime(startTime_),
 		duration(duration_),
 		duration(duration_),
 		manager(manager_),
 		manager(manager_),
-		snode(snode_)
+		node(snode_)
 {
 {
 	ANKI_ASSERT(manager);
 	ANKI_ASSERT(manager);
 }
 }
 
 
+//==============================================================================
+Event::~Event()
+{}
+
 //==============================================================================
 //==============================================================================
 SceneAllocator<U8> Event::getSceneAllocator() const
 SceneAllocator<U8> Event::getSceneAllocator() const
 {
 {
@@ -28,15 +32,6 @@ SceneAllocator<U8> Event::getSceneFrameAllocator() const
 	return manager->getSceneFrameAllocator();
 	return manager->getSceneFrameAllocator();
 }
 }
 
 
-//==============================================================================
-Event::~Event()
-{
-	if(manager)
-	{
-		manager->unregisterEvent(this);
-	}
-}
-
 //==============================================================================
 //==============================================================================
 F32 Event::getDelta(F32 crntTime) const
 F32 Event::getDelta(F32 crntTime) const
 {
 {

+ 13 - 4
src/event/EventManager.cpp

@@ -45,13 +45,13 @@ void EventManager::unregisterEvent(Event* event)
 	EventsContainer::iterator it = events.begin();
 	EventsContainer::iterator it = events.begin();
 	for(; it != events.end(); it++)
 	for(; it != events.end(); it++)
 	{
 	{
-		if(it->get() == event)
+		if((*it) == event)
 		{
 		{
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
-	ANKI_ASSERT(it == events.end());
+	ANKI_ASSERT(it == events.end() && "Trying to unreg non-existing event");
 	events.erase(it);
 	events.erase(it);
 }
 }
 
 
@@ -64,13 +64,22 @@ void EventManager::updateAllEvents(F32 prevUpdateTime_, F32 crntTime_)
 	// Container to gather dead events
 	// Container to gather dead events
 	SceneFrameVector<EventsContainer::iterator> 
 	SceneFrameVector<EventsContainer::iterator> 
 		forDeletion(getSceneFrameAllocator());
 		forDeletion(getSceneFrameAllocator());
-	// XXX reserve on vector
 
 
 	EventsContainer::iterator it = events.begin();
 	EventsContainer::iterator it = events.begin();
 	for(; it != events.end(); it++)
 	for(; it != events.end(); it++)
 	{
 	{
 		Event* pevent = *it;
 		Event* pevent = *it;
 
 
+		// If event or the node's event is marked for deletion then dont 
+		// do anything else for that event
+		if(pevent->isMarkedForDeletion() 
+			|| (pevent->getSceneNode() != nullptr 
+				&& pevent->getSceneNode()->isMarkedForDeletion()))
+		{
+			forDeletion.push_back(it);
+			continue;
+		}
+
 		// Audjust starting time
 		// Audjust starting time
 		if(pevent->startTime < 0.0)
 		if(pevent->startTime < 0.0)
 		{
 		{
@@ -94,7 +103,7 @@ void EventManager::updateAllEvents(F32 prevUpdateTime_, F32 crntTime_)
 			}
 			}
 			else
 			else
 			{
 			{
-				if((*it)->onKilled(prevUpdateTime, crntTime))
+				if(pevent->onKilled(prevUpdateTime, crntTime))
 				{
 				{
 					forDeletion.push_back(it);
 					forDeletion.push_back(it);
 				}
 				}

+ 1 - 1
src/event/FollowPathEvent.cpp

@@ -5,7 +5,7 @@ namespace anki {
 
 
 //==============================================================================
 //==============================================================================
 FollowPathEvent::FollowPathEvent(
 FollowPathEvent::FollowPathEvent(
-	F32 startTime, F32 duration, EventManager* manager, U8 flags,
+	EventManager* manager, F32 startTime, F32 duration, U8 flags,
 	SceneNode* movableSceneNode_, Path* path_, F32 distPerTime_)
 	SceneNode* movableSceneNode_, Path* path_, F32 distPerTime_)
 	:	Event(manager, startTime, duration, nullptr, flags),
 	:	Event(manager, startTime, duration, nullptr, flags),
 		distPerTime(distPerTime_),
 		distPerTime(distPerTime_),

+ 3 - 2
src/event/LightEvent.cpp

@@ -5,8 +5,8 @@ namespace anki {
 
 
 //==============================================================================
 //==============================================================================
 LightEvent::LightEvent(EventManager* manager, F32 startTime, F32 duration,
 LightEvent::LightEvent(EventManager* manager, F32 startTime, F32 duration,
-	U8 flags, Light* light, const LightEventData& data)
-	: Event(manager, startTime, duration, light, flags)
+	Light* light, const LightEventData& data)
+	: Event(manager, startTime, duration, light, EF_NONE)
 {
 {
 	*static_cast<LightEventData*>(this) = data;
 	*static_cast<LightEventData*>(this) = data;
 
 
@@ -34,6 +34,7 @@ LightEvent::LightEvent(EventManager* manager, F32 startTime, F32 duration,
 void LightEvent::update(F32 prevUpdateTime, F32 crntTime)
 void LightEvent::update(F32 prevUpdateTime, F32 crntTime)
 {
 {
 	F32 factor = sin(getDelta(crntTime) * getPi<F32>());
 	F32 factor = sin(getDelta(crntTime) * getPi<F32>());
+	Light* light = static_cast<Light*>(getSceneNode());
 
 
 	switch(light->getLightType())
 	switch(light->getLightType())
 	{
 	{

+ 3 - 4
src/event/MovableEvent.cpp

@@ -7,11 +7,10 @@ namespace anki {
 
 
 //==============================================================================
 //==============================================================================
 MovableEvent::MovableEvent(EventManager* manager, F32 startTime, F32 duration,
 MovableEvent::MovableEvent(EventManager* manager, F32 startTime, F32 duration,
-	U8 flags, SceneNode* movableSceneNode, const MovableEventData& data)
-	: Event(manager, startTime, duration, movableSceneNode, flags)
+	SceneNode* movableSceneNode, const MovableEventData& data)
+	: Event(manager, startTime, duration, movableSceneNode, EF_NONE)
 {
 {
-	ANKI_ASSERT(data.movableSceneNode->getMovable());
-
+	ANKI_ASSERT(movableSceneNode);
 	*static_cast<MovableEventData*>(this) = data;
 	*static_cast<MovableEventData*>(this) = data;
 
 
 	originalPos =
 	originalPos =

+ 1 - 2
src/event/SceneAmbientColorEvent.cpp

@@ -10,8 +10,7 @@ SceneAmbientColorEvent::SceneAmbientColorEvent(EventManager* manager,
 	:	Event(manager, startTime, duration), 
 	:	Event(manager, startTime, duration), 
 		finalColor(finalColor_)
 		finalColor(finalColor_)
 {
 {
-	ANKI_ASSERT(scene);
-	originalColor = scene->getAmbientColor();
+	originalColor = getEventManager().getScene().getAmbientColor();
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 54 - 7
src/resource/Animation.cpp

@@ -38,17 +38,17 @@ void Animation::loadInternal(const XmlElement& el)
 		ch.name = chEl.getChildElement("name").getText();
 		ch.name = chEl.getChildElement("name").getText();
 
 
 		// <positionKeys>
 		// <positionKeys>
-		XmlElement keysEl = chEl.getChildElement("positionsKeys");
+		XmlElement keysEl = chEl.getChildElement("positionKeys");
 		XmlElement keyEl = keysEl.getChildElement("key");
 		XmlElement keyEl = keysEl.getChildElement("key");
 		do
 		do
 		{
 		{
 			Key<Vec3> key;
 			Key<Vec3> key;
 
 
 			// <time>
 			// <time>
-			key.time = keyEl.getFloat();
+			key.time = keyEl.getChildElement("time").getFloat();
 
 
 			// <value>
 			// <value>
-			key.value = keyEl.getVec3();
+			key.value = keyEl.getChildElement("value").getVec3();
 
 
 			// push_back
 			// push_back
 			ch.positions.push_back(key);
 			ch.positions.push_back(key);
@@ -65,10 +65,15 @@ void Animation::loadInternal(const XmlElement& el)
 			Key<Quat> key;
 			Key<Quat> key;
 
 
 			// <time>
 			// <time>
-			key.time = keyEl.getFloat();
+			key.time = keyEl.getChildElement("time").getFloat();
 
 
 			// <value>
 			// <value>
-			key.value = Quat(keyEl.getVec4());
+			Quat a = Quat(keyEl.getChildElement("value").getVec4());
+			key.value.x() = a.w();
+			key.value.y() = a.x();
+			key.value.z() = a.y();
+			key.value.w() = a.z();
+			// XXX
 
 
 			// push_back
 			// push_back
 			ch.rotations.push_back(key);
 			ch.rotations.push_back(key);
@@ -87,10 +92,10 @@ void Animation::loadInternal(const XmlElement& el)
 				Key<F32> key;
 				Key<F32> key;
 
 
 				// <time>
 				// <time>
-				key.time = keyEl.getFloat();
+				key.time = keyEl.getChildElement("time").getFloat();
 
 
 				// <value>
 				// <value>
-				key.value = keyEl.getFloat();
+				key.value = keyEl.getChildElement("value").getFloat();
 
 
 				// push_back
 				// push_back
 				ch.scales.push_back(key);
 				ch.scales.push_back(key);
@@ -105,4 +110,46 @@ void Animation::loadInternal(const XmlElement& el)
 	} while(chEl);
 	} while(chEl);
 }
 }
 
 
+//==============================================================================
+void Animation::interpolate(U channelIndex, F32 time, 
+	Vec3& pos, Quat& rot, F32& scale) const
+{
+	ANKI_ASSERT(time >= startTime && time <= startTime + duration);
+	ANKI_ASSERT(channelIndex < channels.size());
+	
+	const AnimationChannel& channel = channels[channelIndex];
+
+	// Position
+	if(channel.positions.size() > 1)
+	{
+		auto next = channel.positions.begin();
+
+		do
+		{
+		} while((next->time < time) && (++next != channel.positions.end()));
+
+		ANKI_ASSERT(next != channel.positions.end());
+		auto prev = next - 1;
+
+		F32 u = (time - prev->time) / (next->time - prev->time);
+		pos = linearInterpolate(prev->value, next->value, u);
+	}
+
+	// Rotation
+	if(channel.rotations.size() > 1)
+	{
+		auto next = channel.rotations.begin();
+
+		do
+		{
+		} while((next->time < time) && (++next != channel.rotations.end()));
+
+		ANKI_ASSERT(next != channel.rotations.end());
+		auto prev = next - 1;
+
+		F32 u = (time - prev->time) / (next->time - prev->time);
+		rot = prev->value.slerp(next->value, u);
+	}
+}
+
 } // end namespace anki
 } // end namespace anki

+ 11 - 0
src/scene/SceneGraph.cpp

@@ -132,6 +132,7 @@ void SceneGraph::registerNode(SceneNode* node)
 	}
 	}
 
 
 	// Add to vector
 	// Add to vector
+	ANKI_ASSERT(std::find(nodes.begin(), nodes.end(), node) == nodes.end());
 	nodes.push_back(node);
 	nodes.push_back(node);
 }
 }
 
 
@@ -195,6 +196,16 @@ void SceneGraph::deleteNodesMarkedForDeletion()
 		// Now delete
 		// Now delete
 		for(auto& it : forDeletion)
 		for(auto& it : forDeletion)
 		{
 		{
+			// Disable events for that node
+			events.iterateEvents([&](Event& e)
+			{
+				if(e.getSceneNode() == *it)
+				{
+					e.markForDeletion();
+				}
+			});
+
+			// Remove it
 			unregisterNode(*it);
 			unregisterNode(*it);
 
 
 			SceneAllocator<SceneNode> al = alloc;
 			SceneAllocator<SceneNode> al = alloc;

+ 4 - 4
testapp/Main.cpp

@@ -211,18 +211,18 @@ void init()
 		point->setLensFlaresAlpha(1.0);
 		point->setLensFlaresAlpha(1.0);
 
 
 		LightEventData eventData;
 		LightEventData eventData;
-		eventData.light = point;
 		eventData.radiusMultiplier = 0.2;
 		eventData.radiusMultiplier = 0.2;
 		eventData.intensityMultiplier = Vec4(-1.2, 0.0, 0.0, 0.0);
 		eventData.intensityMultiplier = Vec4(-1.2, 0.0, 0.0, 0.0);
 		eventData.specularIntensityMultiplier = Vec4(0.1, 0.1, 0.0, 0.0);
 		eventData.specularIntensityMultiplier = Vec4(0.1, 0.1, 0.0, 0.0);
-		auto event = scene.getEventManager().newLightEvent(0.0, 0.8, eventData);
+		LightEvent* event;
+		scene.getEventManager().newEvent(event, 0.0, 0.8, point, eventData);
 		event->enableBits(Event::EF_REANIMATE);
 		event->enableBits(Event::EF_REANIMATE);
 
 
 		MovableEventData moveData;
 		MovableEventData moveData;
-		moveData.movableSceneNode = point;
 		moveData.posMin = Vec3(-0.5, 0.0, -0.5);
 		moveData.posMin = Vec3(-0.5, 0.0, -0.5);
 		moveData.posMax = Vec3(0.5, 0.0, 0.5);
 		moveData.posMax = Vec3(0.5, 0.0, 0.5);
-		auto mevent = scene.getEventManager().newMovableEvent(0.0, 2.0, moveData);
+		MovableEvent* mevent;
+		scene.getEventManager().newEvent(mevent, 0.0, 2.0, point, moveData);
 		mevent->enableBits(Event::EF_REANIMATE);
 		mevent->enableBits(Event::EF_REANIMATE);
 
 
 		ParticleEmitter* pe = new ParticleEmitter(
 		ParticleEmitter* pe = new ParticleEmitter(

+ 14 - 3
tools/scene/Main.cpp

@@ -691,9 +691,20 @@ static void exportAnimation(
 		{
 		{
 			const aiVectorKey& key = nAnim.mPositionKeys[j];
 			const aiVectorKey& key = nAnim.mPositionKeys[j];
 
 
-			file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
-				<< "<value>" << key.mValue[0] << " " 
-				<< key.mValue[1] << " " << key.mValue[2] << "</value></key>\n";
+			if(config.flipyz)
+			{
+				file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
+					<< "<value>" << key.mValue[0] << " " 
+					<< key.mValue[2] << " " << -key.mValue[1] 
+					<< "</value></key>\n";
+			}
+			else
+			{
+				file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
+					<< "<value>" << key.mValue[0] << " " 
+					<< key.mValue[1] << " " << key.mValue[2] 
+					<< "</value></key>\n";
+			}
 		}
 		}
 		file << "\t\t\t</positionKeys>\n";
 		file << "\t\t\t</positionKeys>\n";