Merge pull request #77 from lordhoto/indy4amiga

SCUMM: Implement proper Indy4 Amiga palette handling.
This commit is contained in:
Eugene Sandulenko 2011-08-27 10:23:19 -07:00
commit 064ab0fd62
11 changed files with 481 additions and 93 deletions

View file

@ -767,6 +767,13 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
_textScreenID = vs->number; _textScreenID = vs->number;
} }
// We need to know the virtual screen we draw on for Indy 4 Amiga, since
// it selects the palette map according to this. We furthermore can not
// use _textScreenID here, since that will cause inventory graphics
// glitches.
if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4)
_drawScreen = vs->number;
printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask); printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask);
_left += _origWidth; _left += _origWidth;
@ -917,12 +924,27 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co
numbits = 8; numbits = 8;
byte *cmap = _vm->_charsetColorMap; byte *cmap = _vm->_charsetColorMap;
// Indy4 Amiga always uses the room or verb palette map to match colors to
// the currently setup palette, thus we need to select it over here too.
// Done like the original interpreter.
byte *amigaMap = 0;
if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4) {
if (_drawScreen == kVerbVirtScreen)
amigaMap = _vm->_verbPalette;
else
amigaMap = _vm->_roomPalette;
}
for (y = 0; y < height && y + drawTop < s.h; y++) { for (y = 0; y < height && y + drawTop < s.h; y++) {
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
color = (bits >> (8 - bpp)) & 0xFF; color = (bits >> (8 - bpp)) & 0xFF;
if (color && y + drawTop >= 0) if (color && y + drawTop >= 0) {
*dst = cmap[color]; if (amigaMap)
*dst = amigaMap[cmap[color]];
else
*dst = cmap[color];
}
dst++; dst++;
bits <<= bpp; bits <<= bpp;
numbits -= bpp; numbits -= bpp;

View file

@ -119,6 +119,9 @@ protected:
int _offsX, _offsY; int _offsX, _offsY;
const byte *_charPtr; const byte *_charPtr;
// On which virtual screen will be drawn right now
VirtScreenNumber _drawScreen;
public: public:
CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {} CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}

View file

@ -545,6 +545,13 @@ void ClassicCostumeRenderer::proc3_ami(Codec1 &v1) {
oldXpos = v1.x; oldXpos = v1.x;
oldScaleIndexX = _scaleIndexX; oldScaleIndexX = _scaleIndexX;
// Indy4 Amiga always uses the room map to match colors to the currently
// setup palette in the actor code in the original, thus we need to do this
// mapping over here too.
byte *amigaMap = 0;
if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4)
amigaMap = _vm->_roomPalette;
do { do {
len = *src++; len = *src++;
color = len >> v1.shr; color = len >> v1.shr;
@ -556,7 +563,10 @@ void ClassicCostumeRenderer::proc3_ami(Codec1 &v1) {
masked = (y < 0 || y >= _out.h) || (v1.x < 0 || v1.x >= _out.w) || (v1.mask_ptr && (mask[0] & maskbit)); masked = (y < 0 || y >= _out.h) || (v1.x < 0 || v1.x >= _out.w) || (v1.mask_ptr && (mask[0] & maskbit));
if (color && !masked) { if (color && !masked) {
*dst = _palette[color]; if (amigaMap)
*dst = amigaMap[_palette[color]];
else
*dst = _palette[color];
} }
if (_scaleX == 255 || v1.scaletable[_scaleIndexX] < _scaleX) { if (_scaleX == 255 || v1.scaletable[_scaleIndexX] < _scaleX) {

View file

@ -609,7 +609,16 @@ void ScummEngine_v5::setBuiltinCursor(int idx) {
for (i = 0; i < 1024; i++) for (i = 0; i < 1024; i++)
WRITE_UINT16(_grabbedCursor + i * 2, 0xFF); WRITE_UINT16(_grabbedCursor + i * 2, 0xFF);
} else { } else {
color = default_cursor_colors[idx]; // Indy4 Amiga uses its own color set for the cursor image.
// This is patchwork code to make the cursor flash in correct colors.
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
static const uint8 indy4AmigaColors[4] = {
252, 252, 253, 254
};
color = indy4AmigaColors[idx];
} else {
color = default_cursor_colors[idx];
}
memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor)); memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
} }

View file

@ -1025,6 +1025,16 @@ void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) {
if (rect.left > vs->w) if (rect.left > vs->w)
return; return;
// Indy4 Amiga always uses the room or verb palette map to match colors to
// the currently setup palette, thus we need to select it over here too.
// Done like the original interpreter.
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
if (vs->number == kVerbVirtScreen)
backColor = _verbPalette[backColor];
else
backColor = _roomPalette[backColor];
}
// Convert 'rect' to local (virtual screen) coordinates // Convert 'rect' to local (virtual screen) coordinates
rect.top -= vs->topline; rect.top -= vs->topline;
rect.bottom -= vs->topline; rect.bottom -= vs->topline;
@ -1235,6 +1245,16 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
if ((vs = findVirtScreen(y)) == NULL) if ((vs = findVirtScreen(y)) == NULL)
return; return;
// Indy4 Amiga always uses the room or verb palette map to match colors to
// the currently setup palette, thus we need to select it over here too.
// Done like the original interpreter.
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
if (vs->number == kVerbVirtScreen)
color = _verbPalette[color];
else
color = _roomPalette[color];
}
if (x > x2) if (x > x2)
SWAP(x, x2); SWAP(x, x2);
@ -1872,6 +1892,16 @@ bool Gdi::drawStrip(byte *dstPtr, VirtScreen *vs, int x, int y, const int width,
} }
assertRange(0, offset, smapLen-1, "screen strip"); assertRange(0, offset, smapLen-1, "screen strip");
// Indy4 Amiga always uses the room or verb palette map to match colors to
// the currently setup palette, thus we need to select it over here too.
// Done like the original interpreter.
if (_vm->_game.platform == Common::kPlatformAmiga && _vm->_game.id == GID_INDY4) {
if (vs->number == kVerbVirtScreen)
_roomPalette = _vm->_verbPalette;
else
_roomPalette = _vm->_roomPalette;
}
return decompressBitmap(dstPtr, vs->pitch, smap_ptr + offset, height); return decompressBitmap(dstPtr, vs->pitch, smap_ptr + offset, height);
} }

View file

@ -372,6 +372,140 @@ void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) {
setDirtyColors(firstIndex, numcolor - 1); setDirtyColors(firstIndex, numcolor - 1);
} }
void ScummEngine::setAmigaPaletteFromPtr(const byte *ptr) {
memcpy(_currentPalette, ptr, 768);
for (int i = 0; i < 32; ++i) {
_shadowPalette[i] = i;
_colorUsedByCycle[i] = 0;
}
_amigaFirstUsedColor = 80;
for (; _amigaFirstUsedColor < 256; ++_amigaFirstUsedColor) {
// We look for the first used color here. If all color components are
// >= 252 the color seems to be unused. Check remapPaletteColor for
// the same behavior.
if (ptr[_amigaFirstUsedColor * 3 + 0] <= 251
|| ptr[_amigaFirstUsedColor * 3 + 1] <= 251
|| ptr[_amigaFirstUsedColor * 3 + 2] <= 251)
break;
}
for (int i = 0; i < 64; ++i) {
_amigaPalette[i * 3 + 0] = _currentPalette[(i + 16) * 3 + 0] >> 4;
_amigaPalette[i * 3 + 1] = _currentPalette[(i + 16) * 3 + 1] >> 4;
_amigaPalette[i * 3 + 2] = _currentPalette[(i + 16) * 3 + 2] >> 4;
}
for (int i = 0; i < 256; ++i) {
if (i < 16 || i >= _amigaFirstUsedColor) {
mapRoomPalette(i);
mapVerbPalette(i);
} else {
int idx = (i - 16) & 31;
// We adjust our verb palette map from [0, 31] to [32, 63], since unlike
// the original we set up the verb palette at colors [32, 63].
// The original instead used two different palettes for the verb virtual
// screen and all the rest.
if (idx != 17) {
_roomPalette[i] = idx;
_verbPalette[i] = idx + 32;
} else {
// In all my tests it seems the colors 0 and 32 in
// _amigaPalette are in fact black. Thus 17 is probably black.
// For the room map the color 17 is 33 (17+16), for the verb
// map it is 65 (17+32).
_roomPalette[i] = 0;
_verbPalette[i] = 32;
}
}
}
setDirtyColors(0, 255);
}
void ScummEngine::mapRoomPalette(int idx) {
// For Color 33 (which is in fact 17+16) see the special case in
// setAmigaPaletteFromPtr.
if (idx >= 16 && idx < 48 && idx != 33)
_roomPalette[idx] = idx - 16;
else
_roomPalette[idx] = remapRoomPaletteColor(_currentPalette[idx * 3 + 0] >> 4,
_currentPalette[idx * 3 + 1] >> 4,
_currentPalette[idx * 3 + 2] >> 4);
}
static const uint8 amigaWeightTable[16] = {
0, 1, 4, 9, 16, 25, 36, 49,
64, 81, 100, 121, 144, 169, 196, 225
};
int ScummEngine::remapRoomPaletteColor(int r, int g, int b) {
int idx = 0;
uint16 minValue = 0xFFFF;
const byte *pal = _amigaPalette;
const byte *cycle = _colorUsedByCycle;
for (int i = 0; i < 32; ++i) {
if (!*cycle++ && i != 17) {
int rD = ABS<int>(*pal++ - r);
int gD = ABS<int>(*pal++ - g);
int bD = ABS<int>(*pal++ - b);
const uint16 weight = amigaWeightTable[rD] + amigaWeightTable[gD] + amigaWeightTable[bD];
if (weight < minValue) {
minValue = weight;
idx = i;
}
} else {
pal += 3;
}
}
return idx;
}
void ScummEngine::mapVerbPalette(int idx) {
// We adjust our verb palette map from [0, 31] to [32, 63], since unlike
// the original we set up the verb palette at colors [32, 63].
// The original instead used two different palettes for the verb virtual
// screen and all the rest.
// For Color 65 (which is in fact 17+32) see the special case in
// setAmigaPaletteFromPtr.
if (idx >= 48 && idx < 80 && idx != 65)
_verbPalette[idx] = idx - 16;
else
_verbPalette[idx] = remapVerbPaletteColor(_currentPalette[idx * 3 + 0] >> 4,
_currentPalette[idx * 3 + 1] >> 4,
_currentPalette[idx * 3 + 2] >> 4) + 32;
}
int ScummEngine::remapVerbPaletteColor(int r, int g, int b) {
int idx = 0;
uint16 minValue = 0xFFFF;
const byte *pal = _amigaPalette + 32 * 3;
for (int i = 0; i < 32; ++i) {
if (i != 17) {
int rD = ABS<int>(*pal++ - r);
int gD = ABS<int>(*pal++ - g);
int bD = ABS<int>(*pal++ - b);
const uint16 weight = amigaWeightTable[rD] + amigaWeightTable[gD] + amigaWeightTable[bD];
if (weight < minValue) {
minValue = weight;
idx = i;
}
} else {
pal += 3;
}
}
return idx;
}
void ScummEngine::setDirtyColors(int min, int max) { void ScummEngine::setDirtyColors(int min, int max) {
if (_palDirtyMin > min) if (_palDirtyMin > min)
_palDirtyMin = min; _palDirtyMin = min;
@ -419,11 +553,26 @@ void ScummEngine::initCycl(const byte *ptr) {
cycl->start = *ptr++; cycl->start = *ptr++;
cycl->end = *ptr++; cycl->end = *ptr++;
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
cycl->start = CLIP(cycl->start - 16, 0, 31);
cycl->end = CLIP(cycl->end - 16, 0, 31);
}
for (int i = cycl->start; i <= cycl->end; ++i) { for (int i = cycl->start; i <= cycl->end; ++i) {
_colorUsedByCycle[i] = 1; _colorUsedByCycle[i] = 1;
} }
} }
} }
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
for (int i = 0; i < 256; ++i) {
if (i >= 16 && i < _amigaFirstUsedColor)
continue;
if (_colorUsedByCycle[_roomPalette[i]])
mapRoomPalette(i);
}
}
} }
void ScummEngine::stopCycle(int i) { void ScummEngine::stopCycle(int i) {
@ -432,11 +581,23 @@ void ScummEngine::stopCycle(int i) {
assertRange(0, i, 16, "stopCycle: cycle"); assertRange(0, i, 16, "stopCycle: cycle");
if (i != 0) { if (i != 0) {
_colorCycle[i - 1].delay = 0; _colorCycle[i - 1].delay = 0;
cycl = &_colorCycle[i - 1];
for (int j = cycl->start; j <= cycl->end && j < 32; ++j) {
_shadowPalette[j] = j;
_colorUsedByCycle[j] = 0;
}
return; return;
} }
for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) {
cycl->delay = 0; cycl->delay = 0;
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
for (int j = cycl->start; j <= cycl->end && j < 32; ++j) {
_shadowPalette[j] = j;
_colorUsedByCycle[j] = 0;
}
}
}
} }
/** /**
@ -512,14 +673,18 @@ void ScummEngine::cyclePalette() {
setDirtyColors(cycl->start, cycl->end); setDirtyColors(cycl->start, cycl->end);
moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2); moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2);
doCyclePalette(_currentPalette, cycl->start, cycl->end, 3, !(cycl->flags & 2)); if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
doCyclePalette(_shadowPalette, cycl->start, cycl->end, 1, !(cycl->flags & 2));
} else {
doCyclePalette(_currentPalette, cycl->start, cycl->end, 3, !(cycl->flags & 2));
if (_shadowPalette) { if (_shadowPalette) {
if (_game.version >= 7) { if (_game.version >= 7) {
for (j = 0; j < NUM_SHADOW_PALETTE; j++) for (j = 0; j < NUM_SHADOW_PALETTE; j++)
doCycleIndirectPalette(_shadowPalette + j * 256, cycl->start, cycl->end, !(cycl->flags & 2)); doCycleIndirectPalette(_shadowPalette + j * 256, cycl->start, cycl->end, !(cycl->flags & 2));
} else { } else {
doCycleIndirectPalette(_shadowPalette, cycl->start, cycl->end, !(cycl->flags & 2)); doCycleIndirectPalette(_shadowPalette, cycl->start, cycl->end, !(cycl->flags & 2));
}
} }
} }
} }
@ -733,62 +898,106 @@ void ScummEngine::setShadowPalette(int redScale, int greenScale, int blueScale,
} }
void ScummEngine::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) { void ScummEngine::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) {
int max; if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
if (_game.version >= 5 && _game.version <= 6 && _game.heversion <= 60) { startColor = CLIP(startColor, 0, 255);
max = 252;
} else {
max = 255;
}
if (startColor <= endColor) { //bool remappedVerbColors = false;
const byte *cptr; bool remappedRoomColors = false;
const byte *palptr; bool cycleFlag = (blueScale >= 250 && greenScale >= 250 && redScale >= 250);
int color, idx, j;
if (_game.heversion >= 90 || _game.version == 8) { const byte *palptr = getPalettePtr(_curPalIndex, _roomResource) + startColor * 3;
palptr = _darkenPalette;
} else {
palptr = getPalettePtr(_curPalIndex, _roomResource);
}
for (j = startColor; j <= endColor; j++) {
idx = (_game.heversion == 70) ? _HEV7ActorPalette[j] : j;
cptr = palptr + idx * 3;
if (_game.heversion == 70) for (int i = startColor; i <= endColor; ++i) {
setDirtyColors(idx, idx); if (i >= 16 && i < 48) {
if (cycleFlag)
// Original FOA Amiga version skips these colors _colorUsedByCycle[i - 16] &= ~2;
// Fixes bug #1206994: "FOA AMIGA: Black cursor and text in Dig Site" else
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) { _colorUsedByCycle[i - 16] |= 2;
if (j < 16) {
cptr += 3;
continue;
}
} }
color = *cptr++; _currentPalette[i * 3 + 0] = (*palptr++ * redScale) >> 8;
color = color * redScale / 0xFF; _currentPalette[i * 3 + 1] = (*palptr++ * greenScale) >> 8;
if (color > max) _currentPalette[i * 3 + 2] = (*palptr++ * blueScale) >> 8;
color = max; }
_currentPalette[idx * 3 + 0] = color;
for (int i = startColor; i <= endColor; ++i) {
color = *cptr++; // Colors 33 (17+16) and 65 (17+32) will never get changed. For
color = color * greenScale / 0xFF; // more information about these check setAmigaPaletteFromPtr.
if (color > max) if (i >= 16 && i < 48 && i != 33) {
color = max; remappedRoomColors = true;
_currentPalette[idx * 3 + 1] = color; _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
_amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
color = *cptr++; _amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
color = color * blueScale / 0xFF; } else if (i >= 48 && i < 80 && i != 65) {
if (color > max) //remappedVerbColors = true;
color = max; _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
_currentPalette[idx * 3 + 2] = color; _amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
_amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
if (_game.features & GF_16BIT_COLOR) }
_16BitPalette[idx] = get16BitColor(_currentPalette[idx * 3 + 0], _currentPalette[idx * 3 + 1], _currentPalette[idx * 3 + 2]); }
for (int i = 0; i < 256; ++i) {
if (i >= 16 && i < _amigaFirstUsedColor)
continue;
bool inRange = (startColor <= i && i <= endColor);
int idx = _roomPalette[i] + 16;
bool mappedInRange = (startColor <= idx && idx <= endColor);
if (inRange != mappedInRange || (remappedRoomColors && cycleFlag))
mapRoomPalette(i);
}
setDirtyColors(startColor, endColor);
} else {
int max;
if (_game.version >= 5 && _game.version <= 6 && _game.heversion <= 60) {
max = 252;
} else {
max = 255;
}
if (startColor <= endColor) {
const byte *cptr;
const byte *palptr;
int color, idx, j;
if (_game.heversion >= 90 || _game.version == 8) {
palptr = _darkenPalette;
} else {
palptr = getPalettePtr(_curPalIndex, _roomResource);
}
for (j = startColor; j <= endColor; j++) {
idx = (_game.heversion == 70) ? _HEV7ActorPalette[j] : j;
cptr = palptr + idx * 3;
if (_game.heversion == 70)
setDirtyColors(idx, idx);
color = *cptr++;
color = color * redScale / 0xFF;
if (color > max)
color = max;
_currentPalette[idx * 3 + 0] = color;
color = *cptr++;
color = color * greenScale / 0xFF;
if (color > max)
color = max;
_currentPalette[idx * 3 + 1] = color;
color = *cptr++;
color = color * blueScale / 0xFF;
if (color > max)
color = max;
_currentPalette[idx * 3 + 2] = color;
if (_game.features & GF_16BIT_COLOR)
_16BitPalette[idx] = get16BitColor(_currentPalette[idx * 3 + 0], _currentPalette[idx * 3 + 1], _currentPalette[idx * 3 + 2]);
}
if (_game.heversion != 70)
setDirtyColors(startColor, endColor);
} }
if (_game.heversion != 70)
setDirtyColors(startColor, endColor);
} }
} }
@ -1007,6 +1216,41 @@ void ScummEngine::setPalColor(int idx, int r, int g, int b) {
_darkenPalette[idx * 3 + 2] = b; _darkenPalette[idx * 3 + 2] = b;
} }
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
// Colors 33 (17+16) and 65 (17+32) will never get changed. For
// more information about these check setAmigaPaletteFromPtr.
if (idx < 16 || idx >= _amigaFirstUsedColor) {
mapRoomPalette(idx);
mapVerbPalette(idx);
} else if (idx >= 16 && idx < 48 && idx != 33) {
_amigaPalette[(idx - 16) * 3 + 0] = _currentPalette[idx * 3 + 0] >> 4;
_amigaPalette[(idx - 16) * 3 + 1] = _currentPalette[idx * 3 + 1] >> 4;
_amigaPalette[(idx - 16) * 3 + 2] = _currentPalette[idx * 3 + 2] >> 4;
for (int i = 0; i < 256; ++i) {
if (i >= 16 && i < _amigaFirstUsedColor)
continue;
if (idx - 16 == _roomPalette[i])
mapRoomPalette(i);
}
} else if (idx >= 48 && idx < 80 && idx != 65) {
_amigaPalette[(idx - 16) * 3 + 0] = _currentPalette[idx * 3 + 0] >> 4;
_amigaPalette[(idx - 16) * 3 + 1] = _currentPalette[idx * 3 + 1] >> 4;
_amigaPalette[(idx - 16) * 3 + 2] = _currentPalette[idx * 3 + 2] >> 4;
for (int i = 0; i < 256; ++i) {
if (i >= 16 && i < _amigaFirstUsedColor)
continue;
// We do - 16 instead of - 48 like the original, since our
// verb palette map is using [32, 63] instead of [0, 31].
if (idx - 16 == _verbPalette[i])
mapVerbPalette(i);
}
}
}
if (_game.features & GF_16BIT_COLOR) if (_game.features & GF_16BIT_COLOR)
_16BitPalette[idx] = get16BitColor(r, g, b); _16BitPalette[idx] = get16BitColor(r, g, b);
@ -1026,6 +1270,8 @@ void ScummEngine::setCurrentPalette(int palindex) {
towns_setPaletteFromPtr(pals); towns_setPaletteFromPtr(pals);
#endif #endif
#endif #endif
} else if (_game.id == GID_INDY4 && _game.platform == Common::kPlatformAmiga) {
setAmigaPaletteFromPtr(pals);
} else { } else {
setPaletteFromPtr(pals); setPaletteFromPtr(pals);
} }
@ -1081,42 +1327,74 @@ void ScummEngine::updatePalette() {
if (_palDirtyMax == -1) if (_palDirtyMax == -1)
return; return;
bool noir_mode = (_game.id == GID_SAMNMAX && readVar(0x8000));
int first = _palDirtyMin;
int num = _palDirtyMax - first + 1;
int i;
byte palette_colors[3 * 256]; byte palette_colors[3 * 256];
byte *p = palette_colors; byte *p = palette_colors;
int first;
int num;
for (i = _palDirtyMin; i <= _palDirtyMax; i++) { if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
byte *data; // Indy4 Amiga has a special palette handling scheme
first = 0;
num = 64;
if (_game.features & GF_SMALL_HEADER && _game.version > 2) for (int i = 0; i < 64; ++i) {
data = _currentPalette + _shadowPalette[i] * 3; byte *data;
else
data = _currentPalette + i * 3;
// Sam & Max film noir mode. Convert the colors to grayscale if (i < 32)
// before uploading them to the backend. data = _amigaPalette + _shadowPalette[i] * 3;
else
data = _amigaPalette + i * 3;
if (noir_mode) { *p++ = data[0] * 255 / 15;
int r, g, b; *p++ = data[1] * 255 / 15;
byte brightness; *p++ = data[2] * 255 / 15;
}
r = data[0]; // Setup colors for the mouse cursor
g = data[1]; // Color values taken from Indy4 DOS
b = data[2]; static const uint8 mouseCursorPalette[] = {
255, 255, 255,
171, 171, 171,
87, 87, 87
};
brightness = (byte)((0.299 * r + 0.587 * g + 0.114 * b) + 0.5); _system->getPaletteManager()->setPalette(mouseCursorPalette, 252, 3);
} else {
bool noir_mode = (_game.id == GID_SAMNMAX && readVar(0x8000));
int i;
*p++ = brightness; first = _palDirtyMin;
*p++ = brightness; num = _palDirtyMax - first + 1;
*p++ = brightness;
} else { for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
*p++ = data[0]; byte *data;
*p++ = data[1];
*p++ = data[2]; if (_game.features & GF_SMALL_HEADER && _game.version > 2)
data = _currentPalette + _shadowPalette[i] * 3;
else
data = _currentPalette + i * 3;
// Sam & Max film noir mode. Convert the colors to grayscale
// before uploading them to the backend.
if (noir_mode) {
int r, g, b;
byte brightness;
r = data[0];
g = data[1];
b = data[2];
brightness = (byte)((0.299 * r + 0.587 * g + 0.114 * b) + 0.5);
*p++ = brightness;
*p++ = brightness;
*p++ = brightness;
} else {
*p++ = data[0];
*p++ = data[1];
*p++ = data[2];
}
} }
} }
@ -1127,7 +1405,7 @@ void ScummEngine::updatePalette() {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (_game.platform == Common::kPlatformFMTowns) { if (_game.platform == Common::kPlatformFMTowns) {
p = palette_colors; p = palette_colors;
for (i = first; i < first + num; ++i) { for (int i = first; i < first + num; ++i) {
_16BitPalette[i] = get16BitColor(p[0], p[1], p[2]); _16BitPalette[i] = get16BitColor(p[0], p[1], p[2]);
p += 3; p += 3;
} }

View file

@ -552,6 +552,10 @@ void ScummEngine::resetRoomSubBlocks() {
} }
} }
// We need to setup the current palette before initCycl for Indy4 Amiga.
if (_PALS_offs || _CLUT_offs)
setCurrentPalette(0);
// Color cycling // Color cycling
// HE 7.0 games load resources but don't use them. // HE 7.0 games load resources but don't use them.
if (_game.version >= 4 && _game.heversion <= 62) { if (_game.version >= 4 && _game.heversion <= 62) {
@ -570,9 +574,6 @@ void ScummEngine::resetRoomSubBlocks() {
} }
} }
#endif #endif
if (_PALS_offs || _CLUT_offs)
setCurrentPalette(0);
} }

View file

@ -1322,6 +1322,9 @@ void ScummEngine::saveOrLoad(Serializer *s) {
if (_shadowPaletteSize) { if (_shadowPaletteSize) {
s->saveLoadArrayOf(_shadowPalette, _shadowPaletteSize, 1, sleByte); s->saveLoadArrayOf(_shadowPalette, _shadowPaletteSize, 1, sleByte);
// _roomPalette didn't show up until V21 save games // _roomPalette didn't show up until V21 save games
// Note that we also save the room palette for Indy4 Amiga, since it
// is used as palette map there too, but we do so slightly a bit
// further down to group it with the other special palettes needed.
if (s->getVersion() >= VER(21) && _game.version < 5) if (s->getVersion() >= VER(21) && _game.version < 5)
s->saveLoadArrayOf(_roomPalette, sizeof(_roomPalette), 1, sleByte); s->saveLoadArrayOf(_roomPalette, sizeof(_roomPalette), 1, sleByte);
} }
@ -1348,6 +1351,20 @@ void ScummEngine::saveOrLoad(Serializer *s) {
memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle)); memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
} }
// Indy4 Amiga specific palette tables were not saved before V85
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
if (s->getVersion() >= 85) {
s->saveLoadArrayOf(_roomPalette, 256, 1, sleByte);
s->saveLoadArrayOf(_verbPalette, 256, 1, sleByte);
s->saveLoadArrayOf(_amigaPalette, 3 * 64, 1, sleByte);
} else {
warning("Save with old Indiana Jones 4 Amiga palette handling detected");
// We need to restore the internal state of the Amiga palette for Indy4
// Amiga. This might lead to graphics glitches!
setAmigaPaletteFromPtr(_currentPalette);
}
}
// //
// Save/load more global object state // Save/load more global object state
// //

View file

@ -47,7 +47,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame * only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently. * which is being loaded/saved currently.
*/ */
#define CURRENT_VER 84 #define CURRENT_VER 85
/** /**
* An auxillary macro, used to specify savegame versions. We use this instead * An auxillary macro, used to specify savegame versions. We use this instead

View file

@ -290,6 +290,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
#endif #endif
_shadowPalette = NULL; _shadowPalette = NULL;
_shadowPaletteSize = 0; _shadowPaletteSize = 0;
_verbPalette = NULL;
memset(_currentPalette, 0, sizeof(_currentPalette)); memset(_currentPalette, 0, sizeof(_currentPalette));
memset(_darkenPalette, 0, sizeof(_darkenPalette)); memset(_darkenPalette, 0, sizeof(_darkenPalette));
memset(_HEV7ActorPalette, 0, sizeof(_HEV7ActorPalette)); memset(_HEV7ActorPalette, 0, sizeof(_HEV7ActorPalette));
@ -610,6 +611,7 @@ ScummEngine::~ScummEngine() {
_textSurface.free(); _textSurface.free();
free(_shadowPalette); free(_shadowPalette);
free(_verbPalette);
free(_palManipPalette); free(_palManipPalette);
free(_palManipIntermediatePal); free(_palManipIntermediatePal);
@ -1408,6 +1410,10 @@ void ScummEngine::resetScumm() {
_16BitPalette = (uint16 *)calloc(512, sizeof(uint16)); _16BitPalette = (uint16 *)calloc(512, sizeof(uint16));
#endif #endif
// Indy4 Amiga needs another palette map for the verb area.
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4 && !_verbPalette)
_verbPalette = (uint8 *)calloc(256, 1);
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (_game.platform == Common::kPlatformFMTowns) { if (_game.platform == Common::kPlatformFMTowns) {
delete _townsScreen; delete _townsScreen;

View file

@ -970,6 +970,7 @@ protected:
void setCurrentPalette(int pal); void setCurrentPalette(int pal);
void setRoomPalette(int pal, int room); void setRoomPalette(int pal, int room);
void setPCEPaletteFromPtr(const byte *ptr); void setPCEPaletteFromPtr(const byte *ptr);
void setAmigaPaletteFromPtr(const byte *ptr);
virtual void setPaletteFromPtr(const byte *ptr, int numcolor = -1); virtual void setPaletteFromPtr(const byte *ptr, int numcolor = -1);
virtual void setPalColor(int index, int r, int g, int b); virtual void setPalColor(int index, int r, int g, int b);
@ -1065,6 +1066,9 @@ public:
uint16 _hePaletteSlot; uint16 _hePaletteSlot;
uint16 *_16BitPalette; uint16 *_16BitPalette;
// Indy4 Amiga specific
byte *_verbPalette;
protected: protected:
int _shadowPaletteSize; int _shadowPaletteSize;
byte _currentPalette[3 * 256]; byte _currentPalette[3 * 256];
@ -1085,6 +1089,14 @@ protected:
bool _enable_gs; bool _enable_gs;
bool _copyProtection; bool _copyProtection;
// Indy4 Amiga specific
uint16 _amigaFirstUsedColor;
byte _amigaPalette[3 * 64];
void mapRoomPalette(int idx);
int remapRoomPaletteColor(int r, int g, int b);
void mapVerbPalette(int idx);
int remapVerbPaletteColor(int r, int g, int b);
public: public:
uint16 _extraBoxFlags[65]; uint16 _extraBoxFlags[65];