[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