1 // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2011 Dzmitry KAMIAHIN (dnk-88) <dnk-88@tut.by>
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Winch Gate Property Limited
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/>.
21 #include "builder_zone.h"
22 #include "list_zones_widget.h"
23 #include "landscape_actions.h"
26 #include <nel/misc/debug.h>
29 #include <QtCore/QDir>
30 #include <QtGui/QMessageBox>
31 #include <QtGui/QProgressDialog>
33 namespace LandscapeEditor
37 ZoneBuilder::ZoneBuilder(LandscapeScene
*landscapeScene
, ListZonesWidget
*listZonesWidget
, QUndoStack
*undoStack
)
38 : m_currentZoneRegion(-1),
40 m_listZonesWidget(listZonesWidget
),
41 m_landscapeScene(landscapeScene
),
42 m_undoStack(undoStack
)
44 nlassert(m_landscapeScene
);
45 m_pixmapDatabase
= new PixmapDatabase();
49 ZoneBuilder::~ZoneBuilder()
51 delete m_pixmapDatabase
;
54 bool ZoneBuilder::init(const QString
&pathName
, bool displayProgress
)
56 if (pathName
.isEmpty())
58 if (pathName
!= m_lastPathName
)
60 m_lastPathName
= pathName
;
61 QString zoneBankPath
= pathName
;
62 zoneBankPath
+= "/zoneligos/";
66 if (!initZoneBank (zoneBankPath
))
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
))
84 void ZoneBuilder::actionLigoTile(const LigoData
&data
, const ZonePosition
&zonePos
)
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
)
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)
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
)
117 if ((m_listZonesWidget
== 0) || (m_undoStack
== 0))
120 if (m_landscapeMap
.empty())
124 std::string zoneName
= m_listZonesWidget
->currentZoneName().toUtf8().constData();
125 if (zoneName
.empty())
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
);
145 if (m_listZonesWidget
->isNotPropogate())
146 builderZoneRegion
->addNotPropagate(posX
, posY
, rot
, flip
, zoneBankElement
);
148 builderZoneRegion
->add(posX
, posY
, rot
, flip
, zoneBankElement
);
153 void ZoneBuilder::addTransition(const sint32 posX
, const sint32 posY
)
156 if ((m_listZonesWidget
== 0) || (m_undoStack
== 0))
159 if (m_landscapeMap
.empty())
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());
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))
189 xTrans
= m_landscapeScene
->cellSize() / 3.0f
;
191 xTrans
= 2.0f
* m_landscapeScene
->cellSize() / 3.0f
;
198 xTrans
= m_landscapeScene
->cellSize();
200 xTrans
+= x
* m_landscapeScene
->cellSize();
202 if ((transPos
== 2) || (transPos
== 3))
205 yTrans
= m_landscapeScene
->cellSize() / 3.0f
;
207 yTrans
= 2.0f
* m_landscapeScene
->cellSize() / 3.0f
;
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;
230 // If not clicked to change the cutEdge so the user want to change the transition
231 if (!bCutEdgeTouched
)
233 builderZoneRegion
->cycleTransition (x
, y
);
238 void ZoneBuilder::delZone(const sint32 posX
, const sint32 posY
)
240 if ((m_listZonesWidget
== 0) || (m_undoStack
== 0))
243 if (m_landscapeMap
.empty())
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
);
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
);
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
;
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
);
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
);
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
;
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
;
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
;
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
);
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
);
379 filters
<< "*.ligozone";
381 // Find all ligozone files in dir
382 QStringList listFiles
= dir
->entryList(filters
, QDir::Files
);
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
);
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
))
411 return m_zoneMask
[(x
- m_minX
) + (y
- m_minY
) * (1 + m_maxX
- m_minX
)];
414 void ZoneBuilder::calcMask()
418 m_minY
= m_minX
= 1000000;
419 m_maxY
= m_maxX
= -1000000;
421 if (m_landscapeMap
.size() == 0)
424 QMapIterator
<int, LandscapeItem
> i(m_landscapeMap
);
428 const NLLIGO::CZoneRegion
®ion
= 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
);
451 if (int(it
.key()) != m_currentZoneRegion
)
453 const NLLIGO::CZoneRegion
®ion
= 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
);
471 const NLLIGO::CZoneRegion
®ion
= it
.value().zoneRegionObject
->ligoZoneRegion();
472 if ((x
< region
.getMinX()) || (x
> region
.getMaxX()) ||
473 (y
< region
.getMinY()) || (y
> region
.getMaxY()))
475 if (region
.getName(x
, y
) != STRING_UNUSED
)
477 builderZoneRegionFrom
= it
.value().builderZoneRegion
;
478 zonePos
= ZonePosition(x
, y
, it
.key());
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
®ion
= 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());
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()
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
);
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
))
542 } /* namespace LandscapeEditor */