void GfxPicture::drawSci11Vga() { byte *inbuffer = _resource->data; int size = _resource->size; int priorityBandsCount = inbuffer[3]; int has_cel = inbuffer[4]; int vector_dataPos = READ_LE_UINT32(inbuffer + 16); int vector_size = size - vector_dataPos; int palette_data_ptr = READ_LE_UINT32(inbuffer + 28); int cel_headerPos = READ_LE_UINT32(inbuffer + 32); int cel_RlePos = READ_LE_UINT32(inbuffer + cel_headerPos + 24); int cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28); Palette palette; // Header // [headerSize:WORD] [unknown:BYTE] [priorityBandCount:BYTE] [hasCel:BYTE] [unknown:BYTE] // [unknown:WORD] [unknown:WORD] [unknown:WORD] [unknown:WORD] [unknown:WORD] // Offset 16 // [vectorDataOffset:DWORD] [unknown:DWORD] [unknown:DWORD] [paletteDataOffset:DWORD] // Offset 32 // [celHeaderOffset:DWORD] [unknown:DWORD] // [priorityBandData:WORD] * priorityBandCount // [priority:BYTE] [unknown:BYTE] // priority bands are supposed to be 14 for sci1.1 pictures assert(priorityBandsCount == 14); if (_addToFlag) { _priority = inbuffer[40 + priorityBandsCount * 2] & 0xF; } // display Cel-data if (has_cel) { // Create palette and set it _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette); _palette->set(&palette, true); drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0); } // process vector data drawVectorData(inbuffer + vector_dataPos, vector_size); // Set priority band information _ports->priorityBandsInitSci11(inbuffer + 40); }
void GfxPicture::drawSci11Vga() { SciSpan<const byte> inbuffer(*_resource); int priorityBandsCount = inbuffer[3]; int has_cel = inbuffer[4]; int vector_dataPos = inbuffer.getUint32LEAt(16); int vector_size = _resource->size() - vector_dataPos; int palette_data_ptr = inbuffer.getUint32LEAt(28); int cel_headerPos = inbuffer.getUint32LEAt(32); int cel_RlePos = inbuffer.getUint32LEAt(cel_headerPos + 24); int cel_LiteralPos = inbuffer.getUint32LEAt(cel_headerPos + 28); Palette palette; // Header // [headerSize:WORD] [unknown:BYTE] [priorityBandCount:BYTE] [hasCel:BYTE] [unknown:BYTE] // [unknown:WORD] [unknown:WORD] [unknown:WORD] [unknown:WORD] [unknown:WORD] // Offset 16 // [vectorDataOffset:DWORD] [unknown:DWORD] [unknown:DWORD] [paletteDataOffset:DWORD] // Offset 32 // [celHeaderOffset:DWORD] [unknown:DWORD] // [priorityBandData:WORD] * priorityBandCount // [priority:BYTE] [unknown:BYTE] // priority bands are supposed to be 14 for sci1.1 pictures assert(priorityBandsCount == 14); if (_addToFlag) { _priority = inbuffer[40 + priorityBandsCount * 2] & 0xF; } // display Cel-data if (has_cel) { // Create palette and set it _palette->createFromData(inbuffer.subspan(palette_data_ptr), &palette); _palette->set(&palette, true); drawCelData(inbuffer, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0, 0, false); } // process vector data drawVectorData(inbuffer.subspan(vector_dataPos, vector_size)); // Set priority band information _ports->priorityBandsInitSci11(inbuffer.subspan(40)); }
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 GfxPicture::drawVectorData(byte *data, int dataSize) { byte pic_op; byte pic_color = _screen->getColorDefaultVectorData(); byte pic_priority = 255, pic_control = 255; int16 x = 0, y = 0, oldx, oldy; byte EGApalettes[PIC_EGAPALETTE_TOTALSIZE] = {0}; byte *EGApalette = &EGApalettes[_EGApaletteNo * PIC_EGAPALETTE_SIZE]; byte EGApriority[PIC_EGAPRIORITY_SIZE] = {0}; bool isEGA = false; int curPos = 0; uint16 size; byte pixel; int i; Palette palette; int16 pattern_Code = 0, pattern_Texture = 0; bool icemanDrawFix = false; bool ignoreBrokenPriority = false; memset(&palette, 0, sizeof(palette)); if (_EGApaletteNo >= PIC_EGAPALETTE_COUNT) _EGApaletteNo = 0; if (_resMan->getViewType() == kViewEga) { isEGA = true; // setup default mapping tables for (i = 0; i < PIC_EGAPALETTE_TOTALSIZE; i += PIC_EGAPALETTE_SIZE) memcpy(&EGApalettes[i], &vector_defaultEGApalette, sizeof(vector_defaultEGApalette)); memcpy(&EGApriority, &vector_defaultEGApriority, sizeof(vector_defaultEGApriority)); if (g_sci->getGameId() == GID_ICEMAN) { // WORKAROUND: we remove certain visual&priority lines in underwater // rooms of iceman, when not dithering the picture. Normally those // lines aren't shown, because they share the same color as the // dithered fill color combination. When not dithering, those lines // would appear and get distracting. if ((_screen->isUnditheringEnabled()) && ((_resourceId >= 53 && _resourceId <= 58) || (_resourceId == 61))) icemanDrawFix = true; } if (g_sci->getGameId() == GID_KQ5) { // WORKAROUND: ignore the seemingly broken priority of picture 48 // (island overview). Fixes bug #3041044. if (_resourceId == 48) ignoreBrokenPriority = true; } if (g_sci->getGameId() == GID_SQ4) { // WORKAROUND: ignore the seemingly broken priority of pictures 546 // and 547 (Vohaul's head and Roger Jr trapped). Fixes bug #3046543. if (_resourceId == 546 || _resourceId == 547) ignoreBrokenPriority = true; // WORKAROUND: ignore the seemingly broken priority of picture 631 // (SQ1 view from the cockpit). Fixes bug #3046513. if (_resourceId == 631) ignoreBrokenPriority = true; } } // Drawing while (curPos < dataSize) { #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++]; if (isEGA) { pic_color = EGApalette[pic_color]; pic_color ^= pic_color << 4; } break; case PIC_OP_DISABLE_VISUAL: pic_color = 0xFF; break; case PIC_OP_SET_PRIORITY: pic_priority = data[curPos++] & 0x0F; if (isEGA) pic_priority = EGApriority[pic_priority]; if (ignoreBrokenPriority) pic_priority = 255; break; case PIC_OP_DISABLE_PRIORITY: pic_priority = 255; break; case PIC_OP_SET_CONTROL: pic_control = data[curPos++] & 0x0F; break; case PIC_OP_DISABLE_CONTROL: pic_control = 255; break; case PIC_OP_SHORT_LINES: // short line vectorGetAbsCoords(data, curPos, x, y); while (vectorIsNonOpcode(data[curPos])) { oldx = x; oldy = y; vectorGetRelCoords(data, curPos, x, y); Common::Point startPoint(oldx, oldy); Common::Point endPoint(x, y); _ports->offsetLine(startPoint, endPoint); _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); } break; case PIC_OP_MEDIUM_LINES: // medium line vectorGetAbsCoords(data, curPos, x, y); if (icemanDrawFix) { // WORKAROUND: remove certain lines in iceman ffs. see above if ((pic_color == 1) && (pic_priority == 14)) { if ((y < 100) || (!(y & 1))) { pic_color = 255; pic_priority = 255; } } } while (vectorIsNonOpcode(data[curPos])) { oldx = x; oldy = y; vectorGetRelCoordsMed(data, curPos, x, y); Common::Point startPoint(oldx, oldy); Common::Point endPoint(x, y); _ports->offsetLine(startPoint, endPoint); _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); } break; case PIC_OP_LONG_LINES: // long line vectorGetAbsCoords(data, curPos, x, y); while (vectorIsNonOpcode(data[curPos])) { oldx = x; oldy = y; vectorGetAbsCoords(data, curPos, x, y); Common::Point startPoint(oldx, oldy); Common::Point endPoint(x, y); _ports->offsetLine(startPoint, endPoint); _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); } break; case PIC_OP_FILL: //fill while (vectorIsNonOpcode(data[curPos])) { vectorGetAbsCoords(data, curPos, x, y); vectorFloodFill(x, y, pic_color, pic_priority, pic_control); } break; // Pattern opcodes are handled in sierra sci1.1+ as actual NOPs and // normally they definitely should not occur inside picture data for // such games. case PIC_OP_SET_PATTERN: if (_resourceType >= SCI_PICTURE_TYPE_SCI11) { if (g_sci->getGameId() == GID_SQ4) { // WORKAROUND: For SQ4 / for some pictures handle this like // a terminator. This picture includes garbage data, first a // set pattern w/o parameter and then short pattern. I guess // that garbage is a left over from the sq4-floppy (sci1) to // sq4-cd (sci1.1) conversion. switch (_resourceId) { case 35: case 381: case 376: return; default: break; } } error("pic-operation set pattern inside sci1.1+ vector data"); } pattern_Code = data[curPos++]; break; case PIC_OP_SHORT_PATTERNS: if (_resourceType >= SCI_PICTURE_TYPE_SCI11) error("pic-operation short pattern inside sci1.1+ vector data"); vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); vectorGetAbsCoords(data, curPos, x, y); vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); while (vectorIsNonOpcode(data[curPos])) { vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); vectorGetRelCoords(data, curPos, x, y); vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); } break; case PIC_OP_MEDIUM_PATTERNS: if (_resourceType >= SCI_PICTURE_TYPE_SCI11) error("pic-operation medium pattern inside sci1.1+ vector data"); vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); vectorGetAbsCoords(data, curPos, x, y); vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); while (vectorIsNonOpcode(data[curPos])) { vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); vectorGetRelCoordsMed(data, curPos, x, y); vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); } break; case PIC_OP_ABSOLUTE_PATTERN: if (_resourceType >= SCI_PICTURE_TYPE_SCI11) error("pic-operation absolute pattern inside sci1.1+ vector data"); while (vectorIsNonOpcode(data[curPos])) { vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); vectorGetAbsCoords(data, curPos, x, y); vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); } break; 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])) { pixel = data[curPos++]; if (pixel >= PIC_EGAPALETTE_TOTALSIZE) { error("picture trying to write to invalid EGA-palette"); } EGApalettes[pixel] = data[curPos++]; } break; case PIC_OPX_EGA_SET_PALETTE: pixel = data[curPos++]; if (pixel >= PIC_EGAPALETTE_COUNT) { error("picture trying to write to invalid palette %d", (int)pixel); } pixel *= PIC_EGAPALETTE_SIZE; for (i = 0; i < PIC_EGAPALETTE_SIZE; i++) { EGApalettes[pixel + i] = data[curPos++]; } break; case PIC_OPX_EGA_MONO0: curPos += 41; break; case PIC_OPX_EGA_MONO1: case PIC_OPX_EGA_MONO3: curPos++; break; case PIC_OPX_EGA_MONO2: case PIC_OPX_EGA_MONO4: break; case PIC_OPX_EGA_EMBEDDED_VIEW: vectorGetAbsCoordsNoMirror(data, curPos, x, y); size = READ_LE_UINT16(data + curPos); curPos += 2; _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0); curPos += size; break; case PIC_OPX_EGA_SET_PRIORITY_TABLE: _ports->priorityBandsInit(data + curPos); curPos += 14; break; default: 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])) { curPos++; // skip commands } break; case PIC_OPX_VGA_SET_PALETTE: 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; } else { // Setting half of the Amiga palette _palette->modifyAmigaPalette(&data[curPos]); curPos += 32; } } else { curPos += 256 + 4; // Skip over mapping and timestamp for (i = 0; i < 256; i++) { palette.colors[i].used = data[curPos++]; palette.colors[i].r = data[curPos++]; palette.colors[i].g = data[curPos++]; palette.colors[i].b = data[curPos++]; } _palette->set(&palette, true); } break; case PIC_OPX_VGA_EMBEDDED_VIEW: // draw cel vectorGetAbsCoordsNoMirror(data, curPos, x, y); size = READ_LE_UINT16(data + curPos); curPos += 2; _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0); curPos += size; break; case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST: _ports->priorityBandsInit(-1, READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2)); curPos += 4; break; case PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT: _ports->priorityBandsInit(data + curPos); curPos += 14; break; default: error("Unsupported sci1 extended pic-operation %X", pic_op); } } break; case PIC_OP_TERMINATE: _priority = pic_priority; // Dithering EGA pictures if (isEGA) { _screen->dither(_addToFlag); switch (g_sci->getGameId()) { case GID_SQ3: switch (_resourceId) { case 154: // SQ3: intro, ship gets sucked in _screen->ditherForceDitheredColor(0xD0); break; default: break; } break; default: break; } } return; default: error("Unsupported pic-operation %X", pic_op); } if ((_EGAdrawingVisualize) && (isEGA)) { _screen->copyToScreen(); g_system->updateScreen(); g_system->delayMillis(10); } } error("picture vector data without terminator"); }