diff options
Diffstat (limited to 'engines/m4/graphics.cpp')
-rw-r--r-- | engines/m4/graphics.cpp | 1361 |
1 files changed, 0 insertions, 1361 deletions
diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp deleted file mode 100644 index 99130aee08..0000000000 --- a/engines/m4/graphics.cpp +++ /dev/null @@ -1,1361 +0,0 @@ -/* 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. - * - */ - -#include "common/system.h" -#include "common/util.h" -#include "common/ptr.h" -#include "common/textconsole.h" - -#include "graphics/palette.h" - -#include "m4/globals.h" -#include "m4/graphics.h" -#include "m4/sprite.h" -#include "m4/m4.h" -#include "m4/compression.h" - -namespace M4 { - -RGBList::RGBList(int numEntries, RGB8 *srcData, bool freeData) { - _size = numEntries; - assert(numEntries <= 256); - - if (srcData == NULL) { - _data = new RGB8[numEntries]; - _freeData = true; - } else { - _data = srcData; - _freeData = freeData; - } - - _palIndexes = new byte[numEntries]; - Common::fill(&_palIndexes[0], &_palIndexes[numEntries], 0); -} - -RGBList::~RGBList() { - if (_freeData) - delete[] _data; - delete[] _palIndexes; -} - -void RGBList::setRange(int start, int count, const RGB8 *src) { - assert((start + count) <= _size); - - Common::copy(&src[0], &src[count], &_data[start]); -} - -/** - * Creates a duplicate of the given rgb list - */ -RGBList *RGBList::clone() const { - RGBList *dest = new RGBList(_size, _data, false); - _madsVm->_palette->addRange(dest); - return dest; -} - -//-------------------------------------------------------------------------- - -#define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2) - -M4Surface::~M4Surface() { - if (_rgbList) { - _madsVm->_palette->deleteRange(_rgbList); - delete _rgbList; - } - if (_ownsData) - free(); -} - -void M4Surface::loadCodesM4(Common::SeekableReadStream *source) { - if (!source) { - free(); - return; - } - - uint16 widthVal = source->readUint16LE(); - uint16 heightVal = source->readUint16LE(); - - create(widthVal, heightVal, Graphics::PixelFormat::createFormatCLUT8()); - source->read(pixels, widthVal * heightVal); -} - -void M4Surface::loadCodesMads(Common::SeekableReadStream *source) { - if (!source) { - free(); - return; - } - - uint16 widthVal = 320; - uint16 heightVal = 156; - byte *walkMap = new byte[source->size()]; - - create(widthVal, heightVal, Graphics::PixelFormat::createFormatCLUT8()); - source->read(walkMap, source->size()); - - byte *ptr = (byte *)getBasePtr(0, 0); - - for (int y = 0; y < heightVal; y++) { - for (int x = 0; x < widthVal; x++) { - int ofs = x + (y * widthVal); - if ((walkMap[ofs / 8] << (ofs % 8)) & 0x80) - *ptr++ = 1; // walkable - else - *ptr++ = 0; - } - } - - delete[] walkMap; -} - -// Sprite related methods - -void M4Surface::vLine(int x, int y1, int y2) { - Graphics::Surface::vLine(x, y1, y2, _color); -} - -void M4Surface::hLine(int x1, int x2, int y) { - Graphics::Surface::hLine(x1, y, x2, _color); -} - -void M4Surface::vLineXor(int x, int y1, int y2) { - // Clipping - if (x < 0 || x >= w) - return; - - if (y2 < y1) - SWAP(y2, y1); - - if (y1 < 0) - y1 = 0; - if (y2 >= h) - y2 = h - 1; - - byte *ptr = (byte *)getBasePtr(x, y1); - while (y1++ <= y2) { - *ptr ^= 0xFF; - ptr += pitch; - } - -} - -void M4Surface::hLineXor(int x1, int x2, int y) { - // Clipping - if (y < 0 || y >= h) - return; - - if (x2 < x1) - SWAP(x2, x1); - - if (x1 < 0) - x1 = 0; - if (x2 >= w) - x2 = w - 1; - - if (x2 < x1) - return; - - byte *ptr = (byte *)getBasePtr(x1, y); - while (x1++ <= x2) - *ptr++ ^= 0xFF; - -} - -void M4Surface::drawLine(int x1, int y1, int x2, int y2, byte color) { - Graphics::Surface::drawLine(x1, y1, x2, y2, color); -} - - -void M4Surface::frameRect(int x1, int y1, int x2, int y2) { - Graphics::Surface::frameRect(Common::Rect(x1, y1, x2, y2), _color); -} - -void M4Surface::fillRect(int x1, int y1, int x2, int y2) { - Graphics::Surface::fillRect(Common::Rect(x1, y1, x2, y2), _color); -} - -void M4Surface::drawSprite(int x, int y, SpriteInfo &info, const Common::Rect &clipRect) { - - enum { - kStatusSkip, - kStatusScale, - kStatusDraw - }; - - // NOTE: The current clipping code assumes that the top left corner of the clip - // rectangle is always 0, 0 - assert(clipRect.top == 0 && clipRect.left == 0); - - // TODO: Put err* and scaled* into SpriteInfo - int errX = info.hotX * info.scaleX % 100; - int errY = info.hotY * info.scaleY % 100; - int scaledWidth = scaleValue(info.width, info.scaleX, errX); - int scaledHeight = scaleValue(info.height, info.scaleY, errY); - - /* - debugCN(kDebugGraphics, "M4Surface::drawSprite() info.width = %d; info.scaleX = %d; info.height = %d; info.scaleY = %d; scaledWidth = %d; scaledHeight = %d\n", - info.width, info.scaleX, info.height, info.scaleY, scaledWidth, scaledHeight); - */ - - int clipX = 0, clipY = 0; - // Clip the sprite's width and height according to the clip rectangle's dimensions - // This clips the sprite to the bottom and right - if (x >= 0) { - scaledWidth = MIN<int>(x + scaledWidth, clipRect.right) - x; - } else { - clipX = x; - scaledWidth = x + scaledWidth; - } - if (y >= 0) { - scaledHeight = MIN<int>(y + scaledHeight, clipRect.bottom) - y; - } else { - clipY = y; - scaledHeight = y + scaledHeight; - } - - //debugCN(kDebugGraphics, "M4Surface::drawSprite() width = %d; height = %d; scaledWidth = %d; scaledHeight = %d\n", info.width, info.height, scaledWidth, scaledHeight); - - // Check if sprite is inside the screen. If it's not, there's no need to draw it - if (scaledWidth + x <= 0 || scaledHeight + y <= 0) // check left and top (in case x,y are negative) - return; - if (scaledWidth <= 0 || scaledHeight <= 0) // check right and bottom - return; - int heightAmt = scaledHeight; - - byte *src = info.sprite->getBasePtr(); - byte *dst = getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY); - - int status = kStatusSkip; - byte *scaledLineBuf = new byte[scaledWidth]; - - while (heightAmt > 0) { - - if (status == kStatusSkip) { - // Skip line - errY -= info.scaleY; - if (errY < 0) - status = kStatusScale; - else - src += info.width; - } else { - - if (status == kStatusScale) { - // Scale current line - byte *lineDst = scaledLineBuf; - int curErrX = errX; - int widthVal = scaledWidth; - byte *tempSrc = src; - int startX = clipX; - while (widthVal > 0) { - byte pixel = *tempSrc++; - curErrX -= info.scaleX; - while (curErrX < 0) { - if (startX == 0) { - *lineDst++ = pixel; - widthVal--; - } else { - startX++; - } - curErrX += 100; - } - } - src += info.width; - status = kStatusDraw; - } - - if (status == kStatusDraw && clipY == 0) { - // Draw previously scaled line - // TODO Implement different drawing types (depth, shadow etc.) - byte *tempDst = dst; - for (int lineX = 0; lineX < scaledWidth; lineX++) { - byte pixel = scaledLineBuf[lineX]; - - if (info.encoding & 0x80) { - - if (pixel == 0x80) { - pixel = 0; - } else { - byte destPixel = *tempDst; - byte r, g, b; - r = CLIP((info.palette[destPixel].r * pixel) >> 10, 0, 31); - g = CLIP((info.palette[destPixel].g * pixel) >> 10, 0, 31); - b = CLIP((info.palette[destPixel].b * pixel) >> 10, 0, 31); - pixel = info.inverseColorTable[(b << 10) | (g << 5) | r]; - } - } - - if (pixel) - *tempDst = pixel; - - tempDst++; - } - dst += pitch; - heightAmt--; - // TODO depth etc. - //depthAddress += Destination -> Width; - - errY += 100; - if (errY >= 0) - status = kStatusSkip; - } else if (status == kStatusDraw && clipY < 0) { - clipY++; - - errY += 100; - if (errY >= 0) - status = kStatusSkip; - } - - } - - } - - delete[] scaledLineBuf; - -} - -// Surface methods - -void M4Surface::freeData() { -} - -void M4Surface::clear() { - Common::fill((byte *)pixels, (byte *)pixels + w * h, _vm->_palette->BLACK); -} - -void M4Surface::reset() { - ::free(pixels); - pixels = NULL; - if (_rgbList) { - _vm->_palette->deleteRange(_rgbList); - delete _rgbList; - _rgbList = NULL; - } -} - -void M4Surface::frameRect(const Common::Rect &r, uint8 color) { - Graphics::Surface::frameRect(r, color); -} - -void M4Surface::fillRect(const Common::Rect &r, uint8 color) { - Graphics::Surface::fillRect(r, color); -} - -void M4Surface::copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY, - int transparentColor) { - // Validation of the rectangle and position - if ((destX >= w) || (destY >= h)) - return; - - Common::Rect copyRect = srcBounds; - if (destX < 0) { - copyRect.left += -destX; - destX = 0; - } else if (destX + copyRect.width() > w) { - copyRect.right -= destX + copyRect.width() - w; - } - if (destY < 0) { - copyRect.top += -destY; - destY = 0; - } else if (destY + copyRect.height() > h) { - copyRect.bottom -= destY + copyRect.height() - h; - } - - if (!copyRect.isValidRect()) - return; - - // Copy the specified area - - byte *data = src->getBasePtr(); - byte *srcPtr = data + (src->width() * copyRect.top + copyRect.left); - byte *destPtr = (byte *)pixels + (destY * width()) + destX; - - for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { - if (transparentColor == -1) - // No transparency, so copy line over - Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr); - else { - // Copy each byte one at a time checking for the transparency color - for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) - if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr]; - } - - srcPtr += src->width(); - destPtr += width(); - } - - src->freeData(); -} - -/** - * Copies a given image onto a destination surface with scaling, transferring only pixels that meet - * the specified depth requirement on a secondary surface contain depth information - */ -void M4Surface::copyFrom(M4Surface *src, int destX, int destY, int depth, - M4Surface *depthsSurface, int scale, int transparentColor) { - - if (scale == 100) { - // Copy the specified area - Common::Rect copyRect(0, 0, src->width(), src->height()); - - if (destX < 0) { - copyRect.left += -destX; - destX = 0; - } else if (destX + copyRect.width() > w) { - copyRect.right -= destX + copyRect.width() - w; - } - if (destY < 0) { - copyRect.top += -destY; - destY = 0; - } else if (destY + copyRect.height() > h) { - copyRect.bottom -= destY + copyRect.height() - h; - } - - if (!copyRect.isValidRect()) - return; - - byte *data = src->getBasePtr(); - byte *srcPtr = data + (src->width() * copyRect.top + copyRect.left); - byte *depthsData = depthsSurface->getBasePtr(); - byte *depthsPtr = depthsData + (depthsSurface->pitch * destY) + destX; - byte *destPtr = (byte *)pixels + (destY * pitch) + destX; - - // 100% scaling variation - for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { - // Copy each byte one at a time checking against the depth - for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) { - if ((depth <= (depthsPtr[xCtr] & 0x7f)) && (srcPtr[xCtr] != transparentColor)) - destPtr[xCtr] = srcPtr[xCtr]; - } - - srcPtr += src->width(); - depthsPtr += depthsSurface->width(); - destPtr += width(); - } - - src->freeData(); - depthsSurface->freeData(); - return; - } - - // Start of draw logic for scaled sprites - const byte *srcPixelsP = src->getBasePtr(); - - int destRight = this->width() - 1; - int destBottom = this->height() - 1; - bool normalFrame = true; // TODO: false for negative frame numbers - int frameWidth = src->width(); - int frameHeight = src->height(); - - int highestDim = MAX(frameWidth, frameHeight); - bool lineDist[MADS_SURFACE_WIDTH]; - int distIndex = 0; - int distXCount = 0, distYCount = 0; - - int distCtr = 0; - do { - distCtr += scale; - if (distCtr < 100) { - lineDist[distIndex] = false; - } else { - lineDist[distIndex] = true; - distCtr -= 100; - - if (distIndex < frameWidth) - ++distXCount; - - if (distIndex < frameHeight) - ++distYCount; - } - } while (++distIndex < highestDim); - - destX -= distXCount / 2; - destY -= distYCount - 1; - - // Check x bounding area - int spriteLeft = 0; - int spriteWidth = distXCount; - int widthAmount = destX + distXCount - 1; - - if (destX < 0) { - spriteWidth += destX; - spriteLeft -= destX; - } - widthAmount -= destRight; - if (widthAmount > 0) - spriteWidth -= widthAmount; - - int spriteRight = spriteLeft + spriteWidth; - if (spriteWidth <= 0) - return; - if (!normalFrame) { - destX += distXCount - 1; - spriteLeft = -(distXCount - spriteRight); - spriteRight = (-spriteLeft + spriteWidth); - } - - // Check y bounding area - int spriteTop = 0; - int spriteHeight = distYCount; - int heightAmount = destY + distYCount - 1; - - if (destY < 0) { - spriteHeight += destY; - spriteTop -= destY; - } - heightAmount -= destBottom; - if (heightAmount > 0) - spriteHeight -= heightAmount; - int spriteBottom = spriteTop + spriteHeight; - - if (spriteHeight <= 0) - return; - - byte *destPixelsP = this->getBasePtr(destX + spriteLeft, destY + spriteTop); - const byte *depthPixelsP = depthsSurface->getBasePtr(destX + spriteLeft, destY + spriteTop); - - spriteLeft = (spriteLeft * (normalFrame ? 1 : -1)); - - // Loop through the lines of the sprite - for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src->pitch) { - if (!lineDist[yp]) - // Not a display line, so skip it - continue; - // Check whether the sprite line is in the display range - ++sprY; - if ((sprY >= spriteBottom) || (sprY < spriteTop)) - continue; - - // Found a line to display. Loop through the pixels - const byte *srcP = srcPixelsP; - const byte *depthP = depthPixelsP; - byte *destP = destPixelsP; - for (int xp = 0, sprX = 0; xp < frameWidth; ++xp, ++srcP) { - if (xp < spriteLeft) - // Not yet reached start of display area - continue; - if (!lineDist[sprX++]) - // Not a display pixel - continue; - - if ((*srcP != transparentColor) && (depth <= (*depthP & 0x7f))) - *destP = *srcP; - - ++destP; - ++depthP; - } - - // Move to the next destination line - destPixelsP += this->pitch; - depthPixelsP += depthsSurface->pitch; - } - - src->freeData(); - depthsSurface->freeData(); - this->freeData(); -} - -void M4Surface::loadBackgroundRiddle(const char *sceneName) { - char resourceName[20]; - Common::SeekableReadStream *stream; - // Loads a Riddle scene - sprintf(resourceName, "%s.tt", sceneName); - stream = _vm->_resourceManager->get(resourceName); - m4LoadBackground(stream); - _vm->_resourceManager->toss(resourceName); -} - -void M4Surface::loadBackground(int sceneNumber, RGBList **palData) { - if (_vm->isM4() || (_vm->getGameType() == GType_RexNebular)) { - char resourceName[20]; - Common::SeekableReadStream *stream; - - if (_vm->getGameType() == GType_RexNebular) { - // Load Rex Nebular screen - bool hasPalette = palData != NULL; - if (!hasPalette) - palData = &_rgbList; - - sprintf(resourceName, "rm%d.art", sceneNumber); - stream = _vm->_resourceManager->get(resourceName); - rexLoadBackground(stream, palData); - - if (!hasPalette) { - _vm->_palette->addRange(_rgbList); - this->translate(_rgbList); - } - } else { - // Loads M4 game scene - if (palData) - *palData = NULL; - sprintf(resourceName, "%i.tt", sceneNumber); - stream = _vm->_resourceManager->get(resourceName); - m4LoadBackground(stream); - } - - _vm->_resourceManager->toss(resourceName); - - } else { - madsLoadBackground(sceneNumber, palData); - } -} - -void M4Surface::madsLoadBackground(int roomNumber, RGBList **palData) { - // Get a MadsPack reference to the tile set and mapping - char resourceName[20]; - int i; - - // Uncompressed tile map resource - sprintf(resourceName, "rm%d.mm", roomNumber); - MadsPack tileMapFile(resourceName, _vm); - Common::SeekableReadStream *mapStream = tileMapFile.getItemStream(0); - - // Get the details of the tiles and map - mapStream->readUint32LE(); - int tileCountX = mapStream->readUint16LE(); - int tileCountY = mapStream->readUint16LE(); - int tileWidthMap = mapStream->readUint16LE(); - int tileHeightMap = mapStream->readUint16LE(); - int screenWidth = mapStream->readUint16LE(); - int screenHeight = mapStream->readUint16LE(); - int tileCountMap = tileCountX * tileCountY; - delete mapStream; - - // Obtain tile map information - typedef Common::List<Common::SharedPtr<M4Surface> > TileSetList; - typedef TileSetList::iterator TileSetIterator; - TileSetList tileSet; - uint16 *tileMap = new uint16[tileCountMap]; - mapStream = tileMapFile.getItemStream(1); - for (i = 0; i < tileCountMap; ++i) - tileMap[i] = mapStream->readUint16LE(); - delete mapStream; - _vm->res()->toss(resourceName); - - // -------------------------------------------------------------------------------- - - // Tile map data, which needs to be kept compressed, as the tile offsets refer to - // the compressed data. Each tile is then uncompressed separately - sprintf(resourceName, "rm%d.tt", roomNumber); - Common::SeekableReadStream *tileDataComp = _vm->_resourceManager->get(resourceName); - MadsPack tileData(tileDataComp); - Common::SeekableReadStream *tileDataUncomp = tileData.getItemStream(0); - - // Validate that the data matches between the tiles and tile map file and is valid - int tileCount = tileDataUncomp->readUint16LE(); - int tileWidth = tileDataUncomp->readUint16LE(); - int tileHeight = tileDataUncomp->readUint16LE(); - delete tileDataUncomp; - assert(tileCountMap == tileCount); - assert(tileWidth == tileWidthMap); - assert(tileHeight == tileHeightMap); - assert(screenWidth == _vm->_screen->width()); - assert(screenHeight <= _vm->_screen->height()); - - // -------------------------------------------------------------------------------- - - // Get the palette to use - tileDataUncomp = tileData.getItemStream(2); - // Set palette - if (!palData) { - _vm->_palette->setMadsPalette(tileDataUncomp, 4); - } else { - int numColors; - RGB8 *rgbList = _vm->_palette->decodeMadsPalette(tileDataUncomp, &numColors); - *palData = new RGBList(numColors, rgbList, true); - } - delete tileDataUncomp; - - // -------------------------------------------------------------------------------- - - // Get tile data - - tileDataUncomp = tileData.getItemStream(1); - FabDecompressor fab; - uint32 compressedTileDataSize = 0; - - for (i = 0; i < tileCount; i++) { - tileDataUncomp->seek(i * 4, SEEK_SET); - uint32 tileOfs = tileDataUncomp->readUint32LE(); - M4Surface* newTile = new M4Surface(tileWidth, tileHeight); - - if (i == tileCount - 1) - compressedTileDataSize = tileDataComp->size() - tileOfs; - else - compressedTileDataSize = tileDataUncomp->readUint32LE() - tileOfs; - - //debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize); - - newTile->clear(); - - byte *compressedTileData = new byte[compressedTileDataSize]; - - tileDataComp->seek(tileData.getDataOffset() + tileOfs, SEEK_SET); - tileDataComp->read(compressedTileData, compressedTileDataSize); - - fab.decompress(compressedTileData, compressedTileDataSize, (byte*)newTile->pixels, tileWidth * tileHeight); - tileSet.push_back(TileSetList::value_type(newTile)); - delete[] compressedTileData; - } - - delete tileDataUncomp; - - // -------------------------------------------------------------------------------- - - // Loop through the mapping data to place the tiles on the screen - - uint16 *tIndex = &tileMap[0]; - for (int y = 0; y < tileCountY; y++) { - for (int x = 0; x < tileCountX; x++) { - int tileIndex = *tIndex++; - assert(tileIndex < tileCount); - TileSetIterator tile = tileSet.begin(); - for (i = 0; i < tileIndex; i++) - ++tile; - ((*tile).get())->copyTo(this, x * tileWidth, y * tileHeight); - } - } - tileSet.clear(); - _vm->res()->toss(resourceName); -} - -void M4Surface::rexLoadBackground(Common::SeekableReadStream *source, RGBList **palData) { - MadsPack packData(source); - Common::SeekableReadStream *sourceUnc = packData.getItemStream(0); - - int sceneWidth = sourceUnc->readUint16LE(); - int sceneHeight = sourceUnc->readUint16LE(); - int sceneSize = sceneWidth * sceneHeight; - - // Set palette - if (!palData) { - _vm->_palette->setMadsPalette(sourceUnc, 4); - } else { - int numColors; - RGB8 *rgbList = _vm->_palette->decodeMadsPalette(sourceUnc, &numColors); - *palData = new RGBList(numColors, rgbList, true); - } - delete sourceUnc; - - // Get the raw data for the background - sourceUnc = packData.getItemStream(1); - assert((int)sourceUnc->size() >= sceneSize); - - create(sceneWidth, sceneHeight, Graphics::PixelFormat::createFormatCLUT8()); - byte *pData = (byte *)pixels; - sourceUnc->read(pData, sceneSize); - - freeData(); - delete sourceUnc; -} - -#undef COL_TRANS - -void M4Surface::m4LoadBackground(Common::SeekableReadStream *source) { - M4Surface *tileBuffer = new M4Surface(); - uint curTileX = 0, curTileY = 0; - int clipX = 0, clipY = 0; - RGB8 palette[256]; - - source->readUint32LE(); // magic, unused - /*uint32 size =*/ source->readUint32LE(); - uint32 widthVal = source->readUint32LE(); - uint32 heightVal = source->readUint32LE(); - uint32 tilesX = source->readUint32LE(); - uint32 tilesY = source->readUint32LE(); - uint32 tileWidth = source->readUint32LE(); - uint32 tileHeight = source->readUint32LE(); - uint8 blackIndex = 0; - - // Debug - //debugCN(kDebugGraphics, "loadBackground(): %dx%d picture (%d bytes) - %dx%d tiles of size %dx%d\n", - // widthVal, heightVal, size, tilesX, tilesY, tileWidth, tileHeight); - - // BGR data, which is converted to RGB8 - for (uint i = 0; i < 256; i++) { - palette[i].b = source->readByte() << 2; - palette[i].g = source->readByte() << 2; - palette[i].r = source->readByte() << 2; - // FIXME - Removed u field from RGB8 as the OSystem palette is now RGB. - // If this is needed, then the system setPalette() call will need changing to skip this. - uint8 u = source->readByte() << 2; - if (u != 0) - debugC(1, kDebugGraphics, "Unused u field in Palette data non-zero: %d", u); - - if ((blackIndex == 0) && !palette[i].r && !palette[i].g && !palette[i].b) - blackIndex = i; - } - - _vm->_palette->setPalette(palette, 0, 256); - - // resize or create the surface - // note that the height of the scene in game scenes is smaller than 480, as the bottom part of the - // screen is the inventory - assert(width() == (int)widthVal); - //debugCN(kDebugGraphics, "width(): %d, widthVal: %d, height(): %d, heightVal: %d\n", width(), widthVal, height(), heightVal); - - tileBuffer->create(tileWidth, tileHeight, Graphics::PixelFormat::createFormatCLUT8()); - - for (curTileY = 0; curTileY < tilesY; curTileY++) { - clipY = MIN(heightVal, (1 + curTileY) * tileHeight) - (curTileY * tileHeight); - - for (curTileX = 0; curTileX < tilesX; curTileX++) { - clipX = MIN(widthVal, (1 + curTileX) * tileWidth) - (curTileX * tileWidth); - - // Read a tile and copy it to the destination surface - source->read(tileBuffer->pixels, tileWidth * tileHeight); - Common::Rect srcBounds(0, 0, clipX, clipY); - copyFrom(tileBuffer, srcBounds, curTileX * tileWidth, curTileY * tileHeight); - } - } - - if (heightVal < (uint)height()) - fillRect(Common::Rect(0, heightVal, width(), height()), blackIndex); - - delete tileBuffer; -} - -void M4Surface::madsLoadInterface(const Common::String &filename) { - MadsPack intFile(filename.c_str(), _vm); - RGB8 *palette = new RGB8[16]; - - // Chunk 0, palette - Common::SeekableReadStream *intStream = intFile.getItemStream(0); - - for (int i = 0; i < 16; i++) { - palette[i].r = intStream->readByte() << 2; - palette[i].g = intStream->readByte() << 2; - palette[i].b = intStream->readByte() << 2; - intStream->readByte(); - intStream->readByte(); - intStream->readByte(); - } - _rgbList = new RGBList(16, palette, true); - delete intStream; - - // Chunk 1, data - intStream = intFile.getItemStream(1); - create(320, 44, Graphics::PixelFormat::createFormatCLUT8()); - intStream->read(pixels, 320 * 44); - delete intStream; - - // Translate the interface palette - _vm->_palette->addRange(_rgbList); - this->translate(_rgbList); -} - -void M4Surface::scrollX(int xAmount) { - if (xAmount == 0) - return; - - byte buffer[80]; - int direction = (xAmount > 0) ? -1 : 1; - int xSize = ABS(xAmount); - assert(xSize <= 80); - - byte *srcP = (byte *)getBasePtr(0, 0); - - for (int y = 0; y < height(); ++y, srcP += pitch) { - if (direction < 0) { - // Copy area to be overwritten - Common::copy(srcP, srcP + xSize, &buffer[0]); - // Shift the remainder of the line over the given area - Common::copy(srcP + xSize, srcP + width(), srcP); - // Move buffered area to the end of the line - Common::copy(&buffer[0], &buffer[xSize], srcP + width() - xSize); - } else { - // Copy area to be overwritten - Common::copy_backward(srcP + width() - xSize, srcP + width(), &buffer[80]); - // Shift the remainder of the line over the given area - Common::copy_backward(srcP, srcP + width() - xSize, srcP + width()); - // Move buffered area to the start of the line - Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize); - } - } -} - -void M4Surface::scrollY(int yAmount) { - if (yAmount == 0) - return; - - int direction = (yAmount > 0) ? 1 : -1; - int ySize = ABS(yAmount); - assert(ySize < (height() / 2)); - assert(width() == pitch); - - int blockSize = ySize * width(); - byte *tempData = (byte *)malloc(blockSize); - byte *pixelsP = (byte *)getBasePtr(0, 0); - - if (direction > 0) { - // Buffer the lines to be overwritten - byte *srcP = (byte *)getBasePtr(0, height() - ySize); - Common::copy(srcP, srcP + (pitch * ySize), tempData); - // Vertically shift all the lines - Common::copy_backward(pixelsP, pixelsP + (pitch * (height() - ySize)), - pixelsP + (pitch * height())); - // Transfer the buffered lines top the top of the screen - Common::copy(tempData, tempData + blockSize, pixelsP); - } else { - // Buffer the lines to be overwritten - Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData); - // Vertically shift all the lines - Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * height()), pixelsP); - // Transfer the buffered lines to the bottom of the screen - Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (height() - ySize))); - } - - ::free(tempData); -} - - -void M4Surface::translate(RGBList *list, bool isTransparent) { - byte *p = getBasePtr(0, 0); - byte *palIndexes = list->palIndexes(); - - for (int i = 0; i < width() * height(); ++i, ++p) { - if (!isTransparent || (*p != TRANSPARENT_COLOR_INDEX)) { - if (*p < list->size()) - *p = palIndexes[*p]; - else - warning("Pal index %d exceeds list size %d", *p, list->size()); - } - } - - freeData(); -} - -M4Surface *M4Surface::flipHorizontal() const { - M4Surface *dest = new M4Surface(width(), height()); - dest->_rgbList = (this->_rgbList == NULL) ? NULL : this->_rgbList->clone(); - - byte *destP = dest->getBasePtr(); - - for (int y = 0; y < height(); ++y) { - const byte *srcP = getBasePtr(width() - 1, y); - for (int x = 0; x < width(); ++x) - *destP++ = *srcP--; - } - - return dest; -} - -//-------------------------------------------------------------------------- -// Palette class -// - -#define GREEN_START 32 -#define NUM_GREENS 32 -#define GREEN_END (GREEN_START + NUM_GREENS - 1) -#define NORMAL_START 64 -#define NORMAL_END 255 -#define NUM_NORMAL (NORMAL_END - NORMAL_START + 1) - -// Support function for creating a list of palette indexes to change entries in the shaded range to - -static void makeTranslationList(RGB8 *palData, byte transList[NUM_GREENS]) { - int i, j, minDistance; - byte bestIndex; - - for (i = 0; i < NUM_GREENS; ++i) { - bestIndex = NORMAL_START; - minDistance = 255; - - uint8 findCol = palData[GREEN_START + i].g; - - // Find the closest matching palette color - for (j = NORMAL_START; j <= NORMAL_END; ++j) { - int greenVal = palData[j].g; - if (ABS(findCol - greenVal) < minDistance) { - minDistance = ABS(findCol - greenVal); - bestIndex = j; - } - - if (minDistance == 0) - break; - } - - transList[i] = bestIndex; - } -} - -// Support function for fading in or out - -static void fadeRange(MadsM4Engine *vm, RGB8 *srcPal, RGB8 *destPal, int startIndex, int endIndex, - int numSteps, uint delayAmount) { - RGB8 tempPal[256]; - - // perform the fade - for (int stepCtr = 1; stepCtr <= numSteps; ++stepCtr) { - // Delay the specified amount - uint32 startTime = g_system->getMillis(); - while ((g_system->getMillis() - startTime) < delayAmount) { - vm->_events->handleEvents(); - g_system->delayMillis(10); - } - - for (int i = startIndex; i <= endIndex; ++i) { - // Handle the intermediate rgb values for fading - tempPal[i].r = (byte) (srcPal[i].r + (destPal[i].r - srcPal[i].r) * stepCtr / numSteps); - tempPal[i].g = (byte) (srcPal[i].g + (destPal[i].g - srcPal[i].g) * stepCtr / numSteps); - tempPal[i].b = (byte) (srcPal[i].b + (destPal[i].b - srcPal[i].b) * stepCtr / numSteps); - } - - vm->_palette->setPalette(&tempPal[startIndex], startIndex, endIndex - startIndex + 1); - vm->_viewManager->refreshAll(); - } - - // Make sure the end palette exactly matches what is wanted - vm->_palette->setPalette(&destPal[startIndex], startIndex, endIndex - startIndex + 1); -} - -Palette::Palette(MadsM4Engine *vm) : _vm(vm) { - reset(); - _fading_in_progress = false; - Common::fill(&_usageCount[0], &_usageCount[256], 0); -} - -void Palette::setPalette(const byte *colors, uint start, uint num) { - g_system->getPaletteManager()->setPalette(colors, start, num); - reset(); -} - -void Palette::setPalette(const RGB8 *colors, uint start, uint num) { - g_system->getPaletteManager()->setPalette((const byte *)colors, start, num); - reset(); -} - -void Palette::grabPalette(byte *colors, uint start, uint num) { - g_system->getPaletteManager()->grabPalette(colors, start, num); -} - -void Palette::setEntry(uint index, uint8 r, uint8 g, uint8 b) { - RGB8 c; - c.r = r; - c.g = g; - c.b = b; - g_system->getPaletteManager()->setPalette((const byte *)&c, index, 1); -} - -uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData) { - byte index = 0; - int32 minDist = 0x7fffffff; - RGB8 palData[256]; - int Rdiff, Gdiff, Bdiff; - - if (paletteData == NULL) { - g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256); - paletteData = &palData[0]; - } - - for (int palIndex = 0; palIndex < 256; ++palIndex) { - Rdiff = r - paletteData[palIndex].r; - Gdiff = g - paletteData[palIndex].g; - Bdiff = b - paletteData[palIndex].b; - - if (Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff < minDist) { - minDist = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff; - index = (uint8)palIndex; - } - } - - return (uint8)index; -} - -void Palette::reset() { - RGB8 palData[256]; - g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256); - - BLACK = palIndexFromRgb(0, 0, 0, palData); - BLUE = palIndexFromRgb(0, 0, 255, palData); - GREEN = palIndexFromRgb(0, 255, 0, palData); - CYAN = palIndexFromRgb(0, 255, 255, palData); - RED = palIndexFromRgb(255, 0, 0, palData); - VIOLET = palIndexFromRgb(255, 0, 255, palData); - BROWN = palIndexFromRgb(168, 84, 84, palData); - LIGHT_GRAY = palIndexFromRgb(168, 168, 168, palData); - DARK_GRAY = palIndexFromRgb(84, 84, 84, palData); - LIGHT_BLUE = palIndexFromRgb(0, 0, 127, palData); - LIGHT_GREEN = palIndexFromRgb(0, 127, 0, palData); - LIGHT_CYAN = palIndexFromRgb(0, 127, 127, palData); - LIGHT_RED = palIndexFromRgb(84, 0, 0, palData); - PINK = palIndexFromRgb(84, 0, 0, palData); - YELLOW = palIndexFromRgb(0, 84, 84, palData); - WHITE = palIndexFromRgb(255, 255, 255, palData); -} - -void Palette::fadeToGreen(int numSteps, uint delayAmount) { - if (_fading_in_progress) - return; - _fading_in_progress = true; - byte translationList[NUM_GREENS]; - - int i; - byte *tempP; - uint8 greenAmount = 0; - RGB8 *srcPalette = (RGB8 *) &_originalPalette[0]; - RGB8 *destPalette = (RGB8 *) &_fadedPalette[0]; - - _vm->_palette->grabPalette(srcPalette, 0, 256); - - // Create the destination 'greenish' palette to fade to by setting the green component - // to the average of the RGB bytes, and leaving the Red and Blue parts as 0 - - Common::copy(&srcPalette[0], &srcPalette[256], &destPalette[0]); - for (i = 32; i < 256; ++i) { - byte luminance = (byte)((destPalette[i].r + destPalette[i].g + destPalette[i].b) / 3); - destPalette[i].g = MIN((byte)255, luminance); - destPalette[i].r = destPalette[i].b = 0; - } - - // Handle the actual fading - fadeRange(_vm, srcPalette, destPalette, 21, 255, numSteps, delayAmount); - - // Create a translation table to be used in translating pixels in the game surface - // using palette indexes in the range the range #32-63 into values from #64-255 - - makeTranslationList(destPalette, translationList); - - // Use palette indexes from #32-63 for the range of possible shades - - for (i = GREEN_START; i <= GREEN_END; ++i, greenAmount += 8) { - destPalette[i].g = greenAmount; - destPalette[i].r = destPalette[i].b = 0; - } - - // Remap all pixels into the #32-63 range - - tempP = _vm->_scene->getBasePtr(); - for (int pixelCtr = 0; pixelCtr < _vm->_scene->width() * _vm->_scene->height(); - ++pixelCtr, ++tempP) { - // If pixel is in #32-63 range already, remap to higher palette entries - if ((*tempP >= GREEN_START) && (*tempP <= GREEN_END)) - *tempP = translationList[*tempP - GREEN_START]; - - *tempP = (uint8) (GREEN_START + (destPalette[*tempP].g >> 3)); - } - - _vm->_palette->setPalette(&destPalette[GREEN_START], GREEN_START, NUM_GREENS); - _vm->_viewManager->refreshAll(); - _fading_in_progress = false; -} - -void Palette::fadeFromGreen(int numSteps, uint delayAmount, bool fadeToBlack) { - if (_fading_in_progress) - return; - _fading_in_progress = true; - RGB8 blackPalette[256]; - RGB8 *fadedPalette = (RGB8 *) &_fadedPalette[0]; - RGB8 *destPalette = (RGB8 *) &_originalPalette[0]; - - if (fadeToBlack) { - Common::fill((byte *)&blackPalette[0], (byte *)&blackPalette[256], 0); - destPalette = &blackPalette[0]; - } - - // Initially restore the faded palette - _vm->_palette->setPalette(fadedPalette, 0, 256); - _vm->_viewManager->refreshAll(); - - // Restore the pixel data from the original screen - _vm->_scene->update(); - - // Handle the actual fading - fadeRange(_vm, fadedPalette, destPalette, GREEN_START, NORMAL_END, numSteps, delayAmount); - - _fading_in_progress = false; -} - -void Palette::fadeIn(int numSteps, uint delayAmount, RGBList *destPalette) { - fadeIn(numSteps, delayAmount, destPalette->data(), destPalette->size()); -} - -void Palette::fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numColors) { - if (_fading_in_progress) - return; - - _fading_in_progress = true; - RGB8 blackPalette[256]; - Common::fill((byte *)&blackPalette[0], (byte *)&blackPalette[256], 0); - - // Initially set the black palette - _vm->_palette->setPalette(blackPalette, 0, numColors); - - // Handle the actual fading - fadeRange(_vm, blackPalette, destPalette, 0, numColors - 1, numSteps, delayAmount); - - _fading_in_progress = false; -} - -RGB8 *Palette::decodeMadsPalette(Common::SeekableReadStream *palStream, int *numColors) { - *numColors = palStream->readUint16LE(); - assert(*numColors <= 252); - - RGB8 *palData = new RGB8[*numColors]; - Common::fill((byte *)&palData[0], (byte *)&palData[*numColors], 0); - - for (int i = 0; i < *numColors; ++i) { - byte r = palStream->readByte(); - byte g = palStream->readByte(); - byte b = palStream->readByte(); - palData[i].r = VGA_COLOR_TRANS(r); - palData[i].g = VGA_COLOR_TRANS(g); - palData[i].b = VGA_COLOR_TRANS(b); - - // The next 3 bytes are unused - palStream->skip(3); - } - - return palData; -} - -int Palette::setMadsPalette(Common::SeekableReadStream *palStream, int indexStart) { - int colorCount; - RGB8 *palData = Palette::decodeMadsPalette(palStream, &colorCount); - _vm->_palette->setPalette(palData, indexStart, colorCount); - delete palData; - return colorCount; -} - -void Palette::setMadsSystemPalette() { - // Rex Nebular default system palette - resetColorCounts(); - - RGB8 palData[4]; - palData[0].r = palData[0].g = palData[0].b = 0; - palData[1].r = palData[1].g = palData[1].b = 0x54; - palData[2].r = palData[2].g = palData[2].b = 0xb4; - palData[3].r = palData[3].g = palData[3].b = 0xff; - - setPalette(palData, 0, 4); - blockRange(0, 4); -} - -void Palette::resetColorCounts() { - Common::fill(&_usageCount[0], &_usageCount[256], 0); -} - -void Palette::blockRange(int startIndex, int size) { - // Use a reference count of -1 to signal a palette index shouldn't be used - Common::fill(&_usageCount[startIndex], &_usageCount[startIndex + size], -1); -} - -void Palette::addRange(RGBList *list) { - RGB8 *data = list->data(); - byte *palIndexes = list->palIndexes(); - RGB8 palData[256]; - g_system->getPaletteManager()->grabPalette((byte *)&palData[0], 0, 256); - bool paletteChanged = false; - - for (int colIndex = 0; colIndex < list->size(); ++colIndex) { - // Scan through for an existing copy of the RGB value - int palIndex = -1; - while (++palIndex < 256) { - if (_usageCount[palIndex] <= 0) - // Palette index is to be skipped - continue; - - if ((palData[palIndex].r == data[colIndex].r) && - (palData[palIndex].g == data[colIndex].g) && - (palData[palIndex].b == data[colIndex].b)) - // Match found - break; - } - - if (palIndex == 256) { - // No match found, so find a free slot to use - palIndex = -1; - while (++palIndex < 256) { - if (_usageCount[palIndex] == 0) - break; - } - - if (palIndex == 256) - error("addRange - Ran out of palette space to allocate"); - - palData[palIndex].r = data[colIndex].r; - palData[palIndex].g = data[colIndex].g; - palData[palIndex].b = data[colIndex].b; - paletteChanged = true; - } - - palIndexes[colIndex] = palIndex; - ++_usageCount[palIndex]; - } - - if (paletteChanged) { - g_system->getPaletteManager()->setPalette((byte *)&palData[0], 0, 256); - reset(); - } -} - -void Palette::deleteRange(RGBList *list) { - // Release the reference count on each of the palette entries - for (int colIndex = 0; colIndex < list->size(); ++colIndex) { - int palIndex = list->palIndexes()[colIndex]; - assert(_usageCount[palIndex] > 0); - --_usageCount[palIndex]; - } -} - -void Palette::deleteAllRanges() { - for (int colIndex = 0; colIndex < 255; ++colIndex) - _usageCount[colIndex] = 0; -} - -//-------------------------------------------------------------------------- -// Support methods - -void decompressRle(byte *rleData, int rleSize, byte *celData, int w, int h) { - byte *src = rleData; - byte *dst = celData; - byte len; - while (1) { - len = *src++; - if (len == 0) { - len = *src++; - if (len <= 2) { - if (len == 1) // end of sprite marker - break; - } else { - while (len--) - *dst++ = *src++; - } - } else { - while (len--) - *dst++ = *src; - src++; - } - } -} - -int scaleValue(int value, int scale, int err) { - int scaled = 0; - while (value--) { - err -= scale; - while (err < 0) { - scaled++; - err += 100; - } - } - return scaled; -} - -} // End of namespace M4 |