New lua versions
[ryzomcore.git] / studio / src / plugins / landscape_editor / builder_zone.cpp
blob8ed5121a494f6b394005fa05ddf42fdfc6f846fb
1 // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2011 Dzmitry KAMIAHIN (dnk-88) <dnk-88@tut.by>
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Winch Gate Property Limited
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 // Project includes
21 #include "builder_zone.h"
22 #include "list_zones_widget.h"
23 #include "landscape_actions.h"
25 // NeL includes
26 #include <nel/misc/debug.h>
28 // Qt includes
29 #include <QtCore/QDir>
30 #include <QtGui/QMessageBox>
31 #include <QtGui/QProgressDialog>
33 namespace LandscapeEditor
35 int LandCounter = 0;
37 ZoneBuilder::ZoneBuilder(LandscapeScene *landscapeScene, ListZonesWidget *listZonesWidget, QUndoStack *undoStack)
38 : m_currentZoneRegion(-1),
39 m_pixmapDatabase(0),
40 m_listZonesWidget(listZonesWidget),
41 m_landscapeScene(landscapeScene),
42 m_undoStack(undoStack)
44 nlassert(m_landscapeScene);
45 m_pixmapDatabase = new PixmapDatabase();
46 m_lastPathName = "";
49 ZoneBuilder::~ZoneBuilder()
51 delete m_pixmapDatabase;
54 bool ZoneBuilder::init(const QString &pathName, bool displayProgress)
56 if (pathName.isEmpty())
57 return false;
58 if (pathName != m_lastPathName)
60 m_lastPathName = pathName;
61 QString zoneBankPath = pathName;
62 zoneBankPath += "/zoneligos/";
64 // Init the ZoneBank
65 m_zoneBank.reset();
66 if (!initZoneBank (zoneBankPath))
68 m_zoneBank.reset();
69 return false;
71 // Construct the DataBase from the ZoneBank
72 QString zoneBitmapPath = pathName;
73 zoneBitmapPath += "/zonebitmaps/";
74 m_pixmapDatabase->reset();
75 if (!m_pixmapDatabase->loadPixmaps(zoneBitmapPath, m_zoneBank, displayProgress))
77 m_zoneBank.reset();
78 return false;
81 return true;
84 void ZoneBuilder::actionLigoTile(const LigoData &data, const ZonePosition &zonePos)
86 if (m_undoStack == 0)
87 return;
89 checkBeginMacro();
90 // nlinfo(QString("%1 %2 %3 (%4 %5)").arg(data.zoneName.c_str()).arg(zonePos.x).arg(zonePos.y).arg(data.posX).arg(data.posY).toUtf8().constData());
91 m_zonePositionList.push_back(zonePos);
92 m_undoStack->push(new LigoTileCommand(data, zonePos, this, m_landscapeScene));
95 void ZoneBuilder::actionLigoMove(uint index, sint32 deltaX, sint32 deltaY)
97 if (m_undoStack == 0)
98 return;
100 checkBeginMacro();
101 //m_undoStack->push(new LigoMoveCommand(index, deltaX, deltaY, this));
104 void ZoneBuilder::actionLigoResize(uint index, sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY)
106 if (m_undoStack == 0)
107 return;
109 checkBeginMacro();
110 // nlinfo(QString("minX=%1 maxX=%2 minY=%3 maxY=%4").arg(newMinX).arg(newMaxX).arg(newMinY).arg(newMaxY).toUtf8().constData());
111 m_undoStack->push(new LigoResizeCommand(index, newMinX, newMaxX, newMinY, newMaxY, this));
114 void ZoneBuilder::addZone(sint32 posX, sint32 posY)
116 // Read-only mode
117 if ((m_listZonesWidget == 0) || (m_undoStack == 0))
118 return;
120 if (m_landscapeMap.empty())
121 return;
123 // Check zone name
124 std::string zoneName = m_listZonesWidget->currentZoneName().toUtf8().constData();
125 if (zoneName.empty())
126 return;
128 BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion;
129 builderZoneRegion->init(this);
131 uint8 rot = uint8(m_listZonesWidget->currentRot());
132 uint8 flip = uint8(m_listZonesWidget->currentFlip());
134 NLLIGO::CZoneBankElement *zoneBankElement = getZoneBank().getElementByZoneName(zoneName);
136 m_titleAction = QString("Add zone %1,%2").arg(posX).arg(posY);
137 m_createdAction = false;
138 m_zonePositionList.clear();
139 if (m_listZonesWidget->isForce())
141 builderZoneRegion->addForce(posX, posY, rot, flip, zoneBankElement);
143 else
145 if (m_listZonesWidget->isNotPropogate())
146 builderZoneRegion->addNotPropagate(posX, posY, rot, flip, zoneBankElement);
147 else
148 builderZoneRegion->add(posX, posY, rot, flip, zoneBankElement);
150 checkEndMacro();
153 void ZoneBuilder::addTransition(const sint32 posX, const sint32 posY)
155 // Read-only mode
156 if ((m_listZonesWidget == 0) || (m_undoStack == 0))
157 return;
159 if (m_landscapeMap.empty())
160 return;
162 m_titleAction = QString("Transition zone %1,%2").arg(posX).arg(posY);
163 m_createdAction = false;
164 m_zonePositionList.clear();
166 nlinfo(QString("trans %1,%2").arg(posX).arg(posY).toUtf8().constData());
168 sint32 x = (sint32)floor(float(posX) / m_landscapeScene->cellSize());
169 sint32 y = (sint32)floor(float(posY) / m_landscapeScene->cellSize());
170 sint32 k;
172 // Detect if we are in a transition square to switch
173 BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion;
174 builderZoneRegion->init(this);
175 const NLLIGO::CZoneRegion &zoneRegion = currentZoneRegion()->ligoZoneRegion();
176 bool bCutEdgeTouched = false;
177 for (uint8 transPos = 0; transPos < 4; ++transPos)
179 uint ce = zoneRegion.getCutEdge(x, y, transPos);
181 if ((ce > 0) && (ce < 3))
182 for (k = 0; k < 2; ++k)
184 float xTrans, yTrans;
186 if ((transPos == 0) || (transPos == 1))
188 if (ce == 1)
189 xTrans = m_landscapeScene->cellSize() / 3.0f;
190 else
191 xTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f;
193 else
195 if (transPos == 2)
196 xTrans = 0;
197 else
198 xTrans = m_landscapeScene->cellSize();
200 xTrans += x * m_landscapeScene->cellSize();
202 if ((transPos == 2) || (transPos == 3))
204 if (ce == 1)
205 yTrans = m_landscapeScene->cellSize() / 3.0f;
206 else
207 yTrans = 2.0f * m_landscapeScene->cellSize() / 3.0f;
209 else
211 if (transPos == 1)
212 yTrans = 0;
213 else
214 yTrans = m_landscapeScene->cellSize();
216 yTrans += y * m_landscapeScene->cellSize();
218 if ((posX >= (xTrans - m_landscapeScene->cellSize() / 12.0f)) &&
219 (posX <= (xTrans + m_landscapeScene->cellSize() / 12.0f)) &&
220 (posY >= (yTrans - m_landscapeScene->cellSize() / 12.0f)) &&
221 (posY <= (yTrans + m_landscapeScene->cellSize() / 12.0f)))
223 builderZoneRegion->invertCutEdge (x, y, transPos);
224 bCutEdgeTouched = true;
226 ce = 3 - ce;
230 // If not clicked to change the cutEdge so the user want to change the transition
231 if (!bCutEdgeTouched)
233 builderZoneRegion->cycleTransition (x, y);
235 checkEndMacro();
238 void ZoneBuilder::delZone(const sint32 posX, const sint32 posY)
240 if ((m_listZonesWidget == 0) || (m_undoStack == 0))
241 return;
243 if (m_landscapeMap.empty())
244 return;
246 m_titleAction = QString("Del zone %1,%2").arg(posX).arg(posY);
247 m_createdAction = false;
249 BuilderZoneRegion *builderZoneRegion = m_landscapeMap.value(m_currentZoneRegion).builderZoneRegion;
251 builderZoneRegion->init(this);
252 builderZoneRegion->del(posX, posY);
253 checkEndMacro();
256 int ZoneBuilder::createZoneRegion()
258 LandscapeItem landItem;
259 landItem.zoneRegionObject = new ZoneRegionObject();
260 landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter);
261 landItem.builderZoneRegion->init(this);
262 landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion());
264 m_landscapeMap.insert(LandCounter, landItem);
265 if (m_currentZoneRegion == -1)
266 setCurrentZoneRegion(LandCounter);
268 calcMask();
269 return LandCounter++;
272 int ZoneBuilder::createZoneRegion(const QString &fileName)
274 LandscapeItem landItem;
275 landItem.zoneRegionObject = new ZoneRegionObject();
276 landItem.zoneRegionObject->load(fileName.toUtf8().constData());
278 if (checkOverlaps(landItem.zoneRegionObject->ligoZoneRegion()))
280 delete landItem.zoneRegionObject;
281 return -1;
283 landItem.builderZoneRegion = new BuilderZoneRegion(LandCounter);
284 landItem.builderZoneRegion->init(this);
286 m_landscapeScene->addZoneRegion(landItem.zoneRegionObject->ligoZoneRegion());
287 landItem.rectItem = m_landscapeScene->createLayerBlackout(landItem.zoneRegionObject->ligoZoneRegion());
288 m_landscapeMap.insert(LandCounter, landItem);
290 if (m_currentZoneRegion == -1)
291 setCurrentZoneRegion(LandCounter);
293 calcMask();
294 return LandCounter++;
297 void ZoneBuilder::deleteZoneRegion(int id)
299 if (m_landscapeMap.contains(id))
301 if (m_landscapeMap.value(id).rectItem != 0)
302 delete m_landscapeMap.value(id).rectItem;
303 m_landscapeScene->delZoneRegion(m_landscapeMap.value(id).zoneRegionObject->ligoZoneRegion());
304 delete m_landscapeMap.value(id).zoneRegionObject;
305 delete m_landscapeMap.value(id).builderZoneRegion;
306 m_landscapeMap.remove(id);
307 calcMask();
309 else
310 nlwarning("Landscape (id %i) not found", id);
313 void ZoneBuilder::setCurrentZoneRegion(int id)
315 if (m_landscapeMap.contains(id))
317 if (currentIdZoneRegion() != -1)
319 NLLIGO::CZoneRegion &ligoRegion = m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject->ligoZoneRegion();
320 m_landscapeMap[m_currentZoneRegion].rectItem = m_landscapeScene->createLayerBlackout(ligoRegion);
322 delete m_landscapeMap.value(id).rectItem;
323 m_landscapeMap[id].rectItem = 0;
324 m_currentZoneRegion = id;
325 calcMask();
327 else
328 nlwarning("Landscape (id %i) not found", id);
331 int ZoneBuilder::currentIdZoneRegion() const
333 return m_currentZoneRegion;
336 ZoneRegionObject *ZoneBuilder::currentZoneRegion() const
338 ZoneRegionObject *result = 0;
339 if (m_landscapeMap.contains(m_currentZoneRegion))
340 result = m_landscapeMap.value(m_currentZoneRegion).zoneRegionObject;
342 return result;
345 int ZoneBuilder::countZoneRegion() const
347 return m_landscapeMap.size();
350 ZoneRegionObject *ZoneBuilder::zoneRegion(int id) const
352 ZoneRegionObject *result = 0;
353 if (m_landscapeMap.contains(id))
354 result = m_landscapeMap.value(id).zoneRegionObject;
356 return result;
359 bool ZoneBuilder::ligoData(LigoData &data, const ZonePosition &zonePos)
361 if (m_landscapeMap.contains(zonePos.region))
363 m_landscapeMap.value(zonePos.region).zoneRegionObject->ligoData(data, zonePos.x, zonePos.y);
364 return true;
366 return false;
369 void ZoneBuilder::setLigoData(LigoData &data, const ZonePosition &zonePos)
371 if (m_landscapeMap.contains(zonePos.region))
372 m_landscapeMap.value(zonePos.region).zoneRegionObject->setLigoData(data, zonePos.x, zonePos.y);
375 bool ZoneBuilder::initZoneBank (const QString &pathName)
377 QDir *dir = new QDir(pathName);
378 QStringList filters;
379 filters << "*.ligozone";
381 // Find all ligozone files in dir
382 QStringList listFiles = dir->entryList(filters, QDir::Files);
384 std::string error;
385 Q_FOREACH(QString file, listFiles)
387 //nlinfo(file.toUtf8().constData());
388 if (!m_zoneBank.addElement((pathName + file).toUtf8().constData(), error))
389 QMessageBox::critical(0, QObject::tr("Landscape editor"), QString(error.c_str()), QMessageBox::Ok);
391 delete dir;
392 return true;
395 PixmapDatabase *ZoneBuilder::pixmapDatabase() const
397 return m_pixmapDatabase;
400 QString ZoneBuilder::dataPath() const
402 return m_lastPathName;
405 bool ZoneBuilder::getZoneMask(sint32 x, sint32 y)
407 if ((x < m_minX) || (x > m_maxX) ||
408 (y < m_minY) || (y > m_maxY))
409 return true;
410 else
411 return m_zoneMask[(x - m_minX) + (y - m_minY) * (1 + m_maxX - m_minX)];
414 void ZoneBuilder::calcMask()
416 sint32 x, y;
418 m_minY = m_minX = 1000000;
419 m_maxY = m_maxX = -1000000;
421 if (m_landscapeMap.size() == 0)
422 return;
424 QMapIterator<int, LandscapeItem> i(m_landscapeMap);
425 while (i.hasNext())
427 i.next();
428 const NLLIGO::CZoneRegion &region = i.value().zoneRegionObject->ligoZoneRegion();
430 if (m_minX > region.getMinX())
431 m_minX = region.getMinX();
432 if (m_minY > region.getMinY())
433 m_minY = region.getMinY();
434 if (m_maxX < region.getMaxX())
435 m_maxX = region.getMaxX();
436 if (m_maxY < region.getMaxY())
437 m_maxY = region.getMaxY();
440 m_zoneMask.resize ((1 + m_maxX - m_minX) * (1 + m_maxY - m_minY));
441 sint32 stride = (1 + m_maxX - m_minX);
442 for (y = m_minY; y <= m_maxY; ++y)
443 for (x = m_minX; x <= m_maxX; ++x)
445 m_zoneMask[x - m_minX + (y - m_minY) * stride] = true;
447 QMapIterator<int, LandscapeItem> it(m_landscapeMap);
448 while (it.hasNext())
450 it.next();
451 if (int(it.key()) != m_currentZoneRegion)
453 const NLLIGO::CZoneRegion &region = it.value().zoneRegionObject->ligoZoneRegion();
455 const std::string &rSZone = region.getName (x, y);
456 if ((rSZone != STRING_OUT_OF_BOUND) && (rSZone != STRING_UNUSED))
458 m_zoneMask[x - m_minX + (y - m_minY) * stride] = false;
465 bool ZoneBuilder::getZoneAmongRegions(ZonePosition &zonePos, BuilderZoneRegion *builderZoneRegionFrom, sint32 x, sint32 y)
467 QMapIterator<int, LandscapeItem> it(m_landscapeMap);
468 while (it.hasNext())
470 it.next();
471 const NLLIGO::CZoneRegion &region = it.value().zoneRegionObject->ligoZoneRegion();
472 if ((x < region.getMinX()) || (x > region.getMaxX()) ||
473 (y < region.getMinY()) || (y > region.getMaxY()))
474 continue;
475 if (region.getName(x, y) != STRING_UNUSED)
477 builderZoneRegionFrom = it.value().builderZoneRegion;
478 zonePos = ZonePosition(x, y, it.key());
479 return true;
483 // The zone is not present in other region so it is an empty or oob zone of the current region
484 const NLLIGO::CZoneRegion &region = zoneRegion(builderZoneRegionFrom->getRegionId())->ligoZoneRegion();
485 if ((x < region.getMinX()) || (x > region.getMaxX()) ||
486 (y < region.getMinY()) || (y > region.getMaxY()))
487 return false; // Out Of Bound
489 zonePos = ZonePosition(x, y, builderZoneRegionFrom->getRegionId());
490 return true;
493 void ZoneBuilder::checkBeginMacro()
495 if (!m_createdAction)
497 m_createdAction = true;
498 m_undoStack->beginMacro(m_titleAction);
499 m_undoScanRegionCommand = new UndoScanRegionCommand(true, this, m_landscapeScene);
500 m_undoStack->push(m_undoScanRegionCommand);
504 void ZoneBuilder::checkEndMacro()
506 if (m_createdAction)
508 UndoScanRegionCommand *redoScanRegionCommand = new UndoScanRegionCommand(false, this, m_landscapeScene);
510 // Sets list positions in which need apply changes
511 m_undoScanRegionCommand->setScanList(m_zonePositionList);
512 redoScanRegionCommand->setScanList(m_zonePositionList);
514 // Adds command in the stack
515 m_undoStack->push(redoScanRegionCommand);
516 m_undoStack->endMacro();
520 bool ZoneBuilder::checkOverlaps(const NLLIGO::CZoneRegion &newZoneRegion)
522 QMapIterator<int, LandscapeItem> it(m_landscapeMap);
523 while (it.hasNext())
525 it.next();
526 const NLLIGO::CZoneRegion &zoneRegion = it.value().zoneRegionObject->ligoZoneRegion();
527 for (sint32 y = zoneRegion.getMinY(); y <= zoneRegion.getMaxY(); ++y)
528 for (sint32 x = zoneRegion.getMinX(); x <= zoneRegion.getMaxX(); ++x)
530 const std::string &refZoneName = zoneRegion.getName(x, y);
531 if (refZoneName != STRING_UNUSED)
533 const std::string &zoneName = newZoneRegion.getName(x, y);
534 if ((zoneName != STRING_UNUSED) && (zoneName != STRING_OUT_OF_BOUND))
535 return true;
539 return false;
542 } /* namespace LandscapeEditor */