Revert "SCI32: Fix broken Remap implementation"

This reverts commit cfda8b9ecd8a6e3c003abe533ea2e2981d8ba984.

This is only to re-apply it immediately in a series of smaller commits.
This commit is contained in:
Willem Jan Palenstijn 2016-06-30 23:59:22 +02:00
parent a40e43f777
commit c6c9593840
18 changed files with 522 additions and 1068 deletions

View File

@ -412,7 +412,7 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv);
reg_t kTextColors(EngineState *s, int argc, reg_t *argv);
reg_t kTextFonts(EngineState *s, int argc, reg_t *argv);
reg_t kShow(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv);
reg_t kDummy(EngineState *s, int argc, reg_t *argv);
reg_t kEmpty(EngineState *s, int argc, reg_t *argv);
reg_t kStub(EngineState *s, int argc, reg_t *argv);
@ -482,13 +482,13 @@ reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv);
reg_t kMulDiv(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv);
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
reg_t kRemapOff(EngineState *s, int argc, reg_t *argv);
reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv);
reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv);
reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv);
reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv);
reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv);
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);

View File

@ -414,12 +414,12 @@ static const SciKernelMapSubEntry kList_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kRemapColors_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
{ SIG_SCI32, 1, MAP_CALL(RemapColorsByRange), "iiii(i)", NULL },
{ SIG_SCI32, 2, MAP_CALL(RemapColorsByPercent), "ii(i)", NULL },
{ SIG_SCI32, 3, MAP_CALL(RemapColorsToGray), "ii(i)", NULL },
{ SIG_SCI32, 4, MAP_CALL(RemapColorsToPercentGray), "iii(i)", NULL },
{ SIG_SCI32, 5, MAP_CALL(RemapColorsBlockRange), "ii", NULL },
{ SIG_SCI32, 0, MAP_CALL(RemapOff), "(i)", NULL },
{ SIG_SCI32, 1, MAP_CALL(RemapByRange), "iiii(i)", NULL },
{ SIG_SCI32, 2, MAP_CALL(RemapByPercent), "ii(i)", NULL },
{ SIG_SCI32, 3, MAP_CALL(RemapToGray), "ii(i)", NULL },
{ SIG_SCI32, 4, MAP_CALL(RemapToPercentGray), "iii(i)", NULL },
{ SIG_SCI32, 5, MAP_CALL(RemapSetNoMatchRange), "ii", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@ -634,9 +634,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL },
{ MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, kReadNumber_workarounds },
{ MAP_CALL(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
{ "RemapColors", kRemapColors16, SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
#ifdef ENABLE_SCI32
{ "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
{ MAP_CALL(RemapColors), SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
#endif
{ MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },

View File

@ -1258,7 +1258,7 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) {
}
// Early variant of the SCI32 kRemapColors kernel function, used in the demo of QFG4
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv) {
uint16 operation = argv[0].toUint16();
switch (operation) {

View File

@ -54,7 +54,6 @@
#include "sci/graphics/frameout.h"
#include "sci/graphics/paint32.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
#endif
@ -926,69 +925,57 @@ reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
if (!s)
return make_reg(0, getSciVersion());
error("not supposed to call this");
}
reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv) {
if (argc == 0) {
g_sci->_gfxRemap32->remapAllOff();
} else {
const uint8 color = argv[0].toUint16();
g_sci->_gfxRemap32->remapOff(color);
}
reg_t kRemapOff(EngineState *s, int argc, reg_t *argv) {
byte color = (argc >= 1) ? argv[0].toUint16() : 0;
g_sci->_gfxRemap32->remapOff(color);
return s->r_acc;
}
reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv) {
const uint8 color = argv[0].toUint16();
const int16 from = argv[1].toSint16();
const int16 to = argv[2].toSint16();
const int16 base = argv[3].toSint16();
// NOTE: There is an optional last parameter after `base`
// which was only used by the priority map debugger, which
// does not exist in release versions of SSCI
g_sci->_gfxRemap32->remapByRange(color, from, to, base);
reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv) {
byte color = argv[0].toUint16();
byte from = argv[1].toUint16();
byte to = argv[2].toUint16();
byte base = argv[3].toUint16();
// The last parameter, depth, is unused
g_sci->_gfxRemap32->setRemappingRange(color, from, to, base);
return s->r_acc;
}
reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv) {
const uint8 color = argv[0].toUint16();
const int16 percent = argv[1].toSint16();
// NOTE: There is an optional last parameter after `percent`
// which was only used by the priority map debugger, which
// does not exist in release versions of SSCI
g_sci->_gfxRemap32->remapByPercent(color, percent);
reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv) {
byte color = argv[0].toUint16();
byte percent = argv[1].toUint16();
// The last parameter, depth, is unused
g_sci->_gfxRemap32->setRemappingPercent(color, percent);
return s->r_acc;
}
reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv) {
const uint8 color = argv[0].toUint16();
const int16 gray = argv[1].toSint16();
// NOTE: There is an optional last parameter after `gray`
// which was only used by the priority map debugger, which
// does not exist in release versions of SSCI
g_sci->_gfxRemap32->remapToGray(color, gray);
reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv) {
byte color = argv[0].toUint16();
byte gray = argv[1].toUint16();
// The last parameter, depth, is unused
g_sci->_gfxRemap32->setRemappingToGray(color, gray);
return s->r_acc;
}
reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv) {
const uint8 color = argv[0].toUint16();
const int16 gray = argv[1].toSint16();
const int16 percent = argv[2].toSint16();
// NOTE: There is an optional last parameter after `percent`
// which was only used by the priority map debugger, which
// does not exist in release versions of SSCI
g_sci->_gfxRemap32->remapToPercentGray(color, gray, percent);
reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv) {
byte color = argv[0].toUint16();
byte gray = argv[1].toUint16();
byte percent = argv[2].toUint16();
// The last parameter, depth, is unused
g_sci->_gfxRemap32->setRemappingToPercentGray(color, gray, percent);
return s->r_acc;
}
reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv) {
const uint8 from = argv[0].toUint16();
const uint8 count = argv[1].toUint16();
g_sci->_gfxRemap32->blockRange(from, count);
reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv) {
byte from = argv[0].toUint16();
byte count = argv[1].toUint16();
g_sci->_gfxRemap32->setNoMatchRange(from, count);
return s->r_acc;
}

View File

@ -48,9 +48,8 @@
#include "sci/sound/music.h"
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/frameout.h"
#endif
namespace Sci {
@ -808,33 +807,6 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
}
}
}
void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) {
if (s.getVersion() < 35) {
return;
}
s.syncAsByte(_numActiveRemaps);
s.syncAsByte(_blockedRangeStart);
s.syncAsSint16LE(_blockedRangeCount);
for (uint i = 0; i < _remaps.size(); ++i) {
SingleRemap &singleRemap = _remaps[i];
s.syncAsByte(singleRemap._type);
if (s.isLoading() && singleRemap._type != kRemapNone) {
singleRemap.reset();
}
s.syncAsByte(singleRemap._from);
s.syncAsByte(singleRemap._to);
s.syncAsByte(singleRemap._delta);
s.syncAsByte(singleRemap._percent);
s.syncAsByte(singleRemap._gray);
}
if (s.isLoading()) {
_needsUpdate = true;
}
}
#endif
void GfxPorts::saveLoadWithSerializer(Common::Serializer &s) {

View File

@ -37,7 +37,6 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
* 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
* 33 - new overridePriority flag in MusicEntry
* 32 - new playBed flag in MusicEntry
@ -60,7 +59,7 @@ struct EngineState;
*/
enum {
CURRENT_SAVEGAME_VERSION = 35,
CURRENT_SAVEGAME_VERSION = 34,
MINIMUM_SAVEGAME_VERSION = 14
};

View File

@ -26,12 +26,13 @@
#include "sci/graphics/celobj32.h"
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/text32.h"
#include "sci/graphics/view.h"
namespace Sci {
#pragma mark CelScaler
CelScaler *CelObj::_scaler = nullptr;
void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) {
@ -322,10 +323,6 @@ public:
#pragma mark -
#pragma mark CelObj - Remappers
/**
* Pixel mapper for a CelObj with transparent pixels and no
* remapping data.
*/
struct MAPPER_NoMD {
inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
if (pixel != skipColor) {
@ -333,49 +330,25 @@ struct MAPPER_NoMD {
}
}
};
/**
* Pixel mapper for a CelObj with no transparent pixels and
* no remapping data.
*/
struct MAPPER_NoMDNoSkip {
inline void draw(byte *target, const byte pixel, const uint8) const {
*target = pixel;
}
};
/**
* Pixel mapper for a CelObj with transparent pixels,
* remapping data, and remapping enabled.
*/
struct MAPPER_Map {
inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
if (pixel != skipColor) {
// NOTE: For some reason, SSCI never checks if the source
// pixel is *above* the range of remaps.
if (pixel < g_sci->_gfxRemap32->getStartColor()) {
*target = pixel;
} else if (g_sci->_gfxRemap32->remapEnabled(pixel)) {
*target = g_sci->_gfxRemap32->remapColor(pixel, *target);
} else {
if (g_sci->_gfxRemap32->remapEnabled(pixel))
*target = g_sci->_gfxRemap32->remapColor(pixel, *target);
}
}
}
};
/**
* Pixel mapper for a CelObj with transparent pixels,
* remapping data, and remapping disabled.
*/
struct MAPPER_NoMap {
inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
// NOTE: For some reason, SSCI never checks if the source
// pixel is *above* the range of remaps.
if (pixel != skipColor && pixel < g_sci->_gfxRemap32->getStartColor()) {
*target = pixel;
}
}
};
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const {
const Common::Point &scaledPosition = screenItem._scaledPosition;
const Ratio &scaleX = screenItem._ratioX;
@ -550,7 +523,6 @@ void CelObj::submitPalette() const {
#pragma mark -
#pragma mark CelObj - Caching
int CelObj::_nextCacheId = 1;
CelCache *CelObj::_cache = nullptr;
@ -652,35 +624,33 @@ void dummyFill(Buffer &target, const Common::Rect &targetRect) {
}
void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMap, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition);
debug("drawHzFlip");
dummyFill(target, targetRect);
}
void CelObj::drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMap, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition);
debug("drawNoFlip");
dummyFill(target, targetRect);
}
void CelObj::drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMap, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
debug("drawUncompNoFlip");
dummyFill(target, targetRect);
}
void CelObj::drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMap, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
debug("drawUncompHzFlip");
dummyFill(target, targetRect);
}
void CelObj::scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
if (_drawMirrored) {
render<MAPPER_NoMap, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
} else {
render<MAPPER_NoMap, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
debug("scaleDraw");
dummyFill(target, targetRect);
}
void CelObj::scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
if (_drawMirrored) {
render<MAPPER_NoMap, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
} else {
render<MAPPER_NoMap, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
debug("scaleDrawUncomp");
dummyFill(target, targetRect);
}
void CelObj::drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
@ -700,19 +670,17 @@ void CelObj::drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect,
}
void CelObj::scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
if (_drawMirrored) {
if (_drawMirrored)
render<MAPPER_Map, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
} else {
else
render<MAPPER_Map, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
}
void CelObj::scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
if (_drawMirrored) {
if (_drawMirrored)
render<MAPPER_Map, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
} else {
else
render<MAPPER_Map, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
}
void CelObj::drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
@ -747,16 +715,14 @@ void CelObj::scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &sca
}
void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
if (_drawMirrored) {
if (_drawMirrored)
render<MAPPER_NoMD, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
} else {
else
render<MAPPER_NoMD, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
}
}
#pragma mark -
#pragma mark CelObjView
CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
_info.type = kCelTypeView;
_info.resourceId = viewId;
@ -874,12 +840,8 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
bool CelObjView::analyzeUncompressedForRemap() const {
byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
for (int i = 0; i < _width * _height; ++i) {
const byte pixel = pixels[i];
if (
pixel >= g_sci->_gfxRemap32->getStartColor() &&
pixel <= g_sci->_gfxRemap32->getEndColor() &&
pixel != _transparentColor
) {
byte pixel = pixels[i];
if (pixel >= g_sci->_gfxRemap32->getStartColor() && pixel <= g_sci->_gfxRemap32->getEndColor() && pixel != _transparentColor) {
return true;
}
}
@ -891,12 +853,8 @@ bool CelObjView::analyzeForRemap() const {
for (int y = 0; y < _height; y++) {
const byte *curRow = reader.getRow(y);
for (int x = 0; x < _width; x++) {
const byte pixel = curRow[x];
if (
pixel >= g_sci->_gfxRemap32->getStartColor() &&
pixel <= g_sci->_gfxRemap32->getEndColor() &&
pixel != _transparentColor
) {
byte pixel = curRow[x];
if (pixel >= g_sci->_gfxRemap32->getStartColor() && pixel <= g_sci->_gfxRemap32->getEndColor() && pixel != _transparentColor) {
return true;
}
}
@ -923,7 +881,6 @@ byte *CelObjView::getResPointer() const {
#pragma mark -
#pragma mark CelObjPic
CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
_info.type = kCelTypePic;
_info.resourceId = picId;
@ -1045,7 +1002,6 @@ byte *CelObjPic::getResPointer() const {
#pragma mark -
#pragma mark CelObjMem
CelObjMem::CelObjMem(const reg_t bitmapObject) {
_info.type = kCelTypeMem;
_info.bitmap = bitmapObject;
@ -1075,7 +1031,6 @@ byte *CelObjMem::getResPointer() const {
#pragma mark -
#pragma mark CelObjColor
CelObjColor::CelObjColor(const uint8 color, const int16 width, const int16 height) {
_info.type = kCelTypeColor;
_info.color = color;

View File

@ -42,13 +42,15 @@
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/font.h"
#include "sci/graphics/view.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint32.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/plane32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/screen_item32.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/text32.h"
#include "sci/graphics/plane32.h"
#include "sci/graphics/screen_item32.h"
#include "sci/graphics/frameout.h"
#include "sci/video/robot_decoder.h"
@ -1005,7 +1007,7 @@ void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showLi
}
void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
Palette sourcePalette(_palette->getNextPalette());
Palette sourcePalette(*_palette->getNextPalette());
alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
@ -1045,7 +1047,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
drawScreenItemList(screenItemLists[i]);
}
Palette nextPalette(_palette->getNextPalette());
Palette nextPalette(*_palette->getNextPalette());
if (prevRoom < 1000) {
for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {

View File

@ -28,7 +28,7 @@
#include "sci/event.h"
#include "sci/resource.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
namespace Sci {
@ -78,6 +78,10 @@ inline void mergePaletteInternal(Palette *const to, const Palette *const from) {
}
}
const Palette *GfxPalette32::getNextPalette() const {
return &_nextPalette;
}
void GfxPalette32::submit(Palette &palette) {
// TODO: The resource manager in SCI32 retains raw data of palettes from
// the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and
@ -174,6 +178,49 @@ void GfxPalette32::set(Palette *newPalette, bool force, bool forceRealMerge) {
submit(*newPalette);
}
// In SCI32 engine this method is SOLPalette::Match(Rgb24 *, int, int *, int *)
// and is used by Remap
// TODO: Anything that calls GfxPalette::matchColor(int, int, int) is going to
// match using an algorithm from SCI16 engine right now. This needs to be
// corrected in the future so either nothing calls
// GfxPalette::matchColor(int, int, int), or it is fixed to match the other
// SCI32 algorithms.
int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable) {
int16 bestIndex = -1;
int bestDifference = 0xFFFFF;
int difference = defaultDifference;
// SQ6 DOS really does check only the first 236 entries
for (int i = 0, channelDifference; i < 236; ++i) {
if (matchTable[i] == 0) {
continue;
}
difference = _sysPalette.colors[i].r - r;
difference *= difference;
if (bestDifference <= difference) {
continue;
}
channelDifference = _sysPalette.colors[i].g - g;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
}
channelDifference = _sysPalette.colors[i].b - b;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
}
bestDifference = difference;
bestIndex = i;
}
// NOTE: This value is only valid if the last index to
// perform a difference calculation was the best index
lastCalculatedDifference = difference;
return bestIndex;
}
bool GfxPalette32::updateForFrame() {
applyAll();
_versionUpdated = false;

View File

@ -113,12 +113,12 @@ private:
public:
virtual void saveLoadWithSerializer(Common::Serializer &s) override;
inline const Palette &getNextPalette() const { return _nextPalette; };
inline const Palette &getCurrentPalette() const { return _sysPalette; };
const Palette *getNextPalette() const;
bool kernelSetFromResource(GuiResourceId resourceId, bool force) override;
int16 kernelFindColor(uint16 r, uint16 g, uint16 b) override;
void set(Palette *newPalette, bool force, bool forceRealMerge = false) override;
int16 matchColor(const byte matchRed, const byte matchGreen, const byte matchBlue, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable);
/**
* Submits a palette to display. Entries marked as used in the
@ -240,11 +240,6 @@ private:
* According to SCI engine code, when two cyclers overlap,
* a fatal error has occurred and the engine will display
* an error and then exit.
*
* The cycle map is also by the color remapping system to
* avoid attempting to remap to palette entries that are
* cycling (so won't be the expected color once the cycler
* runs again).
*/
bool _cycleMap[256];
inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear);
@ -262,7 +257,7 @@ public:
void cycleAllOff();
void applyAllCycles();
void applyCycles();
inline const bool *getCycleMap() const { return _cycleMap; }
const bool *getCyclemap() { return _cycleMap; }
#pragma mark -
#pragma mark Fading

View File

@ -27,7 +27,7 @@
#include "sci/graphics/frameout.h"
#include "sci/graphics/lists32.h"
#include "sci/graphics/plane32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/screen_item32.h"

View File

@ -21,23 +21,31 @@
*/
#include "sci/sci.h"
#include "sci/resource.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
namespace Sci {
#pragma mark -
#pragma mark SCI16 remapping (QFG4 demo)
GfxRemap::GfxRemap(GfxPalette *palette)
: _palette(palette) {
_remapOn = false;
resetRemapping();
}
GfxRemap::~GfxRemap() {
}
byte GfxRemap::remapColor(byte remappedColor, byte screenColor) {
assert(_remapOn);
if (_remappingType[remappedColor] == kRemapByRange)
if (_remappingType[remappedColor] == kRemappingByRange)
return _remappingByRange[screenColor];
else if (_remappingType[remappedColor] == kRemapByPercent)
else if (_remappingType[remappedColor] == kRemappingByPercent)
return _remappingByPercent[screenColor];
else
error("remapColor(): Color %d isn't remapped", remappedColor);
@ -50,7 +58,7 @@ void GfxRemap::resetRemapping() {
_remappingPercentToSet = 0;
for (int i = 0; i < 256; i++) {
_remappingType[i] = kRemapNone;
_remappingType[i] = kRemappingNone;
_remappingByPercent[i] = i;
_remappingByRange[i] = i;
}
@ -72,7 +80,7 @@ void GfxRemap::setRemappingPercent(byte color, byte percent) {
_remappingByPercent[i] = _palette->kernelFindColor(r, g, b);
}
_remappingType[color] = kRemapByPercent;
_remappingType[color] = kRemappingByPercent;
}
void GfxRemap::setRemappingRange(byte color, byte from, byte to, byte base) {
@ -82,7 +90,7 @@ void GfxRemap::setRemappingRange(byte color, byte from, byte to, byte base) {
_remappingByRange[i] = i + base;
}
_remappingType[color] = kRemapByRange;
_remappingType[color] = kRemappingByRange;
}
void GfxRemap::updateRemapping() {
@ -96,4 +104,277 @@ void GfxRemap::updateRemapping() {
}
}
}
#pragma mark -
#pragma mark SCI32 remapping
#ifdef ENABLE_SCI32
GfxRemap32::GfxRemap32(GfxPalette32 *palette) : _palette(palette) {
for (int i = 0; i < REMAP_COLOR_COUNT; i++)
_remaps[i] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
_noMapStart = _noMapCount = 0;
_update = false;
_remapCount = 0;
// The remap range was 245 - 254 in SCI2, but was changed to 235 - 244 in SCI21 middle.
// All versions of KQ7 are using the older remap range semantics.
_remapEndColor = (getSciVersion() >= SCI_VERSION_2_1_MIDDLE || g_sci->getGameId() == GID_KQ7) ? 244 : 254;
}
void GfxRemap32::remapOff(byte color) {
if (!color) {
for (int i = 0; i < REMAP_COLOR_COUNT; i++)
_remaps[i] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
_remapCount = 0;
} else {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
const byte index = _remapEndColor - color;
_remaps[index] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
_remapCount--;
}
_update = true;
}
void GfxRemap32::setRemappingRange(byte color, byte from, byte to, byte base) {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
_remaps[_remapEndColor - color] = RemapParams(from, to, base, 0, 100, kRemappingByRange);
initColorArrays(_remapEndColor - color);
_remapCount++;
_update = true;
}
void GfxRemap32::setRemappingPercent(byte color, byte percent) {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
_remaps[_remapEndColor - color] = RemapParams(0, 0, 0, 0, percent, kRemappingByPercent);
initColorArrays(_remapEndColor - color);
_remapCount++;
_update = true;
}
void GfxRemap32::setRemappingToGray(byte color, byte gray) {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
_remaps[_remapEndColor - color] = RemapParams(0, 0, 0, gray, 100, kRemappingToGray);
initColorArrays(_remapEndColor - color);
_remapCount++;
_update = true;
}
void GfxRemap32::setRemappingToPercentGray(byte color, byte gray, byte percent) {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
_remaps[_remapEndColor - color] = RemapParams(0, 0, 0, gray, percent, kRemappingToPercentGray);
initColorArrays(_remapEndColor - color);
_remapCount++;
_update = true;
}
void GfxRemap32::setNoMatchRange(byte from, byte count) {
_noMapStart = from;
_noMapCount = count;
}
bool GfxRemap32::remapEnabled(byte color) const {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
const byte index = _remapEndColor - color;
return (_remaps[index].type != kRemappingNone);
}
byte GfxRemap32::remapColor(byte color, byte target) {
assert(_remapEndColor - color >= 0 && _remapEndColor - color < REMAP_COLOR_COUNT);
const byte index = _remapEndColor - color;
if (_remaps[index].type != kRemappingNone)
return _remaps[index].remap[target];
else
return target;
}
void GfxRemap32::initColorArrays(byte index) {
Palette *curPalette = &_palette->_sysPalette;
RemapParams *curRemap = &_remaps[index];
memcpy(curRemap->curColor, curPalette->colors, NON_REMAPPED_COLOR_COUNT * sizeof(Color));
memcpy(curRemap->targetColor, curPalette->colors, NON_REMAPPED_COLOR_COUNT * sizeof(Color));
}
bool GfxRemap32::updateRemap(byte index, bool palChanged) {
int result;
RemapParams *curRemap = &_remaps[index];
const Palette *curPalette = &_palette->_sysPalette;
const Palette *nextPalette = _palette->getNextPalette();
bool changed = false;
if (!_update && !palChanged)
return false;
Common::fill(_targetChanged, _targetChanged + NON_REMAPPED_COLOR_COUNT, false);
switch (curRemap->type) {
case kRemappingNone:
return false;
case kRemappingByRange:
for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++) {
if (curRemap->from <= i && i <= curRemap->to)
result = i + curRemap->base;
else
result = i;
if (curRemap->remap[i] != result) {
changed = true;
curRemap->remap[i] = result;
}
curRemap->colorChanged[i] = true;
}
return changed;
case kRemappingByPercent:
for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
// NOTE: This method uses nextPalette instead of curPalette
Color color = nextPalette->colors[i];
if (curRemap->curColor[i] != color) {
curRemap->colorChanged[i] = true;
curRemap->curColor[i] = color;
}
if (curRemap->percent != curRemap->oldPercent || curRemap->colorChanged[i]) {
byte red = CLIP<byte>(color.r * curRemap->percent / 100, 0, 255);
byte green = CLIP<byte>(color.g * curRemap->percent / 100, 0, 255);
byte blue = CLIP<byte>(color.b * curRemap->percent / 100, 0, 255);
byte used = curRemap->targetColor[i].used;
Color newColor = { used, red, green, blue };
if (curRemap->targetColor[i] != newColor) {
_targetChanged[i] = true;
curRemap->targetColor[i] = newColor;
}
}
}
changed = applyRemap(index);
Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
curRemap->oldPercent = curRemap->percent;
return changed;
case kRemappingToGray:
for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
Color color = curPalette->colors[i];
if (curRemap->curColor[i] != color) {
curRemap->colorChanged[i] = true;
curRemap->curColor[i] = color;
}
if (curRemap->gray != curRemap->oldGray || curRemap->colorChanged[i]) {
byte lumosity = ((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8;
byte red = CLIP<byte>(color.r - ((color.r - lumosity) * curRemap->gray / 100), 0, 255);
byte green = CLIP<byte>(color.g - ((color.g - lumosity) * curRemap->gray / 100), 0, 255);
byte blue = CLIP<byte>(color.b - ((color.b - lumosity) * curRemap->gray / 100), 0, 255);
byte used = curRemap->targetColor[i].used;
Color newColor = { used, red, green, blue };
if (curRemap->targetColor[i] != newColor) {
_targetChanged[i] = true;
curRemap->targetColor[i] = newColor;
}
}
}
changed = applyRemap(index);
Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
curRemap->oldGray = curRemap->gray;
return changed;
case kRemappingToPercentGray:
for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
Color color = curPalette->colors[i];
if (curRemap->curColor[i] != color) {
curRemap->colorChanged[i] = true;
curRemap->curColor[i] = color;
}
if (curRemap->percent != curRemap->oldPercent || curRemap->gray != curRemap->oldGray || curRemap->colorChanged[i]) {
byte lumosity = ((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8;
lumosity = lumosity * curRemap->percent / 100;
byte red = CLIP<byte>(color.r - ((color.r - lumosity) * curRemap->gray / 100), 0, 255);
byte green = CLIP<byte>(color.g - ((color.g - lumosity) * curRemap->gray / 100), 0, 255);
byte blue = CLIP<byte>(color.b - ((color.b - lumosity) * curRemap->gray / 100), 0, 255);
byte used = curRemap->targetColor[i].used;
Color newColor = { used, red, green, blue };
if (curRemap->targetColor[i] != newColor) {
_targetChanged[i] = true;
curRemap->targetColor[i] = newColor;
}
}
}
changed = applyRemap(index);
Common::fill(curRemap->colorChanged, curRemap->colorChanged + NON_REMAPPED_COLOR_COUNT, false);
curRemap->oldPercent = curRemap->percent;
curRemap->oldGray = curRemap->gray;
return changed;
default:
return false;
}
}
static int colorDistance(Color a, Color b) {
int rDiff = (a.r - b.r) * (a.r - b.r);
int gDiff = (a.g - b.g) * (a.g - b.g);
int bDiff = (a.b - b.b) * (a.b - b.b);
return rDiff + gDiff + bDiff;
}
bool GfxRemap32::applyRemap(byte index) {
RemapParams *curRemap = &_remaps[index];
const bool *cycleMap = _palette->getCyclemap();
bool unmappedColors[NON_REMAPPED_COLOR_COUNT];
bool changed = false;
Common::fill(unmappedColors, unmappedColors + NON_REMAPPED_COLOR_COUNT, false);
if (_noMapCount)
Common::fill(unmappedColors + _noMapStart, unmappedColors + _noMapStart + _noMapCount, true);
for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++) {
if (cycleMap[i])
unmappedColors[i] = true;
}
for (int i = 1; i < NON_REMAPPED_COLOR_COUNT; i++) {
Color targetColor = curRemap->targetColor[i];
bool colorChanged = curRemap->colorChanged[curRemap->remap[i]];
if (!_targetChanged[i] && !colorChanged)
continue;
if (_targetChanged[i] && colorChanged)
if (curRemap->distance[i] < 100 && colorDistance(targetColor, curRemap->curColor[curRemap->remap[i]]) <= curRemap->distance[i])
continue;
int diff = 0;
int16 result = _palette->matchColor(targetColor.r, targetColor.g, targetColor.b, curRemap->distance[i], diff, unmappedColors);
if (result != -1 && curRemap->remap[i] != result) {
changed = true;
curRemap->remap[i] = result;
curRemap->distance[i] = diff;
}
}
return changed;
}
bool GfxRemap32::remapAllTables(bool palChanged) {
bool changed = false;
for (int i = 0; i < REMAP_COLOR_COUNT; i++) {
changed |= updateRemap(i, palChanged);
}
_update = false;
return changed;
}
#endif
} // End of namespace Sci

View File

@ -24,36 +24,42 @@
#define SCI_GRAPHICS_REMAP_H
#include "common/array.h"
#include "common/serializer.h"
#include "sci/graphics/helpers.h"
namespace Sci {
class GfxScreen;
enum ColorRemappingType {
kRemappingNone = 0,
kRemappingByRange = 1,
kRemappingByPercent = 2,
kRemappingToGray = 3,
kRemappingToPercentGray = 4
};
#define REMAP_COLOR_COUNT 9
#define NON_REMAPPED_COLOR_COUNT 236
/**
* This class handles color remapping for the QFG4 demo.
* Remap class, handles color remapping
*/
class GfxRemap {
private:
enum ColorRemappingType {
kRemapNone = 0,
kRemapByRange = 1,
kRemapByPercent = 2
};
public:
GfxRemap(GfxPalette *_palette);
~GfxRemap();
void resetRemapping();
void setRemappingPercent(byte color, byte percent);
void setRemappingRange(byte color, byte from, byte to, byte base);
bool isRemapped(byte color) const {
return _remapOn && (_remappingType[color] != kRemapNone);
return _remapOn && (_remappingType[color] != kRemappingNone);
}
byte remapColor(byte remappedColor, byte screenColor);
void updateRemapping();
private:
GfxScreen *_screen;
GfxPalette *_palette;
bool _remapOn;
@ -62,6 +68,87 @@ private:
byte _remappingByRange[256];
uint16 _remappingPercentToSet;
};
#ifdef ENABLE_SCI32
struct RemapParams {
byte from;
byte to;
byte base;
byte gray;
byte oldGray;
byte percent;
byte oldPercent;
ColorRemappingType type;
Color curColor[256];
Color targetColor[256];
byte distance[256];
byte remap[256];
bool colorChanged[256];
RemapParams() {
from = to = base = gray = oldGray = percent = oldPercent = 0;
type = kRemappingNone;
// curColor and targetColor are initialized in GfxRemap32::initColorArrays
memset(curColor, 0, 256 * sizeof(Color));
memset(targetColor, 0, 256 * sizeof(Color));
memset(distance, 0, 256);
for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++)
remap[i] = i;
Common::fill(colorChanged, colorChanged + ARRAYSIZE(colorChanged), true);
}
RemapParams(byte from_, byte to_, byte base_, byte gray_, byte percent_, ColorRemappingType type_) {
from = from_;
to = to_;
base = base_;
gray = oldGray = gray_;
percent = oldPercent = percent_;
type = type_;
// curColor and targetColor are initialized in GfxRemap32::initColorArrays
memset(curColor, 0, 256 * sizeof(Color));
memset(targetColor, 0, 256 * sizeof(Color));
memset(distance, 0, 256);
for (int i = 0; i < NON_REMAPPED_COLOR_COUNT; i++)
remap[i] = i;
Common::fill(colorChanged, colorChanged + ARRAYSIZE(colorChanged), true);
}
};
class GfxRemap32 {
public:
GfxRemap32(GfxPalette32 *palette);
~GfxRemap32() {}
void remapOff(byte color);
void setRemappingRange(byte color, byte from, byte to, byte base);
void setRemappingPercent(byte color, byte percent);
void setRemappingToGray(byte color, byte gray);
void setRemappingToPercentGray(byte color, byte gray, byte percent);
void setNoMatchRange(byte from, byte count);
bool remapEnabled(byte color) const;
byte remapColor(byte color, byte target);
bool remapAllTables(bool palChanged);
int getRemapCount() const { return _remapCount; }
int getStartColor() const { return _remapEndColor - REMAP_COLOR_COUNT + 1; }
int getEndColor() const { return _remapEndColor; }
private:
GfxPalette32 *_palette;
RemapParams _remaps[REMAP_COLOR_COUNT];
bool _update;
byte _noMapStart, _noMapCount;
bool _targetChanged[NON_REMAPPED_COLOR_COUNT];
byte _remapEndColor;
int _remapCount;
void initColorArrays(byte index);
bool applyRemap(byte index);
bool updateRemap(byte index, bool palChanged);
};
#endif
} // End of namespace Sci
#endif

View File

@ -1,468 +0,0 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sci/sci.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
namespace Sci {
#pragma mark SingleRemap
void SingleRemap::reset() {
_lastPercent = 100;
_lastGray = 0;
const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
for (uint i = 0; i < remapStartColor; ++i) {
const Color &color = currentPalette.colors[i];
_remapColors[i] = i;
_originalColors[i] = color;
_originalColorsChanged[i] = true;
_idealColors[i] = color;
_idealColorsChanged[i] = false;
_matchDistances[i] = 0;
}
}
bool SingleRemap::update() {
switch (_type) {
case kRemapNone:
break;
case kRemapByRange:
return updateRange();
case kRemapByPercent:
return updateBrightness();
case kRemapToGray:
return updateSaturation();
case kRemapToPercentGray:
return updateSaturationAndBrightness();
default:
error("Illegal remap type %d", _type);
}
return false;
}
bool SingleRemap::updateRange() {
const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
bool updated = false;
for (uint i = 0; i < remapStartColor; ++i) {
uint8 targetColor;
if (_from <= i && i <= _to) {
targetColor = i + _delta;
} else {
targetColor = i;
}
if (_remapColors[i] != targetColor) {
updated = true;
_remapColors[i] = targetColor;
}
_originalColorsChanged[i] = true;
}
return updated;
}
bool SingleRemap::updateBrightness() {
const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
const Palette &nextPalette = g_sci->_gfxPalette32->getNextPalette();
for (uint i = 1; i < remapStartColor; ++i) {
Color color(nextPalette.colors[i]);
if (_originalColors[i] != color) {
_originalColorsChanged[i] = true;
_originalColors[i] = color;
}
if (_percent != _lastPercent || _originalColorsChanged[i]) {
// NOTE: SSCI checked if percent was over 100 and only
// then clipped values, but we always unconditionally
// ensure the result is in the correct range
color.r = MIN(255, (uint16)color.r * _percent / 100);
color.g = MIN(255, (uint16)color.g * _percent / 100);
color.b = MIN(255, (uint16)color.b * _percent / 100);
if (_idealColors[i] != color) {
_idealColorsChanged[i] = true;
_idealColors[i] = color;
}
}
}
const bool updated = apply();
Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
_lastPercent = _percent;
return updated;
}
bool SingleRemap::updateSaturation() {
const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
for (uint i = 1; i < remapStartColor; ++i) {
Color color(currentPalette.colors[i]);
if (_originalColors[i] != color) {
_originalColorsChanged[i] = true;
_originalColors[i] = color;
}
if (_gray != _lastGray || _originalColorsChanged[i]) {
const int luminosity = (((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8) * _percent / 100;
color.r = MIN(255, color.r - ((color.r - luminosity) * _gray / 100));
color.g = MIN(255, color.g - ((color.g - luminosity) * _gray / 100));
color.b = MIN(255, color.b - ((color.b - luminosity) * _gray / 100));
if (_idealColors[i] != color) {
_idealColorsChanged[i] = true;
_idealColors[i] = color;
}
}
}
const bool updated = apply();
Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
_lastGray = _gray;
return updated;
}
bool SingleRemap::updateSaturationAndBrightness() {
const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
for (uint i = 1; i < remapStartColor; i++) {
Color color(currentPalette.colors[i]);
if (_originalColors[i] != color) {
_originalColorsChanged[i] = true;
_originalColors[i] = color;
}
if (_percent != _lastPercent || _gray != _lastGray || _originalColorsChanged[i]) {
const int luminosity = (((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8) * _percent / 100;
color.r = MIN(255, color.r - ((color.r - luminosity) * _gray) / 100);
color.g = MIN(255, color.g - ((color.g - luminosity) * _gray) / 100);
color.b = MIN(255, color.b - ((color.b - luminosity) * _gray) / 100);
if (_idealColors[i] != color) {
_idealColorsChanged[i] = true;
_idealColors[i] = color;
}
}
}
const bool updated = apply();
Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
_lastPercent = _percent;
_lastGray = _gray;
return updated;
}
bool SingleRemap::apply() {
const GfxRemap32 *const gfxRemap32 = g_sci->_gfxRemap32;
const uint8 remapStartColor = gfxRemap32->getStartColor();
// Blocked colors are not allowed to be used as target
// colors for the remap
bool blockedColors[236];
Common::fill(blockedColors, blockedColors + remapStartColor, false);
const bool *const paletteCycleMap = g_sci->_gfxPalette32->getCycleMap();
const int16 blockedRangeCount = gfxRemap32->getBlockedRangeCount();
if (blockedRangeCount) {
const uint8 blockedRangeStart = gfxRemap32->getBlockedRangeStart();
Common::fill(blockedColors + blockedRangeStart, blockedColors + blockedRangeStart + blockedRangeCount, true);
}
for (uint i = 0; i < remapStartColor; ++i) {
if (paletteCycleMap[i]) {
blockedColors[i] = true;
}
}
// NOTE: SSCI did a loop over colors here to create a
// new array of updated, unblocked colors, but then
// never used it
bool updated = false;
for (uint i = 1; i < remapStartColor; ++i) {
int distance;
if (!_idealColorsChanged[i] && !_originalColorsChanged[_remapColors[i]]) {
continue;
}
if (
_idealColorsChanged[i] &&
_originalColorsChanged[_remapColors[i]] &&
_matchDistances[i] < 100 &&
colorDistance(_idealColors[i], _originalColors[_remapColors[i]]) <= _matchDistances[i]
) {
continue;
}
const int16 bestColor = matchColor(_idealColors[i], _matchDistances[i], distance, blockedColors);
if (bestColor != -1 && _remapColors[i] != bestColor) {
updated = true;
_remapColors[i] = bestColor;
_matchDistances[i] = distance;
}
}
return updated;
}
int SingleRemap::colorDistance(const Color &a, const Color &b) const {
int channelDistance = a.r - b.r;
int distance = channelDistance * channelDistance;
channelDistance = a.g - b.g;
distance += channelDistance * channelDistance;
channelDistance = a.b - b.b;
distance += channelDistance * channelDistance;
return distance;
}
int16 SingleRemap::matchColor(const Color &color, const int minimumDistance, int &outDistance, const bool *const blockedIndexes) const {
int16 bestIndex = -1;
int bestDistance = 0xFFFFF;
int distance = minimumDistance;
const Palette &nextPalette = g_sci->_gfxPalette32->getNextPalette();
for (uint i = 0, channelDistance; i < g_sci->_gfxRemap32->getStartColor(); ++i) {
if (blockedIndexes[i]) {
continue;
}
distance = nextPalette.colors[i].r - color.r;
distance *= distance;
if (bestDistance <= distance) {
continue;
}
channelDistance = nextPalette.colors[i].g - color.g;
distance += channelDistance * channelDistance;
if (bestDistance <= distance) {
continue;
}
channelDistance = nextPalette.colors[i].b - color.b;
distance += channelDistance * channelDistance;
if (bestDistance <= distance) {
continue;
}
bestDistance = distance;
bestIndex = i;
}
// This value is only valid if the last index to
// perform a distance calculation was the best index
outDistance = distance;
return bestIndex;
}
#pragma mark -
#pragma mark GfxRemap32
GfxRemap32::GfxRemap32() :
_needsUpdate(false),
_blockedRangeStart(0),
_blockedRangeCount(0),
_remapStartColor(236),
_numActiveRemaps(0) {
// The `_remapStartColor` seems to always be 236 in SSCI,
// but if it is ever changed then the various C-style
// member arrays hard-coded to 236 need to be changed to
// match the highest possible value of `_remapStartColor`
assert(_remapStartColor == 236);
if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE || g_sci->getGameId() == GID_KQ7) {
_remaps.resize(9);
} else {
_remaps.resize(19);
}
_remapEndColor = _remapStartColor + _remaps.size() - 1;
}
void GfxRemap32::remapOff(const uint8 color) {
if (color == 0) {
remapAllOff();
return;
}
// NOTE: SSCI simply ignored invalid input values, but
// we at least give a warning so games can be investigated
// for script bugs
if (color < _remapStartColor || color > _remapEndColor) {
warning("GfxRemap32::remapOff: %d out of remap range", color);
return;
}
const uint8 index = _remapEndColor - color;
SingleRemap &singleRemap = _remaps[index];
singleRemap._type = kRemapNone;
--_numActiveRemaps;
_needsUpdate = true;
}
void GfxRemap32::remapAllOff() {
for (uint i = 0, len = _remaps.size(); i < len; ++i) {
_remaps[i]._type = kRemapNone;
}
_numActiveRemaps = 0;
_needsUpdate = true;
}
void GfxRemap32::remapByRange(const uint8 color, const int16 from, const int16 to, const int16 delta) {
// NOTE: SSCI simply ignored invalid input values, but
// we at least give a warning so games can be investigated
// for script bugs
if (color < _remapStartColor || color > _remapEndColor) {
warning("GfxRemap32::remapByRange: %d out of remap range", color);
return;
}
if (from < 0) {
warning("GfxRemap32::remapByRange: attempt to remap negative color %d", from);
return;
}
if (to >= _remapStartColor) {
warning("GfxRemap32::remapByRange: attempt to remap into the remap zone at %d", to);
return;
}
const uint8 index = _remapEndColor - color;
SingleRemap &singleRemap = _remaps[index];
if (singleRemap._type == kRemapNone) {
++_numActiveRemaps;
singleRemap.reset();
}
singleRemap._from = from;
singleRemap._to = to;
singleRemap._delta = delta;
singleRemap._type = kRemapByRange;
_needsUpdate = true;
}
void GfxRemap32::remapByPercent(const uint8 color, const int16 percent) {
// NOTE: SSCI simply ignored invalid input values, but
// we at least give a warning so games can be investigated
// for script bugs
if (color < _remapStartColor || color > _remapEndColor) {
warning("GfxRemap32::remapByPercent: %d out of remap range", color);
return;
}
const uint8 index = _remapEndColor - color;
SingleRemap &singleRemap = _remaps[index];
if (singleRemap._type == kRemapNone) {
++_numActiveRemaps;
singleRemap.reset();
}
singleRemap._percent = percent;
singleRemap._type = kRemapByPercent;
_needsUpdate = true;
}
void GfxRemap32::remapToGray(const uint8 color, const int8 gray) {
// NOTE: SSCI simply ignored invalid input values, but
// we at least give a warning so games can be investigated
// for script bugs
if (color < _remapStartColor || color > _remapEndColor) {
warning("GfxRemap32::remapToGray: %d out of remap range", color);
return;
}
if (gray < 0 || gray > 100) {
error("RemapToGray percent out of range; gray = %d", gray);
}
const uint8 index = _remapEndColor - color;
SingleRemap &singleRemap = _remaps[index];
if (singleRemap._type == kRemapNone) {
++_numActiveRemaps;
singleRemap.reset();
}
singleRemap._gray = gray;
singleRemap._type = kRemapToGray;
_needsUpdate = true;
}
void GfxRemap32::remapToPercentGray(const uint8 color, const int16 gray, const int16 percent) {
// NOTE: SSCI simply ignored invalid input values, but
// we at least give a warning so games can be investigated
// for script bugs
if (color < _remapStartColor || color > _remapEndColor) {
warning("GfxRemap32::remapToPercentGray: %d out of remap range", color);
return;
}
const uint8 index = _remapEndColor - color;
SingleRemap &singleRemap = _remaps[index];
if (singleRemap._type == kRemapNone) {
++_numActiveRemaps;
singleRemap.reset();
}
singleRemap._percent = percent;
singleRemap._gray = gray;
singleRemap._type = kRemapToPercentGray;
_needsUpdate = true;
}
void GfxRemap32::blockRange(const uint8 from, const int16 count) {
_blockedRangeStart = from;
_blockedRangeCount = count;
}
bool GfxRemap32::remapAllTables(const bool paletteUpdated) {
if (!_needsUpdate && !paletteUpdated) {
return false;
}
bool updated = false;
for (SingleRemapsList::iterator it = _remaps.begin(); it != _remaps.end(); ++it) {
if (it->_type != kRemapNone) {
updated |= it->update();
}
}
_needsUpdate = false;
return updated;
}
} // End of namespace Sci

View File

@ -1,400 +0,0 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SCI_GRAPHICS_REMAP32_H
#define SCI_GRAPHICS_REMAP32_H
#include "common/algorithm.h"
#include "common/array.h"
#include "common/scummsys.h"
#include "sci/graphics/helpers.h"
namespace Sci {
class GfxPalette32;
enum RemapType {
kRemapNone = 0,
kRemapByRange = 1,
kRemapByPercent = 2,
kRemapToGray = 3,
kRemapToPercentGray = 4
};
#pragma mark -
#pragma mark SingleRemap
/**
* SingleRemap objects each manage one remapping operation.
*/
class SingleRemap {
public:
SingleRemap() : _type(kRemapNone) {}
/**
* The type of remap.
*/
RemapType _type;
/**
* The first color that should be shifted by a range
* remap.
*/
uint8 _from;
/**
* The last color that should be shifted a range remap.
*/
uint8 _to;
/**
* The direction and amount that the colors should be
* shifted in a range remap.
*/
int16 _delta;
/**
* The difference in brightness that should be
* applied by a brightness (percent) remap.
*
* This value may be be greater than 100, in
* which case the color will be oversaturated.
*/
int16 _percent;
/**
* The amount of desaturation that should be
* applied by a saturation (gray) remap, where
* 0 is full saturation and 100 is full
* desaturation.
*/
uint8 _gray;
/**
* The final array used by CelObj renderers to composite
* remapped pixels to the screen buffer.
*
* Here is how it works:
*
* The source bitmap being rendered will have pixels
* within the remap range (236-245 or 236-254), and the
* target buffer will have colors in the non-remapped
* range (0-235).
*
* To arrive at the correct color, first the source
* pixel is used to look up the correct SingleRemap for
* that pixel. Then, the final composited color is
* looked up in this array using the target's pixel
* color. In other words,
* `target = _remaps[remapEndColor - source].remapColors[target]`.
*/
uint8 _remapColors[236];
/**
* Resets this SingleRemap's color information to
* default values.
*/
void reset();
/**
* Recalculates and reapplies remap colors to the
* `_remapColors` array.
*/
bool update();
private:
/**
* The previous brightness value. Used to
* determine whether or not targetColors needs
* to be updated.
*/
int16 _lastPercent;
/**
* The previous saturation value. Used to
* determine whether or not targetColors needs
* to be updated.
*/
uint8 _lastGray;
/**
* The colors from the current GfxPalette32 palette
* before this SingleRemap is applied.
*/
Color _originalColors[236];
/**
* Map of colors that changed in `_originalColors`
* when this SingleRemap was updated. This map is
* transient and gets reset to `false` after the
* SingleRemap finishes updating.
*/
bool _originalColorsChanged[236];
/**
* The ideal target RGB color values for each generated
* remap color.
*/
Color _idealColors[236];
/**
* Map of colors that changed in `_idealColors` when
* this SingleRemap was updated. This map is transient
* and gets reset to `false` after the SingleRemap
* finishes applying.
*/
bool _idealColorsChanged[236];
/**
* When applying a SingleRemap, finding an appropriate
* color in the palette is the responsibility of a
* distance function. Once a match is found, the
* distance of that match is stored here so that the
* next time the SingleRemap is applied, it can check
* the distance from the previous application and avoid
* triggering an expensive redraw of the entire screen
* if the new palette value only changed slightly.
*/
int _matchDistances[236];
/**
* Computes the final target values for a range remap
* and applies them directly to the `_remaps` map.
*
* @note Was ByRange in SSCI.
*/
bool updateRange();
/**
* Computes the intermediate target values for a
* brightness remap and applies them indirectly via
* the `apply` method.
*
* @note Was ByPercent in SSCI.
*/
bool updateBrightness();
/**
* Computes the intermediate target values for a
* saturation remap and applies them indirectly via
* the `apply` method.
*
* @note Was ToGray in SSCI.
*/
bool updateSaturation();
/**
* Computes the intermediate target values for a
* saturation + brightness bitmap and applies them
* indirectly via the `apply` method.
*
* @note Was ToPercentGray in SSCI.
*/
bool updateSaturationAndBrightness();
/**
* Computes and applies the final values to the
* `_remaps` map.
*
* @note In SSCI, a boolean array of changed values
* was passed into this method, but this was done by
* creating arrays on the stack in the caller. Instead
* of doing this, we simply add another member property
* `_idealColorsChanged` and use that instead.
*/
bool apply();
/**
* Calculates the square distance of two colors.
*
* @note In SSCI this method is Rgb24::Dist, but it is
* only used by SingleRemap.
*/
int colorDistance(const Color &a, const Color &b) const;
/**
* Finds the closest index in the next palette matching
* the given RGB color. Returns -1 if no match can be
* found that is closer than `minimumDistance`.
*
* @note In SSCI, this method is SOLPalette::Match, but
* this particular signature is only used by
* SingleRemap.
*/
int16 matchColor(const Color &color, const int minimumDistance, int &outDistance, const bool *const blockedIndexes) const;
};
#pragma mark -
#pragma mark GfxRemap32
/**
* This class provides color remapping support for SCI32
* games.
*/
class GfxRemap32 : public Common::Serializable {
public:
GfxRemap32();
void saveLoadWithSerializer(Common::Serializer &s);
inline uint8 getRemapCount() const { return _numActiveRemaps; }
inline uint8 getStartColor() const { return _remapStartColor; }
inline uint8 getEndColor() const { return _remapEndColor; }
inline uint8 getBlockedRangeStart() const { return _blockedRangeStart; }
inline int16 getBlockedRangeCount() const { return _blockedRangeCount; }
/**
* Turns off remapping of the given color. If `color` is
* 0, all remaps are turned off.
*/
void remapOff(const uint8 color);
/**
* Turns off all color remaps.
*/
void remapAllOff();
/**
* Configures a SingleRemap for the remap color `color`.
* The SingleRemap will shift palette colors between
* `from` and `to` (inclusive) by `delta` palette
* entries when the remap is applied.
*/
void remapByRange(const uint8 color, const int16 from, const int16 to, const int16 delta);
/**
* Configures a SingleRemap for the remap color `color`
* to modify the brightness of remapped colors by
* `percent`.
*/
void remapByPercent(const uint8 color, const int16 percent);
/**
* Configures a SingleRemap for the remap color `color`
* to modify the saturation of remapped colors by
* `gray`.
*/
void remapToGray(const uint8 color, const int8 gray);
/**
* Configures a SingleRemap for the remap color `color`
* to modify the brightness of remapped colors by
* `percent`, and saturation of remapped colors by
* `gray`.
*/
void remapToPercentGray(const uint8 color, const int16 gray, const int16 percent);
/**
* Prevents GfxRemap32 from using the given range of
* palette entries as potential remap targets.
*
* @NOTE Was DontMapToRange in SSCI.
*/
void blockRange(const uint8 from, const int16 count);
/**
* Determines whether or not the given color has an
* active remapper. If it does not, it is treated as a
* skip color and the pixel is not drawn.
*
* @note SSCI uses a boolean array to decide whether a
* a pixel is remapped, but it is possible to get the
* same information from `_remaps`, as this function
* does.
* Presumably, the separate array was created for
* performance reasons, since this is called a lot in
* the most critical section of the renderer.
*/
inline bool remapEnabled(uint8 color) const {
const uint8 index = _remapEndColor - color;
assert(index < _remaps.size());
return (_remaps[index]._type != kRemapNone);
}
/**
* Calculates the correct color for a target by looking
* up the target color in the SingleRemap that controls
* the given sourceColor. If there is no remap for the
* given color, it will be treated as a skip color.
*/
inline uint8 remapColor(const uint8 sourceColor, const uint8 targetColor) const {
const uint8 index = _remapEndColor - sourceColor;
assert(index < _remaps.size());
const SingleRemap &singleRemap = _remaps[index];
assert(singleRemap._type != kRemapNone);
return singleRemap._remapColors[targetColor];
}
/**
* Updates all active remaps in response to a palette
* change or a remap settings change.
*
* `paletteChanged` is true if the next palette in
* GfxPalette32 has been previously modified by other
* palette operations.
*/
bool remapAllTables(const bool paletteUpdated);
private:
typedef Common::Array<SingleRemap> SingleRemapsList;
/**
* The first index of the remap area in the system
* palette.
*/
const uint8 _remapStartColor;
/**
* The last index of the remap area in the system
* palette.
*/
uint8 _remapEndColor;
/**
* The number of currently active remaps.
*/
uint8 _numActiveRemaps;
/**
* The list of SingleRemaps.
*/
SingleRemapsList _remaps;
/**
* If true, indicates that one or more SingleRemaps were
* reconfigured and all remaps need to be recalculated.
*/
bool _needsUpdate;
/**
* The first color that is blocked from being used as a
* remap target color.
*/
uint8 _blockedRangeStart;
/**
* The size of the range of blocked colors. If zero,
* all colors are potential targets for remapping.
*/
int16 _blockedRangeCount;
};
} // End of namespace Sci
#endif

View File

@ -55,7 +55,6 @@ struct LoopInfo {
class GfxScreen;
class GfxPalette;
class Resource;
/**
* View class, handles loading of view resources and drawing contained cels to screen

View File

@ -88,7 +88,6 @@ MODULE_OBJS += \
graphics/paint32.o \
graphics/plane32.o \
graphics/palette32.o \
graphics/remap32.o \
graphics/screen_item32.o \
graphics/text32.o \
sound/audio32.o \

View File

@ -65,10 +65,9 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/controls32.h"
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
#include "sci/graphics/frameout.h"
#include "sci/sound/audio32.h"
#include "sci/video/robot_decoder.h"
#endif
@ -700,7 +699,7 @@ void SciEngine::initGraphics() {
if (getSciVersion() >= SCI_VERSION_2) {
_gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
_gfxPalette16 = _gfxPalette32;
_gfxRemap32 = new GfxRemap32();
_gfxRemap32 = new GfxRemap32(_gfxPalette32);
} else {
#endif
_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen);