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/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt index 66cbdb188..8e0a89e22 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt @@ -1,14 +1,15 @@ -ADD_SUBDIRECTORY(core) -ADD_SUBDIRECTORY(example) -ADD_SUBDIRECTORY(ovqt_sheet_builder) +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(example) +ADD_SUBDIRECTORY(ovqt_sheet_builder) ADD_SUBDIRECTORY(landscape_editor) -ADD_SUBDIRECTORY(log) -ADD_SUBDIRECTORY(disp_sheet_id) -ADD_SUBDIRECTORY(object_viewer) -ADD_SUBDIRECTORY(zone_painter) -ADD_SUBDIRECTORY(georges_editor) - -# Ryzom Specific Plugins -IF(WITH_RYZOM AND WITH_RYZOM_TOOLS) - ADD_SUBDIRECTORY(mission_compiler) +ADD_SUBDIRECTORY(log) +ADD_SUBDIRECTORY(disp_sheet_id) +ADD_SUBDIRECTORY(object_viewer) +ADD_SUBDIRECTORY(zone_painter) +ADD_SUBDIRECTORY(georges_editor) + +ADD_SUBDIRECTORY(world_editor) +# Ryzom Specific Plugins +IF(WITH_RYZOM AND WITH_RYZOM_TOOLS) + ADD_SUBDIRECTORY(mission_compiler) ENDIF(WITH_RYZOM AND WITH_RYZOM_TOOLS) \ 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..4681c5d8b 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,19 @@ 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_base.h + landscape_scene.h + list_zones_model.h + list_zones_widget.h + landscape_view.h + project_settings_dialog.h + snapshot_dialog.h ) SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_UIS landscape_editor_window.ui + list_zones_widget.ui + project_settings_dialog.ui + shapshot_dialog.ui ) SET(OVQT_PLUGIN_LANDSCAPE_EDITOR_RCS landscape_editor.qrc) @@ -31,13 +41,13 @@ SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} SOURCE_GROUP("Landscape Editor Plugin" FILES ${SRC}) SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) -ADD_LIBRARY(ovqt_plugin_landscape_editor MODULE ${SRC} +ADD_LIBRARY(ovqt_plugin_landscape_editor SHARED ${SRC} ${OVQT_PLUGIN_LANDSCAPE_EDITOR_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_PLUGIN_LANDSCAPE_EDITOR_UI_HDRS} ${OVQT_PLUGIN_LANDSCAPE_EDITOR_RC_SRCS}) -TARGET_LINK_LIBRARIES(ovqt_plugin_landscape_editor ovqt_plugin_core nelmisc nel3d ${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..62ed76e89 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.cpp @@ -0,0 +1,527 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "builder_zone.h" +#include "list_zones_widget.h" +#include "landscape_actions.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ +int LandCounter = 0; + +ZoneBuilder::ZoneBuilder(LandscapeScene *landscapeScene, ListZonesWidget *listZonesWidget, QUndoStack *undoStack) + : m_currentZoneRegion(-1), + m_pixmapDatabase(0), + m_listZonesWidget(listZonesWidget), + m_landscapeScene(landscapeScene), + m_undoStack(undoStack) +{ + nlassert(m_landscapeScene); + m_pixmapDatabase = new PixmapDatabase(); + m_lastPathName = ""; +} + +ZoneBuilder::~ZoneBuilder() +{ + delete m_pixmapDatabase; +} + +bool ZoneBuilder::init(const QString &pathName, bool displayProgress) +{ + if (pathName.isEmpty()) + return false; + if (pathName != m_lastPathName) + { + m_lastPathName = pathName; + QString zoneBankPath = pathName; + zoneBankPath += "/zoneligos/"; + + // Init the ZoneBank + m_zoneBank.reset(); + if (!initZoneBank (zoneBankPath)) + { + m_zoneBank.reset(); + return false; + } + // Construct the DataBase from the ZoneBank + QString zoneBitmapPath = pathName; + zoneBitmapPath += "/zonebitmaps/"; + m_pixmapDatabase->reset(); + if (!m_pixmapDatabase->loadPixmaps(zoneBitmapPath, m_zoneBank, displayProgress)) + { + m_zoneBank.reset(); + return false; + } + } + return true; +} + +void ZoneBuilder::actionLigoTile(const LigoData &data, const ZonePosition &zonePos) +{ + if (m_undoStack == 0) + return; + + checkBeginMacro(); + nlinfo(QString("%1 %2 %3 (%4 %5)").arg(data.zoneName.c_str()).arg(zonePos.x).arg(zonePos.y).arg(data.posX).arg(data.posY).toStdString().c_str()); + m_zonePositionList.push_back(zonePos); + m_undoStack->push(new LigoTileCommand(data, zonePos, this, m_landscapeScene)); +} + +void ZoneBuilder::actionLigoMove(uint index, sint32 deltaX, sint32 deltaY) +{ + if (m_undoStack == 0) + return; + + checkBeginMacro(); + 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_landscapeMap.empty()) + return; + + // Check zone name + std::string zoneName = m_listZonesWidget->currentZoneName().toStdString(); + if (zoneName.empty()) + return; + + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + builderZoneRegion->init(this); + + uint8 rot = uint8(m_listZonesWidget->currentRot()); + uint8 flip = uint8(m_listZonesWidget->currentFlip()); + + NLLIGO::CZoneBankElement *zoneBankElement = getZoneBank().getElementByZoneName(zoneName); + + m_titleAction = QString("Add zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + m_zonePositionList.clear(); + if (m_listZonesWidget->isForce()) + { + builderZoneRegion->addForce(posX, posY, rot, flip, zoneBankElement); + } + else + { + if (m_listZonesWidget->isNotPropogate()) + builderZoneRegion->addNotPropagate(posX, posY, rot, flip, zoneBankElement); + else + builderZoneRegion->add(posX, posY, rot, flip, zoneBankElement); + } + checkEndMacro(); +} + +void ZoneBuilder::addTransition(const sint32 posX, const sint32 posY) +{ + // Read-only mode + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeMap.empty()) + return; + + m_titleAction = QString("Transition zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + m_zonePositionList.clear(); + + nlinfo(QString("trans %1,%2").arg(posX).arg(posY).toStdString().c_str()); + + sint32 x = (sint32)floor(float(posX) / m_landscapeScene->cellSize()); + sint32 y = (sint32)floor(float(posY) / m_landscapeScene->cellSize()); + sint32 k; + + // Detect if we are in a transition square to switch + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + builderZoneRegion->init(this); + const NLLIGO::CZoneRegion &zoneRegion = currentZoneRegion()->ligoZoneRegion(); + bool bCutEdgeTouched = false; + for (uint8 transPos = 0; transPos < 4; ++transPos) + { + uint ce = zoneRegion.getCutEdge(x, y, transPos); + + if ((ce > 0) && (ce < 3)) + for (k = 0; k < 2; ++k) + { + float xTrans, yTrans; + + if ((transPos == 0) || (transPos == 1)) + { + if (ce == 1) + xTrans = m_landscapeScene->cellSize() / 3.0f; + else + xTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f; + } + else + { + if (transPos == 2) + xTrans = 0; + else + xTrans = m_landscapeScene->cellSize(); + } + xTrans += x * m_landscapeScene->cellSize(); + + if ((transPos == 2) || (transPos == 3)) + { + if (ce == 1) + yTrans = m_landscapeScene->cellSize() / 3.0f; + else + yTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f; + } + else + { + if (transPos == 1) + yTrans = 0; + else + yTrans = m_landscapeScene->cellSize(); + } + yTrans += y * m_landscapeScene->cellSize(); + + if ((posX >= (xTrans - m_landscapeScene->cellSize() / 12.0f)) && + (posX <= (xTrans + m_landscapeScene->cellSize() / 12.0f)) && + (posY >= (yTrans - m_landscapeScene->cellSize() / 12.0f)) && + (posY <= (yTrans + m_landscapeScene->cellSize() / 12.0f))) + { + builderZoneRegion->invertCutEdge (x, y, transPos); + bCutEdgeTouched = true; + } + ce = 3 - ce; + } + } + + // If not clicked to change the cutEdge so the user want to change the transition + if (!bCutEdgeTouched) + { + builderZoneRegion->cycleTransition (x, y); + } + checkEndMacro(); +} + +void ZoneBuilder::delZone(const sint32 posX, const sint32 posY) +{ + if ((m_listZonesWidget == 0) || (m_undoStack == 0)) + return; + + if (m_landscapeMap.empty()) + return; + + m_titleAction = QString("Del zone %1,%2").arg(posX).arg(posY); + m_createdAction = false; + + BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion; + + builderZoneRegion->init(this); + builderZoneRegion->del(posX, posY); + checkEndMacro(); +} + +int ZoneBuilder::createZoneRegion() +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); + landItem.builderZoneRegion->init(this); + landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + + m_landscapeMap.insert(LandCounter, landItem); + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(LandCounter); + + calcMask(); + return LandCounter++; +} + +int ZoneBuilder::createZoneRegion(const QString &fileName) +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.zoneRegionObject->load(fileName.toStdString()); + + if (!checkOverlaps(landItem.zoneRegionObject->ligoZoneRegion())) + { + delete landItem.zoneRegionObject; + return -1; + } + landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); + landItem.builderZoneRegion->init(this); + + m_landscapeScene->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion()); + landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + m_landscapeMap.insert(LandCounter, landItem); + + if (m_currentZoneRegion == -1) + setCurrentZoneRegion(LandCounter); + + calcMask(); + return LandCounter++; +} + +void ZoneBuilder::deleteZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + if (m_landscapeMap.value(id).rectItem != 0) + delete m_landscapeMap.value(id).rectItem; + m_landscapeScene->delZoneRegion(m_landscapeMap.value(id).zoneRegionObject->ligoZoneRegion()); + delete m_landscapeMap.value(id).zoneRegionObject; + delete m_landscapeMap.value(id).builderZoneRegion; + m_landscapeMap.remove(id); + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +void ZoneBuilder::setCurrentZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + if (currentIdZoneRegion() != -1) + { + NLLIGO::CZoneRegion &ligoRegion = m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject->ligoZoneRegion(); + m_landscapeMap[m_currentZoneRegion].rectItem = m_landscapeScene->createLayerBlackout(ligoRegion); + } + delete m_landscapeMap.value(id).rectItem; + m_landscapeMap[id].rectItem = 0; + m_currentZoneRegion = id; + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +int ZoneBuilder::currentIdZoneRegion() const +{ + return m_currentZoneRegion; +} + +ZoneRegionObject *ZoneBuilder::currentZoneRegion() const +{ + return m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject; +} + +int ZoneBuilder::countZoneRegion() const +{ + return m_landscapeMap.size(); +} + +ZoneRegionObject *ZoneBuilder::zoneRegion(int id) const +{ + return m_landscapeMap.value(id).zoneRegionObject; +} + +void ZoneBuilder::ligoData(LigoData &data, const ZonePosition &zonePos) +{ + m_landscapeMap.value(zonePos.region).zoneRegionObject->ligoData(data, zonePos.x, zonePos.y); +} + +void ZoneBuilder::setLigoData(LigoData &data, const ZonePosition &zonePos) +{ + m_landscapeMap.value(zonePos.region).zoneRegionObject->setLigoData(data, zonePos.x, zonePos.y); +} + +bool ZoneBuilder::initZoneBank (const QString &pathName) +{ + QDir *dir = new QDir(pathName); + QStringList filters; + filters << "*.ligozone"; + + // Find all ligozone files in dir + QStringList listFiles = dir->entryList(filters, QDir::Files); + + std::string error; + Q_FOREACH(QString file, listFiles) + { + //nlinfo(file.toStdString().c_str()); + if (!m_zoneBank.addElement((pathName + file).toStdString(), error)) + QMessageBox::critical(0, QObject::tr("Landscape editor"), QString(error.c_str()), QMessageBox::Ok); + } + delete dir; + return true; +} + +PixmapDatabase *ZoneBuilder::pixmapDatabase() const +{ + return m_pixmapDatabase; +} + +QString ZoneBuilder::dataPath() const +{ + return m_lastPathName; +} + +bool ZoneBuilder::getZoneMask(sint32 x, sint32 y) +{ + if ((x < m_minX) || (x > m_maxX) || + (y < m_minY) || (y > m_maxY)) + { + return true; + } + else + { + return m_zoneMask[(x - m_minX) + (y - m_minY) * (1 + m_maxX - m_minX)]; + } +} + +void ZoneBuilder::calcMask() +{ + sint32 x, y; + + m_minY = m_minX = 1000000; + m_maxY = m_maxX = -1000000; + + if (m_landscapeMap.size() == 0) + return; + + QMapIterator i(m_landscapeMap); + while (i.hasNext()) + { + i.next(); + const NLLIGO::CZoneRegion ®ion = i.value().zoneRegionObject->ligoZoneRegion(); + + if (m_minX > region.getMinX()) + m_minX = region.getMinX(); + if (m_minY > region.getMinY()) + m_minY = region.getMinY(); + if (m_maxX < region.getMaxX()) + m_maxX = region.getMaxX(); + if (m_maxY < region.getMaxY()) + m_maxY = region.getMaxY(); + } + + m_zoneMask.resize ((1 + m_maxX - m_minX) * (1 + m_maxY - m_minY)); + sint32 stride = (1 + m_maxX - m_minX); + for (y = m_minY; y <= m_maxY; ++y) + for (x = m_minX; x <= m_maxX; ++x) + { + m_zoneMask[x - m_minX + (y - m_minY) * stride] = true; + + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + if (int(it.key()) != m_currentZoneRegion) + { + const NLLIGO::CZoneRegion ®ion = it.value().zoneRegionObject->ligoZoneRegion(); + + const std::string &rSZone = region.getName (x, y); + if ((rSZone != STRING_OUT_OF_BOUND) && (rSZone != STRING_UNUSED)) + { + m_zoneMask[x - m_minX + (y - m_minY) * stride] = false; + } + } + } + } +} + +bool ZoneBuilder::getZoneAmongRegions(ZonePosition &zonePos, BuilderZoneRegion *builderZoneRegionFrom, sint32 x, sint32 y) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion ®ion = it.value().zoneRegionObject->ligoZoneRegion(); + if ((x < region.getMinX()) || (x > region.getMaxX()) || + (y < region.getMinY()) || (y > region.getMaxY())) + continue; + if (region.getName(x, y) != STRING_UNUSED) + { + builderZoneRegionFrom = it.value().builderZoneRegion; + zonePos = ZonePosition(x, y, it.key()); + return true; + } + } + + // The zone is not present in other region so it is an empty or oob zone of the current region + const NLLIGO::CZoneRegion ®ion = zoneRegion(builderZoneRegionFrom->getRegionId())->ligoZoneRegion(); + if ((x < region.getMinX()) || (x > region.getMaxX()) || + (y < region.getMinY()) || (y > region.getMaxY())) + return false; // Out Of Bound + + zonePos = ZonePosition(x, y, builderZoneRegionFrom->getRegionId()); + return true; +} + +void ZoneBuilder::checkBeginMacro() +{ + if (!m_createdAction) + { + m_createdAction = true; + m_undoStack->beginMacro(m_titleAction); + m_undoScanRegionCommand = new UndoScanRegionCommand(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) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion &zoneRegion = it.value().zoneRegionObject->ligoZoneRegion(); + for (sint32 y = zoneRegion.getMinY(); y <= zoneRegion.getMaxY(); ++y) + for (sint32 x = zoneRegion.getMinX(); x <= zoneRegion.getMaxX(); ++x) + { + const std::string &refZoneName = zoneRegion.getName(x, y); + if (refZoneName != STRING_UNUSED) + { + const std::string &zoneName = newZoneRegion.getName(x, y); + if ((zoneName != STRING_UNUSED) && (zoneName != STRING_OUT_OF_BOUND)) + return false; + } + } + } + return true; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h new file mode 100644 index 000000000..d16008a5f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone.h @@ -0,0 +1,147 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef BUILDER_ZONE_H +#define BUILDER_ZONE_H + +// Project includes +#include "builder_zone_base.h" +#include "builder_zone_region.h" +#include "zone_region_editor.h" +#include "pixmap_database.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ListZonesWidget; +class LandscapeScene; +class UndoScanRegionCommand; + +/** +@class ZoneBuilder +@brief ZoneBuilder contains all the shared data between the tools and the engine. +@details ZoneBank contains the macro zones that is composed of several zones plus a mask. +PixmapDatabase contains the graphics for the zones +*/ +class ZoneBuilder +{ +public: + ZoneBuilder(LandscapeScene *landscapeScene, ListZonesWidget *listZonesWidget = 0, QUndoStack *undoStack = 0); + ~ZoneBuilder(); + + /// Init zoneBank and init zone pixmap database + bool init(const QString &pathName, bool displayProgress = false); + + void calcMask(); + 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(const sint32 posX, const 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; + QMap m_landscapeMap; + + bool m_createdAction; + QString m_titleAction; + QList m_zonePositionList; + UndoScanRegionCommand *m_undoScanRegionCommand; + + PixmapDatabase *m_pixmapDatabase; + NLLIGO::CZoneBank m_zoneBank; + ListZonesWidget *m_listZonesWidget; + LandscapeScene *m_landscapeScene; + QUndoStack *m_undoStack; +}; + +} /* namespace LandscapeEditor */ + +#endif // BUILDER_ZONE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp new file mode 100644 index 000000000..958aee640 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.cpp @@ -0,0 +1,206 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "builder_zone_base.h" +#include "landscape_scene_base.h" +#include "zone_region_editor.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ +int NewLandId = 0; + +ZoneBuilderBase::ZoneBuilderBase(LandscapeSceneBase *landscapeScene) + : m_pixmapDatabase(0), + m_landscapeSceneBase(landscapeScene) +{ + nlassert(m_landscapeSceneBase); + m_pixmapDatabase = new PixmapDatabase(); + m_lastPathName = ""; +} + +ZoneBuilderBase::~ZoneBuilderBase() +{ + delete m_pixmapDatabase; +} + +bool ZoneBuilderBase::init(const QString &pathName, bool displayProgress) +{ + if (pathName.isEmpty()) + return false; + if (pathName != m_lastPathName) + { + m_lastPathName = pathName; + QString zoneBankPath = pathName; + zoneBankPath += "/zoneligos/"; + + // Init the ZoneBank + m_zoneBank.reset(); + if (!initZoneBank (zoneBankPath)) + { + m_zoneBank.reset(); + return false; + } + // Construct the DataBase from the ZoneBank + QString zoneBitmapPath = pathName; + zoneBitmapPath += "/zonebitmaps/"; + m_pixmapDatabase->reset(); + if (!m_pixmapDatabase->loadPixmaps(zoneBitmapPath, m_zoneBank, displayProgress)) + { + m_zoneBank.reset(); + return false; + } + } + return true; +} + +int ZoneBuilderBase::loadZoneRegion(const QString &fileName, int defaultId) +{ + LandscapeItem landItem; + landItem.zoneRegionObject = new ZoneRegionObject(); + landItem.zoneRegionObject->load(fileName.toStdString()); + + if (!checkOverlaps(landItem.zoneRegionObject->ligoZoneRegion())) + { + delete landItem.zoneRegionObject; + return -1; + } + int id = defaultId; + if (id == -1) + id = NewLandId++; +// landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter); +// landItem.builderZoneRegion->init(this); + + m_landscapeSceneBase->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion()); +// landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion()); + m_landscapeMap.insert(id, landItem); + + calcMask(); + return id; +} + +void ZoneBuilderBase::deleteZoneRegion(int id) +{ + if (m_landscapeMap.contains(id)) + { + m_landscapeSceneBase->delZoneRegion(m_landscapeMap.value(id).zoneRegionObject->ligoZoneRegion()); + delete m_landscapeMap.value(id).zoneRegionObject; +// delete m_landscapeMap.value(id).builderZoneRegion; + m_landscapeMap.remove(id); + calcMask(); + } + else + nlwarning("Landscape (id %i) not found", id); +} + +int ZoneBuilderBase::countZoneRegion() const +{ + return m_landscapeMap.size(); +} + +ZoneRegionObject *ZoneBuilderBase::zoneRegion(int id) const +{ + return m_landscapeMap.value(id).zoneRegionObject; +} + +bool ZoneBuilderBase::initZoneBank (const QString &pathName) +{ + QDir *dir = new QDir(pathName); + QStringList filters; + filters << "*.ligozone"; + + // Find all ligozone files in dir + QStringList listFiles = dir->entryList(filters, QDir::Files); + + std::string error; + Q_FOREACH(QString file, listFiles) + { + //nlinfo(file.toStdString().c_str()); + if (!m_zoneBank.addElement((pathName + file).toStdString(), error)) + QMessageBox::critical(0, QObject::tr("Landscape editor"), QString(error.c_str()), QMessageBox::Ok); + } + delete dir; + return true; +} + +PixmapDatabase *ZoneBuilderBase::pixmapDatabase() const +{ + return m_pixmapDatabase; +} + +QString ZoneBuilderBase::dataPath() const +{ + return m_lastPathName; +} + +void ZoneBuilderBase::calcMask() +{ + m_minY = m_minX = 1000000; + m_maxY = m_maxX = -1000000; + + if (m_landscapeMap.size() == 0) + return; + + QMapIterator i(m_landscapeMap); + while (i.hasNext()) + { + i.next(); + const NLLIGO::CZoneRegion ®ion = i.value().zoneRegionObject->ligoZoneRegion(); + + if (m_minX > region.getMinX()) + m_minX = region.getMinX(); + if (m_minY > region.getMinY()) + m_minY = region.getMinY(); + if (m_maxX < region.getMaxX()) + m_maxX = region.getMaxX(); + if (m_maxY < region.getMaxY()) + m_maxY = region.getMaxY(); + } +} + +bool ZoneBuilderBase::checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion) +{ + QMapIterator it(m_landscapeMap); + while (it.hasNext()) + { + it.next(); + const NLLIGO::CZoneRegion &zoneRegion = it.value().zoneRegionObject->ligoZoneRegion(); + for (sint32 y = zoneRegion.getMinY(); y <= zoneRegion.getMaxY(); ++y) + for (sint32 x = zoneRegion.getMinX(); x <= zoneRegion.getMaxX(); ++x) + { + const std::string &refZoneName = zoneRegion.getName(x, y); + if (refZoneName != STRING_UNUSED) + { + const std::string &zoneName = newZoneRegion.getName(x, y); + if ((zoneName != STRING_UNUSED) && (zoneName != STRING_OUT_OF_BOUND)) + return false; + } + } + } + return true; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h new file mode 100644 index 000000000..4c9e501eb --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_base.h @@ -0,0 +1,129 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef BUILDER_ZONE_BASE_H +#define BUILDER_ZONE_BASE_H + +// Project includes +#include "landscape_editor_global.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class LandscapeSceneBase; +class PixmapDatabase; +class ZoneRegionObject; + +// Data +struct ZonePosition +{ + // Absolute position + sint32 x; + sint32 y; + int region; + + ZonePosition() + { + x = 0xffffffff; + y = 0xffffffff; + region = -1; + } + + ZonePosition(const sint32 posX, const sint32 posY, const int id) + { + x = posX; + y = posY; + region = id; + } +}; + +/** +@class 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 LANDSCAPE_EDITOR_EXPORT ZoneBuilderBase +{ +public: + ZoneBuilderBase(LandscapeSceneBase *landscapeScene); + virtual ~ZoneBuilderBase(); + + /// Init zoneBank and init zone pixmap database + bool init(const QString &pathName, bool displayProgress = false); + + /// Zone Region + /// @{ + int loadZoneRegion(const QString &fileName, int defaultId = -1); + void deleteZoneRegion(int id); + int countZoneRegion() const; + ZoneRegionObject *zoneRegion(int id) const; + /// @} + + // Accessors + NLLIGO::CZoneBank &getZoneBank() + { + return m_zoneBank; + } + + PixmapDatabase *pixmapDatabase() const; + + QString dataPath() const; + +private: + + /// Scan ./zoneligos dir and add all *.ligozone files to zoneBank + bool initZoneBank (const QString &path); + + void calcMask(); + + bool checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion); + + struct LandscapeItem + { + ZoneRegionObject *zoneRegionObject; + }; + + sint32 m_minX, m_maxX, m_minY, m_maxY; + + QString m_lastPathName; + + QMap m_landscapeMap; + + PixmapDatabase *m_pixmapDatabase; + NLLIGO::CZoneBank m_zoneBank; + LandscapeSceneBase *m_landscapeSceneBase; +}; + +} /* namespace LandscapeEditor */ + +#endif // BUILDER_ZONE_BASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp new file mode 100644 index 000000000..3f787e6b0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.cpp @@ -0,0 +1,2111 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "builder_zone_region.h" +#include "builder_zone.h" +#include "zone_region_editor.h" + +// NeL includes +#include + +// Qt includes + +namespace LandscapeEditor +{ + +BuilderZoneRegion::BuilderZoneRegion(uint regionId) + : m_regionId(regionId), + m_zoneBuilder(0), + m_firstInit(false) +{ +} + +bool BuilderZoneRegion::init(ZoneBuilder *zoneBuilder) +{ + if (m_firstInit) + return true; + + m_zoneBuilder = zoneBuilder; + + uint32 j, k; + SMatNode mn; + std::vector AllValues; + + // Build the material tree + m_zoneBuilder->getZoneBank().getCategoryValues("material", AllValues); + for (uint32 i = 0; i < AllValues.size(); ++i) + { + mn.Name = AllValues[i]; + m_matTree.push_back(mn); + } + + // Link between materials + AllValues.clear (); + m_zoneBuilder->getZoneBank().getCategoryValues("transname", AllValues); + for (uint32 i = 0; i < AllValues.size(); ++i) + { + // Get the 2 materials linked together + std::string matAstr, matBstr; + for (j = 0; j < AllValues[i].size(); ++j) + { + if (AllValues[i][j] == '-') + break; + else + matAstr += AllValues[i][j]; + } + ++j; + for (; j < AllValues[i].size(); ++j) + matBstr += AllValues[i][j]; + + // Find matA + for (j = 0; j < m_matTree.size(); ++j) + if (m_matTree[j].Name == matAstr) + break; + + if (j < m_matTree.size()) + { + // Find matB + for (k = 0; k < m_matTree.size(); ++k) + if (m_matTree[k].Name == matBstr) + break; + + if (k < m_matTree.size()) + { + // Add a ref to matB in node matA + m_matTree[j].Arcs.push_back(k); + + // Add a ref to matA in node matB + m_matTree[k].Arcs.push_back(j); + } + } + } + + m_firstInit = true; + return true; +} + +class ToUpdate +{ + struct SElement + { + sint32 x, y; + + // Material put into the cell to update + std::string matPut; + + BuilderZoneRegion *builderZoneRegion; + }; + + std::vector m_elements; + +public: + + void add(BuilderZoneRegion *builderZoneRegion, sint32 x, sint32 y, const std::string &matName) + { + bool bFound = false; + for (uint32 m = 0; m < m_elements.size(); ++m) + if ((m_elements[m].x == x) && (m_elements[m].y == y)) + { + bFound = true; + break; + } + if (!bFound) + { + SElement newElement; + newElement.x = x; + newElement.y = y; + newElement.matPut = matName; + newElement.builderZoneRegion = builderZoneRegion; + m_elements.push_back (newElement); + } + } + + void del(sint32 x, sint32 y) + { + bool bFound = false; + uint32 m; + for (m = 0; m < m_elements.size(); ++m) + if ((m_elements[m].x == x) && (m_elements[m].y == y)) + { + bFound = true; + break; + } + if (bFound) + { + for (; m < m_elements.size() - 1; ++m) + m_elements[m] = m_elements[m + 1]; + m_elements.resize (m_elements.size() - 1); + } + } + + uint32 size() + { + return m_elements.size(); + } + + sint32 getX(uint32 m) + { + return m_elements[m].x; + } + + sint32 getY(uint32 m) + { + return m_elements[m].y; + } + + BuilderZoneRegion *getBuilderZoneRegion(uint32 m) + { + return m_elements[m].builderZoneRegion; + } + + const std::string &getMat (uint32 m) + { + return m_elements[m].matPut; + } +}; + +void BuilderZoneRegion::add(sint32 x, sint32 y, uint8 rot, uint8 flip, NLLIGO::CZoneBankElement *zoneBankElement) +{ + sint32 sizeX = zoneBankElement->getSizeX(), sizeY = zoneBankElement->getSizeY(); + sint32 i, j; + NLLIGO::SPiece sMask, sPosX, sPosY; + ToUpdate tUpdate; // Transition to update + + if (!m_zoneBuilder->getZoneMask (x,y)) + return; + + if (zoneBankElement->getCategory("transname") != STRING_NO_CAT_TYPE) + { + addTransition (x, y, rot, flip, zoneBankElement); + return; + } + + // Create the mask in the good rotation and flip + sMask.Tab.resize(sizeX * sizeY); + sPosX.Tab.resize(sizeX * sizeY); + sPosY.Tab.resize(sizeX * sizeY); + + for(j = 0; j < sizeY; ++j) + for(i = 0; i < sizeX; ++i) + { + sPosX.Tab[i + j * sizeX] = (uint8)i; + sPosY.Tab[i + j * sizeX] = (uint8)j; + sMask.Tab[i + j * sizeX] = zoneBankElement->getMask()[i + j * sizeX]; + } + sPosX.w = sPosY.w = sMask.w = sizeX; + sPosX.h = sPosY.h = sMask.h = sizeY; + sMask.rotFlip(rot, flip); + sPosX.rotFlip(rot, flip); + sPosY.rotFlip(rot, flip); + + // Test if the pieces can be put (due to mask) + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + if (m_zoneBuilder->getZoneMask(x + i, y + j) == false) + return; + } + + // Delete all pieces that are under the mask + for (j = 0; j < sMask.h; ++j) + for (i = 0; i < sMask.w; ++i) + if (sMask.Tab[i + j * sMask.w]) + { + del(x + i, y + j, true, &tUpdate); + } + + // Delete all around all material that are not from the same as us + const std::string &curMat = zoneBankElement->getCategory ("material"); + + if (curMat != STRING_NO_CAT_TYPE) + { + // This element is a valid material + // Place the piece + const std::string &eltName = zoneBankElement->getName (); + 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..6de45da50 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/builder_zone_region.h @@ -0,0 +1,100 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef BUILDER_ZONE_REGION_H +#define BUILDER_ZONE_REGION_H + +// Project includes + +// NeL includes +#include +#include + +// STL includes +#include +#include +#include + +// Qt includes + +namespace LandscapeEditor +{ +class ZoneBuilder; + +// 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/icons/ic_grid.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_grid.png new file mode 100644 index 000000000..3534b70ae Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_grid.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png new file mode 100644 index 000000000..99da545b1 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_transition_land.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png new file mode 100644 index 000000000..cdb8230ea Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_nel_zones.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png new file mode 100644 index 000000000..a45143aa4 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/icons/ic_snapshot.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_actions.cpp new file mode 100644 index 000000000..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.qrc b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc index 5dba9074b..2666d8a60 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor.qrc @@ -1,5 +1,9 @@ + icons/ic_nel_zones.png + icons/ic_snapshot.png + icons/ic_grid.png + icons/ic_nel_transition_land.png icons/ic_nel_landscape_item.png icons/ic_nel_landscape_settings.png icons/ic_nel_world_editor.png diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_constants.h index 52775f4c4..76b91dad5 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 @@ -22,13 +22,19 @@ namespace LandscapeEditor { namespace Constants { -const char * const LANDSCAPE_EDITOR_PLUGIN = "LandscapeEditor"; +const char *const LANDSCAPE_EDITOR_PLUGIN = "LandscapeEditor"; //settings -const char * const LANDSCAPE_EDITOR_SECTION = "LandscapeEditor"; +const char *const LANDSCAPE_EDITOR_SECTION = "LandscapeEditor"; +const char *const LANDSCAPE_WINDOW_STATE = "LandscapeWindowState"; +const char *const LANDSCAPE_WINDOW_GEOMETRY = "LandscapeWindowGeometry"; +const char *const LANDSCAPE_DATA_DIRECTORY = "LandscapeDataDirectory"; +const char *const LANDSCAPE_USE_OPENGL = "LandscapeUseOpenGL"; //resources -const char * const ICON_LANDSCAPE_ITEM = ":/icons/ic_nel_landscape_item.png"; +const char *const ICON_LANDSCAPE_ITEM = ":/icons/ic_nel_landscape_item.png"; +const char *const ICON_ZONE_ITEM = ":/icons/ic_nel_zone.png"; +const char *const ICON_LANDSCAPE_ZONES = ":/icons/ic_nel_zones.png"; } // namespace Constants diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp index ac7782343..401256ce6 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_plugin.cpp @@ -75,7 +75,7 @@ QString LandscapeEditorPlugin::name() const QString LandscapeEditorPlugin::version() const { - return "0.0.1"; + return "0.1"; } QString LandscapeEditorPlugin::vendor() const 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..a97dcf380 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,26 +33,78 @@ // Qt includes #include +#include #include +#include +#include namespace LandscapeEditor { + +static const int LANDSCAPE_ID = 32; +int NewLandCounter = 0; QString _lastDir; LandscapeEditorWindow::LandscapeEditorWindow(QWidget *parent) - : QMainWindow(parent) + : QMainWindow(parent), + m_currentItem(0), + m_landscapeScene(0), + m_zoneBuilder(0), + m_undoStack(0), + m_oglWidget(0) { m_ui.setupUi(this); m_undoStack = new QUndoStack(this); + m_landscapeScene = new LandscapeScene(160, this); + + m_zoneBuilder = new ZoneBuilder(m_landscapeScene, m_ui.zoneListWidget, m_undoStack); + m_ui.zoneListWidget->setZoneBuilder(m_zoneBuilder); + m_ui.zoneListWidget->updateUi(); + + m_landscapeScene->setZoneBuilder(m_zoneBuilder); + m_ui.graphicsView->setScene(m_landscapeScene); + + m_ui.newLandAction->setIcon(QIcon(Core::Constants::ICON_NEW)); + m_ui.saveAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + m_ui.saveLandAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + m_ui.saveAsLandAction->setIcon(QIcon(Core::Constants::ICON_SAVE_AS)); + m_ui.zonesDockWidget->toggleViewAction()->setIcon(QIcon(Constants::ICON_LANDSCAPE_ZONES)); + m_ui.landscapesDockWidget->toggleViewAction()->setIcon(QIcon(Constants::ICON_ZONE_ITEM)); + + m_ui.deleteLandAction->setEnabled(false); createMenus(); + createToolBars(); readSettings(); + + connect(m_ui.saveAction, SIGNAL(triggered()), this, SLOT(save())); + connect(m_ui.projectSettingsAction, SIGNAL(triggered()), this, SLOT(openProjectSettings())); + connect(m_ui.snapshotAction, SIGNAL(triggered()), this, SLOT(openSnapshotDialog())); + connect(m_ui.enableGridAction, SIGNAL(toggled(bool)), m_ui.graphicsView, SLOT(setVisibleGrid(bool))); + + connect(m_ui.newLandAction, SIGNAL(triggered()), this, SLOT(newLand())); + connect(m_ui.setActiveLandAction, SIGNAL(triggered()), this, SLOT(setActiveLand())); + connect(m_ui.saveLandAction, SIGNAL(triggered()), this, SLOT(saveSelectedLand())); + connect(m_ui.saveAsLandAction, SIGNAL(triggered()), this, SLOT(saveAsSelectedLand())); + connect(m_ui.deleteLandAction, SIGNAL(triggered()), this, SLOT(deleteSelectedLand())); + connect(m_ui.transitionModeAction, SIGNAL(toggled(bool)), m_landscapeScene, SLOT(setTransitionMode(bool))); + + connect(m_ui.landscapesListWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenu())); + m_ui.landscapesListWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + m_statusBarTimer = new QTimer(this); + connect(m_statusBarTimer, SIGNAL(timeout()), this, SLOT(updateStatusBar())); + + m_statusInfo = new QLabel(this); + m_statusInfo->hide(); + Core::ICore::instance()->mainWindow()->statusBar()->addPermanentWidget(m_statusInfo); } LandscapeEditorWindow::~LandscapeEditorWindow() { writeSettings(); + delete m_zoneBuilder; } QUndoStack *LandscapeEditorWindow::undoStack() const @@ -66,19 +123,281 @@ 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_ui.landscapesListWidget->row(m_currentItem), true); +} + +void LandscapeEditorWindow::openProjectSettings() +{ + ProjectSettingsDialog *dialog = new ProjectSettingsDialog(m_zoneBuilder->dataPath(), this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + m_zoneBuilder->init(dialog->dataPath(), true); + m_ui.zoneListWidget->updateUi(); + } + delete dialog; +} + +void LandscapeEditorWindow::openSnapshotDialog() +{ + SnapshotDialog *dialog = new SnapshotDialog(this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save screenshot landscape"), _lastDir, + tr("Image file (*.png)")); + + setCursor(Qt::WaitCursor); + + NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->currentZoneRegion()->ligoZoneRegion(); + sint32 regionMinX = zoneRegion.getMinX(); + sint32 regionMaxX = zoneRegion.getMaxX(); + sint32 regionMinY = zoneRegion.getMinY(); + sint32 regionMaxY = zoneRegion.getMaxY(); + + int regionWidth = (regionMaxX - regionMinX + 1); + int regionHeight = (regionMaxY - regionMinY + 1); + + int cellSize = m_landscapeScene->cellSize(); + QRectF rect(regionMinX * cellSize, abs(regionMaxY) * cellSize, regionWidth * cellSize, regionHeight * cellSize); + + if (dialog->isCustomSize()) + { + int widthSnapshot = dialog->widthSnapshot(); + int heightSnapshot = dialog->heightSnapshot(); + if (dialog->isKeepRatio()) + heightSnapshot = (widthSnapshot / regionWidth) * regionHeight; + + m_landscapeScene->snapshot(fileName, widthSnapshot, heightSnapshot, rect); + } + else + { + m_landscapeScene->snapshot(fileName, regionWidth * dialog->resolutionZone(), + regionHeight * dialog->resolutionZone(), rect); + } + setCursor(Qt::ArrowCursor); + } + delete dialog; +} + +void LandscapeEditorWindow::customContextMenu() +{ + if (m_ui.landscapesListWidget->currentRow() == -1) + return; + QMenu *popurMenu = new QMenu(this); + popurMenu->addAction(m_ui.setActiveLandAction); + popurMenu->addAction(m_ui.saveLandAction); + popurMenu->addAction(m_ui.saveAsLandAction); + popurMenu->addAction(m_ui.deleteLandAction); + popurMenu->exec(QCursor::pos()); + delete popurMenu; +} + +void LandscapeEditorWindow::newLand() +{ + int row = createLandscape(QString()); + if (row != -1) + setActiveLandscape(row); +} + +void LandscapeEditorWindow::setActiveLand() +{ + setActiveLandscape(m_ui.landscapesListWidget->currentRow()); +} + +void LandscapeEditorWindow::saveSelectedLand() +{ + saveLandscape(m_ui.landscapesListWidget->currentRow(), true); +} + +void LandscapeEditorWindow::saveAsSelectedLand() +{ + saveLandscape(m_ui.landscapesListWidget->currentRow(), false); +} + +void LandscapeEditorWindow::deleteSelectedLand() +{ + int row = m_ui.landscapesListWidget->currentRow(); + int current_row = m_ui.landscapesListWidget->row(m_currentItem); + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + if (row == current_row) + { + if (row == 0) + ++row; + else + --row; + setActiveLandscape(row); + } + m_zoneBuilder->deleteZoneRegion(item->data(LANDSCAPE_ID).toInt()); + m_ui.landscapesListWidget->removeItemWidget(item); + delete item; + + if (m_ui.landscapesListWidget->count() == 1) + m_ui.deleteLandAction->setEnabled(false); + + m_undoStack->clear(); +} + +int LandscapeEditorWindow::createLandscape(const QString &fileName) +{ + int id; + if (fileName.isEmpty()) + id = m_zoneBuilder->createZoneRegion(); + else + id = m_zoneBuilder->createZoneRegion(fileName); + + if (id == -1) + { + QMessageBox::critical(this, "Landscape Editor", "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_currentItem != 0) + m_currentItem->setFont(QFont("SansSerif", 9, QFont::Normal)); + + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + item->setFont(QFont("SansSerif", 9, QFont::Bold)); + m_zoneBuilder->setCurrentZoneRegion(item->data(LANDSCAPE_ID).toInt()); + m_currentItem = item; + } +} + +void LandscapeEditorWindow::saveLandscape(int row, bool force) +{ + if ((0 <= row) && (row < m_ui.landscapesListWidget->count())) + { + QListWidgetItem *item = m_ui.landscapesListWidget->item(row); + ZoneRegionObject *regionObject = m_zoneBuilder->zoneRegion(item->data(LANDSCAPE_ID).toInt()); + if ((!force) || (regionObject->fileName().empty())) + { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save NeL Ligo land file"), _lastDir, + tr("NeL Ligo land file (*.land)")); + if (!fileName.isEmpty()) + { + regionObject->setFileName(fileName.toStdString()); + regionObject->save(); + regionObject->setModified(false); + item->setText(fileName); + } + } + else + { + regionObject->save(); + regionObject->setModified(false); + } + } +} + +void LandscapeEditorWindow::showEvent(QShowEvent *showEvent) +{ + QMainWindow::showEvent(showEvent); + if (m_oglWidget != 0) + m_oglWidget->makeCurrent(); + m_statusInfo->show(); + m_statusBarTimer->start(100); +} + +void LandscapeEditorWindow::hideEvent(QHideEvent *hideEvent) +{ + QMainWindow::hideEvent(hideEvent); + m_statusInfo->hide(); + m_statusBarTimer->stop(); +} + +void LandscapeEditorWindow::updateStatusBar() +{ + m_statusInfo->setText(m_landscapeScene->zoneNameFromMousePos()); +} + void LandscapeEditorWindow::createMenus() { Core::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); + //action = menuManager->action(Core::Constants::SAVE); + //m_ui.fileToolBar->addAction(action); + //action = menuManager->action(Core::Constants::SAVE_AS); + //m_ui.fileToolBar->addAction(action); + + QAction *action = menuManager->action(Core::Constants::OPEN); + m_ui.fileToolBar->addAction(m_ui.newLandAction); + m_ui.fileToolBar->addAction(action); + m_ui.fileToolBar->addAction(m_ui.saveAction); + m_ui.fileToolBar->addSeparator(); + + action = menuManager->action(Core::Constants::UNDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + action = menuManager->action(Core::Constants::REDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + m_ui.zoneToolBar->insertAction(m_ui.enableGridAction, m_ui.landscapesDockWidget->toggleViewAction()); + m_ui.zoneToolBar->insertAction(m_ui.enableGridAction, m_ui.zonesDockWidget->toggleViewAction()); +} + void LandscapeEditorWindow::readSettings() { QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); + restoreState(settings->value(Constants::LANDSCAPE_WINDOW_STATE).toByteArray()); + restoreGeometry(settings->value(Constants::LANDSCAPE_WINDOW_GEOMETRY).toByteArray()); + + // Read landscape data directory (contains sub-paths: zone logos, zone bitmaps) + m_zoneBuilder->init(settings->value(Constants::LANDSCAPE_DATA_DIRECTORY).toString()); + m_ui.zoneListWidget->updateUi(); + + // Use OpenGL graphics system instead raster graphics system + if (settings->value(Constants::LANDSCAPE_USE_OPENGL, false).toBool()) + { + m_oglWidget = new QGLWidget(QGLFormat(QGL::DoubleBuffer)); + m_ui.graphicsView->setViewport(m_oglWidget); + } + settings->endGroup(); } @@ -86,6 +405,9 @@ void LandscapeEditorWindow::writeSettings() { QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup(Constants::LANDSCAPE_EDITOR_SECTION); + settings->setValue(Constants::LANDSCAPE_WINDOW_STATE, saveState()); + settings->setValue(Constants::LANDSCAPE_WINDOW_GEOMETRY, saveGeometry()); + settings->setValue(Constants::LANDSCAPE_DATA_DIRECTORY, m_zoneBuilder->dataPath()); settings->endGroup(); settings->sync(); } 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..67768e39a 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,16 @@ // Qt includes #include +#include +#include +#include namespace LandscapeEditor { +class LandscapeScene; +class ZoneBuilder; + class LandscapeEditorWindow: public QMainWindow { Q_OBJECT @@ -40,14 +46,41 @@ public: Q_SIGNALS: public Q_SLOTS: void open(); + void save(); private Q_SLOTS: + void openProjectSettings(); + void openSnapshotDialog(); + void customContextMenu(); + void updateStatusBar(); + void newLand(); + void setActiveLand(); + void saveSelectedLand(); + void saveAsSelectedLand(); + void deleteSelectedLand(); + +protected: + virtual void showEvent(QShowEvent *showEvent); + virtual void hideEvent(QHideEvent *hideEvent); + private: void createMenus(); + void createToolBars(); void readSettings(); void writeSettings(); + void setActiveLandscape(int row); + void saveLandscape(int row, bool force); + int createLandscape(const QString &fileName); + + QLabel *m_statusInfo; + QTimer *m_statusBarTimer; + + QListWidgetItem *m_currentItem; + LandscapeScene *m_landscapeScene; + ZoneBuilder *m_zoneBuilder; QUndoStack *m_undoStack; + QGLWidget *m_oglWidget; Ui::LandscapeEditorWindow m_ui; }; /* class LandscapeEditorWindow */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui index 5d9606ddf..77133c593 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_editor_window.ui @@ -19,12 +19,42 @@ + + 3 + + + 3 + - + + + + 0.000000000000000 + 0.000000000000000 + 0.000000000000000 + 0.000000000000000 + + + + QGraphicsView::NoDrag + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::FullViewportUpdate + + + QGraphicsView::DontSavePainterState + + - + toolBar @@ -35,7 +65,177 @@ false + + + + :/icons/ic_nel_zones.png:/icons/ic_nel_zones.png + + + Zones + + + 2 + + + + + + + :/icons/ic_nel_zone.png:/icons/ic_nel_zone.png + + + Landscapes + + + 1 + + + + + 3 + + + 3 + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + Project settings + + + + + true + + + true + + + + :/icons/ic_grid.png:/icons/ic_grid.png + + + EnableGrid + + + Show/Hide Grid + + + Ctrl+G + + + + + + :/icons/ic_snapshot.png:/icons/ic_snapshot.png + + + snapshot + + + + + Save + + + + + + :/icons/ic_nel_zone.png:/icons/ic_nel_zone.png + + + Set active + + + Set active selected landscape + + + + + Save + + + Save selected landscape + + + + + Save As landscape + + + Save as selected landscape + + + + + Delete + + + Delete selected landscape + + + + + New + + + Create new landscape + + + + + true + + + + :/icons/ic_nel_landscape_item.png + :/icons/ic_nel_transition_land.png:/icons/ic_nel_landscape_item.png + + + Transition mode + + + Enable transition mode + + + + + LandscapeEditor::ListZonesWidget + QWidget +
list_zones_widget.h
+ 1 +
+ + LandscapeEditor::LandscapeView + QGraphicsView +
landscape_view.h
+
+
diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp new file mode 100644 index 000000000..bb2605b80 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.cpp @@ -0,0 +1,518 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "landscape_scene.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +static const int ZONE_NAME = 0; +static const int LAYER_ZONES = 2; +static const int LAYER_EMPTY_ZONES = 3; +static const int LAYER_BLACKOUT = 4; +const char *const LAYER_BLACKOUT_NAME = "blackout"; + +const int MAX_SCENE_WIDTH = 256; +const int MAX_SCENE_HEIGHT = 256; + +LandscapeScene::LandscapeScene(int sizeCell, QObject *parent) + : QGraphicsScene(parent), + m_cellSize(sizeCell), + m_transitionMode(false), + m_mouseButton(Qt::NoButton), + m_zoneBuilder(0) +{ + setSceneRect(QRectF(0, m_cellSize, MAX_SCENE_WIDTH * m_cellSize, MAX_SCENE_HEIGHT * m_cellSize)); +} + +LandscapeScene::~LandscapeScene() +{ +} + +int LandscapeScene::cellSize() const +{ + return m_cellSize; +} + +void LandscapeScene::setZoneBuilder(ZoneBuilder *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + +QGraphicsItem *LandscapeScene::createItemZone(const LigoData &data, const ZonePosition &zonePos) +{ + if ((data.zoneName == STRING_OUT_OF_BOUND) || (checkUnderZone(zonePos.x, zonePos.y))) + return 0; + + if (data.zoneName == STRING_UNUSED) + return createItemEmptyZone(zonePos); + + if ((m_zoneBuilder == 0) || (data.zoneName.empty())) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(data.zoneName.c_str())); + if (pixmap == 0) + return 0; + + // Rotate the image counterclockwise + QMatrix matrix; + matrix.rotate(-data.rot * 90.0); + + QGraphicsPixmapItem *item; + + if (data.flip == 0) + { + item = addPixmap(pixmap->transformed(matrix, Qt::SmoothTransformation)); + } + else + { + // mirror image + QImage mirrorImage = pixmap->toImage(); + QPixmap mirrorPixmap = QPixmap::fromImage(mirrorImage.mirrored(true, false)); + item = addPixmap(mirrorPixmap.transformed(matrix, Qt::SmoothTransformation)); + } + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + sint32 sizeX = 1, sizeY = 1; + sizeX = float(pixmap->width()) / m_zoneBuilder->pixmapDatabase()->textureSize(); + sizeY = float(pixmap->width()) / m_zoneBuilder->pixmapDatabase()->textureSize(); + + sint32 deltaX = 0, deltaY = 0; + + // Calculate offset for graphics item (for items with size that are larger than 1) + if ((sizeX > 1) || (sizeY > 1)) + { + if (data.flip == 0) + { + switch (data.rot) + { + case 0: + deltaX = -data.posX; + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = -data.posX + sizeX - 1; + break; + case 2: + deltaX = -(sizeX - 1 - data.posX); + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = data.posX; + break; + } + } + else + { + switch (data.rot) + { + case 0: + deltaX = -(sizeX - 1 - data.posX); + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = +data.posX; + break; + case 2: + deltaX = -data.posX; + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = -data.posX + sizeX - 1; + break; + } + } + } + + // Set position graphics item with offset for large piece + item->setPos((zonePos.x + deltaX) * m_cellSize, (abs(int(zonePos.y + deltaY))) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilder->pixmapDatabase()->textureSize()); + + item->setData(ZONE_NAME, QString(data.zoneName.c_str())); + + // for not full item zone + item->setZValue(LAYER_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsItem *LandscapeScene::createItemEmptyZone(const ZonePosition &zonePos) +{ + if (m_zoneBuilder == 0) + return 0; + + if (checkUnderZone(zonePos.x, zonePos.y)) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(STRING_UNUSED)); + + if (pixmap == 0) + return 0; + + QGraphicsPixmapItem *item = addPixmap(*pixmap); + + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + // Set position graphics item + item->setPos(zonePos.x * m_cellSize, abs(int(zonePos.y)) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilder->pixmapDatabase()->textureSize()); + + // for not full item zone + item->setZValue(LAYER_EMPTY_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsRectItem *LandscapeScene::createLayerBlackout(const NLLIGO::CZoneRegion &zoneRegion) +{ + QGraphicsRectItem *rectItem = addRect(zoneRegion.getMinX() * m_cellSize, + abs(zoneRegion.getMaxY()) * m_cellSize, + (abs(zoneRegion.getMaxX() - zoneRegion.getMinX()) + 1) * m_cellSize, + (abs(zoneRegion.getMaxY() - zoneRegion.getMinY()) + 1) * m_cellSize, + Qt::NoPen, QBrush(QColor(0, 0, 0, 50))); + + rectItem->setZValue(LAYER_BLACKOUT); + rectItem->setData(ZONE_NAME, QString(LAYER_BLACKOUT_NAME)); + return rectItem; +} + +void LandscapeScene::deleteItemZone(const ZonePosition &zonePos) +{ + QGraphicsItem *item = itemAt(zonePos.x * m_cellSize, abs(zonePos.y) * m_cellSize); + if ((item != 0) && (item->data(ZONE_NAME).toString() != QString(LAYER_BLACKOUT_NAME))) + { + removeItem(item); + delete item; + } +} + +void LandscapeScene::addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + + std::string zoneName = zoneRegion.getName(i, j); + if (zoneName == STRING_UNUSED) + { + ZonePosition zonePos(i, j, -1); + QGraphicsItem *item = createItemEmptyZone(zonePos); + } + else if (!zoneName.empty()) + { + LigoData data; + ZonePosition zonePos(i, j, -1); + data.zoneName = zoneName; + data.rot = zoneRegion.getRot(i, j); + data.flip = zoneRegion.getFlip(i, j); + data.posX = zoneRegion.getPosX(i, j); + data.posY = zoneRegion.getPosY(i, j); + QGraphicsItem *item = createItemZone(data, zonePos); + } + } + } +} + +void LandscapeScene::delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + deleteItemZone(ZonePosition(i, -j, -1)); + } + } +} + +void LandscapeScene::snapshot(const QString &fileName, int width, int height, const QRectF &landRect) +{ + if (m_zoneBuilder == 0) + return; + + // Create image + QImage image(landRect.width(), landRect.height(), QImage::Format_RGB888); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing, true); + + // Add white background + painter.setBrush(QBrush(Qt::white)); + painter.setPen(Qt::NoPen); + painter.drawRect(0, 0, landRect.width(), landRect.height()); + + // Paint landscape + render(&painter, QRectF(0, 0, landRect.width(), landRect.height()), landRect); + + QImage scaledImage = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + scaledImage.save(fileName); +} + +QString LandscapeScene::zoneNameFromMousePos() const +{ + if ((m_posY > 0) || (m_posY < -MAX_SCENE_HEIGHT) || + (m_posX < 0) || (m_posX > MAX_SCENE_WIDTH)) + return "NOT A VALID ZONE"; + + return QString("%1_%2%3 %4 %5 ").arg(-m_posY).arg(QChar('A' + (m_posX/26))). + arg(QChar('A' + (m_posX%26))).arg(m_mouseX, 0,'f',2).arg(-m_mouseY, 0,'f',2); +} + +void LandscapeScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + if ((x < 0) || (y < 0)) + return; + + m_posX = sint32(floor(x / m_cellSize)); + m_posY = sint32(-floor(y / m_cellSize)); + + if (m_zoneBuilder == 0) + return; + if (m_transitionMode) + { + if (mouseEvent->button() == Qt::LeftButton) + + // Need add offset(= cellSize) on y axes + m_zoneBuilder->addTransition(sint(x), sint(-y + m_cellSize)); + } + else + { + if (mouseEvent->button() == Qt::LeftButton) + m_zoneBuilder->addZone(m_posX, m_posY); + else if (mouseEvent->button() == Qt::RightButton) + m_zoneBuilder->delZone(m_posX, m_posY); + } + m_mouseButton = mouseEvent->button(); + + QGraphicsScene::mousePressEvent(mouseEvent); +} + +void LandscapeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + + sint32 posX = sint32(floor(x / m_cellSize)); + sint32 posY = sint32(-floor(y / m_cellSize)); + + if ((m_posX != posX || m_posY != posY) && + (m_mouseButton == Qt::LeftButton || + m_mouseButton == Qt::RightButton)) + { + if (m_transitionMode) + { + } + else + { + if (m_mouseButton == Qt::LeftButton) + m_zoneBuilder->addZone(posX, posY); + else if (m_mouseButton == Qt::RightButton) + m_zoneBuilder->delZone(posX, posY); + } + m_posX = posX; + m_posY = posY; + QApplication::processEvents(); + } + + m_posX = posX; + m_posY = posY; + + m_mouseX = mouseEvent->scenePos().x(); + m_mouseY = mouseEvent->scenePos().y() - m_cellSize; + QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +void LandscapeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + m_mouseButton = Qt::NoButton; +} + +bool LandscapeScene::checkUnderZone(const int posX, const int posY) +{ + QGraphicsItem *item = itemAt((posX * m_cellSize), abs(posY) * m_cellSize); + if (item != 0) + { + //if (item->data(ZONE_NAME) == QString(LAYER_BLACKOUT_NAME)) + // return false; + //else + return true; + } + return false; +} + +bool LandscapeScene::transitionMode() const +{ + return m_transitionMode; +} + +void LandscapeScene::setTransitionMode(bool enabled) +{ + m_transitionMode = enabled; + update(); +} + +void LandscapeScene::drawForeground(QPainter *painter, const QRectF &rect) +{ + QGraphicsScene::drawForeground(painter, rect); + if ((m_zoneBuilder->currentIdZoneRegion() != -1) && (m_transitionMode)) + drawTransition(painter, rect); + + /* + // 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)); + } + } + */ +} + +void LandscapeScene::drawTransition(QPainter *painter, const QRectF &rect) +{ + int left = int(floor(rect.left() / m_cellSize)); + int right = int(floor(rect.right() / m_cellSize)); + int top = int(floor(rect.top() / m_cellSize)); + int bottom = int(floor(rect.bottom() / m_cellSize)); + + QVector redLines; + QVector whiteLines; + + for (int i = left; i < right + 1; ++i) + { + for (int j = top; j < bottom + 1; ++j) + { + // Get LIGO data + NLLIGO::CZoneRegion &zoneRegion = m_zoneBuilder->currentZoneRegion()->ligoZoneRegion(); + uint8 ceUp = zoneRegion.getCutEdge (i, -j, 0); + uint8 ceLeft = zoneRegion.getCutEdge (i, -j, 2); + if ((ceUp > 0) && (ceUp < 3)) + { + // Calculate position vertical lines + int x1, x2, y1, y2; + + y1 = j * m_cellSize + m_cellSize / 12.0f; + y2 = y1 - (m_cellSize / 6.0f); + + x1 = i * m_cellSize + 3.0f * m_cellSize / 12.0f; + x2 = i * m_cellSize + 5.0f * m_cellSize / 12.0f; + if (ceUp == 1) + { + whiteLines.push_back(QLine(x1, y1, x1, y2)); + whiteLines.push_back(QLine(x2, y1, x2, y2)); + } + else + { + redLines.push_back(QLine(x1, y1, x1, y2)); + redLines.push_back(QLine(x2, y1, x2, y2)); + } + + x1 = i * m_cellSize + 7.0f * m_cellSize / 12.0f; + x2 = i * m_cellSize + 9.0f * m_cellSize / 12.0f; + if (ceUp == 1) + { + redLines.push_back(QLine(x1, y1, x1, y2)); + redLines.push_back(QLine(x2, y1, x2, y2)); + } + else + { + whiteLines.push_back(QLine(x1, y1, x1, y2)); + whiteLines.push_back(QLine(x2, y1, x2, y2)); + } + } + if ((ceLeft > 0) && (ceLeft < 3)) + { + // Calculate position horizontal lines + int x1, x2, y1, y2; + + x1 = i * m_cellSize - m_cellSize / 12.0f; + x2 = x1 + (m_cellSize / 6.0f); + + y1 = j * m_cellSize + 3.0f * m_cellSize / 12.0f; + y2 = j * m_cellSize + 5.0f * m_cellSize / 12.0f; + if (ceLeft == 1) + { + redLines.push_back(QLine(x1, y1, x2, y1)); + redLines.push_back(QLine(x1, y2, x2, y2)); + } + else + { + whiteLines.push_back(QLine(x1, y1, x2, y1)); + whiteLines.push_back(QLine(x1, y2, x2, y2)); + } + + y1 = j * m_cellSize + 7.0f * m_cellSize / 12.0f; + y2 = j * m_cellSize + 9.0f * m_cellSize / 12.0f; + if (ceLeft == 1) + { + whiteLines.push_back(QLine(x1, y1, x2, y1)); + whiteLines.push_back(QLine(x1, y2, x2, y2)); + } + else + { + redLines.push_back(QLine(x1, y1, x2, y1)); + redLines.push_back(QLine(x1, y2, x2, y2)); + } + } + } + } + + // Draw lines + painter->setPen(QPen(Qt::red, 0, Qt::SolidLine)); + painter->drawLines(redLines); + painter->setPen(QPen(Qt::white, 0, Qt::SolidLine)); + painter->drawLines(whiteLines); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h new file mode 100644 index 000000000..612eaca76 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene.h @@ -0,0 +1,89 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef LANDSCAPE_SCENE_H +#define LANDSCAPE_SCENE_H + +// Project includes +#include "zone_region_editor.h" +#include "builder_zone.h" +#include "landscape_editor_global.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LandscapeScene +@brief +@details +*/ +class LandscapeScene : public QGraphicsScene +{ + Q_OBJECT + +public: + LandscapeScene(int sizeCell = 160, QObject *parent = 0); + virtual ~LandscapeScene(); + + int cellSize() const; + void setZoneBuilder(ZoneBuilder *zoneBuilder); + + QGraphicsItem *createItemZone(const LigoData &data, const ZonePosition &zonePos); + QGraphicsItem *createItemEmptyZone(const ZonePosition &zonePos); + QGraphicsRectItem *createLayerBlackout(const NLLIGO::CZoneRegion &zoneRegion); + void deleteItemZone(const ZonePosition &zonePos); + + void addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + void delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + void snapshot(const QString &fileName, int width, int height, const QRectF &landRect); + + QString zoneNameFromMousePos() const; + bool transitionMode() const; + +public Q_SLOTS: + void setTransitionMode(bool enabled); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void drawForeground(QPainter *painter, const QRectF &rect); + + void drawTransition(QPainter *painter, const QRectF &rect); + +private: + bool checkUnderZone(const int posX, const int posY); + + int m_cellSize; + bool m_transitionMode; + qreal m_mouseX, m_mouseY; + sint32 m_posX, m_posY; + Qt::MouseButton m_mouseButton; + ZoneBuilder *m_zoneBuilder; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_SCENE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp new file mode 100644 index 000000000..473b1ad95 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.cpp @@ -0,0 +1,324 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "landscape_scene_base.h" +#include "pixmap_database.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace LandscapeEditor +{ +static const int ZONE_NAME = 0; +static const int LAYER_ZONES = 2; +static const int LAYER_EMPTY_ZONES = 3; + +// TODO: delete +const char *const LAYER_BLACKOUT_NAME = "blackout"; + +const int MAX_SCENE_WIDTH = 256; +const int MAX_SCENE_HEIGHT = 256; + +LandscapeSceneBase::LandscapeSceneBase(int sizeCell, QObject *parent) + : QGraphicsScene(parent), + m_cellSize(sizeCell), + m_zoneBuilderBase(0) +{ + setSceneRect(QRectF(0, m_cellSize, MAX_SCENE_WIDTH * m_cellSize, MAX_SCENE_HEIGHT * m_cellSize)); +} + +LandscapeSceneBase::~LandscapeSceneBase() +{ +} + +int LandscapeSceneBase::cellSize() const +{ + return m_cellSize; +} + +void LandscapeSceneBase::setZoneBuilder(ZoneBuilderBase *zoneBuilder) +{ + m_zoneBuilderBase = zoneBuilder; +} + +QGraphicsItem *LandscapeSceneBase::createItemZone(const LigoData &data, const ZonePosition &zonePos) +{ + if ((data.zoneName == STRING_OUT_OF_BOUND) || (checkUnderZone(zonePos.x, zonePos.y))) + return 0; + + if (data.zoneName == STRING_UNUSED) + return createItemEmptyZone(zonePos); + + if ((m_zoneBuilderBase == 0) || (data.zoneName.empty())) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilderBase->pixmapDatabase()->pixmap(QString(data.zoneName.c_str())); + if (pixmap == 0) + return 0; + + // Rotate the image counter clockwise + QMatrix matrix; + matrix.rotate(-data.rot * 90.0); + + QGraphicsPixmapItem *item; + + if (data.flip == 0) + { + item = addPixmap(pixmap->transformed(matrix, Qt::SmoothTransformation)); + } + else + { + // mirror image + QImage mirrorImage = pixmap->toImage(); + QPixmap mirrorPixmap = QPixmap::fromImage(mirrorImage.mirrored(true, false)); + item = addPixmap(mirrorPixmap.transformed(matrix, Qt::SmoothTransformation)); + } + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + sint32 sizeX = 1, sizeY = 1; + sizeX = float(pixmap->width()) / m_zoneBuilderBase->pixmapDatabase()->textureSize(); + sizeY = float(pixmap->width()) / m_zoneBuilderBase->pixmapDatabase()->textureSize(); + + sint32 deltaX = 0, deltaY = 0; + + // Calculate offset for graphics item (for items with size that are larger than 1) + if ((sizeX > 1) || (sizeY > 1)) + { + if (data.flip == 0) + { + switch (data.rot) + { + case 0: + deltaX = -data.posX; + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = -data.posX + sizeX - 1; + break; + case 2: + deltaX = -(sizeX - 1 - data.posX); + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = data.posX; + break; + } + } + else + { + switch (data.rot) + { + case 0: + deltaX = -(sizeX - 1 - data.posX); + deltaY = -data.posY + sizeY - 1; + break; + case 1: + deltaX = -(sizeY - 1 - data.posY); + deltaY = +data.posX; + break; + case 2: + deltaX = -data.posX; + deltaY = data.posY; + break; + case 3: + deltaX = -data.posY; + deltaY = -data.posX + sizeX - 1; + break; + } + } + } + + // Set position graphics item with offset for large piece + item->setPos((zonePos.x + deltaX) * m_cellSize, (abs(int(zonePos.y + deltaY))) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilderBase->pixmapDatabase()->textureSize()); + + item->setData(ZONE_NAME, QString(data.zoneName.c_str())); + + // for not full item zone + item->setZValue(LAYER_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +QGraphicsItem *LandscapeSceneBase::createItemEmptyZone(const ZonePosition &zonePos) +{ + if (m_zoneBuilderBase == 0) + return 0; + + if (checkUnderZone(zonePos.x, zonePos.y)) + return 0; + + // Get image from pixmap database + QPixmap *pixmap = m_zoneBuilderBase->pixmapDatabase()->pixmap(QString(STRING_UNUSED)); + if (pixmap == 0) + return 0; + + QGraphicsPixmapItem *item = addPixmap(*pixmap); + + // Enable bilinear filtering + item->setTransformationMode(Qt::SmoothTransformation); + + // Set position graphics item + item->setPos(zonePos.x * m_cellSize, abs(int(zonePos.y)) * m_cellSize); + + // The size graphics item should be equal or proportional m_cellSize + item->setScale(float(m_cellSize) / m_zoneBuilderBase->pixmapDatabase()->textureSize()); + + // for not full item zone + item->setZValue(LAYER_EMPTY_ZONES); + + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + return item; +} + +void LandscapeSceneBase::deleteItemZone(const ZonePosition &zonePos) +{ + QGraphicsItem *item = itemAt(zonePos.x * m_cellSize, abs(zonePos.y) * m_cellSize); + + // TODO: delete LAYER_BLACKOUT_NAME + if ((item != 0) && (item->data(ZONE_NAME).toString() != QString(LAYER_BLACKOUT_NAME))) + { + removeItem(item); + delete item; + } +} + +void LandscapeSceneBase::addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + + std::string zoneName = zoneRegion.getName(i, j); + if (zoneName == STRING_UNUSED) + { + ZonePosition zonePos(i, j, -1); + QGraphicsItem *item = createItemEmptyZone(zonePos); + } + else if (!zoneName.empty()) + { + LigoData data; + ZonePosition zonePos(i, j, -1); + data.zoneName = zoneName; + data.rot = zoneRegion.getRot(i, j); + data.flip = zoneRegion.getFlip(i, j); + data.posX = zoneRegion.getPosX(i, j); + data.posY = zoneRegion.getPosY(i, j); + QGraphicsItem *item = createItemZone(data, zonePos); + } + } + } +} + +void LandscapeSceneBase::delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion) +{ + for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i) + { + for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j) + { + deleteItemZone(ZonePosition(i, -j, -1)); + } + } +} + +void LandscapeSceneBase::snapshot(const QString &fileName, int width, int height, const QRectF &landRect) +{ + if (m_zoneBuilderBase == 0) + return; + + // Create image + QImage image(landRect.width(), landRect.height(), QImage::Format_RGB888); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing, true); + + // Add white background + painter.setBrush(QBrush(Qt::white)); + painter.setPen(Qt::NoPen); + painter.drawRect(0, 0, landRect.width(), landRect.height()); + + // Paint landscape + render(&painter, QRectF(0, 0, landRect.width(), landRect.height()), landRect); + + QImage scaledImage = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + scaledImage.save(fileName); +} + +QString LandscapeSceneBase::zoneNameFromMousePos() const +{ + if ((m_posY > 0) || (m_posY < -MAX_SCENE_HEIGHT) || + (m_posX < 0) || (m_posX > MAX_SCENE_WIDTH)) + return "NOT A VALID ZONE"; + + return QString("%1_%2%3 %4 %5 ").arg(-m_posY).arg(QChar('A' + (m_posX/26))). + arg(QChar('A' + (m_posX%26))).arg(m_mouseX, 0,'f',2).arg(-m_mouseY, 0,'f',2); +} + +void LandscapeSceneBase::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mousePressEvent(mouseEvent); + + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + m_posX = sint32(floor(x / m_cellSize)); + m_posY = sint32(-floor(y / m_cellSize)); + + m_mouseButton = mouseEvent->button(); +} + +void LandscapeSceneBase::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + m_mouseX = mouseEvent->scenePos().x(); + m_mouseY = mouseEvent->scenePos().y() - m_cellSize; + + m_posX = sint32(floor(m_mouseX / m_cellSize)); + m_posY = sint32(-floor(m_mouseY / m_cellSize)); + + QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +void LandscapeSceneBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mouseReleaseEvent(mouseEvent); + m_mouseButton = Qt::NoButton; +} + +bool LandscapeSceneBase::checkUnderZone(const int posX, const int posY) +{ + // TODO: it will not work correctly in world editor + QGraphicsItem *item = itemAt((posX * m_cellSize), abs(posY) * m_cellSize); + if (item != 0) + return true; + return false; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h new file mode 100644 index 000000000..acfc0f9f7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_scene_base.h @@ -0,0 +1,81 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef LANDSCAPE_SCENE_BASE_H +#define LANDSCAPE_SCENE_BASE_H + +// Project includes +#include "landscape_editor_global.h" +#include "builder_zone_base.h" +#include "zone_region_editor.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace LandscapeEditor +{ + +/** +@class LandscapeSceneBase +@brief +@details +*/ +class LANDSCAPE_EDITOR_EXPORT LandscapeSceneBase : public QGraphicsScene +{ + Q_OBJECT + +public: + LandscapeSceneBase(int sizeCell = 160, QObject *parent = 0); + virtual ~LandscapeSceneBase(); + + int cellSize() const; + void setZoneBuilder(ZoneBuilderBase *zoneBuilder); + + QGraphicsItem *createItemZone(const LigoData &data, const ZonePosition &zonePos); + QGraphicsItem *createItemEmptyZone(const ZonePosition &zonePos); + void deleteItemZone(const ZonePosition &zonePos); + + void addZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + void delZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + void snapshot(const QString &fileName, int width, int height, const QRectF &landRect); + + QString zoneNameFromMousePos() const; + +public Q_SLOTS: + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + +private: + bool checkUnderZone(const int posX, const int posY); + + int m_cellSize; + qreal m_mouseX, m_mouseY; + sint32 m_posX, m_posY; + Qt::MouseButton m_mouseButton; + ZoneBuilderBase *m_zoneBuilderBase; +}; + +} /* namespace LandscapeEditor */ + +#endif // LANDSCAPE_SCENE_BASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp new file mode 100644 index 000000000..c254fd65d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.cpp @@ -0,0 +1,180 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "landscape_view.h" +#include "landscape_editor_constants.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include + +// Qt includes +#include + +namespace LandscapeEditor +{ + +LandscapeView::LandscapeView(QWidget *parent) + : QGraphicsView(parent), + m_visibleGrid(true), + m_visibleText(true), + 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; + scene()->update(); +} + +void LandscapeView::setVisibleText(bool visible) +{ + m_visibleText = visible; + scene()->update(); +} + +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; + + painter->setPen(QPen(Qt::white, 0, Qt::SolidLine)); + drawGrid(painter, rect); + + if (!m_visibleText) + return; + + if (m_numSteps > -m_maxSteps / 4) + { + painter->setPen(QPen(Qt::white, 0.5, Qt::SolidLine)); + //painter->setFont(QFont("Helvetica [Cronyx]", 12)); + drawZoneNames(painter, rect); + } +} + +void LandscapeView::drawGrid(QPainter *painter, const QRectF &rect) +{ + qreal left = m_cellSize * floor(rect.left() / m_cellSize); + qreal top = m_cellSize * floor(rect.top() / m_cellSize); + + QVector lines; + + // Calculate vertical lines + while (left < rect.right()) + { + lines.push_back(QLine(int(left), int(rect.bottom()), int(left), int(rect.top()))); + left += m_cellSize; + } + + // Calculate horizontal lines + while (top < rect.bottom()) + { + lines.push_back(QLine(int(rect.left()), int(top), int(rect.right()), int(top))); + top += m_cellSize; + } + + // Draw lines + painter->drawLines(lines); +} + +void LandscapeView::drawZoneNames(QPainter *painter, const QRectF &rect) +{ + int leftSide = int(floor(rect.left() / m_cellSize)); + int rightSide = int(floor(rect.right() / m_cellSize)); + int topSide = int(floor(rect.top() / m_cellSize)); + int bottomSide = int(floor(rect.bottom() / m_cellSize)); + + for (int i = leftSide; i < rightSide + 1; ++i) + { + for (int j = topSide; j < bottomSide + 1; ++j) + { + QString text = QString("%1_%2%3").arg(j).arg(QChar('A' + (i / 26))).arg(QChar('A' + (i % 26))); + painter->drawText(i * m_cellSize + 5, j * m_cellSize + 15, text); + } + } +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h new file mode 100644 index 000000000..20e7ee1bc --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/landscape_view.h @@ -0,0 +1,64 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef 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); + void setVisibleText(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); + + void drawGrid(QPainter *painter, const QRectF &rect); + void drawZoneNames(QPainter *painter, const QRectF &rect); +private: + + bool m_visibleGrid, m_visibleText; + 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..6c53ab4bc --- /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 + + + + + + 0° + + + + + 90° + + + + + 180° + + + + + 270° + + + + + Random + + + + + Full cycle + + + + + + + + + NoFlip + + + + + Flip + + + + + Random + + + + + Fyll cycle + + + + + + + + Force + + + + + + + Not propogate + + + + + + + + + + false + + + QAbstractItemView::ScrollPerPixel + + + 1 + + + + + + + + + + + addFilterButton_1 + toggled(bool) + categoryTypeComboBox_2 + setVisible(bool) + + + 20 + 36 + + + 81 + 53 + + + + + addFilterButton_1 + toggled(bool) + categoryValueComboBox_2 + setVisible(bool) + + + 24 + 32 + + + 181 + 50 + + + + + addFilterButton_1 + toggled(bool) + logicComboBox_2 + setVisible(bool) + + + 20 + 31 + + + 301 + 55 + + + + + addFilterButton_2 + toggled(bool) + categoryTypeComboBox_3 + setVisible(bool) + + + 27 + 62 + + + 57 + 75 + + + + + addFilterButton_2 + toggled(bool) + categoryValueComboBox_3 + setVisible(bool) + + + 23 + 58 + + + 156 + 76 + + + + + addFilterButton_2 + toggled(bool) + logicComboBox_3 + setVisible(bool) + + + 23 + 53 + + + 255 + 77 + + + + + addFilterButton_3 + toggled(bool) + categoryTypeComboBox_4 + setVisible(bool) + + + 32 + 94 + + + 44 + 104 + + + + + addFilterButton_3 + toggled(bool) + categoryValueComboBox_4 + setVisible(bool) + + + 32 + 94 + + + 207 + 103 + + + + + addFilterButton_3 + toggled(bool) + logicComboBox_4 + setVisible(bool) + + + 21 + 81 + + + 278 + 104 + + + + + addFilterButton_2 + toggled(bool) + addFilterButton_3 + setVisible(bool) + + + 15 + 59 + + + 16 + 80 + + + + + addFilterButton_1 + toggled(bool) + addFilterButton_2 + setVisible(bool) + + + 13 + 35 + + + 17 + 60 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp new file mode 100644 index 000000000..d3dbd646d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.cpp @@ -0,0 +1,152 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "pixmap_database.h" + +// NeL includes +#include +#include + +// STL includes +#include +#include + +// Qt includes +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ + +PixmapDatabase::PixmapDatabase(int textureSize) + : m_textureSize(textureSize), + m_errorPixmap(0) +{ + m_errorPixmap = new QPixmap(QSize(m_textureSize, m_textureSize)); + QPainter painter(m_errorPixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.fillRect(m_errorPixmap->rect(), QBrush(QColor(Qt::black))); + painter.setFont(QFont("Helvetica [Cronyx]", 14)); + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.drawText(m_errorPixmap->rect(), Qt::AlignCenter | Qt::TextWordWrap, + QObject::tr("Pixmap and LIGO files not found. Set the correct data path and reload landscape.")); + painter.end(); +} + +PixmapDatabase::~PixmapDatabase() +{ + delete m_errorPixmap; + reset(); +} + +bool PixmapDatabase::loadPixmaps(const QString &zonePath, NLLIGO::CZoneBank &zoneBank, bool displayProgress) +{ + QProgressDialog *progressDialog; + std::vector listNames; + zoneBank.getCategoryValues ("zone", listNames); + if (displayProgress) + { + progressDialog = new QProgressDialog("Loading ligo zones.", "Cancel", 0, listNames.size()); + progressDialog->show(); + } + + for (uint i = 0; i < listNames.size(); ++i) + { + QApplication::processEvents(); + + if (displayProgress) + progressDialog->setValue(i); + + NLLIGO::CZoneBankElement *zoneBankItem = zoneBank.getElementByZoneName (listNames[i]); + + // Read the texture file + QString zonePixmapName(listNames[i].c_str()); + uint8 sizeX = zoneBankItem->getSizeX(); + uint8 sizeY = zoneBankItem->getSizeY(); + + QPixmap *pixmap = new QPixmap(zonePath + zonePixmapName + ".png"); + if (pixmap->isNull()) + { + // Generate filled pixmap + QPixmap *emptyPixmap = new QPixmap(QSize(sizeX * m_textureSize, sizeY * m_textureSize)); + QPainter painter(emptyPixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.fillRect(emptyPixmap->rect(), QBrush(QColor(Qt::black))); + painter.setFont(QFont("Helvetica [Cronyx]", 18)); + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.drawText(emptyPixmap->rect(), Qt::AlignCenter, QObject::tr("Pixmap not found")); + painter.end(); + delete pixmap; + m_pixmapMap.insert(zonePixmapName, emptyPixmap); + } + // All pixmaps must be have same size + else if (pixmap->width() != sizeX * m_textureSize) + { + QPixmap *scaledPixmap = new QPixmap(pixmap->scaled(sizeX * m_textureSize, sizeY * m_textureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + delete pixmap; + m_pixmapMap.insert(zonePixmapName, scaledPixmap); + } + else + m_pixmapMap.insert(zonePixmapName, pixmap); + } + + QPixmap *pixmap = new QPixmap(zonePath + "_unused_.png"); + QPixmap *scaledPixmap = new QPixmap(pixmap->scaled(m_textureSize, m_textureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + delete pixmap; + m_pixmapMap.insert(QString(STRING_UNUSED), scaledPixmap); + + if (displayProgress) + delete progressDialog; + + return true; +} + +void PixmapDatabase::reset() +{ + QStringList listNames(m_pixmapMap.keys()); + Q_FOREACH(QString name, listNames) + { + QPixmap *pixmap = m_pixmapMap.value(name); + delete pixmap; + } + m_pixmapMap.clear(); +} + +QStringList PixmapDatabase::listPixmaps() const +{ + return m_pixmapMap.keys(); +} + +QPixmap *PixmapDatabase::pixmap(const QString &zoneName) const +{ + QPixmap *result = m_errorPixmap; + if (!m_pixmapMap.contains(zoneName)) + nlwarning("QPixmap %s not found", zoneName.toStdString().c_str()); + else + result = m_pixmapMap.value(zoneName); + return result; +} + +int PixmapDatabase::textureSize() const +{ + return m_textureSize; +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/pixmap_database.h new file mode 100644 index 000000000..a9d4383ad --- /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) 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; + QPixmap *m_errorPixmap; + QMap m_pixmapMap; +}; + +} /* namespace LandscapeEditor */ + +#endif // PIXMAP_DATABASE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.cpp new file mode 100644 index 000000000..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..e6b2b950a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/project_settings_dialog.h @@ -0,0 +1,50 @@ +// 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" +#include "landscape_editor_global.h" + +// Qt includes + +namespace LandscapeEditor +{ + +class LANDSCAPE_EDITOR_EXPORT 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..66f657012 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/shapshot_dialog.ui @@ -0,0 +1,228 @@ + + + SnapshotDialog + + + + 0 + 0 + 230 + 187 + + + + Snapshot + + + + :/icons/ic_snapshot.png:/icons/ic_snapshot.png + + + + + + + + Original size + + + true + + + + + + + 1024 + + + 128 + + + + + + + + + true + + + Custom size + + + + + + + false + + + + + + + + + 99999 + + + 512 + + + + + + + false + + + Height: + + + heightSpinBox + + + + + + + false + + + 99999 + + + 512 + + + + + + + Width: + + + widthSpinBox + + + + + + + Keep bitmap ratio + + + true + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + originalSizeRadioButton + customSizeRadioButton + widthSpinBox + heightSpinBox + keepRatioCheckBox + buttonBox + + + + + + + buttonBox + accepted() + SnapshotDialog + accept() + + + 227 + 164 + + + 157 + 158 + + + + + buttonBox + rejected() + SnapshotDialog + reject() + + + 276 + 170 + + + 285 + 158 + + + + + customSizeRadioButton + toggled(bool) + groupBox + setEnabled(bool) + + + 59 + 39 + + + 78 + 62 + + + + + keepRatioCheckBox + toggled(bool) + heightSpinBox + setDisabled(bool) + + + 84 + 122 + + + 178 + 106 + + + + + keepRatioCheckBox + toggled(bool) + label_2 + setDisabled(bool) + + + 55 + 129 + + + 48 + 103 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/snapshot_dialog.cpp new file mode 100644 index 000000000..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..a9699acee --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.cpp @@ -0,0 +1,193 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "zone_region_editor.h" + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include + +namespace LandscapeEditor +{ + +ZoneRegionObject::ZoneRegionObject() +{ + m_fileName = ""; +} + +ZoneRegionObject::~ZoneRegionObject() +{ +} + +bool ZoneRegionObject::load(const std::string &fileName) +{ + bool result = true; + try + { + // Open it + NLMISC::CIFile fileIn; + if (fileIn.open(fileName)) + { + NLMISC::CIXml xml(true); + xml.init(fileIn); + m_zoneRegion.serial(xml); + } + else + { + nlwarning("Can't open file %s for reading", fileName.c_str()); + result = false; + } + } + catch (NLMISC::Exception &e) + { + nlwarning("Error reading file %s : %s", fileName.c_str(), e.what ()); + result = false; + } + if (result) + m_fileName = fileName; + return result; +} + +bool ZoneRegionObject::save() +{ + if (m_fileName.empty()) + return false; + + bool result = true; + // Save the landscape + try + { + + // Open file for writing + NLMISC::COFile fileOut; + if (fileOut.open(m_fileName, false, false, true)) + { + // Be careful with the flushing of the COXml object + { + NLMISC::COXml xmlOut; + xmlOut.init(&fileOut); + m_zoneRegion.serial(xmlOut); + // Done + m_modified = false; + } + fileOut.close(); + } + else + { + nlwarning("Can't open file %s for writing.", m_fileName.c_str()); + result = false; + } + } + catch (NLMISC::Exception &e) + { + nlwarning("Error writing file %s : %s", m_fileName.c_str(), e.what()); + result = false; + } + return result; +} + +std::string ZoneRegionObject::fileName() const +{ + return m_fileName; +} + +void ZoneRegionObject::setFileName(const std::string &fileName) +{ + m_fileName = fileName; +} + +void ZoneRegionObject::ligoData(LigoData &data, const sint32 x, const sint32 y) +{ + /* + 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..91b2d66c1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/landscape_editor/zone_region_editor.h @@ -0,0 +1,135 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef LANDSCAPE_EDITOR_H +#define LANDSCAPE_EDITOR_H + +// Project includes +#include "landscape_editor_global.h" + +// NeL includes +#include +#include + +// STL includes +#include + +// 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() + { + posX = 0; + posY = 0; + zoneName = ""; + rot = 0; + flip = 0; + sharingMatNames[0] = ""; + sharingMatNames[1] = ""; + sharingMatNames[2] = ""; + sharingMatNames[3] = ""; + sharingCutEdges[0] = 0; + sharingCutEdges[1] = 0; + sharingCutEdges[2] = 0; + sharingCutEdges[3] = 0; + } + bool operator!= (const LigoData &other) const + { + return (posX != other.posX) || + (posY != other.posY) || + (rot != other.rot) || + (flip != other.flip) || + (zoneName != other.zoneName) || + (sharingMatNames[0] != other.sharingMatNames[0]) || + (sharingMatNames[1] != other.sharingMatNames[1]) || + (sharingMatNames[2] != other.sharingMatNames[2]) || + (sharingMatNames[3] != other.sharingMatNames[3]) || + (sharingCutEdges[0] != other.sharingCutEdges[0]) || + (sharingCutEdges[1] != other.sharingCutEdges[1]) || + (sharingCutEdges[2] != other.sharingCutEdges[2]) || + (sharingCutEdges[3] != other.sharingCutEdges[3]); + } +}; + +/** +@class ZoneRegionObject +@brief +@details +*/ +class LANDSCAPE_EDITOR_EXPORT ZoneRegionObject +{ +public: + ZoneRegionObject(); + ~ZoneRegionObject(); + + /// Load landscape data from file + bool load(const std::string &fileName); + + /// Save landscape data to file (before save, should set file name). + bool save(); + + /// Get ligo data + void ligoData(LigoData &data, const sint32 x, const sint32 y); + + /// Set ligo data + void setLigoData(const LigoData &data, const sint32 x, const sint32 y); + + /// Get file name + std::string fileName() const; + + /// Set file name, use for saving data in file + void setFileName(const std::string &fileName); + + /// Accessor to LIGO CZoneRegion + NLLIGO::CZoneRegion &ligoZoneRegion(); + + void setLigoZoneRegion(const NLLIGO::CZoneRegion &zoneRegion); + + /// Check position, it belongs to the landscape + bool checkPos(const sint32 x, const sint32 y); + + /// Helper flag to know if 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 diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt new file mode 100644 index 000000000..1e41175bd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/CMakeLists.txt @@ -0,0 +1,51 @@ +INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${QT_INCLUDES}) + +FILE(GLOB SRC *.cpp *.h) + +SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) + +SET(OVQT_PLUGIN_WORLD_EDITOR_HDR world_editor_plugin.h + world_editor_window.h + world_editor_scene.h + primitives_model.h + primitives_view.h +) + +SET(OVQT_PLUGIN_WORLD_EDITOR_UIS world_editor_window.ui +) + +SET(OVQT_PLUGIN_WORLD_EDITOR_RCS world_editor.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES(OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS ${OVQT_PLUGIN_WORLD_EDITOR_RCS}) +QT4_WRAP_CPP(OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC ${OVQT_PLUGIN_WORLD_EDITOR_HDR}) +QT4_WRAP_UI(OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS ${OVQT_PLUGIN_WORLD_EDITOR_UIS}) + +SOURCE_GROUP(QtResources FILES ${OVQT_PLUGIN_WORLD_EDITOR_UIS}) +SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS}) +SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC} OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS) +SOURCE_GROUP("World Editor Plugin" FILES ${SRC}) +SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) + +ADD_LIBRARY(ovqt_plugin_world_editor MODULE ${SRC} + ${OVQT_PLUGIN_WORLD_EDITOR_MOC_SRC} + ${OVQT_EXT_SYS_SRC} + ${OVQT_PLUGIN_WORLD_EDITOR_UI_HDRS} + ${OVQT_PLUGIN_WORLD_EDITOR_RC_SRCS}) + +TARGET_LINK_LIBRARIES(ovqt_plugin_world_editor ovqt_plugin_core ovqt_plugin_landscape_editor nelmisc nel3d ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY}) + +NL_DEFAULT_PROPS(ovqt_plugin_world_editor "NeL, Tools, 3D: Object Viewer Qt Plugin: World Editor") +NL_ADD_RUNTIME_FLAGS(ovqt_plugin_world_editor) +NL_ADD_LIB_SUFFIX(ovqt_plugin_world_editor) + +ADD_DEFINITIONS(-DWORLD_EDITOR_LIBRARY ${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) + +INSTALL(TARGETS ovqt_plugin_world_editor LIBRARY DESTINATION lib RUNTIME DESTINATION bin ARCHIVE DESTINATION lib COMPONENT tools3d) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png new file mode 100644 index 000000000..7039bd070 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_move.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png new file mode 100644 index 000000000..73a0be2fe Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_rotate.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png new file mode 100644 index 000000000..e76150ab4 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_scale.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png new file mode 100644 index 000000000..9a677b8a6 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_select.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png new file mode 100644 index 000000000..b03cb0fd0 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_turn.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png new file mode 100644 index 000000000..d41f64e2f Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/icons/ic_nel_world_editor.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp new file mode 100644 index 000000000..e948f8b0f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp @@ -0,0 +1,257 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "primitive_item.h" +#include "world_editor_misc.h" +#include "world_editor_constants.h" + +#include "../landscape_editor/landscape_editor_constants.h" + +// NeL includes +#include + +// Qt includes +#include +#include + +namespace WorldEditor +{ + +Node::Node() + : m_parent(0) +{ +} + +Node::~Node() +{ + if (m_parent) + m_parent->removeChildNode(this); + + qDeleteAll(m_children); + nlassert(m_children.isEmpty()); + m_data.clear(); +} + +void Node::prependChildNode(Node *node) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.prepend(node); + node->m_parent = this; +} + +void Node::appendChildNode(Node *node) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.append(node); + node->m_parent = this; +} + +void Node::insertChildNodeBefore(Node *node, Node *before) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = before ? m_children.indexOf(before) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx, node); + node->m_parent = this; +} + +void Node::insertChildNodeAfter(Node *node, Node *after) +{ + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = after ? m_children.indexOf(after) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx + 1, node); + node->m_parent = this; +} + +void Node::removeChildNode(Node *node) +{ + nlassert(m_children.contains(node)); + nlassert(node->parent() == this); + + m_children.removeOne(node); + + node->m_parent = 0; +} + +Node *Node::child(int row) +{ + return m_children.at(row); +} + +int Node::childCount() const +{ + return m_children.count(); +} + +QVariant Node::data(int key) const +{ + return m_data[key]; +} + +void Node::setData(int key, const QVariant &data) +{ + m_data[key] = data; +} + +Node *Node::parent() +{ + return m_parent; +} + +int Node::row() const +{ + if (m_parent) + return m_parent->m_children.indexOf(const_cast(this)); + + return 0; +} + +Node::NodeType Node::type() const +{ + return BasicNodeType; +} + +WorldEditNode::WorldEditNode(const QString &name) +{ + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(Constants::ICON_WORLD_EDITOR)); +} + +WorldEditNode::~WorldEditNode() +{ +} + +Node::NodeType WorldEditNode::type() const +{ + return WorldEditNodeType; +} + +LandscapeNode::LandscapeNode(const QString &name) +{ + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); +} + +LandscapeNode::~LandscapeNode() +{ +} + +Node::NodeType LandscapeNode::type() const +{ + return LandscapeNodeType; +} + +PrimitiveNode::PrimitiveNode(NLLIGO::IPrimitive *primitive) + : m_primitive(primitive) +{ + setData(Qt::DisplayRole, QString(m_primitive->getName().c_str())); + setData(Qt::ToolTipRole, QString(m_primitive->getClassName().c_str())); + + std::string className; + m_primitive->getPropertyByName("class", className); + + // Set Icon + QString nameIcon = QString("./old_ico/%1.ico").arg(className.c_str()); + QIcon icon(nameIcon); + if (!QFile::exists(nameIcon)) + { + if (primitive->getParent() == NULL) + icon = QIcon("./old_ico/root.ico"); + else if (primitive->getNumChildren() == 0) + icon = QIcon("./old_ico/property.ico"); + else + icon = QIcon("./old_ico/folder_h.ico"); + } + setData(Qt::DecorationRole, icon); + + //setData(3, QString(className.c_str())); +} + +PrimitiveNode::~PrimitiveNode() +{ +} + +NLLIGO::IPrimitive *PrimitiveNode::primitive() const +{ + return m_primitive; +} + +const NLLIGO::CPrimitiveClass *PrimitiveNode::primitiveClass() const +{ + return NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->getPrimitiveClass(*m_primitive); +} + +RootPrimitiveNode *PrimitiveNode::rootPrimitiveNode() +{ + Node *node = this; + while (node && (node->type() != Node::RootPrimitiveNodeType)) + node = node->parent(); + return (RootPrimitiveNode *)node; +} + +Node::NodeType PrimitiveNode::type() const +{ + return PrimitiveNodeType; +} + +RootPrimitiveNode::RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives) + : PrimitiveNode(primitives->RootNode), + m_primitives(primitives) +{ + setData(Qt::DisplayRole, name); +} + +RootPrimitiveNode::~RootPrimitiveNode() +{ +} + +NLLIGO::CPrimitives *RootPrimitiveNode::primitives() const +{ + return m_primitives; +} + +Node::NodeType RootPrimitiveNode::type() const +{ + return RootPrimitiveNodeType; +} + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h new file mode 100644 index 000000000..01c63962c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h @@ -0,0 +1,179 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef PRIMITIVE_ITEM_H +#define PRIMITIVE_ITEM_H + +// Project includes + +// NeL includes +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ + +class WorldEditNode; +class RootPrimitiveNode; +class LandscapeNode; +class PrimitiveNode; + +/* +@class Node +@brief +@details +*/ +class Node +{ +public: + + enum NodeType + { + BasicNodeType, + WorldEditNodeType, + RootPrimitiveNodeType, + LandscapeNodeType, + PrimitiveNodeType, + UserNodeType = 1024 + }; + + Node(); + virtual ~Node(); + + /// Remove child node from the child list. + void removeChildNode(Node *node); + + /// Insert node at the beginning of the list. + void prependChildNode(Node *node); + + /// Insert node at the end of the list. + void appendChildNode(Node *node); + + /// Insert node in front of the node pointed to by the pointer before. + void insertChildNodeBefore(Node *node, Node *before); + + /// Insert node in back of the node pointed to by the pointer after. + void insertChildNodeAfter(Node *node, Node *after); + + /// Return the node at index position row in the child list. + Node *child(int row); + + /// Return the number of nodes in the list. + int childCount() const; + + /// Return a row index this node. + int row() const; + + /// Return a pointer to this node's parent item. If this node does not have a parent, 0 is returned. + Node *parent(); + + /// Set this node's custom data for the key key to value. + void setData(int key, const QVariant &data); + + /// Return this node's custom data for the key key as a QVariant. + QVariant data(int key) const; + + /// Return a type this node. + virtual NodeType type() const; + +private: + Q_DISABLE_COPY(Node) + + Node *m_parent; + QList m_children; + QHash m_data; +}; + +/* +@class WorldEditNode +@brief +@details +*/ +class WorldEditNode: public Node +{ +public: + WorldEditNode(const QString &name); + virtual ~WorldEditNode(); + + virtual NodeType type() const; + +private: +}; + +/* +@class LandscapeNode +@brief +@details +*/ +class LandscapeNode: public Node +{ +public: + LandscapeNode(const QString &name); + virtual ~LandscapeNode(); + + virtual NodeType type() const; + +private: +}; + +/* +@class PrimitiveNode +@brief +@details +*/ +class PrimitiveNode: public Node +{ +public: + PrimitiveNode(NLLIGO::IPrimitive *primitive); + virtual ~PrimitiveNode(); + + NLLIGO::IPrimitive *primitive() const; + const NLLIGO::CPrimitiveClass *primitiveClass() const; + RootPrimitiveNode *rootPrimitiveNode(); + + virtual NodeType type() const; + +private: + NLLIGO::IPrimitive *m_primitive; +}; + +/* +@class RootPrimitiveNode +@brief +@details +*/ +class RootPrimitiveNode: public PrimitiveNode +{ +public: + RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives); + virtual ~RootPrimitiveNode(); + + NLLIGO::CPrimitives *primitives() const; + + virtual NodeType type() const; + +private: + NLLIGO::CPrimitives *m_primitives; +}; + +} /* namespace WorldEditor */ + +#endif // PRIMITIVE_ITEM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp new file mode 100644 index 000000000..bc8925175 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp @@ -0,0 +1,278 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "primitive_item.h" +#include "primitives_model.h" +#include "world_editor_misc.h" + +// NeL includes +#include +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +PrimitivesTreeModel::PrimitivesTreeModel(QObject *parent) + : QAbstractItemModel(parent), + m_worldEditNode(0) +{ + m_rootNode = new Node(); + m_rootNode->setData(Qt::DisplayRole, "Name"); +} + +PrimitivesTreeModel::~PrimitivesTreeModel() +{ + delete m_rootNode; +} + +int PrimitivesTreeModel::columnCount(const QModelIndex &parent) const +{ + /* if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return m_rootItem->columnCount(); + */ + return 1; +} + +QVariant PrimitivesTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + Node *item = static_cast(index.internalPointer()); + switch (role) + { +// case Qt::TextAlignmentRole: +// return int(Qt::AlignLeft | Qt::AlignVCenter); + case Qt::DisplayRole: + return item->data(Qt::DisplayRole); + case Qt::DecorationRole: + return item->data(Qt::DecorationRole); + default: + return QVariant(); + } +} + +Qt::ItemFlags PrimitivesTreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QVariant PrimitivesTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) +// return m_rootNode->data(section); + return m_rootNode->data(Qt::DisplayRole); + + return QVariant(); +} + +QModelIndex PrimitivesTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + Node *parentNode; + + if (!parent.isValid()) + parentNode = m_rootNode; + else + parentNode = static_cast(parent.internalPointer()); + + Node *childNode = parentNode->child(row); + if (childNode) + return createIndex(row, column, childNode); + else + return QModelIndex(); +} + +QModelIndex PrimitivesTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + Node *childNode = static_cast(index.internalPointer()); + Node *parentNode = childNode->parent(); + + if (parentNode == m_rootNode) + return QModelIndex(); + + return createIndex(parentNode->row(), 0, parentNode); +} + +int PrimitivesTreeModel::rowCount(const QModelIndex &parent) const +{ + Node *parentNode; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentNode = m_rootNode; + else + parentNode = static_cast(parent.internalPointer()); + + return parentNode->childCount(); +} + +Path PrimitivesTreeModel::pathFromIndex(const QModelIndex &index) +{ + QModelIndex iter = index; + Path path; + while(iter.isValid()) + { + path.prepend(PathItem(iter.row(), iter.column())); + iter = iter.parent(); + } + return path; +} + +QModelIndex PrimitivesTreeModel::pathToIndex(const Path &path) +{ + QModelIndex iter; + for(int i = 0; i < path.size(); i++) + { + iter = index(path[i].first, path[i].second, iter); + } + return iter; +} + +void PrimitivesTreeModel::createWorldEditNode(const QString &fileName) +{ + beginResetModel(); + m_worldEditNode = new WorldEditNode(fileName); + m_rootNode->appendChildNode(m_worldEditNode); + endResetModel(); +} + +void PrimitivesTreeModel::deleteWorldEditNode() +{ + beginResetModel(); + if (m_worldEditNode != 0) + { + delete m_worldEditNode; + m_worldEditNode = 0; + } + endResetModel(); +} + +Path PrimitivesTreeModel::createLandscapeNode(const QString &fileName) +{ + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); + + QModelIndex parentIndex = index(0, 0, QModelIndex()); + beginInsertRows(parentIndex, 0, 0); + LandscapeNode *newNode = new LandscapeNode(fileName); + m_worldEditNode->prependChildNode(newNode); + endInsertRows(); + return pathFromIndex(index(0, 0, index(0, 0, QModelIndex()))); +} + + +Path PrimitivesTreeModel::createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives) +{ + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); + + // Get position + int pos = m_worldEditNode->childCount(); + + QModelIndex parentIndex = index(0, 0, QModelIndex()); + + // Add root node in tree model + beginInsertRows(parentIndex, pos, pos); + RootPrimitiveNode *newNode = new RootPrimitiveNode(fileName, primitives); + m_worldEditNode->appendChildNode(newNode); + endInsertRows(); + + QModelIndex rootPrimIndex = index(pos, 0, parentIndex); + + // Scan childs items and add in the tree model + for (uint i = 0; i < primitives->RootNode->getNumChildren(); ++i) + { + NLLIGO::IPrimitive *childPrim; + primitives->RootNode->getChild(childPrim, i); + createChildNodes(childPrim, rootPrimIndex); + } + + return pathFromIndex(rootPrimIndex); +} + +Path PrimitivesTreeModel::createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent) +{ + QModelIndex parentIndex = pathToIndex(parent); + Node *parentNode = static_cast(parentIndex.internalPointer()); + int pos = parentNode->childCount(); + + createChildNodes(primitive, parentIndex); + + return pathFromIndex(index(pos, 0, parentIndex)); +} + +void PrimitivesTreeModel::deleteNode(const Path &path) +{ + QModelIndex nodeIndex = pathToIndex(path); + QModelIndex parentIndex = nodeIndex.parent(); + Node *node = static_cast(nodeIndex.internalPointer()); + + // Scan childs items and delete from the tree model + removeChildNodes(node, parentIndex); +} + +void PrimitivesTreeModel::createChildNodes(NLLIGO::IPrimitive *primitive, const QModelIndex &parent) +{ + Node *parentNode = static_cast(parent.internalPointer()); + + int pos = parentNode->childCount(); + + // Add node in the tree model + beginInsertRows(parent, pos, pos); + PrimitiveNode *newNode = new PrimitiveNode(primitive); + parentNode->appendChildNode(newNode); + endInsertRows(); + + // Scan childs items and add in the tree model + QModelIndex childIndex = index(pos, 0, parent); + for (uint i = 0; i < primitive->getNumChildren(); ++i) + { + NLLIGO::IPrimitive *childPrim; + primitive->getChild(childPrim, i); + createChildNodes(childPrim, childIndex); + } +} + +void PrimitivesTreeModel::removeChildNodes(Node *node, const QModelIndex &parent) +{ + // Delete all child nodes from the tree model + while (node->childCount() != 0) + removeChildNodes(node->child(node->childCount() - 1), parent.child(node->row(), 0)); + + // Delete node from the tree model + beginRemoveRows(parent, node->row(), node->row()); + delete node; + endRemoveRows(); +} + +} /* namespace WorldEditor */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h new file mode 100644 index 000000000..d2b6509ad --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h @@ -0,0 +1,99 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef PRIMITIVES_MODEL_H +#define PRIMITIVES_MODEL_H + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ +class Node; +class WorldEditNode; + +typedef QPair PathItem; +/* +@typedef Path +@brief It store a list of row and column numbers which have to walk through from the root index of the model to reach the need item +*/ +typedef QList Path; + +/** +@class PrimitivesTreeModel +@brief +@details +*/ +class PrimitivesTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + PrimitivesTreeModel(QObject *parent = 0); + ~PrimitivesTreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + /// Convert QModelIndex to the persistent index - @Path. + /// @Path is a list of [row,column] pairs showing us the way through the model. + Path pathFromIndex(const QModelIndex &index); + + QModelIndex pathToIndex(const Path &path); + + void createWorldEditNode(const QString &fileName); + void deleteWorldEditNode(); + + /// Add new landscape node in tree model. + Path createLandscapeNode(const QString &fileName); + + /// Add new root primitive node and all sub-primitives in the tree model. + Path createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives); + + /// Add new primitive node and all sub-primitives in the tree model. + Path createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent); + + /// Delete node and all child nodes from the tree model + void deleteNode(const Path &path); + +private: + void createChildNodes(NLLIGO::IPrimitive *primitive, const QModelIndex &parent); + + void removeChildNodes(Node *node, const QModelIndex &parent); + + Node *m_rootNode; + WorldEditNode *m_worldEditNode; +}; + +} /* namespace WorldEditor */ + +#endif // PRIMITIVES_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp new file mode 100644 index 000000000..517dcee43 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp @@ -0,0 +1,373 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "primitives_view.h" +#include "primitive_item.h" +#include "primitives_model.h" +#include "world_editor_actions.h" + +#include "../core/core_constants.h" +#include "../landscape_editor/landscape_editor_constants.h" +#include "../landscape_editor/builder_zone_base.h" + +// NeL includes +#include +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ + +PrimitivesView::PrimitivesView(QWidget *parent) + : QTreeView(parent), + m_undoStack(0), + m_zoneBuilder(0), + m_primitivesTreeModel(0) +{ + setContextMenuPolicy(Qt::DefaultContextMenu); + + m_unloadAction = new QAction("Unload", this); + m_unloadAction->setEnabled(false); + + m_saveAction = new QAction("Save", this); + m_saveAction->setEnabled(false); + m_saveAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + + m_saveAsAction = new QAction("Save As...", this); + m_saveAsAction->setIcon(QIcon(Core::Constants::ICON_SAVE_AS)); + m_saveAsAction->setEnabled(false); + + m_loadLandAction = new QAction("Load landscape file", this); + m_loadLandAction->setIcon(QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); + + m_loadPrimitiveAction = new QAction("Load primitive file", this); + m_loadPrimitiveAction->setIcon(QIcon("./old_ico/root.ico")); + + m_newPrimitiveAction = new QAction("New primitive", this); + + m_deleteAction = new QAction("Delete", this); + m_deleteAction->setEnabled(false); + + m_selectChildrenAction = new QAction("Select children", this); + + m_helpAction = new QAction("Help", this); + m_helpAction->setEnabled(false); + + m_showAction = new QAction("Show", this); + m_showAction->setEnabled(false); + + m_hideAction = new QAction("Hide", this); + m_hideAction->setEnabled(false); + + connect(m_loadLandAction, SIGNAL(triggered()), this, SLOT(loadLandscape())); + connect(m_loadPrimitiveAction, SIGNAL(triggered()), this, SLOT(loadRootPrimitive())); + connect(m_newPrimitiveAction, SIGNAL(triggered()), this, SLOT(createRootPrimitive())); + connect(m_selectChildrenAction, SIGNAL(triggered()), this, SLOT(selectChildren())); + connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deletePrimitives())); + +#ifdef Q_OS_DARWIN + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); +#endif +} + +PrimitivesView::~PrimitivesView() +{ +} + +void PrimitivesView::setUndoStack(QUndoStack *undoStack) +{ + m_undoStack = undoStack; +} + +void PrimitivesView::setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + +void PrimitivesView::setModel(PrimitivesTreeModel *model) +{ + QTreeView::setModel(model); + m_primitivesTreeModel = model; +} + +void PrimitivesView::loadRootPrimitive() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo primitive file"), m_lastDir, + tr("All NeL Ligo primitive files (*.primitive)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro("Load primitive files"); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadRootPrimitiveCommand(fileName, m_primitivesTreeModel)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::loadLandscape() +{ + nlassert(m_undoStack); + nlassert(m_zoneBuilder); + nlassert(m_primitivesTreeModel); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo land file"), m_lastDir, + tr("All NeL Ligo land files (*.land)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro("Load land files"); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadLandscapeCommand(fileName, m_primitivesTreeModel, m_zoneBuilder)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::createRootPrimitive() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + m_undoStack->push(new CreateRootPrimitiveCommand("NewPrimitive", m_primitivesTreeModel)); +} + +void PrimitivesView::selectChildren() +{ + QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex parentIndex = indexList.first(); + + selectionModel()->clearSelection(); + selectChildren(parentIndex); +} + +void PrimitivesView::deletePrimitives() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); +} + +void PrimitivesView::addNewPrimitiveByClass(int value) +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + + PrimitiveNode *node = static_cast(indexList.first().internalPointer()); + + // Get class name + QString className = node->primitiveClass()->DynamicChildren[value].ClassName.c_str(); + + m_undoStack->push(new AddPrimitiveByClassCommand(className, m_primitivesTreeModel->pathFromIndex(indexList.first()), + m_primitivesTreeModel)); +} + +void PrimitivesView::generatePrimitives(int value) +{ +} + +void PrimitivesView::openItem(int value) +{ +} + +void PrimitivesView::contextMenuEvent(QContextMenuEvent *event) +{ + QWidget::contextMenuEvent(event); + QModelIndexList indexList = selectionModel()->selectedRows(); + if (indexList.size() == 0) + return; + + QMenu *popurMenu = new QMenu(this); + + if (indexList.size() == 1) + { + Node *node = static_cast(indexList.first().internalPointer()); + switch (node->type()) + { + case Node::WorldEditNodeType: + fillMenu_WorldEdit(popurMenu); + break; + case Node::RootPrimitiveNodeType: + fillMenu_RootPrimitive(popurMenu, indexList.first()); + break; + case Node::LandscapeNodeType: + fillMenu_Landscape(popurMenu); + break; + case Node::PrimitiveNodeType: + fillMenu_Primitive(popurMenu, indexList.first()); + break; + }; + } + + popurMenu->exec(event->globalPos()); + delete popurMenu; + event->accept(); +} + +void PrimitivesView::selectChildren(const QModelIndex &parent) +{ + const int rowCount = model()->rowCount(parent); + + for (int i = 0; i < rowCount; ++i) + { + QModelIndex childIndex = parent.child(i, 0); + selectionModel()->select(childIndex, QItemSelectionModel::Select); + selectChildren(childIndex); + } +} + +void PrimitivesView::fillMenu_WorldEdit(QMenu *menu) +{ + menu->addAction(m_unloadAction); + menu->addAction(m_saveAction); + menu->addAction(m_saveAsAction); + menu->addSeparator(); + menu->addAction(m_loadLandAction); + menu->addAction(m_loadPrimitiveAction); + menu->addAction(m_newPrimitiveAction); + menu->addSeparator(); + menu->addAction(m_helpAction); +} + +void PrimitivesView::fillMenu_Landscape(QMenu *menu) +{ + menu->addAction(m_deleteAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); +} + +void PrimitivesView::fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_saveAction); + menu->addAction(m_saveAsAction); + fillMenu_Primitive(menu, index); +} + +void PrimitivesView::fillMenu_Primitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_deleteAction); + menu->addAction(m_selectChildrenAction); + menu->addAction(m_helpAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); + + QSignalMapper *addSignalMapper = new QSignalMapper(menu); + QSignalMapper *generateSignalMapper = new QSignalMapper(menu); + QSignalMapper *openSignalMapper = new QSignalMapper(menu); + connect(addSignalMapper, SIGNAL(mapped(int)), this, SLOT(addNewPrimitiveByClass(int))); + connect(generateSignalMapper, SIGNAL(mapped(int)), this, SLOT(generatePrimitives(int))); + //connect(openSignalMapper, SIGNAL(mapped(int)), this, SLOT(openItem(int))); + + PrimitiveNode *node = static_cast(index.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = node->primitiveClass(); + + // What class is it ? + if (primClass && primClass->DynamicChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->DynamicChildren.size(); i++) + { + // Get class name + QString className = primClass->DynamicChildren[i].ClassName.c_str(); + + // Get icon + QIcon icon(QString("./old_ico/%1.ico").arg(className)); + + // Create and add action in popur menu + QAction *action = menu->addAction(icon, QString("Add %1").arg(className)); + addSignalMapper->setMapping(action, i); + connect(action, SIGNAL(triggered()), addSignalMapper, SLOT(map())); + } + } + + // What class is it ? + if (primClass && primClass->GeneratedChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->GeneratedChildren.size(); i++) + { + // Get class name + QString childName = primClass->GeneratedChildren[i].ClassName.c_str(); + + // Create and add action in popur menu + QAction *action = menu->addAction(QString("Generate %1").arg(childName)); + generateSignalMapper->setMapping(action, i); + connect(generateSignalMapper, SIGNAL(triggered()), addSignalMapper, SLOT(map())); + } + } + /* + // What class is it ? + if (primClass) + { + // Look for files + std::vector filenames; + + // Filenames + buildFilenameVector (*Selection.front (), filenames); + + // File names ? + if (!filenames.empty ()) + { + // Add separator + popurMenu->addSeparator(); + + // Found ? + for (uint i = 0; i < filenames.size(); i++) + { + // Add a menu entry + pMenu->AppendMenu (MF_STRING, ID_EDIT_OPEN_FILE_BEGIN+i, ("Open "+NLMISC::CFile::getFilename (filenames[i])).c_str ()); + } + } + */ +} + +} /* namespace WorldEditor */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h new file mode 100644 index 000000000..67c3ffba0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h @@ -0,0 +1,101 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef PRIMITIVES_VIEW_H +#define PRIMITIVES_VIEW_H + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ +class PrimitivesTreeModel; + +/** +@class PrimitivesView +@brief +@details +*/ +class PrimitivesView : public QTreeView +{ + Q_OBJECT + +public: + PrimitivesView(QWidget *parent = 0); + ~PrimitivesView(); + + void setUndoStack(QUndoStack *undoStack); + void setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder); + virtual void setModel(PrimitivesTreeModel *model); + +private Q_SLOTS: + void loadLandscape(); + void loadRootPrimitive(); + void createRootPrimitive(); + void selectChildren(); + + void deletePrimitives(); + void addNewPrimitiveByClass(int value); + void generatePrimitives(int value); + void openItem(int value); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +private: + void selectChildren(const QModelIndex &parent); + void fillMenu_WorldEdit(QMenu *menu); + void fillMenu_Landscape(QMenu *menu); + void fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index); + void fillMenu_Primitive(QMenu *menu, const QModelIndex &index); + + QString m_lastDir; + + QAction *m_unloadAction; + QAction *m_saveAction; + QAction *m_saveAsAction; + QAction *m_loadLandAction; + QAction *m_loadPrimitiveAction; + QAction *m_newPrimitiveAction; + QAction *m_deleteAction; + QAction *m_selectChildrenAction; + QAction *m_helpAction; + QAction *m_showAction; + QAction *m_hideAction; + + QUndoStack *m_undoStack; + LandscapeEditor::ZoneBuilderBase *m_zoneBuilder; + PrimitivesTreeModel *m_primitivesTreeModel; +}; + +} /* namespace WorldEditor */ + +#endif // PRIMITIVES_VIEW_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc new file mode 100644 index 000000000..02ffcbe00 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor.qrc @@ -0,0 +1,10 @@ + + + icons/ic_nel_select.png + icons/ic_nel_scale.png + icons/ic_nel_rotate.png + icons/ic_nel_move.png + icons/ic_nel_turn.png + icons/ic_nel_world_editor.png + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp new file mode 100644 index 000000000..fb8299c23 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp @@ -0,0 +1,226 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_actions.h" +#include "world_editor_misc.h" +#include "primitive_item.h" + +// Lanscape Editor plugin +#include "../landscape_editor/builder_zone_base.h" + +// STL includes +#include + +// NeL includes +#include +#include +#include +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +CreateWorldCommand::CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText("Create new world"); +} + +CreateWorldCommand::~CreateWorldCommand() +{ +} + +void CreateWorldCommand::undo() +{ + m_model->deleteWorldEditNode(); +} + +void CreateWorldCommand::redo() +{ + m_model->createWorldEditNode(m_fileName); +} + +LoadLandscapeCommand::LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent) + : QUndoCommand(parent), + m_id(-1), + m_fileName(fileName), + m_model(model), + m_zoneBuilder(zoneBuilder) +{ + setText("Load land file"); +} + +LoadLandscapeCommand::~LoadLandscapeCommand() +{ +} + +void LoadLandscapeCommand::undo() +{ + m_zoneBuilder->deleteZoneRegion(m_id); + m_model->deleteNode(landIndex); +} + +void LoadLandscapeCommand::redo() +{ + if (m_id == -1) + m_id = m_zoneBuilder->loadZoneRegion(m_fileName); + else + m_zoneBuilder->loadZoneRegion(m_fileName, m_id); + + landIndex = m_model->createLandscapeNode(m_fileName); +} + +CreateRootPrimitiveCommand::CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText("Create new primitive"); +} + +CreateRootPrimitiveCommand::~CreateRootPrimitiveCommand() +{ +} + +void CreateRootPrimitiveCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void CreateRootPrimitiveCommand::redo() +{ + NLLIGO::CPrimitives *newRootPrim = new NLLIGO::CPrimitives(); + m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, newRootPrim); +} + + +LoadRootPrimitiveCommand::LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText("Load primitive file"); +} + +LoadRootPrimitiveCommand::~LoadRootPrimitiveCommand() +{ +} + +void LoadRootPrimitiveCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void LoadRootPrimitiveCommand::redo() +{ + NLLIGO::CPrimitives *primitives = new NLLIGO::CPrimitives(); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = primitives; + + NLLIGO::loadXmlPrimitiveFile(*primitives, m_fileName.toStdString(), *NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + + // Initialize default values + Utils::recursiveUpdateDefaultValues(primitives->RootNode); + + // Check property types + if (Utils::recursiveUpdateDefaultValues(primitives->RootNode)) + { + nlwarning("In file (%s) : Some primitives have been modified to initialise their default values\nor to change their properties type.", m_fileName.toStdString().c_str()); + } + + m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, primitives); +} + +AddPrimitiveByClassCommand::AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_className(className), + m_parentIndex(parentIndex), + m_model(model) +{ + setText(QString("Add %1").arg(m_className)); +} + +AddPrimitiveByClassCommand::~AddPrimitiveByClassCommand() +{ +} + +void AddPrimitiveByClassCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_newPrimIndex); + PrimitiveNode *node = static_cast(index.internalPointer()); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = node->rootPrimitiveNode()->primitives(); + + Utils::deletePrimitive(node->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_model->deleteNode(m_newPrimIndex); +} + +void AddPrimitiveByClassCommand::redo() +{ + QModelIndex parentIndex = m_model->pathToIndex(m_parentIndex); + PrimitiveNode *parentNode = static_cast(parentIndex.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = parentNode->primitiveClass(); + + float delta = 10; + int id = 0; + while (primClass->DynamicChildren[id].ClassName != m_className.toStdString()) + ++id; + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = parentNode->rootPrimitiveNode()->primitives(); + + QString namePrimititve = QString("%1_%2").arg(m_className).arg(parentNode->childCount()); + NLLIGO::IPrimitive *newPrimitive = Utils::createPrimitive(m_className.toStdString().c_str(), namePrimititve.toStdString().c_str(), + NLMISC::CVector(), delta, primClass->DynamicChildren[id].Parameters, parentNode->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_newPrimIndex = m_model->createPrimitiveNode(newPrimitive, m_parentIndex); +} + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h new file mode 100644 index 000000000..00951dd9e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h @@ -0,0 +1,138 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_ACTIONS_H +#define WORLD_EDITOR_ACTIONS_H + +// Project includes +#include "primitives_model.h" + +// NeL includes + +// Qt includes +#include +#include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ + +/** +@class CreateWorldCommand +@brief +@details +*/ +class CreateWorldCommand: public QUndoCommand +{ +public: + CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~CreateWorldCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_fileName; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadLandscapeCommand +@brief +@details +*/ +class LoadLandscapeCommand: public QUndoCommand +{ +public: + LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent = 0); + virtual ~LoadLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path landIndex; + int m_id; + const QString m_fileName; + PrimitivesTreeModel *const m_model; + LandscapeEditor::ZoneBuilderBase *const m_zoneBuilder; +}; + +class CreateRootPrimitiveCommand: public QUndoCommand +{ +public: + CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~CreateRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_fileName; + Path m_rootPrimIndex; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadPrimitiveCommand +@brief +@details +*/ +class LoadRootPrimitiveCommand: public QUndoCommand +{ +public: + LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~LoadRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_rootPrimIndex; + const QString m_fileName; + PrimitivesTreeModel *const m_model; +}; + +/** +@class AddPrimitiveCommand +@brief +@details +*/ +class AddPrimitiveByClassCommand: public QUndoCommand +{ +public: + AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~AddPrimitiveByClassCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_className; + Path m_parentIndex, m_newPrimIndex; + PrimitivesTreeModel *m_model; +}; + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_ACTIONS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h new file mode 100644 index 000000000..cb1abf21e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_constants.h @@ -0,0 +1,43 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_CONSTANTS_H +#define WORLD_EDITOR_CONSTANTS_H + +namespace WorldEditor +{ +namespace Constants +{ +const char *const WORLD_EDITOR_PLUGIN = "WorldEditor"; + +//settings +const char *const WORLD_EDITOR_SECTION = "WorldEditor"; +const char *const WORLD_WINDOW_STATE = "WorldWindowState"; +const char *const WORLD_WINDOW_GEOMETRY = "WorldWindowGeometry"; +const char *const WORLD_EDITOR_CELL_SIZE = "WorldEditorCellSize"; +const char *const WORLD_EDITOR_SNAP = "WorldEditorSnap"; +const char *const ZONE_SNAPSHOT_RES = "WorldEditorZoneSnapshotRes"; +const char *const PRIMITIVE_CLASS_FILENAME = "WorldEditorPrimitiveClassFilename"; + +//resources +const char *const ICON_WORLD_EDITOR = ":/icons/ic_nel_world_editor.png"; + + +} // namespace Constants +} // namespace WorldEditor + +#endif // WORLD_EDITOR_CONSTANTS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h new file mode 100644 index 000000000..a7a94ca75 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_global.h @@ -0,0 +1,30 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_GLOBAL_H +#define WORLD_EDITOR_GLOBAL_H + +#include + +#if defined(WORLD_EDITOR_LIBRARY) +# define WORLD_EDITOR_EXPORT Q_DECL_EXPORT +#else +# define WORLD_EDITOR_EXPORT Q_DECL_IMPORT +#endif + +#endif // WORLD_EDITOR_GLOBAL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp new file mode 100644 index 000000000..e06332deb --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.cpp @@ -0,0 +1,692 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_misc.h" + +// NeL includes +#include +#include +#include +#include +#include +#include +#include + + +// Qt includes + +namespace WorldEditor +{ +namespace Utils +{ + +void syntaxError(const char *filename, xmlNodePtr xmlNode, const char *format, ...) +{ + char buffer[1024]; + + if (format) + { + va_list args; + va_start( args, format ); + sint ret = vsnprintf( buffer, 1024, format, args ); + va_end( args ); + } + else + { + strcpy(buffer, "Unknown error"); + } + + nlerror("(%s), node (%s), line (%d) :\n%s", filename, xmlNode->name, (int)xmlNode->content, buffer); +} + +bool getPropertyString(std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName) +{ + // Call the CIXml version + if (!NLMISC::CIXml::getPropertyString(result, xmlNode, propName)) + { + // Output a formated error + syntaxError(filename, xmlNode, "Missing XML node property (%s)", propName); + return false; + } + return true; +} + +uint32 getUniqueId() +{ + // Wait 1 ms + sint64 time = NLMISC::CTime::getLocalTime (); + sint64 time2; + while ((time2 = NLMISC::CTime::getLocalTime ()) == time) + { + } + + return (uint32)time2; +} + +bool loadWorldEditFile(const std::string &fileName, WorldEditList &worldEditList) +{ + bool result = false; + + // Load the document + NLMISC::CIFile file; + if (file.open(fileName)) + { + try + { + // Load the document in XML + NLMISC::CIXml xml; + xml.init(file); + + // Get root node + xmlNodePtr rootNode = xml.getRootNode(); + if (rootNode) + { + // Good header ? + if (strcmp((const char *)(rootNode->name), "NEL_WORLD_EDITOR_PROJECT") == 0) + { + // Read the version + int version = -1; + + // Read the parameters + xmlNodePtr node = NLMISC::CIXml::getFirstChildNode(rootNode, "VERSION"); + if (node) + { + std::string versionString; + if (NLMISC::CIXml::getContentString (versionString, node)) + version = atoi(versionString.c_str ()); + } + + if (version == -1) + { + // Error + syntaxError(fileName.c_str(), rootNode, "No version node"); + } + else + { + // Old format, + if (version <= 1) + { + syntaxError(fileName.c_str(), rootNode, "Old version node"); + } + else + { + // Read it + if (version > WORLD_EDITOR_FILE_VERSION) + { + syntaxError(fileName.c_str(), node, "Unknown file version"); + } + else + { + // Read data directory + node = NLMISC::CIXml::getFirstChildNode(rootNode, "DATA_DIRECTORY"); + if (node) + { + std::string dataDir; + NLMISC::CIXml::getPropertyString(dataDir, node, "VALUE"); + worldEditList.push_back(WorldEditItem(DataDirectoryType, dataDir)); + } + + // Read data directory + node = NLMISC::CIXml::getFirstChildNode(rootNode, "CONTEXT"); + if (node) + { + std::string context; + NLMISC::CIXml::getPropertyString(context, node, "VALUE"); + worldEditList.push_back(WorldEditItem(ContextType, context)); + } + + // Read the database element + node = NLMISC::CIXml::getFirstChildNode(rootNode, "DATABASE_ELEMENT"); + if (node) + { + do + { + // Get the type + std::string type; + if (getPropertyString(type, fileName.c_str(), node, "TYPE")) + { + // Read the filename + std::string filenameChild; + if (getPropertyString(filenameChild, fileName.c_str(), node, "FILENAME")) + { + // Is it a landscape ? + if (type == "landscape") + { + worldEditList.push_back(WorldEditItem(LandscapeType, filenameChild)); + + // Get the primitives + xmlNodePtr primitives = NLMISC::CIXml::getFirstChildNode(node, "PRIMITIVES"); + if (primitives) + { + NLLIGO::CPrimitives ligoPrimitives; + + // Read it + ligoPrimitives.read(primitives, fileName.c_str(), *NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig); + //_DataHierarchy.back ().Primitives.read (primitives, filename, theApp.Config); + + // Set the filename + //_DataHierarchy.back ().Filename = filenameChild; + } + } + else + { + worldEditList.push_back(WorldEditItem(PrimitiveType, filenameChild)); + } + + } + } + } + while (node = NLMISC::CIXml::getNextChildNode(node, "DATABASE_ELEMENT")); + } + + // Done + result = true; + } + } + } + } + else + { + // Error + syntaxError(fileName.c_str(), rootNode, "Unknown file header : %s", rootNode->name); + } + } + } + catch (NLMISC::Exception &e) + { + nlerror("Error reading file %s : %s", fileName.c_str(), e.what()); + } + } + else + { + nlerror("Can't open the file %s for reading.", fileName.c_str()); + } + + return result; +} + +NLLIGO::IPrimitive *getRootPrimitive(NLLIGO::IPrimitive *primitive) +{ + nlassert(primitive); + + if (primitive->getParent() == NULL) + return primitive; + else + return getRootPrimitive(primitive->getParent()); +} + +void initPrimitiveParameters(const NLLIGO::CPrimitiveClass &primClass, NLLIGO::IPrimitive &primitive, + const std::vector &initParameters) +{ + // Other parameters + for (uint p = 0; p < initParameters.size(); ++p) + { + // The property + const NLLIGO::CPrimitiveClass::CInitParameters ¶meter = initParameters[p]; + + // Look for it in the class + uint cp; + for (cp = 0; cp < primClass.Parameters.size(); ++cp) + { + // Good one ? + if (primClass.Parameters[cp].Name == initParameters[p].Name) + break; + } + + // The primitive type + NLLIGO::CPrimitiveClass::CParameter::TType type; + + // Found ? + if (cp < primClass.Parameters.size()) + type = primClass.Parameters[cp].Type; + + // Name ? + if (initParameters[p].Name == "name") + type = NLLIGO::CPrimitiveClass::CParameter::String; + + // Continue ? + if (cp 1) + nlerror("Warning: parameter (%s) in class name (%s) has more than 1 default value (%d).", + parameter.Name.c_str(), primClass.Name.c_str(), parameter.DefaultValue.size()); + + if ((cp < primClass.Parameters.size() && !primClass.Parameters[cp].Visible) + || parameter.DefaultValue[0].GenID) + { + // Remove this property + primitive.removePropertyByName(parameter.Name.c_str()); + + // Add this property + primitive.addPropertyByName(parameter.Name.c_str(), + new NLLIGO::CPropertyString((parameter.DefaultValue[0].GenID ? NLMISC::toString(getUniqueId()) : "").c_str ())); + } + break; + } + case NLLIGO::CPrimitiveClass::CParameter::ConstStringArray: + case NLLIGO::CPrimitiveClass::CParameter::StringArray: + { + bool Visible = false; + if (cp < primClass.Parameters.size() && !primClass.Parameters[cp].Visible) + { + Visible = true; + } + for (size_t i = 0; i < parameter.DefaultValue.size(); ++i) + { + // Generate a unique id ? + if (parameter.DefaultValue[i].GenID) + { + Visible = true; + } + } + if (Visible) + { + // Remove this property + primitive.removePropertyByName (parameter.Name.c_str()); + + // Add this property + NLLIGO::CPropertyStringArray *str = new NLLIGO::CPropertyStringArray(); + str->StringArray.resize (parameter.DefaultValue.size()); + for (size_t i = 0; i < parameter.DefaultValue.size(); ++i) + { + // Generate a unique id ? + if (parameter.DefaultValue[i].GenID) + { + str->StringArray[i] = NLMISC::toString(getUniqueId()); + } + else + { + str->StringArray[i] = ""; + } + } + primitive.addPropertyByName(parameter.Name.c_str(), str); + } + break; + } + } + } + } + else + { + // Some feedback + nlerror("Warning: parameter (%s) doesn't exist in class (%s).", + initParameters[p].Name.c_str(), primClass.Name.c_str()); + } + } +} + +NLLIGO::IPrimitive *createPrimitive(const char *className, const char *primName, + const NLMISC::CVector &initPos, float deltaPos, + const std::vector &initParameters, + NLLIGO::IPrimitive *parent) +{ + // Get the prim class + const NLLIGO::CPrimitiveClass *primClass = NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->getPrimitiveClass(className); + if (primClass) + { + // Create the base primitive + NLLIGO::IPrimitive *primitive = NULL; + switch (primClass->Type) + { + case NLLIGO::CPrimitiveClass::Node: + primitive = new NLLIGO::CPrimNode; + break; + case NLLIGO::CPrimitiveClass::Point: + { + NLLIGO::CPrimPoint *point = new NLLIGO::CPrimPoint; + primitive = point; + point->Point.CVector::operator = (initPos); + } + break; + case NLLIGO::CPrimitiveClass::Path: + primitive = new NLLIGO::CPrimPath; + break; + case NLLIGO::CPrimitiveClass::Zone: + primitive = new NLLIGO::CPrimZone; + break; + case NLLIGO::CPrimitiveClass::Alias: + primitive = new NLLIGO::CPrimAlias; + break; + case NLLIGO::CPrimitiveClass::Bitmap: + primitive = new NLLIGO::CPrimNode; + break; + } + nlassert(primitive); + + // Add properties + primitive->addPropertyByName("class", new NLLIGO::CPropertyString(className)); + primitive->addPropertyByName("name", new NLLIGO::CPropertyString(primName, primName[0] == 0)); + + // Init with default parameters + std::vector tempParam; + tempParam.reserve(primClass->Parameters.size()); + for (size_t i = 0; i < primClass->Parameters.size(); i++) + tempParam.push_back (primClass->Parameters[i]); + initPrimitiveParameters (*primClass, *primitive, tempParam); + + // Init with option parameters + initPrimitiveParameters(*primClass, *primitive, initParameters); + + parent->insertChild(primitive); + /* + // Insert the primitive + insertPrimitive (locator, primitive); + */ + // The new pos + NLMISC::CVector newPos = initPos; + newPos.x += deltaPos; + + // Create static children + uint c; + for (c = 0; c < primClass->StaticChildren.size(); c++) + { + // The child ref + const NLLIGO::CPrimitiveClass::CChild &child = primClass->StaticChildren[c]; + + // Create the child + const NLLIGO::IPrimitive *childPrim = createPrimitive(child.ClassName.c_str(), child.Name.c_str(), + newPos, deltaPos, primClass->StaticChildren[c].Parameters, primitive); + + // The new pos + newPos.y += deltaPos; + } + + // Canceled ? + if (c < primClass->StaticChildren.size()) + { + deletePrimitive(primitive); + return NULL; + } + + // Prim file ? + if (primClass->Type == NLLIGO::CPrimitiveClass::Bitmap) + { + // Create a dialog file + //CFileDialogEx dialog (BASE_REGISTRY_KEY, "image", TRUE, primClass->FileExtension.c_str (), NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, + // (primClass->FileType+" (*."+primClass->FileExtension+")|*."+primClass->FileExtension+"|All Files (*.*)|*.*||").c_str (), getMainFrame ()); + //if (dialog.DoModal() == IDOK) + //{ + // Save filename + // static_cast(primitive)->init(dialog.GetPathName ()); + //} + } + + // Continue ? + if (primitive) + { + // Auto init ? + if (!primClass->AutoInit) + { + // Make a vector of locator + //CDatabaseLocatorPointer locatorPtr; + //getLocator (locatorPtr, locator); + std::list locators; + //locators.push_back (const_cast (locatorPtr.Primitive)); + + // Yes, go + //CDialogProperties dialogProperty (locators, getMainFrame ()); + //dialogProperty.DoModal (); + } + + // Eval the default name property + std::string name; + if (!primitive->getPropertyByName ("name", name) || name.empty()) + { + const NLLIGO::CPrimitiveClass *primClass = NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->getPrimitiveClass(*primitive); + if (primClass) + { + for (size_t i = 0; i < primClass->Parameters.size(); ++i) + { + if (primClass->Parameters[i].Name == "name") + { + std::string result; + primClass->Parameters[i].getDefaultValue(result, *primitive, *primClass, NULL); + if (!result.empty()) + { + primitive->removePropertyByName("name"); + primitive->addPropertyByName("name", new NLLIGO::CPropertyString(result.c_str(), true)); + } + } + } + } + } + + // Init primitive default values + primitive->initDefaultValues(*NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig); + } + + // Done + return primitive; + } + else + { + nlerror("Unknown primitive class name : %s", className); + } + return 0; +} + +void deletePrimitive(NLLIGO::IPrimitive *primitive) +{ + // Get the parent + NLLIGO::IPrimitive *parent = primitive->getParent(); + nlassert(parent); + + // Get the child id + uint childId; + nlverify(parent->getChildId(childId, primitive)); + + // Delete the child + nlverify(parent->removeChild(childId)); +} + +bool updateDefaultValues(NLLIGO::IPrimitive *primitive) +{ + // Modified + bool modified = false; + + // Get the prim class + const NLLIGO::CPrimitiveClass *primClass = NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->getPrimitiveClass(*primitive); + nlassert(primClass); + + if (primClass) + { + // For each parameters + for (uint i = 0; i < primClass->Parameters.size(); i++) + { + // First check the primitive property has to good type + NLLIGO::IProperty *prop; + if (primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), prop)) + { + // String to array ? + NLLIGO::CPropertyString *propString = dynamic_cast(prop); + const bool classStringArray = primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::StringArray || + primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::ConstStringArray; + if (propString && classStringArray) + { + // Build an array string + std::vector strings; + if (!propString->String.empty()) + strings.push_back(propString->String); + prop = new NLLIGO::CPropertyStringArray(strings); + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), prop); + modified = true; + } + + // Array to string ? + NLLIGO::CPropertyStringArray *propStringArray = dynamic_cast(prop); + if (propStringArray && !classStringArray) + { + // Build an array string + std::string str; + if (!propStringArray->StringArray.empty()) + str = propStringArray->StringArray[0]; + prop = new NLLIGO::CPropertyString(str); + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), prop); + modified = true; + } + } + + // String or string array ? + if (primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::String) + { + // Default value available ? + if (!primClass->Parameters[i].DefaultValue.empty ()) + { + // Unique Id ? + if (primClass->Parameters[i].DefaultValue[0].GenID) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), result)) + { + // Add it ! + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyString(NLMISC::toString(getUniqueId()).c_str())); + modified = true; + } + } + // Hidden ? + else if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName (primClass->Parameters[i].Name.c_str (), result)) + { + // Add it ! + primitive->addPropertyByName (primClass->Parameters[i].Name.c_str (), new NLLIGO::CPropertyString ("")); + modified = true; + } + } + } + } + else if ((primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::StringArray) || + (primClass->Parameters[i].Type == NLLIGO::CPrimitiveClass::CParameter::ConstStringArray)) + { + for (uint j = 0; j < primClass->Parameters[i].DefaultValue.size(); j++) + { + // Unique Id ? + if (primClass->Parameters[i].DefaultValue[j].GenID) + { + // The doesn't exist ? + std::vector result; + std::vector *resultPtr = NULL; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), resultPtr) || + (resultPtr->size() <= j)) + { + // Copy + if (resultPtr) + result = *resultPtr; + + // Resize + if (result.size() <= j) + result.resize(j + 1); + + // Resize to it + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + + // Set the value + result[j] = NLMISC::toString(getUniqueId()); + + // Add the new property array + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyStringArray(result)); + modified = true; + } + } + // Hidden ? + else if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::vector result; + std::vector *resultPtr = NULL; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), resultPtr) || (resultPtr->size () <= j)) + { + // Copy + if (resultPtr) + result = *resultPtr; + + // Resize + if (result.size() <= j) + result.resize(j + 1); + + // Resize to it + primitive->removePropertyByName(primClass->Parameters[i].Name.c_str()); + + // Set the value + result[j] = ""; + + // Add the new property array + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyStringArray(result)); + modified = true; + } + } + } + } + else + { + // Default value available ? + if (!primClass->Parameters[i].DefaultValue.empty ()) + { + // Hidden ? + if (!primClass->Parameters[i].Visible) + { + // The doesn't exist ? + std::string result; + if (!primitive->getPropertyByName(primClass->Parameters[i].Name.c_str(), result)) + { + // Add it ! + primitive->addPropertyByName(primClass->Parameters[i].Name.c_str(), new NLLIGO::CPropertyString("")); + modified = true; + } + } + } + } + } + } + return modified; +} + +bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive) +{ + bool modified = updateDefaultValues(primitive); + + const uint count = primitive->getNumChildren(); + for (uint i = 0; i < count; ++i) + { + // Get the child + NLLIGO::IPrimitive *child; + nlverify(primitive->getChild(child, i)); + modified |= recursiveUpdateDefaultValues(child); + } + + return modified; +} + +} /* namespace Utils */ +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h new file mode 100644 index 000000000..ea6a59f58 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_misc.h @@ -0,0 +1,80 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_MISC_H +#define WORLD_EDITOR_MISC_H + +// Project includes + +// NeL includes +#include +#include +#include + +// STL includes +#include +#include + +#define WORLD_EDITOR_FILE_VERSION 2 +#define WORLD_EDITOR_DATABASE_SIZE 100 + +namespace WorldEditor +{ +namespace Utils +{ +enum ItemType +{ + DataDirectoryType = 0, + ContextType, + LandscapeType, + PrimitiveType +}; + +typedef std::pair WorldEditItem; +typedef std::vector WorldEditList; + +// Generate unique identificator +uint32 getUniqueId(); + +// Load *.worldedit file and return list primitives and landscapes. +bool loadWorldEditFile(const std::string &fileName, WorldEditList &worldEditList); + +// Get root primitive +NLLIGO::IPrimitive *getRootPrimitive(NLLIGO::IPrimitive *primitive); + +// Init a primitive parameters +void initPrimitiveParameters(const NLLIGO::CPrimitiveClass &primClass, NLLIGO::IPrimitive &primitive, + const std::vector &initParameters); + +NLLIGO::IPrimitive *createPrimitive(const char *className, const char *primName, + const NLMISC::CVector &initPos, float deltaPos, + const std::vector &initParameters, + NLLIGO::IPrimitive *parent); + +// Remove the primitive and don't delete it. +//void takeAtPrimitive(NLLIGO::IPrimitive *primitive); + +void deletePrimitive(NLLIGO::IPrimitive *primitive); + +bool updateDefaultValues(NLLIGO::IPrimitive *primitive); + +bool recursiveUpdateDefaultValues(NLLIGO::IPrimitive *primitive); + +} /* namespace Utils */ +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_MISC_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp new file mode 100644 index 000000000..90d2de6d6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.cpp @@ -0,0 +1,158 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_plugin.h" +#include "world_editor_window.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" + +// NeL includes +#include "nel/misc/debug.h" +#include +#include +#include + +// Qt includes +#include + +namespace WorldEditor +{ + +WorldEditorPlugin::~WorldEditorPlugin() +{ + Q_FOREACH(QObject *obj, m_autoReleaseObjects) + { + m_plugMan->removeObject(obj); + } + qDeleteAll(m_autoReleaseObjects); + m_autoReleaseObjects.clear(); +} + +bool WorldEditorPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString) +{ + m_plugMan = pluginManager; + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + m_ligoConfig.CellSize = settings->value(Constants::WORLD_EDITOR_CELL_SIZE, "160").toFloat(); + m_ligoConfig.Snap = settings->value(Constants::WORLD_EDITOR_SNAP, "1").toFloat(); + m_ligoConfig.ZoneSnapShotRes = settings->value(Constants::ZONE_SNAPSHOT_RES, "128").toUInt(); + QString fileName = settings->value(Constants::PRIMITIVE_CLASS_FILENAME, "world_editor_classes.xml").toString(); + settings->endGroup(); + try + { + // Search path of file world_editor_classes.xml + std::string ligoPath = NLMISC::CPath::lookup(fileName.toStdString()); + // Init LIGO + m_ligoConfig.readPrimitiveClass(ligoPath.c_str(), true); + NLLIGO::Register(); + NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; + } + catch (NLMISC::Exception &e) + { + *errorString = tr("(%1)").arg(e.what()); + return false; + } + + // Reset + m_ligoConfig.resetPrimitiveConfiguration (); + + // Load + m_ligoConfig.readPrimitiveClass ("world_editor_primitive_configuration.xml", true); + + + addAutoReleasedObject(new WorldEditorContext(this)); + return true; +} + +void WorldEditorPlugin::extensionsInitialized() +{ +} + +void WorldEditorPlugin::shutdown() +{ +} + +void WorldEditorPlugin::setNelContext(NLMISC::INelContext *nelContext) +{ +#ifdef NL_OS_WINDOWS + // Ensure that a context doesn't exist yet. + // This only applies to platforms without PIC, e.g. Windows. + nlassert(!NLMISC::INelContext::isContextInitialised()); +#endif // NL_OS_WINDOWS + m_libContext = new NLMISC::CLibraryContext(*nelContext); +} + +QString WorldEditorPlugin::name() const +{ + return tr("WorldEditor"); +} + +QString WorldEditorPlugin::version() const +{ + return "0.0.1"; +} + +QString WorldEditorPlugin::vendor() const +{ + return "GSoC2011_dnk-88"; +} + +QString WorldEditorPlugin::description() const +{ + return "World editor ovqt plugin."; +} + +QStringList WorldEditorPlugin::dependencies() const +{ + QStringList list; + list.append(Core::Constants::OVQT_CORE_PLUGIN); + return list; +} + +void WorldEditorPlugin::addAutoReleasedObject(QObject *obj) +{ + m_plugMan->addObject(obj); + m_autoReleaseObjects.prepend(obj); +} + +WorldEditorContext::WorldEditorContext(QObject *parent) + : IContext(parent), + m_worldEditorWindow(0) +{ + m_worldEditorWindow = new WorldEditorWindow(); +} + +QUndoStack *WorldEditorContext::undoStack() +{ + return m_worldEditorWindow->undoStack(); +} + +void WorldEditorContext::open() +{ + m_worldEditorWindow->open(); +} + +QWidget *WorldEditorContext::widget() +{ + return m_worldEditorWindow; +} + +} + +Q_EXPORT_PLUGIN(WorldEditor::WorldEditorPlugin) \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h new file mode 100644 index 000000000..11e2c7871 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_plugin.h @@ -0,0 +1,110 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_PLUGIN_H +#define WORLD_EDITOR_PLUGIN_H + +// Project includes +#include "world_editor_constants.h" +#include "../../extension_system/iplugin.h" +#include "../core/icontext.h" + +// NeL includes +#include "nel/misc/app_context.h" +#include + +// Qt includes +#include +#include + +namespace NLMISC +{ +class CLibraryContext; +} + +namespace ExtensionSystem +{ +class IPluginSpec; +} + +namespace WorldEditor +{ +class WorldEditorWindow; + +class WorldEditorPlugin : public QObject, public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_INTERFACES(ExtensionSystem::IPlugin) +public: + + virtual ~WorldEditorPlugin(); + + bool initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString); + void extensionsInitialized(); + void shutdown(); + + void setNelContext(NLMISC::INelContext *nelContext); + + QString name() const; + QString version() const; + QString vendor() const; + QString description() const; + QStringList dependencies() const; + + void addAutoReleasedObject(QObject *obj); + +protected: + NLMISC::CLibraryContext *m_libContext; + +private: + NLLIGO::CLigoConfig m_ligoConfig; + ExtensionSystem::IPluginManager *m_plugMan; + QList m_autoReleaseObjects; +}; + +class WorldEditorContext: public Core::IContext +{ + Q_OBJECT +public: + WorldEditorContext(QObject *parent = 0); + virtual ~WorldEditorContext() {} + + virtual QString id() const + { + return QLatin1String("WorldEditorContext"); + } + virtual QString trName() const + { + return tr("World Editor"); + } + virtual QIcon icon() const + { + return QIcon(Constants::ICON_WORLD_EDITOR); + } + + virtual void open(); + + virtual QUndoStack *undoStack(); + + virtual QWidget *widget(); + + WorldEditorWindow *m_worldEditorWindow; +}; + +} // namespace WorldEditor + +#endif // WORLD_EDITOR_PLUGIN_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp new file mode 100644 index 000000000..2c4c41065 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.cpp @@ -0,0 +1,71 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_scene.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +namespace WorldEditor +{ + +WorldEditorScene::WorldEditorScene(int sizeCell, QObject *parent) + : LandscapeEditor::LandscapeSceneBase(sizeCell, parent) +{ +} + +WorldEditorScene::~WorldEditorScene() +{ +} +/* +void LandscapeSceneBase::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mousePressEvent(mouseEvent); + + qreal x = mouseEvent->scenePos().x(); + qreal y = mouseEvent->scenePos().y(); + m_posX = sint32(floor(x / m_cellSize)); + m_posY = sint32(-floor(y / m_cellSize)); + + m_mouseButton = mouseEvent->button(); +} + +void LandscapeSceneBase::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + m_mouseX = mouseEvent->scenePos().x(); + m_mouseY = mouseEvent->scenePos().y() - m_cellSize; + + m_posX = sint32(floor(m_mouseX / m_cellSize)); + m_posY = sint32(-floor(m_mouseY / m_cellSize)); + + QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +void LandscapeSceneBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mouseReleaseEvent(mouseEvent); + m_mouseButton = Qt::NoButton; +} +*/ + +} /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h new file mode 100644 index 000000000..84dba333c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_scene.h @@ -0,0 +1,57 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_SCENE_H +#define WORLD_EDITOR_SCENE_H + +// Project includes +#include "world_editor_global.h" + +#include "../landscape_editor/landscape_scene_base.h" + +// NeL includes + +// Qt includes + +namespace WorldEditor +{ + +/* +@class WorldEditorScene +@brief +@details +*/ +class WORLD_EDITOR_EXPORT WorldEditorScene : public LandscapeEditor::LandscapeSceneBase +{ + Q_OBJECT + +public: + WorldEditorScene(int sizeCell = 160, QObject *parent = 0); + virtual ~WorldEditorScene(); + +public Q_SLOTS: + +protected: +// virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); +// virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); +// virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + +private: +}; + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_SCENE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp new file mode 100644 index 000000000..132b52b70 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp @@ -0,0 +1,227 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Project includes +#include "world_editor_window.h" +#include "world_editor_constants.h" +#include "primitives_model.h" +#include "world_editor_scene.h" +#include "world_editor_misc.h" +#include "world_editor_actions.h" + +// Core +#include "../core/icore.h" +#include "../core/imenu_manager.h" +#include "../core/core_constants.h" + +// Lanscape Editor plugin +#include "../landscape_editor/builder_zone_base.h" + +// NeL includes +#include +#include +#include +#include + +// Qt includes +#include +#include +#include + +namespace WorldEditor +{ + +WorldEditorWindow::WorldEditorWindow(QWidget *parent) + : QMainWindow(parent), + m_primitivesModel(0), + m_undoStack(0) +{ + m_ui.setupUi(this); + m_undoStack = new QUndoStack(this); + + m_worldEditorScene = new WorldEditorScene(NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->CellSize, this); + m_zoneBuilderBase = new LandscapeEditor::ZoneBuilderBase(m_worldEditorScene); + + m_worldEditorScene->setZoneBuilder(m_zoneBuilderBase); + m_ui.graphicsView->setScene(m_worldEditorScene); + + QActionGroup *sceneModeGroup = new QActionGroup(this); + sceneModeGroup->addAction(m_ui.selectAction); + sceneModeGroup->addAction(m_ui.moveAction); + sceneModeGroup->addAction(m_ui.rotateAction); + sceneModeGroup->addAction(m_ui.scaleAction); + sceneModeGroup->addAction(m_ui.turnAction); + sceneModeGroup->addAction(m_ui.radiusAction); + m_ui.selectAction->setChecked(true); + + m_ui.newWorldEditAction->setIcon(QIcon(Core::Constants::ICON_NEW)); + m_ui.saveWorldEditAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + + m_primitivesModel = new PrimitivesTreeModel(); + m_ui.treePrimitivesView->setModel(m_primitivesModel); + + // TODO: ? + m_ui.treePrimitivesView->setUndoStack(m_undoStack); + m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase); + + createMenus(); + createToolBars(); + readSettings(); + + connect(m_ui.newWorldEditAction, SIGNAL(triggered()), this, SLOT(newWorldEditFile())); + connect(m_ui.saveWorldEditAction, SIGNAL(triggered()), this, SLOT(saveWorldEditFile())); + +} + +WorldEditorWindow::~WorldEditorWindow() +{ + writeSettings(); + + delete m_zoneBuilderBase; +} + +QUndoStack *WorldEditorWindow::undoStack() const +{ + return m_undoStack; +} + +void WorldEditorWindow::open() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL World Edit file"), m_lastDir, + tr("All NeL World Editor file (*.worldedit)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + loadWorldEditFile(fileName); + } + setCursor(Qt::ArrowCursor); +} + +void WorldEditorWindow::loadWorldEditFile(const QString &fileName) +{ + Utils::WorldEditList worldEditList; + if (!Utils::loadWorldEditFile(fileName.toStdString(), worldEditList)) + { + return; + } + + m_undoStack->beginMacro(QString("Load %1").arg(fileName)); + + checkCurrentWorld(); + + m_undoStack->push(new CreateWorldCommand(fileName, m_primitivesModel)); + for (size_t i = 0; i < worldEditList.size(); ++i) + { + switch (worldEditList[i].first) + { + case Utils::DataDirectoryType: + m_zoneBuilderBase->init(QString(worldEditList[i].second.c_str()), true); + break; + case Utils::ContextType: + break; + case Utils::LandscapeType: + m_undoStack->push(new LoadLandscapeCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel, m_zoneBuilderBase)); + break; + case Utils::PrimitiveType: + m_undoStack->push(new LoadRootPrimitiveCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel)); + break; + }; + } + m_undoStack->endMacro(); +} + +void WorldEditorWindow::checkCurrentWorld() +{ +} + +void WorldEditorWindow::newWorldEditFile() +{ + checkCurrentWorld(); + + m_undoStack->push(new CreateWorldCommand("NewWorldEdit", m_primitivesModel)); +} + +void WorldEditorWindow::saveWorldEditFile() +{ +} + +void WorldEditorWindow::openProjectSettings() +{ + /* + LandscapeEditor::ProjectSettingsDialog *dialog = new LandscapeEditor::ProjectSettingsDialog("", this); + dialog->show(); + int ok = dialog->exec(); + if (ok == QDialog::Accepted) + { + } + delete dialog; + */ +} + +void WorldEditorWindow::createMenus() +{ + Core::IMenuManager *menuManager = Core::ICore::instance()->menuManager(); +} + +void WorldEditorWindow::createToolBars() +{ + Core::IMenuManager *menuManager = Core::ICore::instance()->menuManager(); + //QAction *action = menuManager->action(Core::Constants::NEW); + //m_ui.fileToolBar->addAction(action); + + m_ui.fileToolBar->addAction(m_ui.newWorldEditAction); + QAction *action = menuManager->action(Core::Constants::OPEN); + m_ui.fileToolBar->addAction(action); + m_ui.fileToolBar->addAction(m_ui.saveWorldEditAction); + m_ui.fileToolBar->addSeparator(); + + action = menuManager->action(Core::Constants::UNDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + action = menuManager->action(Core::Constants::REDO); + if (action != 0) + m_ui.fileToolBar->addAction(action); + + //action = menuManager->action(Core::Constants::SAVE); + //m_ui.fileToolBar->addAction(action); + //action = menuManager->action(Core::Constants::SAVE_AS); + //m_ui.fileToolBar->addAction(action); +} + +void WorldEditorWindow::readSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + restoreState(settings->value(Constants::WORLD_WINDOW_STATE).toByteArray()); + restoreGeometry(settings->value(Constants::WORLD_WINDOW_GEOMETRY).toByteArray()); + settings->endGroup(); +} + +void WorldEditorWindow::writeSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + settings->setValue(Constants::WORLD_WINDOW_STATE, saveState()); + settings->setValue(Constants::WORLD_WINDOW_GEOMETRY, saveGeometry()); + settings->endGroup(); + settings->sync(); +} + +} /* namespace LandscapeEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h new file mode 100644 index 000000000..2536bcc1c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h @@ -0,0 +1,75 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef WORLD_EDITOR_WINDOW_H +#define WORLD_EDITOR_WINDOW_H + +// Project includes +#include "ui_world_editor_window.h" + +// Qt includes +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + +namespace WorldEditor +{ +class PrimitivesTreeModel; +class WorldEditorScene; + +class WorldEditorWindow: public QMainWindow +{ + Q_OBJECT + +public: + WorldEditorWindow(QWidget *parent = 0); + ~WorldEditorWindow(); + + QUndoStack *undoStack() const; + +Q_SIGNALS: +public Q_SLOTS: + void open(); + +private Q_SLOTS: + void newWorldEditFile(); + void saveWorldEditFile(); + void openProjectSettings(); + +private: + void createMenus(); + void createToolBars(); + void readSettings(); + void writeSettings(); + + void loadWorldEditFile(const QString &fileName); + void checkCurrentWorld(); + + QString m_lastDir; + + PrimitivesTreeModel *m_primitivesModel; + QUndoStack *m_undoStack; + WorldEditorScene *m_worldEditorScene; + LandscapeEditor::ZoneBuilderBase *m_zoneBuilderBase; + Ui::WorldEditorWindow m_ui; +}; /* class WorldEditorWindow */ + +} /* namespace WorldEditor */ + +#endif // WORLD_EDITOR_WINDOW_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui new file mode 100644 index 000000000..80e4e5ace --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui @@ -0,0 +1,305 @@ + + + WorldEditorWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + :/icons/ic_nel_world_editor.png:/icons/ic_nel_world_editor.png + + + + + + + QGraphicsView::RubberBandDrag + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::AnchorUnderMouse + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + + + + Primitives + + + 2 + + + + + 3 + + + 3 + + + + + true + + + QAbstractItemView::ExtendedSelection + + + true + + + true + + + 250 + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + + loadPrimitive + + + + + newPrimitive + + + + + + :/icons/ic_nel_zonel.png:/icons/ic_nel_zonel.png + + + loadLand + + + + + + :/icons/ic_nel_landscape_settings.png:/icons/ic_nel_landscape_settings.png + + + LandSettings + + + + + true + + + S/H Land + + + + + true + + + S/H Primitives + + + + + true + + + S/H Layers + + + + + true + + + S/H Details + + + + + true + + + + :/icons/ic_grid.png:/icons/ic_grid.png + + + S/H Grid + + + + + true + + + S/H Grid points + + + + + New World Edit file + + + + + Save World Edit file + + + + + true + + + + :/icons/ic_nel_select.png:/icons/ic_nel_select.png + + + Select + + + + + true + + + + :/icons/ic_nel_move.png:/icons/ic_nel_move.png + + + Move + + + + + true + + + + :/icons/ic_nel_rotate.png:/icons/ic_nel_rotate.png + + + Rotate + + + + + true + + + + :/icons/ic_nel_scale.png:/icons/ic_nel_scale.png + + + Scale + + + + + true + + + + :/icons/ic_nel_turn.png:/icons/ic_nel_turn.png + + + Turn + + + + + true + + + Radius + + + + + true + + + Edit points + + + + + + LandscapeEditor::LandscapeView + QGraphicsView +
../landscape_editor/landscape_view.h
+
+ + WorldEditor::PrimitivesView + QTreeView +
primitives_view.h
+
+
+ + + + + +