File indexing completed on 2024-05-05 05:35:34

0001 /*
0002     SPDX-FileCopyrightText: 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0003     SPDX-FileCopyrightText: 2008 Long Huynh Huu <long.upcase@googlemail.com>
0004     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "oxygentileset.h"
0010 
0011 #include <QPainter>
0012 
0013 namespace Oxygen
0014 {
0015 //___________________________________________________________
0016 inline bool bits(TileSet::Tiles flags, TileSet::Tiles testFlags)
0017 {
0018     return (flags & testFlags) == testFlags;
0019 }
0020 
0021 //______________________________________________________________________________________
0022 inline qreal devicePixelRatio(const QPixmap &pixmap)
0023 {
0024     return pixmap.devicePixelRatio();
0025 }
0026 
0027 //______________________________________________________________________________________
0028 inline void setDevicePixelRatio(QPixmap &pixmap, qreal value)
0029 {
0030     return pixmap.setDevicePixelRatio(value);
0031 }
0032 
0033 //______________________________________________________________
0034 int TileSet::_sideExtent = 32;
0035 
0036 //______________________________________________________________
0037 void TileSet::initPixmap(PixmapList &pixmaps, const QPixmap &source, int width, int height, const QRect &rect)
0038 {
0039     QSize size(width, height);
0040     if (!(size.isValid() && rect.isValid())) {
0041         pixmaps.append(QPixmap());
0042 
0043     } else if (size != rect.size()) {
0044         const qreal dpiRatio(devicePixelRatio(source));
0045         const QRect scaledRect(rect.topLeft() * dpiRatio, rect.size() * dpiRatio);
0046         const QSize scaledSize(size * dpiRatio);
0047         const QPixmap tile(source.copy(scaledRect));
0048         QPixmap pixmap(scaledSize);
0049 
0050         pixmap.fill(Qt::transparent);
0051         QPainter painter(&pixmap);
0052         painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile);
0053         setDevicePixelRatio(pixmap, dpiRatio);
0054         pixmaps.append(pixmap);
0055 
0056     } else {
0057         const qreal dpiRatio(devicePixelRatio(source));
0058         const QRect scaledRect(rect.topLeft() * dpiRatio, rect.size() * dpiRatio);
0059         QPixmap pixmap(source.copy(scaledRect));
0060         setDevicePixelRatio(pixmap, dpiRatio);
0061         pixmaps.append(pixmap);
0062     }
0063 }
0064 
0065 //______________________________________________________________
0066 TileSet::TileSet(void)
0067     : _w1(0)
0068     , _h1(0)
0069     , _w3(0)
0070     , _h3(0)
0071 {
0072     _pixmaps.reserve(9);
0073 }
0074 
0075 //______________________________________________________________
0076 TileSet::TileSet(const QPixmap &source, int w1, int h1, int w2, int h2)
0077     : _w1(w1)
0078     , _h1(h1)
0079     , _w3(0)
0080     , _h3(0)
0081 {
0082     _pixmaps.reserve(9);
0083     if (source.isNull())
0084         return;
0085 
0086     _w3 = source.width() / devicePixelRatio(source) - (w1 + w2);
0087     _h3 = source.height() / devicePixelRatio(source) - (h1 + h2);
0088     int w = w2;
0089     int h = h2;
0090 
0091     // initialise pixmap array
0092     initPixmap(_pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1));
0093     initPixmap(_pixmaps, source, w, _h1, QRect(_w1, 0, w2, _h1));
0094     initPixmap(_pixmaps, source, _w3, _h1, QRect(_w1 + w2, 0, _w3, _h1));
0095     initPixmap(_pixmaps, source, _w1, h, QRect(0, _h1, _w1, h2));
0096     initPixmap(_pixmaps, source, w, h, QRect(_w1, _h1, w2, h2));
0097     initPixmap(_pixmaps, source, _w3, h, QRect(_w1 + w2, _h1, _w3, h2));
0098     initPixmap(_pixmaps, source, _w1, _h3, QRect(0, _h1 + h2, _w1, _h3));
0099     initPixmap(_pixmaps, source, w, _h3, QRect(_w1, _h1 + h2, w2, _h3));
0100     initPixmap(_pixmaps, source, _w3, _h3, QRect(_w1 + w2, _h1 + h2, _w3, _h3));
0101 }
0102 
0103 //______________________________________________________________
0104 TileSet::TileSet(const QPixmap &source, int w1, int h1, int w3, int h3, int x1, int y1, int w2, int h2)
0105     : _w1(w1)
0106     , _h1(h1)
0107     , _w3(w3)
0108     , _h3(h3)
0109 {
0110     _pixmaps.reserve(9);
0111     if (source.isNull())
0112         return;
0113 
0114     int x2 = source.width() / devicePixelRatio(source) - _w3;
0115     int y2 = source.height() / devicePixelRatio(source) - _h3;
0116     int w = w2;
0117     int h = h2;
0118 
0119     // initialise pixmap array
0120     initPixmap(_pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1));
0121     initPixmap(_pixmaps, source, w, _h1, QRect(x1, 0, w2, _h1));
0122     initPixmap(_pixmaps, source, _w3, _h1, QRect(x2, 0, _w3, _h1));
0123     initPixmap(_pixmaps, source, _w1, h, QRect(0, y1, _w1, h2));
0124     initPixmap(_pixmaps, source, w, h, QRect(x1, y1, w2, h2));
0125     initPixmap(_pixmaps, source, _w3, h, QRect(x2, y1, _w3, h2));
0126     initPixmap(_pixmaps, source, _w1, _h3, QRect(0, y2, _w1, _h3));
0127     initPixmap(_pixmaps, source, w, _h3, QRect(x1, y2, w2, _h3));
0128     initPixmap(_pixmaps, source, _w3, _h3, QRect(x2, y2, _w3, _h3));
0129 }
0130 
0131 //___________________________________________________________
0132 QRect TileSet::adjust(const QRect &constRect, Tiles tiles) const
0133 {
0134     // adjust rect to deal with missing edges
0135     QRect rect(constRect);
0136     if (!(tiles & Left))
0137         rect.adjust(-_w1, 0, 0, 0);
0138     if (!(tiles & Right))
0139         rect.adjust(0, 0, _w3, 0);
0140     if (!(tiles & Top))
0141         rect.adjust(0, -_h1, 0, 0);
0142     if (!(tiles & Bottom))
0143         rect.adjust(0, 0, 0, _h3);
0144 
0145     return rect;
0146 }
0147 
0148 //___________________________________________________________
0149 void TileSet::render(const QRect &constRect, QPainter *painter, Tiles tiles) const
0150 {
0151     const bool oldHint(painter->testRenderHint(QPainter::SmoothPixmapTransform));
0152     painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
0153 
0154     // check initialization
0155     if (_pixmaps.size() < 9)
0156         return;
0157 
0158     // copy source rect
0159     QRect rect(constRect);
0160 
0161     // get rect dimensions
0162     int x0, y0, w, h;
0163     rect.getRect(&x0, &y0, &w, &h);
0164 
0165     // calculate pixmaps widths
0166     int wLeft(0);
0167     int wRight(0);
0168     if (_w1 + _w3 > 0) {
0169         qreal wRatio(qreal(_w1) / qreal(_w1 + _w3));
0170         wLeft = (tiles & Right) ? qMin(_w1, int(w * wRatio)) : _w1;
0171         wRight = (tiles & Left) ? qMin(_w3, int(w * (1.0 - wRatio))) : _w3;
0172     }
0173 
0174     // calculate pixmap heights
0175     int hTop(0);
0176     int hBottom(0);
0177     if (_h1 + _h3 > 0) {
0178         qreal hRatio(qreal(_h1) / qreal(_h1 + _h3));
0179         hTop = (tiles & Bottom) ? qMin(_h1, int(h * hRatio)) : _h1;
0180         hBottom = (tiles & Top) ? qMin(_h3, int(h * (1.0 - hRatio))) : _h3;
0181     }
0182 
0183     // calculate corner locations
0184     w -= wLeft + wRight;
0185     h -= hTop + hBottom;
0186     const int x1 = x0 + wLeft;
0187     const int x2 = x1 + w;
0188     const int y1 = y0 + hTop;
0189     const int y2 = y1 + h;
0190 
0191     const int w2 = _pixmaps.at(7).width() / devicePixelRatio(_pixmaps.at(7));
0192     const int h2 = _pixmaps.at(5).height() / devicePixelRatio(_pixmaps.at(5));
0193 
0194     // corner
0195     if (bits(tiles, Top | Left))
0196         painter->drawPixmap(x0, y0, _pixmaps.at(0), 0, 0, wLeft * devicePixelRatio(_pixmaps.at(0)), hTop * devicePixelRatio(_pixmaps.at(0)));
0197     if (bits(tiles, Top | Right))
0198         painter->drawPixmap(x2,
0199                             y0,
0200                             _pixmaps.at(2),
0201                             (_w3 - wRight) * devicePixelRatio(_pixmaps.at(2)),
0202                             0,
0203                             wRight * devicePixelRatio(_pixmaps.at(2)),
0204                             hTop * devicePixelRatio(_pixmaps.at(2)));
0205     if (bits(tiles, Bottom | Left))
0206         painter->drawPixmap(x0,
0207                             y2,
0208                             _pixmaps.at(6),
0209                             0,
0210                             (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(6)),
0211                             wLeft * devicePixelRatio(_pixmaps.at(6)),
0212                             hBottom * devicePixelRatio(_pixmaps.at(6)));
0213     if (bits(tiles, Bottom | Right))
0214         painter->drawPixmap(x2,
0215                             y2,
0216                             _pixmaps.at(8),
0217                             (_w3 - wRight) * devicePixelRatio(_pixmaps.at(8)),
0218                             (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(8)),
0219                             wRight * devicePixelRatio(_pixmaps.at(8)),
0220                             hBottom * devicePixelRatio(_pixmaps.at(8)));
0221 
0222     // top and bottom
0223     if (w > 0) {
0224         if (tiles & Top)
0225             painter->drawPixmap(x1, y0, w, hTop, _pixmaps.at(1), 0, 0, w2 * devicePixelRatio(_pixmaps.at(1)), hTop * devicePixelRatio(_pixmaps.at(1)));
0226         if (tiles & Bottom)
0227             painter->drawPixmap(x1,
0228                                 y2,
0229                                 w,
0230                                 hBottom,
0231                                 _pixmaps.at(7),
0232                                 0,
0233                                 (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(7)),
0234                                 w2 * devicePixelRatio(_pixmaps.at(7)),
0235                                 hBottom * devicePixelRatio(_pixmaps.at(7)));
0236     }
0237 
0238     // left and right
0239     if (h > 0) {
0240         if (tiles & Left)
0241             painter->drawPixmap(x0, y1, wLeft, h, _pixmaps.at(3), 0, 0, wLeft * devicePixelRatio(_pixmaps.at(3)), h2 * devicePixelRatio(_pixmaps.at(3)));
0242         if (tiles & Right)
0243             painter->drawPixmap(x2,
0244                                 y1,
0245                                 wRight,
0246                                 h,
0247                                 _pixmaps.at(5),
0248                                 (_w3 - wRight) * devicePixelRatio(_pixmaps.at(5)),
0249                                 0,
0250                                 wRight * devicePixelRatio(_pixmaps.at(5)),
0251                                 h2 * devicePixelRatio(_pixmaps.at(5)));
0252     }
0253 
0254     // center
0255     if ((tiles & Center) && h > 0 && w > 0)
0256         painter->drawPixmap(x1, y1, w, h, _pixmaps.at(4));
0257 
0258     // restore
0259     painter->setRenderHint(QPainter::SmoothPixmapTransform, oldHint);
0260 }
0261 }