SciVersion GameFeatures::detectMessageFunctionType() { if (_messageFunctionType != SCI_VERSION_NONE) return _messageFunctionType; if (getSciVersion() > SCI_VERSION_1_1) { _messageFunctionType = SCI_VERSION_1_1; return _messageFunctionType; } else if (getSciVersion() < SCI_VERSION_1_1) { _messageFunctionType = SCI_VERSION_1_LATE; return _messageFunctionType; } Common::List<ResourceId> resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1); if (resources.empty()) { // No messages found, so this doesn't really matter anyway... _messageFunctionType = SCI_VERSION_1_1; return _messageFunctionType; } Resource *res = g_sci->getResMan()->findResource(*resources.begin(), false); assert(res); // Only v2 Message resources use the kGetMessage kernel function. // v3-v5 use the kMessage kernel function. if (READ_SCI11ENDIAN_UINT32(res->data) / 1000 == 2) _messageFunctionType = SCI_VERSION_1_LATE; else _messageFunctionType = SCI_VERSION_1_1; debugC(1, kDebugLevelVM, "Detected message function type: %s", getSciVersionDesc(_messageFunctionType)); return _messageFunctionType; }
void GfxText32::drawChar(const uint8 charIndex) { byte *bitmap = _segMan->getHunkPointer(_bitmap); byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); _font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height); _drawPosition.x += _font->getCharWidth(charIndex); }
void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictureX, bool mirrored) { byte *inbuffer = _resource->data; int size = _resource->size; int header_size = READ_SCI11ENDIAN_UINT16(inbuffer); int palette_data_ptr = READ_SCI11ENDIAN_UINT32(inbuffer + 6); // int celCount = inbuffer[2]; int cel_headerPos = header_size; int cel_RlePos, cel_LiteralPos; Palette palette; // HACK _mirroredFlag = mirrored; _addToFlag = false; _resourceType = SCI_PICTURE_TYPE_SCI32; if (celNo == 0) { // Create palette and set it _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette); _palette->set(&palette, true); } // Header // [headerSize:WORD] [celCount:BYTE] [Unknown:BYTE] [Unknown:WORD] [paletteOffset:DWORD] [Unknown:DWORD] // cel-header follow afterwards, each is 42 bytes // Cel-Header // [width:WORD] [height:WORD] [displaceX:WORD] [displaceY:WORD] [clearColor:BYTE] [compressed:BYTE] // offset 10-23 is unknown // [rleOffset:DWORD] [literalOffset:DWORD] [Unknown:WORD] [Unknown:WORD] [priority:WORD] [relativeXpos:WORD] [relativeYpos:WORD] cel_headerPos += 42 * celNo; if (mirrored) { // switch around relativeXpos Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea(); drawX = displayArea.width() - drawX - READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0); } cel_RlePos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 24); cel_LiteralPos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 28); drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, drawX, drawY, pictureX); cel_headerPos += 42; }
void GfxText32::erase(const Common::Rect &rect, const bool doScaling) { Common::Rect targetRect = doScaling ? rect : scaleRect(rect); byte *bitmap = _segMan->getHunkPointer(_bitmap); byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); // NOTE: There is an extra optimisation within the SCI code to // do a single memset if the scaledRect is the same size as // the bitmap, not implemented here. Buffer buffer(_width, _height, pixels); buffer.fillRect(targetRect, _backColor); }
void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling) { Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; byte *bitmap = _segMan->getHunkPointer(_bitmap); byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); // NOTE: Not fully disassembled, but this should be right // TODO: Implement variable frame size assert(size == 1); Buffer buffer(_width, _height, pixels); buffer.frameRect(targetRect, color); }
const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const { const byte *const data = getPalPointer(); EntryHeader header; header.startColor = data[10]; header.numColors = READ_SCI11ENDIAN_UINT16(data + 14); header.used = data[16]; header.sharedUsed = data[17]; header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset); return header; }
uint32 RobotDecoder::createCel5(const byte *rawVideoData, const int16 screenItemIndex, const bool usePalette) { _verticalScaleFactor = rawVideoData[1]; const int16 celWidth = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 2); const int16 celHeight = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 4); const Common::Point celPosition((int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 10), (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 12)); const uint16 dataSize = READ_SCI11ENDIAN_UINT16(rawVideoData + 14); const int16 numDataChunks = (int16)READ_SCI11ENDIAN_UINT16(rawVideoData + 16); rawVideoData += kCelHeaderSize; const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; Common::Point origin; if (scriptWidth == kLowResX && scriptHeight == kLowResY) { const Ratio lowResToScreenX(screenWidth, kLowResX); const Ratio lowResToScreenY(screenHeight, kLowResY); const Ratio screenToLowResX(kLowResX, screenWidth); const Ratio screenToLowResY(kLowResY, screenHeight); const int16 scaledX = celPosition.x + (_position.x * lowResToScreenX).toInt(); const int16 scaledY1 = celPosition.y + (_position.y * lowResToScreenY).toInt(); const int16 scaledY2 = scaledY1 + celHeight - 1; const int16 lowResX = (scaledX * screenToLowResX).toInt(); const int16 lowResY = (scaledY2 * screenToLowResY).toInt(); origin.x = (scaledX - (lowResX * lowResToScreenX).toInt()) * -1; origin.y = (lowResY * lowResToScreenY).toInt() - scaledY1; _screenItemX[screenItemIndex] = lowResX; _screenItemY[screenItemIndex] = lowResY; debugC(kDebugLevelVideo, "Low resolution position c: %d %d l: %d/%d %d/%d d: %d %d s: %d/%d %d/%d x: %d y: %d", celPosition.x, celPosition.y, lowResX, scriptWidth, lowResY, scriptHeight, origin.x, origin.y, scaledX, screenWidth, scaledY2, screenHeight, scaledX - origin.x, scaledY2 - origin.y); } else { const int16 highResX = celPosition.x + _position.x; const int16 highResY = celPosition.y + _position.y + celHeight - 1; origin.x = 0; origin.y = celHeight - 1; _screenItemX[screenItemIndex] = highResX; _screenItemY[screenItemIndex] = highResY; debugC(kDebugLevelVideo, "High resolution position c: %d %d s: %d %d d: %d %d", celPosition.x, celPosition.y, highResX, highResY, origin.x, origin.y); } _originalScreenItemX[screenItemIndex] = celPosition.x; _originalScreenItemY[screenItemIndex] = celPosition.y; assert(_celHandles[screenItemIndex].area >= celWidth * celHeight); SciBitmap &bitmap = *_segMan->lookupBitmap(_celHandles[screenItemIndex].bitmapId); assert(bitmap.getWidth() == celWidth && bitmap.getHeight() == celHeight); assert(bitmap.getXResolution() == _xResolution && bitmap.getYResolution() == _yResolution); assert(bitmap.getHunkPaletteOffset() == (uint32)bitmap.getWidth() * bitmap.getHeight() + SciBitmap::getBitmapHeaderSize()); bitmap.setOrigin(origin); byte *targetBuffer = nullptr; if (_verticalScaleFactor == 100) { // direct copy to bitmap targetBuffer = bitmap.getPixels(); } else { // go through squashed cel decompressor _celDecompressionBuffer.resize(_celDecompressionArea >= celWidth * (celHeight * _verticalScaleFactor / 100)); targetBuffer = _celDecompressionBuffer.begin(); } for (int i = 0; i < numDataChunks; ++i) { uint compressedSize = READ_SCI11ENDIAN_UINT32(rawVideoData); uint decompressedSize = READ_SCI11ENDIAN_UINT32(rawVideoData + 4); uint16 compressionType = READ_SCI11ENDIAN_UINT16(rawVideoData + 8); rawVideoData += 10; switch (compressionType) { case kCompressionLZS: { Common::MemoryReadStream videoDataStream(rawVideoData, compressedSize, DisposeAfterUse::NO); _decompressor.unpack(&videoDataStream, targetBuffer, compressedSize, decompressedSize); break; } case kCompressionNone: Common::copy(rawVideoData, rawVideoData + decompressedSize, targetBuffer); break; default: error("Unknown compression type %d!", compressionType); } rawVideoData += compressedSize; targetBuffer += decompressedSize; } if (_verticalScaleFactor != 100) { expandCel(bitmap.getPixels(), _celDecompressionBuffer.begin(), celWidth, celHeight); } if (usePalette) { Common::copy(_rawPalette, _rawPalette + kRawPaletteSize, bitmap.getHunkPalette()); } return kCelHeaderSize + dataSize; }
bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &record) { Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMessage, stack.getModule()), 0); if (!res) { warning("Failed to open message resource %d", stack.getModule()); return false; } MessageReader *reader; int version = READ_SCI11ENDIAN_UINT32(res->data) / 1000; switch (version) { case 2: reader = new MessageReaderV2(res->data, res->size); break; case 3: reader = new MessageReaderV3(res->data, res->size); break; case 4: #ifdef ENABLE_SCI32 case 5: // v5 seems to be compatible with v4 // SCI32 Mac is different than SCI32 DOS/Win here if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1) reader = new MessageReaderV4_MacSCI32(res->data, res->size); else #endif reader = new MessageReaderV4(res->data, res->size); break; default: error("Message: unsupported resource version %d", version); return false; } if (!reader->init()) { delete reader; warning("Message: failed to read resource header"); return false; } while (1) { MessageTuple &t = stack.top(); if (!reader->findRecord(t, record)) { // Tuple not found if (recurse && (stack.size() > 1)) { stack.pop(); continue; } delete reader; return false; } if (recurse) { MessageTuple &ref = record.refTuple; if (ref.noun || ref.verb || ref.cond) { t.seq++; stack.push(ref); continue; } } delete reader; return true; } }
reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, reg_t *outBitmapObject) { _field_22 = 0; _borderColor = borderColor; _text = text; _textRect = rect; _foreColor = foreColor; _dimmed = dimmed; setFont(fontId); int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; int borderSize = 1; mulinc(_textRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight)); CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo); _skipColor = view._transparentColor; _width = view._width * _scaledWidth / view._scaledWidth; _height = view._height * _scaledHeight / view._scaledHeight; Common::Rect bitmapRect(_width, _height); if (_textRect.intersects(bitmapRect)) { _textRect.clip(bitmapRect); } else { _textRect = Common::Rect(); } _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + CelObjMem::getBitmapHeaderSize()); byte *bitmap = _segMan->getHunkPointer(_bitmap); CelObjMem::buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); Buffer buffer(_width, _height, bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28)); // NOTE: The engine filled the bitmap pixels with 11 here, which is silly // because then it just erased the bitmap using the skip color. So we don't // fill the bitmap redundantly here. _backColor = _skipColor; erase(bitmapRect, false); _backColor = backColor; view.draw(buffer, bitmapRect, Common::Point(0, 0), false, Ratio(_scaledWidth, view._scaledWidth), Ratio(_scaledHeight, view._scaledHeight)); if (_backColor != skipColor && _foreColor != skipColor) { erase(_textRect, false); } if (text.size() > 0) { if (_foreColor == skipColor) { error("TODO: Implement transparent text"); } else { if (borderColor != -1) { drawFrame(bitmapRect, borderSize, _borderColor, false); } drawTextBox(); } } *outBitmapObject = _bitmap; return _bitmap; }