Browse Source

Updated ImGuizmo.

Branimir Karadžić 9 years ago
parent
commit
a99c23f649
2 changed files with 97 additions and 34 deletions
  1. 6 5
      3rdparty/ocornut-imgui/widgets/gizmo.h
  2. 91 29
      3rdparty/ocornut-imgui/widgets/gizmo.inl

+ 6 - 5
3rdparty/ocornut-imgui/widgets/gizmo.h

@@ -1,5 +1,5 @@
 // https://github.com/CedricGuillemet/ImGuizmo
-// v 1.02 WIP
+// v 1.03 WIP
 //
 // The MIT License(MIT)
 // 
@@ -25,17 +25,18 @@
 //
 // -------------------------------------------------------------------------------------------
 // History : 
+// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
 // 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
 // 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
 // 2016/08/31 First version
 //
 // -------------------------------------------------------------------------------------------
-// Future:
+// Future (no order):
 //
 // - Multi view
 // - display rotation/translation/scale infos in local/world space and not only local
 // - finish local/world matrix application
-// - snap
+// - OPERATION as bitmask
 // 
 // -------------------------------------------------------------------------------------------
 // Example 
@@ -73,7 +74,7 @@
 // if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
 //		mCurrentGizmoMode = ImGuizmo::WORLD;
 // 
-// ImGuizmo::Mogwai(gCurrentCamera->mView.m16, gCurrentCamera->mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, gizmoMatrix.m16);
+// ImGuizmo::Manipulate(gCurrentCamera->mView.m16, gCurrentCamera->mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, gizmoMatrix.m16);
 //
 
 #pragma once
@@ -128,5 +129,5 @@ namespace ImGuizmo
 		WORLD
 	};
 
-	void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0);
+	void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0, float *snap = 0);
 };

+ 91 - 29
3rdparty/ocornut-imgui/widgets/gizmo.inl

@@ -530,6 +530,7 @@ namespace ImGuizmo
 		// scale
 		vec_t mScale;
 		vec_t mScaleValueOrigin;
+		float mSaveMousePosx;
 
 		// save axis factor when using gizmo
 		bool mBelowAxisLimit[3];
@@ -550,7 +551,7 @@ namespace ImGuizmo
 	static const ImU32 selectionColor = 0xFF1080FF;
 	static const ImU32 inactiveColor = 0x99999999;
 	static const ImU32 translationLineColor = 0xAAAAAAAA;
-	static const char *translationInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "X : %5.2f Y : %5.2f", "Y : %5.2f Z : %5.2f", "X : %5.2f Z : %5.2f", "X : %5.2f Y : %5.2f Z : %5.2f" };
+	static const char *translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", "X : %5.3f Y : %5.3f", "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f Z : %5.3f" };
 	static const char *scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" };
 	static const char *rotationInfoMask[] = { "X : %5.2f deg %5.2f rad", "Y : %5.2f deg %5.2f rad", "Z : %5.2f deg %5.2f rad", "Screen : %5.2f deg %5.2f rad" };
 	static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 0,1,0, 0,2,0, 1,2,0, 0,1,2 };
@@ -558,6 +559,7 @@ namespace ImGuizmo
 	static const float quadMax = 0.8f;
 	static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };
 	static const int halfCircleSegmentCount = 64;
+	static const float snapTension = 0.5f;
 
 	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 	// 
@@ -763,6 +765,39 @@ namespace ImGuizmo
 		}
 	}
 
+	static void ComputeSnap(float*value, float *snap)
+	{
+		if (*snap <= FLT_EPSILON)
+			return;
+		float modulo = fmodf(*value, *snap);
+		float moduloRatio = fabsf(modulo) / *snap;
+		if (moduloRatio < snapTension)
+			*value -= modulo;
+		else if (moduloRatio >(1.f - snapTension))
+			*value = *value - modulo + *snap * ((*value<0.f) ? -1.f : 1.f);
+	}
+	static void ComputeSnap(vec_t& value, float *snap)
+	{
+		for (int i = 0; i < 3; i++)
+		{
+			ComputeSnap(&value[i], &snap[i]);
+		}
+	}
+
+	static float ComputeAngleOnPlan()
+	{
+		const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
+		vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
+
+		vec_t perpendicularVector;
+		perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
+		perpendicularVector.Normalize();
+		float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -0.9999f, 0.9999f);
+		float angle = acosf(acosAngle);
+		angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
+		return angle;
+	}
+
 	static void DrawRotationGizmo(int type)
 	{
 		ImDrawList* drawList = gContext.mDrawList;
@@ -818,6 +853,16 @@ namespace ImGuizmo
 		}
 	}
 
+	static void DrawHatchedAxis(const vec_t& axis)
+	{
+		for (int j = 1; j < 10; j++)
+		{
+			ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP);
+			ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP);
+			gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, 0x80000000, 6.f);
+		}
+	}
+
 	static void DrawScaleGizmo(int type)
 	{
 		ImDrawList* drawList = gContext.mDrawList;
@@ -853,9 +898,12 @@ namespace ImGuizmo
 					drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 6.f);
 					drawList->AddCircleFilled(worldDirSSpaceNoScale, 10.f, 0xFF404040);
 				}
-
+				
 				drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
 				drawList->AddCircleFilled(worldDirSSpace, 10.f, colors[i + 1]);
+
+				if (gContext.mAxisFactor[i] < 0.f)
+					DrawHatchedAxis(dirPlaneX * scaleDisplay[i]);
 			}
 		}
 		
@@ -877,9 +925,9 @@ namespace ImGuizmo
 			drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
 			drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
 		}
-		
 	}
 
+
 	static void DrawTranslationGizmo(int type)
 	{
 		ImDrawList* drawList = gContext.mDrawList;
@@ -905,6 +953,9 @@ namespace ImGuizmo
 				ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
 
 				drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
+				
+				if (gContext.mAxisFactor[i] < 0.f)
+					DrawHatchedAxis(dirPlaneX);
 			}
 
 			// draw plane
@@ -1047,7 +1098,7 @@ namespace ImGuizmo
 		return type;
 	}
 
-	static void HandleTranslation(float *matrix, float *deltaMatrix, int& type)
+	static void HandleTranslation(float *matrix, float *deltaMatrix, int& type, float *snap)
 	{
 		ImGuiIO& io = ImGui::GetIO();
 
@@ -1056,9 +1107,11 @@ namespace ImGuizmo
 		{
 			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
 			vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
+
+			// compute delta
 			vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
 			vec_t delta = newOrigin - gContext.mModel.v.position;
-
+			
 			// 1 axis constraint
 			if (gContext.mCurrentOperation >= MOVE_X && gContext.mCurrentOperation <= MOVE_Z)
 			{
@@ -1068,8 +1121,15 @@ namespace ImGuizmo
 				delta = axisValue * lengthOnAxis;
 			}
 
+			// snap
+			if (snap)
+			{
+				vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;
+				ComputeSnap(cumulativeDelta, snap);
+				delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;
+			}
+
 			// compute matrix & delta
-			gContext.mTranslationPlanOrigin += delta;
 			matrix_t deltaMatrixTranslation;
 			deltaMatrixTranslation.Translation(delta);
 			if (deltaMatrix)
@@ -1103,7 +1163,7 @@ namespace ImGuizmo
 		}
 	}
 
-	static void HandleScale(float *matrix, float *deltaMatrix, int& type)
+	static void HandleScale(float *matrix, float *deltaMatrix, int& type, float *snap)
 	{
 		ImGuiIO& io = ImGui::GetIO();
 
@@ -1125,6 +1185,7 @@ namespace ImGuizmo
 				gContext.mScale.Set(1.f, 1.f, 1.f);
 				gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
 				gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
+				gContext.mSaveMousePosx = io.MousePos.x;
 			}
 		}
 		// scale
@@ -1150,10 +1211,21 @@ namespace ImGuizmo
 			}
 			else
 			{			
-				float scaleDelta = io.MouseDelta.x * 0.01f;
+				float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx)  * 0.01f;
 				gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
 			}
 
+			// snap
+			if (snap)
+			{
+				float scaleSnap[] = { snap[0], snap[0], snap[0] };
+				ComputeSnap(gContext.mScale, scaleSnap);
+			}
+
+			// no 0 allowed
+			for (int i = 0; i < 3;i++)
+				gContext.mScale[i] = max(gContext.mScale[i], 0.001f);
+
 			// compute matrix & delta
 			matrix_t deltaMatrixScale;
 			deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);
@@ -1170,21 +1242,7 @@ namespace ImGuizmo
 		}
 	}
 
-	static float ComputeAngleOnPlan()
-	{
-		const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
-		vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
-
-		vec_t perpendicularVector;
-		perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
-		perpendicularVector.Normalize();
-		float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -0.9999f, 0.9999f);
-		float angle = acosf(acosAngle);
-		angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
-		return angle;
-	}
-
-	static void HandleRotation(float *matrix, float *deltaMatrix, int& type)
+	static void HandleRotation(float *matrix, float *deltaMatrix, int& type, float *snap)
 	{
 		ImGuiIO& io = ImGui::GetIO();
 
@@ -1210,7 +1268,11 @@ namespace ImGuizmo
 		if (gContext.mbUsing)
 		{
 			gContext.mRotationAngle = ComputeAngleOnPlan();
-
+			if (snap)
+			{
+				float snapInRadian = snap[0] * DEG2RAD;
+				ComputeSnap(&gContext.mRotationAngle, &snapInRadian);
+			}
 			vec_t rotationAxisLocalSpace;
 			rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
 
@@ -1268,7 +1330,7 @@ namespace ImGuizmo
 		float validScale[3];
 		for (int i = 0; i < 3; i++)
 		{
-			if (fabsf(scale[i]) < FLT_EPSILON)
+			if (fabsf(scale[i] < FLT_EPSILON))
 				validScale[i] = 0.001f;
 			else
 				validScale[i] = scale[i];
@@ -1279,7 +1341,7 @@ namespace ImGuizmo
 		mat.v.position.Set(translation[0], translation[1], translation[2], 1.f);
 	}
 
-	void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix)
+	void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix, float *snap)
 	{
 		ComputeContext(view, projection, matrix, mode);
 
@@ -1293,13 +1355,13 @@ namespace ImGuizmo
 			switch (operation)
 			{
 			case ROTATE:
-				HandleRotation(matrix, deltaMatrix, type);
+				HandleRotation(matrix, deltaMatrix, type, snap);
 				break;
 			case TRANSLATE:
-				HandleTranslation(matrix, deltaMatrix, type);
+				HandleTranslation(matrix, deltaMatrix, type, snap);
 				break;
 			case SCALE:
-				HandleScale(matrix, deltaMatrix, type);
+				HandleScale(matrix, deltaMatrix, type, snap);
 				break;
 			}
 		}