diff options
-rw-r--r-- | engines/mads/dialogs.h | 6 | ||||
-rw-r--r-- | engines/mads/nebular/dialogs_nebular.cpp | 83 | ||||
-rw-r--r-- | engines/mads/nebular/dialogs_nebular.h | 26 | ||||
-rw-r--r-- | engines/mads/palette.cpp | 159 | ||||
-rw-r--r-- | engines/mads/palette.h | 64 |
5 files changed, 303 insertions, 35 deletions
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h index e4f9bbb038..884f7e6866 100644 --- a/engines/mads/dialogs.h +++ b/engines/mads/dialogs.h @@ -181,7 +181,7 @@ public: /** * Show the dialog, and wait until a key or mouse press. */ - void show(); + virtual void show(); }; class MessageDialog: public TextDialog { @@ -211,9 +211,9 @@ public: virtual ~Dialogs() {} virtual void showDialog() = 0; - virtual void showItem(int objectId, int messageId, int arg = 0) = 0; + virtual void showItem(int objectId, int messageId, int speech = 0) = 0; - virtual bool show(int msgId) = 0; + virtual bool show(int messageId, int objectId = -1) = 0; }; } // End of namespace MADS diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index dc7d432cb8..9dd20cafec 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -33,9 +33,9 @@ namespace MADS { namespace Nebular { -bool DialogsNebular::show(int msgId) { +bool DialogsNebular::show(int messageId, int objectId) { MADSAction &action = _vm->_game->_scene._action; - Common::StringArray msg = _vm->_game->getMessage(msgId); + Common::StringArray msg = _vm->_game->getMessage(messageId); Common::String title; Common::String commandText; Common::String valStr; @@ -76,7 +76,11 @@ bool DialogsNebular::show(int msgId) { if (centerFlag) { crFlag = true; } else { - dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth); + if (objectId == -1) { + dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth); + } else { + dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId); + } dialog->wordWrap(dialogText); dialog->incNumLines(); } @@ -128,7 +132,11 @@ bool DialogsNebular::show(int msgId) { } if (!dialog) { - dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth); + if (objectId == -1) { + dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth); + } else { + dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId); + } } if (centerFlag) { @@ -158,8 +166,11 @@ bool DialogsNebular::show(int msgId) { return result; } -void DialogsNebular::showItem(int objectId, int messageId, int arg) { - show(messageId); +void DialogsNebular::showItem(int objectId, int messageId, int speech) { + // MADS engine doesn't currently support speech + assert(!speech); + + show(messageId, objectId); #if 0 Scene &scene = _vm->_game->_scene; byte highPalette[8 * 3]; @@ -170,15 +181,6 @@ void DialogsNebular::showItem(int objectId, int messageId, int arg) { greyScale[0] = greyScale[1] = greyScale[2] = 0xFFFF; Common::String setName = Common::String::format("*OBJ%.3d.SS", objectId); - // Turn off cycling if active - bool cyclingActive = scene._cyclingActive; - scene._cyclingActive = false; - - // Make a copy of the current screen surface - byte *savedSurface = new byte[MADS_SCREEN_WIDTH * MADS_SCREEN_HEIGHT]; - Common::copy(_vm->_screen.getData(), _vm->_screen.getData() + - MADS_SCREEN_WIDTH * MADS_SCREEN_HEIGHT, savedSurface); - delete[] savedSurface; @@ -287,7 +289,7 @@ TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), 32) { wordWrap("\n"); } -bool CopyProtectionDialog::show() { +void CopyProtectionDialog::show() { draw(); _vm->_events->showCursor(); @@ -298,7 +300,6 @@ bool CopyProtectionDialog::show() { } _vm->_events->_pendingKeys.clear(); - return true; } bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) { @@ -331,6 +332,54 @@ bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) { /*------------------------------------------------------------------------*/ +PictureDialog::PictureDialog(MADSEngine *vm, const Common::Point &pos, + int maxChars, int objectId) : + TextDialog(vm, FONT_INTERFACE, pos, maxChars), _objectId(objectId) { + Scene &scene = _vm->_game->_scene; + Palette &palette = *_vm->_palette; + + // Turn off cycling if active + _cyclingActive = scene._cyclingActive; + scene._cyclingActive = false; + + // Save palette information + Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]); + Common::copy(&palette._palFlags[0], &palette._palFlags[PALETTE_COUNT], &_palFlags[0]); + _rgbList.copy(palette._rgbList); + + // Set up palette allocation + uint32 *palFlagP = &palette._palFlags[0]; + for (int idx = 0; idx < PALETTE_COUNT; ++idx, ++palFlagP) { + *palFlagP = (idx < PALETTE_RESERVED_LOW_COUNT || + idx >= (PALETTE_COUNT - PALETTE_RESERVED_HIGH_COUNT - 10)) ? 1 : 0; + } + + // Reset the flag list + palette._rgbList.reset(); +} + +PictureDialog::~PictureDialog() { + Scene &scene = _vm->_game->_scene; + scene._cyclingActive = _cyclingActive; +} + +void PictureDialog::show() { + setupPalette(); + + TextDialog::show(); +} + +void PictureDialog::setupPalette() { + Palette &palette = *_vm->_palette; + byte map[PALETTE_COUNT]; + + int numColors = PALETTE_COUNT - PALETTE_RESERVED_LOW_COUNT - PALETTE_RESERVED_HIGH_COUNT; + palette.fadeToGrey(palette._mainPalette, &map[PALETTE_RESERVED_LOW_COUNT], + PALETTE_RESERVED_LOW_COUNT, numColors, 248, 8, 1, 16); +} + +/*------------------------------------------------------------------------*/ + ScreenDialog::DialogLine::DialogLine() { _state = 0; _textDisplayIndex = -1; diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index b5ee090efa..fd4d6e706e 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -49,9 +49,9 @@ private: public: virtual void showDialog(); - virtual void showItem(int objectId, int msgId, int arg); + virtual void showItem(int objectId, int messageId, int speech = -1); - virtual bool show(int id); + virtual bool show(int messageId, int objectId = -1); }; struct HOGANUS { @@ -79,7 +79,27 @@ public: /** * Show the dialog */ - bool show(); + virtual void show(); +}; + +class PictureDialog : public TextDialog { +private: + int _objectId; + bool _cyclingActive; + byte _palette[PALETTE_SIZE]; + uint32 _palFlags[PALETTE_COUNT]; + RGBList _rgbList; + + /** + * Sets up the palette and fades the screen to gray + */ + void setupPalette(); +public: + PictureDialog(MADSEngine *vm, const Common::Point &pos, int maxChars, int objectId); + + virtual ~PictureDialog(); + + virtual void show(); }; enum DialogTextAlign { ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 }; diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp index 51de2768ed..ad45562181 100644 --- a/engines/mads/palette.cpp +++ b/engines/mads/palette.cpp @@ -69,7 +69,7 @@ static bool sortHelper(const PaletteUsage::UsageEntry &ue1, const PaletteUsage:: void PaletteUsage::prioritize(Common::Array<RGB6> &palette) { for (uint i = 0; i < _data->size(); ++i) { RGB6 &palEntry = palette[(*_data)[i]._palIndex]; - (*_data)[i]._sortValue = rgbMerge(palEntry); + (*_data)[i]._sortValue = _vm->_palette->rgbMerge(palEntry); } Common::sort(_data->begin(), _data->end(), sortHelper); @@ -237,12 +237,6 @@ int PaletteUsage::process(Common::Array<RGB6> &palette, uint flags) { return rgbIndex; } - -int PaletteUsage::rgbMerge(RGB6 &palEntry) { - return ((palEntry.r + 1) / 4 - 1) * 38 + ((palEntry.g + 1) / 4 - 1) * 76 + - ((palEntry.b + 1) / 4 - 1) * 14; -} - void PaletteUsage::transform(Common::Array<RGB6> &palette) { if (!empty()) { for (uint i = 0; i < _data->size(); ++i) { @@ -336,6 +330,157 @@ int RGBList::scan() { error("RGBList was full"); } +void RGBList::copy(RGBList &src) { + Common::copy(&src._data[0], &src._data[32], &_data[0]); +} + +/*------------------------------------------------------------------------*/ + +Fader::Fader() { + _colorFlags[0] = _colorFlags[1] = _colorFlags[2] = true; + _colorFlags[3] = false; + _colorValues[0] = _colorValues[1] = 0; + _colorValues[2] = _colorValues[3] = 0; +} + +void Fader::fadeToGrey(byte palette[PALETTE_SIZE], byte paletteMap[PALETTE_COUNT], + int baseColor, int numColors, int baseGrey, int numGreys, + int tickDelay, int steps) { + GreyEntry map[PALETTE_COUNT]; + int intensity; + byte palIndex[PALETTE_COUNT][3]; + bool signs[PALETTE_COUNT][3]; + + mapToGreyRamp(palette, baseColor, numColors, baseGrey, numGreys, map); + + for (int palCtr = baseColor; palCtr < (baseColor + numColors); ++palCtr) { + int index = palCtr - baseColor; + for (int colorCtr = 0; colorCtr < 3; ++colorCtr) { + if (_colorFlags[colorCtr]) { + int shiftSign = _colorValues[colorCtr]; + if (shiftSign >= 0) { + intensity = map[index]._intensity << shiftSign; + } else { + intensity = map[index]._intensity >> ABS(shiftSign); + } + } else { + intensity = _colorValues[colorCtr]; + } + + int diff = intensity - palette[palCtr * 3 + colorCtr]; + palIndex[palCtr][colorCtr] = (byte)ABS(diff); + signs[palCtr][colorCtr] = diff / ABS(diff); + } + } + + // TODO: More here +} + +static bool greyCompareFunc(const Fader::GreyTableEntry &g1, const Fader::GreyTableEntry &g2) { + return g1._list < g2._list; +} + +void Fader::mapToGreyRamp(byte palette[PALETTE_SIZE], int baseColor, int numColors, + int baseGrey, int numGreys, GreyEntry *map) { + GreyTableEntry greyList[PALETTE_COUNT]; + byte greyTable[64]; + byte greyIntensity[64]; + int intensity, shiftSign; + + getGreyValues(palette, greyList, baseColor, numColors); + greyPopularity(greyList, greyTable, numColors); + + for (int idx = 0; idx < numColors; ++idx) { + greyList[idx]._mapping = idx; + Common::fill(&map[idx]._accum[0], &map[idx]._accum[3], 0); + } + + for (int idx = 0; idx < PALETTE_COUNT; ++idx) { + map[idx]._mapColor = (byte)idx; + } + + // Sort the mapping list + Common::sort(&greyList[0], &greyList[numColors], greyCompareFunc); + + // Initialise state variables + int greySum = 0; + int greyScan = 0; + int greyMark = 0; + int greyColors = 0; + int greyAccum = 0; + int firstColor = 0; + + for (int greyCtr = 0; greyCtr < 64; greyCtr++) { + for (int idx = 0; idx < greyTable[greyCtr]; idx++) { + greySum += greyList[greyScan++]._list; + ++greyColors; + + greyAccum += numGreys; + while (greyAccum >= numColors) { + greyAccum -= numColors; + if (greyColors > 0) { + greyIntensity[greyMark] = (byte)(greySum / greyColors); + } + + for (int rescan = firstColor; rescan < greyScan; ++rescan) { + map[greyList[rescan]._mapping]._intensity = greyIntensity[greyMark]; + map[greyList[rescan]._mapping]._mapColor = (byte)(greyMark + baseGrey); + } + + firstColor = greyScan; + greySum = 0; + greyColors = 0; + ++greyMark; + } + } + } + + // Process palette with intensities + byte *palP = &palette[baseGrey * 3]; + for (int greys = 0; greys < numGreys; ++greys) { + for (int color = 0; color < 3; ++color) { + if (_colorFlags[color]) { + shiftSign = (byte)_colorValues[color]; + if (shiftSign >= 0) { + intensity = greyIntensity[greys] << shiftSign; + } else { + intensity = greyIntensity[greys] >> abs(shiftSign); + } + } else { + intensity = _colorValues[color]; + } + *palP++ = VGA_COLOR_TRANS(intensity); + } + } +} + +void Fader::getGreyValues(const byte palette[PALETTE_SIZE], + GreyTableEntry greyList[PALETTE_COUNT], int baseColor, int numColors) { + const byte *palP = &palette[baseColor * 3]; + GreyTableEntry *destP = greyList; + + for (int i = 0; i < numColors; ++i, palP += 3, ++destP) { + int v = rgbMerge(palP[0], palP[1], palP[2]); + destP->_list = v >> 7; + } +} + +void Fader::greyPopularity(const GreyTableEntry greyList[PALETTE_COUNT], + byte greyTable[64], int numColors) { + Common::fill(&greyTable[0], &greyTable[64], 0); + for (int i = 0; i < 64; ++i) { + ++greyTable[greyList[i]._list]; + } +} + +int Fader::rgbMerge(RGB6 &palEntry) { + return rgbMerge(palEntry.r, palEntry.g, palEntry.b); +} + +int Fader::rgbMerge(byte r, byte g, byte b) { + return ((r + 1) / 4 - 1) * 38 + ((g + 1) / 4 - 1) * 76 + ((b + 1) / 4 - 1) * 14; +} + /*------------------------------------------------------------------------*/ Palette::Palette(MADSEngine *vm) : _vm(vm), _paletteUsage(vm) { diff --git a/engines/mads/palette.h b/engines/mads/palette.h index d1c7c1da7a..883f7d79d9 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -32,6 +32,12 @@ class MADSEngine; #define PALETTE_USAGE_COUNT 4 +#define PALETTE_RESERVED_LOW_COUNT 18 +#define PALETTE_RESERVED_HIGH_COUNT 10 + +#define PALETTE_COUNT 256 +#define PALETTE_SIZE (256 * 3) + /** * Palette mapping options */ @@ -62,6 +68,9 @@ struct RGB6 { byte _u2; byte _flags; + /** + * Load an entry from a stream + */ void load(Common::SeekableReadStream *f); }; @@ -83,8 +92,6 @@ private: MADSEngine *_vm; Common::Array<UsageEntry> *_data; - int rgbMerge(RGB6 &palEntry); - int getGamePalFreeIndex(int *palIndex); int rgbFactor(byte *palEntry, RGB6 &pal6); @@ -142,6 +149,11 @@ public: void reset(); /** + * Copies the data from another instance + */ + void copy(RGBList &src); + + /** * Scans for a free slot */ int scan(); @@ -149,10 +161,52 @@ public: bool &operator[](int idx) { return _data[idx]; } }; -#define PALETTE_COUNT 256 -#define PALETTE_SIZE (256 * 3) +class Fader { +public: + struct GreyEntry { + byte _intensity; + byte _mapColor; + uint16 _accum[3]; + }; + + struct GreyTableEntry { + int _list; + int _mapping; + }; +private: + void mapToGreyRamp(byte palette[PALETTE_SIZE], int baseColor, int numColors, + int baseGrey, int numGreys, GreyEntry *map); + + void getGreyValues(const byte palette[PALETTE_SIZE], GreyTableEntry greyList[PALETTE_COUNT], + int baseColor, int numColors); + + /** + * Given a grey value list containing grey shades (0-63), creates a 64 byte + * grey table containing the number of grey values for each intensity + */ + void greyPopularity(const GreyTableEntry greyList[PALETTE_COUNT], byte greyTable[64], int numColors); +public: + bool _colorFlags[4]; + int _colorValues[4]; +public: + /** + * Constructor + */ + Fader(); + + int rgbMerge(byte r, byte g, byte b); + + int rgbMerge(RGB6 &palEntry); + + /** + * Fades the given palette to greyscale + */ + void fadeToGrey(byte palette[PALETTE_SIZE], byte paletteMap[PALETTE_COUNT], + int baseColor, int numColors, int baseGrey, int numGreys, + int tickDelay, int steps); +}; -class Palette { +class Palette: public Fader { private: /** * Initialises the first 16 palette indexes with the equivalent |