aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/gob/coktelvideo.cpp8
-rw-r--r--engines/gob/coktelvideo.h7
-rw-r--r--engines/gob/indeo3.cpp274
-rw-r--r--engines/gob/indeo3.h85
-rw-r--r--engines/gob/inter_v6.cpp3
-rw-r--r--engines/gob/video.cpp3
-rw-r--r--engines/gob/video.h8
-rw-r--r--engines/gob/video_v6.cpp9
-rw-r--r--graphics/dither.cpp296
-rw-r--r--graphics/dither.h109
-rw-r--r--graphics/module.mk1
11 files changed, 442 insertions, 361 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp
index 8ea13946d7..cab1072d94 100644
--- a/engines/gob/coktelvideo.cpp
+++ b/engines/gob/coktelvideo.cpp
@@ -25,6 +25,7 @@
#include "common/endian.h"
#include "common/system.h"
+#include "graphics/dither.h"
#include "gob/coktelvideo.h"
#include "gob/indeo3.h"
@@ -863,7 +864,7 @@ const uint16 Vmd::_tableADPCM[128] = {
0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
};
-Vmd::Vmd(PaletteLUT *palLUT) : _palLUT(palLUT) {
+Vmd::Vmd(Graphics::PaletteLUT *palLUT) : _palLUT(palLUT) {
clear(false);
}
@@ -1540,7 +1541,8 @@ void Vmd::blit16(byte *dest, uint16 *src, int16 width, int16 height) {
assert(_palLUT);
- SierraLight *dither = new SierraLight(width, height, _palLUT);
+ Graphics::SierraLight *dither =
+ new Graphics::SierraLight(width, height, _palLUT);
for (int i = 0; i < height; i++) {
byte *d = dest;
@@ -1552,7 +1554,7 @@ void Vmd::blit16(byte *dest, uint16 *src, int16 width, int16 height) {
byte b = ((*s & 0x001F) >> 0) << 1;
byte dY, dU, dV;
- PaletteLUT::RGB2YUV(r << 2, g << 2, b << 2, dY, dU, dV);
+ Graphics::PaletteLUT::RGB2YUV(r << 2, g << 2, b << 2, dY, dU, dV);
byte p = dither->dither(dY, dU, dV, j);
diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h
index 9d7dc93b3f..7ed90ed073 100644
--- a/engines/gob/coktelvideo.h
+++ b/engines/gob/coktelvideo.h
@@ -28,12 +28,13 @@
#include "common/stream.h"
#include "common/array.h"
+#include "graphics/dither.h"
#include "sound/mixer.h"
#include "sound/audiostream.h"
namespace Gob {
-class PaletteLUT;
+class Graphics::PaletteLUT;
class Indeo3;
/** Common interface for handling Coktel Vision videos and derivated formats. */
@@ -303,7 +304,7 @@ protected:
class Vmd : public Imd {
public:
- Vmd(PaletteLUT *palLUT = 0);
+ Vmd(Graphics::PaletteLUT *palLUT = 0);
~Vmd();
bool getAnchor(int16 frame, uint16 partType,
@@ -373,7 +374,7 @@ protected:
byte _scaleExternalX;
byte *_vidMemBuffer;
- PaletteLUT *_palLUT;
+ Graphics::PaletteLUT *_palLUT;
Indeo3 *_codecIndeo3;
void clear(bool del = true);
diff --git a/engines/gob/indeo3.cpp b/engines/gob/indeo3.cpp
index 6182983fe3..951bc2d3e8 100644
--- a/engines/gob/indeo3.cpp
+++ b/engines/gob/indeo3.cpp
@@ -33,282 +33,14 @@
#include "common/endian.h"
#include "common/frac.h"
#include "common/file.h"
+#include "graphics/dither.h"
#include "gob/indeo3.h"
#include "gob/indeo3data.h"
namespace Gob {
-#define SQR(x) ((x) * (x))
-PaletteLUT::PaletteLUT(byte depth, PaletteFormat format) {
- assert((depth > 1) && (depth < 9));
-
- // For adjusting depth
- _depth1 = depth;
- _depth2 = 2 * _depth1;
- _shift = 8 - _depth1;
-
- // The table's dimensions
- _dim1 = (1 << _depth1);
- _dim2 = _dim1 * _dim1;
- _dim3 = _dim1 * _dim1 * _dim1;
-
- _format = format;
-
- // What's already built
- _got = _dim1;
- _gots = new byte[_dim1];
-
- // The lookup table
- _lut = new byte[_dim3];
-
- memset(_lutPal, 0, 768);
- memset(_realPal, 0, 768);
- memset(_gots, 1, _dim1);
-}
-
-void PaletteLUT::setPalette(const byte *palette, PaletteFormat format, byte depth) {
- assert((depth > 1) && (depth < 9));
-
- warning("Building new palette LUT");
-
- int shift = 8 - depth;
-
- // Checking for the table's and the palette's pixel format
- if ((_format == kPaletteRGB) && (format == kPaletteYUV)) {
- byte *newPal = _realPal;
- const byte *oldPal = palette;
- for (int i = 0; i < 256; i++, newPal += 3, oldPal += 3)
- YUV2RGB(oldPal[0] << shift, oldPal[1] << shift, oldPal[2] << shift,
- newPal[0], newPal[1], newPal[2]);
- } else if ((_format == kPaletteYUV) && (format == kPaletteRGB)) {
- byte *newPal = _realPal;
- const byte *oldPal = palette;
- for (int i = 0; i < 256; i++, newPal += 3, oldPal += 3)
- RGB2YUV(oldPal[0] << shift, oldPal[1] << shift, oldPal[2] << shift,
- newPal[0], newPal[1], newPal[2]);
- } else
- memcpy(_realPal, palette, 768);
-
- // Using the specified depth for the lookup
- byte *newPal = _lutPal, *oldPal = _realPal;
- for (int i = 0; i < 768; i++)
- *newPal++ = (*oldPal++) >> _shift;
-
- // Everything has to be rebuilt
- _got = 0;
- memset(_gots, 0, _dim1);
-}
-
-PaletteLUT::~PaletteLUT() {
- delete[] _lut;
- delete[] _gots;
-}
-
-void PaletteLUT::buildNext() {
- if (_got >= _dim1)
- return;
-
- build(_got++);
-}
-
-// Building one "slice"
-void PaletteLUT::build(int d1) {
- // First dimension
- byte *lut = _lut + d1 * _dim2;
-
- // Second dimension
- for (uint32 j = 0; j < _dim1; j++) {
- // Third dimension
- for (uint32 k = 0; k < _dim1; k++) {
- const byte *p = _lutPal;
- uint32 d = 0xFFFFFFFF;
- byte n = 0;
-
- // Going over every palette entry, searching for the closest
- for (int c = 0; c < 256; c++, p += 3) {
- uint32 di = SQR(d1 - p[0]) + SQR(j - p[1]) + SQR(k - p[2]);
- if (di < d) {
- d = di;
- n = c;
- if (d == 0)
- break;
- }
- }
-
- *lut++ = n;
- }
- }
-
- // Got this slice now
- _gots[d1] = 1;
-}
-
-inline int PaletteLUT::getIndex(byte c1, byte c2, byte c3) const {
- return ((c1 >> _shift) << _depth2) | ((c2 >> _shift) << _depth1) | (c3 >> _shift);
-}
-
-void PaletteLUT::getEntry(byte index, byte &c1, byte &c2, byte &c3) const {
- c1 = _realPal[index * 3 + 0];
- c2 = _realPal[index * 3 + 1];
- c3 = _realPal[index * 3 + 2];
-}
-
-byte PaletteLUT::findNearest(byte c1, byte c2, byte c3) {
- return _lut[getIndex(c1, c2, c3)];
-}
-
-byte PaletteLUT::findNearest(byte c1, byte c2, byte c3, byte &nC1, byte &nC2, byte &nC3) {
- // If we don't have the required "slice" yet, build it
- if (!_gots[c1 >> _shift])
- build(c1 >> _shift);
-
- int palIndex = _lut[getIndex(c1, c2, c3)];
- int i = palIndex * 3;
-
- nC1 = _realPal[i + 0];
- nC2 = _realPal[i + 1];
- nC3 = _realPal[i + 2];
-
- return palIndex;
-}
-
-bool PaletteLUT::save(Common::WriteStream &stream) {
- // The table has to be completely built before we can save
- while (_got < _dim1)
- buildNext();
-
- stream.writeByte(_depth1);
- if (stream.write(_realPal, 768) != 768)
- return false;
- if (stream.write(_lutPal, 768) != 768)
- return false;
- if (stream.write(_lut, _dim3) != _dim3)
- return false;
- if (!stream.flush())
- return false;
-
- if (stream.err())
- return false;
-
- return true;
-}
-
-bool PaletteLUT::load(Common::SeekableReadStream &stream) {
- // _realPal + _lutPal + _lut + _depth1
- int32 needSize = 768 + 768 + _dim3 + 1;
-
- if ((stream.size() - stream.pos()) < needSize)
- return false;
-
- byte depth1 = stream.readByte();
-
- if (depth1 != _depth1)
- return false;
-
- if (stream.read(_realPal, 768) != 768)
- return false;
- if (stream.read(_lutPal, 768) != 768)
- return false;
- if (stream.read(_lut, _dim3) != _dim3)
- return false;
-
- _got = _dim1;
- memset(_gots, 1, _dim1);
-
- return true;
-}
-
-SierraLight::SierraLight(int16 width, int16 height, PaletteLUT *palLUT) {
- assert((width > 0) && (height > 0));
-
- _width = width;
- _height = height;
- _palLUT = palLUT;
-
- // Big buffer for the errors of the current and next line
- _errorBuf = new int32[3 * (2 * (_width + 2*1))];
- memset(_errorBuf, 0, (3 * (2 * (_width + 2*1))) * sizeof(int32));
-
- _curLine = 0;
- _errors[0] = _errorBuf + 3;
- _errors[1] = _errors[0] + 3 * (_width + 2*1);
-}
-
-SierraLight::~SierraLight() {
- delete[] _errorBuf;
-}
-
-void SierraLight::newFrame() {
- _curLine = 0;
- memset(_errors[0], 0, 3 * _width * sizeof(int32));
- memset(_errors[1], 0, 3 * _width * sizeof(int32));
-}
-
-void SierraLight::nextLine() {
- // Clear the finished line, it will become the last line in the buffer
- memset(_errors[_curLine], 0, 3 * _width * sizeof(int32));
-
- _curLine = (_curLine + 1) % 2;
-}
-
-byte SierraLight::dither(byte c1, byte c2, byte c3, uint32 x) {
- assert(_palLUT);
-
- int32 eC1, eC2, eC3;
-
- getErrors(x, eC1, eC2, eC3);
-
- // Apply error on values
- c1 = CLIP<int>(c1 + eC1, 0, 255);
- c2 = CLIP<int>(c2 + eC2, 0, 255);
- c3 = CLIP<int>(c3 + eC3, 0, 255);
-
- // Find color
- byte newC1, newC2, newC3;
- byte newPixel = _palLUT->findNearest(c1, c2, c3, newC1, newC2, newC3);
-
- // Calculate new error
- eC1 = c1 - newC1;
- eC2 = c2 - newC2;
- eC3 = c3 - newC3;
-
- // Add them
- addErrors(x, eC1, eC2, eC3);
-
- return newPixel;
-}
-
-inline void SierraLight::getErrors(uint32 x, int32 &eC1, int32 &eC2, int32 &eC3) {
- int32 *errCur = _errors[_curLine];
-
- x *= 3;
- eC1 = errCur[x + 0] >> 2;
- eC2 = errCur[x + 1] >> 2;
- eC3 = errCur[x + 2] >> 2;
-}
-
-inline void SierraLight::addErrors(uint32 x, int32 eC1, int32 eC2, int32 eC3) {
- int32 *errCur = _errors[_curLine];
- int32 *errNext = _errors[(_curLine + 1) % 2];
-
- // Indices for current error
- int x0 = 3 * (x + 1);
- int x1 = 3 * (x + 0);
- int x2 = 3 * (x - 1);
-
- errCur [x0 + 0] += eC1 << 1;
- errCur [x0 + 1] += eC2 << 1;
- errCur [x0 + 2] += eC3 << 1;
- errNext[x1 + 0] += eC1;
- errNext[x1 + 1] += eC2;
- errNext[x1 + 2] += eC3;
- errNext[x2 + 0] += eC1;
- errNext[x2 + 1] += eC2;
- errNext[x2 + 2] += eC3;
-}
-
-Indeo3::Indeo3(int16 width, int16 height, PaletteLUT *palLUT) {
+Indeo3::Indeo3(int16 width, int16 height, Graphics::PaletteLUT *palLUT) {
assert((width > 0) && (height > 0));
_width = width;
@@ -363,7 +95,7 @@ void Indeo3::setDither(DitherAlgorithm dither) {
switch(dither) {
case kDitherSierraLight:
- _ditherSL = new SierraLight(_width, _height, _palLUT);
+ _ditherSL = new Graphics::SierraLight(_width, _height, _palLUT);
break;
default:
diff --git a/engines/gob/indeo3.h b/engines/gob/indeo3.h
index 28eba336e5..f30b47806a 100644
--- a/engines/gob/indeo3.h
+++ b/engines/gob/indeo3.h
@@ -35,81 +35,12 @@
#include "common/stream.h"
-namespace Gob {
-
-class PaletteLUT {
-public:
- enum PaletteFormat {
- kPaletteRGB,
- kPaletteYUV
- };
-
- inline static void YUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) {
- r = CLIP<int>(y + ((1357 * (v - 128)) >> 10), 0, 255);
- g = CLIP<int>(y - (( 691 * (v - 128)) >> 10) - ((333 * (u - 128)) >> 10), 0, 255);
- b = CLIP<int>(y + ((1715 * (u - 128)) >> 10), 0, 255);
- }
- inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) {
- y = CLIP<int>( ((r * 306) >> 10) + ((g * 601) >> 10) + ((b * 117) >> 10) , 0, 255);
- u = CLIP<int>(-((r * 172) >> 10) - ((g * 340) >> 10) + ((b * 512) >> 10) + 128, 0, 255);
- v = CLIP<int>( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255);
- }
-
- PaletteLUT(byte depth, PaletteFormat format);
- ~PaletteLUT();
-
- void setPalette(const byte *palette, PaletteFormat format, byte depth);
-
- void buildNext();
-
- void getEntry(byte index, byte &c1, byte &c2, byte &c3) const;
- byte findNearest(byte c1, byte c2, byte c3);
- byte findNearest(byte c1, byte c2, byte c3, byte &nC1, byte &nC2, byte &nC3);
-
- bool save(Common::WriteStream &stream);
- bool load(Common::SeekableReadStream &stream);
-
-private:
- byte _depth1, _depth2;
- byte _shift;
-
- uint32 _dim1, _dim2, _dim3;
+namespace Graphics {
+ class PaletteLUT;
+ class SierraLight;
+}
- PaletteFormat _format;
- byte _lutPal[768];
- byte _realPal[768];
-
- uint32 _got;
- byte *_gots;
- byte *_lut;
-
- void build(int d1);
- inline int getIndex(byte c1, byte c2, byte c3) const;
- inline void plotEntry(int x, int y, int z, byte e, byte *filled, int &free);
-};
-
-// The Sierra-2-4A ("Filter Light") dithering algorithm
-class SierraLight {
-public:
- SierraLight(int16 width, int16 height, PaletteLUT *palLUT);
- ~SierraLight();
-
- void newFrame();
- void nextLine();
- byte dither(byte c1, byte c2, byte c3, uint32 x);
-
-protected:
- int16 _width, _height;
-
- PaletteLUT *_palLUT;
-
- int32 *_errorBuf;
- int32 *_errors[2];
- int _curLine;
-
- inline void getErrors(uint32 x, int32 &eC1, int32 &eC2, int32 &eC3);
- inline void addErrors(uint32 x, int32 eC1, int32 eC2, int32 eC3);
-};
+namespace Gob {
class Indeo3 {
public:
@@ -118,7 +49,7 @@ public:
kDitherSierraLight
};
- Indeo3(int16 width, int16 height, PaletteLUT *palLUT);
+ Indeo3(int16 width, int16 height, Graphics::PaletteLUT *palLUT);
~Indeo3();
static bool isIndeo3(byte *data, uint32 dataLen);
@@ -154,10 +85,10 @@ private:
byte *_ModPred;
uint16 *_corrector_type;
- PaletteLUT *_palLUT;
+ Graphics::PaletteLUT *_palLUT;
DitherAlgorithm _dither;
- SierraLight *_ditherSL;
+ Graphics::SierraLight *_ditherSL;
struct BlitState {
uint32 curX, curY;
diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp
index 8e16337827..65022ab539 100644
--- a/engines/gob/inter_v6.cpp
+++ b/engines/gob/inter_v6.cpp
@@ -25,6 +25,7 @@
#include "common/endian.h"
#include "common/file.h"
+#include "graphics/dither.h"
#include "gob/gob.h"
#include "gob/inter.h"
@@ -926,7 +927,7 @@ bool Inter_v6::o6_palLoad(OpFuncParams &params) {
if (_gotFirstPalette)
_vm->_video->_palLUT->setPalette((const byte *) _vm->_global->_pPaletteDesc->vgaPal,
- PaletteLUT::kPaletteRGB, 6);
+ Graphics::PaletteLUT::kPaletteRGB, 6);
_gotFirstPalette = true;
return false;
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
index fd256096ce..3c26ea4ee7 100644
--- a/engines/gob/video.cpp
+++ b/engines/gob/video.cpp
@@ -27,6 +27,7 @@
#include "graphics/cursorman.h"
#include "graphics/fontman.h"
#include "graphics/surface.h"
+#include "graphics/dither.h"
#include "gob/gob.h"
#include "gob/video.h"
@@ -109,7 +110,7 @@ Video::Video(GobEngine *vm) : _vm(vm) {
_dirtyAll = false;
- _palLUT = new PaletteLUT(6, PaletteLUT::kPaletteYUV);
+ _palLUT = new Graphics::PaletteLUT(6, Graphics::PaletteLUT::kPaletteYUV);
}
char Video::initDriver(int16 vidMode) {
diff --git a/engines/gob/video.h b/engines/gob/video.h
index 42eafae5de..50653bd26c 100644
--- a/engines/gob/video.h
+++ b/engines/gob/video.h
@@ -31,9 +31,13 @@
#include "gob/gob.h"
+namespace Graphics {
+ class PaletteLUT;
+}
+
namespace Gob {
-class PaletteLUT;
+class Graphics::PaletteLUT;
// Some Surfaces are simultaneous in Draw::spritesArray and discrete
// variables, so it's a references counting class that cleans
@@ -122,7 +126,7 @@ public:
int16 _screenDeltaX;
int16 _screenDeltaY;
- PaletteLUT *_palLUT;
+ Graphics::PaletteLUT *_palLUT;
void freeDriver();
void initPrimary(int16 mode);
diff --git a/engines/gob/video_v6.cpp b/engines/gob/video_v6.cpp
index 6746715de9..a3ba8cb340 100644
--- a/engines/gob/video_v6.cpp
+++ b/engines/gob/video_v6.cpp
@@ -25,6 +25,7 @@
#include "common/endian.h"
#include "common/savefile.h"
+#include "graphics/dither.h"
#include "gob/gob.h"
#include "gob/video.h"
@@ -104,7 +105,7 @@ bool Video_v6::savePalLUT(const char *target) {
void Video_v6::buildPalLUT() {
char text[30];
- _palLUT->setPalette(_ditherPalette, PaletteLUT::kPaletteYUV, 8);
+ _palLUT->setPalette(_ditherPalette, Graphics::PaletteLUT::kPaletteYUV, 8);
for (int i = 0; (i < 64) && !_vm->shouldQuit(); i++) {
sprintf(text, "Building palette table: %02d/63", i);
@@ -175,7 +176,8 @@ void Video_v6::shadeRect(SurfaceDesc *dest,
_palLUT->getEntry(color, sY, sU, sV);
- SierraLight *dither = new SierraLight(width, height, _palLUT);
+ Graphics::SierraLight *dither =
+ new Graphics::SierraLight(width, height, _palLUT);
for (int i = 0; i < height; i++) {
byte *d = vidMem;
@@ -253,7 +255,8 @@ void Video_v6::drawYUV(SurfaceDesc *destDesc, int16 x, int16 y,
if ((y + height - 1) >= destDesc->getHeight())
height = destDesc->getHeight() - y;
- SierraLight *dither = new SierraLight(width, height, _palLUT);
+ Graphics::SierraLight *dither =
+ new Graphics::SierraLight(width, height, _palLUT);
for (int i = 0; i < height; i++) {
byte *dest = vidMem;
diff --git a/graphics/dither.cpp b/graphics/dither.cpp
new file mode 100644
index 0000000000..21f5ded8c3
--- /dev/null
+++ b/graphics/dither.cpp
@@ -0,0 +1,296 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "graphics/dither.h"
+
+namespace Graphics {
+
+PaletteLUT::PaletteLUT(byte depth, PaletteFormat format) {
+ assert((depth > 1) && (depth < 9));
+
+ // For adjusting depth
+ _depth1 = depth;
+ _depth2 = 2 * _depth1;
+ _shift = 8 - _depth1;
+
+ // The table's dimensions
+ _dim1 = (1 << _depth1);
+ _dim2 = _dim1 * _dim1;
+ _dim3 = _dim1 * _dim1 * _dim1;
+
+ _format = format;
+
+ // What's already built
+ _got = _dim1;
+ _gots = new byte[_dim1];
+
+ // The lookup table
+ _lut = new byte[_dim3];
+
+ memset(_lutPal, 0, 768);
+ memset(_realPal, 0, 768);
+ memset(_gots, 1, _dim1);
+}
+
+void PaletteLUT::setPalette(const byte *palette, PaletteFormat format, byte depth) {
+ assert((depth > 1) && (depth < 9));
+
+ int shift = 8 - depth;
+
+ // Checking for the table's and the palette's pixel format
+ if ((_format == kPaletteRGB) && (format == kPaletteYUV)) {
+ byte *newPal = _realPal;
+ const byte *oldPal = palette;
+ for (int i = 0; i < 256; i++, newPal += 3, oldPal += 3)
+ YUV2RGB(oldPal[0] << shift, oldPal[1] << shift, oldPal[2] << shift,
+ newPal[0], newPal[1], newPal[2]);
+ } else if ((_format == kPaletteYUV) && (format == kPaletteRGB)) {
+ byte *newPal = _realPal;
+ const byte *oldPal = palette;
+ for (int i = 0; i < 256; i++, newPal += 3, oldPal += 3)
+ RGB2YUV(oldPal[0] << shift, oldPal[1] << shift, oldPal[2] << shift,
+ newPal[0], newPal[1], newPal[2]);
+ } else
+ memcpy(_realPal, palette, 768);
+
+ // Using the specified depth for the lookup
+ byte *newPal = _lutPal, *oldPal = _realPal;
+ for (int i = 0; i < 768; i++)
+ *newPal++ = (*oldPal++) >> _shift;
+
+ // Everything has to be rebuilt
+ _got = 0;
+ memset(_gots, 0, _dim1);
+}
+
+PaletteLUT::~PaletteLUT() {
+ delete[] _lut;
+ delete[] _gots;
+}
+
+void PaletteLUT::buildNext() {
+ if (_got >= _dim1)
+ return;
+
+ build(_got++);
+}
+
+#define SQR(x) ((x) * (x))
+// Building one "slice"
+void PaletteLUT::build(int d1) {
+ // First dimension
+ byte *lut = _lut + d1 * _dim2;
+
+ // Second dimension
+ for (uint32 j = 0; j < _dim1; j++) {
+ // Third dimension
+ for (uint32 k = 0; k < _dim1; k++) {
+ const byte *p = _lutPal;
+ uint32 d = 0xFFFFFFFF;
+ byte n = 0;
+
+ // Going over every palette entry, searching for the closest
+ for (int c = 0; c < 256; c++, p += 3) {
+ uint32 di = SQR(d1 - p[0]) + SQR(j - p[1]) + SQR(k - p[2]);
+ if (di < d) {
+ d = di;
+ n = c;
+ if (d == 0)
+ break;
+ }
+ }
+
+ *lut++ = n;
+ }
+ }
+
+ // Got this slice now
+ _gots[d1] = 1;
+}
+
+inline int PaletteLUT::getIndex(byte c1, byte c2, byte c3) const {
+ return ((c1 >> _shift) << _depth2) | ((c2 >> _shift) << _depth1) | (c3 >> _shift);
+}
+
+void PaletteLUT::getEntry(byte index, byte &c1, byte &c2, byte &c3) const {
+ c1 = _realPal[index * 3 + 0];
+ c2 = _realPal[index * 3 + 1];
+ c3 = _realPal[index * 3 + 2];
+}
+
+byte PaletteLUT::findNearest(byte c1, byte c2, byte c3) {
+ return _lut[getIndex(c1, c2, c3)];
+}
+
+byte PaletteLUT::findNearest(byte c1, byte c2, byte c3, byte &nC1, byte &nC2, byte &nC3) {
+ // If we don't have the required "slice" yet, build it
+ if (!_gots[c1 >> _shift])
+ build(c1 >> _shift);
+
+ int palIndex = _lut[getIndex(c1, c2, c3)];
+ int i = palIndex * 3;
+
+ nC1 = _realPal[i + 0];
+ nC2 = _realPal[i + 1];
+ nC3 = _realPal[i + 2];
+
+ return palIndex;
+}
+
+bool PaletteLUT::save(Common::WriteStream &stream) {
+ // The table has to be completely built before we can save
+ while (_got < _dim1)
+ buildNext();
+
+ stream.writeByte(_depth1);
+ if (stream.write(_realPal, 768) != 768)
+ return false;
+ if (stream.write(_lutPal, 768) != 768)
+ return false;
+ if (stream.write(_lut, _dim3) != _dim3)
+ return false;
+ if (!stream.flush())
+ return false;
+
+ if (stream.err())
+ return false;
+
+ return true;
+}
+
+bool PaletteLUT::load(Common::SeekableReadStream &stream) {
+ // _realPal + _lutPal + _lut + _depth1
+ int32 needSize = 768 + 768 + _dim3 + 1;
+
+ if ((stream.size() - stream.pos()) < needSize)
+ return false;
+
+ byte depth1 = stream.readByte();
+
+ if (depth1 != _depth1)
+ return false;
+
+ if (stream.read(_realPal, 768) != 768)
+ return false;
+ if (stream.read(_lutPal, 768) != 768)
+ return false;
+ if (stream.read(_lut, _dim3) != _dim3)
+ return false;
+
+ _got = _dim1;
+ memset(_gots, 1, _dim1);
+
+ return true;
+}
+
+SierraLight::SierraLight(int16 width, int16 height, PaletteLUT *palLUT) {
+ assert((width > 0) && (height > 0));
+
+ _width = width;
+ _height = height;
+ _palLUT = palLUT;
+
+ // Big buffer for the errors of the current and next line
+ _errorBuf = new int32[3 * (2 * (_width + 2*1))];
+ memset(_errorBuf, 0, (3 * (2 * (_width + 2*1))) * sizeof(int32));
+
+ _curLine = 0;
+ _errors[0] = _errorBuf + 3;
+ _errors[1] = _errors[0] + 3 * (_width + 2*1);
+}
+
+SierraLight::~SierraLight() {
+ delete[] _errorBuf;
+}
+
+void SierraLight::newFrame() {
+ _curLine = 0;
+ memset(_errors[0], 0, 3 * _width * sizeof(int32));
+ memset(_errors[1], 0, 3 * _width * sizeof(int32));
+}
+
+void SierraLight::nextLine() {
+ // Clear the finished line, it will become the last line in the buffer
+ memset(_errors[_curLine], 0, 3 * _width * sizeof(int32));
+
+ _curLine = (_curLine + 1) % 2;
+}
+
+byte SierraLight::dither(byte c1, byte c2, byte c3, uint32 x) {
+ assert(_palLUT);
+
+ int32 eC1, eC2, eC3;
+
+ getErrors(x, eC1, eC2, eC3);
+
+ // Apply error on values
+ c1 = CLIP<int>(c1 + eC1, 0, 255);
+ c2 = CLIP<int>(c2 + eC2, 0, 255);
+ c3 = CLIP<int>(c3 + eC3, 0, 255);
+
+ // Find color
+ byte newC1, newC2, newC3;
+ byte newPixel = _palLUT->findNearest(c1, c2, c3, newC1, newC2, newC3);
+
+ // Calculate new error
+ eC1 = c1 - newC1;
+ eC2 = c2 - newC2;
+ eC3 = c3 - newC3;
+
+ // Add them
+ addErrors(x, eC1, eC2, eC3);
+
+ return newPixel;
+}
+
+inline void SierraLight::getErrors(uint32 x, int32 &eC1, int32 &eC2, int32 &eC3) {
+ int32 *errCur = _errors[_curLine];
+
+ x *= 3;
+ eC1 = errCur[x + 0] >> 2;
+ eC2 = errCur[x + 1] >> 2;
+ eC3 = errCur[x + 2] >> 2;
+}
+
+inline void SierraLight::addErrors(uint32 x, int32 eC1, int32 eC2, int32 eC3) {
+ int32 *errCur = _errors[_curLine];
+ int32 *errNext = _errors[(_curLine + 1) % 2];
+
+ // Indices for current error
+ int x0 = 3 * (x + 1);
+ int x1 = 3 * (x + 0);
+ int x2 = 3 * (x - 1);
+
+ errCur [x0 + 0] += eC1 << 1;
+ errCur [x0 + 1] += eC2 << 1;
+ errCur [x0 + 2] += eC3 << 1;
+ errNext[x1 + 0] += eC1;
+ errNext[x1 + 1] += eC2;
+ errNext[x1 + 2] += eC3;
+ errNext[x2 + 0] += eC1;
+ errNext[x2 + 1] += eC2;
+ errNext[x2 + 2] += eC3;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/dither.h b/graphics/dither.h
new file mode 100644
index 0000000000..b0284b2534
--- /dev/null
+++ b/graphics/dither.h
@@ -0,0 +1,109 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef GRAPHICS_DITHER_H
+#define GRAPHICS_DITHER_H
+
+#include "common/util.h"
+#include "common/stream.h"
+
+namespace Graphics {
+
+class PaletteLUT {
+public:
+ enum PaletteFormat {
+ kPaletteRGB,
+ kPaletteYUV
+ };
+
+ inline static void YUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) {
+ r = CLIP<int>(y + ((1357 * (v - 128)) >> 10), 0, 255);
+ g = CLIP<int>(y - (( 691 * (v - 128)) >> 10) - ((333 * (u - 128)) >> 10), 0, 255);
+ b = CLIP<int>(y + ((1715 * (u - 128)) >> 10), 0, 255);
+ }
+ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) {
+ y = CLIP<int>( ((r * 306) >> 10) + ((g * 601) >> 10) + ((b * 117) >> 10) , 0, 255);
+ u = CLIP<int>(-((r * 172) >> 10) - ((g * 340) >> 10) + ((b * 512) >> 10) + 128, 0, 255);
+ v = CLIP<int>( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255);
+ }
+
+ PaletteLUT(byte depth, PaletteFormat format);
+ ~PaletteLUT();
+
+ void setPalette(const byte *palette, PaletteFormat format, byte depth);
+
+ void buildNext();
+
+ void getEntry(byte index, byte &c1, byte &c2, byte &c3) const;
+ byte findNearest(byte c1, byte c2, byte c3);
+ byte findNearest(byte c1, byte c2, byte c3, byte &nC1, byte &nC2, byte &nC3);
+
+ bool save(Common::WriteStream &stream);
+ bool load(Common::SeekableReadStream &stream);
+
+private:
+ byte _depth1, _depth2;
+ byte _shift;
+
+ uint32 _dim1, _dim2, _dim3;
+
+ PaletteFormat _format;
+ byte _lutPal[768];
+ byte _realPal[768];
+
+ uint32 _got;
+ byte *_gots;
+ byte *_lut;
+
+ void build(int d1);
+ inline int getIndex(byte c1, byte c2, byte c3) const;
+ inline void plotEntry(int x, int y, int z, byte e, byte *filled, int &free);
+};
+
+// The Sierra-2-4A ("Filter Light") dithering algorithm
+class SierraLight {
+public:
+ SierraLight(int16 width, int16 height, PaletteLUT *palLUT);
+ ~SierraLight();
+
+ void newFrame();
+ void nextLine();
+ byte dither(byte c1, byte c2, byte c3, uint32 x);
+
+protected:
+ int16 _width, _height;
+
+ PaletteLUT *_palLUT;
+
+ int32 *_errorBuf;
+ int32 *_errors[2];
+ int _curLine;
+
+ inline void getErrors(uint32 x, int32 &eC1, int32 &eC2, int32 &eC3);
+ inline void addErrors(uint32 x, int32 eC1, int32 eC2, int32 eC3);
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index 5a10bf2cd0..05a23a5d1b 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -2,6 +2,7 @@ MODULE := graphics
MODULE_OBJS := \
cursorman.o \
+ dither.o \
font.o \
fontman.o \
fonts/consolefont.o \