diff options
author | rtk0c <[email protected]> | 2022-06-03 23:26:44 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-06-03 23:26:44 -0700 |
commit | 60ccc62f4934e44ad5b905fdbcf458302b8d8a09 (patch) | |
tree | 02ec83cc8387abfd08bd5ee7ea4e8115f1bfb8d0 /source/30-game/EditorGuizmo.cpp | |
parent | c2ef7737536bf1f8c81fcfae95c0183b21c9753f (diff) |
Changeset: 63 [WIP] Rename directories
Diffstat (limited to 'source/30-game/EditorGuizmo.cpp')
-rw-r--r-- | source/30-game/EditorGuizmo.cpp | 2897 |
1 files changed, 0 insertions, 2897 deletions
diff --git a/source/30-game/EditorGuizmo.cpp b/source/30-game/EditorGuizmo.cpp deleted file mode 100644 index 3e4f890..0000000 --- a/source/30-game/EditorGuizmo.cpp +++ /dev/null @@ -1,2897 +0,0 @@ -// https://github.com/CedricGuillemet/ImGuizmo -// v 1.84 WIP -// -// The MIT License(MIT) -// -// Copyright(c) 2021 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. -// - -#ifndef IMGUI_DEFINE_MATH_OPERATORS -# define IMGUI_DEFINE_MATH_OPERATORS -#endif -#include "EditorGuizmo.hpp" -#include "imgui_internal.h" - -#if defined(_MSC_VER) || defined(__MINGW32__) -# include <malloc.h> -#endif -#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR) -# define _malloca(x) alloca(x) -# define _freea(x) -#endif - -// includes patches for multiview from -// https://github.com/CedricGuillemet/ImGuizmo/issues/15 - -namespace IMGUIZMO_NAMESPACE { -static const float ZPI = 3.14159265358979323846f; -static const float RAD2DEG = (180.f / ZPI); -static const float DEG2RAD = (ZPI / 180.f); -const float screenRotateSize = 0.06f; -// scale a bit so translate axis do not touch when in universal -const float rotationDisplayFactor = 1.2f; - -static OPERATION operator&(OPERATION lhs, OPERATION rhs) { - return static_cast<OPERATION>(static_cast<int>(lhs) & static_cast<int>(rhs)); -} - -static bool operator!=(OPERATION lhs, int rhs) { - return static_cast<int>(lhs) != rhs; -} - -static bool Intersects(OPERATION lhs, OPERATION rhs) { - return (lhs & rhs) != 0; -} - -// True if lhs contains rhs -static bool Contains(OPERATION lhs, OPERATION rhs) { - return (lhs & rhs) == rhs; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// utility and math - -void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r) { - r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; - r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; - r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; - r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; - - r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; - r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; - r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; - r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; - - r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; - r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; - r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; - r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; - - r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; - r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; - r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; - r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; -} - -void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16) { - float temp, temp2, temp3, temp4; - temp = 2.0f * znear; - temp2 = right - left; - temp3 = top - bottom; - temp4 = zfar - znear; - m16[0] = temp / temp2; - m16[1] = 0.0; - m16[2] = 0.0; - m16[3] = 0.0; - m16[4] = 0.0; - m16[5] = temp / temp3; - m16[6] = 0.0; - m16[7] = 0.0; - m16[8] = (right + left) / temp2; - m16[9] = (top + bottom) / temp3; - m16[10] = (-zfar - znear) / temp4; - m16[11] = -1.0f; - m16[12] = 0.0; - m16[13] = 0.0; - m16[14] = (-temp * zfar) / temp4; - m16[15] = 0.0; -} - -void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16) { - float ymax, xmax; - ymax = znear * tanf(fovyInDegrees * DEG2RAD); - xmax = ymax * aspectRatio; - Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16); -} - -void Cross(const float* a, const float* b, float* r) { - r[0] = a[1] * b[2] - a[2] * b[1]; - r[1] = a[2] * b[0] - a[0] * b[2]; - r[2] = a[0] * b[1] - a[1] * b[0]; -} - -float Dot(const float* a, const float* b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -void Normalize(const float* a, float* r) { - float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON); - r[0] = a[0] * il; - r[1] = a[1] * il; - r[2] = a[2] * il; -} - -void LookAt(const float* eye, const float* at, const float* up, float* m16) { - float X[3], Y[3], Z[3], tmp[3]; - - tmp[0] = eye[0] - at[0]; - tmp[1] = eye[1] - at[1]; - tmp[2] = eye[2] - at[2]; - Normalize(tmp, Z); - Normalize(up, Y); - Cross(Y, Z, tmp); - Normalize(tmp, X); - Cross(Z, X, tmp); - Normalize(tmp, Y); - - m16[0] = X[0]; - m16[1] = Y[0]; - m16[2] = Z[0]; - m16[3] = 0.0f; - m16[4] = X[1]; - m16[5] = Y[1]; - m16[6] = Z[1]; - m16[7] = 0.0f; - m16[8] = X[2]; - m16[9] = Y[2]; - m16[10] = Z[2]; - m16[11] = 0.0f; - m16[12] = -Dot(X, eye); - m16[13] = -Dot(Y, eye); - m16[14] = -Dot(Z, eye); - m16[15] = 1.0f; -} - -template <typename T> -T Clamp(T x, T y, T z) { - return ((x < y) ? y : ((x > z) ? z : x)); -} -template <typename T> -T max(T x, T y) { - return (x > y) ? x : y; -} -template <typename T> -T min(T x, T y) { - return (x < y) ? x : y; -} -template <typename T> -bool IsWithin(T x, T y, T z) { - return (x >= y) && (x <= z); -} - -struct matrix_t; -struct vec_t { -public: - float x, y, z, w; - - void Lerp(const vec_t& v, float t) { - x += (v.x - x) * t; - y += (v.y - y) * t; - z += (v.z - z) * t; - 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; - } - - 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; - } - vec_t& operator*=(const vec_t& v) { - x *= v.x; - y *= v.y; - z *= v.z; - w *= v.w; - return *this; - } - vec_t& operator*=(float v) { - x *= v; - y *= v; - z *= v; - w *= v; - return *this; - } - - vec_t operator*(float f) const; - vec_t operator-() const; - vec_t operator-(const vec_t& v) const; - vec_t operator+(const vec_t& v) const; - vec_t operator*(const vec_t& v) const; - - const vec_t& operator+() const { return (*this); } - 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() > FLT_EPSILON ? Length() : FLT_EPSILON)); - 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 Abs() const; - - void Cross(const vec_t& v) { - vec_t res; - res.x = y * v.z - z * v.y; - res.y = z * v.x - x * v.z; - res.z = x * v.y - y * v.x; - - x = res.x; - y = res.y; - z = res.z; - w = 0.f; - } - - void Cross(const vec_t& v1, const vec_t& v2) { - x = v1.y * v2.z - v1.z * v2.y; - y = v1.z * v2.x - v1.x * v2.z; - z = v1.x * v2.y - v1.y * v2.x; - w = 0.f; - } - - float Dot(const vec_t& v) const { - return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w); - } - - float Dot3(const vec_t& v) const { - return (x * v.x) + (y * v.y) + (z * v.z); - } - - void Transform(const matrix_t& matrix); - void Transform(const vec_t& s, const matrix_t& matrix); - - void TransformVector(const matrix_t& matrix); - void TransformPoint(const matrix_t& matrix); - void TransformVector(const vec_t& v, const matrix_t& matrix) { - (*this) = v; - this->TransformVector(matrix); - } - void TransformPoint(const vec_t& v, const matrix_t& matrix) { - (*this) = v; - this->TransformPoint(matrix); - } - - float& operator[](size_t index) { return ((float*)&x)[index]; } - const float& operator[](size_t index) const { return ((float*)&x)[index]; } - bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)); } -}; - -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 makeVect(ImVec2 v) { - vec_t res; - res.x = v.x; - res.y = v.y; - res.z = 0.f; - res.w = 0.f; - 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); -} -vec_t vec_t::Abs() const { - return makeVect(fabsf(x), fabsf(y), fabsf(z)); -} - -vec_t Normalized(const vec_t& v) { - vec_t res; - res = v; - res.Normalize(); - return res; -} -vec_t Cross(const vec_t& v1, const vec_t& v2) { - vec_t res; - res.x = v1.y * v2.z - v1.z * v2.y; - res.y = v1.z * v2.x - v1.x * v2.z; - res.z = v1.x * v2.y - v1.y * v2.x; - res.w = 0.f; - return res; -} - -float Dot(const vec_t& v1, const vec_t& v2) { - return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); -} - -vec_t BuildPlan(const vec_t& p_point1, const vec_t& p_normal) { - vec_t normal, res; - normal.Normalize(p_normal); - res.w = normal.Dot(p_point1); - res.x = normal.x; - res.y = normal.y; - res.z = normal.z; - return res; -} - -struct matrix_t { -public: - union { - float m[4][4]; - float m16[16]; - struct - { - vec_t right, up, dir, position; - } v; - vec_t component[4]; - }; - - operator float*() { return m16; } - operator const float*() const { return m16; } - void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); } - - void Translation(const vec_t& vt) { - 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) { - 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); } - - matrix_t& operator*=(const matrix_t& mat) { - matrix_t tmpMat; - tmpMat = *this; - tmpMat.Multiply(mat); - *this = tmpMat; - return *this; - } - matrix_t operator*(const matrix_t& mat) const { - matrix_t matT; - matT.Multiply(*this, mat); - return matT; - } - - void Multiply(const matrix_t& matrix) { - matrix_t tmp; - tmp = *this; - - FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this); - } - - void Multiply(const matrix_t& m1, const matrix_t& m2) { - FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this); - } - - float GetDeterminant() const { - return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - - m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1]; - } - - float Inverse(const matrix_t& srcMatrix, bool affine = false); - 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() { - matrix_t tmpm; - for (int l = 0; l < 4; l++) - { - for (int c = 0; c < 4; c++) - { - tmpm.m[l][c] = m[c][l]; - } - } - (*this) = tmpm; - } - - 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) { - vec_t out; - - out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0]; - out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1]; - out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2]; - out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3]; - - x = out.x; - y = out.y; - z = out.z; - w = out.w; -} - -void vec_t::Transform(const vec_t& s, const matrix_t& matrix) { - *this = s; - Transform(matrix); -} - -void vec_t::TransformPoint(const matrix_t& matrix) { - vec_t out; - - out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0]; - out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1]; - out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2]; - out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3]; - - x = out.x; - y = out.y; - z = out.z; - w = out.w; -} - -void vec_t::TransformVector(const matrix_t& matrix) { - vec_t out; - - out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0]; - out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1]; - out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2]; - out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3]; - - x = out.x; - y = out.y; - z = out.z; - w = out.w; -} - -float matrix_t::Inverse(const matrix_t& srcMatrix, bool affine) { - float det = 0; - - if (affine) - { - det = GetDeterminant(); - float s = 1 / det; - m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s; - m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s; - m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s; - m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s; - m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s; - m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s; - m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s; - m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s; - m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s; - m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]); - m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]); - m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]); - } else - { - // transpose matrix - float src[16]; - for (int i = 0; i < 4; ++i) - { - src[i] = srcMatrix.m16[i * 4]; - src[i + 4] = srcMatrix.m16[i * 4 + 1]; - src[i + 8] = srcMatrix.m16[i * 4 + 2]; - src[i + 12] = srcMatrix.m16[i * 4 + 3]; - } - - // calculate pairs for first 8 elements (cofactors) - float tmp[12]; // temp array for pairs - tmp[0] = src[10] * src[15]; - tmp[1] = src[11] * src[14]; - tmp[2] = src[9] * src[15]; - tmp[3] = src[11] * src[13]; - tmp[4] = src[9] * src[14]; - tmp[5] = src[10] * src[13]; - tmp[6] = src[8] * src[15]; - tmp[7] = src[11] * src[12]; - tmp[8] = src[8] * src[14]; - tmp[9] = src[10] * src[12]; - tmp[10] = src[8] * src[13]; - tmp[11] = src[9] * src[12]; - - // calculate first 8 elements (cofactors) - m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]); - m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]); - m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]); - m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]); - m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]); - m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]); - m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]); - m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]); - - // calculate pairs for second 8 elements (cofactors) - tmp[0] = src[2] * src[7]; - tmp[1] = src[3] * src[6]; - tmp[2] = src[1] * src[7]; - tmp[3] = src[3] * src[5]; - tmp[4] = src[1] * src[6]; - tmp[5] = src[2] * src[5]; - tmp[6] = src[0] * src[7]; - tmp[7] = src[3] * src[4]; - tmp[8] = src[0] * src[6]; - tmp[9] = src[2] * src[4]; - tmp[10] = src[0] * src[5]; - tmp[11] = src[1] * src[4]; - - // calculate second 8 elements (cofactors) - m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]); - m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]); - m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]); - m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]); - m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]); - m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]); - m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]); - m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]); - - // calculate determinant - det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3]; - - // calculate matrix inverse - float invdet = 1 / det; - for (int j = 0; j < 16; ++j) - { - m16[j] *= invdet; - } - } - - return det; -} - -void matrix_t::RotationAxis(const vec_t& axis, float angle) { - float length2 = axis.LengthSq(); - if (length2 < FLT_EPSILON) - { - SetToIdentity(); - return; - } - - vec_t n = axis * (1.f / sqrtf(length2)); - float s = sinf(angle); - float c = cosf(angle); - float k = 1.f - c; - - float xx = n.x * n.x * k + c; - float yy = n.y * n.y * k + c; - float zz = n.z * n.z * k + c; - float xy = n.x * n.y * k; - float yz = n.y * n.z * k; - float zx = n.z * n.x * k; - float xs = n.x * s; - float ys = n.y * s; - float zs = n.z * s; - - m[0][0] = xx; - m[0][1] = xy + zs; - m[0][2] = zx - ys; - m[0][3] = 0.f; - m[1][0] = xy - zs; - m[1][1] = yy; - m[1][2] = yz + xs; - m[1][3] = 0.f; - m[2][0] = zx + ys; - m[2][1] = yz - xs; - m[2][2] = zz; - m[2][3] = 0.f; - m[3][0] = 0.f; - m[3][1] = 0.f; - m[3][2] = 0.f; - m[3][3] = 1.f; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// - -enum MOVETYPE { - MT_NONE, - MT_MOVE_X, - MT_MOVE_Y, - MT_MOVE_Z, - MT_MOVE_YZ, - MT_MOVE_ZX, - MT_MOVE_XY, - MT_MOVE_SCREEN, - MT_ROTATE_X, - MT_ROTATE_Y, - MT_ROTATE_Z, - MT_ROTATE_SCREEN, - MT_SCALE_X, - MT_SCALE_Y, - MT_SCALE_Z, - MT_SCALE_XYZ -}; - -static bool IsTranslateType(int type) { - return type >= MT_MOVE_X && type <= MT_MOVE_SCREEN; -} - -static bool IsRotateType(int type) { - return type >= MT_ROTATE_X && type <= MT_ROTATE_SCREEN; -} - -static bool IsScaleType(int type) { - return type >= MT_SCALE_X && type <= MT_SCALE_XYZ; -} - -// Matches MT_MOVE_AB order -static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y }; - -struct Context { - Context() - : mbUsing(false), mbEnable(true), mbUsingBounds(false) { - } - - ImDrawList* mDrawList; - - MODE mMode; - matrix_t mViewMat; - matrix_t mProjectionMat; - matrix_t mModel; - matrix_t mModelLocal; // orthonormalized model - matrix_t mModelInverse; - matrix_t mModelSource; - matrix_t mModelSourceInverse; - matrix_t mMVP; - matrix_t mMVPLocal; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition - matrix_t mViewProjection; - - vec_t mModelScaleOrigin; - vec_t mCameraEye; - vec_t mCameraRight; - vec_t mCameraDir; - vec_t mCameraUp; - vec_t mRayOrigin; - vec_t mRayVector; - - float mRadiusSquareCenter; - ImVec2 mScreenSquareCenter; - ImVec2 mScreenSquareMin; - ImVec2 mScreenSquareMax; - - float mScreenFactor; - vec_t mRelativeOrigin; - - bool mbUsing; - bool mbEnable; - bool mbMouseOver; - bool mReversed; // reversed projection matrix - - // translation - vec_t mTranslationPlan; - vec_t mTranslationPlanOrigin; - vec_t mMatrixOrigin; - vec_t mTranslationLastDelta; - - // rotation - vec_t mRotationVectorSource; - float mRotationAngle; - float mRotationAngleOrigin; - // vec_t mWorldToLocalAxis; - - // scale - vec_t mScale; - vec_t mScaleValueOrigin; - vec_t mScaleLast; - float mSaveMousePosx; - - // save axis factor when using gizmo - bool mBelowAxisLimit[3]; - bool mBelowPlaneLimit[3]; - float mAxisFactor[3]; - - // bounds stretching - // NOTE: these variable only lives during the duration of a drag - /// Position in world space, of the knob on the opposite side of the knob being dragged. - /// This is the point that needs to space regardless of where anchor is placed. - vec_t mBoundsPivot; - /// Position in world space, of the knob begin dragged. - /// This is the point that's being moved. - vec_t mBoundsAnchor; - vec_t mBoundsPlan; - /// Position in local space, of the knob on the opposite side of the knob being dragged - vec_t mBoundsLocalPivot; - int mBoundsBestAxis; - /// The axes that are being modified by the current operation. May contain 1 or 2 elements. - /// Unused elements are filled with -1 during the operation. - int mBoundsAxis[2]; - /// The index of the corner that pivot data is fetched from (opposite side from anchor). - int mBoundsPivotCornerIndex; - bool mbUsingBounds; - bool mbIsUsingBigAnchor; - /// Model matrix passed into ImGuizmo::Manipulate() - matrix_t mBoundsMatrix; - - // - int mCurrentOperation; - - float mX = 0.f; - float mY = 0.f; - float mWidth = 0.f; - float mHeight = 0.f; - float mXMax = 0.f; - float mYMax = 0.f; - float mDisplayRatio = 1.f; - - bool mIsOrthographic = false; - - int mActualID = -1; - int mEditingID = -1; - OPERATION mOperation = OPERATION(-1); - - bool mAllowAxisFlip = true; - float mGizmoSizeClipSpace = 0.1f; -}; - -static Context gContext; - -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] = { IM_COL32(0xAA, 0, 0, 0xFF), IM_COL32(0, 0xAA, 0, 0xFF), IM_COL32(0, 0, 0xAA, 0XFF) }; - -// Alpha: 100%: FF, 87%: DE, 70%: B3, 54%: 8A, 50%: 80, 38%: 61, 12%: 1F -static const ImU32 planeColor[3] = { IM_COL32(0xAA, 0, 0, 0x61), IM_COL32(0, 0xAA, 0, 0x61), IM_COL32(0, 0, 0xAA, 0x61) }; -static const ImU32 selectionColor = IM_COL32(0xFF, 0x80, 0x10, 0x8A); -static const ImU32 inactiveColor = IM_COL32(0x99, 0x99, 0x99, 0x99); -static const ImU32 translationLineColor = IM_COL32(0xAA, 0xAA, 0xAA, 0xAA); -static const char* translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %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, 1, 2, 0, 0, 2, 0, 0, 1, 0, 0, 1, 2 }; -static const float quadMin = 0.5f; -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; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion); -static int GetRotateType(OPERATION op); -static int GetScaleType(OPERATION op); - -static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight)) { - vec_t trans; - trans.TransformPoint(worldPos, mat); - trans *= 0.5f / trans.w; - trans += makeVect(0.5f, 0.5f); - trans.y = 1.f - trans.y; - trans.x *= size.x; - trans.y *= size.y; - trans.x += position.x; - trans.y += position.y; - return ImVec2(trans.x, trans.y); -} - -static void ComputeCameraRay(vec_t& rayOrigin, vec_t& rayDir, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight)) { - ImGuiIO& io = ImGui::GetIO(); - - matrix_t mViewProjInverse; - mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat); - - const float mox = ((io.MousePos.x - position.x) / size.x) * 2.f - 1.f; - const float moy = (1.f - ((io.MousePos.y - position.y) / size.y)) * 2.f - 1.f; - - const float zNear = gContext.mReversed ? (1.f - FLT_EPSILON) : 0.f; - const float zFar = gContext.mReversed ? 0.f : (1.f - FLT_EPSILON); - - rayOrigin.Transform(makeVect(mox, moy, zNear, 1.f), mViewProjInverse); - rayOrigin *= 1.f / rayOrigin.w; - vec_t rayEnd; - rayEnd.Transform(makeVect(mox, moy, zFar, 1.f), mViewProjInverse); - rayEnd *= 1.f / rayEnd.w; - rayDir = Normalized(rayEnd - rayOrigin); -} - -static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end, const bool localCoordinates = false) { - vec_t startOfSegment = start; - const matrix_t& mvp = localCoordinates ? gContext.mMVPLocal : gContext.mMVP; - startOfSegment.TransformPoint(mvp); - if (fabsf(startOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction - { - startOfSegment *= 1.f / startOfSegment.w; - } - - vec_t endOfSegment = end; - endOfSegment.TransformPoint(mvp); - if (fabsf(endOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction - { - endOfSegment *= 1.f / endOfSegment.w; - } - - vec_t clipSpaceAxis = endOfSegment - startOfSegment; - clipSpaceAxis.y /= gContext.mDisplayRatio; - float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + clipSpaceAxis.y * clipSpaceAxis.y); - return segmentLengthInClipSpace; -} - -static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB) { - vec_t pts[] = { ptO, ptA, ptB }; - for (unsigned int i = 0; i < 3; i++) - { - pts[i].TransformPoint(gContext.mMVP); - if (fabsf(pts[i].w) > FLT_EPSILON) // check for axis aligned with camera direction - { - pts[i] *= 1.f / pts[i].w; - } - } - vec_t segA = pts[1] - pts[0]; - vec_t segB = pts[2] - pts[0]; - segA.y /= gContext.mDisplayRatio; - segB.y /= gContext.mDisplayRatio; - vec_t segAOrtho = makeVect(-segA.y, segA.x); - segAOrtho.Normalize(); - float dt = segAOrtho.Dot3(segB); - float surface = sqrtf(segA.x * segA.x + segA.y * segA.y) * fabsf(dt); - return surface; -} - -inline vec_t PointOnSegment(const vec_t& point, const vec_t& vertPos1, const vec_t& vertPos2) { - vec_t c = point - vertPos1; - vec_t V; - - V.Normalize(vertPos2 - vertPos1); - float d = (vertPos2 - vertPos1).Length(); - float t = V.Dot3(c); - - if (t < 0.f) - { - return vertPos1; - } - - if (t > d) - { - return vertPos2; - } - - return vertPos1 + V * t; -} - -static float IntersectRayPlane(const vec_t& rOrigin, const vec_t& rVector, const vec_t& plan) { - const float numer = plan.Dot3(rOrigin) - plan.w; - const float denom = plan.Dot3(rVector); - - if (fabsf(denom) < FLT_EPSILON) // normal is orthogonal to vector, cant intersect - { - return -1.0f; - } - - return -(numer / denom); -} - -static float DistanceToPlane(const vec_t& point, const vec_t& plan) { - return plan.Dot3(point) + plan.w; -} - -static bool IsInContextRect(ImVec2 p) { - return IsWithin(p.x, gContext.mX, gContext.mXMax) && IsWithin(p.y, gContext.mY, gContext.mYMax); -} - -static bool IsHoveringWindow() { - ImGuiContext& g = *ImGui::GetCurrentContext(); - ImGuiWindow* window = ImGui::FindWindowByName(gContext.mDrawList->_OwnerName); - if (g.HoveredWindow == window) // Mouse hovering drawlist window - return true; - if (g.HoveredWindow != NULL) // Any other window is hovered - return false; - if (ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max, false)) // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows) - return true; - return false; -} - -void SetRect(float x, float y, float width, float height) { - gContext.mX = x; - gContext.mY = y; - gContext.mWidth = width; - gContext.mHeight = height; - gContext.mXMax = gContext.mX + gContext.mWidth; - gContext.mYMax = gContext.mY + gContext.mXMax; - gContext.mDisplayRatio = width / height; -} - -void SetOrthographic(bool isOrthographic) { - gContext.mIsOrthographic = isOrthographic; -} - -void SetDrawlist(ImDrawList* drawlist) { - gContext.mDrawList = drawlist ? drawlist : ImGui::GetWindowDrawList(); -} - -void SetImGuiContext(ImGuiContext* ctx) { - ImGui::SetCurrentContext(ctx); -} - -void BeginFrame() { - const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus; - -#ifdef IMGUI_HAS_VIEWPORT - ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size); - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos); -#else - ImGuiIO& io = ImGui::GetIO(); - ImGui::SetNextWindowSize(io.DisplaySize); - ImGui::SetNextWindowPos(ImVec2(0, 0)); -#endif - - ImGui::PushStyleColor(ImGuiCol_WindowBg, 0); - ImGui::PushStyleColor(ImGuiCol_Border, 0); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - - ImGui::Begin("gizmo", NULL, flags); - gContext.mDrawList = ImGui::GetWindowDrawList(); - ImGui::End(); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(2); -} - -bool IsUsing() { - return gContext.mbUsing || gContext.mbUsingBounds; -} - -bool IsOver() { - return (Intersects(gContext.mOperation, TRANSLATE) && GetMoveType(gContext.mOperation, NULL) != MT_NONE) || - (Intersects(gContext.mOperation, ROTATE) && GetRotateType(gContext.mOperation) != MT_NONE) || - (Intersects(gContext.mOperation, SCALE) && GetScaleType(gContext.mOperation) != MT_NONE) || IsUsing(); -} - -bool IsOver(OPERATION op) { - if (IsUsing()) - { - return true; - } - if (Intersects(op, SCALE) && GetScaleType(op) != MT_NONE) - { - return true; - } - if (Intersects(op, ROTATE) && GetRotateType(op) != MT_NONE) - { - return true; - } - if (Intersects(op, TRANSLATE) && GetMoveType(op, NULL) != MT_NONE) - { - return true; - } - return false; -} - -void Enable(bool enable) { - gContext.mbEnable = enable; - if (!enable) - { - gContext.mbUsing = false; - gContext.mbUsingBounds = false; - } -} - -static void ComputeContext(const float* view, const float* projection, float* matrix, MODE mode) { - gContext.mMode = mode; - gContext.mViewMat = *(matrix_t*)view; - gContext.mProjectionMat = *(matrix_t*)projection; - gContext.mbMouseOver = IsHoveringWindow(); - - gContext.mModelLocal = *(matrix_t*)matrix; - gContext.mModelLocal.OrthoNormalize(); - - if (mode == LOCAL) - { - gContext.mModel = gContext.mModelLocal; - } else - { - gContext.mModel.Translation(((matrix_t*)matrix)->v.position); - } - gContext.mModelSource = *(matrix_t*)matrix; - gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length()); - - gContext.mModelInverse.Inverse(gContext.mModel); - gContext.mModelSourceInverse.Inverse(gContext.mModelSource); - gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat; - gContext.mMVP = gContext.mModel * gContext.mViewProjection; - gContext.mMVPLocal = gContext.mModelLocal * gContext.mViewProjection; - - matrix_t viewInverse; - viewInverse.Inverse(gContext.mViewMat); - gContext.mCameraDir = viewInverse.v.dir; - gContext.mCameraEye = viewInverse.v.position; - gContext.mCameraRight = viewInverse.v.right; - gContext.mCameraUp = viewInverse.v.up; - - // projection reverse - vec_t nearPos, farPos; - nearPos.Transform(makeVect(0, 0, 1.f, 1.f), gContext.mProjectionMat); - farPos.Transform(makeVect(0, 0, 2.f, 1.f), gContext.mProjectionMat); - - gContext.mReversed = (nearPos.z / nearPos.w) > (farPos.z / farPos.w); - - // compute scale from the size of camera right vector projected on screen at the matrix position - vec_t pointRight = viewInverse.v.right; - pointRight.TransformPoint(gContext.mViewProjection); - gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w); - - vec_t rightViewInverse = viewInverse.v.right; - rightViewInverse.TransformVector(gContext.mModelInverse); - float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse); - gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / rightLength; - - 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); - - ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector); -} - -static void ComputeColors(ImU32* colors, int type, OPERATION operation) { - if (gContext.mbEnable) - { - switch (operation) - { - case TRANSLATE: - colors[0] = (type == MT_MOVE_SCREEN) ? selectionColor : IM_COL32_WHITE; - for (int i = 0; i < 3; i++) - { - colors[i + 1] = (type == (int)(MT_MOVE_X + i)) ? selectionColor : directionColor[i]; - colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : planeColor[i]; - colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4]; - } - break; - case ROTATE: - colors[0] = (type == MT_ROTATE_SCREEN) ? selectionColor : IM_COL32_WHITE; - for (int i = 0; i < 3; i++) - { - colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? selectionColor : directionColor[i]; - } - break; - case SCALEU: - case SCALE: - colors[0] = (type == MT_SCALE_XYZ) ? selectionColor : IM_COL32_WHITE; - for (int i = 0; i < 3; i++) - { - colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? selectionColor : directionColor[i]; - } - break; - // note: this internal function is only called with three possible values for operation - default: - break; - } - } else - { - for (int i = 0; i < 7; i++) - { - colors[i] = inactiveColor; - } - } -} - -static void ComputeTripodAxisAndVisibility(const int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit, const bool localCoordinates = false) { - dirAxis = directionUnary[axisIndex]; - dirPlaneX = directionUnary[(axisIndex + 1) % 3]; - dirPlaneY = directionUnary[(axisIndex + 2) % 3]; - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - // when using, use stored factors so the gizmo doesn't flip when we translate - belowAxisLimit = gContext.mBelowAxisLimit[axisIndex]; - belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex]; - - dirAxis *= gContext.mAxisFactor[axisIndex]; - dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3]; - dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3]; - } else - { - // new method - float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis, localCoordinates); - float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis, localCoordinates); - - float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX, localCoordinates); - float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneX, localCoordinates); - - float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneY, localCoordinates); - float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneY, localCoordinates); - - // For readability - bool& allowFlip = gContext.mAllowAxisFlip; - float mulAxis = (allowFlip && lenDir < lenDirMinus && fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f; - float mulAxisX = (allowFlip && lenDirPlaneX < lenDirMinusPlaneX && fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f; - float mulAxisY = (allowFlip && lenDirPlaneY < lenDirMinusPlaneY && fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f; - dirAxis *= mulAxis; - dirPlaneX *= mulAxisX; - dirPlaneY *= mulAxisY; - - // for axis - float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis * gContext.mScreenFactor, localCoordinates); - - float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, dirPlaneY * gContext.mScreenFactor); - belowPlaneLimit = (paraSurf > 0.0025f); - belowAxisLimit = (axisLengthInClipSpace > 0.02f); - - // and store values - gContext.mAxisFactor[axisIndex] = mulAxis; - gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX; - gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY; - gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit; - gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit; - } -} - -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, const 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), -1.f, 1.f); - float angle = acosf(acosAngle); - angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f; - return angle; -} - -static void DrawRotationGizmo(OPERATION op, int type) { - if (!Intersects(op, ROTATE)) - { - return; - } - ImDrawList* drawList = gContext.mDrawList; - - // colors - ImU32 colors[7]; - ComputeColors(colors, type, ROTATE); - - vec_t cameraToModelNormalized; - if (gContext.mIsOrthographic) - { - matrix_t viewInverse; - viewInverse.Inverse(*(matrix_t*)&gContext.mViewMat); - cameraToModelNormalized = viewInverse.v.dir; - } else - { - cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye); - } - - cameraToModelNormalized.TransformVector(gContext.mModelInverse); - - gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight; - - bool hasRSC = Intersects(op, ROTATE_SCREEN); - for (int axis = 0; axis < 3; axis++) - { - if (!Intersects(op, static_cast<OPERATION>(ROTATE_Z >> axis))) - { - continue; - } - const bool usingAxis = (gContext.mbUsing && type == MT_ROTATE_Z - axis); - const int circleMul = (hasRSC && !usingAxis) ? 1 : 2; - - ImVec2* circlePos = (ImVec2*)alloca(sizeof(ImVec2) * (circleMul * halfCircleSegmentCount + 1)); - - float angleStart = atan2f(cameraToModelNormalized[(4 - axis) % 3], cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f; - - for (int i = 0; i < circleMul * halfCircleSegmentCount + 1; i++) - { - float ng = angleStart + (float)circleMul * ZPI * ((float)i / (float)halfCircleSegmentCount); - 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 * rotationDisplayFactor; - circlePos[i] = worldToPos(pos, gContext.mMVP); - } - if (!gContext.mbUsing || usingAxis) - { - drawList->AddPolyline(circlePos, circleMul * halfCircleSegmentCount + 1, colors[3 - axis], false, 2); - } - - float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0]))); - if (radiusAxis > gContext.mRadiusSquareCenter) - { - gContext.mRadiusSquareCenter = radiusAxis; - } - } - if (hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN)) - { - drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, 3.f); - } - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(type)) - { - ImVec2 circlePos[halfCircleSegmentCount + 1]; - - 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)); - matrix_t rotateVectorMatrix; - rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng); - vec_t pos; - pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix); - pos *= gContext.mScreenFactor * rotationDisplayFactor; - circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection); - } - drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, IM_COL32(0xFF, 0x80, 0x10, 0x80)); - drawList->AddPolyline(circlePos, halfCircleSegmentCount, IM_COL32(0xFF, 0x80, 0x10, 0xFF), true, 2); - - ImVec2 destinationPosOnScreen = circlePos[1]; - char tmps[512]; - ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - MT_ROTATE_X], (gContext.mRotationAngle / ZPI) * 180.f, gContext.mRotationAngle); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), IM_COL32_BLACK, tmps); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), IM_COL32_WHITE, tmps); - } -} - -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, IM_COL32(0, 0, 0, 0x80), 6.f); - } -} - -static void DrawScaleGizmo(OPERATION op, int type) { - ImDrawList* drawList = gContext.mDrawList; - - if (!Intersects(op, SCALE)) - { - return; - } - - // colors - ImU32 colors[7]; - ComputeColors(colors, type, SCALE); - - // draw - vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f }; - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - scaleDisplay = gContext.mScale; - } - - for (int i = 0; i < 3; i++) - { - if (!Intersects(op, static_cast<OPERATION>(SCALE_X << i))) - { - continue; - } - const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i); - if (!gContext.mbUsing || usingAxis) - { - vec_t dirPlaneX, dirPlaneY, dirAxis; - bool belowAxisLimit, belowPlaneLimit; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true); - - // draw axis - if (belowAxisLimit) - { - bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)); - float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f; - ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP); - ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP); - ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVP); - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, IM_COL32(0x40, 0x40, 0x40, 0xFF), 3.f); - drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, IM_COL32(0x40, 0x40, 0x40, 0xFF)); - } - - if (!hasTranslateOnAxis || gContext.mbUsing) - { - drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); - } - drawList->AddCircleFilled(worldDirSSpace, 6.f, colors[i + 1]); - - if (gContext.mAxisFactor[i] < 0.f) - { - DrawHatchedAxis(dirAxis * scaleDisplay[i]); - } - } - } - } - - // draw screen cirle - drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type)) - { - // 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.v.position - gContext.mMatrixOrigin; - int componentInfoIndex = (type - MT_SCALE_X) * 3; - ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), IM_COL32_BLACK, tmps); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), IM_COL32_WHITE, tmps); - } -} - -static void DrawScaleUniveralGizmo(OPERATION op, int type) { - ImDrawList* drawList = gContext.mDrawList; - - if (!Intersects(op, SCALEU)) - { - return; - } - - // colors - ImU32 colors[7]; - ComputeColors(colors, type, SCALEU); - - // draw - vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f }; - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - scaleDisplay = gContext.mScale; - } - - for (int i = 0; i < 3; i++) - { - if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i))) - { - continue; - } - const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i); - if (!gContext.mbUsing || usingAxis) - { - vec_t dirPlaneX, dirPlaneY, dirAxis; - bool belowAxisLimit, belowPlaneLimit; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true); - - // draw axis - if (belowAxisLimit) - { - bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)); - float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f; - // ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal); - // ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP); - ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVPLocal); - -#if 0 - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, IM_COL32(0x40, 0x40, 0x40, 0xFF), 3.f); - drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, IM_COL32(0x40, 0x40, 0x40, 0xFF)); - } - /* - if (!hasTranslateOnAxis || gContext.mbUsing) - { - drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); - } - */ -#endif - drawList->AddCircleFilled(worldDirSSpace, 12.f, colors[i + 1]); - } - } - } - - // draw screen cirle - drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, 3.f); - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type)) - { - // 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.v.position - gContext.mMatrixOrigin; - int componentInfoIndex = (type - MT_SCALE_X) * 3; - ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), IM_COL32_BLACK, tmps); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), IM_COL32_WHITE, tmps); - } -} - -static void DrawTranslationGizmo(OPERATION op, int type) { - ImDrawList* drawList = gContext.mDrawList; - if (!drawList) - { - return; - } - - if (!Intersects(op, TRANSLATE)) - { - return; - } - - // colors - ImU32 colors[7]; - ComputeColors(colors, type, TRANSLATE); - - const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); - - // draw - bool belowAxisLimit = false; - bool belowPlaneLimit = false; - for (int i = 0; i < 3; ++i) - { - vec_t dirPlaneX, dirPlaneY, dirAxis; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); - - if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_X + i)) - { - // draw axis - if (belowAxisLimit && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i))) - { - ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP); - ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP); - - drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); - - // Arrow head begin - ImVec2 dir(origin - worldDirSSpace); - - float d = sqrtf(ImLengthSqr(dir)); - dir /= d; // Normalize - dir *= 6.0f; - - ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector - ImVec2 a(worldDirSSpace + dir); - drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]); - // Arrow head end - - if (gContext.mAxisFactor[i] < 0.f) - { - DrawHatchedAxis(dirAxis); - } - } - } - // draw plane - if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_YZ + i)) - { - if (belowPlaneLimit && Contains(op, TRANSLATE_PLANS[i])) - { - ImVec2 screenQuadPts[4]; - for (int j = 0; j < 4; ++j) - { - vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor; - screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP); - } - drawList->AddPolyline(screenQuadPts, 4, directionColor[i], true, 1.0f); - drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]); - } - } - } - - drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); - - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(type)) - { - 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, 0.f, 0.f }; - 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.v.position - gContext.mMatrixOrigin; - int componentInfoIndex = (type - MT_MOVE_X) * 3; - ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MT_MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), IM_COL32_BLACK, tmps); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), IM_COL32_WHITE, tmps); - } -} - -static bool CanActivate() { - if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive()) - { - return true; - } - return false; -} - -static bool HandleAndDrawLocalBounds(float* bounds, matrix_t* matrix, const float* snapValues, OPERATION operation) { - ImGuiIO& io = ImGui::GetIO(); - ImDrawList* drawList = gContext.mDrawList; - - // compute best projection axis - vec_t axesWorldDirections[3]; - vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f }; - int axes[3]; - unsigned int numAxes = 1; - axes[0] = gContext.mBoundsBestAxis; - int bestAxis = axes[0]; - if (!gContext.mbUsingBounds) - { - numAxes = 0; - float bestDot = 0.f; - for (int i = 0; i < 3; i++) - { - vec_t dirPlaneNormalWorld; - dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource); - dirPlaneNormalWorld.Normalize(); - - float dt = fabsf(Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld)); - if (dt >= bestDot) - { - bestDot = dt; - bestAxis = i; - bestAxisWorldDirection = dirPlaneNormalWorld; - } - - if (dt >= 0.1f) - { - axes[numAxes] = i; - axesWorldDirections[numAxes] = dirPlaneNormalWorld; - ++numAxes; - } - } - } - - if (numAxes == 0) - { - axes[0] = bestAxis; - axesWorldDirections[0] = bestAxisWorldDirection; - numAxes = 1; - } - - else if (bestAxis != axes[0]) - { - unsigned int bestIndex = 0; - for (unsigned int i = 0; i < numAxes; i++) - { - if (axes[i] == bestAxis) - { - bestIndex = i; - break; - } - } - int tempAxis = axes[0]; - axes[0] = axes[bestIndex]; - axes[bestIndex] = tempAxis; - vec_t tempDirection = axesWorldDirections[0]; - axesWorldDirections[0] = axesWorldDirections[bestIndex]; - axesWorldDirections[bestIndex] = tempDirection; - } - - matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection; - for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex) - { - bestAxis = axes[axisIndex]; - bestAxisWorldDirection = axesWorldDirections[axisIndex]; - - // Corners of the plane (rectangle) containing bestAxis - vec_t corners[4]; - - int secondAxis = (bestAxis + 1) % 3; - int thirdAxis = (bestAxis + 2) % 3; - // ImU32 col[] = { IM_COL32(255, 0, 0, 255), IM_COL32(0, 255, 0, 255), IM_COL32(0, 0, 255, 255) }; - for (int i = 0; i < 4; i++) { - corners[i].w = 0.0f; - corners[i][bestAxis] = 0.0f; - corners[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)]; - corners[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))]; - - // ImVec2 pos = worldToPos(corners[i], boundsMVP); - // drawList->AddCircleFilled(pos, 10.0f, col[axisIndex]); - } - - // draw bounds - unsigned int anchorAlpha = gContext.mbEnable ? IM_COL32_BLACK : IM_COL32(0, 0, 0, 0x80); - - for (int i = 0; i < 4; i++) - { - ImVec2 worldBound1 = worldToPos(corners[i], boundsMVP); - ImVec2 worldBound2 = worldToPos(corners[(i + 1) % 4], boundsMVP); - if (!IsInContextRect(worldBound1) || !IsInContextRect(worldBound2)) - { - continue; - } - float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2)); - int stepCount = (int)(boundDistance / 10.f); - stepCount = min(stepCount, 1000); - float stepLength = 1.f / (float)stepCount; - for (int j = 0; j < stepCount; j++) - { - float t1 = (float)j * stepLength; - float t2 = (float)j * stepLength + stepLength * 0.5f; - ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1)); - ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2)); - // drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0, 0, 0, 0) + anchorAlpha, 3.f); - drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha, 2.f); - } - vec_t midPoint = (corners[i] + corners[(i + 1) % 4]) * 0.5f; - ImVec2 midBound = worldToPos(midPoint, boundsMVP); - static const float AnchorBigRadius = 8.f; - static const float AnchorSmallRadius = 6.f; - bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius); - bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius); - - int type = MT_NONE; - vec_t gizmoHitProportion; - - if (Intersects(operation, TRANSLATE)) - { - type = GetMoveType(operation, &gizmoHitProportion); - } - if (Intersects(operation, ROTATE) && type == MT_NONE) - { - type = GetRotateType(operation); - } - if (Intersects(operation, SCALE) && type == MT_NONE) - { - type = GetScaleType(operation); - } - - if (type != MT_NONE) - { - overBigAnchor = false; - overSmallAnchor = false; - } - - unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha); - unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha); - - drawList->AddCircleFilled(worldBound1, AnchorBigRadius, IM_COL32_BLACK); - drawList->AddCircleFilled(worldBound1, AnchorBigRadius - 1.2f, bigAnchorColor); - - drawList->AddCircleFilled(midBound, AnchorSmallRadius, IM_COL32_BLACK); - drawList->AddCircleFilled(midBound, AnchorSmallRadius - 1.2f, smallAnchorColor); - int oppositeIndex = (i + 2) % 4; - // big anchor on corners - if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate()) - { - gContext.mBoundsPivot.TransformPoint(corners[(i + 2) % 4], gContext.mModelSource); - gContext.mBoundsAnchor.TransformPoint(corners[i], gContext.mModelSource); - gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection); - gContext.mBoundsBestAxis = bestAxis; - gContext.mBoundsAxis[0] = secondAxis; - gContext.mBoundsAxis[1] = thirdAxis; - - gContext.mBoundsLocalPivot.Set(0.f); - gContext.mBoundsLocalPivot[secondAxis] = corners[oppositeIndex][secondAxis]; - gContext.mBoundsLocalPivot[thirdAxis] = corners[oppositeIndex][thirdAxis]; - gContext.mBoundsPivotCornerIndex = oppositeIndex; - - gContext.mbUsingBounds = true; - gContext.mEditingID = gContext.mActualID; - gContext.mBoundsMatrix = gContext.mModelSource; - - gContext.mbIsUsingBigAnchor = true; - } - // small anchor on middle of segment - if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate()) - { - vec_t midPointOpposite = (corners[(i + 2) % 4] + corners[(i + 3) % 4]) * 0.5f; - gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource); - gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource); - gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection); - gContext.mBoundsBestAxis = bestAxis; - int indices[] = { secondAxis, thirdAxis }; - gContext.mBoundsAxis[0] = indices[i % 2]; - gContext.mBoundsAxis[1] = -1; - - int localPivotComponentIdx = gContext.mBoundsAxis[0]; - gContext.mBoundsLocalPivot.Set(0.f); - gContext.mBoundsLocalPivot[localPivotComponentIdx] = corners[oppositeIndex][localPivotComponentIdx]; // bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f); - gContext.mBoundsPivotCornerIndex = oppositeIndex; - - gContext.mbUsingBounds = true; - gContext.mEditingID = gContext.mActualID; - gContext.mBoundsMatrix = gContext.mModelSource; - - gContext.mbIsUsingBigAnchor = false; - } - } - - ImGui::Text("bounds pivot: %.2f, %.2f, %.2f", gContext.mBoundsPivot.x, gContext.mBoundsPivot.y, gContext.mBoundsPivot.z); - ImGui::Text("bounds anchor: %.2f, %.2f, %.2f", gContext.mBoundsAnchor.x, gContext.mBoundsAnchor.y, gContext.mBoundsAnchor.z); - ImGui::Text("bounds plan: %.2f, %.2f, %.2f", gContext.mBoundsPlan.x, gContext.mBoundsPlan.y, gContext.mBoundsPlan.z); - ImGui::Text("bounds local pivot: %.2f, %.2f, %.2f", gContext.mBoundsLocalPivot.x, gContext.mBoundsLocalPivot.y, gContext.mBoundsLocalPivot.z); - if (gContext.mbUsingBounds && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) - { - // compute projected mouse position on plan - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan); - vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len; - - // compute a reference and delta vectors base on mouse move - vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs(); - vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs(); - - ImGui::Text("Delta: %.2f, %.2f, %.2f", deltaVector.x, deltaVector.y, deltaVector.z); - ImGui::Text("Ref: %.2f, %.2f, %.2f", referenceVector.x, referenceVector.y, referenceVector.z); - ImGui::Separator(); - - // for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length - for (int axisIndex1 : gContext.mBoundsAxis) { - if (axisIndex1 == -1) { - continue; - } - - vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs(); - // ImGui::Text("Axisdir: %.2f, %.2f, %.2f", axisDir.x, axisDir.y, axisDir.z); - - float refAxisComp = axisDir.Dot(referenceVector); - float deltaAxisComp = axisDir.Dot(deltaVector); - // ImGui::Text("refAxisComp: %.2f", refAxisComp); - - float length = deltaAxisComp; - if (snapValues) { - ComputeSnap(&length, snapValues[axisIndex1]); - } - - // ImGui::Text("axis idx %d", axisIndex1); - // TODO(hnosm): logic that mapps mouse pos to bound seems to account for translation fixup already? - bounds[axisIndex1] = -length / 2; - bounds[axisIndex1 + 3] = +length / 2; - } - - // Update corner positions, translation fixup code needs them - for (int i = 0; i < 4; i++) { - corners[i].w = 0.0f; - corners[i][bestAxis] = 0.0f; - corners[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)]; - corners[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))]; - } - - // Translation (object center) fixup - make sure pivot stays in place - // TODO(hnosm): is there a better way to write this that doesn't involve transferring a bunch of extra state from begin drag frame? - vec_t newLocalPivot; - if (gContext.mbIsUsingBigAnchor) { - newLocalPivot.Set(0.0f); - newLocalPivot[secondAxis] = corners[gContext.mBoundsPivotCornerIndex][secondAxis]; - newLocalPivot[thirdAxis] = corners[gContext.mBoundsPivotCornerIndex][thirdAxis]; - } else { - newLocalPivot.Set(0.0f); - int localPivotComponentIdx = gContext.mBoundsAxis[0]; - newLocalPivot[localPivotComponentIdx] = corners[gContext.mBoundsPivotCornerIndex][localPivotComponentIdx]; - } - - vec_t delta = gContext.mBoundsLocalPivot - newLocalPivot; - vec_t oldTranslation = gContext.mBoundsMatrix.component[3]; - matrix->component[3] = oldTranslation + delta; - - // info text - char tmps[512]; - ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); - ImFormatString(tmps, sizeof(tmps), - // Size of the bounds in each axis direction - "X: %.2f Y: %.2f Z:%.2f", - (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length(), - (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length(), - (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length()); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), IM_COL32_BLACK, tmps); - drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), IM_COL32_WHITE, tmps); - } - - if (!io.MouseDown[0]) { - gContext.mbUsingBounds = false; - gContext.mEditingID = -1; - } - if (gContext.mbUsingBounds) - { - break; - } - } - - return gContext.mbUsingBounds; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// - -static int GetScaleType(OPERATION op) { - if (gContext.mbUsing) - { - return MT_NONE; - } - ImGuiIO& io = ImGui::GetIO(); - int type = MT_NONE; - - // 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 && - Contains(op, SCALE)) - { - type = MT_SCALE_XYZ; - } - - // compute - for (int i = 0; i < 3 && type == MT_NONE; i++) - { - if (!Intersects(op, static_cast<OPERATION>(SCALE_X << i))) - { - continue; - } - vec_t dirPlaneX, dirPlaneY, dirAxis; - bool belowAxisLimit, belowPlaneLimit; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true); - dirAxis.TransformVector(gContext.mModelLocal); - dirPlaneX.TransformVector(gContext.mModelLocal); - dirPlaneY.TransformVector(gContext.mModelLocal); - - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModelLocal.v.position, dirAxis)); - vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len; - - const float startOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.0f : 0.1f; - const float endOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.4f : 1.0f; - const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection); - const ImVec2 axisStartOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * startOffset, gContext.mViewProjection); - const ImVec2 axisEndOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * endOffset, gContext.mViewProjection); - - vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen)); - - if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size - { - type = MT_SCALE_X + i; - } - } - - // universal - - vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f }; - float dist = deltaScreen.Length(); - if (Contains(op, SCALEU) && dist >= 17.0f && dist < 23.0f) - { - type = MT_SCALE_XYZ; - } - - for (int i = 0; i < 3 && type == MT_NONE; i++) - { - if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i))) - { - continue; - } - - vec_t dirPlaneX, dirPlaneY, dirAxis; - bool belowAxisLimit, belowPlaneLimit; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true); - - // draw axis - if (belowAxisLimit) - { - bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)); - float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f; - // ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal); - // ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP); - ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale) * gContext.mScreenFactor, gContext.mMVPLocal); - - float distance = sqrtf(ImLengthSqr(worldDirSSpace - io.MousePos)); - if (distance < 12.f) - { - type = MT_SCALE_X + i; - } - } - } - return type; -} - -static int GetRotateType(OPERATION op) { - if (gContext.mbUsing) - { - return MT_NONE; - } - ImGuiIO& io = ImGui::GetIO(); - int type = MT_NONE; - - vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f }; - float dist = deltaScreen.Length(); - if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && dist < (gContext.mRadiusSquareCenter + 4.0f)) - { - type = MT_ROTATE_SCREEN; - } - - const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir }; - - vec_t modelViewPos; - modelViewPos.TransformPoint(gContext.mModel.v.position, gContext.mViewMat); - - for (int i = 0; i < 3 && type == MT_NONE; i++) - { - if (!Intersects(op, static_cast<OPERATION>(ROTATE_X << i))) - { - continue; - } - // pickup plan - vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]); - - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan); - const vec_t intersectWorldPos = gContext.mRayOrigin + gContext.mRayVector * len; - vec_t intersectViewPos; - intersectViewPos.TransformPoint(intersectWorldPos, gContext.mViewMat); - - if (ImAbs(modelViewPos.z) - ImAbs(intersectViewPos.z) < -FLT_EPSILON) - { - continue; - } - - const vec_t localPos = intersectWorldPos - gContext.mModel.v.position; - vec_t idealPosOnCircle = Normalized(localPos); - idealPosOnCircle.TransformVector(gContext.mModelInverse); - const ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * rotationDisplayFactor * gContext.mScreenFactor, gContext.mMVP); - - // gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE); - const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos; - - const float distance = makeVect(distanceOnScreen).Length(); - if (distance < 8.f) // pixel size - { - type = MT_ROTATE_X + i; - } - } - - return type; -} - -static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion) { - if (!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver) - { - return MT_NONE; - } - ImGuiIO& io = ImGui::GetIO(); - int type = MT_NONE; - - // 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 && - Contains(op, TRANSLATE)) - { - type = MT_MOVE_SCREEN; - } - - const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY)); - - // compute - for (int i = 0; i < 3 && type == MT_NONE; i++) - { - vec_t dirPlaneX, dirPlaneY, dirAxis; - bool belowAxisLimit, belowPlaneLimit; - ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); - dirAxis.TransformVector(gContext.mModel); - dirPlaneX.TransformVector(gContext.mModel); - dirPlaneY.TransformVector(gContext.mModel); - - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis)); - vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len; - - const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY); - const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY); - - vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), makeVect(axisEndOnScreen)); - if ((closestPointOnAxis - screenCoord).Length() < 12.f && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i))) // pixel size - { - type = MT_MOVE_X + i; - } - - const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor)); - const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor)); - if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3] && Contains(op, TRANSLATE_PLANS[i])) - { - type = MT_MOVE_YZ + i; - } - - if (gizmoHitProportion) - { - *gizmoHitProportion = makeVect(dx, dy, 0.f); - } - } - return type; -} - -static bool HandleTranslation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap) { - if (!Intersects(op, TRANSLATE) || type != MT_NONE) - { - return false; - } - const ImGuiIO& io = ImGui::GetIO(); - const bool applyRotationLocaly = gContext.mMode == LOCAL || type == MT_MOVE_SCREEN; - bool modified = false; - - // move - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation)) - { - ImGui::CaptureMouseFromApp(); - const float signedLength = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); - const float len = fabsf(signedLength); // near plan - const vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len; - - // compute delta - const vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor; - vec_t delta = newOrigin - gContext.mModel.v.position; - - // 1 axis constraint - if (gContext.mCurrentOperation >= MT_MOVE_X && gContext.mCurrentOperation <= MT_MOVE_Z) - { - const int axisIndex = gContext.mCurrentOperation - MT_MOVE_X; - const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex]; - const float lengthOnAxis = Dot(axisValue, delta); - delta = axisValue * lengthOnAxis; - } - - // snap - if (snap) - { - vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin; - if (applyRotationLocaly) - { - matrix_t modelSourceNormalized = gContext.mModelSource; - modelSourceNormalized.OrthoNormalize(); - matrix_t modelSourceNormalizedInverse; - modelSourceNormalizedInverse.Inverse(modelSourceNormalized); - cumulativeDelta.TransformVector(modelSourceNormalizedInverse); - ComputeSnap(cumulativeDelta, snap); - cumulativeDelta.TransformVector(modelSourceNormalized); - } else - { - ComputeSnap(cumulativeDelta, snap); - } - delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position; - } - - if (delta != gContext.mTranslationLastDelta) - { - modified = true; - } - gContext.mTranslationLastDelta = delta; - - // compute matrix & delta - matrix_t deltaMatrixTranslation; - deltaMatrixTranslation.Translation(delta); - if (deltaMatrix) - { - memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16); - } - - const matrix_t res = gContext.mModelSource * deltaMatrixTranslation; - *(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(op, &gizmoHitProportion); - if (type != MT_NONE) - { - ImGui::CaptureMouseFromApp(); - } - if (CanActivate() && type != MT_NONE) - { - gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; - gContext.mCurrentOperation = type; - vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir }; - - vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye); - for (unsigned int i = 0; i < 3; i++) - { - vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized); - movePlanNormal[i].Cross(orthoVector); - movePlanNormal[i].Normalize(); - } - // pickup plan - gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_MOVE_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.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor); - } - } - return modified; -} - -static bool HandleScale(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap) { - if ((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver) - { - return false; - } - ImGuiIO& io = ImGui::GetIO(); - bool modified = false; - - if (!gContext.mbUsing) - { - // find new possible way to scale - type = GetScaleType(op); - if (type != MT_NONE) - { - ImGui::CaptureMouseFromApp(); - } - if (CanActivate() && type != MT_NONE) - { - gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; - 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 - MT_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.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length()); - gContext.mSaveMousePosx = io.MousePos.x; - } - } - // scale - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(gContext.mCurrentOperation)) - { - ImGui::CaptureMouseFromApp(); - 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.mModelLocal.v.position; - - // 1 axis constraint - if (gContext.mCurrentOperation >= MT_SCALE_X && gContext.mCurrentOperation <= MT_SCALE_Z) - { - int axisIndex = gContext.mCurrentOperation - MT_SCALE_X; - const vec_t& axisValue = *(vec_t*)&gContext.mModelLocal.m[axisIndex]; - float lengthOnAxis = Dot(axisValue, delta); - delta = axisValue * lengthOnAxis; - - vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position; - float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector); - - gContext.mScale[axisIndex] = max(ratio, 0.001f); - } else - { - 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); - - if (gContext.mScaleLast != gContext.mScale) - { - modified = true; - } - gContext.mScaleLast = gContext.mScale; - - // compute matrix & delta - matrix_t deltaMatrixScale; - deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin); - - matrix_t res = deltaMatrixScale * gContext.mModelLocal; - *(matrix_t*)matrix = res; - - if (deltaMatrix) - { - vec_t deltaScale = gContext.mScale * gContext.mScaleValueOrigin; - - vec_t originalScaleDivider; - originalScaleDivider.x = 1 / gContext.mModelScaleOrigin.x; - originalScaleDivider.y = 1 / gContext.mModelScaleOrigin.y; - originalScaleDivider.z = 1 / gContext.mModelScaleOrigin.z; - - deltaScale = deltaScale * originalScaleDivider; - - deltaMatrixScale.Scale(deltaScale); - memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16); - } - - if (!io.MouseDown[0]) - { - gContext.mbUsing = false; - gContext.mScale.Set(1.f, 1.f, 1.f); - } - - type = gContext.mCurrentOperation; - } - return modified; -} - -static bool HandleRotation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap) { - if (!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver) - { - return false; - } - ImGuiIO& io = ImGui::GetIO(); - bool applyRotationLocaly = gContext.mMode == LOCAL; - bool modified = false; - - if (!gContext.mbUsing) - { - type = GetRotateType(op); - - if (type != MT_NONE) - { - ImGui::CaptureMouseFromApp(); - } - - if (type == MT_ROTATE_SCREEN) - { - applyRotationLocaly = true; - } - - if (CanActivate() && type != MT_NONE) - { - gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; - gContext.mCurrentOperation = type; - const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir }; - // pickup plan - if (applyRotationLocaly) - { - gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - MT_ROTATE_X]); - } else - { - gContext.mTranslationPlan = BuildPlan(gContext.mModelSource.v.position, directionUnary[type - MT_ROTATE_X]); - } - - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); - vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position; - gContext.mRotationVectorSource = Normalized(localPos); - gContext.mRotationAngleOrigin = ComputeAngleOnPlan(); - } - } - - // rotation - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation)) - { - ImGui::CaptureMouseFromApp(); - 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); - rotationAxisLocalSpace.Normalize(); - - matrix_t deltaRotation; - deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin); - if (gContext.mRotationAngle != gContext.mRotationAngleOrigin) - { - modified = true; - } - gContext.mRotationAngleOrigin = gContext.mRotationAngle; - - matrix_t scaleOrigin; - scaleOrigin.Scale(gContext.mModelScaleOrigin); - - if (applyRotationLocaly) - { - *(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModelLocal; - } else - { - matrix_t res = gContext.mModelSource; - res.v.position.Set(0.f); - - *(matrix_t*)matrix = res * deltaRotation; - ((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position; - } - - if (deltaMatrix) - { - *(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel; - } - - if (!io.MouseDown[0]) - { - gContext.mbUsing = false; - gContext.mEditingID = -1; - } - type = gContext.mCurrentOperation; - } - return modified; -} - -void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale) { - matrix_t mat = *(matrix_t*)matrix; - - scale[0] = mat.v.right.Length(); - scale[1] = mat.v.up.Length(); - scale[2] = mat.v.dir.Length(); - - mat.OrthoNormalize(); - - 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]); - - 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) { - 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]; - - float validScale[3]; - for (int i = 0; i < 3; i++) - { - if (fabsf(scale[i]) < FLT_EPSILON) - { - validScale[i] = 0.001f; - } else - { - validScale[i] = scale[i]; - } - } - mat.v.right *= validScale[0]; - mat.v.up *= validScale[1]; - mat.v.dir *= validScale[2]; - mat.v.position.Set(translation[0], translation[1], translation[2], 1.f); -} - -void SetID(int id) { - gContext.mActualID = id; -} - -void AllowAxisFlip(bool value) { - gContext.mAllowAxisFlip = value; -} - -bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix, const float* snap, float* localBounds, const float* boundsSnap) { - // Scale is always local or matrix will be skewed when applying world scale or oriented matrix - ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode); - - // set delta to identity - if (deltaMatrix) - { - ((matrix_t*)deltaMatrix)->SetToIdentity(); - } - - // behind camera - vec_t camSpacePosition; - camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP); - if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f) - { - return false; - } - - // -- - int type = MT_NONE; - bool manipulated = false; - if (gContext.mbEnable) - { - if (!gContext.mbUsingBounds) - { - manipulated |= HandleTranslation(matrix, deltaMatrix, operation, type, snap) || - HandleScale(matrix, deltaMatrix, operation, type, snap) || - HandleRotation(matrix, deltaMatrix, operation, type, snap); - } - } - if (localBounds && !gContext.mbUsing) - { - manipulated |= HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap, operation); - } - - gContext.mOperation = operation; - if (!gContext.mbUsingBounds) - { - DrawRotationGizmo(operation, type); - DrawTranslationGizmo(operation, type); - DrawScaleGizmo(operation, type); - DrawScaleUniveralGizmo(operation, type); - } - return manipulated; -} - -void SetGizmoSizeClipSpace(float value) { - gContext.mGizmoSizeClipSpace = value; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -void ComputeFrustumPlanes(vec_t* frustum, const float* clip) { - frustum[0].x = clip[3] - clip[0]; - frustum[0].y = clip[7] - clip[4]; - frustum[0].z = clip[11] - clip[8]; - frustum[0].w = clip[15] - clip[12]; - - frustum[1].x = clip[3] + clip[0]; - frustum[1].y = clip[7] + clip[4]; - frustum[1].z = clip[11] + clip[8]; - frustum[1].w = clip[15] + clip[12]; - - frustum[2].x = clip[3] + clip[1]; - frustum[2].y = clip[7] + clip[5]; - frustum[2].z = clip[11] + clip[9]; - frustum[2].w = clip[15] + clip[13]; - - frustum[3].x = clip[3] - clip[1]; - frustum[3].y = clip[7] - clip[5]; - frustum[3].z = clip[11] - clip[9]; - frustum[3].w = clip[15] - clip[13]; - - frustum[4].x = clip[3] - clip[2]; - frustum[4].y = clip[7] - clip[6]; - frustum[4].z = clip[11] - clip[10]; - frustum[4].w = clip[15] - clip[14]; - - frustum[5].x = clip[3] + clip[2]; - frustum[5].y = clip[7] + clip[6]; - frustum[5].z = clip[11] + clip[10]; - frustum[5].w = clip[15] + clip[14]; - - for (int i = 0; i < 6; i++) - { - frustum[i].Normalize(); - } -} - -void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount) { - matrix_t viewInverse; - viewInverse.Inverse(*(matrix_t*)view); - - struct CubeFace { - float z; - ImVec2 faceCoordsScreen[4]; - ImU32 color; - }; - CubeFace* faces = (CubeFace*)_malloca(sizeof(CubeFace) * matrixCount * 6); - - if (!faces) - { - return; - } - - vec_t frustum[6]; - matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection; - ComputeFrustumPlanes(frustum, viewProjection.m16); - - int cubeFaceCount = 0; - for (int cube = 0; cube < matrixCount; cube++) - { - const float* matrix = &matrices[cube * 16]; - - 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], - }; - - // clipping - /* - bool skipFace = false; - for (unsigned int iCoord = 0; iCoord < 4; iCoord++) - { - vec_t camSpacePosition; - camSpacePosition.TransformPoint(faceCoords[iCoord] * 0.5f * invert, res); - if (camSpacePosition.z < 0.001f) - { - skipFace = true; - break; - } - } - if (skipFace) - { - continue; - } - */ - vec_t centerPosition, centerPositionVP; - centerPosition.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, *(matrix_t*)matrix); - centerPositionVP.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, res); - - bool inFrustum = true; - for (int iFrustum = 0; iFrustum < 6; iFrustum++) - { - float dist = DistanceToPlane(centerPosition, frustum[iFrustum]); - if (dist < 0.f) - { - inFrustum = false; - break; - } - } - - if (!inFrustum) - { - continue; - } - CubeFace& cubeFace = faces[cubeFaceCount]; - - // 3D->2D - // ImVec2 faceCoordsScreen[4]; - for (unsigned int iCoord = 0; iCoord < 4; iCoord++) - { - cubeFace.faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res); - } - cubeFace.color = directionColor[normalIndex] | IM_COL32(0x80, 0x80, 0x80, 0); - - cubeFace.z = centerPositionVP.z / centerPositionVP.w; - cubeFaceCount++; - } - } - qsort(faces, cubeFaceCount, sizeof(CubeFace), [](void const* _a, void const* _b) { - CubeFace* a = (CubeFace*)_a; - CubeFace* b = (CubeFace*)_b; - if (a->z < b->z) - { - return 1; - } - return -1; - }); - // draw face with lighter color - for (int iFace = 0; iFace < cubeFaceCount; iFace++) - { - const CubeFace& cubeFace = faces[iFace]; - gContext.mDrawList->AddConvexPolyFilled(cubeFace.faceCoordsScreen, 4, cubeFace.color); - } - - _freea(faces); -} - -void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize) { - matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection; - vec_t frustum[6]; - ComputeFrustumPlanes(frustum, viewProjection.m16); - matrix_t res = *(matrix_t*)matrix * viewProjection; - - for (float f = -gridSize; f <= gridSize; f += 1.f) - { - for (int dir = 0; dir < 2; dir++) - { - vec_t ptA = makeVect(dir ? -gridSize : f, 0.f, dir ? f : -gridSize); - vec_t ptB = makeVect(dir ? gridSize : f, 0.f, dir ? f : gridSize); - bool visible = true; - for (int i = 0; i < 6; i++) - { - float dA = DistanceToPlane(ptA, frustum[i]); - float dB = DistanceToPlane(ptB, frustum[i]); - if (dA < 0.f && dB < 0.f) - { - visible = false; - break; - } - if (dA > 0.f && dB > 0.f) - { - continue; - } - if (dA < 0.f) - { - float len = fabsf(dA - dB); - float t = fabsf(dA) / len; - ptA.Lerp(ptB, t); - } - if (dB < 0.f) - { - float len = fabsf(dB - dA); - float t = fabsf(dB) / len; - ptB.Lerp(ptA, t); - } - } - if (visible) - { - ImU32 col = IM_COL32(0x80, 0x80, 0x80, 0xFF); - col = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? IM_COL32(0x90, 0x90, 0x90, 0xFF) : col; - col = (fabsf(f) < FLT_EPSILON) ? IM_COL32(0x40, 0x40, 0x40, 0xFF) : col; - - float thickness = 1.f; - thickness = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? 1.5f : thickness; - thickness = (fabsf(f) < FLT_EPSILON) ? 2.3f : thickness; - - gContext.mDrawList->AddLine(worldToPos(ptA, res), worldToPos(ptB, res), col, thickness); - } - } - } -} - -void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor) { - static bool isDraging = false; - static bool isClicking = false; - static bool isInside = false; - static vec_t interpolationUp; - static vec_t interpolationDir; - static int interpolationFrames = 0; - const vec_t referenceUp = makeVect(0.f, 1.f, 0.f); - - matrix_t svgView, svgProjection; - svgView = gContext.mViewMat; - svgProjection = gContext.mProjectionMat; - - ImGuiIO& io = ImGui::GetIO(); - gContext.mDrawList->AddRectFilled(position, position + size, backgroundColor); - matrix_t viewInverse; - viewInverse.Inverse(*(matrix_t*)view); - - const vec_t camTarget = viewInverse.v.position - viewInverse.v.dir * length; - - // view/projection matrices - const float distance = 3.f; - matrix_t cubeProjection, cubeView; - float fov = acosf(distance / (sqrtf(distance * distance + 3.f))) * RAD2DEG; - Perspective(fov / sqrtf(2.f), size.x / size.y, 0.01f, 1000.f, cubeProjection.m16); - - vec_t dir = makeVect(viewInverse.m[2][0], viewInverse.m[2][1], viewInverse.m[2][2]); - vec_t up = makeVect(viewInverse.m[1][0], viewInverse.m[1][1], viewInverse.m[1][2]); - vec_t eye = dir * distance; - vec_t zero = makeVect(0.f, 0.f); - LookAt(&eye.x, &zero.x, &up.x, cubeView.m16); - - // set context - gContext.mViewMat = cubeView; - gContext.mProjectionMat = cubeProjection; - ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector, position, size); - - const matrix_t res = cubeView * cubeProjection; - - // panels - static const ImVec2 panelPosition[9] = { ImVec2(0.75f, 0.75f), ImVec2(0.25f, 0.75f), ImVec2(0.f, 0.75f), ImVec2(0.75f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.f, 0.25f), ImVec2(0.75f, 0.f), ImVec2(0.25f, 0.f), ImVec2(0.f, 0.f) }; - - static const ImVec2 panelSize[9] = { ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.25f, 0.5f), ImVec2(0.5f, 0.5f), ImVec2(0.25f, 0.5f), ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f) }; - - // tag faces - bool boxes[27]{}; - for (int iPass = 0; iPass < 2; iPass++) - { - 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 indexVectorX = directionUnary[perpXIndex] * invert; - const vec_t indexVectorY = directionUnary[perpYIndex] * invert; - const vec_t boxOrigin = directionUnary[normalIndex] * -invert - indexVectorX - indexVectorY; - - // plan local space - const vec_t n = directionUnary[normalIndex] * invert; - vec_t viewSpaceNormal = n; - vec_t viewSpacePoint = n * 0.5f; - viewSpaceNormal.TransformVector(cubeView); - viewSpaceNormal.Normalize(); - viewSpacePoint.TransformPoint(cubeView); - const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal); - - // back face culling - if (viewSpaceFacePlan.w > 0.f) - { - continue; - } - - const vec_t facePlan = BuildPlan(n * 0.5f, n); - - const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, facePlan); - vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len - (n * 0.5f); - - float localx = Dot(directionUnary[perpXIndex], posOnPlan) * invert + 0.5f; - float localy = Dot(directionUnary[perpYIndex], posOnPlan) * invert + 0.5f; - - // panels - const vec_t dx = directionUnary[perpXIndex]; - const vec_t dy = directionUnary[perpYIndex]; - const vec_t origin = directionUnary[normalIndex] - dx - dy; - for (int iPanel = 0; iPanel < 9; iPanel++) - { - vec_t boxCoord = boxOrigin + indexVectorX * float(iPanel % 3) + indexVectorY * float(iPanel / 3) + makeVect(1.f, 1.f, 1.f); - const ImVec2 p = panelPosition[iPanel] * 2.f; - const ImVec2 s = panelSize[iPanel] * 2.f; - ImVec2 faceCoordsScreen[4]; - vec_t panelPos[4] = { dx * p.x + dy * p.y, - dx * p.x + dy * (p.y + s.y), - dx * (p.x + s.x) + dy * (p.y + s.y), - dx * (p.x + s.x) + dy * p.y }; - - for (unsigned int iCoord = 0; iCoord < 4; iCoord++) - { - faceCoordsScreen[iCoord] = worldToPos((panelPos[iCoord] + origin) * 0.5f * invert, res, position, size); - } - - const ImVec2 panelCorners[2] = { panelPosition[iPanel], panelPosition[iPanel] + panelSize[iPanel] }; - bool insidePanel = localx > panelCorners[0].x && localx < panelCorners[1].x && localy > panelCorners[0].y && localy < panelCorners[1].y; - int boxCoordInt = int(boxCoord.x * 9.f + boxCoord.y * 3.f + boxCoord.z); - IM_ASSERT(boxCoordInt < 27); - boxes[boxCoordInt] |= insidePanel && (!isDraging) && gContext.mbMouseOver; - - // draw face with lighter color - if (iPass) - { - gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor[normalIndex] | IM_COL32(0x80, 0x80, 0x80, 0x80)) | (isInside ? IM_COL32(0x08, 0x08, 0x08, 0) : 0)); - if (boxes[boxCoordInt]) - { - gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, IM_COL32(0xF0, 0xA0, 0x60, 0x80)); - - if (!io.MouseDown[0] && !isDraging && isClicking) - { - // apply new view direction - int cx = boxCoordInt / 9; - int cy = (boxCoordInt - cx * 9) / 3; - int cz = boxCoordInt % 3; - interpolationDir = makeVect(1.f - (float)cx, 1.f - (float)cy, 1.f - (float)cz); - interpolationDir.Normalize(); - - if (fabsf(Dot(interpolationDir, referenceUp)) > 1.0f - 0.01f) - { - vec_t right = viewInverse.v.right; - if (fabsf(right.x) > fabsf(right.z)) - { - right.z = 0.f; - } else - { - right.x = 0.f; - } - right.Normalize(); - interpolationUp = Cross(interpolationDir, right); - interpolationUp.Normalize(); - } else - { - interpolationUp = referenceUp; - } - interpolationFrames = 40; - isClicking = false; - } - if (io.MouseClicked[0] && !isDraging) - { - isClicking = true; - } - } - } - } - } - } - if (interpolationFrames) - { - interpolationFrames--; - vec_t newDir = viewInverse.v.dir; - newDir.Lerp(interpolationDir, 0.2f); - newDir.Normalize(); - - vec_t newUp = viewInverse.v.up; - newUp.Lerp(interpolationUp, 0.3f); - newUp.Normalize(); - newUp = interpolationUp; - vec_t newEye = camTarget + newDir * length; - LookAt(&newEye.x, &camTarget.x, &newUp.x, view); - } - isInside = gContext.mbMouseOver && ImRect(position, position + size).Contains(io.MousePos); - - // drag view - if (!isDraging && io.MouseClicked[0] && isInside) - { - isDraging = true; - isClicking = false; - } else if (isDraging && !io.MouseDown[0]) - { - isDraging = false; - } - - if (isDraging) - { - matrix_t rx, ry, roll; - - rx.RotationAxis(referenceUp, -io.MouseDelta.x * 0.01f); - ry.RotationAxis(viewInverse.v.right, -io.MouseDelta.y * 0.01f); - - roll = rx * ry; - - vec_t newDir = viewInverse.v.dir; - newDir.TransformVector(roll); - newDir.Normalize(); - - // clamp - vec_t planDir = Cross(viewInverse.v.right, referenceUp); - planDir.y = 0.f; - planDir.Normalize(); - float dt = Dot(planDir, newDir); - if (dt < 0.0f) - { - newDir += planDir * dt; - newDir.Normalize(); - } - - vec_t newEye = camTarget + newDir * length; - LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view); - } - - // restore view/projection because it was used to compute ray - ComputeContext(svgView.m16, svgProjection.m16, gContext.mModelSource.m16, gContext.mMode); -} -}; // namespace IMGUIZMO_NAMESPACE |