SCI: Merged the cel data unpacking code for views and pictures

This commit is contained in:
md5 2011-03-06 19:22:32 +02:00
parent 0b24fc3acc
commit d2ad7898d9
2 changed files with 122 additions and 189 deletions

View File

@ -224,19 +224,20 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu
} }
#endif #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) { void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX) {
byte *celBitmap = NULL; byte *celBitmap = NULL;
byte *ptr = NULL; byte *ptr = NULL;
byte *headerPtr = inbuffer + headerPos; byte *headerPtr = inbuffer + headerPos;
byte *rlePtr = inbuffer + rlePos; byte *rlePtr = inbuffer + rlePos;
byte *literalPtr = inbuffer + literalPos;
int16 displaceX, displaceY; int16 displaceX, displaceY;
byte priority = _addToFlag ? _priority : 0; byte priority = _addToFlag ? _priority : 0;
byte clearColor; byte clearColor;
bool compression = true; bool compression = true;
byte curByte, runLength; byte curByte;
int16 y, lastY, x, leftX, rightX; int16 y, lastY, x, leftX, rightX;
int pixelNr, pixelCount; int pixelCount;
uint16 width, height; uint16 width, height;
#ifdef ENABLE_SCI32 #ifdef ENABLE_SCI32
@ -247,12 +248,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
height = READ_LE_UINT16(headerPtr + 2); height = READ_LE_UINT16(headerPtr + 2);
displaceX = (signed char)headerPtr[4]; displaceX = (signed char)headerPtr[4];
displaceY = (unsigned char)headerPtr[5]; 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 // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
clearColor = _screen->getColorWhite(); clearColor = _screen->getColorWhite();
} else { else
clearColor = headerPtr[6]; clearColor = headerPtr[6];
}
#ifdef ENABLE_SCI32 #ifdef ENABLE_SCI32
} else { } else {
width = READ_SCI11ENDIAN_UINT16(headerPtr + 0); width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);
@ -268,91 +268,18 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
if (displaceX || displaceY) if (displaceX || displaceY)
error("unsupported embedded cel-data in picture"); 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; pixelCount = width * height;
celBitmap = new byte[pixelCount]; celBitmap = new byte[pixelCount];
if (!celBitmap) if (!celBitmap)
error("Unable to allocate temporary memory for picture drawing"); error("Unable to allocate temporary memory for picture drawing");
if (compression) { if (compression)
// We will unpack cel-data into a temporary buffer and then plot it to screen unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false);
// That needs to be done cause a mirrored picture may be requested else
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 {
// No compression (some SCI32 pictures) // No compression (some SCI32 pictures)
memcpy(celBitmap, rlePtr, pixelCount); memcpy(celBitmap, rlePtr, pixelCount);
}
Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea(); Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();

View File

@ -370,22 +370,120 @@ void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int1
outRect.top = outRect.bottom - scaledHeight; 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 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 {
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;
}
}
// decompression for data that has two separate streams (probably SCI 1.1 view)
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) { void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) {
const CelInfo *celInfo = getCelInfo(loopNo, celNo); const CelInfo *celInfo = getCelInfo(loopNo, celNo);
byte *rlePtr;
byte *literalPtr;
uint32 pixelNo = 0, runLength;
byte pixel;
if (celInfo->offsetEGA) { if (celInfo->offsetEGA) {
// decompression for EGA views // decompression for EGA views
literalPtr = _resourceData + _loop[loopNo].cel[celNo].offsetEGA; unpackCelData(_resourceData, outPtr, 0, pixelCount, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false);
while (pixelNo < pixelCount) {
pixel = *literalPtr++;
runLength = pixel >> 4;
memset(outPtr + pixelNo, pixel & 0x0F, MIN<uint32>(runLength, pixelCount - pixelNo));
pixelNo += runLength;
}
} else { } else {
// We fill the buffer with transparent pixels, so that we can later skip // We fill the buffer with transparent pixels, so that we can later skip
// over pixels to automatically have them transparent // over pixels to automatically have them transparent
@ -408,100 +506,8 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou
clearColor = 0; clearColor = 0;
} }
memset(outPtr, clearColor, 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);
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;
}
}
// Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above) // Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above)
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) { if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) {