diff options
author | Max Horn | 2003-09-09 17:29:22 +0000 |
---|---|---|
committer | Max Horn | 2003-09-09 17:29:22 +0000 |
commit | 07e8084eee1b0397b78aa6ee300855d1a1963503 (patch) | |
tree | abe08649eb0c43447e68a28c186a618d57f2b9c5 | |
parent | 163ecdc05406edd90dd4b336f23a8853a4b518d8 (diff) | |
download | scummvm-rg350-07e8084eee1b0397b78aa6ee300855d1a1963503.tar.gz scummvm-rg350-07e8084eee1b0397b78aa6ee300855d1a1963503.tar.bz2 scummvm-rg350-07e8084eee1b0397b78aa6ee300855d1a1963503.zip |
replaced all use of scale items with scale slots. This allowed me to get rid of two big FIXME's, and might fix other scaling bugs in FT/DIG
svn-id: r10140
-rw-r--r-- | scumm/actor.cpp | 41 | ||||
-rw-r--r-- | scumm/boxes.cpp | 139 | ||||
-rw-r--r-- | scumm/saveload.cpp | 9 | ||||
-rw-r--r-- | scumm/saveload.h | 2 | ||||
-rw-r--r-- | scumm/script_v5.cpp | 2 | ||||
-rw-r--r-- | scumm/scumm.h | 1 | ||||
-rw-r--r-- | scumm/scummvm.cpp | 28 |
7 files changed, 86 insertions, 136 deletions
diff --git a/scumm/actor.cpp b/scumm/actor.cpp index f451c890e6..e59dae2ffd 100644 --- a/scumm/actor.cpp +++ b/scumm/actor.cpp @@ -412,47 +412,10 @@ void Actor::setupActorScale() { return; scale = _vm->getScale(walkbox, x, y); - if (_vm->_version == 8) { - // At least in COMI, scale values are clipped to range 1-255 - if (scale < 1) - scale = 1; - else if (scale > 255) - scale = 255; - } - - // FIXME - Hack for The Dig 'Tomb' (room 88) - // Otherwise walking to the far-left door causes the actor - // to shrink to a one-pixel dot. The reason for this is that - // scale items (as handled in setScaleItem etc.) are only - // working as long as the room height is <= 200!!! That's a - // serious problem for DIG/FT, and causes the FIXME below, too. - // A way to properly fix the problem would be to use the - // V8 "scale slots" instead. This would be almost perfect, the - // only problem being that it might render some old savegames - // partially broken... - if (_vm->_gameId == GID_DIG && _vm->_currentRoom == 88) { - scale = 0xFF; - } - - - // FIXME - Quick fix to ft's fuel tower bug (by yazoo) - // - // Ben's Y position can be anything between 272 and 398 inclusive - // (which by the way means that we're always looking at the same - // element in the scale table... hmmm...) - // - // When standing at the bottom of the ladder, Ben's Y position is - // 356, and by the looks of it he ought to be unscaled there. - - if (_vm->_gameId == GID_FT && scale == 1 && _vm->_currentRoom == 76) { - scale = 0xff; - if (y < 356) - scale -= 2 * (356 - y); - } - if (scale > 255) { - warning("Actor %d at %d, scale %d out of range", number, y, scale); + warning("Actor %d at %d, scale %d out of range", number, y, scale); } + scalex = (byte)scale; scaley = (byte)scale; } diff --git a/scumm/boxes.cpp b/scumm/boxes.cpp index 4376107169..325d66d364 100644 --- a/scumm/boxes.cpp +++ b/scumm/boxes.cpp @@ -155,53 +155,58 @@ int Scumm::getScale(int box, int x, int y) { Box *ptr = getBoxBaseAddr(box); if (!ptr) return 255; + + int slot , scale; if (_version == 8) { - int slot = FROM_LE_32(ptr->v8.scaleSlot); - if (slot) { - assert(1 <= slot && slot <= ARRAYSIZE(_scaleSlots)); - int scaleX = 0, scaleY = 0; - ScaleSlot &s = _scaleSlots[slot-1]; - - if (s.y1 == s.y2 && s.x1 == s.x2) - error("Invalid scale slot %d", slot); - - if (s.y1 != s.y2) { - if (y < 0) - y = 0; - - scaleY = (s.scale2 - s.scale1) * (y - s.y1) / (s.y2 - s.y1) + s.scale1; - if (s.x1 == s.x2) { - return scaleY; - } - } + // COMI has a separate field for the scale slot... + slot = FROM_LE_32(ptr->v8.scaleSlot); + scale = FROM_LE_32(ptr->v8.scale); + } else { + scale = READ_LE_UINT16(&ptr->old.scale); + if (scale & 0x8000) + slot = (scale & 0x7FFF) + 1; + else + slot = 0; + } + + // Was a scale slot specified? If so, we compute the effective scale + // from it, ignoring the box scale. + if (slot) { + assert(1 <= slot && slot <= ARRAYSIZE(_scaleSlots)); + int scaleX = 0, scaleY = 0; + ScaleSlot &s = _scaleSlots[slot-1]; + + if (s.y1 == s.y2 && s.x1 == s.x2) + error("Invalid scale slot %d", slot); + + if (s.y1 != s.y2) { + if (y < 0) + y = 0; + scaleY = (s.scale2 - s.scale1) * (y - s.y1) / (s.y2 - s.y1) + s.scale1; + } + if (s.x1 == s.x2) { + scale = scaleY; + } else { scaleX = (s.scale2 - s.scale1) * (x - s.x1) / (s.x2 - s.x1) + s.scale1; if (s.y1 == s.y2) { - return scaleX; + scale = scaleX; } else { - return (scaleX + scaleY - s.x1) / 2; + scale = (scaleX + scaleY - s.x1) / 2; } - } else - return FROM_LE_32(ptr->v8.scale); - } else { - uint16 scale = READ_LE_UINT16(&ptr->old.scale); - - if (scale & 0x8000) { - scale = (scale & 0x7FFF) + 1; - byte *resptr = getResourceAddress(rtScaleTable, scale); - if (resptr == NULL) - error("Scale table %d not defined", scale); - if (y >= _screenHeight) - y = _screenHeight - 1; - else if (y < 0) - y = 0; - scale = resptr[y]; } - - return scale; + + // Clip the scale to range 1-255 + if (scale < 1) + scale = 1; + else if (scale > 255) + scale = 255; } + + // Finally return the scale + return scale; } int Scumm::getBoxScale(int box) { @@ -216,60 +221,36 @@ int Scumm::getBoxScale(int box) { return READ_LE_UINT16(&ptr->old.scale); } -/* - FIXME: It seems that scale items and scale slots are the same thing after - all - they only differ in some details (scale item is used to precompute - a scale table, while for the scale slots the computations are done on the - fly; also for scale slots, the scale along the x axis can vary, too). - - Now, there are various known scale glitches in FT (and apparently also - in The Dig, see FIXME comments in Actor::setupActorScale). In this context - it is very interesting that for V5, there is an opcode which invokes - setScaleItem, and for V8 one that invokes setScaleSlot. But there is no - such opcode to be found for V6/V7 games. - - Hypothesis: we simple are missing this opcode, and implementing it might - fix some or all of the Dig/FT scaling issues. -*/ -void Scumm::setScaleItem(int slot, int y1, int scale1, int y2, int scale2) { - byte *ptr; - int y, tmp; - - if (y1 == y2) - return; - - ptr = createResource(rtScaleTable, slot, 200); - - for (y = 0; y < 200; y++) { - tmp = ((scale2 - scale1) * (y - y1)) / (y2 - y1) + scale1; - if (tmp < 1) - tmp = 1; - if (tmp > 255) - tmp = 255; - *ptr++ = tmp; - } -/* - // TEST! - printf("setScaleItem(%d, %d, %d, %d, %d)\n", slot, y1, scale1, y2, scale2); - convertScaleTableToScaleSlot(slot); -*/ -} - +/** + * Convert a rtScaleTable resource to a corresponding scale slot entry. + * + * At some point, we discovered that the old scale items (stored in rtScaleTable + * resources) are in fact the same as (or rather, a predecessor of) the + * scale slots used in COMI. While not being precomputed (and thus slightly + * slower), they are more flexible, and most importantly, can cope with + * rooms higher than 200 pixels. That's an essential feature for DIG and FT + * and in fact the lack of it caused various bugs in the past. + * + * Hence, we decided to switch all games to use the more powerful scale slots. + * To accomodate old savegames, we attempt here to convert rtScaleTable + * resources to scale slots. + */ void Scumm::convertScaleTableToScaleSlot(int slot) { assert(1 <= slot && slot <= ARRAYSIZE(_scaleSlots)); byte *resptr = getResourceAddress(rtScaleTable, slot); ScaleSlot &s = _scaleSlots[slot-1]; - int lowerIdx, upperIdx; float m, oldM; + // Do nothing if the given scale table doesn't exist + if (resptr == 0) + return; + if (resptr[0] == resptr[199]) { // The scale is constant This usually means we encountered one of the // "broken" cases. We set pseudo scale item values which lead to a // constant scale of 255. - // TODO - printf("Broken case!\n"); s.y1 = 0; s.y2 = 199; s.scale1 = s.scale2 = 255; diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index 5e06e851bd..89be05d0db 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -658,6 +658,15 @@ void Scumm::saveOrLoad(Serializer *s, uint32 savegameVersion) { } } + // With version 22, we replace the scale items with scale slots + if (savegameVersion < VER(22) && !s->isSaving()) { + // Convert all rtScaleTable resources to matching scale items + for (i = 1; i < res.num[rtScaleTable]; i++) { + convertScaleTableToScaleSlot(i); + } + } + + if (_imuse && (_saveSound || !_saveLoadCompatible)) { _imuse->save_or_load(s, this); _imuse->setMasterVolume(_sound->_sound_volume_master); diff --git a/scumm/saveload.h b/scumm/saveload.h index e20fc1237f..225d295c24 100644 --- a/scumm/saveload.h +++ b/scumm/saveload.h @@ -28,7 +28,7 @@ // Can be useful for other ports too :) #define VER(x) x -#define CURRENT_VER 21 +#define CURRENT_VER 22 // To work around a warning in GCC 3.2 (and 3.1 ?) regarding non-POD types, // we use a small trick: instead of 0 we use 42. Why? Well, it seems newer GCC diff --git a/scumm/script_v5.cpp b/scumm/script_v5.cpp index 5ff8e09a72..6e5f4c6be1 100644 --- a/scumm/script_v5.cpp +++ b/scumm/script_v5.cpp @@ -1867,7 +1867,7 @@ void Scumm_v5::o5_roomOps() { d = getVarOrDirectByte(0x40); _opcode = fetchScriptByte(); e = getVarOrDirectByte(0x40); - setScaleItem(e - 1, b, a, d, c); + setScaleSlot(e - 1, 0, b, a, 0, d, c); break; case 8: /* room scale? */ if (_features & GF_SMALL_HEADER) { diff --git a/scumm/scumm.h b/scumm/scumm.h index ec8020ab6e..41d5ad3b1c 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -1051,7 +1051,6 @@ public: int getBoxScale(int box); int getScale(int box, int x, int y); - void setScaleItem(int slot, int a, int b, int c, int d); protected: // Scaling slots/items diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index 35ecd61ea5..72fc298241 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -1996,7 +1996,7 @@ void Scumm::startScene(int room, Actor *a, int objectNr) { } void Scumm::initRoomSubBlocks() { - int i, offs; + int i; const byte *ptr; byte *roomptr, *searchptr, *roomResPtr; const RoomHeader *rmhd; @@ -2178,29 +2178,27 @@ void Scumm::initRoomSubBlocks() { // Load scale data // if (_features & GF_OLD_BUNDLE) - ptr = 0; // TODO ? + ptr = 0; else ptr = findResourceData(MKID('SCAL'), roomptr); if (ptr) { - offs = ptr - roomptr; int s1, s2, y1, y2; if (_version == 8) { - for (i = 1; i < _maxScaleTable; i++, offs += 16) { - s1 = READ_LE_UINT32(roomptr + offs); - y1 = READ_LE_UINT32(roomptr + offs + 4); - s2 = READ_LE_UINT32(roomptr + offs + 8); - y2 = READ_LE_UINT32(roomptr + offs + 12); + for (i = 1; i < _maxScaleTable; i++, ptr += 16) { + s1 = READ_LE_UINT32(ptr); + y1 = READ_LE_UINT32(ptr + 4); + s2 = READ_LE_UINT32(ptr + 8); + y2 = READ_LE_UINT32(ptr + 12); setScaleSlot(i, 0, y1, s1, 0, y2, s2); } } else { - for (i = 1; i < _maxScaleTable; i++, offs += 8) { - s1 = READ_LE_UINT16(roomptr + offs); - y1 = READ_LE_UINT16(roomptr + offs + 2); - s2 = READ_LE_UINT16(roomptr + offs + 4); - y2 = READ_LE_UINT16(roomptr + offs + 6); + for (i = 1; i < _maxScaleTable; i++, ptr += 8) { + s1 = READ_LE_UINT16(ptr); + y1 = READ_LE_UINT16(ptr + 2); + s2 = READ_LE_UINT16(ptr + 4); + y2 = READ_LE_UINT16(ptr + 6); if (s1 || y1 || s2 || y2) { - setScaleItem(i, y1, s1, y2, s2); - roomptr = getResourceAddress(rtRoom, _roomResource); + setScaleSlot(i, 0, y1, s1, 0, y2, s2); } } } |