diff --git a/src/map/renderer/painterrenderer.cpp b/src/map/renderer/painterrenderer.cpp index 0b12ab1..81b177a 100644 --- a/src/map/renderer/painterrenderer.cpp +++ b/src/map/renderer/painterrenderer.cpp @@ -1,215 +1,215 @@ /* Copyright (C) 2020 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "painterrenderer.h" #include "view.h" #include "../scene/scenegraph.h" #include #include #include #include #include using namespace KOSMIndoorMap; PainterRenderer::PainterRenderer() = default; PainterRenderer::~PainterRenderer() = default; -void PainterRenderer::setPaintDevice(QPaintDevice *device) +void PainterRenderer::setPainter(QPainter *painter) { - m_device = device; + m_painter = painter; } void PainterRenderer::render(const SceneGraph &sg, View *view) { QElapsedTimer frameTimer; frameTimer.start(); m_view = view; beginRender(); renderBackground(sg.backgroundColor()); for (const auto &layerOffsets : sg.layerOffsets()) { const auto layerBegin = sg.itemsBegin(layerOffsets); const auto layerEnd = sg.itemsEnd(layerOffsets); //qDebug() << "rendering layer" << (*layerBegin)->layer; // select elements currently in view m_renderBatch.clear(); m_renderBatch.reserve(layerOffsets.second - layerOffsets.first); const QRectF screenRect(QPointF(0, 0), QSizeF(m_view->screenWidth(), m_view->screenHeight())); for (auto it = layerBegin; it != layerEnd; ++it) { if ((*it).payload->inSceneSpace() && m_view->viewport().intersects((*it).payload->boundingRect())) { m_renderBatch.push_back((*it).payload.get()); } if ((*it).payload->inHUDSpace()) { auto bbox = (*it).payload->boundingRect(); bbox.moveCenter(m_view->mapSceneToScreen(bbox.center())); if (screenRect.intersects(bbox)) { m_renderBatch.push_back((*it).payload.get()); } } } for (auto phase : {SceneGraphItemPayload::FillPhase, SceneGraphItemPayload::CasingPhase, SceneGraphItemPayload::StrokePhase, SceneGraphItemPayload::LabelPhase}) { beginPhase(phase); for (const auto item : m_renderBatch) { if ((item->renderPhases() & phase) == 0) { continue; } if (auto i = dynamic_cast(item)) { renderPolygon(i, phase); } else if (auto i = dynamic_cast(item)) { renderMultiPolygon(i, phase); } else if (auto i = dynamic_cast(item)) { renderPolyline(i, phase); } else if (auto i = dynamic_cast(item)) { renderLabel(i); } else { qCritical() << "Unsupported scene graph item!"; } } } } endRender(); m_view = nullptr; qDebug() << "rendering took:" << frameTimer.elapsed() << "ms for" << sg.itemCount() << "items on" << sg.layerOffsets().size() << "layers"; } void PainterRenderer::beginRender() { - m_painter.begin(m_device); + m_painter->save(); } void PainterRenderer::renderBackground(const QColor &bgColor) { - m_painter.fillRect(0, 0, m_view->screenWidth(), m_view->screenHeight(), bgColor); + m_painter->fillRect(0, 0, m_view->screenWidth(), m_view->screenHeight(), bgColor); } void PainterRenderer::beginPhase(SceneGraphItemPayload::RenderPhase phase) { switch (phase) { case SceneGraphItemPayload::NoPhase: Q_UNREACHABLE(); case SceneGraphItemPayload::FillPhase: - m_painter.setPen(Qt::NoPen); - m_painter.setTransform(m_view->sceneToScreenTransform()); - m_painter.setClipRect(m_view->viewport()); - m_painter.setRenderHint(QPainter::Antialiasing, false); + m_painter->setPen(Qt::NoPen); + m_painter->setTransform(m_view->sceneToScreenTransform()); + m_painter->setClipRect(m_view->viewport()); + m_painter->setRenderHint(QPainter::Antialiasing, false); break; case SceneGraphItemPayload::CasingPhase: case SceneGraphItemPayload::StrokePhase: - m_painter.setBrush(Qt::NoBrush); - m_painter.setTransform(m_view->sceneToScreenTransform()); - m_painter.setClipRect(m_view->viewport()); - m_painter.setRenderHint(QPainter::Antialiasing, true); + m_painter->setBrush(Qt::NoBrush); + m_painter->setTransform(m_view->sceneToScreenTransform()); + m_painter->setClipRect(m_view->viewport()); + m_painter->setRenderHint(QPainter::Antialiasing, true); break; case SceneGraphItemPayload::LabelPhase: - m_painter.setTransform({}); - m_painter.setRenderHint(QPainter::Antialiasing, true); + m_painter->setTransform({}); + m_painter->setRenderHint(QPainter::Antialiasing, true); break; } } void PainterRenderer::renderPolygon(PolygonItem *item, SceneGraphItemPayload::RenderPhase phase) { if (phase == SceneGraphItemPayload::FillPhase) { - m_painter.setBrush(item->brush); - m_painter.drawPolygon(item->polygon); + m_painter->setBrush(item->brush); + m_painter->drawPolygon(item->polygon); } else { auto p = item->pen; p.setWidthF(m_view->mapScreenDistanceToSceneDistance(item->pen.widthF())); - m_painter.setPen(p); - m_painter.drawPolygon(item->polygon); + m_painter->setPen(p); + m_painter->drawPolygon(item->polygon); } } void PainterRenderer::renderMultiPolygon(MultiPolygonItem *item, SceneGraphItemPayload::RenderPhase phase) { if (phase == SceneGraphItemPayload::FillPhase) { - m_painter.setBrush(item->brush); - m_painter.drawPath(item->path); + m_painter->setBrush(item->brush); + m_painter->drawPath(item->path); } else { auto p = item->pen; p.setWidthF(m_view->mapScreenDistanceToSceneDistance(item->pen.widthF())); - m_painter.setPen(p); - m_painter.drawPath(item->path); + m_painter->setPen(p); + m_painter->drawPath(item->path); } } void PainterRenderer::renderPolyline(PolylineItem *item, SceneGraphItemPayload::RenderPhase phase) { if (phase == SceneGraphItemPayload::StrokePhase) { auto p = item->pen; p.setWidthF(m_view->mapMetersToScene(item->pen.widthF())); - m_painter.setPen(p); - m_painter.drawPolyline(item->path); + m_painter->setPen(p); + m_painter->drawPolyline(item->path); } else { auto p = item->casingPen; p.setWidthF(m_view->mapMetersToScene(item->pen.widthF()) + m_view->mapScreenDistanceToSceneDistance(item->casingPen.widthF())); - m_painter.setPen(p); - m_painter.drawPolyline(item->path); + m_painter->setPen(p); + m_painter->drawPolyline(item->path); } } void PainterRenderer::renderLabel(LabelItem *item) { if (!item->hasFineBbox) { QFontMetricsF fm(item->font); item->bbox = fm.boundingRect(item->text); item->bbox.moveCenter(item->pos); item->hasFineBbox = true; } - m_painter.save(); - m_painter.translate(m_view->mapSceneToScreen(item->pos)); - m_painter.rotate(item->angle); + m_painter->save(); + m_painter->translate(m_view->mapSceneToScreen(item->pos)); + m_painter->rotate(item->angle); auto box = item->bbox; box.moveCenter({0.0, item->offset}); // draw shield // @see https://wiki.openstreetmap.org/wiki/MapCSS/0.2#Shield_properties auto w = item->casingWidth + item->frameWidth + 2.0; if (item->casingWidth > 0.0 && item->casingColor.alpha() > 0) { - m_painter.fillRect(box.adjusted(-w, -w, w, w), item->casingColor); + m_painter->fillRect(box.adjusted(-w, -w, w, w), item->casingColor); } w -= item->casingWidth; if (item->frameWidth > 0.0 && item->frameColor.alpha() > 0) { - m_painter.fillRect(box.adjusted(-w, -w, w, w), item->frameColor); + m_painter->fillRect(box.adjusted(-w, -w, w, w), item->frameColor); } w -= item->frameWidth; if (item->shieldColor.alpha() > 0) { - m_painter.fillRect(box.adjusted(-w, -w, w, w), item->shieldColor); + m_painter->fillRect(box.adjusted(-w, -w, w, w), item->shieldColor); } // draw text - m_painter.setPen(item->color); - m_painter.setFont(item->font); - m_painter.drawText(box.bottomLeft() - QPointF(0, QFontMetricsF(item->font).descent()), item->text); - m_painter.restore(); + m_painter->setPen(item->color); + m_painter->setFont(item->font); + m_painter->drawText(box.bottomLeft() - QPointF(0, QFontMetricsF(item->font).descent()), item->text); + m_painter->restore(); } void PainterRenderer::endRender() { - m_painter.end(); + m_painter->restore(); } diff --git a/src/map/renderer/painterrenderer.h b/src/map/renderer/painterrenderer.h index e27562f..2805204 100644 --- a/src/map/renderer/painterrenderer.h +++ b/src/map/renderer/painterrenderer.h @@ -1,68 +1,65 @@ /* Copyright (C) 2020 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KOSMINDOORMAP_PAINTERRENDERER_H #define KOSMINDOORMAP_PAINTERRENDERER_H #include "../scene/scenegraphitem.h" #include -#include - -class QPaintDevice; +class QPainter; namespace KOSMIndoorMap { class LabelItem; class PolygonItem; class PolylineItem; class SceneGraph; class View; /** QPainter-based renderer of a SceneGraph. * Trying to keep this somewhat backend-agnostic to possibly implement a 3D renderer in the future. */ class PainterRenderer { public: explicit PainterRenderer(); ~PainterRenderer(); - void setPaintDevice(QPaintDevice *device); + void setPainter(QPainter *painter); void render(const SceneGraph &sg, View *view); private: void beginRender(); void beginPhase(SceneGraphItemPayload::RenderPhase phase); void renderBackground(const QColor &bgColor); void renderPolygon(PolygonItem *item, SceneGraphItemPayload::RenderPhase phase); void renderMultiPolygon(MultiPolygonItem *item, SceneGraphItemPayload::RenderPhase phase); void renderPolyline(PolylineItem *item, SceneGraphItemPayload::RenderPhase phase); void renderLabel(LabelItem *item); void endRender(); - QPaintDevice *m_device = nullptr; - QPainter m_painter; + QPainter *m_painter = nullptr; View *m_view = nullptr; std::vector m_renderBatch; // member rather than function-local to preserve allocations }; } #endif // KOSMINDOORMAP_PAINTERRENDERER_H diff --git a/tests/indoormap.cpp b/tests/indoormap.cpp index 21ef783..b54280d 100644 --- a/tests/indoormap.cpp +++ b/tests/indoormap.cpp @@ -1,159 +1,161 @@ /* Copyright (C) 2020 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include