diff options
author | Sven Hesse | 2008-12-24 15:57:43 +0000 |
---|---|---|
committer | Sven Hesse | 2008-12-24 15:57:43 +0000 |
commit | 74024ff3e52804b0247364a5dfeff2e9520e48f8 (patch) | |
tree | c5050b74e4241aab2e4d6d2cc51c2a3cd1f4a7e7 | |
parent | 6fed0af5d1acc0a629bd21cea735abfebca38271 (diff) | |
download | scummvm-rg350-74024ff3e52804b0247364a5dfeff2e9520e48f8.tar.gz scummvm-rg350-74024ff3e52804b0247364a5dfeff2e9520e48f8.tar.bz2 scummvm-rg350-74024ff3e52804b0247364a5dfeff2e9520e48f8.zip |
Moving the dither code to graphics/
svn-id: r35526
-rw-r--r-- | engines/gob/coktelvideo.cpp | 8 | ||||
-rw-r--r-- | engines/gob/coktelvideo.h | 7 | ||||
-rw-r--r-- | engines/gob/indeo3.cpp | 274 | ||||
-rw-r--r-- | engines/gob/indeo3.h | 85 | ||||
-rw-r--r-- | engines/gob/inter_v6.cpp | 3 | ||||
-rw-r--r-- | engines/gob/video.cpp | 3 | ||||
-rw-r--r-- | engines/gob/video.h | 8 | ||||
-rw-r--r-- | engines/gob/video_v6.cpp | 9 | ||||
-rw-r--r-- | graphics/dither.cpp | 296 | ||||
-rw-r--r-- | graphics/dither.h | 109 | ||||
-rw-r--r-- | graphics/module.mk | 1 |
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 ¶ms) { 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 \ |