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
This commit is contained in:
parent
163ecdc054
commit
07e8084eee
7 changed files with 83 additions and 133 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
scalex = (byte)scale;
|
||||
scaley = (byte)scale;
|
||||
}
|
||||
|
|
111
scumm/boxes.cpp
111
scumm/boxes.cpp
|
@ -156,8 +156,22 @@ int Scumm::getScale(int box, int x, int y) {
|
|||
if (!ptr)
|
||||
return 255;
|
||||
|
||||
int slot , scale;
|
||||
|
||||
if (_version == 8) {
|
||||
int slot = FROM_LE_32(ptr->v8.scaleSlot);
|
||||
// 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;
|
||||
|
@ -171,37 +185,28 @@ int Scumm::getScale(int box, int x, int y) {
|
|||
y = 0;
|
||||
|
||||
scaleY = (s.scale2 - s.scale1) * (y - s.y1) / (s.y2 - s.y1) + s.scale1;
|
||||
}
|
||||
if (s.x1 == s.x2) {
|
||||
return scaleY;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue