diff --git a/code/nel/src/ligo/zone_bank.cpp b/code/nel/src/ligo/zone_bank.cpp index 1dc724ceb..ff24821af 100644 --- a/code/nel/src/ligo/zone_bank.cpp +++ b/code/nel/src/ligo/zone_bank.cpp @@ -19,14 +19,15 @@ #include "nel/ligo/zone_bank.h" -#ifdef NL_OS_WINDOWS - #include "nel/misc/debug.h" #include "nel/misc/file.h" #include "nel/misc/i_xml.h" #include "nel/misc/o_xml.h" + +#ifdef NL_OS_WINDOWS #define NOMINMAX #include +#endif // NL_OS_WINDOWS using namespace std; using namespace NLMISC; @@ -496,8 +497,9 @@ void CZoneBank::reset () _Selection.clear (); } +#ifdef NL_OS_WINDOWS // --------------------------------------------------------------------------- -bool CZoneBank::initFromPath(const string &sPathName, std::string &error) +bool CZoneBank::initFromPath(const std::string &sPathName, std::string &error) { char sDirBackup[512]; GetCurrentDirectory (512, sDirBackup); @@ -520,6 +522,7 @@ bool CZoneBank::initFromPath(const string &sPathName, std::string &error) SetCurrentDirectory (sDirBackup); return true; } +#endif // NL_OS_WINDOWS // --------------------------------------------------------------------------- bool CZoneBank::addElement (const std::string &elementName, std::string &error) @@ -695,5 +698,3 @@ void CZoneBank::getSelection (std::vector &SelectedElements) // *************************************************************************** } // namespace NLLIGO - -#endif // NL_OS_WINDOWS diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/images/resetproperty.png b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/images/resetproperty.png new file mode 100644 index 000000000..9048252ec Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/images/resetproperty.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.cpp b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.cpp index e619cf8cb..e5ac11f81 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.cpp @@ -101,6 +101,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -652,6 +659,7 @@ class QtCheckBoxFactoryPrivate : public EditorFactoryPrivate public: void slotPropertyChanged(QtProperty *property, bool value); void slotSetValue(bool value); + void slotResetProperty(); }; void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, bool value) @@ -662,6 +670,7 @@ void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, bool va QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtBoolEdit *editor = itEditor.next(); + editor->setStateResetButton(property->isModified()); editor->blockCheckBoxSignals(true); editor->setChecked(value); editor->blockCheckBoxSignals(false); @@ -684,6 +693,22 @@ void QtCheckBoxFactoryPrivate::slotSetValue(bool value) } } +void QtCheckBoxFactoryPrivate::slotResetProperty() +{ + QObject *object = q_ptr->sender(); + + const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtBoolPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->emitResetProperty(property); + return; + } +} + /*! \class QtCheckBoxFactory @@ -733,8 +758,10 @@ QWidget *QtCheckBoxFactory::createEditor(QtBoolPropertyManager *manager, QtPrope QWidget *parent) { QtBoolEdit *editor = d_ptr->createEditor(property, parent); + editor->setStateResetButton(property->isModified()); editor->setChecked(manager->value(property)); + connect(editor, SIGNAL(resetProperty()), this, SLOT(slotResetProperty())); connect(editor, SIGNAL(toggled(bool)), this, SLOT(slotSetValue(bool))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); @@ -1853,9 +1880,87 @@ void QtCharEditorFactory::disconnectPropertyManager(QtCharPropertyManager *manag this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); } + +class QtEnumEditWidget : public QWidget { + Q_OBJECT + +public: + QtEnumEditWidget(QWidget *parent); + + bool blockComboBoxSignals(bool block); + void addItems(const QStringList &texts); + void clearComboBox(); + void setItemIcon(int index, const QIcon &icon); + +public Q_SLOTS: + void setValue(int value); + void setStateResetButton(bool enabled); + +Q_SIGNALS: + void valueChanged(int value); + void resetProperty(); + +private: + QComboBox *m_comboBox; + QToolButton *m_defaultButton; +}; + +QtEnumEditWidget::QtEnumEditWidget(QWidget *parent) : + QWidget(parent), + m_comboBox(new QComboBox), + m_defaultButton(new QToolButton) +{ + m_comboBox->view()->setTextElideMode(Qt::ElideRight); + + QHBoxLayout *lt = new QHBoxLayout(this); + lt->setContentsMargins(0, 0, 0, 0); + lt->setSpacing(0); + lt->addWidget(m_comboBox); + + m_defaultButton->setIcon(QIcon(":/trolltech/qtpropertybrowser/images/resetproperty.png")); + m_defaultButton->setMaximumWidth(16); + + connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(valueChanged(int))); + connect(m_defaultButton, SIGNAL(clicked()), this, SIGNAL(resetProperty())); + lt->addWidget(m_defaultButton); + m_defaultButton->setEnabled(false); + setFocusProxy(m_comboBox); +} + +void QtEnumEditWidget::setValue(int value) +{ + if (m_comboBox->currentIndex() != value) + m_comboBox->setCurrentIndex(value); +} + +void QtEnumEditWidget::setStateResetButton(bool enabled) +{ + m_defaultButton->setEnabled(enabled); +} + +bool QtEnumEditWidget::blockComboBoxSignals(bool block) +{ + return m_comboBox->blockSignals(block); +} + +void QtEnumEditWidget::addItems(const QStringList &texts) +{ + m_comboBox->addItems(texts); +} + +void QtEnumEditWidget::clearComboBox() +{ + m_comboBox->clear(); +} + +void QtEnumEditWidget::setItemIcon(int index, const QIcon &icon) +{ + m_comboBox->setItemIcon(index, icon); +} + // QtEnumEditorFactory -class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate +class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate { QtEnumEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtEnumEditorFactory) @@ -1865,19 +1970,36 @@ public: void slotEnumNamesChanged(QtProperty *property, const QStringList &); void slotEnumIconsChanged(QtProperty *property, const QMap &); void slotSetValue(int value); + void slotResetProperty(); }; +void QtEnumEditorFactoryPrivate::slotResetProperty() +{ + QObject *object = q_ptr->sender(); + const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtEnumPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->emitResetProperty(property); + return; + } +} + void QtEnumEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; - QListIterator itEditor(m_createdEditors[property]); + QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { - QComboBox *editor = itEditor.next(); - editor->blockSignals(true); - editor->setCurrentIndex(value); - editor->blockSignals(false); + QtEnumEditWidget *editor = itEditor.next(); + editor->setStateResetButton(property->isModified()); + editor->blockComboBoxSignals(true); + editor->setValue(value); + editor->blockComboBoxSignals(false); } } @@ -1893,17 +2015,17 @@ void QtEnumEditorFactoryPrivate::slotEnumNamesChanged(QtProperty *property, QMap enumIcons = manager->enumIcons(property); - QListIterator itEditor(m_createdEditors[property]); + QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { - QComboBox *editor = itEditor.next(); - editor->blockSignals(true); - editor->clear(); + QtEnumEditWidget *editor = itEditor.next(); + editor->blockComboBoxSignals(true); + editor->clearComboBox(); editor->addItems(enumNames); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); - editor->setCurrentIndex(manager->value(property)); - editor->blockSignals(false); + editor->setValue(manager->value(property)); + editor->blockComboBoxSignals(false); } } @@ -1918,23 +2040,23 @@ void QtEnumEditorFactoryPrivate::slotEnumIconsChanged(QtProperty *property, return; const QStringList enumNames = manager->enumNames(property); - QListIterator itEditor(m_createdEditors[property]); + QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { - QComboBox *editor = itEditor.next(); - editor->blockSignals(true); + QtEnumEditWidget *editor = itEditor.next(); + editor->blockComboBoxSignals(true); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); - editor->setCurrentIndex(manager->value(property)); - editor->blockSignals(false); + editor->setValue(manager->value(property)); + editor->blockComboBoxSignals(false); } } void QtEnumEditorFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); - const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); - for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtEnumPropertyManager *manager = q_ptr->propertyManager(property); @@ -1995,18 +2117,19 @@ void QtEnumEditorFactory::connectPropertyManager(QtEnumPropertyManager *manager) QWidget *QtEnumEditorFactory::createEditor(QtEnumPropertyManager *manager, QtProperty *property, QWidget *parent) { - QComboBox *editor = d_ptr->createEditor(property, parent); + QtEnumEditWidget *editor = d_ptr->createEditor(property, parent); editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - editor->view()->setTextElideMode(Qt::ElideRight); QStringList enumNames = manager->enumNames(property); editor->addItems(enumNames); QMap enumIcons = manager->enumIcons(property); const int enumNamesCount = enumNames.count(); for (int i = 0; i < enumNamesCount; i++) editor->setItemIcon(i, enumIcons.value(i)); - editor->setCurrentIndex(manager->value(property)); + editor->setValue(manager->value(property)); + editor->setStateResetButton(property->isModified()); - connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int))); + connect(editor, SIGNAL(resetProperty()), this, SLOT(slotResetProperty())); + connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; @@ -2601,6 +2724,267 @@ void QtFontEditorFactory::disconnectPropertyManager(QtFontPropertyManager *manag disconnect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); } +class QtTextEditWidget : public QWidget { + Q_OBJECT + +public: + QtTextEditWidget(QWidget *parent); + + bool eventFilter(QObject *obj, QEvent *ev); + +public Q_SLOTS: + void setValue(const QString &value); + void setStateResetButton(bool enabled); + +private Q_SLOTS: + void buttonClicked(); + +Q_SIGNALS: + void valueChanged(const QString &value); + void resetProperty(); + +private: + QLineEdit *m_lineEdit; + QToolButton *m_defaultButton; + QToolButton *m_button; +}; + +QtTextEditWidget::QtTextEditWidget(QWidget *parent) : + QWidget(parent), + m_lineEdit(new QLineEdit), + m_defaultButton(new QToolButton), + m_button(new QToolButton) +{ + QHBoxLayout *lt = new QHBoxLayout(this); + lt->setContentsMargins(0, 0, 0, 0); + lt->setSpacing(0); + lt->addWidget(m_lineEdit); + m_lineEdit->setReadOnly(true); + + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(20); + m_button->setText(tr("...")); + m_button->installEventFilter(this); + + setFocusProxy(m_button); + setFocusPolicy(m_button->focusPolicy()); + + m_defaultButton->setIcon(QIcon(":/trolltech/qtpropertybrowser/images/resetproperty.png")); + m_defaultButton->setMaximumWidth(16); + + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + connect(m_defaultButton, SIGNAL(clicked()), this, SIGNAL(resetProperty())); + lt->addWidget(m_button); + lt->addWidget(m_defaultButton); + m_defaultButton->setEnabled(false); +} + +void QtTextEditWidget::setValue(const QString &value) +{ + if (m_lineEdit->text() != value) + m_lineEdit->setText(value); +} + +void QtTextEditWidget::setStateResetButton(bool enabled) +{ + m_defaultButton->setEnabled(enabled); +} + +void QtTextEditWidget::buttonClicked() +{ + QGridLayout *gridLayout; + QPlainTextEdit *plainTextEdit; + QDialogButtonBox *buttonBox; + QDialog *dialog; + + dialog = new QDialog(this); + dialog->resize(400, 300); + gridLayout = new QGridLayout(dialog); + plainTextEdit = new QPlainTextEdit(dialog); + + gridLayout->addWidget(plainTextEdit, 0, 0, 1, 1); + + buttonBox = new QDialogButtonBox(dialog); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + + gridLayout->addWidget(buttonBox, 1, 0, 1, 1); + + QObject::connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + + plainTextEdit->textCursor().insertText(m_lineEdit->text()); + + dialog->setModal(true); + dialog->show(); + int result = dialog->exec(); + + if (result == QDialog::Accepted) + { + QString newText = plainTextEdit->document()->toPlainText(); + + setValue(newText); + if (plainTextEdit->document()->isModified()) + Q_EMIT valueChanged(newText); + } + + delete dialog; +} + +bool QtTextEditWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_button) { + switch (ev->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate + switch (static_cast(ev)->key()) { + case Qt::Key_Escape: + case Qt::Key_Enter: + case Qt::Key_Return: + ev->ignore(); + return true; + default: + break; + } + } + break; + default: + break; + } + } + return QWidget::eventFilter(obj, ev); +} + +// QtLineEditFactory + +class QtTextEditorFactoryPrivate : public EditorFactoryPrivate +{ + QtTextEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtTextEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QString &value); + void slotSetValue(const QString &value); + void slotResetProperty(); +}; + +void QtTextEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QString &value) +{ + const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); + if (it == m_createdEditors.end()) + return; + QListIterator itEditor(it.value()); + + while (itEditor.hasNext()) + { + QtTextEditWidget *editor = itEditor.next(); + editor->setValue(value); + editor->setStateResetButton(property->isModified()); + } +} + +void QtTextEditorFactoryPrivate::slotSetValue(const QString &value) +{ + QObject *object = q_ptr->sender(); + const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtTextPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +void QtTextEditorFactoryPrivate::slotResetProperty() +{ + QObject *object = q_ptr->sender(); + const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtTextPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->emitResetProperty(property); + return; + } +} + +/*! + \class QtTextEditFactory + + \brief The QtTextEditFactory class provides QTextEdit widgets for + properties created by QtStringPropertyManager objects. + + \sa QtAbstractEditorFactory, QtStringPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtTextEditorFactory::QtTextEditorFactory(QObject *parent) + : QtAbstractEditorFactory(parent) +{ + d_ptr = new QtTextEditorFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtTextEditorFactory::~QtTextEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtTextEditorFactory::connectPropertyManager(QtTextPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtTextEditorFactory::createEditor(QtTextPropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + + QtTextEditWidget *editor = d_ptr->createEditor(property, parent); + + editor->setValue(manager->value(property)); + editor->setStateResetButton(property->isModified()); + + connect(editor, SIGNAL(resetProperty()), this, SLOT(slotResetProperty())); + connect(editor, SIGNAL(valueChanged(QString)), this, SLOT(slotSetValue(QString))); + connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtTextEditorFactory::disconnectPropertyManager(QtTextPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); +} + #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.h b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.h index 47e7b507f..fe47d5f16 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.h +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qteditorfactory.h @@ -186,6 +186,7 @@ private: Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(bool)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_func(), void slotResetProperty()) }; class QtDoubleSpinBoxFactoryPrivate; @@ -373,6 +374,7 @@ private: const QMap &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_func(), void slotResetProperty()) }; class QtCursorEditorFactoryPrivate; @@ -441,6 +443,29 @@ private: Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QFont &)) }; +class QtTextEditorFactoryPrivate; + +class QT_QTPROPERTYBROWSER_EXPORT QtTextEditorFactory : public QtAbstractEditorFactory +{ + Q_OBJECT +public: + QtTextEditorFactory(QObject *parent = 0); + ~QtTextEditorFactory(); +protected: + void connectPropertyManager(QtTextPropertyManager *manager); + QWidget *createEditor(QtTextPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtTextPropertyManager *manager); +private: + QtTextEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtTextEditorFactory) + Q_DISABLE_COPY(QtTextEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_func(), void slotResetProperty()) +}; + #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.cpp b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.cpp index e8c103d9b..9b7d98b09 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.cpp @@ -808,6 +808,11 @@ QtProperty *QtAbstractPropertyManager::addProperty(const QString &name) return property; } +void QtAbstractPropertyManager::emitResetProperty(QtProperty *property) +{ + emit resetProperty(property); +} + /*! Creates a property. diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.h b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.h index 35b7ac0f8..5b63d3917 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.h +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.h @@ -170,6 +170,7 @@ public: void clear() const; QtProperty *addProperty(const QString &name = QString()); + void emitResetProperty(QtProperty *property); Q_SIGNALS: void propertyInserted(QtProperty *property, @@ -177,6 +178,7 @@ Q_SIGNALS: void propertyChanged(QtProperty *property); void propertyRemoved(QtProperty *property, QtProperty *parent); void propertyDestroyed(QtProperty *property); + void resetProperty(QtProperty *property); protected: virtual bool hasValue(const QtProperty *property) const; virtual QIcon valueIcon(const QtProperty *property) const; diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.qrc b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.qrc index 4f91ab782..50c2479f2 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.qrc +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowser.qrc @@ -18,6 +18,7 @@ images/cursor-vsplit.png images/cursor-wait.png images/cursor-whatsthis.png + images/resetproperty.png diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils.cpp b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils.cpp index ce198bfca..9b482a569 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include @@ -260,16 +261,25 @@ QString QtPropertyBrowserUtils::fontValueText(const QFont &f) QtBoolEdit::QtBoolEdit(QWidget *parent) : QWidget(parent), m_checkBox(new QCheckBox(this)), + m_defaultButton(new QToolButton(this)), m_textVisible(true) { + m_defaultButton->setIcon(QIcon(":/trolltech/qtpropertybrowser/images/resetproperty.png")); + m_defaultButton->setMaximumWidth(16); + m_defaultButton->setEnabled(false); + QHBoxLayout *lt = new QHBoxLayout; if (QApplication::layoutDirection() == Qt::LeftToRight) lt->setContentsMargins(4, 0, 0, 0); else lt->setContentsMargins(0, 0, 4, 0); lt->addWidget(m_checkBox); + lt->addWidget(m_defaultButton); setLayout(lt); + connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + connect(m_defaultButton, SIGNAL(clicked()), this, SIGNAL(resetProperty())); + setFocusProxy(m_checkBox); m_checkBox->setText(QString()); } @@ -293,6 +303,11 @@ void QtBoolEdit::setCheckState(Qt::CheckState state) m_checkBox->setCheckState(state); } +void QtBoolEdit::setStateResetButton(bool enabled) +{ + m_defaultButton->setEnabled(enabled); +} + bool QtBoolEdit::isChecked() const { return m_checkBox->isChecked(); diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils_p.h b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils_p.h index dca4b8c37..66156c5d4 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils_p.h +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertybrowserutils_p.h @@ -110,6 +110,7 @@ QT_BEGIN_NAMESPACE class QMouseEvent; class QCheckBox; +class QToolButton; class QLineEdit; class QtCursorDatabase @@ -154,6 +155,7 @@ public: Qt::CheckState checkState() const; void setCheckState(Qt::CheckState state); + void setStateResetButton(bool enabled); bool isChecked() const; void setChecked(bool c); @@ -162,12 +164,14 @@ public: Q_SIGNALS: void toggled(bool); + void resetProperty(); protected: void mousePressEvent(QMouseEvent * event); private: QCheckBox *m_checkBox; + QToolButton *m_defaultButton; bool m_textVisible; }; diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.cpp b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.cpp index 20de19786..fe8ea92c9 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.cpp @@ -99,6 +99,7 @@ #include #include #include +#include #include #include @@ -6457,6 +6458,20 @@ void QtCursorPropertyManager::uninitializeProperty(QtProperty *property) d_ptr->m_values.remove(property); } +QString QtTextPropertyManager::valueText(const QtProperty *property) const +{ + QString text = QtStringPropertyManager::valueText(property); + for (int i = 0; i < text.size(); i++) + { + if (text.at(i) == '\n') + { + QStringRef ret(&text, 0, i); + return ret.toString() + " ..."; + } + } + return text; +} + #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.h b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.h index 709f2abf7..a19dd6e03 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.h +++ b/code/nel/tools/3d/object_viewer_qt/src/3rdparty/qtpropertybrowser/qtpropertymanager.h @@ -160,8 +160,10 @@ public: public Q_SLOTS: void setValue(QtProperty *property, bool val); + Q_SIGNALS: void valueChanged(QtProperty *property, bool val); + protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; @@ -789,6 +791,16 @@ private: Q_DISABLE_COPY(QtCursorPropertyManager) }; +class QT_QTPROPERTYBROWSER_EXPORT QtTextPropertyManager : public QtStringPropertyManager +{ + Q_OBJECT +public: + QtTextPropertyManager(QObject *parent = 0):QtStringPropertyManager(parent) {} + +protected: + virtual QString valueText(const QtProperty *property) const; +}; + #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt index 7903114d1..f38c15502 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt @@ -1,21 +1,23 @@ -ADD_SUBDIRECTORY(core) -ADD_SUBDIRECTORY(example) -ADD_SUBDIRECTORY(ovqt_sheet_builder) -ADD_SUBDIRECTORY(landscape_editor) -ADD_SUBDIRECTORY(log) -ADD_SUBDIRECTORY(disp_sheet_id) -ADD_SUBDIRECTORY(object_viewer) -ADD_SUBDIRECTORY(georges_editor) - -IF(WITH_GUI) - ADD_SUBDIRECTORY(gui_editor) -ENDIF(WITH_GUI) - -ADD_SUBDIRECTORY(translation_manager) -ADD_SUBDIRECTORY(bnp_manager) -# Note: Temporarily disabled until development continues. -#ADD_SUBDIRECTORY(zone_painter) -# Ryzom Specific Plugins -IF(WITH_RYZOM AND WITH_RYZOM_TOOLS) - ADD_SUBDIRECTORY(mission_compiler) -ENDIF(WITH_RYZOM AND WITH_RYZOM_TOOLS) +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(example) +ADD_SUBDIRECTORY(ovqt_sheet_builder) +ADD_SUBDIRECTORY(landscape_editor) +ADD_SUBDIRECTORY(log) +ADD_SUBDIRECTORY(disp_sheet_id) +ADD_SUBDIRECTORY(object_viewer) +ADD_SUBDIRECTORY(georges_editor) + +ADD_SUBDIRECTORY(world_editor) +IF(WITH_GUI) + ADD_SUBDIRECTORY(gui_editor) +ENDIF(WITH_GUI) + +ADD_SUBDIRECTORY(translation_manager) +ADD_SUBDIRECTORY(bnp_manager) +# Note: Temporarily disabled until development continues. +#ADD_SUBDIRECTORY(zone_painter) + +# Ryzom Specific Plugins +IF(WITH_RYZOM AND WITH_RYZOM_TOOLS) + ADD_SUBDIRECTORY(mission_compiler) +ENDIF(WITH_RYZOM AND WITH_RYZOM_TOOLS) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/core/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/core/CMakeLists.txt index 17172c488..a2574a748 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/core/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/core/CMakeLists.txt @@ -1,73 +1,73 @@ -INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${LIBXML2_INCLUDE_DIR} - ${QT_INCLUDES}) - -FILE(GLOB SRC *.cpp *.h) -SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) - -SET(OVQT_CORE_PLUGIN_HDR - icore.h - icontext.h - icore_listener.h - ioptions_page.h - core_plugin.h - core.h - main_window.h - menu_manager.h - context_manager.h - settings_dialog.h - search_paths_settings_page.h - general_settings_page.h - plugin_view_dialog.h -) - -SET(OVQT_CORE_PLUGIN_UIS settings_dialog.ui - plugin_view_dialog.ui - general_settings_page.ui - search_paths_settings_page.ui -) - -SET(OVQT_CORE_PLUGIN_RCS core.qrc) - -SET(QT_USE_QTGUI TRUE) -SET(QT_USE_QTOPENGL TRUE) - -QT4_ADD_RESOURCES(OVQT_CORE_PLUGIN_RC_SRCS ${OVQT_CORE_PLUGIN_RCS}) -QT4_WRAP_CPP(OVQT_CORE_PLUGIN_MOC_SRC ${OVQT_CORE_PLUGIN_HDR}) -QT4_WRAP_UI(OVQT_CORE_PLUGIN_UI_HDRS ${OVQT_CORE_PLUGIN_UIS}) - -SOURCE_GROUP(QtResources FILES ${OVQT_CORE_PLUGIN_UIS} ${OVQT_CORE_PLUGIN_RCS}) -SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_CORE_PLUGIN_UI_HDRS}) -SOURCE_GROUP(QtGeneratedMocSrc FILES ${OVQT_CORE_PLUGIN_MOC_SRC}) -SOURCE_GROUP("Core Plugin" FILES ${SRC}) -SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) - -ADD_LIBRARY(ovqt_plugin_core SHARED ${SRC} ${OVQT_CORE_PLUGIN_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_CORE_PLUGIN_RC_SRCS} ${OVQT_CORE_PLUGIN_UI_HDRS}) - -TARGET_LINK_LIBRARIES(ovqt_plugin_core nelmisc ${QT_LIBRARIES}) - -NL_DEFAULT_PROPS(ovqt_plugin_core "NeL, Tools, 3D: Object Viewer Qt Plugin: Core") -NL_ADD_RUNTIME_FLAGS(ovqt_plugin_core) -NL_ADD_LIB_SUFFIX(ovqt_plugin_core) - -ADD_DEFINITIONS(-DCORE_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) - -IF(WIN32) - IF(WITH_INSTALL_LIBRARIES) - INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) - ELSE(WITH_INSTALL_LIBRARIES) - INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) - ENDIF(WITH_INSTALL_LIBRARIES) -ELSE(WIN32) - IF(WITH_INSTALL_LIBRARIES) - INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT tools3d) - ELSE(WITH_INSTALL_LIBRARIES) - INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT tools3d) - ENDIF(WITH_INSTALL_LIBRARIES) -ENDIF(WIN32) - -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ovqt_plugin_core.xml DESTINATION ${OVQT_PLUGIN_SPECS_DIR} COMPONENT tools3d) - +INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${QT_INCLUDES}) + +FILE(GLOB SRC *.cpp *.h) +SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) + +SET(OVQT_CORE_PLUGIN_HDR + icore.h + icontext.h + icore_listener.h + ioptions_page.h + core_plugin.h + core.h + main_window.h + menu_manager.h + context_manager.h + settings_dialog.h + search_paths_settings_page.h + general_settings_page.h + plugin_view_dialog.h +) + +SET(OVQT_CORE_PLUGIN_UIS settings_dialog.ui + plugin_view_dialog.ui + general_settings_page.ui + search_paths_settings_page.ui +) + +SET(OVQT_CORE_PLUGIN_RCS core.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES(OVQT_CORE_PLUGIN_RC_SRCS ${OVQT_CORE_PLUGIN_RCS}) +QT4_WRAP_CPP(OVQT_CORE_PLUGIN_MOC_SRC ${OVQT_CORE_PLUGIN_HDR}) +QT4_WRAP_UI(OVQT_CORE_PLUGIN_UI_HDRS ${OVQT_CORE_PLUGIN_UIS}) + +SOURCE_GROUP(QtResources FILES ${OVQT_CORE_PLUGIN_UIS} ${OVQT_CORE_PLUGIN_RCS}) +SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_CORE_PLUGIN_UI_HDRS}) +SOURCE_GROUP(QtGeneratedMocSrc FILES ${OVQT_CORE_PLUGIN_MOC_SRC}) +SOURCE_GROUP("Core Plugin" FILES ${SRC}) +SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) + +ADD_LIBRARY(ovqt_plugin_core SHARED ${SRC} ${OVQT_CORE_PLUGIN_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_CORE_PLUGIN_RC_SRCS} ${OVQT_CORE_PLUGIN_UI_HDRS}) + +TARGET_LINK_LIBRARIES(ovqt_plugin_core nelmisc ${QT_LIBRARIES}) + +NL_DEFAULT_PROPS(ovqt_plugin_core "NeL, Tools, 3D: Object Viewer Qt Plugin: Core") +NL_ADD_RUNTIME_FLAGS(ovqt_plugin_core) +NL_ADD_LIB_SUFFIX(ovqt_plugin_core) + +ADD_DEFINITIONS(-DCORE_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) + +IF(WIN32) + IF(WITH_INSTALL_LIBRARIES) + INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) + ELSE(WITH_INSTALL_LIBRARIES) + INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) + ENDIF(WITH_INSTALL_LIBRARIES) +ELSE(WIN32) + IF(WITH_INSTALL_LIBRARIES) + INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT tools3d) + ELSE(WITH_INSTALL_LIBRARIES) + INSTALL(TARGETS ovqt_plugin_core LIBRARY DESTINATION ${NL_LIB_PREFIX} RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT tools3d) + ENDIF(WITH_INSTALL_LIBRARIES) +ENDIF(WIN32) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ovqt_plugin_core.xml DESTINATION ${OVQT_PLUGIN_SPECS_DIR} COMPONENT tools3d) + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/CMakeLists.txt index dc7a8a541..222a9c182 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/CMakeLists.txt @@ -1,50 +1,59 @@ -INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${LIBXML2_INCLUDE_DIR} - ${QT_INCLUDES}) - -FILE(GLOB SRC *.cpp *.h) - -SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) - -SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_HDR landscape_editor_plugin.h - landscape_editor_window.h -) - -SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS landscape_editor_window.ui -) - -SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_RCS landscape_editor.qrc) - -SET(QT_USE_QTGUI TRUE) -SET(QT_USE_QTOPENGL TRUE) - -QT4_ADD_RESOURCES(OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS ${OVQT_PLUGIN_LANDSCAPE_EDITOR_RCS}) -QT4_WRAP_CPP(OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC ${OVQT_PLUGIN_LANDSCAPE_EDITOR_HDR}) -QT4_WRAP_UI(OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS}) - -SOURCE_GROUP(QtResources FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS}) -SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS}) -SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS) -SOURCE_GROUP("Landscape Editor Plugin" FILES ${SRC}) -SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) - -ADD_LIBRARY(ovqt_plugin_landscape_editor MODULE ${SRC} - ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} - ${OVQT_EXT_SYS_SRC} - ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS} - ${OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS}) - -TARGET_LINK_LIBRARIES(ovqt_plugin_landscape_editor ovqt_plugin_core nelmisc nel3d ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY}) - -NL_DEFAULT_PROPS(ovqt_plugin_landscape_editor "NeL, Tools, 3D: Object Viewer Qt Plugin: Landscape Editor") -NL_ADD_RUNTIME_FLAGS(ovqt_plugin_landscape_editor) -NL_ADD_LIB_SUFFIX(ovqt_plugin_landscape_editor) - -ADD_DEFINITIONS(-DLANDSCAPE_EDITOR_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) - -INSTALL(TARGETS ovqt_plugin_landscape_editor LIBRARY DESTINATION ${OVQT_PLUGIN_DIR} RUNTIME DESTINATION ${NL_BIN_PREFIX} ARCHIVE DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) -#INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ovqt_plugin_landscape_editor.xml DESTINATION ${OVQT_PLUGIN_SPECS_DIR} COMPONENT tools3d) - +INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${QT_INCLUDES}) + +FILE(GLOB SRC *.cpp *.h) + +SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) + +SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_HDR landscape_editor_plugin.h + landscape_editor_window.h + landscape_scene_base.h + landscape_scene.h + list_zones_model.h + list_zones_widget.h + landscape_view.h + project_settings_dialog.h + snapshot_dialog.h +) + +SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS landscape_editor_window.ui + list_zones_widget.ui + project_settings_dialog.ui + shapshot_dialog.ui +) + +SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_RCS landscape_editor.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES(OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS ${OVQT_PLUGIN_LANDSCAPE_EDITOR_RCS}) +QT4_WRAP_CPP(OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC ${OVQT_PLUGIN_LANDSCAPE_EDITOR_HDR}) +QT4_WRAP_UI(OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS}) + +SOURCE_GROUP(QtResources FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS}) +SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS}) +SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS) +SOURCE_GROUP("Landscape Editor Plugin" FILES ${SRC}) +SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) + +ADD_LIBRARY(ovqt_plugin_landscape_editor SHARED ${SRC} + ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} + ${OVQT_EXT_SYS_SRC} + ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS} + ${OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS}) + +TARGET_LINK_LIBRARIES(ovqt_plugin_landscape_editor ovqt_plugin_core nelmisc nel3d nelgeorges nelligo ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY}) + +NL_DEFAULT_PROPS(ovqt_plugin_landscape_editor "NeL, Tools, 3D: Object Viewer Qt Plugin: Landscape Editor") +NL_ADD_RUNTIME_FLAGS(ovqt_plugin_landscape_editor) +NL_ADD_LIB_SUFFIX(ovqt_plugin_landscape_editor) + +ADD_DEFINITIONS(-DLANDSCAPE_EDITOR_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) + +INSTALL(TARGETS ovqt_plugin_landscape_editor LIBRARY DESTINATION ${OVQT_PLUGIN_DIR} RUNTIME DESTINATION ${NL_BIN_PREFIX} ARCHIVE DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) +#INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ovqt_plugin_landscape_editor.xml DESTINATION ${OVQT_PLUGIN_SPECS_DIR} COMPONENT tools3d) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.cpp new file mode 100644 index 000000000..35e843481 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.cpp @@ -0,0 +1,540 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "builder_zone.h" +#include "list_zones_widget.h" +#include "landscape_actions.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ +int LandCounter = 0; + +ZoneBuilder::ZoneBuilder(LandscapeScene *landscapeScene, ListZonesWidget *listZonesWidget, QUndoStack *undoStack) + : m_currentZoneRegion(-1), + m_pixmapDatabase(0), + m_listZonesWidget(listZonesWidget), + m_landscapeScene(landscapeScene), + m_undoStack(undoStack) +{ + nlassert(m_landscapeScene); + m_pixmapDatabase = new PixmapDatabase(); + m_lastPathName = ""; +} + +ZoneBuilder::~ZoneBuilder() +{ + delete m_pixmapDatabase; +} + +bool ZoneBuilder::init(const QString &pathName, bool displayProgress) +{ + if (pathName.isEmpty()) + return false; + if (pathName != m_lastPathName) + { + m_lastPathName = pathName; + QString zoneBankPath = pathName; + zoneBankPath += "/zoneligos/"; + + // Init the ZoneBank + m_zoneBank.reset(); + if (!initZoneBank (zoneBankPath)) + { + m_zoneBank.reset(); + return false; + } + // Construct the DataBase from the ZoneBank + QString zoneBitmapPath = pathName; + zoneBitmapPath += "/zonebitmaps/"; + m_pixmapDatabase->reset(); + if (!m_pixmapDatabase->loadPixmaps(zoneBitmapPath, m_zoneBank, displayProgress)) + { + m_zoneBank.reset(); + return false; + } + } + return true; +} + +void ZoneBuilder::actionLigoTile(const LigoData &data, const ZonePosition &zonePos) +{ + if (m_undoStack == 0) + return; + + checkBeginMacro(); + // nlinfo(QString("%1 %2 %3 (%4 %5)").arg(data.zoneName.c_str()).arg(zonePos.x).arg(zonePos.y).arg(data.posX).arg(data.posY).toStdString().c_str()); + m_zonePositionList.push_back(zonePos); + m_undoStack->push(new LigoTileCommand(data, zonePos, this, m_landscapeScene)); +} + +void ZoneBuilder::actionLigoMove(uint index, sint32 deltaX, sint32 deltaY) +{ + if (m_undoStack == 0) + return; + + checkBeginMacro(); + //m_undoStack->push(new LigoMoveCommand(index, deltaX, deltaY, this)); +} + +void ZoneBuilder::actionLigoResize(uint index, sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY) +{ + if (m_undoStack == 0) + return; + + checkBeginMacro(); + // nlinfo(QString("minX=%1 maxX=%2 minY=%3 maxY=%4").arg(newMinX).arg(newMaxX).arg(newMinY).arg(newMaxY).toStdString().c_str()); + m_undoStack->push(new LigoResizeCommand(index, newMinX, newMaxX, newMinY, newMaxY, this)); +} + +void ZoneBuilder::addZone(sint32 posX, sint32 posY) +{ + // Read-only mode + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeMap.empty()) + return; + + // Check zone name + std::string zoneName = m_listZonesWidget->currentZoneName().toStdString(); + if (zoneName.empty()) + return; + + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + builderZoneRegion->init(this); + + uint8 rot = uint8(m_listZonesWidget->currentRot()); + uint8 flip = uint8(m_listZonesWidget->currentFlip()); + + NLLIGO::CZoneBankElement *zoneBankElement = getZoneBank().getElementByZoneName(zoneName); + + m_titleAction = QString("Add zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + m_zonePositionList.clear(); + if (m_listZonesWidget->isForce()) + { + builderZoneRegion->addForce(posX, posY, rot, flip, zoneBankElement); + } + else + { + if (m_listZonesWidget->isNotPropogate()) + builderZoneRegion->addNotPropagate(posX, posY, rot, flip, zoneBankElement); + else + builderZoneRegion->add(posX, posY, rot, flip, zoneBankElement); + } + checkEndMacro(); +} + +void ZoneBuilder::addTransition(const sint32 posX, const sint32 posY) +{ + // Read-only mode + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeMap.empty()) + return; + + m_titleAction = QString("Transition zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + m_zonePositionList.clear(); + + nlinfo(QString("trans %1,%2").arg(posX).arg(posY).toStdString().c_str()); + + sint32 x = (sint32)floor(float(posX) / m_landscapeScene->cellSize()); + sint32 y = (sint32)floor(float(posY) / m_landscapeScene->cellSize()); + sint32 k; + + // Detect if we are in a transition square to switch + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + builderZoneRegion->init(this); + const NLLIGO::CZoneRegion &zoneRegion = currentZoneRegion()->ligoZoneRegion(); + bool bCutEdgeTouched = false; + for (uint8 transPos = 0; transPos < 4; ++transPos) + { + uint ce = zoneRegion.getCutEdge(x, y, transPos); + + if ((ce > 0) && (ce < 3)) + for (k = 0; k < 2; ++k) + { + float xTrans, yTrans; + + if ((transPos == 0) || (transPos == 1)) + { + if (ce == 1) + xTrans = m_landscapeScene->cellSize() / 3.0f; + else + xTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f; + } + else + { + if (transPos == 2) + xTrans = 0; + else + xTrans = m_landscapeScene->cellSize(); + } + xTrans += x * m_landscapeScene->cellSize(); + + if ((transPos == 2) || (transPos == 3)) + { + if (ce == 1) + yTrans = m_landscapeScene->cellSize() / 3.0f; + else + yTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f; + } + else + { + if (transPos == 1) + yTrans = 0; + else + yTrans = m_landscapeScene->cellSize(); + } + yTrans += y * m_landscapeScene->cellSize(); + + if ((posX >= (xTrans - m_landscapeScene->cellSize() / 12.0f)) && + (posX <= (xTrans + m_landscapeScene->cellSize() / 12.0f)) && + (posY >= (yTrans - m_landscapeScene->cellSize() / 12.0f)) && + (posY <= (yTrans + m_landscapeScene->cellSize() / 12.0f))) + { + builderZoneRegion->invertCutEdge (x, y, transPos); + bCutEdgeTouched = true; + } + ce = 3 - ce; + } + } + + // If not clicked to change the cutEdge so the user want to change the transition + if (!bCutEdgeTouched) + { + builderZoneRegion->cycleTransition (x, y); + } + checkEndMacro(); +} + +void ZoneBuilder::delZone(const sint32 posX, const sint32 posY) +{ + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeMap.empty()) + return; + + m_titleAction = QString("Del zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + + builderZoneRegion->init(this); + builderZoneRegion->del(posX, posY); + checkEndMacro(); +} + +int ZoneBuilder::createZoneRegion() +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); + landItem.builderZoneRegion->init(this); + landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + + m_landscapeMap.insert(LandCounter, landItem); + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(LandCounter); + + calcMask(); + return LandCounter++; +} + +int ZoneBuilder::createZoneRegion(const QString &fileName) +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.zoneRegionObject->load(fileName.toStdString()); + + if (checkOverlaps(landItem.zoneRegionObject->ligoZoneRegion())) + { + delete landItem.zoneRegionObject; + return -1; + } + landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); + landItem.builderZoneRegion->init(this); + + m_landscapeScene->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion()); + landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + m_landscapeMap.insert(LandCounter, landItem); + + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(LandCounter); + + calcMask(); + return LandCounter++; +} + +void ZoneBuilder::deleteZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + if (m_landscapeMap.value(id).rectItem != 0) + delete m_landscapeMap.value(id).rectItem; + m_landscapeScene->delZoneRegion(m_landscapeMap.value(id).zoneRegionObject->ligoZoneRegion()); + delete m_landscapeMap.value(id).zoneRegionObject; + delete m_landscapeMap.value(id).builderZoneRegion; + m_landscapeMap.remove(id); + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +void ZoneBuilder::setCurrentZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + if (currentIdZoneRegion() != -1) + { + NLLIGO::CZoneRegion &ligoRegion = m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject->ligoZoneRegion(); + m_landscapeMap[m_currentZoneRegion].rectItem = m_landscapeScene->createLayerBlackout(ligoRegion); + } + delete m_landscapeMap.value(id).rectItem; + m_landscapeMap[id].rectItem = 0; + m_currentZoneRegion = id; + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +int ZoneBuilder::currentIdZoneRegion() const +{ + return m_currentZoneRegion; +} + +ZoneRegionObject *ZoneBuilder::currentZoneRegion() const +{ + ZoneRegionObject *result = 0; + if (m_landscapeMap.contains(m_currentZoneRegion)) + result = m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject; + + return result; +} + +int ZoneBuilder::countZoneRegion() const +{ + return m_landscapeMap.size(); +} + +ZoneRegionObject *ZoneBuilder::zoneRegion(int id) const +{ + ZoneRegionObject *result = 0; + if (m_landscapeMap.contains(id)) + result = m_landscapeMap.value(id).zoneRegionObject; + + return result; +} + +bool ZoneBuilder::ligoData(LigoData &data, const ZonePosition &zonePos) +{ + if (m_landscapeMap.contains(zonePos.region)) + { + m_landscapeMap.value(zonePos.region).zoneRegionObject->ligoData(data, zonePos.x, zonePos.y); + return true; + } + return false; +} + +void ZoneBuilder::setLigoData(LigoData &data, const ZonePosition &zonePos) +{ + if (m_landscapeMap.contains(zonePos.region)) + m_landscapeMap.value(zonePos.region).zoneRegionObject->setLigoData(data, zonePos.x, zonePos.y); +} + +bool ZoneBuilder::initZoneBank (const QString &pathName) +{ + QDir *dir = new QDir(pathName); + QStringList filters; + filters << "*.ligozone"; + + // Find all ligozone files in dir + QStringList listFiles = dir->entryList(filters, QDir::Files); + + std::string error; + Q_FOREACH(QString file, listFiles) + { + //nlinfo(file.toStdString().c_str()); + if (!m_zoneBank.addElement((pathName + file).toStdString(), error)) + QMessageBox::critical(0, QObject::tr("Landscape editor"), QString(error.c_str()), QMessageBox::Ok); + } + delete dir; + return true; +} + +PixmapDatabase *ZoneBuilder::pixmapDatabase() const +{ + return m_pixmapDatabase; +} + +QString ZoneBuilder::dataPath() const +{ + return m_lastPathName; +} + +bool ZoneBuilder::getZoneMask(sint32 x, sint32 y) +{ + if ((x < m_minX) || (x > m_maxX) || + (y < m_minY) || (y > m_maxY)) + return true; + else + return m_zoneMask[(x - m_minX) + (y - m_minY) * (1 + m_maxX - m_minX)]; +} + +void ZoneBuilder::calcMask() +{ + sint32 x, y; + + m_minY = m_minX = 1000000; + m_maxY = m_maxX = -1000000; + + if (m_landscapeMap.size() == 0) + return; + + QMapIterator i(m_landscapeMap); + while (i.hasNext()) + { + i.next(); + const NLLIGO::CZoneRegion ®ion = i.value().zoneRegionObject->ligoZoneRegion(); + + if (m_minX > region.getMinX()) + m_minX = region.getMinX(); + if (m_minY > region.getMinY()) + m_minY = region.getMinY(); + if (m_maxX < region.getMaxX()) + m_maxX = region.getMaxX(); + if (m_maxY < region.getMaxY()) + m_maxY = region.getMaxY(); + } + + m_zoneMask.resize ((1 + m_maxX - m_minX) * (1 + m_maxY - m_minY)); + sint32 stride = (1 + m_maxX - m_minX); + for (y = m_minY; y <= m_maxY; ++y) + for (x = m_minX; x <= m_maxX; ++x) + { + m_zoneMask[x - m_minX + (y - m_minY) * stride] = true; + + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + if (int(it.key()) != m_currentZoneRegion) + { + const NLLIGO::CZoneRegion ®ion = it.value().zoneRegionObject->ligoZoneRegion(); + + const std::string &rSZone = region.getName (x, y); + if ((rSZone != STRING_OUT_OF_BOUND) && (rSZone != STRING_UNUSED)) + { + m_zoneMask[x - m_minX + (y - m_minY) * stride] = false; + } + } + } + } +} + +bool ZoneBuilder::getZoneAmongRegions(ZonePosition &zonePos, BuilderZoneRegion *builderZoneRegionFrom, sint32 x, sint32 y) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion ®ion = it.value().zoneRegionObject->ligoZoneRegion(); + if ((x < region.getMinX()) || (x > region.getMaxX()) || + (y < region.getMinY()) || (y > region.getMaxY())) + continue; + if (region.getName(x, y) != STRING_UNUSED) + { + builderZoneRegionFrom = it.value().builderZoneRegion; + zonePos = ZonePosition(x, y, it.key()); + return true; + } + } + + // The zone is not present in other region so it is an empty or oob zone of the current region + const NLLIGO::CZoneRegion ®ion = zoneRegion(builderZoneRegionFrom->getRegionId())->ligoZoneRegion(); + if ((x < region.getMinX()) || (x > region.getMaxX()) || + (y < region.getMinY()) || (y > region.getMaxY())) + return false; // Out Of Bound + + zonePos = ZonePosition(x, y, builderZoneRegionFrom->getRegionId()); + return true; +} + +void ZoneBuilder::checkBeginMacro() +{ + if (!m_createdAction) + { + m_createdAction = true; + m_undoStack->beginMacro(m_titleAction); + m_undoScanRegionCommand = new UndoScanRegionCommand(true, this, m_landscapeScene); + m_undoStack->push(m_undoScanRegionCommand); + } +} + +void ZoneBuilder::checkEndMacro() +{ + if (m_createdAction) + { + UndoScanRegionCommand *redoScanRegionCommand = new UndoScanRegionCommand(false, this, m_landscapeScene); + + // Sets list positions in which need apply changes + m_undoScanRegionCommand->setScanList(m_zonePositionList); + redoScanRegionCommand->setScanList(m_zonePositionList); + + // Adds command in the stack + m_undoStack->push(redoScanRegionCommand); + m_undoStack->endMacro(); + } +} + +bool ZoneBuilder::checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion &zoneRegion = it.value().zoneRegionObject->ligoZoneRegion(); + for (sint32 y = zoneRegion.getMinY(); y <= zoneRegion.getMaxY(); ++y) + for (sint32 x = zoneRegion.getMinX(); x <= zoneRegion.getMaxX(); ++x) + { + const std::string &refZoneName = zoneRegion.getName(x, y); + if (refZoneName != STRING_UNUSED) + { + const std::string &zoneName = newZoneRegion.getName(x, y); + if ((zoneName != STRING_UNUSED) && (zoneName != STRING_OUT_OF_BOUND)) + return true; + } + } + } + return false; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h new file mode 100644 index 000000000..106b8ee58 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h @@ -0,0 +1,174 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 BUILDER_ZONE_H +#define BUILDER_ZONE_H + +// Project includes +#include "builder_zone_base.h" +#include "builder_zone_region.h" +#include "zone_region_editor.h" +#include "pixmap_database.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ListZonesWidget; +class LandscapeScene; +class UndoScanRegionCommand; + +/** +@class ZoneBuilder +@brief ZoneBuilder contains all the shared data between the tools and the engine. +@details ZoneBank contains the macro zones that is composed of several zones plus a mask. +PixmapDatabase contains the graphics for the zones +*/ +class ZoneBuilder +{ +public: + ZoneBuilder(LandscapeScene *landscapeScene, ListZonesWidget *listZonesWidget = 0, QUndoStack *undoStack = 0); + ~ZoneBuilder(); + + /// Inits zoneBank and init zone pixmap database + bool init(const QString &pathName, bool displayProgress = false); + + void calcMask(); + + /// @return false if in point (x, y) placed zone brick, else true + bool getZoneMask (sint32 x, sint32 y); + + bool getZoneAmongRegions(ZonePosition &zonePos, BuilderZoneRegion *builderZoneRegionFrom, sint32 x, sint32 y); + + /// Ligo Actions + /// @{ + + /// Adds the LigoTileCommand in undo stack + void actionLigoTile(const LigoData &data, const ZonePosition &zonePos); + + void actionLigoMove(uint index, sint32 deltaX, sint32 deltaY); + + /// Adds the LigoResizeCommand in undo stack + void actionLigoResize(uint index, sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY); + /// @} + + /// Zone Bricks + /// @{ + void addZone(const sint32 posX, const sint32 posY); + void addTransition(const sint32 posX, const sint32 posY); + void delZone(const sint32 posX, const sint32 posY); + /// @} + + /// Zone Region + /// @{ + + /// Creates empty zone region and adds in the workspace + /// @return id zone region + int createZoneRegion(); + + /// Loads zone region from file @fileName and adds in the workspace. + /// @return id zone region + int createZoneRegion(const QString &fileName); + + /// Unloads zone region from the workspace + void deleteZoneRegion(int id); + + /// Sets the current zone region with @id + void setCurrentZoneRegion(int id); + + /// @return id the current zone region, if workspace is empty then returns (-1) + int currentIdZoneRegion() const; + + ZoneRegionObject *currentZoneRegion() const; + int countZoneRegion() const; + ZoneRegionObject *zoneRegion(int id) const; + bool ligoData(LigoData &data, const ZonePosition &zonePos); + void setLigoData(LigoData &data, const ZonePosition &zonePos); + /// @} + + // Accessors + NLLIGO::CZoneBank &getZoneBank() + { + return m_zoneBank; + } + + PixmapDatabase *pixmapDatabase() const; + + QString dataPath() const; + +private: + + /// Scans ./zoneligos dir and add all *.ligozone files to zoneBank + bool initZoneBank (const QString &path); + + /// Checks enabled beginMacro mode for undo stack, if false, then enables mode + void checkBeginMacro(); + + /// Checks enabled on beginMacro mode for undo stack, if true, then adds UndoScanRegionCommand + /// in undo stack and disables beginMacro mode + void checkEndMacro(); + + /// Checks intersects between them zone regions + /// @return true if newZoneRegion intersects with loaded zone regions, else return false + bool checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion); + + struct LandscapeItem + { + BuilderZoneRegion *builderZoneRegion; + ZoneRegionObject *zoneRegionObject; + QGraphicsRectItem *rectItem; + }; + + sint32 m_minX, m_maxX, m_minY, m_maxY; + std::vector m_zoneMask; + + QString m_lastPathName; + + int m_currentZoneRegion; + //std::vector m_landscapeItems; + QMap m_landscapeMap; + + bool m_createdAction; + QString m_titleAction; + QList m_zonePositionList; + UndoScanRegionCommand *m_undoScanRegionCommand; + + PixmapDatabase *m_pixmapDatabase; + NLLIGO::CZoneBank m_zoneBank; + ListZonesWidget *m_listZonesWidget; + LandscapeScene *m_landscapeScene; + QUndoStack *m_undoStack; +}; + +} /* namespace LandscapeEditor */ + +#endif // BUILDER_ZONE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp new file mode 100644 index 000000000..958aee640 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp @@ -0,0 +1,206 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "builder_zone_base.h" +#include "landscape_scene_base.h" +#include "zone_region_editor.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ +int NewLandId = 0; + +ZoneBuilderBase::ZoneBuilderBase(LandscapeSceneBase *landscapeScene) + : m_pixmapDatabase(0), + m_landscapeSceneBase(landscapeScene) +{ + nlassert(m_landscapeSceneBase); + m_pixmapDatabase = new PixmapDatabase(); + m_lastPathName = ""; +} + +ZoneBuilderBase::~ZoneBuilderBase() +{ + delete m_pixmapDatabase; +} + +bool ZoneBuilderBase::init(const QString &pathName, bool displayProgress) +{ + if (pathName.isEmpty()) + return false; + if (pathName != m_lastPathName) + { + m_lastPathName = pathName; + QString zoneBankPath = pathName; + zoneBankPath += "/zoneligos/"; + + // Init the ZoneBank + m_zoneBank.reset(); + if (!initZoneBank (zoneBankPath)) + { + m_zoneBank.reset(); + return false; + } + // Construct the DataBase from the ZoneBank + QString zoneBitmapPath = pathName; + zoneBitmapPath += "/zonebitmaps/"; + m_pixmapDatabase->reset(); + if (!m_pixmapDatabase->loadPixmaps(zoneBitmapPath, m_zoneBank, displayProgress)) + { + m_zoneBank.reset(); + return false; + } + } + return true; +} + +int ZoneBuilderBase::loadZoneRegion(const QString &fileName, int defaultId) +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.zoneRegionObject->load(fileName.toStdString()); + + if (!checkOverlaps(landItem.zoneRegionObject->ligoZoneRegion())) + { + delete landItem.zoneRegionObject; + return -1; + } + int id = defaultId; + if (id == -1) + id = NewLandId++; +// landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); +// landItem.builderZoneRegion->init(this); + + m_landscapeSceneBase->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion()); +// landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + m_landscapeMap.insert(id, landItem); + + calcMask(); + return id; +} + +void ZoneBuilderBase::deleteZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + m_landscapeSceneBase->delZoneRegion(m_landscapeMap.value(id).zoneRegionObject->ligoZoneRegion()); + delete m_landscapeMap.value(id).zoneRegionObject; +// delete m_landscapeMap.value(id).builderZoneRegion; + m_landscapeMap.remove(id); + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +int ZoneBuilderBase::countZoneRegion() const +{ + return m_landscapeMap.size(); +} + +ZoneRegionObject *ZoneBuilderBase::zoneRegion(int id) const +{ + return m_landscapeMap.value(id).zoneRegionObject; +} + +bool ZoneBuilderBase::initZoneBank (const QString &pathName) +{ + QDir *dir = new QDir(pathName); + QStringList filters; + filters << "*.ligozone"; + + // Find all ligozone files in dir + QStringList listFiles = dir->entryList(filters, QDir::Files); + + std::string error; + Q_FOREACH(QString file, listFiles) + { + //nlinfo(file.toStdString().c_str()); + if (!m_zoneBank.addElement((pathName + file).toStdString(), error)) + QMessageBox::critical(0, QObject::tr("Landscape editor"), QString(error.c_str()), QMessageBox::Ok); + } + delete dir; + return true; +} + +PixmapDatabase *ZoneBuilderBase::pixmapDatabase() const +{ + return m_pixmapDatabase; +} + +QString ZoneBuilderBase::dataPath() const +{ + return m_lastPathName; +} + +void ZoneBuilderBase::calcMask() +{ + m_minY = m_minX = 1000000; + m_maxY = m_maxX = -1000000; + + if (m_landscapeMap.size() == 0) + return; + + QMapIterator i(m_landscapeMap); + while (i.hasNext()) + { + i.next(); + const NLLIGO::CZoneRegion ®ion = i.value().zoneRegionObject->ligoZoneRegion(); + + if (m_minX > region.getMinX()) + m_minX = region.getMinX(); + if (m_minY > region.getMinY()) + m_minY = region.getMinY(); + if (m_maxX < region.getMaxX()) + m_maxX = region.getMaxX(); + if (m_maxY < region.getMaxY()) + m_maxY = region.getMaxY(); + } +} + +bool ZoneBuilderBase::checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion &zoneRegion = it.value().zoneRegionObject->ligoZoneRegion(); + for (sint32 y = zoneRegion.getMinY(); y <= zoneRegion.getMaxY(); ++y) + for (sint32 x = zoneRegion.getMinX(); x <= zoneRegion.getMaxX(); ++x) + { + const std::string &refZoneName = zoneRegion.getName(x, y); + if (refZoneName != STRING_UNUSED) + { + const std::string &zoneName = newZoneRegion.getName(x, y); + if ((zoneName != STRING_UNUSED) && (zoneName != STRING_OUT_OF_BOUND)) + return false; + } + } + } + return true; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h new file mode 100644 index 000000000..a8637d463 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h @@ -0,0 +1,129 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 BUILDER_ZONE_BASE_H +#define BUILDER_ZONE_BASE_H + +// Project includes +#include "landscape_editor_global.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class LandscapeSceneBase; +class PixmapDatabase; +class ZoneRegionObject; + +// Data +struct ZonePosition +{ + // Absolute position + sint32 x; + sint32 y; + int region; + + ZonePosition() + { + x = 0xffffffff; + y = 0xffffffff; + region = -1; + } + + ZonePosition(const sint32 posX, const sint32 posY, const int id) + { + x = posX; + y = posY; + region = id; + } +}; + +/** +@class ZoneBuilderBase +@brief ZoneBuilderBase contains all the shared data between the tools and the engine. +@details ZoneBank contains the macro zones that is composed of several zones plus a mask. +PixmapDatabase contains the graphics for the zones +*/ +class LANDSCAPE_EDITOR_EXPORT ZoneBuilderBase +{ +public: + explicit ZoneBuilderBase(LandscapeSceneBase *landscapeScene); + virtual ~ZoneBuilderBase(); + + /// Init zoneBank and init zone pixmap database + bool init(const QString &pathName, bool displayProgress = false); + + /// Zone Region + /// @{ + int loadZoneRegion(const QString &fileName, int defaultId = -1); + void deleteZoneRegion(int id); + int countZoneRegion() const; + ZoneRegionObject *zoneRegion(int id) const; + /// @} + + // Accessors + NLLIGO::CZoneBank &getZoneBank() + { + return m_zoneBank; + } + + PixmapDatabase *pixmapDatabase() const; + + QString dataPath() const; + +private: + + /// Scan ./zoneligos dir and add all *.ligozone files to zoneBank + bool initZoneBank (const QString &path); + + void calcMask(); + + bool checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion); + + struct LandscapeItem + { + ZoneRegionObject *zoneRegionObject; + }; + + sint32 m_minX, m_maxX, m_minY, m_maxY; + + QString m_lastPathName; + + QMap m_landscapeMap; + + PixmapDatabase *m_pixmapDatabase; + NLLIGO::CZoneBank m_zoneBank; + LandscapeSceneBase *m_landscapeSceneBase; +}; + +} /* namespace LandscapeEditor */ + +#endif // BUILDER_ZONE_BASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp new file mode 100644 index 000000000..36c70d4c7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp @@ -0,0 +1,2143 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// 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 "builder_zone_region.h" +#include "builder_zone.h" +#include "zone_region_editor.h" + +// NeL includes +#include + +// Qt includes + +namespace LandscapeEditor +{ + +BuilderZoneRegion::BuilderZoneRegion(uint regionId) + : m_regionId(regionId), + m_zoneBuilder(0), + m_firstInit(false) +{ +} + +bool BuilderZoneRegion::init(ZoneBuilder *zoneBuilder) +{ + if (m_firstInit) + return true; + + m_zoneBuilder = zoneBuilder; + + uint32 j, k; + SMatNode mn; + std::vector AllValues; + + // Build the material tree + m_zoneBuilder->getZoneBank().getCategoryValues("material", AllValues); + for (uint32 i = 0; i < AllValues.size(); ++i) + { + mn.Name = AllValues[i]; + m_matTree.push_back(mn); + } + + // Link between materials + AllValues.clear (); + m_zoneBuilder->getZoneBank().getCategoryValues("transname", AllValues); + for (uint32 i = 0; i < AllValues.size(); ++i) + { + // Get the 2 materials linked together + std::string matAstr, matBstr; + for (j = 0; j < AllValues[i].size(); ++j) + { + if (AllValues[i][j] == '-') + break; + else + matAstr += AllValues[i][j]; + } + ++j; + for (; j < AllValues[i].size(); ++j) + matBstr += AllValues[i][j]; + + // Find matA + for (j = 0; j < m_matTree.size(); ++j) + if (m_matTree[j].Name == matAstr) + break; + + if (j < m_matTree.size()) + { + // Find matB + for (k = 0; k < m_matTree.size(); ++k) + if (m_matTree[k].Name == matBstr) + break; + + if (k < m_matTree.size()) + { + // Add a ref to matB in node matA + m_matTree[j].Arcs.push_back(k); + + // Add a ref to matA in node matB + m_matTree[k].Arcs.push_back(j); + } + } + } + + m_firstInit = true; + return true; +} + +class ToUpdate +{ + struct SElement + { + sint32 x, y; + + // Material put into the cell to update + std::string matPut; + + BuilderZoneRegion *builderZoneRegion; + }; + + std::vector m_elements; + +public: + + void add(BuilderZoneRegion *builderZoneRegion, sint32 x, sint32 y, const std::string &matName) + { + bool bFound = false; + for (uint32 m = 0; m < m_elements.size(); ++m) + if ((m_elements[m].x == x) && (m_elements[m].y == y)) + { + bFound = true; + break; + } + if (!bFound) + { + SElement newElement; + newElement.x = x; + newElement.y = y; + newElement.matPut = matName; + newElement.builderZoneRegion = builderZoneRegion; + m_elements.push_back (newElement); + } + } + + void del(sint32 x, sint32 y) + { + bool bFound = false; + uint32 m; + for (m = 0; m < m_elements.size(); ++m) + if ((m_elements[m].x == x) && (m_elements[m].y == y)) + { + bFound = true; + break; + } + if (bFound) + { + for (; m < m_elements.size() - 1; ++m) + m_elements[m] = m_elements[m + 1]; + m_elements.resize (m_elements.size() - 1); + } + } + + uint32 size() + { + return m_elements.size(); + } + + sint32 getX(uint32 m) + { + return m_elements[m].x; + } + + sint32 getY(uint32 m) + { + return m_elements[m].y; + } + + BuilderZoneRegion *getBuilderZoneRegion(uint32 m) + { + return m_elements[m].builderZoneRegion; + } + + const std::string &getMat (uint32 m) + { + return m_elements[m].matPut; + } +}; + +void BuilderZoneRegion::add(sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + sint32 sizeX = zoneBankElement->getSizeX(), sizeY = zoneBankElement->getSizeY(); + sint32 i, j; + NLLIGO::SPiece sMask, sPosX, sPosY; + ToUpdate tUpdate; // Transition to update + + if (!m_zoneBuilder->getZoneMask (x,y)) + return; + + if (zoneBankElement->getCategory("transname") != STRING_NO_CAT_TYPE) + { + addTransition (x, y, rot, flip, zoneBankElement); + return; + } + + // Create the mask in the good rotation and flip + sMask.Tab.resize(sizeX * sizeY); + sPosX.Tab.resize(sizeX * sizeY); + sPosY.Tab.resize(sizeX * sizeY); + + for(j = 0; j < sizeY; ++j) + for(i = 0; i < sizeX; ++i) + { + sPosX.Tab[i + j * sizeX] = (uint8)i; + sPosY.Tab[i + j * sizeX] = (uint8)j; + sMask.Tab[i + j * sizeX] = zoneBankElement->getMask()[i + j * sizeX]; + } + sPosX.w = sPosY.w = sMask.w = sizeX; + sPosX.h = sPosY.h = sMask.h = sizeY; + sMask.rotFlip(rot, flip); + sPosX.rotFlip(rot, flip); + sPosY.rotFlip(rot, flip); + + // Test if the pieces can be put (due to mask) + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + if (m_zoneBuilder->getZoneMask(x + i, y + j) == false) + return; + } + + // Delete all pieces that are under the mask + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + del(x + i, y + j, true, &tUpdate); + } + + // Delete all around all material that are not from the same as us + const std::string &curMat = zoneBankElement->getCategory("material"); + + if (curMat != STRING_NO_CAT_TYPE) + { + // This element is a valid material + // Place the piece + const std::string &eltName = zoneBankElement->getName(); + placePiece(x, y, rot, flip, sMask, sPosX, sPosY, eltName); + + // Put all transitions between different materials + putTransitions (x, y, sMask, curMat, &tUpdate); + placePiece(x, y, rot, flip, sMask, sPosX, sPosY, eltName); + } +} + +void BuilderZoneRegion::invertCutEdge(sint32 x, sint32 y, uint8 cePos) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + if ((x < zoneRegion.getMinX ()) || (x > zoneRegion.getMaxX ()) || + (y < zoneRegion.getMinY ()) || (y > zoneRegion.getMaxY ())) + return; + + NLLIGO::CZoneBankElement *zoneBankElement = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneRegion.getName(x, y)); + if (zoneBankElement == NULL) + return; + if (zoneBankElement->getCategory("transname") == STRING_NO_CAT_TYPE) + return; + + + ZonePosition zonePos(x, y, m_regionId); + LigoData dataZone; + + m_zoneBuilder->ligoData(dataZone, zonePos); + if (dataZone.sharingCutEdges[cePos] != 3 - dataZone.sharingCutEdges[cePos]) + { + dataZone.sharingCutEdges[cePos] = 3 - dataZone.sharingCutEdges[cePos]; + + m_zoneBuilder->actionLigoTile(dataZone, zonePos); + } + updateTrans(x, y); + + // If the transition number is not the same propagate the change + // Propagate where the edge is cut (1/3 or 2/3) and update the transition + if (cePos == 2) + if (dataZone.sharingMatNames[0] != dataZone.sharingMatNames[2]) + { + if (x > zoneRegion.getMinX ()) + { + // [x-1][y].right = [x][y].left + // _Zones[(x-1-zoneRegion->getMinX ())+(y-zoneRegion->getMinY ())*stride].SharingCutEdges[3] = dataZonePos.SharingCutEdges[2]; + ZonePosition zonePosTemp(x - 1, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.sharingCutEdges[3] != dataZone.sharingCutEdges[2]) + { + dataZoneTemp.sharingCutEdges[3] = dataZone.sharingCutEdges[2]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } + } + updateTrans (x - 1, y); + } + if (cePos == 3) + if (dataZone.sharingMatNames[1] != dataZone.sharingMatNames[3]) + { + if (x < zoneRegion.getMaxX ()) + { + // [x+1][y].left = [x][y].right + ZonePosition zonePosTemp(x + 1, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.sharingCutEdges[2] != dataZone.sharingCutEdges[3]) + { + dataZoneTemp.sharingCutEdges[2] = dataZone.sharingCutEdges[3]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } + } + updateTrans (x + 1, y); + } + if (cePos == 1) + if (dataZone.sharingMatNames[0] != dataZone.sharingMatNames[1]) + { + if (y > zoneRegion.getMinY ()) + { + // [x][y-1].up = [x][y].down + ZonePosition zonePosTemp(x, y - 1, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.sharingCutEdges[0] != dataZone.sharingCutEdges[1]) + { + dataZoneTemp.sharingCutEdges[0] = dataZone.sharingCutEdges[1]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } + } + updateTrans (x, y-1); + } + if (cePos == 0) + if (dataZone.sharingMatNames[2] != dataZone.sharingMatNames[3]) + { + if (y < zoneRegion.getMaxY ()) + { + // [x][y+1].down = [x][y].up + ZonePosition zonePosTemp(x, y + 1, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.sharingCutEdges[1] != dataZone.sharingCutEdges[0]) + { + dataZoneTemp.sharingCutEdges[1] = dataZone.sharingCutEdges[0]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } + } + updateTrans (x, y + 1); + } +} + +void BuilderZoneRegion::cycleTransition(sint32 x, sint32 y) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + if ((x < zoneRegion.getMinX ()) || (x > zoneRegion.getMaxX ()) || + (y < zoneRegion.getMinY ()) || (y > zoneRegion.getMaxY ())) + return; + + NLLIGO::CZoneBankElement *zoneBankElement = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneRegion.getName (x, y)); + if (zoneBankElement == NULL) + return; + if (zoneBankElement->getCategory("transname") == STRING_NO_CAT_TYPE) + return; + + // \todo trap -> choose the good transition in function of the transition under the current location + // Choose the next possible transition if not the same as the first one + // Choose among all transition of the same number + + updateTrans (x, y); +} + +bool BuilderZoneRegion::addNotPropagate (sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return false; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + sint32 sizeX = zoneBankElement->getSizeX(), sizeY = zoneBankElement->getSizeY(); + sint32 i, j; + NLLIGO::SPiece sMask, sPosX, sPosY; + ToUpdate tUpdate; // Transition to update + + if (!m_zoneBuilder->getZoneMask (x, y)) + return false; + + if (zoneBankElement->getCategory("transname") != STRING_NO_CAT_TYPE) + { + addTransition (x, y, rot, flip, zoneBankElement); + return true; + } + + // Create the mask in the good rotation and flip + sMask.Tab.resize (sizeX * sizeY); + sPosX.Tab.resize (sizeX * sizeY); + sPosY.Tab.resize (sizeX * sizeY); + + for (j = 0; j < sizeY; ++j) + for (i = 0; i < sizeX; ++i) + { + sPosX.Tab[i + j * sizeX] = (uint8)i; + sPosY.Tab[i + j * sizeX] = (uint8)j; + sMask.Tab[i + j * sizeX] = zoneBankElement->getMask()[i + j * sizeX]; + } + sPosX.w = sPosY.w = sMask.w = sizeX; + sPosX.h = sPosY.h = sMask.h = sizeY; + sMask.rotFlip (rot, flip); + sPosX.rotFlip (rot, flip); + sPosY.rotFlip (rot, flip); + + // Test if the pieces can be put (due to mask) + sint32 stride = (1 + zoneRegion.getMaxX () - zoneRegion.getMinX ()); + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i+j*sMask.w]) + { + if (m_zoneBuilder->getZoneMask(x + i, y + j) == false) + return false; + if (((x + i) < zoneRegion.getMinX ()) || ((x + i) > zoneRegion.getMaxX ()) || + ((y + j) < zoneRegion.getMinY ()) || ((y + j) > zoneRegion.getMaxY ())) + return false; + NLLIGO::CZoneBankElement *zoneBankElementUnder = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneRegion.getName (x + i, y + j)); + if (zoneBankElementUnder == NULL) + return false; + if (zoneBankElementUnder->getCategory("material") != zoneBankElement->getCategory("material")) + return false; + } + + // Delete all pieces that are under the mask + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + del(x + i, y + j, true, &tUpdate); + } + + const std::string &curMat = zoneBankElement->getCategory("material"); + + if (curMat != STRING_NO_CAT_TYPE) + { + // This element is a valid material + // Place the piece + const std::string &eltName = zoneBankElement->getName(); + placePiece(x, y, rot, flip, sMask, sPosX, sPosY, eltName); + } + + return true; +} + +void BuilderZoneRegion::addForce (sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + sint32 sizeX = zoneBankElement->getSizeX(), sizeY = zoneBankElement->getSizeY(); + sint32 i, j; + NLLIGO::SPiece sMask, sPosX, sPosY; + ToUpdate tUpdate; // Transition to update + + if (!m_zoneBuilder->getZoneMask (x, y)) + return; + + /* + if (pElt->getCategory("transname") != STRING_NO_CAT_TYPE) + { + addTransition (x, y, nRot, nFlip, pElt); + return; + }*/ + + // Create the mask in the good rotation and flip + sMask.Tab.resize (sizeX * sizeY); + sPosX.Tab.resize (sizeX * sizeY); + sPosY.Tab.resize (sizeX * sizeY); + + for (j = 0; j < sizeY; ++j) + for (i = 0; i < sizeX; ++i) + { + sPosX.Tab[i + j * sizeX] = (uint8)i; + sPosY.Tab[i + j * sizeX] = (uint8)j; + sMask.Tab[i + j * sizeX] = zoneBankElement->getMask()[i + j * sizeX]; + } + sPosX.w = sPosY.w = sMask.w = sizeX; + sPosX.h = sPosY.h = sMask.h = sizeY; + sMask.rotFlip (rot, flip); + sPosX.rotFlip (rot, flip); + sPosY.rotFlip (rot, flip); + + // Test if the pieces can be put (due to mask) + // All space under the mask must be empty + sint32 stride = (1 + zoneRegion.getMaxX () - zoneRegion.getMinX ()); + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i+j*sMask.w]) + { + if (m_zoneBuilder->getZoneMask(x+i, y+j) == false) + return; + if (((x+i) < zoneRegion.getMinX ()) || ((x+i) > zoneRegion.getMaxX ()) || + ((y+j) < zoneRegion.getMinY ()) || ((y+j) > zoneRegion.getMaxY ())) + return; + NLLIGO::CZoneBankElement *zoneBankElementUnder = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneRegion.getName (x + i, y + i)); + if (zoneBankElementUnder != NULL) + return; + } + + // Delete all pieces that are under the mask + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i+j*sMask.w]) + { + del(x+i, y+j, true, &tUpdate); + } + + const std::string &curMat = zoneBankElement->getCategory ("material"); + const bool transition = zoneBankElement->getCategory("transname") != STRING_NO_CAT_TYPE; + + if (curMat != STRING_NO_CAT_TYPE || transition) + { + // This element is a valid material + // Place the piece + const std::string &eltName = zoneBankElement->getName(); + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + set(x + i, y + j, sPosX.Tab[i + j * sPosX.w], sPosY.Tab[i + j * sPosY.w], eltName, transition); + setRot(x + i, y + j, rot); + setFlip(x + i, y + j, flip); + } + } +} + +uint8 TransToEdge[72][4] = +{ + { 0, 0, 1, 1 }, // TransNum = 0, Flip = 0, Rot = 0 + { 2, 2, 0, 0 }, // TransNum = 0, Flip = 0, Rot = 1 + { 0, 0, 2, 2 }, // TransNum = 0, Flip = 0, Rot = 2 + { 1, 1, 0, 0 }, // TransNum = 0, Flip = 0, Rot = 3 + { 0, 0, 1, 1 }, // TransNum = 0, Flip = 1, Rot = 0 + { 2, 2, 0, 0 }, // TransNum = 0, Flip = 1, Rot = 1 + { 0, 0, 2, 2 }, // TransNum = 0, Flip = 1, Rot = 2 + { 1, 1, 0, 0 }, // TransNum = 0, Flip = 1, Rot = 3 + + { 0, 0, 1, 2 }, // TransNum = 1, Flip = 0, Rot = 0 + { 1, 2, 0, 0 }, // TransNum = 1, Flip = 0, Rot = 1 + { 0, 0, 1, 2 }, // TransNum = 1, Flip = 0, Rot = 2 + { 1, 2, 0, 0 }, // TransNum = 1, Flip = 0, Rot = 3 + { 0, 0, 2, 1 }, // TransNum = 1, Flip = 1, Rot = 0 + { 2, 1, 0, 0 }, // TransNum = 1, Flip = 1, Rot = 1 + { 0, 0, 2, 1 }, // TransNum = 1, Flip = 1, Rot = 2 + { 2, 1, 0, 0 }, // TransNum = 1, Flip = 1, Rot = 3 + + { 0, 0, 2, 2 }, // TransNum = 2, Flip = 0, Rot = 0 + { 1, 1, 0, 0 }, // TransNum = 2, Flip = 0, Rot = 1 + { 0, 0, 1, 1 }, // TransNum = 2, Flip = 0, Rot = 2 + { 2, 2, 0, 0 }, // TransNum = 2, Flip = 0, Rot = 3 + { 0, 0, 2, 2 }, // TransNum = 2, Flip = 1, Rot = 0 + { 1, 1, 0, 0 }, // TransNum = 2, Flip = 1, Rot = 1 + { 0, 0, 1, 1 }, // TransNum = 2, Flip = 1, Rot = 2 + { 2, 2, 0, 0 }, // TransNum = 2, Flip = 1, Rot = 3 + + { 0, 1, 1, 0 }, // TransNum = 3, Flip = 0, Rot = 0 + { 0, 2, 0, 1 }, // TransNum = 3, Flip = 0, Rot = 1 + { 2, 0, 0, 2 }, // TransNum = 3, Flip = 0, Rot = 2 + { 1, 0, 2, 0 }, // TransNum = 3, Flip = 0, Rot = 3 + { 0, 2, 0, 1 }, // TransNum = 3, Flip = 1, Rot = 0 + { 2, 0, 0, 2 }, // TransNum = 3, Flip = 1, Rot = 1 + { 1, 0, 2, 0 }, // TransNum = 3, Flip = 1, Rot = 2 + { 0, 1, 1, 0 }, // TransNum = 3, Flip = 1, Rot = 3 + + { 0, 2, 1, 0 }, // TransNum = 4, Flip = 0, Rot = 0 + { 0, 2, 0, 2 }, // TransNum = 4, Flip = 0, Rot = 1 + { 1, 0, 0, 2 }, // TransNum = 4, Flip = 0, Rot = 2 + { 1, 0, 1, 0 }, // TransNum = 4, Flip = 0, Rot = 3 + { 0, 1, 0, 1 }, // TransNum = 4, Flip = 1, Rot = 0 + { 2, 0, 0, 1 }, // TransNum = 4, Flip = 1, Rot = 1 + { 2, 0, 2, 0 }, // TransNum = 4, Flip = 1, Rot = 2 + { 0, 1, 2, 0 }, // TransNum = 4, Flip = 1, Rot = 3 + + { 0, 2, 2, 0 }, // TransNum = 5, Flip = 0, Rot = 0 + { 0, 1, 0, 2 }, // TransNum = 5, Flip = 0, Rot = 1 + { 1, 0, 0, 1 }, // TransNum = 5, Flip = 0, Rot = 2 + { 2, 0, 1, 0 }, // TransNum = 5, Flip = 0, Rot = 3 + { 0, 1, 0, 2 }, // TransNum = 5, Flip = 1, Rot = 0 + { 1, 0, 0, 1 }, // TransNum = 5, Flip = 1, Rot = 1 + { 2, 0, 1, 0 }, // TransNum = 5, Flip = 1, Rot = 2 + { 0, 2, 2, 0 }, // TransNum = 5, Flip = 1, Rot = 3 + + { 0, 1, 1, 0 }, // TransNum = 6, Flip = 0, Rot = 0 + { 0, 2, 0, 1 }, // TransNum = 6, Flip = 0, Rot = 1 + { 2, 0, 0, 2 }, // TransNum = 6, Flip = 0, Rot = 2 + { 1, 0, 2, 0 }, // TransNum = 6, Flip = 0, Rot = 3 + { 0, 2, 0, 1 }, // TransNum = 6, Flip = 1, Rot = 0 + { 2, 0, 0, 2 }, // TransNum = 6, Flip = 1, Rot = 1 + { 1, 0, 2, 0 }, // TransNum = 6, Flip = 1, Rot = 2 + { 0, 1, 1, 0 }, // TransNum = 6, Flip = 1, Rot = 3 + + { 0, 2, 1, 0 }, // TransNum = 7, Flip = 0, Rot = 0 + { 0, 2, 0, 2 }, // TransNum = 7, Flip = 0, Rot = 1 + { 1, 0, 0, 2 }, // TransNum = 7, Flip = 0, Rot = 2 + { 1, 0, 1, 0 }, // TransNum = 7, Flip = 0, Rot = 3 + { 0, 1, 0, 1 }, // TransNum = 7, Flip = 1, Rot = 0 + { 2, 0, 0, 1 }, // TransNum = 7, Flip = 1, Rot = 1 + { 2, 0, 2, 0 }, // TransNum = 7, Flip = 1, Rot = 2 + { 0, 1, 2, 0 }, // TransNum = 7, Flip = 1, Rot = 3 + + { 0, 2, 2, 0 }, // TransNum = 8, Flip = 0, Rot = 0 + { 0, 1, 0, 2 }, // TransNum = 8, Flip = 0, Rot = 1 + { 1, 0, 0, 1 }, // TransNum = 8, Flip = 0, Rot = 2 + { 2, 0, 1, 0 }, // TransNum = 8, Flip = 0, Rot = 3 + { 0, 1, 0, 2 }, // TransNum = 8, Flip = 1, Rot = 0 + { 1, 0, 0, 1 }, // TransNum = 8, Flip = 1, Rot = 1 + { 2, 0, 1, 0 }, // TransNum = 8, Flip = 1, Rot = 2 + { 0, 2, 2, 0 }, // TransNum = 8, Flip = 1, Rot = 3 +}; + +void BuilderZoneRegion::addTransition (sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + uint32 i; + // Check that we write in an already defined place + if ((x < zoneRegion.getMinX ()) || (x > zoneRegion.getMaxX ()) || + (y < zoneRegion.getMinY ()) || (y > zoneRegion.getMaxY ())) + return; + + // Check size + if ((zoneBankElement->getSizeX() != 1) || (zoneBankElement->getSizeY() != 1)) + return; + + // Check that an element already exist at position we want put the transition + NLLIGO::CZoneBankElement *zoneBankElementUnder = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneRegion.getName(x, y)); + if (zoneBankElementUnder == NULL) + return; + + // And check that this element is also a transition and the same transition + if (zoneBankElementUnder->getCategory ("transname") == STRING_NO_CAT_TYPE) + return; + if (zoneBankElementUnder->getCategory ("transname") != zoneBankElement->getCategory("transname")) + return; + + std::string underType = zoneBankElementUnder->getCategory("transtype"); + std::string overType = zoneBankElement->getCategory("transtype"); + std::string underNum = zoneBankElementUnder->getCategory("transnum"); + std::string overNum = zoneBankElement ->getCategory("transnum"); + + ZonePosition zonePosTemp(x, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + LigoData dataZoneOriginal = dataZoneTemp; + + bool bMustPropagate = false; + // Same type of transition ? + if (zoneBankElementUnder->getCategory("transtype") != zoneBankElement->getCategory("transtype")) + { + // No so random the cutEdges + for (i = 0; i < 4; ++i) + { + uint8 nCut = (uint8)(1.0f + NLMISC::frand(2.0f)); + NLMISC::clamp(nCut, (uint8)1, (uint8)2); + + dataZoneTemp.sharingCutEdges[i] = nCut; + } + zoneBankElement = NULL; + bMustPropagate = true; + } + else + { + // Put exactly the transition as given + sint32 transnum = atoi(zoneBankElement->getCategory("transnum").c_str()); + sint32 flip = zoneRegion.getFlip(x, y); + sint32 rot = zoneRegion.getRot(x, y); + sint32 pos1 = -1, pos2 = -1; + + for (i = 0; i < 4; ++i) + { + if ((TransToEdge[transnum * 8 + flip * 4 + rot][i] != 0) && + (TransToEdge[transnum * 8 + flip * 4 + rot][i] != dataZoneTemp.sharingCutEdges[i])) + bMustPropagate = true; + + dataZoneTemp.sharingCutEdges[i] = TransToEdge[transnum * 8 + flip * 4 + rot][i]; + + if ((pos1 != -1) && (dataZoneTemp.sharingCutEdges[i] != 0)) + pos2 = i; + if ((pos1 == -1) && (dataZoneTemp.sharingCutEdges[i] != 0)) + pos1 = i; + } + // Exchange cutedges != 0 one time /2 to permit all positions + if ((transnum == 1) || (transnum == 4) || (transnum == 7)) + if (zoneBankElement->getName() == zoneBankElementUnder->getName()) + { + bMustPropagate = true; + + dataZoneTemp.sharingCutEdges[pos1] = 3 - dataZoneTemp.sharingCutEdges[pos1]; + dataZoneTemp.sharingCutEdges[pos2] = 3 - dataZoneTemp.sharingCutEdges[pos2]; + } + } + if (dataZoneTemp != dataZoneOriginal) + { + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } + updateTrans (x, y, zoneBankElement); + + // If the transition number is not the same propagate the change + if (bMustPropagate) + { + // Propagate where the edge is cut (1/3 or 2/3) and update the transition + if (dataZoneTemp.sharingMatNames[0] != dataZoneTemp.sharingMatNames[2]) + { + if (x > zoneRegion.getMinX ()) + { + // [x-1][y].right = [x][y].left + // _Zones[(x-1-pBZR->getMinX ())+(y-pBZR->getMinY ())*stride].SharingCutEdges[3] = dataZoneTemp.SharingCutEdges[2]; + ZonePosition zonePosTemp2(x - 1, y, m_regionId); + LigoData dataZoneTemp2; + m_zoneBuilder->ligoData(dataZoneTemp2, zonePosTemp2); + if (dataZoneTemp2.sharingCutEdges[3] != dataZoneTemp.sharingCutEdges[2]) + { + dataZoneTemp2.sharingCutEdges[3] = dataZoneTemp.sharingCutEdges[2]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp2, zonePosTemp2); + } + } + updateTrans (x - 1, y); + } + if (dataZoneTemp.sharingMatNames[1] != dataZoneTemp.sharingMatNames[3]) + { + if (x < zoneRegion.getMaxX ()) + { + // [x+1][y].left = [x][y].right + //_Zones[(x+1-pBZR->getMinX ())+(y-pBZR->getMinY ())*stride].SharingCutEdges[2] = dataZoneTemp.SharingCutEdges[3]; + ZonePosition zonePosTemp2(x + 1, y, m_regionId); + LigoData dataZoneTemp2; + m_zoneBuilder->ligoData(dataZoneTemp2, zonePosTemp2); + if (dataZoneTemp2.sharingCutEdges[2] != dataZoneTemp.sharingCutEdges[3]) + { + dataZoneTemp2.sharingCutEdges[2] = dataZoneTemp.sharingCutEdges[3]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp2, zonePosTemp2); + } + } + updateTrans (x + 1, y); + } + if (dataZoneTemp.sharingMatNames[0] != dataZoneTemp.sharingMatNames[1]) + { + if (y > zoneRegion.getMinY ()) + { + // [x][y-1].up = [x][y].down + //_Zones[(x-pBZR->getMinX ())+(y-1-pBZR->getMinY ())*stride].SharingCutEdges[0] = dataZoneTemp.SharingCutEdges[1]; + ZonePosition zonePosTemp2(x, y - 1, m_regionId); + LigoData dataZoneTemp2; + m_zoneBuilder->ligoData(dataZoneTemp2, zonePosTemp2); + if (dataZoneTemp2.sharingCutEdges[0] != dataZoneTemp.sharingCutEdges[1]) + { + dataZoneTemp2.sharingCutEdges[0] = dataZoneTemp.sharingCutEdges[1]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp2, zonePosTemp2); + } + } + updateTrans (x, y - 1); + } + if (dataZoneTemp.sharingMatNames[2] != dataZoneTemp.sharingMatNames[3]) + { + if (y < zoneRegion.getMaxY ()) + { + // [x][y+1].down = [x][y].up + //_Zones[(x-pBZR->getMinX ())+(y+1-pBZR->getMinY ())*stride].SharingCutEdges[1] = dataZoneTemp.SharingCutEdges[0]; + ZonePosition zonePosTemp2(x, y + 1, m_regionId); + LigoData dataZoneTemp2; + m_zoneBuilder->ligoData(dataZoneTemp2, zonePosTemp2); + if (dataZoneTemp2.sharingCutEdges[1] != dataZoneTemp.sharingCutEdges[0]) + { + dataZoneTemp2.sharingCutEdges[1] = dataZoneTemp.sharingCutEdges[0]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp2, zonePosTemp2); + } + } + updateTrans (x, y + 1); + } + } +} + +void BuilderZoneRegion::addToUpdateAndCreate(BuilderZoneRegion *builderZoneRegion, sint32 sharePos, sint32 x, sint32 y, + const std::string &newMat, ToUpdate *ptCreate, ToUpdate *ptUpdate) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + sint32 stride = (1 + zoneRegion.getMaxX() - zoneRegion.getMinX()); + + ZonePosition zonePos; + if (m_zoneBuilder->getZoneAmongRegions(zonePos, builderZoneRegion, x, y)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePos); + if (data.sharingMatNames[sharePos] != newMat) + { + data.sharingMatNames[sharePos] = newMat; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePos); + } + builderZoneRegion->del(x, y, true, ptUpdate); + ptCreate->add(builderZoneRegion, x, y, newMat); + } +} + +void BuilderZoneRegion::putTransitions (sint32 inX, sint32 inY, const NLLIGO::SPiece &mask, const std::string &matName, + ToUpdate *ptUpdate) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + ToUpdate tCreate; // Transition to create + + sint32 i, j, k, l, m; + sint32 x = inX, y = inY; + for (j = 0; j < mask.h; ++j) + for (i = 0; i < mask.w; ++i) + if (mask.Tab[i + j * mask.w]) + { + for (k = -1; k <= 1; ++k) + for (l = -1; l <= 1; ++l) + { + BuilderZoneRegion *builderZoneRegion2 = this; + ZonePosition zonePos; + if (m_zoneBuilder->getZoneAmongRegions(zonePos, builderZoneRegion2, inX + i + l, inY + j + k)) + tCreate.add(builderZoneRegion2, inX + i + l, inY + j + k, matName); + } + } + + // Check coherency of the transition to update + for (m = 0; m < (sint32)tCreate.size(); ++m) + { + BuilderZoneRegion *builderZoneRegion2 = tCreate.getBuilderZoneRegion(m); + x = tCreate.getX(m); + y = tCreate.getY(m); + std::string putMat = tCreate.getMat(m); + + //if ((x < pBZR->getMinX ())||(x > pBZR->getMaxX ())||(y < pBZR->getMinY ())||(y > pBZR->getMaxY ())) + // continue; + + ZonePosition zoneTemp(x, y, builderZoneRegion2->getRegionId()); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + + if (!((dataZoneTemp.sharingMatNames[0] == dataZoneTemp.sharingMatNames[1])&& + (dataZoneTemp.sharingMatNames[1] == dataZoneTemp.sharingMatNames[2])&& + (dataZoneTemp.sharingMatNames[2] == dataZoneTemp.sharingMatNames[3]))) + builderZoneRegion2->del(x, y, true, ptUpdate); + + // Check to see material can be posed + uint corner; + for (corner = 0; corner < 4; corner++) + { + std::string newMat = getNextMatInTree (putMat, dataZoneTemp.sharingMatNames[corner]); + + // Can't be posed ? + if (newMat == STRING_UNUSED) + break; + } + if ( (corner < 4) && (m != 0) ) + { + // The material can't be paused + for (int t = 0; t < 4; ++t) + dataZoneTemp.sharingMatNames[t] = STRING_UNUSED; + + // Don't propagate any more + } + else + { + // Expand material for the 1st quarter + std::string newMat = getNextMatInTree(putMat, dataZoneTemp.sharingMatNames[0]); + if (newMat != dataZoneTemp.sharingMatNames[0]) + { + // Update the quarter + if (dataZoneTemp.sharingMatNames[0] != newMat) + { + dataZoneTemp.sharingMatNames[0] = newMat; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + + addToUpdateAndCreate(builderZoneRegion2, 1, x - 1, y, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 3, x - 1, y - 1, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 2, x, y - 1, newMat, &tCreate, ptUpdate); + } + + // Expand material for the 2nd quarter + newMat = getNextMatInTree(putMat, dataZoneTemp.sharingMatNames[1]); + if (newMat != dataZoneTemp.sharingMatNames[1]) + { + // Update the quarter + //if (_Builder->getZoneMask(x,y)) + if (dataZoneTemp.sharingMatNames[1] != newMat) + { + dataZoneTemp.sharingMatNames[1] = newMat; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + + addToUpdateAndCreate(builderZoneRegion2, 0, x + 1, y, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 2, x + 1, y - 1, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 3, x, y - 1, newMat, &tCreate, ptUpdate); + } + + // Expand material for the 3rd quarter + newMat = getNextMatInTree(putMat, dataZoneTemp.sharingMatNames[2]); + if (newMat != dataZoneTemp.sharingMatNames[2]) + { + // Update the quarter + //if (_Builder->getZoneMask(x,y)) + if (dataZoneTemp.sharingMatNames[2] != newMat) + { + dataZoneTemp.sharingMatNames[2] = newMat; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + + addToUpdateAndCreate(builderZoneRegion2, 3, x - 1, y, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 1, x - 1, y + 1, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 0, x, y + 1, newMat, &tCreate, ptUpdate); + } + + // Expand material for the 4th quarter + newMat = getNextMatInTree(putMat, dataZoneTemp.sharingMatNames[3]); + if (newMat != dataZoneTemp.sharingMatNames[3]) + { + // Update the quarter + //if (_Builder->getZoneMask(x,y)) + if (dataZoneTemp.sharingMatNames[3] != newMat) + { + dataZoneTemp.sharingMatNames[3] = newMat; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + + addToUpdateAndCreate(builderZoneRegion2, 2, x + 1, y, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 0, x + 1, y + 1, newMat, &tCreate, ptUpdate); + addToUpdateAndCreate(builderZoneRegion2, 1, x, y + 1, newMat, &tCreate, ptUpdate); + } + } + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + + // Delete transitions that are inside the mask + for (j = 0; j < mask.h; ++j) + for (i = 0; i < mask.w; ++i) + if (mask.Tab[i + j * mask.w]) + { + tCreate.del(inX + i, inY + j); + } + + // For all transition to update choose the cut edge + for (m = 0; m < (sint32)tCreate.size(); ++m) + { + ZoneRegionObject *zoneRegionObj2 = m_zoneBuilder->zoneRegion(tCreate.getBuilderZoneRegion(m)->getRegionId()); + if (zoneRegionObj2 == 0) + continue; + + const NLLIGO::CZoneRegion &zoneRegion2 = zoneRegionObj2->ligoZoneRegion(); + x = tCreate.getX(m); + y = tCreate.getY(m); + + if ((x < zoneRegion.getMinX()) || (x > zoneRegion.getMaxX()) || + (y < zoneRegion.getMinY()) || (y > zoneRegion.getMaxY())) + continue; + + ZonePosition zoneTemp(x, y, tCreate.getBuilderZoneRegion(m)->getRegionId()); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + LigoData dataZoneTempOriginal = dataZoneTemp; + + for (i = 0; i < 4; ++i) + { + uint8 nCut = (uint8)(1.0f + NLMISC::frand(2.0f)); + NLMISC::clamp(nCut, (uint8)1, (uint8)2); + dataZoneTemp.sharingCutEdges[i] = nCut; + } + + // Add modification landscape + if (dataZoneTempOriginal != dataZoneTemp) + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + + // Propagate + if (dataZoneTemp.sharingMatNames[0] != dataZoneTemp.sharingMatNames[2]) + { + // [x-1][y].right = [x][y].left + BuilderZoneRegion *builderZoneRegion3 = tCreate.getBuilderZoneRegion(m); + ZonePosition zonePosU; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion3, x - 1, y)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingCutEdges[3] != dataZoneTemp.sharingCutEdges[2]) + { + data.sharingCutEdges[3] = dataZoneTemp.sharingCutEdges[2]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + ptUpdate->add(builderZoneRegion3, x - 1, y, ""); + } + } + else + { + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + if (dataZoneTemp.sharingCutEdges[2] != 0) + { + dataZoneTemp.sharingCutEdges[2] = 0; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + } + + if (dataZoneTemp.sharingMatNames[0] != dataZoneTemp.sharingMatNames[1]) + { + // [x][y-1].up = [x][y].down + BuilderZoneRegion *builderZoneRegion3 = tCreate.getBuilderZoneRegion(m); + ZonePosition zonePosU; + if (m_zoneBuilder->getZoneAmongRegions (zonePosU, builderZoneRegion3, x, y - 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingCutEdges[0] != dataZoneTemp.sharingCutEdges[1]) + { + data.sharingCutEdges[0] = dataZoneTemp.sharingCutEdges[1]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + ptUpdate->add (builderZoneRegion3, x, y - 1, ""); + } + } + else + { + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + if (dataZoneTemp.sharingCutEdges[1] != 0) + { + dataZoneTemp.sharingCutEdges[1] = 0; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + } + + if (dataZoneTemp.sharingMatNames[3] != dataZoneTemp.sharingMatNames[1]) + { + // [x+1][y].left = [x][y].right + BuilderZoneRegion *builderZoneRegion3 = tCreate.getBuilderZoneRegion(m); + ZonePosition zonePosU; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion3, x + 1, y)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingCutEdges[2] != dataZoneTemp.sharingCutEdges[3]) + { + data.sharingCutEdges[2] = dataZoneTemp.sharingCutEdges[3]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + ptUpdate->add(builderZoneRegion3, x + 1, y, ""); + } + } + else + { + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + if (dataZoneTemp.sharingCutEdges[3] != 0) + { + dataZoneTemp.sharingCutEdges[3] = 0; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + } + + if (dataZoneTemp.sharingMatNames[2] != dataZoneTemp.sharingMatNames[3]) + { + // [x][y+1].down = [x][y].up + BuilderZoneRegion *builderZoneRegion3 = tCreate.getBuilderZoneRegion(m); + ZonePosition zonePosU; + if (m_zoneBuilder->getZoneAmongRegions (zonePosU, builderZoneRegion3, x, y+1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingCutEdges[1] = dataZoneTemp.sharingCutEdges[0]) + { + data.sharingCutEdges[1] = dataZoneTemp.sharingCutEdges[0]; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + ptUpdate->add (builderZoneRegion3, x, y + 1, ""); + } + } + else + { + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + if (dataZoneTemp.sharingCutEdges[0] = 0) + { + dataZoneTemp.sharingCutEdges[0] = 0; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zoneTemp); + } + } + } + + // Delete in tUpdate each element in common with tCreate + for (m = 0; m < (sint32)tCreate.size(); ++m) + { + x = tCreate.getX(m); + y = tCreate.getY(m); + ptUpdate->del (x,y); + } + + // Finally update all transition + for (m = 0; m < (sint32)tCreate.size(); ++m) + { + const NLLIGO::CZoneRegion &zoneRegion2 = m_zoneBuilder->zoneRegion(tCreate.getBuilderZoneRegion(m)->getRegionId())->ligoZoneRegion(); + x = tCreate.getX(m); + y = tCreate.getY(m); + + if ((x >= zoneRegion2.getMinX()) && (x <= zoneRegion2.getMaxX()) && + (y >= zoneRegion2.getMinY()) && (y <= zoneRegion2.getMaxY())) + tCreate.getBuilderZoneRegion(m)->updateTrans(x, y); + } + + // WARNING: TODO: check this for + for (m = 0; m < (sint32)ptUpdate->size(); ++m) + { + const NLLIGO::CZoneRegion &zoneRegion2 = m_zoneBuilder->zoneRegion(ptUpdate->getBuilderZoneRegion(m)->getRegionId())->ligoZoneRegion(); + x = ptUpdate->getX(m); + y = ptUpdate->getY(m); + if ((x >= zoneRegion2.getMinX()) && (x <= zoneRegion2.getMaxX()) && + (y >= zoneRegion2.getMinY()) && (y <= zoneRegion2.getMaxY())) + ptUpdate->getBuilderZoneRegion(m)->updateTrans(x, y); + } + + // Cross material + for (m = 0; m < (sint32)tCreate.size(); ++m) + { + const NLLIGO::CZoneRegion &zoneRegion2 = m_zoneBuilder->zoneRegion(tCreate.getBuilderZoneRegion(m)->getRegionId())->ligoZoneRegion(); + x = tCreate.getX(m); + y = tCreate.getY(m); + + + ZonePosition zoneTemp(x, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zoneTemp); + + std::set matNameSet; + for (i = 0; i < 4; ++i) + matNameSet.insert(dataZoneTemp.sharingMatNames[i]); + + if (((dataZoneTemp.sharingMatNames[0] == dataZoneTemp.sharingMatNames[3]) && + (dataZoneTemp.sharingMatNames[1] == dataZoneTemp.sharingMatNames[2]) && + (dataZoneTemp.sharingMatNames[0] != dataZoneTemp.sharingMatNames[1])) + || (matNameSet.size()>2)) + { + NLLIGO::CZoneBank &zoneBank = m_zoneBuilder->getZoneBank(); + zoneBank.resetSelection(); + zoneBank.addOrSwitch("material", tCreate.getMat(m)); + zoneBank.addAndSwitch("size", "1x1"); + std::vector vElts; + zoneBank.getSelection(vElts); + if (vElts.size() == 0) + return; + sint32 nRan = (sint32)(NLMISC::frand((float)vElts.size())); + NLMISC::clamp(nRan, (sint32)0, (sint32)(vElts.size() - 1)); + NLLIGO::CZoneBankElement *zoneBankElement = vElts[nRan]; + nRan = (uint32)(NLMISC::frand (1.0) * 4); + NLMISC::clamp(nRan, (sint32)0, (sint32)3); + uint8 rot = (uint8)nRan; + nRan = (uint32)(NLMISC::frand (1.0) * 2); + NLMISC::clamp (nRan, (sint32)0, (sint32)1); + uint8 flip = (uint8)nRan; + + tCreate.getBuilderZoneRegion(m)->add(x, y, rot, flip, zoneBankElement); + } + } +} + +struct STrans +{ + uint8 Num; + uint8 Rot; + uint8 Flip; +}; + +STrans TranConvTable[128] = +{ + { 0,0,0 }, // Quart = 0, CutEdge = 0, Np = 0 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 0, Np = 1 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 1, Np = 0 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 1, Np = 1 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 2, Np = 0 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 2, Np = 1 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 3, Np = 0 UNUSED + { 0,0,0 }, // Quart = 0, CutEdge = 3, Np = 1 UNUSED + + { 6,0,0 }, // Quart = 1, CutEdge = 0, Np = 0 + { 6,3,1 }, // Quart = 1, CutEdge = 0, Np = 1 + { 7,0,0 }, // Quart = 1, CutEdge = 1, Np = 0 + { 7,0,0 }, // Quart = 1, CutEdge = 1, Np = 1 + { 7,3,1 }, // Quart = 1, CutEdge = 2, Np = 0 + { 7,3,1 }, // Quart = 1, CutEdge = 2, Np = 1 + { 8,0,0 }, // Quart = 1, CutEdge = 3, Np = 0 + { 8,3,1 }, // Quart = 1, CutEdge = 3, Np = 1 + + { 7,0,1 }, // Quart = 2, CutEdge = 0, Np = 0 + { 7,0,1 }, // Quart = 2, CutEdge = 0, Np = 1 + { 6,0,1 }, // Quart = 2, CutEdge = 1, Np = 0 + { 6,1,0 }, // Quart = 2, CutEdge = 1, Np = 1 + { 8,1,0 }, // Quart = 2, CutEdge = 2, Np = 0 + { 8,0,1 }, // Quart = 2, CutEdge = 2, Np = 1 + { 7,1,0 }, // Quart = 2, CutEdge = 3, Np = 0 + { 7,1,0 }, // Quart = 2, CutEdge = 3, Np = 1 + + { 0,0,0 }, // Quart = 3, CutEdge = 0, Np = 0 + { 0,0,1 }, // Quart = 3, CutEdge = 0, Np = 1 + { 1,0,1 }, // Quart = 3, CutEdge = 1, Np = 0 + { 1,0,1 }, // Quart = 3, CutEdge = 1, Np = 1 + { 1,0,0 }, // Quart = 3, CutEdge = 2, Np = 0 + { 1,0,0 }, // Quart = 3, CutEdge = 2, Np = 1 + { 2,0,0 }, // Quart = 3, CutEdge = 3, Np = 0 + { 2,0,1 }, // Quart = 3, CutEdge = 3, Np = 1 + + { 7,3,0 }, // Quart = 4, CutEdge = 0, Np = 0 + { 7,3,0 }, // Quart = 4, CutEdge = 0, Np = 1 + { 8,3,0 }, // Quart = 4, CutEdge = 1, Np = 0 + { 8,2,1 }, // Quart = 4, CutEdge = 1, Np = 1 + { 6,3,0 }, // Quart = 4, CutEdge = 2, Np = 0 + { 6,2,1 }, // Quart = 4, CutEdge = 2, Np = 1 + { 7,2,1 }, // Quart = 4, CutEdge = 3, Np = 0 + { 7,2,1 }, // Quart = 4, CutEdge = 3, Np = 1 + + { 0,3,0 }, // Quart = 5, CutEdge = 0, Np = 0 + { 0,3,1 }, // Quart = 5, CutEdge = 0, Np = 1 + { 1,3,1 }, // Quart = 5, CutEdge = 1, Np = 0 + { 1,3,1 }, // Quart = 5, CutEdge = 1, Np = 1 + { 1,3,0 }, // Quart = 5, CutEdge = 2, Np = 0 + { 1,3,0 }, // Quart = 5, CutEdge = 2, Np = 1 + { 2,3,0 }, // Quart = 5, CutEdge = 3, Np = 0 + { 2,3,1 }, // Quart = 5, CutEdge = 3, Np = 1 + + { 0,0,0 }, // Quart = 6, CutEdge = 0, Np = 0 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 0, Np = 1 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 1, Np = 0 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 1, Np = 1 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 2, Np = 0 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 2, Np = 1 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 3, Np = 0 UNUSED + { 0,0,0 }, // Quart = 6, CutEdge = 3, Np = 1 UNUSED + + { 5,2,0 }, // Quart = 7, CutEdge = 0, Np = 0 + { 5,1,1 }, // Quart = 7, CutEdge = 0, Np = 1 + { 4,1,1 }, // Quart = 7, CutEdge = 1, Np = 0 + { 4,1,1 }, // Quart = 7, CutEdge = 1, Np = 1 + { 4,2,0 }, // Quart = 7, CutEdge = 2, Np = 0 + { 4,2,0 }, // Quart = 7, CutEdge = 2, Np = 1 + { 3,2,0 }, // Quart = 7, CutEdge = 3, Np = 0 + { 3,1,1 }, // Quart = 7, CutEdge = 3, Np = 1 + + { 8,2,0 }, // Quart = 8, CutEdge = 0, Np = 0 + { 8,1,1 }, // Quart = 8, CutEdge = 0, Np = 1 + { 7,1,1 }, // Quart = 8, CutEdge = 1, Np = 0 + { 7,1,1 }, // Quart = 8, CutEdge = 1, Np = 1 + { 7,2,0 }, // Quart = 8, CutEdge = 2, Np = 0 + { 7,2,0 }, // Quart = 8, CutEdge = 2, Np = 1 + { 6,2,0 }, // Quart = 8, CutEdge = 3, Np = 0 + { 6,1,1 }, // Quart = 8, CutEdge = 3, Np = 1 + + { 0,0,0 }, // Quart = 9, CutEdge = 0, Np = 0 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 0, Np = 1 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 1, Np = 0 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 1, Np = 1 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 2, Np = 0 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 2, Np = 1 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 3, Np = 0 UNUSED + { 0,0,0 }, // Quart = 9, CutEdge = 3, Np = 1 UNUSED + + { 2,1,0 }, // Quart = 10, CutEdge = 0, Np = 0 + { 2,1,1 }, // Quart = 10, CutEdge = 0, Np = 1 + { 1,1,1 }, // Quart = 10, CutEdge = 1, Np = 0 + { 1,1,1 }, // Quart = 10, CutEdge = 1, Np = 1 + { 1,1,0 }, // Quart = 10, CutEdge = 2, Np = 0 + { 1,1,0 }, // Quart = 10, CutEdge = 2, Np = 1 + { 0,1,0 }, // Quart = 10, CutEdge = 3, Np = 0 + { 0,1,1 }, // Quart = 10, CutEdge = 3, Np = 1 + + { 4,3,0 }, // Quart = 11, CutEdge = 0, Np = 0 + { 4,3,0 }, // Quart = 11, CutEdge = 0, Np = 1 + { 5,3,0 }, // Quart = 11, CutEdge = 1, Np = 0 + { 5,2,1 }, // Quart = 11, CutEdge = 1, Np = 1 + { 3,3,0 }, // Quart = 11, CutEdge = 2, Np = 0 + { 3,2,1 }, // Quart = 11, CutEdge = 2, Np = 1 + { 4,2,1 }, // Quart = 11, CutEdge = 3, Np = 0 + { 4,2,1 }, // Quart = 11, CutEdge = 3, Np = 1 + + { 2,2,0 }, // Quart = 12, CutEdge = 0, Np = 0 + { 2,2,1 }, // Quart = 12, CutEdge = 0, Np = 1 + { 1,2,1 }, // Quart = 12, CutEdge = 1, Np = 0 + { 1,2,1 }, // Quart = 12, CutEdge = 1, Np = 1 + { 1,2,0 }, // Quart = 12, CutEdge = 2, Np = 0 + { 1,2,0 }, // Quart = 12, CutEdge = 2, Np = 1 + { 0,2,0 }, // Quart = 12, CutEdge = 3, Np = 0 + { 0,2,1 }, // Quart = 12, CutEdge = 3, Np = 1 + + { 4,0,1 }, // Quart = 13, CutEdge = 0, Np = 0 + { 4,0,1 }, // Quart = 13, CutEdge = 0, Np = 1 + { 3,1,0 }, // Quart = 13, CutEdge = 1, Np = 0 + { 3,0,1 }, // Quart = 13, CutEdge = 1, Np = 1 + { 5,1,0 }, // Quart = 13, CutEdge = 2, Np = 0 + { 5,0,1 }, // Quart = 13, CutEdge = 2, Np = 1 + { 4,1,0 }, // Quart = 13, CutEdge = 3, Np = 0 + { 4,1,0 }, // Quart = 13, CutEdge = 3, Np = 1 + + { 3,0,0 }, // Quart = 14, CutEdge = 0, Np = 0 + { 3,3,1 }, // Quart = 14, CutEdge = 0, Np = 1 + { 4,0,0 }, // Quart = 14, CutEdge = 1, Np = 0 + { 4,0,0 }, // Quart = 14, CutEdge = 1, Np = 1 + { 4,3,1 }, // Quart = 14, CutEdge = 2, Np = 0 + { 4,3,1 }, // Quart = 14, CutEdge = 2, Np = 1 + { 5,0,0 }, // Quart = 14, CutEdge = 3, Np = 0 + { 5,3,1 }, // Quart = 14, CutEdge = 3, Np = 1 + + { 0,0,0 }, // Quart = 15, CutEdge = 0, Np = 0 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 0, Np = 1 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 1, Np = 0 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 1, Np = 1 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 2, Np = 0 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 2, Np = 1 UNUSED + { 0,0,0 }, // Quart = 15, CutEdge = 3, Np = 0 UNUSED + { 0,0,0 } // Quart = 15, CutEdge = 3, Np = 1 UNUSED +}; + +void BuilderZoneRegion::updateTrans (sint32 x, sint32 y, NLLIGO::CZoneBankElement *zoneBankElement) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + if ((x < zoneRegion.getMinX()) || (x > zoneRegion.getMaxX()) || + (y < zoneRegion.getMinY()) || (y > zoneRegion.getMaxY())) + return; + + //if (!_Builder->getZoneMask(x,y)) + // return; + + // Interpret the transition info + x -= zoneRegion.getMinX (); + y -= zoneRegion.getMinY (); + sint32 m; + + // Calculate the number of material around with transition info + std::set matNameSet; + + ZonePosition zonePosTemp(x + zoneRegion.getMinX(), y + zoneRegion.getMinY(), m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + LigoData dataZoneTempOriginal = dataZoneTemp; + + for (m = 0; m < 4; ++m) + matNameSet.insert(dataZoneTemp.sharingMatNames[m]); + + if (matNameSet.size() == 1) + { + if (dataZoneTemp.sharingMatNames[0] == STRING_UNUSED) + { + del(x + zoneRegion.getMinX (), y + zoneRegion.getMinY ()); + // set (x+pBZR->getMinX (), y+pBZR->getMinY (), 0, 0, STRING_UNUSED, false); + return; + } + else + { + NLLIGO::CZoneBankElement *zoneBankElement2 = m_zoneBuilder->getZoneBank().getElementByZoneName(dataZoneTemp.zoneName); + if ((zoneBankElement != NULL) && (zoneBankElement2 != NULL) && (zoneBankElement2->getCategory("material") == dataZoneTemp.sharingMatNames[0])) + return; + + NLLIGO::CZoneBank &zoneBank = m_zoneBuilder->getZoneBank(); + zoneBank.resetSelection (); + zoneBank.addOrSwitch ("material", dataZoneTemp.sharingMatNames[0]); + zoneBank.addAndSwitch ("size", "1x1"); + std::vector vElts; + zoneBank.getSelection (vElts); + if (vElts.size() == 0) + return; + sint32 nRan = (sint32)(NLMISC::frand((float)vElts.size())); + NLMISC::clamp (nRan, (sint32)0, (sint32)(vElts.size()-1)); + zoneBankElement = vElts[nRan]; + nRan = (uint32)(NLMISC::frand(1.0) * 4); + NLMISC::clamp (nRan, (sint32)0, (sint32)3); + uint8 rot = (uint8)nRan; + nRan = (uint32)(NLMISC::frand(1.0) * 2); + NLMISC::clamp (nRan, (sint32)0, (sint32)1); + uint8 flip = (uint8)nRan; + + set(x + zoneRegion.getMinX(), y + zoneRegion.getMinY(), 0, 0, zoneBankElement->getName(), false); + setRot(x + zoneRegion.getMinX(), y + zoneRegion.getMinY(), rot); + setFlip(x + zoneRegion.getMinX(), y + zoneRegion.getMinY(), flip); + return; + } + } + + // No 2 materials so the transition system dont work + if (matNameSet.size() != 2) + return; + + std::set::iterator it = matNameSet.begin(); + std::string matA = *it; + ++it; + std::string matB = *it; + + NLLIGO::CZoneBank &zoneBank = m_zoneBuilder->getZoneBank(); + zoneBank.resetSelection (); + zoneBank.addOrSwitch("transname", matA + "-" + matB); + std::vector selection; + zoneBank.getSelection(selection); + if (selection.size() == 0) + { + std::string matTmp = matA; + matA = matB; + matB = matTmp; + zoneBank.resetSelection (); + zoneBank.addOrSwitch ("transname", matA + "-" + matB); + zoneBank.getSelection (selection); + } + + if (selection.size() == 0) + return; + + // Convert the sharingCutEdges and SharingNames to the num and type of transition + uint8 nQuart = 0; // 0-MatA 1-MatB + for (m = 0; m < 4; ++m) + if (dataZoneTemp.sharingMatNames[m] == matB) + nQuart |= (1 << m); + + if ((nQuart == 0) || (nQuart == 6) || + (nQuart == 9) || (nQuart == 15)) + return; // No transition for those types + + uint8 nCutEdge = 0; + uint8 nPosCorner = 0; + + // If up edge is cut write the cut position in nCutEdge bitfield (1->0, 2->1) + if ((nQuart == 4) || (nQuart == 5) || + (nQuart == 7) || (nQuart == 8) || + (nQuart == 10) || (nQuart == 11)) + { + if (dataZoneTemp.sharingCutEdges[0] == 2) + nCutEdge |= 1 << nPosCorner; + ++nPosCorner; + } + else + { + dataZoneTemp.sharingCutEdges[0] = 0; + } + + // Same for down edge + if ((nQuart == 1) || (nQuart == 2) || + (nQuart == 5) || (nQuart == 10) || + (nQuart == 13) || (nQuart == 14)) + { + if (dataZoneTemp.sharingCutEdges[1] == 2) + nCutEdge |= 1 << nPosCorner; + ++nPosCorner; + } + else + { + dataZoneTemp.sharingCutEdges[1] = 0; + } + + // Same for left edge + if ((nQuart == 1) || (nQuart == 3) || + (nQuart == 4) ||(nQuart == 11) || + (nQuart == 12) || (nQuart == 14)) + { + if (dataZoneTemp.sharingCutEdges[2] == 2) + nCutEdge |= 1 << nPosCorner; + ++nPosCorner; + } + else + { + dataZoneTemp.sharingCutEdges[2] = 0; + } + + // Same for right edge + if ((nQuart == 2) || (nQuart == 3) || + (nQuart == 7) || (nQuart == 8) || + (nQuart == 12) || (nQuart == 13)) + { + if (dataZoneTemp.sharingCutEdges[3] == 2) + nCutEdge |= 1 << nPosCorner; + ++nPosCorner; + } + else + { + dataZoneTemp.sharingCutEdges[3] = 0; + } + + nlassert (nPosCorner == 2); // If not this means that more than 2 edges are cut which is not possible + + STrans Trans, TransTmp1, TransTmp2; + + TransTmp1 = TranConvTable[nQuart * 8 + 2 * nCutEdge + 0]; + TransTmp2 = TranConvTable[nQuart * 8 + 2 * nCutEdge + 1]; + + // Choose one or the two + sint32 nTrans = (sint32)(NLMISC::frand(2.0f)); + NLMISC::clamp(nTrans, (sint32)0, (sint32)1); + if (nTrans == 0) + Trans = TransTmp1; + else + Trans = TransTmp2; + + zoneBank.addAndSwitch ("transnum", NLMISC::toString(Trans.Num)); + zoneBank.getSelection (selection); + + if (selection.size() > 0) + { + if (zoneBankElement != NULL) + { + dataZoneTemp.zoneName = zoneBankElement->getName(); + } + else + { + nTrans = (uint32)(NLMISC::frand (1.0) * selection.size()); + NLMISC::clamp(nTrans, (sint32)0, (sint32)(selection.size() - 1)); + dataZoneTemp.zoneName = selection[nTrans]->getName(); + } + dataZoneTemp.posX = dataZoneTemp.posY = 0; + dataZoneTemp.rot = Trans.Rot; + dataZoneTemp.flip = Trans.Flip; + } + + // Add modification landscape + if (dataZoneTempOriginal != dataZoneTemp) + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); +} + +std::string BuilderZoneRegion::getNextMatInTree (const std::string &matA, const std::string &matB) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + uint32 i, posA = 10000, posB = 10000; + + if (matA == matB) + return matA; + + for (i = 0; i < m_matTree.size(); ++i) + { + if (m_matTree[i].Name == matA) + posA = i; + if (m_matTree[i].Name == matB) + posB = i; + } + if ((posA == 10000) || (posB == 10000)) + return STRING_UNUSED; + + std::vector vTemp; + tryPath (posA, posB, vTemp); + if (vTemp.size() <= 1) + return STRING_UNUSED; + else + return m_matTree[vTemp[1]].Name; +} + +struct SNode +{ + sint32 NodePos, Dist, PrevNodePos; + + SNode() + { + NodePos = Dist = PrevNodePos = -1; + } +}; + +void BuilderZoneRegion::tryPath(uint32 posA, uint32 posB, std::vector &path) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + + // Build the adjascence matrix + std::vector matAdj; + sint32 numNodes = m_matTree.size(); + sint32 i, j, cost; + matAdj.resize(numNodes * numNodes, -1); + for (i = 0; i < numNodes; ++i) + for (j = 0; j < (sint32)m_matTree[i].Arcs.size(); ++j) + matAdj[i + m_matTree[i].Arcs[j] * numNodes] = 1; + + std::vector vNodes; // NodesPos == index + vNodes.resize (numNodes); + for (i = 0; i < numNodes; ++i) + vNodes[i].NodePos = i; + vNodes[posA].Dist = 0; + + std::queue qNodes; + qNodes.push (vNodes[posA]); + + while (qNodes.size() > 0) + { + SNode node = qNodes.front(); + qNodes.pop (); + + for (i = 0; i < numNodes; ++i) + { + cost = matAdj[node.NodePos + i * numNodes]; + if (cost != -1) + { + if ((vNodes[i].Dist == -1) || (vNodes[i].Dist > (cost + node.Dist))) + { + vNodes[i].Dist = cost + node.Dist; + vNodes[i].PrevNodePos = node.NodePos; + qNodes.push(vNodes[i]); + } + } + } + } + + // Get path length + i = posB; + j = 0; + while (i != -1) + { + ++j; + i = vNodes[i].PrevNodePos; + } + + // Write the path in the good order (from posA to posB) + path.resize(j); + i = posB; + while (i != -1) + { + --j; + path[j] = i; + i = vNodes[i].PrevNodePos; + } +} + +void BuilderZoneRegion::del(sint32 x, sint32 y, bool transition, ToUpdate *pUpdate) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + if (!m_zoneBuilder->getZoneMask(x, y)) + return; + + const std::string &nameZone = zoneRegion.getName(x, y); + NLLIGO::CZoneBankElement *zoneBankElement = m_zoneBuilder->getZoneBank().getElementByZoneName(nameZone); + if (zoneBankElement != NULL) + { + sint32 sizeX = zoneBankElement->getSizeX(), sizeY = zoneBankElement->getSizeY(); + sint32 posX = zoneRegion.getPosX (x, y), posY = zoneRegion.getPosY (x, y); + uint8 rot = zoneRegion.getRot (x, y); + uint8 flip = zoneRegion.getFlip (x, y); + sint32 i, j; + sint32 deltaX, deltaY; + + if (flip == 0) + { + switch (rot) + { + case 0: + deltaX = -posX; + deltaY = -posY; + break; + case 1: + deltaX = -(sizeY - 1 - posY); + deltaY = -posX; + break; + case 2: + deltaX = -(sizeX - 1 - posX); + deltaY = -(sizeY - 1 - posY); + break; + case 3: + deltaX = -posY; + deltaY = -(sizeX - 1 - posX); + break; + } + } + else + { + switch (rot) + { + case 0: + deltaX = -(sizeX - 1 - posX); + deltaY = -posY; + break; + case 1: + deltaX = -(sizeY - 1 - posY); + deltaY = -(sizeX - 1 - posX); + break; + case 2: + deltaX = -posX; + deltaY = -(sizeY - 1 - posY); + break; + case 3: + deltaX = -posY; + deltaY = -posX; + break; + } + } + + NLLIGO::SPiece mask; + mask.Tab.resize (sizeX * sizeY); + for(i = 0; i < sizeX * sizeY; ++i) + mask.Tab[i] = zoneBankElement->getMask()[i]; + mask.w = sizeX; + mask.h = sizeY; + mask.rotFlip (rot, flip); + + for (j = 0; j < mask.h; ++j) + for (i = 0; i < mask.w; ++i) + if (mask.Tab[i + j * mask.w]) + { + set(x + deltaX + i, y + deltaY + j, 0, 0, STRING_UNUSED, true); + setRot(x + deltaX + i, y + deltaY + j, 0); + setFlip(x + deltaX + i, y + deltaY + j, 0); + if (pUpdate != NULL) + { + pUpdate->add(this, x + deltaX + i, y + deltaY + j, ""); + } + } + if (!transition) + reduceMin (); + } + else + { + if ((x < zoneRegion.getMinX()) || (x > zoneRegion.getMaxX()) || + (y < zoneRegion.getMinY()) || (y > zoneRegion.getMaxY())) + return; + + ZonePosition zonePosTemp(x, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + LigoData dataZoneTempOriginal = dataZoneTemp; + + dataZoneTemp.zoneName = STRING_UNUSED; + dataZoneTemp.posX = 0; + dataZoneTemp.posY = 0; + + for (uint32 i = 0; i < 4; ++i) + { + dataZoneTemp.sharingMatNames[i] = STRING_UNUSED; + dataZoneTemp.sharingCutEdges[i] = 0; + } + + // Add modification landscape + if (dataZoneTempOriginal != dataZoneTemp) + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + + } +} + +void BuilderZoneRegion::move (sint32 x, sint32 y) +{ + m_zoneBuilder->actionLigoMove(m_regionId, x, y); +} + +uint32 BuilderZoneRegion::countZones () +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + sint32 x, y; + + uint32 counter = 0; + + for (y = zoneRegion.getMinY (); y <= zoneRegion.getMaxY (); ++y) + for (x = zoneRegion.getMinX (); x <= zoneRegion.getMaxX (); ++x) + if (zoneRegion.getName (x, y) != STRING_UNUSED) + ++counter; + + return counter; +} + +void BuilderZoneRegion::set(sint32 x, sint32 y, sint32 posX, sint32 posY, + const std::string &zoneName, bool transition) +{ + ZoneRegionObject *zoneRegionObj = m_zoneBuilder->zoneRegion(m_regionId); + if (zoneRegionObj == 0) + return; + + const NLLIGO::CZoneRegion &zoneRegion = zoneRegionObj->ligoZoneRegion(); + + // Do we need to resize ? + if ((x < zoneRegion.getMinX()) || (x > zoneRegion.getMaxX()) || + (y < zoneRegion.getMinY()) || (y > zoneRegion.getMaxY())) + { + sint32 newMinX = (x < zoneRegion.getMinX() ? x: zoneRegion.getMinX()), newMinY = (y < zoneRegion.getMinY() ? y: zoneRegion.getMinY()); + sint32 newMaxX = (x > zoneRegion.getMaxX() ? x: zoneRegion.getMaxX()), newMaxY = (y > zoneRegion.getMaxY() ? y: zoneRegion.getMaxY()); + + resize(newMinX, newMaxX, newMinY, newMaxY); + } + + ZonePosition zonePosTemp(x, y, m_regionId); + LigoData dataZoneTemp; + if (!m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp)) + return; + LigoData dataZoneTempOriginal = dataZoneTemp; + + dataZoneTemp.zoneName = zoneName; + dataZoneTemp.posX = (uint8)posX; + dataZoneTemp.posY = (uint8)posY; + + if (!transition) + { + NLLIGO::CZoneBankElement *zoneBankElem = m_zoneBuilder->getZoneBank().getElementByZoneName(zoneName); + if (zoneBankElem == NULL) + return; + + const std::string &matName = zoneBankElem->getCategory ("material"); + if (matName == STRING_NO_CAT_TYPE) + return; + for (uint32 i = 0; i < 4; ++i) + { + dataZoneTemp.sharingMatNames[i] = matName; + dataZoneTemp.sharingCutEdges[i] = 0; + } + + // Add modification landscape + if (dataZoneTempOriginal != dataZoneTemp) + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + + BuilderZoneRegion *builderZoneRegion = this; + ZonePosition zonePosU; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x - 1, y - 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingMatNames[3] != matName) + { + data.sharingMatNames[3] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x, y - 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if ((data.sharingMatNames[2] != matName) || (data.sharingMatNames[3] != matName)) + { + data.sharingMatNames[2] = matName; + data.sharingMatNames[3] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x + 1, y - 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingMatNames[2] != matName) + { + data.sharingMatNames[2] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x - 1, y)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if ((data.sharingMatNames[1] != matName) || (data.sharingMatNames[3] != matName)) + { + data.sharingMatNames[1] = matName; + data.sharingMatNames[3] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x + 1, y)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if ((data.sharingMatNames[0] != matName) || (data.sharingMatNames[2] != matName)) + { + data.sharingMatNames[0] = matName; + data.sharingMatNames[2] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x - 1, y + 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingMatNames[1] != matName) + { + data.sharingMatNames[1] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x, y + 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if ((data.sharingMatNames[0] != matName) || (data.sharingMatNames[1] != matName)) + { + data.sharingMatNames[0] = matName; + data.sharingMatNames[1] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + builderZoneRegion = this; + if (m_zoneBuilder->getZoneAmongRegions(zonePosU, builderZoneRegion, x + 1, y + 1)) + { + LigoData data; + m_zoneBuilder->ligoData(data, zonePosU); + if (data.sharingMatNames[0] != matName) + { + data.sharingMatNames[0] = matName; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(data, zonePosU); + } + } + } + else + { + // Add modification landscape + if (dataZoneTempOriginal != dataZoneTemp) + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } +} + +void BuilderZoneRegion::setRot (sint32 x, sint32 y, uint8 rot) +{ + ZonePosition zonePosTemp(x, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.rot != rot) + { + dataZoneTemp.rot = rot; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } +} + +void BuilderZoneRegion::setFlip(sint32 x, sint32 y, uint8 flip) +{ + ZonePosition zonePosTemp(x, y, m_regionId); + LigoData dataZoneTemp; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + if (dataZoneTemp.flip != flip) + { + dataZoneTemp.flip = flip; + + // Add modification landscape + m_zoneBuilder->actionLigoTile(dataZoneTemp, zonePosTemp); + } +} + + +void BuilderZoneRegion::reduceMin () +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + sint32 i, j; + + sint32 newMinX = zoneRegion.getMinX(), newMinY = zoneRegion.getMinY (); + sint32 newMaxX = zoneRegion.getMaxX(), newMaxY = zoneRegion.getMaxY (); + bool bCanSuppr; + + // Reduce the MinY + while (true) + { + if (newMinY == newMaxY) + break; + j = newMinY; + bCanSuppr = true; + for (i = newMinX; i <= newMaxX; ++i) + { + std::string str = zoneRegion.getName (i, j) ; + if (!str.empty() && (str != STRING_UNUSED)) + { + bCanSuppr = false; + break; + } + } + if (bCanSuppr) + ++newMinY; + else + break; + } + + // Reduce the MaxY + while (true) + { + if (newMinY == newMaxY) + break; + j = newMaxY; + bCanSuppr = true; + for (i = newMinX; i <= newMaxX; ++i) + { + std::string str = zoneRegion.getName (i, j) ; + if (!str.empty() && (str != STRING_UNUSED)) + { + bCanSuppr = false; + break; + } + } + if (bCanSuppr) + --newMaxY; + else + break; + } + + // Reduce the MinX + while (true) + { + if (newMinX == newMaxX) + break; + i = newMinX; + bCanSuppr = true; + for (j = newMinY; j <= newMaxY; ++j) + { + std::string str = zoneRegion.getName (i, j) ; + if (!str.empty() && (str != STRING_UNUSED)) + { + bCanSuppr = false; + break; + } + } + if (bCanSuppr) + ++newMinX; + else + break; + } + + // Reduce the MaxX + while (true) + { + if (newMinX == newMaxX) + break; + i = newMaxX; + bCanSuppr = true; + for (j = newMinY; j <= newMaxY; ++j) + { + std::string str = zoneRegion.getName (i, j) ; + if (!str.empty() && (str != STRING_UNUSED)) + { + bCanSuppr = false; + break; + } + } + if (bCanSuppr) + --newMaxX; + else + break; + } + + if ((newMinX != zoneRegion.getMinX ()) || + (newMinY != zoneRegion.getMinY ()) || + (newMaxX != zoneRegion.getMaxX ()) || + (newMaxY != zoneRegion.getMaxY ())) + { + resize(newMinX, newMaxX, newMinY, newMaxY); + } +} + +uint BuilderZoneRegion::getRegionId() const +{ + return m_regionId; +} + +void BuilderZoneRegion::resize (sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + if ((zoneRegion.getMinX ()!= newMinX) || + (zoneRegion.getMaxX ()!= newMaxX) || + (zoneRegion.getMinY ()!= newMinY) || + (zoneRegion.getMaxY ()!= newMaxY)) + { + m_zoneBuilder->actionLigoResize(m_regionId, newMinX, newMaxX, newMinY, newMaxY); + } +} + +void BuilderZoneRegion::placePiece(sint32 x, sint32 y, uint8 rot, uint8 flip, + NLLIGO::SPiece &sMask, NLLIGO::SPiece &sPosX, NLLIGO::SPiece &sPosY, + const std::string &eltName) +{ + for (int j = 0; j < sMask.h; ++j) + for (int i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + set(x + i, y + j, sPosX.Tab[i + j * sPosX.w], sPosY.Tab[i + j * sPosY.w], eltName); + setRot(x + i, y + j, rot); + setFlip(x + i, y + j, flip); + } +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.h new file mode 100644 index 000000000..2170c67b9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.h @@ -0,0 +1,107 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// 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 BUILDER_ZONE_REGION_H +#define BUILDER_ZONE_REGION_H + +// Project includes + +// NeL includes +#include +#include + +// STL includes +#include +#include +#include + +// Qt includes + +namespace LandscapeEditor +{ +class ZoneBuilder; +class ToUpdate; + +// CZoneRegion contains informations about the zones painted. +// (Legacy class from old world editor. It needs to refactoring!) +class BuilderZoneRegion +{ +public: + + explicit BuilderZoneRegion(uint regionId); + + // New interface + bool init(ZoneBuilder *zoneBuilder); + void add(sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement); + void invertCutEdge(sint32 x, sint32 y, uint8 cePos); + void cycleTransition(sint32 x, sint32 y); + bool addNotPropagate(sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement); + + /// Brutal adding a zone over empty space do not propagate in any way -> can result + /// in inconsistency when trying the propagation mode + void addForce (sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement); + void del(sint32 x, sint32 y, bool transition = false, ToUpdate *pUpdate = 0); + void move(sint32 x, sint32 y); + uint32 countZones(); + void reduceMin(); + uint getRegionId() const; + +private: + + // An element of the graph + struct SMatNode + { + std::string Name; + // Position in the tree (vector of nodes) + std::vector Arcs; + }; + + void addTransition(sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement); + + void addToUpdateAndCreate(BuilderZoneRegion *builderZoneRegion, sint32 sharePos, sint32 x, sint32 y, + const std::string &newMat, ToUpdate *ptCreate, ToUpdate *ptUpdate); + + void putTransitions(sint32 x, sint32 y, const NLLIGO::SPiece &mask, const std::string &matName, ToUpdate *ptUpdate); + void updateTrans(sint32 x, sint32 y, NLLIGO::CZoneBankElement *zoneBankElement = 0); + + std::string getNextMatInTree(const std::string &matA, const std::string &matB); + + /// Find the fastest way between posA and posB in the MatTree (Dijkstra) + void tryPath(uint32 posA, uint32 posB, std::vector &path); + + void set(sint32 x, sint32 y, sint32 posX, sint32 posY, const std::string &zoneName, bool transition = false); + void setRot(sint32 x, sint32 y, uint8 rot); + void setFlip(sint32 x, sint32 y, uint8 flip); + void resize(sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY); + + void placePiece(sint32 x, sint32 y, uint8 rot, uint8 flip, + NLLIGO::SPiece &sMask, NLLIGO::SPiece &sPosX, NLLIGO::SPiece &sPosY, + const std::string &eltName); + + uint m_regionId; + + // To use the global mask + ZoneBuilder *m_zoneBuilder; + + // The tree of transition between materials + std::vector m_matTree; + + bool m_firstInit; +}; + +} /* namespace LandscapeEditor */ + +#endif // BUILDER_ZONE_REGION_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_grid.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_grid.png new file mode 100644 index 000000000..3534b70ae Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_grid.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png new file mode 100644 index 000000000..99da545b1 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png new file mode 100644 index 000000000..cdb8230ea Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png new file mode 100644 index 000000000..a45143aa4 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp new file mode 100644 index 000000000..e5b3ad4d4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp @@ -0,0 +1,178 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "landscape_actions.h" +#include "builder_zone.h" + +// NeL includes +#include + +// Qt includes + +namespace LandscapeEditor +{ + +LigoTileCommand::LigoTileCommand(const LigoData &data, const ZonePosition &zonePos, + ZoneBuilder *zoneBuilder, LandscapeScene *scene, + QUndoCommand *parent) + : QUndoCommand(parent), + m_zoneBuilder(zoneBuilder), + m_scene(scene) +{ + // Backup position + m_zonePos = zonePos; + + // Backup new data + m_newLigoData = data; + + // Backup old data + m_zoneBuilder->ligoData(m_oldLigoData, m_zonePos); +} + +LigoTileCommand::~LigoTileCommand() +{ +} + +void LigoTileCommand::undo () +{ + m_zoneBuilder->setLigoData(m_oldLigoData, m_zonePos); +} + +void LigoTileCommand::redo () +{ + m_zoneBuilder->setLigoData(m_newLigoData, m_zonePos); +} + +UndoScanRegionCommand::UndoScanRegionCommand(bool direction, ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent) + : QUndoCommand(parent), + m_direction(direction), + m_zoneBuilder(zoneBuilder), + m_scene(scene) +{ +} + +UndoScanRegionCommand::~UndoScanRegionCommand() +{ + m_zonePositionList.clear(); +} + +void UndoScanRegionCommand::setScanList(const QList &zonePositionList) +{ + m_zonePositionList = zonePositionList; +} + +void UndoScanRegionCommand::undo() +{ + if (m_direction) + applyChanges(); +} + +void UndoScanRegionCommand::redo() +{ + if (!m_direction) + applyChanges(); +} + +void UndoScanRegionCommand::applyChanges() +{ + for (int i = 0; i < m_zonePositionList.size(); ++i) + m_scene->deleteItemZone(m_zonePositionList.at(i)); + + for (int i = 0; i < m_zonePositionList.size(); ++i) + { + LigoData data; + m_zoneBuilder->ligoData(data, m_zonePositionList.at(i)); + m_scene->createItemZone(data, m_zonePositionList.at(i)); + } +} + +LigoResizeCommand::LigoResizeCommand(int index, sint32 newMinX, sint32 newMaxX, + sint32 newMinY, sint32 newMaxY, ZoneBuilder *zoneBuilder, + QUndoCommand *parent) + : QUndoCommand(parent), + m_zoneBuilder(zoneBuilder) +{ + m_index = index; + m_newMinX = newMinX; + m_newMaxX = newMaxX; + m_newMinY = newMinY; + m_newMaxY = newMaxY; + + // Backup old region zone + m_oldZoneRegion = m_zoneBuilder->zoneRegion(m_index)->ligoZoneRegion(); +} + +LigoResizeCommand::~LigoResizeCommand() +{ +} + +void LigoResizeCommand::undo () +{ + // Restore old region zone + m_zoneBuilder->zoneRegion(m_index)->setLigoZoneRegion(m_oldZoneRegion); +} + +void LigoResizeCommand::redo () +{ + // Get the zone region + NLLIGO::CZoneRegion ®ion = m_zoneBuilder->zoneRegion(m_index)->ligoZoneRegion(); + + sint32 i, j; + std::vector newZones; + newZones.resize((1 + m_newMaxX - m_newMinX) * (1 + m_newMaxY - m_newMinY)); + + sint32 newStride = 1 + m_newMaxX - m_newMinX; + sint32 Stride = 1 + region.getMaxX() - region.getMinX(); + + for (j = m_newMinY; j <= m_newMaxY; ++j) + for (i = m_newMinX; i <= m_newMaxX; ++i) + { + // Ref on the new value + LigoData &data = newZones[(i - m_newMinX) + (j - m_newMinY) * newStride]; + + // In the old array ? + if ((i >= region.getMinX()) && (i <= region.getMaxX()) && + (j >= region.getMinY()) && (j <= region.getMaxY())) + { + // Backup values + m_zoneBuilder->ligoData(data, ZonePosition(i, j, m_index)); + } + } + region.resize(m_newMinX, m_newMaxX, m_newMinY, m_newMaxY); + + for (j = m_newMinY; j <= m_newMaxY; ++j) + for (i = m_newMinX; i <= m_newMaxX; ++i) + { + // Ref on the new value + const LigoData &data = newZones[(i - m_newMinX) + (j - m_newMinY) * newStride]; + + region.setName(i, j, data.zoneName); + region.setPosX(i, j, data.posX); + region.setPosY(i, j, data.posY); + region.setRot(i, j, data.rot); + region.setFlip(i, j, data.flip); + uint k; + for (k = 0; k < 4; k++) + { + region.setSharingMatNames(i, j, k, data.sharingMatNames[k]); + region.setSharingCutEdges(i, j, k, data.sharingCutEdges[k]); + } + } +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.h new file mode 100644 index 000000000..c976360fa --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.h @@ -0,0 +1,111 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 LANDSCAPE_ACTIONS_H +#define LANDSCAPE_ACTIONS_H + +// Project includes +#include "builder_zone.h" +#include "landscape_scene.h" + +// NeL includes + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LigoTileCommand +@brief +@details +*/ +class LigoTileCommand: public QUndoCommand +{ +public: + LigoTileCommand(const LigoData &data, const ZonePosition &zonePos, + ZoneBuilder *zoneBuilder, LandscapeScene *scene, + QUndoCommand *parent = 0); + virtual ~LigoTileCommand(); + + virtual void undo(); + virtual void redo(); + +private: + ZonePosition m_zonePos; + LigoData m_newLigoData; + LigoData m_oldLigoData; + ZoneBuilder *m_zoneBuilder; + LandscapeScene *m_scene; +}; + +/** +@class UndoScanRegionCommand +@brief +@details +*/ +class UndoScanRegionCommand: public QUndoCommand +{ +public: + UndoScanRegionCommand(bool direction, ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent = 0); + virtual ~UndoScanRegionCommand(); + + void setScanList(const QList &zonePositionList); + virtual void undo(); + virtual void redo(); + +private: + void applyChanges(); + + bool m_direction; + QList m_zonePositionList; + ZoneBuilder *m_zoneBuilder; + LandscapeScene *m_scene; +}; + +/** +@class LigoResizeCommand +@brief +@details +*/ +class LigoResizeCommand: public QUndoCommand +{ +public: + LigoResizeCommand(int index, sint32 newMinX, sint32 newMaxX, + sint32 newMinY, sint32 newMaxY, ZoneBuilder *zoneBuilder, + QUndoCommand *parent = 0); + virtual ~LigoResizeCommand(); + + virtual void undo(); + virtual void redo(); + +private: + int m_index; + sint32 m_newMinX; + sint32 m_newMaxX; + sint32 m_newMinY; + sint32 m_newMaxY; + NLLIGO::CZoneRegion m_oldZoneRegion; + ZoneBuilder *m_zoneBuilder; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_ACTIONS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc index 5dba9074b..2666d8a60 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc @@ -1,5 +1,9 @@ + icons/ic_nel_zones.png + icons/ic_snapshot.png + icons/ic_grid.png + icons/ic_nel_transition_land.png icons/ic_nel_landscape_item.png icons/ic_nel_landscape_settings.png icons/ic_nel_world_editor.png diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h index 52775f4c4..92845abb8 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -22,13 +21,19 @@ namespace LandscapeEditor { namespace Constants { -const char * const LANDSCAPE_EDITOR_PLUGIN = "LandscapeEditor"; +const char *const LANDSCAPE_EDITOR_PLUGIN = "LandscapeEditor"; //settings -const char * const LANDSCAPE_EDITOR_SECTION = "LandscapeEditor"; +const char *const LANDSCAPE_EDITOR_SECTION = "LandscapeEditor"; +const char *const LANDSCAPE_WINDOW_STATE = "LandscapeWindowState"; +const char *const LANDSCAPE_WINDOW_GEOMETRY = "LandscapeWindowGeometry"; +const char *const LANDSCAPE_DATA_DIRECTORY = "LandscapeDataDirectory"; +const char *const LANDSCAPE_USE_OPENGL = "LandscapeUseOpenGL"; //resources -const char * const ICON_LANDSCAPE_ITEM = ":/icons/ic_nel_landscape_item.png"; +const char *const ICON_LANDSCAPE_ITEM = ":/icons/ic_nel_landscape_item.png"; +const char *const ICON_ZONE_ITEM = ":/icons/ic_nel_zone.png"; +const char *const ICON_LANDSCAPE_ZONES = ":/icons/ic_nel_zones.png"; } // namespace Constants diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp index de3694e10..17556d03f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp @@ -1,128 +1,100 @@ -// Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// 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 "landscape_editor_plugin.h" -#include "landscape_editor_window.h" - -#include "../core/icore.h" -#include "../core/core_constants.h" - -// NeL includes -#include "nel/misc/debug.h" - -// Qt includes -#include - -namespace LandscapeEditor -{ - -LandscapeEditorPlugin::~LandscapeEditorPlugin() -{ - Q_FOREACH(QObject *obj, m_autoReleaseObjects) - { - m_plugMan->removeObject(obj); - } - qDeleteAll(m_autoReleaseObjects); - m_autoReleaseObjects.clear(); -} - -bool LandscapeEditorPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString) -{ - Q_UNUSED(errorString); - m_plugMan = pluginManager; - - addAutoReleasedObject(new LandscapeEditorContext(this)); - return true; -} - -void LandscapeEditorPlugin::extensionsInitialized() -{ -} - -void LandscapeEditorPlugin::shutdown() -{ -} - -void LandscapeEditorPlugin::setNelContext(NLMISC::INelContext *nelContext) -{ -#ifdef NL_OS_WINDOWS - // Ensure that a context doesn't exist yet. - // This only applies to platforms without PIC, e.g. Windows. - nlassert(!NLMISC::INelContext::isContextInitialised()); -#endif // NL_OS_WINDOWS - m_libContext = new NLMISC::CLibraryContext(*nelContext); -} - -QString LandscapeEditorPlugin::name() const -{ - return tr("LandscapeEditor"); -} - -QString LandscapeEditorPlugin::version() const -{ - return "0.0.1"; -} - -QString LandscapeEditorPlugin::vendor() const -{ - return "GSoC2011_dnk-88"; -} - -QString LandscapeEditorPlugin::description() const -{ - return "Landscape editor ovqt plugin."; -} - -QStringList LandscapeEditorPlugin::dependencies() const -{ - QStringList list; - list.append(Core::Constants::OVQT_CORE_PLUGIN); - return list; -} - -void LandscapeEditorPlugin::addAutoReleasedObject(QObject *obj) -{ - m_plugMan->addObject(obj); - m_autoReleaseObjects.prepend(obj); -} - -LandscapeEditorContext::LandscapeEditorContext(QObject *parent) - : IContext(parent), - m_landEditorWindow(0) -{ - m_landEditorWindow = new LandscapeEditorWindow(); -} - -QUndoStack *LandscapeEditorContext::undoStack() -{ - return m_landEditorWindow->undoStack(); -} - -void LandscapeEditorContext::open() -{ - m_landEditorWindow->open(); -} - -QWidget *LandscapeEditorContext::widget() -{ - return m_landEditorWindow; -} - -} - -Q_EXPORT_PLUGIN(LandscapeEditor::LandscapeEditorPlugin) \ No newline at end of file +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "landscape_editor_plugin.h" +#include "landscape_editor_window.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include "nel/misc/debug.h" + +// Qt includes +#include + +namespace LandscapeEditor +{ + +LandscapeEditorPlugin::~LandscapeEditorPlugin() +{ + Q_FOREACH(QObject *obj, m_autoReleaseObjects) + { + m_plugMan->removeObject(obj); + } + qDeleteAll(m_autoReleaseObjects); + m_autoReleaseObjects.clear(); +} + +bool LandscapeEditorPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString) +{ + Q_UNUSED(errorString); + m_plugMan = pluginManager; + + addAutoReleasedObject(new LandscapeEditorContext(this)); + return true; +} + +void LandscapeEditorPlugin::extensionsInitialized() +{ +} + +void LandscapeEditorPlugin::shutdown() +{ +} + +void LandscapeEditorPlugin::setNelContext(NLMISC::INelContext *nelContext) +{ +#ifdef NL_OS_WINDOWS + // Ensure that a context doesn't exist yet. + // This only applies to platforms without PIC, e.g. Windows. + nlassert(!NLMISC::INelContext::isContextInitialised()); +#endif // NL_OS_WINDOWS + m_libContext = new NLMISC::CLibraryContext(*nelContext); +} + +void LandscapeEditorPlugin::addAutoReleasedObject(QObject *obj) +{ + m_plugMan->addObject(obj); + m_autoReleaseObjects.prepend(obj); +} + +LandscapeEditorContext::LandscapeEditorContext(QObject *parent) + : IContext(parent), + m_landEditorWindow(0) +{ + m_landEditorWindow = new LandscapeEditorWindow(); +} + +QUndoStack *LandscapeEditorContext::undoStack() +{ + return m_landEditorWindow->undoStack(); +} + +void LandscapeEditorContext::open() +{ + m_landEditorWindow->open(); +} + +QWidget *LandscapeEditorContext::widget() +{ + return m_landEditorWindow; +} + +} +Q_EXPORT_PLUGIN(LandscapeEditor::LandscapeEditorPlugin) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.h index 67a3172ee..a01867894 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.h @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -35,11 +34,6 @@ namespace NLMISC class CLibraryContext; } -namespace ExtensionSystem -{ -class IPluginSpec; -} - namespace LandscapeEditor { class LandscapeEditorWindow; @@ -55,15 +49,8 @@ public: bool initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString); void extensionsInitialized(); void shutdown(); - void setNelContext(NLMISC::INelContext *nelContext); - QString name() const; - QString version() const; - QString vendor() const; - QString description() const; - QStringList dependencies() const; - void addAutoReleasedObject(QObject *obj); protected: @@ -78,7 +65,7 @@ class LandscapeEditorContext: public Core::IContext { Q_OBJECT public: - LandscapeEditorContext(QObject *parent = 0); + explicit LandscapeEditorContext(QObject *parent = 0); virtual ~LandscapeEditorContext() {} virtual QString id() const @@ -91,7 +78,7 @@ public: } virtual QIcon icon() const { - return QIcon(); + return QIcon(Constants::ICON_LANDSCAPE_ITEM); } virtual void open(); diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.cpp index 1d95315d4..22598c555 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.cpp @@ -1,91 +1,414 @@ -// Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// 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 "landscape_editor_window.h" -#include "landscape_editor_constants.h" - -#include "../core/icore.h" -#include "../core/core_constants.h" - -// NeL includes -#include - -// Qt includes -#include -#include - -namespace LandscapeEditor -{ -QString _lastDir; - -LandscapeEditorWindow::LandscapeEditorWindow(QWidget *parent) - : QMainWindow(parent) -{ - m_ui.setupUi(this); - - m_undoStack = new QUndoStack(this); - - createMenus(); - readSettings(); -} - -LandscapeEditorWindow::~LandscapeEditorWindow() -{ - writeSettings(); -} - -QUndoStack *LandscapeEditorWindow::undoStack() const -{ - return m_undoStack; -} - -void LandscapeEditorWindow::open() -{ - QStringList fileNames = QFileDialog::getOpenFileNames(this, - tr("Open NeL Ligo land file"), _lastDir, - tr("All NeL Ligo land files (*.land)")); - - setCursor(Qt::WaitCursor); - if (!fileNames.isEmpty()) - { - QStringList list = fileNames; - _lastDir = QFileInfo(list.front()).absolutePath(); - } - setCursor(Qt::ArrowCursor); -} - -void LandscapeEditorWindow::createMenus() -{ -} - -void LandscapeEditorWindow::readSettings() -{ - QSettings *settings = Core::ICore::instance()->settings(); - settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); - settings->endGroup(); -} - -void LandscapeEditorWindow::writeSettings() -{ - QSettings *settings = Core::ICore::instance()->settings(); - settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); - settings->endGroup(); - settings->sync(); -} - -} /* namespace LandscapeEditor */ +// 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 "landscape_editor_window.h" +#include "landscape_editor_constants.h" +#include "builder_zone.h" +#include "zone_region_editor.h" +#include "landscape_scene.h" +#include "project_settings_dialog.h" +#include "snapshot_dialog.h" + +#include "../core/icore.h" +#include "../core/menu_manager.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +static const int LANDSCAPE_ID = 32; +int NewLandCounter = 0; +QString _lastDir; + +LandscapeEditorWindow::LandscapeEditorWindow(QWidget *parent) + : QMainWindow(parent), + m_currentItem(0), + m_landscapeScene(0), + m_zoneBuilder(0), + m_undoStack(0), + m_oglWidget(0) +{ + m_ui.setupUi(this); + + m_undoStack = new QUndoStack(this); + m_landscapeScene = new LandscapeScene(160, this); + + m_zoneBuilder = new ZoneBuilder(m_landscapeScene, m_ui.zoneListWidget, m_undoStack); + m_ui.zoneListWidget->setZoneBuilder(m_zoneBuilder); + m_ui.zoneListWidget->updateUi(); + + m_landscapeScene->setZoneBuilder(m_zoneBuilder); + m_ui.graphicsView->setScene(m_landscapeScene); + + m_ui.newLandAction->setIcon(QIcon(Core::Constants::ICON_NEW)); + m_ui.saveAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + m_ui.saveLandAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + m_ui.saveAsLandAction->setIcon(QIcon(Core::Constants::ICON_SAVE_AS)); + m_ui.zonesDockWidget->toggleViewAction()->setIcon(QIcon(Constants::ICON_LANDSCAPE_ZONES)); + m_ui.landscapesDockWidget->toggleViewAction()->setIcon(QIcon(Constants::ICON_ZONE_ITEM)); + + m_ui.deleteLandAction->setEnabled(false); + + createMenus(); + createToolBars(); + readSettings(); + + connect(m_ui.saveAction, SIGNAL(triggered()), this, SLOT(save())); + connect(m_ui.projectSettingsAction, SIGNAL(triggered()), this, SLOT(openProjectSettings())); + connect(m_ui.snapshotAction, SIGNAL(triggered()), this, SLOT(openSnapshotDialog())); + connect(m_ui.enableGridAction, SIGNAL(toggled(bool)), m_ui.graphicsView, SLOT(setVisibleGrid(bool))); + + connect(m_ui.newLandAction, SIGNAL(triggered()), this, SLOT(newLand())); + connect(m_ui.setActiveLandAction, SIGNAL(triggered()), this, SLOT(setActiveLand())); + connect(m_ui.saveLandAction, SIGNAL(triggered()), this, SLOT(saveSelectedLand())); + connect(m_ui.saveAsLandAction, SIGNAL(triggered()), this, SLOT(saveAsSelectedLand())); + connect(m_ui.deleteLandAction, SIGNAL(triggered()), this, SLOT(deleteSelectedLand())); + connect(m_ui.transitionModeAction, SIGNAL(toggled(bool)), m_landscapeScene, SLOT(setTransitionMode(bool))); + + connect(m_ui.landscapesListWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenu())); + m_ui.landscapesListWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + m_statusBarTimer = new QTimer(this); + connect(m_statusBarTimer, SIGNAL(timeout()), this, SLOT(updateStatusBar())); + + m_statusInfo = new QLabel(this); + m_statusInfo->hide(); + Core::ICore::instance()->mainWindow()->statusBar()->addPermanentWidget(m_statusInfo); +} + +LandscapeEditorWindow::~LandscapeEditorWindow() +{ + writeSettings(); + delete m_zoneBuilder; +} + +QUndoStack *LandscapeEditorWindow::undoStack() const +{ + return m_undoStack; +} + +void LandscapeEditorWindow::open() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo land file"), _lastDir, + tr("All NeL Ligo land files (*.land)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + _lastDir = QFileInfo(list.front()).absolutePath(); + Q_FOREACH(QString fileName, fileNames) + { + int row = createLandscape(fileName); + if (row != -1) + setActiveLandscape(row); + } + } + setCursor(Qt::ArrowCursor); +} + +void LandscapeEditorWindow::save() +{ + saveLandscape(m_ui.landscapesListWidget->row(m_currentItem), true); +} + +void LandscapeEditorWindow::openProjectSettings() +{ + ProjectSettingsDialog *dialog = new ProjectSettingsDialog(m_zoneBuilder->dataPath(), this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + m_zoneBuilder->init(dialog->dataPath(), true); + m_ui.zoneListWidget->updateUi(); + } + delete dialog; +} + +void LandscapeEditorWindow::openSnapshotDialog() +{ + SnapshotDialog *dialog = new SnapshotDialog(this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save screenshot landscape"), _lastDir, + tr("Image file (*.png)")); + + setCursor(Qt::WaitCursor); + + NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->currentZoneRegion()->ligoZoneRegion(); + sint32 regionMinX = zoneRegion.getMinX(); + sint32 regionMaxX = zoneRegion.getMaxX(); + sint32 regionMinY = zoneRegion.getMinY(); + sint32 regionMaxY = zoneRegion.getMaxY(); + + int regionWidth = (regionMaxX - regionMinX + 1); + int regionHeight = (regionMaxY - regionMinY + 1); + + int cellSize = m_landscapeScene->cellSize(); + QRectF rect(regionMinX * cellSize, abs(regionMaxY) * cellSize, regionWidth * cellSize, regionHeight * cellSize); + + if (dialog->isCustomSize()) + { + int widthSnapshot = dialog->widthSnapshot(); + int heightSnapshot = dialog->heightSnapshot(); + if (dialog->isKeepRatio()) + heightSnapshot = (widthSnapshot / regionWidth) * regionHeight; + + m_landscapeScene->snapshot(fileName, widthSnapshot, heightSnapshot, rect); + } + else + { + m_landscapeScene->snapshot(fileName, regionWidth * dialog->resolutionZone(), + regionHeight * dialog->resolutionZone(), rect); + } + setCursor(Qt::ArrowCursor); + } + delete dialog; +} + +void LandscapeEditorWindow::customContextMenu() +{ + if (m_ui.landscapesListWidget->currentRow() == -1) + return; + QMenu *popurMenu = new QMenu(this); + popurMenu->addAction(m_ui.setActiveLandAction); + popurMenu->addAction(m_ui.saveLandAction); + popurMenu->addAction(m_ui.saveAsLandAction); + popurMenu->addAction(m_ui.deleteLandAction); + popurMenu->exec(QCursor::pos()); + delete popurMenu; +} + +void LandscapeEditorWindow::newLand() +{ + int row = createLandscape(QString()); + if (row != -1) + setActiveLandscape(row); +} + +void LandscapeEditorWindow::setActiveLand() +{ + setActiveLandscape(m_ui.landscapesListWidget->currentRow()); +} + +void LandscapeEditorWindow::saveSelectedLand() +{ + saveLandscape(m_ui.landscapesListWidget->currentRow(), true); +} + +void LandscapeEditorWindow::saveAsSelectedLand() +{ + saveLandscape(m_ui.landscapesListWidget->currentRow(), false); +} + +void LandscapeEditorWindow::deleteSelectedLand() +{ + int row = m_ui.landscapesListWidget->currentRow(); + int current_row = m_ui.landscapesListWidget->row(m_currentItem); + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + if (row == current_row) + { + if (row == 0) + ++row; + else + --row; + setActiveLandscape(row); + } + m_zoneBuilder->deleteZoneRegion(item->data(LANDSCAPE_ID).toInt()); + m_ui.landscapesListWidget->removeItemWidget(item); + delete item; + + if (m_ui.landscapesListWidget->count() == 1) + m_ui.deleteLandAction->setEnabled(false); + + m_undoStack->clear(); +} + +int LandscapeEditorWindow::createLandscape(const QString &fileName) +{ + int id; + if (fileName.isEmpty()) + id = m_zoneBuilder->createZoneRegion(); + else + id = m_zoneBuilder->createZoneRegion(fileName); + + if (id == -1) + { + QMessageBox::critical(this, "Landscape Editor", tr("Cannot add this zone because it overlaps existing ones")); + return -1; + } + ZoneRegionObject *zoneRegion = m_zoneBuilder->zoneRegion(id); + m_ui.graphicsView->setCenter(QPointF(zoneRegion->ligoZoneRegion().getMinX() * m_landscapeScene->cellSize(), + abs(zoneRegion->ligoZoneRegion().getMinY()) * m_landscapeScene->cellSize())); + + QListWidgetItem *item; + if (fileName.isEmpty()) + item = new QListWidgetItem(QString("NewLandscape%1").arg(NewLandCounter++), m_ui.landscapesListWidget); + else + item = new QListWidgetItem(fileName, m_ui.landscapesListWidget); + + item->setData(LANDSCAPE_ID, id); + item->setFont(QFont("SansSerif", 9, QFont::Normal)); + + if (m_ui.landscapesListWidget->count() > 1) + m_ui.deleteLandAction->setEnabled(true); + + return m_ui.landscapesListWidget->count() - 1; +} + +void LandscapeEditorWindow::setActiveLandscape(int row) +{ + if ((0 <= row) && (row < m_ui.landscapesListWidget->count())) + { + if (m_currentItem != 0) + m_currentItem->setFont(QFont("SansSerif", 9, QFont::Normal)); + + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + item->setFont(QFont("SansSerif", 9, QFont::Bold)); + m_zoneBuilder->setCurrentZoneRegion(item->data(LANDSCAPE_ID).toInt()); + m_currentItem = item; + } +} + +void LandscapeEditorWindow::saveLandscape(int row, bool force) +{ + if ((0 <= row) && (row < m_ui.landscapesListWidget->count())) + { + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + ZoneRegionObject *regionObject = m_zoneBuilder->zoneRegion(item->data(LANDSCAPE_ID).toInt()); + if ((!force) || (regionObject->fileName().empty())) + { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save NeL Ligo land file"), _lastDir, + tr("NeL Ligo land file (*.land)")); + if (!fileName.isEmpty()) + { + regionObject->setFileName(fileName.toStdString()); + regionObject->save(); + regionObject->setModified(false); + item->setText(fileName); + } + } + else + { + regionObject->save(); + regionObject->setModified(false); + } + } +} + +void LandscapeEditorWindow::showEvent(QShowEvent *showEvent) +{ + QMainWindow::showEvent(showEvent); + if (m_oglWidget != 0) + m_oglWidget->makeCurrent(); + m_statusInfo->show(); + m_statusBarTimer->start(100); +} + +void LandscapeEditorWindow::hideEvent(QHideEvent *hideEvent) +{ + QMainWindow::hideEvent(hideEvent); + m_statusInfo->hide(); + m_statusBarTimer->stop(); +} + +void LandscapeEditorWindow::updateStatusBar() +{ + m_statusInfo->setText(m_landscapeScene->zoneNameFromMousePos()); +} + +void LandscapeEditorWindow::createMenus() +{ + Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); +} + +void LandscapeEditorWindow::createToolBars() +{ + Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); + //QAction *action = menuManager->action(Core::Constants::NEW); + //m_ui.fileToolBar->addAction(action); + //action = menuManager->action(Core::Constants::SAVE); + //m_ui.fileToolBar->addAction(action); + //action = menuManager->action(Core::Constants::SAVE_AS); + //m_ui.fileToolBar->addAction(action); + + QAction *action = menuManager->action(Core::Constants::OPEN); + m_ui.fileToolBar->addAction(m_ui.newLandAction); + m_ui.fileToolBar->addAction(action); + m_ui.fileToolBar->addAction(m_ui.saveAction); + m_ui.fileToolBar->addSeparator(); + + action = menuManager->action(Core::Constants::UNDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + action = menuManager->action(Core::Constants::REDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + m_ui.zoneToolBar->insertAction(m_ui.enableGridAction, m_ui.landscapesDockWidget->toggleViewAction()); + m_ui.zoneToolBar->insertAction(m_ui.enableGridAction, m_ui.zonesDockWidget->toggleViewAction()); +} + +void LandscapeEditorWindow::readSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); + restoreState(settings->value(Constants::LANDSCAPE_WINDOW_STATE).toByteArray()); + restoreGeometry(settings->value(Constants::LANDSCAPE_WINDOW_GEOMETRY).toByteArray()); + + // Read landscape data directory (contains sub-paths: zone logos, zone bitmaps) + m_zoneBuilder->init(settings->value(Constants::LANDSCAPE_DATA_DIRECTORY).toString()); + m_ui.zoneListWidget->updateUi(); + + // Use OpenGL graphics system instead raster graphics system + if (settings->value(Constants::LANDSCAPE_USE_OPENGL, false).toBool()) + { + m_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer)); + m_ui.graphicsView->setViewport(m_oglWidget); + } + + settings->endGroup(); +} + +void LandscapeEditorWindow::writeSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); + settings->setValue(Constants::LANDSCAPE_WINDOW_STATE, saveState()); + settings->setValue(Constants::LANDSCAPE_WINDOW_GEOMETRY, saveGeometry()); + settings->setValue(Constants::LANDSCAPE_DATA_DIRECTORY, m_zoneBuilder->dataPath()); + settings->endGroup(); + settings->sync(); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.h index cc17e6cbc..6047a9e5e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.h @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -23,16 +22,22 @@ // Qt includes #include +#include +#include +#include namespace LandscapeEditor { +class LandscapeScene; +class ZoneBuilder; + class LandscapeEditorWindow: public QMainWindow { Q_OBJECT public: - LandscapeEditorWindow(QWidget *parent = 0); + explicit LandscapeEditorWindow(QWidget *parent = 0); ~LandscapeEditorWindow(); QUndoStack *undoStack() const; @@ -40,14 +45,41 @@ public: Q_SIGNALS: public Q_SLOTS: void open(); + void save(); private Q_SLOTS: + void openProjectSettings(); + void openSnapshotDialog(); + void customContextMenu(); + void updateStatusBar(); + void newLand(); + void setActiveLand(); + void saveSelectedLand(); + void saveAsSelectedLand(); + void deleteSelectedLand(); + +protected: + virtual void showEvent(QShowEvent *showEvent); + virtual void hideEvent(QHideEvent *hideEvent); + private: void createMenus(); + void createToolBars(); void readSettings(); void writeSettings(); + void setActiveLandscape(int row); + void saveLandscape(int row, bool force); + int createLandscape(const QString &fileName); + + QLabel *m_statusInfo; + QTimer *m_statusBarTimer; + + QListWidgetItem *m_currentItem; + LandscapeScene *m_landscapeScene; + ZoneBuilder *m_zoneBuilder; QUndoStack *m_undoStack; + QGLWidget *m_oglWidget; Ui::LandscapeEditorWindow m_ui; }; /* class LandscapeEditorWindow */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui index 5d9606ddf..77133c593 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui @@ -19,12 +19,42 @@ + + 3 + + + 3 + - + + + + 0.000000000000000 + 0.000000000000000 + 0.000000000000000 + 0.000000000000000 + + + + QGraphicsView::NoDrag + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::FullViewportUpdate + + + QGraphicsView::DontSavePainterState + + - + toolBar @@ -35,7 +65,177 @@ false + + + + :/icons/ic_nel_zones.png:/icons/ic_nel_zones.png + + + Zones + + + 2 + + + + + + + :/icons/ic_nel_zone.png:/icons/ic_nel_zone.png + + + Landscapes + + + 1 + + + + + 3 + + + 3 + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Project settings + + + + + true + + + true + + + + :/icons/ic_grid.png:/icons/ic_grid.png + + + EnableGrid + + + Show/Hide Grid + + + Ctrl+G + + + + + + :/icons/ic_snapshot.png:/icons/ic_snapshot.png + + + snapshot + + + + + Save + + + + + + :/icons/ic_nel_zone.png:/icons/ic_nel_zone.png + + + Set active + + + Set active selected landscape + + + + + Save + + + Save selected landscape + + + + + Save As landscape + + + Save as selected landscape + + + + + Delete + + + Delete selected landscape + + + + + New + + + Create new landscape + + + + + true + + + + :/icons/ic_nel_landscape_item.png + :/icons/ic_nel_transition_land.png:/icons/ic_nel_landscape_item.png + + + Transition mode + + + Enable transition mode + + + + + LandscapeEditor::ListZonesWidget + QWidget +
list_zones_widget.h
+ 1 +
+ + LandscapeEditor::LandscapeView + QGraphicsView +
landscape_view.h
+
+
diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp new file mode 100644 index 000000000..0018b4a53 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp @@ -0,0 +1,498 @@ +// 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 "landscape_scene.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +static const int ZONE_NAME = 0; +static const int LAYER_ZONES = 2; +static const int LAYER_EMPTY_ZONES = 3; +static const int LAYER_BLACKOUT = 4; +const char *const LAYER_BLACKOUT_NAME = "blackout"; + +const int MAX_SCENE_WIDTH = 256; +const int MAX_SCENE_HEIGHT = 256; + +LandscapeScene::LandscapeScene(int sizeCell, QObject *parent) + : QGraphicsScene(parent), + m_cellSize(sizeCell), + m_transitionMode(false), + m_mouseButton(Qt::NoButton), + m_zoneBuilder(0) +{ + setSceneRect(QRectF(0, m_cellSize, MAX_SCENE_WIDTH * m_cellSize, MAX_SCENE_HEIGHT * m_cellSize)); +} + +LandscapeScene::~LandscapeScene() +{ +} + +int LandscapeScene::cellSize() const +{ + return m_cellSize; +} + +void LandscapeScene::setZoneBuilder(ZoneBuilder *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + +QGraphicsItem *LandscapeScene::createItemZone(const LigoData &data, const ZonePosition &zonePos) +{ + if ((data.zoneName == STRING_OUT_OF_BOUND) || (checkUnderZone(zonePos.x, zonePos.y))) + return 0; + + if (data.zoneName == STRING_UNUSED) + return createItemEmptyZone(zonePos); + + if ((m_zoneBuilder == 0) || (data.zoneName.empty())) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(data.zoneName.c_str())); + if (pixmap == 0) + return 0; + + // Rotate the image counterclockwise + QMatrix matrix; + matrix.rotate(-data.rot * 90.0); + + QGraphicsPixmapItem *item; + + if (data.flip == 0) + { + item = addPixmap(pixmap->transformed(matrix, Qt::SmoothTransformation)); + } + else + { + // mirror image + QImage mirrorImage = pixmap->toImage(); + QPixmap mirrorPixmap = QPixmap::fromImage(mirrorImage.mirrored(true, false)); + item = addPixmap(mirrorPixmap.transformed(matrix, Qt::SmoothTransformation)); + } + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + sint32 sizeX = 1, sizeY = 1; + sizeX = float(pixmap->width()) / m_zoneBuilder->pixmapDatabase()->textureSize(); + sizeY = float(pixmap->width()) / m_zoneBuilder->pixmapDatabase()->textureSize(); + + sint32 deltaX = 0, deltaY = 0; + + // Calculate offset for graphics item (for items with size that are larger than 1) + if ((sizeX > 1) || (sizeY > 1)) + { + if (data.flip == 0) + { + switch (data.rot) + { + case 0: + deltaX = -data.posX; + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = -data.posX + sizeX - 1; + break; + case 2: + deltaX = -(sizeX - 1 - data.posX); + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = data.posX; + break; + } + } + else + { + switch (data.rot) + { + case 0: + deltaX = -(sizeX - 1 - data.posX); + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = +data.posX; + break; + case 2: + deltaX = -data.posX; + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = -data.posX + sizeX - 1; + break; + } + } + } + + // Set position graphics item with offset for large piece + item->setPos((zonePos.x + deltaX) * m_cellSize, (abs(int(zonePos.y + deltaY))) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilder->pixmapDatabase()->textureSize()); + + item->setData(ZONE_NAME, QString(data.zoneName.c_str())); + + // for not full item zone + item->setZValue(LAYER_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsItem *LandscapeScene::createItemEmptyZone(const ZonePosition &zonePos) +{ + if (m_zoneBuilder == 0) + return 0; + + if (checkUnderZone(zonePos.x, zonePos.y)) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(STRING_UNUSED)); + + if (pixmap == 0) + return 0; + + QGraphicsPixmapItem *item = addPixmap(*pixmap); + + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + // Set position graphics item + item->setPos(zonePos.x * m_cellSize, abs(int(zonePos.y)) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilder->pixmapDatabase()->textureSize()); + + // for not full item zone + item->setZValue(LAYER_EMPTY_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsRectItem *LandscapeScene::createLayerBlackout(const NLLIGO::CZoneRegion &zoneRegion) +{ + QGraphicsRectItem *rectItem = addRect(zoneRegion.getMinX() * m_cellSize, + abs(zoneRegion.getMaxY()) * m_cellSize, + (abs(zoneRegion.getMaxX() - zoneRegion.getMinX()) + 1) * m_cellSize, + (abs(zoneRegion.getMaxY() - zoneRegion.getMinY()) + 1) * m_cellSize, + Qt::NoPen, QBrush(QColor(0, 0, 0, 50))); + + rectItem->setZValue(LAYER_BLACKOUT); + rectItem->setData(ZONE_NAME, QString(LAYER_BLACKOUT_NAME)); + return rectItem; +} + +void LandscapeScene::deleteItemZone(const ZonePosition &zonePos) +{ + QGraphicsItem *item = itemAt(zonePos.x * m_cellSize, abs(zonePos.y) * m_cellSize); + if ((item != 0) && (item->data(ZONE_NAME).toString() != QString(LAYER_BLACKOUT_NAME))) + { + removeItem(item); + delete item; + } +} + +void LandscapeScene::addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + + std::string zoneName = zoneRegion.getName(i, j); + if (zoneName == STRING_UNUSED) + { + ZonePosition zonePos(i, j, -1); + QGraphicsItem *item = createItemEmptyZone(zonePos); + } + else if (!zoneName.empty()) + { + LigoData data; + ZonePosition zonePos(i, j, -1); + data.zoneName = zoneName; + data.rot = zoneRegion.getRot(i, j); + data.flip = zoneRegion.getFlip(i, j); + data.posX = zoneRegion.getPosX(i, j); + data.posY = zoneRegion.getPosY(i, j); + QGraphicsItem *item = createItemZone(data, zonePos); + } + } + } +} + +void LandscapeScene::delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + deleteItemZone(ZonePosition(i, -j, -1)); + } + } +} + +void LandscapeScene::snapshot(const QString &fileName, int width, int height, const QRectF &landRect) +{ + if (m_zoneBuilder == 0) + return; + + // Create image + QImage image(landRect.width(), landRect.height(), QImage::Format_RGB888); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing, true); + + // Add white background + painter.setBrush(QBrush(Qt::white)); + painter.setPen(Qt::NoPen); + painter.drawRect(0, 0, landRect.width(), landRect.height()); + + // Paint landscape + render(&painter, QRectF(0, 0, landRect.width(), landRect.height()), landRect); + + QImage scaledImage = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + scaledImage.save(fileName); +} + +QString LandscapeScene::zoneNameFromMousePos() const +{ + if ((m_posY > 0) || (m_posY < -MAX_SCENE_HEIGHT) || + (m_posX < 0) || (m_posX > MAX_SCENE_WIDTH)) + return "NOT A VALID ZONE"; + + return QString("%1_%2%3 %4 %5 ").arg(-m_posY).arg(QChar('A' + (m_posX/26))). + arg(QChar('A' + (m_posX%26))).arg(m_mouseX, 0,'f',2).arg(-m_mouseY, 0,'f',2); +} + +void LandscapeScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + if ((x < 0) || (y < 0)) + return; + + m_posX = sint32(floor(x / m_cellSize)); + m_posY = sint32(-floor(y / m_cellSize)); + + if (m_zoneBuilder == 0) + return; + if (m_transitionMode) + { + if (mouseEvent->button() == Qt::LeftButton) + + // Need add offset(= cellSize) on y axes + m_zoneBuilder->addTransition(sint(x), sint(-y + m_cellSize)); + } + else + { + if (mouseEvent->button() == Qt::LeftButton) + m_zoneBuilder->addZone(m_posX, m_posY); + else if (mouseEvent->button() == Qt::RightButton) + m_zoneBuilder->delZone(m_posX, m_posY); + } + m_mouseButton = mouseEvent->button(); + + QGraphicsScene::mousePressEvent(mouseEvent); +} + +void LandscapeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + + sint32 posX = sint32(floor(x / m_cellSize)); + sint32 posY = sint32(-floor(y / m_cellSize)); + + if ((m_posX != posX || m_posY != posY) && + (m_mouseButton == Qt::LeftButton || + m_mouseButton == Qt::RightButton)) + { + if (m_transitionMode) + { + } + else + { + if (m_mouseButton == Qt::LeftButton) + m_zoneBuilder->addZone(posX, posY); + else if (m_mouseButton == Qt::RightButton) + m_zoneBuilder->delZone(posX, posY); + } + m_posX = posX; + m_posY = posY; + QApplication::processEvents(); + } + + m_posX = posX; + m_posY = posY; + + m_mouseX = mouseEvent->scenePos().x(); + m_mouseY = mouseEvent->scenePos().y() - m_cellSize; + QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +void LandscapeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + m_mouseButton = Qt::NoButton; +} + +bool LandscapeScene::checkUnderZone(const int posX, const int posY) +{ + QGraphicsItem *item = itemAt((posX * m_cellSize), abs(posY) * m_cellSize); + if (item != 0) + { + //if (item->data(ZONE_NAME) == QString(LAYER_BLACKOUT_NAME)) + // return false; + //else + return true; + } + return false; +} + +bool LandscapeScene::transitionMode() const +{ + return m_transitionMode; +} + +void LandscapeScene::setTransitionMode(bool enabled) +{ + m_transitionMode = enabled; + update(); +} + +void LandscapeScene::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsScene::drawForeground(painter, rect); + if ((m_zoneBuilder->currentIdZoneRegion() != -1) && (m_transitionMode)) + drawTransition(painter, rect); +} + +void LandscapeScene::drawTransition(QPainter *painter, const QRectF &rect) +{ + int left = int(floor(rect.left() / m_cellSize)); + int right = int(floor(rect.right() / m_cellSize)); + int top = int(floor(rect.top() / m_cellSize)); + int bottom = int(floor(rect.bottom() / m_cellSize)); + + QVector redLines; + QVector whiteLines; + + for (int i = left; i < right + 1; ++i) + { + for (int j = top; j < bottom + 1; ++j) + { + // Get LIGO data + NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->currentZoneRegion()->ligoZoneRegion(); + uint8 ceUp = zoneRegion.getCutEdge (i, -j, 0); + uint8 ceLeft = zoneRegion.getCutEdge (i, -j, 2); + if ((ceUp > 0) && (ceUp < 3)) + { + // Calculate position vertical lines + int x1, x2, y1, y2; + + y1 = j * m_cellSize + m_cellSize / 12.0f; + y2 = y1 - (m_cellSize / 6.0f); + + x1 = i * m_cellSize + 3.0f * m_cellSize / 12.0f; + x2 = i * m_cellSize + 5.0f * m_cellSize / 12.0f; + if (ceUp == 1) + { + whiteLines.push_back(QLine(x1, y1, x1, y2)); + whiteLines.push_back(QLine(x2, y1, x2, y2)); + } + else + { + redLines.push_back(QLine(x1, y1, x1, y2)); + redLines.push_back(QLine(x2, y1, x2, y2)); + } + + x1 = i * m_cellSize + 7.0f * m_cellSize / 12.0f; + x2 = i * m_cellSize + 9.0f * m_cellSize / 12.0f; + if (ceUp == 1) + { + redLines.push_back(QLine(x1, y1, x1, y2)); + redLines.push_back(QLine(x2, y1, x2, y2)); + } + else + { + whiteLines.push_back(QLine(x1, y1, x1, y2)); + whiteLines.push_back(QLine(x2, y1, x2, y2)); + } + } + if ((ceLeft > 0) && (ceLeft < 3)) + { + // Calculate position horizontal lines + int x1, x2, y1, y2; + + x1 = i * m_cellSize - m_cellSize / 12.0f; + x2 = x1 + (m_cellSize / 6.0f); + + y1 = j * m_cellSize + 3.0f * m_cellSize / 12.0f; + y2 = j * m_cellSize + 5.0f * m_cellSize / 12.0f; + if (ceLeft == 1) + { + redLines.push_back(QLine(x1, y1, x2, y1)); + redLines.push_back(QLine(x1, y2, x2, y2)); + } + else + { + whiteLines.push_back(QLine(x1, y1, x2, y1)); + whiteLines.push_back(QLine(x1, y2, x2, y2)); + } + + y1 = j * m_cellSize + 7.0f * m_cellSize / 12.0f; + y2 = j * m_cellSize + 9.0f * m_cellSize / 12.0f; + if (ceLeft == 1) + { + whiteLines.push_back(QLine(x1, y1, x2, y1)); + whiteLines.push_back(QLine(x1, y2, x2, y2)); + } + else + { + redLines.push_back(QLine(x1, y1, x2, y1)); + redLines.push_back(QLine(x1, y2, x2, y2)); + } + } + } + } + + // Draw lines + painter->setPen(QPen(Qt::red, 0, Qt::SolidLine)); + painter->drawLines(redLines); + painter->setPen(QPen(Qt::white, 0, Qt::SolidLine)); + painter->drawLines(whiteLines); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h new file mode 100644 index 000000000..612eaca76 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h @@ -0,0 +1,89 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 LANDSCAPE_SCENE_H +#define LANDSCAPE_SCENE_H + +// Project includes +#include "zone_region_editor.h" +#include "builder_zone.h" +#include "landscape_editor_global.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LandscapeScene +@brief +@details +*/ +class LandscapeScene : public QGraphicsScene +{ + Q_OBJECT + +public: + LandscapeScene(int sizeCell = 160, QObject *parent = 0); + virtual ~LandscapeScene(); + + int cellSize() const; + void setZoneBuilder(ZoneBuilder *zoneBuilder); + + QGraphicsItem *createItemZone(const LigoData &data, const ZonePosition &zonePos); + QGraphicsItem *createItemEmptyZone(const ZonePosition &zonePos); + QGraphicsRectItem *createLayerBlackout(const NLLIGO::CZoneRegion &zoneRegion); + void deleteItemZone(const ZonePosition &zonePos); + + void addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + void delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + void snapshot(const QString &fileName, int width, int height, const QRectF &landRect); + + QString zoneNameFromMousePos() const; + bool transitionMode() const; + +public Q_SLOTS: + void setTransitionMode(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); + + void drawTransition(QPainter *painter, const QRectF &rect); + +private: + bool checkUnderZone(const int posX, const int posY); + + int m_cellSize; + bool m_transitionMode; + qreal m_mouseX, m_mouseY; + sint32 m_posX, m_posY; + Qt::MouseButton m_mouseButton; + ZoneBuilder *m_zoneBuilder; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_SCENE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp new file mode 100644 index 000000000..2027831ae --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp @@ -0,0 +1,331 @@ +// 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 "landscape_scene_base.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ +static const int ZONE_NAME = 0; +static const int LAYER_ZONES = 2; +static const int LAYER_EMPTY_ZONES = 3; + +// TODO: delete +const char *const LAYER_BLACKOUT_NAME = "blackout"; + +const int MAX_SCENE_WIDTH = 256; +const int MAX_SCENE_HEIGHT = 256; + +LandscapeSceneBase::LandscapeSceneBase(int sizeCell, QObject *parent) + : QGraphicsScene(parent), + m_cellSize(sizeCell), + m_zoneBuilderBase(0) +{ + setSceneRect(QRectF(0, m_cellSize, MAX_SCENE_WIDTH * m_cellSize, MAX_SCENE_HEIGHT * m_cellSize)); +} + +LandscapeSceneBase::~LandscapeSceneBase() +{ +} + +int LandscapeSceneBase::cellSize() const +{ + return m_cellSize; +} + +void LandscapeSceneBase::setZoneBuilder(ZoneBuilderBase *zoneBuilder) +{ + m_zoneBuilderBase = zoneBuilder; +} + +QGraphicsItem *LandscapeSceneBase::createItemZone(const LigoData &data, const ZonePosition &zonePos) +{ + if ((data.zoneName == STRING_OUT_OF_BOUND) || (checkUnderZone(zonePos.x, zonePos.y))) + return 0; + + if (data.zoneName == STRING_UNUSED) + return createItemEmptyZone(zonePos); + + if ((m_zoneBuilderBase == 0) || (data.zoneName.empty())) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilderBase->pixmapDatabase()->pixmap(QString(data.zoneName.c_str())); + if (pixmap == 0) + return 0; + + // Rotate the image counter clockwise + QMatrix matrix; + matrix.rotate(-data.rot * 90.0); + + QGraphicsPixmapItem *item; + + if (data.flip == 0) + { + item = addPixmap(pixmap->transformed(matrix, Qt::SmoothTransformation)); + } + else + { + // mirror image + QImage mirrorImage = pixmap->toImage(); + QPixmap mirrorPixmap = QPixmap::fromImage(mirrorImage.mirrored(true, false)); + item = addPixmap(mirrorPixmap.transformed(matrix, Qt::SmoothTransformation)); + } + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + sint32 sizeX = 1, sizeY = 1; + sizeX = float(pixmap->width()) / m_zoneBuilderBase->pixmapDatabase()->textureSize(); + sizeY = float(pixmap->width()) / m_zoneBuilderBase->pixmapDatabase()->textureSize(); + + sint32 deltaX = 0, deltaY = 0; + + // Calculate offset for graphics item (for items with size that are larger than 1) + if ((sizeX > 1) || (sizeY > 1)) + { + if (data.flip == 0) + { + switch (data.rot) + { + case 0: + deltaX = -data.posX; + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = -data.posX + sizeX - 1; + break; + case 2: + deltaX = -(sizeX - 1 - data.posX); + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = data.posX; + break; + } + } + else + { + switch (data.rot) + { + case 0: + deltaX = -(sizeX - 1 - data.posX); + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = +data.posX; + break; + case 2: + deltaX = -data.posX; + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = -data.posX + sizeX - 1; + break; + } + } + } + + // Set position graphics item with offset for large piece + item->setPos((zonePos.x + deltaX) * m_cellSize, (abs(int(zonePos.y + deltaY))) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilderBase->pixmapDatabase()->textureSize()); + + item->setData(ZONE_NAME, QString(data.zoneName.c_str())); + + // for not full item zone + item->setZValue(LAYER_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsItem *LandscapeSceneBase::createItemEmptyZone(const ZonePosition &zonePos) +{ + if (m_zoneBuilderBase == 0) + return 0; + + if (checkUnderZone(zonePos.x, zonePos.y)) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilderBase->pixmapDatabase()->pixmap(QString(STRING_UNUSED)); + if (pixmap == 0) + return 0; + + QGraphicsPixmapItem *item = addPixmap(*pixmap); + + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + // Set position graphics item + item->setPos(zonePos.x * m_cellSize, abs(int(zonePos.y)) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilderBase->pixmapDatabase()->textureSize()); + + // for not full item zone + item->setZValue(LAYER_EMPTY_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +void LandscapeSceneBase::deleteItemZone(const ZonePosition &zonePos) +{ + QList listItems = items(QPointF(zonePos.x * m_cellSize + 10, abs(zonePos.y) * m_cellSize + 10), + Qt::IntersectsItemBoundingRect, Qt::AscendingOrder); + Q_FOREACH(QGraphicsItem *item, listItems) + { + if (qgraphicsitem_cast(item) != 0) + { + removeItem(item); + delete item; + return; + } + } +} + +void LandscapeSceneBase::addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + + std::string zoneName = zoneRegion.getName(i, j); + if (zoneName == STRING_UNUSED) + { + ZonePosition zonePos(i, j, -1); + QGraphicsItem *item = createItemEmptyZone(zonePos); + } + else if (!zoneName.empty()) + { + LigoData data; + ZonePosition zonePos(i, j, -1); + data.zoneName = zoneName; + data.rot = zoneRegion.getRot(i, j); + data.flip = zoneRegion.getFlip(i, j); + data.posX = zoneRegion.getPosX(i, j); + data.posY = zoneRegion.getPosY(i, j); + QGraphicsItem *item = createItemZone(data, zonePos); + } + } + } +} + +void LandscapeSceneBase::delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + + deleteItemZone(ZonePosition(i, -j, -1)); + } + } +} + +void LandscapeSceneBase::snapshot(const QString &fileName, int width, int height, const QRectF &landRect) +{ + if (m_zoneBuilderBase == 0) + return; + + // Create image + QImage image(landRect.width(), landRect.height(), QImage::Format_RGB888); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing, true); + + // Add white background + painter.setBrush(QBrush(Qt::white)); + painter.setPen(Qt::NoPen); + painter.drawRect(0, 0, landRect.width(), landRect.height()); + + // Paint landscape + render(&painter, QRectF(0, 0, landRect.width(), landRect.height()), landRect); + + QImage scaledImage = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + scaledImage.save(fileName); +} + +QString LandscapeSceneBase::zoneNameFromMousePos() const +{ + if ((m_posY > 0) || (m_posY < -MAX_SCENE_HEIGHT) || + (m_posX < 0) || (m_posX > MAX_SCENE_WIDTH)) + return "NOT A VALID ZONE"; + + return QString("%1_%2%3 %4 %5 ").arg(-m_posY+1).arg(QChar('A' + (m_posX/26))). + arg(QChar('A' + (m_posX%26))).arg(m_mouseX, 0,'f',2).arg(-m_mouseY, 0,'f',2); +} + +void LandscapeSceneBase::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::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)); +} + +void LandscapeSceneBase::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + 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); +} + +bool LandscapeSceneBase::checkUnderZone(const int posX, const int posY) +{ + // TODO: Why crash program? + // QList listItems = items(QPointF(posX * m_cellSize + 10, abs(posY) * m_cellSize + 10), + // Qt::IntersectsItemBoundingRect, Qt::AscendingOrder); + + QList listItems = items(); + + QPointF point(posX, abs(posY)); + Q_FOREACH(QGraphicsItem *item, listItems) + { + if (item->pos() == point) + { + if (qgraphicsitem_cast(item) != 0) + return true; + } + } + return false; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h new file mode 100644 index 000000000..b392b8a85 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h @@ -0,0 +1,79 @@ +// 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 LANDSCAPE_SCENE_BASE_H +#define LANDSCAPE_SCENE_BASE_H + +// Project includes +#include "landscape_editor_global.h" +#include "builder_zone_base.h" +#include "zone_region_editor.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LandscapeSceneBase +@brief +@details +*/ +class LANDSCAPE_EDITOR_EXPORT LandscapeSceneBase : public QGraphicsScene +{ + Q_OBJECT + +public: + LandscapeSceneBase(int sizeCell = 160, QObject *parent = 0); + virtual ~LandscapeSceneBase(); + + int cellSize() const; + void setZoneBuilder(ZoneBuilderBase *zoneBuilder); + + QGraphicsItem *createItemZone(const LigoData &data, const ZonePosition &zonePos); + QGraphicsItem *createItemEmptyZone(const ZonePosition &zonePos); + void deleteItemZone(const ZonePosition &zonePos); + + void addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + void delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + void snapshot(const QString &fileName, int width, int height, const QRectF &landRect); + + QString zoneNameFromMousePos() const; + +public Q_SLOTS: + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + +private: + bool checkUnderZone(const int posX, const int posY); + + int m_cellSize; + qreal m_mouseX, m_mouseY; + sint32 m_posX, m_posY; + ZoneBuilderBase *m_zoneBuilderBase; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_SCENE_BASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp new file mode 100644 index 000000000..7a612208a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp @@ -0,0 +1,254 @@ +// 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 "landscape_view.h" +#include "landscape_editor_constants.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include + +namespace LandscapeEditor +{ + +LandscapeView::LandscapeView(QWidget *parent) + : QGraphicsView(parent), + m_visibleGrid(true), + m_visibleText(true) +{ + setTransformationAnchor(AnchorUnderMouse); + setBackgroundBrush(QBrush(Qt::lightGray)); + + m_cellSize = 160; + m_maxView = 0.06; + m_minView = 32.0; + m_maxViewText = 0.6; + + //A modified version of centerOn(), handles special cases + setCenter(QPointF(500.0, 500.0)); +} + +LandscapeView::~LandscapeView() +{ +} + +bool LandscapeView::isVisibleGrid() const +{ + return m_visibleGrid; +} + +void LandscapeView::setVisibleGrid(bool visible) +{ + m_visibleGrid = visible; + scene()->update(); +} + +void LandscapeView::setVisibleText(bool visible) +{ + m_visibleText = visible; + scene()->update(); +} + +void LandscapeView::wheelEvent(QWheelEvent *event) +{ + //How fast we zoom + float numSteps = (( event->delta() / 8 ) / 15) * 1.2; + + QMatrix mat = matrix(); + QPointF mousePosition = event->pos(); + + mat.translate((width() / 2) - mousePosition.x(), (height() / 2) - mousePosition.y()); + + if ( numSteps > 0 ) + mat.scale(numSteps, numSteps); + else + mat.scale(-1 / numSteps, -1 / numSteps); + + mat.translate(mousePosition.x() - (width() / 2), mousePosition.y() - (height() / 2)); + + //Adjust to the new center for correct zooming + setMatrix(mat); + event->accept(); +} + +void LandscapeView::mousePressEvent(QMouseEvent *event) +{ + QGraphicsView::mousePressEvent(event); + if (event->button() != Qt::MiddleButton) + return; + + //For panning the view + m_lastPanPoint = event->pos(); + setCursor(Qt::ClosedHandCursor); +} + +void LandscapeView::mouseMoveEvent(QMouseEvent *event) +{ + if(!m_lastPanPoint.isNull()) + { + //Get how much we panned + QPointF delta = mapToScene(m_lastPanPoint) - mapToScene(event->pos()); + m_lastPanPoint = event->pos(); + + //Update the center ie. do the pan + setCenter(getCenter() + delta); + } + + QGraphicsView::mouseMoveEvent(event); +} + +void LandscapeView::mouseReleaseEvent(QMouseEvent *event) +{ + m_lastPanPoint = QPoint(); + setCursor(Qt::ArrowCursor); + QGraphicsView::mouseReleaseEvent(event); +} + +void LandscapeView::resizeEvent(QResizeEvent *event) +{ + //Get the rectangle of the visible area in scene coords + QRectF visibleArea = mapToScene(rect()).boundingRect(); + setCenter(visibleArea.center()); + + //Call the subclass resize so the scrollbars are updated correctly + QGraphicsView::resizeEvent(event); +} + +void LandscapeView::setCenter(const QPointF ¢erPoint) +{ + //Get the rectangle of the visible area in scene coords + QRectF visibleArea = mapToScene(rect()).boundingRect(); + + //Get the scene area + QRectF sceneBounds = sceneRect(); + + double boundX = visibleArea.width() / 2.0; + double boundY = visibleArea.height() / 2.0; + double boundWidth = sceneBounds.width() - 2.0 * boundX; + double boundHeight = sceneBounds.height() - 2.0 * boundY; + + //The max boundary that the centerPoint can be to + QRectF bounds(boundX, boundY, boundWidth, boundHeight); + + if(bounds.contains(centerPoint)) + { + //We are within the bounds + m_currentCenterPoint = centerPoint; + } + else + { + //We need to clamp or use the center of the screen + if(visibleArea.contains(sceneBounds)) + { + //Use the center of scene ie. we can see the whole scene + m_currentCenterPoint = sceneBounds.center(); + } + else + { + m_currentCenterPoint = centerPoint; + + //We need to clamp the center. The centerPoint is too large + if (centerPoint.x() > bounds.x() + bounds.width()) + m_currentCenterPoint.setX(bounds.x() + bounds.width()); + else if(centerPoint.x() < bounds.x()) + m_currentCenterPoint.setX(bounds.x()); + + if(centerPoint.y() > bounds.y() + bounds.height()) + m_currentCenterPoint.setY(bounds.y() + bounds.height()); + else if(centerPoint.y() < bounds.y()) + m_currentCenterPoint.setY(bounds.y()); + } + } + + //Update the scrollbars + centerOn(m_currentCenterPoint); +} + +QPointF LandscapeView::getCenter() const +{ + //return m_currentCenterPoint; + return mapToScene(viewport()->rect().center()); +} + +void LandscapeView::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsView::drawForeground(painter, rect); + + if (!m_visibleGrid) + return; + + painter->setPen(QPen(Qt::white, 0, Qt::SolidLine)); + drawGrid(painter, rect); + + if (!m_visibleText) + return; + + if (transform().m11() > m_maxViewText) + { + painter->setPen(QPen(Qt::white, 0.5, Qt::SolidLine)); + drawZoneNames(painter, rect); + } +} + +void LandscapeView::drawGrid(QPainter *painter, const QRectF &rect) +{ + qreal left = m_cellSize * floor(rect.left() / m_cellSize); + qreal top = m_cellSize * floor(rect.top() / m_cellSize); + + QVector lines; + + // Calculate vertical lines + while (left < rect.right()) + { + lines.push_back(QLine(int(left), int(rect.bottom()), int(left), int(rect.top()))); + left += m_cellSize; + } + + // Calculate horizontal lines + while (top < rect.bottom()) + { + lines.push_back(QLine(int(rect.left()), int(top), int(rect.right()), int(top))); + top += m_cellSize; + } + + // Draw lines + painter->drawLines(lines); +} + +void LandscapeView::drawZoneNames(QPainter *painter, const QRectF &rect) +{ + int leftSide = int(floor(rect.left() / m_cellSize)); + int rightSide = int(floor(rect.right() / m_cellSize)); + int topSide = int(floor(rect.top() / m_cellSize)); + int bottomSide = int(floor(rect.bottom() / m_cellSize)); + + for (int i = leftSide; i < rightSide + 1; ++i) + { + for (int j = topSide; j < bottomSide + 1; ++j) + { + QString text = QString("%1_%2%3").arg(j).arg(QChar('A' + (i / 26))).arg(QChar('A' + (i % 26))); + painter->drawText(i * m_cellSize + 5, j * m_cellSize + 15, text); + } + } +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h new file mode 100644 index 000000000..158edfaa9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h @@ -0,0 +1,84 @@ +// 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 LANDSCAPE_VIEW_H +#define LANDSCAPE_VIEW_H + +// Project includes +#include "landscape_editor_global.h" + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LandscapeView +@brief Provides graphics view for viewing zone regions. +@details Also provides zooming, panning and displaying grid +*/ +class LANDSCAPE_EDITOR_EXPORT LandscapeView: public QGraphicsView +{ + Q_OBJECT + +public: + explicit LandscapeView(QWidget *parent = 0); + virtual ~LandscapeView(); + + //Set the current centerpoint in the + void setCenter(const QPointF ¢erPoint); + QPointF getCenter() const; + + bool isVisibleGrid() const; + +public Q_SLOTS: + + /// Enable/disable displaying grid. + void setVisibleGrid(bool visible); + + /// Enable/disable displaying text(coord.) above each zone bricks. + void setVisibleText(bool visible); + +private Q_SLOTS: +protected: + //Take over the interaction + virtual void wheelEvent(QWheelEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void drawForeground(QPainter *painter, const QRectF &rect); + virtual void resizeEvent(QResizeEvent *event); + + void drawGrid(QPainter *painter, const QRectF &rect); + void drawZoneNames(QPainter *painter, const QRectF &rect); +private: + + bool m_visibleGrid, m_visibleText; + qreal m_maxView, m_minView, m_maxViewText; + int m_cellSize; + + //Holds the current centerpoint for the view, used for panning and zooming + QPointF m_currentCenterPoint; + + //From panning the view + QPoint m_lastPanPoint; +}; /* class LandscapeView */ + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_VIEW_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.cpp new file mode 100644 index 000000000..103a43052 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.cpp @@ -0,0 +1,137 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "list_zones_model.h" +#include "builder_zone.h" + +// NeL includes +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +ListZonesModel::ListZonesModel(int scaleRatio, QObject *parent) + : QAbstractListModel(parent), + m_scaleRatio(scaleRatio) +{ + +} +ListZonesModel::~ListZonesModel() +{ + resetModel(); +} + +int ListZonesModel::rowCount(const QModelIndex & /* parent */) const +{ + return m_listNames.count(); +} + +int ListZonesModel::columnCount(const QModelIndex & /* parent */) const +{ + return 1; +} + +QVariant ListZonesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + switch (role) + { + case Qt::TextAlignmentRole: + return int(Qt::AlignLeft | Qt::AlignVCenter); + case Qt::DisplayRole: + return m_listNames.at(index.row()); + case Qt::DecorationRole: + { + QPixmap *pixmap = getPixmap(m_listNames.at(index.row())); + return qVariantFromValue(*pixmap); + } + default: + return QVariant(); + } +} + +QVariant ListZonesModel::headerData(int section, Qt::Orientation, int role) const +{ + return QVariant(); +} + +void ListZonesModel::setScaleRatio(int scaleRatio) +{ + m_scaleRatio = scaleRatio; +} + +void ListZonesModel::setListZones(QStringList &listZones) +{ + beginResetModel(); + m_listNames.clear(); + m_listNames = listZones; + endResetModel(); +} + +void ListZonesModel::resetModel() +{ + beginResetModel(); + QStringList listNames(m_pixmapMap.keys()); + Q_FOREACH(QString name, listNames) + { + QPixmap *pixmap = m_pixmapMap.value(name); + delete pixmap; + } + m_pixmapMap.clear(); + m_listNames.clear(); + endResetModel(); +} + +void ListZonesModel::rebuildModel(PixmapDatabase *pixmapDatabase) +{ + resetModel(); + + beginResetModel(); + QStringList listNames; + listNames = pixmapDatabase->listPixmaps(); + + Q_FOREACH(QString name, listNames) + { + QPixmap *pixmap = pixmapDatabase->pixmap(name); + QPixmap *smallPixmap = new QPixmap(pixmap->scaled(pixmap->width() / m_scaleRatio, pixmap->height() / m_scaleRatio)); + m_pixmapMap.insert(name, smallPixmap); + } + endResetModel(); +} + +QPixmap *ListZonesModel::getPixmap(const QString &zoneName) const +{ + QPixmap *result = 0; + if (!m_pixmapMap.contains(zoneName)) + nlwarning("QPixmap %s not found", zoneName.toStdString().c_str()); + else + result = m_pixmapMap.value(zoneName); + return result; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.h new file mode 100644 index 000000000..e4682ebea --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.h @@ -0,0 +1,79 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 LIST_ZONES_MODEL_H +#define LIST_ZONES_MODEL_H + +// Project includes + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class PixmapDatabase; + +/** +@class ListZonesModel +@brief ListZonesModel is used for managed list bricks by ListZonesWidget +@details ListZonesModel contains the small images for QListView +*/ +class ListZonesModel : public QAbstractListModel +{ + Q_OBJECT +public: + ListZonesModel(int scaleRatio = 4, QObject *parent = 0); + ~ListZonesModel(); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role) const; + + /// Set size for small pixmaps + /// Value should be set before calling rebuildModel + void setScaleRatio(int scaleRatio); + + /// Delete all small images and reset model + void resetModel(); + + /// Set current list zones which will be available in QListView + void setListZones(QStringList &listZones); + + /// Build own pixmaps database(all images are scaled: width/scaleRatio, height/scaleRatio) from pixmapDatabase + void rebuildModel(PixmapDatabase *pixmapDatabase); + +private: + /// Get pixmap + /// @return QPixmap* if the image is in the database ; otherwise returns 0. + QPixmap *getPixmap(const QString &zoneName) const; + + int m_scaleRatio; + QMap m_pixmapMap; + QStringList m_listNames; +}; + +} /* namespace LandscapeEditor */ + +#endif // LIST_ZONES_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.cpp new file mode 100644 index 000000000..554b19ca3 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.cpp @@ -0,0 +1,308 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "list_zones_widget.h" +#include "list_zones_model.h" +#include "builder_zone.h" + +// NeL includes +#include +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +ListZonesWidget::ListZonesWidget(QWidget *parent) + : QWidget(parent), + m_rotCycle(0), + m_flipCycle(0), + m_listZonesModel(0), + m_zoneBuilder(0) +{ + m_ui.setupUi(this); + + m_listZonesModel = new ListZonesModel(4, this); + m_ui.listView->setModel(m_listZonesModel); + + m_ui.addFilterButton_1->setChecked(false); + m_ui.addFilterButton_2->setChecked(false); + m_ui.addFilterButton_3->setChecked(false); + + connect(m_ui.categoryTypeComboBox_1, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateFilters_1(QString))); + connect(m_ui.categoryTypeComboBox_2, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateFilters_2(QString))); + connect(m_ui.categoryTypeComboBox_3, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateFilters_3(QString))); + connect(m_ui.categoryTypeComboBox_4, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateFilters_4(QString))); + connect(m_ui.categoryValueComboBox_1, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.categoryValueComboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.categoryValueComboBox_3, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.categoryValueComboBox_4, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.logicComboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.logicComboBox_3, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); + connect(m_ui.logicComboBox_4, SIGNAL(currentIndexChanged(int)), this, SLOT(updateListZones())); +} + +ListZonesWidget::~ListZonesWidget() +{ +} + +void ListZonesWidget::updateUi() +{ + if (m_zoneBuilder == 0) + return; + + disableSignals(true); + std::vector listCategoryType; + m_zoneBuilder->getZoneBank().getCategoriesType(listCategoryType); + + QStringList listCategories; + + listCategories << STRING_UNUSED; + for (size_t i = 0; i < listCategoryType.size(); ++i) + listCategories << QString(listCategoryType[i].c_str()); + + m_ui.categoryTypeComboBox_1->clear(); + m_ui.categoryTypeComboBox_2->clear(); + m_ui.categoryTypeComboBox_3->clear(); + m_ui.categoryTypeComboBox_4->clear(); + m_ui.categoryValueComboBox_1->clear(); + m_ui.categoryValueComboBox_2->clear(); + m_ui.categoryValueComboBox_3->clear(); + m_ui.categoryValueComboBox_4->clear(); + + m_ui.categoryTypeComboBox_1->addItems(listCategories); + m_ui.categoryTypeComboBox_2->addItems(listCategories); + m_ui.categoryTypeComboBox_3->addItems(listCategories); + m_ui.categoryTypeComboBox_4->addItems(listCategories); + + disableSignals(false); + + m_listZonesModel->rebuildModel(m_zoneBuilder->pixmapDatabase()); +} + +QString ListZonesWidget::currentZoneName() +{ + QString zoneName = ""; + QModelIndex index = m_ui.listView->currentIndex(); + if (index.isValid()) + zoneName = index.data().toString(); + if (m_ui.zoneSelectComboBox->currentIndex() == 1) + { + // Random value + if (m_listSelection.size() > 0) + { + uint32 randZone = uint32(NLMISC::frand(m_listSelection.size())); + NLMISC::clamp(randZone, (uint32)0, uint32(m_listSelection.size() - 1)); + zoneName = m_listSelection[randZone]; + } + } + else if (m_ui.zoneSelectComboBox->currentIndex() == 2) + { + // Full cycle + if (m_listSelection.size() > 0) + { + zoneName = m_listSelection[m_zoneNameCycle]; + m_zoneNameCycle++; + m_zoneNameCycle = m_zoneNameCycle % m_listSelection.size(); + } + } + return zoneName; +} + +int ListZonesWidget::currentRot() +{ + int rot = m_ui.rotComboBox->currentIndex(); + if (rot == 4) + { + // Random value + uint32 randRot = uint32(NLMISC::frand(4.0)); + NLMISC::clamp(randRot, (uint32)0, (uint32)3); + rot = int(randRot); + } + else if (rot == 5) + { + // Full cycle + rot = m_rotCycle; + m_rotCycle++; + m_rotCycle = m_rotCycle % 4; + } + return rot; +} + +int ListZonesWidget::currentFlip() +{ + int flip = m_ui.flipComboBox->currentIndex(); + if (flip == 2) + { + // Random value + uint32 randFlip = uint32(NLMISC::frand(2.0)); + NLMISC::clamp (randFlip, (uint32)0, (uint32)1); + flip = int(randFlip); + } + else if (flip == 3) + { + // Full cycle + flip = m_flipCycle; + m_flipCycle++; + m_flipCycle = m_flipCycle % 2; + } + return flip; +} + +bool ListZonesWidget::isNotPropogate() const +{ + return m_ui.propogateCheckBox->isChecked(); +} + +bool ListZonesWidget::isForce() const +{ + return m_ui.forceCheckBox->isChecked(); +} + +void ListZonesWidget::setZoneBuilder(ZoneBuilder *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + +void ListZonesWidget::updateFilters_1(const QString &value) +{ + disableSignals(true); + std::vector allCategoryValues; + m_zoneBuilder->getZoneBank().getCategoryValues(value.toStdString(), allCategoryValues); + m_ui.categoryValueComboBox_1->clear(); + for(size_t i = 0; i < allCategoryValues.size(); ++i) + m_ui.categoryValueComboBox_1->addItem(QString(allCategoryValues[i].c_str())); + + disableSignals(false); + updateListZones(); +} + +void ListZonesWidget::updateFilters_2(const QString &value) +{ + disableSignals(true); + std::vector allCategoryValues; + m_zoneBuilder->getZoneBank().getCategoryValues(value.toStdString(), allCategoryValues); + + m_ui.categoryValueComboBox_2->clear(); + for(size_t i = 0; i < allCategoryValues.size(); ++i) + m_ui.categoryValueComboBox_2->addItem(QString(allCategoryValues[i].c_str())); + + disableSignals(false); + updateListZones(); +} + +void ListZonesWidget::updateFilters_3(const QString &value) +{ + disableSignals(true); + std::vector allCategoryValues; + m_zoneBuilder->getZoneBank().getCategoryValues(value.toStdString(), allCategoryValues); + + m_ui.categoryValueComboBox_3->clear(); + for(size_t i = 0; i < allCategoryValues.size(); ++i) + m_ui.categoryValueComboBox_3->addItem(QString(allCategoryValues[i].c_str())); + + disableSignals(false); + updateListZones(); +} + +void ListZonesWidget::updateFilters_4(const QString &value) +{ + disableSignals(true); + std::vector allCategoryValues; + m_zoneBuilder->getZoneBank().getCategoryValues(value.toStdString(), allCategoryValues); + + m_ui.categoryValueComboBox_4->clear(); + for(size_t i = 0; i < allCategoryValues.size(); ++i) + m_ui.categoryValueComboBox_4->addItem(QString(allCategoryValues[i].c_str())); + + disableSignals(false); + updateListZones(); +} + +void ListZonesWidget::updateListZones() +{ + // Execute the filter + NLLIGO::CZoneBank &zoneBank = m_zoneBuilder->getZoneBank(); + zoneBank.resetSelection (); + + if(m_ui.categoryTypeComboBox_1->currentIndex() > 0 ) + zoneBank.addOrSwitch (m_ui.categoryTypeComboBox_1->currentText().toStdString() + , m_ui.categoryValueComboBox_1->currentText().toStdString()); + + if(m_ui.categoryTypeComboBox_2->currentIndex() > 0 ) + { + if (m_ui.logicComboBox_2->currentIndex() == 0) // AND switch wanted + zoneBank.addAndSwitch(m_ui.categoryTypeComboBox_2->currentText().toStdString() + ,m_ui.categoryValueComboBox_2->currentText().toStdString()); + else // OR switch wanted + zoneBank.addOrSwitch(m_ui.categoryTypeComboBox_2->currentText().toStdString() + ,m_ui.categoryValueComboBox_2->currentText().toStdString()); + } + + if(m_ui.categoryTypeComboBox_3->currentIndex() > 0 ) + { + if (m_ui.logicComboBox_3->currentIndex() == 0) // AND switch wanted + zoneBank.addAndSwitch(m_ui.categoryTypeComboBox_3->currentText().toStdString() + ,m_ui.categoryValueComboBox_3->currentText().toStdString()); + else // OR switch wanted + zoneBank.addOrSwitch(m_ui.categoryTypeComboBox_3->currentText().toStdString() + ,m_ui.categoryValueComboBox_3->currentText().toStdString()); + } + + if(m_ui.categoryTypeComboBox_4->currentIndex() > 0 ) + { + if (m_ui.logicComboBox_4->currentIndex() == 0) // AND switch wanted + zoneBank.addAndSwitch(m_ui.categoryTypeComboBox_4->currentText().toStdString() + ,m_ui.categoryValueComboBox_4->currentText().toStdString()); + else // OR switch wanted + zoneBank.addOrSwitch(m_ui.categoryTypeComboBox_4->currentText().toStdString() + ,m_ui.categoryValueComboBox_4->currentText().toStdString()); + } + + std::vector currentSelection; + zoneBank.getSelection (currentSelection); + + m_listSelection.clear(); + m_zoneNameCycle = 0; + for (size_t i = 0; i < currentSelection.size(); ++i) + m_listSelection << currentSelection[i]->getName().c_str(); + + m_listZonesModel->setListZones(m_listSelection); +} + +void ListZonesWidget::disableSignals(bool block) +{ + m_ui.categoryTypeComboBox_1->blockSignals(block); + m_ui.categoryTypeComboBox_2->blockSignals(block); + m_ui.categoryTypeComboBox_3->blockSignals(block); + m_ui.categoryTypeComboBox_4->blockSignals(block); + m_ui.categoryValueComboBox_1->blockSignals(block); + m_ui.categoryValueComboBox_2->blockSignals(block); + m_ui.categoryValueComboBox_3->blockSignals(block); + m_ui.categoryValueComboBox_4->blockSignals(block); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.h new file mode 100644 index 000000000..f33eda706 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.h @@ -0,0 +1,83 @@ +// 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 LIST_ZONES_WIDGET_H +#define LIST_ZONES_WIDGET_H + +// Project includes +#include "ui_list_zones_widget.h" + +// NeL includes + +// Qt includes + +namespace LandscapeEditor +{ +class ListZonesModel; +class ZoneBuilder; + +/** +@class ZoneListWidget +@brief ZoneListWidget displays list available zones in accordance with the filter settings +@details +*/ +class ListZonesWidget: public QWidget +{ + Q_OBJECT + +public: + explicit ListZonesWidget(QWidget *parent = 0); + ~ListZonesWidget(); + + void updateUi(); + + /// Set zone builder, call this method before using this class + void setZoneBuilder(ZoneBuilder *zoneBuilder); + + /// Get current zone name which user selected from list. + QString currentZoneName(); + + /// Get current rotation value which user selected (Rot 0-0deg, 1-90deg, 2-180deg, 3-270deg). + int currentRot(); + + /// Get current flip value which user selected (Flip 0-false, 1-true). + int currentFlip(); + + bool isNotPropogate() const; + bool isForce() const; + +private Q_SLOTS: + void updateFilters_1(const QString &value); + void updateFilters_2(const QString &value); + void updateFilters_3(const QString &value); + void updateFilters_4(const QString &value); + void updateListZones(); + +private: + void disableSignals(bool block); + + int m_rotCycle, m_flipCycle; + int m_zoneNameCycle; + QStringList m_listSelection; + + ListZonesModel *m_listZonesModel; + ZoneBuilder *m_zoneBuilder; + Ui::ListZonesWidget m_ui; +}; /* ZoneListWidget */ + +} /* namespace LandscapeEditor */ + +#endif // LIST_ZONES_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.ui new file mode 100644 index 000000000..ed9faf74e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.ui @@ -0,0 +1,493 @@ + + + ListZonesWidget + + + + 0 + 0 + 359 + 579 + + + + Form + + + + 3 + + + 3 + + + + + Filter + + + + 6 + + + 3 + + + + + + + + + + + + Select + + + + + Random + + + + + Fyll cycle + + + + + + + + true + + + + + + + true + + + + + + + true + + + + And + + + + + Or + + + + + + + + true + + + + + + + true + + + + + + + true + + + + And + + + + + Or + + + + + + + + true + + + + + + + true + + + + + + + true + + + + And + + + + + Or + + + + + + + + ... + + + + :/core/icons/ic_nel_add_item.png + :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_add_item.png + + + true + + + true + + + + + + + ... + + + + :/core/icons/ic_nel_add_item.png + :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_add_item.png + + + true + + + true + + + + + + + ... + + + + :/core/icons/ic_nel_add_item.png + :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_add_item.png + + + true + + + true + + + + + + + + + + Placement + + + + 6 + + + 3 + + + + + + 0° + + + + + 90° + + + + + 180° + + + + + 270° + + + + + Random + + + + + Full cycle + + + + + + + + + NoFlip + + + + + Flip + + + + + Random + + + + + Fyll cycle + + + + + + + + Force + + + + + + + Not propogate + + + + + + + + + + false + + + QAbstractItemView::ScrollPerPixel + + + 1 + + + + + + + + + + + addFilterButton_1 + toggled(bool) + categoryTypeComboBox_2 + setVisible(bool) + + + 20 + 36 + + + 81 + 53 + + + + + addFilterButton_1 + toggled(bool) + categoryValueComboBox_2 + setVisible(bool) + + + 24 + 32 + + + 181 + 50 + + + + + addFilterButton_1 + toggled(bool) + logicComboBox_2 + setVisible(bool) + + + 20 + 31 + + + 301 + 55 + + + + + addFilterButton_2 + toggled(bool) + categoryTypeComboBox_3 + setVisible(bool) + + + 27 + 62 + + + 57 + 75 + + + + + addFilterButton_2 + toggled(bool) + categoryValueComboBox_3 + setVisible(bool) + + + 23 + 58 + + + 156 + 76 + + + + + addFilterButton_2 + toggled(bool) + logicComboBox_3 + setVisible(bool) + + + 23 + 53 + + + 255 + 77 + + + + + addFilterButton_3 + toggled(bool) + categoryTypeComboBox_4 + setVisible(bool) + + + 32 + 94 + + + 44 + 104 + + + + + addFilterButton_3 + toggled(bool) + categoryValueComboBox_4 + setVisible(bool) + + + 32 + 94 + + + 207 + 103 + + + + + addFilterButton_3 + toggled(bool) + logicComboBox_4 + setVisible(bool) + + + 21 + 81 + + + 278 + 104 + + + + + addFilterButton_2 + toggled(bool) + addFilterButton_3 + setVisible(bool) + + + 15 + 59 + + + 16 + 80 + + + + + addFilterButton_1 + toggled(bool) + addFilterButton_2 + setVisible(bool) + + + 13 + 35 + + + 17 + 60 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/ovqt_plugin_landscape_editor.xml b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/ovqt_plugin_landscape_editor.xml new file mode 100644 index 000000000..ab71b7044 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/ovqt_plugin_landscape_editor.xml @@ -0,0 +1,10 @@ + + ovqt_plugin_landscape_editor + LandscapeEditor + 0.8 + GSoC2011_dnk-88 + Landscape editor ovqt plugin. + + + + \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp new file mode 100644 index 000000000..15f8760be --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp @@ -0,0 +1,154 @@ +// 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 "pixmap_database.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +PixmapDatabase::PixmapDatabase(int textureSize) + : m_textureSize(textureSize), + m_errorPixmap(0) +{ + // Create pixmap for case if pixmap and LIGO files not found + m_errorPixmap = new QPixmap(QSize(m_textureSize, m_textureSize)); + QPainter painter(m_errorPixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.fillRect(m_errorPixmap->rect(), QBrush(QColor(Qt::black))); + painter.setFont(QFont("Helvetica [Cronyx]", 14)); + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.drawText(m_errorPixmap->rect(), Qt::AlignCenter | Qt::TextWordWrap, + QObject::tr("Pixmap and LIGO files not found.")); + painter.end(); +} + +PixmapDatabase::~PixmapDatabase() +{ + delete m_errorPixmap; + reset(); +} + +bool PixmapDatabase::loadPixmaps(const QString &zonePath, NLLIGO::CZoneBank &zoneBank, bool displayProgress) +{ + QProgressDialog *progressDialog; + std::vector listNames; + zoneBank.getCategoryValues ("zone", listNames); + if (displayProgress) + { + progressDialog = new QProgressDialog(QObject::tr("Loading ligo zones."), QObject::tr("Cancel"), 0, listNames.size()); + progressDialog->show(); + } + + for (uint i = 0; i < listNames.size(); ++i) + { + QApplication::processEvents(); + + if (displayProgress) + progressDialog->setValue(i); + + NLLIGO::CZoneBankElement *zoneBankItem = zoneBank.getElementByZoneName (listNames[i]); + + // Read the texture file + QString zonePixmapName(listNames[i].c_str()); + uint8 sizeX = zoneBankItem->getSizeX(); + uint8 sizeY = zoneBankItem->getSizeY(); + + QPixmap *pixmap = new QPixmap(zonePath + zonePixmapName + ".png"); + if (pixmap->isNull()) + { + // Generate filled pixmap if could not load pixmap + QPixmap *emptyPixmap = new QPixmap(QSize(sizeX * m_textureSize, sizeY * m_textureSize)); + QPainter painter(emptyPixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.fillRect(emptyPixmap->rect(), QBrush(QColor(Qt::black))); + painter.setFont(QFont("Helvetica [Cronyx]", 18)); + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.drawText(emptyPixmap->rect(), Qt::AlignCenter, QObject::tr("Pixmap not found")); + painter.end(); + delete pixmap; + m_pixmapMap.insert(zonePixmapName, emptyPixmap); + nlwarning(QString("not found " + zonePath + zonePixmapName + ".png").toStdString().c_str()); + } + // All pixmaps must be have same size + else if (pixmap->width() != sizeX * m_textureSize) + { + QPixmap *scaledPixmap = new QPixmap(pixmap->scaled(sizeX * m_textureSize, sizeY * m_textureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + delete pixmap; + m_pixmapMap.insert(zonePixmapName, scaledPixmap); + } + else + m_pixmapMap.insert(zonePixmapName, pixmap); + } + + QPixmap *pixmap = new QPixmap(zonePath + "_unused_.png"); + QPixmap *scaledPixmap = new QPixmap(pixmap->scaled(m_textureSize, m_textureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + delete pixmap; + m_pixmapMap.insert(QString(STRING_UNUSED), scaledPixmap); + + if (displayProgress) + delete progressDialog; + + return true; +} + +void PixmapDatabase::reset() +{ + QStringList listNames(m_pixmapMap.keys()); + Q_FOREACH(QString name, listNames) + { + QPixmap *pixmap = m_pixmapMap.value(name); + delete pixmap; + } + m_pixmapMap.clear(); +} + +QStringList PixmapDatabase::listPixmaps() const +{ + return m_pixmapMap.keys(); +} + +QPixmap *PixmapDatabase::pixmap(const QString &zoneName) const +{ + QPixmap *result = m_errorPixmap; + if (!m_pixmapMap.contains(zoneName)) + nlwarning("QPixmap %s not found", zoneName.toStdString().c_str()); + else + result = m_pixmapMap.value(zoneName); + return result; +} + +int PixmapDatabase::textureSize() const +{ + return m_textureSize; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h new file mode 100644 index 000000000..282872343 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h @@ -0,0 +1,70 @@ +// 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 PIXMAP_DATABASE_H +#define PIXMAP_DATABASE_H + +// Project includes +#include "landscape_editor_global.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ + +/** +@class PixmapDatabase +@brief PixmapDatabase contains the image database +@details +*/ +class LANDSCAPE_EDITOR_EXPORT PixmapDatabase +{ +public: + explicit PixmapDatabase(int textureSize = 256); + ~PixmapDatabase(); + + /// Load all images(png) from zonePath, list images gets from zoneBank + bool loadPixmaps(const QString &zonePath, NLLIGO::CZoneBank &zoneBank, bool displayProgress = false); + + /// Unload all images + void reset(); + + /// Get list names all loaded pixmaps + QStringList listPixmaps() const; + + /// Get original pixmap + /// @return QPixmap* if the image is in the database ; + /// otherwise returns pixmap which contains error message. + QPixmap *pixmap(const QString &zoneName) const; + + int textureSize() const; + +private: + + int m_textureSize; + QPixmap *m_errorPixmap; + QMap m_pixmapMap; +}; + +} /* namespace LandscapeEditor */ + +#endif // PIXMAP_DATABASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp new file mode 100644 index 000000000..f3eedb8a6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp @@ -0,0 +1,60 @@ +// 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 "landscape_editor_constants.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ + +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 LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.h new file mode 100644 index 000000000..ecad06f58 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_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_H +#define PROJECT_SETTINGS_DIALOG_H + +// Project includes +#include "ui_project_settings_dialog.h" + +// Qt includes + +namespace LandscapeEditor +{ + +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 LandscapeEditor */ + +#endif // PROJECT_SETTINGS_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.ui new file mode 100644 index 000000000..a666cb71c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.ui @@ -0,0 +1,90 @@ + + + ProjectSettingsDialog + + + + 0 + 0 + 419 + 67 + + + + Project settings + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + + + + Data directory: + + + pathLineEdit + + + + + + + + + + ... + + + + + + + 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/landscape_editor/shapshot_dialog.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/shapshot_dialog.ui new file mode 100644 index 000000000..66f657012 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/shapshot_dialog.ui @@ -0,0 +1,228 @@ + + + SnapshotDialog + + + + 0 + 0 + 230 + 187 + + + + Snapshot + + + + :/icons/ic_snapshot.png:/icons/ic_snapshot.png + + + + + + + + Original size + + + true + + + + + + + 1024 + + + 128 + + + + + + + + + true + + + Custom size + + + + + + + false + + + + + + + + + 99999 + + + 512 + + + + + + + false + + + Height: + + + heightSpinBox + + + + + + + false + + + 99999 + + + 512 + + + + + + + Width: + + + widthSpinBox + + + + + + + Keep bitmap ratio + + + true + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + originalSizeRadioButton + customSizeRadioButton + widthSpinBox + heightSpinBox + keepRatioCheckBox + buttonBox + + + + + + + buttonBox + accepted() + SnapshotDialog + accept() + + + 227 + 164 + + + 157 + 158 + + + + + buttonBox + rejected() + SnapshotDialog + reject() + + + 276 + 170 + + + 285 + 158 + + + + + customSizeRadioButton + toggled(bool) + groupBox + setEnabled(bool) + + + 59 + 39 + + + 78 + 62 + + + + + keepRatioCheckBox + toggled(bool) + heightSpinBox + setDisabled(bool) + + + 84 + 122 + + + 178 + 106 + + + + + keepRatioCheckBox + toggled(bool) + label_2 + setDisabled(bool) + + + 55 + 129 + + + 48 + 103 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp new file mode 100644 index 000000000..aeccd21b2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp @@ -0,0 +1,70 @@ +// 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 "snapshot_dialog.h" +#include "landscape_editor_constants.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +SnapshotDialog::SnapshotDialog(QWidget *parent) + : QDialog(parent) +{ + m_ui.setupUi(this); + setFixedHeight(sizeHint().height()); +} + +SnapshotDialog::~SnapshotDialog() +{ +} + +bool SnapshotDialog::isCustomSize() const +{ + return m_ui.customSizeRadioButton->isChecked(); +} + +bool SnapshotDialog::isKeepRatio() const +{ + return m_ui.keepRatioCheckBox->isChecked(); +} + +int SnapshotDialog::resolutionZone() const +{ + return m_ui.resSpinBox->value(); +} + +int SnapshotDialog::widthSnapshot() const +{ + return m_ui.widthSpinBox->value(); +} + +int SnapshotDialog::heightSnapshot() const +{ + return m_ui.heightSpinBox->value(); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.h new file mode 100644 index 000000000..07844ce31 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.h @@ -0,0 +1,49 @@ +// 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 SNAPSHOT_DIALOG_H +#define SNAPSHOT_DIALOG_H + +// Project includes +#include "ui_shapshot_dialog.h" + +// Qt includes + +namespace LandscapeEditor +{ + +class SnapshotDialog: public QDialog +{ + Q_OBJECT + +public: + explicit SnapshotDialog(QWidget *parent = 0); + ~SnapshotDialog(); + + bool isCustomSize() const; + bool isKeepRatio() const; + int resolutionZone() const; + int widthSnapshot() const; + int heightSnapshot() const; + +private: + + Ui::SnapshotDialog m_ui; +}; /* class SnapshotDialog */ + +} /* namespace LandscapeEditor */ + +#endif // SNAPSHOT_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.cpp new file mode 100644 index 000000000..874c5d533 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.cpp @@ -0,0 +1,181 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "zone_region_editor.h" + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include + +namespace LandscapeEditor +{ + +ZoneRegionObject::ZoneRegionObject() +{ + m_fileName = ""; +} + +ZoneRegionObject::~ZoneRegionObject() +{ +} + +bool ZoneRegionObject::load(const std::string &fileName) +{ + bool result = true; + try + { + // Open it + NLMISC::CIFile fileIn; + if (fileIn.open(fileName)) + { + NLMISC::CIXml xml(true); + xml.init(fileIn); + m_zoneRegion.serial(xml); + } + else + { + nlwarning("Can't open file %s for reading", fileName.c_str()); + result = false; + } + } + catch (NLMISC::Exception &e) + { + nlwarning("Error reading file %s : %s", fileName.c_str(), e.what ()); + result = false; + } + if (result) + m_fileName = fileName; + return result; +} + +bool ZoneRegionObject::save() +{ + if (m_fileName.empty()) + return false; + + bool result = true; + // Save the landscape + try + { + + // Open file for writing + NLMISC::COFile fileOut; + if (fileOut.open(m_fileName, false, false, true)) + { + // Be careful with the flushing of the COXml object + { + NLMISC::COXml xmlOut; + xmlOut.init(&fileOut); + m_zoneRegion.serial(xmlOut); + // Done + m_modified = false; + } + fileOut.close(); + } + else + { + nlwarning("Can't open file %s for writing.", m_fileName.c_str()); + result = false; + } + } + catch (NLMISC::Exception &e) + { + nlwarning("Error writing file %s : %s", m_fileName.c_str(), e.what()); + result = false; + } + return result; +} + +std::string ZoneRegionObject::fileName() const +{ + return m_fileName; +} + +void ZoneRegionObject::setFileName(const std::string &fileName) +{ + m_fileName = fileName; +} + +void ZoneRegionObject::ligoData(LigoData &data, const sint32 x, const sint32 y) +{ + data.posX = m_zoneRegion.getPosX(x, y); + data.posY = m_zoneRegion.getPosY(x, y); + data.zoneName = m_zoneRegion.getName(x, y); + data.rot = m_zoneRegion.getRot(x, y); + data.flip = m_zoneRegion.getFlip(x, y); + data.sharingMatNames[0] = m_zoneRegion.getSharingMatNames(x, y, 0); + data.sharingMatNames[1] = m_zoneRegion.getSharingMatNames(x, y, 1); + data.sharingMatNames[2] = m_zoneRegion.getSharingMatNames(x, y, 2); + data.sharingMatNames[3] = m_zoneRegion.getSharingMatNames(x, y, 3); + data.sharingCutEdges[0] = m_zoneRegion.getSharingCutEdges(x, y, 0); + data.sharingCutEdges[1] = m_zoneRegion.getSharingCutEdges(x, y, 1); + data.sharingCutEdges[2] = m_zoneRegion.getSharingCutEdges(x, y, 2); + data.sharingCutEdges[3] = m_zoneRegion.getSharingCutEdges(x, y, 3); +} + +void ZoneRegionObject::setLigoData(const LigoData &data, const sint32 x, const sint32 y) +{ + m_zoneRegion.setPosX(x, y, data.posX); + m_zoneRegion.setPosY(x, y, data.posY); + m_zoneRegion.setName(x, y, data.zoneName); + m_zoneRegion.setRot(x, y, data.rot); + m_zoneRegion.setFlip(x, y, data.flip); + m_zoneRegion.setSharingMatNames(x, y, 0, data.sharingMatNames[0]); + m_zoneRegion.setSharingMatNames(x, y, 1, data.sharingMatNames[1]); + m_zoneRegion.setSharingMatNames(x, y, 2, data.sharingMatNames[2]); + m_zoneRegion.setSharingMatNames(x, y, 3, data.sharingMatNames[3]); + m_zoneRegion.setSharingCutEdges(x, y, 0, data.sharingCutEdges[0]); + m_zoneRegion.setSharingCutEdges(x, y, 1, data.sharingCutEdges[1]); + m_zoneRegion.setSharingCutEdges(x, y, 2, data.sharingCutEdges[2]); + m_zoneRegion.setSharingCutEdges(x, y, 3, data.sharingCutEdges[3]); +} + +NLLIGO::CZoneRegion &ZoneRegionObject::ligoZoneRegion() +{ + return m_zoneRegion; +} + +void ZoneRegionObject::setLigoZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + m_zoneRegion = zoneRegion; +} + +bool ZoneRegionObject::checkPos(const sint32 x, const sint32 y) +{ + return ((x >= m_zoneRegion.getMinX()) && + (x <= m_zoneRegion.getMaxX()) && + (y >= m_zoneRegion.getMinY()) && + (y <= m_zoneRegion.getMaxY())); +} + +bool ZoneRegionObject::isModified() const +{ + return m_modified; +} + +void ZoneRegionObject::setModified(bool modified) +{ + m_modified = modified; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.h new file mode 100644 index 000000000..e40aba9d4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.h @@ -0,0 +1,133 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 LANDSCAPE_EDITOR_H +#define LANDSCAPE_EDITOR_H + +// Project includes +#include "landscape_editor_global.h" + +// NeL includes +#include +#include + +// STL includes +#include + +namespace LandscapeEditor +{ + +// Data +struct LigoData +{ + uint8 posX; + uint8 posY; + uint8 rot; + uint8 flip; + std::string zoneName; + std::string sharingMatNames[4]; + uint8 sharingCutEdges[4]; + + LigoData() + { + posX = 0; + posY = 0; + zoneName = ""; + rot = 0; + flip = 0; + sharingMatNames[0] = ""; + sharingMatNames[1] = ""; + sharingMatNames[2] = ""; + sharingMatNames[3] = ""; + sharingCutEdges[0] = 0; + sharingCutEdges[1] = 0; + sharingCutEdges[2] = 0; + sharingCutEdges[3] = 0; + } + bool operator!= (const LigoData &other) const + { + return (posX != other.posX) || + (posY != other.posY) || + (rot != other.rot) || + (flip != other.flip) || + (zoneName != other.zoneName) || + (sharingMatNames[0] != other.sharingMatNames[0]) || + (sharingMatNames[1] != other.sharingMatNames[1]) || + (sharingMatNames[2] != other.sharingMatNames[2]) || + (sharingMatNames[3] != other.sharingMatNames[3]) || + (sharingCutEdges[0] != other.sharingCutEdges[0]) || + (sharingCutEdges[1] != other.sharingCutEdges[1]) || + (sharingCutEdges[2] != other.sharingCutEdges[2]) || + (sharingCutEdges[3] != other.sharingCutEdges[3]); + } +}; + +/** +@class ZoneRegionObject +@brief The class contains NLLIGO::CZoneRegion object and provides basic operations above it +@details +*/ +class LANDSCAPE_EDITOR_EXPORT ZoneRegionObject +{ +public: + ZoneRegionObject(); + ~ZoneRegionObject(); + + /// Load landscape data from file + bool load(const std::string &fileName); + + /// Save landscape data to file (before save, should set file name). + bool save(); + + /// Get ligo data + void ligoData(LigoData &data, const sint32 x, const sint32 y); + + /// Set ligo data + void setLigoData(const LigoData &data, const sint32 x, const sint32 y); + + /// Get file name + std::string fileName() const; + + /// Set file name, use for saving data in file + void setFileName(const std::string &fileName); + + /// Accessor to LIGO CZoneRegion + NLLIGO::CZoneRegion &ligoZoneRegion(); + + void setLigoZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + /// Check position, it belongs to the landscape + bool checkPos(const sint32 x, const sint32 y); + + /// Helper flag to know if the zone region has been modified + /// @{ + bool isModified() const; + + void setModified(bool modified); + /// @} + +private: + + bool m_modified; + bool m_editable; + std::string m_fileName; + NLLIGO::CZoneRegion m_zoneRegion; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_EDITOR_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 new file mode 100644 index 000000000..32f3950d9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt @@ -0,0 +1,70 @@ +INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${QT_INCLUDES} + ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/qtpropertybrowser + ) + +FILE(GLOB SRC *.cpp *.h) + +SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) + +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 + property_editor_widget.h + world_editor_settings_page.h +) + +SET(OVQT_PLUGIN_WORLD_EDITOR_UIS world_editor_window.ui + project_settings_dialog.ui + property_editor_widget.ui + world_editor_settings_page.ui +) + +SET(OVQT_PLUGIN_WORLD_EDITOR_RCS world_editor.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES(OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS ${OVQT_PLUGIN_WORLD_EDITOR_RCS}) +QT4_WRAP_CPP(OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC ${OVQT_PLUGIN_WORLD_EDITOR_HDR}) +QT4_WRAP_UI(OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS ${OVQT_PLUGIN_WORLD_EDITOR_UIS}) + +SOURCE_GROUP(QtResources FILES ${OVQT_PLUGIN_WORLD_EDITOR_UIS}) +SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS}) +SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC} OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS) +SOURCE_GROUP("World Editor Plugin" FILES ${SRC}) +SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) + +ADD_LIBRARY(ovqt_plugin_world_editor MODULE ${SRC} + ${OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC} + ${OVQT_EXT_SYS_SRC} + ${OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS} + ${OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS}) + +TARGET_LINK_LIBRARIES( ovqt_plugin_world_editor + ovqt_plugin_core + ovqt_plugin_landscape_editor + nelmisc + nel3d + qt_property_browser + ${QT_LIBRARIES} + ${QT_QTOPENGL_LIBRARY} +) + +NL_DEFAULT_PROPS(ovqt_plugin_world_editor "NeL, Tools, 3D: Object Viewer Qt Plugin: World Editor") +NL_ADD_RUNTIME_FLAGS(ovqt_plugin_world_editor) +NL_ADD_LIB_SUFFIX(ovqt_plugin_world_editor) + +ADD_DEFINITIONS(-DWORLD_EDITOR_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) + +INSTALL(TARGETS ovqt_plugin_world_editor LIBRARY DESTINATION ${OVQT_PLUGIN_DIR} RUNTIME DESTINATION ${NL_BIN_PREFIX} ARCHIVE DESTINATION ${OVQT_PLUGIN_DIR} COMPONENT tools3d) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ovqt_plugin_world_editor.xml DESTINATION ${OVQT_PLUGIN_SPECS_DIR} COMPONENT tools3d) + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png new file mode 100644 index 000000000..7039bd070 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png new file mode 100644 index 000000000..73a0be2fe Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png new file mode 100644 index 000000000..e76150ab4 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png new file mode 100644 index 000000000..9a677b8a6 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png new file mode 100644 index 000000000..b03cb0fd0 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png new file mode 100644 index 000000000..d41f64e2f Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/ovqt_plugin_world_editor.xml b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/ovqt_plugin_world_editor.xml new file mode 100644 index 000000000..7a37eaf56 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/ovqt_plugin_world_editor.xml @@ -0,0 +1,11 @@ + + ovqt_plugin_world_editor + WorldEditor + 0.6 + GSoC2011_dnk-88 + Landscape editor ovqt plugin. + + + + + \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp new file mode 100644 index 000000000..12d3b994a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp @@ -0,0 +1,312 @@ +// 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 "primitive_item.h" +#include "world_editor_misc.h" +#include "world_editor_constants.h" + +#include "../landscape_editor/landscape_editor_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace WorldEditor +{ + +Node::Node() + : m_parent(0) +{ + setData(Constants::PRIMITIVE_IS_VISIBLE, true); +} + +Node::~Node() +{ + if (m_parent) + m_parent->removeChildNode(this); + + qDeleteAll(m_children); + nlassert(m_children.isEmpty()); + m_data.clear(); +} + +void Node::prependChildNode(Node *node) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.prepend(node); + node->m_parent = this; +} + +void Node::appendChildNode(Node *node) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.append(node); + node->m_parent = this; +} + +void Node::insertChildNodeBefore(Node *node, Node *before) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = before ? m_children.indexOf(before) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx, node); + node->m_parent = this; +} + +void Node::insertChildNodeAfter(Node *node, Node *after) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = after ? m_children.indexOf(after) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx + 1, node); + node->m_parent = this; +} + +void Node::insertChildNode(int pos, Node *node) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.insert(pos, node); + node->m_parent = this; +} + +void Node::removeChildNode(Node *node) +{ + nlassert(m_children.contains(node)); + nlassert(node->parent() == this); + + m_children.removeOne(node); + + node->m_parent = 0; +} + +Node *Node::child(int row) +{ + return m_children.at(row); +} + +int Node::childCount() const +{ + return m_children.count(); +} + +QVariant Node::data(int key) const +{ + return m_data[key]; +} + +void Node::setData(int key, const QVariant &data) +{ + m_data[key] = data; +} + +Node *Node::parent() +{ + return m_parent; +} + +int Node::row() const +{ + if (m_parent) + return m_parent->m_children.indexOf(const_cast(this)); + + return 0; +} + +Node::NodeType Node::type() const +{ + return BasicNodeType; +} + +WorldEditNode::WorldEditNode(const QString &name) +{ + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(Constants::ICON_WORLD_EDITOR)); +} + +WorldEditNode::~WorldEditNode() +{ +} + +void WorldEditNode::setContext(const QString &name) +{ + m_context = name; +} + +QString WorldEditNode::context() const +{ + return m_context; +} + +void WorldEditNode::setDataPath(const QString &path) +{ + m_dataPath = path; +} + +QString WorldEditNode::dataPath() const +{ + return m_dataPath; +} + +Node::NodeType WorldEditNode::type() const +{ + return WorldEditNodeType; +} + +LandscapeNode::LandscapeNode(const QString &name, int id) + : m_id(id), + m_fileName(name) +{ + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); +} + +LandscapeNode::~LandscapeNode() +{ +} + +QString LandscapeNode::fileName() const +{ + return m_fileName; +} + +int LandscapeNode::id() const +{ + return m_id; +} + +Node::NodeType LandscapeNode::type() const +{ + return LandscapeNodeType; +} + +PrimitiveNode::PrimitiveNode(NLLIGO::IPrimitive *primitive) + : m_primitive(primitive) +{ + setData(Qt::DisplayRole, QString(m_primitive->getName().c_str())); + setData(Qt::ToolTipRole, QString(m_primitive->getClassName().c_str())); + + std::string className; + m_primitive->getPropertyByName("class", className); + + // Set Icon + QString nameIcon = QString("%1/%2.ico").arg(Constants::PATH_TO_OLD_ICONS).arg(className.c_str()); + QIcon icon(nameIcon); + if (!QFile::exists(nameIcon)) + { + if (primitive->getParent() == NULL) + icon = QIcon(Constants::ICON_ROOT_PRIMITIVE); + else if (primitive->getNumChildren() == 0) + icon = QIcon(Constants::ICON_PROPERTY); + else + icon = QIcon(Constants::ICON_FOLDER); + } + setData(Qt::DecorationRole, icon); +} + +PrimitiveNode::~PrimitiveNode() +{ +} + +NLLIGO::IPrimitive *PrimitiveNode::primitive() const +{ + return m_primitive; +} + +const NLLIGO::CPrimitiveClass *PrimitiveNode::primitiveClass() const +{ + return Utils::ligoConfig()->getPrimitiveClass(*m_primitive); +} + +RootPrimitiveNode *PrimitiveNode::rootPrimitiveNode() +{ + Node *node = this; + while (node && (node->type() != Node::RootPrimitiveNodeType)) + node = node->parent(); + return static_cast(node); +} + +Node::NodeType PrimitiveNode::type() const +{ + return PrimitiveNodeType; +} + +RootPrimitiveNode::RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives) + : PrimitiveNode(primitives->RootNode), + m_fileName(name), + m_primitives(primitives) +{ + setData(Qt::DisplayRole, name); +} + +RootPrimitiveNode::~RootPrimitiveNode() +{ +} + +NLLIGO::CPrimitives *RootPrimitiveNode::primitives() const +{ + return m_primitives; +} + +void RootPrimitiveNode::setFileName(const QString &fileName) +{ + setData(Qt::DisplayRole, fileName); + m_fileName = fileName; +} + +QString RootPrimitiveNode::fileName() const +{ + return m_fileName; +} + +Node::NodeType RootPrimitiveNode::type() const +{ + return RootPrimitiveNodeType; +} + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h new file mode 100644 index 000000000..519b40aaf --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h @@ -0,0 +1,200 @@ +// 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 PRIMITIVE_ITEM_H +#define PRIMITIVE_ITEM_H + +// Project includes + +// NeL includes +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ +class RootPrimitiveNode; + +/* +@class Node +@brief +@details +*/ +class Node +{ +public: + + enum NodeType + { + BasicNodeType, + WorldEditNodeType, + RootPrimitiveNodeType, + LandscapeNodeType, + PrimitiveNodeType, + UserNodeType = 1024 + }; + + Node(); + virtual ~Node(); + + /// Remove child node from the child list. + void removeChildNode(Node *node); + + /// Insert node at the beginning of the list. + void prependChildNode(Node *node); + + /// Insert node at the end of the list. + void appendChildNode(Node *node); + + /// Insert node in front of the node pointed to by the pointer before. + void insertChildNodeBefore(Node *node, Node *before); + + /// Insert node in back of the node pointed to by the pointer after. + void insertChildNodeAfter(Node *node, Node *after); + + /// Insert node in pos + void insertChildNode(int pos, Node *node); + + /// Return the node at index position row in the child list. + Node *child(int row); + + /// Return the number of nodes in the list. + int childCount() const; + + /// Return a row index this node. + int row() const; + + /// Return a pointer to this node's parent item. If this node does not have a parent, 0 is returned. + Node *parent(); + + /// Set this node's custom data for the key key to value. + void setData(int key, const QVariant &data); + + /// Return this node's custom data for the key key as a QVariant. + QVariant data(int key) const; + + /// Return a type this node. + virtual NodeType type() const; + +private: + Q_DISABLE_COPY(Node) + + Node *m_parent; + QList m_children; + QHash m_data; +}; + +/* +@class WorldEditNode +@brief +@details +*/ +class WorldEditNode: public Node +{ +public: + WorldEditNode(const QString &name); + virtual ~WorldEditNode(); + + void setContext(const QString &name); + QString context() const; + void setDataPath(const QString &path); + QString dataPath() const; + + virtual NodeType type() const; + +private: + QString m_context; + QString m_dataPath; +}; + +/* +@class LandscapeNode +@brief +@details +*/ +class LandscapeNode: public Node +{ +public: + LandscapeNode(const QString &name, int id); + virtual ~LandscapeNode(); + + int id() const; + QString fileName() const; + + virtual NodeType type() const; + +private: + + QString m_fileName; + int m_id; +}; + +/* +@class PrimitiveNode +@brief +@details +*/ +class PrimitiveNode: public Node +{ +public: + explicit PrimitiveNode(NLLIGO::IPrimitive *primitive); + virtual ~PrimitiveNode(); + + NLLIGO::IPrimitive *primitive() const; + const NLLIGO::CPrimitiveClass *primitiveClass() const; + RootPrimitiveNode *rootPrimitiveNode(); + + virtual NodeType type() const; + +private: + NLLIGO::IPrimitive *m_primitive; +}; + +/* +@class RootPrimitiveNode +@brief +@details +*/ +class RootPrimitiveNode: public PrimitiveNode +{ +public: + RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives); + virtual ~RootPrimitiveNode(); + + NLLIGO::CPrimitives *primitives() const; + + void setFileName(const QString &fileName); + QString fileName() const; + virtual NodeType type() const; + +private: + + QString m_fileName; + NLLIGO::CPrimitives *m_primitives; +}; + +typedef QList NodeList; + +} /* namespace WorldEditor */ + +// Enable the use of QVariant with this class. +Q_DECLARE_METATYPE(WorldEditor::Node *) + +#endif // PRIMITIVE_ITEM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp new file mode 100644 index 000000000..78313624e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp @@ -0,0 +1,328 @@ +// 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 "primitive_item.h" +#include "primitives_model.h" +#include "world_editor_misc.h" +#include "world_editor_constants.h" + +// NeL includes +#include +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +PrimitivesTreeModel::PrimitivesTreeModel(QObject *parent) + : QAbstractItemModel(parent), + m_worldEditNode(0) +{ + m_rootNode = new Node(); + m_rootNode->setData(Qt::DisplayRole, "Name"); +} + +PrimitivesTreeModel::~PrimitivesTreeModel() +{ + delete m_rootNode; +} + +int PrimitivesTreeModel::columnCount(const QModelIndex &parent) const +{ + /* if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return m_rootItem->columnCount(); + */ + return 1; +} + +QVariant PrimitivesTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + Node *item = static_cast(index.internalPointer()); + switch (role) + { +// case Qt::TextAlignmentRole: +// return int(Qt::AlignLeft | Qt::AlignVCenter); + case Qt::DisplayRole: + return item->data(Qt::DisplayRole); + case Qt::DecorationRole: + return item->data(Qt::DecorationRole); + default: + return QVariant(); + } +} + +Qt::ItemFlags PrimitivesTreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QVariant PrimitivesTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) +// return m_rootNode->data(section); + return m_rootNode->data(Qt::DisplayRole); + + return QVariant(); +} + +QModelIndex PrimitivesTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + Node *parentNode; + + if (!parent.isValid()) + parentNode = m_rootNode; + else + parentNode = static_cast(parent.internalPointer()); + + Node *childNode = parentNode->child(row); + if (childNode) + return createIndex(row, column, childNode); + else + return QModelIndex(); +} + +QModelIndex PrimitivesTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + Node *childNode = static_cast(index.internalPointer()); + Node *parentNode = childNode->parent(); + + if (parentNode == m_rootNode) + return QModelIndex(); + + return createIndex(parentNode->row(), 0, parentNode); +} + +int PrimitivesTreeModel::rowCount(const QModelIndex &parent) const +{ + Node *parentNode; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentNode = m_rootNode; + else + parentNode = static_cast(parent.internalPointer()); + + return parentNode->childCount(); +} + +Path PrimitivesTreeModel::pathFromIndex(const QModelIndex &index) +{ + QModelIndex iter = index; + Path path; + while(iter.isValid()) + { + path.prepend(PathItem(iter.row(), iter.column())); + iter = iter.parent(); + } + return path; +} + +Path PrimitivesTreeModel::pathFromNode(Node *node) +{ + Node *iter = node; + Path path; + while(iter != 0) + { + path.prepend(PathItem(iter->row(), 0)); + iter = iter->parent(); + } + return path; +} + +QModelIndex PrimitivesTreeModel::pathToIndex(const Path &path) +{ + QModelIndex iter; + for(int i = 0; i < path.size(); i++) + { + iter = index(path[i].first, path[i].second, iter); + } + return iter; +} + +Node *PrimitivesTreeModel::pathToNode(const Path &path) +{ + Node *node = m_rootNode; + for(int i = 1; i < path.size(); i++) + { + node = node->child(path[i].first); + } + return node; +} + +void PrimitivesTreeModel::createWorldEditNode(const QString &fileName) +{ + // World edit node already is created, if yes is showing error message box + if (m_worldEditNode != 0) + nlerror("World edit node already is created."); + + beginResetModel(); + m_worldEditNode = new WorldEditNode(fileName); + m_rootNode->appendChildNode(m_worldEditNode); + endResetModel(); +} + +void PrimitivesTreeModel::deleteWorldEditNode() +{ + beginResetModel(); + if (m_worldEditNode != 0) + { + delete m_worldEditNode; + m_worldEditNode = 0; + } + endResetModel(); +} + +bool PrimitivesTreeModel::isWorldEditNodeLoaded() const +{ + if (m_worldEditNode == 0) + return false; + else + return true; +} + +Path PrimitivesTreeModel::createLandscapeNode(const QString &fileName, int id, int pos) +{ + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); + + QModelIndex parentIndex = index(0, 0, QModelIndex()); + int insPos = pos; + if (pos == -1) + insPos = 0; + + beginInsertRows(parentIndex, insPos, insPos); + LandscapeNode *newNode = new LandscapeNode(fileName, id); + m_worldEditNode->insertChildNode(insPos, newNode); + endInsertRows(); + return pathFromIndex(index(0, 0, index(insPos, 0, QModelIndex()))); +} + + +Path PrimitivesTreeModel::createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives, int pos) +{ + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); + + QString name = "NewPrimitive"; + if (!fileName.isEmpty()) + name = fileName; + + int insPos = pos; + + // Get position + if (pos == AtTheEnd) + insPos = m_worldEditNode->childCount(); + + QModelIndex parentIndex = index(0, 0, QModelIndex()); + + // Add root node in tree model + beginInsertRows(parentIndex, insPos, insPos); + RootPrimitiveNode *newNode = new RootPrimitiveNode(name, primitives); + m_worldEditNode->insertChildNode(insPos, newNode); + endInsertRows(); + + newNode->setData(Constants::PRIMITIVE_FILE_IS_CREATED, !fileName.isEmpty()); + newNode->setData(Constants::PRIMITIVE_IS_MODIFIED, false); + + QModelIndex rootPrimIndex = index(insPos, 0, parentIndex); + + // Scan childs items and add in the tree model + for (uint i = 0; i < primitives->RootNode->getNumChildren(); ++i) + { + NLLIGO::IPrimitive *childPrim; + primitives->RootNode->getChild(childPrim, i); + createChildNodes(childPrim, i, rootPrimIndex); + } + + return pathFromIndex(rootPrimIndex); +} + +Path PrimitivesTreeModel::createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent, int pos) +{ + QModelIndex parentIndex = pathToIndex(parent); + Node *parentNode = static_cast(parentIndex.internalPointer()); + + int insPos = pos; + if (pos == AtTheEnd) + insPos = parentNode->childCount(); + + createChildNodes(primitive, insPos, parentIndex); + + return pathFromIndex(index(insPos, 0, parentIndex)); +} + +void PrimitivesTreeModel::deleteNode(const Path &path) +{ + QModelIndex nodeIndex = pathToIndex(path); + QModelIndex parentIndex = nodeIndex.parent(); + Node *node = static_cast(nodeIndex.internalPointer()); + + // Scan childs items and delete from the tree model + removeChildNodes(node, parentIndex); +} + +void PrimitivesTreeModel::createChildNodes(NLLIGO::IPrimitive *primitive, int pos, const QModelIndex &parent) +{ + Node *parentNode = static_cast(parent.internalPointer()); + + // Add node in the tree model + beginInsertRows(parent, pos, pos); + PrimitiveNode *newNode = new PrimitiveNode(primitive); + parentNode->insertChildNode(pos, newNode); + endInsertRows(); + + // Scan childs items and add in the tree model + QModelIndex childIndex = index(pos, 0, parent); + for (uint i = 0; i < primitive->getNumChildren(); ++i) + { + NLLIGO::IPrimitive *childPrim; + primitive->getChild(childPrim, i); + createChildNodes(childPrim, i, childIndex); + } +} + +void PrimitivesTreeModel::removeChildNodes(Node *node, const QModelIndex &parent) +{ + // Delete all child nodes from the tree model + while (node->childCount() != 0) + removeChildNodes(node->child(node->childCount() - 1), parent.child(node->row(), 0)); + + // Delete node from the tree model + beginRemoveRows(parent, node->row(), node->row()); + delete node; + endRemoveRows(); +} + +} /* namespace WorldEditor */ \ No newline at end of file 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 new file mode 100644 index 000000000..031317d0c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h @@ -0,0 +1,104 @@ +// 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 PRIMITIVES_MODEL_H +#define PRIMITIVES_MODEL_H + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ +class Node; +class WorldEditNode; + +const int AtTheEnd = -1; + +typedef QPair PathItem; +/* +@typedef Path +@brief It store a list of row and column numbers which have to walk through from the root index of the model to reach the need item. +It is used for undo/redo commands. +*/ +typedef QList Path; + +/** +@class PrimitivesTreeModel +@brief +@details +*/ +class PrimitivesTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit PrimitivesTreeModel(QObject *parent = 0); + ~PrimitivesTreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + /// Convert QModelIndex to the persistent index - @Path. + /// @Path is a list of [row,column] pairs showing us the way through the model. + Path pathFromIndex(const QModelIndex &index); + QModelIndex pathToIndex(const Path &path); + + Path pathFromNode(Node *node); + Node *pathToNode(const Path &path); + + void createWorldEditNode(const QString &fileName); + void deleteWorldEditNode(); + bool isWorldEditNodeLoaded() const; + + /// Add new landscape node in tree model. + Path createLandscapeNode(const QString &fileName, int id, int pos = AtTheEnd); + + /// Add new root primitive node and all sub-primitives in the tree model. + Path createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives, int pos = AtTheEnd); + + /// Add new primitive node and all sub-primitives in the tree model. + Path createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent, int pos = AtTheEnd); + + /// Delete node and all child nodes from the tree model + void deleteNode(const Path &path); + +private: + void createChildNodes(NLLIGO::IPrimitive *primitive, int pos, const QModelIndex &parent); + void removeChildNodes(Node *node, const QModelIndex &parent); + + Node *m_rootNode; + WorldEditNode *m_worldEditNode; +}; + +} /* namespace WorldEditor */ + +#endif // PRIMITIVES_MODEL_H 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 new file mode 100644 index 000000000..e27e824b4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp @@ -0,0 +1,458 @@ +// 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 "primitives_view.h" +#include "primitives_model.h" +#include "world_editor_actions.h" +#include "world_editor_constants.h" + +#include "../core/core_constants.h" +#include "../landscape_editor/landscape_editor_constants.h" +#include "../landscape_editor/builder_zone_base.h" + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include +#include +#include +#include +#include + +namespace WorldEditor +{ + +PrimitivesView::PrimitivesView(QWidget *parent) + : QTreeView(parent), + m_undoStack(0), + m_worldEditorScene(0), + m_zoneBuilder(0), + m_primitivesTreeModel(0) +{ + setContextMenuPolicy(Qt::DefaultContextMenu); + + m_unloadAction = new QAction("Unload", this); + + m_saveAction = new QAction("Save", this); + m_saveAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + + m_saveAsAction = new QAction("Save As...", this); + m_saveAsAction->setIcon(QIcon(Core::Constants::ICON_SAVE_AS)); + + m_loadLandAction = new QAction("Load landscape file", this); + m_loadLandAction->setIcon(QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); + + m_loadPrimitiveAction = new QAction("Load primitive file", this); + m_loadPrimitiveAction->setIcon(QIcon(Constants::ICON_ROOT_PRIMITIVE)); + + m_newPrimitiveAction = new QAction("New primitive", this); + + m_deleteAction = new QAction("Delete", this); + + m_selectChildrenAction = new QAction("Select children", this); + + m_helpAction = new QAction("Help", this); + m_helpAction->setEnabled(false); + + m_showAction = new QAction("Show", this); + m_showAction->setEnabled(false); + + m_hideAction = new QAction("Hide", this); + m_hideAction->setEnabled(false); + + connect(m_loadLandAction, SIGNAL(triggered()), this, SLOT(loadLandscape())); + connect(m_loadPrimitiveAction, SIGNAL(triggered()), this, SLOT(loadRootPrimitive())); + connect(m_newPrimitiveAction, SIGNAL(triggered()), this, SLOT(createRootPrimitive())); + connect(m_selectChildrenAction, SIGNAL(triggered()), this, SLOT(selectChildren())); + connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deletePrimitives())); + connect(m_saveAction, SIGNAL(triggered()), this, SLOT(save())); + connect(m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs())); + connect(m_unloadAction, SIGNAL(triggered()), this, SLOT(unload())); + connect(m_showAction, SIGNAL(triggered()), this, SLOT(showPrimitive())); + connect(m_hideAction, SIGNAL(triggered()), this, SLOT(hidePrimitive())); + +#ifdef Q_OS_DARWIN + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); +#endif +} + +PrimitivesView::~PrimitivesView() +{ +} + +void PrimitivesView::setUndoStack(QUndoStack *undoStack) +{ + m_undoStack = undoStack; +} + +void PrimitivesView::setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + +void PrimitivesView::setWorldScene(WorldEditorScene *worldEditorScene) +{ + m_worldEditorScene = worldEditorScene; +} + +void PrimitivesView::setModel(PrimitivesTreeModel *model) +{ + QTreeView::setModel(model); + m_primitivesTreeModel = model; +} + +void PrimitivesView::loadRootPrimitive() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo primitive file"), m_lastDir, + tr("All NeL Ligo primitive files (*.primitive)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro(tr("Load primitive files")); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadRootPrimitiveCommand(fileName, m_worldEditorScene, m_primitivesTreeModel, this)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::loadLandscape() +{ + nlassert(m_undoStack); + nlassert(m_zoneBuilder); + nlassert(m_primitivesTreeModel); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo land file"), m_lastDir, + tr("All NeL Ligo land files (*.land)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro(tr("Load land files")); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadLandscapeCommand(fileName, m_primitivesTreeModel, m_zoneBuilder)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::createRootPrimitive() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + m_undoStack->push(new CreateRootPrimitiveCommand("NewPrimitive", m_primitivesTreeModel)); +} + +void PrimitivesView::selectChildren() +{ + QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex parentIndex = indexList.first(); + + selectionModel()->clearSelection(); + + QItemSelection itemSelection; + selectChildren(parentIndex, itemSelection); + selectionModel()->select(itemSelection, QItemSelectionModel::Select); +} + +void PrimitivesView::save() +{ + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex index = indexList.first(); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + if (node->data(Constants::PRIMITIVE_FILE_IS_CREATED).toBool()) + { + if (!NLLIGO::saveXmlPrimitiveFile(*node->primitives(), node->fileName().toStdString())) + QMessageBox::warning(this, "World Editor Qt", tr("Error writing output file: %1").arg(node->fileName())); + else + node->setData(Constants::PRIMITIVE_IS_MODIFIED, false); + } + else + saveAs(); +} + +void PrimitivesView::saveAs() +{ + nlassert(m_primitivesTreeModel); + + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save NeL Ligo primitive file"), m_lastDir, + tr("NeL Ligo primitive file (*.primitive)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex index = indexList.first(); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + if (!NLLIGO::saveXmlPrimitiveFile(*node->primitives(), fileName.toStdString())) + QMessageBox::warning(this, "World Editor Qt", tr("Error writing output file: %1").arg(fileName)); + else + { + node->setFileName(fileName); + node->setData(Constants::PRIMITIVE_FILE_IS_CREATED, true); + node->setData(Constants::PRIMITIVE_IS_MODIFIED, false); + } + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::deletePrimitives() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + + QModelIndex index = indexList.first(); + + PrimitiveNode *node = static_cast(index.internalPointer()); + + if (node->primitiveClass()->Deletable) + m_undoStack->push(new DeletePrimitiveCommand(index, m_primitivesTreeModel, m_worldEditorScene, this)); + +} + +void PrimitivesView::unload() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex index = indexList.first(); + Node *node = static_cast(index.internalPointer()); + switch (node->type()) + { + case Node::WorldEditNodeType: + { + break; + } + case Node::LandscapeNodeType: + { + m_undoStack->push(new UnloadLandscapeCommand(index, m_primitivesTreeModel, m_zoneBuilder)); + break; + } + case Node::RootPrimitiveNodeType: + { + m_undoStack->push(new UnloadRootPrimitiveCommand(index, m_worldEditorScene, m_primitivesTreeModel, this)); + break; + } + } +} + +void PrimitivesView::showPrimitive() +{ +} + +void PrimitivesView::hidePrimitive() +{ +} + +void PrimitivesView::addNewPrimitiveByClass(int value) +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + + PrimitiveNode *node = static_cast(indexList.first().internalPointer()); + + // Get class name + QString className = node->primitiveClass()->DynamicChildren[value].ClassName.c_str(); + + m_undoStack->push(new AddPrimitiveByClassCommand(className, m_primitivesTreeModel->pathFromIndex(indexList.first()), + m_worldEditorScene, m_primitivesTreeModel, this)); +} + +void PrimitivesView::generatePrimitives(int value) +{ +} + +void PrimitivesView::openItem(int value) +{ +} + +void PrimitivesView::contextMenuEvent(QContextMenuEvent *event) +{ + QWidget::contextMenuEvent(event); + QModelIndexList indexList = selectionModel()->selectedRows(); + if (indexList.size() == 0) + return; + + QMenu *popurMenu = new QMenu(this); + + if (indexList.size() == 1) + { + Node *node = static_cast(indexList.first().internalPointer()); + switch (node->type()) + { + case Node::WorldEditNodeType: + fillMenu_WorldEdit(popurMenu); + break; + case Node::RootPrimitiveNodeType: + fillMenu_RootPrimitive(popurMenu, indexList.first()); + break; + case Node::LandscapeNodeType: + fillMenu_Landscape(popurMenu); + break; + case Node::PrimitiveNodeType: + fillMenu_Primitive(popurMenu, indexList.first()); + break; + }; + } + + popurMenu->exec(event->globalPos()); + delete popurMenu; + event->accept(); +} + +void PrimitivesView::selectChildren(const QModelIndex &parent, QItemSelection &itemSelection) +{ + const int rowCount = model()->rowCount(parent); + + QItemSelection mergeItemSelection(parent.child(0, 0), parent.child(rowCount - 1, 0)); + itemSelection.merge(mergeItemSelection, QItemSelectionModel::Select); + + for (int i = 0; i < rowCount; ++i) + { + QModelIndex childIndex = parent.child(i, 0); + if (model()->rowCount(childIndex) != 0) + selectChildren(childIndex, itemSelection); + } +} + +void PrimitivesView::fillMenu_WorldEdit(QMenu *menu) +{ + //menu->addAction(m_unloadAction); + //menu->addAction(m_saveAction); + //menu->addAction(m_saveAsAction); + menu->addSeparator(); + menu->addAction(m_loadLandAction); + menu->addAction(m_loadPrimitiveAction); + menu->addAction(m_newPrimitiveAction); + menu->addSeparator(); + menu->addAction(m_helpAction); +} + +void PrimitivesView::fillMenu_Landscape(QMenu *menu) +{ + menu->addAction(m_unloadAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); +} + +void PrimitivesView::fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_saveAction); + menu->addAction(m_saveAsAction); + menu->addAction(m_unloadAction); + fillMenu_Primitive(menu, index); + menu->removeAction(m_deleteAction); +} + +void PrimitivesView::fillMenu_Primitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_deleteAction); + menu->addAction(m_selectChildrenAction); + menu->addAction(m_helpAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); + + QSignalMapper *addSignalMapper = new QSignalMapper(menu); + QSignalMapper *generateSignalMapper = new QSignalMapper(menu); + //QSignalMapper *openSignalMapper = new QSignalMapper(menu); + connect(addSignalMapper, SIGNAL(mapped(int)), this, SLOT(addNewPrimitiveByClass(int))); + connect(generateSignalMapper, SIGNAL(mapped(int)), this, SLOT(generatePrimitives(int))); + //connect(openSignalMapper, SIGNAL(mapped(int)), this, SLOT(openItem(int))); + + PrimitiveNode *node = static_cast(index.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = node->primitiveClass(); + + // What class is it ? + if (primClass && primClass->DynamicChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->DynamicChildren.size(); i++) + { + // Get class name + QString className = primClass->DynamicChildren[i].ClassName.c_str(); + + // Get icon + QIcon icon(QString("%1/%2.ico").arg(Constants::PATH_TO_OLD_ICONS).arg(className)); + + // Create and add action in popur menu + QAction *action = menu->addAction(icon, tr("Add %1").arg(className)); + addSignalMapper->setMapping(action, i); + connect(action, SIGNAL(triggered()), addSignalMapper, SLOT(map())); + } + } + + // What class is it ? + if (primClass && primClass->GeneratedChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->GeneratedChildren.size(); i++) + { + // Get class name + QString childName = primClass->GeneratedChildren[i].ClassName.c_str(); + + // Create and add action in popur menu + QAction *action = menu->addAction(tr("Generate %1").arg(childName)); + generateSignalMapper->setMapping(action, i); + connect(action, SIGNAL(triggered()), generateSignalMapper, SLOT(map())); + } + } +} + +} /* namespace WorldEditor */ \ No newline at end of file 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 new file mode 100644 index 000000000..8da877658 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h @@ -0,0 +1,112 @@ +// 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 PRIMITIVES_VIEW_H +#define PRIMITIVES_VIEW_H + +// Project includes +#include "primitive_item.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ +class PrimitivesTreeModel; +class WorldEditorScene; + +/** +@class PrimitivesView +@brief +@details +*/ +class PrimitivesView : public QTreeView +{ + Q_OBJECT + +public: + explicit PrimitivesView(QWidget *parent = 0); + ~PrimitivesView(); + + void setUndoStack(QUndoStack *undoStack); + void setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder); + void setWorldScene(WorldEditorScene *worldEditorScene); + virtual void setModel(PrimitivesTreeModel *model); + +private Q_SLOTS: + void loadLandscape(); + void loadRootPrimitive(); + void createRootPrimitive(); + void selectChildren(); + + void save(); + void saveAs(); + void deletePrimitives(); + void unload(); + void showPrimitive(); + void hidePrimitive(); + void addNewPrimitiveByClass(int value); + void generatePrimitives(int value); + void openItem(int value); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +private: + void selectChildren(const QModelIndex &parent, QItemSelection &itemSelection); + void fillMenu_WorldEdit(QMenu *menu); + void fillMenu_Landscape(QMenu *menu); + void fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index); + void fillMenu_Primitive(QMenu *menu, const QModelIndex &index); + + QString m_lastDir; + + QAction *m_unloadAction; + QAction *m_saveAction; + QAction *m_saveAsAction; + QAction *m_loadLandAction; + QAction *m_loadPrimitiveAction; + QAction *m_newPrimitiveAction; + QAction *m_deleteAction; + QAction *m_selectChildrenAction; + QAction *m_helpAction; + QAction *m_showAction; + QAction *m_hideAction; + + QUndoStack *m_undoStack; + WorldEditorScene *m_worldEditorScene; + LandscapeEditor::ZoneBuilderBase *m_zoneBuilder; + PrimitivesTreeModel *m_primitivesTreeModel; +}; + +} /* namespace WorldEditor */ + +#endif // PRIMITIVES_VIEW_H 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..42e921106 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/project_settings_dialog.cpp @@ -0,0 +1,68 @@ +// 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 "world_editor_misc.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include +#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); + m_ui.contextComboBox->addItem("empty"); + + // Init the combo box + const std::vector &contexts = Utils::ligoConfig()->getContextString(); + for (uint i = 0; i < contexts.size(); i++) + m_ui.contextComboBox->addItem(QString(contexts[i].c_str())); + + 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/property_editor_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.cpp new file mode 100644 index 000000000..d015adaf1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.cpp @@ -0,0 +1,434 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 "property_editor_widget.h" +#include "world_editor_misc.h" + +// NeL includes +#include + +// STL includes +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +PropertyEditorWidget::PropertyEditorWidget(QWidget *parent) + : QWidget(parent) +{ + m_ui.setupUi(this); + + m_stringManager = new QtStringPropertyManager(this); + m_boolManager = new QtBoolPropertyManager(this); + m_enumManager = new QtEnumPropertyManager(this); + m_stringArrayManager = new QtTextPropertyManager(this); + + QtLineEditFactory *lineEditFactory = new QtLineEditFactory(this); + QtCheckBoxFactory *boolFactory = new QtCheckBoxFactory(this); + QtEnumEditorFactory *enumFactory = new QtEnumEditorFactory(this); + QtTextEditorFactory *textFactory = new QtTextEditorFactory(this); + + m_ui.treePropertyBrowser->setFactoryForManager(m_stringManager, lineEditFactory); + m_ui.treePropertyBrowser->setFactoryForManager(m_boolManager, boolFactory); + m_ui.treePropertyBrowser->setFactoryForManager(m_enumManager, enumFactory); + m_ui.treePropertyBrowser->setFactoryForManager(m_stringArrayManager, textFactory); + + m_groupManager = new QtGroupPropertyManager(this); + + connect(m_stringManager, SIGNAL(propertyChanged(QtProperty *)), this, SLOT(propertyChanged(QtProperty *))); + connect(m_boolManager, SIGNAL(propertyChanged(QtProperty *)), this, SLOT(propertyChanged(QtProperty *))); + connect(m_enumManager, SIGNAL(propertyChanged(QtProperty *)), this, SLOT(propertyChanged(QtProperty *))); + connect(m_stringArrayManager, SIGNAL(propertyChanged(QtProperty *)), this, SLOT(propertyChanged(QtProperty *))); + + connect(m_boolManager, SIGNAL(resetProperty(QtProperty *)), this, SLOT(resetProperty(QtProperty *))); + connect(m_stringManager, SIGNAL(resetProperty(QtProperty *)), this, SLOT(resetProperty(QtProperty *))); + connect(m_enumManager, SIGNAL(resetProperty(QtProperty *)), this, SLOT(resetProperty(QtProperty *))); + connect(m_stringArrayManager, SIGNAL(resetProperty(QtProperty *)), this, SLOT(resetProperty(QtProperty *))); +} + +PropertyEditorWidget::~PropertyEditorWidget() +{ +} + +void PropertyEditorWidget::clearProperties() +{ + m_ui.treePropertyBrowser->clear(); +} + +void PropertyEditorWidget::updateSelection(Node *node) +{ + clearProperties(); + + if ((node == 0) || (node->type() != Node::PrimitiveNodeType)) + return; + + blockSignalsOfProperties(true); + + // The parameter list + std::list parameterList; + + PrimitiveNode *primNode = static_cast(node); + const NLLIGO::IPrimitive *primitive = primNode->primitive(); + const NLLIGO::CPrimitiveClass *primClass = primNode->primitiveClass(); + + // Use the class or not ? + if (primClass) + { + // For each properties of the class + for (uint p = 0; p < primClass->Parameters.size(); p++) + { + // Is the parameter visible ? + if (primClass->Parameters[p].Visible) + { + if (primClass->Parameters[p].Name == "name") + parameterList.push_front(primClass->Parameters[p]); + else + parameterList.push_back(primClass->Parameters[p]); + } + } + } + else + { + // For each primitive property + uint numProp = primitive->getNumProperty(); + for (uint p = 0; p < numProp; p++) + { + // Get the property + std::string propertyName; + const NLLIGO::IProperty *prop; + nlverify(primitive->getProperty(p, propertyName, prop)); + + // Add a default property + NLLIGO::CPrimitiveClass::CParameter defProp(*prop, propertyName.c_str()); + + if (defProp.Name == "name") + parameterList.push_front(defProp); + else + parameterList.push_back(defProp); + } + } + + // Remove property class + std::list::iterator ite = parameterList.begin (); + while (ite != parameterList.end ()) + { + std::list::iterator next = ite; + next++; + if (ite->Name == "class") + { + parameterList.erase(ite); + } + ite = next; + } + + QtProperty *groupNode; + groupNode = m_groupManager->addProperty(QString("%1(%2)").arg(node->data(Qt::DisplayRole).toString()).arg(primClass->Name.c_str())); + m_ui.treePropertyBrowser->addProperty(groupNode); + + ite = parameterList.begin(); + while (ite != parameterList.end()) + { + NLLIGO::CPrimitiveClass::CParameter ¶meter = (*ite); + QtProperty *prop; + NLLIGO::IProperty *ligoProperty = 0; + primitive->getPropertyByName(parameter.Name.c_str(), ligoProperty); + + if (parameter.Type == NLLIGO::CPrimitiveClass::CParameter::ConstString) + prop = addConstStringProperty(ligoProperty, parameter, primitive); + else if (parameter.Type == NLLIGO::CPrimitiveClass::CParameter::String) + prop = addStringProperty(ligoProperty, parameter, primitive); + else if (parameter.Type == NLLIGO::CPrimitiveClass::CParameter::StringArray) + prop = addStringArrayProperty(ligoProperty, parameter, primitive); + else if (parameter.Type == NLLIGO::CPrimitiveClass::CParameter::ConstStringArray) + prop = addConstStringArrayProperty(ligoProperty, parameter, primitive); + else + prop = addBoolProperty(ligoProperty, parameter, primitive); + + // Default value ? + if ((ligoProperty == NULL) || (ligoProperty->Default)) + prop->setModified(false); + else + prop->setModified(true); + + bool staticChildSelected = Utils::ligoConfig()->isStaticChild(*primitive); + if (parameter.ReadOnly || (staticChildSelected && (parameter.Name == "name"))) + prop->setEnabled(false); + + // File ? + if (parameter.Filename && (parameter.FileExtension.empty() || parameter.Type != NLLIGO::CPrimitiveClass::CParameter::StringArray)) + { + // TODO: Create an edit box + // CHECK: only for ConstString + } + + groupNode->addSubProperty(prop); + + ite++; + } + + blockSignalsOfProperties(false); +} + +void PropertyEditorWidget::propertyChanged(QtProperty *property) +{ + nlinfo(QString("property %1 changed").arg(property->propertyName()).toStdString().c_str()); +} + +void PropertyEditorWidget::resetProperty(QtProperty *property) +{ + nlinfo(QString("property %1 reset").arg(property->propertyName()).toStdString().c_str()); +} + +QtProperty *PropertyEditorWidget::addBoolProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive) +{ + std::string value; + std::string name = parameter.Name.c_str(); + primitive->getPropertyByName(name.c_str(), value); + QtProperty *prop = m_boolManager->addProperty(name.c_str()); + // if (Default) + { + //DialogProperties->setDefaultValue (this, value); + m_boolManager->setValue(prop, bool((value=="true")?1:0)); + } + return prop; +} + +QtProperty *PropertyEditorWidget::addConstStringProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive) +{ + std::string value; + std::string name = parameter.Name.c_str(); + + // Get current value + primitive->getPropertyByName(name.c_str(), value); + + // Create qt property + QtProperty *prop = m_enumManager->addProperty(parameter.Name.c_str()); + + QStringList listEnums = getComboValues(parameter); + + if (listEnums.isEmpty()) + { + listEnums << QString(value.c_str()) + tr(" (WRN: Check leveldesign!)"); + m_enumManager->setEnumNames(prop, listEnums); + m_enumManager->setValue(prop, 0); + prop->setEnabled(false); + } + else + { + // TODO: check this logic + if (parameter.DefaultValue.empty() || (parameter.DefaultValue[0].Name.empty())) + listEnums.prepend(""); + + // Fill qt property + m_enumManager->setEnumNames(prop, listEnums); + + // Find index of current value + for (int i = 0; i < listEnums.size(); i++) + { + if (value == listEnums[i].toStdString()) + { + m_enumManager->setValue(prop, i); + break; + } + } + } + + return prop; +} + +QtProperty *PropertyEditorWidget::addStringProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive) +{ + std::string value; + std::string name = parameter.Name.c_str(); + primitive->getPropertyByName(name.c_str(), value); + QtProperty *prop = m_stringManager->addProperty(parameter.Name.c_str()); + m_stringManager->setValue(prop, QString(value.c_str())); + return prop; +} + +QtProperty *PropertyEditorWidget::addStringArrayProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive) +{ + std::string name = parameter.Name.c_str(); + QtProperty *prop = m_stringArrayManager->addProperty(parameter.Name.c_str()); + + const NLLIGO::IProperty *ligoProperty; + std::vector vectString; + + if (primitive->getPropertyByName(parameter.Name.c_str (), ligoProperty)) + { + const NLLIGO::CPropertyStringArray *const propStringArray = dynamic_cast (ligoProperty); + if (propStringArray) + { + const std::vector &vectString = propStringArray->StringArray; + if (!vectString.empty()) + { + std::string temp; + for (size_t i = 0; i < vectString.size(); i++) + { + temp += vectString[i]; + if (i != (vectString.size() - 1)) + temp += '\n'; + } + m_stringArrayManager->setValue(prop, temp.c_str()); + prop->setToolTip(temp.c_str()); + } + } + else + { + m_stringArrayManager->setValue(prop, "StringArray :("); + } + } + + // Create an "EDIT" button if the text is editable (FileExtension != "") + if (parameter.FileExtension != "") + { + // Create an edit box + // TODO: + } + return prop; +} + +QtProperty *PropertyEditorWidget::addConstStringArrayProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive) +{ + std::string value; + std::string name = parameter.Name.c_str(); + + // Get current value + primitive->getPropertyByName(name.c_str(), value); + + // Create qt property +// QtProperty *prop = m_enumManager->addProperty(parameter.Name.c_str()); + QtProperty *prop = m_stringArrayManager->addProperty(parameter.Name.c_str()); + + QStringList listEnums = getComboValues(parameter); + + if (listEnums.isEmpty()) + { +// listEnums << QString(value.c_str()) + tr(" (WRN: Check leveldesign!)"); +// m_enumManager->setEnumNames(prop, listEnums); +// m_enumManager->setValue(prop, 0); + prop->setEnabled(false); + } + else + { + // Fill qt property + m_enumManager->setEnumNames(prop, listEnums); + + // Find index of current value + //for (int i = 0; i < listEnums.size(); i++) + //{ + // if (value == listEnums[i].toStdString()) + // { + // m_enumManager->setValue(prop, i); + // break; + // } + //} + + const NLLIGO::IProperty *ligoProperty; + std::vector vectString; + + if (primitive->getPropertyByName (parameter.Name.c_str(), ligoProperty)) + { + const NLLIGO::CPropertyStringArray *const propStringArray = dynamic_cast (ligoProperty); + if (propStringArray) + { + const std::vector &vectString = propStringArray->StringArray; + if (!vectString.empty()) + { + std::string temp; + for (size_t i = 0; i < vectString.size(); i++) + { + temp += vectString[i]; + if (i != (vectString.size() - 1)) + temp += '\n'; + } + m_stringArrayManager->setValue(prop, temp.c_str()); + prop->setToolTip(temp.c_str()); + } + } + else + { + m_stringArrayManager->setValue(prop, "StringArray :("); + } + } + + m_enumManager->setValue(prop, 0); + } + + return prop; +} + +QStringList PropertyEditorWidget::getComboValues(const NLLIGO::CPrimitiveClass::CParameter ¶meter) +{ + // TODO: get context value from dialog + std::string context("jungle"); + std::string defaultContext("default"); + + std::vector listContext; + + if (context != defaultContext) + listContext.push_back(context); + listContext.push_back(defaultContext); + + QStringList listEnums; + + // Correct fill properties with *both* contexts if the current context is not default and is valid. + for (size_t j = 0; j < listContext.size(); j++) + { + std::map::const_iterator ite = parameter.ComboValues.find(listContext[j].c_str()); + + if (ite != parameter.ComboValues.end()) + { + std::vector pathList; + + // Fill pathList + ite->second.appendFilePath(pathList); + + if (parameter.SortEntries) + std::sort(pathList.begin(), pathList.end()); + + for (size_t i = 0; i < pathList.size(); ++i) + listEnums.append(pathList[i].c_str()); + } + } + + return listEnums; +} + +void PropertyEditorWidget::blockSignalsOfProperties(bool block) +{ + m_stringManager->blockSignals(block); + m_boolManager->blockSignals(block); + m_enumManager->blockSignals(block); + m_stringArrayManager->blockSignals(block); +} +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.h new file mode 100644 index 000000000..85935cccd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.h @@ -0,0 +1,92 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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 PROPERTY_EDITOR_WIDGET_H +#define PROPERTY_EDITOR_WIDGET_H + +// Project includes +#include "ui_property_editor_widget.h" +#include "primitives_model.h" +#include "primitive_item.h" + + +// 3rdparty +#include "qtvariantproperty.h" +#include "qtpropertymanager.h" +#include "qteditorfactory.h" + +// NeL includes + +// Qt includes + +namespace WorldEditor +{ +/** +@class PropertyEditorWidget +@brief PropertyEditorWidget +@details +*/ +class PropertyEditorWidget: public QWidget +{ + Q_OBJECT + +public: + explicit PropertyEditorWidget(QWidget *parent = 0); + ~PropertyEditorWidget(); + +public Q_SLOTS: + void clearProperties(); + + /// Update of selections + void updateSelection(Node *node); + + void propertyChanged(QtProperty *property); + void resetProperty(QtProperty *property); + +private: + QtProperty *addBoolProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive); + QtProperty *addConstStringProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive); + QtProperty *addStringProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive); + QtProperty *addStringArrayProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive); + QtProperty *addConstStringArrayProperty(const NLLIGO::IProperty *property, + const NLLIGO::CPrimitiveClass::CParameter ¶meter, + const NLLIGO::IPrimitive *primitive); + + QStringList getComboValues(const NLLIGO::CPrimitiveClass::CParameter ¶meter); + + void blockSignalsOfProperties(bool block); + + QtBoolPropertyManager *m_boolManager; + QtStringPropertyManager *m_stringManager; + QtEnumPropertyManager *m_enumManager; + QtGroupPropertyManager *m_groupManager; + QtTextPropertyManager *m_stringArrayManager; + + Ui::PropertyEditorWidget m_ui; +}; /* PropertyEditorWidget */ + +} /* namespace WorldEditor */ + +#endif // PROPERTY_EDITOR_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.ui new file mode 100644 index 000000000..a703c7aac --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/property_editor_widget.ui @@ -0,0 +1,40 @@ + + + PropertyEditorWidget + + + + 0 + 0 + 183 + 128 + + + + Form + + + + 3 + + + 3 + + + + + + + + + QtTreePropertyBrowser + QWidget +
qttreepropertybrowser.h
+ 1 +
+
+ + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc new file mode 100644 index 000000000..02ffcbe00 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc @@ -0,0 +1,10 @@ + + + icons/ic_nel_select.png + icons/ic_nel_scale.png + icons/ic_nel_rotate.png + icons/ic_nel_move.png + icons/ic_nel_turn.png + icons/ic_nel_world_editor.png + + 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 new file mode 100644 index 000000000..0f9d91ef2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp @@ -0,0 +1,791 @@ +// 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_actions.h" +#include "world_editor_constants.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" + +// STL includes +#include + +// NeL includes +#include +#include +#include +#include +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ + +QGraphicsItem *getGraphicsItem(Node *node) +{ + QGraphicsItem *result = 0; + if (node->type() == Node::PrimitiveNodeType) + { + PrimitiveNode *primitiveNode = static_cast(node); + if (primitiveNode != 0) + { + switch (primitiveNode->primitiveClass()->Type) + { + case NLLIGO::CPrimitiveClass::Point: + case NLLIGO::CPrimitiveClass::Path: + case NLLIGO::CPrimitiveClass::Zone: + { + result = qvariant_cast(primitiveNode->data(Constants::GRAPHICS_DATA_QT4_2D)); + break; + } + } + } + } + return result; +} + +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; + AbstractWorldItem *item = 0; + + // Draw arrow ? + bool showArrow = node->primitiveClass()->ShowArrow; + + switch (node->primitiveClass()->Type) + { + case NLLIGO::CPrimitiveClass::Point: + { + vec = primitive->getPrimVector(); + NLLIGO::CPrimPoint *primPoint = static_cast(primitive); + + // Have a radius ? + std::string strRadius; + qreal radius = 0; + if (primitive->getPropertyByName ("radius", strRadius)) + radius = atof(strRadius.c_str()); + qreal angle = ((2 * NLMISC::Pi - primPoint->Angle) * 180 / NLMISC::Pi); + item = scene->addWorldItemPoint(QPointF(vec->x, -vec->y + cellSize), + angle, radius, showArrow); + 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, showArrow); + 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, cellSize - vec->y); + ++vec; + } + item = scene->addWorldItemZone(polygon); + break; + } + } + + if (item != 0) + { + // Get color from world_editor_classes.xml + NLMISC::CRGBA color = Utils::ligoConfig()->getPrimitiveColor(*primitive); + primitive->getPropertyByName ("Color", color); + item->setColor(QColor(color.R, color.G, color.B)); + + QVariant variantNode; + variantNode.setValue(node); + item->setData(Constants::WORLD_EDITOR_NODE, variantNode); + + QVariant graphicsData; + graphicsData.setValue(item); + node->setData(Constants::GRAPHICS_DATA_QT4_2D, graphicsData); + + QVariant persistenVariant; + QPersistentModelIndex *persistentIndex = new QPersistentModelIndex(primIndex); + persistenVariant.setValue(persistentIndex); + item->setData(Constants::NODE_PERISTENT_INDEX, persistenVariant); + } + } + + 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) +{ + Node *node = static_cast(primIndex.internalPointer()); + + if (node != 0) + { + QGraphicsItem *item = getGraphicsItem(node); + if (item != 0) + { + delete qvariant_cast(item->data(Constants::NODE_PERISTENT_INDEX)); + scene->removeWorldItem(item); + } + } + + int count = model->rowCount(primIndex); + for (int i = 0; i < count; ++i) + { + removeGraphicsItems(primIndex.child(i, 0), model, scene); + } +} + +QList polygonsFromItems(const QList &items) +{ + QList result; + Q_FOREACH(QGraphicsItem *item, items) + { + AbstractWorldItem *worldItem = qgraphicsitem_cast(item); + result.push_back(worldItem->polygon()); + } + return result; +} + +CreateWorldCommand::CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText(QObject::tr("Create new world")); +} + +CreateWorldCommand::~CreateWorldCommand() +{ +} + +void CreateWorldCommand::undo() +{ + m_model->deleteWorldEditNode(); +} + +void CreateWorldCommand::redo() +{ + m_model->createWorldEditNode(m_fileName); +} + +LoadLandscapeCommand::LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent) + : QUndoCommand(parent), + m_id(-1), + m_fileName(fileName), + m_model(model), + m_zoneBuilder(zoneBuilder) +{ + setText(QObject::tr("Load land file")); +} + +LoadLandscapeCommand::~LoadLandscapeCommand() +{ +} + +void LoadLandscapeCommand::undo() +{ + m_zoneBuilder->deleteZoneRegion(m_id); + m_model->deleteNode(landIndex); +} + +void LoadLandscapeCommand::redo() +{ + if (m_id == -1) + m_id = m_zoneBuilder->loadZoneRegion(m_fileName); + else + m_zoneBuilder->loadZoneRegion(m_fileName, m_id); + + landIndex = m_model->createLandscapeNode(m_fileName, m_id); +} + + +UnloadLandscapeCommand::UnloadLandscapeCommand(const QModelIndex &index, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent) + : QUndoCommand(parent), + m_model(model), + m_zoneBuilder(zoneBuilder) +{ + setText(QObject::tr("Unload land file")); + m_path = m_model->pathFromIndex(index); +} + +UnloadLandscapeCommand::~UnloadLandscapeCommand() +{ +} + +void UnloadLandscapeCommand::undo() +{ + m_zoneBuilder->loadZoneRegion(m_fileName, m_id); + + m_model->createLandscapeNode(m_fileName, m_id, m_path.back().first); +} + +void UnloadLandscapeCommand::redo() +{ + QModelIndex index = m_model->pathToIndex(m_path); + LandscapeNode *node = static_cast(index.internalPointer()); + + m_id = node->id(); + m_fileName = node->fileName(); + + m_zoneBuilder->deleteZoneRegion(m_id); + m_model->deleteNode(m_path); +} + +CreateRootPrimitiveCommand::CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText(QObject::tr("Create new primitive")); +} + +CreateRootPrimitiveCommand::~CreateRootPrimitiveCommand() +{ +} + +void CreateRootPrimitiveCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void CreateRootPrimitiveCommand::redo() +{ + NLLIGO::CPrimitives *newRootPrim = new NLLIGO::CPrimitives(); + m_rootPrimIndex = m_model->createRootPrimitiveNode("", newRootPrim); +} + + +LoadRootPrimitiveCommand::LoadRootPrimitiveCommand(const QString &fileName, WorldEditorScene *scene, + PrimitivesTreeModel *model, QTreeView *view, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_scene(scene), + m_model(model), + m_view(view) +{ + setText(QObject::tr("Load primitive file")); +} + +LoadRootPrimitiveCommand::~LoadRootPrimitiveCommand() +{ +} + +void LoadRootPrimitiveCommand::undo() +{ + // Disable edit points mode + m_scene->setEnabledEditPoints(false); + + m_view->selectionModel()->clearSelection(); + + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + removeGraphicsItems(index, m_model, m_scene); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void LoadRootPrimitiveCommand::redo() +{ + m_scene->setEnabledEditPoints(false); + + NLLIGO::CPrimitives *primitives = new NLLIGO::CPrimitives(); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = primitives; + + NLLIGO::loadXmlPrimitiveFile(*primitives, m_fileName.toStdString(), *Utils::ligoConfig()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + + // Initialize default values + Utils::recursiveUpdateDefaultValues(primitives->RootNode); + + // Check property types + if (Utils::recursiveUpdateDefaultValues(primitives->RootNode)) + { + nlwarning("In file (%s) : Some primitives have been modified to initialise their default values\nor to change their properties type.", m_fileName.toStdString().c_str()); + } + + m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, primitives); + + addNewGraphicsItems(m_model->pathToIndex(m_rootPrimIndex), m_model, m_scene); +} + + +UnloadRootPrimitiveCommand::UnloadRootPrimitiveCommand(const QModelIndex &index, WorldEditorScene *scene, + PrimitivesTreeModel *model, QTreeView *view, QUndoCommand *parent) + : QUndoCommand(parent), + m_scene(scene), + m_model(model), + m_view(view) +{ + setText(QObject::tr("Unload primitive file")); + m_path = m_model->pathFromIndex(index); +} + +UnloadRootPrimitiveCommand::~UnloadRootPrimitiveCommand() +{ +} + +void UnloadRootPrimitiveCommand::undo() +{ + // Disable edit points mode + m_scene->setEnabledEditPoints(false); + + m_path = m_model->createRootPrimitiveNode(m_fileName, m_primitives, m_path.back().first); + + addNewGraphicsItems(m_model->pathToIndex(m_path), m_model, m_scene); +} + +void UnloadRootPrimitiveCommand::redo() +{ + m_scene->setEnabledEditPoints(false); + + m_view->selectionModel()->clearSelection(); + QModelIndex index = m_model->pathToIndex(m_path); + RootPrimitiveNode *node = static_cast(index.internalPointer()); + m_fileName = node->fileName(); + m_primitives = node->primitives(); + + removeGraphicsItems(index, m_model, m_scene); + + m_model->deleteNode(m_path); +} + +AddPrimitiveByClassCommand::AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + WorldEditorScene *scene, PrimitivesTreeModel *model, QTreeView *view, QUndoCommand *parent) + : QUndoCommand(parent), + m_className(className), + m_parentIndex(parentIndex), + m_scene(scene), + m_model(model), + m_view(view) +{ + setText(QObject::tr("Add %1").arg(m_className)); + + QGraphicsView *graphicsView = m_scene->views().first(); + + // TODO: returns incorrect position when zoom in + QRectF visibleArea = graphicsView->mapToScene(view->rect()).boundingRect(); + m_delta = visibleArea.height() / 10.0; + m_initPos = visibleArea.center(); +} + +AddPrimitiveByClassCommand::~AddPrimitiveByClassCommand() +{ +} + +void AddPrimitiveByClassCommand::undo() +{ + m_scene->setEnabledEditPoints(false); + + m_view->selectionModel()->clearSelection(); + + QModelIndex index = m_model->pathToIndex(m_newPrimIndex); + PrimitiveNode *node = static_cast(index.internalPointer()); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = node->rootPrimitiveNode()->primitives(); + + removeGraphicsItems(index, m_model, m_scene); + + Utils::deletePrimitive(node->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_model->deleteNode(m_newPrimIndex); +} + +void AddPrimitiveByClassCommand::redo() +{ + m_scene->setEnabledEditPoints(false); + + QModelIndex parentIndex = m_model->pathToIndex(m_parentIndex); + PrimitiveNode *parentNode = static_cast(parentIndex.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = parentNode->primitiveClass(); + + int id = 0; + while (primClass->DynamicChildren[id].ClassName != m_className.toStdString()) + ++id; + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = parentNode->rootPrimitiveNode()->primitives(); + + QString namePrimititve = QString("%1_%2").arg(m_className).arg(parentNode->childCount()); + NLLIGO::IPrimitive *newPrimitive = Utils::createPrimitive(m_className.toStdString().c_str(), namePrimititve.toStdString().c_str(), + NLMISC::CVector(m_initPos.x(), -m_initPos.y(), 0.0), m_delta, primClass->DynamicChildren[id].Parameters, parentNode->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_newPrimIndex = m_model->createPrimitiveNode(newPrimitive, m_parentIndex); + + addNewGraphicsItems(m_model->pathToIndex(m_newPrimIndex), m_model, m_scene); +} + +DeletePrimitiveCommand::DeletePrimitiveCommand(const QModelIndex &index, PrimitivesTreeModel *model, + WorldEditorScene *scene, QTreeView *view, QUndoCommand *parent) + : QUndoCommand(parent), + m_scene(scene), + m_model(model), + m_view(view) +{ + setText(QObject::tr("Delete primitive")); + + // Save path to primitive + m_path = m_model->pathFromIndex(index); + m_parentPath = m_model->pathFromIndex(index.parent()); + + PrimitiveNode *node = static_cast(index.internalPointer()); + + NLLIGO::IPrimitive *primitive = node->primitive(); + + // Backup primitive + m_oldPrimitive = primitive->copy(); + + // Backup position primitive + primitive->getParent()->getChildId(m_posPrimitive, primitive); +} + +DeletePrimitiveCommand::~DeletePrimitiveCommand() +{ + delete m_oldPrimitive; +} + +void DeletePrimitiveCommand::undo() +{ + m_scene->setEnabledEditPoints(false); + m_view->selectionModel()->clearSelection(); + + QModelIndex parentIndex = m_model->pathToIndex(m_parentPath); + PrimitiveNode *parentNode = static_cast(parentIndex.internalPointer()); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = parentNode->rootPrimitiveNode()->primitives(); + + NLLIGO::IPrimitive *newPrimitive = m_oldPrimitive->copy(); + if (!parentNode->primitive()->insertChild(newPrimitive, m_posPrimitive)) + nlerror("Primitive can't insert, m_posPrimitive is not a valid."); + + // Insert primitive node in tree model + Path newPath = m_model->createPrimitiveNode(newPrimitive, m_parentPath, m_path.back().first); + + // Scan graphics model + addNewGraphicsItems(m_model->pathToIndex(newPath), m_model, m_scene); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; +} + +void DeletePrimitiveCommand::redo() +{ + m_scene->setEnabledEditPoints(false); + m_view->selectionModel()->clearSelection(); + + QModelIndex index = m_model->pathToIndex(m_path); + PrimitiveNode *node = static_cast(index.internalPointer()); + NLLIGO::IPrimitive *primitive = node->primitive(); + + // Removes all graphics items + removeGraphicsItems(index, m_model, m_scene); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = node->rootPrimitiveNode()->primitives(); + + // Delete primitive + Utils::deletePrimitive(primitive); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + // Remove primitive from tree model + m_model->deleteNode(m_path); +} + +AbstractWorldItemCommand::AbstractWorldItemCommand(const QList &items, + WorldEditorScene *scene, + PrimitivesTreeModel *model, + QUndoCommand *parent) + : QUndoCommand(parent), + m_listPaths(graphicsItemsToPaths(items, model)), + m_model(model), + m_scene(scene), + m_firstRun(true) +{ +} + +AbstractWorldItemCommand::~AbstractWorldItemCommand() +{ +} + +void AbstractWorldItemCommand::undo() +{ + bool pointsMode = m_scene->isEnabledEditPoints(); + m_scene->setEnabledEditPoints(false); + for (int i = 0; i < m_listPaths.count(); ++i) + { + Node *node = m_model->pathToNode(m_listPaths.at(i)); + AbstractWorldItem *item = qvariant_cast(node->data(Constants::GRAPHICS_DATA_QT4_2D)); + undoChangeItem(i, item); + updatePrimitiveData(item); + } + m_scene->setEnabledEditPoints(pointsMode); +} + +void AbstractWorldItemCommand::redo() +{ + if (!m_firstRun) + { + bool pointsMode = m_scene->isEnabledEditPoints(); + m_scene->setEnabledEditPoints(false); + for (int i = 0; i < m_listPaths.count(); ++i) + { + Node *node = m_model->pathToNode(m_listPaths.at(i)); + AbstractWorldItem *item = qvariant_cast(node->data(Constants::GRAPHICS_DATA_QT4_2D)); + redoChangeItem(i, item); + updatePrimitiveData(item); + } + m_scene->setEnabledEditPoints(pointsMode); + } + else + { + for (int i = 0; i < m_listPaths.count(); ++i) + { + Node *node = m_model->pathToNode(m_listPaths.at(i)); + AbstractWorldItem *item = qvariant_cast(node->data(Constants::GRAPHICS_DATA_QT4_2D)); + updatePrimitiveData(item); + } + } + + m_firstRun = false; +} + +void AbstractWorldItemCommand::updatePrimitiveData(AbstractWorldItem *item) +{ + float cellSize = Utils::ligoConfig()->CellSize; + Node *node = qvariant_cast(item->data(Constants::WORLD_EDITOR_NODE)); + PrimitiveNode *primitiveNode = static_cast(node); + if (primitiveNode != 0) + { + NLLIGO::IPrimitive *primitive = primitiveNode->primitive(); + + std::vector vPoints; + QPolygonF polygon = item->polygon(); + polygon.translate(item->pos()); + + for (int i = 0; i < polygon.size(); ++i) + { + NLMISC::CVector vec(polygon.at(i).x(), cellSize - polygon.at(i).y(), 0.0); + vPoints.push_back(NLLIGO::CPrimVector(vec)); + } + + switch (primitiveNode->primitiveClass()->Type) + { + case NLLIGO::CPrimitiveClass::Point: + { + qreal angle = static_cast(item)->angle(); + angle = 2 * NLMISC::Pi - (angle * NLMISC::Pi / 180.0); + NLLIGO::CPrimPoint *point = static_cast(primitive); + point->Point = vPoints.front(); + point->Angle = angle; + break; + } + case NLLIGO::CPrimitiveClass::Path: + { + NLLIGO::CPrimPath *path = static_cast(primitive); + path->VPoints = vPoints; + break; + } + case NLLIGO::CPrimitiveClass::Zone: + { + NLLIGO::CPrimZone *zone = static_cast(primitive); + zone->VPoints = vPoints; + break; + } + } + } +} + +QList AbstractWorldItemCommand::graphicsItemsToPaths(const QList &items, PrimitivesTreeModel *model) +{ + QList result; + Q_FOREACH(QGraphicsItem *item, items) + { + Node *node = qvariant_cast(item->data(Constants::WORLD_EDITOR_NODE)); + result.push_back(model->pathFromNode(node)); + } + return result; +} + +MoveWorldItemsCommand::MoveWorldItemsCommand(const QList &items, const QPointF &offset, + WorldEditorScene *scene, PrimitivesTreeModel *model, QUndoCommand *parent) + : AbstractWorldItemCommand(items, scene, model, parent), + m_offset(offset) +{ + setText(QObject::tr("Move item(s)")); +} + +MoveWorldItemsCommand::~MoveWorldItemsCommand() +{ +} + +void MoveWorldItemsCommand::undoChangeItem(int i, AbstractWorldItem *item) +{ + item->moveBy(-m_offset.x(), -m_offset.y()); +} + +void MoveWorldItemsCommand::redoChangeItem(int i, AbstractWorldItem *item) +{ + item->moveBy(m_offset.x(), m_offset.y()); +} + +RotateWorldItemsCommand::RotateWorldItemsCommand(const QList &items, const qreal angle, + const QPointF &pivot, WorldEditorScene *scene, PrimitivesTreeModel *model, QUndoCommand *parent) + : AbstractWorldItemCommand(items, scene, model, parent), + m_angle(angle), + m_pivot(pivot) +{ + setText(QObject::tr("Rotate item(s)")); +} + +RotateWorldItemsCommand::~RotateWorldItemsCommand() +{ +} + +void RotateWorldItemsCommand::undoChangeItem(int i, AbstractWorldItem *item) +{ + item->rotateOn(m_pivot, -m_angle); +} + +void RotateWorldItemsCommand::redoChangeItem(int i, AbstractWorldItem *item) +{ + item->rotateOn(m_pivot, m_angle); +} + +ScaleWorldItemsCommand::ScaleWorldItemsCommand(const QList &items, const QPointF &factor, + const QPointF &pivot, WorldEditorScene *scene, PrimitivesTreeModel *model, QUndoCommand *parent) + : AbstractWorldItemCommand(items, scene, model, parent), + m_factor(factor), + m_pivot(pivot) +{ + setText(QObject::tr("Scale item(s)")); +} + +ScaleWorldItemsCommand::~ScaleWorldItemsCommand() +{ +} + +void ScaleWorldItemsCommand::undoChangeItem(int i, AbstractWorldItem *item) +{ + QPointF m_invertFactor(1 / m_factor.x(), 1 / m_factor.y()); + item->scaleOn(m_pivot, m_invertFactor); +} + +void ScaleWorldItemsCommand::redoChangeItem(int i, AbstractWorldItem *item) +{ + item->scaleOn(m_pivot, m_factor); +} + +TurnWorldItemsCommand::TurnWorldItemsCommand(const QList &items, const qreal angle, + WorldEditorScene *scene, PrimitivesTreeModel *model, QUndoCommand *parent) + : AbstractWorldItemCommand(items, scene, model, parent), + m_angle(angle) +{ + setText(QObject::tr("Turn item(s)")); +} + +TurnWorldItemsCommand::~TurnWorldItemsCommand() +{ +} + +void TurnWorldItemsCommand::undoChangeItem(int i, AbstractWorldItem *item) +{ + item->turnOn(-m_angle); +} + +void TurnWorldItemsCommand::redoChangeItem(int i, AbstractWorldItem *item) +{ + item->turnOn(m_angle); +} + +ShapeWorldItemsCommand::ShapeWorldItemsCommand(const QList &items, const QList &polygons, + WorldEditorScene *scene, PrimitivesTreeModel *model, + QUndoCommand *parent) + : AbstractWorldItemCommand(items, scene, model, parent), + m_redoPolygons(polygons), + m_undoPolygons(polygonsFromItems(items)) +{ + setText(QObject::tr("Change shape")); +} + +ShapeWorldItemsCommand::~ShapeWorldItemsCommand() +{ +} + +void ShapeWorldItemsCommand::undoChangeItem(int i, AbstractWorldItem *item) +{ + item->setPolygon(m_redoPolygons.at(i)); +} + +void ShapeWorldItemsCommand::redoChangeItem(int i, AbstractWorldItem *item) +{ + item->setPolygon(m_undoPolygons.at(i)); +} + +} /* namespace WorldEditor */ 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 new file mode 100644 index 000000000..89de14e9a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h @@ -0,0 +1,388 @@ +// 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_ACTIONS_H +#define WORLD_EDITOR_ACTIONS_H + +// Project includes +#include "primitives_model.h" + +// NeL includes + +// Qt includes +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ +class WorldEditorScene; +class AbstractWorldItem; + +// Auxiliary operations + +// Return QGraphicsItem if node contains it +QGraphicsItem *getGraphicsItem(Node *node); + +// Scan primitives model for create/add necessary QGraphicsItems +void addNewGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene); + +// Recursive scan primitives model for delete Graphics Items +void removeGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene); + +QList polygonsFromItems(const QList &items); + + +/** +@class CreateWorldCommand +@brief +@details +*/ +class CreateWorldCommand: public QUndoCommand +{ +public: + CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~CreateWorldCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_fileName; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadLandscapeCommand +@brief +@details +*/ +class LoadLandscapeCommand: public QUndoCommand +{ +public: + LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent = 0); + virtual ~LoadLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path landIndex; + int m_id; + const QString m_fileName; + PrimitivesTreeModel *const m_model; + LandscapeEditor::ZoneBuilderBase *const m_zoneBuilder; +}; + +/** +@class UnloadLandscapeCommand +@brief +@details +*/ +class UnloadLandscapeCommand: public QUndoCommand +{ +public: + UnloadLandscapeCommand(const QModelIndex &index, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent = 0); + virtual ~UnloadLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_path; + int m_id; + QString m_fileName; + PrimitivesTreeModel *const m_model; + LandscapeEditor::ZoneBuilderBase *const m_zoneBuilder; +}; + +/** +@class CreateRootPrimitiveCommand +@brief +@details +*/ +class CreateRootPrimitiveCommand: public QUndoCommand +{ +public: + CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, + QUndoCommand *parent = 0); + virtual ~CreateRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_fileName; + Path m_rootPrimIndex; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadRootPrimitiveCommand +@brief +@details +*/ +class LoadRootPrimitiveCommand: public QUndoCommand +{ +public: + LoadRootPrimitiveCommand(const QString &fileName, WorldEditorScene *scene, + PrimitivesTreeModel *model, QTreeView *view, + QUndoCommand *parent = 0); + virtual ~LoadRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_rootPrimIndex; + const QString m_fileName; + WorldEditorScene *const m_scene; + PrimitivesTreeModel *const m_model; + QTreeView *m_view; +}; + +/** +@class UnloadRootPrimitiveCommand +@brief +@details +*/ +class UnloadRootPrimitiveCommand: public QUndoCommand +{ +public: + UnloadRootPrimitiveCommand(const QModelIndex &index, WorldEditorScene *scene, + PrimitivesTreeModel *model, QTreeView *view, + QUndoCommand *parent = 0); + virtual ~UnloadRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_path; + QString m_fileName; + NLLIGO::CPrimitives *m_primitives; + WorldEditorScene *const m_scene; + PrimitivesTreeModel *const m_model; + QTreeView *m_view; +}; + +/** +@class AddPrimitiveByClassCommand +@brief +@details +*/ +class AddPrimitiveByClassCommand: public QUndoCommand +{ +public: + AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + WorldEditorScene *scene, PrimitivesTreeModel *model, + QTreeView *view, QUndoCommand *parent = 0); + virtual ~AddPrimitiveByClassCommand(); + + virtual void undo(); + virtual void redo(); +private: + + QPointF m_initPos; + float m_delta; + const QString m_className; + Path m_parentIndex, m_newPrimIndex; + WorldEditorScene *const m_scene; + PrimitivesTreeModel *const m_model; + QTreeView *const m_view; +}; + +/** +@class DeletePrimitiveCommand +@brief +@details +*/ +class DeletePrimitiveCommand: public QUndoCommand +{ +public: + DeletePrimitiveCommand(const QModelIndex &index, PrimitivesTreeModel *model, + WorldEditorScene *scene, QTreeView *view, QUndoCommand *parent = 0); + virtual ~DeletePrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_path, m_parentPath; + uint m_posPrimitive; + NLLIGO::IPrimitive *m_oldPrimitive; + WorldEditorScene *const m_scene; + PrimitivesTreeModel *const m_model; + QTreeView *const m_view; +}; + +/** +@class AbstractWorldItemCommand +@brief +@details +*/ +class AbstractWorldItemCommand: public QUndoCommand +{ +public: + AbstractWorldItemCommand(const QList &items, WorldEditorScene *scene, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~AbstractWorldItemCommand(); + + virtual void undo(); + virtual void redo(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item) = 0; + virtual void redoChangeItem(int i, AbstractWorldItem *item) = 0; + void updatePrimitiveData(AbstractWorldItem *item); + +private: + QList graphicsItemsToPaths(const QList &items, PrimitivesTreeModel *model); + + const QList m_listPaths; + PrimitivesTreeModel *const m_model; + WorldEditorScene *const m_scene; + bool m_firstRun; +}; + +/** +@class MoveWorldItemsCommand +@brief +@details +*/ +class MoveWorldItemsCommand: public AbstractWorldItemCommand +{ +public: + MoveWorldItemsCommand(const QList &items, const QPointF &offset, + WorldEditorScene *scene, PrimitivesTreeModel *model, + QUndoCommand *parent = 0); + virtual ~MoveWorldItemsCommand(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item); + virtual void redoChangeItem(int i, AbstractWorldItem *item); + +private: + + const QPointF m_offset; +}; + +/** +@class RotateWorldItemsCommand +@brief +@details +*/ +class RotateWorldItemsCommand: public AbstractWorldItemCommand +{ +public: + RotateWorldItemsCommand(const QList &items, const qreal angle, + const QPointF &pivot, WorldEditorScene *scene, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~RotateWorldItemsCommand(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item); + virtual void redoChangeItem(int i, AbstractWorldItem *item); + +private: + + const qreal m_angle; + const QPointF m_pivot; +}; + +/** +@class ScaleWorldItemsCommand +@brief +@details +*/ +class ScaleWorldItemsCommand: public AbstractWorldItemCommand +{ +public: + ScaleWorldItemsCommand(const QList &items, const QPointF &factor, + const QPointF &pivot, WorldEditorScene *scene, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~ScaleWorldItemsCommand(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item); + virtual void redoChangeItem(int i, AbstractWorldItem *item); + +private: + + const QPointF m_factor; + const QPointF m_pivot; +}; + +/** +@class TurnWorldItemsCommand +@brief +@details +*/ +class TurnWorldItemsCommand: public AbstractWorldItemCommand +{ +public: + TurnWorldItemsCommand(const QList &items, const qreal angle, + WorldEditorScene *scene, PrimitivesTreeModel *model, + QUndoCommand *parent = 0); + virtual ~TurnWorldItemsCommand(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item); + virtual void redoChangeItem(int i, AbstractWorldItem *item); + +private: + + const qreal m_angle; +}; + +/** +@class TurnWorldItemsCommand +@brief +@details +*/ +class ShapeWorldItemsCommand: public AbstractWorldItemCommand +{ +public: + ShapeWorldItemsCommand(const QList &items, const QList &polygons, + WorldEditorScene *scene, PrimitivesTreeModel *model, + QUndoCommand *parent = 0); + virtual ~ShapeWorldItemsCommand(); + +protected: + virtual void undoChangeItem(int i, AbstractWorldItem *item); + virtual void redoChangeItem(int i, AbstractWorldItem *item); + +private: + + const QList m_redoPolygons; + const QList m_undoPolygons; +}; + +} /* namespace WorldEditor */ + +// Enable the use of QVariant with this class. +Q_DECLARE_METATYPE(QPersistentModelIndex *) + +#endif // WORLD_EDITOR_ACTIONS_H 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 new file mode 100644 index 000000000..7ca698697 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h @@ -0,0 +1,64 @@ +// 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_CONSTANTS_H +#define WORLD_EDITOR_CONSTANTS_H + +namespace WorldEditor +{ +namespace Constants +{ +const char *const WORLD_EDITOR_PLUGIN = "WorldEditor"; + +const int USER_TYPE = 65536; +const int NODE_PERISTENT_INDEX = USER_TYPE + 1; +const int WORLD_EDITOR_NODE = USER_TYPE + 2; +const int GRAPHICS_DATA_QT4_2D = USER_TYPE + 3; +const int GRAPHICS_DATA_NEL3D = USER_TYPE + 4; +const int PRIMITIVE_IS_MODIFIED = USER_TYPE + 5; +const int PRIMITIVE_FILE_IS_CREATED = USER_TYPE + 6; +const int PRIMITIVE_IS_VISIBLE = USER_TYPE + 7; +const int PRIMITIVE_IS_ENABLD = USER_TYPE + 8; +const int PRIMITIVE_FILE_NAME = USER_TYPE + 9; +const int PRIMITIVE_NON_REMOVABLE = USER_TYPE + 10; +const int ROOT_PRIMITIVE_CONTEXT = USER_TYPE + 20; +const int ROOT_PRIMITIVE_DATA_DIRECTORY = USER_TYPE + 21; + +//properties editor +const char *const DIFFERENT_VALUE_STRING = ""; +const char *const DIFFERENT_VALUE_MULTI_STRING = ""; + +//settings +const char *const WORLD_EDITOR_SECTION = "WorldEditor"; +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"; + +//resources +const char *const ICON_WORLD_EDITOR = ":/icons/ic_nel_world_editor.png"; +const char *const ICON_ROOT_PRIMITIVE = "./old_ico/root.ico"; +const char *const ICON_PROPERTY = "./old_ico/property.ico"; +const char *const ICON_FOLDER = "./old_ico/folder_h.ico"; +const char *const PATH_TO_OLD_ICONS = "./old_ico"; + +} // namespace Constants +} // namespace WorldEditor + +#endif // WORLD_EDITOR_CONSTANTS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h new file mode 100644 index 000000000..a7a94ca75 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h @@ -0,0 +1,30 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. +// +// 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_GLOBAL_H +#define WORLD_EDITOR_GLOBAL_H + +#include + +#if defined(WORLD_EDITOR_LIBRARY) +# define WORLD_EDITOR_EXPORT Q_DECL_EXPORT +#else +# define WORLD_EDITOR_EXPORT Q_DECL_IMPORT +#endif + +#endif // WORLD_EDITOR_GLOBAL_H 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 new file mode 100644 index 000000000..f9eb7ce54 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp @@ -0,0 +1,666 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// 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_misc.h" + +// NeL includes +#include +#include +#include +#include +#include +#include +#include + + +// Qt includes + +namespace WorldEditor +{ +namespace Utils +{ + +void syntaxError(const char *filename, xmlNodePtr xmlNode, const char *format, ...) +{ + char buffer[1024]; + + if (format) + { + va_list args; + va_start( args, format ); + sint ret = vsnprintf( buffer, 1024, format, args ); + va_end( args ); + } + else + { + strcpy(buffer, "Unknown error"); + } + + nlerror("(%s), node (%s), line (%s) :\n%s", filename, xmlNode->name, xmlNode->content, buffer); +} + +bool getPropertyString(std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName) +{ + // Call the CIXml version + if (!NLMISC::CIXml::getPropertyString(result, xmlNode, propName)) + { + // Output a formated error + syntaxError(filename, xmlNode, "Missing XML node property (%s)", propName); + return false; + } + return true; +} + +uint32 getUniqueId() +{ + // Wait 1 ms + sint64 time = NLMISC::CTime::getLocalTime (); + sint64 time2; + while ((time2 = NLMISC::CTime::getLocalTime ()) == time) + { + } + + return (uint32)time2; +} + +bool loadWorldEditFile(const std::string &fileName, WorldEditList &worldEditList) +{ + bool result = false; + + // Load the document + NLMISC::CIFile file; + if (file.open(fileName)) + { + try + { + // Load the document in XML + NLMISC::CIXml xml; + xml.init(file); + + // Get root node + xmlNodePtr rootNode = xml.getRootNode(); + if (rootNode) + { + // Good header ? + if (strcmp((const char *)(rootNode->name), "NEL_WORLD_EDITOR_PROJECT") == 0) + { + int version = -1; + + // Read the parameters + xmlNodePtr node = NLMISC::CIXml::getFirstChildNode(rootNode, "VERSION"); + if (node) + { + std::string versionString; + if (NLMISC::CIXml::getContentString (versionString, node)) + version = atoi(versionString.c_str ()); + } + + if (version == -1) + syntaxError(fileName.c_str(), rootNode, "No version node"); + else + { + // Old format, + if (version <= 1) + { + syntaxError(fileName.c_str(), rootNode, "Old version node"); + } + else + { + // Read it + if (version > WORLD_EDITOR_FILE_VERSION) + { + syntaxError(fileName.c_str(), node, "Unknown file version"); + } + else + { + // Read data directory + node = NLMISC::CIXml::getFirstChildNode(rootNode, "DATA_DIRECTORY"); + if (node) + { + std::string dataDir; + NLMISC::CIXml::getPropertyString(dataDir, node, "VALUE"); + worldEditList.push_back(WorldEditItem(DataDirectoryType, dataDir)); + } + + // Read data directory + node = NLMISC::CIXml::getFirstChildNode(rootNode, "CONTEXT"); + if (node) + { + std::string context; + NLMISC::CIXml::getPropertyString(context, node, "VALUE"); + worldEditList.push_back(WorldEditItem(ContextType, context)); + } + + // Read the database element + node = NLMISC::CIXml::getFirstChildNode(rootNode, "DATABASE_ELEMENT"); + if (node) + { + do + { + // Get the type + std::string type; + if (getPropertyString(type, fileName.c_str(), node, "TYPE")) + { + // Read the filename + std::string filenameChild; + if (getPropertyString(filenameChild, fileName.c_str(), node, "FILENAME")) + { + // Is it a landscape ? + if (type == "landscape") + { + worldEditList.push_back(WorldEditItem(LandscapeType, filenameChild)); + + // Get the primitives + xmlNodePtr primitives = NLMISC::CIXml::getFirstChildNode(node, "PRIMITIVES"); + if (primitives) + { + NLLIGO::CPrimitives ligoPrimitives; + + // Read it + ligoPrimitives.read(primitives, fileName.c_str(), *ligoConfig()); + //_DataHierarchy.back ().Primitives.read (primitives, filename, theApp.Config); + + // Set the filename + //_DataHierarchy.back ().Filename = filenameChild; + } + } + else + { + worldEditList.push_back(WorldEditItem(PrimitiveType, filenameChild)); + } + + } + } + } + while (node = NLMISC::CIXml::getNextChildNode(node, "DATABASE_ELEMENT")); + } + + // Done + result = true; + } + } + } + } + else + { + // Error + syntaxError(fileName.c_str(), rootNode, "Unknown file header : %s", rootNode->name); + } + } + } + catch (NLMISC::Exception &e) + { + nlerror("Error reading file %s : %s", fileName.c_str(), e.what()); + } + } + else + nlerror("Can't open the file %s for reading.", fileName.c_str()); + + return result; +} + +NLLIGO::IPrimitive *getRootPrimitive(NLLIGO::IPrimitive *primitive) +{ + nlassert(primitive); + + if (primitive->getParent() == NULL) + return primitive; + else + return getRootPrimitive(primitive->getParent()); +} + +void initPrimitiveParameters(const NLLIGO::CPrimitiveClass &primClass, NLLIGO::IPrimitive &primitive, + const std::vector &initParameters) +{ + // Other parameters + for (uint p = 0; p < initParameters.size(); ++p) + { + // The property + const NLLIGO::CPrimitiveClass::CInitParameters ¶meter = initParameters[p]; + + // Look for it in the class + uint cp; + for (cp = 0; cp < primClass.Parameters.size(); ++cp) + { + // Good one ? + if (primClass.Parameters[cp].Name == initParameters[p].Name) + break; + } + + // The primitive type + NLLIGO::CPrimitiveClass::CParameter::TType type; + + // Found ? + if (cp < primClass.Parameters.size()) + type = primClass.Parameters[cp].Type; + + if (initParameters[p].Name == "name") + type = NLLIGO::CPrimitiveClass::CParameter::String; + + if (cp < primClass.Parameters.size () || (initParameters[p].Name == "name")) + { + // Default value ? + if (!parameter.DefaultValue.empty()) + { + // Type of property + switch (type) + { + case NLLIGO::CPrimitiveClass::CParameter::Boolean: + case NLLIGO::CPrimitiveClass::CParameter::ConstString: + case NLLIGO::CPrimitiveClass::CParameter::String: + { + // Some feedback + if (parameter.DefaultValue.size() > 1) + nlerror("Warning: parameter (%s) in class name (%s) has more than 1 default value (%d).", + parameter.Name.c_str(), primClass.Name.c_str(), parameter.DefaultValue.size()); + + if ((cp < primClass.Parameters.size() && !primClass.Parameters[cp].Visible) + || parameter.DefaultValue[0].GenID) + { + // Remove this property + primitive.removePropertyByName(parameter.Name.c_str()); + + // Add this property + primitive.addPropertyByName(parameter.Name.c_str(), + new NLLIGO::CPropertyString((parameter.DefaultValue[0].GenID ? NLMISC::toString(getUniqueId()) : "").c_str ())); + } + break; + } + case NLLIGO::CPrimitiveClass::CParameter::ConstStringArray: + case NLLIGO::CPrimitiveClass::CParameter::StringArray: + { + bool Visible = false; + if (cp < primClass.Parameters.size() && !primClass.Parameters[cp].Visible) + Visible = true; + for (size_t i = 0; i < parameter.DefaultValue.size(); ++i) + { + // Generate a unique id ? + if (parameter.DefaultValue[i].GenID) + Visible = true; + } + if (Visible) + { + // Remove this property + primitive.removePropertyByName (parameter.Name.c_str()); + + // Add this property + NLLIGO::CPropertyStringArray *str = new NLLIGO::CPropertyStringArray(); + str->StringArray.resize (parameter.DefaultValue.size()); + for (size_t i = 0; i < parameter.DefaultValue.size(); ++i) + { + // Generate a unique id ? + if (parameter.DefaultValue[i].GenID) + str->StringArray[i] = NLMISC::toString(getUniqueId()); + else + str->StringArray[i] = ""; + } + primitive.addPropertyByName(parameter.Name.c_str(), str); + } + break; + } + } + } + } + else + { + // Some feedback + nlerror("Warning: parameter (%s) doesn't exist in class (%s).", + initParameters[p].Name.c_str(), primClass.Name.c_str()); + } + } +} + +NLLIGO::IPrimitive *createPrimitive(const char *className, const char *primName, + const NLMISC::CVector &initPos, float deltaPos, + const std::vector &initParameters, + NLLIGO::IPrimitive *parent) +{ + // Get the prim class + const NLLIGO::CPrimitiveClass *primClass = ligoConfig()->getPrimitiveClass(className); + if (primClass) + { + // Create the base primitive + NLLIGO::IPrimitive *primitive = NULL; + switch (primClass->Type) + { + case NLLIGO::CPrimitiveClass::Node: + primitive = new NLLIGO::CPrimNode; + break; + case NLLIGO::CPrimitiveClass::Point: + { + NLLIGO::CPrimPoint *point = new NLLIGO::CPrimPoint; + primitive = point; + point->Point.CVector::operator = (initPos); + } + break; + case NLLIGO::CPrimitiveClass::Path: + { + NLLIGO::CPrimPath *path = new NLLIGO::CPrimPath; + primitive = path; + path->VPoints.push_back(NLLIGO::CPrimVector(initPos)); + NLMISC::CVector secondPos = NLMISC::CVector(initPos.x + deltaPos, initPos.y, 0.0); + path->VPoints.push_back(NLLIGO::CPrimVector(secondPos)); + break; + } + case NLLIGO::CPrimitiveClass::Zone: + { + NLLIGO::CPrimZone *zone = new NLLIGO::CPrimZone; + primitive = zone; + zone->VPoints.push_back(NLLIGO::CPrimVector(initPos)); + NLMISC::CVector secondPos = NLMISC::CVector(initPos.x + deltaPos, initPos.y, 0.0); + zone->VPoints.push_back(NLLIGO::CPrimVector(secondPos)); + secondPos.y = initPos.y + deltaPos; + zone->VPoints.push_back(NLLIGO::CPrimVector(secondPos)); + break; + } + case NLLIGO::CPrimitiveClass::Alias: + primitive = new NLLIGO::CPrimAlias; + break; + case NLLIGO::CPrimitiveClass::Bitmap: + primitive = new NLLIGO::CPrimNode; + break; + } + nlassert(primitive); + + // Add properties + primitive->addPropertyByName("class", new NLLIGO::CPropertyString(className)); + primitive->addPropertyByName("name", new NLLIGO::CPropertyString(primName, primName[0] == 0)); + + // Init with default parameters + std::vector tempParam; + tempParam.reserve(primClass->Parameters.size()); + for (size_t i = 0; i < primClass->Parameters.size(); i++) + tempParam.push_back (primClass->Parameters[i]); + initPrimitiveParameters (*primClass, *primitive, tempParam); + + // Init with option parameters + initPrimitiveParameters(*primClass, *primitive, initParameters); + + parent->insertChild(primitive); + /* + // Insert the primitive + insertPrimitive (locator, primitive); + */ + // The new pos + NLMISC::CVector newPos = initPos; + newPos.x += deltaPos; + + // Create static children + uint c; + for (c = 0; c < primClass->StaticChildren.size(); c++) + { + // The child ref + const NLLIGO::CPrimitiveClass::CChild &child = primClass->StaticChildren[c]; + + // Create the child + const NLLIGO::IPrimitive *childPrim = createPrimitive(child.ClassName.c_str(), child.Name.c_str(), + newPos, deltaPos, primClass->StaticChildren[c].Parameters, primitive); + + // The new pos + newPos.y += deltaPos; + } + + // Canceled ? + if (c < primClass->StaticChildren.size()) + { + deletePrimitive(primitive); + return NULL; + } + + if (primitive) + { + if (!primClass->AutoInit) + { + // TODO + } + + // Eval the default name property + std::string name; + if (!primitive->getPropertyByName ("name", name) || name.empty()) + { + const NLLIGO::CPrimitiveClass *primClass = ligoConfig()->getPrimitiveClass(*primitive); + if (primClass) + { + for (size_t i = 0; i < primClass->Parameters.size(); ++i) + { + if (primClass->Parameters[i].Name == "name") + { + std::string result; + primClass->Parameters[i].getDefaultValue(result, *primitive, *primClass, NULL); + if (!result.empty()) + { + primitive->removePropertyByName("name"); + primitive->addPropertyByName("name", new NLLIGO::CPropertyString(result.c_str(), true)); + } + } + } + } + } + + primitive->initDefaultValues(*ligoConfig()); + } + return primitive; + } + else + nlerror("Unknown primitive class name : %s", className); + + return 0; +} + +void deletePrimitive(NLLIGO::IPrimitive *primitive) +{ + // Get the parent + NLLIGO::IPrimitive *parent = primitive->getParent(); + nlassert(parent); + + // Get the child id + uint childId; + nlverify(parent->getChildId(childId, primitive)); + + // Delete the child + nlverify(parent->removeChild(childId)); +} + +bool updateDefaultValues(NLLIGO::IPrimitive *primitive) +{ + bool modified = false; + + // Get the prim class + const NLLIGO::CPrimitiveClass *primClass = ligoConfig()->getPrimitiveClass(*primitive); + nlassert(primClass); + + if (primClass) + { + // For each parameters + for (uint i = 0; i < primClass->Parameters.size(); i++) + { + // First check the primitive property has to good type + NLLIGO::IProperty *prop; + if (primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), prop)) + { + // String to array ? + NLLIGO::CPropertyString *propString = dynamic_cast(prop); + const bool classStringArray = primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::StringArray || + primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::ConstStringArray; + if (propString && classStringArray) + { + // Build an array string + std::vector strings; + if (!propString->String.empty()) + strings.push_back(propString->String); + prop = new NLLIGO::CPropertyStringArray(strings); + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), prop); + modified = true; + } + + // Array to string ? + NLLIGO::CPropertyStringArray *propStringArray = dynamic_cast(prop); + if (propStringArray && !classStringArray) + { + // Build an array string + std::string str; + if (!propStringArray->StringArray.empty()) + str = propStringArray->StringArray[0]; + prop = new NLLIGO::CPropertyString(str); + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), prop); + modified = true; + } + } + + // String or string array ? + if (primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::String) + { + // Default value available ? + if (!primClass->Parameters[i].DefaultValue.empty ()) + { + // Unique Id ? + if (primClass->Parameters[i].DefaultValue[0].GenID) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), result)) + { + // Add it ! + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyString(NLMISC::toString(getUniqueId()).c_str())); + modified = true; + } + } + // Hidden ? + else if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName (primClass->Parameters[i].Name.c_str (), result)) + { + // Add it ! + primitive->addPropertyByName (primClass->Parameters[i].Name.c_str (), new NLLIGO::CPropertyString ("")); + modified = true; + } + } + } + } + else if ((primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::StringArray) || + (primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::ConstStringArray)) + { + for (uint j = 0; j < primClass->Parameters[i].DefaultValue.size(); j++) + { + // Unique Id ? + if (primClass->Parameters[i].DefaultValue[j].GenID) + { + // The doesn't exist ? + std::vector result; + std::vector *resultPtr = NULL; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), resultPtr) || + (resultPtr->size() <= j)) + { + // Copy + if (resultPtr) + result = *resultPtr; + + // Resize + if (result.size() <= j) + result.resize(j + 1); + + // Resize to it + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + + // Set the value + result[j] = NLMISC::toString(getUniqueId()); + + // Add the new property array + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyStringArray(result)); + modified = true; + } + } + // Hidden ? + else if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::vector result; + std::vector *resultPtr = NULL; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), resultPtr) || (resultPtr->size () <= j)) + { + // Copy + if (resultPtr) + result = *resultPtr; + + // Resize + if (result.size() <= j) + result.resize(j + 1); + + // Resize to it + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + + // Set the value + result[j] = ""; + + // Add the new property array + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyStringArray(result)); + modified = true; + } + } + } + } + else + { + // Default value available ? + if (!primClass->Parameters[i].DefaultValue.empty ()) + { + // Hidden ? + if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), result)) + { + // Add it ! + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyString("")); + modified = true; + } + } + } + } + } + } + return modified; +} + +bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive) +{ + bool modified = updateDefaultValues(primitive); + + const uint count = primitive->getNumChildren(); + for (uint i = 0; i < count; ++i) + { + // Get the child + NLLIGO::IPrimitive *child; + nlverify(primitive->getChild(child, i)); + modified |= recursiveUpdateDefaultValues(child); + } + + 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 new file mode 100644 index 000000000..d29b2553b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h @@ -0,0 +1,78 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// 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_MISC_H +#define WORLD_EDITOR_MISC_H + +// Project includes + +// NeL includes +#include +#include +#include + +// STL includes +#include +#include + +#define WORLD_EDITOR_FILE_VERSION 2 +#define WORLD_EDITOR_DATABASE_SIZE 100 + +namespace WorldEditor +{ +namespace Utils +{ +enum ItemType +{ + DataDirectoryType = 0, + ContextType, + LandscapeType, + PrimitiveType +}; + +typedef std::pair WorldEditItem; +typedef std::vector WorldEditList; + +// Generate unique identificator +uint32 getUniqueId(); + +// Load *.worldedit file and return list primitives and landscapes. +bool loadWorldEditFile(const std::string &fileName, WorldEditList &worldEditList); + +// Get root primitive +NLLIGO::IPrimitive *getRootPrimitive(NLLIGO::IPrimitive *primitive); + +// Init a primitive parameters +void initPrimitiveParameters(const NLLIGO::CPrimitiveClass &primClass, NLLIGO::IPrimitive &primitive, + const std::vector &initParameters); + +NLLIGO::IPrimitive *createPrimitive(const char *className, const char *primName, + const NLMISC::CVector &initPos, float deltaPos, + const std::vector &initParameters, + NLLIGO::IPrimitive *parent); + +void deletePrimitive(NLLIGO::IPrimitive *primitive); + +bool updateDefaultValues(NLLIGO::IPrimitive *primitive); + +bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive); + +NLLIGO::CLigoConfig *ligoConfig(); + +} /* namespace Utils */ +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_MISC_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp new file mode 100644 index 000000000..aa995777a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp @@ -0,0 +1,136 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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_plugin.h" +#include "world_editor_window.h" +#include "world_editor_settings_page.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include "nel/misc/debug.h" +#include +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +WorldEditorPlugin::~WorldEditorPlugin() +{ + Q_FOREACH(QObject *obj, m_autoReleaseObjects) + { + m_plugMan->removeObject(obj); + } + qDeleteAll(m_autoReleaseObjects); + m_autoReleaseObjects.clear(); +} + +bool WorldEditorPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString) +{ + m_plugMan = pluginManager; + + WorldEditorSettingsPage *weSettings = new WorldEditorSettingsPage(this); + addAutoReleasedObject(weSettings); + + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + m_ligoConfig.CellSize = settings->value(Constants::WORLD_EDITOR_CELL_SIZE, "160").toFloat(); + m_ligoConfig.Snap = settings->value(Constants::WORLD_EDITOR_SNAP, "1").toFloat(); + m_ligoConfig.ZoneSnapShotRes = settings->value(Constants::ZONE_SNAPSHOT_RES, "128").toUInt(); + QString fileName = settings->value(Constants::PRIMITIVE_CLASS_FILENAME, "world_editor_classes.xml").toString(); + settings->endGroup(); + try + { + // Search path of file world_editor_classes.xml + std::string ligoPath = NLMISC::CPath::lookup(fileName.toStdString()); + // Init LIGO + m_ligoConfig.readPrimitiveClass(ligoPath.c_str(), true); + NLLIGO::Register(); + NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; + } + catch (NLMISC::Exception &e) + { + *errorString = tr("(%1)").arg(e.what()); + return false; + } + + // Reset + m_ligoConfig.resetPrimitiveConfiguration (); + + // TODO: get file names! from settings + m_ligoConfig.readPrimitiveClass("world_editor_primitive_configuration.xml", true); + + + addAutoReleasedObject(new WorldEditorContext(this)); + return true; +} + +void WorldEditorPlugin::extensionsInitialized() +{ +} + +void WorldEditorPlugin::shutdown() +{ +} + +void WorldEditorPlugin::setNelContext(NLMISC::INelContext *nelContext) +{ +#ifdef NL_OS_WINDOWS + // Ensure that a context doesn't exist yet. + // This only applies to platforms without PIC, e.g. Windows. + nlassert(!NLMISC::INelContext::isContextInitialised()); +#endif // NL_OS_WINDOWS + m_libContext = new NLMISC::CLibraryContext(*nelContext); +} + +void WorldEditorPlugin::addAutoReleasedObject(QObject *obj) +{ + m_plugMan->addObject(obj); + m_autoReleaseObjects.prepend(obj); +} + +WorldEditorContext::WorldEditorContext(QObject *parent) + : IContext(parent), + m_worldEditorWindow(0) +{ + m_worldEditorWindow = new WorldEditorWindow(); +} + +QUndoStack *WorldEditorContext::undoStack() +{ + return m_worldEditorWindow->undoStack(); +} + +void WorldEditorContext::open() +{ + m_worldEditorWindow->open(); +} + +QWidget *WorldEditorContext::widget() +{ + return m_worldEditorWindow; +} + +} + +Q_EXPORT_PLUGIN(WorldEditor::WorldEditorPlugin) \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h new file mode 100644 index 000000000..686b87e14 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h @@ -0,0 +1,98 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// 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_PLUGIN_H +#define WORLD_EDITOR_PLUGIN_H + +// Project includes +#include "world_editor_constants.h" +#include "../../extension_system/iplugin.h" +#include "../core/icontext.h" + +// NeL includes +#include "nel/misc/app_context.h" +#include + +// Qt includes +#include +#include + +namespace NLMISC +{ +class CLibraryContext; +} + +namespace WorldEditor +{ +class WorldEditorWindow; + +class WorldEditorPlugin : public QObject, public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_INTERFACES(ExtensionSystem::IPlugin) +public: + + virtual ~WorldEditorPlugin(); + + bool initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString); + void extensionsInitialized(); + void shutdown(); + void setNelContext(NLMISC::INelContext *nelContext); + + void addAutoReleasedObject(QObject *obj); + +protected: + NLMISC::CLibraryContext *m_libContext; + +private: + NLLIGO::CLigoConfig m_ligoConfig; + ExtensionSystem::IPluginManager *m_plugMan; + QList m_autoReleaseObjects; +}; + +class WorldEditorContext: public Core::IContext +{ + Q_OBJECT +public: + WorldEditorContext(QObject *parent = 0); + virtual ~WorldEditorContext() {} + + virtual QString id() const + { + return QLatin1String("WorldEditorContext"); + } + virtual QString trName() const + { + return tr("World Editor"); + } + virtual QIcon icon() const + { + return QIcon(Constants::ICON_WORLD_EDITOR); + } + + virtual void open(); + + virtual QUndoStack *undoStack(); + + virtual QWidget *widget(); + + WorldEditorWindow *m_worldEditorWindow; +}; + +} // namespace WorldEditor + +#endif // WORLD_EDITOR_PLUGIN_H 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 new file mode 100644 index 000000000..678b361fe --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp @@ -0,0 +1,604 @@ +// 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.h" +#include "world_editor_scene_item.h" +#include "world_editor_actions.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace WorldEditor +{ + +WorldEditorScene::WorldEditorScene(int sizeCell, PrimitivesTreeModel *model, QUndoStack *undoStack, QObject *parent) + : LandscapeEditor::LandscapeSceneBase(sizeCell, parent), + m_editedSelectedItems(false), + m_lastPickedPrimitive(0), + m_mode(SelectMode), + m_pointsMode(false), + m_undoStack(undoStack), + m_model(model) +{ + setItemIndexMethod(NoIndex); + + // TODO: get params from settings + setSceneRect(QRectF(-20 * 160, -20 * 160, 256 * 160, 256 * 160)); + + m_greenPen.setColor(QColor(50, 255, 155)); + m_greenPen.setWidth(0); + m_greenBrush.setColor(QColor(50, 255, 155, 80)); + m_greenBrush.setStyle(Qt::SolidPattern); + + m_purplePen.setColor(QColor(100, 0, 255)); + m_purplePen.setWidth(0); + m_purpleBrush.setColor(QColor(100, 0, 255, 80)); + m_purpleBrush.setStyle(Qt::SolidPattern); +} + +WorldEditorScene::~WorldEditorScene() +{ +} + +AbstractWorldItem *WorldEditorScene::addWorldItemPoint(const QPointF &point, const qreal angle, + const qreal radius, bool showArrow) +{ + WorldItemPoint *item = new WorldItemPoint(point, angle, radius, showArrow); + addItem(item); + return item; +} + +AbstractWorldItem *WorldEditorScene::addWorldItemPath(const QPolygonF &polyline, bool showArrow) +{ + WorldItemPath *item = new WorldItemPath(polyline); + addItem(item); + return item; +} + +AbstractWorldItem *WorldEditorScene::addWorldItemZone(const QPolygonF &polygon) +{ + WorldItemZone *item = new WorldItemZone(polygon); + addItem(item); + return item; +} + +void WorldEditorScene::removeWorldItem(QGraphicsItem *item) +{ + updateSelectedWorldItems(true); + m_selectedItems.clear(); + m_editedSelectedItems = false; + m_firstSelection = false; + delete item; +} + +void WorldEditorScene::setModeEdit(WorldEditorScene::ModeEdit mode) +{ + if (mode == WorldEditorScene::SelectMode) + m_editedSelectedItems = false; + + m_mode = mode; +} + +WorldEditorScene::ModeEdit WorldEditorScene::editMode() const +{ + return m_mode; +} + +bool WorldEditorScene::isEnabledEditPoints() const +{ + return m_pointsMode; +} + +void WorldEditorScene::setEnabledEditPoints(bool enabled) +{ + if (m_pointsMode == enabled) + return; + + m_pointsMode = enabled; + + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + AbstractWorldItem *worldItem = qgraphicsitem_cast(item); + if (worldItem != 0) + worldItem->setEnabledSubPoints(enabled); + } + + m_selectedPoints.clear(); +} + +void WorldEditorScene::updateSelection(const QList &selected, const QList &deselected) +{ + // Deselect and remove from list graphics items. + Q_FOREACH(QGraphicsItem *item, deselected) + { + // Item is selected? + int i = m_selectedItems.indexOf(item); + if (i != -1) + { + updateSelectedWorldItem(item, false); + m_selectedItems.takeAt(i); + } + } + + // Select and add from list graphics items. + Q_FOREACH(QGraphicsItem *item, selected) + { + // Item is selected? + int i = m_selectedItems.indexOf(item); + if (i == -1) + { + updateSelectedWorldItem(item, true); + m_selectedItems.push_back(item); + } + } + + update(); + m_firstSelection = true; +} + +void WorldEditorScene::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsScene::drawForeground(painter, rect); + + if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0)) + { + // Draw selection area + if (m_selectionArea.left() < m_selectionArea.right()) + { + painter->setPen(m_greenPen); + painter->setBrush(m_greenBrush); + } + else + { + painter->setPen(m_purplePen); + painter->setBrush(m_purpleBrush); + } + painter->drawRect(m_selectionArea); + } +} + +void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + m_firstPick = mouseEvent->scenePos(); + + if (isEnabledEditPoints()) + { + m_polygons = polygonsFromItems(m_selectedItems); + + if (mouseEvent->button() == Qt::LeftButton) + { + // Create new sub-points + // Call method mousePressEvent for sub-point located under mouse + LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent); + + if ((!m_editedSelectedItems && m_selectedPoints.isEmpty()) || + (!calcBoundingRect(m_selectedPoints).contains(mouseEvent->scenePos()))) + { + updatePickSelectionPoints(mouseEvent->scenePos()); + m_firstSelection = true; + } + m_pivot = calcBoundingRect(m_selectedPoints).center(); + } + else if (mouseEvent->button() == Qt::RightButton) + { + updateSelectedPointItems(false); + m_selectedPoints.clear(); + + // Delete sub-points if it located under mouse + // Call method mousePressEvent for sub-point located under mouse + LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent); + } + } + else + { + LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent); + + if (mouseEvent->button() != Qt::LeftButton) + return; + + if ((!m_editedSelectedItems && m_selectedItems.isEmpty()) || + (!calcBoundingRect(m_selectedItems).contains(mouseEvent->scenePos()))) + { + updatePickSelection(mouseEvent->scenePos()); + m_firstSelection = true; + } + + m_pivot = calcBoundingRect(m_selectedItems).center(); + } + + m_editedSelectedItems = false; + m_offset = QPointF(0, 0); + m_angle = 0; + m_scaleFactor = QPointF(1.0, 1.0); + + if (m_mode == WorldEditorScene::SelectMode) + m_selectionArea.setTopLeft(mouseEvent->scenePos()); +} + +void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + if (QApplication::mouseButtons() == Qt::LeftButton) + { + m_selectionArea.setBottomRight(mouseEvent->scenePos()); + switch (m_mode) + { + case WorldEditorScene::SelectMode: + break; + case WorldEditorScene::MoveMode: + updateWorldItemsMove(mouseEvent); + break; + case WorldEditorScene::RotateMode: + updateWorldItemsRotate(mouseEvent); + break; + case WorldEditorScene::ScaleMode: + updateWorldItemsScale(mouseEvent); + break; + case WorldEditorScene::TurnMode: + updateWorldItemsTurn(mouseEvent); + break; + case WorldEditorScene::RadiusMode: + updateWorldItemsRadius(mouseEvent); + break; + }; + + if (isEnabledEditPoints()) + { + if ((editMode() != WorldEditorScene::SelectMode) && (!m_selectedPoints.isEmpty())) + m_editedSelectedItems = true; + else + m_editedSelectedItems = false; + } + else + { + if ((editMode() != WorldEditorScene::SelectMode) && (!m_selectedItems.isEmpty())) + m_editedSelectedItems = true; + else + m_editedSelectedItems = false; + } + // Update render (drawing selection area when enabled multiple selection mode) + update(); + } + + LandscapeEditor::LandscapeSceneBase::mouseMoveEvent(mouseEvent); +} + +void WorldEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + if (mouseEvent->button() == Qt::MidButton) + return; + + if (mouseEvent->button() == Qt::LeftButton) + { + checkUndo(); + + // Update selection + if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0)) + { + QList listItems; + + // Clear selection + updateSelectedPointItems(false); + m_selectedPoints.clear(); + + // Return list of selected items + if (m_selectionArea.left() < m_selectionArea.right()) + listItems = items(m_selectionArea, Qt::IntersectsItemShape, Qt::AscendingOrder); + else + listItems = items(m_selectionArea, Qt::ContainsItemShape, Qt::AscendingOrder); + + if (isEnabledEditPoints()) + { + Q_FOREACH(QGraphicsItem *item, listItems) + { + if (qgraphicsitem_cast(item) == 0) + continue; + m_selectedPoints.push_back(item); + } + updateSelectedPointItems(true); + } + else + { + Q_FOREACH(QGraphicsItem *item, listItems) + { + if (qgraphicsitem_cast(item) == 0) + continue; + m_selectedItems.push_back(item); + } + Q_EMIT updateSelectedItems(m_selectedItems); + updateSelectedWorldItems(true); + } + m_selectionArea = QRectF(); + update(); + } + else + { + if ((!m_editedSelectedItems) && (!m_firstSelection)) + { + if (isEnabledEditPoints()) + updatePickSelectionPoints(mouseEvent->scenePos()); + else + updatePickSelection(mouseEvent->scenePos()); + } + else + m_firstSelection = false; + } + + if (isEnabledEditPoints()) + checkUndoPointsMode(); + } + m_selectionArea = QRectF(); + LandscapeEditor::LandscapeSceneBase::mouseReleaseEvent(mouseEvent); +} + +QRectF WorldEditorScene::calcBoundingRect(const QList &listItems) +{ + QRectF rect; + Q_FOREACH(QGraphicsItem *item, listItems) + { + QRectF itemRect = item->boundingRect(); + rect = rect.united(itemRect.translated(item->scenePos())); + } + 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->scenePos())); + } + return painterPath; +} + +void WorldEditorScene::updateSelectedWorldItems(bool value) +{ + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + updateSelectedWorldItem(item, value); + } + update(); +} + +void WorldEditorScene::updateSelectedWorldItem(QGraphicsItem *item, bool value) +{ + AbstractWorldItem *worldItem = qgraphicsitem_cast(item); + if (worldItem != 0) + worldItem->setActived(value); +} + +void WorldEditorScene::updateSelectedPointItems(bool value) +{ + Q_FOREACH(QGraphicsItem *item, m_selectedPoints) + { + updateSelectedPointItem(item, value); + } + update(); +} + +void WorldEditorScene::updateSelectedPointItem(QGraphicsItem *item, bool value) +{ + WorldItemSubPoint *worldItem = qgraphicsitem_cast(item); + if (worldItem != 0) + worldItem->setActived(value); +} + +void WorldEditorScene::updatePickSelection(const QPointF &point) +{ + updateSelectedWorldItems(false); + m_selectedItems.clear(); + + QList listItems = items(point, Qt::ContainsItemShape, + Qt::AscendingOrder); + + QList worldItemsItems; + + Q_FOREACH(QGraphicsItem *item, listItems) + { + AbstractWorldItem *worldItem = qgraphicsitem_cast(item); + if (worldItem != 0) + worldItemsItems.push_back(worldItem); + } + + if (!worldItemsItems.isEmpty()) + { + // Next primitives + m_lastPickedPrimitive++; + m_lastPickedPrimitive %= worldItemsItems.size(); + + m_selectedItems.push_back(worldItemsItems.at(m_lastPickedPrimitive)); + updateSelectedWorldItems(true); + } + + Q_EMIT updateSelectedItems(m_selectedItems); +} + +void WorldEditorScene::updatePickSelectionPoints(const QPointF &point) +{ + updateSelectedPointItems(false); + m_selectedPoints.clear(); + + QList listItems = items(point, Qt::IntersectsItemBoundingRect, + Qt::AscendingOrder); + + QList subPointsItems; + + Q_FOREACH(QGraphicsItem *item, listItems) + { + WorldItemSubPoint *subPointItem = qgraphicsitem_cast(item); + if (subPointItem != 0) + { + if (subPointItem->subPointType() == WorldItemSubPoint::EdgeType) + subPointsItems.push_back(subPointItem); + } + } + + if (!subPointsItems.isEmpty()) + { + // Next primitives + m_lastPickedPrimitive++; + m_lastPickedPrimitive %= subPointsItems.size(); + + m_selectedPoints.push_back(subPointsItems.at(m_lastPickedPrimitive)); + updateSelectedPointItems(true); + } +} + +void WorldEditorScene::checkUndo() +{ + if (m_editedSelectedItems && (!isEnabledEditPoints())) + { + switch (m_mode) + { + case WorldEditorScene::SelectMode: + break; + case WorldEditorScene::MoveMode: + m_undoStack->push(new MoveWorldItemsCommand(m_selectedItems, m_offset, this, m_model)); + break; + case WorldEditorScene::RotateMode: + m_undoStack->push(new RotateWorldItemsCommand(m_selectedItems, m_angle, m_pivot, this, m_model)); + break; + case WorldEditorScene::ScaleMode: + m_undoStack->push(new ScaleWorldItemsCommand(m_selectedItems, m_scaleFactor, m_pivot, this, m_model)); + break; + case WorldEditorScene::TurnMode: + m_undoStack->push(new TurnWorldItemsCommand(m_selectedItems, m_angle, this, m_model)); + break; + case WorldEditorScene::RadiusMode: + break; + }; + } +} + +void WorldEditorScene::checkUndoPointsMode() +{ + if (m_pointsMode) + { + QList items; + QList polygons; + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + AbstractWorldItem *worldItem = qgraphicsitem_cast(item); + if (worldItem->isShapeChanged()) + { + items.push_back(item); + polygons.push_back(m_polygons.at(m_selectedItems.indexOf(item))); + worldItem->setShapeChanged(false); + } + } + if (!items.isEmpty()) + { + m_undoStack->push(new ShapeWorldItemsCommand(items, polygons, this, m_model)); + m_polygons.clear(); + } + } +} + +void WorldEditorScene::updateWorldItemsMove(QGraphicsSceneMouseEvent *mouseEvent) +{ + QPointF offset = mouseEvent->scenePos() - mouseEvent->lastScenePos(); + m_offset += offset; + if (m_pointsMode) + Q_FOREACH(QGraphicsItem *item, m_selectedPoints) + { + item->moveBy(offset.x(), offset.y()); + } + else + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + item->moveBy(offset.x(), offset.y()); + } +} + +void WorldEditorScene::updateWorldItemsScale(QGraphicsSceneMouseEvent *mouseEvent) +{ + QPointF offset(mouseEvent->scenePos() - mouseEvent->lastScenePos()); + + qreal scaleRatio = 5000; + + // Calculate scale factor + if (offset.x() > 0) + offset.setX(1.0 + (offset.x() / scaleRatio)); + else + offset.setX(1.0 / (1.0 + (-offset.x() / scaleRatio))); + + if (offset.y() < 0) + offset.setY(1.0 - (offset.y() / scaleRatio)); + else + offset.setY(1.0 / (1.0 + (offset.y() / scaleRatio))); + + m_scaleFactor.setX(offset.x() * m_scaleFactor.x()); + m_scaleFactor.setY(offset.y() * m_scaleFactor.y()); + + if (m_pointsMode) + Q_FOREACH(QGraphicsItem *item, m_selectedPoints) + { + qgraphicsitem_cast(item)->scaleOn(m_pivot, offset); + } + else + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->scaleOn(m_pivot, offset); + } +} + +void WorldEditorScene::updateWorldItemsRotate(QGraphicsSceneMouseEvent *mouseEvent) +{ + // Caluculate angle between two line + QLineF firstLine(m_pivot, mouseEvent->lastScenePos()); + QLineF secondLine(m_pivot, mouseEvent->scenePos()); + qreal angle = secondLine.angleTo(firstLine); + m_angle += angle; + + if (m_pointsMode) + Q_FOREACH(QGraphicsItem *item, m_selectedPoints) + { + qgraphicsitem_cast(item)->rotateOn(m_pivot, angle); + } + else + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->rotateOn(m_pivot, angle); + } +} + +void WorldEditorScene::updateWorldItemsTurn(QGraphicsSceneMouseEvent *mouseEvent) +{ + // Caluculate angle between two line + QLineF firstLine(m_pivot, mouseEvent->lastScenePos()); + QLineF secondLine(m_pivot, mouseEvent->scenePos()); + qreal angle = secondLine.angleTo(firstLine); + m_angle += angle; + + Q_FOREACH(QGraphicsItem *item, m_selectedItems) + { + qgraphicsitem_cast(item)->turnOn(angle); + } +} + +void WorldEditorScene::updateWorldItemsRadius(QGraphicsSceneMouseEvent *mouseEvent) +{ +} + +} /* 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 new file mode 100644 index 000000000..7174c69c8 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h @@ -0,0 +1,142 @@ +// 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_H +#define WORLD_EDITOR_SCENE_H + +// Project includes +#include "world_editor_global.h" + +#include "../landscape_editor/landscape_scene_base.h" + +// NeL includes + +// Qt includes +#include + +namespace WorldEditor +{ +class PrimitivesTreeModel; +class AbstractWorldItem; + +/* +@class WorldEditorScene +@brief The WorldEditorScene provides a surface for managing a large number of 2D world items(point/path/zone). +@details WorldEditorScene also provides 'selections model' functionality, which differs from standart selection model. +*/ +class WORLD_EDITOR_EXPORT WorldEditorScene : public LandscapeEditor::LandscapeSceneBase +{ + Q_OBJECT + +public: + enum ModeEdit + { + SelectMode = 0, + MoveMode, + RotateMode, + ScaleMode, + TurnMode, + RadiusMode + }; + + WorldEditorScene(int sizeCell, PrimitivesTreeModel *model, + QUndoStack *undoStack, QObject *parent = 0); + virtual ~WorldEditorScene(); + + /// Create WorldItemPoint and add in scene. + AbstractWorldItem *addWorldItemPoint(const QPointF &point, const qreal angle, + const qreal radius, bool showArrow); + + /// Create WorldItemPath and add in scene. + AbstractWorldItem *addWorldItemPath(const QPolygonF &polyline, bool showArrow); + + /// Create WorldItemZone and add in scene. + AbstractWorldItem *addWorldItemZone(const QPolygonF &polygon); + + /// Remove a world item from the scene. + void removeWorldItem(QGraphicsItem *item); + + /// Set current mode editing(select/move/rotate/scale/turn), above world items. + void setModeEdit(WorldEditorScene::ModeEdit mode); + + WorldEditorScene::ModeEdit editMode() const; + + /// @return true if edit points mode is enabled, else false. + bool isEnabledEditPoints() const; + +Q_SIGNALS: + /// This signal is emitted by WorldEditorScene when the selections changes. + /// The @selected value contains a list of all selected items. + void updateSelectedItems(const QList &selected); + +public Q_SLOTS: + /// Enable/disable edit points mode (user can change shape of WorldItemZone and WorldItemPath) + /// + void setEnabledEditPoints(bool enabled); + + /// Update of selections + void updateSelection(const QList &selected, const QList &deselected); + +protected: + 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 updateSelectedWorldItems(bool value); + void updateSelectedWorldItem(QGraphicsItem *item, bool value); + void updateSelectedPointItems(bool value); + void updateSelectedPointItem(QGraphicsItem *item, bool value); + + void updatePickSelection(const QPointF &point); + void updatePickSelectionPoints(const QPointF &point); + + void checkUndo(); + void checkUndoPointsMode(); + + void updateWorldItemsMove(QGraphicsSceneMouseEvent *mouseEvent); + void updateWorldItemsScale(QGraphicsSceneMouseEvent *mouseEvent); + void updateWorldItemsRotate(QGraphicsSceneMouseEvent *mouseEvent); + void updateWorldItemsTurn(QGraphicsSceneMouseEvent *mouseEvent); + void updateWorldItemsRadius(QGraphicsSceneMouseEvent *mouseEvent); + + QPen m_greenPen, m_purplePen; + QBrush m_greenBrush, m_purpleBrush; + + QPointF m_firstPick, m_scaleFactor, m_pivot, m_offset; + QRectF m_selectionArea; + qreal m_firstPickX, m_firstPickY, m_angle; + + QList m_selectedItems; + QList m_selectedPoints; + QList m_polygons; + + bool m_editedSelectedItems, m_firstSelection; + uint m_lastPickedPrimitive; + ModeEdit m_mode; + bool m_pointsMode; + QUndoStack *m_undoStack; + PrimitivesTreeModel *m_model; +}; + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_SCENE_H 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..1375c40ab --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.cpp @@ -0,0 +1,741 @@ +// 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; +} + +AbstractWorldItem::AbstractWorldItem(QGraphicsItem *parent) + : QGraphicsItem(parent), + m_active(false), + m_shapeChanged(false) +{ +} + +AbstractWorldItem::~AbstractWorldItem() +{ +} + +int AbstractWorldItem::type() const +{ + return Type; +} + +void AbstractWorldItem::setActived(bool actived) +{ + m_active = actived; +} + +bool AbstractWorldItem::isActived() const +{ + return m_active; +} + +void AbstractWorldItem::setShapeChanged(bool value) +{ + m_shapeChanged = value; +} + +bool AbstractWorldItem::isShapeChanged() const +{ + return m_shapeChanged; +} + +WorldItemPoint::WorldItemPoint(const QPointF &point, const qreal angle, const qreal radius, + bool showArrow, QGraphicsItem *parent) + : AbstractWorldItem(parent), + m_angle(angle), + m_radius(radius), + m_showArrow(showArrow) +{ + setZValue(WORLD_POINT_LAYER); + + //setFlag(ItemIgnoresTransformations); + + setPos(point); + + m_rect.setCoords(-SIZE_POINT, -SIZE_POINT, SIZE_POINT, SIZE_POINT); + + m_pen.setColor(QColor(255, 100, 10)); + //m_pen.setWidth(0); + + m_selectedPen.setColor(Qt::white); + //m_selectedPen.setWidth(0); + + m_brush.setColor(QColor(255, 100, 10)); + m_brush.setStyle(Qt::SolidPattern); + + m_selectedBrush.setColor(Qt::white); + m_selectedBrush.setStyle(Qt::SolidPattern); + + createCircle(); + + // Create arrow + if (showArrow) + { + m_arrow.push_back(QLine(0, 0, SIZE_ARROW, 0)); + m_arrow.push_back(QLine(SIZE_ARROW - 2, -2, SIZE_ARROW, 0)); + m_arrow.push_back(QLine(SIZE_ARROW - 2, 2, SIZE_ARROW, 0)); + } + + updateBoundingRect(); +} + +WorldItemPoint::~WorldItemPoint() +{ +} + +qreal WorldItemPoint::angle() const +{ + return m_angle; +} + +void WorldItemPoint::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_rect); + + rotatedPolygon.translate(pos() - 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 &factor) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_rect); + + scaledPolygon.translate(pos() - pivot); + + QTransform trans; + trans = trans.scale(factor.x(), factor.y()); + scaledPolygon = trans.map(scaledPolygon); + scaledPolygon.translate(pivot); + + setPos(scaledPolygon.boundingRect().center()); +} + +void WorldItemPoint::turnOn(const qreal angle) +{ + m_angle += angle; + m_angle -= floor(m_angle / 360) * 360; + update(); +} + +void WorldItemPoint::radiusOn(const qreal radius) +{ + if (m_radius == 0) + return; + + // TODO: implement +} + +void WorldItemPoint::setColor(const QColor &color) +{ + m_pen.setColor(color); + m_brush.setColor(color); +} + +void WorldItemPoint::setPolygon(const QPolygonF &polygon) +{ +} + +QPolygonF WorldItemPoint::polygon() const +{ + QPolygonF polygon; + polygon << QPointF(0, 0); + return polygon; +} + +void WorldItemPoint::createCircle() +{ + if (m_radius != 0) + { + // Create circle + int segmentCount = 20; + QPointF circlePoint(m_radius, 0); + m_circle << circlePoint; + for (int i = 1; i < segmentCount + 1; ++i) + { + qreal angle = i * (2 * NLMISC::Pi / segmentCount); + circlePoint.setX(cos(angle) * m_radius); + circlePoint.setY(sin(angle) * m_radius); + m_circle << circlePoint; + } + } +} + +void WorldItemPoint::updateBoundingRect() +{ + m_boundingRect.setCoords(-SIZE_POINT, -SIZE_POINT, SIZE_POINT, SIZE_POINT); + QRectF circleBoundingRect; + circleBoundingRect.setCoords(-m_radius, -m_radius, m_radius, m_radius); + m_boundingRect = m_boundingRect.united(circleBoundingRect); +} + +QPainterPath WorldItemPoint::shape() const +{ + QPainterPath path; + + path.addRect(m_boundingRect); + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +QRectF WorldItemPoint::boundingRect() const +{ + return m_boundingRect; +} + +void WorldItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + painter->setPen(m_pen); + + // Draw circle + // Draws artefacts with using opengl painter + // painter->drawEllipse(-m_radius / 2, -m_radius / 2, m_radius, m_radius); + painter->drawPolygon(m_circle); + + painter->rotate(m_angle); + + // Draw arrow + painter->drawLines(m_arrow); + + painter->setPen(Qt::NoPen); + if (isActived()) + painter->setBrush(m_selectedBrush); + else + painter->setBrush(m_brush); + + // Draw point + painter->drawRect(m_rect); +} + +BaseWorldItemPolyline::BaseWorldItemPolyline(const QPolygonF &polygon, QGraphicsItem *parent) + : AbstractWorldItem(parent), + m_polyline(polygon), + m_pointEdit(false) +{ + //setFlag(ItemIsSelectable); + QPointF center = m_polyline.boundingRect().center(); + m_polyline.translate(-center); + setPos(center); +} + +BaseWorldItemPolyline::~BaseWorldItemPolyline() +{ +} + +void BaseWorldItemPolyline::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_polyline); + rotatedPolygon.translate(pos() - pivot); + + QTransform trans; + trans = trans.rotate(deltaAngle); + m_polyline = trans.map(rotatedPolygon); + + m_polyline.translate(pivot - pos()); +} + +void BaseWorldItemPolyline::scaleOn(const QPointF &pivot, const QPointF &factor) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_polyline); + scaledPolygon.translate(pos() - pivot); + + QTransform trans; + trans = trans.scale(factor.x(), factor.y()); + m_polyline = trans.map(scaledPolygon); + + m_polyline.translate(pivot - pos()); +} + +void BaseWorldItemPolyline::setEnabledSubPoints(bool enabled) +{ + m_pointEdit = enabled; + if (m_pointEdit) + createSubPoints(); + else + removeSubPoints(); + + setShapeChanged(false); +} + +void BaseWorldItemPolyline::moveSubPoint(WorldItemSubPoint *subPoint) +{ + prepareGeometryChange(); + + QPolygonF polygon; + + // Update polygon + Q_FOREACH(WorldItemSubPoint *node, m_listItems) + { + polygon << node->pos(); + } + + // Update middle points + for (int i = 0; i < m_listLines.size(); ++i) + m_listLines.at(i).itemPoint->setPos((m_listLines.at(i).lineItem.first->pos() + m_listLines.at(i).lineItem.second->pos()) / 2); + + m_polyline = polygon; + setShapeChanged(true); + update(); +} + +void BaseWorldItemPolyline::addSubPoint(WorldItemSubPoint *subPoint) +{ + prepareGeometryChange(); + + for (int i = 0; i < m_listLines.size(); ++i) + { + if (subPoint == m_listLines.at(i).itemPoint) + { + LineStruct oldLineItem = m_listLines[i]; + + // Create the first middle sub-point + WorldItemSubPoint *firstItem = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this); + firstItem->setPos((oldLineItem.lineItem.first->pos() + subPoint->pos()) / 2); + + // Create the second middle sub-point + WorldItemSubPoint *secondItem = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this); + secondItem->setPos((oldLineItem.lineItem.second->pos() + subPoint->pos()) / 2); + + // Add first line in the list + LineStruct firstNewLineItem; + firstNewLineItem.itemPoint = firstItem; + firstNewLineItem.lineItem = LineItem(oldLineItem.lineItem.first, subPoint); + m_listLines.push_back(firstNewLineItem); + + // Add second line in the list + LineStruct secondNewLineItem; + secondNewLineItem.itemPoint = secondItem; + secondNewLineItem.lineItem = LineItem(subPoint, oldLineItem.lineItem.second); + m_listLines.push_back(secondNewLineItem); + + m_listLines.removeAt(i); + + int pos = m_listItems.indexOf(oldLineItem.lineItem.second); + m_listItems.insert(pos, subPoint); + subPoint->setFlag(ItemSendsScenePositionChanges); + + break; + } + } + setShapeChanged(true); +} + +bool BaseWorldItemPolyline::removeSubPoint(WorldItemSubPoint *subPoint) +{ + prepareGeometryChange(); + + int pos = m_listItems.indexOf(subPoint); + m_listItems.takeAt(pos); + LineStruct newLineItem; + newLineItem.itemPoint = subPoint; + + // Delete first line + for (int i = 0; i < m_listLines.size(); ++i) + { + if (subPoint == m_listLines.at(i).lineItem.first) + { + // Saving second point for new line + newLineItem.lineItem.second = m_listLines.at(i).lineItem.second; + delete m_listLines.at(i).itemPoint; + m_listLines.removeAt(i); + break; + } + } + + // Delete second line + for (int i = 0; i < m_listLines.size(); ++i) + { + if (subPoint == m_listLines.at(i).lineItem.second) + { + // Saving first point for new line + newLineItem.lineItem.first = m_listLines.at(i).lineItem.first; + delete m_listLines.at(i).itemPoint; + m_listLines.removeAt(i); + break; + } + } + subPoint->setPos((newLineItem.lineItem.first->pos() + newLineItem.lineItem.second->pos()) / 2); + m_listLines.push_back(newLineItem); + subPoint->setFlag(ItemSendsScenePositionChanges, false); + setShapeChanged(true); + return true; +} + +void BaseWorldItemPolyline::setPolygon(const QPolygonF &polygon) +{ + prepareGeometryChange(); + m_polyline = polygon; + update(); +} + +QPolygonF BaseWorldItemPolyline::polygon() const +{ + return m_polyline; +} + +QRectF BaseWorldItemPolyline::boundingRect() const +{ + return m_polyline.boundingRect(); +} + +void BaseWorldItemPolyline::createSubPoints() +{ + WorldItemSubPoint *firstPoint; + firstPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this); + firstPoint->setPos(m_polyline.front()); + firstPoint->setFlag(ItemSendsScenePositionChanges); + m_listItems.push_back(firstPoint); + + for (int i = 1; i < m_polyline.count(); ++i) + { + WorldItemSubPoint *secondPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this); + secondPoint->setPos(m_polyline.at(i)); + secondPoint->setFlag(ItemSendsScenePositionChanges); + + WorldItemSubPoint *middlePoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this); + middlePoint->setPos((firstPoint->pos() + secondPoint->pos()) / 2); + + LineStruct newLineItem; + newLineItem.itemPoint = middlePoint; + newLineItem.lineItem = LineItem(firstPoint, secondPoint); + m_listLines.push_back(newLineItem); + + firstPoint = secondPoint; + m_listItems.push_back(firstPoint); + } +} + +void BaseWorldItemPolyline::removeSubPoints() +{ + for (int i = 0; i < m_listLines.count(); ++i) + delete m_listLines.at(i).itemPoint; + + for (int i = 0; i < m_listItems.count(); ++i) + delete m_listItems.at(i); + + m_listItems.clear(); + m_listLines.clear(); +} + +WorldItemPath::WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent) + : BaseWorldItemPolyline(polygon, parent) +{ + setZValue(WORLD_PATH_LAYER); + + m_pen.setColor(Qt::black); + m_pen.setWidth(3); + m_pen.setJoinStyle(Qt::MiterJoin); + + m_selectedPen.setColor(Qt::white); + m_selectedPen.setWidth(3); + m_selectedPen.setJoinStyle(Qt::MiterJoin); +} + +WorldItemPath::~WorldItemPath() +{ +} + +void WorldItemPath::setColor(const QColor &color) +{ + m_pen.setColor(color); +} + +bool WorldItemPath::removeSubPoint(WorldItemSubPoint *subPoint) +{ + int pos = m_listItems.indexOf(subPoint); + + // First and second points can not be removed + if ((pos == 0) || (pos == m_listItems.size() - 1)) + return false; + + return BaseWorldItemPolyline::removeSubPoint(subPoint); +} + +QPainterPath WorldItemPath::shape() const +{ + QPainterPath path; + + path.moveTo(m_polyline.first()); + for (int i = 1; i < m_polyline.count(); ++i) + path.lineTo(m_polyline.at(i)); + + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +void WorldItemPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + if (isActived()) + painter->setPen(m_selectedPen); + else + painter->setPen(m_pen); + + painter->drawPolyline(m_polyline); +} + + +WorldItemZone::WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent) + : BaseWorldItemPolyline(polygon, parent) +{ + setZValue(WORLD_ZONE_LAYER); + + m_pen.setColor(QColor(20, 100, 255)); + m_pen.setWidth(0); + m_selectedPen.setColor(Qt::white); + m_selectedPen.setWidth(0); + m_brush.setColor(QColor(20, 100, 255, TRANSPARENCY)); + m_brush.setStyle(Qt::SolidPattern); + m_selectedBrush.setColor(QColor(255, 255, 255, 100)); + m_selectedBrush.setStyle(Qt::SolidPattern); +} + +WorldItemZone::~WorldItemZone() +{ +} + +void WorldItemZone::setColor(const QColor &color) +{ + m_pen.setColor(color); + QColor brushColor(color); + brushColor.setAlpha(TRANSPARENCY); + m_brush.setColor(brushColor); +} + +bool WorldItemZone::removeSubPoint(WorldItemSubPoint *subPoint) +{ + if (m_listItems.size() < 4) + return false; + + return BaseWorldItemPolyline::removeSubPoint(subPoint); +} + +QPainterPath WorldItemZone::shape() const +{ + QPainterPath path; + path.addPolygon(m_polyline); + return qt_graphicsItem_shapeFromPath(path, m_pen); +} + +void WorldItemZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + if (isActived()) + { + painter->setPen(m_selectedPen); + painter->setBrush(m_selectedBrush); + } + else + { + painter->setPen(m_pen); + painter->setBrush(m_brush); + } + + painter->drawPolygon(m_polyline); +} + +void WorldItemZone::createSubPoints() +{ + BaseWorldItemPolyline::createSubPoints(); + + LineStruct endLineItem; + endLineItem.itemPoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this); + endLineItem.itemPoint->setPos((m_listItems.first()->pos() + m_listItems.last()->pos()) / 2); + endLineItem.lineItem = LineItem(m_listItems.last(), m_listItems.first()); + m_listLines.push_back(endLineItem); +} + +//******************************************* + +WorldItemSubPoint::WorldItemSubPoint(SubPointType pointType, AbstractWorldItem *parent) + : QGraphicsObject(parent), + m_type(pointType), + m_active(false), + m_parent(parent) +{ + setZValue(WORLD_POINT_LAYER); + + m_brush.setColor(QColor(20, 100, 255)); + m_brush.setStyle(Qt::SolidPattern); + + m_brushMiddle.setColor(QColor(255, 25, 100)); + m_brushMiddle.setStyle(Qt::SolidPattern); + + m_selectedBrush.setColor(QColor(255, 255, 255, 100)); + m_selectedBrush.setStyle(Qt::SolidPattern); + + m_rect.setCoords(-SIZE_POINT, -SIZE_POINT, SIZE_POINT, SIZE_POINT); + updateBoundingRect(); + + //setFlag(ItemIgnoresTransformations); + //setFlag(ItemSendsScenePositionChanges); +} + +WorldItemSubPoint::~WorldItemSubPoint() +{ +} + +void WorldItemSubPoint::setSubPointType(SubPointType nodeType) +{ + m_type = nodeType; + setFlag(ItemSendsScenePositionChanges); +} + +WorldItemSubPoint::SubPointType WorldItemSubPoint::subPointType() const +{ + return m_type; +} + +void WorldItemSubPoint::rotateOn(const QPointF &pivot, const qreal deltaAngle) +{ + prepareGeometryChange(); + + QPolygonF rotatedPolygon(m_rect); + rotatedPolygon.translate(scenePos() - pivot); + + QTransform trans; + trans = trans.rotate(deltaAngle); + rotatedPolygon = trans.map(rotatedPolygon); + rotatedPolygon.translate(pivot); + + setPos(m_parent->mapFromParent(rotatedPolygon.boundingRect().center())); +} + +void WorldItemSubPoint::scaleOn(const QPointF &pivot, const QPointF &factor) +{ + prepareGeometryChange(); + + QPolygonF scaledPolygon(m_rect); + scaledPolygon.translate(scenePos() - pivot); + + QTransform trans; + trans = trans.scale(factor.x(), factor.y()); + scaledPolygon = trans.map(scaledPolygon); + scaledPolygon.translate(pivot); + + setPos(m_parent->mapFromParent(scaledPolygon.boundingRect().center())); +} + +QRectF WorldItemSubPoint::boundingRect() const +{ + return m_boundingRect; +} + +void WorldItemSubPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + painter->setPen(Qt::NoPen); + if (m_type == WorldItemSubPoint::EdgeType) + { + if (isActived()) + painter->setBrush(m_selectedBrush); + else + painter->setBrush(m_brush); + } + else + painter->setBrush(m_brushMiddle); + + // Draw point + painter->drawRect(m_rect); +} + +int WorldItemSubPoint::type() const +{ + return Type; +} + +void WorldItemSubPoint::setActived(bool actived) +{ + m_active = actived; +} + +bool WorldItemSubPoint::isActived() const +{ + return m_active; +} + +QVariant WorldItemSubPoint::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionHasChanged) + m_parent->moveSubPoint(this); + return QGraphicsItem::itemChange(change, value); +} + +void WorldItemSubPoint::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if ((m_type == MiddleType) && (event->button() == Qt::LeftButton)) + { + m_parent->addSubPoint(this); + setSubPointType(EdgeType); + } + else if ((m_type == EdgeType) && (event->button() == Qt::RightButton)) + { + if (m_parent->removeSubPoint(this)) + setSubPointType(MiddleType); + } + update(); +} + +void WorldItemSubPoint::updateBoundingRect() +{ + m_boundingRect.setCoords(-SIZE_POINT, -SIZE_POINT, SIZE_POINT, SIZE_POINT); +} + +} /* namespace WorldEditor */ \ No newline at end of file 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..9752d783d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene_item.h @@ -0,0 +1,298 @@ +// 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 WorldItemSubPoint; + +typedef QPair LineItem; + +struct LineStruct +{ + WorldItemSubPoint *itemPoint; + LineItem lineItem; +}; + +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; + +const int SIZE_ARROW = 20; + +/* +@class AbstractWorldItem +@brief Abstract class for graphics item +@details +*/ +class AbstractWorldItem: public QGraphicsItem +{ +public: + AbstractWorldItem(QGraphicsItem *parent = 0); + virtual ~AbstractWorldItem(); + + enum { Type = QGraphicsItem::UserType + 1 }; + + /// Rotate item around @pivot point on &deltaAngle (deg). + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle) {} + + /// Scales item relatively @pivot point + // TODO: add modes: IgnoreAspectRatio, KeepAspectRatio + virtual void scaleOn(const QPointF &pivot, const QPointF &factor) {} + + /// Rotate arrow on angle (deg). (only for WorldItemPoint) + virtual void turnOn(const qreal angle) {} + virtual void radiusOn(const qreal radius) {} + + /// Change color + virtual void setColor(const QColor &color) {} + + /// Enable/disable the mode edit shape (only for WorldItemPath and WorldItemPath) + virtual void setEnabledSubPoints(bool enabled) {} + + virtual void moveSubPoint(WorldItemSubPoint *subPoint) {} + virtual void addSubPoint(WorldItemSubPoint *subPoint) {} + virtual bool removeSubPoint(WorldItemSubPoint *subPoint) + { + return false; + } + + virtual void setPolygon(const QPolygonF &polygon) {} + virtual QPolygonF polygon() const + { + return QPolygonF(); + } + + void setActived(bool actived); + bool isActived() const; + + void setShapeChanged(bool value); + bool isShapeChanged() const; + + // Enable the use of qgraphicsitem_cast with this item. + int type() const; + +protected: + + bool m_active, m_shapeChanged; +}; + +/* +@class WorldItemPoint +@brief WorldItemPoint class provides a dot item with arrow and circle(@radius) +that you can add to a WorldEditorScene. +@details +*/ +class WorldItemPoint: public AbstractWorldItem +{ +public: + WorldItemPoint(const QPointF &point, const qreal angle, const qreal radius, + bool showArrow, QGraphicsItem *parent = 0); + virtual ~WorldItemPoint(); + + qreal angle() const; + + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle); + virtual void scaleOn(const QPointF &pivot, const QPointF &factor); + virtual void turnOn(const qreal angle); + virtual void radiusOn(const qreal radius); + + virtual void setColor(const QColor &color); + virtual void setEnabledSubPoints(bool enabled) {} + + virtual void setPolygon(const QPolygonF &polygon); + virtual QPolygonF polygon() const; + + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + void createCircle(); + void updateBoundingRect(); + + static const int SIZE_POINT = 2; + + QPen m_pen, m_selectedPen; + QBrush m_brush, m_selectedBrush; + + QPolygonF m_circle; + QVector m_arrow; + QRectF m_rect, m_boundingRect; + qreal m_angle, m_radius; + bool m_showArrow; +}; + +/* +@class BaseWorldItemPolyline +@brief +@details +*/ +class BaseWorldItemPolyline: public AbstractWorldItem +{ +public: + BaseWorldItemPolyline(const QPolygonF &polygon, QGraphicsItem *parent = 0); + virtual ~BaseWorldItemPolyline(); + + virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle); + virtual void scaleOn(const QPointF &pivot, const QPointF &factor); + + virtual void setEnabledSubPoints(bool enabled); + virtual void moveSubPoint(WorldItemSubPoint *subPoint); + virtual void addSubPoint(WorldItemSubPoint *subPoint); + virtual bool removeSubPoint(WorldItemSubPoint *subPoint); + + virtual void setPolygon(const QPolygonF &polygon); + virtual QPolygonF polygon() const; + + virtual QRectF boundingRect() const; + +protected: + virtual void createSubPoints(); + virtual void removeSubPoints(); + + bool m_pointEdit; + QPolygonF m_polyline; + QPen m_pen, m_selectedPen; + + QList m_listItems; + QList m_listLines; +}; + +/* +@class WorldItemPath +@brief WorldItemPath class provides a polyline item that you can add to a WorldEditorScene. +@details +*/ +class WorldItemPath: public BaseWorldItemPolyline +{ +public: + WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent = 0); + virtual ~WorldItemPath(); + + virtual void setColor(const QColor &color); + virtual bool removeSubPoint(WorldItemSubPoint *subPoint); + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + + QPen m_pen, m_selectedPen; +}; + +/* +@class WorldItemZone +@brief The WorldItemZone class provides a polygon item that you can add to a WorldEditorScene. +@details +*/ +class WorldItemZone: public BaseWorldItemPolyline +{ +public: + WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent = 0); + virtual ~WorldItemZone(); + + virtual void setColor(const QColor &color); + virtual bool removeSubPoint(WorldItemSubPoint *subPoint); + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + virtual void createSubPoints(); + +private: + static const int TRANSPARENCY = 38; + + QPen m_pen, m_selectedPen; + QBrush m_brush, m_selectedBrush; +}; + +/* +@class WorldItemSubPoint +@brief +@details +*/ +class WorldItemSubPoint: public QGraphicsObject +{ + Q_OBJECT +public: + enum SubPointType + { + EdgeType = 0, + MiddleType + }; + + enum { Type = QGraphicsItem::UserType + 2 }; + + WorldItemSubPoint(SubPointType pointType, AbstractWorldItem *parent = 0); + virtual ~WorldItemSubPoint(); + + void setSubPointType(SubPointType nodeType); + SubPointType subPointType() const; + + void rotateOn(const QPointF &pivot, const qreal deltaAngle); + void scaleOn(const QPointF &pivot, const QPointF &factor); + + virtual QRectF boundingRect() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + void setActived(bool actived); + bool isActived() const; + + // Enable the use of qgraphicsitem_cast with this item. + int type() const; + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + +private: + void updateBoundingRect(); + + static const int SIZE_POINT = 6; + + QBrush m_brush, m_brushMiddle, m_selectedBrush; + + QRectF m_rect, m_boundingRect; + SubPointType m_type; + bool m_active; + AbstractWorldItem *m_parent; +}; + +} /* namespace WorldEditor */ + +// Enable the use of QVariant with this class. +Q_DECLARE_METATYPE(WorldEditor::AbstractWorldItem *) + +#endif // WORLD_EDITOR_SCENE_ITEM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.cpp new file mode 100644 index 000000000..f3b3e6551 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.cpp @@ -0,0 +1,71 @@ +// 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_settings_page.h" +#include "world_editor_constants.h" + +// Qt includes +#include + +// NeL includes + +namespace WorldEditor +{ + +WorldEditorSettingsPage::WorldEditorSettingsPage(QObject *parent) + : IOptionsPage(parent), + m_currentPage(NULL) +{ +} + +QString WorldEditorSettingsPage::id() const +{ + return QLatin1String(Constants::WORLD_EDITOR_PLUGIN); +} + +QString WorldEditorSettingsPage::trName() const +{ + return tr("General"); +} + +QString WorldEditorSettingsPage::category() const +{ + return QLatin1String(Constants::WORLD_EDITOR_PLUGIN); +} + +QString WorldEditorSettingsPage::trCategory() const +{ + return tr("World Editor"); +} + +QIcon WorldEditorSettingsPage::categoryIcon() const +{ + return QIcon(); +} + +QWidget *WorldEditorSettingsPage::createPage(QWidget *parent) +{ + m_currentPage = new QWidget(parent); + m_ui.setupUi(m_currentPage); + return m_currentPage; +} + +void WorldEditorSettingsPage::apply() +{ +} + +} /* namespace WorldEditor */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.h new file mode 100644 index 000000000..aa7677b9f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.h @@ -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 . + + +#ifndef WORLD_EDITOR_SETTINGS_PAGE_H +#define WORLD_EDITOR_SETTINGS_PAGE_H + +#include + +#include "../core/ioptions_page.h" + +#include "ui_world_editor_settings_page.h" + +class QWidget; + +namespace WorldEditor +{ + +/** +@class WorldEditorSettingsPage +*/ +class WorldEditorSettingsPage : public Core::IOptionsPage +{ + Q_OBJECT +public: + explicit WorldEditorSettingsPage(QObject *parent = 0); + virtual ~WorldEditorSettingsPage() {} + + virtual QString id() const; + virtual QString trName() const; + virtual QString category() const; + virtual QString trCategory() const; + QIcon categoryIcon() const; + virtual QWidget *createPage(QWidget *parent); + + virtual void apply(); + virtual void finish() {} + +private: + QWidget *m_currentPage; + Ui::WorldEditorSettingsPage m_ui; +}; + +} // namespace WorldEditor + +#endif // WORLD_EDITOR_SETTINGS_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.ui new file mode 100644 index 000000000..9219da6c4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_settings_page.ui @@ -0,0 +1,137 @@ + + + WorldEditorSettingsPage + + + false + + + + 0 + 0 + 329 + 239 + + + + Form + + + + 6 + + + 3 + + + + + Workspace + + + + + + Top Left + + + + + + + + + + + + + Bottom Right + + + + + + + + + + + + + Use OpenGL + + + + + + + + + + Ligoscape + + + + + + Cell size + + + + + + + + + + Snap + + + + + + + + + + Ligo class + + + + + + + + + + + + ... + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + 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 new file mode 100644 index 000000000..382b356c0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp @@ -0,0 +1,422 @@ +// 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_window.h" +#include "world_editor_constants.h" +#include "primitives_model.h" +#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" +#include "../core/menu_manager.h" +#include "../core/core_constants.h" + +// Lanscape Editor plugin +#include "../landscape_editor/builder_zone_base.h" + +// NeL includes + +// Qt includes +#include +#include +#include +#include +#include + +namespace WorldEditor +{ + +WorldEditorWindow::WorldEditorWindow(QWidget *parent) + : QMainWindow(parent), + m_primitivesModel(0), + m_undoStack(0), + m_oglWidget(0) +{ + m_ui.setupUi(this); + m_undoStack = new QUndoStack(this); + + m_primitivesModel = new PrimitivesTreeModel(this); + + m_worldEditorScene = new WorldEditorScene(Utils::ligoConfig()->CellSize, m_primitivesModel, m_undoStack, this); + m_zoneBuilderBase = new LandscapeEditor::ZoneBuilderBase(m_worldEditorScene); + + m_worldEditorScene->setZoneBuilder(m_zoneBuilderBase); + m_ui.graphicsView->setScene(m_worldEditorScene); + m_ui.graphicsView->setVisibleText(false); + + m_ui.treePrimitivesView->setModel(m_primitivesModel); + m_ui.treePrimitivesView->setUndoStack(m_undoStack); + m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase); + m_ui.treePrimitivesView->setWorldScene(m_worldEditorScene); + + QActionGroup *sceneModeGroup = new QActionGroup(this); + sceneModeGroup->addAction(m_ui.selectAction); + sceneModeGroup->addAction(m_ui.moveAction); + sceneModeGroup->addAction(m_ui.rotateAction); + sceneModeGroup->addAction(m_ui.scaleAction); + sceneModeGroup->addAction(m_ui.turnAction); + m_ui.selectAction->setChecked(true); + + m_ui.newWorldEditAction->setIcon(QIcon(Core::Constants::ICON_NEW)); + m_ui.saveWorldEditAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + + 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_modeMapper, SIGNAL(mapped(int)), this, SLOT(setMode(int))); + connect(m_ui.pointsAction, SIGNAL(triggered(bool)), m_worldEditorScene, SLOT(setEnabledEditPoints(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())); + connect(m_ui.visibleGridAction, SIGNAL(toggled(bool)), m_ui.graphicsView, SLOT(setVisibleGrid(bool))); + + connect(m_ui.treePrimitivesView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(updateSelection(QItemSelection, QItemSelection))); + + connect(m_worldEditorScene, SIGNAL(updateSelectedItems(QList)), + this, SLOT(selectedItemsInScene(QList))); + + m_statusBarTimer = new QTimer(this); + connect(m_statusBarTimer, SIGNAL(timeout()), this, SLOT(updateStatusBar())); + + m_statusInfo = new QLabel(this); + m_statusInfo->hide(); + Core::ICore::instance()->mainWindow()->statusBar()->addPermanentWidget(m_statusInfo); +} + +WorldEditorWindow::~WorldEditorWindow() +{ + writeSettings(); + + delete m_zoneBuilderBase; +} + +QUndoStack *WorldEditorWindow::undoStack() const +{ + return m_undoStack; +} + +void WorldEditorWindow::maybeSave() +{ + QMessageBox *messageBox = new QMessageBox(tr("World Editor"), + tr("The data has been modified.\n" + "Do you want to save your changes?"), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape, + this, Qt::Sheet); + + messageBox->setButtonText(QMessageBox::Yes, + tr("Save")); + + messageBox->setButtonText(QMessageBox::No, tr("Don't Save")); + + messageBox->show(); +} + +void WorldEditorWindow::open() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL World Edit file"), m_lastDir, + tr("All NeL World Editor file (*.worldedit)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + loadWorldEditFile(fileName); + } + setCursor(Qt::ArrowCursor); +} + +void WorldEditorWindow::loadWorldEditFile(const QString &fileName) +{ + if (m_primitivesModel->isWorldEditNodeLoaded()) + return; + + Utils::WorldEditList worldEditList; + if (!Utils::loadWorldEditFile(fileName.toStdString(), worldEditList)) + { + // TODO: add the message box + return; + } + + m_undoStack->beginMacro(tr("Load %1").arg(fileName)); + + checkCurrentWorld(); + + m_undoStack->push(new CreateWorldCommand(fileName, m_primitivesModel)); + for (size_t i = 0; i < worldEditList.size(); ++i) + { + switch (worldEditList[i].first) + { + case Utils::DataDirectoryType: + m_zoneBuilderBase->init(QString(worldEditList[i].second.c_str()), true); + break; + case Utils::ContextType: + break; + case Utils::LandscapeType: + 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_worldEditorScene, m_primitivesModel, m_ui.treePrimitivesView)); + break; + }; + } + m_undoStack->endMacro(); +} + +void WorldEditorWindow::checkCurrentWorld() +{ +} + +void WorldEditorWindow::newWorldEditFile() +{ + checkCurrentWorld(); + m_undoStack->push(new CreateWorldCommand("NewWorldEdit", m_primitivesModel)); +} + +void WorldEditorWindow::saveWorldEditFile() +{ +} + +void WorldEditorWindow::openProjectSettings() +{ + 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::updateStatusBar() +{ + m_statusInfo->setText(m_worldEditorScene->zoneNameFromMousePos()); +} + +void WorldEditorWindow::updateSelection(const QItemSelection &selected, const QItemSelection &deselected) +{ + m_ui.pointsAction->setChecked(false); + m_worldEditorScene->setEnabledEditPoints(false); + + NodeList nodesSelected; + Q_FOREACH(QModelIndex modelIndex, selected.indexes()) + { + Node *node = static_cast(modelIndex.internalPointer()); + nodesSelected.push_back(node); + } + + NodeList nodesDeselected; + Q_FOREACH(QModelIndex modelIndex, deselected.indexes()) + { + Node *node = static_cast(modelIndex.internalPointer()); + nodesDeselected.push_back(node); + } + + // update property editor + if (nodesSelected.size() > 0) + { + // only single selection + m_ui.propertyEditWidget->updateSelection(nodesSelected.at(0)); + } + else + { + m_ui.propertyEditWidget->clearProperties(); + } + + QList itemSelected; + Q_FOREACH(Node *node, nodesSelected) + { + QGraphicsItem *item = getGraphicsItem(node); + if (item != 0) + itemSelected.push_back(item); + } + + QList itemDeselected; + Q_FOREACH(Node *node, nodesDeselected) + { + QGraphicsItem *item = getGraphicsItem(node); + if (item != 0) + itemDeselected.push_back(item); + } + + // Update world editor scene + m_worldEditorScene->updateSelection(itemSelected, itemDeselected); +} + +void WorldEditorWindow::selectedItemsInScene(const QList &selected) +{ + QItemSelectionModel *selectionModel = m_ui.treePrimitivesView->selectionModel(); + disconnect(m_ui.treePrimitivesView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(updateSelection(QItemSelection, QItemSelection))); + + selectionModel->clear(); + QItemSelection itemSelection; + Q_FOREACH(QGraphicsItem *item, selected) + { + QPersistentModelIndex *index = qvariant_cast(item->data(Constants::NODE_PERISTENT_INDEX)); + if (index->isValid()) + { + QModelIndex modelIndex = index->operator const QModelIndex &(); + QItemSelection mergeItemSelection(modelIndex, modelIndex); + itemSelection.merge(mergeItemSelection, QItemSelectionModel::Select); + } + QApplication::processEvents(); + } + + selectionModel->select(itemSelection, QItemSelectionModel::Select); + + // update property editor + if (!selected.isEmpty()) + { + // only single selection + Node *node = qvariant_cast(selected.at(0)->data(Constants::WORLD_EDITOR_NODE)); + m_ui.propertyEditWidget->updateSelection(node); + } + else + { + m_ui.propertyEditWidget->clearProperties(); + } + + connect(m_ui.treePrimitivesView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(updateSelection(QItemSelection, QItemSelection))); +} + +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() +{ + //Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); +} + +void WorldEditorWindow::createToolBars() +{ + Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); + //QAction *action = menuManager->action(Core::Constants::NEW); + //m_ui.fileToolBar->addAction(action); + + m_ui.fileToolBar->addAction(m_ui.newWorldEditAction); + QAction *action = menuManager->action(Core::Constants::OPEN); + m_ui.fileToolBar->addAction(action); + m_ui.fileToolBar->addAction(m_ui.saveWorldEditAction); + m_ui.fileToolBar->addSeparator(); + + action = menuManager->action(Core::Constants::UNDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + action = menuManager->action(Core::Constants::REDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + //action = menuManager->action(Core::Constants::SAVE); + //m_ui.fileToolBar->addAction(action); + //action = menuManager->action(Core::Constants::SAVE_AS); + //m_ui.fileToolBar->addAction(action); +} + +void WorldEditorWindow::readSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + 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_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::SampleBuffers)); + m_ui.graphicsView->setViewport(m_oglWidget); + } + + settings->endGroup(); +} + +void WorldEditorWindow::writeSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + settings->setValue(Constants::WORLD_WINDOW_STATE, saveState()); + settings->setValue(Constants::WORLD_WINDOW_GEOMETRY, saveGeometry()); + settings->endGroup(); + settings->sync(); +} + +} /* namespace LandscapeEditor */ 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 new file mode 100644 index 000000000..f289e6c2a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h @@ -0,0 +1,95 @@ +// 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_WINDOW_H +#define WORLD_EDITOR_WINDOW_H + +// Project includes +#include "ui_world_editor_window.h" + +// Qt includes +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ +class PrimitivesTreeModel; +class WorldEditorScene; + +class WorldEditorWindow: public QMainWindow +{ + Q_OBJECT + +public: + explicit WorldEditorWindow(QWidget *parent = 0); + ~WorldEditorWindow(); + + QUndoStack *undoStack() const; + void maybeSave(); + +Q_SIGNALS: +public Q_SLOTS: + void open(); + +private Q_SLOTS: + void newWorldEditFile(); + void saveWorldEditFile(); + void openProjectSettings(); + + void setMode(int value); + void updateStatusBar(); + + void updateSelection(const QItemSelection &selected, const QItemSelection &deselected); + void selectedItemsInScene(const QList &selected); + +protected: + virtual void showEvent(QShowEvent *showEvent); + virtual void hideEvent(QHideEvent *hideEvent); + +private: + void createMenus(); + void createToolBars(); + void readSettings(); + void writeSettings(); + + void loadWorldEditFile(const QString &fileName); + void checkCurrentWorld(); + + QString m_lastDir; + + QLabel *m_statusInfo; + QTimer *m_statusBarTimer; + + PrimitivesTreeModel *m_primitivesModel; + QUndoStack *m_undoStack; + WorldEditorScene *m_worldEditorScene; + LandscapeEditor::ZoneBuilderBase *m_zoneBuilderBase; + QSignalMapper m_modeMapper; + QGLWidget *m_oglWidget; + Ui::WorldEditorWindow m_ui; +}; /* class WorldEditorWindow */ + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_WINDOW_H 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 new file mode 100644 index 000000000..d9b6f8ac3 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui @@ -0,0 +1,379 @@ + + + WorldEditorWindow + + + + 0 + 0 + 819 + 600 + + + + MainWindow + + + + :/icons/ic_nel_world_editor.png:/icons/ic_nel_world_editor.png + + + + + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + QPainter::SmoothPixmapTransform + + + QGraphicsView::NoDrag + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::FullViewportUpdate + + + QGraphicsView::DontAdjustForAntialiasing|QGraphicsView::DontClipPainter + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + + + Primitives + + + 2 + + + + + 3 + + + 3 + + + + + true + + + QAbstractItemView::ExtendedSelection + + + true + + + 250 + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + + + + + Property Editor + + + 2 + + + + + + loadPrimitive + + + + + newPrimitive + + + + + + :/icons/ic_nel_zonel.png:/icons/ic_nel_zonel.png + + + loadLand + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Settings + + + + + true + + + false + + + S/H Land + + + + + true + + + false + + + S/H Zone primitives + + + S/H Zone Primitives + + + + + true + + + false + + + S/H Path primitives + + + + + true + + + false + + + S/H Details + + + + + true + + + true + + + true + + + + :/icons/ic_grid.png:/icons/ic_grid.png + + + S/H Grid + + + + + true + + + false + + + S/H Grid points + + + + + New World Edit file + + + + + Save World Edit file + + + + + true + + + + :/icons/ic_nel_select.png:/icons/ic_nel_select.png + + + Select + + + + + true + + + + :/icons/ic_nel_move.png:/icons/ic_nel_move.png + + + Move + + + + + true + + + + :/icons/ic_nel_rotate.png:/icons/ic_nel_rotate.png + + + Rotate + + + + + true + + + + :/icons/ic_nel_scale.png:/icons/ic_nel_scale.png + + + Scale + + + + + true + + + true + + + + :/icons/ic_nel_turn.png:/icons/ic_nel_turn.png + + + Turn + + + + + true + + + true + + + Edit points + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Project settings + + + + + true + + + false + + + S/H Points primitives + + + S/H Points primitives + + + + + + LandscapeEditor::LandscapeView + QGraphicsView +
../landscape_editor/landscape_view.h
+
+ + WorldEditor::PrimitivesView + QTreeView +
primitives_view.h
+
+ + WorldEditor::PropertyEditorWidget + QWidget +
property_editor_widget.h
+ 1 +
+
+ + + + + +