Explorar el Código

Fixing a memory corruption issue with skeletal animation poses
When running in editor, pause all relevant systems on startup, until play-mode is entered

BearishSun hace 9 años
padre
commit
6e91706388

+ 3 - 0
Source/BansheeCore/Include/BsAnimation.h

@@ -101,8 +101,11 @@ namespace BansheeEngine
 	struct AnimationProxy
 	{
 		AnimationProxy(UINT64 id);
+		AnimationProxy(const AnimationProxy&) = delete;
 		~AnimationProxy();
 
+		AnimationProxy& operator=(const AnimationProxy&) = delete;
+
 		/** 
 		 * Rebuilds the internal proxy data according to the newly assigned skeleton and clips. This should be called
 		 * whenever the animation skeleton changes.

+ 5 - 0
Source/BansheeCore/Include/BsSkeleton.h

@@ -77,8 +77,13 @@ namespace BansheeEngine
 		LocalSkeletonPose();
 		LocalSkeletonPose(UINT32 numBones);
 		LocalSkeletonPose(UINT32 numPos, UINT32 numRot, UINT32 numScale);
+		LocalSkeletonPose(const LocalSkeletonPose& other) = delete;
+		LocalSkeletonPose(LocalSkeletonPose&& other);
 		~LocalSkeletonPose();
 
+		LocalSkeletonPose& operator=(const LocalSkeletonPose& other) = delete;
+		LocalSkeletonPose& operator=(LocalSkeletonPose&& other);
+
 		Vector3* positions; /**< Local bone positions at specific animation time. */
 		Quaternion* rotations; /**< Local bone rotations at specific animation time. */
 		Vector3* scales; /**< Local bone scales at specific animation time. */

+ 31 - 1
Source/BansheeCore/Source/BsSkeleton.cpp

@@ -14,7 +14,7 @@ namespace BansheeEngine
 		: numBones(numBones)
 	{
 		UINT32 elementSize = sizeof(Vector3) * 2 + sizeof(Quaternion);
-		UINT8* buffer = (UINT8*)bs_alloc(elementSize * sizeof(numBones));
+		UINT8* buffer = (UINT8*)bs_alloc(elementSize * numBones);
 
 		positions = (Vector3*)buffer;
 		buffer += sizeof(Vector3) * numBones;
@@ -40,12 +40,42 @@ namespace BansheeEngine
 		scales = (Vector3*)buffer;
 	}
 
+	LocalSkeletonPose::LocalSkeletonPose(LocalSkeletonPose&& other)
+		: positions(other.positions), rotations(other.rotations), scales(other.scales), numBones(other.numBones)
+	{
+		other.positions = nullptr;
+		other.rotations = nullptr;
+		other.scales = nullptr;
+		other.numBones = 0;
+	}
+
 	LocalSkeletonPose::~LocalSkeletonPose()
 	{
 		if (positions != nullptr)
 			bs_free(positions);
 	}
 
+	LocalSkeletonPose& LocalSkeletonPose::operator=(LocalSkeletonPose&& other)
+	{
+		if (this != &other)
+		{
+			if (positions != nullptr)
+				bs_free(positions);
+
+			positions = other.positions;
+			rotations = other.rotations;
+			scales = other.scales;
+			numBones = other.numBones;
+
+			other.positions = nullptr;
+			other.rotations = nullptr;
+			other.scales = nullptr;
+			other.numBones = 0;
+		}
+
+		return *this;
+	}
+
 	Skeleton::Skeleton()
 		:mInvBindPoses(nullptr), mBoneInfo(nullptr), mNumBones(0)
 	{ }

+ 28 - 4
Source/BansheeUtility/Include/BsStringFormat.h

@@ -204,10 +204,22 @@ namespace BansheeEngine
 		template<class T> static std::string toString(T* param) { static_assert("Invalid pointer type."); }
 
 		/**	Helper method that converts a narrow character array to a narrow string. */
-		static std::string toString(const char* param) { return std::string(param); }
+		static std::string toString(const char* param)
+		{
+			if (param == nullptr)
+				return std::string();
+
+			return std::string(param);
+		}
 
 		/**	Helper method that converts a narrow character array to a narrow string. */
-		static std::string toString(char* param) { return std::string(param); }
+		static std::string toString(char* param)
+		{
+			if (param == nullptr)
+				return std::string();
+
+			return std::string(param);
+		}
 
 		/**	Helper method for converting any data type to a wide string. */
 		template<class T> static std::wstring toWString(const T& param) { return std::to_wstring(param); }
@@ -225,10 +237,22 @@ namespace BansheeEngine
 		template<class T> static std::wstring toWString(T* param) { static_assert("Invalid pointer type."); }
 
 		/**	Helper method that converts a wide character array to a wide string. */
-		static std::wstring toWString(const wchar_t* param) { return std::wstring(param); }
+		static std::wstring toWString(const wchar_t* param)
+		{
+			if (param == nullptr)
+				return std::wstring();
+
+			return std::wstring(param);
+		}
 
 		/**	Helper method that converts a wide character array to a wide string. */
-		static std::wstring toWString(wchar_t* param) { return std::wstring(param); }
+		static std::wstring toWString(wchar_t* param)
+		{
+			if (param == nullptr)
+				return std::wstring();
+
+			return std::wstring(param);
+		}
 
 		/**
 		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.

+ 2 - 1
Source/BansheeUtility/Source/BsTaskScheduler.cpp

@@ -30,7 +30,8 @@ namespace BansheeEngine
 
 	void Task::wait()
 	{
-		mParent->waitUntilComplete(this);
+		if(mParent != nullptr)
+			mParent->waitUntilComplete(this);
 	}
 
 	void Task::cancel()

+ 3 - 0
Source/SBansheeEngine/Include/BsPlayInEditorManager.h

@@ -69,6 +69,9 @@ namespace BansheeEngine
 		/**	Saves the current state of the scene in memory. */
 		void saveSceneInMemory();
 
+		/** Pauses or unpauses all pausable engine systems. */
+		void setSystemsPauseState(bool paused);
+
 		PlayInEditorState mState;
 		PlayInEditorState mNextState;
 		bool mFrameStepActive;

+ 12 - 9
Source/SBansheeEngine/Source/BsPlayInEditorManager.cpp

@@ -18,6 +18,8 @@ namespace BansheeEngine
 	{
 		if (!gApplication().isEditor())
 			mState = PlayInEditorState::Playing;
+		else
+			setSystemsPauseState(true);
 	}
 
 	void PlayInEditorManager::setState(PlayInEditorState state)
@@ -46,9 +48,7 @@ namespace BansheeEngine
 			mFrameStepActive = false;
 			mPausableTime = 0.0f;
 
-			gPhysics().setPaused(true);
-			gAudio().setPaused(true);
-			gAnimation().setPaused(true);
+			setSystemsPauseState(true);
 
 			mSavedScene->_instantiate();
 			gSceneManager()._setRootNode(mSavedScene);
@@ -63,17 +63,13 @@ namespace BansheeEngine
 				ScriptGameObjectManager::instance().wakeRuntimeComponents();
 			}
 
-			gPhysics().setPaused(false);
-			gAudio().setPaused(false);
-			gAnimation().setPaused(false);
+			setSystemsPauseState(false);
 		}
 			break;
 		case PlayInEditorState::Paused:
 		{
 			mFrameStepActive = false;
-			gPhysics().setPaused(true);
-			gAudio().setPaused(true);
-			gAnimation().setPaused(true);
+			setSystemsPauseState(true);
 
 			if (oldState == PlayInEditorState::Stopped)
 			{
@@ -146,4 +142,11 @@ namespace BansheeEngine
 			}
 		}
 	}
+
+	void PlayInEditorManager::setSystemsPauseState(bool paused)
+	{
+		gPhysics().setPaused(paused);
+		gAudio().setPaused(paused);
+		gAnimation().setPaused(paused);
+	}
 }