Forráskód Böngészése

Interleaved meshes are implemented. It compiles!

Panagiotis Christopoulos Charitos 13 éve
szülő
commit
31b571da0a

+ 3 - 1
include/anki/gl/BufferObject.h

@@ -30,7 +30,9 @@ public:
 #if ANKI_DEBUG
 #if ANKI_DEBUG
 			, mapped(b.mapped)
 			, mapped(b.mapped)
 #endif
 #endif
-	{}
+	{
+		b.glId = 0;
+	}
 
 
 	/// @see create
 	/// @see create
 	BufferObject(GLenum target, U32 sizeInBytes,
 	BufferObject(GLenum target, U32 sizeInBytes,

+ 8 - 0
include/anki/gl/ContextNonSharable.h

@@ -40,6 +40,14 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
+	ContextNonSharable& operator=(ContextNonSharable&& b)
+	{
+#if ANKI_DEBUG
+		creationThreadId = b.creationThreadId;
+#endif
+		return *this;
+	}
+
 	void crateNonSharable()
 	void crateNonSharable()
 	{
 	{
 #if ANKI_DEBUG
 #if ANKI_DEBUG

+ 18 - 3
include/anki/gl/Vao.h

@@ -26,9 +26,9 @@ public:
 
 
 	/// Move
 	/// Move
 	Vao(Vao&& b)
 	Vao(Vao&& b)
-		: ContextNonSharable(std::move(b)), glId(b.glId), 
-			attachments(b.attachments)
-	{}
+	{
+		*this = std::move(b);
+	}
 
 
 	/// Destroy VAO from the OpenGL context
 	/// Destroy VAO from the OpenGL context
 	~Vao();
 	~Vao();
@@ -44,6 +44,21 @@ public:
 	}
 	}
 	/// @}
 	/// @}
 
 
+	/// @name Operators
+	/// @{
+
+	/// Move
+	Vao& operator=(Vao&& b)
+	{
+		ContextNonSharable::operator=(b);
+		glId = b.glId;
+		attachments = b.attachments;
+
+		b.glId = 0;
+		return *this;
+	}
+	/// @}
+
 	/// Create
 	/// Create
 	void create()
 	void create()
 	{
 	{

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

@@ -49,7 +49,7 @@ public:
 	/// @}
 	/// @}
 
 
 private:
 private:
-	ShaderProgramResourcePointer sProg;
+	ShaderProgramResourcePointer prog;
 	static const U MAX_POINTS_PER_DRAW = 256;
 	static const U MAX_POINTS_PER_DRAW = 256;
 	Array<Vec3, MAX_POINTS_PER_DRAW> positions;
 	Array<Vec3, MAX_POINTS_PER_DRAW> positions;
 	Array<Vec3, MAX_POINTS_PER_DRAW> colors;
 	Array<Vec3, MAX_POINTS_PER_DRAW> colors;

+ 44 - 30
include/anki/resource/Mesh.h

@@ -37,6 +37,43 @@ public:
 		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
 		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
 		U32& size, GLenum& type, U32& stride, U32& offset) const = 0;
 		U32& size, GLenum& type, U32& stride, U32& offset) const = 0;
 
 
+	virtual U32 getVerticesCount() const = 0;
+
+	virtual U32 getIndicesCount(U32 lod) const = 0;
+
+	virtual U32 getTextureChannelsCount() const = 0;
+
+	virtual Bool hasWeights() const = 0;
+
+	virtual U32 getLodsCount() const = 0;
+
+	virtual const Obb& getBoundingShape() const = 0;
+};
+
+/// Mesh Resource. It contains the geometry packed in VBOs
+class Mesh: public MeshBase
+{
+public:
+	/// @name Constructors
+	/// @{
+
+	/// Default constructor. Do nothing
+	Mesh()
+	{}
+
+	/// Load file
+	Mesh(const char* filename)
+	{
+		load(filename);
+	}
+	/// @}
+
+	/// Does nothing
+	~Mesh()
+	{}
+
+	/// @name MeshBase implementers
+	/// @{
 	U32 getVerticesCount() const
 	U32 getVerticesCount() const
 	{
 	{
 		return vertsCount;
 		return vertsCount;
@@ -66,37 +103,8 @@ public:
 	{
 	{
 		return visibilityShape;
 		return visibilityShape;
 	}
 	}
-
-protected:
-	U32 vertsCount;
-	Vector<U32> indicesCount; ///< Indices count per level
-	U32 texChannelsCount;
-	Bool weights;
-	Obb visibilityShape;
-};
-
-/// Mesh Resource. It contains the geometry packed in VBOs
-class Mesh: public MeshBase
-{
-public:
-	/// @name Constructors
-	/// @{
-
-	/// Default constructor. Do nothing
-	Mesh()
-	{}
-
-	/// Load file
-	Mesh(const char* filename)
-	{
-		load(filename);
-	}
 	/// @}
 	/// @}
 
 
-	/// Does nothing
-	~Mesh()
-	{}
-
 	/// Load from a file
 	/// Load from a file
 	void load(const char* filename);
 	void load(const char* filename);
 
 
@@ -106,11 +114,17 @@ public:
 		U32& size, GLenum& type, U32& stride, U32& offset) const;
 		U32& size, GLenum& type, U32& stride, U32& offset) const;
 
 
 private:
 private:
+	U32 vertsCount;
+	Vector<U32> indicesCount; ///< Indices count per level
+	U32 texChannelsCount;
+	Bool weights;
+	Obb visibilityShape;
+
 	Vbo vbo;
 	Vbo vbo;
 	Vector<Vbo> indicesVbos;
 	Vector<Vbo> indicesVbos;
 
 
 	/// Create the VBOs using the mesh data
 	/// Create the VBOs using the mesh data
-	void createVbos(const MeshLoader& meshData);
+	void createVbos(const MeshLoader& loader);
 
 
 	U32 calcVertexSize() const;
 	U32 calcVertexSize() const;
 };
 };

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

@@ -32,7 +32,7 @@ public:
 		uint movableFlags, Movable* movParent, // Movable
 		uint movableFlags, Movable* movParent, // Movable
 		Frustum* frustum) // Spatial & Frustumable
 		Frustum* frustum) // Spatial & Frustumable
 		: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
 		: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
-			Spatial(frustum), Frustumable(frustum), type(type_)
+			Spatial(this, frustum), Frustumable(frustum), type(type_)
 	{}
 	{}
 
 
 	virtual ~Camera();
 	virtual ~Camera();

+ 20 - 13
include/anki/scene/Octree.h

@@ -3,7 +3,7 @@
 
 
 #include "anki/collision/Aabb.h"
 #include "anki/collision/Aabb.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Vector.h"
-#include <array>
+#include "anki/util/Array.h"
 #include <memory>
 #include <memory>
 
 
 namespace anki {
 namespace anki {
@@ -18,7 +18,7 @@ class OctreeNode
 	friend class Octree;
 	friend class Octree;
 
 
 public:
 public:
-	typedef std::array<std::unique_ptr<OctreeNode>, 8> ChildrenContainer;
+	typedef Array<std::unique_ptr<OctreeNode>, 8> ChildrenContainer;
 
 
 	OctreeNode(const Aabb& aabb_, OctreeNode* parent_)
 	OctreeNode(const Aabb& aabb_, OctreeNode* parent_)
 		: parent(parent_), aabb(aabb_)
 		: parent(parent_), aabb(aabb_)
@@ -26,7 +26,7 @@ public:
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
-	const OctreeNode* getChild(uint32_t id) const
+	const OctreeNode* getChild(U id) const
 	{
 	{
 		return children[id].get();
 		return children[id].get();
 	}
 	}
@@ -49,23 +49,31 @@ public:
 	{
 	{
 		return sceneNodes.end();
 		return sceneNodes.end();
 	}
 	}
-	uint32_t getSceneNodesCount() const
+	U getSceneNodesCount() const
 	{
 	{
 		return sceneNodes.size();
 		return sceneNodes.size();
 	}
 	}
 	/// @}
 	/// @}
 
 
-	bool isRoot() const
+	Bool isRoot() const
 	{
 	{
 		return parent == nullptr;
 		return parent == nullptr;
 	}
 	}
 
 
-	void addChild(uint32_t pos, OctreeNode* child)
+	void addChild(U pos, OctreeNode* child)
 	{
 	{
 		child->parent = this;
 		child->parent = this;
 		children[pos].reset(child);
 		children[pos].reset(child);
 	}
 	}
 
 
+	void addSceneNode(SceneNode* sn)
+	{
+		ANKI_ASSERT(sn != nullptr);
+		sceneNodes.push_back(sn);
+	}
+
+	void removeSceneNode(SceneNode* sn);
+
 private:
 private:
 	ChildrenContainer children;
 	ChildrenContainer children;
 	OctreeNode* parent;
 	OctreeNode* parent;
@@ -77,7 +85,7 @@ private:
 class Octree
 class Octree
 {
 {
 public:
 public:
-	Octree(const Aabb& aabb, uint8_t maxDepth, float looseness = 1.5);
+	Octree(const Aabb& aabb, U8 maxDepth, F32 looseness = 1.5);
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
@@ -90,7 +98,7 @@ public:
 		return root;
 		return root;
 	}
 	}
 
 
-	uint32_t getMaxDepth() const
+	U getMaxDepth() const
 	{
 	{
 		return maxDepth;
 		return maxDepth;
 	}
 	}
@@ -103,11 +111,11 @@ public:
 	void doVisibilityTests(Frustumable& fr);
 	void doVisibilityTests(Frustumable& fr);
 
 
 private:
 private:
-	uint32_t maxDepth;
-	float looseness;
+	U maxDepth;
+	F32 looseness;
 	OctreeNode root;
 	OctreeNode root;
 
 
-	OctreeNode* place(const Aabb& aabb, uint depth, OctreeNode& node);
+	OctreeNode* placeInternal(const Aabb& aabb, U depth, OctreeNode& node);
 
 
 	/// Place an AABB inside the tree. The algorithm is pretty simple, find the
 	/// Place an AABB inside the tree. The algorithm is pretty simple, find the
 	/// node that completely includes the aabb. If found then go deeper into
 	/// node that completely includes the aabb. If found then go deeper into
@@ -127,8 +135,7 @@ private:
 	/// @param[in] k 0: back, 1: front
 	/// @param[in] k 0: back, 1: front
 	/// @param[in] parentAabb The parent's AABB
 	/// @param[in] parentAabb The parent's AABB
 	/// @param[out] out The out AABB
 	/// @param[out] out The out AABB
-	void calcAabb(uint i, uint j, uint k, const Aabb& parentAabb,
-		Aabb& out) const;
+	void calcAabb(U i, U j, U k, const Aabb& parentAabb, Aabb& out) const;
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

+ 30 - 33
include/anki/scene/SkinNode.h

@@ -8,7 +8,6 @@
 #include "anki/resource/Model.h"
 #include "anki/resource/Model.h"
 #include "anki/math/Math.h"
 #include "anki/math/Math.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Vector.h"
-#include <array>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -18,58 +17,56 @@ class Skin;
 class SkinMesh: public MeshBase
 class SkinMesh: public MeshBase
 {
 {
 public:
 public:
-	/// Transform feedback VBOs
-	enum TfVboId
-	{
-		VBO_TF_POSITIONS, ///< VBO never empty
-		VBO_TF_NORMALS, ///< VBO never empty
-		VBO_TF_TANGENTS, ///< VBO never empty
-		VBOS_TF_COUNT
-	};
-
 	/// Create the @a tfVbos with empty data
 	/// Create the @a tfVbos with empty data
 	SkinMesh(const MeshBase* mesh);
 	SkinMesh(const MeshBase* mesh);
 
 
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
-	const Vbo* getTransformFeedbackVbo(TfVboId id) const /// XXX Why pointer?
+	const Vbo& getXfbVbo() const
 	{
 	{
-		return &tfVbos[id];
+		return vbo;
 	}
 	}
 	/// @}
 	/// @}
 
 
-	/// @name Implementations of MeshBase virtuals
+	/// @name MeshBase implementers
 	/// @{
 	/// @{
-	const Vbo* getVbo(VboId id) const;
+	U32 getVerticesCount() const
+	{
+		return mesh->getVerticesCount();
+	}
 
 
-	uint getTextureChannelsNumber() const
+	U32 getIndicesCount(U32 lod) const
 	{
 	{
-		return mesh->getTextureChannelsNumber();
+		return mesh->getIndicesCount(lod);
 	}
 	}
 
 
-	uint getLodsNumber() const
+	U32 getTextureChannelsCount() const
 	{
 	{
-		return mesh->getLodsNumber();
+		return mesh->getTextureChannelsCount();
 	}
 	}
 
 
-	uint getIndicesNumber(uint lod) const
+	Bool hasWeights() const
 	{
 	{
-		return mesh->getIndicesNumber(lod);
+		return false;
 	}
 	}
 
 
-	uint getVerticesNumber(uint lod) const
+	U32 getLodsCount() const
 	{
 	{
-		return mesh->getVerticesNumber(lod);
+		return mesh->getLodsCount();
 	}
 	}
 
 
 	const Obb& getBoundingShape() const
 	const Obb& getBoundingShape() const
 	{
 	{
 		return mesh->getBoundingShape();
 		return mesh->getBoundingShape();
 	}
 	}
+
+	void getVboInfo(
+		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
+		U32& size, GLenum& type, U32& stride, U32& offset) const;
 	/// @}
 	/// @}
 
 
 private:
 private:
-	std::array<Vbo, VBOS_TF_COUNT> tfVbos;
+	Vbo vbo; ///< Contains the transformed P,N,T 
 	const MeshBase* mesh; ///< The resource
 	const MeshBase* mesh; ///< The resource
 };
 };
 
 
@@ -80,14 +77,14 @@ class SkinModelPatch: public ModelPatchBase
 {
 {
 public:
 public:
 	/// See TfHwSkinningGeneric.glsl for the locations
 	/// See TfHwSkinningGeneric.glsl for the locations
-	enum TfShaderProgAttribLoc
-	{
-		POSITION_LOC,
-		NORMAL_LOC,
-		TANGENT_LOC,
-		VERT_WEIGHT_BONES_NUM_LOC,
-		VERT_WEIGHT_BONE_IDS_LOC,
-		VERT_WEIGHT_WEIGHTS_LOC
+	enum XfbAttributeLocation
+	{
+		XFBAL_POSITION,
+		XFBAL_NORMAL,
+		XFBAL_TANGENT,
+		XFBAL_BONES_COUNT,
+		XFBAL_BONE_IDS,
+		XFBAL_BONE_WEIGHTS
 	};
 	};
 
 
 	/// @name Constructors/Destructor
 	/// @name Constructors/Destructor
@@ -109,7 +106,7 @@ public:
 
 
 	const Vao& getTransformFeedbackVao() const
 	const Vao& getTransformFeedbackVao() const
 	{
 	{
-		return tfVao;
+		return xfbVao;
 	}
 	}
 	/// @}
 	/// @}
 
 
@@ -129,7 +126,7 @@ public:
 private:
 private:
 	std::unique_ptr<SkinMesh> skinMesh;
 	std::unique_ptr<SkinMesh> skinMesh;
 	const ModelPatch* mpatch;
 	const ModelPatch* mpatch;
-	Vao tfVao; ///< Used as a source VAO in TFB
+	Vao xfbVao; ///< Used as a source VAO in XFB
 };
 };
 
 
 
 

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

@@ -8,6 +8,7 @@
 namespace anki {
 namespace anki {
 
 
 class OctreeNode;
 class OctreeNode;
+class SceneNode;
 
 
 /// @addtogroup Scene
 /// @addtogroup Scene
 /// @{
 /// @{
@@ -26,10 +27,13 @@ public:
 	};
 	};
 
 
 	/// Pass the collision shape here so we can avoid the virtuals
 	/// Pass the collision shape here so we can avoid the virtuals
-	Spatial(CollisionShape* cs)
-		: spatialCs(cs)
+	Spatial(SceneNode* sceneNode_, CollisionShape* cs)
+		: spatialCs(cs), sceneNode(sceneNode_)
 	{}
 	{}
 
 
+	// Remove from current OctreeNode
+	~Spatial();
+
 	/// @name Accessors
 	/// @name Accessors
 	/// @{
 	/// @{
 	const CollisionShape& getSpatialCollisionShape() const
 	const CollisionShape& getSpatialCollisionShape() const
@@ -76,9 +80,10 @@ private:
 	U32 timestamp = Timestamp::getTimestamp();
 	U32 timestamp = Timestamp::getTimestamp();
 	OctreeNode* octreeNode = nullptr; ///< What octree node includes this
 	OctreeNode* octreeNode = nullptr; ///< What octree node includes this
 	Aabb aabb; ///< A faster shape
 	Aabb aabb; ///< A faster shape
+	SceneNode* sceneNode; ///< Know your father
 };
 };
 /// @}
 /// @}
 
 
-} // namespace anki
+} // end namespace anki
 
 
 #endif
 #endif

+ 1 - 1
src/gl/Fbo.cpp

@@ -97,7 +97,7 @@ void Fbo::setColorAttachments(const std::initializer_list<const Texture*>&
 	glDrawBuffers(textures.size(), &colorAttachments[0]);
 	glDrawBuffers(textures.size(), &colorAttachments[0]);
 
 
 	// Set attachments
 	// Set attachments
-	int i = 0;
+	U i = 0;
 	for(const Texture* tex : textures)
 	for(const Texture* tex : textures)
 	{
 	{
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,

+ 7 - 6
src/gl/Vao.cpp

@@ -2,6 +2,7 @@
 #include "anki/gl/Vbo.h"
 #include "anki/gl/Vbo.h"
 #include "anki/util/Exception.h"
 #include "anki/util/Exception.h"
 #include "anki/gl/ShaderProgram.h"
 #include "anki/gl/ShaderProgram.h"
+#include "anki/core/Logger.h"
 
 
 namespace anki {
 namespace anki {
 
 
@@ -24,9 +25,9 @@ void Vao::attachArrayBufferVbo(const Vbo* vbo, const GLint attribVarLocation,
 	const PtrSize stride, const PtrSize offset)
 	const PtrSize stride, const PtrSize offset)
 {
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(vbo.getBufferTarget() == GL_ARRAY_BUFFER
+	ANKI_ASSERT(vbo->getBufferTarget() == GL_ARRAY_BUFFER
 		&& "Only GL_ARRAY_BUFFER is accepted");
 		&& "Only GL_ARRAY_BUFFER is accepted");
-	ANKI_ASSERT(vbo.isCreated());
+	ANKI_ASSERT(vbo->isCreated());
 	checkNonSharable();
 	checkNonSharable();
 
 
 	bind();
 	bind();
@@ -34,7 +35,7 @@ void Vao::attachArrayBufferVbo(const Vbo* vbo, const GLint attribVarLocation,
 	glEnableVertexAttribArray(attribVarLocation);
 	glEnableVertexAttribArray(attribVarLocation);
 	glVertexAttribPointer(attribVarLocation, size, type, normalized,
 	glVertexAttribPointer(attribVarLocation, size, type, normalized,
 		stride, reinterpret_cast<const GLvoid*>(offset));
 		stride, reinterpret_cast<const GLvoid*>(offset));
-	vbo.unbind();
+	vbo->unbind();
 	unbind();
 	unbind();
 
 
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
@@ -56,13 +57,13 @@ void Vao::attachArrayBufferVbo(const Vbo* vbo,
 void Vao::attachElementArrayBufferVbo(const Vbo* vbo)
 void Vao::attachElementArrayBufferVbo(const Vbo* vbo)
 {
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(vbo.getBufferTarget() == GL_ELEMENT_ARRAY_BUFFER
+	ANKI_ASSERT(vbo->getBufferTarget() == GL_ELEMENT_ARRAY_BUFFER
 		&& "Only GL_ELEMENT_ARRAY_BUFFER is accepted");
 		&& "Only GL_ELEMENT_ARRAY_BUFFER is accepted");
-	ANKI_ASSERT(vbo.isCreated());
+	ANKI_ASSERT(vbo->isCreated());
 	checkNonSharable();
 	checkNonSharable();
 
 
 	bind();
 	bind();
-	vbo.bind();
+	vbo->bind();
 	unbind();
 	unbind();
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 
 

+ 1 - 4
src/renderer/Dbg.cpp

@@ -19,8 +19,7 @@ void Dbg::init(const Renderer::Initializer& initializer)
 	try
 	try
 	{
 	{
 		fbo.create();
 		fbo.create();
-		//fbo.setColorAttachments({&r->getPps().getPostPassFai()});
-		fbo.setColorAttachments({&r->getIs().getFai()});
+		fbo.setColorAttachments({&r->getPps().getFai()});
 		fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
 		fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
 
 
 		if(!fbo.isComplete())
 		if(!fbo.isComplete())
@@ -37,8 +36,6 @@ void Dbg::init(const Renderer::Initializer& initializer)
 	sceneDrawer.reset(new SceneDebugDrawer(drawer.get()));
 	sceneDrawer.reset(new SceneDebugDrawer(drawer.get()));
 }
 }
 
 
-U deletemeto = 0;
-
 //==============================================================================
 //==============================================================================
 void Dbg::run()
 void Dbg::run()
 {
 {

+ 11 - 11
src/renderer/DebugDrawer.cpp

@@ -17,31 +17,31 @@ namespace anki {
 // DebugDrawer                                                                 =
 // DebugDrawer                                                                 =
 //==============================================================================
 //==============================================================================
 
 
-//==============================================================================
-DebugDrawer::~DebugDrawer()
-{}
-
 //==============================================================================
 //==============================================================================
 DebugDrawer::DebugDrawer()
 DebugDrawer::DebugDrawer()
 {
 {
-	sProg.load("shaders/Dbg.glsl");
+	prog.load("shaders/Dbg.glsl");
 
 
 	positionsVbo.create(GL_ARRAY_BUFFER, sizeof(positions), NULL,
 	positionsVbo.create(GL_ARRAY_BUFFER, sizeof(positions), NULL,
 		GL_DYNAMIC_DRAW);
 		GL_DYNAMIC_DRAW);
 	colorsVbo.create(GL_ARRAY_BUFFER, sizeof(colors), NULL, GL_DYNAMIC_DRAW);
 	colorsVbo.create(GL_ARRAY_BUFFER, sizeof(colors), NULL, GL_DYNAMIC_DRAW);
 	vao.create();
 	vao.create();
 	const int positionAttribLoc = 0;
 	const int positionAttribLoc = 0;
-	vao.attachArrayBufferVbo(positionsVbo, positionAttribLoc, 3, GL_FLOAT,
-		GL_FALSE, 0, NULL);
+	vao.attachArrayBufferVbo(&positionsVbo, positionAttribLoc, 3, GL_FLOAT,
+		GL_FALSE, 0, 0);
 	const int colorAttribLoc = 1;
 	const int colorAttribLoc = 1;
-	vao.attachArrayBufferVbo(colorsVbo, colorAttribLoc, 3, GL_FLOAT, GL_FALSE,
-		0, NULL);
+	vao.attachArrayBufferVbo(&colorsVbo, colorAttribLoc, 3, GL_FLOAT, GL_FALSE,
+		0, 0);
 
 
 	pointIndex = 0;
 	pointIndex = 0;
 	modelMat.setIdentity();
 	modelMat.setIdentity();
 	crntCol = Vec3(1.0, 0.0, 0.0);
 	crntCol = Vec3(1.0, 0.0, 0.0);
 }
 }
 
 
+//==============================================================================
+DebugDrawer::~DebugDrawer()
+{}
+
 //==============================================================================
 //==============================================================================
 void DebugDrawer::drawLine(const Vec3& from, const Vec3& to, const Vec4& color)
 void DebugDrawer::drawLine(const Vec3& from, const Vec3& to, const Vec4& color)
 {
 {
@@ -212,8 +212,8 @@ void DebugDrawer::end()
 	colorsVbo.write(&colors[0], 0, sizeof(Vec3) * pointIndex);
 	colorsVbo.write(&colors[0], 0, sizeof(Vec3) * pointIndex);
 
 
 	Mat4 pmv = vpMat * modelMat;
 	Mat4 pmv = vpMat * modelMat;
-	sProg->bind();
-	sProg->findUniformVariable("modelViewProjectionMat").set(pmv);
+	prog->bind();
+	prog->findUniformVariable("modelViewProjectionMat").set(pmv);
 
 
 	vao.bind();
 	vao.bind();
 	glDrawArrays(GL_LINES, 0, pointIndex);
 	glDrawArrays(GL_LINES, 0, pointIndex);

+ 2 - 0
src/renderer/Deformer.cpp

@@ -22,6 +22,7 @@ void Deformer::init()
 //==============================================================================
 //==============================================================================
 void Deformer::deform(SkinNode& skinNode, SkinPatchNode& node) const
 void Deformer::deform(SkinNode& skinNode, SkinPatchNode& node) const
 {
 {
+#if 0
 	ANKI_ASSERT(node.getMovable()->getParent() != NULL
 	ANKI_ASSERT(node.getMovable()->getParent() != NULL
 		&& "The SkinPatchNode should always have parent");
 		&& "The SkinPatchNode should always have parent");
 
 
@@ -77,6 +78,7 @@ void Deformer::deform(SkinNode& skinNode, SkinPatchNode& node) const
 	glEndTransformFeedback();
 	glEndTransformFeedback();
 
 
 	GlStateSingleton::get().disable(GL_RASTERIZER_DISCARD);
 	GlStateSingleton::get().disable(GL_RASTERIZER_DISCARD);
+#endif
 }
 }
 
 
 } // end namespace
 } // end namespace

+ 1 - 1
src/renderer/Drawer.cpp

@@ -171,7 +171,7 @@ void RenderableDrawer::render(const Frustumable& fr, uint pass,
 	setupShaderProg(key, fr, renderable);
 	setupShaderProg(key, fr, renderable);
 
 
 	// Render
 	// Render
-	U32 indecesNum = renderable.getModelPatchBase().getIndecesNumber(0);
+	U32 indecesNum = renderable.getModelPatchBase().getIndecesCount(0);
 
 
 	const Vao& vao = renderable.getModelPatchBase().getVao(key);
 	const Vao& vao = renderable.getModelPatchBase().getVao(key);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);

+ 1 - 1
src/renderer/MainRenderer.cpp

@@ -23,7 +23,7 @@ void MainRenderer::init(const Renderer::Initializer& initializer_)
 	const F32 renderingQuality = initializer_.renderingQuality;
 	const F32 renderingQuality = initializer_.renderingQuality;
 	windowWidth = initializer_.width;
 	windowWidth = initializer_.width;
 	windowHeight = initializer_.height;
 	windowHeight = initializer_.height;
-	drawToDefaultFbo = (renderingQuality > 0.9);
+	drawToDefaultFbo = (renderingQuality > 0.9 && !initializer_.dbg.enabled);
 
 
 	// init the offscreen Renderer
 	// init the offscreen Renderer
 	//
 	//

+ 5 - 5
src/renderer/Renderer.cpp

@@ -38,19 +38,19 @@ void Renderer::init(const RendererInitializer& initializer)
 	bs.init(initializer);
 	bs.init(initializer);
 
 
 	// quad VBOs and VAO
 	// quad VBOs and VAO
-	float quadVertCoords[][2] = {{1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0},
+	F32 quadVertCoords[][2] = {{1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0},
 		{1.0, 0.0}}; /// XXX change them to NDC
 		{1.0, 0.0}}; /// XXX change them to NDC
 	quadPositionsVbo.create(GL_ARRAY_BUFFER, sizeof(quadVertCoords),
 	quadPositionsVbo.create(GL_ARRAY_BUFFER, sizeof(quadVertCoords),
 		quadVertCoords, GL_STATIC_DRAW);
 		quadVertCoords, GL_STATIC_DRAW);
 
 
-	ushort quadVertIndeces[2][3] = {{0, 1, 3}, {1, 2, 3}}; // 2 triangles
+	U16 quadVertIndeces[2][3] = {{0, 1, 3}, {1, 2, 3}}; // 2 triangles
 	quadVertIndecesVbo.create(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadVertIndeces),
 	quadVertIndecesVbo.create(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadVertIndeces),
 		quadVertIndeces, GL_STATIC_DRAW);
 		quadVertIndeces, GL_STATIC_DRAW);
 
 
 	quadVao.create();
 	quadVao.create();
-	quadVao.attachArrayBufferVbo(quadPositionsVbo, 0, 2, GL_FLOAT, false, 0,
-		NULL);
-	quadVao.attachElementArrayBufferVbo(quadVertIndecesVbo);
+	quadVao.attachArrayBufferVbo(
+		&quadPositionsVbo, 0, 2, GL_FLOAT, false, 0, 0);
+	quadVao.attachElementArrayBufferVbo(&quadVertIndecesVbo);
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 23 - 22
src/resource/Mesh.cpp

@@ -10,28 +10,28 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 void Mesh::load(const char* filename)
 void Mesh::load(const char* filename)
 {
 {
-	MeshLoader meshData(filename);
+	MeshLoader loader(filename);
 
 
 	// Set the non-VBO members
 	// Set the non-VBO members
-	vertsCount = meshData.getPositions().size();
+	vertsCount = loader.getPositions().size();
 	ANKI_ASSERT(vertsCount > 0);
 	ANKI_ASSERT(vertsCount > 0);
 
 
-	indicesCount.push_back(meshData.getLodsCount());
+	indicesCount.push_back(loader.getLodsCount());
 	for(U lod = 0; lod < indicesCount.size(); lod++)
 	for(U lod = 0; lod < indicesCount.size(); lod++)
 	{
 	{
-		indicesCount[lod] = meshData.getIndices(lod).size();
+		indicesCount[lod] = loader.getIndices(lod).size();
 		ANKI_ASSERT(indicesCount[lod] > 0);
 		ANKI_ASSERT(indicesCount[lod] > 0);
 		ANKI_ASSERT(indicesCount[lod] % 3 == 0 && "Expecting triangles");
 		ANKI_ASSERT(indicesCount[lod] % 3 == 0 && "Expecting triangles");
 	}
 	}
 
 
-	weights = meshData.getWeights().size() > 1;
-	texChannelsCount = meshData.getTextureChannelsCount();
+	weights = loader.getWeights().size() > 1;
+	texChannelsCount = loader.getTextureChannelsCount();
 
 
 	try
 	try
 	{
 	{
-		createVbos(meshData);
+		createVbos(loader);
 
 
-		visibilityShape.set(meshData.getPositions());
+		visibilityShape.set(loader.getPositions());
 	}
 	}
 	catch(std::exception& e)
 	catch(std::exception& e)
 	{
 	{
@@ -42,7 +42,8 @@ void Mesh::load(const char* filename)
 //==============================================================================
 //==============================================================================
 U32 Mesh::calcVertexSize() const
 U32 Mesh::calcVertexSize() const
 {
 {
-	U32 a = (3 + 3 + 4 + texChannelsCount * 2) * sizeof(F32);
+	U32 a = sizeof(Vec3) + sizeof(Vec3) + sizeof(Vec4) 
+		+ texChannelsCount * sizeof(Vec2);
 	if(weights)
 	if(weights)
 	{
 	{
 		a += sizeof(MeshLoader::VertexWeight);
 		a += sizeof(MeshLoader::VertexWeight);
@@ -51,39 +52,39 @@ U32 Mesh::calcVertexSize() const
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Mesh::createVbos(const MeshLoader& meshData)
+void Mesh::createVbos(const MeshLoader& loader)
 {
 {
 	// Calculate VBO size
 	// Calculate VBO size
 	U32 vertexsize = calcVertexSize();
 	U32 vertexsize = calcVertexSize();
 	U32 vbosize = vertexsize * vertsCount;
 	U32 vbosize = vertexsize * vertsCount;
 
 
 	// Create a temp buffer and populate it
 	// Create a temp buffer and populate it
-	Vector<U8> buff;
-	buff.resize(vbosize);
+	Vector<U8> buff(vbosize, 0);
 
 
 	U8* ptr = &buff[0];
 	U8* ptr = &buff[0];
 	for(U i = 0; i < vertsCount; i++)
 	for(U i = 0; i < vertsCount; i++)
 	{
 	{
 		ANKI_ASSERT(ptr + vertexsize <= &buff[0] + vbosize);
 		ANKI_ASSERT(ptr + vertexsize <= &buff[0] + vbosize);
 
 
-		*(Vec3*)ptr = meshData.getPositions()[i];
+		memcpy(ptr, &loader.getPositions()[i], sizeof(Vec3));
 		ptr += sizeof(Vec3);
 		ptr += sizeof(Vec3);
 
 
-		*(Vec3*)ptr = meshData.getNormals()[i];
+		memcpy(ptr, &loader.getNormals()[i], sizeof(Vec3));
 		ptr += sizeof(Vec3);
 		ptr += sizeof(Vec3);
 
 
-		*(Vec4*)ptr = meshData.getTangents()[i];
+		memcpy(ptr, &loader.getTangents()[i], sizeof(Vec4));
 		ptr += sizeof(Vec4);
 		ptr += sizeof(Vec4);
 
 
 		for(U j = 0; j < texChannelsCount; j++)
 		for(U j = 0; j < texChannelsCount; j++)
 		{
 		{
-			*(Vec2*)ptr = meshData.getTexureCoordinates(j)[i];
+			memcpy(ptr, &loader.getTexureCoordinates(j)[i], sizeof(Vec2));
 			ptr += sizeof(Vec2);
 			ptr += sizeof(Vec2);
 		}
 		}
 
 
 		if(weights)
 		if(weights)
 		{
 		{
-			*(MeshLoader::VertexWeight*)ptr = meshData.getWeights()[i];
+			memcpy(ptr, &loader.getWeights()[i], 
+				sizeof(MeshLoader::VertexWeight));
 			ptr += sizeof(MeshLoader::VertexWeight);
 			ptr += sizeof(MeshLoader::VertexWeight);
 		}
 		}
 	}
 	}
@@ -96,14 +97,14 @@ void Mesh::createVbos(const MeshLoader& meshData)
 		GL_STATIC_DRAW);
 		GL_STATIC_DRAW);
 
 
 	/// Create the indices VBOs
 	/// Create the indices VBOs
-	indicesVbos.resize(meshData.getLodsCount());
+	indicesVbos.resize(loader.getLodsCount());
 	U lod = 0;
 	U lod = 0;
 	for(Vbo& v : indicesVbos)
 	for(Vbo& v : indicesVbos)
 	{
 	{
 		v.create(
 		v.create(
 			GL_ELEMENT_ARRAY_BUFFER,
 			GL_ELEMENT_ARRAY_BUFFER,
-			getVectorSizeInBytes(meshData.getIndices(lod)),
-			&meshData.getIndices(lod)[0],
+			getVectorSizeInBytes(loader.getIndices(lod)),
+			&loader.getIndices(lod)[0],
 			GL_STATIC_DRAW);
 			GL_STATIC_DRAW);
 
 
 		++lod;
 		++lod;
@@ -149,7 +150,7 @@ void Mesh::getVboInfo(
 			v = &vbo;
 			v = &vbo;
 			size = 2;
 			size = 2;
 			type = GL_FLOAT;
 			type = GL_FLOAT;
-			offset = sizeof(Vec3) * 2 + sizeof(Vec4) + sizeof(Vec2);
+			offset = sizeof(Vec3) * 2 + sizeof(Vec4);
 		}
 		}
 		break;
 		break;
 	case VA_TEXTURE_COORDS_1:
 	case VA_TEXTURE_COORDS_1:
@@ -158,7 +159,7 @@ void Mesh::getVboInfo(
 			v = &vbo;
 			v = &vbo;
 			size = 2;
 			size = 2;
 			type = GL_FLOAT;
 			type = GL_FLOAT;
-			offset = sizeof(Vec3) * 2 + sizeof(Vec4) + sizeof(Vec2) * 2;
+			offset = sizeof(Vec3) * 2 + sizeof(Vec4) + sizeof(Vec2);
 		}
 		}
 		break;
 		break;
 	case VA_BONE_COUNT:
 	case VA_BONE_COUNT:

+ 5 - 2
src/resource/Model.cpp

@@ -88,6 +88,8 @@ void ModelPatchBase::createVaos(const Material& mtl,
 	VaosContainer& vaos,
 	VaosContainer& vaos,
 	PassLevelToVaoMap& vaosMap)
 	PassLevelToVaoMap& vaosMap)
 {
 {
+	vaos.resize(mtl.getLevelsOfDetail() * mtl.getPasses().size());
+
 	for(U32 level = 0; level < mtl.getLevelsOfDetail(); ++level)
 	for(U32 level = 0; level < mtl.getLevelsOfDetail(); ++level)
 	{
 	{
 		for(U32 pass = 0; pass < mtl.getPasses().size(); ++pass)
 		for(U32 pass = 0; pass < mtl.getPasses().size(); ++pass)
@@ -97,8 +99,9 @@ void ModelPatchBase::createVaos(const Material& mtl,
 			Vao vao;
 			Vao vao;
 			createVao(mtl, meshb, key, vao);
 			createVao(mtl, meshb, key, vao);
 
 
-			vaos.push_back(std::move(vao));
-			vaosMap[key] = &vaos[vaos.size() - 1];
+			U index = level * mtl.getPasses().size() + pass;
+			vaos[index] = std::move(vao);
+			vaosMap[key] = &vaos[index];
 		}
 		}
 	}
 	}
 }
 }

+ 1 - 1
src/scene/Light.cpp

@@ -13,7 +13,7 @@ Light::Light(LightType t, // Light
 	CollisionShape* cs) // Spatial
 	CollisionShape* cs) // Spatial
 	: SceneNode(name, scene),
 	: SceneNode(name, scene),
 		Movable(movableFlags, movParent, *this),
 		Movable(movableFlags, movParent, *this),
-		Spatial(cs), type(t)
+		Spatial(this, cs), type(t)
 {
 {
 	addNewProperty(new ReadWritePointerProperty<Vec4>("color", &color));
 	addNewProperty(new ReadWritePointerProperty<Vec4>("color", &color));
 
 

+ 1 - 1
src/scene/ModelNode.cpp

@@ -13,7 +13,7 @@ ModelPatchNode::ModelPatchNode(const ModelPatch* modelPatch_,
 	const char* name, Scene* scene,
 	const char* name, Scene* scene,
 	uint movableFlags, Movable* movParent)
 	uint movableFlags, Movable* movParent)
 	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
 	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
-		Spatial(&obb), modelPatch(modelPatch_)
+		Spatial(this, &obb), modelPatch(modelPatch_)
 {
 {
 	Renderable::init(*this);
 	Renderable::init(*this);
 }
 }

+ 34 - 23
src/scene/Octree.cpp

@@ -9,7 +9,24 @@
 namespace anki {
 namespace anki {
 
 
 //==============================================================================
 //==============================================================================
-Octree::Octree(const Aabb& aabb, uint8_t maxDepth_, float looseness_)
+// OctreeNode                                                                  =
+//==============================================================================
+
+//==============================================================================
+void OctreeNode::removeSceneNode(SceneNode* sn)
+{
+	Vector<SceneNode*>::iterator it =
+		std::find(sceneNodes.begin(), sceneNodes.end(), sn);
+	ANKI_ASSERT(it != sceneNodes.end());
+	sceneNodes.erase(it);
+}
+
+//==============================================================================
+// Octree                                                                      =
+//==============================================================================
+
+//==============================================================================
+Octree::Octree(const Aabb& aabb, U8 maxDepth_, F32 looseness_)
 	: maxDepth(maxDepth_ < 1 ? 1 : maxDepth_), looseness(looseness_),
 	: maxDepth(maxDepth_ < 1 ? 1 : maxDepth_), looseness(looseness_),
 		root(aabb, nullptr)
 		root(aabb, nullptr)
 {}
 {}
@@ -35,19 +52,14 @@ void Octree::placeSceneNode(SceneNode* sn)
 		return;
 		return;
 	}
 	}
 
 
-	// Remove from current node
+	// Remove from current node ...
 	if(crntNode)
 	if(crntNode)
 	{
 	{
-		Vector<SceneNode*>::iterator it =
-			std::find(crntNode->sceneNodes.begin(),
-			crntNode->sceneNodes.end(), sn);
-
-		ANKI_ASSERT(it != crntNode->sceneNodes.end());
-		crntNode->sceneNodes.erase(it);
+		crntNode->removeSceneNode(sn);
 	}
 	}
 
 
-	// Add to new one node
-	toBePlacedNode->sceneNodes.push_back(sn);
+	// ... and add to a new
+	toBePlacedNode->addSceneNode(sn);
 	sp->setOctreeNode(toBePlacedNode);
 	sp->setOctreeNode(toBePlacedNode);
 }
 }
 
 
@@ -57,7 +69,7 @@ OctreeNode* Octree::place(const Aabb& aabb)
 	if(CollisionAlgorithmsMatrix::collide(aabb, root.aabb))
 	if(CollisionAlgorithmsMatrix::collide(aabb, root.aabb))
 	{
 	{
 		// Run the recursive method
 		// Run the recursive method
-		return place(aabb, 0, root);
+		return placeInternal(aabb, 0, root);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -67,20 +79,20 @@ OctreeNode* Octree::place(const Aabb& aabb)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-OctreeNode* Octree::place(const Aabb& aabb, uint32_t depth, OctreeNode& node)
+OctreeNode* Octree::placeInternal(const Aabb& aabb, U depth, OctreeNode& node)
 {
 {
 	if(depth >= maxDepth)
 	if(depth >= maxDepth)
 	{
 	{
 		return &node;
 		return &node;
 	}
 	}
 
 
-	for(uint32_t i = 0; i < 2; ++i)
+	for(U i = 0; i < 2; ++i)
 	{
 	{
-		for(uint32_t j = 0; j < 2; ++j)
+		for(U j = 0; j < 2; ++j)
 		{
 		{
-			for(uint32_t k = 0; k < 2; ++k)
+			for(U k = 0; k < 2; ++k)
 			{
 			{
-				uint32_t id = i * 4 + j * 2 + k;
+				U id = i * 4 + j * 2 + k;
 
 
 				// Get the node's AABB. If there is no node then calculate the
 				// Get the node's AABB. If there is no node then calculate the
 				// AABB
 				// AABB
@@ -108,7 +120,7 @@ OctreeNode* Octree::place(const Aabb& aabb, uint32_t depth, OctreeNode& node)
 						node.addChild(id, newNode);
 						node.addChild(id, newNode);
 					}
 					}
 
 
-					return place(aabb, depth + 1, *node.children[id]);
+					return placeInternal(aabb, depth + 1, *node.children[id]);
 				}
 				}
 			} // k
 			} // k
 		} // j
 		} // j
@@ -118,8 +130,7 @@ OctreeNode* Octree::place(const Aabb& aabb, uint32_t depth, OctreeNode& node)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Octree::calcAabb(uint32_t i, uint32_t j, uint32_t k, const Aabb& paabb,
-	Aabb& out) const
+void Octree::calcAabb(U i, U j, U k, const Aabb& paabb, Aabb& out) const
 {
 {
 	const Vec3& min = paabb.getMin();
 	const Vec3& min = paabb.getMin();
 	const Vec3& max = paabb.getMax();
 	const Vec3& max = paabb.getMax();
@@ -133,13 +144,13 @@ void Octree::calcAabb(uint32_t i, uint32_t j, uint32_t k, const Aabb& paabb,
 	Vec3 omax = omin + d;
 	Vec3 omax = omin + d;
 
 
 	// Scale the AABB with looseness
 	// Scale the AABB with looseness
-	float tmp0 = (1.0 + looseness) / 2.0;
-	float tmp1 = (1.0 - looseness) / 2.0;
+	F32 tmp0 = (1.0 + looseness) / 2.0;
+	F32 tmp1 = (1.0 - looseness) / 2.0;
 	Vec3 nomin = tmp0 * omin + tmp1 * omax;
 	Vec3 nomin = tmp0 * omin + tmp1 * omax;
 	Vec3 nomax = tmp0 * omax + tmp1 * omin;
 	Vec3 nomax = tmp0 * omax + tmp1 * omin;
 
 
 	// Crop to fit the parent's AABB
 	// Crop to fit the parent's AABB
-	for(uint32_t n = 0; n < 3; ++n)
+	for(U n = 0; n < 3; ++n)
 	{
 	{
 		if(nomin[n] < min[n])
 		if(nomin[n] < min[n])
 		{
 		{
@@ -197,7 +208,7 @@ void Octree::doVisibilityTestsRec(Frustumable& fr, OctreeNode& node)
 		}
 		}
 	}
 	}
 
 
-	for(uint32_t i = 0; i < 8; ++i)
+	for(U i = 0; i < 8; ++i)
 	{
 	{
 		if(node.children[i].get() != nullptr)
 		if(node.children[i].get() != nullptr)
 		{
 		{

+ 47 - 110
src/scene/SkinNode.cpp

@@ -13,58 +13,34 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-const Vbo* SkinMesh::getVbo(VboId id) const
+SkinMesh::SkinMesh(const MeshBase* mesh_)
+	: mesh(mesh_)
 {
 {
-	switch(id)
-	{
-	case VBO_POSITIONS:
-		return &tfVbos[VBO_TF_POSITIONS];
-	case VBO_NORMALS:
-		return &tfVbos[VBO_TF_NORMALS];
-	case VBO_TANGENTS:
-		return &tfVbos[VBO_TF_TANGENTS];
-	default:
-		return mesh->getVbo(id);
-	}
+	// Init the VBO
+	vbo.create(
+		GL_ARRAY_BUFFER,
+		(sizeof(Vec3) * 2 + sizeof(Vec4)) * mesh->getVerticesCount(),
+		nullptr,
+		GL_STATIC_DRAW);
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-SkinMesh::SkinMesh(const MeshBase* mesh_)
-	: mesh(mesh_)
+void SkinMesh::getVboInfo(
+	const VertexAttribute attrib, const U32 lod, const Vbo*& v, 
+	U32& size, GLenum& type, U32& stride, U32& offset) const
 {
 {
-	const Vbo* vbo;
-
-	// Positions
-	vbo = mesh->getVbo(VBO_POSITIONS);
-	if(vbo)
-	{
-		tfVbos[VBO_TF_POSITIONS].create(
-			GL_ARRAY_BUFFER,
-			vbo->getSizeInBytes(),
-			nullptr,
-			GL_STATIC_DRAW);
-	}
-
-	// Normals
-	vbo = mesh->getVbo(VBO_NORMALS);
-	if(vbo)
-	{
-		tfVbos[VBO_TF_NORMALS].create(
-			GL_ARRAY_BUFFER,
-			vbo->getSizeInBytes(),
-			nullptr,
-			GL_STATIC_DRAW);
-	}
+	mesh->getVboInfo(attrib, lod, v, size, type, stride, offset);
 
 
-	// Tangents
-	vbo = mesh->getVbo(VBO_TANGENTS);
-	if(vbo)
+	switch(attrib)
 	{
 	{
-		tfVbos[VBO_TF_TANGENTS].create(
-			GL_ARRAY_BUFFER,
-			vbo->getSizeInBytes(),
-			nullptr,
-			GL_STATIC_DRAW);
+	case VA_POSITION:
+	case VA_NORMAL:
+	case VA_TANGENT:
+		v = &vbo;
+		stride = sizeof(Vec3) * 2 + sizeof(Vec4);
+		break;
+	default:
+		break;
 	}
 	}
 }
 }
 
 
@@ -79,77 +55,38 @@ SkinModelPatch::SkinModelPatch(const ModelPatch* mpatch_)
 	skinMesh.reset(new SkinMesh(&mpatch->getMeshBase()));
 	skinMesh.reset(new SkinMesh(&mpatch->getMeshBase()));
 	create();
 	create();
 
 
-	// Create the VAO
-	//
-	const MeshBase& mesh = mpatch->getMeshBase();
-	tfVao.create();
 	const Vbo* vbo;
 	const Vbo* vbo;
+	U32 size;
+	GLenum type;
+	U32 stride;
+	U32 offset;
 
 
-	// Positions
-	vbo = mesh.getVbo(MeshBase::VBO_POSITIONS);
-	if(vbo)
+	// Create the VAO
+	//
+	xfbVao.create();
+
+	static const Array<MeshBase::VertexAttribute, 6> attribs = {{
+		MeshBase::VA_POSITION, MeshBase::VA_NORMAL, MeshBase::VA_TANGENT,
+		MeshBase::VA_BONE_COUNT, MeshBase::VA_BONE_IDS, 
+		MeshBase::VA_BONE_WEIGHTS}};
+	U i = 0;
+	for(auto a : attribs)
 	{
 	{
-		tfVao.attachArrayBufferVbo(*vbo,
-			POSITION_LOC,
-			3,
-			GL_FLOAT,
-			false,
-			0,
-			NULL);
-	}
+		mpatch->getMeshBase().getVboInfo(
+			a, 0, vbo, size, type, stride, offset);
 
 
-	// Normals
-	vbo = mesh.getVbo(MeshBase::VBO_NORMALS);
-	if(vbo)
-	{
-		tfVao.attachArrayBufferVbo(*vbo,
-			NORMAL_LOC,
-			3,
-			GL_FLOAT,
-			false,
-			0,
-			NULL);
-	}
+		ANKI_ASSERT(vbo != nullptr);
 
 
-	// Tangents
-	vbo = mesh.getVbo(MeshBase::VBO_TANGENTS);
-	if(vbo)
-	{
-		tfVao.attachArrayBufferVbo(*vbo,
-			TANGENT_LOC,
-			4,
-			GL_FLOAT,
-			false,
-			0,
-			NULL);
+		xfbVao.attachArrayBufferVbo(vbo, i, size, type, false, stride, offset);
+
+		++i;
 	}
 	}
 
 
-	vbo = mesh.getVbo(Mesh::VBO_WEIGHTS);
-	ANKI_ASSERT(vbo);
-
-	tfVao.attachArrayBufferVbo(*vbo,
-		VERT_WEIGHT_BONES_NUM_LOC,
-		1,
-		GL_FLOAT,
-		GL_FALSE,
-		sizeof(MeshLoader::VertexWeight),
-		BUFFER_OFFSET(0));
-
-	tfVao.attachArrayBufferVbo(*vbo,
-		VERT_WEIGHT_BONE_IDS_LOC,
-		4,
-		GL_FLOAT,
-		GL_FALSE,
-		sizeof(MeshLoader::VertexWeight),
-		BUFFER_OFFSET(4));
-
-	tfVao.attachArrayBufferVbo(*vbo,
-		VERT_WEIGHT_WEIGHTS_LOC,
-		4,
-		GL_FLOAT,
-		GL_FALSE,
-		sizeof(MeshLoader::VertexWeight),
-		BUFFER_OFFSET(20));
+	// The indices VBO
+	mpatch->getMeshBase().getVboInfo(MeshBase::VA_INDICES, 0, vbo, size, type,
+			stride, offset);
+	ANKI_ASSERT(vbo != nullptr);
+	xfbVao.attachElementArrayBufferVbo(vbo);
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -162,7 +99,7 @@ SkinPatchNode::SkinPatchNode(const ModelPatch* modelPatch_,
 	uint movableFlags, Movable* movParent,
 	uint movableFlags, Movable* movParent,
 	CollisionShape* spatialCs)
 	CollisionShape* spatialCs)
 	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
 	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
-		Spatial(spatialCs)
+		Spatial(this, spatialCs)
 {
 {
 	skinModelPatch.reset(new SkinModelPatch(modelPatch_));
 	skinModelPatch.reset(new SkinModelPatch(modelPatch_));
 	Renderable::init(*this);
 	Renderable::init(*this);

+ 15 - 0
src/scene/Spatial.cpp

@@ -0,0 +1,15 @@
+#include "anki/scene/Spatial.h"
+#include "anki/scene/Octree.h"
+
+namespace anki {
+
+//==============================================================================
+Spatial::~Spatial()
+{
+	if(octreeNode)
+	{
+		octreeNode->removeSceneNode(sceneNode);
+	}
+}
+
+} // end namespace anki

+ 3 - 3
testapp/Main.cpp

@@ -302,7 +302,7 @@ void mainLoop()
 
 
 		// Sleep
 		// Sleep
 		//
 		//
-#if 0
+#if 1
 		timer.stop();
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{
 		{
@@ -359,7 +359,7 @@ void initSubsystems(int argc, char* argv[])
 	// Main renderer
 	// Main renderer
 	RendererInitializer initializer;
 	RendererInitializer initializer;
 	initializer.ms.ez.enabled = true;
 	initializer.ms.ez.enabled = true;
-	initializer.dbg.enabled = false;
+	initializer.dbg.enabled = true;
 	initializer.is.sm.bilinearEnabled = true;
 	initializer.is.sm.bilinearEnabled = true;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.pcfEnabled = false;
 	initializer.is.sm.pcfEnabled = false;
@@ -368,7 +368,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.pps.hdr.renderingQuality = 0.25;
 	initializer.pps.hdr.renderingQuality = 0.25;
 	initializer.pps.hdr.blurringDist = 0.0;
 	initializer.pps.hdr.blurringDist = 0.0;
 	initializer.pps.hdr.blurringIterationsCount = 2;
 	initializer.pps.hdr.blurringIterationsCount = 2;
-	initializer.pps.hdr.exposure = 5.0;
+	initializer.pps.hdr.exposure = 8.0;
 	initializer.pps.ssao.blurringIterationsNum = 4;
 	initializer.pps.ssao.blurringIterationsNum = 4;
 	initializer.pps.ssao.enabled = true;
 	initializer.pps.ssao.enabled = true;
 	initializer.pps.ssao.renderingQuality = 0.3;
 	initializer.pps.ssao.renderingQuality = 0.3;