Browse Source

Fixing bugs on the new scene design. Also instancing now is... nicer

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
cbe796ba3e

+ 5 - 0
include/anki/physics/RigidBody.h

@@ -41,6 +41,11 @@ public:
 	Bool update(SceneNode& node, F32 prevTime, F32 crntTime,
 	Bool update(SceneNode& node, F32 prevTime, F32 crntTime,
 		UpdateType updateType) override;
 		UpdateType updateType) override;
 
 
+	static Type getGlobType()
+	{
+		return RIGID_BODY;
+	}
+
 private:
 private:
 	MotionState motionState;
 	MotionState motionState;
 };
 };

+ 1 - 4
include/anki/renderer/DebugDrawer.h

@@ -6,7 +6,7 @@
 #include "anki/gl/Vao.h"
 #include "anki/gl/Vao.h"
 #include "anki/resource/Resource.h"
 #include "anki/resource/Resource.h"
 #include "anki/collision/CollisionShape.h"
 #include "anki/collision/CollisionShape.h"
-#include "anki/scene/SceneNode.h"
+#include "anki/scene/Forward.h"
 #include "anki/util/Array.h"
 #include "anki/util/Array.h"
 #include <unordered_map>
 #include <unordered_map>
 #include <LinearMath/btIDebugDraw.h>
 #include <LinearMath/btIDebugDraw.h>
@@ -150,9 +150,6 @@ private:
 
 
 // Forward
 // Forward
 class Renderer;
 class Renderer;
-class Camera;
-class Sector;
-class Path;
 
 
 /// This is a drawer for some scene nodes that need debug
 /// This is a drawer for some scene nodes that need debug
 class SceneDebugDrawer
 class SceneDebugDrawer

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

@@ -3,16 +3,16 @@
 
 
 #include "anki/util/StdTypes.h"
 #include "anki/util/StdTypes.h"
 #include "anki/resource/PassLodKey.h"
 #include "anki/resource/PassLodKey.h"
-#include "anki/gl/Drawcall.h"
 
 
 namespace anki {
 namespace anki {
 
 
-class PassLodKey;
 class Renderer;
 class Renderer;
 class FrustumComponent;
 class FrustumComponent;
 class SceneNode;
 class SceneNode;
 class ShaderProgram;
 class ShaderProgram;
 class RenderComponent;
 class RenderComponent;
+class Drawcall;
+class VisibleNode;
 
 
 /// It includes all the functions to render a Renderable
 /// It includes all the functions to render a Renderable
 class RenderableDrawer
 class RenderableDrawer
@@ -35,10 +35,8 @@ public:
 	void render(
 	void render(
 		SceneNode& frsn,
 		SceneNode& frsn,
 		RenderingStage stage, 
 		RenderingStage stage, 
-		Pass pass, 
-		SceneNode& renderableSceneNode,
-		U32* subSpatialIndices,
-		U subSpatialIndicesCount);
+		Pass pass,
+		VisibleNode& visible);
 
 
 private:
 private:
 	Renderer* r;
 	Renderer* r;
@@ -48,8 +46,7 @@ private:
 		const FrustumComponent& fr,
 		const FrustumComponent& fr,
 		const ShaderProgram& prog,
 		const ShaderProgram& prog,
 		RenderComponent& renderable,
 		RenderComponent& renderable,
-		U32* subSpatialIndices,
-		U subSpatialIndicesCount,
+		VisibleNode& visible,
 		F32 flod,
 		F32 flod,
 		Drawcall* dc);
 		Drawcall* dc);
 };
 };

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

@@ -8,6 +8,7 @@
 #include "anki/gl/Gl.h"
 #include "anki/gl/Gl.h"
 #include "anki/util/HighRezTimer.h"
 #include "anki/util/HighRezTimer.h"
 #include "anki/misc/ConfigSet.h"
 #include "anki/misc/ConfigSet.h"
+#include "anki/scene/Forward.h"
 
 
 #include "anki/renderer/Common.h"
 #include "anki/renderer/Common.h"
 #include "anki/renderer/Ms.h"
 #include "anki/renderer/Ms.h"

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

@@ -72,7 +72,7 @@ public:
 		const PassLodKey& key, 
 		const PassLodKey& key, 
 		const Vao*& vao, 
 		const Vao*& vao, 
 		const ShaderProgram*& prog,
 		const ShaderProgram*& prog,
-		const U32* subMeshIndicesArray, U subMeshIndicesCount,
+		const U8* subMeshIndicesArray, U subMeshIndicesCount,
 		Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesCountArray,
 		Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesCountArray,
 		Array<PtrSize, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesOffsetArray, 
 		Array<PtrSize, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesOffsetArray, 
 		U32& drawcallCount) const;
 		U32& drawcallCount) const;

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

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

+ 28 - 0
include/anki/scene/Forward.h

@@ -0,0 +1,28 @@
+#ifndef ANKI_SCENE_FORWARD_H
+#define ANKI_SCENE_FORWARD_H
+
+namespace anki {
+
+// Components
+class FrustumComponent;
+class InstanceComponent;
+class MoveComponent;
+class RenderComponent;
+class SpatialComponent;
+
+// Nodes
+class SceneNode;
+class Light;
+class PointLight;
+class SpotLight;
+class Camera;
+class Path;
+
+// Other
+class SceneGraph;
+class VisibleNode;
+class Sector;
+
+} // end namespace anki
+
+#endif

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

@@ -24,7 +24,7 @@ public:
 
 
 	/// Pass the frustum here so we can avoid the virtuals
 	/// Pass the frustum here so we can avoid the virtuals
 	FrustumComponent(SceneNode* node)
 	FrustumComponent(SceneNode* node)
-		: SceneComponent(this, node)
+		: SceneComponent(FRUSTUM_COMPONENT, node)
 	{
 	{
 		markForUpdate();
 		markForUpdate();
 	}
 	}
@@ -115,6 +115,11 @@ public:
 		visible = nullptr;
 		visible = nullptr;
 	}
 	}
 
 
+	static Type getGlobType()
+	{
+		return FRUSTUM_COMPONENT;
+	}
+
 private:
 private:
 	Mat4 projectionMat = Mat4::getIdentity();
 	Mat4 projectionMat = Mat4::getIdentity();
 	Mat4 viewMat = Mat4::getIdentity();
 	Mat4 viewMat = Mat4::getIdentity();

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

@@ -13,8 +13,13 @@ class InstanceComponent: public SceneComponent
 {
 {
 public:
 public:
 	InstanceComponent(SceneNode* node)
 	InstanceComponent(SceneNode* node)
-		: SceneComponent(this, node)
+		: SceneComponent(INSTANCE_COMPONENT, node)
 	{}
 	{}
+
+	static Type getGlobType()
+	{
+		return INSTANCE_COMPONENT;
+	}
 };
 };
 
 
 /// Instance scene node
 /// Instance scene node

+ 6 - 1
include/anki/scene/Light.h

@@ -15,8 +15,13 @@ class LightComponent: public SceneComponent
 {
 {
 public:
 public:
 	LightComponent(SceneNode* node)
 	LightComponent(SceneNode* node)
-		: SceneComponent(this, node)
+		: SceneComponent(LIGHT_COMPONENT, node)
 	{}
 	{}
+
+	static Type getGlobType()
+	{
+		return LIGHT_COMPONENT;
+	}
 };
 };
 
 
 /// XXX
 /// XXX

+ 8 - 2
include/anki/scene/ModelNode.h

@@ -34,7 +34,7 @@ public:
 	/// Implements RenderComponent::getRenderingData
 	/// Implements RenderComponent::getRenderingData
 	void getRenderingData(
 	void getRenderingData(
 		const PassLodKey& key, 
 		const PassLodKey& key, 
-		const U32* subMeshIndicesArray, U subMeshIndicesCount,
+		const U8* subMeshIndicesArray, U subMeshIndicesCount,
 		const Vao*& vao, const ShaderProgram*& prog,
 		const Vao*& vao, const ShaderProgram*& prog,
 		Drawcall& dracall);
 		Drawcall& dracall);
 
 
@@ -76,6 +76,8 @@ private:
 /// The model scene node
 /// The model scene node
 class ModelNode: public SceneNode, public MoveComponent
 class ModelNode: public SceneNode, public MoveComponent
 {
 {
+	friend class ModelPatchNode;
+
 public:
 public:
 	/// @name Constructors/Destructor
 	/// @name Constructors/Destructor
 	/// @{
 	/// @{
@@ -94,9 +96,13 @@ public:
 	}
 	}
 	/// @}
 	/// @}
 
 
+	/// Override SceneNode::frameUpdate
+	void frameUpdate(F32, F32, SceneNode::UpdateType uptype) override;
+
 private:
 private:
 	ModelResourcePointer model; ///< The resource
 	ModelResourcePointer model; ///< The resource
-	SceneVector<Transform> transforms;
+	SceneVector<Transform> transforms; ///< Cache the transforms of instances
+	Timestamp transformsTimestamp;
 };
 };
 
 
 /// @}
 /// @}

+ 5 - 0
include/anki/scene/MoveComponent.h

@@ -133,6 +133,11 @@ public:
 	}
 	}
 	/// @}
 	/// @}
 
 
+	static Type getGlobType()
+	{
+		return MOVE_COMPONENT;
+	}
+
 private:
 private:
 	SceneNode* node;
 	SceneNode* node;
 
 

+ 6 - 1
include/anki/scene/RenderComponent.h

@@ -188,7 +188,7 @@ public:
 	/// offsets and counts
 	/// offsets and counts
 	virtual void getRenderingData(
 	virtual void getRenderingData(
 		const PassLodKey& key, 
 		const PassLodKey& key, 
-		const U32* subMeshIndicesArray, U subMeshIndicesCount,
+		const U8* subMeshIndicesArray, U subMeshIndicesCount,
 		const Vao*& vao, const ShaderProgram*& prog,
 		const Vao*& vao, const ShaderProgram*& prog,
 		Drawcall& drawcall) = 0;
 		Drawcall& drawcall) = 0;
 
 
@@ -227,6 +227,11 @@ public:
 		}
 		}
 	}
 	}
 
 
+	static Type getGlobType()
+	{
+		return RENDER_COMPONENT;
+	}
+
 protected:
 protected:
 	void init();
 	void init();
 
 

+ 34 - 40
include/anki/scene/SceneComponent.h

@@ -3,35 +3,27 @@
 
 
 #include "anki/scene/Common.h"
 #include "anki/scene/Common.h"
 #include "anki/core/Timestamp.h"
 #include "anki/core/Timestamp.h"
-#include "anki/util/Visitor.h"
 
 
 namespace anki {
 namespace anki {
 
 
-// Forward of all components
-class FrustumComponent;
-class MoveComponent;
-class RenderComponent;
-class SpatialComponent;
-class LightComponent;
-class RigidBody;
-class InstanceComponent;
-
-class SceneComponent;
-
-typedef VisitableCommonBase<
-	SceneComponent, // Base
-	FrustumComponent,
-	MoveComponent,
-	RenderComponent,
-	SpatialComponent,
-	LightComponent,
-	RigidBody,
-	InstanceComponent> SceneComponentVisitable;
-
 /// Scene node component
 /// Scene node component
-class SceneComponent: public SceneComponentVisitable
+class SceneComponent
 {
 {
 public:
 public:
+	// The type of the components
+	enum Type
+	{
+		COMPONENT_NONE,
+		FRUSTUM_COMPONENT,
+		MOVE_COMPONENT,
+		RENDER_COMPONENT,
+		SPATIAL_COMPONENT,
+		LIGHT_COMPONENT,
+		INSTANCE_COMPONENT,
+		RIGID_BODY,
+		LAST_COMPONENT_ID = RIGID_BODY
+	};
+
 	/// The update type
 	/// The update type
 	enum UpdateType
 	enum UpdateType
 	{
 	{
@@ -44,10 +36,18 @@ public:
 	};
 	};
 
 
 	/// Construct the scene component. The x is bogus
 	/// Construct the scene component. The x is bogus
-	template<typename T>
-	SceneComponent(const T* x, SceneNode* node)
+	SceneComponent(Type type_, SceneNode* node)
+		: type(type_)
+	{}
+
+	Type getType() const
+	{
+		return (Type)type;
+	}
+
+	Timestamp getTimestamp() const
 	{
 	{
-		setupVisitable<T>(x);
+		return timestamp;
 	}
 	}
 
 
 	/// Do some reseting before frame starts
 	/// Do some reseting before frame starts
@@ -66,25 +66,19 @@ public:
 	Bool updateReal(SceneNode& node, F32 prevTime, F32 crntTime,
 	Bool updateReal(SceneNode& node, F32 prevTime, F32 crntTime,
 		UpdateType updateType);
 		UpdateType updateType);
 
 
-	Timestamp getTimestamp() const
+	template<typename TComponent>
+	TComponent& downCast()
 	{
 	{
-		return timestamp;
-	}
-
-	I getTypeId() const
-	{
-		return getVisitableTypeId();
-	}
-
-	/// Get the type ID of a derived class
-	template<typename ComponentDerived>
-	static I getTypeIdOf()
-	{
-		return getVariadicTypeId<ComponentDerived>();
+		ANKI_ASSERT(TComponent::getGlobType() == getType());
+		TComponent* out = staticCast<TComponent*>(this);
+		return *out;
 	}
 	}
 
 
 protected:
 protected:
 	Timestamp timestamp; ///< Indicates when an update happened
 	Timestamp timestamp; ///< Indicates when an update happened
+
+private:
+	U8 type;
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

+ 9 - 9
include/anki/scene/SceneNode.h

@@ -98,12 +98,12 @@ public:
 	template<typename Component, typename Func>
 	template<typename Component, typename Func>
 	void iterateComponentsOfType(Func func)
 	void iterateComponentsOfType(Func func)
 	{
 	{
-		I id = SceneComponent::getVariadicTypeId<Component>();
+		SceneComponent::Type type = Component::getGlobType();
 		for(auto comp : components)
 		for(auto comp : components)
 		{
 		{
-			if(comp->getVisitableTypeId() == id)
+			if(comp->getType() == type)
 			{
 			{
-				func(static_cast<Component&>(*comp));
+				func(comp->downCast<Component>());
 			}
 			}
 		}
 		}
 	}
 	}
@@ -112,12 +112,12 @@ public:
 	template<typename Component>
 	template<typename Component>
 	Component* tryGetComponent()
 	Component* tryGetComponent()
 	{
 	{
-		I id = SceneComponent::getVariadicTypeId<Component>();
+		SceneComponent::Type type = Component::getGlobType();
 		for(auto comp : components)
 		for(auto comp : components)
 		{
 		{
-			if(comp->getVisitableTypeId() == id)
+			if(comp->getType() == type)
 			{
 			{
-				return static_cast<Component*>(comp);
+				return &comp->downCast<Component>();
 			}
 			}
 		}
 		}
 		return nullptr;
 		return nullptr;
@@ -127,12 +127,12 @@ public:
 	template<typename Component>
 	template<typename Component>
 	const Component* tryGetComponent() const
 	const Component* tryGetComponent() const
 	{
 	{
-		I id = SceneComponent::getTypeIdOf<Component>();
+		SceneComponent::Type type = Component::getGlobType();
 		for(auto comp : components)
 		for(auto comp : components)
 		{
 		{
-			if(comp->getTypeId() == id)
+			if(comp->getType() == type)
 			{
 			{
-				return static_cast<Component*>(comp);
+				return &comp->downCast<Component>();
 			}
 			}
 		}
 		}
 		return nullptr;
 		return nullptr;

+ 5 - 0
include/anki/scene/SpatialComponent.h

@@ -86,6 +86,11 @@ public:
 	void reset() override;
 	void reset() override;
 	/// @}
 	/// @}
 
 
+	static Type getGlobType()
+	{
+		return SPATIAL_COMPONENT;
+	}
+
 private:
 private:
 	Aabb aabb; ///< A faster shape
 	Aabb aabb; ///< A faster shape
 };
 };

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

@@ -64,7 +64,7 @@ public:
 	/// Implements RenderComponent::getRenderingData
 	/// Implements RenderComponent::getRenderingData
 	void getRenderingData(
 	void getRenderingData(
 		const PassLodKey& key, 
 		const PassLodKey& key, 
-		const U32* subMeshIndicesArray, U subMeshIndicesCount,
+		const U8* subMeshIndicesArray, U subMeshIndicesCount,
 		const Vao*& vao, const ShaderProgram*& prog,
 		const Vao*& vao, const ShaderProgram*& prog,
 		Drawcall& drawcall);
 		Drawcall& drawcall);
 
 

+ 31 - 5
include/anki/scene/Visibility.h

@@ -33,20 +33,46 @@ enum VisibleBy
 };
 };
 
 
 /// Visible node pointer with some more info
 /// Visible node pointer with some more info
+/// @note Keep this structore as small as possible
 struct VisibleNode
 struct VisibleNode
 {
 {
 	SceneNode* node;
 	SceneNode* node;
-	/// An array of the visible spatials.
-	Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES> spatialIndices;
-	U32 spatialsCount;
+	/// An array of the visible spatials
+	U8* spatialIndices;
+	U8 spatialsCount;
 
 
 	VisibleNode()
 	VisibleNode()
-		: node(nullptr), spatialsCount(0)
+		: node(nullptr), spatialIndices(nullptr), spatialsCount(0)
 	{}
 	{}
 
 
 	VisibleNode(const VisibleNode& other)
 	VisibleNode(const VisibleNode& other)
 	{
 	{
-		memcpy(this, &other, sizeof(VisibleNode));
+		operator=(other);
+	}
+
+	VisibleNode(VisibleNode&& other)
+	{
+		node = other.node;
+		spatialIndices = other.spatialIndices;
+		spatialsCount = other.spatialsCount;
+
+		other.node = nullptr;
+		other.spatialIndices = nullptr;
+		other.spatialsCount = 0;
+	}
+
+	VisibleNode& operator=(const VisibleNode& other)
+	{
+		node = other.node;
+		spatialIndices = other.spatialIndices;
+		spatialsCount = other.spatialsCount;
+		return *this;
+	}
+
+	U8 getSpatialIndex(U i)
+	{
+		ANKI_ASSERT(spatialsCount != 0 && i < spatialsCount);
+		return spatialIndices[i];
 	}
 	}
 };
 };
 
 

+ 1 - 1
src/physics/RigidBody.cpp

@@ -10,7 +10,7 @@ RigidBody::RigidBody(PhysicsWorld* world, const Initializer& init)
 	:	PhysicsObject(world),
 	:	PhysicsObject(world),
 		btRigidBody(btRigidBody::btRigidBodyConstructionInfo(0.0, nullptr, 
 		btRigidBody(btRigidBody::btRigidBodyConstructionInfo(0.0, nullptr, 
 			nullptr, btVector3(0.0, 0.0, 0.0))), // dummy init
 			nullptr, btVector3(0.0, 0.0, 0.0))), // dummy init
-		SceneComponent(this, init.node)
+		SceneComponent(RIGID_BODY, init.node)
 {
 {
 	ANKI_ASSERT(init.shape != nullptr 
 	ANKI_ASSERT(init.shape != nullptr 
 		&& init.shape->getShapeType() != INVALID_SHAPE_PROXYTYPE);
 		&& init.shape->getShapeType() != INVALID_SHAPE_PROXYTYPE);

+ 1 - 2
src/renderer/Bs.cpp

@@ -30,8 +30,7 @@ void Bs::run()
 	for(auto it : vi.renderables)
 	for(auto it : vi.renderables)
 	{
 	{
 		drawer.render(scene.getActiveCamera(), RenderableDrawer::RS_BLEND,
 		drawer.render(scene.getActiveCamera(), RenderableDrawer::RS_BLEND,
-			COLOR_PASS, *it.node, &it.spatialIndices[0], 
-			it.spatialsCount);
+			COLOR_PASS, it);
 	}
 	}
 
 
 	GlStateSingleton::get().setDepthMaskEnabled(true);
 	GlStateSingleton::get().setDepthMaskEnabled(true);

+ 5 - 0
src/renderer/DebugDrawer.cpp

@@ -502,6 +502,11 @@ void SceneDebugDrawer::draw(FrustumComponent& fr) const
 //==============================================================================
 //==============================================================================
 void SceneDebugDrawer::draw(SpatialComponent& x) const
 void SceneDebugDrawer::draw(SpatialComponent& x) const
 {
 {
+	if(!x.bitsEnabled(SpatialComponent::SF_VISIBLE_CAMERA))
+	{
+		return;
+	}
+
 	dbg->setColor(Vec3(1.0, 0.0, 1.0));
 	dbg->setColor(Vec3(1.0, 0.0, 1.0));
 	CollisionDebugDrawer coldraw(dbg);
 	CollisionDebugDrawer coldraw(dbg);
 	x.getAabb().accept(coldraw);
 	x.getAabb().accept(coldraw);

+ 14 - 23
src/renderer/Drawer.cpp

@@ -3,8 +3,7 @@
 #include "anki/scene/FrustumComponent.h"
 #include "anki/scene/FrustumComponent.h"
 #include "anki/resource/Material.h"
 #include "anki/resource/Material.h"
 #include "anki/scene/RenderComponent.h"
 #include "anki/scene/RenderComponent.h"
-#include "anki/scene/Camera.h"
-#include "anki/scene/ModelNode.h"
+#include "anki/scene/Visibility.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/core/Counters.h"
 #include "anki/core/Counters.h"
@@ -44,8 +43,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 	Drawcall* dc = nullptr;
 	Drawcall* dc = nullptr;
 
 
 	// Used for 
 	// Used for 
-	const U32* spatialIndices = nullptr;
-	U32 spatialsCount = 0;
+	VisibleNode* visibleNode;
 
 
 	/// Set a uniform in a client block
 	/// Set a uniform in a client block
 	template<typename T>
 	template<typename T>
@@ -84,7 +82,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 					Transform worldTrf;
 					Transform worldTrf;
 
 
 					renderable->getRenderWorldTransform(
 					renderable->getRenderWorldTransform(
-						spatialIndices[i], worldTrf);
+						visibleNode->getSpatialIndex(i), worldTrf);
 
 
 					mvp[i] = vp * Mat4(worldTrf);
 					mvp[i] = vp * Mat4(worldTrf);
 				}
 				}
@@ -107,7 +105,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 					Transform worldTrf;
 					Transform worldTrf;
 
 
 					renderable->getRenderWorldTransform(
 					renderable->getRenderWorldTransform(
-						spatialIndices[i], worldTrf);
+						visibleNode->getSpatialIndex(i), worldTrf);
 
 
 					mv[i] = v * Mat4(worldTrf);
 					mv[i] = v * Mat4(worldTrf);
 				}
 				}
@@ -128,7 +126,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 					Transform worldTrf;
 					Transform worldTrf;
 
 
 					renderable->getRenderWorldTransform(
 					renderable->getRenderWorldTransform(
-						spatialIndices[i], worldTrf);
+						visibleNode->getSpatialIndex(i), worldTrf);
 
 
 					Mat4 mv = v * Mat4(worldTrf);
 					Mat4 mv = v * Mat4(worldTrf);
 					normMats[i] = mv.getRotationPart();
 					normMats[i] = mv.getRotationPart();
@@ -243,7 +241,7 @@ void SetupRenderableVariableVisitor::uniSet<TextureResourcePointer>(
 void RenderableDrawer::setupShaderProg(const PassLodKey& key_,
 void RenderableDrawer::setupShaderProg(const PassLodKey& key_,
 	const FrustumComponent& fr, const ShaderProgram &prog,
 	const FrustumComponent& fr, const ShaderProgram &prog,
 	RenderComponent& renderable, 
 	RenderComponent& renderable, 
-	U32* spatialIndices, U spatialsCount,
+	VisibleNode& visibleNode,
 	F32 flod,
 	F32 flod,
 	Drawcall* dc)
 	Drawcall* dc)
 {
 {
@@ -254,8 +252,7 @@ void RenderableDrawer::setupShaderProg(const PassLodKey& key_,
 	vis.fr = &fr;
 	vis.fr = &fr;
 	vis.renderable = &renderable;
 	vis.renderable = &renderable;
 	vis.r = r;
 	vis.r = r;
-	vis.spatialIndices = spatialIndices;
-	vis.spatialsCount = spatialsCount;
+	vis.visibleNode = &visibleNode;
 	vis.flod = flod;
 	vis.flod = flod;
 	vis.dc = dc;
 	vis.dc = dc;
 
 
@@ -294,22 +291,18 @@ void RenderableDrawer::setupShaderProg(const PassLodKey& key_,
 
 
 //==============================================================================
 //==============================================================================
 void RenderableDrawer::render(SceneNode& frsn, RenderingStage stage,
 void RenderableDrawer::render(SceneNode& frsn, RenderingStage stage,
-	Pass pass, SceneNode& rsn, U32* spatialIndices,
-	U spatialsCount)
+	Pass pass, VisibleNode& visibleNode)
 {
 {
-	// Preconditions
-	ANKI_ASSERT(spatialIndices);
-	ANKI_ASSERT(spatialsCount > 0);
-
 	// Get components
 	// Get components
 	FrustumComponent& fr = frsn.getComponent<FrustumComponent>();
 	FrustumComponent& fr = frsn.getComponent<FrustumComponent>();
-	RenderComponent& renderable = rsn.getComponent<RenderComponent>();
+	RenderComponent& renderable = 
+		visibleNode.node->getComponent<RenderComponent>();
 
 
 	// Calculate the key
 	// Calculate the key
 	Vec3 camPos = fr.getFrustumOrigin();
 	Vec3 camPos = fr.getFrustumOrigin();
 
 
-	F32 dist = (rsn.getComponent<SpatialComponent>().getSpatialOrigin() 
-		- camPos).getLength();
+	F32 dist = (visibleNode.node->getComponent<SpatialComponent>().
+		getSpatialOrigin() - camPos).getLength();
 	F32 lod = r->calculateLod(dist);
 	F32 lod = r->calculateLod(dist);
 
 
 	PassLodKey key(pass, lod);
 	PassLodKey key(pass, lod);
@@ -350,13 +343,12 @@ void RenderableDrawer::render(SceneNode& frsn, RenderingStage stage,
 	Drawcall dc;
 	Drawcall dc;
 
 
 	renderable.getRenderingData(
 	renderable.getRenderingData(
-		key, spatialIndices, spatialsCount, // in
+		key, visibleNode.spatialIndices, visibleNode.spatialsCount, // in
 		vao, prog, dc); //out
 		vao, prog, dc); //out
 
 
 	// Setup shader
 	// Setup shader
 	setupShaderProg(
 	setupShaderProg(
-		key, fr, *prog, renderable, spatialIndices, spatialsCount,
-		lod, &dc);
+		key, fr, *prog, renderable, visibleNode, lod, &dc);
 
 
 	// Render
 	// Render
 	ANKI_ASSERT(vao->getAttachmentsCount() > 1);
 	ANKI_ASSERT(vao->getAttachmentsCount() > 1);
@@ -369,7 +361,6 @@ void RenderableDrawer::render(SceneNode& frsn, RenderingStage stage,
 		glPatchParameteri(GL_PATCH_VERTICES, 3);
 		glPatchParameteri(GL_PATCH_VERTICES, 3);
 		dc.primitiveType = GL_PATCHES;
 		dc.primitiveType = GL_PATCHES;
 	}
 	}
-	else
 #endif
 #endif
 
 
 	// Start drawcall
 	// Start drawcall

+ 1 - 1
src/renderer/Ez.cpp

@@ -27,7 +27,7 @@ void Ez::run()
 	for(auto it : vi.renderables)
 	for(auto it : vi.renderables)
 	{
 	{
 		r->getSceneDrawer().render(cam, RenderableDrawer::RS_MATERIAL,
 		r->getSceneDrawer().render(cam, RenderableDrawer::RS_MATERIAL,
-			DEPTH_PASS, *it.node, &it.spatialIndices[0], it.spatialsCount);
+			DEPTH_PASS, it);
 		++count;
 		++count;
 	}
 	}
 }
 }

+ 1 - 2
src/renderer/Ms.cpp

@@ -116,8 +116,7 @@ void Ms::run()
 	for(auto it : vi.renderables)
 	for(auto it : vi.renderables)
 	{
 	{
 		r->getSceneDrawer().render(r->getSceneGraph().getActiveCamera(),
 		r->getSceneDrawer().render(r->getSceneGraph().getActiveCamera(),
-			RenderableDrawer::RS_MATERIAL, COLOR_PASS, *it.node, 
-			&it.spatialIndices[0], it.spatialsCount);
+			RenderableDrawer::RS_MATERIAL, COLOR_PASS, it);
 	}
 	}
 
 
 	// If there is multisampling then resolve to singlesampled
 	// If there is multisampling then resolve to singlesampled

+ 1 - 2
src/renderer/Sm.cpp

@@ -208,8 +208,7 @@ Sm::Shadowmap* Sm::doLight(Light& light)
 	for(auto it : vi.renderables)
 	for(auto it : vi.renderables)
 	{
 	{
 		r->getSceneDrawer().render(light, RenderableDrawer::RS_MATERIAL,
 		r->getSceneDrawer().render(light, RenderableDrawer::RS_MATERIAL,
-			DEPTH_PASS, *it.node, &it.spatialIndices[0], 
-			it.spatialsCount);
+			DEPTH_PASS, it);
 	}
 	}
 
 
 	ANKI_COUNTER_INC(C_RENDERER_SHADOW_PASSES, (U64)1);
 	ANKI_COUNTER_INC(C_RENDERER_SHADOW_PASSES, (U64)1);

+ 1 - 1
src/resource/Model.cpp

@@ -114,7 +114,7 @@ void ModelPatchBase::getRenderingData(const PassLodKey& key, const Vao*& vao,
 //==============================================================================
 //==============================================================================
 void ModelPatchBase::getRenderingDataSub(const PassLodKey& key,
 void ModelPatchBase::getRenderingDataSub(const PassLodKey& key,
 	const Vao*& vao, const ShaderProgram*& prog, 
 	const Vao*& vao, const ShaderProgram*& prog, 
-	const U32* subMeshIndexArray, U subMeshIndexCount,
+	const U8* subMeshIndexArray, U subMeshIndexCount,
 	Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesCountArray,
 	Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesCountArray,
 	Array<PtrSize, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesOffsetArray, 
 	Array<PtrSize, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesOffsetArray, 
 	U32& drawcallCount) const
 	U32& drawcallCount) const

+ 6 - 8
src/scene/Light.cpp

@@ -50,8 +50,10 @@ void Light::moveUpdate(MoveComponent& move)
 	iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& fr)
 	iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& fr)
 	{
 	{
 		fr.setProjectionMatrix(fr.getFrustum().calculateProjectionMatrix());
 		fr.setProjectionMatrix(fr.getFrustum().calculateProjectionMatrix());
+		fr.setViewMatrix(Mat4(move.getWorldTransform().getInverse()));
 		fr.setViewProjectionMatrix(
 		fr.setViewProjectionMatrix(
 			fr.getProjectionMatrix() * fr.getViewMatrix());
 			fr.getProjectionMatrix() * fr.getViewMatrix());
+
 		fr.getFrustum().setTransform(move.getWorldTransform());
 		fr.getFrustum().setTransform(move.getWorldTransform());
 
 
 		fr.markForUpdate();
 		fr.markForUpdate();
@@ -75,9 +77,9 @@ PointLight::PointLight(const char* name, SceneGraph* scene)
 void PointLight::componentUpdated(SceneComponent& comp, 
 void PointLight::componentUpdated(SceneComponent& comp, 
 	SceneComponent::UpdateType)
 	SceneComponent::UpdateType)
 {
 {
-	if(comp.getTypeId() == SceneComponent::getTypeIdOf<MoveComponent>())
+	if(comp.getType() == MoveComponent::getGlobType())
 	{
 	{
-		MoveComponent& move = static_cast<MoveComponent&>(comp);
+		MoveComponent& move = comp.downCast<MoveComponent>();
 		sphereW.setCenter(move.getWorldTransform().getOrigin());
 		sphereW.setCenter(move.getWorldTransform().getOrigin());
 		moveUpdate(move);
 		moveUpdate(move);
 	}
 	}
@@ -96,22 +98,18 @@ SpotLight::SpotLight(const char* name, SceneGraph* scene)
 	addComponent(static_cast<FrustumComponent*>(this));
 	addComponent(static_cast<FrustumComponent*>(this));
 
 
 	const F32 ang = toRad(45.0);
 	const F32 ang = toRad(45.0);
-	setOuterAngle(ang / 2.0);
 	const F32 dist = 1.0;
 	const F32 dist = 1.0;
 
 
-	// Fix frustum
-	//
 	frustum.setAll(ang, ang, 0.1, dist);
 	frustum.setAll(ang, ang, 0.1, dist);
-	frustumUpdate();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void SpotLight::componentUpdated(SceneComponent& comp,
 void SpotLight::componentUpdated(SceneComponent& comp,
 	SceneComponent::UpdateType)
 	SceneComponent::UpdateType)
 {
 {
-	if(comp.getTypeId() == SceneComponent::getTypeIdOf<MoveComponent>())
+	if(comp.getType() == MoveComponent::getGlobType())
 	{
 	{
-		MoveComponent& move = static_cast<MoveComponent&>(comp);
+		MoveComponent& move = comp.downCast<MoveComponent>();
 		frustum.setTransform(move.getWorldTransform());
 		frustum.setTransform(move.getWorldTransform());
 		moveUpdate(move);
 		moveUpdate(move);
 	}
 	}

+ 168 - 20
src/scene/ModelNode.cpp

@@ -9,6 +9,33 @@
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+// ModelPatchNodeSpatial                                                       =
+//==============================================================================
+
+/// A class that holds spatial information for the instances of ModelPatchNode
+class ModelPatchNodeSpatial: public SpatialComponent
+{
+public:
+	Obb obb;
+
+	ModelPatchNodeSpatial(SceneNode* node)
+		: SpatialComponent(node)
+	{}
+
+	/// Implement SpatialComponent::getSpatialCollisionShape
+	const CollisionShape& getSpatialCollisionShape()
+	{
+		return obb;
+	}
+
+	/// Implement SpatialComponent::getSpatialOrigin
+	Vec3 getSpatialOrigin()
+	{
+		return obb.getCenter();
+	}
+};
+
 //==============================================================================
 //==============================================================================
 // ModelPatchNode                                                              =
 // ModelPatchNode                                                              =
 //==============================================================================
 //==============================================================================
@@ -35,7 +62,7 @@ ModelPatchNode::~ModelPatchNode()
 //==============================================================================
 //==============================================================================
 void ModelPatchNode::getRenderingData(
 void ModelPatchNode::getRenderingData(
 	const PassLodKey& key, 
 	const PassLodKey& key, 
-	const U32* subMeshIndicesArray, U subMeshIndicesCount,
+	const U8* subMeshIndicesArray, U subMeshIndicesCount,
 	const Vao*& vao, const ShaderProgram*& prog,
 	const Vao*& vao, const ShaderProgram*& prog,
 	Drawcall& dc)
 	Drawcall& dc)
 {
 {
@@ -48,7 +75,7 @@ void ModelPatchNode::getRenderingData(
 		++spatialsCount;
 		++spatialsCount;
 	});
 	});
 
 
-	dc.instancesCount = spatialsCount;
+	dc.instancesCount = std::min(spatialsCount, subMeshIndicesCount);
 
 
 	modelPatch->getRenderingDataSub(key, vao, prog, 
 	modelPatch->getRenderingDataSub(key, vao, prog, 
 		subMeshIndicesArray, subMeshIndicesCount, 
 		subMeshIndicesArray, subMeshIndicesCount, 
@@ -70,9 +97,13 @@ void ModelPatchNode::getRenderWorldTransform(U index, Transform& trf)
 	else
 	else
 	{
 	{
 		// Instancing
 		// Instancing
+		SceneNode* parent = staticCast<SceneNode*>(getParent());
+		ANKI_ASSERT(parent);
+		ModelNode* mnode = staticCast<ModelNode*>(parent);
 
 
-		// XXX
-		ANKI_ASSERT(0 && "todo");
+		--index;
+		ANKI_ASSERT(index < mnode->transforms.size());
+		trf = mnode->transforms[index];
 	}
 	}
 }
 }
 
 
@@ -87,34 +118,101 @@ void ModelPatchNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
 	SceneNode* parent = staticCast<SceneNode*>(getParent());
 	SceneNode* parent = staticCast<SceneNode*>(getParent());
 	ANKI_ASSERT(parent);
 	ANKI_ASSERT(parent);
 
 
-	// Count the instances of the parent
-	U instancesCount = 0;
+	// Update first OBB
+	const MoveComponent& parentMove = parent->getComponent<MoveComponent>();
+	if(parentMove.getTimestamp() == getGlobTimestamp())
+	{
+		obb = modelPatch->getBoundingShape().getTransformed(
+			parentMove.getWorldTransform());
+
+		SpatialComponent::markForUpdate();
+	}
+
+	// Get the move components of the instances of the parent
+	SceneFrameVector<MoveComponent*> instanceMoves(getSceneFrameAllocator());
+	Timestamp instancesTimestamp = 0;
 	parent->visitThisAndChildren([&](SceneObject& so)
 	parent->visitThisAndChildren([&](SceneObject& so)
 	{
 	{
 		SceneNode* sn = staticCast<SceneNode*>(&so);
 		SceneNode* sn = staticCast<SceneNode*>(&so);
 		
 		
 		if(sn->tryGetComponent<InstanceComponent>())
 		if(sn->tryGetComponent<InstanceComponent>())
 		{
 		{
-			++instancesCount;
+			MoveComponent& move = sn->getComponent<MoveComponent>();
+
+			instanceMoves.push_back(&move);
+
+			instancesTimestamp = 
+				std::max(instancesTimestamp, move.getTimestamp());
 		}
 		}
 	});
 	});
 
 
-	if(instancesCount == 0)
+	// Instancing?
+	if(instanceMoves.size() != 0)
 	{
 	{
-		// No instances
-		const MoveComponent& parentMove = parent->getComponent<MoveComponent>();
+		Bool needsUpdate = false;
+
+		// Get the spatials and their update time
+		SceneFrameVector<ModelPatchNodeSpatial*> 
+			spatials(getSceneFrameAllocator());
+
+		Timestamp spatialsTimestamp = 0;
+		U count = 0;
 
 
-		if(parentMove.getTimestamp() == getGlobTimestamp())
+		iterateComponentsOfType<SpatialComponent>([&](SpatialComponent& sp)
 		{
 		{
-			obb = modelPatch->getBoundingShape().getTransformed(
-				parentMove.getWorldTransform());
+			// Skip the first
+			if(count != 0)	
+			{
+				ModelPatchNodeSpatial* msp = 
+					staticCast<ModelPatchNodeSpatial*>(&sp);
+		
+				spatialsTimestamp = 
+					std::max(spatialsTimestamp, msp->getTimestamp());
+
+				spatials.push_back(msp);
+			}
+			++count;
+		});
+
+		// If we need to add spatials
+		if(spatials.size() < instanceMoves.size())
+		{
+			needsUpdate = true;
+			U diff = instanceMoves.size() - spatials.size();
+
+			while(diff-- != 0)
+			{
+				ModelPatchNodeSpatial* newSpatial = getSceneAllocator().
+					newInstance<ModelPatchNodeSpatial>(this);
+
+				addComponent(newSpatial);
+
+				spatials.push_back(newSpatial);
+			}
 		}
 		}
-	}
-	else
-	{
-		// XXX
-		ANKI_ASSERT(0 && "todo");
-	}
+		// If we need to remove spatials
+		else if(spatials.size() > instanceMoves.size())
+		{
+			needsUpdate = true;
+
+			// XXX
+			ANKI_ASSERT(0 && "todo");
+		}
+		
+		// Now update all spatials if needed
+		if(needsUpdate || spatialsTimestamp < instancesTimestamp)
+		{
+			for(U i = 0; i < spatials.size(); i++)
+			{
+				ModelPatchNodeSpatial* sp = spatials[i];
+
+				sp->obb = modelPatch->getBoundingShape().getTransformed(
+					instanceMoves[i]->getWorldTransform());
+
+				sp->markForUpdate();
+			}
+		}
+	} // end instancing
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -127,7 +225,8 @@ ModelNode::ModelNode(
 	const char* modelFname)
 	const char* modelFname)
 	: 	SceneNode(name, scene),
 	: 	SceneNode(name, scene),
 		MoveComponent(this),
 		MoveComponent(this),
-		transforms(getSceneAllocator())
+		transforms(getSceneAllocator()),
+		transformsTimestamp(0)
 {
 {
 	addComponent(static_cast<MoveComponent*>(this));
 	addComponent(static_cast<MoveComponent*>(this));
 
 
@@ -168,4 +267,53 @@ ModelNode::~ModelNode()
 	}
 	}
 }
 }
 
 
+//==============================================================================
+void ModelNode::frameUpdate(F32, F32, SceneNode::UpdateType uptype)
+{
+	if(uptype != SceneNode::ASYNC_UPDATE)
+	{
+		return;
+	}
+
+	// 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>())
+		{
+			MoveComponent& move = sn->getComponent<MoveComponent>();
+
+			instanceMoves.push_back(&move);
+
+			instancesTimestamp = 
+				std::max(instancesTimestamp, move.getTimestamp());
+		}
+	});
+
+	// If instancing
+	if(instanceMoves.size() != 0)
+	{
+		Bool transformsNeedUpdate = false;
+
+		if(instanceMoves.size() != transforms.size())
+		{
+			transformsNeedUpdate = true;
+			transforms.resize(instanceMoves.size());
+		}
+
+		if(transformsNeedUpdate || transformsTimestamp < instancesTimestamp)
+		{
+			transformsTimestamp = instancesTimestamp;
+
+			for(U i = 0; i < instanceMoves.size(); i++)
+			{
+				transforms[i] = instanceMoves[i]->getWorldTransform();
+			}
+		}
+	}
+}
+
 } // end namespace anki
 } // end namespace anki

+ 3 - 3
src/scene/MoveComponent.cpp

@@ -5,7 +5,7 @@ namespace anki {
 
 
 //==============================================================================
 //==============================================================================
 MoveComponent::MoveComponent(SceneNode* node_, U32 flags)
 MoveComponent::MoveComponent(SceneNode* node_, U32 flags)
-	:	SceneComponent(this, node_),
+	:	SceneComponent(MOVE_COMPONENT, node_),
 		Base(nullptr, node_->getSceneAllocator()),
 		Base(nullptr, node_->getSceneAllocator()),
 		Bitset<U8>(flags),
 		Bitset<U8>(flags),
 		node(node_)
 		node(node_)
@@ -20,7 +20,7 @@ MoveComponent::~MoveComponent()
 //==============================================================================
 //==============================================================================
 Bool MoveComponent::update(SceneNode&, F32, F32, UpdateType uptype)
 Bool MoveComponent::update(SceneNode&, F32, F32, UpdateType uptype)
 {
 {
-	if(uptype == SYNC_UPDATE && getParent() == nullptr)
+	if(uptype == ASYNC_UPDATE && getParent() == nullptr)
 	{
 	{
 		// Call this only on roots
 		// Call this only on roots
 		updateWorldTransform();
 		updateWorldTransform();
@@ -58,7 +58,7 @@ void MoveComponent::updateWorldTransform()
 			wTrf = lTrf;
 			wTrf = lTrf;
 		}
 		}
 
 
-		node->componentUpdated(*this, SYNC_UPDATE);
+		node->componentUpdated(*this, ASYNC_UPDATE);
 		timestamp = getGlobTimestamp();
 		timestamp = getGlobTimestamp();
 
 
 		// Now it's a good time to cleanse parent
 		// Now it's a good time to cleanse parent

+ 1 - 1
src/scene/RenderComponent.cpp

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

+ 16 - 6
src/scene/SceneGraph.cpp

@@ -1,6 +1,7 @@
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/Camera.h"
 #include "anki/scene/Camera.h"
 #include "anki/scene/ModelNode.h"
 #include "anki/scene/ModelNode.h"
+#include "anki/scene/InstanceNode.h"
 #include "anki/util/Exception.h"
 #include "anki/util/Exception.h"
 #include "anki/core/Threadpool.h"
 #include "anki/core/Threadpool.h"
 #include "anki/core/Counters.h"
 #include "anki/core/Counters.h"
@@ -44,17 +45,22 @@ struct UpdateSceneNodesJob: ThreadpoolTask
 		barrier->wait();
 		barrier->wait();
 
 
 		// Update the rest of the components
 		// Update the rest of the components
-		auto moveComponentTypeId = SceneComponent::getTypeIdOf<MoveComponent>();
+		auto moveComponentTypeId = MoveComponent::getGlobType();
 		scene->iterateSceneNodes(start, end, [&](SceneNode& node)
 		scene->iterateSceneNodes(start, end, [&](SceneNode& node)
 		{
 		{
+			// Components update
 			node.iterateComponents([&](SceneComponent& comp)
 			node.iterateComponents([&](SceneComponent& comp)
 			{
 			{
-				if(comp.getTypeId() != moveComponentTypeId)
+				if(comp.getType() != moveComponentTypeId)
 				{
 				{
 					comp.updateReal(node, prevUpdateTime, crntTime, 
 					comp.updateReal(node, prevUpdateTime, crntTime, 
 						SceneComponent::ASYNC_UPDATE);
 						SceneComponent::ASYNC_UPDATE);
 				}
 				}
 			});
 			});
+
+			// Frame update
+			node.frameUpdate(prevUpdateTime, crntTime, 
+				SceneNode::ASYNC_UPDATE);
 		});
 		});
 	}
 	}
 };
 };
@@ -290,13 +296,17 @@ void SceneGraph::load(const char* filename)
 				if(i == 0)
 				if(i == 0)
 				{
 				{
 					node->setLocalTransform(Transform(el.getMat4()));
 					node->setLocalTransform(Transform(el.getMat4()));
-					//node->setInstanceLocalTransform(
-					//	i, Transform(el.getMat4()));
 				}
 				}
 				else
 				else
 				{
 				{
-					// TODO
-					//node->setInstanceLocalTransform(i, Transform(el.getMat4()));
+					InstanceNode* instance;
+					std::string instName = name + "_inst" 
+						+ std::to_string(i - 1);
+					newSceneNode(instance, instName.c_str());
+
+					instance->setLocalTransform(Transform(el.getMat4()));
+
+					node->SceneNode::addChild(instance);
 				}
 				}
 
 
 				// Advance
 				// Advance

+ 1 - 2
src/scene/SpatialComponent.cpp

@@ -5,8 +5,7 @@ namespace anki {
 
 
 //==============================================================================
 //==============================================================================
 SpatialComponent::SpatialComponent(SceneNode* node, U32 flags)
 SpatialComponent::SpatialComponent(SceneNode* node, U32 flags)
-	:	SceneComponent(this, node),
-		Bitset<U8>(flags)
+	: SceneComponent(SPATIAL_COMPONENT, node), Bitset<U8>(flags)
 {
 {
 	markForUpdate();
 	markForUpdate();
 }
 }

+ 1 - 1
src/scene/StaticGeometryNode.cpp

@@ -73,7 +73,7 @@ StaticGeometryPatchNode::~StaticGeometryPatchNode()
 //==============================================================================
 //==============================================================================
 void StaticGeometryPatchNode::getRenderingData(
 void StaticGeometryPatchNode::getRenderingData(
 	const PassLodKey& key, 
 	const PassLodKey& key, 
-	const U32* subMeshIndicesArray, U subMeshIndicesCount,
+	const U8* subMeshIndicesArray, U subMeshIndicesCount,
 	const Vao*& vao, const ShaderProgram*& prog,
 	const Vao*& vao, const ShaderProgram*& prog,
 	Drawcall& dc)
 	Drawcall& dc)
 {
 {

+ 8 - 5
src/scene/Visibility.cpp

@@ -63,11 +63,11 @@ struct VisibilityTestTask: ThreadpoolTask
 			struct SpatialTemp
 			struct SpatialTemp
 			{
 			{
 				SpatialComponent* sp;
 				SpatialComponent* sp;
-				U32 idx;
+				U8 idx;
 			};
 			};
 			Array<SpatialTemp, ANKI_MAX_MULTIDRAW_PRIMITIVES> sps;
 			Array<SpatialTemp, ANKI_MAX_MULTIDRAW_PRIMITIVES> sps;
 
 
-			U32 i = 0;
+			U spIdx = 0;
 			U count = 0;
 			U count = 0;
 			node.iterateComponentsOfType<SpatialComponent>(
 			node.iterateComponentsOfType<SpatialComponent>(
 				[&](SpatialComponent& sp)
 				[&](SpatialComponent& sp)
@@ -75,14 +75,15 @@ struct VisibilityTestTask: ThreadpoolTask
 				if(testedFr.insideFrustum(sp))
 				if(testedFr.insideFrustum(sp))
 				{
 				{
 					// Inside
 					// Inside
-					sps[count++] = SpatialTemp{&sp, i};
+					ANKI_ASSERT(spIdx < MAX_U8);
+					sps[count++] = SpatialTemp{&sp, (U8)spIdx};
 
 
 					sp.enableBits(isLight 
 					sp.enableBits(isLight 
 						? SpatialComponent::SF_VISIBLE_LIGHT 
 						? SpatialComponent::SF_VISIBLE_LIGHT 
 						: SpatialComponent::SF_VISIBLE_CAMERA);
 						: SpatialComponent::SF_VISIBLE_CAMERA);
 				}
 				}
 
 
-				++i;
+				++spIdx;
 			});
 			});
 
 
 			if(count == 0)
 			if(count == 0)
@@ -105,8 +106,10 @@ struct VisibilityTestTask: ThreadpoolTask
 			});
 			});
 
 
 			// Update the visibleNode
 			// Update the visibleNode
+			ANKI_ASSERT(count < MAX_U8);
 			visibleNode.spatialsCount = count;
 			visibleNode.spatialsCount = count;
-			for(i = 0; i < count; i++)
+			visibleNode.spatialIndices = frameAlloc.newArray<U8>(count);
+			for(U i = 0; i < count; i++)
 			{
 			{
 				visibleNode.spatialIndices[i] = sps[i].idx;
 				visibleNode.spatialIndices[i] = sps[i].idx;
 			}
 			}