aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorsylvaintv2011-03-08 00:54:40 +0100
committersylvaintv2011-03-08 00:54:40 +0100
commitb2a72da6518b30a58a1257ff7217185ae5683628 (patch)
tree41e5d532124466b09a396ec4b043ec74e1b9ea56 /engines/sci
parent53d6a4f831c9e7c7de594cdaed3c8546b41ea2e2 (diff)
parent9fb28410b5ea27fa8e79ac5f0ac4ce70ae4cf3c6 (diff)
downloadscummvm-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.cpp6
-rw-r--r--engines/sci/engine/gc.cpp8
-rw-r--r--engines/sci/engine/kmisc.cpp2
-rw-r--r--engines/sci/engine/vm_types.cpp12
-rw-r--r--engines/sci/engine/workarounds.cpp8
-rw-r--r--engines/sci/graphics/cursor.cpp24
-rw-r--r--engines/sci/graphics/helpers.h3
-rw-r--r--engines/sci/graphics/palette.cpp16
-rw-r--r--engines/sci/graphics/picture.cpp151
-rw-r--r--engines/sci/graphics/view.cpp228
-rw-r--r--engines/sci/resource.cpp19
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: