From 1f78d8c1c88c898259c35d6c36730ed52ca5ba7a Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sat, 23 Jul 2022 01:31:37 +0200 Subject: [PATCH] Introduce a map renderer class It is meant to incorporate the functionality of mapview_common needed to draw the map. Right now it delegates most (all) of its work to mapview_common. --- client/CMakeLists.txt | 1 + client/mapview.cpp | 35 ++++++++---------- client/mapview.h | 8 +++- client/page_game.cpp | 1 - client/renderer.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++ client/renderer.h | 41 +++++++++++++++++++++ 6 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 client/renderer.cpp create mode 100644 client/renderer.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index b81bd75343..80a2a8bedf 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -112,6 +112,7 @@ add_library( plrdlg_common.cpp pregameoptions.cpp ratesdlg.cpp + renderer.cpp repodlgs_common.cpp reqtree.cpp sciencedlg.cpp diff --git a/client/mapview.cpp b/client/mapview.cpp index acff3ca816..512dcbeb15 100644 --- a/client/mapview.cpp +++ b/client/mapview.cpp @@ -28,6 +28,7 @@ #include "mapview_common.h" #include "mapview_g.h" #include "minimap_panel.h" +#include "renderer.h" #include "sprite.h" #include "text.h" #include "tilespec.h" @@ -134,7 +135,7 @@ void draw_calculated_trade_routes(QPainter *painter) Constructor for map */ map_view::map_view() - : QWidget(), + : QWidget(), m_renderer(new freeciv::renderer(this)), m_scale_animation(std::make_unique(this, "scale")) { menu_click = false; @@ -209,6 +210,11 @@ void map_view::zoom_reset() { set_scale(1); } */ void map_view::zoom_out() { set_scale(scale() / 1.2); } +/** + * Retrieves the current scale (zoom level) of the map. + */ +double map_view::scale() const { return m_renderer->scale(); } + /** * Sets the map scale. */ @@ -226,11 +232,7 @@ void map_view::set_scale(double scale) */ void map_view::set_scale_now(double scale) { - m_scale = scale; - // When zoomed in, we pretend that the canvas is smaller than it is. This - // makes text look bad, but everything else is drawn correctly. - map_canvas_resized(width() / m_scale, height() / m_scale); - + m_renderer->set_scale(scale); emit scale_changed(m_scale); } @@ -314,26 +316,19 @@ void map_view::paintEvent(QPaintEvent *event) QPainter painter; painter.begin(this); - paint(&painter, event); + m_renderer->render(painter, event->region()); + painter.scale(1 / scale(), 1 / scale()); + draw_calculated_trade_routes(&painter); painter.end(); } /** - Redraws given rectangle on map + * The widget has been resized. */ -void map_view::paint(QPainter *painter, QPaintEvent *event) +void map_view::resizeEvent(QResizeEvent *event) { - if (scale() != 1) { - painter->setRenderHint(QPainter::SmoothPixmapTransform); - } - auto widget_rect = QRectF(event->rect()); - auto mapview_rect = - QRectF(widget_rect.left() / scale(), widget_rect.top() / scale(), - widget_rect.width() / scale(), widget_rect.height() / scale()); - painter->drawPixmap(widget_rect, *mapview.store, mapview_rect); - - painter->scale(1 / scale(), 1 / scale()); - draw_calculated_trade_routes(painter); + m_renderer->set_viewport_size(event->size()); + event->accept(); } /** diff --git a/client/mapview.h b/client/mapview.h index a1203b5c84..19e430c28b 100644 --- a/client/mapview.h +++ b/client/mapview.h @@ -32,6 +32,9 @@ class QPaintEvent; class QPainter; class fcwidget; +namespace freeciv { +class renderer; +} bool is_point_in_area(int x, int y, int px, int py, int pxe, int pye); void draw_calculated_trade_routes(QPainter *painter); @@ -51,7 +54,6 @@ class map_view : public QWidget { public: map_view(); - void paint(QPainter *painter, QPaintEvent *event); void find_place(int pos_x, int pos_y, int &w, int &h, int wdth, int hght, int recursive_nr, bool direction = false); void resume_searching(int pos_x, int pos_y, int &w, int &h, int wdtht, @@ -63,7 +65,7 @@ class map_view : public QWidget { bool menu_click; - double scale() const { return m_scale; } + double scale() const; freeciv::tileset_debugger *debugger() const { return m_debugger; } @@ -89,6 +91,7 @@ public slots: void mouseMoveEvent(QMouseEvent *event) override; void focusOutEvent(QFocusEvent *event) override; void leaveEvent(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private slots: void set_scale_now(double scale); @@ -98,6 +101,7 @@ private slots: bool stored_autocenter; int cursor_frame{0}; int cursor; + freeciv::renderer *m_renderer; double m_scale = 1; std::unique_ptr m_scale_animation; QPointer m_debugger = nullptr; diff --git a/client/page_game.cpp b/client/page_game.cpp index 25c634c90b..6839ea0096 100644 --- a/client/page_game.cpp +++ b/client/page_game.cpp @@ -513,7 +513,6 @@ bool fc_game_tab_widget::event(QEvent *event) ? static_cast(event)->size() : this->size(); if (event->type() == QEvent::Resize) { - map_canvas_resized(size.width(), size.height()); queen()->message->resize( qRound((size.width() * king()->qt_settings.chat_fwidth)), qRound((size.height() * king()->qt_settings.chat_fheight))); diff --git a/client/renderer.cpp b/client/renderer.cpp new file mode 100644 index 0000000000..13897a22e6 --- /dev/null +++ b/client/renderer.cpp @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2022 Louis Moureaux + * + * SPDX-License-Identifier: GPLv3-or-later + */ + +#include "renderer.h" + +#include "mapview_common.h" + +namespace freeciv { + +/** + * @class renderer + * @brief Renders the map on widgets + * + * This class is used to draw the map. It can handle zoom via the @ref scale + * property. + * + * @property scale By how much the map is scaled before being drawn (a scale + * of 2 means that everything is 2x bigger) + */ + +/** + * Constructor. + */ +renderer::renderer(QObject *parent) : QObject(parent) {} + +/** + * Changes the scale of the rendering (zooms in or out). + */ +void renderer::set_scale(double scale) +{ + m_scale = scale; + + // When zoomed in, we pretend that the canvas is smaller than it actually + // is. This makes text look bad, but everything else is drawn correctly. + map_canvas_resized(m_viewport_size.width() / m_scale, + m_viewport_size.height() / m_scale); +} + +/** + * Instructs the renderer to draw a viewport with a different size. + */ +void renderer::set_viewport_size(const QSize &size) +{ + m_viewport_size = size; + + // When zoomed in, we pretend that the canvas is smaller than it actually + // is. This makes text look bad, but everything else is drawn correctly. + map_canvas_resized(m_viewport_size.width() / m_scale, + m_viewport_size.height() / m_scale); +} + +/** + * Renders the specified region of the visible portion of the map on @c + * painter. + * @see @ref render(QPainter&, const QRect&) + */ +void renderer::render(QPainter &painter, const QRegion ®ion) const +{ + for (const auto &rect : region) { + render(painter, rect); + } +} + +/** + * Renders the specified area of the visible portion of the map on @c + * painter. This is meant to be used directly from @c paintEvent, so the + * position of + * @c area is relative to the @ref viewport. + */ +void renderer::render(QPainter &painter, const QRect &area) const +{ + if (scale() != 1) { + painter.setRenderHint(QPainter::SmoothPixmapTransform); + } + + auto mapview_rect = + QRectF(area.left() / scale(), area.top() / scale(), + area.width() / scale(), area.height() / scale()); + painter.drawPixmap(area, *mapview.store, mapview_rect); +} + +} // namespace freeciv diff --git a/client/renderer.h b/client/renderer.h new file mode 100644 index 0000000000..e6cbeb49c0 --- /dev/null +++ b/client/renderer.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2022 Louis Moureaux + * + * SPDX-License-Identifier: GPLv3-or-later + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace freeciv { + +class renderer : public QObject { + Q_OBJECT + Q_PROPERTY(double scale READ scale WRITE set_scale); + +public: + explicit renderer(QObject *parent = nullptr); + virtual ~renderer() = default; + + /// The scale (zoom) at which rendering is performed + double scale() const { return m_scale; } + void set_scale(double scale); + + /// The current dimensions of the viewport + QSize viewport_size() const { return m_viewport_size; } + void set_viewport_size(const QSize &size); + + void render(QPainter &painter, const QRegion ®ion) const; + void render(QPainter &painter, const QRect &area) const; + +private: + double m_scale = 1.0; + QSize m_viewport_size; +}; + +} // namespace freeciv