diff --git a/3rdparty/dear-imgui/widgets/gizmo.h b/3rdparty/dear-imgui/widgets/gizmo.h index 8859c61bb..4ccff181f 100644 --- a/3rdparty/dear-imgui/widgets/gizmo.h +++ b/3rdparty/dear-imgui/widgets/gizmo.h @@ -1,5 +1,5 @@ // https://github.com/CedricGuillemet/ImGuizmo -// v 1.84 WIP +// v1.91.3 WIP // // The MIT License(MIT) // @@ -39,9 +39,9 @@ // - display rotation/translation/scale infos in local/world space and not only local // - finish local/world matrix application // - OPERATION as bitmask -// +// // ------------------------------------------------------------------------------------------- -// Example +// Example #if 0 void EditTransform(const Camera& camera, matrix_t& matrix) { @@ -115,6 +115,8 @@ void EditTransform(const Camera& camera, matrix_t& matrix) #define IMGUIZMO_NAMESPACE ImGuizmo #endif +struct ImGuiWindow; + namespace IMGUIZMO_NAMESPACE { // call inside your own window and before Manipulate() in order to draw gizmo to that window. @@ -136,6 +138,14 @@ namespace IMGUIZMO_NAMESPACE // return true if mouse IsOver or if the gizmo is in moving state IMGUI_API bool IsUsing(); + // return true if the view gizmo is in moving state + IMGUI_API bool IsUsingViewManipulate(); + // only check if your mouse is over the view manipulator - no matter whether it's active or not + IMGUI_API bool IsViewManipulateHovered(); + + // return true if any gizmo is in moving state + IMGUI_API bool IsUsingAny(); + // enable/disable the gizmo. Stay in the state until next call to Enable. // gizmo is rendered with gray half transparent color when disabled IMGUI_API void Enable(bool enable); @@ -164,7 +174,7 @@ namespace IMGUIZMO_NAMESPACE IMGUI_API void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize); // call it when you want a gizmo - // Needs view and projection matrices. + // Needs view and projection matrices. // matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional // translation is applied in world space enum OPERATION @@ -210,8 +220,34 @@ namespace IMGUIZMO_NAMESPACE // IMGUI_API void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor); + // use this version if you did not call Manipulate before and you are just using ViewManipulate + IMGUI_API void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor); + + IMGUI_API void SetAlternativeWindow(ImGuiWindow* window); + + [[deprecated("Use PushID/PopID instead.")]] IMGUI_API void SetID(int id); + // ID stack/scopes + // Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui. + // - Those questions are answered and impacted by understanding of the ID stack system: + // - "Q: Why is my widget not reacting when I click on it?" + // - "Q: How can I have widgets with an empty label?" + // - "Q: How can I have multiple widgets with the same label?" + // - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely + // want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). + IMGUI_API void PopID(); // pop from the ID stack. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + // return true if the cursor is over the operation's gizmo IMGUI_API bool IsOver(OPERATION op); IMGUI_API void SetGizmoSizeClipSpace(float value); @@ -220,4 +256,51 @@ namespace IMGUIZMO_NAMESPACE // When true (default), the guizmo axis flip for better visibility // When false, they always stay along the positive world/local axis IMGUI_API void AllowAxisFlip(bool value); + + // Configure the limit where axis are hidden + IMGUI_API void SetAxisLimit(float value); + // Set an axis mask to permanently hide a given axis (true -> hidden, false -> shown) + IMGUI_API void SetAxisMask(bool x, bool y, bool z); + // Configure the limit where planes are hiden + IMGUI_API void SetPlaneLimit(float value); + // from a x,y,z point in space and using Manipulation view/projection matrix, check if mouse is in pixel radius distance of that projected point + IMGUI_API bool IsOver(float* position, float pixelRadius); + + enum COLOR + { + DIRECTION_X, // directionColor[0] + DIRECTION_Y, // directionColor[1] + DIRECTION_Z, // directionColor[2] + PLANE_X, // planeColor[0] + PLANE_Y, // planeColor[1] + PLANE_Z, // planeColor[2] + SELECTION, // selectionColor + INACTIVE, // inactiveColor + TRANSLATION_LINE, // translationLineColor + SCALE_LINE, + ROTATION_USING_BORDER, + ROTATION_USING_FILL, + HATCHED_AXIS_LINES, + TEXT, + TEXT_SHADOW, + COUNT + }; + + struct Style + { + IMGUI_API Style(); + + float TranslationLineThickness; // Thickness of lines for translation gizmo + float TranslationLineArrowSize; // Size of arrow at the end of lines for translation gizmo + float RotationLineThickness; // Thickness of lines for rotation gizmo + float RotationOuterLineThickness; // Thickness of line surrounding the rotation gizmo + float ScaleLineThickness; // Thickness of lines for scale gizmo + float ScaleLineCircleSize; // Size of circle at the end of lines for scale gizmo + float HatchedAxisLineThickness; // Thickness of hatched axis lines + float CenterCircleSize; // Size of circle at the center of the translate/scale gizmo + + ImVec4 Colors[COLOR::COUNT]; + }; + + IMGUI_API Style& GetStyle(); } diff --git a/3rdparty/dear-imgui/widgets/gizmo.inl b/3rdparty/dear-imgui/widgets/gizmo.inl index 1e0c1445a..e339c19f5 100644 --- a/3rdparty/dear-imgui/widgets/gizmo.inl +++ b/3rdparty/dear-imgui/widgets/gizmo.inl @@ -1,5 +1,5 @@ // https://github.com/CedricGuillemet/ImGuizmo -// v 1.84 WIP +// v1.91.3 WIP // // The MIT License(MIT) // @@ -24,11 +24,9 @@ // SOFTWARE. // -//#include "imgui.h" #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif -//#include "imgui_internal.h" #include "gizmo.h" #if defined(_MSC_VER) || defined(__MINGW32__) @@ -61,11 +59,6 @@ namespace IMGUIZMO_NAMESPACE return static_cast(lhs) != rhs; } - static bool operator==(OPERATION lhs, int rhs) - { - return static_cast(lhs) == rhs; - } - static bool Intersects(OPERATION lhs, OPERATION rhs) { return (lhs & rhs) != 0; @@ -269,7 +262,7 @@ namespace IMGUIZMO_NAMESPACE 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)); } + bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)) != 0; } }; 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; } @@ -323,9 +316,6 @@ namespace IMGUIZMO_NAMESPACE vec_t component[4]; }; - matrix_t(const matrix_t& other) { memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); } - matrix_t() {} - operator float* () { return m16; } operator const float* () const { return m16; } void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); } @@ -642,13 +632,44 @@ namespace IMGUIZMO_NAMESPACE // Matches MT_MOVE_AB order static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y }; + Style::Style() + { + // default values + TranslationLineThickness = 3.0f; + TranslationLineArrowSize = 6.0f; + RotationLineThickness = 2.0f; + RotationOuterLineThickness = 3.0f; + ScaleLineThickness = 3.0f; + ScaleLineCircleSize = 6.0f; + HatchedAxisLineThickness = 6.0f; + CenterCircleSize = 6.0f; + + // initialize default colors + Colors[DIRECTION_X] = ImVec4(0.666f, 0.000f, 0.000f, 1.000f); + Colors[DIRECTION_Y] = ImVec4(0.000f, 0.666f, 0.000f, 1.000f); + Colors[DIRECTION_Z] = ImVec4(0.000f, 0.000f, 0.666f, 1.000f); + Colors[PLANE_X] = ImVec4(0.666f, 0.000f, 0.000f, 0.380f); + Colors[PLANE_Y] = ImVec4(0.000f, 0.666f, 0.000f, 0.380f); + Colors[PLANE_Z] = ImVec4(0.000f, 0.000f, 0.666f, 0.380f); + Colors[SELECTION] = ImVec4(1.000f, 0.500f, 0.062f, 0.541f); + Colors[INACTIVE] = ImVec4(0.600f, 0.600f, 0.600f, 0.600f); + Colors[TRANSLATION_LINE] = ImVec4(0.666f, 0.666f, 0.666f, 0.666f); + Colors[SCALE_LINE] = ImVec4(0.250f, 0.250f, 0.250f, 1.000f); + Colors[ROTATION_USING_BORDER] = ImVec4(1.000f, 0.500f, 0.062f, 1.000f); + Colors[ROTATION_USING_FILL] = ImVec4(1.000f, 0.500f, 0.062f, 0.500f); + Colors[HATCHED_AXIS_LINES] = ImVec4(0.000f, 0.000f, 0.000f, 0.500f); + Colors[TEXT] = ImVec4(1.000f, 1.000f, 1.000f, 1.000f); + Colors[TEXT_SHADOW] = ImVec4(0.000f, 0.000f, 0.000f, 1.000f); + } + struct Context { - Context() : mbUsing(false), mbEnable(true), mbUsingBounds(false) + Context() : mbUsing(false), mbUsingViewManipulate(false), mbEnable(true), mIsViewManipulatorHovered(false), mbUsingBounds(false) { } ImDrawList* mDrawList; + Style mStyle; MODE mMode; matrix_t mViewMat; @@ -679,9 +700,11 @@ namespace IMGUIZMO_NAMESPACE vec_t mRelativeOrigin; bool mbUsing; + bool mbUsingViewManipulate; bool mbEnable; - + bool mbMouseOver; bool mReversed; // reversed projection matrix + bool mIsViewManipulatorHovered; // translation vec_t mTranslationPlan; @@ -703,9 +726,13 @@ namespace IMGUIZMO_NAMESPACE // save axis factor when using gizmo bool mBelowAxisLimit[3]; + int mAxisMask = 0; bool mBelowPlaneLimit[3]; float mAxisFactor[3]; + float mAxisLimit=0.0025f; + float mPlaneLimit=0.02f; + // bounds stretching vec_t mBoundsPivot; vec_t mBoundsAnchor; @@ -728,25 +755,30 @@ namespace IMGUIZMO_NAMESPACE float mDisplayRatio = 1.f; bool mIsOrthographic = false; + // check to not have multiple gizmo highlighted at the same time + bool mbOverGizmoHotspot = false; - int mActualID = -1; - int mEditingID = -1; + ImGuiWindow* mAlternativeWindow = nullptr; + ImVector mIDStack; + ImGuiID mEditingID = -1; OPERATION mOperation = OPERATION(-1); bool mAllowAxisFlip = true; float mGizmoSizeClipSpace = 0.1f; + + inline ImGuiID GetCurrentID() + { + if (mIDStack.empty()) + { + mIDStack.push_back(-1); + } + return mIDStack.back(); + } }; 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" }; @@ -765,6 +797,17 @@ namespace IMGUIZMO_NAMESPACE static int GetRotateType(OPERATION op); static int GetScaleType(OPERATION op); + Style& GetStyle() + { + return gContext.mStyle; + } + + static ImU32 GetColorU32(int idx) + { + IM_ASSERT(idx < COLOR::COUNT); + return ImGui::ColorConvertFloat4ToU32(gContext.mStyle.Colors[idx]); + } + 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; @@ -818,7 +861,10 @@ namespace IMGUIZMO_NAMESPACE } vec_t clipSpaceAxis = endOfSegment - startOfSegment; - clipSpaceAxis.y /= gContext.mDisplayRatio; + if (gContext.mDisplayRatio < 1.0) + clipSpaceAxis.x *= gContext.mDisplayRatio; + else + clipSpaceAxis.y /= gContext.mDisplayRatio; float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + clipSpaceAxis.y * clipSpaceAxis.y); return segmentLengthInClipSpace; } @@ -890,6 +936,21 @@ namespace IMGUIZMO_NAMESPACE 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 (gContext.mAlternativeWindow != nullptr && g.HoveredWindow == gContext.mAlternativeWindow) + 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; @@ -935,12 +996,28 @@ namespace IMGUIZMO_NAMESPACE ImGui::Begin("gizmo", NULL, flags); gContext.mDrawList = ImGui::GetWindowDrawList(); + gContext.mbOverGizmoHotspot = false; ImGui::End(); ImGui::PopStyleVar(); ImGui::PopStyleColor(2); } bool IsUsing() + { + return (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID)) || gContext.mbUsingBounds; + } + + bool IsUsingViewManipulate() + { + return gContext.mbUsingViewManipulate; + } + + bool IsViewManipulateHovered() + { + return gContext.mIsViewManipulatorHovered; + } + + bool IsUsingAny() { return gContext.mbUsing || gContext.mbUsingBounds; } @@ -988,6 +1065,7 @@ namespace IMGUIZMO_NAMESPACE gContext.mMode = mode; gContext.mViewMat = *(matrix_t*)view; gContext.mProjectionMat = *(matrix_t*)projection; + gContext.mbMouseOver = IsHoveringWindow(); gContext.mModelLocal = *(matrix_t*)matrix; gContext.mModelLocal.OrthoNormalize(); @@ -1026,7 +1104,6 @@ namespace IMGUIZMO_NAMESPACE // 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); @@ -1045,14 +1122,16 @@ namespace IMGUIZMO_NAMESPACE { if (gContext.mbEnable) { + ImU32 selectionColor = GetColorU32(SELECTION); + 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 + 1] = (type == (int)(MT_MOVE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i); + colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : GetColorU32(PLANE_X + i); colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4]; } break; @@ -1060,7 +1139,7 @@ namespace IMGUIZMO_NAMESPACE 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]; + colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i); } break; case SCALEU: @@ -1068,7 +1147,7 @@ namespace IMGUIZMO_NAMESPACE 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]; + colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i); } break; // note: this internal function is only called with three possible values for operation @@ -1078,6 +1157,7 @@ namespace IMGUIZMO_NAMESPACE } else { + ImU32 inactiveColor = GetColorU32(INACTIVE); for (int i = 0; i < 7; i++) { colors[i] = inactiveColor; @@ -1091,11 +1171,13 @@ namespace IMGUIZMO_NAMESPACE dirPlaneX = directionUnary[(axisIndex + 1) % 3]; dirPlaneY = directionUnary[(axisIndex + 2) % 3]; - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID)) { // when using, use stored factors so the gizmo doesn't flip when we translate - belowAxisLimit = gContext.mBelowAxisLimit[axisIndex]; - belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex]; + + // Apply axis mask to axes and planes + belowAxisLimit = gContext.mBelowAxisLimit[axisIndex] && ((1< 0.0025f); - belowAxisLimit = (axisLengthInClipSpace > 0.02f); + // Apply axis mask to axes and planes + belowPlaneLimit = (paraSurf > gContext.mAxisLimit) && (((1< gContext.mPlaneLimit) && !((1<AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1, colors[3 - axis], false, 2); + drawList->AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1, colors[3 - axis], false, gContext.mStyle.RotationLineThickness); } float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0]))); @@ -1238,17 +1331,17 @@ namespace IMGUIZMO_NAMESPACE gContext.mRadiusSquareCenter = radiusAxis; } } - if(hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN)) + if(hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN) && (!isMultipleAxesMasked && isNoAxesMasked)) { - drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, 3.f); + drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, gContext.mStyle.RotationOuterLineThickness); } - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(type)) + if (gContext.mbUsing && (gContext.GetCurrentID() == 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++) + for (unsigned int i = 1; i < halfCircleSegmentCount + 1; i++) { float ng = gContext.mRotationAngle * ((float)(i - 1) / (float)(halfCircleSegmentCount - 1)); matrix_t rotateVectorMatrix; @@ -1258,24 +1351,29 @@ namespace IMGUIZMO_NAMESPACE 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); + drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_FILL)); + drawList->AddPolyline(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_BORDER), true, gContext.mStyle.RotationLineThickness); 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); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps); } } static void DrawHatchedAxis(const vec_t& axis) { + if (gContext.mStyle.HatchedAxisLineThickness <= 0.0f) + { + return; + } + 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); + gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, GetColorU32(HATCHED_AXIS_LINES), gContext.mStyle.HatchedAxisLineThickness); } } @@ -1295,12 +1393,12 @@ namespace IMGUIZMO_NAMESPACE // draw vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f }; - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID)) { scaleDisplay = gContext.mScale; } - for (unsigned int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { if(!Intersects(op, static_cast(SCALE_X << i))) { @@ -1322,17 +1420,18 @@ namespace IMGUIZMO_NAMESPACE 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)) + if (gContext.mbUsing && (gContext.GetCurrentID() == 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)); + ImU32 scaleLineColor = GetColorU32(SCALE_LINE); + drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, scaleLineColor, gContext.mStyle.ScaleLineThickness); + drawList->AddCircleFilled(worldDirSSpaceNoScale, gContext.mStyle.ScaleLineCircleSize, scaleLineColor); } if (!hasTranslateOnAxis || gContext.mbUsing) { - drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); + drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.ScaleLineThickness); } - drawList->AddCircleFilled(worldDirSSpace, 6.f, colors[i + 1]); + drawList->AddCircleFilled(worldDirSSpace, gContext.mStyle.ScaleLineCircleSize, colors[i + 1]); if (gContext.mAxisFactor[i] < 0.f) { @@ -1343,9 +1442,9 @@ namespace IMGUIZMO_NAMESPACE } // draw screen cirle - drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); + drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32); - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsScaleType(type)) { //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection); ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); @@ -1360,8 +1459,8 @@ namespace IMGUIZMO_NAMESPACE //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); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps); } } @@ -1382,12 +1481,12 @@ namespace IMGUIZMO_NAMESPACE // draw vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f }; - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID)) { scaleDisplay = gContext.mScale; } - for (unsigned int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { if (!Intersects(op, static_cast(SCALE_XU << i))) { @@ -1405,11 +1504,12 @@ namespace IMGUIZMO_NAMESPACE { bool hasTranslateOnAxis = Contains(op, static_cast(TRANSLATE_X << i)); float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f; - ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal); + //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 (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) +#if 0 + if (gContext.mbUsing && (gContext.GetCurrentID() == 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)); @@ -1420,15 +1520,16 @@ namespace IMGUIZMO_NAMESPACE 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); + drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, gContext.mStyle.CenterCircleSize); - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsScaleType(type)) { //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection); ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); @@ -1443,8 +1544,8 @@ namespace IMGUIZMO_NAMESPACE //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); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps); } } @@ -1470,7 +1571,7 @@ namespace IMGUIZMO_NAMESPACE // draw bool belowAxisLimit = false; bool belowPlaneLimit = false; - for (unsigned int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { vec_t dirPlaneX, dirPlaneY, dirAxis; ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); @@ -1483,14 +1584,14 @@ namespace IMGUIZMO_NAMESPACE 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); + drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.TranslationLineThickness); // Arrow head begin ImVec2 dir(origin - worldDirSSpace); float d = sqrtf(ImLengthSqr(dir)); dir /= d; // Normalize - dir *= 6.0f; + dir *= gContext.mStyle.TranslationLineArrowSize; ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector ImVec2 a(worldDirSSpace + dir); @@ -1514,16 +1615,18 @@ namespace IMGUIZMO_NAMESPACE 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->AddPolyline(screenQuadPts, 4, GetColorU32(DIRECTION_X + i), true, 1.0f); drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]); } } } - drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); + drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32); - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(type)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsTranslateType(type)) { + ImU32 translationLineColor = GetColorU32(TRANSLATION_LINE); + 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 }; @@ -1537,8 +1640,8 @@ namespace IMGUIZMO_NAMESPACE 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); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps); } } @@ -1567,7 +1670,7 @@ namespace IMGUIZMO_NAMESPACE { numAxes = 0; float bestDot = 0.f; - for (unsigned int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { vec_t dirPlaneNormalWorld; dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource); @@ -1649,9 +1752,9 @@ namespace IMGUIZMO_NAMESPACE 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 stepLength = 1.f / (float)stepCount; float t1 = (float)j * stepLength; float t2 = (float)j * stepLength + stepLength * 0.5f; ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1)); @@ -1688,6 +1791,8 @@ namespace IMGUIZMO_NAMESPACE overSmallAnchor = false; } + ImU32 selectionColor = GetColorU32(SELECTION); + unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha); unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha); @@ -1712,7 +1817,7 @@ namespace IMGUIZMO_NAMESPACE gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis]; gContext.mbUsingBounds = true; - gContext.mEditingID = gContext.mActualID; + gContext.mEditingID = gContext.GetCurrentID(); gContext.mBoundsMatrix = gContext.mModelSource; } // small anchor on middle of segment @@ -1731,12 +1836,12 @@ namespace IMGUIZMO_NAMESPACE gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f); gContext.mbUsingBounds = true; - gContext.mEditingID = gContext.mActualID; + gContext.mEditingID = gContext.GetCurrentID(); gContext.mBoundsMatrix = gContext.mModelSource; } } - if (gContext.mbUsingBounds && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) + if (gContext.mbUsingBounds && (gContext.GetCurrentID() == gContext.mEditingID)) { matrix_t scale; scale.SetToIdentity(); @@ -1790,13 +1895,13 @@ namespace IMGUIZMO_NAMESPACE // info text char tmps[512]; ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); - ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f" + ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z: %.2f" , (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length() , (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length() , (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.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); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps); } if (!io.MouseDown[0]) { @@ -1831,12 +1936,14 @@ namespace IMGUIZMO_NAMESPACE } // compute - for (unsigned int i = 0; i < 3 && type == MT_NONE; i++) + for (int i = 0; i < 3 && type == MT_NONE; i++) { if(!Intersects(op, static_cast(SCALE_X << i))) { continue; } + bool isAxisMasked = ((1 << i) & gContext.mAxisMask) != 0; + vec_t dirPlaneX, dirPlaneY, dirAxis; bool belowAxisLimit, belowPlaneLimit; ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true); @@ -1857,7 +1964,8 @@ namespace IMGUIZMO_NAMESPACE if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size { - type = MT_SCALE_X + i; + if (!isAxisMasked) + type = MT_SCALE_X + i; } } @@ -1870,7 +1978,7 @@ namespace IMGUIZMO_NAMESPACE type = MT_SCALE_XYZ; } - for (unsigned int i = 0; i < 3 && type == MT_NONE; i++) + for (int i = 0; i < 3 && type == MT_NONE; i++) { if (!Intersects(op, static_cast(SCALE_XU << i))) { @@ -1886,7 +1994,7 @@ namespace IMGUIZMO_NAMESPACE { bool hasTranslateOnAxis = Contains(op, static_cast(TRANSLATE_X << i)); float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f; - ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal); + //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); @@ -1906,6 +2014,10 @@ namespace IMGUIZMO_NAMESPACE { return MT_NONE; } + + bool isNoAxesMasked = !gContext.mAxisMask; + bool isMultipleAxesMasked = (gContext.mAxisMask & (gContext.mAxisMask - 1)) != 0; + ImGuiIO& io = ImGui::GetIO(); int type = MT_NONE; @@ -1913,6 +2025,8 @@ namespace IMGUIZMO_NAMESPACE float dist = deltaScreen.Length(); if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && dist < (gContext.mRadiusSquareCenter + 4.0f)) { + if (!isNoAxesMasked) + return MT_NONE; type = MT_ROTATE_SCREEN; } @@ -1921,12 +2035,13 @@ namespace IMGUIZMO_NAMESPACE vec_t modelViewPos; modelViewPos.TransformPoint(gContext.mModel.v.position, gContext.mViewMat); - for (unsigned int i = 0; i < 3 && type == MT_NONE; i++) + for (int i = 0; i < 3 && type == MT_NONE; i++) { if(!Intersects(op, static_cast(ROTATE_X << i))) { continue; } + bool isAxisMasked = ((1 << i) & gContext.mAxisMask) != 0; // pickup plan vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]); @@ -1951,6 +2066,8 @@ namespace IMGUIZMO_NAMESPACE const float distance = makeVect(distanceOnScreen).Length(); if (distance < 8.f) // pixel size { + if ((!isAxisMasked || isMultipleAxesMasked) && !isNoAxesMasked) + break; type = MT_ROTATE_X + i; } } @@ -1960,10 +2077,14 @@ namespace IMGUIZMO_NAMESPACE static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion) { - if(!Intersects(op, TRANSLATE) || gContext.mbUsing) + if(!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver) { return MT_NONE; } + + bool isNoAxesMasked = !gContext.mAxisMask; + bool isMultipleAxesMasked = (gContext.mAxisMask & (gContext.mAxisMask - 1)) != 0; + ImGuiIO& io = ImGui::GetIO(); int type = MT_NONE; @@ -1978,8 +2099,9 @@ namespace IMGUIZMO_NAMESPACE const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY)); // compute - for (unsigned int i = 0; i < 3 && type == MT_NONE; i++) + for (int i = 0; i < 3 && type == MT_NONE; i++) { + bool isAxisMasked = ((1 << i) & gContext.mAxisMask) != 0; vec_t dirPlaneX, dirPlaneY, dirAxis; bool belowAxisLimit, belowPlaneLimit; ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); @@ -1996,6 +2118,8 @@ namespace IMGUIZMO_NAMESPACE vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), makeVect(axisEndOnScreen)); if ((closestPointOnAxis - screenCoord).Length() < 12.f && Intersects(op, static_cast(TRANSLATE_X << i))) // pixel size { + if (isAxisMasked) + break; type = MT_MOVE_X + i; } @@ -2003,6 +2127,8 @@ namespace IMGUIZMO_NAMESPACE 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])) { + if ((!isAxisMasked || isMultipleAxesMasked) && !isNoAxesMasked) + break; type = MT_MOVE_YZ + i; } @@ -2025,9 +2151,13 @@ namespace IMGUIZMO_NAMESPACE bool modified = false; // move - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation)) { +#if IMGUI_VERSION_NUM >= 18723 ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif 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; @@ -2095,15 +2225,20 @@ namespace IMGUIZMO_NAMESPACE { // find new possible way to move vec_t gizmoHitProportion; - type = GetMoveType(op, &gizmoHitProportion); + type = gContext.mbOverGizmoHotspot ? MT_NONE : GetMoveType(op, &gizmoHitProportion); + gContext.mbOverGizmoHotspot |= type != MT_NONE; if (type != MT_NONE) { - ImGui::SetNextFrameWantCaptureMouse(true); +#if IMGUI_VERSION_NUM >= 18723 + ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif } if (CanActivate() && type != MT_NONE) { gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; + gContext.mEditingID = gContext.GetCurrentID(); 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, @@ -2130,7 +2265,7 @@ namespace IMGUIZMO_NAMESPACE static bool HandleScale(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap) { - if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE) + if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver) { return false; } @@ -2140,33 +2275,43 @@ namespace IMGUIZMO_NAMESPACE if (!gContext.mbUsing) { // find new possible way to scale - type = GetScaleType(op); + type = gContext.mbOverGizmoHotspot ? MT_NONE : GetScaleType(op); + gContext.mbOverGizmoHotspot |= type != MT_NONE; + if (type != MT_NONE) { +#if IMGUI_VERSION_NUM >= 18723 ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif } if (CanActivate() && type != MT_NONE) { gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; + gContext.mEditingID = gContext.GetCurrentID(); 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 }; + const vec_t movePlanNormal[] = { gContext.mModelLocal.v.up, gContext.mModelLocal.v.dir, gContext.mModelLocal.v.right, gContext.mModelLocal.v.dir, gContext.mModelLocal.v.up, gContext.mModelLocal.v.right, -gContext.mCameraDir }; // pickup plan - gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_SCALE_X]); + gContext.mTranslationPlan = BuildPlan(gContext.mModelLocal.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.mMatrixOrigin = gContext.mModelLocal.v.position; gContext.mScale.Set(1.f, 1.f, 1.f); - gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor); + gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModelLocal.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)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsScaleType(gContext.mCurrentOperation)) { +#if IMGUI_VERSION_NUM >= 18723 ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif 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; @@ -2243,7 +2388,7 @@ namespace IMGUIZMO_NAMESPACE static bool HandleRotation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap) { - if(!Intersects(op, ROTATE) || type != MT_NONE) + if(!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver) { return false; } @@ -2253,11 +2398,16 @@ namespace IMGUIZMO_NAMESPACE if (!gContext.mbUsing) { - type = GetRotateType(op); + type = gContext.mbOverGizmoHotspot ? MT_NONE : GetRotateType(op); + gContext.mbOverGizmoHotspot |= type != MT_NONE; if (type != MT_NONE) { +#if IMGUI_VERSION_NUM >= 18723 ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif } if (type == MT_ROTATE_SCREEN) @@ -2268,7 +2418,7 @@ namespace IMGUIZMO_NAMESPACE if (CanActivate() && type != MT_NONE) { gContext.mbUsing = true; - gContext.mEditingID = gContext.mActualID; + gContext.mEditingID = gContext.GetCurrentID(); gContext.mCurrentOperation = type; const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir }; // pickup plan @@ -2289,9 +2439,13 @@ namespace IMGUIZMO_NAMESPACE } // rotation - if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation)) + if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation)) { +#if IMGUI_VERSION_NUM >= 18723 ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif gContext.mRotationAngle = ComputeAngleOnPlan(); if (snap) { @@ -2391,9 +2545,78 @@ namespace IMGUIZMO_NAMESPACE mat.v.position.Set(translation[0], translation[1], translation[2], 1.f); } + void SetAlternativeWindow(ImGuiWindow* window) + { + gContext.mAlternativeWindow = window; + } + void SetID(int id) { - gContext.mActualID = id; + if (gContext.mIDStack.empty()) + { + gContext.mIDStack.push_back(-1); + } + gContext.mIDStack.back() = id; + } + + ImGuiID GetID(const char* str, const char* str_end) + { + ImGuiID seed = gContext.GetCurrentID(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + return id; + } + + ImGuiID GetID(const char* str) + { + return GetID(str, nullptr); + } + + ImGuiID GetID(const void* ptr) + { + ImGuiID seed = gContext.GetCurrentID(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + return id; + } + + ImGuiID GetID(int n) + { + ImGuiID seed = gContext.GetCurrentID(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + return id; + } + + void PushID(const char* str_id) + { + ImGuiID id = GetID(str_id); + gContext.mIDStack.push_back(id); + } + + void PushID(const char* str_id_begin, const char* str_id_end) + { + ImGuiID id = GetID(str_id_begin, str_id_end); + gContext.mIDStack.push_back(id); + } + + void PushID(const void* ptr_id) + { + ImGuiID id = GetID(ptr_id); + gContext.mIDStack.push_back(id); + } + + void PushID(int int_id) + { + ImGuiID id = GetID(int_id); + gContext.mIDStack.push_back(id); + } + + void PopID() + { + IM_ASSERT(gContext.mIDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? + gContext.mIDStack.pop_back(); + if (gContext.mIDStack.empty()) + { + gContext.mIDStack.clear(); + } } void AllowAxisFlip(bool value) @@ -2401,8 +2624,33 @@ namespace IMGUIZMO_NAMESPACE gContext.mAllowAxisFlip = value; } + void SetAxisLimit(float value) + { + gContext.mAxisLimit=value; + } + + void SetAxisMask(bool x, bool y, bool z) + { + gContext.mAxisMask = (x ? 1 : 0) + (y ? 2 : 0) + (z ? 4 : 0); + } + + void SetPlaneLimit(float value) + { + gContext.mPlaneLimit = value; + } + + bool IsOver(float* position, float pixelRadius) + { + const ImGuiIO& io = ImGui::GetIO(); + + float radius = sqrtf((ImLengthSqr(worldToPos({ position[0], position[1], position[2], 0.0f }, gContext.mViewProjection) - io.MousePos))); + return radius < pixelRadius; + } + bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix, const float* snap, const float* localBounds, const float* boundsSnap) { + gContext.mDrawList->PushClipRect (ImVec2 (gContext.mX, gContext.mY), ImVec2 (gContext.mX + gContext.mWidth, gContext.mY + gContext.mHeight), false); + // Scale is always local or matrix will be skewed when applying world scale or oriented matrix ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode); @@ -2414,8 +2662,8 @@ namespace IMGUIZMO_NAMESPACE // behind camera vec_t camSpacePosition; - camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mModel * gContext.mViewMat); - if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f) + camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP); + if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f && !gContext.mbUsing) { return false; } @@ -2446,6 +2694,8 @@ namespace IMGUIZMO_NAMESPACE DrawScaleGizmo(operation, type); DrawScaleUniveralGizmo(operation, type); } + + gContext.mDrawList->PopClipRect (); return manipulated; } @@ -2580,7 +2830,9 @@ namespace IMGUIZMO_NAMESPACE { cubeFace.faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res); } - cubeFace.color = directionColor[normalIndex] | IM_COL32(0x80, 0x80, 0x80, 0); + + ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex); + cubeFace.color = directionColor | IM_COL32(0x80, 0x80, 0x80, 0); cubeFace.z = centerPositionVP.z / centerPositionVP.w; cubeFaceCount++; @@ -2661,11 +2913,17 @@ namespace IMGUIZMO_NAMESPACE } } + void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor) + { + // Scale is always local or matrix will be skewed when applying world scale or oriented matrix + ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode); + ViewManipulate(view, length, position, size, backgroundColor); + } + 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; @@ -2712,6 +2970,7 @@ namespace IMGUIZMO_NAMESPACE // tag faces bool boxes[27]{}; + static int overBox = -1; for (int iPass = 0; iPass < 2; iPass++) { for (int iFace = 0; iFace < 6; iFace++) @@ -2768,53 +3027,25 @@ namespace IMGUIZMO_NAMESPACE } 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; + 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); + 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)); + ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex); + gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor | IM_COL32(0x80, 0x80, 0x80, 0x80)) | (gContext.mIsViewManipulatorHovered ? IM_COL32(0x08, 0x08, 0x08, 0) : 0)); if (boxes[boxCoordInt]) { - gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, IM_COL32(0xF0, 0xA0, 0x60, 0x80)); + ImU32 selectionColor = GetColorU32(SELECTION); + gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, selectionColor); - 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 - cx, 1.f - cy, 1.f - 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.MouseDown[0] && !isDraging) - { + if (io.MouseDown[0] && !isClicking && !isDraging && GImGui->ActiveId == 0) { + overBox = boxCoordInt; isClicking = true; + isDraging = true; } } } @@ -2835,19 +3066,51 @@ namespace IMGUIZMO_NAMESPACE vec_t newEye = camTarget + newDir * length; LookAt(&newEye.x, &camTarget.x, &newUp.x, view); } - isInside = ImRect(position, position + size).Contains(io.MousePos); + gContext.mIsViewManipulatorHovered = gContext.mbMouseOver && ImRect(position, position + size).Contains(io.MousePos); - // drag view - if (!isDraging && io.MouseDown[0] && isInside && (fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f)) + if (io.MouseDown[0] && (fabsf(io.MouseDelta[0]) || fabsf(io.MouseDelta[1])) && isClicking) { - isDraging = true; isClicking = false; } - else if (isDraging && !io.MouseDown[0]) + + if (!io.MouseDown[0]) { + if (isClicking) + { + // apply new view direction + int cx = overBox / 9; + int cy = (overBox - cx * 9) / 3; + int cz = overBox % 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; isDraging = false; } + if (isDraging) { matrix_t rx, ry, roll; @@ -2876,6 +3139,15 @@ namespace IMGUIZMO_NAMESPACE LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view); } + gContext.mbUsingViewManipulate = (interpolationFrames != 0) || isDraging; + if (isClicking || gContext.mbUsingViewManipulate || gContext.mIsViewManipulatorHovered) { +#if IMGUI_VERSION_NUM >= 18723 + ImGui::SetNextFrameWantCaptureMouse(true); +#else + ImGui::CaptureMouseFromApp(); +#endif + } + // restore view/projection because it was used to compute ray ComputeContext(svgView.m16, svgProjection.m16, gContext.mModelSource.m16, gContext.mMode); }