Kaynağa Gözat

Adding mouselook. Moving Tiler from IS to new class

Panagiotis Christopoulos Charitos 13 yıl önce
ebeveyn
işleme
6c980de6ad

+ 22 - 0
docs/drafts/interleaved_vbos.txt

@@ -0,0 +1,22 @@
+Changes for interleaved VBOs 
+
+Mesh
+====
+
+MeshBase
+- getVbo() Return the the PNTtW VBO
+- getIndicesVbo() Return I VBO
+- getTextureChannelsCount()
+- getIndicesNumber(lod)
+- getVerticesNumber(lod)
+- getBoundingShape()
+- hasWeights()
+
+
+Model
+=====
+
+ModelPatchBase
+
+
+

+ 12 - 0
include/anki/core/NativeWindow.h

@@ -36,12 +36,24 @@ public:
 	{}
 	~NativeWindow();
 
+	/// @name Accessors
+	/// @{
 	NativeWindowImpl& getNative()
 	{
 		ANKI_ASSERT(isCreated());
 		return *impl;
 	}
 
+	U32 getWidth() const
+	{
+		return width;
+	}
+	U32 getHeight() const
+	{
+		return height;
+	}
+	/// @}
+
 	/// @name Public interface
 	/// Don't implement them in .h files
 	/// @{

+ 16 - 3
include/anki/input/Input.h

@@ -4,20 +4,24 @@
 #include "anki/math/Math.h"
 #include "anki/util/Singleton.h"
 #include "anki/util/Array.h"
+#include "anki/util/StdTypes.h"
 #include "anki/input/KeyCode.h"
+#include <memory>
 
 namespace anki {
 
+struct InputImpl;
 class NativeWindow;
 
 /// Handle the input and other events
+///
+/// @note All positions are in NDC space
 class Input
 {
 public:
 	Input()
 	{}
-	~Input()
-	{}
+	~Input();
 
 	/// @name Acessors
 	/// @{
@@ -26,15 +30,22 @@ public:
 		return keys[i];
 	}
 
-	U32 getMouseBtn(U32 i) const
+	U32 getMouseButton(U32 i) const
 	{
 		return mouseBtns[i];
 	}
+
+	const Vec2& getMousePosition() const
+	{
+		return mousePosNdc;
+	}
 	/// @}
 
 	void init(NativeWindow* nativeWindow);
 	void reset();
 	void handleEvents();
+	void moveMouse(const Vec2& posNdc);
+	void hideCursor(Bool hide);
 
 private:
 	NativeWindow* nativeWindow = nullptr;
@@ -55,6 +66,8 @@ private:
 	Vec2 mousePosNdc; ///< The coords are in the NDC space
 
 	Array<U16, 256> nativeKeyToAnki;
+
+	std::shared_ptr<InputImpl> impl;
 };
 
 typedef Singleton<Input> InputSingleton;

+ 16 - 0
include/anki/input/InputX11.h

@@ -0,0 +1,16 @@
+#ifndef ANKI_INPUT_INPUT_X11_H
+#define ANKI_INPUT_INPUT_X11_H
+
+#include <X11/XKBlib.h>
+
+namespace anki {
+
+/// X11 input implementation
+struct InputImpl
+{
+	Cursor emptyCursor = 0;
+};
+
+} // end namespace anki
+
+#endif

+ 2 - 0
include/anki/math/F16.h

@@ -17,6 +17,7 @@ public:
 	explicit F16();
 	F16(const F16& a);
 	explicit F16(const F32 f);
+	explicit F16(const U16 ui);
 	/// @}
 
 	/// @name Operators with same type
@@ -52,6 +53,7 @@ public:
 	/// @name Other
 	/// @{
 	F32 toF32() const;
+	U16 toU16() const;
 	/// @}
 
 	/// @name Friends

+ 12 - 0
include/anki/math/F16.inl.h

@@ -22,6 +22,12 @@ inline F16::F16(const F32 f)
 	*this = toF16(f);
 }
 
+// U16
+inline F16::F16(const U16 ui)
+{
+	data = ui;
+}
+
 //==============================================================================
 // Operators with same                                                         =
 //==============================================================================
@@ -182,6 +188,12 @@ inline F32 F16::toF32() const
 	return toF32(*this);
 }
 
+// toU16
+inline U16 F16::toU16() const
+{
+	return data;
+}
+
 //==============================================================================
 // Other                                                                       =
 //==============================================================================

+ 0 - 59
include/anki/renderer/Is.h

@@ -32,11 +32,6 @@ class Is: private RenderingPass
 	friend struct UpdateTilesJob;
 
 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_Y_COUNT = 16;
-
 	static const U MAX_LIGHTS_PER_TILE = 40;
 
 	static const U MAX_POINT_LIGHTS = 512;
@@ -54,49 +49,17 @@ public:
 	{
 		return fai;
 	}
-
-	const Texture& getMinMaxFai() const
-	{
-		return minMaxFai;
-	}
 	/// @}
 
 private:
-	/// A screen tile
-	struct Tile
-	{
-		Array<U32, MAX_LIGHTS_PER_TILE> lightIndices;
-		U lightsCount = 0;
-
-		/// Frustum planes
-		Array<Plane, 6> planes;
-		Array<Plane, 6> planesWSpace;
-	};
-
 	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 TILES_BLOCK_BINDING = 3;
 
-	U32 planesUpdateTimestamp = Timestamp::getTimestamp();
-
-	/// @note The [0][0] is the bottom left tile
-	union
-	{
-		Array<Array<Tile, TILES_X_COUNT>, TILES_Y_COUNT> tiles;
-		Array<Tile, TILES_X_COUNT * TILES_Y_COUNT> tiles1d;
-	};
-
-	/// A texture of TILES_X_COUNT*TILES_Y_COUNT size and format RG16F. Used to
-	/// to fill the Tile::depth
-	Texture minMaxFai;
-
 	/// The IS FAI
 	Texture fai;
 
-	/// An FBO to write to the minMaxTex
-	Fbo minMaxTilerFbo;
-
 	/// The IS FBO
 	Fbo fbo;
 
@@ -113,9 +76,6 @@ private:
 	/// Contains the indices of lights per tile
 	Ubo tilesUbo;
 
-	/// Min max shader program
-	ShaderProgramResourcePointer minMaxPassSprog;
-
 	/// Light shaders
 	ShaderProgramResourcePointer lightPassProg;
 
@@ -131,25 +91,6 @@ private:
 	/// Called by init
 	void initInternal(const RendererInitializer& initializer);
 
-	/// Do minmax pass and set the planes of the tiles
-	void updateTiles();
-
-	/// 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
-	void updateTilePlanes(F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2],
-		U32 start, U32 finish);
-
-	/// Update only the 4 planes of the tiles
-	void updateTiles4Planes(U32 start, U32 stop);
-
-	/// Update the 4 planes of the tile for a perspective camera
-	void updateTiles4PlanesInternal(const PerspectiveCamera& cam,
-		U32 start, U32 stop);
-
-	/// See if the light is inside the tile
-	static Bool cullLight(const PointLight& light, const Tile& tile);
-	static Bool cullLight(const SpotLight& light, const Tile& tile);
-
 	// Do the actual pass
 	void lightPass();
 };

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

@@ -67,7 +67,7 @@ private:
 	ShaderProgramResourcePointer prog;
 	Texture fai;
 
-	Bool renderToDefaultFbo;
+	Bool drawToDefaultFbo;
 	U32 width, height;
 
 	void initInternal(const RendererInitializer& initializer);

+ 13 - 8
include/anki/renderer/Tiler.h

@@ -33,12 +33,13 @@ public:
 	/// Update the tiles before doing visibility tests
 	void updateTiles(Camera& cam, const Texture& depthMap);
 
-	/// Return true if the cs is in at least one shape. If the tileIds is not 
-	/// nullptr then check all tiles and return the IDS if the tiles that the
-	/// cs is on
-	Bool test(const CollisionShape& cs,
-		Array<U32, TILES_X_COUNT * TILES_Y_COUNT>* tileIds = nullptr,
-		const Bool skipNearPlaneCheck = false) const;
+	/// Test against all tiles
+	Bool testAll(const CollisionShape& cs,
+ 		const Bool skipNearPlaneCheck = false) const;
+ 
+	/// Test on a specific tile
+	Bool test(const CollisionShape& cs, 
+		const U32 tileId, const Bool skipNearPlaneCheck = false) const;
 
 private:
 	/// A screen tile
@@ -51,6 +52,8 @@ private:
 		/// @}
 	};
 
+	typedef F32 PixelArray[TILES_Y_COUNT][TILES_X_COUNT][2];
+
 	/// @note The [0][0] is the bottom left tile
 	union
 	{
@@ -77,8 +80,10 @@ private:
 	void initInternal(Renderer* r);
 
 	void update4Planes(Camera& cam);
-	void update2Planes(Camera& cam, 
-		F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2]);
+	void update2Planes(Camera& cam, const PixelArray& pixels);
+
+	Bool testInternal(const CollisionShape& cs, const Tile& tile, 
+		const U startPlane) const;
 };
 
 } // end namespace anki

+ 4 - 1
include/anki/resource/MaterialShaderProgramCreator.h

@@ -21,7 +21,8 @@ public:
 		Bool const_;
 	};
 
-	explicit MaterialShaderProgramCreator(const XmlElement& pt);
+	explicit MaterialShaderProgramCreator(const XmlElement& pt, 
+		Bool enableUniformBlocks = false);
 	~MaterialShaderProgramCreator();
 
 	/// Get the shader program source code. This is the one and only public
@@ -44,6 +45,8 @@ private:
 
 	PtrVector<Input> inputs;
 
+	Bool enableUniformBlocks;
+
 	/// Used for shorting vectors of strings. Used in std::sort
 	static bool compareStrings(const std::string& a, const std::string& b);
 

+ 21 - 24
include/anki/resource/MeshLoader.h

@@ -19,48 +19,47 @@ namespace anki {
 /// <string:meshName>
 ///
 /// // Verts
-/// uint: verts number
-/// float: vert 0 x, float vert 0 y, float: vert 0 z
+/// U32: verts number
+/// F32: vert 0 x, F32 vert 0 y, F32: vert 0 z
 /// ...
 ///
 /// // Faces
-/// uint: faces number
-/// uint: tri 0 vert ID 0, uint: tri 0 vert ID 1, uint: tri 0 vert ID 2
+/// U32: faces number
+/// U32: tri 0 vert ID 0, U32: tri 0 vert ID 1, U32: tri 0 vert ID 2
 /// ...
 ///
 /// // Tex coords
-/// uint: tex coords number
-/// float: tex coord for vert 0 x, float: tex coord for vert 0 y
+/// U32: tex coords number
+/// F32: tex coord for vert 0 x, F32: tex coord for vert 0 y
 /// ...
 ///
 /// // Bone weights
-/// uint: bone weights number (equal to verts number)
-/// uint: bones number for vert 0, uint: bone id for vert 0 and weight 0,
-///       float: weight for vert 0 and weight 0, ...
+/// U32: bone weights number (equal to verts number)
+/// U32: bones number for vert 0, U32: bone id for vert 0 and weight 0,
+///       F32: weight for vert 0 and weight 0, ...
 /// ...
 /// @endcode
 class MeshLoader
 {
 public:
 	/// Vertex weight for skeletal animation
-	class VertexWeight
+	struct VertexWeight
 	{
-	public:
 		/// Dont change this or prepare to change the skinning code in
 		/// shader
-		static const uint MAX_BONES_PER_VERT = 4;
+		static const U32 MAX_BONES_PER_VERT = 4;
 
-		/// @todo change the vals to uint when change drivers
-		float bonesNum;
-		Array<float, MAX_BONES_PER_VERT> boneIds;
-		Array<float, MAX_BONES_PER_VERT> weights;
+		/// @todo change the vals to U32 when change drivers
+		F32 bonesNum;
+		Array<F32, MAX_BONES_PER_VERT> boneIds;
+		Array<F32, MAX_BONES_PER_VERT> weights;
 	};
 
 	/// Triangle
 	struct Triangle
 	{
 		/// An array with the vertex indexes in the mesh class
-		Array<uint, 3> vertIds;
+		Array<U32, 3> vertIds;
 		Vec3 normal;
 	};
 
@@ -88,20 +87,18 @@ public:
 		return vertTangents;
 	}
 
-	const Vector<Vec2>& getTexCoords() const
+	const Vector<Vec2>& getTexCoords(const U32 channel = 0) const
 	{
 		return texCoords;
 	}
-
-	const Vector<VertexWeight>& getVertWeights() const
+	U32 getTexCoordChannels() const
 	{
-		return vertWeights;
+		return 0;
 	}
 
-	// XXX Delete: Unused
-	const Vector<Triangle>& getTris() const
+	const Vector<VertexWeight>& getVertWeights() const
 	{
-		return tris;
+		return vertWeights;
 	}
 
 	const Vector<ushort>& getVertIndeces() const

+ 1 - 6
shaders/IsLpGeneric.glsl

@@ -315,14 +315,9 @@ void main()
 #endif
 
 #if 0
-	if(tiles[vInstanceId].lightsCount[2] == 1)
+	if(tiles[vInstanceId].lightsCount[0] > 0)
 	{
 		fColor += vec3(0.0, 0.1, 0.0);
 	}
-
-	if(tiles[vInstanceId].lightsCount[2] == 2)
-	{
-		fColor += vec3(0.0, 0.0, 0.1);
-	}
 #endif
 }

+ 0 - 4
shaders/IsMinMax.glsl

@@ -8,10 +8,6 @@
 #	error "See file"
 #endif
 
-uniform vec2 nearFar;
-#define near nearFar.x
-#define far nearFar.y
-
 uniform sampler2D depthMap;
 
 in vec2 vTexCoords;

+ 2 - 0
src/core/NativeWindowGlxX11.cpp

@@ -257,6 +257,8 @@ void NativeWindow::create(NativeWindowInitializer& initializer)
 {
 	impl.reset(new NativeWindowImpl);
 	impl->create(initializer);
+	width = initializer.width;
+	height = initializer.height;
 }
 
 //==============================================================================

+ 2 - 1
src/gl/BufferObject.cpp

@@ -94,7 +94,8 @@ void BufferObject::write(void* buff, U32 offset, U32 size)
 	glBufferSubData(target, offset, sizeInBytes, buff);
 #else
 	void* mapped = map(offset, size, 
-		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+		GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT 
+		| GL_MAP_UNSYNCHRONIZED_BIT);
 	
 	memcpy(mapped, buff, size);
 	unmap();

+ 73 - 4
src/input/InputX11.cpp

@@ -1,5 +1,6 @@
 #include "anki/input/Input.h"
 #include "anki/core/Logger.h"
+#include "anki/input/InputX11.h"
 #if ANKI_WINDOW_BACKEND_GLXX11
 #	include "anki/core/NativeWindowGlxX11.h"
 #elif ANKI_WINDOW_BACKEND_EGLX11
@@ -18,6 +19,9 @@
 #	define DBG_LOGI(x_) ((void)0)
 #endif
 
+// Undef stupid X11 defines
+#undef Bool
+
 namespace anki {
 
 //==============================================================================
@@ -131,6 +135,10 @@ static Bool eventsPending(Display* display)
 	return false;
 }
 
+//==============================================================================
+Input::~Input()
+{}
+
 //==============================================================================
 void Input::init(NativeWindow* nativeWindow_)
 {
@@ -140,7 +148,9 @@ void Input::init(NativeWindow* nativeWindow_)
 	NativeWindowImpl& nwin = nativeWindow->getNative();
 
 	XSelectInput(nwin.xDisplay, nwin.xWindow, 
-		ExposureMask | ButtonPressMask | KeyPressMask | KeyReleaseMask);
+		ExposureMask | ButtonPressMask | KeyPressMask | KeyReleaseMask 
+		| PointerMotionMask | FocusChangeMask | EnterWindowMask 
+		| LeaveWindowMask);
 
 	memset(&nativeKeyToAnki[0], sizeof(nativeKeyToAnki), KC_UNKNOWN);
 	for(const X11KeyCodeToAnki& a : x2a)
@@ -152,6 +162,9 @@ void Input::init(NativeWindow* nativeWindow_)
 	}
 
 	reset();
+
+	// Init native
+	impl.reset(new InputImpl);
 }
 
 //==============================================================================
@@ -222,13 +235,69 @@ skipXNextEvent:
 				keys[XKEYCODE2ANKI(keysym)] = 0;
 			}
 			break;
+		case MotionNotify:
+			mousePosNdc.x() = 
+				(F32)event.xmotion.x / nativeWindow->getWidth() * 2.0 - 1.0;
+			mousePosNdc.y() = 
+				-((F32)event.xmotion.y / nativeWindow->getHeight() * 2.0 - 1.0);
+
+			DBG_LOGI("MotionNotify: " << event.xmotion.x << " " 
+				<< event.xmotion.y << " (" << mousePosNdc << ")");
+			break;
+		case EnterNotify:
+			DBG_LOGI("EnterNotify: ");
+			break;
+		case LeaveNotify:
+			DBG_LOGI("LeaveNotify: ");
+			break;
 		default:
-#if DEBUG_EVENTS
-			ANKI_LOGW("Unknown X event");
-#endif
+			DBG_LOGI("Unknown X event");
 			break;
 		}
 	}
 }
 
+//==============================================================================
+void Input::moveMouse(const Vec2& pos)
+{
+	DBG_LOGI("Moving to: " << pos.x() << " " << pos.y());
+
+	if(pos != mousePosNdc)
+	{
+		NativeWindowImpl& nwi = nativeWindow->getNative();
+
+		XWarpPointer(nwi.xDisplay, None, nwi.xWindow, 0, 0, 0, 0, 
+			(F32)nativeWindow->getWidth() * (pos.x() / 2.0 + 0.5), 
+			(F32)nativeWindow->getHeight() * (-pos.y() / 2.0 + 0.5));
+
+		XSync(nwi.xDisplay, False);
+	}
+}
+
+//==============================================================================
+void Input::hideCursor(Bool hide)
+{
+	Display* dis = nativeWindow->getNative().xDisplay;
+	Window win = nativeWindow->getNative().xWindow;
+
+	if(impl->emptyCursor == None)
+	{
+		char data[1] = {0};
+		XColor color;
+		Pixmap pixmap;
+
+		color.red = color.green = color.blue = 0;
+		pixmap = XCreateBitmapFromData(dis, DefaultRootWindow(dis), data, 1, 1);
+		if(pixmap) 
+		{
+			impl->emptyCursor = XCreatePixmapCursor(dis, pixmap, pixmap,
+				&color, &color, 0, 0);
+			XFreePixmap(dis, pixmap);
+		}	
+	}
+
+	XDefineCursor(dis, win, impl->emptyCursor);
+	XFlush(dis);
+}
+
 } // end namespace anki

+ 10 - 230
src/renderer/Is.cpp

@@ -48,7 +48,7 @@ struct ShaderTile
 
 struct ShaderTiles
 {
-	Array<ShaderTile, Is::TILES_X_COUNT * Is::TILES_Y_COUNT> tiles;
+	Array<ShaderTile, Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT> tiles;
 };
 
 struct ShaderCommonUniforms
@@ -167,21 +167,21 @@ struct WriteTilesUboJob: ThreadJob
 	{
 		U64 start, end;
 		choseStartEnd(threadId, threadsCount, 
-			Is::TILES_X_COUNT * Is::TILES_Y_COUNT, start, end);
+			Tiler::TILES_X_COUNT * Tiler::TILES_Y_COUNT, start, end);
 
 		for(U32 i = start; i < end; i++)
 		{
-			Is::Tile& tile = is->tiles1d[i];
 			ShaderTile& stile = shaderTiles[i];
 
-			doTile(tile, stile);
+			doTile(i, stile);
 		}
 	}
 
 	/// Do a tile
-	void doTile(Is::Tile& tile, ShaderTile& stile)
+	void doTile(U tileId, ShaderTile& stile)
 	{
 		auto& lightIndices = stile.lightIndices;
+		const Tiler& tiler = is->r->getTiler();
 
 		// Point lights
 		//
@@ -191,7 +191,7 @@ struct WriteTilesUboJob: ThreadJob
 		{
 			const PointLight& light = *visiblePointLights[i];
 
-			if(Is::cullLight(light, tile))
+			if(tiler.test(light.getSphere(), tileId))
 			{
 				// Use % to avoid overflows
 				const U id = pointLightsInTileCount % Is::MAX_LIGHTS_PER_TILE;
@@ -211,7 +211,7 @@ struct WriteTilesUboJob: ThreadJob
 		{
 			const SpotLight& light = *visibleSpotLights[i];
 
-			if(Is::cullLight(light, tile))
+			if(tiler.test(light.getFrustum(), tileId))
 			{
 				const U id = (pointLightsInTileCount + spotLightsInTileCount 
 					+ spotLightsShadowInTileCount) 
@@ -248,22 +248,6 @@ struct WriteTilesUboJob: ThreadJob
 	}
 };
 
-/// Job that updates the tile planes
-struct UpdateTilesJob: ThreadJob
-{
-	F32 (*pixels)[Is::TILES_Y_COUNT][Is::TILES_X_COUNT][2];
-	Is* is;
-
-	void operator()(U threadId, U threadsCount)
-	{
-		U64 start, end;
-		choseStartEnd(threadId, threadsCount, 
-			Is::TILES_X_COUNT * Is::TILES_Y_COUNT, start, end);
-
-		is->updateTilePlanes(pixels, start, end);
-	}
-};
-
 //==============================================================================
 Is::Is(Renderer* r_)
 	: RenderingPass(r_), sm(r_)
@@ -302,8 +286,8 @@ void Is::initInternal(const RendererInitializer& initializer)
 	// Load the programs
 	//
 	std::string pps =
-		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
-		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n"
+		"#define TILES_X_COUNT " + std::to_string(Tiler::TILES_X_COUNT) + "\n"
+		"#define TILES_Y_COUNT " + std::to_string(Tiler::TILES_Y_COUNT) + "\n"
 		"#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
 		"#define RENDERER_HEIGHT " + std::to_string(r->getHeight()) + "\n"
 		"#define MAX_LIGHTS_PER_TILE " + std::to_string(MAX_LIGHTS_PER_TILE)
@@ -320,10 +304,6 @@ void Is::initInternal(const RendererInitializer& initializer)
 	lightPassProg.load(ShaderProgramResource::createSrcCodeToCache(
 		"shaders/IsLpGeneric.glsl", pps.c_str()).c_str());
 
-	// Min max
-	minMaxPassSprog.load(ShaderProgramResource::createSrcCodeToCache(
-		"shaders/IsMinMax.glsl", pps.c_str()).c_str());
-
 	//
 	// Create FBOs
 	//
@@ -340,17 +320,6 @@ void Is::initInternal(const RendererInitializer& initializer)
 		throw ANKI_EXCEPTION("Fbo not complete");
 	}
 
-	// min max FBO
-	Renderer::createFai(TILES_X_COUNT, TILES_Y_COUNT, GL_RG32UI,
-		GL_RG_INTEGER, GL_UNSIGNED_INT, minMaxFai);
-	minMaxFai.setFiltering(Texture::TFT_NEAREST);
-	minMaxTilerFbo.create();
-	minMaxTilerFbo.setColorAttachments({&minMaxFai});
-	if(!minMaxTilerFbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("minMaxTilerFbo not complete");
-	}
-
 	//
 	// Create UBOs
 	//
@@ -404,192 +373,6 @@ void Is::initInternal(const RendererInitializer& initializer)
 	}
 }
 
-//==============================================================================
-Bool Is::cullLight(const PointLight& plight, const Tile& tile)
-{
-	const Sphere& sphere = plight.getSphere();
-
-	for(const Plane& plane : tile.planesWSpace)
-	{
-		if(sphere.testPlane(plane) < 0.0)
-		{
-			return false;
-		}
-	}
-
-	return true;
-}
-
-//==============================================================================
-Bool Is::cullLight(const SpotLight& light, const Tile& tile)
-{
-	const PerspectiveFrustum& fr = light.getFrustum();
-
-	for(const Plane& plane : tile.planesWSpace)
-	{
-		if(fr.testPlane(plane) < 0.0)
-		{
-			return false;
-		}
-	}
-
-	return true;
-}
-
-//==============================================================================
-void Is::updateTiles()
-{
-	// Do the min/max pass
-	//
-	minMaxTilerFbo.bind();
-	minMaxPassSprog->bind();
-	GlStateSingleton::get().setViewport(0, 0, TILES_X_COUNT, TILES_Y_COUNT);
-
-	minMaxPassSprog->findUniformVariable("depthMap").set(
-		r->getMs().getDepthFai());
-
-	r->drawQuad();
-
-	F32 pixels[TILES_Y_COUNT][TILES_X_COUNT][2];
-#if ANKI_GL == ANKI_GL_DESKTOP
-	// It seems read from texture is a bit faster than readpixels on nVidia
-	minMaxFai.readPixels(pixels);
-#else
-	glReadPixels(0, 0, TILES_X_COUNT, TILES_Y_COUNT, GL_RG_INTEGER,
-		GL_UNSIGNED_INT, &pixels[0][0][0]);
-#endif
-
-	// Update the rest of the tile stuff in parallel
-	// 
-
-	ThreadPool& threadPool = ThreadPoolSingleton::get();
-	UpdateTilesJob jobs[ThreadPool::MAX_THREADS];
-	
-	for(U i = 0; i < threadPool.getThreadsCount(); i++)
-	{
-		jobs[i].pixels = &pixels;
-		jobs[i].is = this;
-
-		threadPool.assignNewJob(i, &jobs[i]);
-	}
-
-	threadPool.waitForAllJobsToFinish();
-}
-
-//==============================================================================
-void Is::updateTilePlanes(F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2],
-	U32 start, U32 stop)
-{
-	// Update only the 4 planes
-	updateTiles4Planes(start, stop);
-
-	// - Calc the rest of the 2 planes and 
-	// - transform the planes
-	for(U32 k = start; k < stop; k++)
-	{
-		U i = k % TILES_X_COUNT;
-		U j = k / TILES_X_COUNT;
-		Tile& tile = tiles[j][i];
-
-		/// Calculate as you do in the vertex position inside the shaders
-		F32 minZ = 
-			r->getPlanes().y() / (r->getPlanes().x() + (*pixels)[j][i][0]);
-		F32 maxZ = 
-			-r->getPlanes().y() / (r->getPlanes().x() + (*pixels)[j][i][1]);
-
-		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);
-
-		// Now transform
-		for(U k = 0; k < 6; k++)
-		{
-			tile.planesWSpace[k] = tile.planes[k].getTransformed(
-				Transform(cam->getWorldTransform()));
-		}
-	}
-}
-
-//==============================================================================
-void Is::updateTiles4Planes(U32 start, U32 stop)
-{
-	U32 camTimestamp = cam->getFrustumable()->getFrustumableTimestamp();
-	if(camTimestamp < planesUpdateTimestamp)
-	{
-		// Early exit if the frustum have not changed
-		return;
-	}
-
-	switch(cam->getCameraType())
-	{
-	case Camera::CT_PERSPECTIVE:
-		updateTiles4PlanesInternal(
-			static_cast<const PerspectiveCamera&>(*cam), start, stop);
-		break;
-	default:
-		ANKI_ASSERT(0 && "Unimplemented");
-		break;
-	}
-
-	planesUpdateTimestamp = Timestamp::getTimestamp();
-}
-
-//==============================================================================
-void Is::updateTiles4PlanesInternal(const PerspectiveCamera& cam,
-	U32 start, U32 stop)
-{
-	// The algorithm is almost the same as the recalculation of planes for
-	// PerspectiveFrustum class
-
-	// Algorithm works for even number of tiles per dimension
-	ANKI_ASSERT(TILES_X_COUNT % 2 == 0 && TILES_Y_COUNT % 2 == 0);
-
-	F32 fx = cam.getFovX();
-	F32 fy = cam.getFovY();
-	F32 n = cam.getNear();
-
-	F32 l = 2.0 * n * tan(fx / 2.0);
-	F32 l6 = l / TILES_X_COUNT;
-	F32 o = 2.0 * n * tan(fy / 2.0);
-	F32 o6 = o / TILES_Y_COUNT;
-
-	for(U32 k = start; k < stop; k++)
-	{
-		U i = k % TILES_X_COUNT;
-		U j = k / TILES_X_COUNT;
-
-		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);
-
-		// bottom
-		a = Vec3(0.0, (I(j) - I(TILES_Y_COUNT) / 2) * o6, -n);
-		b = Vec3(1.0, 0.0, 0.0).cross(a);
-		b.normalize();
-
-		planes[Frustum::FP_BOTTOM] = Plane(b, 0.0);
-
-		// bottom
-		a = Vec3(0.0, (I(j) - I(TILES_Y_COUNT) / 2 + 1) * o6, -n);
-		b = a.cross(Vec3(1.0, 0.0, 0.0));
-		b.normalize();
-
-		planes[Frustum::FP_TOP] = Plane(b, 0.0);
-	}
-}
-
 //==============================================================================
 void Is::lightPass()
 {
@@ -790,7 +573,7 @@ void Is::lightPass()
 		r->getMs().getDepthFai());
 	lightPassProg->findUniformVariable("shadowMapArr").set(sm.sm2DArrayTex);
 
-	r->drawQuadInstanced(TILES_Y_COUNT * TILES_X_COUNT);
+	r->drawQuadInstanced(Tiler::TILES_Y_COUNT * Tiler::TILES_X_COUNT);
 }
 
 //==============================================================================
@@ -817,9 +600,6 @@ void Is::run()
 		commonUboUpdateTimestamp = Timestamp::getTimestamp();
 	}
 
-	// Update tiles
-	updateTiles();
-
 	// Do the light pass including the shadow passes
 	lightPass();
 }

+ 3 - 3
src/renderer/Pps.cpp

@@ -25,10 +25,10 @@ void Pps::initInternal(const RendererInitializer& initializer)
 
 	ssao.init(initializer);
 	hdr.init(initializer);
-	renderToDefaultFbo = initializer.pps.drawToDefaultFbo;
+	drawToDefaultFbo = initializer.pps.drawToDefaultFbo;
 
 	// FBO
-	if(!renderToDefaultFbo)
+	if(!drawToDefaultFbo)
 	{
 		Renderer::createFai(r->getWidth(), r->getHeight(), GL_RGB, GL_RGB,
 			GL_FLOAT, fai);
@@ -91,7 +91,7 @@ void Pps::run()
 		hdr.run();
 	}
 
-	if(renderToDefaultFbo)
+	if(drawToDefaultFbo)
 	{
 		Fbo::unbindAll();
 		GlStateSingleton::get().setViewport(

+ 1 - 1
src/renderer/Renderer.cpp

@@ -81,7 +81,7 @@ void Renderer::render(Scene& scene_)
 	viewProjectionMat = cam.getViewProjectionMatrix();
 
 	ms.run();
-	//tiler.updateTiles(scene->getActiveCamera(), ms.getDepthFai());
+	tiler.updateTiles(scene->getActiveCamera(), ms.getDepthFai());
 	is.run();
 	if(pps.getEnabled())
 	{

+ 76 - 84
src/renderer/Tiler.cpp

@@ -12,6 +12,7 @@ struct UpdateTiles4PlanesPerspectiveCameraJob: ThreadJob
 {
 	Tiler* tiler;
 	PerspectiveCamera* cam;
+	Bool onlyTransformPlanes;
 
 	void operator()(U threadId, U threadsCount)
 	{
@@ -28,23 +29,37 @@ struct UpdateTiles4PlanesPerspectiveCameraJob: ThreadJob
 		F32 o = 2.0 * n * tan(fy / 2.0);
 		F32 o6 = o / Tiler::TILES_Y_COUNT;
 
+		Transform trf = Transform(cam->getWorldTransform());
+
 		for(U64 k = start; k < end; k++)
 		{
-			U i = k % Tiler::TILES_X_COUNT;
-			U j = k / Tiler::TILES_X_COUNT;
+			if(!onlyTransformPlanes)
+			{
+				updatePlanes(l, l6, o, o6, k);
+			}
+
+			Tiler::Tile& tile = tiler->tiles1d[k];
 
-			Array<Plane, Frustum::FP_COUNT>& planes = tiler->tiles[j][i].planes;
-			updatePlanes(l, l6, o, o6, i, j, planes);
+			tile.planesWSpace[Frustum::FP_LEFT] = 
+				tile.planes[Frustum::FP_LEFT].getTransformed(trf);
+			tile.planesWSpace[Frustum::FP_RIGHT] = 
+				tile.planes[Frustum::FP_RIGHT].getTransformed(trf);
+			tile.planesWSpace[Frustum::FP_BOTTOM] = 
+				tile.planes[Frustum::FP_BOTTOM].getTransformed(trf);
+			tile.planesWSpace[Frustum::FP_TOP] = 
+				tile.planes[Frustum::FP_TOP].getTransformed(trf);
 		}
 	}
 
 	void updatePlanes(
 		const F32 l, const F32 l6, const F32 o, const F32 o6,
-		const U i, const U j,
-		Array<Plane, Frustum::FP_COUNT>& planes)
+		const U k)
 	{
 		Vec3 a, b;
 		const F32 n = cam->getNear();
+		const U i = k % Tiler::TILES_X_COUNT;
+		const U j = k / Tiler::TILES_X_COUNT;
+		Array<Plane, Frustum::FP_COUNT>& planes = tiler->tiles1d[k].planes;
 
 		// left
 		a = Vec3((I(i) - I(Tiler::TILES_X_COUNT) / 2) * l6, 0.0, -n);
@@ -80,7 +95,7 @@ struct UpdateTiles4PlanesPerspectiveCameraJob: ThreadJob
 /// Job that updates the near and far tile planes and transforms them
 struct UpdateTiles2PlanesJob: ThreadJob
 {
-	F32 (*pixels)[Is::TILES_Y_COUNT][Is::TILES_X_COUNT][2];
+	const Tiler::PixelArray* pixels;
 	Tiler* tiler;
 	Camera* cam;
 
@@ -93,12 +108,13 @@ struct UpdateTiles2PlanesJob: ThreadJob
 		// Calc planes for this camera
 		Vec2 planes;
 		Renderer::calcPlanes(Vec2(cam->getNear(), cam->getFar()), planes);
+		Transform trf = Transform(cam->getWorldTransform());
 
 		for(U64 k = start; k < end; k++)
 		{
 			U i = k % Tiler::TILES_X_COUNT;
 			U j = k / Tiler::TILES_X_COUNT;
-			Tiler::Tile& tile = tiler->tiles[j][i];
+			Tiler::Tile& tile = tiler->tiles1d[k];
 
 			// Calculate depth as you do it for the vertex position inside 
 			// the shaders
@@ -108,12 +124,11 @@ struct UpdateTiles2PlanesJob: ThreadJob
 			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);
 
-			// Transform all planes
-			Transform trf = Transform(cam->getWorldTransform());
-			for(U k = 0; k < Frustum::FP_COUNT; k++)
-			{
-				tile.planesWSpace[k] = tile.planes[k].getTransformed(trf);
-			}
+			// Transform planes
+			tile.planesWSpace[Frustum::FP_NEAR] = 
+				tile.planes[Frustum::FP_NEAR].getTransformed(trf);
+			tile.planesWSpace[Frustum::FP_FAR] = 
+				tile.planes[Frustum::FP_FAR].getTransformed(trf);
 		}
 	}
 };
@@ -170,39 +185,36 @@ void Tiler::initInternal(Renderer* r_)
 //==============================================================================
 void Tiler::updateTiles(Camera& cam, const Texture& depthMap)
 {
-	//
-	// In the meantime update the 4 planes for all the tiles
-	//
-	fbo.bind(); // Flush prev FBO on Mali
-	update4Planes(cam);
-
 	//
 	// Issue the min/max draw call
 	//
 
-	prog->bind();
+	fbo.bind(); // Flush prev FBO on Mali
 	GlStateSingleton::get().setViewport(0, 0, TILES_X_COUNT, TILES_Y_COUNT);
+	prog->bind();
 	prog->findUniformVariable("depthMap").set(depthMap);
 
 	r->drawQuad();
 
+	update4Planes(cam);
+
 	//
 	// Read pixels from the min/max pass
 	//
 
-	F32 pixels[TILES_Y_COUNT][TILES_X_COUNT][2];
+	PixelArray pixels;
 #if ANKI_GL == ANKI_GL_DESKTOP
 	// It seems read from texture is a bit faster than readpixels on nVidia
 	fai.readPixels(pixels);
 #else
 	glReadPixels(0, 0, TILES_X_COUNT, TILES_Y_COUNT, GL_RG_INTEGER,
-		GL_UNSIGNED_INT, &pixels[0][0][0]);
+		GL_UNSIGNED_INT, pixels);
 #endif
 
 	// 
 	// Update the 2 planes and transform the planes
 	// 
-	update2Planes(cam, &pixels);
+	update2Planes(cam, pixels);
 
 	prevCam = &cam;
 }
@@ -211,16 +223,13 @@ void Tiler::updateTiles(Camera& cam, const Texture& depthMap)
 void Tiler::update4Planes(Camera& cam)
 {
 	U32 camTimestamp = cam.getFrustumable()->getFrustumableTimestamp();
-	if(camTimestamp < planes4UpdateTimestamp && prevCam == &cam)
-	{
-		// Early exit because:
-		// - it is the same camera as before and
-		// - the camera frustum have not changed
-		return;
-	}
-#if 0
-	ANKI_LOGI("Updating 4 planes");
-#endif
+
+	// Transform only the planes when:
+	// - it is the same camera as before and
+	// - the camera frustum have not changed
+	Bool onlyTransformPlanes = 
+		camTimestamp < planes4UpdateTimestamp && prevCam == &cam;
+
 
 	// Update the planes in parallel
 	// 
@@ -236,6 +245,7 @@ void Tiler::update4Planes(Camera& cam)
 		{	
 			jobs[i].tiler = this;
 			jobs[i].cam = static_cast<PerspectiveCamera*>(&cam);
+			jobs[i].onlyTransformPlanes = onlyTransformPlanes;
 			threadPool.assignNewJob(i, &jobs[i]);
 		}
 		break;
@@ -246,19 +256,21 @@ void Tiler::update4Planes(Camera& cam)
 
 	threadPool.waitForAllJobsToFinish();
 
-	planes4UpdateTimestamp = Timestamp::getTimestamp();
+	if(!onlyTransformPlanes)
+	{
+		planes4UpdateTimestamp = Timestamp::getTimestamp();
+	}
 }
 
 //==============================================================================
-void Tiler::update2Planes(Camera& cam, 
-	F32 (*pixels)[TILES_Y_COUNT][TILES_X_COUNT][2])
+void Tiler::update2Planes(Camera& cam, const PixelArray& pixels)
 {
 	ThreadPool& threadPool = ThreadPoolSingleton::get();
 	UpdateTiles2PlanesJob jobs[ThreadPool::MAX_THREADS];
 	
 	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
-		jobs[i].pixels = pixels;
+		jobs[i].pixels = &pixels;
 		jobs[i].tiler = this;
 		jobs[i].cam = &cam;
 
@@ -269,63 +281,43 @@ void Tiler::update2Planes(Camera& cam,
 }
 
 //==============================================================================
-Bool Tiler::test(const CollisionShape& cs,
-	Array<U32, TILES_X_COUNT * TILES_Y_COUNT>* tileIds,
+Bool Tiler::testInternal(const CollisionShape& cs, const Tile& tile, 
+	const U startPlane) const
+{
+	for(U j = startPlane; j < Frustum::FP_COUNT; j++)
+	{
+		if(cs.testPlane(tile.planesWSpace[j]) < 0.0)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+//==============================================================================
+Bool Tiler::test(const CollisionShape& cs, const U32 tileId,
+	const Bool skipNearPlaneCheck) const
+{
+	return testInternal(cs, tiles1d[tileId], (skipNearPlaneCheck) ? 1 : 0);
+}
+
+//==============================================================================
+Bool Tiler::testAll(const CollisionShape& cs, 
 	const Bool skipNearPlaneCheck) const
 {
 	static_assert(Frustum::FP_NEAR == 0, "Frustum::FP_NEAR should be 0");
 
 	U startPlane = (skipNearPlaneCheck) ? 1 : 0;
 
-	if(tileIds)
+	for(const Tile& tile : tiles1d)
 	{
-		// Check all tiles
-
-		U32* ip = &(*tileIds)[0];
-		for(U i = 0; i < tiles1d.getSize(); i++)
+		if(testInternal(cs, tile, startPlane))
 		{
-			Bool inside = true;
-			for(U j = startPlane; j < Frustum::FP_COUNT; j++)
-			{
-				if(cs.testPlane(tiles1d[i].planesWSpace[j]) < 0.0)
-				{
-					inside = false;
-					break;
-				}
-			}
-
-			if(inside)
-			{
-				*ip++ = i;
-			}
+			return true;
 		}
-
-		return ip != &(*tileIds)[0];
 	}
-	else
-	{
-		// Check at least one
 
-		for(const Tile& tile : tiles1d)
-		{
-			Bool inside = true;
-			for(U j = startPlane; j < Frustum::FP_COUNT; j++)
-			{
-				if(cs.testPlane(tile.planesWSpace[j]) < 0.0)
-				{
-					inside = false;
-					break;
-				}
-			}
-
-			if(inside)
-			{
-				return true;
-			}
-		}
-
-		return false;
-	}
+	return false;
 }
 
 } // end namespace anki

+ 1 - 1
src/resource/Material.cpp

@@ -240,7 +240,7 @@ void Material::parseMaterialTag(const XmlElement& materialEl)
 	// shaderProgram
 	//
 	XmlElement shaderProgramEl = materialEl.getChildElement("shaderProgram");
-	MaterialShaderProgramCreator mspc(shaderProgramEl);
+	MaterialShaderProgramCreator mspc(shaderProgramEl, ENABLE_UBOS);
 
 	for(uint level = 0; level < levelsOfDetail; ++level)
 	{

+ 24 - 22
src/resource/MaterialShaderProgramCreator.cpp

@@ -6,13 +6,12 @@
 #include <algorithm>
 #include <sstream>
 
-#define ENABLE_UBOS 0
-
 namespace anki {
 
 //==============================================================================
 MaterialShaderProgramCreator::MaterialShaderProgramCreator(
-	const XmlElement& el)
+	const XmlElement& el, Bool enableUniformBlocks_)
+	: enableUniformBlocks(enableUniformBlocks_)
 {
 	parseShaderProgramTag(el);
 }
@@ -35,28 +34,33 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 	} while(shaderEl);
 
 	// Create block
-#if ENABLE_UBOS
-	StringList block;
-	block.push_back("layout(shared, row_major, binding = 0) "
-		"uniform commonBlock\n{");
-	for(Input* in : inputs)
+	if(enableUniformBlocks)
 	{
-		if(in->type == "sampler2D"
-			|| in->const_)
+		StringList block;
+		block.push_back("layout(shared, row_major, binding = 0) "
+			"uniform commonBlock\n{");
+		for(Input* in : inputs)
 		{
-			continue;
-		}
+			if(in->type == "sampler2D"
+				|| in->const_)
+			{
+				continue;
+			}
 
-		block.push_back("\tuniform " + in->type + " " + in->name + ";");
-	}
-	block.push_back("};\n");
+			block.push_back("\tuniform " + in->type + " " + in->name + ";");
+		}
+		block.push_back("};\n");
 
-	if(block.size() > 2)
-	{
-		source = block.join("\n") + srcLines.join("\n");
+		if(block.size() > 2)
+		{
+			source = block.join("\n") + srcLines.join("\n");
+		}
+		else
+		{
+			source = srcLines.join("\n");
+		}
 	}
 	else
-#endif
 	{
 		source = srcLines.join("\n");
 	}
@@ -157,9 +161,7 @@ void MaterialShaderProgramCreator::parseInputTag(
 
 	if(inpvar->const_ == false)
 	{
-#if ENABLE_UBOS
-		if(inpvar->type == "sampler2D")
-#endif
+		if(!(enableUniformBlocks && inpvar->type != "sampler2D"))
 		{
 			line = "uniform " + inpvar->type + " " + inpvar->name + ";";
 		}

+ 0 - 5
src/resource/MeshLoader.cpp

@@ -173,11 +173,6 @@ void MeshLoader::createFaceNormals()
 		const Vec3& v1 = vertCoords[tri.vertIds[1]];
 		const Vec3& v2 = vertCoords[tri.vertIds[2]];
 
-		/*std::cout << v0 << std::endl;
-		std::cout << v1 << std::endl;
-		std::cout << v2 << std::endl;
-		std::cout << std::endl;*/
-
 		tri.normal = (v1 - v0).cross(v2 - v0);
 
 		tri.normal.normalize();

+ 20 - 9
testapp/Main.cpp

@@ -59,7 +59,7 @@ void init()
 	// camera
 	cam = new PerspectiveCamera("main-camera", &scene,
 		Movable::MF_NONE, nullptr);
-	const float ang = 45.0;
+	const F32 ang = 45.0;
 	cam->setAll(
 		MainRendererSingleton::get().getAspectRatio() * toRad(ang),
 		toRad(ang), 0.5, 500.0);
@@ -89,8 +89,10 @@ void init()
 			PointLight* point = new PointLight(name.c_str(), &scene,
 				Movable::MF_NONE, nullptr);
 			point->setRadius(2.0);
-			point->setDiffuseColor(Vec4(randFloat(3.0), randFloat(3.0), randFloat(3.0), 0.0));
-			point->setSpecularColor(Vec4(randFloat(3.0), randFloat(3.0), randFloat(3.0), 0.0));
+			point->setDiffuseColor(Vec4(randFloat(6.0) - 2.0, 
+				randFloat(6.0) - 2.0, randFloat(6.0) - 2.0, 0.0));
+			point->setSpecularColor(Vec4(randFloat(6.0) - 3.0, 
+				randFloat(6.0) - 3.0, randFloat(6.0) - 3.0, 0.0));
 			point->setLocalTranslation(lpos);
 
 			lpos.z() += 10.0;
@@ -185,11 +187,10 @@ void execStdinScpripts()
 //==============================================================================
 void mainLoopExtra()
 {
-	InputSingleton::get().handleEvents();
-
-	float dist = 0.2;
-	float ang = toRad(3.0);
-	float scale = 0.01;
+	F32 dist = 0.2;
+	F32 ang = toRad(3.0);
+	F32 scale = 0.01;
+	F32 mouseSensivity = 9.0;
 
 	// move the camera
 	static Movable* mover = SceneSingleton::get().getActiveCamera().getMovable();
@@ -229,7 +230,8 @@ void mainLoopExtra()
 
 	if(in.getKey(KC_P) == 1)
 	{
-		MainRendererSingleton::get().getPps().getHdr().setExposure(20);
+		//MainRendererSingleton::get().getPps().getHdr().setExposure(20);
+		in.hideCursor(true);
 	}
 
 	if(in.getKey(KC_UP)) mover->rotateLocalX(ang);
@@ -254,6 +256,10 @@ void mainLoopExtra()
 		mover->scale(-scale);
 	}
 
+	mover->rotateLocalY(-ang * in.getMousePosition().x() * mouseSensivity * 
+		MainRendererSingleton::get().getAspectRatio());
+	mover->rotateLocalX(ang * in.getMousePosition().y() * mouseSensivity);
+
 	execStdinScpripts();
 }
 
@@ -277,6 +283,8 @@ void mainLoop()
 
 		// Update
 		//
+		InputSingleton::get().handleEvents();
+		InputSingleton::get().moveMouse(Vec2(0.0));
 		mainLoopExtra();
 		SceneSingleton::get().update(prevUpdateTime, crntTime);
 		EventManagerSingleton::get().updateAllEvents(prevUpdateTime, crntTime);
@@ -287,6 +295,8 @@ void mainLoop()
 			break;
 		}
 
+		//ANKI_LOGI(InputSingleton::get().getMousePosition());
+
 		//AppSingleton::get().swapBuffers();
 		win->swapBuffers();
 
@@ -344,6 +354,7 @@ void initSubsystems(int argc, char* argv[])
 
 	// Input
 	InputSingleton::get().init(win);
+	InputSingleton::get().hideCursor(true);
 
 	// Main renderer
 	RendererInitializer initializer;