diff --git a/include/igl/opengl/glfw/imgui/ImGuizmo.h b/include/igl/opengl/glfw/imgui/ImGuizmo.h deleted file mode 100644 index 84ae50860..000000000 --- a/include/igl/opengl/glfw/imgui/ImGuizmo.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -//////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -//////////////////////////////////////////////////////////////////////////////// - -namespace igl -{ -namespace opengl -{ -namespace glfw -{ -namespace imgui -{ - -void EditTransform(const float *cameraView, const float *cameraProjection, float* matrix, bool isOrthographic) -{ - static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE); - // Alec: This could be a parameter ImGuizmo::WORLD will make senze in some - // circumstances. For now, 109_ImGuizmo and my other use cases make more - // sense in LOCAL mode. - static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL); - - // Maya-style key bindings - if (ImGui::IsKeyPressed('W')) - mCurrentGizmoOperation = ImGuizmo::TRANSLATE; - if (ImGui::IsKeyPressed('E')) - mCurrentGizmoOperation = ImGuizmo::ROTATE; - if (ImGui::IsKeyPressed('R')) - 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, matrixTranslation, matrixRotation, matrixScale); - ImGui::InputFloat3("Tr", matrixTranslation, 3); - ImGui::InputFloat3("Rt", matrixRotation, 3); - ImGui::InputFloat3("Sc", matrixScale, 3); - ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix); - - ImGuiIO& io = ImGui::GetIO(); - ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); - ImGuizmo::Manipulate(cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, NULL); -} - -} // end namespace -} // end namespace -} // end namespace -} // end namespace diff --git a/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp b/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp new file mode 100644 index 000000000..ac34fbf2c --- /dev/null +++ b/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp @@ -0,0 +1,49 @@ +#include "ImGuizmoPlugin.h" +#include +#include +#include +#include +#include + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +IGL_INLINE void ImGuizmoPlugin::init(igl::opengl::glfw::Viewer *_viewer) +{ + ImGuiMenu::init(_viewer); +} +IGL_INLINE bool ImGuizmoPlugin::pre_draw() +{ + ImGuiMenu::pre_draw(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); + ImGuizmo::BeginFrame(); + ImGui::PopStyleVar(); + return false; +} +IGL_INLINE bool ImGuizmoPlugin::post_draw() +{ + // Don't draw the Viewer's default menu: draw just the ImGuizmo + Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom); + Eigen::Matrix4f proj = viewer->core().proj; + if(viewer->core().orthographic){ view(2,3) -= 1000;/* Hack depth */ } + // ImGuizmo doesn't like a lot of scaling in view, shift it to T + const float z = viewer->core().camera_base_zoom; + const Eigen::Matrix4f S = + (Eigen::Matrix4f()<< z,0,0,0, 0,z,0,0, 0,0,z,0, 0,0,0,1).finished(); + view = (view * S.inverse()).eval(); + const Eigen::Matrix4f T0 = T; + T = (S * T).eval(); + ImGuiIO& io = ImGui::GetIO(); + ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); + ImGuizmo::Manipulate( + view.data(),proj.data(),operation,ImGuizmo::LOCAL,T.data(),NULL,NULL); + // invert scaling that was shifted onto T + T = (S.inverse() * T).eval(); + const float diff = (T-T0).array().abs().maxCoeff(); + // Only call if actually changed; otherwise, triggers on all mouse events + if( diff > 1e-7) { callback(T); } + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + return false; +} + +}}}} diff --git a/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h b/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h new file mode 100644 index 000000000..c82da44ac --- /dev/null +++ b/include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h @@ -0,0 +1,37 @@ +#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H +#define IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H +#include "../../../igl_inline.h" +#include "ImGuiMenu.h" +#include +#include +#include +#include + +namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{ + +class ImGuizmoPlugin : public igl::opengl::glfw::imgui::ImGuiMenu +{ +public: + // callback(T) called when the stored transform T changes + std::function callback; + // whether rotating, translating or scaling + ImGuizmo::OPERATION operation; + // stored transformation + Eigen::Matrix4f T; + // Initilize with rotate operation on an identity transform (at origin) + ImGuizmoPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){}; + ///////////////////////////////////////////////////////////////////////////// + // Boilerplate + virtual void init(igl::opengl::glfw::Viewer *_viewer) override; + virtual bool pre_draw() override; + ///////////////////////////////////////////////////////////////////////////// + virtual bool post_draw() override; +}; + +}}}} + +#ifndef IGL_STATIC_LIBRARY +# include "ImGuizmoPlugin.cpp" +#endif + +#endif diff --git a/tutorial/109_ImGuizmo/main.cpp b/tutorial/109_ImGuizmo/main.cpp index 7d30e7096..de3451817 100755 --- a/tutorial/109_ImGuizmo/main.cpp +++ b/tutorial/109_ImGuizmo/main.cpp @@ -1,101 +1,53 @@ +#include #include -#include -#include -#include -#include +#include #include #include -#include "tutorial_shared_path.h" - -class SlicingPlugin : public igl::opengl::glfw::imgui::ImGuiMenu -{ - igl::opengl::ViewerData data; - // Hard Coded Plane Mesh - const Eigen::MatrixXd OV = (Eigen::MatrixXd(4, 3) << - -0.5, -0.5, 0.0, - -0.5, 0.5, 0.0, - 0.5, 0.5, 0.0, - 0.5, -0.5, 0.0).finished(); - const Eigen::MatrixXi OF = (Eigen::MatrixXi(2, 3) << - 0, 2, 1, - 0, 3, 2).finished(); - - virtual void init(igl::opengl::glfw::Viewer *_viewer) override - { - ImGuiMenu::init(_viewer); - // Load slicing plane into viewer (a square mesh) - data.set_mesh(SlicingPlugin::OV, SlicingPlugin::OF); - data.set_face_based(true); - data.set_colors(Eigen::RowVector4d(224, 86, 253, 128)/255.0); - data.show_lines = false; - } - - virtual bool pre_draw() override { - ImGuiMenu::pre_draw(); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); - ImGuizmo::BeginFrame(); - ImGui::PopStyleVar(); - return false; - } - - virtual bool post_draw() override { - viewer->core().draw(data); - ImGuiMenu::post_draw(); - return false; - } - - virtual void draw_custom_window() override { - float menu_width = 180.f * menu_scaling(); - ImGui::SetNextWindowPos(ImVec2(menu_width, 0.0f), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSizeConstraints(ImVec2(1.5f * menu_width, -1.0f), ImVec2(1.5f * menu_width, -1.0f)); - bool _guizmo_menu_visible = true; - ImGui::Begin( - "ImGuizmo Tools", &_guizmo_menu_visible, - ImGuiWindowFlags_NoSavedSettings - | ImGuiWindowFlags_AlwaysAutoResize - ); - - draw_imguizmo_menu(); - - ImGui::End(); - } - - virtual void draw_imguizmo_menu() { - static Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity(); - const float z = viewer->core().camera_base_zoom; - Eigen::Affine3f rescale = Eigen::Scaling(0.5f * z) - * Eigen::Translation3f(viewer->core().camera_base_translation); - Eigen::Affine3f view = Eigen::Affine3f( viewer->core().view * 1./viewer->core().camera_zoom ) * rescale.inverse(); - Eigen::Matrix4f proj = viewer->core().proj; - if(viewer->core().orthographic) - { - view(2,3) -= 50; // Adjust depth for view transform - } - - igl::opengl::glfw::imgui::EditTransform(view.matrix().data(), proj.data(), matrix.data(), viewer->core().orthographic); - - // Transform the slicing plane according to - // ImGuizmo tool manipulations in the viewer - Eigen::Affine3f model = Eigen::Affine3f(rescale.inverse()*matrix); - Eigen::MatrixXd V = (SlicingPlugin::OV.rowwise().homogeneous() - * model.matrix().cast().transpose()).rowwise().hnormalized(); - - if (data.V.rows() == V.rows()) - data.set_vertices(V); - } - -}; +#include +#include +#include +#include int main(int argc, char *argv[]) { - // Plot the mesh - igl::opengl::glfw::Viewer viewer; - viewer.load_mesh_from_file(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cow.off"); - + // Load a mesh from file + Eigen::MatrixXd V; + Eigen::MatrixXi F; + igl::read_triangle_mesh(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cow.off",V,F); + // Set up viewer + igl::opengl::glfw::Viewer vr; + vr.data().set_mesh(V,F); // Custom menu - SlicingPlugin menu; - viewer.plugins.push_back(&menu); - - viewer.launch(); + igl::opengl::glfw::imgui::ImGuizmoPlugin plugin; + vr.plugins.push_back(&plugin); + // Initialize ImGuizmo at mesh centroid + plugin.T.block(0,3,3,1) = + 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()).transpose().cast(); + // Update can be applied relative to this remembered initial transform + const Eigen::Matrix4f T0 = plugin.T; + // Attach callback to apply imguizmo's transform to mesh + plugin.callback = [&](const Eigen::Matrix4f & T) + { + const Eigen::Matrix4d TT = (T*T0.inverse()).cast().transpose(); + vr.data().set_vertices( + (V.rowwise().homogeneous()*TT).rowwise().hnormalized()); + vr.data().compute_normals(); + }; + // Maya-style keyboard shortcuts for operation + vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod) + { + switch(key) + { + case 'W': case 'w': plugin.operation = ImGuizmo::TRANSLATE; return true; + case 'E': case 'e': plugin.operation = ImGuizmo::ROTATE; return true; + case 'R': case 'r': plugin.operation = ImGuizmo::SCALE; return true; + } + return false; + }; + std::cout<