MADS: Cleanup of palette code, updated old-style 4 byte RGB usage to 3 bytes

This commit is contained in:
Paul Gilbert 2014-02-19 21:28:54 -05:00
parent 5c565797e5
commit c687d3f64c
5 changed files with 232 additions and 130 deletions

View File

@ -71,7 +71,7 @@ void MADSEngine::initialise() {
MSprite::setVm(this);
_events = new EventsManager(this);
_palette = new Palette(this);
_palette = Palette::init(this);
_font = Font::init(this);
_resources = new ResourcesManager(this);
_screen = MSurface::init(true);

View File

@ -234,9 +234,9 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
} else {
byte destPixel = *tempDst;
byte r, g, b;
r = CLIP((info.palette[destPixel].r * pixel) >> 10, 0, 31);
g = CLIP((info.palette[destPixel].g * pixel) >> 10, 0, 31);
b = CLIP((info.palette[destPixel].b * pixel) >> 10, 0, 31);
r = CLIP((info.palette[destPixel * 3] * pixel) >> 10, 0, 31);
g = CLIP((info.palette[destPixel * 3 + 1] * pixel) >> 10, 0, 31);
b = CLIP((info.palette[destPixel * 3 + 2] * pixel) >> 10, 0, 31);
pixel = info.inverseColorTable[(b << 10) | (g << 5) | r];
}
}
@ -429,10 +429,10 @@ void MSurfaceMADS::loadBackground(int roomNumber, RGBList **palData) {
tileDataUncomp = tileData.getItemStream(2);
// Set palette
if (!palData) {
_vm->_palette->setMadsPalette(tileDataUncomp, 4);
_vm->_palette->loadPalette(tileDataUncomp, 4);
} else {
int numColors;
RGB8 *rgbList = _vm->_palette->decodeMadsPalette(tileDataUncomp, &numColors);
byte *rgbList = _vm->_palette->decodePalette(tileDataUncomp, &numColors);
*palData = new RGBList(numColors, rgbList, true);
}
delete tileDataUncomp;
@ -495,18 +495,16 @@ void MSurfaceMADS::loadInterface(int index, RGBList **palData) {
char resourceName[20];
sprintf(resourceName, "i%d.int", index);
MadsPack intFile(resourceName, _vm);
RGB8 *palette = new RGB8[16];
byte *palette = new byte[16 * 3];
// Chunk 0, palette
Common::SeekableReadStream *intStream = intFile.getItemStream(0);
for (int i = 0; i < 16; i++) {
palette[i].r = intStream->readByte() << 2;
palette[i].g = intStream->readByte() << 2;
palette[i].b = intStream->readByte() << 2;
intStream->readByte();
intStream->readByte();
intStream->readByte();
palette[i * 3] = intStream->readByte() << 2;
palette[i * 3 + 1] = intStream->readByte() << 2;
palette[i * 3 + 2] = intStream->readByte() << 2;
intStream->skip(3);
}
*palData = new RGBList(16, palette, true);
delete intStream;
@ -551,10 +549,10 @@ void MSurfaceNebular::loadBackgroundStream(Common::SeekableReadStream *source, R
// Set palette
if (!palData) {
_vm->_palette->setMadsPalette(sourceUnc, 4);
_vm->_palette->loadPalette(sourceUnc, 4);
} else {
int numColors;
RGB8 *rgbList = _vm->_palette->decodeMadsPalette(sourceUnc, &numColors);
byte *rgbList = _vm->_palette->decodePalette(sourceUnc, &numColors);
*palData = new RGBList(numColors, rgbList, true);
}
delete sourceUnc;
@ -598,7 +596,7 @@ void MSurfaceM4::loadBackgroundStream(Common::SeekableReadStream *source) {
MSurface *tileBuffer = MSurface::init();
uint curTileX = 0, curTileY = 0;
int clipX = 0, clipY = 0;
RGB8 palette[256];
byte palette[256];
source->skip(4);
/*uint32 size =*/ source->readUint32LE();
@ -612,12 +610,13 @@ void MSurfaceM4::loadBackgroundStream(Common::SeekableReadStream *source) {
// BGR data, which is converted to RGB8
for (uint i = 0; i < 256; i++) {
palette[i].b = source->readByte() << 2;
palette[i].g = source->readByte() << 2;
palette[i].r = source->readByte() << 2;
palette[i].u = source->readByte() << 2;
byte r, g, b;
palette[i * 3] = r = source->readByte() << 2;
palette[i * 3 + 1] = g = source->readByte() << 2;
palette[i * 3 + 2] = b = source->readByte() << 2;
source->skip(1);
if ((blackIndex == 0) && !palette[i].r && !palette[i].g && !palette[i].b)
if ((blackIndex == 0) && !r && !g && !b)
blackIndex = i;
}

View File

@ -43,7 +43,7 @@ struct SpriteInfo {
int scaleX, scaleY;
uint8 encoding;
byte *inverseColorTable;
RGB8 *palette;
byte *palette;
};
/*

View File

@ -28,12 +28,12 @@
namespace MADS {
RGBList::RGBList(int numEntries, RGB8 *srcData, bool freeData) {
RGBList::RGBList(int numEntries, byte *srcData, bool freeData) {
_size = numEntries;
assert(numEntries <= 256);
assert(numEntries <= PALETTE_COUNT);
if (srcData == NULL) {
_data = new RGB8[numEntries];
_data = new byte[numEntries * 3];
_freeData = true;
} else {
_data = srcData;
@ -54,10 +54,18 @@ RGBList::~RGBList() {
#define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2)
Palette *Palette::init(MADSEngine *vm) {
if (vm->getGameFeatures() & GF_MADS) {
return new PaletteMADS(vm);
} else {
return new PaletteM4(vm);
}
}
Palette::Palette(MADSEngine *vm) : _vm(vm) {
reset();
_fading_in_progress = false;
Common::fill(&_usageCount[0], &_usageCount[256], 0);
Common::fill(&_usageCount[0], &_usageCount[PALETTE_COUNT], 0);
}
void Palette::setPalette(const byte *colors, uint start, uint num) {
@ -65,31 +73,26 @@ void Palette::setPalette(const byte *colors, uint start, uint num) {
reset();
}
void Palette::setPalette(const RGB8 *colors, uint start, uint num) {
g_system->getPaletteManager()->setPalette((const byte *)colors, start, num);
reset();
}
void Palette::grabPalette(byte *colors, uint start, uint num) {
g_system->getPaletteManager()->grabPalette(colors, start, num);
reset();
}
uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData) {
uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, byte *paletteData) {
byte index = 0;
int32 minDist = 0x7fffffff;
RGB8 palData[256];
byte palData[PALETTE_SIZE];
int Rdiff, Gdiff, Bdiff;
if (paletteData == NULL) {
g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256);
g_system->getPaletteManager()->grabPalette(palData, 0, PALETTE_COUNT);
paletteData = &palData[0];
}
for (int palIndex = 0; palIndex < 256; ++palIndex) {
Rdiff = r - paletteData[palIndex].r;
Gdiff = g - paletteData[palIndex].g;
Bdiff = b - paletteData[palIndex].b;
for (int palIndex = 0; palIndex < PALETTE_COUNT; ++palIndex) {
Rdiff = r - paletteData[palIndex * 3];
Gdiff = g - paletteData[palIndex * 3 + 1];
Bdiff = b - paletteData[palIndex * 3 + 2];
if (Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff < minDist) {
minDist = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
@ -101,8 +104,8 @@ uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData) {
}
void Palette::reset() {
RGB8 palData[256];
g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256);
byte palData[PALETTE_SIZE];
g_system->getPaletteManager()->grabPalette(palData, 0, PALETTE_COUNT);
BLACK = palIndexFromRgb(0, 0, 0, palData);
BLUE = palIndexFromRgb(0, 0, 255, palData);
@ -126,13 +129,13 @@ void Palette::fadeIn(int numSteps, uint delayAmount, RGBList *destPalette) {
fadeIn(numSteps, delayAmount, destPalette->data(), destPalette->size());
}
void Palette::fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numColors) {
void Palette::fadeIn(int numSteps, uint delayAmount, byte *destPalette, int numColors) {
if (_fading_in_progress)
return;
_fading_in_progress = true;
RGB8 blackPalette[256];
Common::fill((byte *)&blackPalette[0], (byte *)&blackPalette[256], 0);
byte blackPalette[PALETTE_SIZE];
Common::fill(&blackPalette[0], &blackPalette[PALETTE_SIZE], 0);
// Initially set the black palette
_vm->_palette->setPalette(blackPalette, 0, numColors);
@ -143,52 +146,8 @@ void Palette::fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numC
_fading_in_progress = false;
}
RGB8 *Palette::decodeMadsPalette(Common::SeekableReadStream *palStream, int *numColors) {
*numColors = palStream->readUint16LE();
assert(*numColors <= 252);
RGB8 *palData = new RGB8[*numColors];
Common::fill((byte *)&palData[0], (byte *)&palData[*numColors], 0);
for (int i = 0; i < *numColors; ++i) {
byte r = palStream->readByte();
byte g = palStream->readByte();
byte b = palStream->readByte();
palData[i].r = VGA_COLOR_TRANS(r);
palData[i].g = VGA_COLOR_TRANS(g);
palData[i].b = VGA_COLOR_TRANS(b);
// The next 3 bytes are unused
palStream->skip(3);
}
return palData;
}
int Palette::setMadsPalette(Common::SeekableReadStream *palStream, int indexStart) {
int colorCount;
RGB8 *palData = Palette::decodeMadsPalette(palStream, &colorCount);
_vm->_palette->setPalette(palData, indexStart, colorCount);
delete palData;
return colorCount;
}
void Palette::setMadsSystemPalette() {
// Rex Nebular default system palette
resetColorCounts();
RGB8 palData[4];
palData[0].r = palData[0].g = palData[0].b = 0;
palData[1].r = palData[1].g = palData[1].b = 0x54;
palData[2].r = palData[2].g = palData[2].b = 0xb4;
palData[3].r = palData[3].g = palData[3].b = 0xff;
setPalette(palData, 0, 4);
blockRange(0, 4);
}
void Palette::resetColorCounts() {
Common::fill(&_usageCount[0], &_usageCount[256], 0);
Common::fill(&_usageCount[0], &_usageCount[PALETTE_COUNT], 0);
}
void Palette::blockRange(int startIndex, int size) {
@ -197,41 +156,41 @@ void Palette::blockRange(int startIndex, int size) {
}
void Palette::addRange(RGBList *list) {
RGB8 *data = list->data();
byte *data = list->data();
byte *palIndexes = list->palIndexes();
RGB8 palData[256];
g_system->getPaletteManager()->grabPalette((byte *)&palData[0], 0, 256);
byte palData[PALETTE_COUNT];
g_system->getPaletteManager()->grabPalette(palData, 0, PALETTE_COUNT);
bool paletteChanged = false;
for (int colIndex = 0; colIndex < list->size(); ++colIndex) {
// Scan through for an existing copy of the RGB value
int palIndex = -1;
while (++palIndex < 256) {
while (++palIndex < PALETTE_COUNT) {
if (_usageCount[palIndex] <= 0)
// Palette index is to be skipped
continue;
if ((palData[palIndex].r == data[colIndex].r) &&
(palData[palIndex].g == data[colIndex].g) &&
(palData[palIndex].b == data[colIndex].b))
if ((palData[palIndex * 3] == data[colIndex * 3]) &&
(palData[palIndex * 3 + 1] == data[colIndex * 3 + 1]) &&
(palData[palIndex * 3 + 2] == data[colIndex * 3 + 2]))
// Match found
break;
}
if (palIndex == 256) {
if (palIndex == PALETTE_COUNT) {
// No match found, so find a free slot to use
palIndex = -1;
while (++palIndex < 256) {
while (++palIndex < PALETTE_COUNT) {
if (_usageCount[palIndex] == 0)
break;
}
if (palIndex == 256)
if (palIndex == PALETTE_COUNT)
error("addRange - Ran out of palette space to allocate");
palData[palIndex].r = data[colIndex].r;
palData[palIndex].g = data[colIndex].g;
palData[palIndex].b = data[colIndex].b;
palData[palIndex * 3] = data[colIndex * 3];
palData[palIndex * 3 + 1] = data[colIndex * 3 + 1];
palData[palIndex * 3 + 2] = data[colIndex * 3 + 2];
paletteChanged = true;
}
@ -240,7 +199,7 @@ void Palette::addRange(RGBList *list) {
}
if (paletteChanged) {
g_system->getPaletteManager()->setPalette((byte *)&palData[0], 0, 256);
g_system->getPaletteManager()->setPalette(&palData[0], 0, 256);
reset();
}
}
@ -259,9 +218,9 @@ void Palette::deleteAllRanges() {
_usageCount[colIndex] = 0;
}
void Palette::fadeRange(RGB8 *srcPal, RGB8 *destPal, int startIndex, int endIndex,
void Palette::fadeRange(byte *srcPal, byte *destPal, int startIndex, int endIndex,
int numSteps, uint delayAmount) {
RGB8 tempPal[256];
byte tempPal[256 * 3];
// perform the fade
for(int stepCtr = 1; stepCtr <= numSteps; ++stepCtr) {
@ -274,16 +233,62 @@ void Palette::fadeRange(RGB8 *srcPal, RGB8 *destPal, int startIndex, int endInd
for (int i = startIndex; i <= endIndex; ++i) {
// Handle the intermediate rgb values for fading
tempPal[i].r = (byte) (srcPal[i].r + (destPal[i].r - srcPal[i].r) * stepCtr / numSteps);
tempPal[i].g = (byte) (srcPal[i].g + (destPal[i].g - srcPal[i].g) * stepCtr / numSteps);
tempPal[i].b = (byte) (srcPal[i].b + (destPal[i].b - srcPal[i].b) * stepCtr / numSteps);
tempPal[i * 3] = (byte) (srcPal[i * 3] + (destPal[i * 3] - srcPal[i * 3]) * stepCtr / numSteps);
tempPal[i * 3 + 1] = (byte) (srcPal[i * 3 + 1] + (destPal[i * 3 + 1] - srcPal[i * 3 + 1]) * stepCtr / numSteps);
tempPal[i * 3 + 2] = (byte) (srcPal[i * 3 + 2] + (destPal[i * 3 + 2] - srcPal[i * 3 + 2]) * stepCtr / numSteps);
}
_vm->_palette->setPalette(&tempPal[startIndex], startIndex, endIndex - startIndex + 1);
_vm->_palette->setPalette(&tempPal[startIndex * 3], startIndex, endIndex - startIndex + 1);
}
// Make sure the end palette exactly matches what is wanted
_vm->_palette->setPalette(&destPal[startIndex], startIndex, endIndex - startIndex + 1);
_vm->_palette->setPalette(&destPal[startIndex * 3], startIndex, endIndex - startIndex + 1);
}
/*------------------------------------------------------------------------*/
byte *PaletteMADS::decodePalette(Common::SeekableReadStream *palStream, int *numColors) {
*numColors = palStream->readUint16LE();
assert(*numColors <= 252);
byte *palData = new byte[*numColors * 3];
Common::fill(&palData[0], &palData[*numColors * 3], 0);
for (int i = 0; i < *numColors; ++i) {
byte r = palStream->readByte();
byte g = palStream->readByte();
byte b = palStream->readByte();
palData[i * 3] = VGA_COLOR_TRANS(r);
palData[i * 3 + 1] = VGA_COLOR_TRANS(g);
palData[i * 3 + 2] = VGA_COLOR_TRANS(b);
// The next 3 bytes are unused
palStream->skip(3);
}
return palData;
}
int PaletteMADS::loadPalette(Common::SeekableReadStream *palStream, int indexStart) {
int colorCount;
byte *palData = decodePalette(palStream, &colorCount);
_vm->_palette->setPalette(palData, indexStart, colorCount);
delete palData;
return colorCount;
}
void PaletteMADS::setSystemPalette() {
resetColorCounts();
byte palData[4 * 3];
palData[0 * 3] = palData[0 * 3 + 1] = palData[0 * 3 + 2] = 0;
palData[1 * 3] = palData[1 * 3 + 1] = palData[1 * 3 + 2] = 0x54;
palData[2 * 3] = palData[2 * 3 + 1] = palData[2 * 3 + 2] = 0xb4;
palData[3 * 3] = palData[3 * 3 + 1] = palData[3 * 3 + 2] = 0xff;
setPalette(palData, 0, 4);
blockRange(0, 4);
}
} // End of namespace MADS

View File

@ -29,63 +29,137 @@ namespace MADS {
class MADSEngine;
struct RGB8 {
uint8 r, g, b, u;
};
/**
* Used to store a list of RGB values
*/
class RGBList {
private:
int _size;
RGB8 *_data;
byte *_data;
byte *_palIndexes;
bool _freeData;
public:
RGBList(int numEntries = 256, RGB8 *srcData = NULL, bool freeData = true);
/**
* Constructor
*/
RGBList(int numEntries = 256, byte *srcData = NULL, bool freeData = true);
/**
* Destructor
*/
~RGBList();
RGB8 *data() { return _data; }
/**
* Returns the raw data containing the RGB values as 3 bytes per entry
*/
byte *data() { return _data; }
/**
* Returns the list of palette indexes each RGB tuple maps to in the current palette
*/
byte *palIndexes() { return _palIndexes; }
int size() { return _size; }
/**
* Returns the size of the palette
*/
int size() const { return _size; }
};
#define PALETTE_COUNT 256
#define PALETTE_SIZE (256 * 3)
class Palette {
private:
/**
* Support method used by the fading code
*/
void fadeRange(byte *srcPal, byte *destPal, int startIndex, int endIndex,
int numSteps, uint delayAmount);
protected:
MADSEngine *_vm;
bool _colorsChanged;
bool _fading_in_progress;
byte _originalPalette[PALETTE_COUNT * 4];
byte _fadedPalette[PALETTE_COUNT * 4];
int _usageCount[PALETTE_COUNT];
Palette(MADSEngine *vm);
void reset();
public:
Palette(MADSEngine *vm);
/**
* Creates a new palette instance
*/
static Palette *init(MADSEngine *vm);
/**
* Sets a new palette
*/
void setPalette(const byte *colors, uint start, uint num);
void setPalette(const RGB8 *colors, uint start, uint num);
void grabPalette(byte *colors, uint start, uint num);
void grabPalette(RGB8 *colors, uint start, uint num) {
grabPalette((byte *)colors, start, num);
}
uint8 palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData = NULL);
void fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numColors);
/**
* Returns a subset of the currently loaded palette
*/
void grabPalette(byte *colors, uint start, uint num);
/**
* Returns the palette index in the palette that most closely matches the
* specified RGB pair
*/
uint8 palIndexFromRgb(byte r, byte g, byte b, byte *paletteData = nullptr);
/**
* Performs a fade in
*/
void fadeIn(int numSteps, uint delayAmount, byte *destPalette, int numColors);
/**
* Performs a fade in
*/
void fadeIn(int numSteps, uint delayAmount, RGBList *destPalette);
static RGB8 *decodeMadsPalette(Common::SeekableReadStream *palStream, int *numColors);
int setMadsPalette(Common::SeekableReadStream *palStream, int indexStart = 0);
void setMadsSystemPalette();
void fadeRange(RGB8 *srcPal, RGB8 *destPal, int startIndex, int endIndex,
int numSteps, uint delayAmount);
// Methods used for reference counting color usage
/**
* Resets the usage counts for the palette
*/
void resetColorCounts();
/**
* Blocks out a range of the palette from being used
*/
void blockRange(int startIndex, int size);
/**
* Adds the data of an RGBList into the current palette and increment usage counts.
*/
void addRange(RGBList *list);
/**
* Delets a range from the current palette, dercementing the accompanying usage counts.
*/
void deleteRange(RGBList *list);
/**
* Deletes all loaded RGB lists are their usage references.
*/
void deleteAllRanges();
// Virtual method table
/**
* Decode a palette and return it, without affecting the Palette itself
*/
virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors) = 0;
/**
* Loads a palette from a stream
*/
virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0) = 0;
/**
* Sets a small set of system/core colors needed by the game
*/
virtual void setSystemPalette() = 0;
// Color indexes
uint8 BLACK;
uint8 BLUE;
@ -105,6 +179,30 @@ public:
uint8 WHITE;
};
class PaletteMADS: protected Palette {
friend class Palette;
protected:
PaletteMADS(MADSEngine *vm): Palette(vm) {}
public:
virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors);
virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0);
virtual void setSystemPalette();
};
class PaletteM4: protected Palette {
friend class Palette;
protected:
PaletteM4(MADSEngine *vm): Palette(vm) {}
public:
virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors) {
return nullptr;
}
virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0) {
return 0;
}
virtual void setSystemPalette() {}
};
} // End of namespace MADS
#endif /* MADS_PALETTE_H */