Răsfoiți Sursa

Managed joints and rigidbodies now properly reference their parent components
Fixing crash when exiting play-mode while physics element are interacting
Fixed crash on shutdown caused by the physics plugin being unloaded before the physics resources were released

BearishSun 10 ani în urmă
părinte
comite
0d7ee2ee0e

+ 1 - 1
Documentation/GitHub/features.md

@@ -34,7 +34,7 @@ Here you will find a complete list of all currently available features. New feat
   * Supports arbitrary 3D transformations
   * Localization support (string tables)
 * __Input__
-  * Mouse/Keyboard/Gamepad support
+  * Mouse/keyboard/gamepad support
   * Provides both raw and OS input
   * Virtual input with built-in key mapping
   * Virtual axes for analog input devices

+ 4 - 1
Source/BansheeCore/Source/BsCoreApplication.cpp

@@ -58,7 +58,6 @@ namespace BansheeEngine
 		mPrimaryWindow->destroy();
 		mPrimaryWindow = nullptr;
 
-		PhysicsManager::shutDown();
 		Importer::shutDown();
 		FontManager::shutDown();
 		MaterialManager::shutDown();
@@ -75,6 +74,10 @@ namespace BansheeEngine
 		GameObjectManager::shutDown();
 		RenderStateManager::shutDown();
 
+		// This must be done after all resources are released since it will unload the physics plugin, and some resources
+		// might be instances of types from that plugin.
+		PhysicsManager::shutDown();
+
 		RendererManager::shutDown();
 
 		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so

+ 56 - 59
Source/BansheeCore/Source/BsResource.cpp

@@ -1,60 +1,57 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsResource.h"
-#include "BsResourceRTTI.h"
-#include "BsResources.h"
-#include "BsUUID.h"
-#include "BsResourceMetaData.h"
-#include "BsRenderAPI.h"
-
-namespace BansheeEngine
-{
-	Resource::Resource(bool initializeOnRenderThread)
-		:CoreObject(initializeOnRenderThread), mSize(0)
-	{ 
-		mMetaData = bs_shared_ptr_new<ResourceMetaData>();
-	}
-
-	const WString& Resource::getName() const 
-	{ 
-		return mMetaData->displayName; 
-	}
-
-	void Resource::setName(const WString& name) 
-	{ 
-		mMetaData->displayName = name; 
-	}
-
-	bool Resource::areDependenciesLoaded() const
-	{
-		bs_frame_mark();
-
-		bool areLoaded = true;
-		{
-			FrameVector<HResource> dependencies;
-			getResourceDependencies(dependencies);
-
-			for (auto& dependency : dependencies)
-			{
-				if (dependency != nullptr && !dependency.isLoaded())
-				{
-					areLoaded = false;
-					break;
-				}
-			}
-		}
-
-		bs_frame_clear();
-		return areLoaded;
-	}
-
-	RTTITypeBase* Resource::getRTTIStatic()
-	{
-		return ResourceRTTI::instance();
-	}
-
-	RTTITypeBase* Resource::getRTTI() const
-	{
-		return Resource::getRTTIStatic();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsResource.h"
+#include "BsResourceRTTI.h"
+#include "BsResourceMetaData.h"
+
+namespace BansheeEngine
+{
+	Resource::Resource(bool initializeOnRenderThread)
+		:CoreObject(initializeOnRenderThread), mSize(0)
+	{ 
+		mMetaData = bs_shared_ptr_new<ResourceMetaData>();
+	}
+
+	const WString& Resource::getName() const 
+	{ 
+		return mMetaData->displayName; 
+	}
+
+	void Resource::setName(const WString& name) 
+	{ 
+		mMetaData->displayName = name; 
+	}
+
+	bool Resource::areDependenciesLoaded() const
+	{
+		bs_frame_mark();
+
+		bool areLoaded = true;
+		{
+			FrameVector<HResource> dependencies;
+			getResourceDependencies(dependencies);
+
+			for (auto& dependency : dependencies)
+			{
+				if (dependency != nullptr && !dependency.isLoaded())
+				{
+					areLoaded = false;
+					break;
+				}
+			}
+		}
+
+		bs_frame_clear();
+		return areLoaded;
+	}
+
+	RTTITypeBase* Resource::getRTTIStatic()
+	{
+		return ResourceRTTI::instance();
+	}
+
+	RTTITypeBase* Resource::getRTTI() const
+	{
+		return Resource::getRTTIStatic();
+	}
 }

+ 757 - 752
Source/BansheeCore/Source/BsResources.cpp

@@ -1,753 +1,758 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsResources.h"
-#include "BsResource.h"
-#include "BsResourceManifest.h"
-#include "BsException.h"
-#include "BsFileSerializer.h"
-#include "BsFileSystem.h"
-#include "BsTaskScheduler.h"
-#include "BsUUID.h"
-#include "BsDebug.h"
-#include "BsUtility.h"
-#include "BsSavedResourceData.h"
-#include "BsResourceListenerManager.h"
-
-namespace BansheeEngine
-{
-	Resources::Resources()
-	{
-		mDefaultResourceManifest = ResourceManifest::create("Default");
-		mResourceManifests.push_back(mDefaultResourceManifest);
-	}
-
-	Resources::~Resources()
-	{
-		// Unload and invalidate all resources
-		UnorderedMap<String, LoadedResourceData> loadedResourcesCopy = mLoadedResources;
-
-		for (auto& loadedResourcePair : loadedResourcesCopy)
-			destroy(loadedResourcePair.second.resource);
-	}
-
-	HResource Resources::load(const Path& filePath, bool loadDependencies, bool keepInternalReference)
-	{
-		if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			return HResource();
-		}
-
-		String uuid;
-		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
-
-		if (!foundUUID)
-			uuid = UUIDGenerator::generateRandom();
-
-		return loadInternal(uuid, filePath, true, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::load(const WeakResourceHandle<Resource>& handle, bool loadDependencies, bool keepInternalReference)
-	{
-		if (handle.mData == nullptr)
-			return HResource();
-
-		String uuid = handle.getUUID();
-		return loadFromUUID(uuid, false, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference)
-	{
-		if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			return HResource();
-		}
-
-		String uuid;
-		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
-
-		if (!foundUUID)
-			uuid = UUIDGenerator::generateRandom();
-
-		return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies, bool keepInternalReference)
-	{
-		Path filePath;
-
-		// Default manifest is at 0th index but all other take priority since Default manifest could
-		// contain obsolete data. 
-		for (auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
-		{
-			if ((*iter)->uuidToFilePath(uuid, filePath))
-				break;
-		}
-
-		return loadInternal(uuid, filePath, !async, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference)
-	{
-		HResource outputResource;
-
-		bool alreadyLoading = false;
-		bool loadInProgress = false;
-		{
-			// Check if resource is already being loaded on a worker thread
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(UUID);
-			if (iterFind2 != mInProgressResources.end())
-			{
-				LoadedResourceData& resData = iterFind2->second->resData;
-				outputResource = resData.resource.lock();
-
-				if (keepInternalReference)
-				{
-					resData.numInternalRefs++;
-					outputResource.addInternalRef();
-				}
-
-				alreadyLoading = true;
-				loadInProgress = true;
-			}
-
-			// Previously being loaded as async but now we want it synced, so we wait
-			if (loadInProgress && synchronous)
-				outputResource.blockUntilLoaded();
-
-			if (!alreadyLoading)
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end()) // Resource is already loaded
-				{
-					LoadedResourceData& resData = iterFind->second;
-					outputResource = resData.resource.lock();
-
-					if (keepInternalReference)
-					{
-						resData.numInternalRefs++;
-						outputResource.addInternalRef();
-					}
-
-					alreadyLoading = true;
-				}
-			}
-		}
-
-		// Not loaded and not in progress, start loading of new resource
-		// (or if already loaded or in progress, load any dependencies)
-		if (!alreadyLoading)
-		{
-			// Check if the handle already exists
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			auto iterFind = mHandles.find(UUID);
-			if (iterFind != mHandles.end())
-				outputResource = iterFind->second.lock();
-			else
-			{
-				outputResource = HResource(UUID);
-				mHandles[UUID] = outputResource.getWeak();
-			}			
-		}
-
-		// We have nowhere to load from, warn and complete load if a file path was provided,
-		// otherwise pass through as we might just want to load from memory. 
-		if (filePath.isEmpty())
-		{
-			if (!alreadyLoading)
-			{
-				LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
-
-				// Complete the load as that the depedency counter is properly reduced, in case this 
-				// is a dependency of some other resource.
-				loadComplete(outputResource);
-				return outputResource;
-			}
-		}
-		else if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			// Complete the load as that the depedency counter is properly reduced, in case this 
-			// is a dependency of some other resource.
-			loadComplete(outputResource);
-			assert(!loadInProgress); // Resource already being loaded but we can't find its path now?
-
-			return outputResource;
-		}
-
-		// Load dependency data if a file path is provided
-		SPtr<SavedResourceData> savedResourceData;
-		if (!filePath.isEmpty())
-		{
-			FileDecoder fs(filePath);
-			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
-		}
-
-		// If already loading keep the old load operation active, otherwise create a new one
-		if (!alreadyLoading)
-		{
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-				ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
-				mInProgressResources[UUID] = loadData;
-				loadData->resData = outputResource.getWeak();
-
-				if (keepInternalReference)
-				{
-					loadData->resData.numInternalRefs++;
-					outputResource.addInternalRef();
-				}
-
-				loadData->remainingDependencies = 1;
-				loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
-
-				// Register dependencies and count them so we know when the resource is fully loaded
-				if (loadDependencies && savedResourceData != nullptr)
-				{
-					for (auto& dependency : savedResourceData->getDependencies())
-					{
-						if (dependency != UUID)
-						{
-							mDependantLoads[dependency].push_back(loadData);
-							loadData->remainingDependencies++;
-						}
-					}
-				}
-			}
-
-			if (loadDependencies && savedResourceData != nullptr)
-			{
-				const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies();
-				UINT32 numDependencies = (UINT32)dependencyUUIDs.size();
-				Vector<HResource> dependencies(numDependencies);
-
-				for (UINT32 i = 0; i < numDependencies; i++)
-					dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false);
-
-				// Keep dependencies alive until the parent is done loading
-				{
-					BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-					// At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list
-					mInProgressResources[UUID]->dependencies = dependencies;
-				}
-			}
-		}
-		else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded
-		{
-			const Vector<String>& dependencies = savedResourceData->getDependencies();
-			if (!dependencies.empty())
-			{
-				{
-					BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-					ResourceLoadData* loadData = nullptr;
-
-					auto iterFind = mInProgressResources.find(UUID);
-					if (iterFind == mInProgressResources.end()) // Fully loaded
-					{
-						loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
-						loadData->resData = outputResource.getWeak();
-						loadData->remainingDependencies = 0;
-						loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
-
-						mInProgressResources[UUID] = loadData;
-					}
-					else
-					{
-						loadData = iterFind->second;
-					}
-
-					// Register dependencies and count them so we know when the resource is fully loaded
-					for (auto& dependency : dependencies)
-					{
-						if (dependency != UUID)
-						{
-							bool registerDependency = true;
-
-							auto iterFind2 = mDependantLoads.find(dependency);
-							if (iterFind2 != mDependantLoads.end())
-							{
-								Vector<ResourceLoadData*>& dependantData = iterFind2->second;
-								auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(),
-									[&](ResourceLoadData* x)
-								{
-									return x->resData.resource.getUUID() == outputResource.getUUID();
-								});
-
-								registerDependency = iterFind3 == dependantData.end();
-							}
-
-							if (registerDependency)
-							{
-								mDependantLoads[dependency].push_back(loadData);
-								loadData->remainingDependencies++;
-								loadData->dependencies.push_back(_getResourceHandle(dependency));
-							}
-						}
-					}
-				}
-
-				for (auto& dependency : dependencies)
-					loadFromUUID(dependency, !synchronous, true, false);
-			}
-		}
-
-		// Actually start the file read operation if not already loaded or in progress
-		if (!alreadyLoading && !filePath.isEmpty())
-		{
-			// Synchronous or the resource doesn't support async, read the file immediately
-			if (synchronous || !savedResourceData->allowAsyncLoading())
-			{
-				loadCallback(filePath, outputResource);
-			}
-			else // Asynchronous, read the file on a worker thread
-			{
-				String fileName = filePath.getFilename();
-				String taskName = "Resource load: " + fileName;
-
-				TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource));
-				TaskScheduler::instance().addTask(task);
-			}
-		}
-		else // File already loaded or in progress
-		{
-			// Complete the load unless its in progress in which case we wait for its worker thread to complete it.
-			// In case file is already loaded this will only decrement dependency count in case this resource is a dependency.
-			if (!loadInProgress)
-				loadComplete(outputResource);
-			else
-			{
-				// In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered,
-				// so trigger it manually so that the dependency count is properly decremented in case this resource
-				// is a dependency.
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end())
-					loadComplete(outputResource);
-			}
-		}
-
-		return outputResource;
-	}
-
-	ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
-	{
-		FileDecoder fs(filePath);
-		fs.skip(); // Skipped over saved resource data
-		std::shared_ptr<IReflectable> loadedData = fs.decode();
-
-		if (loadedData == nullptr)
-		{
-			LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
-		}
-		else
-		{
-			if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
-				BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
-		}
-
-		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
-		return resource;
-	}
-
-	void Resources::release(ResourceHandleBase& resource)
-	{
-		const String& UUID = resource.getUUID();
-
-		{
-			bool loadInProgress = false;
-
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(UUID);
-			if (iterFind2 != mInProgressResources.end())
-				loadInProgress = true;
-
-			// Technically we should be able to just cancel a load in progress instead of blocking until it finishes.
-			// However that would mean the last reference could get lost on whatever thread did the loading, which
-			// isn't something that's supported. If this ends up being a problem either make handle counting atomic
-			// or add a separate queue for objects destroyed from the load threads.
-			if (loadInProgress)
-				resource.blockUntilLoaded();
-
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end()) // Resource is already loaded
-				{
-					LoadedResourceData& resData = iterFind->second;
-
-					assert(resData.numInternalRefs > 0);
-					resData.numInternalRefs--;
-					resource.removeInternalRef();
-
-					return;
-				}
-			}
-		}
-	}
-
-	void Resources::unloadAllUnused()
-	{
-		Vector<HResource> resourcesToUnload;
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			for(auto iter = mLoadedResources.begin(); iter != mLoadedResources.end(); ++iter)
-			{
-				const LoadedResourceData& resData = iter->second;
-
-				if (resData.resource.mData->mRefCount == resData.numInternalRefs) // Only internal references exist, free it
-					resourcesToUnload.push_back(resData.resource.lock());
-			}
-		}
-
-		// Note: When unloading multiple resources it's possible that unloading one will also unload
-		// another resource in "resourcesToUnload". This is fine because "unload" deals with invalid
-		// handles gracefully.
-		for(auto iter = resourcesToUnload.begin(); iter != resourcesToUnload.end(); ++iter)
-		{
-			release(*iter);
-		}
-	}
-
-	void Resources::destroy(ResourceHandleBase& resource)
-	{
-		if (resource.mData == nullptr)
-			return;
-
-		const String& uuid = resource.getUUID();
-		if (!resource.isLoaded(false))
-		{
-			bool loadInProgress = false;
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-				auto iterFind2 = mInProgressResources.find(uuid);
-				if (iterFind2 != mInProgressResources.end())
-					loadInProgress = true;
-			}
-
-			if (loadInProgress) // If it's still loading wait until that finishes
-				resource.blockUntilLoaded();
-			else
-				return; // Already unloaded
-		}
-
-		// Notify external systems before we actually destroy it
-		onResourceDestroyed(uuid);
-		resource.mData->mPtr->destroy();
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-			auto iterFind = mLoadedResources.find(uuid);
-			if (iterFind != mLoadedResources.end())
-			{
-				LoadedResourceData& resData = iterFind->second;
-				while (resData.numInternalRefs > 0)
-				{
-					resData.numInternalRefs--;
-					resData.resource.removeInternalRef();
-				}
-
-				mLoadedResources.erase(iterFind);
-			}
-			else
-			{
-				assert(false); // This should never happen but in case it does fail silently in release mode
-			}
-		}
-
-		resource.setHandleData(nullptr, uuid);
-	}
-
-	void Resources::save(const HResource& resource, const Path& filePath, bool overwrite)
-	{
-		if (resource == nullptr)
-			return;
-
-		if (!resource.isLoaded(false))
-		{
-			bool loadInProgress = false;
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-				auto iterFind2 = mInProgressResources.find(resource.getUUID());
-				if (iterFind2 != mInProgressResources.end())
-					loadInProgress = true;
-			}
-
-			if (loadInProgress) // If it's still loading wait until that finishes
-				resource.blockUntilLoaded();
-			else
-				return; // Nothing to save
-		}
-
-		bool fileExists = FileSystem::isFile(filePath);
-		if(fileExists)
-		{
-			if(overwrite)
-				FileSystem::remove(filePath);
-			else
-				BS_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
-		}
-
-		mDefaultResourceManifest->registerResource(resource.getUUID(), filePath);
-
-		Vector<ResourceDependency> dependencyList = Utility::findResourceDependencies(*resource.get());
-
-		Vector<String> dependencyUUIDs(dependencyList.size());
-		for (UINT32 i = 0; i < (UINT32)dependencyList.size(); i++)
-			dependencyUUIDs[i] = dependencyList[i].resource.getUUID();
-
-		SPtr<SavedResourceData> resourceData = bs_shared_ptr_new<SavedResourceData>(dependencyUUIDs, resource->allowAsyncLoading());
-
-		FileEncoder fs(filePath);
-		fs.encode(resourceData.get());
-		fs.encode(resource.get());
-	}
-
-	void Resources::save(const HResource& resource)
-	{
-		if (resource == nullptr)
-			return;
-
-		Path path;
-		if (getFilePathFromUUID(resource.getUUID(), path))
-			save(resource, path, true);
-	}
-
-	void Resources::update(HResource& handle, const ResourcePtr& resource)
-	{
-		const String& uuid = handle.getUUID();
-		handle.setHandleData(resource, uuid);
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			auto iterFind = mLoadedResources.find(uuid);
-			if (iterFind == mLoadedResources.end())
-			{
-				LoadedResourceData& resData = mLoadedResources[uuid];
-				resData.resource = handle.getWeak();
-			}
-		}
-
-		onResourceModified(handle);
-	}
-
-	Vector<String> Resources::getDependencies(const Path& filePath)
-	{
-		SPtr<SavedResourceData> savedResourceData;
-		if (!filePath.isEmpty())
-		{
-			FileDecoder fs(filePath);
-			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
-		}
-
-		return savedResourceData->getDependencies();
-	}
-
-	void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
-	{
-		if(manifest->getName() == "Default")
-			return;
-
-		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
-		if(findIter == mResourceManifests.end())
-			mResourceManifests.push_back(manifest);
-		else
-			*findIter = manifest;
-	}
-
-	void Resources::unregisterResourceManifest(const ResourceManifestPtr& manifest)
-	{
-		if (manifest->getName() == "Default")
-			return;
-
-		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
-		if (findIter != mResourceManifests.end())
-			mResourceManifests.erase(findIter);
-	}
-
-	ResourceManifestPtr Resources::getResourceManifest(const String& name) const
-	{
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if(name == (*iter)->getName())
-				return (*iter);
-		}
-
-		return nullptr;
-	}
-
-	bool Resources::isLoaded(const String& uuid, bool checkInProgress)
-	{
-		if (checkInProgress)
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(uuid);
-			if (iterFind2 != mInProgressResources.end())
-			{
-				return true;
-			}
-
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(uuid);
-				if (iterFind != mLoadedResources.end())
-				{
-					return true;
-				}
-			}
-		}
-
-		return false;
-	}
-
-	HResource Resources::_createResourceHandle(const ResourcePtr& obj)
-	{
-		String uuid = UUIDGenerator::generateRandom();
-		HResource newHandle(obj, uuid);
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-			LoadedResourceData& resData = mLoadedResources[uuid];
-			resData.resource = newHandle.getWeak();
-			mHandles[uuid] = newHandle.getWeak();
-		}
-	
-		return newHandle;
-	}
-
-	HResource Resources::_getResourceHandle(const String& uuid)
-	{
-		BS_LOCK_MUTEX(mLoadedResourceMutex);
-		auto iterFind3 = mHandles.find(uuid);
-		if (iterFind3 != mHandles.end()) // Not loaded, but handle does exist
-		{
-			return iterFind3->second.lock();
-		}
-
-		// Create new handle
-		HResource handle(uuid);
-		mHandles[uuid] = handle.getWeak();
-
-		return handle;
-	}
-
-	bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
-	{
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if((*iter)->uuidToFilePath(uuid, filePath))
-				return true;
-		}
-
-		return false;
-	}
-
-	bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
-	{
-		Path manifestPath = path;
-		if (!manifestPath.isAbsolute())
-			manifestPath.makeAbsolute(FileSystem::getWorkingDirectoryPath());
-
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if ((*iter)->filePathToUUID(manifestPath, uuid))
-				return true;
-		}
-
-		return false;
-	}
-
-	void Resources::loadComplete(HResource& resource)
-	{
-		String uuid = resource.getUUID();
-
-		ResourceLoadData* myLoadData = nullptr;
-		bool finishLoad = true;
-		Vector<ResourceLoadData*> dependantLoads;
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-			auto iterFind = mInProgressResources.find(uuid);
-			if (iterFind != mInProgressResources.end())
-			{
-				myLoadData = iterFind->second;
-				finishLoad = myLoadData->remainingDependencies == 0;
-				
-				if (finishLoad)
-					mInProgressResources.erase(iterFind);
-			}
-
-			auto iterFind2 = mDependantLoads.find(uuid);
-
-			if (iterFind2 != mDependantLoads.end())
-				dependantLoads = iterFind2->second;
-
-			if (finishLoad)
-			{
-				mDependantLoads.erase(uuid);
-
-				// If loadedData is null then we're probably completing load on an already loaded resource, triggered
-				// by its dependencies.
-				if (myLoadData != nullptr && myLoadData->loadedData != nullptr)
-				{
-					BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-					mLoadedResources[uuid] = myLoadData->resData;
-					resource.setHandleData(myLoadData->loadedData, uuid);
-				}
-
-				for (auto& dependantLoad : dependantLoads)
-					dependantLoad->remainingDependencies--;
-			}
-		}
-
-		for (auto& dependantLoad : dependantLoads)
-		{
-			HResource dependant = dependantLoad->resData.resource.lock();
-			loadComplete(dependant);
-		}
-
-		if (finishLoad && myLoadData != nullptr)
-		{
-			onResourceLoaded(resource);
-
-			// This should only ever be true on the main thread
-			if (myLoadData->notifyImmediately)
-				ResourceListenerManager::instance().notifyListeners(uuid);
-
-			bs_delete(myLoadData);
-		}
-	}
-
-	void Resources::loadCallback(const Path& filePath, HResource& resource)
-	{
-		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
-
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-			// Check if all my dependencies are loaded
-			ResourceLoadData* myLoadData = mInProgressResources[resource.getUUID()];
-			myLoadData->loadedData = rawResource;
-			myLoadData->remainingDependencies--;
-		}
-
-		loadComplete(resource);
-	}
-
-	BS_CORE_EXPORT Resources& gResources()
-	{
-		return Resources::instance();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsResources.h"
+#include "BsResource.h"
+#include "BsResourceManifest.h"
+#include "BsException.h"
+#include "BsFileSerializer.h"
+#include "BsFileSystem.h"
+#include "BsTaskScheduler.h"
+#include "BsUUID.h"
+#include "BsDebug.h"
+#include "BsUtility.h"
+#include "BsSavedResourceData.h"
+#include "BsResourceListenerManager.h"
+
+namespace BansheeEngine
+{
+	Resources::Resources()
+	{
+		mDefaultResourceManifest = ResourceManifest::create("Default");
+		mResourceManifests.push_back(mDefaultResourceManifest);
+	}
+
+	Resources::~Resources()
+	{
+		// Unload and invalidate all resources
+		UnorderedMap<String, LoadedResourceData> loadedResourcesCopy;
+		
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex)
+			loadedResourcesCopy = mLoadedResources;
+		}
+
+		for (auto& loadedResourcePair : loadedResourcesCopy)
+			destroy(loadedResourcePair.second.resource);
+	}
+
+	HResource Resources::load(const Path& filePath, bool loadDependencies, bool keepInternalReference)
+	{
+		if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			return HResource();
+		}
+
+		String uuid;
+		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
+
+		if (!foundUUID)
+			uuid = UUIDGenerator::generateRandom();
+
+		return loadInternal(uuid, filePath, true, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::load(const WeakResourceHandle<Resource>& handle, bool loadDependencies, bool keepInternalReference)
+	{
+		if (handle.mData == nullptr)
+			return HResource();
+
+		String uuid = handle.getUUID();
+		return loadFromUUID(uuid, false, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference)
+	{
+		if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			return HResource();
+		}
+
+		String uuid;
+		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
+
+		if (!foundUUID)
+			uuid = UUIDGenerator::generateRandom();
+
+		return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies, bool keepInternalReference)
+	{
+		Path filePath;
+
+		// Default manifest is at 0th index but all other take priority since Default manifest could
+		// contain obsolete data. 
+		for (auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
+		{
+			if ((*iter)->uuidToFilePath(uuid, filePath))
+				break;
+		}
+
+		return loadInternal(uuid, filePath, !async, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference)
+	{
+		HResource outputResource;
+
+		bool alreadyLoading = false;
+		bool loadInProgress = false;
+		{
+			// Check if resource is already being loaded on a worker thread
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(UUID);
+			if (iterFind2 != mInProgressResources.end())
+			{
+				LoadedResourceData& resData = iterFind2->second->resData;
+				outputResource = resData.resource.lock();
+
+				if (keepInternalReference)
+				{
+					resData.numInternalRefs++;
+					outputResource.addInternalRef();
+				}
+
+				alreadyLoading = true;
+				loadInProgress = true;
+			}
+
+			// Previously being loaded as async but now we want it synced, so we wait
+			if (loadInProgress && synchronous)
+				outputResource.blockUntilLoaded();
+
+			if (!alreadyLoading)
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end()) // Resource is already loaded
+				{
+					LoadedResourceData& resData = iterFind->second;
+					outputResource = resData.resource.lock();
+
+					if (keepInternalReference)
+					{
+						resData.numInternalRefs++;
+						outputResource.addInternalRef();
+					}
+
+					alreadyLoading = true;
+				}
+			}
+		}
+
+		// Not loaded and not in progress, start loading of new resource
+		// (or if already loaded or in progress, load any dependencies)
+		if (!alreadyLoading)
+		{
+			// Check if the handle already exists
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			auto iterFind = mHandles.find(UUID);
+			if (iterFind != mHandles.end())
+				outputResource = iterFind->second.lock();
+			else
+			{
+				outputResource = HResource(UUID);
+				mHandles[UUID] = outputResource.getWeak();
+			}			
+		}
+
+		// We have nowhere to load from, warn and complete load if a file path was provided,
+		// otherwise pass through as we might just want to load from memory. 
+		if (filePath.isEmpty())
+		{
+			if (!alreadyLoading)
+			{
+				LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
+
+				// Complete the load as that the depedency counter is properly reduced, in case this 
+				// is a dependency of some other resource.
+				loadComplete(outputResource);
+				return outputResource;
+			}
+		}
+		else if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			// Complete the load as that the depedency counter is properly reduced, in case this 
+			// is a dependency of some other resource.
+			loadComplete(outputResource);
+			assert(!loadInProgress); // Resource already being loaded but we can't find its path now?
+
+			return outputResource;
+		}
+
+		// Load dependency data if a file path is provided
+		SPtr<SavedResourceData> savedResourceData;
+		if (!filePath.isEmpty())
+		{
+			FileDecoder fs(filePath);
+			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
+		}
+
+		// If already loading keep the old load operation active, otherwise create a new one
+		if (!alreadyLoading)
+		{
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+				ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
+				mInProgressResources[UUID] = loadData;
+				loadData->resData = outputResource.getWeak();
+
+				if (keepInternalReference)
+				{
+					loadData->resData.numInternalRefs++;
+					outputResource.addInternalRef();
+				}
+
+				loadData->remainingDependencies = 1;
+				loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
+
+				// Register dependencies and count them so we know when the resource is fully loaded
+				if (loadDependencies && savedResourceData != nullptr)
+				{
+					for (auto& dependency : savedResourceData->getDependencies())
+					{
+						if (dependency != UUID)
+						{
+							mDependantLoads[dependency].push_back(loadData);
+							loadData->remainingDependencies++;
+						}
+					}
+				}
+			}
+
+			if (loadDependencies && savedResourceData != nullptr)
+			{
+				const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies();
+				UINT32 numDependencies = (UINT32)dependencyUUIDs.size();
+				Vector<HResource> dependencies(numDependencies);
+
+				for (UINT32 i = 0; i < numDependencies; i++)
+					dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false);
+
+				// Keep dependencies alive until the parent is done loading
+				{
+					BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+					// At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list
+					mInProgressResources[UUID]->dependencies = dependencies;
+				}
+			}
+		}
+		else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded
+		{
+			const Vector<String>& dependencies = savedResourceData->getDependencies();
+			if (!dependencies.empty())
+			{
+				{
+					BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+					ResourceLoadData* loadData = nullptr;
+
+					auto iterFind = mInProgressResources.find(UUID);
+					if (iterFind == mInProgressResources.end()) // Fully loaded
+					{
+						loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
+						loadData->resData = outputResource.getWeak();
+						loadData->remainingDependencies = 0;
+						loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
+
+						mInProgressResources[UUID] = loadData;
+					}
+					else
+					{
+						loadData = iterFind->second;
+					}
+
+					// Register dependencies and count them so we know when the resource is fully loaded
+					for (auto& dependency : dependencies)
+					{
+						if (dependency != UUID)
+						{
+							bool registerDependency = true;
+
+							auto iterFind2 = mDependantLoads.find(dependency);
+							if (iterFind2 != mDependantLoads.end())
+							{
+								Vector<ResourceLoadData*>& dependantData = iterFind2->second;
+								auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(),
+									[&](ResourceLoadData* x)
+								{
+									return x->resData.resource.getUUID() == outputResource.getUUID();
+								});
+
+								registerDependency = iterFind3 == dependantData.end();
+							}
+
+							if (registerDependency)
+							{
+								mDependantLoads[dependency].push_back(loadData);
+								loadData->remainingDependencies++;
+								loadData->dependencies.push_back(_getResourceHandle(dependency));
+							}
+						}
+					}
+				}
+
+				for (auto& dependency : dependencies)
+					loadFromUUID(dependency, !synchronous, true, false);
+			}
+		}
+
+		// Actually start the file read operation if not already loaded or in progress
+		if (!alreadyLoading && !filePath.isEmpty())
+		{
+			// Synchronous or the resource doesn't support async, read the file immediately
+			if (synchronous || !savedResourceData->allowAsyncLoading())
+			{
+				loadCallback(filePath, outputResource);
+			}
+			else // Asynchronous, read the file on a worker thread
+			{
+				String fileName = filePath.getFilename();
+				String taskName = "Resource load: " + fileName;
+
+				TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource));
+				TaskScheduler::instance().addTask(task);
+			}
+		}
+		else // File already loaded or in progress
+		{
+			// Complete the load unless its in progress in which case we wait for its worker thread to complete it.
+			// In case file is already loaded this will only decrement dependency count in case this resource is a dependency.
+			if (!loadInProgress)
+				loadComplete(outputResource);
+			else
+			{
+				// In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered,
+				// so trigger it manually so that the dependency count is properly decremented in case this resource
+				// is a dependency.
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end())
+					loadComplete(outputResource);
+			}
+		}
+
+		return outputResource;
+	}
+
+	ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
+	{
+		FileDecoder fs(filePath);
+		fs.skip(); // Skipped over saved resource data
+		std::shared_ptr<IReflectable> loadedData = fs.decode();
+
+		if (loadedData == nullptr)
+		{
+			LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
+		}
+		else
+		{
+			if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
+				BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
+		}
+
+		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
+		return resource;
+	}
+
+	void Resources::release(ResourceHandleBase& resource)
+	{
+		const String& UUID = resource.getUUID();
+
+		{
+			bool loadInProgress = false;
+
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(UUID);
+			if (iterFind2 != mInProgressResources.end())
+				loadInProgress = true;
+
+			// Technically we should be able to just cancel a load in progress instead of blocking until it finishes.
+			// However that would mean the last reference could get lost on whatever thread did the loading, which
+			// isn't something that's supported. If this ends up being a problem either make handle counting atomic
+			// or add a separate queue for objects destroyed from the load threads.
+			if (loadInProgress)
+				resource.blockUntilLoaded();
+
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end()) // Resource is already loaded
+				{
+					LoadedResourceData& resData = iterFind->second;
+
+					assert(resData.numInternalRefs > 0);
+					resData.numInternalRefs--;
+					resource.removeInternalRef();
+
+					return;
+				}
+			}
+		}
+	}
+
+	void Resources::unloadAllUnused()
+	{
+		Vector<HResource> resourcesToUnload;
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			for(auto iter = mLoadedResources.begin(); iter != mLoadedResources.end(); ++iter)
+			{
+				const LoadedResourceData& resData = iter->second;
+
+				if (resData.resource.mData->mRefCount == resData.numInternalRefs) // Only internal references exist, free it
+					resourcesToUnload.push_back(resData.resource.lock());
+			}
+		}
+
+		// Note: When unloading multiple resources it's possible that unloading one will also unload
+		// another resource in "resourcesToUnload". This is fine because "unload" deals with invalid
+		// handles gracefully.
+		for(auto iter = resourcesToUnload.begin(); iter != resourcesToUnload.end(); ++iter)
+		{
+			release(*iter);
+		}
+	}
+
+	void Resources::destroy(ResourceHandleBase& resource)
+	{
+		if (resource.mData == nullptr)
+			return;
+
+		const String& uuid = resource.getUUID();
+		if (!resource.isLoaded(false))
+		{
+			bool loadInProgress = false;
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+				auto iterFind2 = mInProgressResources.find(uuid);
+				if (iterFind2 != mInProgressResources.end())
+					loadInProgress = true;
+			}
+
+			if (loadInProgress) // If it's still loading wait until that finishes
+				resource.blockUntilLoaded();
+			else
+				return; // Already unloaded
+		}
+
+		// Notify external systems before we actually destroy it
+		onResourceDestroyed(uuid);
+		resource.mData->mPtr->destroy();
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+			auto iterFind = mLoadedResources.find(uuid);
+			if (iterFind != mLoadedResources.end())
+			{
+				LoadedResourceData& resData = iterFind->second;
+				while (resData.numInternalRefs > 0)
+				{
+					resData.numInternalRefs--;
+					resData.resource.removeInternalRef();
+				}
+
+				mLoadedResources.erase(iterFind);
+			}
+			else
+			{
+				assert(false); // This should never happen but in case it does fail silently in release mode
+			}
+		}
+
+		resource.setHandleData(nullptr, uuid);
+	}
+
+	void Resources::save(const HResource& resource, const Path& filePath, bool overwrite)
+	{
+		if (resource == nullptr)
+			return;
+
+		if (!resource.isLoaded(false))
+		{
+			bool loadInProgress = false;
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+				auto iterFind2 = mInProgressResources.find(resource.getUUID());
+				if (iterFind2 != mInProgressResources.end())
+					loadInProgress = true;
+			}
+
+			if (loadInProgress) // If it's still loading wait until that finishes
+				resource.blockUntilLoaded();
+			else
+				return; // Nothing to save
+		}
+
+		bool fileExists = FileSystem::isFile(filePath);
+		if(fileExists)
+		{
+			if(overwrite)
+				FileSystem::remove(filePath);
+			else
+				BS_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
+		}
+
+		mDefaultResourceManifest->registerResource(resource.getUUID(), filePath);
+
+		Vector<ResourceDependency> dependencyList = Utility::findResourceDependencies(*resource.get());
+
+		Vector<String> dependencyUUIDs(dependencyList.size());
+		for (UINT32 i = 0; i < (UINT32)dependencyList.size(); i++)
+			dependencyUUIDs[i] = dependencyList[i].resource.getUUID();
+
+		SPtr<SavedResourceData> resourceData = bs_shared_ptr_new<SavedResourceData>(dependencyUUIDs, resource->allowAsyncLoading());
+
+		FileEncoder fs(filePath);
+		fs.encode(resourceData.get());
+		fs.encode(resource.get());
+	}
+
+	void Resources::save(const HResource& resource)
+	{
+		if (resource == nullptr)
+			return;
+
+		Path path;
+		if (getFilePathFromUUID(resource.getUUID(), path))
+			save(resource, path, true);
+	}
+
+	void Resources::update(HResource& handle, const ResourcePtr& resource)
+	{
+		const String& uuid = handle.getUUID();
+		handle.setHandleData(resource, uuid);
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			auto iterFind = mLoadedResources.find(uuid);
+			if (iterFind == mLoadedResources.end())
+			{
+				LoadedResourceData& resData = mLoadedResources[uuid];
+				resData.resource = handle.getWeak();
+			}
+		}
+
+		onResourceModified(handle);
+	}
+
+	Vector<String> Resources::getDependencies(const Path& filePath)
+	{
+		SPtr<SavedResourceData> savedResourceData;
+		if (!filePath.isEmpty())
+		{
+			FileDecoder fs(filePath);
+			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
+		}
+
+		return savedResourceData->getDependencies();
+	}
+
+	void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
+	{
+		if(manifest->getName() == "Default")
+			return;
+
+		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
+		if(findIter == mResourceManifests.end())
+			mResourceManifests.push_back(manifest);
+		else
+			*findIter = manifest;
+	}
+
+	void Resources::unregisterResourceManifest(const ResourceManifestPtr& manifest)
+	{
+		if (manifest->getName() == "Default")
+			return;
+
+		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
+		if (findIter != mResourceManifests.end())
+			mResourceManifests.erase(findIter);
+	}
+
+	ResourceManifestPtr Resources::getResourceManifest(const String& name) const
+	{
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if(name == (*iter)->getName())
+				return (*iter);
+		}
+
+		return nullptr;
+	}
+
+	bool Resources::isLoaded(const String& uuid, bool checkInProgress)
+	{
+		if (checkInProgress)
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(uuid);
+			if (iterFind2 != mInProgressResources.end())
+			{
+				return true;
+			}
+
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(uuid);
+				if (iterFind != mLoadedResources.end())
+				{
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	HResource Resources::_createResourceHandle(const ResourcePtr& obj)
+	{
+		String uuid = UUIDGenerator::generateRandom();
+		HResource newHandle(obj, uuid);
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+			LoadedResourceData& resData = mLoadedResources[uuid];
+			resData.resource = newHandle.getWeak();
+			mHandles[uuid] = newHandle.getWeak();
+		}
+	
+		return newHandle;
+	}
+
+	HResource Resources::_getResourceHandle(const String& uuid)
+	{
+		BS_LOCK_MUTEX(mLoadedResourceMutex);
+		auto iterFind3 = mHandles.find(uuid);
+		if (iterFind3 != mHandles.end()) // Not loaded, but handle does exist
+		{
+			return iterFind3->second.lock();
+		}
+
+		// Create new handle
+		HResource handle(uuid);
+		mHandles[uuid] = handle.getWeak();
+
+		return handle;
+	}
+
+	bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
+	{
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if((*iter)->uuidToFilePath(uuid, filePath))
+				return true;
+		}
+
+		return false;
+	}
+
+	bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
+	{
+		Path manifestPath = path;
+		if (!manifestPath.isAbsolute())
+			manifestPath.makeAbsolute(FileSystem::getWorkingDirectoryPath());
+
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if ((*iter)->filePathToUUID(manifestPath, uuid))
+				return true;
+		}
+
+		return false;
+	}
+
+	void Resources::loadComplete(HResource& resource)
+	{
+		String uuid = resource.getUUID();
+
+		ResourceLoadData* myLoadData = nullptr;
+		bool finishLoad = true;
+		Vector<ResourceLoadData*> dependantLoads;
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+			auto iterFind = mInProgressResources.find(uuid);
+			if (iterFind != mInProgressResources.end())
+			{
+				myLoadData = iterFind->second;
+				finishLoad = myLoadData->remainingDependencies == 0;
+				
+				if (finishLoad)
+					mInProgressResources.erase(iterFind);
+			}
+
+			auto iterFind2 = mDependantLoads.find(uuid);
+
+			if (iterFind2 != mDependantLoads.end())
+				dependantLoads = iterFind2->second;
+
+			if (finishLoad)
+			{
+				mDependantLoads.erase(uuid);
+
+				// If loadedData is null then we're probably completing load on an already loaded resource, triggered
+				// by its dependencies.
+				if (myLoadData != nullptr && myLoadData->loadedData != nullptr)
+				{
+					BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+					mLoadedResources[uuid] = myLoadData->resData;
+					resource.setHandleData(myLoadData->loadedData, uuid);
+				}
+
+				for (auto& dependantLoad : dependantLoads)
+					dependantLoad->remainingDependencies--;
+			}
+		}
+
+		for (auto& dependantLoad : dependantLoads)
+		{
+			HResource dependant = dependantLoad->resData.resource.lock();
+			loadComplete(dependant);
+		}
+
+		if (finishLoad && myLoadData != nullptr)
+		{
+			onResourceLoaded(resource);
+
+			// This should only ever be true on the main thread
+			if (myLoadData->notifyImmediately)
+				ResourceListenerManager::instance().notifyListeners(uuid);
+
+			bs_delete(myLoadData);
+		}
+	}
+
+	void Resources::loadCallback(const Path& filePath, HResource& resource)
+	{
+		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
+
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+			// Check if all my dependencies are loaded
+			ResourceLoadData* myLoadData = mInProgressResources[resource.getUUID()];
+			myLoadData->loadedData = rawResource;
+			myLoadData->remainingDependencies--;
+		}
+
+		loadComplete(resource);
+	}
+
+	BS_CORE_EXPORT Resources& gResources()
+	{
+		return Resources::instance();
+	}
 }

+ 1 - 0
Source/BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -26,6 +26,7 @@ namespace BansheeEngine
 		if (mStaticBody != nullptr)
 			mStaticBody->release();
 
+		mShape->userData = nullptr;
 		mShape->release();
 	}
 

+ 129 - 128
Source/BansheePhysX/Source/BsFPhysXJoint.cpp

@@ -1,129 +1,130 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsFPhysXJoint.h"
-#include "BsPhysXRigidbody.h"
-#include "PxRigidDynamic.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxJointActorIndex::Enum toJointActor(JointBody body)
-	{
-		if (body == JointBody::A)
-			return PxJointActorIndex::eACTOR0;
-
-		return PxJointActorIndex::eACTOR1;
-	}
-
-	FPhysXJoint::FPhysXJoint(physx::PxJoint* joint)
-		:mJoint(joint)
-	{
-		
-	}
-
-	FPhysXJoint::~FPhysXJoint()
-	{
-		mJoint->release();
-	}
-
-	Rigidbody* FPhysXJoint::getBody(JointBody body) const
-	{
-		PxRigidActor* actorA = nullptr;
-		PxRigidActor* actorB = nullptr;
-
-		mJoint->getActors(actorA, actorB);
-
-		PxRigidActor* wantedActor = body == JointBody::A ? actorA : actorB;
-		if (wantedActor == nullptr)
-			return nullptr;
-
-		return (Rigidbody*)wantedActor->userData;
-	}
-
-	void FPhysXJoint::setBody(JointBody body, Rigidbody* value)
-	{
-		PxRigidActor* actorA = nullptr;
-		PxRigidActor* actorB = nullptr;
-
-		mJoint->getActors(actorA, actorB);
-
-		PxRigidActor* actor = nullptr;
-		if (value != nullptr)
-			actor = static_cast<PhysXRigidbody*>(value)->_getInternal();
-
-		if (body == JointBody::A)
-			actorA = actor;
-		else
-			actorB = actor;
-
-		mJoint->setActors(actorA, actorB);
-	}
-
-	Vector3 FPhysXJoint::getPosition(JointBody body) const
-	{
-		PxVec3 position = mJoint->getLocalPose(toJointActor(body)).p;
-
-		return fromPxVector(position);
-	}
-
-	Quaternion FPhysXJoint::getRotation(JointBody body) const
-	{
-		PxQuat rotation = mJoint->getLocalPose(toJointActor(body)).q;
-
-		return fromPxQuaternion(rotation);
-	}
-
-	void FPhysXJoint::setTransform(JointBody body, const Vector3& position, const Quaternion& rotation)
-	{
-		PxTransform transform = toPxTransform(position, rotation);
-
-		mJoint->setLocalPose(toJointActor(body), transform);
-	}
-
-	float FPhysXJoint::getBreakForce() const
-	{
-		float force = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(force, torque);
-		return force;
-	}
-
-	void FPhysXJoint::setBreakForce(float force)
-	{
-		float dummy = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(dummy, torque);
-		mJoint->setBreakForce(force, torque);
-	}
-
-	float FPhysXJoint::getBreakTorque() const
-	{
-		float force = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(force, torque);
-		return torque;
-	}
-
-	void FPhysXJoint::setBreakTorque(float torque)
-	{
-		float force = 0.0f;
-		float dummy = 0.0f;
-
-		mJoint->getBreakForce(force, dummy);
-		mJoint->setBreakForce(force, torque);
-	}
-
-	bool FPhysXJoint::getEnableCollision() const
-	{
-		return mJoint->getConstraintFlags() & PxConstraintFlag::eCOLLISION_ENABLED;
-	}
-
-	void FPhysXJoint::setEnableCollision(bool value)
-	{
-		mJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value);
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsFPhysXJoint.h"
+#include "BsPhysXRigidbody.h"
+#include "PxRigidDynamic.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxJointActorIndex::Enum toJointActor(JointBody body)
+	{
+		if (body == JointBody::A)
+			return PxJointActorIndex::eACTOR0;
+
+		return PxJointActorIndex::eACTOR1;
+	}
+
+	FPhysXJoint::FPhysXJoint(physx::PxJoint* joint)
+		:mJoint(joint)
+	{
+		
+	}
+
+	FPhysXJoint::~FPhysXJoint()
+	{
+		mJoint->userData = nullptr;
+		mJoint->release();
+	}
+
+	Rigidbody* FPhysXJoint::getBody(JointBody body) const
+	{
+		PxRigidActor* actorA = nullptr;
+		PxRigidActor* actorB = nullptr;
+
+		mJoint->getActors(actorA, actorB);
+
+		PxRigidActor* wantedActor = body == JointBody::A ? actorA : actorB;
+		if (wantedActor == nullptr)
+			return nullptr;
+
+		return (Rigidbody*)wantedActor->userData;
+	}
+
+	void FPhysXJoint::setBody(JointBody body, Rigidbody* value)
+	{
+		PxRigidActor* actorA = nullptr;
+		PxRigidActor* actorB = nullptr;
+
+		mJoint->getActors(actorA, actorB);
+
+		PxRigidActor* actor = nullptr;
+		if (value != nullptr)
+			actor = static_cast<PhysXRigidbody*>(value)->_getInternal();
+
+		if (body == JointBody::A)
+			actorA = actor;
+		else
+			actorB = actor;
+
+		mJoint->setActors(actorA, actorB);
+	}
+
+	Vector3 FPhysXJoint::getPosition(JointBody body) const
+	{
+		PxVec3 position = mJoint->getLocalPose(toJointActor(body)).p;
+
+		return fromPxVector(position);
+	}
+
+	Quaternion FPhysXJoint::getRotation(JointBody body) const
+	{
+		PxQuat rotation = mJoint->getLocalPose(toJointActor(body)).q;
+
+		return fromPxQuaternion(rotation);
+	}
+
+	void FPhysXJoint::setTransform(JointBody body, const Vector3& position, const Quaternion& rotation)
+	{
+		PxTransform transform = toPxTransform(position, rotation);
+
+		mJoint->setLocalPose(toJointActor(body), transform);
+	}
+
+	float FPhysXJoint::getBreakForce() const
+	{
+		float force = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(force, torque);
+		return force;
+	}
+
+	void FPhysXJoint::setBreakForce(float force)
+	{
+		float dummy = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(dummy, torque);
+		mJoint->setBreakForce(force, torque);
+	}
+
+	float FPhysXJoint::getBreakTorque() const
+	{
+		float force = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(force, torque);
+		return torque;
+	}
+
+	void FPhysXJoint::setBreakTorque(float torque)
+	{
+		float force = 0.0f;
+		float dummy = 0.0f;
+
+		mJoint->getBreakForce(force, dummy);
+		mJoint->setBreakForce(force, torque);
+	}
+
+	bool FPhysXJoint::getEnableCollision() const
+	{
+		return mJoint->getConstraintFlags() & PxConstraintFlag::eCOLLISION_ENABLED;
+	}
+
+	void FPhysXJoint::setEnableCollision(bool value)
+	{
+		mJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value);
+	}
 }

+ 23 - 12
Source/BansheePhysX/Source/BsPhysX.cpp

@@ -132,6 +132,8 @@ namespace BansheeEngine
 			for (PxU32 i = 0; i < count; i++)
 			{
 				const PxTriggerPair& pair = pairs[i];
+				if (pair.triggerShape->userData == nullptr)
+					continue;
 				
 				PhysX::ContactEventType type;
 				bool ignoreContact = false;
@@ -270,9 +272,12 @@ namespace BansheeEngine
 					continue;
 
 				PxJoint* pxJoint = (PxJoint*)constraintInfo.externalReference;
-				Joint* joint = (Joint*)pxJoint->userData;
 
-				
+				PhysX::JointBreakEvent event;
+				event.joint = (Joint*)pxJoint->userData;
+
+				if(event.joint != nullptr)
+					gPhysX()._reportJointBreakEvent(event);
 			}
 		}
 	};
@@ -675,19 +680,25 @@ namespace BansheeEngine
 
 		for (auto& entry : mContactEvents)
 		{
-			CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
+			if (entry.colliderA != nullptr)
+			{
+				CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
 
-			if (reportModeA == CollisionReportMode::ReportPersistent)
-				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
-			else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
-				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+				if (reportModeA == CollisionReportMode::ReportPersistent)
+					notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+				else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+					notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+			}
 
-			CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
+			if (entry.colliderB != nullptr)
+			{
+				CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
 
-			if (reportModeB == CollisionReportMode::ReportPersistent)
-				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
-			else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
-				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+				if (reportModeB == CollisionReportMode::ReportPersistent)
+					notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+				else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+					notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+			}
 		}
 
 		for(auto& entry : mJointBreakEvents)

+ 277 - 276
Source/BansheePhysX/Source/BsPhysXCharacterController.cpp

@@ -1,277 +1,278 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXCharacterController.h"
-#include "BsTime.h"
-#include "BsPhysX.h"
-#include "BsCCollider.h"
-#include "characterkinematic\PxControllerManager.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxExtendedVec3 toPxExtVector(const Vector3& input)
-	{
-		return PxExtendedVec3(input.x, input.y, input.z);
-	}
-
-	Vector3 fromPxExtVector(const PxExtendedVec3& input)
-	{
-		return Vector3((float)input.x, (float)input.y, (float)input.z);
-	}
-
-	PxCapsuleClimbingMode::Enum toPxEnum(CharacterClimbingMode value)
-	{
-		return value == CharacterClimbingMode::Normal
-			? PxCapsuleClimbingMode::eEASY
-			: PxCapsuleClimbingMode::eCONSTRAINED;
-	}
-
-	PxControllerNonWalkableMode::Enum toPxEnum(CharacterNonWalkableMode value)
-	{
-		return value == CharacterNonWalkableMode::Prevent
-			? PxControllerNonWalkableMode::ePREVENT_CLIMBING
-			: PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING;
-	}
-
-	CharacterClimbingMode fromPxEnum(PxCapsuleClimbingMode::Enum value)
-	{
-		return value == PxCapsuleClimbingMode::eEASY
-			? CharacterClimbingMode::Normal
-			: CharacterClimbingMode::Constrained;
-	}
-
-	CharacterNonWalkableMode fromPxEnum(PxControllerNonWalkableMode::Enum value)
-	{
-		return value == PxControllerNonWalkableMode::ePREVENT_CLIMBING
-			? CharacterNonWalkableMode::Prevent
-			: CharacterNonWalkableMode::PreventAndSlide;
-	}
-
-	PxCapsuleControllerDesc toPxDesc(const CHAR_CONTROLLER_DESC& desc)
-	{
-		PxCapsuleControllerDesc output;
-		output.climbingMode = toPxEnum(desc.climbingMode);
-		output.nonWalkableMode = toPxEnum(desc.nonWalkableMode);
-		output.contactOffset = desc.contactOffset;
-		output.stepOffset = desc.stepOffset;
-		output.slopeLimit = desc.slopeLimit.valueRadians();
-		output.height = desc.height;
-		output.radius = desc.radius;
-		output.upDirection = toPxVector(desc.up);
-		output.position = toPxExtVector(desc.position);
-
-		return output;
-	}
-
-	PhysXCharacterController::PhysXCharacterController(PxControllerManager* manager, const CHAR_CONTROLLER_DESC& desc)
-		:CharacterController(desc)
-	{
-		PxCapsuleControllerDesc pxDesc = toPxDesc(desc);
-		pxDesc.reportCallback = this;
-
-		mController = static_cast<PxCapsuleController*>(manager->createController(pxDesc));
-		mController->setUserData(this);
-	}
-
-	PhysXCharacterController::~PhysXCharacterController()
-	{
-		mController->release();
-	}
-
-	CharacterCollisionFlags PhysXCharacterController::move(const Vector3& displacement)
-	{
-		PxControllerFilters filters;
-		filters.mFilterCallback = this;
-		filters.mFilterFlags = PxQueryFlag::eANY_HIT | PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC | PxQueryFlag::ePREFILTER;
-		filters.mCCTFilterCallback = this;
-
-		float curTime = gTime().getTime();
-		float delta = curTime - mLastMoveCall;
-		mLastMoveCall = curTime;
-
-		PxControllerCollisionFlags collisionFlag = mController->move(toPxVector(displacement), mMinMoveDistance, delta, filters);
-
-		CharacterCollisionFlags output;
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_DOWN))
-			output.set(CharacterCollisionFlag::Down);
-
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_UP))
-			output.set(CharacterCollisionFlag::Up);
-
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_SIDES))
-			output.set(CharacterCollisionFlag::Sides);
-
-		return output;
-	}
-
-	Vector3 PhysXCharacterController::getPosition() const
-	{
-		return fromPxExtVector(mController->getPosition());
-	}
-
-	void PhysXCharacterController::setPosition(const Vector3& position)
-	{
-		mController->setPosition(toPxExtVector(position));
-	}
-
-	Vector3 PhysXCharacterController::getFootPosition() const
-	{
-		return fromPxExtVector(mController->getFootPosition());
-	}
-
-	void PhysXCharacterController::setFootPosition(const Vector3& position)
-	{
-		mController->setFootPosition(toPxExtVector(position));
-	}
-
-	float PhysXCharacterController::getRadius() const
-	{
-		return mController->getRadius();
-	}
-
-	void PhysXCharacterController::setRadius(float radius)
-	{
-		mController->setRadius(radius);
-	}
-
-	float PhysXCharacterController::getHeight() const
-	{
-		return mController->getHeight();
-	}
-
-	void PhysXCharacterController::setHeight(float height)
-	{
-		mController->setHeight(height);
-	}
-
-	Vector3 PhysXCharacterController::getUp() const
-	{
-		return fromPxVector(mController->getUpDirection());
-	}
-
-	void PhysXCharacterController::setUp(const Vector3& up)
-	{
-		mController->setUpDirection(toPxVector(up));
-	}
-
-	CharacterClimbingMode PhysXCharacterController::getClimbingMode() const
-	{
-		return fromPxEnum(mController->getClimbingMode());
-	}
-
-	void PhysXCharacterController::setClimbingMode(CharacterClimbingMode mode)
-	{
-		mController->setClimbingMode(toPxEnum(mode));
-	}
-
-	CharacterNonWalkableMode PhysXCharacterController::getNonWalkableMode() const
-	{
-		return fromPxEnum(mController->getNonWalkableMode());
-	}
-
-	void PhysXCharacterController::setNonWalkableMode(CharacterNonWalkableMode mode)
-	{
-		mController->setNonWalkableMode(toPxEnum(mode));
-	}
-
-	float PhysXCharacterController::getMinMoveDistance() const
-	{
-		return mMinMoveDistance;
-	}
-
-	void PhysXCharacterController::setMinMoveDistance(float value)
-	{
-		mMinMoveDistance = value;
-	}
-
-	float PhysXCharacterController::getContactOffset() const
-	{
-		return mController->getContactOffset();
-	}
-
-	void PhysXCharacterController::setContactOffset(float value)
-	{
-		mController->setContactOffset(value);
-	}
-
-	float PhysXCharacterController::getStepOffset() const
-	{
-		return mController->getStepOffset();
-	}
-
-	void PhysXCharacterController::setStepOffset(float value)
-	{
-		mController->setStepOffset(value);
-	}
-
-	Radian PhysXCharacterController::getSlopeLimit() const
-	{
-		return Radian(mController->getSlopeLimit());
-	}
-
-	void PhysXCharacterController::setSlopeLimit(Radian value)
-	{
-		mController->setSlopeLimit(value.valueRadians());
-	}
-
-	void PhysXCharacterController::onShapeHit(const PxControllerShapeHit& hit)
-	{
-		if (onColliderHit.empty())
-			return;
-
-		ControllerColliderCollision collision;
-		collision.position = fromPxExtVector(hit.worldPos);
-		collision.normal = fromPxVector(hit.worldNormal);
-		collision.motionDir = fromPxVector(hit.dir);
-		collision.motionAmount = hit.length;
-		collision.triangleIndex = hit.triangleIndex;
-		collision.colliderRaw = (Collider*)hit.shape->userData;
-
-		onColliderHit(collision);
-	}
-
-	void PhysXCharacterController::onControllerHit(const PxControllersHit& hit)
-	{
-		if (CharacterController::onControllerHit.empty())
-			return;
-
-		ControllerControllerCollision collision;
-		collision.position = fromPxExtVector(hit.worldPos);
-		collision.normal = fromPxVector(hit.worldNormal);
-		collision.motionDir = fromPxVector(hit.dir);
-		collision.motionAmount = hit.length;
-		collision.controllerRaw = (CharacterController*)hit.controller->getUserData();
-
-		CharacterController::onControllerHit(collision);
-	}
-
-	PxQueryHitType::Enum PhysXCharacterController::preFilter(const PxFilterData& filterData, const PxShape* shape,
-		const PxRigidActor* actor, PxHitFlags& queryFlags)
-	{
-		PxFilterData colliderFilterData = shape->getSimulationFilterData();
-		UINT64 colliderLayer = *(UINT64*)&colliderFilterData.word0;
-
-		bool canCollide = gPhysics().isCollisionEnabled(colliderLayer, getLayer());
-
-		if(canCollide)
-			return PxSceneQueryHitType::eBLOCK;
-
-		return PxSceneQueryHitType::eNONE;
-	}
-
-	PxQueryHitType::Enum PhysXCharacterController::postFilter(const PxFilterData& filterData,
-		const PxQueryHit& hit)
-	{
-		return PxSceneQueryHitType::eBLOCK;
-	}
-
-	bool PhysXCharacterController::filter(const PxController& a, const PxController& b)
-	{
-		CharacterController* controllerA = (CharacterController*)a.getUserData();
-		CharacterController* controllerB = (CharacterController*)b.getUserData();
-
-		bool canCollide = gPhysics().isCollisionEnabled(controllerA->getLayer(), controllerB->getLayer());
-		return canCollide;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXCharacterController.h"
+#include "BsTime.h"
+#include "BsPhysX.h"
+#include "BsCCollider.h"
+#include "characterkinematic\PxControllerManager.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxExtendedVec3 toPxExtVector(const Vector3& input)
+	{
+		return PxExtendedVec3(input.x, input.y, input.z);
+	}
+
+	Vector3 fromPxExtVector(const PxExtendedVec3& input)
+	{
+		return Vector3((float)input.x, (float)input.y, (float)input.z);
+	}
+
+	PxCapsuleClimbingMode::Enum toPxEnum(CharacterClimbingMode value)
+	{
+		return value == CharacterClimbingMode::Normal
+			? PxCapsuleClimbingMode::eEASY
+			: PxCapsuleClimbingMode::eCONSTRAINED;
+	}
+
+	PxControllerNonWalkableMode::Enum toPxEnum(CharacterNonWalkableMode value)
+	{
+		return value == CharacterNonWalkableMode::Prevent
+			? PxControllerNonWalkableMode::ePREVENT_CLIMBING
+			: PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING;
+	}
+
+	CharacterClimbingMode fromPxEnum(PxCapsuleClimbingMode::Enum value)
+	{
+		return value == PxCapsuleClimbingMode::eEASY
+			? CharacterClimbingMode::Normal
+			: CharacterClimbingMode::Constrained;
+	}
+
+	CharacterNonWalkableMode fromPxEnum(PxControllerNonWalkableMode::Enum value)
+	{
+		return value == PxControllerNonWalkableMode::ePREVENT_CLIMBING
+			? CharacterNonWalkableMode::Prevent
+			: CharacterNonWalkableMode::PreventAndSlide;
+	}
+
+	PxCapsuleControllerDesc toPxDesc(const CHAR_CONTROLLER_DESC& desc)
+	{
+		PxCapsuleControllerDesc output;
+		output.climbingMode = toPxEnum(desc.climbingMode);
+		output.nonWalkableMode = toPxEnum(desc.nonWalkableMode);
+		output.contactOffset = desc.contactOffset;
+		output.stepOffset = desc.stepOffset;
+		output.slopeLimit = desc.slopeLimit.valueRadians();
+		output.height = desc.height;
+		output.radius = desc.radius;
+		output.upDirection = toPxVector(desc.up);
+		output.position = toPxExtVector(desc.position);
+
+		return output;
+	}
+
+	PhysXCharacterController::PhysXCharacterController(PxControllerManager* manager, const CHAR_CONTROLLER_DESC& desc)
+		:CharacterController(desc)
+	{
+		PxCapsuleControllerDesc pxDesc = toPxDesc(desc);
+		pxDesc.reportCallback = this;
+
+		mController = static_cast<PxCapsuleController*>(manager->createController(pxDesc));
+		mController->setUserData(this);
+	}
+
+	PhysXCharacterController::~PhysXCharacterController()
+	{
+		mController->setUserData(nullptr);
+		mController->release();
+	}
+
+	CharacterCollisionFlags PhysXCharacterController::move(const Vector3& displacement)
+	{
+		PxControllerFilters filters;
+		filters.mFilterCallback = this;
+		filters.mFilterFlags = PxQueryFlag::eANY_HIT | PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC | PxQueryFlag::ePREFILTER;
+		filters.mCCTFilterCallback = this;
+
+		float curTime = gTime().getTime();
+		float delta = curTime - mLastMoveCall;
+		mLastMoveCall = curTime;
+
+		PxControllerCollisionFlags collisionFlag = mController->move(toPxVector(displacement), mMinMoveDistance, delta, filters);
+
+		CharacterCollisionFlags output;
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_DOWN))
+			output.set(CharacterCollisionFlag::Down);
+
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_UP))
+			output.set(CharacterCollisionFlag::Up);
+
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_SIDES))
+			output.set(CharacterCollisionFlag::Sides);
+
+		return output;
+	}
+
+	Vector3 PhysXCharacterController::getPosition() const
+	{
+		return fromPxExtVector(mController->getPosition());
+	}
+
+	void PhysXCharacterController::setPosition(const Vector3& position)
+	{
+		mController->setPosition(toPxExtVector(position));
+	}
+
+	Vector3 PhysXCharacterController::getFootPosition() const
+	{
+		return fromPxExtVector(mController->getFootPosition());
+	}
+
+	void PhysXCharacterController::setFootPosition(const Vector3& position)
+	{
+		mController->setFootPosition(toPxExtVector(position));
+	}
+
+	float PhysXCharacterController::getRadius() const
+	{
+		return mController->getRadius();
+	}
+
+	void PhysXCharacterController::setRadius(float radius)
+	{
+		mController->setRadius(radius);
+	}
+
+	float PhysXCharacterController::getHeight() const
+	{
+		return mController->getHeight();
+	}
+
+	void PhysXCharacterController::setHeight(float height)
+	{
+		mController->setHeight(height);
+	}
+
+	Vector3 PhysXCharacterController::getUp() const
+	{
+		return fromPxVector(mController->getUpDirection());
+	}
+
+	void PhysXCharacterController::setUp(const Vector3& up)
+	{
+		mController->setUpDirection(toPxVector(up));
+	}
+
+	CharacterClimbingMode PhysXCharacterController::getClimbingMode() const
+	{
+		return fromPxEnum(mController->getClimbingMode());
+	}
+
+	void PhysXCharacterController::setClimbingMode(CharacterClimbingMode mode)
+	{
+		mController->setClimbingMode(toPxEnum(mode));
+	}
+
+	CharacterNonWalkableMode PhysXCharacterController::getNonWalkableMode() const
+	{
+		return fromPxEnum(mController->getNonWalkableMode());
+	}
+
+	void PhysXCharacterController::setNonWalkableMode(CharacterNonWalkableMode mode)
+	{
+		mController->setNonWalkableMode(toPxEnum(mode));
+	}
+
+	float PhysXCharacterController::getMinMoveDistance() const
+	{
+		return mMinMoveDistance;
+	}
+
+	void PhysXCharacterController::setMinMoveDistance(float value)
+	{
+		mMinMoveDistance = value;
+	}
+
+	float PhysXCharacterController::getContactOffset() const
+	{
+		return mController->getContactOffset();
+	}
+
+	void PhysXCharacterController::setContactOffset(float value)
+	{
+		mController->setContactOffset(value);
+	}
+
+	float PhysXCharacterController::getStepOffset() const
+	{
+		return mController->getStepOffset();
+	}
+
+	void PhysXCharacterController::setStepOffset(float value)
+	{
+		mController->setStepOffset(value);
+	}
+
+	Radian PhysXCharacterController::getSlopeLimit() const
+	{
+		return Radian(mController->getSlopeLimit());
+	}
+
+	void PhysXCharacterController::setSlopeLimit(Radian value)
+	{
+		mController->setSlopeLimit(value.valueRadians());
+	}
+
+	void PhysXCharacterController::onShapeHit(const PxControllerShapeHit& hit)
+	{
+		if (onColliderHit.empty())
+			return;
+
+		ControllerColliderCollision collision;
+		collision.position = fromPxExtVector(hit.worldPos);
+		collision.normal = fromPxVector(hit.worldNormal);
+		collision.motionDir = fromPxVector(hit.dir);
+		collision.motionAmount = hit.length;
+		collision.triangleIndex = hit.triangleIndex;
+		collision.colliderRaw = (Collider*)hit.shape->userData;
+
+		onColliderHit(collision);
+	}
+
+	void PhysXCharacterController::onControllerHit(const PxControllersHit& hit)
+	{
+		if (CharacterController::onControllerHit.empty())
+			return;
+
+		ControllerControllerCollision collision;
+		collision.position = fromPxExtVector(hit.worldPos);
+		collision.normal = fromPxVector(hit.worldNormal);
+		collision.motionDir = fromPxVector(hit.dir);
+		collision.motionAmount = hit.length;
+		collision.controllerRaw = (CharacterController*)hit.controller->getUserData();
+
+		CharacterController::onControllerHit(collision);
+	}
+
+	PxQueryHitType::Enum PhysXCharacterController::preFilter(const PxFilterData& filterData, const PxShape* shape,
+		const PxRigidActor* actor, PxHitFlags& queryFlags)
+	{
+		PxFilterData colliderFilterData = shape->getSimulationFilterData();
+		UINT64 colliderLayer = *(UINT64*)&colliderFilterData.word0;
+
+		bool canCollide = gPhysics().isCollisionEnabled(colliderLayer, getLayer());
+
+		if(canCollide)
+			return PxSceneQueryHitType::eBLOCK;
+
+		return PxSceneQueryHitType::eNONE;
+	}
+
+	PxQueryHitType::Enum PhysXCharacterController::postFilter(const PxFilterData& filterData,
+		const PxQueryHit& hit)
+	{
+		return PxSceneQueryHitType::eBLOCK;
+	}
+
+	bool PhysXCharacterController::filter(const PxController& a, const PxController& b)
+	{
+		CharacterController* controllerA = (CharacterController*)a.getUserData();
+		CharacterController* controllerB = (CharacterController*)b.getUserData();
+
+		bool canCollide = gPhysics().isCollisionEnabled(controllerA->getLayer(), controllerB->getLayer());
+		return canCollide;
+	}
 }

+ 1 - 0
Source/MBansheeEngine/Physics/Joint.cs

@@ -247,6 +247,7 @@ namespace BansheeEngine
         private void RestoreNative()
 	    {
             native = CreateNative();
+            native.Component = this;
 
             // Note: Merge into one call to avoid many virtual function calls
             Rigidbody[] bodies = new Rigidbody[2];

+ 187 - 179
Source/MBansheeEngine/Physics/NativeCharacterController.cs

@@ -1,179 +1,187 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native CharacterController class.
-    /// <see cref="CharacterController"/>
-    /// </summary>
-    internal class NativeCharacterController : ScriptObject
-    {
-        private CharacterController component;
-
-        /// <summary>
-        /// Component that owns the native character controller object.
-        /// </summary>
-        public CharacterController Component
-        {
-            get { return component; }
-            set { component = value; }
-        }
-
-        public Vector3 Position
-        {
-            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
-            set { Internal_SetPosition(mCachedPtr, ref value); }
-        }
-
-        public Vector3 FootPosition
-        {
-            get { Vector3 pos; Internal_GetFootPosition(mCachedPtr, out pos); return pos; }
-            set { Internal_SetFootPosition(mCachedPtr, ref value); }
-        }
-
-        public float Radius
-        {
-            set { Internal_SetRadius(mCachedPtr, value); }
-        }
-
-        public float Height
-        {
-            set { Internal_SetHeight(mCachedPtr, value); }
-        }
-
-        public Vector3 Up
-        {
-            set { Internal_SetUp(mCachedPtr, ref value); }
-        }
-
-        public CharacterClimbingMode ClimbingMode
-        {
-            set { Internal_SetClimbingMode(mCachedPtr, value); }
-        }
-
-        public CharacterNonWalkableMode NonWalkableMode
-        {
-            set { Internal_SetNonWalkableMode(mCachedPtr, value); }
-        }
-
-        public float MinMoveDistance
-        {
-            set { Internal_SetMinMoveDistance(mCachedPtr, value); }
-        }
-
-        public float ContactOffset
-        {
-            set { Internal_SetContactOffset(mCachedPtr, value); }
-        }
-
-        public float StepOffset
-        {
-            set { Internal_SetStepOffset(mCachedPtr, value); }
-        }
-
-        public Radian SlopeLimit
-        {
-            set { Internal_SetSlopeLimit(mCachedPtr, value.Radians); }
-        }
-
-        public ulong Layer
-        {
-            set { Internal_SetLayer(mCachedPtr, value); }
-        }
-
-        public NativeCharacterController(ScriptCharacterControllerData initData)
-        {
-            Internal_CreateInstance(this, ref initData);
-        }
-
-        public void Destroy()
-        {
-            Internal_Destroy(mCachedPtr);
-        }
-
-        public void Move(Vector3 position)
-        {
-            Internal_Move(mCachedPtr, ref position);
-        }
-
-        private void Internal_DoOnColliderHit(ScriptControllerCollision scriptCollisionData)
-        {
-            ControllerColliderCollision collisionData = new ControllerColliderCollision();
-            collisionData.position = scriptCollisionData.position;
-            collisionData.normal = scriptCollisionData.normal;
-            collisionData.motionDir = scriptCollisionData.motionDir;
-            collisionData.motionAmount = scriptCollisionData.motionAmount;
-            collisionData.triangleIndex = scriptCollisionData.triangleIndex;
-            collisionData.collider = scriptCollisionData.collider.Component;
-
-            Component.DoOnColliderHit(collisionData);
-        }
-
-        private void Internal_DoOnControllerHit(ScriptControllerCollision scriptCollisionData)
-        {
-            ControllerControllerCollision collisionData = new ControllerControllerCollision();
-            collisionData.position = scriptCollisionData.position;
-            collisionData.normal = scriptCollisionData.normal;
-            collisionData.motionDir = scriptCollisionData.motionDir;
-            collisionData.motionAmount = scriptCollisionData.motionAmount;
-            collisionData.controller = scriptCollisionData.controller.Component;
-
-            Component.DoOnControllerHit(collisionData);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(NativeCharacterController instance, 
-            ref ScriptCharacterControllerData initData);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
-        
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetFootPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetFootPosition(IntPtr thisPtr, ref Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRadius(IntPtr thisPtr, float radius);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetHeight(IntPtr thisPtr, float height);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetUp(IntPtr thisPtr, ref Vector3 up);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetClimbingMode(IntPtr thisPtr, CharacterClimbingMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetNonWalkableMode(IntPtr thisPtr, CharacterNonWalkableMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMinMoveDistance(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetStepOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetSlopeLimit(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLayer(IntPtr thisPtr, 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>
+    /// Wrapper around the native CharacterController class.
+    /// <see cref="CharacterController"/>
+    /// </summary>
+    internal class NativeCharacterController : ScriptObject
+    {
+        private CharacterController component;
+
+        /// <summary>
+        /// Component that owns the native character controller object.
+        /// </summary>
+        public CharacterController Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public Vector3 Position
+        {
+            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
+            set { Internal_SetPosition(mCachedPtr, ref value); }
+        }
+
+        public Vector3 FootPosition
+        {
+            get { Vector3 pos; Internal_GetFootPosition(mCachedPtr, out pos); return pos; }
+            set { Internal_SetFootPosition(mCachedPtr, ref value); }
+        }
+
+        public float Radius
+        {
+            set { Internal_SetRadius(mCachedPtr, value); }
+        }
+
+        public float Height
+        {
+            set { Internal_SetHeight(mCachedPtr, value); }
+        }
+
+        public Vector3 Up
+        {
+            set { Internal_SetUp(mCachedPtr, ref value); }
+        }
+
+        public CharacterClimbingMode ClimbingMode
+        {
+            set { Internal_SetClimbingMode(mCachedPtr, value); }
+        }
+
+        public CharacterNonWalkableMode NonWalkableMode
+        {
+            set { Internal_SetNonWalkableMode(mCachedPtr, value); }
+        }
+
+        public float MinMoveDistance
+        {
+            set { Internal_SetMinMoveDistance(mCachedPtr, value); }
+        }
+
+        public float ContactOffset
+        {
+            set { Internal_SetContactOffset(mCachedPtr, value); }
+        }
+
+        public float StepOffset
+        {
+            set { Internal_SetStepOffset(mCachedPtr, value); }
+        }
+
+        public Radian SlopeLimit
+        {
+            set { Internal_SetSlopeLimit(mCachedPtr, value.Radians); }
+        }
+
+        public ulong Layer
+        {
+            set { Internal_SetLayer(mCachedPtr, value); }
+        }
+
+        public NativeCharacterController(ScriptCharacterControllerData initData)
+        {
+            Internal_CreateInstance(this, ref initData);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        public void Move(Vector3 position)
+        {
+            Internal_Move(mCachedPtr, ref position);
+        }
+
+        private void Internal_DoOnColliderHit(ScriptControllerCollision scriptCollisionData)
+        {
+            ControllerColliderCollision collisionData = new ControllerColliderCollision();
+            collisionData.position = scriptCollisionData.position;
+            collisionData.normal = scriptCollisionData.normal;
+            collisionData.motionDir = scriptCollisionData.motionDir;
+            collisionData.motionAmount = scriptCollisionData.motionAmount;
+            collisionData.triangleIndex = scriptCollisionData.triangleIndex;
+
+            if(scriptCollisionData.collider != null)
+                collisionData.collider = scriptCollisionData.collider.Component;
+            else
+                collisionData.collider = null;
+
+            Component.DoOnColliderHit(collisionData);
+        }
+
+        private void Internal_DoOnControllerHit(ScriptControllerCollision scriptCollisionData)
+        {
+            ControllerControllerCollision collisionData = new ControllerControllerCollision();
+            collisionData.position = scriptCollisionData.position;
+            collisionData.normal = scriptCollisionData.normal;
+            collisionData.motionDir = scriptCollisionData.motionDir;
+            collisionData.motionAmount = scriptCollisionData.motionAmount;
+
+            if (scriptCollisionData.controller != null)
+                collisionData.controller = scriptCollisionData.controller.Component;
+            else
+                collisionData.controller = null;
+
+            Component.DoOnControllerHit(collisionData);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(NativeCharacterController instance, 
+            ref ScriptCharacterControllerData initData);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetFootPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetFootPosition(IntPtr thisPtr, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRadius(IntPtr thisPtr, float radius);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetHeight(IntPtr thisPtr, float height);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUp(IntPtr thisPtr, ref Vector3 up);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetClimbingMode(IntPtr thisPtr, CharacterClimbingMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetNonWalkableMode(IntPtr thisPtr, CharacterNonWalkableMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMinMoveDistance(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetStepOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSlopeLimit(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
+    }
+}

+ 200 - 215
Source/MBansheeEngine/Physics/NativeCollider.cs

@@ -1,215 +1,200 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native Collider class.
-    /// <see cref="Collider"/>
-    /// </summary>
-    internal class NativeCollider : ScriptObject
-    {
-        private Collider component;
-
-        /// <summary>
-        /// Component that owns the native collider object.
-        /// </summary>
-        public Collider Component
-        {
-            get { return component; }
-            set { component = value; }
-        }
-
-        public Vector3 Position
-        {
-            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
-            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
-        }
-
-        public Quaternion Rotation
-        {
-            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
-            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
-        }
-
-        public Vector3 Scale
-        {
-            get { Vector3 scale; Internal_GetScale(mCachedPtr, out scale); return scale; }
-            set { Internal_SetScale(mCachedPtr, ref value); }
-        }
-
-        public bool IsTrigger
-        {
-            get { return Internal_GetIsTrigger(mCachedPtr); }
-            set { Internal_SetIsTrigger(mCachedPtr, value); }
-        }
-
-        public NativeRigidbody Rigidbody
-        {
-            get { return Internal_GetRigidbody(mCachedPtr); }
-            set
-            {
-                IntPtr rigidbodyPtr = IntPtr.Zero;
-                if (value != null)
-                    rigidbodyPtr = value.GetCachedPtr();
-
-                Internal_SetRigidbody(mCachedPtr, rigidbodyPtr);
-            }
-        }
-
-        public float Mass
-        {
-            get { return Internal_GetMass(mCachedPtr); }
-            set { Internal_SetMass(mCachedPtr, value); }
-        }
-
-        public PhysicsMaterial Material
-        {
-            get { return Internal_GetMaterial(mCachedPtr); }
-            set
-            {
-                IntPtr materialPtr = IntPtr.Zero;
-                if (value != null)
-                    materialPtr = value.GetCachedPtr();
-
-                Internal_SetMaterial(mCachedPtr, materialPtr);
-            }
-        }
-
-        public float ContactOffset
-        {
-            get { return Internal_GetContactOffset(mCachedPtr); }
-            set { Internal_SetContactOffset(mCachedPtr, value); }
-        }
-
-        public float RestOffset
-        {
-            get { return Internal_GetRestOffset(mCachedPtr); }
-            set { Internal_SetRestOffset(mCachedPtr, value); }
-        }
-
-        public ulong Layer
-        {
-            get { return Internal_GetLayer(mCachedPtr); }
-            set { Internal_SetLayer(mCachedPtr, value); }
-        }
-
-        public CollisionReportMode CollisionReportMode
-        {
-            get { return Internal_GetCollisionReportMode(mCachedPtr); }
-            set { Internal_SetCollisionReportMode(mCachedPtr, value); }
-        }
-
-        public bool Raycast(Vector3 origin, Vector3 unitDir, out ScriptPhysicsQueryHit hit, float maxDist)
-        {
-            return Internal_RayCast(mCachedPtr, ref origin, ref unitDir, out hit, maxDist);
-        }
-
-        public void Destroy()
-        {
-            Internal_Destroy(mCachedPtr);
-        }
-
-        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionBegin(collisionData);
-        }
-
-        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionStay(collisionData);
-        }
-
-        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionEnd(collisionData);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 pos);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rot);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetScale(IntPtr thisPtr, ref Vector3 scale);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetScale(IntPtr thisPtr, out Vector3 scale);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetIsTrigger(IntPtr thisPtr, bool value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetIsTrigger(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRigidbody(IntPtr thisPtr, IntPtr rigidbody);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeRigidbody Internal_GetRigidbody(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetMass(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr physicsMaterial);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern PhysicsMaterial Internal_GetMaterial(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetContactOffset(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRestOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetRestOffset(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ulong Internal_GetLayer(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetCollisionReportMode(IntPtr thisPtr, CollisionReportMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern CollisionReportMode Internal_GetCollisionReportMode(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_RayCast(IntPtr thisPtr, ref Vector3 origin, ref Vector3 unitDir, 
-            out ScriptPhysicsQueryHit hit, float maxDist);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native Collider class.
+    /// <see cref="Collider"/>
+    /// </summary>
+    internal class NativeCollider : ScriptObject
+    {
+        private Collider component;
+
+        /// <summary>
+        /// Component that owns the native collider object.
+        /// </summary>
+        public Collider Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public Vector3 Position
+        {
+            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
+            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
+        }
+
+        public Quaternion Rotation
+        {
+            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
+            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
+        }
+
+        public Vector3 Scale
+        {
+            get { Vector3 scale; Internal_GetScale(mCachedPtr, out scale); return scale; }
+            set { Internal_SetScale(mCachedPtr, ref value); }
+        }
+
+        public bool IsTrigger
+        {
+            get { return Internal_GetIsTrigger(mCachedPtr); }
+            set { Internal_SetIsTrigger(mCachedPtr, value); }
+        }
+
+        public NativeRigidbody Rigidbody
+        {
+            get { return Internal_GetRigidbody(mCachedPtr); }
+            set
+            {
+                IntPtr rigidbodyPtr = IntPtr.Zero;
+                if (value != null)
+                    rigidbodyPtr = value.GetCachedPtr();
+
+                Internal_SetRigidbody(mCachedPtr, rigidbodyPtr);
+            }
+        }
+
+        public float Mass
+        {
+            get { return Internal_GetMass(mCachedPtr); }
+            set { Internal_SetMass(mCachedPtr, value); }
+        }
+
+        public PhysicsMaterial Material
+        {
+            get { return Internal_GetMaterial(mCachedPtr); }
+            set
+            {
+                IntPtr materialPtr = IntPtr.Zero;
+                if (value != null)
+                    materialPtr = value.GetCachedPtr();
+
+                Internal_SetMaterial(mCachedPtr, materialPtr);
+            }
+        }
+
+        public float ContactOffset
+        {
+            get { return Internal_GetContactOffset(mCachedPtr); }
+            set { Internal_SetContactOffset(mCachedPtr, value); }
+        }
+
+        public float RestOffset
+        {
+            get { return Internal_GetRestOffset(mCachedPtr); }
+            set { Internal_SetRestOffset(mCachedPtr, value); }
+        }
+
+        public ulong Layer
+        {
+            get { return Internal_GetLayer(mCachedPtr); }
+            set { Internal_SetLayer(mCachedPtr, value); }
+        }
+
+        public CollisionReportMode CollisionReportMode
+        {
+            get { return Internal_GetCollisionReportMode(mCachedPtr); }
+            set { Internal_SetCollisionReportMode(mCachedPtr, value); }
+        }
+
+        public bool Raycast(Vector3 origin, Vector3 unitDir, out ScriptPhysicsQueryHit hit, float maxDist)
+        {
+            return Internal_RayCast(mCachedPtr, ref origin, ref unitDir, out hit, maxDist);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionBegin(new CollisionData(scriptCollisionData));
+        }
+
+        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionStay(new CollisionData(scriptCollisionData));
+        }
+
+        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionEnd(new CollisionData(scriptCollisionData));
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 pos);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rot);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetScale(IntPtr thisPtr, ref Vector3 scale);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetScale(IntPtr thisPtr, out Vector3 scale);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetIsTrigger(IntPtr thisPtr, bool value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetIsTrigger(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRigidbody(IntPtr thisPtr, IntPtr rigidbody);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeRigidbody Internal_GetRigidbody(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetMass(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr physicsMaterial);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern PhysicsMaterial Internal_GetMaterial(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetContactOffset(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRestOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRestOffset(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ulong Internal_GetLayer(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetCollisionReportMode(IntPtr thisPtr, CollisionReportMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern CollisionReportMode Internal_GetCollisionReportMode(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_RayCast(IntPtr thisPtr, ref Vector3 origin, ref Vector3 unitDir, 
+            out ScriptPhysicsQueryHit hit, float maxDist);
+    }
+}

+ 3 - 18
Source/MBansheeEngine/Physics/NativeRigidbody.cs

@@ -218,32 +218,17 @@ namespace BansheeEngine
 
         private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionBegin(collisionData);
+            Component.DoOnCollisionBegin(new CollisionData(scriptCollisionData));
         }
 
         private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionStay(collisionData);
+            Component.DoOnCollisionStay(new CollisionData(scriptCollisionData));
         }
 
         private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionEnd(collisionData);
+            Component.DoOnCollisionEnd(new CollisionData(scriptCollisionData));
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]

+ 150 - 135
Source/MBansheeEngine/Physics/PhysicsCommon.cs

@@ -1,135 +1,150 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Hit information from a physics query.
-    /// </summary>
-    public struct PhysicsQueryHit
-    {
-        /// <summary>
-        /// Position of the hit in world space.
-        /// </summary>
-        public Vector3 point;
-
-        /// <summary>
-        /// Normal to the surface that was hit. 
-        /// </summary>
-        public Vector3 normal;
-
-        /// <summary>
-        /// UV coordinates of the triangle that was hit (only applicable when triangle meshes are hit).
-        /// </summary>
-        public Vector2 uv;
-
-        /// <summary>
-        /// Distance from the query origin to the hit position.
-        /// </summary>
-        public float distance;
-
-        /// <summary>
-        /// Index of the triangle that was hit (only applicable when triangle meshes are hit).
-        /// </summary>
-        public int triangleIdx;
-
-        /// <summary>
-        /// Collider that was hit.
-        /// </summary>
-        public Collider collider;
-    }
-
-    /// <summary>
-    /// Information about a single contact point during physics collision.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct ContactPoint // Note: Must match C++ ContactPoint struct
-    {
-        /// <summary>
-        /// Contact point in world space.
-        /// </summary>
-        public Vector3 position;
-
-        /// <summary>
-        /// Normal pointing from the second shape to the first shape.
-        /// </summary>
-        public Vector3 normal;
-
-        /// <summary>
-        /// Impulse applied to the objects to keep them from penetrating. Divide by simulation step to get the force.
-        /// </summary>
-        public float impulse;
-
-        /// <summary>
-        /// Determines how far are the objects. Negative value denotes penetration.
-        /// </summary>
-        public float separation;
-    }
-
-    /// <summary>
-    /// Information about a collision between two physics objects.
-    /// </summary>
-    public struct CollisionData
-    {
-        /// <summary>
-        /// First of the colliders involved in the collision.
-        /// </summary>
-        public Collider colliderA;
-
-        /// <summary>
-        /// Second of the colliders involved in the collision.
-        /// </summary>
-        public Collider colliderB;
-
-        /// <summary>
-        /// Information about all the contact points for the hit. 
-        /// </summary>
-        public ContactPoint[] contactPoints;
-    }
-
-    /// <summary>
-    /// Interop class used for passing PhysicsQueryHit data from native to managed code. <see cref="PhysicsQueryHit"/>.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptPhysicsQueryHit // Note: Must match C++ struct ScriptPhysicsQueryHit
-    {
-        public Vector3 point;
-        public Vector3 normal;
-        public Vector2 uv;
-        public float distance;
-        public int triangleIdx;
-        public NativeCollider collider;
-    }
-
-    /// <summary>
-    /// Interop class used for passing CollisionData data from native to managed code. <see cref="CollisionData"/>.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptCollisionData // Note: Must match C++ CollisionData struct
-    {
-        public NativeCollider colliderA;
-        public NativeCollider colliderB;
-        public ContactPoint[] contactPoints;
-    }
-
-    /// <summary>
-    /// Determines which collision events will be reported by physics objects.
-    /// </summary>
-    public enum CollisionReportMode
-    {
-        /// <summary>
-        /// No collision events will be triggered.
-        /// </summary>
-        None,
-        /// <summary>
-        /// Collision events will be triggered when object enters and/or leaves collision.
-        /// </summary>
-		Report,
-		/// <summary>
-        /// Collision events will be triggered when object enters and/or leaves collision, but also every frame the object 
-        /// remains in collision. 
-        /// </summary>
-		ReportPersistent, 
-	}
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Hit information from a physics query.
+    /// </summary>
+    public struct PhysicsQueryHit
+    {
+        /// <summary>
+        /// Position of the hit in world space.
+        /// </summary>
+        public Vector3 point;
+
+        /// <summary>
+        /// Normal to the surface that was hit. 
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// UV coordinates of the triangle that was hit (only applicable when triangle meshes are hit).
+        /// </summary>
+        public Vector2 uv;
+
+        /// <summary>
+        /// Distance from the query origin to the hit position.
+        /// </summary>
+        public float distance;
+
+        /// <summary>
+        /// Index of the triangle that was hit (only applicable when triangle meshes are hit).
+        /// </summary>
+        public int triangleIdx;
+
+        /// <summary>
+        /// Collider that was hit.
+        /// </summary>
+        public Collider collider;
+    }
+
+    /// <summary>
+    /// Information about a single contact point during physics collision.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct ContactPoint // Note: Must match C++ ContactPoint struct
+    {
+        /// <summary>
+        /// Contact point in world space.
+        /// </summary>
+        public Vector3 position;
+
+        /// <summary>
+        /// Normal pointing from the second shape to the first shape.
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// Impulse applied to the objects to keep them from penetrating. Divide by simulation step to get the force.
+        /// </summary>
+        public float impulse;
+
+        /// <summary>
+        /// Determines how far are the objects. Negative value denotes penetration.
+        /// </summary>
+        public float separation;
+    }
+
+    /// <summary>
+    /// Information about a collision between two physics objects.
+    /// </summary>
+    public struct CollisionData
+    {
+        internal CollisionData(ScriptCollisionData data)
+        {
+            if (data.colliderA != null)
+                colliderA = data.colliderA.Component;
+            else
+                colliderA = null;
+
+            if (data.colliderB != null)
+                colliderB = data.colliderB.Component;
+            else
+                colliderB = null;
+
+            contactPoints = data.contactPoints;
+        }
+
+        /// <summary>
+        /// First of the colliders involved in the collision.
+        /// </summary>
+        public Collider colliderA;
+
+        /// <summary>
+        /// Second of the colliders involved in the collision.
+        /// </summary>
+        public Collider colliderB;
+
+        /// <summary>
+        /// Information about all the contact points for the hit. 
+        /// </summary>
+        public ContactPoint[] contactPoints;
+    }
+
+    /// <summary>
+    /// Interop class used for passing PhysicsQueryHit data from native to managed code. <see cref="PhysicsQueryHit"/>.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptPhysicsQueryHit // Note: Must match C++ struct ScriptPhysicsQueryHit
+    {
+        public Vector3 point;
+        public Vector3 normal;
+        public Vector2 uv;
+        public float distance;
+        public int triangleIdx;
+        public NativeCollider collider;
+    }
+
+    /// <summary>
+    /// Interop class used for passing CollisionData data from native to managed code. <see cref="CollisionData"/>.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptCollisionData // Note: Must match C++ CollisionData struct
+    {
+        public NativeCollider colliderA;
+        public NativeCollider colliderB;
+        public ContactPoint[] contactPoints;
+    }
+
+    /// <summary>
+    /// Determines which collision events will be reported by physics objects.
+    /// </summary>
+    public enum CollisionReportMode
+    {
+        /// <summary>
+        /// No collision events will be triggered.
+        /// </summary>
+        None,
+        /// <summary>
+        /// Collision events will be triggered when object enters and/or leaves collision.
+        /// </summary>
+		Report,
+		/// <summary>
+        /// Collision events will be triggered when object enters and/or leaves collision, but also every frame the object 
+        /// remains in collision. 
+        /// </summary>
+		ReportPersistent, 
+	}
+}

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

@@ -647,6 +647,7 @@ namespace BansheeEngine
         private void RestoreNative()
         {
             native = new NativeRigidbody(SceneObject);
+            native.Component = this;
 
             UpdateColliders();