SCI32: Initial implementation of kRemapColors

applyRemap() is still not finished, so nothing is actually visible yet
This commit is contained in:
Filippos Karapetis 2016-03-11 05:10:32 +02:00
parent 22097018bb
commit 3a770fa0d8
8 changed files with 326 additions and 100 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);
@ -452,7 +452,14 @@ reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv);
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 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

@ -351,6 +351,17 @@ static const SciKernelMapSubEntry kList_subops[] = {
SCI_SUBOPENTRY_TERMINATOR
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kRemapColors_subops[] = {
{ 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
};
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kString_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL },
@ -550,9 +561,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)", NULL, 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

@ -45,6 +45,7 @@
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
@ -907,79 +908,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) {
// TODO
#if 0
uint16 operation = argv[0].toUint16();
reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
if (!s)
return make_reg(0, getSciVersion());
error("not supposed to call this");
}
switch (operation) {
case 0: { // turn remapping off
// WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room
// 140 (the character point allocation screen) and never turn it back on,
// even if it's clearly used in that screen.
if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140)
return s->r_acc;
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;
}
int16 color = (argc >= 2) ? argv[1].toSint16() : 0;
if (color > 0)
warning("kRemapColors(0) called with base %d", color);
//g_sci->_gfxPalette32->resetRemapping();
}
break;
case 1: { // remap by range
uint16 color = argv[1].toUint16();
uint16 from = argv[2].toUint16();
uint16 to = argv[3].toUint16();
uint16 delta = argv[4].toUint16();
uint16 depth = (argc >= 6) ? argv[5].toUint16() : 0;
if (depth > 0)
warning("kRemapColors(1) called with 6 parameters, depth is %d", depth);
//g_sci->_gfxPalette32->setRemappingRange(color, from, to, delta);
}
break;
case 2: { // remap by percent
uint16 color = argv[1].toUint16();
uint16 percent = argv[2].toUint16(); // 0 - 100
uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
if (depth >= 0)
warning("RemapByPercent called with 4 parameters, depth is %d", depth);
//g_sci->_gfxPalette32->setRemappingPercent(color, percent);
}
break;
case 3: { // remap to gray
// Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0.
// In this room, it's used for the cloud before Baba Yaga appears.
uint16 color = argv[1].toUint16();
uint16 percent = argv[2].toUint16(); // 0 - 100
uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
if (depth >= 0)
warning("RemapToGray called with 4 parameters, depth is %d", depth);
//g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
}
break;
case 4: { // remap to percent gray
// Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200
uint16 color = argv[1].toUint16();
uint16 percent = argv[2].toUint16(); // 0 - 100
uint16 grayPercent = argv[3].toUint16();
uint16 depth = (argc >= 5) ? argv[4].toUint16() : 0;
if (argc >= 5)
warning("RemapToGrayPercent called with 5 parameters, depth is %d", depth);
//g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
}
break;
case 5: { // don't map to range
//uint16 start = argv[1].toSint16();
//uint16 count = argv[2].toUint16();
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;
}
kStub(s, argc, argv);
}
break;
default:
break;
}
#endif
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 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 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 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

@ -28,6 +28,7 @@
#include "sci/event.h"
#include "sci/resource.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
namespace Sci {
@ -223,9 +224,7 @@ int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const i
bool GfxPalette32::updateForFrame() {
applyAll();
_versionUpdated = false;
// TODO: Implement remapping
// return g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
return false;
return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
}
void GfxPalette32::updateFFrame() {
@ -233,8 +232,7 @@ void GfxPalette32::updateFFrame() {
_nextPalette.colors[i] = _sourcePalette.colors[i];
}
_versionUpdated = false;
// TODO: Implement remapping
// g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
}
void GfxPalette32::updateHardware() {

View File

@ -23,6 +23,7 @@
#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"
@ -107,28 +108,198 @@ void GfxRemap::updateRemapping() {
#pragma mark -
#pragma mark SCI32 remapping
#if 0
// TODO
void GfxRemap32::setRemappingPercentGray(byte color, byte percent) {
_remapOn = true;
#ifdef ENABLE_SCI32
// We need to defer the setup of the remapping table every time the screen
// palette is changed, so that kernelFindColor() can find the correct
// colors. Set it once here, in case the palette stays the same and update
// it on each palette change by copySysPaletteToScreen().
_remappingPercentToSet = percent;
GfxRemap32::GfxRemap32(GfxPalette *palette) {
for (int i = 0; i < REMAP_COLOR_COUNT; i++)
_remaps[i] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
_noMapStart = _noMapCount = 0;
_update = false;
}
// Note: This is not what the original does, but the results are the same visually
for (int i = 0; i < 256; i++) {
byte rComponent = (byte)(_sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100);
byte gComponent = (byte)(_sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100);
byte bComponent = (byte)(_sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100);
byte luminosity = rComponent + gComponent + bComponent;
_remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity);
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);
} else {
const byte index = REMAP_END_COLOR - color;
_remaps[index] = RemapParams(0, 0, 0, 0, 100, kRemappingNone);
}
_remappingType[color] = kRemappingByPercent;
_update = true;
}
void GfxRemap32::setRemappingRange(byte color, byte from, byte to, byte base) {
_remaps[REMAP_END_COLOR - color] = RemapParams(from, to, base, 0, 100, kRemappingByRange);
initColorArrays(REMAP_END_COLOR - color);
_update = true;
}
void GfxRemap32::setRemappingPercent(byte color, byte percent) {
_remaps[REMAP_END_COLOR - color] = RemapParams(0, 0, 0, 0, percent, kRemappingByPercent);
initColorArrays(REMAP_END_COLOR - color);
_update = true;
}
void GfxRemap32::setRemappingToGray(byte color, byte gray) {
_remaps[REMAP_END_COLOR - color] = RemapParams(0, 0, 0, gray, 100, kRemappingToGray);
initColorArrays(REMAP_END_COLOR - color);
_update = true;
}
void GfxRemap32::setRemappingToPercentGray(byte color, byte gray, byte percent) {
_remaps[REMAP_END_COLOR - color] = RemapParams(0, 0, 0, gray, percent, kRemappingToPercentGray);
initColorArrays(REMAP_END_COLOR - color);
_update = true;
}
void GfxRemap32::setNoMatchRange(byte from, byte count) {
_noMapStart = from;
_noMapCount = count;
}
void GfxRemap32::initColorArrays(byte index) {
assert(index < REMAP_COLOR_COUNT);
Palette *curPalette = &g_sci->_gfxPalette32->_sysPalette;
RemapParams *curRemap = &_remaps[index];
memcpy(curRemap->curColor, curPalette->colors, 236 * sizeof(Color));
memcpy(curRemap->targetColor, curPalette->colors, 236 * sizeof(Color));
}
bool GfxRemap32::updateRemap(byte index) {
int result;
RemapParams *curRemap = &_remaps[index];
Palette *curPalette = &g_sci->_gfxPalette32->_sysPalette;
bool changed = false;
memset(_targetChanged, false, 236);
switch (curRemap->type) {
case kRemappingNone:
return false;
case kRemappingByRange:
for (int i = 0; i < 236; 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 < 236; 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->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);
memset(curRemap->colorChanged, false, 236);
curRemap->oldPercent = curRemap->percent;
return changed;
case kRemappingToGray:
for (int i = 1; i < 236; 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);
memset(curRemap->colorChanged, false, 236);
curRemap->oldGray = curRemap->gray;
return changed;
case kRemappingToPercentGray:
for (int i = 1; i < 236; 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);
memset(curRemap->colorChanged, false, 236);
curRemap->oldPercent = curRemap->percent;
curRemap->oldGray = curRemap->gray;
return changed;
default:
return false;
}
}
bool GfxRemap32::applyRemap(byte index) {
// TODO
//warning("applyRemap");
return false;
}
bool GfxRemap32::remapAllTables(bool palChanged) {
bool changed = false;
for (int i = 0; i < REMAP_COLOR_COUNT; i++) {
changed |= updateRemap(i);
}
_update = false;
return changed;
}
#endif
} // End of namespace Sci

View File

@ -33,9 +33,14 @@ class GfxScreen;
enum ColorRemappingType {
kRemappingNone = 0,
kRemappingByRange = 1,
kRemappingByPercent = 2
kRemappingByPercent = 2,
kRemappingToGray = 3,
kRemappingToPercentGray = 4
};
#define REMAP_COLOR_COUNT 9
#define REMAP_END_COLOR 254
/**
* Remap class, handles color remapping
*/
@ -43,6 +48,7 @@ class GfxRemap {
public:
GfxRemap(GfxScreen *screen, GfxPalette *_palette);
~GfxRemap();
void resetRemapping();
void setRemappingPercent(byte color, byte percent);
void setRemappingRange(byte color, byte from, byte to, byte base);
@ -64,11 +70,65 @@ private:
};
#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() : RemapParams(0, 0, 0, 0, 100, kRemappingNone) {
}
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 < 236; i++)
remap[i] = i;
memset(colorChanged, true, 256);
}
};
class GfxRemap32 {
public:
GfxRemap32(GfxScreen *screen, GfxPalette *_palette) {}
GfxRemap32(GfxPalette *_palette);
~GfxRemap32() {}
//void setRemappingPercentGray(byte color, byte percent);
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 remapAllTables(bool palChanged);
private:
RemapParams _remaps[REMAP_COLOR_COUNT];
bool _update;
byte _noMapStart, _noMapCount;
bool _targetChanged[236];
void initColorArrays(byte index);
bool applyRemap(byte index);
bool updateRemap(byte index);
};
#endif

View File

@ -684,7 +684,7 @@ void SciEngine::initGraphics() {
if (getSciVersion() >= SCI_VERSION_2) {
_gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
_gfxPalette16 = _gfxPalette32;
_gfxRemap32 = new GfxRemap32(_gfxScreen, _gfxPalette32);
_gfxRemap32 = new GfxRemap32(_gfxPalette32);
} else {
#endif
_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen);