Przeglądaj źródła

Moving kinematic rigidbodies now works
Collider inspectors now work better so they don't refresh values currently being edited by the user
Added a way to retrieve pointer coordinates relative to the game window

BearishSun 9 lat temu
rodzic
commit
d35fec301d

+ 8 - 0
Source/BansheeCore/Source/BsCRigidbody.cpp

@@ -22,12 +22,20 @@ namespace BansheeEngine
 	{
 		if (mInternal != nullptr)
 			mInternal->move(position);
+
+		mNotifyFlags = (TransformChangedFlags)0;
+		SO()->setWorldPosition(position);
+		mNotifyFlags = (TransformChangedFlags)(TCF_Parent | TCF_Transform);
 	}
 
 	void CRigidbody::rotate(const Quaternion& rotation)
 	{
 		if (mInternal != nullptr)
 			mInternal->rotate(rotation);
+
+		mNotifyFlags = (TransformChangedFlags)0;
+		SO()->setWorldRotation(rotation);
+		mNotifyFlags = (TransformChangedFlags)(TCF_Parent | TCF_Transform);
 	}
 
 	void CRigidbody::setMass(float mass)

+ 1 - 1
Source/BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -140,7 +140,7 @@ namespace BansheeEngine
 		virtual bool acceptDragAndDrop() const override;
 
 		/** @copydoc GUITreeView::dragAndDropStart */	
-		virtual void dragAndDropStart() override;
+		virtual void dragAndDropStart(const Vector<TreeElement*>& elements) override;
 
 		/** @copydoc GUITreeView::dragAndDropEnded */	
 		virtual void dragAndDropEnded(TreeElement* overTreeElement) override;

+ 1 - 1
Source/BansheeEditor/Include/BsGUISceneTreeView.h

@@ -162,7 +162,7 @@ namespace BansheeEngine
 		virtual bool acceptDragAndDrop() const override;
 
 		/** @copydoc TreeView::dragAndDropStart */
-		virtual void dragAndDropStart() override;
+		virtual void dragAndDropStart(const Vector<TreeElement*>& elements) override;
 
 		/** @copydoc TreeView::dragAndDropEnded */
 		virtual void dragAndDropEnded(TreeElement* overTreeElement) override;

+ 1 - 1
Source/BansheeEditor/Include/BsGUITreeView.h

@@ -196,7 +196,7 @@ namespace BansheeEngine
 		virtual bool acceptDragAndDrop() const = 0;
 
 		/**	Triggered when the user drags a tree element and starts a drag and drop operation. */
-		virtual void dragAndDropStart() = 0;
+		virtual void dragAndDropStart(const Vector<TreeElement*>& elements) = 0;
 
 		/**
 		 * Triggered when the user ends a drag and drop operation over the tree view.

+ 524 - 524
Source/BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -1,525 +1,525 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsGUIResourceTreeView.h"
-#include "BsProjectLibrary.h"
-#include "BsDragAndDropManager.h"
-#include "BsFileSystem.h"
-#include "BsGUIWidget.h"
-#include "BsViewport.h"
-#include "BsRenderWindow.h"
-#include "BsPlatform.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	const MessageId GUIResourceTreeView::SELECTION_CHANGED_MSG = MessageId("ResourceTreeView_SelectionChanged");
-
-	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
-		:numObjects(numObjects)
-	{
-		resourcePaths = bs_newN<Path>(numObjects);
-	}
-
-	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
-	{
-		bs_deleteN(resourcePaths, numObjects);
-		resourcePaths = nullptr;
-	}
-
-	GUIResourceTreeView::GUIResourceTreeView(const String& backgroundStyle, const String& elementBtnStyle, const String& foldoutBtnStyle, 
-		const String& highlightBackgroundStyle, const String& selectionBackgroundStyle, const String& editBoxStyle,
-		const String& dragHighlightStyle, const String& dragSepHighlightStyle, const GUIDimensions& dimensions)
-		:GUITreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, highlightBackgroundStyle, 
-		selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, dimensions), 
-		mDraggedResources(nullptr), mCurrentWindow(nullptr), mDropTarget(nullptr), mDropTargetDragActive(false)
-	{
-		ResourceTreeViewLocator::_provide(this);
-
-		gProjectLibrary().onEntryAdded.connect(std::bind(&GUIResourceTreeView::entryAdded, this, _1));
-		gProjectLibrary().onEntryRemoved.connect(std::bind(&GUIResourceTreeView::entryRemoved, this, _1));
-
-		const ProjectLibrary::LibraryEntry* rootEntry = gProjectLibrary().getRootEntry();
-
-		mRootElement.mFullPath = rootEntry->path;
-		mRootElement.mElementName = mRootElement.mFullPath.getWTail();
-
-		expandElement(&mRootElement);
-
-		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
-	}
-
-	GUIResourceTreeView::~GUIResourceTreeView()
-	{
-		clearDropTarget();
-
-		ResourceTreeViewLocator::_provide(nullptr);
-	}
-
-	GUIResourceTreeView* GUIResourceTreeView::create(const String& backgroundStyle, const String& elementBtnStyle, 
-		const String& foldoutBtnStyle, const String& highlightBackgroundStyle, const String& selectionBackgroundStyle, 
-		const String& editBoxStyle, const String& dragHighlightStyle, const String& dragSepHighlightStyle)
-	{
-		return new (bs_alloc<GUIResourceTreeView>()) GUIResourceTreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, 
-			highlightBackgroundStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUIDimensions::create());
-	}
-
-	GUIResourceTreeView* GUIResourceTreeView::create(const GUIOptions& options, const String& backgroundStyle,
-		const String& elementBtnStyle, const String& foldoutBtnStyle, const String& highlightBackgroundStyle, 
-		const String& selectionBackgroundStyle, const String& editBoxStyle, const String& dragHighlightStyle,
-		const String& dragSepHighlightStyle)
-	{
-		return new (bs_alloc<GUIResourceTreeView>()) GUIResourceTreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, 
-			highlightBackgroundStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUIDimensions::create(options));
-	}
-
-	void GUIResourceTreeView::_updateLayoutInternal(const GUILayoutData& data)
-	{
-		GUITreeView::_updateLayoutInternal(data);
-
-		if(mDropTarget != nullptr)
-		{
-			mDropTarget->setArea(data.area.x, data.area.y, data.area.width, data.area.height);
-		}
-	}
-
-	void GUIResourceTreeView::updateTreeElementHierarchy()
-	{
-		// Do nothing, updates are handled via callbacks
-	}
-
-	void GUIResourceTreeView::renameTreeElement(GUITreeView::TreeElement* element, const WString& name)
-	{
-		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
-		
-		Path oldPath = resourceTreeElement->mFullPath;
-		Path newPath = oldPath.getParent();
-		newPath.append(name);
-
-		gProjectLibrary().moveEntry(oldPath, findUniquePath(newPath));
-	}
-
-	void GUIResourceTreeView::deleteTreeElement(TreeElement* element) 
-	{
-		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
-
-		gProjectLibrary().deleteEntry(resourceTreeElement->mFullPath);
-	}
-
-	void GUIResourceTreeView::updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry)
-	{
-		struct StackElem
-		{
-			StackElem(const ProjectLibrary::LibraryEntry* entry, ResourceTreeElement* treeElem)
-				:entry(entry), treeElem(treeElem)
-			{ }
-
-			const ProjectLibrary::LibraryEntry* entry;
-			ResourceTreeElement* treeElem;
-		};
-
-		if(libraryEntry->type == ProjectLibrary::LibraryEntryType::Directory)
-		{
-			Stack<StackElem> todo;
-			todo.push(StackElem(libraryEntry, treeElement));
-
-			while(!todo.empty())
-			{
-				StackElem curElem = todo.top();
-				todo.pop();
-
-				const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
-
-				for(auto& child : dirEntry->mChildren)
-				{
-					ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, child->path);
-
-					if(child->type == ProjectLibrary::LibraryEntryType::Directory)
-						todo.push(StackElem(child, newChild));
-				}
-
-				sortTreeElement(curElem.treeElem);
-			}
-		}
-	}
-
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const Path& fullPath)
-	{
-		ResourceTreeElement* newChild = bs_new<ResourceTreeElement>();
-		newChild->mParent = parent;
-		newChild->mName = fullPath.getTail();
-		newChild->mFullPath = fullPath;
-		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
-		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
-		newChild->mElementName = fullPath.getWTail();
-
-		parent->mChildren.push_back(newChild);
-
-		updateElementGUI(parent);
-		updateElementGUI(newChild);
-
-		return newChild;
-	}
-
-	void GUIResourceTreeView::deleteTreeElement(ResourceTreeElement* element)
-	{
-		closeTemporarilyExpandedElements(); // In case this element is one of them
-
-		if (element->mIsHighlighted)
-			clearPing();
-
-		if(element->mIsSelected)
-			unselectElement(element);
-
-		if(element->mParent != nullptr)
-		{
-			auto iterFind = std::find(element->mParent->mChildren.begin(), element->mParent->mChildren.end(), element);
-			if(iterFind != element->mParent->mChildren.end())
-				element->mParent->mChildren.erase(iterFind);
-
-			sortTreeElement(static_cast<ResourceTreeElement*>(element->mParent));
-			updateElementGUI(element->mParent);
-		}
-
-		if(&mRootElement != element)
-			bs_delete(element);
-	}
-
-	void GUIResourceTreeView::sortTreeElement(ResourceTreeElement* element)
-	{
-		auto cmp = [&] (const TreeElement* a, const TreeElement* b)
-		{
-			return a->mName.compare(b->mName) < 0;
-		};
-
-		std::sort(element->mChildren.begin(), element->mChildren.end(), cmp);
-
-		UINT32 idx = 0;
-		for(auto& child : element->mChildren)
-		{
-			child->mSortedIdx = idx;
-			idx++;
-		}
-	}
-
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const Path& fullPath)
-	{
-		if (!mRootElement.mFullPath.includes(fullPath))
-			return nullptr;
-
-		Path relPath = fullPath.getRelative(mRootElement.mFullPath);
-		UINT32 numElems = relPath.getNumDirectories() + (relPath.isFile() ? 1 : 0);
-		UINT32 idx = 0;
-
-		ResourceTreeElement* current = &mRootElement;
-		while (current != nullptr)
-		{
-			if (idx == numElems)
-				return current;
-
-			WString curElem;
-			if (relPath.isFile() && idx == (numElems - 1))
-				curElem = relPath.getWFilename();
-			else
-				curElem = relPath[idx];
-
-			bool foundChild = false;
-			for (auto& child : current->mChildren)
-			{
-				ResourceTreeElement* resourceChild = static_cast<ResourceTreeElement*>(child);
-				if (Path::comparePathElem(curElem, resourceChild->mElementName))
-				{
-					idx++;
-					current = resourceChild;
-					foundChild = true;
-					break;
-				}
-			}
-
-			if (!foundChild)
-				current = nullptr;
-		}
-
-		return nullptr;
-	}
-
-	void GUIResourceTreeView::entryAdded(const Path& path)
-	{
-		Path parentPath = path.getParent();
-
-		ResourceTreeElement* parentElement = findTreeElement(parentPath);
-		assert(parentElement != nullptr);
-
-		ResourceTreeElement* newElement = addTreeElement(parentElement, path);
-		sortTreeElement(parentElement);
-
-		ProjectLibrary::LibraryEntry* libEntry = gProjectLibrary().findEntry(path);
-		
-		assert(libEntry != nullptr);
-		updateFromProjectLibraryEntry(newElement, libEntry);
-
-		_markLayoutAsDirty();
-	}
-
-	void GUIResourceTreeView::entryRemoved(const Path& path)
-	{
-		ResourceTreeElement* treeElement = findTreeElement(path);
-		
-		if(treeElement != nullptr)
-			deleteTreeElement(treeElement);
-	}
-
-	void GUIResourceTreeView::setDropTarget(RenderWindow* parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height)
-	{
-		if(mDropTarget != nullptr)
-		{
-			Platform::destroyDropTarget(*mDropTarget);
-
-			mDropTargetEnterConn.disconnect();
-			mDropTargetLeaveConn.disconnect();
-			mDropTargetMoveConn.disconnect();
-			mDropTargetDroppedConn.disconnect();
-		}
-
-		if(parentWindow != nullptr)
-		{
-			mCurrentWindow = parentWindow;
-			mDropTarget = &Platform::createDropTarget(mCurrentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
-
-			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
-			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
-			mDropTargetLeaveConn = mDropTarget->onLeave.connect(std::bind(&GUIResourceTreeView::dropTargetDragLeave, this));
-			mDropTargetDroppedConn = mDropTarget->onDrop.connect(std::bind(&GUIResourceTreeView::dropTargetDragDropped, this, _1, _2));
-		}
-		else
-			mDropTarget = nullptr;
-	}
-
-	void GUIResourceTreeView::clearDropTarget()
-	{
-		setDropTarget(nullptr, 0, 0, 0, 0);
-	}
-
-	void GUIResourceTreeView::dropTargetDragMove(INT32 x, INT32 y)
-	{
-		mDragPosition = Vector2I(x, y);
-		mDragInProgress = true;
-		mDropTargetDragActive = true;
-		_markLayoutAsDirty();
-
-		if(mBottomScrollBounds.contains(mDragPosition))
-		{
-			if(mScrollState != ScrollState::Down)
-				mScrollState = ScrollState::TransitioningDown;
-		}
-		else if(mTopScrollBounds.contains(mDragPosition))
-		{
-			if(mScrollState != ScrollState::Up)
-				mScrollState = ScrollState::TransitioningUp;
-		}
-		else
-			mScrollState = ScrollState::None;
-	}
-
-	void GUIResourceTreeView::dropTargetDragLeave()
-	{
-		mDragInProgress = false;
-		mDropTargetDragActive = false;
-		_markLayoutAsDirty();
-	}
-
-	void GUIResourceTreeView::dropTargetDragDropped(INT32 x, INT32 y)
-	{
-		const GUITreeView::InteractableElement* element = findElementUnderCoord(Vector2I(x, y));
-
-		TreeElement* treeElement = nullptr;
-		if(element != nullptr)
-		{
-			if(element->isTreeElement())
-				treeElement = element->getTreeElement();
-			else
-				treeElement = element->parent;
-		}
-
-		if(mDropTarget->getDropType() == OSDropType::FileList)
-		{
-			Vector<WString> fileList = mDropTarget->getFileList();
-
-			mDraggedResources = bs_new<InternalDraggedResources>((UINT32)fileList.size());
-			for(UINT32 i = 0; i < (UINT32)fileList.size(); i++)
-				mDraggedResources->resourcePaths[i] = fileList[i];
-
-			dragAndDropEnded(treeElement);
-
-			bs_delete(mDraggedResources);
-			mDraggedResources = nullptr;
-
-			unselectAll();
-		}
-
-		mDragInProgress = false;
-		mDropTargetDragActive = false;
-		_markLayoutAsDirty();
-	}
-
-	Path GUIResourceTreeView::findUniquePath(const Path& path)
-	{
-		if(FileSystem::exists(path))
-		{
-			Path newPath = path;
-			WString filename = path.getWFilename(false);
-			UINT32 cnt = 1;
-			do 
-			{
-				newPath.setBasename(filename + toWString(cnt));
-				cnt++;
-			} while (FileSystem::exists(newPath));
-
-			return newPath;
-		}
-		else
-			return path;
-	}
-
-	bool GUIResourceTreeView::acceptDragAndDrop() const
-	{
-		return mDropTargetDragActive || DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::Resources;
-	}
-
-	void GUIResourceTreeView::dragAndDropStart()
-	{
-		assert(mDraggedResources == nullptr);
-
-		DraggedResources* draggedResources = bs_new<DraggedResources>();
-		InternalDraggedResources* internalDraggedResources = bs_new<InternalDraggedResources>((UINT32)mSelectedElements.size());
-
-		UINT32 cnt = 0;
-		for(auto& selectedElement : mSelectedElements)
-		{
-			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(selectedElement.element);
-			internalDraggedResources->resourcePaths[cnt] = resourceTreeElement->mFullPath; 
-			draggedResources->resourcePaths.push_back(internalDraggedResources->resourcePaths[cnt]);
-
-			cnt++;
-		}
-
-		mDraggedResources = internalDraggedResources;
-
-		DragAndDropManager::instance().startDrag((UINT32)DragAndDropType::Resources, (void*)draggedResources, 
-			std::bind(&GUIResourceTreeView::dragAndDropFinalize, this), true);
-	}
-
-	void GUIResourceTreeView::dragAndDropEnded(TreeElement* overTreeElement)
-	{
-		if(overTreeElement != nullptr && mDraggedResources != nullptr)
-		{
-			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
-
-			Path destDir = resourceTreeElement->mFullPath;
-			if(FileSystem::isFile(destDir))
-				destDir = destDir.getParent();
-
-			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
-			{
-				WString filename = mDraggedResources->resourcePaths[i].getWFilename();
-				Path currentParent = mDraggedResources->resourcePaths[i].getParent();
-
-				if(currentParent != destDir)
-				{
-					Path newPath = destDir;
-					newPath.append(filename);
-
-					gProjectLibrary().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
-				}
-			}
-		}
-	}
-
-	void GUIResourceTreeView::dragAndDropFinalize()
-	{
-		mDragInProgress = false;
-		_markLayoutAsDirty();
-
-		DraggedResources* draggedResources = reinterpret_cast<DraggedResources*>(DragAndDropManager::instance().getDragData());
-		bs_delete(draggedResources);
-
-		if(mDraggedResources != nullptr)
-		{
-			bs_delete(mDraggedResources);
-			mDraggedResources = nullptr;
-		}
-	}
-
-	void GUIResourceTreeView::_changeParentWidget(GUIWidget* widget)
-	{
-		GUITreeView::_changeParentWidget(widget);
-
-		if (widget != nullptr && widget->getTarget()->getTarget()->getProperties().isWindow())
-		{
-			RenderWindow* parentWindow = static_cast<RenderWindow*>(widget->getTarget()->getTarget().get());
-			setDropTarget(parentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
-		}
-		else
-			clearDropTarget();
-	}
-
-	bool GUIResourceTreeView::_acceptDragAndDrop(const Vector2I position, UINT32 typeId) const
-	{
-		return typeId == (UINT32)DragAndDropType::Resources && !_isDisabled();
-	}
-
-	void GUIResourceTreeView::selectionChanged()
-	{
-		onSelectionChanged();
-
-		sendMessage(SELECTION_CHANGED_MSG);
-	}
-
-	Vector<Path> GUIResourceTreeView::getSelection() const
-	{
-		Vector<Path> selectedPaths;
-		for (auto& selectedElem : mSelectedElements)
-		{
-			ResourceTreeElement* resTreeElement = static_cast<ResourceTreeElement*>(selectedElem.element);
-
-			selectedPaths.push_back(resTreeElement->mFullPath);
-		}
-
-		return selectedPaths;
-	}
-
-	void GUIResourceTreeView::setSelection(const Vector<Path>& paths)
-	{
-		unselectAll();
-
-		ResourceTreeElement& root = mRootElement;
-
-		Stack<ResourceTreeElement*> todo;
-		todo.push(&mRootElement);
-
-		while (!todo.empty())
-		{
-			ResourceTreeElement* currentElem = todo.top();
-			todo.pop();
-
-			auto iterFind = std::find(paths.begin(), paths.end(), currentElem->mFullPath);
-			if (iterFind != paths.end())
-			{
-				expandToElement(currentElem);
-				selectElement(currentElem);
-			}
-
-			for (auto& child : currentElem->mChildren)
-			{
-				ResourceTreeElement* sceneChild = static_cast<ResourceTreeElement*>(child);
-				todo.push(sceneChild);
-			}
-		}
-	}
-
-	const String& GUIResourceTreeView::getGUITypeName()
-	{
-		static String typeName = "ResourceTreeView";
-		return typeName;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsGUIResourceTreeView.h"
+#include "BsProjectLibrary.h"
+#include "BsDragAndDropManager.h"
+#include "BsFileSystem.h"
+#include "BsGUIWidget.h"
+#include "BsViewport.h"
+#include "BsRenderWindow.h"
+#include "BsPlatform.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	const MessageId GUIResourceTreeView::SELECTION_CHANGED_MSG = MessageId("ResourceTreeView_SelectionChanged");
+
+	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
+		:numObjects(numObjects)
+	{
+		resourcePaths = bs_newN<Path>(numObjects);
+	}
+
+	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
+	{
+		bs_deleteN(resourcePaths, numObjects);
+		resourcePaths = nullptr;
+	}
+
+	GUIResourceTreeView::GUIResourceTreeView(const String& backgroundStyle, const String& elementBtnStyle, const String& foldoutBtnStyle, 
+		const String& highlightBackgroundStyle, const String& selectionBackgroundStyle, const String& editBoxStyle,
+		const String& dragHighlightStyle, const String& dragSepHighlightStyle, const GUIDimensions& dimensions)
+		:GUITreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, highlightBackgroundStyle, 
+		selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, dimensions), 
+		mDraggedResources(nullptr), mCurrentWindow(nullptr), mDropTarget(nullptr), mDropTargetDragActive(false)
+	{
+		ResourceTreeViewLocator::_provide(this);
+
+		gProjectLibrary().onEntryAdded.connect(std::bind(&GUIResourceTreeView::entryAdded, this, _1));
+		gProjectLibrary().onEntryRemoved.connect(std::bind(&GUIResourceTreeView::entryRemoved, this, _1));
+
+		const ProjectLibrary::LibraryEntry* rootEntry = gProjectLibrary().getRootEntry();
+
+		mRootElement.mFullPath = rootEntry->path;
+		mRootElement.mElementName = mRootElement.mFullPath.getWTail();
+
+		expandElement(&mRootElement);
+
+		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
+	}
+
+	GUIResourceTreeView::~GUIResourceTreeView()
+	{
+		clearDropTarget();
+
+		ResourceTreeViewLocator::_provide(nullptr);
+	}
+
+	GUIResourceTreeView* GUIResourceTreeView::create(const String& backgroundStyle, const String& elementBtnStyle, 
+		const String& foldoutBtnStyle, const String& highlightBackgroundStyle, const String& selectionBackgroundStyle, 
+		const String& editBoxStyle, const String& dragHighlightStyle, const String& dragSepHighlightStyle)
+	{
+		return new (bs_alloc<GUIResourceTreeView>()) GUIResourceTreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, 
+			highlightBackgroundStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUIDimensions::create());
+	}
+
+	GUIResourceTreeView* GUIResourceTreeView::create(const GUIOptions& options, const String& backgroundStyle,
+		const String& elementBtnStyle, const String& foldoutBtnStyle, const String& highlightBackgroundStyle, 
+		const String& selectionBackgroundStyle, const String& editBoxStyle, const String& dragHighlightStyle,
+		const String& dragSepHighlightStyle)
+	{
+		return new (bs_alloc<GUIResourceTreeView>()) GUIResourceTreeView(backgroundStyle, elementBtnStyle, foldoutBtnStyle, 
+			highlightBackgroundStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUIDimensions::create(options));
+	}
+
+	void GUIResourceTreeView::_updateLayoutInternal(const GUILayoutData& data)
+	{
+		GUITreeView::_updateLayoutInternal(data);
+
+		if(mDropTarget != nullptr)
+		{
+			mDropTarget->setArea(data.area.x, data.area.y, data.area.width, data.area.height);
+		}
+	}
+
+	void GUIResourceTreeView::updateTreeElementHierarchy()
+	{
+		// Do nothing, updates are handled via callbacks
+	}
+
+	void GUIResourceTreeView::renameTreeElement(GUITreeView::TreeElement* element, const WString& name)
+	{
+		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
+		
+		Path oldPath = resourceTreeElement->mFullPath;
+		Path newPath = oldPath.getParent();
+		newPath.append(name);
+
+		gProjectLibrary().moveEntry(oldPath, findUniquePath(newPath));
+	}
+
+	void GUIResourceTreeView::deleteTreeElement(TreeElement* element) 
+	{
+		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
+
+		gProjectLibrary().deleteEntry(resourceTreeElement->mFullPath);
+	}
+
+	void GUIResourceTreeView::updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry)
+	{
+		struct StackElem
+		{
+			StackElem(const ProjectLibrary::LibraryEntry* entry, ResourceTreeElement* treeElem)
+				:entry(entry), treeElem(treeElem)
+			{ }
+
+			const ProjectLibrary::LibraryEntry* entry;
+			ResourceTreeElement* treeElem;
+		};
+
+		if(libraryEntry->type == ProjectLibrary::LibraryEntryType::Directory)
+		{
+			Stack<StackElem> todo;
+			todo.push(StackElem(libraryEntry, treeElement));
+
+			while(!todo.empty())
+			{
+				StackElem curElem = todo.top();
+				todo.pop();
+
+				const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
+
+				for(auto& child : dirEntry->mChildren)
+				{
+					ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, child->path);
+
+					if(child->type == ProjectLibrary::LibraryEntryType::Directory)
+						todo.push(StackElem(child, newChild));
+				}
+
+				sortTreeElement(curElem.treeElem);
+			}
+		}
+	}
+
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const Path& fullPath)
+	{
+		ResourceTreeElement* newChild = bs_new<ResourceTreeElement>();
+		newChild->mParent = parent;
+		newChild->mName = fullPath.getTail();
+		newChild->mFullPath = fullPath;
+		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
+		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
+		newChild->mElementName = fullPath.getWTail();
+
+		parent->mChildren.push_back(newChild);
+
+		updateElementGUI(parent);
+		updateElementGUI(newChild);
+
+		return newChild;
+	}
+
+	void GUIResourceTreeView::deleteTreeElement(ResourceTreeElement* element)
+	{
+		closeTemporarilyExpandedElements(); // In case this element is one of them
+
+		if (element->mIsHighlighted)
+			clearPing();
+
+		if(element->mIsSelected)
+			unselectElement(element);
+
+		if(element->mParent != nullptr)
+		{
+			auto iterFind = std::find(element->mParent->mChildren.begin(), element->mParent->mChildren.end(), element);
+			if(iterFind != element->mParent->mChildren.end())
+				element->mParent->mChildren.erase(iterFind);
+
+			sortTreeElement(static_cast<ResourceTreeElement*>(element->mParent));
+			updateElementGUI(element->mParent);
+		}
+
+		if(&mRootElement != element)
+			bs_delete(element);
+	}
+
+	void GUIResourceTreeView::sortTreeElement(ResourceTreeElement* element)
+	{
+		auto cmp = [&] (const TreeElement* a, const TreeElement* b)
+		{
+			return a->mName.compare(b->mName) < 0;
+		};
+
+		std::sort(element->mChildren.begin(), element->mChildren.end(), cmp);
+
+		UINT32 idx = 0;
+		for(auto& child : element->mChildren)
+		{
+			child->mSortedIdx = idx;
+			idx++;
+		}
+	}
+
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const Path& fullPath)
+	{
+		if (!mRootElement.mFullPath.includes(fullPath))
+			return nullptr;
+
+		Path relPath = fullPath.getRelative(mRootElement.mFullPath);
+		UINT32 numElems = relPath.getNumDirectories() + (relPath.isFile() ? 1 : 0);
+		UINT32 idx = 0;
+
+		ResourceTreeElement* current = &mRootElement;
+		while (current != nullptr)
+		{
+			if (idx == numElems)
+				return current;
+
+			WString curElem;
+			if (relPath.isFile() && idx == (numElems - 1))
+				curElem = relPath.getWFilename();
+			else
+				curElem = relPath[idx];
+
+			bool foundChild = false;
+			for (auto& child : current->mChildren)
+			{
+				ResourceTreeElement* resourceChild = static_cast<ResourceTreeElement*>(child);
+				if (Path::comparePathElem(curElem, resourceChild->mElementName))
+				{
+					idx++;
+					current = resourceChild;
+					foundChild = true;
+					break;
+				}
+			}
+
+			if (!foundChild)
+				current = nullptr;
+		}
+
+		return nullptr;
+	}
+
+	void GUIResourceTreeView::entryAdded(const Path& path)
+	{
+		Path parentPath = path.getParent();
+
+		ResourceTreeElement* parentElement = findTreeElement(parentPath);
+		assert(parentElement != nullptr);
+
+		ResourceTreeElement* newElement = addTreeElement(parentElement, path);
+		sortTreeElement(parentElement);
+
+		ProjectLibrary::LibraryEntry* libEntry = gProjectLibrary().findEntry(path);
+		
+		assert(libEntry != nullptr);
+		updateFromProjectLibraryEntry(newElement, libEntry);
+
+		_markLayoutAsDirty();
+	}
+
+	void GUIResourceTreeView::entryRemoved(const Path& path)
+	{
+		ResourceTreeElement* treeElement = findTreeElement(path);
+		
+		if(treeElement != nullptr)
+			deleteTreeElement(treeElement);
+	}
+
+	void GUIResourceTreeView::setDropTarget(RenderWindow* parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height)
+	{
+		if(mDropTarget != nullptr)
+		{
+			Platform::destroyDropTarget(*mDropTarget);
+
+			mDropTargetEnterConn.disconnect();
+			mDropTargetLeaveConn.disconnect();
+			mDropTargetMoveConn.disconnect();
+			mDropTargetDroppedConn.disconnect();
+		}
+
+		if(parentWindow != nullptr)
+		{
+			mCurrentWindow = parentWindow;
+			mDropTarget = &Platform::createDropTarget(mCurrentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
+
+			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
+			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
+			mDropTargetLeaveConn = mDropTarget->onLeave.connect(std::bind(&GUIResourceTreeView::dropTargetDragLeave, this));
+			mDropTargetDroppedConn = mDropTarget->onDrop.connect(std::bind(&GUIResourceTreeView::dropTargetDragDropped, this, _1, _2));
+		}
+		else
+			mDropTarget = nullptr;
+	}
+
+	void GUIResourceTreeView::clearDropTarget()
+	{
+		setDropTarget(nullptr, 0, 0, 0, 0);
+	}
+
+	void GUIResourceTreeView::dropTargetDragMove(INT32 x, INT32 y)
+	{
+		mDragPosition = Vector2I(x, y);
+		mDragInProgress = true;
+		mDropTargetDragActive = true;
+		_markLayoutAsDirty();
+
+		if(mBottomScrollBounds.contains(mDragPosition))
+		{
+			if(mScrollState != ScrollState::Down)
+				mScrollState = ScrollState::TransitioningDown;
+		}
+		else if(mTopScrollBounds.contains(mDragPosition))
+		{
+			if(mScrollState != ScrollState::Up)
+				mScrollState = ScrollState::TransitioningUp;
+		}
+		else
+			mScrollState = ScrollState::None;
+	}
+
+	void GUIResourceTreeView::dropTargetDragLeave()
+	{
+		mDragInProgress = false;
+		mDropTargetDragActive = false;
+		_markLayoutAsDirty();
+	}
+
+	void GUIResourceTreeView::dropTargetDragDropped(INT32 x, INT32 y)
+	{
+		const GUITreeView::InteractableElement* element = findElementUnderCoord(Vector2I(x, y));
+
+		TreeElement* treeElement = nullptr;
+		if(element != nullptr)
+		{
+			if(element->isTreeElement())
+				treeElement = element->getTreeElement();
+			else
+				treeElement = element->parent;
+		}
+
+		if(mDropTarget->getDropType() == OSDropType::FileList)
+		{
+			Vector<WString> fileList = mDropTarget->getFileList();
+
+			mDraggedResources = bs_new<InternalDraggedResources>((UINT32)fileList.size());
+			for(UINT32 i = 0; i < (UINT32)fileList.size(); i++)
+				mDraggedResources->resourcePaths[i] = fileList[i];
+
+			dragAndDropEnded(treeElement);
+
+			bs_delete(mDraggedResources);
+			mDraggedResources = nullptr;
+
+			unselectAll();
+		}
+
+		mDragInProgress = false;
+		mDropTargetDragActive = false;
+		_markLayoutAsDirty();
+	}
+
+	Path GUIResourceTreeView::findUniquePath(const Path& path)
+	{
+		if(FileSystem::exists(path))
+		{
+			Path newPath = path;
+			WString filename = path.getWFilename(false);
+			UINT32 cnt = 1;
+			do 
+			{
+				newPath.setBasename(filename + toWString(cnt));
+				cnt++;
+			} while (FileSystem::exists(newPath));
+
+			return newPath;
+		}
+		else
+			return path;
+	}
+
+	bool GUIResourceTreeView::acceptDragAndDrop() const
+	{
+		return mDropTargetDragActive || DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::Resources;
+	}
+
+	void GUIResourceTreeView::dragAndDropStart(const Vector<TreeElement*>& elements)
+	{
+		assert(mDraggedResources == nullptr);
+
+		DraggedResources* draggedResources = bs_new<DraggedResources>();
+		InternalDraggedResources* internalDraggedResources = bs_new<InternalDraggedResources>((UINT32)mSelectedElements.size());
+
+		UINT32 cnt = 0;
+		for(auto& entry : elements)
+		{
+			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(entry);
+			internalDraggedResources->resourcePaths[cnt] = resourceTreeElement->mFullPath; 
+			draggedResources->resourcePaths.push_back(internalDraggedResources->resourcePaths[cnt]);
+
+			cnt++;
+		}
+
+		mDraggedResources = internalDraggedResources;
+
+		DragAndDropManager::instance().startDrag((UINT32)DragAndDropType::Resources, (void*)draggedResources, 
+			std::bind(&GUIResourceTreeView::dragAndDropFinalize, this), true);
+	}
+
+	void GUIResourceTreeView::dragAndDropEnded(TreeElement* overTreeElement)
+	{
+		if(overTreeElement != nullptr && mDraggedResources != nullptr)
+		{
+			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
+
+			Path destDir = resourceTreeElement->mFullPath;
+			if(FileSystem::isFile(destDir))
+				destDir = destDir.getParent();
+
+			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
+			{
+				WString filename = mDraggedResources->resourcePaths[i].getWFilename();
+				Path currentParent = mDraggedResources->resourcePaths[i].getParent();
+
+				if(currentParent != destDir)
+				{
+					Path newPath = destDir;
+					newPath.append(filename);
+
+					gProjectLibrary().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
+				}
+			}
+		}
+	}
+
+	void GUIResourceTreeView::dragAndDropFinalize()
+	{
+		mDragInProgress = false;
+		_markLayoutAsDirty();
+
+		DraggedResources* draggedResources = reinterpret_cast<DraggedResources*>(DragAndDropManager::instance().getDragData());
+		bs_delete(draggedResources);
+
+		if(mDraggedResources != nullptr)
+		{
+			bs_delete(mDraggedResources);
+			mDraggedResources = nullptr;
+		}
+	}
+
+	void GUIResourceTreeView::_changeParentWidget(GUIWidget* widget)
+	{
+		GUITreeView::_changeParentWidget(widget);
+
+		if (widget != nullptr && widget->getTarget()->getTarget()->getProperties().isWindow())
+		{
+			RenderWindow* parentWindow = static_cast<RenderWindow*>(widget->getTarget()->getTarget().get());
+			setDropTarget(parentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
+		}
+		else
+			clearDropTarget();
+	}
+
+	bool GUIResourceTreeView::_acceptDragAndDrop(const Vector2I position, UINT32 typeId) const
+	{
+		return typeId == (UINT32)DragAndDropType::Resources && !_isDisabled();
+	}
+
+	void GUIResourceTreeView::selectionChanged()
+	{
+		onSelectionChanged();
+
+		sendMessage(SELECTION_CHANGED_MSG);
+	}
+
+	Vector<Path> GUIResourceTreeView::getSelection() const
+	{
+		Vector<Path> selectedPaths;
+		for (auto& selectedElem : mSelectedElements)
+		{
+			ResourceTreeElement* resTreeElement = static_cast<ResourceTreeElement*>(selectedElem.element);
+
+			selectedPaths.push_back(resTreeElement->mFullPath);
+		}
+
+		return selectedPaths;
+	}
+
+	void GUIResourceTreeView::setSelection(const Vector<Path>& paths)
+	{
+		unselectAll();
+
+		ResourceTreeElement& root = mRootElement;
+
+		Stack<ResourceTreeElement*> todo;
+		todo.push(&mRootElement);
+
+		while (!todo.empty())
+		{
+			ResourceTreeElement* currentElem = todo.top();
+			todo.pop();
+
+			auto iterFind = std::find(paths.begin(), paths.end(), currentElem->mFullPath);
+			if (iterFind != paths.end())
+			{
+				expandToElement(currentElem);
+				selectElement(currentElem);
+			}
+
+			for (auto& child : currentElem->mChildren)
+			{
+				ResourceTreeElement* sceneChild = static_cast<ResourceTreeElement*>(child);
+				todo.push(sceneChild);
+			}
+		}
+	}
+
+	const String& GUIResourceTreeView::getGUITypeName()
+	{
+		static String typeName = "ResourceTreeView";
+		return typeName;
+	}
 }

+ 4 - 4
Source/BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -302,14 +302,14 @@ namespace BansheeEngine
 			DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::Resources);
 	}
 
-	void GUISceneTreeView::dragAndDropStart()
+	void GUISceneTreeView::dragAndDropStart(const Vector<TreeElement*>& elements)
 	{
-		DraggedSceneObjects* draggedSceneObjects = bs_new<DraggedSceneObjects>((UINT32)mSelectedElements.size());
+		DraggedSceneObjects* draggedSceneObjects = bs_new<DraggedSceneObjects>((UINT32)elements.size());
 
 		UINT32 cnt = 0;
-		for(auto& selectedElement : mSelectedElements)
+		for(auto& entry : elements)
 		{
-			SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(selectedElement.element);
+			SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(entry);
 			draggedSceneObjects->objects[cnt] = sceneTreeElement->mSceneObject;
 			cnt++;
 		}

+ 11 - 7
Source/BansheeEditor/Source/BsGUITreeView.cpp

@@ -85,7 +85,7 @@ namespace BansheeEngine
 		const String& editBoxStyle, const String& dragHighlightStyle, const String& dragSepHighlightStyle, const GUIDimensions& dimensions)
 		:GUIElementContainer(dimensions), mBackgroundStyle(backgroundStyle),
 		mElementBtnStyle(elementBtnStyle), mFoldoutBtnStyle(foldoutBtnStyle), mEditBoxStyle(editBoxStyle), mEditElement(nullptr), mIsElementSelected(false),
-		mNameEditBox(nullptr), mHighlightBackgroundStyle(highlightBackgroundStyle), mSelectionBackgroundStyle(selectionBackgroundStyle), mDragInProgress(nullptr), 
+		mNameEditBox(nullptr), mHighlightBackgroundStyle(highlightBackgroundStyle), mSelectionBackgroundStyle(selectionBackgroundStyle), mDragInProgress(false), 
 		mDragHighlightStyle(dragHighlightStyle), mDragSepHighlightStyle(dragSepHighlightStyle), mDragHighlight(nullptr), mDragSepHighlight(nullptr), mMouseOverDragElement(nullptr), 
 		mMouseOverDragElementTime(0.0f), mScrollState(ScrollState::None), mLastScrollTime(0.0f), mIsElementHighlighted(false)
 	{
@@ -351,21 +351,25 @@ namespace BansheeEngine
 					const GUITreeView::InteractableElement* element = findElementUnderCoord(mDragStartPosition);
 					TreeElement* treeElement = nullptr;
 
+					Vector<TreeElement*> draggedElements;
+
 					if(element != nullptr && element->isTreeElement())
 					{
-						// If element we are trying to drag isn't selected, select it
+						// If multiple elements are selected, drag all of them
 						TreeElement* treeElement = element->getTreeElement();
 						auto iterFind = std::find_if(mSelectedElements.begin(), mSelectedElements.end(), 
 							[&] (const SelectedElement& x) { return x.element == treeElement; });
 
-						if(iterFind == mSelectedElements.end())
+						if (iterFind != mSelectedElements.end())
 						{
-							unselectAll();
-							selectElement(element->getTreeElement());
-						}						
+							for (auto& entry : mSelectedElements)
+								draggedElements.push_back(entry.element);
+						}
+						else
+							draggedElements.push_back(treeElement);
 					}
 
-					dragAndDropStart();
+					dragAndDropStart(draggedElements);
 
 					mDragPosition = event.getPosition();
 					mDragInProgress = true;

+ 17 - 8
Source/BansheeEngine/Include/BsGUIManager.h

@@ -195,6 +195,23 @@ namespace BansheeEngine
 		 */
 		void setInputBridge(const RenderTexture* renderTex, const GUIElement* element);
 
+		/**
+		 * Converts window coordinates to coordinates relative to the specified bridged render target (target displayed 
+		 * with a GUI element). Returned coordinates will be relative to the bridge element.
+		 *
+		 * @return	If provided widget has no bridge, coordinates are returned as is.
+		 */
+		Vector2I windowToBridgedCoords(const RenderTargetPtr& target, const Vector2I& windowPos) const;
+
+		/** 
+		 * Returns the render window that holds the GUI element that displays the provided render texture. 
+		 *
+		 * @param[in]	target	Render texture to find the bridged window for.
+		 * @return				Window that displays the GUI element with the render texture, or null if the render texture
+		 *						is not bridged.
+		 */
+		RenderWindowPtr getBridgeWindow(const RenderTexturePtr& target) const;
+
 		/** Gets the core thread portion of the GUI manager, responsible for rendering of GUI elements. */
 		GUIManagerCore* getCore() const { return mCore.load(std::memory_order_relaxed); }
 
@@ -277,14 +294,6 @@ namespace BansheeEngine
 		/**	Converts screen coordinates to coordinates relative to the specified widget. */
 		Vector2I getWidgetRelativePos(const GUIWidget* widget, const Vector2I& screenPos) const;
 
-		/**
-		 * Converts window coordinates to coordinates relative to the specified bridged widget. Returned coordinates will
-		 * be relative to the bridge element.
-		 *
-		 * @param[in]	If provided widget has no bridge, coordinates are returned as is.
-		 */
-		Vector2I windowToBridgedCoords(const GUIWidget& widget, const Vector2I& windowPos) const;
-
 		/**	Returns the parent render window of the specified widget. */
 		const RenderWindow* getWidgetWindow(const GUIWidget& widget) const;
 

+ 34 - 4
Source/BansheeEngine/Source/BsGUIManager.cpp

@@ -1257,7 +1257,8 @@ namespace BansheeEngine
 				}
 
 				GUIWidget* widget = widgetInfo.widget;
-				if(widgetWindows[widgetIdx] == windowUnderPointer && widget->inBounds(windowToBridgedCoords(*widget, windowPos)))
+				if(widgetWindows[widgetIdx] == windowUnderPointer 
+					&& widget->inBounds(windowToBridgedCoords(widget->getTarget()->getTarget(), windowPos)))
 				{
 					const Vector<GUIElement*>& elements = widget->getElements();
 					Vector2I localPos = getWidgetRelativePos(widget, pointerScreenPos);
@@ -1564,7 +1565,7 @@ namespace BansheeEngine
 			return Vector2I();
 
 		Vector2I windowPos = window->screenToWindowPos(screenPos);
-		windowPos = windowToBridgedCoords(*widget, windowPos);
+		windowPos = windowToBridgedCoords(widget->getTarget()->getTarget(), windowPos);
 
 		const Matrix4& worldTfrm = widget->getWorldTfrm();
 
@@ -1574,12 +1575,12 @@ namespace BansheeEngine
 		return curLocalPos;
 	}
 
-	Vector2I GUIManager::windowToBridgedCoords(const GUIWidget& widget, const Vector2I& windowPos) const
+	Vector2I GUIManager::windowToBridgedCoords(const RenderTargetPtr& target, const Vector2I& windowPos) const
 	{
 		// This cast might not be valid (the render target could be a window), but we only really need to cast
 		// so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
 		// (in which case we know it is a RenderTexture)
-		const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
+		const RenderTexture* renderTexture = static_cast<const RenderTexture*>(target.get());
 		const RenderTargetProperties& rtProps = renderTexture->getProperties();
 
 		auto iterFind = mInputBridge.find(renderTexture);
@@ -1644,6 +1645,35 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	RenderWindowPtr GUIManager::getBridgeWindow(const RenderTexturePtr& target) const
+	{
+		if (target == nullptr)
+			return nullptr;
+
+		while (true)
+		{
+			auto iterFind = mInputBridge.find(target.get());
+			if (iterFind == mInputBridge.end())
+				return nullptr;
+
+			GUIWidget* parentWidget = iterFind->second->_getParentWidget();
+			if (parentWidget == nullptr)
+				return nullptr;
+
+			RenderTargetPtr curTarget = parentWidget->getTarget()->getTarget();
+			if (curTarget == nullptr)
+				return nullptr;
+
+			if (curTarget == target)
+				return nullptr;
+
+			if (curTarget->getProperties().isWindow())
+				return std::static_pointer_cast<RenderWindow>(curTarget);
+		}
+
+		return nullptr;
+	}
+
 	bool GUIManager::sendMouseEvent(GUIElement* element, const GUIMouseEvent& event)
 	{
 		if (element->_isDestroyed())

+ 24 - 8
Source/BansheePhysX/Source/BsPhysXRigidbody.cpp

@@ -61,22 +61,38 @@ namespace BansheeEngine
 
 	void PhysXRigidbody::move(const Vector3& position)
 	{
-		PxTransform target;
-		mInternal->getKinematicTarget(target);
+		if (getIsKinematic())
+		{
+			PxTransform target;
+			if (!mInternal->getKinematicTarget(target))
+				target = PxTransform(PxIdentity);
 
-		target.p = toPxVector(position);
+			target.p = toPxVector(position);
 
-		mInternal->setKinematicTarget(target);
+			mInternal->setKinematicTarget(target);
+		}
+		else
+		{
+			setTransform(position, getRotation());
+		}
 	}
 
 	void PhysXRigidbody::rotate(const Quaternion& rotation)
 	{
-		PxTransform target;
-		mInternal->getKinematicTarget(target);
+		if (getIsKinematic())
+		{
+			PxTransform target;
+			if (!mInternal->getKinematicTarget(target))
+				target = PxTransform(PxIdentity);
 
-		target.q = toPxQuaternion(rotation);
+			target.q = toPxQuaternion(rotation);
 
-		mInternal->setKinematicTarget(target);
+			mInternal->setKinematicTarget(target);
+		}
+		else
+		{
+			setTransform(getPosition(), rotation);
+		}
 	}
 
 	Vector3 PhysXRigidbody::getPosition() const

+ 1156 - 1156
Source/MBansheeEditor/ColorPicker.cs

@@ -1,1156 +1,1156 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// A color picker window that allows the user to select from a gamut of colors.
-    /// </summary>
-    public class ColorPicker : ModalWindow
-    {
-        private const int SliderIndividualWidth = 150;
-        private const int SliderIndividualHeight = 15;
-
-        private const int ColorBoxWidth = 200;
-        private const int ColorBoxHeight = 200;
-
-        private const int SliderSideWidth = 40;
-        private const int SliderSideHeight = 200;
-
-        private float colRed, colGreen, colBlue;
-        private float colHue, colSaturation, colValue;
-        private float colAlpha = 1.0f;
-
-        private ColorSlider1DHorz sliderR, sliderG, sliderB, sliderA;
-        private ColorSlider2D colorBox;
-        private ColorSlider1DVert sideSlider;
-
-        private ColorBoxMode colorBoxMode = ColorBoxMode.BG_R;
-        private SliderMode sliderMode = SliderMode.HSV;
-
-        private GUIColorField guiColor;
-        private GUITexture guiSlider2DTex;
-        private GUITexture guiSliderVertTex;
-        private GUITexture guiSliderRHorzTex;
-        private GUITexture guiSliderGHorzTex;
-        private GUITexture guiSliderBHorzTex;
-        private GUITexture guiSliderAHorzTex;
-
-        private GUIButton guiColorBoxBtn;
-        private GUIButton guiColorModeBtn;
-
-        private GUISliderV guiSliderVert;
-        private GUISliderH guiSliderRHorz;
-        private GUISliderH guiSliderGHorz;
-        private GUISliderH guiSliderBHorz;
-        private GUISliderH guiSliderAHorz;
-        private GUITexture guiSlider2DHandle;
-
-        private GUILabel guiLabelR;
-        private GUILabel guiLabelG;
-        private GUILabel guiLabelB;
-        private GUILabel guiLabelA;
-
-        private GUIIntField guiInputR;
-        private GUIIntField guiInputG;
-        private GUIIntField guiInputB;
-        private GUIIntField guiInputA;
-
-        private GUIButton guiOK;
-        private GUIButton guiCancel;
-
-        private Action<bool, Color> closedCallback;
-
-        /// <summary>
-        /// Determines color gamut shown in the color box.
-        /// </summary>
-        public enum ColorBoxMode
-        {
-            BG_R,
-            BR_G,
-            RG_B,
-            SV_H,
-            HV_S,
-            HS_V
-        }
-
-        /// <summary>
-        /// Determines color gamut shown in the horizontal sliders.
-        /// </summary>
-        public enum SliderMode
-        {
-            RGB,
-            HSV
-        }
-
-        /// <summary>
-        /// Returns currently selected color as RGBA values.
-        /// </summary>
-        public Color SelectedColor
-        {
-            get
-            {
-                return new Color(colRed, colGreen, colBlue, colAlpha);
-            }
-        }
-
-        /// <summary>
-        /// Shows the color picker window.
-        /// </summary>
-        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
-        ///                              of the dialog.</param>
-        /// <returns>A. instance of the color picker window.</returns>
-        public static ColorPicker Show(Action<bool, Color> closedCallback = null)
-        {
-            ColorPicker picker = new ColorPicker(Color.Black, closedCallback);
-            return picker;
-        }
-
-        /// <summary>
-        /// Shows the color picker window and sets the initial color to show.
-        /// </summary>
-        /// <param name="color">Initial color to display.</param>
-        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
-        ///                              of the dialog.</param>
-        /// <returns>A. instance of the color picker window.</returns>
-        public static ColorPicker Show(Color color, Action<bool, Color> closedCallback = null)
-        {
-            ColorPicker picker = new ColorPicker(color, closedCallback);
-            return picker;
-        }
-
-        /// <summary>
-        /// Constructs a new color picker window.
-        /// </summary>
-        /// <param name="color">Initial color to display.</param>
-        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
-        ///                              of the dialog.</param>
-        protected ColorPicker(Color color, Action<bool, Color> closedCallback = null)
-            : base(false)
-        {
-            Title = new LocEdString("Color Picker");
-            Width = 270;
-            Height = 400;
-
-            colRed = color.r;
-            colGreen = color.g;
-            colBlue = color.b;
-            colAlpha = color.a;
-
-            RGBToHSV();
-
-            this.closedCallback = closedCallback;
-        }
-
-        private void OnInitialize()
-        {
-            guiColor = new GUIColorField("", GUIOption.FixedWidth(100));
-            guiSlider2DTex = new GUITexture(null, GUIOption.FixedHeight(ColorBoxHeight), GUIOption.FixedWidth(ColorBoxWidth));
-            guiSliderVertTex = new GUITexture(null, GUIOption.FixedHeight(SliderSideHeight), GUIOption.FixedWidth(SliderSideWidth));
-            guiSliderRHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
-            guiSliderGHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
-            guiSliderBHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
-            guiSliderAHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
-
-            guiColorBoxBtn = new GUIButton(colorBoxMode.ToString());
-            guiColorModeBtn = new GUIButton(sliderMode.ToString());
-
-            guiSliderVert = new GUISliderV(EditorStyles.ColorSliderVert);
-            guiSliderRHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
-            guiSliderGHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
-            guiSliderBHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
-            guiSliderAHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
-            guiSlider2DHandle = new GUITexture(null, EditorStyles.ColorSlider2DHandle);
-
-            guiLabelR = new GUILabel(new LocEdString("R"));
-            guiLabelG = new GUILabel(new LocEdString("G"));
-            guiLabelB = new GUILabel(new LocEdString("B"));
-            guiLabelA = new GUILabel(new LocEdString("A"));
-
-            guiInputR = new GUIIntField();
-            guiInputG = new GUIIntField();
-            guiInputB = new GUIIntField();
-            guiInputA = new GUIIntField();
-
-            guiOK = new GUIButton(new LocEdString("OK"));
-            guiCancel = new GUIButton(new LocEdString("Cancel"));
-
-            guiColorBoxBtn.OnClick += OnColorBoxModeChanged;
-            guiColorModeBtn.OnClick += OnSliderModeChanged;
-
-            guiSliderVert.OnChanged += OnSliderVertChanged;
-            guiSliderRHorz.OnChanged += OnSliderRHorzChanged;
-            guiSliderGHorz.OnChanged += OnSliderGHorzChanged;
-            guiSliderBHorz.OnChanged += OnSliderBHorzChanged;
-            guiSliderAHorz.OnChanged += OnSliderAHorzChanged;
-
-            guiInputR.OnChanged += OnInputRChanged;
-            guiInputG.OnChanged += OnInputGChanged;
-            guiInputB.OnChanged += OnInputBChanged;
-            guiInputA.OnChanged += OnInputAChanged;
-
-            guiOK.OnClick += OnOK;
-            guiCancel.OnClick += OnCancel;
-
-            GUIPanel mainPanel = GUI.AddPanel(0);
-            GUILayout v0 = mainPanel.AddLayoutY();
-
-            v0.AddSpace(5);
-
-            GUILayout h0 = v0.AddLayoutX();
-            h0.AddSpace(10);
-            h0.AddElement(guiColor);
-            h0.AddFlexibleSpace();
-            h0.AddElement(guiColorBoxBtn);
-            h0.AddElement(guiColorModeBtn);
-            h0.AddSpace(10);
-
-            v0.AddSpace(10);
-
-            GUILayout h1 = v0.AddLayoutX();
-            h1.AddSpace(10);
-            h1.AddElement(guiSlider2DTex);
-            h1.AddFlexibleSpace();
-            h1.AddElement(guiSliderVertTex);
-            h1.AddSpace(10);
-
-            v0.AddSpace(10);
-
-            GUILayout h2 = v0.AddLayoutX();
-            h2.AddSpace(10);
-            h2.AddElement(guiLabelR);
-            h2.AddFlexibleSpace();
-            h2.AddElement(guiSliderRHorzTex);
-            h2.AddFlexibleSpace();
-            h2.AddElement(guiInputR);
-            h2.AddSpace(10);
-
-            v0.AddSpace(5);
-
-            GUILayout h3 = v0.AddLayoutX();
-            h3.AddSpace(10);
-            h3.AddElement(guiLabelG);
-            h3.AddFlexibleSpace();
-            h3.AddElement(guiSliderGHorzTex);
-            h3.AddFlexibleSpace();
-            h3.AddElement(guiInputG);
-            h3.AddSpace(10);
-
-            v0.AddSpace(5);
-
-            GUILayout h4 = v0.AddLayoutX();
-            h4.AddSpace(10);
-            h4.AddElement(guiLabelB);
-            h4.AddFlexibleSpace();
-            h4.AddElement(guiSliderBHorzTex);
-            h4.AddFlexibleSpace();
-            h4.AddElement(guiInputB);
-            h4.AddSpace(10);
-
-            v0.AddSpace(5);
-
-            GUILayout h5 = v0.AddLayoutX();
-            h5.AddSpace(10);
-            h5.AddElement(guiLabelA);
-            h5.AddFlexibleSpace();
-            h5.AddElement(guiSliderAHorzTex);
-            h5.AddFlexibleSpace();
-            h5.AddElement(guiInputA);
-            h5.AddSpace(10);
-
-            v0.AddSpace(10);
-
-            GUILayout h6 = v0.AddLayoutX();
-            h6.AddFlexibleSpace();
-            h6.AddElement(guiOK);
-            h6.AddSpace(10);
-            h6.AddElement(guiCancel);
-            h6.AddFlexibleSpace();
-
-            v0.AddSpace(5);
-
-            GUIPanel overlay = GUI.AddPanel(-1);
-            overlay.SetWidth(Width);
-            overlay.SetHeight(Height);
-
-            overlay.AddElement(guiSliderVert);
-            overlay.AddElement(guiSliderRHorz);
-            overlay.AddElement(guiSliderGHorz);
-            overlay.AddElement(guiSliderBHorz);
-            overlay.AddElement(guiSliderAHorz);
-            overlay.AddElement(guiSlider2DHandle);
-
-            colorBox = new ColorSlider2D(guiSlider2DTex, guiSlider2DHandle, ColorBoxWidth, ColorBoxHeight);
-            sideSlider = new ColorSlider1DVert(guiSliderVertTex, guiSliderVert, SliderSideWidth, SliderSideHeight);
-
-            sliderR = new ColorSlider1DHorz(guiSliderRHorzTex, guiSliderRHorz, SliderIndividualWidth, SliderIndividualHeight);
-            sliderG = new ColorSlider1DHorz(guiSliderGHorzTex, guiSliderGHorz, SliderIndividualWidth, SliderIndividualHeight);
-            sliderB = new ColorSlider1DHorz(guiSliderBHorzTex, guiSliderBHorz, SliderIndividualWidth, SliderIndividualHeight);
-            sliderA = new ColorSlider1DHorz(guiSliderAHorzTex, guiSliderAHorz, SliderIndividualWidth, SliderIndividualHeight);
-
-            colorBox.OnValueChanged += OnColorBoxValueChanged;
-
-            Color startA = new Color(0, 0, 0, 1);
-            Color stepA = new Color(1, 1, 1, 0);
-            sliderA.UpdateTexture(startA, stepA, false);
-            guiInputA.SetRange(0, 255);
-            guiInputA.Value = 255;
-            guiSliderAHorz.Percent = 1.0f;
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update2DSliderValues();
-            Update1DSliderValues();
-            UpdateSliderMode();
-            Update2DSliderTextures();
-            Update1DSliderTextures();
-        }
-
-        private void OnEditorUpdate()
-        {
-            Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
-
-            colorBox.UpdateInput(windowPos);
-        }
-
-        /// <summary>
-        /// Fills a 2D area with colors using the provided starting point and gradients.
-        /// </summary>
-        /// <param name="width">Width of the area to fill.</param>
-        /// <param name="height">Height of the area to fill.</param>
-        /// <param name="colors">Array to contain the output. Must be of 
-        ///                      <paramref name="width"/>*<paramref name="height"/> size.</param>
-        /// <param name="start">Initial color in the top-left corner of the area.</param>
-        /// <param name="rightGradient">Gradient towards which the colors increase to the right of the area.</param>
-        /// <param name="downGradient">Gradient towards which the colors increase to the bottom of the area.</param>
-        private static void FillArea(int width, int height, Color[] colors, Color start, Color rightGradient, Color downGradient)
-        {
-            Color rightDelta = new Color(0, 0, 0, 0);
-            if (width > 1)
-                rightDelta = rightGradient / (width - 1);
-
-            Color downDelta = new Color(0, 0, 0, 0);
-            if (height > 1)
-                downDelta = downGradient / (height - 1);
-
-            Color verticalColor = start;
-            for (int y = 0; y < height; y++)
-            {
-                int rowIdx = (height - y - 1) * width;
-
-                Color currentColor = verticalColor;
-                for (int x = 0; x < width; x++)
-                {
-                    colors[rowIdx + x] = currentColor;
-                    currentColor += rightDelta;
-                }
-                verticalColor += downDelta;
-            }
-        }
-
-        /// <summary>
-        /// Converts the currently selected color from HSV to RGB color space.
-        /// </summary>
-        void HSVToRGB()
-        {
-            Color hsv = new Color(colHue, colSaturation, colValue);
-            Color rgb = Color.HSV2RGB(hsv);
-
-            colRed = rgb.r;
-            colGreen = rgb.g;
-            colBlue = rgb.b;
-        }
-
-        /// <summary>
-        /// Converts the currently selected color from RGB to HSV color space.
-        /// </summary>
-        void RGBToHSV()
-        {
-            Color rgb = new Color(colRed, colGreen, colBlue);
-            Color hsv = Color.RGB2HSV(rgb);
-
-            colHue = hsv.r;
-            colSaturation = hsv.g;
-            colValue = hsv.b;
-        }
-
-        /// <summary>
-        /// Triggered when the user selects a new mode for the color box, changing the gamut of colors displayed in the box.
-        /// </summary>
-        void OnColorBoxModeChanged()
-        {
-            int maxModes = Enum.GetNames(colorBoxMode.GetType()).Length;
-            colorBoxMode = (ColorBoxMode)(((int)colorBoxMode + 1) % maxModes);
-
-            guiColorBoxBtn.SetContent(colorBoxMode.ToString());
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user selects a new mode for the side slider, changing the gamut of colors displayed in the 
-        /// slider.
-        /// </summary>
-        void OnSliderModeChanged()
-        {
-            int maxModes = Enum.GetNames(sliderMode.GetType()).Length;
-            sliderMode = (SliderMode)(((int)sliderMode + 1) % maxModes);
-
-            UpdateSliderMode();
-
-            guiColorModeBtn.SetContent(sliderMode.ToString());
-            UpdateInputBoxValues();
-            Update1DSliderTextures();
-            Update1DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user selects a color in the color box.
-        /// </summary>
-        /// <param name="value">Location on the color box that was selected.</param>
-        void OnColorBoxValueChanged(Vector2 value)
-        {
-            switch (colorBoxMode)
-            {
-                case ColorBoxMode.BG_R:
-                    colBlue = value.x;
-                    colGreen = value.y;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.BR_G:
-                    colBlue = value.x;
-                    colRed = value.y;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.RG_B:
-                    colRed = value.x;
-                    colGreen = value.y;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.SV_H:
-                    colSaturation = value.x;
-                    colValue = value.y;
-                    HSVToRGB();
-                    break;
-                case ColorBoxMode.HV_S:
-                    colHue = value.x;
-                    colValue = value.y;
-                    HSVToRGB();
-                    break;
-                case ColorBoxMode.HS_V:
-                    colHue = value.x;
-                    colSaturation = value.y;
-                    HSVToRGB();
-                    break;
-            }
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update1DSliderTextures();
-            Update1DSliderValues();
-            UpdateSideSliderTexture();
-
-            Vector2 xy;
-            float z;
-
-            GetColorBoxValues(out xy, out z);
-            guiSliderVert.Percent = 1.0f - z;
-        }
-
-        /// <summary>
-        /// Triggered when the user moves the side slider.
-        /// </summary>
-        /// <param name="percent">New value of the slider.</param>
-        void OnSliderVertChanged(float percent)
-        {
-            percent = 1.0f - percent;
-
-            switch (colorBoxMode)
-            {
-                case ColorBoxMode.BG_R:
-                    colRed = percent;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.BR_G:
-                    colGreen = percent;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.RG_B:
-                    colBlue = percent;
-                    RGBToHSV();
-                    break;
-                case ColorBoxMode.SV_H:
-                    colHue = percent;
-                    HSVToRGB();
-                    break;
-                case ColorBoxMode.HV_S:
-                    colSaturation = percent;
-                    HSVToRGB();
-                    break;
-                case ColorBoxMode.HS_V:
-                    colValue = percent;
-                    HSVToRGB();
-                    break;
-            }
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update1DSliderTextures();
-            Update1DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user moves the horizontal Red/Hue slider.
-        /// </summary>
-        /// <param name="percent">New value of the slider.</param>
-        void OnSliderRHorzChanged(float percent)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colHue = percent;
-                HSVToRGB();
-            }
-            else
-            {
-                colRed = percent;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user moves the horizontal Green/Saturation slider.
-        /// </summary>
-        /// <param name="percent">New value of the slider.</param>
-        void OnSliderGHorzChanged(float percent)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colSaturation = percent;
-                HSVToRGB();
-            }
-            else
-            {
-                colGreen = percent;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user moves the horizontal Blue/Value slider.
-        /// </summary>
-        /// <param name="percent">New value of the slider.</param>
-        void OnSliderBHorzChanged(float percent)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colValue = percent;
-                HSVToRGB();
-            }
-            else
-            {
-                colBlue = percent;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            UpdateInputBoxValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user moves the horizontal alpha slider.
-        /// </summary>
-        /// <param name="percent">New value of the slider.</param>
-        void OnSliderAHorzChanged(float percent)
-        {
-            colAlpha = percent;
-
-            guiColor.Value = SelectedColor;
-            guiInputA.Value = MathEx.RoundToInt(colAlpha * 255.0f);
-        }
-
-        /// <summary>
-        /// Triggered when the user inputs new value in the Red/Hue input box.
-        /// </summary>
-        /// <param name="value">New value in the input box.</param>
-        void OnInputRChanged(int value)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colHue = value/359.0f;
-                HSVToRGB();
-            }
-            else
-            {
-                colRed = value/255.0f;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            Update1DSliderValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user inputs new value in the Green/Saturation input box.
-        /// </summary>
-        /// <param name="value">New value in the input box.</param>
-        void OnInputGChanged(int value)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colSaturation = value / 255.0f;
-                HSVToRGB();
-            }
-            else
-            {
-                colGreen = value / 255.0f;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            Update1DSliderValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user inputs new value in the Blue/Value input box.
-        /// </summary>
-        /// <param name="value">New value in the input box.</param>
-        void OnInputBChanged(int value)
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                colValue = value / 255.0f;
-                HSVToRGB();
-            }
-            else
-            {
-                colBlue = value / 255.0f;
-                RGBToHSV();
-            }
-
-            guiColor.Value = SelectedColor;
-            Update1DSliderValues();
-            Update2DSliderTextures();
-            Update2DSliderValues();
-        }
-
-        /// <summary>
-        /// Triggered when the user inputs new value in the alpha input box.
-        /// </summary>
-        /// <param name="value">New value in the input box.</param>
-        void OnInputAChanged(int value)
-        {
-            colAlpha = value/255.0f;
-
-            guiColor.Value = SelectedColor;
-            guiSliderAHorz.Percent = colAlpha;
-        }
-
-        /// <summary>
-        /// Triggered when the user selects a color and closes the dialog.
-        /// </summary>
-        void OnOK()
-        {
-            if (closedCallback != null)
-                closedCallback(true, SelectedColor);
-
-            Close();
-        }
-
-        /// <summary>
-        /// Triggered when the user cancels color selection and closes the dialog.
-        /// </summary>
-        void OnCancel()
-        {
-            if (closedCallback != null)
-                closedCallback(false, SelectedColor);
-
-            Close();
-        }
-
-        /// <summary>
-        /// Updates Red/Green/Blue or Hue/Saturation/Value labels and input box ranges depending on currently active mode.
-        /// </summary>
-        void UpdateSliderMode()
-        {
-            if (sliderMode == SliderMode.RGB)
-            {
-                guiLabelR.SetContent(new LocEdString("R"));
-                guiLabelG.SetContent(new LocEdString("G"));
-                guiLabelB.SetContent(new LocEdString("B"));
-
-                guiInputR.SetRange(0, 255);
-                guiInputG.SetRange(0, 255);
-                guiInputB.SetRange(0, 255);
-            }
-            else
-            {
-                guiLabelR.SetContent(new LocEdString("H"));
-                guiLabelG.SetContent(new LocEdString("S"));
-                guiLabelB.SetContent(new LocEdString("V"));
-
-                guiInputR.SetRange(0, 359);
-                guiInputG.SetRange(0, 255);
-                guiInputB.SetRange(0, 255);
-            }
-        }
-
-        /// <summary>
-        /// Updates Red/Green/Blue or Hue/Saturation/Value input boxes with currently selected color.
-        /// </summary>
-        void UpdateInputBoxValues()
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                guiInputR.Value = MathEx.RoundToInt(colHue * 359.0f);
-                guiInputG.Value = MathEx.RoundToInt(colSaturation * 255.0f);
-                guiInputB.Value = MathEx.RoundToInt(colValue * 255.0f);
-            }
-            else
-            {
-                guiInputR.Value = MathEx.RoundToInt(colRed * 255.0f);
-                guiInputG.Value = MathEx.RoundToInt(colGreen * 255.0f);
-                guiInputB.Value = MathEx.RoundToInt(colBlue * 255.0f);
-            }
-        }
-
-        /// <summary>
-        /// Updates Red/Green/Blue or Hue/Saturation/Value sliders with currently selected color.
-        /// </summary>
-        void Update1DSliderValues()
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-            if (isHSV)
-            {
-                guiSliderRHorz.Percent = colHue;
-                guiSliderGHorz.Percent = colSaturation;
-                guiSliderBHorz.Percent = colValue;
-            }
-            else
-            {
-                guiSliderRHorz.Percent = colRed;
-                guiSliderGHorz.Percent = colGreen;
-                guiSliderBHorz.Percent = colBlue;
-            }
-        }
-
-        /// <summary>
-        /// Returns the current color in the form of color box and side slider coordinates.
-        /// </summary>
-        /// <param name="xy">Coordinates on the color box the current color is located on.</param>
-        /// <param name="z">Coordinates on the side slider the current color is located on.</param>
-        void GetColorBoxValues(out Vector2 xy, out float z)
-        {
-            xy = Vector2.Zero;
-            z = 0.0f;
-
-            switch (colorBoxMode)
-            {
-                case ColorBoxMode.BG_R:
-                    xy.x = colBlue;
-                    xy.y = colGreen;
-                    z = colRed;
-                    break;
-                case ColorBoxMode.BR_G:
-                    xy.x = colBlue;
-                    xy.y = colRed;
-                    z = colGreen;
-                    break;
-                case ColorBoxMode.RG_B:
-                    xy.x = colRed;
-                    xy.y = colGreen;
-                    z = colBlue;
-                    break;
-                case ColorBoxMode.SV_H:
-                    xy.x = colSaturation;
-                    xy.y = colValue;
-                    z = colHue;
-                    break;
-                case ColorBoxMode.HV_S:
-                    xy.x = colHue;
-                    xy.y = colValue;
-                    z = colSaturation;
-                    break;
-                case ColorBoxMode.HS_V:
-                    xy.x = colHue;
-                    xy.y = colSaturation;
-                    z = colValue;
-                    break;
-            }
-        }
-
-        /// <summary>
-        /// Updates values of the color box and side slider according to the current color.
-        /// </summary>
-        void Update2DSliderValues()
-        {
-            Vector2 xy = Vector2.Zero;
-            float z = 0.0f;
-
-            GetColorBoxValues(out xy, out z);
-
-            colorBox.SetValue(xy);
-            guiSliderVert.Percent = z;
-        }
-
-        /// <summary>
-        /// Generates textures to display for all horizontal (RGB/HSV) sliders depending on active slider mode.
-        /// </summary>
-        void Update1DSliderTextures()
-        {
-            bool isHSV = sliderMode == SliderMode.HSV;
-
-            if (isHSV)
-            {
-                Color startH = new Color(0, 1, 1);
-                Color stepH = new Color(1, 0, 0, 0);
-
-                sliderR.UpdateTexture(startH, stepH, true);
-
-                Color startS = new Color(colHue, 0, MathEx.Max(colValue, 0.2f));
-                Color stepS = new Color(0, 1, 0, 0);
-
-                sliderG.UpdateTexture(startS, stepS, true);
-
-                Color startV = new Color(colHue, colSaturation, 0);
-                Color stepV = new Color(0, 0, 1, 0);
-
-                sliderB.UpdateTexture(startV, stepV, true);
-            }
-            else
-            {
-                Color startR = new Color(0, colGreen, colBlue);
-                Color stepR = new Color(1, 0, 0, 0);
-
-                sliderR.UpdateTexture(startR, stepR, false);
-
-                Color startG = new Color(colRed, 0, colBlue);
-                Color stepG = new Color(0, 1, 0, 0);
-
-                sliderG.UpdateTexture(startG, stepG, false);
-
-                Color startB = new Color(colRed, colGreen, 0);
-                Color stepB = new Color(0, 0, 1, 0);
-
-                sliderB.UpdateTexture(startB, stepB, false);
-            }
-        }
-
-        /// <summary>
-        /// Generates a texture for the side slider depending on active color box mode.
-        /// </summary>
-        void UpdateSideSliderTexture()
-        {
-            switch (colorBoxMode)
-            {
-                case ColorBoxMode.BG_R:
-                    sideSlider.UpdateTexture(new Color(0, colGreen, colBlue, 1), new Color(1, 0, 0, 0), false);
-                    break;
-                case ColorBoxMode.BR_G:
-                    sideSlider.UpdateTexture(new Color(colRed, 0, colBlue, 1), new Color(0, 1, 0, 0), false);
-                    break;
-                case ColorBoxMode.RG_B:
-                    sideSlider.UpdateTexture(new Color(colRed, colGreen, 0, 1), new Color(0, 0, 1, 0), false);
-                    break;
-                case ColorBoxMode.SV_H:
-                    sideSlider.UpdateTexture(new Color(0, 1, 1, 1), new Color(1, 0, 0, 0), true);
-                    break;
-                case ColorBoxMode.HV_S:
-                    sideSlider.UpdateTexture(new Color(colHue, 0, MathEx.Max(colValue, 0.2f), 1), new Color(0, 1, 0, 0), true);
-                    break;
-                case ColorBoxMode.HS_V:
-                    sideSlider.UpdateTexture(new Color(colHue, colSaturation, 0, 1), new Color(0, 0, 1, 0), true);
-                    break;
-            }
-        }
-
-        /// <summary>
-        /// Generates textures for the color box and the side slider depending on active color box mode.
-        /// </summary>
-        void Update2DSliderTextures()
-        {
-            UpdateSideSliderTexture();
-
-            float[] valueLookup = new float[] { colRed, colGreen, colBlue, colHue, colSaturation, colValue };
-            colorBox.UpdateTexture(colorBoxMode, valueLookup[(int)colorBoxMode]);
-        }
-
-        /// <summary>
-        /// Manages GUI for a 1D horizontal slider (used RGB/HSV display).
-        /// </summary>
-        public class ColorSlider1DHorz
-        {
-            private const int SLIDER_X_OFFSET = 3;
-            private const int SLIDER_Y_OFFSET = 5;
-
-            private int width, height;
-            private Texture2D texture;
-            private SpriteTexture spriteTexture;
-
-            private GUITexture guiTexture;
-            private GUISliderH guiSlider;
-
-            /// <summary>
-            /// Creates a new horizontal slider.
-            /// </summary>
-            /// <param name="guiTexture">GUI element to display the slider color range on.</param>
-            /// <param name="guiSlider">Slider rendered on top of the texture that may be moved by the user to select a 
-            ///                         color.</param>
-            /// <param name="width">Width of the slider in pixels.</param>
-            /// <param name="height">Height of the slider in pixels.</param>
-            public ColorSlider1DHorz(GUITexture guiTexture, GUISliderH guiSlider, int width, int height)
-            {
-                this.width = width;
-                this.height = height;
-                this.guiTexture = guiTexture;
-                this.guiSlider = guiSlider;
-
-                texture = new Texture2D(width, height);
-                spriteTexture = new SpriteTexture(texture);
-            }
-
-            /// <summary>
-            /// Updates the displayed texture with specified color information.
-            /// </summary>
-            /// <param name="start">Initial color on the left of the slider.</param>
-            /// <param name="step">Final color to the right of the slider.</param>
-            /// <param name="isHSV">Determines are the provided colors in RGB or HSV space.</param>
-            public void UpdateTexture(Color start, Color step, bool isHSV)
-            {
-                Color[] colors = new Color[width * height];
-                FillArea(width, height, colors, start, step, new Color(0, 0, 0, 0));
-
-                if (isHSV)
-                {
-                    for (int i = 0; i < colors.Length; i++)
-                        colors[i] = Color.HSV2RGB(colors[i]);
-                }
-
-                texture.SetPixels(colors);
-                guiTexture.SetTexture(spriteTexture);
-
-                Rect2I sliderBounds = guiTexture.Bounds;
-                sliderBounds.x -= SLIDER_X_OFFSET;
-                sliderBounds.width += SLIDER_X_OFFSET * 2;
-                sliderBounds.y -= SLIDER_Y_OFFSET;
-                sliderBounds.height += SLIDER_Y_OFFSET;
-
-                guiSlider.Bounds = sliderBounds;
-            }
-        }
-
-        /// <summary>
-        /// Manages GUI for a 1D vertical slider (side slider along with the color box).
-        /// </summary>
-        public class ColorSlider1DVert
-        {
-            private const int SLIDER_X_OFFSET = 5;
-            private const int SLIDER_Y_OFFSET = 3;
-
-            private int width, height;
-            private Texture2D texture;
-            private SpriteTexture spriteTexture;
-
-            private GUITexture guiTexture;
-            private GUISliderV guiSlider;
-
-            /// <summary>
-            /// Creates a new vertical slider.
-            /// </summary>
-            /// <param name="guiTexture">GUI element to display the slider color range on.</param>
-            /// <param name="guiSlider">Slider rendered on top of the texture that may be moved by the user to select a 
-            ///                         color.</param>
-            /// <param name="width">Width of the slider in pixels.</param>
-            /// <param name="height">Height of the slider in pixels.</param>
-            public ColorSlider1DVert(GUITexture guiTexture, GUISliderV guiSlider, int width, int height)
-            {
-                this.width = width;
-                this.height = height;
-                this.guiTexture = guiTexture;
-                this.guiSlider = guiSlider;
-
-                texture = new Texture2D(width, height);
-                spriteTexture = new SpriteTexture(texture);
-            }
-
-            /// <summary>
-            /// Updates the displayed texture with specified color information.
-            /// </summary>
-            /// <param name="start">Initial color on the top of the slider.</param>
-            /// <param name="step">Final color to the bottom of the slider.</param>
-            /// <param name="isHSV">Determines are the provided colors in RGB or HSV space.</param>
-            public void UpdateTexture(Color start, Color step, bool isHSV)
-            {
-                Color[] colors = new Color[width * height];
-                FillArea(width, height, colors, start, new Color(0, 0, 0, 0), step);
-
-                if (isHSV)
-                {
-                    for (int i = 0; i < colors.Length; i++)
-                        colors[i] = Color.HSV2RGB(colors[i]);
-                }
-
-                texture.SetPixels(colors);
-                guiTexture.SetTexture(spriteTexture);
-
-                Rect2I sliderBounds = guiTexture.Bounds;
-                sliderBounds.x -= SLIDER_X_OFFSET;
-                sliderBounds.width += SLIDER_X_OFFSET;
-                sliderBounds.y -= SLIDER_Y_OFFSET;
-                sliderBounds.height += SLIDER_Y_OFFSET * 2;
-
-                guiSlider.Bounds = sliderBounds;
-            }
-        }
-
-        /// <summary>
-        /// Manages GUI for a 2D color box, as well as manually handling color box input. Color box serves as a 2D sliders 
-        /// as you can portion of it to select a color.
-        /// </summary>
-        public class ColorSlider2D
-        {
-            private int width, height;
-            private Texture2D texture;
-            private SpriteTexture spriteTexture;
-
-            private GUITexture guiTexture;
-            private GUITexture guiSliderHandle;
-
-            private Vector2 oldValue = new Vector2(-1, -1);
-
-            public delegate void OnValueChangedDelegate(Vector2 value);
-            public event OnValueChangedDelegate OnValueChanged;
-
-            /// <summary>
-            /// Creates a new color box.
-            /// </summary>
-            /// <param name="guiTexture">GUI element to display the 2D color range on.</param>
-            /// <param name="guiSliderHandle">Texture to be used for displaying the position of the currently selected 
-            ///                               color.</param>
-            /// <param name="width">Width of the slider in pixels.</param>
-            /// <param name="height">Height of the slider in pixels.</param>
-            public ColorSlider2D(GUITexture guiTexture, GUITexture guiSliderHandle, int width, int height)
-            {
-                this.width = width;
-                this.height = height;
-
-                this.guiTexture = guiTexture;
-                this.guiSliderHandle = guiSliderHandle;
-
-                texture = new Texture2D(width, height);
-                spriteTexture = new SpriteTexture(texture);
-            }
-
-            /// <summary>
-            /// Updates the texture displayed on the color box.
-            /// </summary>
-            /// <param name="mode">Mode determining the color gamut shown in the color box.</param>
-            /// <param name="value">Value of the third component (normally retrieved from the separate side slider).</param>
-            public void UpdateTexture(ColorBoxMode mode, float value)
-            {
-                Color[] colors = new Color[width * height];
-
-                switch (mode)
-                {
-                    case ColorBoxMode.BG_R:
-                        FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 0, 1, 0), new Color(0, 1, 0, 0));
-                        break;
-                    case ColorBoxMode.BR_G:
-                        FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(0, 0, 1, 0), new Color(1, 0, 0, 0));
-                        break;
-                    case ColorBoxMode.RG_B:
-                        FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0));
-                        break;
-                    case ColorBoxMode.SV_H:
-                        FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 1, 0, 0), new Color(0, 0, 1, 0));
-                        for (int i = 0; i < colors.Length; i++)
-                            colors[i] = Color.HSV2RGB(colors[i]);
-                        break;
-                    case ColorBoxMode.HV_S:
-                        FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(1, 0, 0, 0), new Color(0, 0, 1, 0));
-                        for (int i = 0; i < colors.Length; i++)
-                            colors[i] = Color.HSV2RGB(colors[i]);
-                        break;
-                    case ColorBoxMode.HS_V:
-                        FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0));
-                        for (int i = 0; i < colors.Length; i++)
-                            colors[i] = Color.HSV2RGB(colors[i]);
-                        break;
-                }
-
-                texture.SetPixels(colors);
-                guiTexture.SetTexture(spriteTexture);
-            }
-
-            /// <summary>
-            /// Handles input over the color box, moving the handle as needed.
-            /// </summary>
-            /// <param name="windowPos">Position of the pointer relative to the color picker window.</param>
-            public void UpdateInput(Vector2I windowPos)
-            {
-                if (Input.IsPointerButtonHeld(PointerButton.Left))
-                {
-                    Rect2I bounds = guiTexture.Bounds;
-
-                    if (bounds.Contains(windowPos))
-                    {
-                        Vector2 newValue = Vector2.Zero;
-                        newValue.x = (windowPos.x - bounds.x) / (float)bounds.width;
-                        newValue.y = 1.0f - (windowPos.y - bounds.y) / (float)bounds.height;
-
-                        SetValue(newValue);
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Moves the handle to a specific location on the color box and selects that color.
-            /// </summary>
-            /// <param name="value">Coordinates relative to the color box.</param>
-            public void SetValue(Vector2 value)
-            {
-                Vector2 pos = value;
-                pos.y = 1.0f - pos.y;
-
-                if (oldValue == value)
-                    return;
-
-                Rect2I handleBounds = guiSliderHandle.Bounds;
-                Rect2I boxBounds = guiTexture.Bounds;
-
-                handleBounds.x = boxBounds.x + MathEx.RoundToInt(pos.x * boxBounds.width) - handleBounds.width / 2;
-                handleBounds.y = boxBounds.y + MathEx.RoundToInt(pos.y * boxBounds.height) - handleBounds.height / 2;
-
-                guiSliderHandle.Bounds = handleBounds;
-                oldValue = value;
-
-                if (OnValueChanged != null)
-                    OnValueChanged(value);
-            }
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// A color picker window that allows the user to select from a gamut of colors.
+    /// </summary>
+    public class ColorPicker : ModalWindow
+    {
+        private const int SliderIndividualWidth = 150;
+        private const int SliderIndividualHeight = 15;
+
+        private const int ColorBoxWidth = 200;
+        private const int ColorBoxHeight = 200;
+
+        private const int SliderSideWidth = 40;
+        private const int SliderSideHeight = 200;
+
+        private float colRed, colGreen, colBlue;
+        private float colHue, colSaturation, colValue;
+        private float colAlpha = 1.0f;
+
+        private ColorSlider1DHorz sliderR, sliderG, sliderB, sliderA;
+        private ColorSlider2D colorBox;
+        private ColorSlider1DVert sideSlider;
+
+        private ColorBoxMode colorBoxMode = ColorBoxMode.BG_R;
+        private SliderMode sliderMode = SliderMode.HSV;
+
+        private GUIColorField guiColor;
+        private GUITexture guiSlider2DTex;
+        private GUITexture guiSliderVertTex;
+        private GUITexture guiSliderRHorzTex;
+        private GUITexture guiSliderGHorzTex;
+        private GUITexture guiSliderBHorzTex;
+        private GUITexture guiSliderAHorzTex;
+
+        private GUIButton guiColorBoxBtn;
+        private GUIButton guiColorModeBtn;
+
+        private GUISliderV guiSliderVert;
+        private GUISliderH guiSliderRHorz;
+        private GUISliderH guiSliderGHorz;
+        private GUISliderH guiSliderBHorz;
+        private GUISliderH guiSliderAHorz;
+        private GUITexture guiSlider2DHandle;
+
+        private GUILabel guiLabelR;
+        private GUILabel guiLabelG;
+        private GUILabel guiLabelB;
+        private GUILabel guiLabelA;
+
+        private GUIIntField guiInputR;
+        private GUIIntField guiInputG;
+        private GUIIntField guiInputB;
+        private GUIIntField guiInputA;
+
+        private GUIButton guiOK;
+        private GUIButton guiCancel;
+
+        private Action<bool, Color> closedCallback;
+
+        /// <summary>
+        /// Determines color gamut shown in the color box.
+        /// </summary>
+        public enum ColorBoxMode
+        {
+            BG_R,
+            BR_G,
+            RG_B,
+            SV_H,
+            HV_S,
+            HS_V
+        }
+
+        /// <summary>
+        /// Determines color gamut shown in the horizontal sliders.
+        /// </summary>
+        public enum SliderMode
+        {
+            RGB,
+            HSV
+        }
+
+        /// <summary>
+        /// Returns currently selected color as RGBA values.
+        /// </summary>
+        public Color SelectedColor
+        {
+            get
+            {
+                return new Color(colRed, colGreen, colBlue, colAlpha);
+            }
+        }
+
+        /// <summary>
+        /// Shows the color picker window.
+        /// </summary>
+        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
+        ///                              of the dialog.</param>
+        /// <returns>A. instance of the color picker window.</returns>
+        public static ColorPicker Show(Action<bool, Color> closedCallback = null)
+        {
+            ColorPicker picker = new ColorPicker(Color.Black, closedCallback);
+            return picker;
+        }
+
+        /// <summary>
+        /// Shows the color picker window and sets the initial color to show.
+        /// </summary>
+        /// <param name="color">Initial color to display.</param>
+        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
+        ///                              of the dialog.</param>
+        /// <returns>A. instance of the color picker window.</returns>
+        public static ColorPicker Show(Color color, Action<bool, Color> closedCallback = null)
+        {
+            ColorPicker picker = new ColorPicker(color, closedCallback);
+            return picker;
+        }
+
+        /// <summary>
+        /// Constructs a new color picker window.
+        /// </summary>
+        /// <param name="color">Initial color to display.</param>
+        /// <param name="closedCallback">Optional callback to trigger when the user selects a color or cancels out
+        ///                              of the dialog.</param>
+        protected ColorPicker(Color color, Action<bool, Color> closedCallback = null)
+            : base(false)
+        {
+            Title = new LocEdString("Color Picker");
+            Width = 270;
+            Height = 400;
+
+            colRed = color.r;
+            colGreen = color.g;
+            colBlue = color.b;
+            colAlpha = color.a;
+
+            RGBToHSV();
+
+            this.closedCallback = closedCallback;
+        }
+
+        private void OnInitialize()
+        {
+            guiColor = new GUIColorField("", GUIOption.FixedWidth(100));
+            guiSlider2DTex = new GUITexture(null, GUIOption.FixedHeight(ColorBoxHeight), GUIOption.FixedWidth(ColorBoxWidth));
+            guiSliderVertTex = new GUITexture(null, GUIOption.FixedHeight(SliderSideHeight), GUIOption.FixedWidth(SliderSideWidth));
+            guiSliderRHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
+            guiSliderGHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
+            guiSliderBHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
+            guiSliderAHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight));
+
+            guiColorBoxBtn = new GUIButton(colorBoxMode.ToString());
+            guiColorModeBtn = new GUIButton(sliderMode.ToString());
+
+            guiSliderVert = new GUISliderV(EditorStyles.ColorSliderVert);
+            guiSliderRHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
+            guiSliderGHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
+            guiSliderBHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
+            guiSliderAHorz = new GUISliderH(EditorStyles.ColorSliderHorz);
+            guiSlider2DHandle = new GUITexture(null, EditorStyles.ColorSlider2DHandle);
+
+            guiLabelR = new GUILabel(new LocEdString("R"));
+            guiLabelG = new GUILabel(new LocEdString("G"));
+            guiLabelB = new GUILabel(new LocEdString("B"));
+            guiLabelA = new GUILabel(new LocEdString("A"));
+
+            guiInputR = new GUIIntField();
+            guiInputG = new GUIIntField();
+            guiInputB = new GUIIntField();
+            guiInputA = new GUIIntField();
+
+            guiOK = new GUIButton(new LocEdString("OK"));
+            guiCancel = new GUIButton(new LocEdString("Cancel"));
+
+            guiColorBoxBtn.OnClick += OnColorBoxModeChanged;
+            guiColorModeBtn.OnClick += OnSliderModeChanged;
+
+            guiSliderVert.OnChanged += OnSliderVertChanged;
+            guiSliderRHorz.OnChanged += OnSliderRHorzChanged;
+            guiSliderGHorz.OnChanged += OnSliderGHorzChanged;
+            guiSliderBHorz.OnChanged += OnSliderBHorzChanged;
+            guiSliderAHorz.OnChanged += OnSliderAHorzChanged;
+
+            guiInputR.OnChanged += OnInputRChanged;
+            guiInputG.OnChanged += OnInputGChanged;
+            guiInputB.OnChanged += OnInputBChanged;
+            guiInputA.OnChanged += OnInputAChanged;
+
+            guiOK.OnClick += OnOK;
+            guiCancel.OnClick += OnCancel;
+
+            GUIPanel mainPanel = GUI.AddPanel(0);
+            GUILayout v0 = mainPanel.AddLayoutY();
+
+            v0.AddSpace(5);
+
+            GUILayout h0 = v0.AddLayoutX();
+            h0.AddSpace(10);
+            h0.AddElement(guiColor);
+            h0.AddFlexibleSpace();
+            h0.AddElement(guiColorBoxBtn);
+            h0.AddElement(guiColorModeBtn);
+            h0.AddSpace(10);
+
+            v0.AddSpace(10);
+
+            GUILayout h1 = v0.AddLayoutX();
+            h1.AddSpace(10);
+            h1.AddElement(guiSlider2DTex);
+            h1.AddFlexibleSpace();
+            h1.AddElement(guiSliderVertTex);
+            h1.AddSpace(10);
+
+            v0.AddSpace(10);
+
+            GUILayout h2 = v0.AddLayoutX();
+            h2.AddSpace(10);
+            h2.AddElement(guiLabelR);
+            h2.AddFlexibleSpace();
+            h2.AddElement(guiSliderRHorzTex);
+            h2.AddFlexibleSpace();
+            h2.AddElement(guiInputR);
+            h2.AddSpace(10);
+
+            v0.AddSpace(5);
+
+            GUILayout h3 = v0.AddLayoutX();
+            h3.AddSpace(10);
+            h3.AddElement(guiLabelG);
+            h3.AddFlexibleSpace();
+            h3.AddElement(guiSliderGHorzTex);
+            h3.AddFlexibleSpace();
+            h3.AddElement(guiInputG);
+            h3.AddSpace(10);
+
+            v0.AddSpace(5);
+
+            GUILayout h4 = v0.AddLayoutX();
+            h4.AddSpace(10);
+            h4.AddElement(guiLabelB);
+            h4.AddFlexibleSpace();
+            h4.AddElement(guiSliderBHorzTex);
+            h4.AddFlexibleSpace();
+            h4.AddElement(guiInputB);
+            h4.AddSpace(10);
+
+            v0.AddSpace(5);
+
+            GUILayout h5 = v0.AddLayoutX();
+            h5.AddSpace(10);
+            h5.AddElement(guiLabelA);
+            h5.AddFlexibleSpace();
+            h5.AddElement(guiSliderAHorzTex);
+            h5.AddFlexibleSpace();
+            h5.AddElement(guiInputA);
+            h5.AddSpace(10);
+
+            v0.AddSpace(10);
+
+            GUILayout h6 = v0.AddLayoutX();
+            h6.AddFlexibleSpace();
+            h6.AddElement(guiOK);
+            h6.AddSpace(10);
+            h6.AddElement(guiCancel);
+            h6.AddFlexibleSpace();
+
+            v0.AddSpace(5);
+
+            GUIPanel overlay = GUI.AddPanel(-1);
+            overlay.SetWidth(Width);
+            overlay.SetHeight(Height);
+
+            overlay.AddElement(guiSliderVert);
+            overlay.AddElement(guiSliderRHorz);
+            overlay.AddElement(guiSliderGHorz);
+            overlay.AddElement(guiSliderBHorz);
+            overlay.AddElement(guiSliderAHorz);
+            overlay.AddElement(guiSlider2DHandle);
+
+            colorBox = new ColorSlider2D(guiSlider2DTex, guiSlider2DHandle, ColorBoxWidth, ColorBoxHeight);
+            sideSlider = new ColorSlider1DVert(guiSliderVertTex, guiSliderVert, SliderSideWidth, SliderSideHeight);
+
+            sliderR = new ColorSlider1DHorz(guiSliderRHorzTex, guiSliderRHorz, SliderIndividualWidth, SliderIndividualHeight);
+            sliderG = new ColorSlider1DHorz(guiSliderGHorzTex, guiSliderGHorz, SliderIndividualWidth, SliderIndividualHeight);
+            sliderB = new ColorSlider1DHorz(guiSliderBHorzTex, guiSliderBHorz, SliderIndividualWidth, SliderIndividualHeight);
+            sliderA = new ColorSlider1DHorz(guiSliderAHorzTex, guiSliderAHorz, SliderIndividualWidth, SliderIndividualHeight);
+
+            colorBox.OnValueChanged += OnColorBoxValueChanged;
+
+            Color startA = new Color(0, 0, 0, 1);
+            Color stepA = new Color(1, 1, 1, 0);
+            sliderA.UpdateTexture(startA, stepA, false);
+            guiInputA.SetRange(0, 255);
+            guiInputA.Value = 255;
+            guiSliderAHorz.Percent = 1.0f;
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderValues();
+            Update1DSliderValues();
+            UpdateSliderMode();
+            Update2DSliderTextures();
+            Update1DSliderTextures();
+        }
+
+        private void OnEditorUpdate()
+        {
+            Vector2I windowPos = ScreenToWindowPos(Input.PointerScreenPosition);
+
+            colorBox.UpdateInput(windowPos);
+        }
+
+        /// <summary>
+        /// Fills a 2D area with colors using the provided starting point and gradients.
+        /// </summary>
+        /// <param name="width">Width of the area to fill.</param>
+        /// <param name="height">Height of the area to fill.</param>
+        /// <param name="colors">Array to contain the output. Must be of 
+        ///                      <paramref name="width"/>*<paramref name="height"/> size.</param>
+        /// <param name="start">Initial color in the top-left corner of the area.</param>
+        /// <param name="rightGradient">Gradient towards which the colors increase to the right of the area.</param>
+        /// <param name="downGradient">Gradient towards which the colors increase to the bottom of the area.</param>
+        private static void FillArea(int width, int height, Color[] colors, Color start, Color rightGradient, Color downGradient)
+        {
+            Color rightDelta = new Color(0, 0, 0, 0);
+            if (width > 1)
+                rightDelta = rightGradient / (width - 1);
+
+            Color downDelta = new Color(0, 0, 0, 0);
+            if (height > 1)
+                downDelta = downGradient / (height - 1);
+
+            Color verticalColor = start;
+            for (int y = 0; y < height; y++)
+            {
+                int rowIdx = (height - y - 1) * width;
+
+                Color currentColor = verticalColor;
+                for (int x = 0; x < width; x++)
+                {
+                    colors[rowIdx + x] = currentColor;
+                    currentColor += rightDelta;
+                }
+                verticalColor += downDelta;
+            }
+        }
+
+        /// <summary>
+        /// Converts the currently selected color from HSV to RGB color space.
+        /// </summary>
+        void HSVToRGB()
+        {
+            Color hsv = new Color(colHue, colSaturation, colValue);
+            Color rgb = Color.HSV2RGB(hsv);
+
+            colRed = rgb.r;
+            colGreen = rgb.g;
+            colBlue = rgb.b;
+        }
+
+        /// <summary>
+        /// Converts the currently selected color from RGB to HSV color space.
+        /// </summary>
+        void RGBToHSV()
+        {
+            Color rgb = new Color(colRed, colGreen, colBlue);
+            Color hsv = Color.RGB2HSV(rgb);
+
+            colHue = hsv.r;
+            colSaturation = hsv.g;
+            colValue = hsv.b;
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a new mode for the color box, changing the gamut of colors displayed in the box.
+        /// </summary>
+        void OnColorBoxModeChanged()
+        {
+            int maxModes = Enum.GetNames(colorBoxMode.GetType()).Length;
+            colorBoxMode = (ColorBoxMode)(((int)colorBoxMode + 1) % maxModes);
+
+            guiColorBoxBtn.SetContent(colorBoxMode.ToString());
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a new mode for the side slider, changing the gamut of colors displayed in the 
+        /// slider.
+        /// </summary>
+        void OnSliderModeChanged()
+        {
+            int maxModes = Enum.GetNames(sliderMode.GetType()).Length;
+            sliderMode = (SliderMode)(((int)sliderMode + 1) % maxModes);
+
+            UpdateSliderMode();
+
+            guiColorModeBtn.SetContent(sliderMode.ToString());
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a color in the color box.
+        /// </summary>
+        /// <param name="value">Location on the color box that was selected.</param>
+        void OnColorBoxValueChanged(Vector2 value)
+        {
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    colBlue = value.x;
+                    colGreen = value.y;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.BR_G:
+                    colBlue = value.x;
+                    colRed = value.y;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.RG_B:
+                    colRed = value.x;
+                    colGreen = value.y;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.SV_H:
+                    colSaturation = value.x;
+                    colValue = value.y;
+                    HSVToRGB();
+                    break;
+                case ColorBoxMode.HV_S:
+                    colHue = value.x;
+                    colValue = value.y;
+                    HSVToRGB();
+                    break;
+                case ColorBoxMode.HS_V:
+                    colHue = value.x;
+                    colSaturation = value.y;
+                    HSVToRGB();
+                    break;
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+            UpdateSideSliderTexture();
+
+            Vector2 xy;
+            float z;
+
+            GetColorBoxValues(out xy, out z);
+            guiSliderVert.Percent = 1.0f - z;
+        }
+
+        /// <summary>
+        /// Triggered when the user moves the side slider.
+        /// </summary>
+        /// <param name="percent">New value of the slider.</param>
+        void OnSliderVertChanged(float percent)
+        {
+            percent = 1.0f - percent;
+
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    colRed = percent;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.BR_G:
+                    colGreen = percent;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.RG_B:
+                    colBlue = percent;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.SV_H:
+                    colHue = percent;
+                    HSVToRGB();
+                    break;
+                case ColorBoxMode.HV_S:
+                    colSaturation = percent;
+                    HSVToRGB();
+                    break;
+                case ColorBoxMode.HS_V:
+                    colValue = percent;
+                    HSVToRGB();
+                    break;
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user moves the horizontal Red/Hue slider.
+        /// </summary>
+        /// <param name="percent">New value of the slider.</param>
+        void OnSliderRHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colHue = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colRed = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user moves the horizontal Green/Saturation slider.
+        /// </summary>
+        /// <param name="percent">New value of the slider.</param>
+        void OnSliderGHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colSaturation = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colGreen = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user moves the horizontal Blue/Value slider.
+        /// </summary>
+        /// <param name="percent">New value of the slider.</param>
+        void OnSliderBHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colValue = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colBlue = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user moves the horizontal alpha slider.
+        /// </summary>
+        /// <param name="percent">New value of the slider.</param>
+        void OnSliderAHorzChanged(float percent)
+        {
+            colAlpha = percent;
+
+            guiColor.Value = SelectedColor;
+            guiInputA.Value = MathEx.RoundToInt(colAlpha * 255.0f);
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs new value in the Red/Hue input box.
+        /// </summary>
+        /// <param name="value">New value in the input box.</param>
+        void OnInputRChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colHue = value/359.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colRed = value/255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs new value in the Green/Saturation input box.
+        /// </summary>
+        /// <param name="value">New value in the input box.</param>
+        void OnInputGChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colSaturation = value / 255.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colGreen = value / 255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs new value in the Blue/Value input box.
+        /// </summary>
+        /// <param name="value">New value in the input box.</param>
+        void OnInputBChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colValue = value / 255.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colBlue = value / 255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs new value in the alpha input box.
+        /// </summary>
+        /// <param name="value">New value in the input box.</param>
+        void OnInputAChanged(int value)
+        {
+            colAlpha = value/255.0f;
+
+            guiColor.Value = SelectedColor;
+            guiSliderAHorz.Percent = colAlpha;
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a color and closes the dialog.
+        /// </summary>
+        void OnOK()
+        {
+            if (closedCallback != null)
+                closedCallback(true, SelectedColor);
+
+            Close();
+        }
+
+        /// <summary>
+        /// Triggered when the user cancels color selection and closes the dialog.
+        /// </summary>
+        void OnCancel()
+        {
+            if (closedCallback != null)
+                closedCallback(false, SelectedColor);
+
+            Close();
+        }
+
+        /// <summary>
+        /// Updates Red/Green/Blue or Hue/Saturation/Value labels and input box ranges depending on currently active mode.
+        /// </summary>
+        void UpdateSliderMode()
+        {
+            if (sliderMode == SliderMode.RGB)
+            {
+                guiLabelR.SetContent(new LocEdString("R"));
+                guiLabelG.SetContent(new LocEdString("G"));
+                guiLabelB.SetContent(new LocEdString("B"));
+
+                guiInputR.SetRange(0, 255);
+                guiInputG.SetRange(0, 255);
+                guiInputB.SetRange(0, 255);
+            }
+            else
+            {
+                guiLabelR.SetContent(new LocEdString("H"));
+                guiLabelG.SetContent(new LocEdString("S"));
+                guiLabelB.SetContent(new LocEdString("V"));
+
+                guiInputR.SetRange(0, 359);
+                guiInputG.SetRange(0, 255);
+                guiInputB.SetRange(0, 255);
+            }
+        }
+
+        /// <summary>
+        /// Updates Red/Green/Blue or Hue/Saturation/Value input boxes with currently selected color.
+        /// </summary>
+        void UpdateInputBoxValues()
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                guiInputR.Value = MathEx.RoundToInt(colHue * 359.0f);
+                guiInputG.Value = MathEx.RoundToInt(colSaturation * 255.0f);
+                guiInputB.Value = MathEx.RoundToInt(colValue * 255.0f);
+            }
+            else
+            {
+                guiInputR.Value = MathEx.RoundToInt(colRed * 255.0f);
+                guiInputG.Value = MathEx.RoundToInt(colGreen * 255.0f);
+                guiInputB.Value = MathEx.RoundToInt(colBlue * 255.0f);
+            }
+        }
+
+        /// <summary>
+        /// Updates Red/Green/Blue or Hue/Saturation/Value sliders with currently selected color.
+        /// </summary>
+        void Update1DSliderValues()
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                guiSliderRHorz.Percent = colHue;
+                guiSliderGHorz.Percent = colSaturation;
+                guiSliderBHorz.Percent = colValue;
+            }
+            else
+            {
+                guiSliderRHorz.Percent = colRed;
+                guiSliderGHorz.Percent = colGreen;
+                guiSliderBHorz.Percent = colBlue;
+            }
+        }
+
+        /// <summary>
+        /// Returns the current color in the form of color box and side slider coordinates.
+        /// </summary>
+        /// <param name="xy">Coordinates on the color box the current color is located on.</param>
+        /// <param name="z">Coordinates on the side slider the current color is located on.</param>
+        void GetColorBoxValues(out Vector2 xy, out float z)
+        {
+            xy = Vector2.Zero;
+            z = 0.0f;
+
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    xy.x = colBlue;
+                    xy.y = colGreen;
+                    z = colRed;
+                    break;
+                case ColorBoxMode.BR_G:
+                    xy.x = colBlue;
+                    xy.y = colRed;
+                    z = colGreen;
+                    break;
+                case ColorBoxMode.RG_B:
+                    xy.x = colRed;
+                    xy.y = colGreen;
+                    z = colBlue;
+                    break;
+                case ColorBoxMode.SV_H:
+                    xy.x = colSaturation;
+                    xy.y = colValue;
+                    z = colHue;
+                    break;
+                case ColorBoxMode.HV_S:
+                    xy.x = colHue;
+                    xy.y = colValue;
+                    z = colSaturation;
+                    break;
+                case ColorBoxMode.HS_V:
+                    xy.x = colHue;
+                    xy.y = colSaturation;
+                    z = colValue;
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Updates values of the color box and side slider according to the current color.
+        /// </summary>
+        void Update2DSliderValues()
+        {
+            Vector2 xy = Vector2.Zero;
+            float z = 0.0f;
+
+            GetColorBoxValues(out xy, out z);
+
+            colorBox.SetValue(xy);
+            guiSliderVert.Percent = z;
+        }
+
+        /// <summary>
+        /// Generates textures to display for all horizontal (RGB/HSV) sliders depending on active slider mode.
+        /// </summary>
+        void Update1DSliderTextures()
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+
+            if (isHSV)
+            {
+                Color startH = new Color(0, 1, 1);
+                Color stepH = new Color(1, 0, 0, 0);
+
+                sliderR.UpdateTexture(startH, stepH, true);
+
+                Color startS = new Color(colHue, 0, MathEx.Max(colValue, 0.2f));
+                Color stepS = new Color(0, 1, 0, 0);
+
+                sliderG.UpdateTexture(startS, stepS, true);
+
+                Color startV = new Color(colHue, colSaturation, 0);
+                Color stepV = new Color(0, 0, 1, 0);
+
+                sliderB.UpdateTexture(startV, stepV, true);
+            }
+            else
+            {
+                Color startR = new Color(0, colGreen, colBlue);
+                Color stepR = new Color(1, 0, 0, 0);
+
+                sliderR.UpdateTexture(startR, stepR, false);
+
+                Color startG = new Color(colRed, 0, colBlue);
+                Color stepG = new Color(0, 1, 0, 0);
+
+                sliderG.UpdateTexture(startG, stepG, false);
+
+                Color startB = new Color(colRed, colGreen, 0);
+                Color stepB = new Color(0, 0, 1, 0);
+
+                sliderB.UpdateTexture(startB, stepB, false);
+            }
+        }
+
+        /// <summary>
+        /// Generates a texture for the side slider depending on active color box mode.
+        /// </summary>
+        void UpdateSideSliderTexture()
+        {
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    sideSlider.UpdateTexture(new Color(0, colGreen, colBlue, 1), new Color(1, 0, 0, 0), false);
+                    break;
+                case ColorBoxMode.BR_G:
+                    sideSlider.UpdateTexture(new Color(colRed, 0, colBlue, 1), new Color(0, 1, 0, 0), false);
+                    break;
+                case ColorBoxMode.RG_B:
+                    sideSlider.UpdateTexture(new Color(colRed, colGreen, 0, 1), new Color(0, 0, 1, 0), false);
+                    break;
+                case ColorBoxMode.SV_H:
+                    sideSlider.UpdateTexture(new Color(0, 1, 1, 1), new Color(1, 0, 0, 0), true);
+                    break;
+                case ColorBoxMode.HV_S:
+                    sideSlider.UpdateTexture(new Color(colHue, 0, MathEx.Max(colValue, 0.2f), 1), new Color(0, 1, 0, 0), true);
+                    break;
+                case ColorBoxMode.HS_V:
+                    sideSlider.UpdateTexture(new Color(colHue, colSaturation, 0, 1), new Color(0, 0, 1, 0), true);
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Generates textures for the color box and the side slider depending on active color box mode.
+        /// </summary>
+        void Update2DSliderTextures()
+        {
+            UpdateSideSliderTexture();
+
+            float[] valueLookup = new float[] { colRed, colGreen, colBlue, colHue, colSaturation, colValue };
+            colorBox.UpdateTexture(colorBoxMode, valueLookup[(int)colorBoxMode]);
+        }
+
+        /// <summary>
+        /// Manages GUI for a 1D horizontal slider (used RGB/HSV display).
+        /// </summary>
+        public class ColorSlider1DHorz
+        {
+            private const int SLIDER_X_OFFSET = 3;
+            private const int SLIDER_Y_OFFSET = 5;
+
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUISliderH guiSlider;
+
+            /// <summary>
+            /// Creates a new horizontal slider.
+            /// </summary>
+            /// <param name="guiTexture">GUI element to display the slider color range on.</param>
+            /// <param name="guiSlider">Slider rendered on top of the texture that may be moved by the user to select a 
+            ///                         color.</param>
+            /// <param name="width">Width of the slider in pixels.</param>
+            /// <param name="height">Height of the slider in pixels.</param>
+            public ColorSlider1DHorz(GUITexture guiTexture, GUISliderH guiSlider, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+                this.guiTexture = guiTexture;
+                this.guiSlider = guiSlider;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            /// <summary>
+            /// Updates the displayed texture with specified color information.
+            /// </summary>
+            /// <param name="start">Initial color on the left of the slider.</param>
+            /// <param name="step">Final color to the right of the slider.</param>
+            /// <param name="isHSV">Determines are the provided colors in RGB or HSV space.</param>
+            public void UpdateTexture(Color start, Color step, bool isHSV)
+            {
+                Color[] colors = new Color[width * height];
+                FillArea(width, height, colors, start, step, new Color(0, 0, 0, 0));
+
+                if (isHSV)
+                {
+                    for (int i = 0; i < colors.Length; i++)
+                        colors[i] = Color.HSV2RGB(colors[i]);
+                }
+
+                texture.SetPixels(colors);
+                guiTexture.SetTexture(spriteTexture);
+
+                Rect2I sliderBounds = guiTexture.Bounds;
+                sliderBounds.x -= SLIDER_X_OFFSET;
+                sliderBounds.width += SLIDER_X_OFFSET * 2;
+                sliderBounds.y -= SLIDER_Y_OFFSET;
+                sliderBounds.height += SLIDER_Y_OFFSET;
+
+                guiSlider.Bounds = sliderBounds;
+            }
+        }
+
+        /// <summary>
+        /// Manages GUI for a 1D vertical slider (side slider along with the color box).
+        /// </summary>
+        public class ColorSlider1DVert
+        {
+            private const int SLIDER_X_OFFSET = 5;
+            private const int SLIDER_Y_OFFSET = 3;
+
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUISliderV guiSlider;
+
+            /// <summary>
+            /// Creates a new vertical slider.
+            /// </summary>
+            /// <param name="guiTexture">GUI element to display the slider color range on.</param>
+            /// <param name="guiSlider">Slider rendered on top of the texture that may be moved by the user to select a 
+            ///                         color.</param>
+            /// <param name="width">Width of the slider in pixels.</param>
+            /// <param name="height">Height of the slider in pixels.</param>
+            public ColorSlider1DVert(GUITexture guiTexture, GUISliderV guiSlider, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+                this.guiTexture = guiTexture;
+                this.guiSlider = guiSlider;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            /// <summary>
+            /// Updates the displayed texture with specified color information.
+            /// </summary>
+            /// <param name="start">Initial color on the top of the slider.</param>
+            /// <param name="step">Final color to the bottom of the slider.</param>
+            /// <param name="isHSV">Determines are the provided colors in RGB or HSV space.</param>
+            public void UpdateTexture(Color start, Color step, bool isHSV)
+            {
+                Color[] colors = new Color[width * height];
+                FillArea(width, height, colors, start, new Color(0, 0, 0, 0), step);
+
+                if (isHSV)
+                {
+                    for (int i = 0; i < colors.Length; i++)
+                        colors[i] = Color.HSV2RGB(colors[i]);
+                }
+
+                texture.SetPixels(colors);
+                guiTexture.SetTexture(spriteTexture);
+
+                Rect2I sliderBounds = guiTexture.Bounds;
+                sliderBounds.x -= SLIDER_X_OFFSET;
+                sliderBounds.width += SLIDER_X_OFFSET;
+                sliderBounds.y -= SLIDER_Y_OFFSET;
+                sliderBounds.height += SLIDER_Y_OFFSET * 2;
+
+                guiSlider.Bounds = sliderBounds;
+            }
+        }
+
+        /// <summary>
+        /// Manages GUI for a 2D color box, as well as manually handling color box input. Color box serves as a 2D sliders 
+        /// as you can portion of it to select a color.
+        /// </summary>
+        public class ColorSlider2D
+        {
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUITexture guiSliderHandle;
+
+            private Vector2 oldValue = new Vector2(-1, -1);
+
+            public delegate void OnValueChangedDelegate(Vector2 value);
+            public event OnValueChangedDelegate OnValueChanged;
+
+            /// <summary>
+            /// Creates a new color box.
+            /// </summary>
+            /// <param name="guiTexture">GUI element to display the 2D color range on.</param>
+            /// <param name="guiSliderHandle">Texture to be used for displaying the position of the currently selected 
+            ///                               color.</param>
+            /// <param name="width">Width of the slider in pixels.</param>
+            /// <param name="height">Height of the slider in pixels.</param>
+            public ColorSlider2D(GUITexture guiTexture, GUITexture guiSliderHandle, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+
+                this.guiTexture = guiTexture;
+                this.guiSliderHandle = guiSliderHandle;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            /// <summary>
+            /// Updates the texture displayed on the color box.
+            /// </summary>
+            /// <param name="mode">Mode determining the color gamut shown in the color box.</param>
+            /// <param name="value">Value of the third component (normally retrieved from the separate side slider).</param>
+            public void UpdateTexture(ColorBoxMode mode, float value)
+            {
+                Color[] colors = new Color[width * height];
+
+                switch (mode)
+                {
+                    case ColorBoxMode.BG_R:
+                        FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 0, 1, 0), new Color(0, 1, 0, 0));
+                        break;
+                    case ColorBoxMode.BR_G:
+                        FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(0, 0, 1, 0), new Color(1, 0, 0, 0));
+                        break;
+                    case ColorBoxMode.RG_B:
+                        FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0));
+                        break;
+                    case ColorBoxMode.SV_H:
+                        FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 1, 0, 0), new Color(0, 0, 1, 0));
+                        for (int i = 0; i < colors.Length; i++)
+                            colors[i] = Color.HSV2RGB(colors[i]);
+                        break;
+                    case ColorBoxMode.HV_S:
+                        FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(1, 0, 0, 0), new Color(0, 0, 1, 0));
+                        for (int i = 0; i < colors.Length; i++)
+                            colors[i] = Color.HSV2RGB(colors[i]);
+                        break;
+                    case ColorBoxMode.HS_V:
+                        FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0));
+                        for (int i = 0; i < colors.Length; i++)
+                            colors[i] = Color.HSV2RGB(colors[i]);
+                        break;
+                }
+
+                texture.SetPixels(colors);
+                guiTexture.SetTexture(spriteTexture);
+            }
+
+            /// <summary>
+            /// Handles input over the color box, moving the handle as needed.
+            /// </summary>
+            /// <param name="windowPos">Position of the pointer relative to the color picker window.</param>
+            public void UpdateInput(Vector2I windowPos)
+            {
+                if (Input.IsPointerButtonHeld(PointerButton.Left))
+                {
+                    Rect2I bounds = guiTexture.Bounds;
+
+                    if (bounds.Contains(windowPos))
+                    {
+                        Vector2 newValue = Vector2.Zero;
+                        newValue.x = (windowPos.x - bounds.x) / (float)bounds.width;
+                        newValue.y = 1.0f - (windowPos.y - bounds.y) / (float)bounds.height;
+
+                        SetValue(newValue);
+                    }
+                }
+            }
+
+            /// <summary>
+            /// Moves the handle to a specific location on the color box and selects that color.
+            /// </summary>
+            /// <param name="value">Coordinates relative to the color box.</param>
+            public void SetValue(Vector2 value)
+            {
+                Vector2 pos = value;
+                pos.y = 1.0f - pos.y;
+
+                if (oldValue == value)
+                    return;
+
+                Rect2I handleBounds = guiSliderHandle.Bounds;
+                Rect2I boxBounds = guiTexture.Bounds;
+
+                handleBounds.x = boxBounds.x + MathEx.RoundToInt(pos.x * boxBounds.width) - handleBounds.width / 2;
+                handleBounds.y = boxBounds.y + MathEx.RoundToInt(pos.y * boxBounds.height) - handleBounds.height / 2;
+
+                guiSliderHandle.Bounds = handleBounds;
+                oldValue = value;
+
+                if (OnValueChanged != null)
+                    OnValueChanged(value);
+            }
+        }
+    }
+}

+ 1 - 1
Source/MBansheeEditor/Inspector/InspectorWindow.cs

@@ -517,7 +517,7 @@ namespace BansheeEditor
             {
                 if ((DragDrop.DragInProgress || DragDrop.DropInProgress) && DragDrop.Type == DragDropType.Resource)
                 {
-                    Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
+                    Vector2I windowPos = ScreenToWindowPos(Input.PointerScreenPosition);
                     Vector2I scrollPos = windowPos;
                     Rect2I contentBounds = inspectorLayout.Bounds;
                     scrollPos.x -= contentBounds.x;

+ 5 - 2
Source/MBansheeEditor/Inspectors/BoxColliderInspector.cs

@@ -63,8 +63,11 @@ namespace BansheeEditor
         /// <param name="collider">Collider to update the GUI from.</param>
         protected void Refresh(BoxCollider collider)
         {
-            centerField.Value = collider.Center;
-            extentsField.Value = collider.Extents;
+            if (!centerField.HasInputFocus)
+                centerField.Value = collider.Center;
+
+            if(!extentsField.HasInputFocus)
+                extentsField.Value = collider.Extents;
 
             base.Refresh(collider);
         }

+ 11 - 4
Source/MBansheeEditor/Inspectors/CapsuleColliderInspector.cs

@@ -86,10 +86,17 @@ namespace BansheeEditor
         /// <param name="collider">Collider to update the GUI from.</param>
         protected void Refresh(CapsuleCollider collider)
         {
-            centerField.Value = collider.Center;
-            orientationField.Value = orientation;
-            radiusField.Value = collider.Radius;
-            halfHeightField.Value = collider.HalfHeight;
+            if (!centerField.HasInputFocus)
+                centerField.Value = collider.Center;
+
+            if (!orientationField.HasInputFocus)
+                orientationField.Value = orientation;
+
+            if (!radiusField.HasInputFocus)
+                radiusField.Value = collider.Radius;
+
+            if (!halfHeightField.HasInputFocus)
+                halfHeightField.Value = collider.HalfHeight;
 
             base.Refresh(collider);
         }

+ 5 - 2
Source/MBansheeEditor/Inspectors/PlaneColliderInspector.cs

@@ -73,8 +73,11 @@ namespace BansheeEditor
         /// <param name="collider">Collider to update the GUI from.</param>
         protected void Refresh(PlaneCollider collider)
         {
-            normalField.Value = normal;
-            distanceField.Value = collider.Distance;
+            if (!normalField.HasInputFocus)
+                normalField.Value = normal;
+
+            if (!distanceField.HasInputFocus)
+                distanceField.Value = collider.Distance;
 
             base.Refresh(collider);
         }

+ 5 - 2
Source/MBansheeEditor/Inspectors/SphereColliderInspector.cs

@@ -63,8 +63,11 @@ namespace BansheeEditor
         /// <param name="collider">Collider to update the GUI from.</param>
         protected void Refresh(SphereCollider collider)
         {
-            centerField.Value = collider.Center;
-            radiusField.Value = collider.Radius;
+            if (!centerField.HasInputFocus)
+                centerField.Value = collider.Center;
+
+            if (!radiusField.HasInputFocus)
+                radiusField.Value = collider.Radius;
 
             base.Refresh(collider);
         }

+ 1 - 1
Source/MBansheeEditor/Library/LibraryDropTarget.cs

@@ -151,7 +151,7 @@ namespace BansheeEditor
         /// </summary>
         public void Update()
         {
-            Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(Input.PointerPosition);
+            Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(Input.PointerScreenPosition);
 
             if (triggerStartLocalDrag)
             {

+ 512 - 512
Source/MBansheeEditor/Scene/SceneCamera.cs

@@ -1,512 +1,512 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Handles camera movement in the scene view.
-    /// </summary>
-    [RunInEditor]
-    internal sealed class SceneCamera : Component
-    {
-        #region Constants
-        public const string MoveForwardBinding = "SceneForward";
-	    public const string MoveLeftBinding = "SceneLeft";
-	    public const string MoveRightBinding = "SceneRight";
-	    public const string MoveBackBinding = "SceneBackward";
-        public const string MoveUpBinding = "SceneUp";
-        public const string MoveDownBinding = "SceneDown";
-        public const string FastMoveBinding = "SceneFastMove";
-        public const string PanBinding = "ScenePan";
-        public const string RotateBinding = "SceneRotate";
-	    public const string HorizontalAxisBinding = "SceneHorizontal";
-	    public const string VerticalAxisBinding = "SceneVertical";
-        public const string ScrollAxisBinding = "SceneScroll";
-
-        private const float StartSpeed = 4.0f;
-	    private const float TopSpeed = 12.0f;
-	    private const float Acceleration = 1.0f;
-	    private const float FastModeMultiplier = 2.0f;
-        private const float PanSpeed = 3.0f;
-        private const float ScrollSpeed = 3.0f;
-	    private const float RotationalSpeed = 360.0f; // Degrees/second
-        private readonly Degree FieldOfView = (Degree)90.0f;
-        #endregion
-
-        #region Fields
-        private VirtualButton moveForwardBtn;
-        private VirtualButton moveLeftBtn;
-        private VirtualButton moveRightBtn;
-        private VirtualButton moveBackwardBtn;
-        private VirtualButton moveUpBtn;
-        private VirtualButton moveDownBtn;
-        private VirtualButton fastMoveBtn;
-        private VirtualButton activeBtn;
-        private VirtualButton panBtn;
-        private VirtualAxis horizontalAxis;
-        private VirtualAxis verticalAxis;
-        private VirtualAxis scrollAxis;
-
-        private float currentSpeed;
-        private Degree yaw;
-        private Degree pitch;
-        private bool lastButtonState;
-        private Camera camera;
-        private bool inputEnabled = true;
-
-        // Animating camera transitions
-        private CameraAnimation animation = new CameraAnimation();
-        private float frustumWidth = 50.0f;
-        private float lerp;
-        private bool isAnimating;
-        #endregion
-
-        #region Public properties
-        /// <summary>
-        /// Type of projection used by camera for rendering the scene.
-        /// </summary>
-        public ProjectionType ProjectionType
-        {
-            get { return camera.ProjectionType; }
-            set
-            {
-                if (camera.ProjectionType != value)
-                {
-                    CameraState state = new CameraState();
-                    state.Position = camera.SceneObject.Position;
-                    state.Rotation = camera.SceneObject.Rotation;
-                    state.Ortographic = value == ProjectionType.Orthographic;
-                    state.FrustumWidth = frustumWidth;
-
-                    SetState(state);
-                }
-            }
-        }
-        #endregion
-
-        #region Public methods
-        /// <summary>
-        /// Enables or disables camera controls.
-        /// </summary>
-        /// <param name="enable">True to enable controls, false to disable.</param>
-        public void EnableInput(bool enable)
-        {
-            inputEnabled = enable;
-        }
-
-        /// <summary>
-        /// Focuses the camera on the currently selected object(s).
-        /// </summary>
-        public void FrameSelected()
-        {
-            SceneObject[] selectedObjects = Selection.SceneObjects;
-            if (selectedObjects.Length > 0)
-            {
-                AABox box = EditorUtility.CalculateBounds(Selection.SceneObjects);
-                FrameBounds(box);
-            }
-        }
-
-        /// <summary>
-        /// Orients the camera so it looks along the provided axis.
-        /// </summary>
-        public void LookAlong(Vector3 axis)
-        {
-            Vector3 up = Vector3.YAxis;
-            if (MathEx.Abs(Vector3.Dot(axis, up)) > 0.9f)
-                up = Vector3.ZAxis;
-
-            CameraState state = new CameraState();
-            state.Position = camera.SceneObject.Position;
-            state.Rotation = Quaternion.LookRotation(axis, up);
-            state.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
-            state.FrustumWidth = frustumWidth;
-
-            SetState(state);
-        }
-
-        #endregion
-
-        #region Private methods
-        private void OnReset()
-        {
-            camera = SceneObject.GetComponent<Camera>();
-
-            moveForwardBtn = new VirtualButton(MoveForwardBinding);
-            moveLeftBtn = new VirtualButton(MoveLeftBinding);
-            moveRightBtn = new VirtualButton(MoveRightBinding);
-            moveBackwardBtn = new VirtualButton(MoveBackBinding);
-            moveUpBtn = new VirtualButton(MoveUpBinding);
-            moveDownBtn = new VirtualButton(MoveDownBinding);
-            fastMoveBtn = new VirtualButton(FastMoveBinding);
-            activeBtn = new VirtualButton(RotateBinding);
-            panBtn = new VirtualButton(PanBinding);
-            horizontalAxis = new VirtualAxis(HorizontalAxisBinding);
-            verticalAxis = new VirtualAxis(VerticalAxisBinding);
-            scrollAxis = new VirtualAxis(ScrollAxisBinding);
-        }
-
-        private void OnUpdate()
-        {
-            bool isOrtographic = camera.ProjectionType == ProjectionType.Orthographic;
-
-            if (inputEnabled)
-            {
-                bool goingForward = VirtualInput.IsButtonHeld(moveForwardBtn);
-                bool goingBack = VirtualInput.IsButtonHeld(moveBackwardBtn);
-                bool goingLeft = VirtualInput.IsButtonHeld(moveLeftBtn);
-                bool goingRight = VirtualInput.IsButtonHeld(moveRightBtn);
-                bool goingUp = VirtualInput.IsButtonHeld(moveUpBtn);
-                bool goingDown = VirtualInput.IsButtonHeld(moveDownBtn);
-                bool fastMove = VirtualInput.IsButtonHeld(fastMoveBtn);
-                bool camActive = VirtualInput.IsButtonHeld(activeBtn);
-                bool isPanning = VirtualInput.IsButtonHeld(panBtn);
-
-                bool hideCursor = camActive || isPanning;
-                if (hideCursor != lastButtonState)
-                {
-                    if (hideCursor)
-                    {
-                        Cursor.Hide();
-
-                        Rect2I clipRect;
-                        clipRect.x = Input.PointerPosition.x - 2;
-                        clipRect.y = Input.PointerPosition.y - 2;
-                        clipRect.width = 4;
-                        clipRect.height = 4;
-
-                        Cursor.ClipToRect(clipRect);
-                    }
-                    else
-                    {
-                        Cursor.Show();
-                        Cursor.ClipDisable();
-                    }
-
-                    lastButtonState = hideCursor;
-                }
-
-                float frameDelta = Time.FrameDelta;
-                if (camActive)
-                {
-                    float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
-                    float vertValue = VirtualInput.GetAxisValue(verticalAxis);
-
-                    float rotationAmount = RotationalSpeed * EditorSettings.MouseSensitivity * frameDelta;
-
-                    yaw += new Degree(horzValue * rotationAmount);
-                    pitch += new Degree(vertValue * rotationAmount);
-
-                    yaw = MathEx.WrapAngle(yaw);
-                    pitch = MathEx.WrapAngle(pitch);
-
-                    Quaternion yRot = Quaternion.FromAxisAngle(Vector3.YAxis, yaw);
-                    Quaternion xRot = Quaternion.FromAxisAngle(Vector3.XAxis, pitch);
-
-                    Quaternion camRot = yRot*xRot;
-                    camRot.Normalize();
-
-                    SceneObject.Rotation = camRot;
-
-                    // Handle movement using movement keys
-                    Vector3 direction = Vector3.Zero;
-
-                    if (goingForward) direction += SceneObject.Forward;
-                    if (goingBack) direction -= SceneObject.Forward;
-                    if (goingRight) direction += SceneObject.Right;
-                    if (goingLeft) direction -= SceneObject.Right;
-                    if (goingUp) direction += SceneObject.Up;
-                    if (goingDown) direction -= SceneObject.Up;
-
-                    if (direction.SqrdLength != 0)
-                    {
-                        direction.Normalize();
-
-                        float multiplier = 1.0f;
-                        if (fastMove)
-                            multiplier = FastModeMultiplier;
-
-                        currentSpeed = MathEx.Clamp(currentSpeed + Acceleration*frameDelta, StartSpeed, TopSpeed);
-                        currentSpeed *= multiplier;
-                    }
-                    else
-                    {
-                        currentSpeed = 0.0f;
-                    }
-
-                    const float tooSmall = 0.0001f;
-                    if (currentSpeed > tooSmall)
-                    {
-                        Vector3 velocity = direction*currentSpeed;
-                        SceneObject.Move(velocity*frameDelta);
-                    }
-                }
-
-                // Pan
-                if (isPanning)
-                {
-                    float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
-                    float vertValue = VirtualInput.GetAxisValue(verticalAxis);
-
-                    Vector3 direction = new Vector3(horzValue, -vertValue, 0.0f);
-                    direction = camera.SceneObject.Rotation.Rotate(direction);
-
-                    SceneObject.Move(direction*PanSpeed*frameDelta);
-                }
-            }
-            else
-            {
-                Cursor.Show();
-                Cursor.ClipDisable();
-            }
-
-            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
-            if (sceneWindow.Active)
-            {
-                Rect2I bounds = sceneWindow.Bounds;
-
-                // Move using scroll wheel
-                if (bounds.Contains(Input.PointerPosition))
-                {
-                    float scrollAmount = VirtualInput.GetAxisValue(scrollAxis);
-                    if (!isOrtographic)
-                    {
-                        SceneObject.Move(SceneObject.Forward*scrollAmount*ScrollSpeed);
-                    }
-                    else
-                    {
-                        float orthoHeight = MathEx.Max(1.0f, camera.OrthoHeight - scrollAmount);
-                        camera.OrthoHeight = orthoHeight;
-                    }
-                }
-            }
-
-            UpdateAnim();
-        }
-
-        /// <summary>
-        /// Moves and orients a camera so that the provided bounds end covering the camera's viewport.
-        /// </summary>
-        /// <param name="bounds">Bounds to frame in camera's view.</param>
-        /// <param name="padding">Amount of padding to leave on the borders of the viewport, in percent [0, 1].</param>
-        private void FrameBounds(AABox bounds, float padding = 0.0f)
-        {
-            // TODO - Use AABox bounds directly instead of a sphere to be more accurate
-            float worldWidth = bounds.Size.Length;
-            float worldHeight = worldWidth;
-
-            if (worldWidth == 0.0f)
-                worldWidth = 1.0f;
-
-            if (worldHeight == 0.0f)
-                worldHeight = 1.0f;
-
-            float boundsAspect = worldWidth / worldHeight;
-            float paddingScale = MathEx.Clamp01(padding) + 1.0f;
-            float frustumWidth;
-
-            // If camera has wider aspect than bounds then height will be the limiting dimension
-            if (camera.AspectRatio > boundsAspect)
-                frustumWidth = worldHeight * camera.AspectRatio * paddingScale;
-            else // Otherwise width
-                frustumWidth = worldWidth * paddingScale;
-
-            float distance = CalcDistanceForFrustumWidth(frustumWidth);
-
-            Vector3 forward = bounds.Center - SceneObject.Position;
-            forward.Normalize();
-
-            CameraState state = new CameraState();
-            state.Position = bounds.Center - forward * distance;
-            state.Rotation = Quaternion.LookRotation(forward, Vector3.YAxis);
-            state.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
-            state.FrustumWidth = frustumWidth;
-
-            SetState(state);
-        }
-
-        /// <summary>
-        /// Changes the state of the camera, either instantly or animated over several frames. The state includes
-        /// camera position, rotation, type and possibly other parameters.
-        /// </summary>
-        /// <param name="state">New state of the camera.</param>
-        /// <param name="animated">Should the state be linearly interpolated over a course of several frames.</param>
-        private void SetState(CameraState state, bool animated = true)
-        {
-            CameraState startState = new CameraState();
-
-            startState.Position = SceneObject.Position;
-            startState.Rotation = SceneObject.Rotation;
-            startState.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
-            startState.FrustumWidth = frustumWidth;
-
-            animation.Start(startState, state);
-            if (!animated)
-            {
-                ApplyState(1.0f);
-
-                isAnimating = false;
-            }
-            else
-            {
-                isAnimating = true;
-                lerp = 0.0f;
-            }
-        }
-
-        /// <summary>
-        /// Applies the animation target state depending on the interpolation parameter. <see cref="SetState"/>.
-        /// </summary>
-        /// <param name="t">Interpolation parameter ranging [0, 1] that interpolated between the start state and the
-        ///                 target state.</param>
-        private void ApplyState(float t)
-        {
-            animation.Update(t);
-
-            SceneObject.Position = animation.State.Position;
-            SceneObject.Rotation = animation.State.Rotation;
-            frustumWidth = animation.State.FrustumWidth;
-
-            Vector3 eulerAngles = SceneObject.Rotation.ToEuler();
-            pitch = (Degree)eulerAngles.x;
-            yaw = (Degree)eulerAngles.y;
-
-            Degree FOV = (Degree)(1.0f - animation.State.OrtographicPct)*FieldOfView;
-            if (FOV < (Degree)5.0f)
-            {
-                camera.ProjectionType = ProjectionType.Orthographic;
-                camera.OrthoHeight = frustumWidth * 0.5f / camera.AspectRatio;
-            }
-            else
-            {
-                camera.ProjectionType = ProjectionType.Perspective;
-                camera.FieldOfView = FOV;
-            }
-
-            // Note: Consider having a global setting for near/far planes as changing it here might confuse the user
-            float distance = CalcDistanceForFrustumWidth(frustumWidth);
-            if (distance < 1)
-            {
-                camera.NearClipPlane = 0.005f;
-                camera.FarClipPlane = 1000f;
-            }
-            if (distance < 100)
-            {
-                camera.NearClipPlane = 0.05f;
-                camera.FarClipPlane = 2500f;
-            }
-            else if (distance < 1000)
-            {
-                camera.NearClipPlane = 0.5f;
-                camera.FarClipPlane = 10000f;
-            }
-            else
-            {
-                camera.NearClipPlane = 5.0f;
-                camera.FarClipPlane = 1000000f;
-            }
-        }
-
-        /// <summary>
-        /// Calculates distance at which the camera's frustum width is equal to the provided width.
-        /// </summary>
-        /// <param name="frustumWidth">Frustum width to find the distance for, in world units.</param>
-        /// <returns>Distance at which the camera's frustum is the specified width, in world units.</returns>
-        private float CalcDistanceForFrustumWidth(float frustumWidth)
-        {
-            if (camera.ProjectionType == ProjectionType.Perspective)
-                return (frustumWidth*0.5f)/MathEx.Tan(camera.FieldOfView*0.5f);
-            else
-                return frustumWidth * 2.0f;
-        }
-
-        /// <summary>
-        /// Updates camera state transition animation. Should be called every frame.
-        /// </summary>
-        private void UpdateAnim()
-        {
-            if (!isAnimating)
-                return;
-
-            const float ANIM_TIME = 0.5f; // 0.5f seconds
-            lerp += Time.FrameDelta * (1.0f / ANIM_TIME);
-
-            if (lerp >= 1.0f)
-            {
-                lerp = 1.0f;
-                isAnimating = false;
-            }
-
-            ApplyState(lerp);
-        }
-
-        /// <summary>
-        /// Contains data for a possible camera state. Camera states can be interpolated between each other as needed.
-        /// </summary>
-        private struct CameraState
-        {
-            private float _ortographic;
-
-            public Vector3 Position { get; set; }
-            public Quaternion Rotation { get; set; }
-            public float FrustumWidth { get; set; }
-
-            public bool Ortographic
-            {
-                get { return _ortographic > 0.5; }
-                set { _ortographic = value ? 1.0f : 0.0f; }
-            }
-
-            public float OrtographicPct
-            {
-                get { return _ortographic; }
-                set { _ortographic = value; }
-            }
-        }
-
-        /// <summary>
-        /// Helper class that performs linear interpolation between two camera states.
-        /// </summary>
-        private struct CameraAnimation
-        {
-            private CameraState start;
-            private CameraState target;
-            private CameraState interpolated;
-
-            /// <summary>
-            /// Returns currently interpolated animation state.
-            /// </summary>
-            public CameraState State
-            {
-                get { return interpolated; }
-            }
-
-            /// <summary>
-            /// Initializes the animation with initial and target states.
-            /// </summary>
-            /// <param name="start">Initial state to animate from.</param>
-            /// <param name="target">Target state to animate towards.</param>
-            public void Start(CameraState start, CameraState target)
-            {
-                this.start = start;
-                this.target = target;
-            }
-
-            /// <summary>
-            /// Updates the animation by interpolating between the start and target states.
-            /// </summary>
-            /// <param name="t">Interpolation parameter in range [0, 1] that determines how much to interpolate between
-            ///                 start and target states.</param>
-            public void Update(float t)
-            {
-                interpolated.Position = start.Position * (1.0f - t) + target.Position * t;
-                interpolated.Rotation = Quaternion.Slerp(start.Rotation, target.Rotation, t);
-                interpolated.OrtographicPct = start.OrtographicPct * (1.0f - t) + target.OrtographicPct * t;
-
-                interpolated.FrustumWidth = start.FrustumWidth * (1.0f - t) + target.FrustumWidth * t;
-            }
-        };
-        #endregion 
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Handles camera movement in the scene view.
+    /// </summary>
+    [RunInEditor]
+    internal sealed class SceneCamera : Component
+    {
+        #region Constants
+        public const string MoveForwardBinding = "SceneForward";
+	    public const string MoveLeftBinding = "SceneLeft";
+	    public const string MoveRightBinding = "SceneRight";
+	    public const string MoveBackBinding = "SceneBackward";
+        public const string MoveUpBinding = "SceneUp";
+        public const string MoveDownBinding = "SceneDown";
+        public const string FastMoveBinding = "SceneFastMove";
+        public const string PanBinding = "ScenePan";
+        public const string RotateBinding = "SceneRotate";
+	    public const string HorizontalAxisBinding = "SceneHorizontal";
+	    public const string VerticalAxisBinding = "SceneVertical";
+        public const string ScrollAxisBinding = "SceneScroll";
+
+        private const float StartSpeed = 4.0f;
+	    private const float TopSpeed = 12.0f;
+	    private const float Acceleration = 1.0f;
+	    private const float FastModeMultiplier = 2.0f;
+        private const float PanSpeed = 3.0f;
+        private const float ScrollSpeed = 3.0f;
+	    private const float RotationalSpeed = 360.0f; // Degrees/second
+        private readonly Degree FieldOfView = (Degree)90.0f;
+        #endregion
+
+        #region Fields
+        private VirtualButton moveForwardBtn;
+        private VirtualButton moveLeftBtn;
+        private VirtualButton moveRightBtn;
+        private VirtualButton moveBackwardBtn;
+        private VirtualButton moveUpBtn;
+        private VirtualButton moveDownBtn;
+        private VirtualButton fastMoveBtn;
+        private VirtualButton activeBtn;
+        private VirtualButton panBtn;
+        private VirtualAxis horizontalAxis;
+        private VirtualAxis verticalAxis;
+        private VirtualAxis scrollAxis;
+
+        private float currentSpeed;
+        private Degree yaw;
+        private Degree pitch;
+        private bool lastButtonState;
+        private Camera camera;
+        private bool inputEnabled = true;
+
+        // Animating camera transitions
+        private CameraAnimation animation = new CameraAnimation();
+        private float frustumWidth = 50.0f;
+        private float lerp;
+        private bool isAnimating;
+        #endregion
+
+        #region Public properties
+        /// <summary>
+        /// Type of projection used by camera for rendering the scene.
+        /// </summary>
+        public ProjectionType ProjectionType
+        {
+            get { return camera.ProjectionType; }
+            set
+            {
+                if (camera.ProjectionType != value)
+                {
+                    CameraState state = new CameraState();
+                    state.Position = camera.SceneObject.Position;
+                    state.Rotation = camera.SceneObject.Rotation;
+                    state.Ortographic = value == ProjectionType.Orthographic;
+                    state.FrustumWidth = frustumWidth;
+
+                    SetState(state);
+                }
+            }
+        }
+        #endregion
+
+        #region Public methods
+        /// <summary>
+        /// Enables or disables camera controls.
+        /// </summary>
+        /// <param name="enable">True to enable controls, false to disable.</param>
+        public void EnableInput(bool enable)
+        {
+            inputEnabled = enable;
+        }
+
+        /// <summary>
+        /// Focuses the camera on the currently selected object(s).
+        /// </summary>
+        public void FrameSelected()
+        {
+            SceneObject[] selectedObjects = Selection.SceneObjects;
+            if (selectedObjects.Length > 0)
+            {
+                AABox box = EditorUtility.CalculateBounds(Selection.SceneObjects);
+                FrameBounds(box);
+            }
+        }
+
+        /// <summary>
+        /// Orients the camera so it looks along the provided axis.
+        /// </summary>
+        public void LookAlong(Vector3 axis)
+        {
+            Vector3 up = Vector3.YAxis;
+            if (MathEx.Abs(Vector3.Dot(axis, up)) > 0.9f)
+                up = Vector3.ZAxis;
+
+            CameraState state = new CameraState();
+            state.Position = camera.SceneObject.Position;
+            state.Rotation = Quaternion.LookRotation(axis, up);
+            state.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
+            state.FrustumWidth = frustumWidth;
+
+            SetState(state);
+        }
+
+        #endregion
+
+        #region Private methods
+        private void OnReset()
+        {
+            camera = SceneObject.GetComponent<Camera>();
+
+            moveForwardBtn = new VirtualButton(MoveForwardBinding);
+            moveLeftBtn = new VirtualButton(MoveLeftBinding);
+            moveRightBtn = new VirtualButton(MoveRightBinding);
+            moveBackwardBtn = new VirtualButton(MoveBackBinding);
+            moveUpBtn = new VirtualButton(MoveUpBinding);
+            moveDownBtn = new VirtualButton(MoveDownBinding);
+            fastMoveBtn = new VirtualButton(FastMoveBinding);
+            activeBtn = new VirtualButton(RotateBinding);
+            panBtn = new VirtualButton(PanBinding);
+            horizontalAxis = new VirtualAxis(HorizontalAxisBinding);
+            verticalAxis = new VirtualAxis(VerticalAxisBinding);
+            scrollAxis = new VirtualAxis(ScrollAxisBinding);
+        }
+
+        private void OnUpdate()
+        {
+            bool isOrtographic = camera.ProjectionType == ProjectionType.Orthographic;
+
+            if (inputEnabled)
+            {
+                bool goingForward = VirtualInput.IsButtonHeld(moveForwardBtn);
+                bool goingBack = VirtualInput.IsButtonHeld(moveBackwardBtn);
+                bool goingLeft = VirtualInput.IsButtonHeld(moveLeftBtn);
+                bool goingRight = VirtualInput.IsButtonHeld(moveRightBtn);
+                bool goingUp = VirtualInput.IsButtonHeld(moveUpBtn);
+                bool goingDown = VirtualInput.IsButtonHeld(moveDownBtn);
+                bool fastMove = VirtualInput.IsButtonHeld(fastMoveBtn);
+                bool camActive = VirtualInput.IsButtonHeld(activeBtn);
+                bool isPanning = VirtualInput.IsButtonHeld(panBtn);
+
+                bool hideCursor = camActive || isPanning;
+                if (hideCursor != lastButtonState)
+                {
+                    if (hideCursor)
+                    {
+                        Cursor.Hide();
+
+                        Rect2I clipRect;
+                        clipRect.x = Input.PointerScreenPosition.x - 2;
+                        clipRect.y = Input.PointerScreenPosition.y - 2;
+                        clipRect.width = 4;
+                        clipRect.height = 4;
+
+                        Cursor.ClipToRect(clipRect);
+                    }
+                    else
+                    {
+                        Cursor.Show();
+                        Cursor.ClipDisable();
+                    }
+
+                    lastButtonState = hideCursor;
+                }
+
+                float frameDelta = Time.FrameDelta;
+                if (camActive)
+                {
+                    float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
+                    float vertValue = VirtualInput.GetAxisValue(verticalAxis);
+
+                    float rotationAmount = RotationalSpeed * EditorSettings.MouseSensitivity * frameDelta;
+
+                    yaw += new Degree(horzValue * rotationAmount);
+                    pitch += new Degree(vertValue * rotationAmount);
+
+                    yaw = MathEx.WrapAngle(yaw);
+                    pitch = MathEx.WrapAngle(pitch);
+
+                    Quaternion yRot = Quaternion.FromAxisAngle(Vector3.YAxis, yaw);
+                    Quaternion xRot = Quaternion.FromAxisAngle(Vector3.XAxis, pitch);
+
+                    Quaternion camRot = yRot*xRot;
+                    camRot.Normalize();
+
+                    SceneObject.Rotation = camRot;
+
+                    // Handle movement using movement keys
+                    Vector3 direction = Vector3.Zero;
+
+                    if (goingForward) direction += SceneObject.Forward;
+                    if (goingBack) direction -= SceneObject.Forward;
+                    if (goingRight) direction += SceneObject.Right;
+                    if (goingLeft) direction -= SceneObject.Right;
+                    if (goingUp) direction += SceneObject.Up;
+                    if (goingDown) direction -= SceneObject.Up;
+
+                    if (direction.SqrdLength != 0)
+                    {
+                        direction.Normalize();
+
+                        float multiplier = 1.0f;
+                        if (fastMove)
+                            multiplier = FastModeMultiplier;
+
+                        currentSpeed = MathEx.Clamp(currentSpeed + Acceleration*frameDelta, StartSpeed, TopSpeed);
+                        currentSpeed *= multiplier;
+                    }
+                    else
+                    {
+                        currentSpeed = 0.0f;
+                    }
+
+                    const float tooSmall = 0.0001f;
+                    if (currentSpeed > tooSmall)
+                    {
+                        Vector3 velocity = direction*currentSpeed;
+                        SceneObject.Move(velocity*frameDelta);
+                    }
+                }
+
+                // Pan
+                if (isPanning)
+                {
+                    float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
+                    float vertValue = VirtualInput.GetAxisValue(verticalAxis);
+
+                    Vector3 direction = new Vector3(horzValue, -vertValue, 0.0f);
+                    direction = camera.SceneObject.Rotation.Rotate(direction);
+
+                    SceneObject.Move(direction*PanSpeed*frameDelta);
+                }
+            }
+            else
+            {
+                Cursor.Show();
+                Cursor.ClipDisable();
+            }
+
+            SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
+            if (sceneWindow.Active)
+            {
+                Rect2I bounds = sceneWindow.Bounds;
+
+                // Move using scroll wheel
+                if (bounds.Contains(Input.PointerScreenPosition))
+                {
+                    float scrollAmount = VirtualInput.GetAxisValue(scrollAxis);
+                    if (!isOrtographic)
+                    {
+                        SceneObject.Move(SceneObject.Forward*scrollAmount*ScrollSpeed);
+                    }
+                    else
+                    {
+                        float orthoHeight = MathEx.Max(1.0f, camera.OrthoHeight - scrollAmount);
+                        camera.OrthoHeight = orthoHeight;
+                    }
+                }
+            }
+
+            UpdateAnim();
+        }
+
+        /// <summary>
+        /// Moves and orients a camera so that the provided bounds end covering the camera's viewport.
+        /// </summary>
+        /// <param name="bounds">Bounds to frame in camera's view.</param>
+        /// <param name="padding">Amount of padding to leave on the borders of the viewport, in percent [0, 1].</param>
+        private void FrameBounds(AABox bounds, float padding = 0.0f)
+        {
+            // TODO - Use AABox bounds directly instead of a sphere to be more accurate
+            float worldWidth = bounds.Size.Length;
+            float worldHeight = worldWidth;
+
+            if (worldWidth == 0.0f)
+                worldWidth = 1.0f;
+
+            if (worldHeight == 0.0f)
+                worldHeight = 1.0f;
+
+            float boundsAspect = worldWidth / worldHeight;
+            float paddingScale = MathEx.Clamp01(padding) + 1.0f;
+            float frustumWidth;
+
+            // If camera has wider aspect than bounds then height will be the limiting dimension
+            if (camera.AspectRatio > boundsAspect)
+                frustumWidth = worldHeight * camera.AspectRatio * paddingScale;
+            else // Otherwise width
+                frustumWidth = worldWidth * paddingScale;
+
+            float distance = CalcDistanceForFrustumWidth(frustumWidth);
+
+            Vector3 forward = bounds.Center - SceneObject.Position;
+            forward.Normalize();
+
+            CameraState state = new CameraState();
+            state.Position = bounds.Center - forward * distance;
+            state.Rotation = Quaternion.LookRotation(forward, Vector3.YAxis);
+            state.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
+            state.FrustumWidth = frustumWidth;
+
+            SetState(state);
+        }
+
+        /// <summary>
+        /// Changes the state of the camera, either instantly or animated over several frames. The state includes
+        /// camera position, rotation, type and possibly other parameters.
+        /// </summary>
+        /// <param name="state">New state of the camera.</param>
+        /// <param name="animated">Should the state be linearly interpolated over a course of several frames.</param>
+        private void SetState(CameraState state, bool animated = true)
+        {
+            CameraState startState = new CameraState();
+
+            startState.Position = SceneObject.Position;
+            startState.Rotation = SceneObject.Rotation;
+            startState.Ortographic = camera.ProjectionType == ProjectionType.Orthographic;
+            startState.FrustumWidth = frustumWidth;
+
+            animation.Start(startState, state);
+            if (!animated)
+            {
+                ApplyState(1.0f);
+
+                isAnimating = false;
+            }
+            else
+            {
+                isAnimating = true;
+                lerp = 0.0f;
+            }
+        }
+
+        /// <summary>
+        /// Applies the animation target state depending on the interpolation parameter. <see cref="SetState"/>.
+        /// </summary>
+        /// <param name="t">Interpolation parameter ranging [0, 1] that interpolated between the start state and the
+        ///                 target state.</param>
+        private void ApplyState(float t)
+        {
+            animation.Update(t);
+
+            SceneObject.Position = animation.State.Position;
+            SceneObject.Rotation = animation.State.Rotation;
+            frustumWidth = animation.State.FrustumWidth;
+
+            Vector3 eulerAngles = SceneObject.Rotation.ToEuler();
+            pitch = (Degree)eulerAngles.x;
+            yaw = (Degree)eulerAngles.y;
+
+            Degree FOV = (Degree)(1.0f - animation.State.OrtographicPct)*FieldOfView;
+            if (FOV < (Degree)5.0f)
+            {
+                camera.ProjectionType = ProjectionType.Orthographic;
+                camera.OrthoHeight = frustumWidth * 0.5f / camera.AspectRatio;
+            }
+            else
+            {
+                camera.ProjectionType = ProjectionType.Perspective;
+                camera.FieldOfView = FOV;
+            }
+
+            // Note: Consider having a global setting for near/far planes as changing it here might confuse the user
+            float distance = CalcDistanceForFrustumWidth(frustumWidth);
+            if (distance < 1)
+            {
+                camera.NearClipPlane = 0.005f;
+                camera.FarClipPlane = 1000f;
+            }
+            if (distance < 100)
+            {
+                camera.NearClipPlane = 0.05f;
+                camera.FarClipPlane = 2500f;
+            }
+            else if (distance < 1000)
+            {
+                camera.NearClipPlane = 0.5f;
+                camera.FarClipPlane = 10000f;
+            }
+            else
+            {
+                camera.NearClipPlane = 5.0f;
+                camera.FarClipPlane = 1000000f;
+            }
+        }
+
+        /// <summary>
+        /// Calculates distance at which the camera's frustum width is equal to the provided width.
+        /// </summary>
+        /// <param name="frustumWidth">Frustum width to find the distance for, in world units.</param>
+        /// <returns>Distance at which the camera's frustum is the specified width, in world units.</returns>
+        private float CalcDistanceForFrustumWidth(float frustumWidth)
+        {
+            if (camera.ProjectionType == ProjectionType.Perspective)
+                return (frustumWidth*0.5f)/MathEx.Tan(camera.FieldOfView*0.5f);
+            else
+                return frustumWidth * 2.0f;
+        }
+
+        /// <summary>
+        /// Updates camera state transition animation. Should be called every frame.
+        /// </summary>
+        private void UpdateAnim()
+        {
+            if (!isAnimating)
+                return;
+
+            const float ANIM_TIME = 0.5f; // 0.5f seconds
+            lerp += Time.FrameDelta * (1.0f / ANIM_TIME);
+
+            if (lerp >= 1.0f)
+            {
+                lerp = 1.0f;
+                isAnimating = false;
+            }
+
+            ApplyState(lerp);
+        }
+
+        /// <summary>
+        /// Contains data for a possible camera state. Camera states can be interpolated between each other as needed.
+        /// </summary>
+        private struct CameraState
+        {
+            private float _ortographic;
+
+            public Vector3 Position { get; set; }
+            public Quaternion Rotation { get; set; }
+            public float FrustumWidth { get; set; }
+
+            public bool Ortographic
+            {
+                get { return _ortographic > 0.5; }
+                set { _ortographic = value ? 1.0f : 0.0f; }
+            }
+
+            public float OrtographicPct
+            {
+                get { return _ortographic; }
+                set { _ortographic = value; }
+            }
+        }
+
+        /// <summary>
+        /// Helper class that performs linear interpolation between two camera states.
+        /// </summary>
+        private struct CameraAnimation
+        {
+            private CameraState start;
+            private CameraState target;
+            private CameraState interpolated;
+
+            /// <summary>
+            /// Returns currently interpolated animation state.
+            /// </summary>
+            public CameraState State
+            {
+                get { return interpolated; }
+            }
+
+            /// <summary>
+            /// Initializes the animation with initial and target states.
+            /// </summary>
+            /// <param name="start">Initial state to animate from.</param>
+            /// <param name="target">Target state to animate towards.</param>
+            public void Start(CameraState start, CameraState target)
+            {
+                this.start = start;
+                this.target = target;
+            }
+
+            /// <summary>
+            /// Updates the animation by interpolating between the start and target states.
+            /// </summary>
+            /// <param name="t">Interpolation parameter in range [0, 1] that determines how much to interpolate between
+            ///                 start and target states.</param>
+            public void Update(float t)
+            {
+                interpolated.Position = start.Position * (1.0f - t) + target.Position * t;
+                interpolated.Rotation = Quaternion.Slerp(start.Rotation, target.Rotation, t);
+                interpolated.OrtographicPct = start.OrtographicPct * (1.0f - t) + target.OrtographicPct * t;
+
+                interpolated.FrustumWidth = start.FrustumWidth * (1.0f - t) + target.FrustumWidth * t;
+            }
+        };
+        #endregion 
+    }
+}

+ 1 - 1
Source/MBansheeEditor/Scene/SceneWindow.cs

@@ -491,7 +491,7 @@ namespace BansheeEditor
             }
 
             Vector2I scenePos;
-            bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos);
+            bool inBounds = ScreenToScenePos(Input.PointerScreenPosition, out scenePos);
 
             bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress;
             draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource;

+ 17 - 1
Source/MBansheeEngine/Input.cs

@@ -292,7 +292,7 @@ namespace BansheeEngine
         }
 
         /// <summary>
-        /// Returns position of the pointer (for example mouse cursor) relative to the screen.
+        /// Returns position of the pointer (for example mouse cursor) relative to the game window (or viewport).
         /// </summary>
         public static Vector2I PointerPosition
         {
@@ -304,6 +304,19 @@ namespace BansheeEngine
             }
         }
 
+        /// <summary>
+        /// Returns position of the pointer (for example mouse cursor) relative to the screen.
+        /// </summary>
+        public static Vector2I PointerScreenPosition
+        {
+            get
+            {
+                Vector2I value;
+                Internal_GetPointerScreenPosition(out value);
+                return value;
+            }
+        }
+
         /// <summary>
         /// Returns difference between last and current pointer position.
         /// </summary>
@@ -466,6 +479,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetPointerPosition(out Vector2I position);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPointerScreenPosition(out Vector2I position);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetPointerDelta(out Vector2I delta);
     }

+ 676 - 676
Source/MBansheeEngine/Physics/Physics.cs

@@ -1,676 +1,676 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Provides global access to the physics system, including scene queries and global options.
-    /// </summary>
-    public static class Physics
-    {
-        /// <summary>
-        /// Global gravity value for all objects in the scene.
-        /// </summary>
-        public static Vector3 Gravity
-        {
-            get { Vector3 gravity; Internal_GetGravity(out gravity); return gravity; }
-            set { Internal_SetGravity(ref value); }
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="ray">Ray to cast into the scene.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool RayCast(Ray ray, out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if (RayCast(ray.origin, ray.direction, out hit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            return false;
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="origin">Origin of the ray to cast into the scene.</param>
-        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool RayCast(Vector3 origin, Vector3 unitDir, out PhysicsQueryHit hit,
-           ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if(Internal_RayCast(ref origin, ref unitDir, out scriptHit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            hit = new PhysicsQueryHit();
-            return false;
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a box and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="box">Box to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the box.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool BoxCast(AABox box, Quaternion rotation, Vector3 unitDir, out PhysicsQueryHit hit,
-            ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if(Internal_BoxCast(ref box, ref rotation, ref unitDir, out scriptHit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            hit = new PhysicsQueryHit();
-            return false;
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a sphere and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="sphere">Sphere to sweep through the scene.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool SphereCast(Sphere sphere, Vector3 unitDir, out PhysicsQueryHit hit,
-            ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if(Internal_SphereCast(ref sphere, ref unitDir, out scriptHit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            hit = new PhysicsQueryHit();
-            return false;
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a capsule and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="capsule">Capsule to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the capsule.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool CapsuleCast(Capsule capsule, Quaternion rotation, Vector3 unitDir,
-            out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if(Internal_CapsuleCast(ref capsule, ref rotation, ref unitDir, out scriptHit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            hit = new PhysicsQueryHit();
-            return false;
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a convex mesh and returns the closest found hit, if any.
-        /// </summary>
-        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
-        /// <param name="position">Starting position of the mesh.</param>
-        /// <param name="rotation">Orientation of the mesh.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool ConvexCast(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
-            Vector3 unitDir, out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            IntPtr meshPtr = IntPtr.Zero;
-            if (mesh != null)
-                meshPtr = mesh.GetCachedPtr();
-
-            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
-            if(Internal_ConvexCast(meshPtr, ref position, ref rotation, ref unitDir, out scriptHit, layer, max))
-            {
-                ConvertPhysicsQueryHit(ref scriptHit, out hit);
-                return true;
-            }
-
-            hit = new PhysicsQueryHit();
-            return false;
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and returns all found hits.
-        /// </summary>
-        /// <param name="ray">Ray to cast into the scene.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] RayCastAll(Ray ray, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return RayCastAll(ray.origin, ray.direction, layer, max);
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and returns all found hits.
-        /// </summary>
-        /// <param name="origin">Origin of the ray to cast into the scene.</param>
-        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] RayCastAll(Vector3 origin, Vector3 unitDir,
-			ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return ConvertPhysicsQueryHits(Internal_RayCastAll(ref origin, ref unitDir, layer, max));
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a box and returns all found hits.
-        /// </summary>
-        /// <param name="box">Box to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the box.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] BoxCastAll(AABox box, Quaternion rotation,
-            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return ConvertPhysicsQueryHits(Internal_BoxCastAll(ref box, ref rotation, ref unitDir, layer, max));
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a sphere and returns all found hits.
-        /// </summary>
-        /// <param name="sphere">Sphere to sweep through the scene.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] SphereCastAll(Sphere sphere, Vector3 unitDir,
-            ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return ConvertPhysicsQueryHits(Internal_SphereCastAll(ref sphere, ref unitDir, layer, max));
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a capsule and returns all found hits.
-        /// </summary>
-        /// <param name="capsule">Capsule to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the capsule.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] CapsuleCastAll(Capsule capsule, Quaternion rotation,
-            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return ConvertPhysicsQueryHits(Internal_CapsuleCastAll(ref capsule, ref rotation, ref unitDir, layer, max));
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a convex mesh and returns all found hits.
-        /// </summary>
-        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
-        /// <param name="position">Starting position of the mesh.</param>
-        /// <param name="rotation">Orientation of the mesh.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>List of all detected hits.</returns>
-        public static PhysicsQueryHit[] ConvexCastAll(PhysicsMesh mesh, Vector3 position,
-            Quaternion rotation, Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            IntPtr meshPtr = IntPtr.Zero;
-            if (mesh != null)
-                meshPtr = mesh.GetCachedPtr();
-
-            return ConvertPhysicsQueryHits(Internal_ConvexCastAll(meshPtr, ref position, ref rotation, ref unitDir, layer, max));
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and checks if it has hit anything. This can be significantly more efficient than 
-        /// other types of cast* calls.
-        /// </summary>
-        /// <param name="ray">Ray to cast into the scene.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool RayCastAny(Ray ray, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return RayCastAny(ray.origin, ray.direction, layer, max);
-        }
-
-        /// <summary>
-        /// Casts a ray into the scene and checks if it has hit anything. This can be significantly more efficient than 
-        /// other types of cast* calls.
-        /// </summary>
-        /// <param name="origin">Origin of the ray to cast into the scene.</param>
-        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool RayCastAny(Vector3 origin, Vector3 unitDir, ulong layer = ulong.MaxValue, 
-            float max = float.MaxValue)
-        {
-            return Internal_RayCastAny(ref origin, ref unitDir, layer, max);
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a box and checks if it has hit anything. This can be significantly more 
-        /// efficient than other types of cast* calls.
-        /// </summary>
-        /// <param name="box">Box to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the box.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool BoxCastAny(AABox box, Quaternion rotation, Vector3 unitDir, ulong layer = ulong.MaxValue, 
-            float max = float.MaxValue)
-        {
-            return Internal_BoxCastAny(ref box, ref rotation, ref unitDir, layer, max);
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a sphere and checks if it has hit anything. This can be significantly more
-        /// efficient than other types of cast* calls.
-        /// </summary>
-        /// <param name="sphere">Sphere to sweep through the scene.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool SphereCastAny(Sphere sphere, Vector3 unitDir, ulong layer = ulong.MaxValue, 
-            float max = float.MaxValue)
-        {
-            return Internal_SphereCastAny(ref sphere, ref unitDir, layer, max);
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a capsule and checks if it has hit anything. This can be significantly 
-        /// more efficient than other types of cast* calls.
-        /// </summary>
-        /// <param name="capsule">Capsule to sweep through the scene.</param>
-        /// <param name="rotation">Orientation of the capsule.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool CapsuleCastAny(Capsule capsule, Quaternion rotation, Vector3 unitDir,
-            ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            return Internal_CapsuleCastAny(ref capsule, ref rotation, ref unitDir, layer, max);
-        }
-
-        /// <summary>
-        /// Performs a sweep into the scene using a convex mesh and checks if it has hit anything. This can be significantly
-        /// more efficient than other types of cast* calls.
-        /// </summary>
-        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
-        /// <param name="position">Starting position of the mesh.</param>
-        /// <param name="rotation">Orientation of the mesh.</param>
-        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
-        ///                   </param>
-        /// <returns>True if something was hit, false otherwise.</returns>
-        public static bool ConvexCastAny(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
-            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
-        {
-            IntPtr meshPtr = IntPtr.Zero;
-            if (mesh != null)
-                meshPtr = mesh.GetCachedPtr();
-
-            return Internal_ConvexCastAny(meshPtr, ref position, ref rotation, ref unitDir, layer, max);
-        }
-
-        /// <summary>
-        /// Returns a list of all colliders in the scene that overlap the provided box.
-        /// </summary>
-        /// <param name="box">Box to check for overlap.</param>
-        /// <param name="rotation">Orientation of the box.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>List of all colliders that overlap the box.</returns>
-        public static Collider[] BoxOverlap(AABox box, Quaternion rotation, ulong layer = ulong.MaxValue)
-        {
-            return ConvertColliders(Internal_BoxOverlap(ref box, ref rotation, layer));
-        }
-
-        /// <summary>
-        /// Returns a list of all colliders in the scene that overlap the provided sphere.
-        /// </summary>
-        /// <param name="sphere">Sphere to check for overlap.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>List of all colliders that overlap the sphere.</returns>
-        public static Collider[] SphereOverlap(Sphere sphere, ulong layer = ulong.MaxValue)
-        {
-            return ConvertColliders(Internal_SphereOverlap(ref sphere, layer));
-        }
-
-        /// <summary>
-        /// Returns a list of all colliders in the scene that overlap the provided capsule.
-        /// </summary>
-        /// <param name="capsule">Capsule to check for overlap.</param>
-        /// <param name="rotation">Orientation of the capsule.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>List of all colliders that overlap the sphere.</returns>
-        public static Collider[] CapsuleOverlap(Capsule capsule, Quaternion rotation, ulong layer = ulong.MaxValue)
-        {
-            return ConvertColliders(Internal_CapsuleOverlap(ref capsule, ref rotation, layer));
-        }
-
-        /// <summary>
-        /// Returns a list of all colliders in the scene that overlap the provided convex mesh.
-        /// </summary>
-        /// <param name="mesh">Mesh to check for overlap. Must be convex.</param>
-        /// <param name="position">Position of the mesh.</param>
-        /// <param name="rotation">Orientation of the mesh.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>List of all colliders that overlap the mesh.</returns>
-        public static Collider[] ConvexOverlap(PhysicsMesh mesh, Vector3 position, Quaternion rotation, 
-            ulong layer = ulong.MaxValue)
-        {
-            IntPtr meshPtr = IntPtr.Zero;
-            if (mesh != null)
-                meshPtr = mesh.GetCachedPtr();
-
-            return ConvertColliders(Internal_ConvexOverlap(meshPtr, ref position, ref rotation, layer));
-        }
-
-        /// <summary>
-        /// Checks if the provided box overlaps any other collider in the scene.
-        /// </summary>
-        /// <param name="box">Box to check for overlap.</param>
-        /// <param name="rotation">Orientation of the box.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>True if there is overlap with another object, false otherwise.</returns>
-        public static bool BoxOverlapAny(AABox box, Quaternion rotation, ulong layer = ulong.MaxValue)
-        {
-            return Internal_BoxOverlapAny(ref box, ref rotation, layer);
-        }
-
-        /// <summary>
-        /// Checks if the provided sphere overlaps any other collider in the scene.
-        /// </summary>
-        /// <param name="sphere">Sphere to check for overlap.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>True if there is overlap with another object, false otherwise.</returns>
-        public static bool SphereOverlapAny(Sphere sphere, ulong layer = ulong.MaxValue)
-        {
-            return Internal_SphereOverlapAny(ref sphere, layer);
-        }
-
-        /// <summary>
-        /// Checks if the provided capsule overlaps any other collider in the scene.
-        /// </summary>
-        /// <param name="capsule">Capsule to check for overlap.</param>
-        /// <param name="rotation">Orientation of the capsule.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>True if there is overlap with another object, false otherwise.</returns>
-        public static bool CapsuleOverlapAny(Capsule capsule, Quaternion rotation, ulong layer = ulong.MaxValue)
-        {
-            return Internal_CapsuleOverlapAny(ref capsule, ref rotation, layer);
-        }
-
-        /// <summary>
-        /// Checks if the provided convex mesh overlaps any other collider in the scene.
-        /// </summary>
-        /// <param name="mesh">Mesh to check for overlap. Must be convex.</param>
-        /// <param name="position">Position of the mesh.</param>
-        /// <param name="rotation">Orientation of the mesh.</param>
-        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
-        ///                     </param>
-        /// <returns>True if there is overlap with another object, false otherwise.</returns>
-        public static bool ConvexOverlapAny(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
-            ulong layer = ulong.MaxValue)
-        {
-            IntPtr meshPtr = IntPtr.Zero;
-            if (mesh != null)
-                meshPtr = mesh.GetCachedPtr();
-
-            return Internal_ConvexOverlapAny(meshPtr, ref position, ref rotation, layer);
-        }
-
-        /// <summary>
-        /// Adds a new physics region. Certain physics options require you to set up regions in which physics objects are
-        /// allowed to be in, and objects outside of these regions will not be handled by physics.You do not need to set
-        /// up these regions by default.
-        /// </summary>
-        /// <param name="region">Region of space that physics objects are allowed to be in.</param>
-        /// <returns>A unique handle to the region.</returns>
-        public static int AddPhysicsRegion(AABox region)
-        {
-            return Internal_AddPhysicsRegion(ref region);
-        }
-
-        /// <summary>
-        /// Removes a physics region.
-        /// </summary>
-        /// <param name="handle">Handle of the region returned by <see cref="AddPhysicsRegion"/></param>
-        public static void RemovePhysicsRegion(int handle)
-        {
-            Internal_RemovePhysicsRegion(handle);
-        }
-
-        /// <summary>
-        /// Removes all physics regions. 
-        /// </summary>
-        public static void ClearPhysicsRegions()
-        {
-            Internal_ClearPhysicsRegions();
-        }
-
-        /// <summary>
-        /// Enables or disables collision between two layers. Each physics object can be assigned a specific layer, and here
-        /// you can determine which layers can interact with each other.
-        /// </summary>
-        /// <param name="layerA">First collision layer.</param>
-        /// <param name="layerB">Second collision layer.</param>
-        /// <param name="enabled">True if the layers are allowed to interact, false otherwise.</param>
-        public static void ToggleCollision(ulong layerA, ulong layerB, bool enabled)
-        {
-            Internal_ToggleCollision(layerA, layerB, enabled);
-        }
-
-        /// <summary>
-        /// Checks if two collision layers are allowed to interact.
-        /// </summary>
-        /// <param name="layerA">First collision layer.</param>
-        /// <param name="layerB">Second collision layer.</param>
-        /// <returns>True if the two provided layers are allowed to interact.</returns>
-        public static bool IsCollisionEnabled(ulong layerA, ulong layerB)
-        {
-            return Internal_IsCollisionEnabled(layerA, layerB);
-        }
-
-        /// <summary>
-        /// Checks is the physics simulation update currently in progress.
-        /// </summary>
-        internal static bool IsUpdateInProgress
-        {
-            get { return Internal_IsUpdateInProgress(); }
-        }
-
-        /// <summary>
-        /// Converts a physics query hit info retrieved from native code into managed physics query hit.
-        /// </summary>
-        /// <param name="scriptHit">Native physics query hit info.</param>
-        /// <param name="hit">Managed physics query hit info</param>
-        private static void ConvertPhysicsQueryHit(ref ScriptPhysicsQueryHit scriptHit, out PhysicsQueryHit hit)
-        {
-            hit.collider = scriptHit.collider.Component;
-            hit.distance = scriptHit.distance;
-            hit.normal = scriptHit.normal;
-            hit.point = scriptHit.point;
-            hit.triangleIdx = scriptHit.triangleIdx;
-            hit.uv = scriptHit.uv;
-        }
-
-        /// <summary>
-        /// Converts all provided physics query hit infos retrieved from native code into managed physics query hits.
-        /// </summary>
-        /// <param name="scriptHits">Native physics query hits.</param>
-        /// <returns>Converted managed physics query hits.</returns>
-        private static PhysicsQueryHit[] ConvertPhysicsQueryHits(ScriptPhysicsQueryHit[] scriptHits)
-        {
-            PhysicsQueryHit[] output = new PhysicsQueryHit[scriptHits.Length];
-
-            for (int i = 0; i < scriptHits.Length; i++)
-                ConvertPhysicsQueryHit(ref scriptHits[i], out output[i]);
-
-            return output;
-        }
-
-        /// <summary>
-        /// Converts an array of native colliders to collider components.
-        /// </summary>
-        /// <param name="colliders">Native colliders.</param>
-        /// <returns>Managed collider components.</returns>
-        private static Collider[] ConvertColliders(NativeCollider[] colliders)
-        {
-            Collider[] output = new Collider[colliders.Length];
-            for (int i = 0; i < colliders.Length; i++)
-                output[i] = colliders[i].Component;
-
-            return output;
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetGravity(out Vector3 gravity);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetGravity(ref Vector3 gravity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_AddPhysicsRegion(ref AABox region);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_RemovePhysicsRegion(int handle);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_ClearPhysicsRegions();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_ToggleCollision(ulong layerA, ulong layerB, bool enabled);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_IsCollisionEnabled(ulong layerA, ulong layerB);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_IsUpdateInProgress();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_RayCast(ref Vector3 origin, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_BoxCast(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_SphereCast(ref Sphere sphere, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_CapsuleCast(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_ConvexCast(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ScriptPhysicsQueryHit[] Internal_RayCastAll(ref Vector3 origin, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ScriptPhysicsQueryHit[] Internal_BoxCastAll(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ScriptPhysicsQueryHit[] Internal_SphereCastAll(ref Sphere sphere, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ScriptPhysicsQueryHit[] Internal_CapsuleCastAll(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ScriptPhysicsQueryHit[] Internal_ConvexCastAll(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_RayCastAny(ref Vector3 origin, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_BoxCastAny(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_SphereCastAny(ref Sphere sphere, ref Vector3 unitDir, ulong layer,  float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_CapsuleCastAny(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_ConvexCastAny(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeCollider[] Internal_BoxOverlap(ref AABox box, ref Quaternion rotation, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeCollider[] Internal_SphereOverlap(ref Sphere sphere, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeCollider[] Internal_CapsuleOverlap(ref Capsule capsule, ref Quaternion rotation, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeCollider[] Internal_ConvexOverlap(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ulong layer);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_BoxOverlapAny(ref AABox box, ref Quaternion rotation, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_SphereOverlapAny(ref Sphere sphere, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_CapsuleOverlapAny(ref Capsule capsule, ref Quaternion rotation, ulong layer);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_ConvexOverlapAny(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ulong layer);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Provides global access to the physics system, including scene queries and global options.
+    /// </summary>
+    public static class Physics
+    {
+        /// <summary>
+        /// Global gravity value for all objects in the scene.
+        /// </summary>
+        public static Vector3 Gravity
+        {
+            get { Vector3 gravity; Internal_GetGravity(out gravity); return gravity; }
+            set { Internal_SetGravity(ref value); }
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="ray">Ray to cast into the scene.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool RayCast(Ray ray, out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if (RayCast(ray.origin, ray.direction, out hit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="origin">Origin of the ray to cast into the scene.</param>
+        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool RayCast(Vector3 origin, Vector3 unitDir, out PhysicsQueryHit hit,
+           ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if(Internal_RayCast(ref origin, ref unitDir, out scriptHit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            hit = new PhysicsQueryHit();
+            return false;
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a box and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="box">Box to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the box.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool BoxCast(AABox box, Quaternion rotation, Vector3 unitDir, out PhysicsQueryHit hit,
+            ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if(Internal_BoxCast(ref box, ref rotation, ref unitDir, out scriptHit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            hit = new PhysicsQueryHit();
+            return false;
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a sphere and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="sphere">Sphere to sweep through the scene.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool SphereCast(Sphere sphere, Vector3 unitDir, out PhysicsQueryHit hit,
+            ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if(Internal_SphereCast(ref sphere, ref unitDir, out scriptHit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            hit = new PhysicsQueryHit();
+            return false;
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a capsule and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="capsule">Capsule to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the capsule.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool CapsuleCast(Capsule capsule, Quaternion rotation, Vector3 unitDir,
+            out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if(Internal_CapsuleCast(ref capsule, ref rotation, ref unitDir, out scriptHit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            hit = new PhysicsQueryHit();
+            return false;
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a convex mesh and returns the closest found hit, if any.
+        /// </summary>
+        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
+        /// <param name="position">Starting position of the mesh.</param>
+        /// <param name="rotation">Orientation of the mesh.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="hit">Information recorded about a hit. Only valid if method returns true.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool ConvexCast(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
+            Vector3 unitDir, out PhysicsQueryHit hit, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            IntPtr meshPtr = IntPtr.Zero;
+            if (mesh != null)
+                meshPtr = mesh.GetCachedPtr();
+
+            ScriptPhysicsQueryHit scriptHit = new ScriptPhysicsQueryHit();
+            if(Internal_ConvexCast(meshPtr, ref position, ref rotation, ref unitDir, out scriptHit, layer, max))
+            {
+                ConvertPhysicsQueryHit(ref scriptHit, out hit);
+                return true;
+            }
+
+            hit = new PhysicsQueryHit();
+            return false;
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and returns all found hits.
+        /// </summary>
+        /// <param name="ray">Ray to cast into the scene.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] RayCastAll(Ray ray, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return RayCastAll(ray.origin, ray.direction, layer, max);
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and returns all found hits.
+        /// </summary>
+        /// <param name="origin">Origin of the ray to cast into the scene.</param>
+        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] RayCastAll(Vector3 origin, Vector3 unitDir,
+			ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return ConvertPhysicsQueryHits(Internal_RayCastAll(ref origin, ref unitDir, layer, max));
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a box and returns all found hits.
+        /// </summary>
+        /// <param name="box">Box to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the box.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] BoxCastAll(AABox box, Quaternion rotation,
+            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return ConvertPhysicsQueryHits(Internal_BoxCastAll(ref box, ref rotation, ref unitDir, layer, max));
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a sphere and returns all found hits.
+        /// </summary>
+        /// <param name="sphere">Sphere to sweep through the scene.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] SphereCastAll(Sphere sphere, Vector3 unitDir,
+            ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return ConvertPhysicsQueryHits(Internal_SphereCastAll(ref sphere, ref unitDir, layer, max));
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a capsule and returns all found hits.
+        /// </summary>
+        /// <param name="capsule">Capsule to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the capsule.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] CapsuleCastAll(Capsule capsule, Quaternion rotation,
+            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return ConvertPhysicsQueryHits(Internal_CapsuleCastAll(ref capsule, ref rotation, ref unitDir, layer, max));
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a convex mesh and returns all found hits.
+        /// </summary>
+        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
+        /// <param name="position">Starting position of the mesh.</param>
+        /// <param name="rotation">Orientation of the mesh.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>List of all detected hits.</returns>
+        public static PhysicsQueryHit[] ConvexCastAll(PhysicsMesh mesh, Vector3 position,
+            Quaternion rotation, Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            IntPtr meshPtr = IntPtr.Zero;
+            if (mesh != null)
+                meshPtr = mesh.GetCachedPtr();
+
+            return ConvertPhysicsQueryHits(Internal_ConvexCastAll(meshPtr, ref position, ref rotation, ref unitDir, layer, max));
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and checks if it has hit anything. This can be significantly more efficient than 
+        /// other types of cast* calls.
+        /// </summary>
+        /// <param name="ray">Ray to cast into the scene.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool RayCastAny(Ray ray, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return RayCastAny(ray.origin, ray.direction, layer, max);
+        }
+
+        /// <summary>
+        /// Casts a ray into the scene and checks if it has hit anything. This can be significantly more efficient than 
+        /// other types of cast* calls.
+        /// </summary>
+        /// <param name="origin">Origin of the ray to cast into the scene.</param>
+        /// <param name="unitDir">Unit direction of the ray to cast into the scene.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool RayCastAny(Vector3 origin, Vector3 unitDir, ulong layer = ulong.MaxValue, 
+            float max = float.MaxValue)
+        {
+            return Internal_RayCastAny(ref origin, ref unitDir, layer, max);
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a box and checks if it has hit anything. This can be significantly more 
+        /// efficient than other types of cast* calls.
+        /// </summary>
+        /// <param name="box">Box to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the box.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool BoxCastAny(AABox box, Quaternion rotation, Vector3 unitDir, ulong layer = ulong.MaxValue, 
+            float max = float.MaxValue)
+        {
+            return Internal_BoxCastAny(ref box, ref rotation, ref unitDir, layer, max);
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a sphere and checks if it has hit anything. This can be significantly more
+        /// efficient than other types of cast* calls.
+        /// </summary>
+        /// <param name="sphere">Sphere to sweep through the scene.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool SphereCastAny(Sphere sphere, Vector3 unitDir, ulong layer = ulong.MaxValue, 
+            float max = float.MaxValue)
+        {
+            return Internal_SphereCastAny(ref sphere, ref unitDir, layer, max);
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a capsule and checks if it has hit anything. This can be significantly 
+        /// more efficient than other types of cast* calls.
+        /// </summary>
+        /// <param name="capsule">Capsule to sweep through the scene.</param>
+        /// <param name="rotation">Orientation of the capsule.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool CapsuleCastAny(Capsule capsule, Quaternion rotation, Vector3 unitDir,
+            ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            return Internal_CapsuleCastAny(ref capsule, ref rotation, ref unitDir, layer, max);
+        }
+
+        /// <summary>
+        /// Performs a sweep into the scene using a convex mesh and checks if it has hit anything. This can be significantly
+        /// more efficient than other types of cast* calls.
+        /// </summary>
+        /// <param name="mesh">Mesh to sweep through the scene. Must be convex.</param>
+        /// <param name="position">Starting position of the mesh.</param>
+        /// <param name="rotation">Orientation of the mesh.</param>
+        /// <param name="unitDir">Unit direction towards which to perform the sweep.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <param name="max">Maximum distance at which to perform the query. Hits past this distance will not be detected.
+        ///                   </param>
+        /// <returns>True if something was hit, false otherwise.</returns>
+        public static bool ConvexCastAny(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
+            Vector3 unitDir, ulong layer = ulong.MaxValue, float max = float.MaxValue)
+        {
+            IntPtr meshPtr = IntPtr.Zero;
+            if (mesh != null)
+                meshPtr = mesh.GetCachedPtr();
+
+            return Internal_ConvexCastAny(meshPtr, ref position, ref rotation, ref unitDir, layer, max);
+        }
+
+        /// <summary>
+        /// Returns a list of all colliders in the scene that overlap the provided box.
+        /// </summary>
+        /// <param name="box">Box to check for overlap.</param>
+        /// <param name="rotation">Orientation of the box.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>List of all colliders that overlap the box.</returns>
+        public static Collider[] BoxOverlap(AABox box, Quaternion rotation, ulong layer = ulong.MaxValue)
+        {
+            return ConvertColliders(Internal_BoxOverlap(ref box, ref rotation, layer));
+        }
+
+        /// <summary>
+        /// Returns a list of all colliders in the scene that overlap the provided sphere.
+        /// </summary>
+        /// <param name="sphere">Sphere to check for overlap.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>List of all colliders that overlap the sphere.</returns>
+        public static Collider[] SphereOverlap(Sphere sphere, ulong layer = ulong.MaxValue)
+        {
+            return ConvertColliders(Internal_SphereOverlap(ref sphere, layer));
+        }
+
+        /// <summary>
+        /// Returns a list of all colliders in the scene that overlap the provided capsule.
+        /// </summary>
+        /// <param name="capsule">Capsule to check for overlap.</param>
+        /// <param name="rotation">Orientation of the capsule.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>List of all colliders that overlap the sphere.</returns>
+        public static Collider[] CapsuleOverlap(Capsule capsule, Quaternion rotation, ulong layer = ulong.MaxValue)
+        {
+            return ConvertColliders(Internal_CapsuleOverlap(ref capsule, ref rotation, layer));
+        }
+
+        /// <summary>
+        /// Returns a list of all colliders in the scene that overlap the provided convex mesh.
+        /// </summary>
+        /// <param name="mesh">Mesh to check for overlap. Must be convex.</param>
+        /// <param name="position">Position of the mesh.</param>
+        /// <param name="rotation">Orientation of the mesh.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>List of all colliders that overlap the mesh.</returns>
+        public static Collider[] ConvexOverlap(PhysicsMesh mesh, Vector3 position, Quaternion rotation, 
+            ulong layer = ulong.MaxValue)
+        {
+            IntPtr meshPtr = IntPtr.Zero;
+            if (mesh != null)
+                meshPtr = mesh.GetCachedPtr();
+
+            return ConvertColliders(Internal_ConvexOverlap(meshPtr, ref position, ref rotation, layer));
+        }
+
+        /// <summary>
+        /// Checks if the provided box overlaps any other collider in the scene.
+        /// </summary>
+        /// <param name="box">Box to check for overlap.</param>
+        /// <param name="rotation">Orientation of the box.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>True if there is overlap with another object, false otherwise.</returns>
+        public static bool BoxOverlapAny(AABox box, Quaternion rotation, ulong layer = ulong.MaxValue)
+        {
+            return Internal_BoxOverlapAny(ref box, ref rotation, layer);
+        }
+
+        /// <summary>
+        /// Checks if the provided sphere overlaps any other collider in the scene.
+        /// </summary>
+        /// <param name="sphere">Sphere to check for overlap.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>True if there is overlap with another object, false otherwise.</returns>
+        public static bool SphereOverlapAny(Sphere sphere, ulong layer = ulong.MaxValue)
+        {
+            return Internal_SphereOverlapAny(ref sphere, layer);
+        }
+
+        /// <summary>
+        /// Checks if the provided capsule overlaps any other collider in the scene.
+        /// </summary>
+        /// <param name="capsule">Capsule to check for overlap.</param>
+        /// <param name="rotation">Orientation of the capsule.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>True if there is overlap with another object, false otherwise.</returns>
+        public static bool CapsuleOverlapAny(Capsule capsule, Quaternion rotation, ulong layer = ulong.MaxValue)
+        {
+            return Internal_CapsuleOverlapAny(ref capsule, ref rotation, layer);
+        }
+
+        /// <summary>
+        /// Checks if the provided convex mesh overlaps any other collider in the scene.
+        /// </summary>
+        /// <param name="mesh">Mesh to check for overlap. Must be convex.</param>
+        /// <param name="position">Position of the mesh.</param>
+        /// <param name="rotation">Orientation of the mesh.</param>
+        /// <param name="layer">Layers to consider for the query. This allows you to ignore certain groups of objects.
+        ///                     </param>
+        /// <returns>True if there is overlap with another object, false otherwise.</returns>
+        public static bool ConvexOverlapAny(PhysicsMesh mesh, Vector3 position, Quaternion rotation,
+            ulong layer = ulong.MaxValue)
+        {
+            IntPtr meshPtr = IntPtr.Zero;
+            if (mesh != null)
+                meshPtr = mesh.GetCachedPtr();
+
+            return Internal_ConvexOverlapAny(meshPtr, ref position, ref rotation, layer);
+        }
+
+        /// <summary>
+        /// Adds a new physics region. Certain physics options require you to set up regions in which physics objects are
+        /// allowed to be in, and objects outside of these regions will not be handled by physics.You do not need to set
+        /// up these regions by default.
+        /// </summary>
+        /// <param name="region">Region of space that physics objects are allowed to be in.</param>
+        /// <returns>A unique handle to the region.</returns>
+        public static int AddPhysicsRegion(AABox region)
+        {
+            return Internal_AddPhysicsRegion(ref region);
+        }
+
+        /// <summary>
+        /// Removes a physics region.
+        /// </summary>
+        /// <param name="handle">Handle of the region returned by <see cref="AddPhysicsRegion"/></param>
+        public static void RemovePhysicsRegion(int handle)
+        {
+            Internal_RemovePhysicsRegion(handle);
+        }
+
+        /// <summary>
+        /// Removes all physics regions. 
+        /// </summary>
+        public static void ClearPhysicsRegions()
+        {
+            Internal_ClearPhysicsRegions();
+        }
+
+        /// <summary>
+        /// Enables or disables collision between two layers. Each physics object can be assigned a specific layer, and here
+        /// you can determine which layers can interact with each other.
+        /// </summary>
+        /// <param name="layerA">First collision layer.</param>
+        /// <param name="layerB">Second collision layer.</param>
+        /// <param name="enabled">True if the layers are allowed to interact, false otherwise.</param>
+        public static void ToggleCollision(ulong layerA, ulong layerB, bool enabled)
+        {
+            Internal_ToggleCollision(layerA, layerB, enabled);
+        }
+
+        /// <summary>
+        /// Checks if two collision layers are allowed to interact.
+        /// </summary>
+        /// <param name="layerA">First collision layer.</param>
+        /// <param name="layerB">Second collision layer.</param>
+        /// <returns>True if the two provided layers are allowed to interact.</returns>
+        public static bool IsCollisionEnabled(ulong layerA, ulong layerB)
+        {
+            return Internal_IsCollisionEnabled(layerA, layerB);
+        }
+
+        /// <summary>
+        /// Checks is the physics simulation update currently in progress.
+        /// </summary>
+        internal static bool IsUpdateInProgress
+        {
+            get { return Internal_IsUpdateInProgress(); }
+        }
+
+        /// <summary>
+        /// Converts a physics query hit info retrieved from native code into managed physics query hit.
+        /// </summary>
+        /// <param name="scriptHit">Native physics query hit info.</param>
+        /// <param name="hit">Managed physics query hit info</param>
+        private static void ConvertPhysicsQueryHit(ref ScriptPhysicsQueryHit scriptHit, out PhysicsQueryHit hit)
+        {
+            hit.collider = scriptHit.collider.Component;
+            hit.distance = scriptHit.distance;
+            hit.normal = scriptHit.normal;
+            hit.point = scriptHit.point;
+            hit.triangleIdx = scriptHit.triangleIdx;
+            hit.uv = scriptHit.uv;
+        }
+
+        /// <summary>
+        /// Converts all provided physics query hit infos retrieved from native code into managed physics query hits.
+        /// </summary>
+        /// <param name="scriptHits">Native physics query hits.</param>
+        /// <returns>Converted managed physics query hits.</returns>
+        private static PhysicsQueryHit[] ConvertPhysicsQueryHits(ScriptPhysicsQueryHit[] scriptHits)
+        {
+            PhysicsQueryHit[] output = new PhysicsQueryHit[scriptHits.Length];
+
+            for (int i = 0; i < scriptHits.Length; i++)
+                ConvertPhysicsQueryHit(ref scriptHits[i], out output[i]);
+
+            return output;
+        }
+
+        /// <summary>
+        /// Converts an array of native colliders to collider components.
+        /// </summary>
+        /// <param name="colliders">Native colliders.</param>
+        /// <returns>Managed collider components.</returns>
+        private static Collider[] ConvertColliders(NativeCollider[] colliders)
+        {
+            Collider[] output = new Collider[colliders.Length];
+            for (int i = 0; i < colliders.Length; i++)
+                output[i] = colliders[i].Component;
+
+            return output;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetGravity(out Vector3 gravity);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetGravity(ref Vector3 gravity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_AddPhysicsRegion(ref AABox region);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_RemovePhysicsRegion(int handle);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_ClearPhysicsRegions();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_ToggleCollision(ulong layerA, ulong layerB, bool enabled);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_IsCollisionEnabled(ulong layerA, ulong layerB);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_IsUpdateInProgress();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_RayCast(ref Vector3 origin, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_BoxCast(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_SphereCast(ref Sphere sphere, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_CapsuleCast(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_ConvexCast(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, out ScriptPhysicsQueryHit hit, ulong layer, float max);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ScriptPhysicsQueryHit[] Internal_RayCastAll(ref Vector3 origin, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ScriptPhysicsQueryHit[] Internal_BoxCastAll(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ScriptPhysicsQueryHit[] Internal_SphereCastAll(ref Sphere sphere, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ScriptPhysicsQueryHit[] Internal_CapsuleCastAll(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ScriptPhysicsQueryHit[] Internal_ConvexCastAll(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_RayCastAny(ref Vector3 origin, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_BoxCastAny(ref AABox box, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_SphereCastAny(ref Sphere sphere, ref Vector3 unitDir, ulong layer,  float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_CapsuleCastAny(ref Capsule capsule, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_ConvexCastAny(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ref Vector3 unitDir, ulong layer, float max);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeCollider[] Internal_BoxOverlap(ref AABox box, ref Quaternion rotation, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeCollider[] Internal_SphereOverlap(ref Sphere sphere, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeCollider[] Internal_CapsuleOverlap(ref Capsule capsule, ref Quaternion rotation, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeCollider[] Internal_ConvexOverlap(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ulong layer);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_BoxOverlapAny(ref AABox box, ref Quaternion rotation, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_SphereOverlapAny(ref Sphere sphere, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_CapsuleOverlapAny(ref Capsule capsule, ref Quaternion rotation, ulong layer);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_ConvexOverlapAny(IntPtr mesh, ref Vector3 position, ref Quaternion rotation, ulong layer);
+    }
+}

+ 8 - 0
Source/MBansheeEngine/Physics/Rigidbody.cs

@@ -359,6 +359,10 @@ namespace BansheeEngine
         {
             if (native != null)
                 native.Move(position);
+
+            NotifyFlags = TransformChangedFlags.None;
+            SceneObject.Position = position;
+            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
         }
 
         /// <summary>
@@ -370,6 +374,10 @@ namespace BansheeEngine
         {
             if (native != null)
                 native.Rotate(rotation);
+
+            NotifyFlags = TransformChangedFlags.None;
+            SceneObject.Rotation = rotation;
+            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
         }
 
         /// <summary>

+ 1 - 0
Source/SBansheeEngine/Include/BsScriptInput.h

@@ -67,6 +67,7 @@ namespace BansheeEngine
 		static bool internal_isPointerDoubleClicked();
 		static float internal_getAxisValue(UINT32 axisType, UINT32 deviceIdx);
 		static void internal_getPointerPosition(Vector2I* position);
+		static void internal_getPointerScreenPosition(Vector2I* position);
 		static void internal_getPointerDelta(Vector2I* position);
 
 		typedef void(__stdcall *OnButtonEventThunkDef) (ButtonCode, UINT32, MonoException**);

+ 240 - 200
Source/SBansheeEngine/Source/BsScriptInput.cpp

@@ -1,201 +1,241 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsScriptInput.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
-#include "BsMonoMethod.h"
-#include "BsMonoUtil.h"
-#include "BsInput.h"
-#include "BsScriptVector2I.h"
-#include "BsPlayInEditorManager.h"
-
-namespace BansheeEngine
-{
-	ScriptInput::OnButtonEventThunkDef ScriptInput::OnButtonPressedThunk;
-	ScriptInput::OnButtonEventThunkDef ScriptInput::OnButtonReleasedThunk;
-	ScriptInput::OnCharInputEventThunkDef ScriptInput::OnCharInputThunk;
-	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerPressedThunk;
-	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerReleasedThunk;
-	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerMovedThunk;
-	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerDoubleClickThunk;
-
-	HEvent ScriptInput::OnButtonPressedConn;
-	HEvent ScriptInput::OnButtonReleasedConn;
-	HEvent ScriptInput::OnCharInputConn;
-	HEvent ScriptInput::OnPointerPressedConn;
-	HEvent ScriptInput::OnPointerReleasedConn;
-	HEvent ScriptInput::OnPointerMovedConn;
-	HEvent ScriptInput::OnPointerDoubleClickConn;
-
-	ScriptInput::ScriptInput(MonoObject* instance)
-		:ScriptObject(instance)
-	{ }
-
-	void ScriptInput::initRuntimeData()
-	{
-		metaData.scriptClass->addInternalCall("Internal_IsButtonHeld", &ScriptInput::internal_isButtonHeld);
-		metaData.scriptClass->addInternalCall("Internal_IsButtonDown", &ScriptInput::internal_isButtonDown);
-		metaData.scriptClass->addInternalCall("Internal_IsButtonUp", &ScriptInput::internal_isButtonUp);
-		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonHeld", &ScriptInput::internal_isPointerButtonHeld);
-		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonDown", &ScriptInput::internal_isPointerButtonDown);
-		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonUp", &ScriptInput::internal_isPointerButtonUp);
-		metaData.scriptClass->addInternalCall("Internal_IsPointerDoubleClicked", &ScriptInput::internal_isPointerDoubleClicked);
-		metaData.scriptClass->addInternalCall("Internal_GetAxisValue", &ScriptInput::internal_getAxisValue);
-		metaData.scriptClass->addInternalCall("Internal_GetPointerPosition", &ScriptInput::internal_getPointerPosition);
-		metaData.scriptClass->addInternalCall("Internal_GetPointerDelta", &ScriptInput::internal_getPointerDelta);
-
-		OnButtonPressedThunk = (OnButtonEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerButtonDown", "ButtonCode,int")->getThunk();
-		OnButtonReleasedThunk = (OnButtonEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerButtonUp", "ButtonCode,int")->getThunk();
-		OnCharInputThunk = (OnCharInputEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerCharInput", "int")->getThunk();
-		OnPointerPressedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerPressed", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
-		OnPointerReleasedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerReleased", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
-		OnPointerMovedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerMove", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
-		OnPointerDoubleClickThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerDoubleClick", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
-	}
-
-	void ScriptInput::startUp()
-	{
-		Input& input = Input::instance();
-
-		OnButtonPressedConn = input.onButtonDown.connect(&ScriptInput::onButtonDown);
-		OnButtonReleasedConn = input.onButtonUp.connect(&ScriptInput::onButtonUp);
-		OnCharInputConn = input.onCharInput.connect(&ScriptInput::onCharInput);
-		OnPointerPressedConn = input.onPointerPressed.connect(&ScriptInput::onPointerPressed);
-		OnPointerReleasedConn = input.onPointerReleased.connect(&ScriptInput::onPointerReleased);
-		OnPointerMovedConn = input.onPointerMoved.connect(&ScriptInput::onPointerMoved);
-		OnPointerDoubleClickConn = input.onPointerDoubleClick.connect(&ScriptInput::onPointerDoubleClick);
-	}
-
-	void ScriptInput::shutDown()
-	{
-		OnButtonPressedConn.disconnect();
-		OnButtonReleasedConn.disconnect();
-		OnCharInputConn.disconnect();
-		OnPointerPressedConn.disconnect();
-		OnPointerReleasedConn.disconnect();
-		OnPointerMovedConn.disconnect();
-		OnPointerDoubleClickConn.disconnect();
-	}
-
-	void ScriptInput::onButtonDown(const ButtonEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoUtil::invokeThunk(OnButtonPressedThunk, ev.buttonCode, ev.deviceIdx);
-	}
-
-	void ScriptInput::onButtonUp(const ButtonEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoUtil::invokeThunk(OnButtonReleasedThunk, ev.buttonCode, ev.deviceIdx);
-	}
-
-	void ScriptInput::onCharInput(const TextInputEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoUtil::invokeThunk(OnCharInputThunk, ev.textChar);
-	}
-
-	void ScriptInput::onPointerMoved(const PointerEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
-		MonoObject* delta = ScriptVector2I::box(ev.delta);
-
-		MonoUtil::invokeThunk(OnPointerMovedThunk, screenPos, delta, 
-			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
-	}
-
-	void ScriptInput::onPointerPressed(const PointerEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
-		MonoObject* delta = ScriptVector2I::box(ev.delta);
-
-		MonoUtil::invokeThunk(OnPointerPressedThunk, screenPos, delta, 
-			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
-	}
-
-	void ScriptInput::onPointerReleased(const PointerEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
-		MonoObject* delta = ScriptVector2I::box(ev.delta);
-
-		MonoUtil::invokeThunk(OnPointerReleasedThunk, screenPos, delta, 
-			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
-	}
-
-	void ScriptInput::onPointerDoubleClick(const PointerEvent& ev)
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
-			return;
-
-		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
-		MonoObject* delta = ScriptVector2I::box(ev.delta);
-
-		MonoUtil::invokeThunk(OnPointerDoubleClickThunk, screenPos, delta, 
-			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
-	}
-
-	bool ScriptInput::internal_isButtonHeld(ButtonCode code, UINT32 deviceIdx)
-	{
-		return Input::instance().isButtonHeld(code, deviceIdx);
-	}
-
-	bool ScriptInput::internal_isButtonDown(ButtonCode code, UINT32 deviceIdx)
-	{
-		return Input::instance().isButtonDown(code, deviceIdx);
-	}
-
-	bool ScriptInput::internal_isButtonUp(ButtonCode code, UINT32 deviceIdx)
-	{
-		return Input::instance().isButtonUp(code, deviceIdx);
-	}
-
-	bool ScriptInput::internal_isPointerButtonHeld(PointerEventButton code)
-	{
-		return Input::instance().isPointerButtonHeld(code);
-	}
-
-	bool ScriptInput::internal_isPointerButtonDown(PointerEventButton code)
-	{
-		return Input::instance().isPointerButtonDown(code);
-	}
-
-	bool ScriptInput::internal_isPointerButtonUp(PointerEventButton code)
-	{
-		return Input::instance().isPointerButtonUp(code);
-	}
-
-	bool ScriptInput::internal_isPointerDoubleClicked()
-	{
-		return Input::instance().isPointerDoubleClicked();
-	}
-
-	float ScriptInput::internal_getAxisValue(UINT32 axisType, UINT32 deviceIdx)
-	{
-		return Input::instance().getAxisValue(axisType, deviceIdx);
-	}
-
-	void ScriptInput::internal_getPointerPosition(Vector2I* position)
-	{
-		*position = Input::instance().getPointerPosition();
-	}
-
-	void ScriptInput::internal_getPointerDelta(Vector2I* position)
-	{
-		*position = Input::instance().getPointerDelta();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptInput.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsInput.h"
+#include "BsScriptVector2I.h"
+#include "BsPlayInEditorManager.h"
+#include "BsSceneManager.h"
+#include "BsCamera.h"
+#include "BsViewport.h"
+#include "BsRenderTarget.h"
+#include "BsRenderWindow.h"
+#include "BsRenderTexture.h"
+#include "BsGUIManager.h"
+
+namespace BansheeEngine
+{
+	ScriptInput::OnButtonEventThunkDef ScriptInput::OnButtonPressedThunk;
+	ScriptInput::OnButtonEventThunkDef ScriptInput::OnButtonReleasedThunk;
+	ScriptInput::OnCharInputEventThunkDef ScriptInput::OnCharInputThunk;
+	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerPressedThunk;
+	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerReleasedThunk;
+	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerMovedThunk;
+	ScriptInput::OnPointerEventThunkDef ScriptInput::OnPointerDoubleClickThunk;
+
+	HEvent ScriptInput::OnButtonPressedConn;
+	HEvent ScriptInput::OnButtonReleasedConn;
+	HEvent ScriptInput::OnCharInputConn;
+	HEvent ScriptInput::OnPointerPressedConn;
+	HEvent ScriptInput::OnPointerReleasedConn;
+	HEvent ScriptInput::OnPointerMovedConn;
+	HEvent ScriptInput::OnPointerDoubleClickConn;
+
+	ScriptInput::ScriptInput(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptInput::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_IsButtonHeld", &ScriptInput::internal_isButtonHeld);
+		metaData.scriptClass->addInternalCall("Internal_IsButtonDown", &ScriptInput::internal_isButtonDown);
+		metaData.scriptClass->addInternalCall("Internal_IsButtonUp", &ScriptInput::internal_isButtonUp);
+		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonHeld", &ScriptInput::internal_isPointerButtonHeld);
+		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonDown", &ScriptInput::internal_isPointerButtonDown);
+		metaData.scriptClass->addInternalCall("Internal_IsPointerButtonUp", &ScriptInput::internal_isPointerButtonUp);
+		metaData.scriptClass->addInternalCall("Internal_IsPointerDoubleClicked", &ScriptInput::internal_isPointerDoubleClicked);
+		metaData.scriptClass->addInternalCall("Internal_GetAxisValue", &ScriptInput::internal_getAxisValue);
+		metaData.scriptClass->addInternalCall("Internal_GetPointerPosition", &ScriptInput::internal_getPointerPosition);
+		metaData.scriptClass->addInternalCall("Internal_GetPointerScreenPosition", &ScriptInput::internal_getPointerScreenPosition);
+		metaData.scriptClass->addInternalCall("Internal_GetPointerDelta", &ScriptInput::internal_getPointerDelta);
+
+		OnButtonPressedThunk = (OnButtonEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerButtonDown", "ButtonCode,int")->getThunk();
+		OnButtonReleasedThunk = (OnButtonEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerButtonUp", "ButtonCode,int")->getThunk();
+		OnCharInputThunk = (OnCharInputEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerCharInput", "int")->getThunk();
+		OnPointerPressedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerPressed", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
+		OnPointerReleasedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerReleased", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
+		OnPointerMovedThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerMove", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
+		OnPointerDoubleClickThunk = (OnPointerEventThunkDef)metaData.scriptClass->getMethodExact("Internal_TriggerPointerDoubleClick", "Vector2I,Vector2I,PointerButton,bool,bool,bool,single")->getThunk();
+	}
+
+	void ScriptInput::startUp()
+	{
+		Input& input = Input::instance();
+
+		OnButtonPressedConn = input.onButtonDown.connect(&ScriptInput::onButtonDown);
+		OnButtonReleasedConn = input.onButtonUp.connect(&ScriptInput::onButtonUp);
+		OnCharInputConn = input.onCharInput.connect(&ScriptInput::onCharInput);
+		OnPointerPressedConn = input.onPointerPressed.connect(&ScriptInput::onPointerPressed);
+		OnPointerReleasedConn = input.onPointerReleased.connect(&ScriptInput::onPointerReleased);
+		OnPointerMovedConn = input.onPointerMoved.connect(&ScriptInput::onPointerMoved);
+		OnPointerDoubleClickConn = input.onPointerDoubleClick.connect(&ScriptInput::onPointerDoubleClick);
+	}
+
+	void ScriptInput::shutDown()
+	{
+		OnButtonPressedConn.disconnect();
+		OnButtonReleasedConn.disconnect();
+		OnCharInputConn.disconnect();
+		OnPointerPressedConn.disconnect();
+		OnPointerReleasedConn.disconnect();
+		OnPointerMovedConn.disconnect();
+		OnPointerDoubleClickConn.disconnect();
+	}
+
+	void ScriptInput::onButtonDown(const ButtonEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoUtil::invokeThunk(OnButtonPressedThunk, ev.buttonCode, ev.deviceIdx);
+	}
+
+	void ScriptInput::onButtonUp(const ButtonEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoUtil::invokeThunk(OnButtonReleasedThunk, ev.buttonCode, ev.deviceIdx);
+	}
+
+	void ScriptInput::onCharInput(const TextInputEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoUtil::invokeThunk(OnCharInputThunk, ev.textChar);
+	}
+
+	void ScriptInput::onPointerMoved(const PointerEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
+		MonoObject* delta = ScriptVector2I::box(ev.delta);
+
+		MonoUtil::invokeThunk(OnPointerMovedThunk, screenPos, delta, 
+			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
+	}
+
+	void ScriptInput::onPointerPressed(const PointerEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
+		MonoObject* delta = ScriptVector2I::box(ev.delta);
+
+		MonoUtil::invokeThunk(OnPointerPressedThunk, screenPos, delta, 
+			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
+	}
+
+	void ScriptInput::onPointerReleased(const PointerEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
+		MonoObject* delta = ScriptVector2I::box(ev.delta);
+
+		MonoUtil::invokeThunk(OnPointerReleasedThunk, screenPos, delta, 
+			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
+	}
+
+	void ScriptInput::onPointerDoubleClick(const PointerEvent& ev)
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing)
+			return;
+
+		MonoObject* screenPos = ScriptVector2I::box(ev.screenPos);
+		MonoObject* delta = ScriptVector2I::box(ev.delta);
+
+		MonoUtil::invokeThunk(OnPointerDoubleClickThunk, screenPos, delta, 
+			ev.button, ev.shift, ev.control, ev.alt, ev.mouseWheelScrollAmount);
+	}
+
+	bool ScriptInput::internal_isButtonHeld(ButtonCode code, UINT32 deviceIdx)
+	{
+		return Input::instance().isButtonHeld(code, deviceIdx);
+	}
+
+	bool ScriptInput::internal_isButtonDown(ButtonCode code, UINT32 deviceIdx)
+	{
+		return Input::instance().isButtonDown(code, deviceIdx);
+	}
+
+	bool ScriptInput::internal_isButtonUp(ButtonCode code, UINT32 deviceIdx)
+	{
+		return Input::instance().isButtonUp(code, deviceIdx);
+	}
+
+	bool ScriptInput::internal_isPointerButtonHeld(PointerEventButton code)
+	{
+		return Input::instance().isPointerButtonHeld(code);
+	}
+
+	bool ScriptInput::internal_isPointerButtonDown(PointerEventButton code)
+	{
+		return Input::instance().isPointerButtonDown(code);
+	}
+
+	bool ScriptInput::internal_isPointerButtonUp(PointerEventButton code)
+	{
+		return Input::instance().isPointerButtonUp(code);
+	}
+
+	bool ScriptInput::internal_isPointerDoubleClicked()
+	{
+		return Input::instance().isPointerDoubleClicked();
+	}
+
+	float ScriptInput::internal_getAxisValue(UINT32 axisType, UINT32 deviceIdx)
+	{
+		return Input::instance().getAxisValue(axisType, deviceIdx);
+	}
+
+	void ScriptInput::internal_getPointerPosition(Vector2I* position)
+	{
+		*position = Input::instance().getPointerPosition();
+
+		SceneCameraData mainCamera = gSceneManager().getMainCamera();
+		if (mainCamera.camera == nullptr)
+			return;
+
+		// The main camera could be rendering to a standalone window, or be a part of the editor GUI. Find out which
+		// and transform the pointer position appropriately.
+		RenderTargetPtr target = mainCamera.camera->getViewport()->getTarget();
+		if (target == nullptr)
+			return;
+
+		if(target->getProperties().isWindow())
+		{
+			RenderWindowPtr window = std::static_pointer_cast<RenderWindow>(target);
+			*position = window->screenToWindowPos(*position);
+		}
+		else
+		{
+			RenderTexturePtr texture = std::static_pointer_cast<RenderTexture>(target);
+
+			RenderWindowPtr window = GUIManager::instance().getBridgeWindow(texture);
+			if (window == nullptr)
+				return;
+
+			*position = window->screenToWindowPos(*position);
+			*position = GUIManager::instance().windowToBridgedCoords(target, *position);
+		}		
+	}
+
+	void ScriptInput::internal_getPointerScreenPosition(Vector2I* position)
+	{
+		*position = Input::instance().getPointerPosition();
+	}
+
+	void ScriptInput::internal_getPointerDelta(Vector2I* position)
+	{
+		*position = Input::instance().getPointerDelta();
+	}
 }