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 program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "landscape_scene.h"
19 #include "pixmap_database.h"
22 #include <nel/misc/debug.h>
25 #include <QtGui/QPainter>
26 #include <QtGui/QGraphicsPixmapItem>
27 #include <QtGui/QGraphicsSimpleTextItem>
28 #include <QApplication>
30 namespace LandscapeEditor
33 static const int ZONE_NAME
= 0;
34 static const int LAYER_ZONES
= 2;
35 static const int LAYER_EMPTY_ZONES
= 3;
36 static const int LAYER_BLACKOUT
= 4;
37 const char *const LAYER_BLACKOUT_NAME
= "blackout";
39 const int MAX_SCENE_WIDTH
= 256;
40 const int MAX_SCENE_HEIGHT
= 256;
42 LandscapeScene::LandscapeScene(int sizeCell
, QObject
*parent
)
43 : QGraphicsScene(parent
),
45 m_transitionMode(false),
46 m_mouseButton(Qt::NoButton
),
49 setSceneRect(QRectF(0, m_cellSize
, MAX_SCENE_WIDTH
* m_cellSize
, MAX_SCENE_HEIGHT
* m_cellSize
));
52 LandscapeScene::~LandscapeScene()
56 int LandscapeScene::cellSize() const
61 void LandscapeScene::setZoneBuilder(ZoneBuilder
*zoneBuilder
)
63 m_zoneBuilder
= zoneBuilder
;
66 QGraphicsItem
*LandscapeScene::createItemZone(const LigoData
&data
, const ZonePosition
&zonePos
)
68 if ((data
.zoneName
== STRING_OUT_OF_BOUND
) || (checkUnderZone(zonePos
.x
, zonePos
.y
)))
71 if (data
.zoneName
== STRING_UNUSED
)
72 return createItemEmptyZone(zonePos
);
74 if ((m_zoneBuilder
== 0) || (data
.zoneName
.empty()))
77 // Get image from pixmap database
78 QPixmap
*pixmap
= m_zoneBuilder
->pixmapDatabase()->pixmap(QString(data
.zoneName
.c_str()));
82 // Rotate the image counterclockwise
84 matrix
.rotate(-data
.rot
* 90.0);
86 QGraphicsPixmapItem
*item
;
90 item
= addPixmap(pixmap
->transformed(matrix
, Qt::SmoothTransformation
));
95 QImage mirrorImage
= pixmap
->toImage();
96 QPixmap mirrorPixmap
= QPixmap::fromImage(mirrorImage
.mirrored(true, false));
97 item
= addPixmap(mirrorPixmap
.transformed(matrix
, Qt::SmoothTransformation
));
99 // Enable bilinear filtering
100 item
->setTransformationMode(Qt::SmoothTransformation
);
102 sint32 sizeX
= 1, sizeY
= 1;
103 sizeX
= float(pixmap
->width()) / m_zoneBuilder
->pixmapDatabase()->textureSize();
104 sizeY
= float(pixmap
->width()) / m_zoneBuilder
->pixmapDatabase()->textureSize();
106 sint32 deltaX
= 0, deltaY
= 0;
108 // Calculate offset for graphics item (for items with size that are larger than 1)
109 if ((sizeX
> 1) || (sizeY
> 1))
117 deltaY
= -data
.posY
+ sizeY
- 1;
120 deltaX
= -(sizeY
- 1 - data
.posY
);
121 deltaY
= -data
.posX
+ sizeX
- 1;
124 deltaX
= -(sizeX
- 1 - data
.posX
);
138 deltaX
= -(sizeX
- 1 - data
.posX
);
139 deltaY
= -data
.posY
+ sizeY
- 1;
142 deltaX
= -(sizeY
- 1 - data
.posY
);
151 deltaY
= -data
.posX
+ sizeX
- 1;
157 // Set position graphics item with offset for large piece
158 item
->setPos((zonePos
.x
+ deltaX
) * m_cellSize
, (abs(int(zonePos
.y
+ deltaY
))) * m_cellSize
);
160 // The size graphics item should be equal or proportional m_cellSize
161 item
->setScale(float(m_cellSize
) / m_zoneBuilder
->pixmapDatabase()->textureSize());
163 item
->setData(ZONE_NAME
, QString(data
.zoneName
.c_str()));
165 // for not full item zone
166 item
->setZValue(LAYER_ZONES
);
168 item
->setShapeMode(QGraphicsPixmapItem::BoundingRectShape
);
173 QGraphicsItem
*LandscapeScene::createItemEmptyZone(const ZonePosition
&zonePos
)
175 if (m_zoneBuilder
== 0)
178 if (checkUnderZone(zonePos
.x
, zonePos
.y
))
181 // Get image from pixmap database
182 QPixmap
*pixmap
= m_zoneBuilder
->pixmapDatabase()->pixmap(QString(STRING_UNUSED
));
187 QGraphicsPixmapItem
*item
= addPixmap(*pixmap
);
189 // Enable bilinear filtering
190 item
->setTransformationMode(Qt::SmoothTransformation
);
192 // Set position graphics item
193 item
->setPos(zonePos
.x
* m_cellSize
, abs(int(zonePos
.y
)) * m_cellSize
);
195 // The size graphics item should be equal or proportional m_cellSize
196 item
->setScale(float(m_cellSize
) / m_zoneBuilder
->pixmapDatabase()->textureSize());
198 // for not full item zone
199 item
->setZValue(LAYER_EMPTY_ZONES
);
201 item
->setShapeMode(QGraphicsPixmapItem::BoundingRectShape
);
206 QGraphicsRectItem
*LandscapeScene::createLayerBlackout(const NLLIGO::CZoneRegion
&zoneRegion
)
208 QGraphicsRectItem
*rectItem
= addRect(zoneRegion
.getMinX() * m_cellSize
,
209 abs(zoneRegion
.getMaxY()) * m_cellSize
,
210 (abs(zoneRegion
.getMaxX() - zoneRegion
.getMinX()) + 1) * m_cellSize
,
211 (abs(zoneRegion
.getMaxY() - zoneRegion
.getMinY()) + 1) * m_cellSize
,
212 Qt::NoPen
, QBrush(QColor(0, 0, 0, 50)));
214 rectItem
->setZValue(LAYER_BLACKOUT
);
215 rectItem
->setData(ZONE_NAME
, QString(LAYER_BLACKOUT_NAME
));
219 void LandscapeScene::deleteItemZone(const ZonePosition
&zonePos
)
221 QGraphicsItem
*item
= itemAt(zonePos
.x
* m_cellSize
, abs(zonePos
.y
) * m_cellSize
);
222 if ((item
!= 0) && (item
->data(ZONE_NAME
).toString() != QString(LAYER_BLACKOUT_NAME
)))
229 void LandscapeScene::addZoneRegion(const NLLIGO::CZoneRegion
&zoneRegion
)
231 for (sint32 i
= zoneRegion
.getMinX(); i
<= zoneRegion
.getMaxX(); ++i
)
233 for (sint32 j
= zoneRegion
.getMinY(); j
<= zoneRegion
.getMaxY(); ++j
)
236 std::string zoneName
= zoneRegion
.getName(i
, j
);
237 if (zoneName
== STRING_UNUSED
)
239 ZonePosition
zonePos(i
, j
, -1);
240 QGraphicsItem
*item
= createItemEmptyZone(zonePos
);
242 else if (!zoneName
.empty())
245 ZonePosition
zonePos(i
, j
, -1);
246 data
.zoneName
= zoneName
;
247 data
.rot
= zoneRegion
.getRot(i
, j
);
248 data
.flip
= zoneRegion
.getFlip(i
, j
);
249 data
.posX
= zoneRegion
.getPosX(i
, j
);
250 data
.posY
= zoneRegion
.getPosY(i
, j
);
251 QGraphicsItem
*item
= createItemZone(data
, zonePos
);
257 void LandscapeScene::delZoneRegion(const NLLIGO::CZoneRegion
&zoneRegion
)
259 for (sint32 i
= zoneRegion
.getMinX(); i
<= zoneRegion
.getMaxX(); ++i
)
261 for (sint32 j
= zoneRegion
.getMinY(); j
<= zoneRegion
.getMaxY(); ++j
)
263 deleteItemZone(ZonePosition(i
, -j
, -1));
268 void LandscapeScene::snapshot(const QString
&fileName
, int width
, int height
, const QRectF
&landRect
)
270 if (m_zoneBuilder
== 0)
274 QImage
image(landRect
.width(), landRect
.height(), QImage::Format_RGB888
);
275 QPainter
painter(&image
);
276 painter
.setRenderHint(QPainter::Antialiasing
, true);
278 // Add white background
279 painter
.setBrush(QBrush(Qt::white
));
280 painter
.setPen(Qt::NoPen
);
281 painter
.drawRect(0, 0, landRect
.width(), landRect
.height());
284 render(&painter
, QRectF(0, 0, landRect
.width(), landRect
.height()), landRect
);
286 QImage scaledImage
= image
.scaled(width
, height
, Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
287 scaledImage
.save(fileName
);
290 QString
LandscapeScene::zoneNameFromMousePos() const
292 if ((m_posY
> 0) || (m_posY
< -MAX_SCENE_HEIGHT
) ||
293 (m_posX
< 0) || (m_posX
> MAX_SCENE_WIDTH
))
294 return "NOT A VALID ZONE";
296 return QString("%1_%2%3 %4 %5 ").arg(-m_posY
).arg(QChar('A' + (m_posX
/26))).
297 arg(QChar('A' + (m_posX
%26))).arg(m_mouseX
, 0,'f',2).arg(-m_mouseY
, 0,'f',2);
300 void LandscapeScene::mousePressEvent(QGraphicsSceneMouseEvent
*mouseEvent
)
302 qreal x
= mouseEvent
->scenePos().x();
303 qreal y
= mouseEvent
->scenePos().y();
304 if ((x
< 0) || (y
< 0))
307 m_posX
= sint32(floor(x
/ m_cellSize
));
308 m_posY
= sint32(-floor(y
/ m_cellSize
));
310 if (m_zoneBuilder
== 0)
312 if (m_transitionMode
)
314 if (mouseEvent
->button() == Qt::LeftButton
)
316 // Need add offset(= cellSize) on y axes
317 m_zoneBuilder
->addTransition(sint(x
), sint(-y
+ m_cellSize
));
321 if (mouseEvent
->button() == Qt::LeftButton
)
322 m_zoneBuilder
->addZone(m_posX
, m_posY
);
323 else if (mouseEvent
->button() == Qt::RightButton
)
324 m_zoneBuilder
->delZone(m_posX
, m_posY
);
326 m_mouseButton
= mouseEvent
->button();
328 QGraphicsScene::mousePressEvent(mouseEvent
);
331 void LandscapeScene::mouseMoveEvent(QGraphicsSceneMouseEvent
*mouseEvent
)
333 qreal x
= mouseEvent
->scenePos().x();
334 qreal y
= mouseEvent
->scenePos().y();
336 sint32 posX
= sint32(floor(x
/ m_cellSize
));
337 sint32 posY
= sint32(-floor(y
/ m_cellSize
));
339 if ((m_posX
!= posX
|| m_posY
!= posY
) &&
340 (m_mouseButton
== Qt::LeftButton
||
341 m_mouseButton
== Qt::RightButton
))
343 if (m_transitionMode
)
348 if (m_mouseButton
== Qt::LeftButton
)
349 m_zoneBuilder
->addZone(posX
, posY
);
350 else if (m_mouseButton
== Qt::RightButton
)
351 m_zoneBuilder
->delZone(posX
, posY
);
355 QApplication::processEvents();
361 m_mouseX
= mouseEvent
->scenePos().x();
362 m_mouseY
= mouseEvent
->scenePos().y() - m_cellSize
;
363 QGraphicsScene::mouseMoveEvent(mouseEvent
);
366 void LandscapeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent
*mouseEvent
)
368 m_mouseButton
= Qt::NoButton
;
371 bool LandscapeScene::checkUnderZone(const int posX
, const int posY
)
373 QGraphicsItem
*item
= itemAt((posX
* m_cellSize
), abs(posY
) * m_cellSize
);
376 //if (item->data(ZONE_NAME) == QString(LAYER_BLACKOUT_NAME))
384 bool LandscapeScene::transitionMode() const
386 return m_transitionMode
;
389 void LandscapeScene::setTransitionMode(bool enabled
)
391 m_transitionMode
= enabled
;
395 void LandscapeScene::drawForeground(QPainter
*painter
, const QRectF
&rect
)
397 QGraphicsScene::drawForeground(painter
, rect
);
398 if ((m_zoneBuilder
->currentIdZoneRegion() != -1) && (m_transitionMode
))
399 drawTransition(painter
, rect
);
402 void LandscapeScene::drawTransition(QPainter
*painter
, const QRectF
&rect
)
404 int left
= int(floor(rect
.left() / m_cellSize
));
405 int right
= int(floor(rect
.right() / m_cellSize
));
406 int top
= int(floor(rect
.top() / m_cellSize
));
407 int bottom
= int(floor(rect
.bottom() / m_cellSize
));
409 QVector
<QLine
> redLines
;
410 QVector
<QLine
> whiteLines
;
412 for (int i
= left
; i
< right
+ 1; ++i
)
414 for (int j
= top
; j
< bottom
+ 1; ++j
)
417 NLLIGO::CZoneRegion
&zoneRegion
= m_zoneBuilder
->currentZoneRegion()->ligoZoneRegion();
418 uint8 ceUp
= zoneRegion
.getCutEdge (i
, -j
, 0);
419 uint8 ceLeft
= zoneRegion
.getCutEdge (i
, -j
, 2);
420 if ((ceUp
> 0) && (ceUp
< 3))
422 // Calculate position vertical lines
425 y1
= j
* m_cellSize
+ m_cellSize
/ 12.0f
;
426 y2
= y1
- (m_cellSize
/ 6.0f
);
428 x1
= i
* m_cellSize
+ 3.0f
* m_cellSize
/ 12.0f
;
429 x2
= i
* m_cellSize
+ 5.0f
* m_cellSize
/ 12.0f
;
432 whiteLines
.push_back(QLine(x1
, y1
, x1
, y2
));
433 whiteLines
.push_back(QLine(x2
, y1
, x2
, y2
));
437 redLines
.push_back(QLine(x1
, y1
, x1
, y2
));
438 redLines
.push_back(QLine(x2
, y1
, x2
, y2
));
441 x1
= i
* m_cellSize
+ 7.0f
* m_cellSize
/ 12.0f
;
442 x2
= i
* m_cellSize
+ 9.0f
* m_cellSize
/ 12.0f
;
445 redLines
.push_back(QLine(x1
, y1
, x1
, y2
));
446 redLines
.push_back(QLine(x2
, y1
, x2
, y2
));
450 whiteLines
.push_back(QLine(x1
, y1
, x1
, y2
));
451 whiteLines
.push_back(QLine(x2
, y1
, x2
, y2
));
454 if ((ceLeft
> 0) && (ceLeft
< 3))
456 // Calculate position horizontal lines
459 x1
= i
* m_cellSize
- m_cellSize
/ 12.0f
;
460 x2
= x1
+ (m_cellSize
/ 6.0f
);
462 y1
= j
* m_cellSize
+ 3.0f
* m_cellSize
/ 12.0f
;
463 y2
= j
* m_cellSize
+ 5.0f
* m_cellSize
/ 12.0f
;
466 redLines
.push_back(QLine(x1
, y1
, x2
, y1
));
467 redLines
.push_back(QLine(x1
, y2
, x2
, y2
));
471 whiteLines
.push_back(QLine(x1
, y1
, x2
, y1
));
472 whiteLines
.push_back(QLine(x1
, y2
, x2
, y2
));
475 y1
= j
* m_cellSize
+ 7.0f
* m_cellSize
/ 12.0f
;
476 y2
= j
* m_cellSize
+ 9.0f
* m_cellSize
/ 12.0f
;
479 whiteLines
.push_back(QLine(x1
, y1
, x2
, y1
));
480 whiteLines
.push_back(QLine(x1
, y2
, x2
, y2
));
484 redLines
.push_back(QLine(x1
, y1
, x2
, y1
));
485 redLines
.push_back(QLine(x1
, y2
, x2
, y2
));
492 painter
->setPen(QPen(Qt::red
, 0, Qt::SolidLine
));
493 painter
->drawLines(redLines
);
494 painter
->setPen(QPen(Qt::white
, 0, Qt::SolidLine
));
495 painter
->drawLines(whiteLines
);
498 } /* namespace LandscapeEditor */