gizmo test

This commit is contained in:
sshumakov3
2020-11-19 18:23:43 +03:00
parent 94fbe61d3b
commit 65eb617e1a
26 changed files with 5684 additions and 183 deletions

View File

@@ -191,6 +191,7 @@ endif()
add_subdirectory (src/external/qt-color-widgets)
add_subdirectory (src/external/framelesshelper)
add_subdirectory (src/external/qtimgui)
# Add the found include directories to our include list.
include_directories (SYSTEM "${CMAKE_SOURCE_DIR}/include/")
@@ -224,6 +225,7 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/external/PNG2BLP/libpng" )
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/external/PNG2BLP/libtxc_dxtn" )
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/external/PNG2BLP/pngpp" )
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/external/PNG2BLP/zlib" )
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/external/imguizmo" )
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
COLLECT_FILES(false noggit_root_sources src/noggit .cpp)
@@ -232,6 +234,7 @@ COLLECT_FILES(false math_sources src/math .cpp)
COLLECT_FILES(false opengl_sources src/opengl .cpp)
COLLECT_FILES(true red_sources src/noggit/Red .cpp)
COLLECT_FILES(true png_blp_sources src/external/PNG2BLP ".c;.cpp;")
COLLECT_FILES(false imguizmo_sources src/external/imguizmo ".c;.cpp;")
set ( util_sources
src/util/exception_to_string.cpp
)
@@ -242,6 +245,7 @@ COLLECT_FILES(false opengl_headers src/opengl ".h;.hpp")
COLLECT_FILES(false shaders src/glsl .glsl)
COLLECT_FILES(true red_headers src/noggit/Red ".hpp;.inl")
COLLECT_FILES(true png_blp_headers src/external/PNG2BLP ".h;.hpp;")
COLLECT_FILES(false imguizmo_headers src/external/imguizmo ".h;.hpp;")
IF(WIN32)
set ( os_sources
@@ -274,6 +278,7 @@ source_group("util" FILES ${util_sources})
source_group("glsl" FILES ${shaders})
source_group("noggit/Red" FILES ${red_headers} ${red_sources})
source_group("png_blp" FILES ${png_blp_headers} ${png_blp_sources})
source_group("imguizmo" FILES ${imguizmo_headers} ${imguizmo_sources})
COLLECT_FILES(false resource_files resources .qrc)
qt5_add_resources (compiled_resource_files ${resource_files})
@@ -293,6 +298,7 @@ ADD_EXECUTABLE ( noggit
${util_sources}
${red_sources}
${png_blp_sources}
${imguizmo_sources}
${noggit_root_headers}
${noggit_ui_headers}
${opengl_headers}
@@ -304,6 +310,7 @@ ADD_EXECUTABLE ( noggit
${ResFiles}
${moced}
${red_headers}
${imguizmo_headers}
${compiled_resource_files}
${compiled_ui_files}
${shaders}
@@ -321,6 +328,7 @@ TARGET_LINK_LIBRARIES (noggit
Qt5::OpenGLExtensions
ColorWidgets-qt5
FramelessHelper
qt_imgui_widgets
)
set (_noggit_revision_output_dir "${CMAKE_BINARY_DIR}/revision_output")

429
src/external/imguizmo/ImCurveEdit.cpp vendored Normal file
View File

@@ -0,0 +1,429 @@
#include "ImCurveEdit.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <stdint.h>
#include <set>
#include <vector>
#if !defined(_MSC_VER)
#define _malloca(x) alloca(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::BeginChildFrame(id, size);
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* pts = delegate.GetPoints(sel.curveIndex);
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::EndChildFrame();
ImGui::PopStyleVar();
ImGui::PopStyleColor(1);
if (selectedPoints)
{
selectedPoints->resize(int(selection.size()));
int index = 0;
for (auto& point : selection)
(*selectedPoints)[index++] = point;
}
return ret;
}
}

55
src/external/imguizmo/ImCurveEdit.h vendored Normal file
View File

@@ -0,0 +1,55 @@
#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() {}
};
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect = NULL, ImVector<EditPoint>* selectedPoints = NULL);
}

94
src/external/imguizmo/ImGradient.cpp vendored Normal file
View File

@@ -0,0 +1,94 @@
#include "ImGradient.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <stdint.h>
#include <set>
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)
{
int ret = 0;
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::BeginChildFrame(137, size);
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::EndChildFrame();
ImGui::PopStyleVar();
selection = currentSelection;
return ret;
}
}

19
src/external/imguizmo/ImGradient.h vendored Normal file
View File

@@ -0,0 +1,19 @@
#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;
};
bool Edit(Delegate& delegate, const ImVec2& size, int& selection);
}

2593
src/external/imguizmo/ImGuizmo.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

187
src/external/imguizmo/ImGuizmo.h vendored Normal file
View File

@@ -0,0 +1,187 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.61 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2016 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -------------------------------------------------------------------------------------------
// History :
// 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
namespace ImGuizmo
{
// 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();
// 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();
// 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,
ROTATE,
SCALE,
BOUNDS,
};
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);
IMGUI_API void SetID(int id);
// return true if the cursor is over the operation's gizmo
IMGUI_API bool IsOver(OPERATION op);
IMGUI_API void SetGizmoSizeClipSpace(float value);
};

672
src/external/imguizmo/ImSequencer.cpp vendored Normal file
View File

@@ -0,0 +1,672 @@
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#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 delRect(pos, ImVec2(pos.x + 16, pos.y + 16));
bool overDel = delRect.Contains(io.MousePos);
int delColor = overDel ? 0xFFAAAAAA : 0x50000000;
float midy = pos.y + 16 / 2 - 0.5f;
float midx = pos.x + 16 / 2 - 0.5f;
draw_list->AddRect(delRect.Min, delRect.Max, delColor, 4);
draw_list->AddLine(ImVec2(delRect.Min.x + 3, midy), ImVec2(delRect.Max.x - 3, midy), delColor, 2);
if (add)
draw_list->AddLine(ImVec2(midx, delRect.Min.y + 3), ImVec2(midx, delRect.Max.y - 3), delColor, 2);
return overDel;
}
static int min(int a, int b) { return (a < b) ? a : b; }
static int max(int a, int b) { return (a > b) ? a : b; }
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
int frameOverCursor = 0;
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];
sprintf(tmps, "%d Frames / %d entries", 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::BeginChildFrame(889, childFrameSize);
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) && io.MouseReleased[0])
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];
sprintf(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);
// 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)
{
bool overDel = SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight + 2 - 10, tpos.y + 2), false);
if (overDel && io.MouseReleased[0])
delEntry = i;
bool overDup = SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight - ItemHeight + 2 - 10, tpos.y + 2), true);
if (overDup && io.MouseReleased[0])
dupEntry = i;
}
customHeight += sequence->GetCustomHeight(i);
}
// clipping rect so items bars are not visible in the legend on the left when scrolled
//
// 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);
// 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);
}
ImRect rects[3] = { ImRect(slotP1, ImVec2(slotP1.x + framePixelWidth / 2, slotP2.y))
, ImRect(ImVec2(slotP2.x - framePixelWidth / 2, 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)
{
ImGui::CaptureMouseFromApp();
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];
sprintf(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::EndChildFrame();
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);
float handleRadius = (scrollBarMax.y - scrollBarMin.y) / 2;
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)
{
bool overExpanded = SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + 2, canvas_pos.y + 2), !*expanded);
if (overExpanded && io.MouseReleased[0])
*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;
}
}

51
src/external/imguizmo/ImSequencer.h vendored Normal file
View File

@@ -0,0 +1,51 @@
#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 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*/) {}
};
// return true if selection is made
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
}

245
src/external/imguizmo/ImZoomSlider.h vendored Normal file
View File

@@ -0,0 +1,245 @@
// https://github.com/CedricGuillemet/ImGuizmo
// ImZoomSlider v 1.0
//
// The MIT License(MIT)
//
// Copyright(c) 2020 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 = -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 = -1;
}
else
{
viewHigher = ImMin(saveViewHigher + deltaView, higher);
}
}
else if (sizingLBar)
{
if (!io.MouseDown[0])
{
sizingLBarSvg = false;
editingId = -1;
}
else
{
viewLower = ImMax(saveViewLower + deltaView, lower);
}
}
else
{
if (movingScrollBar)
{
if (!io.MouseDown[0])
{
movingScrollBarSvg = false;
editingId = -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

21
src/external/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.

167
src/external/imguizmo/README.md vendored Normal file
View File

@@ -0,0 +1,167 @@
### ImViewGizmo
Manipulate view orientation with 1 single line of code
![Image of ImViewGizmo](http://i.imgur.com/7UVcyDd.gif)
### ImGuizmo
ImGizmo 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...
### 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);
}
```
### License
ImGuizmo is licensed under the MIT License, see LICENSE for more information.

63
src/external/qtimgui/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,63 @@
cmake_minimum_required (VERSION 3.8.1)
project(qtimgui)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Core Quick Gui Widgets Svg REQUIRED)
# imgui library: imgui is build by default, but you can
# provide your own version by setting QTIMGUI_BUILD_IMGUI to OFF
option(QTIMGUI_BUILD_IMGUI "Use imgui provided as qtimgui submodule" ON)
if (QTIMGUI_BUILD_IMGUI)
add_library(imgui
STATIC
imgui/imconfig.h
imgui/imgui_demo.cpp
imgui/imgui_draw.cpp
imgui/imgui_internal.h
imgui/imgui_widgets.cpp
imgui/imgui.cpp
)
target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
endif(QTIMGUI_BUILD_IMGUI)
set(
qt_imgui_sources
ImGuiRenderer.h
ImGuiRenderer.cpp
QtImGui.h
QtImGui.cpp
)
# qt_imgui_quick: library with a qt renderer for Qml / QtQuick applications
add_library(qt_imgui_quick STATIC ${qt_imgui_sources})
target_include_directories(qt_imgui_quick PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
qt_imgui_quick
PUBLIC
imgui
Qt5::Core Qt5::Quick Qt5::Svg
)
if (ANDROID)
target_link_libraries(qt_imgui_quick PUBLIC log dl GLESv2 z)
endif()
# qt_imgui_widget: library with a qt renderer for classic Qt Widget applications
add_library(qt_imgui_widgets STATIC ${qt_imgui_sources})
target_include_directories(qt_imgui_widgets PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
qt_imgui_widgets
PUBLIC
imgui
Qt5::Core Qt5::Widgets Qt5::Svg
)
if (ANDROID)
target_link_libraries(qt_imgui_widgets PUBLIC log dl GLESv2 z)
endif()
target_compile_definitions(qt_imgui_widgets PUBLIC QT_WIDGETS_LIB)
# Demo with Qt quick
add_subdirectory(demo-window)
# Demo with classic widgets
add_subdirectory(demo-widget)

439
src/external/qtimgui/ImGuiRenderer.cpp vendored Normal file
View File

@@ -0,0 +1,439 @@
#include "ImGuiRenderer.h"
#include <QDateTime>
#include <QGuiApplication>
#include <QMouseEvent>
#include <QClipboard>
#include <QCursor>
#include <QDebug>
#include <unordered_map>
#ifdef ANDROID
#define GL_VERTEX_ARRAY_BINDING 0x85B5 // Missing in android as of May 2020
#define USE_GLSL_ES
#endif
#ifdef USE_GLSL_ES
#define IMGUIRENDERER_GLSL_VERSION "#version 300 es\n"
#else
#define IMGUIRENDERER_GLSL_VERSION "#version 330\n"
#endif
namespace QtImGui {
namespace {
QHash<int, ImGuiKey> keyMap = {
{ Qt::Key_Tab, ImGuiKey_Tab },
{ Qt::Key_Left, ImGuiKey_LeftArrow },
{ Qt::Key_Right, ImGuiKey_RightArrow },
{ Qt::Key_Up, ImGuiKey_UpArrow },
{ Qt::Key_Down, ImGuiKey_DownArrow },
{ Qt::Key_PageUp, ImGuiKey_PageUp },
{ Qt::Key_PageDown, ImGuiKey_PageDown },
{ Qt::Key_Home, ImGuiKey_Home },
{ Qt::Key_End, ImGuiKey_End },
{ Qt::Key_Delete, ImGuiKey_Delete },
{ Qt::Key_Backspace, ImGuiKey_Backspace },
{ Qt::Key_Enter, ImGuiKey_Enter },
{ Qt::Key_Return, ImGuiKey_Enter },
{ Qt::Key_Escape, ImGuiKey_Escape },
{ Qt::Key_A, ImGuiKey_A },
{ Qt::Key_C, ImGuiKey_C },
{ Qt::Key_V, ImGuiKey_V },
{ Qt::Key_X, ImGuiKey_X },
{ Qt::Key_Y, ImGuiKey_Y },
{ Qt::Key_Z, ImGuiKey_Z },
};
QByteArray g_currentClipboardText;
}
void ImGuiRenderer::initialize(WindowWrapper *window, ImGuiContext* context) {
m_window.reset(window);
initializeOpenGLFunctions();
_context = context;
ImGuiIO &io = ImGui::GetIO();
for (ImGuiKey key : keyMap.values()) {
io.KeyMap[key] = key;
}
io.RenderDrawListsFn = [](ImDrawData *drawData) {
instance(ImGui::GetCurrentContext())->renderDrawList(drawData);
};
io.SetClipboardTextFn = [](void *user_data, const char *text) {
Q_UNUSED(user_data);
QGuiApplication::clipboard()->setText(text);
};
io.GetClipboardTextFn = [](void *user_data) {
Q_UNUSED(user_data);
g_currentClipboardText = QGuiApplication::clipboard()->text().toUtf8();
return (const char *)g_currentClipboardText.data();
};
window->installEventFilter(this);
}
void ImGuiRenderer::renderDrawList(ImDrawData *draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
ImGuiIO& io = ImGui::GetIO();
int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width == 0 || fb_height == 0)
return;
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Backup GL state
GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
GLint last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, &last_blend_src_rgb);
GLint last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, &last_blend_dst_rgb);
GLint last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, &last_blend_src_alpha);
GLint last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, &last_blend_dst_alpha);
GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb);
GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
// Setup viewport, orthographic projection matrix
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
const float ortho_projection[4][4] =
{
{ 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{-1.0f, 1.0f, 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
glBindVertexArray(g_VaoHandle);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawIdx* idx_buffer_offset = 0;
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
glBindTexture(GL_TEXTURE_2D, (GLuint)(size_t)pcmd->TextureId);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
}
idx_buffer_offset += pcmd->ElemCount;
}
}
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
glActiveTexture(last_active_texture);
glBindVertexArray(last_vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
bool ImGuiRenderer::createFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (void *)(size_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
bool ImGuiRenderer::createDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer, last_vertex_array;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
const GLchar *vertex_shader =
IMGUIRENDERER_GLSL_VERSION
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* fragment_shader =
IMGUIRENDERER_GLSL_VERSION
"precision mediump float;"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
"}\n";
g_ShaderHandle = glCreateProgram();
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_VertHandle, 1, &vertex_shader, 0);
glShaderSource(g_FragHandle, 1, &fragment_shader, 0);
glCompileShader(g_VertHandle);
glCompileShader(g_FragHandle);
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
glGenVertexArrays(1, &g_VaoHandle);
glBindVertexArray(g_VaoHandle);
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glEnableVertexAttribArray(g_AttribLocationPosition);
glEnableVertexAttribArray(g_AttribLocationUV);
glEnableVertexAttribArray(g_AttribLocationColor);
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col));
#undef OFFSETOF
createFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBindVertexArray(last_vertex_array);
return true;
}
void ImGuiRenderer::newFrame()
{
ImGui::SetCurrentContext(_context);
if (!g_FontTexture)
createDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
io.DisplaySize = ImVec2(m_window->size().width(), m_window->size().height());
io.DisplayFramebufferScale = ImVec2(m_window->devicePixelRatio(), m_window->devicePixelRatio());
// Setup time step
double current_time = QDateTime::currentMSecsSinceEpoch() / double(1000);
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
g_Time = current_time;
// Setup inputs
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
if (m_window->isActive())
{
auto pos = m_window->mapFromGlobal(QCursor::pos());
io.MousePos = ImVec2(pos.x(), pos.y()); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.)
}
else
{
io.MousePos = ImVec2(-1,-1);
}
for (int i = 0; i < 3; i++)
{
io.MouseDown[i] = g_MousePressed[i];
}
io.MouseWheelH = g_MouseWheelH;
io.MouseWheel = g_MouseWheel;
g_MouseWheelH = 0;
g_MouseWheel = 0;
// Hide OS mouse cursor if ImGui is drawing it
// glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
// Start the frame
ImGui::NewFrame();
}
void ImGuiRenderer::onMousePressedChange(QMouseEvent *event)
{
g_MousePressed[0] = event->buttons() & Qt::LeftButton;
g_MousePressed[1] = event->buttons() & Qt::RightButton;
g_MousePressed[2] = event->buttons() & Qt::MiddleButton;
}
void ImGuiRenderer::onWheel(QWheelEvent *event)
{
// Handle horizontal component
if(event->pixelDelta().x() != 0)
{
g_MouseWheelH += event->pixelDelta().x() / (ImGui::GetTextLineHeight());
} else {
// Magic number of 120 comes from Qt doc on QWheelEvent::pixelDelta()
g_MouseWheelH += event->angleDelta().x() / 120;
}
// Handle vertical component
if(event->pixelDelta().y() != 0)
{
// 5 lines per unit
g_MouseWheel += event->pixelDelta().y() / (5.0 * ImGui::GetTextLineHeight());
} else {
// Magic number of 120 comes from Qt doc on QWheelEvent::pixelDelta()
g_MouseWheel += event->angleDelta().y() / 120;
}
}
void ImGuiRenderer::onKeyPressRelease(QKeyEvent *event)
{
ImGuiIO& io = ImGui::GetIO();
if (keyMap.contains(event->key())) {
io.KeysDown[keyMap[event->key()]] = event->type() == QEvent::KeyPress;
}
if (event->type() == QEvent::KeyPress) {
QString text = event->text();
if (text.size() == 1) {
io.AddInputCharacter(text.at(0).unicode());
}
}
#ifdef Q_OS_MAC
io.KeyCtrl = event->modifiers() & Qt::MetaModifier;
io.KeyShift = event->modifiers() & Qt::ShiftModifier;
io.KeyAlt = event->modifiers() & Qt::AltModifier;
io.KeySuper = event->modifiers() & Qt::ControlModifier; // Comamnd key
#else
io.KeyCtrl = event->modifiers() & Qt::ControlModifier;
io.KeyShift = event->modifiers() & Qt::ShiftModifier;
io.KeyAlt = event->modifiers() & Qt::AltModifier;
io.KeySuper = event->modifiers() & Qt::MetaModifier;
#endif
}
bool ImGuiRenderer::eventFilter(QObject *watched, QEvent *event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
this->onMousePressedChange(static_cast<QMouseEvent *>(event));
break;
case QEvent::Wheel:
this->onWheel(static_cast<QWheelEvent *>(event));
break;
case QEvent::KeyPress:
case QEvent::KeyRelease:
this->onKeyPressRelease(static_cast<QKeyEvent *>(event));
break;
default:
break;
}
return QObject::eventFilter(watched, event);
}
ImGuiRenderer* ImGuiRenderer::instance(ImGuiContext* context) {
auto it = QtImGui::instances.find(context);
ImGuiRenderer* instance = nullptr;
if (it == QtImGui::instances.end())
{
instance = new ImGuiRenderer();
QtImGui::instances[context] = instance;
}
else
{
instance = QtImGui::instances[context];
}
return instance;
}
ImGuiRenderer* ImGuiRenderer::instance() {
ImGuiContext* context = ImGui::GetCurrentContext();
auto it = QtImGui::instances.find(context);
ImGuiRenderer* instance = nullptr;
if (it == QtImGui::instances.end())
{
throw std::logic_error("Context was not created");
}
else
{
instance = instances[context];
}
return instance;
}
}

64
src/external/qtimgui/ImGuiRenderer.h vendored Normal file
View File

@@ -0,0 +1,64 @@
#pragma once
#include <QOpenGLExtraFunctions>
#include <QObject>
#include <QPoint>
#include <imgui.h>
#include <memory>
#include <unordered_map>
class QMouseEvent;
class QWheelEvent;
class QKeyEvent;
namespace QtImGui {
class WindowWrapper {
public:
virtual ~WindowWrapper() {}
virtual void installEventFilter(QObject *object) = 0;
virtual QSize size() const = 0;
virtual qreal devicePixelRatio() const = 0;
virtual bool isActive() const = 0;
virtual QPoint mapFromGlobal(const QPoint &p) const = 0;
};
class ImGuiRenderer : public QObject, QOpenGLExtraFunctions {
Q_OBJECT
public:
void initialize(WindowWrapper *window, ImGuiContext* context);
void newFrame();
bool eventFilter(QObject *watched, QEvent *event);
static ImGuiRenderer *instance();
static ImGuiRenderer *instance(ImGuiContext* context);
private:
ImGuiRenderer() {}
void onMousePressedChange(QMouseEvent *event);
void onWheel(QWheelEvent *event);
void onKeyPressRelease(QKeyEvent *event);
void renderDrawList(ImDrawData *draw_data);
bool createFontsTexture();
bool createDeviceObjects();
std::unique_ptr<WindowWrapper> m_window;
double g_Time = 0.0f;
bool g_MousePressed[3] = { false, false, false };
float g_MouseWheel;
float g_MouseWheelH;
GLuint g_FontTexture = 0;
int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0;
ImGuiContext* _context;
};
static std::unordered_map<ImGuiContext*, ImGuiRenderer*> instances;
}

85
src/external/qtimgui/QtImGui.cpp vendored Normal file
View File

@@ -0,0 +1,85 @@
#include "QtImGui.h"
#include "ImGuiRenderer.h"
#include <QWindow>
#ifdef QT_WIDGETS_LIB
#include <QWidget>
#endif
namespace QtImGui {
#ifdef QT_WIDGETS_LIB
namespace {
class QWidgetWindowWrapper : public WindowWrapper {
public:
QWidgetWindowWrapper(QWidget *w) : w(w) {}
void installEventFilter(QObject *object) override {
return w->installEventFilter(object);
}
QSize size() const override {
return w->size();
}
qreal devicePixelRatio() const override {
return w->devicePixelRatioF();
}
bool isActive() const override {
return w->isActiveWindow();
}
QPoint mapFromGlobal(const QPoint &p) const override {
return w->mapFromGlobal(p);
}
private:
QWidget *w;
};
}
ImGuiContext* initialize(QWidget *window) {
ImGuiContext* context = ImGui::CreateContext();
ImGui::SetCurrentContext(context);
ImGuiRenderer::instance(context)->initialize(new QWidgetWindowWrapper(window), context);
return context;
}
#endif
namespace {
class QWindowWindowWrapper : public WindowWrapper {
public:
QWindowWindowWrapper(QWindow *w) : w(w) {}
void installEventFilter(QObject *object) override {
return w->installEventFilter(object);
}
QSize size() const override {
return w->size();
}
qreal devicePixelRatio() const override {
return w->devicePixelRatio();
}
bool isActive() const override {
return w->isActive();
}
QPoint mapFromGlobal(const QPoint &p) const override {
return w->mapFromGlobal(p);
}
private:
QWindow *w;
};
}
ImGuiContext* initialize(QWindow *window) {
ImGuiContext* context = ImGui::CreateContext();
ImGuiRenderer::instance(context)->initialize(new QWindowWindowWrapper(window), context);
return context;
}
void newFrame() {
ImGuiRenderer::instance()->newFrame();
}
}

17
src/external/qtimgui/QtImGui.h vendored Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <imgui.h>
class QWidget;
class QWindow;
namespace QtImGui {
#ifdef QT_WIDGETS_LIB
ImGuiContext* initialize(QWidget *window);
#endif
ImGuiContext* initialize(QWindow *window);
void newFrame();
}

View File

@@ -4,6 +4,8 @@
#include <noggit/Selection.h>
#include <noggit/tool_enums.hpp>
#include <noggit/ContextObject.hpp>
#include <external/qtimgui/QtImGui.h>
#include <external/qtimgui/imgui/imgui.h>
#include <vector>
#include <cmath>
@@ -38,6 +40,8 @@ void ModelViewer::initializeGL()
gl.viewport(0.0f, 0.0f, width(), height());
gl.clearColor (0.5f, 0.5f, 0.5f, 1.0f);
emit resized();
_imgui_context = QtImGui::initialize(this);
}
void ModelViewer::paintGL()
@@ -54,6 +58,15 @@ void ModelViewer::paintGL()
_last_update = now;
draw();
ImGui::SetCurrentContext(_imgui_context);
QtImGui::newFrame();
ImGui::Text("Test");
ImGui::Render();
}
void ModelViewer::resizeGL(int w, int h)
@@ -119,12 +132,14 @@ void ModelViewer::mouseMoveEvent(QMouseEvent* event)
void ModelViewer::mousePressEvent(QMouseEvent* event)
{
look = true;
if (event->button() == Qt::RightButton)
look = true;
}
void ModelViewer::mouseReleaseEvent(QMouseEvent* event)
{
look = false;
if (event->button() == Qt::RightButton)
look = false;
}
void ModelViewer::wheelEvent(QWheelEvent* event)

View File

@@ -21,6 +21,7 @@
#include <noggit/WMO.h>
#include <noggit/Model.h>
#include <noggit/Red/PreviewRenderer/PreviewRenderer.hpp>
#include <external/qtimgui/QtImGui.h>
namespace noggit
@@ -76,6 +77,8 @@ namespace noggit
void keyPressEvent(QKeyEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
ImGuiContext* _imgui_context;
};
}
}

View File

@@ -74,7 +74,7 @@ MapCreationWizard::MapCreationWizard(QWidget* parent) : noggit::ui::widget(paren
std::string name = i->getLocalizedString(MapDB::Name);
int area_type = i->getUInt(MapDB::AreaType);
if (area_type < 0 ||area_type > 4 || !World::IsEditableWorld(map_id))
if (area_type < 0 || area_type > 4 || !World::IsEditableWorld(map_id))
continue;
_corpse_map_id->addItem(QString::number(map_id) + " - " + QString::fromUtf8 (name.c_str()));

View File

@@ -1,12 +1,18 @@
#include "ModelView.hpp"
#include <math/projection.hpp>
#include <external/qtimgui/imgui/imgui.h>
#include <external/imguizmo/ImGuizmo.h>
#include <QMatrix4x4>
#include <QVector3D>
using namespace noggit::Red::PresetEditor;
ModelViewer::ModelViewer(QWidget *parent)
: AssetBrowser::ModelViewer(parent, noggit::NoggitRenderContext::PRESET_EDITOR)
, _world(std::make_unique<World> ("azeroth", 0, noggit::NoggitRenderContext::PRESET_EDITOR))
, _world(nullptr)
, _world_camera(_camera.position, _camera.yaw(), _camera.pitch())
{
}
void ModelViewer::paintGL()
@@ -24,50 +30,187 @@ void ModelViewer::paintGL()
MinimapRenderSettings _settings_unused;
std::map<int, misc::random_color> area_id_colors;
_world->draw(model_view().transposed()
, projection().transposed()
, math::vector_3d(0.f, 0.f, 0.f)
, 0.f
, math::vector_4d(1.f, 1.f, 1.f, 1.f)
, CursorType::CIRCLE
, 0.f
, false
, false
, 0.f
, math::vector_3d(0.f, 0.f, 0.f)
, 0.f
, 0.f
, false
, false
, false
, false
, false
, editing_mode::ground
, math::vector_3d(0.f, 0.f, 0.f)
, true
, false
, false
, false
, true
, true
, true
, true
, true
, true
, false
, false
, false
, &_settings_unused
, area_id_colors
, false
, eTerrainType::eTerrainType_Flat
, 0
, display_mode::in_3D
if (_world)
{
_world->draw(world_model_view().transposed()
, world_projection().transposed()
, math::vector_3d(0.f, 0.f, 0.f)
, 0.f
, math::vector_4d(1.f, 1.f, 1.f, 1.f)
, CursorType::CIRCLE
, 0.f
, false
, false
, 0.f
, math::vector_3d(0.f, 0.f, 0.f)
, 0.f
, 0.f
, false
, false
, false
, false
, false
, editing_mode::ground
, _world_camera.position
, true
, false
, false
, false
, true
, true
, true
, true
, true
, true
, false
, false
, false
, &_settings_unused
, area_id_colors
, false
, eTerrainType::eTerrainType_Flat
, 0
, display_mode::in_3D
);
);
}
// Sorting issues may naturally occur here due to draw order. But we can't avoid them if we want world as an underlay.
// It is just a preview after all.
draw();
ImGui::SetCurrentContext(_imgui_context);
QtImGui::newFrame();
ImGuizmo::SetDrawlist();
ImGuizmo::SetOrthographic(false);
ImGuizmo::BeginFrame();
ImGuiIO& io = ImGui::GetIO();
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
auto obj_mat = _wmo_instances[0].transform_matrix().transposed();
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
ImGuizmo::DecomposeMatrixToComponents(obj_mat, matrixTranslation, matrixRotation, matrixScale);
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, obj_mat);
auto delta_mat = math::matrix_4x4(math::matrix_4x4::unit).transposed();
ImGuizmo::Manipulate(static_cast<float*>(model_view().transposed()),
static_cast<float*>(projection().transposed()),
ImGuizmo::TRANSLATE,
ImGuizmo::WORLD,
obj_mat,
delta_mat,
NULL);
std::string test;
for (int i = 0; i < 16; ++i)
{
test += std::to_string(static_cast<float*>(delta_mat)[i]) + " ";
}
QMatrix4x4 new_mat (static_cast<float*>(delta_mat));
QVector3D pos = {_wmo_instances[0].pos.x, _wmo_instances[0].pos.y, _wmo_instances[0].pos.z};
QVector3D transform = pos * new_mat;
_wmo_instances[0].pos = {transform.x(), transform.y(), transform.z()};
_wmo_instances[0].recalcExtents();
test += "\n" + std::to_string(_wmo_instances[0].pos.x) + " "
+ std::to_string(_wmo_instances[0].pos.y)
+ " " + std::to_string(_wmo_instances[0].pos.z);
ImGui::Text(test.c_str());
ImGui::Render();
}
void ModelViewer::loadWorldUnderlay(const std::string& internal_name, int map_id)
{
opengl::context::scoped_setter const _ (::gl, context());
makeCurrent();
if (map_id < 0)
{
_world = nullptr;
}
else
{
_world = std::make_unique<World> (internal_name, map_id,
noggit::NoggitRenderContext::PRESET_EDITOR);
}
}
math::matrix_4x4 ModelViewer::world_model_view() const
{
return _world_camera.look_at_matrix();
}
math::matrix_4x4 ModelViewer::world_projection() const
{
float far_z = _settings->value("farZ", 2048).toFloat();
return math::perspective(_world_camera.fov(), aspect_ratio(), 0.1f, far_z);
}
void ModelViewer::tick(float dt)
{
if (_world)
{
_world->mapIndex.enterTile (tile_index (_world_camera.position));
_world->mapIndex.unloadTiles (tile_index (_world_camera.position));
}
AssetBrowser::ModelViewer::tick(dt);
if (turn)
{
_world_camera.add_to_yaw(math::degrees(turn));
}
if (lookat)
{
_world_camera.add_to_pitch(math::degrees(lookat));
}
if (moving)
{
_world_camera.move_forward(moving, dt);
}
if (strafing)
{
_world_camera.move_horizontal(strafing, dt);
}
if (updown)
{
_world_camera.move_vertical(updown, dt);
}
}
void ModelViewer::mouseMoveEvent(QMouseEvent *event)
{
QLineF const relative_movement (_last_mouse_pos, event->pos());
if (look)
{
_world_camera.add_to_yaw(math::degrees(relative_movement.dx() / 20.0f));
_world_camera.add_to_pitch(math::degrees(mousedir * relative_movement.dy() / 20.0f));
}
AssetBrowser::ModelViewer::mouseMoveEvent(event);
}
void ModelViewer::initializeGL()
{
AssetBrowser::ModelViewer::initializeGL();
}

View File

@@ -3,6 +3,8 @@
#include <noggit/Red/AssetBrowser/ModelView.hpp>
#include <noggit/World.h>
#include <noggit/camera.hpp>
namespace noggit
@@ -14,10 +16,26 @@ namespace noggit
public:
explicit ModelViewer(QWidget* parent = nullptr);
void loadWorldUnderlay(std::string const& internal_name, int map_id);
World* getWorld() { return _world.get(); };
noggit::camera* getCamera() { return &_camera; };
noggit::camera* getWorldCamera() { return &_world_camera; };
private:
std::unique_ptr<World> _world;
noggit::camera _world_camera;
void paintGL() override;
void initializeGL() override;
void tick(float dt) override;
math::matrix_4x4 world_model_view() const;
math::matrix_4x4 world_projection() const;
void mouseMoveEvent(QMouseEvent* event) override;
};

View File

@@ -1,6 +1,7 @@
#include "PresetEditor.hpp"
#include <noggit/ui/FramelessWindow.hpp>
#include <noggit/ui/font_noggit.hpp>
#include <noggit/DBC.h>
using namespace noggit::Red::PresetEditor::Ui;
@@ -73,6 +74,33 @@ PresetEditorWidget::PresetEditorWidget(QWidget *parent)
setupConnectsCommon();
// Fill selector combo
ui->worldSelector->addItem("None");
ui->worldSelector->setItemData(0, QVariant(-1));
int count = 1;
for (DBCFile::Iterator i = gMapDB.begin(); i != gMapDB.end(); ++i)
{
int map_id = i->getInt(MapDB::MapID);
std::string name = i->getLocalizedString(MapDB::Name);
int area_type = i->getUInt(MapDB::AreaType);
if (area_type < 0 || area_type > 4 || !World::IsEditableWorld(map_id))
continue;
ui->worldSelector->addItem(QString::number(map_id) + " - " + QString::fromUtf8 (name.c_str()));
ui->worldSelector->setItemData(count, QVariant(map_id), Qt::UserRole);
auto map_internal_name = i->getString(MapDB::InternalName);
ui->worldSelector->setItemData(count, QVariant(QString::fromStdString(map_internal_name)), Qt::UserRole + 1);
count++;
}
// Handle minimap widget
ui->minimapWidget->draw_boundaries(true);
ui->minimapWidget->camera(ui->viewport->getWorldCamera());
}
void PresetEditorWidget::setupConnectsCommon()
@@ -85,6 +113,25 @@ void PresetEditorWidget::setupConnectsCommon()
);
connect(ui->worldUnloadButton, &QPushButton::clicked
,[this]()
{
int map_id = ui->worldSelector->itemData(ui->worldSelector->currentIndex(), Qt::UserRole).toInt();
ui->viewport->loadWorldUnderlay(
ui->worldSelector->itemData(ui->worldSelector->currentIndex(), Qt::UserRole + 1).toString().toStdString(), map_id);
ui->minimapWidget->world(ui->viewport->getWorld());
}
);
connect(ui->minimapWidget, &minimap_widget::map_clicked
, [this] (::math::vector_3d const& pos)
{
ui->viewport->getWorldCamera()->position = pos;
}
);
connect(viewport_overlay_ui->lightDirY, &QDial::valueChanged
,[this]()
{

View File

@@ -47,6 +47,18 @@
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="minimumSize">
@@ -63,7 +75,7 @@
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="directoryBar">
<property name="spacing">
<number>0</number>
</property>
@@ -164,7 +176,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="widget_2" native="true">
<widget class="QWidget" name="viewportHolder" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
@@ -194,146 +206,198 @@
<number>0</number>
</property>
<item>
<widget class="noggit::Red::PresetEditor::ModelViewer" name="viewport">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>400</height>
</size>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="viewport_tab">
<attribute name="title">
<string>Viewport</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="noggit::Red::PresetEditor::ModelViewer" name="viewport">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>400</height>
</size>
</property>
</widget>
<widget class="QWidget" name="toolPanel" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>684</height>
</rect>
</property>
<attribute name="label">
<string>World navigation</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item alignment="Qt::AlignHCenter|Qt::AlignTop">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="mapSelector_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>-1</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Map:</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="worldSelector"/>
</item>
<item>
<widget class="QPushButton" name="worldUnloadButton">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
<widget class="noggit::ui::minimap_widget" name="minimapWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>684</height>
</rect>
</property>
<attribute name="label">
<string>Page 2</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="nodes_tab">
<attribute name="title">
<string>Nodes</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="toolPanel" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>561</width>
<height>702</height>
</rect>
</property>
<attribute name="label">
<string>World navigation</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QWidget" name="widget_3" native="true">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="mapSelector_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>-1</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Map:</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="noggit::ui::minimap_widget" name="minimapHolder_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>561</width>
<height>702</height>
</rect>
</property>
<attribute name="label">
<string>Page 2</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@@ -468,7 +468,7 @@ QPixmap* PreviewRenderer::renderToPixmap()
gl.clearColor(0.5f, 0.5f, 0.5f, 1.f);
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
tick(20.f);
tick(1.0f);
draw();
auto& async_loader = AsyncLoader::instance();
@@ -528,6 +528,8 @@ void PreviewRenderer::update_emitters(float dt)
void PreviewRenderer::tick(float dt)
{
dt = std::min(dt, 1.0f);
_animtime += dt * 1000.0f;
if (_draw_animated.get())

View File

@@ -26,7 +26,7 @@ namespace noggit
setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
//setMouseTracking(true);
setMaximumSize(QSize(1024, 1024));
setMinimumSize(QSize(512, 512));
setMinimumSize(QSize(128, 128));
}
QSize minimap_widget::sizeHint() const