-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a class to create colorized sprite variants
We need a method to make sprites depend on the player color (see #429). After some research, it seems that a standard technique involves shifting pixels in the image that have a specific hue. This is a quite simple method with very few free parameters; one could imagine changing the saturation and lightness as well to create "darker" or "more gray" nations. Create a class that encapsulates all of this so it's easy to change later. It generates colorized sprites on the fly (might create flicker as this is an expensive operation...) and caches them for later use. The sprites are only meant to be freed at tileset unload, so there is no way to clear the cache. See #429.
- Loading branch information
Showing
3 changed files
with
104 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022 Louis Moureaux <[email protected]> | ||
* | ||
* SPDX-License-Identifier: GPLv3-or-later | ||
*/ | ||
|
||
#include "colorizer.h" | ||
|
||
#include <QBrush> | ||
#include <QPainter> | ||
|
||
namespace freeciv { | ||
|
||
/** | ||
* @class colorizer Swaps colors in QPixmap | ||
* | ||
* Starting from a base pixmap, this class generates new pixmaps with one | ||
* color replaced (for instance, all pink pixels changed to green). | ||
*/ | ||
|
||
/** | ||
* Creates a colorizer that will replace every pixel of the given hue. | ||
* Passing a negative hue disables colorization. | ||
*/ | ||
colorizer::colorizer(const QPixmap &base, int hue_to_replace, | ||
QObject *parent) | ||
: QObject(parent), m_base(base), m_base_image(base.toImage()), | ||
m_hue_to_replace(hue_to_replace) | ||
{ | ||
} | ||
|
||
/** | ||
* Returns a pixmap with some pixels changed to the target color. The pixmap | ||
* is cached for later use. | ||
*/ | ||
const QPixmap *colorizer::pixmap(const QColor &color) const | ||
{ | ||
// Easy cases with nothing to do | ||
if (m_hue_to_replace < 0 || !color.isValid()) { | ||
return &m_base; | ||
} | ||
|
||
// Draw it if we don't have it yet | ||
if (m_cache.count(color.rgba()) == 0) { | ||
auto new_hue = color.hslHue(); | ||
auto image = m_base_image.copy(); | ||
|
||
// Iterate through pixels and replace the hue | ||
for (int x = 0; x < image.width(); ++x) { | ||
for (int y = 0; y < image.height(); ++y) { | ||
auto pixel = image.pixelColor(x, y); | ||
if (pixel.hslHue() == m_hue_to_replace) { | ||
image.setPixelColor(x, y, | ||
QColor::fromHsl(new_hue, pixel.hslSaturation(), | ||
pixel.lightness())); | ||
} | ||
} | ||
} | ||
|
||
m_cache[color.rgba()] = QPixmap::fromImage(image); | ||
} | ||
|
||
return &m_cache[color.rgba()]; | ||
} | ||
|
||
} // namespace freeciv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022 Louis Moureaux <[email protected]> | ||
* | ||
* SPDX-License-Identifier: GPLv3-or-later | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <QBitmap> | ||
#include <QColor> | ||
#include <QPixmap> | ||
|
||
#include <map> | ||
|
||
namespace freeciv { | ||
|
||
class colorizer : public QObject { | ||
Q_OBJECT | ||
|
||
public: | ||
explicit colorizer(const QPixmap &base, int hue_to_replace, | ||
QObject *parent = nullptr); | ||
virtual ~colorizer() = default; | ||
|
||
/// Returns the base pixmap used by this colorizer | ||
QPixmap base() const { return m_base; } | ||
|
||
const QPixmap *pixmap(const QColor &color) const; | ||
|
||
private: | ||
QPixmap m_base; | ||
QImage m_base_image; | ||
int m_hue_to_replace; | ||
mutable std::map<QRgb, QPixmap> m_cache; | ||
}; | ||
|
||
} // namespace freeciv |