aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/palette.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/palette.cpp')
-rw-r--r--engines/scumm/palette.cpp444
1 files changed, 361 insertions, 83 deletions
diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp
index 30096000ce..9977436dc6 100644
--- a/engines/scumm/palette.cpp
+++ b/engines/scumm/palette.cpp
@@ -372,6 +372,140 @@ void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) {
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) {
if (_palDirtyMin > min)
_palDirtyMin = min;
@@ -419,11 +553,26 @@ void ScummEngine::initCycl(const byte *ptr) {
cycl->start = *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) {
_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) {
@@ -432,11 +581,23 @@ void ScummEngine::stopCycle(int i) {
assertRange(0, i, 16, "stopCycle: cycle");
if (i != 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;
}
- for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++)
+ for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) {
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);
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 (_game.version >= 7) {
- for (j = 0; j < NUM_SHADOW_PALETTE; j++)
+ if (_shadowPalette) {
+ if (_game.version >= 7) {
+ for (j = 0; j < NUM_SHADOW_PALETTE; j++)
doCycleIndirectPalette(_shadowPalette + j * 256, cycl->start, cycl->end, !(cycl->flags & 2));
- } else {
- doCycleIndirectPalette(_shadowPalette, cycl->start, cycl->end, !(cycl->flags & 2));
+ } else {
+ 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) {
- int max;
- if (_game.version >= 5 && _game.version <= 6 && _game.heversion <= 60) {
- max = 252;
- } else {
- max = 255;
- }
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ startColor = CLIP(startColor, 0, 255);
- if (startColor <= endColor) {
- const byte *cptr;
- const byte *palptr;
- int color, idx, j;
+ //bool remappedVerbColors = false;
+ bool remappedRoomColors = false;
+ bool cycleFlag = (blueScale >= 250 && greenScale >= 250 && redScale >= 250);
+
+ const byte *palptr = getPalettePtr(_curPalIndex, _roomResource) + startColor * 3;
+
+ for (int i = startColor; i <= endColor; ++i) {
+ if (i >= 16 && i < 48) {
+ if (cycleFlag)
+ _colorUsedByCycle[i - 16] &= ~2;
+ else
+ _colorUsedByCycle[i - 16] |= 2;
+ }
+
+ _currentPalette[i * 3 + 0] = (*palptr++ * redScale) >> 8;
+ _currentPalette[i * 3 + 1] = (*palptr++ * greenScale) >> 8;
+ _currentPalette[i * 3 + 2] = (*palptr++ * blueScale) >> 8;
+ }
+
+ for (int i = startColor; i <= endColor; ++i) {
+ // Colors 33 (17+16) and 65 (17+32) will never get changed. For
+ // more information about these check setAmigaPaletteFromPtr.
+ if (i >= 16 && i < 48 && i != 33) {
+ remappedRoomColors = true;
+ _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
+ _amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
+ _amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
+ } else if (i >= 48 && i < 80 && i != 65) {
+ //remappedVerbColors = true;
+ _amigaPalette[(i - 16) * 3 + 0] = _currentPalette[i * 3 + 0] >> 4;
+ _amigaPalette[(i - 16) * 3 + 1] = _currentPalette[i * 3 + 1] >> 4;
+ _amigaPalette[(i - 16) * 3 + 2] = _currentPalette[i * 3 + 2] >> 4;
+ }
+ }
+
+ 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 (_game.heversion >= 90 || _game.version == 8) {
- palptr = _darkenPalette;
+ 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 {
- palptr = getPalettePtr(_curPalIndex, _roomResource);
+ max = 255;
}
- for (j = startColor; j <= endColor; j++) {
- idx = (_game.heversion == 70) ? _HEV7ActorPalette[j] : j;
- cptr = palptr + idx * 3;
- if (_game.heversion == 70)
- setDirtyColors(idx, idx);
+ if (startColor <= endColor) {
+ const byte *cptr;
+ const byte *palptr;
+ int color, idx, j;
- // Original FOA Amiga version skips these colors
- // Fixes bug #1206994: "FOA AMIGA: Black cursor and text in Dig Site"
- if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
- if (j < 16) {
- cptr += 3;
- continue;
- }
+ if (_game.heversion >= 90 || _game.version == 8) {
+ palptr = _darkenPalette;
+ } else {
+ palptr = getPalettePtr(_curPalIndex, _roomResource);
}
-
- 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]);
+ 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;
}
+ 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)
_16BitPalette[idx] = get16BitColor(r, g, b);
@@ -1026,6 +1270,8 @@ void ScummEngine::setCurrentPalette(int palindex) {
towns_setPaletteFromPtr(pals);
#endif
#endif
+ } else if (_game.id == GID_INDY4 && _game.platform == Common::kPlatformAmiga) {
+ setAmigaPaletteFromPtr(pals);
} else {
setPaletteFromPtr(pals);
}
@@ -1081,42 +1327,74 @@ void ScummEngine::updatePalette() {
if (_palDirtyMax == -1)
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 *p = palette_colors;
+ int first;
+ int num;
- for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
- byte *data;
+ if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
+ // Indy4 Amiga has a special palette handling scheme
+ first = 0;
+ num = 64;
- if (_game.features & GF_SMALL_HEADER && _game.version > 2)
- data = _currentPalette + _shadowPalette[i] * 3;
- else
- data = _currentPalette + i * 3;
+ for (int i = 0; i < 64; ++i) {
+ byte *data;
- // Sam & Max film noir mode. Convert the colors to grayscale
- // before uploading them to the backend.
+ if (i < 32)
+ data = _amigaPalette + _shadowPalette[i] * 3;
+ else
+ data = _amigaPalette + i * 3;
- if (noir_mode) {
- int r, g, b;
- byte brightness;
+ *p++ = data[0] * 255 / 15;
+ *p++ = data[1] * 255 / 15;
+ *p++ = data[2] * 255 / 15;
+ }
- r = data[0];
- g = data[1];
- b = data[2];
+ // Setup colors for the mouse cursor
+ // Color values taken from Indy4 DOS
+ 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;
- *p++ = brightness;
- *p++ = brightness;
- } else {
- *p++ = data[0];
- *p++ = data[1];
- *p++ = data[2];
+ first = _palDirtyMin;
+ num = _palDirtyMax - first + 1;
+
+ for (i = _palDirtyMin; i <= _palDirtyMax; i++) {
+ byte *data;
+
+ 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
if (_game.platform == Common::kPlatformFMTowns) {
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]);
p += 3;
}