diff options
author | Johannes Schickel | 2010-10-13 03:57:44 +0000 |
---|---|---|
committer | Johannes Schickel | 2010-10-13 03:57:44 +0000 |
commit | 75e8452b6e6a2bf4fb2f588aa00b428a60d873b5 (patch) | |
tree | f29541d55309487a94bd1d38e8b53bb3dde9aec6 /engines/scumm/gfx_towns.cpp | |
parent | 48ee83b88957dab86bc763e9ef21a70179fa8679 (diff) | |
parent | e9f50882ea5b6beeefa994040be9d3bab6a1f107 (diff) | |
download | scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.gz scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.bz2 scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.zip |
OPENGL: Merged from trunk, from rev 52105 to 53396.
This includes an rather hacky attempt to merge all the recent gp2x backend
changes into the branch. I suppose the gp2x backend and probably all new
backends, i.e. gph, dingux etc., might not compile anymore.
Since I have no way of testing those it would be nice if porters could look
into getting those up to speed in this branch.
svn-id: r53399
Diffstat (limited to 'engines/scumm/gfx_towns.cpp')
-rw-r--r-- | engines/scumm/gfx_towns.cpp | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/engines/scumm/gfx_towns.cpp b/engines/scumm/gfx_towns.cpp new file mode 100644 index 0000000000..33b1779b0b --- /dev/null +++ b/engines/scumm/gfx_towns.cpp @@ -0,0 +1,522 @@ +/* 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 "common/endian.h" + +#include "scumm/scumm.h" +#include "scumm/charset.h" +#include "scumm/util.h" +#include "scumm/resource.h" + +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE + +namespace Scumm { + +void ScummEngine::towns_drawStripToScreen(VirtScreen *vs, int dstX, int dstY, int srcX, int srcY, int width, int height) { + if (width <= 0 || height <= 0) + return; + + assert(_textSurface.pixels); + + int m = _textSurfaceMultiplier; + + uint8 *src1 = vs->getPixels(srcX, srcY); + uint8 *src2 = (uint8*)_textSurface.getBasePtr(srcX * m, (srcY + vs->topline - _screenTop) * m); + uint8 *dst1 = _townsScreen->getLayerPixels(0, dstX, dstY); + uint8 *dst2 = _townsScreen->getLayerPixels(1, dstX * m, dstY * m); + + int dp1 = _townsScreen->getLayerPitch(0) - width * _townsScreen->getLayerBpp(0); + int dp2 = _townsScreen->getLayerPitch(1) - width * m * _townsScreen->getLayerBpp(1); + int sp1 = vs->pitch - (width * vs->bytesPerPixel); + int sp2 = _textSurface.pitch - width * m; + + if (vs->number == kMainVirtScreen || _game.id == GID_INDY3 || _game.id == GID_ZAK) { + for (int h = 0; h < height; ++h) { + if (_bytesPerPixelOutput == 2) { + for (int w = 0; w < width; ++w) { + *(uint16*)dst1 = _16BitPalette[*src1++]; + dst1 += _bytesPerPixelOutput; + } + + src1 += sp1; + dst1 += dp1; + } else { + memcpy(dst1, src1, width); + src1 += vs->pitch; + dst1 += _townsScreen->getLayerPitch(0); + } + + for (int sH = 0; sH < m; ++sH) { + memcpy(dst2, src2, width * m); + src2 += _textSurface.pitch; + dst2 += _townsScreen->getLayerPitch(1); + } + } + } else { + dst1 = dst2; + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + uint8 t = (*src1++) & 0x0f; + memset(dst1, (t << 4) | t, m); + dst1 += m; + } + + dst1 = dst2; + uint8 *src3 = src2; + + if (m == 2) { + dst2 += _townsScreen->getLayerPitch(1); + src3 += _townsScreen->getLayerPitch(1); + } + + for (int w = 0; w < width * m; ++w) { + *dst2++ = (*src3 | (*dst1 & _townsLayer2Mask[*src3])); + *dst1 = (*src2 | (*dst1 & _townsLayer2Mask[*src2])); + src2++; + src3++; + dst1++; + } + + src1 += sp1; + src2 = src3 + sp2; + dst1 = dst2 + dp2; + dst2 += dp2; + } + } + + _townsScreen->addDirtyRect(dstX * m, dstY * m, width * m, height * m); +} + +bool ScummEngine::towns_isRectInStringBox(int x1, int y1, int x2, int y2) { + if (_game.platform == Common::kPlatformFMTowns && _charset->_hasMask && y1 <= _curStringRect.bottom && x1 <= _curStringRect.right && y2 >= _curStringRect.top && x2 >= _curStringRect.left) + return true; + return false; +} + +void ScummEngine::towns_restoreCharsetBg() { + if (_curStringRect.left != -1) { + restoreBackground(_curStringRect, 0); + _curStringRect.left = -1; + _charset->_hasMask = false; + _nextLeft = _string[0].xpos; + } + + _nextLeft = _string[0].xpos; + _nextTop = _string[0].ypos; +} + +#ifdef USE_RGB_COLOR +void ScummEngine::towns_setPaletteFromPtr(const byte *ptr, int numcolor) { + setPaletteFromPtr(ptr, numcolor); + + if (_game.version == 5) + towns_setTextPaletteFromPtr(_currentPalette); + + _townsOverrideShadowColor = 1; + int m = 48; + for (int i = 1; i < 16; ++i) { + int val = _currentPalette[i * 3] + _currentPalette[i * 3 + 1] + _currentPalette[i * 3 + 2]; + if (m > val) { + _townsOverrideShadowColor = i; + m = val; + } + } +} + +void ScummEngine::towns_setTextPaletteFromPtr(const byte *ptr) { + memcpy(_textPalette, ptr, 48); +} +#endif + +void ScummEngine::towns_setupPalCycleField(int x1, int y1, int x2, int y2) { + if (_numCyclRects >= 10) + return; + _cyclRects[_numCyclRects].left = x1; + _cyclRects[_numCyclRects].top = y1; + _cyclRects[_numCyclRects].right = x2; + _cyclRects[_numCyclRects].bottom = y2; + _numCyclRects++; + _townsPaletteFlags |= 1; +} + +void ScummEngine::towns_processPalCycleField() { + for (int i = 0; i < _numCyclRects; i++) { + int x1 = _cyclRects[i].left - _virtscr[kMainVirtScreen].xstart; + int x2 = _cyclRects[i].right - _virtscr[kMainVirtScreen].xstart; + if (x1 < 0) + x1 = 0; + if (x2 > 320) + x2 = 320; + if (x2 > 0) + markRectAsDirty(kMainVirtScreen, x1, x2, _cyclRects[i].top, _cyclRects[i].bottom); + } +} + +void ScummEngine::towns_resetPalCycleFields() { + _numCyclRects = 0; + _townsPaletteFlags &= ~1; +} + +const uint8 ScummEngine::_townsLayer2Mask[] = { + 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#define DIRTY_RECTS_MAX 20 +#define FULL_REDRAW (DIRTY_RECTS_MAX + 1) + +TownsScreen::TownsScreen(OSystem *system, int width, int height, int bpp) : + _system(system), _width(width), _height(height), _bpp(bpp), _pitch(width * bpp) { + memset(&_layers[0], 0, sizeof(TownsScreenLayer)); + memset(&_layers[1], 0, sizeof(TownsScreenLayer)); + _outBuffer = new byte[_pitch * _height]; + memset(_outBuffer, 0, _pitch * _height); + + setupLayer(0, width, height, 256); +} + +TownsScreen::~TownsScreen() { + delete[] _layers[0].pixels; + delete[] _layers[1].pixels; + delete[] _layers[0].bltInternX; + delete[] _layers[1].bltInternX; + delete[] _layers[0].bltInternY; + delete[] _layers[1].bltInternY; + delete[] _layers[0].bltTmpPal; + delete[] _layers[1].bltTmpPal; + delete[] _outBuffer; + _dirtyRects.clear(); +} + +void TownsScreen::setupLayer(int layer, int width, int height, int numCol, void *pal) { + if (layer < 0 || layer > 1) + return; + + TownsScreenLayer *l = &_layers[layer]; + + if (numCol >> 15) + error("TownsScreen::setupLayer(): No more than 32767 colors supported."); + + if (width > _width || height > _height) + error("TownsScreen::setupLayer(): Layer width/height must be equal or less than screen width/height"); + + l->scaleW = _width / width; + l->scaleH = _height / height; + + if ((float)l->scaleW != ((float)_width / (float)width) || (float)l->scaleH != ((float)_height / (float)height)) + error("TownsScreen::setupLayer(): Layer width/height must be equal or an EXACT half, third, etc. of screen width/height.\n More complex aspect ratio scaling is not supported."); + + if (width <= 0 || height <= 0 || numCol < 16) + error("TownsScreen::setupLayer(): Invalid width/height/number of colors setting."); + + l->height = height; + l->numCol = numCol; + l->bpp = ((numCol - 1) & 0xff00) ? 2 : 1; + l->pitch = width * l->bpp; + l->palette = (uint8*)pal; + + if (l->palette && _bpp == 1) + warning("TownsScreen::setupLayer(): Layer palette usage requires 15 bit graphics setting.\nLayer palette will be ignored."); + + delete[] l->pixels; + l->pixels = new uint8[l->pitch * l->height]; + assert(l->pixels); + memset(l->pixels, 0, l->pitch * l->height); + + // build offset tables to speed up merging/scaling layers + delete[] l->bltInternX; + l->bltInternX = new uint16[_width]; + for (int i = 0; i < _width; ++i) + l->bltInternX[i] = (i / l->scaleW) * l->bpp; + + delete[] l->bltInternY; + l->bltInternY = new uint8*[_height]; + for (int i = 0; i < _height; ++i) + l->bltInternY[i] = l->pixels + (i / l->scaleH) * l->pitch; + + delete[] l->bltTmpPal; + l->bltTmpPal = (l->bpp == 1 && _bpp == 2) ? new uint16[l->numCol] : 0; + + l->enabled = true; + l->onBottom = (!layer || !_layers[0].enabled); + l->ready = true; +} + +void TownsScreen::clearLayer(int layer) { + if (layer < 0 || layer > 1) + return; + + TownsScreenLayer *l = &_layers[layer]; + if (!l->ready) + return; + + memset(l->pixels, 0, l->pitch * l->height); + _dirtyRects.push_back(Common::Rect(_width - 1, _height - 1)); + _numDirtyRects = FULL_REDRAW; +} + + +void TownsScreen::fillLayerRect(int layer, int x, int y, int w, int h, int col) { + if (layer < 0 || layer > 1 || w <= 0 || h <= 0) + return; + + TownsScreenLayer *l = &_layers[layer]; + if (!l->ready) + return; + + assert(x >= 0 && y >= 0 && ((x + w) * l->bpp) <= (l->pitch) && (y + h) <= (l->height)); + + uint8 *pos = l->pixels + y * l->pitch + x * l->bpp; + + for (int i = 0; i < h; ++i) { + if (l->bpp == 2) { + for (int ii = 0; ii < w; ++ii) { + *(uint16*)pos = col; + pos += 2; + } + pos += (l->pitch - w * 2); + } else { + memset(pos, col, w); + pos += l->pitch; + } + } + addDirtyRect(x * l->scaleW, y * l->scaleH, w * l->scaleW, h * l->scaleH); +} + +uint8 *TownsScreen::getLayerPixels(int layer, int x, int y) { + if (layer < 0 || layer > 1) + return 0; + + TownsScreenLayer *l = &_layers[layer]; + if (!l->ready) + return 0; + + return l->pixels + y * l->pitch + x * l->bpp; +} + +int TownsScreen::getLayerPitch(int layer) { + if (layer >= 0 && layer < 2) + return _layers[layer].pitch; + return 0; +} + +int TownsScreen::getLayerHeight(int layer) { + if (layer >= 0 && layer < 2) + return _layers[layer].height; + return 0; +} + +int TownsScreen::getLayerBpp(int layer) { + if (layer >= 0 && layer < 2) + return _layers[layer].bpp; + return 0; +} + +int TownsScreen::getLayerScaleW(int layer) { + if (layer >= 0 && layer < 2) + return _layers[layer].scaleW; + return 0; +} + +int TownsScreen::getLayerScaleH(int layer) { + if (layer >= 0 && layer < 2) + return _layers[layer].scaleH; + return 0; +} + +void TownsScreen::addDirtyRect(int x, int y, int w, int h) { + if (w <= 0 || h <= 0 || _numDirtyRects > DIRTY_RECTS_MAX) + return; + + if (_numDirtyRects == DIRTY_RECTS_MAX) { + // full redraw + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(_width - 1, _height - 1)); + _numDirtyRects++; + return; + } + + int x2 = x + w - 1; + int y2 = y + h - 1; + + assert(x >= 0 && y >= 0 && x2 <= _width && y2 <= _height); + + bool skip = false; + for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r) { + // Try to merge new rect with an existing rect (only once, since trying to merge + // more than one overlapping rect would be causing more overhead than doing any good). + if (x > r->left && x < r->right && y > r->top && y < r->bottom) { + x = r->left; + y = r->top; + skip = true; + } + + if (x2 > r->left && x2 < r->right && y > r->top && y < r->bottom) { + x2 = r->right; + y = r->top; + skip = true; + } + + if (x2 > r->left && x2 < r->right && y2 > r->top && y2 < r->bottom) { + x2 = r->right; + y2 = r->bottom; + skip = true; + } + + if (x > r->left && x < r->right && y2 > r->top && y2 < r->bottom) { + x = r->left; + y2 = r->bottom; + skip = true; + } + + if (skip) { + r->left = x; + r->top = y; + r->right = x2; + r->bottom = y2; + break; + } + } + + if (!skip) { + _dirtyRects.push_back(Common::Rect(x, y, x2, y2)); + _numDirtyRects++; + } +} + +void TownsScreen::toggleLayers(int flag) { + if (flag < 0 || flag > 3) + return; + + for (int i = 0; i < 2; ++i) { + _layers[i].enabled = (flag & (i + 1)) ? true : false; + _layers[i].onBottom = (!i || !_layers[0].enabled); + } + + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(_width - 1, _height - 1)); + _numDirtyRects = FULL_REDRAW; + + memset(_outBuffer, 0, _pitch * _height); + updateOutputBuffer(); + outputToScreen(); + + _system->updateScreen(); +} + +void TownsScreen::update() { + updateOutputBuffer(); + outputToScreen(); +} + +void TownsScreen::updateOutputBuffer() { + for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r) { + for (int i = 0; i < 2; i++) { + + TownsScreenLayer *l = &_layers[i]; + if (!l->enabled || !l->ready) + continue; + + uint8 *dst = _outBuffer + r->top * _pitch + r->left * _bpp; + int ptch = _pitch - (r->right - r->left + 1) * _bpp; + + if (_bpp == 2 && l->bpp == 1) { + for (int ic = 0; ic < l->numCol; ic++) + l->bltTmpPal[ic] = calc16BitColor(&l->palette[ic * 3]); + } + + for (int y = r->top; y <= r->bottom; ++y) { + if (l->bpp == _bpp && l->scaleW == 1 && l->onBottom) { + memcpy(dst, l->bltInternY[y] + l->bltInternX[r->left], (r->right + 1 - r->left) * _bpp); + dst += _pitch; + + } else if (_bpp == 2) { + for (int x = r->left; x <= r->right; ++x) { + uint8 *src = l->bltInternY[y] + l->bltInternX[x]; + if (l->bpp == 1) { + uint8 col = *src; + if (col || l->onBottom) { + if (l->numCol == 16) + col = (col >> 4) & (col & 0x0f); + *(uint16*)dst = l->bltTmpPal[col]; + } + } else { + *(uint16*)dst = *(uint16*)src; + } + dst += 2; + } + dst += ptch; + + } else { + for (int x = r->left; x <= r->right; ++x) { + uint8 col = *(l->bltInternY[y] + l->bltInternX[x]); + if (col || l->onBottom) { + if (l->numCol == 16) + col = (col >> 4) & (col & 0x0f); + *dst = col; + } + dst++; + } + dst += ptch; + } + } + } + } +} + +void TownsScreen::outputToScreen() { + for (Common::List<Common::Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) + _system->copyRectToScreen(_outBuffer + i->top * _pitch + i->left * _bpp, _pitch, i->left, i->top, i->right - i->left + 1, i->bottom - i->top + 1); + _dirtyRects.clear(); + _numDirtyRects = 0; +} + +uint16 TownsScreen::calc16BitColor(const uint8 *palEntry) { + uint16 ar = (palEntry[0] & 0xf8) << 7; + uint16 ag = (palEntry[1] & 0xf8) << 2; + uint16 ab = (palEntry[2] >> 3); + uint16 col = ar | ag | ab; + return col; +} + +#undef DIRTY_RECTS_MAX +#undef FULL_REDRAW + +} // End of namespace Scumm + +#endif // DISABLE_TOWNS_DUAL_LAYER_MODE |