aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/dialogs.h6
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp83
-rw-r--r--engines/mads/nebular/dialogs_nebular.h26
-rw-r--r--engines/mads/palette.cpp159
-rw-r--r--engines/mads/palette.h64
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