diff options
author | sylvaintv | 2011-03-08 00:54:40 +0100 |
---|---|---|
committer | sylvaintv | 2011-03-08 00:54:40 +0100 |
commit | b2a72da6518b30a58a1257ff7217185ae5683628 (patch) | |
tree | 41e5d532124466b09a396ec4b043ec74e1b9ea56 /engines/sci | |
parent | 53d6a4f831c9e7c7de594cdaed3c8546b41ea2e2 (diff) | |
parent | 9fb28410b5ea27fa8e79ac5f0ac4ce70ae4cf3c6 (diff) | |
download | scummvm-rg350-b2a72da6518b30a58a1257ff7217185ae5683628.tar.gz scummvm-rg350-b2a72da6518b30a58a1257ff7217185ae5683628.tar.bz2 scummvm-rg350-b2a72da6518b30a58a1257ff7217185ae5683628.zip |
Merge branch 'master' of github.com:scummvm/scummvm
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/console.cpp | 6 | ||||
-rw-r--r-- | engines/sci/engine/gc.cpp | 8 | ||||
-rw-r--r-- | engines/sci/engine/kmisc.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/vm_types.cpp | 12 | ||||
-rw-r--r-- | engines/sci/engine/workarounds.cpp | 8 | ||||
-rw-r--r-- | engines/sci/graphics/cursor.cpp | 24 | ||||
-rw-r--r-- | engines/sci/graphics/helpers.h | 3 | ||||
-rw-r--r-- | engines/sci/graphics/palette.cpp | 16 | ||||
-rw-r--r-- | engines/sci/graphics/picture.cpp | 151 | ||||
-rw-r--r-- | engines/sci/graphics/view.cpp | 228 | ||||
-rw-r--r-- | engines/sci/resource.cpp | 19 |
11 files changed, 246 insertions, 231 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index de0cfe20d8..b5bb5aaad0 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -2198,7 +2198,7 @@ bool Console::cmdStack(int argc, const char **argv) { return true; } - ExecStack &xs = _engine->_gamestate->_executionStack.back(); + const ExecStack &xs = _engine->_gamestate->_executionStack.back(); int nr = atoi(argv[1]); for (int i = nr; i > 0; i--) { @@ -2447,12 +2447,12 @@ bool Console::cmdScriptSteps(int argc, const char **argv) { bool Console::cmdBacktrace(int argc, const char **argv) { DebugPrintf("Call stack (current base: 0x%x):\n", _engine->_gamestate->executionStackBase); - Common::List<ExecStack>::iterator iter; + Common::List<ExecStack>::const_iterator iter; uint i = 0; for (iter = _engine->_gamestate->_executionStack.begin(); iter != _engine->_gamestate->_executionStack.end(); ++iter, ++i) { - ExecStack &call = *iter; + const ExecStack &call = *iter; const char *objname = _engine->_gamestate->_segMan->getObjectName(call.sendp); int paramc, totalparamc; diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp index 85238ec851..6d00c20422 100644 --- a/engines/sci/engine/gc.cpp +++ b/engines/sci/engine/gc.cpp @@ -108,7 +108,7 @@ AddrSet *findAllActiveReferences(EngineState *s) { // Initialize value stack // We do this one by hand since the stack doesn't know the current execution stack - Common::List<ExecStack>::iterator iter = s->_executionStack.reverse_begin(); + Common::List<ExecStack>::const_iterator iter = s->_executionStack.reverse_begin(); // Skip fake kernel stack frame if it's on top if ((*iter).type == EXEC_STACK_TYPE_KERNEL) @@ -116,9 +116,9 @@ AddrSet *findAllActiveReferences(EngineState *s) { assert((iter != s->_executionStack.end()) && ((*iter).type != EXEC_STACK_TYPE_KERNEL)); - ExecStack &xs = *iter; + const StackPtr sp = iter->sp; - for (reg_t *pos = s->stack_base; pos < xs.sp; pos++) + for (reg_t *pos = s->stack_base; pos < sp; pos++) wm.push(*pos); debugC(kDebugLevelGC, "[GC] -- Finished adding value stack"); @@ -126,7 +126,7 @@ AddrSet *findAllActiveReferences(EngineState *s) { // Init: Execution Stack for (iter = s->_executionStack.begin(); iter != s->_executionStack.end(); ++iter) { - ExecStack &es = *iter; + const ExecStack &es = *iter; if (es.type != EXEC_STACK_TYPE_KERNEL) { wm.push(es.objp); diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 73c92a9394..0061f3aa1c 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -497,7 +497,7 @@ reg_t kStub(EngineState *s, int argc, reg_t *argv) { Kernel *kernel = g_sci->getKernel(); int kernelCallNr = -1; - Common::List<ExecStack>::iterator callIterator = s->_executionStack.end(); + Common::List<ExecStack>::const_iterator callIterator = s->_executionStack.end(); if (callIterator != s->_executionStack.begin()) { callIterator--; ExecStack lastCall = *callIterator; diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index 17b08a5afd..0b790bb8af 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -193,11 +193,13 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { bool reg_t::pointerComparisonWithInteger(const reg_t right) const { // This function handles the case where a script tries to compare a pointer // to a number. Normally, we would not want to allow that. However, SCI0 - - // SCI1 scripts do this in order to distinguish pointers (to resources) - // from plain numbers. In our SCI implementation, such a check may seem - // pointless, as one can simply use the segment value to achieve this goal. - // But Sierra's SCI did not have the notion of segment IDs, so both pointer - // and numbers were simple integers. + // SCI1 scripts do this in order to distinguish references to + // external resources (which are numbers) from pointers. In + // our SCI implementation, such a check may seem pointless, as + // one can simply use the segment value to achieve this goal. + // But Sierra's SCI did not have the notion of segment IDs, so + // both pointer and numbers were simple integers. + // // But for some things, scripts had (and have) to distinguish between // numbers and pointers. Lacking the segment information, Sierra's // developers resorted to a hack: If an integer is smaller than a certain diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 2b60b1aa81..fb6c0e485f 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -401,14 +401,14 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun return sci3IgnoreForNow; } - EngineState *state = g_sci->getEngineState(); + const EngineState *state = g_sci->getEngineState(); ExecStack *lastCall = state->xs; - Script *local_script = state->_segMan->getScriptIfLoaded(lastCall->local_segment); - int curScriptNr = local_script->getScriptNumber(); + const Script *localScript = state->_segMan->getScriptIfLoaded(lastCall->local_segment); + int curScriptNr = localScript->getScriptNumber(); if (lastCall->debugLocalCallOffset != -1) { // if lastcall was actually a local call search back for a real call - Common::List<ExecStack>::iterator callIterator = state->_executionStack.end(); + Common::List<ExecStack>::const_iterator callIterator = state->_executionStack.end(); while (callIterator != state->_executionStack.begin()) { callIterator--; ExecStack loopCall = *callIterator; diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index b085654d02..9d1c3dabd6 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -26,6 +26,7 @@ #include "common/config-manager.h" #include "common/events.h" #include "common/macresman.h" +#include "common/memstream.h" #include "common/system.h" #include "common/util.h" #include "graphics/cursorman.h" @@ -434,9 +435,15 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu if (_macCursorRemap.empty()) { // QFG1/Freddy/Hoyle4 use a straight viewNum->cursor ID mapping - // KQ6 seems to use this mapping for its cursors - if (g_sci->getGameId() == GID_KQ6) - viewNum = loopNum * 1000 + celNum; + // KQ6 uses this mapping for its cursors + if (g_sci->getGameId() == GID_KQ6) { + if (viewNum == 990) // Inventory Cursors + viewNum = loopNum * 16 + celNum + 2000; + else if (viewNum == 998) // Regular Cursors + viewNum = celNum + 1000; + else // Unknown cursor, ignored + return; + } } else { // If we do have the list, we'll be using a remap based on what the // scripts have given us. @@ -485,8 +492,8 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu cursorBitmap[i * 8 + b] = 0; // Doesn't matter, just is transparent } - uint16 hotspotX = READ_BE_UINT16(data); - uint16 hotspotY = READ_BE_UINT16(data + 2); + uint16 hotspotY = READ_BE_UINT16(data); + uint16 hotspotX = READ_BE_UINT16(data + 2); static const byte cursorPalette[] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff }; @@ -498,11 +505,12 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu // Mac crsr cursor byte *cursorBitmap, *palette; int width, height, hotspotX, hotspotY, palSize, keycolor; - Common::MacResManager::convertCrsrCursor(resource->data, resource->size, &cursorBitmap, &width, &height, &hotspotX, &hotspotY, &keycolor, true, &palette, &palSize); + Common::MemoryReadStream resStream(resource->data, resource->size); + Common::MacResManager::convertCrsrCursor(&resStream, &cursorBitmap, width, height, hotspotX, hotspotY, keycolor, true, &palette, palSize); CursorMan.replaceCursor(cursorBitmap, width, height, hotspotX, hotspotY, keycolor); CursorMan.replaceCursorPalette(palette, 0, palSize); - free(cursorBitmap); - free(palette); + delete[] cursorBitmap; + delete[] palette; } kernelShow(); diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h index 1a87e566d5..343f3c7e6e 100644 --- a/engines/sci/graphics/helpers.h +++ b/engines/sci/graphics/helpers.h @@ -143,7 +143,8 @@ enum ViewType { kViewUnknown, // uninitialized, or non-SCI kViewEga, // EGA SCI0/SCI1 and Amiga SCI0/SCI1 ECS 16 colors kViewAmiga, // Amiga SCI1 ECS 32 colors - kViewVga, // VGA SCI1 256 colors or Amiga SCI1 AGA 64 colors (i.e. Longbow) + kViewAmiga64, // Amiga SCI1 AGA 64 colors (i.e. Longbow) + kViewVga, // VGA SCI1 256 colors kViewVga11 // VGA SCI1.1 and newer 256 colors }; diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 3b3596a336..5a6b1859cd 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -78,18 +78,18 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool useMergi #endif switch (_resMan->getViewType()) { - case kViewVga: - case kViewVga11: - if (g_sci->getPlatform() == Common::kPlatformAmiga) - _totalScreenColors = 64; // Longbow Amiga - else - _totalScreenColors = 256; + case kViewEga: + _totalScreenColors = 16; break; case kViewAmiga: _totalScreenColors = 32; break; - case kViewEga: - _totalScreenColors = 16; + case kViewAmiga64: + _totalScreenColors = 64; + break; + case kViewVga: + case kViewVga11: + _totalScreenColors = 256; break; default: error("GfxPalette: Unknown view type"); diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 60b40eee5b..e60a62e423 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -36,6 +36,8 @@ namespace Sci { +//#define DEBUG_PICTURE_DRAW + GfxPicture::GfxPicture(ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPorts *ports, GfxScreen *screen, GfxPalette *palette, GuiResourceId resourceId, bool EGAdrawingVisualize) : _resMan(resMan), _coordAdjuster(coordAdjuster), _ports(ports), _screen(screen), _palette(palette), _resourceId(resourceId), _EGAdrawingVisualize(EGAdrawingVisualize) { assert(resourceId != -1); @@ -222,19 +224,20 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu } #endif +extern void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData); + void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX) { byte *celBitmap = NULL; byte *ptr = NULL; byte *headerPtr = inbuffer + headerPos; byte *rlePtr = inbuffer + rlePos; - byte *literalPtr = inbuffer + literalPos; int16 displaceX, displaceY; byte priority = _addToFlag ? _priority : 0; byte clearColor; bool compression = true; - byte curByte, runLength; + byte curByte; int16 y, lastY, x, leftX, rightX; - int pixelNr, pixelCount; + int pixelCount; uint16 width, height; #ifdef ENABLE_SCI32 @@ -245,12 +248,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos height = READ_LE_UINT16(headerPtr + 2); displaceX = (signed char)headerPtr[4]; displaceY = (unsigned char)headerPtr[5]; - if (_resourceType == SCI_PICTURE_TYPE_SCI11) { + if (_resourceType == SCI_PICTURE_TYPE_SCI11) // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise clearColor = _screen->getColorWhite(); - } else { + else clearColor = headerPtr[6]; - } #ifdef ENABLE_SCI32 } else { width = READ_SCI11ENDIAN_UINT16(headerPtr + 0); @@ -266,91 +268,18 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos if (displaceX || displaceY) error("unsupported embedded cel-data in picture"); + // We will unpack cel-data into a temporary buffer and then plot it to screen + // That needs to be done cause a mirrored picture may be requested pixelCount = width * height; celBitmap = new byte[pixelCount]; if (!celBitmap) error("Unable to allocate temporary memory for picture drawing"); - if (compression) { - // We will unpack cel-data into a temporary buffer and then plot it to screen - // That needs to be done cause a mirrored picture may be requested - memset(celBitmap, clearColor, pixelCount); - pixelNr = 0; - ptr = celBitmap; - if (literalPos == 0) { - // decompression for data that has only one stream (vecor embedded view data) - switch (_resMan->getViewType()) { - case kViewEga: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte >> 4; - memset(ptr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - } - break; - case kViewVga: - case kViewVga11: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte & 0x3F; - switch (curByte & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNr < pixelCount) - ptr[pixelNr++] = *rlePtr++; - break; - case 0x80: // fill with color - memset(ptr + pixelNr, *rlePtr++, MIN<uint16>(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - break; - case 0xC0: // fill with transparent - pixelNr += runLength; - break; - } - } - break; - case kViewAmiga: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - if (curByte & 0x07) { // fill with color - runLength = curByte & 0x07; - curByte = curByte >> 3; - while (runLength-- && pixelNr < pixelCount) { - ptr[pixelNr++] = curByte; - } - } else { // fill with transparent - runLength = curByte >> 3; - pixelNr += runLength; - } - } - break; - - default: - error("Unsupported picture viewtype"); - } - } else { - // decompression for data that has two separate streams (probably SCI 1.1 picture) - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte & 0x3F; - switch (curByte & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNr < pixelCount) - ptr[pixelNr++] = *literalPtr++; - break; - case 0x80: // fill with color - memset(ptr + pixelNr, *literalPtr++, MIN<uint16>(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - break; - case 0xC0: // fill with transparent - pixelNr += runLength; - break; - } - } - } - } else { + if (compression) + unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false); + else // No compression (some SCI32 pictures) memcpy(celBitmap, rlePtr, pixelCount); - } Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea(); @@ -443,6 +372,7 @@ enum { PIC_OP_OPX = 0xfe, PIC_OP_TERMINATE = 0xff }; + #define PIC_OP_FIRST PIC_OP_SET_COLOR enum { @@ -465,6 +395,47 @@ enum { PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4 }; +#ifdef DEBUG_PICTURE_DRAW +const char *picOpcodeNames[] = { + "Set color", + "Disable visual", + "Set priority", + "Disable priority", + "Short patterns", + "Medium lines", + "Long lines", + "Short lines", + "Fill", + "Set pattern", + "Absolute pattern", + "Set control", + "Disable control", + "Medium patterns", + "Extended opcode", + "Terminate" +}; + +const char *picExOpcodeNamesEGA[] = { + "Set palette entries", + "Set palette", + "Mono0", + "Mono1", + "Mono2", + "Mono3", + "Mono4", + "Embedded view", + "Set priority table" +}; + +const char *picExOpcodeNamesVGA[] = { + "Set palette entries", + "Embedded view", + "Set palette", + "Set priority table (eqdist)", + "Set priority table (explicit)" +}; +#endif + #define PIC_EGAPALETTE_COUNT 4 #define PIC_EGAPALETTE_SIZE 40 #define PIC_EGAPALETTE_TOTALSIZE PIC_EGAPALETTE_COUNT*PIC_EGAPALETTE_SIZE @@ -543,7 +514,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { // Drawing while (curPos < dataSize) { - //warning("%X at %d", data[curPos], curPos); +#ifdef DEBUG_PICTURE_DRAW + debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos); +#endif switch (pic_op = data[curPos++]) { case PIC_OP_SET_COLOR: pic_color = data[curPos++]; @@ -681,6 +654,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { case PIC_OP_OPX: // Extended functions if (isEGA) { +#ifdef DEBUG_PICTURE_DRAW + debug("* Picture ex op: %X (%s) at %d", data[curPos], picExOpcodeNamesEGA[data[curPos]], curPos); +#endif switch (pic_op = data[curPos++]) { case PIC_OPX_EGA_SET_PALETTE_ENTRIES: while (vectorIsNonOpcode(data[curPos])) { @@ -726,6 +702,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { error("Unsupported sci1 extended pic-operation %X", pic_op); } } else { +#ifdef DEBUG_PICTURE_DRAW + debug("* Picture ex op: %X (%s) at %d", data[curPos], picExOpcodeNamesVGA[data[curPos]], curPos); +#endif switch (pic_op = data[curPos++]) { case PIC_OPX_VGA_SET_PALETTE_ENTRIES: while (vectorIsNonOpcode(data[curPos])) { @@ -733,7 +712,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { } break; case PIC_OPX_VGA_SET_PALETTE: - if (_resMan->getViewType() == kViewAmiga) { + if (_resMan->getViewType() == kViewAmiga || _resMan->getViewType() == kViewAmiga64) { if ((data[curPos] == 0x00) && (data[curPos + 1] == 0x01) && ((data[curPos + 32] & 0xF0) != 0xF0)) { // Left-Over VGA palette, we simply ignore it curPos += 256 + 4 + 1024; diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 9e6854e3b9..fd74714495 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -106,7 +106,8 @@ void GfxView::initData(GuiResourceId resourceId) { switch (curViewType) { case kViewEga: // SCI0 (and Amiga 16 colors) isEGA = true; - case kViewAmiga: // Amiga (32 colors) + case kViewAmiga: // Amiga ECS (32 colors) + case kViewAmiga64: // Amiga AGA (64 colors) case kViewVga: // View-format SCI1 // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... @@ -370,22 +371,129 @@ void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int1 outRect.top = outRect.bottom - scaledHeight; } +void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) { + byte *outPtr = celBitmap; + byte curByte, runLength; + byte *rlePtr = inBuffer + rlePos; + byte *literalPtr = inBuffer + literalPos; + int pixelNr = 0; + + memset(celBitmap, clearColor, pixelCount); + + if (!literalPos) { + // decompression for data that has only one combined stream + switch (viewType) { + case kViewEga: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte >> 4; + memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + } + break; + case kViewAmiga: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + if (curByte & 0x07) { // fill with color + runLength = curByte & 0x07; + curByte = curByte >> 3; + while (runLength-- && pixelNr < pixelCount) + outPtr[pixelNr++] = curByte; + } else { // fill with transparent + runLength = curByte >> 3; + pixelNr += runLength; + } + } + break; + case kViewAmiga64: + // TODO: This isn't 100% right. Implement it fully. + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte >> 6; + memset(outPtr + pixelNr, curByte & 0x3F, MIN<uint16>(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + } + break; + case kViewVga: + case kViewVga11: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte & 0x3F; + switch (curByte & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNr < pixelCount) + outPtr[pixelNr++] = *rlePtr++; + break; + case 0x40: // copy bytes as is (In copy case, runLength can go upto 127 i.e. pixel & 0x40). Fixes bug #3135872. + runLength += 64; + break; + case 0x80: // fill with color + memset(outPtr + pixelNr, *rlePtr++, MIN<uint16>(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + break; + case 0xC0: // fill with transparent + pixelNr += runLength; + break; + } + } + break; + default: + error("Unsupported picture viewtype"); + } + } else { + // decompression for data that has two separate streams (probably a SCI 1.1 view) + if (isMacSci11ViewData) { + // KQ6/Freddy Pharkas use byte lengths, all others use uint16 + // The SCI devs must have realized that a max of 255 pixels wide + // was not very good for 320 or 640 width games. + bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS); + + // compression for SCI1.1+ Mac + while (pixelNr < pixelCount) { + uint32 pixelLine = pixelNr; + + if (hasByteLengths) { + pixelNr += *rlePtr++; + runLength = *rlePtr++; + } else { + pixelNr += READ_BE_UINT16(rlePtr); + runLength = READ_BE_UINT16(rlePtr + 2); + rlePtr += 4; + } + + while (runLength-- && pixelNr < pixelCount) + outPtr[pixelNr++] = *literalPtr++; + + pixelNr = pixelLine + width; + } + } else { + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte & 0x3F; + switch (curByte & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNr < pixelCount) + outPtr[pixelNr++] = *literalPtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNr, *literalPtr++, MIN<uint16>(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + break; + case 0xC0: // fill with transparent + pixelNr += runLength; + break; + } + } + } + } +} + void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) { const CelInfo *celInfo = getCelInfo(loopNo, celNo); - byte *rlePtr; - byte *literalPtr; - uint32 pixelNo = 0, runLength; - byte pixel; if (celInfo->offsetEGA) { // decompression for EGA views - literalPtr = _resourceData + _loop[loopNo].cel[celNo].offsetEGA; - while (pixelNo < pixelCount) { - pixel = *literalPtr++; - runLength = pixel >> 4; - memset(outPtr + pixelNo, pixel & 0x0F, MIN<uint32>(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - } + unpackCelData(_resourceData, outPtr, 0, pixelCount, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false); } else { // We fill the buffer with transparent pixels, so that we can later skip // over pixels to automatically have them transparent @@ -408,100 +516,8 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou clearColor = 0; } - memset(outPtr, clearColor, pixelCount); - - rlePtr = _resourceData + celInfo->offsetRLE; - if (!celInfo->offsetLiteral) { // no additional literal data - if (_resMan->getViewType() == kViewAmiga) { - // decompression for amiga views - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - if (pixel & 0x07) { // fill with color - runLength = pixel & 0x07; - pixel = pixel >> 3; - while (runLength-- && pixelNo < pixelCount) { - outPtr[pixelNo++] = pixel; - } - } else { // fill with transparent - runLength = pixel >> 3; - pixelNo += runLength; - } - } - } else { - // decompression for data that has just one combined stream - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - runLength = pixel & 0x3F; - switch (pixel & 0xC0) { - case 0x40: // copy bytes as is (In copy case, runLength can go upto 127 i.e. pixel & 0x40) - runLength += 64; - case 0x00: // copy bytes as-is - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *rlePtr++; - break; - case 0x80: // fill with color - memset(outPtr + pixelNo, *rlePtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - break; - case 0xC0: // fill with transparent - pixelNo += runLength; - break; - } - } - } - } else { - literalPtr = _resourceData + celInfo->offsetLiteral; - if (celInfo->offsetRLE) { - if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1) { - // KQ6/Freddy Pharkas use byte lengths, all others use uint16 - // The SCI devs must have realized that a max of 255 pixels wide - // was not very good for 320 or 640 width games. - bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS); - - // compression for SCI1.1+ Mac - while (pixelNo < pixelCount) { - uint32 pixelLine = pixelNo; - - if (hasByteLengths) { - pixelNo += *rlePtr++; - runLength = *rlePtr++; - } else { - pixelNo += READ_BE_UINT16(rlePtr); - runLength = READ_BE_UINT16(rlePtr + 2); - rlePtr += 4; - } - - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *literalPtr++; - - pixelNo = pixelLine + celInfo->width; - } - } else { - // decompression for data that has separate rle and literal streams - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - runLength = pixel & 0x3F; - switch (pixel & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *literalPtr++; - break; - case 0x80: // fill with color - memset(outPtr + pixelNo, *literalPtr++, MIN<uint32>(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - break; - case 0xC0: // fill with transparent - pixelNo += runLength; - break; - } - } - } - } else { - // literal stream only, so no compression - memcpy(outPtr, literalPtr, pixelCount); - pixelNo = pixelCount; - } - } + bool isMacSci11ViewData = g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1; + unpackCelData(_resourceData, outPtr, clearColor, pixelCount, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData); // Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above) if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) { diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 002f520935..7a4534d3ac 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -948,15 +948,18 @@ void ResourceManager::init(bool initFromFallbackDetector) { case kViewEga: debugC(1, kDebugLevelResMan, "resMan: Detected EGA graphic resources"); break; + case kViewAmiga: + debugC(1, kDebugLevelResMan, "resMan: Detected Amiga ECS graphic resources"); + break; + case kViewAmiga64: + debugC(1, kDebugLevelResMan, "resMan: Detected Amiga AGA graphic resources"); + break; case kViewVga: debugC(1, kDebugLevelResMan, "resMan: Detected VGA graphic resources"); break; case kViewVga11: debugC(1, kDebugLevelResMan, "resMan: Detected SCI1.1 VGA graphic resources"); break; - case kViewAmiga: - debugC(1, kDebugLevelResMan, "resMan: Detected Amiga graphic resources"); - break; default: #ifdef ENABLE_SCI32 error("resMan: Couldn't determine view type"); @@ -2057,7 +2060,13 @@ ViewType ResourceManager::detectViewType() { switch (res->data[1]) { case 128: - // If the 2nd byte is 128, it's a VGA game + // If the 2nd byte is 128, it's a VGA game. + // However, Longbow Amiga (AGA, 64 colors), also sets this byte + // to 128, but it's a mixed VGA/Amiga format. Detect this from + // the platform here. + if (g_sci && g_sci->getPlatform() == Common::kPlatformAmiga) + return kViewAmiga64; + return kViewVga; case 0: // EGA or Amiga, try to read as Amiga view @@ -2264,7 +2273,7 @@ void ResourceManager::detectSciVersion() { case kResVersionKQ5FMT: s_sciVersion = SCI_VERSION_1_MIDDLE; // Amiga SCI1 middle games are actually SCI1 late - if (_viewType == kViewAmiga) + if (_viewType == kViewAmiga || _viewType == kViewAmiga64) s_sciVersion = SCI_VERSION_1_LATE; return; case kResVersionSci1Late: |