Browse Source

Merge branch 'MarcoROG-master'

BearishSun 9 years ago
parent
commit
0210221435
85 changed files with 670 additions and 91 deletions
  1. BIN
      Data/Editor/GUISkin.asset
  2. BIN
      Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd16.asset
  3. BIN
      Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd32.asset
  4. BIN
      Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd48.asset
  5. BIN
      Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd16.asset
  6. BIN
      Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd32.asset
  7. BIN
      Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd48.asset
  8. BIN
      Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd16.asset
  9. BIN
      Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd32.asset
  10. BIN
      Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd48.asset
  11. BIN
      Data/Editor/Icons/Sprites/sprite_FolderIcon.psd16.asset
  12. BIN
      Data/Editor/Icons/Sprites/sprite_FolderIcon.psd32.asset
  13. BIN
      Data/Editor/Icons/Sprites/sprite_FolderIcon.psd48.asset
  14. BIN
      Data/Editor/Icons/Sprites/sprite_FontIcon.psd16.asset
  15. BIN
      Data/Editor/Icons/Sprites/sprite_FontIcon.psd32.asset
  16. BIN
      Data/Editor/Icons/Sprites/sprite_FontIcon.psd48.asset
  17. BIN
      Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd16.asset
  18. BIN
      Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd32.asset
  19. BIN
      Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd48.asset
  20. BIN
      Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd16.asset
  21. BIN
      Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd32.asset
  22. BIN
      Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd48.asset
  23. BIN
      Data/Editor/Icons/Sprites/sprite_MeshIcon.psd16.asset
  24. BIN
      Data/Editor/Icons/Sprites/sprite_MeshIcon.psd32.asset
  25. BIN
      Data/Editor/Icons/Sprites/sprite_MeshIcon.psd48.asset
  26. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd16.asset
  27. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd32.asset
  28. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd48.asset
  29. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd16.asset
  30. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd32.asset
  31. BIN
      Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd48.asset
  32. BIN
      Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd16.asset
  33. BIN
      Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd32.asset
  34. BIN
      Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd48.asset
  35. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd16.asset
  36. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd32.asset
  37. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd48.asset
  38. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd16.asset
  39. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd32.asset
  40. BIN
      Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd48.asset
  41. BIN
      Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd16.asset
  42. BIN
      Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd32.asset
  43. BIN
      Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd48.asset
  44. BIN
      Data/Editor/Icons/Sprites/sprite_TextIcon.psd16.asset
  45. BIN
      Data/Editor/Icons/Sprites/sprite_TextIcon.psd32.asset
  46. BIN
      Data/Editor/Icons/Sprites/sprite_TextIcon.psd48.asset
  47. BIN
      Data/Editor/Icons/Sprites/sprite_TextureIcon.psd16.asset
  48. BIN
      Data/Editor/Icons/Sprites/sprite_TextureIcon.psd32.asset
  49. BIN
      Data/Editor/Icons/Sprites/sprite_TextureIcon.psd48.asset
  50. BIN
      Data/Editor/Includes/PickingAlphaCull.bslinc.asset
  51. BIN
      Data/Editor/Includes/PickingCull.bslinc.asset
  52. BIN
      Data/Editor/ResourceManifest.asset
  53. BIN
      Data/Editor/Shaders/PickingAlphaCullCCW.bsl.asset
  54. BIN
      Data/Editor/Shaders/PickingAlphaCullCW.bsl.asset
  55. BIN
      Data/Editor/Shaders/PickingAlphaCullNone.bsl.asset
  56. BIN
      Data/Editor/Shaders/PickingCullCCW.bsl.asset
  57. BIN
      Data/Editor/Shaders/PickingCullCW.bsl.asset
  58. BIN
      Data/Editor/Shaders/PickingCullNone.bsl.asset
  59. BIN
      Data/Editor/Timestamp.asset
  60. BIN
      Data/Editor/arial.ttf.asset
  61. BIN
      Data/Editor/arialAA.ttf.asset
  62. 15 3
      Data/Raw/Editor/Includes/PickingAlphaCull.bslinc
  63. 17 4
      Data/Raw/Editor/Includes/PickingCull.bslinc
  64. 2 0
      Documentation/Manuals/Native/style.md
  65. 11 2
      Source/BansheeCore/Include/BsCamera.h
  66. 20 3
      Source/BansheeCore/Include/BsMultiRenderTexture.h
  67. 18 3
      Source/BansheeCore/Include/BsPixelData.h
  68. 7 1
      Source/BansheeCore/Include/BsPixelUtil.h
  69. 19 0
      Source/BansheeCore/Source/BsCamera.cpp
  70. 5 0
      Source/BansheeCore/Source/BsMultiRenderTexture.cpp
  71. 51 3
      Source/BansheeCore/Source/BsPixelData.cpp
  72. 48 5
      Source/BansheeCore/Source/BsPixelUtil.cpp
  73. 39 14
      Source/BansheeEditor/Include/BsScenePicking.h
  74. 104 18
      Source/BansheeEditor/Source/BsScenePicking.cpp
  75. 2 0
      Source/BansheeFBXImporter/Source/BsFBXImporter.cpp
  76. 1 1
      Source/MBansheeEditor/MBansheeEditor.csproj
  77. 6 6
      Source/MBansheeEditor/Window/MenuItems.cs
  78. 1 1
      Source/MBansheeEditor/Windows/Scene/SceneCamera.cs
  79. 55 3
      Source/MBansheeEditor/Windows/Scene/SceneSelection.cs
  80. 119 14
      Source/MBansheeEditor/Windows/Scene/SceneWindow.cs
  81. 1 1
      Source/MBansheeEngine/MBansheeEngine.csproj
  82. 2 2
      Source/RenderBeast/Include/BsRendererCamera.h
  83. 1 1
      Source/RenderBeast/Source/BsRendererCamera.cpp
  84. 4 1
      Source/SBansheeEditor/Include/BsScriptSceneSelection.h
  85. 122 5
      Source/SBansheeEditor/Source/BsScriptSceneSelection.cpp

BIN
Data/Editor/GUISkin.asset


BIN
Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_AnimationClipIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_AudioClipIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_CSharpIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_FolderIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_FolderIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_FolderIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_FontIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_FontIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_FontIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_GUISkinIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_MaterialIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_MeshIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_MeshIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_MeshIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMaterialIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_PhysicsMeshIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_PrefabIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_ShaderIncludeIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_SpriteIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextIcon.psd48.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextureIcon.psd16.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextureIcon.psd32.asset


BIN
Data/Editor/Icons/Sprites/sprite_TextureIcon.psd48.asset


BIN
Data/Editor/Includes/PickingAlphaCull.bslinc.asset


BIN
Data/Editor/Includes/PickingCull.bslinc.asset


BIN
Data/Editor/ResourceManifest.asset


BIN
Data/Editor/Shaders/PickingAlphaCullCCW.bsl.asset


BIN
Data/Editor/Shaders/PickingAlphaCullCW.bsl.asset


BIN
Data/Editor/Shaders/PickingAlphaCullNone.bsl.asset


BIN
Data/Editor/Shaders/PickingCullCCW.bsl.asset


BIN
Data/Editor/Shaders/PickingCullCW.bsl.asset


BIN
Data/Editor/Shaders/PickingCullNone.bsl.asset


BIN
Data/Editor/Timestamp.asset


BIN
Data/Editor/arial.ttf.asset


BIN
Data/Editor/arialAA.ttf.asset


+ 15 - 3
Data/Raw/Editor/Includes/PickingAlphaCull.bslinc

@@ -23,11 +23,14 @@ Technique : base("PickingAlphaCull") =
 
 			void main(
 				in float3 inPos : POSITION,
+				in float3 inNorm : NORMAL,
 				in float2 uv : TEXCOORD0,
 				out float4 oPosition : SV_Position,
+				out float4 oNorm : NORMAL,
 				out float2 oUv : TEXCOORD0)
 			{
 				oPosition = mul(matWorldViewProj, float4(inPos.xyz, 1));
+				oNorm = float4(inNorm, 0);
 				oUv = uv;
 			}
 		};
@@ -42,9 +45,12 @@ Technique : base("PickingAlphaCull") =
 
 			float4 main(
 				in float4 inPos : SV_Position,
-				in float2 uv : TEXCOORD0) : SV_Target
+				in float4 inNorm : NORMAL,
+				in float2 uv : TEXCOORD0,
+				out float4 oNorm : SV_Target1) : SV_Target0
 			{
 				float4 color = mainTexture.Sample(mainTexSamp, uv);
+				oNorm = (inNorm + float4(1,1,1,0)) / 2;
 				if(color.a < alphaCutoff)
 					discard;
 				
@@ -111,6 +117,8 @@ Technique : base("PickingAlphaCull") =
 			uniform mat4 matWorldViewProj;
 			in vec3 bs_position;
 			in vec2 bs_texcoord0;
+			in vec3 bs_normal;
+			out vec4 normal
 			out vec2 texcoord0;
 
 			out gl_PerVertex
@@ -122,6 +130,7 @@ Technique : base("PickingAlphaCull") =
 			{
 				gl_Position = matWorldViewProj * vec4(bs_position.xyz, 1);
 				texcoord0 = bs_texcoord0;
+				normal = vec4(bs_normal, 0);
 			}
 		};
 		
@@ -130,7 +139,9 @@ Technique : base("PickingAlphaCull") =
 			uniform sampler2D mainTexture;
 			uniform vec4 colorIndex;
 			uniform float alphaCutoff;
+			in vec4 normal;
 			in vec2 texcoord0;
+			out vec4 normalsColor;
 			out vec4 fragColor;
 
 			void main()
@@ -138,9 +149,10 @@ Technique : base("PickingAlphaCull") =
 				vec4 color = texture2D(mainTexture, texcoord0);
 				if(color.a < alphaCutoff)
 					discard;
-				
+					
+				normalsColor = (normal + vec4(1,1,1,0)) / 2;
 				fragColor = colorIndex;
 			}
 		};
 	};
-};
+};

+ 17 - 4
Data/Raw/Editor/Includes/PickingCull.bslinc

@@ -19,9 +19,12 @@ Technique : base("PickingCull") =
 
 			void main(
 				in float3 inPos : POSITION,
-				out float4 oPosition : SV_Position)
+				in float3 inNorm : NORMAL,
+				out float4 oPosition : SV_Position,
+				out float4 oNorm : NORMAL)
 			{
 				oPosition = mul(matWorldViewProj, float4(inPos.xyz, 1));
+				oNorm = float4(inNorm, 0);
 			}
 		};
 		
@@ -29,8 +32,13 @@ Technique : base("PickingCull") =
 		{
 			float4 colorIndex;
 
-			float4 main(in float4 inPos : SV_Position) : SV_Target
+			float4 main(
+				in float4 inPos : SV_Position,
+				in float4 inNorm : NORMAL,	
+				out float4 oNorm :SV_Target1
+			) : SV_Target0
 			{
+				oNorm = (inNorm + float4(1,1,1,0)) / 2;
 				return colorIndex;
 			}
 		};
@@ -81,7 +89,8 @@ Technique : base("PickingCull") =
 		{
 			uniform mat4 matWorldViewProj;
 			in vec3 bs_position;
-
+			in vec3 bs_normal;
+			out vec4 normal;
 			out gl_PerVertex
 			{
 				vec4 gl_Position;
@@ -89,19 +98,23 @@ Technique : base("PickingCull") =
 			
 			void main()
 			{
+				normal = vec4(bs_normal,0);
 				gl_Position = matWorldViewProj * vec4(bs_position.xyz, 1);
 			}
 		};
 		
 		Fragment =
 		{
+			in vec4 normal;
 			uniform vec4 colorIndex;
+			out vec4 normalsColor;
 			out vec4 fragColor;
 
 			void main()
 			{
+				normalsColor = (normal + vec4(1,1,1,0)) / 2;
 				fragColor = colorIndex;
 			}
 		};
 	};
-};
+};

+ 2 - 0
Documentation/Manuals/Native/style.md

@@ -40,6 +40,8 @@ Guidelines
   - Always put a space after a semicolon (e.g. for(int i = 0; i < 5; i++)).
   - Always put a space between operators (e.g. 5 + 2).
   - Separate meaningful parts of the code in a method with empty lines
+  - Always but a blank line after a block {}, and in general try to separate relevant pieces of code with "paragraphs" separated by blank lines
+  - No single line should be longer than column 124 (set up a guideline in your editor)
  - If method doesn't modify data, always mark it as const (getters especially)
  - Always pass non-primitive parameters by reference unless `null` is a valid value in which case use a pointer
  - Reference/pointer parameters that won't be modified by a function should always be `const`

+ 11 - 2
Source/BansheeCore/Include/BsCamera.h

@@ -348,11 +348,20 @@ namespace BansheeEngine
 		 * world space.
 		 *
 		 * @param[in]	screenPoint	Point to transform.
-		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
-		 *							origin to the point on the near plane.
+		 * @param[in]	depth		Depth to place the world point at, in world coordinates. The depth is applied to the 
+		 *							vector going from camera origin to the point on the near plane.
 		 */
 		Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
 
+		/**
+		* Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point in
+		* world space.
+		*
+		* @param[in]	screenPoint	Point to transform.
+		* @param[in]	deviceDepth	Depth to place the world point at, in normalized device coordinates.
+		*/
+		Vector3 screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth = 0.5f) const;
+
 		/**
 		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point
 		 * relative to camera's coordinate system (view space).

+ 20 - 3
Source/BansheeCore/Include/BsMultiRenderTexture.h

@@ -91,7 +91,7 @@ namespace BansheeEngine
 		SPtr<CoreObjectCore> createCore() const override;
 
 		/** @copydoc CoreObjectCore::syncToCore */
-		virtual CoreSyncData syncToCore(FrameAlloc* allocator) override;
+		CoreSyncData syncToCore(FrameAlloc* allocator) override;
 
 		MULTI_RENDER_TEXTURE_DESC mDesc;
 		Vector<HTexture> mBindableColorTex;
@@ -116,16 +116,33 @@ namespace BansheeEngine
 		virtual ~MultiRenderTextureCore();
 
 		/** @copydoc CoreObjectCore::initialize */
-		virtual void initialize() override;
+		void initialize() override;
 
 		/** Returns properties that describe the render texture. */
 		const MultiRenderTextureProperties& getProperties() const;
 
+		/**
+		 * Returns a depth/stencil surface texture you may bind as an input to an GPU program.
+		 *
+		 * @note	Be aware that you cannot bind a render texture for reading and writing at the same time.
+		 */
+		const SPtr<TextureView> getBindableDepthStencilTexture() const { return mDepthStencilSurface; }
+
+		/**
+		 * Returns a color surface texture you may bind as an input to an GPU program.
+		 *
+		 * @note	Be aware that you cannot bind a render texture for reading and writing at the same time.
+		 */
+		const SPtr<TextureView>& getBindableColorTexture(UINT32 idx) const { return mColorSurfaces[idx]; }
+
+		/** @copydoc	TextureManager::createMultiRenderTexture(const MULTI_RENDER_TEXTURE_DESC&) */
+		static SPtr<MultiRenderTextureCore> create(const MULTI_RENDER_TEXTURE_CORE_DESC& desc);
+
 	protected:
 		MultiRenderTextureCore(const MULTI_RENDER_TEXTURE_CORE_DESC& desc);
 
 		/** @copydoc CoreObjectCore::syncToCore */
-		virtual void syncToCore(const CoreSyncData& data) override;
+		void syncToCore(const CoreSyncData& data) override;
 
 	private:
 		/** Checks that all render surfaces and depth/stencil surface match. If they do not match an exception is thrown. */

+ 18 - 3
Source/BansheeCore/Include/BsPixelData.h

@@ -306,7 +306,7 @@ namespace BansheeEngine
 		Color getColorAt(UINT32 x, UINT32 y, UINT32 z = 0) const;
 
 		/**	Sets the pixel color at the specified coordinates. */
-        void setColorAt(Color const &cv, UINT32 x, UINT32 y, UINT32 z = 0);
+        void setColorAt(const Color& color, UINT32 x, UINT32 y, UINT32 z = 0);
 
 		/**
 		 * Converts all the internal data into an array of colors. Array is mapped as such: 
@@ -326,6 +326,21 @@ namespace BansheeEngine
 		 */
 		void setColors(Color* colors, UINT32 numElements);
 
+		/** 
+		 * Decodes data stored in a depth texture at the specified pixel coordinates, and outputs a floating point depth
+		 * value in range [0, 1]. 
+		 */
+		float getDepthAt(UINT32 x, UINT32 y, UINT32 z = 0) const;
+
+		/** Sets a depth value in range [0, 1] at the specified pixel coordinates. */
+		void setDepthAt(float depth, UINT32 x, UINT32 y, UINT32 z = 0);
+
+		/**
+		 * Converts all the internal data into an array of float. Array is mapped as such:
+		 * arrayIdx = x + y * width + z * width * height.
+		 */
+		Vector<float> getDepths() const;
+
 		/**
 		 * Constructs a new object with an internal buffer capable of holding "extents" volume of pixels, where each pixel
 		 * is of the specified pixel format. Extent offsets are also stored, but are not used internally.
@@ -373,8 +388,8 @@ namespace BansheeEngine
 	public:
 		friend class PixelDataRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
+		RTTITypeBase* getRTTI() const override;
     };
 
 	/** @} */
-}
+}

+ 7 - 1
Source/BansheeCore/Include/BsPixelUtil.h

@@ -189,6 +189,12 @@ namespace BansheeEngine
 		 * is not natively floating point a conversion is done in such a way that returned values range [0.0, 1.0].
 		 */
         static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src); 
+
+		/** Writes a depth value to the provided memory location. Depth should be in range [0, 1]. */
+		static void packDepth(float depth, const PixelFormat format, void* dest);
+
+		/** Reads the depth from the provided memory location. Value ranges in [0, 1]. */
+		static float unpackDepth(PixelFormat format, void* src);
         
 		/**
 		 * Converts pixels from one format to another. Provided pixel data objects must have previously allocated buffers
@@ -227,4 +233,4 @@ namespace BansheeEngine
     };
 
 	/** @} */
-}
+}

+ 19 - 0
Source/BansheeCore/Source/BsCamera.cpp

@@ -554,6 +554,25 @@ namespace BansheeEngine
 		return ndcToWorldPoint(ndcPoint, depth);
 	}
 
+	Vector3 CameraBase::screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth) const
+	{
+		Vector2 ndcPoint = screenToNdcPoint(screenPoint);
+		Vector4 worldPoint(ndcPoint.x, ndcPoint.y, deviceDepth, 1.0f);
+		worldPoint = getProjectionMatrixRS().inverse().multiply(worldPoint);
+
+		Vector3 worldPoint3D;
+		if (Math::abs(worldPoint.w) > 1e-7f)
+		{
+			float invW = 1.0f / worldPoint.w;
+
+			worldPoint3D.x = worldPoint.x * invW;
+			worldPoint3D.y = worldPoint.y * invW;
+			worldPoint3D.z = worldPoint.z * invW;
+		}
+
+		return viewToWorldPoint(worldPoint3D);
+	}
+
 	Vector3 CameraBase::screenToViewPoint(const Vector2I& screenPoint, float depth) const
 	{
 		Vector2 ndcPoint = screenToNdcPoint(screenPoint);

+ 5 - 0
Source/BansheeCore/Source/BsMultiRenderTexture.cpp

@@ -127,6 +127,11 @@ namespace BansheeEngine
 		return static_cast<const MultiRenderTextureProperties&>(getPropertiesInternal());
 	}
 
+	SPtr<MultiRenderTextureCore> MultiRenderTextureCore::create(const MULTI_RENDER_TEXTURE_CORE_DESC& desc)
+	{
+		return TextureCoreManager::instance().createMultiRenderTexture(desc);
+	}
+
 	void MultiRenderTextureCore::throwIfBuffersDontMatch() const
 	{
 		SPtr<TextureView> firstSurfaceDesc = nullptr;

+ 51 - 3
Source/BansheeCore/Source/BsPixelData.cpp

@@ -83,11 +83,11 @@ namespace BansheeEngine
 		return cv;
 	}
 
-	void PixelData::setColorAt(Color const &cv, UINT32 x, UINT32 y, UINT32 z)
+	void PixelData::setColorAt(const Color& color, UINT32 x, UINT32 y, UINT32 z)
 	{
 		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
 		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
-		PixelUtil::packColor(cv, mFormat, (unsigned char *)getData() + pixelOffset);
+		PixelUtil::packColor(color, mFormat, (unsigned char *)getData() + pixelOffset);
 	}
 
 	Vector<Color> PixelData::getColors() const
@@ -176,6 +176,54 @@ namespace BansheeEngine
 		setColorsInternal(colors, numElements);
 	}
 
+	float PixelData::getDepthAt(UINT32 x, UINT32 y, UINT32 z) const
+	{
+		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
+		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
+		return PixelUtil::unpackDepth(mFormat, (unsigned char *)getData() + pixelOffset);;
+	}
+
+	void PixelData::setDepthAt(float depth, UINT32 x, UINT32 y, UINT32 z)
+	{
+		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
+		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
+		PixelUtil::packDepth(depth, mFormat, (unsigned char *)getData() + pixelOffset);
+	}
+
+	Vector<float> PixelData::getDepths() const
+	{
+		UINT32 depth = mExtents.getDepth();
+		UINT32 height = mExtents.getHeight();
+		UINT32 width = mExtents.getWidth();
+
+		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
+		UINT8* data = getData();
+
+		Vector<float> depths(width * height * depth);
+		for (UINT32 z = 0; z < depth; z++)
+		{
+			UINT32 zArrayIdx = z * width * height;
+			UINT32 zDataIdx = z * mSlicePitch * pixelSize;
+
+			for (UINT32 y = 0; y < height; y++)
+			{
+				UINT32 yArrayIdx = y * width;
+				UINT32 yDataIdx = y * mRowPitch * pixelSize;
+
+				for (UINT32 x = 0; x < width; x++)
+				{
+					UINT32 arrayIdx = x + yArrayIdx + zArrayIdx;
+					UINT32 dataIdx = x * pixelSize + yDataIdx + zDataIdx;
+
+					UINT8* dest = data + dataIdx;
+					depths[arrayIdx] = PixelUtil::unpackDepth(mFormat, dest);
+				}
+			}
+		}
+
+		return depths;
+	}
+
 	SPtr<PixelData> PixelData::create(const PixelVolume &extents, PixelFormat pixelFormat)
 	{
 		SPtr<PixelData> pixelData = bs_shared_ptr_new<PixelData>(extents, pixelFormat);
@@ -210,4 +258,4 @@ namespace BansheeEngine
 	{
 		return PixelData::getRTTIStatic();
 	}
-}
+}

+ 48 - 5
Source/BansheeCore/Source/BsPixelUtil.cpp

@@ -740,11 +740,11 @@ namespace BansheeEngine
 	//-----------------------------------------------------------------------
 		{"PF_D32_S8X24",
 		/* Bytes per element */
-		4,
+		8,
 		/* Flags */
 		PFF_DEPTH | PFF_FLOAT,
 		/* Component type and count */
-		PCT_FLOAT32, 1,
+		PCT_FLOAT32, 2,
 		/* rbits, gbits, bbits, abits */
 		0, 0, 0, 0,
 		/* Masks and shifts */
@@ -753,11 +753,11 @@ namespace BansheeEngine
 	//-----------------------------------------------------------------------
 		{"PF_D24_S8",
 		/* Bytes per element */
-		8,
+		4,
 		/* Flags */
 		PFF_DEPTH | PFF_FLOAT,
 		/* Component type and count */
-		PCT_FLOAT32, 2,
+		PCT_FLOAT32, 1,
 		/* rbits, gbits, bbits, abits */
 		0, 0, 0, 0,
 		/* Masks and shifts */
@@ -1275,7 +1275,6 @@ namespace BansheeEngine
     void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
     {
         const PixelFormatDescription &des = getDescriptionFor(format);
-
         if(des.flags & PFF_NATIVEENDIAN) 
 		{
             // Shortcut for integer formats unpacking
@@ -1359,6 +1358,50 @@ namespace BansheeEngine
         }
     }
 
+	void PixelUtil::packDepth(float depth, const PixelFormat format, void* dest)
+	{
+		if (!isDepth(format))
+		{
+			LOGERR("Cannot convert depth to " + getFormatName(format) + ": it is not a depth format");
+			return;
+		}
+		
+		LOGERR("Method is not implemented");	
+		//TODO implement depth packing
+
+	}
+
+	float PixelUtil::unpackDepth(PixelFormat format, void* src)
+	{
+		const PixelFormatDescription &des = getDescriptionFor(format);
+		if (!isDepth(format))
+		{
+			LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
+			return 0;
+		}
+		
+		UINT32* color = (UINT32 *)src;
+		switch (format) 
+		{
+		case PF_D24S8:
+			return  static_cast<float>(*color & 0x00FFFFFF) / (float)16777216;
+			break;
+		case PF_D16:
+			return static_cast<float>(*color & 0xFFFF) / (float)65536;
+			break;
+		case PF_D32:
+			return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
+			break;
+		case PF_D32_S8X24:
+			return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
+			break;
+		default:
+			LOGERR("Cannot unpack from " + getFormatName(format));
+			return 0;
+			break;
+		}
+	}
+
     void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
     {
         assert(src.getWidth() == dst.getWidth() &&

+ 39 - 14
Source/BansheeEditor/Include/BsScenePicking.h

@@ -13,6 +13,21 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	/** Contains the data of a scene picking action. */
+	struct SnapData
+	{
+		Vector3 normal;
+		Vector3 pickPosition;
+	};
+
+	/** Contains the results of a scene picking action. */
+	struct PickResults
+	{
+		Vector<UINT32> objects;
+		Vector3 normal;
+		float depth;
+	};
+
 	class ScenePickingCore;
 
 	/**	Handles picking of scene objects with a pointer in scene view. */
@@ -36,25 +51,32 @@ namespace BansheeEngine
 		/**
 		 * Attempts to find a single nearest scene object under the provided position and area.
 		 *
-		 * @param[in]	cam			Camera to perform the picking from.
-		 * @param[in]	position	Pointer position relative to the camera viewport, in pixels.
-		 * @param[in]	area		Width/height of the checked area in pixels. Use (1, 1) if you want the exact position
-		 *							under the pointer.
-		 * @return					Nearest SceneObject under the provided area, or an empty handle if no object is found.
+		 * @param[in]	cam					Camera to perform the picking from.
+		 * @param[in]	position			Pointer position relative to the camera viewport, in pixels.
+		 * @param[in]	area				Width/height of the checked area in pixels. Use (1, 1) if you want the exact
+		 *									position under the pointer.
+		 * @param[in]	ignoreRenderables	A list of objects that should be ignored during scene picking.
+		 * @param[out]	data				Picking data regarding position and normal.
+		 * @return							Nearest SceneObject under the provided area, or an empty handle if no object is
+		 *									found.
 		 */
-		HSceneObject pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area);
+		HSceneObject pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, 
+			Vector<HSceneObject>& ignoreRenderables, SnapData* data = nullptr);
 
 		/**
 		 * Attempts to find all scene objects under the provided position and area. This does not mean objects occluded by
 		 * other objects.
 		 *
-		 * @param[in]	cam			Camera to perform the picking from.
-		 * @param[in]	position	Pointer position relative to the camera viewport, in pixels.
-		 * @param[in]	area		Width/height of the checked area in pixels. Use (1, 1) if you want the exact position
-		 *							under the pointer.
-		 * @return					A list of SceneObject%s under the provided area.
+		 * @param[in]	cam					Camera to perform the picking from.
+		 * @param[in]	position			Pointer position relative to the camera viewport, in pixels.
+		 * @param[in]	area				Width/height of the checked area in pixels. Use (1, 1) if you want the exact 
+		 *									position under the pointer.
+		 * @param[in]	ignoreRenderables	A list of objects that should be ignored during scene picking.
+		 * @param[out]	data				Picking data regarding position and normal.
+		 * @return							A list of SceneObject%s under the provided area.
 		 */
-		Vector<HSceneObject> pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area);
+		Vector<HSceneObject> pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, 
+			Vector<HSceneObject>& ignoreRenderables, SnapData* data = nullptr);
 
 	private:
 		friend class ScenePickingCore;
@@ -123,19 +145,22 @@ namespace BansheeEngine
 		 * @param[in]	viewportArea	Normalized area of the render target we're rendering in.
 		 * @param[in]	position		Position of the pointer where to pick objects, in pixels relative to viewport.
 		 * @param[in]	area			Width/height of the area to pick objects, in pixels.
+		 * @param[in]	gatherSnapData	Determines whather normal & depth information will be recorded.
 		 * @param[out]	asyncOp			Async operation handle that when complete will contain the results of the picking
 		 *								operation in the form of Vector<SelectedObject>.
 		 */
 		void corePickingEnd(const SPtr<RenderTargetCore>& target, const Rect2& viewportArea, const Vector2I& position,
-			const Vector2I& area, AsyncOp& asyncOp);
+			const Vector2I& area, bool gatherSnapData, AsyncOp& asyncOp);
 
 	private:
 		friend class ScenePicking;
 
+		SPtr<MultiRenderTextureCore> mPickingTexture;
+
 		static const float ALPHA_CUTOFF;
 
 		MaterialData mMaterialData[3];
 	};
 
 	/** @} */
-}
+}

+ 104 - 18
Source/BansheeEditor/Source/BsScenePicking.cpp

@@ -17,6 +17,7 @@
 #include "BsPass.h"
 #include "BsRasterizerState.h"
 #include "BsRenderTarget.h"
+#include "BsMultiRenderTexture.h"
 #include "BsPixelData.h"
 #include "BsGpuParams.h"
 #include "BsGpuParamsSet.h"
@@ -53,16 +54,25 @@ namespace BansheeEngine
 		gCoreAccessor().queueCommand(std::bind(&ScenePickingCore::destroy, mCore));
 	}
 
-	HSceneObject ScenePicking::pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area)
+	HSceneObject ScenePicking::pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, 
+		Vector<HSceneObject>& ignoreRenderables, SnapData* data)
 	{
-		Vector<HSceneObject> selectedObjects = pickObjects(cam, position, area);
+		Vector<HSceneObject> selectedObjects = pickObjects(cam, position, area, ignoreRenderables, data);
 		if (selectedObjects.size() == 0)
 			return HSceneObject();
-
+			
+		if (data != nullptr)
+		{
+			Matrix3 rotation;
+			selectedObjects[0]->getWorldRotation().toRotationMatrix(rotation);
+			data->normal = rotation.inverse().transpose().transform(data->normal);
+		}
+		
 		return selectedObjects[0];
 	}
 
-	Vector<HSceneObject> ScenePicking::pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area)
+	Vector<HSceneObject> ScenePicking::pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, 
+		Vector<HSceneObject>& ignoreRenderables, SnapData* data)
 	{
 		auto comparePickElement = [&] (const ScenePicking::RenderablePickData& a, const ScenePicking::RenderablePickData& b)
 		{
@@ -96,6 +106,19 @@ namespace BansheeEngine
 			if (!mesh.isLoaded())
 				continue;
 
+			bool found = false;
+			for (int i = 0; i < ignoreRenderables.size(); i++)
+			{
+				if (ignoreRenderables[i] == so)
+				{
+					found = true;
+					break;
+				}
+			}
+			
+			if (found)
+				continue;
+
 			Bounds worldBounds = mesh->getProperties().getBounds();
 			Matrix4 worldTransform = so->getWorldTfrm();
 			worldBounds.transformAffine(worldTransform);
@@ -163,12 +186,19 @@ namespace BansheeEngine
 		GizmoManager::instance().renderForPicking(cam, [&](UINT32 inputIdx) { return encodeIndex(firstGizmoIdx + inputIdx); });
 
 		AsyncOp op = gCoreAccessor().queueReturnCommand(std::bind(&ScenePickingCore::corePickingEnd, mCore, target, 
-			cam->getViewport()->getNormArea(), position, area, _1));
+			cam->getViewport()->getNormArea(), position, area, data != nullptr, _1));
 		gCoreAccessor().submitToCoreThread(true);
 
 		assert(op.hasCompleted());
 
-		Vector<UINT32> selectedObjects = op.getReturnValue<Vector<UINT32>>();
+		PickResults pickResults = op.getReturnValue<PickResults>();
+		if (data != nullptr)
+		{
+			data->pickPosition = cam->screenToWorldPointDeviceDepth(position, pickResults.depth);
+			data->normal = pickResults.normal;
+		}
+
+		Vector<UINT32> selectedObjects = pickResults.objects;
 		Vector<HSceneObject> results;
 
 		for (auto& selectedObjectIdx : selectedObjects)
@@ -257,8 +287,29 @@ namespace BansheeEngine
 	{
 		RenderAPICore& rs = RenderAPICore::instance();
 
+		SPtr<RenderTextureCore> rtt = std::static_pointer_cast<RenderTextureCore>(target);
+
+		SPtr<TextureCore> outputTexture = rtt->getBindableColorTexture();
+		TextureProperties outputTextureProperties = outputTexture->getProperties();
+
+		SPtr<TextureCore> normalsTexture = TextureCore::create(TEX_TYPE_2D, outputTextureProperties.getWidth(),
+			outputTextureProperties.getHeight(), 0, PF_R8G8B8A8, TU_RENDERTARGET, false, 1);
+		SPtr<TextureCore> depthTexture = rtt->getBindableDepthStencilTexture();
+
+		MULTI_RENDER_TEXTURE_CORE_DESC pickingMRT;
+		pickingMRT.colorSurfaces.resize(2);
+		pickingMRT.colorSurfaces[0].face = 0;
+		pickingMRT.colorSurfaces[0].texture = outputTexture;
+		pickingMRT.colorSurfaces[1].face = 0;
+		pickingMRT.colorSurfaces[1].texture = normalsTexture;
+
+		pickingMRT.depthStencilSurface.face = 0;
+		pickingMRT.depthStencilSurface.texture = depthTexture;
+		
+		mPickingTexture = MultiRenderTextureCore::create(pickingMRT);
+
 		rs.beginFrame();
-		rs.setRenderTarget(target);
+		rs.setRenderTarget(mPickingTexture);
 		rs.setViewport(viewportArea);
 		rs.clearRenderTarget(FBT_COLOR | FBT_DEPTH | FBT_STENCIL, Color::White);
 		rs.setScissorRect(position.x, position.y, position.x + area.x, position.y + area.y);
@@ -309,9 +360,13 @@ namespace BansheeEngine
 	}
 
 	void ScenePickingCore::corePickingEnd(const SPtr<RenderTargetCore>& target, const Rect2& viewportArea, const Vector2I& position,
-		const Vector2I& area, AsyncOp& asyncOp)
+		const Vector2I& area, bool gatherSnapData, AsyncOp& asyncOp)
 	{
 		const RenderTargetProperties& rtProps = target->getProperties();
+		RenderAPICore& rs = RenderAPICore::instance();
+
+		rs.endFrame();
+		rs.setRenderTarget(nullptr);
 
 		if (rtProps.isWindow())
 		{
@@ -319,22 +374,28 @@ namespace BansheeEngine
 			BS_EXCEPT(NotImplementedException, "Picking is not supported on render windows as framebuffer readback methods aren't implemented");
 		}
 
-		SPtr<RenderTextureCore> rtt = std::static_pointer_cast<RenderTextureCore>(target);
-		SPtr<TextureCore> outputTexture = rtt->getBindableColorTexture();
+		SPtr<TextureCore> outputTexture = mPickingTexture->getBindableColorTexture(0)->getTexture();
+		SPtr<TextureCore> normalsTexture = mPickingTexture->getBindableColorTexture(1)->getTexture();
+		SPtr<TextureCore> depthTexture = mPickingTexture->getBindableDepthStencilTexture()->getTexture();
 
 		if (position.x < 0 || position.x >= (INT32)outputTexture->getProperties().getWidth() ||
 			position.y < 0 || position.y >= (INT32)outputTexture->getProperties().getHeight())
 		{
+			mPickingTexture = nullptr;
+
 			asyncOp._completeOperation(Vector<UINT32>());
 			return;
 		}
 
 		SPtr<PixelData> outputPixelData = outputTexture->getProperties().allocateSubresourceBuffer(0);
-		AsyncOp unused;
-
-		RenderAPICore& rs = RenderAPICore::instance();
+		SPtr<PixelData> normalsPixelData;
+		SPtr<PixelData> depthPixelData;
+		if (gatherSnapData)
+		{
+			normalsPixelData = normalsTexture->getProperties().allocateSubresourceBuffer(0);
+			depthPixelData = depthTexture->getProperties().allocateSubresourceBuffer(0);
+		}
 
-		rs.endFrame();
 		outputTexture->readSubresource(0, *outputPixelData);
 
 		Map<UINT32, UINT32> selectionScores;
@@ -400,10 +461,35 @@ namespace BansheeEngine
 			return b.score < a.score;
 		});
 
-		Vector<UINT32> results;
+		Vector<UINT32> objects;
 		for (auto& selectedObject : selectedObjects)
-			results.push_back(selectedObject.index);
+			objects.push_back(selectedObject.index);
+		
+		PickResults result;
+		if (gatherSnapData)
+		{
+			depthTexture->readSubresource(0, *depthPixelData);
+			normalsTexture->readSubresource(0, *normalsPixelData);
+
+			Vector2I samplePixel = position;
+			if (rtProps.requiresTextureFlipping())
+				samplePixel.y = depthPixelData->getHeight() - samplePixel.y;
+
+			float depth = depthPixelData->getDepthAt(samplePixel.x, samplePixel.y);
+			Color normal = normalsPixelData->getColorAt(samplePixel.x, samplePixel.y);
+
+			const RenderAPIInfo& rapiInfo = rs.getAPIInfo();
+			float max = rapiInfo.getMaximumDepthInputValue();
+			float min = rapiInfo.getMinimumDepthInputValue();
+			depth = depth * Math::abs(max - min) + min;
+
+			result.depth = depth;
+			result.normal = Vector3((normal.r * 2) - 1, (normal.g * 2) - 1, (normal.b * 2) - 1);
+		}
 
-		asyncOp._completeOperation(results);
+		mPickingTexture = nullptr;
+		
+		result.objects = objects;
+		asyncOp._completeOperation(result);
 	}
-}
+}

+ 2 - 0
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -88,6 +88,8 @@ namespace BansheeEngine
 		:SpecificImporter(), mFBXManager(nullptr)
 	{
 		mExtensions.push_back(L"fbx");
+		mExtensions.push_back(L"obj");
+		mExtensions.push_back(L"dae");
 	}
 
 	FBXImporter::~FBXImporter() 

+ 1 - 1
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -232,7 +232,7 @@
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
-    <PostBuildEvent>$(ProjectDir)..\..\Scripts\pdb2mdb.bat "$(TargetPath)" "$(ConfigurationName)"</PostBuildEvent>
+    <PostBuildEvent>"$(ProjectDir)..\..\Scripts\pdb2mdb.bat" "$(TargetPath)" "$(ConfigurationName)"</PostBuildEvent>
   </PropertyGroup>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 6 - 6
Source/MBansheeEditor/Window/MenuItems.cs

@@ -720,16 +720,16 @@ namespace BansheeEditor
         /// </summary>
         private static void FocusOnHierarchyOrScene()
         {
-            HierarchyWindow hierarchyWindow = EditorWindow.GetWindow<HierarchyWindow>();
-            if (hierarchyWindow != null)
+            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
+            if (sceneWindow != null)
             {
-                hierarchyWindow.HasFocus = true;
+                sceneWindow.HasFocus = true;
                 return;
             }
 
-            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
-            if (sceneWindow != null)
-                sceneWindow.HasFocus = true;
+            HierarchyWindow hierarchyWindow = EditorWindow.GetWindow<HierarchyWindow>();
+            if (hierarchyWindow != null)
+                hierarchyWindow.HasFocus = true;
         }
     }
 

+ 1 - 1
Source/MBansheeEditor/Windows/Scene/SceneCamera.cs

@@ -271,7 +271,7 @@ namespace BansheeEditor
             }
 
             SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
-            if (sceneWindow.Active && sceneWindow.HasFocus)
+            if ((sceneWindow.Active && sceneWindow.HasFocus) || sceneWindow.IsPointerHovering)
             {
                 Rect2I bounds = sceneWindow.Bounds;
 

+ 55 - 3
Source/MBansheeEditor/Windows/Scene/SceneSelection.cs

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 using System;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using BansheeEngine;
 
 namespace BansheeEditor
@@ -10,6 +11,23 @@ namespace BansheeEditor
      *  @{
      */
 
+    /// <summary>
+    /// Contains world position and normal of the surface of the object in a snap operation.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    struct SnapData
+    {
+        /// <summary>
+        /// The normal to the object surface at the snapping point.
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// The world position on the surface of the object.
+        /// </summary>
+        public Vector3 position;
+    }
+
     /// <summary>
     /// Handles rendering of the selection overlay and picking of objects in the target camera's view.
     /// </summary>
@@ -37,9 +55,37 @@ namespace BansheeEditor
         /// </summary>
         /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param>
         /// <param name="controlHeld">Should this selection add to the existing selection, or replace it.</param>
-        internal void PickObject(Vector2I pointerPos, bool controlHeld)
+        /// <param name="ignoreSceneObjects">Optional set of objects to ignore during scene picking.</param>
+        internal void PickObject(Vector2I pointerPos, bool controlHeld, SceneObject[] ignoreSceneObjects = null)
         {
-            Internal_PickObject(mCachedPtr, ref pointerPos, controlHeld);
+            Internal_PickObject(mCachedPtr, ref pointerPos, controlHeld, ignoreSceneObjects);
+        }
+
+        /// <summary>
+        /// Attempts to select a scene object in the specified area.
+        /// </summary>
+        /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param>
+        /// <param name="area">Size of the in which objects will be selected, in pixels and relative to 
+        ///                    <paramref name="pointerPos"/>.</param>
+        /// <param name="controlHeld">Should this selection add to the existing selection, or replace it.</param>
+        /// <param name="ignoreSceneObjects">Optional set of objects to ignore during scene picking.</param>
+        internal void PickObjects(Vector2I pointerPos, Vector2I area, bool controlHeld, 
+            SceneObject[] ignoreSceneObjects = null)
+        {
+            Internal_PickObjects(mCachedPtr, ref pointerPos, ref area, controlHeld, ignoreSceneObjects);
+        }
+
+        /// <summary>
+        /// Attempts to find a scene object under the provided position, while also returning the world position and normal
+        /// of the point that was hit.
+        /// </summary>
+        /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param>
+        /// <param name="data">Position and normal on the object surface at the point that was hit.</param>
+        /// <param name="ignoreSceneObjects">Optional set of objects to ignore during scene picking.</param>
+        /// <returns>The object the pointer is snapping to.</returns>
+        internal SceneObject Snap(Vector2I pointerPos, out SnapData data, SceneObject[] ignoreSceneObjects = null)
+        {
+            return Internal_Snap(mCachedPtr, ref pointerPos, out data, ignoreSceneObjects);
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
@@ -49,7 +95,13 @@ namespace BansheeEditor
         private static extern void Internal_Draw(IntPtr thisPtr);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_PickObject(IntPtr thisPtr, ref Vector2I pointerPos, bool controlHeld);
+        private static extern void Internal_PickObject(IntPtr thisPtr, ref Vector2I pointerPos, bool controlHeld, SceneObject[] ignoreRenderables);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_PickObjects(IntPtr thisPtr, ref Vector2I pointerPos, ref Vector2I extents, bool controlHeld, SceneObject[] ignoreRenderables);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject Internal_Snap(IntPtr thisPtr, ref Vector2I pointerPos, out SnapData data, SceneObject[] ignoreRenderables);
     }
 
     /** @} */

+ 119 - 14
Source/MBansheeEditor/Windows/Scene/SceneWindow.cs

@@ -85,6 +85,12 @@ namespace BansheeEditor
         private bool dragActive;
         private SceneObject draggedSO;
         private Vector3 draggedSOOffset;
+        private GUITexture dragSelection;
+        private bool isDraggingSelection;
+        private Vector2I dragSelectionStart;
+        private Vector2I dragSelectionEnd;
+        private Vector2I mouseDownPosition;
+        private GUIPanel selectionPanel;
 
         /// <summary>
         /// Returns the scene camera.
@@ -265,6 +271,8 @@ namespace BansheeEditor
             GUIPanel mainPanel = mainLayout.AddPanel();
             rtPanel = mainPanel.AddPanel();
 
+            selectionPanel = mainPanel.AddPanel(-1);
+
             GUIPanel sceneAxesPanel = mainPanel.AddPanel(-1);
             sceneAxesGUI = new SceneAxesGUI(this, sceneAxesPanel, HandleAxesGUISize, HandleAxesGUISize, ProjectionType.Perspective);
 
@@ -478,10 +486,13 @@ namespace BansheeEditor
             // Update scene view handles and selection
             sceneGizmos.Draw();
             sceneGrid.Draw();
-
+            bool dragResult = false;
             bool handleActive = false;
+            Vector2I scenePos;
+            bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos);
             if (Input.IsPointerButtonUp(PointerButton.Left))
             {
+                dragResult = EndDragSelection();
                 if (sceneHandles.IsActive())
                 {
                     sceneHandles.ClearSelection();
@@ -493,11 +504,12 @@ namespace BansheeEditor
                     sceneAxesGUI.ClearSelection();
                     handleActive = true;
                 }
+            } 
+            else if (Input.IsPointerButtonDown(PointerButton.Left))
+            {
+                mouseDownPosition = scenePos;
             }
 
-            Vector2I scenePos;
-            bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos);
-
             bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress;
             draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource;
 
@@ -506,13 +518,12 @@ namespace BansheeEditor
                 if (DragDrop.DropInProgress)
                 {
                     dragActive = false;
-
                     if (draggedSO != null)
                     {
                         Selection.SceneObject = draggedSO;
                         EditorApplication.SetSceneDirty();
                     }
-
+                    
                     draggedSO = null;
                 }
                 else
@@ -540,7 +551,6 @@ namespace BansheeEditor
 
                                         Renderable renderable = draggedSO.AddComponent<Renderable>();
                                         renderable.Mesh = mesh;
-
                                         if (mesh != null)
                                             draggedSOOffset = mesh.Bounds.Box.Center;
                                         else
@@ -573,8 +583,20 @@ namespace BansheeEditor
 
                     if (draggedSO != null)
                     {
-                        Ray worldRay = camera.ViewportToWorldRay(scenePos);
-                        draggedSO.Position = worldRay*DefaultPlacementDepth - draggedSOOffset;
+                        if (Input.IsButtonHeld(ButtonCode.Space))
+                        {
+                            SnapData snapData;
+                            sceneSelection.Snap(scenePos, out snapData, new SceneObject[] {draggedSO});
+
+                            Quaternion q = Quaternion.FromToRotation(Vector3.YAxis, snapData.normal);
+                            draggedSO.Position = snapData.position;
+                            draggedSO.Rotation = q;
+                        }
+                        else
+                        {
+                            Ray worldRay = camera.ViewportToWorldRay(scenePos);
+                            draggedSO.Position = worldRay * DefaultPlacementDepth - draggedSOOffset;
+                        }
                     }
                 }
 
@@ -594,11 +616,11 @@ namespace BansheeEditor
                 }
             }
 
-            if (HasContentFocus)
+            if (HasContentFocus || IsPointerHovering)
             {
                 cameraController.EnableInput(true);
 
-                if (inBounds)
+                if (inBounds && HasContentFocus)
                 {
                     if (Input.IsPointerButtonDown(PointerButton.Left))
                     {
@@ -610,21 +632,29 @@ namespace BansheeEditor
                         else
                             sceneHandles.TrySelect(scenePos);
                     }
+                    else if (Input.IsPointerButtonHeld(PointerButton.Left) && !handleActive && !dragActive &&
+                             draggedSO == null && scenePos != mouseDownPosition)
+                    {
+                        if (isDraggingSelection)
+                            UpdateDragSelection(scenePos);
+                        else
+                            StartDragSelection(scenePos);
+                    }
                     else if (Input.IsPointerButtonUp(PointerButton.Left))
                     {
-                        if (!handleActive)
+                        if (!handleActive && !dragActive && !dragResult)
                         {
                             bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) ||
                                             Input.IsButtonHeld(ButtonCode.RightControl);
 
-                            sceneSelection.PickObject(scenePos, ctrlHeld);
+                            sceneSelection.PickObject(scenePos, ctrlHeld, new SceneObject[] {draggedSO});
                         }
                     }
                 }
             }
             else
                 cameraController.EnableInput(false);
-
+            
             SceneHandles.BeginInput();
             sceneHandles.UpdateInput(scenePos, Input.PointerDelta);
             sceneHandles.Draw();
@@ -911,6 +941,81 @@ namespace BansheeEditor
 
 		    objects = cleanList.ToArray();
 	    }
+
+        /// <summary>
+        /// Starts a drag operation that displays a selection outline allowing the user to select multiple entries at once.
+        /// </summary>
+        /// <param name="scenePos">Coordinates relative to the scene where the drag originated.</param>
+        private void StartDragSelection(Vector2I scenePos)
+        {
+            isDraggingSelection = true;
+            dragSelectionStart = scenePos;
+            dragSelectionEnd = dragSelectionStart;
+        }
+
+        /// <summary>
+        /// Updates a selection outline drag operation by expanding the outline to the new location. Elements in the outline
+        /// are selected.
+        /// </summary>
+        /// <param name="scenePos">Coordinates of the pointer relative to the scene.</param>
+        /// <returns>True if the selection outline drag is valid and was updated, false otherwise.</returns>
+        private bool UpdateDragSelection(Vector2I scenePos)
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection == null)
+            {
+                dragSelection = new GUITexture(null, true, EditorStylesInternal.SelectionArea);
+                selectionPanel.AddElement(dragSelection);
+            }
+            
+            dragSelectionEnd = scenePos;
+
+            Rect2I selectionArea = new Rect2I();
+
+            Vector2I min = new Vector2I(Math.Min(dragSelectionStart.x, dragSelectionEnd.x), Math.Min(dragSelectionStart.y, dragSelectionEnd.y));
+            Vector2I max = new Vector2I(Math.Max(dragSelectionStart.x, dragSelectionEnd.x), Math.Max(dragSelectionStart.y, dragSelectionEnd.y));
+            selectionArea.x = min.x;
+            selectionArea.y = min.y;
+            selectionArea.width = Math.Max(max.x - min.x, 1);
+            selectionArea.height = Math.Max(max.y - min.y, 1);
+
+            dragSelection.Bounds = selectionArea;
+
+            return true;
+        }
+
+        /// <summary>
+        /// Ends the selection outline drag operation. Elements in the outline are selected.
+        /// </summary>
+        /// <returns>True if the selection outline drag is valid and was ended, false otherwise.</returns>
+        private bool EndDragSelection()
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection != null)
+            {
+                dragSelection.Destroy();
+                dragSelection = null;
+            }
+
+            if ((dragSelectionEnd - dragSelectionStart).Length < 1)
+            {
+                isDraggingSelection = false;
+                return false;
+            }
+
+            Vector2I min = new Vector2I(Math.Min(dragSelectionStart.x, dragSelectionEnd.x),
+                    Math.Min(dragSelectionStart.y, dragSelectionEnd.y));
+            Vector2I max = new Vector2I(Math.Max(dragSelectionStart.x, dragSelectionEnd.x),
+                Math.Max(dragSelectionStart.y, dragSelectionEnd.y));
+            sceneSelection.PickObjects(min, max - min,
+                Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl));
+            isDraggingSelection = false;
+            return true;
+        }
     }
 
     /** @} */

+ 1 - 1
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -215,7 +215,7 @@
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
-    <PostBuildEvent>$(ProjectDir)..\..\Scripts\pdb2mdb.bat "$(TargetPath)" "$(ConfigurationName)"</PostBuildEvent>
+    <PostBuildEvent>"$(ProjectDir)..\..\Scripts\pdb2mdb.bat" "$(TargetPath)" "$(ConfigurationName)"</PostBuildEvent>
   </PropertyGroup>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 2 - 2
Source/RenderBeast/Include/BsRendererCamera.h

@@ -81,12 +81,12 @@ namespace BansheeEngine
 		/**
 		 * Extracts the necessary values from the projection matrix that allow you to transform device Z value into
 		 * world Z value.
-		 * 			
+		 * 
 		 * @param[in]	projMatrix	Projection matrix that was used to create the device Z value to transform.
 		 * @return					Returns two values that can be used to transform device z to world z using this formula:
 		 * 							z = (deviceZ + y) * x.
 		 */
-		Vector2 getDeviceZTransform(const Matrix4& projMatrix);
+		Vector2 getDeviceZTransform(const Matrix4& projMatrix) const;
 
 		const CameraCore* mCamera;
 		SPtr<RenderQueue> mOpaqueQueue;

+ 1 - 1
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -130,7 +130,7 @@ namespace BansheeEngine
 		mTransparentQueue->sort();
 	}
 
-	Vector2 RendererCamera::getDeviceZTransform(const Matrix4& projMatrix)
+	Vector2 RendererCamera::getDeviceZTransform(const Matrix4& projMatrix) const
 	{
 		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
 		// in world space. This involes applying the inverse projection transform to the depth value. When you multiply

+ 4 - 1
Source/SBansheeEditor/Include/BsScriptSceneSelection.h

@@ -4,6 +4,7 @@
 
 #include "BsScriptEditorPrerequisites.h"
 #include "BsScriptObject.h"
+#include "BsScenePicking.h"
 
 namespace BansheeEngine
 {
@@ -29,7 +30,9 @@ namespace BansheeEngine
 		/************************************************************************/
 		static void internal_Create(MonoObject* managedInstance, ScriptCamera* camera);
 		static void internal_Draw(ScriptSceneSelection* thisPtr);
-		static void internal_PickObject(ScriptSceneSelection* thisPtr, Vector2I* inputPos, bool additive);
+		static void internal_PickObject(ScriptSceneSelection* thisPtr, Vector2I* inputPos, bool additive, MonoArray* ignoreRenderables);
+		static void internal_PickObjects(ScriptSceneSelection* thisPtr, Vector2I* inputPos, Vector2I* area, bool additive, MonoArray* ignoreRenderables);
+		static MonoObject* internal_Snap(ScriptSceneSelection* thisPtr, Vector2I* inputPos, SnapData* data, MonoArray* ignoreRenderables);
 	};
 
 	/** @} */

+ 122 - 5
Source/SBansheeEditor/Source/BsScriptSceneSelection.cpp

@@ -3,8 +3,12 @@
 #include "BsScriptSceneSelection.h"
 #include "BsScriptCamera.h"
 #include "BsSelectionRenderer.h"
+#include "BsScriptSceneObject.h"
+#include "BsScriptGameObjectManager.h"
 #include "BsScenePicking.h"
 #include "BsSelection.h"
+#include "BsMonoPrerequisites.h"
+#include <BsMonoArray.h>
 
 namespace BansheeEngine
 {
@@ -24,6 +28,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_Create", &ScriptSceneSelection::internal_Create);
 		metaData.scriptClass->addInternalCall("Internal_Draw", &ScriptSceneSelection::internal_Draw);
 		metaData.scriptClass->addInternalCall("Internal_PickObject", &ScriptSceneSelection::internal_PickObject);
+		metaData.scriptClass->addInternalCall("Internal_PickObjects", &ScriptSceneSelection::internal_PickObjects);
+		metaData.scriptClass->addInternalCall("Internal_Snap", &ScriptSceneSelection::internal_Snap);
 	}
 
 	void ScriptSceneSelection::internal_Create(MonoObject* managedInstance, ScriptCamera* camera)
@@ -36,11 +42,29 @@ namespace BansheeEngine
 		thisPtr->mSelectionRenderer->update(thisPtr->mCamera);
 	}
 
-	void ScriptSceneSelection::internal_PickObject(ScriptSceneSelection* thisPtr, Vector2I* inputPos, bool additive)
+	void ScriptSceneSelection::internal_PickObject(ScriptSceneSelection* thisPtr, Vector2I* inputPos, bool additive, MonoArray* ignoreRenderables)
 	{
-		// TODO - Handle multi-selection (i.e. selection rectangle when dragging)
-		HSceneObject pickedObject = ScenePicking::instance().pickClosestObject(thisPtr->mCamera, *inputPos, Vector2I(1, 1));
+		Vector<HSceneObject> ignoredSceneObjects;
 
+		if (ignoreRenderables != nullptr)
+		{
+			ScriptArray scriptArray(ignoreRenderables);
+
+			UINT32 arrayLen = scriptArray.size();
+			for (UINT32 i = 0; i < arrayLen; i++)
+			{
+				MonoObject* monoSO = scriptArray.get<MonoObject*>(i);
+				ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(monoSO);
+
+				if (scriptSO == nullptr)
+					continue;
+
+				HSceneObject so = static_object_cast<SceneObject>(scriptSO->getNativeHandle());
+				ignoredSceneObjects.push_back(so);
+			}
+		}
+
+		HSceneObject pickedObject = ScenePicking::instance().pickClosestObject(thisPtr->mCamera, *inputPos, Vector2I(1, 1), ignoredSceneObjects);
 		if (pickedObject)
 		{
 			if (additive) // Append to existing selection
@@ -59,11 +83,104 @@ namespace BansheeEngine
 			else
 			{
 				Vector<HSceneObject> selectedSOs = { pickedObject };
+				Selection::instance().setSceneObjects(selectedSOs);
+			}
+		}
+		else if (!additive)
+		{
+			Selection::instance().clearSceneSelection();
+		}
+	}
+
+	void ScriptSceneSelection::internal_PickObjects(ScriptSceneSelection* thisPtr, Vector2I* inputPos, Vector2I* area, 
+		bool additive, MonoArray* ignoreRenderables)
+	{
+		Vector<HSceneObject> ignoredSceneObjects;
+
+		if (ignoreRenderables != nullptr)
+		{
+			ScriptArray scriptArray(ignoreRenderables);
+
+			UINT32 arrayLen = scriptArray.size();
+			for (UINT32 i = 0; i < arrayLen; i++)
+			{
+				MonoObject* monoSO = scriptArray.get<MonoObject*>(i);
+				ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(monoSO);
+
+				if (scriptSO == nullptr)
+					continue;
+
+				HSceneObject so = static_object_cast<SceneObject>(scriptSO->getNativeHandle());
+				ignoredSceneObjects.push_back(so);
+			}
+		}
+
+		Vector<HSceneObject> pickedObjects = ScenePicking::instance().pickObjects(thisPtr->mCamera, *inputPos, 
+			*area, ignoredSceneObjects);
+
+		if (pickedObjects.size() != 0)
+		{
+			if (additive) // Append to existing selection
+			{
+				Vector<HSceneObject> selectedSOs = Selection::instance().getSceneObjects();
+
+				for (int i = 0; i < pickedObjects.size(); i++) 
+				{
+					bool found = false;
+					for (int j = 0; j < selectedSOs.size(); j++)
+					{
+						if (selectedSOs[j] == pickedObjects[i])
+						{
+							found = true;
+							break;
+						}
+					}
+
+					if (!found)
+						selectedSOs.push_back(pickedObjects[i]);
+				}
 
 				Selection::instance().setSceneObjects(selectedSOs);
 			}
+			else
+				Selection::instance().setSceneObjects(pickedObjects);
 		}
-		else
+		else if (!additive)
+		{
 			Selection::instance().clearSceneSelection();
+		}
+	}
+
+	MonoObject* ScriptSceneSelection::internal_Snap(ScriptSceneSelection* thisPtr, Vector2I* inputPos, SnapData* data, 
+		MonoArray* ignoreRenderables)
+	{
+		Vector<HSceneObject> ignoredSceneObjects;
+
+		if (ignoreRenderables != nullptr)
+		{
+			ScriptArray scriptArray(ignoreRenderables);
+
+			UINT32 arrayLen = scriptArray.size();
+			for (UINT32 i = 0; i < arrayLen; i++)
+			{
+				MonoObject* monoSO = scriptArray.get<MonoObject*>(i);
+				ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(monoSO);
+
+				if (scriptSO == nullptr)
+					continue;
+
+				HSceneObject so = static_object_cast<SceneObject>(scriptSO->getNativeHandle());
+				ignoredSceneObjects.push_back(so);
+			}
+		}
+
+		HSceneObject instance = ScenePicking::instance().pickClosestObject(thisPtr->mCamera, *inputPos, Vector2I(1, 1), 
+			ignoredSceneObjects, data);
+
+		if (instance == nullptr)
+			return nullptr;
+
+		ScriptSceneObject* scriptSO = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(instance);
+		return scriptSO->getManagedInstance();
 	}
-}
+}