SCI: Implement accurate renderer architecture for SCI32
This commit is contained in:
parent
4ba0ff8deb
commit
75ccabc325
25 changed files with 6514 additions and 1238 deletions
|
@ -137,6 +137,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
|
||||||
registerCmd("wl", WRAP_METHOD(Console, cmdWindowList)); // alias
|
registerCmd("wl", WRAP_METHOD(Console, cmdWindowList)); // alias
|
||||||
registerCmd("plane_list", WRAP_METHOD(Console, cmdPlaneList));
|
registerCmd("plane_list", WRAP_METHOD(Console, cmdPlaneList));
|
||||||
registerCmd("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias
|
registerCmd("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias
|
||||||
|
registerCmd("visible_plane_list", WRAP_METHOD(Console, cmdVisiblePlaneList));
|
||||||
|
registerCmd("vpl", WRAP_METHOD(Console, cmdVisiblePlaneList)); // alias
|
||||||
registerCmd("plane_items", WRAP_METHOD(Console, cmdPlaneItemList));
|
registerCmd("plane_items", WRAP_METHOD(Console, cmdPlaneItemList));
|
||||||
registerCmd("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias
|
registerCmd("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias
|
||||||
registerCmd("saved_bits", WRAP_METHOD(Console, cmdSavedBits));
|
registerCmd("saved_bits", WRAP_METHOD(Console, cmdSavedBits));
|
||||||
|
@ -380,6 +382,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
|
||||||
debugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n");
|
debugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n");
|
||||||
debugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n");
|
debugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n");
|
||||||
debugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n");
|
debugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n");
|
||||||
|
debugPrintf(" visible_plane_list / vpl - Shows a list of all the planes in the visible draw list (SCI2+)\n");
|
||||||
debugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n");
|
debugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n");
|
||||||
debugPrintf(" saved_bits - List saved bits on the hunk\n");
|
debugPrintf(" saved_bits - List saved bits on the hunk\n");
|
||||||
debugPrintf(" show_saved_bits - Display saved bits\n");
|
debugPrintf(" show_saved_bits - Display saved bits\n");
|
||||||
|
@ -1766,6 +1769,21 @@ bool Console::cmdPlaneList(int argc, const char **argv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Console::cmdVisiblePlaneList(int argc, const char **argv) {
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
if (_engine->_gfxFrameout) {
|
||||||
|
debugPrintf("Visible plane list:\n");
|
||||||
|
_engine->_gfxFrameout->printVisiblePlaneList(this);
|
||||||
|
} else {
|
||||||
|
debugPrintf("This SCI version does not have a list of planes\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
debugPrintf("SCI32 isn't included in this compiled executable\n");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Console::cmdPlaneItemList(int argc, const char **argv) {
|
bool Console::cmdPlaneItemList(int argc, const char **argv) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
debugPrintf("Shows the list of items for a plane\n");
|
debugPrintf("Shows the list of items for a plane\n");
|
||||||
|
|
|
@ -96,6 +96,7 @@ private:
|
||||||
bool cmdAnimateList(int argc, const char **argv);
|
bool cmdAnimateList(int argc, const char **argv);
|
||||||
bool cmdWindowList(int argc, const char **argv);
|
bool cmdWindowList(int argc, const char **argv);
|
||||||
bool cmdPlaneList(int argc, const char **argv);
|
bool cmdPlaneList(int argc, const char **argv);
|
||||||
|
bool cmdVisiblePlaneList(int argc, const char **argv);
|
||||||
bool cmdPlaneItemList(int argc, const char **argv);
|
bool cmdPlaneItemList(int argc, const char **argv);
|
||||||
bool cmdSavedBits(int argc, const char **argv);
|
bool cmdSavedBits(int argc, const char **argv);
|
||||||
bool cmdShowSavedBits(int argc, const char **argv);
|
bool cmdShowSavedBits(int argc, const char **argv);
|
||||||
|
|
|
@ -80,21 +80,18 @@ reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) {
|
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) {
|
||||||
if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL)
|
|
||||||
g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]);
|
g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]);
|
||||||
else
|
return NULL_REG;
|
||||||
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
|
|
||||||
return s->r_acc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) {
|
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) {
|
||||||
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
|
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
|
||||||
return s->r_acc;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
|
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
|
||||||
g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]);
|
g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]);
|
||||||
return s->r_acc;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) {
|
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -115,11 +112,12 @@ reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) {
|
||||||
reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
|
reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
|
||||||
reg_t planeObj = argv[0];
|
reg_t planeObj = argv[0];
|
||||||
GuiResourceId pictureId = argv[1].toUint16();
|
GuiResourceId pictureId = argv[1].toUint16();
|
||||||
int16 pictureX = argv[2].toSint16();
|
int16 x = argv[2].toSint16();
|
||||||
int16 pictureY = argv[3].toSint16();
|
int16 y = argv[3].toSint16();
|
||||||
|
bool mirrorX = argc > 4 ? argv[4].toSint16() : false;
|
||||||
|
|
||||||
g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY);
|
g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX);
|
||||||
return s->r_acc;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
|
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -127,43 +125,13 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
|
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
|
||||||
/* TODO: Transcribed from SCI engine disassembly.
|
bool showBits = argc > 0 ? argv[0].toUint16() : true;
|
||||||
GraphicsMgr &graphicsMgr = g_sci->_graphicsMgr;
|
g_sci->_gfxFrameout->kernelFrameout(showBits);
|
||||||
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;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) {
|
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) {
|
||||||
/* TODO: Transcribed from SCI engine disassembly.
|
g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16());
|
||||||
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;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,72 +234,59 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for scene transitions, replacing (but reusing parts of) the old
|
* Causes an immediate plane transition with an optional transition
|
||||||
* transition code.
|
* effect
|
||||||
*/
|
*/
|
||||||
reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
|
reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
|
||||||
// Can be called with 7 or 8 parameters
|
ShowStyleType type = (ShowStyleType)argv[0].toUint16();
|
||||||
// The style defines which transition to perform. Related to the transition
|
reg_t planeObj = argv[1];
|
||||||
// tables inside graphics/transitions.cpp
|
int16 seconds = argv[2].toSint16();
|
||||||
uint16 showStyle = argv[0].toUint16(); // 0 - 15
|
// NOTE: This value seems to indicate whether the transition is an
|
||||||
reg_t planeObj = argv[1]; // the affected plane
|
// “exit” transition (0) or an “enter” transition (-1) for fade
|
||||||
Common::String planeObjName = s->_segMan->getObjectName(planeObj);
|
// transitions. For other types of transitions, it indicates a palette
|
||||||
uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts
|
// index value to use when filling the screen.
|
||||||
uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff
|
int16 back = argv[3].toSint16();
|
||||||
int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out
|
int16 priority = argv[4].toSint16();
|
||||||
uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts
|
int16 animate = argv[5].toSint16();
|
||||||
uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out
|
// TODO: Rename to frameOutNow?
|
||||||
|
int16 refFrame = argv[6].toSint16();
|
||||||
|
int16 blackScreen;
|
||||||
|
reg_t pFadeArray;
|
||||||
int16 divisions;
|
int16 divisions;
|
||||||
|
|
||||||
// If the game has the pFadeArray selector, another parameter is used here,
|
// SCI 2–2.1early
|
||||||
// before the optional last parameter
|
if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
|
||||||
bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0;
|
blackScreen = 0;
|
||||||
if (hasFadeArray) {
|
pFadeArray = NULL_REG;
|
||||||
// argv[7]
|
divisions = argc > 7 ? argv[7].toSint16() : -1;
|
||||||
divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?)
|
}
|
||||||
} else {
|
// SCI 2.1mid–2.1late
|
||||||
divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?)
|
else if (getSciVersion() < SCI_VERSION_3) {
|
||||||
|
blackScreen = 0;
|
||||||
|
pFadeArray = argc > 7 ? argv[7] : NULL_REG;
|
||||||
|
divisions = argc > 8 ? argv[8].toSint16() : -1;
|
||||||
|
}
|
||||||
|
// SCI 3
|
||||||
|
else {
|
||||||
|
blackScreen = argv[7].toSint16();
|
||||||
|
pFadeArray = argc > 8 ? argv[8] : NULL_REG;
|
||||||
|
divisions = argc > 9 ? argv[9].toSint16() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showStyle > 15) {
|
// TODO: Reuse later for SCI2 and SCI3 implementation and then discard
|
||||||
warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj));
|
// warning("kSetShowStyle: effect %d, plane: %04x:%04x (%s), sec: %d, "
|
||||||
return s->r_acc;
|
// "dir: %d, prio: %d, animate: %d, ref frame: %d, black screen: %d, "
|
||||||
}
|
// "pFadeArray: %04x:%04x (%s), divisions: %d",
|
||||||
|
// type, PRINT_REG(planeObj), s->_segMan->getObjectName(planeObj), seconds,
|
||||||
|
// back, priority, animate, refFrame, blackScreen,
|
||||||
|
// PRINT_REG(pFadeArray), s->_segMan->getObjectName(pFadeArray), divisions);
|
||||||
|
|
||||||
// GK1 calls fadeout (13) / fadein (14) with the following parameters:
|
// NOTE: The order of planeObj and showStyle are reversed
|
||||||
// seconds: 1
|
// because this is how SCI3 called the corresponding method
|
||||||
// backColor: 0 / -1
|
// on the KernelMgr
|
||||||
// fade: 200
|
g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
|
||||||
// animate: 0
|
|
||||||
// refFrame: 0
|
|
||||||
// divisions: 0 / 20
|
|
||||||
|
|
||||||
// TODO: Check if the plane is in the list of planes to draw
|
return NULL_REG;
|
||||||
|
|
||||||
Common::String effectName = "unknown";
|
|
||||||
|
|
||||||
switch (showStyle) {
|
|
||||||
case 0: // no transition / show
|
|
||||||
effectName = "show";
|
|
||||||
break;
|
|
||||||
case 13: // fade out
|
|
||||||
effectName = "fade out";
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
case 14: // fade in
|
|
||||||
effectName = "fade in";
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, "
|
|
||||||
"back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d",
|
|
||||||
showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(),
|
|
||||||
seconds, backColor, priority, animate, refFrame, divisions);
|
|
||||||
return s->r_acc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
|
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -359,6 +314,8 @@ reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
|
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
return kStub(s, argc, argv);
|
||||||
|
#if 0
|
||||||
// Used by SQ6 and LSL6 hires for the text area in the bottom of the
|
// Used by SQ6 and LSL6 hires for the text area in the bottom of the
|
||||||
// screen. The relevant scripts also exist in Phantasmagoria 1, but they're
|
// screen. The relevant scripts also exist in Phantasmagoria 1, but they're
|
||||||
// unused. This is always called by scripts 64906 (ScrollerWindow) and
|
// unused. This is always called by scripts 64906 (ScrollerWindow) and
|
||||||
|
@ -464,6 +421,7 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return s->r_acc;
|
return s->r_acc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) {
|
reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -497,6 +455,8 @@ reg_t kFont(EngineState *s, int argc, reg_t *argv) {
|
||||||
// TODO: Eventually, all of the kBitmap operations should be put
|
// TODO: Eventually, all of the kBitmap operations should be put
|
||||||
// in a separate class
|
// in a separate class
|
||||||
|
|
||||||
|
// NOTE: This size is correct only for SCI2.1mid; the size for
|
||||||
|
// SCI2/2.1early is 36
|
||||||
#define BITMAP_HEADER_SIZE 46
|
#define BITMAP_HEADER_SIZE 46
|
||||||
|
|
||||||
reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
|
reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -673,6 +633,8 @@ reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
|
reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
return kStub(s, argc, argv);
|
||||||
|
#if 0
|
||||||
reg_t plane = argv[0];
|
reg_t plane = argv[0];
|
||||||
Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16());
|
Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16());
|
||||||
Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16());
|
Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16());
|
||||||
|
@ -681,10 +643,15 @@ reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
|
||||||
byte priority = (byte)argv[7].toUint16();
|
byte priority = (byte)argv[7].toUint16();
|
||||||
byte control = (byte)argv[8].toUint16();
|
byte control = (byte)argv[8].toUint16();
|
||||||
// argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
|
// argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
|
||||||
return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control);
|
// return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control);
|
||||||
|
return s->r_acc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) {
|
reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
return kStub(s, argc, argv);
|
||||||
|
|
||||||
|
#if 0
|
||||||
reg_t hunkId = argv[0];
|
reg_t hunkId = argv[0];
|
||||||
reg_t plane = argv[1];
|
reg_t plane = argv[1];
|
||||||
Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16());
|
Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16());
|
||||||
|
@ -694,14 +661,18 @@ reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) {
|
||||||
byte priority = (byte)argv[8].toUint16();
|
byte priority = (byte)argv[8].toUint16();
|
||||||
byte control = (byte)argv[9].toUint16();
|
byte control = (byte)argv[9].toUint16();
|
||||||
// argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
|
// argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
|
||||||
g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control);
|
// g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control);
|
||||||
return s->r_acc;
|
return s->r_acc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
|
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
return kStub(s, argc, argv);
|
||||||
|
#if 0
|
||||||
reg_t hunkId = argv[0];
|
reg_t hunkId = argv[0];
|
||||||
reg_t plane = argv[1];
|
reg_t plane = argv[1];
|
||||||
g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId);
|
// g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId);
|
||||||
return s->r_acc;
|
return s->r_acc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
|
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -730,12 +701,7 @@ reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
|
||||||
// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
|
// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
|
||||||
reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) {
|
reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) {
|
||||||
// TODO: g_sci->_gfxManager->palMorphIsOn = true
|
g_sci->_gfxFrameout->_palMorphIsOn = true;
|
||||||
// This function sets the palMorphIsOn flag which causes kFrameOut to use
|
|
||||||
// an alternative FrameOut function (GraphicsMgr::PalMorphFrameOut instead
|
|
||||||
// of GraphicsMgr::FrameOut). At the end of the frame, kFrameOut sets the
|
|
||||||
// palMorphIsOn flag back to false.
|
|
||||||
kStub(s, argc, argv);
|
|
||||||
return NULL_REG;
|
return NULL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,19 @@ enum {
|
||||||
|
|
||||||
enum infoSelectorFlags {
|
enum infoSelectorFlags {
|
||||||
kInfoFlagClone = 0x0001,
|
kInfoFlagClone = 0x0001,
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
/**
|
||||||
|
* When set, indicates to game scripts that a screen
|
||||||
|
* item can be updated.
|
||||||
|
*/
|
||||||
|
kInfoFlagViewVisible = 0x0008, // TODO: "dirty" ?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set, the object has an associated screen item in
|
||||||
|
* the rendering tree.
|
||||||
|
*/
|
||||||
|
kInfoFlagViewInserted = 0x0010,
|
||||||
|
#endif
|
||||||
kInfoFlagClass = 0x8000
|
kInfoFlagClass = 0x8000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,7 +133,24 @@ public:
|
||||||
_infoSelectorSci3 = info;
|
_infoSelectorSci3 = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No setter for the -info- selector
|
#ifdef ENABLE_SCI32
|
||||||
|
void setInfoSelectorFlag(infoSelectorFlags flag) {
|
||||||
|
if (getSciVersion() < SCI_VERSION_3) {
|
||||||
|
_variables[_offset + 2] |= flag;
|
||||||
|
} else {
|
||||||
|
_infoSelectorSci3 |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: In real engine, -info- is treated as byte size
|
||||||
|
void clearInfoSelectorFlag(infoSelectorFlags flag) {
|
||||||
|
if (getSciVersion() < SCI_VERSION_3) {
|
||||||
|
_variables[_offset + 2] &= ~flag;
|
||||||
|
} else {
|
||||||
|
_infoSelectorSci3 &= ~flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
reg_t getNameSelector() const {
|
reg_t getNameSelector() const {
|
||||||
if (getSciVersion() < SCI_VERSION_3)
|
if (getSciVersion() < SCI_VERSION_3)
|
||||||
|
|
|
@ -187,6 +187,7 @@ void Kernel::mapSelectors() {
|
||||||
FIND_SELECTOR(inLeft);
|
FIND_SELECTOR(inLeft);
|
||||||
FIND_SELECTOR(inBottom);
|
FIND_SELECTOR(inBottom);
|
||||||
FIND_SELECTOR(inRight);
|
FIND_SELECTOR(inRight);
|
||||||
|
FIND_SELECTOR(magnifier);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,8 +212,16 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t
|
||||||
if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
|
if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
|
||||||
error("Selector '%s' of object at %04x:%04x could not be"
|
error("Selector '%s' of object at %04x:%04x could not be"
|
||||||
" written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
|
" written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
|
||||||
else
|
else {
|
||||||
*address.getPointer(segMan) = value;
|
*address.getPointer(segMan) = value;
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
// TODO: Make this correct for all SCI versions
|
||||||
|
// Selectors 26 through 44 are selectors for View script objects
|
||||||
|
if (getSciVersion() >= SCI_VERSION_2 && selectorId >= 26 && selectorId <= 44) {
|
||||||
|
segMan->getObject(object)->setInfoSelectorFlag(kInfoFlagViewVisible);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void invokeSelector(EngineState *s, reg_t object, int selectorId,
|
void invokeSelector(EngineState *s, reg_t object, int selectorId,
|
||||||
|
|
|
@ -153,6 +153,8 @@ struct SelectorCache {
|
||||||
|
|
||||||
Selector useInsetRect;
|
Selector useInsetRect;
|
||||||
Selector inTop, inLeft, inBottom, inRight;
|
Selector inTop, inLeft, inBottom, inRight;
|
||||||
|
|
||||||
|
Selector magnifier;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,20 @@ reg_t reg_t::operator^(const reg_t right) const {
|
||||||
return lookForWorkaround(right, "bitwise XOR");
|
return lookForWorkaround(right, "bitwise XOR");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
reg_t reg_t::operator&(int16 right) const {
|
||||||
|
return *this & make_reg(0, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t reg_t::operator|(int16 right) const {
|
||||||
|
return *this | make_reg(0, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t reg_t::operator^(int16 right) const {
|
||||||
|
return *this ^ make_reg(0, right);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
|
int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
|
||||||
if (getSegment() == right.getSegment()) { // can compare things in the same segment
|
if (getSegment() == right.getSegment()) { // can compare things in the same segment
|
||||||
if (treatAsUnsigned || !isNumber())
|
if (treatAsUnsigned || !isNumber())
|
||||||
|
|
|
@ -136,6 +136,19 @@ struct reg_t {
|
||||||
reg_t operator|(const reg_t right) const;
|
reg_t operator|(const reg_t right) const;
|
||||||
reg_t operator^(const reg_t right) const;
|
reg_t operator^(const reg_t right) const;
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
reg_t operator&(int16 right) const;
|
||||||
|
reg_t operator|(int16 right) const;
|
||||||
|
reg_t operator^(int16 right) const;
|
||||||
|
|
||||||
|
void operator&=(const reg_t &right) { *this = *this & right; }
|
||||||
|
void operator|=(const reg_t &right) { *this = *this | right; }
|
||||||
|
void operator^=(const reg_t &right) { *this = *this ^ right; }
|
||||||
|
void operator&=(int16 right) { *this = *this & right; }
|
||||||
|
void operator|=(int16 right) { *this = *this | right; }
|
||||||
|
void operator^=(int16 right) { *this = *this ^ right; }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Compares two reg_t's.
|
* Compares two reg_t's.
|
||||||
|
|
988
engines/sci/graphics/celobj32.cpp
Normal file
988
engines/sci/graphics/celobj32.cpp
Normal file
|
@ -0,0 +1,988 @@
|
||||||
|
/* 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/resource.h"
|
||||||
|
#include "sci/engine/seg_manager.h"
|
||||||
|
#include "sci/engine/state.h"
|
||||||
|
#include "sci/graphics/celobj32.h"
|
||||||
|
#include "sci/graphics/frameout.h"
|
||||||
|
#include "sci/graphics/palette32.h"
|
||||||
|
#include "sci/graphics/picture.h"
|
||||||
|
#include "sci/graphics/view.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
#pragma mark CelScaler
|
||||||
|
CelScaler *CelObj::_scaler = nullptr;
|
||||||
|
|
||||||
|
void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) {
|
||||||
|
const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
|
||||||
|
const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYSIZE(_scaleTables); ++i) {
|
||||||
|
if (_scaleTables[i].scaleX == scaleX && _scaleTables[i].scaleY == scaleY) {
|
||||||
|
_activeIndex = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 1 - _activeIndex;
|
||||||
|
_activeIndex = i;
|
||||||
|
CelScalerTable &table = _scaleTables[i];
|
||||||
|
|
||||||
|
if (table.scaleX != scaleX) {
|
||||||
|
assert(screenWidth <= ARRAYSIZE(table.valuesX));
|
||||||
|
buildLookupTable(table.valuesX, scaleX, screenWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (table.scaleY != scaleY) {
|
||||||
|
assert(screenHeight <= ARRAYSIZE(table.valuesY));
|
||||||
|
buildLookupTable(table.valuesY, scaleY, screenHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelScaler::buildLookupTable(int *table, const Ratio &ratio, const int size) {
|
||||||
|
int value = 0;
|
||||||
|
int remainder = 0;
|
||||||
|
int num = ratio.getNumerator();
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
*table++ = value;
|
||||||
|
remainder += ratio.getDenominator();
|
||||||
|
if (remainder >= num) {
|
||||||
|
value += remainder / num;
|
||||||
|
remainder %= num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio &scaleY) {
|
||||||
|
activateScaleTables(scaleX, scaleY);
|
||||||
|
return &_scaleTables[_activeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj
|
||||||
|
|
||||||
|
void CelObj::init() {
|
||||||
|
_nextCacheId = 1;
|
||||||
|
delete _scaler;
|
||||||
|
_scaler = new CelScaler();
|
||||||
|
delete _cache;
|
||||||
|
_cache = new CelCache;
|
||||||
|
_cache->resize(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::deinit() {
|
||||||
|
delete _scaler;
|
||||||
|
_scaler = nullptr;
|
||||||
|
delete _cache;
|
||||||
|
_cache = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const {
|
||||||
|
const Buffer &priorityMap = g_sci->_gfxFrameout->getPriorityMap();
|
||||||
|
const Common::Point &scaledPosition = screenItem._scaledPosition;
|
||||||
|
const Ratio &scaleX = screenItem._ratioX;
|
||||||
|
const Ratio &scaleY = screenItem._ratioY;
|
||||||
|
|
||||||
|
if (_remap) {
|
||||||
|
if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
|
||||||
|
const uint8 priority = MAX((uint8)0, MIN((uint8)255, (uint8)screenItem._priority));
|
||||||
|
|
||||||
|
// NOTE: In the original engine code, there was a second branch for
|
||||||
|
// _remap here that would then call the following functions if _remap was false:
|
||||||
|
//
|
||||||
|
// drawHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
// drawNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
// drawUncompHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
// drawUncompNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
// scaleDraw(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
// scaleDrawUncomp(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
|
||||||
|
//
|
||||||
|
// However, obviously, _remap cannot be false here. This dead code branch existed in
|
||||||
|
// at least SCI2/GK1 and SCI2.1/SQ6.
|
||||||
|
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
drawNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
scaleDrawMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
|
||||||
|
// but since we are already in a `_remap` branch, there is no reason to check it
|
||||||
|
// again
|
||||||
|
if (/* TODO: g_Remap_numActiveRemaps */ false) {
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipMap(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipMap(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipMap(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawNoFlipMap(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlip(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlip(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlip(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawNoFlip(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
scaleDraw(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
|
||||||
|
const uint8 priority = MAX((uint8)0, MIN((uint8)255, (uint8)screenItem._priority));
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
drawNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
|
||||||
|
} else {
|
||||||
|
scaleDrawNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_transparent) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipNoMDNoSkip(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipNoMDNoSkip(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawNoFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) {
|
||||||
|
_drawMirrored = mirrorX;
|
||||||
|
draw(target, screenItem, targetRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) {
|
||||||
|
_drawMirrored = mirrorX;
|
||||||
|
Ratio square;
|
||||||
|
drawTo(target, targetRect, scaledPosition, square, square);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::drawTo(Buffer &target, Common::Rect const &targetRect, Common::Point const &scaledPosition, Ratio const &scaleX, Ratio const &scaleY) const {
|
||||||
|
if (_remap) {
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipMap(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipMap(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipMap(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawNoFlipMap(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (scaleX.isOne() && scaleY.isOne()) {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_drawMirrored) {
|
||||||
|
drawHzFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
drawNoFlipNoMD(target, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
} else {
|
||||||
|
scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const {
|
||||||
|
byte *resource = getResPointer();
|
||||||
|
byte *celHeader = resource + _celHeaderOffset;
|
||||||
|
|
||||||
|
if (mirrorX) {
|
||||||
|
x = _width - x - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_compressionType == kCelCompressionNone) {
|
||||||
|
byte *pixels = resource + READ_SCI11ENDIAN_UINT32(celHeader + 24);
|
||||||
|
return pixels[y * _width + x];
|
||||||
|
} else {
|
||||||
|
byte buffer[1024];
|
||||||
|
|
||||||
|
uint32 dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
|
||||||
|
uint32 uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28);
|
||||||
|
uint32 controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32);
|
||||||
|
|
||||||
|
// compressed data segment for row
|
||||||
|
byte *row = resource + dataOffset + READ_SCI11ENDIAN_UINT32(resource + controlOffset + y * 4);
|
||||||
|
|
||||||
|
// uncompressed data segment for row
|
||||||
|
byte *literal = resource + uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(resource + controlOffset + _height * 4 + y * 4);
|
||||||
|
|
||||||
|
uint8 length;
|
||||||
|
byte controlByte;
|
||||||
|
for (uint i = 0; i <= x; i += length) {
|
||||||
|
controlByte = *row++;
|
||||||
|
length = controlByte;
|
||||||
|
|
||||||
|
// Run-length encoded
|
||||||
|
if (controlByte & 0x80) {
|
||||||
|
length &= 0x3F;
|
||||||
|
assert(i + length < sizeof(buffer));
|
||||||
|
|
||||||
|
// Fill with skip color
|
||||||
|
if (controlByte & 0x40) {
|
||||||
|
memset(buffer + i, _transparentColor, length);
|
||||||
|
// Next value is fill colour
|
||||||
|
} else {
|
||||||
|
memset(buffer + i, *literal, length);
|
||||||
|
++literal;
|
||||||
|
}
|
||||||
|
// Uncompressed
|
||||||
|
} else {
|
||||||
|
assert(i + length < sizeof(buffer));
|
||||||
|
memcpy(buffer + i, literal, length);
|
||||||
|
literal += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::submitPalette() const {
|
||||||
|
if (_hunkPaletteOffset) {
|
||||||
|
Palette palette;
|
||||||
|
|
||||||
|
byte *res = getResPointer();
|
||||||
|
// NOTE: In SCI engine this uses HunkPalette::Init.
|
||||||
|
// TODO: Use a better size value
|
||||||
|
g_sci->_gfxPalette32->createFromData(res + _hunkPaletteOffset, 999999, &palette);
|
||||||
|
g_sci->_gfxPalette32->submit(palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj - Caching
|
||||||
|
int CelObj::_nextCacheId = 1;
|
||||||
|
CelCache *CelObj::_cache = nullptr;
|
||||||
|
|
||||||
|
int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const {
|
||||||
|
int oldestId = _nextCacheId + 1;
|
||||||
|
int oldestIndex = -1;
|
||||||
|
|
||||||
|
for (int i = 0, len = _cache->size(); i < len; ++i) {
|
||||||
|
CelCacheEntry &entry = (*_cache)[i];
|
||||||
|
|
||||||
|
if (entry.celObj != nullptr) {
|
||||||
|
if (entry.celObj->_info == celInfo) {
|
||||||
|
entry.id = ++_nextCacheId;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldestId > entry.id) {
|
||||||
|
oldestId = entry.id;
|
||||||
|
oldestIndex = i;
|
||||||
|
}
|
||||||
|
} else if (oldestIndex == -1) {
|
||||||
|
oldestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Unlike the original SCI engine code, the out-param
|
||||||
|
// here is only updated if there was not a cache hit.
|
||||||
|
*nextInsertIndex = oldestIndex;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::putCopyInCache(const int cacheIndex) const {
|
||||||
|
if (cacheIndex == -1) {
|
||||||
|
error("Invalid cache index");
|
||||||
|
}
|
||||||
|
|
||||||
|
CelCacheEntry &entry = (*_cache)[cacheIndex];
|
||||||
|
|
||||||
|
if (entry.celObj != nullptr) {
|
||||||
|
delete entry.celObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.celObj = duplicate();
|
||||||
|
entry.id = ++_nextCacheId;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj - Drawing
|
||||||
|
void dummyFill(Buffer &target, const Common::Rect &targetRect) {
|
||||||
|
target.fillRect(targetRect, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawHzFlip");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawNoFlip");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawUncompNoFlip");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
debug("scaleDrawUncomp");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawHzFlipMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawNoFlipMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawUncompNoFlipMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawUncompHzFlipMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("scaleDrawMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("scaleDrawUncompMap");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawHzFlipNoMD");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
const int sourceX = targetRect.left - scaledPosition.x;
|
||||||
|
const int sourceY = targetRect.top - scaledPosition.y;
|
||||||
|
|
||||||
|
byte *targetPixel = (byte *)target.getPixels() + (targetRect.top * target.screenWidth) + targetRect.left;
|
||||||
|
|
||||||
|
const int stride = target.screenWidth - targetRect.width();
|
||||||
|
|
||||||
|
byte *resource = getResPointer();
|
||||||
|
byte *celHeader = resource + _celHeaderOffset;
|
||||||
|
|
||||||
|
byte buffer[1024];
|
||||||
|
|
||||||
|
uint32 dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
|
||||||
|
uint32 uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28);
|
||||||
|
uint32 controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32);
|
||||||
|
|
||||||
|
for (int y = sourceY; y < sourceY + targetRect.height(); ++y) {
|
||||||
|
// compressed data segment for row
|
||||||
|
byte *row = resource + dataOffset + READ_SCI11ENDIAN_UINT32(resource + controlOffset + y * 4);
|
||||||
|
|
||||||
|
// uncompressed data segment for row
|
||||||
|
byte *literal = resource + uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(resource + controlOffset + _height * 4 + y * 4);
|
||||||
|
|
||||||
|
uint8 length;
|
||||||
|
byte controlByte;
|
||||||
|
for (int i = 0; i <= targetRect.width(); i += length) {
|
||||||
|
controlByte = *row++;
|
||||||
|
length = controlByte;
|
||||||
|
|
||||||
|
// Run-length encoded
|
||||||
|
if (controlByte & 0x80) {
|
||||||
|
length &= 0x3F;
|
||||||
|
assert(i + length < (int)sizeof(buffer));
|
||||||
|
|
||||||
|
// Fill with skip color
|
||||||
|
if (controlByte & 0x40) {
|
||||||
|
memset(buffer + i, _transparentColor, length);
|
||||||
|
// Next value is fill colour
|
||||||
|
} else {
|
||||||
|
memset(buffer + i, *literal, length);
|
||||||
|
++literal;
|
||||||
|
}
|
||||||
|
// Uncompressed
|
||||||
|
} else {
|
||||||
|
assert(i + length < (int)sizeof(buffer));
|
||||||
|
memcpy(buffer + i, literal, length);
|
||||||
|
literal += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < targetRect.width(); ++x) {
|
||||||
|
byte pixel = buffer[sourceX + x];
|
||||||
|
|
||||||
|
if (pixel != _transparentColor) {
|
||||||
|
*targetPixel = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
++targetPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetPixel += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
const int sourceX = targetRect.left - scaledPosition.x;
|
||||||
|
const int sourceY = targetRect.top - scaledPosition.y;
|
||||||
|
|
||||||
|
const int sourceStride = _width - targetRect.width();
|
||||||
|
const int targetStride = target.screenWidth - targetRect.width();
|
||||||
|
const int dataOffset = READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
|
||||||
|
|
||||||
|
byte *sourcePixel = getResPointer() + dataOffset + (sourceY * _width) + sourceX;
|
||||||
|
byte *targetPixel = (byte *)target.getPixels() + targetRect.top * target.screenWidth + targetRect.left;
|
||||||
|
|
||||||
|
for (int y = 0; y < targetRect.height(); ++y) {
|
||||||
|
for (int x = 0; x < targetRect.width(); ++x) {
|
||||||
|
byte pixel = *sourcePixel++;
|
||||||
|
|
||||||
|
if (pixel != _transparentColor) {
|
||||||
|
*targetPixel = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
++targetPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcePixel += sourceStride;
|
||||||
|
targetPixel += targetStride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
const int sourceX = targetRect.left - scaledPosition.x;
|
||||||
|
const int sourceY = targetRect.top - scaledPosition.y;
|
||||||
|
const int dataOffset = READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
|
||||||
|
|
||||||
|
byte *sourcePixel = getResPointer() + dataOffset + (sourceY * _width) + sourceX;
|
||||||
|
|
||||||
|
target.copyRectToSurface(sourcePixel, _width, targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
|
||||||
|
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawUncompHzFlipNoMD");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("drawUncompHzFlipNoMDNoSkip");
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObj::scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("scaleDrawNoMD %d/%d, %d/%d", scaleX.getNumerator(), scaleX.getDenominator(), scaleY.getNumerator(), scaleY.getDenominator());
|
||||||
|
dummyFill(target, targetRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
|
||||||
|
debug("scaleDrawUncompNoMD %d/%d, %d/%d", scaleX.getNumerator(), scaleX.getDenominator(), scaleY.getNumerator(), scaleY.getDenominator());
|
||||||
|
if (targetRect.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CelScalerTable *table = _scaler->getScalerTable(scaleX, scaleY);
|
||||||
|
|
||||||
|
int pixelX[1024];
|
||||||
|
int pixelY[1024];
|
||||||
|
|
||||||
|
bool use2xOptimisedDrawRoutine = false /* TODO: scaleX.getDenominator() * 2 == scaleX.getNumerator() */;
|
||||||
|
|
||||||
|
int16 sourceX = (scaledPosition.x * scaleX.getInverse()).toInt();
|
||||||
|
int16 sourceY = (scaledPosition.y * scaleY.getInverse()).toInt();
|
||||||
|
|
||||||
|
if (_drawMirrored) {
|
||||||
|
for (int x = targetRect.left; x < targetRect.right; ++x) {
|
||||||
|
pixelX[x] = _width - 1 - (table->valuesX[x] - sourceX);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int x = targetRect.left; x < targetRect.right; ++x) {
|
||||||
|
pixelX[x] = table->valuesX[x] - sourceX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = targetRect.top; y < targetRect.bottom; ++y) {
|
||||||
|
pixelY[y] = table->valuesY[y] - sourceY;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *sourcePixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
|
||||||
|
|
||||||
|
for (int y = targetRect.top; y < targetRect.bottom; ++y) {
|
||||||
|
byte *targetPixel = target.getAddress(targetRect.left, y);
|
||||||
|
byte *sourcePixel = sourcePixels + pixelY[y] * _width;
|
||||||
|
const int *sourcePixelIndex = pixelX + targetRect.left;
|
||||||
|
|
||||||
|
if (/* TODO */ use2xOptimisedDrawRoutine) {
|
||||||
|
// WriteUncompScaleLine2();
|
||||||
|
} else {
|
||||||
|
// start WriteUncompScaleLine
|
||||||
|
for (int x = targetRect.left; x < targetRect.right; ++x) {
|
||||||
|
byte value = sourcePixel[*sourcePixelIndex++];
|
||||||
|
if (value != _transparentColor) {
|
||||||
|
*targetPixel = value;
|
||||||
|
}
|
||||||
|
++targetPixel;
|
||||||
|
}
|
||||||
|
// end WriteUncompScaleLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: These functions may all be vestigial.
|
||||||
|
void CelObj::drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
void CelObj::scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjView
|
||||||
|
CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
|
||||||
|
_info.type = kCelTypeView;
|
||||||
|
_info.resourceId = viewId;
|
||||||
|
_info.loopNo = loopNo;
|
||||||
|
_info.celNo = celNo;
|
||||||
|
_mirrorX = false;
|
||||||
|
_compressionType = kCelCompressionInvalid;
|
||||||
|
_transparent = true;
|
||||||
|
|
||||||
|
int cacheInsertIndex;
|
||||||
|
int cacheIndex = searchCache(_info, &cacheInsertIndex);
|
||||||
|
if (cacheIndex != -1) {
|
||||||
|
CelCacheEntry &entry = (*_cache)[cacheIndex];
|
||||||
|
*this = *dynamic_cast<CelObjView *>(entry.celObj);
|
||||||
|
entry.id = ++_nextCacheId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The next code should be moved to a common file that
|
||||||
|
// generates view resource metadata for both SCI16 and SCI32
|
||||||
|
// implementations
|
||||||
|
|
||||||
|
Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
|
||||||
|
|
||||||
|
// NOTE: SCI2.1/SQ6 just silently returns here.
|
||||||
|
if (!resource) {
|
||||||
|
warning("View resource %d not loaded", viewId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *data = resource->data;
|
||||||
|
|
||||||
|
_scaledWidth = READ_SCI11ENDIAN_UINT16(data + 14);
|
||||||
|
_scaledHeight = READ_SCI11ENDIAN_UINT16(data + 16);
|
||||||
|
|
||||||
|
if (_scaledWidth == 0 || _scaledHeight == 0) {
|
||||||
|
byte sizeFlag = data[5];
|
||||||
|
if (sizeFlag == 0) {
|
||||||
|
_scaledWidth = 320;
|
||||||
|
_scaledHeight = 200;
|
||||||
|
} else if (sizeFlag == 1) {
|
||||||
|
_scaledWidth = 640;
|
||||||
|
_scaledHeight = 480;
|
||||||
|
} else if (sizeFlag == 2) {
|
||||||
|
_scaledWidth = 640;
|
||||||
|
_scaledHeight = 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 loopCount = data[2];
|
||||||
|
if (_info.loopNo >= loopCount) {
|
||||||
|
_info.loopNo = loopCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This is the actual check, in the actual location,
|
||||||
|
// from SCI engine.
|
||||||
|
if (loopNo < 0) {
|
||||||
|
error("Loop is less than 0!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data);
|
||||||
|
const uint8 loopHeaderSize = data[12];
|
||||||
|
const uint8 viewHeaderFieldSize = 2;
|
||||||
|
|
||||||
|
byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo);
|
||||||
|
|
||||||
|
if ((int8)loopHeader[0] != -1) {
|
||||||
|
if (loopHeader[1] == 1) {
|
||||||
|
_mirrorX = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 celCount = loopHeader[2];
|
||||||
|
if (_info.celNo >= celCount) {
|
||||||
|
_info.celNo = celCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8);
|
||||||
|
_celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo);
|
||||||
|
|
||||||
|
byte *celHeader = data + _celHeaderOffset;
|
||||||
|
|
||||||
|
_width = READ_SCI11ENDIAN_UINT16(celHeader);
|
||||||
|
_height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
|
||||||
|
_displace.x = _width / 2 - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
|
||||||
|
_displace.y = _height - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6) - 1;
|
||||||
|
_transparentColor = celHeader[8];
|
||||||
|
_compressionType = (CelCompressionType)celHeader[9];
|
||||||
|
|
||||||
|
if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) {
|
||||||
|
error("Compression type not supported - V: %d L: %d C: %d", _info.resourceId, _info.loopNo, _info.celNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (celHeader[10] & 128) {
|
||||||
|
// NOTE: This is correct according to SCI2.1/SQ6/DOS;
|
||||||
|
// the engine re-reads the byte value as a word value
|
||||||
|
uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
|
||||||
|
_transparent = flags & 1 ? true : false;
|
||||||
|
_remap = flags & 2 ? true : false;
|
||||||
|
} else if (_compressionType == kCelCompressionNone) {
|
||||||
|
_remap = analyzeUncompressedForRemap();
|
||||||
|
} else {
|
||||||
|
_remap = analyzeForRemap();
|
||||||
|
}
|
||||||
|
|
||||||
|
putCopyInCache(cacheInsertIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CelObjView::analyzeUncompressedForRemap() const {
|
||||||
|
byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
|
||||||
|
for (int i = 0; i < _width * _height; ++i) {
|
||||||
|
uint8 pixel = pixels[i];
|
||||||
|
if (/* TODO: pixel >= Remap::minRemapColor && pixel <= Remap::maxRemapColor */ false && pixel != _transparentColor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CelObjView::analyzeForRemap() const {
|
||||||
|
// TODO: Implement decompression and analysis
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObjView::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY) {
|
||||||
|
_drawMirrored = mirrorX;
|
||||||
|
drawTo(target, targetRect, scaledPosition, scaleX, scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObjView *CelObjView::duplicate() const {
|
||||||
|
return new CelObjView(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *CelObjView::getResPointer() const {
|
||||||
|
return g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false)->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjPic
|
||||||
|
CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
|
||||||
|
_info.type = kCelTypePic;
|
||||||
|
_info.resourceId = picId;
|
||||||
|
_info.loopNo = 0;
|
||||||
|
_info.celNo = celNo;
|
||||||
|
_mirrorX = false;
|
||||||
|
_compressionType = kCelCompressionInvalid;
|
||||||
|
_transparent = true;
|
||||||
|
_remap = false;
|
||||||
|
|
||||||
|
int cacheInsertIndex;
|
||||||
|
int cacheIndex = searchCache(_info, &cacheInsertIndex);
|
||||||
|
if (cacheIndex != -1) {
|
||||||
|
CelCacheEntry &entry = (*_cache)[cacheIndex];
|
||||||
|
*this = *dynamic_cast<CelObjPic *>(entry.celObj);
|
||||||
|
entry.id = ++_nextCacheId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, picId), false);
|
||||||
|
|
||||||
|
// NOTE: SCI2.1/SQ6 just silently returns here.
|
||||||
|
if (!resource) {
|
||||||
|
warning("Pic resource %d not loaded", picId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *data = resource->data;
|
||||||
|
|
||||||
|
_celCount = data[2];
|
||||||
|
|
||||||
|
if (_info.celNo >= _celCount) {
|
||||||
|
error("Cel number %d greater than cel count %d", _info.celNo, _celCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
_celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo);
|
||||||
|
_hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6);
|
||||||
|
|
||||||
|
byte *celHeader = data + _celHeaderOffset;
|
||||||
|
|
||||||
|
_width = READ_SCI11ENDIAN_UINT16(celHeader);
|
||||||
|
_height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
|
||||||
|
_displace.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
|
||||||
|
_displace.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6);
|
||||||
|
_transparentColor = celHeader[8];
|
||||||
|
_compressionType = (CelCompressionType)celHeader[9];
|
||||||
|
_priority = READ_SCI11ENDIAN_UINT16(celHeader + 36);
|
||||||
|
_relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38);
|
||||||
|
_relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40);
|
||||||
|
|
||||||
|
uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10);
|
||||||
|
uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12);
|
||||||
|
|
||||||
|
if (sizeFlag2) {
|
||||||
|
_scaledWidth = sizeFlag1;
|
||||||
|
_scaledHeight = sizeFlag2;
|
||||||
|
} else if (sizeFlag1 == 0) {
|
||||||
|
_scaledWidth = 320;
|
||||||
|
_scaledHeight = 200;
|
||||||
|
} else if (sizeFlag1 == 1) {
|
||||||
|
_scaledWidth = 640;
|
||||||
|
_scaledHeight = 480;
|
||||||
|
} else if (sizeFlag1 == 2) {
|
||||||
|
_scaledWidth = 640;
|
||||||
|
_scaledHeight = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (celHeader[10] & 128) {
|
||||||
|
// NOTE: This is correct according to SCI2.1/SQ6/DOS;
|
||||||
|
// the engine re-reads the byte value as a word value
|
||||||
|
uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
|
||||||
|
_transparent = flags & 1 ? true : false;
|
||||||
|
_remap = flags & 2 ? true : false;
|
||||||
|
} else {
|
||||||
|
_transparent = _compressionType != kCelCompressionNone ? true : analyzeUncompressedForSkip();
|
||||||
|
|
||||||
|
if (_compressionType != kCelCompressionNone && _compressionType != kCelCompressionRLE) {
|
||||||
|
error("Compression type not supported - P: %d C: %d", picId, celNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putCopyInCache(cacheInsertIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CelObjPic::analyzeUncompressedForSkip() const {
|
||||||
|
byte *resource = getResPointer();
|
||||||
|
byte *pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24);
|
||||||
|
for (int i = 0; i < _width * _height; ++i) {
|
||||||
|
uint8 pixel = pixels[i];
|
||||||
|
if (pixel == _transparentColor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObjPic::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) {
|
||||||
|
Ratio square;
|
||||||
|
_drawMirrored = mirrorX;
|
||||||
|
drawTo(target, targetRect, scaledPosition, square, square);
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObjPic *CelObjPic::duplicate() const {
|
||||||
|
return new CelObjPic(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *CelObjPic::getResPointer() const {
|
||||||
|
return g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false)->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjMem
|
||||||
|
CelObjMem::CelObjMem(const reg_t bitmap) {
|
||||||
|
_info.type = kCelTypeMem;
|
||||||
|
_info.bitmap = bitmap;
|
||||||
|
_mirrorX = false;
|
||||||
|
_compressionType = kCelCompressionNone;
|
||||||
|
_celHeaderOffset = 0;
|
||||||
|
_transparent = true;
|
||||||
|
|
||||||
|
byte *bitmapData = g_sci->getEngineState()->_segMan->getHunkPointer(bitmap);
|
||||||
|
if (bitmapData == nullptr || READ_SCI11ENDIAN_UINT32(bitmapData + 28) != 46) {
|
||||||
|
error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
_width = READ_SCI11ENDIAN_UINT16(bitmapData);
|
||||||
|
_height = READ_SCI11ENDIAN_UINT16(bitmapData + 2);
|
||||||
|
_displace.x = READ_SCI11ENDIAN_UINT16(bitmapData + 4);
|
||||||
|
_displace.y = READ_SCI11ENDIAN_UINT16(bitmapData + 6);
|
||||||
|
_transparentColor = bitmapData[8];
|
||||||
|
_scaledWidth = READ_SCI11ENDIAN_UINT16(bitmapData + 36);
|
||||||
|
_scaledHeight = READ_SCI11ENDIAN_UINT16(bitmapData + 38);
|
||||||
|
_hunkPaletteOffset = READ_SCI11ENDIAN_UINT16(bitmapData + 20);
|
||||||
|
_remap = (READ_SCI11ENDIAN_UINT16(bitmapData + 10) & 2) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObjMem *CelObjMem::duplicate() const {
|
||||||
|
return new CelObjMem(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *CelObjMem::getResPointer() const {
|
||||||
|
return g_sci->getEngineState()->_segMan->getHunkPointer(_info.bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjColor
|
||||||
|
CelObjColor::CelObjColor(const uint8 color, const int16 width, const int16 height) {
|
||||||
|
_info.type = kCelTypeColor;
|
||||||
|
_info.color = color;
|
||||||
|
_displace.x = 0;
|
||||||
|
_displace.y = 0;
|
||||||
|
_scaledWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
||||||
|
_scaledHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
||||||
|
_hunkPaletteOffset = 0;
|
||||||
|
_mirrorX = false;
|
||||||
|
_remap = false;
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CelObjColor::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) {
|
||||||
|
// TODO: The original engine sets this flag but why? One cannot
|
||||||
|
// draw a solid colour mirrored.
|
||||||
|
_drawMirrored = mirrorX;
|
||||||
|
draw(target, targetRect);
|
||||||
|
}
|
||||||
|
void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX) {
|
||||||
|
error("Unsupported method");
|
||||||
|
}
|
||||||
|
void CelObjColor::draw(Buffer &target, const Common::Rect &targetRect) const {
|
||||||
|
target.fillRect(targetRect, _info.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObjColor *CelObjColor::duplicate() const {
|
||||||
|
return new CelObjColor(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *CelObjColor::getResPointer() const {
|
||||||
|
error("Unsupported method");
|
||||||
|
}
|
||||||
|
}
|
577
engines/sci/graphics/celobj32.h
Normal file
577
engines/sci/graphics/celobj32.h
Normal file
|
@ -0,0 +1,577 @@
|
||||||
|
/* 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_CELOBJ32_H
|
||||||
|
#define SCI_GRAPHICS_CELOBJ32_H
|
||||||
|
|
||||||
|
#include "common/rational.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "sci/resource.h"
|
||||||
|
#include "sci/engine/vm_types.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
typedef Common::Rational Ratio;
|
||||||
|
|
||||||
|
enum CelType {
|
||||||
|
kCelTypeView = 0,
|
||||||
|
kCelTypePic = 1,
|
||||||
|
kCelTypeMem = 2,
|
||||||
|
kCelTypeColor = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CelCompressionType {
|
||||||
|
kCelCompressionNone = 0,
|
||||||
|
kCelCompressionRLE = 138,
|
||||||
|
kCelCompressionInvalid = 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CelInfo32 object describes the basic properties of a
|
||||||
|
* cel object.
|
||||||
|
*/
|
||||||
|
struct CelInfo32 {
|
||||||
|
/**
|
||||||
|
* The type of the cel object.
|
||||||
|
*/
|
||||||
|
CelType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For cel objects that draw from resources, the ID of
|
||||||
|
* the resource to load.
|
||||||
|
*/
|
||||||
|
GuiResourceId resourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For CelObjView, the loop number to draw from the
|
||||||
|
* view resource.
|
||||||
|
*/
|
||||||
|
int16 loopNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For CelObjView and CelObjPic, the cel number to draw
|
||||||
|
* from the view or pic resource.
|
||||||
|
*/
|
||||||
|
int16 celNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For CelObjMem, a segment register pointing to a heap
|
||||||
|
* resource containing headered bitmap data.
|
||||||
|
*/
|
||||||
|
reg_t bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For CelObjColor, the fill colour.
|
||||||
|
*/
|
||||||
|
uint8 color;
|
||||||
|
|
||||||
|
// NOTE: In at least SCI2.1/SQ6, color is left
|
||||||
|
// uninitialised.
|
||||||
|
CelInfo32() :
|
||||||
|
type(kCelTypeMem),
|
||||||
|
resourceId(0),
|
||||||
|
loopNo(0),
|
||||||
|
celNo(0),
|
||||||
|
bitmap(NULL_REG) {}
|
||||||
|
|
||||||
|
// NOTE: This is the equivalence criteria used by
|
||||||
|
// CelObj::searchCache in at least SCI2.1/SQ6. Notably,
|
||||||
|
// it does not check the color field.
|
||||||
|
inline bool operator==(const CelInfo32 &other) {
|
||||||
|
return (
|
||||||
|
type == other.type &&
|
||||||
|
resourceId == other.resourceId &&
|
||||||
|
loopNo == other.loopNo &&
|
||||||
|
celNo == other.celNo &&
|
||||||
|
bitmap == other.bitmap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CelObj;
|
||||||
|
struct CelCacheEntry {
|
||||||
|
/**
|
||||||
|
* A monotonically increasing cache ID used to identify
|
||||||
|
* the least recently used item in the cache for
|
||||||
|
* replacement.
|
||||||
|
*/
|
||||||
|
int id;
|
||||||
|
CelObj *celObj;
|
||||||
|
CelCacheEntry() : id(0), celObj(nullptr) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Common::Array<CelCacheEntry> CelCache;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelScaler
|
||||||
|
|
||||||
|
struct CelScalerTable {
|
||||||
|
/**
|
||||||
|
* A lookup table of indexes that should be used to find
|
||||||
|
* the correct column to read from the source bitmap
|
||||||
|
* when drawing a scaled version of the source bitmap.
|
||||||
|
*/
|
||||||
|
int valuesX[1024];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ratio used to generate the x-values.
|
||||||
|
*/
|
||||||
|
Ratio scaleX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lookup table of indexes that should be used to find
|
||||||
|
* the correct row to read from a source bitmap when
|
||||||
|
* drawing a scaled version of the source bitmap.
|
||||||
|
*/
|
||||||
|
int valuesY[1024];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ratio used to generate the y-values.
|
||||||
|
*/
|
||||||
|
Ratio scaleY;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CelScaler {
|
||||||
|
/**
|
||||||
|
* Cached scale tables.
|
||||||
|
*/
|
||||||
|
CelScalerTable _scaleTables[2];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the most recently used scale table.
|
||||||
|
*/
|
||||||
|
int _activeIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates a scale table for the given X and Y ratios.
|
||||||
|
* If there is no table that matches the given ratios,
|
||||||
|
* the least most recently used table will be replaced
|
||||||
|
* and activated.
|
||||||
|
*/
|
||||||
|
void activateScaleTables(const Ratio &scaleX, const Ratio &scaleY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a pixel lookup table in `table` for the given
|
||||||
|
* ratio. The table will be filled up to the specified
|
||||||
|
* size, which should be large enough to draw across the
|
||||||
|
* entire target buffer.
|
||||||
|
*/
|
||||||
|
void buildLookupTable(int *table, const Ratio &ratio, const int size);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CelScaler() :
|
||||||
|
_scaleTables(),
|
||||||
|
_activeIndex(0) {
|
||||||
|
CelScalerTable &table = _scaleTables[_activeIndex];
|
||||||
|
table.scaleX = Ratio();
|
||||||
|
table.scaleY = Ratio();
|
||||||
|
for (int i = 0; i < ARRAYSIZE(table.valuesX); ++i) {
|
||||||
|
table.valuesX[i] = i;
|
||||||
|
table.valuesY[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves scaler tables for the given X and Y ratios.
|
||||||
|
*/
|
||||||
|
const CelScalerTable *getScalerTable(const Ratio &scaleX, const Ratio &scaleY);
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj
|
||||||
|
|
||||||
|
class ScreenItem;
|
||||||
|
/**
|
||||||
|
* A cel object is the lowest-level rendering primitive in
|
||||||
|
* the SCI engine and draws itself directly to a target
|
||||||
|
* pixel buffer.
|
||||||
|
*/
|
||||||
|
class CelObj {
|
||||||
|
private:
|
||||||
|
static CelScaler *_scaler;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* When true, this cel will be horizontally mirrored
|
||||||
|
* when it is drawn. This is an internal flag that is
|
||||||
|
* set by draw methods based on the combination of the
|
||||||
|
* cel's `_mirrorX` property and the owner screen item's
|
||||||
|
* `_mirrorX` property.
|
||||||
|
*/
|
||||||
|
bool _drawMirrored;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The basic identifying information for this cel. This
|
||||||
|
* information effectively acts as a composite key for
|
||||||
|
* a cel object, and any cel object can be recreated
|
||||||
|
* from this data alone.
|
||||||
|
*/
|
||||||
|
CelInfo32 _info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset to the cel header for this cel within the
|
||||||
|
* raw resource data.
|
||||||
|
*/
|
||||||
|
uint32 _celHeaderOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset to the embedded palette for this cel
|
||||||
|
* within the raw resource data.
|
||||||
|
*/
|
||||||
|
uint32 _hunkPaletteOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The natural dimensions of the cel.
|
||||||
|
*/
|
||||||
|
uint16 _width, _height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
Common::Point _displace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimensions of the original coordinate system for
|
||||||
|
* the cel. Used to scale cels from their native size
|
||||||
|
* to the correct size on screen.
|
||||||
|
*
|
||||||
|
* @note This is set to scriptWidth/Height for
|
||||||
|
* CelObjColor. For other cel objects, the value comes
|
||||||
|
* from the raw resource data. For text bitmaps, this is
|
||||||
|
* the width/height of the coordinate system used to
|
||||||
|
* generate the text, which also defaults to
|
||||||
|
* scriptWidth/Height but seems to typically be changed
|
||||||
|
* to more closely match the native screen resolution.
|
||||||
|
*/
|
||||||
|
uint16 _scaledWidth, _scaledHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The skip (transparent) colour for the cel. When
|
||||||
|
* compositing, any pixels matching this colour will not
|
||||||
|
* be copied to the buffer.
|
||||||
|
*/
|
||||||
|
uint8 _transparentColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this cel has any transparent regions.
|
||||||
|
* This is used for optimised drawing of non-transparent
|
||||||
|
* cels.
|
||||||
|
*/
|
||||||
|
bool _transparent; // TODO: probably "skip"?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The compression type for the pixel data for this cel.
|
||||||
|
*/
|
||||||
|
CelCompressionType _compressionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this cel should be palette-remapped?
|
||||||
|
*/
|
||||||
|
bool _remap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the cel contains pre-mirrored picture data.
|
||||||
|
* This value comes directly from the resource data and
|
||||||
|
* is XORed with the `_mirrorX` property of the owner
|
||||||
|
* screen item when rendering.
|
||||||
|
*/
|
||||||
|
bool _mirrorX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises static CelObj members.
|
||||||
|
*/
|
||||||
|
static void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees static CelObj members.
|
||||||
|
*/
|
||||||
|
static void deinit();
|
||||||
|
|
||||||
|
virtual ~CelObj() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the cel to the target buffer using the priority
|
||||||
|
* and positioning information from the given screen
|
||||||
|
* item. The mirroring of the cel will be unchanged from
|
||||||
|
* any previous call to draw.
|
||||||
|
*/
|
||||||
|
void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the cel to the target buffer using the priority
|
||||||
|
* and positioning information from the given screen
|
||||||
|
* item and the given mirror flag.
|
||||||
|
*
|
||||||
|
* @note In SCI engine, this function was a virtual
|
||||||
|
* function, but CelObjView, CelObjPic, and CelObjMem
|
||||||
|
* all used the same function and the compiler
|
||||||
|
* deduplicated the copies; we deduplicate the source by
|
||||||
|
* putting the implementation on CelObj instead of
|
||||||
|
* copying it to 3/4 of the subclasses.
|
||||||
|
*/
|
||||||
|
virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the cel to the target buffer using the
|
||||||
|
* positioning and mirroring information from the
|
||||||
|
* provided arguments.
|
||||||
|
*
|
||||||
|
* @note In SCI engine, this function was a virtual
|
||||||
|
* function, but CelObjView, CelObjPic, and CelObjMem
|
||||||
|
* all used the same function and the compiler
|
||||||
|
* deduplicated the copies; we deduplicate the source by
|
||||||
|
* putting the implementation on CelObj instead of
|
||||||
|
* copying it to 3/4 of the subclasses.
|
||||||
|
*/
|
||||||
|
virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the cel to the target buffer using the given
|
||||||
|
* position and scaling parameters. The mirroring of the
|
||||||
|
* cel will be unchanged from any previous call to draw.
|
||||||
|
*/
|
||||||
|
void drawTo(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of this cel on the free store and
|
||||||
|
* returns a pointer to the new object. The new cel will
|
||||||
|
* point to a shared copy of bitmap/resource data.
|
||||||
|
*/
|
||||||
|
virtual CelObj *duplicate() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a pointer to the raw resource data for this
|
||||||
|
* cel. This method cannot be used with a CelObjColor.
|
||||||
|
*/
|
||||||
|
virtual byte *getResPointer() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the pixel at the given coordinates. This method
|
||||||
|
* is valid only for CelObjView and CelObjPic.
|
||||||
|
*/
|
||||||
|
inline uint8 readPixel(uint16 x, uint16 y, bool mirrorX) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the palette from this cel to the palette
|
||||||
|
* manager for integration into the master screen
|
||||||
|
* palette.
|
||||||
|
*/
|
||||||
|
void submitPalette() const;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj - Drawing
|
||||||
|
private:
|
||||||
|
void drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
|
||||||
|
void drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
void scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObj - Caching
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* A monotonically increasing cache ID used to identify
|
||||||
|
* the least recently used item in the cache for
|
||||||
|
* replacement.
|
||||||
|
*/
|
||||||
|
static int _nextCacheId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache of cel objects used to avoid reinitialisation
|
||||||
|
* overhead for cels with the same CelInfo32.
|
||||||
|
*/
|
||||||
|
// NOTE: At least SQ6 uses a fixed cache size of 100.
|
||||||
|
static CelCache *_cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the cel cache for a CelObj matching the
|
||||||
|
* provided CelInfo32. If not found, -1 is returned.
|
||||||
|
* nextInsertIndex will receive the index of the oldest
|
||||||
|
* item in the cache, which can be used to replace
|
||||||
|
* the oldest item with a newer item.
|
||||||
|
*/
|
||||||
|
int searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a copy of this CelObj into the cache at the
|
||||||
|
* given cache index.
|
||||||
|
*/
|
||||||
|
void putCopyInCache(int index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CelObjView is the drawing primitive for a View type
|
||||||
|
* resource. Each CelObjView corresponds to a single cel
|
||||||
|
* within a single loop of a view.
|
||||||
|
*/
|
||||||
|
class CelObjView : public CelObj {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Analyses resources without baked-in remap flags
|
||||||
|
* to determine whether or not they should be remapped.
|
||||||
|
*/
|
||||||
|
bool analyzeUncompressedForRemap() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyses compressed resources without baked-in remap
|
||||||
|
* flags to determine whether or not they should be
|
||||||
|
* remapped.
|
||||||
|
*/
|
||||||
|
bool analyzeForRemap() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CelObjView(GuiResourceId viewId, int16 loopNo, int16 celNo);
|
||||||
|
virtual ~CelObjView() override {};
|
||||||
|
|
||||||
|
using CelObj::draw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the cel to the target buffer using the
|
||||||
|
* positioning, mirroring, and scaling information from
|
||||||
|
* the provided arguments.
|
||||||
|
*/
|
||||||
|
void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY);
|
||||||
|
|
||||||
|
virtual CelObjView *duplicate() const override;
|
||||||
|
virtual byte *getResPointer() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjPic
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CelObjPic is the drawing primitive for a Picture type
|
||||||
|
* resource. Each CelObjPic corresponds to a single cel
|
||||||
|
* within a picture.
|
||||||
|
*/
|
||||||
|
class CelObjPic : public CelObj {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Analyses uncompressed resources without baked-in skip
|
||||||
|
* flags to determine whether or not they can use fast
|
||||||
|
* blitting.
|
||||||
|
*/
|
||||||
|
bool analyzeUncompressedForSkip() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The number of cels in the original picture resource.
|
||||||
|
*/
|
||||||
|
uint8 _celCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position of this cel relative to the top-left
|
||||||
|
* corner of the picture.
|
||||||
|
*/
|
||||||
|
Common::Point _relativePosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The z-buffer priority for this cel. Higher prorities
|
||||||
|
* are drawn on top of lower priorities.
|
||||||
|
*/
|
||||||
|
int16 _priority;
|
||||||
|
|
||||||
|
CelObjPic(GuiResourceId pictureId, int16 celNo);
|
||||||
|
virtual ~CelObjPic() override {};
|
||||||
|
|
||||||
|
using CelObj::draw;
|
||||||
|
virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override;
|
||||||
|
|
||||||
|
virtual CelObjPic *duplicate() const override;
|
||||||
|
virtual byte *getResPointer() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjMem
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CelObjMem is the drawing primitive for arbitrary
|
||||||
|
* bitmaps generated in memory. Generated bitmaps in SCI32
|
||||||
|
* include text & vector drawings and per-pixel screen
|
||||||
|
* transitions like dissolves.
|
||||||
|
*/
|
||||||
|
class CelObjMem : public CelObj {
|
||||||
|
public:
|
||||||
|
CelObjMem(reg_t bitmap);
|
||||||
|
virtual ~CelObjMem() override {};
|
||||||
|
|
||||||
|
virtual CelObjMem *duplicate() const override;
|
||||||
|
virtual byte *getResPointer() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CelObjColor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CelObjColor is the drawing primitive for fast,
|
||||||
|
* low-memory, flat colour fills.
|
||||||
|
*/
|
||||||
|
class CelObjColor : public CelObj {
|
||||||
|
public:
|
||||||
|
CelObjColor(uint8 color, int16 width, int16 height);
|
||||||
|
virtual ~CelObjColor() override {};
|
||||||
|
|
||||||
|
using CelObj::draw;
|
||||||
|
/**
|
||||||
|
* Block fills the target buffer with the cel colour.
|
||||||
|
*/
|
||||||
|
void draw(Buffer &target, const Common::Rect &targetRect) const;
|
||||||
|
virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) override;
|
||||||
|
virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX) override;
|
||||||
|
|
||||||
|
virtual CelObjColor *duplicate() const override;
|
||||||
|
virtual byte *getResPointer() const override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -23,85 +23,189 @@
|
||||||
#ifndef SCI_GRAPHICS_FRAMEOUT_H
|
#ifndef SCI_GRAPHICS_FRAMEOUT_H
|
||||||
#define SCI_GRAPHICS_FRAMEOUT_H
|
#define SCI_GRAPHICS_FRAMEOUT_H
|
||||||
|
|
||||||
|
#include "sci/graphics/plane32.h"
|
||||||
|
#include "sci/graphics/screen_item32.h"
|
||||||
|
|
||||||
namespace Sci {
|
namespace Sci {
|
||||||
|
// TODO: Don't do this this way
|
||||||
|
int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]);
|
||||||
|
|
||||||
class GfxPicture;
|
// TODO: Verify display styles and adjust names appropriately for
|
||||||
|
// types 1 through 12 & 15 (others are correct)
|
||||||
struct PlaneLineEntry {
|
// Names should be:
|
||||||
reg_t hunkId;
|
// * VShutterIn, VShutterOut
|
||||||
Common::Point startPoint;
|
// * HShutterIn, HShutterOut
|
||||||
Common::Point endPoint;
|
// * WipeLeft, WipeRight, WipeDown, WipeUp
|
||||||
byte color;
|
// * PixelDissolve
|
||||||
byte priority;
|
// * ShutDown and Kill? (and Plain and Fade?)
|
||||||
byte control;
|
enum ShowStyleType /* : uint8 */ {
|
||||||
|
kShowStyleNone = 0,
|
||||||
|
kShowStyleHShutterOut = 1,
|
||||||
|
kShowStyleHShutterIn = 2,
|
||||||
|
kShowStyleVShutterOut = 3,
|
||||||
|
kShowStyleVShutterIn = 4,
|
||||||
|
kShowStyleWipeLeft = 5,
|
||||||
|
kShowStyleWipeRight = 6,
|
||||||
|
kShowStyleWipeUp = 7,
|
||||||
|
kShowStyleWipeDown = 8,
|
||||||
|
kShowStyleIrisOut = 9,
|
||||||
|
kShowStyleIrisIn = 10,
|
||||||
|
kShowStyle11 = 11,
|
||||||
|
kShowStyle12 = 12,
|
||||||
|
kShowStyleFadeOut = 13,
|
||||||
|
kShowStyleFadeIn = 14,
|
||||||
|
// TODO: Only in SCI3
|
||||||
|
kShowStyleUnknown = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Common::List<PlaneLineEntry> PlaneLineList;
|
/**
|
||||||
|
* Show styles represent transitions applied to draw planes.
|
||||||
|
* One show style per plane can be active at a time.
|
||||||
|
*/
|
||||||
|
struct ShowStyleEntry {
|
||||||
|
/**
|
||||||
|
* The ID of the plane this show style belongs to.
|
||||||
|
* In SCI2.1mid (at least SQ6), per-plane transitions
|
||||||
|
* were removed and a single plane ID is used.
|
||||||
|
*/
|
||||||
|
reg_t plane;
|
||||||
|
|
||||||
struct PlaneEntry {
|
/**
|
||||||
reg_t object;
|
* The type of the transition.
|
||||||
int16 priority;
|
*/
|
||||||
int16 lastPriority;
|
ShowStyleType type;
|
||||||
int16 planeOffsetX;
|
|
||||||
int16 planeOffsetY;
|
// TODO: This name is probably incorrect
|
||||||
GuiResourceId pictureId;
|
bool fadeUp;
|
||||||
Common::Rect planeRect;
|
|
||||||
Common::Rect planeClipRect;
|
/**
|
||||||
Common::Rect upscaledPlaneRect;
|
* The number of steps for the show style.
|
||||||
Common::Rect upscaledPlaneClipRect;
|
*/
|
||||||
bool planePictureMirrored;
|
int16 divisions;
|
||||||
byte planeBack;
|
|
||||||
PlaneLineList lines;
|
// NOTE: This property exists from SCI2 through at least
|
||||||
|
// SCI2.1mid but is never used in the actual processing
|
||||||
|
// of the styles?
|
||||||
|
int unknownC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The colour used by transitions that draw CelObjColor
|
||||||
|
* screen items. -1 for transitions that do not draw
|
||||||
|
* screen items.
|
||||||
|
*/
|
||||||
|
int16 color;
|
||||||
|
|
||||||
|
// TODO: Probably uint32
|
||||||
|
// TODO: This field probably should be used in order to
|
||||||
|
// provide time-accurate processing of show styles. In the
|
||||||
|
// actual SCI engine (at least 2–2.1mid) it appears that
|
||||||
|
// style transitions are drawn “as fast as possible”, one
|
||||||
|
// step per loop, even though this delay field exists
|
||||||
|
int delay;
|
||||||
|
|
||||||
|
// TODO: Probably bool, but never seems to be true?
|
||||||
|
int animate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The wall time at which the next step of the animation
|
||||||
|
* should execute.
|
||||||
|
*/
|
||||||
|
uint32 nextTick;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* During playback of the show style, the current step
|
||||||
|
* (out of divisions).
|
||||||
|
*/
|
||||||
|
int currentStep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next show style.
|
||||||
|
*/
|
||||||
|
ShowStyleEntry *next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this style has finished running and
|
||||||
|
* is ready for disposal.
|
||||||
|
*/
|
||||||
|
bool processed;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Engine-specific properties for SCI2 through 2.1early
|
||||||
|
//
|
||||||
|
|
||||||
|
// TODO: Could union this stuff to save literally
|
||||||
|
// several bytes of memory.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the plane. Used to determine the correct
|
||||||
|
* size of screen items for wipes.
|
||||||
|
*/
|
||||||
|
int width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the plane. Used to determine the correct
|
||||||
|
* size of screen items for wipes.
|
||||||
|
*/
|
||||||
|
int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of edges that a transition operates on.
|
||||||
|
* Slide wipe: 1 edge
|
||||||
|
* Reveal wipe: 2 edges
|
||||||
|
* Iris wipe: 4 edges
|
||||||
|
*/
|
||||||
|
// TODO: I have no idea why SCI engine stores this instead
|
||||||
|
// of a screenItems count
|
||||||
|
int edgeCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by transition types 1 through 10.
|
||||||
|
* One screen item per division per edge.
|
||||||
|
*/
|
||||||
|
ScreenItemList screenItems;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by transition types 11 and 12. A copy of the
|
||||||
|
* visible frame buffer.
|
||||||
|
*/
|
||||||
|
// TODO: This is a reg_t in SCI engine; not sure if
|
||||||
|
// we can avoid allocation through SegMan or not.
|
||||||
|
reg_t bitmapMemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by transition types 11 and 12. A screen item
|
||||||
|
* used to display the associated bitmap data.
|
||||||
|
*/
|
||||||
|
ScreenItem *bitmapScreenItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A number used to pick pixels to dissolve by types
|
||||||
|
* 11 and 12.
|
||||||
|
*/
|
||||||
|
int dissolveSeed;
|
||||||
|
int unknown3A;
|
||||||
|
// max?
|
||||||
|
int dissolveInitial;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Engine specific properties for SCI2.1mid through SCI3
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of entries in the fadeColorRanges array.
|
||||||
|
*/
|
||||||
|
uint8 fadeColorRangesCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pointer to an dynamically sized array of palette
|
||||||
|
* indexes, in the order [ fromColor, toColor, ... ].
|
||||||
|
* Only colors within this range are transitioned.
|
||||||
|
*/
|
||||||
|
uint16 *fadeColorRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Common::List<PlaneEntry> PlaneList;
|
typedef Common::Array<DrawList> ScreenItemListList;
|
||||||
|
typedef Common::Array<RectList> EraseListList;
|
||||||
struct FrameoutEntry {
|
|
||||||
uint16 givenOrderNr;
|
|
||||||
reg_t object;
|
|
||||||
GuiResourceId viewId;
|
|
||||||
int16 loopNo;
|
|
||||||
int16 celNo;
|
|
||||||
int16 x, y, z;
|
|
||||||
int16 priority;
|
|
||||||
uint16 signal;
|
|
||||||
uint16 scaleSignal;
|
|
||||||
int16 scaleX;
|
|
||||||
int16 scaleY;
|
|
||||||
Common::Rect celRect;
|
|
||||||
GfxPicture *picture;
|
|
||||||
int16 picStartX;
|
|
||||||
int16 picStartY;
|
|
||||||
bool visible;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Common::List<FrameoutEntry *> FrameoutList;
|
|
||||||
|
|
||||||
struct PlanePictureEntry {
|
|
||||||
reg_t object;
|
|
||||||
int16 startX;
|
|
||||||
int16 startY;
|
|
||||||
GuiResourceId pictureId;
|
|
||||||
GfxPicture *picture;
|
|
||||||
FrameoutEntry *pictureCels; // temporary
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Common::List<PlanePictureEntry> PlanePictureList;
|
|
||||||
|
|
||||||
struct ScrollTextEntry {
|
|
||||||
reg_t bitmapHandle;
|
|
||||||
reg_t kWindow;
|
|
||||||
uint16 x;
|
|
||||||
uint16 y;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Common::Array<ScrollTextEntry> ScrollTextList;
|
|
||||||
|
|
||||||
enum ViewScaleSignals32 {
|
|
||||||
kScaleSignalDoScaling32 = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY)
|
|
||||||
kScaleSignalUnk1 = 0x0002, // unknown
|
|
||||||
kScaleSignalDisableGlobalScaling32 = 0x0004
|
|
||||||
};
|
|
||||||
|
|
||||||
class GfxCache;
|
class GfxCache;
|
||||||
class GfxCoordAdjuster32;
|
class GfxCoordAdjuster32;
|
||||||
|
@ -114,69 +218,285 @@ class GfxScreen;
|
||||||
* Roughly equivalent to GraphicsMgr in the actual SCI engine.
|
* Roughly equivalent to GraphicsMgr in the actual SCI engine.
|
||||||
*/
|
*/
|
||||||
class GfxFrameout {
|
class GfxFrameout {
|
||||||
|
private:
|
||||||
|
bool _isHiRes;
|
||||||
|
GfxCache *_cache;
|
||||||
|
GfxCoordAdjuster32 *_coordAdjuster;
|
||||||
|
GfxPalette32 *_palette;
|
||||||
|
ResourceManager *_resMan;
|
||||||
|
GfxScreen *_screen;
|
||||||
|
SegManager *_segMan;
|
||||||
|
GfxPaint32 *_paint32;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32);
|
GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32);
|
||||||
~GfxFrameout();
|
~GfxFrameout();
|
||||||
|
|
||||||
void kernelAddPlane(reg_t object);
|
|
||||||
void kernelUpdatePlane(reg_t object);
|
|
||||||
void kernelDeletePlane(reg_t object);
|
|
||||||
void applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight);
|
|
||||||
void kernelAddScreenItem(reg_t object);
|
|
||||||
void kernelUpdateScreenItem(reg_t object);
|
|
||||||
void kernelDeleteScreenItem(reg_t object);
|
|
||||||
void deletePlaneItems(reg_t planeObject);
|
|
||||||
FrameoutEntry *findScreenItem(reg_t object);
|
|
||||||
int16 kernelGetHighPlanePri();
|
|
||||||
void kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY);
|
|
||||||
void kernelFrameout();
|
|
||||||
|
|
||||||
void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0);
|
|
||||||
void deletePlanePictures(reg_t object);
|
|
||||||
reg_t addPlaneLine(reg_t object, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control);
|
|
||||||
void updatePlaneLine(reg_t object, reg_t hunkId, Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control);
|
|
||||||
void deletePlaneLine(reg_t object, reg_t hunkId);
|
|
||||||
void clear();
|
void clear();
|
||||||
|
void run();
|
||||||
|
|
||||||
// Scroll text functions
|
#pragma mark -
|
||||||
void addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace);
|
#pragma mark Screen items
|
||||||
void showCurrentScrollText();
|
|
||||||
void initScrollText(uint16 maxItems) { _maxScrollTexts = maxItems; }
|
|
||||||
void clearScrollTexts();
|
|
||||||
void firstScrollText() { if (_scrollTexts.size() > 0) _curScrollText = 0; }
|
|
||||||
void lastScrollText() { if (_scrollTexts.size() > 0) _curScrollText = _scrollTexts.size() - 1; }
|
|
||||||
void prevScrollText() { if (_curScrollText > 0) _curScrollText--; }
|
|
||||||
void nextScrollText() { if (_curScrollText + 1 < (uint16)_scrollTexts.size()) _curScrollText++; }
|
|
||||||
void toggleScrollText(bool show) { _showScrollText = show; }
|
|
||||||
|
|
||||||
void printPlaneList(Console *con);
|
|
||||||
void printPlaneItemList(Console *con, reg_t planeObject);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isHiRes;
|
void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
|
||||||
|
|
||||||
void showVideo();
|
public:
|
||||||
void createPlaneItemList(reg_t planeObject, FrameoutList &itemList);
|
void kernelAddScreenItem(const reg_t object);
|
||||||
bool isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY);
|
void kernelUpdateScreenItem(const reg_t object);
|
||||||
void drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored);
|
void kernelDeleteScreenItem(const reg_t object);
|
||||||
|
|
||||||
SegManager *_segMan;
|
#pragma mark -
|
||||||
ResourceManager *_resMan;
|
#pragma mark Planes
|
||||||
GfxCoordAdjuster32 *_coordAdjuster;
|
private:
|
||||||
GfxCache *_cache;
|
/**
|
||||||
GfxPalette32 *_palette;
|
* The list of planes (i.e. layers) that have been added
|
||||||
GfxScreen *_screen;
|
* to the screen.
|
||||||
GfxPaint32 *_paint32;
|
*
|
||||||
|
* @note This field is on `GraphicsMgr.screen` in SCI
|
||||||
FrameoutList _screenItems;
|
* engine.
|
||||||
|
*/
|
||||||
PlaneList _planes;
|
PlaneList _planes;
|
||||||
PlanePictureList _planePictures;
|
|
||||||
ScrollTextList _scrollTexts;
|
|
||||||
int16 _curScrollText;
|
|
||||||
bool _showScrollText;
|
|
||||||
uint16 _maxScrollTexts;
|
|
||||||
|
|
||||||
void sortPlanes();
|
/**
|
||||||
|
* Creates and adds a new plane to the plane list, or
|
||||||
|
* cancels deletion and updates an already-existing
|
||||||
|
* plane if a plane matching the given plane VM object
|
||||||
|
* already exists within the current plane list.
|
||||||
|
*
|
||||||
|
* @note This method is on Screen in SCI engine, but it
|
||||||
|
* is only ever called on `GraphicsMgr.screen`.
|
||||||
|
*/
|
||||||
|
void addPlane(Plane &plane);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an existing plane with properties from the
|
||||||
|
* given VM object.
|
||||||
|
*/
|
||||||
|
void updatePlane(Plane &plane);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const PlaneList &getPlanes() const {
|
||||||
|
return _planes;
|
||||||
|
}
|
||||||
|
void kernelAddPlane(const reg_t object);
|
||||||
|
void kernelUpdatePlane(const reg_t object);
|
||||||
|
void kernelDeletePlane(const reg_t object);
|
||||||
|
int16 kernelGetHighPlanePri();
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Pics
|
||||||
|
public:
|
||||||
|
void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX);
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
// TODO: Remap-related?
|
||||||
|
void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Transitions
|
||||||
|
private:
|
||||||
|
int *_dissolveSequenceSeeds;
|
||||||
|
int16 *_defaultDivisions;
|
||||||
|
int16 *_defaultUnknownC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
ShowStyleEntry *_showStyles;
|
||||||
|
|
||||||
|
inline ShowStyleEntry *findShowStyleForPlane(const reg_t planeObj) const;
|
||||||
|
inline ShowStyleEntry *deleteShowStyleInternal(ShowStyleEntry *const showStyle);
|
||||||
|
void processShowStyles();
|
||||||
|
bool processShowStyleNone(ShowStyleEntry *showStyle);
|
||||||
|
bool processShowStyleMorph(ShowStyleEntry *showStyle);
|
||||||
|
bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
|
||||||
|
#if 0
|
||||||
|
bool processShowStyleWipe(const int direction, ShowStyleEntry *const showStyle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
// NOTE: This signature is taken from SCI3 Phantasmagoria 2
|
||||||
|
// and is valid for all implementations of SCI32
|
||||||
|
void kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, const reg_t &pFadeArray, const int16 divisions, const int16 blackScreen);
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Rendering
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
int8 _styleRanges[256];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal display pixel buffer. During frameOut,
|
||||||
|
* this buffer is drawn into according to the draw and
|
||||||
|
* erase rects calculated by `calcLists`, then drawn out
|
||||||
|
* to the hardware surface according to the `_showList`
|
||||||
|
* rects (which are also calculated by `calcLists`).
|
||||||
|
*/
|
||||||
|
Buffer _currentBuffer;
|
||||||
|
|
||||||
|
// TODO: In SCI2.1/SQ6, priority map pixels are not allocated
|
||||||
|
// by default. In SCI2/GK1, pixels are allocated, but not used
|
||||||
|
// anywhere except within CelObj::Draw in seemingly the same
|
||||||
|
// way they are used in SCI2.1/SQ6: that is, never read, only
|
||||||
|
// written.
|
||||||
|
Buffer _priorityMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
bool _remapOccurred;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the data in the current buffer is what
|
||||||
|
* is visible to the user. During rendering updates,
|
||||||
|
* this flag is set to false.
|
||||||
|
*/
|
||||||
|
bool _frameNowVisible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document
|
||||||
|
* TODO: Depending upon if the engine ever modifies this
|
||||||
|
* rect, it may be stupid to store it separately instead
|
||||||
|
* of just getting width/height from GfxScreen.
|
||||||
|
*
|
||||||
|
* @note This field is on `GraphicsMgr.screen` in SCI
|
||||||
|
* engine.
|
||||||
|
*/
|
||||||
|
Common::Rect _screenRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of rectangles, in display coordinates, that
|
||||||
|
* represent portions of the internal screen buffer that
|
||||||
|
* should be drawn to the hardware display surface.
|
||||||
|
*
|
||||||
|
* @note This field is on `GraphicsMgr.screen` in SCI
|
||||||
|
* engine.
|
||||||
|
*/
|
||||||
|
RectList _showList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of extra overdraw that is acceptable when
|
||||||
|
* merging two show list rectangles together into a
|
||||||
|
* single larger rectangle.
|
||||||
|
*
|
||||||
|
* @note This field is on `GraphicsMgr.screen` in SCI
|
||||||
|
* engine.
|
||||||
|
*/
|
||||||
|
int _overdrawThreshold;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of planes that are currently drawn to the
|
||||||
|
* hardware display surface. Used to calculate
|
||||||
|
* differences in plane properties between the last
|
||||||
|
* frame and current frame.
|
||||||
|
*
|
||||||
|
* @note This field is on `GraphicsMgr.visibleScreen` in
|
||||||
|
* SCI engine.
|
||||||
|
*/
|
||||||
|
PlaneList _visiblePlanes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the location and dimensions of dirty rects
|
||||||
|
* over the entire screen for rendering the next frame.
|
||||||
|
* The draw and erase lists in `drawLists` and
|
||||||
|
* `eraseLists` each represent one plane on the screen.
|
||||||
|
*/
|
||||||
|
void calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erases the areas in the given erase list from the
|
||||||
|
* visible screen buffer by filling them with the color
|
||||||
|
* from the corresponding plane. This is an optimisation
|
||||||
|
* for coloured-type planes only; other plane types have
|
||||||
|
* to be redrawn from pixel data.
|
||||||
|
*/
|
||||||
|
void drawEraseList(const RectList &eraseList, const Plane &plane);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws all screen items from the given draw list to
|
||||||
|
* the visible screen buffer.
|
||||||
|
*/
|
||||||
|
void drawScreenItemList(const DrawList &screenItemList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the internal screen buffer for the next
|
||||||
|
* frame. If `shouldShowBits` is true, also sends the
|
||||||
|
* buffer to hardware.
|
||||||
|
*/
|
||||||
|
void frameOut(const bool shouldShowBits, const Common::Rect &rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new rectangle to the list of regions to write
|
||||||
|
* out to the hardware. The provided rect may be merged
|
||||||
|
* into an existing rectangle to reduce the number of
|
||||||
|
* blit operations.
|
||||||
|
*/
|
||||||
|
void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
void palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the internal frame buffer out to hardware and
|
||||||
|
* clears the show list.
|
||||||
|
*/
|
||||||
|
void showBits();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* TODO: Document
|
||||||
|
* This is used by CelObj::Draw.
|
||||||
|
*/
|
||||||
|
bool _hasRemappedScreenItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether palMorphFrameOut should be used instead of
|
||||||
|
* frameOut for rendering. Used by kMorphOn to
|
||||||
|
* explicitly enable palMorphFrameOut for one frame.
|
||||||
|
*/
|
||||||
|
bool _palMorphIsOn;
|
||||||
|
|
||||||
|
inline Buffer &getCurrentBuffer() {
|
||||||
|
return _currentBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernelFrameout(const bool showBits);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the raw pixel data for the next frame with
|
||||||
|
* new palette indexes based on matched style ranges.
|
||||||
|
*/
|
||||||
|
void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges);
|
||||||
|
|
||||||
|
// TODO: SCI2 engine never uses priority map?
|
||||||
|
inline Buffer &getPriorityMap() {
|
||||||
|
return _priorityMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This function is used within ScreenItem subsystem and assigned
|
||||||
|
// to various booleanish fields that seem to represent the state of the
|
||||||
|
// screen item (created, updated, deleted). In GK1/DOS, Phant1/m68k,
|
||||||
|
// SQ6/DOS, SQ6/Win, and Phant2/Win, this function simply returns 1. If
|
||||||
|
// you know of any game/environment where this function returns some
|
||||||
|
// value other than 1, or if you used to work at Sierra and can explain
|
||||||
|
// why this is a thing (and if anyone needs to care about it), please
|
||||||
|
// open a ticket!!
|
||||||
|
inline int getScreenCount() const {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Debugging
|
||||||
|
public:
|
||||||
|
void printPlaneList(Console *con) const;
|
||||||
|
void printVisiblePlaneList(Console *con) const;
|
||||||
|
void printPlaneListInternal(Console *con, const PlaneList &planeList) const;
|
||||||
|
void printPlaneItemList(Console *con, const reg_t planeObject) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
#include "common/endian.h" // for READ_LE_UINT16
|
#include "common/endian.h" // for READ_LE_UINT16
|
||||||
#include "common/rect.h"
|
#include "common/rect.h"
|
||||||
#include "common/serializer.h"
|
#include "common/serializer.h"
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
#include "common/rational.h"
|
||||||
|
#include "graphics/pixelformat.h"
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
#endif
|
||||||
#include "sci/engine/vm_types.h"
|
#include "sci/engine/vm_types.h"
|
||||||
|
|
||||||
namespace Sci {
|
namespace Sci {
|
||||||
|
@ -45,6 +50,9 @@ typedef int16 TextAlignment;
|
||||||
#define PORTS_FIRSTWINDOWID 2
|
#define PORTS_FIRSTWINDOWID 2
|
||||||
#define PORTS_FIRSTSCRIPTWINDOWID 3
|
#define PORTS_FIRSTSCRIPTWINDOWID 3
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
#define PRINT_RECT(x) (x).left,(x).top,(x).right,(x).bottom
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
uint16 id;
|
uint16 id;
|
||||||
|
@ -118,6 +126,79 @@ struct Window : public Port, public Common::Serializable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
/**
|
||||||
|
* Multiplies a number by a rational number, rounding up to
|
||||||
|
* the nearest whole number.
|
||||||
|
*/
|
||||||
|
inline int mulru(const int value, const Common::Rational &ratio, const int extra = 0) {
|
||||||
|
int num = (value + extra) * ratio.getNumerator();
|
||||||
|
int result = num / ratio.getDenominator();
|
||||||
|
if (num > ratio.getDenominator() && num % ratio.getDenominator()) {
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
return result - extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies a point by two rational numbers for X and Y,
|
||||||
|
* rounding up to the nearest whole number. Modifies the
|
||||||
|
* point directly.
|
||||||
|
*/
|
||||||
|
inline void mulru(Common::Point &point, const Common::Rational &ratioX, const Common::Rational &ratioY) {
|
||||||
|
point.x = mulru(point.x, ratioX);
|
||||||
|
point.y = mulru(point.y, ratioY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies a point by two rational numbers for X and Y,
|
||||||
|
* rounding up to the nearest whole number. Modifies the
|
||||||
|
* rect directly.
|
||||||
|
*/
|
||||||
|
inline void mulru(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY, const int brExtra = 0) {
|
||||||
|
rect.left = mulru(rect.left, ratioX);
|
||||||
|
rect.top = mulru(rect.top, ratioY);
|
||||||
|
rect.right = mulru(rect.right, ratioX, brExtra);
|
||||||
|
rect.bottom = mulru(rect.bottom, ratioY, brExtra);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Buffer : public Graphics::Surface {
|
||||||
|
uint16 screenWidth;
|
||||||
|
uint16 screenHeight;
|
||||||
|
uint16 scriptWidth;
|
||||||
|
uint16 scriptHeight;
|
||||||
|
|
||||||
|
Buffer(const uint16 width, const uint16 height, uint8 *const pix) :
|
||||||
|
screenWidth(width),
|
||||||
|
screenHeight(height),
|
||||||
|
// TODO: These values are not correct for all games. Script
|
||||||
|
// dimensions were hard-coded per game in the original
|
||||||
|
// interpreter. Search all games for their internal script
|
||||||
|
// dimensions and set appropriately. (This code does not
|
||||||
|
// appear to exist at all in SCI3, which uses 640x480.)
|
||||||
|
scriptWidth(320),
|
||||||
|
scriptHeight(200) {
|
||||||
|
init(width, height, width, pix, Graphics::PixelFormat::createFormatCLUT8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(const uint8 value) {
|
||||||
|
memset(pixels, value, w * h);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 *getAddress(const uint16 x, const uint16 y) {
|
||||||
|
return (uint8 *)getBasePtr(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 *getAddressSimRes(const uint16 x, const uint16 y) {
|
||||||
|
return (uint8*)pixels + (y * w * screenHeight / scriptHeight) + (x * screenWidth / scriptWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull() {
|
||||||
|
return pixels == nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
byte used;
|
byte used;
|
||||||
byte r, g, b;
|
byte r, g, b;
|
||||||
|
|
192
engines/sci/graphics/lists32.h
Normal file
192
engines/sci/graphics/lists32.h
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/* 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_LISTS32_H
|
||||||
|
#define SCI_GRAPHICS_LISTS32_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StablePointerArray holds pointers in a fixed-size array
|
||||||
|
* that maintains position of erased items until `pack` is
|
||||||
|
* called. It is used by DrawList, RectList, and
|
||||||
|
* ScreenItemList. StablePointerArray takes ownership of
|
||||||
|
* all pointers that are passed to it and deletes them when
|
||||||
|
* calling `erase` or when destroying the
|
||||||
|
* StablePointerArray.
|
||||||
|
*/
|
||||||
|
template <class T, uint N>
|
||||||
|
class StablePointerArray {
|
||||||
|
uint _size;
|
||||||
|
T *_items[N];
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef T **iterator;
|
||||||
|
typedef T *const *const_iterator;
|
||||||
|
typedef T *value_type;
|
||||||
|
typedef uint size_type;
|
||||||
|
|
||||||
|
StablePointerArray() : _size(0), _items() {}
|
||||||
|
StablePointerArray(const StablePointerArray &other) : _size(other._size) {
|
||||||
|
for (size_type i = 0; i < _size; ++i) {
|
||||||
|
if (other._items[i] == nullptr) {
|
||||||
|
_items[i] = nullptr;
|
||||||
|
} else {
|
||||||
|
_items[i] = new T(*other._items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~StablePointerArray() {
|
||||||
|
for (size_type i = 0; i < _size; ++i) {
|
||||||
|
delete _items[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const StablePointerArray &other) {
|
||||||
|
clear();
|
||||||
|
_size = other._size;
|
||||||
|
for (size_type i = 0; i < _size; ++i) {
|
||||||
|
if (other._items[i] == nullptr) {
|
||||||
|
_items[i] = nullptr;
|
||||||
|
} else {
|
||||||
|
_items[i] = new T(*other._items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T *const &operator[](size_type index) const {
|
||||||
|
assert(index >= 0 && index < _size);
|
||||||
|
return _items[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
T *&operator[](size_type index) {
|
||||||
|
assert(index >= 0 && index < _size);
|
||||||
|
return _items[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new pointer to the array.
|
||||||
|
*/
|
||||||
|
void add(T *item) {
|
||||||
|
assert(_size < N);
|
||||||
|
_items[_size++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return _items;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return _items;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
for (size_type i = 0; i < _size; ++i) {
|
||||||
|
delete _items[i];
|
||||||
|
_items[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() {
|
||||||
|
return _items + _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return _items + _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erases the object pointed to by the given iterator.
|
||||||
|
*/
|
||||||
|
void erase(T *item) {
|
||||||
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
|
if (*it == item) {
|
||||||
|
delete *it;
|
||||||
|
*it = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erases the object pointed to by the given iterator.
|
||||||
|
*/
|
||||||
|
void erase(iterator &it) {
|
||||||
|
assert(it >= _items && it < _items + _size);
|
||||||
|
delete *it;
|
||||||
|
*it = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erases the object pointed to at the given index.
|
||||||
|
*/
|
||||||
|
void erase_at(size_type index) {
|
||||||
|
assert(index >= 0 && index < _size);
|
||||||
|
|
||||||
|
delete _items[index];
|
||||||
|
_items[index] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes freed pointers from the pointer list.
|
||||||
|
*/
|
||||||
|
size_type pack() {
|
||||||
|
iterator freePtr = begin();
|
||||||
|
size_type newSize = 0;
|
||||||
|
|
||||||
|
for (iterator it = begin(), last = end(); it != last; ++it) {
|
||||||
|
if (*it != nullptr) {
|
||||||
|
*freePtr = *it;
|
||||||
|
++freePtr;
|
||||||
|
++newSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_size = newSize;
|
||||||
|
return newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of populated slots in the array. The size
|
||||||
|
* of the array will only go down once `pack` is called.
|
||||||
|
*/
|
||||||
|
size_type size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class FindByObject {
|
||||||
|
const reg_t &_object;
|
||||||
|
public:
|
||||||
|
FindByObject(const reg_t &object) : _object(object) {}
|
||||||
|
bool operator()(const T entry) const {
|
||||||
|
return entry->_object == _object;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -47,7 +47,6 @@ GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen)
|
||||||
_version(1), _versionUpdated(false) {
|
_version(1), _versionUpdated(false) {
|
||||||
_varyPercent = _varyTargetPercent;
|
_varyPercent = _varyTargetPercent;
|
||||||
memset(_fadeTable, 100, sizeof(_fadeTable));
|
memset(_fadeTable, 100, sizeof(_fadeTable));
|
||||||
|
|
||||||
// NOTE: In SCI engine, the palette manager constructor loads
|
// NOTE: In SCI engine, the palette manager constructor loads
|
||||||
// the default palette, but in ScummVM this initialisation
|
// the default palette, but in ScummVM this initialisation
|
||||||
// is performed by SciEngine::run; see r49523 for details
|
// is performed by SciEngine::run; see r49523 for details
|
||||||
|
@ -67,6 +66,10 @@ inline void mergePaletteInternal(Palette *const to, const Palette *const from) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Palette *GfxPalette32::getNextPalette() const {
|
||||||
|
return &_nextPalette;
|
||||||
|
}
|
||||||
|
|
||||||
void GfxPalette32::submit(Palette &palette) {
|
void GfxPalette32::submit(Palette &palette) {
|
||||||
// TODO: The resource manager in SCI32 retains raw data of palettes from
|
// TODO: The resource manager in SCI32 retains raw data of palettes from
|
||||||
// the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and
|
// the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and
|
||||||
|
@ -206,10 +209,20 @@ int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const i
|
||||||
return bestIndex;
|
return bestIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxPalette32::updateForFrame() {
|
bool GfxPalette32::updateForFrame() {
|
||||||
applyAll();
|
applyAll();
|
||||||
_versionUpdated = false;
|
_versionUpdated = false;
|
||||||
// TODO: Implement remapping
|
// TODO: Implement remapping
|
||||||
|
// return g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxPalette32::updateFFrame() {
|
||||||
|
for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) {
|
||||||
|
_nextPalette.colors[i] = _sourcePalette.colors[i];
|
||||||
|
}
|
||||||
|
_versionUpdated = false;
|
||||||
|
// TODO: Implement remapping
|
||||||
// g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
|
// g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +423,7 @@ void GfxPalette32::setVaryPercent(const int16 percent, const int time, const int
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 GfxPalette32::getVaryPercent() const {
|
int16 GfxPalette32::getVaryPercent() const {
|
||||||
return abs(_varyPercent);
|
return ABS(_varyPercent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxPalette32::varyOff() {
|
void GfxPalette32::varyOff() {
|
||||||
|
@ -773,6 +786,12 @@ void GfxPalette32::applyCycles() {
|
||||||
// Palette fading
|
// Palette fading
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// NOTE: There are some game scripts (like SQ6 Sierra logo and main menu) that call
|
||||||
|
// setFade with numColorsToFade set to 256, but other parts of the engine like
|
||||||
|
// processShowStyleNone use 255 instead of 256. It is not clear if this is because
|
||||||
|
// the last palette entry is intentionally left unmodified, or if this is a bug
|
||||||
|
// in the engine. It certainly seems confused because all other places that accept
|
||||||
|
// colour ranges typically receive values in the range of 0–255.
|
||||||
void GfxPalette32::setFade(uint8 percent, uint8 fromColor, uint16 numColorsToFade) {
|
void GfxPalette32::setFade(uint8 percent, uint8 fromColor, uint16 numColorsToFade) {
|
||||||
if (fromColor > numColorsToFade) {
|
if (fromColor > numColorsToFade) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "sci/graphics/palette.h"
|
#include "sci/graphics/palette.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
enum PalCyclerDirection {
|
enum PalCyclerDirection {
|
||||||
PalCycleBackward = 0,
|
PalCycleBackward = 0,
|
||||||
PalCycleForward = 1
|
PalCycleForward = 1
|
||||||
|
@ -71,13 +72,15 @@ struct PalCycler {
|
||||||
uint16 numTimesPaused;
|
uint16 numTimesPaused;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Sci {
|
|
||||||
class GfxPalette32 : public GfxPalette {
|
class GfxPalette32 : public GfxPalette {
|
||||||
public:
|
public:
|
||||||
GfxPalette32(ResourceManager *resMan, GfxScreen *screen);
|
GfxPalette32(ResourceManager *resMan, GfxScreen *screen);
|
||||||
~GfxPalette32();
|
~GfxPalette32();
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
// NOTE: currentPalette in SCI engine is called _sysPalette
|
||||||
|
// here.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The palette revision version. Increments once per game
|
* The palette revision version. Increments once per game
|
||||||
* loop that changes the source palette. TODO: Possibly
|
* loop that changes the source palette. TODO: Possibly
|
||||||
|
@ -105,32 +108,47 @@ namespace Sci {
|
||||||
*/
|
*/
|
||||||
Palette _nextPalette;
|
Palette _nextPalette;
|
||||||
|
|
||||||
// SQ6 defines 10 cyclers
|
bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const;
|
||||||
PalCycler *_cyclers[10];
|
Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void saveLoadWithSerializer(Common::Serializer &s) override;
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cycle map is used to detect overlapping cyclers.
|
* Submits a palette to display. Entries marked as “used” in the
|
||||||
* According to SCI engine code, when two cyclers overlap,
|
* submitted palette are merged into the existing entries of
|
||||||
* a fatal error has occurred and the engine will display
|
* _sourcePalette.
|
||||||
* an error and then exit.
|
|
||||||
*/
|
*/
|
||||||
bool _cycleMap[256];
|
void submit(Palette &palette);
|
||||||
inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear);
|
|
||||||
inline void setCycleMap(uint16 fromColor, uint16 numColorsToClear);
|
|
||||||
inline PalCycler *getCycler(uint16 fromColor);
|
|
||||||
|
|
||||||
/**
|
bool updateForFrame();
|
||||||
* The fade table records the expected intensity level of each pixel
|
void updateFFrame();
|
||||||
* in the palette that will be displayed on the next frame.
|
void updateHardware();
|
||||||
*/
|
void applyAll();
|
||||||
byte _fadeTable[256];
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Colour look-up
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* An optional lookup table used to remap RGB565 colors to a palette
|
* An optional lookup table used to remap RGB565 colors to a palette
|
||||||
* index. Used by Phantasmagoria 2 in 8-bit color environments.
|
* index. Used by Phantasmagoria 2 in 8-bit color environments.
|
||||||
*/
|
*/
|
||||||
byte *_clutTable;
|
byte *_clutTable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool loadClut(uint16 clutId);
|
||||||
|
byte matchClutColor(uint16 color);
|
||||||
|
void unloadClut();
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Varying
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* An optional palette used to describe the source colors used
|
* An optional palette used to describe the source colors used
|
||||||
* in a palette vary operation. If this palette is not specified,
|
* in a palette vary operation. If this palette is not specified,
|
||||||
|
@ -162,14 +180,13 @@ namespace Sci {
|
||||||
uint32 _varyLastTick;
|
uint32 _varyLastTick;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Document
|
* The amount of time to elapse, in ticks, between each cycle
|
||||||
* The velocity of change in percent?
|
* of a palette vary animation.
|
||||||
*/
|
*/
|
||||||
int _varyTime;
|
int _varyTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Better documentation
|
* The direction of change: -1, 0, or 1.
|
||||||
* The direction of change, -1, 0, or 1.
|
|
||||||
*/
|
*/
|
||||||
int16 _varyDirection;
|
int16 _varyDirection;
|
||||||
|
|
||||||
|
@ -190,29 +207,7 @@ namespace Sci {
|
||||||
*/
|
*/
|
||||||
uint16 _varyNumTimesPaused;
|
uint16 _varyNumTimesPaused;
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits a palette to display. Entries marked as “used” in the
|
|
||||||
* submitted palette are merged into the existing entries of
|
|
||||||
* _sourcePalette.
|
|
||||||
*/
|
|
||||||
void submit(Palette &palette);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void saveLoadWithSerializer(Common::Serializer &s) override;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
void updateForFrame();
|
|
||||||
void updateHardware();
|
|
||||||
void applyAll();
|
|
||||||
|
|
||||||
bool loadClut(uint16 clutId);
|
|
||||||
byte matchClutColor(uint16 color);
|
|
||||||
void unloadClut();
|
|
||||||
|
|
||||||
void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor);
|
void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor);
|
||||||
void kernelPalVaryMergeTarget(const GuiResourceId paletteId);
|
void kernelPalVaryMergeTarget(const GuiResourceId paletteId);
|
||||||
void kernelPalVarySetTarget(const GuiResourceId paletteId);
|
void kernelPalVarySetTarget(const GuiResourceId paletteId);
|
||||||
|
@ -231,13 +226,27 @@ namespace Sci {
|
||||||
void setTarget(const Palette *const palette);
|
void setTarget(const Palette *const palette);
|
||||||
void setStart(const Palette *const palette);
|
void setStart(const Palette *const palette);
|
||||||
void mergeStart(const Palette *const palette);
|
void mergeStart(const Palette *const palette);
|
||||||
private:
|
|
||||||
bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const;
|
|
||||||
Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const;
|
|
||||||
void setVaryTimeInternal(const int16 percent, const int time);
|
void setVaryTimeInternal(const int16 percent, const int time);
|
||||||
public:
|
|
||||||
void applyVary();
|
void applyVary();
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Cycling
|
||||||
|
private:
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
public:
|
||||||
void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay);
|
void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay);
|
||||||
void doCycle(const uint8 fromColor, const int16 speed);
|
void doCycle(const uint8 fromColor, const int16 speed);
|
||||||
void cycleOn(const uint8 fromColor);
|
void cycleOn(const uint8 fromColor);
|
||||||
|
@ -249,6 +258,16 @@ namespace Sci {
|
||||||
void applyAllCycles();
|
void applyAllCycles();
|
||||||
void applyCycles();
|
void applyCycles();
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Fading
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* 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];
|
||||||
|
|
||||||
|
public:
|
||||||
void setFade(const uint8 percent, const uint8 fromColor, const uint16 toColor);
|
void setFade(const uint8 percent, const uint8 fromColor, const uint16 toColor);
|
||||||
void fadeOff();
|
void fadeOff();
|
||||||
void applyFade();
|
void applyFade();
|
||||||
|
|
|
@ -209,12 +209,12 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
// [headerSize:WORD] [celCount:BYTE] [Unknown:BYTE] [Unknown:WORD] [paletteOffset:DWORD] [Unknown:DWORD]
|
// 0[headerSize:WORD] 2[celCount:BYTE] 3[Unknown:BYTE] 4[celHeaderSize:WORD] 6[paletteOffset:DWORD] 10[Unknown:WORD] 12[Unknown:WORD]
|
||||||
// cel-header follow afterwards, each is 42 bytes
|
// cel-header follow afterwards, each is 42 bytes
|
||||||
// Cel-Header
|
// Cel-Header
|
||||||
// [width:WORD] [height:WORD] [displaceX:WORD] [displaceY:WORD] [clearColor:BYTE] [compressed:BYTE]
|
// 0[width:WORD] 2[height:WORD] 4[displaceX:WORD] 6[displaceY:WORD] 8[clearColor:BYTE] 9[compressed:BYTE]
|
||||||
// offset 10-23 is unknown
|
// offset 10-23 is unknown
|
||||||
// [rleOffset:DWORD] [literalOffset:DWORD] [Unknown:WORD] [Unknown:WORD] [priority:WORD] [relativeXpos:WORD] [relativeYpos:WORD]
|
// 24[rleOffset:DWORD] 28[literalOffset:DWORD] 32[Unknown:WORD] 34[Unknown:WORD] 36[priority:WORD] 38[relativeXpos:WORD] 40[relativeYpos:WORD]
|
||||||
|
|
||||||
cel_headerPos += 42 * celNo;
|
cel_headerPos += 42 * celNo;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ enum {
|
||||||
class GfxPorts;
|
class GfxPorts;
|
||||||
class GfxScreen;
|
class GfxScreen;
|
||||||
class GfxPalette;
|
class GfxPalette;
|
||||||
|
class GfxCoordAdjuster;
|
||||||
|
class ResourceManager;
|
||||||
|
class Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Picture class, handles loading and displaying of picture resources
|
* Picture class, handles loading and displaying of picture resources
|
||||||
|
|
841
engines/sci/graphics/plane32.cpp
Normal file
841
engines/sci/graphics/plane32.cpp
Normal file
|
@ -0,0 +1,841 @@
|
||||||
|
/* 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/console.h"
|
||||||
|
#include "sci/engine/kernel.h"
|
||||||
|
#include "sci/engine/selector.h"
|
||||||
|
#include "sci/engine/state.h"
|
||||||
|
#include "sci/graphics/frameout.h"
|
||||||
|
#include "sci/graphics/lists32.h"
|
||||||
|
#include "sci/graphics/plane32.h"
|
||||||
|
#include "sci/graphics/screen.h"
|
||||||
|
#include "sci/graphics/screen_item32.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
#pragma mark DrawList
|
||||||
|
void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
|
||||||
|
DrawItem *drawItem = new DrawItem;
|
||||||
|
drawItem->screenItem = screenItem;
|
||||||
|
drawItem->rect = rect;
|
||||||
|
DrawListBase::add(drawItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane
|
||||||
|
uint16 Plane::_nextObjectId = 20000;
|
||||||
|
|
||||||
|
Plane::Plane(const Common::Rect &gameRect) :
|
||||||
|
_gameRect(gameRect),
|
||||||
|
_object(make_reg(0, _nextObjectId++)),
|
||||||
|
_back(0),
|
||||||
|
_pictureId(kPlanePicColored),
|
||||||
|
_mirrored(false),
|
||||||
|
_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
|
||||||
|
_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
|
||||||
|
_deleted(0),
|
||||||
|
_updated(0),
|
||||||
|
_priorityChanged(0),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()),
|
||||||
|
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()) {
|
||||||
|
convertGameRectToPlaneRect();
|
||||||
|
_priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1);
|
||||||
|
setType();
|
||||||
|
_screenRect = _planeRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plane::Plane(reg_t object) :
|
||||||
|
_object(object),
|
||||||
|
_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
|
||||||
|
_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()),
|
||||||
|
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
|
||||||
|
_deleted(0),
|
||||||
|
_updated(0),
|
||||||
|
_priorityChanged(false),
|
||||||
|
_moved(0) {
|
||||||
|
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||||
|
_vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
|
||||||
|
_vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
|
||||||
|
|
||||||
|
_gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
|
||||||
|
_gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
|
||||||
|
_gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight));
|
||||||
|
_gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom));
|
||||||
|
convertGameRectToPlaneRect();
|
||||||
|
|
||||||
|
_back = readSelectorValue(segMan, object, SELECTOR(back));
|
||||||
|
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
|
||||||
|
_pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
|
||||||
|
setType();
|
||||||
|
|
||||||
|
_mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
|
||||||
|
_screenRect = _planeRect;
|
||||||
|
changePic();
|
||||||
|
}
|
||||||
|
|
||||||
|
Plane::Plane(const Plane &other) :
|
||||||
|
_object(other._object),
|
||||||
|
_priority(other._priority),
|
||||||
|
_pictureId(other._pictureId),
|
||||||
|
_mirrored(other._mirrored),
|
||||||
|
_back(other._back),
|
||||||
|
_field_34(other._field_34), _field_38(other._field_38),
|
||||||
|
_field_3C(other._field_3C), _field_40(other._field_40),
|
||||||
|
_planeRect(other._planeRect),
|
||||||
|
_gameRect(other._gameRect),
|
||||||
|
_screenRect(other._screenRect),
|
||||||
|
_screenItemList(other._screenItemList) {}
|
||||||
|
|
||||||
|
void Plane::operator=(const Plane &other) {
|
||||||
|
_gameRect = other._gameRect;
|
||||||
|
_planeRect = other._planeRect;
|
||||||
|
_vanishingPoint = other._vanishingPoint;
|
||||||
|
_pictureId = other._pictureId;
|
||||||
|
_type = other._type;
|
||||||
|
_mirrored = other._mirrored;
|
||||||
|
_priority = other._priority;
|
||||||
|
_back = other._back;
|
||||||
|
_width = other._width;
|
||||||
|
_field_34 = other._field_34;
|
||||||
|
_height = other._height;
|
||||||
|
_screenRect = other._screenRect;
|
||||||
|
_field_3C = other._field_3C;
|
||||||
|
_priorityChanged = other._priorityChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::init() {
|
||||||
|
_nextObjectId = 20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::convertGameRectToPlaneRect() {
|
||||||
|
const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
|
||||||
|
const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
|
||||||
|
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
||||||
|
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
||||||
|
|
||||||
|
const Ratio ratioX = Ratio(screenWidth, scriptWidth);
|
||||||
|
const Ratio ratioY = Ratio(screenHeight, scriptHeight);
|
||||||
|
|
||||||
|
_planeRect = _gameRect;
|
||||||
|
mulru(_planeRect, ratioX, ratioY, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::printDebugInfo(Console *con) const {
|
||||||
|
Common::String name;
|
||||||
|
|
||||||
|
if (_object.isNumber()) {
|
||||||
|
name = "-scummvm-";
|
||||||
|
} else {
|
||||||
|
name = g_sci->getEngineState()->_segMan->getObjectName(_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
con->debugPrintf("%04x:%04x (%s): type %d, prio %d, pic %d, mirror %d, back %d\n",
|
||||||
|
PRINT_REG(_object),
|
||||||
|
name.c_str(),
|
||||||
|
_type,
|
||||||
|
_priority,
|
||||||
|
_pictureId,
|
||||||
|
_mirrored,
|
||||||
|
_back
|
||||||
|
);
|
||||||
|
con->debugPrintf(" game rect: (%d, %d, %d, %d), plane rect: (%d, %d, %d, %d)\n screen rect: (%d, %d, %d, %d)\n",
|
||||||
|
PRINT_RECT(_gameRect),
|
||||||
|
PRINT_RECT(_planeRect),
|
||||||
|
PRINT_RECT(_screenRect)
|
||||||
|
);
|
||||||
|
con->debugPrintf(" # screen items: %d\n", _screenItemList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane - Pic
|
||||||
|
|
||||||
|
void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX) {
|
||||||
|
|
||||||
|
uint16 celCount = 1000;
|
||||||
|
for (uint16 celNo = 0; celNo < celCount; ++celNo) {
|
||||||
|
CelObjPic *celObj = new CelObjPic(pictureId, celNo);
|
||||||
|
if (celCount == 1000) {
|
||||||
|
celCount = celObj->_celCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenItem *screenItem = new ScreenItem(_object, celObj->_info);
|
||||||
|
screenItem->_pictureId = pictureId;
|
||||||
|
screenItem->_mirrorX = mirrorX;
|
||||||
|
screenItem->_priority = celObj->_priority;
|
||||||
|
screenItem->_fixPriority = true;
|
||||||
|
if (position != nullptr) {
|
||||||
|
screenItem->_position = *position;
|
||||||
|
} else {
|
||||||
|
screenItem->_position = celObj->_relativePosition;
|
||||||
|
}
|
||||||
|
_screenItemList.add(screenItem);
|
||||||
|
|
||||||
|
delete screenItem->_celObj;
|
||||||
|
screenItem->_celObj = celObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
|
||||||
|
deletePic(pictureId);
|
||||||
|
addPicInternal(pictureId, &position, mirrorX);
|
||||||
|
// NOTE: In SCI engine this method returned the pictureId of the
|
||||||
|
// plane, but this return value was never used
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::changePic() {
|
||||||
|
_pictureChanged = false;
|
||||||
|
|
||||||
|
if (_type != kPlaneTypePicture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPicInternal(_pictureId, nullptr, _mirrored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::deletePic(const GuiResourceId pictureId) {
|
||||||
|
for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
|
||||||
|
ScreenItem *screenItem = *it;
|
||||||
|
if (screenItem->_pictureId == pictureId) {
|
||||||
|
screenItem->_created = 0;
|
||||||
|
screenItem->_updated = 0;
|
||||||
|
screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId) {
|
||||||
|
deletePic(oldPictureId);
|
||||||
|
_pictureId = newPictureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::deleteAllPics() {
|
||||||
|
for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
|
||||||
|
ScreenItem *screenItem = *it;
|
||||||
|
if (screenItem != nullptr && screenItem->_celInfo.type == kCelTypePic) {
|
||||||
|
if (screenItem->_created == 0) {
|
||||||
|
screenItem->_created = 0;
|
||||||
|
screenItem->_updated = 0;
|
||||||
|
screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
} else {
|
||||||
|
_screenItemList.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_screenItemList.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane - Rendering
|
||||||
|
|
||||||
|
void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const {
|
||||||
|
int index = planeList.findIndexByObject(_object);
|
||||||
|
|
||||||
|
for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
|
||||||
|
for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
|
||||||
|
if (planeList[j]->_type != kPlaneTypeTransparent) {
|
||||||
|
Common::Rect ptr[4];
|
||||||
|
int count = splitRects(drawList[i]->rect, planeList[j]->_screenRect, ptr);
|
||||||
|
if (count != -1) {
|
||||||
|
for (int k = count - 1; k >= 0; --k) {
|
||||||
|
drawList.add(drawList[i]->screenItem, ptr[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawList.erase_at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drawList.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const {
|
||||||
|
int index = planeList.findIndexByObject(_object);
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
|
||||||
|
for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
|
||||||
|
if (planeList[j]->_type != kPlaneTypeTransparent) {
|
||||||
|
Common::Rect ptr[4];
|
||||||
|
|
||||||
|
int count = splitRects(*eraseList[i], planeList[j]->_screenRect, ptr);
|
||||||
|
if (count != -1) {
|
||||||
|
for (int k = count - 1; k >= 0; --k) {
|
||||||
|
eraseList.add(ptr[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
eraseList.erase_at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eraseList.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
|
||||||
|
ScreenItemList::size_type planeItemCount = _screenItemList.size();
|
||||||
|
ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size();
|
||||||
|
|
||||||
|
for (PlaneList::size_type i = 0; i < planeItemCount; ++i) {
|
||||||
|
ScreenItem *vitem = nullptr;
|
||||||
|
// NOTE: The original engine used an array without bounds checking
|
||||||
|
// so could just get the visible screen item directly; we need to
|
||||||
|
// verify that the index is actually within the valid range for
|
||||||
|
// the visible plane before accessing the item to avoid a range
|
||||||
|
// error.
|
||||||
|
if (i < visiblePlaneItemCount) {
|
||||||
|
vitem = visiblePlane._screenItemList[i];
|
||||||
|
}
|
||||||
|
ScreenItem *item = _screenItemList[i];
|
||||||
|
|
||||||
|
if (i < _screenItemList.size() && item != nullptr) {
|
||||||
|
if (item->_deleted) {
|
||||||
|
// add item's rect to erase list
|
||||||
|
if (i < visiblePlane._screenItemList.size() && vitem != nullptr) {
|
||||||
|
if (!vitem->_screenRect.isEmpty()) {
|
||||||
|
if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
|
||||||
|
mergeToRectList(vitem->_screenRect, eraseList);
|
||||||
|
} else {
|
||||||
|
eraseList.add(vitem->_screenRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item->_created) {
|
||||||
|
// add item to draw list
|
||||||
|
item->getCelObj();
|
||||||
|
item->calcRects(*this);
|
||||||
|
|
||||||
|
if(!item->_screenRect.isEmpty()) {
|
||||||
|
if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
|
||||||
|
drawList.add(item, item->_screenRect);
|
||||||
|
mergeToRectList(item->_screenRect, eraseList);
|
||||||
|
} else {
|
||||||
|
drawList.add(item, item->_screenRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item->_updated) {
|
||||||
|
// add old rect to erase list, new item to draw list
|
||||||
|
item->getCelObj();
|
||||||
|
item->calcRects(*this);
|
||||||
|
if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps
|
||||||
|
// if item and vitem don't overlap, ...
|
||||||
|
if (item->_screenRect.isEmpty() ||
|
||||||
|
i >= visiblePlaneItemCount ||
|
||||||
|
vitem == nullptr ||
|
||||||
|
vitem->_screenRect.isEmpty() ||
|
||||||
|
!vitem->_screenRect.intersects(item->_screenRect)
|
||||||
|
) {
|
||||||
|
// add item to draw list, and old rect to erase list
|
||||||
|
if (!item->_screenRect.isEmpty()) {
|
||||||
|
drawList.add(item, item->_screenRect);
|
||||||
|
mergeToRectList(item->_screenRect, eraseList);
|
||||||
|
}
|
||||||
|
if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) {
|
||||||
|
mergeToRectList(vitem->_screenRect, eraseList);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise, add bounding box of old+new to erase list,
|
||||||
|
// and item to draw list
|
||||||
|
|
||||||
|
// TODO: This was changed from disasm, verify please!
|
||||||
|
Common::Rect extendedScreenItem = vitem->_screenRect;
|
||||||
|
extendedScreenItem.extend(item->_screenRect);
|
||||||
|
drawList.add(item, item->_screenRect);
|
||||||
|
mergeToRectList(extendedScreenItem, eraseList);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if no active remaps, just add item to draw list and old rect
|
||||||
|
// to erase list
|
||||||
|
if (!item->_screenRect.isEmpty()) {
|
||||||
|
drawList.add(item, item->_screenRect);
|
||||||
|
}
|
||||||
|
if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) {
|
||||||
|
eraseList.add(vitem->_screenRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
breakEraseListByPlanes(eraseList, planeList);
|
||||||
|
breakDrawListByPlanes(drawList, planeList);
|
||||||
|
|
||||||
|
if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"????
|
||||||
|
_screenItemList.sort();
|
||||||
|
bool encounteredPic = false;
|
||||||
|
bool v81 = false;
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
|
||||||
|
Common::Rect *rect = eraseList[i];
|
||||||
|
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
|
||||||
|
if (j < _screenItemList.size() && item != nullptr) {
|
||||||
|
if (rect->intersects(item->_screenRect)) {
|
||||||
|
Common::Rect intersection = rect->findIntersectingRect(item->_screenRect);
|
||||||
|
if (!item->_deleted) {
|
||||||
|
if (encounteredPic) {
|
||||||
|
if (item->_celInfo.type == kCelTypePic) {
|
||||||
|
if (v81 || item->_celInfo.celNo == 0) {
|
||||||
|
drawList.add(item, intersection);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!item->_updated && !item->_created) {
|
||||||
|
drawList.add(item, intersection);
|
||||||
|
}
|
||||||
|
v81 = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!item->_updated && !item->_created) {
|
||||||
|
drawList.add(item, intersection);
|
||||||
|
}
|
||||||
|
if (item->_celInfo.type == kCelTypePic) {
|
||||||
|
encounteredPic = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_screenItemList.unsort();
|
||||||
|
} else {
|
||||||
|
// add all items overlapping the erase list to the draw list
|
||||||
|
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
if (j < _screenItemList.size() && item != nullptr && !item->_updated && !item->_deleted && !item->_created && eraseList[i]->intersects(item->_screenRect)) {
|
||||||
|
drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (/* TODO: g_Remap_numActiveRemaps */ false) { // no remaps active?
|
||||||
|
// Add all items that overlap with items in the drawlist and have higher
|
||||||
|
// priority
|
||||||
|
for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
|
||||||
|
DrawItem *dli = drawList[i];
|
||||||
|
|
||||||
|
for (PlaneList::size_type j = 0; j < planeItemCount; ++j) {
|
||||||
|
ScreenItem *sli = _screenItemList[j];
|
||||||
|
|
||||||
|
if (i < drawList.size() && dli) {
|
||||||
|
if (j < _screenItemList.size() && sli) {
|
||||||
|
if (!sli->_updated && !sli->_deleted && !sli->_created) {
|
||||||
|
ScreenItem *item = dli->screenItem;
|
||||||
|
if (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) {
|
||||||
|
if (dli->rect.intersects(sli->_screenRect)) {
|
||||||
|
drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decrementScreenItemArrayCounts(&visiblePlane, false);
|
||||||
|
_screenItemList.pack();
|
||||||
|
visiblePlane._screenItemList.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate) {
|
||||||
|
// The size of the screenItemList may change, so it is
|
||||||
|
// critical to re-check the size on each iteration
|
||||||
|
for (ScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) {
|
||||||
|
ScreenItem *item = _screenItemList[i];
|
||||||
|
|
||||||
|
if (item != nullptr) {
|
||||||
|
// update item in visiblePlane if item is updated
|
||||||
|
if (
|
||||||
|
item->_updated ||
|
||||||
|
(
|
||||||
|
forceUpdate &&
|
||||||
|
visiblePlane != nullptr &&
|
||||||
|
Common::find(visiblePlane->_screenItemList.begin(), visiblePlane->_screenItemList.end(), item) != visiblePlane->_screenItemList.end()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
*visiblePlane->_screenItemList[i] = *_screenItemList[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->_updated) {
|
||||||
|
item->_updated--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new item in visiblePlane if item was added
|
||||||
|
if (item->_created) {
|
||||||
|
item->_created--;
|
||||||
|
if (visiblePlane != nullptr) {
|
||||||
|
ScreenItem *n = new ScreenItem(*item);
|
||||||
|
visiblePlane->_screenItemList.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete item from both planes if it was deleted
|
||||||
|
if (item->_deleted) {
|
||||||
|
item->_deleted--;
|
||||||
|
if (!item->_deleted) {
|
||||||
|
visiblePlane->_screenItemList.erase_at(i);
|
||||||
|
_screenItemList.erase_at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const {
|
||||||
|
if (_type == kPlaneTypeTransparent) {
|
||||||
|
for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
|
||||||
|
Common::Rect *r = transparentEraseList[i];
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
if (item != nullptr) {
|
||||||
|
if (r->intersects(item->_screenRect)) {
|
||||||
|
mergeToDrawList(j, *r, drawList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
|
||||||
|
Common::Rect *r = transparentEraseList[i];
|
||||||
|
if (r->intersects(_screenRect)) {
|
||||||
|
r->clip(_screenRect);
|
||||||
|
mergeToRectList(*r, eraseList);
|
||||||
|
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
|
||||||
|
if (item != nullptr) {
|
||||||
|
if (r->intersects(item->_screenRect)) {
|
||||||
|
mergeToDrawList(j, *r, drawList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect ptr[4];
|
||||||
|
Common::Rect *r2 = transparentEraseList[i];
|
||||||
|
int count = splitRects(*r2, *r, ptr);
|
||||||
|
for (int k = count - 1; k >= 0; --k) {
|
||||||
|
transparentEraseList.add(ptr[k]);
|
||||||
|
}
|
||||||
|
transparentEraseList.erase_at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transparentEraseList.pack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const {
|
||||||
|
for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
|
||||||
|
Common::Rect &r = drawList[i]->rect;
|
||||||
|
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
if (item != nullptr) {
|
||||||
|
if (r.intersects(item->_screenRect)) {
|
||||||
|
mergeToDrawList(j, r, transparentDrawList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const {
|
||||||
|
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
|
||||||
|
Common::Rect &r = *eraseList[i];
|
||||||
|
for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
|
||||||
|
ScreenItem *item = _screenItemList[j];
|
||||||
|
|
||||||
|
if (item != nullptr) {
|
||||||
|
if (r.intersects(item->_screenRect)) {
|
||||||
|
mergeToDrawList(j, r, drawList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
|
||||||
|
RectList rects;
|
||||||
|
|
||||||
|
Common::Rect r = _screenItemList[index]->_screenRect;
|
||||||
|
r.clip(rect);
|
||||||
|
|
||||||
|
rects.add(r);
|
||||||
|
ScreenItem *item = _screenItemList[index];
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < rects.size(); ++i) {
|
||||||
|
r = *rects[i];
|
||||||
|
|
||||||
|
for (DrawList::size_type j = 0; j < drawList.size(); ++j) {
|
||||||
|
DrawItem *drawitem = drawList[j];
|
||||||
|
if (item->_object == drawitem->screenItem->_object) {
|
||||||
|
if (drawitem->rect.contains(r)) {
|
||||||
|
rects.erase_at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect outRects[4];
|
||||||
|
int count = splitRects(r, drawitem->rect, outRects);
|
||||||
|
if (count != -1) {
|
||||||
|
for (int k = count - 1; k >= 0; --k) {
|
||||||
|
rects.add(outRects[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rects.erase_at(i);
|
||||||
|
|
||||||
|
// proceed to the next rect
|
||||||
|
r = *rects[++i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rects.pack();
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < rects.size(); ++i) {
|
||||||
|
drawList.add(item, *rects[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::mergeToRectList(const Common::Rect &rect, RectList &rectList) const {
|
||||||
|
RectList temp;
|
||||||
|
temp.add(rect);
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < temp.size(); ++i) {
|
||||||
|
Common::Rect *outerRect = temp[i];
|
||||||
|
for (RectList::size_type j = 0; j < rectList.size(); ++j) {
|
||||||
|
Common::Rect *innerRect = rectList[i];
|
||||||
|
if (innerRect->intersects(*outerRect)) {
|
||||||
|
Common::Rect out[4];
|
||||||
|
int count = splitRects(*outerRect, *innerRect, out);
|
||||||
|
for (int k = count - 1; k >= 0; --k) {
|
||||||
|
temp.add(out[k]);
|
||||||
|
}
|
||||||
|
temp.erase_at(i);
|
||||||
|
} else {
|
||||||
|
temp.erase_at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
temp.pack();
|
||||||
|
|
||||||
|
for (RectList::size_type i = 0; i < temp.size(); ++i) {
|
||||||
|
rectList.add(*temp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
|
||||||
|
for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) {
|
||||||
|
if (*screenItemPtr != nullptr) {
|
||||||
|
ScreenItem &screenItem = **screenItemPtr;
|
||||||
|
if (!screenItem._deleted) {
|
||||||
|
screenItem.getCelObj();
|
||||||
|
screenItem.calcRects(*this);
|
||||||
|
if (!screenItem._screenRect.isEmpty()) {
|
||||||
|
drawList.add(&screenItem, screenItem._screenRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eraseList.clear();
|
||||||
|
|
||||||
|
if (!_screenRect.isEmpty() && _type != kPlaneTypePicture && _type != kPlaneTypeOpaque) {
|
||||||
|
eraseList.add(_screenRect);
|
||||||
|
}
|
||||||
|
breakEraseListByPlanes(eraseList, planeList);
|
||||||
|
breakDrawListByPlanes(drawList, planeList);
|
||||||
|
--_redrawAllCount;
|
||||||
|
decrementScreenItemArrayCounts(visiblePlane, true);
|
||||||
|
_screenItemList.pack();
|
||||||
|
if (visiblePlane != nullptr) {
|
||||||
|
visiblePlane->_screenItemList.pack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::setType() {
|
||||||
|
if (_pictureId == kPlanePicOpaque) {
|
||||||
|
_type = kPlaneTypeOpaque;
|
||||||
|
} else if (_pictureId == kPlanePicTransparent) {
|
||||||
|
_type = kPlaneTypeTransparent;
|
||||||
|
} else if (_pictureId == kPlanePicColored) {
|
||||||
|
_type = kPlaneTypeColored;
|
||||||
|
} else {
|
||||||
|
_type = kPlaneTypePicture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
|
||||||
|
if (other == nullptr) {
|
||||||
|
if (_pictureChanged) {
|
||||||
|
deleteAllPics();
|
||||||
|
setType();
|
||||||
|
changePic();
|
||||||
|
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
} else {
|
||||||
|
setType();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
_planeRect.top != other->_planeRect.top ||
|
||||||
|
_planeRect.left != other->_planeRect.left ||
|
||||||
|
_planeRect.right > other->_planeRect.right ||
|
||||||
|
_planeRect.bottom > other->_planeRect.bottom
|
||||||
|
) {
|
||||||
|
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
_updated = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
} else if (_planeRect != other->_planeRect) {
|
||||||
|
_updated = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_priority != other->_priority) {
|
||||||
|
_priorityChanged = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pictureId != other->_pictureId || _mirrored != other->_mirrored || _pictureChanged) {
|
||||||
|
deleteAllPics();
|
||||||
|
setType();
|
||||||
|
changePic();
|
||||||
|
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_back != other->_back) {
|
||||||
|
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleted = 0;
|
||||||
|
if (_created == 0) {
|
||||||
|
_moved = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
convertGameRectToPlaneRect();
|
||||||
|
_width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
||||||
|
_height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
||||||
|
_screenRect = _planeRect;
|
||||||
|
// NOTE: screenRect originally was retrieved through globals
|
||||||
|
// instead of being passed into the function
|
||||||
|
clipScreenRect(screenRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::update(const reg_t object) {
|
||||||
|
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||||
|
_vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
|
||||||
|
_vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
|
||||||
|
_gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
|
||||||
|
_gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
|
||||||
|
_gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight));
|
||||||
|
_gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom));
|
||||||
|
convertGameRectToPlaneRect();
|
||||||
|
|
||||||
|
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
|
||||||
|
GuiResourceId pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
|
||||||
|
if (_pictureId != pictureId) {
|
||||||
|
_pictureId = pictureId;
|
||||||
|
_pictureChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
|
||||||
|
_back = readSelectorValue(segMan, object, SELECTOR(back));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark PlaneList
|
||||||
|
void PlaneList::clear() {
|
||||||
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaneListBase::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaneList::erase(Plane *plane) {
|
||||||
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
|
if (*it == plane) {
|
||||||
|
erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlaneList::findIndexByObject(const reg_t object) const {
|
||||||
|
for (size_type i = 0; i < size(); ++i) {
|
||||||
|
if ((*this)[i] != nullptr && (*this)[i]->_object == object) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plane *PlaneList::findByObject(const reg_t object) const {
|
||||||
|
const_iterator planeIt = Common::find_if(begin(), end(), FindByObject<Plane *>(object));
|
||||||
|
|
||||||
|
if (planeIt == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *planeIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 PlaneList::getTopPlanePriority() const {
|
||||||
|
if (size() > 0) {
|
||||||
|
return (*this)[size() - 1]->_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 PlaneList::getTopSciPlanePriority() const {
|
||||||
|
int16 priority = 0;
|
||||||
|
|
||||||
|
for (const_iterator it = begin(); it != end(); ++it) {
|
||||||
|
if ((*it)->_priority >= 10000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
priority = (*it)->_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaneList::add(Plane *plane) {
|
||||||
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
|
if ((*it)->_priority < plane->_priority) {
|
||||||
|
insert(it, plane);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push_back(plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
465
engines/sci/graphics/plane32.h
Normal file
465
engines/sci/graphics/plane32.h
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
/* 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_PLANE32_H
|
||||||
|
#define SCI_GRAPHICS_PLANE32_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "sci/engine/vm_types.h"
|
||||||
|
#include "sci/graphics/helpers.h"
|
||||||
|
#include "sci/graphics/lists32.h"
|
||||||
|
#include "sci/graphics/screen_item32.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
enum PlaneType {
|
||||||
|
kPlaneTypeColored = 0,
|
||||||
|
kPlaneTypePicture = 1,
|
||||||
|
kPlaneTypeTransparent = 2,
|
||||||
|
kPlaneTypeOpaque = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PlanePictureCodes {
|
||||||
|
// NOTE: Any value at or below 65532 means the plane
|
||||||
|
// is a kPlaneTypePicture.
|
||||||
|
kPlanePic = 65532,
|
||||||
|
kPlanePicOpaque = 65533,
|
||||||
|
kPlanePicTransparent = 65534,
|
||||||
|
kPlanePicColored = 65535
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark RectList
|
||||||
|
|
||||||
|
typedef StablePointerArray<Common::Rect, 200> RectListBase;
|
||||||
|
class RectList : public RectListBase {
|
||||||
|
public:
|
||||||
|
void add(const Common::Rect &rect) {
|
||||||
|
RectListBase::add(new Common::Rect(rect));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark DrawList
|
||||||
|
|
||||||
|
struct DrawItem {
|
||||||
|
ScreenItem *screenItem;
|
||||||
|
Common::Rect rect;
|
||||||
|
|
||||||
|
inline bool operator<(const DrawItem &other) const {
|
||||||
|
return *screenItem < *other.screenItem;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef StablePointerArray<DrawItem, 250> DrawListBase;
|
||||||
|
class DrawList : public DrawListBase {
|
||||||
|
private:
|
||||||
|
inline static bool sortHelper(const DrawItem *a, const DrawItem *b) {
|
||||||
|
return *a < *b;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void add(ScreenItem *screenItem, const Common::Rect &rect);
|
||||||
|
inline void sort() {
|
||||||
|
pack();
|
||||||
|
Common::sort(begin(), end(), sortHelper);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlaneList;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plane is a grouped layer of screen items.
|
||||||
|
*/
|
||||||
|
class Plane {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* A serial used for planes that are generated inside
|
||||||
|
* the graphics engine, rather than the interpreter.
|
||||||
|
*/
|
||||||
|
static uint16 _nextObjectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimensions of the plane, in game script
|
||||||
|
* coordinates.
|
||||||
|
* TODO: These are never used and are always
|
||||||
|
* scriptWidth x scriptHeight in SCI engine? The actual
|
||||||
|
* dimensions of the plane are always in
|
||||||
|
* gameRect/planeRect.
|
||||||
|
*/
|
||||||
|
int16 _width, _height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For planes that are used to render picture data, the
|
||||||
|
* resource ID of the picture to be displayed. This
|
||||||
|
* value may also be one of the special
|
||||||
|
* PlanePictureCodes, in which case the plane becomes a
|
||||||
|
* non-picture plane.
|
||||||
|
*/
|
||||||
|
GuiResourceId _pictureId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the contents of picture planes should
|
||||||
|
* be drawn horizontally mirrored. Only applies to
|
||||||
|
* planes of type kPlaneTypePicture.
|
||||||
|
*/
|
||||||
|
bool _mirrored;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the picture ID for this plane has changed.
|
||||||
|
* This flag is set when the plane is created or updated
|
||||||
|
* from a VM object, and is cleared when the plane is
|
||||||
|
* synchronised to another plane (which calls
|
||||||
|
* changePic).
|
||||||
|
*/
|
||||||
|
bool _pictureChanged; // ?
|
||||||
|
|
||||||
|
// TODO: Are these ever actually used?
|
||||||
|
int _field_34, _field_38; // probably a point or ratio
|
||||||
|
int _field_3C, _field_40; // probably a point or ratio
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the dimensions of the game rect used by
|
||||||
|
* scripts to the dimensions of the plane rect used to
|
||||||
|
* render content to the screen. Coordinates with
|
||||||
|
* remainders are rounded up to the next whole pixel.
|
||||||
|
*/
|
||||||
|
void convertGameRectToPlaneRect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of the plane according to its assigned
|
||||||
|
* picture resource ID.
|
||||||
|
*/
|
||||||
|
void setType();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The colour to use when erasing the plane. Only
|
||||||
|
* applies to planes of type kPlaneTypeColored.
|
||||||
|
*/
|
||||||
|
byte _back;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the priority of this plane has changed.
|
||||||
|
* This flag is set when the plane is updated from
|
||||||
|
* another plane and cleared when draw list calculation
|
||||||
|
* occurs.
|
||||||
|
*/
|
||||||
|
int _priorityChanged; // ?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle to the VM object corresponding to this
|
||||||
|
* plane. Some planes are generated purely within the
|
||||||
|
* graphics engine and have a numeric object value.
|
||||||
|
*/
|
||||||
|
reg_t _object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rendering priority of the plane. Higher
|
||||||
|
* priorities are drawn above lower priorities.
|
||||||
|
*/
|
||||||
|
int16 _priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document
|
||||||
|
*/
|
||||||
|
int _redrawAllCount;
|
||||||
|
|
||||||
|
PlaneType _type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags indicating the state of the plane.
|
||||||
|
* - `created` is set when the plane is first created,
|
||||||
|
* either from a VM object or from within the engine
|
||||||
|
* itself
|
||||||
|
* - `updated` is set when the plane is updated from
|
||||||
|
* another plane and the two planes' `planeRect`s do
|
||||||
|
* not match
|
||||||
|
* - `deleted` is set when the plane is deleted by a
|
||||||
|
* kernel call
|
||||||
|
* - `moved` is set when the plane is synchronised from
|
||||||
|
* another plane and is not already in the "created"
|
||||||
|
* state
|
||||||
|
*/
|
||||||
|
int _created, _updated, _deleted, _moved;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The vanishing point for the plane. Used when
|
||||||
|
* calculating the correct scaling of the plane's screen
|
||||||
|
* items according to their position.
|
||||||
|
*/
|
||||||
|
Common::Point _vanishingPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position & dimensions of the plane in screen
|
||||||
|
* coordinates. This rect is not clipped to the screen,
|
||||||
|
* so may include coordinates that are offscreen.
|
||||||
|
*/
|
||||||
|
Common::Rect _planeRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position & dimensions of the plane in game script
|
||||||
|
* coordinates.
|
||||||
|
*/
|
||||||
|
Common::Rect _gameRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position & dimensions of the plane in screen
|
||||||
|
* coordinates. This rect is clipped to the screen.
|
||||||
|
*/
|
||||||
|
Common::Rect _screenRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of screen items grouped within this plane.
|
||||||
|
*/
|
||||||
|
ScreenItemList _screenItemList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initialises static Plane members.
|
||||||
|
*/
|
||||||
|
static void init();
|
||||||
|
|
||||||
|
Plane(const Common::Rect &gameRect);
|
||||||
|
Plane(const reg_t object);
|
||||||
|
Plane(const Plane &other);
|
||||||
|
void operator=(const Plane &other);
|
||||||
|
inline bool operator<(const Plane &other) const {
|
||||||
|
// TODO: In SCI engine, _object is actually a uint16 and can either
|
||||||
|
// contain a MemID (a handle to MemoryMgr, similar to reg_t) or
|
||||||
|
// a serial (Plane::_nextObjectId). These numbers can be compared
|
||||||
|
// directly in the real engine and the lowest MemID wins, but in
|
||||||
|
// ScummVM reg_t pointers are not comparable so we have to use a
|
||||||
|
// different strategy when two planes generated by scripts conflict.
|
||||||
|
// For now we just don't check if the priority is below 0, since
|
||||||
|
// that priority is used to represent hidden planes and is guaranteed
|
||||||
|
// to generate conflicts with script-generated planes. If there are
|
||||||
|
// other future conflicts with script-generated planes then we need
|
||||||
|
// to come up with a solution that works, similar to
|
||||||
|
// reg_t::pointerComparisonWithInteger used by SCI16.
|
||||||
|
return _priority < other._priority || (_priority == other._priority && _priority > -1 && _object < other._object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clips the screen rect of this plane to fit within the
|
||||||
|
* given screen rect.
|
||||||
|
*/
|
||||||
|
inline void clipScreenRect(const Common::Rect &screenRect) {
|
||||||
|
if (_screenRect.intersects(screenRect)) {
|
||||||
|
_screenRect.clip(screenRect);
|
||||||
|
} else {
|
||||||
|
_screenRect.left = 0;
|
||||||
|
_screenRect.top = 0;
|
||||||
|
_screenRect.right = 0;
|
||||||
|
_screenRect.bottom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printDebugInfo(Console *con) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the properties of the current plane against
|
||||||
|
* the properties of the `other` plane (which is the
|
||||||
|
* corresponding plane from the visible plane list) to
|
||||||
|
* discover which properties have been changed on this
|
||||||
|
* plane by a call to `update(reg_t)`.
|
||||||
|
*
|
||||||
|
* @note This method was originally called UpdatePlane
|
||||||
|
* in SCI engine.
|
||||||
|
*/
|
||||||
|
void sync(const Plane *other, const Common::Rect &screenRect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the plane to match the state of the plane
|
||||||
|
* object from the virtual machine.
|
||||||
|
*
|
||||||
|
* @note This method was originally called UpdatePlane
|
||||||
|
* in SCI engine.
|
||||||
|
*/
|
||||||
|
void update(const reg_t object);
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane - Pic
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Adds all cels from the specified picture resource to
|
||||||
|
* the plane as screen items. If a position is provided,
|
||||||
|
* the screen items will be given that position;
|
||||||
|
* otherwise, the default relative positions for each
|
||||||
|
* cel will be taken from the picture resource data.
|
||||||
|
*/
|
||||||
|
inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the plane is a picture plane, re-adds all cels
|
||||||
|
* from its picture resource to the plane.
|
||||||
|
*/
|
||||||
|
void changePic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks all screen items to be deleted that are within
|
||||||
|
* this plane and match the given picture ID.
|
||||||
|
*/
|
||||||
|
void deletePic(const GuiResourceId pictureId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks all screen items to be deleted that are within
|
||||||
|
* this plane and match the given picture ID, then sets
|
||||||
|
* the picture ID of the plane to the new picture ID
|
||||||
|
* without adding any screen items.
|
||||||
|
*/
|
||||||
|
void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks all screen items to be deleted that are within
|
||||||
|
* this plane and are picture cels.
|
||||||
|
*/
|
||||||
|
void deleteAllPics();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Marks all existing screen items matching the current
|
||||||
|
* picture to be deleted, then adds all cels from the
|
||||||
|
* new picture resource to the plane at the given
|
||||||
|
* position.
|
||||||
|
*/
|
||||||
|
void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Plane - Rendering
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Splits all rects in the given draw list at the edges
|
||||||
|
* of all non-transparent planes above the current
|
||||||
|
* plane.
|
||||||
|
*/
|
||||||
|
void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits all rects in the given erase list rects at the
|
||||||
|
* edges of all non-transparent planes above the current
|
||||||
|
* plane.
|
||||||
|
*/
|
||||||
|
void breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronises changes to screen items from the current
|
||||||
|
* plane to the visible plane and deletes screen items
|
||||||
|
* from the current plane that have been marked as
|
||||||
|
* deleted. If `forceUpdate` is true, all screen items
|
||||||
|
* on the visible plane will be updated, even if they
|
||||||
|
* are not marked as having changed.
|
||||||
|
*/
|
||||||
|
void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the screen item from this plane at the given
|
||||||
|
* index into the given draw list, clipped to the given
|
||||||
|
* rect. TODO: Finish documenting
|
||||||
|
*/
|
||||||
|
void mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given rect into the given rect list,
|
||||||
|
* merging it with other rects already inside the list,
|
||||||
|
* if possible, to avoid overdraw. TODO: Finish
|
||||||
|
* documenting
|
||||||
|
*/
|
||||||
|
void mergeToRectList(const Common::Rect &rect, RectList &rectList) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Calculates the location and dimensions of dirty rects
|
||||||
|
* of the screen items in this plane and adds them to
|
||||||
|
* the given draw and erase lists, and synchronises this
|
||||||
|
* plane's list of screen items to the given visible
|
||||||
|
* plane.
|
||||||
|
*/
|
||||||
|
void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
void filterUpEraseRects(DrawList &drawList, RectList &eraseList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
void filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all of the plane's non-deleted screen items
|
||||||
|
* and adds them to the given draw and erase lists.
|
||||||
|
*/
|
||||||
|
void redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark PlaneList
|
||||||
|
|
||||||
|
typedef Common::Array<Plane *> PlaneListBase;
|
||||||
|
class PlaneList : public PlaneListBase {
|
||||||
|
private:
|
||||||
|
inline static bool sortHelper(const Plane *a, const Plane *b) {
|
||||||
|
return *a < *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
using PlaneListBase::push_back;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// A method for finding the index of a plane inside a
|
||||||
|
// PlaneList is used because entries in the main plane
|
||||||
|
// list and visible plane list of GfxFrameout are
|
||||||
|
// synchronised by index
|
||||||
|
int findIndexByObject(const reg_t object) const;
|
||||||
|
Plane *findByObject(const reg_t object) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority of the top plane in the plane list.
|
||||||
|
*/
|
||||||
|
int16 getTopPlanePriority() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority of the top plane in the plane list
|
||||||
|
* created by a game script.
|
||||||
|
*/
|
||||||
|
int16 getTopSciPlanePriority() const;
|
||||||
|
|
||||||
|
void add(Plane *plane);
|
||||||
|
void clear();
|
||||||
|
using PlaneListBase::erase;
|
||||||
|
void erase(Plane *plane);
|
||||||
|
inline void sort() {
|
||||||
|
Common::sort(begin(), end(), sortHelper);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -76,6 +76,11 @@ public:
|
||||||
byte getColorWhite() { return _colorWhite; }
|
byte getColorWhite() { return _colorWhite; }
|
||||||
byte getColorDefaultVectorData() { return _colorDefaultVectorData; }
|
byte getColorDefaultVectorData() { return _colorDefaultVectorData; }
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
byte *getDisplayScreen() { return _displayScreen; }
|
||||||
|
byte *getPriorityScreen() { return _priorityScreen; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void clearForRestoreGame();
|
void clearForRestoreGame();
|
||||||
void copyToScreen();
|
void copyToScreen();
|
||||||
void copyFromScreen(byte *buffer);
|
void copyFromScreen(byte *buffer);
|
||||||
|
|
534
engines/sci/graphics/screen_item32.cpp
Normal file
534
engines/sci/graphics/screen_item32.cpp
Normal file
|
@ -0,0 +1,534 @@
|
||||||
|
/* 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/console.h"
|
||||||
|
#include "sci/resource.h"
|
||||||
|
#include "sci/engine/kernel.h"
|
||||||
|
#include "sci/engine/selector.h"
|
||||||
|
#include "sci/engine/state.h"
|
||||||
|
#include "sci/graphics/celobj32.h"
|
||||||
|
#include "sci/graphics/frameout.h"
|
||||||
|
#include "sci/graphics/screen_item32.h"
|
||||||
|
#include "sci/graphics/view.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
#pragma mark ScreenItem
|
||||||
|
|
||||||
|
uint16 ScreenItem::_nextObjectId = 20000;
|
||||||
|
|
||||||
|
ScreenItem::ScreenItem(const reg_t object) :
|
||||||
|
_mirrorX(false),
|
||||||
|
_pictureId(-1),
|
||||||
|
_celObj(nullptr),
|
||||||
|
_object(object),
|
||||||
|
_deleted(0),
|
||||||
|
_updated(0),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()) {
|
||||||
|
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||||
|
|
||||||
|
setFromObject(segMan, object, true, true);
|
||||||
|
_plane = readSelector(segMan, object, SELECTOR(plane));
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo) :
|
||||||
|
_position(0, 0),
|
||||||
|
_z(0),
|
||||||
|
_object(make_reg(0, _nextObjectId++)),
|
||||||
|
_celInfo(celInfo),
|
||||||
|
_plane(plane),
|
||||||
|
_celObj(nullptr),
|
||||||
|
_useInsetRect(false),
|
||||||
|
_fixPriority(false),
|
||||||
|
_mirrorX(false),
|
||||||
|
_pictureId(-1),
|
||||||
|
_updated(0),
|
||||||
|
_deleted(0),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()) {}
|
||||||
|
|
||||||
|
ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) :
|
||||||
|
_position(rect.left, rect.top),
|
||||||
|
_z(0),
|
||||||
|
_object(make_reg(0, _nextObjectId++)),
|
||||||
|
_celInfo(celInfo),
|
||||||
|
_plane(plane),
|
||||||
|
_celObj(nullptr),
|
||||||
|
_useInsetRect(false),
|
||||||
|
_fixPriority(false),
|
||||||
|
_mirrorX(false),
|
||||||
|
_pictureId(-1),
|
||||||
|
_updated(0),
|
||||||
|
_deleted(0),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()) {
|
||||||
|
if (celInfo.type == kCelTypeColor) {
|
||||||
|
_insetRect = rect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo) :
|
||||||
|
_position(rect.left, rect.top),
|
||||||
|
_z(0),
|
||||||
|
_object(make_reg(0, _nextObjectId++)),
|
||||||
|
_celInfo(celInfo),
|
||||||
|
_plane(plane),
|
||||||
|
_celObj(nullptr),
|
||||||
|
_useInsetRect(false),
|
||||||
|
_fixPriority(false),
|
||||||
|
_mirrorX(false),
|
||||||
|
_pictureId(-1),
|
||||||
|
_updated(0),
|
||||||
|
_deleted(0),
|
||||||
|
_created(g_sci->_gfxFrameout->getScreenCount()),
|
||||||
|
_scale(scaleInfo) {}
|
||||||
|
|
||||||
|
ScreenItem::ScreenItem(const ScreenItem &other) :
|
||||||
|
_object(other._object),
|
||||||
|
_plane(other._plane),
|
||||||
|
_celInfo(other._celInfo),
|
||||||
|
_celObj(nullptr),
|
||||||
|
_screenRect(other._screenRect),
|
||||||
|
_mirrorX(other._mirrorX),
|
||||||
|
_useInsetRect(other._useInsetRect),
|
||||||
|
_scale(other._scale),
|
||||||
|
_scaledPosition(other._scaledPosition) {
|
||||||
|
if (other._useInsetRect) {
|
||||||
|
_insetRect = other._insetRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::operator=(const ScreenItem &other) {
|
||||||
|
_celInfo = other._celInfo;
|
||||||
|
_screenRect = other._screenRect;
|
||||||
|
_mirrorX = other._mirrorX;
|
||||||
|
_useInsetRect = other._useInsetRect;
|
||||||
|
if (other._useInsetRect) {
|
||||||
|
_insetRect = other._insetRect;
|
||||||
|
}
|
||||||
|
_scale = other._scale;
|
||||||
|
_scaledPosition = other._scaledPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::init() {
|
||||||
|
_nextObjectId = 20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap) {
|
||||||
|
_position.x = readSelectorValue(segMan, object, SELECTOR(x));
|
||||||
|
_position.y = readSelectorValue(segMan, object, SELECTOR(y));
|
||||||
|
_scale.x = readSelectorValue(segMan, object, SELECTOR(scaleX));
|
||||||
|
_scale.y = readSelectorValue(segMan, object, SELECTOR(scaleY));
|
||||||
|
_scale.max = readSelectorValue(segMan, object, SELECTOR(maxScale));
|
||||||
|
_scale.signal = (ScaleSignals32)(readSelectorValue(segMan, object, SELECTOR(scaleSignal)) & 3);
|
||||||
|
|
||||||
|
if (updateCel) {
|
||||||
|
_celInfo.resourceId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(view));
|
||||||
|
_celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
|
||||||
|
_celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));
|
||||||
|
|
||||||
|
if (_celInfo.resourceId <= kPlanePic) {
|
||||||
|
// TODO: Enhance GfxView or ResourceManager to allow
|
||||||
|
// metadata for resources to be retrieved once, from a
|
||||||
|
// single location
|
||||||
|
Resource *view = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _celInfo.resourceId), false);
|
||||||
|
if (!view) {
|
||||||
|
error("Failed to load resource %d", _celInfo.resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: +2 because the header size field itself is excluded from
|
||||||
|
// the header size in the data
|
||||||
|
const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2;
|
||||||
|
const uint8 loopCount = view->data[2];
|
||||||
|
const uint8 loopSize = view->data[12];
|
||||||
|
|
||||||
|
if (_celInfo.loopNo >= loopCount) {
|
||||||
|
const int maxLoopNo = loopCount - 1;
|
||||||
|
_celInfo.loopNo = maxLoopNo;
|
||||||
|
writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize);
|
||||||
|
const int8 seekEntry = loopData[0];
|
||||||
|
if (seekEntry != -1) {
|
||||||
|
loopData = view->data + headerSize + (seekEntry * loopSize);
|
||||||
|
}
|
||||||
|
const uint8 celCount = loopData[2];
|
||||||
|
if (_celInfo.celNo >= celCount) {
|
||||||
|
const int maxCelNo = celCount - 1;
|
||||||
|
_celInfo.celNo = maxCelNo;
|
||||||
|
writeSelectorValue(segMan, object, SELECTOR(cel), maxCelNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateBitmap) {
|
||||||
|
const reg_t bitmap = readSelector(segMan, object, SELECTOR(bitmap));
|
||||||
|
if (!bitmap.isNull()) {
|
||||||
|
_celInfo.bitmap = bitmap;
|
||||||
|
_celInfo.type = kCelTypeMem;
|
||||||
|
} else {
|
||||||
|
_celInfo.bitmap = NULL_REG;
|
||||||
|
_celInfo.type = kCelTypeView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateCel || updateBitmap) {
|
||||||
|
delete _celObj;
|
||||||
|
_celObj = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
|
||||||
|
_fixPriority = true;
|
||||||
|
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
|
||||||
|
} else {
|
||||||
|
_fixPriority = false;
|
||||||
|
writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
_z = readSelectorValue(segMan, object, SELECTOR(z));
|
||||||
|
_position.y -= _z;
|
||||||
|
|
||||||
|
if (readSelectorValue(segMan, object, SELECTOR(useInsetRect))) {
|
||||||
|
_useInsetRect = true;
|
||||||
|
_insetRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
|
||||||
|
_insetRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
|
||||||
|
_insetRect.right = readSelectorValue(segMan, object, SELECTOR(inRight));
|
||||||
|
_insetRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom));
|
||||||
|
} else {
|
||||||
|
_useInsetRect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: SCI2.1/SQ6 engine clears this flag any time ScreenItem::Update(MemID)
|
||||||
|
// or ScreenItem::ScreenItem(MemID) are called, but doing this breaks
|
||||||
|
// view cycling because the flag isn't being set again later. There are over
|
||||||
|
// 100 places in the engine code where this flag is set, so it is probably
|
||||||
|
// a matter of figuring out what all of those calls are that re-set it. For
|
||||||
|
// now, since these are the *only* calls that clear this flag, we can just
|
||||||
|
// leave it set all the time.
|
||||||
|
// segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::calcRects(const Plane &plane) {
|
||||||
|
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
||||||
|
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
||||||
|
const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
|
||||||
|
const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
|
||||||
|
|
||||||
|
Common::Rect celRect(_celObj->_width, _celObj->_height);
|
||||||
|
if (_useInsetRect) {
|
||||||
|
if (_insetRect.intersects(celRect)) {
|
||||||
|
_insetRect.clip(celRect);
|
||||||
|
} else {
|
||||||
|
_insetRect = Common::Rect();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_insetRect = celRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ratio newRatioX;
|
||||||
|
Ratio newRatioY;
|
||||||
|
|
||||||
|
if (_scale.signal & kScaleSignalDoScaling32) {
|
||||||
|
if (_scale.signal & kScaleSignalUseVanishingPoint) {
|
||||||
|
int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y);
|
||||||
|
newRatioX = Ratio(num, 128);
|
||||||
|
newRatioY = Ratio(num, 128);
|
||||||
|
} else {
|
||||||
|
newRatioX = Ratio(_scale.x, 128);
|
||||||
|
newRatioY = Ratio(_scale.y, 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newRatioX.getNumerator() && newRatioY.getNumerator()) {
|
||||||
|
_screenItemRect = _insetRect;
|
||||||
|
|
||||||
|
if (_celObj->_scaledWidth != scriptWidth || _celObj->_scaledHeight != scriptHeight) {
|
||||||
|
if (_useInsetRect) {
|
||||||
|
Ratio celScriptXRatio(_celObj->_scaledWidth, scriptWidth);
|
||||||
|
Ratio celScriptYRatio(_celObj->_scaledHeight, scriptHeight);
|
||||||
|
mulru(_screenItemRect, celScriptXRatio, celScriptYRatio);
|
||||||
|
|
||||||
|
if (_screenItemRect.intersects(celRect)) {
|
||||||
|
_screenItemRect.clip(celRect);
|
||||||
|
} else {
|
||||||
|
_screenItemRect = Common::Rect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int displaceX = _celObj->_displace.x;
|
||||||
|
int displaceY = _celObj->_displace.y;
|
||||||
|
|
||||||
|
if (_mirrorX != _celObj->_mirrorX && _celInfo.type != kCelTypePic) {
|
||||||
|
displaceX = _celObj->_width - _celObj->_displace.x - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newRatioX.isOne() || !newRatioY.isOne()) {
|
||||||
|
mulru(_screenItemRect, newRatioX, newRatioY);
|
||||||
|
displaceX = (displaceX * newRatioX).toInt();
|
||||||
|
displaceY = (displaceY * newRatioY).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ratio celXRatio(screenWidth, _celObj->_scaledWidth);
|
||||||
|
Ratio celYRatio(screenHeight, _celObj->_scaledHeight);
|
||||||
|
|
||||||
|
displaceX = (displaceX * celXRatio).toInt();
|
||||||
|
displaceY = (displaceY * celYRatio).toInt();
|
||||||
|
|
||||||
|
mulru(_screenItemRect, celXRatio, celYRatio);
|
||||||
|
|
||||||
|
if (/* TODO: dword_C6288 */ false && _celInfo.type == kCelTypePic) {
|
||||||
|
_scaledPosition.x = _position.x;
|
||||||
|
_scaledPosition.y = _position.y;
|
||||||
|
} else {
|
||||||
|
_scaledPosition.x = (_position.x * screenWidth / scriptWidth) - displaceX;
|
||||||
|
_scaledPosition.y = (_position.y * screenHeight / scriptHeight) - displaceY;
|
||||||
|
}
|
||||||
|
|
||||||
|
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
|
||||||
|
|
||||||
|
if (_mirrorX != _celObj->_mirrorX && _celInfo.type == kCelTypePic) {
|
||||||
|
Common::Rect temp(_insetRect);
|
||||||
|
|
||||||
|
if (!newRatioX.isOne()) {
|
||||||
|
mulru(temp, newRatioX, Ratio());
|
||||||
|
}
|
||||||
|
|
||||||
|
mulru(temp, celXRatio, Ratio());
|
||||||
|
|
||||||
|
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
|
||||||
|
|
||||||
|
temp.translate(celObjPic->_relativePosition.x * screenWidth / scriptWidth - displaceX, 0);
|
||||||
|
|
||||||
|
// TODO: This is weird, and probably wrong calculation of widths
|
||||||
|
// due to BR-inclusion
|
||||||
|
int deltaX = plane._planeRect.right - plane._planeRect.left + 1 - temp.right - 1 - temp.left;
|
||||||
|
|
||||||
|
_scaledPosition.x += deltaX;
|
||||||
|
_screenItemRect.translate(deltaX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_scaledPosition.x += plane._planeRect.left;
|
||||||
|
_scaledPosition.y += plane._planeRect.top;
|
||||||
|
_screenItemRect.translate(plane._planeRect.left, plane._planeRect.top);
|
||||||
|
|
||||||
|
_ratioX = newRatioX * Ratio(screenWidth, _celObj->_scaledWidth);
|
||||||
|
_ratioY = newRatioY * Ratio(screenHeight, _celObj->_scaledHeight);
|
||||||
|
} else {
|
||||||
|
int displaceX = _celObj->_displace.x;
|
||||||
|
if (_mirrorX != _celObj->_mirrorX && _celInfo.type != kCelTypePic) {
|
||||||
|
displaceX = _celObj->_width - _celObj->_displace.x - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newRatioX.isOne() || !newRatioY.isOne()) {
|
||||||
|
mulru(_screenItemRect, newRatioX, newRatioY);
|
||||||
|
// TODO: This was in the original code, baked into the
|
||||||
|
// multiplication though it is not immediately clear
|
||||||
|
// why this is the only one that reduces the BR corner
|
||||||
|
_screenItemRect.right -= 1;
|
||||||
|
_screenItemRect.bottom -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_scaledPosition.x = _position.x - (displaceX * newRatioX).toInt();
|
||||||
|
_scaledPosition.y = _position.y - (_celObj->_displace.y * newRatioY).toInt();
|
||||||
|
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
|
||||||
|
|
||||||
|
if (_mirrorX != _celObj->_mirrorX && _celInfo.type == kCelTypePic) {
|
||||||
|
Common::Rect temp(_insetRect);
|
||||||
|
|
||||||
|
if (!newRatioX.isOne()) {
|
||||||
|
mulru(temp, newRatioX, Ratio());
|
||||||
|
temp.right -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
|
||||||
|
temp.translate(celObjPic->_relativePosition.x - (displaceX * newRatioX).toInt(), celObjPic->_relativePosition.y - (_celObj->_displace.y * newRatioY).toInt());
|
||||||
|
|
||||||
|
// TODO: This is weird, and probably wrong calculation of widths
|
||||||
|
// due to BR-inclusion
|
||||||
|
int deltaX = plane._gameRect.right - plane._gameRect.left + 1 - temp.right - 1 - temp.left;
|
||||||
|
|
||||||
|
_scaledPosition.x += deltaX;
|
||||||
|
_screenItemRect.translate(deltaX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_scaledPosition.x += plane._gameRect.left;
|
||||||
|
_scaledPosition.y += plane._gameRect.top;
|
||||||
|
_screenItemRect.translate(plane._gameRect.left, plane._gameRect.top);
|
||||||
|
|
||||||
|
if (screenWidth != _celObj->_scaledWidth || _celObj->_scaledHeight != screenHeight) {
|
||||||
|
Ratio celXRatio(screenWidth, _celObj->_scaledWidth);
|
||||||
|
Ratio celYRatio(screenHeight, _celObj->_scaledHeight);
|
||||||
|
mulru(_scaledPosition, celXRatio, celYRatio);
|
||||||
|
mulru(_screenItemRect, celXRatio, celYRatio, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ratioX = newRatioX * Ratio(screenWidth, _celObj->_scaledWidth);
|
||||||
|
_ratioY = newRatioY * Ratio(screenHeight, _celObj->_scaledHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
_screenRect = _screenItemRect;
|
||||||
|
|
||||||
|
if (_screenRect.intersects(plane._screenRect)) {
|
||||||
|
_screenRect.clip(plane._screenRect);
|
||||||
|
} else {
|
||||||
|
_screenRect.right = 0;
|
||||||
|
_screenRect.bottom = 0;
|
||||||
|
_screenRect.left = 0;
|
||||||
|
_screenRect.top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_fixPriority) {
|
||||||
|
_priority = _z + _position.y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_screenRect.left = 0;
|
||||||
|
_screenRect.top = 0;
|
||||||
|
_screenRect.right = 0;
|
||||||
|
_screenRect.bottom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CelObj &ScreenItem::getCelObj() {
|
||||||
|
if (_celObj == nullptr) {
|
||||||
|
switch (_celInfo.type) {
|
||||||
|
case kCelTypeView:
|
||||||
|
_celObj = new CelObjView(_celInfo.resourceId, _celInfo.loopNo, _celInfo.celNo);
|
||||||
|
break;
|
||||||
|
case kCelTypePic:
|
||||||
|
error("Internal error, pic screen item with no cel.");
|
||||||
|
break;
|
||||||
|
case kCelTypeMem:
|
||||||
|
_celObj = new CelObjMem(_celInfo.bitmap);
|
||||||
|
break;
|
||||||
|
case kCelTypeColor:
|
||||||
|
_celObj = new CelObjColor(_celInfo.color, _insetRect.width(), _insetRect.height());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *_celObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::printDebugInfo(Console *con) const {
|
||||||
|
con->debugPrintf("prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n",
|
||||||
|
_priority,
|
||||||
|
_position.x,
|
||||||
|
_position.y,
|
||||||
|
_z,
|
||||||
|
_scaledPosition.x,
|
||||||
|
_scaledPosition.y,
|
||||||
|
_created | (_updated << 1) | (_deleted << 2)
|
||||||
|
);
|
||||||
|
con->debugPrintf(" screen rect (%d, %d, %d, %d)\n", PRINT_RECT(_screenRect));
|
||||||
|
if (_useInsetRect) {
|
||||||
|
con->debugPrintf(" inset rect: (%d, %d, %d, %d)\n", PRINT_RECT(_insetRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String celType;
|
||||||
|
switch (_celInfo.type) {
|
||||||
|
case kCelTypePic:
|
||||||
|
celType = "pic";
|
||||||
|
break;
|
||||||
|
case kCelTypeView:
|
||||||
|
celType = "view";
|
||||||
|
break;
|
||||||
|
case kCelTypeColor:
|
||||||
|
celType = "color";
|
||||||
|
break;
|
||||||
|
case kCelTypeMem:
|
||||||
|
celType = "mem";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->debugPrintf(" type: %s, res %d, loop %d, cel %d, bitmap %04x:%04x, color: %d\n",
|
||||||
|
celType.c_str(),
|
||||||
|
_celInfo.resourceId,
|
||||||
|
_celInfo.loopNo,
|
||||||
|
_celInfo.celNo,
|
||||||
|
PRINT_REG(_celInfo.bitmap),
|
||||||
|
_celInfo.color
|
||||||
|
);
|
||||||
|
if (_celObj != nullptr) {
|
||||||
|
con->debugPrintf(" width %d, height %d, scaledWidth %d, scaledHeight %d\n",
|
||||||
|
_celObj->_width,
|
||||||
|
_celObj->_height,
|
||||||
|
_celObj->_scaledWidth,
|
||||||
|
_celObj->_scaledHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenItem::update(const reg_t object) {
|
||||||
|
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||||
|
|
||||||
|
const GuiResourceId view = readSelectorValue(segMan, object, SELECTOR(view));
|
||||||
|
const int16 loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
|
||||||
|
const int16 celNo = readSelectorValue(segMan, object, SELECTOR(cel));
|
||||||
|
|
||||||
|
const bool updateCel = (
|
||||||
|
_celInfo.resourceId != view ||
|
||||||
|
_celInfo.loopNo != loopNo ||
|
||||||
|
_celInfo.celNo != celNo
|
||||||
|
);
|
||||||
|
|
||||||
|
const bool updateBitmap = !readSelector(segMan, object, SELECTOR(bitmap)).isNull();
|
||||||
|
|
||||||
|
setFromObject(segMan, object, updateCel, updateBitmap);
|
||||||
|
|
||||||
|
if (!_created) {
|
||||||
|
_updated = g_sci->_gfxFrameout->getScreenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleted = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark ScreenItemList
|
||||||
|
ScreenItem *ScreenItemList::findByObject(const reg_t object) const {
|
||||||
|
const_iterator screenItemIt = Common::find_if(begin(), end(), FindByObject<ScreenItem *>(object));
|
||||||
|
|
||||||
|
if (screenItemIt == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *screenItemIt;
|
||||||
|
}
|
||||||
|
void ScreenItemList::sort() {
|
||||||
|
// TODO: SCI engine used _unsorted as an array of indexes into the
|
||||||
|
// list itself and then performed the same swap operations on the
|
||||||
|
// _unsorted array as the _storage array during sorting, but the
|
||||||
|
// only reason to do this would be if some of the pointers in the
|
||||||
|
// list were replaced so the pointer values themselves couldn’t
|
||||||
|
// simply be recorded and then restored later. It is not yet
|
||||||
|
// verified whether this simplification of the sort/unsort is
|
||||||
|
// safe.
|
||||||
|
for (size_type i = 0; i < size(); ++i) {
|
||||||
|
_unsorted[i] = (*this)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::sort(begin(), end(), sortHelper);
|
||||||
|
}
|
||||||
|
void ScreenItemList::unsort() {
|
||||||
|
for (size_type i = 0; i < size(); ++i) {
|
||||||
|
(*this)[i] = _unsorted[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
280
engines/sci/graphics/screen_item32.h
Normal file
280
engines/sci/graphics/screen_item32.h
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
/* 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_SCREEN_ITEM32_H
|
||||||
|
#define SCI_GRAPHICS_SCREEN_ITEM32_H
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "sci/graphics/celobj32.h"
|
||||||
|
#include "sci/graphics/lists32.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
|
||||||
|
enum ScaleSignals32 {
|
||||||
|
kScaleSignalNone = 0,
|
||||||
|
kScaleSignalDoScaling32 = 1, // enables scaling when drawing that cel (involves scaleX and scaleY)
|
||||||
|
kScaleSignalUseVanishingPoint = 2,
|
||||||
|
// TODO: Is this actually a thing? I have not seen it and
|
||||||
|
// the original engine masks &3 where it uses scale signals.
|
||||||
|
kScaleSignalDisableGlobalScaling32 = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScaleInfo {
|
||||||
|
int x, y, max;
|
||||||
|
ScaleSignals32 signal;
|
||||||
|
ScaleInfo() : x(128), y(128), max(100), signal(kScaleSignalNone) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CelObj;
|
||||||
|
class Plane;
|
||||||
|
class SegManager;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark ScreenItem
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ScreenItem is the engine-side representation of a
|
||||||
|
* game script View.
|
||||||
|
*/
|
||||||
|
class ScreenItem {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* A serial used for screen items that are generated
|
||||||
|
* inside the graphics engine, rather than the
|
||||||
|
* interpreter.
|
||||||
|
*/
|
||||||
|
static uint16 _nextObjectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent plane of this screen item.
|
||||||
|
*/
|
||||||
|
reg_t _plane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scaling data used to calculate the final screen
|
||||||
|
* dimensions of the screen item as well as the scaling
|
||||||
|
* ratios used when drawing the item to screen.
|
||||||
|
*/
|
||||||
|
ScaleInfo _scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position & dimensions of the screen item in
|
||||||
|
* screen coordinates. This rect includes the offset
|
||||||
|
* of the parent plane, but is not clipped to the
|
||||||
|
* screen, so may include coordinates that are
|
||||||
|
* offscreen.
|
||||||
|
*/
|
||||||
|
Common::Rect _screenItemRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document
|
||||||
|
*/
|
||||||
|
bool _useInsetRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
* The insetRect is also used to describe the fill
|
||||||
|
* rectangle of a screen item that is drawn using
|
||||||
|
* CelObjColor.
|
||||||
|
*/
|
||||||
|
Common::Rect _insetRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The z-index of the screen item in pseudo-3D space.
|
||||||
|
* Higher values are drawn on top of lower values.
|
||||||
|
*/
|
||||||
|
int _z;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the common properties of a screen item that must
|
||||||
|
* be set both during creation and update of a screen
|
||||||
|
* item.
|
||||||
|
*/
|
||||||
|
void setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* A descriptor for the cel object represented by the
|
||||||
|
* screen item.
|
||||||
|
*/
|
||||||
|
CelInfo32 _celInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cel object used to actually render the screen
|
||||||
|
* item. This member is populated by calling
|
||||||
|
* `getCelObj`.
|
||||||
|
*/
|
||||||
|
CelObj *_celObj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, the priority for this screen item is fixed
|
||||||
|
* in place. Otherwise, the priority of the screen item
|
||||||
|
* is calculated from its y-position + z-index.
|
||||||
|
*/
|
||||||
|
bool _fixPriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rendering priority of the screen item, relative
|
||||||
|
* only to the other screen items within the same plane.
|
||||||
|
* Higher priorities are drawn above lower priorities.
|
||||||
|
*/
|
||||||
|
int16 _priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top-left corner of the screen item, in game
|
||||||
|
* script coordinates, relative to the parent plane.
|
||||||
|
*/
|
||||||
|
Common::Point _position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated View script object that was
|
||||||
|
* used to create the ScreenItem, or a numeric
|
||||||
|
* value in the case of a ScreenItem that was
|
||||||
|
* generated outside of the VM.
|
||||||
|
*/
|
||||||
|
reg_t _object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For screen items representing picture resources,
|
||||||
|
* the resource ID of the picture.
|
||||||
|
*/
|
||||||
|
GuiResourceId _pictureId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags indicating the state of the screen item.
|
||||||
|
* - `created` is set when the screen item is first
|
||||||
|
* created, either from a VM object or from within the
|
||||||
|
* engine itself
|
||||||
|
* - `updated` is set when `created` is not already set
|
||||||
|
* and the screen item is updated from a VM object
|
||||||
|
* - `deleted` is set by the parent plane, if the parent
|
||||||
|
* plane is a pic type and its picture resource ID has
|
||||||
|
* changed
|
||||||
|
*/
|
||||||
|
int _created, _updated, _deleted; // ?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For screen items that represent picture cels, this
|
||||||
|
* value is set to match the `_mirrorX` property of the
|
||||||
|
* parent plane and indicates that the cel should be
|
||||||
|
* drawn horizontally mirrored. For final drawing, it is
|
||||||
|
* XORed with the `_mirrorX` property of the cel object.
|
||||||
|
* The cel object's `_mirrorX` property comes from the
|
||||||
|
* resource data itself.
|
||||||
|
*/
|
||||||
|
bool _mirrorX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scaling ratios to use when drawing this screen
|
||||||
|
* item. These values are calculated according to the
|
||||||
|
* scale info whenever the screen item is updated.
|
||||||
|
*/
|
||||||
|
Ratio _ratioX, _ratioY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top-left corner of the screen item, in screen
|
||||||
|
* coordinates.
|
||||||
|
*/
|
||||||
|
Common::Point _scaledPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position & dimensions of the screen item in
|
||||||
|
* screen coordinates. This rect includes the offset of
|
||||||
|
* the parent plane and is clipped to the screen.
|
||||||
|
*/
|
||||||
|
Common::Rect _screenRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises static Plane members.
|
||||||
|
*/
|
||||||
|
static void init();
|
||||||
|
|
||||||
|
ScreenItem(const reg_t screenItem);
|
||||||
|
ScreenItem(const reg_t plane, const CelInfo32 &celInfo);
|
||||||
|
ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect);
|
||||||
|
ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo);
|
||||||
|
ScreenItem(const ScreenItem &other);
|
||||||
|
void operator=(const ScreenItem &);
|
||||||
|
|
||||||
|
inline bool operator<(const ScreenItem &other) const {
|
||||||
|
if (_priority < other._priority) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_priority == other._priority) {
|
||||||
|
if (_position.y + _z < other._position.y + other._z) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_position.y + _z == other._position.y + other._z) {
|
||||||
|
return false;
|
||||||
|
// TODO: Failure in SQ6 room 220
|
||||||
|
// return _object < other._object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the dimensions and scaling parameters for
|
||||||
|
* the screen item, using the given plane as the parent
|
||||||
|
* plane for screen rect positioning.
|
||||||
|
*
|
||||||
|
* @note This method was called Update in SCI engine.
|
||||||
|
*/
|
||||||
|
void calcRects(const Plane &plane);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the corresponding cel object for this
|
||||||
|
* screen item. If a cel object does not already exist,
|
||||||
|
* one will be created and assigned.
|
||||||
|
*/
|
||||||
|
CelObj &getCelObj();
|
||||||
|
|
||||||
|
void printDebugInfo(Console *con) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the properties of the screen item from a
|
||||||
|
* VM object.
|
||||||
|
*/
|
||||||
|
void update(const reg_t object);
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark ScreenItemList
|
||||||
|
|
||||||
|
typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase;
|
||||||
|
class ScreenItemList : public ScreenItemListBase {
|
||||||
|
static bool inline sortHelper(const ScreenItem *a, const ScreenItem *b) {
|
||||||
|
return *a < *b;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
ScreenItem *_unsorted[250];
|
||||||
|
|
||||||
|
ScreenItem *findByObject(const reg_t object) const;
|
||||||
|
void sort();
|
||||||
|
void unsort();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -81,10 +81,13 @@ MODULE_OBJS := \
|
||||||
ifdef ENABLE_SCI32
|
ifdef ENABLE_SCI32
|
||||||
MODULE_OBJS += \
|
MODULE_OBJS += \
|
||||||
engine/kgraphics32.o \
|
engine/kgraphics32.o \
|
||||||
|
graphics/celobj32.o \
|
||||||
graphics/controls32.o \
|
graphics/controls32.o \
|
||||||
graphics/frameout.o \
|
graphics/frameout.o \
|
||||||
graphics/paint32.o \
|
graphics/paint32.o \
|
||||||
|
graphics/plane32.o \
|
||||||
graphics/palette32.o \
|
graphics/palette32.o \
|
||||||
|
graphics/screen_item32.o\
|
||||||
graphics/text32.o \
|
graphics/text32.o \
|
||||||
video/robot_decoder.o
|
video/robot_decoder.o
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -694,6 +694,7 @@ void SciEngine::initGraphics() {
|
||||||
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
|
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
|
||||||
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
|
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
|
||||||
_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32);
|
_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32);
|
||||||
|
_gfxFrameout->run();
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
// SCI0-SCI1.1 graphic objects creation
|
// SCI0-SCI1.1 graphic objects creation
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue