aboutsummaryrefslogtreecommitdiff
path: root/scumm/gfx.cpp
diff options
context:
space:
mode:
authorMax Horn2002-12-15 23:40:37 +0000
committerMax Horn2002-12-15 23:40:37 +0000
commit20c501ea587ac03167fca87b6cbccf2b51f1c135 (patch)
tree1224510a3193492f043a7e8b975034171aad3876 /scumm/gfx.cpp
parentcfc4bc586a732eb0c3c660e380d747c4f90eecd3 (diff)
downloadscummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.tar.gz
scummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.tar.bz2
scummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.zip
cleanup; reordering stuff in gfx.cpp, trying to group code into logical groups (cursor, bomp, camera, palette, fades)
svn-id: r5985
Diffstat (limited to 'scumm/gfx.cpp')
-rw-r--r--scumm/gfx.cpp1825
1 files changed, 910 insertions, 915 deletions
diff --git a/scumm/gfx.cpp b/scumm/gfx.cpp
index 4ecb60ee86..4e648e270c 100644
--- a/scumm/gfx.cpp
+++ b/scumm/gfx.cpp
@@ -26,11 +26,84 @@
#include "resource.h"
#include "util.h"
+
+#ifdef _MSC_VER
+# pragma warning( disable : 4068 ) // turn off "unknown pragma" warning
+#endif
+
+
enum {
kScrolltime = 500, // ms scrolling is supposed to take
kPictureDelay = 20
};
+#define NUM_SHAKE_POSITIONS 8
+static const int8 shake_positions[NUM_SHAKE_POSITIONS] = {
+ 0, 1 * 2, 2 * 2, 1 * 2, 0 * 2, 2 * 2, 3 * 2, 1 * 2
+};
+
+static const uint32 zplane_tags[] = {
+ MKID('ZP00'),
+ MKID('ZP01'),
+ MKID('ZP02'),
+ MKID('ZP03'),
+ MKID('ZP04')
+};
+
+static const int8 screen_eff7_table1[4][16] = {
+ { 1, 1, -1, 1, -1, 1, -1, -1,
+ 1, -1, -1, -1, 1, 1, 1, -1},
+ { 0, 1, 2, 1, 2, 0, 2, 1,
+ 2, 0, 2, 1, 0, 0, 0, 0},
+ {-2, -1, 0, -1, -2, -1, -2, 0, -2, -1, -2, 0, 0, 0, 0, 0},
+ { 0, -1, -2, -1, -2, 0, -2, -1, -2, 0, -2, -1, 0, 0, 0, 0}
+};
+
+static const byte screen_eff7_table2[4][16] = {
+ { 0, 0, 39, 0, 39, 0, 39, 24,
+ 0, 24, 39, 24, 0, 0, 0, 24},
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 255, 0, 0, 0},
+ {39, 24, 39, 24, 39, 24, 39, 24,
+ 38, 24, 38, 24, 255, 0, 0, 0},
+ { 0, 24, 39, 24, 39, 0, 39, 24,
+ 38, 0, 38, 24, 255, 0, 0, 0}
+};
+
+static const byte transition_num_of_iterations[4] = {
+ 13, 25, 25, 25
+};
+
+
+static const byte default_cursor_colors[4] = {
+ 15, 15, 7, 8
+};
+
+static const uint16 default_cursor_images[4][16] = {
+ /* cross-hair */
+ { 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f,
+ 0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 },
+ /* hourglass */
+ { 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0,
+ 0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 },
+ /* arrow */
+ { 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
+ 0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 },
+ /* hand */
+ { 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249,
+ 0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff },
+};
+
+static const byte default_cursor_hotspots[8] = {
+ 8, 7, 8, 7, 1, 1, 5, 0
+};
+
+
+static inline uint colorWeight(int red, int green, int blue)
+{
+ return 3 * red * red + 6 * green * green + 2 * blue * blue;
+}
+
void Scumm::getGraphicsPerformance()
{
int i;
@@ -131,6 +204,83 @@ void Scumm::initVirtScreen(int slot, int number, int top, int width, int height,
}
}
+VirtScreen *Scumm::findVirtScreen(int y)
+{
+ VirtScreen *vs = virtscr;
+ int i;
+
+ for (i = 0; i < 3; i++, vs++) {
+ if (y >= vs->topline && y < vs->topline + vs->height) {
+ return _curVirtScreen = vs;
+ }
+ }
+ return _curVirtScreen = NULL;
+}
+
+void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits)
+{
+ VirtScreen *vs = &virtscr[virt];
+ int lp, rp;
+ uint32 *sp;
+ int num;
+
+ if (top > vs->height || left > vs->width || right < 0 || bottom < 0)
+ return;
+
+ if (top < 0)
+ top = 0;
+ if (left < 0)
+ left = 0;
+ if (bottom > vs->height)
+ bottom = vs->height;
+ if (right > vs->width)
+ right = vs->width;
+
+ if (virt == 0 && dirtybits) {
+ rp = (right >> 3) + _screenStartStrip;
+ lp = (left >> 3) + _screenStartStrip;
+ if (lp < 0)
+ lp = 0;
+ if (_features & GF_AFTER_V7) {
+ if (rp > 409)
+ rp = 409;
+ } else {
+ if (rp >= 200)
+ rp = 200;
+ }
+ if (lp <= rp) {
+ num = rp - lp + 1;
+ sp = &gfxUsageBits[lp];
+ do {
+ *sp++ |= dirtybits;
+ } while (--num);
+ }
+ }
+
+ setVirtscreenDirty(vs, left, top, right, bottom);
+}
+
+void Scumm::setVirtscreenDirty(VirtScreen *vs, int left, int top, int right, int bottom)
+{
+ int lp = left >> 3;
+ int rp = right >> 3;
+
+ if ((lp >= gdi._numStrips) || (rp < 0))
+ return;
+ if (lp < 0)
+ lp = 0;
+ if (rp >= gdi._numStrips)
+ rp = gdi._numStrips - 1;
+
+ while (lp <= rp) {
+ if (top < vs->tdirty[lp])
+ vs->tdirty[lp] = top;
+ if (bottom > vs->bdirty[lp])
+ vs->bdirty[lp] = bottom;
+ lp++;
+ }
+}
+
void Scumm::setDirtyRange(int slot, int top, int bottom)
{
int i;
@@ -141,13 +291,6 @@ void Scumm::setDirtyRange(int slot, int top, int bottom)
}
}
-/* power of 2 */
-#define NUM_SHAKE_POSITIONS 8
-
-static const int8 shake_positions[NUM_SHAKE_POSITIONS] = {
- 0, 1 * 2, 2 * 2, 1 * 2, 0 * 2, 2 * 2, 3 * 2, 1 * 2
-};
-
void Scumm::drawDirtyScreenParts()
{
int i;
@@ -217,9 +360,9 @@ void Gdi::updateDirtyScreen(VirtScreen *vs)
continue;
}
if (_vm->_features & GF_AFTER_V7)
- drawStripToScreen(vs, start, w, 0, vs->height);
+ drawStripToScreen(vs, start * 8, w, 0, vs->height);
else
- drawStripToScreen(vs, start, w, top, bottom);
+ drawStripToScreen(vs, start * 8, w, top, bottom);
w = 8;
}
start = i + 1;
@@ -249,136 +392,59 @@ void Gdi::drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b)
assert(_vm->_screenTop >= 0);
scrollY = _vm->_screenTop;
- ptr = vs->screenPtr + (t * _numStrips + x) * 8 + _readOffs + scrollY * _vm->_realWidth;
- _vm->_system->copy_rect(ptr, _vm->_realWidth, x * 8, vs->topline + t, w, height);
+ ptr = vs->screenPtr + t * _numStrips * 8 + x + _readOffs + scrollY * _vm->_realWidth;
+ _vm->_system->copy_rect(ptr, _vm->_realWidth, x, vs->topline + t, w, height);
}
-void Scumm::blit(byte *dst, byte *src, int w, int h)
-{
- assert(h > 0);
- assert(src != NULL);
- assert(dst != NULL);
-
- do {
- memcpy(dst, src, w);
- dst += _realWidth;
- src += _realWidth;
- } while (--h);
-}
-
-void Scumm::setCursor(int cursor)
-{
- if (cursor >= 0 && cursor <= 3)
- _currentCursor = cursor;
- else
- warning("setCursor(%d)", cursor);
-}
-
-void Scumm::setCameraAtEx(int at)
+void Gdi::clearUpperMask()
{
- if (!(_features & GF_AFTER_V7)) {
- camera._mode = CM_NORMAL;
- camera._cur.x = at;
- setCameraAt(at, 0);
- camera._movingToActor = false;
- }
+ memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0]);
}
-void Scumm::setCameraAt(int pos_x, int pos_y)
+void Gdi::resetBackground(int top, int bottom, int strip)
{
- if (_features & GF_AFTER_V7) {
- ScummPoint old;
-
- old = camera._cur;
-
- camera._cur.x = pos_x;
- camera._cur.y = pos_y;
-
- clampCameraPos(&camera._cur);
-
- camera._dest = camera._cur;
-
- assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
-
- if ((camera._cur.x != old.x || camera._cur.y != old.y)
- && _vars[VAR_SCROLL_SCRIPT]) {
- _vars[VAR_CAMERA_POS_X] = camera._cur.x;
- _vars[VAR_CAMERA_POS_Y] = camera._cur.y;
- runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
- }
- } else {
- int t;
+ VirtScreen *vs = &_vm->virtscr[0];
+ int offs;
- if (camera._mode != CM_FOLLOW_ACTOR || abs(pos_x - camera._cur.x) > (_realWidth / 2)) {
- camera._cur.x = pos_x;
- }
- camera._dest.x = pos_x;
+ if (top < vs->tdirty[strip])
+ vs->tdirty[strip] = top;
- t = _vars[VAR_CAMERA_MIN_X];
- if (camera._cur.x < t)
- camera._cur.x = t;
+ if (bottom > vs->bdirty[strip])
+ vs->bdirty[strip] = bottom;
- t = _vars[VAR_CAMERA_MAX_X];
- if (camera._cur.x > t)
- camera._cur.x = t;
+ offs = (top * _numStrips + _vm->_screenStartStrip + strip);
+ _mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + offs;
+ _bgbak_ptr = _vm->getResourceAddress(rtBuffer, 5) + (offs << 3);
+ _backbuff_ptr = vs->screenPtr + (offs << 3);
- if (_vars[VAR_SCROLL_SCRIPT]) {
- _vars[VAR_CAMERA_POS_X] = camera._cur.x;
- runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ _numLinesToProcess = bottom - top;
+ if (_numLinesToProcess) {
+ if ((_vm->_features & GF_AFTER_V6) || (_vm->_vars[_vm->VAR_CURRENT_LIGHTS] & LIGHTMODE_screen)) {
+ if (_vm->hasCharsetMask(strip << 3, top, (strip + 1) << 3, bottom))
+ draw8ColWithMasking(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess, _mask_ptr);
+ else
+ draw8Col(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess);
+ } else {
+ clear8Col(_backbuff_ptr, _numLinesToProcess);
}
-
- if (camera._cur.x != camera._last.x && charset._hasMask)
- stopTalk();
}
}
-void Scumm::setCameraFollows(Actor *a)
+void Scumm::blit(byte *dst, byte *src, int w, int h)
{
- if (_features & GF_AFTER_V7) {
- byte oldfollow = camera._follows;
- int ax, ay;
-
- camera._follows = a->number;
-
- if (!a->isInCurrentRoom()) {
- startScene(a->getRoom(), 0, 0);
- }
-
- ax = abs(a->x - camera._cur.x);
- ay = abs(a->y - camera._cur.y);
-
- if (ax > _vars[VAR_CAMERA_THRESHOLD_X] || ay > _vars[VAR_CAMERA_THRESHOLD_Y] || ax > (_realWidth / 2) || ay > (_realHeight / 2)) {
- setCameraAt(a->x, a->y);
- }
-
- if (a->number != oldfollow)
- runHook(0);
- } else {
- int t, i;
-
- camera._mode = CM_FOLLOW_ACTOR;
- camera._follows = a->number;
-
- if (!a->isInCurrentRoom()) {
- startScene(a->getRoom(), 0, 0);
- camera._mode = CM_FOLLOW_ACTOR;
- camera._cur.x = a->x;
- setCameraAt(camera._cur.x, 0);
- }
-
- t = (a->x >> 3);
-
- if (t - _screenStartStrip < camera._leftTrigger || t - _screenStartStrip > camera._rightTrigger)
- setCameraAt(a->x, 0);
+ assert(h > 0);
+ assert(src != NULL);
+ assert(dst != NULL);
- for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) {
- if (a->isInCurrentRoom())
- a->needRedraw = true;
- }
- runHook(0);
- }
+ do {
+ memcpy(dst, src, w);
+ dst += _realWidth;
+ src += _realWidth;
+ } while (--h);
}
+#pragma mark -
+
void Scumm::initBGBuffers(int height)
{
byte *ptr;
@@ -427,183 +493,6 @@ void Scumm::initBGBuffers(int height)
}
}
-void Scumm::setPaletteFromPtr(byte *ptr)
-{
- int i;
- byte *dest, r, g, b;
- int numcolor;
-
- if (_features & GF_SMALL_HEADER) {
- if (_features & GF_OLD256)
- numcolor = 256;
- else
- numcolor = READ_LE_UINT16(ptr + 6) / 3;
- ptr += 8;
- } else {
- numcolor = getResourceDataSize(ptr) / 3;
- }
-
- checkRange(256, 0, numcolor, "Too many colors (%d) in Palette");
-
- dest = _currentPalette;
-
- for (i = 0; i < numcolor; i++) {
- r = *ptr++;
- g = *ptr++;
- b = *ptr++;
-
- // This comparison might look wierd, but it's what the disassembly (DOTT) says!
- // FIXME: Fingolfin still thinks it looks weird: the value 252 = 4*63 clearly comes from
- // the days 6/6/6 palettes were used, OK. But it breaks MonkeyVGA, so I had to add a
- // check for that. And somebody before me added a check for V7 games, turning this
- // off there, too... I wonder if it hurts other games, too? What exactly is broken
- // if we remove this patch?
- if ((_gameId == GID_MONKEY_VGA) || (_features & GF_AFTER_V7) || (i <= 15 || r < 252 || g < 252 || b < 252)) {
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- } else {
- dest += 3;
- }
- }
- setDirtyColors(0, numcolor - 1);
-}
-
-void Scumm::setPaletteFromRes()
-{
- byte *ptr;
- ptr = getResourceAddress(rtRoom, _roomResource) + _CLUT_offs;
- setPaletteFromPtr(ptr);
-}
-
-
-void Scumm::setDirtyColors(int min, int max)
-{
- if (_palDirtyMin > min)
- _palDirtyMin = min;
- if (_palDirtyMax < max)
- _palDirtyMax = max;
-}
-
-void Scumm::initCycl(byte *ptr)
-{
- int j;
- ColorCycle *cycl;
-
- memset(_colorCycle, 0, sizeof(_colorCycle));
-
- while ((j = *ptr++) != 0) {
- if (j < 1 || j > 16) {
- error("Invalid color cycle index %d", j);
- }
- cycl = &_colorCycle[j - 1];
-
- ptr += 2;
- cycl->counter = 0;
- cycl->delay = 16384 / READ_BE_UINT16_UNALIGNED(ptr);
- ptr += 2;
- cycl->flags = READ_BE_UINT16_UNALIGNED(ptr);
- ptr += 2;
- cycl->start = *ptr++;
- cycl->end = *ptr++;
- }
-}
-
-void Scumm::stopCycle(int i)
-{
- ColorCycle *cycl;
-
- checkRange(16, 0, i, "Stop Cycle %d Out Of Range");
- if (i != 0) {
- _colorCycle[i - 1].delay = 0;
- return;
- }
-
- for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++)
- cycl->delay = 0;
-}
-
-void Scumm::cyclePalette()
-{
- ColorCycle *cycl;
- int valueToAdd;
- int i, num;
- byte *start, *end;
- byte tmp[3];
-
- valueToAdd = _vars[VAR_TIMER];
- if (valueToAdd < _vars[VAR_TIMER_NEXT])
- valueToAdd = _vars[VAR_TIMER_NEXT];
-
- if (!_colorCycle) // FIXME
- return;
-
- for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) {
- if (cycl->delay && (cycl->counter += valueToAdd) >= cycl->delay) {
- do {
- cycl->counter -= cycl->delay;
- } while (cycl->delay <= cycl->counter);
-
- setDirtyColors(cycl->start, cycl->end);
- moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2);
- start = &_currentPalette[cycl->start * 3];
- end = &_currentPalette[cycl->end * 3];
-
- num = cycl->end - cycl->start;
-
- if (!(cycl->flags & 2)) {
- memmove(tmp, end, 3);
- memmove(start + 3, start, num * 3);
- memmove(start, tmp, 3);
- } else {
- memmove(tmp, start, 3);
- memmove(start, start + 3, num * 3);
- memmove(end, tmp, 3);
- }
- }
- }
-}
-
-// Perform color cycling on the palManipulate data, too, otherwise
-// color cycling will be disturbed by the palette fade.
-void Scumm::moveMemInPalRes(int start, int end, byte direction)
-{
- byte *startptr, *endptr;
- byte *startptr2, *endptr2;
- int num;
- byte tmp[6];
-
- if (!_palManipCounter)
- return;
-
- startptr = _palManipPalette + start * 3;
- endptr = _palManipPalette + end * 3;
- startptr2 = _palManipIntermediatePal + start * 6;
- endptr2 = _palManipIntermediatePal + end * 6;
- num = end - start;
-
- if (!endptr) {
- warning("moveMemInPalRes(%d,%d): Bad end pointer\n", start, end);
- return;
- }
-
- if (!direction) {
- memmove(tmp, endptr, 3);
- memmove(startptr + 3, startptr, num * 3);
- memmove(startptr, tmp, 3);
- memmove(tmp, endptr2, 6);
- memmove(startptr2 + 6, startptr2, num * 6);
- memmove(startptr2, tmp, 6);
- } else {
- memmove(tmp, startptr, 3);
- memmove(startptr, startptr + 3, num * 3);
- memmove(endptr, tmp, 3);
- memmove(tmp, startptr2, 6);
- memmove(startptr2, startptr2 + 6, num * 6);
- memmove(endptr2, tmp, 6);
- }
-}
-
void Scumm::drawFlashlight()
{
int i, j, offset, x, y;
@@ -643,8 +532,8 @@ void Scumm::drawFlashlight()
// Clip the flashlight at the borders
if (_flashlight.x < 0)
_flashlight.x = 0;
- else if (_flashlight.x + _flashlight.w > gdi._numStrips*8)
- _flashlight.x = gdi._numStrips*8 - _flashlight.w;
+ else if (_flashlight.x + _flashlight.w > gdi._numStrips * 8)
+ _flashlight.x = gdi._numStrips * 8 - _flashlight.w;
if (_flashlight.y < 0)
_flashlight.y = 0;
else if (_flashlight.y + _flashlight.h> virtscr[0].height)
@@ -685,84 +574,6 @@ void Scumm::drawFlashlight()
_flashlightIsDrawn = true;
}
-void Scumm::fadeIn(int effect)
-{
- switch (effect) {
- case 1:
- case 2:
- case 3:
- case 4:
- transitionEffect(effect - 1);
- break;
- case 128:
- unkScreenEffect6();
- break;
- case 130:
- case 131:
- case 132:
- case 133:
- scrollEffect(133 - effect);
- break;
- case 134:
- dissolveEffect(1, 1);
- break;
- case 135:
- unkScreenEffect5(1);
- break;
- case 129:
- break;
- default:
- warning("Unknown screen effect, %d", effect);
- }
- _screenEffectFlag = true;
-}
-
-void Scumm::fadeOut(int effect)
-{
- VirtScreen *vs;
-
- setDirtyRange(0, 0, 0);
- if (!(_features & GF_AFTER_V7))
- camera._last.x = camera._cur.x;
-
- if (!_screenEffectFlag)
- return;
- _screenEffectFlag = false;
-
- if (effect == 0)
- return;
-
- // Fill screen 0 with black
- vs = &virtscr[0];
- memset(vs->screenPtr + vs->xstart, 0, vs->size);
-
- // Fade to black with the specified effect, if any.
- switch (effect) {
- case 1:
- case 2:
- case 3:
- case 4:
- transitionEffect(effect - 1);
- break;
- case 128:
- unkScreenEffect6();
- break;
- case 129:
- // Just blit screen 0 to the display (i.e. display will be black)
- setDirtyRange(0, 0, vs->height);
- updateDirtyScreen(0);
- break;
- case 134:
- dissolveEffect(1, 1);
- break;
- case 135:
- unkScreenEffect5(1);
- break;
- default:
- warning("fadeOut: default case %d", effect);
- }
-}
-
void Scumm::redrawBGAreas()
{
int i;
@@ -814,13 +625,142 @@ void Scumm::redrawBGAreas()
_BgNeedsRedraw = false;
}
-static const uint32 zplane_tags[] = {
- MKID('ZP00'),
- MKID('ZP01'),
- MKID('ZP02'),
- MKID('ZP03'),
- MKID('ZP04')
-};
+void Scumm::redrawBGStrip(int start, int num)
+{
+ int s = _screenStartStrip + start;
+
+ assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0]));
+
+ _curVirtScreen = &virtscr[0];
+
+ for (int i = 0; i < num; i++)
+ gfxUsageBits[s + i] |= 0x80000000;
+
+ /*if (_curVirtScreen->height < _scrHeight) {
+ warning("Screen Y size %d < Room height %d",
+ _curVirtScreen->height,
+ _scrHeight);
+ } */
+
+ gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs,
+ _curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0);
+}
+
+void Scumm::restoreCharsetBg()
+{
+ if (gdi._mask_left != -1) {
+ restoreBG(gdi._mask_left, gdi._mask_top, gdi._mask_right, gdi._mask_bottom);
+ charset._hasMask = false;
+ gdi._mask_left = -1;
+ charset._strLeft = -1;
+ charset._left = -1;
+ }
+
+ charset._nextLeft = _string[0].xpos;
+ charset._nextTop = _string[0].ypos;
+}
+
+void Scumm::restoreBG(int left, int top, int right, int bottom, byte backColor)
+{
+ VirtScreen *vs;
+ int topline, height, width;
+ byte *backbuff, *bgbak;
+
+ if (left == right || top == bottom)
+ return;
+ if (top < 0)
+ top = 0;
+
+ if ((vs = findVirtScreen(top)) == NULL)
+ return;
+
+ topline = vs->topline;
+ height = topline + vs->height;
+
+// right++; // FIXME - why did we increment here?!? it caused bug
+ if (left < 0)
+ left = 0;
+ if (right < 0)
+ right = 0;
+ if (left > _realWidth)
+ return;
+ if (right > _realWidth)
+ right = _realWidth;
+ if (bottom >= height)
+ bottom = height;
+
+ updateDirtyRect(vs->number, left, right, top - topline, bottom - topline, 0x40000000);
+
+ int offset = (top - topline) * _realWidth + vs->xstart + left;
+ backbuff = vs->screenPtr + offset;
+ bgbak = getResourceAddress(rtBuffer, vs->number + 5) + offset;
+
+ height = bottom - top;
+ width = right - left;
+
+ if (vs->alloctwobuffers && _currentRoom != 0 /*&& _vars[VAR_V5_DRAWFLAGS]&2 */ ) {
+ blit(backbuff, bgbak, width, height);
+ if (vs->number == 0 && charset._hasMask && height) {
+ byte *mask;
+ int mask_width = (width >> 3);
+
+ if (width & 0x07)
+ mask_width++;
+
+ mask = getResourceAddress(rtBuffer, 9) + top * gdi._numStrips + (left >> 3) + _screenStartStrip;
+ if (vs->number == 0)
+ mask += vs->topline * gdi._numStrips;
+
+ do {
+ memset(mask, 0, mask_width);
+ mask += gdi._numStrips;
+ } while (--height);
+ }
+ } else {
+ while (height--) {
+ memset(backbuff, backColor, width);
+ backbuff += _realWidth;
+ }
+ }
+}
+
+int Scumm::hasCharsetMask(int x, int y, int x2, int y2)
+{
+ if (!charset._hasMask || y > gdi._mask_bottom || x > gdi._mask_right ||
+ y2 < gdi._mask_top || x2 < gdi._mask_left)
+ return 0;
+ return 1;
+}
+
+byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem)
+{
+ int w, h, i;
+
+ l >>= 3;
+ if (l < 0)
+ l = 0;
+ if (t < 0)
+ t = 0;
+
+ r >>= 3;
+ if (r > gdi._numStrips - 1)
+ r = gdi._numStrips - 1;
+
+ mem += l + t * gdi._numStrips;
+
+ w = r - l;
+ h = b - t + 1;
+
+ do {
+ for (i = 0; i <= w; i++)
+ if (mem[i]) {
+ return true;
+ }
+ mem += gdi._numStrips;
+ } while (--h);
+
+ return false;
+}
void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, int h,
int stripnr, int numstrip, byte flag)
@@ -1132,14 +1072,6 @@ void Gdi::decompressBitmap()
}
}
-int Scumm::hasCharsetMask(int x, int y, int x2, int y2)
-{
- if (!charset._hasMask || y > gdi._mask_bottom || x > gdi._mask_right ||
- y2 < gdi._mask_top || x2 < gdi._mask_left)
- return 0;
- return 1;
-}
-
void Gdi::draw8ColWithMasking(byte *dst, byte *src, int height, byte *mask)
{
byte maskbits;
@@ -1213,34 +1145,33 @@ void Gdi::clear8ColWithMasking(byte *dst, int height, byte *mask)
} while (--height);
}
-void Gdi::clear8Col(byte *dst, int height)
+
+void Gdi::draw8Col(byte *dst, byte *src, int height)
{
do {
#if defined(SCUMM_NEED_ALIGNMENT)
- memset(dst, 0, 8);
+ memcpy(dst, src, 8);
#else
- ((uint32 *)dst)[0] = 0;
- ((uint32 *)dst)[1] = 0;
+ ((uint32 *)dst)[0] = ((uint32 *)src)[0];
+ ((uint32 *)dst)[1] = ((uint32 *)src)[1];
#endif
dst += _vm->_realWidth;
+ src += _vm->_realWidth;
} while (--height);
}
-
-void Gdi::draw8Col(byte *dst, byte *src, int height)
+void Gdi::clear8Col(byte *dst, int height)
{
do {
#if defined(SCUMM_NEED_ALIGNMENT)
- memcpy(dst, src, 8);
+ memset(dst, 0, 8);
#else
- ((uint32 *)dst)[0] = ((uint32 *)src)[0];
- ((uint32 *)dst)[1] = ((uint32 *)src)[1];
+ ((uint32 *)dst)[0] = 0;
+ ((uint32 *)dst)[1] = 0;
#endif
dst += _vm->_realWidth;
- src += _vm->_realWidth;
} while (--height);
}
-
void Gdi::decompressMaskImg(byte *dst, byte *src, int height)
{
byte b, c;
@@ -1297,27 +1228,6 @@ void Gdi::decompressMaskImgOr(byte *dst, byte *src, int height)
}
}
-void Scumm::redrawBGStrip(int start, int num)
-{
- int s = _screenStartStrip + start;
-
- assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0]));
-
- _curVirtScreen = &virtscr[0];
-
- for (int i = 0; i < num; i++)
- gfxUsageBits[s + i] |= 0x80000000;
-
- /*if (_curVirtScreen->height < _scrHeight) {
- warning("Screen Y size %d < Room height %d",
- _curVirtScreen->height,
- _scrHeight);
- } */
-
- gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs,
- _curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0);
-}
-
#define READ_BIT (cl--,bit = bits&1, bits>>=1,bit)
#define FILL_BITS if (cl <= 8) { bits |= (*src++ << cl); cl += 8;}
@@ -1753,218 +1663,451 @@ void Gdi::unkDecode11()
} while (--_currentX);
}
-
#undef NEXT_ROW
#undef READ_256BIT
#undef READ_BIT
#undef FILL_BITS
-void Scumm::restoreCharsetBg()
+
+#pragma mark -
+#pragma mark ### Camera ###
+#pragma mark -
+
+void Scumm::setCameraAtEx(int at)
{
- if (gdi._mask_left != -1) {
- restoreBG(gdi._mask_left, gdi._mask_top, gdi._mask_right, gdi._mask_bottom);
- charset._hasMask = false;
- gdi._mask_left = -1;
- charset._strLeft = -1;
- charset._left = -1;
+ if (!(_features & GF_AFTER_V7)) {
+ camera._mode = CM_NORMAL;
+ camera._cur.x = at;
+ setCameraAt(at, 0);
+ camera._movingToActor = false;
}
-
- charset._nextLeft = _string[0].xpos;
- charset._nextTop = _string[0].ypos;
}
-void Scumm::restoreBG(int left, int top, int right, int bottom, byte backColor)
+void Scumm::setCameraAt(int pos_x, int pos_y)
{
- VirtScreen *vs;
- int topline, height, width;
- byte *backbuff, *bgbak;
+ if (_features & GF_AFTER_V7) {
+ ScummPoint old;
- if (left == right || top == bottom)
- return;
- if (top < 0)
- top = 0;
+ old = camera._cur;
- if ((vs = findVirtScreen(top)) == NULL)
- return;
+ camera._cur.x = pos_x;
+ camera._cur.y = pos_y;
- topline = vs->topline;
- height = topline + vs->height;
+ clampCameraPos(&camera._cur);
-// right++; // FIXME - why did we increment here?!? it caused bug
- if (left < 0)
- left = 0;
- if (right < 0)
- right = 0;
- if (left > _realWidth)
- return;
- if (right > _realWidth)
- right = _realWidth;
- if (bottom >= height)
- bottom = height;
+ camera._dest = camera._cur;
- updateDirtyRect(vs->number, left, right, top - topline, bottom - topline, 0x40000000);
+ assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
- int offset = (top - topline) * _realWidth + vs->xstart + left;
- backbuff = vs->screenPtr + offset;
- bgbak = getResourceAddress(rtBuffer, vs->number + 5) + offset;
+ if ((camera._cur.x != old.x || camera._cur.y != old.y)
+ && _vars[VAR_SCROLL_SCRIPT]) {
+ _vars[VAR_CAMERA_POS_X] = camera._cur.x;
+ _vars[VAR_CAMERA_POS_Y] = camera._cur.y;
+ runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
+ } else {
+ int t;
- height = bottom - top;
- width = right - left;
+ if (camera._mode != CM_FOLLOW_ACTOR || abs(pos_x - camera._cur.x) > (_realWidth / 2)) {
+ camera._cur.x = pos_x;
+ }
+ camera._dest.x = pos_x;
- if (vs->alloctwobuffers && _currentRoom != 0 /*&& _vars[VAR_V5_DRAWFLAGS]&2 */ ) {
- blit(backbuff, bgbak, width, height);
- if (vs->number == 0 && charset._hasMask && height) {
- byte *mask;
- int mask_width = (width >> 3);
+ t = _vars[VAR_CAMERA_MIN_X];
+ if (camera._cur.x < t)
+ camera._cur.x = t;
- if (width & 0x07)
- mask_width++;
+ t = _vars[VAR_CAMERA_MAX_X];
+ if (camera._cur.x > t)
+ camera._cur.x = t;
- mask = getResourceAddress(rtBuffer, 9) + top * gdi._numStrips + (left >> 3) + _screenStartStrip;
- if (vs->number == 0)
- mask += vs->topline * gdi._numStrips;
+ if (_vars[VAR_SCROLL_SCRIPT]) {
+ _vars[VAR_CAMERA_POS_X] = camera._cur.x;
+ runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
- do {
- memset(mask, 0, mask_width);
- mask += gdi._numStrips;
- } while (--height);
+ if (camera._cur.x != camera._last.x && charset._hasMask)
+ stopTalk();
+ }
+}
+
+void Scumm::setCameraFollows(Actor *a)
+{
+ if (_features & GF_AFTER_V7) {
+ byte oldfollow = camera._follows;
+ int ax, ay;
+
+ camera._follows = a->number;
+
+ if (!a->isInCurrentRoom()) {
+ startScene(a->getRoom(), 0, 0);
+ }
+
+ ax = abs(a->x - camera._cur.x);
+ ay = abs(a->y - camera._cur.y);
+
+ if (ax > _vars[VAR_CAMERA_THRESHOLD_X] || ay > _vars[VAR_CAMERA_THRESHOLD_Y] || ax > (_realWidth / 2) || ay > (_realHeight / 2)) {
+ setCameraAt(a->x, a->y);
}
+
+ if (a->number != oldfollow)
+ runHook(0);
} else {
- while (height--) {
- memset(backbuff, backColor, width);
- backbuff += _realWidth;
+ int t, i;
+
+ camera._mode = CM_FOLLOW_ACTOR;
+ camera._follows = a->number;
+
+ if (!a->isInCurrentRoom()) {
+ startScene(a->getRoom(), 0, 0);
+ camera._mode = CM_FOLLOW_ACTOR;
+ camera._cur.x = a->x;
+ setCameraAt(camera._cur.x, 0);
}
+
+ t = (a->x >> 3);
+
+ if (t - _screenStartStrip < camera._leftTrigger || t - _screenStartStrip > camera._rightTrigger)
+ setCameraAt(a->x, 0);
+
+ for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) {
+ if (a->isInCurrentRoom())
+ a->needRedraw = true;
+ }
+ runHook(0);
}
}
-void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits)
+void Scumm::clampCameraPos(ScummPoint *pt)
{
- VirtScreen *vs = &virtscr[virt];
- int lp, rp;
- uint32 *sp;
- int num;
+ if (pt->x < _vars[VAR_CAMERA_MIN_X])
+ pt->x = _vars[VAR_CAMERA_MIN_X];
- if (top > vs->height || left > vs->width || right < 0 || bottom < 0)
- return;
+ if (pt->x > _vars[VAR_CAMERA_MAX_X])
+ pt->x = _vars[VAR_CAMERA_MAX_X];
- if (top < 0)
- top = 0;
- if (left < 0)
- left = 0;
- if (bottom > vs->height)
- bottom = vs->height;
- if (right > vs->width)
- right = vs->width;
+ if (pt->y < _vars[VAR_CAMERA_MIN_Y])
+ pt->y = _vars[VAR_CAMERA_MIN_Y];
- if (virt == 0 && dirtybits) {
- rp = (right >> 3) + _screenStartStrip;
- lp = (left >> 3) + _screenStartStrip;
- if (lp < 0)
- lp = 0;
- if (_features & GF_AFTER_V7) {
- if (rp > 409)
- rp = 409;
+ if (pt->y > _vars[VAR_CAMERA_MAX_Y])
+ pt->y = _vars[VAR_CAMERA_MAX_Y];
+}
+
+void Scumm::moveCamera()
+{
+ if (_features & GF_AFTER_V7) {
+ ScummPoint old = camera._cur;
+ Actor *a = NULL;
+
+ if (camera._follows) {
+ a = derefActorSafe(camera._follows, "moveCamera");
+ if (abs(camera._cur.x - a->x) > _vars[VAR_CAMERA_THRESHOLD_X] ||
+ abs(camera._cur.y - a->y) > _vars[VAR_CAMERA_THRESHOLD_Y]) {
+ camera._movingToActor = true;
+ if (_vars[VAR_CAMERA_THRESHOLD_X] == 0)
+ camera._cur.x = a->x;
+ if (_vars[VAR_CAMERA_THRESHOLD_Y] == 0)
+ camera._cur.y = a->y;
+ clampCameraPos(&camera._cur);
+ }
} else {
- if (rp >= 200)
- rp = 200;
+ camera._movingToActor = false;
}
- if (lp <= rp) {
- num = rp - lp + 1;
- sp = &gfxUsageBits[lp];
- do {
- *sp++ |= dirtybits;
- } while (--num);
+
+ if (camera._movingToActor) {
+ camera._dest.x = a->x;
+ camera._dest.y = a->y;
}
- }
- setVirtscreenDirty(vs, left, top, right, bottom);
-}
+ assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
-void Scumm::setVirtscreenDirty(VirtScreen *vs, int left, int top, int right, int bottom)
-{
- int lp = left >> 3;
- int rp = right >> 3;
+ clampCameraPos(&camera._dest);
- if ((lp >= gdi._numStrips) || (rp < 0))
- return;
- if (lp < 0)
- lp = 0;
- if (rp >= gdi._numStrips)
- rp = gdi._numStrips - 1;
+ if (camera._cur.x < camera._dest.x) {
+ camera._cur.x += _vars[VAR_CAMERA_SPEED_X];
+ if (camera._cur.x > camera._dest.x)
+ camera._cur.x = camera._dest.x;
+ }
- while (lp <= rp) {
- if (top < vs->tdirty[lp])
- vs->tdirty[lp] = top;
- if (bottom > vs->bdirty[lp])
- vs->bdirty[lp] = bottom;
- lp++;
+ if (camera._cur.x > camera._dest.x) {
+ camera._cur.x -= _vars[VAR_CAMERA_SPEED_X];
+ if (camera._cur.x < camera._dest.x)
+ camera._cur.x = camera._dest.x;
+ }
+
+ if (camera._cur.y < camera._dest.y) {
+ camera._cur.y += _vars[VAR_CAMERA_SPEED_Y];
+ if (camera._cur.y > camera._dest.y)
+ camera._cur.y = camera._dest.y;
+ }
+
+ if (camera._cur.y > camera._dest.y) {
+ camera._cur.y -= _vars[VAR_CAMERA_SPEED_Y];
+ if (camera._cur.y < camera._dest.y)
+ camera._cur.y = camera._dest.y;
+ }
+
+ if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) {
+
+ camera._movingToActor = false;
+ camera._accel.x = camera._accel.y = 0;
+ _vars[VAR_CAMERA_SPEED_X] = _vars[VAR_CAMERA_SPEED_Y] = 0;
+ } else {
+
+ camera._accel.x += _vars[VAR_CAMERA_ACCEL_X];
+ camera._accel.y += _vars[VAR_CAMERA_ACCEL_Y];
+
+ _vars[VAR_CAMERA_SPEED_X] += camera._accel.x / 100;
+ _vars[VAR_CAMERA_SPEED_Y] += camera._accel.y / 100;
+
+ if (_vars[VAR_CAMERA_SPEED_X] < 8)
+ _vars[VAR_CAMERA_SPEED_X] = 8;
+
+ if (_vars[VAR_CAMERA_SPEED_Y] < 8)
+ _vars[VAR_CAMERA_SPEED_Y] = 8;
+
+ }
+
+ cameraMoved();
+
+ if (camera._cur.x != old.x || camera._cur.y != old.y) {
+ _vars[VAR_CAMERA_POS_X] = camera._cur.x;
+ _vars[VAR_CAMERA_POS_Y] = camera._cur.y;
+
+ _vars[VAR_CAMERA_DEST_X] = camera._dest.x;
+
+ _vars[VAR_CAMERA_DEST_Y] = camera._dest.y;
+
+ _vars[VAR_CAMERA_FOLLOWED_ACTOR] = camera._follows;
+
+ if (_vars[VAR_SCROLL_SCRIPT])
+ runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
+ } else {
+ int pos = camera._cur.x;
+ int actorx, t;
+ Actor *a = NULL;
+
+ camera._cur.x &= 0xFFF8;
+
+ if (camera._cur.x < _vars[VAR_CAMERA_MIN_X]) {
+ if (_vars[VAR_CAMERA_FAST_X])
+ camera._cur.x = _vars[VAR_CAMERA_MIN_X];
+ else
+ camera._cur.x += 8;
+ cameraMoved();
+ return;
+ }
+
+ if (camera._cur.x > _vars[VAR_CAMERA_MAX_X]) {
+ if (_vars[VAR_CAMERA_FAST_X])
+ camera._cur.x = _vars[VAR_CAMERA_MAX_X];
+ else
+ camera._cur.x -= 8;
+ cameraMoved();
+ return;
+ }
+
+ if (camera._mode == CM_FOLLOW_ACTOR) {
+ a = derefActorSafe(camera._follows, "moveCamera");
+
+ actorx = a->x;
+ t = (actorx >> 3) - _screenStartStrip;
+
+ if (t < camera._leftTrigger || t > camera._rightTrigger) {
+ if (_vars[VAR_CAMERA_FAST_X]) {
+ if (t > 35)
+ camera._dest.x = actorx + 80;
+ if (t < 5)
+ camera._dest.x = actorx - 80;
+ } else
+ camera._movingToActor = true;
+ }
+ }
+
+ if (camera._movingToActor) {
+ a = derefActorSafe(camera._follows, "moveCamera(2)");
+ camera._dest.x = a->x;
+ }
+
+ if (camera._dest.x < _vars[VAR_CAMERA_MIN_X])
+ camera._dest.x = _vars[VAR_CAMERA_MIN_X];
+
+ if (camera._dest.x > _vars[VAR_CAMERA_MAX_X])
+ camera._dest.x = _vars[VAR_CAMERA_MAX_X];
+
+ if (_vars[VAR_CAMERA_FAST_X]) {
+ camera._cur.x = camera._dest.x;
+ } else {
+ if (camera._cur.x < camera._dest.x)
+ camera._cur.x += 8;
+ if (camera._cur.x > camera._dest.x)
+ camera._cur.x -= 8;
+ }
+
+ /* a is set a bit above */
+ if (camera._movingToActor && (camera._cur.x >> 3) == (a->x >> 3)) {
+ camera._movingToActor = false;
+ }
+
+ cameraMoved();
+
+ if (pos != camera._cur.x && _vars[VAR_SCROLL_SCRIPT]) {
+ _vars[VAR_CAMERA_POS_X] = camera._cur.x;
+ runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
}
}
-VirtScreen *Scumm::findVirtScreen(int y)
+void Scumm::cameraMoved()
{
- VirtScreen *vs = virtscr;
- int i;
+ if (_features & GF_AFTER_V7) {
- for (i = 0; i < 3; i++, vs++) {
- if (y >= vs->topline && y < vs->topline + vs->height) {
- return _curVirtScreen = vs;
+ assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
+
+ } else {
+
+ if (camera._cur.x < (_realWidth / 2)) {
+ camera._cur.x = (_realWidth / 2);
+ } else if (camera._cur.x > _scrWidth - (_realWidth / 2)) {
+ camera._cur.x = _scrWidth - (_realWidth / 2);
}
}
- return _curVirtScreen = NULL;
+
+ _screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3;
+ _screenEndStrip = _screenStartStrip + gdi._numStrips - 1;
+ virtscr[0].xstart = _screenStartStrip << 3;
+
+
+ _screenTop = camera._cur.y - (_realHeight / 2);
+ if (_features & GF_AFTER_V7) {
+
+ _screenLeft = camera._cur.x - (_realWidth / 2);
+ } else {
+
+ _screenLeft = _screenStartStrip << 3;
+ }
+
}
-void Scumm::unkScreenEffect1()
+void Scumm::panCameraTo(int x, int y)
{
- /* XXX: not implemented */
- warning("stub unkScreenEffect1()");
+ if (_features & GF_AFTER_V7) {
+
+ camera._follows = 0;
+ camera._dest.x = x;
+ camera._dest.y = y;
+ } else {
+
+ camera._dest.x = x;
+ camera._mode = CM_PANNING;
+ camera._movingToActor = false;
+ }
}
-void Scumm::unkScreenEffect2()
+void Scumm::actorFollowCamera(int act)
{
- /* XXX: not implemented */
- warning("stub unkScreenEffect2()");
+ if (!(_features & GF_AFTER_V7)) {
+ int old;
+
+ /* mi1 compatibilty */
+ if (act == 0) {
+ camera._mode = CM_NORMAL;
+ camera._follows = 0;
+ camera._movingToActor = false;
+ return;
+ }
+
+ old = camera._follows;
+ setCameraFollows(derefActorSafe(act, "actorFollowCamera"));
+ if (camera._follows != old)
+ runHook(0);
+
+ camera._movingToActor = false;
+ }
}
-void Scumm::unkScreenEffect3()
+#pragma mark -
+#pragma mark ### Transition effects ###
+#pragma mark -
+
+void Scumm::fadeIn(int effect)
{
- /* XXX: not implemented */
- warning("stub unkScreenEffect3()");
+ switch (effect) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ transitionEffect(effect - 1);
+ break;
+ case 128:
+ unkScreenEffect6();
+ break;
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ scrollEffect(133 - effect);
+ break;
+ case 134:
+ dissolveEffect(1, 1);
+ break;
+ case 135:
+ unkScreenEffect5(1);
+ break;
+ case 129:
+ break;
+ default:
+ warning("Unknown screen effect, %d", effect);
+ }
+ _screenEffectFlag = true;
}
-void Scumm::unkScreenEffect4()
+void Scumm::fadeOut(int effect)
{
- /* XXX: not implemented */
- warning("stub unkScreenEffect4()");
-}
+ VirtScreen *vs;
-/* *INDENT-OFF* */
+ setDirtyRange(0, 0, 0);
+ if (!(_features & GF_AFTER_V7))
+ camera._last.x = camera._cur.x;
-static const int8 screen_eff7_table1[4][16] = {
- { 1, 1, -1, 1, -1, 1, -1, -1,
- 1, -1, -1, -1, 1, 1, 1, -1},
- { 0, 1, 2, 1, 2, 0, 2, 1,
- 2, 0, 2, 1, 0, 0, 0, 0},
- {-2, -1, 0, -1, -2, -1, -2, 0, -2, -1, -2, 0, 0, 0, 0, 0},
- { 0, -1, -2, -1, -2, 0, -2, -1, -2, 0, -2, -1, 0, 0, 0, 0}
-};
+ if (!_screenEffectFlag)
+ return;
+ _screenEffectFlag = false;
-static const byte screen_eff7_table2[4][16] = {
- { 0, 0, 39, 0, 39, 0, 39, 24,
- 0, 24, 39, 24, 0, 0, 0, 24},
- { 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 1, 0, 255, 0, 0, 0},
- {39, 24, 39, 24, 39, 24, 39, 24,
- 38, 24, 38, 24, 255, 0, 0, 0},
- { 0, 24, 39, 24, 39, 0, 39, 24,
- 38, 0, 38, 24, 255, 0, 0, 0}
-};
+ if (effect == 0)
+ return;
-static const byte transition_num_of_iterations[4] = {
- 13, 25, 25, 25
-};
+ // Fill screen 0 with black
+ vs = &virtscr[0];
+ memset(vs->screenPtr + vs->xstart, 0, vs->size);
-/* *INDENT-ON* */
+ // Fade to black with the specified effect, if any.
+ switch (effect) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ transitionEffect(effect - 1);
+ break;
+ case 128:
+ unkScreenEffect6();
+ break;
+ case 129:
+ // Just blit screen 0 to the display (i.e. display will be black)
+ setDirtyRange(0, 0, vs->height);
+ updateDirtyScreen(0);
+ break;
+ case 134:
+ dissolveEffect(1, 1);
+ break;
+ case 135:
+ unkScreenEffect5(1);
+ break;
+ default:
+ warning("fadeOut: default case %d", effect);
+ }
+}
/* Transition effect. There are four different effects possible,
* indicated by the value of a:
@@ -2220,7 +2363,6 @@ void Scumm::scrollEffect(int dir) {
}
}
-
void Scumm::unkScreenEffect6() {
if (_gameId == GID_LOOM256)
dissolveEffect(1, 1);
@@ -2249,259 +2391,184 @@ void Scumm::setShake(int mode)
_system->set_shake_pos(0);
}
-void Gdi::clearUpperMask()
-{
- memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0]
- );
-}
+#pragma mark -
+#pragma mark ### Palette ###
+#pragma mark -
-void Scumm::clampCameraPos(ScummPoint *pt)
+void Scumm::setPaletteFromPtr(byte *ptr)
{
- if (pt->x < _vars[VAR_CAMERA_MIN_X])
- pt->x = _vars[VAR_CAMERA_MIN_X];
-
- if (pt->x > _vars[VAR_CAMERA_MAX_X])
- pt->x = _vars[VAR_CAMERA_MAX_X];
+ int i;
+ byte *dest, r, g, b;
+ int numcolor;
- if (pt->y < _vars[VAR_CAMERA_MIN_Y])
- pt->y = _vars[VAR_CAMERA_MIN_Y];
+ if (_features & GF_SMALL_HEADER) {
+ if (_features & GF_OLD256)
+ numcolor = 256;
+ else
+ numcolor = READ_LE_UINT16(ptr + 6) / 3;
+ ptr += 8;
+ } else {
+ numcolor = getResourceDataSize(ptr) / 3;
+ }
- if (pt->y > _vars[VAR_CAMERA_MAX_Y])
- pt->y = _vars[VAR_CAMERA_MAX_Y];
-}
+ checkRange(256, 0, numcolor, "Too many colors (%d) in Palette");
+ dest = _currentPalette;
-void Scumm::moveCamera()
-{
- if (_features & GF_AFTER_V7) {
- ScummPoint old = camera._cur;
- Actor *a = NULL;
+ for (i = 0; i < numcolor; i++) {
+ r = *ptr++;
+ g = *ptr++;
+ b = *ptr++;
- if (camera._follows) {
- a = derefActorSafe(camera._follows, "moveCamera");
- if (abs(camera._cur.x - a->x) > _vars[VAR_CAMERA_THRESHOLD_X] ||
- abs(camera._cur.y - a->y) > _vars[VAR_CAMERA_THRESHOLD_Y]) {
- camera._movingToActor = true;
- if (_vars[VAR_CAMERA_THRESHOLD_X] == 0)
- camera._cur.x = a->x;
- if (_vars[VAR_CAMERA_THRESHOLD_Y] == 0)
- camera._cur.y = a->y;
- clampCameraPos(&camera._cur);
- }
+ // This comparison might look wierd, but it's what the disassembly (DOTT) says!
+ // FIXME: Fingolfin still thinks it looks weird: the value 252 = 4*63 clearly comes from
+ // the days 6/6/6 palettes were used, OK. But it breaks MonkeyVGA, so I had to add a
+ // check for that. And somebody before me added a check for V7 games, turning this
+ // off there, too... I wonder if it hurts other games, too? What exactly is broken
+ // if we remove this patch?
+ if ((_gameId == GID_MONKEY_VGA) || (_features & GF_AFTER_V7) || (i <= 15 || r < 252 || g < 252 || b < 252)) {
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
} else {
- camera._movingToActor = false;
- }
-
- if (camera._movingToActor) {
- camera._dest.x = a->x;
- camera._dest.y = a->y;
- }
-
- assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
-
- clampCameraPos(&camera._dest);
-
- if (camera._cur.x < camera._dest.x) {
- camera._cur.x += _vars[VAR_CAMERA_SPEED_X];
- if (camera._cur.x > camera._dest.x)
- camera._cur.x = camera._dest.x;
- }
-
- if (camera._cur.x > camera._dest.x) {
- camera._cur.x -= _vars[VAR_CAMERA_SPEED_X];
- if (camera._cur.x < camera._dest.x)
- camera._cur.x = camera._dest.x;
- }
-
- if (camera._cur.y < camera._dest.y) {
- camera._cur.y += _vars[VAR_CAMERA_SPEED_Y];
- if (camera._cur.y > camera._dest.y)
- camera._cur.y = camera._dest.y;
- }
-
- if (camera._cur.y > camera._dest.y) {
- camera._cur.y -= _vars[VAR_CAMERA_SPEED_Y];
- if (camera._cur.y < camera._dest.y)
- camera._cur.y = camera._dest.y;
+ dest += 3;
}
+ }
+ setDirtyColors(0, numcolor - 1);
+}
- if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) {
-
- camera._movingToActor = false;
- camera._accel.x = camera._accel.y = 0;
- _vars[VAR_CAMERA_SPEED_X] = _vars[VAR_CAMERA_SPEED_Y] = 0;
- } else {
+void Scumm::setPaletteFromRes()
+{
+ byte *ptr;
+ ptr = getResourceAddress(rtRoom, _roomResource) + _CLUT_offs;
+ setPaletteFromPtr(ptr);
+}
- camera._accel.x += _vars[VAR_CAMERA_ACCEL_X];
- camera._accel.y += _vars[VAR_CAMERA_ACCEL_Y];
- _vars[VAR_CAMERA_SPEED_X] += camera._accel.x / 100;
- _vars[VAR_CAMERA_SPEED_Y] += camera._accel.y / 100;
+void Scumm::setDirtyColors(int min, int max)
+{
+ if (_palDirtyMin > min)
+ _palDirtyMin = min;
+ if (_palDirtyMax < max)
+ _palDirtyMax = max;
+}
- if (_vars[VAR_CAMERA_SPEED_X] < 8)
- _vars[VAR_CAMERA_SPEED_X] = 8;
+void Scumm::initCycl(byte *ptr)
+{
+ int j;
+ ColorCycle *cycl;
- if (_vars[VAR_CAMERA_SPEED_Y] < 8)
- _vars[VAR_CAMERA_SPEED_Y] = 8;
+ memset(_colorCycle, 0, sizeof(_colorCycle));
+ while ((j = *ptr++) != 0) {
+ if (j < 1 || j > 16) {
+ error("Invalid color cycle index %d", j);
}
+ cycl = &_colorCycle[j - 1];
- cameraMoved();
-
- if (camera._cur.x != old.x || camera._cur.y != old.y) {
- _vars[VAR_CAMERA_POS_X] = camera._cur.x;
- _vars[VAR_CAMERA_POS_Y] = camera._cur.y;
+ ptr += 2;
+ cycl->counter = 0;
+ cycl->delay = 16384 / READ_BE_UINT16_UNALIGNED(ptr);
+ ptr += 2;
+ cycl->flags = READ_BE_UINT16_UNALIGNED(ptr);
+ ptr += 2;
+ cycl->start = *ptr++;
+ cycl->end = *ptr++;
+ }
+}
- _vars[VAR_CAMERA_DEST_X] = camera._dest.x;
+void Scumm::stopCycle(int i)
+{
+ ColorCycle *cycl;
- _vars[VAR_CAMERA_DEST_Y] = camera._dest.y;
+ checkRange(16, 0, i, "Stop Cycle %d Out Of Range");
+ if (i != 0) {
+ _colorCycle[i - 1].delay = 0;
+ return;
+ }
- _vars[VAR_CAMERA_FOLLOWED_ACTOR] = camera._follows;
+ for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++)
+ cycl->delay = 0;
+}
- if (_vars[VAR_SCROLL_SCRIPT])
- runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
- }
- } else {
- int pos = camera._cur.x;
- int actorx, t;
- Actor *a = NULL;
+void Scumm::cyclePalette()
+{
+ ColorCycle *cycl;
+ int valueToAdd;
+ int i, num;
+ byte *start, *end;
+ byte tmp[3];
- camera._cur.x &= 0xFFF8;
+ valueToAdd = _vars[VAR_TIMER];
+ if (valueToAdd < _vars[VAR_TIMER_NEXT])
+ valueToAdd = _vars[VAR_TIMER_NEXT];
- if (camera._cur.x < _vars[VAR_CAMERA_MIN_X]) {
- if (_vars[VAR_CAMERA_FAST_X])
- camera._cur.x = _vars[VAR_CAMERA_MIN_X];
- else
- camera._cur.x += 8;
- cameraMoved();
- return;
- }
+ if (!_colorCycle) // FIXME
+ return;
- if (camera._cur.x > _vars[VAR_CAMERA_MAX_X]) {
- if (_vars[VAR_CAMERA_FAST_X])
- camera._cur.x = _vars[VAR_CAMERA_MAX_X];
- else
- camera._cur.x -= 8;
- cameraMoved();
- return;
- }
+ for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) {
+ if (cycl->delay && (cycl->counter += valueToAdd) >= cycl->delay) {
+ do {
+ cycl->counter -= cycl->delay;
+ } while (cycl->delay <= cycl->counter);
- if (camera._mode == CM_FOLLOW_ACTOR) {
- a = derefActorSafe(camera._follows, "moveCamera");
+ setDirtyColors(cycl->start, cycl->end);
+ moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2);
+ start = &_currentPalette[cycl->start * 3];
+ end = &_currentPalette[cycl->end * 3];
- actorx = a->x;
- t = (actorx >> 3) - _screenStartStrip;
+ num = cycl->end - cycl->start;
- if (t < camera._leftTrigger || t > camera._rightTrigger) {
- if (_vars[VAR_CAMERA_FAST_X]) {
- if (t > 35)
- camera._dest.x = actorx + 80;
- if (t < 5)
- camera._dest.x = actorx - 80;
- } else
- camera._movingToActor = true;
+ if (!(cycl->flags & 2)) {
+ memmove(tmp, end, 3);
+ memmove(start + 3, start, num * 3);
+ memmove(start, tmp, 3);
+ } else {
+ memmove(tmp, start, 3);
+ memmove(start, start + 3, num * 3);
+ memmove(end, tmp, 3);
}
}
-
- if (camera._movingToActor) {
- a = derefActorSafe(camera._follows, "moveCamera(2)");
- camera._dest.x = a->x;
- }
-
- if (camera._dest.x < _vars[VAR_CAMERA_MIN_X])
- camera._dest.x = _vars[VAR_CAMERA_MIN_X];
-
- if (camera._dest.x > _vars[VAR_CAMERA_MAX_X])
- camera._dest.x = _vars[VAR_CAMERA_MAX_X];
-
- if (_vars[VAR_CAMERA_FAST_X]) {
- camera._cur.x = camera._dest.x;
- } else {
- if (camera._cur.x < camera._dest.x)
- camera._cur.x += 8;
- if (camera._cur.x > camera._dest.x)
- camera._cur.x -= 8;
- }
-
- /* a is set a bit above */
- if (camera._movingToActor && (camera._cur.x >> 3) == (a->x >> 3)) {
- camera._movingToActor = false;
- }
-
- cameraMoved();
-
- if (pos != camera._cur.x && _vars[VAR_SCROLL_SCRIPT]) {
- _vars[VAR_CAMERA_POS_X] = camera._cur.x;
- runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
- }
}
}
-void Scumm::cameraMoved()
+// Perform color cycling on the palManipulate data, too, otherwise
+// color cycling will be disturbed by the palette fade.
+void Scumm::moveMemInPalRes(int start, int end, byte direction)
{
- if (_features & GF_AFTER_V7) {
-
- assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2));
-
- } else {
-
- if (camera._cur.x < (_realWidth / 2)) {
- camera._cur.x = (_realWidth / 2);
- } else if (camera._cur.x > _scrWidth - (_realWidth / 2)) {
- camera._cur.x = _scrWidth - (_realWidth / 2);
- }
- }
-
- _screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3;
- _screenEndStrip = _screenStartStrip + gdi._numStrips - 1;
- virtscr[0].xstart = _screenStartStrip << 3;
-
+ byte *startptr, *endptr;
+ byte *startptr2, *endptr2;
+ int num;
+ byte tmp[6];
- _screenTop = camera._cur.y - (_realHeight / 2);
- if (_features & GF_AFTER_V7) {
+ if (!_palManipCounter)
+ return;
- _screenLeft = camera._cur.x - (_realWidth / 2);
- } else {
+ startptr = _palManipPalette + start * 3;
+ endptr = _palManipPalette + end * 3;
+ startptr2 = _palManipIntermediatePal + start * 6;
+ endptr2 = _palManipIntermediatePal + end * 6;
+ num = end - start;
- _screenLeft = _screenStartStrip << 3;
+ if (!endptr) {
+ warning("moveMemInPalRes(%d,%d): Bad end pointer\n", start, end);
+ return;
}
-}
-
-void Scumm::panCameraTo(int x, int y)
-{
- if (_features & GF_AFTER_V7) {
-
- camera._follows = 0;
- camera._dest.x = x;
- camera._dest.y = y;
+ if (!direction) {
+ memmove(tmp, endptr, 3);
+ memmove(startptr + 3, startptr, num * 3);
+ memmove(startptr, tmp, 3);
+ memmove(tmp, endptr2, 6);
+ memmove(startptr2 + 6, startptr2, num * 6);
+ memmove(startptr2, tmp, 6);
} else {
-
- camera._dest.x = x;
- camera._mode = CM_PANNING;
- camera._movingToActor = false;
- }
-}
-
-void Scumm::actorFollowCamera(int act)
-{
- if (!(_features & GF_AFTER_V7)) {
- int old;
-
- /* mi1 compatibilty */
- if (act == 0) {
- camera._mode = CM_NORMAL;
- camera._follows = 0;
- camera._movingToActor = false;
- return;
- }
-
- old = camera._follows;
- setCameraFollows(derefActorSafe(act, "actorFollowCamera"));
- if (camera._follows != old)
- runHook(0);
-
- camera._movingToActor = false;
+ memmove(tmp, startptr, 3);
+ memmove(startptr, startptr + 3, num * 3);
+ memmove(endptr, tmp, 3);
+ memmove(tmp, startptr2, 6);
+ memmove(startptr2, startptr2 + 6, num * 6);
+ memmove(endptr2, tmp, 6);
}
}
@@ -2606,11 +2673,6 @@ void Scumm::setupShadowPalette(int slot, int redScale, int greenScale, int blueS
}
}
-static inline uint colorWeight(int red, int green, int blue)
-{
- return 3 * red * red + 6 * green * green + 2 * blue * blue;
-}
-
void Scumm::setupShadowPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor)
{
byte *basepal = getPalettePtr();
@@ -2857,35 +2919,6 @@ void Scumm::copyPalColor(int dst, int src)
setDirtyColors(dst, dst);
}
-void Gdi::resetBackground(int top, int bottom, int strip)
-{
- VirtScreen *vs = &_vm->virtscr[0];
- int offs;
-
- if (top < vs->tdirty[strip])
- vs->tdirty[strip] = top;
-
- if (bottom > vs->bdirty[strip])
- vs->bdirty[strip] = bottom;
-
- offs = (top * _numStrips + _vm->_screenStartStrip + strip);
- _mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + offs;
- _bgbak_ptr = _vm->getResourceAddress(rtBuffer, 5) + (offs << 3);
- _backbuff_ptr = vs->screenPtr + (offs << 3);
-
- _numLinesToProcess = bottom - top;
- if (_numLinesToProcess) {
- if ((_vm->_features & GF_AFTER_V6) || (_vm->_vars[_vm->VAR_CURRENT_LIGHTS] & LIGHTMODE_screen)) {
- if (_vm->hasCharsetMask(strip << 3, top, (strip + 1) << 3, bottom))
- draw8ColWithMasking(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess, _mask_ptr);
- else
- draw8Col(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess);
- } else {
- clear8Col(_backbuff_ptr, _numLinesToProcess);
- }
- }
-}
-
void Scumm::setPalColor(int idx, int r, int g, int b)
{
_currentPalette[idx * 3 + 0] = r;
@@ -2894,42 +2927,6 @@ void Scumm::setPalColor(int idx, int r, int g, int b)
setDirtyColors(idx, idx);
}
-void Scumm::setCursorHotspot2(int x, int y)
-{
- _cursor.hotspotX = x;
- _cursor.hotspotY = y;
-}
-
-byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem)
-{
- int w, h, i;
-
- l >>= 3;
- if (l < 0)
- l = 0;
- if (t < 0)
- t = 0;
-
- r >>= 3;
- if (r > gdi._numStrips - 1)
- r = gdi._numStrips - 1;
-
- mem += l + t * gdi._numStrips;
-
- w = r - l;
- h = b - t + 1;
-
- do {
- for (i = 0; i <= w; i++)
- if (mem[i]) {
- return true;
- }
- mem += gdi._numStrips;
- } while (--h);
-
- return false;
-}
-
void Scumm::setPalette(int palindex)
{
byte *pals;
@@ -2975,6 +2972,10 @@ byte *Scumm::getPalettePtr()
return cptr;
}
+#pragma mark -
+#pragma mark ### Cursor ###
+#pragma mark -
+
void Scumm::grabCursor(int x, int y, int w, int h)
{
VirtScreen *vs = findVirtScreen(y);
@@ -2988,36 +2989,6 @@ void Scumm::grabCursor(int x, int y, int w, int h)
}
-void Scumm::decompressBomp(byte *dst, byte *src, int w, int h)
-{
- int len, num;
- byte code, color;
-
- src += 8;
-
- do {
- len = w;
- src += 2;
- while (len) {
- code = *src++;
- num = (code >> 1) + 1;
- if (num > len)
- num = len;
- len -= num;
- if (code & 1) {
- color = *src++;
- do
- *dst++ = color;
- while (--num);
- } else {
- do
- *dst++ = *src++;
- while (--num);
- }
- }
- } while (--h);
-}
-
void Scumm::grabCursor(byte *ptr, int width, int height)
{
uint size;
@@ -3061,10 +3032,24 @@ void Scumm::useIm01Cursor(byte *im, int w, int h)
blit(vs->screenPtr + vs->xstart, getResourceAddress(rtBuffer, 5) + vs->xstart, w, h);
}
+void Scumm::setCursor(int cursor)
+{
+ if (cursor >= 0 && cursor <= 3)
+ _currentCursor = cursor;
+ else
+ warning("setCursor(%d)", cursor);
+}
+
+void Scumm::setCursorHotspot2(int x, int y)
+{
+ _cursor.hotspotX = x;
+ _cursor.hotspotY = y;
+}
+
void Scumm::updateCursor()
{
_system->set_mouse_cursor(_grabbedCursor, _cursor.width, _cursor.height,
- _cursor.hotspotX, _cursor.hotspotY);
+ _cursor.hotspotX, _cursor.hotspotY);
}
void Scumm::animateCursor()
@@ -3075,7 +3060,6 @@ void Scumm::animateCursor()
}
_cursor.animateIndex++;
}
-
}
void Scumm::useBompCursor(byte *im, int width, int height)
@@ -3098,29 +3082,6 @@ void Scumm::useBompCursor(byte *im, int width, int height)
updateCursor();
}
-static const byte default_cursor_colors[4] = {
- 15, 15, 7, 8
-};
-
-static const uint16 default_cursor_images[4][16] = {
- /* cross-hair */
- { 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f,
- 0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 },
- /* hourglass */
- { 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0,
- 0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 },
- /* arrow */
- { 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
- 0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 },
- /* hand */
- { 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249,
- 0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff },
-};
-
-static const byte default_cursor_hotspots[8] = {
- 8, 7, 8, 7, 1, 1, 5, 0
-};
-
void Scumm::decompressDefaultCursor(int idx)
{
int i, j;
@@ -3175,6 +3136,10 @@ void Scumm::makeCursorColorTransparent(int a)
updateCursor();
}
+#pragma mark -
+#pragma mark ### Bomp ###
+#pragma mark -
+
int32 Scumm::bompDecodeLineMode0(byte * src, byte * line_buffer, int32 size) {
if (size <= 0)
return size;
@@ -3328,6 +3293,36 @@ void Scumm::bompScaleFuncX(byte * line_buffer, byte * scalling_x_ptr, byte skip,
}
}
+void Scumm::decompressBomp(byte *dst, byte *src, int w, int h)
+{
+ int len, num;
+ byte code, color;
+
+ src += 8;
+
+ do {
+ len = w;
+ src += 2;
+ while (len) {
+ code = *src++;
+ num = (code >> 1) + 1;
+ if (num > len)
+ num = len;
+ len -= num;
+ if (code & 1) {
+ color = *src++;
+ do
+ *dst++ = color;
+ while (--num);
+ } else {
+ do
+ *dst++ = *src++;
+ while (--num);
+ }
+ }
+ } while (--h);
+}
+
void Scumm::drawBomp(BompDrawData * bd, int decode_mode, int mask) {
byte skip_y = 128;
byte skip_y_new = 0;