From 53b50aaff39cf929587c2cd34c85192dfb76c5b8 Mon Sep 17 00:00:00 2001 From: DennisWG Date: Fri, 6 Sep 2024 20:16:57 +0000 Subject: [PATCH] Tools rewrite --- CMakeLists.txt | 8 +- src/noggit/Action.cpp | 6 +- src/noggit/Action.hpp | 6 +- src/noggit/Input.hpp | 9 + src/noggit/MapView.cpp | 2911 ++--------------- src/noggit/MapView.h | 198 +- src/noggit/MinimapRenderSettings.hpp | 53 + src/noggit/StringHash.hpp | 40 + src/noggit/Tool.cpp | 247 ++ src/noggit/Tool.hpp | 208 ++ src/noggit/ToolDrawParameters.hpp | 31 + src/noggit/object_paste_params.hpp | 17 + src/noggit/tools/AreaTool.cpp | 122 + src/noggit/tools/AreaTool.hpp | 48 + src/noggit/tools/ChunkTool.cpp | 43 + src/noggit/tools/ChunkTool.hpp | 34 + src/noggit/tools/FlattenBlurTool.cpp | 187 ++ src/noggit/tools/FlattenBlurTool.hpp | 45 + src/noggit/tools/HoleTool.cpp | 113 + src/noggit/tools/HoleTool.hpp | 45 + src/noggit/tools/ImpassTool.cpp | 71 + src/noggit/tools/ImpassTool.hpp | 32 + src/noggit/tools/LightTool.cpp | 49 + src/noggit/tools/LightTool.hpp | 36 + src/noggit/tools/MinimapTool.cpp | 299 ++ src/noggit/tools/MinimapTool.hpp | 60 + src/noggit/tools/ObjectTool.cpp | 968 ++++++ src/noggit/tools/ObjectTool.hpp | 93 + src/noggit/tools/RaiseLowerTool.cpp | 254 ++ src/noggit/tools/RaiseLowerTool.hpp | 45 + src/noggit/tools/ScriptingTool.cpp | 70 + src/noggit/tools/ScriptingTool.hpp | 39 + src/noggit/tools/StampTool.cpp | 177 + src/noggit/tools/StampTool.hpp | 44 + src/noggit/tools/TexturingTool.cpp | 584 ++++ src/noggit/tools/TexturingTool.hpp | 70 + src/noggit/tools/VertexPainterTool.cpp | 162 + src/noggit/tools/VertexPainterTool.hpp | 47 + src/noggit/tools/WaterTool.cpp | 165 + src/noggit/tools/WaterTool.hpp | 47 + src/noggit/ui/FontAwesome.hpp | 1 + src/noggit/ui/GroundEffectsTool.cpp | 4 + src/noggit/ui/GroundEffectsTool.hpp | 3 +- src/noggit/ui/Help.cpp | 708 ++-- src/noggit/ui/MinimapCreator.cpp | 6 +- src/noggit/ui/MinimapCreator.hpp | 49 +- src/noggit/ui/ObjectEditor.cpp | 4 +- src/noggit/ui/ObjectEditor.h | 16 +- src/noggit/ui/ShaderTool.cpp | 4 +- src/noggit/ui/TerrainTool.cpp | 4 +- src/noggit/ui/Toolbar.cpp | 21 +- src/noggit/ui/Toolbar.h | 4 +- src/noggit/ui/Water.cpp | 792 ++--- src/noggit/ui/minimap_widget.cpp | 2 +- src/noggit/ui/minimap_widget.hpp | 6 +- src/noggit/ui/object_palette.cpp | 2 +- src/noggit/ui/texturing_tool.cpp | 6 +- src/noggit/ui/texturing_tool.hpp | 5 + .../ui/tools/AssetBrowser/Ui/AssetBrowser.cpp | 9 +- .../ui/tools/AssetBrowser/Ui/AssetBrowser.hpp | 1 + .../ui/tools/ViewToolbar/Ui/ViewToolbar.cpp | 14 +- .../ui/tools/ViewToolbar/Ui/ViewToolbar.hpp | 15 +- .../ui/tools/ViewportGizmo/ViewportGizmo.cpp | 2 +- src/noggit/ui/widgets/LightViewWidget.cpp | 1 + .../ui/windows/noggitWindow/NoggitWindow.cpp | 1 + 65 files changed, 5795 insertions(+), 3568 deletions(-) create mode 100644 src/noggit/Input.hpp create mode 100644 src/noggit/MinimapRenderSettings.hpp create mode 100644 src/noggit/StringHash.hpp create mode 100644 src/noggit/Tool.cpp create mode 100644 src/noggit/Tool.hpp create mode 100644 src/noggit/ToolDrawParameters.hpp create mode 100644 src/noggit/object_paste_params.hpp create mode 100644 src/noggit/tools/AreaTool.cpp create mode 100644 src/noggit/tools/AreaTool.hpp create mode 100644 src/noggit/tools/ChunkTool.cpp create mode 100644 src/noggit/tools/ChunkTool.hpp create mode 100644 src/noggit/tools/FlattenBlurTool.cpp create mode 100644 src/noggit/tools/FlattenBlurTool.hpp create mode 100644 src/noggit/tools/HoleTool.cpp create mode 100644 src/noggit/tools/HoleTool.hpp create mode 100644 src/noggit/tools/ImpassTool.cpp create mode 100644 src/noggit/tools/ImpassTool.hpp create mode 100644 src/noggit/tools/LightTool.cpp create mode 100644 src/noggit/tools/LightTool.hpp create mode 100644 src/noggit/tools/MinimapTool.cpp create mode 100644 src/noggit/tools/MinimapTool.hpp create mode 100644 src/noggit/tools/ObjectTool.cpp create mode 100644 src/noggit/tools/ObjectTool.hpp create mode 100644 src/noggit/tools/RaiseLowerTool.cpp create mode 100644 src/noggit/tools/RaiseLowerTool.hpp create mode 100644 src/noggit/tools/ScriptingTool.cpp create mode 100644 src/noggit/tools/ScriptingTool.hpp create mode 100644 src/noggit/tools/StampTool.cpp create mode 100644 src/noggit/tools/StampTool.hpp create mode 100644 src/noggit/tools/TexturingTool.cpp create mode 100644 src/noggit/tools/TexturingTool.hpp create mode 100644 src/noggit/tools/VertexPainterTool.cpp create mode 100644 src/noggit/tools/VertexPainterTool.hpp create mode 100644 src/noggit/tools/WaterTool.cpp create mode 100644 src/noggit/tools/WaterTool.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e2abe0f7..500f0be1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,8 +106,12 @@ FIND_PACKAGE(OpenGL REQUIRED) FIND_PACKAGE(Json REQUIRED) FIND_PACKAGE(lodepng REQUIRED) -set(FASTNOISE2_NOISETOOL OFF CACHE BOOL "") -FIND_PACKAGE(FastNoise2 REQUIRED) +FetchContent_Declare( + FastNoise2 + GIT_REPOSITORY https://github.com/Auburn/FastNoise2.git + GIT_TAG v0.10.0-alpha +) +FetchContent_MakeAvailable(FastNoise2) FIND_PACKAGE(Sol2 REQUIRED) FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGLExtensions Gui Network Xml Multimedia REQUIRED) diff --git a/src/noggit/Action.cpp b/src/noggit/Action.cpp index 64d849a1..40609aea 100755 --- a/src/noggit/Action.cpp +++ b/src/noggit/Action.cpp @@ -544,7 +544,7 @@ void Noggit::Action::finish() } if (_post) - (_map_view->*_post)(); + _post(); } float* Noggit::Action::getChunkTerrainOriginalData(MapChunk* chunk) @@ -578,9 +578,9 @@ bool Noggit::Action::getBlockCursor() const } -void Noggit::Action::setPostCallback(auto(MapView::*method)()->void) +void Noggit::Action::setPostCallback(std::function function) { - _post = method; + _post = function; } diff --git a/src/noggit/Action.hpp b/src/noggit/Action.hpp index 9c965ce7..4a8b295e 100755 --- a/src/noggit/Action.hpp +++ b/src/noggit/Action.hpp @@ -18,6 +18,8 @@ #include #include +#include + class MapView; class MapChunk; @@ -115,7 +117,7 @@ namespace Noggit float getDelta() const; void setBlockCursor(bool state); bool getBlockCursor() const; - void setPostCallback(auto(MapView::*method)()->void); + void setPostCallback(std::function function); bool getTag() { return _tag; }; void setTag(bool tag) { _tag = tag; }; @@ -184,7 +186,7 @@ namespace Noggit tsl::robin_map> _object_operations; - auto(MapView::*_post)()->void = nullptr; + std::function _post; }; } diff --git a/src/noggit/Input.hpp b/src/noggit/Input.hpp new file mode 100644 index 00000000..1594cf2e --- /dev/null +++ b/src/noggit/Input.hpp @@ -0,0 +1,9 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +namespace Noggit +{ + constexpr float XSENS = 15.0f; + constexpr float YSENS = 15.0f; +} \ No newline at end of file diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index c163e0f6..83449599 100755 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -41,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +52,24 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #ifdef USE_MYSQL_UID_STORAGE #include @@ -93,6 +111,7 @@ #include #include +#include /* Some ugly macros we use */ @@ -211,25 +230,15 @@ ACTION_CODE }); \ } - -static const float XSENS = 15.0f; -static const float YSENS = 15.0f; +using Noggit::XSENS; +using Noggit::YSENS; void MapView::set_editing_mode(editing_mode mode) { { QSignalBlocker const asset_browser_blocker(_asset_browser_dock); - QSignalBlocker const tex_browser_blocker(_texture_browser_dock); - QSignalBlocker const texture_palette_blocker(_texture_palette_dock); - QSignalBlocker const object_palette_blocker(_object_palette_dock); - objectEditor->modelImport->hide(); - objectEditor->rotationEditor->hide(); - _texture_browser_dock->hide(); - _texture_picker_dock->hide(); - _texture_palette_dock->hide(); - _object_palette_dock->hide(); _asset_browser_dock->hide(); _viewport_overlay_ui->gizmoBar->hide(); } @@ -240,17 +249,6 @@ void MapView::set_editing_mode(editing_mode mode) if (context() && context()->isValid()) { - if (mode == editing_mode::holes && previous_mode != editing_mode::holes) - { - _world->renderer()->getTerrainParamsUniformBlock()->draw_lines = true; - _world->renderer()->getTerrainParamsUniformBlock()->draw_hole_lines = true; - } - else if (previous_mode == editing_mode::holes && mode != editing_mode::holes) - { - _world->renderer()->getTerrainParamsUniformBlock()->draw_lines = _draw_lines.get(); - _world->renderer()->getTerrainParamsUniformBlock()->draw_hole_lines = _draw_hole_lines.get(); - } - _world->renderer()->getTerrainParamsUniformBlock()->draw_areaid_overlay = false; _world->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = false; _world->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = false; @@ -259,77 +257,17 @@ void MapView::set_editing_mode(editing_mode mode) _world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false; _world->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false; _minimap->use_selection(nullptr); - - bool use_classic_ui = _settings->value("classicUI", false).toBool(); - - if (mode != editing_mode::paint) + + if (terrainMode != mode) { - getGroundEffectsTool()->hide(); - } - - switch (mode) - { - case editing_mode::ground: - if (terrainTool->_edit_type != eTerrainType_Vertex || (terrainTool->_edit_type != eTerrainType_Script && terrainTool->getImageMaskSelector()->isEnabled())) - { - terrainTool->updateMaskImage(); - } - break; - case editing_mode::paint: - if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint && texturingTool->getImageMaskSelector()->isEnabled()) - { - texturingTool->updateMaskImage(); - } - else if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect) - { - getGroundEffectsTool()->updateTerrainUniformParams(); - } - - if (use_classic_ui) - { - if (texturingTool->show_unpaintable_chunks()) - { - _world->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = true; - } - } - else - { - if (_left_sec_toolbar->showUnpaintableChunk()) - { - _world->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = true; - } - } - break; - case editing_mode::mccv: - if (shaderTool->getImageMaskSelector()->isEnabled()) - { - shaderTool->updateMaskImage(); - } - break; - case editing_mode::stamp: - if (stampTool->getActiveBrushItem() && stampTool->getActiveBrushItem()->isEnabled()) - { - stampTool->getActiveBrushItem()->updateMask(); - } - break; - case editing_mode::areaid: - _world->renderer()->getTerrainParamsUniformBlock()->draw_areaid_overlay = true; - break; - case editing_mode::impass: - _world->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = true; - break; - case editing_mode::minimap: - _world->renderer()->getTerrainParamsUniformBlock()->draw_selection_overlay = true; - _minimap->use_selection(minimapTool->getSelectedTiles()); - break; - default: - break; + activeTool()->onDeselected(); + activeTool(mode); + activeTool()->onSelected(); } } - MoveObj = false; _world->reset_selection(); - _rotation_editor_need_update = true; + emit rotationChanged(); if (!ui_hidden) { @@ -352,13 +290,8 @@ void MapView::setToolPropertyWidgetVisibility(editing_mode mode) case editing_mode::object: _asset_browser_dock->setVisible(!ui_hidden && _settings->value("map_view/asset_browser", false).toBool()); - _object_palette_dock->setVisible(!ui_hidden && _settings->value("map_view/object_palette", false).toBool()); _viewport_overlay_ui->gizmoBar->setVisible(!ui_hidden); break; - case editing_mode::paint: - _texture_browser_dock->setVisible(!ui_hidden && _settings->value("map_view/texture_browser", false).toBool()); - _texture_palette_dock->setVisible(!ui_hidden && _settings->value("map_view/texture_palette", false).toBool()); - break; default: break; } @@ -397,7 +330,7 @@ void MapView::ResetSelectedObjectRotation() } } - _rotation_editor_need_update = true; + emit rotationChanged(); } void MapView::snap_selected_models_to_the_ground() @@ -408,7 +341,12 @@ void MapView::snap_selected_models_to_the_ground() } _world->snap_selected_models_to_the_ground(); - _rotation_editor_need_update = true; + emit rotationChanged(); +} + +bool MapView::isRotatingCamera() const +{ + return look; } @@ -423,16 +361,9 @@ void MapView::DeleteSelectedObjects() OpenGL::context::scoped_setter const _ (::gl, context()); _world->delete_selected_models(); - _rotation_editor_need_update = true; + emit rotationChanged(); } - -void MapView::changeZoneIDValue (int set) -{ - _selected_area_id = set; -} - - QWidgetAction* MapView::createTextSeparator(const QString& text) { auto* pLabel = new QLabel(text); @@ -545,384 +476,6 @@ void MapView::updateGizmoOverlay(ImGuizmo::OPERATION operation) _gizmo_operation = operation; } -void MapView::setupRaiseLowerUi() -{ - terrainTool = new Noggit::Ui::TerrainTool(this, this); - _tool_panel_dock->registerTool("Raise | Lower", terrainTool); - - connect(terrainTool - , &Noggit::Ui::TerrainTool::updateVertices - , [this](int vertex_mode, math::degrees const& angle, math::degrees const& orientation) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - _world->orientVertices(vertex_mode == eVertexMode_Mouse - ? _cursor_pos - : _world->vertexCenter() - , angle - , orientation - ); - } - ); - - terrainTool->storeCursorPos(&_cursor_pos); - -} - -void MapView::setupFlattenBlurUi() -{ - flattenTool = new Noggit::Ui::flatten_blur_tool(this); - _tool_panel_dock->registerTool("Flatten | Blur", flattenTool); -} - -void MapView::setupTexturePainterUi() -{ - /* Tool */ - texturingTool = new Noggit::Ui::texturing_tool(&_camera.position, this, &_show_texture_palette_small_window, this); - _tool_panel_dock->registerTool("Texture Painter", texturingTool); - - // Connects - connect( texturingTool->texture_swap_tool()->texture_display() - , &Noggit::Ui::current_texture::texture_dropped - , [=] (std::string const& filename) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - texturingTool->texture_swap_tool()->set_texture(filename); - } - ); - - connect( texturingTool->_current_texture - , &Noggit::Ui::current_texture::texture_dropped - , [=] (std::string const& filename) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - Noggit::Ui::selected_texture::set({filename, _context}); - } - ); - - connect(texturingTool->_current_texture, &Noggit::Ui::current_texture::clicked - , [=] - { - _texture_browser_dock->setVisible(!_texture_browser_dock->isVisible()); - } - ); - - /* Additional tools */ - - /* Texture Browser */ - - // Dock - _texture_browser_dock = new QDockWidget("Texture Browser", this); - _texture_browser_dock->setFeatures(QDockWidget::DockWidgetMovable - | QDockWidget::DockWidgetFloatable - | QDockWidget::DockWidgetClosable); - _texture_browser_dock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea); - _main_window->addDockWidget(Qt::BottomDockWidgetArea, _texture_browser_dock); - _texture_browser_dock->hide(); - - connect(_texture_browser_dock, &QDockWidget::visibilityChanged, - [=](bool visible) - { - if (ui_hidden) - return; - - _settings->setValue ("map_view/texture_browser", visible); - _settings->sync(); - }); - - connect(this, &QObject::destroyed, _texture_browser_dock, &QObject::deleteLater); - // End Dock - - TexturePalette = new Noggit::Ui::tileset_chooser(this); - _texture_browser_dock->setWidget(TexturePalette); - connect(this, &QObject::destroyed, TexturePalette, &QObject::deleteLater); - - connect(TexturePalette, &Noggit::Ui::tileset_chooser::selected - , [=](std::string const& filename) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - Noggit::Ui::selected_texture::set({filename, _context}); - texturingTool->_current_texture->set_texture(filename); - TexturePicker->setMainTexture(texturingTool->_current_texture); - TexturePicker->updateSelection(); - } - ); - - connect ( TexturePalette, &Noggit::Ui::widget::visibilityChanged - , &_show_texture_palette_window, &Noggit::BoolToggleProperty::set - ); - - connect ( &_show_texture_palette_window, &Noggit::BoolToggleProperty::changed - , [this] - { - if ((terrainMode == editing_mode::paint || terrainMode == editing_mode::stamp) && !ui_hidden) - { - _texture_browser_dock->setVisible(_show_texture_palette_window.get()); - } - else - { - QSignalBlocker const _ (_show_texture_palette_window); - _show_texture_palette_window.set(false); - } - } - ); - - - /* Texture Palette Small */ - _texture_palette_small = new Noggit::Ui::texture_palette_small(_project, _world->getMapID(), this); - - // Dock - _texture_palette_dock = new QDockWidget("Texture Palette", this); - _texture_palette_dock->setFeatures(QDockWidget::DockWidgetMovable - | QDockWidget::DockWidgetFloatable - | QDockWidget::DockWidgetClosable - ); - - _texture_palette_dock->setWidget(_texture_palette_small); - _texture_palette_dock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);; - - _main_window->addDockWidget(Qt::BottomDockWidgetArea, _texture_palette_dock); - // End Dock - - connect(_texture_palette_dock, &QDockWidget::visibilityChanged, - [=](bool visible) - { - if (ui_hidden) - return; - - _settings->setValue ("map_view/texture_palette", visible); - _settings->sync(); - }); - - connect(_texture_palette_small, &Noggit::Ui::texture_palette_small::selected - , [=](std::string const& filename) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - Noggit::Ui::selected_texture::set({filename, _context}); - texturingTool->_current_texture->set_texture(filename); - } - ); - connect(this, &QObject::destroyed, _texture_palette_small, &QObject::deleteLater); - - connect(&_show_texture_palette_small_window, &Noggit::BoolToggleProperty::changed - , _texture_palette_dock, [this] - { - QSignalBlocker const blocker(_show_texture_palette_small_window); - if (terrainMode == editing_mode::paint && !ui_hidden) - { - _texture_palette_dock->setVisible(_show_texture_palette_small_window.get()); - } - else - { - _show_texture_palette_small_window.set(false); - } - } - ); - connect(_texture_palette_dock, &QDockWidget::visibilityChanged - , &_show_texture_palette_small_window, &Noggit::BoolToggleProperty::set - ); - - connect(texturingTool->_current_texture, &Noggit::Ui::current_texture::texture_updated - , [=]() - { - _world->notifyTileRendererOnSelectedTextureChange(); - getGroundEffectsTool()->TextureChanged(); - } - ); - - /* Texture Picker */ - - // Dock - _texture_picker_dock = new QDockWidget("Texture picker", this); - _texture_picker_dock->setFeatures(QDockWidget::DockWidgetMovable - | QDockWidget::DockWidgetFloatable - | QDockWidget::DockWidgetClosable); - _main_window->addDockWidget(Qt::BottomDockWidgetArea, _texture_picker_dock); - _texture_picker_dock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); - _texture_picker_dock->setFloating(true); - _texture_picker_dock->hide(); - connect(this, &QObject::destroyed, _texture_picker_dock, &QObject::deleteLater); - // End Dock - - TexturePicker = new Noggit::Ui::texture_picker(texturingTool->_current_texture, this); - _texture_picker_dock->setWidget(TexturePicker); - connect(this, &QObject::destroyed, TexturePicker, &QObject::deleteLater); - - connect( TexturePicker - , &Noggit::Ui::texture_picker::set_texture - , [=] (scoped_blp_texture_reference texture) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - Noggit::Ui::selected_texture::set(std::move(texture)); - } - ); - connect(TexturePicker, &Noggit::Ui::texture_picker::shift_left - , [=] - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - TexturePicker->shiftSelectedTextureLeft(); - } - ); - connect(TexturePicker, &Noggit::Ui::texture_picker::shift_right - , [=] - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - TexturePicker->shiftSelectedTextureRight(); - } - ); - -} - -void MapView::setupHoleCutterUi() -{ - holeTool = new Noggit::Ui::hole_tool(this); - _tool_panel_dock->registerTool("Hole Cutter", holeTool); -} - -void MapView::setupAreaDesignatorUi() -{ - ZoneIDBrowser = new Noggit::Ui::zone_id_browser(this); - _tool_panel_dock->registerTool("Area Designator", ZoneIDBrowser); - - ZoneIDBrowser->setMapID(_world->getMapID()); - connect(ZoneIDBrowser, &Noggit::Ui::zone_id_browser::selected - , [this](int area_id) { changeZoneIDValue(area_id); } - ); -} - -void MapView::setupFlagUi() -{ - auto placeholder = new QWidget(this); - _tool_panel_dock->registerTool("Flag", placeholder); -} - -void MapView::setupWaterEditorUi() -{ - guiWater = new Noggit::Ui::water(&_displayed_water_layer, &_display_all_water_layers, this); - _tool_panel_dock->registerTool("Water Editor", guiWater); - - connect(guiWater, &Noggit::Ui::water::regenerate_water_opacity - , [this](float factor) - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_WATER); - _world->autoGenWaterTrans(_camera.position, factor); - NOGGIT_ACTION_MGR->endAction(); - } - ); - - connect(guiWater, &Noggit::Ui::water::crop_water - , [this] - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_WATER); - _world->CropWaterADT(_camera.position); - NOGGIT_ACTION_MGR->endAction(); - } - ); -} -void MapView::setupVertexPainterUi() -{ - shaderTool = new Noggit::Ui::ShaderTool(this, this); - _tool_panel_dock->registerTool("Vertex Painter", shaderTool); -} - -void MapView::setupScriptingUi() -{ - scriptingTool = new Noggit::Scripting::scripting_tool(this, this, _settings); - _tool_panel_dock->registerTool("Scripting", scriptingTool); -} - -void MapView::setupObjectEditorUi() -{ - // initialize some saved defaults - _object_paste_params.rotate_on_terrain = _settings->value("paste_params/rotate_on_terrain", true).toBool(); - - /* Tool */ - objectEditor = new Noggit::Ui::object_editor(this - , _world.get() - , &_move_model_to_cursor_position - , &_snap_multi_selection_to_ground - , &_use_median_pivot_point - , &_object_paste_params - , &_rotate_along_ground - , &_rotate_along_ground_smooth - , &_rotate_along_ground_random - , &_move_model_snap_to_objects - , this - ); - _tool_panel_dock->registerTool("Object Editor", objectEditor); - - /* Additional tools */ - - /* Area selection */ - _area_selection = new QRubberBand(QRubberBand::Rectangle, this); - - /* Object Palette */ - _object_palette = new Noggit::Ui::ObjectPalette(this, _project, this); - _object_palette->hide(); - - // Dock - _object_palette_dock = new QDockWidget("Object Palette", this); - _object_palette_dock->setFeatures(QDockWidget::DockWidgetMovable - | QDockWidget::DockWidgetFloatable - | QDockWidget::DockWidgetClosable - ); - - _object_palette_dock->setWidget(_object_palette); - _object_palette_dock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); - _main_window->addDockWidget(Qt::BottomDockWidgetArea, _object_palette_dock); - connect(this, &QObject::destroyed, _texture_palette_dock, &QObject::deleteLater); - // End Dock - - connect(_object_palette_dock, &QDockWidget::visibilityChanged, - [=](bool visible) - { - if (ui_hidden) - return; - - _settings->setValue ("map_view/object_palette", visible); - _settings->sync(); - }); - -} -void MapView::setupMinimapEditorUi() -{ - minimapTool = new Noggit::Ui::MinimapCreator(this, _world.get(), this); - _tool_panel_dock->registerTool("Minimap Editor", minimapTool); -} -void MapView::setupStampUi() -{ - stampTool = new Noggit::Ui::Tools::BrushStack(this, this); - _tool_panel_dock->registerTool("Stamp", stampTool); -} - -void MapView::setupLightEditorUi() -{ - lightEditor = new Noggit::Ui::Tools::LightEditor(this, this); - _tool_panel_dock->registerTool("Light Editor", lightEditor); -} - -void MapView::setupChunkManipulatorUi() -{ - _chunk_manipulator = new Noggit::Ui::Tools::ChunkManipulator::ChunkManipulatorPanel(this, this); - _tool_panel_dock->registerTool("Chunk Manipulator", _chunk_manipulator); -} - void MapView::setupNodeEditor() { auto _node_editor = new Noggit::Ui::Tools::NodeEditor::Ui::NodeEditorWidget(this); @@ -997,7 +550,6 @@ void MapView::setupAssetBrowser() });; connect(this, &QObject::destroyed, _asset_browser_dock, &QObject::deleteLater); - } void MapView::setupDetailInfos() @@ -1093,7 +645,7 @@ void MapView::updateDetailInfos() void MapView::setupToolbars() { - _toolbar = new Noggit::Ui::toolbar([this] (editing_mode mode) { set_editing_mode (mode); }); + _toolbar = new Noggit::Ui::toolbar(_tools, [this] (editing_mode mode) { set_editing_mode (mode); }); _toolbar->setOrientation(Qt::Vertical); auto left_toolbar_layout = new QVBoxLayout(_viewport_overlay_ui->leftToolbarHolder); left_toolbar_layout->addWidget( _toolbar); @@ -1203,6 +755,75 @@ void MapView::setupMainToolbar() // IDEAs : various client utils like synchronize client view with noggit, reload, patch WoW.exe with community patches like unlock md5 check, set WoW client version } +std::unique_ptr& MapView::activeTool() +{ + return _tools[_activeToolIndex]; +} + +void MapView::activeTool(editing_mode newTool) +{ + for (size_t i = 0; i < _tools.size(); ++i) + { + if (_tools[i]->editingMode() == newTool) + { + _activeToolIndex = i; + return; + } + } + + throw std::exception{ std::format("Tried to call MapView::activeTool with invalid editing_mode `{}`!", static_cast(newTool)).c_str() }; +} + +Noggit::Ui::Tools::ViewToolbar::Ui::ViewToolbar* MapView::getLeftSecondaryViewToolbar() +{ + return _left_sec_toolbar; +} + +QSettings* MapView::settings() +{ + return _settings; +} + +Noggit::Ui::Windows::NoggitWindow* MapView::mainWindow() +{ + return _main_window; +} + +bool MapView::isUiHidden() const +{ + return ui_hidden; +} + +bool MapView::drawAdtGrid() const +{ + return _draw_lines.get(); +} + +bool MapView::drawHoleGrid() const +{ + return _draw_hole_lines.get(); +} + +void MapView::invalidate() +{ + _needs_redraw = true; +} + +void MapView::selectObjects(std::array selection_box, float depth) +{ + _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), depth, _camera.position); +} + +std::shared_ptr& MapView::project() +{ + return _project; +} + +float MapView::timeSpeed() const +{ + return mTimespeed; +} + void MapView::setupKeybindingsGui() { _keybindings = new Noggit::Ui::help(this); @@ -1250,7 +871,7 @@ void MapView::setupFileMenu() makeCurrent(); OpenGL::context::scoped_setter const _ (::gl, context()); _world->reload_tile (_camera.position); - _rotation_editor_need_update = true; + emit rotationChanged(); emit saved(); } ); @@ -1343,28 +964,9 @@ void MapView::setupAssistMenu() auto assist_menu (_main_window->_menuBar->addMenu ("Assist")); connect (this, &QObject::destroyed, assist_menu, &QObject::deleteLater); - assist_menu->addSeparator(); - assist_menu->addAction(createTextSeparator("Model")); - assist_menu->addSeparator(); - ADD_ACTION (assist_menu, "Last M2 from WMV", "Shift+V", [this] { objectEditor->import_last_model_from_wmv(eMODEL); }); - ADD_ACTION (assist_menu, "Last WMO from WMV", "Alt+V", [this] { objectEditor->import_last_model_from_wmv(eWMO); }); - ADD_ACTION_NS (assist_menu, "Helper models", [this] { objectEditor->helper_models_widget->show(); }); - assist_menu->addSeparator(); assist_menu->addAction(createTextSeparator("Current ADT")); assist_menu->addSeparator(); - ADD_ACTION_NS( assist_menu - , "Set Area ID" - , [this] - { - if (terrainMode == editing_mode::areaid && _selected_area_id != -1) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_AREAID); - _world->setAreaID(_camera.position, _selected_area_id, true); - NOGGIT_ACTION_MGR->endAction(); - } - } - ); ADD_ACTION_NS ( assist_menu , "Ensure 4 texture layers" @@ -1446,7 +1048,7 @@ void MapView::setupAssistMenu() NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_REMOVED); _world->clearAllModelsOnADT(_camera.position, true); NOGGIT_ACTION_MGR->endAction(); - _rotation_editor_need_update = true; + emit rotationChanged(); } ); ADD_ACTION_NS ( cleanup_menu @@ -2283,16 +1885,9 @@ void MapView::setupViewMenu() QWidget *widget_list[] = { - _texture_browser_dock, - _texture_picker_dock, _detail_infos_dock, _keybindings, _minimap_dock, - objectEditor->modelImport, - objectEditor->rotationEditor, - objectEditor->helper_models_widget, - _texture_palette_small, - _object_palette_dock, _asset_browser_dock, _overlay_widget, _tool_panel_dock @@ -2332,14 +1927,10 @@ void MapView::setupViewMenu() ADD_TOGGLE (view_menu, "Detail infos", Qt::Key_F8, _show_detail_info_window); - ADD_TOGGLE (view_menu, "Texture Browser", Qt::Key_X, _show_texture_palette_window); - - ADD_TOGGLE_NS(view_menu, "Texture palette", _show_texture_palette_small_window); - addHotkey( Qt::Key_H , MOD_none - , [this] { _show_texture_palette_small_window.toggle(); } - , [this] { return terrainMode == editing_mode::paint; } + , [this] { activeTool()->onHotkeyPress("toggleTexturePalette"_hash); } + , [this] { return activeTool()->hotkeyCondition("toggleTexturePalette"_hash); } ); ADD_ACTION (view_menu, "Increase time speed", Qt::Key_N, [this] { mTimespeed += 90.0f; }); @@ -2407,6 +1998,17 @@ void MapView::setupViewMenu() } +void MapView::setupToolsMenu() +{ + auto menu(_main_window->_menuBar->addMenu("Tools")); + connect(this, &QObject::destroyed, menu, &QObject::deleteLater); + + for (auto&& tool : _tools) + { + tool->registerMenuItems(menu); + } +} + void MapView::setupHelpMenu() { auto help_menu (_main_window->_menuBar->addMenu ("Help")); @@ -2522,177 +2124,32 @@ void MapView::setupHotkeys() } ); - addHotkey ( Qt::Key_C - , MOD_ctrl - , [this] - { - objectEditor->copy_current_selection(_world.get()); - } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); - /* - addHotkey ( Qt::Key_C - , MOD_none - , [this] - { - objectEditor->copy_current_selection(_world.get()); - } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - );*/ + addHotkey(Qt::Key_C, MOD_ctrl, "copySelection"_hash); - addHotkey ( Qt::Key_V - , MOD_ctrl - , - [this] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED); - objectEditor->pasteObject (_cursor_pos, _camera.position, _world.get(), &_object_paste_params); - NOGGIT_ACTION_MGR->endAction(); - } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); - /* - addHotkey ( Qt::Key_V - , MOD_none - , [this] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED); - objectEditor->pasteObject (_cursor_pos, _camera.position, _world.get(), &_object_paste_params); - NOGGIT_ACTION_MGR->endAction(); - } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - );*/ - addHotkey ( Qt::Key_V - , MOD_shift - , [this] { objectEditor->import_last_model_from_wmv(eMODEL); } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); - addHotkey ( Qt::Key_V - , MOD_alt - , [this] { objectEditor->import_last_model_from_wmv(eWMO); } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_V, MOD_ctrl, "paste"_hash); - addHotkey ( Qt::Key_C - , MOD_none - , [this] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eVERTEX_SELECTION); - _world->clearVertexSelection(); - NOGGIT_ACTION_MGR->endAction(); - } - , [this] { return terrainMode == editing_mode::ground && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_V, MOD_shift, "importM2FromWmv"_hash); - addHotkey( Qt::Key_B - , MOD_ctrl - , [this] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED); - objectEditor->copy_current_selection(_world.get()); - objectEditor->pasteObject(_cursor_pos, _camera.position, _world.get(), &_object_paste_params); - NOGGIT_ACTION_MGR->endAction(); - } - , [this] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_V, MOD_alt, "importWmoFromWmv"_hash); - addHotkey ( Qt::Key_Y - , MOD_none - , [this] { terrainTool->nextType(); } - , [this] { return terrainMode == editing_mode::ground && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_C, MOD_none, "clearVertexSelection"_hash); - addHotkey ( Qt::Key_Y - , MOD_none - , [this] { flattenTool->nextFlattenType(); } - , [this] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_B, MOD_ctrl, "duplacteSelection"_hash); - addHotkey ( Qt::Key_T - , MOD_none - , [&] - { - flattenTool->toggleFlattenAngle(); - } - , [&] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_Y, MOD_none, "nextType"_hash); - addHotkey ( Qt::Key_T - , MOD_space - , [&] - { - _left_sec_toolbar->nextFlattenMode(this); - flattenTool->nextFlattenMode(); - } - , [&] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_T, MOD_none, "toggleAngle"_hash); - addHotkey ( Qt::Key_T - , MOD_none - , [&] - { - texturingTool->toggle_tool(); - } - , [&] { return terrainMode == editing_mode::paint && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_T, MOD_space, "nextMode"_hash); - addHotkey ( Qt::Key_T - , MOD_none - , [&] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_HOLES); - _world->setHoleADT (_camera.position, false); - NOGGIT_ACTION_MGR->endAction(); - } - , [&] - { - return terrainMode == editing_mode::holes && !NOGGIT_CUR_ACTION; - } - ); + addHotkey(Qt::Key_T, MOD_none, "toggleTool"_hash); - addHotkey ( Qt::Key_T - , MOD_alt - , [&] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_HOLES); - _world->setHoleADT (_camera.position, true); - NOGGIT_ACTION_MGR->endAction(); - } - , [&] { return terrainMode == editing_mode::holes && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_T, MOD_none, "unsetAdtHole"_hash); + addHotkey(Qt::Key_T, MOD_alt, "setAdtHole"_hash); - addHotkey(Qt::Key_F - , MOD_none - , [&] - { - if (_selected_area_id != -1) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_AREAID); - _world->setAreaID(_camera.position, _selected_area_id, true); - NOGGIT_ACTION_MGR->endAction(); - } - } - , [&] { return terrainMode == editing_mode::areaid && !NOGGIT_CUR_ACTION; } - ); - - addHotkey ( Qt::Key_T - , MOD_none - , [&] - { - guiWater->toggle_angled_mode(); - } - , [&] { return terrainMode == editing_mode::water && !NOGGIT_CUR_ACTION; } - ); - - addHotkey ( Qt::Key_T - , MOD_none - , [&] - { - objectEditor->togglePasteMode(); - } - , [&] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_T, MOD_none, "toggleAngled"_hash); + addHotkey(Qt::Key_T, MOD_none, "togglePasteMode"_hash); addHotkey ( Qt::Key_H , MOD_none @@ -2730,14 +2187,7 @@ void MapView::setupHotkeys() , [&] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } ); - addHotkey(Qt::Key_R - , MOD_space - , [&] - { - texturingTool->toggle_brush_level_min_max(); - } - , [&] { return terrainMode == editing_mode::paint && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_R, MOD_space, "setBrushLevelMinMax"_hash); addHotkey ( Qt::Key_H , MOD_shift @@ -2749,49 +2199,10 @@ void MapView::setupHotkeys() , [&] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } ); - addHotkey ( Qt::Key_F - , MOD_space - , [&] - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN); - terrainTool->flattenVertices (_world.get()); - NOGGIT_ACTION_MGR->endAction(); + addHotkey(Qt::Key_F, MOD_space, "toggleLock"_hash); + + addHotkey(Qt::Key_F, MOD_none, "lockCursor"_hash); - } - , [&] { return terrainMode == editing_mode::ground && !NOGGIT_CUR_ACTION; } - ); - addHotkey ( Qt::Key_F - , MOD_space - , [&] - { - flattenTool->toggleFlattenLock(); - } - , [&] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; } - ); - addHotkey ( Qt::Key_F - , MOD_none - , [&] - { - flattenTool->lockPos (_cursor_pos); - } - , [&] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; } - ); - addHotkey ( Qt::Key_F - , MOD_space - , [&] - { - guiWater->toggle_lock(); - } - , [&] { return terrainMode == editing_mode::water && !NOGGIT_CUR_ACTION; } - ); - addHotkey( Qt::Key_F - , MOD_none - , [&] - { - guiWater->lockPos(_cursor_pos); - } - , [&] { return terrainMode == editing_mode::water && !NOGGIT_CUR_ACTION; } - ); addHotkey ( Qt::Key_F , MOD_none , [&] @@ -2799,51 +2210,25 @@ void MapView::setupHotkeys() NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED); _world->set_selected_models_pos(_cursor_pos); - _rotation_editor_need_update = true; + emit rotationChanged(); NOGGIT_ACTION_MGR->endAction(); } , [&] { return terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION; } ); - addHotkey (Qt::Key_Plus, MOD_alt, [this] { terrainTool->changeRadius(0.01f); } - , [this] { return terrainMode == editing_mode::ground && !NOGGIT_CUR_ACTION; }); - - addHotkey (Qt::Key_Plus, MOD_alt, [this] { flattenTool->changeRadius(0.01f); } - , [this] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }); - - addHotkey ( Qt::Key_Plus - , MOD_alt - , [&] - { - texturingTool->change_radius(0.1f); - } - , [this] { return terrainMode == editing_mode::paint && !NOGGIT_CUR_ACTION; } - ); - - addHotkey (Qt::Key_Minus, MOD_alt, [this] { terrainTool->changeRadius(-0.01f); } - , [this] { return terrainMode == editing_mode::ground && !NOGGIT_CUR_ACTION; }); - - addHotkey (Qt::Key_Minus, MOD_alt, [this] { flattenTool->changeRadius(-0.01f); } - , [this] { return terrainMode == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }); - - addHotkey ( Qt::Key_Minus - , MOD_alt - , [&] - { - texturingTool->change_radius(-0.1f); - } - , [this] { return terrainMode == editing_mode::paint && !NOGGIT_CUR_ACTION; } - ); + addHotkey(Qt::Key_Plus, MOD_alt, "increaseRadius"_hash); + addHotkey(Qt::Key_Minus, MOD_alt, "decreaseRadius"_hash); addHotkey (Qt::Key_1, MOD_shift, [this] { _camera.move_speed = 15.0f; }); addHotkey (Qt::Key_2, MOD_shift, [this] { _camera.move_speed = 50.0f; }); addHotkey (Qt::Key_3, MOD_shift, [this] { _camera.move_speed = 200.0f; }); addHotkey (Qt::Key_4, MOD_shift, [this] { _camera.move_speed = 800.0f; }); - addHotkey (Qt::Key_1, MOD_alt, [this] { texturingTool->set_brush_level(0.0f); }); - addHotkey (Qt::Key_2, MOD_alt, [this] { texturingTool->set_brush_level(255.0f* 0.25f); }); - addHotkey (Qt::Key_3, MOD_alt, [this] { texturingTool->set_brush_level(255.0f* 0.5f); }); - addHotkey (Qt::Key_4, MOD_alt, [this] { texturingTool->set_brush_level(255.0f* 0.75f); }); - addHotkey (Qt::Key_5, MOD_alt, [this] { texturingTool->set_brush_level(255.0f); }); + + addHotkey(Qt::Key_1, MOD_alt, "setBrushLevel0Pct"_hash); + addHotkey(Qt::Key_2, MOD_alt, "setBrushLevel25Pct"_hash); + addHotkey(Qt::Key_3, MOD_alt, "setBrushLevel50Pct"_hash); + addHotkey(Qt::Key_4, MOD_alt, "setBrushLevel75Pct"_hash); + addHotkey(Qt::Key_5, MOD_alt, "setBrushLevel100Pct"_hash); addHotkey(Qt::Key_1, MOD_none, [this] { set_editing_mode(editing_mode::ground); } , [this] { return !_mod_num_down && !NOGGIT_CUR_ACTION; }); @@ -2876,6 +2261,24 @@ void MapView::setupHotkeys() addHotkey(Qt::Key_9, MOD_ctrl, [this] { change_selected_wmo_doodadset(9); }); addHotkey(Qt::Key_Escape, MOD_none, [this] { _main_window->close(); }); + + addHotkey(Qt::Key_Plus, MOD_none, "addColor"_hash); + + addHotkey(Qt::Key_2, MOD_num, "moveSelectedDown"_hash); + addHotkey(Qt::Key_8, MOD_num, "moveSelectedUp"_hash); + addHotkey(Qt::Key_4, MOD_num, "moveSelectedLeft"_hash); + addHotkey(Qt::Key_6, MOD_num, "moveSelectedRight"_hash); + + addHotkey(Qt::Key_3, MOD_num, "rotateSelectedPitchCcw"_hash); + addHotkey(Qt::Key_1, MOD_num, "rotateSelectedPitchCw"_hash); + + addHotkey(Qt::Key_7, MOD_num, "rotateSelectedYawCcw"_hash); + addHotkey(Qt::Key_9, MOD_num, "rotateSelectedYawCw"_hash); + + addHotkey(Qt::Key_Plus, MOD_num, "increaseSelectedScale"_hash); + addHotkey(Qt::Key_Minus, MOD_num, "decreaseSelectedScale"_hash); + + addHotkey(Qt::Key_F, MOD_none, "setAreaId"_hash); } void MapView::setupMinimap() @@ -2957,29 +2360,28 @@ void MapView::createGUI() connect(this, &QObject::destroyed, _tool_panel_dock, &QObject::deleteLater); _main_window->addDockWidget(Qt::RightDockWidgetArea, _tool_panel_dock); - // These calls need to be correctly ordered in order to work with the toolbar. - // TODO: fix + setupAssetBrowser(); + + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); + _tools.emplace_back(std::make_unique(this))->setupUi(_tool_panel_dock); - setupRaiseLowerUi(); - setupFlattenBlurUi(); - setupTexturePainterUi(); - setupHoleCutterUi(); - setupAreaDesignatorUi(); - setupFlagUi(); - setupWaterEditorUi(); - setupVertexPainterUi(); - setupObjectEditorUi(); - setupMinimapEditorUi(); - setupStampUi(); - setupLightEditorUi(); - setupScriptingUi(); - setupChunkManipulatorUi(); // End combined dock setupViewportOverlay(); // texturingTool->setup_ge_tool_renderer(); setupNodeEditor(); - setupAssetBrowser(); setupDetailInfos(); setupToolbars(); setupKeybindingsGui(); @@ -2988,6 +2390,7 @@ void MapView::createGUI() setupFileMenu(); setupEditMenu(); setupViewMenu(); + setupToolsMenu(); setupAssistMenu(); setupHelpMenu(); setupClientMenu(); @@ -2995,6 +2398,11 @@ void MapView::createGUI() setupMainToolbar(); + for (auto&& tool : _tools) + { + tool->postUiSetup(); + } + connect(_main_window, &Noggit::Ui::Windows::NoggitWindow::exitPromptOpened, this, &MapView::on_exit_prompt); set_editing_mode (editing_mode::ground); @@ -3018,14 +2426,7 @@ void MapView::on_exit_prompt() // hide all popups _keybindings->hide(); _minimap_dock->hide(); - _texture_palette_small->hide(); - _object_palette_dock->hide(); - objectEditor->helper_models_widget->hide(); - objectEditor->modelImport->hide(); - objectEditor->rotationEditor->hide(); _detail_infos_dock->hide(); - _texture_picker_dock->hide(); - _texture_browser_dock->hide(); } MapView::MapView( math::degrees camera_yaw0 @@ -3125,9 +2526,9 @@ MapView::MapView( math::degrees camera_yaw0 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&))); - connect(this, &MapView::selectionUpdated, [this]() + connect(this, &MapView::selectionUpdated, [this](std::vector&) { - updateDetailInfos(); + // updateDetailInfos(); }); moving = strafing = updown = lookat = turn = 0.0f; @@ -3309,257 +2710,6 @@ void MapView::initializeGL() _gl_initialized = true; } - -void MapView::saveMinimap(MinimapRenderSettings* settings) -{ - - OpenGL::context::scoped_setter const _ (::gl, context()); - - bool mmap_render_success = false; - - static QProgressBar* progress; - static QPushButton* cancel_btn; - - switch (settings->export_mode) - { - case MinimapGenMode::CURRENT_ADT: - { - TileIndex tile = TileIndex(_camera.position); - - if (_world->mapIndex.hasTile(tile)) - { - mmap_render_success = _world->renderer()->saveMinimap(tile, settings, _mmap_combined_image); - } - - if (mmap_render_success) - { - _world->mapIndex.saveMinimapMD5translate(); - } - - saving_minimap = false; - - break; - } - case MinimapGenMode::MAP: - { - - // init progress - if (!_mmap_async_index) - { - progress = new QProgressBar(nullptr); - progress->setMinimum(0); - progress->setMaximum(_world->mapIndex.getNumExistingTiles()); - _main_window->statusBar()->addPermanentWidget(progress); - - cancel_btn = new QPushButton(nullptr); - cancel_btn->setText("Cancel"); - - connect(cancel_btn, &QPushButton::clicked, - [=, this] - { - _mmap_async_index = 0; - _mmap_render_index = 0; - saving_minimap = false; - progress->deleteLater(); - cancel_btn->deleteLater(); - _mmap_combined_image.reset(); - }); - - _main_window->statusBar()->addPermanentWidget(cancel_btn); - - connect(this, &MapView::updateProgress, - [=](int value) - { - - progress->setValue(value); - }); - - // setup combined image if necessary - if (settings->combined_minimap) - { - _mmap_combined_image.emplace(8192, 8192, QImage::Format_RGBA8888); - _mmap_combined_image->fill(Qt::black); - } - - } - - if (!saving_minimap) - return; - - if (_mmap_async_index < 4096 && static_cast(_mmap_render_index) < progress->maximum()) - { - TileIndex tile = TileIndex(_mmap_async_index / 64, _mmap_async_index % 64); - - if (_world->mapIndex.hasTile(tile)) - { - OpenGL::context::scoped_setter const _(::gl, context()); - makeCurrent(); - mmap_render_success = _world->renderer()->saveMinimap(tile, settings, _mmap_combined_image); - - _mmap_render_index++; - emit updateProgress(_mmap_render_index); - - if (!mmap_render_success) - { - LogError << "Minimap rendered incorrectly for tile: " << tile.x << "_" << tile.z << std::endl; - } - } - - _mmap_async_index++; - } - else - { - _mmap_async_index = 0; - _mmap_render_index = 0; - saving_minimap = false; - progress->deleteLater(); - cancel_btn->deleteLater(); - _world->mapIndex.saveMinimapMD5translate(); - - // save combined minimap - if (settings->combined_minimap) - { - QString image_path = QString(std::string(_world->basename + "_combined_minimap.png").c_str()); - QSettings app_settings; - QString str = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str());; - if (!(str.endsWith('\\') || str.endsWith('/'))) - { - str += "/"; - } - - QDir dir(str + "/textures/minimap/"); - if (!dir.exists()) - dir.mkpath("."); - - _mmap_combined_image->save(dir.filePath(image_path)); - _mmap_combined_image.reset(); - } - - } - - //_main_window->statusBar()->showMessage("Minimap rendering done.", 2000); - break; - } - case MinimapGenMode::SELECTED_ADTS: - { - auto selected_tiles = minimapTool->getSelectedTiles(); - - // init progress - if (!_mmap_async_index) - { - progress = new QProgressBar(nullptr); - progress->setMinimum(0); - - unsigned n_selected_tiles = 0; - - for (int i = 0; i < 4096; ++i) - { - if (selected_tiles->at(i)) - n_selected_tiles++; - } - - progress->setMaximum(n_selected_tiles); - _main_window->statusBar()->addPermanentWidget(progress); - - cancel_btn = new QPushButton(nullptr); - cancel_btn->setText("Cancel"); - - connect(cancel_btn, &QPushButton::clicked, - [=, this] - { - _mmap_async_index = 0; - _mmap_render_index = 0; - saving_minimap = false; - progress->deleteLater(); - cancel_btn->deleteLater(); - _mmap_combined_image.reset(); - }); - - _main_window->statusBar()->addPermanentWidget(cancel_btn); - - connect(this, &MapView::updateProgress, - [=](int value) - { - // This weirdness is required due to a bug on Linux when QT repaint crashes due to too many events - // being passed through. TODO: this potentially only masks the issue, which may reappear on faster - // hardware. - if (progress->value() != value) - progress->setValue(value); - }); - - // setup combined image if necessary - if (settings->combined_minimap) - { - _mmap_combined_image.emplace(8192, 8192, QImage::Format_RGBA8888); - _mmap_combined_image->fill(Qt::black); - } - - } - - if (!saving_minimap) - return; - - - if (_mmap_async_index < 4096 && static_cast(_mmap_render_index) < progress->maximum()) - { - if (selected_tiles->at(_mmap_async_index)) - { - TileIndex tile = TileIndex(_mmap_async_index / 64, _mmap_async_index % 64); - - if (_world->mapIndex.hasTile(tile)) - { - mmap_render_success = _world->renderer()->saveMinimap(tile, settings, _mmap_combined_image); - _mmap_render_index++; - - emit updateProgress(_mmap_render_index); - - - if (!mmap_render_success) - { - LogError << "Minimap rendered incorrectly for tile: " << tile.x << "_" << tile.z << std::endl; - } - } - } - _mmap_async_index++; - - } - else - { - _mmap_async_index = 0; - _mmap_render_index = 0; - saving_minimap = false; - progress->deleteLater(); - cancel_btn->deleteLater(); - _world->mapIndex.saveMinimapMD5translate(); - - // save combined minimap - if (settings->combined_minimap) - { - QString image_path = QString(std::string(_world->basename + "_combined_minimap.png").c_str()); - QString str = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str()); - if (!(str.endsWith('\\') || str.endsWith('/'))) - { - str += "/"; - } - - QDir dir(str + "/textures/minimap/"); - if (!dir.exists()) - dir.mkpath("."); - - _mmap_combined_image->save(dir.filePath(image_path)); - _mmap_combined_image.reset(); - } - - } - - break; - - } - } - - //minimapTool->progressUpdate(0); -} - void MapView::paintGL() { ZoneScoped; @@ -3589,24 +2739,19 @@ void MapView::paintGL() _last_frame_durations.emplace_back (now - _last_update); - // minimap rendering - if (saving_minimap) + lock = true; + if (!activeTool()->preRender()) { - OpenGL::context::scoped_setter const _(::gl, context()); - makeCurrent(); - _camera_moved_since_last_draw = true; - lock = true; - saveMinimap(minimapTool->getMinimapRenderSettings()); - lock = false; - return; + lock = false; + return; } + lock = false; OpenGL::context::scoped_setter const _(::gl, context()); makeCurrent(); gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (!saving_minimap) { lock = true; draw_map(); @@ -3616,6 +2761,9 @@ void MapView::paintGL() _last_update = now; + lock = true; + activeTool()->postRender(); + lock = false; if (_gizmo_on.get() && _world->has_selection()) { @@ -3633,7 +2781,7 @@ void MapView::paintGL() _transform_gizmo.setCurrentGizmoOperation(_gizmo_operation); _transform_gizmo.setCurrentGizmoMode(_gizmo_mode); - _transform_gizmo.setUseMultiselectionPivot(_use_median_pivot_point.get()); + _transform_gizmo.setUseMultiselectionPivot(activeTool()->useMultiselectionPivot()); auto pivot = _world->multi_select_pivot().has_value() ? _world->multi_select_pivot().value() : glm::vec3(0.f, 0.f, 0.f); @@ -3699,7 +2847,7 @@ void MapView::paintGL() } - if (!saving_minimap && _world->uid_duplicates_found() && !_uid_duplicate_warning_shown) + if (_world->uid_duplicates_found() && !_uid_duplicate_warning_shown) { _uid_duplicate_warning_shown = true; @@ -3739,8 +2887,7 @@ MapView::~MapView() // when the uid fix fail the UI isn't created if (!_uid_fix_failed) { - delete TexturePicker; // explicitly delete this here to avoid opengl context related crash - delete objectEditor; + //delete objectEditor; // since the ground effect tool preview renderer got added, this causes crashing on exit to menu. // Now it crashes in application exit. @@ -3790,12 +2937,8 @@ void MapView::tick (float dt) action_modality |= Noggit::ActionModalityControllers::eLMB; if (rightMouse) action_modality |= Noggit::ActionModalityControllers::eRMB; - if (MoveObj) - action_modality |= Noggit::ActionModalityControllers::eMMB; - if (keys) - action_modality |= Noggit::ActionModalityControllers::eSCALE; - if (keyr) - action_modality |= Noggit::ActionModalityControllers::eROTATE; + + action_modality |= activeTool()->actionModality(); // if (keyx != 0 || keyy != 0 || keyz != 0) // action_modality |= Noggit::ActionModalityControllers::eTRANSLATE; @@ -3858,6 +3001,23 @@ void MapView::tick (float dt) // note : selection update most commonly happens in mouseReleaseEvent, which sets leftMouse to false bool selection_changed = false; + Noggit::TickParameters tickParams + { + .displayMode = _display_mode, + .underMap = _world->isUnderMap(_cursor_pos), + .left_mouse = leftMouse, + .right_mouse = rightMouse, + .mod_shift_down = _mod_shift_down, + .mod_ctrl_down = _mod_ctrl_down, + .mod_alt_down = _mod_alt_down, + .mod_num_down = _mod_num_down, + .dir = dir, + .dirUp = dirUp, + .dirRight = dirRight, + }; + + activeTool()->onTick(dt, tickParams); + auto currentSelection = _world->current_selection(); if (_world->has_selection()) { @@ -3865,557 +3025,10 @@ void MapView::tick (float dt) if (lastSelected != currentSelection) { selection_changed = true; - _rotation_editor_need_update = true; - } - - if (terrainMode == editing_mode::object) - { - // reset numpad_moveratio when no numpad key is pressed - if (!(keyx != 0 || keyy != 0 || keyz != 0 || keyr != 0 || keys != 0)) - { - numpad_moveratio = 0.5f; - } - else // Set move scale and rotate for numpad keys - { - if (_mod_ctrl_down && _mod_shift_down) - { - numpad_moveratio += 0.5f; - } - else if (_mod_shift_down) - { - numpad_moveratio += 0.05f; - } - else if (_mod_ctrl_down) - { - numpad_moveratio += 0.005f; - } - } - - if (keys != 0.f) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eSCALE); - _world->scale_selected_models(keys*numpad_moveratio / 50.f, World::m2_scaling_type::add); - _rotation_editor_need_update = true; - } - if (keyr != 0.f) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eROTATE); - _world->rotate_selected_models( math::degrees(0.f) - , math::degrees(keyr * numpad_moveratio * 5.f) - , math::degrees(0.f) - , _use_median_pivot_point.get() - ); - _rotation_editor_need_update = true; - } - - if (MoveObj) - { - if (_mod_alt_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eALT - | Noggit::ActionModalityControllers::eMMB ); - _world->scale_selected_models(std::pow(2.f, mv*4.f), World::m2_scaling_type::mult); - } - else if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eMMB ); - _world->move_selected_models(0.f, mv*80.f, 0.f); - } - else if (_mod_ctrl_down) - { - // do nothing - } - else - { - bool snapped = false; - bool snapped_to_object = false; - if (_world->has_multiple_model_selected()) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eMMB ); - _world->set_selected_models_pos(_cursor_pos, false); - - if (_snap_multi_selection_to_ground.get()) - { - snap_selected_models_to_the_ground(); - snapped = true; - } - } - else - { - if (!_move_model_to_cursor_position.get()) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eMMB ); - - if ((mh <= 0.01f && mh >= -0.01f) && (mv <= 0.01f && mv >= -0.01f)) - { - glm::vec3 _vec = (mh * dirUp + mv * dirRight); - _world->move_selected_models(_vec * 500.f); - } - } - else - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eMMB ); - - if (_move_model_to_cursor_position.get() || _move_model_snap_to_objects.get()) - { - selection_result results(intersect_result(false)); - - if (!results.empty()) - { - for (auto result = results.begin(); result != results.end(); result++) - { - auto const& hit(result->second); - bool is_selected_model = false; - - // if a terrain is found first use that (terrain cursor pos position updated on move already) - if (hit.index() == eEntry_MapChunk && _move_model_to_cursor_position.get()) - { - break; - } - - if (hit.index() == eEntry_Object && _move_model_snap_to_objects.get()) - { - auto obj_hit = std::get(hit); - auto obj_hit_type = obj_hit->which(); - - // don't snap to animated models - if (obj_hit_type == eMODEL) - { - auto m2_model_hit = static_cast(obj_hit); - if (m2_model_hit->model->animated_mesh()) - continue; - } - - // find and ignore current object/selected models or it will keep snaping to itself - for (auto& entry : _world->current_selection()) - { - auto type = entry.index(); - if (type == eEntry_Object) - { - auto& selection_obj = std::get(entry); - if (selection_obj->uid == obj_hit->uid) - { - is_selected_model = true; - break; - } - } - } - if (is_selected_model) - continue; - auto hit_pos = intersect_ray().position(result->first); - _cursor_pos = hit_pos; - snapped_to_object = true; - // TODO : rotate objects to objects normal - // if (_rotate_doodads_along_doodads.get()) - // _world->rotate_selected_models_to_object_normal(_rotate_along_ground_smooth.get(), obj_hit, hit_pos, glm::transpose(model_view()), _rotate_doodads_along_wmos.get()); - break; - } - } - } - _world->set_selected_models_pos(_cursor_pos, false); - snapped = true; - } - } - } - - if (snapped && _rotate_along_ground.get()) - { - if (!snapped_to_object) - _world->rotate_selected_models_to_ground_normal(_rotate_along_ground_smooth.get()); - - if (_rotate_along_ground_random.get()) - { - float minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0; - - if (_settings->value("model/random_rotation", false).toBool()) - { - minY = _object_paste_params.minRotation; - maxY = _object_paste_params.maxRotation; - } - - if (_settings->value("model/random_tilt", false).toBool()) - { - minX = _object_paste_params.minTilt; - maxX = _object_paste_params.maxTilt; - minZ = minX; - maxZ = maxX; - } - - _world->rotate_selected_models_randomly( - minX, - maxX, - minY, - maxY, - minZ, - maxZ); - - if (_settings->value("model/random_size", false).toBool()) - { - float min = _object_paste_params.minScale; - float max = _object_paste_params.maxScale; - - _world->scale_selected_models(misc::randfloat(min, max), World::m2_scaling_type::set); - } - } - } - - - } - - _rotation_editor_need_update = true; - } - - /* TODO: Numpad for action system - if (keyx != 0.f || keyy != 0.f || keyz != 0.f) - { - _world->move_selected_models(keyx * numpad_moveratio, keyy * numpad_moveratio, keyz * numpad_moveratio); - _rotation_editor_need_update = true; - } - */ - - if (look) - { - if (_mod_ctrl_down) // X - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eRMB ); - _world->rotate_selected_models( math::degrees(rh + rv) - , math::degrees(0.f) - , math::degrees(0.f) - , _use_median_pivot_point.get() - ); - } - if (_mod_shift_down) // Y - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eRMB ); - _world->rotate_selected_models( math::degrees(0.f) - , math::degrees(rh + rv) - , math::degrees(0.f) - , _use_median_pivot_point.get() - ); - } - if (_mod_alt_down) // Z - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, - Noggit::ActionModalityControllers::eALT - | Noggit::ActionModalityControllers::eRMB ); - _world->rotate_selected_models( math::degrees(0.f) - , math::degrees(0.f) - , math::degrees(rh + rv) - , _use_median_pivot_point.get() - ); - } - - _rotation_editor_need_update = true; - } - } - - for (auto& selection : currentSelection) - { - if (selection.index() == eEntry_MapChunk && terrainMode == editing_mode::scripting) - { - scriptingTool->sendBrushEvent(_cursor_pos, 7.5f * dt); - } - - if (leftMouse && selection.index() == eEntry_MapChunk) - { - bool underMap = _world->isUnderMap(_cursor_pos); - auto cur_action = NOGGIT_CUR_ACTION; - - switch (terrainMode) - { - case editing_mode::ground: - if (_display_mode == display_mode::in_3D && !underMap) - { - auto mask_selector = terrainTool->getImageMaskSelector(); - - if (_mod_shift_down && (!mask_selector->isEnabled() || mask_selector->getBrushMode())) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeTerrainRotation); - - terrainTool->changeTerrain(_world.get(), _cursor_pos, 7.5f * dt); - } - else if (_mod_ctrl_down && (!mask_selector->isEnabled() || mask_selector->getBrushMode())) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeTerrainRotation); - - terrainTool->changeTerrain(_world.get(), _cursor_pos, -7.5f * dt); - } - } - break; - case editing_mode::flatten_blur: - if (_display_mode == display_mode::in_3D && !underMap) - { - if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - flattenTool->flatten(_world.get(), _cursor_pos, dt); - } - else if (_mod_ctrl_down) - { - - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - flattenTool->blur(_world.get(), _cursor_pos, dt); - } - } - break; - case editing_mode::paint: - - if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect) - { - if (_mod_shift_down) - { - if (texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::exclusion) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - _world->paintGroundEffectExclusion(_cursor_pos, texturingTool->getGroundEffectsTool()->radius(), true); - // _world->setHole(_cursor_pos, holeTool->brushRadius(), _mod_alt_down, false); - } - else if (texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::effect) - { - - } - - } - else if (_mod_ctrl_down && !underMap) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - _world->paintGroundEffectExclusion(_cursor_pos, texturingTool->getGroundEffectsTool()->radius(), false); - } - } - else - { - if (_mod_shift_down && _mod_ctrl_down && _mod_alt_down) - { - // clear chunk texture - if (!underMap) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eALT - | Noggit::ActionModalityControllers::eLMB); - - _world->eraseTextures(_cursor_pos); - } - } - else if (_mod_ctrl_down && !ui_hidden) - { - _texture_picker_need_update = true; - // Pick texture - // _texture_picker_dock->setVisible(true); - // TexturePicker->setMainTexture(texturingTool->_current_texture); - // TexturePicker->getTextures(selection); - } - else if (_mod_shift_down && !!Noggit::Ui::selected_texture::get()) - { - if ((_display_mode == display_mode::in_3D && !underMap) || _display_mode == display_mode::in_2D) - { - auto image_mask_selector = texturingTool->getImageMaskSelector(); - - if (NOGGIT_CUR_ACTION - && texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint - && image_mask_selector->isEnabled() - && !image_mask_selector->getBrushMode()) - break; - - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeTexturingRotation); - - if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint - && image_mask_selector->isEnabled() - && !image_mask_selector->getBrushMode()) - action->setBlockCursor(true); - - texturingTool->paint(_world.get(), _cursor_pos, dt, *Noggit::Ui::selected_texture::get()); - } - } - } - - - break; - - case editing_mode::holes: - // no undermap check here, else it's impossible to remove holes - if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_HOLES, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - _world->setHole(_cursor_pos, holeTool->brushRadius(),_mod_alt_down, false); - } - else if (_mod_ctrl_down && !underMap) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_HOLES, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - _world->setHole(_cursor_pos, holeTool->brushRadius(), _mod_alt_down, true); - } - break; - case editing_mode::areaid: - if (!underMap) - { - if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_AREAID, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - // draw the selected AreaId on current selected chunk - _world->setAreaID(_cursor_pos, _selected_area_id, false, ZoneIDBrowser->brushRadius()); - } - else if (_mod_ctrl_down) - { - // pick areaID from chunk - _area_picker_need_update = true; - // MapChunk* chnk(std::get(selection).chunk); - // int newID = chnk->getAreaID(); - // _selected_area_id = newID; - // ZoneIDBrowser->setZoneID(newID); - } - } - break; - case editing_mode::impass: - if (!underMap) - { - // todo: replace this - if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_FLAGS, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - _world->mapIndex.setFlag(true, _cursor_pos, 0x2); - } - else if (_mod_ctrl_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_FLAGS, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - _world->mapIndex.setFlag(false, _cursor_pos, 0x2); - } - } - break; - case editing_mode::water: - if (_display_mode == display_mode::in_3D && !underMap) - { - if (_mod_shift_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_WATER, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - guiWater->paintLiquid(_world.get(), _cursor_pos, true); - } - else if (_mod_ctrl_down) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_WATER, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - guiWater->paintLiquid(_world.get(), _cursor_pos, false); - } - } - break; - case editing_mode::stamp: - if (_display_mode == display_mode::in_3D && (_mod_shift_down || _mod_ctrl_down || _mod_alt_down) && stampTool->getBrushMode()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eNO_FLAG, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - if (!stampTool->getBrushMode()) - action->setBlockCursor(true); - - stampTool->execute(_cursor_pos, _world.get(), dt, _mod_shift_down, _mod_alt_down, _mod_ctrl_down, underMap); - } - break; - case editing_mode::mccv: - if (!underMap) - { - if (_mod_shift_down) - { - - auto image_mask_selector = shaderTool->getImageMaskSelector(); - - if (NOGGIT_CUR_ACTION - && image_mask_selector->isEnabled() - && !image_mask_selector->getBrushMode()) - break; - - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_VERTEX_COLOR, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeShaderRotation); - - if (image_mask_selector->isEnabled() && !image_mask_selector->getBrushMode()) - action->setBlockCursor(true); - - shaderTool->changeShader(_world.get(), _cursor_pos, dt, true); - } - if (_mod_ctrl_down) - { - - auto image_mask_selector = shaderTool->getImageMaskSelector(); - - if (NOGGIT_CUR_ACTION - && image_mask_selector->isEnabled() - && !image_mask_selector->getBrushMode()) - break; - - - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_VERTEX_COLOR, - Noggit::ActionModalityControllers::eCTRL - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeShaderRotation); - - if (image_mask_selector->isEnabled() && !image_mask_selector->getBrushMode()) - action->setBlockCursor(true); - - shaderTool->changeShader(_world.get(), _cursor_pos, dt, false); - } - } - break; - default: - break; - } - } + emit rotationChanged(); } } - mh = 0; - mv = 0; - rh = 0; - rv = 0; - if (_display_mode == display_mode::in_3D) { if (turn) @@ -4519,9 +3132,6 @@ void MapView::tick (float dt) _world->time += this->mTimespeed * dt; _world->animtime += dt * 1000.0f; - if (mTimespeed > 0.0f) - lightEditor->UpdateWorldTime(); - if (_draw_model_animations.get()) { _world->update_models_emitters(dt); @@ -4532,12 +3142,6 @@ void MapView::tick (float dt) lastSelected = currentSelection; } - if (_rotation_editor_need_update) - { - objectEditor->rotationEditor->updateValues(_world.get()); - _rotation_editor_need_update = false; - } - QString status; status += ( QString ("tile: %1 %2") . arg (std::floor (_camera.position.x / TILESIZE)) @@ -4602,28 +3206,8 @@ void MapView::tick (float dt) if (selection_changed) { - // emit selectionUpdated(); + emit selectionUpdated(currentSelection); // updateDetailInfos(); - - // update areaid and texture picker - if (_texture_picker_need_update) - { - _texture_picker_dock->setVisible(true); - TexturePicker->setMainTexture(texturingTool->_current_texture); - TexturePicker->getTextures(*currentSelection.begin()); - - _texture_picker_need_update = false; - } - - if (_area_picker_need_update) - { - MapChunk* chnk(std::get(*currentSelection.begin()).chunk); - int newID = chnk->getAreaID(); - _selected_area_id = newID; - ZoneIDBrowser->setZoneID(newID); - - _area_picker_need_update = false; - } } _status_area->setText @@ -4666,8 +3250,6 @@ void MapView::tick (float dt) + "\t Loaded objects: " + QString::number(_world->getModelInstanceStorage().getTotalModelsCount()) + ", Rendered objects: " + QString::number(_world->getNumRenderedObjects()) ); - - guiWater->updatePos (_camera.position); } glm::vec4 MapView::normalized_device_coords (int x, int y) const @@ -4751,20 +3333,7 @@ void MapView::doSelection (bool selectTerrainOnly, bool mouseMove) if (terrainMode == editing_mode::object || terrainMode == editing_mode::minimap) { - float radius = 0.0f; - switch (terrainMode) - { - case editing_mode::object: - radius = objectEditor->brushRadius(); - break; - - case editing_mode::minimap: - radius = minimapTool->brushRadius(); - break; - - default: - break; - } + float radius = activeTool()->brushRadius(); if (_mod_shift_down) { @@ -4815,8 +3384,7 @@ void MapView::doSelection (bool selectTerrainOnly, bool mouseMove) } - _rotation_editor_need_update = true; - objectEditor->update_selection_ui(_world.get()); + emit rotationChanged(); } void MapView::update_cursor_pos() @@ -4934,66 +3502,26 @@ void MapView::draw_map() _cursorType = CursorType::CIRCLE; - switch (terrainMode) - { - case editing_mode::ground: - radius = terrainTool->brushRadius(); - inner_radius = terrainTool->innerRadius(); - if ((terrainTool->_edit_type != eTerrainType_Vertex && terrainTool->_edit_type != eTerrainType_Script) && terrainTool->getImageMaskSelector()->isEnabled()) - _cursorType = CursorType::STAMP; - break; - case editing_mode::flatten_blur: - radius = flattenTool->brushRadius(); - angle = flattenTool->angle(); - orientation = flattenTool->orientation(); - ref_pos = flattenTool->ref_pos(); - angled_mode = flattenTool->angled_mode(); - use_ref_pos = flattenTool->use_ref_pos(); - break; - case editing_mode::paint: - radius = texturingTool->brush_radius(); - inner_radius = texturingTool->hardness(); - if(texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint && texturingTool->getImageMaskSelector()->isEnabled()) - _cursorType = CursorType::STAMP; - break; - case editing_mode::stamp: - radius = stampTool->getRadius(); - inner_radius = stampTool->getInnerRadius(); - if(stampTool->getActiveBrushItem() && stampTool->getActiveBrushItem()->isMaskEnabled()) - _cursorType = CursorType::STAMP; - break; - case editing_mode::water: - radius = guiWater->brushRadius(); - angle = guiWater->angle(); - orientation = guiWater->orientation(); - ref_pos = guiWater->ref_pos(); - angled_mode = guiWater->angled_mode(); - use_ref_pos = guiWater->use_ref_pos(); - break; - case editing_mode::mccv: - radius = shaderTool->brushRadius(); - if(shaderTool->getImageMaskSelector()->isEnabled()) - _cursorType = CursorType::STAMP; - break; - case editing_mode::areaid: - radius = ZoneIDBrowser->brushRadius(); - break; - case editing_mode::holes: - radius = holeTool->brushRadius(); - break; - case editing_mode::object: - radius = objectEditor->brushRadius(); - break; - case editing_mode::minimap: - radius = minimapTool->brushRadius(); - break; - case editing_mode::scripting: - radius = scriptingTool->get_settings()->brushRadius(); - inner_radius = scriptingTool->get_settings()->innerRadius(); - break; - default: - break; - } + eTerrainType terrainType = eTerrainType_Flat; + bool show_unpaintable_chunks = false; + int displayed_water_layer = -1; + auto cursorColor = cursor_color; + MinimapRenderSettings minimapRenderSettings; + + auto draw_parameters = activeTool()->drawParameters(); + radius = draw_parameters.radius; + inner_radius = draw_parameters.inner_radius; + _cursorType = draw_parameters.cursor_type; + terrainType = draw_parameters.terrain_type; + angle = draw_parameters.angle; + orientation = draw_parameters.orientation; + ref_pos = draw_parameters.ref_pos; + angled_mode = draw_parameters.angled_mode; + use_ref_pos = draw_parameters.use_ref_pos; + show_unpaintable_chunks = draw_parameters.show_unpaintable_chunks; + displayed_water_layer = draw_parameters.displayed_water_layer; + cursorColor = draw_parameters.cursor_color; + minimapRenderSettings = draw_parameters.minimapRenderSettings; //! \note Select terrain below mouse, if no item selected or the item is map. if (!(_world->has_selection() @@ -5008,17 +3536,18 @@ void MapView::draw_map() } bool classic_ui = _settings->value("classicUI", false).toBool(); - bool show_unpaintable = classic_ui ? texturingTool->show_unpaintable_chunks() : _left_sec_toolbar->showUnpaintableChunk(); + bool show_unpaintable = classic_ui ? show_unpaintable_chunks : _left_sec_toolbar->showUnpaintableChunk(); bool debug_cam = _debug_cam_mode.get(); // math::frustum frustum(model_view(debug_cam) * projection()); + _world->renderer()->draw ( model_view(debug_cam) , projection() , _cursor_pos , _cursorRotation - , terrainMode == editing_mode::mccv ? shaderTool->shaderColor() : cursor_color + , cursorColor , _cursorType , radius , show_unpaintable @@ -5046,10 +3575,10 @@ void MapView::draw_map() , _draw_hidden_models.get() , _draw_sky.get() , _draw_skybox.get() - , minimapTool->getMinimapRenderSettings() + , &minimapRenderSettings , _draw_fog.get() - , terrainTool->_edit_type - , _display_all_water_layers.get() ? -1 : _displayed_water_layer.get() + , terrainType + , displayed_water_layer , _display_mode , _draw_occlusion_boxes.get() ,false @@ -5083,7 +3612,7 @@ void MapView::keyPressEvent (QKeyEvent *event) makeCurrent(); OpenGL::context::scoped_setter const _ (::gl, context()); - hotkey.function(); + hotkey.onPress(); return; } } @@ -5136,61 +3665,6 @@ void MapView::keyPressEvent (QKeyEvent *event) updown = -1.0f; } - if (event->key() == Qt::Key_2 && event->modifiers() & Qt::KeypadModifier) - { - keyx = 1; - } - if (event->key() == Qt::Key_8 && event->modifiers() & Qt::KeypadModifier) - { - keyx = -1; - } - - if (event->key() == Qt::Key_4 && event->modifiers() & Qt::KeypadModifier) - { - keyz = 1; - } - if (event->key() == Qt::Key_6 && event->modifiers() & Qt::KeypadModifier) - { - keyz = -1; - } - - if (event->key() == Qt::Key_3 && event->modifiers() & Qt::KeypadModifier) - { - keyy = 1; - } - if (event->key() == Qt::Key_1 && event->modifiers() & Qt::KeypadModifier) - { - keyy = -1; - } - - if (event->key() == Qt::Key_7 && event->modifiers() & Qt::KeypadModifier) - { - keyr = 1; - } - if (event->key() == Qt::Key_9 && event->modifiers() & Qt::KeypadModifier) - { - keyr = -1; - } - - if (event->key() == Qt::Key_Plus) - { - keys = 1; - - switch (terrainMode) - { - case editing_mode::mccv: - { - shaderTool->addColorToPalette(); - break; - } - default: - break; - } - } - if (event->key() == Qt::Key_Minus) - { - keys = -1; - } if (event->key() == Qt::Key_Home) { _camera.position = glm::vec3(_cursor_pos.x, _cursor_pos.y + 50, _cursor_pos.z); @@ -5265,6 +3739,27 @@ void MapView::keyReleaseEvent (QKeyEvent* event) checkInputsSettings(); + size_t const modifier + (((event->modifiers() & Qt::ShiftModifier) ? MOD_shift : 0) + | ((event->modifiers() & Qt::ControlModifier) ? MOD_ctrl : 0) + | ((event->modifiers() & Qt::AltModifier) ? MOD_alt : 0) + | ((event->modifiers() & Qt::MetaModifier) ? MOD_meta : 0) + | ((event->modifiers() & Qt::KeypadModifier) ? MOD_num : 0) + | (_mod_space_down ? MOD_space : 0) + ); + for (auto&& hotkey : hotkeys) + { + auto k = event->key(); + if (k == hotkey.key && modifier == hotkey.modifiers && hotkey.condition()) + { + makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, context()); + + hotkey.onRelease(); + return; + } + } + // movement if (event->key() == _inputs[0] || event->key() == _inputs[1]) { @@ -5290,32 +3785,6 @@ void MapView::keyReleaseEvent (QKeyEvent* event) { updown = 0.0f; } - - - if ((event->key() == Qt::Key_2 || event->key() == Qt::Key_8) && event->modifiers() & Qt::KeypadModifier) - { - keyx = 0.0f; - } - - if ((event->key() == Qt::Key_4 || event->key() == Qt::Key_6) && event->modifiers() & Qt::KeypadModifier) - { - keyz = 0.0f; - } - - if ((event->key() == Qt::Key_3 || event->key() == Qt::Key_1) && event->modifiers() & Qt::KeypadModifier) - { - keyy = 0.0f; - } - - if ((event->key() == Qt::Key_7 || event->key() == Qt::Key_9) && event->modifiers() & Qt::KeypadModifier) - { - keyr = 0.0f; - } - - if (event->key() == Qt::Key_Plus || event->key() == Qt::Key_Minus) - { - keys = 0.0f; - } if (event->key() == Qt::Key_L || event->key() == Qt::Key_Minus) { @@ -5351,17 +3820,12 @@ void MapView::focusOutEvent (QFocusEvent*) strafing = 0.0f; updown = 0.0f; - keyx = 0; - keyz = 0; - keyy = 0; - keyr = 0; - keys = 0; - leftMouse = false; rightMouse = false; - MoveObj = false; look = false; freelook = false; + + activeTool()->onFocusLost(); } void MapView::mouseMoveEvent (QMouseEvent* event) @@ -5378,242 +3842,20 @@ void MapView::mouseMoveEvent (QMouseEvent* event) _camera_moved_since_last_draw = true; } - if (MoveObj) - { - mh = -aspect_ratio()*relative_movement.dx() / static_cast(width()); - mv = -relative_movement.dy() / static_cast(height()); - } - else - { - mh = 0.0f; - mv = 0.0f; - } + Noggit::MouseMoveParameters params{ + .displayMode = _display_mode, + .left_mouse = leftMouse, + .right_mouse = rightMouse, + .mod_shift_down = _mod_shift_down, + .mod_ctrl_down = _mod_ctrl_down, + .mod_alt_down = _mod_alt_down, + .mod_num_down = _mod_num_down, + .mod_space_down = _mod_space_down, + .relative_movement = relative_movement, + .mouse_position = event->pos() + }; - if (_mod_shift_down || _mod_ctrl_down || _mod_alt_down || _mod_space_down) - { - rh = relative_movement.dx() / XSENS * 5.0f; - rv = relative_movement.dy() / YSENS * 5.0f; - } - - if (rightMouse && _mod_alt_down && !_mod_shift_down && !_mod_ctrl_down) - { - if (terrainMode == editing_mode::ground) - { - if (terrainTool->_edit_type == eTerrainType_Vertex) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eALT | Noggit::ActionModalityControllers::eRMB); - terrainTool->changeOrientation (-relative_movement.dx() / XSENS * 4.5f); - } - else - { - terrainTool->changeInnerRadius(relative_movement.dx() / 100.0f); - } - - } - else if (terrainMode == editing_mode::paint) - { - texturingTool->change_hardness(relative_movement.dx() / 300.0f); - } - else if (terrainMode == editing_mode::stamp) - { - stampTool->changeInnerRadius(relative_movement.dx() / 300.0f); - } - } - - if (rightMouse && _mod_shift_down && !_mod_alt_down && !_mod_ctrl_down) - { - if (terrainMode == editing_mode::ground) - { - if (terrainTool->_edit_type == eTerrainType_Vertex) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eSHIFT | Noggit::ActionModalityControllers::eRMB); - terrainTool->moveVertices (_world.get(), -relative_movement.dy() / YSENS); - } - } - } - - if (rightMouse && _mod_ctrl_down && !_mod_alt_down && !_mod_shift_down) - { - if (terrainMode == editing_mode::ground) - { - if (terrainTool->_edit_type == eTerrainType_Vertex) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eCTRL | - Noggit::ActionModalityControllers::eRMB); - terrainTool->changeAngle(-relative_movement.dy() / YSENS * 4.f); - } - } - } - - - if (rightMouse && _mod_space_down) - { - if (terrainMode == editing_mode::ground) - { - if (terrainTool->_edit_type == eTerrainType_Vertex) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eRMB - | Noggit::ActionModalityControllers::eSPACE); - terrainTool->setOrientRelativeTo(_world.get(), _cursor_pos); - } - else if (terrainTool->getImageMaskSelector()->isEnabled()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, - Noggit::ActionModalityControllers::eRMB - | Noggit::ActionModalityControllers::eSPACE); - terrainTool->getImageMaskSelector()->setRotation(-relative_movement.dx() / XSENS * 10.f); - action->setBlockCursor(true); - } - - } - else if (terrainMode == editing_mode::paint) - { - if (texturingTool->getImageMaskSelector()->isEnabled()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, - Noggit::ActionModalityControllers::eRMB - | Noggit::ActionModalityControllers::eSPACE); - texturingTool->getImageMaskSelector()->setRotation(-relative_movement.dx() / XSENS * 10.f); - action->setBlockCursor(true); - - } - - } - else if (terrainMode == editing_mode::mccv) - { - if (shaderTool->getImageMaskSelector()->isEnabled()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, - Noggit::ActionModalityControllers::eRMB - | Noggit::ActionModalityControllers::eSPACE); - shaderTool->getImageMaskSelector()->setRotation(-relative_movement.dx() / XSENS * 10.f); - action->setBlockCursor(true); - - } - - } - else if (terrainMode == editing_mode::stamp) - { - - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, - Noggit::ActionModalityControllers::eRMB - | Noggit::ActionModalityControllers::eSPACE); - stampTool->changeRotation(-relative_movement.dx() / XSENS * 10.f); - action->setBlockCursor(true); - } - } - - if (leftMouse && _mod_alt_down && !_mod_shift_down && !_mod_ctrl_down) - { - switch (terrainMode) - { - case editing_mode::ground: - terrainTool->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::flatten_blur: - flattenTool->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::paint: - texturingTool->change_radius(relative_movement.dx() / XSENS); - break; - case editing_mode::water: - guiWater->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::mccv: - shaderTool->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::areaid: - ZoneIDBrowser->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::holes: - holeTool->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::object: - objectEditor->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::minimap: - minimapTool->changeRadius(relative_movement.dx() / XSENS); - break; - case editing_mode::stamp: - stampTool->changeRadius(relative_movement.dx() / XSENS); - break; - default: - break; - } - } - - if (leftMouse && _mod_space_down) - { - switch (terrainMode) - { - case editing_mode::ground: - terrainTool->changeSpeed(relative_movement.dx() / 30.0f); - break; - case editing_mode::flatten_blur: - flattenTool->changeSpeed(relative_movement.dx() / 30.0f); - break; - case editing_mode::paint: - texturingTool->change_pressure(relative_movement.dx() / 300.0f); - break; - case editing_mode::mccv: - shaderTool->changeSpeed(relative_movement.dx() / XSENS); - break; - case editing_mode::stamp: - stampTool->changeSpeed(relative_movement.dx() / XSENS); - break; - default: - break; - } - } - - if (leftMouse && (_mod_shift_down || _mod_ctrl_down)) - { - if (terrainMode == editing_mode::object || terrainMode == editing_mode::minimap) - { - doSelection(false, true); // Required for radius selection in Object mode - } - } - // drag selection, only do it when not using brush - else if (!_mod_alt_down && leftMouse && terrainMode == editing_mode::object && _display_mode == display_mode::in_3D && !ImGuizmo::IsUsing()) - { - _needs_redraw = true; - _area_selection->setGeometry(QRect(_drag_start_pos, event->pos()).normalized()); - } - - if (leftMouse && _mod_shift_down) - { - if (terrainMode == editing_mode::ground && _display_mode == display_mode::in_3D) - { - auto image_mask_selector = terrainTool->getImageMaskSelector(); - if (terrainTool->_edit_type != eTerrainType_Vertex && terrainTool->_edit_type != eTerrainType_Script && - image_mask_selector->isEnabled() && !image_mask_selector->getBrushMode()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeTerrainRotation); - - terrainTool->changeTerrain(_world.get(), _cursor_pos, relative_movement.dx() / 30.0f); - } - } - else if (terrainMode == editing_mode::stamp && _display_mode == display_mode::in_3D && !stampTool->getBrushMode()) - { - auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eNO_FLAG, - Noggit::ActionModalityControllers::eSHIFT - | Noggit::ActionModalityControllers::eLMB); - - action->setPostCallback(&MapView::randomizeStampRotation); - action->setBlockCursor(true); - - stampTool->execute(_cursor_pos, _world.get(), relative_movement.dx() / 30.0f, _mod_shift_down, _mod_alt_down, _mod_ctrl_down, false); - } - - } + activeTool()->onMouseMove(params); if (_display_mode == display_mode::in_2D && leftMouse && _mod_alt_down && _mod_shift_down) { @@ -5686,6 +3928,12 @@ void MapView::mousePressEvent(QMouseEvent* event) makeCurrent(); OpenGL::context::scoped_setter const _(::gl, context()); + activeTool()->onMousePress({ + .button = event->button(), + .mouse_position = event->pos(), + .mod_ctrl_down = _mod_ctrl_down, + }); + switch (event->button()) { case Qt::LeftButton: @@ -5696,28 +3944,14 @@ void MapView::mousePressEvent(QMouseEvent* event) rightMouse = true; break; - case Qt::MiddleButton: - if (_world->has_selection()) - { - MoveObj = true; - } - - if(terrainMode == editing_mode::mccv) - { - shaderTool->pickColor(_world.get(), _cursor_pos); - } - break; - default: break; } - if (leftMouse && ((terrainMode == editing_mode::object || terrainMode == editing_mode::minimap) && !_mod_ctrl_down)) + if (leftMouse && terrainMode == editing_mode::minimap && !_mod_ctrl_down) { _drag_start_pos = event->pos(); _needs_redraw = true; - _area_selection->setGeometry(QRect(_drag_start_pos, QSize())); - _area_selection->show(); } if (rightMouse) @@ -5746,53 +3980,16 @@ void MapView::wheelEvent (QWheelEvent* event) } ); - if (terrainMode == editing_mode::paint) + Noggit::MouseWheelParameters params { - if (_mod_space_down) - { - texturingTool->change_brush_level (delta_for_range (255.f)); - } - else if (_mod_alt_down) - { - texturingTool->change_spray_size (delta_for_range (39.f)); - } - else if (_mod_shift_down) - { - texturingTool->change_spray_pressure (delta_for_range (10.f)); - } - } - else if (terrainMode == editing_mode::flatten_blur) - { - if (_mod_alt_down) - { - flattenTool->changeOrientation (delta_for_range (360.f)); - } - else if (_mod_shift_down) - { - flattenTool->changeAngle (delta_for_range (89.f)); - } - else if (_mod_space_down) - { - //! \note not actual range - flattenTool->changeHeight (delta_for_range (40.f)); - } - } - else if (terrainMode == editing_mode::water) - { - if (_mod_alt_down) - { - guiWater->changeOrientation (delta_for_range (360.f)); - } - else if (_mod_shift_down) - { - guiWater->changeAngle (delta_for_range (89.f)); - } - else if (_mod_space_down) - { - //! \note not actual range - guiWater->change_height (delta_for_range (40.f)); - } - } + .event = *event, + .mod_shift_down = _mod_shift_down, + .mod_ctrl_down = _mod_ctrl_down, + .mod_alt_down = _mod_alt_down, + .mod_num_down = _mod_num_down, + .mod_space_down = _mod_space_down, + }; + activeTool()->onMouseWheel(params); } void MapView::mouseReleaseEvent (QMouseEvent* event) @@ -5800,6 +3997,13 @@ void MapView::mouseReleaseEvent (QMouseEvent* event) makeCurrent(); OpenGL::context::scoped_setter const _(::gl, context()); + activeTool()->onMouseRelease( + { + .button = event->button(), + .mouse_position = event->pos(), + .mod_ctrl_down = _mod_ctrl_down, + }); + switch (event->button()) { case Qt::LeftButton: @@ -5811,30 +4015,31 @@ void MapView::mouseReleaseEvent (QMouseEvent* event) moving = 0; } - if ((terrainMode == editing_mode::object || terrainMode == editing_mode::minimap) && !_mod_ctrl_down) + if (terrainMode == editing_mode::minimap ) { - auto drag_end_pos = event->pos(); + if (!_mod_ctrl_down) + { + auto drag_end_pos = event->pos(); - if (_drag_start_pos != drag_end_pos && !ImGuizmo::IsUsing()) - { - const std::array selection_box + if (_drag_start_pos != drag_end_pos && !ImGuizmo::IsUsing()) { - glm::vec2(std::min(_drag_start_pos.x(), drag_end_pos.x()), std::min(_drag_start_pos.y(), drag_end_pos.y())), - glm::vec2(std::max(_drag_start_pos.x(), drag_end_pos.x()), std::max(_drag_start_pos.y(), drag_end_pos.y())) - }; - // _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), objectEditor->drag_selection_depth(), _camera.position); - _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), 3000.0f, _camera.position); + const std::array selection_box + { + glm::vec2(std::min(_drag_start_pos.x(), drag_end_pos.x()), std::min(_drag_start_pos.y(), drag_end_pos.y())), + glm::vec2(std::max(_drag_start_pos.x(), drag_end_pos.x()), std::max(_drag_start_pos.y(), drag_end_pos.y())) + }; + // _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), objectEditor->drag_selection_depth(), _camera.position); + _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), 3000.0f, _camera.position); + } + else // Do normal selection when we just clicked + { + doSelection(false); + } } - else // Do normal selection when we just clicked + else { - doSelection(false); + doSelection(true); } - - _area_selection->hide(); - } - else - { - doSelection(true); } break; @@ -5854,10 +4059,6 @@ void MapView::mouseReleaseEvent (QMouseEvent* event) - break; - - case Qt::MiddleButton: - MoveObj = false; break; default: @@ -5869,8 +4070,7 @@ void MapView::save(save_mode mode) { bool save = true; - // Save minimap creator model filters - minimapTool->saveFiltersToJSON(); + activeTool()->saveSettings(); if (AsyncLoader::instance->important_object_failed_loading()) { @@ -5967,55 +4167,12 @@ void MapView::addHotkey(Qt::Key key, size_t modifiers, std::function fun hotkeys.emplace_front (key, modifiers, function, condition); } -void MapView::randomizeTerrainRotation() +void MapView::addHotkey(Qt::Key key, size_t modifiers, StringHash hotkeyName) { - auto image_mask_selector = terrainTool->getImageMaskSelector(); - if (!image_mask_selector->getRandomizeRotation()) - return; - - unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); - std::mt19937 gen(ms); - std::uniform_int_distribution<> uid(0, 360); - - image_mask_selector->setRotation(uid(gen)); -} - -void MapView::randomizeTexturingRotation() -{ - auto image_mask_selector = texturingTool->getImageMaskSelector(); - if (!image_mask_selector->getRandomizeRotation()) - return; - - unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); - std::mt19937 gen(ms); - std::uniform_int_distribution<> uid(0, 360); - - image_mask_selector->setRotation(uid(gen)); -} - -void MapView::randomizeShaderRotation() -{ - auto image_mask_selector = shaderTool->getImageMaskSelector(); - if (!image_mask_selector->getRandomizeRotation()) - return; - - unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); - std::mt19937 gen(ms); - std::uniform_int_distribution<> uid(0, 360); - - image_mask_selector->setRotation(uid(gen)); -} - -void MapView::randomizeStampRotation() -{ - if (!stampTool->getRandomizeRotation()) - return; - - unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); - std::mt19937 gen(ms); - std::uniform_int_distribution<> uid(0, 360); - - stampTool->changeRotation(uid(gen)); + hotkeys.emplace_front (key, modifiers + , [=] { activeTool()->onHotkeyPress(hotkeyName); } + , [=] { return activeTool()->hotkeyCondition(hotkeyName); } + , [=] { activeTool()->onHotkeyRelease(hotkeyName); }); } void MapView::unloadOpenglData() @@ -6057,18 +4214,14 @@ QWidget* MapView::getLeftSecondaryToolbar() return _viewport_overlay_ui->leftSecondaryToolbarHolder; } -QWidget* MapView::getActiveStampModeItem() +glm::vec3 MapView::cursorPosition() const { - auto item = stampTool->getActiveBrushItem(); - if (item) - return item->getTool(); - else - return nullptr; + return _cursor_pos; } -Noggit::Ui::GroundEffectsTool* MapView::getGroundEffectsTool() +void MapView::cursorPosition(glm::vec3 position) { - return texturingTool->getGroundEffectsTool(); + _cursor_pos = position; } void MapView::onSettingsSave() @@ -6128,390 +4281,10 @@ void MapView::ShowContextMenu(QPoint pos) NOGGIT_ACTION_MGR->redo(); }); - menu->addSeparator(); - - if (terrainMode == editing_mode::object) - { - bool has_selected_objects = _world->get_selected_model_count(); - bool has_copied_objects = objectEditor->clipboardSize(); - - // Copy - QAction action_8("Copy Object(s)", this); - menu->addAction(&action_8); - action_8.setEnabled(has_selected_objects); - action_8.setShortcut(QKeySequence::Copy); - QObject::connect(&action_8, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION) - objectEditor->copy_current_selection(_world.get()); - }); - - // Paste - QAction action_9("Paste Object(s)", this); - menu->addAction(&action_9); - action_9.setEnabled(has_copied_objects); - action_9.setShortcut(QKeySequence::Paste); // (Qt::CTRL | Qt::Key_P) - QObject::connect(&action_9, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED); - objectEditor->pasteObject(_cursor_pos, _camera.position, _world.get(), &_object_paste_params); - NOGGIT_ACTION_MGR->endAction(); - } - }); - - // Delete - QAction action_10("Delete Object(s)", this); - menu->addAction(&action_10); - action_10.setEnabled(has_selected_objects); - action_10.setShortcut(QKeySequence::Delete); // (Qt::CTRL | Qt::Key_P) - QObject::connect(&action_10, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_REMOVED); - DeleteSelectedObjects(); - NOGGIT_ACTION_MGR->endAction(); - } - }); - - // Duplicate - QAction action_11("Duplicate Object(s)", this); - menu->addAction(&action_11); - action_11.setEnabled(has_copied_objects); - action_11.setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B)); // (Qt::CTRL | Qt::Key_P) - QObject::connect(&action_11, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED); - objectEditor->copy_current_selection(_world.get()); - objectEditor->pasteObject(_cursor_pos, _camera.position, _world.get(), &_object_paste_params); - NOGGIT_ACTION_MGR->endAction(); - } - }); - - menu->addSeparator(); - - // selection stuff - QAction action_1("Select all Like Selected", this); // select all objects with the same model - action_1.setToolTip("Warning : Doing actions on models overlapping unloaded tiles can cause crash"); - menu->addAction(&action_1); - action_1.setEnabled(_world->get_selected_model_count() == 1); - QObject::connect(&action_1, &QAction::triggered, [=]() - { - auto last_entry = _world->get_last_selected_model(); - if (last_entry) - { - if (!last_entry.value().index() == eEntry_Object) - return; - - auto obj = std::get(last_entry.value()); - auto model_name = obj->instance_model()->file_key().filepath(); - // auto models = _world->get_models_by_filename()[model_name]; - - // if changing this, make sure to check for duplicate instead // if (!_world->is_selected(instance)) - _world->reset_selection(); - - if (obj->which() == eMODEL) - { - _world->getModelInstanceStorage().for_each_m2_instance([&](ModelInstance& model_instance) - { - if (model_instance.instance_model()->file_key().filepath() == model_name) - { - _world->add_to_selection(&model_instance); - } - }); - } - else if (obj->which() == eWMO) - _world->getModelInstanceStorage().for_each_wmo_instance([&](WMOInstance& wmo_instance) - { - if (wmo_instance.instance_model()->file_key().filepath() == model_name) - { - // objects_to_select.push_back(wmo_instance.uid); - _world->add_to_selection(&wmo_instance); - } - }); - - // for (auto uid_it = objects_to_select.begin(); uid_it != objects_to_select.end(); uid_it++) - // { - // auto instance = _world->getObjectInstance(*uid_it); - // // if (!_world->is_selected(instance)) - // _world->add_to_selection(instance); - // } - } - }); - - QAction action_2("Hide Selected Objects", this); - menu->addAction(&action_2); - action_2.setEnabled(has_selected_objects); - action_2.setShortcut(Qt::Key_H); - QObject::connect(&action_2, &QAction::triggered, [=]() - { - if (_world->has_selection()) - { - for (auto& obj : _world->get_selected_objects()) - { - if (obj->which() == eMODEL) - static_cast(obj)->model->hide(); - else if (obj->which() == eWMO) - static_cast(obj)->wmo->hide(); - } - } - }); - - QAction action_3("Hide Unselected Objects", this); - - - // QAction action_2("Show Hidden", this); - - QAction action_palette_add("Add Object To Palette", this); - menu->addAction(&action_palette_add); - action_palette_add.setEnabled(_world->get_selected_model_count() == 1); - QObject::connect(&action_palette_add, &QAction::triggered, [=]() - { - auto last_entry = _world->get_last_selected_model(); - if (last_entry) - { - if (!last_entry.value().index() == eEntry_Object) - return; - - getObjectPalette()->setVisible(true); - auto obj = std::get(last_entry.value()); - auto model_name = obj->instance_model()->file_key().filepath(); - _object_palette->addObjectByFilename(model_name.c_str()); - } - - }); - - menu->addSeparator(); - - // allow replacing all selected? - QAction action_replace("Replace Models (By Clipboard)", this); - menu->addAction(&action_replace); - action_replace.setEnabled(has_selected_objects && objectEditor->clipboardSize() == 1); - action_replace.setToolTip("Replace the currently selected objects by the object in the clipboard (There must only be one!). M2s can only be replaced by m2s"); - QObject::connect(&action_replace, &QAction::triggered, [=]() - { - makeCurrent(); - OpenGL::context::scoped_setter const _(::gl, context()); - - if (terrainMode != editing_mode::object && NOGGIT_CUR_ACTION) - return; - - if (!objectEditor->clipboardSize()) - return; - - // verify this - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_ADDED | Noggit::ActionFlags::eOBJECTS_REMOVED); - - // get the model to replace by - auto replace_select = objectEditor->getClipboard().front(); - auto replacement_obj = std::get(replace_select); - auto& replace_path = replacement_obj->instance_model()->file_key().filepath(); - - std::vector objects_to_delete; - - // iterate selection (objects to replace) - std::vector selected_objects = _world->get_selected_objects(); - for (SceneObject* old_obj : selected_objects) - { - if (old_obj->instance_model()->file_key().filepath() == replace_path) - continue; - - math::degrees::vec3 source_rot(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._); - source_rot = old_obj->dir; - float source_scale = old_obj->scale; - glm::vec3 source_pos = old_obj->pos; - - // _world->deleteInstance(old_obj->uid); - objects_to_delete.emplace_back(old_obj); - - if (replacement_obj->which() == eWMO) - { - // auto replace_wmo = static_cast(replacement_obj); - // auto source_wmo = static_cast(old_obj); - - auto new_obj = _world->addWMOAndGetInstance(replace_path, source_pos, source_rot, true); - new_obj->wmo->wait_until_loaded(); - new_obj->wmo->waitForChildrenLoaded(); - new_obj->recalcExtents(); - } - else if (replacement_obj->which() == eMODEL) - { - // auto replace_m2 = static_cast(replacement_obj); - // auto source_m2 = static_cast(source_obj); - - // Just swapping model - // Issue : doesn't work with actions - // _world->updateTilesEntry(entry, model_update::remove); - // source_m2->model = scoped_model_reference(replace_path, _context); - // source_m2->recalcExtents(); - // _world->updateTilesEntry(entry, model_update::add); - - auto new_obj = _world->addM2AndGetInstance(replace_path - , source_pos - , source_scale - , source_rot - , &_object_paste_params - , true - , true - ); - new_obj->model->wait_until_loaded(); - new_obj->model->waitForChildrenLoaded(); - new_obj->recalcExtents(); - } - } - // this would also delete models that got skipped - // _world->delete_selected_models(); - - _world->deleteObjects(objects_to_delete, true); - _world->reset_selection(); - - NOGGIT_ACTION_MGR->endAction(); - }); - - QAction action_snap("Snap Selected To Ground", this); - menu->addAction(&action_snap); - action_snap.setEnabled(has_selected_objects); - action_snap.setShortcut(Qt::Key_PageDown); // (Qt::CTRL | Qt::Key_P) - QObject::connect(&action_snap, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object && !NOGGIT_CUR_ACTION) - { - NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eOBJECTS_TRANSFORMED); - snap_selected_models_to_the_ground(); - NOGGIT_ACTION_MGR->endAction(); - } - }); - - QAction action_save_obj_coords("Save objects coords(to file)", this); - menu->addAction(&action_save_obj_coords); - action_save_obj_coords.setEnabled(has_selected_objects); - QObject::connect(&action_save_obj_coords, &QAction::triggered, [=]() - { - if (terrainMode == editing_mode::object) - { - if (_world->has_selection() && _world->get_selected_model_count()) - { - std::stringstream obj_data; - for (auto& obj : _world->get_selected_objects()) - { - obj_data << "\"Object : " << obj->instance_model()->file_key().filepath() << "(UID :" << obj->uid << ")\"," << std::endl; - obj_data << "\"Scale : " << obj->scale << "\"," << std::endl; - // coords string in ts-wow format - obj_data << "\"Coords(server): {map:" << _world->getMapID() << ",x:" << (ZEROPOINT - obj->pos.z) << ",y:" << (ZEROPOINT - obj->pos.x) - << ",z:" << obj->pos.y << ",o:"; - - float server_rot = 2 * glm::pi() - glm::pi() / 180.0 * (float(obj->dir.y) < 0 ? fabs(float(obj->dir.y)) + 180.0 : fabs(float(obj->dir.y) - 180.0)); - // float server_rot = glm::radians(obj->dir.y) + glm::radians(180.f); - - obj_data << server_rot << "}\"," << std::endl; - - /// converting db gobject rotation to noggit. Keep commented for later usage - /* - glm::quat test_db_quat = glm::quat(1.0, 1.0, 1.0, 1.0); - test_db_quat.x = 0.607692, test_db_quat.y = -0.361538, test_db_quat.z = 0.607693, test_db_quat.w = 0.361539; - glm::vec3 rot_euler = glm::eulerAngles(test_db_quat); - glm::vec3 rot_degrees = glm::degrees(rot_euler); - rot_degrees = glm::vec3(rot_degrees.y, rot_degrees.z - 180.f, rot_degrees.x); // final noggit coords - */ - - glm::quat rot_quat = glm::quat(glm::vec3(glm::radians(obj->dir.z), glm::radians(obj->dir.x), server_rot)); - auto normalized_quat = glm::normalize(rot_quat); - - obj_data << "\"Rotation (server quaternion): {x:" << normalized_quat.x << ",y:" << normalized_quat.y << ",z:" << normalized_quat.z - << ",w:" << normalized_quat.w << "}\"," << std::endl << "\n"; - } - - std::ofstream f("saved_objects_data.txt", std::ios_base::app); - f << "\"Saved " << _world->get_selected_model_count() << " objects at : " << QDateTime::currentDateTime().toString("dd MMMM yyyy hh:mm:ss").toStdString() << "\"" << std::endl; - f << obj_data.str(); - f.close(); - } - } - }); - - menu->addSeparator(); - // TODO - QAction action_group("Group Selected Objects", this); - menu->addAction(&action_group); - // check if all selected objects are already grouped - bool groupable = false; - if ( _world->has_multiple_model_selected()) - { - // if there's no existing groups, that means it's always groupable - if (!_world->_selection_groups.size()) - groupable = true; - - if (!groupable) - { - // check if there's any ungrouped object - for (auto obj : _world->get_selected_objects()) - { - bool obj_ungrouped = true; - for (auto& group : _world->_selection_groups) - { - if (group.contains_object(obj)) - obj_ungrouped = false; - } - if (obj_ungrouped) - { - groupable = true; - break; - } - } - } - } - action_group.setEnabled(groupable); - QObject::connect(&action_group, &QAction::triggered, [=]() - { - // remove all groups the objects are already in and create a new one - // for (auto obj : _world->get_selected_objects()) - // { - // for (auto& group : _world->_selection_groups) - // { - // if (group.contains_object(obj)) - // { - // group.remove_group(); - // } - // } - // } - for (auto& group : _world->_selection_groups) - { - if (group.isSelected()) - { - group.remove_group(); - } - } - - _world->add_object_group_from_selection(); - }); - - - QAction action_ungroup("Ungroup Selected Objects", this); - menu->addAction(&action_ungroup); - bool group_selected = false; - for (auto& group : _world->_selection_groups) - { - if (group.isSelected()) - { - group_selected = true; - break; - } - } - action_ungroup.setEnabled(group_selected); - QObject::connect(&action_ungroup, &QAction::triggered, [=]() - { - _world->clear_selection_groups(); - }); - - - menu->exec(mapToGlobal(pos)); // synch - // menu->popup(mapToGlobal(pos)); // asynch, needs to be preloaded to work - }; + activeTool()->registerContextMenuItems(menu); + menu->exec(mapToGlobal(pos)); // synch + // menu->popup(mapToGlobal(pos)); // asynch, needs to be preloaded to work } void MapView::onApplicationStateChanged(Qt::ApplicationState state) diff --git a/src/noggit/MapView.h b/src/noggit/MapView.h index 547792e5..05b52d9e 100755 --- a/src/noggit/MapView.h +++ b/src/noggit/MapView.h @@ -5,22 +5,17 @@ #include #include #include -#include #include #include -#include -#include #include -#include #include #include #include -#include #include #include #include #include -#include +#include #include #include @@ -51,6 +46,7 @@ namespace Noggit::Ui::Windows namespace Noggit { + class Tool; namespace Ui::Tools::ViewToolbar::Ui { @@ -59,18 +55,7 @@ namespace Noggit namespace Ui::Tools { - class BrushStack; - class LightEditor; - - namespace ChunkManipulator - { - class ChunkManipulatorPanel; - } - } - - namespace Scripting - { - class scripting_tool; + class ToolPanel; } class Camera; @@ -79,21 +64,9 @@ namespace Noggit namespace Ui { class detail_infos; - class flatten_blur_tool; class help; class minimap_widget; - class ShaderTool; - class TerrainTool; - class texture_picker; - class texturing_tool; class toolbar; - class water; - class zone_id_browser; - class texture_palette_small; - class hole_tool; - struct tileset_chooser; - class ObjectPalette; - class GroundEffectsTool; } } @@ -171,12 +144,6 @@ public: Noggit::BoolToggleProperty _show_minimap_window = { false }; private: - int _selected_area_id = -1; - - [[nodiscard]] - math::ray intersect_ray() const; - selection_result intersect_result(bool terrain_only); - void doSelection(bool selectTerrainOnly, bool mouseMove = false); void update_cursor_pos(); display_mode _display_mode; @@ -196,26 +163,13 @@ private: float mTimespeed; void ResetSelectedObjectRotation(); - void snap_selected_models_to_the_ground(); - void DeleteSelectedObjects(); - void changeZoneIDValue (int set); QPointF _last_mouse_pos; - float mh, mv, rh, rv; // mh = left click x, rv = right click y - - float keyx = 0, keyy = 0, keyz = 0, keyr = 0, keys = 0; - - bool MoveObj; - float numpad_moveratio = 0.001f; glm::vec3 objMove; std::vector lastSelected; - bool _rotation_editor_need_update = false; - bool _texture_picker_need_update = false; - bool _area_picker_need_update = false; - // Vars for the ground editing toggle mode store the status of some // view settings when the ground editing mode is switched on to // restore them if switch back again @@ -243,8 +197,6 @@ private: uid_fix_mode _uid_fix; bool _from_bookmark; - bool saving_minimap = false; - Noggit::Ui::toolbar* _toolbar; Noggit::Ui::Tools::ViewToolbar::Ui::ViewToolbar* _view_toolbar; Noggit::Ui::Tools::ViewToolbar::Ui::ViewToolbar* _secondary_toolbar; @@ -261,7 +213,10 @@ signals: void resized(); void saved(); void updateProgress(int value); - void selectionUpdated(); + void selectionUpdated(std::vector& selection); + void menuToggleChanged(bool value); + void rotationChanged(); + void trySetBrushTexture(QImage* image, QWidget* sender); public slots: void on_exit_prompt(); void ShowContextMenu(QPoint pos); @@ -284,16 +239,9 @@ public: void tick (float dt); void change_selected_wmo_nameset(int set); void change_selected_wmo_doodadset(int set); - void saveMinimap(MinimapRenderSettings* settings); - void initMinimapSave() { saving_minimap = true; }; auto setBrushTexture(QImage const* img) -> void; Noggit::Camera* getCamera() { return &_camera; }; - void randomizeTerrainRotation(); - void randomizeTexturingRotation(); - void randomizeShaderRotation(); - void randomizeStampRotation(); void onSettingsSave(); - void updateRotationEditor() { _rotation_editor_need_update = true; }; void setCameraDirty() { _camera_moved_since_last_draw = true; }; [[nodiscard]] @@ -308,15 +256,6 @@ public: [[nodiscard]] QWidget *getLeftSecondaryToolbar(); - [[nodiscard]] - QWidget* getActiveStampModeItem(); - - [[nodiscard]] - Noggit::Ui::flatten_blur_tool* getFlattenTool() { return flattenTool; }; - - [[nodiscard]] - Noggit::Ui::GroundEffectsTool* getGroundEffectsTool(); - [[nodiscard]] Noggit::NoggitRenderContext getRenderContext() { return _context; }; @@ -329,14 +268,8 @@ public: [[nodiscard]] Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget* getAssetBrowserWidget() { return _asset_browser; }; - [[nodiscard]] - Noggit::Ui::object_editor* getObjectEditor() { return objectEditor; }; - - [[nodiscard]] - QDockWidget* getObjectPalette() { return _object_palette_dock; }; - - [[nodiscard]] - QDockWidget* getTexturePalette() { return _texture_palette_dock; }; + glm::vec3 cursorPosition() const; + void cursorPosition(glm::vec3 position); private: enum Modifier @@ -353,15 +286,17 @@ private: { Qt::Key key; size_t modifiers; - std::function function; + std::function onPress; + std::function onRelease; std::function condition; - HotKey (Qt::Key k, size_t m, std::function f, std::function c) - : key (k), modifiers (m), function (f), condition (c) {} + HotKey (Qt::Key k, size_t m, std::function f, std::function c, std::function r = []{}) + : key (k), modifiers (m), onPress(f), onRelease{r}, condition (c) {} }; std::forward_list hotkeys; void addHotkey(Qt::Key key, size_t modifiers, std::function function, std::function condition = [] { return true; }); + void addHotkey(Qt::Key key, size_t modifiers, StringHash hotkeyName); QElapsedTimer _startup_time; qreal _last_update = 0.f; @@ -389,7 +324,6 @@ private: Noggit::Ui::Windows::NoggitWindow* _main_window; glm::vec4 normalized_device_coords (int x, int y) const; - float aspect_ratio() const; Noggit::TabletManager* _tablet_manager; @@ -402,31 +336,17 @@ private: QLabel* _status_database; Noggit::BoolToggleProperty _locked_cursor_mode = {false}; - Noggit::BoolToggleProperty _move_model_to_cursor_position = {true}; - Noggit::BoolToggleProperty _move_model_snap_to_objects = { true }; - Noggit::BoolToggleProperty _snap_multi_selection_to_ground = {false}; - Noggit::BoolToggleProperty _rotate_along_ground = {true }; Noggit::BoolToggleProperty _rotate_doodads_along_doodads = { false }; Noggit::BoolToggleProperty _rotate_doodads_along_wmos = { false }; - Noggit::BoolToggleProperty _rotate_along_ground_smooth = {true }; - Noggit::BoolToggleProperty _rotate_along_ground_random = {false }; - Noggit::BoolToggleProperty _use_median_pivot_point = {true}; - Noggit::BoolToggleProperty _display_all_water_layers = {true}; - Noggit::unsigned_int_property _displayed_water_layer = {0}; - Noggit::object_paste_params _object_paste_params; Noggit::BoolToggleProperty _show_node_editor = {false}; Noggit::BoolToggleProperty _show_minimap_borders = {true}; Noggit::BoolToggleProperty _show_minimap_skies = {false}; Noggit::BoolToggleProperty _show_keybindings_window = {false}; - Noggit::BoolToggleProperty _show_texture_palette_window = {false}; - Noggit::BoolToggleProperty _show_texture_palette_small_window = {false}; Noggit::BoolToggleProperty _showStampPalette{false}; Noggit::Ui::minimap_widget* _minimap; QDockWidget* _minimap_dock; - QDockWidget* _texture_palette_dock; - QDockWidget* _object_palette_dock; void move_camera_with_auto_height (glm::vec3 const&); @@ -435,33 +355,14 @@ private: void unloadOpenglData() override; Noggit::Ui::help* _keybindings; - Noggit::Ui::tileset_chooser* TexturePalette; Noggit::Ui::detail_infos* guidetailInfos; - Noggit::Ui::zone_id_browser* ZoneIDBrowser; - Noggit::Ui::texture_palette_small* _texture_palette_small; - Noggit::Ui::ObjectPalette* _object_palette; - Noggit::Ui::texture_picker* TexturePicker; - Noggit::Ui::water* guiWater; - Noggit::Ui::object_editor* objectEditor; - Noggit::Ui::flatten_blur_tool* flattenTool; - Noggit::Ui::TerrainTool* terrainTool; - Noggit::Ui::ShaderTool* shaderTool; - Noggit::Ui::texturing_tool* texturingTool; - Noggit::Ui::hole_tool* holeTool; - Noggit::Ui::MinimapCreator* minimapTool; - Noggit::Ui::Tools::BrushStack* stampTool; - Noggit::Ui::Tools::LightEditor* lightEditor; - Noggit::Ui::Tools::ChunkManipulator::ChunkManipulatorPanel* _chunk_manipulator; - Noggit::Scripting::scripting_tool* scriptingTool; OpenGL::texture* const _texBrush; - Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget* _asset_browser; + Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget* _asset_browser = nullptr; QDockWidget* _asset_browser_dock; QDockWidget* _node_editor_dock; - QDockWidget* _texture_browser_dock; - QDockWidget* _texture_picker_dock; QDockWidget* _detail_infos_dock; Noggit::Ui::Tools::ToolPanel* _tool_panel_dock; @@ -479,33 +380,14 @@ private: bool _needs_redraw = false; bool _unload_tiles = true; - unsigned _mmap_async_index = 0; - unsigned _mmap_render_index = 0; - std::optional _mmap_combined_image; - OpenGL::Scoped::deferred_upload_buffers<2> _buffers; - QRubberBand* _area_selection; public: private: void setupViewportOverlay(); - void setupRaiseLowerUi(); - void setupFlattenBlurUi(); - void setupTexturePainterUi(); - void setupHoleCutterUi(); - void setupAreaDesignatorUi(); - void setupFlagUi(); - void setupWaterEditorUi(); - void setupVertexPainterUi(); - void setupObjectEditorUi(); - void setupMinimapEditorUi(); - void setupStampUi(); - void setupLightEditorUi(); - void setupScriptingUi(); - void setupChunkManipulatorUi(); void setupNodeEditor(); void setupAssetBrowser(); void setupDetailInfos(); @@ -517,10 +399,60 @@ private: void setupEditMenu(); void setupAssistMenu(); void setupViewMenu(); + void setupToolsMenu(); void setupHelpMenu(); void setupHotkeys(); void setupClientMenu(); void setupMainToolbar(); QWidget* _overlay_widget; + + std::vector> _tools; + size_t _activeToolIndex = 0; + + std::unique_ptr& activeTool(); + void activeTool(editing_mode newTool); + + public: + [[nodiscard]] + Noggit::Ui::Tools::ViewToolbar::Ui::ViewToolbar* getLeftSecondaryViewToolbar(); + + [[nodiscard]] + QSettings* settings(); + + [[nodiscard]] + Noggit::Ui::Windows::NoggitWindow* mainWindow(); + + [[nodiscard]] + bool isUiHidden() const; + + [[nodiscard]] + bool drawAdtGrid() const; + [[nodiscard]] + bool drawHoleGrid() const; + + void invalidate(); + + void selectObjects(std::array selection_box, float depth); + void doSelection(bool selectTerrainOnly, bool mouseMove = false); + void DeleteSelectedObjects(); + void snap_selected_models_to_the_ground(); + + [[nodiscard]] + bool isRotatingCamera() const; + + [[nodiscard]] + float aspect_ratio() const; + + [[nodiscard]] + math::ray intersect_ray() const; + + [[nodiscard]] + selection_result intersect_result(bool terrain_only); + + [[nodiscard]] + std::shared_ptr& project(); + + [[nodiscard]] + float timeSpeed() const; }; diff --git a/src/noggit/MinimapRenderSettings.hpp b/src/noggit/MinimapRenderSettings.hpp new file mode 100644 index 00000000..4a812c33 --- /dev/null +++ b/src/noggit/MinimapRenderSettings.hpp @@ -0,0 +1,53 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +class QListWidget; + +#include +#include + +#include +#include + +enum MinimapGenMode +{ + CURRENT_ADT, + SELECTED_ADTS, + MAP +}; + +struct MinimapRenderSettings +{ + MinimapGenMode export_mode = CURRENT_ADT; + std::string file_format = ".blp"; + + // Render settings + int resolution = 512; + bool draw_m2 = false; + bool draw_wmo = true; + bool draw_water = true; + bool draw_adt_grid = false; + bool draw_elevation = false; + bool draw_shadows = false; + bool use_filters = false; + bool combined_minimap = false; + + // Selection + // std::array selected_tiles = {false}; + + std::vector selected_tiles = std::vector( size_t{4096}, false, {} ); + + // Filtering + QListWidget* m2_model_filter_include = nullptr; + QListWidget* m2_instance_filter_include = nullptr; + QListWidget* wmo_model_filter_exclude = nullptr; + QListWidget* wmo_instance_filter_exclude = nullptr; + + // Lighting. Based on default eastern kingdom global light settings (lightparams 12) + glm::vec3 diffuse_color = {1.0, 0.532352924, 0.0}; + glm::vec3 ambient_color = {0.407770514, 0.508424163, 0.602650642}; + glm::vec4 ocean_color_light = {0.0693173409, 0.294008732, 0.348329663, 0.75}; + glm::vec4 ocean_color_dark = {0.000762581825, 0.113907099, 0.161220074, 1.0}; + glm::vec4 river_color_light = {0.308351517, 0.363725543, 0.0798838138, 0.5}; + glm::vec4 river_color_dark = {0.19945538, 0.320697188, 0.332425594, 1.0}; +}; \ No newline at end of file diff --git a/src/noggit/StringHash.hpp b/src/noggit/StringHash.hpp new file mode 100644 index 00000000..0d0f9579 --- /dev/null +++ b/src/noggit/StringHash.hpp @@ -0,0 +1,40 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +struct StringHash +{ + uint64_t hash; + + consteval explicit StringHash(uint64_t value) + : hash{ value } + { + } + + [[nodiscard]] + constexpr operator uint64_t() + { + return hash; + } +}; + +consteval auto operator""_hash(char const* str, size_t len) +{ + // djb2 hash + + uint64_t hash = 5381; + + for (size_t i = 0; i < len; ++i) + { + hash = ((hash << 5) + hash) + static_cast(str[i]); + } + + return StringHash{ hash }; +} + +consteval bool operator==(StringHash a, StringHash b) +{ + return a.hash == b.hash; +} \ No newline at end of file diff --git a/src/noggit/Tool.cpp b/src/noggit/Tool.cpp new file mode 100644 index 00000000..8d33719a --- /dev/null +++ b/src/noggit/Tool.cpp @@ -0,0 +1,247 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "Tool.hpp" +#include +#include +#include +#include + +#include +#include +#include + +namespace Noggit +{ + Tool::Tool(MapView* mapView) + : _mapView{ mapView } + { + } + + MapView* const Tool::mapView() + { + return _mapView; + } + + void Tool::onHotkeyPress(StringHash name) + { + if (auto&& itr = _hotkeys.find(name); itr != _hotkeys.end()) + { + itr->second.onPress(); + } + } + + void Tool::onHotkeyRelease(StringHash name) + { + if (auto&& itr = _hotkeys.find(name); itr != _hotkeys.end()) + { + itr->second.onRelease(); + } + } + + bool Tool::hotkeyCondition(StringHash name) + { + if (auto&& itr = _hotkeys.find(name); itr != _hotkeys.end()) + { + return itr->second.condition(); + } + + return false; + } + + unsigned int Tool::actionModality() const + { + return 0; + } + + void Tool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + } + + void Tool::postUiSetup() + { + } + + ToolDrawParameters Tool::drawParameters() const + { + return {}; + } + + float Tool::brushRadius() const + { + return 0.0f; + } + + bool Tool::useMultiselectionPivot() const + { + return false; + } + + bool Tool::useMedianPivotPoint() const + { + return false; + } + + void Tool::onSelected() + { + } + + void Tool::onDeselected() + { + } + + void Tool::onTick(float deltaTime, TickParameters const& params) + { + } + + bool Tool::preRender() + { + return true; + } + + void Tool::postRender() + { + } + + void Tool::onMousePress(MousePressParameters const& params) + { + } + + void Tool::onMouseRelease(MouseReleaseParameters const& params) + { + } + + void Tool::onMouseMove(MouseMoveParameters const& params) + { + } + + void Tool::onMouseWheel(MouseWheelParameters const& params) + { + } + + void Tool::hidePopups() + { + } + + void Tool::onFocusLost() + { + } + + void Tool::saveSettings() + { + } + + void Tool::registerMenuItems(QMenu* menu) + { + } + + void Tool::registerContextMenuItems(QMenu* menu) + { + } + + void Tool::addHotkey(StringHash name, Hotkey hotkey) + { + if (auto&& itr = _hotkeys.find(name); itr != _hotkeys.end()) + { + // If you get here and you're sure the name you're using isn't already used by this tool, + // then you may have run into a hash collision and we need to re-evaluate the hashing algorithm. + // Or, just change the name and move on... + throw std::exception{ "There's already a hotkey with this name!" }; + } + + _hotkeys[name] = hotkey; + } + + void Tool::addMenuTitle(QMenu* menu, char const* title) + { + menu->addSeparator(); + + auto* pLabel = new QLabel(title); + pLabel->setAlignment(Qt::AlignCenter); + auto* separator = new QWidgetAction(_mapView); + separator->setDefaultWidget(pLabel); + menu->addAction(separator); + + menu->addSeparator(); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, BoolToggleProperty& property) + { + QAction* action(new QAction(title, _mapView)); + action->setShortcut(shortcut); + action->setCheckable(true); + action->setChecked(property.get()); + menu->addAction(action); + QObject::connect(action, &QAction::toggled + , &property, &Noggit::BoolToggleProperty::set + ); + QObject::connect(&property, &Noggit::BoolToggleProperty::changed + , action, &QAction::setChecked + ); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, BoolToggleProperty& property) + { + QAction* action(new QAction(title, _mapView)); + action->setCheckable(true); + action->setChecked(property.get()); + menu->addAction(action); + QObject::connect(action, &QAction::toggled + , &property, &Noggit::BoolToggleProperty::set + ); + QObject::connect(&property, &Noggit::BoolToggleProperty::changed + , action, &QAction::setChecked + ); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, std::function onAction) + { + auto action(menu->addAction(title)); + action->setShortcut(shortcut); + auto callback = onAction; + QObject::connect(action, &QAction::triggered, [this, callback]() + { + if (NOGGIT_CUR_ACTION) \ + return; + callback(); + }); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, bool enabled, std::function onAction) + { + auto action(menu->addAction(title)); + action->setShortcut(shortcut); + action->setEnabled(enabled); + auto callback = onAction; + QObject::connect(action, &QAction::triggered, [this, callback]() + { + if (NOGGIT_CUR_ACTION) \ + return; + callback(); + }); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, char const* tooltip, bool enabled, std::function onAction) + { + auto action(menu->addAction(title)); + action->setToolTip(tooltip); + action->setEnabled(enabled); + auto callback = onAction; + QObject::connect(action, &QAction::triggered, [this, callback]() + { + if (NOGGIT_CUR_ACTION) \ + return; + callback(); + }); + } + + void Tool::addMenuItem(QMenu* menu, char const* title, std::function onAction) + { + auto action(menu->addAction(title)); + QObject::connect(action, &QAction::triggered, onAction); + } + + void Tool::addMenuSeperator(QMenu* menu) + { + menu->addSeparator(); + } +} \ No newline at end of file diff --git a/src/noggit/Tool.hpp b/src/noggit/Tool.hpp new file mode 100644 index 00000000..f031da7f --- /dev/null +++ b/src/noggit/Tool.hpp @@ -0,0 +1,208 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include "tool_enums.hpp" +#include "ToolDrawParameters.hpp" +#include "StringHash.hpp" + +#include + +#include + +#include +#include + +#include +#include +#include + +class MapView; + +class QWheelEvent; +class QMenu; + +namespace Noggit +{ + struct BoolToggleProperty; + + namespace Ui::Tools + { + class ToolPanel; + } + + struct TickParameters + { + display_mode displayMode = display_mode::in_3D; + bool underMap = false; + + bool left_mouse = false; + bool right_mouse = false; + bool mod_shift_down = false; + bool mod_ctrl_down = false; + bool mod_alt_down = false; + bool mod_num_down = false; + + glm::vec3 dir = { 1.0f, 0.0f, 0.0f }; + glm::vec3 dirUp = { 1.0f, 0.0f, 0.0f }; + glm::vec3 dirRight = { 0.0f, 0.0f, 1.0f }; + }; + + struct MousePressParameters + { + Qt::MouseButton button = Qt::MouseButton::NoButton; + QPoint mouse_position; + bool mod_ctrl_down = false; + }; + + struct MouseReleaseParameters + { + Qt::MouseButton button = Qt::MouseButton::NoButton; + QPoint mouse_position; + bool mod_ctrl_down = false; + }; + + struct MouseMoveParameters + { + display_mode displayMode = display_mode::in_3D; + bool left_mouse = false; + bool right_mouse = false; + bool mod_shift_down = false; + bool mod_ctrl_down = false; + bool mod_alt_down = false; + bool mod_num_down = false; + bool mod_space_down = false; + QLineF relative_movement; + QPoint mouse_position; + }; + + struct MouseWheelParameters + { + QWheelEvent& event; + bool mod_shift_down = false; + bool mod_ctrl_down = false; + bool mod_alt_down = false; + bool mod_num_down = false; + bool mod_space_down = false; + }; + + class Tool + { + protected: + struct Hotkey + { + std::function onPress; + std::function onRelease = [] {}; + std::function condition; + }; + + public: + explicit Tool(MapView* mapView); + virtual ~Tool() = default; + + [[nodiscard]] + MapView* const mapView(); + + // will be called whenever a user presses a hotkey + void onHotkeyPress(StringHash name); + + // will be called after a user pressed a hotkey + void onHotkeyRelease(StringHash name); + + // will be called before onHotkeyPress to see if it needs to be called + [[nodiscard]] + bool hotkeyCondition(StringHash name); + + // Returns the current action modality to cancel the current action on mismatch + [[nodiscard]] + virtual unsigned int actionModality() const; + + // The name displayed in the toolbar + [[nodiscard]] + virtual char const* name() const = 0; + + [[nodiscard]] + virtual editing_mode editingMode() const = 0; + + // The icon displayed in the toolbar + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const = 0; + + // UI setup code goes here + virtual void setupUi(Ui::Tools::ToolPanel* toolPanel); + + // UI setup code that relies on other UI elements being initialized goes here + virtual void postUiSetup(); + + // If you need menu items, register them here + virtual void registerMenuItems(QMenu* menu); + + // If you need context menu items, register them here + virtual void registerContextMenuItems(QMenu* menu); + + // Returns the ToolDrawParameters required by the renderer to draw tool specific objects (like the brush for texturing mode) + [[nodiscard]] + virtual ToolDrawParameters drawParameters() const; + + [[nodiscard]] + virtual float brushRadius() const; + + [[nodiscard]] + virtual bool useMultiselectionPivot() const; + + [[nodiscard]] + virtual bool useMedianPivotPoint() const; + + // will be called whenever this tool gets selected by the user + virtual void onSelected(); + + // will be called whenever the user selects a different tool + virtual void onDeselected(); + + // will be called every tick + virtual void onTick(float deltaTime, TickParameters const& params); + + // will be called before the map gets drawn. May return false to skip rendering the map + virtual bool preRender(); + + // will be called after the map got drawn + virtual void postRender(); + + // will be called whenever a mouse button is pressed + virtual void onMousePress(MousePressParameters const& params); + + virtual void onMouseRelease(MouseReleaseParameters const& params); + + // will be called whenever the mouse moves + virtual void onMouseMove(MouseMoveParameters const& params); + + // will be called when the user scrolls the mouse wheel + virtual void onMouseWheel(MouseWheelParameters const& params); + + // Hide your tools' popups! + virtual void hidePopups(); + + // The main window's focus was lost + virtual void onFocusLost(); + + // Save tool-specific settings to disk + virtual void saveSettings(); + + protected: + void addHotkey(StringHash name, Hotkey hotkey); + + void addMenuTitle(QMenu* menu, char const* title); + void addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, BoolToggleProperty& property); + void addMenuItem(QMenu* menu, char const* title, BoolToggleProperty& property); + void addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, std::function onAction); + void addMenuItem(QMenu* menu, char const* title, QKeySequence shortcut, bool enabled, std::function onAction); + void addMenuItem(QMenu* menu, char const* title, char const* tooltip, bool enabled, std::function onAction); + void addMenuItem(QMenu* menu, char const* title, std::function onAction); + + void addMenuSeperator(QMenu* menu); + + private: + MapView* _mapView = nullptr; + std::unordered_map _hotkeys; + }; +} \ No newline at end of file diff --git a/src/noggit/ToolDrawParameters.hpp b/src/noggit/ToolDrawParameters.hpp new file mode 100644 index 00000000..6381bcfe --- /dev/null +++ b/src/noggit/ToolDrawParameters.hpp @@ -0,0 +1,31 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include "tool_enums.hpp" +#include "MinimapRenderSettings.hpp" + +#include +#include + +struct MinimapRenderSettings; + +namespace Noggit +{ + struct ToolDrawParameters + { + float radius = 0.0f; + float inner_radius = 0.0f; + float angle = 0.0f; + float orientation = 0.0f; + glm::vec3 ref_pos; + bool angled_mode = false; + bool use_ref_pos = false; + bool show_unpaintable_chunks = false; + CursorType cursor_type = CursorType::CIRCLE; + eTerrainType terrain_type = eTerrainType::eTerrainType_Flat; + int displayed_water_layer = -1; + glm::vec4 cursor_color = { 1.f, 1.f, 1.f, 1.f }; + MinimapRenderSettings minimapRenderSettings; + }; +} \ No newline at end of file diff --git a/src/noggit/object_paste_params.hpp b/src/noggit/object_paste_params.hpp new file mode 100644 index 00000000..b9bddff8 --- /dev/null +++ b/src/noggit/object_paste_params.hpp @@ -0,0 +1,17 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +namespace Noggit +{ + struct object_paste_params + { + float minRotation = -180.f; + float maxRotation = 180.f; + float minTilt = -5.f; + float maxTilt = 5.f; + float minScale = 0.9f; + float maxScale = 1.1f; + bool rotate_on_terrain = true; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/AreaTool.cpp b/src/noggit/tools/AreaTool.cpp new file mode 100644 index 00000000..e425b331 --- /dev/null +++ b/src/noggit/tools/AreaTool.cpp @@ -0,0 +1,122 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "AreaTool.hpp" + +#include +#include +#include +#include +#include + +namespace Noggit +{ + AreaTool::AreaTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("setAreaId"_hash, { + .onPress = [=] { + if (_selectedAreaId != -1) + { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eCHUNKS_AREAID); + mapView->getWorld()->setAreaID(mapView->getCamera()->position, _selectedAreaId, true); + NOGGIT_ACTION_MGR->endAction(); + }}, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::areaid && !NOGGIT_CUR_ACTION; } + }); + } + + AreaTool::~AreaTool() + { + } + + char const* AreaTool::name() const + { + return "Area Designator"; + } + + editing_mode AreaTool::editingMode() const + { + return editing_mode::areaid; + } + + Ui::FontNoggit::Icons AreaTool::icon() const + { + return Ui::FontNoggit::TOOL_AREA_DESIGNATOR; + } + + void AreaTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _areaTool = new Noggit::Ui::zone_id_browser(mapView()); + toolPanel->registerTool(name(), _areaTool); + + _areaTool->setMapID(mapView()->getWorld()->getMapID()); + QObject::connect(_areaTool, &Noggit::Ui::zone_id_browser::selected + , [this](int area_id) { _selectedAreaId = area_id; } + ); + } + + ToolDrawParameters AreaTool::drawParameters() const + { + return ToolDrawParameters(); + } + + void AreaTool::registerMenuItems(QMenu* menu) + { + addMenuTitle(menu, "Area Designator"); + addMenuItem(menu, "Set Area ID", [=] { + if (_selectedAreaId == -1) + { + return; + } + + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_AREAID); + mapView()->getWorld()->setAreaID(mapView()->getCamera()->position, _selectedAreaId, true); + NOGGIT_ACTION_MGR->endAction(); + }); + } + + void AreaTool::onSelected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_areaid_overlay = true; + } + + void AreaTool::onDeselected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_areaid_overlay = false; + } + + void AreaTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || params.underMap || !params.left_mouse) + { + return; + } + + if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_AREAID, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + // draw the selected AreaId on current selected chunk + mapView()->getWorld()->setAreaID(mapView()->cursorPosition(), _selectedAreaId, false, _areaTool->brushRadius()); + } + else if (params.mod_ctrl_down) + { + for (auto&& selection : mapView()->getWorld()->current_selection()) + { + MapChunk* chnk(std::get(selection).chunk); + int newID = chnk->getAreaID(); + _selectedAreaId = newID; + _areaTool->setZoneID(newID); + } + } + } + + void AreaTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.left_mouse && params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _areaTool->changeRadius(params.relative_movement.dx() / XSENS); + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/AreaTool.hpp b/src/noggit/tools/AreaTool.hpp new file mode 100644 index 00000000..64dedd3b --- /dev/null +++ b/src/noggit/tools/AreaTool.hpp @@ -0,0 +1,48 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui + { + class zone_id_browser; + } + + class AreaTool final : public Tool + { + public: + AreaTool(MapView* mapView); + ~AreaTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void registerMenuItems(QMenu* menu) override; + + virtual void onSelected(); + + virtual void onDeselected(); + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + private: + Ui::zone_id_browser* _areaTool = nullptr; + int _selectedAreaId = -1; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/ChunkTool.cpp b/src/noggit/tools/ChunkTool.cpp new file mode 100644 index 00000000..f466634e --- /dev/null +++ b/src/noggit/tools/ChunkTool.cpp @@ -0,0 +1,43 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "ChunkTool.hpp" + +#include +#include +#include +#include +#include + +namespace Noggit +{ + ChunkTool::ChunkTool(MapView* mapView) + : Tool{ mapView } + { + } + + ChunkTool::~ChunkTool() + { + delete _chunkManipulator; + } + + char const* ChunkTool::name() const + { + return "Chunk Manipulator"; + } + + editing_mode ChunkTool::editingMode() const + { + return editing_mode::chunk; + } + + Ui::FontNoggit::Icons ChunkTool::icon() const + { + return Ui::FontNoggit::INFO; + } + + void ChunkTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _chunkManipulator = new Noggit::Ui::Tools::ChunkManipulator::ChunkManipulatorPanel(mapView(), mapView()); + toolPanel->registerTool(name(), _chunkManipulator); + } +} \ No newline at end of file diff --git a/src/noggit/tools/ChunkTool.hpp b/src/noggit/tools/ChunkTool.hpp new file mode 100644 index 00000000..2744e488 --- /dev/null +++ b/src/noggit/tools/ChunkTool.hpp @@ -0,0 +1,34 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui::Tools::ChunkManipulator + { + class ChunkManipulatorPanel; + } + + class ChunkTool final : public Tool + { + public: + ChunkTool(MapView* mapView); + ~ChunkTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + private: + Ui::Tools::ChunkManipulator::ChunkManipulatorPanel* _chunkManipulator = nullptr; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/FlattenBlurTool.cpp b/src/noggit/tools/FlattenBlurTool.cpp new file mode 100644 index 00000000..adb1b2f7 --- /dev/null +++ b/src/noggit/tools/FlattenBlurTool.cpp @@ -0,0 +1,187 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "FlattenBlurTool.hpp" + +#include +#include +#include +#include +#include +#include + +namespace Noggit +{ + FlattenBlurTool::FlattenBlurTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("nextType"_hash, Hotkey{ + .onPress = [this] { _flattenTool->nextFlattenType(); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("toggleAngle"_hash, Hotkey{ + .onPress = [this] { _flattenTool->toggleFlattenAngle(); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("nextMode"_hash, Hotkey{ + .onPress = [this, mv = mapView] + { + mv->getLeftSecondaryViewToolbar()->nextFlattenMode(); + _flattenTool->nextFlattenMode(); + }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("toggleLock"_hash, Hotkey{ + .onPress = [this] { _flattenTool->toggleFlattenLock(); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("lockCursor"_hash, Hotkey{ + .onPress = [this, mv = mapView] { _flattenTool->lockPos(mv->cursorPosition()); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("increaseRadius"_hash, Hotkey{ + .onPress = [this] { _flattenTool->changeRadius(0.01f); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("decreaseRadius"_hash, Hotkey{ + .onPress = [this] { _flattenTool->changeRadius(-0.01f); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::flatten_blur && !NOGGIT_CUR_ACTION; }, + }); + } + + FlattenBlurTool::~FlattenBlurTool() + { + delete _flattenTool; + } + + char const* FlattenBlurTool::name() const + { + return "Flatten | Blur"; + } + + editing_mode FlattenBlurTool::editingMode() const + { + return editing_mode::flatten_blur; + } + + Ui::FontNoggit::Icons FlattenBlurTool::icon() const + { + return Ui::FontNoggit::TOOL_FLATTEN_BLUR; + } + + void FlattenBlurTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _flattenTool = new Noggit::Ui::flatten_blur_tool(mapView()); + toolPanel->registerTool(name(), _flattenTool); + } + + void FlattenBlurTool::postUiSetup() + { + QObject::connect(mapView()->getLeftSecondaryViewToolbar() + , &Ui::Tools::ViewToolbar::Ui::ViewToolbar::updateStateRaise + , [this](bool newState) + { + _flattenTool->_flatten_mode.raise = newState; + } + ); + + QObject::connect(mapView()->getLeftSecondaryViewToolbar() + , &Ui::Tools::ViewToolbar::Ui::ViewToolbar::updateStateLower + , [this](bool newState) + { + _flattenTool->_flatten_mode.lower = newState; + } + ); + } + + void FlattenBlurTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || !params.left_mouse) + { + return; + } + + if (params.displayMode == display_mode::in_3D && !params.underMap) + { + if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + _flattenTool->flatten(mapView()->getWorld(), mapView()->cursorPosition(), deltaTime); + } + else if (params.mod_ctrl_down) + { + + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + _flattenTool->blur(mapView()->getWorld(), mapView()->cursorPosition(), deltaTime); + } + } + } + + ToolDrawParameters FlattenBlurTool::drawParameters() const + { + return + { + .radius = _flattenTool->brushRadius(), + .angle = _flattenTool->angle(), + .orientation = _flattenTool->orientation(), + .ref_pos = _flattenTool->ref_pos(), + .angled_mode = _flattenTool->angled_mode(), + .use_ref_pos = _flattenTool->use_ref_pos(), + }; + } + + void FlattenBlurTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _flattenTool->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_space_down) + { + _flattenTool->changeSpeed(params.relative_movement.dx() / 30.0f); + } + } + } + + void FlattenBlurTool::onMouseWheel(MouseWheelParameters const& params) + { + auto&& delta_for_range + ([&](float range) + { + //! \note / 8.f for degrees, / 40.f for smoothness + return (params.mod_ctrl_down ? 0.01f : 0.1f) + * range + // alt = horizontal delta + * (params.mod_alt_down ? params.event.angleDelta().x() : params.event.angleDelta().y()) + / 320.f + ; + } + ); + + if (params.mod_alt_down) + { + _flattenTool->changeOrientation(delta_for_range(360.f)); + } + else if (params.mod_shift_down) + { + _flattenTool->changeAngle(delta_for_range(89.f)); + } + else if (params.mod_space_down) + { + //! \note not actual range + _flattenTool->changeHeight(delta_for_range(40.f)); + } + } +} diff --git a/src/noggit/tools/FlattenBlurTool.hpp b/src/noggit/tools/FlattenBlurTool.hpp new file mode 100644 index 00000000..3f179876 --- /dev/null +++ b/src/noggit/tools/FlattenBlurTool.hpp @@ -0,0 +1,45 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui + { + class flatten_blur_tool; + } + + class FlattenBlurTool final : public Tool + { + public: + FlattenBlurTool(MapView* mapView); + ~FlattenBlurTool(); + + [[nodiscard]] + char const* name() const override; + + [[nodiscard]] + editing_mode editingMode() const override; + + [[nodiscard]] + Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + void postUiSetup() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onMouseMove(MouseMoveParameters const& params) override; + + void onMouseWheel(MouseWheelParameters const& params) override; + + private: + Ui::flatten_blur_tool* _flattenTool = nullptr; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/HoleTool.cpp b/src/noggit/tools/HoleTool.cpp new file mode 100644 index 00000000..5b99ee57 --- /dev/null +++ b/src/noggit/tools/HoleTool.cpp @@ -0,0 +1,113 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "HoleTool.hpp" + +#include +#include +#include +#include +#include + +namespace Noggit +{ + HoleTool::HoleTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("unsetAdtHole"_hash, Hotkey{ + .onPress = [=] { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eCHUNKS_HOLES); + mapView->getWorld()->setHoleADT(mapView->getCamera()->position, false); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::holes && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setAdtHole"_hash, Hotkey{ + .onPress = [=] { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eCHUNKS_HOLES); + mapView->getWorld()->setHoleADT(mapView->getCamera()->position, true); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::holes && !NOGGIT_CUR_ACTION; }, + }); + } + + HoleTool::~HoleTool() + { + delete _holeTool; + } + + char const* HoleTool::name() const + { + return "Hole Cutter"; + } + + editing_mode HoleTool::editingMode() const + { + return editing_mode::holes; + } + + Ui::FontNoggit::Icons HoleTool::icon() const + { + return Ui::FontNoggit::TOOL_HOLE_CUTTER; + } + + void HoleTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _holeTool = new Noggit::Ui::hole_tool(mapView()); + toolPanel->registerTool(name(), _holeTool); + } + + ToolDrawParameters HoleTool::drawParameters() const + { + return + { + .radius = _holeTool->brushRadius(), + }; + } + + void HoleTool::onSelected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_lines = true; + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_hole_lines = true; + } + + void HoleTool::onDeselected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_lines = mapView()->drawAdtGrid(); + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_hole_lines = mapView()->drawHoleGrid(); + } + + void HoleTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || !params.left_mouse) + { + return; + } + + auto mv = mapView(); + // no undermap check here, else it's impossible to remove holes + if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_HOLES, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + mv->getWorld()->setHole(mv->cursorPosition(), _holeTool->brushRadius(), params.mod_alt_down, false); + } + else if (params.mod_ctrl_down && !params.underMap) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_HOLES, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + mv->getWorld()->setHole(mv->cursorPosition(), _holeTool->brushRadius(), params.mod_alt_down, true); + } + } + + void HoleTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.left_mouse && params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _holeTool->changeRadius(params.relative_movement.dx() / XSENS); + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/HoleTool.hpp b/src/noggit/tools/HoleTool.hpp new file mode 100644 index 00000000..35f95533 --- /dev/null +++ b/src/noggit/tools/HoleTool.hpp @@ -0,0 +1,45 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui + { + class hole_tool; + } + + class HoleTool final : public Tool + { + public: + HoleTool(MapView* mapView); + ~HoleTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onDeselected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + private: + Ui::hole_tool* _holeTool = nullptr; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/ImpassTool.cpp b/src/noggit/tools/ImpassTool.cpp new file mode 100644 index 00000000..d9a965c3 --- /dev/null +++ b/src/noggit/tools/ImpassTool.cpp @@ -0,0 +1,71 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "ImpassTool.hpp" + +#include +#include +#include +#include + +namespace Noggit +{ + ImpassTool::ImpassTool(MapView* mapView) + : Tool{ mapView } + { + } + + char const* ImpassTool::name() const + { + return "Impass Designator"; + } + + editing_mode ImpassTool::editingMode() const + { + return editing_mode::impass; + } + + Ui::FontNoggit::Icons ImpassTool::icon() const + { + return Ui::FontNoggit::TOOL_IMPASS_DESIGNATOR; + } + + void ImpassTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + // Dummy, because the toolbar requires a widget for every tool + toolPanel->registerTool(name(), new QWidget{mapView()}); + } + + void ImpassTool::onSelected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = true; + } + + void ImpassTool::onDeselected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = false; + } + + void ImpassTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || params.underMap || !params.left_mouse) + { + return; + } + + // todo: replace this -- why and with what? + if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_FLAGS, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + mapView()->getWorld()->mapIndex.setFlag(true, mapView()->cursorPosition(), 0x2); + } + else if (params.mod_ctrl_down) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_FLAGS, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + mapView()->getWorld()->mapIndex.setFlag(false, mapView()->cursorPosition(), 0x2); + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/ImpassTool.hpp b/src/noggit/tools/ImpassTool.hpp new file mode 100644 index 00000000..2f18707a --- /dev/null +++ b/src/noggit/tools/ImpassTool.hpp @@ -0,0 +1,32 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + class ImpassTool final : public Tool + { + public: + ImpassTool(MapView* mapView); + ~ImpassTool() = default; + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + virtual void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + void onSelected() override; + + void onDeselected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/LightTool.cpp b/src/noggit/tools/LightTool.cpp new file mode 100644 index 00000000..9a8f44bc --- /dev/null +++ b/src/noggit/tools/LightTool.cpp @@ -0,0 +1,49 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "LightTool.hpp" + +#include +#include +#include +#include +#include + +namespace Noggit +{ + LightTool::LightTool(MapView* mapView) + : Tool{ mapView } + { + } + + LightTool::~LightTool() + { + delete _lightEditor; + } + + char const* LightTool::name() const + { + return "Light Editor"; + } + + editing_mode LightTool::editingMode() const + { + return editing_mode::light; + } + + Ui::FontNoggit::Icons LightTool::icon() const + { + return Ui::FontNoggit::TOOL_LIGHT; + } + + void LightTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _lightEditor = new Noggit::Ui::Tools::LightEditor(mapView(), mapView()); + toolPanel->registerTool(name(), _lightEditor); + } + + void LightTool::onTick(float deltaTime, TickParameters const& params) + { + if (mapView()->timeSpeed() > 0.0f) + _lightEditor->UpdateWorldTime(); + } +} \ No newline at end of file diff --git a/src/noggit/tools/LightTool.hpp b/src/noggit/tools/LightTool.hpp new file mode 100644 index 00000000..ed3511c1 --- /dev/null +++ b/src/noggit/tools/LightTool.hpp @@ -0,0 +1,36 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui::Tools + { + class LightEditor; + } + + class LightTool final : public Tool + { + public: + LightTool(MapView* mapView); + ~LightTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + void onTick(float deltaTime, TickParameters const& params) override; + + private: + Ui::Tools::LightEditor* _lightEditor = nullptr; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/MinimapTool.cpp b/src/noggit/tools/MinimapTool.cpp new file mode 100644 index 00000000..db4ca33b --- /dev/null +++ b/src/noggit/tools/MinimapTool.cpp @@ -0,0 +1,299 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "MinimapTool.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Noggit +{ + MinimapTool::MinimapTool(MapView* mapView) + : Tool{ mapView } + { + } + + MinimapTool::~MinimapTool() + { + delete _minimapTool; + } + + char const* MinimapTool::name() const + { + return "Minimap Editor"; + } + + editing_mode MinimapTool::editingMode() const + { + return editing_mode::minimap; + } + + Ui::FontNoggit::Icons MinimapTool::icon() const + { + return Ui::FontNoggit::TOOL_MINIMAP_EDITOR; + } + + void MinimapTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + auto mv = mapView(); + _minimapTool = new Noggit::Ui::MinimapCreator(mv, mv->getWorld(), mv); + toolPanel->registerTool(name(), _minimapTool); + + QObject::connect(_minimapTool, &Ui::MinimapCreator::onSave, [=] { + saving_minimap = true; + }); + } + + ToolDrawParameters MinimapTool::drawParameters() const + { + return + { + .radius = _minimapTool->brushRadius(), + .minimapRenderSettings = *_minimapTool->getMinimapRenderSettings(), + }; + } + + void MinimapTool::onSelected() + { + mapView()->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_selection_overlay = true; + mapView()->getMinimapWidget()->use_selection(_minimapTool->getSelectedTiles()); + } + + void MinimapTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || !params.left_mouse) + { + return; + } + } + + bool MinimapTool::preRender() + { + if (!saving_minimap) + { + return true; + } + + auto mv = mapView(); + auto world = mv->getWorld(); + auto settings = _minimapTool->getMinimapRenderSettings(); + + mv->setCameraDirty(); + + OpenGL::context::scoped_setter const _(::gl, mv->context()); + mv->makeCurrent(); + + bool mmap_render_success = false; + + static QProgressBar* progress; + static QPushButton* cancel_btn; + + auto init = [=](int max) { + progress = new QProgressBar(nullptr); + progress->setMinimum(0); + progress->setMaximum(max); + mv->mainWindow()->statusBar()->addPermanentWidget(progress); + + cancel_btn = new QPushButton(nullptr); + cancel_btn->setText("Cancel"); + + QObject::connect(cancel_btn, &QPushButton::clicked, + [=] + { + _mmap_async_index = 0; + _mmap_render_index = 0; + saving_minimap = false; + progress->deleteLater(); + cancel_btn->deleteLater(); + _mmap_combined_image.reset(); + }); + + mv->mainWindow()->statusBar()->addPermanentWidget(cancel_btn); + + QObject::connect(mv, &MapView::updateProgress, + [=](int value) + { + // This weirdness is required due to a bug on Linux when QT repaint crashes due to too many events + // being passed through. TODO: this potentially only masks the issue, which may reappear on faster + // hardware. + if (progress->value() != value) + progress->setValue(value); + }); + + // setup combined image if necessary + if (settings->combined_minimap) + { + _mmap_combined_image.emplace(8192, 8192, QImage::Format_RGBA8888); + _mmap_combined_image->fill(Qt::black); + } + }; + + auto save = [=, &mmap_render_success]() + { + while (!world->mapIndex.hasTile({ _mmap_async_index / 64, _mmap_async_index % 64 })) + { + ++_mmap_async_index; + } + + TileIndex tile = TileIndex(_mmap_async_index / 64, _mmap_async_index % 64); + + if (world->mapIndex.hasTile(tile)) + { + OpenGL::context::scoped_setter const _(::gl, mv->context()); + mv->makeCurrent(); + mmap_render_success = world->renderer()->saveMinimap(tile, settings, _mmap_combined_image); + + _mmap_render_index++; + emit mv->updateProgress(_mmap_render_index); + + if (!mmap_render_success) + { + LogError << "Minimap rendered incorrectly for tile: " << tile.x << "_" << tile.z << std::endl; + } + } + }; + + + switch (settings->export_mode) + { + case MinimapGenMode::CURRENT_ADT: + { + TileIndex tile = TileIndex(mv->getCamera()->position); + + if (world->mapIndex.hasTile(tile)) + { + mmap_render_success = world->renderer()->saveMinimap(tile, settings, _mmap_combined_image); + } + + if (mmap_render_success) + { + world->mapIndex.saveMinimapMD5translate(); + } + + saving_minimap = false; + + break; + } + case MinimapGenMode::MAP: + { + // init progress + if (!_mmap_async_index) + { + init(world->mapIndex.getNumExistingTiles()); + } + + if (!saving_minimap) + return false; + + if (_mmap_async_index < 4096 && static_cast(_mmap_render_index) < progress->maximum()) + { + save(); + _mmap_async_index++; + } + else + { + finishSaving(progress, cancel_btn, world, settings); + } + + //_main_window->statusBar()->showMessage("Minimap rendering done.", 2000); + break; + } + case MinimapGenMode::SELECTED_ADTS: + { + auto selected_tiles = _minimapTool->getSelectedTiles(); + + // init progress + if (!_mmap_async_index) + { + int n_selected_tiles = 0; + + for (int i = 0; i < 4096; ++i) + { + if (selected_tiles->at(i)) + n_selected_tiles++; + } + + init(n_selected_tiles); + } + + if (!saving_minimap) + return false; + + if (_mmap_async_index < 4096 && static_cast(_mmap_render_index) < progress->maximum()) + { + if (selected_tiles->at(_mmap_async_index)) + { + save(); + } + _mmap_async_index++; + } + else + { + finishSaving(progress, cancel_btn, world, settings); + } + + break; + } + } + + //minimapTool->progressUpdate(0); + return !saving_minimap; + } + + void MinimapTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _minimapTool->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_shift_down || params.mod_ctrl_down) + { + mapView()->doSelection(false, true); + } + } + } + + void MinimapTool::finishSaving(QProgressBar* progress, QPushButton* cancel_btn, World* world, MinimapRenderSettings* settings) + { + _mmap_async_index = 0; + _mmap_render_index = 0; + saving_minimap = false; + progress->deleteLater(); + cancel_btn->deleteLater(); + world->mapIndex.saveMinimapMD5translate(); + + // save combined minimap + if (settings->combined_minimap) + { + QString image_path = QString(std::string(world->basename + "_combined_minimap.png").c_str()); + QString str = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str()); + if (!(str.endsWith('\\') || str.endsWith('/'))) + { + str += "/"; + } + + QDir dir(str + "/textures/minimap/"); + if (!dir.exists()) + dir.mkpath("."); + + _mmap_combined_image->save(dir.filePath(image_path)); + _mmap_combined_image.reset(); + } + } + + void MinimapTool::saveSettings() + { + // Save minimap creator model filters + _minimapTool->saveFiltersToJSON(); + } +} \ No newline at end of file diff --git a/src/noggit/tools/MinimapTool.hpp b/src/noggit/tools/MinimapTool.hpp new file mode 100644 index 00000000..bf0206e4 --- /dev/null +++ b/src/noggit/tools/MinimapTool.hpp @@ -0,0 +1,60 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +class QProgressBar; +class QPushButton; +class World; +struct MinimapRenderSettings; + +namespace Noggit +{ + namespace Ui + { + class MinimapCreator; + } + + class MinimapTool final : public Tool + { + public: + MinimapTool(MapView* mapView); + ~MinimapTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + bool preRender() override; + + void onMouseMove(MouseMoveParameters const& params) override; + + void saveSettings() override; + + private: + Ui::MinimapCreator* _minimapTool = nullptr; + + unsigned _mmap_async_index = 0; + unsigned _mmap_render_index = 0; + std::optional _mmap_combined_image; + + bool saving_minimap = false; + + void finishSaving(QProgressBar* progress, QPushButton* cancel_btn, World* world, MinimapRenderSettings* settings); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/ObjectTool.cpp b/src/noggit/tools/ObjectTool.cpp new file mode 100644 index 00000000..46713570 --- /dev/null +++ b/src/noggit/tools/ObjectTool.cpp @@ -0,0 +1,968 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "ObjectTool.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Noggit +{ + ObjectTool::ObjectTool(MapView* mapView) + : Tool{ mapView } + { + setupHotkeys(); + } + + ObjectTool::~ObjectTool() + { + delete _objectEditor; + } + + unsigned int ObjectTool::actionModality() const + { + unsigned int actionModality = 0; + if (_moveObject) + actionModality |= Noggit::ActionModalityControllers::eMMB; + if (_keys) + actionModality |= Noggit::ActionModalityControllers::eSCALE; + if (_keyr) + actionModality |= Noggit::ActionModalityControllers::eROTATE; + + return actionModality; + } + + char const* ObjectTool::name() const + { + return "Object Editor"; + } + + editing_mode ObjectTool::editingMode() const + { + return editing_mode::object; + } + + Ui::FontNoggit::Icons ObjectTool::icon() const + { + return Ui::FontNoggit::TOOL_OBJECT_EDITOR; + } + + void ObjectTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + auto mv = mapView(); + + // initialize some saved defaults + _object_paste_params.rotate_on_terrain = mv->settings()->value("paste_params/rotate_on_terrain", true).toBool(); + + /* Tool */ + _objectEditor = new Noggit::Ui::object_editor(mv + , mv->getWorld() + , &_move_model_to_cursor_position + , &_snap_multi_selection_to_ground + , &_use_median_pivot_point + , &_object_paste_params + , &_rotate_along_ground + , &_rotate_along_ground_smooth + , &_rotate_along_ground_random + , &_move_model_snap_to_objects + , mv + ); + toolPanel->registerTool(name(), _objectEditor); + + /* Additional tools */ + + /* Area selection */ + _area_selection = new QRubberBand(QRubberBand::Rectangle, mv); + + /* Object Palette */ + _object_palette = new Noggit::Ui::ObjectPalette(mv, mv->project(), mv); + _object_palette->hide(); + + // Dock + _object_palette_dock = new QDockWidget("Object Palette", mv); + _object_palette_dock->setFeatures(QDockWidget::DockWidgetMovable + | QDockWidget::DockWidgetFloatable + | QDockWidget::DockWidgetClosable + ); + + _object_palette_dock->setWidget(_object_palette); + _object_palette_dock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); + mv->mainWindow()->addDockWidget(Qt::BottomDockWidgetArea, _object_palette_dock); + _object_palette_dock->hide(); + // End Dock + + QObject::connect(_object_palette_dock, &QDockWidget::visibilityChanged, + [=](bool visible) + { + if (mv->isUiHidden()) + return; + + mv->settings()->setValue("map_view/object_palette", visible); + mv->settings()->sync(); + }); + + QObject::connect(mapView(), &MapView::rotationChanged, [=] { + updateRotationEditor(); + }); + + QObject::connect(_objectEditor, &Ui::object_editor::objectPaletteBtnPressed, [=] { + _object_palette_dock->setVisible(_object_palette_dock->isHidden()); + }); + + QObject::connect(mapView(), &MapView::selectionUpdated, [=](auto) { + _objectEditor->update_selection_ui(mapView()->getWorld()); + }); + + using AssetBrowser = Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget; + QObject::connect(mapView()->getAssetBrowserWidget(), &AssetBrowser::selectionChanged, [=](std::string const& path) { + if (_objectEditor->isVisible()) _objectEditor->copy(path); + }); + + QObject::connect(_object_palette, &Ui::ObjectPalette::selected, [=](std::string str) { + _objectEditor->copy(str); + }); + } + + ToolDrawParameters ObjectTool::drawParameters() const + { + return + { + .radius = _objectEditor->brushRadius(), + }; + } + + float ObjectTool::brushRadius() const + { + return _objectEditor->brushRadius(); + } + + bool ObjectTool::useMultiselectionPivot() const + { + return _use_median_pivot_point.get(); + } + + bool ObjectTool::useMedianPivotPoint() const + { + return _use_median_pivot_point.get(); + } + + void ObjectTool::registerMenuItems(QMenu* menu) + { + addMenuTitle(menu, name()); + + addMenuItem(menu, "Last M2 from WMV", QKeySequence{ "Shift+V" }, [this] { _objectEditor->import_last_model_from_wmv(eMODEL); }); + addMenuItem(menu, "Last WMO from WMV", QKeySequence{ "Alt+V" }, [this] { _objectEditor->import_last_model_from_wmv(eWMO); }); + addMenuItem(menu, "Helper models", [this] {_objectEditor->helper_models_widget->show(); }); + } + + void ObjectTool::registerContextMenuItems(QMenu* menu) + { + auto world = mapView()->getWorld(); + addMenuTitle(menu, name()); + + bool has_selected_objects = world->get_selected_model_count(); + bool has_copied_objects = _objectEditor->clipboardSize(); + + addMenuItem(menu, "Copy Object(s)", QKeySequence::Copy, has_selected_objects, [=] { _objectEditor->copy_current_selection(world); }); + addMenuItem(menu, "Paste Object(s)", QKeySequence::Paste, has_copied_objects, [=] { + auto mv = mapView(); + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_ADDED); + _objectEditor->pasteObject(mv->cursorPosition(), mv->getCamera()->position, world, &_object_paste_params); + NOGGIT_ACTION_MGR->endAction(); + }); + + addMenuItem(menu, "Delete Object(s)", QKeySequence::Delete, has_selected_objects, [=] { + auto mv = mapView(); + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_REMOVED); + mv->DeleteSelectedObjects(); + NOGGIT_ACTION_MGR->endAction(); + }); + + addMenuItem(menu, "Duplicate Object(s)", { "CTRL+B" }, has_copied_objects, [=] { + auto mv = mapView(); + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_ADDED); + _objectEditor->copy_current_selection(world); + _objectEditor->pasteObject(mv->cursorPosition(), mv->getCamera()->position, world, &_object_paste_params); + NOGGIT_ACTION_MGR->endAction(); + }); + + addMenuSeperator(menu); + + addMenuItem(menu, "Select all Like Selected", "Warning : Doing actions on models overlapping unloaded tiles can cause crash", + world->get_selected_model_count() == 1, [=] { + auto world = mapView()->getWorld(); + + auto last_entry = world->get_last_selected_model(); + if (last_entry) + { + if (!last_entry.value().index() == eEntry_Object) + return; + + auto obj = std::get(last_entry.value()); + auto model_name = obj->instance_model()->file_key().filepath(); + // auto models = world->get_models_by_filename()[model_name]; + + // if changing this, make sure to check for duplicate instead // if (!world->is_selected(instance)) + world->reset_selection(); + + if (obj->which() == eMODEL) + { + world->getModelInstanceStorage().for_each_m2_instance([&](ModelInstance& model_instance) + { + if (model_instance.instance_model()->file_key().filepath() == model_name) + { + world->add_to_selection(&model_instance); + } + }); + } + else if (obj->which() == eWMO) + world->getModelInstanceStorage().for_each_wmo_instance([&](WMOInstance& wmo_instance) + { + if (wmo_instance.instance_model()->file_key().filepath() == model_name) + { + // objects_to_select.push_back(wmo_instance.uid); + world->add_to_selection(&wmo_instance); + } + }); + + // for (auto uid_it = objects_to_select.begin(); uid_it != objects_to_select.end(); uid_it++) + // { + // auto instance = world->getObjectInstance(*uid_it); + // // if (!world->is_selected(instance)) + // world->add_to_selection(instance); + // } + } + }); + + addMenuItem(menu, "Hide Selected Objects", Qt::Key_H, has_selected_objects, [=] { + if (world->has_selection()) + { + for (auto& obj : world->get_selected_objects()) + { + if (obj->which() == eMODEL) + static_cast(obj)->model->hide(); + else if (obj->which() == eWMO) + static_cast(obj)->wmo->hide(); + } + } + }); + + addMenuItem(menu, "Hide Unselected Objects (NOT IMPLEMENTED)", [] {}); + + // QAction action_2("Show Hidden", this); + + addMenuItem(menu, "Add Object To Palette", QKeySequence::UnknownKey, world->get_selected_model_count(), + [=] { + auto last_entry = world->get_last_selected_model(); + if (last_entry) + { + if (!last_entry.value().index() == eEntry_Object) + return; + + _object_palette_dock->setVisible(true); + auto obj = std::get(last_entry.value()); + auto model_name = obj->instance_model()->file_key().filepath(); + _object_palette->addObjectByFilename(model_name.c_str()); + } + }); + + addMenuSeperator(menu); + + // allow replacing all selected? + addMenuItem(menu, "Replace Models (By Clipboard)", "Replace the currently selected objects by the object in the clipboard (There must only be one!). M2s can only be replaced by m2s", + has_selected_objects && _objectEditor->clipboardSize() == 1, [=] { + auto mv = mapView(); + + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + + if (mv->get_editing_mode() != editing_mode::object && NOGGIT_CUR_ACTION) + return; + + if (!_objectEditor->clipboardSize()) + return; + + // verify this + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_ADDED | Noggit::ActionFlags::eOBJECTS_REMOVED); + + // get the model to replace by + auto replace_select = _objectEditor->getClipboard().front(); + auto replacement_obj = std::get(replace_select); + auto& replace_path = replacement_obj->instance_model()->file_key().filepath(); + + std::vector objects_to_delete; + + // iterate selection (objects to replace) + std::vector selected_objects = world->get_selected_objects(); + for (SceneObject* old_obj : selected_objects) + { + if (old_obj->instance_model()->file_key().filepath() == replace_path) + continue; + + math::degrees::vec3 source_rot(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._); + source_rot = old_obj->dir; + float source_scale = old_obj->scale; + glm::vec3 source_pos = old_obj->pos; + + // world->deleteInstance(old_obj->uid); + objects_to_delete.emplace_back(old_obj); + + if (replacement_obj->which() == eWMO) + { + // auto replace_wmo = static_cast(replacement_obj); + // auto source_wmo = static_cast(old_obj); + + auto new_obj = world->addWMOAndGetInstance(replace_path, source_pos, source_rot, true); + new_obj->wmo->wait_until_loaded(); + new_obj->wmo->waitForChildrenLoaded(); + new_obj->recalcExtents(); + } + else if (replacement_obj->which() == eMODEL) + { + // auto replace_m2 = static_cast(replacement_obj); + // auto source_m2 = static_cast(source_obj); + + // Just swapping model + // Issue : doesn't work with actions + // world->updateTilesEntry(entry, model_update::remove); + // source_m2->model = scoped_model_reference(replace_path, _context); + // source_m2->recalcExtents(); + // world->updateTilesEntry(entry, model_update::add); + + auto new_obj = world->addM2AndGetInstance(replace_path + , source_pos + , source_scale + , source_rot + , &_object_paste_params + , true + , true + ); + new_obj->model->wait_until_loaded(); + new_obj->model->waitForChildrenLoaded(); + new_obj->recalcExtents(); + } + } + // this would also delete models that got skipped + // world->delete_selected_models(); + + world->deleteObjects(objects_to_delete, true); + world->reset_selection(); + + NOGGIT_ACTION_MGR->endAction(); + }); + + addMenuItem(menu, "Snap Selected To Ground", Qt::Key_PageDown, has_selected_objects, [=] { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eOBJECTS_TRANSFORMED); + mapView()->snap_selected_models_to_the_ground(); + NOGGIT_ACTION_MGR->endAction(); + }); + + addMenuItem(menu, "Save objects coords(to file)", QKeySequence::UnknownKey, has_selected_objects, [=] { + if (world->has_selection() && world->get_selected_model_count()) + { + std::stringstream obj_data; + for (auto& obj : world->get_selected_objects()) + { + obj_data << "\"Object : " << obj->instance_model()->file_key().filepath() << "(UID :" << obj->uid << ")\"," << std::endl; + obj_data << "\"Scale : " << obj->scale << "\"," << std::endl; + // coords string in ts-wow format + obj_data << "\"Coords(server): {map:" << world->getMapID() << ",x:" << (ZEROPOINT - obj->pos.z) << ",y:" << (ZEROPOINT - obj->pos.x) + << ",z:" << obj->pos.y << ",o:"; + + float server_rot = 2 * glm::pi() - glm::pi() / 180.0 * (float(obj->dir.y) < 0 ? fabs(float(obj->dir.y)) + 180.0 : fabs(float(obj->dir.y) - 180.0)); + // float server_rot = glm::radians(obj->dir.y) + glm::radians(180.f); + + obj_data << server_rot << "}\"," << std::endl; + + /// converting db gobject rotation to noggit. Keep commented for later usage + /* + glm::quat test_db_quat = glm::quat(1.0, 1.0, 1.0, 1.0); + test_db_quat.x = 0.607692, test_db_quat.y = -0.361538, test_db_quat.z = 0.607693, test_db_quat.w = 0.361539; + glm::vec3 rot_euler = glm::eulerAngles(test_db_quat); + glm::vec3 rot_degrees = glm::degrees(rot_euler); + rot_degrees = glm::vec3(rot_degrees.y, rot_degrees.z - 180.f, rot_degrees.x); // final noggit coords + */ + + glm::quat rot_quat = glm::quat(glm::vec3(glm::radians(obj->dir.z), glm::radians(obj->dir.x), server_rot)); + auto normalized_quat = glm::normalize(rot_quat); + + obj_data << "\"Rotation (server quaternion): {x:" << normalized_quat.x << ",y:" << normalized_quat.y << ",z:" << normalized_quat.z + << ",w:" << normalized_quat.w << "}\"," << std::endl << "\n"; + } + + std::ofstream f("saved_objects_data.txt", std::ios_base::app); + f << "\"Saved " << world->get_selected_model_count() << " objects at : " << QDateTime::currentDateTime().toString("dd MMMM yyyy hh:mm:ss").toStdString() << "\"" << std::endl; + f << obj_data.str(); + f.close(); + }}); + + addMenuSeperator(menu); + + bool groupable = false; + if (world->has_multiple_model_selected()) + { + // if there's no existing groups, that means it's always groupable + if (!world->_selection_groups.size()) + groupable = true; + + if (!groupable) + { + // check if there's any ungrouped object + for (auto obj : world->get_selected_objects()) + { + bool obj_ungrouped = true; + for (auto& group : world->_selection_groups) + { + if (group.contains_object(obj)) + obj_ungrouped = false; + } + if (obj_ungrouped) + { + groupable = true; + break; + } + } + } + } + // TODO + addMenuItem(menu, "Group Selected Objects", QKeySequence::UnknownKey, groupable, [=] { + // remove all groups the objects are already in and create a new one + // for (auto obj : _world->get_selected_objects()) + // { + // for (auto& group : _world->_selection_groups) + // { + // if (group.contains_object(obj)) + // { + // group.remove_group(); + // } + // } + // } + for (auto& group : world->_selection_groups) + { + if (group.isSelected()) + { + group.remove_group(); + } + } + + world->add_object_group_from_selection(); + }); + + bool group_selected = false; + for (auto& group : world->_selection_groups) + { + if (group.isSelected()) + { + group_selected = true; + break; + } + } + addMenuItem(menu, "Ungroup Selected Objects", QKeySequence::UnknownKey, group_selected, [=] { + world->clear_selection_groups(); + }); + } + + void ObjectTool::onSelected() + { + _object_palette_dock->setVisible(!mapView()->isUiHidden() && mapView()->settings()->value("map_view/object_palette", false).toBool()); + } + + void ObjectTool::onDeselected() + { + _objectEditor->modelImport->hide(); + _objectEditor->rotationEditor->hide(); + _object_palette->hide(); + _object_palette_dock->hide(); + _moveObject = false; + } + + void ObjectTool::onTick(float deltaTime, TickParameters const& params) + { + unsigned action_modality = 0; + + float numpad_moveratio = 0.001f; + + if (mapView()->getWorld()->has_selection()) + { + auto mv = mapView(); + auto world = mv->getWorld(); + + // reset numpad_moveratio when no numpad key is pressed + if (!(_keyx != 0 || _keyy != 0 || _keyz != 0 || _keyr != 0 || _keys != 0)) + { + numpad_moveratio = 0.5f; + } + else // Set move scale and rotate for numpad keys + { + if (params.mod_ctrl_down && params.mod_shift_down) + { + numpad_moveratio += 0.5f; + } + else if (params.mod_shift_down) + { + numpad_moveratio += 0.05f; + } + else if (params.mod_ctrl_down) + { + numpad_moveratio += 0.005f; + } + } + + if (_keys != 0.f) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eSCALE); + world->scale_selected_models(_keys * numpad_moveratio / 50.f, World::m2_scaling_type::add); + updateRotationEditor(); + } + if (_keyr != 0.f) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eROTATE); + world->rotate_selected_models(math::degrees(0.f) + , math::degrees(_keyr * numpad_moveratio * 5.f) + , math::degrees(0.f) + , _use_median_pivot_point.get() + ); + updateRotationEditor(); + } + + if (_moveObject) + { + if (params.mod_alt_down) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eALT + | Noggit::ActionModalityControllers::eMMB); + world->scale_selected_models(std::pow(2.f, _mv * 4.f), World::m2_scaling_type::mult); + } + else if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eMMB); + world->move_selected_models(0.f, _mv * 80.f, 0.f); + } + else if (params.mod_ctrl_down) + { + // do nothing + } + else + { + bool snapped = false; + bool snapped_to_object = false; + if (world->has_multiple_model_selected()) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eMMB); + world->set_selected_models_pos(mv->cursorPosition(), false); + + if (_snap_multi_selection_to_ground.get()) + { + mv->snap_selected_models_to_the_ground(); + snapped = true; + } + } + else + { + if (!_move_model_to_cursor_position.get()) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eMMB); + + if ((_mh <= 0.01f && _mh >= -0.01f) && (_mv <= 0.01f && _mv >= -0.01f)) + { + glm::vec3 _vec = (_mh * params.dirUp + _mv * params.dirRight); + world->move_selected_models(_vec * 500.f); + } + } + else + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eMMB); + + if (_move_model_to_cursor_position.get() || _move_model_snap_to_objects.get()) + { + selection_result results(mv->intersect_result(false)); + + if (!results.empty()) + { + for (auto result = results.begin(); result != results.end(); result++) + { + auto const& hit(result->second); + bool is_selected_model = false; + + // if a terrain is found first use that (terrain cursor pos position updated on move already) + if (hit.index() == eEntry_MapChunk && _move_model_to_cursor_position.get()) + { + break; + } + + if (hit.index() == eEntry_Object && _move_model_snap_to_objects.get()) + { + auto obj_hit = std::get(hit); + auto obj_hit_type = obj_hit->which(); + + // don't snap to animated models + if (obj_hit_type == eMODEL) + { + auto m2_model_hit = static_cast(obj_hit); + if (m2_model_hit->model->animated_mesh()) + continue; + } + + // find and ignore current object/selected models or it will keep snaping to itself + for (auto& entry : world->current_selection()) + { + auto type = entry.index(); + if (type == eEntry_Object) + { + auto& selection_obj = std::get(entry); + if (selection_obj->uid == obj_hit->uid) + { + is_selected_model = true; + break; + } + } + } + if (is_selected_model) + continue; + auto hit_pos = mv->intersect_ray().position(result->first); + mv->cursorPosition(hit_pos); + snapped_to_object = true; + // TODO : rotate objects to objects normal + // if (_rotate_doodads_along_doodads.get()) + // world->rotate_selected_models_to_object_normal(_rotate_along_ground_smooth.get(), obj_hit, hit_pos, glm::transpose(model_view()), _rotate_doodads_along_wmos.get()); + break; + } + } + } + world->set_selected_models_pos(mv->cursorPosition(), false); + snapped = true; + } + } + } + + if (snapped && _rotate_along_ground.get()) + { + if (!snapped_to_object) + world->rotate_selected_models_to_ground_normal(_rotate_along_ground_smooth.get()); + + if (_rotate_along_ground_random.get()) + { + float minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0; + + if (mv->settings()->value("model/random_rotation", false).toBool()) + { + minY = _object_paste_params.minRotation; + maxY = _object_paste_params.maxRotation; + } + + if (mv->settings()->value("model/random_tilt", false).toBool()) + { + minX = _object_paste_params.minTilt; + maxX = _object_paste_params.maxTilt; + minZ = minX; + maxZ = maxX; + } + + world->rotate_selected_models_randomly( + minX, + maxX, + minY, + maxY, + minZ, + maxZ); + + if (mv->settings()->value("model/random_size", false).toBool()) + { + float min = _object_paste_params.minScale; + float max = _object_paste_params.maxScale; + + world->scale_selected_models(misc::randfloat(min, max), World::m2_scaling_type::set); + } + } + } + } + + updateRotationEditor(); + } + + /* TODO: Numpad for action system + if (_keyx != 0.f || _keyy != 0.f || _keyz != 0.f) + { + world->move_selected_models(_keyx * numpad_moveratio, _keyy * numpad_moveratio, _keyz * numpad_moveratio); + updateRotationEditor(); + } + */ + + if (mv->isRotatingCamera()) + { + if (params.mod_ctrl_down) // X + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eRMB); + world->rotate_selected_models(math::degrees(_rh + _rv) + , math::degrees(0.f) + , math::degrees(0.f) + , _use_median_pivot_point.get() + ); + } + if (params.mod_shift_down) // Y + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eRMB); + world->rotate_selected_models(math::degrees(0.f) + , math::degrees(_rh + _rv) + , math::degrees(0.f) + , _use_median_pivot_point.get() + ); + } + if (params.mod_alt_down) // Z + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, + Noggit::ActionModalityControllers::eALT + | Noggit::ActionModalityControllers::eRMB); + world->rotate_selected_models(math::degrees(0.f) + , math::degrees(0.f) + , math::degrees(_rh + _rv) + , _use_median_pivot_point.get() + ); + } + + updateRotationEditor(); + } + } + + _mh = 0; + _mv = 0; + _rh = 0; + _rv = 0; + } + + void ObjectTool::onMousePress(MousePressParameters const& params) + { + if (params.button == Qt::MouseButton::LeftButton && !params.mod_ctrl_down) + { + _area_selection->setGeometry(QRect(_drag_start_pos, QSize())); + _area_selection->show(); + _drag_start_pos = params.mouse_position; + mapView()->invalidate(); + } + + if (params.button == Qt::MouseButton::MiddleButton) + { + _moveObject = true; + } + } + + void ObjectTool::onMouseRelease(MouseReleaseParameters const& params) + { + if (params.button == Qt::MouseButton::MiddleButton) + { + _moveObject = false; + return; + } + + if (params.button != Qt::MouseButton::LeftButton || params.mod_ctrl_down) + { + return; + } + + auto drag_end_pos = params.mouse_position; + + if (_drag_start_pos != drag_end_pos && !ImGuizmo::IsUsing()) + { + const std::array selection_box + { + glm::vec2(std::min(_drag_start_pos.x(), drag_end_pos.x()), std::min(_drag_start_pos.y(), drag_end_pos.y())), + glm::vec2(std::max(_drag_start_pos.x(), drag_end_pos.x()), std::max(_drag_start_pos.y(), drag_end_pos.y())) + }; + // _world->select_objects_in_area(selection_box, !_mod_shift_down, model_view(), projection(), width(), height(), objectEditor->drag_selection_depth(), _camera.position); + mapView()->selectObjects(selection_box, 3000.0f); + } + else // Do normal selection when we just clicked + { + mapView()->doSelection(false); + } + + _area_selection->hide(); + } + + void ObjectTool::onMouseMove(MouseMoveParameters const& params) + { + auto mapView = this->mapView(); + if (_moveObject) + { + _mh = -mapView->aspect_ratio() * params.relative_movement.dx() / static_cast(mapView->width()); + _mv = -params.relative_movement.dy() / static_cast(mapView->height()); + } + else + { + _mh = 0.0f; + _mv = 0.0f; + } + + if (params.mod_shift_down || params.mod_ctrl_down || params.mod_alt_down || params.mod_space_down) + { + _rh = params.relative_movement.dx() / XSENS * 5.0f; + _rv = params.relative_movement.dy() / YSENS * 5.0f; + } + + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _objectEditor->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (!params.mod_alt_down && params.displayMode == display_mode::in_3D && !ImGuizmo::IsUsing()) + { + _area_selection->setGeometry(QRect(_drag_start_pos, params.mouse_position).normalized()); + mapView->invalidate(); + } + + if (params.mod_shift_down || params.mod_ctrl_down) + { + mapView->doSelection(false, true); + } + } + } + + void ObjectTool::hidePopups() + { + _objectEditor->modelImport->hide(); + _objectEditor->rotationEditor->hide(); + _objectEditor->helper_models_widget->hide(); + _object_palette_dock->hide(); + } + + void ObjectTool::onFocusLost() + { + _keyx = 0; + _keyz = 0; + _keyy = 0; + _keyr = 0; + _keys = 0; + _moveObject = false; + } + + void ObjectTool::setupHotkeys() + { + auto mapView = this->mapView(); + + addHotkey("copySelection"_hash, Hotkey{ + .onPress = [=] { _objectEditor->copy_current_selection(mapView->getWorld()); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("paste"_hash, Hotkey{ + .onPress = [=] { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eOBJECTS_ADDED); + _objectEditor->pasteObject(mapView->cursorPosition(), mapView->getCamera()->position, mapView->getWorld(), &_object_paste_params); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("importM2FromWmv"_hash, Hotkey{ + .onPress = [=] { _objectEditor->import_last_model_from_wmv(eMODEL); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("importWmoFromWmv"_hash, Hotkey{ + .onPress = [=] { _objectEditor->import_last_model_from_wmv(eWMO); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("duplacteSelection"_hash, Hotkey{ + .onPress = [=] { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eOBJECTS_ADDED); + _objectEditor->copy_current_selection(mapView->getWorld()); + _objectEditor->pasteObject(mapView->cursorPosition(), mapView->getCamera()->position, mapView->getWorld(), &_object_paste_params); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("togglePasteMode"_hash, Hotkey{ + .onPress = [=] { _objectEditor->togglePasteMode(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("moveSelectedDown"_hash, Hotkey{ + .onPress = [=] { _keyx = 1; }, + .onRelease = [=] { _keyx = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("moveSelectedUp"_hash, Hotkey{ + .onPress = [=] { _keyx = -1; }, + .onRelease = [=] { _keyx = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("moveSelectedLeft"_hash, Hotkey{ + .onPress = [=] { _keyz = 1; }, + .onRelease = [=] { _keyz = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("moveSelectedRight"_hash, Hotkey{ + .onPress = [=] { _keyz = -1; }, + .onRelease = [=] { _keyz = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("rotateSelectedPitchCcw"_hash, Hotkey{ + .onPress = [=] { _keyy = 1; }, + .onRelease = [=] { _keyy = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("rotateSelectedPitchCw"_hash, Hotkey{ + .onPress = [=] { _keyy = -1; }, + .onRelease = [=] { _keyy = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("rotateSelectedYawCcw"_hash, Hotkey{ + .onPress = [=] { _keyr = 1; }, + .onRelease = [=] {_keyr = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("rotateSelectedYawCw"_hash, Hotkey{ + .onPress = [=] {_keyr = -1; }, + .onRelease = [=] {_keyr = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("increaseSelectedScale"_hash, Hotkey{ + .onPress = [=] { _keys = 1; }, + .onRelease = [=] { _keys = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + + addHotkey("decreaseSelectedScale"_hash, Hotkey{ + .onPress = [=] { _keys = -1; }, + .onRelease = [=] { _keys = 0; }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::object; }, + }); + } + + void ObjectTool::updateRotationEditor() + { + _objectEditor->rotationEditor->updateValues(mapView()->getWorld()); + } +} \ No newline at end of file diff --git a/src/noggit/tools/ObjectTool.hpp b/src/noggit/tools/ObjectTool.hpp new file mode 100644 index 00000000..164c0133 --- /dev/null +++ b/src/noggit/tools/ObjectTool.hpp @@ -0,0 +1,93 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include +#include +#include + +class QRubberBand; +class QDockWidget; + +namespace Noggit +{ + namespace Ui + { + class object_editor; + class ObjectPalette; + } + + class ObjectTool final : public Tool + { + public: + ObjectTool(MapView* mapView); + ~ObjectTool(); + + [[nodiscard]] + unsigned int actionModality() const override; + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + [[nodiscard]] + float brushRadius() const override; + + [[nodiscard]] + bool useMultiselectionPivot() const override; + + [[nodiscard]] + bool useMedianPivotPoint() const override; + + void registerMenuItems(QMenu* menu) override; + + void registerContextMenuItems(QMenu* menu) override; + + void onSelected() override; + + void onDeselected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMousePress(MousePressParameters const& params) override; + + void onMouseRelease(MouseReleaseParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + void hidePopups() override; + + void onFocusLost() override; + + private: + Ui::object_editor* _objectEditor = nullptr; + QRubberBand* _area_selection = nullptr; + Ui::ObjectPalette* _object_palette = nullptr; + QDockWidget* _object_palette_dock = nullptr; + object_paste_params _object_paste_params; + BoolToggleProperty _move_model_to_cursor_position = { true }; + BoolToggleProperty _snap_multi_selection_to_ground = { false }; + BoolToggleProperty _use_median_pivot_point = { true }; + BoolToggleProperty _rotate_along_ground = { true }; + BoolToggleProperty _rotate_along_ground_smooth = { true }; + BoolToggleProperty _rotate_along_ground_random = { false }; + BoolToggleProperty _move_model_snap_to_objects = { true }; + QPoint _drag_start_pos; + float _keyx = 0, _keyy = 0, _keyz = 0, _keyr = 0, _keys = 0; + float _mh = 0, _mv = 0, _rh = 0, _rv = 0; // mh = left click x, rv = right click y + bool _moveObject = false; + + void setupHotkeys(); + void updateRotationEditor(); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/RaiseLowerTool.cpp b/src/noggit/tools/RaiseLowerTool.cpp new file mode 100644 index 00000000..0461cd1d --- /dev/null +++ b/src/noggit/tools/RaiseLowerTool.cpp @@ -0,0 +1,254 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "RaiseLowerTool.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace Noggit +{ + RaiseLowerTool::RaiseLowerTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("nextType"_hash, Hotkey{ + .onPress = [this] { _terrainTool->nextType(); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::ground && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("flatten"_hash, Hotkey{ + .onPress = [this] { + NOGGIT_ACTION_MGR->beginAction(this->mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN); + _terrainTool->flattenVertices(this->mapView()->getWorld()); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::ground && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("increaseRadius"_hash, Hotkey{ + .onPress = [this] { _terrainTool->changeRadius(0.01f); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::ground && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("decreaseRadius"_hash, Hotkey{ + .onPress = [this] { _terrainTool->changeRadius(-0.01f); }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::ground && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("clearVertexSelection"_hash, Hotkey{ + .onPress = [=] { + NOGGIT_ACTION_MGR->beginAction(mapView, Noggit::ActionFlags::eVERTEX_SELECTION); + mapView->getWorld()->clearVertexSelection(); + NOGGIT_ACTION_MGR->endAction(); + }, + .condition = [mapView] { return mapView->get_editing_mode() == editing_mode::ground && !NOGGIT_CUR_ACTION; }, + }); + } + + RaiseLowerTool::~RaiseLowerTool() + { + delete _terrainTool; + } + + char const* RaiseLowerTool::name() const + { + return "Raise / Lower"; + } + + editing_mode RaiseLowerTool::editingMode() const + { + return editing_mode::ground; + } + + Ui::FontNoggit::Icons RaiseLowerTool::icon() const + { + return Ui::FontNoggit::TOOL_RAISE_LOWER; + } + + void RaiseLowerTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _terrainTool = new Noggit::Ui::TerrainTool{ mapView(), mapView() }; + toolPanel->registerTool(name(), _terrainTool); + + QObject::connect(_terrainTool + , &Noggit::Ui::TerrainTool::updateVertices + , [mapView = mapView()](int vertex_mode, math::degrees const& angle, math::degrees const& orientation) + { + mapView->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mapView->context()); + + mapView->getWorld()->orientVertices(vertex_mode == eVertexMode_Mouse + ? mapView->cursorPosition() + : mapView->getWorld()->vertexCenter() + , angle + , orientation + ); + } + ); + } + + ToolDrawParameters RaiseLowerTool::drawParameters() const + { + CursorType cursorType = CursorType::CIRCLE; + if ((_terrainTool->_edit_type != eTerrainType_Vertex && _terrainTool->_edit_type != eTerrainType_Script) && _terrainTool->getImageMaskSelector()->isEnabled()) + cursorType = CursorType::STAMP; + + return ToolDrawParameters + { + .radius = _terrainTool->brushRadius(), + .inner_radius = _terrainTool->innerRadius(), + .cursor_type = cursorType, + .terrain_type = _terrainTool->_edit_type, + }; + } + + void RaiseLowerTool::onSelected() + { + if (_terrainTool->_edit_type != eTerrainType_Vertex + || (_terrainTool->_edit_type != eTerrainType_Script && _terrainTool->getImageMaskSelector()->isEnabled())) + { + _terrainTool->updateMaskImage(); + } + } + + void RaiseLowerTool::onTick(float deltaTime, TickParameters const& params) + { + if (!params.left_mouse) + { + return; + } + + if (params.displayMode == display_mode::in_3D && !params.underMap) + { + auto mask_selector = _terrainTool->getImageMaskSelector(); + auto mv = mapView(); + + if (params.mod_shift_down && (!mask_selector->isEnabled() || mask_selector->getBrushMode())) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeTerrainRotation(); }); + + _terrainTool->changeTerrain(mv->getWorld(), mv->cursorPosition(), 7.5f * deltaTime); + } + else if (params.mod_ctrl_down && (!mask_selector->isEnabled() || mask_selector->getBrushMode())) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeTerrainRotation(); }); + + _terrainTool->changeTerrain(mv->getWorld(), mv->cursorPosition(), -7.5f * deltaTime); + } + } + } + + void RaiseLowerTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.right_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + if (_terrainTool->_edit_type == eTerrainType_Vertex) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eALT | Noggit::ActionModalityControllers::eRMB); + _terrainTool->changeOrientation(-params.relative_movement.dx() / XSENS * 4.5f); + } + else + { + _terrainTool->changeInnerRadius(params.relative_movement.dx() / 100.0f); + } + } + + if (!params.mod_alt_down && params.mod_shift_down && !params.mod_ctrl_down) + { + if (_terrainTool->_edit_type == eTerrainType_Vertex) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eSHIFT | Noggit::ActionModalityControllers::eRMB); + _terrainTool->moveVertices(mapView()->getWorld(), -params.relative_movement.dy() / YSENS); + } + } + + if (!params.mod_alt_down && !params.mod_shift_down && params.mod_ctrl_down) + { + if (_terrainTool->_edit_type == eTerrainType_Vertex) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eCTRL | + Noggit::ActionModalityControllers::eRMB); + _terrainTool->changeAngle(-params.relative_movement.dy() / YSENS * 4.f); + } + } + + if (params.mod_space_down) + { + if (_terrainTool->_edit_type == eTerrainType_Vertex) + { + NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eRMB + | Noggit::ActionModalityControllers::eSPACE); + _terrainTool->setOrientRelativeTo(mapView()->getWorld(), mapView()->cursorPosition()); + } + else if (_terrainTool->getImageMaskSelector()->isEnabled()) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, + Noggit::ActionModalityControllers::eRMB + | Noggit::ActionModalityControllers::eSPACE); + _terrainTool->getImageMaskSelector()->setRotation(-params.relative_movement.dx() / XSENS * 10.f); + action->setBlockCursor(true); + } + } + } + + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _terrainTool->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_space_down) + { + _terrainTool->changeSpeed(params.relative_movement.dx() / 30.0f); + } + + if (params.mod_shift_down && params.displayMode == display_mode::in_3D) + { + auto image_mask_selector = _terrainTool->getImageMaskSelector(); + if (_terrainTool->_edit_type != eTerrainType_Vertex && _terrainTool->_edit_type != eTerrainType_Script && + image_mask_selector->isEnabled() && !image_mask_selector->getBrushMode()) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eCHUNKS_TERRAIN, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeTerrainRotation(); }); + + _terrainTool->changeTerrain(mapView()->getWorld(), mapView()->cursorPosition(), params.relative_movement.dx() / 30.0f); + } + } + } + } + + void RaiseLowerTool::randomizeTerrainRotation() + { + auto image_mask_selector = _terrainTool->getImageMaskSelector(); + if (!image_mask_selector->getRandomizeRotation()) + return; + + unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); + std::mt19937 gen(ms); + std::uniform_int_distribution<> uid(0, 360); + + image_mask_selector->setRotation(uid(gen)); + } +} \ No newline at end of file diff --git a/src/noggit/tools/RaiseLowerTool.hpp b/src/noggit/tools/RaiseLowerTool.hpp new file mode 100644 index 00000000..cdac90fc --- /dev/null +++ b/src/noggit/tools/RaiseLowerTool.hpp @@ -0,0 +1,45 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui + { + class TerrainTool; + } + + class RaiseLowerTool final : public Tool + { + public: + RaiseLowerTool(MapView* mapView); + ~RaiseLowerTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + private: + Ui::TerrainTool* _terrainTool = nullptr; + + void randomizeTerrainRotation(); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/ScriptingTool.cpp b/src/noggit/tools/ScriptingTool.cpp new file mode 100644 index 00000000..0c6e479a --- /dev/null +++ b/src/noggit/tools/ScriptingTool.cpp @@ -0,0 +1,70 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "ScriptingTool.hpp" + +#include +#include +#include +#include +#include +#include + +namespace Noggit +{ + ScriptingTool::ScriptingTool(MapView* mapView) + : Tool{ mapView } + { + } + + ScriptingTool::~ScriptingTool() + { + delete _scriptingTool; + } + + char const* ScriptingTool::name() const + { + return "Scripting"; + } + + editing_mode ScriptingTool::editingMode() const + { + return editing_mode::scripting; + } + + Ui::FontNoggit::Icons ScriptingTool::icon() const + { + return Ui::FontNoggit::INFO; + } + + void ScriptingTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _scriptingTool = new Noggit::Scripting::scripting_tool(mapView(), mapView(), mapView()->settings()); + toolPanel->registerTool(name(), _scriptingTool); + } + + ToolDrawParameters ScriptingTool::drawParameters() const + { + return + { + .radius = _scriptingTool->get_settings()->brushRadius(), + .inner_radius = _scriptingTool->get_settings()->innerRadius(), + }; + } + + void ScriptingTool::onTick(float deltaTime, TickParameters const& params) + { + auto world = mapView()->getWorld(); + + auto currentSelection = world->current_selection(); + if (world->has_selection()) + { + for (auto& selection : currentSelection) + { + if (selection.index() == eEntry_MapChunk) + { + _scriptingTool->sendBrushEvent(mapView()->cursorPosition(), 7.5f * deltaTime); + } + } + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/ScriptingTool.hpp b/src/noggit/tools/ScriptingTool.hpp new file mode 100644 index 00000000..f0cf411e --- /dev/null +++ b/src/noggit/tools/ScriptingTool.hpp @@ -0,0 +1,39 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Scripting + { + class scripting_tool; + } + + class ScriptingTool final : public Tool + { + public: + ScriptingTool(MapView* mapView); + ~ScriptingTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onTick(float deltaTime, TickParameters const& params) override; + + private: + Scripting::scripting_tool* _scriptingTool = nullptr; + }; +} \ No newline at end of file diff --git a/src/noggit/tools/StampTool.cpp b/src/noggit/tools/StampTool.cpp new file mode 100644 index 00000000..40baa59f --- /dev/null +++ b/src/noggit/tools/StampTool.cpp @@ -0,0 +1,177 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "StampTool.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace Noggit +{ + StampTool::StampTool(MapView* mapView) + : Tool{ mapView } + { + } + + StampTool::~StampTool() + { + delete _stampTool; + } + + char const* StampTool::name() const + { + return "Stamp Mode"; + } + + editing_mode StampTool::editingMode() const + { + return editing_mode::stamp; + } + + Ui::FontNoggit::Icons StampTool::icon() const + { + return Ui::FontNoggit::TOOL_STAMP; + } + + void StampTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _stampTool = new Noggit::Ui::Tools::BrushStack(mapView(), mapView()); + toolPanel->registerTool(name(), _stampTool); + + QObject::connect(mapView(), &MapView::trySetBrushTexture, [=](QImage* brush, QWidget* sender) { + auto mv = mapView(); + auto item = _stampTool->getActiveBrushItem(); + + if (mv->get_editing_mode() != editing_mode::stamp || (item && item->getTool() == sender)) + { + mv->setBrushTexture(brush); + } + }); + } + + ToolDrawParameters StampTool::drawParameters() const + { + return + { + .radius = _stampTool->getRadius(), + .inner_radius = _stampTool->getInnerRadius(), + .cursor_type = (_stampTool->getActiveBrushItem() && _stampTool->getActiveBrushItem()->isMaskEnabled()) ? CursorType::STAMP : CursorType::CIRCLE, + }; + } + + void StampTool::onSelected() + { + if (_stampTool->getActiveBrushItem() && _stampTool->getActiveBrushItem()->isEnabled()) + { + _stampTool->getActiveBrushItem()->updateMask(); + } + } + + void StampTool::onTick(float deltaTime, TickParameters const& params) + { + if (!mapView()->getWorld()->has_selection() || !params.left_mouse) + { + return; + } + + auto mv = mapView(); + auto world = mv->getWorld(); + + for (auto& selection : world->current_selection()) + { + if (selection.index() != eEntry_MapChunk + || params.displayMode != display_mode::in_3D + || !(params.mod_shift_down || params.mod_ctrl_down || params.mod_alt_down) + || !_stampTool->getBrushMode()) + { + continue; + } + + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eNO_FLAG, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + + if (!_stampTool->getBrushMode()) + action->setBlockCursor(true); + + _stampTool->execute(mv->cursorPosition(), + world, deltaTime, + params.mod_shift_down, + params.mod_alt_down, + params.mod_ctrl_down, + world->isUnderMap(mv->cursorPosition())); + } + } + + void StampTool::onMouseMove(MouseMoveParameters const& params) + { + auto mv = mapView(); + if (params.right_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _stampTool->changeInnerRadius(params.relative_movement.dx() / 300.0f); + } + + if (params.mod_space_down) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, + Noggit::ActionModalityControllers::eRMB + | Noggit::ActionModalityControllers::eSPACE); + + _stampTool->changeRotation(-params.relative_movement.dx() / XSENS * 10.f); + action->setBlockCursor(true); + } + } + + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _stampTool->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_space_down) + { + _stampTool->changeSpeed(params.relative_movement.dx() / XSENS); + } + + if (params.mod_shift_down) + { + if(params.displayMode == display_mode::in_3D && !_stampTool->getBrushMode()) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eNO_FLAG, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeStampRotation(); }); + action->setBlockCursor(true); + + _stampTool->execute(mv->cursorPosition() + , mv->getWorld() + , params.relative_movement.dx() / 30.0f + , params.mod_shift_down + , params.mod_alt_down + , params.mod_ctrl_down + , false); + } + } + } + } + + void StampTool::randomizeStampRotation() + { + if (!_stampTool->getRandomizeRotation()) + return; + + unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); + std::mt19937 gen(ms); + std::uniform_int_distribution<> uid(0, 360); + + _stampTool->changeRotation(uid(gen)); + } +} \ No newline at end of file diff --git a/src/noggit/tools/StampTool.hpp b/src/noggit/tools/StampTool.hpp new file mode 100644 index 00000000..6c9d7735 --- /dev/null +++ b/src/noggit/tools/StampTool.hpp @@ -0,0 +1,44 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui::Tools + { + class BrushStack; + } + + class StampTool final : public Tool + { + public: + StampTool(MapView* mapView); + ~StampTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + private: + Ui::Tools::BrushStack* _stampTool = nullptr; + void randomizeStampRotation(); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/TexturingTool.cpp b/src/noggit/tools/TexturingTool.cpp new file mode 100644 index 00000000..60ef973f --- /dev/null +++ b/src/noggit/tools/TexturingTool.cpp @@ -0,0 +1,584 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "FlattenBlurTool.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TexturingTool.hpp" +#include + +#include +#include + +#include + +namespace Noggit +{ + TexturingTool::TexturingTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("toggleTool"_hash, Hotkey{ + .onPress = [=] { _texturingTool->toggle_tool(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevelMinMax"_hash, Hotkey{ + .onPress = [=] { _texturingTool->toggle_brush_level_min_max(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("increaseRadius"_hash, Hotkey{ + .onPress = [=] { _texturingTool->change_radius(0.1f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("decreaseRadius"_hash, Hotkey{ + .onPress = [=] { _texturingTool->change_radius(-0.1f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevel0Pct"_hash, Hotkey{ + .onPress = [=] { _texturingTool->set_brush_level(0.0f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevel25Pct"_hash, Hotkey{ + .onPress = [=] { _texturingTool->set_brush_level(255.0f * 0.25f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevel50Pct"_hash, Hotkey{ + .onPress = [=] { _texturingTool->set_brush_level(255.0f * 0.5f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevel75Pct"_hash, Hotkey{ + .onPress = [=] { _texturingTool->set_brush_level(255.0f * 0.75f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("setBrushLevel100Pct"_hash, Hotkey{ + .onPress = [=] { _texturingTool->set_brush_level(255.0f); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("toggleTexturePalette"_hash, Hotkey{ + .onPress = [=] { _show_texture_palette_small_window.toggle(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::paint && !NOGGIT_CUR_ACTION; }, + }); + + QObject::connect(mapView + , &MapView::selectionUpdated + , [=](std::vector& selection) + { + if (_texturePickerNeedUpdate) + { + _texturePickerDock->setVisible(true); + _texturePicker->setMainTexture(_texturingTool->_current_texture); + _texturePicker->getTextures(*selection.begin()); + + _texturePickerNeedUpdate = false; + } + } + ); + } + + TexturingTool::~TexturingTool() + { + delete _texturePickerDock; + delete _texturePaletteDock; + delete _textureBrowserDock; + delete _texturingTool; + } + + char const* TexturingTool::name() const + { + return "Texture Painter"; + } + + editing_mode TexturingTool::editingMode() const + { + return editing_mode::paint; + } + + Ui::FontNoggit::Icons TexturingTool::icon() const + { + return Ui::FontNoggit::TOOL_TEXTURE_PAINT; + } + + void TexturingTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + auto mv = mapView(); + /* Tool */ + _texturingTool = new Ui::texturing_tool(&mv->getCamera()->position, mv, &_show_texture_palette_small_window, mv); + toolPanel->registerTool(name(), _texturingTool); + + // Connects + QObject::connect(_texturingTool->texture_swap_tool()->texture_display() + , &Noggit::Ui::current_texture::texture_dropped + , [=](std::string const& filename) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + + _texturingTool->texture_swap_tool()->set_texture(filename); + } + ); + + QObject::connect(_texturingTool->_current_texture + , &Noggit::Ui::current_texture::texture_dropped + , [=](std::string const& filename) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + + Noggit::Ui::selected_texture::set({ filename, mv->getRenderContext() }); + } + ); + + QObject::connect(_texturingTool->_current_texture, &Noggit::Ui::current_texture::clicked + , [=] + { + _textureBrowserDock->setVisible(!_textureBrowserDock->isVisible()); + } + ); + + QObject::connect(_texturingTool, &Ui::texturing_tool::texturePaletteToggled, + [=]() + { + _show_texture_palette_small_window.set(!_show_texture_palette_small_window.get()); + }); + + /* Additional tools */ + + /* Texture Browser */ + + // Dock + _textureBrowserDock = new QDockWidget("Texture Browser", mv); + _textureBrowserDock->setFeatures(QDockWidget::DockWidgetMovable + | QDockWidget::DockWidgetFloatable + | QDockWidget::DockWidgetClosable); + _textureBrowserDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea); + mv->mainWindow()->addDockWidget(Qt::BottomDockWidgetArea, _textureBrowserDock); + _textureBrowserDock->hide(); + + QObject::connect(_textureBrowserDock, &QDockWidget::visibilityChanged, + [=](bool visible) + { + if (mv->isUiHidden()) + return; + + mv->settings()->setValue("map_view/texture_browser", visible); + mv->settings()->sync(); + }); + + QObject::connect(mv, &QObject::destroyed, _textureBrowserDock, &QObject::deleteLater); + // End Dock + + _texturePalette = new Noggit::Ui::tileset_chooser(mv); + _textureBrowserDock->setWidget(_texturePalette); + QObject::connect(mv, &QObject::destroyed, _texturePalette, &QObject::deleteLater); + + QObject::connect(_texturePalette, &Noggit::Ui::tileset_chooser::selected + , [=](std::string const& filename) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + + Noggit::Ui::selected_texture::set({ filename, mv->getRenderContext() }); + _texturingTool->_current_texture->set_texture(filename); + _texturePicker->setMainTexture(_texturingTool->_current_texture); + _texturePicker->updateSelection(); + } + ); + + QObject::connect(_texturePalette, &Noggit::Ui::widget::visibilityChanged + , &_show_texture_palette_window, &Noggit::BoolToggleProperty::set + ); + + QObject::connect(&_show_texture_palette_window, &Noggit::BoolToggleProperty::changed + , [this, mv] + { + if ((mv->get_editing_mode() == editing_mode::paint || mv->get_editing_mode() == editing_mode::stamp) + && !mv->isUiHidden()) + { + _textureBrowserDock->setVisible(_show_texture_palette_window.get()); + } + else + { + QSignalBlocker const _(_show_texture_palette_window); + _show_texture_palette_window.set(false); + } + } + ); + + /* Texture Palette Small */ + _texturePaletteSmall = new Noggit::Ui::texture_palette_small(mv->project(), mv->getWorld()->getMapID(), mv); + + // Dock + _texturePaletteDock = new QDockWidget("Texture Palette", mv); + _texturePaletteDock->setFeatures(QDockWidget::DockWidgetMovable + | QDockWidget::DockWidgetFloatable + | QDockWidget::DockWidgetClosable + ); + + _texturePaletteDock->setWidget(_texturePaletteSmall); + _texturePaletteDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); + _texturePaletteDock->hide(); + + QObject::connect(mv, &QObject::destroyed, _texturePaletteDock, &QObject::deleteLater); + + mv->mainWindow()->addDockWidget(Qt::BottomDockWidgetArea, _texturePaletteDock); + // End Dock + + QObject::connect(_texturePaletteDock, &QDockWidget::visibilityChanged, + [=](bool visible) + { + if (mv->isUiHidden()) + return; + + mv->settings()->setValue("map_view/texture_palette", visible); + mv->settings()->sync(); + }); + + QObject::connect(_texturePaletteSmall, &Noggit::Ui::texture_palette_small::selected + , [=](std::string const& filename) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + + Noggit::Ui::selected_texture::set({ filename, mv->getRenderContext() }); + _texturingTool->_current_texture->set_texture(filename); + } + ); + QObject::connect(mv, &QObject::destroyed, _texturePaletteSmall, &QObject::deleteLater); + + QObject::connect(&_show_texture_palette_small_window, &Noggit::BoolToggleProperty::changed + , _texturePaletteDock, [=] + { + QSignalBlocker const blocker(_show_texture_palette_small_window); + if (mv->get_editing_mode() == editing_mode::paint && !mv->isUiHidden()) + { + _texturePaletteDock->setVisible(_show_texture_palette_small_window.get()); + } + else + { + _show_texture_palette_small_window.set(false); + } + } + ); + QObject::connect(_texturePaletteDock, &QDockWidget::visibilityChanged + , &_show_texture_palette_small_window, &Noggit::BoolToggleProperty::set + ); + + QObject::connect(_texturingTool->_current_texture, &Noggit::Ui::current_texture::texture_updated + , [=]() + { + mv->getWorld()->notifyTileRendererOnSelectedTextureChange(); + _texturingTool->getGroundEffectsTool()->TextureChanged(); + } + ); + + /* Texture Picker */ + + // Dock + _texturePickerDock = new QDockWidget("Texture picker", mv); + _texturePickerDock->setFeatures(QDockWidget::DockWidgetMovable + | QDockWidget::DockWidgetFloatable + | QDockWidget::DockWidgetClosable); + mv->mainWindow()->addDockWidget(Qt::BottomDockWidgetArea, _texturePickerDock); + _texturePickerDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); + _texturePickerDock->setFloating(true); + _texturePickerDock->hide(); + QObject::connect(mv, &QObject::destroyed, _texturePickerDock, &QObject::deleteLater); + // End Dock + + _texturePicker = new Noggit::Ui::texture_picker(_texturingTool->_current_texture, mv); + _texturePickerDock->setWidget(_texturePicker); + QObject::connect(mv, &QObject::destroyed, _texturePicker, &QObject::deleteLater); + + QObject::connect(_texturePicker + , &Noggit::Ui::texture_picker::set_texture + , [=](scoped_blp_texture_reference texture) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + Noggit::Ui::selected_texture::set(std::move(texture)); + } + ); + QObject::connect(_texturePicker, &Noggit::Ui::texture_picker::shift_left + , [=] + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + _texturePicker->shiftSelectedTextureLeft(); + } + ); + QObject::connect(_texturePicker, &Noggit::Ui::texture_picker::shift_right + , [=] + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + _texturePicker->shiftSelectedTextureRight(); + } + ); + } + + void TexturingTool::registerMenuItems(QMenu* menu) + { + addMenuTitle(menu, "Texture Painter"); + addMenuItem(menu, "Texture Browser", Qt::Key_X, _show_texture_palette_window); + addMenuItem(menu, "Texture palette", _show_texture_palette_small_window); + } + + ToolDrawParameters TexturingTool::drawParameters() const + { + auto cursorType = CursorType::CIRCLE; + if (_texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint && _texturingTool->getImageMaskSelector()->isEnabled()) + cursorType = CursorType::STAMP; + + return + { + .radius = _texturingTool->brush_radius(), + .inner_radius = _texturingTool->hardness(), + .show_unpaintable_chunks = _texturingTool->show_unpaintable_chunks(), + .cursor_type = cursorType, + }; + } + + void TexturingTool::onSelected() + { + auto mv = mapView(); + if (_texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint && _texturingTool->getImageMaskSelector()->isEnabled()) + { + _texturingTool->updateMaskImage(); + } + else if (_texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect) + { + _texturingTool->getGroundEffectsTool()->updateTerrainUniformParams(); + } + + bool use_classic_ui = mv->settings()->value("classicUI", false).toBool(); + if (use_classic_ui) + { + if (_texturingTool->show_unpaintable_chunks()) + { + mv->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = true; + } + } + else + { + if (mv->getLeftSecondaryViewToolbar()->showUnpaintableChunk()) + { + mv->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = true; + } + } + + _textureBrowserDock->setVisible(!mv->isUiHidden() && mv->settings()->value("map_view/texture_browser", false).toBool()); + _texturePaletteDock->setVisible(!mv->isUiHidden() && mv->settings()->value("map_view/texture_palette", false).toBool()); + } + + void TexturingTool::onDeselected() + { + _texturingTool->getGroundEffectsTool()->hide(); + _textureBrowserDock->setVisible(false); + _texturePaletteDock->setVisible(false); + } + + void TexturingTool::onTick(float deltaTime, TickParameters const& params) + { + if (!params.left_mouse) + { + return; + } + + auto mv = mapView(); + + if (_texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect) + { + if (params.mod_shift_down) + { + if (_texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::exclusion) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + mv->getWorld()->paintGroundEffectExclusion(mv->cursorPosition(), _texturingTool->getGroundEffectsTool()->radius(), true); + // mv->getWorld()->setHole(mv->cursorPosition(), holeTool->brushRadius(), _mod_alt_down, false); + } + else if (_texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::effect) + { + + } + + } + else if (params.mod_ctrl_down && !params.underMap) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + mv->getWorld()->paintGroundEffectExclusion(mv->cursorPosition(), _texturingTool->getGroundEffectsTool()->radius(), false); + } + } + else + { + if (params.mod_shift_down && params.mod_ctrl_down && params.mod_alt_down) + { + // clear chunk texture + if (!params.underMap) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_TEXTURE, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eALT + | Noggit::ActionModalityControllers::eLMB); + + mv->getWorld()->eraseTextures(mv->cursorPosition()); + } + } + else if (params.mod_ctrl_down && !mv->isUiHidden()) + { + _texturePickerNeedUpdate = true; + // Pick texture + // _texturePickerDock->setVisible(true); + // _texturePicker->setMainTexture(_texturingTool->_current_texture); + // _texturePicker->getTextures(selection); + } + else if (params.mod_shift_down && !!Noggit::Ui::selected_texture::get()) + { + if ((params.displayMode == display_mode::in_3D && !params.underMap) || params.displayMode == display_mode::in_2D) + { + auto image_mask_selector = _texturingTool->getImageMaskSelector(); + + if (NOGGIT_CUR_ACTION + && _texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint + && image_mask_selector->isEnabled() + && !image_mask_selector->getBrushMode()) + { + return; + } + + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_TEXTURE, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeTexturingRotation(); }); + + if (_texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint + && image_mask_selector->isEnabled() + && !image_mask_selector->getBrushMode()) + action->setBlockCursor(true); + + _texturingTool->paint(mv->getWorld(), mv->cursorPosition(), deltaTime, *Noggit::Ui::selected_texture::get()); + } + } + } + } + + void TexturingTool::onMousePress(MousePressParameters const& params) + { + if (params.button != Qt::MouseButton::LeftButton || !params.mod_ctrl_down) + { + return; + } + + mapView()->doSelection(false, false); + } + + void TexturingTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.right_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _texturingTool->change_hardness(params.relative_movement.dx() / 300.0f); + } + + if (params.mod_space_down) + { + if (_texturingTool->getImageMaskSelector()->isEnabled()) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, + Noggit::ActionModalityControllers::eRMB + | Noggit::ActionModalityControllers::eSPACE); + _texturingTool->getImageMaskSelector()->setRotation(-params.relative_movement.dx() / XSENS * 10.f); + action->setBlockCursor(true); + } + } + } + + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _texturingTool->change_radius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_space_down) + { + _texturingTool->change_pressure(params.relative_movement.dx() / 300.0f); + } + } + } + + void TexturingTool::onMouseWheel(MouseWheelParameters const& params) + { + auto&& delta_for_range + ([&](float range) + { + //! \note / 8.f for degrees, / 40.f for smoothness + return (params.mod_ctrl_down ? 0.01f : 0.1f) + * range + // alt = horizontal delta + * (params.mod_alt_down ? params.event.angleDelta().x() : params.event.angleDelta().y()) + / 320.f + ; + } + ); + + if (params.mod_space_down) + { + _texturingTool->change_brush_level(delta_for_range(255.f)); + } + else if (params.mod_alt_down) + { + _texturingTool->change_spray_size(delta_for_range(39.f)); + } + else if (params.mod_shift_down) + { + _texturingTool->change_spray_pressure(delta_for_range(10.f)); + } + } + + void TexturingTool::hidePopups() + { + _texturePaletteSmall->hide(); + _texturePickerDock->hide(); + _textureBrowserDock->hide(); + } + + void TexturingTool::randomizeTexturingRotation() + { + auto image_mask_selector = _texturingTool->getImageMaskSelector(); + if (!image_mask_selector->getRandomizeRotation()) + return; + + unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); + std::mt19937 gen(ms); + std::uniform_int_distribution<> uid(0, 360); + + image_mask_selector->setRotation(uid(gen)); + } +} \ No newline at end of file diff --git a/src/noggit/tools/TexturingTool.hpp b/src/noggit/tools/TexturingTool.hpp new file mode 100644 index 00000000..2d2eaf75 --- /dev/null +++ b/src/noggit/tools/TexturingTool.hpp @@ -0,0 +1,70 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include +#include + +class QDockWidget; + +namespace Noggit +{ + namespace Ui + { + class texturing_tool; + struct tileset_chooser; + class texture_picker; + class texture_palette_small; + } + + class TexturingTool final : public Tool + { + public: + TexturingTool(MapView* mapView); + ~TexturingTool(); + + [[nodiscard]] + char const* name() const override; + + [[nodiscard]] + editing_mode editingMode() const override; + + [[nodiscard]] + Ui::FontNoggit::Icons icon() const override; + + void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + void registerMenuItems(QMenu* menu) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onDeselected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMousePress(MousePressParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + void onMouseWheel(MouseWheelParameters const& params) override; + + void hidePopups() override; + + private: + Ui::texturing_tool* _texturingTool = nullptr; + QDockWidget* _textureBrowserDock = nullptr; + Ui::tileset_chooser* _texturePalette = nullptr; + Ui::texture_picker* _texturePicker = nullptr; + Ui::texture_palette_small* _texturePaletteSmall = nullptr; + QDockWidget* _texturePaletteDock = nullptr; + QDockWidget* _texturePickerDock = nullptr; + bool _texturePickerNeedUpdate = false; + Noggit::BoolToggleProperty _show_texture_palette_window = { false }; + Noggit::BoolToggleProperty _show_texture_palette_small_window = { false }; + + void randomizeTexturingRotation(); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/VertexPainterTool.cpp b/src/noggit/tools/VertexPainterTool.cpp new file mode 100644 index 00000000..246e0dc6 --- /dev/null +++ b/src/noggit/tools/VertexPainterTool.cpp @@ -0,0 +1,162 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "VertexPainterTool.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace Noggit +{ + VertexPainterTool::VertexPainterTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("addColor"_hash, Hotkey{ + .onPress = [=] { _shaderTool->addColorToPalette(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::mccv && !NOGGIT_CUR_ACTION; }, + }); + } + + VertexPainterTool::~VertexPainterTool() + { + delete _shaderTool; + } + + char const* VertexPainterTool::name() const + { + return "Vertex Painter"; + } + + editing_mode VertexPainterTool::editingMode() const + { + return editing_mode::mccv; + } + + Ui::FontNoggit::Icons VertexPainterTool::icon() const + { + return Ui::FontNoggit::TOOL_VERTEX_PAINT; + } + + void VertexPainterTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _shaderTool = new Noggit::Ui::ShaderTool(mapView(), mapView()); + toolPanel->registerTool(name(), _shaderTool); + } + + ToolDrawParameters VertexPainterTool::drawParameters() const + { + return + { + .radius = _shaderTool->brushRadius(), + .cursor_type = (_shaderTool->getImageMaskSelector()->isEnabled()) ? CursorType::STAMP : CursorType::CIRCLE, + .cursor_color = _shaderTool->shaderColor(), + }; + } + + void VertexPainterTool::onSelected() + { + if (_shaderTool->getImageMaskSelector()->isEnabled()) + { + _shaderTool->updateMaskImage(); + } + } + + void VertexPainterTool::randomizeShaderRotation() + { + auto image_mask_selector = _shaderTool->getImageMaskSelector(); + if (!image_mask_selector->getRandomizeRotation()) + return; + + unsigned int ms = static_cast(QDateTime::currentMSecsSinceEpoch()); + std::mt19937 gen(ms); + std::uniform_int_distribution<> uid(0, 360); + + image_mask_selector->setRotation(uid(gen)); + } + + void VertexPainterTool::onTick(float deltaTime, TickParameters const& params) + { + if (params.underMap || !params.left_mouse) + { + return; + } + + for (auto& selection : mapView()->getWorld()->current_selection()) + { + if (selection.index() != eEntry_MapChunk) + { + continue; + } + + if ((params.mod_shift_down ^ params.mod_ctrl_down) == 0) + { + continue; + } + + auto mv = mapView(); + bool add = params.mod_shift_down && !params.mod_ctrl_down; + auto flags = add ? Noggit::ActionModalityControllers::eSHIFT : Noggit::ActionModalityControllers::eCTRL; + + auto image_mask_selector = _shaderTool->getImageMaskSelector(); + + if (NOGGIT_CUR_ACTION + && image_mask_selector->isEnabled() + && !image_mask_selector->getBrushMode()) + { + break; + } + + auto action = NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_VERTEX_COLOR, + flags | Noggit::ActionModalityControllers::eLMB); + + action->setPostCallback([this] { randomizeShaderRotation(); }); + + if (image_mask_selector->isEnabled() && !image_mask_selector->getBrushMode()) + action->setBlockCursor(true); + + _shaderTool->changeShader(mv->getWorld(), mv->cursorPosition(), deltaTime, add); + } + } + + void VertexPainterTool::onMousePress(MousePressParameters const& params) + { + if (params.button != Qt::MouseButton::MiddleButton) + { + return; + } + + _shaderTool->pickColor(mapView()->getWorld(), mapView()->cursorPosition()); + } + + void VertexPainterTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.right_mouse) + { + if (params.mod_space_down && _shaderTool->getImageMaskSelector()->isEnabled()) + { + auto action = NOGGIT_ACTION_MGR->beginAction(mapView(), Noggit::ActionFlags::eDO_NOT_WRITE_HISTORY, + Noggit::ActionModalityControllers::eRMB + | Noggit::ActionModalityControllers::eSPACE); + _shaderTool->getImageMaskSelector()->setRotation(-params.relative_movement.dx() / XSENS * 10.f); + action->setBlockCursor(true); + } + } + + if (params.left_mouse) + { + if (params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _shaderTool->changeRadius(params.relative_movement.dx() / XSENS); + } + + if (params.mod_space_down) + { + _shaderTool->changeSpeed(params.relative_movement.dx() / XSENS); + } + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/VertexPainterTool.hpp b/src/noggit/tools/VertexPainterTool.hpp new file mode 100644 index 00000000..645f39e4 --- /dev/null +++ b/src/noggit/tools/VertexPainterTool.hpp @@ -0,0 +1,47 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +namespace Noggit +{ + namespace Ui + { + class ShaderTool; + } + + class VertexPainterTool final : public Tool + { + public: + VertexPainterTool(MapView* mapView); + ~VertexPainterTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + virtual void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onSelected() override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMousePress(MousePressParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + private: + Noggit::Ui::ShaderTool* _shaderTool = nullptr; + + void randomizeShaderRotation(); + }; +} \ No newline at end of file diff --git a/src/noggit/tools/WaterTool.cpp b/src/noggit/tools/WaterTool.cpp new file mode 100644 index 00000000..aedf2507 --- /dev/null +++ b/src/noggit/tools/WaterTool.cpp @@ -0,0 +1,165 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "WaterTool.hpp" + +#include +#include +#include +#include +#include + +namespace Noggit +{ + WaterTool::WaterTool(MapView* mapView) + : Tool{ mapView } + { + addHotkey("toggleAngled"_hash, Hotkey{ + .onPress = [=] { _guiWater->toggle_angled_mode(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::water && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("toggleLock"_hash, Hotkey{ + .onPress = [=] { _guiWater->toggle_lock(); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::water && !NOGGIT_CUR_ACTION; }, + }); + + addHotkey("lockCursor"_hash, Hotkey{ + .onPress = [=] { _guiWater->lockPos(mapView->cursorPosition()); }, + .condition = [=] { return mapView->get_editing_mode() == editing_mode::water && !NOGGIT_CUR_ACTION; }, + }); + } + + WaterTool::~WaterTool() + { + delete _guiWater; + } + + char const* WaterTool::name() const + { + return "Water Editor"; + } + + editing_mode WaterTool::editingMode() const + { + return editing_mode::water; + } + + Ui::FontNoggit::Icons WaterTool::icon() const + { + return Ui::FontNoggit::TOOL_WATER_EDITOR; + } + + void WaterTool::setupUi(Ui::Tools::ToolPanel* toolPanel) + { + _guiWater = new Noggit::Ui::water(&_displayedWaterLayer, &_displayAllWaterLayers, mapView()); + toolPanel->registerTool(name(), _guiWater); + + auto mv = mapView(); + + QObject::connect(_guiWater, &Noggit::Ui::water::regenerate_water_opacity + , [=](float factor) + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_WATER); + mv->getWorld()->autoGenWaterTrans(mv->getCamera()->position, factor); + NOGGIT_ACTION_MGR->endAction(); + } + ); + + QObject::connect(_guiWater, &Noggit::Ui::water::crop_water + , [=] + { + mv->makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, mv->context()); + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_WATER); + mv->getWorld()->CropWaterADT(mv->getCamera()->position); + NOGGIT_ACTION_MGR->endAction(); + } + ); + } + + ToolDrawParameters WaterTool::drawParameters() const + { + return + { + .radius = _guiWater->brushRadius(), + .angle = _guiWater->angle(), + .orientation = _guiWater->orientation(), + .ref_pos = _guiWater->ref_pos(), + .angled_mode = _guiWater->angled_mode(), + .use_ref_pos = _guiWater->use_ref_pos(), + .displayed_water_layer = _displayAllWaterLayers.get() ? -1 : static_cast(_displayedWaterLayer.get()), + }; + } + + void WaterTool::onTick(float deltaTime, TickParameters const& params) + { + if (params.underMap || !params.left_mouse) + { + return; + } + + auto mv = mapView(); + if (params.displayMode == display_mode::in_3D && !params.underMap) + { + if (params.mod_shift_down) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_WATER, + Noggit::ActionModalityControllers::eSHIFT + | Noggit::ActionModalityControllers::eLMB); + _guiWater->paintLiquid(mv->getWorld(), mv->cursorPosition(), true); + } + else if (params.mod_ctrl_down) + { + NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eCHUNKS_WATER, + Noggit::ActionModalityControllers::eCTRL + | Noggit::ActionModalityControllers::eLMB); + _guiWater->paintLiquid(mv->getWorld(), mv->cursorPosition(), false); + } + } + + // HINT: this was originally at the very end of MapView::Tick. Do we need a new postTick method? + // While testing I can't find any issues with the tools. + // Using the camera's position from last frame doesn't seem to matter but it's technically incorrect for one frame! + _guiWater->updatePos(mv->getCamera()->position); + } + + void WaterTool::onMouseMove(MouseMoveParameters const& params) + { + if (params.left_mouse && params.mod_alt_down && !params.mod_shift_down && !params.mod_ctrl_down) + { + _guiWater->changeRadius(params.relative_movement.dx() / XSENS); + } + } + + void WaterTool::onMouseWheel(MouseWheelParameters const& params) + { + auto&& delta_for_range + ([&](float range) + { + //! \note / 8.f for degrees, / 40.f for smoothness + return (params.mod_ctrl_down ? 0.01f : 0.1f) + * range + // alt = horizontal delta + * (params.mod_alt_down ? params.event.angleDelta().x() : params.event.angleDelta().y()) + / 320.f + ; + } + ); + + if (params.mod_alt_down) + { + _guiWater->changeOrientation(delta_for_range(360.f)); + } + else if (params.mod_shift_down) + { + _guiWater->changeAngle(delta_for_range(89.f)); + } + else if (params.mod_space_down) + { + //! \note not actual range + _guiWater->change_height(delta_for_range(40.f)); + } + } +} \ No newline at end of file diff --git a/src/noggit/tools/WaterTool.hpp b/src/noggit/tools/WaterTool.hpp new file mode 100644 index 00000000..418cab4b --- /dev/null +++ b/src/noggit/tools/WaterTool.hpp @@ -0,0 +1,47 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include +#include +#include + +namespace Noggit +{ + namespace Ui + { + class water; + } + + class WaterTool final : public Tool + { + public: + WaterTool(MapView* mapView); + ~WaterTool(); + + [[nodiscard]] + virtual char const* name() const override; + + [[nodiscard]] + virtual editing_mode editingMode() const override; + + [[nodiscard]] + virtual Ui::FontNoggit::Icons icon() const override; + + virtual void setupUi(Ui::Tools::ToolPanel* toolPanel) override; + + [[nodiscard]] + ToolDrawParameters drawParameters() const override; + + void onTick(float deltaTime, TickParameters const& params) override; + + void onMouseMove(MouseMoveParameters const& params) override; + + void onMouseWheel(MouseWheelParameters const& params) override; + + private: + Noggit::Ui::water* _guiWater = nullptr; + Noggit::unsigned_int_property _displayedWaterLayer = { 0 }; + Noggit::BoolToggleProperty _displayAllWaterLayers = { true }; + }; +} \ No newline at end of file diff --git a/src/noggit/ui/FontAwesome.hpp b/src/noggit/ui/FontAwesome.hpp index b1d4af69..27b7890c 100755 --- a/src/noggit/ui/FontAwesome.hpp +++ b/src/noggit/ui/FontAwesome.hpp @@ -2,6 +2,7 @@ #pragma once +#include #include #include diff --git a/src/noggit/ui/GroundEffectsTool.cpp b/src/noggit/ui/GroundEffectsTool.cpp index 12d85710..0a4f4414 100644 --- a/src/noggit/ui/GroundEffectsTool.cpp +++ b/src/noggit/ui/GroundEffectsTool.cpp @@ -383,6 +383,10 @@ namespace Noggit } ); + using AssetBrowser = Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget; + connect(map_view->getAssetBrowserWidget(), &AssetBrowser::selectionChanged, this, [=](std::string const& path) { + if (isVisible()) setDoodadSlotFromBrowser(path.c_str()); + }); } void GroundEffectsTool::updateTerrainUniformParams() diff --git a/src/noggit/ui/GroundEffectsTool.hpp b/src/noggit/ui/GroundEffectsTool.hpp index 796f8a7c..45add575 100644 --- a/src/noggit/ui/GroundEffectsTool.hpp +++ b/src/noggit/ui/GroundEffectsTool.hpp @@ -14,7 +14,6 @@ #include class World; -class texturing_tool; class MapView; class DBCFile::Record; @@ -22,6 +21,8 @@ namespace Noggit { namespace Ui { + class texturing_tool; + struct ground_effect_doodad { unsigned int ID = 0; diff --git a/src/noggit/ui/Help.cpp b/src/noggit/ui/Help.cpp index 65def43b..b0622539 100755 --- a/src/noggit/ui/Help.cpp +++ b/src/noggit/ui/Help.cpp @@ -1,354 +1,354 @@ -// This file is part of Noggit3, licensed under GNU General Public License (version 3). - -#include -#include - -#include -#include -#include -#include -#include - -#include - -namespace Noggit -{ - namespace Ui - { - - help::help(QWidget* parent) - : widget (parent, Qt::Window) - { - setWindowTitle ("Help"); - setWindowIcon (QIcon (":/icon")); - setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); - - QString header_style = - "QLabel { \n " - " font-weight: bold; \n " - " margin-top: 8px; \n " - " margin-bottom: 4px; \n " - " margin-left: 150px; \n " - "} \n "; - - - auto layout (new QFormLayout (this)); - layout->setSizeConstraint(QLayout::SetFixedSize); - - auto tabs (new QTabWidget (this)); - - auto base_widget (new QWidget (this)); - auto base_layout(new QGridLayout (base_widget)); - - - auto basic_controls_layout (new QFormLayout (this)); - base_layout->addLayout(basic_controls_layout, 0, 0); - - base_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - auto label = new QLabel("Basic controls:"); - label->setStyleSheet(header_style); - basic_controls_layout->addRow(label); - - generate_hotkey_row({FontNoggit::rmb_drag}, "\aRotate camera", basic_controls_layout); - generate_hotkey_row({FontNoggit::lmb}, "\aSelect chunk or object", basic_controls_layout); - generate_hotkey_row({FontNoggit::i}, "\aInvert mouse up and down", basic_controls_layout); - generate_hotkey_row({FontNoggit::q, FontNoggit::e}, "\a,\aMove up and down", basic_controls_layout); - generate_hotkey_row({FontNoggit::w, FontNoggit::a , FontNoggit::s , FontNoggit::d}, "\a\a\a\aMove left, right, forward, backwards", basic_controls_layout); - generate_hotkey_row({FontNoggit::home}, "\aMove position to the cursor", basic_controls_layout); - generate_hotkey_row({FontNoggit::m}, "\aShow map", basic_controls_layout); - generate_hotkey_row({FontNoggit::u}, "\a2D texture editor", basic_controls_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::f1}, "\a+\aThis help", basic_controls_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::j}, "\a+\aReload an adt under the camera", basic_controls_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::r}, "\a+\aTurn camera 180 degrees", basic_controls_layout); - generate_hotkey_row({FontNoggit::shift}, "\a+ 1, 2, 3 or 4 Set a predefined camera speed", basic_controls_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::f4}, "\a+\aExit to main menu", basic_controls_layout); - generate_hotkey_row({FontNoggit::l}, "\aToggle top view (hint: it's faster to use with graphic tablet stylus buttons)", basic_controls_layout); - generate_hotkey_row({}, "", basic_controls_layout); // padding - - auto toggles_layout(new QFormLayout(this)); - base_layout->addLayout(toggles_layout, 0, 1); - - auto label_toggle = new QLabel("Toggles:"); - label_toggle->setStyleSheet(header_style); - toggles_layout->addRow(label_toggle); - - generate_hotkey_row({FontNoggit::f1}, "\aToggle M2s", toggles_layout); - generate_hotkey_row({FontNoggit::f2}, "\aToggle WMO doodads set", toggles_layout); - generate_hotkey_row({FontNoggit::f3}, "\aToggle ground", toggles_layout); - generate_hotkey_row({FontNoggit::f4}, "\aToggle water", toggles_layout); - generate_hotkey_row({FontNoggit::f6}, "\aToggle WMOs", toggles_layout); - generate_hotkey_row({FontNoggit::f7}, "\aToggle chunk (red) and ADT (green) lines", toggles_layout); - generate_hotkey_row({FontNoggit::f8}, "\aToggle detailed window", toggles_layout); - generate_hotkey_row({FontNoggit::f9}, "\aToggle map contour", toggles_layout); - generate_hotkey_row({FontNoggit::f10}, "\aToggle wireframe", toggles_layout); - generate_hotkey_row({FontNoggit::f11}, "\aToggle model animations", toggles_layout); - generate_hotkey_row({FontNoggit::f12}, "\aToggle fog", toggles_layout); - generate_hotkey_row({}, "1 - 9 Select the editing modes", toggles_layout); - - auto files_layout(new QFormLayout(this)); - base_layout->addLayout(files_layout, 1, 0); - - auto label_files = new QLabel("Files:"); - label_files->setStyleSheet(header_style); - files_layout->addRow(label_files); - - generate_hotkey_row({FontNoggit::f5}, "\aSave bookmark", files_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::s}, "\a+\a Save all changed ADT tiles", files_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::s}, "\a+\a+\aSave ADT tile at camera position", files_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::a}, "\a+\a+\aSave all loaded ADT tiles", files_layout); - generate_hotkey_row({FontNoggit::g}, "\aSave port commands to ports.txt", files_layout); - - auto adjust_layout(new QFormLayout(this)); - base_layout->addLayout(adjust_layout, 1, 1); - - auto label_adjust = new QLabel("Adjust:"); - label_adjust->setStyleSheet(header_style); - adjust_layout->addRow(label_adjust); - - generate_hotkey_row({FontNoggit::o, FontNoggit::p}, "\aor\aSlower / Faster movement", adjust_layout); - generate_hotkey_row({FontNoggit::b, FontNoggit::n}, "\aor\aSlower / Faster time", adjust_layout); - generate_hotkey_row({FontNoggit::j}, "\aPause time", adjust_layout); - // NYI - // generate_hotkey_row({FontNoggit::shift, FontNoggit::plus, FontNoggit::minus}, "\a+\aor\aFog distance when no model is selected", adjust_layout); - - auto flag_widget (new QWidget (this)); - auto flag_layout (new QFormLayout (flag_widget)); - - auto holes_label = new QLabel("Holes:"); - holes_label->setStyleSheet(header_style); - flag_layout->addRow(holes_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb}, "\a+\aClear hole", flag_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb}, "\a+\aAdd hole", flag_layout); - generate_hotkey_row({FontNoggit::t}, "\aRemove all holes on ADT", flag_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::t}, "\a+\aRemove all ground on ADT", flag_layout); - - auto impass_flags_label = new QLabel("Impassible Flags:"); - impass_flags_label->setStyleSheet(header_style); - flag_layout->addRow(impass_flags_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aPaint flag", flag_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aClear flag", flag_layout); - - auto areaid_label = new QLabel("AreaID Flags:"); - areaid_label->setStyleSheet(header_style); - flag_layout->addRow(areaid_label); - - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aPick existing AreaID", flag_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aPaint selected AreaID", flag_layout); - generate_hotkey_row({ FontNoggit::f }, "\a - Fill current ADT with selected AreaID", flag_layout); - - - auto ground_widget (new QWidget (this)); - auto ground_layout (new QGridLayout (ground_widget)); - - auto ground_column1_layout(new QFormLayout(this)); - ground_layout->addLayout(ground_column1_layout, 0, 0); - - auto ground_label = new QLabel("Edit ground:"); - ground_label->setStyleSheet(header_style); - ground_column1_layout->addRow(ground_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::f1 }, "\a+\aToggle ground edit mode", ground_column1_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", ground_column1_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange speed", ground_column1_layout); - - auto raise_label = new QLabel("Raise / Lower tool:"); - raise_label->setStyleSheet(header_style); - ground_column1_layout->addRow(raise_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aRaise terrain", ground_column1_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aLower terrain", ground_column1_layout); - generate_hotkey_row({FontNoggit::y }, "\aSwitch to next type", ground_column1_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::rmb_drag }, "\a+\aChange inner radius", ground_column1_layout); - - auto raise_label_vm = new QLabel("Raise / Lower tool (vertex mode):"); - raise_label_vm->setStyleSheet(header_style); - ground_column1_layout->addRow(raise_label_vm); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aSelect vertices", ground_column1_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aDeselect vertices", ground_column1_layout); - generate_hotkey_row({FontNoggit::c }, "\aClear selection", ground_column1_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aFlatten vertices", ground_column1_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::rmb_drag }, "\a+\aOrient vertices toward the mouse cursor", ground_column1_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::rmb_drag }, "\a+\aChange vertices height", ground_column1_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", ground_column1_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", ground_column1_layout); - - auto ground_column2_layout(new QFormLayout(this)); - ground_layout->addLayout(ground_column2_layout, 0, 1); - - auto flatten_label = new QLabel("Flatten / Blur tool:"); - flatten_label->setStyleSheet(header_style); - ground_column2_layout->addRow(flatten_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aFlatten terrain", ground_column2_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aBlur terrain", ground_column2_layout); - generate_hotkey_row({FontNoggit::t }, "\aToggle flatten angle", ground_column2_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::t }, "\a+\aToggle flatten type", ground_column2_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", ground_column2_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", ground_column2_layout); - generate_hotkey_row({FontNoggit::y }, "\aSwitch to next type", ground_column2_layout); - generate_hotkey_row({FontNoggit::f }, "\aSet relative point", ground_column2_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aToggle flatten relative mode", ground_column2_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange height", ground_column2_layout); - - - auto texture_widget (new QWidget (this)); - auto texture_layout (new QFormLayout (texture_widget)); - - auto common_controls_label = new QLabel("Common controls:"); - common_controls_label->setStyleSheet(header_style); - texture_layout->addRow(common_controls_label); - - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aOpen texture picker for the chunk", texture_layout); - - auto paint_label = new QLabel("Paint:"); - paint_label->setStyleSheet(header_style); - texture_layout->addRow(paint_label); - - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::alt, FontNoggit::lmb }, "\a+\a+\a+\aErase textures", texture_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aDraw texture or fills if chunk is empty", texture_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange radius", texture_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::rmb_drag }, "\a+\aChange hardness (falloff)", texture_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange pressure (strength)", texture_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange opacity (gradient)", texture_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::r }, "\a+\aToggle min and max oapcity (gradient)", texture_layout); - generate_hotkey_row({FontNoggit::t }, "\aToggle spray brush", texture_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange spray radius", texture_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange spray pressure", texture_layout); - - auto swapper_label = new QLabel("Swap:"); - swapper_label->setStyleSheet(header_style); - texture_layout->addRow(swapper_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aSwap texture", texture_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange radius", texture_layout); - generate_hotkey_row({FontNoggit::t }, "\aToggle brush swapper", texture_layout); - - auto anim_label = new QLabel("Anim:"); - anim_label->setStyleSheet(header_style); - texture_layout->addRow(anim_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aUpdate animation", texture_layout); - generate_hotkey_row({FontNoggit::t }, "\aSwitch between add/remove animation mode", texture_layout); - - - auto water_widget (new QWidget (this)); - auto water_layout (new QFormLayout (water_widget)); - - auto water_label = new QLabel("Water:"); - water_label->setStyleSheet(header_style); - water_layout->addRow(water_label); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aAdd liquid", water_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aRemove liquid", water_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", water_layout); - generate_hotkey_row({FontNoggit::t }, "\aToggle angled mode", water_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", water_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", water_layout); - generate_hotkey_row({FontNoggit::f }, "\aSet lock position to cursor position", water_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aToggle lock mode", water_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange height", water_layout); - - - auto object_widget (new QWidget (this)); - auto object_layout (new QFormLayout (object_widget)); - - auto object_label = new QLabel("Edit objects if a model is selected with left click (in object editor):"); - object_label->setStyleSheet(header_style); - object_layout->addRow(object_label); - - generate_hotkey_row({FontNoggit::mmb }, "\aMove object", object_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aScale M2", object_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::ctrl, FontNoggit::alt, FontNoggit::lmb }, "\aor\aor\a+\aRotate object", object_layout); - generate_hotkey_row({FontNoggit::ctrl }, "\a+ 0 - 9 Change doodadset of selected WMO", object_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::r }, "\a+\aReset rotation", object_layout); - generate_hotkey_row({FontNoggit::h }, "\aToggle selected model/wmo visibility", object_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::h }, "\a+\a - Hide/Show hidden model/wmo", object_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::h }, "\a+\a - Clear hidden model/wmo list", object_layout); - generate_hotkey_row({FontNoggit::page_down }, "\aSet object to ground level", object_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::c }, "\a+\aCopy object to clipboard", object_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::v }, "\a+\aPaste object on mouse position", object_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::b }, "\a+\aDuplicate selected object to mouse position", object_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::v }, "\a+\aImport last M2 from WMV", object_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::v }, "\a+\aImport last WMO from WMV", object_layout); - generate_hotkey_row({FontNoggit::t }, "\aSwitch between paste modes", object_layout); - generate_hotkey_row({FontNoggit::f }, "\aMove selection to cursor position", object_layout); - generate_hotkey_row({FontNoggit::minus, FontNoggit::plus }, "\aor\aScale M2", object_layout); - generate_hotkey_row({FontNoggit::num }, "\a 7 or 9 Rotate object", object_layout); - generate_hotkey_row({FontNoggit::num }, "\a 4 or 8 or 6 or 2 Vertical position", object_layout); - generate_hotkey_row({FontNoggit::num }, "\a 1 or 3 Move up/down", object_layout); - generate_hotkey_row({FontNoggit::shift }, "Holding \a 1 / 3 Double speed", object_layout); - generate_hotkey_row({FontNoggit::ctrl }, "Holding \a 1 / 3 Triple speed", object_layout); - generate_hotkey_row({FontNoggit::shift, FontNoggit::ctrl }, "Holding \a and \a Half speed", object_layout); - - auto shader_widget (new QWidget (this)); - auto shader_layout (new QFormLayout (shader_widget)); - - generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aAdd shader", shader_layout); - generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aRemove shader", shader_layout); - generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", shader_layout); - generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange speed", shader_layout); - generate_hotkey_row({FontNoggit::mmb }, "\aPick shader color from the ground", shader_layout); - generate_hotkey_row({FontNoggit::plus }, "\aAdd current color to palette", shader_layout); - - layout->addWidget(tabs); - tabs->addTab(base_widget, "Basic"); - tabs->addTab(ground_widget, "Terrain Editors"); - tabs->addTab(texture_widget, "Texture Painter"); - tabs->addTab(water_widget, "Water Editor"); - tabs->addTab(object_widget, "Object Editor"); - tabs->addTab(shader_widget, "Vertex Painter"); - tabs->addTab(flag_widget, "Impass Flag / Hole Cutter / Area ID"); - } - - - void help::generate_hotkey_row(std::initializer_list&& hotkeys, const char* description, QFormLayout* layout) - { - auto row_layout = new QHBoxLayout(this); - - const char* from = nullptr; - auto icon = hotkeys.begin(); - - while (*description) - { - if (*description == '\a') - { - if (from) - { - auto label = new QLabel(::std::string(from, description - from).c_str()); - row_layout->addWidget(label); - } - - auto label = new QLabel(this); - QIcon hotkey_icon = FontNoggitIcon(*icon++); - label->setPixmap(hotkey_icon.pixmap(22, 22)); - row_layout->addWidget(label); - - from = ++description; - } - else - { - if (!from) - { - from = description; - } - ++description; - } - } - - if (from && *from) - { - auto label = new QLabel(from); - row_layout->addWidget(label); - } - - row_layout->setAlignment(Qt::AlignLeft); - layout->addRow(row_layout); - - } - - } -} +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace Noggit +{ + namespace Ui + { + + help::help(QWidget* parent) + : widget (parent, Qt::Window) + { + setWindowTitle ("Help"); + setWindowIcon (QIcon (":/icon")); + setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); + + QString header_style = + "QLabel { \n " + " font-weight: bold; \n " + " margin-top: 8px; \n " + " margin-bottom: 4px; \n " + " margin-left: 150px; \n " + "} \n "; + + + auto layout (new QFormLayout (this)); + layout->setSizeConstraint(QLayout::SetFixedSize); + + auto tabs (new QTabWidget (this)); + + auto base_widget (new QWidget (this)); + auto base_layout(new QGridLayout (base_widget)); + + + auto basic_controls_layout (new QFormLayout (this)); + base_layout->addLayout(basic_controls_layout, 0, 0); + + base_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto label = new QLabel("Basic controls:"); + label->setStyleSheet(header_style); + basic_controls_layout->addRow(label); + + generate_hotkey_row({FontNoggit::rmb_drag}, "\aRotate camera", basic_controls_layout); + generate_hotkey_row({FontNoggit::lmb}, "\aSelect chunk or object", basic_controls_layout); + generate_hotkey_row({FontNoggit::i}, "\aInvert mouse up and down", basic_controls_layout); + generate_hotkey_row({FontNoggit::q, FontNoggit::e}, "\a,\aMove up and down", basic_controls_layout); + generate_hotkey_row({FontNoggit::w, FontNoggit::a , FontNoggit::s , FontNoggit::d}, "\a\a\a\aMove left, right, forward, backwards", basic_controls_layout); + generate_hotkey_row({FontNoggit::home}, "\aMove position to the cursor", basic_controls_layout); + generate_hotkey_row({FontNoggit::m}, "\aShow map", basic_controls_layout); + generate_hotkey_row({FontNoggit::u}, "\a2D texture editor", basic_controls_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::f1}, "\a+\aThis help", basic_controls_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::j}, "\a+\aReload an adt under the camera", basic_controls_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::r}, "\a+\aTurn camera 180 degrees", basic_controls_layout); + generate_hotkey_row({FontNoggit::shift}, "\a+ 1, 2, 3 or 4 Set a predefined camera speed", basic_controls_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::f4}, "\a+\aExit to main menu", basic_controls_layout); + generate_hotkey_row({FontNoggit::l}, "\aToggle top view (hint: it's faster to use with graphic tablet stylus buttons)", basic_controls_layout); + generate_hotkey_row({}, "", basic_controls_layout); // padding + + auto toggles_layout(new QFormLayout(this)); + base_layout->addLayout(toggles_layout, 0, 1); + + auto label_toggle = new QLabel("Toggles:"); + label_toggle->setStyleSheet(header_style); + toggles_layout->addRow(label_toggle); + + generate_hotkey_row({FontNoggit::f1}, "\aToggle M2s", toggles_layout); + generate_hotkey_row({FontNoggit::f2}, "\aToggle WMO doodads set", toggles_layout); + generate_hotkey_row({FontNoggit::f3}, "\aToggle ground", toggles_layout); + generate_hotkey_row({FontNoggit::f4}, "\aToggle water", toggles_layout); + generate_hotkey_row({FontNoggit::f6}, "\aToggle WMOs", toggles_layout); + generate_hotkey_row({FontNoggit::f7}, "\aToggle chunk (red) and ADT (green) lines", toggles_layout); + generate_hotkey_row({FontNoggit::f8}, "\aToggle detailed window", toggles_layout); + generate_hotkey_row({FontNoggit::f9}, "\aToggle map contour", toggles_layout); + generate_hotkey_row({FontNoggit::f10}, "\aToggle wireframe", toggles_layout); + generate_hotkey_row({FontNoggit::f11}, "\aToggle model animations", toggles_layout); + generate_hotkey_row({FontNoggit::f12}, "\aToggle fog", toggles_layout); + generate_hotkey_row({}, "1 - 9 Select the editing modes", toggles_layout); + + auto files_layout(new QFormLayout(this)); + base_layout->addLayout(files_layout, 1, 0); + + auto label_files = new QLabel("Files:"); + label_files->setStyleSheet(header_style); + files_layout->addRow(label_files); + + generate_hotkey_row({FontNoggit::f5}, "\aSave bookmark", files_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::s}, "\a+\a Save all changed ADT tiles", files_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::s}, "\a+\a+\aSave ADT tile at camera position", files_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::a}, "\a+\a+\aSave all loaded ADT tiles", files_layout); + generate_hotkey_row({FontNoggit::g}, "\aSave port commands to ports.txt", files_layout); + + auto adjust_layout(new QFormLayout(this)); + base_layout->addLayout(adjust_layout, 1, 1); + + auto label_adjust = new QLabel("Adjust:"); + label_adjust->setStyleSheet(header_style); + adjust_layout->addRow(label_adjust); + + generate_hotkey_row({FontNoggit::o, FontNoggit::p}, "\aor\aSlower / Faster movement", adjust_layout); + generate_hotkey_row({FontNoggit::b, FontNoggit::n}, "\aor\aSlower / Faster time", adjust_layout); + generate_hotkey_row({FontNoggit::j}, "\aPause time", adjust_layout); + // NYI + // generate_hotkey_row({FontNoggit::shift, FontNoggit::plus, FontNoggit::minus}, "\a+\aor\aFog distance when no model is selected", adjust_layout); + + auto flag_widget (new QWidget (this)); + auto flag_layout (new QFormLayout (flag_widget)); + + auto holes_label = new QLabel("Holes:"); + holes_label->setStyleSheet(header_style); + flag_layout->addRow(holes_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb}, "\a+\aClear hole", flag_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb}, "\a+\aAdd hole", flag_layout); + generate_hotkey_row({FontNoggit::t}, "\aRemove all holes on ADT", flag_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::t}, "\a+\aRemove all ground on ADT", flag_layout); + + auto impass_flags_label = new QLabel("Impassible Flags:"); + impass_flags_label->setStyleSheet(header_style); + flag_layout->addRow(impass_flags_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aPaint flag", flag_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aClear flag", flag_layout); + + auto areaid_label = new QLabel("AreaID Flags:"); + areaid_label->setStyleSheet(header_style); + flag_layout->addRow(areaid_label); + + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aPick existing AreaID", flag_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aPaint selected AreaID", flag_layout); + generate_hotkey_row({ FontNoggit::f }, "\a - Fill current ADT with selected AreaID", flag_layout); + + + auto ground_widget (new QWidget (this)); + auto ground_layout (new QGridLayout (ground_widget)); + + auto ground_column1_layout(new QFormLayout(this)); + ground_layout->addLayout(ground_column1_layout, 0, 0); + + auto ground_label = new QLabel("Edit ground:"); + ground_label->setStyleSheet(header_style); + ground_column1_layout->addRow(ground_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::f1 }, "\a+\aToggle ground edit mode", ground_column1_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", ground_column1_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange speed", ground_column1_layout); + + auto raise_label = new QLabel("Raise / Lower tool:"); + raise_label->setStyleSheet(header_style); + ground_column1_layout->addRow(raise_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aRaise terrain", ground_column1_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aLower terrain", ground_column1_layout); + generate_hotkey_row({FontNoggit::y }, "\aSwitch to next type", ground_column1_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::rmb_drag }, "\a+\aChange inner radius", ground_column1_layout); + + auto raise_label_vm = new QLabel("Raise / Lower tool (vertex mode):"); + raise_label_vm->setStyleSheet(header_style); + ground_column1_layout->addRow(raise_label_vm); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aSelect vertices", ground_column1_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aDeselect vertices", ground_column1_layout); + generate_hotkey_row({FontNoggit::c }, "\aClear selection", ground_column1_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aFlatten vertices", ground_column1_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::rmb_drag }, "\a+\aOrient vertices toward the mouse cursor", ground_column1_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::rmb_drag }, "\a+\aChange vertices height", ground_column1_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", ground_column1_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", ground_column1_layout); + + auto ground_column2_layout(new QFormLayout(this)); + ground_layout->addLayout(ground_column2_layout, 0, 1); + + auto flatten_label = new QLabel("Flatten / Blur tool:"); + flatten_label->setStyleSheet(header_style); + ground_column2_layout->addRow(flatten_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aFlatten terrain", ground_column2_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aBlur terrain", ground_column2_layout); + generate_hotkey_row({FontNoggit::t }, "\aToggle flatten angle", ground_column2_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::t }, "\a+\aToggle flatten type", ground_column2_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", ground_column2_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", ground_column2_layout); + generate_hotkey_row({FontNoggit::y }, "\aSwitch to next type", ground_column2_layout); + generate_hotkey_row({FontNoggit::f }, "\aSet relative point", ground_column2_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aToggle flatten relative mode", ground_column2_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange height", ground_column2_layout); + + + auto texture_widget (new QWidget (this)); + auto texture_layout (new QFormLayout (texture_widget)); + + auto common_controls_label = new QLabel("Common controls:"); + common_controls_label->setStyleSheet(header_style); + texture_layout->addRow(common_controls_label); + + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aOpen texture picker for the chunk", texture_layout); + + auto paint_label = new QLabel("Paint:"); + paint_label->setStyleSheet(header_style); + texture_layout->addRow(paint_label); + + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::shift, FontNoggit::alt, FontNoggit::lmb }, "\a+\a+\a+\aErase textures", texture_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aDraw texture or fills if chunk is empty", texture_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange radius", texture_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::rmb_drag }, "\a+\aChange hardness (falloff)", texture_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange pressure (strength)", texture_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange opacity (gradient)", texture_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::r }, "\a+\aToggle min and max oapcity (gradient)", texture_layout); + generate_hotkey_row({FontNoggit::t }, "\aToggle spray brush", texture_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange spray radius", texture_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange spray pressure", texture_layout); + + auto swapper_label = new QLabel("Swap:"); + swapper_label->setStyleSheet(header_style); + texture_layout->addRow(swapper_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aSwap texture", texture_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange radius", texture_layout); + generate_hotkey_row({FontNoggit::t }, "\aToggle brush swapper", texture_layout); + + auto anim_label = new QLabel("Anim:"); + anim_label->setStyleSheet(header_style); + texture_layout->addRow(anim_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aUpdate animation", texture_layout); + generate_hotkey_row({FontNoggit::t }, "\aSwitch between add/remove animation mode", texture_layout); + + + auto water_widget (new QWidget (this)); + auto water_layout (new QFormLayout (water_widget)); + + auto water_label = new QLabel("Water:"); + water_label->setStyleSheet(header_style); + water_layout->addRow(water_label); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aAdd liquid", water_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aRemove liquid", water_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", water_layout); + generate_hotkey_row({FontNoggit::t }, "\aToggle angled mode", water_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aChange orientation", water_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::mmb }, "\a+\aChange angle", water_layout); + generate_hotkey_row({FontNoggit::f }, "\aSet lock position to cursor position", water_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::f }, "\a+\aToggle lock mode", water_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::mmb }, "\a+\aChange height", water_layout); + + + auto object_widget (new QWidget (this)); + auto object_layout (new QFormLayout (object_widget)); + + auto object_label = new QLabel("Edit objects if a model is selected with left click (in object editor):"); + object_label->setStyleSheet(header_style); + object_layout->addRow(object_label); + + generate_hotkey_row({FontNoggit::mmb }, "\aMove object", object_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::mmb }, "\a+\aScale M2", object_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::ctrl, FontNoggit::alt, FontNoggit::lmb }, "\aor\aor\a+\aRotate object", object_layout); + generate_hotkey_row({FontNoggit::ctrl }, "\a+ 0 - 9 Change doodadset of selected WMO", object_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::r }, "\a+\aReset rotation", object_layout); + generate_hotkey_row({FontNoggit::h }, "\aToggle selected model/wmo visibility", object_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::h }, "\a+\a - Hide/Show hidden model/wmo", object_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::h }, "\a+\a - Clear hidden model/wmo list", object_layout); + generate_hotkey_row({FontNoggit::page_down }, "\aSet object to ground level", object_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::c }, "\a+\aCopy object to clipboard", object_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::v }, "\a+\aPaste object on mouse position", object_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::b }, "\a+\aDuplicate selected object to mouse position", object_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::v }, "\a+\aImport last M2 from WMV", object_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::v }, "\a+\aImport last WMO from WMV", object_layout); + generate_hotkey_row({FontNoggit::t }, "\aSwitch between paste modes", object_layout); + generate_hotkey_row({FontNoggit::f }, "\aMove selection to cursor position", object_layout); + generate_hotkey_row({FontNoggit::minus, FontNoggit::plus }, "\aor\aScale M2", object_layout); + generate_hotkey_row({FontNoggit::num }, "\a 7 or 9 Rotate object", object_layout); + generate_hotkey_row({FontNoggit::num }, "\a 4 or 8 or 6 or 2 Vertical position", object_layout); + generate_hotkey_row({FontNoggit::num }, "\a 1 or 3 Move up/down", object_layout); + generate_hotkey_row({FontNoggit::shift }, "Holding \a 1 / 3 Double speed", object_layout); + generate_hotkey_row({FontNoggit::ctrl }, "Holding \a 1 / 3 Triple speed", object_layout); + generate_hotkey_row({FontNoggit::shift, FontNoggit::ctrl }, "Holding \a and \a Half speed", object_layout); + + auto shader_widget (new QWidget (this)); + auto shader_layout (new QFormLayout (shader_widget)); + + generate_hotkey_row({FontNoggit::shift, FontNoggit::lmb }, "\a+\aAdd shader", shader_layout); + generate_hotkey_row({FontNoggit::ctrl, FontNoggit::lmb }, "\a+\aRemove shader", shader_layout); + generate_hotkey_row({FontNoggit::alt, FontNoggit::lmb_drag }, "\a+\aChange brush size", shader_layout); + generate_hotkey_row({FontNoggit::space, FontNoggit::lmb_drag }, "\a+\aChange speed", shader_layout); + generate_hotkey_row({FontNoggit::mmb }, "\aPick shader color from the ground", shader_layout); + generate_hotkey_row({FontNoggit::plus }, "\aAdd current color to palette", shader_layout); + + layout->addWidget(tabs); + tabs->addTab(base_widget, "Basic"); + tabs->addTab(ground_widget, "Terrain Editors"); + tabs->addTab(texture_widget, "Texture Painter"); + tabs->addTab(water_widget, "Water Editor"); + tabs->addTab(object_widget, "Object Editor"); + tabs->addTab(shader_widget, "Vertex Painter"); + tabs->addTab(flag_widget, "Impass Flag / Hole Cutter / Area ID"); + } + + + void help::generate_hotkey_row(std::initializer_list&& hotkeys, const char* description, QFormLayout* layout) + { + auto row_layout = new QHBoxLayout(this); + + const char* from = nullptr; + auto icon = hotkeys.begin(); + + while (*description) + { + if (*description == '\a') + { + if (from) + { + auto label = new QLabel(::std::string(from, description - from).c_str()); + row_layout->addWidget(label); + } + + auto label = new QLabel(this); + QIcon hotkey_icon = FontNoggitIcon(*icon++); + label->setPixmap(hotkey_icon.pixmap(22, 22)); + row_layout->addWidget(label); + + from = ++description; + } + else + { + if (!from) + { + from = description; + } + ++description; + } + } + + if (from && *from) + { + auto label = new QLabel(from); + row_layout->addWidget(label); + } + + row_layout->setAlignment(Qt::AlignLeft); + layout->addRow(row_layout); + + } + + } +} diff --git a/src/noggit/ui/MinimapCreator.cpp b/src/noggit/ui/MinimapCreator.cpp index 14649f20..0052bf01 100755 --- a/src/noggit/ui/MinimapCreator.cpp +++ b/src/noggit/ui/MinimapCreator.cpp @@ -827,17 +827,17 @@ namespace Noggit // Buttons connect(cur_adt_btn, &QPushButton::clicked, [=]() { _render_settings.export_mode = MinimapGenMode::CURRENT_ADT; - mapView->initMinimapSave(); + emit onSave(); }); connect(sel_adts_btn, &QPushButton::clicked, [=]() { _render_settings.export_mode = MinimapGenMode::SELECTED_ADTS; - mapView->initMinimapSave(); + emit onSave(); }); connect(all_adts_btn, &QPushButton::clicked, [=]() { _render_settings.export_mode = MinimapGenMode::MAP; - mapView->initMinimapSave(); + emit onSave(); }); } diff --git a/src/noggit/ui/MinimapCreator.hpp b/src/noggit/ui/MinimapCreator.hpp index 14910361..7c20d37e 100755 --- a/src/noggit/ui/MinimapCreator.hpp +++ b/src/noggit/ui/MinimapCreator.hpp @@ -15,53 +15,13 @@ #include #include +#include #include class MapView; class World; -enum MinimapGenMode -{ - CURRENT_ADT, - SELECTED_ADTS, - MAP -}; - -struct MinimapRenderSettings -{ - MinimapGenMode export_mode; - std::string file_format = ".blp"; - - // Render settings - int resolution = 512; - bool draw_m2 = false; - bool draw_wmo = true; - bool draw_water = true; - bool draw_adt_grid = false; - bool draw_elevation = false; - bool draw_shadows = false; - bool use_filters = false; - bool combined_minimap = false; - - // Selection - std::array selected_tiles = {false}; - - // Filtering - QListWidget* m2_model_filter_include; - QListWidget* m2_instance_filter_include; - QListWidget* wmo_model_filter_exclude; - QListWidget* wmo_instance_filter_exclude; - - // Lighting. Based on default eastern kingdom global light settings (lightparams 12) - glm::vec3 diffuse_color = {1.0, 0.532352924, 0.0}; - glm::vec3 ambient_color = {0.407770514, 0.508424163, 0.602650642}; - glm::vec4 ocean_color_light = {0.0693173409, 0.294008732, 0.348329663, 0.75}; - glm::vec4 ocean_color_dark = {0.000762581825, 0.113907099, 0.161220074, 1.0}; - glm::vec4 river_color_light = {0.308351517, 0.363725543, 0.0798838138, 0.5}; - glm::vec4 river_color_dark = {0.19945538, 0.320697188, 0.332425594, 1.0}; - -}; namespace Noggit @@ -72,6 +32,7 @@ namespace Noggit class MinimapCreator : public QWidget { + Q_OBJECT public: MinimapCreator(MapView* mapView, World* world, QWidget* parent = nullptr); @@ -79,7 +40,8 @@ namespace Noggit float brushRadius() const { return _radius; } - std::array* getSelectedTiles() { return &_render_settings.selected_tiles; }; + //std::array* getSelectedTiles() { return &_render_settings.selected_tiles; }; + std::vector* getSelectedTiles() { return &_render_settings.selected_tiles; }; MinimapRenderSettings* getMinimapRenderSettings() { return &_render_settings; }; @@ -98,6 +60,9 @@ namespace Noggit void loadFiltersFromJSON(); void saveFiltersToJSON(); + signals: + void onSave(); + private: float _radius = 0.01f; MinimapRenderSettings _render_settings; diff --git a/src/noggit/ui/ObjectEditor.cpp b/src/noggit/ui/ObjectEditor.cpp index c4d678fa..1f88c69a 100755 --- a/src/noggit/ui/ObjectEditor.cpp +++ b/src/noggit/ui/ObjectEditor.cpp @@ -544,7 +544,9 @@ namespace Noggit connect( object_palette_btn , &QPushButton::clicked - , [=]() { mapView->getObjectPalette()->setVisible(mapView->getObjectPalette()->isHidden()); } + , [=]() { + emit objectPaletteBtnPressed(); + } ); connect(_doodadSetSelector diff --git a/src/noggit/ui/ObjectEditor.h b/src/noggit/ui/ObjectEditor.h index a1201b31..8e594001 100755 --- a/src/noggit/ui/ObjectEditor.h +++ b/src/noggit/ui/ObjectEditor.h @@ -3,6 +3,7 @@ #pragma once #include #include +#include #include #include @@ -36,21 +37,11 @@ enum ModelPasteMode namespace Noggit { - struct object_paste_params - { - float minRotation = -180.f; - float maxRotation = 180.f; - float minTilt = -5.f; - float maxTilt = 5.f; - float minScale = 0.9f; - float maxScale = 1.1f; - bool rotate_on_terrain = true; - }; - namespace Ui { class object_editor : public QWidget { + Q_OBJECT public: object_editor ( MapView* , World* @@ -94,6 +85,9 @@ namespace Noggit void update_selection_ui(World* world); + signals: + void objectPaletteBtnPressed(); + private: float _radius = 0.01f; float _drag_selection_depth = 100.0f; diff --git a/src/noggit/ui/ShaderTool.cpp b/src/noggit/ui/ShaderTool.cpp index 0bd5cdaf..a7d3aa9d 100755 --- a/src/noggit/ui/ShaderTool.cpp +++ b/src/noggit/ui/ShaderTool.cpp @@ -273,9 +273,7 @@ namespace Noggit matrix.rotateRadians(_image_mask_group->getRotation() / 360.0f * 2.0f * M_PI); _mask_image = pixmap->toImage().transformed(matrix, Qt::SmoothTransformation); - if (_map_view->get_editing_mode() != editing_mode::stamp - || (_map_view->getActiveStampModeItem() && _map_view->getActiveStampModeItem() == this)) - _map_view->setBrushTexture(&_mask_image); + emit _map_view->trySetBrushTexture(&_mask_image, this); } QJsonObject ShaderTool::toJSON() diff --git a/src/noggit/ui/TerrainTool.cpp b/src/noggit/ui/TerrainTool.cpp index 68a645f0..cd65a959 100755 --- a/src/noggit/ui/TerrainTool.cpp +++ b/src/noggit/ui/TerrainTool.cpp @@ -241,9 +241,7 @@ namespace Noggit matrix.rotateRadians(_image_mask_group->getRotation() / 360.0f * 2.0f * M_PI); _mask_image = pixmap->toImage().transformed(matrix, Qt::SmoothTransformation); - if (_map_view->get_editing_mode() != editing_mode::stamp - || (_map_view->getActiveStampModeItem() && _map_view->getActiveStampModeItem() == this)) - _map_view->setBrushTexture(&_mask_image); + emit _map_view->trySetBrushTexture(&_mask_image, this); } void TerrainTool::changeTerrain diff --git a/src/noggit/ui/Toolbar.cpp b/src/noggit/ui/Toolbar.cpp index a630214b..e4175d9e 100755 --- a/src/noggit/ui/Toolbar.cpp +++ b/src/noggit/ui/Toolbar.cpp @@ -1,12 +1,13 @@ // This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include #include namespace Noggit { namespace Ui { - toolbar::toolbar(std::function set_editing_mode) + toolbar::toolbar(std::vector> const& tools, std::function set_editing_mode) : _set_editing_mode (set_editing_mode) , _tool_group(this) { @@ -14,20 +15,10 @@ namespace Noggit setAllowedAreas(Qt::LeftToolBarArea); setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - add_tool_icon(editing_mode::ground, tr("Raise / Lower"), FontNoggit::TOOL_RAISE_LOWER); - add_tool_icon(editing_mode::flatten_blur, tr("Flatten / Blur"), FontNoggit::TOOL_FLATTEN_BLUR); - add_tool_icon(editing_mode::paint, tr("Texture Painter"), FontNoggit::TOOL_TEXTURE_PAINT); - add_tool_icon(editing_mode::holes, tr("Hole Cutter"), FontNoggit::TOOL_HOLE_CUTTER); - add_tool_icon(editing_mode::areaid, tr("Area Designator"), FontNoggit::TOOL_AREA_DESIGNATOR); - add_tool_icon(editing_mode::impass, tr("Impass Designator"), FontNoggit::TOOL_IMPASS_DESIGNATOR); - add_tool_icon(editing_mode::water, tr("Water Editor"), FontNoggit::TOOL_WATER_EDITOR); - add_tool_icon(editing_mode::mccv, tr("Vertex Painter"), FontNoggit::TOOL_VERTEX_PAINT); - add_tool_icon(editing_mode::object, tr("Object Editor"), FontNoggit::TOOL_OBJECT_EDITOR); - add_tool_icon(editing_mode::minimap, tr("Minimap Editor"), FontNoggit::TOOL_MINIMAP_EDITOR); - add_tool_icon(editing_mode::stamp, tr("Stamp Mode"), FontNoggit::TOOL_STAMP); - add_tool_icon(editing_mode::light, tr("Light Editor"), FontNoggit::TOOL_LIGHT); - add_tool_icon(editing_mode::scripting, tr("Scripting"), FontNoggit::INFO); - add_tool_icon(editing_mode::chunk, tr("Chunk Manipulator"), FontNoggit::INFO); + for (auto&& tool : tools) + { + add_tool_icon(tool->editingMode(), tr(tool->name()), tool->icon()); + } } void toolbar::add_tool_icon(editing_mode mode, const QString& name, const FontNoggit::Icons& icon) diff --git a/src/noggit/ui/Toolbar.h b/src/noggit/ui/Toolbar.h index a424a00d..6f5bd595 100755 --- a/src/noggit/ui/Toolbar.h +++ b/src/noggit/ui/Toolbar.h @@ -12,12 +12,14 @@ namespace Noggit { + class Tool; + namespace Ui { class toolbar: public QToolBar { public: - toolbar(std::function set_editing_mode); + toolbar(std::vector> const& tools, std::function set_editing_mode); void check_tool(editing_mode); diff --git a/src/noggit/ui/Water.cpp b/src/noggit/ui/Water.cpp index f134230b..3e3566b8 100755 --- a/src/noggit/ui/Water.cpp +++ b/src/noggit/ui/Water.cpp @@ -1,396 +1,396 @@ -// This file is part of Noggit3, licensed under GNU General Public License (version 3). - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Noggit -{ - namespace Ui - { - water::water ( unsigned_int_property* current_layer - , BoolToggleProperty* display_all_layers - , QWidget* parent - ) - : QWidget (parent) - , _liquid_id(5) - , _liquid_type(liquid_basic_types_water) - , _radius(10.0f) - , _angle(10.0f) - , _orientation(0.0f) - , _locked(false) - , _angled_mode(false) - , _override_liquid_id(true) - , _override_height(true) - , _opacity_mode(auto_opacity) - , _custom_opacity_factor(RIVER_OPACITY_VALUE) - , _lock_pos(glm::vec3(0.0f, 0.0f, 0.0f)) - , tile(0, 0) - { - setMinimumWidth(250); - setMaximumWidth(250); - - auto layout (new QFormLayout (this)); - - auto brush_group(new QGroupBox("Brush", this)); - auto brush_layout (new QFormLayout (brush_group)); - - _radius_spin = new QDoubleSpinBox (this); - _radius_spin->setRange (0.f, 1000.f); - connect ( _radius_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _radius = f; } - ); - _radius_spin->setValue(_radius); - brush_layout->addRow ("Radius", _radius_spin); - - waterType = new QComboBox(this); - - for (DBCFile::Iterator i = gLiquidTypeDB.begin(); i != gLiquidTypeDB.end(); ++i) - { - int liquid_id = i->getInt(LiquidTypeDB::ID); - - // filter WMO liquids - if (liquid_id == LIQUID_WMO_Water || liquid_id == LIQUID_WMO_Ocean || liquid_id == LIQUID_WMO_Water_Interior - || liquid_id == LIQUID_WMO_Magma || liquid_id == LIQUID_WMO_Slime) - continue; - - std::stringstream ss; - ss << liquid_id << "-" << LiquidTypeDB::getLiquidName(liquid_id); - waterType->addItem (QString::fromUtf8(ss.str().c_str()), QVariant (liquid_id)); - - } - - connect (waterType, qOverload (&QComboBox::currentIndexChanged) - , [&] - { - changeWaterType(waterType->currentData().toInt()); - - // change auto opacity based on liquid type - if (_opacity_mode == custom_opacity || _opacity_mode == auto_opacity) - return; - - // other liquid types shouldn't use opacity(depth) - int liquid_type = LiquidTypeDB::getLiquidType(_liquid_id); - if (liquid_type == liquid_basic_types_ocean) // ocean - { - ocean_button->setChecked(true); - _opacity_mode = ocean_opacity; - } - else // water. opacity doesn't matter for lava/slim - { - river_button->setChecked(true); - _opacity_mode = river_opacity; - } - - } - ); - - brush_layout->addRow (waterType); - - layout->addRow (brush_group); - - auto angle_group (new QGroupBox ("Angled mode", this)); - angle_group->setCheckable (true); - angle_group->setChecked (_angled_mode.get()); - - - connect ( &_angled_mode, &BoolToggleProperty::changed - , angle_group, &QGroupBox::setChecked - ); - connect ( angle_group, &QGroupBox::toggled - , &_angled_mode, &BoolToggleProperty::set - ); - auto angle_layout (new QFormLayout (angle_group)); - - _angle_spin = new QDoubleSpinBox (this); - _angle_spin->setRange (0.00001f, 89.f); - _angle_spin->setSingleStep (2.0f); - connect ( _angle_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _angle = f; } - ); - _angle_spin->setValue(_angle); - angle_layout->addRow ("Angle", _angle_spin); - - _orientation_spin = new QDoubleSpinBox (this); - _orientation_spin->setRange (0.f, 360.f); - _orientation_spin->setWrapping (true); - _orientation_spin->setValue(_orientation); - _orientation_spin->setSingleStep (5.0f); - connect ( _orientation_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _orientation = f; } - ); - - angle_layout->addRow ("Orienation", _orientation_spin); - - layout->addRow (angle_group); - - auto lock_group (new QGroupBox ("Lock", this)); - lock_group->setCheckable (true); - lock_group->setChecked (_locked.get()); - auto lock_layout (new QFormLayout (lock_group)); - - lock_layout->addRow("X:", _x_spin = new QDoubleSpinBox (this)); - lock_layout->addRow("Z:", _z_spin = new QDoubleSpinBox (this)); - lock_layout->addRow("H:", _h_spin = new QDoubleSpinBox (this)); - - _x_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); - _z_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); - _h_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); - _x_spin->setDecimals (2); - _z_spin->setDecimals (2); - _h_spin->setDecimals (2); - - connect ( _x_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _lock_pos.x = f; } - ); - connect ( _z_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _lock_pos.z = f; } - ); - connect ( _h_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _lock_pos.y = f; } - ); - - connect ( &_locked, &BoolToggleProperty::changed - , lock_group, &QGroupBox::setChecked - ); - connect ( lock_group, &QGroupBox::toggled - , &_locked, &BoolToggleProperty::set - ); - - layout->addRow(lock_group); - - auto override_group (new QGroupBox ("Override", this)); - auto override_layout (new QFormLayout (override_group)); - - override_layout->addWidget (new CheckBox ("Liquid ID", &_override_liquid_id, this)); - override_layout->addWidget (new CheckBox ("Height", &_override_height, this)); - - layout->addRow(override_group); - - auto opacity_group (new QGroupBox ("Auto opacity", this)); - auto opacity_layout (new QFormLayout (opacity_group)); - - auto auto_button(new QRadioButton("Auto", this)); - auto_button->setToolTip("Automatically uses river or ocean opacity based on liquid type."); - river_button = new QRadioButton ("River", this); - river_button->setToolTip(std::to_string(RIVER_OPACITY_VALUE).c_str()); - ocean_button = new QRadioButton ("Ocean", this); - ocean_button->setToolTip(std::to_string(OCEAN_OPACITY_VALUE).c_str()); - custom_button = new QRadioButton ("Custom factor:", this); - - transparency_toggle = new QButtonGroup (this); - transparency_toggle->addButton(auto_button, auto_opacity); - transparency_toggle->addButton (river_button, river_opacity); - transparency_toggle->addButton (ocean_button, ocean_opacity); - transparency_toggle->addButton (custom_button, custom_opacity); - - connect ( transparency_toggle, qOverload (&QButtonGroup::idClicked) - , [&] (int id) { _opacity_mode = id; } - ); - - opacity_layout->addRow(auto_button); - opacity_layout->addRow (river_button); - opacity_layout->addRow (ocean_button); - opacity_layout->addRow (custom_button); - - transparency_toggle->button (_opacity_mode)->setChecked (true); - - QDoubleSpinBox *opacity_spin = new QDoubleSpinBox (this); - opacity_spin->setRange (0.f, 1.f); - opacity_spin->setDecimals (4); - opacity_spin->setSingleStep (0.02f); - opacity_spin->setValue(_custom_opacity_factor); - connect ( opacity_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (float f) { _custom_opacity_factor = f; } - ); - opacity_layout->addRow (opacity_spin); - - layout->addRow (opacity_group); - - layout->addRow ( new pushbutton - ( "Regen ADT opacity" - , [this] - { - emit regenerate_water_opacity - (get_opacity_factor()); - } - ) - ); - layout->addRow ( new pushbutton - ( "Crop water" - , [this] - { - emit crop_water(); - } - ) - ); - - auto layer_group (new QGroupBox ("Layers", this)); - auto layer_layout (new QFormLayout (layer_group)); - - layer_layout->addRow (new CheckBox("Show all layers", display_all_layers)); - layer_layout->addRow (new QLabel("Current layer:", this)); - - waterLayer = new QSpinBox (this); - waterLayer->setValue (current_layer->get()); - waterLayer->setRange (0, 100); - layer_layout->addRow (waterLayer); - - layout->addRow (layer_group); - - connect ( waterLayer, qOverload (&QSpinBox::valueChanged) - , current_layer, &unsigned_int_property::set - ); - connect ( current_layer, &unsigned_int_property::changed - , waterLayer, &QSpinBox::setValue - ); - - updateData(); - - } - - void water::updatePos(TileIndex const& newTile) - { - if (newTile == tile) return; - - tile = newTile; - - updateData(); - } - - void water::updateData() - { - std::stringstream mt; - mt << _liquid_id << " - " << LiquidTypeDB::getLiquidName(_liquid_id); - waterType->setCurrentText (QString::fromStdString (mt.str())); - _liquid_type = static_cast(LiquidTypeDB::getLiquidType(_liquid_id)); - } - - void water::changeWaterType(int waterint) - { - _liquid_id = waterint; - - updateData(); - } - - void water::changeRadius(float change) - { - _radius_spin->setValue(_radius + change); - } - - void water::setRadius(float radius) - { - _radius_spin->setValue(radius); - } - - void water::changeOrientation(float change) - { - _orientation += change; - - while (_orientation >= 360.0f) - { - _orientation -= 360.0f; - } - while (_orientation < 0.0f) - { - _orientation += 360.0f; - } - - _orientation_spin->setValue(_orientation); - } - - void water::changeAngle(float change) - { - _angle_spin->setValue(_angle + change); - } - - void water::change_height(float change) - { - _h_spin->setValue(_lock_pos.y + change); - } - - void water::paintLiquid (World* world, glm::vec3 const& pos, bool add) - { - world->paintLiquid ( pos - , _radius - , _liquid_id - , add - , math::degrees (_angled_mode.get() ? _angle : 0.0f) - , math::degrees (_angled_mode.get() ? _orientation : 0.0f) - , _locked.get() - , _lock_pos - , _override_height.get() - , _override_liquid_id.get() - , get_opacity_factor() - ); - } - - void water::lockPos(glm::vec3 const& cursor_pos) - { - QSignalBlocker const blocker_x(_x_spin); - QSignalBlocker const blocker_z(_z_spin); - QSignalBlocker const blocker_h(_h_spin); - _lock_pos = cursor_pos; - - _x_spin->setValue(_lock_pos.x); - _z_spin->setValue(_lock_pos.z); - _h_spin->setValue(_lock_pos.y); - - if (!_locked.get()) - { - toggle_lock(); - } - } - - void water::toggle_lock() - { - _locked.toggle(); - } - - void water::toggle_angled_mode() - { - _angled_mode.toggle(); - } - - float water::get_opacity_factor() const - { - switch (_opacity_mode) - { - default: // values found by experimenting - case river_opacity: return RIVER_OPACITY_VALUE; - case ocean_opacity: return OCEAN_OPACITY_VALUE; - case custom_opacity: return _custom_opacity_factor; - case auto_opacity: - { - switch (_liquid_type) - { - case 0: return RIVER_OPACITY_VALUE; - case 1: return OCEAN_OPACITY_VALUE; - default: return RIVER_OPACITY_VALUE; // lava and slime, opacity isn't used - } - } - break; - } - } - - QSize water::sizeHint() const - { - return QSize(250, height()); - } - } -} +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Noggit +{ + namespace Ui + { + water::water ( unsigned_int_property* current_layer + , BoolToggleProperty* display_all_layers + , QWidget* parent + ) + : QWidget (parent) + , _liquid_id(5) + , _liquid_type(liquid_basic_types_water) + , _radius(10.0f) + , _angle(10.0f) + , _orientation(0.0f) + , _locked(false) + , _angled_mode(false) + , _override_liquid_id(true) + , _override_height(true) + , _opacity_mode(auto_opacity) + , _custom_opacity_factor(RIVER_OPACITY_VALUE) + , _lock_pos(glm::vec3(0.0f, 0.0f, 0.0f)) + , tile(0, 0) + { + setMinimumWidth(250); + setMaximumWidth(250); + + auto layout (new QFormLayout (this)); + + auto brush_group(new QGroupBox("Brush", this)); + auto brush_layout (new QFormLayout (brush_group)); + + _radius_spin = new QDoubleSpinBox (this); + _radius_spin->setRange (0.f, 1000.f); + connect ( _radius_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _radius = f; } + ); + _radius_spin->setValue(_radius); + brush_layout->addRow ("Radius", _radius_spin); + + waterType = new QComboBox(this); + + for (DBCFile::Iterator i = gLiquidTypeDB.begin(); i != gLiquidTypeDB.end(); ++i) + { + int liquid_id = i->getInt(LiquidTypeDB::ID); + + // filter WMO liquids + if (liquid_id == LIQUID_WMO_Water || liquid_id == LIQUID_WMO_Ocean || liquid_id == LIQUID_WMO_Water_Interior + || liquid_id == LIQUID_WMO_Magma || liquid_id == LIQUID_WMO_Slime) + continue; + + std::stringstream ss; + ss << liquid_id << "-" << LiquidTypeDB::getLiquidName(liquid_id); + waterType->addItem (QString::fromUtf8(ss.str().c_str()), QVariant (liquid_id)); + + } + + connect (waterType, qOverload (&QComboBox::currentIndexChanged) + , [&] + { + changeWaterType(waterType->currentData().toInt()); + + // change auto opacity based on liquid type + if (_opacity_mode == custom_opacity || _opacity_mode == auto_opacity) + return; + + // other liquid types shouldn't use opacity(depth) + int liquid_type = LiquidTypeDB::getLiquidType(_liquid_id); + if (liquid_type == liquid_basic_types_ocean) // ocean + { + ocean_button->setChecked(true); + _opacity_mode = ocean_opacity; + } + else // water. opacity doesn't matter for lava/slim + { + river_button->setChecked(true); + _opacity_mode = river_opacity; + } + + } + ); + + brush_layout->addRow (waterType); + + layout->addRow (brush_group); + + auto angle_group (new QGroupBox ("Angled mode", this)); + angle_group->setCheckable (true); + angle_group->setChecked (_angled_mode.get()); + + + connect ( &_angled_mode, &BoolToggleProperty::changed + , angle_group, &QGroupBox::setChecked + ); + connect ( angle_group, &QGroupBox::toggled + , &_angled_mode, &BoolToggleProperty::set + ); + auto angle_layout (new QFormLayout (angle_group)); + + _angle_spin = new QDoubleSpinBox (this); + _angle_spin->setRange (0.00001f, 89.f); + _angle_spin->setSingleStep (2.0f); + connect ( _angle_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _angle = f; } + ); + _angle_spin->setValue(_angle); + angle_layout->addRow ("Angle", _angle_spin); + + _orientation_spin = new QDoubleSpinBox (this); + _orientation_spin->setRange (0.f, 360.f); + _orientation_spin->setWrapping (true); + _orientation_spin->setValue(_orientation); + _orientation_spin->setSingleStep (5.0f); + connect ( _orientation_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _orientation = f; } + ); + + angle_layout->addRow ("Orienation", _orientation_spin); + + layout->addRow (angle_group); + + auto lock_group (new QGroupBox ("Lock", this)); + lock_group->setCheckable (true); + lock_group->setChecked (_locked.get()); + auto lock_layout (new QFormLayout (lock_group)); + + lock_layout->addRow("X:", _x_spin = new QDoubleSpinBox (this)); + lock_layout->addRow("Z:", _z_spin = new QDoubleSpinBox (this)); + lock_layout->addRow("H:", _h_spin = new QDoubleSpinBox (this)); + + _x_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); + _z_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); + _h_spin->setRange (std::numeric_limits::lowest(), std::numeric_limits::max()); + _x_spin->setDecimals (2); + _z_spin->setDecimals (2); + _h_spin->setDecimals (2); + + connect ( _x_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _lock_pos.x = f; } + ); + connect ( _z_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _lock_pos.z = f; } + ); + connect ( _h_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _lock_pos.y = f; } + ); + + connect ( &_locked, &BoolToggleProperty::changed + , lock_group, &QGroupBox::setChecked + ); + connect ( lock_group, &QGroupBox::toggled + , &_locked, &BoolToggleProperty::set + ); + + layout->addRow(lock_group); + + auto override_group (new QGroupBox ("Override", this)); + auto override_layout (new QFormLayout (override_group)); + + override_layout->addWidget (new CheckBox ("Liquid ID", &_override_liquid_id, this)); + override_layout->addWidget (new CheckBox ("Height", &_override_height, this)); + + layout->addRow(override_group); + + auto opacity_group (new QGroupBox ("Auto opacity", this)); + auto opacity_layout (new QFormLayout (opacity_group)); + + auto auto_button(new QRadioButton("Auto", this)); + auto_button->setToolTip("Automatically uses river or ocean opacity based on liquid type."); + river_button = new QRadioButton ("River", this); + river_button->setToolTip(std::to_string(RIVER_OPACITY_VALUE).c_str()); + ocean_button = new QRadioButton ("Ocean", this); + ocean_button->setToolTip(std::to_string(OCEAN_OPACITY_VALUE).c_str()); + custom_button = new QRadioButton ("Custom factor:", this); + + transparency_toggle = new QButtonGroup (this); + transparency_toggle->addButton(auto_button, auto_opacity); + transparency_toggle->addButton (river_button, river_opacity); + transparency_toggle->addButton (ocean_button, ocean_opacity); + transparency_toggle->addButton (custom_button, custom_opacity); + + connect ( transparency_toggle, qOverload (&QButtonGroup::idClicked) + , [&] (int id) { _opacity_mode = id; } + ); + + opacity_layout->addRow(auto_button); + opacity_layout->addRow (river_button); + opacity_layout->addRow (ocean_button); + opacity_layout->addRow (custom_button); + + transparency_toggle->button (_opacity_mode)->setChecked (true); + + QDoubleSpinBox *opacity_spin = new QDoubleSpinBox (this); + opacity_spin->setRange (0.f, 1.f); + opacity_spin->setDecimals (4); + opacity_spin->setSingleStep (0.02f); + opacity_spin->setValue(_custom_opacity_factor); + connect ( opacity_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (float f) { _custom_opacity_factor = f; } + ); + opacity_layout->addRow (opacity_spin); + + layout->addRow (opacity_group); + + layout->addRow ( new pushbutton + ( "Regen ADT opacity" + , [this] + { + emit regenerate_water_opacity + (get_opacity_factor()); + } + ) + ); + layout->addRow ( new pushbutton + ( "Crop water" + , [this] + { + emit crop_water(); + } + ) + ); + + auto layer_group (new QGroupBox ("Layers", this)); + auto layer_layout (new QFormLayout (layer_group)); + + layer_layout->addRow (new CheckBox("Show all layers", display_all_layers)); + layer_layout->addRow (new QLabel("Current layer:", this)); + + waterLayer = new QSpinBox (this); + waterLayer->setValue (current_layer->get()); + waterLayer->setRange (0, 100); + layer_layout->addRow (waterLayer); + + layout->addRow (layer_group); + + connect ( waterLayer, qOverload (&QSpinBox::valueChanged) + , current_layer, &unsigned_int_property::set + ); + connect ( current_layer, &unsigned_int_property::changed + , waterLayer, &QSpinBox::setValue + ); + + updateData(); + + } + + void water::updatePos(TileIndex const& newTile) + { + if (newTile == tile) return; + + tile = newTile; + + updateData(); + } + + void water::updateData() + { + std::stringstream mt; + mt << _liquid_id << " - " << LiquidTypeDB::getLiquidName(_liquid_id); + waterType->setCurrentText (QString::fromStdString (mt.str())); + _liquid_type = static_cast(LiquidTypeDB::getLiquidType(_liquid_id)); + } + + void water::changeWaterType(int waterint) + { + _liquid_id = waterint; + + updateData(); + } + + void water::changeRadius(float change) + { + _radius_spin->setValue(_radius + change); + } + + void water::setRadius(float radius) + { + _radius_spin->setValue(radius); + } + + void water::changeOrientation(float change) + { + _orientation += change; + + while (_orientation >= 360.0f) + { + _orientation -= 360.0f; + } + while (_orientation < 0.0f) + { + _orientation += 360.0f; + } + + _orientation_spin->setValue(_orientation); + } + + void water::changeAngle(float change) + { + _angle_spin->setValue(_angle + change); + } + + void water::change_height(float change) + { + _h_spin->setValue(_lock_pos.y + change); + } + + void water::paintLiquid (World* world, glm::vec3 const& pos, bool add) + { + world->paintLiquid ( pos + , _radius + , _liquid_id + , add + , math::degrees (_angled_mode.get() ? _angle : 0.0f) + , math::degrees (_angled_mode.get() ? _orientation : 0.0f) + , _locked.get() + , _lock_pos + , _override_height.get() + , _override_liquid_id.get() + , get_opacity_factor() + ); + } + + void water::lockPos(glm::vec3 const& cursor_pos) + { + QSignalBlocker const blocker_x(_x_spin); + QSignalBlocker const blocker_z(_z_spin); + QSignalBlocker const blocker_h(_h_spin); + _lock_pos = cursor_pos; + + _x_spin->setValue(_lock_pos.x); + _z_spin->setValue(_lock_pos.z); + _h_spin->setValue(_lock_pos.y); + + if (!_locked.get()) + { + toggle_lock(); + } + } + + void water::toggle_lock() + { + _locked.toggle(); + } + + void water::toggle_angled_mode() + { + _angled_mode.toggle(); + } + + float water::get_opacity_factor() const + { + switch (_opacity_mode) + { + default: // values found by experimenting + case river_opacity: return RIVER_OPACITY_VALUE; + case ocean_opacity: return OCEAN_OPACITY_VALUE; + case custom_opacity: return _custom_opacity_factor; + case auto_opacity: + { + switch (_liquid_type) + { + case 0: return RIVER_OPACITY_VALUE; + case 1: return OCEAN_OPACITY_VALUE; + default: return RIVER_OPACITY_VALUE; // lava and slime, opacity isn't used + } + } + break; + } + } + + QSize water::sizeHint() const + { + return QSize(250, height()); + } + } +} diff --git a/src/noggit/ui/minimap_widget.cpp b/src/noggit/ui/minimap_widget.cpp index 268a7e7c..1628c1cc 100755 --- a/src/noggit/ui/minimap_widget.cpp +++ b/src/noggit/ui/minimap_widget.cpp @@ -76,7 +76,7 @@ namespace Noggit if (!_selected_tiles) return; - _selected_tiles->fill(false); + std::memset(_selected_tiles->data(), false, _selected_tiles->size()); } ); } diff --git a/src/noggit/ui/minimap_widget.hpp b/src/noggit/ui/minimap_widget.hpp index b557fe8b..80bbd22b 100755 --- a/src/noggit/ui/minimap_widget.hpp +++ b/src/noggit/ui/minimap_widget.hpp @@ -41,9 +41,9 @@ namespace Noggit { _draw_boundaries = draw_boundaries_; update(); return _draw_boundaries; } inline const bool& draw_boundaries() const { return _draw_boundaries; } - inline const std::array* use_selection (std::array* selection_) + inline const std::vector* use_selection (std::vector* selection_) { _use_selection = selection_; _selected_tiles = selection_; update(); return _selected_tiles; } - inline const std::array* selection() const { return _selected_tiles; } + inline const std::vector* selection() const { return _selected_tiles; } inline void camera (Noggit::Camera* camera) { _camera = camera; } void set_resizeable(bool state) { _resizeable = state; }; @@ -66,7 +66,7 @@ namespace Noggit private: World* _world; Noggit::Camera* _camera; - std::array* _selected_tiles; + std::vector* _selected_tiles; bool _draw_skies; bool _draw_camera; diff --git a/src/noggit/ui/object_palette.cpp b/src/noggit/ui/object_palette.cpp index ae532432..3179059b 100755 --- a/src/noggit/ui/object_palette.cpp +++ b/src/noggit/ui/object_palette.cpp @@ -102,7 +102,7 @@ namespace Noggit connect(_object_list, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) { - _map_view->getObjectEditor()->copy(item->toolTip().toStdString()); + emit selected(item->toolTip().toStdString()); } ); diff --git a/src/noggit/ui/texturing_tool.cpp b/src/noggit/ui/texturing_tool.cpp index 32164b6e..a5ad3f7d 100755 --- a/src/noggit/ui/texturing_tool.cpp +++ b/src/noggit/ui/texturing_tool.cpp @@ -347,7 +347,7 @@ namespace Noggit connect ( quick_palette_btn, &QPushButton::clicked , [=] () { - _map_view->getTexturePalette()->setVisible(_map_view->getTexturePalette()->isHidden()); + emit texturePaletteToggled(); } ); @@ -402,9 +402,7 @@ namespace Noggit matrix.rotateRadians(_image_mask_group->getRotation() * M_PI / 180.f); _mask_image = pixmap->toImage().transformed(matrix, Qt::SmoothTransformation); - if (_map_view->get_editing_mode() != editing_mode::stamp - || (_map_view->getActiveStampModeItem() && _map_view->getActiveStampModeItem() == this)) - _map_view->setBrushTexture(&_mask_image); + emit _map_view->trySetBrushTexture(&_mask_image, this); } void texturing_tool::update_brush_hardness() diff --git a/src/noggit/ui/texturing_tool.hpp b/src/noggit/ui/texturing_tool.hpp index 878011b3..d28938d0 100755 --- a/src/noggit/ui/texturing_tool.hpp +++ b/src/noggit/ui/texturing_tool.hpp @@ -21,6 +21,7 @@ #include #include #include +#include class World; class MapView; @@ -127,6 +128,7 @@ namespace Noggit class texturing_tool : public QWidget { + Q_OBJECT public: texturing_tool ( const glm::vec3* camera_pos , MapView* map_view @@ -197,6 +199,9 @@ namespace Noggit QJsonObject toJSON(); void fromJSON(QJsonObject const& json); + signals: + void texturePaletteToggled(); + private: void change_tex_flag(World* world, glm::vec3 const& pos, bool add, scoped_blp_texture_reference texture); diff --git a/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.cpp b/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.cpp index e00e9985..f291e51b 100755 --- a/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.cpp +++ b/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.cpp @@ -135,14 +135,7 @@ AssetBrowserWidget::AssetBrowserWidget(MapView* map_view, QWidget *parent) ui->viewport->setModel(str_path); _selected_path = str_path; - if (_browse_mode == asset_browse_mode::detail_doodads && _map_view->get_editing_mode() == editing_mode::paint) - { - _map_view->getGroundEffectsTool()->setDoodadSlotFromBrowser(str_path.c_str()); - } - else - { - _map_view->getObjectEditor()->copy(str_path); - } + emit selectionChanged(str_path); } } diff --git a/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp b/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp index 7a5aea00..1aa5b16a 100755 --- a/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp +++ b/src/noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp @@ -91,6 +91,7 @@ namespace Noggit asset_browse_mode _browse_mode = asset_browse_mode::world; signals: void gl_data_unloaded(); + void selectionChanged(std::string const& path); private: ::Ui::AssetBrowser* ui; diff --git a/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.cpp b/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.cpp index 34488a23..bfbe9c97 100755 --- a/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.cpp +++ b/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.cpp @@ -1,5 +1,7 @@ // This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include #include #include #include @@ -213,15 +215,15 @@ ViewToolbar::ViewToolbar(MapView* mapView, editing_mode mode) IconAction* _icon = new IconAction(FontNoggitIcon{ FontNoggit::TOOL_FLATTEN_BLUR }); CheckBoxAction* _raise = new CheckBoxAction(tr("Raise"), true); - connect(_raise->checkbox(), &QCheckBox::stateChanged, [mapView](int state) + connect(_raise->checkbox(), &QCheckBox::stateChanged, [this, mapView](int state) { - mapView->getFlattenTool()->_flatten_mode.raise = state; + emit updateStateRaise(state != 0); }); CheckBoxAction* _lower = new CheckBoxAction(tr("Lower"), true); - connect(_lower->checkbox(), &QCheckBox::stateChanged, [mapView](int state) + connect(_lower->checkbox(), &QCheckBox::stateChanged, [this, mapView](int state) { - mapView->getFlattenTool()->_flatten_mode.lower = state; + emit updateStateLower(state != 0); }); @@ -434,10 +436,8 @@ bool ViewToolbar::showUnpaintableChunk() return static_cast(_texture_secondary_tool[0])->GET(unpaintable_chunk_index)->checkbox()->isChecked() && current_mode == editing_mode::paint; } -void ViewToolbar::nextFlattenMode(MapView* mapView) +void ViewToolbar::nextFlattenMode() { - mapView->getFlattenTool()->_flatten_mode.next(); - CheckBoxAction* _raise_option = static_cast(_flatten_secondary_tool[0])->GET(raise_index); CheckBoxAction* _lower_option = static_cast(_flatten_secondary_tool[0])->GET(lower_index); diff --git a/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.hpp b/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.hpp index 314fdabf..e7523bb3 100755 --- a/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.hpp +++ b/src/noggit/ui/tools/ViewToolbar/Ui/ViewToolbar.hpp @@ -8,17 +8,20 @@ #include #include -#include #include -#include -#include + +class MapView; namespace Noggit { + struct BoolToggleProperty; + namespace Ui::Tools::ViewToolbar::Ui { class ViewToolbar: public QToolBar { + Q_OBJECT + public: ViewToolbar(MapView* mapView); ViewToolbar(MapView* mapView, ViewToolbar* tb); @@ -34,7 +37,7 @@ namespace Noggit /*secondary left tool*/ QVector _flatten_secondary_tool; - void nextFlattenMode(MapView* mapView); + void nextFlattenMode(); QVector _texture_secondary_tool; bool showUnpaintableChunk(); @@ -46,6 +49,10 @@ namespace Noggit bool drawWireframeSphereLight(); float getAlphaSphereLight(); + signals: + void updateStateRaise(bool newState); + void updateStateLower(bool newState); + private: QActionGroup _tool_group; editing_mode current_mode; diff --git a/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp b/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp index d1cd2882..7a0fb93e 100755 --- a/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp +++ b/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp @@ -289,7 +289,7 @@ void ViewportGizmo::handleTransformGizmo(MapView* map_view if (map_view) { - map_view->updateRotationEditor(); + emit map_view->rotationChanged(); } if (_world) diff --git a/src/noggit/ui/widgets/LightViewWidget.cpp b/src/noggit/ui/widgets/LightViewWidget.cpp index ebd02bbf..6bd4b956 100644 --- a/src/noggit/ui/widgets/LightViewWidget.cpp +++ b/src/noggit/ui/widgets/LightViewWidget.cpp @@ -1,4 +1,5 @@ #include "LightViewWidget.h" +#include LightViewWidget::LightViewWidget(QWidget* parent) : QWidget(parent) diff --git a/src/noggit/ui/windows/noggitWindow/NoggitWindow.cpp b/src/noggit/ui/windows/noggitWindow/NoggitWindow.cpp index 4d4bcf2e..1a26980c 100755 --- a/src/noggit/ui/windows/noggitWindow/NoggitWindow.cpp +++ b/src/noggit/ui/windows/noggitWindow/NoggitWindow.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include