[Scummvm-git-logs] scummvm master -> 8af5e557122d8b7b17a428945b372982ef3d61c7
sev-
noreply at scummvm.org
Mon Mar 11 00:02:23 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
8af5e55712 GRAPHICS: Define Palette class and use in PaletteLookup
Commit: 8af5e557122d8b7b17a428945b372982ef3d61c7
https://github.com/scummvm/scummvm/commit/8af5e557122d8b7b17a428945b372982ef3d61c7
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2024-03-11T01:02:15+01:00
Commit Message:
GRAPHICS: Define Palette class and use in PaletteLookup
Changed paths:
graphics/palette.cpp
graphics/palette.h
diff --git a/graphics/palette.cpp b/graphics/palette.cpp
index 1568af8c343..4138a52ef26 100644
--- a/graphics/palette.cpp
+++ b/graphics/palette.cpp
@@ -22,23 +22,107 @@
namespace Graphics {
-PaletteLookup::PaletteLookup() {
+Palette::Palette(uint size) : _data(nullptr), _size(size) {
+ if (_size > 0) {
+ _data = new byte[_size * 3]();
+ }
+}
+
+Palette::Palette(const Palette &p) : _data(nullptr), _size(p._size) {
+ if (_size > 0) {
+ _data = new byte[_size * 3]();
+ memcpy(_data, p._data, _size * 3);
+ }
+}
+
+Palette::~Palette() {
+ delete[] _data;
+}
+
+bool Palette::equals(const Palette &p) const {
+ return p._size == _size && !memcmp(_data, p._data, p._size * 3);
+}
+
+bool Palette::contains(const Palette& p) const {
+ return p._size <= _size && !memcmp(_data, p._data, p._size * 3);
+}
+
+byte Palette::findBestColor(byte cr, byte cg, byte cb, bool useNaiveAlg) const {
+ uint bestColor = 0;
+ uint32 min = 0xFFFFFFFF;
+
+ if (useNaiveAlg) {
+ for (uint i = 0; i < _size; i++) {
+ int r = _data[3 * i + 0] - cr;
+ int g = _data[3 * i + 1] - cg;
+ int b = _data[3 * i + 2] - cb;
+
+ uint32 distWeighted = 3 * r * r + 5 * g * g + 2 * b * b;
+ if (distWeighted < min) {
+ bestColor = i;
+ min = distWeighted;
+ }
+ }
+ } else {
+ for (uint i = 0; i < _size; ++i) {
+ int rmean = (_data[3 * i + 0] + cr) / 2;
+ int r = _data[3 * i + 0] - cr;
+ int g = _data[3 * i + 1] - cg;
+ int b = _data[3 * i + 2] - cb;
+
+ uint32 distSquared = (((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8);
+ if (distSquared < min) {
+ bestColor = i;
+ min = distSquared;
+ }
+ }
+ }
+
+ return bestColor;
+}
+
+void Palette::clear() {
+ if (_size > 0)
+ memset(_data, 0, _size);
+}
+
+void Palette::set(const byte *colors, uint start, uint num) {
+ assert(start < _size && (start + num) <= _size);
+ memcpy(_data + 3 * start, colors, 3 * num);
+}
+
+void Palette::set(const Palette &p, uint start, uint num) {
+ assert(start < _size && (start + num) <= _size);
+ memcpy(_data + 3 * start, p._data, 3 * num);
+}
+
+void Palette::grab(byte *colors, uint start, uint num) const {
+ assert(start < _size && (start + num) <= _size);
+ memcpy(colors, _data + 3 * start, 3 * num);
+}
+
+void Palette::grab(Palette &p, uint start, uint num) const {
+ assert(start < _size && (start + num) <= _size);
+ memcpy(p._data, _data + 3 * start, 3 * num);
+}
+
+PaletteLookup::PaletteLookup(): _palette(256) {
_paletteSize = 0;
}
-PaletteLookup::PaletteLookup(const byte *palette, uint len) {
+PaletteLookup::PaletteLookup(const byte *palette, uint len) : _palette(256) {
_paletteSize = len;
- memcpy(_palette, palette, len * 3);
+ _palette.set(palette, 0, len);
}
bool PaletteLookup::setPalette(const byte *palette, uint len) {
// Check if the passed palette matched the one we have
- if (len == _paletteSize && !memcmp(_palette, palette, len * 3))
+ if (len == _paletteSize && !memcmp(_palette.data(), palette, len * 3))
return false;
_paletteSize = len;
- memcpy(_palette, palette, len * 3);
+ _palette.set(palette, 0, len);
_colorHash.clear();
return true;
@@ -50,52 +134,19 @@ byte PaletteLookup::findBestColor(byte cr, byte cg, byte cb, bool useNaiveAlg) {
return 0;
}
- uint bestColor = 0;
- double min = 0xFFFFFFFF;
-
uint32 color = cr << 16 | cg << 8 | cb;
if (_colorHash.contains(color))
return _colorHash[color];
- if (useNaiveAlg) {
- byte *palettePtr = _palette;
-
- for (uint i = 0; i < _paletteSize; i++) {
- int redSquareDiff = (cr - palettePtr[0]) * (cr - palettePtr[0]);
- int greenSquareDiff = (cg - palettePtr[1]) * (cg - palettePtr[1]);
- int blueSquareDiff = (cb - palettePtr[2]) * (cb - palettePtr[2]);
-
- int weightedColorError = 3 * redSquareDiff + 5 * greenSquareDiff + 2 * blueSquareDiff;
- if (weightedColorError < min) {
- bestColor = i;
- min = weightedColorError;
- }
-
- palettePtr += 3;
- }
- } else {
- for (uint i = 0; i < _paletteSize; ++i) {
- int rmean = (*(_palette + 3 * i + 0) + cr) / 2;
- int r = *(_palette + 3 * i + 0) - cr;
- int g = *(_palette + 3 * i + 1) - cg;
- int b = *(_palette + 3 * i + 2) - cb;
-
- double dist = sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
- if (min > dist) {
- bestColor = i;
- min = dist;
- }
- }
- }
-
+ uint bestColor = _palette.findBestColor(cr, cg, cb, useNaiveAlg);
_colorHash[color] = bestColor;
return bestColor;
}
uint32 *PaletteLookup::createMap(const byte *srcPalette, uint len, bool useNaiveAlg) {
- if (len <= _paletteSize && memcmp(_palette, srcPalette, len * 3) == 0)
+ if (len <= _paletteSize && memcmp(_palette.data(), srcPalette, len * 3) == 0)
return nullptr;
uint32 *map = new uint32[len];
diff --git a/graphics/palette.h b/graphics/palette.h
index 8ebad3fdb1b..02ff1b6089f 100644
--- a/graphics/palette.h
+++ b/graphics/palette.h
@@ -111,6 +111,110 @@ public:
namespace Graphics {
+/**
+ * @brief Simple class for handling a palette data.
+ *
+ * The palette data is specified in interleaved RGB format. That is, the
+ * first byte of the memory block 'colors' points at is the red component
+ * of the first new color; the second byte the green component of the first
+ * new color; the third byte the blue component, the last byte to the alpha
+ * (transparency) value. Then the second color starts, and so on. So memory
+ * looks like this: R1-G1-B1-R2-G2-B2-R3-...
+ */
+class Palette {
+ byte *_data;
+ uint16 _size;
+
+public:
+ static const uint16 npos = 0xFFFF;
+
+ /**
+ * @brief Construct a new Palette object
+ *
+ * @param size the number of palette entries
+ */
+ Palette(uint size);
+
+ Palette(const Palette &p);
+
+ ~Palette();
+
+ bool operator==(const Palette &rhs) const { return equals(rhs); }
+ bool operator!=(const Palette &rhs) const { return !equals(rhs); }
+
+ bool equals(const Palette &p) const;
+
+ bool contains(const Palette &p) const;
+
+ const byte *data() const { return _data; }
+ uint size() const { return _size; }
+
+ void set(uint entry, byte r, byte g, byte b) {
+ assert(entry < _size);
+ _data[entry * 3 + 0] = r;
+ _data[entry * 3 + 1] = g;
+ _data[entry * 3 + 2] = b;
+ }
+
+ void get(uint entry, byte &r, byte &g, byte &b) const {
+ assert(entry < _size);
+ r = _data[entry * 3 + 0];
+ g = _data[entry * 3 + 1];
+ b = _data[entry * 3 + 2];
+ }
+
+ /**
+ * Finds the index of an exact color from the palette.
+ *
+ * @return the palette index or npos if not found
+ */
+ uint find(byte r, byte g, byte b) const {
+ for (uint i = 0; i < _size; i++) {
+ if (_data[i * 3 + 0] == r && _data[i * 3 + 1] == g && _data[i * 3 + 2] == b)
+ return i;
+ }
+ return npos;
+ }
+
+ /**
+ * Finds the index of the closest color from the palette.
+ *
+ * @param useNaiveAlg if true, use a simpler algorithm
+ *
+ * @return the palette index
+ */
+ byte findBestColor(byte r, byte g, byte b, bool useNaiveAlg = false) const;
+
+ void clear();
+
+ /**
+ * Replace the specified range of the palette with new colors.
+ * The palette entries from 'start' till (start+num-1) will be replaced - so
+ * a full palette update is accomplished via start=0, num=256.
+ *
+ * @param colors the new palette data, in interleaved RGB format
+ * @param start the first palette entry to be updated
+ * @param num the number of palette entries to be updated
+ *
+ * @note It is an error if start+num exceeds 256.
+ */
+ void set(const byte *colors, uint start, uint num);
+ void set(const Palette &p, uint start, uint num);
+
+ /**
+ * Grabs a specified part of the currently active palette.
+ * The format is the same as for setPalette.
+ *
+ * @param colors the palette data, in interleaved RGB format
+ * @param start the first platte entry to be read
+ * @param num the number of palette entries to be read
+ *
+ * @note It is an error if start+num exceeds 256.
+ */
+ void grab(byte *colors, uint start, uint num) const;
+ void grab(Palette &p, uint start, uint num) const;
+};
+
class PaletteLookup {
public:
PaletteLookup();
@@ -137,7 +241,7 @@ public:
* @brief This method returns closest color from the palette
* and it uses cache for faster lookups
*
- * @param useNaiveAlg if true, use a simpler algorithm (non-floating point calculations)
+ * @param useNaiveAlg if true, use a simpler algorithm
*
* @return the palette index
*/
@@ -149,14 +253,14 @@ public:
*
* @param palette the palette data, in interleaved RGB format
* @param len the number of palette entries to be read
- * @param useNaiveAlg if true, use a simpler algorithm (non-floating point calculations)
+ * @param useNaiveAlg if true, use a simpler algorithm
*
* @return the created map, or nullptr if one isn't needed.
*/
uint32 *createMap(const byte *srcPalette, uint len, bool useNaiveAlg = false);
private:
- byte _palette[256 * 3];
+ Palette _palette;
uint _paletteSize;
Common::HashMap<int, byte> _colorHash;
};
More information about the Scummvm-git-logs
mailing list