diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/costume.cpp | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/costume.cpp')
-rw-r--r-- | engines/scumm/costume.cpp | 1160 |
1 files changed, 1160 insertions, 0 deletions
diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp new file mode 100644 index 0000000000..48f81111c6 --- /dev/null +++ b/engines/scumm/costume.cpp @@ -0,0 +1,1160 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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/stdafx.h" +#include "scumm/scumm.h" +#include "scumm/actor.h" +#include "scumm/costume.h" +#include "scumm/sound.h" +#include "scumm/util.h" + +namespace Scumm { + +#ifdef PALMOS_68K +const byte *smallCostumeScaleTable; +#else +const byte smallCostumeScaleTable[256] = { + 0xFF, 0xFD, 0x7D, 0xBD, 0x3D, 0xDD, 0x5D, 0x9D, + 0x1D, 0xED, 0x6D, 0xAD, 0x2D, 0xCD, 0x4D, 0x8D, + 0x0D, 0xF5, 0x75, 0xB5, 0x35, 0xD5, 0x55, 0x95, + 0x15, 0xE5, 0x65, 0xA5, 0x25, 0xC5, 0x45, 0x85, + 0x05, 0xF9, 0x79, 0xB9, 0x39, 0xD9, 0x59, 0x99, + 0x19, 0xE9, 0x69, 0xA9, 0x29, 0xC9, 0x49, 0x89, + 0x09, 0xF1, 0x71, 0xB1, 0x31, 0xD1, 0x51, 0x91, + 0x11, 0xE1, 0x61, 0xA1, 0x21, 0xC1, 0x41, 0x81, + 0x01, 0xFB, 0x7B, 0xBB, 0x3B, 0xDB, 0x5B, 0x9B, + 0x1B, 0xEB, 0x6B, 0xAB, 0x2B, 0xCB, 0x4B, 0x8B, + 0x0B, 0xF3, 0x73, 0xB3, 0x33, 0xD3, 0x53, 0x93, + 0x13, 0xE3, 0x63, 0xA3, 0x23, 0xC3, 0x43, 0x83, + 0x03, 0xF7, 0x77, 0xB7, 0x37, 0xD7, 0x57, 0x97, + 0x17, 0xE7, 0x67, 0xA7, 0x27, 0xC7, 0x47, 0x87, + 0x07, 0xEF, 0x6F, 0xAF, 0x2F, 0xCF, 0x4F, 0x8F, + 0x0F, 0xDF, 0x5F, 0x9F, 0x1F, 0xBF, 0x3F, 0x7F, + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE +}; +#endif + +static const int v1MMNESLookup[25] = { + 0x00, 0x03, 0x01, 0x06, 0x08, + 0x02, 0x00, 0x07, 0x0C, 0x04, + 0x09, 0x0A, 0x12, 0x0B, 0x14, + 0x0D, 0x11, 0x0F, 0x0E, 0x10, + 0x17, 0x00, 0x01, 0x05, 0x16 +}; + + +byte ClassicCostumeRenderer::mainRoutine(int xmoveCur, int ymoveCur) { + int i, skip = 0; + byte drawFlag = 1; + bool use_scaling; + byte startScaleIndexX; + int ex1, ex2; + Common::Rect rect; + int step; + Codec1 v1; + + + const int scaletableSize = 128; + const bool newAmiCost = (_vm->_version == 5) && (_vm->_platform == Common::kPlatformAmiga); + + CHECK_HEAP + + v1.scaletable = smallCostumeScaleTable; + + if (_loaded._numColors == 32) { + v1.mask = 7; + v1.shr = 3; + } else { + v1.mask = 15; + v1.shr = 4; + } + + switch (_loaded._format) { + case 0x60: + case 0x61: + // This format is used e.g. in the Sam&Max intro + ex1 = _srcptr[0]; + ex2 = _srcptr[1]; + _srcptr += 2; + if (ex1 != 0xFF || ex2 != 0xFF) { + ex1 = READ_LE_UINT16(_loaded._frameOffsets + ex1 * 2); + _srcptr = _loaded._baseptr + READ_LE_UINT16(_loaded._baseptr + ex1 + ex2 * 2) + 14; + } + } + + use_scaling = (_scaleX != 0xFF) || (_scaleY != 0xFF); + + v1.x = _actorX; + v1.y = _actorY; + + if (use_scaling) { + + /* Scale direction */ + v1.scaleXstep = -1; + if (xmoveCur < 0) { + xmoveCur = -xmoveCur; + v1.scaleXstep = 1; + } + + if (_mirror) { + /* Adjust X position */ + startScaleIndexX = _scaleIndexX = scaletableSize - xmoveCur; + for (i = 0; i < xmoveCur; i++) { + if (v1.scaletable[_scaleIndexX++] < _scaleX) + v1.x -= v1.scaleXstep; + } + + rect.left = rect.right = v1.x; + + _scaleIndexX = startScaleIndexX; + for (i = 0; i < _width; i++) { + if (rect.right < 0) { + skip++; + startScaleIndexX = _scaleIndexX; + } + if (v1.scaletable[_scaleIndexX++] < _scaleX) + rect.right++; + } + } else { + /* No mirror */ + /* Adjust X position */ + startScaleIndexX = _scaleIndexX = xmoveCur + scaletableSize; + for (i = 0; i < xmoveCur; i++) { + if (v1.scaletable[_scaleIndexX--] < _scaleX) + v1.x += v1.scaleXstep; + } + + rect.left = rect.right = v1.x; + + _scaleIndexX = startScaleIndexX; + for (i = 0; i < _width; i++) { + if (rect.left >= _out.w) { + startScaleIndexX = _scaleIndexX; + skip++; + } + if (v1.scaletable[_scaleIndexX--] < _scaleX) + rect.left--; + } + } + _scaleIndexX = startScaleIndexX; + + if (skip) + skip--; + + step = -1; + if (ymoveCur < 0) { + ymoveCur = -ymoveCur; + step = 1; + } + + _scaleIndexY = scaletableSize - ymoveCur; + for (i = 0; i < ymoveCur; i++) { + if (v1.scaletable[_scaleIndexY++] < _scaleY) + v1.y -= step; + } + + rect.top = rect.bottom = v1.y; + _scaleIndexY = scaletableSize - ymoveCur; + for (i = 0; i < _height; i++) { + if (v1.scaletable[_scaleIndexY++] < _scaleY) + rect.bottom++; + } + + _scaleIndexY = scaletableSize - ymoveCur; + } else { + if (!_mirror) + xmoveCur = -xmoveCur; + + v1.x += xmoveCur; + v1.y += ymoveCur; + + if (_mirror) { + rect.left = v1.x; + rect.right = v1.x + _width; + } else { + rect.left = v1.x - _width; + rect.right = v1.x; + } + + rect.top = v1.y; + rect.bottom = rect.top + _height; + + } + + v1.skip_width = _width; + v1.scaleXstep = _mirror ? 1 : -1; + + if (_vm->_version == 1) + // V1 games uses 8 x 8 pixels for actors + _vm->markRectAsDirty(kMainVirtScreen, rect.left, rect.right + 8, rect.top, rect.bottom, _actorID); + else + _vm->markRectAsDirty(kMainVirtScreen, rect.left, rect.right + 1, rect.top, rect.bottom, _actorID); + + if (rect.top >= _out.h || rect.bottom <= 0) + return 0; + + if (rect.left >= _out.w || rect.right <= 0) + return 0; + + v1.replen = 0; + + if (_mirror) { + if (!use_scaling) + skip = -v1.x; + if (skip > 0) { + if (!newAmiCost && _loaded._format != 0x57) { + v1.skip_width -= skip; + codec1_ignorePakCols(v1, skip); + v1.x = 0; + } + } else { + skip = rect.right - _out.w; + if (skip <= 0) { + drawFlag = 2; + } else { + v1.skip_width -= skip; + } + } + } else { + if (!use_scaling) + skip = rect.right - _out.w; + if (skip > 0) { + if (!newAmiCost && _loaded._format != 0x57) { + v1.skip_width -= skip; + codec1_ignorePakCols(v1, skip); + v1.x = _out.w - 1; + } + } else { + // V1 games uses 8 x 8 pixels for actors + if (_loaded._format == 0x57) + skip = -8 - rect.left; + else + skip = -1 - rect.left; + if (skip <= 0) + drawFlag = 2; + else + v1.skip_width -= skip; + } + } + + if (v1.skip_width <= 0) + return 0; + + if (rect.left < 0) + rect.left = 0; + + if (rect.top < 0) + rect.top = 0; + + if (rect.top > _out.h) + rect.top = _out.h; + + if (rect.bottom > _out.h) + rect.bottom = _out.h; + + if (_draw_top > rect.top) + _draw_top = rect.top; + if (_draw_bottom < rect.bottom) + _draw_bottom = rect.bottom; + + if (_height + rect.top >= 256) { + CHECK_HEAP + return 2; + } + + v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x; + + v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, _zbuf); + + CHECK_HEAP + + if (_loaded._format == 0x57) { + // The v1 costume renderer needs the actor number, which is + // the same thing as the costume renderer's _actorID. + procC64(v1, _actorID); + } else if (newAmiCost) + proc3_ami(v1); + else + proc3(v1); + + CHECK_HEAP + return drawFlag; +} + +static const int v1MMActorPalatte1[25] = { + 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; +static const int v1MMActorPalatte2[25] = { + 0, 7, 2, 6, 9, 1, 3, 7, 7, 1, 1, 9, 1, 4, 5, 5, 4, 1, 0, 5, 4, 2, 2, 7, 7 +}; + +#define MASK_AT(xoff) \ + (mask && (mask[((v1.x + xoff) / 8)] & revBitMask((v1.x + xoff) & 7))) +#define LINE(c,p) \ + pcolor = (color >> c) & 3; \ + if (pcolor) { \ + if (!MASK_AT(p)) \ + dst[p] = palette[pcolor]; \ + if (!MASK_AT(p + 1)) \ + dst[p + 1] = palette[pcolor]; \ + } + +void ClassicCostumeRenderer::procC64(Codec1 &v1, int actor) { + const byte *mask, *src; + byte *dst; + byte len; + int y; + uint height; + byte color, pcolor; + bool rep; + + y = v1.y; + src = _srcptr; + dst = v1.destptr; + len = v1.replen; + color = v1.repcolor; + height = _height; + + v1.skip_width /= 8; + + // Set up the palette data + byte palette[4] = { 0, 0, 0, 0 }; + if (!(_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_color)) { + palette[2] = 11; + palette[3] = 11; + } else if (_vm->_gameId == GID_MANIAC) { + palette[1] = v1MMActorPalatte1[actor]; + palette[2] = v1MMActorPalatte2[actor]; + } else { + palette[1] = (_vm->_platform == Common::kPlatformC64) ? 10 : 8; + palette[2] = _palette[actor]; + } + mask = v1.mask_ptr; + + if (len) + goto StartPos; + + do { + len = *src++; + if (len & 0x80) + color = *src++; + StartPos:; + rep = (len & 0x80) != 0; + len &= 0x7f; + while (len--) { + if (!rep) + color = *src++; + + if (0 <= y && y < _out.h && 0 <= v1.x && v1.x < _out.w) { + if (!_mirror) { + LINE(0, 0); LINE(2, 2); LINE(4, 4); LINE(6, 6); + } else { + LINE(6, 0); LINE(4, 2); LINE(2, 4); LINE(0, 6); + } + } + dst += _out.pitch; + y++; + mask += _numStrips; + if (!--height) { + if (!--v1.skip_width) + return; + height = _height; + y = v1.y; + v1.x += 8 * v1.scaleXstep; + if (v1.x < 0 || v1.x >= _out.w) + return; + mask = v1.mask_ptr; + v1.destptr += 8 * v1.scaleXstep; + dst = v1.destptr; + } + } + } while (1); +} + +#undef LINE +#undef MASK_AT + +void ClassicCostumeRenderer::proc3(Codec1 &v1) { + const byte *mask, *src; + byte *dst; + byte len, maskbit; + int y; + uint color, height, pcolor; + const byte *scaleytab; + bool masked; + + y = v1.y; + src = _srcptr; + dst = v1.destptr; + len = v1.replen; + color = v1.repcolor; + height = _height; + + scaleytab = &v1.scaletable[_scaleIndexY]; + maskbit = revBitMask(v1.x & 7); + mask = v1.mask_ptr + v1.x / 8; + + if (len) + goto StartPos; + + do { + len = *src++; + color = len >> v1.shr; + len &= v1.mask; + if (!len) + len = *src++; + + do { + if (_scaleY == 255 || *scaleytab++ < _scaleY) { + masked = (y < 0 || y >= _out.h) || (v1.mask_ptr && (mask[0] & maskbit)); + + if (color && !masked) { + if (_shadow_mode & 0x20) { + pcolor = _shadow_table[*dst]; + } else { + pcolor = _palette[color]; + if (pcolor == 13 && _shadow_table) + pcolor = _shadow_table[*dst]; + } + *dst = pcolor; + } + dst += _out.pitch; + mask += _numStrips; + y++; + } + if (!--height) { + if (!--v1.skip_width) + return; + height = _height; + y = v1.y; + + scaleytab = &v1.scaletable[_scaleIndexY]; + + if (_scaleX == 255 || v1.scaletable[_scaleIndexX] < _scaleX) { + v1.x += v1.scaleXstep; + if (v1.x < 0 || v1.x >= _out.w) + return; + maskbit = revBitMask(v1.x & 7); + v1.destptr += v1.scaleXstep; + } + _scaleIndexX += v1.scaleXstep; + dst = v1.destptr; + mask = v1.mask_ptr + v1.x / 8; + } + StartPos:; + } while (--len); + } while (1); +} + +void ClassicCostumeRenderer::proc3_ami(Codec1 &v1) { + const byte *mask, *src; + byte *dst; + byte maskbit, len, height, width; + int color; + int y; + bool masked; + int oldXpos, oldScaleIndexX; + + mask = v1.mask_ptr + v1.x / 8; + dst = v1.destptr; + height = _height; + width = _width; + src = _srcptr; + maskbit = revBitMask(v1.x & 7); + y = v1.y; + oldXpos = v1.x; + oldScaleIndexX = _scaleIndexX; + + do { + len = *src++; + color = len >> v1.shr; + len &= v1.mask; + if (!len) + len = *src++; + do { + if (_scaleY == 255 || v1.scaletable[_scaleIndexY] < _scaleY) { + masked = (y < 0 || y >= _out.h) || (v1.mask_ptr && (mask[0] & maskbit)); + + if (color && v1.x >= 0 && v1.x < _out.w && !masked) { + *dst = _palette[color]; + } + + if (_scaleX == 255 || v1.scaletable[_scaleIndexX] < _scaleX) { + v1.x += v1.scaleXstep; + dst += v1.scaleXstep; + maskbit = revBitMask(v1.x & 7); + } + _scaleIndexX += v1.scaleXstep; + mask = v1.mask_ptr + v1.x / 8; + } + if (!--width) { + if (!--height) + return; + + if (y >= _out.h) + return; + + if (v1.x != oldXpos) { + dst += _out.pitch - (v1.x - oldXpos); + v1.mask_ptr += _numStrips; + mask = v1.mask_ptr + oldXpos / 8; + maskbit = revBitMask(oldXpos & 7); + y++; + } + width = _width; + v1.x = oldXpos; + _scaleIndexX = oldScaleIndexX; + _scaleIndexY++; + } + } while (--len); + } while (1); +} + +void ClassicCostumeLoader::loadCostume(int id) { + _id = id; + byte *ptr = _vm->getResourceAddress(rtCostume, id); + + if (_vm->_version >= 6) + ptr += 8; + else if (_vm->_features & GF_OLD_BUNDLE) + ptr += -2; + else if (_vm->_features & GF_SMALL_HEADER) + ptr += 0; + else + ptr += 2; + + _baseptr = ptr; + + _numAnim = ptr[6]; + _format = ptr[7] & 0x7F; + _mirror = (ptr[7] & 0x80) != 0; + _palette = ptr + 8; + switch (_format) { + case 0x57: // Only used in V1 games + _numColors = 0; + break; + case 0x58: + _numColors = 16; + break; + case 0x59: + _numColors = 32; + break; + case 0x60: // New since version 6 + _numColors = 16; + break; + case 0x61: // New since version 6 + _numColors = 32; + break; + default: + error("Costume %d with format 0x%X is invalid", id, _format); + } + + + // In GF_OLD_BUNDLE games, there is no actual palette, just a single color byte. + // Don't forget, these games were designed around a fixed 16 color HW palette :-) + // In addition, all offsets are shifted by 2; we accomodate that via a separate + // _baseptr value (instead of adding tons of if's throughout the code). + if (_vm->_features & GF_OLD_BUNDLE) { + _numColors = (_format == 0x57) ? 0 : 1; + _baseptr += 2; + } + ptr += 8 + _numColors; + _frameOffsets = ptr + 2; + if (_format == 0x57) { + _dataOffsets = ptr + 18; + _baseptr += 4; + } else { + _dataOffsets = ptr + 34; + } + _animCmds = _baseptr + READ_LE_UINT16(ptr); +} + +byte NESCostumeRenderer::drawLimb(const Actor *a, int limb) { + const byte darkpalette[16] = {0x00,0x00,0x2D,0x3D,0x00,0x00,0x2D,0x3D,0x00,0x00,0x2D,0x3D,0x00,0x00,0x2D,0x3D}; + const CostumeData &cost = a->_cost; + const byte *palette, *src, *sprdata; + int anim, frameNum, frame, offset, numSprites; + + // If the specified limb is stopped or not existing, do nothing. + if (cost.curpos[limb] == 0xFFFF) + return 0; + + if (_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_base) + palette = _vm->_NESPalette[1]; + else + palette = darkpalette; + + src = _loaded._dataOffsets; + anim = 4 * cost.frame[limb] + newDirToOldDir(a->getFacing()); + frameNum = cost.curpos[limb]; + frame = src[src[2 * anim] + frameNum]; + + offset = READ_LE_UINT16(_vm->_NEScostdesc + v1MMNESLookup[_loaded._id] * 2); + numSprites = _vm->_NEScostlens[offset + frame] + 1; + sprdata = _vm->_NEScostdata + READ_LE_UINT16(_vm->_NEScostoffs + 2 * (offset + frame)) + numSprites * 3; + + bool flipped = (newDirToOldDir(a->getFacing()) == 1); + int left = 239, right = 0, top = 239, bottom = 0; + byte *maskBuf = _vm->getMaskBuffer(0, 0, 1); + + for (int spr = 0; spr < numSprites; spr++) { + byte mask, tile, sprpal; + int8 y, x; + + sprdata -= 3; + + mask = (sprdata[0] & 0x80) ? 0x01 : 0x80; + y = sprdata[0] << 1; + y >>= 1; + + tile = sprdata[1]; + + sprpal = (sprdata[2] & 0x03) << 2; + x = sprdata[2]; + x >>= 2; + + if (flipped) { + mask = (mask == 0x80) ? 0x01 : 0x80; + x = -x; + } + + if ((_actorX + x < 0) || (_actorX + x + 8 >= _out.w)) + continue; + if ((_actorY + y < 0) || (_actorY + y + 8 >= _out.h)) + continue; + + for (int ty = 0; ty < 8; ty++) { + byte c1 = _vm->_NESPatTable[0][tile * 16 + ty]; + byte c2 = _vm->_NESPatTable[0][tile * 16 + ty + 8]; + + for (int tx = 0; tx < 8; tx++) { + unsigned char c = ((c1 & mask) ? 1 : 0) | ((c2 & mask) ? 2 : 0) | sprpal; + if (mask == 0x01) { + c1 >>= 1; + c2 >>= 1; + } else { + c1 <<= 1; + c2 <<= 1; + } + if (!(c & 3)) + continue; + int my = _actorY + y + ty; + int mx = _actorX + x + tx; + if (!(_zbuf && (maskBuf[my * _numStrips + mx / 8] & revBitMask(mx & 7)))) + *((byte *)_out.pixels + my * _out.pitch + mx) = palette[c]; + } + } + left = MIN(left, _actorX + x); + right = MAX(right, _actorX + x + 8); + top = MIN(top, _actorY + y); + bottom = MAX(bottom, _actorY + y + 8); + } + + _draw_top = top; + _draw_bottom = bottom; + + _vm->markRectAsDirty(kMainVirtScreen, left, right, top, bottom, _actorID); + + return 0; +} + +byte ClassicCostumeRenderer::drawLimb(const Actor *a, int limb) { + int i; + int code; + const byte *frameptr; + const CostumeData &cost = a->_cost; + + // If the specified limb is stopped or not existing, do nothing. + if (cost.curpos[limb] == 0xFFFF || cost.stopped & (1 << limb)) + return 0; + + // Determine the position the limb is at + i = cost.curpos[limb] & 0x7FFF; + + // Get the frame pointer for that limb + frameptr = _loaded._baseptr + READ_LE_UINT16(_loaded._frameOffsets + limb * 2); + + // Determine the offset to the costume data for the limb at position i + code = _loaded._animCmds[i] & 0x7F; + + // Code 0x7B indicates a limb for which there is nothing to draw + if (code != 0x7B) { + _srcptr = _loaded._baseptr + READ_LE_UINT16(frameptr + code * 2); + + if (!(_vm->_features & GF_OLD256) || code < 0x79) { + const CostumeInfo *costumeInfo; + int xmoveCur, ymoveCur; + + if (_loaded._format == 0x57) { + _width = _srcptr[0] * 8; + _height = _srcptr[1]; + xmoveCur = _xmove + (int8)_srcptr[2] * 8; + ymoveCur = _ymove - (int8)_srcptr[3]; + _xmove += (int8)_srcptr[4] * 8; + _ymove -= (int8)_srcptr[5]; + _srcptr += 6; + } else { + costumeInfo = (const CostumeInfo *)_srcptr; + _width = READ_LE_UINT16(&costumeInfo->width); + _height = READ_LE_UINT16(&costumeInfo->height); + xmoveCur = _xmove + (int16)READ_LE_UINT16(&costumeInfo->rel_x); + ymoveCur = _ymove + (int16)READ_LE_UINT16(&costumeInfo->rel_y); + _xmove += (int16)READ_LE_UINT16(&costumeInfo->move_x); + _ymove -= (int16)READ_LE_UINT16(&costumeInfo->move_y); + _srcptr += 12; + } + + return mainRoutine(xmoveCur, ymoveCur); + } + } + + return 0; + +} + +void NESCostumeRenderer::setPalette(byte *palette) { + // TODO +} + +void NESCostumeRenderer::setFacing(const Actor *a) { + // TODO + //_mirror = newDirToOldDir(a->getFacing()) != 0 || _loaded._mirror; +} + +void NESCostumeRenderer::setCostume(int costume, int shadow) { + _loaded.loadCostume(costume); +} + +void ClassicCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { + const byte *r; + uint mask, j; + int i; + byte extra, cmd; + int anim; + + loadCostume(a->_costume); + + anim = newDirToOldDir(a->getFacing()) + frame * 4; + + if (anim > _numAnim) { + return; + } + + r = _baseptr + READ_LE_UINT16(_dataOffsets + anim * 2); + + if (r == _baseptr) { + return; + } + + if (_vm->_version == 1) { + mask = *r++ << 8; + } else { + mask = READ_LE_UINT16(r); + r += 2; + } + i = 0; + do { + if (mask & 0x8000) { + if (_vm->_version <= 3) { + j = *r++; + + if (j == 0xFF) + j = 0xFFFF; + } else { + j = READ_LE_UINT16(r); + r += 2; + } + if (usemask & 0x8000) { + if (j == 0xFFFF) { + a->_cost.curpos[i] = 0xFFFF; + a->_cost.start[i] = 0; + a->_cost.frame[i] = frame; + } else { + extra = *r++; + cmd = _animCmds[j]; + if (cmd == 0x7A) { + a->_cost.stopped &= ~(1 << i); + } else if (cmd == 0x79) { + a->_cost.stopped |= (1 << i); + } else { + a->_cost.curpos[i] = a->_cost.start[i] = j; + a->_cost.end[i] = j + (extra & 0x7F); + if (extra & 0x80) + a->_cost.curpos[i] |= 0x8000; + a->_cost.frame[i] = frame; + } + } + } else { + if (j != 0xFFFF) + r++; + } + } + i++; + usemask <<= 1; + mask <<= 1; + } while (mask&0xFFFF); +} + +void ClassicCostumeRenderer::setPalette(byte *palette) { + int i; + byte color; + + if (_loaded._format == 0x57) { + memcpy(_palette, palette, 13); + } else if (_vm->_features & GF_OLD_BUNDLE) { + if ((_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_color)) { + memcpy(_palette, palette, 16); + } else { + memset(_palette, 8, 16); + _palette[12] = 0; + } + _palette[_loaded._palette[0]] = _palette[0]; + } else { + if ((_vm->VAR_CURRENT_LIGHTS == 0xFF) || (_vm->VAR(_vm->VAR_CURRENT_LIGHTS) & LIGHTMODE_actor_color)) { + for (i = 0; i < _loaded._numColors; i++) { + color = palette[i]; + if (color == 255) + color = _loaded._palette[i]; + _palette[i] = color; + } + } else { + memset(_palette, 8, _loaded._numColors); + _palette[12] = 0; + } + } +} + +void ClassicCostumeRenderer::setFacing(const Actor *a) { + _mirror = newDirToOldDir(a->getFacing()) != 0 || _loaded._mirror; +} + +void ClassicCostumeRenderer::setCostume(int costume, int shadow) { + _loaded.loadCostume(costume); +} + +byte ClassicCostumeLoader::increaseAnims(Actor *a) { + int i; + byte r = 0; + + for (i = 0; i != 16; i++) { + if (a->_cost.curpos[i] != 0xFFFF) + r += increaseAnim(a, i); + } + return r; +} + +byte ClassicCostumeLoader::increaseAnim(Actor *a, int slot) { + int highflag; + int i, end; + byte code, nc; + + if (a->_cost.curpos[slot] == 0xFFFF) + return 0; + + highflag = a->_cost.curpos[slot] & 0x8000; + i = a->_cost.curpos[slot] & 0x7FFF; + end = a->_cost.end[slot]; + code = _animCmds[i] & 0x7F; + + if (_vm->_version <= 3) { + if (_animCmds[i] & 0x80) + a->_cost.soundCounter++; + } + + do { + if (!highflag) { + if (i++ >= end) + i = a->_cost.start[slot]; + } else { + if (i != end) + i++; + } + nc = _animCmds[i]; + + if (nc == 0x7C) { + a->_cost.animCounter++; + if (a->_cost.start[slot] != end) + continue; + } else { + if (_vm->_version >= 6) { + if (nc >= 0x71 && nc <= 0x78) { + uint sound = (_vm->_heversion == 60) ? 0x78 - nc : nc - 0x71; + _vm->_sound->addSoundToQueue2(a->_sound[sound]); + if (a->_cost.start[slot] != end) + continue; + } + } else { + if (nc == 0x78) { + a->_cost.soundCounter++; + if (a->_cost.start[slot] != end) + continue; + } + } + } + + a->_cost.curpos[slot] = i | highflag; + return (_animCmds[i] & 0x7F) != code; + } while (1); +} + +/** + * costume ID -> v1MMNESLookup[] -> desc -> lens & offs -> data -> Gfx & pal + */ +void NESCostumeLoader::loadCostume(int id) { + _id = id; + _baseptr = _vm->getResourceAddress(rtCostume, id); + _dataOffsets = _baseptr + 2; + _numAnim = 0x17; +} + +void NESCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { + int anim; + + loadCostume(a->_costume); + + anim = 4 * frame + newDirToOldDir(a->getFacing()); + + if (anim > _numAnim) { + return; + } + + a->_cost.curpos[0] = 0; + a->_cost.start[0] = 0; + a->_cost.end[0] = _dataOffsets[2 * anim + 1]; + a->_cost.frame[0] = frame; +} + +byte NESCostumeLoader::increaseAnims(Actor *a) { + int i; + byte r = 0; + + for (i = 0; i != 16; i++) { + if (a->_cost.curpos[i] != 0xFFFF) + r += increaseAnim(a, i); + } + return r; +} + +byte NESCostumeLoader::increaseAnim(Actor *a, int slot) { + int oldframe = a->_cost.curpos[slot]++; + if (a->_cost.curpos[slot] >= a->_cost.end[slot]) + a->_cost.curpos[slot] = a->_cost.start[slot]; + return (a->_cost.curpos[slot] != oldframe); +} + +static const byte actorColorsMMC64[] = { + 0, 7, 2, 6, 9, 1, 3, 7, 7, 1, 1, 9, 1, 4, 5, 5, + 4, 1, 0, 5, 4, 2, 2, 7, 7, 0, 6, 6, 6, 6, 6, 6 +}; + +byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { + if (limb >= 8) + return 0; + + if (limb == 0) { + _draw_top = 200; + _draw_bottom = 0; + } + + // TODO: + // get out how animations are handled + byte state = a->_moving != 0 ? 0 : 1; + byte unk1 = (_loaded._animCmds + (state*32) + newDirToOldDir(a->getFacing()) * 8)[limb]; + byte unk2 = _loaded._frameOffsets[_loaded._frameOffsets[limb] + (unk1 & 0x7f)]; + bool flipped = (unk1 & 0x80) != 0; + + byte p1 = _loaded._frameOffsets[unk2]; + byte temp1 = _loaded._baseptr[p1]; + byte temp2 = temp1 + _loaded._dataOffsets[4]; + int offL = _loaded._baseptr[temp1 + 2]; + int offH = _loaded._baseptr[temp2]; + int off = (offH << 8) + offL; + + const byte *data = _loaded._baseptr + off; + const byte actorColors[] = { + 0, 10, actorColorsMMC64[_actorID], 0 + }; + + int width = *data++; + int height = *data++; + int offsetX = *data++; + int offsetY = *data++; + // these two fields seems to be most times zero + // byte6 was one time 255 in one costume I tried +// int byte5 = *data++; +// int byte6 = *data++; +// debug(3, "byte5: %d", byte5); +// debug(3, "byte6: %d", byte6); + data += 2; + + if (!width || !height) + return 0; + + int xpos = 0; + int ypos = _loaded._maxHeight - offsetY; + + if (flipped) { + if (offsetX) + xpos += (offsetX-1) * 8; + } else { + xpos += offsetX * 8; + } + + // + 4 could be commented, because maybe the _actorX position is + // wrong, I looked at the scumm-c64 interpreter by lloyd + // and there Bernhard is directly on the right in the intro + // but here in ScummVM he is 4 pixel left of the other position. + xpos += _actorX - (a->_width / 2) + 4; + ypos += _actorY - _loaded._maxHeight; + + if (flipped) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + byte c = data[y*width+x]; + byte b, d; + int realX = 0; + if (offsetX == 0||offsetX == 1) { + realX = width-(x+1); + } else if (offsetX == 2) { + realX = width-(x+2); + } + byte *dest = &(((byte*)_out.pixels)[((y + ypos) * _out.pitch) + ((realX * 8) + xpos)]); + + for (int i = 0; i <= 6; i += 2) { + if ((d = (c >> i) & 0x03)) { + b = actorColors[d]; + *dest++ = b; + *dest++ = b; + continue; + } + dest += 2; + } + } + } + } else { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + byte c = data[y*width+x]; + byte b, d; + byte *dest = &(((byte*)_out.pixels)[((y + ypos) * _out.pitch) + ((x * 8) + xpos)]); + + for (int i = 6; i >= 0; i -= 2) { + if ((d = (c >> i) & 0x03)) { + b = actorColors[d]; + *dest++ = b; + *dest++ = b; + continue; + } + dest += 2; + } + } + } + } + + _draw_top = MIN(_draw_top, ypos); + _draw_bottom = MAX(_draw_bottom, ypos+height); + // if +4 above is NOT commented, here "+(flipped ? 4 : 0)" can be commented out + // and other way round + _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos+(width*8)/*+(flipped ? 4 : 0)*/, ypos, ypos+height, _actorID); + + return 0; +} + +void C64CostumeRenderer::setCostume(int costume, int shadow) { + _loaded.loadCostume(costume); +} + +void C64CostumeLoader::loadCostume(int id) { + const byte *ptr = _vm->getResourceAddress(rtCostume, id); + _id = id; + _baseptr = ptr + 9; + + _format = 0x57; + _numColors = 0; + _numAnim = 0; + _mirror = 0; + _palette = &actorColorsMMC64[id]; + + _frameOffsets = _baseptr + READ_LE_UINT16(ptr + 5); + _dataOffsets = ptr; + _animCmds = _baseptr + READ_LE_UINT16(ptr + 7); + + _maxHeight = 0; + for (int i = 0; i < 8; ++i) { + int pid = _frameOffsets[_frameOffsets[i]]; + byte p1 = _frameOffsets[pid]; + byte b = _baseptr[p1]; + byte c = b + _dataOffsets[4]; + int offL = _baseptr[b + 2]; + int offH = _baseptr[c]; + int off = (offH << 8) + offL; + const byte *data = _baseptr + off; + + if (data[3] > _maxHeight) { + _maxHeight = data[3]; // data[3] is libs's Y offset + } + } + ++_maxHeight; +} + +void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { +} + +byte C64CostumeLoader::increaseAnims(Actor *a) { + return 0; +} + +byte C64CostumeLoader::increaseAnim(Actor *a, int slot) { + return 0; +} + + +} // End of namespace Scumm + +#ifdef PALMOS_68K +#include "scumm_globals.h" + +_GINIT(Costume) +_GSETPTR(Scumm::smallCostumeScaleTable, GBVARS_SMALLSCALETABLE_INDEX, byte, GBVARS_SCUMM) +_GEND + +_GRELEASE(Costume) +_GRELEASEPTR(GBVARS_SMALLSCALETABLE_INDEX, GBVARS_SCUMM) +_GEND + +#endif |