From d19feac70c0ee487ec1508d7b79660aef9900bbf Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Tue, 9 Aug 2011 23:56:26 +0300 Subject: [PATCH] Changed: #1302 Added additional visual elements (Point, Path, Zone) in 2d render without undo/redo operations(move, rotate, scale). --HG-- branch : gsoc2011-worldeditorqt --- .../src/plugins/world_editor/CMakeLists.txt | 3 + .../plugins/world_editor/primitives_model.h | 2 + .../plugins/world_editor/primitives_view.cpp | 8 +- .../plugins/world_editor/primitives_view.h | 4 +- .../world_editor/project_settings_dialog.cpp | 59 ++ .../world_editor/project_settings_dialog.h | 48 ++ .../world_editor/project_settings_dialog.ui | 103 +++ .../world_editor/world_editor_actions.cpp | 97 ++- .../world_editor/world_editor_actions.h | 8 +- .../world_editor/world_editor_constants.h | 1 + .../world_editor/world_editor_misc.cpp | 5 + .../plugins/world_editor/world_editor_misc.h | 2 + .../world_editor/world_editor_scene.cpp | 294 +++++++- .../plugins/world_editor/world_editor_scene.h | 46 +- .../world_editor/world_editor_scene_item.cpp | 649 ++++++++++++++++++ .../world_editor/world_editor_scene_item.h | 237 +++++++ .../world_editor/world_editor_window.cpp | 99 ++- .../world_editor/world_editor_window.h | 10 + .../world_editor/world_editor_window.ui | 59 +- 19 files changed, 1688 insertions(+), 46 deletions(-) create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.ui create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.h diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt index 1e41175bd..07d7fa5d1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt @@ -12,11 +12,14 @@ SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin. SET(OVQT_PLUGIN_WORLD_EDITOR_HDR world_editor_plugin.h world_editor_window.h world_editor_scene.h + world_editor_scene_item.h primitives_model.h primitives_view.h + project_settings_dialog.h ) SET(OVQT_PLUGIN_WORLD_EDITOR_UIS world_editor_window.ui + project_settings_dialog.ui ) SET(OVQT_PLUGIN_WORLD_EDITOR_RCS world_editor.qrc) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h index d2b6509ad..7f9a90aa7 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h @@ -68,6 +68,8 @@ public: /// @Path is a list of [row,column] pairs showing us the way through the model. Path pathFromIndex(const QModelIndex &index); + //Path pathFromNode(Node *index); + QModelIndex pathToIndex(const Path &path); void createWorldEditNode(const QString &fileName); diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp index 517dcee43..f324da9b9 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp @@ -40,6 +40,7 @@ namespace WorldEditor PrimitivesView::PrimitivesView(QWidget *parent) : QTreeView(parent), m_undoStack(0), + m_worldEditorScene(0), m_zoneBuilder(0), m_primitivesTreeModel(0) { @@ -103,6 +104,11 @@ void PrimitivesView::setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilde m_zoneBuilder = zoneBuilder; } +void PrimitivesView::setWorldScene(WorldEditorScene *worldEditorScene) +{ + m_worldEditorScene = worldEditorScene; +} + void PrimitivesView::setModel(PrimitivesTreeModel *model) { QTreeView::setModel(model); @@ -127,7 +133,7 @@ void PrimitivesView::loadRootPrimitive() Q_FOREACH(QString fileName, fileNames) { m_lastDir = QFileInfo(fileName).absolutePath(); - m_undoStack->push(new LoadRootPrimitiveCommand(fileName, m_primitivesTreeModel)); + m_undoStack->push(new LoadRootPrimitiveCommand(fileName, m_worldEditorScene, m_primitivesTreeModel)); } if (fileNames.count() > 1) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h index 67c3ffba0..18785b909 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h @@ -27,7 +27,6 @@ #include #include #include -#include #include namespace LandscapeEditor @@ -38,6 +37,7 @@ class ZoneBuilderBase; namespace WorldEditor { class PrimitivesTreeModel; +class WorldEditorScene; /** @class PrimitivesView @@ -54,6 +54,7 @@ public: void setUndoStack(QUndoStack *undoStack); void setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder); + void setWorldScene(WorldEditorScene *worldEditorScene); virtual void setModel(PrimitivesTreeModel *model); private Q_SLOTS: @@ -92,6 +93,7 @@ private: QAction *m_hideAction; QUndoStack *m_undoStack; + WorldEditorScene *m_worldEditorScene; LandscapeEditor::ZoneBuilderBase *m_zoneBuilder; PrimitivesTreeModel *m_primitivesTreeModel; }; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.cpp new file mode 100644 index 000000000..28654864c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.cpp @@ -0,0 +1,59 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "project_settings_dialog.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ + +ProjectSettingsDialog::ProjectSettingsDialog(const QString &dataPath, QWidget *parent) + : QDialog(parent) +{ + m_ui.setupUi(this); + m_ui.pathLineEdit->setText(dataPath); + setFixedHeight(sizeHint().height()); + connect(m_ui.selectPathButton, SIGNAL(clicked()), this, SLOT(selectPath())); +} + +ProjectSettingsDialog::~ProjectSettingsDialog() +{ +} + +QString ProjectSettingsDialog::dataPath() const +{ + return m_ui.pathLineEdit->text(); +} + +void ProjectSettingsDialog::selectPath() +{ + QString dataPath = QFileDialog::getExistingDirectory(this, tr("Select data path"), m_ui.pathLineEdit->text()); + if (!dataPath.isEmpty()) + m_ui.pathLineEdit->setText(dataPath); +} + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.h new file mode 100644 index 000000000..b9a54b9ed --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.h @@ -0,0 +1,48 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef PROJECT_SETTINGS_DIALOG_WE_H +#define PROJECT_SETTINGS_DIALOG_WE_H + +// Project includes +#include "ui_project_settings_dialog.h" + +// Qt includes + +namespace WorldEditor +{ + +class ProjectSettingsDialog: public QDialog +{ + Q_OBJECT + +public: + ProjectSettingsDialog(const QString &dataPath, QWidget *parent = 0); + ~ProjectSettingsDialog(); + + QString dataPath() const; + +private Q_SLOTS: + void selectPath(); + +private: + + Ui::ProjectSettingsDialog m_ui; +}; /* class ProjectSettingsDialog */ + +} /* namespace WorldEditor */ + +#endif // PROJECT_SETTINGS_DIALOG_WE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.ui new file mode 100644 index 000000000..6904a57a2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.ui @@ -0,0 +1,103 @@ + + + ProjectSettingsDialog + + + + 0 + 0 + 419 + 93 + + + + Project settings + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + + + + Data directory: + + + pathLineEdit + + + + + + + + + + ... + + + + + + + Context: + + + contextComboBox + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ProjectSettingsDialog + accept() + + + 257 + 83 + + + 157 + 274 + + + + + buttonBox + rejected() + ProjectSettingsDialog + reject() + + + 325 + 83 + + + 286 + 274 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp index fb8299c23..a654e8f31 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp @@ -18,6 +18,8 @@ #include "world_editor_actions.h" #include "world_editor_misc.h" #include "primitive_item.h" +#include "world_editor_scene.h" +#include "world_editor_scene_item.h" // Lanscape Editor plugin #include "../landscape_editor/builder_zone_base.h" @@ -30,6 +32,7 @@ #include #include #include +#include #include // Qt includes @@ -38,6 +41,92 @@ namespace WorldEditor { +void addNewGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene) +{ + PrimitiveNode *node = static_cast(primIndex.internalPointer()); + + float cellSize = Utils::ligoConfig()->CellSize; + if (node != 0) + { + NLLIGO::IPrimitive *primitive = node->primitive(); + NLLIGO::CPrimVector *vec = 0; + QGraphicsItem *item; + switch (node->primitiveClass()->Type) + { + case NLLIGO::CPrimitiveClass::Point: + { + vec = primitive->getPrimVector(); + item = scene->addWorldItemPoint(QPointF(vec->x, -vec->y + cellSize), 0); + break; + } + case NLLIGO::CPrimitiveClass::Path: + { + QPolygonF polygon; + vec = primitive->getPrimVector(); + int sizeVec = primitive->getNumVector(); + + for (int i = 0; i < sizeVec; ++i) + { + polygon << QPointF(vec->x, -vec->y + cellSize); + ++vec; + } + + item = scene->addWorldItemPath(polygon); + break; + } + case NLLIGO::CPrimitiveClass::Zone: + { + QPolygonF polygon; + vec = primitive->getPrimVector(); + int sizeVec = primitive->getNumVector(); + + for (int i = 0; i < sizeVec; ++i) + { + polygon << QPointF(vec->x, -vec->y + cellSize); + ++vec; + } + item = scene->addWorldItemZone(polygon); + break; + } + } + + node->setGraphicsData(GRAPHICS_DATA_QT2D, item); + } + + int count = model->rowCount(primIndex); + for (int i = 0; i < count; ++i) + { + addNewGraphicsItems(primIndex.child(i, 0), model, scene); + } +} + +void removeGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene) +{ + PrimitiveNode *node = static_cast(primIndex.internalPointer()); + + if (node != 0) + { + switch (node->primitiveClass()->Type) + { + case NLLIGO::CPrimitiveClass::Point: + case NLLIGO::CPrimitiveClass::Path: + case NLLIGO::CPrimitiveClass::Zone: + { + QGraphicsItem *item = static_cast(node->graphicsData(GRAPHICS_DATA_QT2D)); + if (item != 0) + delete item; + break; + } + } + } + + int count = model->rowCount(primIndex); + for (int i = 0; i < count; ++i) + { + removeGraphicsItems(primIndex.child(i, 0), model, scene); + } +} + CreateWorldCommand::CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) : QUndoCommand(parent), m_fileName(fileName), @@ -121,9 +210,11 @@ void CreateRootPrimitiveCommand::redo() } -LoadRootPrimitiveCommand::LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) +LoadRootPrimitiveCommand::LoadRootPrimitiveCommand(const QString &fileName, WorldEditorScene *scene, + PrimitivesTreeModel *model, QUndoCommand *parent) : QUndoCommand(parent), m_fileName(fileName), + m_scene(scene), m_model(model) { setText("Load primitive file"); @@ -137,6 +228,8 @@ void LoadRootPrimitiveCommand::undo() { QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + removeGraphicsItems(index, m_model, m_scene); + RootPrimitiveNode *node = static_cast(index.internalPointer()); delete node->primitives(); @@ -167,6 +260,8 @@ void LoadRootPrimitiveCommand::redo() } m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, primitives); + + addNewGraphicsItems(m_model->pathToIndex(m_rootPrimIndex), m_model, m_scene); } AddPrimitiveByClassCommand::AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h index 00951dd9e..7393861b0 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h @@ -34,6 +34,10 @@ class ZoneBuilderBase; namespace WorldEditor { +class WorldEditorScene; + +void addNewGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene); +void removeGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene); /** @class CreateWorldCommand @@ -100,7 +104,8 @@ private: class LoadRootPrimitiveCommand: public QUndoCommand { public: - LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + LoadRootPrimitiveCommand(const QString &fileName, WorldEditorScene *scene, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); virtual ~LoadRootPrimitiveCommand(); virtual void undo(); @@ -109,6 +114,7 @@ private: Path m_rootPrimIndex; const QString m_fileName; + WorldEditorScene *const m_scene; PrimitivesTreeModel *const m_model; }; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h index cb1abf21e..5c1d32908 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h @@ -30,6 +30,7 @@ const char *const WORLD_WINDOW_STATE = "WorldWindowState"; const char *const WORLD_WINDOW_GEOMETRY = "WorldWindowGeometry"; const char *const WORLD_EDITOR_CELL_SIZE = "WorldEditorCellSize"; const char *const WORLD_EDITOR_SNAP = "WorldEditorSnap"; +const char *const WORLD_EDITOR_USE_OPENGL = "WorldEditorUseOpenGL"; const char *const ZONE_SNAPSHOT_RES = "WorldEditorZoneSnapshotRes"; const char *const PRIMITIVE_CLASS_FILENAME = "WorldEditorPrimitiveClassFilename"; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp index e06332deb..1f77ee63d 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp @@ -688,5 +688,10 @@ bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive) return modified; } +NLLIGO::CLigoConfig *ligoConfig() +{ + return NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig; +} + } /* namespace Utils */ } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h index ea6a59f58..2e7fc93b1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h @@ -74,6 +74,8 @@ bool updateDefaultValues(NLLIGO::IPrimitive *primitive); bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive); +NLLIGO::CLigoConfig *ligoConfig(); + } /* namespace Utils */ } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp index 2c4c41065..fd2d85a24 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp @@ -30,42 +30,304 @@ namespace WorldEditor { WorldEditorScene::WorldEditorScene(int sizeCell, QObject *parent) - : LandscapeEditor::LandscapeSceneBase(sizeCell, parent) + : LandscapeEditor::LandscapeSceneBase(sizeCell, parent), + m_editedSelectedItems(false), + m_lastPickedPrimitive(0), + m_mode(SelectMode), + m_editMode(false) { + setItemIndexMethod(NoIndex); + + m_pen.setColor(QColor(50, 255, 155)); + m_pen.setWidth(0); + + m_brush.setColor(QColor(50, 255, 155, 80)); + m_brush.setStyle(Qt::SolidPattern); } WorldEditorScene::~WorldEditorScene() { } -/* -void LandscapeSceneBase::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) + +QGraphicsItem *WorldEditorScene::addWorldItemPoint(const QPointF &point, const float angle) { - QGraphicsScene::mousePressEvent(mouseEvent); + WorldItemPoint *item = new WorldItemPoint(point, angle); + addItem(item); + return item; +} + +QGraphicsItem *WorldEditorScene::addWorldItemPath(const QPolygonF &polyline) +{ + WorldItemPath *item = new WorldItemPath(polyline); + addItem(item); + return item; +} + +QGraphicsItem *WorldEditorScene::addWorldItemZone(const QPolygonF &polygon) +{ + WorldItemZone *item = new WorldItemZone(polygon); + addItem(item); + return item; +} + +void WorldEditorScene::setModeEdit(WorldEditorScene::ModeEdit mode) +{ + if (mode == WorldEditorScene::SelectMode) + m_editedSelectedItems = false; + + m_selectionArea = QRectF(); + + m_mode = mode; +} + +WorldEditorScene::ModeEdit WorldEditorScene::editMode() const +{ + return m_mode; +} + +bool WorldEditorScene::isEnabledEditPoint() const +{ + return m_editMode; +} + +void WorldEditorScene::setEnabledEditPoint(bool enabled) +{ + m_editMode = enabled; +} + +void WorldEditorScene::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsScene::drawForeground(painter, rect); + + if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0)) + { + painter->setPen(m_pen); + painter->setBrush(m_brush); + painter->drawRect(m_selectionArea); + } +} + +void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent); qreal x = mouseEvent->scenePos().x(); qreal y = mouseEvent->scenePos().y(); - m_posX = sint32(floor(x / m_cellSize)); - m_posY = sint32(-floor(y / m_cellSize)); - m_mouseButton = mouseEvent->button(); + if (mouseEvent->button() != Qt::LeftButton) + return; + +// if ((!m_editedSelectedItems) && (m_mode != WorldEditorScene::SelectMode)) + if ((!m_editedSelectedItems && m_selectedItems.isEmpty()) || + (!calcBoundingShape(m_selectedItems).contains(mouseEvent->scenePos()))) + { + updatePickSelection(mouseEvent->scenePos()); + m_firstSelection = true; + } + + m_editedSelectedItems = false; + + switch (m_mode) + { + case WorldEditorScene::SelectMode: + { + m_selectionArea.setTopLeft(mouseEvent->scenePos()); + break; + } + case WorldEditorScene::MoveMode: + { + break; + } + case WorldEditorScene::RotateMode: + break; + case WorldEditorScene::ScaleMode: + break; + case WorldEditorScene::TurnMode: + break; + case WorldEditorScene::RadiusMode: + break; + }; + +// if (m_selectedItems.isEmpty()) +// m_selectionArea.setTopLeft(mouseEvent->scenePos()); } -void LandscapeSceneBase::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { - m_mouseX = mouseEvent->scenePos().x(); + if (QApplication::mouseButtons() == Qt::LeftButton) + { + + QPointF offset(mouseEvent->scenePos() - mouseEvent->lastScenePos()); + + m_selectionArea.setBottomRight(mouseEvent->scenePos()); + + switch (m_mode) + { + case WorldEditorScene::SelectMode: + break; + case WorldEditorScene::MoveMode: + { + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->moveOn(offset); + } + break; + } + case WorldEditorScene::RotateMode: + { + QRectF pivot = calcBoundingRect(m_selectedItems); + + // Caluculate angle between two line + QLineF firstLine(pivot.center(), mouseEvent->lastScenePos()); + QLineF secondLine(pivot.center(), mouseEvent->scenePos()); + qreal angle = secondLine.angleTo(firstLine); + + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->rotateOn(pivot.center(), angle); + } + break; + } + case WorldEditorScene::ScaleMode: + { + // float scale = (_SelectionMin.x - _SelectionMax.x + _SelectionMax.y - _SelectionMin.y) * SCALE_PER_PIXEL + 1.f; + // moveAction->setScale (std::max (0.001f, scale), _MainFrame->getTransformMode ()==CMainFrame::Scale, radius); + + // TODO: perfomance + QRectF pivot = calcBoundingRect(m_selectedItems); + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->scaleOn(pivot.center(), offset); + } + break; + } + case WorldEditorScene::TurnMode: + break; + case WorldEditorScene::RadiusMode: + break; + }; + + if ((editMode() != WorldEditorScene::SelectMode) && (!m_selectedItems.isEmpty())) + m_editedSelectedItems = true; + else + m_editedSelectedItems = false; + + update(); + } + /*m_mouseX = mouseEvent->scenePos().x(); m_mouseY = mouseEvent->scenePos().y() - m_cellSize; - - m_posX = sint32(floor(m_mouseX / m_cellSize)); - m_posY = sint32(-floor(m_mouseY / m_cellSize)); - + */ QGraphicsScene::mouseMoveEvent(mouseEvent); } -void LandscapeSceneBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +void WorldEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) { + if (mouseEvent->button() != Qt::LeftButton) + return; + + if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0)) + { + QList listItems; + + // Clear selection + updateSelectedItems(false); + m_selectedItems.clear(); + + if (m_selectionArea.left() < m_selectionArea.right()) + { + listItems = items(m_selectionArea, Qt::IntersectsItemShape, + Qt::AscendingOrder); + } + else + { + listItems = items(m_selectionArea, Qt::ContainsItemShape, + Qt::AscendingOrder); + } + + Q_FOREACH(QGraphicsItem *item, listItems) + { + if (qgraphicsitem_cast(item) == 0) + continue; + + m_selectedItems.push_back(item); + } + updateSelectedItems(true); + m_selectionArea = QRectF(); + update(); + } + else + { + if ((!m_editedSelectedItems) && (!m_firstSelection)) + updatePickSelection(mouseEvent->scenePos()); + else + m_firstSelection = false; + } +// Huck for standart selection model +// clearSelection(); +// updateSelectedItems(true); + QGraphicsScene::mouseReleaseEvent(mouseEvent); - m_mouseButton = Qt::NoButton; } -*/ + +QRectF WorldEditorScene::calcBoundingRect(const QList &listItems) +{ + QRectF rect; + Q_FOREACH(QGraphicsItem *item, listItems) + { + QRectF itemRect = item->boundingRect(); + rect = rect.united(itemRect.translated(item->pos())); + } + return rect; +} + +QPainterPath WorldEditorScene::calcBoundingShape(const QList &listItems) +{ + QPainterPath painterPath; + Q_FOREACH(QGraphicsItem *item, listItems) + { + QPainterPath itemPath = item->shape(); + painterPath = painterPath.united(itemPath.translated(item->pos())); + } + return painterPath; +} + +void WorldEditorScene::updateSelectedItems(bool value) +{ + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + if (value) + { + item->setFlag(QGraphicsItem::ItemIsSelectable); + //item->setZValue(SELECTED_LAYER); + } + else + { + item->setFlag(QGraphicsItem::ItemIsSelectable, false); + //item->setZValue(UNSELECTED_LAYER); + } + item->setSelected(value); + } +} + +void WorldEditorScene::updatePickSelection(const QPointF &point) +{ + //clearSelection(); + updateSelectedItems(false); + m_selectedItems.clear(); + + QList listItems = items(point, Qt::ContainsItemShape, + Qt::AscendingOrder); + if (!listItems.isEmpty()) + { + // Next primitives + m_lastPickedPrimitive++; + m_lastPickedPrimitive %= listItems.size(); + QGraphicsItem *selectedItem = listItems.at(m_lastPickedPrimitive); + if (qgraphicsitem_cast(selectedItem) != 0) + m_selectedItems.push_back(selectedItem); + + updateSelectedItems(true); + } +} } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h index 84dba333c..36f27b9b4 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h @@ -19,6 +19,7 @@ // Project includes #include "world_editor_global.h" +#include "world_editor_scene_item.h" #include "../landscape_editor/landscape_scene_base.h" @@ -39,17 +40,56 @@ class WORLD_EDITOR_EXPORT WorldEditorScene : public LandscapeEditor::LandscapeSc Q_OBJECT public: + enum ModeEdit + { + SelectMode = 0, + MoveMode, + RotateMode, + ScaleMode, + TurnMode, + RadiusMode + }; + WorldEditorScene(int sizeCell = 160, QObject *parent = 0); virtual ~WorldEditorScene(); + QGraphicsItem *addWorldItemPoint(const QPointF &point, const float angle); + QGraphicsItem *addWorldItemPath(const QPolygonF &polyline); + QGraphicsItem *addWorldItemZone(const QPolygonF &polygon); + + void setModeEdit(WorldEditorScene::ModeEdit mode); + WorldEditorScene::ModeEdit editMode() const; + + bool isEnabledEditPoint() const; + public Q_SLOTS: + void setEnabledEditPoint(bool enabled); protected: -// virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); -// virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); -// virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void drawForeground(QPainter *painter, const QRectF &rect); + + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); private: + + QRectF calcBoundingRect(const QList &listItems); + QPainterPath calcBoundingShape(const QList &listItems); + void updateSelectedItems(bool value); + + void updatePickSelection(const QPointF &point); + + QPen m_pen; + QBrush m_brush; + + QRectF m_selectionArea; + qreal m_firstPickX, m_firstPickY; + QList m_selectedItems; + bool m_editedSelectedItems, m_firstSelection; + uint m_lastPickedPrimitive; + ModeEdit m_mode; + bool m_editMode; }; } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.cpp new file mode 100644 index 000000000..f88c95b9a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.cpp @@ -0,0 +1,649 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_scene_item.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +namespace WorldEditor +{ + +static QPainterPath qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen) +{ + // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0 + // if we pass a value of 0.0 to QPainterPathStroker::setWidth() + const qreal penWidthZero = qreal(0.00000001); + + if (path == QPainterPath()) + return path; + QPainterPathStroker ps; + ps.setCapStyle(pen.capStyle()); + if (pen.widthF() <= 0.0) + ps.setWidth(penWidthZero); + else + ps.setWidth(pen.widthF()); + ps.setJoinStyle(pen.joinStyle()); + ps.setMiterLimit(pen.miterLimit()); + QPainterPath p = ps.createStroke(path); + p.addPath(path); + return p; +} +/* +GraphicsItemNode::GraphicsItemNode(GraphicsItemZone *itemZone, QGraphicsItem *parent) + : QGraphicsObject(parent) +{ + m_itemZone = itemZone; + m_color = QColor(12, 150, 215); + //setFlag(ItemIgnoresTransformations, true); + //setFlag(ItemClipsToShape); + + QPropertyAnimation *animation = new QPropertyAnimation(this, "colorNode"); + animation->setDuration(3000); + animation->setStartValue(QColor(10, 0, 50)); + animation->setKeyValueAt(0.5, QColor(155, 255, 0)); + animation->setEndValue(QColor(10, 0, 50)); + animation->setLoopCount(2000); + animation->setEasingCurve(QEasingCurve::OutInExpo); + animation->start(); + + setFlag(ItemIsSelectable); + setFlag(ItemIsMovable); + setFlag(ItemSendsScenePositionChanges); + m_type = EdgeType; + + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); + setZValue(10000000); +} + +GraphicsItemNode::~GraphicsItemNode() +{ +} + +void GraphicsItemNode::setColorNode(const QColor &color) +{ + m_color = color; + update(); +} + +void GraphicsItemNode::setNodeType(NodeType nodeType) +{ + m_type = nodeType; + if (m_type == EdgeType) + { + setFlag(ItemIsSelectable); + setFlag(ItemIsMovable); + setFlag(ItemSendsScenePositionChanges); + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); + setZValue(10000); + } + else if (m_type == MiddleType) + { + setFlag(ItemIsSelectable, false); + setFlag(ItemIsMovable, false); + setFlag(ItemSendsScenePositionChanges, false); + setAcceptedMouseButtons(Qt::LeftButton); + setZValue(10001); + } + update(); +} + +QRectF GraphicsItemNode::boundingRect() const +{ + return QRectF(QPointF(0, 0), QSizeF(20, 20)); +} + +void GraphicsItemNode::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *) +{ + // Here comes the magic: + //painter->setClipRect(option->exposedRect); + + painter->setPen(Qt::NoPen); + + if (m_type == EdgeType) + { + painter->setBrush(QColor(255, 0, 0)); + } + else if (m_type == MiddleType) + { + painter->setBrush(QColor(0, 0, 255)); + } + if (option->state & QStyle::State_Selected) + { + painter->setBrush(QColor(0, 255, 0)); + } + + painter->drawRect(2, 2, 18, 18); +} + +QVariant GraphicsItemNode::itemChange(GraphicsItemChange change, + const QVariant &value) +{ + if (change == ItemPositionHasChanged) + { + m_itemZone->updateZone(); + } + return QGraphicsItem::itemChange(change, value); +} + +void GraphicsItemNode::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if ((m_type == MiddleType) && (event->button() == Qt::LeftButton)) + { + m_itemZone->updateMiddleNode(this); + setNodeType(EdgeType); + } + else if ((m_type == EdgeType) && (event->button() == Qt::RightButton)) + { + if (m_itemZone->deleteEdgePoint(this)) + setNodeType(MiddleType); + } +} + +GraphicsItemZone::GraphicsItemZone(QGraphicsScene *scene, QGraphicsItem *parent) + : QGraphicsPolygonItem(parent) +{ + m_scene = scene; + + m_color = QColor(12, 150, 215); + + setBrush(QBrush(QColor(100, 100, 255, 128))); + updateZone(); + setZValue(100); + //setFlag(ItemClipsToShape); + //setFlag(ItemIsSelectable, true); + //setFlag(ItemIsMovable, true); + //setFlag(ItemHasNoContents, true); +} + +GraphicsItemZone::~GraphicsItemZone() +{ +} + +void GraphicsItemZone::updateMiddleNode(GraphicsItemNode *node) +{ + for (int i = 0; i < m_listLines.size(); ++i) + { + if (node == m_listLines.at(i).itemPoint) + { + LineItem oldLineItem = m_listLines[i]; + + GraphicsItemNode *newNode1 = new GraphicsItemNode(this); + newNode1->setPos((oldLineItem.lineNode.first->pos() + node->pos()) / 2); + newNode1->setNodeType(GraphicsItemNode::MiddleType); + m_scene->addItem(newNode1); + + GraphicsItemNode *newNode2 = new GraphicsItemNode(this); + newNode2->setPos((oldLineItem.lineNode.second->pos() + node->pos()) / 2); + newNode2->setNodeType(GraphicsItemNode::MiddleType); + m_scene->addItem(newNode2); + + LineItem newLineItem1; + newLineItem1.itemPoint = newNode1; + newLineItem1.lineNode = LineNode(oldLineItem.lineNode.first, node); + m_listLines.push_back(newLineItem1); + + LineItem newLineItem2; + newLineItem2.itemPoint = newNode2; + newLineItem2.lineNode = LineNode(node, oldLineItem.lineNode.second); + m_listLines.push_back(newLineItem2); + + m_listLines.removeAt(i); + + int pos = m_listItems.indexOf(oldLineItem.lineNode.second); + m_listItems.insert(pos, node); + + break; + } + } +} + +bool GraphicsItemZone::deleteEdgePoint(GraphicsItemNode *node) +{ + if (m_listItems.size() < 4) + return false; + + int pos = m_listItems.indexOf(node); + m_listItems.takeAt(pos); + + LineItem newLineItem; + + newLineItem.itemPoint = node; + + for (int i = 0; i < m_listLines.size(); ++i) + { + if (node == m_listLines.at(i).lineNode.first) + { + // Saving second point for new line + newLineItem.lineNode.second = m_listLines.at(i).lineNode.second; + delete m_listLines.at(i).itemPoint; + m_listLines.removeAt(i); + break; + } + } + + for (int i = 0; i < m_listLines.size(); ++i) + { + if (node == m_listLines.at(i).lineNode.second) + { + newLineItem.lineNode.first = m_listLines.at(i).lineNode.first; + delete m_listLines.at(i).itemPoint; + m_listLines.removeAt(i); + break; + } + } + node->setPos((newLineItem.lineNode.first->pos() + newLineItem.lineNode.second->pos()) / 2); + m_listLines.push_back(newLineItem); + + return true; +} + +void GraphicsItemZone::scanPolygon(const QPolygonF &polygon) +{ + GraphicsItemNode *node1; + node1 = new GraphicsItemNode(this); + node1->setPos(*polygon.begin()); + m_listItems.push_back(node1); + m_scene->addItem(node1); + for (int i = 1; i < polygon.count(); ++i) + { + GraphicsItemNode *node2 = new GraphicsItemNode(this); + node2->setPos(polygon.at(i)); + m_listItems.push_back(node2); + + GraphicsItemNode *node3 = new GraphicsItemNode(this); + node3->setPos((node1->pos() + node2->pos()) / 2); + node3->setNodeType(GraphicsItemNode::MiddleType); + m_scene->addItem(node3); + + LineItem newLineItem; + newLineItem.itemPoint = node3; + newLineItem.lineNode = LineNode(node1, node2); + m_listLines.push_back(newLineItem); + + node1 = node2; + m_scene->addItem(node1); + } + setPolygon(polygon); +} + +void GraphicsItemZone::updateZone() +{ + QPolygonF polygon; + Q_FOREACH(GraphicsItemNode *node, m_listItems) + { + polygon << node->pos(); + } + + for (int i = 0; i < m_listLines.size(); ++i) + { + m_listLines.at(i).itemPoint->setPos((m_listLines.at(i).lineNode.first->pos() + m_listLines.at(i).lineNode.second->pos()) / 2); + } + + setPolygon(polygon); +} +*/ + +AbstractWorldItem::AbstractWorldItem(QGraphicsItem *parent) + : QGraphicsItem(parent) +{ +} + +AbstractWorldItem::~AbstractWorldItem() +{ +} + +int AbstractWorldItem::type() const +{ + return Type; +} + +WorldItemPoint::WorldItemPoint(const QPointF &point, const float angle, QGraphicsItem *parent) + : AbstractWorldItem(parent), + m_angle(angle) +{ + setZValue(WORLD_POINT_LAYER); + + setPos(point); + + m_rect.setCoords(-SIZE_POINT, -SIZE_POINT, SIZE_POINT, SIZE_POINT); + + m_pen.setColor(QColor(255, 100, 10)); + m_pen.setWidth(5); + + m_selectedPen.setColor(QColor(0, 255, 0)); + m_selectedPen.setWidth(5); + + m_brush.setColor(QColor(255, 100, 10)); + m_brush.setStyle(Qt::SolidPattern); + + m_selectedBrush.setColor(QColor(0, 255, 0)); + m_selectedBrush.setStyle(Qt::SolidPattern); + + //setFlag(ItemIsSelectable); +} + +WorldItemPoint::~WorldItemPoint() +{ +} + +void WorldItemPoint::moveOn(const QPointF &offset) +{ + prepareGeometryChange(); + + setPos(pos() + offset); +} + +void WorldItemPoint::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_rect); + + // TODO + rotatedPolygon.translate(pos()); + rotatedPolygon.translate(-pivot); + + QTransform trans; + trans = trans.rotate(deltaAngle); + rotatedPolygon = trans.map(rotatedPolygon); + rotatedPolygon.translate(pivot); + + setPos(rotatedPolygon.boundingRect().center()); +} + +void WorldItemPoint::scaleOn(const QPointF &pivot, const QPointF &offset) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_rect); + + // TODO + scaledPolygon.translate(pos()); + scaledPolygon.translate(-pivot); + + QTransform trans; + trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000)); + scaledPolygon = trans.map(scaledPolygon); + scaledPolygon.translate(pivot); + + setPos(scaledPolygon.boundingRect().center()); +} + +void WorldItemPoint::turnOn(const QPointF &offset) +{ +} + +void WorldItemPoint::radiusOn(const qreal radius) +{ +} + +QPainterPath WorldItemPoint::shape() const +{ + QPainterPath path; + + path.addRect(m_rect); + + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +QRectF WorldItemPoint::boundingRect() const +{ + return m_rect; +} + +void WorldItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + // Here comes the magic: + //painter->setClipRect(option->exposedRect); + + painter->setPen(Qt::NoPen); + + if (option->state & QStyle::State_Selected) + { + painter->setBrush(m_selectedBrush); + } + else + { + painter->setBrush(m_brush); + } + + painter->drawRect(m_rect); +} + +QVariant WorldItemPoint::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionHasChanged) + { + } + return QGraphicsItem::itemChange(change, value); +} + +WorldItemPath::WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent) + : AbstractWorldItem(parent), + m_polygon(polygon) +{ + //setFlag(ItemIsSelectable); + + setZValue(WORLD_PATH_LAYER); + + m_pen.setColor(QColor(0, 0, 0)); + m_pen.setWidth(5); + + m_selectedPen.setColor(QColor(255, 0, 0)); + m_selectedPen.setWidth(5); +} + +WorldItemPath::~WorldItemPath() +{ +} + +void WorldItemPath::moveOn(const QPointF &offset) +{ + prepareGeometryChange(); + + m_polygon.translate(offset); +} + +void WorldItemPath::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_polygon); + rotatedPolygon.translate(-pivot); + + QTransform trans; + trans = trans.rotate(deltaAngle); + m_polygon = trans.map(rotatedPolygon); + + m_polygon.translate(pivot); +} + +void WorldItemPath::scaleOn(const QPointF &pivot, const QPointF &offset) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_polygon); + scaledPolygon.translate(-pivot); + + QTransform trans; + trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000)); + m_polygon = trans.map(scaledPolygon); + + m_polygon.translate(pivot); +} + +void WorldItemPath::turnOn(const QPointF &offset) +{ +} + +void WorldItemPath::radiusOn(const qreal radius) +{ +} + +QPainterPath WorldItemPath::shape() const +{ + QPainterPath path; + + path.moveTo(m_polygon.first()); + for (int i = 1; i < m_polygon.count(); ++i) + path.lineTo(m_polygon.at(i)); + + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +QRectF WorldItemPath::boundingRect() const +{ + return m_polygon.boundingRect(); +} + +void WorldItemPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + // Here comes the magic: + //painter->setClipRect(option->exposedRect); + + if (option->state & QStyle::State_Selected) + painter->setPen(m_selectedPen); + else + painter->setPen(m_pen); + + painter->drawPolyline(m_polygon); +} + +QVariant WorldItemPath::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionHasChanged) + { + } + return QGraphicsItem::itemChange(change, value); +} + +WorldItemZone::WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent) + : AbstractWorldItem(parent), + m_polygon(polygon) +{ + //setFlag(ItemIsSelectable); + + setZValue(WORLD_ZONE_LAYER); + + m_pen.setColor(QColor(20, 100, 255)); + m_pen.setWidth(0); + + m_selectedPen.setColor(QColor(255, 0, 0)); + m_selectedPen.setWidth(0); + + m_brush.setColor(QColor(20, 100, 255, 28)); + m_brush.setStyle(Qt::SolidPattern); + + m_selectedBrush.setColor(QColor(255, 0, 0, 128)); + m_selectedBrush.setStyle(Qt::SolidPattern); +} + +WorldItemZone::~WorldItemZone() +{ +} + +void WorldItemZone::moveOn(const QPointF &offset) +{ + prepareGeometryChange(); + + m_polygon.translate(offset); +} + +void WorldItemZone::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_polygon); + rotatedPolygon.translate(-pivot); + + QTransform trans; + trans = trans.rotate(deltaAngle); + m_polygon = trans.map(rotatedPolygon); + + m_polygon.translate(pivot); +} + +void WorldItemZone::scaleOn(const QPointF &pivot, const QPointF &offset) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_polygon); + scaledPolygon.translate(-pivot); + + QTransform trans; + trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000)); + m_polygon = trans.map(scaledPolygon); + + m_polygon.translate(pivot); +} + +void WorldItemZone::turnOn(const QPointF &offset) +{ +} + +void WorldItemZone::radiusOn(const qreal radius) +{ +} + +QRectF WorldItemZone::boundingRect() const +{ + return m_polygon.boundingRect(); +} + +QPainterPath WorldItemZone::shape() const +{ + QPainterPath path; + path.addPolygon(m_polygon); + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +void WorldItemZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + if (option->state & QStyle::State_Selected) + { + painter->setPen(m_selectedPen); + painter->setBrush(m_selectedBrush); + } + else + { + painter->setPen(m_pen); + painter->setBrush(m_brush); + } + + painter->drawPolygon(m_polygon); +} + +QVariant WorldItemZone::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionHasChanged) + { + } + return QGraphicsItem::itemChange(change, value); +} + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.h new file mode 100644 index 000000000..6c144518c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.h @@ -0,0 +1,237 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_SCENE_ITEM_H +#define WORLD_EDITOR_SCENE_ITEM_H + +// Project includes +#include "world_editor_global.h" + +// NeL includes + +// Qt includes +#include +#include +#include +#include +#include +#include + +namespace WorldEditor +{ +class GraphicsItemZone; +class GraphicsItemNode; + +typedef QPair LineNode; + +const int SELECTED_LAYER = 200; +const int UNSELECTED_LAYER = 100; +const int WORLD_ZONE_LAYER = 100; +const int WORLD_POINT_LAYER = 200; +const int WORLD_PATH_LAYER = 200; +const int MIDDLE_POINT_LAYER = 201; +const int EDGE_POINT_LAYER = 201; + +/* +// Deprecated +class GraphicsItemNode: public QGraphicsObject +{ + Q_OBJECT + Q_PROPERTY(QColor colorNode READ colorNode WRITE setColorNode) +public: + enum NodeType + { + EdgeType = 0, + MiddleType + }; + + GraphicsItemNode(GraphicsItemZone *itemZone, QGraphicsItem *parent = 0); + virtual ~GraphicsItemNode(); + + void setColorNode(const QColor &color); + QColor colorNode() const + { + return m_color; + } + + void setNodeType(NodeType nodeType); + + virtual QRectF boundingRect() const; + //QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + +private: + + NodeType m_type; + GraphicsItemZone *m_itemZone; + QColor m_color; +}; + +// Deprecated +class GraphicsItemZone: public QGraphicsPolygonItem +{ +public: + GraphicsItemZone(QGraphicsScene *scene, QGraphicsItem *parent = 0); + virtual ~GraphicsItemZone(); + + void scanPolygon(const QPolygonF &polygon); + void updateMiddleNode(GraphicsItemNode *node); + bool deleteEdgePoint(GraphicsItemNode *node); + //void addNode(GraphicsItemNode *node); + void updateZone(); + //QRectF boundingRect() const; + //void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + // QVariant itemChange(GraphicsItemChange change, const QVariant &value); + +private: + struct LineItem + { + GraphicsItemNode *itemPoint; + LineNode lineNode; + }; + QGraphicsScene *m_scene; + QColor m_color; + QList m_listItems; + QList m_listLines; +}; +*/ + +/* +@class WorldItemPoint +@brief +@details +*/ +class AbstractWorldItem: public QGraphicsItem +{ +public: + AbstractWorldItem(QGraphicsItem *parent = 0); + virtual ~AbstractWorldItem(); + + enum { Type = QGraphicsItem::UserType + 1 }; + + virtual void moveOn(const QPointF &offset) = 0; + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle) = 0; + // TODO: add modes: IgnoreAspectRatio, KeepAspectRatio + virtual void scaleOn(const QPointF &pivot, const QPointF &offset) = 0; + virtual void turnOn(const QPointF &offset) = 0; + virtual void radiusOn(const qreal radius) = 0; + + // Enable the use of qgraphicsitem_cast with this item. + int type() const; +}; + +/* +@class WorldItemPoint +@brief +@details +*/ +class WorldItemPoint: public AbstractWorldItem +{ +public: + WorldItemPoint(const QPointF &point, const float angle, QGraphicsItem *parent = 0); + virtual ~WorldItemPoint(); + + virtual void moveOn(const QPointF &offset); + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle); + virtual void scaleOn(const QPointF &pivot, const QPointF &offset); + virtual void turnOn(const QPointF &offset); + virtual void radiusOn(const qreal radius); + + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + +private: + + // TODO + static const int SIZE_POINT = 7; + + QPen m_pen, m_selectedPen; + QBrush m_brush, m_selectedBrush; + + QRectF m_rect; + float m_angle; +}; + +/* +@class WorldItemPath +@brief +@details +*/ +class WorldItemPath: public AbstractWorldItem +{ +public: + WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent = 0); + virtual ~WorldItemPath(); + + virtual void moveOn(const QPointF &offset); + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle); + virtual void scaleOn(const QPointF &pivot, const QPointF &offset); + virtual void turnOn(const QPointF &offset); + virtual void radiusOn(const qreal radius); + + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + QPen m_pen, m_selectedPen; + QPolygonF m_polygon; +}; + +/* +@class WorldItemZone +@brief +@details +*/ +class WorldItemZone: public AbstractWorldItem +{ +public: + WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent = 0); + virtual ~WorldItemZone(); + + virtual void moveOn(const QPointF &offset); + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle); + virtual void scaleOn(const QPointF &pivot, const QPointF &offset); + virtual void turnOn(const QPointF &offset); + virtual void radiusOn(const qreal radius); + + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + QPen m_pen, m_selectedPen; + QBrush m_brush, m_selectedBrush; + QPolygonF m_polygon; +}; + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_SCENE_ITEM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp index 132b52b70..ac46491f3 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp @@ -21,6 +21,8 @@ #include "world_editor_scene.h" #include "world_editor_misc.h" #include "world_editor_actions.h" +#include "world_editor_scene_item.h" +#include "project_settings_dialog.h" // Core #include "../core/icore.h" @@ -31,14 +33,9 @@ #include "../landscape_editor/builder_zone_base.h" // NeL includes -#include -#include -#include -#include // Qt includes #include -#include #include namespace WorldEditor @@ -57,6 +54,7 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent) m_worldEditorScene->setZoneBuilder(m_zoneBuilderBase); m_ui.graphicsView->setScene(m_worldEditorScene); + m_ui.graphicsView->setVisibleText(false); QActionGroup *sceneModeGroup = new QActionGroup(this); sceneModeGroup->addAction(m_ui.selectAction); @@ -70,20 +68,38 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent) m_ui.newWorldEditAction->setIcon(QIcon(Core::Constants::ICON_NEW)); m_ui.saveWorldEditAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); - m_primitivesModel = new PrimitivesTreeModel(); + m_primitivesModel = new PrimitivesTreeModel(this); m_ui.treePrimitivesView->setModel(m_primitivesModel); // TODO: ? m_ui.treePrimitivesView->setUndoStack(m_undoStack); m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase); + m_ui.treePrimitivesView->setWorldScene(m_worldEditorScene); createMenus(); createToolBars(); readSettings(); + QSignalMapper *m_modeMapper = new QSignalMapper(this); + connect(m_ui.selectAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.selectAction, 0); + connect(m_ui.moveAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.moveAction, 1); + connect(m_ui.rotateAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.rotateAction, 2); + connect(m_ui.scaleAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.scaleAction, 3); + connect(m_ui.turnAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.turnAction, 4); + connect(m_ui.radiusAction, SIGNAL(triggered()), m_modeMapper, SLOT(map())); + m_modeMapper->setMapping(m_ui.radiusAction, 5); + + connect(m_modeMapper, SIGNAL(mapped(int)), this, SLOT(setMode(int))); + connect(m_ui.pointsAction, SIGNAL(triggered(bool)), m_worldEditorScene, SLOT(setEnabledEditPoint(bool))); + + connect(m_ui.settingsAction, SIGNAL(triggered()), this, SLOT(openProjectSettings())); connect(m_ui.newWorldEditAction, SIGNAL(triggered()), this, SLOT(newWorldEditFile())); connect(m_ui.saveWorldEditAction, SIGNAL(triggered()), this, SLOT(saveWorldEditFile())); - } WorldEditorWindow::~WorldEditorWindow() @@ -118,6 +134,7 @@ void WorldEditorWindow::loadWorldEditFile(const QString &fileName) Utils::WorldEditList worldEditList; if (!Utils::loadWorldEditFile(fileName.toStdString(), worldEditList)) { + // TODO: add the message box return; } @@ -139,7 +156,7 @@ void WorldEditorWindow::loadWorldEditFile(const QString &fileName) m_undoStack->push(new LoadLandscapeCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel, m_zoneBuilderBase)); break; case Utils::PrimitiveType: - m_undoStack->push(new LoadRootPrimitiveCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel)); + m_undoStack->push(new LoadRootPrimitiveCommand(QString(worldEditList[i].second.c_str()), m_worldEditorScene, m_primitivesModel)); break; }; } @@ -163,15 +180,55 @@ void WorldEditorWindow::saveWorldEditFile() void WorldEditorWindow::openProjectSettings() { - /* - LandscapeEditor::ProjectSettingsDialog *dialog = new LandscapeEditor::ProjectSettingsDialog("", this); - dialog->show(); - int ok = dialog->exec(); - if (ok == QDialog::Accepted) - { - } - delete dialog; - */ + ProjectSettingsDialog *dialog = new ProjectSettingsDialog(m_zoneBuilderBase->dataPath(), this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + m_zoneBuilderBase->init(dialog->dataPath(), true); + } + delete dialog; +} + +void WorldEditorWindow::setMode(int value) +{ + switch (value) + { + case 0: + m_worldEditorScene->setModeEdit(WorldEditorScene::SelectMode); + break; + case 1: + m_worldEditorScene->setModeEdit(WorldEditorScene::MoveMode); + break; + case 2: + m_worldEditorScene->setModeEdit(WorldEditorScene::RotateMode); + break; + case 3: + m_worldEditorScene->setModeEdit(WorldEditorScene::ScaleMode); + break; + case 4: + m_worldEditorScene->setModeEdit(WorldEditorScene::TurnMode); + break; + case 5: + m_worldEditorScene->setModeEdit(WorldEditorScene::RadiusMode); + break; + } +} + +void WorldEditorWindow::showEvent(QShowEvent *showEvent) +{ + QMainWindow::showEvent(showEvent); + if (m_oglWidget != 0) + m_oglWidget->makeCurrent(); + //m_statusInfo->show(); + //m_statusBarTimer->start(100); +} + +void WorldEditorWindow::hideEvent(QHideEvent *hideEvent) +{ + QMainWindow::hideEvent(hideEvent); + //m_statusInfo->hide(); + //m_statusBarTimer->stop(); } void WorldEditorWindow::createMenus() @@ -211,6 +268,14 @@ void WorldEditorWindow::readSettings() settings->beginGroup(Constants::WORLD_EDITOR_SECTION); restoreState(settings->value(Constants::WORLD_WINDOW_STATE).toByteArray()); restoreGeometry(settings->value(Constants::WORLD_WINDOW_GEOMETRY).toByteArray()); + + // Use OpenGL graphics system instead raster graphics system + if (settings->value(Constants::WORLD_EDITOR_USE_OPENGL, true).toBool()) + { + m_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer)); + m_ui.graphicsView->setViewport(m_oglWidget); + } + settings->endGroup(); } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h index 2536bcc1c..321c46c3e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h @@ -22,6 +22,8 @@ // Qt includes #include +#include +#include namespace LandscapeEditor { @@ -52,6 +54,12 @@ private Q_SLOTS: void saveWorldEditFile(); void openProjectSettings(); + void setMode(int value); + +protected: + virtual void showEvent(QShowEvent *showEvent); + virtual void hideEvent(QHideEvent *hideEvent); + private: void createMenus(); void createToolBars(); @@ -67,6 +75,8 @@ private: QUndoStack *m_undoStack; WorldEditorScene *m_worldEditorScene; LandscapeEditor::ZoneBuilderBase *m_zoneBuilderBase; + QSignalMapper m_modeMapper; + QGLWidget *m_oglWidget; Ui::WorldEditorWindow m_ui; }; /* class WorldEditorWindow */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui index 80e4e5ace..37f56ca11 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui @@ -21,8 +21,14 @@ + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + - QGraphicsView::RubberBandDrag + QGraphicsView::NoDrag QGraphicsView::AnchorUnderMouse @@ -30,6 +36,12 @@ QGraphicsView::AnchorUnderMouse + + QGraphicsView::BoundingRectViewportUpdate + + + QGraphicsView::DontAdjustForAntialiasing|QGraphicsView::DontClipPainter + @@ -87,9 +99,6 @@ QAbstractItemView::ExtendedSelection - - true - true @@ -117,6 +126,8 @@ + + @@ -137,19 +148,22 @@ loadLand - + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png - LandSettings + Settings true + + false + S/H Land @@ -158,6 +172,9 @@ true + + false + S/H Primitives @@ -166,6 +183,9 @@ true + + false + S/H Layers @@ -174,6 +194,9 @@ true + + false + S/H Details @@ -182,6 +205,9 @@ true + + false + :/icons/ic_grid.png:/icons/ic_grid.png @@ -194,6 +220,9 @@ true + + false + S/H Grid points @@ -260,6 +289,9 @@ true + + false + :/icons/ic_nel_turn.png:/icons/ic_nel_turn.png @@ -272,6 +304,9 @@ true + + false + Radius @@ -280,10 +315,22 @@ true + + false + Edit points + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Project settings + +