From 36080a490a6b81795d559a1911857e94471bb7af Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 26 Oct 2024 09:42:19 +0300 Subject: [PATCH 1/2] Editor: Sprite Editor handles issues #851 --- engine/includes/components/actor.h | 6 + engine/includes/editor/editortool.h | 2 +- .../converter/textureconverter.cpp | 2 +- .../texturetools/converter/textureconverter.h | 8 +- .../texturetools/editor/spritecontroller.cpp | 293 +++--------------- .../texturetools/editor/spritecontroller.h | 30 +- .../{textureedit.cpp => spriteedit.cpp} | 46 +-- .../editor/{textureedit.h => spriteedit.h} | 18 +- .../editor/{textureedit.ui => spriteedit.ui} | 4 +- .../texturetools/editor/tools/spritetool.cpp | 260 ++++++++++++++++ .../texturetools/editor/tools/spritetool.h | 36 +++ modules/editor/texturetools/texturetools.cpp | 8 +- .../uikit/includes/editor/widgetcontroller.h | 2 - modules/uikit/src/editor/widgetcontroller.cpp | 22 +- .../objecthierarchy/objecthierarchymodel.cpp | 4 +- 15 files changed, 423 insertions(+), 318 deletions(-) rename modules/editor/texturetools/editor/{textureedit.cpp => spriteedit.cpp} (78%) rename modules/editor/texturetools/editor/{textureedit.h => spriteedit.h} (79%) rename modules/editor/texturetools/editor/{textureedit.ui => spriteedit.ui} (97%) create mode 100644 modules/editor/texturetools/editor/tools/spritetool.cpp create mode 100644 modules/editor/texturetools/editor/tools/spritetool.h diff --git a/engine/includes/components/actor.h b/engine/includes/components/actor.h index 329fc4d8a..1ccc9d777 100644 --- a/engine/includes/components/actor.h +++ b/engine/includes/components/actor.h @@ -46,6 +46,12 @@ class ENGINE_EXPORT Actor : public Object { World *world() const; Component *component(const std::string type); + + template + T *getComponent() { + return static_cast(component(T::metaClass()->name())); + } + Component *componentInChild(const std::string type); std::list componentsInChild(const std::string type); diff --git a/engine/includes/editor/editortool.h b/engine/includes/editor/editortool.h index 50caf57ee..e5353b630 100644 --- a/engine/includes/editor/editortool.h +++ b/engine/includes/editor/editortool.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include class Actor; diff --git a/modules/editor/texturetools/converter/textureconverter.cpp b/modules/editor/texturetools/converter/textureconverter.cpp index e2bfefb42..be4d0667d 100644 --- a/modules/editor/texturetools/converter/textureconverter.cpp +++ b/modules/editor/texturetools/converter/textureconverter.cpp @@ -102,7 +102,7 @@ std::string TextureImportSettings::findFreeElementName(const std::string &name) return "Element"; } -const TextureImportSettings::ElementMap &TextureImportSettings::elements() const { +TextureImportSettings::ElementMap &TextureImportSettings::elements() { return m_elements; } diff --git a/modules/editor/texturetools/converter/textureconverter.h b/modules/editor/texturetools/converter/textureconverter.h index a0c90788c..0e4700423 100644 --- a/modules/editor/texturetools/converter/textureconverter.h +++ b/modules/editor/texturetools/converter/textureconverter.h @@ -43,9 +43,15 @@ class TextureImportSettings : public AssetConverterSettings { Vector2 m_min; Vector2 m_max; + Vector2 m_saveMin; + Vector2 m_saveMax; + Vector2 m_borderMin; Vector2 m_borderMax; + Vector2 m_saveBorderMin; + Vector2 m_saveBorderMax; + Vector2 m_pivot = Vector2(0.5f); }; typedef std::map ElementMap; @@ -65,7 +71,7 @@ class TextureImportSettings : public AssetConverterSettings { bool lod() const; void setLod(bool lod); - const ElementMap &elements() const; + ElementMap &elements(); std::string setElement(const Element &element, const std::string &key = std::string()); void removeElement(const std::string &key); diff --git a/modules/editor/texturetools/editor/spritecontroller.cpp b/modules/editor/texturetools/editor/spritecontroller.cpp index 2d25cac68..4d9b78a69 100644 --- a/modules/editor/texturetools/editor/spritecontroller.cpp +++ b/modules/editor/texturetools/editor/spritecontroller.cpp @@ -15,10 +15,10 @@ SpriteController::SpriteController(QWidget *view) : CameraController(), m_settings(nullptr), + m_spriteTool(new SpriteTool(this, m_dummy)), m_width(0), m_height(0), - m_drag(false), - m_borderAxes(0) { + m_drag(false) { } @@ -34,271 +34,66 @@ void SpriteController::setSize(uint32_t width, uint32_t height) { } } -void SpriteController::selectElements(const std::list &list) { - m_list = list; +bool SpriteController::isSelected(const std::string &key) const { + return std::find(m_selected.begin(), m_selected.end(), key) != m_selected.end(); +} - m_elementList.clear(); - if(m_settings) { - auto elements = m_settings->elements(); - for(auto &it : m_list) { - auto result = elements.find(it); - if(result != elements.end()) { - m_elementList.push_back(result->second); - } - } - } +void SpriteController::selectElements(const std::list &list) { + m_selected = list; - if(m_list.empty()) { + if(m_selected.empty()) { emit selectionChanged(QString()); } else { - emit selectionChanged(m_list.front().c_str()); + emit selectionChanged(m_selected.front().c_str()); } } const std::list &SpriteController::selectedElements() { - return m_list; + return m_selected; } -void SpriteController::update() { - Vector4 pos(Input::mousePosition()); - Vector3 world = m_activeCamera->unproject(Vector3(pos.z, pos.w, 0.0f)); - world.x = CLAMP(world.x, 0.0f, m_width); - world.y = CLAMP(world.y, 0.0f, m_height); - - Handles::s_Mouse = Vector2(pos.x, pos.y); - Handles::s_Screen = m_screenSize; - - CameraController::update(); - - if(Input::isKeyDown(Input::KEY_DELETE)) { - if(!m_list.empty()) { - UndoManager::instance()->push(new DestroySprites(m_list, this)); - } - } - - if(m_settings && Input::isMouseButtonDown(Input::MOUSE_LEFT)) { - m_startPoint = m_currentPoint = world; - - if(Handles::s_Axes == 0) { - std::string key; - for(auto &it : m_settings->elements()) { - if(it.second.m_min.x < world.x && it.second.m_max.x > world.x && - it.second.m_min.y < world.y && it.second.m_max.y > world.y) { - key = it.first; - break; - } - } - - if(key.empty()) { - selectElements({}); - } else { - UndoManager::instance()->push(new SelectSprites({key}, this)); - } - } - - if(!m_elementList.empty()) { - TextureImportSettings::Element element = m_elementList.front(); - - m_min = element.m_min; - m_max = element.m_max; - - m_borderMin = element.m_borderMin; - m_borderMax = element.m_borderMax; - } +void SpriteController::setDrag(bool drag) { + if(drag) { + m_spriteTool->beginControl(); } + m_drag = drag; +} - if(Input::isMouseButtonUp(Input::MOUSE_LEFT)) { - if(m_drag && m_settings && !m_list.empty()) { - UndoManager::instance()->push(new UpdateSprites(m_list, m_elementList, this)); - } - m_drag = false; - - if(m_elementList.empty() && m_currentPoint != m_startPoint) { - TextureImportSettings::Element element; - element.m_min = Vector2(MIN(m_startPoint.x, m_currentPoint.x), MIN(m_startPoint.y, m_currentPoint.y)); - element.m_max = Vector2(MAX(m_startPoint.x, m_currentPoint.x), MAX(m_startPoint.y, m_currentPoint.y)); - - UndoManager::instance()->push(new CreateSprite(element, this)); - } - m_startPoint = m_currentPoint; - } - - if(m_settings && Input::isMouseButton(Input::MOUSE_LEFT)) { - m_currentPoint = world; - - if(!m_elementList.empty()) { - Vector2 delta(int(m_currentPoint.x - m_startPoint.x), int(m_currentPoint.y - m_startPoint.y)); - - if(delta.length() > 1.0f && !m_drag) { - m_drag = true; - } - - if(m_drag) { - Vector2 min(m_min); - Vector2 max(m_max); - - bool useBorder = - (m_borderAxes == (Handles::POINT_L | Handles::POINT_T) && m_borderAxes != Handles::s_Axes) || - (m_borderAxes == (Handles::POINT_L | Handles::POINT_B) && m_borderAxes != Handles::s_Axes) || - (m_borderAxes == (Handles::POINT_R | Handles::POINT_T) && m_borderAxes != Handles::s_Axes) || - (m_borderAxes == (Handles::POINT_R | Handles::POINT_B) && m_borderAxes != Handles::s_Axes) || - m_borderAxes == Handles::POINT_L || m_borderAxes == Handles::POINT_R || - m_borderAxes == Handles::POINT_T || m_borderAxes == Handles::POINT_B; - - uint8_t axes = Handles::s_Axes; - if(useBorder) { - axes = m_borderAxes; - min = m_borderMin; - max = m_borderMax; - } - - if(axes == (Handles::POINT_T | Handles::POINT_B | Handles::POINT_L | Handles::POINT_R)) { - min += delta; - max += delta; - } else if(axes == (Handles::POINT_T | Handles::POINT_R)) { - max += useBorder ? -delta : delta; - } else if(axes == (Handles::POINT_T | Handles::POINT_L)) { - min.x += delta.x; - max.y += useBorder ? -delta.y : delta.y; - } else if(axes == (Handles::POINT_B | Handles::POINT_R)) { - max.x += useBorder ? -delta.x : delta.x; - min.y += delta.y; - } else if(axes == (Handles::POINT_B | Handles::POINT_L)) { - min += delta; - } else if(axes == Handles::POINT_T) { - max.y += useBorder ? -delta.y : delta.y; - } else if(axes == Handles::POINT_B) { - min.y += delta.y; - } else if(axes == Handles::POINT_L) { - min.x += delta.x; - } else if(axes == Handles::POINT_R) { - max.x += useBorder ? -delta.x : delta.x; - } - - TextureImportSettings::Element &element = m_elementList.front(); - - if(useBorder) { - Vector2 size(element.m_max - element.m_min); +Vector3 SpriteController::world() const { + return m_world; +} - element.m_borderMin.x = CLAMP(min.x, 0.0f, size.x/* - max.x*/); - element.m_borderMin.y = CLAMP(min.y, 0.0f, size.y - max.y); +void SpriteController::update() { + CameraController::update(); - element.m_borderMax.x = CLAMP(max.x, 0.0f, size.x - min.x); - element.m_borderMax.y = CLAMP(max.y, 0.0f, size.y/* - min.y*/); - } else { - element.m_min = min; - element.m_max = max; - } - } - } + if(m_settings == nullptr) { + return; } - if(m_drag && m_settings && Input::isMouseButtonDown(Input::MOUSE_RIGHT)) { - if(!m_elementList.empty()) { - TextureImportSettings::Element &element = m_elementList.front(); - - element.m_min = m_min; - element.m_max = m_max; - - m_currentPoint = m_startPoint; - m_drag = false; - } + if(m_spriteTool->cursor() != Qt::ArrowCursor) { + emit setCursor(QCursor(m_spriteTool->cursor())); + } else { + emit unsetCursor(); } } void SpriteController::drawHandles() { - if(m_settings) { - Qt::CursorShape shape = Qt::ArrowCursor; - - for(auto &it : m_settings->elements()) { - if(find(m_list.begin(), m_list.end(), it.first) == m_list.end()) { - AABBox rect; - rect.setBox(Vector3(it.second.m_min, 0.0f), Vector3(it.second.m_max, 0.0f)); - - Gizmos::drawRectangle(rect.center, Vector2(rect.extent.x * 2.0f, rect.extent.y * 2.0f), Handles::s_Normal); - } - } - - for(auto &it : m_elementList) { - AABBox rect; - rect.setBox(Vector3(it.m_min, 0.0f), Vector3(it.m_max, 0.0f)); - - AABBox bb; - bb.setBox(Vector3(it.m_min.x + it.m_borderMin.x, it.m_min.y + it.m_borderMin.y, 0.0f), - Vector3(it.m_max.x - it.m_borderMax.x, it.m_max.y - it.m_borderMax.y, 0.0f)); + CameraController::drawHandles(); - int axis; - - Vector3 tl0(it.m_min.x, it.m_max.y - it.m_borderMax.y, 0.0f); - Vector3 tr0(it.m_max.x, it.m_max.y - it.m_borderMax.y, 0.0f); - Vector3 bl0(it.m_min.x, it.m_min.y + it.m_borderMin.y, 0.0f); - Vector3 br0(it.m_max.x, it.m_min.y + it.m_borderMin.y, 0.0f); - - Vector3 tl1(it.m_min.x + it.m_borderMin.x, it.m_max.y, 0.0f); - Vector3 tr1(it.m_max.x - it.m_borderMax.x, it.m_max.y, 0.0f); - Vector3 bl1(it.m_min.x + it.m_borderMin.x, it.m_min.y, 0.0f); - Vector3 br1(it.m_max.x - it.m_borderMax.x, it.m_min.y, 0.0f); - - Gizmos::drawLines({tr0, tl0, br0, bl0, tr1, br1, tl1, bl1}, {0, 1, 2, 3, 4, 5, 6, 7}, Handles::s_yColor); - - Handles::s_Color = Handles::s_yColor; - Handles::rectTool(bb.center, bb.extent * 2.0f, axis, true, m_drag); - - if(!m_drag) { - m_borderAxes = Handles::s_Axes; - } - - Handles::s_Color = Handles::s_zColor; - Handles::rectTool(rect.center, rect.extent * 2.0f, axis, false, m_drag); - - bool useBorder = - m_borderAxes == Handles::POINT_L || m_borderAxes == Handles::POINT_R || - m_borderAxes == Handles::POINT_T || m_borderAxes == Handles::POINT_B || - m_borderAxes == (Handles::POINT_T | Handles::POINT_R) || - m_borderAxes == (Handles::POINT_T | Handles::POINT_L) || - m_borderAxes == (Handles::POINT_B | Handles::POINT_R) || - m_borderAxes == (Handles::POINT_B | Handles::POINT_L); - - uint8_t axes = Handles::s_Axes; - if(useBorder) { - axes = m_borderAxes; - } + Vector4 pos(Input::mousePosition()); + Handles::s_Mouse = Vector2(pos.z, pos.w); + Handles::s_Screen = m_screenSize; - if(axes == (Handles::POINT_T | Handles::POINT_B | Handles::POINT_L | Handles::POINT_R)) { - shape = Qt::SizeAllCursor; - } else if(axes == (Handles::POINT_T | Handles::POINT_R)) { - shape = Qt::SizeBDiagCursor; - } else if(axes == (Handles::POINT_T | Handles::POINT_L)) { - shape = Qt::SizeFDiagCursor; - } else if(axes == (Handles::POINT_B | Handles::POINT_R)) { - shape = Qt::SizeFDiagCursor; - } else if(axes == (Handles::POINT_B | Handles::POINT_L)) { - shape = Qt::SizeBDiagCursor; - } else if(axes == Handles::POINT_T || axes == Handles::POINT_B) { - shape = Qt::SizeVerCursor; - } else if(axes == Handles::POINT_L || axes == Handles::POINT_R) { - shape = Qt::SizeHorCursor; - } - } + m_world = m_activeCamera->unproject(Vector3(pos.z, pos.w, 0.0f)); + m_world.x = CLAMP(m_world.x, 0.0f, m_width); + m_world.y = CLAMP(m_world.y, 0.0f, m_height); - if(m_list.empty() && m_currentPoint != m_startPoint) { - AABBox bb; - bb.setBox(m_startPoint, m_currentPoint); - Gizmos::drawRectangle(bb.center, Vector2(bb.extent.x * 2.0f, bb.extent.y * 2.0f), Handles::s_yColor); - } - Handles::s_Color = Handles::s_Normal; - - if(shape != Qt::ArrowCursor) { - emit setCursor(QCursor(shape)); - } else if(!m_drag) { - emit unsetCursor(); - } - } + m_spriteTool->update(false, true, Input::isKey(Input::KEY_LEFT_CONTROL)); } -SelectSprites::SelectSprites(const std::list &elements, SpriteController *ctrl, const QString &name, QUndoCommand *group) : +SelectSprites::SelectSprites(const std::list &list, SpriteController *ctrl, const QString &name, QUndoCommand *group) : UndoSprite(ctrl, name, group), - m_list(elements) { + m_list(list) { } void SelectSprites::undo() { redo(); @@ -329,15 +124,15 @@ void CreateSprite::redo() { } } -DestroySprites::DestroySprites(const std::list &elements, SpriteController *ctrl, const QString &name, QUndoCommand *group) : +DestroySprites::DestroySprites(SpriteController *ctrl, const QString &name, QUndoCommand *group) : UndoSprite(ctrl, name, group), - m_list(elements) { + m_list(ctrl->selectedElements()) { } void DestroySprites::undo() { TextureImportSettings *settings = m_controller->settings(); if(settings) { for(int32_t i = 0; i < m_elements.size(); i++) { - settings->setElement(*next(m_elements.begin(), i), *next(m_list.begin(), i)); + settings->setElement(*std::next(m_elements.begin(), i), *std::next(m_list.begin(), i)); } m_controller->selectElements(m_list); } @@ -357,10 +152,10 @@ void DestroySprites::redo() { } } -UpdateSprites::UpdateSprites(const std::list &elements, const std::list &list, SpriteController *ctrl, const QString &name, QUndoCommand *group) : - UndoSprite(ctrl, name, group), - m_list(elements), - m_elements(list) { +UpdateSprites::UpdateSprites(const std::list &list, SpriteController *ctrl, const QString &name, QUndoCommand *group) : + UndoSprite(ctrl, name, group), + m_list(ctrl->selectedElements()), + m_elements(list) { } void UpdateSprites::undo() { redo(); @@ -376,7 +171,7 @@ void UpdateSprites::redo() { TextureImportSettings::Element back = element->second; temp.push_back(back); } - settings->setElement(*next(m_elements.begin(), i), *next(m_list.begin(), i)); + settings->setElement(*std::next(m_elements.begin(), i), *std::next(m_list.begin(), i)); } m_elements = temp; m_controller->selectElements(m_list); diff --git a/modules/editor/texturetools/editor/spritecontroller.h b/modules/editor/texturetools/editor/spritecontroller.h index fdfaadf9d..c0e3a892a 100644 --- a/modules/editor/texturetools/editor/spritecontroller.h +++ b/modules/editor/texturetools/editor/spritecontroller.h @@ -6,6 +6,8 @@ #include "../converter/textureconverter.h" +#include "tools/spritetool.h" + class SpriteController : public CameraController { Q_OBJECT @@ -16,10 +18,18 @@ class SpriteController : public CameraController { void setSettings(TextureImportSettings *settings) { m_settings = settings; } void setSize(uint32_t width, uint32_t height); + uint32_t width() const { return m_width; } + uint32_t height() const { return m_height; } + bool isSelected(const std::string &key) const; void selectElements(const std::list &list); const std::list &selectedElements(); + bool isDrag() const { return m_drag; } + void setDrag(bool drag); + + Vector3 world() const; + signals: void selectionChanged(const QString &key); @@ -29,24 +39,18 @@ class SpriteController : public CameraController { void drawHandles() override; private: - std::list m_list; - std::list m_elementList; + std::list m_selected; - Vector3 m_startPoint; - Vector3 m_currentPoint; + EditorTool::SelectList m_dummy; TextureImportSettings *m_settings; - Vector2 m_min; - Vector2 m_max; - - Vector2 m_borderMin; - Vector2 m_borderMax; + SpriteTool *m_spriteTool; uint32_t m_width; uint32_t m_height; - uint8_t m_borderAxes; + Vector3 m_world; bool m_drag; }; @@ -66,7 +70,7 @@ class UndoSprite : public UndoCommand { class SelectSprites : public UndoSprite { public: - SelectSprites(const std::list &elements, SpriteController *ctrl, const QString &name = QObject::tr("Select Sprite Elements"), QUndoCommand *group = nullptr); + SelectSprites(const std::list &list, SpriteController *ctrl, const QString &name = QObject::tr("Select Sprite Elements"), QUndoCommand *group = nullptr); void undo() override; void redo() override; @@ -90,7 +94,7 @@ class CreateSprite : public UndoSprite { class DestroySprites : public UndoSprite { public: - DestroySprites(const std::list &elements, SpriteController *ctrl, const QString &name = QObject::tr("Destroy Sprite Elements"), QUndoCommand *group = nullptr); + DestroySprites(SpriteController *ctrl, const QString &name = QObject::tr("Destroy Sprite Elements"), QUndoCommand *group = nullptr); void undo() override; void redo() override; @@ -103,7 +107,7 @@ class DestroySprites : public UndoSprite { class UpdateSprites : public UndoSprite { public: - UpdateSprites(const std::list &elements, const std::list &list, SpriteController *ctrl, const QString &name = QObject::tr("Update Sprite Elements"), QUndoCommand *group = nullptr); + UpdateSprites(const std::list &list, SpriteController *ctrl, const QString &name = QObject::tr("Update Sprite Elements"), QUndoCommand *group = nullptr); void undo() override; void redo() override; diff --git a/modules/editor/texturetools/editor/textureedit.cpp b/modules/editor/texturetools/editor/spriteedit.cpp similarity index 78% rename from modules/editor/texturetools/editor/textureedit.cpp rename to modules/editor/texturetools/editor/spriteedit.cpp index 5ca1743a0..8af0ca71e 100644 --- a/modules/editor/texturetools/editor/textureedit.cpp +++ b/modules/editor/texturetools/editor/spriteedit.cpp @@ -1,5 +1,5 @@ -#include "textureedit.h" -#include "ui_textureedit.h" +#include "spriteedit.h" +#include "ui_spriteedit.h" #include #include @@ -20,13 +20,13 @@ namespace { const char *gSpriteRender("SpriteRender"); }; -TextureEdit::TextureEdit() : - ui(new Ui::TextureEdit), +SpriteEdit::SpriteEdit() : + ui(new Ui::SpriteEdit), m_resource(nullptr), m_render(nullptr), m_converter(new TextureConverter), - m_graph(Engine::objectCreate("World")), - m_scene(Engine::objectCreate("Scene", m_graph)), + m_world(Engine::objectCreate("World")), + m_scene(Engine::objectCreate("Scene", m_world)), m_controller(new SpriteController(this)) { ui->setupUi(this); @@ -35,7 +35,7 @@ TextureEdit::TextureEdit() : m_controller->blockRotations(true); ui->viewport->setController(m_controller); - ui->viewport->setWorld(m_graph); + ui->viewport->setWorld(m_world); ui->viewport->init(); // must be called after all options set ui->viewport->setGridEnabled(false); @@ -49,39 +49,41 @@ TextureEdit::TextureEdit() : } Actor *object = Engine::composeActor(gSpriteRender, gSpriteRender, m_scene); - m_render = static_cast(object->component(gSpriteRender)); + m_render = object->getComponent(); m_render->setLayer(2); object = Engine::composeActor(gSpriteRender, "CheckerBoard", m_scene); - m_checker = static_cast(object->component(gSpriteRender)); + m_checker = object->getComponent(); m_checker->setMaterial(Engine::loadResource(".embedded/checkerboard.shader")); setAcceptDrops(true); setMouseTracking(true); } -TextureEdit::~TextureEdit() { +SpriteEdit::~SpriteEdit() { if(m_resource) { m_resource->unsubscribe(this); } + delete m_world; + delete ui; } -bool TextureEdit::isModified() const { +bool SpriteEdit::isModified() const { if(!m_settings.isEmpty()) { return m_settings.first()->isModified(); } return false; } -void TextureEdit::loadAsset(AssetConverterSettings *settings) { +void SpriteEdit::loadAsset(AssetConverterSettings *settings) { if(m_settings.contains(settings)) { return; } if(!m_settings.isEmpty()) { - disconnect(m_settings.first(), &AssetConverterSettings::updated, this, &TextureEdit::onUpdateTemplate); + disconnect(m_settings.first(), &AssetConverterSettings::updated, this, &SpriteEdit::onUpdateTemplate); } AssetEditor::loadAsset(settings); @@ -91,7 +93,7 @@ void TextureEdit::loadAsset(AssetConverterSettings *settings) { m_resource = Engine::loadResource(qPrintable(settings->destination())); if(m_resource) { - m_resource->subscribe(&TextureEdit::resourceUpdated, this); + m_resource->subscribe(&SpriteEdit::resourceUpdated, this); } Sprite *sprite = dynamic_cast(m_resource); @@ -122,24 +124,24 @@ void TextureEdit::loadAsset(AssetConverterSettings *settings) { ui->widget->setSettings(static_cast(m_settings.first())); - connect(m_settings.first(), &AssetConverterSettings::updated, this, &TextureEdit::onUpdateTemplate); + connect(m_settings.first(), &AssetConverterSettings::updated, this, &SpriteEdit::onUpdateTemplate); } -void TextureEdit::saveAsset(const QString &) { +void SpriteEdit::saveAsset(const QString &) { m_settings.first()->saveSettings(); } -QStringList TextureEdit::suffixes() const { +QStringList SpriteEdit::suffixes() const { return static_cast(m_converter)->suffixes(); } -void TextureEdit::onUpdateTemplate() { +void SpriteEdit::onUpdateTemplate() { if(!m_settings.isEmpty()) { m_converter->convertTexture(m_render->texture(), static_cast(m_settings.first())); } } -void TextureEdit::resizeEvent(QResizeEvent *event) { +void SpriteEdit::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); QRect r = ui->widget->geometry(); @@ -148,9 +150,9 @@ void TextureEdit::resizeEvent(QResizeEvent *event) { ui->widget->setGeometry(r); } -void TextureEdit::resourceUpdated(int state, void *ptr) { +void SpriteEdit::resourceUpdated(int state, void *ptr) { if(state == Resource::ToBeDeleted) { - TextureEdit *p = static_cast(ptr); + SpriteEdit *p = static_cast(ptr); p->m_render->actor()->setEnabled(false); p->m_resource = nullptr; @@ -158,7 +160,7 @@ void TextureEdit::resourceUpdated(int state, void *ptr) { } } -void TextureEdit::changeEvent(QEvent *event) { +void SpriteEdit::changeEvent(QEvent *event) { if(event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } diff --git a/modules/editor/texturetools/editor/textureedit.h b/modules/editor/texturetools/editor/spriteedit.h similarity index 79% rename from modules/editor/texturetools/editor/textureedit.h rename to modules/editor/texturetools/editor/spriteedit.h index ed51770e9..39c83709d 100644 --- a/modules/editor/texturetools/editor/textureedit.h +++ b/modules/editor/texturetools/editor/spriteedit.h @@ -1,5 +1,5 @@ -#ifndef TEXTUREEDIT_H -#define TEXTUREEDIT_H +#ifndef SPRITEEDIT_H +#define SPRITEEDIT_H #include @@ -11,15 +11,15 @@ class TextureConverter; class SpriteController; namespace Ui { - class TextureEdit; + class SpriteEdit; } -class TextureEdit : public AssetEditor { +class SpriteEdit : public AssetEditor { Q_OBJECT public: - TextureEdit(); - ~TextureEdit(); + SpriteEdit(); + ~SpriteEdit(); private: void loadAsset(AssetConverterSettings *settings) override; @@ -36,7 +36,7 @@ class TextureEdit : public AssetEditor { static void resourceUpdated(int state, void *ptr); - Ui::TextureEdit *ui; + Ui::SpriteEdit *ui; Resource *m_resource; @@ -45,7 +45,7 @@ class TextureEdit : public AssetEditor { TextureConverter *m_converter; - World *m_graph; + World *m_world; Scene *m_scene; @@ -56,4 +56,4 @@ private slots: }; -#endif // TEXTUREEDIT_H +#endif // SPRITEEDIT_H diff --git a/modules/editor/texturetools/editor/textureedit.ui b/modules/editor/texturetools/editor/spriteedit.ui similarity index 97% rename from modules/editor/texturetools/editor/textureedit.ui rename to modules/editor/texturetools/editor/spriteedit.ui index fc509cb02..d637d4501 100644 --- a/modules/editor/texturetools/editor/textureedit.ui +++ b/modules/editor/texturetools/editor/spriteedit.ui @@ -1,7 +1,7 @@ - TextureEdit - + SpriteEdit + 0 diff --git a/modules/editor/texturetools/editor/tools/spritetool.cpp b/modules/editor/texturetools/editor/tools/spritetool.cpp new file mode 100644 index 000000000..80dcf4319 --- /dev/null +++ b/modules/editor/texturetools/editor/tools/spritetool.cpp @@ -0,0 +1,260 @@ +#include "spritetool.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../spritecontroller.h" + +SpriteTool::SpriteTool(SpriteController *controller, SelectList &selection) : + EditorTool(selection), + m_controller(controller), + m_borderAxes(0), + m_useBorder(false) { + +} + +void SpriteTool::beginControl() { + m_savedPoint = m_currentPoint; + + TextureImportSettings *settings = m_controller->settings(); + for(auto &it : settings->elements()) { + it.second.m_saveBorderMin = it.second.m_borderMin; + it.second.m_saveBorderMax = it.second.m_borderMax; + + it.second.m_saveMin = it.second.m_min; + it.second.m_saveMax = it.second.m_max; + } + + m_useBorder = + (m_borderAxes == (Handles::POINT_L | Handles::POINT_T)) || + (m_borderAxes == (Handles::POINT_L | Handles::POINT_B)) || + (m_borderAxes == (Handles::POINT_R | Handles::POINT_T)) || + (m_borderAxes == (Handles::POINT_R | Handles::POINT_B)) || + m_borderAxes == Handles::POINT_L || m_borderAxes == Handles::POINT_R || + m_borderAxes == Handles::POINT_T || m_borderAxes == Handles::POINT_B; +} + +void SpriteTool::cancelControl() { + TextureImportSettings *settings = m_controller->settings(); + for(auto &it : settings->elements()) { + it.second.m_borderMin = it.second.m_saveBorderMin; + it.second.m_borderMax = it.second.m_saveBorderMax; + + it.second.m_min = it.second.m_saveMin; + it.second.m_max = it.second.m_saveMax; + } +} + +void SpriteTool::update(bool pivot, bool local, bool snap) { + TextureImportSettings *settings = m_controller->settings(); + + bool isDrag = m_controller->isDrag(); + Qt::CursorShape shape = Qt::ArrowCursor; + + m_currentPoint = m_controller->world(); + + std::list elementList; + + const std::list &selected(m_controller->selectedElements()); + for(auto &it : settings->elements()) { + AABBox rect; + rect.setBox(Vector3(it.second.m_min, 0.0f), Vector3(it.second.m_max, 0.0f)); + + if(m_controller->isSelected(it.first)) { + Vector3 tl0(it.second.m_min.x, it.second.m_max.y - it.second.m_borderMax.y, 0.0f); + Vector3 tr0(it.second.m_max.x, it.second.m_max.y - it.second.m_borderMax.y, 0.0f); + Vector3 bl0(it.second.m_min.x, it.second.m_min.y + it.second.m_borderMin.y, 0.0f); + Vector3 br0(it.second.m_max.x, it.second.m_min.y + it.second.m_borderMin.y, 0.0f); + + Vector3 tl1(it.second.m_min.x + it.second.m_borderMin.x, it.second.m_max.y, 0.0f); + Vector3 tr1(it.second.m_max.x - it.second.m_borderMax.x, it.second.m_max.y, 0.0f); + Vector3 bl1(it.second.m_min.x + it.second.m_borderMin.x, it.second.m_min.y, 0.0f); + Vector3 br1(it.second.m_max.x - it.second.m_borderMax.x, it.second.m_min.y, 0.0f); + + Gizmos::drawLines({tr0, tl0, br0, bl0, tr1, br1, tl1, bl1}, {0, 1, 2, 3, 4, 5, 6, 7}, Handles::s_yColor); + + AABBox sub; + sub.setBox(Vector3(it.second.m_min.x + it.second.m_borderMin.x, it.second.m_min.y + it.second.m_borderMin.y, 0.0f), + Vector3(it.second.m_max.x - it.second.m_borderMax.x, it.second.m_max.y - it.second.m_borderMax.y, 0.0f)); + + int axis; + + if(!isDrag) { + m_borderAxes = 0; + } + + Handles::s_Color = Handles::s_yColor; + Handles::rectTool(sub.center, sub.extent * 2.0f, axis, true, isDrag); + + if(!isDrag) { + m_borderAxes = Handles::s_Axes; + } + + Handles::s_Color = Handles::s_zColor; + m_currentPoint = Handles::rectTool(rect.center, rect.extent * 2.0f, axis, false, isDrag); + Handles::s_Color = Handles::s_Normal; + + uint8_t axes = Handles::s_Axes; + if(m_useBorder) { + axes = m_borderAxes; + } + + if(isDrag) { + Vector3 delta(m_currentPoint - m_savedPoint); + + Vector2 min(it.second.m_min); + Vector2 max(it.second.m_max); + + if(m_useBorder) { + min = it.second.m_borderMin; + max = it.second.m_borderMax; + } + + if(axes == (Handles::POINT_T | Handles::POINT_B | Handles::POINT_L | Handles::POINT_R)) { + min += delta; + max += delta; + } else if(axes == (Handles::POINT_T | Handles::POINT_R)) { + max += m_useBorder ? -delta : delta; + } else if(axes == (Handles::POINT_T | Handles::POINT_L)) { + min.x += delta.x; + max.y += m_useBorder ? -delta.y : delta.y; + } else if(axes == (Handles::POINT_B | Handles::POINT_R)) { + max.x += m_useBorder ? -delta.x : delta.x; + min.y += delta.y; + } else if(axes == (Handles::POINT_B | Handles::POINT_L)) { + min += delta; + } else if(axes == Handles::POINT_T) { + max.y += m_useBorder ? -delta.y : delta.y; + } else if(axes == Handles::POINT_B) { + min.y += delta.y; + } else if(axes == Handles::POINT_L) { + min.x += delta.x; + } else if(axes == Handles::POINT_R) { + max.x += m_useBorder ? -delta.x : delta.x; + } + + if(m_useBorder) { + Vector2 size(it.second.m_max - it.second.m_min); + + it.second.m_borderMin.x = CLAMP(min.x, 0.0f, size.x); + it.second.m_borderMin.y = CLAMP(min.y, 0.0f, size.y - max.y); + + it.second.m_borderMax.x = CLAMP(max.x, 0.0f, size.x - min.x); + it.second.m_borderMax.y = CLAMP(max.y, 0.0f, size.y); + } else { + it.second.m_min.x = MAX(min.x, 0.0f); + it.second.m_min.y = MAX(min.y, 0.0f); + it.second.m_max.x = MIN(max.x, m_controller->width()); + it.second.m_max.y = MIN(max.y, m_controller->height()); + } + + m_savedPoint = m_currentPoint; + } + + if(axes == (Handles::POINT_T | Handles::POINT_B | Handles::POINT_L | Handles::POINT_R)) { + if(m_borderAxes != 0 && m_borderAxes != (Handles::POINT_T | Handles::POINT_B | Handles::POINT_L | Handles::POINT_R)) { + axes = m_borderAxes; + } + shape = Qt::SizeAllCursor; + } + + if(axes == (Handles::POINT_T | Handles::POINT_R)) { + shape = Qt::SizeBDiagCursor; + } else if(axes == (Handles::POINT_T | Handles::POINT_L)) { + shape = Qt::SizeFDiagCursor; + } else if(axes == (Handles::POINT_B | Handles::POINT_R)) { + shape = Qt::SizeFDiagCursor; + } else if(axes == (Handles::POINT_B | Handles::POINT_L)) { + shape = Qt::SizeBDiagCursor; + } else if(axes == Handles::POINT_T || axes == Handles::POINT_B) { + shape = Qt::SizeVerCursor; + } else if(axes == Handles::POINT_L || axes == Handles::POINT_R) { + shape = Qt::SizeHorCursor; + } + + elementList.push_back(it.second); + } else { + Gizmos::drawRectangle(rect.center, Vector2(rect.extent.x * 2.0f, rect.extent.y * 2.0f), Handles::s_xColor); + } + } + + if(Input::isMouseButtonDown(Input::MOUSE_LEFT)) { + m_currentPoint = m_startPoint = m_controller->world(); + + if(Handles::s_Axes == 0) { + std::string key; + + Vector3 world = m_controller->world(); + for(auto &it : settings->elements()) { + if(it.second.m_min.x < world.x && it.second.m_max.x > world.x && + it.second.m_min.y < world.y && it.second.m_max.y > world.y) { + key = it.first; + break; + } + } + + if(key.empty()) { + m_controller->selectElements({}); + } else { + UndoManager::instance()->push(new SelectSprites({key}, m_controller)); + } + } else if(!isDrag) { + m_controller->setDrag(true); + } + } + + if(Input::isMouseButtonUp(Input::MOUSE_LEFT)) { + if(isDrag && !selected.empty()) { + cancelControl(); + UndoManager::instance()->push(new UpdateSprites(elementList, m_controller)); + } + + m_useBorder = false; + m_controller->setDrag(false); + + if(selected.empty() && m_currentPoint != m_startPoint) { + TextureImportSettings::Element element; + element.m_min = Vector2(MIN(m_startPoint.x, m_currentPoint.x), MIN(m_startPoint.y, m_currentPoint.y)); + element.m_max = Vector2(MAX(m_startPoint.x, m_currentPoint.x), MAX(m_startPoint.y, m_currentPoint.y)); + + UndoManager::instance()->push(new CreateSprite(element, m_controller)); + + m_startPoint = m_currentPoint; + } + } + + // Creation of sprite + if(selected.empty() && Input::isMouseButton(Input::MOUSE_LEFT) && m_currentPoint != m_startPoint) { + AABBox bb; + bb.setBox(m_startPoint, m_currentPoint); + + Gizmos::drawRectangle(bb.center, Vector2(bb.extent.x * 2.0f, bb.extent.y * 2.0f), Handles::s_yColor); + } + + if(isDrag && Input::isMouseButtonDown(Input::MOUSE_RIGHT)) { + cancelControl(); + m_useBorder = false; + m_controller->setDrag(false); + } + + if(!selected.empty() && Input::isKeyDown(Input::KEY_DELETE)) { + UndoManager::instance()->push(new DestroySprites(m_controller)); + } + + m_cursor = shape; +} + +QString SpriteTool::icon() const { + return ":/Images/editor/Transform.png"; +} + +QString SpriteTool::name() const { + return "Resize"; +} diff --git a/modules/editor/texturetools/editor/tools/spritetool.h b/modules/editor/texturetools/editor/tools/spritetool.h new file mode 100644 index 000000000..8da4626a3 --- /dev/null +++ b/modules/editor/texturetools/editor/tools/spritetool.h @@ -0,0 +1,36 @@ +#ifndef SPRITETOOL_H +#define SPRITETOOL_H + +#include + +class SpriteController; + +class SpriteTool : public EditorTool { +public: + explicit SpriteTool(SpriteController *controller, EditorTool::SelectList &selection); + + void update(bool pivot, bool local, bool snap) override; + + void beginControl() override; + void cancelControl() override; + + QString icon() const override; + QString name() const override; + +protected: + SpriteController *m_controller; + + AABBox m_savedBox; + + AABBox m_box; + + Vector3 m_startPoint; + Vector3 m_savedPoint; + Vector3 m_currentPoint; + + uint8_t m_borderAxes; + + bool m_useBorder; +}; + +#endif // SPRITETOOL_H diff --git a/modules/editor/texturetools/texturetools.cpp b/modules/editor/texturetools/texturetools.cpp index 3f29b930d..1995bd2e2 100644 --- a/modules/editor/texturetools/texturetools.cpp +++ b/modules/editor/texturetools/texturetools.cpp @@ -6,7 +6,7 @@ #include #include "converter/textureconverter.h" -#include "editor/textureedit.h" +#include "editor/spriteedit.h" static const char *meta = \ "{" @@ -16,7 +16,7 @@ static const char *meta = \ " \"author\": \"Evgeniy Prikazchikov\"," " \"objects\": {" " \"TextureConverter\": \"converter\"," -" \"TextureEdit\": \"editor\"" +" \"SpriteEdit\": \"editor\"" " }" "}"; @@ -35,8 +35,8 @@ const char *TextureTools::metaInfo() const { void *TextureTools::getObject(const char *name) { if(strcmp(name, "TextureConverter") == 0) { return new TextureConverter; - } else if(strcmp(name, "TextureEdit") == 0) { - return new TextureEdit; + } else if(strcmp(name, "SpriteEdit") == 0) { + return new SpriteEdit; } return nullptr; } diff --git a/modules/uikit/includes/editor/widgetcontroller.h b/modules/uikit/includes/editor/widgetcontroller.h index 0f9201fb8..3df83f791 100644 --- a/modules/uikit/includes/editor/widgetcontroller.h +++ b/modules/uikit/includes/editor/widgetcontroller.h @@ -52,8 +52,6 @@ public slots: Object *m_rootObject; - Widget *m_focusWidget; - WidgetTool *m_widgetTool; uint32_t m_width; diff --git a/modules/uikit/src/editor/widgetcontroller.cpp b/modules/uikit/src/editor/widgetcontroller.cpp index 925a1dc50..22d2b0ccb 100644 --- a/modules/uikit/src/editor/widgetcontroller.cpp +++ b/modules/uikit/src/editor/widgetcontroller.cpp @@ -22,7 +22,6 @@ WidgetController::WidgetController(Object *rootObject, QWidget *view) : CameraController(), m_rootObject(rootObject), - m_focusWidget(nullptr), m_widgetTool(new WidgetTool(this, m_selected)), m_width(0), m_height(0), @@ -123,7 +122,6 @@ void WidgetController::drawHandles() { if(!m_selected.empty()) { m_widgetTool->update(false, true, Input::isKey(Input::KEY_LEFT_CONTROL)); } - } void WidgetController::update() { @@ -132,14 +130,14 @@ void WidgetController::update() { CameraController::update(); - m_focusWidget = getHoverWidget(pos.x, pos.y); + Widget *focusWidget = getHoverWidget(pos.x, pos.y); if(Input::isMouseButtonUp(Input::MOUSE_LEFT)) { if(!m_drag) { std::list objects; if(!m_canceled) { - if(m_focusWidget) { - objects.push_back(m_focusWidget->actor()->uuid()); + if(focusWidget) { + objects.push_back(focusWidget->actor()->uuid()); } onSelectActor(objects, Input::isKey(Input::KEY_LEFT_CONTROL)); } else { @@ -184,14 +182,12 @@ void WidgetController::update() { setDrag(false); } - if(Input::isMouseButtonDown(Input::MOUSE_RIGHT)) { - if(m_drag) { - m_widgetTool->cancelControl(); + if(m_drag && Input::isMouseButtonDown(Input::MOUSE_RIGHT)) { + m_widgetTool->cancelControl(); - setDrag(false); - m_canceled = true; - emit sceneUpdated(); - } + setDrag(false); + m_canceled = true; + emit sceneUpdated(); } if(!m_selected.empty()) { @@ -206,7 +202,7 @@ void WidgetController::update() { if(m_widgetTool->cursor() != Qt::ArrowCursor) { emit setCursor(QCursor(m_widgetTool->cursor())); - } else if(m_focusWidget) { + } else if(focusWidget) { emit setCursor(QCursor(Qt::CrossCursor)); } else { emit unsetCursor(); diff --git a/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.cpp b/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.cpp index 6c0007ff2..d2ee3adb8 100644 --- a/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.cpp +++ b/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.cpp @@ -174,7 +174,9 @@ QModelIndex ObjectHierarchyModel::index(int row, int column, const QModelIndex & ptr = *std::next(children.begin(), row-1); } } - return createIndex(row, column, ptr->uuid()); + if(ptr) { + return createIndex(row, column, ptr->uuid()); + } } return QModelIndex(); } From 7e4e1f8317a73a5898e540b3c9136450bac73a6d Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 26 Oct 2024 15:43:29 +0300 Subject: [PATCH 2/2] Editor Tool refactoring --- engine/includes/editor/editortool.h | 36 +------- engine/src/editor/editortool.cpp | 92 +------------------ .../texturetools/editor/spritecontroller.cpp | 2 +- .../texturetools/editor/spritecontroller.h | 2 - .../texturetools/editor/tools/spritetool.cpp | 3 +- .../texturetools/editor/tools/spritetool.h | 2 +- .../uikit/includes/editor/tools/widgettool.h | 29 +++++- .../uikit/includes/editor/widgetcontroller.h | 3 +- modules/uikit/src/editor/tools/widgettool.cpp | 92 ++++++++++++++++++- modules/uikit/src/editor/widgetcontroller.cpp | 4 +- .../scenecomposer/objectcontroller.cpp | 12 +-- .../screens/scenecomposer/objectcontroller.h | 13 +-- .../screens/scenecomposer/scenecomposer.cpp | 2 +- .../screens/scenecomposer/tools/movetool.cpp | 8 +- .../screens/scenecomposer/tools/movetool.h | 2 +- .../scenecomposer/tools/resizetool.cpp | 8 +- .../screens/scenecomposer/tools/resizetool.h | 2 +- .../scenecomposer/tools/rotatetool.cpp | 8 +- .../screens/scenecomposer/tools/rotatetool.h | 2 +- .../screens/scenecomposer/tools/scaletool.cpp | 8 +- .../screens/scenecomposer/tools/scaletool.h | 2 +- .../scenecomposer/tools/selecttool.cpp | 89 +++++++++++++++++- .../screens/scenecomposer/tools/selecttool.h | 31 ++++++- 23 files changed, 279 insertions(+), 173 deletions(-) diff --git a/engine/includes/editor/editortool.h b/engine/includes/editor/editortool.h index e5353b630..dbd302aae 100644 --- a/engine/includes/editor/editortool.h +++ b/engine/includes/editor/editortool.h @@ -4,36 +4,11 @@ #include #include -#include #include -class Actor; -class Renderable; - class ENGINE_EXPORT EditorTool { public: - struct ENGINE_EXPORT Select { - Select(); - - bool operator==(const Select &left) { - return (uuid == left.uuid); - } - - uint32_t uuid; - Actor *object; - Renderable *renderable; - Vector3 position; - Vector3 scale; - Vector3 euler; - Vector3 pivot; - Quaternion quat; - AABBox box; - }; - - typedef QList SelectList; + +public: + explicit WidgetTool(WidgetController *controller); void update(bool pivot, bool local, bool snap) override; void beginControl() override; + void cancelControl() override; QString icon() const override; QString name() const override; + Vector3 objectPosition(); + AABBox objectBound(); + + const VariantList &cache() const; + protected: + VariantList m_propertiesCache; + WidgetController *m_controller; AABBox m_savedBox; diff --git a/modules/uikit/includes/editor/widgetcontroller.h b/modules/uikit/includes/editor/widgetcontroller.h index 3df83f791..ab06b19ce 100644 --- a/modules/uikit/includes/editor/widgetcontroller.h +++ b/modules/uikit/includes/editor/widgetcontroller.h @@ -19,6 +19,7 @@ class WidgetController : public CameraController { void clear(bool signal); QList selected() override; + WidgetTool::SelectList &selectList() { return m_selected; } void selectActors(const std::list &list); @@ -46,7 +47,7 @@ public slots: Widget *getHoverWidget(float x, float y); private: - EditorTool::SelectList m_selected; + WidgetTool::SelectList m_selected; std::list m_objectsList; diff --git a/modules/uikit/src/editor/tools/widgettool.cpp b/modules/uikit/src/editor/tools/widgettool.cpp index 1ad52c2f3..41823cced 100644 --- a/modules/uikit/src/editor/tools/widgettool.cpp +++ b/modules/uikit/src/editor/tools/widgettool.cpp @@ -17,8 +17,7 @@ const Vector3 cornerB(10.0f,-20.0f, 0.0f); const Vector3 cornerC(20.0f, 10.0f, 0.0f); const Vector3 cornerD(10.0f, 20.0f, 0.0f); -WidgetTool::WidgetTool(WidgetController *controller, SelectList &selection) : - EditorTool(selection), +WidgetTool::WidgetTool(WidgetController *controller) : m_controller(controller) { } @@ -26,13 +25,59 @@ WidgetTool::WidgetTool(WidgetController *controller, SelectList &selection) : void WidgetTool::beginControl() { EditorTool::beginControl(); + m_propertiesCache.clear(); + + for(auto &it : m_controller->selectList()) { + Transform *t = it.object->transform(); + it.position = t->position(); + it.scale = t->scale(); + it.euler = t->rotation(); + it.quat = t->quaternion(); + + VariantMap components; + for(auto &child : it.object->getChildren()) { + Component *component = dynamic_cast(child); + if(component) { + VariantMap properies; + const MetaObject *meta = component->metaObject(); + for(int i = 0; i < meta->propertyCount(); i++) { + MetaProperty property = meta->property(i); + properies[property.name()] = property.read(component); + } + components[std::to_string(component->uuid())] = properies; + } + } + m_propertiesCache.push_back(components); + } + + m_position = objectPosition(); m_savedWorld = m_world; } +void WidgetTool::cancelControl() { + auto cache = m_propertiesCache.begin(); + for(auto &it : m_controller->selectList()) { + VariantMap components = (*cache).toMap(); + for(auto &child : it.object->getChildren()) { + Component *component = dynamic_cast(child); + if(component) { + VariantMap properties = components[std::to_string(component->uuid())].toMap(); + const MetaObject *meta = component->metaObject(); + for(int i = 0; i < meta->propertyCount(); i++) { + MetaProperty property = meta->property(i); + property.write(component, properties[property.name()]); + } + } + } + + ++cache; + } +} + void WidgetTool::update(bool pivot, bool local, bool snap) { EditorTool::update(pivot, local, snap); - RectTransform *rect = static_cast(m_selected.front().object->transform()); + RectTransform *rect = static_cast(m_controller->selectList().front().object->transform()); RectTransform *parent = dynamic_cast(rect->parentTransform()); if(parent) { @@ -81,7 +126,7 @@ void WidgetTool::update(bool pivot, bool local, bool snap) { if(isDrag) { Vector3 delta(m_world - m_savedWorld); if(delta.length() > 1.0f) { - for(const auto &it : qAsConst(m_selected)) { + for(const auto &it : qAsConst(m_controller->selectList())) { RectTransform *rect = static_cast(it.object->transform()); Vector3 p(rect->position()); @@ -144,3 +189,42 @@ QString WidgetTool::icon() const { QString WidgetTool::name() const { return "Resize"; } + +const VariantList &WidgetTool::cache() const { + return m_propertiesCache; +} + +Vector3 WidgetTool::objectPosition() { + if(m_controller->selectList().size() == 1) { + return m_controller->selectList().front().object->transform()->worldPosition(); + } + return objectBound().center; +} + +AABBox WidgetTool::objectBound() { + AABBox result; + result.extent = Vector3(-1.0f); + if(!m_controller->selectList().empty()) { + bool first = true; + for(auto &it : m_controller->selectList()) { + if(it.renderable == nullptr) { + it.renderable = it.object->getComponent(); + } + if(it.renderable) { + if(first) { + result = it.renderable->bound(); + first = false; + } else { + result.encapsulate(it.renderable->bound()); + } + } else { + if(first) { + result.center = it.object->transform()->worldPosition(); + } else { + result.encapsulate(it.object->transform()->worldPosition()); + } + } + } + } + return result; +} diff --git a/modules/uikit/src/editor/widgetcontroller.cpp b/modules/uikit/src/editor/widgetcontroller.cpp index 22d2b0ccb..6f908c975 100644 --- a/modules/uikit/src/editor/widgetcontroller.cpp +++ b/modules/uikit/src/editor/widgetcontroller.cpp @@ -22,7 +22,7 @@ WidgetController::WidgetController(Object *rootObject, QWidget *view) : CameraController(), m_rootObject(rootObject), - m_widgetTool(new WidgetTool(this, m_selected)), + m_widgetTool(new WidgetTool(this)), m_width(0), m_height(0), m_canceled(false), @@ -64,7 +64,7 @@ void WidgetController::selectActors(const std::list &list) { for(auto it : list) { Actor *actor = dynamic_cast(findObject(it)); if(actor) { - EditorTool::Select data; + WidgetTool::Select data; data.object = actor; data.uuid = actor->uuid(); m_selected.push_back(data); diff --git a/worldeditor/src/screens/scenecomposer/objectcontroller.cpp b/worldeditor/src/screens/scenecomposer/objectcontroller.cpp index 587f279a2..ca96962f8 100644 --- a/worldeditor/src/screens/scenecomposer/objectcontroller.cpp +++ b/worldeditor/src/screens/scenecomposer/objectcontroller.cpp @@ -179,11 +179,11 @@ ObjectController::ObjectController() : EditorSettings::instance()->value(gIsolationColor, QColor(0, 76, 140, 0)); m_tools = { - new SelectTool(this, m_selected), - new MoveTool(this, m_selected), - new RotateTool(this, m_selected), - new ScaleTool(this, m_selected), - new ResizeTool(this, m_selected), + new SelectTool(this), + new MoveTool(this), + new RotateTool(this), + new ScaleTool(this), + new ResizeTool(this), }; } @@ -430,7 +430,7 @@ void ObjectController::selectActors(const std::list &list) { for(auto it : list) { Actor *actor = dynamic_cast(findObject(it)); if(actor) { - EditorTool::Select data; + SelectTool::Select data; data.object = actor; data.uuid = actor->uuid(); m_selected.push_back(data); diff --git a/worldeditor/src/screens/scenecomposer/objectcontroller.h b/worldeditor/src/screens/scenecomposer/objectcontroller.h index 336b6feb8..817dd688b 100644 --- a/worldeditor/src/screens/scenecomposer/objectcontroller.h +++ b/worldeditor/src/screens/scenecomposer/objectcontroller.h @@ -4,10 +4,11 @@ #include #include -#include #include #include +#include "tools/selecttool.h" + class Actor; class Scene; @@ -43,9 +44,9 @@ class ObjectController : public CameraController { void setIsolatedModified(bool flag) { m_isolatedActorModified = flag; } bool isIsolatedModified() const { return m_isolatedActorModified; } - QList tools() const { return m_tools; } + QList tools() const { return m_tools; } - EditorTool::SelectList &selectList() { return m_selected; } + SelectTool::SelectList &selectList() { return m_selected; } bool isDrag() const { return m_drag; } void setDrag(bool drag); @@ -95,7 +96,7 @@ private slots: void onPrefabCreated(uint32_t uuid, uint32_t clone); protected: - EditorTool::SelectList m_selected; + SelectTool::SelectList m_selected; QList m_isolationSelectedBackup; @@ -104,7 +105,7 @@ private slots: std:: list m_objectsList; - QList m_tools; + QList m_tools; Vector2 m_mousePosition; @@ -112,7 +113,7 @@ private slots: Actor *m_isolatedActor; - EditorTool *m_activeTool; + SelectTool *m_activeTool; ViewportRaycast *m_rayCast; diff --git a/worldeditor/src/screens/scenecomposer/scenecomposer.cpp b/worldeditor/src/screens/scenecomposer/scenecomposer.cpp index 59f77c89f..b92188f7b 100644 --- a/worldeditor/src/screens/scenecomposer/scenecomposer.cpp +++ b/worldeditor/src/screens/scenecomposer/scenecomposer.cpp @@ -383,7 +383,7 @@ void SceneComposer::restoreBackupScenes() { emit objectsHierarchyChanged(Engine::world()); // Repick selection bool first = true; - EditorTool::SelectList &list = m_controller->selectList(); + SelectTool::SelectList &list = m_controller->selectList(); for(auto &it : list) { Actor *actor = dynamic_cast(ObjectSystem::findObject(it.uuid, Engine::world())); if(actor) { diff --git a/worldeditor/src/screens/scenecomposer/tools/movetool.cpp b/worldeditor/src/screens/scenecomposer/tools/movetool.cpp index 7da3c58fc..28c1c6788 100644 --- a/worldeditor/src/screens/scenecomposer/tools/movetool.cpp +++ b/worldeditor/src/screens/scenecomposer/tools/movetool.cpp @@ -7,8 +7,8 @@ #include "../objectcontroller.h" -MoveTool::MoveTool(ObjectController *controller, SelectList &selection) : - SelectTool(controller, selection) { +MoveTool::MoveTool(ObjectController *controller) : + SelectTool(controller) { m_snap = 0.25f; @@ -19,7 +19,7 @@ void MoveTool::update(bool center, bool local, bool snap) { bool isDrag = m_controller->isDrag(); - Transform *t = m_selected.back().object->transform(); + Transform *t = m_controller->selectList().back().object->transform(); m_world = Handles::moveTool(objectPosition(), local ? t->worldQuaternion() : Quaternion(), isDrag); if(isDrag) { @@ -30,7 +30,7 @@ void MoveTool::update(bool center, bool local, bool snap) { } } QSet scenes; - for(const auto &it : qAsConst(m_selected)) { + for(const auto &it : qAsConst(m_controller->selectList())) { Vector3 dt(local ? t->worldQuaternion() * delta : delta); Actor *a = dynamic_cast(it.object->parent()); if(!local && a && a->transform()) { diff --git a/worldeditor/src/screens/scenecomposer/tools/movetool.h b/worldeditor/src/screens/scenecomposer/tools/movetool.h index 5e66bba07..22d53b8b7 100644 --- a/worldeditor/src/screens/scenecomposer/tools/movetool.h +++ b/worldeditor/src/screens/scenecomposer/tools/movetool.h @@ -7,7 +7,7 @@ class ObjectCtrl; class MoveTool : public SelectTool { public: - explicit MoveTool(ObjectController *controller, SelectList &selection); + explicit MoveTool(ObjectController *controller); void update(bool center, bool local, bool snap) override; diff --git a/worldeditor/src/screens/scenecomposer/tools/resizetool.cpp b/worldeditor/src/screens/scenecomposer/tools/resizetool.cpp index b39e4cc61..c25c264d4 100644 --- a/worldeditor/src/screens/scenecomposer/tools/resizetool.cpp +++ b/worldeditor/src/screens/scenecomposer/tools/resizetool.cpp @@ -9,15 +9,15 @@ #include "../objectcontroller.h" -ResizeTool::ResizeTool(ObjectController *controller, SelectList &selection) : - SelectTool(controller, selection) { +ResizeTool::ResizeTool(ObjectController *controller) : + SelectTool(controller) { } void ResizeTool::beginControl() { SelectTool::beginControl(); m_savedBox = m_box; - for(auto &it : m_selected) { + for(auto &it : m_controller->selectList()) { if(it.renderable) { it.box = it.renderable->bound(); @@ -84,7 +84,7 @@ void ResizeTool::update(bool pivot, bool local, bool snap) { QSet scenes; - for(const auto &it : qAsConst(m_selected)) { + for(const auto &it : qAsConst(m_controller->selectList())) { Transform *tr = it.object->transform(); Matrix4 parent; diff --git a/worldeditor/src/screens/scenecomposer/tools/resizetool.h b/worldeditor/src/screens/scenecomposer/tools/resizetool.h index c6a8f94d9..fbfe1af10 100644 --- a/worldeditor/src/screens/scenecomposer/tools/resizetool.h +++ b/worldeditor/src/screens/scenecomposer/tools/resizetool.h @@ -5,7 +5,7 @@ class ResizeTool : public SelectTool { public: - explicit ResizeTool(ObjectController *controller, EditorTool::SelectList &selection); + explicit ResizeTool(ObjectController *controller); void update(bool pivot, bool local, bool snap) override; diff --git a/worldeditor/src/screens/scenecomposer/tools/rotatetool.cpp b/worldeditor/src/screens/scenecomposer/tools/rotatetool.cpp index f87e048a8..2c8287ed6 100644 --- a/worldeditor/src/screens/scenecomposer/tools/rotatetool.cpp +++ b/worldeditor/src/screens/scenecomposer/tools/rotatetool.cpp @@ -8,8 +8,8 @@ #include "../objectcontroller.h" -RotateTool::RotateTool(ObjectController *controller, SelectList &selection) : - SelectTool(controller, selection) { +RotateTool::RotateTool(ObjectController *controller) : + SelectTool(controller) { m_snap = 5.0f; } @@ -21,7 +21,7 @@ void RotateTool::update(bool pivot, bool local, bool snap) { m_position = objectPosition(); } - EditorTool::Select &sel = m_selected.back(); + SelectTool::Select &sel = m_controller->selectList().back(); float angle = Handles::rotationTool(m_position, local ? sel.quat : Quaternion(), m_controller->isDrag()); if(m_snap > 0) { @@ -31,7 +31,7 @@ void RotateTool::update(bool pivot, bool local, bool snap) { if(m_controller->isDrag()) { QSet scenes; - for(const auto &it : qAsConst(m_selected)) { + for(const auto &it : qAsConst(m_controller->selectList())) { Transform *tr = it.object->transform(); Matrix4 parent; if(tr->parentTransform()) { diff --git a/worldeditor/src/screens/scenecomposer/tools/rotatetool.h b/worldeditor/src/screens/scenecomposer/tools/rotatetool.h index a7950992a..d16bac639 100644 --- a/worldeditor/src/screens/scenecomposer/tools/rotatetool.h +++ b/worldeditor/src/screens/scenecomposer/tools/rotatetool.h @@ -5,7 +5,7 @@ class RotateTool : public SelectTool { public: - explicit RotateTool(ObjectController *controller, EditorTool::SelectList &selection); + explicit RotateTool(ObjectController *controller); void update(bool pivot, bool local, bool snap) override; diff --git a/worldeditor/src/screens/scenecomposer/tools/scaletool.cpp b/worldeditor/src/screens/scenecomposer/tools/scaletool.cpp index 56586dfae..3d72fb6c6 100644 --- a/worldeditor/src/screens/scenecomposer/tools/scaletool.cpp +++ b/worldeditor/src/screens/scenecomposer/tools/scaletool.cpp @@ -8,8 +8,8 @@ #include "../objectcontroller.h" -ScaleTool::ScaleTool(ObjectController *controller, SelectList &selection) : - SelectTool(controller, selection) { +ScaleTool::ScaleTool(ObjectController *controller) : + SelectTool(controller) { m_snap = 1.0f; } @@ -24,7 +24,7 @@ void ScaleTool::update(bool center, bool local, bool snap) { Handles::s_Axes = 0; } - Transform *t = m_selected.back().object->transform(); + Transform *t = m_controller->selectList().back().object->transform(); m_world = Handles::scaleTool(m_position, local ? t->worldQuaternion() : Quaternion(), isDrag); @@ -58,7 +58,7 @@ void ScaleTool::update(bool center, bool local, bool snap) { } QSet scenes; - for(const auto &it : qAsConst(m_selected)) { + for(const auto &it : qAsConst(m_controller->selectList())) { Transform *tr = it.object->transform(); Matrix4 parent; if(tr->parentTransform()) { diff --git a/worldeditor/src/screens/scenecomposer/tools/scaletool.h b/worldeditor/src/screens/scenecomposer/tools/scaletool.h index a12e35469..56f2a3d0b 100644 --- a/worldeditor/src/screens/scenecomposer/tools/scaletool.h +++ b/worldeditor/src/screens/scenecomposer/tools/scaletool.h @@ -5,7 +5,7 @@ class ScaleTool : public SelectTool { public: - explicit ScaleTool(ObjectController *controller, EditorTool::SelectList &selection); + explicit ScaleTool(ObjectController *controller); void update(bool center, bool local, bool snap) override; diff --git a/worldeditor/src/screens/scenecomposer/tools/selecttool.cpp b/worldeditor/src/screens/scenecomposer/tools/selecttool.cpp index bc2ef32da..d63f1a2ab 100644 --- a/worldeditor/src/screens/scenecomposer/tools/selecttool.cpp +++ b/worldeditor/src/screens/scenecomposer/tools/selecttool.cpp @@ -2,13 +2,14 @@ #include #include +#include #include #include "../objectcontroller.h" -SelectTool::SelectTool(ObjectController *controller, SelectList &selection) : - EditorTool(selection), +SelectTool::SelectTool(ObjectController *controller) : + EditorTool(), m_controller(controller) { } @@ -16,10 +17,55 @@ SelectTool::SelectTool(ObjectController *controller, SelectList &selection) : void SelectTool::beginControl() { EditorTool::beginControl(); + m_propertiesCache.clear(); + + for(auto &it : m_controller->selectList()) { + Transform *t = it.object->transform(); + it.position = t->position(); + it.scale = t->scale(); + it.euler = t->rotation(); + it.quat = t->quaternion(); + + VariantMap components; + for(auto &child : it.object->getChildren()) { + Component *component = dynamic_cast(child); + if(component) { + VariantMap properies; + const MetaObject *meta = component->metaObject(); + for(int i = 0; i < meta->propertyCount(); i++) { + MetaProperty property = meta->property(i); + properies[property.name()] = property.read(component); + } + components[std::to_string(component->uuid())] = properies; + } + } + m_propertiesCache.push_back(components); + } + m_position = objectPosition(); m_savedWorld = m_world; } +void SelectTool::cancelControl() { + auto cache = m_propertiesCache.begin(); + for(auto &it : m_controller->selectList()) { + VariantMap components = (*cache).toMap(); + for(auto &child : it.object->getChildren()) { + Component *component = dynamic_cast(child); + if(component) { + VariantMap properties = components[std::to_string(component->uuid())].toMap(); + const MetaObject *meta = component->metaObject(); + for(int i = 0; i < meta->propertyCount(); i++) { + MetaProperty property = meta->property(i); + property.write(component, properties[property.name()]); + } + } + } + + ++cache; + } +} + QString SelectTool::icon() const { return ":/Images/editor/Select.png"; } @@ -27,3 +73,42 @@ QString SelectTool::icon() const { QString SelectTool::name() const { return "Select"; } + +const VariantList &SelectTool::cache() const { + return m_propertiesCache; +} + +Vector3 SelectTool::objectPosition() { + if(m_controller->selectList().size() == 1) { + return m_controller->selectList().front().object->transform()->worldPosition(); + } + return objectBound().center; +} + +AABBox SelectTool::objectBound() { + AABBox result; + result.extent = Vector3(-1.0f); + if(!m_controller->selectList().empty()) { + bool first = true; + for(auto &it : m_controller->selectList()) { + if(it.renderable == nullptr) { + it.renderable = it.object->getComponent(); + } + if(it.renderable) { + if(first) { + result = it.renderable->bound(); + first = false; + } else { + result.encapsulate(it.renderable->bound()); + } + } else { + if(first) { + result.center = it.object->transform()->worldPosition(); + } else { + result.encapsulate(it.object->transform()->worldPosition()); + } + } + } + } + return result; +} diff --git a/worldeditor/src/screens/scenecomposer/tools/selecttool.h b/worldeditor/src/screens/scenecomposer/tools/selecttool.h index a0e4d0c9c..d574af6c3 100644 --- a/worldeditor/src/screens/scenecomposer/tools/selecttool.h +++ b/worldeditor/src/screens/scenecomposer/tools/selecttool.h @@ -4,17 +4,46 @@ #include "editor/editortool.h" class ObjectController; +class Renderable; class SelectTool : public EditorTool { public: - explicit SelectTool(ObjectController *controller, EditorTool::SelectList &selection); + struct Select { + bool operator==(const Select &left) { + return (uuid == left.uuid); + } + + uint32_t uuid = 0; + Actor *object = nullptr; + Renderable *renderable = nullptr; + + Vector3 position; + Vector3 scale; + Vector3 euler; + Vector3 pivot; + Quaternion quat; + AABBox box; + }; + + typedef QList