Linux multi-monitor fullscreen support
[ryzomcore.git] / studio / src / plugins / landscape_editor / landscape_scene.cpp
blobf877935b54c5d47cb3dd774a9ab412df559c0a45
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 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.
8 //
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/>.
17 // Project includes
18 #include "landscape_scene.h"
19 #include "pixmap_database.h"
21 // NeL includes
22 #include <nel/misc/debug.h>
24 // Qt includes
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),
44 m_cellSize(sizeCell),
45 m_transitionMode(false),
46 m_mouseButton(Qt::NoButton),
47 m_zoneBuilder(0)
49 setSceneRect(QRectF(0, m_cellSize, MAX_SCENE_WIDTH * m_cellSize, MAX_SCENE_HEIGHT * m_cellSize));
52 LandscapeScene::~LandscapeScene()
56 int LandscapeScene::cellSize() const
58 return m_cellSize;
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)))
69 return 0;
71 if (data.zoneName == STRING_UNUSED)
72 return createItemEmptyZone(zonePos);
74 if ((m_zoneBuilder == 0) || (data.zoneName.empty()))
75 return 0;
77 // Get image from pixmap database
78 QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(data.zoneName.c_str()));
79 if (pixmap == 0)
80 return 0;
82 // Rotate the image counterclockwise
83 QMatrix matrix;
84 matrix.rotate(-data.rot * 90.0);
86 QGraphicsPixmapItem *item;
88 if (data.flip == 0)
90 item = addPixmap(pixmap->transformed(matrix, Qt::SmoothTransformation));
92 else
94 // mirror image
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))
111 if (data.flip == 0)
113 switch (data.rot)
115 case 0:
116 deltaX = -data.posX;
117 deltaY = -data.posY + sizeY - 1;
118 break;
119 case 1:
120 deltaX = -(sizeY - 1 - data.posY);
121 deltaY = -data.posX + sizeX - 1;
122 break;
123 case 2:
124 deltaX = -(sizeX - 1 - data.posX);
125 deltaY = data.posY;
126 break;
127 case 3:
128 deltaX = -data.posY;
129 deltaY = data.posX;
130 break;
133 else
135 switch (data.rot)
137 case 0:
138 deltaX = -(sizeX - 1 - data.posX);
139 deltaY = -data.posY + sizeY - 1;
140 break;
141 case 1:
142 deltaX = -(sizeY - 1 - data.posY);
143 deltaY = +data.posX;
144 break;
145 case 2:
146 deltaX = -data.posX;
147 deltaY = data.posY;
148 break;
149 case 3:
150 deltaX = -data.posY;
151 deltaY = -data.posX + sizeX - 1;
152 break;
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);
170 return item;
173 QGraphicsItem *LandscapeScene::createItemEmptyZone(const ZonePosition &zonePos)
175 if (m_zoneBuilder == 0)
176 return 0;
178 if (checkUnderZone(zonePos.x, zonePos.y))
179 return 0;
181 // Get image from pixmap database
182 QPixmap *pixmap = m_zoneBuilder->pixmapDatabase()->pixmap(QString(STRING_UNUSED));
184 if (pixmap == 0)
185 return 0;
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);
203 return item;
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));
216 return rectItem;
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)))
224 removeItem(item);
225 delete item;
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())
244 LigoData data;
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)
271 return;
273 // Create image
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());
283 // Paint landscape
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))
305 return;
307 m_posX = sint32(floor(x / m_cellSize));
308 m_posY = sint32(-floor(y / m_cellSize));
310 if (m_zoneBuilder == 0)
311 return;
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));
319 else
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)
346 else
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);
353 m_posX = posX;
354 m_posY = posY;
355 QApplication::processEvents();
358 m_posX = posX;
359 m_posY = posY;
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);
374 if (item != 0)
376 //if (item->data(ZONE_NAME) == QString(LAYER_BLACKOUT_NAME))
377 // return false;
378 //else
379 return true;
381 return false;
384 bool LandscapeScene::transitionMode() const
386 return m_transitionMode;
389 void LandscapeScene::setTransitionMode(bool enabled)
391 m_transitionMode = enabled;
392 update();
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)
416 // Get LIGO data
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
423 int x1, x2, y1, y2;
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;
430 if (ceUp == 1)
432 whiteLines.push_back(QLine(x1, y1, x1, y2));
433 whiteLines.push_back(QLine(x2, y1, x2, y2));
435 else
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;
443 if (ceUp == 1)
445 redLines.push_back(QLine(x1, y1, x1, y2));
446 redLines.push_back(QLine(x2, y1, x2, y2));
448 else
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
457 int x1, x2, y1, y2;
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;
464 if (ceLeft == 1)
466 redLines.push_back(QLine(x1, y1, x2, y1));
467 redLines.push_back(QLine(x1, y2, x2, y2));
469 else
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;
477 if (ceLeft == 1)
479 whiteLines.push_back(QLine(x1, y1, x2, y1));
480 whiteLines.push_back(QLine(x1, y2, x2, y2));
482 else
484 redLines.push_back(QLine(x1, y1, x2, y1));
485 redLines.push_back(QLine(x1, y2, x2, y2));
491 // Draw lines
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 */