Bläddra i källkod

Adding instancing support on ModelNode & SceneNode refactoring & making SSAO prettier & making everything compile with gcc 4.8

Panagiotis Christopoulos Charitos 12 år sedan
förälder
incheckning
3e6e33290e
44 ändrade filer med 653 tillägg och 308 borttagningar
  1. 8 7
      CMakeLists.txt
  2. 1 1
      include/anki/Config.h.cmake
  3. 2 2
      include/anki/collision/Obb.h
  4. 2 0
      include/anki/event/Event.h
  5. 3 1
      include/anki/renderer/Drawer.h
  6. 3 2
      include/anki/resource/MaterialShaderProgramCreator.h
  7. 11 8
      include/anki/scene/Camera.h
  8. 9 8
      include/anki/scene/Light.h
  9. 50 21
      include/anki/scene/ModelNode.h
  10. 7 12
      include/anki/scene/Movable.h
  11. 14 22
      include/anki/scene/ParticleEmitter.h
  12. 4 3
      include/anki/scene/Path.h
  13. 5 5
      include/anki/scene/Renderable.h
  14. 24 6
      include/anki/scene/SceneNode.h
  15. 1 1
      include/anki/scene/Spatial.h
  16. 9 7
      include/anki/scene/StaticGeometryNode.h
  17. 2 2
      include/anki/scene/Visibility.h
  18. 0 1
      include/anki/script/Common.h
  19. 36 0
      include/anki/util/Array.h
  20. 9 9
      shaders/GaussianBlurGeneric.glsl
  21. 7 0
      shaders/Pps.glsl
  22. 11 7
      shaders/PpsSsao.glsl
  23. 4 2
      shaders/VariableSamplingBlurGeneric.glsl
  24. 6 7
      src/collision/Obb.cpp
  25. 1 1
      src/core/App.cpp
  26. 10 6
      src/core/Counters.cpp
  27. 5 0
      src/core/NativeWindowEglFbdev.cpp
  28. 28 11
      src/renderer/Drawer.cpp
  29. 6 7
      src/renderer/Hdr.cpp
  30. 1 1
      src/renderer/Ssao.cpp
  31. 40 8
      src/resource/MaterialShaderProgramCreator.cpp
  32. 15 14
      src/scene/Camera.cpp
  33. 15 12
      src/scene/Light.cpp
  34. 167 13
      src/scene/ModelNode.cpp
  35. 27 15
      src/scene/Movable.cpp
  36. 22 30
      src/scene/ParticleEmitter.cpp
  37. 6 5
      src/scene/Path.cpp
  38. 14 4
      src/scene/SceneGraph.cpp
  39. 24 3
      src/scene/SceneNode.cpp
  40. 4 0
      src/scene/SkinNode.cpp
  41. 9 9
      src/scene/StaticGeometryNode.cpp
  42. 0 1
      src/script/renderer/MainRenderer.cpp
  43. 3 2
      src/util/FilesystemPosix.cpp
  44. 28 32
      testapp/Main.cpp

+ 8 - 7
CMakeLists.txt

@@ -49,6 +49,10 @@ SET(ANKI_WINDOW_BACKEND "${_WIN_BACKEND}" CACHE STRING "The window backend (GLXX
 
 SET(ANKI_GCC_TO_STRING_WORKAROUND "0" CACHE STRING "Enable workaround for C++11 GCC bug (0 or 1)")
 
+# Extra directories
+SET(ANKI_EXTRA_INCLUDE_DIRS CACHE STRING "Some extra include paths (Needed for some weird builds)")
+SET(ANKI_EXTRA_LIB_DIRS CACHE STRING "Some extra lib paths (Needed for some weird builds)")
+
 #
 # Options that affect anki and extern
 #
@@ -160,6 +164,9 @@ ELSE()
 	MESSAGE("++ With gperftools profiler: false")
 ENDIF()
 
+INCLUDE_DIRECTORIES(${ANKI_EXTRA_INCLUDE_DIRS})
+LINK_DIRECTORIES(${ANKI_EXTRA_LIB_DIRS})
+
 #
 # Install
 #
@@ -223,17 +230,11 @@ ADD_DEFINITIONS("-Dthread_local=__thread")
 #
 # AnKi compiler flags (Mainly warnings)
 #
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors -pedantic -ansi -Wall -W -Wextra -Wwrite-strings -Wno-unused -Wundef -Wunused-variable -Werror -std=c++11")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors -pedantic -ansi -Wall -W -Wextra -Wwrite-strings -Wno-unused -Wno-unused-parameter -Wundef -Werror -std=c++11")
 
 #
 # Include & lib directories
 #
-SET(ANKI_EXTRA_INCLUDE_DIRS CACHE STRING "Some extra include paths (Needed for FBDEV)")
-SET(ANKI_EXTRA_LIB_DIRS CACHE STRING "Some extra lib paths (Needed for FBDEV)")
-
-INCLUDE_DIRECTORIES(${ANKI_EXTRA_INCLUDE_DIRS})
-LINK_DIRECTORIES(${ANKI_EXTRA_LIB_DIRS})
-
 INCLUDE_DIRECTORIES("extern/tinyxml2/include" "extern/lua" "extern/png" "extern/bullet" "include"
 	"${CMAKE_CURRENT_BINARY_DIR}")
 

+ 1 - 1
include/anki/Config.h.cmake

@@ -90,7 +90,7 @@
 
 // General config
 #define ANKI_MAX_MULTIDRAW_PRIMITIVES 64
-#define ANKI_MAX_INSTANCES 16
+#define ANKI_MAX_INSTANCES 64
 
 // Renderer config
 #define ANKI_RENDERER_MAX_POINT_LIGHTS (512 - 16)

+ 2 - 2
include/anki/collision/Obb.h

@@ -3,7 +3,7 @@
 
 #include "anki/collision/CollisionShape.h"
 #include "anki/Math.h"
-#include <array>
+#include "anki/util/Array.h"
 
 namespace anki {
 
@@ -119,7 +119,7 @@ public:
 	void set(const Container& container);
 
 	/// Get extreme points in 3D space
-	void getExtremePoints(std::array<Vec3, 8>& points) const;
+	void getExtremePoints(Array<Vec3, 8>& points) const;
 
 public:
 	/// @name Data

+ 2 - 0
include/anki/event/Event.h

@@ -65,6 +65,8 @@ public:
 	/// @return Return false if you don't want to be killed
 	virtual Bool onKilled(F32 prevUpdateTime, F32 crntTime)
 	{
+		(void)prevUpdateTime;
+		(void)crntTime;
 		return true;
 	}
 

+ 3 - 1
include/anki/renderer/Drawer.h

@@ -47,7 +47,9 @@ private:
 		const PassLevelKey& key,
 		const Frustumable& fr,
 		const ShaderProgram& prog,
-		Renderable& renderable);
+		Renderable& renderable,
+		U32* subSpatialIndices,
+		U subSpatialIndicesCount);
 };
 
 } // end namespace anki

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

@@ -11,8 +11,8 @@ class XmlElement;
 /// <shaderProgam></shaderProgram> located inside a <material></material>
 /// and creates the source of a custom program.
 ///
-/// @note Be carefull when you change the methods. Create as less unique 
-///       shaders as possible
+/// @note Be carefull when you change the methods. Some change may create more
+////      unique shaders and this is never good.
 class MaterialShaderProgramCreator
 {
 public:
@@ -26,6 +26,7 @@ public:
 		std::string line;
 		U32 shaders = 0; ///< Shader mask
 		Bool putInBlock = false;
+		Bool instanced = false;
 	};
 
 	explicit MaterialShaderProgramCreator(const XmlElement& pt, 

+ 11 - 8
include/anki/scene/Camera.h

@@ -27,10 +27,11 @@ public:
 
 	/// @name Constructors/Destructor
 	/// @{
-	Camera(CameraType type_,
-		const char* name, SceneGraph* scene, // SceneNode
-		U32 movableFlags, Movable* movParent, // Movable
-		Frustum* frustum); // Spatial & Frustumable
+	Camera(
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags, // Movable
+		Frustum* frustum, // Spatial & Frustumable
+		CameraType type_); // Self
 
 	virtual ~Camera();
 	/// @}
@@ -118,8 +119,9 @@ public:
 
 	/// @name Constructors
 	/// @{
-	PerspectiveCamera(const char* name, SceneGraph* scene,
-		uint movableFlags, Movable* movParent);
+	PerspectiveCamera(
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags); // Movable
 	/// @}
 
 	/// @name Accessors
@@ -201,8 +203,9 @@ public:
 
 	/// @name Constructors
 	/// @{
-	OrthographicCamera(const char* name, SceneGraph* scene,
-		uint movableFlags, Movable* movParent);
+	OrthographicCamera(
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags); // Movable
 	/// @}
 
 	/// @name Accessors

+ 9 - 8
include/anki/scene/Light.h

@@ -38,10 +38,11 @@ public:
 
 	/// @name Constructors
 	/// @{
-	Light(LightType t, // Light
-		const char* name, SceneGraph* scene, // Scene
-		U32 movableFlags, Movable* movParent, // Movable
-		CollisionShape* cs); // Spatial
+	Light(
+		const char* name, SceneGraph* scene, SceneNode* parent, // Scene
+		U32 movableFlags, // Movable
+		CollisionShape* cs, // Spatial
+		LightType t); // Self
 	/// @}
 
 	virtual ~Light();
@@ -123,8 +124,8 @@ class PointLight: public Light
 public:
 	/// @name Constructors/Destructor
 	/// @{
-	PointLight(const char* name, SceneGraph* scene,
-		U32 movableFlags, Movable* movParent);
+	PointLight(const char* name, SceneGraph* scene, SceneNode* parent,
+		U32 movableFlags);
 	/// @}
 
 	/// @name Accessors
@@ -170,8 +171,8 @@ public:
 
 	/// @name Constructors/Destructor
 	/// @{
-	SpotLight(const char* name, SceneGraph* scene,
-		U32 movableFlags, Movable* movParent);
+	SpotLight(const char* name, SceneGraph* scene, SceneNode* parent,
+		U32 movableFlags);
 	/// @}
 
 	/// @name Accessors

+ 50 - 21
include/anki/scene/ModelNode.h

@@ -14,21 +14,46 @@ namespace anki {
 /// @addtogroup Scene
 /// @{
 
-/// XXX
-class ModelPatchNodeInstance: public Spatial, public Movable
+/// A model instance
+class ModelPatchNodeInstance: public SceneNode, public Movable, public Spatial
 {
+	friend class ModelPatchNode;
+
+public:
+	ModelPatchNodeInstance(
+		const char* name, SceneGraph* scene, SceneNode* parent, // Scene
+		U32 movableFlags, // Movable
+		const ModelPatchBase* modelPatchResource); // Self
+
+	/// @name Movable virtuals
+	/// @{
+
+	/// Overrides Movable::moveUpdate(). This does:
+	/// - Update the collision shape
+	/// - If it's the last instance update the parent's CS.
+	void movableUpdate();
+	/// @}
+
+private:
+	Obb obb; ///< In world space
+	const ModelPatchBase* modelPatch; ///< Keep the resource for tha OBB
 };
 
 /// A fragment of the ModelNode
 class ModelPatchNode: public SceneNode, public Movable, public Renderable,
 	public Spatial
 {
+	friend class ModelPatchNodeInstance;
+
 public:
 	/// @name Constructors/Destructor
 	/// @{
-	ModelPatchNode(const ModelPatchBase* modelPatch_,
-		const char* name, SceneGraph* scene, // Scene
-		U32 movableFlags, Movable* movParent); // Movable
+	ModelPatchNode(
+		const char* name, SceneGraph* scene, SceneNode* parent, // Scene
+		U32 movableFlags, // Movable
+		const ModelPatchBase* modelPatch, U instances); // Self
+
+	~ModelPatchNode();
 	/// @}
 
 	/// @name SceneNode virtuals
@@ -41,45 +66,48 @@ public:
 	}
 	/// @}
 
-	// @name Movable virtuals
+	/// @name Movable virtuals
 	/// @{
 
 	/// Overrides Movable::moveUpdate(). This does:
 	/// - Update the collision shape
-	void movableUpdate()
-	{
-		Movable::movableUpdate();
-		obb = modelPatch->getBoundingShape().getTransformed(
-			getWorldTransform());
-		spatialMarkForUpdate();
-	}
+	void movableUpdate();
 	/// @}
 
 	/// @name Renderable virtuals
 	/// @{
 
 	/// Implements Renderable::getModelPatchBase
-	const ModelPatchBase& getRenderableModelPatchBase() const
+	const ModelPatchBase& getRenderableModelPatchBase()
 	{
 		return *modelPatch;
 	}
 
 	/// Implements  Renderable::getMaterial
-	const Material& getRenderableMaterial() const
+	const Material& getRenderableMaterial()
 	{
 		return modelPatch->getMaterial();
 	}
 
 	/// Overrides Renderable::getRenderableWorldTransforms
-	const Transform* getRenderableWorldTransforms() const
+	const Transform* getRenderableWorldTransforms();
+
+	/// Overrides Renderable::getRenderableInstancesCount
+	U32 getRenderableInstancesCount()
 	{
-		return &getWorldTransform();
+		// return this and the instances 
+		return (transforms.size() > 0) ? transforms.size() : 1;
 	}
 	/// @}
 
 private:
-	Obb obb; ///< In world space
+	Obb obb; ///< In world space.
 	const ModelPatchBase* modelPatch; ///< The resource
+	SceneVector<ModelPatchNodeInstance*> instances;
+	SceneVector<Transform> transforms;
+
+	/// This is called by the last of the instances on it's movableUpdate()
+	void updateSpatialCs();
 };
 
 /// The model scene node
@@ -90,9 +118,10 @@ public:
 
 	/// @name Constructors/Destructor
 	/// @{
-	ModelNode(const char* modelFname,
-		const char* name, SceneGraph* scene, // SceneNode
-		uint movableFlags, Movable* movParent); // Movable
+	ModelNode(
+		const char* name, SceneGraph* scene, SceneNode* node, // SceneNode
+		U32 movableFlags, // Movable
+		const char* modelFname, U instances = 1); // Self
 
 	virtual ~ModelNode();
 	/// @}

+ 7 - 12
include/anki/scene/Movable.h

@@ -1,27 +1,22 @@
 #ifndef ANKI_SCENE_MOVABLE_H
 #define ANKI_SCENE_MOVABLE_H
 
-#include "anki/util/Object.h"
 #include "anki/util/Bitset.h"
 #include "anki/Math.h"
 #include "anki/core/Timestamp.h"
 #include "anki/scene/Common.h"
-#include <algorithm> // For std::find
 
 namespace anki {
 
-class PropertyMap;
+class SceneNode;
 
 /// @addtogroup Scene
 /// @{
 
 /// Interface for movable scene nodes
-class Movable: public Object<Movable, SceneAllocator<Movable>>,
-	public Bitset<U8>
+class Movable: public Bitset<U8>
 {
 public:
-	typedef Object<Movable, SceneAllocator<Movable>> Base;
-
 	enum MovableFlag
 	{
 		MF_NONE = 0,
@@ -36,10 +31,8 @@ public:
 
 	/// The one and only constructor
 	/// @param flags The flags
-	/// @param parent The parent. It can be nullptr
-	/// @param pmap Property map to add a few variables
-	Movable(U32 flags, Movable* parent, PropertyMap& pmap,
-		const SceneAllocator<Movable>& alloc);
+	/// @param node Pass the scene node
+	Movable(U32 flags, SceneNode* node);
 
 	~Movable();
 	/// @}
@@ -55,7 +48,7 @@ public:
 		lTrf = x;
 		movableMarkForUpdate();
 	}
-	void setLocalTranslation(const Vec3& x)
+	void setLocalOrigin(const Vec3& x)
 	{
 		lTrf.setOrigin(x);
 		movableMarkForUpdate();
@@ -152,6 +145,8 @@ protected:
 	/// Keep the previous transformation for checking if it moved
 	Transform prevWTrf = Transform::getIdentity();
 
+	SceneNode* node;
+
 	/// The frame where it was last moved
 	Timestamp timestamp = getGlobTimestamp();
 

+ 14 - 22
include/anki/scene/ParticleEmitter.h

@@ -26,11 +26,9 @@ public:
 	};
 
 	ParticleBase(
-		ParticleType type,
-		// SceneNode
-		const char* name, SceneGraph* scene, 
-		// Movable
-		U32 movableFlags, Movable* movParent);
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags, // Movable
+		ParticleType type); // Self
 
 	virtual ~ParticleBase();
 
@@ -103,10 +101,8 @@ class ParticleSimple: public ParticleBase
 {
 public:
 	ParticleSimple(
-		// SceneNode
-		const char* name, SceneGraph* scene, 
-		// Movable
-		U32 movableFlags, Movable* movParent);
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags); // Movable
 
 	void revive(const ParticleEmitter& pe,
 		F32 prevUpdateTime, F32 crntTime);
@@ -124,10 +120,8 @@ class Particle: public ParticleBase, public RigidBody
 {
 public:
 	Particle(
-		// SceneNode
-		const char* name, SceneGraph* scene, 
-		// Movable
-		U32 movableFlags, Movable* movParent,
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags, // Movable
 		// RigidBody
 		PhysWorld* masterContainer, const RigidBody::Initializer& init); 
 
@@ -153,11 +147,9 @@ class ParticleEmitter: public SceneNode, public Spatial, public Movable,
 
 public:
 	ParticleEmitter(
-		const char* filename,
-		// SceneNode
-		const char* name, SceneGraph* scene,
-		// Movable
-		U32 movableFlags, Movable* movParent);
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags, // Movable
+		const char* filename); // Self
 
 	~ParticleEmitter();
 
@@ -172,19 +164,19 @@ public:
 	/// @{
 
 	/// Implements Renderable::getModelPatchBase
-	const ModelPatchBase& getRenderableModelPatchBase() const;
+	const ModelPatchBase& getRenderableModelPatchBase();
 
 	/// Implements  Renderable::getMaterial
-	const Material& getRenderableMaterial() const;
+	const Material& getRenderableMaterial();
 
 	/// Overrides Renderable::getRenderableWorldTransforms
-	const Transform* getRenderableWorldTransforms() const
+	const Transform* getRenderableWorldTransforms()
 	{
 		return &(*instancingTransformations)[0];
 	}
 
 	/// Overrides Renderable::getRenderableInstancesCount
-	U32 getRenderableInstancesCount() const
+	U32 getRenderableInstancesCount()
 	{
 		return instancesCount;
 	}

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

@@ -47,9 +47,10 @@ private:
 class Path: public SceneNode, public Movable
 {
 public:
-	Path(const char* filename,
-		const char* name, SceneGraph* scene, // SceneNode
-		U32 movableFlags, Movable* movParent); // Movable
+	Path(
+		const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+		U32 movableFlags, // Movable
+		const char* filename); // Self
 
 	const SceneVector<PathPoint>& getPoints() const
 	{

+ 5 - 5
include/anki/scene/Renderable.h

@@ -156,19 +156,19 @@ public:
 	virtual ~Renderable();
 
 	/// Access to VAOs
-	virtual const ModelPatchBase& getRenderableModelPatchBase() const = 0;
+	virtual const ModelPatchBase& getRenderableModelPatchBase() = 0;
 
 	/// Access the material
-	virtual const Material& getRenderableMaterial() const = 0;
+	virtual const Material& getRenderableMaterial() = 0;
 
 	/// Information for movables. It's actualy an array of transformations.
-	virtual const Transform* getRenderableWorldTransforms() const
+	virtual const Transform* getRenderableWorldTransforms()
 	{
 		return nullptr;
 	}
 
 	/// Number of instances. If greater than 1 then it's instanced
-	virtual U32 getRenderableInstancesCount() const
+	virtual U32 getRenderableInstancesCount()
 	{
 		return 1;
 	}
@@ -190,7 +190,7 @@ public:
 	}
 	/// @}
 
-	U32 getSubMeshesCount() const
+	U32 getSubMeshesCount()
 	{
 		return getRenderableModelPatchBase().getSubMeshesCount();
 	}

+ 24 - 6
include/anki/scene/SceneNode.h

@@ -3,8 +3,7 @@
 
 #include "anki/scene/Property.h"
 #include "anki/scene/Common.h"
-#include "anki/scene/SceneObject.h"
-#include <string>
+#include "anki/util/Object.h"
 
 namespace anki {
 
@@ -23,18 +22,24 @@ class Path;
 /// @{
 
 /// Interface class backbone of scene
-class SceneNode: public SceneObject, public PropertyMap
+class SceneNode: public Object<SceneNode, SceneAllocator<SceneNode>>,
+	public PropertyMap
 {
 public:
+	typedef Object<SceneNode, SceneAllocator<SceneNode>> Base;
+
 	/// @name Constructors/Destructor
 	/// @{
 
 	/// The one and only constructor
-	/// @param name The unique name of the node
+	/// @param name The unique name of the node. If it's nullptr the the node
+	///             is not searchable
 	/// @param scene The scene that will register it
+	/// @param parent The parent of tha node. Used mainly in movable nodes
 	explicit SceneNode(
 		const char* name,
-		SceneGraph* scene);
+		SceneGraph* scene,
+		SceneNode* parent = nullptr);
 
 	/// Unregister node
 	virtual ~SceneNode();
@@ -42,9 +47,21 @@ public:
 
 	/// @name Accessors
 	/// @{
+
+	/// Return the name. It may be nullptr for nodes that we don't want to 
+	/// track
 	const char* getName() const
 	{
-		return name.c_str();
+		return name.length() > 0 ? name.c_str() : nullptr;
+	}
+
+	SceneAllocator<U8> getSceneAllocator() const;
+
+	SceneAllocator<U8> getSceneFrameAllocator() const;
+
+	SceneGraph& getSceneGraph()
+	{
+		return *scene;
 	}
 	/// @}
 
@@ -142,6 +159,7 @@ protected:
 	} sceneNodeProtected;
 
 private:
+	SceneGraph* scene;
 	SceneString name; ///< A unique name
 };
 /// @}

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

@@ -39,7 +39,7 @@ public:
 		/// with any surface then it shouldn't be visible and be processed 
 		/// further. This flag is being used to check if we should test agains
 		/// near plane when using the tiler for visibility tests.
-		SF_FULLY_TRANSPARENT = 1 << 3
+		SF_FULLY_TRANSPARENT = 1 << 3,
 	};
 
 	/// Pass the collision shape here so we can avoid the virtuals

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

@@ -17,7 +17,7 @@ class StaticGeometrySpatial: public Spatial
 public:
 	/// @name Constructors/Destructor
 	/// @{
-	StaticGeometrySpatial(const Obb& obb, const SceneAllocator<U8>& alloc);
+	StaticGeometrySpatial(const Obb* obb, const SceneAllocator<U8>& alloc);
 	/// @}
 };
 
@@ -28,8 +28,9 @@ class StaticGeometryPatchNode: public SceneNode, public Spatial,
 public:
 	/// @name Constructors/Destructor
 	/// @{
-	StaticGeometryPatchNode(const ModelPatchBase* modelPatch,
-		const char* name, SceneGraph* scene); // Scene
+	StaticGeometryPatchNode(
+		const char* name, SceneGraph* scene, // Scene
+		const ModelPatchBase* modelPatch); // Self
 
 	~StaticGeometryPatchNode();
 	/// @}
@@ -38,13 +39,13 @@ public:
 	/// @{
 
 	/// Implements Renderable::getModelPatchBase
-	const ModelPatchBase& getRenderableModelPatchBase() const
+	const ModelPatchBase& getRenderableModelPatchBase()
 	{
 		return *modelPatch;
 	}
 
 	/// Implements  Renderable::getMaterial
-	const Material& getRenderableMaterial() const
+	const Material& getRenderableMaterial()
 	{
 		return modelPatch->getMaterial();
 	}
@@ -58,8 +59,9 @@ private:
 class StaticGeometryNode: public SceneNode
 {
 public:
-	StaticGeometryNode(const char* filename,
-		const char* name, SceneGraph* scene); // Scene
+	StaticGeometryNode(
+		const char* name, SceneGraph* scene, // Scene
+		const char* filename); // Self
 
 	~StaticGeometryNode();
 

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

@@ -146,7 +146,7 @@ struct DistanceSortJob: ThreadJob
 	VisibilityTestResults::Container::iterator nodes;
 	Vec3 origin;
 
-	void operator()(U threadId, U threadsCount)
+	void operator()(U /*threadId*/, U /*threadsCount*/)
 	{
 		DistanceSortFunctor comp;
 		comp.origin = origin;
@@ -160,7 +160,7 @@ struct MaterialSortJob: ThreadJob
 	U nodesCount;
 	VisibilityTestResults::Container::iterator nodes;
 
-	void operator()(U threadId, U threadsCount)
+	void operator()(U /*threadId*/, U /*threadsCount*/)
 	{
 		std::sort(nodes, nodes + nodesCount, MaterialSortFunctor());
 	}

+ 0 - 1
include/anki/script/Common.h

@@ -19,7 +19,6 @@
 #define ANKI_SCRIPT_WRAP_SINGLETON(x) \
 	ANKI_SCRIPT_WRAP(x) { \
 	ANKI_LUA_CLASS_BEGIN_NO_DESTRUCTOR(lb, x)	\
-		ANKI_LUA_CONSTRUCTOR() \
 		ANKI_LUA_STATIC_METHOD("get", &x::get) \
 	ANKI_LUA_CLASS_END() }
 

+ 36 - 0
include/anki/util/Array.h

@@ -21,6 +21,12 @@ struct Array
 	typedef Value& Reference;
 	typedef const Value& ConstReference;
 
+	// std compatible
+	typedef Iterator iterator;
+	typedef ConstIterator const_iterator;
+	typedef Reference reference;
+	typedef ConstReference const_reference;
+
 	Value data[N];
 
 	Reference operator[](const PtrSize n)
@@ -59,10 +65,40 @@ struct Array
 		return &data[0] + N;
 	}
 
+	/// Make it compatible with STL
+	Reference front() 
+	{
+		return data[0];
+	}
+
+	/// Make it compatible with STL
+	ConstReference front() const
+	{
+		return data[0];
+	}
+
+	/// Make it compatible with STL
+	Reference back() 
+	{
+		return data[N - 1];
+	}
+
+	/// Make it compatible with STL
+	ConstReference back() const
+	{
+		return data[N - 1];
+	}
+
 	static constexpr PtrSize getSize()
 	{
 		return N;
 	}
+
+	/// Make it compatible with STL
+	static constexpr PtrSize size()
+	{
+		return N;
+	}
 };
 /// @}
 /// @}

+ 9 - 9
shaders/GaussianBlurGeneric.glsl

@@ -71,20 +71,20 @@ const float weights[4] = float[](
 
 // Calc the kernel
 #if defined(VPASS)
-#	define BLURRING_OFFSET_X(val) (float(val) / float(IMG_DIMENSION))
-#	define BLURRING_OFFSET_Y(val) 0.0
+#	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) 0.0
-#	define BLURRING_OFFSET_Y(val) (float(val) / float(IMG_DIMENSION))
+#	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(v) vec2(BLURRING_OFFSET_X(v), BLURRING_OFFSET_Y(v))
+#define BLURRING_OFFSET(val, sign_) vec2(BLURRING_OFFSET_X(val, sign_), BLURRING_OFFSET_Y(val, sign_))
 
 const vec2 kernel[4] = vec2[](
-	BLURRING_OFFSET(1.3846153846),
-	BLURRING_OFFSET(3.2307692308),
-	BLURRING_OFFSET(-1.3846153846),
-	BLURRING_OFFSET(-3.2307692308));
+	BLURRING_OFFSET(1.3846153846, 1),
+	BLURRING_OFFSET(3.2307692308, 1),
+	BLURRING_OFFSET(1.3846153846, -1),
+	BLURRING_OFFSET(3.2307692308, -1));
 
 // Output
 layout(location = 0) out COL_TYPE fFragColor;

+ 7 - 0
shaders/Pps.glsl

@@ -112,5 +112,12 @@ void main(void)
 		fColor = vec3(ssao);
 	}
 #endif
+
+#if 0
+	if(fColor.r != 0.00000001)
+	{
+		fColor = hdr;
+	}
+#endif
 }
 

+ 11 - 7
shaders/PpsSsao.glsl

@@ -45,7 +45,7 @@ uniform sampler2D noiseMap;
 #define SAMPLE_RAD 0.08
 #define SCALE 1.0
 #define INTENSITY 3.0
-#define BIAS 0.0
+#define BIAS 0.1
 
 vec3 getNormal(in vec2 uv)
 {
@@ -56,11 +56,13 @@ vec3 getNormal(in vec2 uv)
 
 vec2 getRandom(in vec2 uv)
 {
-	vec2 noise = texture(
-		noiseMap, 
-		vec2(float(WIDTH), float(HEIGHT)) 
-		* uv / float(NOISE_MAP_SIZE) / 2.0).xy;
-	return normalize(noise * 2.0 - 1.0);
+	const vec2 tmp = vec2(
+		float(WIDTH) / float(NOISE_MAP_SIZE), 
+		float(HEIGHT) / float(NOISE_MAP_SIZE));
+
+	vec2 noise = texture(noiseMap, tmp * uv).xy;
+	//return normalize(noise * 2.0 - 1.0);r
+	return noise;
 }
 
 vec3 getPosition(in vec2 uv)
@@ -105,7 +107,7 @@ void main(void)
 	vec3 p = getPosition(vTexCoords);
 	vec3 n = getNormal(vTexCoords);
 	vec2 rand = getRandom(vTexCoords);
-	//rand = rand - rand + vec2(0.0, 0.0);
+	//rand = rand * 0.000001 + vec2(0.0, 0.0);
 
 	fColor = 0.0;
 	
@@ -116,5 +118,7 @@ void main(void)
 	}
 
 	fColor = 1.0 - fColor / float(KERNEL_SIZE);
+
+	//fColor = fColor * 0.00001 + (rand.x + rand.y) / 2.0;
 }
 

+ 4 - 2
shaders/VariableSamplingBlurGeneric.glsl

@@ -64,12 +64,14 @@ in vec2 vTexCoords;
 #endif
 
 // Calc the kernel. Use offsets of 3 to take advantage of bilinear filtering
+#define BLURRING(val, sign_) ((float(val) * (float(BLURRING_DIST) + 1.0) / float(IMG_DIMENSION)) * float(sign_))
+
 #if defined(VPASS)
-#	define BLURRING_OFFSET_X(val, sign_) ((float(val) * (BLURRING_DIST + 3.0) / float(IMG_DIMENSION)) * float(sign_))
+#	define BLURRING_OFFSET_X(val, sign_) BLURRING(val, sign_)
 #	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) * (BLURRING_DIST + 3.0) / float(IMG_DIMENSION)) * float(sign_))
+#	define BLURRING_OFFSET_Y(val, sign_) BLURRING(val, sign_)
 #endif
 
 #define BLURRING_OFFSET(v, s) vec2(BLURRING_OFFSET_X(v, s), BLURRING_OFFSET_Y(v, s))

+ 6 - 7
src/collision/Obb.cpp

@@ -60,13 +60,13 @@ Obb Obb::getCompoundShape(const Obb& b) const
 {
 	Obb out;
 
-	std::array<Vec3, 8> points0;
-	std::array<Vec3, 8> points1;
+	Array<Vec3, 8> points0;
+	Array<Vec3, 8> points1;
 
 	getExtremePoints(points0);
 	b.getExtremePoints(points1);
 
-	std::array<Vec3, 16> points;
+	Array<Vec3, 16> points;
 	for(U i = 0; i < 8; i++)
 	{
 		points[i] = points0[i];
@@ -78,7 +78,7 @@ Obb Obb::getCompoundShape(const Obb& b) const
 }
 
 //==============================================================================
-void Obb::getExtremePoints(std::array<Vec3, 8>& points) const
+void Obb::getExtremePoints(Array<Vec3, 8>& points) const
 {
 	// L: left, R: right, T: top, B: bottom, F: front, B: back
 	enum
@@ -112,10 +112,9 @@ void Obb::getExtremePoints(std::array<Vec3, 8>& points) const
 	points[RTB] = 2.0 * points[LTF].dot(yAxis) * yAxis - points[LTF];
 	points[RBF] = 2.0 * points[LTF].dot(zAxis) * zAxis - points[LTF];
 
-	std::array<Vec3, 8>::iterator it = points.begin();
-	for(; it != points.end(); ++it)
+	for(Vec3& point : points)
 	{
-		(*it) += center;
+		point += center;
 	}
 }
 

+ 1 - 1
src/core/App.cpp

@@ -34,7 +34,7 @@ void App::handleLoggerMessages(const Logger::Info& info)
 {
 	std::ostream* out = NULL;
 	const char* x = NULL;
-	const char* terminalColor;
+	const char* terminalColor = nullptr;
 
 	switch(info.type)
 	{

+ 10 - 6
src/core/Counters.cpp

@@ -37,6 +37,8 @@ static const Array<CounterInfo, C_COUNT> cinfo = {{
 	{"SWAP_BUFFERS_TIME", CF_PER_RUN | CF_F64}
 }};
 
+#define MAX_NAME "24"
+
 //==============================================================================
 CountersManager::CountersManager()
 {
@@ -67,16 +69,17 @@ CountersManager::CountersManager()
 		{
 			if(i != 0)
 			{
-				perrunFile.writeString(", %s", inf.name);
+				perrunFile.writeString(", %" MAX_NAME "s", inf.name);
 			}
 			else
 			{
-				perrunFile.writeString("%s", inf.name);
+				perrunFile.writeString("%" MAX_NAME "s", inf.name);
 			}
 
 			++i;
 		}
 	}
+	perrunFile.writeString("\n");
 }
 
 //==============================================================================
@@ -177,7 +180,6 @@ void CountersManager::resolveFrame()
 void CountersManager::flush()
 {
 	// Resolve per run counters
-	perrunFile.writeString("\n");
 	U i = 0;
 	U j = 0;
 	for(const CounterInfo& inf : cinfo)
@@ -191,18 +193,19 @@ void CountersManager::flush()
 
 			if(inf.flags & CF_U64)
 			{
-				perrunFile.writeString("%llu", perrunValues[i]);
+				perrunFile.writeString("%" MAX_NAME "llu", perrunValues[i]);
 			}
 			else if(inf.flags & CF_F64)
 			{
 				if(inf.flags & CF_FPS)
 				{
-					perrunFile.writeString("%f", 
+					perrunFile.writeString("%" MAX_NAME "f", 
 						(F64)getGlobTimestamp() / *((F64*)&perrunValues[i]));
 				}
 				else
 				{
-					perrunFile.writeString("%f", *((F64*)&perrunValues[i]));
+					perrunFile.writeString("%" MAX_NAME "f", 
+						*((F64*)&perrunValues[i]));
 				}
 			}
 			else
@@ -216,6 +219,7 @@ void CountersManager::flush()
 
 		++i;
 	}
+	perrunFile.writeString("\n");
 
 	// Close and flush files
 	perframeFile.close();

+ 5 - 0
src/core/NativeWindowEglFbdev.cpp

@@ -198,6 +198,11 @@ void NativeWindow::create(NativeWindowInitializer& initializer)
 {
 	impl.reset(new NativeWindowImpl);
 	impl->create(initializer);
+
+	// Set the size after because the create may have changed it to something
+	// more nice
+	width = initializer.width;
+	height = initializer.height;
 }
 
 //==============================================================================

+ 28 - 11
src/renderer/Drawer.cpp

@@ -33,6 +33,10 @@ struct SetupRenderableVariableVisitor
 	RenderableVariable* rvar = nullptr;
 	const ShaderProgramUniformVariable* uni;
 
+	// Used for 
+	U32* subSpatialIndices = nullptr;
+	U32 subSpatialIndicesCount = 0;
+
 	/// Set a uniform in a client block
 	template<typename T>
 	void uniSet(const ShaderProgramUniformVariable& uni,
@@ -54,8 +58,6 @@ struct SetupRenderableVariableVisitor
 		const Mat4& vp = fr->getViewProjectionMatrix();
 		const Mat4& v = fr->getViewMatrix();
 
-		const U32 maxInstances = 32;
-
 		switch(x.getBuildinId())
 		{
 		case BMV_NO_BUILDIN:
@@ -65,7 +67,7 @@ struct SetupRenderableVariableVisitor
 		case BMV_MVP_MATRIX:
 			if(trfs)
 			{
-				Array<Mat4, maxInstances> mvp;
+				Array<Mat4, ANKI_MAX_INSTANCES> mvp;
 
 				for(U i = 0; i < size; i++)
 				{
@@ -83,7 +85,7 @@ struct SetupRenderableVariableVisitor
 		case BMV_MV_MATRIX:
 			{
 				ANKI_ASSERT(trfs != nullptr);
-				Array<Mat4, maxInstances> mv;
+				Array<Mat4, ANKI_MAX_INSTANCES> mv;
 
 				for(U i = 0; i < size; i++)
 				{
@@ -99,7 +101,7 @@ struct SetupRenderableVariableVisitor
 		case BMV_NORMAL_MATRIX:
 			if(trfs)
 			{
-				Array<Mat3, maxInstances> normm;
+				Array<Mat3, ANKI_MAX_INSTANCES> normm;
 
 				for(U i = 0; i < size; i++)
 				{
@@ -125,7 +127,7 @@ struct SetupRenderableVariableVisitor
 				Mat3 rot =
 					fr->getViewMatrix().getRotationPart().getTransposed();
 
-				Array<Mat4, maxInstances> bmvp;
+				Array<Mat4, ANKI_MAX_INSTANCES> bmvp;
 
 				for(U i = 0; i < size; i++)
 				{
@@ -191,7 +193,8 @@ void SetupRenderableVariableVisitor::uniSet<TextureResourcePointer>(
 //==============================================================================
 void RenderableDrawer::setupShaderProg(const PassLevelKey& key_,
 	const Frustumable& fr, const ShaderProgram &prog,
-	Renderable& renderable)
+	Renderable& renderable, 
+	U32* subSpatialIndices, U subSpatialIndicesCount)
 {
 	prog.bind();
 	
@@ -200,6 +203,8 @@ void RenderableDrawer::setupShaderProg(const PassLevelKey& key_,
 	vis.fr = &fr;
 	vis.renderable = &renderable;
 	vis.r = r;
+	vis.subSpatialIndices = subSpatialIndices;
+	vis.subSpatialIndicesCount = subSpatialIndicesCount;
 
 	PassLevelKey key(key_.pass,
 		std::min(key_.level,
@@ -297,23 +302,35 @@ void RenderableDrawer::render(SceneNode& frsn, RenderingStage stage,
 
 	U32 primCount = 1;
 
-	if(subSpatialIndicesCount == 0)
+	const ModelPatchBase& resource = renderable->getRenderableModelPatchBase();
+	if(subSpatialIndicesCount == 0 || resource.getSubMeshesCount() == 0)
 	{
-		renderable->getRenderableModelPatchBase().getRenderingData(
+		// No multimesh
+
+		resource.getRenderingData(
 			key, vao, prog, indicesCountArray[0]);
 
 		indicesOffsetArray[0] = nullptr;
 	}
 	else
 	{
-		renderable->getRenderableModelPatchBase().getRenderingDataSub(
+		// It's a multimesh
+
+		resource.getRenderingDataSub(
 			key, vao, prog, 
 			subSpatialIndices, subSpatialIndicesCount,
 			indicesCountArray, indicesOffsetArray, primCount);
 	}
 
+	// Hack the instances count
+	if(subSpatialIndicesCount > 0 && instancesCount > 1)
+	{
+		instancesCount = subSpatialIndicesCount;
+	}
+
 	// Setup shader
-	setupShaderProg(key, fr, *prog, *renderable);
+	setupShaderProg(
+		key, fr, *prog, *renderable, subSpatialIndices, subSpatialIndicesCount);
 
 	// Render
 	ANKI_ASSERT(vao->getAttachmentsCount() > 1);

+ 6 - 7
src/renderer/Hdr.cpp

@@ -54,22 +54,21 @@ void Hdr::initInternal(const Renderer::Initializer& initializer)
 
 	const char* SHADER_FILENAME = "shaders/GaussianBlurGeneric.glsl";
 
-	F32 blurringDistRealX = F32(blurringDist / width);// XXX
-	F32 blurringDistRealY = F32(blurringDist / height);// XXX
-
 	std::string pps =
 		"#define HPASS\n"
 		"#define COL_RGB\n"
-		"#define BLURRING_DIST " + std::to_string(blurringDistRealX) + "\n" // XXX
-		"#define IMG_DIMENSION " + std::to_string(height) + ".0\n";
+		"#define BLURRING_DIST " + std::to_string(blurringDist) + "\n"
+		"#define IMG_DIMENSION " + std::to_string(height) + "\n"
+		"#define SAMPLES 7\n";
 	hblurSProg.load(ShaderProgramResource::createSrcCodeToCache(
 		SHADER_FILENAME, pps.c_str()).c_str());
 
 	pps =
 		"#define VPASS\n"
 		"#define COL_RGB\n"
-		"#define BLURRING_DIST " + std::to_string(blurringDistRealY) + "\n"// XXX
-		"#define IMG_DIMENSION " + std::to_string(width) + ".0\n";
+		"#define BLURRING_DIST " + std::to_string(blurringDist) + "\n"
+		"#define IMG_DIMENSION " + std::to_string(width) + "\n"
+		"#define SAMPLES 7\n";
 	vblurSProg.load(ShaderProgramResource::createSrcCodeToCache(
 		SHADER_FILENAME, pps.c_str()).c_str());
 

+ 1 - 1
src/renderer/Ssao.cpp

@@ -72,7 +72,7 @@ void Ssao::initInternal(const RendererInitializer& initializer)
 	//
 	// noise map
 	//
-	noiseMap.load("engine-rsrc/noise.png");
+	noiseMap.load("engine-rsrc/noise3.png");
 	noiseMap->setFiltering(Texture::TFT_NEAREST);
 	if(noiseMap->getWidth() != noiseMap->getHeight())
 	{

+ 40 - 8
src/resource/MaterialShaderProgramCreator.cpp

@@ -96,6 +96,7 @@ void MaterialShaderProgramCreator::parseInputsTag(const XmlElement& programEl)
 		XmlElement constEl = inputEl.getChildElementOptional("const");
 		XmlElement valueEl = inputEl.getChildElement("value");
 		XmlElement arrSizeEl = inputEl.getChildElementOptional("arraySize");
+		XmlElement instancedEl = inputEl.getChildElementOptional("instanced");
 
 		// <const>
 		inpvar->constant = (constEl) ? constEl.getInt() : false;
@@ -103,6 +104,12 @@ void MaterialShaderProgramCreator::parseInputsTag(const XmlElement& programEl)
 		// <array>
 		inpvar->arraySize = (arrSizeEl) ? arrSizeEl.getInt() : 0;
 
+		// instanced
+		if(inpvar->arraySize == 0)
+		{
+			inpvar->instanced = (instancedEl) ? instancedEl.getInt() : 0;
+		}
+
 		// <value>
 		if(valueEl.getText())
 		{
@@ -111,7 +118,7 @@ void MaterialShaderProgramCreator::parseInputsTag(const XmlElement& programEl)
 
 		if(inpvar->constant == false)
 		{
-			// Handle non-consts
+			// Handle NON-consts
 
 			inpvar->line = inpvar->type + " " + inpvar->name;
 				
@@ -121,6 +128,12 @@ void MaterialShaderProgramCreator::parseInputsTag(const XmlElement& programEl)
 					+ "U]";
 			}
 
+			if(inpvar->instanced)
+			{
+				inpvar->line += "[" + std::to_string(ANKI_MAX_INSTANCES) 
+					+ "U]";
+			}
+
 			inpvar->line += ";";
 
 			// Can put it block
@@ -184,10 +197,14 @@ void MaterialShaderProgramCreator::parseShaderTag(const XmlElement& shaderEl)
 	{
 		shader = VERTEX;
 	}
-	else
+	else if(type == "fragment")
 	{
 		shader = FRAGMENT;
 	}
+	else
+	{
+		throw ANKI_EXCEPTION("Unknown <shader>");
+	}
 
 	// <includes></includes>
 	//
@@ -290,24 +307,39 @@ void MaterialShaderProgramCreator::parseOperationTag(
 		do
 		{
 			// Search for all the inputs and mark the appropriate
+			Input* input = nullptr;
 			for(U i = 0; i < inputs.size(); i++)
 			{
 				// Check that the first part of the string is equal to the 
 				// variable and the following char is '['
 				std::string text = argEl.getText();
 				const std::string& name = inputs[i]->name;
-				if(text == name 
-					|| (text.find(name) == 0 
-						&& text.size() > name.size()
-						&& text[name.size()] == '['))
+				if(text == name)
 				{
 					inputs[i]->shaders |= (U32)shader;
+					input = inputs[i];
 					break;
 				}
 			}
 
-			// Add to a list
-			argsList.push_back(argEl.getText());
+			// Add to a list and do something special if instanced
+			if(input && input->instanced)
+			{
+				if(shader == VERTEX)
+				{
+					argsList.push_back(std::string(argEl.getText()) 
+						+ "[gl_InstanceID]");
+				}
+				else
+				{
+					argsList.push_back(std::string(argEl.getText()) 
+						+ "[vInstanceId]");
+				}
+			}
+			else
+			{
+				argsList.push_back(argEl.getText());
+			}
 
 			// Advance
 			argEl = argEl.getNextSiblingElement("argument");

+ 15 - 14
src/scene/Camera.cpp

@@ -7,12 +7,13 @@ namespace anki {
 //==============================================================================
 
 //==============================================================================
-Camera::Camera(CameraType type_,
-	const char* name, SceneGraph* scene, // SceneNode
-	U32 movableFlags, Movable* movParent, // Movable
-	Frustum* frustum) // Spatial & Frustumable
-	:	SceneNode(name, scene),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+Camera::Camera(
+	const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+	U32 movableFlags, // Movable
+	Frustum* frustum, // Spatial & Frustumable
+	CameraType type_) 
+	:	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
 		Spatial(frustum, getSceneAllocator()),
 		Frustumable(frustum),
 		type(type_)
@@ -44,10 +45,10 @@ void Camera::lookAtPoint(const Vec3& point)
 //==============================================================================
 
 //==============================================================================
-PerspectiveCamera::PerspectiveCamera(const char* name, SceneGraph* scene,
-	uint movableFlags, Movable* movParent)
-	: Camera(CT_PERSPECTIVE, name, scene, movableFlags, movParent, 
-		&frustum)
+PerspectiveCamera::PerspectiveCamera(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags)
+	: Camera(name, scene, parent, movableFlags, &frustum, CT_PERSPECTIVE)
 {}
 
 //==============================================================================
@@ -55,10 +56,10 @@ PerspectiveCamera::PerspectiveCamera(const char* name, SceneGraph* scene,
 //==============================================================================
 
 //==============================================================================
-OrthographicCamera::OrthographicCamera(const char* name, SceneGraph* scene,
-	uint movableFlags, Movable* movParent)
-	: Camera(CT_ORTHOGRAPHIC, name, scene, movableFlags, movParent, 
-		&frustum)
+OrthographicCamera::OrthographicCamera(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags)
+	: Camera(name, scene, parent, movableFlags, &frustum, CT_ORTHOGRAPHIC)
 {}
 
 } // end namespace

+ 15 - 12
src/scene/Light.cpp

@@ -7,12 +7,13 @@ namespace anki {
 //==============================================================================
 
 //==============================================================================
-Light::Light(LightType t, // Light
-	const char* name, SceneGraph* scene, // Scene
-	U32 movableFlags, Movable* movParent, // Movable
-	CollisionShape* cs) // Spatial
-	:	SceneNode(name, scene),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+Light::Light(
+	const char* name, SceneGraph* scene, SceneNode* parent, // Scene
+	U32 movableFlags, // Movable
+	CollisionShape* cs, // Spatial
+	LightType t) // Self
+	:	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
 		Spatial(cs, getSceneAllocator()),
 		type(t)
 {
@@ -37,9 +38,10 @@ Light::~Light()
 //==============================================================================
 
 //==============================================================================
-PointLight::PointLight(const char* name, SceneGraph* scene,
-	U32 movableFlags, Movable* movParent)
-	: Light(LT_POINT, name, scene, movableFlags, movParent, &sphereW)
+PointLight::PointLight(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags)
+	: Light(name, scene, parent, movableFlags, &sphereW, LT_POINT)
 {
 	F32& r = sphereW.getRadius();
 	addNewProperty(new ReadWritePointerProperty<F32>("radius", &r));
@@ -50,9 +52,10 @@ PointLight::PointLight(const char* name, SceneGraph* scene,
 //==============================================================================
 
 //==============================================================================
-SpotLight::SpotLight(const char* name, SceneGraph* scene,
-	U32 movableFlags, Movable* movParent)
-	: 	Light(LT_SPOT, name, scene, movableFlags, movParent, &frustum),
+SpotLight::SpotLight(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags)
+	: 	Light(name, scene, parent, movableFlags, &frustum, LT_SPOT),
 		Frustumable(&frustum)
 {
 	sceneNodeProtected.frustumable = this;

+ 167 - 13
src/scene/ModelNode.cpp

@@ -4,25 +4,178 @@
 
 namespace anki {
 
+//==============================================================================
+// ModelPatchNodeInstance                                                      =
+//==============================================================================
+
+//==============================================================================
+ModelPatchNodeInstance::ModelPatchNodeInstance(
+	const char* name, SceneGraph* scene, SceneNode* parent, // Scene
+	U32 movableFlags, // Movable
+	const ModelPatchBase* modelPatchResource) // Self
+	:	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
+		Spatial(&obb, getSceneAllocator()),
+		modelPatch(modelPatchResource)
+{
+	sceneNodeProtected.movable = this;
+
+	// Dont mark it as spatial because it's sub-spatial and don't want to 
+	// be updated by the scene
+	sceneNodeProtected.spatial = nullptr;
+
+	ANKI_ASSERT(modelPatch);
+}
+
+//==============================================================================
+void ModelPatchNodeInstance::movableUpdate()
+{
+	ANKI_ASSERT(modelPatch);
+
+	// Update the obb of self
+	obb = modelPatch->getBoundingShape().getTransformed(
+		getWorldTransform());
+	spatialMarkForUpdate();
+
+	// If this instance is the last update the parent's collision shape
+	SceneNode* parentNode = getParent();
+	ANKI_ASSERT(parentNode);
+
+	ModelPatchNode* modelPatchNode = 
+#if ANKI_DEBUG
+		dynamic_cast<ModelPatchNode*>(parentNode);
+	ANKI_ASSERT(modelPatchNode);
+#else
+		static_cast<ModelPatchNode*>(parentNode);
+#endif
+
+	ANKI_ASSERT(modelPatchNode->instances.size() > 0);
+	if(this == modelPatchNode->instances.back())
+	{
+		modelPatchNode->updateSpatialCs();
+	}
+}
+
 //==============================================================================
 // ModelPatchNode                                                              =
 //==============================================================================
 
 //==============================================================================
-ModelPatchNode::ModelPatchNode(const ModelPatchBase *modelPatch_,
-	const char* name, SceneGraph* scene,
-	U32 movableFlags, Movable* movParent)
-	:	SceneNode(name, scene),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+ModelPatchNode::ModelPatchNode(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags,
+	const ModelPatchBase* modelPatch_, U instancesCount)
+	:	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
 		Renderable(getSceneAllocator()),
 		Spatial(&obb, getSceneAllocator()), 
-		modelPatch(modelPatch_)
+		modelPatch(modelPatch_),
+		instances(getSceneAllocator()),
+		transforms(getSceneAllocator())
 {
 	sceneNodeProtected.movable = this;
 	sceneNodeProtected.renderable = this;
 	sceneNodeProtected.spatial = this;
 
 	Renderable::init(*this);
+
+	// Create the instances as ModelPatchNodeInstance
+	if(instancesCount > 1)
+	{
+		spatialProtected.subSpatials.resize(instancesCount, nullptr);
+		instances.resize(instancesCount, nullptr);
+		transforms.resize(instancesCount, Transform::getIdentity());
+
+		Vec3 pos = Vec3(0.0);
+
+		for(U i = 0; i < instancesCount; i++)
+		{
+			ModelPatchNodeInstance* instance = ANKI_NEW(
+				ModelPatchNodeInstance, getSceneAllocator(), 
+				nullptr, scene, this, Movable::MF_NONE,
+				modelPatch);
+
+			instance->setLocalOrigin(pos);
+			pos.x() += 2.0;
+
+			spatialProtected.subSpatials[i] = instance;
+			instances[i] = instance;
+		}
+	}
+}
+
+//==============================================================================
+ModelPatchNode::~ModelPatchNode()
+{
+	for(ModelPatchNodeInstance* instance : instances)
+	{
+		ANKI_DELETE(instance, getSceneAllocator());
+	}
+}
+
+//==============================================================================
+const Transform* ModelPatchNode::getRenderableWorldTransforms()
+{
+	if(transforms.size() == 0)
+	{
+		// NO instancing
+		return &getWorldTransform();
+	}
+	else
+	{
+		// Instancing
+
+		ANKI_ASSERT(transforms.size() == instances.size());
+
+		// Set the transforms
+		for(U i = 0; i < instances.size(); i++)
+		{
+			transforms[i] = instances[i]->getWorldTransform();
+		}
+
+		return &transforms[0];
+	}
+}
+
+//==============================================================================
+void ModelPatchNode::movableUpdate()
+{
+	Movable::movableUpdate();
+
+	if(instances.size() == 0)
+	{
+		// NO instancing
+
+		obb = modelPatch->getBoundingShape().getTransformed(
+			getWorldTransform());
+
+		spatialMarkForUpdate();
+	}
+	else
+	{
+		// Instancing
+		
+		// Do nothing. You cannot update the obb because the instances have
+		// not been updated their CSs yet. The update will be triggered by the 
+		// last instance.
+	}
+}
+
+//==============================================================================
+void ModelPatchNode::updateSpatialCs()
+{
+	ANKI_ASSERT(instances.size() > 0);
+
+	obb = instances[0]->obb;
+
+	for(U i = 1; i < instances.size(); i++)
+	{
+		ANKI_ASSERT(instances[i]);
+
+		obb = obb.getCompoundShape(instances[i]->obb);
+	}
+
+	spatialMarkForUpdate();
 }
 
 //==============================================================================
@@ -30,11 +183,12 @@ ModelPatchNode::ModelPatchNode(const ModelPatchBase *modelPatch_,
 //==============================================================================
 
 //==============================================================================
-ModelNode::ModelNode(const char* modelFname,
-	const char* name, SceneGraph* scene,
-	uint movableFlags, Movable* movParent)
-	: 	SceneNode(name, scene),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+ModelNode::ModelNode(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags,
+	const char* modelFname, U instances)
+	: 	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
 		patches(getSceneAllocator())
 {
 	sceneNodeProtected.movable = this;
@@ -49,8 +203,8 @@ ModelNode::ModelNode(const char* modelFname,
 		std::string name_ = name + std::to_string(i);
 
 		ModelPatchNode* mpn = ANKI_NEW(ModelPatchNode, getSceneAllocator(),
-			patch, name_.c_str(),
-			scene, Movable::MF_IGNORE_LOCAL_TRANSFORM, this);
+			name_.c_str(), scene, this,
+			Movable::MF_IGNORE_LOCAL_TRANSFORM, patch, instances);
 
 		patches.push_back(mpn);
 		++i;

+ 27 - 15
src/scene/Movable.cpp

@@ -1,17 +1,18 @@
 #include "anki/scene/Movable.h"
-#include "anki/scene/Property.h"
+#include "anki/scene/SceneNode.h"
 
 namespace anki {
 
 //==============================================================================
-Movable::Movable(U32 flags_, Movable* parent, PropertyMap& pmap,
-	const SceneAllocator<Movable>& alloc)
-	: Base(parent, alloc), Bitset(flags_)
+Movable::Movable(U32 flags_, SceneNode* node_)
+	: Bitset(flags_), node(node_)
 {
-	pmap.addNewProperty(
+	ANKI_ASSERT(node);
+
+	/*pmap.addNewProperty(
 		new ReadWritePointerProperty<Transform>("localTransform", &lTrf));
 	pmap.addNewProperty(
-		new ReadPointerProperty<Transform>("worldTransform", &wTrf));
+		new ReadPointerProperty<Transform>("worldTransform", &wTrf));*/
 
 	movableMarkForUpdate();
 }
@@ -24,7 +25,7 @@ Movable::~Movable()
 void Movable::update()
 {
 	// If root begin updating
-	if(getParent() == nullptr)
+	if(node->getParent() == nullptr)
 	{
 		updateWorldTransform();
 	}
@@ -34,7 +35,10 @@ void Movable::update()
 void Movable::updateWorldTransform()
 {
 	prevWTrf = wTrf;
-	const Movable* parent = getParent();
+	const Movable* parent = 
+		node->getParent() 
+		? node->getParent()->getMovable() 
+		: nullptr;
 	const Bool dirty = bitsEnabled(MF_TRANSFORM_DIRTY);
 
 	// If dirty then update world transform
@@ -61,16 +65,24 @@ void Movable::updateWorldTransform()
 	}
 
 	// Update the children
-	Movable::Container::iterator it = getChildrenBegin();
-	for(; it != getChildrenEnd(); it++)
+	SceneNode::Base::Container::iterator it = node->getChildrenBegin();
+	for(; it != node->getChildrenEnd(); it++)
 	{
-		// If parent is dirty then make children dirty as well
-		if(dirty)
+		SceneNode* sn = (*it);
+		ANKI_ASSERT(sn);
+		Movable* mov = sn->getMovable();
+
+		// If child is movable update it
+		if(mov)
 		{
-			(*it)->movableMarkForUpdate();
-		}
+			// If parent is dirty then make children dirty as well
+			if(dirty)
+			{
+				mov->movableMarkForUpdate();
+			}
 
-		(*it)->updateWorldTransform();
+			mov->updateWorldTransform();
+		}
 	}
 
 	// Now it's a good time to cleanse parent

+ 22 - 30
src/scene/ParticleEmitter.cpp

@@ -42,13 +42,11 @@ Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
 
 //==============================================================================
 ParticleBase::ParticleBase(
-	ParticleType type_,
-	// SceneNode
-	const char* name, SceneGraph* scene, 
-	// Movable
-	U32 movableFlags, Movable* movParent)
-	:	SceneNode(name, scene),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+	const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+	U32 movableFlags, // Movable
+	ParticleType type_)
+	:	SceneNode(name, scene, parent),
+		Movable(movableFlags, this),
 		type(type_)
 {
 	sceneNodeProtected.movable = this;
@@ -77,11 +75,9 @@ void ParticleBase::revive(const ParticleEmitter& pe,
 
 //==============================================================================
 ParticleSimple::ParticleSimple(
-	// SceneNode
-	const char* name, SceneGraph* scene, 
-	// Movable
-	U32 movableFlags, Movable* movParent)
-	: ParticleBase(PT_SIMPLE, name, scene, movableFlags, movParent)
+	const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+	U32 movableFlags) // Movable
+	: ParticleBase(name, scene, parent, movableFlags, PT_SIMPLE)
 {}
 
 //==============================================================================
@@ -135,13 +131,11 @@ void ParticleSimple::revive(const ParticleEmitter& pe,
 
 //==============================================================================
 Particle::Particle(
-	// Scene
-	const char* name, SceneGraph* scene,
-	// Movable
-	U32 movableFlags, Movable* movParent, 
+	const char* name, SceneGraph* scene, SceneNode* parent, // SceneNode
+	U32 movableFlags, // Movable
 	// RigidBody
 	PhysWorld* masterContainer, const Initializer& init)
-	: ParticleBase(PT_PHYSICS, name, scene, movableFlags, movParent),
+	:	ParticleBase(name, scene, parent, movableFlags, PT_PHYSICS),
 		RigidBody(masterContainer, init, this)
 {
 	sceneNodeProtected.rigidBody = this;
@@ -222,14 +216,12 @@ void Particle::revive(const ParticleEmitter& pe,
 
 //==============================================================================
 ParticleEmitter::ParticleEmitter(
-	const char* filename,
-	// SceneNode
-	const char* name, SceneGraph* scene, 
-	// Movable
-	U32 movableFlags, Movable* movParent)
-	:	SceneNode(name, scene),
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags,
+	const char* filename)
+	:	SceneNode(name, scene, parent),
 		Spatial(&aabb, getSceneAllocator()),
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+		Movable(movableFlags, this),
 		Renderable(getSceneAllocator()),
 		particles(getSceneAllocator())
 {
@@ -283,13 +275,13 @@ ParticleEmitter::~ParticleEmitter()
 }
 
 //==============================================================================
-const ModelPatchBase& ParticleEmitter::getRenderableModelPatchBase() const
+const ModelPatchBase& ParticleEmitter::getRenderableModelPatchBase()
 {
 	return *particleEmitterResource->getModel().getModelPatches()[0];
 }
 
 //==============================================================================
-const Material& ParticleEmitter::getRenderableMaterial() const
+const Material& ParticleEmitter::getRenderableMaterial()
 {
 	return
 		particleEmitterResource->getModel().getModelPatches()[0]->getMaterial();
@@ -319,8 +311,8 @@ void ParticleEmitter::createParticlesSimulation(SceneGraph* scene)
 		binit.mass = getRandom(particle.mass, particle.massDeviation);
 
 		Particle* part = ANKI_NEW(Particle, getSceneAllocator(),
-			(getName() + std::to_string(i)).c_str(), scene,
-			Movable::MF_NONE, nullptr,
+			(getName() + std::to_string(i)).c_str(), scene, nullptr,
+			Movable::MF_NONE,
 			&scene->getPhysics(), binit);
 
 		part->size = getRandom(particle.size, particle.sizeDeviation);
@@ -337,8 +329,8 @@ void ParticleEmitter::createParticlesSimpleSimulation(SceneGraph* scene)
 	for(U i = 0; i < maxNumOfParticles; i++)
 	{
 		ParticleSimple* part = ANKI_NEW(ParticleSimple, getSceneAllocator(),
-			(getName() + std::to_string(i)).c_str(),
-			scene, Movable::MF_NONE, nullptr);
+			(getName() + std::to_string(i)).c_str(), scene, nullptr,
+			Movable::MF_NONE);
 
 		part->size = getRandom(particle.size, particle.sizeDeviation);
 		part->alpha = getRandom(particle.alpha, particle.alphaDeviation);

+ 6 - 5
src/scene/Path.cpp

@@ -3,11 +3,12 @@
 namespace anki {
 
 //==============================================================================
-Path::Path(const char* filename,
-	const char* name, SceneGraph* scene,
-	U32 movableFlags, Movable* movParent)
-	:	SceneNode(name, scene), 
-		Movable(movableFlags, movParent, *this, getSceneAllocator()),
+Path::Path(
+	const char* name, SceneGraph* scene, SceneNode* parent,
+	U32 movableFlags,
+	const char* filename)
+	:	SceneNode(name, scene, parent), 
+		Movable(movableFlags, this),
 		points(getSceneAllocator())
 {
 	// Set scene node related flags

+ 14 - 4
src/scene/SceneGraph.cpp

@@ -116,14 +116,24 @@ SceneGraph::~SceneGraph()
 void SceneGraph::registerNode(SceneNode* node)
 {
 	addC(nodes, node);
-	addDict(nameToNode, node);
+
+	// Add to dict if it has name
+	if(node->getName())
+	{
+		addDict(nameToNode, node);
+	}
 }
 
 //==============================================================================
 void SceneGraph::unregisterNode(SceneNode* node)
 {
 	removeC(nodes, node);
-	removeDict(nameToNode, node);
+
+	// Remove from dict if it has name
+	if(node->getName())
+	{
+		removeDict(nameToNode, node);
+	}
 }
 
 //==============================================================================
@@ -233,8 +243,8 @@ void SceneGraph::load(const char* filename)
 			// <model>
 			el = mdlNodeEl.getChildElement("model");
 
-			ModelNode* node = new ModelNode(el.getText(), "name", this, 
-				Movable::MF_NONE, nullptr);
+			ModelNode* node = new ModelNode("name", this, nullptr,
+				Movable::MF_NONE, el.getText());
 
 			// <transform>
 			el = mdlNodeEl.getChildElement("transform");

+ 24 - 3
src/scene/SceneNode.cpp

@@ -7,10 +7,17 @@
 namespace anki {
 
 //==============================================================================
-SceneNode::SceneNode(const char* name_, SceneGraph* scene_)
-	: SceneObject(nullptr, scene_), name(name_, scene_->getAllocator())
+SceneNode::SceneNode(const char* name_, SceneGraph* scene_, SceneNode* parent)
+	:	Base(parent, scene_->getAllocator()),
+		scene(scene_)
 {
-	name.shrink_to_fit(); // Do that first
+	ANKI_ASSERT(scene);
+
+	if(name_)
+	{
+		name = SceneString(name_, scene->getAllocator());
+	}
+	
 	scene->registerNode(this);
 
 	/// Add the first property
@@ -28,6 +35,20 @@ SceneNode::~SceneNode()
 	}
 }
 
+//==============================================================================
+SceneAllocator<U8> SceneNode::getSceneAllocator() const
+{
+	ANKI_ASSERT(scene);
+	return scene->getAllocator();
+}
+
+//==============================================================================
+SceneAllocator<U8> SceneNode::getSceneFrameAllocator() const
+{
+	ANKI_ASSERT(scene);
+	return scene->getFrameAllocator();
+}
+
 //==============================================================================
 U32 SceneNode::getLastUpdateFrame()
 {

+ 4 - 0
src/scene/SkinNode.cpp

@@ -8,6 +8,8 @@ namespace anki {
 
 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
 
+#if 0
+
 //==============================================================================
 // SkinMesh                                                                    =
 //==============================================================================
@@ -370,4 +372,6 @@ void SkinNode::deformHeadsTails(const Skeleton& skeleton,
 #endif
 }
 
+#endif
+
 } // end namespace

+ 9 - 9
src/scene/StaticGeometryNode.cpp

@@ -8,9 +8,9 @@ namespace anki {
 //==============================================================================
 
 //==============================================================================
-StaticGeometrySpatial::StaticGeometrySpatial(const Obb& obb,
+StaticGeometrySpatial::StaticGeometrySpatial(const Obb* obb,
 	const SceneAllocator<U8>& alloc)
-	: Spatial(&obb, alloc)
+	: Spatial(obb, alloc)
 {}
 
 //==============================================================================
@@ -19,8 +19,8 @@ StaticGeometrySpatial::StaticGeometrySpatial(const Obb& obb,
 
 //==============================================================================
 StaticGeometryPatchNode::StaticGeometryPatchNode(
-	const ModelPatchBase* modelPatch_, const char* name, SceneGraph* scene)
-	:	SceneNode(name, scene),
+	const char* name, SceneGraph* scene, const ModelPatchBase* modelPatch_)
+	:	SceneNode(name, scene, nullptr),
 		Spatial(&modelPatch_->getBoundingShape(), getSceneAllocator()),
 		Renderable(getSceneAllocator()),
 		modelPatch(modelPatch_)
@@ -40,7 +40,7 @@ StaticGeometryPatchNode::StaticGeometryPatchNode(
 		{
 			StaticGeometrySpatial* spatial =
 				ANKI_NEW(StaticGeometrySpatial, getSceneAllocator(),
-				modelPatch->getBoundingShapeSub(i), getSceneAllocator());
+				&modelPatch->getBoundingShapeSub(i), getSceneAllocator());
 
 			spatialProtected.subSpatials[i] = spatial;
 		}
@@ -61,9 +61,9 @@ StaticGeometryPatchNode::~StaticGeometryPatchNode()
 //==============================================================================
 
 //==============================================================================
-StaticGeometryNode::StaticGeometryNode(const char* filename,
-	const char* name, SceneGraph* scene)
-	: SceneNode(name, scene), patches(getSceneAllocator())
+StaticGeometryNode::StaticGeometryNode(
+	const char* name, SceneGraph* scene, const char* filename)
+	: SceneNode(name, scene, nullptr), patches(getSceneAllocator())
 {
 	model.load(filename);
 
@@ -76,7 +76,7 @@ StaticGeometryNode::StaticGeometryNode(const char* filename,
 
 		StaticGeometryPatchNode* node = ANKI_NEW(
 			StaticGeometryPatchNode, getSceneAllocator(),
-			patch, name_.c_str(), scene);
+			name_.c_str(), scene, patch);
 
 		patches.push_back(node);
 		++i;

+ 0 - 1
src/script/renderer/MainRenderer.cpp

@@ -18,7 +18,6 @@ static Pps& getPps(MainRenderer* self)
 ANKI_SCRIPT_WRAP(MainRenderer)
 {
 	ANKI_LUA_CLASS_BEGIN(lb, MainRenderer)
-		ANKI_LUA_CONSTRUCTOR()
 		ANKI_LUA_FUNCTION_AS_METHOD("getDbg", &getDbg)
 		ANKI_LUA_FUNCTION_AS_METHOD("getPps", &getPps)
 	ANKI_LUA_CLASS_END()

+ 3 - 2
src/util/FilesystemPosix.cpp

@@ -41,8 +41,8 @@ bool directoryExists(const char* filename)
 }
 
 //==============================================================================
-static int rmDir(const char* fpath, const struct stat* sb, int typeflag,
-	struct FTW* ftwbuf)
+static int rmDir(const char* fpath, const struct stat* sb, int /*typeflag*/,
+	struct FTW* /*ftwbuf*/)
 {
 	(void)sb;
 	int rv = remove(fpath);
@@ -81,6 +81,7 @@ void createDirectory(const char* dir)
 void toNativePath(const char* path)
 {
 	ANKI_ASSERT(path);
+	(void)path;
 }
 
 } // end namespace anki

+ 28 - 32
testapp/Main.cpp

@@ -94,9 +94,8 @@ void initPhysics()
 					+ std::to_string(j) + std::to_string(k);
 
 				ModelNode* mnode = new ModelNode(
-					"data/models/crate0/crate0.mdl",
-					name.c_str(),
-					&SceneGraphSingleton::get(), Movable::MF_NONE, nullptr);
+					name.c_str(), &SceneGraphSingleton::get(), nullptr,
+					Movable::MF_NONE, "data/models/crate0/crate0.mdl");
 
 				init.movable = mnode;
 				ANKI_ASSERT(init.movable);
@@ -128,8 +127,8 @@ void init()
 #endif
 
 	// camera
-	cam = new PerspectiveCamera("main-camera", &scene,
-		Movable::MF_NONE, nullptr);
+	cam = new PerspectiveCamera("main-camera", &scene, nullptr,
+		Movable::MF_NONE);
 	const F32 ang = 45.0;
 	cam->setAll(
 		MainRendererSingleton::get().getAspectRatio() * toRad(ang),
@@ -140,7 +139,7 @@ void init()
 	scene.setActiveCamera(cam);
 
 	// lights
-#if 1
+#if 0
 	Vec3 lpos(-24.0, 0.1, -10.0);
 	for(int i = 0; i < 50; i++)
 	{
@@ -148,14 +147,14 @@ void init()
 		{
 			std::string name = "plight" + std::to_string(i) + std::to_string(j);
 
-			PointLight* point = new PointLight(name.c_str(), &scene,
-				Movable::MF_NONE, nullptr);
+			PointLight* point = new PointLight(name.c_str(), &scene, nullptr,
+				Movable::MF_NONE);
 			point->setRadius(0.5);
 			point->setDiffuseColor(Vec4(randFloat(6.0) - 2.0, 
 				randFloat(6.0) - 2.0, randFloat(6.0) - 2.0, 0.0));
 			point->setSpecularColor(Vec4(randFloat(6.0) - 3.0, 
 				randFloat(6.0) - 3.0, randFloat(6.0) - 3.0, 0.0));
-			point->setLocalTranslation(lpos);
+			point->setLocalOrigin(lpos);
 
 			lpos.z() += 2.0;
 		}
@@ -165,8 +164,8 @@ void init()
 	}
 #endif
 
-#if 1
-	SpotLight* spot = new SpotLight("spot0", &scene, Movable::MF_NONE, nullptr);
+#if 0
+	SpotLight* spot = new SpotLight("spot0", &scene, nullptr, Movable::MF_NONE);
 	spot->setOuterAngle(toRad(45.0));
 	spot->setInnerAngle(toRad(15.0));
 	spot->setLocalTransform(Transform(Vec3(8.27936, 5.86285, 1.85526),
@@ -177,7 +176,7 @@ void init()
 	spot->setShadowEnabled(true);
 
 
-	spot = new SpotLight("spot1", &scene, Movable::MF_NONE, nullptr);
+	spot = new SpotLight("spot1", &scene, nullptr, Movable::MF_NONE);
 	spot->setOuterAngle(toRad(45.0));
 	spot->setInnerAngle(toRad(15.0));
 	spot->setLocalTransform(Transform(Vec3(5.3, 4.3, 3.0),
@@ -188,7 +187,7 @@ void init()
 	spot->setShadowEnabled(true);
 #endif
 
-#if 1
+#if 0
 	// Vase point lights
 	F32 x = 8.5;
 	F32 y = 2.25;
@@ -201,9 +200,9 @@ void init()
 
 		PointLight* point =
 			new PointLight(("vase_plight" + std::to_string(i)).c_str(),
-			&scene, Movable::MF_NONE, nullptr);
+			&scene, nullptr, Movable::MF_NONE);
 		point->setRadius(2.0);
-		point->setLocalTranslation(lightPos);
+		point->setLocalOrigin(lightPos);
 		point->setDiffuseColor(Vec4(3.0, 0.2, 0.0, 0.0));
 		point->setSpecularColor(Vec4(1.0, 1.0, 0.0, 0.0));
 
@@ -223,39 +222,37 @@ void init()
 		mevent->enableBits(Event::EF_REANIMATE);
 
 		ParticleEmitter* pe = new ParticleEmitter(
-			"data/particles/smoke.particles",
-			("pe" + std::to_string(i)).c_str(), &scene,
-			Movable::MF_NONE, nullptr);
-		pe->setLocalTranslation(lightPos);
+			("pe" + std::to_string(i)).c_str(), &scene, nullptr,
+			Movable::MF_NONE, "data/particles/smoke.particles");
+		pe->setLocalOrigin(lightPos);
 
 		pe = new ParticleEmitter(
-			"data/particles/fire.particles",
-			("pef" + std::to_string(i)).c_str(), &scene,
-			Movable::MF_NONE, nullptr);
-		pe->setLocalTranslation(lightPos);
+			("pef" + std::to_string(i)).c_str(), &scene, nullptr,
+			Movable::MF_NONE, "data/particles/fire.particles");
+		pe->setLocalOrigin(lightPos);
 	}
 #endif
 
 #if 1
 	// horse
-	horse = new ModelNode("data/models/horse/horse.mdl", "horse", &scene,
-		Movable::MF_NONE, nullptr);
+	horse = new ModelNode("horse", &scene, nullptr,
+		Movable::MF_NONE, "data/models/horse/horse.mdl");
 	horse->setLocalTransform(Transform(Vec3(-2, 0, 0), Mat3::getIdentity(),
 		0.7));
 
 	// barrel
-	ModelNode* redBarrel = new ModelNode("data/models/red_barrel/red_barrel.mdl",
-		"red_barrel", &scene, Movable::MF_NONE, nullptr);
+	ModelNode* redBarrel = new ModelNode(
+		"red_barrel", &scene, nullptr, Movable::MF_NONE, 
+		"data/models/red_barrel/red_barrel.mdl", 2);
 	redBarrel->setLocalTransform(Transform(Vec3(+2, 0, 0), Mat3::getIdentity(),
 		0.7));
 #endif
 
-#if 1
+#if 0
 	StaticGeometryNode* sponzaModel = new StaticGeometryNode(
 		//"data/maps/sponza/sponza_no_bmeshes.mdl",
 		//"data/maps/sponza/sponza.mdl",
-		"data/maps/sponza/static_geometry.mdl",
-		"sponza", &scene);
+		"sponza", &scene, "data/maps/sponza/static_geometry.mdl");
 
 	(void)sponzaModel;
 #endif
@@ -351,8 +348,7 @@ void mainLoopExtra()
 	}
 	if(in.getKey(KC_7))
 	{
-		mover = SceneGraphSingleton::get().findSceneNode("sponza").getMovable();
-		std::cout << mover->getWorldTransform() << std::endl;
+		mover = SceneGraphSingleton::get().findSceneNode("red_barrel").getMovable();
 	}
 
 	if(in.getKey(KC_L) == 1)