Browse Source

Merging AsyncGL branch to trunk after 4 months of work

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
6dad4f27d4
100 changed files with 7443 additions and 5025 deletions
  1. 136 0
      docs/drafts/physics.md
  2. 15 0
      include/anki/AnKi.h
  3. 7 2
      include/anki/Config.h.cmake
  4. 34 0
      include/anki/Gl.h
  5. 3 0
      include/anki/Math.h
  6. 10 0
      include/anki/Renderer.h
  7. 30 0
      include/anki/Util.h
  8. 26 24
      include/anki/collision/Aabb.h
  9. 22 16
      include/anki/collision/CollisionShape.h
  10. 1 1
      include/anki/collision/Forward.h
  11. 87 87
      include/anki/collision/Frustum.h
  12. 1 1
      include/anki/collision/Functions.h
  13. 9 5
      include/anki/collision/LineSegment.h
  14. 21 23
      include/anki/collision/Obb.h
  15. 5 5
      include/anki/collision/Plane.h
  16. 5 5
      include/anki/collision/Ray.h
  17. 9 5
      include/anki/collision/Sphere.h
  18. 4 4
      include/anki/core/App.h
  19. 25 22
      include/anki/core/Counters.h
  20. 45 25
      include/anki/core/Logger.h
  21. 26 24
      include/anki/core/NativeWindow.h
  22. 6 3
      include/anki/core/NativeWindowSdl.h
  23. 10 5
      include/anki/core/StdinListener.h
  24. 0 17
      include/anki/gl/Common.h
  25. 0 53
      include/anki/gl/Drawcall.h
  26. 0 156
      include/anki/gl/Fbo.h
  27. 0 19
      include/anki/gl/Gl.h
  28. 43 73
      include/anki/gl/GlBuffer.h
  29. 88 0
      include/anki/gl/GlBufferHandle.h
  30. 118 0
      include/anki/gl/GlClientBuffer.h
  31. 47 0
      include/anki/gl/GlClientBufferHandle.h
  32. 262 0
      include/anki/gl/GlCommon.h
  33. 40 0
      include/anki/gl/GlContainerHandle.h
  34. 5 4
      include/anki/gl/GlError.h
  35. 85 0
      include/anki/gl/GlFramebuffer.h
  36. 43 0
      include/anki/gl/GlFramebufferHandle.h
  37. 368 0
      include/anki/gl/GlHandle.h
  38. 46 0
      include/anki/gl/GlHandleDeferredDeleter.h
  39. 156 0
      include/anki/gl/GlJobChain.h
  40. 170 0
      include/anki/gl/GlJobChainHandle.h
  41. 125 0
      include/anki/gl/GlJobManager.h
  42. 64 0
      include/anki/gl/GlManager.h
  43. 10 70
      include/anki/gl/GlObject.h
  44. 227 0
      include/anki/gl/GlOperations.h
  45. 151 0
      include/anki/gl/GlProgram.h
  46. 61 0
      include/anki/gl/GlProgramHandle.h
  47. 61 0
      include/anki/gl/GlProgramPipeline.h
  48. 58 0
      include/anki/gl/GlProgramPipelineHandle.h
  49. 25 110
      include/anki/gl/GlState.h
  50. 35 0
      include/anki/gl/GlSync.h
  51. 41 0
      include/anki/gl/GlSyncHandles.h
  52. 164 0
      include/anki/gl/GlTexture.h
  53. 69 0
      include/anki/gl/GlTextureHandle.h
  54. 0 61
      include/anki/gl/Query.h
  55. 0 453
      include/anki/gl/ShaderProgram.h
  56. 0 329
      include/anki/gl/Texture.h
  57. 0 164
      include/anki/gl/Vao.h
  58. 13 13
      include/anki/input/Input.h
  59. 1 1
      include/anki/input/InputSdl.h
  60. 45 45
      include/anki/math/Axisang.h
  61. 1 1
      include/anki/math/CommonIncludes.h
  62. 1 0
      include/anki/math/CommonSrc.h
  63. 12 12
      include/anki/math/Euler.h
  64. 8 8
      include/anki/math/F16.h
  65. 9 0
      include/anki/math/Forward.h
  66. 48 5
      include/anki/math/Functions.h
  67. 779 0
      include/anki/math/Mat.h
  68. 28 598
      include/anki/math/Mat3.h
  69. 126 0
      include/anki/math/Mat3x4.h
  70. 47 494
      include/anki/math/Mat4.h
  71. 41 187
      include/anki/math/Mat4.inl.h
  72. 64 182
      include/anki/math/Quat.h
  73. 38 36
      include/anki/math/Transform.h
  74. 2167 0
      include/anki/math/Vec.h
  75. 35 286
      include/anki/math/Vec2.h
  76. 30 297
      include/anki/math/Vec3.h
  77. 44 391
      include/anki/math/Vec4.h
  78. 44 164
      include/anki/math/Vec4.inl.h
  79. 0 14
      include/anki/misc/ConfigSet.h
  80. 12 12
      include/anki/physics/Ragdoll.h
  81. 13 9
      include/anki/renderer/Bl.h
  82. 7 3
      include/anki/renderer/Bs.h
  83. 18 13
      include/anki/renderer/Dbg.h
  84. 46 29
      include/anki/renderer/DebugDrawer.h
  85. 8 3
      include/anki/renderer/Deformer.h
  86. 42 23
      include/anki/renderer/Drawer.h
  87. 8 3
      include/anki/renderer/Ez.h
  88. 41 28
      include/anki/renderer/Hdr.h
  89. 58 51
      include/anki/renderer/Is.h
  90. 32 19
      include/anki/renderer/Lf.h
  91. 10 2
      include/anki/renderer/MainRenderer.h
  92. 38 17
      include/anki/renderer/Ms.h
  93. 30 20
      include/anki/renderer/Pps.h
  94. 91 70
      include/anki/renderer/Renderer.h
  95. 18 16
      include/anki/renderer/RenderingPass.h
  96. 27 20
      include/anki/renderer/Sm.h
  97. 32 29
      include/anki/renderer/Ssao.h
  98. 24 20
      include/anki/renderer/Tiler.h
  99. 122 138
      include/anki/resource/Material.h
  100. 86 0
      include/anki/resource/MaterialProgramCreator.h

+ 136 - 0
docs/drafts/physics.md

@@ -0,0 +1,136 @@
+
+Physics engine spec
+===================
+
+This is a spec for a physics implementation based on ODE.
+
+Plan
+----
+
+1. Make changes to collision
+2. Test that all is working
+
+Changes to collision
+--------------------
+
+1. Add compound functionality
+2. Remove frustums to another level of functionality
+3. Remove Ray and rename LineSegment to Ray
+4. Add capsule shape
+5. Add trimesh shape
+6. Change the collision matrix to support penetration
+
+### Add compound functionality
+
+Every shape has 2 pointers pointing to previous and next shape. 
+
+Some methods
+(testPlane, transform, computeAabb, accept) will have to propagade to the next
+shape and so on. The pure virtuals will have to change names everywhere to
+xxxSingle (eg testPlaneSingle) and the CollisionShape will have the xxx names.
+The CollisionShape::testPlane for example will propagade to _this_ and the 
+children.
+
+Assertions will make sure that the methods start from the root shape.
+
+Add copy constructor and call this in derived classes. Assert if trying to 
+copy compound.
+
+### Remove frustums to another level of functionality
+
+The Frustum will look like:
+
+```
+virtual CollisionShape& getCollisionShape() = 0;
+Bool insideFrustum(const CollisionShape& b) const;
+virtual void computeProjectionMatrix(Mat4& m) const = 0;
+virtual void setTransform(const Transform& trf) = 0;
+
+void transformPlanes(const Transform& trf);
+
+Transform m_trf;
+F32 m_near;
+F32 m_far;
+Plane m_planes[6];
+```
+
+The PerspectiveFrustum will look like:
+
+```
+F32 m_fovX;
+F32 m_fovY;
+Ray m_rays[4]; // Compound
+```
+
+Optimize setTransform(). There is no need to recalculate.
+
+
+ODE physics
+-----------
+
+dxGeom:
+- type
+- flags
+- data: used defined void*
+- body: the body
+- final_posr: pointer to position
+- offset_posr: pointer to position relative to the body
+- body_next: pointer to dxGeom
+- [other pointers to dxGeom]
+- parent_space: pointer to space
+- category_bits & collide_bits: some flags
+- aabb: cached AABB
+
+dxConvex:
+- planes
+- positions
+- indices for the above positions
+- saabb: A static AABB
+- edges: Array of edges
+
+dxSphere:
+- radius
+
+dxBox:
+- side: Same as extend
+
+dxPlane
+- p: 4 plane numbers
+
+dxCylinded:
+- radius: Along Z axis
+- lz: Length along Z axis
+
+Class diagram of physics
+------------------------
+
+The source tree is:
+```
+-- src
+   |-- math
+   |-- collision
+   |-- physics
+```
+
+### Collision shape
+
+```
+PhysicsWorld
+init
+destroy
+castRay
+```
+
+RigidBody
+<constructor>: type, init_data_union
+setPosition
+setRotation
+getPosition
+getRotation
+getMoveUpdateTimestamp
+addForce
+
+CharacterController
+
+
+

+ 15 - 0
include/anki/AnKi.h

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

+ 7 - 2
include/anki/Config.h.cmake

@@ -9,6 +9,7 @@
 #define ANKI_REVISION ${ANKI_REVISION}
 
 #define ANKI_DEBUG ${ANKI_DEBUG}
+#define ANKI_ASSERTIONS ANKI_DEBUG
 
 // Operating system
 #define ANKI_OS_LINUX 1 
@@ -108,8 +109,6 @@
 //==============================================================================
 
 // General config
-#define ANKI_MAX_MULTIDRAW_PRIMITIVES 64
-#define ANKI_MAX_INSTANCES 32
 #define ANKI_SAFE_ALIGNMENT 16
 
 // Renderer and rendering related config options
@@ -134,6 +133,12 @@
 /// If true then we can place spatials in a thread-safe way
 #define ANKI_CFG_OCTREE_THREAD_SAFE 1
 
+// GL
+#define ANKI_GL_MAX_MIPMAPS 32
+#define ANKI_GL_MAX_TEXTURE_LAYERS 32
+#define ANKI_GL_MAX_SUB_DRAWCALLS 64
+#define ANKI_GL_MAX_INSTANCES 32
+
 //==============================================================================
 // Other                                                                       =
 //==============================================================================

+ 34 - 0
include/anki/Gl.h

@@ -0,0 +1,34 @@
+/// @file
+/// This file contains the public OpenGL headers and all the GL classes that
+/// the rest of AnKi should use
+
+#ifndef ANKI_GL_H
+#define ANKI_GL_H
+
+/// @defgroup opengl OpenGL
+/// @ingroup anki_private
+
+/// @defgroup opengl_private OpenGL private interfaces
+/// Other modules should not use them.
+/// @ingroup opengl
+
+/// @defgroup opengl_containers OpenGL container objects
+/// The containers of OpenGL
+/// @ingroup opengl
+
+/// @defgroup opengl_other OpenGL uncategorized interfaces 
+/// @ingroup opengl
+
+#include "anki/gl/GlBufferHandle.h"
+#include "anki/gl/GlTextureHandle.h"
+#include "anki/gl/GlProgramHandle.h"
+
+#include "anki/gl/GlFramebufferHandle.h"
+#include "anki/gl/GlProgramPipelineHandle.h"
+
+#include "anki/gl/GlOperations.h"
+
+#include "anki/gl/GlJobChainHandle.h"
+#include "anki/gl/GlManager.h"
+
+#endif

+ 3 - 0
include/anki/Math.h

@@ -5,4 +5,7 @@
 #include "anki/math/CommonSrc.h"
 #include "anki/math/Functions.h"
 
+/// @defgroup math Math library
+/// @ingroup anki_public
+
 #endif

+ 10 - 0
include/anki/Renderer.h

@@ -0,0 +1,10 @@
+#ifndef ANKI_RENDERER_H
+#define ANKI_RENDERER_H
+
+#include "anki/renderer/MainRenderer.h"
+
+/// @defgroup renderer Renderering system
+/// @ingroup anki_public
+
+#endif
+

+ 30 - 0
include/anki/Util.h

@@ -23,4 +23,34 @@
 #include "anki/util/Vector.h"
 #include "anki/util/Visitor.h"
 
+/// @defgroup util Utilities (like STL)
+/// @ingroup anki_public
+
+/// @defgroup util_containers STL compatible containers
+/// @ingroup util
+
+/// @defgroup util_memory Memory management
+/// @ingroup util
+
+/// @defgroup util_file Filesystem
+/// @ingroup util
+
+/// @defgroup util_time Time
+/// @ingroup util
+
+/// @defgroup util_patterns Design patterns
+/// @ingroup util
+
+/// @defgroup util_system System
+/// @ingroup util
+
+/// @defgroup util_file Filesystem
+/// @ingroup util
+
+/// @defgroup util_thread Threading
+/// @ingroup util
+
+/// @defgroup util_other Other interfaces
+/// @ingroup util
+
 #endif

+ 26 - 24
include/anki/collision/Aabb.h

@@ -16,17 +16,19 @@ public:
 	/// @name Constructors
 	/// @{
 	Aabb()
-		: CollisionShape(CST_AABB)
+		: CollisionShape(Type::AABB)
 	{}
 
-	Aabb(const Vec3& min_, const Vec3& max_)
-		: CollisionShape(CST_AABB), min(min_), max(max_)
+	Aabb(const Vec3& min, const Vec3& max)
+		: CollisionShape(Type::AABB), m_min(min), m_max(max)
 	{
-		ANKI_ASSERT(min < max);
+		ANKI_ASSERT(m_min < m_max);
 	}
 
 	Aabb(const Aabb& b)
-		: CollisionShape(CST_AABB), min(b.min), max(b.max)
+		:	CollisionShape(Type::AABB), 
+			m_min(b.m_min), 
+			m_max(b.m_max)
 	{}
 	/// @}
 
@@ -34,28 +36,28 @@ public:
 	/// @{
 	const Vec3& getMin() const
 	{
-		return min;
+		return m_min;
 	}
 	Vec3& getMin()
 	{
-		return min;
+		return m_min;
 	}
 	void setMin(const Vec3& x)
 	{
-		min = x;
+		m_min = x;
 	}
 
 	const Vec3& getMax() const
 	{
-		return max;
+		return m_max;
 	}
 	Vec3& getMax()
 	{
-		return max;
+		return m_max;
 	}
 	void setMax(const Vec3& x)
 	{
-		max = x;
+		m_max = x;
 	}
 	/// @}
 
@@ -63,8 +65,8 @@ public:
 	/// @{
 	Aabb& operator=(const Aabb& b)
 	{
-		min = b.min;
-		max = b.max;
+		m_min = b.m_min;
+		m_max = b.m_max;
 		return *this;
 	}
 	/// @}
@@ -96,8 +98,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& b) const
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& b) const
 	{
 		b = *this;
 	}
@@ -116,8 +118,8 @@ public:
 private:
 	/// @name Data
 	/// @{
-	Vec3 min;
-	Vec3 max;
+	Vec3 m_min;
+	Vec3 m_max;
 	/// @}
 };
 /// @}
@@ -128,8 +130,8 @@ void Aabb::set(const Container& container)
 {
 	ANKI_ASSERT(container.size() >= 1);
 
-	min = container.front();
-	max = min;
+	m_min = container.front();
+	m_max = m_min;
 
 	// for all the Vec3s calc the max and min
 	typename Container::const_iterator it = container.begin() + 1;
@@ -137,18 +139,18 @@ void Aabb::set(const Container& container)
 	{
 		for(U j = 0; j < 3; j++)
 		{
-			if((*it)[j] > max[j])
+			if((*it)[j] > m_max[j])
 			{
-				max[j] = (*it)[j];
+				m_max[j] = (*it)[j];
 			}
-			else if((*it)[j] < min[j])
+			else if((*it)[j] < m_min[j])
 			{
-				min[j] = (*it)[j];
+				m_min[j] = (*it)[j];
 			}
 		}
 	}
 }
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 22 - 16
include/anki/collision/CollisionShape.h

@@ -5,6 +5,7 @@
 #include "anki/collision/CollisionAlgorithms.h"
 #include "anki/Math.h"
 #include "anki/util/StdTypes.h"
+#include "anki/util/Visitor.h"
 
 namespace anki {
 
@@ -17,20 +18,21 @@ class CollisionShape
 {
 public:
 	/// Collision shape type
-	enum CollisionShapeType
+	enum class Type: U8
 	{
-		CST_LINE_SEG,
-		CST_RAY,
-		CST_PLANE,
-		CST_SPHERE,
-		CST_AABB,
-		CST_OBB,
-		CST_FRUSTUM,
+		LINE_SEG,
+		RAY,
+		PLANE,
+		SPHERE,
+		AABB,
+		OBB,
+		FRUSTUM,
 	};
 
 	/// Generic mutable visitor
-	struct MutableVisitor
+	class MutableVisitor
 	{
+	public:
 		virtual ~MutableVisitor()
 		{}
 
@@ -44,8 +46,9 @@ public:
 	};
 
 	/// Generic const visitor
-	struct ConstVisitor
+	class ConstVisitor
 	{
+	public:
 		virtual ~ConstVisitor()
 		{}
 
@@ -60,16 +63,19 @@ public:
 
 	/// @name Constructors & destructor
 	/// @{
-	CollisionShape(CollisionShapeType cid_)
-		: cid(cid_)
+	CollisionShape(Type cid)
+		: m_cid(cid)
+	{}
+
+	virtual ~CollisionShape()
 	{}
 	/// @}
 
 	/// @name Accessors
 	/// @{
-	CollisionShapeType getCollisionShapeType() const
+	Type getType() const
 	{
-		return cid;
+		return m_cid;
 	}
 	/// @}
 
@@ -90,7 +96,7 @@ public:
 	virtual void transform(const Transform& trf) = 0;
 
 	/// Get the AABB
-	void toAabb(Aabb&) const;
+	virtual void computeAabb(Aabb&) const = 0;
 
 	/// Visitor accept
 	virtual void accept(MutableVisitor&) = 0;
@@ -100,7 +106,7 @@ public:
 private:
 	/// Keep an ID to avoid (in some cases) the visitor and thus the cost of
 	/// virtuals
-	CollisionShapeType cid;
+	Type m_cid;
 };
 /// @}
 

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

@@ -13,6 +13,6 @@ class Ray;
 class Sphere;
 class Aabb;
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 87 - 87
include/anki/collision/Frustum.h

@@ -5,41 +5,41 @@
 #include "anki/collision/Plane.h"
 #include "anki/collision/Obb.h"
 #include "anki/Math.h"
-#include <array>
+#include "anki/util/Array.h"
 
 namespace anki {
 
 /// @addtogroup Collision
 /// @{
 
+/// Frustum type
+enum class FrustumType: U8
+{
+	PERSPECTIVE,
+	ORTHOGRAPHIC
+};
+
+/// The 6 frustum planes
+enum class FrustumPlane: U8
+{
+	NEAR,
+	FAR,
+	LEFT,
+	RIGHT,
+	TOP,
+	BOTTOM,
+	COUNT ///< Number of planes
+};
+
 /// Frustum collision shape. This shape consists from 6 planes. The planes are
 /// being used to find shapes that are inside the frustum
 class Frustum: public CollisionShape
 {
 public:
-	/// Frustum type
-	enum FrustumType
-	{
-		FT_PERSPECTIVE,
-		FT_ORTHOGRAPHIC
-	};
-
-	/// The 6 planes
-	enum FrustrumPlane
-	{
-		FP_NEAR,
-		FP_FAR,
-		FP_LEFT,
-		FP_RIGHT,
-		FP_TOP,
-		FP_BOTTOM,
-		FP_COUNT ///< Number of planes
-	};
-
 	/// @name Constructors
 	/// @{
-	Frustum(FrustumType type_)
-		: CollisionShape(CST_FRUSTUM), type(type_)
+	Frustum(FrustumType type)
+		: CollisionShape(Type::FRUSTUM), m_type(type)
 	{}
 
 	virtual ~Frustum()
@@ -50,26 +50,26 @@ public:
 	/// @{
 	FrustumType getFrustumType() const
 	{
-		return type;
+		return m_type;
 	}
 
 	F32 getNear() const
 	{
-		return near;
+		return m_near;
 	}
 	void setNear(const F32 x)
 	{
-		near = x;
+		m_near = x;
 		recalculate();
 	}
 
 	F32 getFar() const
 	{
-		return far;
+		return m_far;
 	}
 	void setFar(const F32 x)
 	{
-		far = x;
+		m_far = x;
 		recalculate();
 	}
 	/// @}
@@ -103,19 +103,19 @@ public:
 	virtual void setTransform(const Transform& trf) = 0;
 
 	/// Implements CollisionShape::toAbb
-	void toAabb(Aabb& aabb) const;
+	void computeAabb(Aabb& aabb) const;
 
 protected:
 	/// @name Viewing variables
 	/// @{
-	F32 near = 0.0;
-	F32 far = 0.0;
+	F32 m_near = 0.0;
+	F32 m_far = 0.0;
 	/// @}
 
 	/// Used to check against the frustum
-	std::array<Plane, FP_COUNT> planes;
+	Array<Plane, (U)FrustumPlane::COUNT> m_planes;
 
-	Transform trf = Transform::getIdentity(); ///< Retain the transformation
+	Transform m_trf = Transform::getIdentity(); ///< Retain the transformation
 
 	/// Called when a viewing variable changes. It recalculates the planes and
 	/// the other variables
@@ -126,14 +126,14 @@ protected:
 
 	void transformPlanes()
 	{
-		for(Plane& p : planes)
+		for(Plane& p : m_planes)
 		{
-			p.transform(trf);
+			p.transform(m_trf);
 		}
 	}
 
 private:
-	FrustumType type;
+	FrustumType m_type;
 };
 
 /// Frustum shape for perspective cameras
@@ -145,21 +145,21 @@ public:
 
 	/// Default
 	PerspectiveFrustum()
-		: Frustum(FT_PERSPECTIVE)
+		: Frustum(FrustumType::PERSPECTIVE)
 	{}
 
 	/// Copy
 	PerspectiveFrustum(const PerspectiveFrustum& b)
-		: Frustum(FT_PERSPECTIVE)
+		: Frustum(FrustumType::PERSPECTIVE)
 	{
 		*this = b;
 	}
 
 	/// Set all
-	PerspectiveFrustum(F32 fovX_, F32 fovY_, F32 near_, F32 far_)
-		: Frustum(FT_PERSPECTIVE)
+	PerspectiveFrustum(F32 fovX, F32 fovY, F32 near, F32 far)
+		: Frustum(FrustumType::PERSPECTIVE)
 	{
-		setAll(fovX_, fovY_, near_, far_);
+		setAll(fovX, fovY, near, far);
 	}
 	/// @}
 
@@ -167,37 +167,37 @@ public:
 	/// @{
 	F32 getFovX() const
 	{
-		return fovX;
+		return m_fovX;
 	}
 	void setFovX(F32 ang)
 	{
-		fovX = ang;
+		m_fovX = ang;
 		recalculate();
 	}
 
 	F32 getFovY() const
 	{
-		return fovY;
+		return m_fovY;
 	}
 	void setFovY(F32 ang)
 	{
-		fovY = ang;
+		m_fovY = ang;
 		recalculate();
 	}
 
 	/// Set all the parameters and recalculate the planes and shape
-	void setAll(F32 fovX_, F32 fovY_, F32 near_, F32 far_)
+	void setAll(F32 fovX, F32 fovY, F32 near, F32 far)
 	{
-		fovX = fovX_;
-		fovY = fovY_,
-		near = near_;
-		far = far_;
+		m_fovX = fovX;
+		m_fovY = fovY,
+		m_near = near;
+		m_far = far;
 		recalculate();
 	}
 
 	const Array<Vec3, 4>& getDirections() const
 	{
-		return dirs;
+		return m_dirs;
 	}
 	/// @}
 
@@ -224,20 +224,20 @@ public:
 	/// Implements Frustum::calculateProjectionMatrix
 	Mat4 calculateProjectionMatrix() const;
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& aabb) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& aabb) const;
 
 private:
 	/// @name Viewing variables
 	/// @{
-	F32 fovX = 0.0;
-	F32 fovY = 0.0;
+	F32 m_fovX = 0.0;
+	F32 m_fovY = 0.0;
 	/// @}
 
 	/// @name Shape
 	/// @{
-	Vec3 eye; ///< The eye point
-	Array<Vec3, 4> dirs; ///< Directions
+	Vec3 m_eye; ///< The eye point
+	Array<Vec3, 4> m_dirs; ///< Directions
 	/// @}
 
 	/// Implements CollisionShape::recalculate. Recalculate:
@@ -259,22 +259,22 @@ public:
 
 	/// Default
 	OrthographicFrustum()
-		: Frustum(FT_ORTHOGRAPHIC)
+		: Frustum(FrustumType::ORTHOGRAPHIC)
 	{}
 
 	/// Copy
 	OrthographicFrustum(const OrthographicFrustum& b)
-		: Frustum(FT_ORTHOGRAPHIC)
+		: Frustum(FrustumType::ORTHOGRAPHIC)
 	{
 		*this = b;
 	}
 
 	/// Set all
-	OrthographicFrustum(F32 left_, F32 right_, F32 near_,
-		F32 far_, F32 top_, F32 bottom_)
-		: Frustum(FT_ORTHOGRAPHIC)
+	OrthographicFrustum(F32 left, F32 right, F32 near,
+		F32 far, F32 top, F32 bottom)
+		: Frustum(FrustumType::ORTHOGRAPHIC)
 	{
-		setAll(left_, right_, near_, far_, top_, bottom_);
+		setAll(left, right, near, far, top, bottom);
 	}
 	/// @}
 
@@ -282,61 +282,61 @@ public:
 	/// @{
 	F32 getLeft() const
 	{
-		return left;
+		return m_left;
 	}
 	void setLeft(F32 f)
 	{
-		left = f;
+		m_left = f;
 		recalculate();
 	}
 
 	F32 getRight() const
 	{
-		return right;
+		return m_right;
 	}
 	void setRight(F32 f)
 	{
-		right = f;
+		m_right = f;
 		recalculate();
 	}
 
 	F32 getTop() const
 	{
-		return top;
+		return m_top;
 	}
 	void setTop(F32 f)
 	{
-		top = f;
+		m_top = f;
 		recalculate();
 	}
 
 	F32 getBottom() const
 	{
-		return bottom;
+		return m_bottom;
 	}
 	void setBottom(F32 f)
 	{
-		bottom = f;
+		m_bottom = f;
 		recalculate();
 	}
 
 	/// Set all
-	void setAll(F32 left_, F32 right_, F32 near_,
-		F32 far_, F32 top_, F32 bottom_)
-	{
-		left = left_;
-		right = right_;
-		near = near_;
-		far = far_;
-		top = top_;
-		bottom = bottom_;
+	void setAll(F32 left, F32 right, F32 near,
+		F32 far, F32 top, F32 bottom)
+	{
+		m_left = left;
+		m_right = right;
+		m_near = near;
+		m_far = far;
+		m_top = top;
+		m_bottom = bottom;
 		recalculate();
 	}
 
 	/// Needed for debug drawing
 	const Obb& getObb() const
 	{
-		return obb;
+		return m_obb;
 	}
 	/// @}
 
@@ -346,7 +346,7 @@ public:
 	/// Implements CollisionShape::testPlane
 	F32 testPlane(const Plane& p) const
 	{
-		return obb.testPlane(p);
+		return m_obb.testPlane(p);
 	}
 
 	/// Override Frustum::transform
@@ -355,10 +355,10 @@ public:
 	/// Implements Frustum::setTransform
 	void setTransform(const Transform& trf);
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& aabb) const
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& aabb) const
 	{
-		obb.toAabb(aabb);
+		m_obb.computeAabb(aabb);
 	}
 
 	/// Implements Frustum::calculateProjectionMatrix
@@ -375,12 +375,12 @@ public:
 private:
 	/// @name Viewing variables
 	/// @{
-	F32 left = 0.0, right = 0.0, top = 0.0, bottom = 0.0;
+	F32 m_left = 0.0, m_right = 0.0, m_top = 0.0, m_bottom = 0.0;
 	/// @}
 
 	/// @name Shape
 	/// @{
-	Obb obb; ///< Including shape
+	Obb m_obb; ///< Including shape
 	/// @}
 
 	/// Implements CollisionShape::recalculate. Recalculate @a planes and
@@ -390,7 +390,7 @@ private:
 	/// Transform the @a obb using @a Frustrum::trf
 	void transformShape()
 	{
-		obb.transform(trf);
+		m_obb.transform(m_trf);
 	}
 };
 /// @}

+ 1 - 1
include/anki/collision/Functions.h

@@ -16,7 +16,7 @@ namespace anki {
 ///
 /// @note plane_count * 8 muls, plane_count sqrt
 extern void extractClipPlanes(const Mat4& mvp, 
-	Plane* planes[Frustum::FP_COUNT]);
+	Plane* planes[(U)FrustumPlane::COUNT]);
 
 /// @}
 

+ 9 - 5
include/anki/collision/LineSegment.h

@@ -17,15 +17,19 @@ public:
 	/// @name Constructors
 	/// @{
 	LineSegment()
-		: CollisionShape(CST_LINE_SEG)
+		: CollisionShape(Type::LINE_SEG)
 	{}
 
 	LineSegment(const Vec3& origin_, const Vec3& direction)
-		: CollisionShape(CST_LINE_SEG), origin(origin_), dir(direction)
+		:	CollisionShape(Type::LINE_SEG), 
+			origin(origin_), 
+			dir(direction)
 	{}
 
 	LineSegment(const LineSegment& b)
-		: CollisionShape(CST_LINE_SEG), origin(b.origin), dir(b.dir)
+		:	CollisionShape(Type::LINE_SEG), 
+			origin(b.origin), 
+			dir(b.dir)
 	{}
 	/// @}
 
@@ -95,8 +99,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& b) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& b) const;
 
 	LineSegment getTransformed(const Transform& transform) const;
 

+ 21 - 23
include/anki/collision/Obb.h

@@ -16,9 +16,7 @@ class Obb: public CollisionShape
 public:
 	/// @name Constructors
 	/// @{
-	Obb()
-		: CollisionShape(CST_OBB)
-	{}
+	Obb();
 
 	Obb(const Obb& b);
 
@@ -29,41 +27,41 @@ public:
 	/// @{
 	const Vec3& getCenter() const
 	{
-		return center;
+		return m_center;
 	}
 	Vec3& getCenter()
 	{
-		return center;
+		return m_center;
 	}
 	void setCenter(const Vec3& x)
 	{
-		center = x;
+		m_center = x;
 	}
 
 	const Mat3& getRotation() const
 	{
-		return rotation;
+		return m_rotation;
 	}
 	Mat3& getRotation()
 	{
-		return rotation;
+		return m_rotation;
 	}
 	void setRotation(const Mat3& x)
 	{
-		rotation = x;
+		m_rotation = x;
 	}
 
 	const Vec3& getExtend() const
 	{
-		return extends;
+		return m_extends;
 	}
 	Vec3& getExtend()
 	{
-		return extends;
+		return m_extends;
 	}
 	void setExtend(const Vec3& x)
 	{
-		extends = x;
+		m_extends = x;
 	}
 	/// @}
 
@@ -71,9 +69,9 @@ public:
 	/// @{
 	Obb& operator=(const Obb& b)
 	{
-		center = b.center;
-		rotation = b.rotation;
-		extends = b.extends;
+		m_center = b.m_center;
+		m_rotation = b.m_rotation;
+		m_extends = b.m_extends;
 		return *this;
 	}
 	/// @}
@@ -105,8 +103,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& aabb) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& aabb) const;
 
 	Obb getTransformed(const Transform& transform) const;
 
@@ -124,11 +122,11 @@ public:
 public:
 	/// @name Data
 	/// @{
-	Vec3 center;
-	Mat3 rotation;
+	Vec3 m_center;
+	Mat3 m_rotation;
 	/// With identity rotation this points to max (front, right, top in
 	/// our case)
-	Vec3 extends;
+	Vec3 m_extends;
 	/// @}
 };
 /// @}
@@ -162,9 +160,9 @@ void Obb::set(const Container& container)
 	}
 
 	// set the locals
-	center = (max + min) / 2.0;
-	rotation = Mat3::getIdentity();
-	extends = max - center;
+	m_center = (max + min) / 2.0;
+	m_rotation = Mat3::getIdentity();
+	m_extends = max - m_center;
 }
 
 } // end namespace

+ 5 - 5
include/anki/collision/Plane.h

@@ -18,7 +18,7 @@ public:
 
 	/// Default constructor
 	Plane()
-		: CollisionShape(CST_PLANE)
+		: CollisionShape(Type::PLANE)
 	{}
 
 	/// Copy constructor
@@ -29,14 +29,14 @@ public:
 
 	/// @see setFrom3Points
 	Plane(const Vec3& p0, const Vec3& p1, const Vec3& p2)
-		: CollisionShape(CST_PLANE)
+		: CollisionShape(Type::PLANE)
 	{
 		setFrom3Points(p0, p1, p2);
 	}
 
 	/// @see setFromPlaneEquation
 	Plane(F32 a, F32 b, F32 c, F32 d)
-		: CollisionShape(CST_PLANE)
+		: CollisionShape(Type::PLANE)
 	{
 		setFromPlaneEquation(a, b, c, d);
 	}
@@ -108,8 +108,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& b) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& b) const;
 
 	/// Return the transformed
 	Plane getTransformed(const Transform& trf) const;

+ 5 - 5
include/anki/collision/Ray.h

@@ -18,17 +18,17 @@ public:
 
 	/// Default constructor
 	Ray()
-		: CollisionShape(CST_RAY)
+		: CollisionShape(Type::RAY)
 	{}
 
 	/// Copy constructor
 	Ray(const Ray& b)
-		: CollisionShape(CST_RAY), origin(b.origin), dir(b.dir)
+		: CollisionShape(Type::RAY), origin(b.origin), dir(b.dir)
 	{}
 
 	/// Constructor
 	Ray(const Vec3& origin_, const Vec3& direction_)
-		: CollisionShape(CST_RAY), origin(origin_), dir(direction_)
+		: CollisionShape(Type::RAY), origin(origin_), dir(direction_)
 	{}
 	/// @}
 
@@ -98,8 +98,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& aabb) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& aabb) const;
 
 	Ray getTransformed(const Transform& transform) const;
 

+ 9 - 5
include/anki/collision/Sphere.h

@@ -18,17 +18,21 @@ public:
 
 	/// Default constructor
 	Sphere()
-		: CollisionShape(CST_SPHERE)
+		: CollisionShape(Type::SPHERE)
 	{}
 
 	/// Copy constructor
 	Sphere(const Sphere& b)
-		: CollisionShape(CST_SPHERE), center(b.center), radius(b.radius)
+		:	CollisionShape(Type::SPHERE), 
+			center(b.center), 
+			radius(b.radius)
 	{}
 
 	/// Constructor
 	Sphere(const Vec3& center_, F32 radius_)
-		: CollisionShape(CST_SPHERE), center(center_), radius(radius_)
+		:	CollisionShape(Type::SPHERE), 
+			center(center_), 
+			radius(radius_)
 	{}
 	/// @}
 
@@ -98,8 +102,8 @@ public:
 		*this = getTransformed(trf);
 	}
 
-	/// Implements CollisionShape::toAabb
-	void toAabb(Aabb& b) const;
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(Aabb& b) const;
 
 	Sphere getTransformed(const Transform& transform) const;
 

+ 4 - 4
include/anki/core/App.h

@@ -45,12 +45,12 @@ public:
 		timerTick = x;
 	}
 
-	const std::string& getSettingsPath() const
+	const String& getSettingsPath() const
 	{
 		return settingsPath;
 	}
 
-	const std::string& getCachePath() const
+	const String& getCachePath() const
 	{
 		return cachePath;
 	}
@@ -68,9 +68,9 @@ public:
 
 private:
 	/// The path that holds the configuration
-	std::string settingsPath;
+	String settingsPath;
 	/// This is used as a cache
-	std::string cachePath;
+	String cachePath;
 	F32 timerTick;
 
 	void initDirs();

+ 25 - 22
include/anki/core/Counters.h

@@ -6,21 +6,23 @@
 namespace anki {
 
 /// Enumeration of counters
-enum Counter
+enum class Counter
 {
-	C_FPS,
-	C_MAIN_RENDERER_TIME,
-	C_RENDERER_MS_TIME,
-	C_RENDERER_IS_TIME,
-	C_RENDERER_PPS_TIME,
-	C_RENDERER_SHADOW_PASSES,
-	C_RENDERER_DRAWCALLS_COUNT,
-	C_RENDERER_VERTICES_COUNT,
-	C_RENDERER_LIGHTS_COUNT,
-	C_SCENE_UPDATE_TIME,
-	C_SWAP_BUFFERS_TIME,
-
-	C_COUNT
+	FPS,
+	MAIN_RENDERER_TIME,
+	RENDERER_MS_TIME,
+	RENDERER_IS_TIME,
+	RENDERER_PPS_TIME,
+	RENDERER_SHADOW_PASSES,
+	RENDERER_LIGHTS_COUNT,
+	SCENE_UPDATE_TIME,
+	SWAP_BUFFERS_TIME,
+	GL_CLIENT_WAIT_TIME,
+	GL_SERVER_WAIT_TIME,
+	GL_DRAWCALLS_COUNT,
+	GL_VERTICES_COUNT,
+
+	COUNT
 };
 
 /// The counters manager. It's been used with a singleton
@@ -47,11 +49,11 @@ public:
 	void stopTimerIncreaseCounter(Counter counter);
 
 private:
-	File perframeFile;
-	File perrunFile;
-	Vector<U64> perframeValues;
-	Vector<U64> perrunValues;
-	Vector<HighRezTimer::Scalar> counterTimes;
+	File m_perframeFile;
+	File m_perrunFile;
+	Vector<U64> m_perframeValues;
+	Vector<U64> m_perrunValues;
+	Vector<HighRezTimer::Scalar> m_counterTimes;
 };
 
 /// The singleton of the counters manager
@@ -61,13 +63,14 @@ typedef Singleton<CountersManager> CountersManagerSingleton;
 
 #if ANKI_ENABLE_COUNTERS
 #	define ANKI_COUNTER_INC(counter_, val_) \
-		CountersManagerSingleton::get().increaseCounter(counter_, val_)
+		CountersManagerSingleton::get().increaseCounter(Counter::counter_, val_)
 
 #	define ANKI_COUNTER_START_TIMER(counter_) \
-		CountersManagerSingleton::get().startTimer(counter_)
+		CountersManagerSingleton::get().startTimer(Counter::counter_)
 
 #	define ANKI_COUNTER_STOP_TIMER_INC(counter_) \
-		CountersManagerSingleton::get().stopTimerIncreaseCounter(counter_)
+		CountersManagerSingleton::get(). \
+		stopTimerIncreaseCounter(Counter::counter_)
 
 #	define ANKI_COUNTERS_RESOLVE_FRAME() \
 		CountersManagerSingleton::get().resolveFrame()

+ 45 - 25
include/anki/core/Logger.h

@@ -19,59 +19,76 @@ class Logger
 {
 public:
 	/// Logger message type
-	enum LoggerMessageType
+	enum class MessageType: U8
 	{
-		LMT_NORMAL,
-		LMT_ERROR,
-		LMT_WARNING
+		NORMAL,
+		ERROR,
+		WARNING
 	};
 
 	/// Logger init mask
-	enum LoggerInitFlags
+	enum class InitFlags: U8
 	{
-		INIT_SYSTEM_MESSAGE_HANDLER = 1 << 0,
-		INIT_LOG_FILE_MESSAGE_HANDLER  = 1 << 1
+		NONE = 0,
+		WITH_SYSTEM_MESSAGE_HANDLER = 1 << 0,
+		WITH_LOG_FILE_MESSAGE_HANDLER  = 1 << 1
 	};
 
+	friend InitFlags operator|(InitFlags a, InitFlags b)
+	{
+		typedef std::underlying_type<InitFlags>::type Int;
+		return 
+			static_cast<InitFlags>(static_cast<Int>(a) | static_cast<Int>(b));
+	}
+
+	friend InitFlags operator&(InitFlags a, InitFlags b)
+	{
+		typedef std::underlying_type<InitFlags>::type Int;
+		return 
+			static_cast<InitFlags>(static_cast<Int>(a) & static_cast<Int>(b));
+	}
+
 	/// Used as parammeter when emitting the signal
-	struct Info
+	class Info
 	{
-		const char* file;
-		int line;
-		const char* func;
-		LoggerMessageType type;
-		const char* msg;
+	public:
+		const char* m_file;
+		I32 m_line;
+		const char* m_func;
+		MessageType m_type;
+		const char* m_msg;
 	};
 
 	/// The message handler callback
 	using MessageHandlerCallback = void (*)(void*, const Info& info);
 
 	/// Initialize the logger
-	void init(U32 flags);
+	void init(InitFlags flags, HeapAllocator<U8>& alloc);
 
 	/// Add a new message handler
 	void addMessageHandler(void* data, MessageHandlerCallback callback);
 
 	/// Send a message
 	void write(const char* file, int line, const char* func,
-		LoggerMessageType type, const char* msg);
+		MessageType type, const char* msg);
 
 	/// Send a formated message
 	void writeFormated(const char* file, int line, const char* func,
-		LoggerMessageType type, const char* fmt, ...);
+		MessageType type, const char* fmt, ...);
 
 private:
-	std::mutex mutex; ///< For thread safety
+	std::mutex m_mutex; ///< For thread safety
 
-	struct Handler
+	class Handler
 	{
-		void* data;
-		MessageHandlerCallback callback;
+	public:
+		void* m_data;
+		MessageHandlerCallback m_callback;
 	};
 
-	Vector<Handler> handlers;
+	Vector<Handler> m_handlers;
 
-	File logfile;
+	File m_logfile;
 	
 	static void defaultSystemMessageHandler(void*, const Info& info);
 	static void logfileMessageHandler(void* vlogger, const Info& info);
@@ -93,10 +110,13 @@ typedef Singleton<Logger> LoggerSingleton;
 			t, __VA_ARGS__); \
 	} while(false);
 
-#define ANKI_LOGI(...) ANKI_LOGGER_MESSAGE(Logger::LMT_NORMAL, __VA_ARGS__)
+#define ANKI_LOGI(...) ANKI_LOGGER_MESSAGE(Logger::MessageType::NORMAL, \
+	__VA_ARGS__)
 
-#define ANKI_LOGW(...) ANKI_LOGGER_MESSAGE(Logger::LMT_WARNING, __VA_ARGS__)
+#define ANKI_LOGW(...) ANKI_LOGGER_MESSAGE(Logger::MessageType::WARNING, \
+	__VA_ARGS__)
 
-#define ANKI_LOGE(...) ANKI_LOGGER_MESSAGE(Logger::LMT_ERROR, __VA_ARGS__)
+#define ANKI_LOGE(...) ANKI_LOGGER_MESSAGE(Logger::MessageType::ERROR, \
+	__VA_ARGS__)
 
 #endif

+ 26 - 24
include/anki/core/NativeWindow.h

@@ -4,39 +4,40 @@
 #include "anki/util/StdTypes.h"
 #include "anki/util/Array.h"
 #include "anki/util/Singleton.h"
+#include "anki/util/String.h"
 #include <string>
 #include <memory>
 
 namespace anki {
 
-struct NativeWindowImpl;
-struct ContextImpl;
+class NativeWindowImpl;
+typedef void* Context;
 
 /// Window initializer
 struct NativeWindowInitializer
 {
-	U32 width = 640;
-	U32 height = 768;
-	Array<U32, 4> rgbaBits = {{8, 8, 8, 0}};
-	U32 depthBits = 0;
-	U32 stencilBits = 0;
-	U32 samplesCount = 0;
-	static const Bool doubleBuffer = true;
+	U32 m_width = 640;
+	U32 m_height = 768;
+	Array<U32, 4> m_rgbaBits = {{8, 8, 8, 0}};
+	U32 m_depthBits = 0;
+	U32 m_stencilBits = 0;
+	U32 m_samplesCount = 0;
+	static const Bool m_doubleBuffer = true;
 	/// Create a fullscreen window with the desktop's resolution
-	Bool fullscreenDesktopRez = false;
+	Bool8 m_fullscreenDesktopRez = false;
 
 	/// @name GL context properties
 	/// @{
 
 	/// Minor OpenGL version. Used to create core profile context
-	U32 minorVersion = 0;
+	U32 m_minorVersion = 0;
 	/// Major OpenGL version. Used to create core profile context
-	U32 majorVersion = 0; 
-	Bool useGles = false; ///< Use OpenGL ES
-	Bool debugContext = false; ///< Enables KHR_debug
+	U32 m_majorVersion = 0;
+	Bool8 m_useGles = false; ///< Use OpenGL ES
+	Bool8 m_debugContext = false; ///< Enables KHR_debug
 	/// @}
 
-	std::string title = "Untitled window";
+	String m_title = "Untitled window";
 };
 
 /// Native window with GL context
@@ -52,16 +53,16 @@ public:
 	NativeWindowImpl& getNative()
 	{
 		ANKI_ASSERT(isCreated());
-		return *impl;
+		return *m_impl;
 	}
 
 	U32 getWidth() const
 	{
-		return width;
+		return m_width;
 	}
 	U32 getHeight() const
 	{
-		return height;
+		return m_height;
 	}
 	/// @}
 
@@ -71,19 +72,20 @@ public:
 	void create(NativeWindowInitializer& initializer);
 	void destroy();
 	void swapBuffers();
-	ContextImpl* createSharedContext();
-	void contextMakeCurrent(ContextImpl& ctx);
+	Context createSharedContext();
+	Context getCurrentContext();
+	void contextMakeCurrent(Context ctx);
 	/// @}
 
 private:
-	U32 width;
-	U32 height;
+	U32 m_width;
+	U32 m_height;
 
-	std::shared_ptr<NativeWindowImpl> impl;
+	std::shared_ptr<NativeWindowImpl> m_impl;
 
 	Bool isCreated() const
 	{
-		return impl.get() != nullptr;
+		return m_impl.get() != nullptr;
 	}
 };
 

+ 6 - 3
include/anki/core/NativeWindowSdl.h

@@ -6,11 +6,14 @@
 
 namespace anki {
 
+static_assert(sizeof(SDL_GLContext) == sizeof(void*), "Incorrect assumption");
+
 /// Native window implementation for SDL
-struct NativeWindowImpl
+class NativeWindowImpl
 {
-	SDL_Window* window = nullptr;
-	SDL_GLContext context = 0;
+public:
+	SDL_Window* m_window = nullptr;
+	SDL_GLContext m_context = 0;
 };
 
 } // end namespace anki

+ 10 - 5
include/anki/core/StdinListener.h

@@ -2,13 +2,16 @@
 #define ANKI_CORE_STDIN_LISTENER_H
 
 #include "anki/util/Singleton.h"
+#include "anki/util/String.h"
 #include <thread>
 #include <mutex>
-#include <string>
 #include <queue>
 
 namespace anki {
 
+/// @addtogroup core
+/// @{
+
 /// The listener of the stdin.
 /// It initiates a thread that constantly reads the stdin and puts the results
 /// in a queue
@@ -16,15 +19,15 @@ class StdinListener
 {
 public:
 	/// Get line from the queue or return an empty string
-	std::string getLine();
+	String getLine();
 
 	/// Start reading
 	void start();
 
 private:
-	std::queue<std::string> q;
-	std::mutex mtx; ///< Protect the queue
-	std::thread thrd; ///< The thread
+	std::queue<String> m_q;
+	std::mutex m_mtx; ///< Protect the queue
+	std::thread m_thrd; ///< The thread
 
 	void workingFunc(); ///< The thread function
 };
@@ -32,6 +35,8 @@ private:
 /// Singleton
 typedef Singleton<StdinListener> StdinListenerSingleton;
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 0 - 17
include/anki/gl/Common.h

@@ -1,17 +0,0 @@
-#ifndef ANKI_GL_COMMON_H
-#define ANKI_GL_COMMON_H
-
-#include "anki/Config.h"
-
-#if ANKI_GL == ANKI_GL_DESKTOP
-#	include <GL/glew.h>
-#	if !defined(ANKI_GLEW_H)
-#		error "Wrong GLEW included"
-#	endif
-#elif ANKI_GL == ANKI_GL_ES
-#	include <GLES3/gl3.h>
-#else
-#	error "See file"
-#endif
-
-#endif

+ 0 - 53
include/anki/gl/Drawcall.h

@@ -1,53 +0,0 @@
-#ifndef ANKI_GL_DRAWCALL_H
-#define ANKI_GL_DRAWCALL_H
-
-#include "anki/gl/Common.h"
-#include "anki/util/StdTypes.h"
-#include "anki/util/Array.h"
-
-namespace anki {
-
-/// @addtogroup OpenGL
-/// @{
-
-/// A GL drawcall
-struct Drawcall
-{
-	/// The GL primitive type (eg GL_POINTS). Need to set it
-	GLenum primitiveType;
-	
-	/// Type of the indices. If zero then draw with glDrawArraysXXX. Default is
-	/// zero
-	GLenum indicesType; 
-
-	/// Used in instanced drawcalls. Default is 1
-	U32 instancesCount;
-
-	/// Used in glMultiDrawXXX. Default is 1
-	U32 drawCount;
-
-	/// The indices or elements
-	union
-	{
-		U32 count;
-		Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES> countArray;
-	};
-
-	union
-	{
-		PtrSize offset;
-		Array<PtrSize, ANKI_MAX_MULTIDRAW_PRIMITIVES> offsetArray;
-	};
-
-	Drawcall();
-
-	/// Execute the drawcall
-	void enque();
-};
-/// @}
-
-static_assert(sizeof(GLsizei) == sizeof(U32), "Wrong assumption");
-
-} // end namespace anki
-
-#endif

+ 0 - 156
include/anki/gl/Fbo.h

@@ -1,156 +0,0 @@
-#ifndef ANKI_GL_FBO_H
-#define ANKI_GL_FBO_H
-
-#include "anki/gl/GlObject.h"
-#include "anki/util/Array.h"
-#include "anki/Math.h"
-#include <initializer_list>
-
-namespace anki {
-
-class Texture;
-
-/// @addtogroup OpenGL
-/// @{
-
-/// Frame buffer object. The class is actually a wrapper to avoid common 
-/// mistakes
-class Fbo: public GlObjectContextNonSharable
-{
-public:
-	static const U MAX_COLOR_ATTACHMENTS = 4;
-
-	typedef GlObjectContextNonSharable Base;
-
-	/// Used as an argument on FBO creation
-	struct Attachment
-	{
-		const Texture* texture;
-		GLenum attachmentPoint;
-		I32 layer; ///< Layer or face
-
-		Attachment(const Texture* tex, GLenum attachmentPoint_)
-			:	texture(tex),
-				attachmentPoint(attachmentPoint_),
-				layer(-1)
-		{
-			ANKI_ASSERT(texture != nullptr);
-		}
-
-		Attachment(const Texture* tex, GLenum attachmentPoint_, I32 layer_)
-			:	texture(tex), 
-				attachmentPoint(attachmentPoint_), 
-				layer(layer_)
-		{
-			ANKI_ASSERT(texture != nullptr);
-			ANKI_ASSERT(layer != -1);
-		}
-	};
-
-	/// FBO target
-	enum Target
-	{
-		DRAW_TARGET = 1 << 1,
-		READ_TARGET = 1 << 2,
-		ALL_TARGETS = DRAW_TARGET | READ_TARGET
-	};
-
-	/// @name Constructors/Destructor
-	/// @{
-	Fbo()
-		: colorAttachmentsCount(0)
-	{}
-
-	/// Move
-	Fbo(Fbo&& b)
-		: Fbo()
-	{
-		*this = std::move(b);
-	}
-
-	~Fbo()
-	{
-		destroy();
-	}
-	/// @}
-
-	/// @name Operators
-	/// @{
-	Fbo& operator=(Fbo&& b)
-	{
-		destroy();
-		Base::operator=(std::forward<Base>(b));
-		colorAttachmentsCount = b.colorAttachmentsCount;
-		b.colorAttachmentsCount = 0;
-		return *this;
-	}
-	/// @}
-
-	/// Creates a new FBO
-	void create(const std::initializer_list<Attachment>& attachments);
-
-	/// Destroy it
-	void destroy();
-
-	/// Binds FBO
-	void bind(Bool invalidate, const Target target = ALL_TARGETS) const
-	{
-		ANKI_ASSERT(isCreated());
-		checkNonSharable();
-		bindInternal(this, invalidate, target);
-	}
-
-	/// Unbind all targets. Unbinds both draw and read FBOs so the active is
-	/// the default FBO
-	static void bindDefault(
-		Bool invalidate, const Target target = ALL_TARGETS)
-	{
-		bindInternal(nullptr, invalidate, target);
-	}
-
-	/// Blit another framebuffer to this one
-	void blitFrom(const Fbo& source, const UVec2& srcMin, const UVec2& srcMax, 
-		const UVec2& dstMin, const UVec2& dstMax, 
-		GLbitfield mask, GLenum filter);
-
-private:
-	static thread_local const Fbo* currentRead;
-	static thread_local const Fbo* currentDraw;
-
-	U8 colorAttachmentsCount;
-
-	static GLuint getCurrentFboGlId()
-	{
-		GLint i;
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &i);
-		return i;
-	}
-
-	static GLuint getCurrentDrawFboGlId()
-	{
-		GLint i;
-		glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &i);
-		return i;
-	}
-
-	static GLuint getCurrentReadFboGlId()
-	{
-		GLint i;
-		glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &i);
-		return i;
-	}
-
-	/// Bind an FBO
-	/// @param fbo May be nullptr
-	static void bindInternal(const Fbo* fbo, Bool invalidate, 
-		const Target target);
-
-	/// Attach texture internal
-	void attachTextureInternal(GLenum attachment, const Texture& tex, 
-		const I32 layer);
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 19
include/anki/gl/Gl.h

@@ -1,19 +0,0 @@
-/// @file
-/// This file contains the correct OpenGL headers and all the GL classes
-
-#ifndef ANKI_GL_GL_H
-#define ANKI_GL_GL_H
-
-#include "anki/gl/GlBuffer.h"
-#include "anki/gl/Fbo.h"
-#include "anki/gl/GlException.h"
-#include "anki/gl/GlState.h"
-#include "anki/gl/Query.h"
-#include "anki/gl/ShaderProgram.h"
-#include "anki/gl/Texture.h"
-#include "anki/gl/Vao.h"
-#include "anki/gl/Drawcall.h"
-
-#include "anki/gl/Common.h"
-
-#endif

+ 43 - 73
include/anki/gl/GlBuffer.h

@@ -5,11 +5,11 @@
 
 namespace anki {
 
-/// @addtogroup OpenGL
+/// @addtogroup opengl_private
 /// @{
 	
 /// A wrapper for OpenGL buffer objects (vertex arrays, texture buffers etc)
-/// to prevent us from making idiotic errors
+/// to prevent us from making idiotic errors. It's storage immutable
 class GlBuffer: public GlObject
 {
 public:
@@ -22,8 +22,21 @@ public:
 	GlBuffer()
 	{}
 
+	/// Creates a new BO with the given parameters and checks if everything
+	/// went OK. Throws exception if fails
+	/// @param target Depends on the BO
+	/// @param sizeInBytes The size of the buffer that we will allocate in bytes
+	/// @param dataPtr Points to the data buffer to copy to the VGA memory.
+	///		   Put NULL if you want just to allocate memory
+	/// @param flags GL access flags
+	GlBuffer(GLenum target, U32 sizeInBytes, const void* dataPtr,
+		GLbitfield flags)
+	{
+		create(target, sizeInBytes, dataPtr, flags);
+	}
+
 	/// Move
-	GlBuffer(GlBuffer&& b)	
+	GlBuffer(GlBuffer&& b)
 	{
 		*this = std::move(b);
 	}
@@ -43,25 +56,28 @@ public:
 	GLenum getTarget() const
 	{
 		ANKI_ASSERT(isCreated());
-		return target;
+		return m_target;
 	}
 
-	void setTarget(GLenum target_)
+	void setTarget(GLenum target)
 	{
 		ANKI_ASSERT(isCreated());
-		target = target_;
+		unbind(); // Unbind from the previous target
+		m_target = target;
 	}
 
-	GLenum getUsage() const
+	U32 getSize() const
 	{
 		ANKI_ASSERT(isCreated());
-		return usage;
+		return m_size;
 	}
 
-	U32 getSizeInBytes() const
+	/// Return the prersistent mapped address
+	void* getPersistentMappingAddress()
 	{
 		ANKI_ASSERT(isCreated());
-		return sizeInBytes;
+		ANKI_ASSERT(m_persistentMapping);
+		return m_persistentMapping;
 	}
 	/// @}
 
@@ -69,39 +85,27 @@ public:
 	void bind() const
 	{
 		ANKI_ASSERT(isCreated());
-		glBindBuffer(target, getGlId());
+		glBindBuffer(m_target, m_glName);
 	}
 
 	/// Unbind BO
 	void unbind() const
 	{
 		ANKI_ASSERT(isCreated());
-		glBindBuffer(target, 0);
+		bindDefault(m_target);
 	}
 
-	/// Creates a new BO with the given parameters and checks if everything
-	/// went OK. Throws exception if fails
-	/// @param target Depends on the BO
-	/// @param sizeInBytes The size of the buffer that we will allocate in bytes
-	/// @param dataPtr Points to the data buffer to copy to the VGA memory.
-	///		   Put NULL if you want just to allocate memory
-	/// @param usage It should be: GL_STREAM_DRAW or GL_STATIC_DRAW or
-	///		   GL_DYNAMIC_DRAW only!!!!!!!!!
-	/// @param objectCount The number of objects
-	void create(GLenum target, U32 sizeInBytes, const void* dataPtr,
-		GLenum usage);
-
-	/// Delete the BO
-	void destroy();
+	/// Bind the default to a target
+	static void bindDefault(GLenum target)
+	{
+		glBindBuffer(target, 0);
+	}
 
-	/// Write data to buffer. This means that maps the BO to local memory,
-	/// writes the local memory and unmaps it. Throws exception if the
-	/// given size and the BO size are not equal. It throws an exception if
-	/// the usage is GL_STATIC_DRAW
+	/// Write data to buffer. 
 	/// @param[in] buff The buffer to copy to BO
 	void write(void* buff)
 	{
-		write(buff, 0, sizeInBytes);
+		write(buff, 0, m_size);
 	}
 
 	/// The same as the other write but it maps only a subset of the data
@@ -110,57 +114,23 @@ public:
 	/// @param[in] size The size in bytes we want to write
 	void write(void* buff, U32 offset, U32 size);
 
-	/// Read the containts of the buffer
-	/// @param[out] outBuff The buffer to copy from BO
-	void read(void* outBuff)
-	{
-		read(outBuff, 0, sizeInBytes);
-	}
-
-	/// Read the containts of the buffer
-	/// @param[in] outBuff The buffer to copy from BO
-	/// @param[in] offset The offset
-	/// @param[in] size The size in bytes we want to write
-	void read(void* buff, U32 offset, U32 size);
-
-	/// Map part of the buffer
-	void* map(U32 offset, U32 length, GLuint flags);
-
-	/// Map the entire buffer
-	void* map(GLuint flags)
-	{
-		return map(0, sizeInBytes, flags);
-	}
-
-	/// Unmap buffer
-	void unmap();
-
 	/// Set the binding for this buffer
 	void setBinding(GLuint binding) const;
 
 	/// Set the binding point of this buffer with range
 	void setBindingRange(GLuint binding, PtrSize offset, PtrSize size) const;
 
-	/// Return GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
-	static PtrSize getUniformBufferOffsetAlignment()
-	{
-		GLint64 offsetAlignment;
-		glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment);
-		return offsetAlignment;
-	}
-
 private:
-	/// Used in glBindBuffer(target, glId) and its for easy access so we
-	/// wont have to query the GL driver. Its the type of the buffer eg
-	/// GL_TEXTURE_BUFFER or GL_ELEMENT_ARRAY_BUFFER etc
-	GLenum target;
+	GLenum m_target; ///< GL_TEXTURE_BUFFER or GL_ELEMENT_ARRAY_BUFFER etc
+	U32 m_size; ///< The size of the buffer
+	void* m_persistentMapping = nullptr;
 
-	GLenum usage; ///< GL_STREAM_DRAW or GL_STATIC_DRAW or GL_DYNAMIC_DRAW
-	U32 sizeInBytes; ///< The size of the buffer
+	/// Create
+	void create(GLenum target, U32 sizeInBytes, const void* dataPtr,
+		GLbitfield flags);
 
-#if ANKI_DEBUG
-	Bool mapped = false; ///< Only in debug
-#endif
+	/// Delete the BO
+	void destroy();
 };
 
 /// @}

+ 88 - 0
include/anki/gl/GlBufferHandle.h

@@ -0,0 +1,88 @@
+#ifndef ANKI_GL_GL_BUFFER_HANDLE_H
+#define ANKI_GL_GL_BUFFER_HANDLE_H
+
+#include "anki/gl/GlContainerHandle.h"
+
+namespace anki {
+
+// Forward
+class GlBuffer;
+class GlClientBufferHandle;
+class GlJobChainHandle;
+
+/// @addtogroup opengl_containers
+/// @{
+
+/// GPU buffer handle
+class GlBufferHandle: public GlContainerHandle<GlBuffer>
+{
+public:
+	typedef GlContainerHandle<GlBuffer> Base;
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlBufferHandle();
+
+	/// Create the buffer with data
+	explicit GlBufferHandle(GlJobChainHandle& jobs, GLenum target, 
+		GlClientBufferHandle& data, GLbitfield flags);
+
+	/// Create the buffer without data
+	explicit GlBufferHandle(GlJobChainHandle& jobs, GLenum target, 
+		PtrSize size, GLbitfield flags);
+
+	~GlBufferHandle();
+	/// @}
+
+	/// Get buffer size. It may serialize 
+	PtrSize getSize() const;
+
+	/// Get buffer's current target. It may serialize 
+	GLenum getTarget() const;
+
+	/// Get persistent mapping address. It may serialize 
+	void* getPersistentMappingAddress();
+
+	/// Write data to the buffer
+	void write(
+		GlJobChainHandle& jobs, 
+		GlClientBufferHandle& data, PtrSize readOffset,
+		PtrSize writeOffset, PtrSize size);
+
+	/// Bind to the state as uniform/shader storage buffer
+	void bindShaderBuffer(GlJobChainHandle& jobs, U32 bindingPoint)
+	{
+		bindShaderBufferInternal(jobs, -1, -1, bindingPoint);
+	}
+
+	/// Bind to the state as uniform/shader storage buffer
+	void bindShaderBuffer(GlJobChainHandle& jobs,
+		U32 offset, U32 size, U32 bindingPoint)
+	{
+		bindShaderBufferInternal(jobs, offset, size, bindingPoint);
+	}
+
+	/// Bind to the state as vertex buffer
+	void bindVertexBuffer(
+		GlJobChainHandle& jobs, 
+		U32 elementSize,
+		GLenum type,
+		Bool normalized,
+		PtrSize stride,
+		PtrSize offset,
+		U32 attribLocation);
+
+	/// Bind to the state as index buffer
+	void bindIndexBuffer(GlJobChainHandle& jobs);
+
+private:
+	void bindShaderBufferInternal(GlJobChainHandle& jobs,
+		I32 offset, I32 size, U32 bindingPoint);
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 118 - 0
include/anki/gl/GlClientBuffer.h

@@ -0,0 +1,118 @@
+#ifndef ANKI_GL_GL_CLIENT_BUFFER_H
+#define ANKI_GL_GL_CLIENT_BUFFER_H
+
+#include "anki/gl/GlCommon.h"
+#include <memory>
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// A client buffer used to pass data to and from the server
+class GlClientBuffer: public NonCopyable
+{
+public:
+	/// @name Constructors/Destructor
+	/// @{
+
+	/// Default constructor
+	GlClientBuffer()
+	{}
+
+	/// Create the buffer and allocate memory for the chain's allocator
+	GlClientBuffer(const GlJobChainAllocator<U8>& chainAlloc, PtrSize size)
+		: m_alloc(chainAlloc)
+	{
+		ANKI_ASSERT(size > 0);
+		m_ptr = m_alloc.allocate(size);
+		m_size = size;
+		m_preallocated = false;
+	}
+
+	/// Create the buffer using preallocated memory
+	GlClientBuffer(void* preallocatedMem, PtrSize size)
+	{
+		ANKI_ASSERT(size > 0);
+		m_ptr = preallocatedMem;
+		m_size = size;
+		m_preallocated = true;
+	}
+
+	/// Move
+	GlClientBuffer(GlClientBuffer&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GlClientBuffer()
+	{
+		destroy();
+	}
+	/// @}
+
+	/// Move
+	GlClientBuffer& operator=(GlClientBuffer&& b)
+	{
+		destroy();
+
+		m_ptr = b.m_ptr;
+		m_size = b.m_size;
+		b.m_ptr = nullptr;
+		b.m_size = 0;
+		m_preallocated = b.m_preallocated;
+
+		if(!m_preallocated)
+		{
+			m_alloc = b.m_alloc;
+			b.m_alloc = GlJobChainAllocator<U8>();
+		}
+		return *this;
+	}
+
+	/// Return the base address
+	void* getBaseAddress()
+	{
+		ANKI_ASSERT(m_size > 0 && m_ptr != 0);
+		return m_ptr;
+	}
+
+	/// Get size of buffer
+	PtrSize getSize() const 
+	{
+		ANKI_ASSERT(m_size > 0);
+		return m_size;
+	}
+
+	/// Return the allocator
+	GlJobChainAllocator<U8> getAllocator() const
+	{
+		ANKI_ASSERT(!m_preallocated);
+		return m_alloc;
+	}
+
+private:
+	void* m_ptr = nullptr;
+	U32 m_size = 0;
+	GlJobChainAllocator<U8> m_alloc;
+	Bool8 m_preallocated;
+
+	void destroy()
+	{
+		if(!m_preallocated && m_ptr)
+		{
+			ANKI_ASSERT(m_size > 0);
+			m_alloc.deallocate(m_ptr, m_size);
+
+			m_size = 0;
+			m_ptr = nullptr;
+		}
+	}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 47 - 0
include/anki/gl/GlClientBufferHandle.h

@@ -0,0 +1,47 @@
+#ifndef ANKI_GL_GL_CLIENT_BUFFER_HANDLE_H
+#define ANKI_GL_GL_CLIENT_BUFFER_HANDLE_H
+
+#include "anki/gl/GlHandle.h"
+
+namespace anki {
+
+// Forward
+class GlClientBuffer;
+class GlJobChainHandle;
+
+/// @addtogroup opengl_other
+/// @{
+
+/// Client buffer handle
+class GlClientBufferHandle: public GlHandle<GlClientBuffer>
+{
+public:
+	typedef GlHandle<GlClientBuffer> Base;
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlClientBufferHandle();
+
+	/// Create the buffer using preallocated memory or memory from the chain
+	/// @param chain The job chain this client memory belongs to
+	/// @param size The size of the buffer
+	/// @param preallocatedMem Preallocated memory. Can be nullptr
+	/// @return The address of the new memory
+	GlClientBufferHandle(
+		GlJobChainHandle& chain, PtrSize size, void* preallocatedMem);
+
+	~GlClientBufferHandle();
+	/// @}
+
+	/// Get the base address
+	void* getBaseAddress();
+
+	/// Get size
+	PtrSize getSize() const;
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 262 - 0
include/anki/gl/GlCommon.h

@@ -0,0 +1,262 @@
+#ifndef ANKI_GL_COMMON_H
+#define ANKI_GL_COMMON_H
+
+#include "anki/Config.h"
+#include "anki/util/Allocator.h"
+#include "anki/util/NonCopyable.h"
+#include "anki/util/Assert.h"
+#include "anki/util/Array.h"
+#include "anki/util/StdTypes.h"
+#include "anki/Math.h"
+
+#include <atomic>
+#include <string>
+
+#if ANKI_GL == ANKI_GL_DESKTOP
+#	include <GL/glew.h>
+#	if !defined(ANKI_GLEW_H)
+#		error "Wrong GLEW included"
+#	endif
+#elif ANKI_GL == ANKI_GL_ES
+#	include <GLES3/gl3.h>
+#else
+#	error "See file"
+#endif
+
+#define ANKI_JOB_MANAGER_DISABLE_ASYNC 0
+
+namespace anki {
+
+// Forward
+class GlProgramData;
+class GlProgramBlock;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// The type of the allocator of GlJobChain
+template<typename T>
+using GlJobChainAllocator = ChainAllocator<T>;
+
+/// The type of the allocator for heap allocations
+template<typename T>
+using GlGlobalHeapAllocator = HeapAllocator<T>;
+
+/// Texture filtering method
+enum class GlTextureFilter: U8
+{
+	NEAREST,
+	LINEAR,
+	TRILINEAR
+};
+
+/// Split the initializer for re-using parts of it
+class GlTextureInitializerBase
+{
+public:
+	U32 m_width = 0;
+	U32 m_height = 0;
+	U32 m_depth = 0; ///< Relevant only for 3D and 2DArray textures
+	GLenum m_target = GL_TEXTURE_2D;
+	GLenum m_internalFormat = GL_NONE;
+	GLenum m_format = GL_NONE;
+	GLenum m_type = GL_NONE;
+	U32 m_mipmapsCount = 0;
+	GlTextureFilter m_filterType = GlTextureFilter::NEAREST;
+	Bool8 m_repeat = false;
+	I32 m_anisotropyLevel = 0;
+	Bool8 m_genMipmaps = false;
+	U32 m_samples = 1;
+};
+
+/// @}
+
+/// @addtogroup opengl_other
+
+/// A function that returns an index from a shader type GLenum
+U computeShaderTypeIndex(const GLenum glType);
+
+/// A function that returns a GLenum from an index
+GLenum computeGlShaderType(const U idx, GLbitfield* bit = nullptr);
+
+/// GL generic callback
+using GlCallback = void(*)(void*);
+
+/// @}
+
+/// @addtogroup opengl_containers
+/// @{
+
+/// Shader program variable. The type is attribute or uniform
+class GlProgramVariable
+{
+	friend class GlProgram;
+
+public:
+	/// Shader program variable type
+	enum class Type: U8
+	{
+		INPUT, ///< Attribute on vertex
+		UNIFORM,
+		BUFFER
+	};
+
+	/// @name Accessors
+	/// @{
+	Type getType() const
+	{
+		return m_type;
+	}
+
+	const char* getName() const
+	{
+		return &m_name[0];
+	}
+
+	GLenum getDataType() const
+	{
+		ANKI_ASSERT(m_dataType != GL_NONE);
+		return m_dataType;
+	}
+
+	PtrSize getArraySize() const
+	{
+		ANKI_ASSERT(m_arrSize != 0);
+		return m_arrSize;
+	}
+
+	GLint getLocation() const
+	{
+		ANKI_ASSERT(m_loc != -1);
+		return m_loc;
+	}
+
+	U32 getTextureUnit() const
+	{
+		ANKI_ASSERT(m_texUnit >= 0);
+		return (U32)m_texUnit;
+	}
+
+	/// @return The block or nullptr if it doesn't belong to a block
+	const GlProgramBlock* getBlock() const;
+	/// @}
+
+	/// @name Block setters
+	/// Write a client memory that represents the interface block
+	/// @{
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const F32 arr[], U32 size) const;
+
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const Vec2 arr[], U32 size) const;
+
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const Vec3 arr[], U32 size) const;
+
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const Vec4 arr[], U32 size) const;
+
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const Mat3 arr[], U32 size) const;
+
+	void writeClientMemory(void* buffBase, U32 buffSize,
+		const Mat4 arr[], U32 size) const;
+	/// @}
+
+private:
+	Type m_type; ///< It's type
+	char* m_name; ///< The name inside the shader program
+	const GlProgramData* m_progData = nullptr; ///< Know your father
+
+	GLenum m_dataType = GL_NONE; ///< GL_FLOAT or GL_FLOAT_VEC2 etc.
+	U8 m_arrSize = 0; ///< Its 1 if it is a single or >1 if it is an array
+
+	I32 m_loc = -1; ///< For uniforms and attributes
+
+	/// @name For variables in interface blocks
+	/// @{
+
+	/// Stride between the each array element if the variable is array
+	I32 m_arrStride = -1;
+
+	I32 m_offset = -1; ///< Offset inside the block
+
+	/// Identifying the stride between columns of a column-major matrix or rows 
+	/// of a row-major matrix
+	I32 m_matrixStride = -1;
+
+	I16 m_blockIdx = -1; ///< Interface block
+	/// @}
+
+	I32 m_texUnit = -1; ///< Explicit unit for samplers
+
+	/// Do common checks
+	template<typename T>
+	void writeClientMemorySanityChecks(void* buffBase, U32 buffSize,
+		const T arr[], U32 size) const;
+
+	/// Do the actual job of setClientMemory
+	template<typename T>
+	void writeClientMemoryInternal(
+		void* buff, U32 buffSize, const T arr[], U32 size) const;
+
+	/// Do the actual job of setClientMemory for matrices
+	template<typename Mat, typename Vec>
+	void writeClientMemoryInternalMatrix(void* buff, U32 buffSize,
+		const Mat arr[], U32 size) const;
+};
+
+/// Interface shader block
+class GlProgramBlock
+{
+	friend class GlProgram;
+
+public:
+	static const U32 MAX_VARIABLES_PER_BLOCK = 16;
+
+	/// Interface shader block type
+	enum class Type: U8
+	{
+		UNIFORM,
+		SHADER_STORAGE
+	};
+
+	/// @name Accessors
+	/// @{
+	Type getType() const
+	{
+		return m_type;
+	}
+
+	PtrSize getSize() const
+	{
+		return m_size;
+	}
+
+	const char* getName() const
+	{
+		return &m_name[0];
+	}
+
+	U32 getBinding() const
+	{
+		return m_bindingPoint;
+	}
+	/// @}
+
+private:
+	Type m_type;
+	char* m_name;
+	const GlProgramData* m_progData = nullptr; ///< Know your father
+	/// Keep the indices as U16 to save memory
+	Array<U16, MAX_VARIABLES_PER_BLOCK> m_variableIdx; 
+	U32 m_size; ///< In bytes
+	U32 m_bindingPoint;
+	U8 m_variablesCount = 0;
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 40 - 0
include/anki/gl/GlContainerHandle.h

@@ -0,0 +1,40 @@
+#ifndef ANKI_GL_GL_CONTAINER_HANDLE_H
+#define ANKI_GL_GL_CONTAINER_HANDLE_H
+
+#include "anki/gl/GlHandle.h"
+#include "anki/gl/GlManager.h"
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Handle template for container objects
+template<typename T>
+class GlContainerHandle: public GlHandle<T>
+{
+public:
+	typedef GlHandle<T> Base;
+
+protected:
+	/// Check if the object has been created and if not serialize the server
+	void serializeOnGetter() const
+	{
+		GlHandleState state = Base::_getState();
+		ANKI_ASSERT(state != GlHandleState::NEW);
+
+		if(state == GlHandleState::TO_BE_CREATED)
+		{
+			Base::_getManager()._getJobManager().syncClientServer();
+			ANKI_ASSERT(Base::_getState() > GlHandleState::TO_BE_CREATED);
+		}
+	}
+};
+
+/// @}
+
+
+} // end namespace anki
+
+#endif
+

+ 5 - 4
include/anki/gl/GlException.h → include/anki/gl/GlError.h

@@ -1,11 +1,12 @@
-#ifndef ANKI_GL_GL_EXCEPTION_H
-#define ANKI_GL_GL_EXCEPTION_H
+#ifndef ANKI_GL_GL_ERROR_H
+#define ANKI_GL_GL_ERROR_H
 
 #include "anki/Config.h"
+#include "anki/gl/GlCommon.h"
 
 namespace anki {
 
-/// @addtogroup OpenGL
+/// @addtogroup opengl_private
 /// @{
 
 // Enable the exception on debug. Calling glGetError calls serialization
@@ -24,6 +25,6 @@ void glConditionalThrowException(const char* file, int line, const char* func);
 
 /// @}
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 85 - 0
include/anki/gl/GlFramebuffer.h

@@ -0,0 +1,85 @@
+#ifndef ANKI_GL_GL_FRAMEBUFFER_H
+#define ANKI_GL_GL_FRAMEBUFFER_H
+
+#include "anki/gl/GlObject.h"
+#include "anki/gl/GlTextureHandle.h"
+
+namespace anki {
+
+// Forward
+class GlTexture;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Framebuffer
+class GlFramebuffer: public GlObject
+{
+public:
+	typedef GlObject Base;
+
+	static const U32 MAX_COLOR_ATTACHMENTS = 4;
+
+	/// Used to set the attachments
+	class Attachment
+	{
+	public:
+		Attachment()
+		{}
+
+		Attachment(const GlTextureHandle& tex, GLenum point, U32 layer = 0)
+			: m_tex(tex), m_point(point), m_layer(layer)
+		{}
+
+		GlTextureHandle m_tex;
+		GLenum m_point;
+		U32 m_layer;
+	};
+
+	/// @name Constructors/Desctructor
+	/// @{
+	GlFramebuffer()
+	{}
+
+	/// Set all the attachments. It will overwrite the previous state. If the
+	/// initalizer list is empty the it will bind the default framebuffer
+	explicit GlFramebuffer(
+		Attachment* attachmentsBegin, Attachment* attachmentsEnd);
+
+	GlFramebuffer(GlFramebuffer&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GlFramebuffer()
+	{
+		destroy();
+	}
+	/// @}
+
+	GlFramebuffer& operator=(GlFramebuffer&& b);
+
+	/// Bind it to the state. Call it in rendering thread
+	/// @param invalidate If true invalidate the FB after binding it
+	void bind(Bool invalidate);
+
+private:
+	Array<GlTextureHandle, MAX_COLOR_ATTACHMENTS + 1> m_attachments;
+	Bool8 m_bindDefault = false;
+
+	/// Attach a texture
+	static void attachTextureInternal(GLenum attachment, const GlTexture& tex, 
+		const U32 layer);
+
+	/// Create the FBO
+	void createFbo(const Array<U, MAX_COLOR_ATTACHMENTS + 1>& layers,
+		GLenum depthStencilBindingPoint);
+
+	void destroy();
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 43 - 0
include/anki/gl/GlFramebufferHandle.h

@@ -0,0 +1,43 @@
+#ifndef ANKI_GL_GL_FRAMEBUFFER_HANDLE_H
+#define ANKI_GL_GL_FRAMEBUFFER_HANDLE_H
+
+#include "anki/gl/GlContainerHandle.h"
+#include "anki/gl/GlFramebuffer.h"
+
+namespace anki {
+
+// Forward
+class GlJobChainHandle;
+
+/// @addtogroup opengl_misc
+/// @{
+
+/// Framebuffer handle
+class GlFramebufferHandle: public GlContainerHandle<GlFramebuffer>
+{
+public:
+	using Base = GlContainerHandle<GlFramebuffer>;
+	using Attachment = GlFramebuffer::Attachment;
+
+	/// @name Contructors/Destructor
+	/// @{
+	GlFramebufferHandle();
+
+	/// Create a framebuffer
+	explicit GlFramebufferHandle(
+		GlJobChainHandle& jobs,
+		const std::initializer_list<Attachment>& attachments);
+
+	~GlFramebufferHandle();
+	/// @}
+
+	/// Bind it to the state
+	/// @param jobs The job chain
+	/// @param invalidate If true invalidate the FB after binding it
+	void bind(GlJobChainHandle& jobs, Bool invalidate);
+};
+
+} // end namespace anki
+
+#endif
+

+ 368 - 0
include/anki/gl/GlHandle.h

@@ -0,0 +1,368 @@
+#ifndef ANKI_GL_GL_HANDLE_H
+#define ANKI_GL_GL_HANDLE_H
+
+#include "anki/gl/GlCommon.h"
+
+namespace anki {
+
+// Forward
+class GlManager;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// State of the handle
+enum class GlHandleState: U8
+{
+	NEW,
+	TO_BE_CREATED,
+	CREATED,
+	TO_BE_DELETED,
+	DELETED
+};
+
+/// Default deleter for the GlHandle
+template<typename T, typename TAlloc>
+class GlHandleDefaultDeleter
+{
+public:
+	void operator()(T* ptr, TAlloc alloc, GlManager*)
+	{
+		alloc.deleteInstance(ptr);
+	}
+};
+
+/// It's essentialy a custom shared pointer. Created to have full control over 
+/// allocations, it takes less space than a regular shared pointer (1 pointer 
+/// instead of 2) and it can have custom control blocks
+///
+/// @tparam T The type of the pointer
+template<typename T>
+class GlHandle
+{
+public:
+	typedef T Type;
+
+	/// @name Constructor/Destructor
+	/// @{
+	GlHandle()
+		: m_cb(nullptr)
+	{}
+
+	/// Create an object and initialize the handle with that
+	/// @param[in,out] manager If it's not nullptr then it will create a more 
+	///                        sophisticated handle. Pass nullptr otherwise
+	/// @param[in] alloc The allocator that will be used for all internal 
+	///                  allocations of the handle
+	/// @param[in] del The deleter that will be used to cleanup the allocated
+	///                object. The containers for example require deferred 
+	///                deleters
+	/// @param args The arguments to pass to the object's constructor
+	template<typename TAlloc, typename TDeleter, typename... TArgs>
+	GlHandle(GlManager* manager, TAlloc alloc, TDeleter del, TArgs&&... args)
+	{
+		// Create the object
+		T* ptr = alloc.template newInstance<T>(std::forward<TArgs>(args)...);
+
+		if(manager)
+		{
+			// Container block
+
+			typedef CtrlBlockContainer<T, TAlloc, TDeleter> Block;
+
+			Block* blk = alloc.template newInstance<Block>();
+
+			blk->m_state = GlHandleState::NEW;
+			blk->m_manager = manager;
+			blk->m_alloc = alloc;
+			blk->m_del = del;
+
+			m_cb = blk;
+		}
+		else
+		{
+			// Simple block
+
+			typedef CtrlBlockSimple<T, TAlloc, TDeleter> Block;
+
+			Block* blk = alloc.template newInstance<Block>();
+
+			blk->m_alloc = alloc;
+			blk->m_del = del;
+
+			m_cb = blk;
+		}
+
+		// Set common
+		m_cb->m_refcount = 1;
+		m_cb->m_ptr = ptr;
+	}
+
+	GlHandle(const GlHandle& b)
+		: GlHandle()
+	{
+		*this = b;
+	}
+
+	GlHandle(GlHandle&& b)
+		: GlHandle()
+	{
+		*this = std::move(b);
+	}
+
+	~GlHandle()
+	{
+		reset();
+	}
+	/// @}
+
+	/// Move
+	GlHandle& operator=(GlHandle&& b)
+	{
+		reset();
+	
+		if(b.m_cb)
+		{
+			m_cb = b.m_cb;
+			b.m_cb = nullptr;
+		}
+
+		return *this;
+	}
+
+	/// Copy
+	GlHandle& operator=(const GlHandle& b)
+	{
+		reset();
+	
+		if(b.m_cb)
+		{
+			auto count = b.m_cb->m_refcount.fetch_add(1);
+			ANKI_ASSERT(count > 0);
+			(void)count;
+
+			m_cb = b.m_cb;
+		}
+
+		return *this;
+	}
+
+	/// Compare
+	Bool operator==(const GlHandle& b) const
+	{
+		return m_cb == b.m_cb;
+	}
+
+	/// Compare
+	Bool operator!=(const GlHandle& b) const
+	{
+		return m_cb != b.m_cb;
+	}
+
+	/// Compare
+	Bool operator<(const GlHandle& b) const
+	{
+		return m_cb < b.m_cb;
+	}
+
+	/// Compare
+	Bool operator<=(const GlHandle& b) const
+	{
+		return m_cb <= b.m_cb;
+	}
+
+	/// Compare
+	Bool operator>(const GlHandle& b) const
+	{
+		return m_cb > b.m_cb;
+	}
+
+	/// Compare
+	Bool operator>=(const GlHandle& b) const
+	{
+		return m_cb >= b.m_cb;
+	}
+
+	/// Return true if it's pointing to actual data
+	Bool isCreated() const
+	{
+		return m_cb != nullptr;
+	}
+
+	/// Return the number of users
+	U getReferenceCount() const
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
+		return m_cb->m_refcount.load();
+	}
+
+	/// Get the mutable pointer 
+	T& _get()
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
+		return *m_cb->m_ptr;
+	}
+
+	/// Get the immutable pointer
+	const T& _get() const
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
+		return *m_cb->m_ptr;
+	}
+
+	/// Get the current state
+	GlHandleState _getState() const
+	{
+		ANKI_ASSERT(m_cb != nullptr);
+		return m_cb->getStateAtomically(nullptr);
+	}
+
+	/// Set the handle state
+	GlHandleState _setState(GlHandleState newVal)
+	{
+		ANKI_ASSERT(m_cb != nullptr);
+		return m_cb->getStateAtomically(&newVal);
+	}
+
+	GlManager& _getManager() const
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->getManager() != nullptr);
+		return *m_cb->getManager(); 
+	}
+
+private:
+	/// Control block base
+	/// @note The non-pure virtuals indicate an optional feature
+	template<typename Y>
+	class CtrlBlockBase
+	{
+	public:
+		Y* m_ptr;
+		std::atomic<I32> m_refcount;
+
+		virtual ~CtrlBlockBase()
+		{}
+		
+		/// Destroy the object in m_ptr
+		virtual void deletePtr() = 0;
+
+		/// Delete the block itself
+		virtual void deleteSelf() = 0;
+
+		/// The container handles want the manager
+		virtual GlManager* getManager() const
+		{
+			return nullptr;
+		}
+
+		/// Manipulate the state. It will return the value of the state and if
+		/// newVal is not nullptr it will set a new value
+		virtual GlHandleState getStateAtomically(GlHandleState* newVal)
+		{
+			(void)newVal;
+			return GlHandleState::NEW;
+		}
+	};
+
+	/// Control block for simple objects
+	template<typename Y, typename YAlloc, typename YDeleter>
+	class CtrlBlockSimple: public CtrlBlockBase<Y>
+	{
+	public:	
+		typedef CtrlBlockBase<Y> Base;
+
+		/// Copy of the allocator
+		YAlloc m_alloc; 
+
+		/// The deleter functor
+		YDeleter m_del;
+		
+		void deletePtr()
+		{
+			// Delete object
+			m_del(Base::m_ptr, m_alloc, nullptr);
+		}
+
+		void deleteSelf()
+		{
+			// Delete control block
+			m_alloc.deleteInstance(this);
+		}
+	};
+
+	/// Control block for container objects
+	template<typename Y, typename YAlloc, typename YDeleter>
+	class CtrlBlockContainer: public CtrlBlockBase<Y>
+	{
+	public:	
+		typedef CtrlBlockBase<Y> Base;
+
+		/// Copy of the allocator
+		YAlloc m_alloc; 
+
+		/// The deleter functor
+		YDeleter m_del;
+
+		/// @note Its mutable because we want read/write access to it
+		mutable GlManager* m_manager; 
+
+		std::atomic<GlHandleState> m_state;
+		
+		void deletePtr()
+		{
+			// Delete object
+			m_del(Base::m_ptr, m_alloc, getManager());
+		}
+
+		void deleteSelf()
+		{
+			// Delete control block
+			m_alloc.deleteInstance(this);
+		}
+
+		GlManager* getManager() const override
+		{
+			return m_manager;
+		}
+
+		GlHandleState getStateAtomically(GlHandleState* newVal) override
+		{
+			GlHandleState crntVal;
+			if(newVal)
+			{
+				crntVal = m_state.exchange(*newVal);
+			}
+			else
+			{
+				crntVal = m_state.load();
+			}
+			return crntVal;
+		}
+	};
+
+	CtrlBlockBase<T>* m_cb;
+
+	/// Reset the pointer to it's original state and remove the references to
+	/// any object
+	void reset()
+	{
+		if(m_cb)
+		{
+			auto count = m_cb->m_refcount.fetch_sub(1);
+			if(count == 1)
+			{
+				m_cb->deletePtr();
+				m_cb->deleteSelf();
+			}
+
+			m_cb = nullptr;
+		}
+	}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 46 - 0
include/anki/gl/GlHandleDeferredDeleter.h

@@ -0,0 +1,46 @@
+#ifndef ANKI_GL_GL_HANDLE_DEFERRED_DELETER_H
+#define ANKI_GL_GL_HANDLE_DEFERRED_DELETER_H
+
+#include "anki/gl/GlManager.h"
+#include "anki/gl/GlJobChainHandle.h"
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Common deleter for objects that require deferred deletion. Some handles
+/// might get releaced in various threads but their underlying GL object should 
+/// get deleted in the server thread (where the context is). This deleter will
+/// fire a server job with the deletion if the handle gets realeased thread 
+/// other than the server thread.
+template<typename T, typename TAlloc, typename TDeleteJob>
+class GlHandleDeferredDeleter
+{
+public:
+	void operator()(T* obj, TAlloc alloc, GlManager* manager)
+	{
+		ANKI_ASSERT(obj);
+		ANKI_ASSERT(manager);
+		
+		/// If not the server thread then create a job for the server thread
+		if(!manager->_getJobManager().isServerThread())
+		{
+			GlJobChainHandle jobs(manager);
+			
+			jobs.template _pushBackNewJob<TDeleteJob>(obj, alloc);
+			jobs.flush();
+		}
+		else
+		{
+			alloc.deleteInstance(obj);
+		}
+	}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 156 - 0
include/anki/gl/GlJobChain.h

@@ -0,0 +1,156 @@
+#ifndef ANKI_GL_GL_JOB_CHAIN_H
+#define ANKI_GL_GL_JOB_CHAIN_H
+
+#include "anki/gl/GlCommon.h"
+#include "anki/util/Assert.h"
+#include "anki/util/Allocator.h"
+
+namespace anki {
+
+// Forward 
+class GlJobManager;
+class GlJobChain;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// The base of all GL jobs
+class GlJob
+{
+public:
+	GlJob* nextJob = nullptr;
+
+	virtual ~GlJob()
+	{}
+
+	/// Execute job
+	virtual void operator()(GlJobChain*) = 0;
+};
+
+/// A common job that deletes an object
+template<typename T, typename TAlloc>
+class GlDeleteObjectJob: public GlJob
+{
+public:
+	T* m_ptr;
+	TAlloc m_alloc;
+
+	GlDeleteObjectJob(T* ptr, TAlloc alloc)
+		: m_ptr(ptr), m_alloc(alloc)
+	{
+		ANKI_ASSERT(m_ptr);
+	}
+
+	void operator()(GlJobChain*)
+	{
+		m_alloc.deleteInstance(m_ptr);
+	}
+};
+
+/// Job chain initialization hints. They are used to optimize the allocators
+/// of a job chain
+class GlJobChainInitHints
+{
+	friend class GlJobChain;
+
+private:
+	static const PtrSize m_maxChunkSize = 1024 * 1024; // 1MB
+
+	PtrSize m_chunkSize = 1024;
+};
+
+/// A number of GL jobs organized in a chain
+class GlJobChain: public NonCopyable
+{
+public:
+	/// Default constructor
+	/// @param server The job chains server
+	/// @param hints Hints to optimize the job's allocator
+	GlJobChain(GlJobManager* server, const GlJobChainInitHints& hints);
+
+	/// Move
+	GlJobChain(GlJobChain&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GlJobChain()
+	{
+		destroy();
+	}
+
+	/// Move
+	GlJobChain& operator=(GlJobChain&& b);
+
+	/// Get he allocator
+	GlJobChainAllocator<U8> getAllocator() const
+	{
+		return m_alloc;
+	}
+
+	GlGlobalHeapAllocator<U8> getGlobalAllocator() const;
+
+	GlJobManager& getJobManager()
+	{
+		return *m_server;
+	}
+
+	const GlJobManager& getJobManager() const
+	{
+		return *m_server;
+	}
+
+	/// Compute initialization hints
+	GlJobChainInitHints computeInitHints() const;
+
+	/// Create a new job and add it to the chain
+	template<typename TJob, typename... TArgs>
+	void pushBackNewJob(TArgs&&... args)
+	{
+		ANKI_ASSERT(m_immutable == false);
+		TJob* newJob = 
+			m_alloc.template newInstance<TJob>(std::forward<TArgs>(args)...);
+
+		if(m_firstJob != nullptr)
+		{
+			ANKI_ASSERT(m_lastJob != nullptr);
+			ANKI_ASSERT(m_lastJob->nextJob == nullptr);
+			m_lastJob->nextJob = newJob;
+			m_lastJob = newJob;
+		}
+		else
+		{
+			m_firstJob = newJob;
+			m_lastJob = newJob;
+		}
+	}
+
+	/// Execute all jobs
+	void executeAllJobs();
+
+	/// Make immutable
+	void makeImmutable()
+	{
+		m_immutable = true;
+	}
+
+private:
+	GlJobManager* m_server;
+	GlJob* m_firstJob = nullptr;
+	GlJob* m_lastJob = nullptr;
+	GlJobChainAllocator<U8> m_alloc;
+	Bool8 m_immutable = false;
+
+#if ANKI_DEBUG
+	Bool8 m_executed = false;
+#endif
+
+	void destroy();
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 170 - 0
include/anki/gl/GlJobChainHandle.h

@@ -0,0 +1,170 @@
+#ifndef ANKI_GL_GL_JOB_CHAIN_HANDLE_H
+#define ANKI_GL_GL_JOB_CHAIN_HANDLE_H
+
+#include "anki/gl/GlHandle.h"
+#include "anki/gl/GlJobChain.h"
+
+namespace anki {
+
+// Forward
+class GlManager;
+
+/// @addtogroup opengl_other
+/// @{
+
+/// Job chain handle
+class GlJobChainHandle: public GlHandle<GlJobChain>
+{
+public:
+	typedef GlHandle<GlJobChain> Base;
+	using UserCallback = void(*)(void*);
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlJobChainHandle();
+
+	/// Create job chain
+	explicit GlJobChainHandle(GlManager* gl, 
+		GlJobChainInitHints hints = GlJobChainInitHints());
+
+	~GlJobChainHandle();
+	/// @}
+
+	/// Add a user job at the end of the chain
+	void pushBackUserJob(UserCallback callback, void* data);
+
+	/// Add another job chain for execution
+	void pushBackOtherJobChain(GlJobChainHandle& jobs);
+
+	/// Flush chain for deffered deletion
+	void flush();
+
+	/// Flush and wait to finish
+	void finish();
+
+	/// Compute initialization hints
+	GlJobChainInitHints computeInitHints() const
+	{
+		return _get().computeInitHints();
+	}
+
+	/// @name State manipulation
+	/// @{
+
+	/// Set clear color buffers value
+	void setClearColor(F32 r, F32 g, F32 b, F32 a);
+
+	/// Set clear depth buffer value
+	void setClearDepth(F32 value);
+
+	/// Set clear stencil buffer value
+	void setClearStencil(U32 value);
+
+	/// Clear color/depth/stencil buffers
+	void clearBuffers(U32 mask);
+
+	/// Set the viewport
+	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
+
+	/// Set the color mask
+	void setColorWriteMask(Bool red, Bool green, Bool blue, Bool alpha);
+
+	/// Enable/disable depth test
+	void enableDepthTest(Bool enable);
+
+	/// Set depth compare function
+	void setDepthFunction(GLenum func);
+
+	/// Set depth write mask
+	void setDepthWriteMask(Bool write);
+
+	/// Enable or note stencil test
+	void enableStencilTest(Bool enable);
+
+	/// Set stencil function. Equivalent to glStencilFunc
+	void setStencilFunction(GLenum function, U32 reference, U32 mask);
+
+	/// Set the stencil mask. Equivalent to glStencilMask
+	void setStencilPlaneMask(U32 mask);
+
+	/// Set the operations of stencil fail, depth fail, depth pass. Equivalent
+	/// to glStencilOp
+	void setStencilOperations(GLenum stencFail, GLenum depthFail, 
+		GLenum depthPass);
+
+	/// Enable or not blending. Equivalent to glEnable/glDisable(GL_BLEND)
+	void enableBlend(Bool enable);
+
+	/// Set blend equation. Equivalent to glBlendEquation
+	void setBlendEquation(GLenum equation);
+
+	/// Set the blend functions. Equivalent to glBlendFunc
+	void setBlendFunctions(GLenum sfactor, GLenum dfactor);
+
+	/// Set the blend color. Equivalent to glBlendColor
+	void setBlendColor(F32 r, F32 g, F32 b, F32 a);
+
+	/// Enable primitive restart
+	void enablePrimitiveRestart(Bool enable);
+
+	/// Set patch number of vertices
+	void setPatchVertexCount(U32 count);
+
+	/// Enable or not face culling. Equal to glEnable(GL_CULL_FASE)
+	void enableCulling(Bool enable);
+
+	/// Set the faces to cull. Works when culling is enabled. Equal to
+	/// glCullFace(x)
+	void setCullFace(GLenum mode);
+
+	/// Set the polygon offset. Equal to glPolygonOffset() plus 
+	/// glEnable(GL_POLYGON_OFFSET_FILL)
+	void setPolygonOffset(F32 factor, F32 units);
+
+	/// Enable/disable polygon offset
+	void enablePolygonOffset(Bool enable);
+	/// @}
+
+	/// @privatesection
+	/// @{
+	GlJobChainAllocator<U8> _getAllocator() const
+	{
+		return _get().getAllocator();
+	}
+
+	GlGlobalHeapAllocator<U8> _getGlobalAllocator() const
+	{
+		return _get().getGlobalAllocator();
+	}
+
+	GlJobManager& _getJobManager()
+	{
+		return _get().getJobManager();
+	}
+
+	const GlJobManager& _getJobManager() const
+	{
+		return _get().getJobManager();
+	}
+
+	/// Add a new job to the list
+	template<typename TJob, typename... TArgs>
+	void _pushBackNewJob(TArgs&&... args)
+	{
+		_get().template pushBackNewJob<TJob>(std::forward<TArgs>(args)...);
+	}
+
+	/// Execute all jobs
+	void _executeAllJobs()
+	{
+		_get().executeAllJobs();
+	}
+	/// @}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 125 - 0
include/anki/gl/GlJobManager.h

@@ -0,0 +1,125 @@
+#ifndef ANKI_GL_GL_JOB_MANAGER_H
+#define ANKI_GL_GL_JOB_MANAGER_H
+
+#include "anki/gl/GlJobChainHandle.h"
+#include "anki/gl/GlSyncHandles.h"
+#include "anki/gl/GlState.h"
+#include "anki/util/Thread.h"
+
+namespace anki {
+
+// Forward
+class GlManager;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Job manager. It's essentialy a queue of job chains waiting for execution 
+/// and a server
+class GlJobManager
+{
+public:
+	/// @name Contructors/Destructor
+	/// @{
+	GlJobManager(GlManager* manager);
+
+	~GlJobManager();
+	/// @}
+
+	/// @name Accessors
+	/// @{
+	GlManager& getManager()
+	{
+		ANKI_ASSERT(m_manager);
+		return *m_manager;
+	}
+
+	const GlManager& getManager() const
+	{
+		ANKI_ASSERT(m_manager);
+		return *m_manager;
+	}
+
+	GlState& getState()
+	{
+		return m_state;
+	}
+
+	const GlState& getState() const
+	{
+		return m_state;
+	}
+	/// @}
+
+	/// Start the working thread
+	/// @note Don't free the context before calling #stop
+	void start(
+		GlCallback makeCurrentCallback, void* context, 
+		GlCallback swapBuffersCallback, void* swapBuffersCbData,
+		Bool registerMessages);
+
+	/// Stop the working thread
+	void stop();
+
+	/// Push a job chain to the queue for deferred execution
+	void flushJobChain(GlJobChainHandle& jobs);
+
+	/// Push a job chain to the queue and wait for it
+	void finishJobChain(GlJobChainHandle& jobs);
+
+	/// Sync the client and server
+	void syncClientServer();
+
+	/// Return true if this is the main thread
+	Bool isServerThread() const
+	{
+		return m_serverThreadId == std::this_thread::get_id();
+	}
+
+	/// Swap buffers
+	void swapBuffers();
+
+private:
+	GlManager* m_manager = nullptr;
+
+	Array<GlJobChainHandle, 32> m_queue; ///< Job queue
+	U64 m_tail; ///< Tail of queue
+	U64 m_head; ///< Head of queue. Points to the end
+	U8 m_renderingThreadSignal; ///< Signal to the thread
+	std::mutex m_mtx; ///< Wake the thread
+	std::condition_variable m_condVar; ///< To wake up the thread
+	std::thread m_thread;
+
+	void* m_ctx = nullptr; ///< Pointer to the system GL context
+	GlCallback m_makeCurrent; ///< Making a context current
+
+	GlJobChainHandle m_swapBuffersJobs;
+	GlCallback m_swapBuffersCallback;
+	void* m_swapBuffersCbData;
+	std::condition_variable m_frameCondVar;
+	std::mutex m_frameMtx;
+	Bool8 m_frameWait = false;
+
+	std::thread::id m_serverThreadId;
+	
+	GlState m_state;
+	GLuint m_defaultVao;
+
+	/// A special jobchain that is called every time we want to wait for the
+	/// server
+	GlJobChainHandle m_syncJobs;
+	GlClientSyncHandle m_sync;
+
+	/// The function that the thread runs
+	void threadLoop();
+	void prepare();
+	void finish();
+
+	static void swapBuffersInternal(void* self);
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 64 - 0
include/anki/gl/GlManager.h

@@ -0,0 +1,64 @@
+#ifndef ANKI_GL_GL_MANAGER_H
+#define ANKI_GL_GL_MANAGER_H
+
+#include "anki/gl/GlCommon.h"
+#include "anki/util/Singleton.h"
+#include "anki/gl/GlJobManager.h"
+
+namespace anki {
+
+/// @addtogroup opengl_other
+/// @{
+
+/// Common stuff for all GL contexts
+class GlManager
+{
+public:
+	/// @see GlJobManager::start
+	void init(
+		GlCallback makeCurrentCallback, void* context,
+		GlCallback swapBuffersCallback, void* swapBuffersCbData,
+		Bool registerDebugMessages);
+
+	void destroy();
+
+	/// Synchronize client and server
+	void syncClientServer();
+
+	/// Swap buffers
+	void swapBuffers();
+
+	/// Return the alignment of a buffer target
+	PtrSize getBufferOffsetAlignment(GLenum target);
+
+	/// @privatesection
+	/// @{
+	HeapAllocator<U8> _getAllocator() const
+	{
+		return m_alloc;
+	}
+
+	GlJobManager& _getJobManager() 
+	{
+		return *m_jobManager;
+	}
+
+	const GlJobManager& _getJobManager() const
+	{
+		return *m_jobManager;
+	}
+	/// @}
+
+private:
+	std::unique_ptr<GlJobManager> m_jobManager;
+	HeapAllocator<U8> m_alloc; ///< Keep it last to be deleted last
+};
+
+/// Singleton for common GL stuff
+typedef Singleton<GlManager> GlManagerSingleton;
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 10 - 70
include/anki/gl/GlObject.h

@@ -1,30 +1,20 @@
 #ifndef ANKI_GL_GL_OBJECT_H
 #define ANKI_GL_GL_OBJECT_H
 
-#include "anki/gl/Common.h"
-#include "anki/gl/GlException.h"
-#include "anki/Config.h"
-#include "anki/util/NonCopyable.h"
-#include "anki/util/Assert.h"
-#include "anki/util/Array.h"
-#include "anki/util/StdTypes.h"
-#include "anki/core/Timestamp.h"
-#include <thread>
-#include <atomic>
-#include <cstring>
+#include "anki/gl/GlCommon.h"
 
 namespace anki {
 
-/// @addtogroup OpenGL
+/// @addtogroup opengl_private
 /// @{
 
-/// A compound GL object that supports buffering depending on the frame
+/// A GL object
 class GlObject: public NonCopyable
 {
 public:
 	/// Default
 	GlObject()
-		: glId(0)
+		: m_glName(0)
 	{}
 
 	/// Move
@@ -45,76 +35,26 @@ public:
 	{
 		ANKI_ASSERT(!isCreated());
 		
-		glId = b.glId;
-		b.glId = 0;
+		m_glName = b.m_glName;
+		b.m_glName = 0;
 		return *this;
 	}
 
 	/// Get the GL name for the current frame
-	GLuint getGlId() const
+	GLuint getGlName() const
 	{
 		ANKI_ASSERT(isCreated());
-		return glId;
+		return m_glName;
 	}
 
 	/// GL object is created
 	Bool isCreated() const
 	{
-		return glId != 0;
+		return m_glName != 0;
 	}
 
 protected:
-	/// OpenGL name
-	GLuint glId;
-};
-
-/// Defines an non sharable GL object. Used to avoid idiotic mistakes and more
-/// specifically using the object from other than contexts
-class GlObjectContextNonSharable: protected GlObject
-{
-public:
-	GlObjectContextNonSharable()
-	{}
-
-	GlObjectContextNonSharable(GlObjectContextNonSharable&& b)
-	{
-		*this = std::move(b);
-	}
-
-	~GlObjectContextNonSharable()
-	{
-		checkNonSharable();
-	}
-
-	GlObjectContextNonSharable& operator=(GlObjectContextNonSharable&& b)
-	{
-		GlObject::operator=(std::forward<GlObject>(b));
-#if ANKI_DEBUG
-		creationThreadId = b.creationThreadId;
-#endif
-		return *this;
-	}
-
-	void crateNonSharable()
-	{
-#if ANKI_DEBUG
-		creationThreadId = std::this_thread::get_id();
-#endif
-	}
-
-	void checkNonSharable() const
-	{
-#if ANKI_DEBUG
-		ANKI_ASSERT((!isCreated()
-			|| creationThreadId == std::this_thread::get_id())
-			&& "Object is not context sharable");
-#endif
-	}
-
-private:
-#if ANKI_DEBUG
-	std::thread::id creationThreadId;
-#endif
+	GLuint m_glName; ///< OpenGL name
 };
 
 /// @}

+ 227 - 0
include/anki/gl/GlOperations.h

@@ -0,0 +1,227 @@
+#ifndef ANKI_GL_GL_OPERATIONS_H
+#define ANKI_GL_GL_OPERATIONS_H
+
+#include "anki/gl/GlCommon.h"
+#include "anki/gl/GlBufferHandle.h"
+#include "anki/gl/GlClientBufferHandle.h"
+
+namespace anki {
+
+/// @addtogroup opengl_other
+/// @{
+
+/// A GL drawcall for elements
+class GlDrawcallElements
+{
+	friend class GlDrawElementsJob;
+
+public:
+	/// Indirect structure
+	class Indirect
+	{
+	public:
+		Indirect()
+		{}
+
+		Indirect(U32 count, U32 instanceCount, U32 firstIndex, 
+			U32 baseVertex, U32 baseInstance)
+			:	m_count(count), m_instanceCount(instanceCount), 
+				m_firstIndex(firstIndex), m_baseVertex(baseVertex),
+				m_baseInstance(baseInstance)
+		{}
+
+		U32 m_count;
+		U32 m_instanceCount = 1;
+		U32 m_firstIndex = 0;
+		U32 m_baseVertex = 0;
+		U32 m_baseInstance = 0;
+	};
+
+	/// Default
+	GlDrawcallElements()
+		: m_drawCount(0)
+	{}
+
+	/// Initialize a glDrawElementsInstancedBaseVertexBaseInstance call
+	GlDrawcallElements(GLenum mode, U8 indexSize, U32 count, 
+		U32 instanceCount = 1, U32 firstIndex = 0, U32 baseVertex = 0,
+		U32 baseInstance = 0)
+		:	m_primitiveType(mode),
+			m_indexSize(indexSize),
+			m_drawCount(1)
+	{
+		m_noIndirect.m_count = count;
+		m_noIndirect.m_instanceCount = instanceCount;
+		m_noIndirect.m_firstIndex = firstIndex;
+		m_noIndirect.m_baseVertex = baseVertex;
+		m_noIndirect.m_baseInstance = baseInstance;
+	}
+
+	/// Initialize a glMultiDrawElementsIndirect call with server buffer
+	GlDrawcallElements(GLenum mode, U8 indexSize, 
+		const GlBufferHandle& indirectBuff, U32 drawCount, 
+		PtrSize offset, PtrSize stride)
+		:	m_primitiveType(mode),
+			m_indexSize(indexSize),
+			m_drawCount(drawCount),
+			m_indirectBuff(indirectBuff)
+	{
+		m_indirect.m_offset = offset;
+		m_indirect.m_stride = stride;
+	}
+
+	/// Initialize a glMultiDrawElementsIndirect call with client buffer
+	GlDrawcallElements(GLenum mode, U8 indexSize, 
+		const GlClientBufferHandle& indirectBuff, U32 drawCount, 
+		PtrSize offset, PtrSize stride)
+		:	m_primitiveType(mode),
+			m_indexSize(indexSize),
+			m_drawCount(drawCount),
+			m_indirectClientBuff(indirectBuff)
+	{
+		m_indirect.m_offset = offset;
+		m_indirect.m_stride = stride;
+	}
+
+	Bool isCreated() const
+	{
+		return m_drawCount > 0;
+	}
+
+	/// Execute the drawcall
+	void draw(GlJobChainHandle& jobs);
+
+private:
+	class IndirectView
+	{
+	public:
+		/// Indirect buffer offset
+		U32 m_offset;
+	
+		/// Indirect buffer stride
+		U32 m_stride;
+	};
+
+	/// The GL primitive type (eg GL_POINTS). Need to set it
+	GLenum m_primitiveType;
+	
+	/// Type of the indices
+	U8 m_indexSize;
+
+	/// Used in glMultiDrawElementsXXX
+	U8 m_drawCount;
+
+	/// Indirect buffer
+	GlBufferHandle m_indirectBuff;
+
+	/// Indirect client buffer
+	GlClientBufferHandle m_indirectClientBuff;
+
+	union
+	{
+		Indirect m_noIndirect;
+		IndirectView m_indirect;
+	};
+
+	/// Execute the job. Called by the server
+	void exec();
+};
+
+/// A GL drawcall for arrays
+class GlDrawcallArrays
+{
+	friend class GlDrawArraysJob;
+
+public:
+	/// Indirect structure
+	class Indirect
+	{
+	public:
+		Indirect()
+		{}
+
+		Indirect(U32 count, U32 instanceCount, U32 first, U32 baseInstance)
+			:	m_count(count), 
+				m_instanceCount(instanceCount), 
+				m_first(first), 
+				m_baseInstance(baseInstance)
+		{}
+
+		U32 m_count;
+		U32 m_instanceCount = 1;
+		U32 m_first = 0;
+		U32 m_baseInstance = 0;	
+	};
+
+	/// Default
+	GlDrawcallArrays()
+		: m_drawCount(0)
+	{}
+
+	/// Initialize a glDrawArraysInstancedBaseInstance call
+	GlDrawcallArrays(GLenum mode, U32 count, U32 instanceCount = 1, 
+		U32 first = 0, U32 baseInstance = 0)
+		:	m_primitiveType(mode),
+			m_noIndirect{count, instanceCount, first, baseInstance},
+			m_drawCount(1)
+	{}
+	
+	/// Initialize a glMultiDrawArraysIndirect call with server buffer
+	GlDrawcallArrays(GLenum mode, const GlBufferHandle& indirectBuff,
+		U32 drawCount, PtrSize offset, PtrSize stride)
+		:	m_primitiveType(mode),
+			m_drawCount(drawCount),
+			m_indirectBuff(indirectBuff),
+			m_offset(offset),
+			m_stride(stride)
+	{}
+
+	/// Initialize a glMultiDrawArraysIndirect call with client buffer
+	GlDrawcallArrays(GLenum mode, const GlClientBufferHandle& indirectBuff,
+		U32 drawCount, PtrSize offset, PtrSize stride)
+		:	m_primitiveType(mode),
+			m_drawCount(drawCount),
+			m_indirectClientBuff(indirectBuff),
+			m_offset(offset),
+			m_stride(stride)
+	{}
+
+	Bool isCreated() const
+	{
+		return m_drawCount > 0;
+	}
+
+	/// Execute the drawcall
+	void draw(GlJobChainHandle& jobs);
+
+private:
+	/// The GL primitive type (eg GL_POINTS). Need to set it
+	GLenum m_primitiveType;
+
+	/// No indirect data
+	Indirect m_noIndirect;
+
+	/// Used in glMultiDrawArraysXXX
+	U8 m_drawCount;
+
+	/// Indirect buffer
+	GlBufferHandle m_indirectBuff;
+
+	/// Indirect client buffer
+	GlClientBufferHandle m_indirectClientBuff;
+
+	/// Indirect buffer offset
+	U32 m_offset;
+	
+	/// Indirect buffer stride
+	U32 m_stride;
+
+	/// Execute the job. Called by the server
+	void exec();
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 151 - 0
include/anki/gl/GlProgram.h

@@ -0,0 +1,151 @@
+#ifndef ANKI_GL_GL_PROGRAM_H
+#define ANKI_GL_GL_PROGRAM_H
+
+#include "anki/gl/GlObject.h"
+#include "anki/util/Dictionary.h"
+#include "anki/util/Vector.h"
+
+namespace anki {
+
+// Forward
+class GlProgram;
+
+/// @addtogroup opengl_private
+/// @{
+
+/// All program data in a struct to ease moving it
+class GlProgramData: public NonCopyable
+{
+public:
+	template<typename T>
+	using ProgramVector = Vector<T, GlGlobalHeapAllocator<T>>;
+
+	template<typename T>
+	using ProgramDictionary = 
+		Dictionary<T, GlGlobalHeapAllocator<std::pair<const char*, T>>>;
+
+	GlProgramData(const GlGlobalHeapAllocator<U8>& alloc)
+		:	m_variables(alloc), 
+			m_variablesDict(10, DictionaryHasher(), DictionaryEqual(), alloc), 
+			m_blocks(alloc), 
+			m_blocksDict(10, DictionaryHasher(), DictionaryEqual(), alloc),
+			m_names(nullptr),
+			m_prog(nullptr)
+	{}
+
+	~GlProgramData() noexcept
+	{
+		if(m_names)
+		{
+			auto alloc = m_variables.get_allocator();
+			alloc.deallocate(m_names, 0);
+		}
+	}
+
+	ProgramVector<GlProgramVariable> m_variables;
+	ProgramDictionary<GlProgramVariable*> m_variablesDict;
+
+	ProgramVector<GlProgramBlock> m_blocks;
+	ProgramDictionary<GlProgramBlock*> m_blocksDict;
+
+	/// Keep all the names of blocks and variables in a single place
+	char* m_names;
+
+	/// As always keep the father
+	GlProgram* m_prog;
+};
+
+/// Shader program. It only contains a single shader and it can be combined 
+/// with other programs in a program pipiline.
+class GlProgram: public GlObject
+{
+	friend class GlProgramVariable;
+	friend class GlProgramBlock;
+
+public:
+	typedef GlObject Base;
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlProgram()
+		: m_data(nullptr)
+	{}
+
+	GlProgram(GlProgram&& b)
+	{
+		*this = std::move(b);
+	}
+
+	/// Create the program
+	/// @param shaderType The type of the shader in the program
+	/// @param source The shader's source
+	/// @param alloc The allocator to be used for internally
+	GlProgram(GLenum shaderType, const char* source, 
+		const GlGlobalHeapAllocator<U8>& alloc)
+		: m_data(nullptr)
+	{
+		create(shaderType, source, alloc);
+	}
+
+	~GlProgram()
+	{
+		destroy();
+	}
+	/// @}
+
+	/// Move
+	GlProgram& operator=(GlProgram&& b);
+
+	/// @name Accessors
+	/// @{
+	GLenum getType() const
+	{
+		ANKI_ASSERT(isCreated() && m_data);
+		return m_type;
+	}
+
+	const GlProgramData::ProgramVector<GlProgramVariable>& getVariables() const
+	{
+		ANKI_ASSERT(isCreated() && m_data);
+		return m_data->m_variables;
+	}
+
+	const GlProgramData::ProgramVector<GlProgramBlock>& getBlocks() const
+	{
+		ANKI_ASSERT(isCreated() && m_data);
+		return m_data->m_blocks;
+	}
+
+	const GlProgramVariable& findVariable(const char* name) const;
+	const GlProgramBlock& findBlock(const char* name) const;
+
+	const GlProgramVariable* tryFindVariable(const char* name) const;
+	const GlProgramBlock* tryFindBlock(const char* name) const;
+	/// @}
+
+private:
+	GLenum m_type;
+	GlProgramData* m_data;
+
+	void create(GLenum type, const char* source, 
+		const GlGlobalHeapAllocator<U8>& alloc);
+	void createInternal(GLenum type, const char* source, 
+		const GlGlobalHeapAllocator<U8>& alloc);
+	void destroy();
+
+	/// Query the program for blocks
+	void initBlocksOfType(GLenum programInterface, U count, U index,
+		char*& namesPtr, U& namesLen);
+
+	/// Query the program for variables
+	void initVariablesOfType(
+		GLenum programInterface, U count, U index, U blkIndex,
+		char*& namesPtr, U& namesLen);
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 61 - 0
include/anki/gl/GlProgramHandle.h

@@ -0,0 +1,61 @@
+#ifndef ANKI_GL_GL_PROGRAM_HANDLE_H
+#define ANKI_GL_GL_PROGRAM_HANDLE_H
+
+#include "anki/gl/GlContainerHandle.h"
+#include "anki/util/Vector.h"
+
+namespace anki {
+
+// Forward
+class GlProgram;
+class GlClientBufferHandle;
+
+/// @addtogroup opengl_containers
+/// @{
+
+/// Program handle
+class GlProgramHandle: public GlContainerHandle<GlProgram>
+{
+public:
+	typedef GlContainerHandle<GlProgram> Base;
+
+	// Re-define it here
+	template<typename T>
+	using ProgramVector = Vector<T, GlGlobalHeapAllocator<T>>;
+
+	/// @name Contructors/Destructor
+	/// @{
+	GlProgramHandle();
+
+	/// Create program
+	explicit GlProgramHandle(GlJobChainHandle& jobs, 
+		GLenum shaderType, const GlClientBufferHandle& source);
+
+	~GlProgramHandle();
+	/// @}
+
+	/// @name Accessors
+	/// They will sync
+	/// @{
+	GLenum getType() const;
+
+	const ProgramVector<GlProgramVariable>& getVariables() const;
+
+	const ProgramVector<GlProgramBlock>& getBlocks() const;
+
+	const GlProgramVariable& findVariable(const char* name) const;
+
+	const GlProgramBlock& findBlock(const char* name) const;
+
+	const GlProgramVariable* tryFindVariable(const char* name) const;
+
+	const GlProgramBlock* tryFindBlock(const char* name) const;
+	/// @}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 61 - 0
include/anki/gl/GlProgramPipeline.h

@@ -0,0 +1,61 @@
+#ifndef ANKI_GL_GL_PROGRAM_PIPELINE_H
+#define ANKI_GL_GL_PROGRAM_PIPELINE_H
+
+#include "anki/gl/GlObject.h"
+#include "anki/gl/GlProgramHandle.h"
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Program pipeline
+class GlProgramPipeline: public GlObject
+{
+public:
+	typedef GlObject Base;
+
+	/// @name Constructors/Desctructor
+	/// @{
+	GlProgramPipeline()
+	{}
+
+	GlProgramPipeline(GlProgramPipeline&& b)
+	{
+		*this = std::move(b);
+	}
+
+	GlProgramPipeline(
+		const GlProgramHandle* progsBegin, const GlProgramHandle* progsEnd);
+
+	~GlProgramPipeline()
+	{
+		destroy();
+	}
+	/// @}
+
+	GlProgramPipeline& operator=(GlProgramPipeline&& b);
+
+	GlProgramHandle getAttachedProgram(GLenum type) const;
+
+	/// Bind the pipeline to the state
+	void bind();
+
+private:
+	Array<GlProgramHandle, 6> m_progs;
+
+	/// Create pipeline object
+	void createPpline();
+
+	/// Attach all the programs
+	void attachProgramsInternal(const GlProgramHandle* progs, PtrSize count);
+
+	void destroy();
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 58 - 0
include/anki/gl/GlProgramPipelineHandle.h

@@ -0,0 +1,58 @@
+#ifndef ANKI_GL_GL_PROGRAM_PIPELINE_HANDLE_H
+#define ANKI_GL_GL_PROGRAM_PIPELINE_HANDLE_H
+
+#include "anki/gl/GlContainerHandle.h"
+
+namespace anki {
+
+// Forward
+class GlJobChainHandle;
+class GlProgramPipeline;
+class GlProgramHandle;
+
+/// @addtogroup opengl_misc
+/// @{
+
+/// Program pipeline handle
+class GlProgramPipelineHandle: public GlContainerHandle<GlProgramPipeline>
+{
+public:
+	using Base = GlContainerHandle<GlProgramPipeline>;
+
+	/// @name Contructors/Destructor
+	/// @{
+	GlProgramPipelineHandle();
+
+	/// Create a pipeline
+	explicit GlProgramPipelineHandle(
+		GlJobChainHandle& jobs,
+		const GlProgramHandle* progsBegin, const GlProgramHandle* progsEnd)
+	{
+		commonConstructor(jobs, progsBegin, progsEnd);
+	}
+
+	/// Create using initializer list
+	explicit GlProgramPipelineHandle(
+		GlJobChainHandle& jobs,
+		std::initializer_list<GlProgramHandle> progs);
+
+	~GlProgramPipelineHandle();
+	/// @}
+
+	/// Bind it to the state
+	void bind(GlJobChainHandle& jobs);
+
+	/// Get an attached program. It may serialize
+	GlProgramHandle getAttachedProgram(GLenum type) const;
+
+public:
+	void commonConstructor(GlJobChainHandle& jobs,
+		const GlProgramHandle* progsBegin, const GlProgramHandle* progsEnd);
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 25 - 110
include/anki/gl/GlState.h

@@ -1,137 +1,52 @@
 #ifndef ANKI_GL_GL_STATE_H
 #define ANKI_GL_GL_STATE_H
 
-#include "anki/util/Singleton.h"
-#include "anki/gl/Common.h"
-#include "anki/util/Assert.h"
-#include "anki/util/StdTypes.h"
-#include "anki/util/Array.h"
-#include "anki/Math.h"
+#include "anki/gl/GlCommon.h"
 
 namespace anki {
 
-class Vao;
-class Fbo;
-class ShaderProgram;
-
-/// @addtogroup OpenGL
+/// @addtogroup opengl_private
 /// @{
 
-/// Common stuff for all GL states
-class GlStateCommon
+/// Knowing the ventor allows some optimizations
+enum class GlGpu: U8
 {
-public:
-	/// Knowing the ventor allows some optimizations
-	enum Gpu
-	{
-		GPU_UNKNOWN,
-		GPU_ARM,
-		GPU_NVIDIA
-	};
-
-	/// Return something like 430
-	U32 getVersion() const
-	{
-		ANKI_ASSERT(version != -1);
-		return version;
-	}
-
-	Gpu getGpu() const
-	{
-		return gpu;
-	}
-
-	Bool isTessellationSupported() const
-	{
-		return version >= 400;
-	}
-
-	Bool isComputeShaderSupported() const
-	{
-		return version >= 430;
-	}
-
-	Bool isDeferredRenderer() const
-	{
-		return gpu == GPU_ARM;
-	}
-
-	void init(const U32 major, const U32 minor, 
-		Bool registerDebugMessages = false);
-
-private:
-	/// Minor major GL version
-	I32 version = -1;
-	Gpu gpu = GPU_UNKNOWN;
+	UNKNOWN,
+	ARM,
+	NVIDIA
 };
 
-typedef Singleton<GlStateCommon> GlStateCommonSingleton;
-
-/// Access the GL state machine.
-/// This class saves us from calling the GL functions
+/// Part of the global state. It's essentialy a cache of the state mainly used
+/// for optimizations and other stuff
 class GlState
 {
 public:
-	GlState()
-	{
-		sync();
-	}
-
-	~GlState()
-	{}
-
-	/// @name Alter the GL state when needed
+	I32 m_version = -1; ///< Minor major GL version. Something like 430
+	GlGpu m_gpu = GlGpu::UNKNOWN;
+	U32 m_texUnitsCount = 0;
+	Bool8 m_registerMessages = false;
+	U32 m_uniBuffOffsetAlignment = 0;
+	U32 m_ssBuffOffsetAlignment = 0;
+
+	/// @name Cached state
 	/// @{
-	void enable(GLenum cap, Bool enable = true);
-	void disable(GLenum cap)
-	{
-		enable(cap, false);
-	}
-	bool isEnabled(GLenum cap);
+	Array<U16, 4> m_viewport = {{0, 0, 0, 0}};
 
-	void setViewport(U32 x, U32 y, U32 w, U32 h);
+	GLenum m_blendSfunc = GL_ONE;
+	GLenum m_blendDfunc = GL_ZERO;
 
-	void setClearColor(const Vec4& color);
+	GLuint m_crntPpline = 0;
 
-	void setClearDepthValue(const GLfloat depth);
-
-	void setClearStencilValue(const GLint s);
-
-	void setBlendFunctions(const GLenum sFactor, const GLenum dFactor);
-
-	void setDepthMaskEnabled(const Bool enable);
-	void setDepthFunc(const GLenum val);
-
-	void setPolygonMode(const GLenum mode);
-	/// @}
-
-private:
-	/// @name The GL state
-	/// @{
-	Array<Bool, 7> flags;
-	Array<GLint, 4> viewport;
-	GLfloat clearDepthValue;
-	GLint clearStencilValue;
-	Array<GLenum, 2> blendFuncs;
-
-	Array<GLint, 4> colorMask;
-	GLint depthMask;
-	GLenum depthFunc;
-
-#if ANKI_GL == ANKI_GL_DESKTOP
-	GLenum polyMode;
-#endif
+	Array<GLuint, 256> m_texUnits;
 	/// @}
 
-	/// Sync the local members with the opengl ones
-	void sync();
-
-	static U getIndexFromGlEnum(const GLenum cap);
+	/// Call this from the server
+	void init();
 };
 
-typedef SingletonThreadSafe<GlState> GlStateSingleton;
 /// @}
 
 } // end namespace anki
 
 #endif
+

+ 35 - 0
include/anki/gl/GlSync.h

@@ -0,0 +1,35 @@
+#ifndef ANKI_GL_GL_SYNC_H
+#define ANKI_GL_GL_SYNC_H
+
+#include "anki/gl/GlCommon.h"
+#include "anki/util/Thread.h"
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Sync with the client
+class GlClientSync
+{
+public:
+	GlClientSync()
+		: m_barrier(2)
+	{}
+
+	/// Wait 
+	void wait()
+	{
+		m_barrier.wait();
+	}
+
+private:
+	Barrier m_barrier;
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 41 - 0
include/anki/gl/GlSyncHandles.h

@@ -0,0 +1,41 @@
+#ifndef ANKI_GL_GL_SYNC_HANDLES_H
+#define ANKI_GL_GL_SYNC_HANDLES_H
+
+#include "anki/gl/GlHandle.h"
+
+namespace anki {
+
+// Forward
+class GlClientSync;
+class GlJobChainHandle;
+
+/// @addtogroup opengl_other
+/// @{
+
+/// Client sync handle
+class GlClientSyncHandle: public GlHandle<GlClientSync>
+{
+public:
+	typedef GlHandle<GlClientSync> Base;
+
+	GlClientSyncHandle();
+
+	GlClientSyncHandle(GlJobChainHandle& jobs);
+
+	~GlClientSyncHandle();
+
+	/// Fire a job that adds a waits for the client. The client should call 
+	/// wait some time after this call or the server will keep waiting forever
+	void sync(GlJobChainHandle& jobs);
+
+	/// Wait for the server. You need to call sync first or the client will
+	/// keep waiting forever
+	void wait();
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 164 - 0
include/anki/gl/GlTexture.h

@@ -0,0 +1,164 @@
+#ifndef ANKI_GL_GL_TEXTURE_H
+#define ANKI_GL_GL_TEXTURE_H
+
+#include "anki/gl/GlObject.h"
+#include "anki/util/Array.h"
+#include <cstring>
+
+namespace anki {
+
+/// @addtogroup opengl_private
+/// @{
+
+/// Texture container
+class GlTexture: public GlObject
+{
+public:
+	typedef GlObject Base;
+
+	typedef GlTextureFilter Filter;
+
+	/// Texture handle initializer struct
+	class Initializer: public GlTextureInitializerBase
+	{
+	public:
+		class Data
+		{
+		public:
+			void* m_ptr;
+			PtrSize m_size;
+		};
+
+		/// Array of data in: [mip][layer]
+		Array2d<Data, ANKI_GL_MAX_MIPMAPS, ANKI_GL_MAX_TEXTURE_LAYERS> m_data;
+
+		Initializer()
+		{
+			memset(&m_data[0][0], 0, sizeof(m_data));
+		}
+	};
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlTexture()
+	{}
+
+	GlTexture(const Initializer& init, 
+		GlGlobalHeapAllocator<U8>& alloc)
+	{
+		create(init, alloc);
+	}
+
+	GlTexture(GlTexture&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GlTexture()
+	{
+		destroy();
+	}
+	/// @}
+
+	/// Move
+	GlTexture& operator=(GlTexture&& b);
+
+	/// @name Accessors
+	/// @{
+	GLenum getInternalFormat() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_internalFormat;
+	}
+
+	GLenum getFormat() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_format;
+	}
+
+	GLenum getTarget() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_target;
+	}
+
+	GLenum getType() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_type;
+	}
+
+	U32 getWidth() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_width;
+	}
+
+	U32 getHeight() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_height;
+	}
+
+	U32 getDepth() const
+	{
+		ANKI_ASSERT(isCreated());
+		return m_depth;
+	}
+	/// @}
+
+	/// Bind the texture to a specified unit
+	void bind(U32 unit) const;
+
+	/// Change the filtering type
+	void setFilter(const Filter filterType)
+	{
+		bind(0);
+		setFilterNoBind(filterType);
+	}
+
+	Filter getFilter() const
+	{
+		return m_filter;
+	}
+
+	/// Set texture parameter
+	void setParameter(GLenum param, GLint value)
+	{
+		bind(0);
+		glTexParameteri(m_target, param, value);
+	}
+
+	/// Set the range of the mipmaps
+	/// @param baseLevel The level of the base mipmap. By default is 0
+	/// @param maxLevel The level of the max mimap. Most of the time it's 1000.
+	void setMipmapsRange(U32 baseLevel, U32 maxLevel);
+
+	/// Generate mipmaps
+	void generateMipmaps();
+
+private:
+	GLenum m_target; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
+	GLenum m_internalFormat; ///< GL_COMPRESSED_RED, GL_RGB16 etc
+	GLenum m_format; ///< GL_RED, GL_RG, GL_RGB etc
+	GLenum m_type; ///< GL_UNSIGNED_BYTE, GL_BYTE etc
+	U32 m_width;
+	U32 m_height;
+	U32 m_depth;
+	Filter m_filter;
+	U8 m_samples;
+
+	/// Create a texture
+	void create(const Initializer& init, GlGlobalHeapAllocator<U8>& alloc);
+
+	void destroy();
+
+	void setFilterNoBind(Filter filterType);
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 69 - 0
include/anki/gl/GlTextureHandle.h

@@ -0,0 +1,69 @@
+#ifndef ANKI_GL_GL_TEXTURE_HANDLE_H
+#define ANKI_GL_GL_TEXTURE_HANDLE_H
+
+#include "anki/gl/GlContainerHandle.h"
+#include "anki/gl/GlClientBufferHandle.h"
+
+namespace anki {
+
+// Forward
+class GlTexture;
+
+/// @addtogroup opengl_containers
+/// @{
+
+/// Texture handle
+class GlTextureHandle: public GlContainerHandle<GlTexture>
+{
+public:
+	typedef GlContainerHandle<GlTexture> Base;
+
+	typedef GlTextureFilter Filter;
+
+	/// Texture handle initializer
+	class Initializer: public GlTextureInitializerBase
+	{
+	public:
+		Array2d<GlClientBufferHandle, 
+			ANKI_GL_MAX_MIPMAPS, ANKI_GL_MAX_TEXTURE_LAYERS> m_data;
+	};
+
+	/// @name Constructors/Destructor
+	/// @{
+
+	/// Create husk
+	GlTextureHandle();
+
+	/// Create the texture
+	explicit GlTextureHandle(GlJobChainHandle& chain, const Initializer& init);
+
+	~GlTextureHandle();
+	/// @}
+
+	/// Bind to a unit
+	void bind(GlJobChainHandle& chain, U32 unit);
+
+	/// Change filtering type
+	void setFilter(GlJobChainHandle& chain, Filter filter);
+
+	/// Generate mips
+	void generateMipmaps(GlJobChainHandle& chain);
+
+	/// Set a texture parameter
+	void setParameter(GlJobChainHandle& chain, GLenum param, GLint value);
+
+	/// Get depth
+	U32 getDepth() const;
+
+	/// Get width
+	U32 getWidth() const;
+
+	/// Get height
+	U32 getHeight() const;
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 0 - 61
include/anki/gl/Query.h

@@ -1,61 +0,0 @@
-#ifndef ANKI_GL_QUERY_H
-#define ANKI_GL_QUERY_H
-
-#include "anki/gl/GlObject.h"
-
-namespace anki {
-
-/// @addtogroup OpenGL
-/// @{
-
-/// Query object
-class Query: public GlObjectContextNonSharable
-{
-public:
-	typedef GlObjectContextNonSharable Base;
-
-	/// @name Constructors/Destructor
-	/// @{
-
-	/// @param q One of GL_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED, 
-	///          GL_TIME_ELAPSED
-	Query(GLenum q);
-
-	/// Move
-	Query(Query&& b)
-	{
-		*this = std::move(b);
-	}
-
-	~Query();
-	/// @}
-
-	/// Move
-	Query& operator=(Query&& b);
-
-	/// Start
-	void begin();
-
-	/// End
-	void end();
-
-	/// Get results. Waits for operations to finish
-	GLuint64 getResult();
-
-	/// Get results. Doesn't Wait for operations to finish. If @a finished is
-	/// false then the return value is irrelevant
-	GLuint64 getResultNoWait(Bool& finished);
-
-private:
-	GLenum question;
-
-	void create(const GLenum q);
-
-	void destroy();
-};
-
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 453
include/anki/gl/ShaderProgram.h

@@ -1,453 +0,0 @@
-#ifndef ANKI_GL_SHADER_PROGRAM_H
-#define ANKI_GL_SHADER_PROGRAM_H
-
-#include "anki/gl/GlObject.h"
-#include "anki/util/Dictionary.h"
-#include "anki/Math.h"
-#include "anki/util/Vector.h"
-#include <string>
-#include <memory>
-
-namespace anki {
-
-class ShaderProgram;
-class ShaderProgramUniformBlock;
-class Texture;
-
-/// @addtogroup OpenGL
-/// @{
-
-/// Shader program variable. The type is attribute or uniform
-class ShaderProgramVariable
-{
-	friend class ShaderProgram;
-
-public:
-	/// Shader var types
-	enum ShaderProgramVariableType
-	{
-		SPVT_ATTRIBUTE,
-		SPVT_UNIFORM
-	};
-
-	ShaderProgramVariable(ShaderProgramVariableType type_)
-		: type(type_)
-	{}
-	virtual ~ShaderProgramVariable()
-	{}
-
-	ShaderProgramVariable& operator=(const ShaderProgramVariable& b);
-
-	/// @name Accessors
-	/// @{
-	const ShaderProgram& getFatherShaderProgram() const
-	{
-		return *fatherSProg;
-	}
-
-	GLint getLocation() const
-	{
-		return loc;
-	}
-
-	const std::string& getName() const
-	{
-		return name;
-	}
-
-	GLenum getGlDataType() const
-	{
-		return glDataType;
-	}
-
-	ShaderProgramVariableType getType() const
-	{
-		return type;
-	}
-
-	PtrSize getSize() const
-	{
-		return size;
-	}
-	/// @}
-
-private:
-	GLint loc; ///< GL location
-	std::string name; ///< The name inside the shader program
-	/// GL_FLOAT, GL_FLOAT_VEC2 etc. See
-	/// http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml
-	GLenum glDataType;
-	PtrSize size; ///< Its 1 if it is a single or >1 if it is an array
-	ShaderProgramVariableType type;
-	/// We need the ShaderProg of this variable mainly for sanity checks
-	const ShaderProgram* fatherSProg;
-};
-
-/// Uniform shader variable
-class ShaderProgramUniformVariable: public ShaderProgramVariable
-{
-	friend class ShaderProgramUniformBlock;
-	friend class ShaderProgram;
-
-public:
-	ShaderProgramUniformVariable()
-		: ShaderProgramVariable(SPVT_UNIFORM)
-	{}
-
-	ShaderProgramUniformVariable& operator=(
-		const ShaderProgramUniformVariable& b);
-
-	const ShaderProgramUniformBlock* getUniformBlock() const
-	{
-		return block;
-	}
-
-	/// @name Set the var
-	/// @{
-	void set(const F32 x) const;
-	void set(const Vec2& x) const;
-	void set(const Vec3& x) const
-	{
-		set(&x, 1);
-	}
-	void set(const Vec4& x) const
-	{
-		set(&x, 1);
-	}
-	void set(const Mat3& x) const
-	{
-		set(&x, 1);
-	}
-	void set(const Mat4& x) const
-	{
-		set(&x, 1);
-	}
-	void set(const Texture& tex) const;
-
-	void set(const Texture* const texes[], const U32 count) const;
-
-	void set(const F32 x[], U32 size) const;
-	void set(const Vec2 x[], U32 size) const;
-	void set(const Vec3 x[], U32 size) const;
-	void set(const Vec4 x[], U32 size) const;
-	void set(const Mat3 x[], U32 size) const;
-	void set(const Mat4 x[], U32 size) const;
-
-	/// @tparam Container It could be something like array<F32, X> or 
-	///         vector<Vec2> etc
-	template<typename Container>
-	void setContainer(const Container& c) const
-	{
-		set(&c[0], c.size());
-	}
-	/// @}
-
-	/// @name Uniform block setters
-	/// Write a client memory that represents the uniform block
-	/// @{
-	void setClientMemory(void* buff, U32 buffSize,
-		const F32 arr[], U32 size) const;
-
-	void setClientMemory(void* buff, U32 buffSize,
-		const Vec2 arr[], U32 size) const;
-
-	void setClientMemory(void* buff, U32 buffSize,
-		const Vec3 arr[], U32 size) const;
-
-	void setClientMemory(void* buff, U32 buffSize,
-		const Vec4 arr[], U32 size) const;
-
-	void setClientMemory(void* buff, U32 buffSize,
-		const Mat3 arr[], U32 size) const;
-
-	void setClientMemory(void* buff, U32 buffSize,
-		const Mat4 arr[], U32 size) const;
-	/// @}
-
-private:
-	GLuint index;
-
-	ShaderProgramUniformBlock* block = nullptr;
-
-	/// Offset inside the uniform block. -1 if it's inside the default uniform 
-	/// block
-	GLint offset = -1; 
-
-	/// "An array identifying the stride between elements, in basic machine 
-	/// units, of each of the uniforms specified by the corresponding array of
-	/// uniformIndices is returned. The stride of a uniform associated with
-	/// the default uniform block is -1. Note that this information only makes
-	/// sense for uniforms that are arrays. For uniforms that are not arrays, 
-	/// but are declared in a named uniform block, an array stride of zero is 
-	/// returned"
-	GLint arrayStride = -1;
-
-	/// Identifying the stride between columns of a column-major matrix or rows 
-	/// of a row-major matrix
-	GLint matrixStride = -1;
-
-	/// Standard set uniform checks
-	/// - Check if initialized
-	/// - if the current shader program is the var's shader program
-	/// - if the GL driver gives the same location as the one the var has
-	void doCommonSetCode() const;
-
-	/// Do common checks
-	template<typename T>
-	void setClientMemorySanityChecks(U32 buffSize, U32 size) const;
-
-	/// Do the actual job of setClientMemory
-	template<typename T>
-	void setClientMemoryInternal(void* buff_, U32 buffSize,
-		const T arr[], U32 size) const;
-
-	/// Do the actual job of setClientMemory for matrices
-	template<typename Mat, typename Vec>
-	void setClientMemoryInternalMatrix(void* buff_, U32 buffSize,
-		const Mat arr[], U32 size) const;
-};
-
-/// Attribute shader program variable
-class ShaderProgramAttributeVariable: public ShaderProgramVariable
-{
-	friend class ShaderProgram;
-
-public:
-	ShaderProgramAttributeVariable()
-		: ShaderProgramVariable(SPVT_ATTRIBUTE)
-	{}
-};
-
-/// Uniform shader block
-class ShaderProgramUniformBlock
-{
-	friend class ShaderProgram;
-
-public:
-	ShaderProgramUniformBlock()
-	{}
-	ShaderProgramUniformBlock(const ShaderProgramUniformBlock& b)
-	{
-		operator=(b);
-	}
-	~ShaderProgramUniformBlock()
-	{}
-
-	/// @name Accessors
-	/// @{
-	GLuint getIndex() const
-	{
-		return index;
-	}
-
-	U32 getSize() const
-	{
-		return size;
-	}
-
-	const std::string& getName() const
-	{
-		return name;
-	}
-
-	GLuint getBinding() const
-	{
-		return bindingPoint;
-	}
-	void setBinding(GLuint bp) const
-	{
-		// Don't try any opts with existing binding point. Binding points 
-		// should break
-		glUniformBlockBinding(progId, index, bp);
-		bindingPoint = bp;
-	}
-	/// @}
-
-	ShaderProgramUniformBlock& operator=(const ShaderProgramUniformBlock& b);
-
-private:
-	Vector<ShaderProgramUniformVariable*> uniforms;
-	GLuint index = GL_INVALID_INDEX;
-	U32 size = 0; ///< In bytes
-	std::string name;
-	/// Ask the program to get you the binding point
-	mutable GLuint bindingPoint;
-	GLuint progId; ///< Needed for binding
-};
-
-/// Shader program object
-class ShaderProgram: public GlObject
-{
-public:
-	typedef GlObject Base;
-
-	typedef Vector<ShaderProgramUniformVariable>
-		UniformVariablesContainer;
-	typedef Vector<ShaderProgramAttributeVariable>
-		AttributeVariablesContainer;
-	typedef Vector<ShaderProgramUniformBlock>
-		UniformBlocksContainer;
-
-	/// @name Constructors/Destructor
-	/// @{
-	ShaderProgram()
-	{}
-
-	/// Move. It's not movable untill we need it
-	ShaderProgram(ShaderProgram&& b) = delete;
-
-	ShaderProgram(const char* vertSource, const char* tcSource, 
-		const char* teSource, const char* geomSource, const char* fragSource,
-		const char* compSource,
-		const char* transformFeedbackVaryings[],
-		const GLenum xfbBufferMode = GL_SEPARATE_ATTRIBS)
-	{
-		create(vertSource, tcSource, teSource, geomSource, fragSource,
-			compSource, transformFeedbackVaryings, xfbBufferMode);
-	}
-
-	~ShaderProgram()
-	{
-		destroy();
-	}
-	/// @}
-
-	/// Move deleted. It's not movable untill we need it
-	ShaderProgram& operator=(ShaderProgram&& b) = delete;
-
-	/// @name Accessors
-	/// @{
-	const UniformVariablesContainer& getUniformVariables() const
-	{
-		ANKI_ASSERT(isCreated());
-		return unis;
-	}
-
-	const AttributeVariablesContainer& getAttributeVariables() const
-	{
-		ANKI_ASSERT(isCreated());
-		return attribs;
-	}
-	/// @}
-
-	/// Create the program
-	/// @param vertSource Vertex shader source
-	/// @param tcSource Tessellation control shader source. Can be nullptr
-	/// @param teSource Tessellation evaluation shader source. Can be nullptr
-	/// @param geomSource Geometry shader source. Can be nullptr
-	/// @param fragSource Fragment shader source. Can be nullptr
-	/// @param compSource Compute shader source. Can be nullptr
-	/// @param xfbVaryings An array of varyings names. Eg 
-	///                    {"var0", "var1", nullptr}. Can be nullptr
-	/// @param xfbBufferMode GL_SEPARATE_ATTRIBS or GL_INTERLEAVED_ATTRIBS
-	void create(
-		const char* vertSource, const char* tcSource, const char* teSource, 
-		const char* geomSource, const char* fragSource, const char* compSource,
-		const char* xfbVaryings[], 
-		const GLenum xfbBufferMode = GL_SEPARATE_ATTRIBS);
-
-	/// Bind the shader program
-	void bind() const
-	{
-		ANKI_ASSERT(isCreated());
-		if(current != this)
-		{
-			glUseProgram(glId);
-			current = this;
-		}
-	}
-
-	// Unbinds only @a this if its binded
-	void unbind() const
-	{
-		ANKI_ASSERT(isCreated());
-		if(current == this)
-		{
-			glUseProgram(0);
-			current = nullptr;
-		}
-	}
-
-	/// @name Variable finders
-	/// Used to find and return the variable. They return nullptr if the 
-	/// variable is not found
-	/// @{
-	const ShaderProgramUniformVariable* tryFindUniformVariable(
-		const char* varName) const;
-	const ShaderProgramUniformVariable& findUniformVariable(
-		const char* varName) const;
-	const ShaderProgramAttributeVariable* tryFindAttributeVariable(
-		const char* varName) const;
-	const ShaderProgramAttributeVariable& findAttributeVariable(
-		const char* varName) const;
-	const ShaderProgramUniformBlock* tryFindUniformBlock(
-		const char* name) const;
-	const ShaderProgramUniformBlock& findUniformBlock(const char* name) const;
-	/// @}
-
-	static GLuint getCurrentProgramGlId()
-	{
-		GLint i;
-		glGetIntegerv(GL_CURRENT_PROGRAM, &i);
-		return i;
-	}
-
-	/// For debugging
-	friend std::ostream& operator<<(std::ostream& s,
-		const ShaderProgram& x);
-
-private:
-	typedef Dictionary<ShaderProgramUniformVariable*>
-		NameToUniVarHashMap;
-
-	typedef Dictionary<ShaderProgramAttributeVariable*>
-		NameToAttribVarHashMap;
-
-	typedef Dictionary<ShaderProgramUniformBlock*>
-		NameToUniformBlockHashMap;
-
-	static thread_local const ShaderProgram* current;
-
-	GLuint vertShaderGlId = 0; ///< Vertex shader OpenGL id
-	GLuint tcShaderGlId = 0; ///< Tessellation control shader OpenGL id
-	GLuint teShaderGlId = 0; ///< Tessellation eval shader OpenGL id
-	GLuint geomShaderGlId = 0; ///< Geometry shader OpenGL id
-	GLuint fragShaderGlId = 0; ///< Fragment shader OpenGL id
-	GLuint compShaderGlId = 0; ///< Compute shader OpenGL id
-
-	/// @name Containers
-	/// @{
-	UniformVariablesContainer unis;
-	AttributeVariablesContainer attribs;
-
-	NameToUniVarHashMap nameToUniVar; ///< Uniform searching
-	NameToAttribVarHashMap nameToAttribVar; ///< Attribute searching
-
-	UniformBlocksContainer blocks;
-	NameToUniformBlockHashMap nameToBlock;
-	/// @}
-
-	/// Query the driver to get the vars. After the linking of the shader
-	/// prog is done gather all the vars in custom containers
-	void initUniAndAttribVars();
-
-	/// Get info about the uniform blocks
-	void initUniformBlocks();
-
-	/// Create and compile shader
-	/// @return The shader's OpenGL id
-	/// @exception Exception
-	static GLuint createAndCompileShader(const char* sourceCode,
-		const char* preproc, GLenum type);
-
-	/// Link the shader program
-	/// @exception Exception
-	void link() const;
-
-	void destroy();
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 329
include/anki/gl/Texture.h

@@ -1,329 +0,0 @@
-#ifndef ANKI_GL_TEXTURE_H
-#define ANKI_GL_TEXTURE_H
-
-#include "anki/util/Assert.h"
-#include "anki/util/Array.h"
-#include "anki/util/Singleton.h"
-#include "anki/util/Vector.h"
-#include "anki/util/StdTypes.h"
-#include "anki/util/NonCopyable.h"
-#include "anki/gl/Common.h"
-#include <cstdlib>
-#include <cstring>
-#include <limits>
-#include <thread>
-
-namespace anki {
-
-class Texture;
-
-/// @addtogroup OpenGL
-/// @{
-
-/// The absolute limit of textures
-const U MAX_TEXTURES = 512;
-
-/// Contains a few hints on how to crate textures
-class TextureManager
-{
-public:
-	TextureManager();
-
-	/// @name Accessors
-	/// @{
-	U getAnisotropyLevel() const
-	{
-		return anisotropyLevel;
-	}
-	void setAnisotropyLevel(U x)
-	{
-		anisotropyLevel = x;
-	}
-
-	Bool getMipmappingEnabled() const
-	{
-		return mipmapping;
-	}
-	void setMipmappingEnabled(Bool x)
-	{
-		mipmapping = x;
-	}
-
-	Bool getCompressionEnabled() const
-	{
-		return compression;
-	}
-	void setCompressionEnabled(Bool x)
-	{
-		compression = x;
-	}
-
-	U getMaxUnitsCount() const
-	{
-		return unitsCount;
-	}
-	/// @}
-
-private:
-	/// @name Hints
-	/// Hints when creating new textures. The implementation may try to ignore 
-	/// them
-	/// @{
-	U anisotropyLevel;
-	Bool mipmapping;
-	/// If true the new textures will be compressed if not already
-	Bool compression;
-	/// @}
-
-	U unitsCount;
-};
-
-/// The global texture manager
-typedef Singleton<TextureManager> TextureManagerSingleton;
-
-/// Class for effective binding of textures
-///
-/// @note GL has some nonsense where you can bind different texture targets in 
-///       the same unit. This class doesn't support that
-class TextureUnits
-{
-public:
-	TextureUnits();
-
-	/// Alias for glActiveTexture
-	void activateUnit(U unit);
-
-	/// Bind the texture to a unit. It's not sure that it will activate the unit
-	/// @return The texture unit index
-	U bindTexture(const Texture& tex);
-
-	/// Like bindTexture but ensure that the unit is active
-	void bindTextureAndActivateUnit(const Texture& tex);
-
-	/// Unbind a texture from it's unit
-	void unbindTexture(const Texture& tex);
-
-	/// Get the number of the texture unit the @a tex is binded. Returns -1 if
-	/// not binded to any unit
-	I whichUnit(const Texture& tex);
-
-private:
-	/// Texture unit representation
-	struct Unit
-	{
-		/// Have the GL ID to save memory. 0 if no tex is binded to that unit
-		GLuint tex;
-		
-		/// Born time. The bigger the value the latter the unit has been
-		/// accessed. This practically means that if the @a born is low the
-		/// unit is a candidate for replacement
-		U64 born;
-	};
-
-	/// Texture units
-	Vector<Unit> units;
-
-	/// A map that goes from a texture name to it's bound unit. We don't keep 
-	/// the unit in the texture because it could be different for each context
-	Vector<I8> texIdToUnitId;
-
-	/// The active texture unit
-	I activeUnit;
-
-	/// How many times the @a choseUnit has been called. Used to set the 
-	/// Unit::born
-	U64 choseUnitTimes;
-
-	/// Helper method. It returns the texture unit where the @a tex can be
-	/// binded
-	U choseUnit(const Texture& tex, Bool& allreadyBinded);
-};
-
-/// The global texture units manager. Its per thread
-typedef SingletonThreadSafe<TextureUnits> TextureUnitsSingleton;
-
-/// Texture class.
-/// Generally its thread safe as long as you have a shared context and the 
-/// driver supports it
-class Texture: public NonCopyable
-{
-	friend class TextureManager;
-
-public:
-	// A fake enum: Texture filtering type
-	typedef U8 TextureFilteringType;
-	enum
-	{
-		TFT_NEAREST,
-		TFT_LINEAR,
-		TFT_TRILINEAR
-	};
-
-	/// Texture initializer struct
-	struct Initializer
-	{
-		struct Data
-		{
-			const void* ptr;
-			PtrSize size;
-		};
-
-		U width = 0;
-		U height = 0;
-		U depth = 0; ///< Relevant only for 3D and 2DArray textures
-		GLenum target = GL_TEXTURE_2D;
-		GLenum internalFormat = GL_NONE;
-		GLenum format = GL_NONE;
-		GLenum type = GL_NONE;
-		U mipmapsCount = 0;
-		TextureFilteringType filteringType = TFT_NEAREST;
-		Bool repeat = false;
-		I anisotropyLevel = 0;
-		Bool genMipmaps = false;
-		U samples = 1;
-
-		Array<Array<Data, 128>, 128> data; ///< Array of data in: [mip][layer]
-
-		Initializer()
-		{
-			memset(&data[0][0], 0, sizeof(data));
-		}
-	};
-
-	/// @name Constructors/Destructor
-	/// @{
-
-	/// Default constructor
-	Texture()
-	{}
-
-	Texture(const Initializer& init)
-	{
-		create(init);
-	}
-
-	/// Desrcuctor
-	~Texture();
-	/// @}
-
-	/// @name Accessors
-	/// Thread safe
-	/// @{
-	GLuint getGlId() const
-	{
-		ANKI_ASSERT(isCreated());
-		return glId;
-	}
-
-	GLenum getInternalFormat() const
-	{
-		ANKI_ASSERT(isCreated());
-		return internalFormat;
-	}
-
-	GLenum getFormat() const
-	{
-		ANKI_ASSERT(isCreated());
-		return format;
-	}
-
-	GLenum getTarget() const
-	{
-		ANKI_ASSERT(isCreated());
-		return target;
-	}
-
-	GLenum getType() const
-	{
-		ANKI_ASSERT(isCreated());
-		return type;
-	}
-
-	I getUnit() const
-	{
-		ANKI_ASSERT(isCreated());
-		return TextureUnitsSingleton::get().whichUnit(*this);
-	}
-
-	GLuint getWidth() const
-	{
-		ANKI_ASSERT(isCreated());
-		return width;
-	}
-
-	GLuint getHeight() const
-	{
-		ANKI_ASSERT(isCreated());
-		return height;
-	}
-
-	GLuint getDepth() const
-	{
-		ANKI_ASSERT(isCreated());
-		return depth;
-	}
-	/// @}
-
-	/// Create a texture
-	void create(const Initializer& init);
-
-	/// Create a FAI
-	void create2dFai(
-		U w, U h, GLenum internalFormat, GLenum format, GLenum type,
-		U samples = 1);
-
-	/// Bind the texture to a unit that the texture unit system will decide
-	/// @return The texture init
-	U bind() const;
-
-	/// Change the filtering type
-	void setFiltering(const TextureFilteringType filterType)
-	{
-		TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
-		setFilteringNoBind(filterType);
-	}
-	TextureFilteringType getFiltering() const
-	{
-		return filtering;
-	}
-
-	/// Set texture parameter
-	void setParameter(GLenum param, GLint value)
-	{
-		TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
-		glTexParameteri(target, param, value);
-	}
-
-	/// Read the data from the texture. Available only in GL desktop
-	void readPixels(void* data, U level = 0) const;
-
-	/// Set the range of the mipmaps
-	/// @param baseLevel The level of the base mipmap. By default is 0
-	/// @param maxLevel The level of the max mimap. Most of the time it's 1000.
-	void setMipmapsRange(U baseLevel, U maxLevel);
-
-	/// Generate mipmaps
-	void generateMipmaps();
-
-private:
-	GLuint glId = 0; ///< Identification for OGL
-	GLenum target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
-	GLenum internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
-	GLenum format = GL_NONE; ///< GL_RED, GL_RG, GL_RGB etc
-	GLenum type = GL_NONE; ///< GL_UNSIGNED_BYTE, GL_BYTE etc
-	GLuint width = 0, height = 0, depth = 0;
-	TextureFilteringType filtering;
-	U8 samples = 1;
-
-	Bool isCreated() const
-	{
-		return glId != 0;
-	}
-
-	void setFilteringNoBind(TextureFilteringType filterType);
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 164
include/anki/gl/Vao.h

@@ -1,164 +0,0 @@
-#ifndef ANKI_GL_VAO_H
-#define ANKI_GL_VAO_H
-
-#include "anki/gl/GlException.h"
-#include "anki/gl/GlObject.h"
-
-namespace anki {
-
-class ShaderProgramAttributeVariable;
-class GlBuffer;
-
-/// @addtogroup OpenGL
-/// @{
-
-/// Vertex array object. Non-copyable to avoid instantiating it in the stack
-class Vao: public GlObjectContextNonSharable
-{
-public:
-	typedef GlObjectContextNonSharable Base;
-
-	/// @name Constructors/Destructor
-	/// @{
-
-	/// Default
-	Vao()
-	{}
-
-	/// Move
-	Vao(Vao&& b)
-	{
-		*this = std::move(b);
-	}
-
-	/// Destroy VAO from the OpenGL context
-	~Vao()
-	{
-		destroy();
-	}
-	/// @}
-
-	/// @name Operators
-	/// @{
-
-	/// Move
-	Vao& operator=(Vao&& b)
-	{
-		crateNonSharable();
-		destroy();
-
-		Base::operator=(std::forward<Base>(b));
-		attachments = b.attachments;
-		b.attachments = 0;
-		return *this;
-	}
-	/// @}
-
-	/// Create
-	void create()
-	{
-		ANKI_ASSERT(!isCreated());
-		crateNonSharable();
-		glGenVertexArrays(1, &glId);
-		ANKI_CHECK_GL_ERROR();
-	}
-
-	/// Destroy
-	void destroy();
-
-	/// Attach an array buffer VBO. See @link
-	/// http://www.opengl.org/sdk/docs/man3/xhtml/glVertexAttribPointer.xml
-	/// @endlink
-	/// @param vbo The VBO to attach
-	/// @param attribVar For the shader attribute location
-	/// @param size Specifies the number of components per generic vertex
-	///        attribute. Must be 1, 2, 3, 4
-	/// @param type GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT etc
-	/// @param normalized Specifies whether fixed-point data values should
-	///        be normalized
-	/// @param stride Specifies the byte offset between consecutive generic
-	///        vertex attributes
-	/// @param offset Specifies a offset of the first component of the
-	///        first generic vertex attribute in the array
-	void attachArrayBufferVbo(
-	    const GlBuffer* vbo,
-	    const ShaderProgramAttributeVariable& attribVar,
-	    const PtrSize size,
-	    const GLenum type,
-	    const Bool normalized,
-	    const PtrSize stride,
-	    const PtrSize offset);
-
-	/// Attach an array buffer VBO. See @link
-	/// http://www.opengl.org/sdk/docs/man3/xhtml/glVertexAttribPointer.xml
-	/// @endlink
-	/// @param vbo The VBO to attach
-	/// @param attribVarLocation Shader attribute location
-	/// @param size Specifies the number of components per generic vertex
-	///        attribute. Must be 1, 2, 3, 4
-	/// @param type GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT etc
-	/// @param normalized Specifies whether fixed-point data values should
-	///        be normalized
-	/// @param stride Specifies the byte offset between consecutive generic
-	///        vertex attributes
-	/// @param pointer Specifies a offset of the first component of the
-	///        first generic vertex attribute in the array
-	void attachArrayBufferVbo(
-	    const GlBuffer* vbo,
-	    const GLint attribVarLocation,
-	    const PtrSize size,
-	    const GLenum type,
-	    const Bool normalized,
-	    const PtrSize stride,
-	    const PtrSize offset);
-
-	U32 getAttachmentsCount() const
-	{
-		ANKI_ASSERT(isCreated());
-		return attachments;
-	}
-
-	/// Attach an element array buffer VBO
-	void attachElementArrayBufferVbo(const GlBuffer* vbo);
-
-	/// Bind it
-	void bind() const
-	{
-		ANKI_ASSERT(isCreated());
-		checkNonSharable();
-		if(current != this)
-		{
-			glBindVertexArray(glId);
-			current = this;
-		}
-		ANKI_ASSERT(getCurrentVertexArrayBinding() == glId);
-	}
-
-	/// Unbind all VAOs
-	void unbind() const
-	{
-		ANKI_ASSERT(isCreated());
-		checkNonSharable();
-		if(current == this)
-		{
-			glBindVertexArray(0);
-			current = nullptr;
-		}
-	}
-
-private:
-	static const Vao* current;
-	U32 attachments = 0;
-
-	static GLuint getCurrentVertexArrayBinding()
-	{
-		GLint x;
-		glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &x);
-		return (GLuint)x;
-	}
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 13 - 13
include/anki/input/Input.h

@@ -37,23 +37,23 @@ public:
 	/// @{
 	U getKey(U32 i) const
 	{
-		return keys[i];
+		return m_keys[i];
 	}
 
 	U getMouseButton(U32 i) const
 	{
-		return mouseBtns[i];
+		return m_mouseBtns[i];
 	}
 
 	const Vec2& getMousePosition() const
 	{
-		return mousePosNdc;
+		return m_mousePosNdc;
 	}
 
 	/// Get the times an event was triggered and resets the counter
 	U getEvent(Event eventId) const
 	{
-		return events[eventId];
+		return m_events[eventId];
 	}
 	/// @}
 
@@ -77,17 +77,17 @@ public:
 	/// Lock mouse to (0, 0)
 	void lockCursor(Bool lock)
 	{
-		lockCurs = lock;
+		m_lockCurs = lock;
 	}
 
 	/// Add a new event
 	void addEvent(Event eventId)
 	{
-		++events[eventId];
+		++m_events[eventId];
 	}
 
 private:
-	NativeWindow* nativeWindow = nullptr;
+	NativeWindow* m_nativeWindow = nullptr;
 
 	/// @name Keys and btns
 	/// @{
@@ -96,19 +96,19 @@ private:
 	/// - 0 times: unpressed
 	/// - 1 times: pressed once
 	/// - >1 times: Kept pressed 'n' times continuously
-	Array<U32, KC_COUNT> keys;
+	Array<U32, KC_COUNT> m_keys;
 
 	/// Mouse btns. Supporting 3 btns & wheel. @see keys
-	Array<U32, 8> mouseBtns;
+	Array<U32, 8> m_mouseBtns;
 	/// @}
 
-	Vec2 mousePosNdc = Vec2(2.0); ///< The coords are in the NDC space
+	Vec2 m_mousePosNdc = Vec2(2.0); ///< The coords are in the NDC space
 
-	Array<U8, EVENTS_COUNT> events;
+	Array<U8, EVENTS_COUNT> m_events;
 
-	std::shared_ptr<InputImpl> impl;
+	std::shared_ptr<InputImpl> m_impl;
 
-	Bool8 lockCurs = false;
+	Bool8 m_lockCurs = false;
 };
 
 typedef Singleton<Input> InputSingleton;

+ 1 - 1
include/anki/input/InputSdl.h

@@ -10,7 +10,7 @@ namespace anki {
 /// SDL input implementation
 struct InputImpl
 {
-	std::unordered_map<SDL_Keycode, KeyCode> sdlKeyToAnki;
+	std::unordered_map<SDL_Keycode, KeyCode> m_sdlKeyToAnki;
 };
 
 } // end namespace anki

+ 45 - 45
include/anki/math/Axisang.h

@@ -5,7 +5,7 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Axis angles. Used for rotations
@@ -16,29 +16,29 @@ public:
 	/// @name Constructors
 	/// @{
 	explicit TAxisang()
-		: ang(0.0), axis(0.0)
+		: m_ang(0.0), m_axis(0.0)
 	{}
 	
 	TAxisang(const TAxisang& b)
-		: ang(b.ang), axis(b.axis)
+		: m_ang(b.ang), m_axis(b.axis)
 	{}
 
-	explicit TAxisang(const T rad, const TVec3<T>& axis_)
-		: ang(rad), axis(axis_)
+	explicit TAxisang(const T rad, const TVec3<T>& axis)
+		: m_ang(rad), m_axis(axis)
 	{}
 
 	explicit TAxisang(const TQuat<T>& q)
 	{
-		ang = 2.0 * acos<T>(q.w());
+		m_ang = 2.0 * acos<T>(q.w());
 		T length = sqrt<T>(1.0 - q.w() * q.w());
 		if(!isZero<T>(length))
 		{
 			length = 1.0 / length;
-			axis = TVec3<T>(q.x() * length, q.y() * length, q.z() * length);
+			m_axis = TVec3<T>(q.x() * length, q.y() * length, q.z() * length);
 		}
 		else
 		{
-			axis = TVec3<T>(0.0);
+			m_axis = TVec3<T>(0.0);
 		}
 	}
 
@@ -54,44 +54,44 @@ public:
 				&& (fabs<T>(m3(1, 2) + m3(2, 1)) < 0.1) 
 				&& (fabs<T>(m3(0, 0) + m3(1, 1) + m3(2, 2)) - 3) < 0.1)
 			{
-				axis = TVec3<T>(1.0, 0.0, 0.0);
-				ang = 0.0;
+				m_axis = TVec3<T>(1.0, 0.0, 0.0);
+				m_ang = 0.0;
 				return;
 			}
 
-			ang = getPi<T>();
-			axis.x() = (m3(0, 0) + 1.0) / 2.0;
-			if(axis.x() > 0.0)
+			m_ang = getPi<T>();
+			m_axis.x() = (m3(0, 0) + 1.0) / 2.0;
+			if(m_axis.x() > 0.0)
 			{
-				axis.x() = sqrt(axis.x());
+				m_axis.x() = sqrt(m_axis.x());
 			}
 			else
 			{
-				axis.x() = 0.0;
+				m_axis.x() = 0.0;
 			}
-			axis.y() = (m3(1, 1) + 1.0) / 2.0;
-			if(axis.y() > 0.0)
+			m_axis.y() = (m3(1, 1) + 1.0) / 2.0;
+			if(m_axis.y() > 0.0)
 			{
-				axis.y() = sqrt(axis.y());
+				m_axis.y() = sqrt(m_axis.y());
 			}
 			else
 			{
-				axis.y() = 0.0;
+				m_axis.y() = 0.0;
 			}
 
-			axis.z() = (m3(2, 2) + 1.0) / 2.0;
-			if(axis.z() > 0.0)
+			m_axis.z() = (m3(2, 2) + 1.0) / 2.0;
+			if(m_axis.z() > 0.0)
 			{
-				axis.z() = sqrt(axis.z());
+				m_axis.z() = sqrt(m_axis.z());
 			}
 			else
 			{
-				axis.z() = 0.0;
+				m_axis.z() = 0.0;
 			}
 
-			Bool xZero = isZero<T>(axis.x());
-			Bool yZero = isZero<T>(axis.y());
-			Bool zZero = isZero<T>(axis.z());
+			Bool xZero = isZero<T>(m_axis.x());
+			Bool yZero = isZero<T>(m_axis.y());
+			Bool zZero = isZero<T>(m_axis.z());
 			Bool xyPositive = (m3(0, 1) > 0);
 			Bool xzPositive = (m3(0, 2) > 0);
 			Bool yzPositive = (m3(1, 2) > 0);
@@ -99,21 +99,21 @@ public:
 			{
 				if(!yzPositive)
 				{
-					axis.y() = -axis.y();
+					m_axis.y() = -m_axis.y();
 				}
 			}
 			else if(yZero && !zZero)
 			{
 				if(!xzPositive)
 				{
-					axis.z() = -axis.z();
+					m_axis.z() = -m_axis.z();
 				}
 			}
 			else if(zZero)
 			{
 				if(!xyPositive)
 				{
-					axis.x() = -axis.x();
+					m_axis.x() = -m_axis.x();
 				}
 			}
 
@@ -129,10 +129,10 @@ public:
 			s = 1.0;
 		}
 
-		ang = acos<T>((m3(0, 0) + m3(1, 1) + m3(2, 2) - 1.0) / 2.0);
-		axis.x() = (m3(2, 1) - m3(1, 2)) / s;
-		axis.y() = (m3(0, 2) - m3(2, 0)) / s;
-		axis.z() = (m3(1, 0) - m3(0, 1)) / s;		
+		m_ang = acos<T>((m3(0, 0) + m3(1, 1) + m3(2, 2) - 1.0) / 2.0);
+		m_axis.x() = (m3(2, 1) - m3(1, 2)) / s;
+		m_axis.y() = (m3(0, 2) - m3(2, 0)) / s;
+		m_axis.z() = (m3(1, 0) - m3(0, 1)) / s;		
 	}
 	/// @}
 
@@ -140,32 +140,32 @@ public:
 	/// @{
 	T getAngle() const
 	{
-		return ang;
+		return m_ang;
 	}
 
 	T& getAngle()
 	{
-		return ang;
+		return m_ang;
 	}
 
 	void setAngle(const T a)
 	{
-		ang = a;
+		m_ang = a;
 	}
 
 	const TVec3<T>& getAxis() const
 	{
-		return axis;
+		return m_axis;
 	}
 
 	TVec3<T>& getAxis()
 	{
-		return axis;
+		return m_axis;
 	}
 
 	void setAxis(const TVec3<T>& a)
 	{
-		axis = a;
+		m_axis = a;
 	}
 	/// @}
 
@@ -173,8 +173,8 @@ public:
 	/// @{
 	TAxisang& operator=(const TAxisang& b)
 	{
-		ang = b.ang;
-		axis = b.axis;
+		m_ang = b.m_ang;
+		m_axis = b.m_axis;
 		return *this;
 	}
 	/// @}
@@ -183,8 +183,8 @@ public:
 	/// @{
 	std::string toString() const
 	{
-		std::string s = "axis: " + axis.toString() 
-			+ ", angle: " + std::to_string(ang);
+		std::string s = "axis: " + m_axis.toString() 
+			+ ", angle: " + std::to_string(m_ang);
 		return s;
 	}
 	/// @}
@@ -192,8 +192,8 @@ public:
 private:
 	/// @name Data
 	/// @{
-	T ang;
-	TVec3<T> axis;
+	T m_ang;
+	TVec3<T> m_axis;
 	/// @}
 };
 

+ 1 - 1
include/anki/math/CommonIncludes.h

@@ -4,4 +4,4 @@
 #include "anki/util/StdTypes.h"
 #include "anki/util/Array.h"
 #include "anki/util/Assert.h"
-#include <string>
+#include "anki/util/String.h"

+ 1 - 0
include/anki/math/CommonSrc.h

@@ -6,6 +6,7 @@
 #include "anki/math/Euler.h"
 #include "anki/math/Mat3.h"
 #include "anki/math/Mat4.h"
+#include "anki/math/Mat3x4.h"
 #include "anki/math/Transform.h"
 #include "anki/math/F16.h"
 #include "anki/math/Functions.h"

+ 12 - 12
include/anki/math/Euler.h

@@ -5,7 +5,7 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Euler angles. Used for rotations. It cannot describe a rotation
@@ -99,42 +99,42 @@ public:
 	/// @{
 	T& operator [](const U i)
 	{
-		return arr[i];
+		return m_arr[i];
 	}
 
 	T operator [](const U i) const
 	{
-		return arr[i];
+		return m_arr[i];
 	}
 
 	T& x()
 	{
-		return vec.x;
+		return m_vec.m_x;
 	}
 
 	T x() const
 	{
-		return vec.x;
+		return m_vec.m_x;
 	}
 
 	T& y()
 	{
-		return vec.y;
+		return m_vec.m_y;
 	}
 
 	T y() const
 	{
-		return vec.y;
+		return m_vec.m_y;
 	}
 
 	T& z()
 	{
-		return vec.z;
+		return m_vec.m_z;
 	}
 
 	T z() const
 	{
-		return vec.z;
+		return m_vec.m_z;
 	}
 	/// @}
 
@@ -164,13 +164,13 @@ private:
 	/// @{
 	struct Vec
 	{
-		T x, y, z;
+		T m_x, m_y, m_z;
 	};
 
 	union
 	{
-		Vec vec;
-		Array<T, 3> arr;
+		Vec m_vec;
+		Array<T, 3> m_arr;
 	};
 	/// @}
 };

+ 8 - 8
include/anki/math/F16.h

@@ -5,7 +5,7 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Half float
@@ -27,7 +27,7 @@ public:
 
 	F16(const F16& b)
 	{
-		data = b.data;
+		m_data = b.m_data;
 	}
 
 	explicit F16(const F32 f)
@@ -37,7 +37,7 @@ public:
 
 	explicit F16(const U16 ui)
 	{
-		data = ui;
+		m_data = ui;
 	}
 	/// @}
 
@@ -45,7 +45,7 @@ public:
 	/// @{
 	F16& operator=(const F16 b)
 	{
-		data = b.data;
+		m_data = b.m_data;
 		return *this;
 	}
 
@@ -95,12 +95,12 @@ public:
 
 	Bool operator==(const F16 b) const
 	{
-		return data == b.data;
+		return m_data == b.m_data;
 	}
 
 	Bool operator!=(const F16 b) const
 	{
-		return data != b.data;
+		return m_data != b.m_data;
 	}
 	/// @}
 
@@ -176,12 +176,12 @@ public:
 
 	U16 toU16() const
 	{
-		return data;
+		return m_data;
 	}
 	/// @}
 
 private:
-	U16 data;
+	U16 m_data;
 
 	static F32 toF32(F16 h);
 	static F16 toF16(F32 f);

+ 9 - 0
include/anki/math/Forward.h

@@ -1,15 +1,24 @@
 #ifndef ANKI_MATH_FORWARD_H
 #define ANKI_MATH_FORWARD_H
 
+#include "anki/util/StdTypes.h"
+
 namespace anki {
 
 class F16;
 
+template<typename T, U N, typename TSimd, typename TV> 
+class TVec;
 template<typename T> class TVec2;
 template<typename T> class TVec3;
 template<typename T> class TVec4;
+
+template<typename T, U J, U I, typename TSimd, typename TM, typename TVJ, 
+	typename TVI>
+class TMat;
 template<typename T> class TMat3;
 template<typename T> class TMat4;
+
 template<typename T> class TQuat;
 template<typename T> class TTransform;
 template<typename T> class TAxisang;

+ 48 - 5
include/anki/math/Functions.h

@@ -3,10 +3,11 @@
 
 #include "anki/util/StdTypes.h"
 #include <cmath>
+#include <cstdlib>
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 //==============================================================================
@@ -29,7 +30,11 @@ inline constexpr F64 getPi<F64>()
 }
 
 template<typename Scalar>
-constexpr Scalar getEpsilon();
+constexpr Scalar getEpsilon()
+{
+	static_assert(1, "Shouldn't instantiate");
+	return Scalar(0);
+}
 
 template<>
 constexpr F32 getEpsilon<F32>()
@@ -120,22 +125,60 @@ inline T mod(const T x, const T y)
 // Other math functions                                                        =
 //==============================================================================
 
+template<typename T>
+inline T abs(const T f)
+{ 
+	return ::fabs(f);
+}
+
+#define ANKI_SPECIALIZE_ABS_INT(type_) \
+	template<> \
+	inline type_ abs(const type_ f) \
+	{ \
+		return ::abs(f); \
+	}
+
+ANKI_SPECIALIZE_ABS_INT(I8)
+ANKI_SPECIALIZE_ABS_INT(I16)
+ANKI_SPECIALIZE_ABS_INT(I32)
+ANKI_SPECIALIZE_ABS_INT(I64)
+
+#undef ANKI_SPECIALIZE_ABS_INT
+
 template<typename T>
 inline Bool isZero(const T f)
 {
-	return fabs(f) < getEpsilon<T>();
+	return abs<T>(f) < getEpsilon<T>();
 }
 
+#define ANKI_SPECIALIZE_IS_ZERO_INT(type_) \
+	template<> \
+	inline Bool isZero(const type_ x) \
+	{ \
+		return x == type_(0); \
+	}
+
+ANKI_SPECIALIZE_IS_ZERO_INT(I8)
+ANKI_SPECIALIZE_IS_ZERO_INT(I16)
+ANKI_SPECIALIZE_IS_ZERO_INT(I32)
+ANKI_SPECIALIZE_IS_ZERO_INT(I64)
+ANKI_SPECIALIZE_IS_ZERO_INT(U8)
+ANKI_SPECIALIZE_IS_ZERO_INT(U16)
+ANKI_SPECIALIZE_IS_ZERO_INT(U32)
+ANKI_SPECIALIZE_IS_ZERO_INT(U64)
+
+#undef ANKI_SPECIALIZE_IS_ZERO_INT
+
 template<typename T>
 inline T toRad(const T degrees)
 {
-	return degrees * (getPi<T>() / T(180.0));
+	return degrees * (getPi<T>() / T(180));
 }
 
 template<typename T>
 inline T toDegrees(const T rad)
 {
-	return rad * (T(180.0) / getPi<T>());
+	return rad * (T(180) / getPi<T>());
 }
 
 //==============================================================================

+ 779 - 0
include/anki/math/Mat.h

@@ -0,0 +1,779 @@
+#ifndef ANKI_MATH_MAT_H
+#define ANKI_MATH_MAT_H
+
+#include "anki/math/CommonIncludes.h"
+#include "anki/math/Vec.h"
+
+namespace anki {
+
+/// @addtogroup math
+/// @{
+
+/// Common code for all matrices
+/// @tparam T The scalar type. Eg float.
+/// @tparam J The number of rows.
+/// @tparam I The number of columns.
+/// @tparam TM The type of the derived class. Eg TMat3.
+/// @tparam TVJ The vector type of the row.
+/// @tparam TVI The vector type of the column.
+template<typename T, U J, U I, typename TSimd, typename TM, typename TVJ, 
+	typename TVI>
+class TMat
+{
+public:
+	using Scalar = T;
+	static constexpr U ROW_SIZE = J; ///< Number of rows
+	static constexpr U COLUMN_SIZE = I; ///< Number of columns
+	static constexpr U SIZE = J * I; ///< Number of total elements
+
+	/// @name Constructors
+	/// @{
+	explicit TMat() 
+	{}
+
+	TMat(const TMat& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] = b.m_arr1[i]; 
+		}
+	}
+
+	explicit TMat(const T f)
+	{
+		for(T& x : m_arr1)
+		{
+			x = f;
+		}
+	}
+
+	explicit TMat(const T arr[])
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] = arr[i]; 
+		}
+	}
+	/// @}
+
+	/// @name Accessors
+	/// @{
+	T& operator()(const U j, const U i)
+	{
+		return m_arr2[j][i];
+	}
+
+	T operator()(const U j, const U i) const
+	{
+		return m_arr2[j][i];
+	}
+
+	T& operator[](const U n)
+	{
+		return m_arr1[n];
+	}
+
+	T operator[](const U n) const
+	{
+		return m_arr1[n];
+	}
+	/// @}
+
+	/// @name Operators with same type
+	/// @{
+	TM& operator=(const TM& b)
+	{
+		for(U n = 0; n < N; n++)
+		{
+			m_arr1[n] = b.m_arr1[n];
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator+(const TM& b) const
+	{
+		TM c;
+		for(U n = 0; n < N; n++)
+		{
+			c.m_arr1[n] = m_arr1[n] + b.m_arr1[n];
+		}
+		return c;
+	}
+
+	TM& operator+=(const TM& b)
+	{
+		for(U n = 0; n < N; n++)
+		{
+			m_arr1[n] += b.m_arr1[n];
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator-(const TM& b) const
+	{
+		TM c;
+		for(U n = 0; n < N; n++)
+		{
+			c.m_arr1[n] = m_arr1[n] - b.m_arr1[n];
+		}
+		return c;
+	}
+
+	TM& operator-=(const TM& b)
+	{
+		for(U n = 0; n < N; n++)
+		{
+			m_arr1[n] -= b.m_arr1[n];
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator*(const TM& b) const
+	{
+		static_assert(I == J, "Only for square matrices");
+		TM out;
+		const TMat& a = *this;
+		for(U j = 0; j < J; j++)
+		{
+			for(U i = 0; i < I; i++)
+			{
+				out(j, i) = T(0);
+				for(U k = 0; k < I; k++)
+				{
+					out(j, i) += a(j, k) * b(k, i);
+				}
+			}
+		}
+		return out;
+	}
+
+	TM& operator*=(const TM& b)
+	{
+		(*this) = (*this) * b;
+		return static_cast<TM&>(*this);
+	}
+
+	Bool operator==(const TM& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(!isZero<T>(m_arr1[i] - b.m_arr1[i]))
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	Bool operator!=(const TM& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(!isZero<T>(m_arr1[i] - b.m_arr1[i]))
+			{
+				return true;
+			}
+		}
+		return false;
+	}
+	/// @}
+
+	/// @name Operators with T
+	/// @{
+	TM operator+(const T f) const
+	{
+		TM out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr1[i] = m_arr1[i] + f;
+		}
+		return out;
+	}
+
+	TM& operator+=(const T f)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] += f;
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator-(const T f) const
+	{
+		TM out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr1[i] = m_arr1[i] - f;
+		}
+		return out;
+	}
+
+	TM& operator-=(const T f)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] -= f;
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator*(const T f) const
+	{
+		TM out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr1[i] = m_arr1[i] * f;
+		}
+		return out;
+	}
+
+	TM& operator*=(const T f)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] *= f;
+		}
+		return static_cast<TM&>(*this);
+	}
+
+	TM operator/(const T f) const
+	{
+		ANKI_ASSERT(f != T(0));
+		TM out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr1[i] = m_arr1[i] / f;
+		}
+		return out;
+	}
+
+	TM& operator/=(const T f)
+	{
+		ANKI_ASSERT(f != T(0));
+		for(U i = 0; i < N; i++)
+		{
+			m_arr1[i] /= f;
+		}
+		return static_cast<TM&>(*this);
+	}
+	/// @}
+
+	/// @name Operators with other types
+	/// @{
+	TVI operator*(const TVJ& v) const
+	{
+		const TMat& m = *this;
+		TVI out;
+		for(U j = 0; j < J; j++)
+		{
+			T sum = 0.0;
+			for(U i = 0; i < I; i++)
+			{
+				sum += m(j, i) * v[i];
+			}
+			out[j] = sum;
+		}
+		return out;
+	}
+	/// @}
+
+	/// @name Other
+	/// @{
+	void setRow(const U j, const TVJ& v)
+	{
+		for(U i = 0; i < I; i++)
+		{
+			m_arr2[j][i] = v[i];
+		}
+	}
+
+	void setRows(const TVJ& a, const TVJ& b, const TVJ& c)
+	{
+		setRow(0, a);
+		setRow(1, b);
+		setRow(2, c);
+	}
+
+	void setRows(const TVJ& a, const TVJ& b, const TVJ& c, const TVJ& d)
+	{
+		static_assert(J > 3, "Wrong matrix");
+		setRows(a, b, c);
+		setRow(3, d);
+	}
+
+	TVJ getRow(const U j) const
+	{
+		TVJ out;
+		for(U i = 0; i < I; i++)
+		{
+			out[i] = m_arr2[j][i];
+		}
+		return out;
+	}
+
+	void getRows(TVJ& a, TVJ& b, TVJ& c) const
+	{
+		a = getRow(0);
+		b = getRow(1);
+		c = getRow(2);
+	}
+
+	void getRows(TVJ& a, TVJ& b, TVJ& c, TVJ& d) const
+	{
+		static_assert(J > 3, "Wrong matrix");
+		getRows(a, b, c);
+		d = getRow(3);
+	}
+
+	void setColumn(const U i, const TVI& v)
+	{
+		for(U j = 0; j < J; j++)
+		{
+			m_arr2[j][i] = v[j];
+		}
+	}
+
+	void setColumns(const TVI& a, const TVI& b, const TVI& c)
+	{
+		setColumn(0, a);
+		setColumn(1, b);
+		setColumn(2, c);
+	}
+
+	void setColumns(const TVI& a, const TVI& b, const TVI& c, const TVI& d)
+	{
+		static_assert(I > 3, "Check column number");
+		setColumns(a, b, c);
+		setColumn(3, d);
+	}
+
+	TVI getColumn(const U i) const
+	{
+		TVI out;
+		for(U j = 0; j < J; j++)
+		{
+			out[j] = m_arr2[j][i];
+		}
+		return out;
+	}
+
+	void getColumns(TVI& a, TVI& b, TVI& c) const
+	{
+		a = getColumn(0);
+		b = getColumn(1);
+		c = getColumn(2);
+	}
+
+	void getColumns(TVI& a, TVI& b, TVI& c, TVI& d) const
+	{
+		static_assert(I > 3, "Check column number");
+		getColumns(a, b, c);
+		d = getColumn(3);
+	}
+
+	/// Get 1st column
+	TVI getXAxis() const
+	{
+		return getColumn(0);
+	}
+
+	/// Get 2nd column
+	TVI getYAxis() const
+	{
+		return getColumn(1);
+	}
+
+	/// Get 3rd column
+	TVI getZAxis() const
+	{
+		return getColumn(2);
+	}
+
+	/// Set 1st column
+	void setXAxis(const TVI& v)
+	{
+		setColumn(0, v);
+	}
+
+	/// Set 2nd column
+	void setYAxis(const TVI& v)
+	{
+		setColumn(1, v);
+	}
+
+	/// Set 3rd column
+	void setZAxis(const TVI& v)
+	{
+		setColumn(2, v);
+	}
+
+	void setRotationX(const T rad)
+	{
+		TMat& m = *this;
+		T sintheta, costheta;
+		sinCos(rad, sintheta, costheta);
+
+		m(0, 0) = 1.0;
+		m(0, 1) = 0.0;
+		m(0, 2) = 0.0;
+		m(1, 0) = 0.0;
+		m(1, 1) = costheta;
+		m(1, 2) = -sintheta;
+		m(2, 0) = 0.0;
+		m(2, 1) = sintheta;
+		m(2, 2) = costheta;
+	}
+
+	void setRotationY(const T rad)
+	{
+		TMat& m = *this;
+		T sintheta, costheta;
+		sinCos(rad, sintheta, costheta);
+
+		m(0, 0) = costheta;
+		m(0, 1) = 0.0;
+		m(0, 2) = sintheta;
+		m(1, 0) = 0.0;
+		m(1, 1) = 1.0;
+		m(1, 2) = 0.0;
+		m(2, 0) = -sintheta;
+		m(2, 1) = 0.0;
+		m(2, 2) = costheta;
+	}
+
+	void setRotationZ(const T rad)
+	{
+		TMat& m = *this;
+		T sintheta, costheta;
+		sinCos(rad, sintheta, costheta);
+
+		m(0, 0) = costheta;
+		m(0, 1) = -sintheta;
+		m(0, 2) = 0.0;
+		m(1, 0) = sintheta;
+		m(1, 1) = costheta;
+		m(1, 2) = 0.0;
+		m(2, 0) = 0.0;
+		m(2, 1) = 0.0;
+		m(2, 2) = 1.0;
+	}
+
+	/// It rotates "this" in the axis defined by the rotation AND not the
+	/// world axis
+	void rotateXAxis(const T rad)
+	{
+		TMat& m = *this;
+		// If we analize the mat3 we can extract the 3 unit vectors rotated by 
+		// the mat3. The 3 rotated vectors are in mat's columns. This means 
+		// that: mat3.colomn[0] == i * mat3. rotateXAxis() rotates rad angle 
+		// not from i vector (aka x axis) but from the vector from colomn 0
+		// NOTE: See the clean code from < r664
+
+		T sina, cosa;
+		sinCos(rad, sina, cosa);
+
+		// zAxis = zAxis*cosa - yAxis*sina;
+		m(0, 2) = m(0, 2) * cosa - m(0, 1) * sina;
+		m(1, 2) = m(1, 2) * cosa - m(1, 1) * sina;
+		m(2, 2) = m(2, 2) * cosa - m(2, 1) * sina;
+
+		// zAxis.normalize();
+		T len = sqrt(m(0, 2) * m(0, 2)
+			+ m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2));
+		m(0, 2) /= len;
+		m(1, 2) /= len;
+		m(2, 2) /= len;
+
+		// yAxis = zAxis * xAxis;
+		m(0, 1) = m(1, 2) * m(2, 0) - m(2, 2) * m(1, 0);
+		m(1, 1) = m(2, 2) * m(0, 0) - m(0, 2) * m(2, 0);
+		m(2, 1) = m(0, 2) * m(1, 0) - m(1, 2) * m(0, 0);
+
+		// yAxis.normalize();
+	}
+
+	/// @copybrief rotateXAxis
+	void rotateYAxis(const T rad)
+	{
+		TMat& m = *this;
+		// NOTE: See the clean code from < r664
+		T sina, cosa;
+		sinCos(rad, sina, cosa);
+
+		// zAxis = zAxis*cosa + xAxis*sina;
+		m(0, 2) = m(0, 2) * cosa + m(0, 0) * sina;
+		m(1, 2) = m(1, 2) * cosa + m(1, 0) * sina;
+		m(2, 2) = m(2, 2) * cosa + m(2, 0) * sina;
+
+		// zAxis.normalize();
+		T len = sqrt(m(0, 2) * m(0, 2)
+			+ m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2));
+		m(0, 2) /= len;
+		m(1, 2) /= len;
+		m(2, 2) /= len;
+
+		// xAxis = (zAxis*yAxis) * -1.0f;
+		m(0, 0) = m(2, 2) * m(1, 1) - m(1, 2) * m(2, 1);
+		m(1, 0) = m(0, 2) * m(2, 1) - m(2, 2) * m(0, 1);
+		m(2, 0) = m(1, 2) * m(0, 1) - m(0, 2) * m(1, 1);
+	}
+
+	/// @copybrief rotateXAxis
+	void rotateZAxis(const T rad)
+	{
+		TMat& m = *this;
+		// NOTE: See the clean code from < r664
+		T sina, cosa;
+		sinCos(rad, sina, cosa);
+
+		// xAxis = xAxis*cosa + yAxis*sina;
+		m(0, 0) = m(0, 0) * cosa + m(0, 1) * sina;
+		m(1, 0) = m(1, 0) * cosa + m(1, 1) * sina;
+		m(2, 0) = m(2, 0) * cosa + m(2, 1) * sina;
+
+		// xAxis.normalize();
+		T len = sqrt(m(0, 0) * m(0, 0)
+			+ m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0));
+		m(0, 0) /= len;
+		m(1, 0) /= len;
+		m(2, 0) /= len;
+
+		// yAxis = zAxis*xAxis;
+		m(0, 1) = m(1, 2) * m(2, 0) - m(2, 2) * m(1, 0);
+		m(1, 1) = m(2, 2) * m(0, 0) - m(0, 2) * m(2, 0);
+		m(2, 1) = m(0, 2) * m(1, 0) - m(1, 2) * m(0, 0);
+	}
+
+	void setRotationPart(const TMat3<T>& m3)
+	{
+		TMat& m = *this;
+		for(U j = 0; j < 3; j++)
+		{
+			for(U i = 0; i < 3; i++)
+			{
+				m(j, i) = m3(j, i);
+			}
+		}
+	}
+
+	void setRotationPart(const TQuat<T>& q)
+	{
+		TMat& m = *this;
+		// If length is > 1 + 0.002 or < 1 - 0.002 then not normalized quat
+		ANKI_ASSERT(fabs(1.0 - q.getLength()) <= 0.002);
+
+		T xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
+
+		xs = q.x() + q.x();
+		ys = q.y() + q.y();
+		zs = q.z() + q.z();
+		wx = q.w() * xs;
+		wy = q.w() * ys;
+		wz = q.w() * zs;
+		xx = q.x() * xs;
+		xy = q.x() * ys;
+		xz = q.x() * zs;
+		yy = q.y() * ys;
+		yz = q.y() * zs;
+		zz = q.z() * zs;
+
+		m(0, 0) = 1.0 - (yy + zz);
+		m(0, 1) = xy - wz;
+		m(0, 2) = xz + wy;
+
+		m(1, 0) = xy + wz;
+		m(1, 1) = 1.0 - (xx + zz);
+		m(1, 2) = yz - wx;
+
+		m(2, 0) = xz - wy;
+		m(2, 1) = yz + wx;
+		m(2, 2) = 1.0 - (xx + yy);
+	}
+
+	void setRotationPart(const TEuler<T>& e)
+	{
+		TMat& m = *this;
+		T ch, sh, ca, sa, cb, sb;
+		sinCos(e.y(), sh, ch);
+		sinCos(e.z(), sa, ca);
+		sinCos(e.x(), sb, cb);
+
+		m(0, 0) = ch * ca;
+		m(0, 1) = sh * sb - ch * sa * cb;
+		m(0, 2) = ch * sa * sb + sh * cb;
+		m(1, 0) = sa;
+		m(1, 1) = ca * cb;
+		m(1, 2) = -ca * sb;
+		m(2, 0) = -sh * ca;
+		m(2, 1) = sh * sa * cb + ch * sb;
+		m(2, 2) = -sh * sa * sb + ch * cb;
+	}
+
+	void setRotationPart(const TAxisang<T>& axisang)
+	{
+		TMat& m = *this;
+		// Not normalized axis
+		ANKI_ASSERT(isZero<T>(1.0 - axisang.getAxis().getLength()));
+
+		T c, s;
+		sinCos(axisang.getAngle(), s, c);
+		T t = 1.0 - c;
+
+		const TVec3<T>& axis = axisang.getAxis();
+		m(0, 0) = c + axis.x() * axis.x() * t;
+		m(1, 1) = c + axis.y() * axis.y() * t;
+		m(2, 2) = c + axis.z() * axis.z() * t;
+
+		T tmp1 = axis.x() * axis.y() * t;
+		T tmp2 = axis.z() * s;
+		m(1, 0) = tmp1 + tmp2;
+		m(0, 1) = tmp1 - tmp2;
+		tmp1 = axis.x() * axis.z() * t;
+		tmp2 = axis.y() * s;
+		m(2, 0) = tmp1 - tmp2;
+		m(0, 2) = tmp1 + tmp2;
+		tmp1 = axis.y() * axis.z() * t;
+		tmp2 = axis.x() * s;
+		m(2, 1) = tmp1 + tmp2;
+		m(1, 2) = tmp1 - tmp2;
+	}
+
+	TMat3<T> getRotationPart() const
+	{
+		const TMat& m = *this;
+		TMat3<T> m3;
+		m3(0, 0) = m(0, 0);
+		m3(0, 1) = m(0, 1);
+		m3(0, 2) = m(0, 2);
+		m3(1, 0) = m(1, 0);
+		m3(1, 1) = m(1, 1);
+		m3(1, 2) = m(1, 2);
+		m3(2, 0) = m(2, 0);
+		m3(2, 1) = m(2, 1);
+		m3(2, 2) = m(2, 2);
+		return m3;
+	}
+
+	void setTranslationPart(const TVI& v)
+	{
+		setColumn(3, v);
+	}
+
+	TVI getTranslationPart() const
+	{
+		return getColumn(3);
+	}
+
+	void reorthogonalize()
+	{
+		// There are 2 methods, the standard and the Gram-Schmidt method with a 
+		// twist for zAxis. This uses the 2nd. For the first see < r664
+		TVI xAxis, yAxis, zAxis;
+		getColumns(xAxis, yAxis, zAxis);
+
+		xAxis.normalize();
+
+		yAxis = yAxis - (xAxis * xAxis.dot(yAxis));
+		yAxis.normalize();
+
+		zAxis = xAxis.cross(yAxis);
+
+		setColumns(xAxis, yAxis, zAxis);
+	}
+
+	void transpose()
+	{
+		static_assert(I == J, "Only for square matrices");
+		for(U j = 0; j < J; j++)
+		{
+			for(U i = j + 1; i < I; i++)
+			{
+				T tmp = m_arr2[j][i];
+				m_arr2[j][i] = m_arr2[i][j];
+				m_arr2[i][j] = tmp;
+			}
+		}
+	}
+
+	void transposeRotationPart()
+	{
+		for(U j = 0; j < 3; j++)
+		{
+			for(U i = j + 1; i < 3; i++)
+			{
+				T tmp = m_arr2[j][i];
+				m_arr2[j][i] = m_arr2[i][j];
+				m_arr2[i][j] = tmp;
+			}
+		}
+	}
+
+	TM getTransposed() const
+	{
+		static_assert(I == J, "Only for square matrices");
+		TM out;
+		for(U j = 0; j < J; j++)
+		{
+			for(U i = 0; i < I; i++)
+			{
+				out.m_arr2[i][j] = m_arr2[j][i];
+			}
+		}
+		return out;
+	}
+
+	TMat lerp(const TMat& b, T t) const
+	{
+		return ((*this) * (1.0 - t)) + (b * t);
+	}
+
+	static const TM& getZero()
+	{
+		static const TM zero(0.0);
+		return zero;
+	}
+
+	void setZero()
+	{
+		*this = getZero();
+	}
+
+	String toString() const
+	{
+		const TMat& m = *this;
+		String s;
+		for(U j = 0; j < J; j++)
+		{
+			for(U i = 0; i < I; i++)
+			{
+				s += std::to_string(m(j, i)) + " ";
+			}
+			s += "\n";
+		}
+		return s;
+	}
+	/// @}
+
+protected:
+	static constexpr U N = I * J;
+
+	/// @name Data members
+	/// @{
+	union
+	{
+		Array<T, N> m_arr1;
+		Array2d<T, J, I> m_arr2;
+		T m_carr1[N]; ///< For easier debugging with gdb
+		T m_carr2[J][I]; ///< For easier debugging with gdb
+		TSimd m_simd;
+	};
+	/// @}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 28 - 598
include/anki/math/Mat3.h

@@ -2,16 +2,18 @@
 #define ANKI_MATH_MAT3_H
 
 #include "anki/math/CommonIncludes.h"
+#include "anki/math/Mat.h"
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// 3x3 Matrix. Mainly used for rotations. It includes many helpful member
 /// functions. Its row major. The columns are the x,y,z axis
+/// @note TMat3*TMat3: 27 muls 18 adds
 template<typename T>
-class TMat3
+class TMat3: public TMat<T, 3, 3, Array<T, 9>, TMat3<T>, TVec3<T>, TVec3<T>>
 {
 	/// @name Friends
 	/// @{
@@ -26,22 +28,22 @@ class TMat3
 	/// @}
 
 public:
+	using Base = TMat<T, 3, 3, Array<T, 9>, TMat3<T>, TVec3<T>, TVec3<T>>;
+
+	using Base::setRotationPart;
+
 	/// @name Constructors
 	/// @{
 	explicit TMat3() 
+		: Base()
 	{}
 
-	explicit TMat3(const T f)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] = f;
-		}
-	}
+	TMat3(const TMat3& b)
+		: Base(b)
+	{}
 
-	explicit TMat3(const T m00, const T m01, const T m02,
-		const T m10, const T m11, const T m12,
-		const T m20, const T m21, const T m22)
+	explicit TMat3(
+		T m00, T m01, T m02, T m10, T m11, T m12, T m20, T m21, T m22)
 	{
 		TMat3& m = *this;
 		m(0, 0) = m00;
@@ -55,597 +57,32 @@ public:
 		m(2, 2) = m22;
 	}
 
-	explicit TMat3(const T arr[])
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] = arr[i];
-		}
-	}
+	explicit TMat3(const T f)
+		: Base(f)
+	{}
 
-	TMat3(const TMat3& b)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] = b.arr1[i];
-		}
-	}
+	explicit TMat3(const T arr[])
+		: Base(arr)
+	{}
 
-	/// TQuat to TMat3. 12 muls, 12 adds
 	explicit TMat3(const TQuat<T>& q)
 	{
-		TMat3& m = *this;
-		// If length is > 1 + 0.002 or < 1 - 0.002 then not normalized quat
-		ANKI_ASSERT(fabs(1.0 - q.getLength()) <= 0.002);
-
-		T xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
-
-		xs = q.x() + q.x();
-		ys = q.y() + q.y();
-		zs = q.z() + q.z();
-		wx = q.w() * xs;
-		wy = q.w() * ys;
-		wz = q.w() * zs;
-		xx = q.x() * xs;
-		xy = q.x() * ys;
-		xz = q.x() * zs;
-		yy = q.y() * ys;
-		yz = q.y() * zs;
-		zz = q.z() * zs;
-
-		m(0, 0) = 1.0 - (yy + zz);
-		m(0, 1) = xy - wz;
-		m(0, 2) = xz + wy;
-
-		m(1, 0) = xy + wz;
-		m(1, 1) = 1.0 - (xx + zz);
-		m(1, 2) = yz - wx;
-
-		m(2, 0) = xz - wy;
-		m(2, 1) = yz + wx;
-		m(2, 2) = 1.0 - (xx + yy);
+		setRotationPart(q);
 	}
 
 	explicit TMat3(const TEuler<T>& e)
 	{
-		TMat3& m = *this;
-		T ch, sh, ca, sa, cb, sb;
-		sinCos(e.y(), sh, ch);
-		sinCos(e.z(), sa, ca);
-		sinCos(e.x(), sb, cb);
-
-		m(0, 0) = ch * ca;
-		m(0, 1) = sh * sb - ch * sa * cb;
-		m(0, 2) = ch * sa * sb + sh * cb;
-		m(1, 0) = sa;
-		m(1, 1) = ca * cb;
-		m(1, 2) = -ca * sb;
-		m(2, 0) = -sh * ca;
-		m(2, 1) = sh * sa * cb + ch * sb;
-		m(2, 2) = -sh * sa * sb + ch * cb;
+		setRotationPart(e);
 	}
 
 	explicit TMat3(const TAxisang<T>& axisang)
 	{
-		TMat3& m = *this;
-		// Not normalized axis
-		ANKI_ASSERT(isZero<T>(1.0 - axisang.getAxis().getLength()));
-
-		T c, s;
-		sinCos(axisang.getAngle(), s, c);
-		T t = 1.0 - c;
-
-		const TVec3<T>& axis = axisang.getAxis();
-		m(0, 0) = c + axis.x() * axis.x() * t;
-		m(1, 1) = c + axis.y() * axis.y() * t;
-		m(2, 2) = c + axis.z() * axis.z() * t;
-
-		T tmp1 = axis.x() * axis.y() * t;
-		T tmp2 = axis.z() * s;
-		m(1, 0) = tmp1 + tmp2;
-		m(0, 1) = tmp1 - tmp2;
-		tmp1 = axis.x() * axis.z() * t;
-		tmp2 = axis.y() * s;
-		m(2, 0) = tmp1 - tmp2;
-		m(0, 2) = tmp1 + tmp2;
-		tmp1 = axis.y() * axis.z() * t;
-		tmp2 = axis.x() * s;
-		m(2, 1) = tmp1 + tmp2;
-		m(1, 2) = tmp1 - tmp2;
-	}
-	/// @}
-
-	/// @name Accessors
-	/// @{
-	T& operator()(const U i, const U j)
-	{
-		return arr2[i][j];
-	}
-
-	const T& operator()(const U i, const U j) const
-	{
-		return arr2[i][j];
-	}
-
-	T& operator[](const U i)
-	{
-		return arr1[i];
-	}
-
-	const T& operator[](const U i) const
-	{
-		return arr1[i];
-	}
-	/// @}
-
-	/// @name Operators with same type
-	/// @{
-	TMat3& operator=(const TMat3& b)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] = b.arr1[i];
-		}
-		return (*this);
-	}
-
-	TMat3 operator+(const TMat3& b) const
-	{
-		TMat3<T> c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] + b.arr1[i];
-		}
-		return c;
-	}
-
-	TMat3& operator+=(const TMat3& b)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] += b.arr1[i];
-		}
-		return (*this);
-	}
-
-	TMat3 operator-(const TMat3& b) const
-	{
-		TMat3 c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] - b.arr1[i];
-		}
-		return c;
-	}
-
-	TMat3& operator-=(const TMat3& b)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] -= b.arr1[i];
-		}
-		return (*this);
-	}
-
-	/// @note 27 muls, 18 adds
-	TMat3 operator*(const TMat3& b) const
-	{
-		TMat3 c;
-		const TMat3& a = *this;
-		c(0, 0) = a(0, 0) * b(0, 0) + a(0, 1) * b(1, 0) + a(0, 2) * b(2, 0);
-		c(0, 1) = a(0, 0) * b(0, 1) + a(0, 1) * b(1, 1) + a(0, 2) * b(2, 1);
-		c(0, 2) = a(0, 0) * b(0, 2) + a(0, 1) * b(1, 2) + a(0, 2) * b(2, 2);
-		c(1, 0) = a(1, 0) * b(0, 0) + a(1, 1) * b(1, 0) + a(1, 2) * b(2, 0);
-		c(1, 1) = a(1, 0) * b(0, 1) + a(1, 1) * b(1, 1) + a(1, 2) * b(2, 1);
-		c(1, 2) = a(1, 0) * b(0, 2) + a(1, 1) * b(1, 2) + a(1, 2) * b(2, 2);
-		c(2, 0) = a(2, 0) * b(0, 0) + a(2, 1) * b(1, 0) + a(2, 2) * b(2, 0);
-		c(2, 1) = a(2, 0) * b(0, 1) + a(2, 1) * b(1, 1) + a(2, 2) * b(2, 1);
-		c(2, 2) = a(2, 0) * b(0, 2) + a(2, 1) * b(1, 2) + a(2, 2) * b(2, 2);
-		return c;
-	}
-
-	TMat3& operator*=(const TMat3& b)
-	{
-		(*this) = (*this) * b;
-		return (*this);
-	}
-
-	Bool operator==(const TMat3& b) const
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			if(!isZero<T>(arr1[i] - b.arr1[i]))
-			{
-				return false;
-			}
-		}
-		return true;
-	}
-
-	Bool operator!=(const TMat3& b) const
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			if(!isZero<T>(arr1[i] - b.arr1[i]))
-			{
-				return true;
-			}
-		}
-		return false;
-	}
-	/// @}
-
-	/// @name Operators with T
-	/// @{
-	TMat3 operator+(const T f) const
-	{
-		TMat3 c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] + f;
-		}
-		return c;
-	}
-
-	TMat3& operator+=(const T f)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] += f;
-		}
-		return (*this);
-	}
-
-	TMat3 operator-(const T f) const
-	{
-		TMat3 c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] - f;
-		}
-		return c;
-	}
-
-	TMat3& operator-=(const T f)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] -= f;
-		}
-		return (*this);
-	}
-
-	TMat3 operator*(const T f) const
-	{
-		TMat3 c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] * f;
-		}
-		return c;
-	}
-
-	TMat3& operator*=(const T f)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] *= f;
-		}
-		return (*this);
-	}
-
-	TMat3 operator/(const T f) const
-	{
-		TMat3 c;
-		for(U i = 0; i < 9; i++)
-		{
-			c.arr1[i] = arr1[i] / f;
-		}
-		return c;
-	}
-
-	TMat3& operator/=(const T f)
-	{
-		for(U i = 0; i < 9; i++)
-		{
-			arr1[i] /= f;
-		}
-		return (*this);
-	}
-	/// @}
-
-	/// @name Operators with others
-	/// @{
-
-	/// TVec3<T>(dot(row0 * b), dot(row1 * b), dot(row2 * b)). 9 muls, 6 adds
-	TVec3<T> operator*(const TVec3<T>& b) const
-	{
-		const TMat3& m = *this;
-		return TVec3<T>(
-			m(0, 0) * b.x() + m(0, 1) * b.y() + m(0, 2) * b.z(),
-			m(1, 0) * b.x() + m(1, 1) * b.y() + m(1, 2) * b.z(),
-			m(2, 0) * b.x() + m(2, 1) * b.y() + m(2, 2) * b.z());
-		
+		setRotationPart(axisang);
 	}
 	/// @}
 
 	/// @name Other
 	/// @{
-	void setRows(const TVec3<T>& a, const TVec3<T>& b, const TVec3<T>& c)
-	{
-		setRow(0, a);
-		setRow(1, b);
-		setRow(2, c);
-	}
-
-	void setRow(const U i, const TVec3<T>& v)
-	{
-		TMat3& m = *this;
-		m(i, 0) = v.x();
-		m(i, 1) = v.y();
-		m(i, 2) = v.z();
-	}
-
-	void getRows(TVec3<T>& a, TVec3<T>& b, TVec3<T>& c) const
-	{
-		a = getRow(0);
-		b = getRow(1);
-		c = getRow(2);
-	}
-
-	TVec3<T> getRow(const U i) const
-	{
-		const TMat3& m = *this;
-		return TVec3<T>(m(i, 0), m(i, 1), m(i, 2));
-	}
-
-	void setColumns(const TVec3<T>& a, const TVec3<T>& b, const TVec3<T>& c)
-	{
-		setColumn(0, a);
-		setColumn(1, b);
-		setColumn(2, c);
-	}
-
-	void setColumn(const U i, const TVec3<T>& v)
-	{
-		TMat3& m = *this;
-		m(0, i) = v.x();
-		m(1, i) = v.y();
-		m(2, i) = v.z();
-	}
-
-	void getColumns(TVec3<T>& a, TVec3<T>& b, TVec3<T>& c) const
-	{
-		a = getColumn(0);
-		b = getColumn(1);
-		c = getColumn(2);
-	}
-
-	TVec3<T> getColumn(const U i) const
-	{
-		const TMat3& m = *this;
-		return TVec3<T>(m(0, i), m(1, i), m(2, i));
-	}
-
-	/// Get 1st column
-	TVec3<T> getXAxis() const
-	{
-		return getColumn(0);
-	}
-
-	/// Get 2nd column
-	TVec3<T> getYAxis() const
-	{
-		return getColumn(1);
-	}
-
-	/// Get 3rd column
-	TVec3<T> getZAxis() const
-	{
-		return getColumn(2);
-	}
-
-	/// Set 1st column
-	void setXAxis(const TVec3<T>& v3)
-	{
-		setColumn(0, v3);
-	}
-
-	/// Set 2nd column
-	void setYAxis(const TVec3<T>& v3)
-	{
-		setColumn(1, v3);
-	}
-
-	/// Set 3rd column
-	void setZAxis(const TVec3<T>& v3)
-	{
-		setColumn(2, v3);
-	}
-
-	void setRotationX(const T rad)
-	{
-		TMat3& m = *this;
-		T sintheta, costheta;
-		sinCos(rad, sintheta, costheta);
-
-		m(0, 0) = 1.0;
-		m(0, 1) = 0.0;
-		m(0, 2) = 0.0;
-		m(1, 0) = 0.0;
-		m(1, 1) = costheta;
-		m(1, 2) = -sintheta;
-		m(2, 0) = 0.0;
-		m(2, 1) = sintheta;
-		m(2, 2) = costheta;
-	}
-
-	void setRotationY(const T rad)
-	{
-		TMat3& m = *this;
-		T sintheta, costheta;
-		sinCos(rad, sintheta, costheta);
-
-		m(0, 0) = costheta;
-		m(0, 1) = 0.0;
-		m(0, 2) = sintheta;
-		m(1, 0) = 0.0;
-		m(1, 1) = 1.0;
-		m(1, 2) = 0.0;
-		m(2, 0) = -sintheta;
-		m(2, 1) = 0.0;
-		m(2, 2) = costheta;
-	}
-
-	void setRotationZ(const T rad)
-	{
-		TMat3& m = *this;
-		T sintheta, costheta;
-		sinCos(rad, sintheta, costheta);
-
-		m(0, 0) = costheta;
-		m(0, 1) = -sintheta;
-		m(0, 2) = 0.0;
-		m(1, 0) = sintheta;
-		m(1, 1) = costheta;
-		m(1, 2) = 0.0;
-		m(2, 0) = 0.0;
-		m(2, 1) = 0.0;
-		m(2, 2) = 1.0;
-	}
-
-	/// It rotates "this" in the axis defined by the rotation AND not the
-	/// world axis
-	void rotateXAxis(const T rad)
-	{
-		TMat3& m = *this;
-		// If we analize the mat3 we can extract the 3 unit vectors rotated by 
-		// the mat3. The 3 rotated vectors are in mat's columns. This means 
-		// that: mat3.colomn[0] == i * mat3. rotateXAxis() rotates rad angle 
-		// not from i vector (aka x axis) but from the vector from colomn 0
-		// NOTE: See the clean code from < r664
-
-		T sina, cosa;
-		sinCos(rad, sina, cosa);
-
-		// zAxis = zAxis*cosa - yAxis*sina;
-		m(0, 2) = m(0, 2) * cosa - m(0, 1) * sina;
-		m(1, 2) = m(1, 2) * cosa - m(1, 1) * sina;
-		m(2, 2) = m(2, 2) * cosa - m(2, 1) * sina;
-
-		// zAxis.normalize();
-		T len = sqrt(m(0, 2) * m(0, 2)
-			+ m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2));
-		m(0, 2) /= len;
-		m(1, 2) /= len;
-		m(2, 2) /= len;
-
-		// yAxis = zAxis * xAxis;
-		m(0, 1) = m(1, 2) * m(2, 0) - m(2, 2) * m(1, 0);
-		m(1, 1) = m(2, 2) * m(0, 0) - m(0, 2) * m(2, 0);
-		m(2, 1) = m(0, 2) * m(1, 0) - m(1, 2) * m(0, 0);
-
-		// yAxis.normalize();
-	}
-
-	/// @copybrief rotateXAxis
-	void rotateYAxis(const T rad)
-	{
-		TMat3& m = *this;
-		// NOTE: See the clean code from < r664
-		T sina, cosa;
-		sinCos(rad, sina, cosa);
-
-		// zAxis = zAxis*cosa + xAxis*sina;
-		m(0, 2) = m(0, 2) * cosa + m(0, 0) * sina;
-		m(1, 2) = m(1, 2) * cosa + m(1, 0) * sina;
-		m(2, 2) = m(2, 2) * cosa + m(2, 0) * sina;
-
-		// zAxis.normalize();
-		T len = sqrt(m(0, 2) * m(0, 2)
-			+ m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2));
-		m(0, 2) /= len;
-		m(1, 2) /= len;
-		m(2, 2) /= len;
-
-		// xAxis = (zAxis*yAxis) * -1.0f;
-		m(0, 0) = m(2, 2) * m(1, 1) - m(1, 2) * m(2, 1);
-		m(1, 0) = m(0, 2) * m(2, 1) - m(2, 2) * m(0, 1);
-		m(2, 0) = m(1, 2) * m(0, 1) - m(0, 2) * m(1, 1);
-	}
-
-	/// @copybrief rotateXAxis
-	void rotateZAxis(const T rad)
-	{
-		TMat3& m = *this;
-		// NOTE: See the clean code from < r664
-		T sina, cosa;
-		sinCos(rad, sina, cosa);
-
-		// xAxis = xAxis*cosa + yAxis*sina;
-		m(0, 0) = m(0, 0) * cosa + m(0, 1) * sina;
-		m(1, 0) = m(1, 0) * cosa + m(1, 1) * sina;
-		m(2, 0) = m(2, 0) * cosa + m(2, 1) * sina;
-
-		// xAxis.normalize();
-		T len = sqrt(m(0, 0) * m(0, 0)
-			+ m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0));
-		m(0, 0) /= len;
-		m(1, 0) /= len;
-		m(2, 0) /= len;
-
-		// yAxis = zAxis*xAxis;
-		m(0, 1) = m(1, 2) * m(2, 0) - m(2, 2) * m(1, 0);
-		m(1, 1) = m(2, 2) * m(0, 0) - m(0, 2) * m(2, 0);
-		m(2, 1) = m(0, 2) * m(1, 0) - m(1, 2) * m(0, 0);
-	}
-
-	void transpose()
-	{
-		TMat3& m = *this;
-		T temp = m(0, 1);
-		m(0, 1) = m(1, 0);
-		m(1, 0) = temp;
-		temp = m(0, 2);
-		m(0, 2) = m(2, 0);
-		m(2, 0) = temp;
-		temp = m(1, 2);
-		m(1, 2) = m(2, 1);
-		m(2, 1) = temp;
-		
-	}
-
-	TMat3 getTransposed() const
-	{
-		const TMat3& m = *this;
-		TMat3 m3;
-		for(U i = 0; i < 3; i++)
-		{
-			for(U j = 0; j < 3; j++)
-			{
-				m3(i, j) = m(j, i);
-			}
-		}
-		return m3;
-	}
-
-	void reorthogonalize()
-	{
-		// There are 2 methods, the standard and the Gram-Schmidt method with a 
-		// twist for zAxis. This uses the 2nd. For the first see < r664
-		TVec3<T> xAxis, yAxis, zAxis;
-		getColumns(xAxis, yAxis, zAxis);
-
-		xAxis.normalize();
-
-		yAxis = yAxis - (xAxis * xAxis.dot(yAxis));
-		yAxis.normalize();
-
-		zAxis = xAxis.cross(yAxis);
-
-		setColumns(xAxis, yAxis, zAxis);
-	}
-
 	T getDet() const
 	{
 		const TMat3& m = *this;
@@ -710,26 +147,16 @@ public:
 		return ident;
 	}
 	/// @}
-
-private:
-	/// @name Data members
-	/// @{
-	union
-	{
-		Array<T, 9> arr1;
-		Array<Array<T, 3>, 3> arr2;
-		T carr1[9]; ///< For easier debugging with gdb
-		T carr2[3][3]; ///< For easier debugging with gdb
-	};
-	/// @}
 };
 
+/// @memberof TMat3
 template<typename T>
 TMat3<T> operator+(T f, const TMat3<T>& m3)
 {
 	return m3 + f;
 }
 
+/// @memberof TMat3
 template<typename T>
 TMat3<T> operator-(T f, const TMat3<T>& m3)
 {
@@ -741,18 +168,21 @@ TMat3<T> operator-(T f, const TMat3<T>& m3)
 	return out;
 }
 
+/// @memberof TMat3
 template<typename T>
 TMat3<T> operator*(T f, const TMat3<T>& m3)
 {
 	return m3 * f;
 }
 
+/// @memberof TMat3
 template<typename T>
 TMat3<T> operator/(T f, const TMat3<T>& m3)
 {
 	TMat3<T> out;
 	for(U i = 0; i < 9; i++)
 	{
+		ANKI_ASSERT(m3[i] != T(0));
 		out[i] = f / m3[i];
 	}
 	return out;

+ 126 - 0
include/anki/math/Mat3x4.h

@@ -0,0 +1,126 @@
+#ifndef ANKI_MATH_MAT3X4_H
+#define ANKI_MATH_MAT3X4_H
+
+#include "anki/math/CommonIncludes.h"
+#include "anki/math/Mat.h"
+
+namespace anki {
+
+/// @addtogroup math
+/// @{
+
+/// Template struct that gives the type of the TMat4 SIMD
+template<typename T>
+class TMat3x4Simd
+{
+public:
+	using Type = Array<T, 12>;
+};
+
+#if ANKI_SIMD == ANKI_SIMD_SSE
+// Specialize for F32
+template<>
+class TMat3x4Simd<F32>
+{
+public:
+	using Type = Array<__m128, 3>;
+};
+#endif
+
+/// 3x4 Matrix. Mainly used for rotations. It includes many helpful member
+/// functions. Its row major. The columns are the x,y,z axis
+template<typename T>
+class alignas(16) TMat3x4: public TMat<T, 3, 4, typename TMat3x4Simd<T>::Type, 
+	  TMat3x4<T>, TVec4<T>, TVec3<T>>
+{
+public:
+	using Base = TMat<T, 3, 4, typename TMat3x4Simd<T>::Type, 
+	  TMat3x4<T>, TVec4<T>, TVec3<T>>;
+
+	using Base::Base;
+
+	/// @name Constructors
+	/// @{
+	explicit TMat3x4(const TMat3<T>& m3)
+	{
+		TMat3x4& m = *this;
+		m(0, 0) = m3(0, 0);
+		m(0, 1) = m3(0, 1);
+		m(0, 2) = m3(0, 2);
+		m(0, 3) = 0.0;
+		m(1, 0) = m3(1, 0);
+		m(1, 1) = m3(1, 1);
+		m(1, 2) = m3(1, 2);
+		m(1, 3) = 0.0;
+		m(2, 0) = m3(2, 0);
+		m(2, 1) = m3(2, 1);
+		m(2, 2) = m3(2, 2);
+		m(2, 3) = 0.0;
+	}
+
+	explicit TMat3x4(const TVec3<T>& v)
+	{
+		TMat3x4& m = *this;
+		m(0, 0) = 1.0;
+		m(0, 1) = 0.0;
+		m(0, 2) = 0.0;
+		m(0, 3) = v.x();
+		m(1, 0) = 0.0;
+		m(1, 1) = 1.0;
+		m(1, 2) = 0.0;
+		m(1, 3) = v.y();
+		m(2, 0) = 0.0;
+		m(2, 1) = 0.0;
+		m(2, 2) = 1.0;
+		m(2, 3) = v.z();
+	}
+
+	explicit TMat3x4(const TVec3<T>& transl, const TMat3<T>& rot)
+	{
+		setRotationPart(rot);
+		setTranslationPart(transl);
+	}
+
+	explicit TMat3x4(const TVec3<T>& transl, const TMat3<T>& rot, const T scale)
+	{
+		if(isZero<T>(scale - 1.0))
+		{
+			setRotationPart(rot);
+		}
+		else
+		{
+			setRotationPart(rot * scale);
+		}
+
+		setTranslationPart(transl);
+	}
+
+	explicit TMat3x4(const TTransform<T>& t)
+	{
+		(*this) = TMat3x4(t.getOrigin(), t.getRotation(), t.getScale());
+	}
+	/// @}
+
+	/// @name Other
+	/// @{
+	void setIdentity()
+	{
+		(*this) = getIdentity();
+	}
+
+	static const TMat3x4& getIdentity()
+	{
+		static const TMat3x4 ident(
+			1.0, 0.0, 0.0, 0.0, 
+			0.0, 1.0, 0.0, 0.0, 
+			0.0, 0.0, 1.0, 0.0);
+		return ident;
+	}
+	/// @}	
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 47 - 494
include/anki/math/Mat4.h

@@ -5,29 +5,33 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Template struct that gives the type of the TVec4 SIMD
 template<typename T>
-struct TMat4Simd
+class TMat4Simd
 {
-	typedef Array<T, 16> Type;
+public:
+	using Type = Array<T, 16>;
 };
 
 #if ANKI_SIMD == ANKI_SIMD_SSE
 // Specialize for F32
 template<>
-struct TMat4Simd<F32>
+class TMat4Simd<F32>
 {
-	typedef Array<__m128, 4> Type;
+public:
+	using Type = Array<__m128, 4>;
 };
 #endif
 
 /// 4x4 Matrix. Used mainly for transformations but not necessarily. Its
 /// row major. SSE optimized
+/// @note TMat4*TMat4: 64 muls 48 adds
 template<typename T>
-ANKI_ATTRIBUTE_ALIGNED(class, 16) TMat4
+class alignas(16) TMat4: public TMat<T, 4, 4, typename TMat4Simd<T>::Type, 
+	  TMat4<T>, TVec4<T>, TVec4<T>>
 {
 	/// @name Friends
 	/// @{
@@ -42,27 +46,26 @@ ANKI_ATTRIBUTE_ALIGNED(class, 16) TMat4
 	/// @}
 
 public:
-	typedef typename TMat4Simd<T>::Type Simd;
+	using Base = TMat<T, 4, 4, typename TMat4Simd<T>::Type, 
+	  TMat4<T>, TVec4<T>, TVec4<T>>;
+
+	using Base::getTranslationPart;
+	using Base::setTranslationPart;
+	using Base::getRotationPart;
+	using Base::setRotationPart;
 
 	/// @name Constructors
 	/// @{
 	explicit TMat4()
+		: Base()
 	{}
 
-	explicit TMat4(const T f)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] = f;
-		}
-	}
+	TMat4(const TMat4& b)
+		: Base(b)
+	{}
 
-	explicit TMat4(const T m00, const T m01, const T m02,
-		const T m03, const T m10, const T m11,
-		const T m12, const T m13, const T m20,
-		const T m21, const T m22, const T m23,
-		const T m30, const T m31, const T m32,
-		const T m33)
+	explicit TMat4(T m00, T m01, T m02, T m03, T m10, T m11, T m12, T m13, 
+		T m20, T m21, T m22, T m23, T m30, T m31, T m32, T m33)
 	{
 		TMat4& m = *this;
 		m(0, 0) = m00;
@@ -83,21 +86,9 @@ public:
 		m(3, 3) = m33;
 	}
 
-	explicit TMat4(const T arr[])
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] = arr[i];
-		}	
-	}
-
-	TMat4(const TMat4& b)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] = b.arr1[i];
-		}
-	}
+	explicit TMat4(const T f)
+		: Base(f)
+	{}
 
 	explicit TMat4(const TMat3<T>& m3)
 	{
@@ -165,10 +156,9 @@ public:
 	explicit TMat4(const TVec3<T>& transl, const TMat3<T>& rot)
 	{
 		setRotationPart(rot);
-		setTranslationPart(transl);
+		setTranslationPart(TVec4<T>(transl, 1.0));
 		TMat4& m = *this;
 		m(3, 0) = m(3, 1) = m(3, 2) = 0.0;
-		m(3, 3) = 1.0;
 	}
 
 	explicit TMat4(const TVec3<T>& transl, const TMat3<T>& rot, const T scale)
@@ -182,11 +172,10 @@ public:
 			setRotationPart(rot * scale);
 		}
 
-		setTranslationPart(transl);
+		setTranslationPart(TVec4<T>(transl, 1.0));
 
 		TMat4& m = *this;
 		m(3, 0) = m(3, 1) = m(3, 2) = 0.0;
-		m(3, 3) = 1.0;
 	}
 
 	explicit TMat4(const TTransform<T>& t)
@@ -195,382 +184,8 @@ public:
 	}
 	/// @}
 
-	/// @name Accessors
-	/// @{
-	T& operator()(const U i, const U j)
-	{
-		return arr2[i][j];
-	}
-
-	const T& operator()(const U i, const U j) const
-	{
-		return arr2[i][j];
-	}
-
-	T& operator[](const U i)
-	{
-		return arr1[i];
-	}
-
-	const T& operator[](const U i) const
-	{
-		return arr1[i];
-	}
-	/// @}
-
-	/// @name Operators with same type
-	/// @{
-	TMat4& operator=(const TMat4& b)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] = b.arr1[i];
-		}
-		return *this;
-	}
-
-	TMat4 operator+(const TMat4& b) const
-	{
-		TMat4<T> c;
-		for(U i = 0; i < 16; i++)
-		{
-			c.arr1[i] = arr1[i] + b.arr1[i];
-		}
-		return c;
-	}
-
-	TMat4& operator+=(const TMat4& b)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] += b.arr1[i];
-		}
-		return (*this);
-	}
-
-	TMat4 operator-(const TMat4& b) const
-	{
-		TMat4<T> c;
-		for(U i = 0; i < 16; i++)
-		{
-			c.arr1[i] = arr1[i] - b.arr1[i];
-		}
-		return c;
-	}
-
-	TMat4& operator-=(const TMat4& b)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] -= b.arr1[i];
-		}
-		return (*this);
-	}
-
-	/// @note 64 muls, 48 adds
-	TMat4 operator*(const TMat4& b) const
-	{
-		TMat4<T> c;
-		const TMat4& m = *this;
-		for(U i = 0; i < 4; i++)
-		{
-			for(U j = 0; j < 4; j++)
-			{
-				c(i, j) = m(i, 0) * b(0, j) + m(i, 1) * b(1, j) 
-					+ m(i, 2) * b(2, j) + m(i, 3) * b(3, j);
-			}
-		}
-		return c;
-	}
-
-	TMat4& operator*=(const TMat4& b)
-	{
-		(*this) = (*this) * b;
-		return (*this);
-	}
-
-	Bool operator==(const TMat4& b) const
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			if(!isZero<T>(arr1[i] - b.arr1[i]))
-			{
-				return false;
-			}
-		}
-		return true;
-	}
-
-	Bool operator!=(const TMat4& b) const
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			if(!isZero(arr1[i] - b.arr1[i]))
-			{
-				return true;
-			}
-		}
-		return false;
-	}
-	/// @}
-
-	/// @name Operators with T
-	/// @{
-	TMat4 operator+(const T f) const
-	{
-		TMat4 c;
-		for(U i = 0; i < 16; i++)
-		{
-			c.arr1[i] = arr1[i] + f;
-		}
-		return c;
-	}
-
-	TMat4& operator+=(const T f)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] += f;
-		}
-	}
-
-	TMat4 operator-(const T f) const
-	{
-		TMat4 c;
-		for(U i = 0; i < 16; i++)
-		{
-			c.arr1[i] = arr1[i] - f;
-		}
-		return c;
-	}
-
-	TMat4& operator-=(const T f)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] -= f;
-		}
-	}
-
-	TMat4 operator*(const T f) const
-	{
-		TMat4 c;
-		for(U i = 0; i < 16; i++)
-		{
-			c.arr1[i] = arr1[i] * f;
-		}
-		return c;
-	}
-
-	TMat4& operator*=(const T f)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] *= f;
-		}
-		return *this;
-	}
-
-	TMat4 operator/(const T f) const
-	{
-		TMat4 c;
-		for(U i = 0; i < 16; i++)
-		{
-			c[i] = arr1[i] / f;
-		}
-		return c;
-	}
-
-	TMat4& operator/=(const T f)
-	{
-		for(U i = 0; i < 16; i++)
-		{
-			arr1[i] /= f;
-		}
-	}
-	/// @}
-
-	/// @name Operators with other types
-	/// @{
-
-	/// 16 muls, 12 adds
-	TVec4<T> operator*(const TVec4<T>& v4) const
-	{
-		TVec4<T> out;
-		const TMat4& m = *this;
-
-		out.x() = m(0, 0) * v4.x() + m(0, 1) * v4.y() 
-			+ m(0, 2) * v4.z() + m(0, 3) * v4.w();
-
-		out.y() = m(1, 0) * v4.x() + m(1, 1) * v4.y() 
-			+ m(1, 2) * v4.z() + m(1, 3) * v4.w();
-
-		out.z() = m(2, 0) * v4.x() + m(2, 1) * v4.y() 
-			+ m(2, 2) * v4.z() + m(2, 3) * v4.w();
-
-		out.w() = m(3, 0) * v4.x() + m(3, 1) * v4.y() 
-			+ m(3, 2) * v4.z() + m(3, 3) * v4.w();
-
-		return out;
-	}
-	/// @}
-
 	/// @name Other
 	/// @{
-	void setRow(const U i, const TVec4<T>& v)
-	{
-		TMat4& m = *this;
-		m(i, 0) = v.x();
-		m(i, 1) = v.y();
-		m(i, 2) = v.z();
-		m(i, 3) = v.w();
-	}
-
-	void setRows(const TVec4<T>& a, const TVec4<T>& b, const TVec4<T>& c,
-		const TVec4<T>& d)
-	{
-		setRow(0, a);
-		setRow(1, b);
-		setRow(2, c);
-		setRow(3, d);
-	}
-
-	TVec4<T> getRow(const U i) const
-	{
-		const TMat4& m = *this;
-		return TVec4<T>(m(i, 0), m(i, 1), m(i, 2), m(i, 3));
-	}
-
-	void getRows(TVec4<T>& a, TVec4<T>& b, TVec4<T>& c, TVec4<T>& d) const
-	{
-		a = getRow(0);
-		b = getRow(1);
-		c = getRow(2);
-		d = getRow(3);
-	}
-
-	void setColumn(const U i, const TVec4<T>& v)
-	{
-		TMat4& m = *this;
-		m(0, i) = v.x();
-		m(1, i) = v.y();
-		m(2, i) = v.z();
-		m(3, i) = v.w();
-	}
-
-	void setColumns(const TVec4<T>& a, const TVec4<T>& b, const TVec4<T>& c,
-		const TVec4<T>& d)
-	{
-		setColumn(0, a);
-		setColumn(1, b);
-		setColumn(2, c);
-		setColumn(3, d);
-	}
-
-	TVec4<T> getColumn(const U i) const
-	{
-		const TMat4& m = *this;
-		return TVec4<T>(m(0, i), m(1, i), m(2, i), m(3, i));
-	}
-
-	void getColumns(TVec4<T>& a, TVec4<T>& b, TVec4<T>& c, TVec4<T>& d) const
-	{
-		a = getColumn(0);
-		b = getColumn(1);
-		c = getColumn(2);
-		d = getColumn(3);
-	}
-
-	void setRotationPart(const TMat3<T>& m3)
-	{
-		TMat4& m = *this;
-		m(0, 0) = m3(0, 0);
-		m(0, 1) = m3(0, 1);
-		m(0, 2) = m3(0, 2);
-		m(1, 0) = m3(1, 0);
-		m(1, 1) = m3(1, 1);
-		m(1, 2) = m3(1, 2);
-		m(2, 0) = m3(2, 0);
-		m(2, 1) = m3(2, 1);
-		m(2, 2) = m3(2, 2);
-	}
-
-	TMat3<T> getRotationPart() const
-	{
-		const TMat4& m = *this;
-		TMat3<T> m3;
-		m3(0, 0) = m(0, 0);
-		m3(0, 1) = m(0, 1);
-		m3(0, 2) = m(0, 2);
-		m3(1, 0) = m(1, 0);
-		m3(1, 1) = m(1, 1);
-		m3(1, 2) = m(1, 2);
-		m3(2, 0) = m(2, 0);
-		m3(2, 1) = m(2, 1);
-		m3(2, 2) = m(2, 2);
-		return m3;
-	}
-
-	void setTranslationPart(const TVec4<T>& v)
-	{
-		TMat4& m = *this;
-		m(0, 3) = v.x();
-		m(1, 3) = v.y();
-		m(2, 3) = v.z();
-		m(3, 3) = v.w();
-	}
-
-	void setTranslationPart(const TVec3<T>& v)
-	{
-		TMat4& m = *this;
-		m(0, 3) = v.x();
-		m(1, 3) = v.y();
-		m(2, 3) = v.z();
-	}
-
-	TVec3<T> getTranslationPart() const
-	{
-		const TMat4& m = *this;
-		return TVec3<T>(m(0, 3), m(1, 3), m(2, 3));
-	}
-
-	void transpose()
-	{
-		TMat4& m = *this;
-		T tmp = m(0, 1);
-		m(0, 1) = m(1, 0);
-		m(1, 0) = tmp;
-		tmp = m(0, 2);
-		m(0, 2) = m(2, 0);
-		m(2, 0) = tmp;
-		tmp = m(0, 3);
-		m(0, 3) = m(3, 0);
-		m(3, 0) = tmp;
-		tmp = m(1, 2);
-		m(1, 2) = m(2, 1);
-		m(2, 1) = tmp;
-		tmp = m(1, 3);
-		m(1, 3) = m(3, 1);
-		m(3, 1) = tmp;
-		tmp = m(2, 3);
-		m(2, 3) = m(3, 2);
-		m(3, 2) = tmp;
-	}
-
-	TMat4 getTransposed() const
-	{
-		const TMat4& m = *this;
-		TMat4 out;
-		for(U i = 0; i < 4; i++)
-		{
-			for(U j = 0; j < 4; j++)
-			{
-				out(i, j) = m(j, i);
-			}
-		}
-		return out;
-	}
-
 	T getDet() const
 	{
 		const TMat4& t = *this;
@@ -692,11 +307,6 @@ public:
 		return TMat4(invertedTsl, invertedRot);
 	}
 
-	TMat4 lerp(const TMat4& b, T t) const
-	{
-		return ((*this) * (1.0 - t)) + (b * t);
-	}
-
 	void setIdentity()
 	{
 		(*this) = getIdentity();
@@ -704,17 +314,14 @@ public:
 
 	static const TMat4& getIdentity()
 	{
-		static const TMat4 ident(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 
-			0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
+		static const TMat4 ident(
+			1.0, 0.0, 0.0, 0.0, 
+			0.0, 1.0, 0.0, 0.0, 
+			0.0, 0.0, 1.0, 0.0, 
+			0.0, 0.0, 0.0, 1.0);
 		return ident;
 	}
 
-	static const TMat4& getZero()
-	{
-		static const TMat4 zero(0.0);
-		return zero;
-	}
-
 	/// 12 muls, 27 adds. Something like m4 = m0 * m1 but without touching
 	/// the 4rth row and allot faster
 	static TMat4 combineTransformations(const TMat4& m0, const TMat4& m1)
@@ -760,34 +367,6 @@ public:
 
 		return m4;
 	}
-
-	std::string toString() const
-	{
-		const TMat4& m = *this;
-		std::string s;
-		for(U i = 0; i < 4; i++)
-		{
-			for(U j = 0; j < 4; j++)
-			{
-				s += std::to_string(m(i, j)) + " ";
-			}
-			s += "\n";
-		}
-		return s;
-	}
-	/// @}
-
-private:
-	/// @name Data
-	/// @{
-	union
-	{
-		Array<T, 16> arr1;
-		Array<Array<T, 4>, 4> arr2;
-		T carr1[16]; ///< For easier debugging with gdb
-		T carr2[4][4]; ///< For easier debugging with gdb
-		Simd simd;
-	};
 	/// @}
 };
 
@@ -796,71 +375,45 @@ private:
 // Forward declare specializations
 
 template<>
-TMat4<F32>::TMat4(const TMat4<F32>& b);
-
-template<>
-TMat4<F32>::TMat4(const F32 f);
-
-template<>
-TMat4<F32>& TMat4<F32>::operator=(const TMat4<F32>& b);
+TMat4<F32>::Base::TMat(const TMat4<F32>::Base& b);
 
 template<>
-TMat4<F32> TMat4<F32>::operator+(const TMat4<F32>& b) const;
+TMat4<F32>::Base::TMat(const F32 f);
 
 template<>
-TMat4<F32>& TMat4<F32>::operator+=(const TMat4<F32>& b);
+TMat4<F32>& TMat4<F32>::Base::operator=(const TMat4<F32>& b);
 
 template<>
-TMat4<F32> TMat4<F32>::operator-(const TMat4<F32>& b) const;
+TMat4<F32> TMat4<F32>::Base::operator+(const TMat4<F32>& b) const;
 
 template<>
-TMat4<F32>& TMat4<F32>::operator-=(const TMat4<F32>& b);
+TMat4<F32>& TMat4<F32>::Base::operator+=(const TMat4<F32>& b);
 
 template<>
-TMat4<F32> TMat4<F32>::operator*(const TMat4<F32>& b) const;
+TMat4<F32> TMat4<F32>::Base::operator-(const TMat4<F32>& b) const;
 
 template<>
-TMat4<F32> TMat4<F32>::operator+(const F32 f) const;
+TMat4<F32>& TMat4<F32>::Base::operator-=(const TMat4<F32>& b);
 
 template<>
-TMat4<F32>& TMat4<F32>::operator+=(const F32 f);
+TMat4<F32> TMat4<F32>::Base::operator*(const TMat4<F32>& b) const;
 
 template<>
-TMat4<F32> TMat4<F32>::operator-(const F32 f) const;
+TVec4<F32> TMat4<F32>::Base::operator*(const TVec4<F32>& b) const;
 
 template<>
-TMat4<F32>& TMat4<F32>::operator-=(const F32 f);
-
-template<>
-TMat4<F32> TMat4<F32>::operator*(const F32 f) const;
-
-template<>
-TMat4<F32>& TMat4<F32>::operator*=(const F32 f);
-
-template<>
-TMat4<F32> TMat4<F32>::operator/(const F32 f) const;
-
-template<>
-TMat4<F32>& TMat4<F32>::operator/=(const F32 f);
-
-template<>
-TVec4<F32> TMat4<F32>::operator*(const TVec4<F32>& b) const;
-
-template<>
-void TMat4<F32>::setRows(const TVec4<F32>& a, const TVec4<F32>& b, 
+void TMat4<F32>::Base::setRows(const TVec4<F32>& a, const TVec4<F32>& b, 
 	const TVec4<F32>& c, const TVec4<F32>& d);
 
 template<>
-void TMat4<F32>::setRow(const U i, const TVec4<F32>& v);
+void TMat4<F32>::Base::setRow(const U i, const TVec4<F32>& v);
 
 template<>
-void TMat4<F32>::transpose();
+void TMat4<F32>::Base::transpose();
 
-template<>
-TMat4<F32> operator-(const F32 f, const TMat4<F32>& m4);
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 
-template<>
-TMat4<F32> operator/(const F32 f, const TMat4<F32>& m4);
+#	error "TODO"
 
 #endif
 

+ 41 - 187
include/anki/math/Mat4.inl.h

@@ -7,6 +7,7 @@ namespace anki {
 //==============================================================================
 
 //==============================================================================
+/// @memberof TMat4
 template<typename T>
 TMat4<T> operator+(const T f, const TMat4<T>& m4)
 {
@@ -14,6 +15,7 @@ TMat4<T> operator+(const T f, const TMat4<T>& m4)
 }
 
 //==============================================================================
+/// @memberof TMat4
 template<typename T>
 TMat4<T> operator-(const T f, const TMat4<T>& m4)
 {
@@ -26,6 +28,7 @@ TMat4<T> operator-(const T f, const TMat4<T>& m4)
 }
 
 //==============================================================================
+/// @memberof TMat4
 template<typename T>
 TMat4<T> operator*(const T f, const TMat4<T>& m4)
 {
@@ -33,6 +36,7 @@ TMat4<T> operator*(const T f, const TMat4<T>& m4)
 }
 
 //==============================================================================
+/// @memberof TMat4
 template<typename T>
 TMat4<T> operator/(const T f, const TMat4<T>& m4)
 {
@@ -56,21 +60,21 @@ TMat4<T> operator/(const T f, const TMat4<T>& m4)
 
 //==============================================================================
 template<>
-inline TMat4<F32>::TMat4(const TMat4<F32>& b)
+inline TMat4<F32>::Base::TMat(const TMat4<F32>::Base& b)
 {
 	for(U i = 0; i < 4; i++)
 	{
-		simd[i] = b.simd[i];
+		m_simd[i] = b.m_simd[i];
 	}
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32>::TMat4(const F32 f)
+inline TMat4<F32>::Base::TMat(const F32 f)
 {
 	for(U i = 0; i < 4; i++)
 	{
-		simd[i] = _mm_set1_ps(f);
+		m_simd[i] = _mm_set1_ps(f);
 	}
 }
 
@@ -80,218 +84,98 @@ inline TMat4<F32>::TMat4(const F32 f)
 
 //==============================================================================
 template<>
-inline TMat4<F32>& TMat4<F32>::operator=(const TMat4<F32>& b)
+inline TMat4<F32>& TMat4<F32>::Base::operator=(const TMat4<F32>& b)
 {
 	for(U i = 0; i < 4; i++)
 	{
-		simd[i] = b.simd[i];
+		m_simd[i] = b.m_simd[i];
 	}
-	return *this;
+	return static_cast<TMat4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32> TMat4<F32>::operator+(const TMat4<F32>& b) const
+inline TMat4<F32> TMat4<F32>::Base::operator+(const TMat4<F32>& b) const
 {
 	TMat4<F32> c;
 	for(U i = 0; i < 4; i++)
 	{
-		c.simd[i] = _mm_add_ps(simd[i], b.simd[i]);
+		c.m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
 	}
 	return c;
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32>& TMat4<F32>::operator+=(const TMat4<F32>& b)
+inline TMat4<F32>& TMat4<F32>::Base::operator+=(const TMat4<F32>& b)
 {
 	for(U i = 0; i < 4; i++)
 	{
-		simd[i] = _mm_add_ps(simd[i], b.simd[i]);
+		m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
 	}
-	return *this;
+	return static_cast<TMat4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32> TMat4<F32>::operator-(const TMat4<F32>& b) const
+inline TMat4<F32> TMat4<F32>::Base::operator-(const TMat4<F32>& b) const
 {
 	TMat4<F32> c;
 	for(U i = 0; i < 4; i++)
 	{
-		c.simd[i] = _mm_sub_ps(simd[i], b.simd[i]);
+		c.m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
 	}
 	return c;
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32>& TMat4<F32>::operator-=(const TMat4<F32>& b)
+inline TMat4<F32>& TMat4<F32>::Base::operator-=(const TMat4<F32>& b)
 {
 	for(U i = 0; i < 4; i++)
 	{
-		simd[i] = _mm_sub_ps(simd[i], b.simd[i]);
+		m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
 	}
-	return *this;
+	return static_cast<TMat4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TMat4<F32> TMat4<F32>::operator*(const TMat4<F32>& b) const
+inline TMat4<F32> TMat4<F32>::Base::operator*(const TMat4<F32>& b) const
 {
 	TMat4<F32> out;
-	const TMat4<F32>& m = *this;
+	const TMat4<F32>& m = *static_cast<const TMat4<F32>*>(this);
 	for(U i = 0; i < 4; i++)
 	{
 		__m128 t1, t2;
 
 		t1 = _mm_set1_ps(m(i, 0));
-		t2 = _mm_mul_ps(b.simd[0], t1);
+		t2 = _mm_mul_ps(b.m_simd[0], t1);
 		t1 =_mm_set1_ps(m(i, 1));
-		t2 = _mm_add_ps(_mm_mul_ps(b.simd[1], t1), t2);
+		t2 = _mm_add_ps(_mm_mul_ps(b.m_simd[1], t1), t2);
 		t1 =_mm_set1_ps(m(i, 2));
-		t2 = _mm_add_ps(_mm_mul_ps(b.simd[2], t1), t2);
+		t2 = _mm_add_ps(_mm_mul_ps(b.m_simd[2], t1), t2);
 		t1 =_mm_set1_ps(m(i, 3));
-		t2 = _mm_add_ps(_mm_mul_ps(b.simd[3], t1), t2);
+		t2 = _mm_add_ps(_mm_mul_ps(b.m_simd[3], t1), t2);
 
-		out.simd[i] = t2;
+		out.m_simd[i] = t2;
 	}
 	return out;
 }
 
-//==============================================================================
-// Operators with F32                                                          =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline TMat4<F32> TMat4<F32>::operator+(const F32 f) const
-{
-	TMat4<F32> c;
-	__m128 mm = _mm_set1_ps(f);
-	
-	for(U i = 0; i < 4; i++)
-	{
-		c.simd[i] = _mm_add_ps(simd[i], mm);
-	}
-
-	return c;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32>& TMat4<F32>::operator+=(const F32 f)
-{
-	__m128 mm = _mm_set1_ps(f);
-	
-	for(U i = 0; i < 4; i++)
-	{
-		simd[i] = _mm_add_ps(simd[i], mm);
-	}
-
-	return *this;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32> TMat4<F32>::operator-(const F32 f) const
-{
-	TMat4<F32> r;
-	__m128 mm = _mm_set1_ps(f);
-	
-	for(U i = 0; i < 4; i++)
-	{
-		r.simd[i] = _mm_sub_ps(simd[i], mm);
-	}
-
-	return r;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32>& TMat4<F32>::operator-=(const F32 f)
-{
-	__m128 mm = _mm_set1_ps(f);
-	
-	for(U i = 0; i < 4; i++)
-	{
-		simd[i] = _mm_sub_ps(simd[i], mm);
-	}
-
-	return (*this);
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32> TMat4<F32>::operator*(const F32 f) const
-{
-	TMat4<F32> r;
-	__m128 mm = _mm_set1_ps(f);
-	
-	for(U i = 0; i < 4; i++)
-	{
-		r.simd[i] = _mm_mul_ps(simd[i], mm);
-	}
-
-	return r;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32>& TMat4<F32>::operator*=(const F32 f)
-{
-	__m128 mm = _mm_set1_ps(f);
-
-	for(U i = 0; i < 4; i++)
-	{
-		simd[i] = _mm_mul_ps(simd[i], mm);
-	}
-
-	return *this;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32> TMat4<F32>::operator/(const F32 f) const
-{
-	TMat4<F32> r;
-	__m128 mm = _mm_set1_ps(f);
-
-	for(U i = 0; i < 4; i++)
-	{
-		r.simd[i] = _mm_div_ps(simd[i], mm);
-	}
-
-	return r;
-}
-
-//==============================================================================
-template<>
-inline TMat4<F32>& TMat4<F32>::operator/=(const F32 f)
-{
-	__m128 mm = _mm_set1_ps(f);
-
-	for(U i = 0; i < 4; i++)
-	{
-		simd[i] = _mm_div_ps(simd[i], mm);
-	}
-
-	return *this;
-}
-
 //==============================================================================
 // Operators with other                                                        =
 //==============================================================================
 
 //==============================================================================
 template<>
-inline TVec4<F32> TMat4<F32>::operator*(const TVec4<F32>& b) const
+inline TVec4<F32> TMat4<F32>::Base::operator*(const TVec4<F32>& b) const
 {
 	TVec4<F32> v;
 	
 	for(U i = 0; i < 4; i++)
 	{
-		_mm_store_ss(&v[i], _mm_dp_ps(simd[i], b.getSimd(), 0xF1));
+		_mm_store_ss(&v[i], _mm_dp_ps(m_simd[i], b.getSimd(), 0xF1));
 	}
 
 	return v;
@@ -303,62 +187,32 @@ inline TVec4<F32> TMat4<F32>::operator*(const TVec4<F32>& b) const
 
 //==============================================================================
 template<>
-inline void TMat4<F32>::setRows(const TVec4<F32>& a, const TVec4<F32>& b, 
+inline void TMat4<F32>::Base::setRows(const TVec4<F32>& a, const TVec4<F32>& b, 
 	const TVec4<F32>& c, const TVec4<F32>& d)
 {
-	simd[0] = a.getSimd();
-	simd[1] = b.getSimd();
-	simd[2] = c.getSimd();
-	simd[3] = d.getSimd();
+	m_simd[0] = a.getSimd();
+	m_simd[1] = b.getSimd();
+	m_simd[2] = c.getSimd();
+	m_simd[3] = d.getSimd();
 }
 
 //==============================================================================
 template<>
-inline void TMat4<F32>::setRow(const U i, const TVec4<F32>& v)
+inline void TMat4<F32>::Base::setRow(const U i, const TVec4<F32>& v)
 {
-	simd[i] = v.getSimd();
+	m_simd[i] = v.getSimd();
 }
 
 //==============================================================================
 template<>
-inline void TMat4<F32>::transpose()
-{
-	_MM_TRANSPOSE4_PS(simd[0], simd[1], simd[2], simd[3]);
-}
-
-//==============================================================================
-// Friends                                                                     =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline TMat4<F32> operator-(const F32 f, const TMat4<F32>& m4)
+inline void TMat4<F32>::Base::transpose()
 {
-	TMat4<F32> r;
-	__m128 mm = _mm_set1_ps(f);
-
-	for(U i = 0; i < 4; i++)
-	{
-		r.simd[i] = _mm_sub_ps(mm, m4.simd[i]);
-	}
-
-	return r;
+	_MM_TRANSPOSE4_PS(m_simd[0], m_simd[1], m_simd[2], m_simd[3]);
 }
 
-//==============================================================================
-template<>
-inline TMat4<F32> operator/(const F32 f, const TMat4<F32>& m4)
-{
-	TMat4<F32> r;
-	__m128 mm = _mm_set1_ps(f);
-
-	for(U i = 0; i < 4; i++)
-	{
-		r.simd[i] = _mm_div_ps(mm, m4.simd[i]);
-	}
+#elif ANKI_SIMD == ANKI_SIMD_NEON
 
-	return r;
-}
+#	error "TODO"
 
 #endif
 

+ 64 - 182
include/anki/math/Quat.h

@@ -2,68 +2,66 @@
 #define ANKI_MATH_QUAT_H
 
 #include "anki/math/CommonIncludes.h"
+#include "anki/math/Vec4.h"
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Quaternion. Used in rotations
 template<typename T>
-ANKI_ATTRIBUTE_ALIGNED(class, 16) TQuat
+class alignas(16) TQuat: public TVec4<T>
 {
 public:
+	using Base = TVec4<T>;
+	
+	using Base::Base;
+	using Base::x;
+	using Base::y;
+	using Base::z;
+	using Base::w;
+	using Base::operator=;
+	using Base::getLengthSquared;
+	using Base::normalize;
+
 	/// @name Constructors
 	/// @{
 	explicit TQuat()
-	{
-		x() = y() = z() = w() = 0.0;
-	}
+		: Base()
+	{}
 
-	explicit TQuat(const T f)
-	{
-		x() = y() = z() = w() = f;
-	}
+	TQuat(const TQuat& b)
+		: Base(b)
+	{}
 
 	explicit TQuat(const T x_, const T y_, const T z_, const T w_)
-	{
-		x() = x_;
-		y() = y_;
-		z() = z_;
-		w() = w_;
-	}
+		: Base(x_, y_, z_, w_)
+	{}
 
-	explicit TQuat(const TVec2<T>& v2, const T z_, const T w_)
-	{
-		x() = v2.x();
-		y() = v2.y();
-		z() = z_;
-		w() = w_;
-	}
+	explicit TQuat(const T f)
+		: Base(f)
+	{}
 
-	explicit TQuat(const TVec3<T>& v3, const T w_)
-	{
-		x() = v3.x();
-		y() = v3.y();
-		z() = v3.z();
-		w() = w_;
-	}
+	explicit TQuat(const T arr[])
+		: Base(arr)
+	{}
 
-	explicit TQuat(const TVec4<T>& v4)
-	{
-		x() = v4.x();
-		y() = v4.y();
-		z() = v4.z();
-		w() = v4.w();
-	}
-	
-	TQuat(const TQuat& b)
-	{
-		x() = b.x();
-		y() = b.y();
-		z() = b.z();
-		w() = b.w();
-	}
+	explicit TQuat(const typename Base::Simd& simd)
+		: Base(simd)
+	{}
+
+	explicit TQuat(const TVec2<T>& v, const T z_, const T w_)
+		: Base(v, z_, w_)
+	{}
+
+	explicit TQuat(const TVec3<T>& v, const T w_)
+		: Base(v, w_)
+	{}
+
+	explicit TQuat(const TVec4<T>& v)
+		: Base(v)
+	{}
 
 	explicit TQuat(const TMat3<T>& m3)
 	{
@@ -147,92 +145,6 @@ public:
 	}
 	/// @}
 
-	/// @name Accessors
-	/// @{
-	T x() const
-	{
-		return vec.x;
-	}
-
-	T& x()
-	{
-		return vec.x;
-	}
-
-	T y() const
-	{
-		return vec.y;
-	}
-
-	T& y()
-	{
-		return vec.y;
-	}
-
-	T z() const
-	{
-		return vec.z;
-	}
-
-	T& z()
-	{
-		return vec.z;
-	}
-
-	T w() const
-	{
-		return vec.w;
-	}
-
-	T& w()
-	{
-		return vec.w;
-	}
-	/// @}
-
-	/// Operators with same type
-	/// @{
-	TQuat& operator=(const TQuat& b)
-	{
-		x() = b.x();
-		y() = b.y();
-		z() = b.z();
-		w() = b.w();
-		return *this;
-	}
-
-	/// 16 muls, 12 adds
-	TQuat operator*(const TQuat& b) const
-	{
-		// XXX See if this can be optimized
-		TQuat out;
-		out.vec.x = x() * b.w() + y() * b.z() - z() * b.y() + w() * b.x();
-		out.vec.y = -x() * b.z() + y() * b.w() + z() * b.x() + w() * b.y();
-		out.vec.z = x() * b.y() - y() * b.x() + z() * b.w() + w() * b.z();
-		out.vec.w = -x() * b.x() - y() * b.y() - z() * b.z() + w() * b.w();
-		return out;
-	}
-
-	TQuat& operator*=(const TQuat& b)
-	{
-		(*this) = (*this) * b;
-		return (*this);
-	}
-
-	Bool operator==(const TQuat& b) const
-	{
-		return isZero<T>(x() - b.x()) &&
-			isZero<T>(y() - b.y()) &&
-			isZero<T>(z() - b.z()) &&
-			isZero<T>(w() - b.w());
-	}
-
-	Bool operator!=(const TQuat& b) const
-	{
-		return !((*this) == b);
-	}
-	/// @}
-
 	/// @name Other
 	/// @{
 
@@ -240,7 +152,7 @@ public:
 	void setFrom2Vec3(const TVec3<T>& from, const TVec3<T>& to)
 	{
 		TVec3<T> axis(from.cross(to));
-		(*this) = TQuat(axis.x(), axis.y(), axis.z(), from.dot(to));
+		*this = TQuat(axis.x(), axis.y(), axis.z(), from.dot(to));
 		normalize();
 		w() += 1.0;
 
@@ -248,24 +160,19 @@ public:
 		{
 			if(from.z() * from.z() > from.x() * from.x())
 			{
-				(*this) = TQuat(0.0, from.z(), -from.y(), 0.0);
+				*this = TQuat(0.0, from.z(), -from.y(), 0.0);
 			}
 			else
 			{
-				(*this) = TQuat(from.y(), -from.x(), 0.0, 0.0);
+				*this = TQuat(from.y(), -from.x(), 0.0, 0.0);
 			}
 		}
 		normalize();
 	}
 
-	T getLength() const
-	{
-		return sqrt<T>(w() * w() + x() * x() + y() * y() + z() * z());
-	}
-
 	TQuat getInverted() const
 	{
-		T norm = w() * w() + x() * x() + y() * y() + z() * z();
+		T norm = getLengthSquared();
 
 		ANKI_ASSERT(!isZero<T>(norm)); // Norm is zero
 
@@ -290,26 +197,11 @@ public:
 		return TQuat(-x(), -y(), -z(), w());
 	}
 
-	void normalize()
-	{
-		(*this) = getNormalized();
-	}
-
-	TQuat getNormalized() const
-	{
-		return TQuat(TVec4<T>(*this).getNormalized());
-	}
-
-	T dot(const TQuat& b) const
-	{
-		return w() * b.w() + x() * b.x() + y() * b.y() + z() * b.z();
-	}
-
 	/// Returns slerp(this, q1, t)
 	TQuat slerp(const TQuat& q1_, const T t) const
 	{
-		TVec4<T> q0(*this);
-		TVec4<T> q1(q1_);
+		TQuat q1 = q1_;
+		const TQuat& q0 = *this;
 		T cosHalfTheta = q0.dot(q1);
 		if(cosHalfTheta < 0.0)
 		{
@@ -329,54 +221,44 @@ public:
 		{
 			return TQuat((q0 + q1) * 0.5);
 		}
+
 		T ratioA = sin<T>((1.0 - t) * halfTheta) / sinHalfTheta;
-		T ratio_b = sin<T>(t * halfTheta) / sinHalfTheta;
-		TVec4<T> tmp, tmp1, sum;
+		T ratioB = sin<T>(t * halfTheta) / sinHalfTheta;
+		TQuat tmp, tmp1, sum;
 		tmp = q0 * ratioA;
-		tmp1 = q1 * ratio_b;
+		tmp1 = q1 * ratioB;
 		sum = tmp + tmp1;
 		sum.normalize();
 		return TQuat(sum);
 	}
 
-	/// The same as TQuat * TQuat
+	/// @note 16 muls, 12 adds
 	TQuat getRotated(const TQuat& b) const 
 	{
-		return (*this) * b;
+		// XXX See if this can be optimized
+		TQuat out;
+		out.x() = x() * b.w() + y() * b.z() - z() * b.y() + w() * b.x();
+		out.y() = -x() * b.z() + y() * b.w() + z() * b.x() + w() * b.y();
+		out.z() = x() * b.y() - y() * b.x() + z() * b.w() + w() * b.z();
+		out.w() = -x() * b.x() - y() * b.y() - z() * b.z() + w() * b.w();
+		return out;
 	}
 
 	/// @see getRotated
 	void rotate(const TQuat& b)
 	{
-		(*this) = getRotated(b);
+		*this = getRotated(b);
 	}
 
 	void setIdentity()
 	{
-		x() = y() = z() = 0.0;
-		w() = 1.0;
+		*this = getIdentity();
 	}
 
-	static const TQuat& getIdentity()
+	static TQuat getIdentity()
 	{
-		static TQuat ident(0.0, 0.0, 0.0, 1.0);
-		return ident;
+		return TQuat(0.0, 0.0, 0.0, 1.0);
 	}
-
-	std::string toString() const
-	{
-		return std::to_string(x()) + " " + std::to_string(y()) + " "
-			+ std::to_string(z()) + " " + std::to_string(w());
-	}
-	/// @}
-
-private:
-	/// @name Data
-	/// @{
-	struct
-	{
-		T x, y, z, w;
-	} vec;
 	/// @}
 };
 

+ 38 - 36
include/anki/math/Transform.h

@@ -7,7 +7,7 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Transformation
@@ -21,19 +21,19 @@ public:
 	{}
 
 	TTransform(const TTransform& b)
-		: origin(b.origin), rotation(b.rotation), scale(b.scale)
+		: m_origin(b.m_origin), m_rotation(b.m_rotation), m_scale(b.m_scale)
 	{}
 
 	explicit TTransform(const Mat4& m4)
 	{
-		rotation = m4.getRotationPart();
-		origin = m4.getTranslationPart();
-		scale = 1.0;
+		m_rotation = m4.getRotationPart();
+		m_origin = m4.getTranslationPart().xyz();
+		m_scale = 1.0;
 	}
 
-	explicit TTransform(const TVec3<T>& origin_, const TMat3<T>& rotation_,
-		const T scale_)
-		: origin(origin_), rotation(rotation_), scale(scale_)
+	explicit TTransform(const TVec3<T>& origin, const TMat3<T>& rotation,
+		const T scale)
+		: m_origin(origin), m_rotation(rotation), m_scale(scale)
 	{}
 	/// @}
 
@@ -41,47 +41,47 @@ public:
 	/// @{
 	const TVec3<T>& getOrigin() const
 	{
-		return origin;
+		return m_origin;
 	}
 
 	TVec3<T>& getOrigin()
 	{
-		return origin;
+		return m_origin;
 	}
 
-	void setOrigin(const TVec3<T> o)
+	void setOrigin(const TVec3<T>& o)
 	{
-		origin = o;
+		m_origin = o;
 	}
 
 	const TMat3<T>& getRotation() const
 	{
-		return rotation;
+		return m_rotation;
 	}
 
 	TMat3<T>& getRotation()
 	{
-		return rotation;
+		return m_rotation;
 	}
 
 	void setRotation(const TMat3<T>& r)
 	{
-		rotation = r;
+		m_rotation = r;
 	}
 
 	T getScale() const
 	{
-		return scale;
+		return m_scale;
 	}
 
 	T& getScale()
 	{
-		return scale;
+		return m_scale;
 	}
 
 	void setScale(const T s)
 	{
-		scale = s;
+		m_scale = s;
 	}
 	/// @}
 
@@ -89,15 +89,16 @@ public:
 	/// @{
 	TTransform& operator=(const TTransform& b)
 	{
-		origin = b.origin;
-		rotation = b.rotation;
-		scale = b.scale;
+		m_origin = b.m_origin;
+		m_rotation = b.m_rotation;
+		m_scale = b.m_scale;
 		return *this;
 	}
 
 	Bool operator==(const TTransform& b) const
 	{
-		return origin == b.origin && rotation == b.rotation && scale == b.scale;
+		return m_origin == b.m_origin && m_rotation == b.m_rotation 
+			&& m_scale == b.m_scale;
 	}
 
 	Bool operator!=(const TTransform& b) const
@@ -145,9 +146,10 @@ public:
 	{
 		TTransform out;
 
-		out.origin = b.origin.getTransformed(a.origin, a.rotation, a.scale);
-		out.rotation = a.rotation * b.rotation;
-		out.scale = a.scale * b.scale;
+		out.m_origin = 
+			b.m_origin.getTransformed(a.m_origin, a.m_rotation, a.m_scale);
+		out.m_rotation = a.m_rotation * b.m_rotation;
+		out.m_scale = a.m_scale * b.m_scale;
 
 		return out;
 	}
@@ -156,9 +158,9 @@ public:
 	TTransform getInverse() const
 	{
 		TTransform o;
-		o.rotation = rotation.getTransposed(); // Rotation
-		o.scale = 1.0 / scale; // Apply scale
-		o.origin = -((o.rotation * o.scale) * origin); // Translation
+		o.m_rotation = m_rotation.getTransposed(); // Rotation
+		o.m_scale = 1.0 / m_scale; // Apply scale
+		o.m_origin = -((o.m_rotation * o.m_scale) * m_origin); // Translation
 		return o;
 	}
 
@@ -169,24 +171,24 @@ public:
 
 	void transform(const TTransform& b)
 	{
-		origin = b.origin.getTransformed(origin, rotation, scale);
-		rotation = rotation * b.rotation;
-		scale *= b.scale;
+		m_origin = b.m_origin.getTransformed(m_origin, m_rotation, m_scale);
+		m_rotation = m_rotation * b.m_rotation;
+		m_scale *= b.m_scale;
 	}
 
 	std::string toString() const
 	{
-		return origin.toString() + " " + rotation.toString() + " " + 
-			std::to_string(scale);
+		return m_origin.toString() + " " + m_rotation.toString() + " " + 
+			std::to_string(m_scale);
 	}
 	/// @}
 
 private:
 	/// @name Data
 	/// @{
-	TVec3<T> origin; ///< The rotation
-	TMat3<T> rotation; ///< The translation
-	T scale; ///< The uniform scaling
+	TVec3<T> m_origin; ///< The rotation
+	TMat3<T> m_rotation; ///< The translation
+	T m_scale; ///< The uniform scaling
 	/// @}
 };
 

+ 2167 - 0
include/anki/math/Vec.h

@@ -0,0 +1,2167 @@
+#ifndef ANKI_MATH_VEC_H
+#define ANKI_MATH_VEC_H
+
+#include "anki/math/CommonIncludes.h"
+#include <type_traits>
+
+namespace anki {
+
+/// @addtogroup math
+/// @{
+
+/// Common code for all vectors
+template<typename T, U N, typename TSimd, typename TV>
+class TVec
+{
+public:
+	using Scalar = T;
+	using Simd = TSimd;
+	static constexpr U SIZE = N;
+	static constexpr Bool IS_INTEGER = std::is_integral<T>::value;
+
+	/// @name Constructors
+	/// @{
+	explicit TVec()
+	{}
+
+	TVec(const TVec& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] = b.m_arr[i];
+		}
+	}
+
+	explicit TVec(const T x_, const T y_)
+	{
+		static_assert(N == 2, "Wrong vector");
+		x() = x_;
+		y() = y_;
+	}
+
+	explicit TVec(const T x_, const T y_, const T z_)
+	{
+		static_assert(N == 3, "Wrong vector");
+		x() = x_;
+		y() = y_;
+		z() = z_;
+	}
+
+	explicit TVec(const T x_, const T y_, const T z_, const T w_)
+	{
+		static_assert(N == 4, "Wrong vector");
+		x() = x_;
+		y() = y_;
+		z() = z_;
+		w() = w_;
+	}
+
+	explicit TVec(const T f)
+	{
+		for(U i = 0; i < N; ++i)
+		{
+			m_arr[i] = f;
+		}
+	}
+
+	explicit TVec(const T arr[])
+	{
+		for(U i = 0; i < N; ++i)
+		{
+			m_arr[i] = arr[i];
+		}
+	}
+
+	explicit TVec(const Simd& simd)
+	{
+		m_simd = simd;
+	}
+	/// @}
+
+	/// @name Accessors
+	/// @{
+	T& x()
+	{
+		return m_arr[0];
+	}
+
+	T x() const
+	{
+		return m_arr[0];
+	}
+
+	T& y()
+	{
+		return m_arr[1];
+	}
+
+	T y() const
+	{
+		return m_arr[1];
+	}
+
+	T& z()
+	{
+		static_assert(N > 2, "Wrong vector");
+		return m_arr[2];
+	}
+
+	T z() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return m_arr[2];
+	}
+
+	T& w()
+	{
+		static_assert(N > 3, "Wrong vector");
+		return m_arr[3];
+	}
+
+	T w() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return m_arr[3];
+	}
+
+	TVec2<T> xx() const
+	{
+		return TVec2<T>(x(), x());
+	}
+
+	TVec2<T> yy() const
+	{
+		return TVec2<T>(y(), y());
+	}
+
+	TVec2<T> xy() const
+	{
+		return TVec2<T>(x(), y());
+	}
+
+	TVec2<T> yx() const
+	{
+		return TVec2<T>(y(), x());
+	}
+
+	TVec3<T> xxx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), x(), x());
+	}
+
+	TVec3<T> xxy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), x(), y());
+	}
+
+	TVec3<T> xxz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), x(), z());
+	}
+
+	TVec3<T> xyx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), y(), x());
+	}
+
+	TVec3<T> xyy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), y(), y());
+	}
+
+	TVec3<T> xyz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), y(), z());
+	}
+
+	TVec3<T> xzx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), z(), x());
+	}
+
+	TVec3<T> xzy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), z(), y());
+	}
+
+	TVec3<T> xzz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(x(), z(), z());
+	}
+
+	TVec3<T> yxx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), x(), x());
+	}
+
+	TVec3<T> yxy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), x(), y());
+	}
+
+	TVec3<T> yxz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), x(), z());
+	}
+
+	TVec3<T> yyx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), y(), x());
+	}
+
+	TVec3<T> yyy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), y(), y());
+	}
+
+	TVec3<T> yyz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), y(), z());
+	}
+
+	TVec3<T> yzx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), z(), x());
+	}
+
+	TVec3<T> yzy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), z(), y());
+	}
+
+	TVec3<T> yzz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(y(), z(), z());
+	}
+
+	TVec3<T> zxx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), x(), x());
+	}
+
+	TVec3<T> zxy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), x(), y());
+	}
+
+	TVec3<T> zxz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), x(), z());
+	}
+
+	TVec3<T> zyx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), y(), x());
+	}
+
+	TVec3<T> zyy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), y(), y());
+	}
+
+	TVec3<T> zyz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), y(), z());
+	}
+
+	TVec3<T> zzx() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), z(), x());
+	}
+
+	TVec3<T> zzy() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), z(), y());
+	}
+
+	TVec3<T> zzz() const
+	{
+		static_assert(N > 2, "Wrong vector");
+		return TVec3<T>(z(), z(), z());
+	}
+
+
+	TVec4<T> xxxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), x(), x());
+	}
+
+	TVec4<T> xxxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), x(), y());
+	}
+
+	TVec4<T> xxxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), x(), z());
+	}
+
+	TVec4<T> xxxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), x(), w());
+	}
+
+	TVec4<T> xxyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), y(), x());
+	}
+
+	TVec4<T> xxyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), y(), y());
+	}
+
+	TVec4<T> xxyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), y(), z());
+	}
+
+	TVec4<T> xxyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), y(), w());
+	}
+
+	TVec4<T> xxzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), z(), x());
+	}
+
+	TVec4<T> xxzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), z(), y());
+	}
+
+	TVec4<T> xxzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), z(), z());
+	}
+
+	TVec4<T> xxzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), z(), w());
+	}
+
+	TVec4<T> xxwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), w(), x());
+	}
+
+	TVec4<T> xxwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), w(), y());
+	}
+
+	TVec4<T> xxwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), w(), z());
+	}
+
+	TVec4<T> xxww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), x(), w(), w());
+	}
+
+	TVec4<T> xyxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), x(), x());
+	}
+
+	TVec4<T> xyxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), x(), y());
+	}
+
+	TVec4<T> xyxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), x(), z());
+	}
+
+	TVec4<T> xyxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), x(), w());
+	}
+
+	TVec4<T> xyyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), y(), x());
+	}
+
+	TVec4<T> xyyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), y(), y());
+	}
+
+	TVec4<T> xyyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), y(), z());
+	}
+
+	TVec4<T> xyyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), y(), w());
+	}
+
+	TVec4<T> xyzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), z(), x());
+	}
+
+	TVec4<T> xyzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), z(), y());
+	}
+
+	TVec4<T> xyzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), z(), z());
+	}
+
+	TVec4<T> xyzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), z(), w());
+	}
+
+	TVec4<T> xywx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), w(), x());
+	}
+
+	TVec4<T> xywy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), w(), y());
+	}
+
+	TVec4<T> xywz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), w(), z());
+	}
+
+	TVec4<T> xyww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), y(), w(), w());
+	}
+
+	TVec4<T> xzxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), x(), x());
+	}
+
+	TVec4<T> xzxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), x(), y());
+	}
+
+	TVec4<T> xzxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), x(), z());
+	}
+
+	TVec4<T> xzxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), x(), w());
+	}
+
+	TVec4<T> xzyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), y(), x());
+	}
+
+	TVec4<T> xzyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), y(), y());
+	}
+
+	TVec4<T> xzyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), y(), z());
+	}
+
+	TVec4<T> xzyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), y(), w());
+	}
+
+	TVec4<T> xzzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), z(), x());
+	}
+
+	TVec4<T> xzzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), z(), y());
+	}
+
+	TVec4<T> xzzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), z(), z());
+	}
+
+	TVec4<T> xzzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), z(), w());
+	}
+
+	TVec4<T> xzwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), w(), x());
+	}
+
+	TVec4<T> xzwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), w(), y());
+	}
+
+	TVec4<T> xzwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), w(), z());
+	}
+
+	TVec4<T> xzww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), z(), w(), w());
+	}
+
+	TVec4<T> xwxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), x(), x());
+	}
+
+	TVec4<T> xwxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), x(), y());
+	}
+
+	TVec4<T> xwxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), x(), z());
+	}
+
+	TVec4<T> xwxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), x(), w());
+	}
+
+	TVec4<T> xwyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), y(), x());
+	}
+
+	TVec4<T> xwyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), y(), y());
+	}
+
+	TVec4<T> xwyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), y(), z());
+	}
+
+	TVec4<T> xwyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), y(), w());
+	}
+
+	TVec4<T> xwzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), z(), x());
+	}
+
+	TVec4<T> xwzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), z(), y());
+	}
+
+	TVec4<T> xwzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), z(), z());
+	}
+
+	TVec4<T> xwzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), z(), w());
+	}
+
+	TVec4<T> xwwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), w(), x());
+	}
+
+	TVec4<T> xwwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), w(), y());
+	}
+
+	TVec4<T> xwwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), w(), z());
+	}
+
+	TVec4<T> xwww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(x(), w(), w(), w());
+	}
+
+	TVec4<T> yxxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), x(), x());
+	}
+
+	TVec4<T> yxxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), x(), y());
+	}
+
+	TVec4<T> yxxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), x(), z());
+	}
+
+	TVec4<T> yxxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), x(), w());
+	}
+
+	TVec4<T> yxyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), y(), x());
+	}
+
+	TVec4<T> yxyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), y(), y());
+	}
+
+	TVec4<T> yxyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), y(), z());
+	}
+
+	TVec4<T> yxyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), y(), w());
+	}
+
+	TVec4<T> yxzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), z(), x());
+	}
+
+	TVec4<T> yxzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), z(), y());
+	}
+
+	TVec4<T> yxzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), z(), z());
+	}
+
+	TVec4<T> yxzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), z(), w());
+	}
+
+	TVec4<T> yxwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), w(), x());
+	}
+
+	TVec4<T> yxwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), w(), y());
+	}
+
+	TVec4<T> yxwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), w(), z());
+	}
+
+	TVec4<T> yxww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), x(), w(), w());
+	}
+
+	TVec4<T> yyxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), x(), x());
+	}
+
+	TVec4<T> yyxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), x(), y());
+	}
+
+	TVec4<T> yyxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), x(), z());
+	}
+
+	TVec4<T> yyxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), x(), w());
+	}
+
+	TVec4<T> yyyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), y(), x());
+	}
+
+	TVec4<T> yyyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), y(), y());
+	}
+
+	TVec4<T> yyyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), y(), z());
+	}
+
+	TVec4<T> yyyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), y(), w());
+	}
+
+	TVec4<T> yyzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), z(), x());
+	}
+
+	TVec4<T> yyzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), z(), y());
+	}
+
+	TVec4<T> yyzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), z(), z());
+	}
+
+	TVec4<T> yyzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), z(), w());
+	}
+
+	TVec4<T> yywx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), w(), x());
+	}
+
+	TVec4<T> yywy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), w(), y());
+	}
+
+	TVec4<T> yywz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), w(), z());
+	}
+
+	TVec4<T> yyww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), y(), w(), w());
+	}
+
+	TVec4<T> yzxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), x(), x());
+	}
+
+	TVec4<T> yzxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), x(), y());
+	}
+
+	TVec4<T> yzxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), x(), z());
+	}
+
+	TVec4<T> yzxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), x(), w());
+	}
+
+	TVec4<T> yzyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), y(), x());
+	}
+
+	TVec4<T> yzyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), y(), y());
+	}
+
+	TVec4<T> yzyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), y(), z());
+	}
+
+	TVec4<T> yzyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), y(), w());
+	}
+
+	TVec4<T> yzzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), z(), x());
+	}
+
+	TVec4<T> yzzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), z(), y());
+	}
+
+	TVec4<T> yzzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), z(), z());
+	}
+
+	TVec4<T> yzzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), z(), w());
+	}
+
+	TVec4<T> yzwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), w(), x());
+	}
+
+	TVec4<T> yzwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), w(), y());
+	}
+
+	TVec4<T> yzwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), w(), z());
+	}
+
+	TVec4<T> yzww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), z(), w(), w());
+	}
+
+	TVec4<T> ywxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), x(), x());
+	}
+
+	TVec4<T> ywxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), x(), y());
+	}
+
+	TVec4<T> ywxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), x(), z());
+	}
+
+	TVec4<T> ywxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), x(), w());
+	}
+
+	TVec4<T> ywyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), y(), x());
+	}
+
+	TVec4<T> ywyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), y(), y());
+	}
+
+	TVec4<T> ywyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), y(), z());
+	}
+
+	TVec4<T> ywyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), y(), w());
+	}
+
+	TVec4<T> ywzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), z(), x());
+	}
+
+	TVec4<T> ywzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), z(), y());
+	}
+
+	TVec4<T> ywzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), z(), z());
+	}
+
+	TVec4<T> ywzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), z(), w());
+	}
+
+	TVec4<T> ywwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), w(), x());
+	}
+
+	TVec4<T> ywwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), w(), y());
+	}
+
+	TVec4<T> ywwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), w(), z());
+	}
+
+	TVec4<T> ywww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(y(), w(), w(), w());
+	}
+
+	TVec4<T> zxxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), x(), x());
+	}
+
+	TVec4<T> zxxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), x(), y());
+	}
+
+	TVec4<T> zxxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), x(), z());
+	}
+
+	TVec4<T> zxxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), x(), w());
+	}
+
+	TVec4<T> zxyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), y(), x());
+	}
+
+	TVec4<T> zxyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), y(), y());
+	}
+
+	TVec4<T> zxyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), y(), z());
+	}
+
+	TVec4<T> zxyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), y(), w());
+	}
+
+	TVec4<T> zxzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), z(), x());
+	}
+
+	TVec4<T> zxzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), z(), y());
+	}
+
+	TVec4<T> zxzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), z(), z());
+	}
+
+	TVec4<T> zxzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), z(), w());
+	}
+
+	TVec4<T> zxwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), w(), x());
+	}
+
+	TVec4<T> zxwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), w(), y());
+	}
+
+	TVec4<T> zxwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), w(), z());
+	}
+
+	TVec4<T> zxww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), x(), w(), w());
+	}
+
+	TVec4<T> zyxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), x(), x());
+	}
+
+	TVec4<T> zyxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), x(), y());
+	}
+
+	TVec4<T> zyxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), x(), z());
+	}
+
+	TVec4<T> zyxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), x(), w());
+	}
+
+	TVec4<T> zyyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), y(), x());
+	}
+
+	TVec4<T> zyyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), y(), y());
+	}
+
+	TVec4<T> zyyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), y(), z());
+	}
+
+	TVec4<T> zyyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), y(), w());
+	}
+
+	TVec4<T> zyzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), z(), x());
+	}
+
+	TVec4<T> zyzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), z(), y());
+	}
+
+	TVec4<T> zyzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), z(), z());
+	}
+
+	TVec4<T> zyzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), z(), w());
+	}
+
+	TVec4<T> zywx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), w(), x());
+	}
+
+	TVec4<T> zywy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), w(), y());
+	}
+
+	TVec4<T> zywz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), w(), z());
+	}
+
+	TVec4<T> zyww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), y(), w(), w());
+	}
+
+	TVec4<T> zzxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), x(), x());
+	}
+
+	TVec4<T> zzxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), x(), y());
+	}
+
+	TVec4<T> zzxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), x(), z());
+	}
+
+	TVec4<T> zzxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), x(), w());
+	}
+
+	TVec4<T> zzyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), y(), x());
+	}
+
+	TVec4<T> zzyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), y(), y());
+	}
+
+	TVec4<T> zzyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), y(), z());
+	}
+
+	TVec4<T> zzyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), y(), w());
+	}
+
+	TVec4<T> zzzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), z(), x());
+	}
+
+	TVec4<T> zzzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), z(), y());
+	}
+
+	TVec4<T> zzzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), z(), z());
+	}
+
+	TVec4<T> zzzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), z(), w());
+	}
+
+	TVec4<T> zzwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), w(), x());
+	}
+
+	TVec4<T> zzwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), w(), y());
+	}
+
+	TVec4<T> zzwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), w(), z());
+	}
+
+	TVec4<T> zzww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), z(), w(), w());
+	}
+
+	TVec4<T> zwxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), x(), x());
+	}
+
+	TVec4<T> zwxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), x(), y());
+	}
+
+	TVec4<T> zwxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), x(), z());
+	}
+
+	TVec4<T> zwxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), x(), w());
+	}
+
+	TVec4<T> zwyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), y(), x());
+	}
+
+	TVec4<T> zwyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), y(), y());
+	}
+
+	TVec4<T> zwyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), y(), z());
+	}
+
+	TVec4<T> zwyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), y(), w());
+	}
+
+	TVec4<T> zwzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), z(), x());
+	}
+
+	TVec4<T> zwzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), z(), y());
+	}
+
+	TVec4<T> zwzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), z(), z());
+	}
+
+	TVec4<T> zwzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), z(), w());
+	}
+
+	TVec4<T> zwwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), w(), x());
+	}
+
+	TVec4<T> zwwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), w(), y());
+	}
+
+	TVec4<T> zwwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), w(), z());
+	}
+
+	TVec4<T> zwww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(z(), w(), w(), w());
+	}
+
+	TVec4<T> wxxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), x(), x());
+	}
+
+	TVec4<T> wxxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), x(), y());
+	}
+
+	TVec4<T> wxxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), x(), z());
+	}
+
+	TVec4<T> wxxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), x(), w());
+	}
+
+	TVec4<T> wxyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), y(), x());
+	}
+
+	TVec4<T> wxyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), y(), y());
+	}
+
+	TVec4<T> wxyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), y(), z());
+	}
+
+	TVec4<T> wxyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), y(), w());
+	}
+
+	TVec4<T> wxzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), z(), x());
+	}
+
+	TVec4<T> wxzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), z(), y());
+	}
+
+	TVec4<T> wxzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), z(), z());
+	}
+
+	TVec4<T> wxzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), z(), w());
+	}
+
+	TVec4<T> wxwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), w(), x());
+	}
+
+	TVec4<T> wxwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), w(), y());
+	}
+
+	TVec4<T> wxwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), w(), z());
+	}
+
+	TVec4<T> wxww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), x(), w(), w());
+	}
+
+	TVec4<T> wyxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), x(), x());
+	}
+
+	TVec4<T> wyxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), x(), y());
+	}
+
+	TVec4<T> wyxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), x(), z());
+	}
+
+	TVec4<T> wyxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), x(), w());
+	}
+
+	TVec4<T> wyyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), y(), x());
+	}
+
+	TVec4<T> wyyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), y(), y());
+	}
+
+	TVec4<T> wyyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), y(), z());
+	}
+
+	TVec4<T> wyyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), y(), w());
+	}
+
+	TVec4<T> wyzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), z(), x());
+	}
+
+	TVec4<T> wyzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), z(), y());
+	}
+
+	TVec4<T> wyzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), z(), z());
+	}
+
+	TVec4<T> wyzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), z(), w());
+	}
+
+	TVec4<T> wywx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), w(), x());
+	}
+
+	TVec4<T> wywy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), w(), y());
+	}
+
+	TVec4<T> wywz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), w(), z());
+	}
+
+	TVec4<T> wyww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), y(), w(), w());
+	}
+
+	TVec4<T> wzxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), x(), x());
+	}
+
+	TVec4<T> wzxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), x(), y());
+	}
+
+	TVec4<T> wzxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), x(), z());
+	}
+
+	TVec4<T> wzxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), x(), w());
+	}
+
+	TVec4<T> wzyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), y(), x());
+	}
+
+	TVec4<T> wzyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), y(), y());
+	}
+
+	TVec4<T> wzyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), y(), z());
+	}
+
+	TVec4<T> wzyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), y(), w());
+	}
+
+	TVec4<T> wzzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), z(), x());
+	}
+
+	TVec4<T> wzzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), z(), y());
+	}
+
+	TVec4<T> wzzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), z(), z());
+	}
+
+	TVec4<T> wzzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), z(), w());
+	}
+
+	TVec4<T> wzwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), w(), x());
+	}
+
+	TVec4<T> wzwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), w(), y());
+	}
+
+	TVec4<T> wzwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), w(), z());
+	}
+
+	TVec4<T> wzww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), z(), w(), w());
+	}
+
+	TVec4<T> wwxx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), x(), x());
+	}
+
+	TVec4<T> wwxy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), x(), y());
+	}
+
+	TVec4<T> wwxz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), x(), z());
+	}
+
+	TVec4<T> wwxw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), x(), w());
+	}
+
+	TVec4<T> wwyx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), y(), x());
+	}
+
+	TVec4<T> wwyy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), y(), y());
+	}
+
+	TVec4<T> wwyz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), y(), z());
+	}
+
+	TVec4<T> wwyw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), y(), w());
+	}
+
+	TVec4<T> wwzx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), z(), x());
+	}
+
+	TVec4<T> wwzy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), z(), y());
+	}
+
+	TVec4<T> wwzz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), z(), z());
+	}
+
+	TVec4<T> wwzw() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), z(), w());
+	}
+
+	TVec4<T> wwwx() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), w(), x());
+	}
+
+	TVec4<T> wwwy() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), w(), y());
+	}
+
+	TVec4<T> wwwz() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), w(), z());
+	}
+
+	TVec4<T> wwww() const
+	{
+		static_assert(N > 3, "Wrong vector");
+		return TVec4<T>(w(), w(), w(), w());
+	}	
+
+	T& operator[](const U i)
+	{
+		return m_arr[i];
+	}
+
+	T operator[](const U i) const
+	{
+		return m_arr[i];
+	}
+
+	TSimd& getSimd()
+	{
+		return m_simd;
+	}
+
+	const TSimd& getSimd() const
+	{
+		return m_simd;
+	}
+	/// @}
+
+	/// @name Operators with same type
+	/// @{
+	TVec& operator=(const TVec& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] = b.m_arr[i]; 
+		}
+		return *this;
+	}
+
+	TV& operator=(const TV& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] = b.m_arr[i]; 
+		}
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator+(const TV& b) const
+	{
+		TV out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr[i] = m_arr[i] + b.m_arr[i];
+		}
+		return out;
+	}
+
+	TV& operator+=(const TV& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] += b.m_arr[i];
+		}
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator-(const TV& b) const
+	{
+		TV out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr[i] = m_arr[i] - b.m_arr[i];
+		}
+		return out;
+	}
+
+	TV& operator-=(const TV& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] -= b.m_arr[i];
+		}
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator*(const TV& b) const
+	{
+		TV out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr[i] = m_arr[i] * b.m_arr[i];
+		}
+		return out;
+	}
+
+	TV& operator*=(const TV& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			m_arr[i] *= b.m_arr[i];
+		}
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator/(const TV& b) const
+	{
+		TV out;
+		for(U i = 0; i < N; i++)
+		{
+			ANKI_ASSERT(b.m_arr[i] != 0.0);
+			out.m_arr[i] = m_arr[i] / b.m_arr[i];
+		}
+		return out;
+	}
+
+	TV& operator/=(const TV& b)
+	{
+		for(U i = 0; i < N; i++)
+		{
+			ANKI_ASSERT(b.m_arr[i] != 0.0);
+			m_arr[i] /= b.m_arr[i];
+		}
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator-() const
+	{
+		TV out;
+		for(U i = 0; i < N; i++)
+		{
+			out.m_arr[i] = -m_arr[i];
+		}
+		return out;
+	}
+
+	Bool operator==(const TV& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(!isZero<T>(m_arr[i] - b.m_arr[i]))
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	Bool operator!=(const TV& b) const
+	{
+		return !operator==(b);
+	}
+
+	Bool operator<(const TV& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(m_arr[i] >= b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	Bool operator<=(const TV& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(m_arr[i] > b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	Bool operator>(const TV& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(m_arr[i] <= b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	Bool operator>=(const TV& b) const
+	{
+		for(U i = 0; i < N; i++)
+		{
+			if(m_arr[i] < b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+	/// @}
+
+	/// @name Operators with T
+	/// @{
+	TV operator+(const T f) const
+	{
+		return (*this) + TV(f);
+	}
+
+	TV& operator+=(const T f)
+	{
+		(*this) += TV(f);
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator-(const T f) const
+	{
+		return (*this) - TV(f);
+	}
+
+	TV& operator-=(const T f)
+	{
+		(*this) -= TV(f);
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator*(const T f) const
+	{
+		return (*this) * TV(f);
+	}
+
+	TV& operator*=(const T f)
+	{
+		(*this) *= TV(f);
+		return static_cast<TV&>(*this);
+	}
+
+	TV operator/(const T f) const
+	{
+		return (*this) / TV(f);
+	}
+
+	TV& operator/=(const T f)
+	{
+		(*this) /= TV(f);
+		return static_cast<TV&>(*this);
+	}
+	/// @}
+
+	/// @name Other
+	/// @{
+	T dot(const TV& b) const
+	{
+		T out = 0.0;
+		for(U i = 0; i < N; i++)
+		{
+			out += m_arr[i] * b.m_arr[i];
+		}
+		return out;
+	}
+
+	T getLengthSquared() const
+	{
+		T out = 0.0;
+		for(U i = 0; i < N; i++)
+		{
+			out += m_arr[i] * m_arr[i];
+		}
+		return out;
+	}
+
+	T getLength() const
+	{
+		return sqrt<T>(getLengthSquared());
+	}
+
+	T getDistanceSquared(const TV& b) const
+	{
+		return ((*this) - b).getLengthSquared();
+	}
+
+	T getDistance(const TV& b) const
+	{
+		return sqrt<T>(getDistance(b));
+	}
+
+	void normalize()
+	{
+		(*this) /= getLength();
+	}
+
+	TV getNormalized() const
+	{
+		return (*this) / getLength();
+	}
+
+	/// Return lerp(this, v1, t)
+	TV lerp(const TV& v1, T t) const
+	{
+		return ((*this) * (1.0 - t)) + (v1 * t);
+	}
+
+	String toString() const
+	{
+		String out;
+		for(U i = 0; i < N; i++)
+		{
+			out += std::to_string(m_arr[i]) + " ";
+		}
+		return out;
+	}
+	/// @}
+
+protected:
+	/// @name Data
+	/// @{
+	union
+	{
+		Array<T, N> m_arr;
+		TSimd m_simd;
+	};
+	/// @}
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif

+ 35 - 286
include/anki/math/Vec2.h

@@ -2,333 +2,82 @@
 #define ANKI_MATH_VEC2_H
 
 #include "anki/math/CommonIncludes.h"
+#include "anki/math/Vec.h"
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// 2D vector
 template<typename T>
-class TVec2
+class TVec2: public TVec<T, 2, Array<T, 2>, TVec2<T>>
 {
 	/// @name Friends
+	/// @{
 	template<typename Y>
-	friend TVec2<Y> operator+(const Y f, const TVec2<Y>& v2);
+	friend TVec2<Y> operator+(const Y f, const TVec2<Y>& b);
 	template<typename Y>
-	friend TVec2<Y> operator-(const Y f, const TVec2<Y>& v2);
+	friend TVec2<Y> operator-(const Y f, const TVec2<Y>& b);
 	template<typename Y>
-	friend TVec2<Y> operator*(const Y f, const TVec2<Y>& v2);
+	friend TVec2<Y> operator*(const Y f, const TVec2<Y>& b);
 	template<typename Y>
-	friend TVec2<Y> operator/(const Y f, const TVec2<Y>& v2);
-	///@]
+	friend TVec2<Y> operator/(const Y f, const TVec2<Y>& b);
+	///@}
 
 public:
+	using Base = TVec<T, 2, Array<T, 2>, TVec2<T>>;
+
 	/// @name Constructors
 	/// @{
 	explicit TVec2()
+		: Base()
 	{}
 
-	explicit TVec2(const T x_, const T y_)
-	{
-		x() = x_;
-		y() = y_;
-	}
-	
-	explicit TVec2(const T f)
-	{
-		x() = y() = f;
-	}
-
-	explicit TVec2(const T arr_[])
-	{
-		x() = arr_[0];
-		y() = arr_[1];
-	}
-
 	TVec2(const TVec2& b)
-	{
-		x() = b.x();
-		y() = b.y();
-	}
-
-	explicit TVec2(const TVec3<T>& v3)
-	{
-		x() = v3.x();
-		y() = v3.y();
-	}
-
-	explicit TVec2(const TVec4<T>& v4)
-	{
-		x() = v4.x();
-		y() = v4.y();
-	}
-	/// @}
-
-	/// @name Accessors
-	/// @{
-	T& x()
-	{
-		return vec.x;
-	}
-
-	T x() const
-	{
-		return vec.x;
-	}
-
-	T& y()
-	{
-		return vec.y;
-	}
-
-	T y() const
-	{
-		return vec.y;
-	}
-
-	TVec2 xx() const
-	{
-		return TVec2(vec.x, vec.x);
-	}
-
-	TVec2 yy() const
-	{
-		return TVec2(vec.y, vec.y);
-	}
-
-	TVec2 xy() const
-	{
-		return *this;
-	}
-
-	TVec2 yx() const
-	{
-		return TVec2(vec.y, vec.x);
-	}
-
-	T& operator[](const U i)
-	{
-		return arr[i];
-	}
-
-	T operator[](const U i) const
-	{
-		return arr[i];
-	}
-	/// @}
-
-	/// @name Operators with same type
-	/// @{
-	TVec2& operator=(const TVec2& b)
-	{
-		x() = b.x();
-		y() = b.y();
-		return *this;
-	}
-
-	TVec2 operator+(const TVec2& b) const
-	{
-		return TVec2(x() + b.x(), y() + b.y());
-	}
-
-	TVec2& operator+=(const TVec2& b)
-	{
-		x() += b.x();
-		y() += b.y();
-		return (*this);
-	}
-
-	TVec2 operator-(const TVec2& b) const
-	{
-		return TVec2(x() - b.x(), y() - b.y());
-	}
-
-	TVec2& operator-=(const TVec2& b)
-	{
-		x() -= b.x();
-		y() -= b.y();
-		return (*this);
-	}
-
-	TVec2 operator*(const TVec2& b) const
-	{
-		return TVec2(x() * b.x(), y() * b.y());
-	}
-
-	TVec2& operator*=(const TVec2& b)
-	{
-		x() *= b.x();
-		y() *= b.y();
-		return (*this);
-	}
-
-	TVec2 operator/(const TVec2& b) const
-	{
-		return TVec2(x() / b.x(), y() / b.y());
-	}
-
-	TVec2& operator/=(const TVec2& b)
-	{
-		x() /= b.x();
-		y() /= b.y();
-		return (*this);
-	}
-
-	TVec2 operator-() const
-	{
-		return TVec2(-x(), -y());
-	}
-
-	Bool operator==(const TVec2& b) const
-	{
-		return isZero<T>(x() - b.x()) && isZero<T>(y() - b.y());
-	}
-
-	Bool operator!=(const TVec2& b) const
-	{
-		return !(*this == b);
-	}
-
-	Bool operator<(const TVec2& b) const
-	{
-		return vec.x < b.vec.x && vec.y < b.vec.y;
-	}
-
-	Bool operator<=(const TVec2& b) const
-	{
-		return vec.x <= b.vec.x && vec.y <= b.vec.y;
-	}
-
-	Bool operator>(const TVec2& b) const
-	{
-		return vec.x > b.vec.x && vec.y > b.vec.y;
-	}
-
-	Bool operator>=(const TVec2& b) const
-	{
-		return vec.x >= b.vec.x && vec.y >= b.vec.y;
-	}
-	/// @}
-
-	/// @name Operators with T
-	/// @{
-	TVec2 operator+(const T f) const
-	{
-		return (*this) + TVec2(f);
-	}
-
-	TVec2& operator+=(const T f)
-	{
-		(*this) += TVec2(f);
-		return (*this);
-	}
-
-	TVec2 operator-(const T f) const
-	{
-		return (*this) - TVec2(f);
-	}
-
-	TVec2& operator-=(const T f)
-	{
-		(*this) -= TVec2(f);
-		return (*this);
-	}
-
-	TVec2 operator*(const T f) const
-	{
-		return (*this) * TVec2(f);
-	}
-
-	TVec2& operator*=(const T f)
-	{
-		(*this) *= TVec2(f);
-		return (*this);
-	}
-
-	TVec2 operator/(const T f) const
-	{
-		return (*this) / TVec2(f);
-	}
-
-	TVec2& operator/=(const T f)
-	{
-		(*this) /= TVec2(f);
-		return (*this);
-	}
-	/// @}
-
-	/// @name Other
-	/// @{
-	T getLengthSquared() const
-	{
-		return x() * x() + y() * y();
-	}
-
-	T getLength() const
-	{
-		return sqrt<T>(getLengthSquared());
-	}
-
-	TVec2 getNormalized() const
-	{
-		return (*this) / getLength();
-	}
-
-	void normalize()
-	{
-		(*this) /= getLength();
-	}
-
-	T dot(const TVec2& b) const
-	{
-		return x() * b.x() + y() * b.y();
-	}
+		: Base(b)
+	{}
 
-	std::string toString() const
-	{
-		return std::to_string(x()) + " " + std::to_string(y());
-	}
-	/// @}
+	explicit TVec2(const T x_, const T y_)
+		: Base(x_, y_)
+	{}
 
-private:
-	/// @name Data members
-	/// @{
-	struct Vec
-	{
-		T x, y;
-	};
+	explicit TVec2(const T f)
+		: Base(f)
+	{}
 
-	union
-	{
-		Vec vec;
-		Array<T, 2> arr;
-	};
+	explicit TVec2(const T arr[])
+		: Base(arr)
+	{}
 	/// @}
 };
 
+/// @memberof TVec2
 template<typename T>
-TVec2<T> operator+(const T f, const TVec2<T>& v2)
+TVec2<T> operator+(const T f, const TVec2<T>& b)
 {
-	return v2 + f;
+	return b + f;
 }
 
+/// @memberof TVec2
 template<typename T>
-TVec2<T> operator-(const T f, const TVec2<T>& v2)
+TVec2<T> operator-(const T f, const TVec2<T>& b)
 {
-	return TVec2<T>(f - v2.x(), f - v2.y());
+	return TVec2<T>(f - b.x(), f - b.y());
 }
 
+/// @memberof TVec2
 template<typename T>
-TVec2<T> operator*(const T f, const TVec2<T>& v2)
+TVec2<T> operator*(const T f, const TVec2<T>& b)
 {
-	return v2 * f;
+	return b * f;
 }
 
+/// @memberof TVec2
 template<typename T>
-TVec2<T> operator/(const T f, const TVec2<T>& v2)
+TVec2<T> operator/(const T f, const TVec2<T>& b)
 {
-	return TVec2<T>(f / v2.x(), f / v2.y());
+	return TVec2<T>(f / b.x(), f / b.y());
 }
 
 /// F32 2D vector

+ 30 - 297
include/anki/math/Vec3.h

@@ -2,15 +2,16 @@
 #define ANKI_MATH_VEC3_H
 
 #include "anki/math/CommonIncludes.h"
+#include "anki/math/Vec.h"
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// 3D vector template. One of the most used classes
 template<typename T>
-class TVec3
+class TVec3: public TVec<T, 3, Array<T, 3>, TVec3<T>>
 {
 	/// @name Friends
 	/// @{
@@ -25,252 +26,38 @@ class TVec3
 	/// @}
 
 public:
+	using Base = TVec<T, 3, Array<T, 3>, TVec3<T>>;
+
+	using Base::x;
+	using Base::y;
+	using Base::z;
+	using Base::operator*;
+
 	/// @name Constructors
 	/// @{
 	explicit TVec3()
+		: Base()
 	{}
 
-	explicit TVec3(const T x_, const T y_, const T z_)
-	{
-		x() = x_;
-		y() = y_;
-		z() = z_;
-	}
-
-	explicit TVec3(const T f)
-	{
-		arr[0] = arr[1] = arr[2] = f;
-	}
-
-	explicit TVec3(const T arr_[])
-	{
-		arr[0] = arr_[0];
-		arr[1] = arr_[1];
-		arr[2] = arr_[2];
-	}
-
-	explicit TVec3(const TVec2<T>& v2, const T z_)
-	{
-		x() = v2.x();
-		y() = v2.y();
-		z() = z_;
-	}
-
 	TVec3(const TVec3& b)
-	{
-		arr[0] = b.arr[0];
-		arr[1] = b.arr[1];
-		arr[2] = b.arr[2];
-	}
-
-	explicit TVec3(const TVec4<T>& v4)
-	{
-		arr[0] = v4[0];
-		arr[1] = v4[1];
-		arr[2] = v4[2];
-	}
-
-	explicit TVec3(const TQuat<T>& q)
-	{
-		x() = q.x();
-		y() = q.y();
-		z() = q.z();
-	}
-	/// @}
-
-	/// @name Accessors
-	/// @{
-	T& x()
-	{
-		return vec.x;
-	}
-
-	T x() const
-	{
-		return vec.x;
-	}
-
-	T& y()
-	{
-		return vec.y;
-	}
-
-	T y() const
-	{
-		return vec.y;
-	}
-
-	T& z()
-	{
-		return vec.z;
-	}
-
-	T z() const
-	{
-		return vec.z;
-	}
-
-	T& operator[](const U i)
-	{
-		return arr[i];
-	}
-
-	T operator[](const U i) const
-	{
-		return arr[i];
-	}
-
-	TVec2<T> xy() const
-	{
-		return TVec2<T>(x(), y());
-	}
-	/// @}
-
-	/// @name Operators with same type
-	/// @{
-	TVec3& operator=(const TVec3& b)
-	{
-		arr[0] = b.arr[0];
-		arr[1] = b.arr[1];
-		arr[2] = b.arr[2];
-		return (*this);
-	}
-
-	TVec3 operator+(const TVec3& b) const
-	{
-		return TVec3(x() + b.x(), y() + b.y(), z() + b.z());
-	}
-
-	TVec3& operator+=(const TVec3& b)
-	{
-		x() += b.x();
-		y() += b.y();
-		z() += b.z();
-		return *this;
-	}
-
-	TVec3 operator-(const TVec3& b) const
-	{
-		return TVec3(x() - b.x(), y() - b.y(), z() - b.z());
-	}
-
-	TVec3& operator-=(const TVec3& b)
-	{
-		x() -= b.x();
-		y() -= b.y();
-		z() -= b.z();
-		return (*this);
-	}
-
-	TVec3 operator*(const TVec3& b) const
-	{
-		return TVec3(x() * b.x(), y() * b.y(), z() * b.z());
-	}
-
-	TVec3& operator*=(const TVec3& b)
-	{
-		x() *= b.x();
-		y() *= b.y();
-		z() *= b.z();
-		return (*this);
-	}
-
-	TVec3 operator/(const TVec3& b) const
-	{
-		return TVec3(x() / b.x(), y() / b.y(), z() / b.z());
-	}
-
-	TVec3& operator/=(const TVec3& b)
-	{
-		x() /= b.x();
-		y() /= b.y();
-		z() /= b.z();
-		return (*this);
-	}
-
-	TVec3 operator-() const
-	{
-		return TVec3(-x(), -y(), -z());
-	}
-
-	Bool operator==(const TVec3& b) const
-	{
-		return isZero<T>(x() - b.x()) 
-			&& isZero<T>(y() - b.y()) 
-			&& isZero<T>(z() - b.z());
-	}
-
-	Bool operator!=(const TVec3& b) const
-	{
-		return !operator==(b);
-	}
-
-	Bool operator<(const TVec3& b) const
-	{
-		return x() < b.x() && y() < b.y() && z() < b.z();
-	}
-
-	Bool operator<=(const TVec3& b) const
-	{
-		return x() <= b.x() && y() <= b.y() && z() <= b.z();
-	}
-
-	Bool operator>(const TVec3& b) const
-	{
-		return x() > b.x() && y() > b.y() && z() > b.z();
-	}
-
-	Bool operator>=(const TVec3& b) const
-	{
-		return x() >= b.x() && y() >= b.y() && z() >= b.z();
-	}
-	/// @}
-
-	/// @name Operators with T
-	/// @{
-	TVec3 operator+(const T f) const
-	{
-		return (*this) + TVec3(f);
-	}
-
-	TVec3& operator+=(const T f)
-	{
-		(*this) += TVec3(f);
-		return (*this);
-	}
-
-	TVec3 operator-(const T f) const
-	{
-		return (*this) - TVec3(f);
-	}
-
-	TVec3& operator-=(const T f)
-	{
-		(*this) -= TVec3(f);
-		return (*this);
-	}
+		: Base(b)
+	{}
 
-	TVec3 operator*(const T f) const
-	{
-		return (*this) * TVec3(f);
-	}
+	explicit TVec3(const T x_, const T y_, const T z_)
+		: Base(x_, y_, z_)
+	{}
 
-	TVec3& operator*=(const T f)
-	{
-		(*this) *= TVec3(f);
-		return (*this);
-	}
+	explicit TVec3(const T f)
+		: Base(f)
+	{}
 
-	TVec3 operator/(const T f) const
-	{
-		return (*this) / TVec3(f);
-	}
+	explicit TVec3(const T arr[])
+		: Base(arr)
+	{}
 
-	TVec3& operator/=(const T f)
-	{
-		(*this) /= TVec3(f);
-		return (*this);
-	}
+	explicit TVec3(const TVec2<T>& v, const T z_)
+		: Base(v.x(), v.y(), z_)
+	{}
 	/// @}
 
 	/// @name Operators with other types
@@ -285,12 +72,6 @@ public:
 	/// @name Other
 	/// @{
 
-	/// 3 muls, 2 adds
-	T dot(const TVec3& b) const
-	{
-		return x() * b.x() + y() * b.y() + z() * b.z();
-	}
-
 	/// 6 muls, 3 adds
 	TVec3 cross(const TVec3& b) const
 	{
@@ -299,31 +80,6 @@ public:
 			x() * b.y() - y() * b.x());
 	}
 
-	T getLengthSquared() const
-	{
-		return x() * x() + y() * y() + z() * z();
-	}
-
-	T getLength() const
-	{
-		return sqrt(getLengthSquared());
-	}
-
-	T getDistanceSquared(const TVec3& b) const
-	{
-		return ((*this) - b).getLengthSquared();
-	}
-
-	void normalize()
-	{
-		(*this) /= getLength();
-	}
-
-	TVec3 getNormalized() const
-	{
-		return (*this) / getLength();
-	}
-
 	TVec3 getProjection(const TVec3& toThis) const
 	{
 		return toThis * ((*this).dot(toThis) / (toThis.dot(toThis)));
@@ -334,7 +90,7 @@ public:
 	TVec3 getRotated(const TQuat<T>& q) const
 	{
 		ANKI_ASSERT(isZero<T>(1.0 - q.getLength())); // Not normalized quat
-		TVec3 qXyz(q);
+		TVec3 qXyz(q.x(), q.y(), q.z());
 		return 
 			(*this) + qXyz.cross(qXyz.cross((*this)) + (*this) * q.w()) * 2.0;
 	}
@@ -343,12 +99,6 @@ public:
 	{
 		(*this) = getRotated(q);
 	}
-
-	/// Return lerp(this, v1, t)
-	TVec3 lerp(const TVec3& v1, T t) const
-	{
-		return ((*this) * (1.0 - t)) + (v1 * t);
-	}
 	/// @}
 
 	/// @name Transformations
@@ -428,48 +178,31 @@ public:
 	{
 		(*this) = getTransformed(transform);
 	}
-
-	std::string toString() const
-	{
-		return std::to_string(x()) + " " + std::to_string(y()) + " " 
-			+ std::to_string(z());
-	}
-	/// @}
-
-private:
-	/// @name Data
-	/// @{
-	struct Vec
-	{
-		T x, y, z;
-	};
-
-	union
-	{
-		Vec vec;
-		Array<T, 3> arr;
-	};
 	/// @}
 };
 
+/// @memberof TVec3
 template<typename T>
 TVec3<T> operator+(const T f, const TVec3<T>& v)
 {
 	return v + f;
 }
 
+/// @memberof TVec3
 template<typename T>
 TVec3<T> operator-(const T f, const TVec3<T>& v)
 {
 	return TVec3<T>(f) - v;
 }
 
+/// @memberof TVec3
 template<typename T>
 TVec3<T> operator*(const T f, const TVec3<T>& v)
 {
 	return v * f;
 }
 
+/// @memberof TVec3
 template<typename T>
 TVec3<T> operator/(const T f, const TVec3<T>& v)
 {

+ 44 - 391
include/anki/math/Vec4.h

@@ -5,7 +5,7 @@
 
 namespace anki {
 
-/// @addtogroup Math
+/// @addtogroup math
 /// @{
 
 /// Template struct that gives the type of the TVec4 SIMD
@@ -33,7 +33,8 @@ struct TVec4Simd<F32>
 
 /// 4D vector. SIMD optimized
 template<typename T>
-ANKI_ATTRIBUTE_ALIGNED(class, 16) TVec4
+class alignas(16) TVec4: 
+	public TVec<T, 4, typename TVec4Simd<T>::Type, TVec4<T>>
 {
 	/// @name Friends
 	/// @{
@@ -48,305 +49,47 @@ ANKI_ATTRIBUTE_ALIGNED(class, 16) TVec4
 	/// @}
 
 public:
-	typedef typename TVec4Simd<T>::Type Simd;
+	using Base = TVec<T, 4, typename TVec4Simd<T>::Type, TVec4<T>>;
+	
+	using Base::x;
+	using Base::y;
+	using Base::z;
+	using Base::w;
+	using Base::operator*;
 
 	/// @name Constructors
 	/// @{
 	explicit TVec4()
+		: Base()
 	{}
 
-	explicit TVec4(const T x_, const T y_, const T z_, const T w_)
-	{
-		x() = x_;
-		y() = y_;
-		z() = z_;
-		w() = w_;
-	}
-
-	explicit TVec4(const T f)
-	{
-		arr[0] = arr[1] = arr[2] = arr[3] = f;
-	}
-
-	explicit TVec4(const T arr_[])
-	{
-		arr[0] = arr_[0];
-		arr[1] = arr_[1];
-		arr[2] = arr_[2];
-		arr[3] = arr_[3];
-	}
-
-	explicit TVec4(const TVec2<T>& v2, const T z_, const T w_)
-	{
-		x() = v2.x();
-		y() = v2.y();
-		z() = z_;
-		w() = w_;
-	}
-
-	explicit TVec4(const TVec2<T>& av2, const TVec2<T>& bv2)
-	{
-		x() = av2.x();
-		y() = av2.y();
-		z() = bv2.x();
-		w() = bv2.y();
-	}
-
-	explicit TVec4(const TVec3<T>& v3, const T w_)
-	{
-		x() = v3.x();
-		y() = v3.y();
-		z() = v3.z();
-		w() = w_;
-	}
-
 	TVec4(const TVec4& b)
-	{
-		x() = b.x();
-		y() = b.y();
-		z() = b.z();
-		w() = b.w();
-	}
-
-	explicit TVec4(const TQuat<T>& q)
-	{
-		x() = q.x();
-		y() = q.y();
-		z() = q.z();
-		w() = q.w();
-	}
-
-	explicit TVec4(const Simd& simd_)
-	{
-		simd = simd_;
-	}
-	/// @}
-
-	/// @name Accessors
-	/// @{
-	T& x()
-	{
-		return vec.x;
-	}
-
-	T x() const
-	{
-		return vec.x;
-	}
-
-	T& y()
-	{
-		return vec.y;
-	}
-
-	T y() const
-	{
-		return vec.y;
-	}
-
-	T& z()
-	{
-		return vec.z;
-	}
-
-	T z() const
-	{
-		return vec.z;
-	}
-
-	T& w()
-	{
-		return vec.w;
-	}
-
-	T w() const
-	{
-		return vec.w;
-	}
-
-	T& operator[](const U i)
-	{
-		return arr[i];
-	}
-
-	T operator[](const U i) const
-	{
-		return arr[i];
-	}
-
-	TVec2<T> xy() const
-	{
-		return TVec2<T>(x(), y());
-	}
-
-	TVec3<T> xyz() const
-	{
-		return TVec3<T>(x(), y(), z());
-	}
-
-	Simd& getSimd()
-	{
-		return simd;
-	}
-
-	const Simd& getSimd() const
-	{
-		return simd;
-	}
-	/// @}
-
-	/// @name Operators with same type
-	/// @{
-	TVec4& operator=(const TVec4& b)
-	{
-		x() = b.x();
-		y() = b.y();
-		z() = b.z();
-		w() = b.w();
-		return (*this);
-	}
-
-	TVec4 operator+(const TVec4& b) const
-	{
-		return TVec4(x() + b.x(), y() + b.y(), z() + b.z(), w() + b.w());
-	}
-
-	TVec4& operator+=(const TVec4& b)
-	{
-		x() += b.x();
-		y() += b.y();
-		z() += b.z();
-		w() += b.w();
-		return (*this);
-	}
-
-	TVec4 operator-(const TVec4& b) const
-	{
-		return TVec4(x() - b.x(), y() - b.y(), z() - b.z(), w() - b.w());
-	}
-
-	TVec4& operator-=(const TVec4& b)
-	{
-		x() -= b.x();
-		y() -= b.y();
-		z() -= b.z();
-		w() -= b.w();
-		return (*this);
-	}
-
-	TVec4 operator*(const TVec4& b) const
-	{
-		return TVec4(x() * b.x(), y() * b.y(), z() * b.z(), w() * b.w());
-	}
-
-	TVec4& operator*=(const TVec4& b)
-	{
-		x() *= b.x();
-		y() *= b.y();
-		z() *= b.z();
-		w() *= b.w();
-		return (*this);
-	}
-
-	TVec4 operator/(const TVec4& b) const
-	{
-		return TVec4(x() / b.x(), y() / b.y(), z() / b.z(), w() / b.w());
-	}
-
-	TVec4& operator/=(const TVec4& b)
-	{
-		x() /= b.x();
-		y() /= b.y();
-		z() /= b.z();
-		w() /= b.w();
-		return (*this);
-	}
-
-	TVec4 operator-() const
-	{
-		return TVec4(-x(), -y(), -z(), -w());
-	}
-
-	Bool operator==(const TVec4& b) const
-	{
-		TVec4 sub = (*this) - b;
-		return isZero<T>(sub.x()) 
-			&& isZero<T>(sub.y()) 
-			&& isZero<T>(sub.z()) 
-			&& isZero<T>(sub.w());
-	}
-
-	Bool operator!=(const TVec4& b) const
-	{
-		return !operator==(b);
-	}
-
-	Bool operator<(const TVec4& b) const
-	{
-		return x() < b.x() && y() < b.y() && z() < b.z() && w() < b.w();
-	}
-
-	Bool operator<=(const TVec4& b) const
-	{
-		return x() <= b.x() && y() <= b.y() && z() <= b.z() && w() <= b.w();
-	}
-
-	Bool operator>(const TVec4& b) const
-	{
-		return x() > b.x() && y() > b.y() && z() > b.z() && w() > b.w();
-	}
-
-	Bool operator>=(const TVec4& b) const
-	{
-		return x() >= b.x() && y() >= b.y() && z() >= b.z() && w() >= b.w();
-	}
-	/// @}
-
-	/// @name Operators with T
-	/// @{
-	TVec4 operator+(const T f) const
-	{
-		return (*this) + TVec4(f);
-	}
-
-	TVec4& operator+=(const T f)
-	{
-		(*this) += TVec4(f);
-		return (*this);
-	}
+		: Base(b)
+	{}
 
-	TVec4 operator-(const T f) const
-	{
-		return (*this) - TVec4(f);
-	}
+	explicit TVec4(const T x_, const T y_, const T z_, const T w_)
+		: Base(x_, y_, z_, w_)
+	{}
 
-	TVec4& operator-=(const T f)
-	{
-		(*this) -= TVec4(f);
-		return (*this);
-	}
+	explicit TVec4(const T f)
+		: Base(f)
+	{}
 
-	TVec4 operator*(const T f) const
-	{
-		return (*this) * TVec4(f);
-	}
+	explicit TVec4(const T arr[])
+		: Base(arr)
+	{}
 
-	TVec4& operator*=(const T f)
-	{
-		(*this) *= TVec4(f);
-		return (*this);
-	}
+	explicit TVec4(const typename Base::Simd& simd)
+		: Base(simd)
+	{}
 
-	TVec4 operator/(const T f) const
-	{
-		return (*this) / TVec4(f);
-	}
+	explicit TVec4(const TVec2<T>& v, const T z_, const T w_)
+		: Base(v.x(), v.y(), z_, w_)
+	{}
 
-	TVec4& operator/=(const T f)
-	{
-		(*this) /= TVec4(f);
-		return (*this);
-	}
+	explicit TVec4(const TVec3<T>& v, const T w_)
+		: Base(v.x(), v.y(), v.z(), w_)
+	{}
 	/// @}
 
 	/// @name Operators with other
@@ -362,53 +105,6 @@ public:
 			x() * m4(0, 3) + y() * m4(1, 3) + z() * m4(2, 3) + w() * m4(3, 3));
 	}
 	/// @}
-
-	/// @name Other
-	/// @{
-	T getLength() const
-	{
-		return sqrt<T>(dot(*this));
-	}
-
-	TVec4 getNormalized() const
-	{
-		return (*this) / getLength();
-	}
-
-	void normalize()
-	{
-		(*this) /= getLength();
-	}
-
-	T dot(const TVec4& b) const
-	{
-		return x() * b.x() + y() * b.y() + z() * b.z() + w() * b.w();
-	}
-
-	std::string toString() const
-	{
-		return std::to_string(x()) 
-			+ " " + std::to_string(y())
-			+ " " + std::to_string(z())
-			+ " " + std::to_string(w());
-	}
-	/// @}
-
-private:
-	/// @name Data
-	/// @{
-	struct Vec
-	{
-		T x, y, z, w;
-	};
-
-	union
-	{
-		Vec vec;	
-		Array<T, 4> arr;
-		Simd simd;
-	};
-	/// @}
 };
 
 #if ANKI_SIMD == ANKI_SIMD_SSE
@@ -428,87 +124,44 @@ template<>
 TVec4<F32>::TVec4(const TVec4<F32>& b);
 
 template<>
-TVec4<F32>& TVec4<F32>::operator=(const TVec4<F32>& b);
+TVec4<F32>& TVec4<F32>::Base::operator=(const TVec4<F32>& b);
 
 template<>
-TVec4<F32> TVec4<F32>::operator+(const TVec4<F32>& b) const;
+TVec4<F32> TVec4<F32>::Base::operator+(const TVec4<F32>& b) const;
 
 template<>
-TVec4<F32>& TVec4<F32>::operator+=(const TVec4<F32>& b);
+TVec4<F32>& TVec4<F32>::Base::operator+=(const TVec4<F32>& b);
 
 template<>
-TVec4<F32> TVec4<F32>::operator-(const TVec4<F32>& b) const;
+TVec4<F32> TVec4<F32>::Base::operator-(const TVec4<F32>& b) const;
 
 template<>
-TVec4<F32>& TVec4<F32>::operator-=(const TVec4<F32>& b);
+TVec4<F32>& TVec4<F32>::Base::operator-=(const TVec4<F32>& b);
 
 template<>
-TVec4<F32> TVec4<F32>::operator*(const TVec4<F32>& b) const;
+TVec4<F32> TVec4<F32>::Base::operator*(const TVec4<F32>& b) const;
 
 template<>
-TVec4<F32>& TVec4<F32>::operator*=(const TVec4<F32>& b);
+TVec4<F32>& TVec4<F32>::Base::operator*=(const TVec4<F32>& b);
 
 template<>
-TVec4<F32> TVec4<F32>::operator/(const TVec4<F32>& b) const;
+TVec4<F32> TVec4<F32>::Base::operator/(const TVec4<F32>& b) const;
 
 template<>
-TVec4<F32>& TVec4<F32>::operator/=(const TVec4<F32>& b);
+TVec4<F32>& TVec4<F32>::Base::operator/=(const TVec4<F32>& b);
 
 template<>
-F32 TVec4<F32>::dot(const TVec4<F32>& b) const;
+F32 TVec4<F32>::Base::dot(const TVec4<F32>& b) const;
 
 template<>
-TVec4<F32> TVec4<F32>::getNormalized() const;
+TVec4<F32> TVec4<F32>::Base::getNormalized() const;
 
 template<>
-void TVec4<F32>::normalize();
+void TVec4<F32>::Base::normalize();
 
 #elif ANKI_SIMD == ANKI_SIMD_NEON
 
-template<>
-TVec4<F32>::TVec4(F32 f);
-
-template<>
-TVec4<F32>::TVec4(const F32 arr_[]);
-
-template<>
-TVec4<F32>::TVec4(const TVec4<F32>& b);
-
-template<>
-TVec4<F32>& TVec4<F32>::operator=(const TVec4<F32>& b);
-
-template<>
-TVec4<F32> TVec4<F32>::operator+(const TVec4<F32>& b) const;
-
-template<>
-TVec4<F32>& TVec4<F32>::operator+=(const TVec4<F32>& b);
-
-template<>
-TVec4<F32> TVec4<F32>::operator-(const TVec4<F32>& b) const;
-
-template<>
-TVec4<F32>& TVec4<F32>::operator-=(const TVec4<F32>& b);
-
-template<>
-TVec4<F32> TVec4<F32>::operator*(const TVec4<F32>& b) const;
-
-template<>
-TVec4<F32>& TVec4<F32>::operator*=(const TVec4<F32>& b);
-
-template<>
-TVec4<F32> operator*(const F32 f) const;
-
-template<>
-TVec4<F32>& operator*=(const F32 f);
-
-template<>
-F32 TVec4<F32>::dot(const TVec4<F32>& b) const;
-
-template<>
-TVec4<F32> TVec4<F32>::getNormalized() const;
-
-template<>
-void TVec4<F32>::normalize();
+#	error "TODO"
 
 #endif
 

+ 44 - 164
include/anki/math/Vec4.inl.h

@@ -7,6 +7,7 @@ namespace anki {
 //==============================================================================
 
 //==============================================================================
+/// @memberof TVec4
 template<typename T>
 TVec4<T> operator+(const T f, const TVec4<T>& v4)
 {
@@ -14,6 +15,7 @@ TVec4<T> operator+(const T f, const TVec4<T>& v4)
 }
 
 //==============================================================================
+/// @memberof TVec4
 template<typename T>
 TVec4<T> operator-(const T f, const TVec4<T>& v4)
 {
@@ -21,6 +23,7 @@ TVec4<T> operator-(const T f, const TVec4<T>& v4)
 }
 
 //==============================================================================
+/// @memberof TVec4
 template<typename T>
 TVec4<T> operator*(const T f, const TVec4<T>& v4)
 {
@@ -28,6 +31,7 @@ TVec4<T> operator*(const T f, const TVec4<T>& v4)
 }
 
 //==============================================================================
+/// @memberof TVec4
 template<typename T>
 TVec4<T> operator/(const T f, const TVec4<T>& v4)
 {
@@ -48,28 +52,30 @@ TVec4<T> operator/(const T f, const TVec4<T>& v4)
 template<>
 inline TVec4<F32>::TVec4(F32 f)
 {
-	simd = _mm_set1_ps(f);
+	m_simd = _mm_set1_ps(f);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>::TVec4(const F32 arr_[])
+inline TVec4<F32>::TVec4(const F32 arr[])
 {
-	simd = _mm_load_ps(arr_);
+	m_simd = _mm_load_ps(arr);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>::TVec4(const F32 x_, const F32 y_, const F32 z_, const F32 w_)
+inline TVec4<F32>::TVec4(const F32 x_, const F32 y_, const F32 z_, 
+	const F32 w_)
 {
-	simd = _mm_set_ps(w_, z_, y_, x_);
+	m_simd = _mm_set_ps(w_, z_, y_, x_);
 }
 
 //==============================================================================
 template<>
 inline TVec4<F32>::TVec4(const TVec4<F32>& b)
+	: Base()
 {
-	simd = b.simd;
+	m_simd = b.m_simd;
 }
 
 //==============================================================================
@@ -78,70 +84,70 @@ inline TVec4<F32>::TVec4(const TVec4<F32>& b)
 
 //==============================================================================
 template<>
-inline TVec4<F32>& TVec4<F32>::operator=(const TVec4<F32>& b)
+inline TVec4<F32>& TVec4<F32>::Base::operator=(const TVec4<F32>& b)
 {
-	simd = b.simd;
-	return (*this);
+	m_simd = b.m_simd;
+	return static_cast<TVec4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32> TVec4<F32>::operator+(const TVec4<F32>& b) const
+inline TVec4<F32> TVec4<F32>::Base::operator+(const TVec4<F32>& b) const
 {
-	return TVec4<F32>(_mm_add_ps(simd, b.simd));
+	return TVec4<F32>(_mm_add_ps(m_simd, b.m_simd));
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>& TVec4<F32>::operator+=(const TVec4<F32>& b)
+inline TVec4<F32>& TVec4<F32>::Base::operator+=(const TVec4<F32>& b)
 {
-	simd = _mm_add_ps(simd, b.simd);
-	return (*this);
+	m_simd = _mm_add_ps(m_simd, b.m_simd);
+	return static_cast<TVec4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32> TVec4<F32>::operator-(const TVec4<F32>& b) const
+inline TVec4<F32> TVec4<F32>::Base::operator-(const TVec4<F32>& b) const
 {
-	return TVec4<F32>(_mm_sub_ps(simd, b.simd));
+	return TVec4<F32>(_mm_sub_ps(m_simd, b.m_simd));
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>& TVec4<F32>::operator-=(const TVec4<F32>& b)
+inline TVec4<F32>& TVec4<F32>::Base::operator-=(const TVec4<F32>& b)
 {
-	simd = _mm_sub_ps(simd, b.simd);
-	return (*this);
+	m_simd = _mm_sub_ps(m_simd, b.m_simd);
+	return static_cast<TVec4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32> TVec4<F32>::operator*(const TVec4<F32>& b) const
+inline TVec4<F32> TVec4<F32>::Base::operator*(const TVec4<F32>& b) const
 {
-	return TVec4<F32>(_mm_mul_ps(simd, b.simd));
+	return TVec4<F32>(_mm_mul_ps(m_simd, b.m_simd));
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>& TVec4<F32>::operator*=(const TVec4<F32>& b)
+inline TVec4<F32>& TVec4<F32>::Base::operator*=(const TVec4<F32>& b)
 {
-	simd = _mm_mul_ps(simd, b.simd);
-	return (*this);
+	m_simd = _mm_mul_ps(m_simd, b.m_simd);
+	return static_cast<TVec4<F32>&>(*this);
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32> TVec4<F32>::operator/(const TVec4<F32>& b) const
+inline TVec4<F32> TVec4<F32>::Base::operator/(const TVec4<F32>& b) const
 {
-	return TVec4<F32>(_mm_div_ps(simd, b.simd));
+	return TVec4<F32>(_mm_div_ps(m_simd, b.m_simd));
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32>& TVec4<F32>::operator/=(const TVec4<F32>& b)
+inline TVec4<F32>& TVec4<F32>::Base::operator/=(const TVec4<F32>& b)
 {
-	simd = _mm_div_ps(simd, b.simd);
-	return (*this);
+	m_simd = _mm_div_ps(m_simd, b.m_simd);
+	return static_cast<TVec4<F32>&>(*this);
 }
 
 //==============================================================================
@@ -150,27 +156,27 @@ inline TVec4<F32>& TVec4<F32>::operator/=(const TVec4<F32>& b)
 
 //==============================================================================
 template<>
-inline F32 TVec4<F32>::dot(const TVec4<F32>& b) const
+inline F32 TVec4<F32>::Base::dot(const TVec4<F32>& b) const
 {
 	F32 o;
-	_mm_store_ss(&o, _mm_dp_ps(simd, b.simd, 0xF1));
+	_mm_store_ss(&o, _mm_dp_ps(m_simd, b.m_simd, 0xF1));
 	return o;
 }
 
 //==============================================================================
 template<>
-inline TVec4<F32> TVec4<F32>::getNormalized() const
+inline TVec4<F32> TVec4<F32>::Base::getNormalized() const
 {
-	__m128 inverse_norm = _mm_rsqrt_ps(_mm_dp_ps(simd, simd, 0xFF));
-	return TVec4<F32>(_mm_mul_ps(simd, inverse_norm));
+	__m128 inverse_norm = _mm_rsqrt_ps(_mm_dp_ps(m_simd, m_simd, 0xFF));
+	return TVec4<F32>(_mm_mul_ps(m_simd, inverse_norm));
 }
 
 //==============================================================================
 template<>
-inline void TVec4<F32>::normalize()
+inline void TVec4<F32>::Base::normalize()
 {
-	__m128 inverseNorm = _mm_rsqrt_ps(_mm_dp_ps(simd, simd, 0xFF));
-	simd = _mm_mul_ps(simd, inverseNorm);
+	__m128 inverseNorm = _mm_rsqrt_ps(_mm_dp_ps(m_simd, m_simd, 0xFF));
+	m_simd = _mm_mul_ps(m_simd, inverseNorm);
 }
 
 #elif ANKI_SIMD == ANKI_SIMD_NEON
@@ -179,133 +185,7 @@ inline void TVec4<F32>::normalize()
 // NEON specializations                                                        =
 //==============================================================================
 
-//==============================================================================
-// Constructors                                                                =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline TVec4<F32>::TVec4(F32 f)
-{
-	simd = vdupq_n_f32(f);
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>::TVec4(const F32 arr_[])
-{
-	simd = vld1q_f32(arr_);
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>::TVec4(const TVec4<F32>& b)
-{
-	simd = b.simd;
-}
-
-//==============================================================================
-// Operators with same                                                         =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline TVec4<F32>& TVec4<F32>::operator=(const TVec4<F32>& b)
-{
-	simd = b.simd;
-	return (*this);
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32> TVec4<F32>::operator+(const TVec4<F32>& b) const
-{
-	return TVec4<F32>(vaddq_f32(simd, b.simd));
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>& TVec4<F32>::operator+=(const TVec4<F32>& b)
-{
-	simd = vaddq_f32(simd, b.simd);
-	return (*this);
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32> TVec4<F32>::operator-(const TVec4<F32>& b) const
-{
-	return TVec4<F32>(vsubq_f32(simd, b.simd));
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>& TVec4<F32>::operator-=(const TVec4<F32>& b)
-{
-	simd = vsubq_f32(simd, b.simd);
-	return (*this);
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32> TVec4<F32>::operator*(const TVec4<F32>& b) const
-{
-	return TVec4<F32>(vmulq_f32(simd, b.simd));
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>& TVec4<F32>::operator*=(const TVec4<F32>& b)
-{
-	simd = vmulq_f32(simd, b.simd);
-	return (*this);
-}
-
-//==============================================================================
-// Operators with F32                                                          =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline TVec4<F32> operator*(const F32 f) const
-{
-	return TVec4<F32>(vmulq_n_f32(simd, f));
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32>& operator*=(const F32 f)
-{
-	simd = vmulq_n_f32(simd, f);
-	return *this;
-}
-
-//==============================================================================
-// Other                                                                       =
-//==============================================================================
-
-//==============================================================================
-template<>
-inline F32 TVec4<F32>::dot(const TVec4<F32>& b) const
-{
-	F32 o;
-	// XXX
-	return o;
-}
-
-//==============================================================================
-template<>
-inline TVec4<F32> TVec4<F32>::getNormalized() const
-{
-	// XXX
-}
-
-//==============================================================================
-template<>
-inline void TVec4<F32>::normalize()
-{
-	// XXX
-}
+#	error "TODO"
 
 #endif
 

+ 0 - 14
include/anki/misc/ConfigSet.h

@@ -25,20 +25,6 @@ public:
 		}
 	}
 
-	/// Find an option and return it's value
-	F64& get(const char* name)
-	{
-		std::unordered_map<std::string, F64>::iterator it = map.find(name);
-		if(it != map.end())
-		{
-			return it->second;
-		}
-		else
-		{
-			throw ANKI_EXCEPTION("Option not found");
-		}
-	}
-
 	// Set an option
 	void set(const char* name, F64 value)
 	{

+ 12 - 12
include/anki/physics/Ragdoll.h

@@ -13,12 +13,12 @@ class Ragdoll
 			BP_SPINE,
 			BP_HEAD,
 
-			BP_LEFT_UPPER_ARM,
-			BP_LEFT_LOWER_ARM,
-			BP_LEFT_PALM,
-			BP_LEFT_UPPER_LEG,
-			BP_LEFT_LOWER_LEG,
-			BP_LEFT_FOOT,
+			BP_LEFrustumType::UPPER_ARM,
+			BP_LEFrustumType::LOWER_ARM,
+			BP_LEFrustumType::PALM,
+			BP_LEFrustumType::UPPER_LEG,
+			BP_LEFrustumType::LOWER_LEG,
+			BP_LEFrustumType::FOOT,
 
 			BP_RIGHT_UPPER_ARM,
 			BP_RIGHT_LOWER_ARM,
@@ -35,12 +35,12 @@ class Ragdoll
 			JOINT_PELVIS_SPINE,
 			JOINT_SPINE_HEAD,
 
-			JOINT_LEFT_SHOULDER,
-			JOINT_LEFT_ELBOW,
-			JOINT_LEFT_WRIST,
-			JOINT_LEFT_HIP,
-			JOINT_LEFT_KNEE,
-			JOINT_LEFT_ANKLE,
+			JOINT_LEFrustumType::SHOULDER,
+			JOINT_LEFrustumType::ELBOW,
+			JOINT_LEFrustumType::WRIST,
+			JOINT_LEFrustumType::HIP,
+			JOINT_LEFrustumType::KNEE,
+			JOINT_LEFrustumType::ANKLE,
 
 			JOINT_RIGHT_SHOULDER,
 			JOINT_RIGHT_ELBOW,

+ 13 - 9
include/anki/renderer/Bl.h

@@ -4,12 +4,12 @@
 #include "anki/renderer/RenderingPass.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/Resource.h"
-#include "anki/resource/ShaderProgramResource.h"
-#include "anki/gl/Fbo.h"
+#include "anki/resource/ProgramResource.h"
+#include "anki/Gl.h"
 
 namespace anki {
 
-class ShaderProgramResource;
+class ProgramResource;
 
 /// Blurring rendering pass
 class Bl: public SwitchableRenderingPass
@@ -22,17 +22,18 @@ public:
 	void init(const RendererInitializer& initializer);
 	void run();
 
+#if 0
 	/// @name Accessors
 	/// @{
-	float getSideBlurFactor() const
+	F32 getSideBlurFactor() const
 	{
 		return sideBlurFactor;
 	}
-	float& getSideBlurFactor()
+	F32& getSideBlurFactor()
 	{
 		return sideBlurFactor;
 	}
-	void setSideBlurFactor(const float x)
+	void setSideBlurFactor(const F32 x)
 	{
 		sideBlurFactor = x;
 	}
@@ -50,15 +51,17 @@ public:
 		blurringIterationsNum = x;
 	}
 	/// @}
+#endif
 
 private:
+#if 0
 	Fbo hBlurFbo; ///< Fbo that writes to blurFai
 	Fbo vBlurFbo; ///< Fbo that writes to postPassSProg
 	Fbo sideBlurFbo;
 
-	ShaderProgramResourcePointer hBlurSProg;
-	ShaderProgramResourcePointer vBlurSProg;
-	ShaderProgramResourcePointer sideBlurSProg;
+	ProgramResourcePointer hBlurSProg;
+	ProgramResourcePointer vBlurSProg;
+	ProgramResourcePointer sideBlurSProg;
 
 	Texture blurFai; ///< Temp FAI for blurring
 	TextureResourcePointer sideBlurMap;
@@ -68,6 +71,7 @@ private:
 
 	void runBlur();
 	void runSideBlur();
+#endif
 };
 
 } // end namespace

+ 7 - 3
include/anki/renderer/Bs.h

@@ -2,12 +2,14 @@
 #define ANKI_RENDERER_BS_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
-#include "anki/gl/Texture.h"
+#include "anki/Gl.h"
 #include "anki/resource/Resource.h"
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Blending stage. The objects that blend must be handled differently
 class Bs: public RenderingPass
 {
@@ -19,9 +21,11 @@ public:
 	~Bs();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 18 - 13
include/anki/renderer/Dbg.h

@@ -2,13 +2,16 @@
 #define ANKI_RENDERER_DBG_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
+#include "anki/Gl.h"
 #include "anki/renderer/DebugDrawer.h"
 #include "anki/util/Bitset.h"
 #include <memory>
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Debugging stage
 class Dbg: public SwitchableRenderingPass, public Bitset<U8>
 {
@@ -25,45 +28,47 @@ public:
 			| DF_PHYSICS
 	};
 
-	Dbg(Renderer* r_)
-		: SwitchableRenderingPass(r_)
+	Dbg(Renderer* r)
+		: SwitchableRenderingPass(r)
 	{}
 	
 	~Dbg();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 	Bool getDepthTestEnabled() const
 	{
-		return depthTest;
+		return m_depthTest;
 	}
 	void setDepthTestEnabled(Bool enable)
 	{
-		depthTest = enable;
+		m_depthTest = enable;
 	}
 	void switchDepthTestEnabled()
 	{
-		depthTest = !depthTest;
+		m_depthTest = !m_depthTest;
 	}
 
 	DebugDrawer& getDebugDrawer()
 	{
-		return *drawer;
+		return *m_drawer;
 	}
 	const DebugDrawer& getDebugDrawer() const
 	{
-		return *drawer;
+		return *m_drawer;
 	}
 
 private:
-	Fbo fbo;
-	std::unique_ptr<DebugDrawer> drawer;
+	GlFramebufferHandle m_fb;
+	std::unique_ptr<DebugDrawer> m_drawer;
 	// Have it as ptr because the constructor calls opengl
-	std::unique_ptr<SceneDebugDrawer> sceneDrawer;
-	Bool depthTest = true;
+	std::unique_ptr<SceneDebugDrawer> m_sceneDrawer;
+	Bool8 m_depthTest = true;
 };
 
+/// @}
+
 } // end namespace
 
 #endif

+ 46 - 29
include/anki/renderer/DebugDrawer.h

@@ -2,8 +2,7 @@
 #define ANKI_RENDERER_DEBUG_DRAWER_H
 
 #include "anki/Math.h"
-#include "anki/gl/GlBuffer.h"
-#include "anki/gl/Vao.h"
+#include "anki/Gl.h"
 #include "anki/resource/Resource.h"
 #include "anki/collision/CollisionShape.h"
 #include "anki/scene/Forward.h"
@@ -13,6 +12,9 @@
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Draws simple primitives
 class DebugDrawer
 {
@@ -25,6 +27,16 @@ public:
 	void drawCube(F32 size = 1.0);
 	void drawLine(const Vec3& from, const Vec3& to, const Vec4& color);
 
+	void prepareDraw(GlJobChainHandle& jobs)
+	{
+		m_jobs = jobs;
+	}
+
+	void finishDraw()
+	{
+		m_jobs = GlJobChainHandle(); // Release job chain
+	}
+
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
 	/// @{
 	void begin(); ///< Initiates the draw
@@ -33,12 +45,12 @@ public:
 	/// Something like glColor
 	void setColor(const Vec3& col)
 	{
-		crntCol = col;
+		m_crntCol = col;
 	}
 	/// Something like glColor
 	void setColor(const Vec4& col)
 	{
-		crntCol = Vec3(col);
+		m_crntCol = col.xyz();
 	}
 	void setModelMatrix(const Mat4& m);
 	void setViewProjectionMatrix(const Mat4& m);
@@ -50,27 +62,30 @@ public:
 private:
 	struct Vertex
 	{
-		Vec4 positionAndColor;
-		Mat4 matrix;
+		Vec4 m_positionAndColor;
+		Mat4 m_matrix;
 	};
 
-	ShaderProgramResourcePointer prog;
+	ProgramResourcePointer m_frag;
+	ProgramResourcePointer m_vert;
+	GlProgramPipelineHandle m_ppline;
+	GlJobChainHandle m_jobs;
+
 	static const U MAX_POINTS_PER_DRAW = 256;
-	Mat4 mMat;
-	Mat4 vpMat;
-	Mat4 mvpMat; ///< Optimization
-	U32 vertexPointer;
-	Vec3 crntCol;
+	Mat4 m_mMat;
+	Mat4 m_vpMat;
+	Mat4 m_mvpMat; ///< Optimization
+	U32 m_vertexPointer;
+	Vec3 m_crntCol;
 
-	Array<Vertex, MAX_POINTS_PER_DRAW> clientVerts;
+	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientVerts;
 
-	GlBuffer vbo;
-	Vao vao;
+	GlBufferHandle m_vertBuff;
 
 	/// This is a container of some precalculated spheres. Its a map that
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// pairs)
-	std::unordered_map<U32, Vector<Vec3>> complexityToPreCalculatedSphere;
+	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
 };
 
 /// Contains methods to render the collision shapes
@@ -78,8 +93,8 @@ class CollisionDebugDrawer: public CollisionShape::ConstVisitor
 {
 public:
 	/// Constructor
-	CollisionDebugDrawer(DebugDrawer* dbg_)
-		: dbg(dbg_)
+	CollisionDebugDrawer(DebugDrawer* dbg)
+		: m_dbg(dbg)
 	{}
 
 	void visit(const LineSegment&)
@@ -104,7 +119,7 @@ public:
 	void visit(const Aabb&);
 
 private:
-	DebugDrawer* dbg; ///< The debug drawer
+	DebugDrawer* m_dbg; ///< The debug drawer
 };
 
 /// An implementation of btIDebugDraw used for debugging Bullet. See Bullet
@@ -112,8 +127,8 @@ private:
 class PhysicsDebugDrawer: public btIDebugDraw
 {
 public:
-	PhysicsDebugDrawer(DebugDrawer* dbg_)
-		: dbg(dbg_)
+	PhysicsDebugDrawer(DebugDrawer* dbg)
+		: m_dbg(dbg)
 	{}
 
 	void drawLine(const btVector3& from, const btVector3& to,
@@ -134,18 +149,18 @@ public:
 
 	void reportErrorWarning(const char* warningString);
 	void draw3dText(const btVector3& location, const char* textString);
-	void setDebugMode(int debugMode_)
+	void setDebugMode(int debugMode)
 	{
-		debugMode = debugMode_;
+		m_debugMode = debugMode;
 	}
 	int getDebugMode() const
 	{
-		return debugMode;
+		return m_debugMode;
 	}
 
 private:
-	int debugMode;
-	DebugDrawer* dbg;
+	int m_debugMode;
+	DebugDrawer* m_dbg;
 };
 
 // Forward
@@ -156,7 +171,7 @@ class SceneDebugDrawer
 {
 public:
 	SceneDebugDrawer(DebugDrawer* d)
-		: dbg(d)
+		: m_dbg(d)
 	{}
 
 	~SceneDebugDrawer()
@@ -168,11 +183,11 @@ public:
 
 	void setViewProjectionMatrix(const Mat4& m)
 	{
-		dbg->setViewProjectionMatrix(m);
+		m_dbg->setViewProjectionMatrix(m);
 	}
 
 private:
-	DebugDrawer* dbg;
+	DebugDrawer* m_dbg;
 
 	void draw(FrustumComponent& fr) const;
 
@@ -181,6 +196,8 @@ private:
 	void drawPath(const Path& path) const;
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 8 - 3
include/anki/renderer/Deformer.h

@@ -5,10 +5,13 @@
 
 namespace anki {
 
-class ShaderProgramResource;
+class ProgramResource;
 class SkinPatchNode;
 class SkinNode;
 
+/// @addtogroup renderer
+/// @{
+
 /// SkinPatchNode deformer
 ///
 /// It gets a SkinPatchNode and using transform feedback it deforms its vertex 
@@ -26,14 +29,16 @@ public:
 
 private:
 	/// Shader program that deforms all attribs
-	ShaderProgramResourcePointer tfHwSkinningAllSProg;
+	ProgramResourcePointer tfHwSkinningAllSProg;
 
 	/// Shader program that deforms only the position attribute
-	ShaderProgramResourcePointer tfHwSkinningPosSProg;
+	ProgramResourcePointer tfHwSkinningPosSProg;
 
 	void init();
 };
 
+/// @}
+
 } // end namespace
 
 #endif

+ 42 - 23
include/anki/renderer/Drawer.h

@@ -2,52 +2,71 @@
 #define ANKI_RENDERER_DRAWER_H
 
 #include "anki/util/StdTypes.h"
-#include "anki/resource/PassLodKey.h"
+#include "anki/util/Ptr.h"
+#include "anki/resource/RenderingKey.h"
 #include "anki/scene/Forward.h"
+#include "anki/Gl.h"
 
 namespace anki {
 
+// Forward
 class Renderer;
-class ShaderProgram;
-struct Drawcall;
+
+/// @addtogroup renderer
+/// @{
+
+/// The rendering stage
+enum class RenderingStage: U8
+{
+	MATERIAL,
+	BLEND
+};
 
 /// It includes all the functions to render a Renderable
 class RenderableDrawer
 {
+	friend class SetupRenderableVariableVisitor;
+
 public:
-	enum RenderingStage
-	{
-		RS_MATERIAL,
-		RS_BLEND
-	};
+	static const U32 MAX_UNIFORM_BUFFER_SIZE = 1024 * 1024 * 1;
 
 	/// The one and only constructor
-	RenderableDrawer(Renderer* r_)
-		: r(r_)
-	{}
+	RenderableDrawer(Renderer* r);
 
-	void prepareDraw()
-	{}
+	void prepareDraw(RenderingStage stage, Pass pass, GlJobChainHandle& jobs);
 
 	void render(
 		SceneNode& frsn,
-		RenderingStage stage, 
-		Pass pass,
 		VisibleNode& visible);
 
+	void finishDraw();
+
 private:
-	Renderer* r;
+	Renderer* m_r;
+	GlBufferHandle m_uniformBuff;
+
+	/// @name State
+	/// @{
+	GlJobChainHandle m_jobs;
+	U8* m_uniformPtr;
+
+	/// Used to calc if the uni buffer is big enough. Zero it per swap buffers
+	U32 m_uniformsUsedSize; 
+	U32 m_uniformsUsedSizeFrame;
 
-	void setupShaderProg(
-		const PassLodKey& key,
-		const FrustumComponent& fr,
-		const ShaderProgram& prog,
+	RenderingStage m_stage;
+	Pass m_pass;
+	/// @}
+
+	void setupUniforms(
+		VisibleNode& visibleNode, 
 		RenderComponent& renderable,
-		VisibleNode& visible,
-		F32 flod,
-		Drawcall* dc);
+		FrustumComponent& fr,
+		F32 flod);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 8 - 3
include/anki/renderer/Ez.h

@@ -2,10 +2,13 @@
 #define ANKI_RENDERER_EZ_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
+#include "anki/Gl.h"
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Material stage EarlyZ pass
 class Ez: public OptionalRenderingPass
 {
@@ -15,12 +18,14 @@ public:
 	{}
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 private:
-	U maxObjectsToDraw;
+	U32 m_maxObjectsToDraw;
 };
 
+/// @}
+
 } // end namespace anki
 
 

+ 41 - 28
include/anki/renderer/Hdr.h

@@ -2,10 +2,9 @@
 #define ANKI_RENDERER_HDR_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
-#include "anki/gl/GlBuffer.h"
+#include "anki/Gl.h"
 #include "anki/resource/TextureResource.h"
-#include "anki/resource/ShaderProgramResource.h"
+#include "anki/resource/ProgramResource.h"
 #include "anki/resource/Resource.h"
 #include "anki/core/Timestamp.h"
 
@@ -13,68 +12,82 @@ namespace anki {
 
 class ShaderProgram;
 
+/// @addtogroup renderer
+/// @{
+
 /// High dynamic range lighting pass
 class Hdr: public SwitchableRenderingPass
 {
 public:
-	Hdr(Renderer* r_)
-		: SwitchableRenderingPass(r_)
+	Hdr(Renderer* r)
+		: SwitchableRenderingPass(r)
 	{}
 
 	~Hdr();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 	/// @name Accessors
 	/// @{
 	F32 getExposure() const
 	{
-		return exposure;
+		return m_exposure;
 	}
 	void setExposure(const F32 x)
 	{
-		exposure = x;
-		parameterUpdateTimestamp = getGlobTimestamp();
+		m_exposure = x;
+		m_parameterUpdateTimestamp = getGlobTimestamp();
 	}
 
 	U32 getBlurringIterationsCount() const
 	{
-		return blurringIterationsCount;
+		return m_blurringIterationsCount;
 	}
 	void setBlurringIterationsCount(const U32 x)
 	{
-		blurringIterationsCount = x;
+		m_blurringIterationsCount = x;
 	}
 
-	Texture& getFai()
+	GlTextureHandle& getRt()
 	{
-		return vblurFai;
+		return m_vblurRt;
 	}
 	/// @}
 
 private:
-	U32 width, height;
-	F32 exposure = 4.0; ///< How bright is the HDR
-	U32 blurringIterationsCount = 2; ///< The blurring iterations
-	F32 blurringDist = 1.0; ///< Distance in blurring
-	Fbo hblurFbo;
-	Fbo vblurFbo;
-	ShaderProgramResourcePointer toneSProg;
-	ShaderProgramResourcePointer hblurSProg;
-	ShaderProgramResourcePointer vblurSProg;
-	Texture hblurFai; ///< pass0Fai with the horizontal blur FAI
-	Texture vblurFai; ///< The final FAI
+	U32 m_width, m_height;
+	F32 m_exposure = 4.0; ///< How bright is the HDR
+	U32 m_blurringIterationsCount = 2; ///< The blurring iterations
+	F32 m_blurringDist = 1.0; ///< Distance in blurring
+	
+	GlFramebufferHandle m_hblurFb;
+	GlFramebufferHandle m_vblurFb;
+
+	ProgramResourcePointer m_toneFrag;
+	ProgramResourcePointer m_hblurFrag;
+	ProgramResourcePointer m_vblurFrag;
+
+	GlProgramPipelineHandle m_tonePpline;
+	GlProgramPipelineHandle m_hblurPpline;
+	GlProgramPipelineHandle m_vblurPpline;
+
+	GlTextureHandle m_hblurRt; ///< pass0Fai with the horizontal blur FAI
+	GlTextureHandle m_vblurRt; ///< The final FAI
 	/// When a parameter changed by the setters
-	Timestamp parameterUpdateTimestamp = getGlobTimestamp();
+	Timestamp m_parameterUpdateTimestamp = getGlobTimestamp();
 	/// When the commonUbo got updated
-	Timestamp commonUboUpdateTimestamp = getGlobTimestamp();
-	GlBuffer commonUbo;
+	Timestamp m_commonUboUpdateTimestamp = getGlobTimestamp();
+	GlBufferHandle m_commonBuff;
 
-	void initFbo(Fbo& fbo, Texture& fai);
+	void initFb(GlFramebufferHandle& fb, GlTextureHandle& rt);
 	void initInternal(const RendererInitializer& initializer);
+
+	void updateDefaultBlock(GlJobChainHandle& jobs);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 58 - 51
include/anki/renderer/Is.h

@@ -4,8 +4,8 @@
 #include "anki/renderer/RenderingPass.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/Resource.h"
-#include "anki/resource/ShaderProgramResource.h"
-#include "anki/gl/Gl.h"
+#include "anki/resource/ProgramResource.h"
+#include "anki/Gl.h"
 #include "anki/Math.h"
 #include "anki/renderer/Sm.h"
 #include "anki/util/StdTypes.h"
@@ -20,121 +20,128 @@ class PerspectiveCamera;
 class PointLight;
 class SpotLight;
 
+/// @addtogroup renderer
+/// @{
+
 /// Illumination stage
 class Is: private RenderingPass
 {
-	friend struct WriteLightsJob;
+	friend class WriteLightsJob;
 
 public:
 	Is(Renderer* r);
 	~Is();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 	/// @name Accessors
 	/// @{
-	const Texture& getFai() const
+	const GlTextureHandle& getRt() const
 	{
-		return fai;
+		return m_rt;
 	}
 
-	Texture& getFai()
+	GlTextureHandle& getRt()
 	{
-		return fai;
+		return m_rt;
 	}
 	/// @}
 
 private:
-	static const U COMMON_UNIFORMS_BLOCK_BINDING = 0;
-	static const U POINT_LIGHTS_BLOCK_BINDING = 1;
-	static const U SPOT_LIGHTS_BLOCK_BINDING = 2;
-	static const U SPOT_TEX_LIGHTS_BLOCK_BINDING = 3;
-	static const U TILES_BLOCK_BINDING = 4;
-	static const U TILES_POINT_LIGHT_INDICES_BLOCK_BINDING = 5;
-	static const U TILES_SPOT_LIGHT_INDICES_BLOCK_BINDING = 6;
+	enum
+	{
+		COMMON_UNIFORMS_BLOCK_BINDING = 0,
+		POINT_LIGHTS_BLOCK_BINDING = 1,
+		SPOT_LIGHTS_BLOCK_BINDING = 2,
+		SPOT_TEX_LIGHTS_BLOCK_BINDING = 3,
+		TILES_BLOCK_BINDING = 4
+	};
+
+	enum
+	{
+		MS_RT0_TEX_UNIT = 0,
+		MS_RT1_TEX_UNIT = 1,
+		MS_DEPTH_RT_TEX_UNIT = 2,
+		SM_ARRAY_TEX_UNIT = 3
+	};
 
-	/// The IS FAI
-	Texture fai;
+	/// The IS render target
+	GlTextureHandle m_rt;
 
 	/// The IS FBO
-	Fbo fbo;
+	GlFramebufferHandle m_fb;
 
 	/// @name GPU buffers
 	/// @{
 
-	PtrSize uboAlignment = MAX_PTR_SIZE; ///< Cache the value here
-
 	/// Contains common data for all shader programs
-	GlBuffer commonUbo;
+	GlBufferHandle m_commonBuff;
 
 	/// Track the updates of commonUbo
-	Timestamp commonUboUpdateTimestamp = getGlobTimestamp();
+	Timestamp m_commonBuffUpdateTimestamp = getGlobTimestamp();
 
 	/// Contains all the lights
-	GlBuffer lightsUbo;
+	GlBufferHandle m_lightsBuff;
 
 	/// Contains the number of lights per tile
-	GlBuffer tilesBuffer;
-
-	GlBuffer pointLightIndicesBuffer;
-	GlBuffer spotLightIndicesBuffer;
+	GlBufferHandle m_tilesBuff;
 	/// @}
 
 	// Light shaders
-	ShaderProgramResourcePointer lightPassProg;
-	ShaderProgramResourcePointer rejectProg;
+	ProgramResourcePointer m_lightVert;
+	ProgramResourcePointer m_lightFrag;
+	GlProgramPipelineHandle m_lightPpline;
 
 	/// Shadow mapping
-	Sm sm;
+	Sm m_sm;
 
 	/// Opt because many ask for it
-	Camera* cam;
+	Camera* m_cam;
 
 	/// If enabled the ground emmits a light
-	Bool groundLightEnabled;
+	Bool8 m_groundLightEnabled;
 	/// Keep the prev light dir to avoid uniform block updates
-	Vec3 prevGroundLightDir = Vec3(0.0);
+	Vec3 m_prevGroundLightDir = Vec3(0.0);
 
 	/// @name For drawing a quad into the active framebuffer
 	/// @{
-	GlBuffer quadPositionsVbo; ///< The VBO for quad positions
-	Vao quadVao; ///< This VAO is used everywhere except material stage
+	GlBufferHandle m_quadPositionsVertBuff;
 	/// @}
 
 	/// @name Limits
 	/// @{
-	U16 maxPointLights;
-	U8 maxSpotLights;
-	U8 maxSpotTexLights;
+	U16 m_maxPointLights;
+	U8 m_maxSpotLights;
+	U8 m_maxSpotTexLights;
 
-	U8 maxPointLightsPerTile;
-	U8 maxSpotLightsPerTile;
-	U8 maxSpotTexLightsPerTile;
+	U8 m_maxPointLightsPerTile;
+	U8 m_maxSpotLightsPerTile;
+	U8 m_maxSpotTexLightsPerTile;
 	/// @}
 
+	U32 m_tileSize; ///< Cache the value here
+
 	/// Called by init
 	void initInternal(const RendererInitializer& initializer);
 
 	/// Do the actual pass
-	void lightPass();
+	void lightPass(GlJobChainHandle& jobs);
 
 	/// Prepare GL for rendering
-	void setState();
+	void setState(GlJobChainHandle& jobs);
 
 	/// Calculate the size of the lights UBO
-	PtrSize calcLightsUboSize() const;
+	PtrSize calcLightsBufferSize() const;
 
-	/// Calculate the size of the indices of point lights
-	PtrSize calcPointLightIndicesBufferSize() const;
+	/// Calculate the size of the tile
+	PtrSize calcTileSize() const;
 
-	/// Calculate the size of the indices of spot lights
-	PtrSize calcSpotLightIndicesBufferSize() const;
-
-	/// Setup the binding of the block and do some sanity checks on the size
-	void blockSetupAndSanityCheck(const char* name, U binding, PtrSize size);
+	void updateCommonBlock(GlJobChainHandle& jobs);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 32 - 19
include/anki/renderer/Lf.h

@@ -2,50 +2,63 @@
 #define ANKI_RENDERER_LF_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Gl.h"
+#include "anki/Gl.h"
 #include "anki/resource/Resource.h"
-#include "anki/resource/ShaderProgramResource.h"
+#include "anki/resource/ProgramResource.h"
 #include "anki/resource/TextureResource.h"
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Lens flare rendering pass
 class Lf: public OptionalRenderingPass
 {
 	friend class MainRenderer;
 
 public:
-	Lf(Renderer* r_)
-		: OptionalRenderingPass(r_)
+	Lf(Renderer* r)
+		: OptionalRenderingPass(r)
 	{}
 
 	~Lf();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
-	const Texture& getFai() const
+	const GlTextureHandle& getRt() const
+	{
+		return m_rt;
+	}
+	GlTextureHandle& getRt()
 	{
-		return fai;
+		return m_rt;
 	}
 
 private:
-	/// Pseudo lens flare program
-	ShaderProgramResourcePointer pseudoProg;
-	/// Real lens flare program
-	ShaderProgramResourcePointer realProg;
-	Texture fai;
-	Fbo fbo;
-	TextureResourcePointer lensDirtTex;
-	U8 maxFlaresPerLight;
-	U8 maxLightsWithFlares;
-	GlBuffer flareDataUbo;
-	const ShaderProgramUniformBlock* ublock;
-	
+	// Pseudo flares
+	ProgramResourcePointer m_pseudoFrag;
+	GlProgramPipelineHandle m_pseudoPpline;
 
+	// Sprite billboards
+	ProgramResourcePointer m_realVert; 
+	ProgramResourcePointer m_realFrag;
+	GlProgramPipelineHandle m_realPpline;
+
+	GlTextureHandle m_rt;
+	GlFramebufferHandle m_fb;
+
+	TextureResourcePointer m_lensDirtTex;
+	U8 m_maxFlaresPerLight;
+	U8 m_maxLightsWithFlares;
+	GlBufferHandle m_flareDataBuff;
+	
 	void initInternal(const RendererInitializer& initializer);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 10 - 2
include/anki/renderer/MainRenderer.h

@@ -7,6 +7,9 @@
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Main onscreen renderer
 class MainRenderer: public Renderer
 {
@@ -28,8 +31,11 @@ public:
 	void takeScreenshot(const char* filename);
 
 private:
-	std::unique_ptr<Deformer> deformer;
-	ShaderProgramResourcePointer blitProg;
+	std::unique_ptr<Deformer> m_deformer;
+	ProgramResourcePointer m_blitFrag;
+	GlProgramPipelineHandle m_blitPpline;
+
+	GlJobChainInitHints m_jobsInitHints; ///< Optimize job chain
 
 	void takeScreenshotTga(const char* filename);
 	void initGl();
@@ -37,6 +43,8 @@ private:
 
 typedef Singleton<MainRenderer> MainRendererSingleton;
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 38 - 17
include/anki/renderer/Ms.h

@@ -2,52 +2,73 @@
 #define ANKI_RENDERER_MS_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Texture.h"
-#include "anki/gl/Fbo.h"
+#include "anki/Gl.h"
 #include "anki/renderer/Ez.h"
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Material stage also known as G buffer stage. It populates the G buffer
 class Ms: public RenderingPass
 {
 public:
-	Ms(Renderer* r_)
-		: RenderingPass(r_), ez(r_)
+	Ms(Renderer* r)
+		: RenderingPass(r), m_ez(r)
 	{}
 
 	~Ms();
 
 	/// @name Accessors
 	/// @{
-	Texture& getFai0()
+	GlTextureHandle& getRt0()
 	{
-		return fai0[1];
+		return m_planes[1].m_rt0;
 	}
 
-	const Texture& getFai1() const;
+	GlTextureHandle& getRt1()
+	{
+		return m_planes[1].m_rt1;
+	}
 
-	const Texture& getDepthFai() const
+	GlTextureHandle& getDepthRt()
 	{
-		return depthFai[1];
+		return m_planes[1].m_depthRt;
 	}
 	/// @}
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 private:
-	Ez ez; /// EarlyZ pass
-	Array<Fbo, 2> fbo;
-	Array<Texture, 2> fai0; ///< The FAI for diffuse color, normals and specular
-	/// Contains the normal and spec power on the MRT case
-	Array<Texture, 2> fai1;
-	Array<Texture, 2> depthFai; ///< The FAI for depth
+	/// A collection of data
+	class Plane
+	{
+	public:
+		GlFramebufferHandle m_fb;
+
+		/// Contains diffuse color and part of specular
+		GlTextureHandle m_rt0; 
+
+		/// Contains the normal and spec power
+		GlTextureHandle m_rt1;
+
+		/// Depth stencil
+		GlTextureHandle m_depthRt; 
+	};
+
+	Ez m_ez; /// EarlyZ pass
+
+	/// One for multisampled and one for not. 0: multisampled, 1: not
+	Array<Plane, 2> m_planes;
 
 	/// Create a G buffer FBO
-	void createFbo(U index, U samples);
+	void createRt(U32 index, U32 samples);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 30 - 20
include/anki/renderer/Pps.h

@@ -2,7 +2,7 @@
 #define ANKI_RENDERER_PPS_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
+#include "anki/Gl.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/Resource.h"
 #include "anki/renderer/Hdr.h"
@@ -14,6 +14,9 @@ namespace anki {
 
 class ShaderProgram;
 
+/// @addtogroup renderer
+/// @{
+
 /// Post-processing stage.This stage is divided into 2 two parts. The first
 /// happens before blending stage and the second after
 class Pps: public OptionalRenderingPass
@@ -23,68 +26,75 @@ public:
 	~Pps();
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 	/// @name Accessors
 	/// @{
 	const Hdr& getHdr() const
 	{
-		return hdr;
+		return m_hdr;
 	}
 	Hdr& getHdr()
 	{
-		return hdr;
+		return m_hdr;
 	}
 
 	const Ssao& getSsao() const
 	{
-		return ssao;
+		return m_ssao;
+	}
+	Ssao& getSsao()
+	{
+		return m_ssao;
 	}
 
 	const Bl& getBl() const
 	{
-		return bl;
+		return m_bl;
 	}
 	Bl& getBl()
 	{
-		return bl;
+		return m_bl;
 	}
 
 	const Lf& getLf() const
 	{
-		return lf;
+		return m_lf;
 	}
 	Lf& getLf()
 	{
-		return lf;
+		return m_lf;
 	}
 
-	const Texture& getFai() const
+	const GlTextureHandle& getRt() const
 	{
-		return fai;
+		return m_rt;
 	}
-	Texture& getFai()
+	GlTextureHandle& getRt()
 	{
-		return fai;
+		return m_rt;
 	}
 	/// @}
 
 private:
 	/// @name Passes
 	/// @{
-	Hdr hdr;
-	Ssao ssao;
-	Bl bl;
-	Lf lf;
+	Hdr m_hdr;
+	Ssao m_ssao;
+	Bl m_bl;
+	Lf m_lf;
 	/// @}
 
-	Fbo fbo;
-	ShaderProgramResourcePointer prog;
-	Texture fai;
+	GlFramebufferHandle m_fb;
+	ProgramResourcePointer m_frag;
+	GlProgramPipelineHandle m_ppline;
+	GlTextureHandle m_rt;
 
 	void initInternal(const RendererInitializer& initializer);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 91 - 70
include/anki/renderer/Renderer.h

@@ -3,9 +3,9 @@
 
 #include "anki/Math.h"
 #include "anki/resource/TextureResource.h"
-#include "anki/resource/ShaderProgramResource.h"
+#include "anki/resource/ProgramResource.h"
 #include "anki/resource/Resource.h"
-#include "anki/gl/Gl.h"
+#include "anki/Gl.h"
 #include "anki/util/HighRezTimer.h"
 #include "anki/misc/ConfigSet.h"
 #include "anki/scene/Forward.h"
@@ -20,6 +20,9 @@
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// A struct to initialize the renderer. It contains a few extra params for
 /// the MainRenderer. Open Renderer.cpp to see all the options
 class RendererInitializer: public ConfigSet
@@ -40,155 +43,160 @@ public:
 	/// @{
 	const Ms& getMs() const
 	{
-		return ms;
+		return m_ms;
 	}
 	Ms& getMs()
 	{
-		return ms;
+		return m_ms;
 	}
 
 	const Is& getIs() const
 	{
-		return is;
+		return m_is;
 	}
 	Is& getIs()
 	{
-		return is;
+		return m_is;
 	}
 
 	const Tiler& getTiler() const
 	{
-		return tiler;
+		return m_tiler;
 	}
 	Tiler& getTiler()
 	{
-		return tiler;
+		return m_tiler;
 	}
 
 	const Pps& getPps() const
 	{
-		return pps;
+		return m_pps;
 	}
 	Pps& getPps()
 	{
-		return pps;
+		return m_pps;
 	}
 
 	const Dbg& getDbg() const
 	{
-		return dbg;
+		return m_dbg;
 	}
 	Dbg& getDbg()
 	{
-		return dbg;
+		return m_dbg;
 	}
 
 	U32 getWidth() const
 	{
-		return width;
+		return m_width;
 	}
 
 	U32 getHeight() const
 	{
-		return height;
+		return m_height;
 	}
 
 	U32 getWindowWidth() const
 	{
-		ANKI_ASSERT(!isOffscreen);
-		return width / renderingQuality;
+		ANKI_ASSERT(!m_isOffscreen);
+		return m_width / m_renderingQuality;
 	}
 
 	U32 getWindowHeight() const
 	{
-		ANKI_ASSERT(!isOffscreen);
-		return height / renderingQuality;
+		ANKI_ASSERT(!m_isOffscreen);
+		return m_height / m_renderingQuality;
 	}
 
 	F32 getAspectRatio() const
 	{
-		return F32(width) / height;
+		return F32(m_width) / m_height;
 	}
 
 	U32 getFramesCount() const
 	{
-		return framesNum;
+		return m_framesNum;
 	}
 
 	const SceneGraph& getSceneGraph() const
 	{
-		return *scene;
+		return *m_scene;
 	}
 	SceneGraph& getSceneGraph()
 	{
-		return *scene;
+		return *m_scene;
 	}
 
 	const RenderableDrawer& getSceneDrawer() const
 	{
-		return sceneDrawer;
+		return m_sceneDrawer;
 	}
 	RenderableDrawer& getSceneDrawer()
 	{
-		return sceneDrawer;
+		return m_sceneDrawer;
 	}
 
 	const Vec2& getPlanes() const
 	{
-		return planes;
+		return m_planes;
 	}
 	const Vec2& getLimitsOfNearPlane() const
 	{
-		return limitsOfNearPlane;
+		return m_limitsOfNearPlane;
 	}
 	const Vec2& getLimitsOfNearPlane2() const
 	{
-		return limitsOfNearPlane2;
+		return m_limitsOfNearPlane2;
 	}
 	Timestamp getPlanesUpdateTimestamp() const
 	{
-		return planesUpdateTimestamp;
+		return m_planesUpdateTimestamp;
 	}
 
 	U getSamples() const
 	{
-		return samples;
-	}
-
-	Bool getUseMrt() const
-	{
-		return useMrt;
+		return m_samples;
 	}
 
 	Bool getIsOffscreen() const
 	{
-		return isOffscreen;
+		return m_isOffscreen;
 	}
 
 	Bool usesTessellation() const
 	{
-		return tessellation;
+		return m_tessellation;
 	}
 
 	F32 getRenderingQuality() const
 	{
-		return renderingQuality;
+		return m_renderingQuality;
 	}
 
 	U32 getMaxTextureSize() const
 	{
-		return maxTextureSize;
+		return m_maxTextureSize;
 	}
 
 	const UVec2& getTilesCount() const
 	{
-		return tilesCount;
+		return m_tilesCount;
 	}
 
 	/// Get string to pass to the material shaders
 	const std::string& getShaderPostProcessorString() const
 	{
-		return shaderPostProcessorString;
+		return m_shaderPostProcessorString;
+	}
+
+	const GlProgramHandle& getDrawQuadVertexProgram() const
+	{
+		return m_drawQuadVert->getGlProgram();
+	}
+
+	GlFramebufferHandle& getDefaultFramebuffer()
+	{
+		return m_defaultFb;
 	}
 	/// @}
 
@@ -197,7 +205,7 @@ public:
 	void init(const RendererInitializer& initializer);
 
 	/// This function does all the rendering stages and produces a final FAI
-	void render(SceneGraph& scene);
+	void render(SceneGraph& scene, GlJobChainHandle& jobs);
 
 	/// My version of gluUnproject
 	/// @param windowCoords Window screen coords
@@ -211,9 +219,9 @@ public:
 
 	/// Draws a quad. Actually it draws 2 triangles because OpenGL will no
 	/// longer support quads
-	void drawQuad();
+	void drawQuad(GlJobChainHandle& jobs);
 
-	void drawQuadInstanced(U32 primitiveCount);
+	void drawQuadInstanced(GlJobChainHandle& jobs, U32 primitiveCount);
 
 	/// Calculate the planes needed for the calculation of the fragment
 	/// position z in view space. Having the fragment's depth, the camera's
@@ -237,64 +245,77 @@ public:
 	/// Get the LOD given the distance of an object from the camera
 	F32 calculateLod(F32 distance) const
 	{
-		return distance / lodDistance;
+		return distance / m_lodDistance;
 	}
 
+	/// Create a framebuffer attachment texture
+	void createRenderTarget(U32 w, U32 h, GLenum internalFormat, 
+		GLenum format, GLenum type, U32 samples, GlTextureHandle& rt);
+
+	/// Create a pipeline object that has as a vertex shader the m_drawQuadVert
+	/// and the given fragment progam
+	GlProgramPipelineHandle createDrawQuadProgramPipeline(
+		GlProgramHandle frag);
+
 private:
 	/// @name Rendering stages
 	/// @{
-	Ms ms; ///< Material rendering stage
-	Is is; ///< Illumination rendering stage
-	Pps pps; ///< Postprocessing rendering stage
-	Bs bs; ///< Blending stage
-	Dbg dbg; ///< Debug stage
-	Tiler tiler;
+	Ms m_ms; ///< Material rendering stage
+	Is m_is; ///< Illumination rendering stage
+	Pps m_pps; ///< Postprocessing rendering stage
+	Bs m_bs; ///< Blending stage
+	Dbg m_dbg; ///< Debug stage
+	Tiler m_tiler;
 	/// @}
 
 	/// Width of the rendering. Don't confuse with the window width
-	U32 width;
+	U32 m_width;
 	/// Height of the rendering. Don't confuse with the window height
-	U32 height;
-	F32 lodDistance; ///< Distance that used to calculate the LOD
-	U8 samples; ///< Number of sample in multisampling
-	Bool8 useMrt; ///< Use MRT or pack things inside the G buffer
-	Bool8 isOffscreen; ///< Is offscreen renderer?
-	Bool8 tessellation;
-	F32 renderingQuality; ///< Rendering quality. Relevant for offscreen 
-	U32 maxTextureSize; ///< Texture size limit. Just kept here.
-	UVec2 tilesCount;
+	U32 m_height;
+	F32 m_lodDistance; ///< Distance that used to calculate the LOD
+	U8 m_samples; ///< Number of sample in multisampling
+	Bool8 m_isOffscreen; ///< Is offscreen renderer?
+	Bool8 m_tessellation;
+	F32 m_renderingQuality; ///< Rendering quality. Relevant for offscreen 
+	U32 m_maxTextureSize; ///< Texture size limit. Just kept here.
+	UVec2 m_tilesCount;
 
 	/// @name For drawing a quad into the active framebuffer
 	/// @{
-	GlBuffer quadPositionsVbo; ///< The VBO for quad positions
-	Vao quadVao; ///< This VAO is used everywhere except material stage
+	GlBufferHandle m_quadPositionsBuff; ///< The VBO for quad positions
+
+	ProgramResourcePointer m_drawQuadVert;
 	/// @}
 
 	/// @name Optimization vars
 	/// Used in other stages
 	/// @{
-	Timestamp planesUpdateTimestamp = getGlobTimestamp();
+	Timestamp m_planesUpdateTimestamp = getGlobTimestamp();
 
 	/// Used to to calculate the frag pos in view space inside a few shader
 	/// programs
-	Vec2 planes;
+	Vec2 m_planes;
 	/// Used to to calculate the frag pos in view space inside a few shader
 	/// programs
-	Vec2 limitsOfNearPlane;
+	Vec2 m_limitsOfNearPlane;
 	/// Used to to calculate the frag pos in view space inside a few shader
 	/// programs
-	Vec2 limitsOfNearPlane2;
+	Vec2 m_limitsOfNearPlane2;
 	/// @}
 
-	SceneGraph* scene; ///< Current scene
-	RenderableDrawer sceneDrawer;
+	SceneGraph* m_scene; ///< Current scene
+	RenderableDrawer m_sceneDrawer;
 
-	U framesNum; ///< Frame number
+	U m_framesNum; ///< Frame number
 
 	/// String to pass to the material shaders
-	std::string shaderPostProcessorString;
+	std::string m_shaderPostProcessorString;
+
+	GlFramebufferHandle m_defaultFb;
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 18 - 16
include/anki/renderer/RenderingPass.h

@@ -8,62 +8,64 @@ namespace anki {
 class Renderer;
 class RendererInitializer;
 
+/// @addtogroup renderer
+/// @{
+
 /// Rendering pass
 class RenderingPass
 {
 public:
-	RenderingPass(Renderer* r_)
-		: r(r_)
+	RenderingPass(Renderer* r)
+		: m_r(r)
 	{}
 
-	virtual ~RenderingPass()
+	~RenderingPass()
 	{}
 
-	/// All passes should have an init
-	virtual void init(const RendererInitializer& initializer) = 0;
-
 protected:
-	Renderer* r; ///< Know your father
+	Renderer* m_r; ///< Know your father
 };
 
 /// Rendering pass that can be enabled or disabled at runtime
 class SwitchableRenderingPass: public RenderingPass
 {
 public:
-	SwitchableRenderingPass(Renderer* r_)
-		: RenderingPass(r_)
+	SwitchableRenderingPass(Renderer* r)
+		: RenderingPass(r)
 	{}
 
 	Bool getEnabled() const
 	{
-		return enabled;
+		return m_enabled;
 	}
 	void setEnabled(Bool e)
 	{
-		enabled = e;
+		m_enabled = e;
 	}
 
 protected:
-	Bool8 enabled = false;
+	Bool8 m_enabled = false;
 };
 
 /// Rendering pass that can be enabled or disabled
 class OptionalRenderingPass: public RenderingPass
 {
 public:
-	OptionalRenderingPass(Renderer* r_)
-		: RenderingPass(r_)
+	OptionalRenderingPass(Renderer* r)
+		: RenderingPass(r)
 	{}
 
 	Bool getEnabled() const
 	{
-		return enabled;
+		return m_enabled;
 	}
 
 protected:
-	Bool8 enabled = false;
+	Bool8 m_enabled = false;
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 27 - 20
include/anki/renderer/Sm.h

@@ -2,7 +2,7 @@
 #define ANKI_RENDERER_SM_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/gl/Fbo.h"
+#include "anki/Gl.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Array.h"
@@ -11,74 +11,81 @@ namespace anki {
 
 class Light;
 
+/// @addtogroup renderer
+/// @{
+
 /// Shadowmapping pass
 class Sm: private RenderingPass
 {
 	friend class Is;
+
 public:
 	static const U32 MAX_SHADOW_CASTERS = 8;
 
-	Sm(Renderer* r_)
-		: RenderingPass(r_)
+	Sm(Renderer* r)
+		: RenderingPass(r)
 	{}
 
 	/// @name Accessors
 	/// @{
 	Bool getEnabled() const
 	{
-		return enabled;
+		return m_enabled;
 	}
 
 	Bool getPoissonEnabled() const
 	{
-		return poissonEnabled;
+		return m_poissonEnabled;
 	}
 	/// @}
 
 	void init(const RendererInitializer& initializer);
-	void run(Light* shadowCasters[], U32 shadowCastersCount);
+	void run(Light* shadowCasters[], U32 shadowCastersCount, 
+		GlJobChainHandle& jobs);
 
 private:
-	Texture sm2DArrayTex;
+	GlTextureHandle m_sm2DArrayTex;
 
 	/// Shadowmap
 	struct Shadowmap
 	{
-		U32 layerId;
-		Fbo fbo;
-		Light* light = nullptr;
-		U32 timestamp = 0; ///< Timestamp of last render or light change
+		U32 m_layerId;
+		GlFramebufferHandle m_fb;
+		Light* m_light = nullptr;
+		U32 m_timestamp = 0; ///< Timestamp of last render or light change
 	};
 
-	Vector<Shadowmap> sms;
+	Vector<Shadowmap> m_sms;
 
 	/// If false then disable SM at all
-	Bool enabled; 
+	Bool8 m_enabled; 
 
 	/// Enable Poisson for all the levels
-	Bool poissonEnabled;
+	Bool8 m_poissonEnabled;
 
 	/// Shadowmap bilinear filtering for the first level. Better quality
-	Bool bilinearEnabled;
+	Bool8 m_bilinearEnabled;
 
 	/// Shadowmap resolution
-	U32 resolution;
+	U32 m_resolution;
 
 	/// Get max shadow casters
 	U32 getMaxLightsCount()
 	{
-		return sms.size();
+		return m_sms.size();
 	}
 
-	void prepareDraw();
-	void afterDraw();
+	void prepareDraw(GlJobChainHandle& jobs);
+	void finishDraw(GlJobChainHandle& jobs);
 
 	/// Find the best shadowmap for that light
 	Shadowmap& bestCandidate(Light& light);
 
-	Shadowmap* doLight(Light& light);
+	Shadowmap* doLight(Light& light, GlJobChainHandle& jobs);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 32 - 29
include/anki/renderer/Ssao.h

@@ -2,59 +2,62 @@
 #define ANKI_RENDERER_SSAO_H
 
 #include "anki/renderer/RenderingPass.h"
-#include "anki/resource/ShaderProgramResource.h"
+#include "anki/resource/ProgramResource.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/resource/Resource.h"
-#include "anki/gl/Fbo.h"
-#include "anki/gl/Texture.h"
-#include "anki/gl/GlBuffer.h"
+#include "anki/Gl.h"
 #include "anki/core/Timestamp.h"
 
 namespace anki {
 
+/// @addtogroup renderer
+/// @{
+
 /// Screen space ambient occlusion pass
-///
-/// Three passes:
-/// @li Calc ssao factor
-/// @li Blur vertically
-/// @li Blur horizontally
-/// @li Repeat from 2
 class Ssao: public SwitchableRenderingPass
 {
 public:
-	Ssao(Renderer* r_)
-		: SwitchableRenderingPass(r_)
+	Ssao(Renderer* r)
+		: SwitchableRenderingPass(r)
 	{}
 
 	void init(const RendererInitializer& initializer);
-	void run();
+	void run(GlJobChainHandle& jobs);
 
 	/// @name Accessors
 	/// @{
-	const Texture& getFai() const
+	GlTextureHandle& getRt()
 	{
-		return vblurFai;
+		return m_vblurRt;
 	}
 	/// @}
 
 private:
-	U32 width, height; ///< Blur passes size
-	Texture vblurFai;
-	Texture hblurFai;
-	U32 blurringIterationsCount;
-	Fbo vblurFbo;
-	Fbo hblurFbo;
-	Texture noiseTex;
-	ShaderProgramResourcePointer ssaoSProg;
-	ShaderProgramResourcePointer hblurSProg;
-	ShaderProgramResourcePointer vblurSProg;
-	Timestamp commonUboUpdateTimestamp = getGlobTimestamp();
-	GlBuffer commonUbo;
-
-	static void createFbo(Fbo& fbo, Texture& fai, U width, U height);
+	U32 m_width, m_height; ///< Blur passes size
+	U8 m_blurringIterationsCount;
+
+	GlTextureHandle m_vblurRt;
+	GlTextureHandle m_hblurRt;
+	GlFramebufferHandle m_vblurFb;
+	GlFramebufferHandle m_hblurFb;
+
+	ProgramResourcePointer m_ssaoFrag;
+	ProgramResourcePointer m_hblurFrag;
+	ProgramResourcePointer m_vblurFrag;
+	GlProgramPipelineHandle m_ssaoPpline;
+	GlProgramPipelineHandle m_hblurPpline;
+	GlProgramPipelineHandle m_vblurPpline;
+	
+	Timestamp m_commonUboUpdateTimestamp = getGlobTimestamp();
+	GlBufferHandle m_uniformsBuff;
+	GlTextureHandle m_noiseTex;
+
+	void createFb(GlFramebufferHandle& fb, GlTextureHandle& rt);
 	void initInternal(const RendererInitializer& initializer);
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 24 - 20
include/anki/renderer/Tiler.h

@@ -3,7 +3,7 @@
 
 #include "anki/util/StdTypes.h"
 #include "anki/Collision.h"
-#include "anki/gl/Gl.h"
+#include "anki/Gl.h"
 #include "anki/resource/Resource.h"
 #include "anki/core/Timestamp.h"
 #include <bitset>
@@ -15,6 +15,9 @@ class Camera;
 class ShaderProgramUniformVariable;
 class Frustumable;
 
+/// @addtogroup renderer
+/// @{
+
 /// Tiler used for visibility tests
 class Tiler
 {
@@ -31,7 +34,7 @@ public:
 	void init(Renderer* r);
 
 	/// Issue the GPU job
-	void runMinMax(const Texture& depthMap);
+	void runMinMax(const GlTextureHandle& depthMap);
 
 	/// Update the tiles before doing visibility tests
 	void updateTiles(Camera& cam);
@@ -48,43 +51,44 @@ public:
 
 private:
 	/// Tile planes
-	Vector<Plane> allPlanes;
-	Plane* planesY = nullptr;
-	Plane* planesX = nullptr;
-	Plane* planesYW = nullptr;
-	Plane* planesXW = nullptr;
-	Plane* nearPlanesW = nullptr;
-	Plane* farPlanesW = nullptr;
+	Vector<Plane> m_allPlanes;
+	Plane* m_planesY = nullptr;
+	Plane* m_planesX = nullptr;
+	Plane* m_planesYW = nullptr;
+	Plane* m_planesXW = nullptr;
+	Plane* m_nearPlanesW = nullptr;
+	Plane* m_farPlanesW = nullptr;
 
 	/// A texture of tilesXCount * tilesYCount size and format RG32UI. Used to
 	/// calculate the near and far planes of the tiles
-	Texture fai;
+	GlTextureHandle m_rt;
 
-	/// Main FBO for the fai
-	Fbo fbo;
+	/// Main FB for the fai
+	GlFramebufferHandle m_fb;
 
 	/// PBO buffer that is used to read the data of fai asynchronously
-	GlBuffer pbo;
+	GlBufferHandle m_pixelBuff;
 
 	/// Main shader program
-	ShaderProgramResourcePointer prog;
-
-	const ShaderProgramUniformVariable* depthMapUniform = nullptr; ///< Cache it
+	ProgramResourcePointer m_frag;
+	GlProgramPipelineHandle m_ppline;
 
-	Renderer* r = nullptr;
+	Renderer* m_r = nullptr;
 
 	/// Used to check if the camera is changed and we need to update the planes
-	const Camera* prevCam = nullptr;
+	const Camera* m_prevCam = nullptr;
 
 	/// Timestamp for the same reason as prevCam
-	Timestamp planes4UpdateTimestamp = getGlobTimestamp();
+	Timestamp m_planes4UpdateTimestamp = getGlobTimestamp();
 
-	void initInternal(Renderer* r_);
+	void initInternal(Renderer* r);
 
 	void testRange(const CollisionShape& cs, Bool nearPlane,
 		U iFrom, U iTo, U jFrom, U jTo, Bitset& bitset) const;
 };
 
+/// @}
+
 } // end namespace anki
 
 #endif

+ 122 - 138
include/anki/resource/Material.h

@@ -2,8 +2,8 @@
 #define ANKI_RESOURCE_MATERIAL_H
 
 #include "anki/resource/Resource.h"
-#include "anki/resource/ShaderProgramResource.h"
-#include "anki/resource/PassLodKey.h"
+#include "anki/resource/ProgramResource.h"
+#include "anki/resource/RenderingKey.h"
 #include "anki/Math.h"
 #include "anki/util/Visitor.h"
 #include "anki/util/Dictionary.h"
@@ -14,9 +14,8 @@ namespace anki {
 
 // Forward
 class XmlElement;
-class MaterialShaderProgramCreator;
+class MaterialProgramCreator;
 
-// Forward
 template<typename T>
 class MaterialVariableTemplate;
 
@@ -43,11 +42,10 @@ public:
 
 	/// @name Constructors & destructor
 	/// @{
-	MaterialVariable(
-		const char* shaderProgVarName,
-		PassLodArray<ShaderProgramResourcePointer>& progs)
+	MaterialVariable(const GlProgramVariable* glvar, Bool instanced)
+		: m_progVar(glvar), m_instanced(instanced)
 	{
-		init(shaderProgVarName, progs);
+		ANKI_ASSERT(m_progVar);
 	}
 
 	virtual ~MaterialVariable();
@@ -56,74 +54,75 @@ public:
 	/// @name Accessors
 	/// @{
 	template<typename T>
-	const T* getValues() const
+	const T* begin() const
 	{
-		ANKI_ASSERT(Base::getVariadicTypeId<MaterialVariableTemplate<T>>()
-			== Base::getVisitableTypeId());
-		return static_cast<const MaterialVariableTemplate<T>*>(this)->get();
+		ANKI_ASSERT(Base::isTypeOf<MaterialVariableTemplate<T>>());
+		auto derived = static_cast<const MaterialVariableTemplate<T>*>(this);
+		return derived->begin();
 	}
-
 	template<typename T>
-	void setValues(const T* x, U32 size)
+	const T* end() const
 	{
-		ANKI_ASSERT(Base::getVariadicTypeId<MaterialVariableTemplate<T>>()
-			== Base::getVisitableTypeId());
-		static_cast<MaterialVariableTemplate<T>*>(this)->set(x, size);
+		ANKI_ASSERT(Base::isTypeOf<MaterialVariableTemplate<T>>());
+		auto derived = static_cast<const MaterialVariableTemplate<T>*>(this);
+		return derived->end();
 	}
 
-	U32 getArraySize() const;
-
-	/// Given a key return the uniform. If the uniform is not present in the
-	/// LOD pass key then returns nullptr
-	const ShaderProgramUniformVariable* findShaderProgramUniformVariable(
-		const PassLodKey& key) const
+	template<typename T>
+	const T& operator[](U idx) const
 	{
-		return progVars[key.pass][key.lod];
+		ANKI_ASSERT(Base::isTypeOf<MaterialVariableTemplate<T>>());
+		auto derived = static_cast<const MaterialVariableTemplate<T>*>(this);
+		return (*derived)[idx];
 	}
 
-	/// Get the GL data type of all the shader program variables
-	GLenum getGlDataType() const;
-
-	/// Get the name of all the shader program variables
-	const std::string& getName() const;
-
-	const ShaderProgramUniformVariable&
-		getAShaderProgramUniformVariable() const
+	const GlProgramVariable& getGlProgramVariable() const
 	{
-		return *oneSProgVar;
+		return *m_progVar;
 	}
 
+	/// Get the name of all the shader program variables
+	const char* getName() const;
+
 	/// If false then it should be buildin
 	virtual Bool hasValues() const = 0;
+
+	U32 getArraySize() const;
+
+	Bool isInstanced() const
+	{
+		return m_instanced;
+	}
 	/// @}
 
 private:
-	PassLodArray<const ShaderProgramUniformVariable*> progVars;
-
-	/// Keep one ShaderProgramVariable here for easy access of the common
+	/// Keep one program variable here for easy access of the common
 	/// variable stuff like name or GL data type etc
-	const ShaderProgramUniformVariable* oneSProgVar;
+	const GlProgramVariable* m_progVar;
 
-	/// Common constructor code
-	void init(const char* shaderProgVarName,
-		PassLodArray<ShaderProgramResourcePointer>& progs);
+	Bool8 m_instanced;
 };
 
 /// Material variable with data. A complete type
-template<typename Data>
+template<typename TData>
 class MaterialVariableTemplate: public MaterialVariable
 {
 public:
-	typedef Data Type;
+	typedef TData Type;
 
 	/// @name Constructors/Destructor
 	/// @{
 	MaterialVariableTemplate(
-		const char* shaderProgVarName,
-		PassLodArray<ShaderProgramResourcePointer>& progs)
-		: MaterialVariable(shaderProgVarName, progs)
+		const GlProgramVariable* glvar, Bool instanced, 
+		const TData* x, U32 size)
+		: MaterialVariable(glvar, instanced)
 	{
 		setupVisitable(this);
+
+		if(size > 0)
+		{
+			m_data.insert(m_data.begin(), x, x + size);
+		}
 	}
 
 	~MaterialVariableTemplate()
@@ -132,27 +131,33 @@ public:
 
 	/// @name Accessors
 	/// @{
-	const Data* get() const
+	const TData* begin() const
 	{
-		return (data.size() > 0) ? &data[0] : nullptr;
+		ANKI_ASSERT(hasValues());
+		return &(*m_data.begin());
+	}
+	const TData* end() const
+	{
+		ANKI_ASSERT(hasValues());
+		return &(*m_data.end());
 	}
 
-	void set(const Data* x, U32 size)
+	const TData& operator[](U idx) const
 	{
-		if(size > 0)
-		{
-			data.insert(data.begin(), x, x + size);
-		}
+		ANKI_ASSERT(hasValues());
+		ANKI_ASSERT(idx < m_data.size());
+		return m_data[idx];
 	}
 
+	/// Implements hasValues
 	Bool hasValues() const
 	{
-		return data.size() > 0;
+		return m_data.size() > 0;
 	}
 	/// @}
 
 private:
-	Vector<Data> data;
+	Vector<TData> m_data;
 };
 
 /// Contains a few properties that other classes may use. For an explanation of
@@ -164,62 +169,62 @@ public:
 	/// @{
 	U getLevelsOfDetail() const
 	{
-		return lodsCount;
+		return m_lodsCount;
 	}
 
 	U getPassesCount() const
 	{
-		return passesCount;
+		return m_passesCount;
 	}
 
 	Bool getShadow() const
 	{
-		return shadow;
+		return m_shadow;
 	}
 
 	GLenum getBlendingSfactor() const
 	{
-		return blendingSfactor;
+		return m_blendingSfactor;
 	}
 
 	GLenum getBlendingDfactor() const
 	{
-		return blendingDfactor;
+		return m_blendingDfactor;
 	}
 
 	Bool getDepthTestingEnabled() const
 	{
-		return depthTesting;
+		return m_depthTesting;
 	}
 
 	Bool getWireframe() const
 	{
-		return wireframe;
+		return m_wireframe;
 	}
 
 	Bool getTessellation() const
 	{
-		return tessellation;
+		return m_tessellation;
 	}
 	/// @}
 
 	/// Check if blending is enabled
 	Bool isBlendingEnabled() const
 	{
-		return blendingSfactor != GL_ONE || blendingDfactor != GL_ZERO;
+		return m_blendingSfactor != GL_ONE || m_blendingDfactor != GL_ZERO;
 	}
 
 protected:
-	GLenum blendingSfactor = GL_ONE; ///< Default GL_ONE
-	GLenum blendingDfactor = GL_ZERO; ///< Default GL_ZERO
+	GLenum m_blendingSfactor = GL_ONE; ///< Default GL_ONE
+	GLenum m_blendingDfactor = GL_ZERO; ///< Default GL_ZERO
 
-	Bool8 depthTesting = true;
-	Bool8 wireframe = false;
-	Bool8 shadow = true;
-	Bool8 tessellation = false;
+	Bool8 m_depthTesting = true;
+	Bool8 m_wireframe = false;
+	Bool8 m_shadow = true;
+	Bool8 m_tessellation = false;
 
-	U8 passesCount = 1;
-	U8 lodsCount = 1;
+	U8 m_passesCount = 1;
+	U8 m_lodsCount = 1;
 };
 
 /// Material resource
@@ -236,8 +241,6 @@ protected:
 /// Material XML file format:
 /// @code
 /// <material>
-/// 	[<passes>COLOR DEPTH</passes>]
-///
 /// 	[<levelsOfDetail>N</levelsOfDetail>]
 ///
 /// 	[<shadow>0 | 1</shadow>]
@@ -251,22 +254,23 @@ protected:
 ///
 /// 	[<wireframe>0 | 1</wireframe>]
 ///
-/// 	<shaderProgram>
+/// 	<programs>
+/// 		<program>
+/// 			<type>vert | tesc | tese | geom | frag</type>
 ///
-///			[<inputs> (3)
-///				<input>
-///					<name>xx</name>
-///					<type>any glsl type</type>
-///					<value> (4)
-///						[a_series_of_numbers |
-///						path/to/image.tga]
-///					</value>
-///					[<const>0 | 1</const>] (5)
-///				</input>
-///			</inputs>]
-///
-/// 		<shader> (2)
-/// 			<type>vertex | tc | te | geometry | fragment</type>
+///				[<inputs> (1)
+///					<input>
+///						<name>xx</name>
+///						<type>any glsl type</type>
+///						<value> (2)
+///							[a_series_of_numbers |
+///							path/to/image.tga]
+///						</value>
+///						[<const>0 | 1</const>] (3)
+///						[<instanced>0 | 1</instanced>]
+///						[<arraySize>N</<arraySize>]
+///					</input>
+///				</inputs>]
 ///
 /// 			<includes>
 /// 				<include>path/to/file.glsl</include>
@@ -283,23 +287,24 @@ protected:
 /// 						<argument>yy</argument>
 /// 					</arguments>]
 /// 				</operation>
+///
+/// 				<operation>...</operation>
 /// 			</operations>
-/// 		</vertexShader>
+/// 		</program>
 ///
-/// 		<shader>...</shader>
-/// 	</shaderProgram>
+/// 		<program>...</program>
+/// 	</programs>
 /// </material>
 /// @endcode
-/// (2): The order of the shaders is crucial
-/// (3): AKA uniforms
-/// (4): The \<value\> can be left empty for build-in variables
-/// (5): The \<const\> will mark a variable as constant and it cannot be changed
-///      at all. Defauls is 0
+/// (1): AKA uniforms
+/// (2): The \<value\> can be left empty for build-in variables
+/// (3): The \<const\> will mark a variable as constant and it cannot be changed
+///      at all. Default is 0
 class Material: public MaterialProperties, public NonCopyable
 {
-public:
-	typedef Vector<MaterialVariable*> VarsContainer;
+	friend class MaterialVariable;
 
+public:
 	Material();
 	~Material();
 
@@ -313,40 +318,25 @@ public:
 	}
 
 	// Variable accessors
-	const VarsContainer& getVariables() const
+	const Vector<MaterialVariable*>& getVariables() const
 	{
-		return vars;
+		return m_vars;
 	}
 
-	const ShaderProgramUniformBlock* getCommonUniformBlock() const
+	U32 getDefaultBlockSize() const
 	{
-		return commonUniformBlock;
+		return m_shaderBlockSize;
 	}
 	/// @}
 
-	const ShaderProgram& findShaderProgram(const PassLodKey& key) const
-	{
-		ANKI_ASSERT(progs[key.pass][key.lod].isLoaded());
-		return *progs[key.pass][key.lod];
-	}
-
-	const ShaderProgram* tryFindShaderProgram(const PassLodKey& key) const
-	{
-		if(progs[key.pass][key.lod].isLoaded())
-		{
-			return progs[key.pass][key.lod].get();
-		}
-		else
-		{
-			return nullptr;
-		}
-	}
+	GlProgramPipelineHandle getProgramPipeline(
+		const RenderingKey& key);
 
 	/// Get by name
 	const MaterialVariable* findVariableByName(const char* name) const
 	{
-		NameToVariableHashMap::const_iterator it = nameToVar.find(name);
-		return (it == nameToVar.end()) ? nullptr : it->second;
+		auto it = m_varDict.find(name);
+		return (it == m_varDict.end()) ? nullptr : it->second;
 	}
 
 	/// Load a material file
@@ -355,39 +345,33 @@ public:
 	/// For sorting
 	Bool operator<(const Material& b) const
 	{
-		return hash < b.hash;
+		return m_hash < b.m_hash;
 	}
 
 private:
-	typedef Dictionary<MaterialVariable*> NameToVariableHashMap;
-
-	std::string fname; ///< filename
-
-	/// All the material variables
-	VarsContainer vars;
+	Vector<MaterialVariable*> m_vars;
+	Dictionary<MaterialVariable*> m_varDict;
 
-	NameToVariableHashMap nameToVar;
+	Vector<ProgramResourcePointer> m_progs;
+	Vector<GlProgramPipelineHandle> m_pplines;
 
-	/// The most important aspect of materials. These are all the shader
-	/// programs per level and per pass. Their number are NP * NL where
-	/// NP is the number of passes and NL the number of levels of detail
-	PassLodArray<ShaderProgramResourcePointer> progs;
+	U32 m_shaderBlockSize;
 
 	/// Used for sorting
-	std::size_t hash;
+	PtrSize m_hash;
 
-	/// One uniform block
-	const ShaderProgramUniformBlock* commonUniformBlock;
+	/// Get a program resource
+	ProgramResourcePointer& getProgram(const RenderingKey key, U32 shaderId);
 
 	/// Parse what is within the @code <material></material> @endcode
 	void parseMaterialTag(const XmlElement& el);
 
 	/// Create a unique shader source in chache. If already exists do nothing
-	std::string createShaderProgSourceToCache(const std::string& source);
+	std::string createProgramSourceToChache(const std::string& source);
 
 	/// Read all shader programs and pupulate the @a vars and @a nameToVar
 	/// containers
-	void populateVariables(const MaterialShaderProgramCreator& mspc);
+	void populateVariables(const MaterialProgramCreator& mspc);
 };
 
 } // end namespace anki

+ 86 - 0
include/anki/resource/MaterialProgramCreator.h

@@ -0,0 +1,86 @@
+#ifndef ANKI_RESOURCE_MATERIAL_SHADER_PROGRAM_CREATOR_H
+#define ANKI_RESOURCE_MATERIAL_SHADER_PROGRAM_CREATOR_H
+
+#include "anki/util/StringList.h"
+#include "anki/Gl.h"
+
+namespace anki {
+
+class XmlElement;
+
+/// Creator of shader programs. This class parses between
+/// @code <shaderProgams></shaderPrograms> @endcode located inside a 
+/// @code <material></material> @endcode and creates the source of a custom 
+/// program.
+///
+/// @note Be carefull when you change the methods. Some change may create more
+///       unique shaders and this is never good.
+class MaterialProgramCreator
+{
+public:
+	class Input
+	{
+	public:
+		std::string m_name;
+		std::string m_type;
+		StringList m_value;
+		Bool8 m_constant;
+		U16 m_arraySize;
+		Bool8 m_instanced = false;
+
+		std::string m_line;
+		GLbitfield m_shaderDefinedMask = 0; ///< Defined in
+		GLbitfield m_shaderReferencedMask = 0; ///< Referenced by
+		Bool8 m_inBlock = true;
+	};
+
+	explicit MaterialProgramCreator(const XmlElement& pt);
+
+	~MaterialProgramCreator();
+
+	/// Get the shader program source code
+	std::string getProgramSource(U shaderType) const
+	{
+		ANKI_ASSERT(m_source[shaderType].size() > 0);
+		return m_source[shaderType].join("\n");
+	}
+
+	const Vector<Input>& getInputVariables() const
+	{
+		return m_inputs;
+	}
+
+	Bool hasTessellation() const
+	{
+		return m_tessellation;
+	}
+
+private:
+	Array<StringList, 5> m_source; ///< Shader program final source
+	Vector<Input> m_inputs;
+	StringList m_uniformBlock;
+	GLbitfield m_uniformBlockReferencedMask = 0;
+	Bool8 m_instanced = false;
+	U32 m_texBinding = 0;
+	GLbitfield m_instanceIdMask = 0;
+	Bool8 m_tessellation = false;
+
+	/// Parse what is within the
+	/// @code <programs></programs> @endcode
+	void parseProgramsTag(const XmlElement& el);
+
+	/// Parse what is within the
+	/// @code <program></program> @endcode
+	void parseProgramTag(const XmlElement& el);
+
+	/// Parse what is within the @code <inputs></inputs> @endcode
+	void parseInputsTag(const XmlElement& programEl);
+
+	/// Parse what is within the @code <operation></operation> @endcode
+	void parseOperationTag(const XmlElement& el, GLenum glshader, 
+		GLbitfield glshaderbit, std::string& out);
+};
+
+} // end namespace anki
+
+#endif

Some files were not shown because too many files changed in this diff