ADD: Selection

This commit is contained in:
2025-11-18 02:18:16 +09:00
parent 24089dc325
commit 94ba704f99
37 changed files with 7495 additions and 35 deletions

View File

@@ -49,6 +49,26 @@ target_sources(imgui PRIVATE
target_link_libraries(imgui PUBLIC Vulkan::Vulkan SDL2::SDL2)
add_library(ImGuizmo STATIC
ImGuizmo/ImGuizmo.cpp
ImGuizmo/ImSequencer.cpp
ImGuizmo/ImCurveEdit.cpp
ImGuizmo/ImGradient.cpp
ImGuizmo/GraphEditor.cpp
)
target_include_directories(ImGuizmo PUBLIC
ImGuizmo
imgui
)
target_compile_definitions(ImGuizmo
PRIVATE
IMGUI_DEFINE_MATH_OPERATORS
)
target_link_libraries(ImGuizmo PUBLIC imgui)
target_include_directories(stb_image INTERFACE stb_image)
# MikkTSpace (optional)

11
third_party/ImGuizmo/.editorconfig vendored Normal file
View File

@@ -0,0 +1,11 @@
root = true
[*]
indent_style = space
indent_size = 3
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

1111
third_party/ImGuizmo/GraphEditor.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

151
third_party/ImGuizmo/GraphEditor.h vendored Normal file
View File

@@ -0,0 +1,151 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#pragma once
#include <vector>
#include <stdint.h>
#include <string>
#include "imgui.h"
#include "imgui_internal.h"
namespace GraphEditor {
typedef size_t NodeIndex;
typedef size_t SlotIndex;
typedef size_t LinkIndex;
typedef size_t TemplateIndex;
// Force the view to be respositionned and zoom to fit nodes with Show function.
// Parameter value will be changed to Fit_None by the function.
enum FitOnScreen
{
Fit_None,
Fit_AllNodes,
Fit_SelectedNodes
};
// Display options and colors
struct Options
{
ImRect mMinimap{{0.75f, 0.8f, 0.99f, 0.99f}}; // rectangle coordinates of minimap
ImU32 mBackgroundColor{ IM_COL32(40, 40, 40, 255) }; // full background color
ImU32 mGridColor{ IM_COL32(0, 0, 0, 60) }; // grid lines color
ImU32 mGridColor2{ IM_COL32(0, 0, 0, 160) }; // grid lines color every 10th
ImU32 mSelectedNodeBorderColor{ IM_COL32(255, 130, 30, 255) }; // node border color when it's selected
ImU32 mNodeBorderColor{ IM_COL32(100, 100, 100, 0) }; // node border color when it's not selected
ImU32 mQuadSelection{ IM_COL32(255, 32, 32, 64) }; // quad selection inside color
ImU32 mQuadSelectionBorder{ IM_COL32(255, 32, 32, 255) }; // quad selection border color
ImU32 mDefaultSlotColor{ IM_COL32(128, 128, 128, 255) }; // when no color is provided in node template, use this value
ImU32 mFrameFocus{ IM_COL32(64, 128, 255, 255) }; // rectangle border when graph editor has focus
float mLineThickness{ 5 }; // links width in pixels when zoom value is 1
float mGridSize{ 64.f }; // background grid size in pixels when zoom value is 1
float mRounding{ 3.f }; // rounding at node corners
float mZoomRatio{ 0.1f }; // factor per mouse wheel delta
float mZoomLerpFactor{ 0.25f }; // the smaller, the smoother
float mBorderSelectionThickness{ 6.f }; // thickness of selection border around nodes
float mBorderThickness{ 6.f }; // thickness of selection border around nodes
float mNodeSlotRadius{ 8.f }; // circle radius for inputs and outputs
float mNodeSlotHoverFactor{ 1.2f }; // increase size when hovering
float mMinZoom{ 0.2f }, mMaxZoom { 1.1f };
float mSnap{ 5.f };
bool mDisplayLinksAsCurves{ true }; // false is straight and 45deg lines
bool mAllowQuadSelection{ true }; // multiple selection using drag and drop
bool mRenderGrid{ true }; // grid or nothing
bool mDrawIONameOnHover{ true }; // only draw node input/output when hovering
};
// View state: scroll position and zoom factor
struct ViewState
{
ImVec2 mPosition{0.0f, 0.0f}; // scroll position
float mFactor{ 1.0f }; // current zoom factor
float mFactorTarget{ 1.0f }; // targeted zoom factor interpolated using Options.mZoomLerpFactor
};
struct Template
{
ImU32 mHeaderColor;
ImU32 mBackgroundColor;
ImU32 mBackgroundColorOver;
ImU8 mInputCount;
const char** mInputNames; // can be nullptr. No text displayed.
ImU32* mInputColors; // can be nullptr, default slot color will be used.
ImU8 mOutputCount;
const char** mOutputNames; // can be nullptr. No text displayed.
ImU32* mOutputColors; // can be nullptr, default slot color will be used.
};
struct Node
{
const char* mName;
TemplateIndex mTemplateIndex;
ImRect mRect;
bool mSelected{ false };
};
struct Link
{
NodeIndex mInputNodeIndex;
SlotIndex mInputSlotIndex;
NodeIndex mOutputNodeIndex;
SlotIndex mOutputSlotIndex;
};
struct Delegate
{
virtual bool AllowedLink(NodeIndex from, NodeIndex to) = 0;
virtual void SelectNode(NodeIndex nodeIndex, bool selected) = 0;
virtual void MoveSelectedNodes(const ImVec2 delta) = 0;
virtual void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) = 0;
virtual void DelLink(LinkIndex linkIndex) = 0;
// user is responsible for clipping
virtual void CustomDraw(ImDrawList* drawList, ImRect rectangle, NodeIndex nodeIndex) = 0;
// use mouse position to open context menu
// if nodeIndex != -1, right click happens on the specified node
virtual void RightClick(NodeIndex nodeIndex, SlotIndex slotIndexInput, SlotIndex slotIndexOutput) = 0;
virtual const size_t GetTemplateCount() = 0;
virtual const Template GetTemplate(TemplateIndex index) = 0;
virtual const size_t GetNodeCount() = 0;
virtual const Node GetNode(NodeIndex index) = 0;
virtual const size_t GetLinkCount() = 0;
virtual const Link GetLink(LinkIndex index) = 0;
virtual ~Delegate() = default;
};
void Show(Delegate& delegate, const Options& options, ViewState& viewState, bool enabled, FitOnScreen* fit = nullptr);
void GraphEditorClear();
bool EditOptions(Options& options);
} // namespace

458
third_party/ImGuizmo/ImCurveEdit.cpp vendored Normal file
View File

@@ -0,0 +1,458 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#include "ImCurveEdit.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <stdint.h>
#include <set>
#include <vector>
#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
namespace ImCurveEdit
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x + b.x, a.y + b.y);
}
static ImVec2 operator-(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x - b.x, a.y - b.y);
}
static ImVec2 operator*(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x * b.x, a.y * b.y);
}
static ImVec2 operator/(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x / b.x, a.y / b.y);
}
static ImVec2 operator*(const ImVec2& a, const float b) {
return ImVec2(a.x * b, a.y * b);
}
#endif
static float smoothstep(float edge0, float edge1, float x)
{
x = ImClamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return x * x * (3 - 2 * x);
}
static float distance(float x, float y, float x1, float y1, float x2, float y2)
{
float A = x - x1;
float B = y - y1;
float C = x2 - x1;
float D = y2 - y1;
float dot = A * C + B * D;
float len_sq = C * C + D * D;
float param = -1.f;
if (len_sq > FLT_EPSILON)
param = dot / len_sq;
float xx, yy;
if (param < 0.f) {
xx = x1;
yy = y1;
}
else if (param > 1.f) {
xx = x2;
yy = y2;
}
else {
xx = x1 + param * C;
yy = y1 + param * D;
}
float dx = x - xx;
float dy = y - yy;
return sqrtf(dx * dx + dy * dy);
}
static int DrawPoint(ImDrawList* draw_list, ImVec2 pos, const ImVec2 size, const ImVec2 offset, bool edited)
{
int ret = 0;
ImGuiIO& io = ImGui::GetIO();
static const ImVec2 localOffsets[4] = { ImVec2(1,0), ImVec2(0,1), ImVec2(-1,0), ImVec2(0,-1) };
ImVec2 offsets[4];
for (int i = 0; i < 4; i++)
{
offsets[i] = pos * size + localOffsets[i] * 4.5f + offset;
}
const ImVec2 center = pos * size + offset;
const ImRect anchor(center - ImVec2(5, 5), center + ImVec2(5, 5));
draw_list->AddConvexPolyFilled(offsets, 4, 0xFF000000);
if (anchor.Contains(io.MousePos))
{
ret = 1;
if (io.MouseDown[0])
ret = 2;
}
if (edited)
draw_list->AddPolyline(offsets, 4, 0xFFFFFFFF, true, 3.0f);
else if (ret)
draw_list->AddPolyline(offsets, 4, 0xFF80B0FF, true, 2.0f);
else
draw_list->AddPolyline(offsets, 4, 0xFF0080FF, true, 2.0f);
return ret;
}
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect, ImVector<EditPoint>* selectedPoints)
{
static bool selectingQuad = false;
static ImVec2 quadSelection;
static int overCurve = -1;
static int movingCurve = -1;
static bool scrollingV = false;
static std::set<EditPoint> selection;
static bool overSelectedPoint = false;
int ret = 0;
ImGuiIO& io = ImGui::GetIO();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleColor(ImGuiCol_Border, 0);
ImGui::BeginChild(id, size, ImGuiChildFlags_FrameStyle);
delegate.focused = ImGui::IsWindowFocused();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (clippingRect)
draw_list->PushClipRect(clippingRect->Min, clippingRect->Max, true);
const ImVec2 offset = ImGui::GetCursorScreenPos() + ImVec2(0.f, size.y);
const ImVec2 ssize(size.x, -size.y);
const ImRect container(offset + ImVec2(0.f, ssize.y), offset + ImVec2(ssize.x, 0.f));
ImVec2& min = delegate.GetMin();
ImVec2& max = delegate.GetMax();
// handle zoom and VScroll
if (container.Contains(io.MousePos))
{
if (fabsf(io.MouseWheel) > FLT_EPSILON)
{
const float r = (io.MousePos.y - offset.y) / ssize.y;
float ratioY = ImLerp(min.y, max.y, r);
auto scaleValue = [&](float v) {
v -= ratioY;
v *= (1.f - io.MouseWheel * 0.05f);
v += ratioY;
return v;
};
min.y = scaleValue(min.y);
max.y = scaleValue(max.y);
}
if (!scrollingV && ImGui::IsMouseDown(2))
{
scrollingV = true;
}
}
ImVec2 range = max - min + ImVec2(1.f, 0.f); // +1 because of inclusive last frame
const ImVec2 viewSize(size.x, -size.y);
const ImVec2 sizeOfPixel = ImVec2(1.f, 1.f) / viewSize;
const size_t curveCount = delegate.GetCurveCount();
if (scrollingV)
{
float deltaH = io.MouseDelta.y * range.y * sizeOfPixel.y;
min.y -= deltaH;
max.y -= deltaH;
if (!ImGui::IsMouseDown(2))
scrollingV = false;
}
draw_list->AddRectFilled(offset, offset + ssize, delegate.GetBackgroundColor());
auto pointToRange = [&](ImVec2 pt) { return (pt - min) / range; };
auto rangeToPoint = [&](ImVec2 pt) { return (pt * range) + min; };
draw_list->AddLine(ImVec2(-1.f, -min.y / range.y) * viewSize + offset, ImVec2(1.f, -min.y / range.y) * viewSize + offset, 0xFF000000, 1.5f);
bool overCurveOrPoint = false;
int localOverCurve = -1;
// make sure highlighted curve is rendered last
int* curvesIndex = (int*)_malloca(sizeof(int) * curveCount);
for (size_t c = 0; c < curveCount; c++)
curvesIndex[c] = int(c);
int highLightedCurveIndex = -1;
if (overCurve != -1 && curveCount)
{
ImSwap(curvesIndex[overCurve], curvesIndex[curveCount - 1]);
highLightedCurveIndex = overCurve;
}
for (size_t cur = 0; cur < curveCount; cur++)
{
int c = curvesIndex[cur];
if (!delegate.IsVisible(c))
continue;
const size_t ptCount = delegate.GetPointCount(c);
if (ptCount < 1)
continue;
CurveType curveType = delegate.GetCurveType(c);
if (curveType == CurveNone)
continue;
const ImVec2* pts = delegate.GetPoints(c);
uint32_t curveColor = delegate.GetCurveColor(c);
if ((c == highLightedCurveIndex && selection.empty() && !selectingQuad) || movingCurve == c)
curveColor = 0xFFFFFFFF;
for (size_t p = 0; p < ptCount - 1; p++)
{
const ImVec2 p1 = pointToRange(pts[p]);
const ImVec2 p2 = pointToRange(pts[p + 1]);
if (curveType == CurveSmooth || curveType == CurveLinear)
{
size_t subStepCount = (curveType == CurveSmooth) ? 20 : 2;
float step = 1.f / float(subStepCount - 1);
for (size_t substep = 0; substep < subStepCount - 1; substep++)
{
float t = float(substep) * step;
const ImVec2 sp1 = ImLerp(p1, p2, t);
const ImVec2 sp2 = ImLerp(p1, p2, t + step);
const float rt1 = smoothstep(p1.x, p2.x, sp1.x);
const float rt2 = smoothstep(p1.x, p2.x, sp2.x);
const ImVec2 pos1 = ImVec2(sp1.x, ImLerp(p1.y, p2.y, rt1)) * viewSize + offset;
const ImVec2 pos2 = ImVec2(sp2.x, ImLerp(p1.y, p2.y, rt2)) * viewSize + offset;
if (distance(io.MousePos.x, io.MousePos.y, pos1.x, pos1.y, pos2.x, pos2.y) < 8.f && !scrollingV)
{
localOverCurve = int(c);
overCurve = int(c);
overCurveOrPoint = true;
}
draw_list->AddLine(pos1, pos2, curveColor, 1.3f);
} // substep
}
else if (curveType == CurveDiscrete)
{
ImVec2 dp1 = p1 * viewSize + offset;
ImVec2 dp2 = ImVec2(p2.x, p1.y) * viewSize + offset;
ImVec2 dp3 = p2 * viewSize + offset;
draw_list->AddLine(dp1, dp2, curveColor, 1.3f);
draw_list->AddLine(dp2, dp3, curveColor, 1.3f);
if ((distance(io.MousePos.x, io.MousePos.y, dp1.x, dp1.y, dp3.x, dp1.y) < 8.f ||
distance(io.MousePos.x, io.MousePos.y, dp3.x, dp1.y, dp3.x, dp3.y) < 8.f)
/*&& localOverCurve == -1*/)
{
localOverCurve = int(c);
overCurve = int(c);
overCurveOrPoint = true;
}
}
} // point loop
for (size_t p = 0; p < ptCount; p++)
{
const int drawState = DrawPoint(draw_list, pointToRange(pts[p]), viewSize, offset, (selection.find({ int(c), int(p) }) != selection.end() && movingCurve == -1 && !scrollingV));
if (drawState && movingCurve == -1 && !selectingQuad)
{
overCurveOrPoint = true;
overSelectedPoint = true;
overCurve = -1;
if (drawState == 2)
{
if (!io.KeyShift && selection.find({ int(c), int(p) }) == selection.end())
selection.clear();
selection.insert({ int(c), int(p) });
}
}
}
} // curves loop
if (localOverCurve == -1)
overCurve = -1;
// move selection
static bool pointsMoved = false;
static ImVec2 mousePosOrigin;
static std::vector<ImVec2> originalPoints;
if (overSelectedPoint && io.MouseDown[0])
{
if ((fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f) && !selection.empty())
{
if (!pointsMoved)
{
delegate.BeginEdit(0);
mousePosOrigin = io.MousePos;
originalPoints.resize(selection.size());
int index = 0;
for (auto& sel : selection)
{
const ImVec2* pts = delegate.GetPoints(sel.curveIndex);
originalPoints[index++] = pts[sel.pointIndex];
}
}
pointsMoved = true;
ret = 1;
auto prevSelection = selection;
int originalIndex = 0;
for (auto& sel : prevSelection)
{
const ImVec2 p = rangeToPoint(pointToRange(originalPoints[originalIndex]) + (io.MousePos - mousePosOrigin) * sizeOfPixel);
const int newIndex = delegate.EditPoint(sel.curveIndex, sel.pointIndex, p);
if (newIndex != sel.pointIndex)
{
selection.erase(sel);
selection.insert({ sel.curveIndex, newIndex });
}
originalIndex++;
}
}
}
if (overSelectedPoint && !io.MouseDown[0])
{
overSelectedPoint = false;
if (pointsMoved)
{
pointsMoved = false;
delegate.EndEdit();
}
}
// add point
if (overCurve != -1 && io.MouseDoubleClicked[0])
{
const ImVec2 np = rangeToPoint((io.MousePos - offset) / viewSize);
delegate.BeginEdit(overCurve);
delegate.AddPoint(overCurve, np);
delegate.EndEdit();
ret = 1;
}
// move curve
if (movingCurve != -1)
{
const size_t ptCount = delegate.GetPointCount(movingCurve);
const ImVec2* pts = delegate.GetPoints(movingCurve);
if (!pointsMoved)
{
mousePosOrigin = io.MousePos;
pointsMoved = true;
originalPoints.resize(ptCount);
for (size_t index = 0; index < ptCount; index++)
{
originalPoints[index] = pts[index];
}
}
if (ptCount >= 1)
{
for (size_t p = 0; p < ptCount; p++)
{
delegate.EditPoint(movingCurve, int(p), rangeToPoint(pointToRange(originalPoints[p]) + (io.MousePos - mousePosOrigin) * sizeOfPixel));
}
ret = 1;
}
if (!io.MouseDown[0])
{
movingCurve = -1;
pointsMoved = false;
delegate.EndEdit();
}
}
if (movingCurve == -1 && overCurve != -1 && ImGui::IsMouseClicked(0) && selection.empty() && !selectingQuad)
{
movingCurve = overCurve;
delegate.BeginEdit(overCurve);
}
// quad selection
if (selectingQuad)
{
const ImVec2 bmin = ImMin(quadSelection, io.MousePos);
const ImVec2 bmax = ImMax(quadSelection, io.MousePos);
draw_list->AddRectFilled(bmin, bmax, 0x40FF0000, 1.f);
draw_list->AddRect(bmin, bmax, 0xFFFF0000, 1.f);
const ImRect selectionQuad(bmin, bmax);
if (!io.MouseDown[0])
{
if (!io.KeyShift)
selection.clear();
// select everythnig is quad
for (size_t c = 0; c < curveCount; c++)
{
if (!delegate.IsVisible(c))
continue;
const size_t ptCount = delegate.GetPointCount(c);
if (ptCount < 1)
continue;
const ImVec2* pts = delegate.GetPoints(c);
for (size_t p = 0; p < ptCount; p++)
{
const ImVec2 center = pointToRange(pts[p]) * viewSize + offset;
if (selectionQuad.Contains(center))
selection.insert({ int(c), int(p) });
}
}
// done
selectingQuad = false;
}
}
if (!overCurveOrPoint && ImGui::IsMouseClicked(0) && !selectingQuad && movingCurve == -1 && !overSelectedPoint && container.Contains(io.MousePos))
{
selectingQuad = true;
quadSelection = io.MousePos;
}
if (clippingRect)
draw_list->PopClipRect();
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopStyleColor(1);
if (selectedPoints)
{
selectedPoints->resize(int(selection.size()));
int index = 0;
for (auto& point : selection)
(*selectedPoints)[index++] = point;
}
_freea(curvesIndex);
return ret;
}
}

82
third_party/ImGuizmo/ImCurveEdit.h vendored Normal file
View File

@@ -0,0 +1,82 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#pragma once
#include <stdint.h>
#include "imgui.h"
struct ImRect;
namespace ImCurveEdit
{
enum CurveType
{
CurveNone,
CurveDiscrete,
CurveLinear,
CurveSmooth,
CurveBezier,
};
struct EditPoint
{
int curveIndex;
int pointIndex;
bool operator <(const EditPoint& other) const
{
if (curveIndex < other.curveIndex)
return true;
if (curveIndex > other.curveIndex)
return false;
if (pointIndex < other.pointIndex)
return true;
return false;
}
};
struct Delegate
{
bool focused = false;
virtual size_t GetCurveCount() = 0;
virtual bool IsVisible(size_t /*curveIndex*/) { return true; }
virtual CurveType GetCurveType(size_t /*curveIndex*/) const { return CurveLinear; }
virtual ImVec2& GetMin() = 0;
virtual ImVec2& GetMax() = 0;
virtual size_t GetPointCount(size_t curveIndex) = 0;
virtual uint32_t GetCurveColor(size_t curveIndex) = 0;
virtual ImVec2* GetPoints(size_t curveIndex) = 0;
virtual int EditPoint(size_t curveIndex, int pointIndex, ImVec2 value) = 0;
virtual void AddPoint(size_t curveIndex, ImVec2 value) = 0;
virtual unsigned int GetBackgroundColor() { return 0xFF202020; }
// handle undo/redo thru this functions
virtual void BeginEdit(int /*index*/) {}
virtual void EndEdit() {}
virtual ~Delegate() = default;
};
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect = NULL, ImVector<EditPoint>* selectedPoints = NULL);
}

116
third_party/ImGuizmo/ImGradient.cpp vendored Normal file
View File

@@ -0,0 +1,116 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#include "ImGradient.h"
#include "imgui.h"
#include "imgui_internal.h"
namespace ImGradient
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
#endif
static int DrawPoint(ImDrawList* draw_list, ImVec4 color, const ImVec2 size, bool editing, ImVec2 pos)
{
ImGuiIO& io = ImGui::GetIO();
ImVec2 p1 = ImLerp(pos, ImVec2(pos + ImVec2(size.x - size.y, 0.f)), color.w) + ImVec2(3, 3);
ImVec2 p2 = ImLerp(pos + ImVec2(size.y, size.y), ImVec2(pos + size), color.w) - ImVec2(3, 3);
ImRect rc(p1, p2);
color.w = 1.f;
draw_list->AddRectFilled(p1, p2, ImColor(color));
if (editing)
draw_list->AddRect(p1, p2, 0xFFFFFFFF, 2.f, 15, 2.5f);
else
draw_list->AddRect(p1, p2, 0x80FFFFFF, 2.f, 15, 1.25f);
if (rc.Contains(io.MousePos))
{
if (io.MouseClicked[0])
return 2;
return 1;
}
return 0;
}
bool Edit(Delegate& delegate, const ImVec2& size, int& selection)
{
bool ret = false;
ImGuiIO& io = ImGui::GetIO();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::BeginChild(137, size, ImGuiChildFlags_FrameStyle);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
const ImVec2 offset = ImGui::GetCursorScreenPos();
const ImVec4* pts = delegate.GetPoints();
static int currentSelection = -1;
static int movingPt = -1;
if (currentSelection >= int(delegate.GetPointCount()))
currentSelection = -1;
if (movingPt != -1)
{
ImVec4 current = pts[movingPt];
current.w += io.MouseDelta.x / size.x;
current.w = ImClamp(current.w, 0.f, 1.f);
delegate.EditPoint(movingPt, current);
ret = true;
if (!io.MouseDown[0])
movingPt = -1;
}
for (size_t i = 0; i < delegate.GetPointCount(); i++)
{
int ptSel = DrawPoint(draw_list, pts[i], size, i == currentSelection, offset);
if (ptSel == 2)
{
currentSelection = int(i);
ret = true;
}
if (ptSel == 1 && io.MouseDown[0] && movingPt == -1)
{
movingPt = int(i);
}
}
ImRect rc(offset, offset + size);
if (rc.Contains(io.MousePos) && io.MouseDoubleClicked[0])
{
float t = (io.MousePos.x - offset.x) / size.x;
delegate.AddPoint(delegate.GetPoint(t));
ret = true;
}
ImGui::EndChild();
ImGui::PopStyleVar();
selection = currentSelection;
return ret;
}
}

45
third_party/ImGuizmo/ImGradient.h vendored Normal file
View File

@@ -0,0 +1,45 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#pragma once
#include <cstddef>
struct ImVec4;
struct ImVec2;
namespace ImGradient
{
struct Delegate
{
virtual size_t GetPointCount() = 0;
virtual ImVec4* GetPoints() = 0;
virtual int EditPoint(int pointIndex, ImVec4 value) = 0;
virtual ImVec4 GetPoint(float t) = 0;
virtual void AddPoint(ImVec4 value) = 0;
virtual ~Delegate() = default;
};
bool Edit(Delegate& delegate, const ImVec2& size, int& selection);
}

3164
third_party/ImGuizmo/ImGuizmo.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

306
third_party/ImGuizmo/ImGuizmo.h vendored Normal file
View File

@@ -0,0 +1,306 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
// -------------------------------------------------------------------------------------------
// History :
// 2019/11/03 View gizmo
// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode.
// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
// 2016/08/31 First version
//
// -------------------------------------------------------------------------------------------
// Future (no order):
//
// - Multi view
// - display rotation/translation/scale infos in local/world space and not only local
// - finish local/world matrix application
// - OPERATION as bitmask
//
// -------------------------------------------------------------------------------------------
// Example
#if 0
void EditTransform(const Camera& camera, matrix_t& matrix)
{
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
if (ImGui::IsKeyPressed(90))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
if (ImGui::IsKeyPressed(69))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
if (ImGui::IsKeyPressed(82)) // r Key
mCurrentGizmoOperation = ImGuizmo::SCALE;
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
ImGui::SameLine();
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
ImGui::SameLine();
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
mCurrentGizmoOperation = ImGuizmo::SCALE;
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);
ImGui::InputFloat3("Tr", matrixTranslation, 3);
ImGui::InputFloat3("Rt", matrixRotation, 3);
ImGui::InputFloat3("Sc", matrixScale, 3);
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
{
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
mCurrentGizmoMode = ImGuizmo::LOCAL;
ImGui::SameLine();
if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
mCurrentGizmoMode = ImGuizmo::WORLD;
}
static bool useSnap(false);
if (ImGui::IsKeyPressed(83))
useSnap = !useSnap;
ImGui::Checkbox("", &useSnap);
ImGui::SameLine();
vec_t snap;
switch (mCurrentGizmoOperation)
{
case ImGuizmo::TRANSLATE:
snap = config.mSnapTranslation;
ImGui::InputFloat3("Snap", &snap.x);
break;
case ImGuizmo::ROTATE:
snap = config.mSnapRotation;
ImGui::InputFloat("Angle Snap", &snap.x);
break;
case ImGuizmo::SCALE:
snap = config.mSnapScale;
ImGui::InputFloat("Scale Snap", &snap.x);
break;
}
ImGuiIO& io = ImGui::GetIO();
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);
}
#endif
#pragma once
#ifdef USE_IMGUI_API
#include "imconfig.h"
#endif
#ifndef IMGUI_API
#define IMGUI_API
#endif
#ifndef IMGUIZMO_NAMESPACE
#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.
// Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()).
IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr);
// call BeginFrame right after ImGui_XXXX_NewFrame();
IMGUI_API void BeginFrame();
// this is necessary because when imguizmo is compiled into a dll, and imgui into another
// globals are not shared between them.
// More details at https://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam
// expose method to set imgui context
IMGUI_API void SetImGuiContext(ImGuiContext* ctx);
// return true if mouse cursor is over any gizmo control (axis, plan or screen component)
IMGUI_API bool IsOver();
// 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);
// helper functions for manualy editing translation/rotation/scale with an input float
// translation, rotation and scale float points to 3 floats each
// Angles are in degrees (more suitable for human editing)
// example:
// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
// ImGui::InputFloat3("Tr", matrixTranslation, 3);
// ImGui::InputFloat3("Rt", matrixRotation, 3);
// ImGui::InputFloat3("Sc", matrixScale, 3);
// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
//
// These functions have some numerical stability issues for now. Use with caution.
IMGUI_API void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale);
IMGUI_API void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix);
IMGUI_API void SetRect(float x, float y, float width, float height);
// default is false
IMGUI_API void SetOrthographic(bool isOrthographic);
// Render a cube with face color corresponding to face normal. Usefull for debug/tests
IMGUI_API void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount);
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.
// 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
{
TRANSLATE_X = (1u << 0),
TRANSLATE_Y = (1u << 1),
TRANSLATE_Z = (1u << 2),
ROTATE_X = (1u << 3),
ROTATE_Y = (1u << 4),
ROTATE_Z = (1u << 5),
ROTATE_SCREEN = (1u << 6),
SCALE_X = (1u << 7),
SCALE_Y = (1u << 8),
SCALE_Z = (1u << 9),
BOUNDS = (1u << 10),
SCALE_XU = (1u << 11),
SCALE_YU = (1u << 12),
SCALE_ZU = (1u << 13),
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
};
inline OPERATION operator|(OPERATION lhs, OPERATION rhs)
{
return static_cast<OPERATION>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
enum MODE
{
LOCAL,
WORLD
};
IMGUI_API bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix = NULL, const float* snap = NULL, const float* localBounds = NULL, const float* boundsSnap = NULL);
//
// Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en
// It seems to be a defensive patent in the US. I don't think it will bring troubles using it as
// other software are using the same mechanics. But just in case, you are now warned!
//
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);
// Allow axis to flip
// 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();
}

695
third_party/ImGuizmo/ImSequencer.cpp vendored Normal file
View File

@@ -0,0 +1,695 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#include "ImSequencer.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <cstdlib>
namespace ImSequencer
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x + b.x, a.y + b.y);
}
#endif
static bool SequencerAddDelButton(ImDrawList* draw_list, ImVec2 pos, bool add = true)
{
ImGuiIO& io = ImGui::GetIO();
ImRect btnRect(pos, ImVec2(pos.x + 16, pos.y + 16));
bool overBtn = btnRect.Contains(io.MousePos);
bool containedClick = overBtn && btnRect.Contains(io.MouseClickedPos[0]);
bool clickedBtn = containedClick && io.MouseReleased[0];
int btnColor = overBtn ? 0xAAEAFFAA : 0x77A3B2AA;
if (containedClick && io.MouseDownDuration[0] > 0)
btnRect.Expand(2.0f);
float midy = pos.y + 16 / 2 - 0.5f;
float midx = pos.x + 16 / 2 - 0.5f;
draw_list->AddRect(btnRect.Min, btnRect.Max, btnColor, 4);
draw_list->AddLine(ImVec2(btnRect.Min.x + 3, midy), ImVec2(btnRect.Max.x - 3, midy), btnColor, 2);
if (add)
draw_list->AddLine(ImVec2(midx, btnRect.Min.y + 3), ImVec2(midx, btnRect.Max.y - 3), btnColor, 2);
return clickedBtn;
}
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions)
{
bool ret = false;
ImGuiIO& io = ImGui::GetIO();
int cx = (int)(io.MousePos.x);
int cy = (int)(io.MousePos.y);
static float framePixelWidth = 10.f;
static float framePixelWidthTarget = 10.f;
int legendWidth = 200;
static int movingEntry = -1;
static int movingPos = -1;
static int movingPart = -1;
int delEntry = -1;
int dupEntry = -1;
int ItemHeight = 20;
bool popupOpened = false;
int sequenceCount = sequence->GetItemCount();
if (!sequenceCount)
return false;
ImGui::BeginGroup();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
int firstFrameUsed = firstFrame ? *firstFrame : 0;
int controlHeight = sequenceCount * ItemHeight;
for (int i = 0; i < sequenceCount; i++)
controlHeight += int(sequence->GetCustomHeight(i));
int frameCount = ImMax(sequence->GetFrameMax() - sequence->GetFrameMin(), 1);
static bool MovingScrollBar = false;
static bool MovingCurrentFrame = false;
struct CustomDraw
{
int index;
ImRect customRect;
ImRect legendRect;
ImRect clippingRect;
ImRect legendClippingRect;
};
ImVector<CustomDraw> customDraws;
ImVector<CustomDraw> compactCustomDraws;
// zoom in/out
const int visibleFrameCount = (int)floorf((canvas_size.x - legendWidth) / framePixelWidth);
const float barWidthRatio = ImMin(visibleFrameCount / (float)frameCount, 1.f);
const float barWidthInPixels = barWidthRatio * (canvas_size.x - legendWidth);
ImRect regionRect(canvas_pos, canvas_pos + canvas_size);
static bool panningView = false;
static ImVec2 panningViewSource;
static int panningViewFrame;
if (ImGui::IsWindowFocused() && io.KeyAlt && io.MouseDown[2])
{
if (!panningView)
{
panningViewSource = io.MousePos;
panningView = true;
panningViewFrame = *firstFrame;
}
*firstFrame = panningViewFrame - int((io.MousePos.x - panningViewSource.x) / framePixelWidth);
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), sequence->GetFrameMax() - visibleFrameCount);
}
if (panningView && !io.MouseDown[2])
{
panningView = false;
}
framePixelWidthTarget = ImClamp(framePixelWidthTarget, 0.1f, 50.f);
framePixelWidth = ImLerp(framePixelWidth, framePixelWidthTarget, 0.33f);
frameCount = sequence->GetFrameMax() - sequence->GetFrameMin();
if (visibleFrameCount >= frameCount && firstFrame)
*firstFrame = sequence->GetFrameMin();
// --
if (expanded && !*expanded)
{
ImGui::InvisibleButton("canvas", ImVec2(canvas_size.x - canvas_pos.x, (float)ItemHeight));
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), sequence->GetCollapseFmt(), frameCount, sequenceCount);
draw_list->AddText(ImVec2(canvas_pos.x + 26, canvas_pos.y + 2), 0xFFFFFFFF, tmps);
}
else
{
bool hasScrollBar(true);
/*
int framesPixelWidth = int(frameCount * framePixelWidth);
if ((framesPixelWidth + legendWidth) >= canvas_size.x)
{
hasScrollBar = true;
}
*/
// test scroll area
ImVec2 headerSize(canvas_size.x, (float)ItemHeight);
ImVec2 scrollBarSize(canvas_size.x, 14.f);
ImGui::InvisibleButton("topBar", headerSize);
draw_list->AddRectFilled(canvas_pos, canvas_pos + headerSize, 0xFFFF0000, 0);
ImVec2 childFramePos = ImGui::GetCursorScreenPos();
ImVec2 childFrameSize(canvas_size.x, canvas_size.y - 8.f - headerSize.y - (hasScrollBar ? scrollBarSize.y : 0));
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
ImGui::BeginChild(889, childFrameSize, ImGuiChildFlags_FrameStyle);
sequence->focused = ImGui::IsWindowFocused();
ImGui::InvisibleButton("contentBar", ImVec2(canvas_size.x, float(controlHeight)));
const ImVec2 contentMin = ImGui::GetItemRectMin();
const ImVec2 contentMax = ImGui::GetItemRectMax();
const ImRect contentRect(contentMin, contentMax);
const float contentHeight = contentMax.y - contentMin.y;
// full background
draw_list->AddRectFilled(canvas_pos, canvas_pos + canvas_size, 0xFF242424, 0);
// current frame top
ImRect topRect(ImVec2(canvas_pos.x + legendWidth, canvas_pos.y), ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + ItemHeight));
if (!MovingCurrentFrame && !MovingScrollBar && movingEntry == -1 && sequenceOptions & SEQUENCER_CHANGE_FRAME && currentFrame && *currentFrame >= 0 && topRect.Contains(io.MousePos) && io.MouseDown[0])
{
MovingCurrentFrame = true;
}
if (MovingCurrentFrame)
{
if (frameCount)
{
*currentFrame = (int)((io.MousePos.x - topRect.Min.x) / framePixelWidth) + firstFrameUsed;
if (*currentFrame < sequence->GetFrameMin())
*currentFrame = sequence->GetFrameMin();
if (*currentFrame >= sequence->GetFrameMax())
*currentFrame = sequence->GetFrameMax();
}
if (!io.MouseDown[0])
MovingCurrentFrame = false;
}
//header
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
if (sequenceOptions & SEQUENCER_ADD)
{
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + legendWidth - ItemHeight, canvas_pos.y + 2), true))
ImGui::OpenPopup("addEntry");
if (ImGui::BeginPopup("addEntry"))
{
for (int i = 0; i < sequence->GetItemTypeCount(); i++)
if (ImGui::Selectable(sequence->GetItemTypeName(i)))
{
sequence->Add(i);
*selectedEntry = sequence->GetItemCount() - 1;
}
ImGui::EndPopup();
popupOpened = true;
}
}
//header frame number and lines
int modFrameCount = 10;
int frameStep = 1;
while ((modFrameCount * framePixelWidth) < 150)
{
modFrameCount *= 2;
frameStep *= 2;
};
int halfModFrameCount = modFrameCount / 2;
auto drawLine = [&](int i, int regionHeight) {
bool baseIndex = ((i % modFrameCount) == 0) || (i == sequence->GetFrameMax() || i == sequence->GetFrameMin());
bool halfIndex = (i % halfModFrameCount) == 0;
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
int tiretStart = baseIndex ? 4 : (halfIndex ? 10 : 14);
int tiretEnd = baseIndex ? regionHeight : ItemHeight;
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
{
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)ItemHeight), ImVec2((float)px, canvas_pos.y + (float)regionHeight - 1), 0x30606060, 1);
}
if (baseIndex && px > (canvas_pos.x + legendWidth))
{
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", i);
draw_list->AddText(ImVec2((float)px + 3.f, canvas_pos.y), 0xFFBBBBBB, tmps);
}
};
auto drawLineContent = [&](int i, int /*regionHeight*/) {
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
int tiretStart = int(contentMin.y);
int tiretEnd = int(contentMax.y);
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
{
//draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
draw_list->AddLine(ImVec2(float(px), float(tiretStart)), ImVec2(float(px), float(tiretEnd)), 0x30606060, 1);
}
};
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
{
drawLine(i, ItemHeight);
}
drawLine(sequence->GetFrameMin(), ItemHeight);
drawLine(sequence->GetFrameMax(), ItemHeight);
/*
draw_list->AddLine(canvas_pos, ImVec2(canvas_pos.x, canvas_pos.y + controlHeight), 0xFF000000, 1);
draw_list->AddLine(ImVec2(canvas_pos.x, canvas_pos.y + ItemHeight), ImVec2(canvas_size.x, canvas_pos.y + ItemHeight), 0xFF000000, 1);
*/
// clip content
draw_list->PushClipRect(childFramePos, childFramePos + childFrameSize, true);
// draw item names in the legend rect on the left
size_t customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
int type;
sequence->Get(i, NULL, NULL, &type, NULL);
ImVec2 tpos(contentMin.x + 3, contentMin.y + i * ItemHeight + 2 + customHeight);
draw_list->AddText(tpos, 0xFFFFFFFF, sequence->GetItemLabel(i));
if (sequenceOptions & SEQUENCER_DEL)
{
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight + 2 - 10, tpos.y + 2), false))
delEntry = i;
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight - ItemHeight + 2 - 10, tpos.y + 2), true))
dupEntry = i;
}
customHeight += sequence->GetCustomHeight(i);
}
// slots background
customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
unsigned int col = (i & 1) ? 0xFF3A3636 : 0xFF413D3D;
size_t localCustomHeight = sequence->GetCustomHeight(i);
ImVec2 pos = ImVec2(contentMin.x + legendWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
ImVec2 sz = ImVec2(canvas_size.x + canvas_pos.x, pos.y + ItemHeight - 1 + localCustomHeight);
if (!popupOpened && cy >= pos.y && cy < pos.y + (ItemHeight + localCustomHeight) && movingEntry == -1 && cx>contentMin.x && cx < contentMin.x + canvas_size.x)
{
col += 0x80201008;
pos.x -= legendWidth;
}
draw_list->AddRectFilled(pos, sz, col, 0);
customHeight += localCustomHeight;
}
draw_list->PushClipRect(childFramePos + ImVec2(float(legendWidth), 0.f), childFramePos + childFrameSize, true);
// vertical frame lines in content area
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
{
drawLineContent(i, int(contentHeight));
}
drawLineContent(sequence->GetFrameMin(), int(contentHeight));
drawLineContent(sequence->GetFrameMax(), int(contentHeight));
// selection
bool selected = selectedEntry && (*selectedEntry >= 0);
if (selected)
{
customHeight = 0;
for (int i = 0; i < *selectedEntry; i++)
customHeight += sequence->GetCustomHeight(i);
draw_list->AddRectFilled(ImVec2(contentMin.x, contentMin.y + ItemHeight * *selectedEntry + customHeight), ImVec2(contentMin.x + canvas_size.x, contentMin.y + ItemHeight * (*selectedEntry + 1) + customHeight), 0x801080FF, 1.f);
}
// slots
customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
int* start, * end;
unsigned int color;
sequence->Get(i, &start, &end, NULL, &color);
size_t localCustomHeight = sequence->GetCustomHeight(i);
ImVec2 pos = ImVec2(contentMin.x + legendWidth - firstFrameUsed * framePixelWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
ImVec2 slotP1(pos.x + *start * framePixelWidth, pos.y + 2);
ImVec2 slotP2(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2);
ImVec2 slotP3(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2 + localCustomHeight);
unsigned int slotColor = color | 0xFF000000;
unsigned int slotColorHalf = (color & 0xFFFFFF) | 0x40000000;
if (slotP1.x <= (canvas_size.x + contentMin.x) && slotP2.x >= (contentMin.x + legendWidth))
{
draw_list->AddRectFilled(slotP1, slotP3, slotColorHalf, 2);
draw_list->AddRectFilled(slotP1, slotP2, slotColor, 2);
}
if (ImRect(slotP1, slotP2).Contains(io.MousePos) && io.MouseDoubleClicked[0])
{
sequence->DoubleClick(i);
}
// Ensure grabbable handles
const float max_handle_width = slotP2.x - slotP1.x / 3.0f;
const float min_handle_width = ImMin(10.0f, max_handle_width);
const float handle_width = ImClamp(framePixelWidth / 2.0f, min_handle_width, max_handle_width);
ImRect rects[3] = { ImRect(slotP1, ImVec2(slotP1.x + handle_width, slotP2.y))
, ImRect(ImVec2(slotP2.x - handle_width, slotP1.y), slotP2)
, ImRect(slotP1, slotP2) };
const unsigned int quadColor[] = { 0xFFFFFFFF, 0xFFFFFFFF, slotColor + (selected ? 0 : 0x202020) };
if (movingEntry == -1 && (sequenceOptions & SEQUENCER_EDIT_STARTEND))// TODOFOCUS && backgroundRect.Contains(io.MousePos))
{
for (int j = 2; j >= 0; j--)
{
ImRect& rc = rects[j];
if (!rc.Contains(io.MousePos))
continue;
draw_list->AddRectFilled(rc.Min, rc.Max, quadColor[j], 2);
}
for (int j = 0; j < 3; j++)
{
ImRect& rc = rects[j];
if (!rc.Contains(io.MousePos))
continue;
if (!ImRect(childFramePos, childFramePos + childFrameSize).Contains(io.MousePos))
continue;
if (ImGui::IsMouseClicked(0) && !MovingScrollBar && !MovingCurrentFrame)
{
movingEntry = i;
movingPos = cx;
movingPart = j + 1;
sequence->BeginEdit(movingEntry);
break;
}
}
}
// custom draw
if (localCustomHeight > 0)
{
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + 1 + customHeight);
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(ItemHeight)),
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(localCustomHeight + ItemHeight)));
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(ItemHeight)), rp + ImVec2(canvas_size.x, float(localCustomHeight + ItemHeight)));
ImRect legendRect(rp + ImVec2(0.f, float(ItemHeight)), rp + ImVec2(float(legendWidth), float(localCustomHeight)));
ImRect legendClippingRect(canvas_pos + ImVec2(0.f, float(ItemHeight)), canvas_pos + ImVec2(float(legendWidth), float(localCustomHeight + ItemHeight)));
customDraws.push_back({ i, customRect, legendRect, clippingRect, legendClippingRect });
}
else
{
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + customHeight);
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(0.f)),
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(ItemHeight)));
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(0.f)), rp + ImVec2(canvas_size.x, float(ItemHeight)));
compactCustomDraws.push_back({ i, customRect, ImRect(), clippingRect, ImRect() });
}
customHeight += localCustomHeight;
}
// moving
if (/*backgroundRect.Contains(io.MousePos) && */movingEntry >= 0)
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
int diffFrame = int((cx - movingPos) / framePixelWidth);
if (std::abs(diffFrame) > 0)
{
int* start, * end;
sequence->Get(movingEntry, &start, &end, NULL, NULL);
if (selectedEntry)
*selectedEntry = movingEntry;
int& l = *start;
int& r = *end;
if (movingPart & 1)
l += diffFrame;
if (movingPart & 2)
r += diffFrame;
if (l < 0)
{
if (movingPart & 2)
r -= l;
l = 0;
}
if (movingPart & 1 && l > r)
l = r;
if (movingPart & 2 && r < l)
r = l;
movingPos += int(diffFrame * framePixelWidth);
}
if (!io.MouseDown[0])
{
// single select
if (!diffFrame && movingPart && selectedEntry)
{
*selectedEntry = movingEntry;
ret = true;
}
movingEntry = -1;
sequence->EndEdit();
}
}
// cursor
if (currentFrame && firstFrame && *currentFrame >= *firstFrame && *currentFrame <= sequence->GetFrameMax())
{
static const float cursorWidth = 8.f;
float cursorOffset = contentMin.x + legendWidth + (*currentFrame - firstFrameUsed) * framePixelWidth + framePixelWidth / 2 - cursorWidth * 0.5f;
draw_list->AddLine(ImVec2(cursorOffset, canvas_pos.y), ImVec2(cursorOffset, contentMax.y), 0xA02A2AFF, cursorWidth);
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", *currentFrame);
draw_list->AddText(ImVec2(cursorOffset + 10, canvas_pos.y + 2), 0xFF2A2AFF, tmps);
}
draw_list->PopClipRect();
draw_list->PopClipRect();
for (auto& customDraw : customDraws)
sequence->CustomDraw(customDraw.index, draw_list, customDraw.customRect, customDraw.legendRect, customDraw.clippingRect, customDraw.legendClippingRect);
for (auto& customDraw : compactCustomDraws)
sequence->CustomDrawCompact(customDraw.index, draw_list, customDraw.customRect, customDraw.clippingRect);
// copy paste
if (sequenceOptions & SEQUENCER_COPYPASTE)
{
ImRect rectCopy(ImVec2(contentMin.x + 100, canvas_pos.y + 2)
, ImVec2(contentMin.x + 100 + 30, canvas_pos.y + ItemHeight - 2));
bool inRectCopy = rectCopy.Contains(io.MousePos);
unsigned int copyColor = inRectCopy ? 0xFF1080FF : 0xFF000000;
draw_list->AddText(rectCopy.Min, copyColor, "Copy");
ImRect rectPaste(ImVec2(contentMin.x + 140, canvas_pos.y + 2)
, ImVec2(contentMin.x + 140 + 30, canvas_pos.y + ItemHeight - 2));
bool inRectPaste = rectPaste.Contains(io.MousePos);
unsigned int pasteColor = inRectPaste ? 0xFF1080FF : 0xFF000000;
draw_list->AddText(rectPaste.Min, pasteColor, "Paste");
if (inRectCopy && io.MouseReleased[0])
{
sequence->Copy();
}
if (inRectPaste && io.MouseReleased[0])
{
sequence->Paste();
}
}
//
ImGui::EndChild();
ImGui::PopStyleColor();
if (hasScrollBar)
{
ImGui::InvisibleButton("scrollBar", scrollBarSize);
ImVec2 scrollBarMin = ImGui::GetItemRectMin();
ImVec2 scrollBarMax = ImGui::GetItemRectMax();
// ratio = number of frames visible in control / number to total frames
float startFrameOffset = ((float)(firstFrameUsed - sequence->GetFrameMin()) / (float)frameCount) * (canvas_size.x - legendWidth);
ImVec2 scrollBarA(scrollBarMin.x + legendWidth, scrollBarMin.y - 2);
ImVec2 scrollBarB(scrollBarMin.x + canvas_size.x, scrollBarMax.y - 1);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
ImRect scrollBarRect(scrollBarA, scrollBarB);
bool inScrollBar = scrollBarRect.Contains(io.MousePos);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, 8);
ImVec2 scrollBarC(scrollBarMin.x + legendWidth + startFrameOffset, scrollBarMin.y);
ImVec2 scrollBarD(scrollBarMin.x + legendWidth + barWidthInPixels + startFrameOffset, scrollBarMax.y - 2);
draw_list->AddRectFilled(scrollBarC, scrollBarD, (inScrollBar || MovingScrollBar) ? 0xFF606060 : 0xFF505050, 6);
ImRect barHandleLeft(scrollBarC, ImVec2(scrollBarC.x + 14, scrollBarD.y));
ImRect barHandleRight(ImVec2(scrollBarD.x - 14, scrollBarC.y), scrollBarD);
bool onLeft = barHandleLeft.Contains(io.MousePos);
bool onRight = barHandleRight.Contains(io.MousePos);
static bool sizingRBar = false;
static bool sizingLBar = false;
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, (onLeft || sizingLBar) ? 0xFFAAAAAA : 0xFF666666, 6);
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, (onRight || sizingRBar) ? 0xFFAAAAAA : 0xFF666666, 6);
ImRect scrollBarThumb(scrollBarC, scrollBarD);
static const float MinBarWidth = 44.f;
if (sizingRBar)
{
if (!io.MouseDown[0])
{
sizingRBar = false;
}
else
{
float barNewWidth = ImMax(barWidthInPixels + io.MouseDelta.x, MinBarWidth);
float barRatio = barNewWidth / barWidthInPixels;
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
int newVisibleFrameCount = int((canvas_size.x - legendWidth) / framePixelWidthTarget);
int lastFrame = *firstFrame + newVisibleFrameCount;
if (lastFrame > sequence->GetFrameMax())
{
framePixelWidthTarget = framePixelWidth = (canvas_size.x - legendWidth) / float(sequence->GetFrameMax() - *firstFrame);
}
}
}
else if (sizingLBar)
{
if (!io.MouseDown[0])
{
sizingLBar = false;
}
else
{
if (fabsf(io.MouseDelta.x) > FLT_EPSILON)
{
float barNewWidth = ImMax(barWidthInPixels - io.MouseDelta.x, MinBarWidth);
float barRatio = barNewWidth / barWidthInPixels;
float previousFramePixelWidthTarget = framePixelWidthTarget;
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
int newVisibleFrameCount = int(visibleFrameCount / barRatio);
int newFirstFrame = *firstFrame + newVisibleFrameCount - visibleFrameCount;
newFirstFrame = ImClamp(newFirstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
if (newFirstFrame == *firstFrame)
{
framePixelWidth = framePixelWidthTarget = previousFramePixelWidthTarget;
}
else
{
*firstFrame = newFirstFrame;
}
}
}
}
else
{
if (MovingScrollBar)
{
if (!io.MouseDown[0])
{
MovingScrollBar = false;
}
else
{
float framesPerPixelInBar = barWidthInPixels / (float)visibleFrameCount;
*firstFrame = int((io.MousePos.x - panningViewSource.x) / framesPerPixelInBar) - panningViewFrame;
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
}
}
else
{
if (scrollBarThumb.Contains(io.MousePos) && ImGui::IsMouseClicked(0) && firstFrame && !MovingCurrentFrame && movingEntry == -1)
{
MovingScrollBar = true;
panningViewSource = io.MousePos;
panningViewFrame = -*firstFrame;
}
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0))
sizingRBar = true;
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0))
sizingLBar = true;
}
}
}
}
ImGui::EndGroup();
if (regionRect.Contains(io.MousePos))
{
bool overCustomDraw = false;
for (auto& custom : customDraws)
{
if (custom.customRect.Contains(io.MousePos))
{
overCustomDraw = true;
}
}
if (overCustomDraw)
{
}
else
{
#if 0
frameOverCursor = *firstFrame + (int)(visibleFrameCount * ((io.MousePos.x - (float)legendWidth - canvas_pos.x) / (canvas_size.x - legendWidth)));
//frameOverCursor = max(min(*firstFrame - visibleFrameCount / 2, frameCount - visibleFrameCount), 0);
/**firstFrame -= frameOverCursor;
*firstFrame *= framePixelWidthTarget / framePixelWidth;
*firstFrame += frameOverCursor;*/
if (io.MouseWheel < -FLT_EPSILON)
{
*firstFrame -= frameOverCursor;
*firstFrame = int(*firstFrame * 1.1f);
framePixelWidthTarget *= 0.9f;
*firstFrame += frameOverCursor;
}
if (io.MouseWheel > FLT_EPSILON)
{
*firstFrame -= frameOverCursor;
*firstFrame = int(*firstFrame * 0.9f);
framePixelWidthTarget *= 1.1f;
*firstFrame += frameOverCursor;
}
#endif
}
}
if (expanded)
{
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + 2, canvas_pos.y + 2), !*expanded))
*expanded = !*expanded;
}
if (delEntry != -1)
{
sequence->Del(delEntry);
if (selectedEntry && (*selectedEntry == delEntry || *selectedEntry >= sequence->GetItemCount()))
*selectedEntry = -1;
}
if (dupEntry != -1)
{
sequence->Duplicate(dupEntry);
}
return ret;
}
}

79
third_party/ImGuizmo/ImSequencer.h vendored Normal file
View File

@@ -0,0 +1,79 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#pragma once
#include <cstddef>
struct ImDrawList;
struct ImRect;
namespace ImSequencer
{
enum SEQUENCER_OPTIONS
{
SEQUENCER_EDIT_NONE = 0,
SEQUENCER_EDIT_STARTEND = 1 << 1,
SEQUENCER_CHANGE_FRAME = 1 << 3,
SEQUENCER_ADD = 1 << 4,
SEQUENCER_DEL = 1 << 5,
SEQUENCER_COPYPASTE = 1 << 6,
SEQUENCER_EDIT_ALL = SEQUENCER_EDIT_STARTEND | SEQUENCER_CHANGE_FRAME
};
struct SequenceInterface
{
bool focused = false;
virtual int GetFrameMin() const = 0;
virtual int GetFrameMax() const = 0;
virtual int GetItemCount() const = 0;
virtual void BeginEdit(int /*index*/) {}
virtual void EndEdit() {}
virtual int GetItemTypeCount() const { return 0; }
virtual const char* GetItemTypeName(int /*typeIndex*/) const { return ""; }
virtual const char* GetItemLabel(int /*index*/) const { return ""; }
virtual const char* GetCollapseFmt() const { return "%d Frames / %d entries"; }
virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) = 0;
virtual void Add(int /*type*/) {}
virtual void Del(int /*index*/) {}
virtual void Duplicate(int /*index*/) {}
virtual void Copy() {}
virtual void Paste() {}
virtual size_t GetCustomHeight(int /*index*/) { return 0; }
virtual void DoubleClick(int /*index*/) {}
virtual void CustomDraw(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*legendRect*/, const ImRect& /*clippingRect*/, const ImRect& /*legendClippingRect*/) {}
virtual void CustomDrawCompact(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*clippingRect*/) {}
virtual ~SequenceInterface() = default;
};
// return true if selection is made
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
}

245
third_party/ImGuizmo/ImZoomSlider.h vendored Normal file
View File

@@ -0,0 +1,245 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v1.92.5 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016-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.
//
#pragma once
namespace ImZoomSlider
{
typedef int ImGuiZoomSliderFlags;
enum ImGuiPopupFlags_
{
ImGuiZoomSliderFlags_None = 0,
ImGuiZoomSliderFlags_Vertical = 1,
ImGuiZoomSliderFlags_NoAnchors = 2,
ImGuiZoomSliderFlags_NoMiddleCarets = 4,
ImGuiZoomSliderFlags_NoWheel = 8,
};
template<typename T> bool ImZoomSlider(const T lower, const T higher, T& viewLower, T& viewHigher, float wheelRatio = 0.01f, ImGuiZoomSliderFlags flags = ImGuiZoomSliderFlags_None)
{
bool interacted = false;
ImGuiIO& io = ImGui::GetIO();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
static const float handleSize = 12;
static const float roundRadius = 3.f;
static const char* controlName = "ImZoomSlider";
static bool movingScrollBarSvg = false;
static bool sizingRBarSvg = false;
static bool sizingLBarSvg = false;
static ImGuiID editingId = (ImGuiID)-1;
static float scrollingSource = 0.f;
static float saveViewLower;
static float saveViewHigher;
const bool isVertical = flags & ImGuiZoomSliderFlags_Vertical;
const ImVec2 canvasPos = ImGui::GetCursorScreenPos();
const ImVec2 canvasSize = ImGui::GetContentRegionAvail();
const float canvasSizeLength = isVertical ? ImGui::GetItemRectSize().y : canvasSize.x;
const ImVec2 scrollBarSize = isVertical ? ImVec2(14.f, canvasSizeLength) : ImVec2(canvasSizeLength, 14.f);
ImGui::InvisibleButton(controlName, scrollBarSize);
const ImGuiID currentId = ImGui::GetID(controlName);
const bool usingEditingId = currentId == editingId;
const bool canUseControl = usingEditingId || editingId == -1;
const bool movingScrollBar = usingEditingId ? movingScrollBarSvg : false;
const bool sizingRBar = usingEditingId ? sizingRBarSvg : false;
const bool sizingLBar = usingEditingId ? sizingLBarSvg : false;
const int componentIndex = isVertical ? 1 : 0;
const ImVec2 scrollBarMin = ImGui::GetItemRectMin();
const ImVec2 scrollBarMax = ImGui::GetItemRectMax();
const ImVec2 scrollBarA = ImVec2(scrollBarMin.x, scrollBarMin.y) - (isVertical ? ImVec2(2,0) : ImVec2(0,2));
const ImVec2 scrollBarB = isVertical ? ImVec2(scrollBarMax.x - 1.f, scrollBarMin.y + canvasSizeLength) : ImVec2(scrollBarMin.x + canvasSizeLength, scrollBarMax.y - 1.f);
const float scrollStart = ((viewLower - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
const float scrollEnd = ((viewHigher - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
const float screenSize = scrollEnd - scrollStart;
const ImVec2 scrollTopLeft = isVertical ? ImVec2(scrollBarMin.x, scrollStart) : ImVec2(scrollStart, scrollBarMin.y);
const ImVec2 scrollBottomRight = isVertical ? ImVec2(scrollBarMax.x - 2.f, scrollEnd) : ImVec2(scrollEnd, scrollBarMax.y - 2.f);
const bool inScrollBar = canUseControl && ImRect(scrollTopLeft, scrollBottomRight).Contains(io.MousePos);
const ImRect scrollBarRect(scrollBarA, scrollBarB);
const float deltaScreen = io.MousePos[componentIndex] - scrollingSource;
const float deltaView = ((higher - lower) / canvasSizeLength) * deltaScreen;
const uint32_t barColor = ImGui::GetColorU32((inScrollBar || movingScrollBar) ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
const float middleCoord = (scrollStart + scrollEnd) * 0.5f;
const bool insideControl = canUseControl && ImRect(scrollBarMin, scrollBarMax).Contains(io.MousePos);
const bool hasAnchors = !(flags & ImGuiZoomSliderFlags_NoAnchors);
const float viewMinSize = ((3.f * handleSize) / canvasSizeLength) * (higher - lower);
const auto ClipView = [lower, higher, &viewLower, &viewHigher]() {
if (viewLower < lower)
{
const float deltaClip = lower - viewLower;
viewLower += deltaClip;
viewHigher += deltaClip;
}
if (viewHigher > higher)
{
const float deltaClip = viewHigher - higher;
viewLower -= deltaClip;
viewHigher -= deltaClip;
}
};
bool onLeft = false;
bool onRight = false;
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, roundRadius);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
draw_list->AddRectFilled(scrollTopLeft, scrollBottomRight, barColor, roundRadius);
if (!(flags & ImGuiZoomSliderFlags_NoMiddleCarets))
{
for (float i = 0.5f; i < 3.f; i += 1.f)
{
const float coordA = middleCoord - handleSize * 0.5f;
const float coordB = middleCoord + handleSize * 0.5f;
ImVec2 base = scrollBarMin;
base.x += scrollBarSize.x * 0.25f * i;
base.y += scrollBarSize.y * 0.25f * i;
if (isVertical)
{
draw_list->AddLine(ImVec2(base.x, coordA), ImVec2(base.x, coordB), ImGui::GetColorU32(ImGuiCol_SliderGrab));
}
else
{
draw_list->AddLine(ImVec2(coordA, base.y), ImVec2(coordB, base.y), ImGui::GetColorU32(ImGuiCol_SliderGrab));
}
}
}
// Mouse wheel
if (io.MouseClicked[0] && insideControl && !inScrollBar)
{
const float ratio = (io.MousePos[componentIndex] - scrollBarMin[componentIndex]) / (scrollBarMax[componentIndex] - scrollBarMin[componentIndex]);
const float size = (higher - lower);
const float halfViewSize = (viewHigher - viewLower) * 0.5f;
const float middle = ratio * size + lower;
viewLower = middle - halfViewSize;
viewHigher = middle + halfViewSize;
ClipView();
interacted = true;
}
if (!(flags & ImGuiZoomSliderFlags_NoWheel) && inScrollBar && fabsf(io.MouseWheel) > 0.f)
{
const float ratio = (io.MousePos[componentIndex] - scrollStart) / (scrollEnd - scrollStart);
const float amount = io.MouseWheel * wheelRatio * (viewHigher - viewLower);
viewLower -= ratio * amount;
viewHigher += (1.f - ratio) * amount;
ClipView();
interacted = true;
}
if (screenSize > handleSize * 2.f && hasAnchors)
{
const ImRect barHandleLeft(scrollTopLeft, isVertical ? ImVec2(scrollBottomRight.x, scrollTopLeft.y + handleSize) : ImVec2(scrollTopLeft.x + handleSize, scrollBottomRight.y));
const ImRect barHandleRight(isVertical ? ImVec2(scrollTopLeft.x, scrollBottomRight.y - handleSize) : ImVec2(scrollBottomRight.x - handleSize, scrollTopLeft.y), scrollBottomRight);
onLeft = barHandleLeft.Contains(io.MousePos);
onRight = barHandleRight.Contains(io.MousePos);
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, ImGui::GetColorU32((onLeft || sizingLBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, ImGui::GetColorU32((onRight || sizingRBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
}
if (sizingRBar)
{
if (!io.MouseDown[0])
{
sizingRBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewHigher = ImMin(saveViewHigher + deltaView, higher);
}
}
else if (sizingLBar)
{
if (!io.MouseDown[0])
{
sizingLBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewLower = ImMax(saveViewLower + deltaView, lower);
}
}
else
{
if (movingScrollBar)
{
if (!io.MouseDown[0])
{
movingScrollBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewLower = saveViewLower + deltaView;
viewHigher = saveViewHigher + deltaView;
ClipView();
}
}
else
{
if (inScrollBar && ImGui::IsMouseClicked(0))
{
movingScrollBarSvg = true;
scrollingSource = io.MousePos[componentIndex];
saveViewLower = viewLower;
saveViewHigher = viewHigher;
editingId = currentId;
}
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0) && hasAnchors)
{
sizingRBarSvg = true;
editingId = currentId;
}
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0) && hasAnchors)
{
sizingLBarSvg = true;
editingId = currentId;
}
}
}
// minimal size check
if ((viewHigher - viewLower) < viewMinSize)
{
const float middle = (viewLower + viewHigher) * 0.5f;
viewLower = middle - viewMinSize * 0.5f;
viewHigher = middle + viewMinSize * 0.5f;
ClipView();
}
return movingScrollBar || sizingRBar || sizingLBar || interacted;
}
} // namespace

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

21
third_party/ImGuizmo/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Cedric Guillemet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

19
third_party/ImGuizmo/Makefile vendored Normal file
View File

@@ -0,0 +1,19 @@
CXXFLAGS=-std=c++11
CPPFLAGS=-I. -Iexample
LIB_OBJS = ImGuizmo.o GraphEditor.o ImCurveEdit.o ImGradient.o ImSequencer.o
EXAMPLE_OBJS = example/imgui.o example/imgui_draw.o example/imgui_tables.o example/imgui_widgets.o example/main.o
EXAMPLE_NAME = example.exe
LDFLAGS=-mwindows -static-libgcc -static-libstdc++
LIBS=-limm32 -lopengl32 -lgdi32
$(EXAMPLE_NAME): $(LIB_OBJS) $(EXAMPLE_OBJS)
$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
example/main.o: CXXFLAGS := -std=c++17
clean:
$(RM) $(LIB_OBJS)
$(RM) $(EXAMPLE_OBJS)
$(RM) $(EXAMPLE_NAME)

192
third_party/ImGuizmo/README.md vendored Normal file
View File

@@ -0,0 +1,192 @@
# ImGuizmo
Latest stable tagged version is 1.83. Current master version is 1.84 WIP.
What started with the gizmo is now a collection of dear imgui widgets and more advanced controls.
## Guizmos
### ImViewGizmo
Manipulate view orientation with 1 single line of code
![Image of ImViewGizmo](http://i.imgur.com/7UVcyDd.gif)
### ImGuizmo
ImGuizmo is a small (.h and .cpp) library built ontop of Dear ImGui that allow you to manipulate(Rotate & translate at the moment) 4x4 float matrices. No other dependancies. Coded with Immediate Mode (IM) philosophy in mind.
Built against DearImgui 1.53WIP
![Image of Rotation](http://i.imgur.com/y4mcVoT.gif)
![Image of Translation](http://i.imgur.com/o8q8iHq.gif)
![Image of Bounds](http://i.imgur.com/3Ez5LBr.gif)
There is now a sample for Win32/OpenGL ! With a binary in bin directory.
![Image of Sample](https://i.imgur.com/nXlzyqD.png)
### ImSequencer
A WIP little sequencer used to edit frame start/end for different events in a timeline.
![Image of Rotation](http://i.imgur.com/BeyNwCn.png)
Check the sample for the documentation. More to come...
### Graph Editor
Nodes + connections. Custom draw inside nodes is possible with the delegate system in place.
![Image of GraphEditor](Images/nodeeditor.jpg)
### API doc
Call BeginFrame right after ImGui_XXXX_NewFrame();
```C++
void BeginFrame();
```
return true if mouse cursor is over any gizmo control (axis, plan or screen component)
```C++
bool IsOver();**
```
return true if mouse IsOver or if the gizmo is in moving state
```C++
bool IsUsing();**
```
enable/disable the gizmo. Stay in the state until next call to Enable. gizmo is rendered with gray half transparent color when disabled
```C++
void Enable(bool enable);**
```
helper functions for manualy editing translation/rotation/scale with an input float
translation, rotation and scale float points to 3 floats each
Angles are in degrees (more suitable for human editing)
example:
```C++
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
ImGui::InputFloat3("Tr", matrixTranslation, 3);
ImGui::InputFloat3("Rt", matrixRotation, 3);
ImGui::InputFloat3("Sc", matrixScale, 3);
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
```
These functions have some numerical stability issues for now. Use with caution.
```C++
void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale);
void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix);**
```
Render a cube with face color corresponding to face normal. Usefull for debug/test
```C++
void DrawCube(const float *view, const float *projection, float *matrix);**
```
Call it when you want a gizmo
Needs view and projection matrices.
Matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional. snap points to a float[3] for translation and to a single float for scale or rotation. Snap angle is in Euler Degrees.
```C++
enum OPERATION
{
TRANSLATE,
ROTATE,
SCALE
};
enum MODE
{
LOCAL,
WORLD
};
void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0, float *snap = 0);**
```
### ImGui Example
Code for :
![Image of dialog](http://i.imgur.com/GL5flN1.png)
```C++
void EditTransform(const Camera& camera, matrix_t& matrix)
{
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
if (ImGui::IsKeyPressed(90))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
if (ImGui::IsKeyPressed(69))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
if (ImGui::IsKeyPressed(82)) // r Key
mCurrentGizmoOperation = ImGuizmo::SCALE;
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
ImGui::SameLine();
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
ImGui::SameLine();
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
mCurrentGizmoOperation = ImGuizmo::SCALE;
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);
ImGui::InputFloat3("Tr", matrixTranslation, 3);
ImGui::InputFloat3("Rt", matrixRotation, 3);
ImGui::InputFloat3("Sc", matrixScale, 3);
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
{
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
mCurrentGizmoMode = ImGuizmo::LOCAL;
ImGui::SameLine();
if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
mCurrentGizmoMode = ImGuizmo::WORLD;
}
static bool useSnap(false);
if (ImGui::IsKeyPressed(83))
useSnap = !useSnap;
ImGui::Checkbox("", &useSnap);
ImGui::SameLine();
vec_t snap;
switch (mCurrentGizmoOperation)
{
case ImGuizmo::TRANSLATE:
snap = config.mSnapTranslation;
ImGui::InputFloat3("Snap", &snap.x);
break;
case ImGuizmo::ROTATE:
snap = config.mSnapRotation;
ImGui::InputFloat("Angle Snap", &snap.x);
break;
case ImGuizmo::SCALE:
snap = config.mSnapScale;
ImGui::InputFloat("Scale Snap", &snap.x);
break;
}
ImGuiIO& io = ImGui::GetIO();
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);
}
```
## Install
ImGuizmo can be installed via [vcpkg](https://github.com/microsoft/vcpkg) and used cmake
```bash
vcpkg install imguizmo
```
See the [vcpkg example](/vcpkg-example) for more details
## License
ImGuizmo is licensed under the MIT License, see [LICENSE](/LICENSE) for more information.