// https://github.com/CedricGuillemet/ImGuizmo // v 1.84 WIP // // The MIT License(MIT) // // Copyright(c) 2021 Cedric Guillemet // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files(the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions : // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #include "imgui.h" #define IMGUI_DEFINE_MATH_OPERATORS #include "imgui_internal.h" #define IMAPP_IMPL #include "ImApp.h" #include "ImGuizmo.h" #include "ImSequencer.h" #include "ImZoomSlider.h" #include "ImCurveEdit.h" #include "GraphEditor.h" #include #include #include bool useWindow = true; int gizmoCount = 1; float camDistance = 8.f; static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE); float objectMatrix[4][16] = { { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f }, { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 2.f, 0.f, 0.f, 1.f }, { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 2.f, 0.f, 2.f, 1.f }, { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 2.f, 1.f } }; static const float identityMatrix[16] = { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f }; void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16) { float temp, temp2, temp3, temp4; temp = 2.0f * znear; temp2 = right - left; temp3 = top - bottom; temp4 = zfar - znear; m16[0] = temp / temp2; m16[1] = 0.0; m16[2] = 0.0; m16[3] = 0.0; m16[4] = 0.0; m16[5] = temp / temp3; m16[6] = 0.0; m16[7] = 0.0; m16[8] = (right + left) / temp2; m16[9] = (top + bottom) / temp3; m16[10] = (-zfar - znear) / temp4; m16[11] = -1.0f; m16[12] = 0.0; m16[13] = 0.0; m16[14] = (-temp * zfar) / temp4; m16[15] = 0.0; } void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16) { float ymax, xmax; ymax = znear * tanf(fovyInDegrees * 3.141592f / 180.0f); xmax = ymax * aspectRatio; Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16); } void Cross(const float* a, const float* b, float* r) { r[0] = a[1] * b[2] - a[2] * b[1]; r[1] = a[2] * b[0] - a[0] * b[2]; r[2] = a[0] * b[1] - a[1] * b[0]; } float Dot(const float* a, const float* b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } void Normalize(const float* a, float* r) { float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON); r[0] = a[0] * il; r[1] = a[1] * il; r[2] = a[2] * il; } void LookAt(const float* eye, const float* at, const float* up, float* m16) { float X[3], Y[3], Z[3], tmp[3]; tmp[0] = eye[0] - at[0]; tmp[1] = eye[1] - at[1]; tmp[2] = eye[2] - at[2]; Normalize(tmp, Z); Normalize(up, Y); Cross(Y, Z, tmp); Normalize(tmp, X); Cross(Z, X, tmp); Normalize(tmp, Y); m16[0] = X[0]; m16[1] = Y[0]; m16[2] = Z[0]; m16[3] = 0.0f; m16[4] = X[1]; m16[5] = Y[1]; m16[6] = Z[1]; m16[7] = 0.0f; m16[8] = X[2]; m16[9] = Y[2]; m16[10] = Z[2]; m16[11] = 0.0f; m16[12] = -Dot(X, eye); m16[13] = -Dot(Y, eye); m16[14] = -Dot(Z, eye); m16[15] = 1.0f; } void OrthoGraphic(const float l, float r, float b, const float t, float zn, const float zf, float* m16) { m16[0] = 2 / (r - l); m16[1] = 0.0f; m16[2] = 0.0f; m16[3] = 0.0f; m16[4] = 0.0f; m16[5] = 2 / (t - b); m16[6] = 0.0f; m16[7] = 0.0f; m16[8] = 0.0f; m16[9] = 0.0f; m16[10] = 1.0f / (zf - zn); m16[11] = 0.0f; m16[12] = (l + r) / (l - r); m16[13] = (t + b) / (b - t); m16[14] = zn / (zn - zf); m16[15] = 1.0f; } inline void rotationY(const float angle, float* m16) { float c = cosf(angle); float s = sinf(angle); m16[0] = c; m16[1] = 0.0f; m16[2] = -s; m16[3] = 0.0f; m16[4] = 0.0f; m16[5] = 1.f; m16[6] = 0.0f; m16[7] = 0.0f; m16[8] = s; m16[9] = 0.0f; m16[10] = c; m16[11] = 0.0f; m16[12] = 0.f; m16[13] = 0.f; m16[14] = 0.f; m16[15] = 1.0f; } void EditTransform(float* cameraView, float* cameraProjection, float* matrix, bool editTransformDecomposition) { static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL); static bool useSnap = false; static float snap[3] = { 1.f, 1.f, 1.f }; static float bounds[] = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; static float boundsSnap[] = { 0.1f, 0.1f, 0.1f }; static bool boundSizing = false; static bool boundSizingSnap = false; if (editTransformDecomposition) { 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; if (ImGui::RadioButton("Universal", mCurrentGizmoOperation == ImGuizmo::UNIVERSAL)) mCurrentGizmoOperation = ImGuizmo::UNIVERSAL; float matrixTranslation[3], matrixRotation[3], matrixScale[3]; ImGuizmo::DecomposeMatrixToComponents(matrix, matrixTranslation, matrixRotation, matrixScale); ImGui::InputFloat3("Tr", matrixTranslation); ImGui::InputFloat3("Rt", matrixRotation); ImGui::InputFloat3("Sc", matrixScale); ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix); 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; } if (ImGui::IsKeyPressed(83)) useSnap = !useSnap; ImGui::Checkbox("", &useSnap); ImGui::SameLine(); switch (mCurrentGizmoOperation) { case ImGuizmo::TRANSLATE: ImGui::InputFloat3("Snap", &snap[0]); break; case ImGuizmo::ROTATE: ImGui::InputFloat("Angle Snap", &snap[0]); break; case ImGuizmo::SCALE: ImGui::InputFloat("Scale Snap", &snap[0]); break; } ImGui::Checkbox("Bound Sizing", &boundSizing); if (boundSizing) { ImGui::PushID(3); ImGui::Checkbox("", &boundSizingSnap); ImGui::SameLine(); ImGui::InputFloat3("Snap", boundsSnap); ImGui::PopID(); } } ImGuiIO& io = ImGui::GetIO(); float viewManipulateRight = io.DisplaySize.x; float viewManipulateTop = 0; if (useWindow) { ImGui::SetNextWindowSize(ImVec2(800, 400)); ImGui::SetNextWindowPos(ImVec2(400,20)); ImGui::PushStyleColor(ImGuiCol_WindowBg, (ImVec4)ImColor(0.35f, 0.3f, 0.3f)); ImGui::Begin("Gizmo", 0, ImGuiWindowFlags_NoMove); ImGuizmo::SetDrawlist(); float windowWidth = (float)ImGui::GetWindowWidth(); float windowHeight = (float)ImGui::GetWindowHeight(); ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight); viewManipulateRight = ImGui::GetWindowPos().x + windowWidth; viewManipulateTop = ImGui::GetWindowPos().y; } else { ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); } ImGuizmo::DrawGrid(cameraView, cameraProjection, identityMatrix, 100.f); ImGuizmo::DrawCubes(cameraView, cameraProjection, &objectMatrix[0][0], gizmoCount); ImGuizmo::Manipulate(cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, useSnap ? &snap[0] : NULL, boundSizing ? bounds : NULL, boundSizingSnap ? boundsSnap : NULL); ImGuizmo::ViewManipulate(cameraView, camDistance, ImVec2(viewManipulateRight - 128, viewManipulateTop), ImVec2(128, 128), 0x10101010); if (useWindow) { ImGui::End(); ImGui::PopStyleColor(1); } } // // // ImSequencer interface // // static const char* SequencerItemTypeNames[] = { "Camera","Music", "ScreenEffect", "FadeIn", "Animation" }; struct RampEdit : public ImCurveEdit::Delegate { RampEdit() { mPts[0][0] = ImVec2(-10.f, 0); mPts[0][1] = ImVec2(20.f, 0.6f); mPts[0][2] = ImVec2(25.f, 0.2f); mPts[0][3] = ImVec2(70.f, 0.4f); mPts[0][4] = ImVec2(120.f, 1.f); mPointCount[0] = 5; mPts[1][0] = ImVec2(-50.f, 0.2f); mPts[1][1] = ImVec2(33.f, 0.7f); mPts[1][2] = ImVec2(80.f, 0.2f); mPts[1][3] = ImVec2(82.f, 0.8f); mPointCount[1] = 4; mPts[2][0] = ImVec2(40.f, 0); mPts[2][1] = ImVec2(60.f, 0.1f); mPts[2][2] = ImVec2(90.f, 0.82f); mPts[2][3] = ImVec2(150.f, 0.24f); mPts[2][4] = ImVec2(200.f, 0.34f); mPts[2][5] = ImVec2(250.f, 0.12f); mPointCount[2] = 6; mbVisible[0] = mbVisible[1] = mbVisible[2] = true; mMax = ImVec2(1.f, 1.f); mMin = ImVec2(0.f, 0.f); } size_t GetCurveCount() { return 3; } bool IsVisible(size_t curveIndex) { return mbVisible[curveIndex]; } size_t GetPointCount(size_t curveIndex) { return mPointCount[curveIndex]; } uint32_t GetCurveColor(size_t curveIndex) { uint32_t cols[] = { 0xFF0000FF, 0xFF00FF00, 0xFFFF0000 }; return cols[curveIndex]; } ImVec2* GetPoints(size_t curveIndex) { return mPts[curveIndex]; } virtual ImCurveEdit::CurveType GetCurveType(size_t curveIndex) const { return ImCurveEdit::CurveSmooth; } virtual int EditPoint(size_t curveIndex, int pointIndex, ImVec2 value) { mPts[curveIndex][pointIndex] = ImVec2(value.x, value.y); SortValues(curveIndex); for (size_t i = 0; i < GetPointCount(curveIndex); i++) { if (mPts[curveIndex][i].x == value.x) return (int)i; } return pointIndex; } virtual void AddPoint(size_t curveIndex, ImVec2 value) { if (mPointCount[curveIndex] >= 8) return; mPts[curveIndex][mPointCount[curveIndex]++] = value; SortValues(curveIndex); } virtual ImVec2& GetMax() { return mMax; } virtual ImVec2& GetMin() { return mMin; } virtual unsigned int GetBackgroundColor() { return 0; } ImVec2 mPts[3][8]; size_t mPointCount[3]; bool mbVisible[3]; ImVec2 mMin; ImVec2 mMax; private: void SortValues(size_t curveIndex) { auto b = std::begin(mPts[curveIndex]); auto e = std::begin(mPts[curveIndex]) + GetPointCount(curveIndex); std::sort(b, e, [](ImVec2 a, ImVec2 b) { return a.x < b.x; }); } }; struct MySequence : public ImSequencer::SequenceInterface { // interface with sequencer virtual int GetFrameMin() const { return mFrameMin; } virtual int GetFrameMax() const { return mFrameMax; } virtual int GetItemCount() const { return (int)myItems.size(); } virtual int GetItemTypeCount() const { return sizeof(SequencerItemTypeNames) / sizeof(char*); } virtual const char* GetItemTypeName(int typeIndex) const { return SequencerItemTypeNames[typeIndex]; } virtual const char* GetItemLabel(int index) const { static char tmps[512]; snprintf(tmps, 512, "[%02d] %s", index, SequencerItemTypeNames[myItems[index].mType]); return tmps; } virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) { MySequenceItem& item = myItems[index]; if (color) *color = 0xFFAA8080; // same color for everyone, return color based on type if (start) *start = &item.mFrameStart; if (end) *end = &item.mFrameEnd; if (type) *type = item.mType; } virtual void Add(int type) { myItems.push_back(MySequenceItem{ type, 0, 10, false }); }; virtual void Del(int index) { myItems.erase(myItems.begin() + index); } virtual void Duplicate(int index) { myItems.push_back(myItems[index]); } virtual size_t GetCustomHeight(int index) { return myItems[index].mExpanded ? 300 : 0; } // my datas MySequence() : mFrameMin(0), mFrameMax(0) {} int mFrameMin, mFrameMax; struct MySequenceItem { int mType; int mFrameStart, mFrameEnd; bool mExpanded; }; std::vector myItems; RampEdit rampEdit; virtual void DoubleClick(int index) { if (myItems[index].mExpanded) { myItems[index].mExpanded = false; return; } for (auto& item : myItems) item.mExpanded = false; myItems[index].mExpanded = !myItems[index].mExpanded; } virtual void CustomDraw(int index, ImDrawList* draw_list, const ImRect& rc, const ImRect& legendRect, const ImRect& clippingRect, const ImRect& legendClippingRect) { static const char* labels[] = { "Translation", "Rotation" , "Scale" }; rampEdit.mMax = ImVec2(float(mFrameMax), 1.f); rampEdit.mMin = ImVec2(float(mFrameMin), 0.f); draw_list->PushClipRect(legendClippingRect.Min, legendClippingRect.Max, true); for (int i = 0; i < 3; i++) { ImVec2 pta(legendRect.Min.x + 30, legendRect.Min.y + i * 14.f); ImVec2 ptb(legendRect.Max.x, legendRect.Min.y + (i + 1) * 14.f); draw_list->AddText(pta, rampEdit.mbVisible[i] ? 0xFFFFFFFF : 0x80FFFFFF, labels[i]); if (ImRect(pta, ptb).Contains(ImGui::GetMousePos()) && ImGui::IsMouseClicked(0)) rampEdit.mbVisible[i] = !rampEdit.mbVisible[i]; } draw_list->PopClipRect(); ImGui::SetCursorScreenPos(rc.Min); ImCurveEdit::Edit(rampEdit, rc.Max - rc.Min, 137 + index, &clippingRect); } virtual void CustomDrawCompact(int index, ImDrawList* draw_list, const ImRect& rc, const ImRect& clippingRect) { rampEdit.mMax = ImVec2(float(mFrameMax), 1.f); rampEdit.mMin = ImVec2(float(mFrameMin), 0.f); draw_list->PushClipRect(clippingRect.Min, clippingRect.Max, true); for (int i = 0; i < 3; i++) { for (int j = 0; j < rampEdit.mPointCount[i]; j++) { float p = rampEdit.mPts[i][j].x; if (p < myItems[index].mFrameStart || p > myItems[index].mFrameEnd) continue; float r = (p - mFrameMin) / float(mFrameMax - mFrameMin); float x = ImLerp(rc.Min.x, rc.Max.x, r); draw_list->AddLine(ImVec2(x, rc.Min.y + 6), ImVec2(x, rc.Max.y - 4), 0xAA000000, 4.f); } } draw_list->PopClipRect(); } }; // // // GraphEditor interface // // template struct Array { T data[N]; const size_t size() const { return N; } const T operator [] (size_t index) const { return data[index]; } operator T* () { T* p = new T[N]; memcpy(p, data, sizeof(data)); return p; } }; template Array(T, U...)->Array; struct GraphEditorDelegate : public GraphEditor::Delegate { bool AllowedLink(GraphEditor::NodeIndex from, GraphEditor::NodeIndex to) override { return true; } void SelectNode(GraphEditor::NodeIndex nodeIndex, bool selected) override { mNodes[nodeIndex].mSelected = selected; } void MoveSelectedNodes(const ImVec2 delta) override { for (auto& node : mNodes) { if (!node.mSelected) { continue; } node.x += delta.x; node.y += delta.y; } } virtual void RightClick(GraphEditor::NodeIndex nodeIndex, GraphEditor::SlotIndex slotIndexInput, GraphEditor::SlotIndex slotIndexOutput) override { } void AddLink(GraphEditor::NodeIndex inputNodeIndex, GraphEditor::SlotIndex inputSlotIndex, GraphEditor::NodeIndex outputNodeIndex, GraphEditor::SlotIndex outputSlotIndex) override { mLinks.push_back({ inputNodeIndex, inputSlotIndex, outputNodeIndex, outputSlotIndex }); } void DelLink(GraphEditor::LinkIndex linkIndex) override { mLinks.erase(mLinks.begin() + linkIndex); } void CustomDraw(ImDrawList* drawList, ImRect rectangle, GraphEditor::NodeIndex nodeIndex) override { drawList->AddLine(rectangle.Min, rectangle.Max, IM_COL32(0, 0, 0, 255)); drawList->AddText(rectangle.Min, IM_COL32(255, 128, 64, 255), "Draw"); } const size_t GetTemplateCount() override { return sizeof(mTemplates) / sizeof(GraphEditor::Template); } const GraphEditor::Template GetTemplate(GraphEditor::TemplateIndex index) override { return mTemplates[index]; } const size_t GetNodeCount() override { return mNodes.size(); } const GraphEditor::Node GetNode(GraphEditor::NodeIndex index) override { const auto& myNode = mNodes[index]; return GraphEditor::Node { myNode.name, myNode.templateIndex, ImRect(ImVec2(myNode.x, myNode.y), ImVec2(myNode.x + 200, myNode.y + 200)), myNode.mSelected }; } const size_t GetLinkCount() override { return mLinks.size(); } const GraphEditor::Link GetLink(GraphEditor::LinkIndex index) override { return mLinks[index]; } // Graph datas static const inline GraphEditor::Template mTemplates[] = { { IM_COL32(160, 160, 180, 255), IM_COL32(100, 100, 140, 255), IM_COL32(110, 110, 150, 255), 1, Array{"MyInput"}, nullptr, 2, Array{"MyOutput0", "MyOuput1"}, nullptr }, { IM_COL32(180, 160, 160, 255), IM_COL32(140, 100, 100, 255), IM_COL32(150, 110, 110, 255), 3, nullptr, Array{ IM_COL32(200,100,100,255), IM_COL32(100,200,100,255), IM_COL32(100,100,200,255) }, 1, Array{"MyOutput0"}, Array{ IM_COL32(200,200,200,255)} } }; struct Node { const char* name; GraphEditor::TemplateIndex templateIndex; float x, y; bool mSelected; }; std::vector mNodes = { { "My Node 0", 0, 0, 0, false }, { "My Node 1", 0, 400, 0, false }, { "My Node 2", 1, 400, 400, false } }; std::vector mLinks = { {0, 0, 1, 0} }; }; int main(int, char**) { ImApp::ImApp imApp; ImApp::Config config; config.mWidth = 1280; config.mHeight = 720; //config.mFullscreen = true; imApp.Init(config); int lastUsing = 0; float cameraView[16] = { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f }; float cameraProjection[16]; // build a procedural texture. Copy/pasted and adapted from https://rosettacode.org/wiki/Plasma_effect#Graphics_version unsigned int procTexture; glGenTextures(1, &procTexture); glBindTexture(GL_TEXTURE_2D, procTexture); uint32_t* tempBitmap = new uint32_t[256 * 256]; int index = 0; for (int y = 0; y < 256; y++) { for (int x = 0; x < 256; x++) { float dx = x + .5f; float dy = y + .5f; float dv = sinf(x * 0.02f) + sinf(0.03f * (x + y)) + sinf(sqrtf(0.4f * (dx * dx + dy * dy) + 1.f)); tempBitmap[index] = 0xFF000000 + (int(255 * fabsf(sinf(dv * 3.141592f))) << 16) + (int(255 * fabsf(sinf(dv * 3.141592f + 2 * 3.141592f / 3))) << 8) + (int(255 * fabs(sin(dv * 3.141592f + 4.f * 3.141592f / 3.f)))); index++; } } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempBitmap); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); delete [] tempBitmap; // sequence with default values MySequence mySequence; mySequence.mFrameMin = -100; mySequence.mFrameMax = 1000; mySequence.myItems.push_back(MySequence::MySequenceItem{ 0, 10, 30, false }); mySequence.myItems.push_back(MySequence::MySequenceItem{ 1, 20, 30, true }); mySequence.myItems.push_back(MySequence::MySequenceItem{ 3, 12, 60, false }); mySequence.myItems.push_back(MySequence::MySequenceItem{ 2, 61, 90, false }); mySequence.myItems.push_back(MySequence::MySequenceItem{ 4, 90, 99, false }); // Camera projection bool isPerspective = true; float fov = 27.f; float viewWidth = 10.f; // for orthographic float camYAngle = 165.f / 180.f * 3.14159f; float camXAngle = 32.f / 180.f * 3.14159f; bool firstFrame = true; // Main loop while (!imApp.Done()) { imApp.NewFrame(); ImGuiIO& io = ImGui::GetIO(); if (isPerspective) { Perspective(fov, io.DisplaySize.x / io.DisplaySize.y, 0.1f, 100.f, cameraProjection); } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; OrthoGraphic(-viewWidth, viewWidth, -viewHeight, viewHeight, 1000.f, -1000.f, cameraProjection); } ImGuizmo::SetOrthographic(!isPerspective); ImGuizmo::BeginFrame(); ImGui::SetNextWindowPos(ImVec2(1024, 100)); ImGui::SetNextWindowSize(ImVec2(256, 256)); // create a window and insert the inspector ImGui::SetNextWindowPos(ImVec2(10, 10)); ImGui::SetNextWindowSize(ImVec2(320, 340)); ImGui::Begin("Editor"); if (ImGui::RadioButton("Full view", !useWindow)) useWindow = false; ImGui::SameLine(); if (ImGui::RadioButton("Window", useWindow)) useWindow = true; ImGui::Text("Camera"); bool viewDirty = false; if (ImGui::RadioButton("Perspective", isPerspective)) isPerspective = true; ImGui::SameLine(); if (ImGui::RadioButton("Orthographic", !isPerspective)) isPerspective = false; if (isPerspective) { ImGui::SliderFloat("Fov", &fov, 20.f, 110.f); } else { ImGui::SliderFloat("Ortho width", &viewWidth, 1, 20); } viewDirty |= ImGui::SliderFloat("Distance", &camDistance, 1.f, 10.f); ImGui::SliderInt("Gizmo count", &gizmoCount, 1, 4); if (viewDirty || firstFrame) { float eye[] = { cosf(camYAngle) * cosf(camXAngle) * camDistance, sinf(camXAngle) * camDistance, sinf(camYAngle) * cosf(camXAngle) * camDistance }; float at[] = { 0.f, 0.f, 0.f }; float up[] = { 0.f, 1.f, 0.f }; LookAt(eye, at, up, cameraView); firstFrame = false; } ImGui::Text("X: %f Y: %f", io.MousePos.x, io.MousePos.y); if (ImGuizmo::IsUsing()) { ImGui::Text("Using gizmo"); } else { ImGui::Text(ImGuizmo::IsOver()?"Over gizmo":""); ImGui::SameLine(); ImGui::Text(ImGuizmo::IsOver(ImGuizmo::TRANSLATE) ? "Over translate gizmo" : ""); ImGui::SameLine(); ImGui::Text(ImGuizmo::IsOver(ImGuizmo::ROTATE) ? "Over rotate gizmo" : ""); ImGui::SameLine(); ImGui::Text(ImGuizmo::IsOver(ImGuizmo::SCALE) ? "Over scale gizmo" : ""); } ImGui::Separator(); for (int matId = 0; matId < gizmoCount; matId++) { ImGuizmo::SetID(matId); EditTransform(cameraView, cameraProjection, objectMatrix[matId], lastUsing == matId); if (ImGuizmo::IsUsing()) { lastUsing = matId; } } ImGui::End(); ImGui::SetNextWindowPos(ImVec2(10, 350)); ImGui::SetNextWindowSize(ImVec2(940, 480)); ImGui::Begin("Other controls"); if (ImGui::CollapsingHeader("Zoom Slider")) { static float uMin = 0.4f, uMax = 0.6f; static float vMin = 0.4f, vMax = 0.6f; ImGui::Image((ImTextureID)(uint64_t)procTexture, ImVec2(900,300), ImVec2(uMin, vMin), ImVec2(uMax, vMax)); { ImGui::SameLine(); ImGui::PushID(18); ImZoomSlider::ImZoomSlider(0.f, 1.f, vMin, vMax, 0.01f, ImZoomSlider::ImGuiZoomSliderFlags_Vertical); ImGui::PopID(); } { ImGui::PushID(19); ImZoomSlider::ImZoomSlider(0.f, 1.f, uMin, uMax); ImGui::PopID(); } } if (ImGui::CollapsingHeader("Sequencer")) { // let's create the sequencer static int selectedEntry = -1; static int firstFrame = 0; static bool expanded = true; static int currentFrame = 100; ImGui::PushItemWidth(130); ImGui::InputInt("Frame Min", &mySequence.mFrameMin); ImGui::SameLine(); ImGui::InputInt("Frame ", ¤tFrame); ImGui::SameLine(); ImGui::InputInt("Frame Max", &mySequence.mFrameMax); ImGui::PopItemWidth(); Sequencer(&mySequence, ¤tFrame, &expanded, &selectedEntry, &firstFrame, ImSequencer::SEQUENCER_EDIT_STARTEND | ImSequencer::SEQUENCER_ADD | ImSequencer::SEQUENCER_DEL | ImSequencer::SEQUENCER_COPYPASTE | ImSequencer::SEQUENCER_CHANGE_FRAME); // add a UI to edit that particular item if (selectedEntry != -1) { const MySequence::MySequenceItem &item = mySequence.myItems[selectedEntry]; ImGui::Text("I am a %s, please edit me", SequencerItemTypeNames[item.mType]); // switch (type) .... } } // Graph Editor static GraphEditor::Options options; static GraphEditorDelegate delegate; static GraphEditor::ViewState viewState; static GraphEditor::FitOnScreen fit = GraphEditor::Fit_None; static bool showGraphEditor = true; if (ImGui::CollapsingHeader("Graph Editor")) { ImGui::Checkbox("Show GraphEditor", &showGraphEditor); GraphEditor::EditOptions(options); } ImGui::End(); if (showGraphEditor) { ImGui::Begin("Graph Editor", NULL, 0); if (ImGui::Button("Fit all nodes")) { fit = GraphEditor::Fit_AllNodes; } ImGui::SameLine(); if (ImGui::Button("Fit selected nodes")) { fit = GraphEditor::Fit_SelectedNodes; } GraphEditor::Show(delegate, options, viewState, true, &fit); ImGui::End(); } // render everything glClearColor(0.45f, 0.4f, 0.4f, 1.f); glClear(GL_COLOR_BUFFER_BIT); imApp.EndFrame(); } imApp.Finish(); return 0; }