diff options
author | Max Horn | 2002-12-15 23:40:37 +0000 |
---|---|---|
committer | Max Horn | 2002-12-15 23:40:37 +0000 |
commit | 20c501ea587ac03167fca87b6cbccf2b51f1c135 (patch) | |
tree | 1224510a3193492f043a7e8b975034171aad3876 /scumm/gfx.cpp | |
parent | cfc4bc586a732eb0c3c660e380d747c4f90eecd3 (diff) | |
download | scummvm-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.cpp | 1825 |
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; |