Ver Fonte

Fixing bugs

Panagiotis Christopoulos Charitos há 11 anos atrás
pai
commit
a333caecd0

+ 5 - 5
include/anki/AnKi.h

@@ -6,15 +6,15 @@
 #ifndef ANKI_ANKI_H
 #define ANKI_ANKI_H
 
-#include "anki/Util.h"
-#include "anki/Math.h"
-#include "anki/Scene.h"
-#include "anki/Event.h"
-
 /// @defgroup anki_public Public AnKi interfaces
 /// This includes the interfaces that should be exposed from the library
 
 /// @defgroup anki_private Private AnKi interfaces
 /// This includes the interfaces that shouldn't be exposed from the library
 
+#include "anki/Util.h"
+#include "anki/Math.h"
+#include "anki/Scene.h"
+#include "anki/Event.h"
+
 #endif

+ 11 - 1
include/anki/Util.h

@@ -42,21 +42,31 @@
 #include "anki/util/Allocator.h"
 #include "anki/util/Array.h"
 #include "anki/util/Assert.h"
-#include "anki/util/Thread.h"
+#include "anki/util/Atomic.h"
 #include "anki/util/Bitset.h"
+#include "anki/util/DArray.h"
 #include "anki/util/Dictionary.h"
+#include "anki/util/Enum.h"
 #include "anki/util/File.h"
 #include "anki/util/Filesystem.h"
 #include "anki/util/Functions.h"
+#include "anki/util/Hash.h"
 #include "anki/util/HighRezTimer.h"
 #include "anki/util/LinuxMalinfo.h"
+#include "anki/util/List.h"
+#include "anki/util/Logger.h"
 #include "anki/util/Memory.h"
 #include "anki/util/NonCopyable.h"
 #include "anki/util/Object.h"
+//#include "anki/util/Observer.h"
+#include "anki/util/Ptr.h"
+#include "anki/util/ScopeDestroyer.h"
 #include "anki/util/Singleton.h"
 #include "anki/util/StdTypes.h"
+#include "anki/util/String.h"
 #include "anki/util/StringList.h"
 #include "anki/util/System.h"
+#include "anki/util/Thread.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Visitor.h"
 

+ 1 - 4
include/anki/event/Event.h

@@ -79,10 +79,7 @@ public:
 		return m_node;
 	}
 
-	void markForDeletion()
-	{
-		m_flags |= Flag::MARKED_FOR_DELETION;
-	}
+	void setMarkedForDeletion();
 
 	Bool getMarkedForDeletion() const
 	{

+ 6 - 1
include/anki/event/EventManager.h

@@ -66,7 +66,7 @@ public:
 	/// Delete an event. It actualy marks it for deletion
 	void deleteEvent(Event* event)
 	{
-		event->markForDeletion();
+		event->setMarkedForDeletion();
 	}
 
 	/// Update
@@ -75,6 +75,11 @@ public:
 	/// Delete events that pending deletion
 	void deleteEventsMarkedForDeletion();
 
+	void increaseMarkedForDeletion()
+	{
+		++m_markedForDeletionCount;
+	}
+
 private:
 	SceneGraph* m_scene = nullptr;
 	EventsContainer m_events;

+ 1 - 1
include/anki/gl/GlCommandBufferHandle.h

@@ -39,7 +39,7 @@ public:
 	/// Add another command buffer for execution
 	void pushBackOtherCommandBuffer(GlCommandBufferHandle& commands);
 
-	/// Flush command buffer for deffered deletion
+	/// Flush command buffer for deffered execution.
 	void flush();
 
 	/// Flush and wait to finish

+ 26 - 23
include/anki/scene/SceneGraph.h

@@ -152,24 +152,7 @@ public:
 	/// Iterate a range of scene nodes using a lambda
 	template<typename Func>
 	ANKI_USE_RESULT Error iterateSceneNodes(
-		PtrSize begin, PtrSize count, Func func)
-	{
-		ANKI_ASSERT(begin < m_nodesCount && count <= m_nodesCount);
-		auto it = m_nodes.getBegin() + begin;
-		
-		while(count-- != 0)
-		{
-			Error err = func(*(*it));
-			if(err)
-			{
-				return err;
-			}
-
-			++it;
-		}
-
-		return ErrorCode::NONE;
-	}
+		PtrSize begin, PtrSize end, Func func);
 
 	/// Create a new SceneNode
 	template<typename Node, typename... Args>
@@ -179,16 +162,13 @@ public:
 	/// Delete a scene node. It actualy marks it for deletion
 	void deleteSceneNode(SceneNode* node)
 	{
-		node->markForDeletion();
+		node->setMarkedForDeletion();
 	}
+
 	void increaseObjectsMarkedForDeletion()
 	{
 		++m_objectsMarkedForDeletionCount;
 	}
-	void decreaseObjectsMarkedForDeletion()
-	{
-		++m_objectsMarkedForDeletionCount;
-	}
 
 	/// @privatesection
 	/// @{
@@ -273,6 +253,29 @@ inline Error SceneGraph::newSceneNode(
 
 	return err;
 }
+
+//==============================================================================
+template<typename Func>
+Error SceneGraph::iterateSceneNodes(PtrSize begin, PtrSize end, Func func)
+{
+	ANKI_ASSERT(begin < m_nodesCount && end <= m_nodesCount);
+	auto it = m_nodes.getBegin() + begin;
+	
+	PtrSize count = end - begin;
+	while(count-- != 0)
+	{
+		ANKI_ASSERT(it != m_nodes.getEnd());
+		Error err = func(*(*it));
+		if(err)
+		{
+			return err;
+		}
+
+		++it;
+	}
+
+	return ErrorCode::NONE;
+}
 /// @}
 
 } // end namespace anki

+ 28 - 8
include/anki/scene/SceneNode.h

@@ -7,7 +7,7 @@
 #define ANKI_SCENE_SCENE_NODE_H
 
 #include "anki/scene/Common.h"
-#include "anki/scene/SceneObject.h"
+#include "anki/util/Object.h"
 #include "anki/scene/SceneComponent.h"
 
 namespace anki {
@@ -19,9 +19,11 @@ class ResourceManager;
 /// @{
 
 /// Interface class backbone of scene
-class SceneNode: public SceneObject
+class SceneNode: public Object<SceneNode, SceneAllocator<SceneNode>>
 {
 public:
+	using Base = Object<SceneNode, SceneAllocator<SceneNode>>;
+
 	/// The one and only constructor
 	SceneNode(SceneGraph* scene);
 
@@ -32,6 +34,11 @@ public:
 	///             is not searchable.
 	ANKI_USE_RESULT Error create(const CString& name);
 
+	SceneGraph& getSceneGraph()
+	{
+		return *m_scene;
+	}
+
 	/// Return the name. It may be empty for nodes that we don't want to track
 	CString getName() const
 	{
@@ -43,6 +50,22 @@ public:
 		return m_componentsCount;
 	}
 
+	Bool getMarkedForDeletion() const
+	{
+		return m_forDeletion;
+	}
+
+	void setMarkedForDeletion();
+
+	SceneAllocator<U8> getSceneAllocator() const;
+
+	SceneAllocator<U8> getSceneFrameAllocator() const;
+
+	ANKI_USE_RESULT Error addChild(SceneNode* obj)
+	{
+		return Base::addChild(getSceneAllocator(), obj);
+	}
+
 	/// This is called by the scene every frame after logic and before
 	/// rendering. By default it does nothing
 	/// @param prevUpdateTime Timestamp of the previous update
@@ -139,11 +162,6 @@ public:
 		return *out;
 	}
 
-	static constexpr SceneObject::Type getClassType()
-	{
-		return SceneObject::Type::SCENE_NODE;
-	}
-
 protected:
 	/// Append a component to the components container. The SceneNode will not
 	/// take ownership
@@ -155,9 +173,11 @@ protected:
 	ResourceManager& getResourceManager();
 
 private:
-	SceneString m_name; ///< A unique name
+	SceneGraph* m_scene = nullptr;
 	SceneDArray<SceneComponent*> m_components;
 	U8 m_componentsCount = 0;
+	SceneString m_name; ///< A unique name
+	Bool8 m_forDeletion = false;
 };
 
 /// @}

+ 0 - 124
include/anki/scene/SceneObject.h

@@ -1,124 +0,0 @@
-// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_SCENE_SCENE_OBJECT_H
-#define ANKI_SCENE_SCENE_OBJECT_H
-
-#include "anki/scene/Common.h"
-#include "anki/util/Object.h"
-#include "anki/util/Functions.h"
-#include "anki/util/Enum.h"
-
-namespace anki {
-
-// Forward
-class SceneGraph;
-class SceneObject;
-
-/// @addtogroup scene
-/// @{
-
-/// The callbacks of SceneObject
-struct SceneObjectCallbackCollection
-{
-	/// Called when a child is been removed from a parent
-	void onChildRemoved(SceneObject* child, SceneObject* parent);
-
-	/// Called when a child is been added to a parent
-	void onChildAdded(SceneObject* child, SceneObject* parent)
-	{
-		ANKI_ASSERT(child && parent);
-		// Do nothing
-	}
-};
-
-/// The base of all scene related objects
-class SceneObject: 
-	public Object<SceneObject, SceneAllocator<SceneObject>, 
-	SceneObjectCallbackCollection>
-{
-public:
-	using Base = Object<SceneObject, SceneAllocator<SceneObject>,
-		SceneObjectCallbackCollection>;
-
-	enum class Type: U8
-	{
-		NONE = 0,
-		SCENE_NODE = 1 << 0,
-		EVENT = 1 << 1,
-		_TYPE_MASK = SCENE_NODE | EVENT,
-		_MARKED_FOR_DELETION = 1 << 2
-	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Type, friend)
-
-	SceneObject(Type type, SceneGraph* scene);
-
-	virtual ~SceneObject();
-
-	Type getType() const
-	{
-		return m_bits & Type::_TYPE_MASK;
-	}
-
-	SceneAllocator<U8> getSceneAllocator() const;
-
-	SceneAllocator<U8> getSceneFrameAllocator() const;
-
-	SceneGraph& getSceneGraph()
-	{
-		return *m_scene;
-	}
-
-	ANKI_USE_RESULT Error addChild(SceneObject* obj)
-	{
-		return Base::addChild(getSceneAllocator(), obj);
-	}
-
-	const SceneGraph& getSceneGraph() const
-	{
-		return *m_scene;
-	}
-
-	Bool isMarkedForDeletion() const
-	{
-		return (m_bits & Type::_MARKED_FOR_DELETION) != Type::NONE;
-	}
-
-	void markForDeletion();
-
-	/// Downcast the class
-	template<typename TScObj>
-	TScObj& downCast()
-	{
-		ANKI_ASSERT(TScObj::getClassType() == getType());
-		TScObj* out = staticCastPtr<TScObj*>(this);
-		return *out;
-	}
-
-	/// Downcast the class
-	template<typename TScObj>
-	const TScObj& downCast() const
-	{
-		ANKI_ASSERT(TScObj::getClassType() == getType());
-		const TScObj* out = staticCastPtr<const TScObj*>(this);
-		return *out;
-	}
-
-private:
-	SceneGraph* m_scene = 0;
-	Type m_bits = Type::NONE; ///< Contains the type and other flags
-};
-
-inline void SceneObjectCallbackCollection::onChildRemoved(
-	SceneObject* child, SceneObject* parent)
-{
-	child->markForDeletion();
-}
-
-/// @}
-
-} // end namespace anki
-
-#endif

+ 7 - 0
include/anki/scene/Visibility.h

@@ -99,6 +99,13 @@ public:
 		return err;
 	}
 
+	void prepareMerge()
+	{
+		ANKI_ASSERT(m_renderablesCount == 0 && m_lightsCount == 0);
+		m_renderablesCount = m_renderables.getSize();
+		m_lightsCount = m_lights.getSize();
+	}
+
 	VisibleNode* getRenderablesBegin()
 	{
 		return (m_renderablesCount) ? &m_renderables[0] : nullptr;

+ 5 - 8
include/anki/util/List.h

@@ -329,7 +329,9 @@ public:
 	/// Find item.
 	Iterator find(const Value& a);
 
-	/// Quicksort.
+	/// Sort the list.
+	/// @note It's almost 300 slower than std::list::sort, at some point replace
+	///       the algorithm.
 	template<typename TCompFunc = std::less<Value>>
 	void sort(TCompFunc compFunc = TCompFunc());
 
@@ -349,13 +351,8 @@ private:
 		b.m_tail = nullptr;
 	}
 
-	/// Sort.
-	template<typename TCompFunc>
-	void sortInternal(TCompFunc compFunc, Node* l, Node* r);
-
-	/// Used in sortInternal.
-	template<typename TCompFunc>
-	Node* partition(TCompFunc compFunc, Node* l, Node* r);
+	/// Used in sort.
+	Node* swap(Node* one, Node* two);
 
 	void pushBackNode(Node* node);
 };

+ 59 - 33
include/anki/util/List.inl.h

@@ -250,52 +250,78 @@ template<typename T, typename TAlloc>
 template<typename TCompFunc>
 void List<T, TAlloc>::sort(TCompFunc compFunc)
 {
-	sortInternal(compFunc, m_head, m_tail);
-}
+	Node* sortPtr;
+	Node* newTail = m_tail;
 
-//==============================================================================
-template<typename T, typename TAlloc>
-template<typename TCompFunc>
-void List<T, TAlloc>::sortInternal(TCompFunc compFunc, Node* l, Node* r)
-{
-	if (r != nullptr && l != r && l != r->m_next)
+	while(newTail != m_head)
 	{
-		Node* p = partition(compFunc, l, r);
-		sortInternal(compFunc, l, p->m_prev);
-		sortInternal(compFunc, p->m_next, r);
+		sortPtr = m_head;
+		Bool swapped = false;
+		Bool end = false;
+
+		do
+		{
+			ANKI_ASSERT(sortPtr != nullptr);
+			Node* sortPtrNext = sortPtr->m_next;
+			ANKI_ASSERT(sortPtrNext != nullptr);
+
+			if(compFunc(sortPtrNext->m_value, sortPtr->m_value))
+			{
+				sortPtr = swap(sortPtr, sortPtrNext);
+				swapped = true;
+			}
+			else
+			{
+				sortPtr = sortPtrNext;
+			}
+
+			if(sortPtr == m_tail || sortPtr == newTail)
+			{
+				if(swapped)
+				{
+					newTail = sortPtr->m_prev;
+				}
+				else
+				{
+					newTail = m_head;
+				}
+
+				end = true;
+			}
+		} while(!end);
 	}
 }
 
 //==============================================================================
 template<typename T, typename TAlloc>
-template<typename TCompFunc>
-typename List<T, TAlloc>::Node* List<T, TAlloc>::partition(
-	TCompFunc compFunc, Node* l, Node* r)
+typename List<T, TAlloc>::Node* List<T, TAlloc>::swap(Node* one, Node* two)
 {
-	// Set pivot as h element
-	Value& x = r->m_value;
- 
-	// similar to i = l-1 for array implementation
-	Node* i = l->m_prev;
- 
-	// Similar to "for (int j = l; j <= h- 1; j++)"
-	for(Node* j = l; j != r; j = j->m_next)
+	if(one->m_prev == nullptr)
 	{
-		if(compFunc(j->m_value, x))
-		{
-			// Similar to i++ for array
-			i = (i == nullptr) ? l : i->m_next;
+		m_head = two;
+	}
+	else
+	{
+		ANKI_ASSERT(one->m_prev);
+		one->m_prev->m_next = two;
+	}
 
-			// Swap
-			std::swap(i->m_value, j->m_value);
-		}
+	if(two->m_next == nullptr)
+	{
+		m_tail = one;
+	}
+	else
+	{
+		ANKI_ASSERT(two->m_next);
+		two->m_next->m_prev = one;
 	}
 
-	i = (i == nullptr) ? l : i->m_next; // Similar to i++
-	
-	std::swap(i->m_value, r->m_value);
+	two->m_prev = one->m_prev;
+	one->m_next = two->m_next;
+	one->m_prev = two;
+	two->m_next = one;
 
-	return i;
+	return one;
 }
 
 //==============================================================================

+ 4 - 2
include/anki/util/Object.inl.h

@@ -16,7 +16,9 @@ void Object<T, TAlloc, TCallbackCollection>::destroy(Allocator alloc)
 	}
 
 	// Remove all children (fast version)
-	for(typename Container::Iterator it : m_children)
+	auto it = m_children.getBegin();
+	auto end = m_children.getEnd();
+	for(; it != end; ++it)
 	{
 		Value* child = *it;
 		child->m_parent = nullptr;
@@ -65,7 +67,7 @@ void Object<T, TAlloc, TCallbackCollection>::removeChild(
 
 	ANKI_ASSERT(it != m_children.getEnd() && "Child not found");
 
-	m_children.erase(it);
+	m_children.erase(alloc, it);
 	child->m_parent = nullptr;
 
 	m_callbacks.onChildRemoved(child, getSelf());

+ 42 - 20
include/anki/util/String.h

@@ -131,44 +131,67 @@ public:
 
 	Bool operator==(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) == 0;
+		if(m_ptr == nullptr || b.m_ptr == nullptr)
+		{
+			return m_ptr == b.m_ptr;
+		}
+		else
+		{
+			return std::strcmp(m_ptr, b.m_ptr) == 0;
+		}
 	}
 
 	Bool operator!=(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) != 0;
+		return !((*this) == b);
 	}
 
 	Bool operator<(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) < 0;
+		if(m_ptr == nullptr || b.m_ptr == nullptr)
+		{
+			return false;
+		}
+		else
+		{
+			return std::strcmp(m_ptr, b.m_ptr) < 0;
+		}
 	}
 
 	Bool operator<=(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) <= 0;
+		if(m_ptr == nullptr || b.m_ptr == nullptr)
+		{
+			return m_ptr == b.m_ptr;
+		}
+		else
+		{
+			return std::strcmp(m_ptr, b.m_ptr) <= 0;
+		}
 	}
 
 	Bool operator>(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) > 0;
+		if(m_ptr == nullptr || b.m_ptr == nullptr)
+		{
+			return false;
+		}
+		else
+		{
+			return std::strcmp(m_ptr, b.m_ptr) > 0;
+		}
 	}
 
 	Bool operator>=(const CString& b) const 
 	{
-		checkInit();
-		b.checkInit();
-		return std::strcmp(m_ptr, b.m_ptr) >= 0;
+		if(m_ptr == nullptr || b.m_ptr == nullptr)
+		{
+			return m_ptr == b.m_ptr;
+		}
+		else
+		{
+			return std::strcmp(m_ptr, b.m_ptr) >= 0;
+		}
 	}
 
 	/// Get the underlying C string.
@@ -181,8 +204,7 @@ public:
 	/// Get the string length.
 	U getLength() const 
 	{
-		checkInit();
-		if(m_length == 0)
+		if(m_length == 0 && m_ptr != nullptr)
 		{
 			m_length = std::strlen(m_ptr);
 		}

+ 11 - 5
include/anki/util/String.inl.h

@@ -9,12 +9,18 @@ namespace anki {
 template<typename TAlloc>
 Error StringBase<TAlloc>::create(Allocator alloc, const CStringType& cstr)
 {
-	auto size = cstr.getLength() + 1;
-	Error err = m_data.create(alloc, size);
-
-	if(!err)
+	Error err = ErrorCode::NONE;
+	
+	auto len = cstr.getLength();
+	if(len > 0)
 	{
-		std::memcpy(&m_data[0], cstr.get(), sizeof(Char) * size);
+		auto size = len + 1;
+		err = m_data.create(alloc, size);
+
+		if(!err)
+		{
+			std::memcpy(&m_data[0], &cstr[0], sizeof(Char) * size);
+		}
 	}
 
 	return err;

+ 1 - 1
include/anki/util/Thread.h

@@ -11,7 +11,7 @@
 #include "anki/util/NonCopyable.h"
 #include <atomic>
 
-#define ANKI_DISABLE_THREADPOOL_THREADING 0
+#define ANKI_DISABLE_THREADPOOL_THREADING 1
 
 namespace anki {
 

+ 10 - 0
src/event/Event.cpp

@@ -34,6 +34,16 @@ Error Event::create(
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+void Event::setMarkedForDeletion()
+{
+	if(!getMarkedForDeletion())
+	{
+		m_flags |= Flag::MARKED_FOR_DELETION;
+		m_manager->increaseMarkedForDeletion();
+	}
+}
+
 //==============================================================================
 F32 Event::getDelta(F32 crntTime) const
 {

+ 13 - 3
src/event/EventManager.cpp

@@ -71,9 +71,9 @@ Error EventManager::updateAllEvents(F32 prevUpdateTime, F32 crntTime)
 		}
 
 		if(event->getSceneNode() != nullptr 
-			&& event->getSceneNode()->isMarkedForDeletion())
+			&& event->getSceneNode()->getMarkedForDeletion())
 		{
-			event->markForDeletion();
+			event->setMarkedForDeletion();
 			continue;
 		}
 
@@ -108,7 +108,7 @@ Error EventManager::updateAllEvents(F32 prevUpdateTime, F32 crntTime)
 				err = event->onKilled(prevUpdateTime, crntTime, kill);
 				if(!err && kill)
 				{
-					event->markForDeletion();
+					event->setMarkedForDeletion();
 				}
 			}
 		}
@@ -122,6 +122,16 @@ void EventManager::deleteEventsMarkedForDeletion()
 {
 	SceneAllocator<U8> alloc = getSceneAllocator();
 
+	// Check if nodes are marked for deletion
+	if(true)
+	{
+		auto it = m_events.getBegin();
+		auto end = m_events.getEnd();
+		for(; it != end; ++it)
+		{
+		}
+	}
+
 	// Gather events for deletion
 	while(m_markedForDeletionCount != 0)
 	{

+ 9 - 13
src/scene/ModelNode.cpp

@@ -103,7 +103,7 @@ Error ModelPatchNode::buildRendering(RenderingBuildData& data)
 //==============================================================================
 void ModelPatchNode::getRenderWorldTransform(U index, Transform& trf)
 {
-	SceneNode* parent = &getParent()->downCast<SceneNode>();
+	SceneNode* parent = getParent();
 	ANKI_ASSERT(parent);
 	MoveComponent& move = parent->getComponent<MoveComponent>();
 
@@ -115,7 +115,7 @@ void ModelPatchNode::getRenderWorldTransform(U index, Transform& trf)
 	else
 	{
 		// Asking for a next instance
-		SceneNode* parent = &getParent()->downCast<SceneNode>();
+		SceneNode* parent = getParent();
 		ANKI_ASSERT(parent);
 		ModelNode* mnode = staticCastPtr<ModelNode*>(parent);
 
@@ -257,7 +257,7 @@ Error ModelNode::create(const CString& name, const CString& modelFname)
 			{
 				m_modelPatches[count++] = mpn;
 
-				err = SceneObject::addChild(mpn);
+				err = addChild(mpn);
 			}
 		}
 	}
@@ -299,20 +299,16 @@ Error ModelNode::frameUpdate(F32, F32)
 		return err;
 	}
 
-	err = SceneObject::visitChildren([&](SceneObject& obj) -> Error
+	err = visitChildren([&](SceneNode& sn) -> Error
 	{
-		if(obj.getType() == SceneNode::getClassType())
+		if(sn.tryGetComponent<InstanceComponent>())
 		{
-			SceneNode& sn = obj.downCast<SceneNode>();
-			if(sn.tryGetComponent<InstanceComponent>())
-			{
-				MoveComponent& move = sn.getComponent<MoveComponent>();
+			MoveComponent& move = sn.getComponent<MoveComponent>();
 
-				instanceMoves[instanceMovesCount++] = &move;
+			instanceMoves[instanceMovesCount++] = &move;
 
-				instancesTimestamp = 
-					std::max(instancesTimestamp, move.getTimestamp());
-			}
+			instancesTimestamp = 
+				std::max(instancesTimestamp, move.getTimestamp());
 		}
 
 		return ErrorCode::NONE;

+ 10 - 15
src/scene/MoveComponent.cpp

@@ -37,11 +37,10 @@ Bool MoveComponent::updateWorldTransform(SceneNode& node)
 	// If dirty then update world transform
 	if(dirty)
 	{
-		const SceneObject* parentObj = node.getParent();
+		const SceneNode* parent = node.getParent();
 
-		if(parentObj)
+		if(parent)
 		{
-			const SceneNode* parent = &parentObj->downCast<SceneNode>();
 			const MoveComponent* parentMove = 
 				parent->tryGetComponent<MoveComponent>();
 
@@ -79,21 +78,17 @@ Bool MoveComponent::updateWorldTransform(SceneNode& node)
 	// whole tree because you will re-walk it later
 	if(dirty)
 	{
-		Error err = node.visitChildrenMaxDepth(1, [](SceneObject& obj) -> Error
+		Error err = node.visitChildrenMaxDepth(1, 
+			[](SceneNode& childNode) -> Error
 		{ 
-			if(obj.getType() == SceneNode::getClassType())
+			Error e = childNode.iterateComponentsOfType<MoveComponent>(
+				[](MoveComponent& mov) -> Error
 			{
-				SceneNode& childNode = obj.downCast<SceneNode>();
+				mov.markForUpdate();
+				return ErrorCode::NONE;
+			});
 
-				Error e = childNode.iterateComponentsOfType<MoveComponent>(
-					[](MoveComponent& mov) -> Error
-				{
-					mov.markForUpdate();
-					return ErrorCode::NONE;
-				});
-
-				(void)e;
-			}
+			(void)e;
 
 			return ErrorCode::NONE;
 		});

+ 13 - 17
src/scene/ParticleEmitter.cpp

@@ -562,6 +562,8 @@ Error ParticleEmitter::doInstancingCalcs()
 	// Gather the move components of the instances
 	//
 	SceneFrameDArray<MoveComponent*> instanceMoves;
+	SceneFrameDArray<MoveComponent*>::ScopeDestroyer instanceMovesd(
+		&instanceMoves, getSceneFrameAllocator());
 	U instanceMovesCount = 0;
 	Timestamp instancesTimestamp = 0;
 
@@ -571,20 +573,16 @@ Error ParticleEmitter::doInstancingCalcs()
 		return err;
 	}
 
-	err = SceneObject::visitChildren([&](SceneObject& obj) -> Error
+	err = SceneNode::visitChildren([&](SceneNode& sn) -> Error
 	{	
-		if(obj.getType() == SceneNode::getClassType())
+		if(sn.tryGetComponent<InstanceComponent>())
 		{
-			SceneNode& sn = obj.downCast<SceneNode>();
-			if(sn.tryGetComponent<InstanceComponent>())
-			{
-				MoveComponent& move = sn.getComponent<MoveComponent>();
+			MoveComponent& move = sn.getComponent<MoveComponent>();
 
-				instanceMoves[instanceMovesCount++] = &move;
+			instanceMoves[instanceMovesCount++] = &move;
 
-				instancesTimestamp = 
-					std::max(instancesTimestamp, move.getTimestamp());
-			}
+			instancesTimestamp = 
+				std::max(instancesTimestamp, move.getTimestamp());
 		}
 
 		return ErrorCode::NONE;
@@ -655,13 +653,14 @@ Error ParticleEmitter::doInstancingCalcs()
 		if(!err)
 		{
 			U count = 0;
+			SpatialComponent* meSpatial = this;
 			err = iterateComponentsOfType<SpatialComponent>(
 				[&](SpatialComponent& sp) -> Error
 			{
 				Error err2 = ErrorCode::NONE;
 
 				// Skip the first
-				if(count != 0)	
+				if(&sp != meSpatial)	
 				{
 					ObbSpatialComponent* msp = 
 						staticCastPtr<ObbSpatialComponent*>(&sp);
@@ -670,9 +669,8 @@ Error ParticleEmitter::doInstancingCalcs()
 					{
 						Obb aobb = m_obb;
 						aobb.setCenter(Vec4(0.0));
-						msp->m_obb =
-							aobb.getTransformed(m_transforms[count - 1]);
-
+						msp->m_obb = aobb.getTransformed(m_transforms[count]);
+						++count;
 						msp->markForUpdate();
 					}
 					else
@@ -681,12 +679,10 @@ Error ParticleEmitter::doInstancingCalcs()
 					}
 				}
 
-				++count;
-
 				return err2;
 			});
 
-			ANKI_ASSERT(count - 1 == m_transforms.getSize());
+			ANKI_ASSERT(count == m_transforms.getSize());
 		}
 	} // end if instancing
 

+ 11 - 16
src/scene/SceneGraph.cpp

@@ -9,7 +9,6 @@
 #include "anki/scene/InstanceNode.h"
 #include "anki/core/Counters.h"
 #include "anki/renderer/Renderer.h"
-#include "anki/misc/Xml.h"
 
 namespace anki {
 
@@ -67,17 +66,9 @@ public:
 		}
 
 		// Update children
-		err = node.visitChildren([&](SceneObject& obj) -> Error
+		err = node.visitChildren([&](SceneNode& child) -> Error
 		{
-			Error err2 = ErrorCode::NONE;
-
-			if(obj.getType() == SceneObject::Type::SCENE_NODE)
-			{
-				SceneNode& child = obj.downCast<SceneNode>();
-				err2 = updateInternal(child, prevTime, crntTime);
-			}
-
-			return err2;
+			return updateInternal(child, prevTime, crntTime);
 		});
 
 		// Frame update
@@ -224,19 +215,23 @@ void SceneGraph::deleteNodesMarkedForDeletion()
 	/// should have finished their tasks
 	while(m_objectsMarkedForDeletionCount > 0)
 	{
+		Bool found = false;
 		auto it = m_nodes.begin();
-		for(; it != m_nodes.end(); it++)
+		auto end = m_nodes.end();
+		for(; it != end; it++)
 		{
-			if((*it)->isMarkedForDeletion())
+			if((*it)->getMarkedForDeletion())
 			{
 				// Delete node
 				unregisterNode(*it);
-				m_alloc.deleteInstance(*it);		
+				m_alloc.deleteInstance(*it);
+				found = true;
+				break;
 			}
 		}
 
-		// Do the same for events
-		m_events.deleteEventsMarkedForDeletion();
+		(void)found;
+		ANKI_ASSERT(found && "Something is wrong with marked for deletion");
 	}
 }
 

+ 37 - 2
src/scene/SceneNode.cpp

@@ -10,7 +10,7 @@ namespace anki {
 
 //==============================================================================
 SceneNode::SceneNode(SceneGraph* scene)
-:	SceneObject(Type::SCENE_NODE, scene)
+:	m_scene(scene)
 {}
 
 //==============================================================================
@@ -23,10 +23,45 @@ Error SceneNode::create(const CString& name)
 SceneNode::~SceneNode()
 {
 	auto alloc = getSceneAllocator();
+	Base::destroy(alloc);
 	m_name.destroy(alloc);
 	m_components.destroy(alloc);
 }
 
+//==============================================================================
+void SceneNode::setMarkedForDeletion()
+{
+	// Mark for deletion only when it's not already marked because we don't 
+	// want to increase the counter again
+	if(!getMarkedForDeletion())
+	{
+		m_forDeletion = true;
+		m_scene->increaseObjectsMarkedForDeletion();
+	}
+
+	Error err = visitChildren([](SceneNode& obj) -> Error
+	{
+		obj.setMarkedForDeletion();
+		return ErrorCode::NONE;
+	});
+
+	(void)err;
+}
+
+//==============================================================================
+SceneAllocator<U8> SceneNode::getSceneAllocator() const
+{
+	ANKI_ASSERT(m_scene);
+	return m_scene->getAllocator();
+}
+
+//==============================================================================
+SceneAllocator<U8> SceneNode::getSceneFrameAllocator() const
+{
+	ANKI_ASSERT(m_scene);
+	return m_scene->getFrameAllocator();
+}
+
 //==============================================================================
 U32 SceneNode::getLastUpdateFrame() const
 {
@@ -74,7 +109,7 @@ void SceneNode::removeComponent(SceneComponent* comp)
 //==============================================================================
 ResourceManager& SceneNode::getResourceManager()
 {
-	return getSceneGraph()._getResourceManager();
+	return m_scene->_getResourceManager();
 }
 
 } // end namespace anki

+ 0 - 60
src/scene/SceneObject.cpp

@@ -1,60 +0,0 @@
-// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/scene/SceneObject.h"
-#include "anki/scene/SceneGraph.h"
-
-namespace anki {
-
-//==============================================================================
-SceneObject::SceneObject(Type type, SceneGraph* scene)
-:	Base(),
-	m_scene(scene),
-	m_bits(type)
-{
-	ANKI_ASSERT(m_scene);
-}
-
-//==============================================================================
-SceneObject::~SceneObject()
-{
-	m_scene->decreaseObjectsMarkedForDeletion();
-}
-
-//==============================================================================
-SceneAllocator<U8> SceneObject::getSceneAllocator() const
-{
-	ANKI_ASSERT(m_scene);
-	return m_scene->getAllocator();
-}
-
-//==============================================================================
-SceneAllocator<U8> SceneObject::getSceneFrameAllocator() const
-{
-	ANKI_ASSERT(m_scene);
-	return m_scene->getFrameAllocator();
-}
-
-//==============================================================================
-void SceneObject::markForDeletion()
-{
-	// Mark for deletion only when it's not already marked because we don't 
-	// want to increase the counter again
-	if(!isMarkedForDeletion())
-	{
-		m_bits |= Type::_MARKED_FOR_DELETION	;
-		m_scene->increaseObjectsMarkedForDeletion();
-	}
-
-	Error err = visitChildren([](SceneObject& obj) -> Error
-	{
-		obj.markForDeletion();
-		return ErrorCode::NONE;
-	});
-
-	(void)err;
-}
-
-} // end namespace anki

+ 8 - 23
src/scene/Visibility.cpp

@@ -53,11 +53,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 	// Allocate visible
 	VisibilityTestResults* visible = 
 		m_alloc.newInstance<VisibilityTestResults>();
-
-	if(visible == nullptr)
-	{
-		return ErrorCode::OUT_OF_MEMORY;
-	}
+	if(visible == nullptr) return ErrorCode::OUT_OF_MEMORY;
 
 	// Init visible
 	FrustumComponent::VisibilityStats stats = testedFr.getLastVisibilityStats();
@@ -71,10 +67,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 
 	err = visible->create(
 		m_alloc, stats.m_renderablesCount, stats.m_lightsCount);
-	if(err)
-	{
-		return err;
-	}
+	if(err)	return err;
 
 	// Chose the test range and a few other things
 	PtrSize start, end;
@@ -216,7 +209,8 @@ Error VisibilityTestResults::moveBack(
 	if(count + 1 > c.getSize())
 	{
 		// Need to grow
-		err = c.resize(alloc, c.getSize() * 2);
+		U newSize = (c.getSize() != 0) ? c.getSize() * 2 : 2;
+		err = c.resize(alloc, newSize);
 	}
 
 	if(!err)
@@ -248,10 +242,7 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 	}
 
 	Error err = threadPool.waitForAllThreadsToFinish();
-	if(err)
-	{
-		return err;
-	}
+	if(err)	return err;
 
 	//
 	// Combine results
@@ -270,21 +261,15 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 	// Allocate
 	VisibilityTestResults* visible = 
 		scene.getFrameAllocator().newInstance<VisibilityTestResults>();
-
-	if(visible == nullptr)
-	{
-		return ErrorCode::OUT_OF_MEMORY;
-	}
+	if(visible == nullptr)	return ErrorCode::OUT_OF_MEMORY;
 
 	err = visible->create(
 		scene.getFrameAllocator(), 
 		renderablesSize, 
 		lightsSize);
+	if(err)	return err;
 
-	if(err)
-	{
-		return err;
-	}
+	visible->prepareMerge();
 
 	if(renderablesSize == 0)
 	{

+ 2 - 3
src/util/Thread.cpp

@@ -197,14 +197,13 @@ Threadpool::~Threadpool()
 //==============================================================================
 void Threadpool::assignNewTask(U32 slot, Task* task)
 {
-#if !ANKI_DISABLE_THREADPOOL_THREADING
 	ANKI_ASSERT(slot < getThreadsCount());
-	
 	if(task == nullptr)
 	{
 		task = &m_dummyTask;
 	}
-	
+
+#if !ANKI_DISABLE_THREADPOOL_THREADING
 	m_threads[slot].assignNewTask(task);
 #else
 	Error err = (*task)(slot, m_threadsCount);

+ 1 - 1
testapp/Main.cpp

@@ -233,7 +233,7 @@ Error init()
 		0.7));*/
 #endif
 
-#if 1
+#if 0
 	{
 		ScriptResourcePointer script;
 

+ 31 - 11
tests/util/Foo.h

@@ -6,7 +6,17 @@
 #ifndef ANKI_TESTS_UTIL_FOO_H
 #define ANKI_TESTS_UTIL_FOO_H
 
-#include <iostream>
+#include <cstdio>
+
+#ifndef ANKI_TESTS_FOO_VERBOSE
+#	define ANKI_TESTS_FOO_VERBOSE 0
+#endif
+
+#if ANKI_TESTS_FOO_VERBOSE
+#	define ANKI_TESTS_FOO_PRINT() printf("%s\n", __PRETTY_FUNCTION__)
+#else
+#	define ANKI_TESTS_FOO_PRINT() ((void)0)
+#endif
 
 /// Struct for testing
 struct Foo
@@ -17,53 +27,63 @@ struct Foo
 
 	Foo()
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		++constructorCallCount;
 	}
 
 	Foo(int x_)
-		: x(x_)
+	:	x(x_)
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		++constructorCallCount;
 	}
 
 	Foo(const Foo& b)
-		: x(b.x)
+	:	x(b.x)
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		++constructorCallCount;
 	}
 
 	Foo(Foo&& b)
-		: x(b.x)
+	:	x(b.x)
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		b.x = 0;
 		++constructorCallCount;
 	}
 
 	~Foo()
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		++destructorCallCount;
 	}
 
 	Foo& operator=(const Foo& b)
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		x = b.x;
 		return *this;
 	}
 
 	Foo& operator=(Foo&& b)
 	{
-		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		ANKI_TESTS_FOO_PRINT();
 		x = b.x;
 		b.x = 0;
 		return *this;
 	}
 
+	bool operator==(const Foo& b) const
+	{
+		return x == b.x;
+	}
+
+	bool operator!=(const Foo& b) const
+	{
+		return x != b.x;
+	}
+
 	static void reset()
 	{
 		destructorCallCount = constructorCallCount = 0;

+ 45 - 0
tests/util/List.cpp

@@ -6,6 +6,8 @@
 #include "tests/framework/Framework.h"
 #include "tests/util/Foo.h"
 #include "anki/util/List.h"
+#include "anki/util/HighRezTimer.h"
+#include <list>
 
 ANKI_TEST(Util, List)
 {
@@ -93,6 +95,49 @@ ANKI_TEST(Util, List)
 		a.destroy(alloc);
 	}
 
+	// Extreme sort
+	{
+		const U COUNT = 10000;
+		List<Foo> a;
+		std::list<Foo> b;
+
+		for(U i = 0; i < COUNT; i++)
+		{
+			I randVal = rand();
+			Foo f(randVal);
+
+			ANKI_TEST_EXPECT_NO_ERR(a.pushBack(alloc, f));
+			b.push_back(f);
+		}
+
+		//auto ta = HighRezTimer::getCurrentTime();
+		b.sort([](const Foo& a, const Foo& b){return a.x < b.x;});
+		//auto tb = HighRezTimer::getCurrentTime();
+		a.sort([](const Foo& a, const Foo& b){return a.x < b.x;});
+		//auto tc = HighRezTimer::getCurrentTime();
+
+		//printf("%f %f\n", tb - ta, tc - tb);
+
+		auto ait = a.getBegin();
+		auto bit = b.begin();
+		auto aend = a.getEnd();
+		auto bend = b.end();
+
+		while(ait != aend && bit != bend)
+		{
+			const Foo& afoo = *ait;
+			const Foo& bfoo = *bit;
+
+			ANKI_TEST_EXPECT_EQ(afoo, bfoo);
+			++ait;
+			++bit;
+		}
+
+		ANKI_TEST_EXPECT_EQ(ait, aend);
+		ANKI_TEST_EXPECT_EQ(bit, bend);
+		a.destroy(alloc);
+	}
+
 	// Iterate
 	{
 		List<I> a;