aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/cine/pal.cpp69
-rw-r--r--engines/cine/pal.h37
2 files changed, 86 insertions, 20 deletions
diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp
index 9fbb51b915..7f421e6722 100644
--- a/engines/cine/pal.cpp
+++ b/engines/cine/pal.cpp
@@ -161,6 +161,7 @@ void transformPaletteRange(byte *dstPal, byte *srcPal, int startColor, int stopC
}
}
+/*! \brief Shift byte to the left by given amount (Handles negative shifting amounts too, otherwise this would be trivial). */
byte shiftByteLeft(const byte value, const signed shiftLeft) {
if (shiftLeft >= 0)
return value << shiftLeft;
@@ -168,6 +169,33 @@ byte shiftByteLeft(const byte value, const signed shiftLeft) {
return value >> abs(shiftLeft);
}
+/*! \brief Is given endian type big endian? (Handles native endian type too, otherwise this would be trivial). */
+bool isBigEndian(const EndianType endianType) {
+ assert(endianType == NATIVE_ENDIAN || endianType == LITTLE_ENDIAN || endianType == BIG_ENDIAN);
+
+ // Handle explicit little and big endian types here
+ if (endianType != NATIVE_ENDIAN) {
+ return (endianType == BIG_ENDIAN);
+ }
+
+ // Handle native endian type here
+#if defined(SCUMM_BIG_ENDIAN)
+ return true;
+#elif defined(SCUMM_LITTLE_ENDIAN)
+ return false;
+#else
+ #error No endianness defined
+#endif
+}
+
+/*! \brief Calculate byte position of given bit position in a multibyte variable using defined endianness. */
+int bytePos(const int bitPos, const int numBytes, const bool bigEndian) {
+ if (bigEndian)
+ return (numBytes - 1) - (bitPos / 8);
+ else // little endian
+ return bitPos / 8;
+}
+
// a.k.a. palRotate
Palette &Palette::rotateRight(byte firstIndex, byte lastIndex) {
const Color lastColor = _colors[lastIndex];
@@ -183,6 +211,10 @@ uint Palette::colorCount() const {
return _colors.size();
}
+const EndianType Palette::endianType() const {
+ return (_bigEndian ? BIG_ENDIAN : LITTLE_ENDIAN);
+}
+
Graphics::PixelFormat Palette::colorFormat() const {
return _format;
}
@@ -199,6 +231,10 @@ void Palette::setColorFormat(const Graphics::PixelFormat format) {
_bMax = (1 << _bBits) - 1;
}
+void Palette::setEndianType(const EndianType endianType) {
+ _bigEndian = isBigEndian(endianType);
+}
+
// a.k.a. transformPaletteRange
Palette &Palette::saturatedAddColor(byte firstIndex, byte lastIndex, signed r, signed g, signed b) {
assert(firstIndex < colorCount() && lastIndex < colorCount());
@@ -219,37 +255,42 @@ void Palette::saturatedAddColor(byte index, signed r, signed g, signed b) {
_colors[index].b = CLIP<int>(_colors[index].b + b, 0, _bMax);
}
-Palette &Palette::load(const byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors) {
+Palette &Palette::load(const byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const EndianType endianType) {
assert(format.bytesPerPixel * numColors <= size); // Make sure there's enough input space
assert(format.aLoss == 8); // No alpha
assert(format.rShift / 8 == (format.rShift + MAX<int>(0, 8 - format.rLoss - 1)) / 8); // R must be inside one byte
assert(format.gShift / 8 == (format.gShift + MAX<int>(0, 8 - format.gLoss - 1)) / 8); // G must be inside one byte
assert(format.bShift / 8 == (format.bShift + MAX<int>(0, 8 - format.bLoss - 1)) / 8); // B must be inside one byte
+ setEndianType(endianType);
setColorFormat(format);
_colors.clear();
_colors.resize(numColors);
+
+ const int rBytePos = bytePos(format.rShift, format.bytesPerPixel, isBigEndian(endianType));
+ const int gBytePos = bytePos(format.gShift, format.bytesPerPixel, isBigEndian(endianType));
+ const int bBytePos = bytePos(format.bShift, format.bytesPerPixel, isBigEndian(endianType));
for (uint i = 0; i < numColors; i++) {
// _rMax, _gMax, _bMax are also used as masks here
- _colors[i].r = (buf[i * format.bytesPerPixel + (format.rShift / 8)] >> (format.rShift % 8)) & _rMax;
- _colors[i].g = (buf[i * format.bytesPerPixel + (format.gShift / 8)] >> (format.gShift % 8)) & _gMax;
- _colors[i].b = (buf[i * format.bytesPerPixel + (format.bShift / 8)] >> (format.bShift % 8)) & _bMax;
+ _colors[i].r = (buf[i * format.bytesPerPixel + rBytePos] >> (format.rShift % 8)) & _rMax;
+ _colors[i].g = (buf[i * format.bytesPerPixel + gBytePos] >> (format.gShift % 8)) & _gMax;
+ _colors[i].b = (buf[i * format.bytesPerPixel + bBytePos] >> (format.bShift % 8)) & _bMax;
}
return *this;
}
-byte *Palette::save(byte *buf, const uint size) const {
- return save(buf, size, colorFormat(), colorCount());
+byte *Palette::save(byte *buf, const uint size, const EndianType endianType) const {
+ return save(buf, size, colorFormat(), colorCount(), endianType);
}
-byte *Palette::save(byte *buf, const uint size, const Graphics::PixelFormat format) const {
- return save(buf, size, format, colorCount());
+byte *Palette::save(byte *buf, const uint size, const Graphics::PixelFormat format, const EndianType endianType) const {
+ return save(buf, size, format, colorCount(), endianType);
}
-byte *Palette::save(byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const byte firstIndex) const {
+byte *Palette::save(byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const EndianType endianType, const byte firstIndex) const {
assert(format.bytesPerPixel * numColors <= size); // Make sure there's enough output space
assert(format.aLoss == 8); // No alpha
assert(format.rShift / 8 == (format.rShift + MAX<int>(0, 8 - format.rLoss - 1)) / 8); // R must be inside one byte
@@ -269,12 +310,16 @@ byte *Palette::save(byte *buf, const uint size, const Graphics::PixelFormat form
const byte gMask = ((1 << (8 - format.gLoss)) - 1) << (format.gShift % 8);
const byte bMask = ((1 << (8 - format.bLoss)) - 1) << (format.bShift % 8);
+ const int rBytePos = bytePos(format.rShift, format.bytesPerPixel, isBigEndian(endianType));
+ const int gBytePos = bytePos(format.gShift, format.bytesPerPixel, isBigEndian(endianType));
+ const int bBytePos = bytePos(format.bShift, format.bytesPerPixel, isBigEndian(endianType));
+
// Save the palette to the output in the specified format
for (uint i = firstIndex; i < firstIndex + numColors; i++) {
// _rMax, _gMax, _bMax are also used as masks here
- buf[i * format.bytesPerPixel + (format.rShift / 8)] |= (shiftByteLeft(_colors[i].r, rShiftLeft) & rMask);
- buf[i * format.bytesPerPixel + (format.gShift / 8)] |= (shiftByteLeft(_colors[i].g, gShiftLeft) & gMask);
- buf[i * format.bytesPerPixel + (format.bShift / 8)] |= (shiftByteLeft(_colors[i].b, bShiftLeft) & bMask);
+ buf[i * format.bytesPerPixel + rBytePos] |= (shiftByteLeft(_colors[i].r, rShiftLeft) & rMask);
+ buf[i * format.bytesPerPixel + gBytePos] |= (shiftByteLeft(_colors[i].g, gShiftLeft) & gMask);
+ buf[i * format.bytesPerPixel + bBytePos] |= (shiftByteLeft(_colors[i].b, bShiftLeft) & bMask);
}
// Return the pointer to the output palette
diff --git a/engines/cine/pal.h b/engines/cine/pal.h
index 23c9007986..f7c7dee354 100644
--- a/engines/cine/pal.h
+++ b/engines/cine/pal.h
@@ -39,6 +39,15 @@ static const Graphics::PixelFormat kHighPalFormat = {3, 0, 0, 0, 8, 0, 8, 16, 0}
/*! \brief The color format used by OSystem's setPalette-function. */
static const Graphics::PixelFormat kSystemPalFormat = {4, 0, 0, 0, 8, 0, 8, 16, 0};
+/*! \brief Endian types. Used at least by Palette class's load and save functions.
+ * TODO: Move somewhere more general as this is definitely not Cine-engine specific
+ */
+enum EndianType {
+ NATIVE_ENDIAN,
+ LITTLE_ENDIAN,
+ BIG_ENDIAN
+};
+
struct PalEntry {
char name[10];
byte pal1[16];
@@ -63,45 +72,55 @@ void transformPaletteRange(byte *srcPal, byte *dstPal, int startColor, int stopC
// TODO: Test
class Palette {
public:
- /*! \brief Load palette from buffer with given color format and number of colors.
+ /*! \brief Load palette from buffer with given color format, endianness and number of colors.
* \param buf Input buffer
* \param size Input buffer size in bytes
* \param format Input color format
* \param numColors Number of colors to load
+ * \param endianType The endianness of the colors in the input buffer
*/
- Palette &load(const byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors);
+ Palette &load(const byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const EndianType endianType);
- /*! \brief Save the whole palette to buffer in original color format.
+ /*! \brief Save the whole palette to buffer in original color format using defined endianness.
* \param buf Output buffer
* \param size Output buffer size in bytes
+ * \param endianType The endian type to use
*/
- byte *save(byte *buf, const uint size) const;
+ byte *save(byte *buf, const uint size, const EndianType endianType) const;
- /*! \brief Save the whole palette to buffer with given color format.
+ /*! \brief Save the whole palette to buffer in given color format using defined endianness.
* \param buf Output buffer
* \param size Output buffer size in bytes
* \param format Output color format
+ * \param endianType The endian type to use
*/
- byte *save(byte *buf, const uint size, const Graphics::PixelFormat format) const;
+ byte *save(byte *buf, const uint size, const Graphics::PixelFormat format, const EndianType endianType) const;
- /*! \brief Save (partial) palette to buffer with given color format.
+ /*! \brief Save (partial) palette to buffer in given color format using defined endianness.
* \param buf Output buffer
* \param size Output buffer size in bytes
* \param format Output color format
* \param numColors Number of colors to save
+ * \param endianType The endian type to use
* \param firstIndex Starting color index (from which onwards to save the colors)
*/
- byte *save(byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const byte firstIndex = 0) const;
+ byte *save(byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const EndianType endianType, const byte firstIndex = 0) const;
Palette &rotateRight(byte firstIndex, byte lastIndex);
Palette &saturatedAddColor(byte firstIndex, byte lastIndex, signed r, signed g, signed b);
uint colorCount() const;
+ /*! \brief The original endian type in which this palette was loaded.
+ * \note This will always return either BIG_ENDIAN or LITTLE_ENDIAN (So no NATIVE_ENDIAN).
+ */
+ const EndianType endianType() const;
+
/*! \brief The original color format in which this palette was loaded. */
Graphics::PixelFormat colorFormat() const;
private:
void setColorFormat(const Graphics::PixelFormat format);
+ void setEndianType(const EndianType endianType);
void saturatedAddColor(byte index, signed r, signed g, signed b);
private:
@@ -109,9 +128,11 @@ private:
uint8 r, g, b;
};
+ // The used source format, its endianness etc.
Graphics::PixelFormat _format;
uint _rBits, _gBits, _bBits;
uint _rMax, _gMax, _bMax;
+ bool _bigEndian;
Common::Array<Color> _colors;
};