Przeglądaj źródła

Updated ImGuizmo.

Branimir Karadžić 9 lat temu
rodzic
commit
7c95b30d4d

+ 97 - 4
3rdparty/ocornut-imgui/widgets/gizmo.h

@@ -1,4 +1,73 @@
 // https://github.com/CedricGuillemet/ImGuizmo
+// v 1.0 WIP
+//
+// The MIT License(MIT)
+// 
+// Copyright(c) 2016 Cedric Guillemet
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+// -------------------------------------------------------------------------------------------
+// History : 
+// 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
+//
+// -------------------------------------------------------------------------------------------
+// Example 
+//
+// static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE);
+// static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL);
+// 
+// // Maya shortcut keys
+// if (ImGui::IsKeyPressed(90)) // w Key
+//		mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
+// if (ImGui::IsKeyPressed(69)) // e Key
+//		mCurrentGizmoOperation = ImGuizmo::ROTATE;
+// if (ImGui::IsKeyPressed(82)) // r Key
+//		mCurrentGizmoOperation = ImGuizmo::SCALE;
+//
+// if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
+//		mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
+// ImGui::SameLine();
+// if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
+//		mCurrentGizmoOperation = ImGuizmo::ROTATE;
+// ImGui::SameLine();
+// if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
+//		mCurrentGizmoOperation = ImGuizmo::SCALE;
+//
+// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
+// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
+// ImGui::InputFloat3("Tr", matrixTranslation, 3);
+// ImGui::InputFloat3("Rt", matrixRotation, 3);
+// ImGui::InputFloat3("Sc", matrixScale, 3);
+// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
+// 
+// if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
+//		mCurrentGizmoMode = ImGuizmo::LOCAL;
+// ImGui::SameLine();
+// if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
+//		mCurrentGizmoMode = ImGuizmo::WORLD;
+// 
+// ImGuizmo::Mogwai(gCurrentCamera->mView.m16, gCurrentCamera->mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, gizmoMatrix.m16);
+//
+
+#pragma once
 
 namespace ImGuizmo
 {
@@ -15,16 +84,40 @@ namespace ImGuizmo
 	// gizmo is rendered with gray half transparent color when disabled
 	void Enable(bool enable);
 
+	// helper functions for manualy editing translation/rotation/scale with an input float
+	// translation, rotation and scale float points to 3 floats each
+	// Angles are in degrees (more suitable for human editing)
+	// example:
+	// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
+	// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
+	// ImGui::InputFloat3("Tr", matrixTranslation, 3);
+	// ImGui::InputFloat3("Rt", matrixRotation, 3);
+	// ImGui::InputFloat3("Sc", matrixScale, 3);
+	// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
+	//
+	// These functions have some numerical stability issues for now. Use with caution.
+	void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale);
+	void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix);
+
+	// Render a cube with face color corresponding to face normal. Usefull for debug/tests
+	void DrawCube(const float *view, const float *projection, float *matrix);
+
 	// call it when you want a gizmo
 	// Needs view and projection matrices. 
 	// matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional
 	// translation is applied in world space
-	enum MODE
+	enum OPERATION
 	{
 		TRANSLATE,
 		ROTATE,
 		SCALE
 	};
-	void Mogwai(const float *view, const float *projection, MODE mode, float *matrix, float *deltaMatrix = 0);
-	
-} // namespace ImGuizmo
+
+	enum MODE
+	{
+		LOCAL,
+		WORLD
+	};
+
+	void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0);
+};

+ 320 - 218
3rdparty/ocornut-imgui/widgets/gizmo.inl

@@ -1,8 +1,30 @@
-// https://github.com/CedricGuillemet/ImGuizmo
+// The MIT License(MIT)
+// 
+// Copyright(c) 2016 Cedric Guillemet
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
 
 namespace ImGuizmo
 {
-	const float ZPI = 3.14159265358979323846f;
+	static const float ZPI = 3.14159265358979323846f;
+	static const float RAD2DEG = (180.f / ZPI);
+	static const float DEG2RAD = (ZPI / 180.f);
 
 	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 	// utility and math
@@ -47,8 +69,8 @@ namespace ImGuizmo
 			w += (v.w - w) * t;
 		}
 
-		void set(float v) { x = y = z = w = v; }
-		void set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }
+		void Set(float v) { x = y = z = w = v; }
+		void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }
 
 		vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
 		vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
@@ -65,7 +87,7 @@ namespace ImGuizmo
 		float Length() const { return sqrtf(x*x + y*y + z*z); };
 		float LengthSq() const { return (x*x + y*y + z*z); };
 		vec_t Normalize() { (*this) *= (1.f / Length()); return (*this); }
-		vec_t Normalize(const vec_t& v) { this->set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
+		vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
 
 		void Cross(const vec_t& v)
 		{
@@ -107,41 +129,12 @@ namespace ImGuizmo
 		const float& operator [] (size_t index) const { return ((float*)&x)[index]; }
 	};
 
-	vec_t vect(float _x, float _y, float _z = 0.f, float _w = 0.f)
-	{
-		vec_t res;
-		res.x = _x;
-		res.y = _y;
-		res.z = _z;
-		res.w = _w;
-		return res;
-	}
-
-	vec_t vect(int _x, int _y, int _z = 0, int _w = 0)
-	{
-		vec_t res;
-		res.x = float(_x);
-		res.y = float(_y);
-		res.z = float(_z);
-		res.w = float(_w);
-		return res;
-	}
-
-	vec_t vect(float v)
-	{
-		vec_t res;
-		res.x = v;
-		res.y = v;
-		res.z = v;
-		res.w = v;
-		return res;
-	}
-
-	vec_t vec_t::operator * (float f) const { return vect(x * f, y * f, z * f, w *f); }
-	vec_t vec_t::operator - () const { return vect(-x, -y, -z, -w); }
-	vec_t vec_t::operator - (const vec_t& v) const { return vect(x - v.x, y - v.y, z - v.z, w - v.w); }
-	vec_t vec_t::operator + (const vec_t& v) const { return vect(x + v.x, y + v.y, z + v.z, w + v.w); }
-	vec_t vec_t::operator * (const vec_t& v) const { return vect(x * v.x, y * v.y, z * v.z, w * v.w); }
+	vec_t makeVect(float _x, float _y, float _z = 0.f, float _w = 0.f) { vec_t res; res.x = _x; res.y = _y; res.z = _z; res.w = _w; return res; }
+	vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w *f); }
+	vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); }
+	vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); }
+	vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
+	vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
 
 	ImVec2 operator+ (const ImVec2& a, const ImVec2& b) { return ImVec2(a.x + b.x, a.y + b.y); }
 
@@ -175,6 +168,7 @@ namespace ImGuizmo
 	struct matrix_t
 	{
 	public:
+
 		union
 		{
 			float m[4][4];
@@ -182,11 +176,7 @@ namespace ImGuizmo
 			struct
 			{
 				vec_t right, up, dir, position;
-			};
-			struct
-			{
-				vec_t line[4];
-			};
+			} v;
 		};
 
 		matrix_t(const matrix_t& other) { memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); }
@@ -194,24 +184,24 @@ namespace ImGuizmo
 
 		operator float * () { return m16; }
 		operator const float* () const { return m16; }
-		void translation(float _x, float _y, float _z) { this->translation(vect(_x, _y, _z)); }
+		void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); }
 
-		void translation(const vec_t& vt)
+		void Translation(const vec_t& vt)
 		{
-			right.set(1.f, 0.f, 0.f, 0.f);
-			up.set(0.f, 1.f, 0.f, 0.f);
-			dir.set(0.f, 0.f, 1.f, 0.f);
-			position.set(vt.x, vt.y, vt.z, 1.f);
+			v.right.Set(1.f, 0.f, 0.f, 0.f);
+			v.up.Set(0.f, 1.f, 0.f, 0.f);
+			v.dir.Set(0.f, 0.f, 1.f, 0.f);
+			v.position.Set(vt.x, vt.y, vt.z, 1.f);
 		}
 
-		void scale(float _x, float _y, float _z)
+		void Scale(float _x, float _y, float _z)
 		{
-			right.set(_x, 0.f, 0.f, 0.f);
-			up.set(0.f, _y, 0.f, 0.f);
-			dir.set(0.f, 0.f, _z, 0.f);
-			position.set(0.f, 0.f, 0.f, 1.f);
+			v.right.Set(_x, 0.f, 0.f, 0.f);
+			v.up.Set(0.f, _y, 0.f, 0.f);
+			v.dir.Set(0.f, 0.f, _z, 0.f);
+			v.position.Set(0.f, 0.f, 0.f, 1.f);
 		}
-		void scale(const vec_t& s) { scale(s.x, s.y, s.z); }
+		void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); }
 
 		matrix_t& operator *= (const matrix_t& mat)
 		{
@@ -249,13 +239,14 @@ namespace ImGuizmo
 
 		float Inverse(const matrix_t &srcMatrix, bool affine = false);
 		float Inverse(bool affine = false);
-		void SetToIdentity() {
-			right.set(1.f, 0.f, 0.f, 0.f);
-			up.set(0.f, 1.f, 0.f, 0.f);
-			dir.set(0.f, 0.f, 1.f, 0.f);
-			position.set(0.f, 0.f, 0.f, 1.f);
+		void SetToIdentity() 
+		{
+			v.right.Set(1.f, 0.f, 0.f, 0.f);
+			v.up.Set(0.f, 1.f, 0.f, 0.f);
+			v.dir.Set(0.f, 0.f, 1.f, 0.f);
+			v.position.Set(0.f, 0.f, 0.f, 1.f);
 		}
-		void transpose()
+		void Transpose()
 		{
 			matrix_t tmpm;
 			for (int l = 0; l < 4; l++)
@@ -269,6 +260,13 @@ namespace ImGuizmo
 		}
 		
 		void RotationAxis(const vec_t & axis, float angle);
+
+		void OrthoNormalize()
+		{
+			v.right.Normalize();
+			v.up.Normalize();
+			v.dir.Normalize();
+		}
 	};
 
 	void vec_t::Transform(const matrix_t& matrix)
@@ -496,6 +494,7 @@ namespace ImGuizmo
 		matrix_t mProjectionMat;
 		matrix_t mModel;
 		matrix_t mModelInverse;
+		matrix_t mModelSource;
 		matrix_t mMVP;
 		matrix_t mViewProjection;
 
@@ -528,6 +527,10 @@ namespace ImGuizmo
 		float mRotationAngle;
 		float mRotationAngleOrigin;
 
+		// scale
+		vec_t mScale;
+		ImVec2 mScaleMousePos;
+
 		int mCurrentOperation;
 	};
 
@@ -536,12 +539,13 @@ namespace ImGuizmo
 	static const float angleLimit = 0.96f;
 	static const float planeLimit = 0.2f;
 
-	static const vec_t direction[3] = { vect(1.f,0.f,0.f), vect(0.f,1.f,0.f), vect(0.f,0.f,1.f) };
+	static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };
 	static const ImU32 directionColor[3] = { 0xFF0000AA, 0xFF00AA00, 0xFFAA0000 };
 	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", "X : %5.2f Z : %5.2f", "Y : %5.2f Z : %5.2f", "X : %5.2f Y : %5.2f Z : %5.2f" };
+	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 *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 };
 	static const float quadMin = 0.5f;
@@ -553,6 +557,7 @@ namespace ImGuizmo
 	// 
 	static int GetMoveType(vec_t *gizmoHitProportion);
 	static int GetRotateType();
+	static int GetScaleType();
 
 	static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat)
 	{
@@ -561,7 +566,7 @@ namespace ImGuizmo
 		vec_t trans;
 		trans.TransformPoint(worldPos, mat);
 		trans *= 0.5f / trans.w;
-		trans += vect(0.5f);
+		trans += makeVect(0.5f, 0.5f);
 		trans.y = 1.f - trans.y;
 		trans.x *= io.DisplaySize.x;
 		trans.y *= io.DisplaySize.y;
@@ -578,10 +583,10 @@ namespace ImGuizmo
 		float mox = (io.MousePos.x / io.DisplaySize.x) * 2.f - 1.f;
 		float moy = (1.f - (io.MousePos.y / io.DisplaySize.y)) * 2.f - 1.f;
 
-		rayOrigin.Transform(vect(mox, moy, 0.f, 1.f), mViewProjInverse);
+		rayOrigin.Transform(makeVect(mox, moy, 0.f, 1.f), mViewProjInverse);
 		rayOrigin *= 1.f / rayOrigin.w;
 		vec_t rayEnd;
-		rayEnd.Transform(vect(mox, moy, 1.f, 1.f), mViewProjInverse);
+		rayEnd.Transform(makeVect(mox, moy, 1.f, 1.f), mViewProjInverse);
 		rayEnd *= 1.f / rayEnd.w;
 		rayDir = Normalized(rayEnd - rayOrigin);
 	}
@@ -614,7 +619,7 @@ namespace ImGuizmo
 
 	bool IsOver()
 	{
-		return (GetMoveType(NULL) != NONE) || GetRotateType() != NONE || IsUsing();
+		return (GetMoveType(NULL) != NONE) || GetRotateType() != NONE || GetScaleType() != NONE || IsUsing();
 	}
 
 	void Enable(bool enable)
@@ -626,30 +631,39 @@ namespace ImGuizmo
 
 	static float GetUniform(const vec_t& position, const matrix_t& mat)
 	{
-		vec_t trf = vect(position.x, position.y, position.z, 1.f);
+		vec_t trf = makeVect(position.x, position.y, position.z, 1.f);
 		trf.Transform(mat);
 		return trf.w;
 	}
 
-	static void ComputeContext(const float *view, const float *projection, float *matrix)
+	static void ComputeContext(const float *view, const float *projection, float *matrix, MODE mode)
 	{
 		gContext.mViewMat = *(matrix_t*)view;
 		gContext.mProjectionMat = *(matrix_t*)projection;
-		gContext.mModel = *(matrix_t*)matrix;
+		if (mode == LOCAL)
+		{
+			gContext.mModel = *(matrix_t*)matrix;
+			gContext.mModel.OrthoNormalize();
+		}
+		else
+		{
+			gContext.mModel.Translation(((matrix_t*)matrix)->v.position);
+		}
+		gContext.mModelSource = *(matrix_t*)matrix;
 		gContext.mModelInverse.Inverse(gContext.mModel);
 		gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat;
 		gContext.mMVP = gContext.mModel * gContext.mViewProjection;
 
 		matrix_t viewInverse;
 		viewInverse.Inverse(gContext.mViewMat);
-		gContext.mCameraDir = viewInverse.dir;
-		gContext.mCameraEye = viewInverse.position;
-		gContext.mCameraRight = viewInverse.right;
-		gContext.mCameraUp = viewInverse.up;
-		gContext.mCameraToModel = gContext.mModel.position - gContext.mCameraEye;
-		gContext.mScreenFactor = 0.1f * GetUniform(gContext.mModel.position, gContext.mViewProjection);
-
-		ImVec2 centerSSpace = worldToPos(vect(0.f), gContext.mMVP);
+		gContext.mCameraDir = viewInverse.v.dir;
+		gContext.mCameraEye = viewInverse.v.position;
+		gContext.mCameraRight = viewInverse.v.right;
+		gContext.mCameraUp = viewInverse.v.up;
+		gContext.mCameraToModel = gContext.mModel.v.position - gContext.mCameraEye;
+		gContext.mScreenFactor = 0.1f * GetUniform(gContext.mModel.v.position, gContext.mViewProjection);
+
+		ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP);
 		gContext.mScreenSquareCenter = centerSSpace;
 		gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f);
 		gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f);
@@ -657,11 +671,11 @@ namespace ImGuizmo
 		ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector);
 	}
 
-	static void ComputeColors(ImU32 *colors, int type, MODE mode)
+	static void ComputeColors(ImU32 *colors, int type, OPERATION operation)
 	{
 		if (gContext.mbEnable)
 		{
-			switch (mode)
+			switch (operation)
 			{
 			case TRANSLATE:
 				colors[0] = (type == MOVE_SCREEN) ? selectionColor : 0xFFFFFFFF;
@@ -678,12 +692,15 @@ namespace ImGuizmo
 					colors[i + 1] = (type == (int)(ROTATE_X + i)) ? selectionColor : directionColor[i];
 				break;
 			case SCALE:
+				colors[0] = (type == SCALE_XYZ) ? selectionColor : 0xFFFFFFFF;
+				for (int i = 0; i < 3; i++)
+					colors[i + 1] = (type == (int)(SCALE_X + i)) ? selectionColor : directionColor[i];
 				break;
 			}
 		}
 		else
 		{
-			for (int i = 0; i < int(sizeof(colors) / sizeof(ImU32)); i++)
+			for (int i = 0; i < 7; i++)
 				colors[i] = inactiveColor;
 		}
 	}
@@ -709,19 +726,19 @@ namespace ImGuizmo
 			for (unsigned int i = 0; i < halfCircleSegmentCount; i++)
 			{
 				float ng = angleStart + ZPI * ((float)i / (float)halfCircleSegmentCount);
-				vec_t axisPos = vect(cosf(ng), sinf(ng), 0.f);
-				vec_t pos = vect(axisPos[axis], axisPos[(axis+1)%3], axisPos[(axis+2)%3]) * gContext.mScreenFactor;
+				vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f);
+				vec_t pos = makeVect(axisPos[axis], axisPos[(axis+1)%3], axisPos[(axis+2)%3]) * gContext.mScreenFactor;
 				circlePos[i] = worldToPos(pos, gContext.mMVP);
 			}
 			drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2, true);
 		}
-		drawList->AddCircle(worldToPos(gContext.mModel.position, gContext.mViewProjection), 0.06f * io.DisplaySize.x, colors[0], 64);
+		drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), 0.06f * io.DisplaySize.x, colors[0], 64);
 
 		if (gContext.mbUsing)
 		{
 			ImVec2 circlePos[halfCircleSegmentCount +1];
 
-			circlePos[0] = worldToPos(gContext.mModel.position, gContext.mViewProjection);
+			circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
 			for (unsigned int i = 1; i < halfCircleSegmentCount; i++)
 			{
 				float ng = gContext.mRotationAngle * ((float)(i-1) / (float)(halfCircleSegmentCount -1));
@@ -730,7 +747,7 @@ namespace ImGuizmo
 				vec_t pos;
 				pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix);
 				pos *= gContext.mScreenFactor;
-				circlePos[i] = worldToPos(pos + gContext.mModel.position, gContext.mViewProjection);
+				circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
 			}
 			drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF, true);
 			drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2, true);
@@ -751,62 +768,63 @@ namespace ImGuizmo
 		ImU32 colors[7];
 		ComputeColors(colors, type, SCALE);
 
-		// draw screen quad
-		drawList->AddCircle(gContext.mScreenSquareCenter, 8.f, colors[0]);
-		/*
+		// draw screen cirle
+		drawList->AddCircleFilled(gContext.mScreenSquareCenter, 12.f, colors[0], 32);
+
 		// draw
+		vec_t scale = { 1.f, 1.f, 1.f, 1.f };
+		
+		if (gContext.mbUsing)
+			scale = gContext.mScale;
+			
 		for (unsigned int i = 0; i < 3; i++)
 		{
-			const int planNormal = (i + 2) % 3;
-			const vec_t& dirPlaneX = direction[i];
-			const vec_t& dirPlaneY = direction[(i + 1) % 3];
-			const vec_t& dirPlaneNormal = direction[planNormal];
+			//const int planNormal = (i + 2) % 3;
+			const vec_t& dirPlaneX = directionUnary[i];
+			//const vec_t& dirPlaneY = directionUnary[(i + 1) % 3];
+			//const vec_t& dirPlaneNormal = directionUnary[planNormal];
 
-			vec_t cameraEyeToGizmo = Normalized(gContext.mModel.position - gContext.mCameraEye);
-			const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneX)) < angleLimit);
-			const bool belowPlaneLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneNormal)) > planeLimit);
+			//vec_t cameraEyeToGizmo = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
+			//const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneX)) < angleLimit);
+			//const bool belowPlaneLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneNormal)) > planeLimit);
 
 			// draw axis
-			if (belowAxisLimit)
+			//if (belowAxisLimit)
 			{
 				ImVec2 baseSSpace = worldToPos(dirPlaneX * 0.1f * gContext.mScreenFactor, gContext.mMVP);
-				ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
+				ImVec2 worldDirSSpaceNoScale = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
+				ImVec2 worldDirSSpace = worldToPos(dirPlaneX * (1.f / scale[i]) * gContext.mScreenFactor, gContext.mMVP);
 
-				drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
-			}
-
-			// draw plane
-			if (belowPlaneLimit)
-			{
-				ImVec2 screenQuadPts[4];
-				for (int j = 0; j < 4; j++)
+				if (gContext.mbUsing)
 				{
-					vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY  * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
-					screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
+					drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 6.f);
+					drawList->AddCircleFilled(worldDirSSpaceNoScale, 10.f, 0xFF404040);
 				}
-				drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4], true);
+
+				drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
+				drawList->AddCircleFilled(worldDirSSpace, 10.f, colors[i + 1]);
 			}
 		}
-
+		
 		if (gContext.mbUsing)
 		{
-			ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
-			ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.position, gContext.mViewProjection);
-			vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
+//			ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
+			ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
+			/*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
 			dif.Normalize();
 			dif *= 5.f;
 			drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
 			drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
 			drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
-
+			*/
 			char tmps[512];
-			vec_t deltaInfo = gContext.mModel.position - gContext.mMatrixOrigin;
-			int componentInfoIndex = (type - MOVE_X) * 3;
-			ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);
+			//vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
+			int componentInfoIndex = (type - SCALE_X) * 3;
+			ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - SCALE_X], 1.f/gContext.mScale[translationInfoIndex[componentInfoIndex]]);
 			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)
@@ -818,22 +836,22 @@ namespace ImGuizmo
 		ComputeColors(colors, type, TRANSLATE);
 
 		// draw screen quad
-		drawList->AddCircle(gContext.mScreenSquareCenter, 8.f, colors[0]);
+		drawList->AddRectFilled(gContext.mScreenSquareMin, gContext.mScreenSquareMax, colors[0], 2.f);
 
 		// draw
 		for (unsigned int i = 0; i < 3; i++)
 		{
-			const int planNormal = (i + 2) % 3;
-			const vec_t& dirPlaneX = direction[i];
-			const vec_t& dirPlaneY = direction[(i + 1) % 3];
-			const vec_t& dirPlaneNormal = direction[planNormal];
+			//const int planNormal = (i + 2) % 3;
+			const vec_t& dirPlaneX = directionUnary[i];
+			const vec_t& dirPlaneY = directionUnary[(i + 1) % 3];
+			//const vec_t& dirPlaneNormal = directionUnary[planNormal];
 
-			vec_t cameraEyeToGizmo = Normalized(gContext.mModel.position - gContext.mCameraEye);
-			const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneX)) < angleLimit);
-			const bool belowPlaneLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneNormal)) > planeLimit);
+			//vec_t cameraEyeToGizmo = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
+			//const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneX)) < angleLimit);
+			//const bool belowPlaneLimit = (fabsf(cameraEyeToGizmo.Dot3(dirPlaneNormal)) > planeLimit);
 
 			// draw axis
-			if (belowAxisLimit)
+			//if (belowAxisLimit)
 			{
 				ImVec2 baseSSpace = worldToPos(dirPlaneX * 0.1f * gContext.mScreenFactor, gContext.mMVP);
 				ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
@@ -842,7 +860,7 @@ namespace ImGuizmo
 			}
 
 			// draw plane
-			if (belowPlaneLimit)
+			//if (belowPlaneLimit)
 			{
 				ImVec2 screenQuadPts[4];
 				for (int j = 0; j < 4; j++)
@@ -857,8 +875,8 @@ namespace ImGuizmo
 		if (gContext.mbUsing)
 		{
 			ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
-			ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.position, gContext.mViewProjection);
-			vec_t dif = vect(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
+			ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
+			vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y, 0.0f, 0.0f };
 			dif.Normalize();
 			dif *= 5.f;
 			drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
@@ -866,7 +884,7 @@ namespace ImGuizmo
 			drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
 
 			char tmps[512];
-			vec_t deltaInfo = gContext.mModel.position - gContext.mMatrixOrigin;
+			vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
 			int componentInfoIndex = (type - MOVE_X) * 3;
 			ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);
 			drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
@@ -879,32 +897,32 @@ namespace ImGuizmo
 
 	static int GetScaleType()
 	{
-		int type = NONE;
-		/*
 		ImGuiIO& io = ImGui::GetIO();
-		vec_t deltaScreen(io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y);
-		float dist = deltaScreen.Length();
-		if (dist >= 0.058f * io.DisplaySize.x && dist < 0.062f * io.DisplaySize.x)
-			type = ROTATE_SCREEN;
+		int type = NONE;
 
-		const vec_t planNormals[] = { gContext.mModel.right, gContext.mModel.up, gContext.mModel.dir };
+		// screen
+		if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
+			io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y)
+			type = SCALE_XYZ;
 
+		const vec_t direction[3] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir };
+		// compute
 		for (unsigned int i = 0; i < 3 && type == NONE; i++)
 		{
-			// pickup plan
-			vec_t pickupPlan = BuildPlan(gContext.mModel.position, planNormals[i]);
+			const int planNormal = (i + 2) % 3;
+			const int nextPlan = (i + 1) % 3;
 
-			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);
-			vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.position;
+			vec_t cameraEyeToGizmo = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
+			const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(direction[i])) < angleLimit);
 
-			if (Dot(Normalized(localPos), gContext.mRayVector) > FLT_EPSILON)
-				continue;
+			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, direction[planNormal]));
+			vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
 
-			float distance = localPos.Length() / gContext.mScreenFactor;
-			if (distance > 0.9f && distance < 1.1f)
-				type = ROTATE_X + i;
+			const float dx = direction[i].Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
+			const float dy = direction[nextPlan].Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
+			if (belowAxisLimit && dy > -0.1f && dy < 0.1f && dx > 0.1f  && dx < 1.f)
+				type = SCALE_X + i;
 		}
-		*/
 		return type;
 	}
 
@@ -913,20 +931,20 @@ namespace ImGuizmo
 		ImGuiIO& io = ImGui::GetIO();
 		int type = NONE;
 
-		vec_t deltaScreen = vect(io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y);
+		vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.0f, 0.0f };
 		float dist = deltaScreen.Length();
 		if (dist >= 0.058f * io.DisplaySize.x && dist < 0.062f * io.DisplaySize.x)
 			type = ROTATE_SCREEN;
 
-		const vec_t planNormals[] = { gContext.mModel.right, gContext.mModel.up, gContext.mModel.dir};
+		const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir};
 
 		for (unsigned int i = 0; i < 3 && type == NONE; i++)
 		{
 			// pickup plan
-			vec_t pickupPlan = BuildPlan(gContext.mModel.position, planNormals[i]);
+			vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]);
 
 			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);
-			vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.position;
+			vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;
 
 			if (Dot(Normalized(localPos), gContext.mRayVector) > FLT_EPSILON)
 				continue;
@@ -949,21 +967,23 @@ namespace ImGuizmo
 			io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y)
 			type = MOVE_SCREEN;
 
+		const vec_t direction[3] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir };
+
 		// compute
 		for (unsigned int i = 0; i < 3 && type == NONE; i++)
 		{
 			const int planNormal = (i + 2) % 3;
 			const int nextPlan = (i + 1) % 3;
 
-			vec_t cameraEyeToGizmo = Normalized(gContext.mModel.position - gContext.mCameraEye);
+			vec_t cameraEyeToGizmo = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
 			const bool belowAxisLimit = (fabsf(cameraEyeToGizmo.Dot3(direction[i])) < angleLimit);
 			const bool belowPlaneLimit = (fabsf(cameraEyeToGizmo.Dot3(direction[planNormal])) > planeLimit);
 
-			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.position, direction[planNormal]));
+			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, direction[planNormal]));
 			vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
 
-			const float dx = direction[i].Dot3((posOnPlan - gContext.mModel.position) * (1.f / gContext.mScreenFactor));
-			const float dy = direction[nextPlan].Dot3((posOnPlan - gContext.mModel.position) * (1.f / gContext.mScreenFactor));
+			const float dx = direction[i].Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
+			const float dy = direction[nextPlan].Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
 			if (belowAxisLimit && dy > -0.1f && dy < 0.1f && dx > 0.1f  && dx < 1.f)
 				type = MOVE_X + i;
 
@@ -971,7 +991,7 @@ namespace ImGuizmo
 				type = MOVE_XY + i;
 
 			if (gizmoHitProportion)
-				*gizmoHitProportion = vect(dx, dy, 0.f);
+				*gizmoHitProportion = makeVect(dx, dy, 0.f);
 		}
 		return type;
 	}
@@ -986,13 +1006,13 @@ namespace ImGuizmo
 			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
 			vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
 			vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
-			vec_t delta = newOrigin - gContext.mModel.position;
+			vec_t delta = newOrigin - gContext.mModel.v.position;
 
 			// 1 axis constraint
 			if (gContext.mCurrentOperation >= MOVE_X && gContext.mCurrentOperation <= MOVE_Z)
 			{
 				int axisIndex = gContext.mCurrentOperation - MOVE_X;
-				const vec_t& axisValue = gContext.mModel.line[axisIndex];
+				const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex];
 				float lengthOnAxis = Dot(axisValue, delta);
 				delta = axisValue * lengthOnAxis;
 			}
@@ -1000,10 +1020,10 @@ namespace ImGuizmo
 			// compute matrix & delta
 			gContext.mTranslationPlanOrigin += delta;
 			matrix_t deltaMatrixTranslation;
-			deltaMatrixTranslation.translation(delta);
+			deltaMatrixTranslation.Translation(delta);
 			if (deltaMatrix)
 				memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16);
-			matrix_t res = *(matrix_t*)matrix * deltaMatrixTranslation;
+			matrix_t res = gContext.mModelSource * deltaMatrixTranslation;
 			*(matrix_t*)matrix = res;
 
 			if (!io.MouseDown[0])
@@ -1020,80 +1040,90 @@ namespace ImGuizmo
 			{
 				gContext.mbUsing = true;
 				gContext.mCurrentOperation = type;
-				const vec_t movePlanNormal[] = { gContext.mModel.up, gContext.mModel.dir, gContext.mModel.right, gContext.mModel.dir, gContext.mModel.up, gContext.mModel.right, -gContext.mCameraDir };
+				const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.up, -gContext.mCameraDir };
 				// pickup plan
-				gContext.mTranslationPlan = BuildPlan(gContext.mModel.position, movePlanNormal[type - MOVE_X]);
+				gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MOVE_X]);
 				const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
 				gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
-				gContext.mMatrixOrigin = gContext.mModel.position;
+				gContext.mMatrixOrigin = gContext.mModel.v.position;
 
-				gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.position) * (1.f / gContext.mScreenFactor);
+				gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
 			}
 		}
 	}
 
-	static void HandleScale(float * /*matrix*/, float * /*deltaMatrix*/, int& type)
+	static void HandleScale(float *matrix, float *deltaMatrix, int& type)
 	{
 		ImGuiIO& io = ImGui::GetIO();
 
-		// move
+		if (!gContext.mbUsing)
+		{
+			// find new possible way to scale
+			//vec_t gizmoHitProportion;
+			type = GetScaleType();
+			if (io.MouseDown[0] && type != NONE)
+			{
+				gContext.mbUsing = true;
+				gContext.mCurrentOperation = type;
+				const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir };
+				// pickup plan
+
+				gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - SCALE_X]);
+				const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
+				gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
+			 	gContext.mMatrixOrigin = gContext.mModel.v.position;
+				gContext.mScale.Set(1.f, 1.f, 1.f);
+				gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
+				gContext.mScaleMousePos = io.MousePos;
+			}
+		}
+		// scale
 		if (gContext.mbUsing)
 		{
-			/*
+			vec_t newScale = { 1.f, 1.f, 1.f, 0.0f };
 			const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
 			vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
 			vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
-			vec_t delta = newOrigin - gContext.mModel.position;
+			vec_t delta = newOrigin - gContext.mModel.v.position;
+			
 			// 1 axis constraint
-			if (gContext.mCurrentOperation >= MOVE_X && gContext.mCurrentOperation <= MOVE_Z)
+			if (gContext.mCurrentOperation >= SCALE_X && gContext.mCurrentOperation <= SCALE_Z)
 			{
-				int axisIndex = gContext.mCurrentOperation - MOVE_X;
-				const vec_t& axisValue = gContext.mModel.line[axisIndex];
-				float lengthOnAxis = Dot(axisValue, delta);
-				delta = axisValue * lengthOnAxis;
+				int axisIndex = gContext.mCurrentOperation - SCALE_X;
+				const vec_t& axisValue = directionUnary[axisIndex];
+				float lengthOnAxis = 1.f - Dot(axisValue, delta) / gContext.mScreenFactor;
+				
+				if (lengthOnAxis >= 0.f)
+					newScale[axisIndex] = lengthOnAxis;
+				else
+					newScale[axisIndex] = Clamp(lengthOnAxis, 0.001f, 1.f);
 			}
-
+			else
+			{			
+				float newScaleUniform = 1.f + (io.MousePos.x - gContext.mScaleMousePos.x) * 0.01f;
+				newScale.Set(newScaleUniform, newScaleUniform, newScaleUniform, 0.f);
+			}
+			
 			// compute matrix & delta
-			gContext.mTranslationPlanOrigin += delta;
-			matrix_t deltaMatrixTranslation;
-			deltaMatrixTranslation.translation(delta);
+			matrix_t deltaMatrixScale;
+			deltaMatrixScale.Scale(makeVect(1.f, 1.f, 1.f) - (newScale - gContext.mScale));
+			gContext.mScale = newScale;
 			if (deltaMatrix)
-				memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16);
-			matrix_t res = *(matrix_t*)matrix * deltaMatrixTranslation;
+				memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16);
+			matrix_t res = deltaMatrixScale * gContext.mModelSource;
 			*(matrix_t*)matrix = res;
-			*/
+			
 			if (!io.MouseDown[0])
 				gContext.mbUsing = false;
 
 			type = gContext.mCurrentOperation;
 		}
-		else
-		{
-			// find new possible way to move
-			vec_t gizmoHitProportion;
-			type = GetMoveType(&gizmoHitProportion);
-			if (io.MouseDown[0] && type != NONE)
-			{
-				gContext.mbUsing = true;
-				gContext.mCurrentOperation = type;
-				// pickup plan
-				/*
-				const vec_t movePlanNormal[] = { gContext.mModel.up, gContext.mModel.dir, gContext.mModel.right, gContext.mModel.dir, gContext.mModel.up, gContext.mModel.right, -gContext.mCameraDir };
-				gContext.mTranslationPlan = BuildPlan(gContext.mModel.position, movePlanNormal[type - MOVE_X]);
-				const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
-				gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
-				gContext.mMatrixOrigin = gContext.mModel.position;
-
-				gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.position) * (1.f / gContext.mScreenFactor);
-				*/
-			}
-		}
 	}
 
 	static float ComputeAngleOnPlan()
 	{
 		const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
-		vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.position);
+		vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
 
 		vec_t perpendicularVector;
 		perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
@@ -1115,33 +1145,35 @@ namespace ImGuizmo
 			{
 				gContext.mbUsing = true;
 				gContext.mCurrentOperation = type;
-				const vec_t rotatePlanNormal[] = { gContext.mModel.right, gContext.mModel.up, gContext.mModel.dir, -gContext.mCameraDir };
+				const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
 				// pickup plan
-				gContext.mTranslationPlan = BuildPlan(gContext.mModel.position, rotatePlanNormal[type - ROTATE_X]);
+				gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - ROTATE_X]);
 
 				const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
-				vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.position;
+				vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;
 				gContext.mRotationVectorSource = Normalized(localPos);
 				gContext.mRotationAngleOrigin = ComputeAngleOnPlan();
 			}
 		}
 
-		// move
+		// rotation
 		if (gContext.mbUsing)
 		{
 			gContext.mRotationAngle = ComputeAngleOnPlan();
 
 			vec_t rotationAxisLocalSpace;
-			rotationAxisLocalSpace.TransformVector(vect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
+			rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
 
 			matrix_t deltaRotation;
 			deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin);
 			gContext.mRotationAngleOrigin = gContext.mRotationAngle;
 
-			*(matrix_t*)matrix = deltaRotation * gContext.mModel;
+			*(matrix_t*)matrix = deltaRotation * gContext.mModelSource;
 
 			if (deltaMatrix)
-				*(matrix_t*)deltaMatrix = deltaRotation;
+			{
+				*(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel;
+			}
 
 			if (!io.MouseDown[0])
 				gContext.mbUsing = false;
@@ -1149,10 +1181,43 @@ namespace ImGuizmo
 			type = gContext.mCurrentOperation;
 		}
 	}
-	
-	void Mogwai(const float *view, const float *projection, ImGuizmo::MODE mode, float *matrix, float *deltaMatrix)
+
+	void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale)
+	{
+		matrix_t& mat = *(matrix_t*)matrix;
+
+		rotation[0] = RAD2DEG * atan2f(mat.m[1][2], mat.m[2][2]);
+		rotation[1] = RAD2DEG * atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] + mat.m[2][2]* mat.m[2][2]));
+		rotation[2] = RAD2DEG * atan2f(mat.m[0][1], mat.m[0][0]);
+
+		scale[0] = mat.v.right.Length();
+		scale[1] = mat.v.up.Length();
+		scale[2] = mat.v.dir.Length();
+
+		translation[0] = mat.v.position.x;
+		translation[1] = mat.v.position.y;
+		translation[2] = mat.v.position.z;
+	}
+
+	void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix)
 	{
-		ComputeContext(view, projection, matrix);
+		matrix_t& mat = *(matrix_t*)matrix;
+
+		matrix_t rot[3];
+		for (int i = 0; i < 3;i++)
+			rot[i].RotationAxis(directionUnary[i], rotation[i] * DEG2RAD);
+
+		mat = rot[0] * rot[1] * rot[2];
+
+		mat.v.right *= scale[0];
+		mat.v.up *= scale[1];
+		mat.v.dir *= scale[2];
+		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)
+	{
+		ComputeContext(view, projection, matrix, mode);
 
 		// set delta to identity 
 		if (deltaMatrix)
@@ -1161,7 +1226,7 @@ namespace ImGuizmo
 		int type = NONE;
 		if (gContext.mbEnable)
 		{
-			switch (mode)
+			switch (operation)
 			{
 			case ROTATE:
 				HandleRotation(matrix, deltaMatrix, type);
@@ -1175,7 +1240,7 @@ namespace ImGuizmo
 			}
 		}
 
-		switch (mode)
+		switch (operation)
 		{
 		case ROTATE:
 			DrawRotationGizmo(type);
@@ -1188,4 +1253,41 @@ namespace ImGuizmo
 			break;
 		}
 	}
-} // namespace ImGuizmo
+
+	void DrawCube(const float *view, const float *projection, float *matrix)
+	{
+		matrix_t viewInverse;
+		viewInverse.Inverse(*(matrix_t*)view);
+		const matrix_t& model = *(matrix_t*)matrix;
+		matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection;
+
+		for (int iFace = 0; iFace < 6; iFace++)
+		{
+			const int normalIndex = (iFace % 3);
+			const int perpXIndex = (normalIndex + 1) % 3;
+			const int perpYIndex = (normalIndex + 2) % 3;
+			const float invert = (iFace > 2) ? -1.f : 1.f;
+			
+			const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex],
+				directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex],
+				directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex],
+				directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex],
+			};
+			ImVec2 faceCoordsScreen[4];
+			for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
+				faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res);
+
+			// back face culling 
+			vec_t cullPos, cullNormal;
+			cullPos.TransformPoint(faceCoords[0] * 0.5f * invert, model);
+			cullNormal.TransformVector(directionUnary[normalIndex] * invert, model);
+			float dt = Dot(Normalized(cullPos - viewInverse.v.position), Normalized(cullNormal));
+			if (dt>0.f)
+				continue;
+
+			// draw face with lighter color
+			gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080, true);
+		}
+	}
+};
+