diff --git a/code/nel/src/ligo/zone_bank.cpp b/code/nel/src/ligo/zone_bank.cpp index 28f30db4b..decc50f75 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) @@ -694,6 +697,4 @@ void CZoneBank::getSelection (std::vector &SelectedElements) // *************************************************************************** -} // namespace NLLIGO - -#endif // NL_OS_WINDOWS +} // namespace NLLIGO \ No newline at end of file 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 3b6a61c5e..2f1d58c66 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 @@ -11,9 +11,18 @@ SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin. SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_HDR landscape_editor_plugin.h landscape_editor_window.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) @@ -37,7 +46,7 @@ ADD_LIBRARY(ovqt_plugin_landscape_editor MODULE ${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}) +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) 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..9550b1f76 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.cpp @@ -0,0 +1,456 @@ +// 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 +#include + +namespace LandscapeEditor +{ + +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 makeAZone) +{ + bool bRet = true; + 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)) + { + m_zoneBank.reset(); + return false; + } + } + if ((makeAZone) && (bRet)) + createZoneRegion(); + return bRet; +} + +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(); + nlinfo("ligoMove"); + //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_landscapeItems.empty()) + return; + + // Check zone name + std::string zoneName = m_listZonesWidget->currentZoneName().toStdString(); + if (zoneName.empty()) + return; + + BuilderZoneRegion *builderZoneRegion = m_landscapeItems.at(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) +{ + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; +} + +void ZoneBuilder::delZone(const sint32 posX, const sint32 posY) +{ + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeItems.empty()) + return; + + m_titleAction = QString("Del zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + + BuilderZoneRegion *builderZoneRegion = m_landscapeItems.at(m_currentZoneRegion).builderZoneRegion; + + builderZoneRegion->init(this); + builderZoneRegion->del(posX, posY); + checkEndMacro(); +} + +int ZoneBuilder::createZoneRegion() +{ + int newId = m_landscapeItems.size(); + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.builderZoneRegion = new BuilderZoneRegion(newId); + landItem.builderZoneRegion->init(this); + landItem.rectItem = 0; + + newZone(); + m_landscapeItems.push_back(landItem); + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(newId); + + return newId; +} + +int ZoneBuilder::createZoneRegion(const QString &fileName) +{ + int newId = m_landscapeItems.size(); + 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(newId); + landItem.builderZoneRegion->init(this); + + newZone(); + m_landscapeItems.push_back(landItem); + + m_landscapeScene->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion()); + m_landscapeItems.at(newId).rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(newId); + + return newId; +} + +void ZoneBuilder::deleteZoneRegion(int id) +{ + if ((0 <= id) && (id < int(m_landscapeItems.size()))) + { + if (m_landscapeItems.at(id).rectItem != 0) + delete m_landscapeItems.at(id).rectItem; + m_landscapeScene->delZoneRegion(m_landscapeItems.at(id).zoneRegionObject->ligoZoneRegion()); + delete m_landscapeItems.at(id).zoneRegionObject; + delete m_landscapeItems.at(id).builderZoneRegion; + m_landscapeItems.erase(m_landscapeItems.begin() + id); + calcMask(); + } +} + +void ZoneBuilder::setCurrentZoneRegion(int id) +{ + if ((0 <= id) && (id < int(m_landscapeItems.size()))) + { + if (currentIdZoneRegion() != -1) + { + NLLIGO::CZoneRegion &ligoRegion = m_landscapeItems.at(m_currentZoneRegion).zoneRegionObject->ligoZoneRegion(); + m_landscapeItems.at(m_currentZoneRegion).rectItem = m_landscapeScene->createLayerBlackout(ligoRegion); + } + delete m_landscapeItems.at(id).rectItem; + m_landscapeItems.at(id).rectItem = 0; + m_currentZoneRegion = id; + } +} + +int ZoneBuilder::currentIdZoneRegion() const +{ + return m_currentZoneRegion; +} + +ZoneRegionObject *ZoneBuilder::currentZoneRegion() const +{ + return m_landscapeItems.at(m_currentZoneRegion).zoneRegionObject; +} + +int ZoneBuilder::countZoneRegion() const +{ + return m_landscapeItems.size(); +} + +ZoneRegionObject *ZoneBuilder::zoneRegion(int id) const +{ + return m_landscapeItems.at(id).zoneRegionObject; +} + +void ZoneBuilder::ligoData(LigoData &data, const ZonePosition &zonePos) +{ + m_landscapeItems.at(zonePos.region).zoneRegionObject->ligoData(data, zonePos.x, zonePos.y); +} + +void ZoneBuilder::setLigoData(LigoData &data, const ZonePosition &zonePos) +{ + m_landscapeItems.at(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; +} + +void ZoneBuilder::newZone() +{ + // Select starting point for the moment 0,0 + sint32 x = 0, y = 0; + + // If there are some zone already present increase x until free + for (size_t i = 0; i < m_landscapeItems.size(); ++i) + { + const NLLIGO::CZoneRegion &zoneRegion = m_landscapeItems.at(i).zoneRegionObject->ligoZoneRegion(); + const std::string &zoneName = zoneRegion.getName (x, y); + if ((zoneName != STRING_OUT_OF_BOUND) && (zoneName != STRING_UNUSED)) + { + ++x; + i = -1; + } + } + calcMask(); +} + +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_landscapeItems.size() == 0) + return; + + for (size_t i = 0; i < m_landscapeItems.size(); ++i) + { + const NLLIGO::CZoneRegion ®ion = m_landscapeItems.at(i).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; + + for (size_t i = 0; i < m_landscapeItems.size(); ++i) + if (int(i) != m_currentZoneRegion) + { + const NLLIGO::CZoneRegion ®ion = zoneRegion(i)->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) +{ + for (size_t i = 0; i < m_landscapeItems.size(); ++i) + { + const NLLIGO::CZoneRegion ®ion = m_landscapeItems.at(i).zoneRegionObject->ligoZoneRegion(); + if ((x < region.getMinX()) || (x > region.getMaxX()) || + (y < region.getMinY()) || (y > region.getMaxY())) + continue; + if (region.getName(x, y) != STRING_UNUSED) + { + builderZoneRegionFrom = m_landscapeItems.at(i).builderZoneRegion; + zonePos = ZonePosition(x, y, i); + 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(this, m_landscapeScene); + m_undoStack->push(m_undoScanRegionCommand); + } +} + +void ZoneBuilder::checkEndMacro() +{ + if (m_createdAction) + { + RedoScanRegionCommand *redoScanRegionCommand = new RedoScanRegionCommand(this, m_landscapeScene); + m_undoScanRegionCommand->setScanList(m_zonePositionList); + redoScanRegionCommand->setScanList(m_zonePositionList); + m_undoStack->push(redoScanRegionCommand); + m_undoStack->endMacro(); + } +} + +bool ZoneBuilder::checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion) +{ + for (size_t j = 0; j < m_landscapeItems.size(); ++j) + { + const NLLIGO::CZoneRegion &zoneRegion = m_landscapeItems.at(j).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.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h new file mode 100644 index 000000000..17d5a6f7e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h @@ -0,0 +1,169 @@ +// 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_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; + +// 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 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(); + + /// Init zoneBank and init zone pixmap database + bool init(const QString &pathName, bool bMakeAZone); + + void calcMask(); + void newZone(); + bool getZoneMask (sint32 x, sint32 y); + bool getZoneAmongRegions(ZonePosition &zonePos, BuilderZoneRegion *builderZoneRegionFrom, sint32 x, sint32 y); + + /// Ligo Actions + /// @{ + void actionLigoTile(const LigoData &data, const ZonePosition &zonePos); + void actionLigoMove(uint index, sint32 deltaX, sint32 deltaY); + void actionLigoResize(uint index, sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY); + /// @} + + /// Zone Bricks + /// @{ + void addZone(sint32 posX, sint32 posY); + void addTransition(const sint32 posX, const sint32 posY); + void delZone(const sint32 posX, const sint32 posY); + /// @} + + /// Zone Region + /// @{ + int createZoneRegion(); + int createZoneRegion(const QString &fileName); + void deleteZoneRegion(int id); + void setCurrentZoneRegion(int id); + int currentIdZoneRegion() const; + ZoneRegionObject *currentZoneRegion() const; + int countZoneRegion() const; + ZoneRegionObject *zoneRegion(int id) const; + void 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: + + /// Scan ./zoneligos dir and add all *.ligozone files to zoneBank + bool initZoneBank (const QString &path); + + void checkBeginMacro(); + void checkEndMacro(); + + 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; + + 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_region.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp new file mode 100644 index 000000000..b294ce97b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp @@ -0,0 +1,2112 @@ +// 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_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 (); + 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); + setRot(x + i, y + j, rot); + setFlip(x + i, y + j, flip); + } + + // Put all transitions between different materials + putTransitions (x, y, sMask, curMat, &tUpdate); + + // Place the piece + 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); + setRot(x + i, y + j, rot); + setFlip(x + i, y + j, flip); + } + } +} + +void BuilderZoneRegion::invertCutEdge(sint32 x, sint32 y, uint8 cePos) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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 (); + 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); + setRot (x + i, y + j, rot); + setFlip (x + i, y + j, flip); + } + } + + return true; +} + +void BuilderZoneRegion::addForce (sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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, void *pInt1, void *pInt2) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + ToUpdate *ptCreate = reinterpret_cast(pInt1); + ToUpdate *ptUpdate = reinterpret_cast(pInt2); + 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, + void *pInternal) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + ToUpdate tCreate; // Transition to create + ToUpdate *ptUpdate = reinterpret_cast(pInternal); // Transition to update + + 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 + dataZoneTemp.sharingMatNames[0] = STRING_UNUSED; + dataZoneTemp.sharingMatNames[1] = STRING_UNUSED; + dataZoneTemp.sharingMatNames[2] = STRING_UNUSED; + dataZoneTemp.sharingMatNames[3] = 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) + { + const NLLIGO::CZoneRegion &zoneRegion2 = m_zoneBuilder->zoneRegion(tCreate.getBuilderZoneRegion(m)->getRegionId())->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); + } + for (m = 0; m < (sint32)ptUpdate->size(); ++m) + { + const NLLIGO::CZoneRegion &zoneRegion2 = m_zoneBuilder->zoneRegion(tCreate.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())) + tCreate.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->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) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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, void *pInternal) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->ligoZoneRegion(); + if (!m_zoneBuilder->getZoneMask(x, y)) + return; + + const std::string &nameZone = zoneRegion.getName(x, y); + + ToUpdate *pUpdate = reinterpret_cast(pInternal); + + 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) +{ + const NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->zoneRegion(m_regionId)->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; + m_zoneBuilder->ligoData(dataZoneTemp, zonePosTemp); + 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); + } +} + +} /* 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..63656d643 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.h @@ -0,0 +1,101 @@ +// 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_REGION_H +#define BUILDER_ZONE_REGION_H + +// Project includes + +// NeL includes +#include +#include + +// STL includes +#include +#include +#include + +// Qt includes + +namespace LandscapeEditor +{ +class ZoneBuilder; + +// CZoneRegion contains informations about the zones painted +class BuilderZoneRegion +{ +public: + + 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, void *pInternal = NULL); + 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, void *pInt1, void *pInt2); + + void putTransitions(sint32 x, sint32 y, const NLLIGO::SPiece &mask, const std::string &matName, void *pInternal); + void updateTrans(sint32 x, sint32 y, NLLIGO::CZoneBankElement *zoneBankElement = NULL); + + 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); + + 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/landscape_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp new file mode 100644 index 000000000..4fcf36efe --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp @@ -0,0 +1,236 @@ +// 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 +{ + +OpenLandscapeCommand::OpenLandscapeCommand(const QString &fileName, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName) +{ +} + +OpenLandscapeCommand::~OpenLandscapeCommand() +{ +} + +void OpenLandscapeCommand::undo() +{ +} + +void OpenLandscapeCommand::redo() +{ +} + +NewLandscapeCommand::NewLandscapeCommand(QUndoCommand *parent) + : QUndoCommand(parent) +{ +} + +NewLandscapeCommand::~NewLandscapeCommand() +{ +} + +void NewLandscapeCommand::undo() +{ +} + +void NewLandscapeCommand::redo() +{ +} + +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(ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent) + : QUndoCommand(parent), + m_zoneBuilder(zoneBuilder), + m_scene(scene) +{ +} + +UndoScanRegionCommand::~UndoScanRegionCommand() +{ + m_zonePositionList.clear(); +} + +void UndoScanRegionCommand::setScanList(const QList &zonePositionList) +{ + m_zonePositionList = zonePositionList; +} + +void UndoScanRegionCommand::undo() +{ + 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)); + } +} + +void UndoScanRegionCommand::redo() +{ +} + +RedoScanRegionCommand::RedoScanRegionCommand(ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent) + : QUndoCommand(parent), + m_zoneBuilder(zoneBuilder), + m_scene(scene) +{ +} + +RedoScanRegionCommand::~RedoScanRegionCommand() +{ + m_zonePositionList.clear(); +} + +void RedoScanRegionCommand::setScanList(const QList &zonePositionList) +{ + m_zonePositionList = zonePositionList; +} + +void RedoScanRegionCommand::undo() +{ +} + +void RedoScanRegionCommand::redo() +{ + 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..c4afcc801 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.h @@ -0,0 +1,156 @@ +// 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 OpenLandscapeCommand: public QUndoCommand +{ +public: + OpenLandscapeCommand(const QString &fileName, QUndoCommand *parent = 0); + virtual ~OpenLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: + + QString m_fileName; +}; + +class NewLandscapeCommand: public QUndoCommand +{ +public: + NewLandscapeCommand(QUndoCommand *parent = 0); + virtual ~NewLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: +}; + +// Modify the landscape +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: public QUndoCommand +{ +public: + UndoScanRegionCommand(ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent = 0); + virtual ~UndoScanRegionCommand(); + + void setScanList(const QList &zonePositionList); + virtual void undo(); + virtual void redo(); + +private: + + QList m_zonePositionList; + ZoneBuilder *m_zoneBuilder; + LandscapeScene *m_scene; +}; + +class RedoScanRegionCommand: public QUndoCommand +{ +public: + RedoScanRegionCommand(ZoneBuilder *zoneBuilder, LandscapeScene *scene, QUndoCommand *parent = 0); + virtual ~RedoScanRegionCommand(); + + void setScanList(const QList &zonePositionList); + virtual void undo(); + virtual void redo(); + +private: + + QList m_zonePositionList; + ZoneBuilder *m_zoneBuilder; + LandscapeScene *m_scene; +}; + +/* +// Move the landscape +class LigoMoveCommand: public QUndoCommand +{ +public: + + LigoMoveCommand(int index, sint32 deltaX, sint32 deltaY, ZoneBuilder *zoneBuilder, QUndoCommand *parent = 0); + virtual ~LigoMoveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + int m_index; + sint32 m_deltaX; + sint32 m_deltaY; + ZoneBuilder *m_zoneBuilder; +}; +*/ +// Modify the landscape +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_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h index 52775f4c4..6875ddfab 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 @@ -26,6 +26,8 @@ const char * const LANDSCAPE_EDITOR_PLUGIN = "LandscapeEditor"; //settings const char * const LANDSCAPE_EDITOR_SECTION = "LandscapeEditor"; +const char * const LANDSCAPE_WINDOW_STATE = "LandscapeWindowState"; +const char * const LANDSCAPE_WINDOW_GEOMETRY = "LandscapeWindowGeometry"; //resources const char * const ICON_LANDSCAPE_ITEM = ":/icons/ic_nel_landscape_item.png"; 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..8f9f811cf 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 @@ -91,7 +91,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 4b075adfc..da949fea5 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 @@ -18,6 +18,11 @@ // 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/imenu_manager.h" @@ -28,25 +33,70 @@ // Qt includes #include +#include #include +#include namespace LandscapeEditor { + +static const int LANDSCAPE_ID = 32; +int NewLandCounter = 0; QString _lastDir; LandscapeEditorWindow::LandscapeEditorWindow(QWidget *parent) - : QMainWindow(parent) + : QMainWindow(parent), + m_currentRow(-1), + 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(this); + + m_zoneBuilder = new ZoneBuilder(m_landscapeScene, m_ui.zoneListWidget, m_undoStack); + m_zoneBuilder->init("e:/-nel-/install/continents/newbieland", false); + m_ui.zoneListWidget->setZoneBuilder(m_zoneBuilder); + m_ui.zoneListWidget->updateUi(); + + m_landscapeScene->setZoneBuilder(m_zoneBuilder); + m_ui.graphicsView->setScene(m_landscapeScene); + //m_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer)); + m_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::SampleBuffers)); + m_ui.graphicsView->setViewport(m_oglWidget); + + 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.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.landscapesListWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenu())); + m_ui.landscapesListWidget->setContextMenuPolicy(Qt::CustomContextMenu); + } LandscapeEditorWindow::~LandscapeEditorWindow() { + delete m_zoneBuilder; writeSettings(); } @@ -66,19 +116,252 @@ void LandscapeEditorWindow::open() { 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_currentRow, 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(), false); + 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() +{ + createLandscape(QString()); +} + +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(); + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + if (row == m_currentRow) + { + 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); +} + +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", "Cannot add this zone because it overlaps existing ones"); + return -1; + } + ZoneRegionObject *zoneRegion = m_zoneBuilder->zoneRegion(id); + m_ui.graphicsView->centerOn(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_currentRow != -1) + { + QListWidgetItem *item = m_ui.landscapesListWidget->item(m_currentRow); + item->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_currentRow = row; + } +} + +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(); +} + void LandscapeEditorWindow::createMenus() { Core::IMenuManager *menuManager = Core::ICore::instance()->menuManager(); } +void LandscapeEditorWindow::createToolBars() +{ + Core::IMenuManager *menuManager = Core::ICore::instance()->menuManager(); + //QAction *action = menuManager->action(Core::Constants::NEW); + //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); + + const char * const UNDO = "ObjectViewerQt.Undo"; + const char * const REDO = "ObjectViewerQt.Redo"; + + //action = menuManager->action(Core::Constants::UNDO); + action = menuManager->action(UNDO); + if (action != 0) + m_ui.undoToolBar->addAction(action); + + //action = menuManager->action(Core::Constants::REDO); + action = menuManager->action(REDO); + if (action != 0) + m_ui.undoToolBar->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 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()); settings->endGroup(); } @@ -86,6 +369,8 @@ 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->endGroup(); settings->sync(); } 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..f3421f120 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 @@ -23,10 +23,14 @@ // Qt includes #include +#include namespace LandscapeEditor { +class LandscapeScene; +class ZoneBuilder; + class LandscapeEditorWindow: public QMainWindow { Q_OBJECT @@ -40,14 +44,36 @@ public: Q_SIGNALS: public Q_SLOTS: void open(); + void save(); private Q_SLOTS: + void openProjectSettings(); + void openSnapshotDialog(); + void customContextMenu(); + void newLand(); + void setActiveLand(); + void saveSelectedLand(); + void saveAsSelectedLand(); + void deleteSelectedLand(); + +protected: + virtual void showEvent(QShowEvent *showEvent); + private: void createMenus(); + void createToolBars(); void readSettings(); void writeSettings(); + void setActiveLandscape(int row); + void saveLandscape(int row, bool force); + int createLandscape(const QString &fileName); + + int m_currentRow; + 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..7d71acd49 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,30 @@ + + 3 + + + 3 + - + + + + 0.000000000000000 + 0.000000000000000 + 99999.000000000000000 + 99999.000000000000000 + + + + QGraphicsView::NoDrag + + - + toolBar @@ -35,7 +53,155 @@ false + + + Zones + + + 2 + + + + + + toolBar_2 + + + TopToolBarArea + + + false + + + + + Landscapes + + + 1 + + + + + 3 + + + 3 + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Project settings + + + + + true + + + true + + + EnableGrid + + + Show/Hide Grid + + + Ctrl+G + + + + + 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 + + + + + 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..81a94fb1f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp @@ -0,0 +1,337 @@ +// 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_scene.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#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; + +LandscapeScene::LandscapeScene(QObject *parent) + : QGraphicsScene(parent), + m_mouseX(0.0), + m_mouseY(0.0), + m_zoneBuilder(0) +{ + m_cellSize = 160; +} + +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); + + NLLIGO::CZoneBankElement *zoneBankItem = m_zoneBuilder->getZoneBank().getElementByZoneName(data.zoneName); + + sint32 deltaX = 0, deltaY = 0; + + // Calculate offset for graphics item (for items with size that are larger than 1) + if ((zoneBankItem->getSizeX() > 1) || (zoneBankItem->getSizeY() > 1)) + { + sint32 sizeX = zoneBankItem->getSizeX(), sizeY = zoneBankItem->getSizeY(); + 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); + + return item; +} + +QGraphicsItem *LandscapeScene::createItemEmptyZone(const ZonePosition &zonePos) +{ + if (m_zoneBuilder == 0) + 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); + + 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); + return rectItem; +} + +void LandscapeScene::deleteItemZone(const ZonePosition &zonePos) +{ + QGraphicsItem *item = itemAt(zonePos.x * m_cellSize, abs(zonePos.y) * m_cellSize); + if (item != 0) + { + 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); +} + +void LandscapeScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + if (m_zoneBuilder == 0) + return; + + qreal x = mouseEvent->scenePos().rx(); + qreal y = mouseEvent->scenePos().ry(); + if ((x < 0) || (y < 0)) + return; + + sint32 posX = sint32(floor(x / m_cellSize)); + sint32 posY = sint32(-floor(y / m_cellSize)); + + if (mouseEvent->button() == Qt::LeftButton) + m_zoneBuilder->addZone(posX, posY); + else if (mouseEvent->button() == Qt::RightButton) + m_zoneBuilder->delZone(posX, posY); + + QGraphicsScene::mousePressEvent(mouseEvent); +} + +void LandscapeScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent) +{ + m_mouseX = mouseEvent->scenePos().x(); + m_mouseY = mouseEvent->scenePos().y(); + QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +bool LandscapeScene::checkUnderZone(const int posX, const int posY) +{ + QGraphicsItem *item = itemAt((posX * m_cellSize), abs(posY) * m_cellSize); + if (item != 0) + { + return true; + } + return false; +} + +void LandscapeScene::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsScene::drawForeground(painter, rect); + /* + // Render debug text (slow!) + painter->setPen(QPen(Qt::white, 0.5, Qt::SolidLine)); + + 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)); + + for (int i = left; i < right; ++i) + { + for (int j = top; j < bottom; ++j) + { + LigoData data; + m_zoneBuilder->currentZoneRegion()->ligoData(data, i, -j); + painter->drawText(i * m_cellSize + 10, j * m_cellSize + 10, QString("%1 %2 %3 %4").arg(i).arg(j).arg(data.posX).arg(data.posY)); + } + } + */ +} + +} /* 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..34fe50e05 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h @@ -0,0 +1,77 @@ +// 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 LANDSCAPE_EDITOR_EXPORT LandscapeScene : public QGraphicsScene +{ + Q_OBJECT + +public: + LandscapeScene(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); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void drawForeground(QPainter *painter, const QRectF &rect); + +private: + bool checkUnderZone(const int posX, const int posY); + + int m_cellSize; + qreal m_mouseX, m_mouseY; + ZoneBuilder *m_zoneBuilder; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_SCENE_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..84bc4b47d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp @@ -0,0 +1,142 @@ +// 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_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_moveMouse(false) +{ + setDragMode(ScrollHandDrag); + setTransformationAnchor(AnchorUnderMouse); + setBackgroundBrush(QBrush(Qt::lightGray)); + //setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + //setRenderHints(QPainter::Antialiasing); + //setCacheMode(QGraphicsView::CacheBackground); + m_cellSize = 160; + m_numSteps = 0; + m_maxSteps = 20; +} + +LandscapeView::~LandscapeView() +{ +} + +bool LandscapeView::isVisibleGrid() const +{ + return m_visibleGrid; +} + +void LandscapeView::setVisibleGrid(bool visible) +{ + m_visibleGrid = visible; + + // hack for repaint view + translate(0.0001, 0.0001); +} + +void LandscapeView::wheelEvent(QWheelEvent *event) +{ + double numDegrees = event->delta() / 8.0; + double numSteps = numDegrees / 15.0; + double factor = std::pow(1.125, numSteps); + if (factor > 1.0) + { + // check max scale view + if (m_numSteps > m_maxSteps) + return; + ++m_numSteps; + } + else + { + // check min scale view + if (m_numSteps < -m_maxSteps) + return; + --m_numSteps; + } + scale(factor, factor); + QGraphicsView::wheelEvent(event); +} + +void LandscapeView::mousePressEvent(QMouseEvent *event) +{ + QGraphicsView::mousePressEvent(event); + if (event->button() != Qt::MiddleButton) + return; + m_moveMouse = true; + QApplication::setOverrideCursor(Qt::ClosedHandCursor); +} + +void LandscapeView::mouseMoveEvent(QMouseEvent *event) +{ + if (m_moveMouse) + translate(0.001, 0.001); + QGraphicsView::mouseMoveEvent(event); +} + +void LandscapeView::mouseReleaseEvent(QMouseEvent *event) +{ + QApplication::restoreOverrideCursor(); + m_moveMouse = false; + QGraphicsView::mouseReleaseEvent(event); +} + +void LandscapeView::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsView::drawForeground(painter, rect); + + if (!m_visibleGrid) + return; + + qreal scaleFactor = transform().m11(); + painter->setPen(QPen(Qt::white, 0, Qt::SolidLine)); + + // draw grid + qreal left = m_cellSize * floor(rect.left() / m_cellSize); + qreal top = m_cellSize * floor(rect.top() / m_cellSize); + + // draw vertical lines + while (left < rect.right()) + { + painter->drawLine(int(left), int(rect.bottom()), int(left), int(rect.top())); + left += m_cellSize; + } + + // draw horizontal lines + while (top < rect.bottom()) + { + painter->drawLine(int(rect.left()), int(top), int(rect.right()), int(top)); + top += m_cellSize; + } +} + +} /* 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..2ae251fee --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h @@ -0,0 +1,62 @@ +// 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_VIEW_H +#define LANDSCAPE_VIEW_H + +// Project includes +#include "landscape_editor_global.h" + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +class LANDSCAPE_EDITOR_EXPORT LandscapeView: public QGraphicsView +{ + Q_OBJECT + +public: + LandscapeView(QWidget *parent = 0); + virtual ~LandscapeView(); + + bool isVisibleGrid() const; + +public Q_SLOTS: + void setVisibleGrid(bool visible); + +private Q_SLOTS: +protected: + 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); + +private: + + bool m_visibleGrid; + int m_numSteps, m_maxSteps; + int m_cellSize; + bool m_moveMouse; +}; /* 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..57e8683c0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_model.cpp @@ -0,0 +1,139 @@ +// 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 /* 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..475416887 --- /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 contains the small images for QListView +@details +*/ +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); + + /// Unload all 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..7298bbe3c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/list_zones_widget.h @@ -0,0 +1,84 @@ +// 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_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: + 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 + + + + + + + + + + + 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/pixmap_database.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp new file mode 100644 index 000000000..f0e2859f6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp @@ -0,0 +1,132 @@ +// 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 "pixmap_database.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +PixmapDatabase::PixmapDatabase(int textureSize) + : m_textureSize(textureSize) +{ +} + +PixmapDatabase::~PixmapDatabase() +{ + 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(); + progressDialog->show(); + progressDialog->setRange(0, listNames.size()); + } + + 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 + } + // All pixmaps must be have same size + 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 = 0; + 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..fc90fe180 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h @@ -0,0 +1,69 @@ +// 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 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: + 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 0. + QPixmap *pixmap(const QString &zoneName) const; + + int textureSize() const; + +private: + + int m_textureSize; + 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..3acd3ff66 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp @@ -0,0 +1,61 @@ +// 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 "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..abb93ab81 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.h @@ -0,0 +1,49 @@ +// 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 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..8be20c9aa --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_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/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..1c25a2ace --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/shapshot_dialog.ui @@ -0,0 +1,222 @@ + + + SnapshotDialog + + + + 0 + 0 + 230 + 187 + + + + Snapshot + + + + + + + + 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..ab2579722 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp @@ -0,0 +1,71 @@ +// 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 "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..b66133a07 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.h @@ -0,0 +1,53 @@ +// 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 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: + SnapshotDialog(QWidget *parent = 0); + ~SnapshotDialog(); + + bool isCustomSize() const; + bool isKeepRatio() const; + int resolutionZone() const; + int widthSnapshot() const; + int heightSnapshot() const; + +private Q_SLOTS: + + +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..399d39496 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.cpp @@ -0,0 +1,227 @@ +// 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 +{ + +LigoData::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 LigoData::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]); +} + +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) +{ + /* + nlassert((x >= m_zoneRegion.getMinX()) && + (x <= m_zoneRegion.getMaxX()) && + (y >= m_zoneRegion.getMinY()) && + (y <= m_zoneRegion.getMaxY())); + */ + 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) +{ + /* + nlassert((x >= m_zoneRegion.getMinX()) && + (x <= m_zoneRegion.getMaxX()) && + (y >= m_zoneRegion.getMinY()) && + (y <= m_zoneRegion.getMaxY())); + */ + 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..9081d7002 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.h @@ -0,0 +1,105 @@ +// 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 + +// NeL includes +#include +#include + +// STL includes +#include + +// Qt includes + +namespace LandscapeEditor +{ + +// Data +struct LigoData +{ + uint8 posX; + uint8 posY; + uint8 rot; + uint8 flip; + std::string zoneName; + std::string sharingMatNames[4]; + uint8 sharingCutEdges[4]; + + LigoData(); + + bool operator!= (const LigoData& other) const; +}; + +/** +@class ZoneRegionObject +@brief +@details +*/ +class 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 a ps 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