KDEGames

kgamerenderedobjectitem.cpp
1 /***************************************************************************
2  * Copyright 2010 Stefan Majewsky <[email protected]> *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU Library General Public License *
6  * version 2 as published by the Free Software Foundation *
7  * *
8  * This program is distributed in the hope that it will be useful, *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11  * GNU Library General Public License for more details. *
12  * *
13  * You should have received a copy of the GNU Library General Public *
14  * License along with this program; if not, write to the *
15  * Free Software Foundation, Inc., *
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
17  ***************************************************************************/
18 
19 #include "kgamerenderedobjectitem.h"
20 #include "kgamerenderer.h"
21 
22 #include <QtMath>
23 #include <QGraphicsView>
24 
25 class KGameRenderedObjectItemPrivate : public QGraphicsPixmapItem
26 {
27  public:
28  KGameRenderedObjectItemPrivate(KGameRenderedObjectItem* parent);
29  bool adjustRenderSize(); //returns whether an adjustment was made; WARNING: only call when m_primaryView != 0
30  void adjustTransform();
31 
32  //QGraphicsItem reimplementations (see comment below for why we need all of this)
33  bool contains(const QPointF& point) const override;
34  bool isObscuredBy(const QGraphicsItem* item) const override;
35  QPainterPath opaqueArea() const override;
36  void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
37  QPainterPath shape() const override;
38  public:
39  KGameRenderedObjectItem* m_parent;
40  QGraphicsView* m_primaryView;
41  QSize m_correctRenderSize;
42  QSizeF m_fixedSize;
43 };
44 
45 KGameRenderedObjectItemPrivate::KGameRenderedObjectItemPrivate(KGameRenderedObjectItem* parent)
46  : QGraphicsPixmapItem(parent)
47  , m_parent(parent)
48  , m_primaryView(nullptr)
49  , m_correctRenderSize(0, 0)
50  , m_fixedSize(-1, -1)
51 {
52 }
53 
54 static inline int vectorLength(const QPointF& point)
55 {
56  return qSqrt(point.x() * point.x() + point.y() * point.y());
57 }
58 
59 bool KGameRenderedObjectItemPrivate::adjustRenderSize()
60 {
61  Q_ASSERT(m_primaryView);
62  //create a polygon from the item's boundingRect
63  const QRectF itemRect = m_parent->boundingRect();
64  QPolygonF itemPolygon(3);
65  itemPolygon[0] = itemRect.topLeft();
66  itemPolygon[1] = itemRect.topRight();
67  itemPolygon[2] = itemRect.bottomLeft();
68  //determine correct render size
69  const QPolygonF scenePolygon = m_parent->sceneTransform().map(itemPolygon);
70  const QPolygon viewPolygon = m_primaryView->mapFromScene(scenePolygon);
71  m_correctRenderSize.setWidth(qMax(vectorLength(viewPolygon[1] - viewPolygon[0]), 1));
72  m_correctRenderSize.setHeight(qMax(vectorLength(viewPolygon[2] - viewPolygon[0]), 1));
73  //ignore fluctuations in the render size which result from rounding errors
74  const QSize diff = m_parent->renderSize() - m_correctRenderSize;
75  if (qAbs(diff.width()) <= 1 && qAbs(diff.height()) <= 1)
76  {
77  return false;
78  }
79  m_parent->setRenderSize(m_correctRenderSize);
80  adjustTransform();
81  return true;
82 }
83 
84 void KGameRenderedObjectItemPrivate::adjustTransform()
85 {
86  //calculate new transform for this item
87  QTransform t;
88  t.scale(m_fixedSize.width() / m_correctRenderSize.width(), m_fixedSize.height() / m_correctRenderSize.height());
89  //render item
90  m_parent->prepareGeometryChange();
91  setTransform(t);
92  m_parent->update();
93 }
94 
96  : QGraphicsObject(parent)
97  , KGameRendererClient(renderer, spriteKey)
98  , d(new KGameRenderedObjectItemPrivate(this))
99 {
100  setPrimaryView(renderer->defaultPrimaryView());
101 }
102 
103 KGameRenderedObjectItem::~KGameRenderedObjectItem()
104 {
105  delete d;
106 }
107 
109 {
110  return d->pos();
111 }
112 
114 {
115  if (d->pos() != offset)
116  {
118  d->setPos(offset);
119  update();
120  }
121 }
122 
124 {
125  setOffset(QPointF(x, y));
126 }
127 
129 {
130  return d->m_fixedSize;
131 }
132 
134 {
135  if (d->m_primaryView)
136  {
137  d->m_fixedSize = fixedSize.expandedTo(QSize(1, 1));
138  d->adjustTransform();
139  }
140 }
141 
143 {
144  return d->m_primaryView;
145 }
146 
148 {
149  if (d->m_primaryView != view)
150  {
151  d->m_primaryView = view;
152  if (view)
153  {
154  if (!d->m_fixedSize.isValid())
155  {
156  d->m_fixedSize = QSize(1, 1);
157  }
158  //determine render size and adjust coordinate system
159  d->m_correctRenderSize = QSize(-10, -10); //force adjustment to be made
160  d->adjustRenderSize();
161  }
162  else
163  {
164  d->m_fixedSize = QSize(-1, -1);
165  //reset transform to make coordinate systems of this item and the private item equal
167  d->setTransform(QTransform());
168  update();
169  }
170  }
171 }
172 
174 {
176  d->setPixmap(pixmap);
177  update();
178 }
179 
180 //We want to make sure that all interactional events are sent ot this item, and
181 //not to the contained QGraphicsPixmapItem which provides the visual
182 //representation (and the metrics calculations).
183 //At the same time, we do not want the contained QGraphicsPixmapItem to slow
184 //down operations like QGraphicsScene::collidingItems().
185 //So the strategy is to use the QGraphicsPixmapItem implementation from
186 //KGameRenderedObjectItemPrivate for KGameRenderedObjectItem.
187 //Then the relevant methods in KGameRenderedObjectItemPrivate are reimplemented empty
188 //to effectively clear the item and hide it from any collision detection. This
189 //strategy allows us to use the nifty QGraphicsPixmapItem logic without exposing
190 //a QGraphicsPixmapItem subclass (which would conflict with QGraphicsObject).
191 
192 //BEGIN QGraphicsItem reimplementation of KGameRenderedObjectItem
193 
194 QRectF KGameRenderedObjectItem::boundingRect() const
195 {
196  return d->mapRectToParent(d->QGraphicsPixmapItem::boundingRect());
197 }
198 
199 bool KGameRenderedObjectItem::contains(const QPointF& point) const
200 {
201  return d->QGraphicsPixmapItem::contains(d->mapFromParent(point));
202 }
203 
204 bool KGameRenderedObjectItem::isObscuredBy(const QGraphicsItem* item) const
205 {
206  return d->QGraphicsPixmapItem::isObscuredBy(item);
207 }
208 
209 QPainterPath KGameRenderedObjectItem::opaqueArea() const
210 {
211  return d->mapToParent(d->QGraphicsPixmapItem::opaqueArea());
212 }
213 
214 void KGameRenderedObjectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
215 {
216  Q_UNUSED(painter) Q_UNUSED(option) Q_UNUSED(widget)
217 }
218 
219 QPainterPath KGameRenderedObjectItem::shape() const
220 {
221  return d->mapToParent(d->QGraphicsPixmapItem::shape());
222 }
223 
224 //END QGraphicsItem reimplementation of KGameRenderedObjectItem
225 //BEGIN QGraphicsItem reimplementation of KGameRenderedObjectItemPrivate
226 
227 bool KGameRenderedObjectItemPrivate::contains(const QPointF& point) const
228 {
229  Q_UNUSED(point)
230  return false;
231 }
232 
233 bool KGameRenderedObjectItemPrivate::isObscuredBy(const QGraphicsItem* item) const
234 {
235  Q_UNUSED(item)
236  return false;
237 }
238 
239 QPainterPath KGameRenderedObjectItemPrivate::opaqueArea() const
240 {
241  return QPainterPath();
242 }
243 
244 void KGameRenderedObjectItemPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
245 {
246  //Trivial stuff up to now. The fun stuff starts here. ;-)
247  //There is no way to get informed when the viewport's coordinate system
248  //(relative to this item's coordinate system) has changed, so we're checking
249  //the renderSize in each paintEvent coming from the primary view.
250  if (m_primaryView)
251  {
252  if (m_primaryView == widget || m_primaryView->isAncestorOf(widget))
253  {
254  const bool isSimpleTransformation = !painter->transform().isRotating();
255  //If an adjustment was made, do not paint now, but wait for the next
256  //painting. However, paint directly if the transformation is
257  //complex, in order to avoid flicker.
258  if (adjustRenderSize())
259  {
260  if (isSimpleTransformation)
261  {
262  return;
263  }
264  }
265  if (isSimpleTransformation)
266  {
267  //draw pixmap directly in physical coordinates
268  const QPoint basePos = painter->transform().map(QPointF()).toPoint();
269  painter->save();
270  painter->setTransform(QTransform());
271  painter->drawPixmap(basePos, pixmap());
272  painter->restore();
273  return;
274  }
275  }
276  }
277  QGraphicsPixmapItem::paint(painter, option, widget);
278 }
279 
280 QPainterPath KGameRenderedObjectItemPrivate::shape() const
281 {
282  return QPainterPath();
283 }
284 
285 //END QGraphicsItem reimplementation of KGameRenderedObjectItemPrivate
286 
287 
void setTransform(const QTransform &transform, bool combine)
qreal x() const const
qreal y() const const
int width() const const
QPoint map(const QPoint &point) const const
A QGraphicsObject which displays pixmaps from a KGameRenderer.
void setFixedSize(const QSizeF &size)
Sets the fixed size of this item, i.e.
void save()
const QTransform & transform() const const
QSizeF expandedTo(const QSizeF &otherSize) const const
bool isAncestorOf(const QWidget *child) const const
void update(const QRectF &rect)
qreal x() const const
qreal y() const const
QTransform & scale(qreal sx, qreal sy)
virtual bool isObscuredBy(const QGraphicsItem *item) const const override
QGraphicsView * defaultPrimaryView() const
Cache-enabled rendering of SVG themes.
Definition: kgamerenderer.h:94
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
QPointF topLeft() const const
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
virtual bool contains(const QPointF &point) const const override
QPointF topRight() const const
QString spriteKey() const
void prepareGeometryChange()
KGameRenderedObjectItem(KGameRenderer *renderer, const QString &spriteKey, QGraphicsItem *parent=nullptr)
Creates a new KGameRenderedObjectItem which renders the sprite with the given spriteKey as provided b...
void restore()
An object that receives pixmaps from a KGameRenderer.
bool isRotating() const const
KGameRenderer * renderer() const
virtual QPainterPath opaqueArea() const const override
virtual QPainterPath shape() const const override
void receivePixmap(const QPixmap &pixmap) override
This method is called when the KGameRenderer has provided a new pixmap for this client (esp...
void setTransform(const QTransform &matrix, bool combine)
QGraphicsView * primaryView() const
Returns a pointer to the current primary view, or 0 if no primary view has been set (which is the def...
QPointF bottomLeft() const const
int height() const const
void setPrimaryView(QGraphicsView *view)
Sets the primary view of this item.
void setOffset(const QPointF &offset)
Sets the item&#39;s offset, which defines the point of the top-left corner of the bounding rect...
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Nov 30 2020 22:37:54 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.