aboutsummaryrefslogtreecommitdiff
path: root/engines/tony/gfxcore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tony/gfxcore.cpp')
-rw-r--r--engines/tony/gfxcore.cpp2212
1 files changed, 2212 insertions, 0 deletions
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
new file mode 100644
index 0000000000..71bf31396c
--- /dev/null
+++ b/engines/tony/gfxcore.cpp
@@ -0,0 +1,2212 @@
+/* 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.
+ *
+ */
+
+/*
+ * This code is based on original Tony Tough source code
+ *
+ * Copyright (c) 1997-2003 Nayma Software
+ */
+
+#include "tony/gfxengine.h"
+#include "tony/mpal/mpalutils.h"
+#include "tony/tony.h"
+
+namespace Tony {
+
+/****************************************************************************\
+* RMGfxTask Methods
+\****************************************************************************/
+
+RMGfxTask::RMGfxTask() {
+ _nPrior = 0;
+ _nInList = 0;
+}
+
+int RMGfxTask::priority() {
+ return _nPrior;
+}
+
+void RMGfxTask::removeThis(CORO_PARAM, bool &result) {
+ result = true;
+}
+
+/**
+ * Registration
+ */
+void RMGfxTask::Register() {
+ _nInList++;
+}
+
+void RMGfxTask::Unregister() {
+ _nInList--;
+ assert(_nInList >= 0);
+}
+
+/****************************************************************************\
+* RMGfxTaskSetPrior Methods
+\****************************************************************************/
+
+void RMGfxTaskSetPrior::setPriority(int nPrior) {
+ _nPrior = nPrior;
+}
+
+
+/****************************************************************************\
+* RMGfxBuffer Methods
+\****************************************************************************/
+
+RMGfxBuffer::RMGfxBuffer() {
+ _dimx = _dimy = 0;
+ _origBuf = _buf = NULL;
+}
+
+RMGfxBuffer::~RMGfxBuffer() {
+ destroy();
+}
+
+void RMGfxBuffer::create(int dimx, int dimy, int nBpp) {
+ // Destroy the buffer it is already exists
+ if (_buf != NULL)
+ destroy();
+
+ // Copy the parameters in the private members
+ _dimx = dimx;
+ _dimy = dimy;
+
+ // Allocate a buffer
+ _origBuf = _buf = new byte[_dimx * _dimy * nBpp / 8];
+ assert(_buf != NULL);
+ Common::fill(_origBuf, _origBuf + _dimx * _dimy * nBpp / 8, 0);
+}
+
+void RMGfxBuffer::destroy() {
+ if (_origBuf != NULL && _origBuf == _buf) {
+ delete[] _origBuf;
+ _origBuf = _buf = NULL;
+ }
+}
+
+void RMGfxBuffer::offsetY(int nLines, int nBpp) {
+ _buf += nLines * getDimx() * nBpp / 8;
+}
+
+
+RMGfxBuffer::operator byte *() {
+ return _buf;
+}
+
+RMGfxBuffer::operator void *() {
+ return (void *)_buf;
+}
+
+RMGfxBuffer::RMGfxBuffer(int dimx, int dimy, int nBpp) {
+ create(dimx, dimy, nBpp);
+}
+
+int RMGfxBuffer::getDimx() {
+ return _dimx;
+}
+
+int RMGfxBuffer::getDimy() {
+ return _dimy;
+}
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer Methods
+\****************************************************************************/
+
+int RMGfxSourceBuffer::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) {
+ create(dimx, dimy, getBpp());
+ memcpy(_buf, buf, dimx * dimy * getBpp() / 8);
+
+ // Invokes the method for preparing the surface (inherited)
+ prepareImage();
+
+ return dimx * dimy * getBpp() / 8;
+}
+
+void RMGfxSourceBuffer::init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette) {
+ create(dimx, dimy, getBpp());
+ ds.read(_buf, dimx * dimy * getBpp() / 8);
+
+ // Invokes the method for preparing the surface (inherited)
+ prepareImage();
+}
+
+RMGfxSourceBuffer::~RMGfxSourceBuffer() {
+}
+
+void RMGfxSourceBuffer::prepareImage() {
+ // Do nothing. Can be overloaded if necessary
+}
+
+bool RMGfxSourceBuffer::clip2D(int &x1, int &y1, int &u, int &v, int &width, int &height, bool bUseSrc, RMGfxTargetBuffer *buf) {
+ int destw, desth;
+
+ destw = buf->getDimx();
+ desth = buf->getDimy();
+
+ if (!bUseSrc) {
+ u = v = 0;
+ width = _dimx;
+ height = _dimy;
+ }
+
+ if (x1 > destw - 1)
+ return false;
+
+ if (y1 > desth - 1)
+ return false;
+
+ if (x1 < 0) {
+ width += x1;
+ if (width < 0)
+ return false;
+ u -= x1;
+ x1 = 0;
+ }
+
+ if (y1 < 0) {
+ height += y1;
+ if (height < 0)
+ return false;
+ v -= y1;
+ y1 = 0;
+ }
+
+ if (x1 + width - 1 > destw - 1)
+ width = destw - x1;
+
+ if (y1 + height - 1 > desth - 1)
+ height = desth - y1;
+
+ return (width > 1 && height > 1);
+}
+
+/**
+ * Initializes a surface by resource Id
+ *
+ * @param resID Resource ID
+ * @param dimx Buffer X dimension
+ * @param dimy Buffer Y dimension
+ */
+int RMGfxSourceBuffer::init(uint32 resID, int dimx, int dimy, bool bLoadPalette) {
+ return init(RMRes(resID), dimx, dimy, bLoadPalette);
+}
+
+void RMGfxSourceBuffer::offsetY(int nLines) {
+ RMGfxBuffer::offsetY(nLines, getBpp());
+}
+
+/****************************************************************************\
+* RMGfxWoodyBuffer Methods
+\****************************************************************************/
+
+RMGfxWoodyBuffer::~RMGfxWoodyBuffer() {
+
+}
+
+void RMGfxWoodyBuffer::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // Draw the OT list
+ CORO_INVOKE_0(drawOT);
+
+ // Draw itself into the target buffer
+ CORO_INVOKE_2(RMGfxSourceBuffer16::draw, bigBuf, prim);
+
+ CORO_END_CODE;
+}
+
+RMGfxWoodyBuffer::RMGfxWoodyBuffer() {
+
+}
+
+RMGfxWoodyBuffer::RMGfxWoodyBuffer(int dimx, int dimy)
+ : RMGfxBuffer(dimx, dimy, 16) {
+}
+
+/****************************************************************************\
+* RMGfxTargetBuffer Methods
+\****************************************************************************/
+
+RMGfxTargetBuffer::RMGfxTargetBuffer() {
+ _otlist = NULL;
+ _otSize = 0;
+ _trackDirtyRects = false;
+}
+
+RMGfxTargetBuffer::~RMGfxTargetBuffer() {
+ clearOT();
+}
+
+void RMGfxTargetBuffer::clearOT() {
+ OTList *cur, *n;
+
+ cur = _otlist;
+
+ while (cur != NULL) {
+ cur->_prim->_task->Unregister();
+ delete cur->_prim;
+ n = cur->_next;
+ delete cur;
+ cur = n;
+ }
+
+ _otlist = NULL;
+}
+
+void RMGfxTargetBuffer::drawOT(CORO_PARAM) {
+ CORO_BEGIN_CONTEXT;
+ OTList *cur;
+ OTList *prev;
+ OTList *next;
+ RMGfxPrimitive *myprim;
+ bool result;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ _ctx->prev = NULL;
+ _ctx->cur = _otlist;
+
+ while (_ctx->cur != NULL) {
+ // Call the task Draw method, passing it a copy of the original
+ _ctx->myprim = _ctx->cur->_prim->duplicate();
+ CORO_INVOKE_2(_ctx->cur->_prim->_task->draw, *this, _ctx->myprim);
+ delete _ctx->myprim;
+
+ // Check if it's time to remove the task from the OT list
+ CORO_INVOKE_1(_ctx->cur->_prim->_task->removeThis, _ctx->result);
+ if (_ctx->result) {
+ // De-register the task
+ _ctx->cur->_prim->_task->Unregister();
+
+ // Delete task, freeing the memory
+ delete _ctx->cur->_prim;
+ _ctx->next = _ctx->cur->_next;
+ delete _ctx->cur;
+
+ // If it was the first item, update the list head
+ if (_ctx->prev == NULL)
+ _otlist = _ctx->next;
+ // Otherwise update the next pinter of the previous item
+ else
+ _ctx->prev->_next = _ctx->next;
+
+ _ctx->cur = _ctx->next;
+ } else {
+ // Update the pointer to the previous item, and the current to the next
+ _ctx->prev = _ctx->cur;
+ _ctx->cur = _ctx->cur->_next;
+ }
+ }
+
+ CORO_END_CODE;
+}
+
+void RMGfxTargetBuffer::addPrim(RMGfxPrimitive *prim) {
+ int nPrior;
+ OTList *cur, *n;
+
+ // Warn of the OT listing
+ prim->_task->Register();
+
+ // Check the priority
+ nPrior = prim->_task->priority();
+ n = new OTList(prim);
+
+ // Empty list
+ if (_otlist == NULL) {
+ _otlist = n;
+ _otlist->_next = NULL;
+ }
+ // Inclusion in the head
+ else if (nPrior < _otlist->_prim->_task->priority()) {
+ n->_next = _otlist;
+ _otlist = n;
+ } else {
+ cur = _otlist;
+ while (cur->_next != NULL && nPrior > cur->_next->_prim->_task->priority())
+ cur = cur->_next;
+
+ n->_next = cur->_next;
+ cur->_next = n;
+ }
+}
+
+void RMGfxTargetBuffer::addDirtyRect(const Common::Rect &r) {
+ assert(r.isValidRect());
+ if (_trackDirtyRects && r.width() > 0 && r.height() > 0)
+ _currentDirtyRects.push_back(r);
+}
+
+Common::List<Common::Rect> &RMGfxTargetBuffer::getDirtyRects() {
+ // Copy rects from both the current and previous frame into the output dirty rects list
+ Common::List<Common::Rect>::iterator i;
+ _dirtyRects.clear();
+ for (i = _previousDirtyRects.begin(); i != _previousDirtyRects.end(); ++i)
+ _dirtyRects.push_back(*i);
+ for (i = _currentDirtyRects.begin(); i != _currentDirtyRects.end(); ++i)
+ _dirtyRects.push_back(*i);
+
+ mergeDirtyRects();
+ return _dirtyRects;
+}
+
+/**
+ * Move the set of dirty rects from the finished current frame into the previous frame list.
+ */
+void RMGfxTargetBuffer::clearDirtyRects() {
+ Common::List<Common::Rect>::iterator i;
+ _previousDirtyRects.clear();
+ for (i = _currentDirtyRects.begin(); i != _currentDirtyRects.end(); ++i)
+ _previousDirtyRects.push_back(*i);
+
+ _currentDirtyRects.clear();
+}
+
+/**
+ * Merges any clipping rectangles that overlap to try and reduce
+ * the total number of clip rectangles.
+ */
+void RMGfxTargetBuffer::mergeDirtyRects() {
+ if (_dirtyRects.size() <= 1)
+ return;
+
+ Common::List<Common::Rect>::iterator rOuter, rInner;
+
+ for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
+ rInner = rOuter;
+ while (++rInner != _dirtyRects.end()) {
+
+ if ((*rOuter).intersects(*rInner)) {
+ // these two rectangles overlap or
+ // are next to each other - merge them
+
+ (*rOuter).extend(*rInner);
+
+ // remove the inner rect from the list
+ _dirtyRects.erase(rInner);
+
+ // move back to beginning of list
+ rInner = rOuter;
+ }
+ }
+ }
+}
+
+uint16 *RMGfxTargetBuffer::_precalcTable = NULL;
+
+/**
+ * Set up the black & white precalculated mapping table. This is only
+ * called if the user selects the black & white option.
+ */
+void RMGfxTargetBuffer::createBWPrecalcTable() {
+ _precalcTable = new uint16[0x8000];
+
+ for (int i = 0; i < 0x8000; i++) {
+ int r = (i >> 10) & 0x1F;
+ int g = (i >> 5) & 0x1F;
+ int b = i & 0x1F;
+
+ int min = MIN(r, MIN(g, b));
+ int max = MAX(r, MAX(g, b));
+
+ min = (min + max) / 2;
+
+ r = CLIP(min + 8 - 8, 0, 31);
+ g = CLIP(min + 5 - 8, 0, 31);
+ b = CLIP(min + 0 - 8, 0, 31);
+
+ _precalcTable[i] = (r << 10) | (g << 5) | b;
+ }
+}
+
+/**
+ * Frees the black & white precalculated mapping table.
+ */
+void RMGfxTargetBuffer::freeBWPrecalcTable() {
+ delete[] _precalcTable;
+ _precalcTable = NULL;
+}
+
+RMGfxTargetBuffer::operator byte *() {
+ return _buf;
+}
+
+RMGfxTargetBuffer::operator void *() {
+ return (void *)_buf;
+}
+
+RMGfxTargetBuffer::operator uint16 *() {
+ // FIXME: This may not be endian safe
+ return (uint16 *)_buf;
+}
+
+/**
+ * Offseting buffer
+ */
+void RMGfxTargetBuffer::offsetY(int nLines) {
+ RMGfxBuffer::offsetY(nLines, 16);
+}
+
+void RMGfxTargetBuffer::setTrackDirtyRects(bool v) {
+ _trackDirtyRects = v;
+}
+
+bool RMGfxTargetBuffer::getTrackDirtyRects() const {
+ return _trackDirtyRects;
+}
+
+/****************************************************************************\
+* RMGfxSourceBufferPal Methods
+\****************************************************************************/
+
+RMGfxSourceBufferPal::~RMGfxSourceBufferPal() {
+
+}
+
+int RMGfxSourceBufferPal::loadPaletteWA(const byte *buf, bool bSwapped) {
+ if (bSwapped) {
+ for (int i = 0; i < (1 << getBpp()); i++) {
+ _pal[i * 3 + 0] = buf[i * 3 + 2];
+ _pal[i * 3 + 1] = buf[i * 3 + 1];
+ _pal[i * 3 + 2] = buf[i * 3 + 0];
+ }
+ } else {
+ memcpy(_pal, buf, (1 << getBpp()) * 3);
+ }
+
+ preparePalette();
+
+ return (1 << getBpp()) * 3;
+}
+
+int RMGfxSourceBufferPal::loadPalette(const byte *buf) {
+ int i;
+
+ for (i = 0; i < 256; i++)
+ memcpy(_pal + i * 3, buf + i * 4, 3);
+
+ preparePalette();
+
+ return (1 << getBpp()) * 4;
+}
+
+void RMGfxSourceBufferPal::preparePalette() {
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ _palFinal[i] = (((int)_pal[i * 3 + 0] >> 3) << 10) |
+ (((int)_pal[i * 3 + 1] >> 3) << 5) |
+ (((int)_pal[i * 3 + 2] >> 3) << 0);
+ }
+}
+
+int RMGfxSourceBufferPal::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) {
+ int read;
+
+ // Load the RAW image
+ read = RMGfxSourceBuffer::init(buf, dimx, dimy);
+
+ // Load the palette if necessary
+ if (bLoadPalette)
+ read += loadPaletteWA(&buf[read]);
+
+ return read;
+}
+
+void RMGfxSourceBufferPal::init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette) {
+ // Load the RAW image
+ RMGfxSourceBuffer::init(ds, dimx, dimy);
+
+ // Load the palette if necessary
+ if (bLoadPalette) {
+ byte *suxpal = new byte[256 * 3];
+ ds.read(suxpal, 256 * 3);
+ loadPaletteWA(suxpal);
+ delete[] suxpal;
+ }
+}
+
+int RMGfxSourceBufferPal::loadPalette(uint32 resID) {
+ return loadPalette(RMRes(resID));
+}
+
+int RMGfxSourceBufferPal::loadPaletteWA(uint32 resID, bool bSwapped) {
+ return loadPaletteWA(RMRes(resID), bSwapped);
+}
+
+/****************************************************************************\
+* RMGfxSourceBuffer4 Methods
+\****************************************************************************/
+
+void RMGfxSourceBuffer4::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+}
+
+RMGfxSourceBuffer4::RMGfxSourceBuffer4(int dimx, int dimy)
+ : RMGfxBuffer(dimx, dimy, 4) {
+ setPriority(0);
+}
+
+
+/**
+ * Returns the number of bits per pixel of the surface
+ *
+ * @returns Bit per pixel
+ */
+int RMGfxSourceBuffer4::getBpp() {
+ return 4;
+}
+
+void RMGfxSourceBuffer4::create(int dimx, int dimy) {
+ RMGfxBuffer::create(dimx, dimy, 4);
+}
+
+/****************************************************************************\
+* RMGfxSourceBuffer8 Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer8::~RMGfxSourceBuffer8() {
+
+}
+
+void RMGfxSourceBuffer8::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ int x, y, width, height, u, v;
+ int bufx = bigBuf.getDimx();
+ uint16 *buf = bigBuf;
+ byte *raw = _buf;
+
+ // Destination buffer
+ RMRect dst;
+ if (prim->haveDst())
+ dst = prim->getDst();
+
+ // Clipping
+ if (prim->haveSrc()) {
+ u = prim->getSrc()._x1;
+ v = prim->getSrc()._y1;
+
+ width = prim->getSrc().width();
+ height = prim->getSrc().height();
+ }
+
+ if (!clip2D(dst._x1, dst._y1, u, v, width, height, prim->haveSrc(), &bigBuf))
+ return;
+
+ // Starting offset into the buffer
+ buf += dst._y1 * bufx + dst._x1;
+
+ // Normal step
+ if (_bTrasp0) {
+ for (y = 0; y < height; y++) {
+ raw = _buf + (y + v) * _dimx + u;
+
+ for (x = 0; x < width; x++) {
+ if (*raw)
+ *buf = _palFinal[*raw];
+ buf++;
+ raw++;
+ }
+
+ buf += bufx - width;
+ }
+ } else {
+ for (y = 0; y < height; y++) {
+ raw = _buf + (y + v) * _dimx + u;
+
+ for (x = 0; x < width; x += 2) {
+ buf[0] = _palFinal[raw[0]];
+ buf[1] = _palFinal[raw[1]];
+
+ buf += 2;
+ raw += 2;
+ }
+
+ buf += bufx - width;
+ }
+ }
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(dst._x1, dst._y1, dst._x1 + width, dst._y1 + height));
+}
+
+RMGfxSourceBuffer8::RMGfxSourceBuffer8(int dimx, int dimy)
+ : RMGfxBuffer(dimx, dimy, 8) {
+ setPriority(0);
+ _bTrasp0 = false;
+}
+
+RMGfxSourceBuffer8::RMGfxSourceBuffer8(bool bTrasp0) {
+ _bTrasp0 = bTrasp0;
+}
+
+
+/**
+ * Returns the number of bits per pixel of the surface
+ *
+ * @returns Bit per pixel
+ */
+int RMGfxSourceBuffer8::getBpp() {
+ return 8;
+}
+
+void RMGfxSourceBuffer8::create(int dimx, int dimy) {
+ RMGfxBuffer::create(dimx, dimy, 8);
+}
+
+#define GETRED(x) (((x) >> 10) & 0x1F)
+#define GETGREEN(x) (((x) >> 5) & 0x1F)
+#define GETBLUE(x) ((x) & 0x1F)
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer8AB Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer8AB::~RMGfxSourceBuffer8AB() {
+
+}
+
+int RMGfxSourceBuffer8AB::calcTrasp(int fore, int back) {
+ int r, g, b;
+
+ r = (GETRED(fore) >> 2) + (GETRED(back) >> 1);
+ g = (GETGREEN(fore) >> 2) + (GETGREEN(back) >> 1);
+ b = (GETBLUE(fore) >> 2) + (GETBLUE(back) >> 1);
+
+ if (r > 0x1F)
+ r = 0x1F;
+
+ if (g > 0x1F)
+ g = 0x1F;
+
+ if (b > 0x1F)
+ b = 0x1F;
+
+ return (r << 10) | (g << 5) | b;
+}
+
+
+void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ int x, y, width, height, u, v;
+ int bufx = bigBuf.getDimx();
+ uint16 *buf = bigBuf;
+ byte *raw = _buf;
+
+ // Destination buffer
+ RMRect dst;
+ if (prim->haveDst())
+ dst = prim->getDst();
+
+ // Clipping
+ if (prim->haveSrc()) {
+ u = prim->getSrc()._x1;
+ v = prim->getSrc()._y1;
+
+ width = prim->getSrc().width();
+ height = prim->getSrc().height();
+ }
+
+ if (!clip2D(dst._x1, dst._y1, u, v, width, height, prim->haveSrc(), &bigBuf))
+ return;
+
+ // Starting offset into the buffer
+ buf += dst._y1 * bufx + dst._x1;
+
+ // Passaggio normale
+ if (_bTrasp0) {
+ for (y = 0; y < height; y++) {
+ raw = _buf + (y + v) * _dimx + u;
+
+ for (x = 0; x < width; x++) {
+ if (*raw)
+ *buf = calcTrasp(_palFinal[*raw], *buf);
+
+ buf++;
+ raw++;
+ }
+
+ buf += bufx - width;
+ }
+ } else {
+ for (y = 0; y < height; y++) {
+ raw = _buf + (y + v) * _dimx + u;
+
+ for (x = 0; x < width; x += 2) {
+ buf[0] = calcTrasp(_palFinal[raw[0]], buf[0]);
+ buf[1] = calcTrasp(_palFinal[raw[1]], buf[1]);
+
+ buf += 2;
+ raw += 2;
+ }
+
+ buf += bufx - width;
+ }
+ }
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(dst._x1, dst._y1, dst._x1 + width, dst._y1 + height));
+}
+
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer8RLE Methods
+\****************************************************************************/
+
+byte RMGfxSourceBuffer8RLE::_megaRLEBuf[512 * 1024];
+
+void RMGfxSourceBuffer8RLE::setAlphaBlendColor(int color) {
+ _alphaBlendColor = color;
+}
+
+RMGfxSourceBuffer8RLE::RMGfxSourceBuffer8RLE() {
+ _alphaBlendColor = -1;
+ _bNeedRLECompress = true;
+ _buf = NULL;
+
+ _alphaR = _alphaG = _alphaB = 0;
+}
+
+RMGfxSourceBuffer8RLE::~RMGfxSourceBuffer8RLE() {
+ if (_buf != NULL) {
+ delete[] _buf;
+ _buf = NULL;
+ }
+}
+
+
+int RMGfxSourceBuffer8RLE::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) {
+ return RMGfxSourceBufferPal::init(buf, dimx, dimy, bLoadPalette);
+}
+
+void RMGfxSourceBuffer8RLE::init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette) {
+ if (_bNeedRLECompress) {
+ RMGfxSourceBufferPal::init(ds, dimx, dimy, bLoadPalette);
+ } else {
+ int size;
+
+ size = ds.readSint32LE();
+ _buf = new byte[size];
+ ds.read(_buf, size);
+
+ _dimx = dimx;
+ _dimy = dimy;
+ }
+}
+
+void RMGfxSourceBuffer8RLE::preparePalette() {
+ // Invoke the parent method
+ RMGfxSourceBuffer8::preparePalette();
+
+ // Handle RGB alpha blending
+ if (_alphaBlendColor != -1) {
+ _alphaR = (_palFinal[_alphaBlendColor] >> 10) & 0x1F;
+ _alphaG = (_palFinal[_alphaBlendColor] >> 5) & 0x1F;
+ _alphaB = (_palFinal[_alphaBlendColor]) & 0x1F;
+ }
+}
+
+void RMGfxSourceBuffer8RLE::prepareImage() {
+ // Invoke the parent method
+ RMGfxSourceBuffer::prepareImage();
+
+ // Compress
+ compressRLE();
+}
+
+void RMGfxSourceBuffer8RLE::setAlreadyCompressed() {
+ _bNeedRLECompress = false;
+}
+
+void RMGfxSourceBuffer8RLE::compressRLE() {
+ int x, y;
+ byte *startline;
+ byte *cur;
+ byte curdata;
+ byte *src;
+ byte *startsrc;
+ int rep;
+
+ // Perform RLE compression for lines
+ cur = _megaRLEBuf;
+ src = _buf;
+ for (y = 0; y < _dimy; y++) {
+ // Save the beginning of the line
+ startline = cur;
+
+ // Leave space for the length of the line
+ cur += 2;
+
+ // It starts from the empty space
+ curdata = 0;
+ rep = 0;
+ startsrc = src;
+ for (x = 0; x < _dimx;) {
+ if ((curdata == 0 && *src == 0) || (curdata == 1 && *src == _alphaBlendColor)
+ || (curdata == 2 && (*src != _alphaBlendColor && *src != 0))) {
+ src++;
+ rep++;
+ x++;
+ } else {
+ if (curdata == 0) {
+ RLEWriteTrasp(cur, rep);
+ curdata++;
+ } else if (curdata == 1) {
+ RLEWriteAlphaBlend(cur, rep);
+ curdata++;
+ } else {
+ RLEWriteData(cur, rep, startsrc);
+ curdata = 0;
+ }
+
+ rep = 0;
+ startsrc = src;
+ }
+ }
+
+ // Pending data?
+ if (curdata == 1) {
+ RLEWriteAlphaBlend(cur, rep);
+ RLEWriteData(cur, 0, NULL);
+ }
+
+ if (curdata == 2) {
+ RLEWriteData(cur, rep, startsrc);
+ }
+
+ // End of line
+ RLEWriteEOL(cur);
+
+ // Write the length of the line
+ WRITE_LE_UINT16(startline, (uint16)(cur - startline));
+ }
+
+ // Delete the original image
+ delete[] _buf;
+
+ // Copy the compressed image
+ x = cur - _megaRLEBuf;
+ _buf = new byte[x];
+ Common::copy(_megaRLEBuf, _megaRLEBuf + x, _buf);
+}
+
+void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ int y;
+ byte *src;
+ uint16 *buf = bigBuf;
+ int x1, y1, u, v, width, height;
+
+ // Clipping
+ x1 = prim->getDst()._x1;
+ y1 = prim->getDst()._y1;
+ if (!clip2D(x1, y1, u, v, width, height, false, &bigBuf))
+ return;
+
+ // Go forward through the RLE lines
+ src = _buf;
+ for (y = 0; y < v; y++)
+ src += READ_LE_UINT16(src);
+
+ // Calculate the position in the destination buffer
+ buf += y1 * bigBuf.getDimx();
+
+ // Loop
+ if (prim->isFlipped()) {
+// Eliminate horizontal clipping
+// width = m_dimx;
+// x1=prim->Dst().x1;
+
+ // Clipping
+ u = _dimx - (width + u);
+ x1 = (prim->getDst()._x1 + _dimx - 1) - u;
+
+ if (width > x1)
+ width = x1;
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1 - width, y1, x1 + 1, y1 + height));
+
+ for (y = 0; y < height; y++) {
+ // Decompression
+ RLEDecompressLineFlipped(buf + x1, src + 2, u, width);
+
+ // Next line
+ src += READ_LE_UINT16(src);
+
+ // Skip to the next line
+ buf += bigBuf.getDimx();
+ }
+ } else {
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + width, y1 + height));
+
+ for (y = 0; y < height; y++) {
+ // Decompression
+ RLEDecompressLine(buf + x1, src + 2, u, width);
+
+ // Next line
+ src += READ_LE_UINT16(src);
+
+ // Skip to the next line
+ buf += bigBuf.getDimx();
+ }
+ }
+}
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer8RLEByte Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer8RLEByte::~RMGfxSourceBuffer8RLEByte() {
+
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEWriteTrasp(byte *&cur, int rep) {
+ assert(rep < 255);
+ *cur ++ = rep;
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEWriteAlphaBlend(byte *&cur, int rep) {
+ assert(rep < 255);
+ *cur ++ = rep;
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEWriteData(byte *&cur, int rep, byte *src) {
+ assert(rep < 256);
+
+ *cur ++ = rep;
+ if (rep > 0) {
+ memcpy(cur, src, rep);
+ cur += rep;
+ src += rep;
+ }
+
+ return;
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEWriteEOL(byte *&cur) {
+ *cur ++ = 0xFF;
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int i, n;
+ int r, g, b;
+
+ if (nStartSkip == 0)
+ goto RLEByteDoTrasp;
+
+ while (1) {
+ assert(nStartSkip > 0);
+
+ // TRASP
+ n = *src++;
+ if (n == 0xFF)
+ return;
+
+ if (n >= nStartSkip) {
+ dst += n - nStartSkip;
+ nLength -= n - nStartSkip;
+ if (nLength > 0)
+ goto RLEByteDoAlpha;
+ else
+ return;
+ }
+ nStartSkip -= n;
+
+
+ assert(nStartSkip > 0);
+
+ // ALPHA
+ n = *src++;
+ if (n >= nStartSkip) {
+ n -= nStartSkip;
+ goto RLEByteDoAlpha2;
+ }
+ nStartSkip -= n;
+
+ assert(nStartSkip > 0);
+
+ // DATA
+ n = *src++;
+ if (n >= nStartSkip) {
+ src += nStartSkip;
+ n -= nStartSkip;
+ goto RLEByteDoCopy2;
+ }
+ nStartSkip -= n;
+ src += n;
+ }
+
+
+ while (1) {
+RLEByteDoTrasp:
+ // Get the trasp of s**t
+ n = *src++;
+
+ // EOL?
+ if (n == 0xFF)
+ return;
+
+ dst += n;
+ nLength -= n;
+ if (nLength <= 0)
+ return;
+
+RLEByteDoAlpha:
+ // Alpha
+ n = *src++;
+
+RLEByteDoAlpha2:
+ if (n > nLength)
+ n = nLength;
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r = (r >> 2) + (_alphaR >> 1);
+ g = (g >> 2) + (_alphaG >> 1);
+ b = (b >> 2) + (_alphaB >> 1);
+
+ *dst ++ = (r << 10) | (g << 5) | b;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+ assert(nLength > 0);
+
+//RLEByteDoCopy:
+ // Copy the stuff
+ n = *src++;
+
+RLEByteDoCopy2:
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++)
+ *dst ++ = _palFinal[*src++];
+
+ nLength -= n;
+ if (!nLength)
+ return;
+ assert(nLength > 0);
+ }
+}
+
+void RMGfxSourceBuffer8RLEByte::RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int i, n;
+ int r, g, b;
+
+ if (nStartSkip == 0)
+ goto RLEByteFlippedDoTrasp;
+
+ while (1) {
+ assert(nStartSkip > 0);
+
+ // TRASP
+ n = *src++;
+ if (n == 0xFF)
+ return;
+
+ if (n >= nStartSkip) {
+ dst -= n - nStartSkip;
+ nLength -= n - nStartSkip;
+ if (nLength > 0)
+ goto RLEByteFlippedDoAlpha;
+ else
+ return;
+ }
+ nStartSkip -= n;
+
+
+ assert(nStartSkip > 0);
+
+ // ALPHA
+ n = *src++;
+ if (n >= nStartSkip) {
+ n -= nStartSkip;
+ goto RLEByteFlippedDoAlpha2;
+ }
+ nStartSkip -= n;
+
+ assert(nStartSkip > 0);
+
+ // DATA
+ n = *src++;
+ if (n >= nStartSkip) {
+ src += nStartSkip;
+ n -= nStartSkip;
+ goto RLEByteFlippedDoCopy2;
+ }
+ nStartSkip -= n;
+ src += n;
+ }
+
+
+ while (1) {
+RLEByteFlippedDoTrasp:
+ // Get the trasp of s**t
+ n = *src++;
+
+ // EOL?
+ if (n == 0xFF)
+ return;
+
+ dst -= n;
+ nLength -= n;
+ if (nLength <= 0)
+ return;
+
+RLEByteFlippedDoAlpha:
+ // Alpha
+ n = *src++;
+
+RLEByteFlippedDoAlpha2:
+ if (n > nLength)
+ n = nLength;
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r = (r >> 2) + (_alphaR >> 1);
+ g = (g >> 2) + (_alphaG >> 1);
+ b = (b >> 2) + (_alphaB >> 1);
+
+ *dst-- = (r << 10) | (g << 5) | b;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+ assert(nLength > 0);
+
+//RLEByteFlippedDoCopy:
+ // Copy the data
+ n = *src++;
+
+RLEByteFlippedDoCopy2:
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++)
+ *dst-- = _palFinal[*src++];
+
+ nLength -= n;
+ if (!nLength)
+ return;
+ assert(nLength > 0);
+ }
+}
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer8RLEWord Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer8RLEWord::~RMGfxSourceBuffer8RLEWord() {
+
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEWriteTrasp(byte *&cur, int rep) {
+ WRITE_LE_UINT16(cur, rep);
+ cur += 2;
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEWriteAlphaBlend(byte *&cur, int rep) {
+ WRITE_LE_UINT16(cur, rep);
+ cur += 2;
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEWriteData(byte *&cur, int rep, byte *src) {
+ WRITE_LE_UINT16(cur, rep);
+ cur += 2;
+
+ if (rep > 0) {
+ memcpy(cur, src, rep);
+ cur += rep;
+ src += rep;
+ }
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEWriteEOL(byte *&cur) {
+ *cur ++ = 0xFF;
+ *cur ++ = 0xFF;
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int i, n;
+ int r, g, b;
+
+ if (nStartSkip == 0)
+ goto RLEWordDoTrasp;
+
+ while (1) {
+ assert(nStartSkip > 0);
+
+ // TRASP
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n == 0xFFFF)
+ return;
+
+ if (n >= nStartSkip) {
+ dst += n - nStartSkip;
+ nLength -= n - nStartSkip;
+
+ if (nLength > 0)
+ goto RLEWordDoAlpha;
+ else
+ return;
+ }
+ nStartSkip -= n;
+
+ assert(nStartSkip > 0);
+
+ // ALPHA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ n -= nStartSkip;
+ goto RLEWordDoAlpha2;
+ }
+ nStartSkip -= n;
+
+ // DATA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ src += nStartSkip;
+ n -= nStartSkip;
+ goto RLEWordDoCopy2;
+ }
+ nStartSkip -= n;
+ src += n;
+ }
+
+
+ while (1) {
+RLEWordDoTrasp:
+ // Get the trasp of s**t
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ // EOL?
+ if (n == 0xFFFF)
+ return;
+
+ dst += n;
+
+ nLength -= n;
+ if (nLength <= 0)
+ return;
+
+RLEWordDoAlpha:
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordDoAlpha2:
+
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r = (r >> 2) + (_alphaR >> 1);
+ g = (g >> 2) + (_alphaG >> 1);
+ b = (b >> 2) + (_alphaB >> 1);
+
+ *dst++ = (r << 10) | (g << 5) | b;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+
+//RLEWordDoCopy:
+ // Copy the data
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordDoCopy2:
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++)
+ *dst++ = _palFinal[*src++];
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+
+ }
+}
+
+void RMGfxSourceBuffer8RLEWord::RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int i, n;
+ int r, g, b;
+
+ if (nStartSkip == 0)
+ goto RLEWordFlippedDoTrasp;
+
+ while (1) {
+ assert(nStartSkip > 0);
+
+ // TRASP
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n == 0xFFFF)
+ return;
+
+ if (n >= nStartSkip) {
+ dst -= n - nStartSkip;
+ nLength -= n - nStartSkip;
+
+ if (nLength > 0)
+ goto RLEWordFlippedDoAlpha;
+ else
+ return;
+ }
+ nStartSkip -= n;
+
+ assert(nStartSkip > 0);
+
+ // ALPHA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ n -= nStartSkip;
+ goto RLEWordFlippedDoAlpha2;
+ }
+ nStartSkip -= n;
+
+ // DATA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ src += nStartSkip;
+ n -= nStartSkip;
+ goto RLEWordFlippedDoCopy2;
+ }
+ nStartSkip -= n;
+ src += n;
+ }
+
+
+ while (1) {
+RLEWordFlippedDoTrasp:
+ // Get the trasp of s**t
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ // EOL?
+ if (n == 0xFFFF)
+ return;
+
+ dst -= n;
+
+ nLength -= n;
+ if (nLength <= 0)
+ return;
+
+RLEWordFlippedDoAlpha:
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordFlippedDoAlpha2:
+
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r = (r >> 2) + (_alphaR >> 1);
+ g = (g >> 2) + (_alphaG >> 1);
+ b = (b >> 2) + (_alphaB >> 1);
+
+ *dst-- = (r << 10) | (g << 5) | b;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+
+//RLEWordFlippedDoCopy:
+ // Copy the data
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordFlippedDoCopy2:
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++)
+ *dst-- = _palFinal[*src++];
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+ }
+}
+
+/****************************************************************************\
+* Methods for RMGfxSourceBuffer8RLEWord
+\****************************************************************************/
+
+RMGfxSourceBuffer8RLEWordAB::~RMGfxSourceBuffer8RLEWordAB() {
+
+}
+
+void RMGfxSourceBuffer8RLEWordAB::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int i, n;
+ int r, g, b, r2, g2, b2;
+
+ if (!GLOBALS._bCfgTransparence) {
+ RMGfxSourceBuffer8RLEWord::RLEDecompressLine(dst, src, nStartSkip, nLength);
+ return;
+ }
+
+ if (nStartSkip == 0)
+ goto RLEWordDoTrasp;
+
+ while (1) {
+ assert(nStartSkip > 0);
+
+ // TRASP
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n == 0xFFFF)
+ return;
+
+ if (n >= nStartSkip) {
+ dst += n - nStartSkip;
+ nLength -= n - nStartSkip;
+
+ if (nLength > 0)
+ goto RLEWordDoAlpha;
+ else
+ return;
+ }
+ nStartSkip -= n;
+
+ assert(nStartSkip > 0);
+
+ // ALPHA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ n -= nStartSkip;
+ goto RLEWordDoAlpha2;
+ }
+ nStartSkip -= n;
+
+ // DATA
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ if (n >= nStartSkip) {
+ src += nStartSkip;
+ n -= nStartSkip;
+ goto RLEWordDoCopy2;
+ }
+ nStartSkip -= n;
+ src += n;
+ }
+
+
+ while (1) {
+RLEWordDoTrasp:
+ // Get the trasp of s**t
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+ // EOL?
+ if (n == 0xFFFF)
+ return;
+
+ dst += n;
+
+ nLength -= n;
+ if (nLength <= 0)
+ return;
+
+RLEWordDoAlpha:
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordDoAlpha2:
+
+ if (n > nLength)
+ n = nLength;
+
+ // @@@ SHOULD NOT BE THERE !!!!!
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r = (r >> 2) + (_alphaR >> 1);
+ g = (g >> 2) + (_alphaG >> 1);
+ b = (b >> 2) + (_alphaB >> 1);
+
+ *dst++ = (r << 10) | (g << 5) | b;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+
+//RLEWordDoCopy:
+ // Copy the data
+ n = READ_LE_UINT16(src);
+ src += 2;
+
+RLEWordDoCopy2:
+ if (n > nLength)
+ n = nLength;
+
+ for (i = 0; i < n; i++) {
+ r = (*dst >> 10) & 0x1F;
+ g = (*dst >> 5) & 0x1F;
+ b = *dst & 0x1F;
+
+ r2 = (_palFinal[*src] >> 10) & 0x1F;
+ g2 = (_palFinal[*src] >> 5) & 0x1F;
+ b2 = _palFinal[*src] & 0x1F;
+
+ r = (r >> 1) + (r2 >> 1);
+ g = (g >> 1) + (g2 >> 1);
+ b = (b >> 1) + (b2 >> 1);
+
+ *dst ++ = (r << 10) | (g << 5) | b;
+ src++;
+ }
+
+ nLength -= n;
+ if (!nLength)
+ return;
+
+ assert(nLength > 0);
+ }
+}
+
+/****************************************************************************\
+* Methods for RMGfxSourceBuffer8AA
+\****************************************************************************/
+
+byte RMGfxSourceBuffer8AA::_megaAABuf[256 * 1024];
+byte RMGfxSourceBuffer8AA::_megaAABuf2[64 * 1024];
+
+void RMGfxSourceBuffer8AA::prepareImage() {
+ // Invoke the parent method
+ RMGfxSourceBuffer::prepareImage();
+
+ // Prepare the buffer for anti-aliasing
+ calculateAA();
+}
+
+void RMGfxSourceBuffer8AA::calculateAA() {
+ int x, y;
+ byte *src, *srcaa;
+
+ // First pass: fill the edges
+ Common::fill(_megaAABuf, _megaAABuf + _dimx * _dimy, 0);
+
+ src = _buf;
+ srcaa = _megaAABuf;
+ for (y = 0; y < _dimy; y++) {
+ for (x = 0; x < _dimx; x++) {
+ if (*src == 0) {
+ if ((y > 0 && src[-_dimx] != 0) ||
+ (y < _dimy - 1 && src[_dimx] != 0) ||
+ (x > 0 && src[-1] != 0) ||
+ (x < _dimx - 1 && src[1] != 0))
+ *srcaa = 1;
+ }
+
+ src++;
+ srcaa++;
+ }
+ }
+
+ src = _buf;
+ srcaa = _megaAABuf;
+ for (y = 0; y < _dimy; y++) {
+ for (x = 0; x < _dimx; x++) {
+ if (*src != 0) {
+ if ((y > 0 && srcaa[-_dimx] == 1) ||
+ (y < _dimy - 1 && srcaa[_dimx] == 1) ||
+ (x > 0 && srcaa[-1] == 1) ||
+ (x < _dimx - 1 && srcaa[1] == 1))
+ *srcaa = 2;
+ }
+
+ src++;
+ srcaa++;
+ }
+ }
+
+ if (_aabuf != NULL)
+ delete[] _aabuf;
+
+ _aabuf = new byte[_dimx * _dimy];
+ memcpy(_aabuf, _megaAABuf, _dimx * _dimy);
+}
+
+RMGfxSourceBuffer8AA::RMGfxSourceBuffer8AA() : RMGfxSourceBuffer8() {
+ _aabuf = NULL;
+}
+
+RMGfxSourceBuffer8AA::~RMGfxSourceBuffer8AA() {
+ if (_aabuf != NULL)
+ delete[] _aabuf;
+}
+
+void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ int x, y;
+ byte *src;
+ uint16 *mybuf;
+ uint16 *buf;
+ int x1, y1, u, v, width, height;
+ int r, g, b;
+ int step;
+
+ // Clip the sprite
+ x1 = prim->getDst()._x1;
+ y1 = prim->getDst()._y1;
+ if (!clip2D(x1, y1, u, v, width, height, false, &bigBuf))
+ return;
+
+ // Go forward through the RLE lines
+ src = _buf;
+ for (y = 0; y < v; y++)
+ src += READ_LE_UINT16(src);
+
+ // Eliminate horizontal clipping
+
+ if (prim->isFlipped()) {
+ u = _dimx - (width + u);
+ x1 = (prim->getDst()._x1 + _dimx - 1) - u;
+
+ if (width > x1)
+ width = x1;
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1 - width, y1, x1 + 1, y1 + height));
+ } else {
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + width, y1 + height));
+ }
+
+// width = _dimx;
+// x1 = prim->Dst().x1;
+
+
+ // Position into the destination buffer
+ buf = bigBuf;
+ buf += y1 * bigBuf.getDimx();
+
+ if (prim->isFlipped())
+ step = -1;
+ else
+ step = 1;
+
+ // Loop
+ buf += bigBuf.getDimx(); // Skip the first line
+ for (y = 1; y < height - 1; y++) {
+ // if (prim->IsFlipped())
+ // mybuf=&buf[x1+m_dimx-1];
+ // else
+ mybuf = &buf[x1];
+
+ for (x = 0; x < width; x++, mybuf += step) {
+ if (_aabuf[(y + v) * _dimx + x + u] == 2 && x != 0 && x != width - 1) {
+ r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
+ g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
+ b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
+
+ r += GETRED(mybuf[0]);
+ g += GETGREEN(mybuf[0]);
+ b += GETBLUE(mybuf[0]);
+
+ r /= 5;
+ g /= 5;
+ b /= 5;
+
+ if (r > 31) r = 31;
+ if (g > 31) g = 31;
+ if (b > 31) b = 31;
+
+ mybuf[0] = (r << 10) | (g << 5) | b;
+ }
+ }
+
+ // Skip to the next line
+ buf += bigBuf.getDimx();
+ }
+
+ // Position into the destination buffer
+ buf = bigBuf;
+ buf += y1 * bigBuf.getDimx();
+
+ // Looppone
+ buf += bigBuf.getDimx();
+ for (y = 1; y < height - 1; y++) {
+ // if (prim->IsFlipped())
+ // mybuf=&buf[x1+m_dimx-1];
+ // else
+ mybuf = &buf[x1];
+
+ for (x = 0; x < width; x++, mybuf += step) {
+ if (_aabuf[(y + v) * _dimx + x + u] == 1 && x != 0 && x != width - 1) {
+ r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
+ g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
+ b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
+
+ r += GETRED(mybuf[0]) * 2;
+ g += GETGREEN(mybuf[0]) * 2;
+ b += GETBLUE(mybuf[0]) * 2;
+
+ r /= 6;
+ g /= 6;
+ b /= 6;
+
+ if (r > 31) r = 31;
+ if (g > 31) g = 31;
+ if (b > 31) b = 31;
+
+ mybuf[0] = (r << 10) | (g << 5) | b;
+ }
+ }
+
+ // Skip to the next line
+ buf += bigBuf.getDimx();
+ }
+}
+
+
+
+void RMGfxSourceBuffer8AA::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ CORO_INVOKE_2(RMGfxSourceBuffer8::draw, bigBuf, prim);
+ drawAA(bigBuf, prim);
+
+ CORO_END_CODE;
+}
+
+/****************************************************************************\
+* RMGfxSourceBuffer8RLEAA Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer8RLEByteAA::~RMGfxSourceBuffer8RLEByteAA() {
+}
+
+void RMGfxSourceBuffer8RLEByteAA::prepareImage() {
+ RMGfxSourceBuffer::prepareImage();
+ calculateAA();
+ compressRLE();
+}
+
+void RMGfxSourceBuffer8RLEByteAA::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ CORO_INVOKE_2(RMGfxSourceBuffer8RLE::draw, bigBuf, prim);
+ if (GLOBALS._bCfgAntiAlias)
+ drawAA(bigBuf, prim);
+
+ CORO_END_CODE;
+}
+
+int RMGfxSourceBuffer8RLEByteAA::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) {
+ return RMGfxSourceBuffer8RLE::init(buf, dimx, dimy, bLoadPalette);
+}
+
+void RMGfxSourceBuffer8RLEByteAA::init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette) {
+ RMGfxSourceBuffer8RLE::init(ds, dimx, dimy, bLoadPalette);
+
+ if (!_bNeedRLECompress) {
+ // Load the anti-aliasing mask
+ _aabuf = new byte[dimx * dimy];
+ ds.read(_aabuf, dimx * dimy);
+ }
+}
+
+RMGfxSourceBuffer8RLEWordAA::~RMGfxSourceBuffer8RLEWordAA() {
+}
+
+void RMGfxSourceBuffer8RLEWordAA::prepareImage() {
+ RMGfxSourceBuffer::prepareImage();
+ calculateAA();
+ compressRLE();
+}
+
+void RMGfxSourceBuffer8RLEWordAA::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ CORO_INVOKE_2(RMGfxSourceBuffer8RLE::draw, bigBuf, prim);
+ if (GLOBALS._bCfgAntiAlias)
+ drawAA(bigBuf, prim);
+
+ CORO_END_CODE;
+}
+
+int RMGfxSourceBuffer8RLEWordAA::init(byte *buf, int dimx, int dimy, bool bLoadPalette) {
+ return RMGfxSourceBuffer8RLE::init(buf, dimx, dimy, bLoadPalette);
+}
+
+void RMGfxSourceBuffer8RLEWordAA::init(Common::ReadStream &ds, int dimx, int dimy, bool bLoadPalette) {
+ RMGfxSourceBuffer8RLE::init(ds, dimx, dimy, bLoadPalette);
+
+ if (!_bNeedRLECompress) {
+ // Load the anti-aliasing mask
+ _aabuf = new byte[dimx * dimy];
+ ds.read(_aabuf, dimx * dimy);
+ }
+}
+
+
+/****************************************************************************\
+* RMGfxSourceBuffer16 Methods
+\****************************************************************************/
+
+RMGfxSourceBuffer16::RMGfxSourceBuffer16(bool bTrasp0) {
+ _bTrasp0 = bTrasp0;
+}
+
+RMGfxSourceBuffer16::~RMGfxSourceBuffer16() {
+}
+
+void RMGfxSourceBuffer16::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ uint16 *buf = bigBuf;
+ uint16 *raw = (uint16 *)_buf;
+ int dimx, dimy;
+ int u, v;
+ int x1, y1;
+
+ dimx = _dimx;
+ dimy = _dimy;
+ u = 0;
+ v = 0;
+ x1 = 0;
+ y1 = 0;
+
+ if (prim->haveSrc()) {
+ u = prim->getSrc()._x1;
+ v = prim->getSrc()._y1;
+ dimx = prim->getSrc().width();
+ dimy = prim->getSrc().height();
+ }
+
+ if (prim->haveDst()) {
+ x1 = prim->getDst()._x1;
+ y1 = prim->getDst()._y1;
+ }
+
+ if (!clip2D(x1, y1, u, v, dimx, dimy, true, &bigBuf))
+ return;
+
+ raw += v * _dimx + u;
+ buf += y1 * bigBuf.getDimx() + x1;
+
+ if (_bTrasp0) {
+ for (int y = 0; y < dimy; y++) {
+ for (int x = 0; x < dimx;) {
+ while (x < dimx && raw[x] == 0)
+ x++;
+
+ while (x < dimx && raw[x] != 0) {
+ buf[x] = raw[x];
+ x++;
+ }
+ }
+
+ raw += _dimx;
+ buf += bigBuf.getDimx();
+ }
+ } else {
+ for (int y = 0; y < dimy; y++) {
+ Common::copy(raw, raw + dimx, buf);
+ buf += bigBuf.getDimx();
+ raw += _dimx;
+ }
+ }
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + dimx, y1 + dimy));
+}
+
+void RMGfxSourceBuffer16::prepareImage() {
+ // Color space conversion if necessary!
+ int i;
+ uint16 *buf = (uint16 *)_buf;
+
+ for (i = 0; i < _dimx * _dimy; i++)
+ WRITE_LE_UINT16(&buf[i], FROM_LE_16(buf[i]) & 0x7FFF);
+}
+
+RMGfxSourceBuffer16::RMGfxSourceBuffer16(int dimx, int dimy)
+ : RMGfxBuffer(dimx, dimy, 16) {
+ setPriority(0);
+ _bTrasp0 = false;
+}
+
+/**
+ * Returns the number of bits per pixel of the surface
+ *
+ * @returns Bit per pixel
+ */
+int RMGfxSourceBuffer16::getBpp() {
+ return 16;
+}
+
+void RMGfxSourceBuffer16::create(int dimx, int dimy) {
+ RMGfxBuffer::create(dimx, dimy, 16);
+}
+
+/****************************************************************************\
+* RMGfxBox Methods
+\****************************************************************************/
+
+void RMGfxBox::removeThis(CORO_PARAM, bool &result) {
+ result = true;
+}
+
+void RMGfxBox::setColor(byte r, byte g, byte b) {
+ r >>= 3;
+ g >>= 3;
+ b >>= 3;
+ _wFillColor = (r << 10) | (g << 5) | b;
+}
+
+void RMGfxBox::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
+ int i, j;
+ uint16 *buf = bigBuf;
+ RMRect rcDst;
+
+ // It takes the destination rectangle
+ rcDst = prim->getDst();
+ buf += rcDst._y1 * bigBuf.getDimx() + rcDst._x1;
+
+ // Loop through the pixels
+ for (j = 0; j < rcDst.height(); j++) {
+ for (i = 0; i < rcDst.width(); i++)
+ *buf++ = _wFillColor;
+
+ buf += bigBuf.getDimx() - rcDst.width();
+ }
+
+ // Specify the drawn area
+ bigBuf.addDirtyRect(rcDst);
+}
+
+
+/****************************************************************************\
+* RMGfxClearTask Methods
+\****************************************************************************/
+
+int RMGfxClearTask::priority() {
+ // Maximum priority (must be done first)
+ return 1;
+}
+
+void RMGfxClearTask::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *) {
+ // Clean the target buffer
+ Common::fill((byte *)bigBuf, (byte *)bigBuf + (bigBuf.getDimx() * bigBuf.getDimy() * 2), 0x0);
+ bigBuf.addDirtyRect(Common::Rect(bigBuf.getDimx(), bigBuf.getDimy()));
+}
+
+void RMGfxClearTask::removeThis(CORO_PARAM, bool &result) {
+ // The task is fine to be removed
+ result = true;
+}
+
+/****************************************************************************\
+* RMGfxPrimitive Methods
+\****************************************************************************/
+
+RMGfxPrimitive::RMGfxPrimitive() {
+ _bFlag = 0;
+ _task = NULL;
+ _src.setEmpty();
+ _dst.setEmpty();
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task) {
+ _task = task;
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMRect &dst) {
+ _task = task;
+ _src = src;
+ _dst = dst;
+ _bFlag = 0;
+ _bStretch = (src.width() != dst.width() || src.height() != dst.height());
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMPoint &src, RMRect &dst) {
+ _task = task;
+ _src.topLeft() = src;
+ _dst = dst;
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMPoint &src, RMPoint &dst) {
+ _task = task;
+ _src.topLeft() = src;
+ _dst.topLeft() = dst;
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMRect &src, RMPoint &dst) {
+ _task = task;
+ _src = src;
+ _dst.topLeft() = dst;
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMRect &dst) {
+ _task = task;
+ _dst = dst;
+ _src.setEmpty();
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::RMGfxPrimitive(RMGfxTask *task, const RMPoint &dst) {
+ _task = task;
+ _dst.topLeft() = dst;
+ _src.setEmpty();
+ _bFlag = 0;
+ _bStretch = false;
+}
+
+RMGfxPrimitive::~RMGfxPrimitive() {
+}
+
+void RMGfxPrimitive::setFlag(byte bFlag) {
+ _bFlag = bFlag;
+}
+
+void RMGfxPrimitive::setTask(RMGfxTask *task) {
+ _task = task;
+}
+
+void RMGfxPrimitive::setSrc(const RMRect &src) {
+ _src = src;
+}
+
+void RMGfxPrimitive::setSrc(const RMPoint &src) {
+ _src.topLeft() = src;
+}
+
+void RMGfxPrimitive::setDst(const RMRect &dst) {
+ _dst = dst;
+}
+
+void RMGfxPrimitive::setDst(const RMPoint &dst) {
+ _dst.topLeft() = dst;
+}
+
+void RMGfxPrimitive::setStretch(bool bStretch) {
+ _bStretch = bStretch;
+}
+
+bool RMGfxPrimitive::haveDst() {
+ return !_dst.isEmpty();
+}
+
+RMRect &RMGfxPrimitive::getDst() {
+ return _dst;
+}
+
+bool RMGfxPrimitive::haveSrc() {
+ return !_src.isEmpty();
+}
+
+RMRect &RMGfxPrimitive::getSrc() {
+ return _src;
+}
+
+/**
+ * Flags
+ */
+bool RMGfxPrimitive::isFlipped() {
+ return _bFlag & 1;
+}
+
+/**
+ * Duplicate
+ */
+RMGfxPrimitive *RMGfxPrimitive::duplicate() {
+ return new RMGfxPrimitive(*this);
+}
+
+} // End of namespace Tony