Panagiotis Christopoulos Charitos 12 years ago
parent
commit
0e82b8b7c7
67 changed files with 495 additions and 424 deletions
  1. 3 1
      CMakeLists.txt
  2. 19 7
      bench/Main.cpp
  3. 0 1
      include/anki/Util.h
  4. 1 1
      include/anki/event/AnimationEvent.h
  5. 6 5
      include/anki/math/Euler.h
  6. 17 0
      include/anki/math/Functions.h
  7. 6 5
      include/anki/math/Vec2.h
  8. 6 5
      include/anki/math/Vec3.h
  9. 6 6
      include/anki/math/Vec4.h
  10. 1 1
      include/anki/misc/Xml.h
  11. 1 1
      include/anki/physics/RigidBody.h
  12. 0 14
      include/anki/renderer/Common.h
  13. 2 5
      include/anki/renderer/Drawer.h
  14. 0 1
      include/anki/renderer/Renderer.h
  15. 1 1
      include/anki/renderer/RenderingPass.h
  16. 11 0
      include/anki/resource/Animation.h
  17. 1 1
      include/anki/resource/Material.h
  18. 2 2
      include/anki/resource/MaterialShaderProgramCreator.h
  19. 1 0
      include/anki/resource/ParticleEmitterResource.h
  20. 9 3
      include/anki/resource/ResourceManager.h
  21. 1 1
      include/anki/scene/Camera.h
  22. 1 1
      include/anki/scene/Forward.h
  23. 1 1
      include/anki/scene/FrustumComponent.h
  24. 1 1
      include/anki/scene/InstanceNode.h
  25. 3 4
      include/anki/scene/Light.h
  26. 1 1
      include/anki/scene/MoveComponent.h
  27. 2 2
      include/anki/scene/RenderComponent.h
  28. 3 2
      include/anki/scene/SceneComponent.h
  29. 8 3
      include/anki/scene/SceneNode.h
  30. 98 5
      include/anki/scene/SceneObject.h
  31. 1 1
      include/anki/scene/SpatialComponent.h
  32. 1 1
      include/anki/util/Allocator.h
  33. 1 1
      include/anki/util/Array.h
  34. 0 179
      include/anki/util/DynamicArray.h
  35. 11 3
      include/anki/util/Exception.h
  36. 4 2
      include/anki/util/Functions.h
  37. 0 24
      include/anki/util/Vector.h
  38. 27 3
      shaders/BsCommonFrag.glsl
  39. 18 14
      shaders/GaussianBlurGeneric.glsl
  40. 9 0
      shaders/MsCommonFrag.glsl
  41. 29 34
      shaders/VariableSamplingBlurGeneric.glsl
  42. 2 0
      src/event/AnimationEvent.cpp
  43. 1 1
      src/event/EventManager.cpp
  44. 1 1
      src/gl/BufferObject.cpp
  45. 3 3
      src/gl/ShaderProgram.cpp
  46. 6 3
      src/gl/Texture.cpp
  47. 14 13
      src/renderer/Hdr.cpp
  48. 4 4
      src/renderer/Is.cpp
  49. 1 1
      src/renderer/Lf.cpp
  50. 3 2
      src/renderer/Renderer.cpp
  51. 29 3
      src/resource/Animation.cpp
  52. 10 3
      src/resource/Material.cpp
  53. 6 1
      src/resource/MaterialShaderProgramCreator.cpp
  54. 3 0
      src/resource/ParticleEmitterResource.cpp
  55. 11 2
      src/scene/Light.cpp
  56. 13 17
      src/scene/ModelNode.cpp
  57. 14 9
      src/scene/ParticleEmitter.cpp
  58. 1 1
      src/scene/SceneGraph.cpp
  59. 1 1
      src/scene/SceneNode.cpp
  60. 3 3
      src/scene/SceneObject.cpp
  61. 1 1
      src/scene/Visibility.cpp
  62. 2 2
      src/script/ScriptManager.cpp
  63. 2 0
      src/script/math/Vec2.cpp
  64. 3 0
      src/script/math/Vec3.cpp
  65. 3 0
      src/script/math/Vec4.cpp
  66. 28 3
      src/util/Exception.cpp
  67. 17 7
      testapp/Main.cpp

+ 3 - 1
CMakeLists.txt

@@ -186,10 +186,12 @@ add_subdirectory(extern)
 #
 # Doxygen
 #
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/doxyfile ${CMAKE_CURRENT_BINARY_DIR}/doxyfile @ONLY)
+
 find_package(Doxygen)
 
 if(DOXYGEN_FOUND)
-	configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/doxyfile ${CMAKE_CURRENT_BINARY_DIR}/doxyfile @ONLY)
+	message("++ Doxygen found")
 	
 	add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 
 		COMMENT "Generating API documentation with Doxygen" VERBATIM)

+ 19 - 7
bench/Main.cpp

@@ -54,7 +54,7 @@ void initSubsystems()
 #endif
 	nwinit.depthBits = 0;
 	nwinit.stencilBits = 0;
-	nwinit.fullscreenDesktopRez = true;
+	nwinit.fullscreenDesktopRez = false;
 	nwinit.debugContext = false;
 	NativeWindowSingleton::get().create(nwinit);
 
@@ -85,7 +85,7 @@ void initSubsystems()
 	initializer.get("pps.hdr.exposure") = 8.0;
 	initializer.get("pps.ssao.enabled") = false;
 	initializer.get("pps.ssao.blurringIterationsNum") = 1;
-	initializer.get("pps.ssao.renderingQuality") = 0.25;
+	initializer.get("pps.ssao.renderingQuality") = 0.5;
 	initializer.get("pps.bl.enabled") = true;
 	initializer.get("pps.bl.blurringIterationsNum") = 2;
 	initializer.get("pps.bl.sideBlurFactor") = 1.0;
@@ -102,19 +102,24 @@ void initSubsystems()
 	initializer.get("samples") = 1;
 	initializer.get("is.groundLightEnabled") = false;
 	initializer.get("is.maxPointLights") = 64;
-	initializer.get("is.maxPointLightsPerTile") = 4;
+	initializer.get("is.maxPointLightsPerTile") = 8;
 	initializer.get("is.maxSpotLightsPerTile") = 4;
 	initializer.get("is.maxSpotTexLightsPerTile") = 4;
 	initializer.get("is.sm.poissonEnabled") = false;
 	initializer.get("is.sm.bilinearEnabled") = false;
 	initializer.get("renderingQuality") = 0.5;
-	initializer.get("pps.hdr.renderingQuality") = 0.3;
+	initializer.get("pps.hdr.enabled") = true;
+	initializer.get("pps.hdr.renderingQuality") = 0.4;
+	initializer.get("pps.hdr.blurringDist") = 1.0;
+	initializer.get("pps.hdr.samples") = 5;
+	initializer.get("pps.hdr.blurringIterationsCount") = 1;
+	initializer.get("pps.hdr.exposure") = 8.0;
 	initializer.get("maxTextureSize") = 1024;
 	initializer.get("mrt") = false;
 	initializer.get("tilesXCount") = 16;
 	initializer.get("tilesYCount") = 16;
 	initializer.get("pps.sharpen") = false;
-	initializer.get("pps.gammaCorrection") = false;
+	initializer.get("pps.gammaCorrection") = true;
 #endif
 
 	MainRendererSingleton::get().init(initializer);
@@ -217,6 +222,13 @@ void initScene()
 
 			scene.findSceneNode("pesmoke").addChild(instance);
 		}
+
+		{
+			ParticleEmitter* pe;
+			scene.newSceneNode(pe, ("pesparks" + std::to_string(i)).c_str(), 
+				"particles/sparks.ankipart");
+			pe->setLocalOrigin(lightPos);
+		}
 	}
 #endif
 
@@ -231,8 +243,8 @@ void initScene()
 	scene.newSceneNode(spot, "spot0");
 	spot->setOuterAngle(toRad(45.0));
 	spot->setInnerAngle(toRad(15.0));
-	spot->setLocalTransform(Transform(Vec3(8.27936, 5.86285, 1.85526),
-		Mat3(Quat(-0.125117, 0.620465, 0.154831, 0.758544)), 1.0));
+	spot->setLocalTransform(Transform(Vec3(10.769279, 13.472027, -0.324927),
+		Mat3(Quat(-0.267508, 0.664765, 0.244565, 0.653239)), 1.0));
 	spot->setDiffuseColor(Vec4(2.0));
 	spot->setSpecularColor(Vec4(1.0, 0.0, 1.0, 1.0));
 	spot->setDistance(30.0);

+ 0 - 1
include/anki/Util.h

@@ -7,7 +7,6 @@
 #include "anki/util/Thread.h"
 #include "anki/util/Bitset.h"
 #include "anki/util/Dictionary.h"
-#include "anki/util/DynamicArray.h"
 #include "anki/util/Exception.h"
 #include "anki/util/File.h"
 #include "anki/util/Functions.h"

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

@@ -14,7 +14,7 @@ public:
 		SceneNode* movableSceneNode);
 
 	/// Implements Event::update
-	void update(F32 prevUpdateTime, F32 crntTime);
+	void update(F32 prevUpdateTime, F32 crntTime) override;
 
 private:
 	AnimationResourcePointer anim;

+ 6 - 5
include/anki/math/Euler.h

@@ -162,13 +162,14 @@ public:
 private:
 	/// @name Data
 	/// @{
-	union
+	struct Vec
 	{
-		struct
-		{
-			T x, y, z;
-		} vec;
+		T x, y, z;
+	};
 
+	union
+	{
+		Vec vec;
 		Array<T, 3> arr;
 	};
 	/// @}

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

@@ -6,6 +6,9 @@
 
 namespace anki {
 
+/// @addtogroup Math
+/// @{
+
 //==============================================================================
 // Math constants                                                              =
 //==============================================================================
@@ -101,6 +104,18 @@ inline T sqrt(const T x)
 	return std::sqrt(x);
 }
 
+template<typename T>
+inline T fract(const T x)
+{
+	return x - std::floor(x);
+}
+
+template<typename T>
+inline T mod(const T x, const T y)
+{
+	return x - y * std::floor(x / y);
+}       
+
 //==============================================================================
 // Other math functions                                                        =
 //==============================================================================
@@ -171,6 +186,8 @@ static Type cubicInterpolate(
 	return(a0 * u * u2 + a1 * u2 + a2 * u + a3);
 }
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 6 - 5
include/anki/math/Vec2.h

@@ -294,13 +294,14 @@ public:
 private:
 	/// @name Data members
 	/// @{
-	union
+	struct Vec
 	{
-		struct
-		{
-			T x, y;
-		} vec;
+		T x, y;
+	};
 
+	union
+	{
+		Vec vec;
 		Array<T, 2> arr;
 	};
 	/// @}

+ 6 - 5
include/anki/math/Vec3.h

@@ -439,13 +439,14 @@ public:
 private:
 	/// @name Data
 	/// @{
-	union
+	struct Vec
 	{
-		struct
-		{
-			T x, y, z;
-		} vec;
+		T x, y, z;
+	};
 
+	union
+	{
+		Vec vec;
 		Array<T, 3> arr;
 	};
 	/// @}

+ 6 - 6
include/anki/math/Vec4.h

@@ -397,15 +397,15 @@ public:
 private:
 	/// @name Data
 	/// @{
-	union
+	struct Vec
 	{
-		struct
-		{
-			T x, y, z, w;
-		} vec;
+		T x, y, z, w;
+	};
 
+	union
+	{
+		Vec vec;	
 		Array<T, 4> arr;
-
 		Simd simd;
 	};
 	/// @}

+ 1 - 1
include/anki/misc/Xml.h

@@ -13,7 +13,7 @@
 namespace anki {
 
 /// XML element
-struct XmlElement
+class XmlElement
 {
 	friend class XmlDocument;
 public:

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

@@ -41,7 +41,7 @@ public:
 	Bool update(SceneNode& node, F32 prevTime, F32 crntTime,
 		UpdateType updateType) override;
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return RIGID_BODY;
 	}

+ 0 - 14
include/anki/renderer/Common.h

@@ -1,14 +0,0 @@
-#ifndef ANKI_RENDERER_COMMON_H
-#define ANKI_RENDERER_COMMON_H
-
-/// @addtogroup config
-/// @{
-/// @addtogroup renderer_config
-/// @{
-
-#define ANKI_CFG_RENDERER_PROFILE 1
-
-/// @}
-/// @}
-
-#endif

+ 2 - 5
include/anki/renderer/Drawer.h

@@ -3,16 +3,13 @@
 
 #include "anki/util/StdTypes.h"
 #include "anki/resource/PassLodKey.h"
+#include "anki/scene/Forward.h"
 
 namespace anki {
 
 class Renderer;
-class FrustumComponent;
-class SceneNode;
 class ShaderProgram;
-class RenderComponent;
-class Drawcall;
-class VisibleNode;
+struct Drawcall;
 
 /// It includes all the functions to render a Renderable
 class RenderableDrawer

+ 0 - 1
include/anki/renderer/Renderer.h

@@ -10,7 +10,6 @@
 #include "anki/misc/ConfigSet.h"
 #include "anki/scene/Forward.h"
 
-#include "anki/renderer/Common.h"
 #include "anki/renderer/Ms.h"
 #include "anki/renderer/Is.h"
 #include "anki/renderer/Pps.h"

+ 1 - 1
include/anki/renderer/RenderingPass.h

@@ -6,7 +6,7 @@
 namespace anki {
 
 class Renderer;
-struct RendererInitializer;
+class RendererInitializer;
 
 /// Rendering pass
 class RenderingPass

+ 11 - 0
include/anki/resource/Animation.h

@@ -54,20 +54,30 @@ public:
 
 	/// @name Accessors
 	/// @{
+
+	/// Get a vector of all animation channels
 	const Vector<AnimationChannel>& getChannels() const
 	{
 		return channels;
 	}
 
+	/// Get the duration of the animation in seconds
 	F32 getDuration() const
 	{
 		return duration;
 	}
 
+	/// Get the time (in seconds) the animation should start
 	F32 getStartingTime() const
 	{
 		return startTime;
 	}
+
+	/// The animation repeats
+	Bool getRepeat() const
+	{
+		return repeat;
+	}
 	/// @}
 
 	/// Get the interpolated data
@@ -78,6 +88,7 @@ private:
 	Vector<AnimationChannel> channels;
 	F32 duration;
 	F32 startTime;
+	Bool8 repeat;
 
 	void loadInternal(const XmlElement& el);
 };

+ 1 - 1
include/anki/resource/Material.h

@@ -299,7 +299,7 @@ protected:
 class Material: public MaterialProperties, public NonCopyable
 {
 public:
-	typedef PtrVector<MaterialVariable> VarsContainer;
+	typedef Vector<MaterialVariable*> VarsContainer;
 
 	Material();
 	~Material();

+ 2 - 2
include/anki/resource/MaterialShaderProgramCreator.h

@@ -40,7 +40,7 @@ public:
 		return source;
 	}
 
-	const PtrVector<Input>& getInputVariables() const
+	const Vector<Input*>& getInputVariables() const
 	{
 		return inputs;
 	}
@@ -69,7 +69,7 @@ private:
 
 	std::string source; ///< Shader program final source
 
-	PtrVector<Input> inputs;
+	Vector<Input*> inputs;
 
 	Bool enableUniformBlocks;
 

+ 1 - 0
include/anki/resource/ParticleEmitterResource.h

@@ -35,6 +35,7 @@ struct ParticleEmitterProperties
 		/// this
 		F32 alpha = 1.0;
 		F32 alphaDeviation = 0.0;
+		Bool8 alphaAnimation = false;
 
 		/// Initial force. If not set only the gravity applies
 		Vec3 forceDirection = Vec3(0.0, 1.0, 0.0);

+ 9 - 3
include/anki/resource/ResourceManager.h

@@ -4,6 +4,7 @@
 #include "anki/util/Vector.h"
 #include "anki/util/StdTypes.h"
 #include "anki/util/Singleton.h"
+#include "anki/util/Functions.h"
 #include <string>
 
 namespace anki {
@@ -47,7 +48,7 @@ private:
 /// The singleton of resource manager
 typedef Singleton<ResourceManager> ResourceManagerSingleton;
 
-/// Convenience macro to sanitize resources
+/// Convenience macro to sanitize resources path
 #define ANKI_R(x_) \
 	ResourceManagerSingleton::get().fixResourcePath(x_).c_str()
 
@@ -58,12 +59,17 @@ class TypeResourceManager
 public:
 	typedef TypeResourceManager<Type> Self;
 	typedef ResourceHook<Type> Hook;
-	typedef PtrVector<Hook> Container;
+	typedef Vector<Hook*> Container;
 	typedef typename Container::iterator Iterator;
 	typedef typename Container::const_iterator ConstIterator;
 
 	virtual ~TypeResourceManager()
-	{}
+	{
+		for(auto it : hooks)
+		{
+			propperDelete(it);
+		}
+	}
 
 	Hook& load(const char* filename);
 

+ 1 - 1
include/anki/scene/Camera.h

@@ -51,7 +51,7 @@ public:
 	void componentUpdated(SceneComponent& comp, 
 		SceneComponent::UpdateType) override
 	{
-		if(comp.getType() == MoveComponent::getGlobType())
+		if(comp.getType() == MoveComponent::getClassType())
 		{
 			moveUpdate(comp.downCast<MoveComponent>());
 		}

+ 1 - 1
include/anki/scene/Forward.h

@@ -20,7 +20,7 @@ class Path;
 
 // Other
 class SceneGraph;
-class VisibleNode;
+struct VisibleNode;
 class Sector;
 
 } // end namespace anki

+ 1 - 1
include/anki/scene/FrustumComponent.h

@@ -115,7 +115,7 @@ public:
 		visible = nullptr;
 	}
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return FRUSTUM_COMPONENT;
 	}

+ 1 - 1
include/anki/scene/InstanceNode.h

@@ -16,7 +16,7 @@ public:
 		: SceneComponent(INSTANCE_COMPONENT, node)
 	{}
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return INSTANCE_COMPONENT;
 	}

+ 3 - 4
include/anki/scene/Light.h

@@ -5,6 +5,7 @@
 #include "anki/scene/MoveComponent.h"
 #include "anki/scene/FrustumComponent.h"
 #include "anki/scene/SpatialComponent.h"
+#include "anki/scene/Forward.h"
 #include "anki/resource/Resource.h"
 #include "anki/resource/TextureResource.h"
 
@@ -14,11 +15,9 @@ namespace anki {
 class LightComponent: public SceneComponent
 {
 public:
-	LightComponent(SceneNode* node)
-		: SceneComponent(LIGHT_COMPONENT, node)
-	{}
+	LightComponent(Light* node);
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return LIGHT_COMPONENT;
 	}

+ 1 - 1
include/anki/scene/MoveComponent.h

@@ -133,7 +133,7 @@ public:
 	}
 	/// @}
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return MOVE_COMPONENT;
 	}

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

@@ -10,7 +10,7 @@
 
 namespace anki {
 
-class Drawcall;
+struct Drawcall;
 
 /// @addtogroup Scene
 /// @{
@@ -227,7 +227,7 @@ public:
 		}
 	}
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return RENDER_COMPONENT;
 	}

+ 3 - 2
include/anki/scene/SceneComponent.h

@@ -3,6 +3,7 @@
 
 #include "anki/scene/Common.h"
 #include "anki/core/Timestamp.h"
+#include "anki/util/Functions.h"
 
 namespace anki {
 
@@ -69,8 +70,8 @@ public:
 	template<typename TComponent>
 	TComponent& downCast()
 	{
-		ANKI_ASSERT(TComponent::getGlobType() == getType());
-		TComponent* out = staticCast<TComponent*>(this);
+		ANKI_ASSERT(TComponent::getClassType() == getType());
+		TComponent* out = staticCastPtr<TComponent*>(this);
 		return *out;
 	}
 

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

@@ -98,7 +98,7 @@ public:
 	template<typename Component, typename Func>
 	void iterateComponentsOfType(Func func)
 	{
-		SceneComponent::Type type = Component::getGlobType();
+		SceneComponent::Type type = Component::getClassType();
 		for(auto comp : components)
 		{
 			if(comp->getType() == type)
@@ -112,7 +112,7 @@ public:
 	template<typename Component>
 	Component* tryGetComponent()
 	{
-		SceneComponent::Type type = Component::getGlobType();
+		SceneComponent::Type type = Component::getClassType();
 		for(auto comp : components)
 		{
 			if(comp->getType() == type)
@@ -127,7 +127,7 @@ public:
 	template<typename Component>
 	const Component* tryGetComponent() const
 	{
-		SceneComponent::Type type = Component::getGlobType();
+		SceneComponent::Type type = Component::getClassType();
 		for(auto comp : components)
 		{
 			if(comp->getType() == type)
@@ -156,6 +156,11 @@ public:
 		return *out;
 	}
 
+	static constexpr SceneObject::Type getClassType()
+	{
+		return SCENE_NODE_TYPE;
+	}
+
 protected:
 	/// Append a component to the components container
 	void addComponent(SceneComponent* comp);

+ 98 - 5
include/anki/scene/SceneObject.h

@@ -3,22 +3,54 @@
 
 #include "anki/scene/Common.h"
 #include "anki/util/Object.h"
+#include "anki/util/Functions.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>>
+class SceneObject: 
+	public Object<SceneObject, SceneAllocator<SceneObject>, 
+	SceneObjectCallbackCollection>
 {
 public:
-	typedef Object<SceneObject, SceneAllocator<SceneObject>> Base;
+	enum Type
+	{
+		SCENE_NODE_TYPE = 0,
+		EVENT_TYPE = 1 << 0
+	};
+
+	typedef Object<SceneObject, SceneAllocator<SceneObject>,
+		SceneObjectCallbackCollection> Base;
 
-	SceneObject(SceneObject* parent, SceneGraph* scene);
+	SceneObject(Type type, SceneObject* parent, SceneGraph* scene);
+
+	/// @name Accessors
+	/// @{
+	Type getType() const
+	{
+		return (Type)(flags & EVENT_TYPE);
+	}
 
 	SceneAllocator<U8> getSceneAllocator() const;
 
@@ -28,17 +60,78 @@ public:
 	{
 		return *scene;
 	}
+	/// @}
 
 	Bool isMarkedForDeletion() const
 	{
-		return markedForDeletion;
+		return (flags & MARKED_FOR_DELETION) != 0;
 	}
 	void markForDeletion();
 
+	/// Visit this and the children of a specific SceneObject type
+	template<typename ScObj, typename Func>
+	void visitThisAndChildren(Func func)
+	{
+		Base::visitThisAndChildren([&](SceneObject& so)
+		{
+			const Type type = ScObj::getClassType();
+
+			if(so.getType() == type)
+			{
+				func(so.downCast<ScObj>());
+			}
+		});
+	}
+
+	/// Visit this and the children of a specific SceneObject type
+	template<typename ScObj, typename Func>
+	void visitThisAndChildren(Func func) const
+	{
+		Base::visitThisAndChildren([&](const SceneObject& so)
+		{
+			const Type type = ScObj::getClassType();
+
+			if(so.getType() == type)
+			{
+				func(so.downCast<ScObj>());
+			}
+		});
+	}
+
+	/// Downcast the class
+	template<typename ScObj>
+	ScObj& downCast()
+	{
+		ANKI_ASSERT(ScObj::getClassType() == getType());
+		ScObj* out = staticCastPtr<ScObj*>(this);
+		return *out;
+	}
+
+	/// Downcast the class
+	template<typename ScObj>
+	const ScObj& downCast() const
+	{
+		ANKI_ASSERT(ScObj::getClassType() == getType());
+		ScObj* out = staticCastPtr<ScObj*>(this);
+		return *out;
+	}
+
 public:
+	enum
+	{
+		MARKED_FOR_DELETION = 1 << 1
+	};
+
 	SceneGraph* scene;
-	Bool8 markedForDeletion;
+	U8 flags; ///< Contains the type and the marked for deletion
 };
+
+inline void SceneObjectCallbackCollection::onChildRemoved(
+	SceneObject* child, SceneObject* parent)
+{
+	child->markForDeletion();
+}
+
 /// @}
 
 } // end namespace anki

+ 1 - 1
include/anki/scene/SpatialComponent.h

@@ -86,7 +86,7 @@ public:
 	void reset() override;
 	/// @}
 
-	static Type getGlobType()
+	static constexpr Type getClassType()
 	{
 		return SPATIAL_COMPONENT;
 	}

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

@@ -24,7 +24,7 @@ namespace anki {
 
 namespace detail {
 
-/// Internal methods for the #Allocator class
+/// Internal methods for the Allocator class
 class AllocatorInternal
 {
 public:

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

@@ -102,7 +102,7 @@ struct Array
 };
 
 /// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to 
-/// @code X a[10][2];
+/// @code X a[10][2]; @endcode
 template<typename T, PtrSize I, PtrSize J>
 using Array2d = Array<Array<T, J>, I>;
 /// @}

+ 0 - 179
include/anki/util/DynamicArray.h

@@ -1,179 +0,0 @@
-#ifndef ANKI_UTIL_DYNAMIC_ARRAY_H
-#define ANKI_UTIL_DYNAMIC_ARRAY_H
-
-#include "anki/util/Allocator.h"
-
-namespace anki {
-
-/// @addtogroup util
-/// @{
-/// @addtogroup containers
-/// @{
-
-template<typename T, typename Alloc = Allocator<T>>
-class DynamicArray
-{
-public:
-	typedef T Value;
-	typedef Value* Iterator;
-	typedef const Value* ConstIterator;
-	typedef Value& Reference;
-	typedef const Value& ConstReference;
-
-	/// @name Constructors/destructor
-	/// @{
-
-	/// Default
-	DynamicArray()
-	{}
-
-	/// Copy is deleted
-	DynamicArray(const DynamicArray&) = delete;
-
-	/// Move
-	DynamicArray(DynamicArray&& other)
-		: b(other.e), e(other.e), allocator(other.allocator)
-	{
-		other.b = nullptr;
-	}
-
-	/// Allocate the array
-	DynamicArray(const PtrSize n, const Alloc& alloc = Alloc())
-		: allocator(alloc)
-	{
-		resize(n);
-	}
-
-	///
-	DynamicArray(const Alloc& alloc)
-		: allocator(alloc)
-	{}
-
-	/// Deallocate
-	~DynamicArray()
-	{
-		clear();
-	}
-	/// @}
-
-	Reference operator[](const PtrSize n)
-	{
-		ANKI_ASSERT(b != nullptr);
-		ANKI_ASSERT(n < getSize());
-		return *(begin + n);
-	}
-
-	ConstReference operator[](const PtrSize n) const
-	{
-		ANKI_ASSERT(b != nullptr);
-		ANKI_ASSERT(n < getSize());
-		return *(begin + n);
-	}
-
-	/// Copy is not permited
-	DynamicArray& operator=(const DynamicArray&) = delete;
-
-	/// Move
-	DynamicArray& operator=(DynamicArray&& other)
-	{
-		clear();
-
-		b = other.b;
-		e = other.e;
-		allocator = b.allocator;
-
-		other.b = nullptr;
-		other.e = nullptr;
-
-		return *this;
-	}
-
-	/// Make it compatible with the C++11 range based for loop
-	Iterator begin()
-	{
-		ANKI_ASSERT(b != nullptr);
-		return b;
-	}
-
-	/// Make it compatible with the C++11 range based for loop
-	ConstIterator begin() const
-	{
-		ANKI_ASSERT(b != nullptr);
-		return b;
-	}
-
-	/// Make it compatible with the C++11 range based for loop
-	Iterator end()
-	{
-		ANKI_ASSERT(b != nullptr);
-		return e;
-	}
-
-	/// Make it compatible with the C++11 range based for loop
-	ConstIterator end() const
-	{
-		ANKI_ASSERT(b != nullptr);
-		return e;
-	}
-
-	/// Get the elements count
-	PtrSize getSize() const
-	{
-		return e - b;
-	}
-
-	/// Resize the array and call the constructors
-	template<typename... Args>
-	void resize(const PtrSize n, Args&&... args)
-	{
-		ANKI_ASSERT(b == nullptr && e == nullptr);
-		ANKI_ASSERT(n > 0);
-
-		// Allocate memory
-		b = allocator.allocate(n);
-		e = b + n;
-
-		// Call the constructors
-		for(PtrSize i = 0; i < n; i++)
-		{
-			allocator.construct(b + i, std::forward<Args>(args)...);
-		}
-	}
-
-	/// Clear the array
-	void clear()
-	{
-		if(b)
-		{
-			ANKI_ASSERT(e != nullptr);
-
-			PtrSize n = getSize();
-			ANKI_ASSERT(n > 0);
-
-			// Call the destructors
-			for(PtrSize i = 0; i < n; i++)
-			{
-				allocator.destroy(b + i);
-			}
-
-			// Deallocate the memory
-			allocator.deallocate(b, n);
-
-			// Reset the data
-			b = nullptr;
-			e = nullptr;
-		}
-	}
-
-private:
-	Value* b = nullptr;
-	Value* e = nullptr;
-	Alloc allocator;
-};
-
-/// @}
-/// @}
-
-} // end namespace anki
-
-#endif

+ 11 - 3
include/anki/util/Exception.h

@@ -8,6 +8,11 @@
 
 namespace anki {
 
+/// @addtogroup util
+/// @{
+/// @addtogroup misc
+/// @{
+
 /// Mother of all AnKi exceptions.
 ///
 /// Custom exception that takes file, line and function that throw it. Throw 
@@ -17,7 +22,7 @@ class Exception: public std::exception
 public:
 	/// Constructor
 	explicit Exception(const char* file, I line, const char* func, 
-		const char* errorFmt, ...);
+		const char* errorFmt, ...) throw();
 
 	/// Copy constructor
 	Exception(const Exception& e);
@@ -49,10 +54,13 @@ private:
 		I line, const char* func);
 };
 
-} // end namespace anki
-
 /// Macro for easy throwing
 #define ANKI_EXCEPTION(...) \
 	Exception(ANKI_FILE, __LINE__, ANKI_FUNC, __VA_ARGS__)
 
+/// @}
+/// @}
+
+} // end namespace anki
+
 #endif

+ 4 - 2
include/anki/util/Functions.h

@@ -134,10 +134,12 @@ struct RemovePointer<T*>
 
 /// Perform a static cast
 template<typename To, typename From>
-To staticCast(From from)
+To staticCastPtr(From from)
 {
 #if ANKI_DEBUG == 1
-	return dynamic_cast<To>(from);
+	To ptr = dynamic_cast<To>(from);
+	ANKI_ASSERT(ptr != nullptr);
+	return ptr;
 #else
 	return static_cast<To>(from);
 #endif

+ 0 - 24
include/anki/util/Vector.h

@@ -2,9 +2,7 @@
 #define ANKI_UTIL_VECTOR_H
 
 #include "anki/util/Assert.h"
-#include "anki/util/Functions.h"
 #include "anki/util/Allocator.h"
-#include "anki/util/Memory.h"
 #include <vector>
 
 namespace anki {
@@ -17,28 +15,6 @@ namespace anki {
 template<typename T, typename Alloc = Allocator<T>>
 using Vector = std::vector<T, Alloc>;
 
-/// Vector of pointers. The same as the regular vector but it deallocates the
-/// pointers
-template<typename T, typename Alloc = Allocator<T>>
-class PtrVector: public Vector<T*, Alloc>
-{
-public:
-	typedef Vector<T*, Alloc> Base;
-
-	~PtrVector()
-	{
-		for(typename Base::iterator it = Base::begin(); it != Base::end(); it++)
-		{
-			propperDelete(*it);
-		}
-	}
-
-	typename Base::iterator erase(typename Base::iterator pos)
-	{
-		return Base::erase(pos);
-	}
-};
-
 /// @}
 /// @}
 

+ 27 - 3
shaders/BsCommonFrag.glsl

@@ -23,6 +23,9 @@ float getAlpha()
 	return vAlpha;
 }
 
+#define getPointCoord_DEFINED
+#define getPointCoord() gl_PointCoord
+
 #if defined(PASS_COLOR)
 #	define writeFais_DEFINED
 void writeFais(in vec4 color)
@@ -42,8 +45,9 @@ void particleAlpha(in sampler2D tex, in float alpha)
 #endif
 
 #if defined(PASS_COLOR)
-#	define particleSoft_DEFINED
-void particleSoft(in sampler2D depthMap, in sampler2D tex, in float alpha)
+#	define particleSoftTextureAlpha_DEFINED
+void particleSoftTextureAlpha(in sampler2D depthMap, in sampler2D tex, 
+	in float alpha)
 {
 	const vec2 screenSize = 
 		vec2(1.0 / float(RENDERING_WIDTH), 1.0 / float(RENDERING_HEIGHT));
@@ -55,7 +59,27 @@ void particleSoft(in sampler2D depthMap, in sampler2D tex, in float alpha)
 	vec4 color = texture(tex, gl_PointCoord);
 	color.a *= alpha * softalpha;
 	writeFais(color);
-	//writeFais(color * 0.0001 + vec4(1.0, 0.0, 1.0, 1.0));
 }
 #endif
 
+#if defined(PASS_COLOR)
+#	define particleSoftColorAlpha_DEFINED
+void particleSoftColorAlpha(in sampler2D depthMap, in vec3 icolor, 
+	in float alpha)
+{
+	const vec2 screenSize = 
+		vec2(1.0 / float(RENDERING_WIDTH), 1.0 / float(RENDERING_HEIGHT));
+	float depth = texture(depthMap, gl_FragCoord.xy * screenSize).r;
+
+	float delta = depth - gl_FragCoord.z;
+	float softalpha = clamp(delta * 100.0, 0.0, 1.0);
+
+	vec2 pix = (1.0 - abs(gl_PointCoord * 2.0 - 1.0));
+	float roundFactor = pix.x * pix.y;
+
+	vec4 color;
+	color.rgb = icolor;
+	color.a = alpha * softalpha * roundFactor;
+	writeFais(color);
+}
+#endif

+ 18 - 14
shaders/GaussianBlurGeneric.glsl

@@ -61,21 +61,25 @@ const float weights[4] = float[](
 	0.3162162162, 0.0702702703);
 
 // Calc the kernel
-#if defined(VPASS)
-#	define BLURRING_OFFSET_X(val, sign_) ((float(val) + float(BLURRING_DIST)) * float(sign_) / float(IMG_DIMENSION))
-#	define BLURRING_OFFSET_Y(val, sign_) 0.0
-#else
-#	define BLURRING_OFFSET_X(val, sign_) 0.0
-#	define BLURRING_OFFSET_Y(val, sign_) ((float(val) + float(BLURRING_DIST)) * float(sign_) / float(IMG_DIMENSION))
-#endif
+#define BLURRING_OFFSET_DIM(val, sign_) ((val + float(BLURRING_DIST)) * float(sign_) / float(IMG_DIMENSION))
+
+#define BLURRING_OFFSET(valx, valy, sign_) vec2(BLURRING_OFFSET_DIM(valx, sign_), BLURRING_OFFSET_DIM(valy, sign_))
 
-#define BLURRING_OFFSET(val, sign_) vec2(BLURRING_OFFSET_X(val, sign_), BLURRING_OFFSET_Y(val, sign_))
+#define KERNEL_SIZE 4
 
-const vec2 kernel[4] = vec2[](
-	BLURRING_OFFSET(1.3846153846, 1),
-	BLURRING_OFFSET(3.2307692308, 1),
-	BLURRING_OFFSET(1.3846153846, -1),
-	BLURRING_OFFSET(3.2307692308, -1));
+const vec2 kernel[KERNEL_SIZE] = vec2[](
+#if defined(VPASS)
+	BLURRING_OFFSET(1.3846153846, 0.0, 1),
+	BLURRING_OFFSET(3.2307692308, 0.0, 1),
+	BLURRING_OFFSET(1.3846153846, 0.0, -1),
+	BLURRING_OFFSET(3.2307692308, 0.0, -1)
+#elif defined(HPASS)
+	BLURRING_OFFSET(0.0, 1.3846153846, 1),
+	BLURRING_OFFSET(0.0, 3.2307692308, 1),
+	BLURRING_OFFSET(0.0, 1.3846153846, -1),
+	BLURRING_OFFSET(0.0, 3.2307692308, -1)
+#endif
+);
 
 // Output
 layout(location = 0) out COL_TYPE fFragColor;
@@ -86,7 +90,7 @@ void main()
 	fFragColor = texture(img, vTexCoords).TEX_FETCH * first_weight;
 
 	// side pixels
-	for(int i = 0; i < 4; i++)
+	for(int i = 0; i < KERNEL_SIZE; i++)
 	{
 		fFragColor += 
 			texture(img, vTexCoords + kernel[i]).TEX_FETCH * weights[i];

+ 9 - 0
shaders/MsCommonFrag.glsl

@@ -183,6 +183,15 @@ vec3 readRgbFromTexture(in sampler2D tex, in highp vec2 texCoords)
 }
 #endif
 
+// Just read the RGB color from cube texture
+#if PASS_COLOR
+#	define readRgbFromCubeTexture_DEFINED
+vec3 readRgbFromCubeTexture(in samplerCube tex, in mediump vec3 texCoord)
+{
+	return texture(tex, texCoord).rgb;
+}
+#endif
+
 // Write the data to FAIs
 #if PASS_COLOR
 #	define writeFais_DEFINED

+ 29 - 34
shaders/VariableSamplingBlurGeneric.glsl

@@ -77,52 +77,47 @@ in vec2 vTexCoords;
 
 #define BLURRING_OFFSET(v, s) vec2(BLURRING_OFFSET_X(v, s), BLURRING_OFFSET_Y(v, s))
 
-#if SAMPLES == 3
-const vec2 kernel[SAMPLES] = vec2[](
+const vec2 kernel[SAMPLES - 1] = vec2[](
 	BLURRING_OFFSET(1, -1),
-	BLURRING_OFFSET(0, 1),
-	BLURRING_OFFSET(1, 1));
-#elif SAMPLES == 5
-const vec2 kernel[SAMPLES] = vec2[](
-	BLURRING_OFFSET(2, -1),
-	BLURRING_OFFSET(1, -1),
-	BLURRING_OFFSET(0, 0),
-	BLURRING_OFFSET(1, 1),
-	BLURRING_OFFSET(2, 1));
-#elif SAMPLES == 7
-const vec2 kernel[SAMPLES] = vec2[](
-	BLURRING_OFFSET(3, -1),
-	BLURRING_OFFSET(2, -1),
-	BLURRING_OFFSET(1, -1),
-	BLURRING_OFFSET(0, 1),
-	BLURRING_OFFSET(1, 1),
-	BLURRING_OFFSET(2, 1),
-	BLURRING_OFFSET(3, 1));
-#elif SAMPLES == 9
-const vec2 kernel[SAMPLES] = vec2[](
-	BLURRING_OFFSET(4, -1),
-	BLURRING_OFFSET(3, -1),
-	BLURRING_OFFSET(2, -1),
-	BLURRING_OFFSET(1, -1),
-	BLURRING_OFFSET(0, 1),
-	BLURRING_OFFSET(1, 1),
-	BLURRING_OFFSET(2, 1),
-	BLURRING_OFFSET(3, 1),
-	BLURRING_OFFSET(4, 1));
+	BLURRING_OFFSET(1, 1)
+#if SAMPLES > 3
+	,BLURRING_OFFSET(2, -1),
+	BLURRING_OFFSET(2, 1)
+#endif
+#if SAMPLES > 5
+	,BLURRING_OFFSET(3, -1),
+	BLURRING_OFFSET(3, 1)
+#endif
+#if SAMPLES > 7
+	,BLURRING_OFFSET(4, -1),
+	BLURRING_OFFSET(4, 1)
+#endif
+#if SAMPLES > 9
+	,BLURRING_OFFSET(5, -1),
+	BLURRING_OFFSET(5, 1)
+#endif
+#if SAMPLES > 11
+	,BLURRING_OFFSET(6, -1),
+	BLURRING_OFFSET(6, 1)
+#endif
+#if SAMPLES > 13
+	,BLURRING_OFFSET(7, -1),
+	BLURRING_OFFSET(7, 1)
 #endif
+	);
 
 layout(location = 0) out COL_TYPE fFragColor;
 
 void main()
 {
 	// Get the first
-	COL_TYPE col = textureFai(img, vTexCoords + kernel[0]).TEX_FETCH;
+	COL_TYPE col = textureFai(img, vTexCoords).TEX_FETCH;
 
 	// Get the rest of the samples
-	for(int i = 1; i < SAMPLES; i++)
+	for(int i = 0; i < SAMPLES - 1; i++)
 	{
 		col += textureFai(img, vTexCoords + kernel[i]).TEX_FETCH;
 	}
 
-	fFragColor = col * (1.0 / float(SAMPLES));
+	fFragColor = col / float(SAMPLES);
 }

+ 2 - 0
src/event/AnimationEvent.cpp

@@ -15,6 +15,8 @@ AnimationEvent::AnimationEvent(EventManager* manager,
 
 	startTime = anim->getStartingTime();
 	duration = anim->getDuration();
+
+	enableBits(EF_REANIMATE, anim->getRepeat());
 }
 
 //==============================================================================

+ 1 - 1
src/event/EventManager.cpp

@@ -78,7 +78,7 @@ void EventManager::updateAllEvents(F32 prevUpdateTime_, F32 crntTime_)
 		// Audjust starting time
 		if(pevent->startTime < 0.0)
 		{
-			pevent->startTime = crntTime_;
+			pevent->startTime = crntTime;
 		}
 
 		// If not dead update it

+ 1 - 1
src/gl/BufferObject.cpp

@@ -40,7 +40,7 @@ void BufferObject::destroy()
 	{
 		unbind();
 		glDeleteBuffers(objectsCount, &glIds[0]);
-		memset(&glIds[0], 0, sizeof(Base::glIds));
+		memset(&glIds[0], 0, sizeof(glIds));
 		objectsCount = 1;
 	}
 }

+ 3 - 3
src/gl/ShaderProgram.cpp

@@ -159,6 +159,7 @@ void ShaderProgramUniformVariable::set(const Texture& tex) const
 		|| getGlDataType() == GL_UNSIGNED_INT_SAMPLER_2D
 		|| getGlDataType() == GL_SAMPLER_2D_ARRAY_SHADOW
 		|| getGlDataType() == GL_SAMPLER_2D_ARRAY
+		|| getGlDataType() == GL_SAMPLER_CUBE
 #if ANKI_GL == ANKI_GL_DESKTOP
 		|| getGlDataType() == GL_SAMPLER_2D_MULTISAMPLE
 #endif
@@ -641,9 +642,8 @@ void ShaderProgram::link() const
 
 		infoLogTxt.resize(infoLen + 1);
 		glGetProgramInfoLog(glId, infoLen, &charsWritten, &infoLogTxt[0]);
-		std::string linkLog = std::string("Link error log follows:\n")
-			+ infoLogTxt; 
-		throw ANKI_EXCEPTION(linkLog.c_str());
+		throw ANKI_EXCEPTION("Link error log follows:\n%s", 
+			infoLogTxt.c_str());
 	}
 }
 

+ 6 - 3
src/gl/Texture.cpp

@@ -283,7 +283,7 @@ void Texture::create(const Initializer& init)
 						0, 
 						format, 
 						type, 
-						init.data[level][0].ptr);
+						init.data[level][face].ptr);
 				}
 				else
 				{
@@ -294,8 +294,8 @@ void Texture::create(const Initializer& init)
 						w, 
 						h, 
 						0, 
-						init.data[level][0].size, 
-						init.data[level][0].ptr);
+						init.data[level][face].size, 
+						init.data[level][face].ptr);
 				}
 			}
 			break;
@@ -463,6 +463,9 @@ U Texture::bind() const
 	case GL_TEXTURE_2D_ARRAY:
 		bindingPoint = GL_TEXTURE_BINDING_2D_ARRAY;
 		break;
+	case GL_TEXTURE_CUBE_MAP:
+		bindingPoint = GL_TEXTURE_BINDING_CUBE_MAP;
+		break;
 #if ANKI_GL == ANKI_GL_DESKTOP
 	case GL_TEXTURE_2D_MULTISAMPLE:
 		bindingPoint = GL_TEXTURE_BINDING_2D_MULTISAMPLE;

+ 14 - 13
src/renderer/Hdr.cpp

@@ -1,5 +1,6 @@
 #include "anki/renderer/Hdr.h"
 #include "anki/renderer/Renderer.h"
+#include <sstream>
 
 namespace anki {
 
@@ -53,25 +54,25 @@ void Hdr::initInternal(const RendererInitializer& initializer)
 	toneSProg.load("shaders/PpsHdr.glsl");
 	toneSProg->findUniformBlock("commonBlock").setBinding(0);
 
-	const char* SHADER_FILENAME = "shaders/GaussianBlurGeneric.glsl";
+	const char* SHADER_FILENAME = "shaders/VariableSamplingBlurGeneric.glsl";
 
-	std::string pps =
-		"#define HPASS\n"
+	std::stringstream pps;
+	pps << "#define HPASS\n"
 		"#define COL_RGB\n"
-		"#define BLURRING_DIST " + std::to_string(blurringDist) + "\n"
-		"#define IMG_DIMENSION " + std::to_string(height) + "\n"
-		"#define SAMPLES 7\n";
+		"#define BLURRING_DIST float(" << blurringDist << ")\n"
+		"#define IMG_DIMENSION " << height << "\n"
+		"#define SAMPLES " << (U)initializer.get("pps.hdr.samples") << "\n";
 	hblurSProg.load(ShaderProgramResource::createSrcCodeToCache(
-		SHADER_FILENAME, pps.c_str(), "r_").c_str());
+		SHADER_FILENAME, pps.str().c_str(), "r_").c_str());
 
-	pps =
-		"#define VPASS\n"
+	pps.str("");
+	pps << "#define VPASS\n"
 		"#define COL_RGB\n"
-		"#define BLURRING_DIST " + std::to_string(blurringDist) + "\n"
-		"#define IMG_DIMENSION " + std::to_string(width) + "\n"
-		"#define SAMPLES 7\n";
+		"#define BLURRING_DIST float(" << blurringDist << ")\n"
+		"#define IMG_DIMENSION " << width << "\n"
+		"#define SAMPLES " << (U)initializer.get("pps.hdr.samples") << "\n";
 	vblurSProg.load(ShaderProgramResource::createSrcCodeToCache(
-		SHADER_FILENAME, pps.c_str(), "r_").c_str());
+		SHADER_FILENAME, pps.str().c_str(), "r_").c_str());
 
 	// Set timestamps
 	parameterUpdateTimestamp = getGlobTimestamp();

+ 4 - 4
src/renderer/Is.cpp

@@ -128,7 +128,7 @@ struct WriteLightsJob: ThreadpoolTask
 		for(U64 i = start; i < end; i++)
 		{
 			SceneNode* snode = (*(lightsBegin + i)).node;
-			Light* light = staticCast<Light*>(snode);
+			Light* light = staticCastPtr<Light*>(snode);
 			ANKI_ASSERT(light);
 
 			switch(light->getLightType())
@@ -136,7 +136,7 @@ struct WriteLightsJob: ThreadpoolTask
 			case Light::LT_POINT:
 				{
 					PointLight& l = 
-						*staticCast<PointLight*>(light);
+						*staticCastPtr<PointLight*>(light);
 					I pos = doLight(l);
 					if(binLights && pos != -1)
 					{
@@ -146,7 +146,7 @@ struct WriteLightsJob: ThreadpoolTask
 				break;
 			case Light::LT_SPOT:
 				{
-					SpotLight& l = *staticCast<SpotLight*>(light);
+					SpotLight& l = *staticCastPtr<SpotLight*>(light);
 					I pos = doLight(l);
 					if(binLights && pos != -1)
 					{
@@ -591,7 +591,7 @@ void Is::lightPass()
 
 	for(auto it : vi.lights)
 	{
-		Light* light = staticCast<Light*>(it.node);
+		Light* light = staticCastPtr<Light*>(it.node);
 		switch(light->getLightType())
 		{
 		case Light::LT_POINT:

+ 1 - 1
src/renderer/Lf.cpp

@@ -156,7 +156,7 @@ void Lf::run()
 	{
 		SceneNode& sn = *it.node;
 		ANKI_ASSERT(sn.tryGetComponent<LightComponent>() != nullptr);
-		Light* light = staticCast<Light*>(&sn);
+		Light* light = staticCastPtr<Light*>(&sn);
 
 		if(light->hasLensFlare())
 		{

+ 3 - 2
src/renderer/Renderer.cpp

@@ -35,9 +35,10 @@ RendererInitializer::RendererInitializer()
 
 	// Pps
 	newOption("pps.hdr.enabled", true);
-	newOption("pps.hdr.renderingQuality", 0.25);
+	newOption("pps.hdr.renderingQuality", 0.5);
 	newOption("pps.hdr.blurringDist", 1.0);
-	newOption("pps.hdr.blurringIterationsCount", 2);
+	newOption("pps.hdr.samples", 5);
+	newOption("pps.hdr.blurringIterationsCount", 1);
 	newOption("pps.hdr.exposure", 4.0);
 
 	newOption("pps.ssao.enabled", true);

+ 29 - 3
src/resource/Animation.cpp

@@ -22,19 +22,31 @@ void Animation::load(const char* filename)
 //==============================================================================
 void Animation::loadInternal(const XmlElement& el)
 {
+	startTime = MAX_F32;
+	F32 maxTime = MIN_F32;
+
 	// Count the number of identity keys. If all of the keys are identities
 	// drop a vector
 	U identPosCount = 0;
 	U identRotCount = 0;
 	U identScaleCount = 0;
 
-	// <duration>
-	duration = el.getChildElement("duration").getFloat();
+	// <repeat>
+	XmlElement repel = el.getChildElementOptional("repeat");
+	if(repel)
+	{
+		repeat = repel.getInt();
+	}
+	else
+	{
+		repeat = false;
+	}
 
 	// <channels>
 	XmlElement channelsEl = el.getChildElement("channels");
 	XmlElement chEl = channelsEl.getChildElement("channel");
 
+	// For all channels
 	do
 	{
 		channels.push_back(AnimationChannel());	
@@ -56,6 +68,8 @@ void Animation::loadInternal(const XmlElement& el)
 
 				// <time>
 				key.time = keyEl.getChildElement("time").getFloat();
+				startTime = std::min(startTime, key.time);
+				maxTime = std::max(maxTime, key.time);
 
 				// <value>
 				key.value = keyEl.getChildElement("value").getVec3();
@@ -85,6 +99,8 @@ void Animation::loadInternal(const XmlElement& el)
 
 				// <time>
 				key.time = keyEl.getChildElement("time").getFloat();
+				startTime = std::min(startTime, key.time);
+				maxTime = std::max(maxTime, key.time);
 
 				// <value>
 				key.value = Quat(keyEl.getChildElement("value").getVec4());
@@ -114,6 +130,8 @@ void Animation::loadInternal(const XmlElement& el)
 
 				// <time>
 				key.time = keyEl.getChildElement("time").getFloat();
+				startTime = std::min(startTime, key.time);
+				maxTime = std::max(maxTime, key.time);
 
 				// <value>
 				key.value = keyEl.getChildElement("value").getFloat();
@@ -149,15 +167,23 @@ void Animation::loadInternal(const XmlElement& el)
 		// Move to next channel
 		chEl = chEl.getNextSiblingElement("channel");
 	} while(chEl);
+
+	duration = maxTime - startTime;
 }
 
 //==============================================================================
 void Animation::interpolate(U channelIndex, F32 time, 
 	Vec3& pos, Quat& rot, F32& scale) const
 {
+	// Audjust time
+	if(repeat && time > startTime + duration)
+	{
+		time = mod(time - startTime, duration) + startTime;
+	}
+
 	ANKI_ASSERT(time >= startTime && time <= startTime + duration);
 	ANKI_ASSERT(channelIndex < channels.size());
-	
+
 	const AnimationChannel& channel = channels[channelIndex];
 
 	// Position

+ 10 - 3
src/resource/Material.cpp

@@ -179,7 +179,12 @@ Material::Material()
 
 //==============================================================================
 Material::~Material()
-{}
+{
+	for(auto it : vars)
+	{
+		propperDelete(it);
+	}
+}
 
 //==============================================================================
 void Material::load(const char* filename)
@@ -377,7 +382,7 @@ void Material::populateVariables(const MaterialShaderProgramCreator& mspc)
 
 	// Now combine
 	//
-	const PtrVector<MaterialShaderProgramCreator::Input>& invars =
+	const Vector<MaterialShaderProgramCreator::Input*>& invars =
 		mspc.getInputVariables();
 	for(std::map<std::string, GLenum>::value_type& it : allVarNames)
 	{
@@ -406,8 +411,9 @@ void Material::populateVariables(const MaterialShaderProgramCreator& mspc)
 
 		switch(dataType)
 		{
-		// sampler2D
+		// samplers
 		case GL_SAMPLER_2D:
+		case GL_SAMPLER_CUBE:
 			v = new MaterialVariableTemplate<TextureResourcePointer>(
 				n, progs);
 			break;
@@ -451,6 +457,7 @@ void Material::populateVariables(const MaterialShaderProgramCreator& mspc)
 			{
 			// sampler2D
 			case GL_SAMPLER_2D:
+			case GL_SAMPLER_CUBE:
 				{
 					TextureResourcePointer tp(value[0].c_str());
 					v->setValues(&tp, 1);

+ 6 - 1
src/resource/MaterialShaderProgramCreator.cpp

@@ -50,7 +50,12 @@ MaterialShaderProgramCreator::MaterialShaderProgramCreator(
 
 //==============================================================================
 MaterialShaderProgramCreator::~MaterialShaderProgramCreator()
-{}
+{
+	for(auto it : inputs)
+	{
+		propperDelete(it);
+	}
+}
 
 //==============================================================================
 void MaterialShaderProgramCreator::parseShaderProgramTag(

+ 3 - 0
src/resource/ParticleEmitterResource.cpp

@@ -134,6 +134,9 @@ void ParticleEmitterResource::loadInternal(const XmlElement& rootel)
 
 	xmlReadFloat(rootel, "alpha", particle.alpha);
 	xmlReadFloat(rootel, "alphaDeviation", particle.alphaDeviation);
+	U32 tmp;
+	xmlReadU(rootel, "alphaAnimationEnabled", tmp);
+	particle.alphaAnimation = tmp;
 
 	xmlReadVec3(rootel, "forceDirection", particle.forceDirection);
 	xmlReadVec3(rootel, "forceDirectionDeviation", 

+ 11 - 2
src/scene/Light.cpp

@@ -2,6 +2,15 @@
 
 namespace anki {
 
+//==============================================================================
+// LightComponent                                                              =
+//==============================================================================
+
+//==============================================================================
+LightComponent::LightComponent(Light* node)
+	: SceneComponent(LIGHT_COMPONENT, node)
+{}
+
 //==============================================================================
 // Light                                                                       =
 //==============================================================================
@@ -77,7 +86,7 @@ PointLight::PointLight(const char* name, SceneGraph* scene)
 void PointLight::componentUpdated(SceneComponent& comp, 
 	SceneComponent::UpdateType)
 {
-	if(comp.getType() == MoveComponent::getGlobType())
+	if(comp.getType() == MoveComponent::getClassType())
 	{
 		MoveComponent& move = comp.downCast<MoveComponent>();
 		sphereW.setCenter(move.getWorldTransform().getOrigin());
@@ -107,7 +116,7 @@ SpotLight::SpotLight(const char* name, SceneGraph* scene)
 void SpotLight::componentUpdated(SceneComponent& comp,
 	SceneComponent::UpdateType)
 {
-	if(comp.getType() == MoveComponent::getGlobType())
+	if(comp.getType() == MoveComponent::getClassType())
 	{
 		MoveComponent& move = comp.downCast<MoveComponent>();
 		frustum.setTransform(move.getWorldTransform());

+ 13 - 17
src/scene/ModelNode.cpp

@@ -59,7 +59,7 @@ void ModelPatchNode::getRenderingData(
 //==============================================================================
 void ModelPatchNode::getRenderWorldTransform(U index, Transform& trf)
 {
-	SceneNode* parent = staticCast<SceneNode*>(getParent());
+	SceneNode* parent = &getParent()->downCast<SceneNode>();
 	ANKI_ASSERT(parent);
 	MoveComponent& move = parent->getComponent<MoveComponent>();
 
@@ -71,9 +71,9 @@ void ModelPatchNode::getRenderWorldTransform(U index, Transform& trf)
 	else
 	{
 		// Instancing
-		SceneNode* parent = staticCast<SceneNode*>(getParent());
+		SceneNode* parent = &getParent()->downCast<SceneNode>();
 		ANKI_ASSERT(parent);
-		ModelNode* mnode = staticCast<ModelNode*>(parent);
+		ModelNode* mnode = staticCastPtr<ModelNode*>(parent);
 
 		--index;
 		ANKI_ASSERT(index < mnode->transforms.size());
@@ -89,7 +89,7 @@ void ModelPatchNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
 		return;
 	}
 
-	SceneNode* parent = staticCast<SceneNode*>(getParent());
+	SceneNode* parent = &getParent()->downCast<SceneNode>();
 	ANKI_ASSERT(parent);
 
 	// Update first OBB
@@ -105,13 +105,11 @@ void ModelPatchNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
 	// Get the move components of the instances of the parent
 	SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
 	Timestamp instancesTimestamp = 0;
-	parent->visitThisAndChildren([&](SceneObject& so)
-	{
-		SceneNode* sn = staticCast<SceneNode*>(&so);
-		
-		if(sn->tryGetComponent<InstanceComponent>())
+	parent->visitThisAndChildren<SceneNode>([&](SceneNode& sn)
+	{		
+		if(sn.tryGetComponent<InstanceComponent>())
 		{
-			MoveComponent& move = sn->getComponent<MoveComponent>();
+			MoveComponent& move = sn.getComponent<MoveComponent>();
 
 			instanceMoves.push_back(&move);
 
@@ -138,7 +136,7 @@ void ModelPatchNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
 			if(count != 0)	
 			{
 				ObbSpatialComponent* msp = 
-					staticCast<ObbSpatialComponent*>(&sp);
+					staticCastPtr<ObbSpatialComponent*>(&sp);
 		
 				spatialsTimestamp = 
 					std::max(spatialsTimestamp, msp->getTimestamp());
@@ -252,13 +250,11 @@ void ModelNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
 	// Get the move components of the instances of the parent
 	SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
 	Timestamp instancesTimestamp = 0;
-	SceneNode::visitThisAndChildren([&](SceneObject& so)
-	{
-		SceneNode* sn = staticCast<SceneNode*>(&so);
-		
-		if(sn->tryGetComponent<InstanceComponent>())
+	SceneObject::visitThisAndChildren<SceneNode>([&](SceneNode& sn)
+	{		
+		if(sn.tryGetComponent<InstanceComponent>())
 		{
-			MoveComponent& move = sn->getComponent<MoveComponent>();
+			MoveComponent& move = sn.getComponent<MoveComponent>();
 
 			instanceMoves.push_back(&move);
 

+ 14 - 9
src/scene/ParticleEmitter.cpp

@@ -301,7 +301,7 @@ const Material& ParticleEmitter::getMaterial()
 void ParticleEmitter::componentUpdated(SceneComponent& comp, 
 	SceneComponent::UpdateType)
 {
-	if(comp.getType() == MoveComponent::getGlobType())
+	if(comp.getType() == MoveComponent::getClassType())
 	{
 		identityRotation =
 			getWorldTransform().getRotation() == Mat3::getIdentity();
@@ -417,7 +417,14 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime,
 			verts[3] = p->size + (lifePercent * particle.sizeAnimation);
 
 			// Set alpha
-			verts[4] = sin((lifePercent) * getPi<F32>()) * p->alpha;
+			if(particle.alphaAnimation)
+			{
+				verts[4] = sin((lifePercent) * getPi<F32>()) * p->alpha;
+			}
+			else
+			{
+				verts[4] = p->alpha;
+			}
 
 			++aliveParticlesCount;
 			verts += 5;
@@ -484,13 +491,11 @@ void ParticleEmitter::doInstancingCalcs()
 	// Gather the move components of the instances
 	SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
 	Timestamp instancesTimestamp = 0;
-	SceneNode::visitThisAndChildren([&](SceneObject& so)
-	{
-		SceneNode* sn = staticCast<SceneNode*>(&so);
-		
-		if(sn->tryGetComponent<InstanceComponent>())
+	SceneObject::visitThisAndChildren<SceneNode>([&](SceneNode& sn)
+	{	
+		if(sn.tryGetComponent<InstanceComponent>())
 		{
-			MoveComponent& move = sn->getComponent<MoveComponent>();
+			MoveComponent& move = sn.getComponent<MoveComponent>();
 
 			instanceMoves.push_back(&move);
 
@@ -555,7 +560,7 @@ void ParticleEmitter::doInstancingCalcs()
 			if(count != 0)	
 			{
 				ObbSpatialComponent* msp = 
-					staticCast<ObbSpatialComponent*>(&sp);
+					staticCastPtr<ObbSpatialComponent*>(&sp);
 		
 				Obb aobb = obb;
 				aobb.setCenter(Vec3(0.0));

+ 1 - 1
src/scene/SceneGraph.cpp

@@ -45,7 +45,7 @@ struct UpdateSceneNodesJob: ThreadpoolTask
 		barrier->wait();
 
 		// Update the rest of the components
-		auto moveComponentTypeId = MoveComponent::getGlobType();
+		auto moveComponentTypeId = MoveComponent::getClassType();
 		scene->iterateSceneNodes(start, end, [&](SceneNode& node)
 		{
 			// Components update

+ 1 - 1
src/scene/SceneNode.cpp

@@ -8,7 +8,7 @@ namespace anki {
 
 //==============================================================================
 SceneNode::SceneNode(const char* name_, SceneGraph* scene_)
-	:	SceneObject(nullptr, scene_),
+	:	SceneObject(SCENE_NODE_TYPE, nullptr, scene_),
 		name(getSceneAllocator()),
 		components(getSceneAllocator())
 {

+ 3 - 3
src/scene/SceneObject.cpp

@@ -4,10 +4,10 @@
 namespace anki {
 
 //==============================================================================
-SceneObject::SceneObject(SceneObject* parent, SceneGraph* scene_)
+SceneObject::SceneObject(Type type, SceneObject* parent, SceneGraph* scene_)
 	:	Base(parent, scene_->getAllocator()),
 		scene(scene_),
-		markedForDeletion(false)
+		flags((U8)type)
 {
 	ANKI_ASSERT(scene);
 }
@@ -29,7 +29,7 @@ SceneAllocator<U8> SceneObject::getSceneFrameAllocator() const
 //==============================================================================
 void SceneObject::markForDeletion()
 {
-	markedForDeletion = true;
+	flags |= MARKED_FOR_DELETION;
 
 	visitChildren([](SceneObject& obj)
 	{

+ 1 - 1
src/scene/Visibility.cpp

@@ -134,7 +134,7 @@ struct VisibilityTestTask: ThreadpoolTask
 					LightComponent* l = node.tryGetComponent<LightComponent>();
 					if(l)
 					{
-						Light* light = staticCast<Light*>(&node);
+						Light* light = staticCastPtr<Light*>(&node);
 
 						visible->lights.push_back(visibleNode);
 

+ 2 - 2
src/script/ScriptManager.cpp

@@ -11,9 +11,9 @@ void ScriptManager::init()
 	ANKI_LOGI("Initializing scripting engine...");
 
 	// Math
-	ANKI_SCRIPT_CALL_WRAP(Vec2);
+	/*ANKI_SCRIPT_CALL_WRAP(Vec2);
 	ANKI_SCRIPT_CALL_WRAP(Vec3);
-	ANKI_SCRIPT_CALL_WRAP(Vec4);
+	ANKI_SCRIPT_CALL_WRAP(Vec4);*/
 
 	// Renderer
 	ANKI_SCRIPT_CALL_WRAP(Dbg);

+ 2 - 0
src/script/math/Vec2.cpp

@@ -3,6 +3,7 @@
 
 namespace anki {
 
+#if 0
 static void vec2SetX(Vec2* self, F32 x)
 {
 	self->x() = x;
@@ -50,5 +51,6 @@ ANKI_SCRIPT_WRAP(Vec2)
 		ANKI_LUA_METHOD("dot", &Vec2::dot)
 	ANKI_LUA_CLASS_END()
 }
+#endif
 
 } // end namespace anki

+ 3 - 0
src/script/math/Vec3.cpp

@@ -3,6 +3,8 @@
 
 namespace anki {
 
+#if 0
+
 static void vec3SetX(Vec3* self, F32 x)
 {
 	self->x() = x;
@@ -57,5 +59,6 @@ ANKI_SCRIPT_WRAP(Vec3)
 		ANKI_LUA_METHOD("dot", &Vec3::dot)
 	ANKI_LUA_CLASS_END()
 }
+#endif
 
 } // end namespace anki

+ 3 - 0
src/script/math/Vec4.cpp

@@ -3,6 +3,8 @@
 
 namespace anki {
 
+#if 0
+
 static void vec4SetX(Vec4* self, F32 x)
 {
 	self->x() = x;
@@ -64,5 +66,6 @@ ANKI_SCRIPT_WRAP(Vec4)
 		ANKI_LUA_METHOD("dot", &Vec4::dot)
 	ANKI_LUA_CLASS_END()
 }
+#endif
 
 } // end namespace anki

+ 28 - 3
src/util/Exception.cpp

@@ -1,6 +1,9 @@
 #include "anki/util/Exception.h"
+#include "anki/util/Vector.h"
 #include <sstream>
 #include <iostream>
+#include <cstring>
+#include <cstdarg>
 
 // Instead of throwing abort. Its easier to debug
 #define ANKI_ABORT_ON_THROW 0
@@ -9,16 +12,38 @@ namespace anki {
 
 //==============================================================================
 Exception::Exception(const char* file, I line, const char* func, 
-	const char* fmt, ...)
+	const char* fmt, ...) throw()
 {
 	char buffer[1024];
+	const char* out = &buffer[0];
+	Vector<char> largeStr;
 	va_list args;
 
 	va_start(args, fmt);
-	vsnprintf(buffer, sizeof(buffer), fmt, args);
+	I len = vsnprintf(buffer, sizeof(buffer), fmt, args);
 	va_end(args);
 
-	err = synthErr(buffer, file, line, func);
+	if(len < 0)
+	{
+		// Error in vsnprintf()
+		strcpy(buffer, "Error when throwing exception. vsnprintf() failed");
+	}
+	else if((PtrSize)len >= sizeof(buffer))
+	{
+		// The buffer is not big enough
+
+		// Create a huge string
+		largeStr.resize(len + 1, '-');
+		out = &largeStr[0];
+
+		va_start(args, fmt);
+		len = vsnprintf(&largeStr[0], largeStr.size(), fmt, args);
+		va_end(args);
+
+		ANKI_ASSERT(len < largeStr.size());
+	}
+
+	err = synthErr(out, file, line, func);
 
 #if ANKI_ABORT_ON_THROW
 	std::cerr << err << std::endl;

+ 17 - 7
testapp/Main.cpp

@@ -164,7 +164,7 @@ void init()
 	scene.newSceneNode(spot, "spot0");
 	spot->setOuterAngle(toRad(45.0));
 	spot->setInnerAngle(toRad(15.0));
-	spot->setLocalTransform(Transform(Vec3(8.27936, 5.86285, 1.85526),
+	spot->setLocalTransform(Transform(Vec3(-1.434199, 5.474161, -10.774253),
 		Mat3(Quat(-0.125117, 0.620465, 0.154831, 0.758544)), 1.0));
 	spot->setDiffuseColor(Vec4(2.0));
 	spot->setSpecularColor(Vec4(-1.0));
@@ -251,6 +251,12 @@ void init()
 
 			scene.findSceneNode("pesmoke").addChild(instance);
 		}
+
+		{
+			scene.newSceneNode(pe, ("pesparks" + std::to_string(i)).c_str(), 
+				"particles/sparks.ankipart");
+			pe->setLocalOrigin(lightPos);
+		}
 	}
 #endif
 
@@ -526,13 +532,13 @@ void mainLoop()
 		increaseGlobTimestamp();
 	}
 
-#if 1
-	MainRendererSingleton::get().takeScreenshot("screenshot.tga");
-#endif
-
 	ANKI_COUNTER_STOP_TIMER_INC(C_FPS);
 
 	ANKI_COUNTERS_FLUSH();
+
+#if 0
+	MainRendererSingleton::get().takeScreenshot("screenshot.tga");
+#endif
 }
 
 //==============================================================================
@@ -548,6 +554,9 @@ void initSubsystems(int argc, char* argv[])
 	U32 glminor = 0;
 #endif
 
+	// Logger
+	LoggerSingleton::get().init(Logger::INIT_SYSTEM_MESSAGE_HANDLER);
+
 	// App
 	AppSingleton::get().init();
 
@@ -559,7 +568,7 @@ void initSubsystems(int argc, char* argv[])
 	nwinit.minorVersion = glminor;
 	nwinit.depthBits = 0;
 	nwinit.stencilBits = 0;
-	nwinit.fullscreenDesktopRez = false;
+	nwinit.fullscreenDesktopRez = true;
 	nwinit.debugContext = false;
 	win = new NativeWindow;	
 	win->create(nwinit);
@@ -589,6 +598,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.get("pps.hdr.blurringDist") = 1.0;
 	initializer.get("pps.hdr.blurringIterationsCount") = 1;
 	initializer.get("pps.hdr.exposure") = 8.0;
+	initializer.get("pps.hdr.samples") = 9;
 	initializer.get("pps.ssao.blurringIterationsNum") = 1;
 	initializer.get("pps.ssao.enabled") = true;
 	initializer.get("pps.ssao.renderingQuality") = 0.35;
@@ -602,7 +612,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.get("height") = win->getHeight();
 	initializer.get("lodDistance") = 20.0;
 	initializer.get("samples") = 1;
-	initializer.get("tessellation") = true;
+	initializer.get("tessellation") = false;
 	initializer.get("tilesXCount") = 16;
 	initializer.get("tilesYCount") = 16;