Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • graphics
  • bitmap
tiledbuffer.cpp
1/*
2
3Pencil - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2018 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16*/
17#include "tiledbuffer.h"
18
19#include <QPainterPath>
20#include <QtMath>
21
22#include "tile.h"
23
24TiledBuffer::TiledBuffer(QObject* parent) : QObject(parent)
25{
26}
27
28TiledBuffer::~TiledBuffer()
29{
30 clear();
31}
32
33Tile* TiledBuffer::getTileFromIndex(const TileIndex& tileIndex)
34{
35 Tile* selectedTile = mTiles.value(tileIndex, nullptr);
36
37 if (!selectedTile) {
38 // Time to allocate it, update table:
39 const QPoint& tilePos (getTilePos(tileIndex));
40 selectedTile = new Tile(tilePos, QSize(UNIFORM_TILE_SIZE, UNIFORM_TILE_SIZE));
41 mTiles.insert(tileIndex, selectedTile);
42
43 emit this->tileCreated(this, selectedTile);
44 } else {
45 emit this->tileUpdated(this, selectedTile);
46 }
47
48 return selectedTile;
49}
50
51void TiledBuffer::drawBrush(QPointF point, qreal brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing) {
52 const float tileSize = UNIFORM_TILE_SIZE;
53
54 // Gather the number of tiles that fits the size of the brush width
55 const int xLeft = qFloor((qFloor(point.x() - brushWidth)) / tileSize);
56 const int xRight = qFloor((qFloor(point.x() + brushWidth)) / tileSize);
57 const int yTop = qFloor(qFloor(point.y() - brushWidth) / tileSize);
58 const int yBottom = qFloor(qFloor(point.y() + brushWidth) / tileSize);
59
60 // If we are not using antialiasing, make sure at least one pixel is within the brush's circle
61 bool drawPoint = false;
62 if (!antialiasing && brushWidth < 1.42) { // Overestimated approximation of 2*sqrt(2), which is the maximum distance a point can be from the center of a pixel
63 // Measure the actual distance to the center of the nearest pixel
64 const QPointF nearestPixelCenter(qRound(point.x()+0.5)-0.5, qRound(point.y()+0.5)-0.5);
65 const qreal distanceToNearest = QLineF(point, nearestPixelCenter).length();
66 if (distanceToNearest >= brushWidth/2) {
67 // Nothing will be drawn with drawEllipse, so prepare to draw the nearest pixel with drawPoint
68 drawPoint = true;
69 point = QPointF(nearestPixelCenter.x() - 0.5, nearestPixelCenter.y() - 0.5);
70 pen = QPen(brush, 1);
71 }
72 }
73 const QRectF brushRect(point.x() - 0.5 * brushWidth, point.y() - 0.5 * brushWidth, brushWidth, brushWidth);
74
75 for (int tileY = yTop; tileY <= yBottom; tileY++) {
76 for (int tileX = xLeft; tileX <= xRight; tileX++) {
77
78 Tile* tile = getTileFromIndex({tileX, tileY});
79
80 QPainter painter(&tile->pixmap());
81
82 painter.translate(-tile->pos());
83 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
84 painter.setPen(pen);
85 painter.setBrush(brush);
86 painter.setCompositionMode(cm);
87 if (drawPoint) {
88 painter.drawPoint(point);
89 } else {
90 painter.drawEllipse(brushRect);
91 }
92 painter.end();
93
94 mTileBounds.extend(tile->bounds());
95 }
96 }
97}
98
99void TiledBuffer::drawImage(const QImage& image, const QRect& imageBounds, QPainter::CompositionMode cm, bool antialiasing) {
100 const float tileSize = UNIFORM_TILE_SIZE;
101 const float imageXRad = image.width();
102 const float imageYRad = image.height();
103 // Gather the number of tiles that fits the size of the brush width
104 const int xLeft = qFloor((qFloor(imageBounds.left() - imageXRad)) / tileSize);
105 const int xRight = qFloor((qFloor(imageBounds.right() + imageXRad)) / tileSize);
106 const int yTop = qFloor(qFloor(imageBounds.top() - imageYRad) / tileSize);
107 const int yBottom = qFloor(qFloor(imageBounds.bottom() + imageYRad) / tileSize);
108
109 for (int tileY = yTop; tileY <= yBottom; tileY++) {
110 for (int tileX = xLeft; tileX <= xRight; tileX++) {
111
112 Tile* tile = getTileFromIndex({tileX, tileY});
113
114 QPainter painter(&tile->pixmap());
115
116 painter.translate(-tile->pos());
117 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
118 painter.setCompositionMode(cm);
119 painter.drawImage(imageBounds.topLeft(), image);
120 painter.end();
121
122 mTileBounds.extend(tile->bounds());
123 }
124 }
125}
126
127
128void TiledBuffer::drawPath(QPainterPath path, QPen pen, QBrush brush,
129 QPainter::CompositionMode cm, bool antialiasing)
130{
131 const qreal width = pen.widthF();
132 const float tileSize = UNIFORM_TILE_SIZE;
133 const QRectF pathRect = path.boundingRect();
134
135 // Gather the number of tiles that fits the size of the brush width
136 const int xLeft = qFloor((qFloor(pathRect.left() - width)) / tileSize);
137 const int xRight = qFloor((qFloor(pathRect.right() + width)) / tileSize);
138 const int yTop = qFloor(qFloor(pathRect.top() - width) / tileSize);
139 const int yBottom = qFloor(qFloor(pathRect.bottom() + width) / tileSize);
140
141 for (int tileY = yTop; tileY <= yBottom; tileY++) {
142 for (int tileX = xLeft; tileX <= xRight; tileX++) {
143
144 Tile* tile = getTileFromIndex({tileX, tileY});
145
146 QPainter painter(&tile->pixmap());
147
148 painter.translate(-tile->pos());
149 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
150 painter.setPen(pen);
151 painter.setBrush(brush);
152 painter.setCompositionMode(cm);
153 painter.drawPath(path);
154 painter.end();
155
156 mTileBounds.extend(tile->bounds());
157 }
158 }
159}
160
161void TiledBuffer::clear()
162{
163 QHashIterator<TileIndex, Tile*> i(mTiles);
164
165 while (i.hasNext()) {
166 i.next();
167 Tile* tile = i.value();
168 if (tile)
169 {
170 mTiles.remove(i.key());
171 delete tile;
172 }
173 }
174
175 mTileBounds = BlitRect();
176}
177
178QPoint TiledBuffer::getTilePos(const TileIndex& index) const
179{
180 return QPoint { qRound(UNIFORM_TILE_SIZE*static_cast<qreal>(index.x)),
181 qRound(UNIFORM_TILE_SIZE*static_cast<qreal>(index.y)) };
182}
BlitRect
Definition: blitrect.h:25
Tile
Definition: tile.h:24
TiledBuffer::drawPath
void drawPath(QPainterPath path, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing)
Draws a path with the specified parameters to the tiled buffer.
Definition: tiledbuffer.cpp:128
TiledBuffer::clear
void clear()
Clears the content of the tiled buffer.
Definition: tiledbuffer.cpp:161
TiledBuffer::drawImage
void drawImage(const QImage &image, const QRect &imageBounds, QPainter::CompositionMode cm, bool antialiasing)
Draws a image with the specified parameters to the tiled buffer.
Definition: tiledbuffer.cpp:99
TiledBuffer::drawBrush
void drawBrush(QPointF point, qreal brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing)
Draws a brush with the specified parameters to the tiled buffer.
Definition: tiledbuffer.cpp:51
QBrush
QHash::insert
QHash::iterator insert(const Key &key, const T &value)
QHash::remove
int remove(const Key &key)
QHash::value
const T value(const Key &key) const const
QHashIterator
QHashIterator::hasNext
bool hasNext() const const
QHashIterator::key
const Key & key() const const
QHashIterator::next
QHashIterator::Item next()
QHashIterator::value
const T & value() const const
QImage
QImage::height
int height() const const
QImage::width
int width() const const
QLineF
QLineF::length
qreal length() const const
QObject
QPainter
QPainter::CompositionMode
CompositionMode
QPainter::Antialiasing
Antialiasing
QPainterPath
QPainterPath::boundingRect
QRectF boundingRect() const const
QPen
QPen::widthF
qreal widthF() const const
QPoint
QPointF
QPointF::x
qreal x() const const
QPointF::y
qreal y() const const
QRect
QRect::bottom
int bottom() const const
QRect::left
int left() const const
QRect::right
int right() const const
QRect::top
int top() const const
QRect::topLeft
QPoint topLeft() const const
QRectF
QRectF::bottom
qreal bottom() const const
QRectF::left
qreal left() const const
QRectF::right
qreal right() const const
QRectF::top
qreal top() const const
QSize
TileIndex
Definition: tiledbuffer.h:28
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39