diff --git a/src/edit/include/edit/editor.hpp b/src/edit/include/edit/editor.hpp index dafc865906fcce9ab2aa8176de528439ec6e4f23..b8797515cc98607148faede99cd9d9dd5a104022 100644 --- a/src/edit/include/edit/editor.hpp +++ b/src/edit/include/edit/editor.hpp @@ -203,14 +203,18 @@ class Editor node_ptr prev_rebuild_node; bool can_rotate_component = true; + module_ptr rotation_locked_module; bool rofi_invalid_state = false; + std::set<module_ptr> collided_modules; rofi::cardinal selected_cardinality = rofi::cardinal::North; std::pair<connector_ptr, connector_ptr> selected_connectors = {nullptr, nullptr}; std::pair<glm::vec3, node_ptr> first_connector_highlights = {glm::vec3(0.0f), nullptr}; std::pair<glm::vec3, node_ptr> second_connector_highlights = {glm::vec3(0.0f), nullptr}; + // Default Mesh + mesh_ptr voxel_mesh = Mesh::loadMesh("./data/models/rofi/cube_new_scale.obj"); mesh_ptr body_mesh = Mesh::loadMesh("./data/models/rofi/body_new_scale.obj", false, false); @@ -222,6 +226,28 @@ class Editor mesh_ptr empty_shoe_mesh = Mesh::loadMesh("./data/models/rofi/shoe_new_scale.obj", false, false); + // Invalid Mesh + + mesh_ptr voxel_mesh_invalid = Mesh::loadMesh("./data/models/rofi/cube_new_scale.obj"); + mesh_ptr body_mesh_invalid = Mesh::loadMesh("./data/models/rofi/body_new_scale.obj", false, false); + + mesh_ptr fixed_connector_mesh_invalid = Mesh::loadMesh("./data/models/rofi/connector_new_scale.obj", false, false); + mesh_ptr open_connector_mesh_invalid = Mesh::loadMesh("./data/models/rofi/connector_new_scale.obj", false, false); + mesh_ptr connected_connector_mesh_invalid = Mesh::loadMesh("./data/models/rofi/connector_connected_new_scale.obj", false, false); + mesh_ptr shared_connector_mesh_invalid = Mesh::loadMesh("./data/models/rofi/connector_new_scale.obj"); + mesh_ptr empty_connector_mesh_invalid = Mesh::loadMesh("./data/models/rofi/connector_new_scale.obj", false, false); + + mesh_ptr empty_shoe_mesh_invalid = Mesh::loadMesh("./data/models/rofi/shoe_new_scale.obj", false, false); + + const std::vector<mesh_ptr> voxel_meshes = { voxel_mesh, voxel_mesh_invalid }; + const std::vector<mesh_ptr> body_meshes = { body_mesh, body_mesh_invalid }; + const std::vector<mesh_ptr> fixed_connector_meshes = { fixed_connector_mesh, fixed_connector_mesh_invalid }; + const std::vector<mesh_ptr> open_connector_meshes = { open_connector_mesh, open_connector_mesh_invalid }; + const std::vector<mesh_ptr> connected_connector_meshes = { connected_connector_mesh, connected_connector_mesh_invalid }; + const std::vector<mesh_ptr> shared_connector_meshes = { shared_connector_mesh, shared_connector_mesh_invalid }; + const std::vector<mesh_ptr> empty_connector_meshes = { empty_connector_mesh, empty_connector_mesh_invalid }; + const std::vector<mesh_ptr> empty_shoe_meshes = { empty_shoe_mesh, empty_shoe_mesh_invalid }; + public: Editor(const osi::Keyboard &_keyboard, const osi::Mouse &_mouse, @@ -232,6 +258,7 @@ public: : keyboard{_keyboard}, mouse{_mouse}, timer{_timer}, window{_window}, scene{_scene}, controls{_controls} { + // Default Mesh voxel_mesh->setMaterial(mat::yellow_plastic); body_mesh->setMaterial(mat::black_plastic); @@ -243,6 +270,18 @@ public: empty_shoe_mesh->setMaterial(mat::yellow_plastic); + //Invalid Mesh + voxel_mesh_invalid->setMaterial(mat::red_highlight); + body_mesh_invalid->setMaterial(mat::red_highlight); + + fixed_connector_mesh_invalid->setMaterial(mat::red_highlight); + open_connector_mesh_invalid->setMaterial(mat::red_highlight); + connected_connector_mesh_invalid->setMaterial(mat::red_highlight); + shared_connector_mesh_invalid->setMaterial(mat::red_highlight); + empty_connector_mesh_invalid->setMaterial(mat::red_highlight); + + empty_shoe_mesh_invalid->setMaterial(mat::red_highlight); + enterPhaseOne(); linkModulesNodes(modules); @@ -408,10 +447,10 @@ private: void seekAndDestroyOrphans(); void updateRoFIMesh(const voxel_graph_ptr vg); - void toggleRoFIInvalidStateMesh(bool invalid); - void setRoFIMesh(const voxel_graph_ptr vg); - void setVoxelMesh(const voxel_ptr voxel); - void setConnectorMesh(const connector_ptr connector); + void toggleRoFIInvalidStateMesh(bool invalid, const std::set<module_ptr> &_modules); + void setRoFIMesh(const voxel_graph_ptr vg, bool invalid_state = false); + void setVoxelMesh(const voxel_ptr voxel, bool invalid_state = false); + void setConnectorMesh(const connector_ptr connector, bool invalid_state = false); void linkImportVoxelGraphToNodes(const voxel_graph_ptr vg); /* ROFI -- PHASE TWO */ diff --git a/src/edit/src/editor.cpp b/src/edit/src/editor.cpp index a0a6231c752f09e4e7ed19ad0aa13edc3814b353..5e61908101f4645829002d611930e0c94fea5510 100644 --- a/src/edit/src/editor.cpp +++ b/src/edit/src/editor.cpp @@ -1932,76 +1932,82 @@ void Editor::linkImportVoxelGraphToNodes(const voxel_graph_ptr vg) connector->getNode()->addObject(connector); } -void Editor::toggleRoFIInvalidStateMesh(bool invalid) +void Editor::toggleRoFIInvalidStateMesh(bool invalid, const std::set<module_ptr> &modules) { - if (invalid == rofi_invalid_state) - return; + // if (invalid == rofi_invalid_state) + // return; - if (invalid) - { - voxel_mesh->setMaterial(mat::red_highlight); - body_mesh->setMaterial(mat::red_highlight); + // if (invalid) + // { + // voxel_mesh->setMaterial(mat::red_highlight); + // body_mesh->setMaterial(mat::red_highlight); - fixed_connector_mesh->setMaterial(mat::red_highlight); - open_connector_mesh->setMaterial(mat::red_highlight); - connected_connector_mesh->setMaterial(mat::red_highlight); - shared_connector_mesh->setMaterial(mat::red_highlight); + // fixed_connector_mesh->setMaterial(mat::red_highlight); + // open_connector_mesh->setMaterial(mat::red_highlight); + // connected_connector_mesh->setMaterial(mat::red_highlight); + // shared_connector_mesh->setMaterial(mat::red_highlight); - empty_shoe_mesh->setMaterial(mat::red_highlight); + // empty_shoe_mesh->setMaterial(mat::red_highlight); - } - else - { - voxel_mesh->setMaterial(mat::yellow_plastic); - body_mesh->setMaterial(mat::black_plastic); + // } + // else + // { + // voxel_mesh->setMaterial(mat::yellow_plastic); + // body_mesh->setMaterial(mat::black_plastic); - fixed_connector_mesh->setMaterial(mat::red_plastic); - open_connector_mesh->setMaterial(mat::blue_plastic); - connected_connector_mesh->setMaterial(mat::red_plastic); - shared_connector_mesh->setMaterial(mat::black_plastic); - empty_connector_mesh->setMaterial(mat::empty_material); + // fixed_connector_mesh->setMaterial(mat::red_plastic); + // open_connector_mesh->setMaterial(mat::blue_plastic); + // connected_connector_mesh->setMaterial(mat::red_plastic); + // shared_connector_mesh->setMaterial(mat::black_plastic); + // empty_connector_mesh->setMaterial(mat::empty_material); - empty_shoe_mesh->setMaterial(mat::yellow_plastic); - } + // empty_shoe_mesh->setMaterial(mat::yellow_plastic); + // } + + for (auto &module : modules) + setRoFIMesh(module->getParts(), invalid); } -void Editor::setRoFIMesh(const voxel_graph_ptr vg) +void Editor::setRoFIMesh(const voxel_graph_ptr vg, bool invalid_state) { for (const auto &voxel : vg->getVoxels()) - setVoxelMesh(voxel); + setVoxelMesh(voxel, invalid_state); for (const auto &connector : vg->getConnections()) - setConnectorMesh(connector); + setConnectorMesh(connector, invalid_state); } -void Editor::setVoxelMesh(const voxel_ptr voxel) +void Editor::setVoxelMesh(const voxel_ptr voxel, bool invalid_state) { if (std::dynamic_pointer_cast<rofi::ModuleLink>(voxel)) return; + int i = invalid_state ? 1 : 0; + scene->removeAllMesh(voxel->getNode()); - const auto mesh = voxel->hasSharedRotation() ? body_mesh : voxel_mesh; + const auto mesh = voxel->hasSharedRotation() ? body_meshes[i] : voxel_meshes[i]; scene->addMesh(voxel->getNode(), mesh); } -void Editor::setConnectorMesh(const connector_ptr connector) +void Editor::setConnectorMesh(const connector_ptr connector, bool invalid_state) { scene->removeAllMesh(connector->getNode()); mesh_ptr mesh; bool is_full = connector->isFull(); + int i = invalid_state ? 1 : 0; switch (connector->getType(true)) { using enum rofi::connector_type; case fixed: - mesh = is_full ? connected_connector_mesh : fixed_connector_mesh; + mesh = is_full ? connected_connector_meshes[i] : fixed_connector_meshes[i]; break; case open: - mesh = is_full ? connected_connector_mesh : open_connector_mesh; + mesh = is_full ? connected_connector_meshes[i] : open_connector_meshes[i]; break; case shared_rotation: - mesh = shared_connector_mesh; + mesh = shared_connector_meshes[i]; break; case rotation: { @@ -2011,17 +2017,17 @@ void Editor::setConnectorMesh(const connector_ptr connector) switch(connector->getType(false)) { case empty: - mesh = is_head ? empty_shoe_mesh : empty_connector_mesh; + mesh = is_head ? empty_shoe_meshes[i] : empty_connector_meshes[i]; break; case fixed: - mesh = is_full ? connected_connector_mesh : fixed_connector_mesh; + mesh = is_full ? connected_connector_meshes[i] : fixed_connector_meshes[i]; if (is_head) - scene->addMesh(connector->getNode(), empty_shoe_mesh); + scene->addMesh(connector->getNode(), empty_shoe_meshes[i]); break; case open: - mesh = is_full ? connected_connector_mesh : open_connector_mesh; + mesh = is_full ? connected_connector_meshes[i] : open_connector_meshes[i]; if (is_head) - scene->addMesh(connector->getNode(), empty_shoe_mesh); + scene->addMesh(connector->getNode(), empty_shoe_meshes[i]); break; default: ASSUMPTION(false); @@ -2130,10 +2136,11 @@ void Editor::exitRotateComponent() prev_rebuild_node = nullptr; can_rotate_component = true; is_rotating_component = false; + rotation_locked_module = nullptr; if (!detectCollision(true, rofiworld)) { - toggleRoFIInvalidStateMesh(false); + toggleRoFIInvalidStateMesh(false, collided_modules); rofi_invalid_state = false; } } @@ -2303,14 +2310,17 @@ bool Editor::checkSelectedComponentValid() void Editor::updateRotationHint() { + if (!rotation_locked_module) + return; + if (timer.passed_seconds() - error_start_second > 1) { - toggleRoFIInvalidStateMesh(false); + toggleRoFIInvalidStateMesh(false, {rotation_locked_module}); rofi_invalid_state = false; } else { - toggleRoFIInvalidStateMesh(true); + toggleRoFIInvalidStateMesh(true, {rotation_locked_module}); rofi_invalid_state = true; } } @@ -2549,8 +2559,11 @@ void Editor::rotateComponent() if (!can_rotate_component) { setError("Cycle detected, rotation not permited."); + rotation_locked_module = rofiworld->getModuleWithNode(selection); return; } + else + rotation_locked_module = nullptr; if (is_voxel) rotateVoxel(voxel, component_rotation_angle); @@ -2659,9 +2672,25 @@ bool Editor::detectCollision(bool something_changed, rofiworld_ptr rofiworld) if (!something_changed) return false; - auto collision_detected = rofiworld->detectCollision(); + // toggleRoFIInvalidStateMesh(false, collided_modules); + std::set<module_ptr> curr_collided_modules; + + auto collision_detected = rofiworld->detectCollision(curr_collided_modules); + + std::set<module_ptr> no_longer_collided_modules; + std::set_difference(collided_modules.begin(), collided_modules.end(), curr_collided_modules.begin(), curr_collided_modules.end(), + std::inserter(no_longer_collided_modules, no_longer_collided_modules.begin())); + + toggleRoFIInvalidStateMesh(false, no_longer_collided_modules); + + std::set<module_ptr> newly_collided_modules; + std::set_difference(curr_collided_modules.begin(), curr_collided_modules.end(), collided_modules.begin(), collided_modules.end(), + std::inserter(newly_collided_modules, newly_collided_modules.begin())); + + toggleRoFIInvalidStateMesh(true, newly_collided_modules); + + collided_modules = curr_collided_modules; - toggleRoFIInvalidStateMesh(collision_detected); rofi_invalid_state = collision_detected; return collision_detected; diff --git a/src/gui/src/ui.cpp b/src/gui/src/ui.cpp index 6f0744360eb48a28ec81fa60a16d46e56e4bc062..cd63fc2ff70790267e27f43f5da214ac380cedd7 100644 --- a/src/gui/src/ui.cpp +++ b/src/gui/src/ui.cpp @@ -676,7 +676,8 @@ void module_rotation_drag(edit::UIData &data, glm::vec3 &euler_angles) if (ImGui::ArrowButton(button_labels[i], 0)) euler_angles[i] = glm::clamp(euler_angles[i] - data.module_rotation_step, min_limit, max_limit); ImGui::SameLine(); - ImGui::DragFloat(drag_labels[i], &euler_angles[i], data.module_rotation_step, min_limit, max_limit, "%.3f°", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragFloat(drag_labels[i], &euler_angles[i], data.module_rotation_step, min_limit, max_limit, "%.3f°", + ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_NoInput); ImGui::SameLine(); if (ImGui::ArrowButton(button_labels[i + 3], 1)) euler_angles[i] = glm::clamp(euler_angles[i] + data.module_rotation_step, min_limit, max_limit); diff --git a/src/rofi/include/rofi/rofiworld.hpp b/src/rofi/include/rofi/rofiworld.hpp index 613dffe0488abd4bea63675643487d983cd335e8..8397ac3cdefcc8f91d8a9dce1f1c7d8f1ec223a9 100644 --- a/src/rofi/include/rofi/rofiworld.hpp +++ b/src/rofi/include/rofi/rofiworld.hpp @@ -50,7 +50,7 @@ public: bool rebuildNodeTree(module_ptr module, node_ptr root_node); bool rebuildNodeTree(voxel_ptr voxel, node_ptr root_node); - bool detectCollision() const; + bool detectCollision(std::set<module_ptr> &collided_modules) const; private: void disconnectModule(module_ptr module); diff --git a/src/rofi/src/rofiworld.cpp b/src/rofi/src/rofiworld.cpp index f9682c170728704a7ef0c9ee120d1d068df1987a..548a5d9883472be99739d06de79d7ce2d5afe5ca 100644 --- a/src/rofi/src/rofiworld.cpp +++ b/src/rofi/src/rofiworld.cpp @@ -164,8 +164,10 @@ bool RofiWorld::rebuildNodeTree(voxel_ptr voxel, node_ptr root_node) return true; } -bool RofiWorld::detectCollision() const +bool RofiWorld::detectCollision(std::set<module_ptr> &collided_modules) const { + bool retval = false; + for (const auto &[module_node, module] : nodes_map) { for (const auto &voxel : module->getParts()->getVoxels()) @@ -178,14 +180,19 @@ bool RofiWorld::detectCollision() const for (const auto &voxel2 : module2->getParts()->getVoxels()) { + // 0.86 is the length of the longest side of UM body mesh if (glm::distance(voxel->getNode()->getPositionWorld(), voxel2->getNode()->getPositionWorld()) < 0.86f) - return true; + { + collided_modules.emplace(module); + collided_modules.emplace(module2); + retval = true; + } } } } } - return false; + return retval; } /* PRIVATE */