Panagiotis Christopoulos Charitos 13 gadi atpakaļ
vecāks
revīzija
aa773e584c

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

@@ -95,7 +95,7 @@ public:
 	/// the @a trf, it just replaces it
 	/// the @a trf, it just replaces it
 	virtual void setTransform(const Transform& trf) = 0;
 	virtual void setTransform(const Transform& trf) = 0;
 
 
-protected:
+public: // XXX
 	/// @name Viewing variables
 	/// @name Viewing variables
 	/// @{
 	/// @{
 	F32 near = 0.0;
 	F32 near = 0.0;

+ 4 - 0
include/anki/gl/BufferObject.h

@@ -150,6 +150,10 @@ private:
 
 
 	GLenum usage; ///< GL_STREAM_DRAW or GL_STATIC_DRAW or GL_DYNAMIC_DRAW
 	GLenum usage; ///< GL_STREAM_DRAW or GL_STATIC_DRAW or GL_DYNAMIC_DRAW
 	U32 sizeInBytes; ///< The size of the buffer
 	U32 sizeInBytes; ///< The size of the buffer
+
+#if !NDEBUG
+	Bool mapped = false;
+#endif
 };
 };
 /// @}
 /// @}
 
 

+ 4 - 2
include/anki/gl/ShaderProgram.h

@@ -8,6 +8,7 @@
 #include "anki/util/NonCopyable.h"
 #include "anki/util/NonCopyable.h"
 #include "anki/gl/Ogl.h"
 #include "anki/gl/Ogl.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Vector.h"
+#include "anki/util/StdTypes.h"
 #include <string>
 #include <string>
 #include <memory>
 #include <memory>
 
 
@@ -221,9 +222,10 @@ public:
 private:
 private:
 	Vector<ShaderProgramUniformVariable*> uniforms;
 	Vector<ShaderProgramUniformVariable*> uniforms;
 	GLuint index = GL_INVALID_INDEX;
 	GLuint index = GL_INVALID_INDEX;
-	uint32_t size = 0; ///< In bytes
+	U32 size = 0; ///< In bytes
 	std::string name;
 	std::string name;
-	mutable GLuint bindingPoint = 0; ///< All blocks the default to 0
+	/// Ask the program to get you the binding point
+	mutable GLuint bindingPoint;
 	GLuint progId;
 	GLuint progId;
 };
 };
 
 

+ 2 - 2
include/anki/math/Math.h

@@ -12,8 +12,8 @@ namespace anki {
 class Math
 class Math
 {
 {
 public:
 public:
-	static const F32 PI;
-	static const F32 EPSILON;
+	static constexpr F32 PI = 3.14159265358979323846;
+	static constexpr F32 EPSILON = 1.0e-6;
 
 
 	/// A fast func that given the angle in rads it returns the sin and cos
 	/// A fast func that given the angle in rads it returns the sin and cos
 	static void sinCos(const F32 rad, F32& sin_, F32& cos_);
 	static void sinCos(const F32 rad, F32& sin_, F32& cos_);

+ 11 - 32
include/anki/renderer/Is.h

@@ -22,12 +22,14 @@ class SpotLight;
 class Is: private RenderingPass
 class Is: private RenderingPass
 {
 {
 public:
 public:
+	// Config. These values affect the size of the uniform blocks and keep in
+	// mind that there are size limitations in uniform blocks.
 	static const U TILES_X_COUNT = 16;
 	static const U TILES_X_COUNT = 16;
 	static const U TILES_Y_COUNT = 16;
 	static const U TILES_Y_COUNT = 16;
 
 
-	static const U MAX_LIGHTS_PER_TILE = 128;
+	static const U MAX_LIGHTS_PER_TILE = 32;
 
 
-	static const U MAX_LIGHTS = 1024;
+	static const U MAX_LIGHTS = 512;
 
 
 	Is(Renderer* r);
 	Is(Renderer* r);
 
 
@@ -49,7 +51,7 @@ public:
 	}
 	}
 	/// @}
 	/// @}
 
 
-private:
+public: // XXX
 	enum LightSubType
 	enum LightSubType
 	{
 	{
 		LST_POINT,
 		LST_POINT,
@@ -61,15 +63,6 @@ private:
 	/// A screen tile
 	/// A screen tile
 	struct Tile
 	struct Tile
 	{
 	{
-		/// depth[0] = min depth, depth[1] = max depth
-		Vec2 depth;
-
-		/// Used for 2D light culling
-		/// @note The coords are in NDC
-		/// @note coords[0] is the bottom left coord, and the coords[1] the 
-		///       top right
-		Array<Vec2, 2> coords;
-
 		Array<U32, MAX_LIGHTS_PER_TILE> lightIndices;
 		Array<U32, MAX_LIGHTS_PER_TILE> lightIndices;
 		U lightsCount = 0;
 		U lightsCount = 0;
 
 
@@ -80,7 +73,7 @@ private:
 	U32 planesUpdateTimestamp = Timestamp::getTimestamp();
 	U32 planesUpdateTimestamp = Timestamp::getTimestamp();
 
 
 	/// @note The [0][0] is the bottom left tile
 	/// @note The [0][0] is the bottom left tile
-	Tile tiles[TILES_Y_COUNT][TILES_X_COUNT];
+	Array<Array<Tile, TILES_X_COUNT>, TILES_Y_COUNT> tiles;
 
 
 	/// A texture of TILES_X_COUNT*TILES_Y_COUNT size and format RG16F. Used to
 	/// A texture of TILES_X_COUNT*TILES_Y_COUNT size and format RG16F. Used to
 	/// to fill the Tile::depth
 	/// to fill the Tile::depth
@@ -98,12 +91,12 @@ private:
 	/// Contains common data for all shader programs
 	/// Contains common data for all shader programs
 	Ubo commonUbo;
 	Ubo commonUbo;
 
 
-	/// Contains the indices of lights per tile
-	Ubo lightIndicesUbo;
-
 	/// Contains info of all the lights
 	/// Contains info of all the lights
 	Ubo lightsUbo;
 	Ubo lightsUbo;
 
 
+	/// Contains the indices of lights per tile
+	Ubo tilesUbo;
+
 	/// Min max shader program
 	/// Min max shader program
 	ShaderProgramResourcePointer minMaxPassSprog;
 	ShaderProgramResourcePointer minMaxPassSprog;
 
 
@@ -112,28 +105,14 @@ private:
 
 
 	Sm sm;
 	Sm sm;
 
 
-	/// Project a sphere to a circle
-	static void projectShape(const Camera& cam,
-		const Sphere& sphere, Vec2& circleCenter, F32& circleRadius);
-	/// Project a perspective frustum to a triangle
-	static void projectShape(const Mat4& projectionMat,
-		const PerspectiveFrustum& fr, Array<Vec2, 3>& coords);
-
-	/// For intersecting of point lights
-	static Bool circleIntersects(const Tile& tile, const Vec2& circleCenter, 
-		F32 circleRadius);
-	/// For intersecting of spot lights
-	static Bool triangleIntersects(const Tile& tile, 
-		const Array<Vec2, 3>& coords);
-
 	/// Updates all the planes except the near and far plane. Near and far 
 	/// Updates all the planes except the near and far plane. Near and far 
 	/// planes will be updated in min max pass when the depth is known
 	/// planes will be updated in min max pass when the depth is known
 	void updateAllTilesPlanes();
 	void updateAllTilesPlanes();
 
 
 	void updateAllTilesPlanes(const PerspectiveCamera& pcam);
 	void updateAllTilesPlanes(const PerspectiveCamera& pcam);
 
 
-	/// Fill the minMaxFai
-	void minMaxPass();
+	/// XXX
+	void updateTiles();
 
 
 	/// See if the light is inside the tile
 	/// See if the light is inside the tile
 	Bool cullLight(const PointLight& light, const Tile& tile);
 	Bool cullLight(const PointLight& light, const Tile& tile);

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

@@ -15,7 +15,7 @@ class OctreeNode;
 /// Spatial "interface" for scene nodes. It indicates scene nodes that need to 
 /// Spatial "interface" for scene nodes. It indicates scene nodes that need to 
 /// be placed in the scene's octree and they participate in the visibility 
 /// be placed in the scene's octree and they participate in the visibility 
 /// tests
 /// tests
-class Spatial: public Flags<uint32_t>
+class Spatial: public Flags<U32>
 {
 {
 public:
 public:
 	/// Spatial flags
 	/// Spatial flags

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

@@ -1,6 +1,7 @@
 #ifndef ANKI_UTIL_ARRAY_H
 #ifndef ANKI_UTIL_ARRAY_H
 #define ANKI_UTIL_ARRAY_H
 #define ANKI_UTIL_ARRAY_H
 
 
+#include "anki/util/Assert.h"
 #include <array>
 #include <array>
 
 
 namespace anki {
 namespace anki {
@@ -8,7 +9,26 @@ namespace anki {
 /// @addtogroup util
 /// @addtogroup util
 /// @{
 /// @{
 template<typename T, size_t size>
 template<typename T, size_t size>
-using Array = std::array<T, size>;
+class Array: public std::array<T, size>
+{
+public:
+	typedef std::array<T, size> Base;
+
+#if !NDEBUG
+	typename Base::reference operator[](typename Base::size_type n)
+	{
+		ANKI_ASSERT(n < Base::size());
+		return Base::operator[](n);
+	}
+
+	typename Base::const_reference operator[](
+		typename Base::size_type n) const
+	{
+		ANKI_ASSERT(n < Base::size());
+		return Base::operator[](n);
+	}
+#endif
+};
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 33 - 12
shaders/IsLpGeneric.glsl

@@ -10,21 +10,15 @@
 
 
 #pragma anki include "shaders/Pack.glsl"
 #pragma anki include "shaders/Pack.glsl"
 
 
+#if !MAX_LIGHTS_PER_TILE || !TILES_X_COUNT || !TILES_Y_COUNT || !TILES_COUNT
+#	error "See file"
+#endif
+
 /// @name Uniforms
 /// @name Uniforms
 /// @{
 /// @{
 
 
-struct Light
-{
-	vec4 posAndRadius; ///< xyz: Light pos in eye space. w: The radius
-	vec4 diffuseColor;
-	vec4 specularColor;
-#if SPOT_LIGHT
-	mat4 texProjectionMat;
-#endif
-};
-
 // Common uniforms between lights
 // Common uniforms between lights
-layout(std140, row_major) uniform generalBlock
+layout(std140, row_major, binding = 0) uniform commonBlock
 {
 {
 	/// Packs:
 	/// Packs:
 	/// - x: zNear. For the calculation of frag pos in view space
 	/// - x: zNear. For the calculation of frag pos in view space
@@ -42,6 +36,32 @@ layout(std140, row_major) uniform generalBlock
 #define limitsOfNearPlane limitsOfNearPlane_.xy
 #define limitsOfNearPlane limitsOfNearPlane_.xy
 #define limitsOfNearPlane2 limitsOfNearPlane_.zw
 #define limitsOfNearPlane2 limitsOfNearPlane_.zw
 
 
+struct Light
+{
+	vec4 posAndRadius; ///< xyz: Light pos in eye space. w: The radius
+	vec4 diffuseColor;
+	vec4 specularColor;
+#if SPOT_LIGHT
+	mat4 texProjectionMat;
+#endif
+};
+
+layout(std140, row_major, binding = 1) uniform lightsBlock
+{
+	Light lights[MAX_LIGHTS];
+};
+
+struct Tile
+{
+	uint lightsCount;
+	uvec4 lightIndices[MAX_LIGHTS_PER_TILE / 4];
+};
+
+layout(std140, row_major, binding = 2) uniform tilesBlock
+{
+	Tile tiles[TILES_X_COUNT * TILES_Y_COUNT];
+};
+
 uniform usampler2D msFai0;
 uniform usampler2D msFai0;
 uniform sampler2D msDepthFai;
 uniform sampler2D msDepthFai;
 uniform sampler2D lightTex;
 uniform sampler2D lightTex;
@@ -51,6 +71,7 @@ uniform sampler2DShadow shadowMap;
 /// @name Varyings
 /// @name Varyings
 /// @{
 /// @{
 in vec2 vTexCoords;
 in vec2 vTexCoords;
+flat in uint vInstanceId;
 /// @}
 /// @}
 
 
 /// @name Output
 /// @name Output
@@ -60,5 +81,5 @@ out vec3 fColor;
 
 
 void main()
 void main()
 {
 {
-	fColor = vec3(vTexCoords, 0.0);
+	fColor = vec3(0.0, float(tiles[vInstanceId].lightsCount), 0.0);
 }
 }

+ 3 - 0
shaders/IsLpVertex.glsl

@@ -5,6 +5,7 @@
 layout(location = 0) in vec2 position;
 layout(location = 0) in vec2 position;
 
 
 out vec2 vTexCoords;
 out vec2 vTexCoords;
+flat out uint vInstanceId;
 
 
 void main()
 void main()
 {
 {
@@ -12,6 +13,8 @@ void main()
 		float(gl_InstanceID % TILES_X_COUNT), 
 		float(gl_InstanceID % TILES_X_COUNT), 
 		float(gl_InstanceID / TILES_X_COUNT));
 		float(gl_InstanceID / TILES_X_COUNT));
 
 
+	vInstanceId = gl_InstanceID;
+
 	const vec2 SIZES = vec2(1.0 / TILES_X_COUNT, 1.0 / TILES_Y_COUNT);
 	const vec2 SIZES = vec2(1.0 / TILES_X_COUNT, 1.0 / TILES_Y_COUNT);
 
 
 	vTexCoords = (position + ij) * SIZES;
 	vTexCoords = (position + ij) * SIZES;

+ 47 - 4
src/collision/Frustum.cpp

@@ -117,14 +117,14 @@ void PerspectiveFrustum::recalculate()
 	//
 	//
 	F32 c, s; // cos & sine
 	F32 c, s; // cos & sine
 
 
-	Math::sinCos(Math::PI + fovX / 2, s, c);
+	Math::sinCos(Math::PI + fovX / 2.0, s, c);
 	// right
 	// right
 	planes[FP_RIGHT] = Plane(Vec3(c, 0.0, s), 0.0);
 	planes[FP_RIGHT] = Plane(Vec3(c, 0.0, s), 0.0);
 	// left
 	// left
 	planes[FP_LEFT] = Plane(Vec3(-c, 0.0, s), 0.0);
 	planes[FP_LEFT] = Plane(Vec3(-c, 0.0, s), 0.0);
 
 
 #if 0
 #if 0
-	Math::sinCos((3 * Math::PI - fovY) * 0.5, s, c);
+	Math::sinCos((3.0 * Math::PI - fovY) * 0.5, s, c);
 	// top
 	// top
 	planes[FP_TOP] = Plane(Vec3(0.0, s, c), 0.0);
 	planes[FP_TOP] = Plane(Vec3(0.0, s, c), 0.0);
 	// bottom
 	// bottom
@@ -164,13 +164,14 @@ void PerspectiveFrustum::recalculate()
 //==============================================================================
 //==============================================================================
 Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 {
 {
-	ANKI_ASSERT(fovX != 0.0 && fovX != 0.0);
+	ANKI_ASSERT(fovX != 0.0 && fovY != 0.0);
 	Mat4 projectionMat;
 	Mat4 projectionMat;
 
 
+#if 0
 	F32 f = 1.0 / tan(fovY * 0.5); // f = cot(fovY/2)
 	F32 f = 1.0 / tan(fovY * 0.5); // f = cot(fovY/2)
 	F32 g = near - far;
 	F32 g = near - far;
 
 
-	projectionMat(0, 0) = f * fovY / fovX; // = f/aspectRatio;
+	projectionMat(0, 0) = f * (fovY / fovX); // = f/aspectRatio;
 	projectionMat(0, 1) = 0.0;
 	projectionMat(0, 1) = 0.0;
 	projectionMat(0, 2) = 0.0;
 	projectionMat(0, 2) = 0.0;
 	projectionMat(0, 3) = 0.0;
 	projectionMat(0, 3) = 0.0;
@@ -186,6 +187,48 @@ Mat4 PerspectiveFrustum::calculateProjectionMatrix() const
 	projectionMat(3, 1) = 0.0;
 	projectionMat(3, 1) = 0.0;
 	projectionMat(3, 2) = -1.0;
 	projectionMat(3, 2) = -1.0;
 	projectionMat(3, 3) = 0.0;
 	projectionMat(3, 3) = 0.0;
+#else
+	/*F32 size = near * tanf(fovX / 2.0);
+	F32 a = fovX / fovY;
+	F32 left = -size, right = size, bottom = -size / a, top = size / a;
+
+	projectionMat(0, 0) = 2 * near / (right - left);
+	projectionMat(0, 1) = 0.0;
+	projectionMat(0, 2) = 0.0;
+	projectionMat(0, 3) = 0.0;
+	projectionMat(1, 0) = 0.0;
+	projectionMat(1, 1) = 2 * near / (top - bottom);
+	projectionMat(1, 2) = 0.0;
+	projectionMat(1, 3) = 0.0;
+	projectionMat(2, 0) = (right + left) / (right - left);
+	projectionMat(2, 1) = (top + bottom) / (top - bottom);
+	projectionMat(2, 2) = -(far + near) / (far - near);
+	projectionMat(2, 3) = -1;
+	projectionMat(3, 0) = 0.0;
+	projectionMat(3, 1) = 0.0;
+	projectionMat(3, 2) = -(2 * far * near) / (far - near);
+	projectionMat(3, 3) = 0.0;*/
+
+	F32 e = 1.0 / tanf(fovX / 2.0);
+	F32 a = fovY / fovX;
+
+	projectionMat(0, 0) = e;
+	projectionMat(0, 1) = 0.0;
+	projectionMat(0, 2) = 0.0;
+	projectionMat(0, 3) = 0.0;
+	projectionMat(1, 0) = 0.0;
+	projectionMat(1, 1) = e / a;
+	projectionMat(1, 2) = 0.0;
+	projectionMat(1, 3) = 0.0;
+	projectionMat(2, 0) = 0.0;
+	projectionMat(2, 1) = 0.0;
+	projectionMat(2, 2) = -(far + near) / (far - near);
+	projectionMat(2, 3) = (2.0 * far * near) / (near - far);
+	projectionMat(3, 0) = 0.0;
+	projectionMat(3, 1) = 0.0;
+	projectionMat(3, 2) = -1.0;
+	projectionMat(3, 3) = 0.0;
+#endif
 
 
 	return projectionMat;
 	return projectionMat;
 }
 }

+ 8 - 0
src/gl/BufferObject.cpp

@@ -55,18 +55,26 @@ void BufferObject::create(GLenum target_, U32 sizeInBytes_,
 //==============================================================================
 //==============================================================================
 void* BufferObject::map(U32 offset, U32 length, GLuint flags)
 void* BufferObject::map(U32 offset, U32 length, GLuint flags)
 {
 {
+	ANKI_ASSERT(mapped == false);
 	bind();
 	bind();
 	ANKI_ASSERT(offset + length <= sizeInBytes);
 	ANKI_ASSERT(offset + length <= sizeInBytes);
 	void* mappedMem = glMapBufferRange(target, offset, length, flags);
 	void* mappedMem = glMapBufferRange(target, offset, length, flags);
 	ANKI_ASSERT(mappedMem != nullptr);
 	ANKI_ASSERT(mappedMem != nullptr);
+#if !NDEBUG
+	mapped = true;
+#endif
 	return mappedMem;
 	return mappedMem;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void BufferObject::unmap()
 void BufferObject::unmap()
 {
 {
+	ANKI_ASSERT(mapped == true);
 	bind();
 	bind();
 	glUnmapBuffer(target);
 	glUnmapBuffer(target);
+#if !NDEBUG
+	mapped = false;
+#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 5 - 4
src/math/Math.cpp

@@ -2,10 +2,6 @@
 
 
 namespace anki {
 namespace anki {
 
 
-//==============================================================================
-const F32 Math::PI = 3.14159265358979323846;
-const F32 Math::EPSILON = 1.0e-6;
-
 //==============================================================================
 //==============================================================================
 F32 Math::polynomialSinQuadrant(const F32 a)
 F32 Math::polynomialSinQuadrant(const F32 a)
 {
 {
@@ -16,6 +12,7 @@ F32 Math::polynomialSinQuadrant(const F32 a)
 //==============================================================================
 //==============================================================================
 void Math::sinCos(const F32 a_, F32& sina, F32& cosa)
 void Math::sinCos(const F32 a_, F32& sina, F32& cosa)
 {
 {
+#if NDEBUG
 	Bool negative = false;
 	Bool negative = false;
 	F32 a = a_;
 	F32 a = a_;
 	if(a < 0.0)
 	if(a < 0.0)
@@ -58,6 +55,10 @@ void Math::sinCos(const F32 a_, F32& sina, F32& cosa)
 	{
 	{
 		sina = -sina;
 		sina = -sina;
 	}
 	}
+#else
+	sina = ::sin(a_);
+	cosa = ::cos(a_);
+#endif
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 72 - 1
src/renderer/Dbg.cpp

@@ -2,6 +2,7 @@
 #include "anki/renderer/Renderer.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/resource/ShaderProgramResource.h"
 #include "anki/resource/ShaderProgramResource.h"
 #include "anki/scene/Scene.h"
 #include "anki/scene/Scene.h"
+#include "anki/scene/Light.h"
 #include "anki/core/Logger.h"
 #include "anki/core/Logger.h"
 
 
 namespace anki {
 namespace anki {
@@ -53,7 +54,9 @@ void Dbg::run()
 
 
 	drawer->setViewProjectionMatrix(r->getViewProjectionMatrix());
 	drawer->setViewProjectionMatrix(r->getViewProjectionMatrix());
 	drawer->setModelMatrix(Mat4::getIdentity());
 	drawer->setModelMatrix(Mat4::getIdentity());
-	drawer->drawGrid();
+	//drawer->drawGrid();
+
+	PointLight* deleteme;
 
 
 	for(auto it = scene.getAllNodesBegin(); it != scene.getAllNodesEnd(); it++)
 	for(auto it = scene.getAllNodesBegin(); it != scene.getAllNodesEnd(); it++)
 	{
 	{
@@ -64,6 +67,17 @@ void Dbg::run()
 		}
 		}
 
 
 		sceneDrawer->draw(*node);
 		sceneDrawer->draw(*node);
+
+		// XXX
+		if(node->getLight())
+		{
+			CollisionDebugDrawer cdd(drawer.get());
+			Light& l = *node->getLight();
+			l.getLightType();
+			PointLight& pl = static_cast<PointLight&>(l);
+			deleteme = &pl;
+			pl.getSphere().accept(cdd);
+		}
 	}
 	}
 
 
 	for(const Sector* sector : scene.sectors)
 	for(const Sector* sector : scene.sectors)
@@ -71,6 +85,62 @@ void Dbg::run()
 		sceneDrawer->draw(sector->getOctree());
 		sceneDrawer->draw(sector->getOctree());
 	}
 	}
 
 
+	// XXX
+	drawer->setViewProjectionMatrix(r->getViewProjectionMatrix());
+	drawer->setModelMatrix(Mat4::getIdentity());
+
+	Camera* camera1 = static_cast<Camera*>(scene.findSceneNode("camera1"));
+
+	F32 fx = static_cast<PerspectiveCamera*>(camera1)->getFovX();
+	F32 fy = static_cast<PerspectiveCamera*>(camera1)->getFovY();
+
+	//std::cout << fx << " " << fy << std::endl;
+
+	Vec3 a(0.0);
+	F32 s, c;
+	Math::sinCos(Math::PI / 2 - fx / 2, s, c);
+	Vec3 b(c, 0.0, -s);
+
+	a.transform(camera1->getWorldTransform());
+	b.transform(camera1->getWorldTransform());
+
+	drawer->drawLine(a, b, Vec4(1));
+
+	Math::sinCos(fy / 2, s, c);
+	b = Vec3(0.0, s, -c);
+	b.transform(camera1->getWorldTransform());
+
+	drawer->drawLine(a, b, Vec4(1));
+
+#if 0
+	{
+	PerspectiveFrustum fr =
+		static_cast<const PerspectiveFrustum&>(scene.getActiveCamera().getFrustumable()->getFrustum());
+
+	fr.setTransform(Transform::getIdentity());
+
+	CollisionDebugDrawer cdd(drawer.get());
+	fr.accept(cdd);
+	}
+
+	for(U j = 0; j < 1; j++)
+	{
+		for(U i = 0; i < 16; i++)
+		{
+			Is::Tile& tile = r->getIs().tiles[j][i];
+
+			Mat4 vmat = scene.getActiveCamera().getViewMatrix();
+
+			CollisionDebugDrawer cdd(drawer.get());
+			tile.planes[Frustum::FP_LEFT].accept(cdd);
+			tile.planes[Frustum::FP_RIGHT].accept(cdd);
+			//tile.planes[Frustum::FP_BOTTOM].accept(cdd);
+			//tile.planes[Frustum::FP_TOP].accept(cdd);
+		}
+	}
+#endif
+
+#if 0
 	// XXX Remove these
 	// XXX Remove these
 	CollisionDebugDrawer cdd(drawer.get());
 	CollisionDebugDrawer cdd(drawer.get());
 	Sphere s(Vec3(90.0, 4.0, 0.0), 2.0);
 	Sphere s(Vec3(90.0, 4.0, 0.0), 2.0);
@@ -120,6 +190,7 @@ void Dbg::run()
 
 
 	drawer->drawLine(Vec3(circleCenter, 0.0),
 	drawer->drawLine(Vec3(circleCenter, 0.0),
 		Vec3(circleCenter, 0.0) + Vec3(circleRadius, 0.0, 0.0), Vec4(0.0, 1.0, 1.0, 0.0));
 		Vec3(circleCenter, 0.0) + Vec3(circleRadius, 0.0, 0.0), Vec4(0.0, 1.0, 1.0, 0.0));
+#endif
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 1
src/renderer/Drawer.cpp

@@ -443,7 +443,8 @@ void SceneDebugDrawer::draw(SceneNode& node)
 	}
 	}
 
 
 	Spatial* sp;
 	Spatial* sp;
-	if(isFlagEnabled(DF_SPATIAL) && (sp = node.getSpatial()))
+	if(isFlagEnabled(DF_SPATIAL) && (sp = node.getSpatial())
+		&& sp->isFlagEnabled(Spatial::SF_VISIBLE))
 	{
 	{
 		draw(*sp);
 		draw(*sp);
 	}
 	}

+ 130 - 102
src/renderer/Is.cpp

@@ -39,6 +39,7 @@ struct ShaderSpotLights
 struct ShaderTile
 struct ShaderTile
 {
 {
 	U32 lightsCount;
 	U32 lightsCount;
+	U32 padding[3];
 	Array<U32, Is::MAX_LIGHTS_PER_TILE> lightIndices;
 	Array<U32, Is::MAX_LIGHTS_PER_TILE> lightIndices;
 };
 };
 
 
@@ -90,7 +91,12 @@ void Is::initInternal(const RendererInitializer& initializer)
 		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
 		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
 		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n"
 		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n"
 		"#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
 		"#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
-		"#define RENDERER_HEIGHT " + std::to_string(r->getWidth()) + "\n";
+		"#define RENDERER_HEIGHT " + std::to_string(r->getWidth()) + "\n"
+		"#define MAX_LIGHTS_PER_TILE " + std::to_string(MAX_LIGHTS_PER_TILE)
+		+ "\n"
+		"#define TILES_COUNT " + std::to_string(TILES_X_COUNT * TILES_Y_COUNT)
+		+ "\n"
+		"#define MAX_LIGHTS " + std::to_string(MAX_LIGHTS) + "\n";
 
 
 	// point light
 	// point light
 	lightSProgs[LST_POINT].load(ShaderProgramResource::createSrcCodeToCache(
 	lightSProgs[LST_POINT].load(ShaderProgramResource::createSrcCodeToCache(
@@ -158,91 +164,58 @@ void Is::initInternal(const RendererInitializer& initializer)
 
 
 	// lights UBO
 	// lights UBO
 	lightsUbo.create(sizeof(ShaderSpotLights), nullptr);
 	lightsUbo.create(sizeof(ShaderSpotLights), nullptr);
-	commonUbo.setBinding(1);
+	lightsUbo.setBinding(1);
 
 
 	// lightIndices UBO
 	// lightIndices UBO
-	lightIndicesUbo.create(sizeof(ShaderTiles), nullptr);
-	commonUbo.setBinding(2);
+	tilesUbo.create(sizeof(ShaderTiles), nullptr);
+	tilesUbo.setBinding(2);
 
 
-	//
-	// Init tiles
-	//
-	F32 tileW = 1.0 / TILES_X_COUNT;
-	F32 tileH = 1.0 / TILES_Y_COUNT;
+	// Sanity checks
+	const ShaderProgramUniformBlock* ublock;
 
 
-	for(U j = 0; j < TILES_Y_COUNT; j++)
+	ublock = &lightSProgs[LST_POINT]->findUniformBlock("commonBlock");
+	if(ublock->getSize() != sizeof(ShaderCommonUniforms)
+		|| ublock->getBindingPoint() != 0)
 	{
 	{
-		for(U i = 0; i < TILES_X_COUNT; i++)
-		{
-			F32 x = i * tileW;
-			F32 y = j * tileH;
+		throw ANKI_EXCEPTION("Problem with the commonBlock");
+	}
 
 
-			tiles[j][i].coords[0] = Vec2(x, y) * 2.0 - 1.0;
-			tiles[j][i].coords[1] = Vec2(x + tileW, y + tileH) * 2.0 - 1.0;
-		}
+	ublock = &lightSProgs[LST_POINT]->findUniformBlock("lightsBlock");
+	if(ublock->getSize() != sizeof(ShaderPointLights)
+		|| ublock->getBindingPoint() != 1)
+	{
+		throw ANKI_EXCEPTION("Problem with the lightsBlock");
+	}
+
+	ublock = &lightSProgs[LST_POINT]->findUniformBlock("tilesBlock");
+	if(ublock->getSize() != sizeof(ShaderTiles)
+		|| ublock->getBindingPoint() != 2)
+	{
+		throw ANKI_EXCEPTION("Problem with the tilesBlock");
 	}
 	}
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::projectShape(const Camera& cam,
-	const Sphere& sphere, Vec2& circleCenter, F32& circleRadius)
+Bool Is::cullLight(const PointLight& plight, const Tile& tile)
 {
 {
-	F32 r = sphere.getRadius();
-	Vec4 c(sphere.getCenter(), 1.0);
-	Vec4 a = Vec4(sphere.getCenter()
-		+ cam.getWorldTransform().getRotation() * Vec3(r, 0.0, 0.0), 1.0);
-
-	c = cam.getViewProjectionMatrix() * c;
-	c /= c.w();
-
-	a = cam.getViewProjectionMatrix() * a;
-	a /= a.w();
+	Camera& cam = r->getScene().getActiveCamera();
+	Sphere sphere = plight.getSphere();
 
 
-	circleCenter = c.xy();
-	circleRadius = (c.xy() - a.xy()).getLength();
-}
+	return cam.getFrustumable()->getFrustum().insideFrustum(sphere);
 
 
-//==============================================================================
-Bool Is::circleIntersects(const Tile& tile, const Vec2& c, F32 r)
-{
-	// For more info about the algorithm see the collision between an AABB and
-	// a sphere
+#if 0
+	sphere.transform(Transform(cam.getViewMatrix()));
 
 
-	Vec2 cp; // Closes point
-	for(U i = 0; i < 2; i++)
+	for(const Plane& plane : tile.planes)
 	{
 	{
-		if(c[i] > tile.coords[1][i])
+		if(sphere.testPlane(plane) < 0.0)
 		{
 		{
-			cp[i] = tile.coords[1][i];
-		}
-		else if(c[i] < tile.coords[0][i])
-		{
-			cp[i] = tile.coords[0][i];
-		}
-		else
-		{
-			cp[i] = c[i];
+			return false;
 		}
 		}
 	}
 	}
 
 
-	F32 rsq = r * r;
-	Vec2 sub = c - cp;
-
-	if(sub.getLengthSquared() <= rsq)
-	{
-		return true;
-	}
-
-	return false;
-}
-
-//==============================================================================
-Bool Is::cullLight(const PointLight& plight, const Tile& tile)
-{
-	Vec2 cc;
-	F32 rad;
-	projectShape(r->getScene().getActiveCamera(), plight.getSphere(), cc, rad);
-	return circleIntersects(tile, cc, rad);
+	return true;
+#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -251,12 +224,14 @@ void Is::updateAllTilesPlanes(const PerspectiveCamera& cam)
 	// The algorithm is almost the same as the recalculation of planes for
 	// The algorithm is almost the same as the recalculation of planes for
 	// PerspectiveFrustum class
 	// PerspectiveFrustum class
 
 
-	// Algorithm works for even number of tiles per dimention
+	// Algorithm works for even number of tiles per dimension
 	ANKI_ASSERT(TILES_X_COUNT % 2 == 0 && TILES_Y_COUNT % 2 == 0);
 	ANKI_ASSERT(TILES_X_COUNT % 2 == 0 && TILES_Y_COUNT % 2 == 0);
 
 
-	F32 fovX = cam.getFovX();
-	F32 fovY = cam.getFovY();
+	F32 fx = cam.getFovX();
+	F32 fy = cam.getFovY();
+	F32 n = cam.getNear();
 
 
+#if 0
 	// Opts
 	// Opts
 	F32 piAddfovXDiv2 = Math::PI + fovX / 2.0;
 	F32 piAddfovXDiv2 = Math::PI + fovX / 2.0;
 	F32 piAddFovYDiv2 = (Math::PI + fovY) * 0.5;
 	F32 piAddFovYDiv2 = (Math::PI + fovY) * 0.5;
@@ -265,11 +240,33 @@ void Is::updateAllTilesPlanes(const PerspectiveCamera& cam)
 	F32 fovXFragment = fovX / TILES_X_COUNT;
 	F32 fovXFragment = fovX / TILES_X_COUNT;
 	// See above
 	// See above
 	F32 fovYFragment = fovY / TILES_Y_COUNT;
 	F32 fovYFragment = fovY / TILES_Y_COUNT;
+#endif
+
+	F32 l = 2.0 * n * tan(fx / 2.0);
+	F32 l6 = l / TILES_X_COUNT;
 
 
-	for(U j = 0; j < TILES_Y_COUNT / 2; j++)
+	for(U j = 0; j < TILES_Y_COUNT; j++)
 	{
 	{
-		for(U i = 0; i < TILES_X_COUNT / 2; i++)
+		for(U i = 0; i < TILES_X_COUNT; i++)
 		{
 		{
+			Array<Plane, Frustum::FP_COUNT>& planes = tiles[j][i].planes;
+			Vec3 a, b;
+
+			// left
+			a = Vec3((I(i) - I(TILES_X_COUNT) / 2) * l6, 0.0, -n);
+			b = a.cross(Vec3(0.0, 1.0, 0.0));
+			b.normalize();
+
+			planes[Frustum::FP_LEFT] = Plane(b, 0.0);
+
+			// right
+			a = Vec3((I(i) - I(TILES_X_COUNT) / 2 + 1) * l6, 0.0, -n);
+			b = Vec3(0.0, 1.0, 0.0).cross(a);
+			b.normalize();
+
+			planes[Frustum::FP_RIGHT] = Plane(b, 0.0);
+
+#if 0
 			F32 c, s; // cos & sin
 			F32 c, s; // cos & sin
 
 
 			// Calc planes for one of those tiles:
 			// Calc planes for one of those tiles:
@@ -282,19 +279,23 @@ void Is::updateAllTilesPlanes(const PerspectiveCamera& cam)
 			// +-+-+-+-+
 			// +-+-+-+-+
 			// |x|x| | |
 			// |x|x| | |
 			// +-+-+-+-+
 			// +-+-+-+-+
-			Array<Plane, 6>& planes = tiles[j][i].planes;
+			Array<Plane, Frustum::FP_COUNT>& planes = tiles[j][i].planes;
 			
 			
-			Math::sinCos(piAddfovXDiv2 - i * fovXFragment, s, c);
 			// right
 			// right
+			Math::sinCos(piAddfovXDiv2 - (TILES_X_COUNT - i - 1) * fovXFragment, s, c);
 			planes[Frustum::FP_RIGHT] = Plane(Vec3(c, 0.0, s), 0.0);
 			planes[Frustum::FP_RIGHT] = Plane(Vec3(c, 0.0, s), 0.0);
 			// left
 			// left
-			planes[Frustum::FP_LEFT] = Plane(Vec3(-c, 0.0, s), 0.0);
+			Math::sinCos(-fovX / 2.0 + i * fovXFragment, s, c);
+			planes[Frustum::FP_LEFT] = Plane(Vec3(c, 0.0, s), 0.0);
 
 
-			Math::sinCos(piAddFovYDiv2 - j * fovYFragment, s, c);
 			// bottom
 			// bottom
+			Math::sinCos(piAddFovYDiv2 - j * fovYFragment, s, c);
 			planes[Frustum::FP_BOTTOM] = Plane(Vec3(0.0, s, c), 0.0);
 			planes[Frustum::FP_BOTTOM] = Plane(Vec3(0.0, s, c), 0.0);
 			// top
 			// top
-			planes[Frustum::FP_TOP] = Plane(Vec3(0.0, -s, c), 0.0);
+			Math::sinCos((3.0 * Math::PI - fovY) / 2 + (TILES_Y_COUNT - j - 1) * fovYFragment, s, c);
+			planes[Frustum::FP_TOP] = Plane(Vec3(0.0, s, c), 0.0);
+
+			continue;
 
 
 			// Mirror planes for those tiles:
 			// Mirror planes for those tiles:
 			// +-+-+-+-+
 			// +-+-+-+-+
@@ -360,6 +361,7 @@ void Is::updateAllTilesPlanes(const PerspectiveCamera& cam)
 
 
 			planes4[Frustum::FP_BOTTOM] = planes3[Frustum::FP_BOTTOM];
 			planes4[Frustum::FP_BOTTOM] = planes3[Frustum::FP_BOTTOM];
 			planes4[Frustum::FP_TOP] = planes3[Frustum::FP_TOP];
 			planes4[Frustum::FP_TOP] = planes3[Frustum::FP_TOP];
+#endif
 		}
 		}
 	}
 	}
 }
 }
@@ -370,26 +372,28 @@ void Is::updateAllTilesPlanes()
 	Camera& cam = r->getScene().getActiveCamera();
 	Camera& cam = r->getScene().getActiveCamera();
 	U32 camTimestamp = cam.getFrustumable()->getFrustumableTimestamp();
 	U32 camTimestamp = cam.getFrustumable()->getFrustumableTimestamp();
 
 
-	if(camTimestamp <= planesUpdateTimestamp)
+	if(camTimestamp < planesUpdateTimestamp)
 	{
 	{
 		return;
 		return;
 	}
 	}
 
 
 	switch(cam.getCameraType())
 	switch(cam.getCameraType())
 	{
 	{
-		case Camera::CT_PERSPECTIVE:
-			updateAllTilesPlanes(static_cast<const PerspectiveCamera&>(cam));
-			break;
-		default:
-			ANKI_ASSERT(0 && "Unimplemented");
-			break;
+	case Camera::CT_PERSPECTIVE:
+		updateAllTilesPlanes(static_cast<const PerspectiveCamera&>(cam));
+		break;
+	default:
+		ANKI_ASSERT(0 && "Unimplemented");
+		break;
 	}
 	}
+
+	planesUpdateTimestamp = Timestamp::getTimestamp();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::minMaxPass()
+void Is::updateTiles()
 {
 {
-	// Do the pass
+	// Do the min/max pass
 	//
 	//
 	const Camera& cam = r->getScene().getActiveCamera();
 	const Camera& cam = r->getScene().getActiveCamera();
 
 
@@ -405,10 +409,14 @@ void Is::minMaxPass()
 
 
 	r->drawQuad();
 	r->drawQuad();
 
 
-	// Update the tiles
+	// Do something else instead of waiting for the draw call to finish.
+	// Update the tile planes
 	//
 	//
-	F32 pixels[TILES_Y_COUNT][TILES_X_COUNT][2];
+	updateAllTilesPlanes();
 
 
+	// Update the near and far planes of tiles
+	//
+	F32 pixels[TILES_Y_COUNT][TILES_X_COUNT][2];
 	minMaxFai.readPixels(pixels);
 	minMaxFai.readPixels(pixels);
 
 
 	for(U j = 0; j < TILES_Y_COUNT; j++)
 	for(U j = 0; j < TILES_Y_COUNT; j++)
@@ -416,7 +424,18 @@ void Is::minMaxPass()
 		for(U i = 0; i < TILES_X_COUNT; i++)
 		for(U i = 0; i < TILES_X_COUNT; i++)
 		{
 		{
 			Tile& tile = tiles[j][i];
 			Tile& tile = tiles[j][i];
-			tile.depth = Vec2(pixels[j][i][0], pixels[j][i][1]);
+#if 0
+			F32 minZ =
+				-r->getPlanes().y() / (r->getPlanes().x() + pixels[j][i][0]);
+			F32 maxZ =
+				-r->getPlanes().y() / (r->getPlanes().x() + pixels[j][i][1]);
+#else
+			F32 minZ = -cam.getNear();
+			F32 maxZ = -cam.getFar();
+#endif
+
+			tile.planes[Frustum::FP_NEAR] = Plane(Vec3(0.0, 0.0, -1.0), -minZ);
+			tile.planes[Frustum::FP_FAR] = Plane(Vec3(0.0, 0.0, 1.0), maxZ);
 		}
 		}
 	}
 	}
 }
 }
@@ -442,8 +461,13 @@ void Is::pointLightsPass()
 		}
 		}
 	}
 	}
 
 
+	if(pointLightsCount > MAX_LIGHTS)
+	{
+		throw ANKI_EXCEPTION("Too many lights");
+	}
+
 	// Map
 	// Map
-	ShaderPointLight* lightsMappedBuff = (ShaderPointLight*)lightsUbo.map(
+	ShaderPointLights* lightsMappedBuff = (ShaderPointLights*)lightsUbo.map(
 		0, 
 		0, 
 		sizeof(ShaderPointLight) * pointLightsCount,
 		sizeof(ShaderPointLight) * pointLightsCount,
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
@@ -455,7 +479,7 @@ void Is::pointLightsPass()
 		const Light& light = *(*it);
 		const Light& light = *(*it);
 		if(light.getLightType() == Light::LT_POINT)
 		if(light.getLightType() == Light::LT_POINT)
 		{
 		{
-			ShaderPointLight& pl = lightsMappedBuff[pointLightsCount];
+			ShaderPointLight& pl = lightsMappedBuff->lights[pointLightsCount];
 			const PointLight& plight = static_cast<const PointLight&>(light);
 			const PointLight& plight = static_cast<const PointLight&>(light);
 
 
 			Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
 			Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
@@ -472,7 +496,7 @@ void Is::pointLightsPass()
 	// Done
 	// Done
 	lightsUbo.unmap();
 	lightsUbo.unmap();
 
 
-#if 0
+#if 1
 	//
 	//
 	// Update the tiles
 	// Update the tiles
 	//
 	//
@@ -501,23 +525,27 @@ void Is::pointLightsPass()
 
 
 				if(cullLight(plight, tile))
 				if(cullLight(plight, tile))
 				{
 				{
-					tile.lightIndices[ids] = lightsInTileCount;
-					++ids;
+					tile.lightIndices[lightsInTileCount] = ids;
+					++lightsInTileCount;
 				}
 				}
 
 
-				++lightsInTileCount;
+				++ids;
 			}
 			}
 
 
+			/*if(lightsInTileCount > MAX_LIGHTS_PER_TILE)
+			{
+				throw ANKI_EXCEPTION("Too many lights per tile");
+			}*/
+
 			tile.lightsCount = lightsInTileCount;
 			tile.lightsCount = lightsInTileCount;
 		}
 		}
 	}
 	}
 #endif
 #endif
 
 
 	//
 	//
-	// Write the lightIndicesUbo
+	// Write the tilesUbo
 	//
 	//
-
-	ShaderTiles* stiles = (ShaderTiles*)lightIndicesUbo.map(
+	ShaderTiles* stiles = (ShaderTiles*)tilesUbo.map(
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
 
 
 	for(U j = 0; j < TILES_Y_COUNT; j++)
 	for(U j = 0; j < TILES_Y_COUNT; j++)
@@ -527,14 +555,14 @@ void Is::pointLightsPass()
 			const Tile& tile = tiles[j][i];
 			const Tile& tile = tiles[j][i];
 			stiles->tiles[j][i].lightsCount = tile.lightsCount;
 			stiles->tiles[j][i].lightsCount = tile.lightsCount;
 
 
-			for(U k = 0; k < tile.lightsCount; k++)
+			/*for(U k = 0; k < tile.lightsCount; k++)
 			{
 			{
 				stiles->tiles[j][i].lightIndices[k] = tile.lightIndices[k];
 				stiles->tiles[j][i].lightIndices[k] = tile.lightIndices[k];
-			}
+			}*/
 		}
 		}
 	}
 	}
 
 
-	lightIndicesUbo.unmap();
+	tilesUbo.unmap();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -543,7 +571,7 @@ void Is::run()
 	GlStateSingleton::get().disable(GL_DEPTH_TEST);
 	GlStateSingleton::get().disable(GL_DEPTH_TEST);
 	GlStateSingleton::get().disable(GL_BLEND);
 	GlStateSingleton::get().disable(GL_BLEND);
 
 
-	minMaxPass();
+	updateTiles();
 
 
 	fbo.bind();
 	fbo.bind();
 	GlStateSingleton::get().setViewport(0, 0, r->getWidth(), r->getHeight());
 	GlStateSingleton::get().setViewport(0, 0, r->getWidth(), r->getHeight());

+ 6 - 0
src/scene/Scene.cpp

@@ -40,6 +40,12 @@ void Scene::update(float prevUpdateTime, float crntTime)
 		{
 		{
 			m->update();
 			m->update();
 		}
 		}
+
+		Spatial* sp = n->getSpatial();
+		if(sp)
+		{
+			sp->disableFlag(Spatial::SF_VISIBLE);
+		}
 	}
 	}
 
 
 	// Then the rest
 	// Then the rest

+ 21 - 7
testapp/Main.cpp

@@ -59,7 +59,7 @@ void init()
 	// camera
 	// camera
 	cam = new PerspectiveCamera("main-camera", &scene,
 	cam = new PerspectiveCamera("main-camera", &scene,
 		Movable::MF_NONE, nullptr);
 		Movable::MF_NONE, nullptr);
-	const float ang = 70.0;
+	const float ang = 45.0;
 	cam->setAll(
 	cam->setAll(
 		MainRendererSingleton::get().getAspectRatio() * Math::toRad(ang),
 		MainRendererSingleton::get().getAspectRatio() * Math::toRad(ang),
 		Math::toRad(ang), 0.5, 200.0);
 		Math::toRad(ang), 0.5, 200.0);
@@ -68,11 +68,21 @@ void init()
 		1.0));
 		1.0));
 	scene.setActiveCamera(cam);
 	scene.setActiveCamera(cam);
 
 
+	// camera 2
+	PerspectiveCamera* pcam = new PerspectiveCamera("camera1", &scene,
+		Movable::MF_NONE, nullptr);
+	pcam->setAll(
+		MainRendererSingleton::get().getAspectRatio() * Math::toRad(ang),
+		Math::toRad(ang), 0.5, 200.0);
+	pcam->setLocalTransform(Transform(Vec3(100.0, 3.0, 8.0),
+		Mat3(Axisang(Math::toRad(90), Vec3(0, 1, 0))),
+		1.0));
+
 	// lights
 	// lights
 	Vec3 lpos(-100.0, 0.0, 0.0);
 	Vec3 lpos(-100.0, 0.0, 0.0);
-	for(int i = 0; i < 100; i++)
+	for(int i = 0; i < 1; i++)
 	{
 	{
-		for(int j = 0; j < 10; j++)
+		for(int j = 0; j < 1; j++)
 		{
 		{
 			std::string name = "plight" + std::to_string(i) + std::to_string(j);
 			std::string name = "plight" + std::to_string(i) + std::to_string(j);
 
 
@@ -179,7 +189,7 @@ void mainLoopExtra()
 	{
 	{
 		mover = SceneSingleton::get().findSceneNode("horse")->getMovable();
 		mover = SceneSingleton::get().findSceneNode("horse")->getMovable();
 	}
 	}
-	if(in.getKey(SDL_SCANCODE_3))
+	/*if(in.getKey(SDL_SCANCODE_3))
 	{
 	{
 		mover = SceneSingleton::get().findSceneNode("spot0")->getMovable();
 		mover = SceneSingleton::get().findSceneNode("spot0")->getMovable();
 	}
 	}
@@ -190,6 +200,11 @@ void mainLoopExtra()
 	if(in.getKey(SDL_SCANCODE_5))
 	if(in.getKey(SDL_SCANCODE_5))
 	{
 	{
 		mover = SceneSingleton::get().findSceneNode("point1")->getMovable();
 		mover = SceneSingleton::get().findSceneNode("point1")->getMovable();
+	}*/
+	if(in.getKey(SDL_SCANCODE_6))
+	{
+		mover = SceneSingleton::get().findSceneNode("camera1")->getMovable();
+		mover->setLocalTransform(cam->getLocalTransform());
 	}
 	}
 
 
 	if(in.getKey(SDL_SCANCODE_L) == 1)
 	if(in.getKey(SDL_SCANCODE_L) == 1)
@@ -257,7 +272,7 @@ void mainLoop()
 
 
 		// Sleep
 		// Sleep
 		//
 		//
-#if 0
+#if 1
 		timer.stop();
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{
 		{
@@ -277,7 +292,6 @@ void mainLoop()
 		<< " sec)");
 		<< " sec)");
 }
 }
 
 
-
 //==============================================================================
 //==============================================================================
 // initSubsystems                                                              =
 // initSubsystems                                                              =
 //==============================================================================
 //==============================================================================
@@ -289,7 +303,7 @@ void initSubsystems(int argc, char* argv[])
 	// Main renderer
 	// Main renderer
 	RendererInitializer initializer;
 	RendererInitializer initializer;
 	initializer.ms.ez.enabled = true;
 	initializer.ms.ez.enabled = true;
-	initializer.dbg.enabled = false;
+	initializer.dbg.enabled = true;
 	initializer.is.sm.bilinearEnabled = true;
 	initializer.is.sm.bilinearEnabled = true;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.pcfEnabled = true;
 	initializer.is.sm.pcfEnabled = true;