diff options
| author | Filippos Karapetis | 2016-01-08 10:58:03 +0200 | 
|---|---|---|
| committer | Filippos Karapetis | 2016-01-08 10:58:03 +0200 | 
| commit | 7379e531c75294577b4859fceb73ae01559dae0f (patch) | |
| tree | 0c82a41e6ad085ca210ba29e49ab9ce1c7a84275 | |
| parent | 6e0d6e36a921972305e458fe9194548efc50dead (diff) | |
| parent | 275db1f7f24e373bd41b6b689303fee9f6f771be (diff) | |
| download | scummvm-rg350-7379e531c75294577b4859fceb73ae01559dae0f.tar.gz scummvm-rg350-7379e531c75294577b4859fceb73ae01559dae0f.tar.bz2 scummvm-rg350-7379e531c75294577b4859fceb73ae01559dae0f.zip | |
Merge pull request #644 from csnover/sci32-kPalCycle
SCI32: palette management (full kPalCycle, partial kSetPalStyleRange and kPalFade)
| -rw-r--r-- | engines/sci/console.cpp | 6 | ||||
| -rw-r--r-- | engines/sci/engine/kernel.h | 1 | ||||
| -rw-r--r-- | engines/sci/engine/kernel_tables.h | 2 | ||||
| -rw-r--r-- | engines/sci/engine/kgraphics.cpp | 50 | ||||
| -rw-r--r-- | engines/sci/engine/kgraphics32.cpp | 139 | ||||
| -rw-r--r-- | engines/sci/engine/kpathing.cpp | 12 | ||||
| -rw-r--r-- | engines/sci/engine/kvideo.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/savegame.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/state.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/engine/state.h | 2 | ||||
| -rw-r--r-- | engines/sci/graphics/frameout.cpp | 100 | ||||
| -rw-r--r-- | engines/sci/graphics/frameout.h | 4 | ||||
| -rw-r--r-- | engines/sci/graphics/maciconbar.cpp | 2 | ||||
| -rw-r--r-- | engines/sci/graphics/palette.cpp | 64 | ||||
| -rw-r--r-- | engines/sci/graphics/palette.h | 10 | ||||
| -rw-r--r-- | engines/sci/graphics/palette32.cpp | 350 | ||||
| -rw-r--r-- | engines/sci/graphics/palette32.h | 122 | ||||
| -rw-r--r-- | engines/sci/module.mk | 1 | ||||
| -rw-r--r-- | engines/sci/sci.cpp | 42 | ||||
| -rw-r--r-- | engines/sci/sci.h | 5 | 
20 files changed, 737 insertions, 181 deletions
| diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 5cd7b9f7ca..438c725324 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -487,8 +487,8 @@ bool Console::cmdGetVersion(int argc, const char **argv) {  		debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)");  #endif  	debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]); -	debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette->isMerging() ? "yes" : "no"); -	debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette->isUsing16bitColorMatch() ? "yes" : "no"); +	debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no"); +	debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");  	debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc());  	debugPrintf("Resource map version: %s\n", g_sci->getResMan()->getMapVersionDesc());  	debugPrintf("Contains selector vocabulary (vocab.997): %s\n", hasVocab997 ? "yes" : "no"); @@ -1618,7 +1618,7 @@ bool Console::cmdSetPalette(int argc, const char **argv) {  	uint16 resourceId = atoi(argv[1]); -	_engine->_gfxPalette->kernelSetFromResource(resourceId, true); +	_engine->_gfxPalette16->kernelSetFromResource(resourceId, true);  	return true;  } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index f62a074ef1..a2563b5a32 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -456,6 +456,7 @@ reg_t kAddPlane(EngineState *s, int argc, reg_t *argv);  reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv);  reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv);  reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv); +reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv);  reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv);  reg_t kFrameOut(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 49dfa17554..98ea067600 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -694,6 +694,8 @@ static SciKernelMapEntry s_kernelMap[] = {  	// MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons  	// SetPalStyleRange - 2 integer parameters, start and end. All styles from start-end  	//   (inclusive) are set to 0 +	{ MAP_CALL(SetPalStyleRange),  SIG_EVERYWHERE,            "ii",                   NULL,            NULL }, +  	// MorphOn - used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)  	// SCI3 Kernel Functions diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 8b790e6a58..0b945c1eec 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -254,7 +254,7 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) {  }  reg_t kGraphGetColorCount(EngineState *s, int argc, reg_t *argv) { -	return make_reg(0, g_sci->_gfxPalette->getTotalColorCount()); +	return make_reg(0, g_sci->_gfxPalette16->getTotalColorCount());  }  reg_t kGraphDrawLine(EngineState *s, int argc, reg_t *argv) { @@ -596,10 +596,10 @@ reg_t kPaletteSetFromResource(EngineState *s, int argc, reg_t *argv) {  	// Non-VGA games don't use palette resources.  	// This has been changed to 64 colors because Longbow Amiga does have  	// one palette (palette 999). -	if (g_sci->_gfxPalette->getTotalColorCount() < 64) +	if (g_sci->_gfxPalette16->getTotalColorCount() < 64)  		return s->r_acc; -	g_sci->_gfxPalette->kernelSetFromResource(resourceId, force); +	g_sci->_gfxPalette16->kernelSetFromResource(resourceId, force);  	return s->r_acc;  } @@ -607,7 +607,7 @@ reg_t kPaletteSetFlag(EngineState *s, int argc, reg_t *argv) {  	uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);  	uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);  	uint16 flags = argv[2].toUint16(); -	g_sci->_gfxPalette->kernelSetFlag(fromColor, toColor, flags); +	g_sci->_gfxPalette16->kernelSetFlag(fromColor, toColor, flags);  	return s->r_acc;  } @@ -615,7 +615,7 @@ reg_t kPaletteUnsetFlag(EngineState *s, int argc, reg_t *argv) {  	uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);  	uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);  	uint16 flags = argv[2].toUint16(); -	g_sci->_gfxPalette->kernelUnsetFlag(fromColor, toColor, flags); +	g_sci->_gfxPalette16->kernelUnsetFlag(fromColor, toColor, flags);  	return s->r_acc;  } @@ -626,10 +626,10 @@ reg_t kPaletteSetIntensity(EngineState *s, int argc, reg_t *argv) {  	bool setPalette = (argc < 4) ? true : (argv[3].isNull()) ? true : false;  	// Palette intensity in non-VGA SCI1 games has been removed -	if (g_sci->_gfxPalette->getTotalColorCount() < 256) +	if (g_sci->_gfxPalette16->getTotalColorCount() < 256)  		return s->r_acc; -	g_sci->_gfxPalette->kernelSetIntensity(fromColor, toColor, intensity, setPalette); +	g_sci->_gfxPalette16->kernelSetIntensity(fromColor, toColor, intensity, setPalette);  	return s->r_acc;  } @@ -637,7 +637,7 @@ reg_t kPaletteFindColor(EngineState *s, int argc, reg_t *argv) {  	uint16 r = argv[0].toUint16();  	uint16 g = argv[1].toUint16();  	uint16 b = argv[2].toUint16(); -	return make_reg(0, g_sci->_gfxPalette->kernelFindColor(r, g, b)); +	return make_reg(0, g_sci->_gfxPalette16->kernelFindColor(r, g, b));  }  reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) { @@ -645,18 +645,18 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {  	bool paletteChanged = false;  	// Palette animation in non-VGA SCI1 games has been removed -	if (g_sci->_gfxPalette->getTotalColorCount() < 256) +	if (g_sci->_gfxPalette16->getTotalColorCount() < 256)  		return s->r_acc;  	for (argNr = 0; argNr < argc; argNr += 3) {  		uint16 fromColor = argv[argNr].toUint16();  		uint16 toColor = argv[argNr + 1].toUint16();  		int16 speed = argv[argNr + 2].toSint16(); -		if (g_sci->_gfxPalette->kernelAnimate(fromColor, toColor, speed)) +		if (g_sci->_gfxPalette16->kernelAnimate(fromColor, toColor, speed))  			paletteChanged = true;  	}  	if (paletteChanged) -		g_sci->_gfxPalette->kernelAnimateSet(); +		g_sci->_gfxPalette16->kernelAnimateSet();  	// WORKAROUND: The game scripts in SQ4 floppy count the number of elapsed  	// cycles in the intro from the number of successive kAnimate calls during @@ -676,11 +676,11 @@ reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {  }  reg_t kPaletteSave(EngineState *s, int argc, reg_t *argv) { -	return g_sci->_gfxPalette->kernelSave(); +	return g_sci->_gfxPalette16->kernelSave();  }  reg_t kPaletteRestore(EngineState *s, int argc, reg_t *argv) { -	g_sci->_gfxPalette->kernelRestore(argv[0]); +	g_sci->_gfxPalette16->kernelRestore(argv[0]);  	return argv[0];  } @@ -695,7 +695,7 @@ reg_t kPalVaryInit(EngineState *s, int argc, reg_t *argv) {  	uint16 ticks = argv[1].toUint16();  	uint16 stepStop = argc >= 3 ? argv[2].toUint16() : 64;  	uint16 direction = argc >= 4 ? argv[3].toUint16() : 1; -	if (g_sci->_gfxPalette->kernelPalVaryInit(paletteId, ticks, stepStop, direction)) +	if (g_sci->_gfxPalette16->kernelPalVaryInit(paletteId, ticks, stepStop, direction))  		return SIGNAL_REG;  	return NULL_REG;  } @@ -705,40 +705,40 @@ reg_t kPalVaryReverse(EngineState *s, int argc, reg_t *argv) {  	int16 stepStop = argc >= 2 ? argv[1].toUint16() : 0;  	int16 direction = argc >= 3 ? argv[2].toSint16() : -1; -	return make_reg(0, g_sci->_gfxPalette->kernelPalVaryReverse(ticks, stepStop, direction)); +	return make_reg(0, g_sci->_gfxPalette16->kernelPalVaryReverse(ticks, stepStop, direction));  }  reg_t kPalVaryGetCurrentStep(EngineState *s, int argc, reg_t *argv) { -	return make_reg(0, g_sci->_gfxPalette->kernelPalVaryGetCurrentStep()); +	return make_reg(0, g_sci->_gfxPalette16->kernelPalVaryGetCurrentStep());  }  reg_t kPalVaryDeinit(EngineState *s, int argc, reg_t *argv) { -	g_sci->_gfxPalette->kernelPalVaryDeinit(); +	g_sci->_gfxPalette16->kernelPalVaryDeinit();  	return NULL_REG;  }  reg_t kPalVaryChangeTarget(EngineState *s, int argc, reg_t *argv) {  	GuiResourceId paletteId = argv[0].toUint16(); -	int16 currentStep = g_sci->_gfxPalette->kernelPalVaryChangeTarget(paletteId); +	int16 currentStep = g_sci->_gfxPalette16->kernelPalVaryChangeTarget(paletteId);  	return make_reg(0, currentStep);  }  reg_t kPalVaryChangeTicks(EngineState *s, int argc, reg_t *argv) {  	uint16 ticks = argv[0].toUint16(); -	g_sci->_gfxPalette->kernelPalVaryChangeTicks(ticks); +	g_sci->_gfxPalette16->kernelPalVaryChangeTicks(ticks);  	return NULL_REG;  }  reg_t kPalVaryPauseResume(EngineState *s, int argc, reg_t *argv) {  	bool pauseState = !argv[0].isNull(); -	g_sci->_gfxPalette->kernelPalVaryPause(pauseState); +	g_sci->_gfxPalette16->kernelPalVaryPause(pauseState);  	return NULL_REG;  }  reg_t kAssertPalette(EngineState *s, int argc, reg_t *argv) {  	GuiResourceId paletteId = argv[0].toUint16(); -	g_sci->_gfxPalette->kernelAssertPalette(paletteId); +	g_sci->_gfxPalette16->kernelAssertPalette(paletteId);  	return s->r_acc;  } @@ -1253,16 +1253,16 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {  	switch (operation) {  	case 0: { // remap by percent  		uint16 percent = argv[1].toUint16(); -		g_sci->_gfxPalette->resetRemapping(); -		g_sci->_gfxPalette->setRemappingPercent(254, percent); +		g_sci->_gfxPalette16->resetRemapping(); +		g_sci->_gfxPalette16->setRemappingPercent(254, percent);  		}  		break;  	case 1:	{ // remap by range  		uint16 from = argv[1].toUint16();  		uint16 to = argv[2].toUint16();  		uint16 base = argv[3].toUint16(); -		g_sci->_gfxPalette->resetRemapping(); -		g_sci->_gfxPalette->setRemappingRange(254, from, to, base); +		g_sci->_gfxPalette16->resetRemapping(); +		g_sci->_gfxPalette16->setRemappingRange(254, from, to, base);  		}  		break;  	case 2:	// turn remapping off (unused) diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 8953f45266..a765fe842e 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -49,6 +49,7 @@  #include "sci/graphics/text16.h"  #include "sci/graphics/view.h"  #ifdef ENABLE_SCI32 +#include "sci/graphics/palette32.h"  #include "sci/graphics/controls32.h"  #include "sci/graphics/font.h"	// TODO: remove once kBitmap is moved in a separate class  #include "sci/graphics/text32.h" @@ -126,10 +127,46 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {  }  reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { +/* TODO: Transcribed from SCI engine disassembly. +	GraphicsMgr &graphicsMgr = g_sci->_graphicsMgr; +	if (graphicsMgr.palMorphNeeded) { +		graphicsMgr.PalMorphFrameOut(&g_PalStyleRanges, false); +	} +	else { +		// TODO: Not sure if this is a pointer or not yet. +		if (g_ScrollState != nullptr) { +			kFrameOutDoScroll(); +		} + +		bool showBits = true; +		if (argc == 1) { +			showBits = (bool) argv[0].toUint16(); +		} + +		rect SOL_Rect = { .left = 0, .top = 0, .right = UINT32_MAX, .bottom = UINT32_MAX }; +		graphicsMgr.FrameOut(showBits, &rect); +	} +*/  	g_sci->_gfxFrameout->kernelFrameout();  	return NULL_REG;  } +reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) { +/* TODO: Transcribed from SCI engine disassembly. +	 uint16 start = argv[0].toUint16(); +	 uint16 end = argv[1].toUint16(); +	 if (end <= start) { +		uint16 index = start; +		while (index <= end) { +			g_PalStyleRanges[index] = 0; +		} +	 } +*/ + +	kStub(s, argc, argv); +	return NULL_REG; +} +  reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {  	Common::Rect objRect1 = g_sci->_gfxCompare->getNSRect(argv[0]);  	Common::Rect objRect2 = g_sci->_gfxCompare->getNSRect(argv[1]); @@ -707,66 +744,64 @@ reg_t kPalVaryUnknown2(EngineState *s, int argc, reg_t *argv) {  	return kStub(s, argc, argv);  } +enum { +	kSetCycle = 0, +	kDoCycle = 1, +	kCyclePause = 2, +	kCycleOn = 3, +	kCycleOff = 4 +}; +  reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {  	// Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen)  	switch (argv[0].toUint16()) { -	case 0: {	// Palette animation initialization -		// 3 or 4 extra params -		// Case 1 sends fromColor and speed again, so we don't need them here. -		// Only toColor is stored -		//uint16 fromColor = argv[1].toUint16(); -		s->_palCycleToColor = argv[2].toUint16(); -		//uint16 speed = argv[3].toUint16(); - -		// Invalidate the picture, so that the palette steps calls (case 1 -		// below) can update its palette without it being overwritten by the -		// view/picture palettes. -		g_sci->_gfxScreen->_picNotValid = 1; - -		// TODO: The fourth optional parameter is an unknown integer, and is 0 by default -		if (argc == 5) { -			// When this variant is used, picNotValid doesn't seem to be set -			// (e.g. GK1 room 480). In this case, the animation step calls are -			// not made, so perhaps this signifies the palette cycling steps -			// to make. -			// GK1 sets this to 6 (6 palette steps?) -			g_sci->_gfxScreen->_picNotValid = 0; -		} -		kStub(s, argc, argv); +	case kSetCycle: { +		uint16 fromColor = argv[1].toUint16(); +		uint16 toColor = argv[2].toUint16(); +		int16 direction = argv[3].toSint16(); +		uint16 delay = (argc == 4 ? 0 : argv[4].toUint16()); + +		g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay);  		}  		break; -	case 1:	{ // Palette animation step -		// This is the same as the old kPaletteAnimate call, with 1 set of colors. -		// The end color is set up during initialization in case 0 above. - -		// 1 or 2 extra params +	case kDoCycle: {  		uint16 fromColor = argv[1].toUint16(); -		uint16 speed = (argc == 2) ? 1 : argv[2].toUint16(); -		// TODO: For some reason, this doesn't set the color correctly -		// (e.g. LSL6 intro, room 100, Sierra logo) -		if (g_sci->_gfxPalette->kernelAnimate(fromColor, s->_palCycleToColor, speed)) -			g_sci->_gfxPalette->kernelAnimateSet(); +		int16 speed = (argc == 2) ? 1 : argv[2].toSint16(); +		g_sci->_gfxPalette32->doCycle(fromColor, speed);  		} -		// No kStub() call here, as this gets called loads of times, like kPaletteAnimate  		break; -	// case 2 hasn't been encountered -	// case 3 hasn't been encountered -	case 4:	// reset any palette cycling and make the picture valid again -		// Gets called when changing rooms and after palette cycling animations finish -		// 0 or 1 extra params +	case kCyclePause: {  		if (argc == 1) { -			g_sci->_gfxScreen->_picNotValid = 0; -			// TODO: This also seems to perform more steps +			g_sci->_gfxPalette32->cycleAllPause();  		} else { -			// The variant with the 1 extra param resets remapping to base -			// TODO +			uint16 fromColor = argv[1].toUint16(); +			g_sci->_gfxPalette32->cyclePause(fromColor); +		} +		} +		break; +	case kCycleOn: { +		if (argc == 1) { +			g_sci->_gfxPalette32->cycleAllOn(); +		} else { +			uint16 fromColor = argv[1].toUint16(); +			g_sci->_gfxPalette32->cycleOn(fromColor); +		} +		} +		break; +	case kCycleOff: { +		if (argc == 1) { +			g_sci->_gfxPalette32->cycleAllOff(); +		} else { +			uint16 fromColor = argv[1].toUint16(); +			g_sci->_gfxPalette32->cycleOff(fromColor);  		} -		kStub(s, argc, argv);  		break; +		}  	default: -		// TODO -		kStub(s, argc, argv); +		// In SCI2.1 there are no values above 4, so should never get here; +		// SCI just returns early if this ever happens. +		assert(false);  		break;  	} @@ -787,7 +822,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		int16 base = (argc >= 2) ? argv[1].toSint16() : 0;  		if (base > 0)  			warning("kRemapColors(0) called with base %d", base); -		g_sci->_gfxPalette->resetRemapping(); +		g_sci->_gfxPalette32->resetRemapping();  		}  		break;  	case 1:	{ // remap by range @@ -798,7 +833,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0;  		if (unk5 > 0)  			warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5); -		g_sci->_gfxPalette->setRemappingRange(color, from, to, base); +		g_sci->_gfxPalette32->setRemappingRange(color, from, to, base);  		}  		break;  	case 2:	{ // remap by percent @@ -806,7 +841,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		uint16 percent = argv[2].toUint16(); // 0 - 100  		if (argc >= 4)  			warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); -		g_sci->_gfxPalette->setRemappingPercent(color, percent); +		g_sci->_gfxPalette32->setRemappingPercent(color, percent);  		}  		break;  	case 3:	{ // remap to gray @@ -816,7 +851,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		int16 percent = argv[2].toSint16(); // 0 - 100  		if (argc >= 4)  			warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); -		g_sci->_gfxPalette->setRemappingPercentGray(color, percent); +		g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);  		}  		break;  	case 4:	{ // remap to percent gray @@ -826,7 +861,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		// argv[3] is unknown (a number, e.g. 200) - start color, perhaps?  		if (argc >= 5)  			warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); -		g_sci->_gfxPalette->setRemappingPercentGray(color, percent); +		g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);  		}  		break;  	case 5:	{ // don't map to range @@ -834,7 +869,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {  		uint16 intensity = argv[2].toUint16();  		// HACK for PQ4  		if (g_sci->getGameId() == GID_PQ4) -			g_sci->_gfxPalette->kernelSetIntensity(0, 255, intensity, true); +			g_sci->_gfxPalette32->kernelSetIntensity(0, 255, intensity, true);  		kStub(s, argc, argv);  		} diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 67d814b86f..5b2245e84d 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -312,10 +312,10 @@ static void draw_line(EngineState *s, Common::Point p1, Common::Point p2, int ty  	// Red : Barred access  	// Yellow: Contained access  	int poly_colors[4] = { -		g_sci->_gfxPalette->kernelFindColor(0, 255, 0),	// green -		g_sci->_gfxPalette->kernelFindColor(0, 0, 255),	// blue -		g_sci->_gfxPalette->kernelFindColor(255, 0, 0),	// red -		g_sci->_gfxPalette->kernelFindColor(255, 255, 0)	// yellow +		g_sci->_gfxPalette16->kernelFindColor(0, 255, 0),	// green +		g_sci->_gfxPalette16->kernelFindColor(0, 0, 255),	// blue +		g_sci->_gfxPalette16->kernelFindColor(255, 0, 0),	// red +		g_sci->_gfxPalette16->kernelFindColor(255, 255, 0)	// yellow  	};  	// Clip @@ -334,8 +334,8 @@ static void draw_point(EngineState *s, Common::Point p, int start, int width, in  	// Green: End point  	// Blue: Starting point  	int point_colors[2] = { -		g_sci->_gfxPalette->kernelFindColor(0, 255, 0),	// green -		g_sci->_gfxPalette->kernelFindColor(0, 0, 255)		// blue +		g_sci->_gfxPalette16->kernelFindColor(0, 255, 0),	// green +		g_sci->_gfxPalette16->kernelFindColor(0, 0, 255)		// blue  	};  	Common::Rect rect = Common::Rect(p.x - 1, p.y - 1, p.x - 1 + 3, p.y - 1 + 3); diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 6920466711..8db0c542eb 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -231,7 +231,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {  			initGraphics(screenWidth, screenHeight, screenWidth > 320);  		else {  			g_sci->_gfxScreen->kernelSyncWithFramebuffer(); -			g_sci->_gfxPalette->kernelSyncScreenPalette(); +			g_sci->_gfxPalette16->kernelSyncScreenPalette();  		}  	} diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index b464d347bd..09ccff39ac 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -304,7 +304,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {  	_segMan->saveLoadWithSerializer(s);  	g_sci->_soundCmd->syncPlayList(s); -	g_sci->_gfxPalette->saveLoadWithSerializer(s); +	g_sci->_gfxPalette16->saveLoadWithSerializer(s);  }  void Vocabulary::saveLoadWithSerializer(Common::Serializer &s) { diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 417d98e2e2..d53e6b48c8 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -129,8 +129,6 @@ void EngineState::reset(bool isRestoring) {  	_vmdPalStart = 0;  	_vmdPalEnd = 256; - -	_palCycleToColor = 255;  }  void EngineState::speedThrottler(uint32 neededSleep) { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index e7499e66c9..eb9f3bbc5d 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -203,8 +203,6 @@ public:  	uint16 _vmdPalStart, _vmdPalEnd;  	bool _syncedAudioOptions; -	uint16 _palCycleToColor; -  	/**  	 * Resets the engine state.  	 */ diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 61aeb00ac3..9512ec2ed1 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -44,7 +44,7 @@  #include "sci/graphics/view.h"  #include "sci/graphics/screen.h"  #include "sci/graphics/paint32.h" -#include "sci/graphics/palette.h" +#include "sci/graphics/palette32.h"  #include "sci/graphics/picture.h"  #include "sci/graphics/text32.h"  #include "sci/graphics/frameout.h" @@ -59,7 +59,7 @@ enum SciSpeciaPlanelPictureCodes {  	kPlanePlainColored = 0xffff		// -1  }; -GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32) +GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32)  	: _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) {  	_coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; @@ -651,6 +651,97 @@ void GfxFrameout::drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int1  	//	warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority);  } +/* TODO: This is the proper implementation of GraphicsMgr::FrameOut transcribed from SQ6 SCI engine disassembly. +static DrawList* g_drawLists[100]; +static RectList* g_rectLists[100]; +void GfxFrameout::FrameOut(bool shouldShowBits, SOL_Rect *rect) { +	if (robot) { +		robot.doRobot(); +	} + +	auto planeCount = screen.planeList.planeCount; +	if (planeCount > 0) { +		for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { +			Plane plane = *screen.planeList[planeIndex]; + +			DrawList* drawList = new DrawList(); +			g_drawLists[planeIndex] = drawList; +			RectList* rectList = new RectList(); +			g_rectLists[planeIndex] = rectList; +		} +	} +  +	if (g_Remap_numActiveRemaps > 0 && remapNeeded) { +		screen.RemapMarkRedraw(); +	} +  +	CalcLists(&g_drawLists, &g_rectLists, rect); + +	// SCI engine stores reference *after* CalcLists +	planeCount = screen.planeList.planeCount; +	if (planeCount > 0) { +		for (int drawListIndex = 0; drawListIndex < planeCount; ++i) { +			DrawList* drawList = g_drawLists[drawListIndex]; +			drawList->Sort(); +		} + +		for (int drawListIndex = 0; drawListIndex < planeCount; ++i) { +			DrawList* drawList = g_drawLists[drawListIndex]; +			if (drawList == nullptr || drawList->count == 0) { +				continue; +			} + +			for (int screenItemIndex = 0, screenItemCount = drawList->count; screenItemIndex < screenItemCount; ++screenItemIndex) { +				ScreenItem* screenItem = drawList->items[screenItemIndex]; +				screenItem->GetCelObj()->SubmitPalette(); +			} +		} +	} + +	// UpdateForFrame is where all palette mutations occur (cycles, varies, etc.) +	bool remapNeeded = GPalette().UpdateForFrame(); +	if (planeCount > 0) { +		frameNowVisible = false; + +		for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { +			Plane* plane = screen.planeList[planeIndex]; + +			DrawEraseList(g_rectLists[planeIndex], plane); +			DrawScreenItemsList(g_drawLists[planeIndex]); +		} +	} + +	if (robot) { +		robot.FrameAlmostVisible(); +	} + +	GPalette().UpdateHardware(); + +	if (shouldShowBits) { +		ShowBits(); +	} + +	frameNowVisible = true; + +	if (robot) { +		robot.FrameNowVisible(); +	} + +	if (planeCount > 0) { +		for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) { +			if (g_rectLists[planeIndex] != nullptr) { +				delete g_rectLists[planeIndex]; +			} +			if (g_drawLists[planeIndex] != nullptr) { +				delete g_drawLists[planeIndex]; +			} +		} +	} +} +void GfxFrameout::CalcLists(DrawList **drawLists, RectList **rectLists, SOL_Rect *rect) { +	screen.CalcLists(&visibleScreen, drawLists, rectLists, rect); +} +*/  void GfxFrameout::kernelFrameout() {  	if (g_sci->_robotDecoder->isVideoLoaded()) {  		showVideo(); @@ -658,6 +749,11 @@ void GfxFrameout::kernelFrameout() {  	}  	_palette->palVaryUpdate(); +	_palette->applyCycles(); +	_palette->applyFade(); +	// TODO: This should probably not require screen pic invalidation +	_screen->_picNotValid = 1; +	_palette->setOnScreen();  	for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {  		reg_t planeObject = it->object; diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index e0c60f92c1..a422572ef4 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -114,7 +114,7 @@ class GfxScreen;   */  class GfxFrameout {  public: -	GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32); +	GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32);  	~GfxFrameout();  	void kernelAddPlane(reg_t object); @@ -161,7 +161,7 @@ private:  	ResourceManager *_resMan;  	GfxCoordAdjuster32 *_coordAdjuster;  	GfxCache *_cache; -	GfxPalette *_palette; +	GfxPalette32 *_palette;  	GfxScreen *_screen;  	GfxPaint32 *_paint32; diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index 8e2e12b7bd..e10b9fddbf 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -234,7 +234,7 @@ void GfxMacIconBar::remapColors(Graphics::Surface *surf, const byte *palette) {  		byte g = palette[color * 3 + 1];  		byte b = palette[color * 3 + 2]; -		*pixels++ = g_sci->_gfxPalette->findMacIconBarColor(r, g, b); +		*pixels++ = g_sci->_gfxPalette16->findMacIconBarColor(r, g, b);  	}  } diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 59abef5550..667aef4f28 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -86,10 +86,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)  	_macClut = 0;  	loadMacIconBarPalette(); -#ifdef ENABLE_SCI32 -	_clutTable = 0; -#endif -  	switch (_resMan->getViewType()) {  	case kViewEga:  		_totalScreenColors = 16; @@ -117,10 +113,6 @@ GfxPalette::~GfxPalette() {  		palVaryRemoveTimer();  	delete[] _macClut; - -#ifdef ENABLE_SCI32 -	unloadClut(); -#endif  }  bool GfxPalette::isMerging() { @@ -819,6 +811,8 @@ bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) {  	return false;  } +// TODO: This code should not set up an independent timer in SCI32. SCI32 engine palette varies happen in +// Palette::UpdateForFrame which is called by GraphicsMgr::FrameOut.  void GfxPalette::palVaryInstallTimer() {  	// Remove any possible leftover palVary timer callbacks.  	// This happens for example in QFG1VGA, when sleeping at Erana's place @@ -1087,58 +1081,4 @@ bool GfxPalette::colorIsFromMacClut(byte index) {  	return index != 0 && _macClut && (_macClut[index * 3] != 0 || _macClut[index * 3 + 1] != 0 || _macClut[index * 3 + 2] != 0);  } -#ifdef ENABLE_SCI32 - -bool GfxPalette::loadClut(uint16 clutId) { -	// loadClut() will load a color lookup table from a clu file and set -	// the palette found in the file. This is to be used with Phantasmagoria 2. - -	unloadClut(); - -	Common::String filename = Common::String::format("%d.clu", clutId); -	Common::File clut; - -	if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3) -		return false; - -	// Read in the lookup table -	// It maps each RGB565 color to a palette index -	_clutTable = new byte[0x10000]; -	clut.read(_clutTable, 0x10000); - -	Palette pal; -	memset(&pal, 0, sizeof(Palette)); - -	// Setup 1:1 mapping -	for (int i = 0; i < 256; i++) { -		pal.mapping[i] = i; -	} - -	// Now load in the palette -	for (int i = 1; i <= 236; i++) { -		pal.colors[i].used = 1; -		pal.colors[i].r = clut.readByte(); -		pal.colors[i].g = clut.readByte(); -		pal.colors[i].b = clut.readByte(); -	} - -	set(&pal, true); -	setOnScreen(); -	return true; -} - -byte GfxPalette::matchClutColor(uint16 color) { -	// Match a color in RGB565 format to a palette index based on the loaded CLUT -	assert(_clutTable); -	return _clutTable[color]; -} - -void GfxPalette::unloadClut() { -	// This will only unload the actual table, but not reset any palette -	delete[] _clutTable; -	_clutTable = 0; -} - -#endif -  } // End of namespace Sci diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 500a45eccf..82fd20a432 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -110,12 +110,6 @@ public:  	byte findMacIconBarColor(byte r, byte g, byte b);  	bool colorIsFromMacClut(byte index); -#ifdef ENABLE_SCI32 -	bool loadClut(uint16 clutId); -	byte matchClutColor(uint16 color); -	void unloadClut(); -#endif -  private:  	void palVaryInit();  	void palVaryInstallTimer(); @@ -152,10 +146,6 @@ private:  	void loadMacIconBarPalette();  	byte *_macClut; - -#ifdef ENABLE_SCI32 -	byte *_clutTable; -#endif  };  } // End of namespace Sci diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp new file mode 100644 index 0000000000..61ca1b99c2 --- /dev/null +++ b/engines/sci/graphics/palette32.cpp @@ -0,0 +1,350 @@ +/* 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 "common/file.h" + +#include "sci/sci.h" +#include "sci/graphics/palette32.h" + +namespace Sci { +	 +GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen) +	: GfxPalette(resMan, screen), _clutTable(0), _cyclers(), _cycleMap() {} + +GfxPalette32::~GfxPalette32() { +	unloadClut(); +	cycleAllOff(); +} + +bool GfxPalette32::loadClut(uint16 clutId) { +	// loadClut() will load a color lookup table from a clu file and set +	// the palette found in the file. This is to be used with Phantasmagoria 2. + +	unloadClut(); + +	Common::String filename = Common::String::format("%d.clu", clutId); +	Common::File clut; + +	if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3) +		return false; + +	// Read in the lookup table +	// It maps each RGB565 color to a palette index +	_clutTable = new byte[0x10000]; +	clut.read(_clutTable, 0x10000); + +	Palette pal; +	memset(&pal, 0, sizeof(Palette)); + +	// Setup 1:1 mapping +	for (int i = 0; i < 256; i++) { +		pal.mapping[i] = i; +	} + +	// Now load in the palette +	for (int i = 1; i <= 236; i++) { +		pal.colors[i].used = 1; +		pal.colors[i].r = clut.readByte(); +		pal.colors[i].g = clut.readByte(); +		pal.colors[i].b = clut.readByte(); +	} + +	set(&pal, true); +	setOnScreen(); +	return true; +} + +byte GfxPalette32::matchClutColor(uint16 color) { +	// Match a color in RGB565 format to a palette index based on the loaded CLUT +	assert(_clutTable); +	return _clutTable[color]; +} + +void GfxPalette32::unloadClut() { +	// This will only unload the actual table, but not reset any palette +	delete[] _clutTable; +	_clutTable = 0; +} + +inline void GfxPalette32::_clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear) { +	bool *mapEntry = _cycleMap + fromColor; +	const bool *lastEntry = _cycleMap + numColorsToClear; +	while (mapEntry < lastEntry) { +		*mapEntry++ = false; +	} +} + +inline void GfxPalette32::_setCycleMap(const uint16 fromColor, const uint16 numColorsToSet) { +	bool *mapEntry = _cycleMap + fromColor; +	const bool *lastEntry = _cycleMap + numColorsToSet; +	while (mapEntry < lastEntry) { +		if (*mapEntry != false) { +			error("Cycles intersect"); +		} +		*mapEntry++ = true; +	} +} + +inline PalCycler *GfxPalette32::_getCycler(const uint16 fromColor) { +	const int numCyclers = ARRAYSIZE(_cyclers); + +	for (int cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { +		PalCycler *cycler = _cyclers[cyclerIndex]; +		if (cycler != nullptr && cycler->fromColor == fromColor) { +			return cycler; +		} +	} + +	return nullptr; +} + +inline void _doCycle(PalCycler *cycler, const int16 speed) { +	int16 currentCycle = cycler->currentCycle; +	const uint16 numColorsToCycle = cycler->numColorsToCycle; + +	if (cycler->direction == 0) { +		currentCycle = (currentCycle - (speed % numColorsToCycle)) + numColorsToCycle; +	} else { +		currentCycle = currentCycle + speed; +	} + +	cycler->currentCycle = (uint8) (currentCycle % numColorsToCycle); +} + +inline void _applyCycleToPalette(PalCycler *cycler, Palette *palette) { +	const int16 currentCycle = cycler->currentCycle; +	const uint16 numColorsToCycle = cycler->numColorsToCycle; + +	Sci::Color tempPalette[numColorsToCycle]; +	Sci::Color *sourceColor = palette->colors + cycler->fromColor; +	memcpy(tempPalette, sourceColor, sizeof(tempPalette)); + +	Sci::Color *targetColor = sourceColor; +	for (int numColorsCycled = 0; numColorsCycled < numColorsToCycle; ++numColorsCycled) { +		Sci::Color sourceColor = *(tempPalette + ((currentCycle + numColorsCycled) % numColorsToCycle)); +		*(targetColor + numColorsCycled) = sourceColor; +	} +} + +void GfxPalette32::applyAllCycles() { +	for (int cyclerIndex = 0, numCyclers = ARRAYSIZE(_cyclers); cyclerIndex < numCyclers; ++cyclerIndex) { +		PalCycler *cycler = _cyclers[cyclerIndex]; +		if (cycler != nullptr) { +			cycler->currentCycle = (uint8) ((((int) cycler->currentCycle) + 1) % cycler->numColorsToCycle); +			// Disassembly was not fully evaluated to verify this is exactly the same +			// as the code from applyCycles, but it appeared to be at a glance +			_applyCycleToPalette(cycler, &_sysPalette); +		} +	} +} + +void GfxPalette32::applyCycles() { +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler == nullptr) { +			continue; +		} + +		if (cycler->delay != 0 && cycler->numTimesPaused == 0) { +			while ((cycler->delay + cycler->lastUpdateTick) < g_sci->getTickCount()) { +				_doCycle(cycler, 1); +				cycler->lastUpdateTick += cycler->delay; +			} +		} + +		_applyCycleToPalette(cycler, &_sysPalette); +	} +} + +int16 GfxPalette32::setCycle(const uint16 fromColor, const uint16 toColor, const int16 direction, const int16 delay) { +	assert(fromColor <= UINT8_MAX); +	assert(toColor <= UINT8_MAX); +	assert(fromColor < toColor); + +	int cyclerIndex; +	const int numCyclers = ARRAYSIZE(_cyclers); + +	PalCycler *cycler = _getCycler(fromColor); + +	if (cycler != nullptr) { +		debug("Resetting existing cycler"); +		_clearCycleMap(fromColor, cycler->numColorsToCycle); +	} else { +		for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { +			if (_cyclers[cyclerIndex] == nullptr) { +				cycler = new PalCycler; +				_cyclers[cyclerIndex] = cycler; +				break; +			} +		} +	} + +	// SCI engine overrides the first oldest cycler that it finds where +	// “oldest” is determined by the difference between the tick and now +	if (cycler == nullptr) { +		int maxUpdateDelta = -1; +		// Optimization: Unlike actual SCI (SQ6) engine, we call +		// getTickCount only once and store it, instead of calling it +		// twice on each iteration through the loop +		const uint32 now = g_sci->getTickCount(); + +		for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { +			PalCycler *candidate = _cyclers[cyclerIndex]; + +			const int32 updateDelta = now - candidate->lastUpdateTick; +			if (updateDelta >= maxUpdateDelta) { +				maxUpdateDelta = updateDelta; +				cycler = candidate; +			} +		} + +		_clearCycleMap(cycler->fromColor, cycler->numColorsToCycle); +	} + +	const uint16 numColorsToCycle = 1 + ((uint8) toColor) - fromColor; +	cycler->fromColor = (uint8) fromColor; +	cycler->numColorsToCycle = (uint8) numColorsToCycle; +	cycler->currentCycle = (uint8) fromColor; +	cycler->direction = direction < 0 ? PalCycleBackward : PalCycleForward; +	cycler->delay = delay; +	cycler->lastUpdateTick = g_sci->getTickCount(); +	cycler->numTimesPaused = 0; + +	_setCycleMap(fromColor, numColorsToCycle); + +	// TODO: Validate that this is the correct return value according +	// to disassembly +	return 0; +} + +void GfxPalette32::doCycle(const uint16 fromColor, const int16 speed) { +	PalCycler *cycler = _getCycler(fromColor); +	if (cycler != nullptr) { +		cycler->lastUpdateTick = g_sci->getTickCount(); +		_doCycle(cycler, speed); +	} +} + +void GfxPalette32::cycleOn(const uint16 fromColor) { +	PalCycler *cycler = _getCycler(fromColor); +	if (cycler != nullptr && cycler->numTimesPaused > 0) { +		--cycler->numTimesPaused; +	} +} + +void GfxPalette32::cyclePause(const uint16 fromColor) { +	PalCycler *cycler = _getCycler(fromColor); +	if (cycler != nullptr) { +		++cycler->numTimesPaused; +	} +} + +void GfxPalette32::cycleAllOn() { +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler != nullptr && cycler->numTimesPaused > 0) { +			--cycler->numTimesPaused; +		} +	} +} + +void GfxPalette32::cycleAllPause() { +	// TODO: The SCI SQ6 cycleAllPause function does not seem to perform +	// nullptr checking?? This would definitely cause null pointer +	// dereference in SCI code. I have not seen anything actually call +	// this function yet, so it is possible it is just unused and broken +	// in SCI SQ6. This assert exists so that if this function is called, +	// it is noticed and can be rechecked in the actual engine. +	// Obviously this code *does* do nullptr checks instead of crashing. :) +	assert(0); +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler != nullptr) { +			// This seems odd, because currentCycle is 0..numColorsPerCycle, +			// but fromColor is 0..255. When applyAllCycles runs, the values +			// end up back in range +			cycler->currentCycle = cycler->fromColor; +		} +	} + +	applyAllCycles(); + +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler != nullptr) { +			++cycler->numTimesPaused; +		} +	} +} + +void GfxPalette32::cycleOff(const uint16 fromColor) { +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler != nullptr && cycler->fromColor == fromColor) { +			_clearCycleMap(fromColor, cycler->numColorsToCycle); +			delete cycler; +			_cyclers[i] = nullptr; +			break; +		} +	} +} + +void GfxPalette32::cycleAllOff() { +	for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { +		PalCycler *cycler = _cyclers[i]; +		if (cycler != nullptr) { +			_clearCycleMap(cycler->fromColor, cycler->numColorsToCycle); +			delete cycler; +			_cyclers[i] = nullptr; +		} +	} +} + +void GfxPalette32::applyFade() { +	// TODO: Create and update a _nextPalette, not a single _sysPalette, to +	// conform to the way the actual SCI32 engine works (writes to a +	// next-frame-palette and then copies to the current palette on frameout) +	Sci::Color *color = _sysPalette.colors; +	uint8 *fadeAmount = _fadeTable; +	for (int i = 0; i < 256; ++i) { +		if (*fadeAmount == 100) { +			continue; +		} + +		color->r = ((int) color->r * ((int) *fadeAmount)) / 100; +		color->g = ((int) color->r * ((int) *fadeAmount)) / 100; +		color->b = ((int) color->r * ((int) *fadeAmount)) / 100; +	} +} + +void GfxPalette32::setFade(uint8 percent, uint16 fromColor, uint16 toColor) { +	uint8 *fadeAmount = _fadeTable; +	for (int i = fromColor, len = toColor - fromColor + 1; i < len; ++i) { +		*fadeAmount++ = percent; +	} +} + +void GfxPalette32::fadeOff() { +	setFade(100, 0, 255); +} + +} diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h new file mode 100644 index 0000000000..87bebbb2fa --- /dev/null +++ b/engines/sci/graphics/palette32.h @@ -0,0 +1,122 @@ +/* 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_PALETTE32_H +#define SCI_GRAPHICS_PALETTE32_H + +#include "sci/graphics/palette.h" + +enum PalCyclerDirection { +	PalCycleBackward = 0, +	PalCycleForward = 1 +}; + +struct PalCycler { +	/** +	 * The color index of the palette cycler. This value is effectively used as the ID for the +	 * cycler. +	 */ +	uint8 fromColor; + +	/** +	 * The number of palette slots which are cycled by the palette cycler. +	 */ +	uint16 numColorsToCycle; + +	/** +	 * The position of the cursor in its cycle. +	 */ +	uint8 currentCycle; + +	/** +	 * The direction of the cycler. +	 */ +	PalCyclerDirection direction; + +	/** +	 * The cycle tick at the last time the cycler’s currentCycle was updated. +	 * 795 days of game time ought to be enough for everyone? :) +	 */ +	uint32 lastUpdateTick; + +	/** +	 * The amount of time in ticks each cycle should take to complete. In other words, +	 * the higher the delay, the slower the cycle animation. If delay is 0, the cycler +	 * does not automatically cycle and needs to be pumped manually with DoCycle. +	 */ +	int16 delay; + +	/** +	 * The number of times this cycler has been paused. +	 */ +	uint16 numTimesPaused; +}; + +namespace Sci { +	class GfxPalette32 : public GfxPalette { +	public: +		GfxPalette32(ResourceManager *resMan, GfxScreen *screen); +		~GfxPalette32(); + +	private: +		// SCI2 (SQ6) defines 10 cyclers +		PalCycler *_cyclers[10]; +		/** +		 * The cycle map is used to detect overlapping cyclers. According to SCI engine code, when two cyclers overlap, +		 * a fatal error has occurred and the engine will display an error and then exit. +		 */ +		bool _cycleMap[256]; +		inline void _clearCycleMap(uint16 fromColor, uint16 numColorsToClear); +		inline void _setCycleMap(uint16 fromColor, uint16 numColorsToClear); +		inline PalCycler *_getCycler(uint16 fromColor); + +		/** +		 * The fade table records the expected intensity level of each pixel in the palette that will be displayed on +		 * the next frame. +		 */ +		byte _fadeTable[256]; +		byte *_clutTable; + +	public: +		void applyAllCycles(); +		void applyCycles(); +		void applyFade(); + +		bool loadClut(uint16 clutId); +		byte matchClutColor(uint16 color); +		void unloadClut(); + +		int16 setCycle(uint16 fromColor, uint16 toColor, int16 direction, int16 delay); +		void doCycle(uint16 fromColor, int16 speed); +		void cycleOn(uint16 fromColor); +		void cyclePause(uint16 fromColor); +		void cycleAllOn(); +		void cycleAllPause(); +		void cycleOff(uint16 fromColor); +		void cycleAllOff(); + +		void setFade(uint8 percent, uint16 fromColor, uint16 toColor); +		void fadeOff(); +	}; +} + +#endif diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 33392e3b42..08e5ea84d8 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -84,6 +84,7 @@ MODULE_OBJS += \  	graphics/controls32.o \  	graphics/frameout.o \  	graphics/paint32.o \ +	graphics/palette32.o \  	graphics/text32.o \  	video/robot_decoder.o  endif diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index f1ab65ef98..598368e428 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -63,6 +63,7 @@  #include "sci/graphics/transitions.h"  #ifdef ENABLE_SCI32 +#include "sci/graphics/palette32.h"  #include "sci/graphics/text32.h"  #include "sci/graphics/frameout.h"  #include "sci/video/robot_decoder.h" @@ -153,6 +154,9 @@ SciEngine::~SciEngine() {  	DebugMan.clearAllDebugChannels();  #ifdef ENABLE_SCI32 +	// _gfxPalette32 is the same as _gfxPalette16 +	// and will be destroyed when _gfxPalette16 is +	// destroyed  	delete _gfxControls32;  	delete _gfxText32;  	delete _robotDecoder; @@ -168,7 +172,7 @@ SciEngine::~SciEngine() {  	delete _gfxCoordAdjuster;  	delete _gfxPorts;  	delete _gfxCache; -	delete _gfxPalette; +	delete _gfxPalette16;  	delete _gfxCursor;  	delete _gfxScreen; @@ -614,7 +618,8 @@ void SciEngine::initGraphics() {  	_gfxMenu = 0;  	_gfxPaint = 0;  	_gfxPaint16 = 0; -	_gfxPalette = 0; +	_gfxPalette16 = 0; +	_gfxPalette32 = 0;  	_gfxPorts = 0;  	_gfxText16 = 0;  	_gfxTransitions = 0; @@ -629,9 +634,19 @@ void SciEngine::initGraphics() {  	if (hasMacIconBar())  		_gfxMacIconBar = new GfxMacIconBar(); -	_gfxPalette = new GfxPalette(_resMan, _gfxScreen); -	_gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette); -	_gfxCursor = new GfxCursor(_resMan, _gfxPalette, _gfxScreen); +#ifdef ENABLE_SCI32 +	if (getSciVersion() >= SCI_VERSION_2) { +		_gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen); +		_gfxPalette16 = _gfxPalette32; +	} else { +#endif +		_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen); +#ifdef ENABLE_SCI32 +	} +#endif + +	_gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16); +	_gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);  #ifdef ENABLE_SCI32  	if (getSciVersion() >= SCI_VERSION_2) { @@ -639,12 +654,12 @@ void SciEngine::initGraphics() {  		_gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan);  		_gfxCursor->init(_gfxCoordAdjuster, _eventMan);  		_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); -		_gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette); +		_gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32);  		_gfxPaint = _gfxPaint32;  		_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen);  		_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);  		_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); -		_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); +		_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32);  	} else {  #endif  		// SCI0-SCI1.1 graphic objects creation @@ -652,10 +667,10 @@ void SciEngine::initGraphics() {  		_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);  		_gfxCursor->init(_gfxCoordAdjuster, _eventMan);  		_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); -		_gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette); -		_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette, _gfxTransitions, _audio); +		_gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16); +		_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio);  		_gfxPaint = _gfxPaint16; -		_gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette, _gfxCursor, _gfxTransitions); +		_gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions);  		_gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen);  		_gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen);  		_gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor); @@ -670,7 +685,7 @@ void SciEngine::initGraphics() {  #endif  	// Set default (EGA, amiga or resource 999) palette -	_gfxPalette->setDefault(); +	_gfxPalette16->setDefault();  }  void SciEngine::initStackBaseWithSelector(Selector selector) { @@ -1022,4 +1037,9 @@ void SciEngine::loadMacExecutable() {  	}  } +// Note that SCI engine also has a corresponding TimeMgr::SetTickCount method +// which is used by TimeMgr::SaveRestore when loading a save game. +uint32 SciEngine::getTickCount() { +	return (uint32) ((g_system->getMillis() * 60) / 1000); +}  } // End of namespace Sci diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 15034d5e94..c5528e412a 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -79,6 +79,7 @@ class GfxTransitions;  #ifdef ENABLE_SCI32  class RobotDecoder;  class GfxFrameout; +class GfxPalette32;  #endif  // our engine debug levels @@ -235,6 +236,7 @@ public:  	bool canLoadGameStateCurrently();  	bool canSaveGameStateCurrently();  	void syncSoundSettings(); +	uint32 getTickCount();  	/**  	 * Syncs the audio options of the ScummVM launcher (speech, subtitles or @@ -343,7 +345,8 @@ public:  	GfxCoordAdjuster *_gfxCoordAdjuster;  	GfxCursor *_gfxCursor;  	GfxMenu *_gfxMenu; // Menu for 16-bit gfx -	GfxPalette *_gfxPalette; +	GfxPalette *_gfxPalette16; +	GfxPalette32 *_gfxPalette32; // Palette for 32-bit gfx  	GfxPaint *_gfxPaint;  	GfxPaint16 *_gfxPaint16; // Painting in 16-bit gfx  	GfxPaint32 *_gfxPaint32; // Painting in 32-bit gfx | 
