void OpenGlTexture::updateLevel(uint32 level, const Graphics::Surface *surface, const byte *palette) { if (level == 0) { _width = surface->w; _height = surface->h; } if (surface->format.bytesPerPixel != 4) { // Convert the surface to texture format Graphics::Surface *convertedSurface = surface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), palette); glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, convertedSurface->w, convertedSurface->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, convertedSurface->getPixels()); convertedSurface->free(); delete convertedSurface; } else { glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, surface->getPixels()); } }
void writeSavegameHeader(Common::OutSaveFile *out, CruiseSavegameHeader &header) { // Write out a savegame header char saveIdentBuffer[6]; strcpy(saveIdentBuffer, "SVMCR"); out->write(saveIdentBuffer, 6); out->writeByte(CRUISE_SAVEGAME_VERSION); // Write savegame name out->write(header.saveName.c_str(), header.saveName.size() + 1); // Create a thumbnail and save it Graphics::Surface *thumb = new Graphics::Surface(); ::createThumbnail(thumb, globalScreen, 320, 200, workpal); Graphics::saveThumbnail(*out, *thumb); thumb->free(); delete thumb; }
Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { if (shouldQuit()) return 0; Common::WriteStream *out = 0; if (!(out = _saveFileMan->openForSaving(filename))) { warning("Can't create file '%s', game not saved", filename); return 0; } // Savegame version out->writeUint32BE(MKTAG('W', 'W', 'S', 'V')); out->writeByte(_flags.gameID); out->writeUint32BE(CURRENT_SAVE_VERSION); out->write(saveName, strlen(saveName) + 1); if (_flags.isTalkie) out->writeUint32BE(GF_TALKIE); else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) out->writeUint32BE(GF_FMTOWNS); else out->writeUint32BE(GF_FLOPPY); if (out->err()) { warning("Can't write file '%s'. (Disk full?)", filename); delete out; return 0; } Graphics::Surface *genThumbnail = 0; if (!thumbnail) thumbnail = genThumbnail = generateSaveThumbnail(); if (thumbnail) Graphics::saveThumbnail(*out, *thumbnail); else Graphics::saveThumbnail(*out); if (genThumbnail) { genThumbnail->free(); delete genThumbnail; } return out; }
SaveDataWidget::SaveDataWidget(int slot, Gfx::Driver *gfx, SaveLoadMenuScreen *screen) : StaticLocationWidget(nullptr, nullptr, nullptr), _slot(slot), _screen(screen), _thumbWidth(StarkUserInterface->kThumbnailWidth), _thumbHeight(StarkUserInterface->kThumbnailHeight), _texture(gfx->createTexture()), _outline(gfx->createTexture()), _surfaceRenderer(gfx->createSurfaceRenderer()), _textDesc(gfx), _textTime(gfx), _isMouseHovered(false), _hasSave(false), _name() { // Load from the save data loadSaveDataElements(); _textDesc.setColor(_textColor); _textDesc.setFont(FontProvider::kCustomFont, 3); _textTime.setColor(_textColor); _textTime.setFont(FontProvider::kCustomFont, 3); // Create the outline texture Graphics::Surface lineSurface; lineSurface.create(_thumbWidth, _thumbHeight, Gfx::Driver::getRGBAPixelFormat()); lineSurface.drawThickLine(0, 0, _thumbWidth - 1, 0, 2, 2, _outlineColor); lineSurface.drawThickLine(0, 0, 0, _thumbHeight - 1, 2, 2, _outlineColor); lineSurface.drawThickLine(_thumbWidth - 2, 0, _thumbWidth - 2, _thumbHeight - 2, 2, 2, _outlineColor); lineSurface.drawThickLine(0, _thumbHeight - 2, _thumbWidth - 2, _thumbHeight - 2, 2, 2, _outlineColor); _outline->update(&lineSurface); lineSurface.free(); // Set the position _thumbPos.x = 41 + (_slot % SaveLoadMenuScreen::_slotPerRow) * (_thumbWidth + 39); _thumbPos.y = 61 + (_slot % SaveLoadMenuScreen::_slotPerPage / SaveLoadMenuScreen::_slotPerColumn) * (_thumbHeight + 38); _textDescPos.x = _thumbPos.x; _textDescPos.y = _thumbPos.y + _thumbHeight + 2; _textTimePos.x = _thumbPos.x; _textTimePos.y = _textDescPos.y + 12; }
void PlaybackFile::checkRecordedMD5() { uint8 currentMD5[16]; uint8 savedMD5[16]; Graphics::Surface screen; _readStream->read(savedMD5, 16); if (!g_eventRec.grabScreenAndComputeMD5(screen, currentMD5)) { return; } uint32 seconds = g_system->getMillis(true) / 1000; String screenTime = String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60); if (memcmp(savedMD5, currentMD5, 16) != 0) { debugC(1, kDebugLevelEventRec, "playback:action=\"Check screenshot\" time=%s result = fail", screenTime.c_str()); warning("Recorded and current screenshots are different"); } else { debugC(1, kDebugLevelEventRec, "playback:action=\"Check screenshot\" time=%s result = success", screenTime.c_str()); } Graphics::saveThumbnail(*_screenshotsFile, screen); screen.free(); }
void Menu::goToNode(uint16 node) { if (_vm->_state->getMenuSavedAge() == 0 && _vm->_state->getLocationRoom() != 901) { // Entering menu, save current location ... _vm->_state->setMenuSavedAge(_vm->_state->getLocationAge()); _vm->_state->setMenuSavedRoom(_vm->_state->getLocationRoom()); _vm->_state->setMenuSavedNode(_vm->_state->getLocationNode()); // ... and capture the screen Graphics::Surface *big = _vm->_gfx->getScreenshot(); createThumbnail(big, _saveThumb); big->free(); delete big; } _vm->_state->setMenuEscapePressed(0); _vm->_state->setLocationNextAge(9); _vm->_state->setLocationNextRoom(901); _vm->goToNode(node, 2); }
bool InputControl::process(uint32 deltaTimeInMillis) { if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; // First see if we need to render the text if (_textChanged) { // Blit the text using the RenderManager Graphics::Surface txt; txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_pixelFormat); if (!_readOnly || !_focused) _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt); else _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt); _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top); txt.free(); } if (_animation && !_readOnly && _focused) { bool needDraw = true;// = _textChanged; _frameDelay -= deltaTimeInMillis; if (_frameDelay <= 0) { _frame = (_frame + 1) % _animation->frameCount(); _frameDelay = _animation->frameTime(); needDraw = true; } if (needDraw) { const Graphics::Surface *srf = _animation->getFrameData(_frame); uint32 xx = _textRectangle.left + _txtWidth; if (xx >= _textRectangle.left + (_textRectangle.width() - _animation->width())) xx = _textRectangle.left + _textRectangle.width() - _animation->width(); _engine->getRenderManager()->blitSurfaceToBkg(*srf, xx, _textRectangle.top); } } _textChanged = false; return false; }
void RenderManager::processSubs(uint16 deltatime) { bool redraw = false; for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) { if (it->_value.timer != -1) { it->_value.timer -= deltatime; if (it->_value.timer <= 0) it->_value.todelete = true; } if (it->_value.todelete) { _subsList.erase(it); redraw = true; } else if (it->_value.redraw) { redraw = true; } } if (redraw) { _subtitleSurface.fillRect(Common::Rect(_subtitleSurface.w, _subtitleSurface.h), 0); for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) { OneSubtitle *sub = &it->_value; if (sub->txt.size()) { Graphics::Surface *rndr = new Graphics::Surface(); rndr->create(sub->r.width(), sub->r.height(), _engine->_resourcePixelFormat); _engine->getTextRenderer()->drawTxtInOneLine(sub->txt, *rndr); Common::Rect empty; blitSurfaceToSurface(*rndr, empty, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top); rndr->free(); delete rndr; } sub->redraw = false; } Common::Rect rect( _subtitleArea.left, _subtitleArea.top, _subtitleArea.left + _subtitleSurface.w, _subtitleArea.top + _subtitleSurface.h ); copyToScreen(_subtitleSurface, rect, 0, 0); } }
bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, Graphics::Surface *dest) { assert(dest); Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO); ::Image::PNGDecoder png; if (!png.loadStream(*fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done error("Error while reading PNG image"); const Graphics::Surface *sourceSurface = png.getSurface(); Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette()); dest->copyFrom(*pngSurface); pngSurface->free(); delete pngSurface; delete fileStr; // Signal success return true; }
void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &desc) { Common::String filename = getFilenameForSlot(slot); debugC(kWintermuteDebugSaveGame, "Trying to list savegame %s in slot %d", filename.c_str(), slot); if (DID_FAIL(readHeader(filename))) { debugC(kWintermuteDebugSaveGame, "getSavedDesc(%d) - Failed for %s", slot, filename.c_str()); return; } desc.setSaveSlot(slot); desc.setDescription(_savedDescription); desc.setDeletableFlag(true); desc.setWriteProtectedFlag(false); int thumbSize = 0; byte *thumbData = nullptr; if (_scummVMThumbSize > 0) { thumbSize = _scummVMThumbSize; thumbData = _scummVMThumbnailData; } else if (_thumbnailDataSize > 0) { thumbSize = _thumbnailDataSize; thumbData = _thumbnailData; } if (thumbSize > 0) { Common::MemoryReadStream thumbStream(thumbData, thumbSize, DisposeAfterUse::NO); Graphics::BitmapDecoder bmpDecoder; if (bmpDecoder.loadStream(thumbStream)) { const Graphics::Surface *bmpSurface = bmpDecoder.getSurface(); TransparentSurface *scaleableSurface = new TransparentSurface(*bmpSurface, false); Graphics::Surface *scaled = scaleableSurface->scale(kThumbnailWidth, kThumbnailHeight2); Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat()); desc.setThumbnail(thumb); delete scaleableSurface; scaled->free(); delete scaled; } } desc.setSaveDate(_savedTimestamp.tm_year, _savedTimestamp.tm_mon, _savedTimestamp.tm_mday); desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min); desc.setPlayTime(0); }
// TODO: this method will probably go away and be integrated in the main loop void Animation::play() { Common::EventManager *eventMan = g_system->getEventManager(); while (!hasEnded() && !Engine::shouldQuit()) { process(); if (_changed) { // Create a temporary surface to merge the overlay with the background Graphics::Surface *s = new Graphics::Surface; s->create(640, 480, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); draw(s); // XXX: Update the screen g_system->copyRectToScreen(s->getPixels(), s->pitch, 0, 0, s->w, s->h); // Free the temporary surface s->free(); delete s; _changed = false; } g_system->updateScreen(); //FIXME: implement subtitles g_system->delayMillis(20); // Handle right-click to interrupt animations Common::Event ev = Common::Event(); while (eventMan->pollEvent(ev)) { if (ev.type == Common::EVENT_RBUTTONUP) { // Stop audio if (_audio) _audio->finish(); // TODO start LNK file sound? return; } } } }
const Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) { if (!_jpeg->read(stream)) { warning("Failed to decode JPEG frame"); return 0; } if (!_surface) { _surface = new Graphics::Surface(); _surface->create(_jpeg->getWidth(), _jpeg->getHeight(), _pixelFormat.bytesPerPixel); } Graphics::Surface *frame = _jpeg->getSurface(_pixelFormat); assert(frame); _surface->copyFrom(*frame); frame->free(); delete frame; return _surface; }
void Cursor::loadAvailableCursors() { assert(_textures.empty()); // Load available cursors for (uint i = 0; i < ARRAYSIZE(availableCursors); i++) { // Check if a cursor sharing the same texture has already been loaded if (_textures.contains(availableCursors[i].nodeID)) continue; // Load the cursor bitmap const DirectorySubEntry *cursorDesc = _vm->getFileDescription("GLOB", availableCursors[i].nodeID, 0, DirectorySubEntry::kRawData); if (!cursorDesc) error("Cursor %d does not exist", availableCursors[i].nodeID); Common::MemoryReadStream *bmpStream = cursorDesc->getData(); Image::BitmapDecoder bitmapDecoder; if (!bitmapDecoder.loadStream(*bmpStream)) error("Could not decode Myst III bitmap"); const Graphics::Surface *surfaceBGRA = bitmapDecoder.getSurface(); Graphics::Surface *surfaceRGBA = surfaceBGRA->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); delete bmpStream; // Apply the colorkey for transparency for (uint u = 0; u < surfaceRGBA->w; u++) { for (uint v = 0; v < surfaceRGBA->h; v++) { uint32 *pixel = (uint32*)(surfaceRGBA->getBasePtr(u, v)); if (*pixel == 0xFF00FF00) *pixel = 0x0000FF00; } } // Create and store the texture _textures.setVal(availableCursors[i].nodeID, _vm->_gfx->createTexture(surfaceRGBA)); surfaceRGBA->free(); delete surfaceRGBA; } }
bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) { Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO); ::Image::PNGDecoder png; if (!png.loadStream(*fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done error("Error while reading PNG image"); const Graphics::Surface *sourceSurface = png.getSurface(); Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), png.getPalette()); width = pngSurface->w; height = pngSurface->h; uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h]; memcpy(uncompressedDataPtr, (byte *)pngSurface->getPixels(), pngSurface->pitch * pngSurface->h); pngSurface->free(); delete pngSurface; delete fileStr; // Signal success return true; }
bool Console::dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type) { const DirectorySubEntry *maskDesc = _vm->getFileDescription(0, index, face, type); if (!maskDesc) return false; Common::MemoryReadStream *maskStream = maskDesc->getData(); Graphics::Surface *mask = Effect::loadMask(maskStream); delete maskStream; Common::DumpFile outFile; outFile.open(Common::String::format("dump/%d-%d.masku_%d", index, face, type)); outFile.write(mask->getPixels(), mask->pitch * mask->h); outFile.close(); mask->free(); delete mask; return true; }
void OSystem_3DS::flushCursor() { if (_cursor.getPixels()) { Graphics::Surface *converted = _cursor.convertTo(_pfGameTexture, _cursorPaletteEnabled ? _cursorPalette : _palette); _cursorTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h)); _cursorTexture.markDirty(); converted->free(); delete converted; if (_pfCursor.bytesPerPixel == 1) { uint* dest = (uint*) _cursorTexture.getPixels(); byte* src = (byte*) _cursor.getPixels(); for (int y = 0; y < _cursor.h; ++y) { for (int x = 0; x < _cursor.w; ++x) { if (*src++ == _cursorKeyColor) *dest++ = 0; else dest++; } dest += _cursorTexture.w - _cursorTexture.actualWidth; } } } }
ThemeEngine::~ThemeEngine() { delete _vectorRenderer; _vectorRenderer = 0; _screen.free(); _backBuffer.free(); unloadTheme(); // Release all graphics surfaces for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i) { Graphics::Surface *surf = i->_value; if (surf) { surf->free(); delete surf; } } _bitmaps.clear(); delete _parser; delete _themeEval; delete[] _cursor; delete _themeArchive; }
Common::Error BladeRunnerEngine::saveGameState(int slot, const Common::String &desc) { Common::OutSaveFile *saveFile = BladeRunner::SaveFileManager::openForSaving(_targetName, slot); if (saveFile == nullptr || saveFile->err()) { delete saveFile; return Common::kReadingFailed; } Graphics::Surface thumbnail = generateThumbnail(); BladeRunner::SaveFileHeader header; header._name = desc; BladeRunner::SaveFileManager::writeHeader(*saveFile, header); saveGame(*saveFile, thumbnail); saveFile->finalize(); thumbnail.free(); delete saveFile; return Common::kNoError; }
void AVISurface::copyMovieFrame(const Graphics::Surface &src, Graphics::ManagedSurface &dest) { // WORKAROUND: Handle rare cases where frame sizes don't match the video size Common::Rect copyRect(0, 0, MIN(src.w, dest.w), MIN(src.h, dest.h)); if (src.format.bytesPerPixel == 1) { // Paletted 8-bit, so convert to 16-bit and copy over const byte *palette = _decoder->getPalette(); if (palette) { Graphics::Surface *s = src.convertTo(dest.format, palette); dest.blitFrom(*s, copyRect, Common::Point(0, 0)); s->free(); delete s; } } else if (src.format.bytesPerPixel == 2) { // Source is already 16-bit, with no alpha, so do a straight copy dest.blitFrom(src, copyRect, Common::Point(0, 0)); } else { // Source is 32-bit which may have transparent pixels. Copy over each // pixel, replacing transparent pixels with the special transparency color byte a, r, g, b; assert(src.format.bytesPerPixel == 4 && dest.format.bytesPerPixel == 2); uint16 transPixel = _videoSurface->getTransparencyColor(); for (uint y = 0; y < MIN(src.h, dest.h); ++y) { const uint32 *pSrc = (const uint32 *)src.getBasePtr(0, y); uint16 *pDest = (uint16 *)dest.getBasePtr(0, y); for (uint x = 0; x < MIN(src.w, dest.w); ++x, ++pSrc, ++pDest) { src.format.colorToARGB(*pSrc, a, r, g, b); assert(a == 0 || a == 0xff); *pDest = (a == 0) ? transPixel : dest.format.RGBToColor(r, g, b); } } } }
bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) { #ifndef USE_INTERNAL_PNG_DECODER png_structp png_ptr = NULL; png_infop info_ptr = NULL; int bitDepth; int colorType; int interlaceType; int i; // Check for valid PNG signature if (!doIsCorrectImageFormat(fileDataPtr, fileSize)) { error("png_check_sig failed"); } // Create both PNG structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { error("Could not create libpng read struct."); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { error("Could not create libpng info struct."); } // Use alternative reading function const byte **ref = &fileDataPtr; png_set_read_fn(png_ptr, (void *)ref, png_user_read_data); // Read PNG header png_read_info(png_ptr, info_ptr); // Read out PNG informations png_uint_32 w, h; png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); width = w; height = h; // Calculate pitch of output image pitch = GraphicEngine::calcPitch(GraphicEngine::CF_ARGB32, width); // Allocate memory for the final image data. // To keep memory framentation low this happens before allocating memory for temporary image data. uncompressedDataPtr = new byte[pitch * height]; if (!uncompressedDataPtr) { error("Could not allocate memory for output image."); } // Images of all color formates will be transformed into ARGB images if (bitDepth == 16) png_set_strip_16(png_ptr); if (colorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (bitDepth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); // After the transformations have been registered, the image data is read again. png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); width = w; height = h; if (interlaceType == PNG_INTERLACE_NONE) { // PNGs without interlacing can simply be read row by row. for (i = 0; i < height; i++) { png_read_row(png_ptr, uncompressedDataPtr + i * pitch, NULL); } } else { // PNGs with interlacing require us to allocate an auxillary // buffer with pointers to all row starts. // Allocate row pointer buffer png_bytep *pRowPtr = new png_bytep[height]; if (!pRowPtr) { error("Could not allocate memory for row pointers."); } // Initialize row pointers for (i = 0; i < height; i++) pRowPtr[i] = uncompressedDataPtr + i * pitch; // Read image data png_read_image(png_ptr, pRowPtr); // Free row pointer buffer delete[] pRowPtr; } // Read additional data at the end. png_read_end(png_ptr, NULL); // Destroy libpng structures png_destroy_read_struct(&png_ptr, &info_ptr, NULL); #else Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO); Graphics::PNG *png = new Graphics::PNG(); if (!png->read(fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done error("Error while reading PNG image"); Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); Graphics::Surface *pngSurface = png->getSurface(format); width = pngSurface->w; height = pngSurface->h; uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h]; memcpy(uncompressedDataPtr, (byte *)pngSurface->pixels, pngSurface->pitch * pngSurface->h); pngSurface->free(); delete pngSurface; delete png; #endif // Signal success return true; }
bool VideoManager::updateMovies() { bool updateScreen = false; for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) { // Skip deleted videos if (!_videoStreams[i].video) continue; // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { _videoStreams[i]->seek(_videoStreams[i].start); } else { // Check the video time one last time before deleting it _vm->doVideoTimer(i, true); delete _videoStreams[i].video; _videoStreams[i].clear(); continue; } } // Nothing more to do if we're paused if (_videoStreams[i]->isPaused()) continue; // Check if we need to draw a frame if (_videoStreams[i]->needsUpdate()) { const Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame(); Graphics::Surface *convertedFrame = 0; if (frame && _videoStreams[i].enabled) { Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); if (frame->format != pixelFormat) { // We don't support downconverting to 8bpp if (pixelFormat.bytesPerPixel == 1) error("Cannot convert high color video frame to 8bpp"); // Convert to the current screen format convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette()); frame = convertedFrame; } else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) { // Set the palette when running in 8bpp mode only _vm->_system->getPaletteManager()->setPalette(_videoStreams[i]->getPalette(), 0, 256); } // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; // Delete 8bpp conversion surface if (convertedFrame) { convertedFrame->free(); delete convertedFrame; } } } // Check the video time _vm->doVideoTimer(i, false); } // Return true if we need to update the screen return updateScreen; }
bool writePNG(Common::WriteStream &out, const Graphics::Surface &input, const bool bottomUp) { #ifdef USE_PNG const Graphics::PixelFormat requiredFormat_3byte(3, 8, 8, 8, 0, 16, 8, 0, 0); const Graphics::PixelFormat requiredFormat_4byte(4, 8, 8, 8, 8, 0, 8, 16, 24); if (input.format.bytesPerPixel == 3) { if (input.format != requiredFormat_3byte) { warning("Cannot currently write PNG with 3-byte pixel format other than %s", requiredFormat_3byte.toString().c_str()); return false; } } else if (input.format.bytesPerPixel != 4) { warning("Cannot currently write PNG with pixel format of bpp other than 3, 4"); return false; } int colorType; Graphics::Surface *tmp = NULL; const Graphics::Surface *surface; if (input.format == requiredFormat_3byte) { surface = &input; colorType = PNG_COLOR_TYPE_RGB; } else { if (input.format == requiredFormat_4byte) { surface = &input; } else { surface = tmp = input.convertTo(requiredFormat_4byte); } colorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) { return false; } png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { png_destroy_write_struct(&pngPtr, NULL); return false; } png_set_error_fn(pngPtr, NULL, pngError, pngWarning); // TODO: The manual says errors should be handled via setjmp png_set_write_fn(pngPtr, &out, pngWriteToStream, pngFlushStream); png_set_IHDR(pngPtr, infoPtr, surface->w, surface->h, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); Common::Array<const uint8 *> rows; rows.reserve(surface->h); if (bottomUp) { for (uint y = surface->h; y-- > 0;) { rows.push_back((const uint8 *)surface->getBasePtr(0, y)); } } else { for (uint y = 0; y < surface->h; ++y) { rows.push_back((const uint8 *)surface->getBasePtr(0, y)); } } png_set_rows(pngPtr, infoPtr, const_cast<uint8 **>(&rows.front())); png_write_png(pngPtr, infoPtr, 0, NULL); png_destroy_write_struct(&pngPtr, &infoPtr); // free tmp surface if (tmp) { tmp->free(); delete tmp; } return true; #else return false; #endif }
BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, TTextAlign align, int maxHeight, int &textOffset) { //TextLineList lines; // TODO: Use WideString-conversion here. //WrapText(text, width, maxHeight, lines); Common::Array<WideString> lines; _font->wordWrapText(text, width, lines); while (maxHeight > 0 && lines.size() * _lineHeight > maxHeight) { lines.pop_back(); } if (lines.size() == 0) { return nullptr; } Graphics::TextAlign alignment = Graphics::kTextAlignInvalid; if (align == TAL_LEFT) { alignment = Graphics::kTextAlignLeft; } else if (align == TAL_CENTER) { alignment = Graphics::kTextAlignCenter; } else if (align == TAL_RIGHT) { alignment = Graphics::kTextAlignRight; } // TODO: This debug call does not work with WideString because text.c_str() returns an uint32 array. //debugC(kWintermuteDebugFont, "%s %d %d %d %d", text.c_str(), RGBCOLGetR(_layers[0]->_color), RGBCOLGetG(_layers[0]->_color), RGBCOLGetB(_layers[0]->_color), RGBCOLGetA(_layers[0]->_color)); // void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; Graphics::Surface *surface = new Graphics::Surface(); surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), _gameRef->_renderer->getPixelFormat()); uint32 useColor = 0xffffffff; Common::Array<WideString>::iterator it; int heightOffset = 0; for (it = lines.begin(); it != lines.end(); ++it) { _font->drawString(surface, *it, 0, heightOffset, width, useColor, alignment); heightOffset += (int)_lineHeight; } BaseSurface *retSurface = _gameRef->_renderer->createSurface(); if (_deletableFont) { // Reconstruct the alpha channel of the font. // Since we painted it with color 0xFFFFFFFF onto a black background, // the alpha channel is gone, but the color value of each pixel corresponds // to its original alpha value. Graphics::PixelFormat format = _gameRef->_renderer->getPixelFormat(); uint32 *pixels = (uint32 *)surface->getPixels(); // This is a Surface we created ourselves, so no empty space between rows. for (int i = 0; i < surface->w * surface->h; ++i) { uint8 a, r, g, b; format.colorToRGB(*pixels, r, g, b); a = r; *pixels++ = format.ARGBToColor(a, r, g, b); } } retSurface->putSurface(*surface, true); surface->free(); delete surface; return retSurface; // TODO: _isUnderline, _isBold, _isItalic, _isStriked }
bool VideoManager::updateMovies() { bool updateScreen = false; for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) { // Skip deleted videos if (!_videoStreams[i].video) continue; // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { _videoStreams[i]->seekToTime(_videoStreams[i].start); } else { delete _videoStreams[i].video; _videoStreams[i].clear(); continue; } } // Check if we need to draw a frame if (!_videoStreams[i]->isPaused() && _videoStreams[i]->needsUpdate()) { const Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame(); Graphics::Surface *convertedFrame = 0; if (frame && _videoStreams[i].enabled) { // Convert from 8bpp to the current screen format if necessary Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); if (frame->format.bytesPerPixel == 1) { if (pixelFormat.bytesPerPixel == 1) { if (_videoStreams[i]->hasDirtyPalette()) _videoStreams[i]->setSystemPalette(); } else { convertedFrame = new Graphics::Surface(); const byte *palette = _videoStreams[i]->getPalette(); assert(palette); convertedFrame->create(frame->w, frame->h, pixelFormat); for (uint16 j = 0; j < frame->h; j++) { for (uint16 k = 0; k < frame->w; k++) { byte palIndex = *((const byte *)frame->getBasePtr(k, j)); byte r = palette[palIndex * 3]; byte g = palette[palIndex * 3 + 1]; byte b = palette[palIndex * 3 + 2]; if (pixelFormat.bytesPerPixel == 2) *((uint16 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); else *((uint32 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); } } frame = convertedFrame; } } // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; // Delete 8bpp conversion surface if (convertedFrame) { convertedFrame->free(); delete convertedFrame; } } } } // Return true if we need to update the screen return updateScreen; }
void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect, bool skippable, Subtitle *sub) { Common::Rect dst = destRect; // If destRect is empty, no specific scaling was requested. However, we may choose to do scaling anyway if (dst.isEmpty()) dst = Common::Rect(vid.getWidth(), vid.getHeight()); Graphics::Surface *scaled = NULL; if (vid.getWidth() != dst.width() || vid.getHeight() != dst.height()) { scaled = new Graphics::Surface; scaled->create(dst.width(), dst.height(), vid.getPixelFormat()); } uint16 x = _workingWindow.left + dst.left; uint16 y = _workingWindow.top + dst.top; uint16 finalWidth = dst.width() < _workingWindow.width() ? dst.width() : _workingWindow.width(); uint16 finalHeight = dst.height() < _workingWindow.height() ? dst.height() : _workingWindow.height(); bool showSubs = (_scriptManager->getStateValue(StateKey_Subtitles) == 1); _clock.stop(); vid.start(); _videoIsPlaying = true; // Only continue while the video is still playing while (!shouldQuit() && !vid.endOfVideo() && vid.isPlaying()) { // Check for engine quit and video stop key presses while (_eventMan->pollEvent(_event)) { switch (_event.type) { case Common::EVENT_KEYDOWN: switch (_event.kbd.keycode) { case Common::KEYCODE_q: if (_event.kbd.hasFlags(Common::KBD_CTRL)) quitGame(); break; case Common::KEYCODE_SPACE: if (skippable) { vid.stop(); } break; default: break; } default: break; } } if (vid.needsUpdate()) { const Graphics::Surface *frame = vid.decodeNextFrame(); if (sub && showSubs) sub->process(vid.getCurFrame()); if (frame) { if (scaled) { _renderManager->scaleBuffer(frame->getPixels(), scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, scaled->w, scaled->h); frame = scaled; } Common::Rect rect = Common::Rect(x, y, x + finalWidth, y + finalHeight); _renderManager->copyToScreen(*frame, rect, 0, 0); _renderManager->processSubs(0); } } // Always update the screen so the mouse continues to render _system->updateScreen(); _system->delayMillis(vid.getTimeToNextFrame() / 2); } _videoIsPlaying = false; _clock.start(); if (scaled) { scaled->free(); delete scaled; } }
bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) { Video::VideoDecoder *video = videoEntry->_video; const Graphics::Surface *frame = video->decodeNextFrame(); if (!frame || !videoEntry->isEnabled()) { return false; } Graphics::Surface *convertedFrame = nullptr; Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); if (frame->format != pixelFormat) { // We don't support downconverting to 8bpp without having // support in the codec. Set _enableDither if shows up. if (pixelFormat.bytesPerPixel == 1) { warning("Cannot convert high color video frame to 8bpp"); return false; } // Convert to the current screen format convertedFrame = frame->convertTo(pixelFormat, video->getPalette()); frame = convertedFrame; } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) { // Set the palette when running in 8bpp mode only // Don't do this for Myst, which has its own per-stack handling if (_vm->getGameType() != GType_MYST) _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256); } // Clip the video to make sure it stays on the screen (Myst does this a few times) Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight()); targetRect.translate(videoEntry->getX(), videoEntry->getY()); Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight()); if (targetRect.left < 0) { frameRect.left -= targetRect.left; targetRect.left = 0; } if (targetRect.top < 0) { frameRect.top -= targetRect.top; targetRect.top = 0; } if (targetRect.right > _vm->_system->getWidth()) { frameRect.right -= targetRect.right - _vm->_system->getWidth(); targetRect.right = _vm->_system->getWidth(); } if (targetRect.bottom > _vm->_system->getHeight()) { frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight(); targetRect.bottom = _vm->_system->getHeight(); } _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch, targetRect.left, targetRect.top, targetRect.width(), targetRect.height()); // Delete 8bpp conversion surface if (convertedFrame) { convertedFrame->free(); delete convertedFrame; } // We've drawn something to the screen, make sure we update it return true; }
bool VideoManager::updateMovies() { bool updateScreen = false; for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) { // Skip deleted videos if (!_videoStreams[i].video) continue; // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { _videoStreams[i]->seekToTime(_videoStreams[i].start); } else { // Check the video time one last time before deleting it _vm->doVideoTimer(i, true); delete _videoStreams[i].video; _videoStreams[i].clear(); continue; } } // Nothing more to do if we're paused if (_videoStreams[i]->isPaused()) continue; // Check if we need to draw a frame if (_videoStreams[i]->needsUpdate()) { const Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame(); Graphics::Surface *convertedFrame = 0; if (frame && _videoStreams[i].enabled) { Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); // Create (or resize) the off-screen surface if (frame->w > _videoStreams[i].surface.w || frame->h > _videoStreams[i].surface.h) { _videoStreams[i].surface.create(frame->w, frame->h, pixelFormat); } // Convert from 8bpp to the current screen format if necessary if (frame->format.bytesPerPixel == 1) { if (pixelFormat.bytesPerPixel == 1) { if (_videoStreams[i]->hasDirtyPalette()) _videoStreams[i]->setSystemPalette(); } else { convertedFrame = new Graphics::Surface(); const byte *palette = _videoStreams[i]->getPalette(); assert(palette); convertedFrame->create(frame->w, frame->h, pixelFormat); for (uint16 j = 0; j < frame->h; j++) { for (uint16 k = 0; k < frame->w; k++) { byte palIndex = *((const byte *)frame->getBasePtr(k, j)); byte r = palette[palIndex * 3]; byte g = palette[palIndex * 3 + 1]; byte b = palette[palIndex * 3 + 2]; if (pixelFormat.bytesPerPixel == 2) *((uint16 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); else *((uint32 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); } } frame = convertedFrame; } } // Copy frame to the off-screen surface for (int y = 0; y < frame->h; ++y) { memcpy(_videoStreams[i].surface.getBasePtr(0, y), frame->getBasePtr(0, y), frame->w * pixelFormat.bytesPerPixel); } // Delete 8bpp conversion surface if (convertedFrame) { convertedFrame->free(); delete convertedFrame; } } } // Don't draw anything until we have a valid surface if (_videoStreams[i].surface.w == 0 || _videoStreams[i].surface.h == 0) continue; // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); // Render the off-screen surface _vm->_system->copyRectToScreen((byte *)_videoStreams[i].surface.pixels, _videoStreams[i].surface.pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); updateScreen = true; // Check the video time _vm->doVideoTimer(i, false); } // Return true if we need to update the screen return updateScreen; }
bool AnimationEffect::process(uint32 deltaTimeInMillis) { ScriptManager *scriptManager = _engine->getScriptManager(); RenderManager *renderManager = _engine->getRenderManager(); RenderTable::RenderState renderState = renderManager->getRenderTable()->getRenderState(); bool isPanorama = (renderState == RenderTable::PANORAMA); int16 velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity(); // Do not update animation nodes in panoramic mode while turning, if the user // has set this option if (scriptManager->getStateValue(StateKey_NoTurnAnim) == 1 && isPanorama && velocity) return false; PlayNodes::iterator it = _playList.begin(); if (it != _playList.end()) { playnode *nod = &(*it); if (nod->_curFrame == -1) { // The node is just beginning playback nod->_curFrame = nod->start; _animation->start(); _animation->seekToFrame(nod->start); _animation->setEndFrame(nod->stop); nod->_delay = deltaTimeInMillis; // Force the frame to draw if (nod->slot) scriptManager->setStateValue(nod->slot, 1); } else if (_animation->endOfVideo()) { // The node has reached the end; check if we need to loop nod->loop--; if (nod->loop == 0) { if (nod->slot >= 0) scriptManager->setStateValue(nod->slot, 2); if (nod->_scaled) { nod->_scaled->free(); delete nod->_scaled; } _playList.erase(it); return _disposeAfterUse; } nod->_curFrame = nod->start; _animation->seekToFrame(nod->start); } // Check if we need to draw a frame bool needsUpdate = false; if (_frmDelayOverride == 0) { // If not overridden, use the VideoDecoder's check needsUpdate = _animation->needsUpdate(); } else { // Otherwise, implement our own timing nod->_delay -= deltaTimeInMillis; if (nod->_delay <= 0) { nod->_delay += _frmDelayOverride; needsUpdate = true; } } if (needsUpdate) { const Graphics::Surface *frame = _animation->decodeNextFrame(); if (frame) { uint32 dstw; uint32 dsth; if (isPanorama) { dstw = nod->pos.height(); dsth = nod->pos.width(); } else { dstw = nod->pos.width(); dsth = nod->pos.height(); } // We only scale down the animation to fit its frame, not up, otherwise we // end up with distorted animations - e.g. the armor visor in location cz1e // in Nemesis (one of the armors inside Irondune), or the planet in location // aa10 in Nemesis (Juperon, outside the asylum). We do allow scaling up only // when a simple 2x filter is requested (e.g. the alchemists and cup sequence // in Nemesis) if (frame->w > dstw || frame->h > dsth || (frame->w == dstw / 2 && frame->h == dsth / 2)) { if (nod->_scaled) if (nod->_scaled->w != dstw || nod->_scaled->h != dsth) { nod->_scaled->free(); delete nod->_scaled; nod->_scaled = NULL; } if (!nod->_scaled) { nod->_scaled = new Graphics::Surface; nod->_scaled->create(dstw, dsth, frame->format); } renderManager->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth); frame = nod->_scaled; } if (isPanorama) { Graphics::Surface *transposed = RenderManager::tranposeSurface(frame); renderManager->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask); transposed->free(); delete transposed; } else { renderManager->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask); } } } } return false; }
void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in) { int numBytes = in.readSint16BE(); int y1 = in.readSint16BE(); int x1 = in.readSint16BE(); int y2 = in.readSint16BE(); int x2 = in.readSint16BE(); int w = x2 - x1; int h = y2 - y1; Graphics::Surface tmp; tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); numBytes -= 10; int x = 0, y = 0; while (numBytes > 0 && y < h) { int n = in.readSByte(); int count; int b = 0; int state = 0; numBytes--; if ((n >= 0) && (n <= 127)) { // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. count = n + 1; state = 1; } else if ((n >= -127) && (n <= -1)) { // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. b = in.readByte(); numBytes--; count = -n + 1; state = 2; } else { // Else if n is -128, noop. count = 0; } for (int i = 0; i < count && y < h; i++) { byte color = 0; if (state == 1) { color = in.readByte(); numBytes--; } else if (state == 2) color = b; for (int c = 0; c < 8; c++) { if (_boundsCalculationMode) { adjustBounds(x1 + x, y1 + y); } else if (x1 + x >= 0 && x1 + x < surface->w && y1 + y >= 0 && y1 + y < surface->h) *((byte *)tmp.getBasePtr(x, y)) = (color & (1 << (7 - c % 8))) ? kColorBlack : kColorWhite; x++; if (x == w) { y++; x = 0; break; } } } } in.skip(numBytes); if (!_boundsCalculationMode) { Graphics::FloodFill ff(&tmp, kColorWhite, kColorGreen); for (int yy = 0; yy < h; yy++) { ff.addSeed(0, yy); ff.addSeed(w - 1, yy); } for (int xx = 0; xx < w; xx++) { ff.addSeed(xx, 0); ff.addSeed(xx, h - 1); } ff.fill(); for (y = 0; y < h && y1 + y < surface->h; y++) { byte *src = (byte *)tmp.getBasePtr(0, y); byte *dst = (byte *)surface->getBasePtr(x1, y1 + y); for (x = 0; x < w; x++) { if (*src != kColorGreen) *dst = *src; src++; dst++; } } } tmp.free(); }
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) { Common::Rect srcRect = _srcRect; if (srcRect.isEmpty()) srcRect = Common::Rect(src.w, src.h); srcRect.clip(src.w, src.h); Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h); srcRect.clip(dstRect); if (srcRect.isEmpty() || !srcRect.isValidRect()) return; Graphics::Surface *srcAdapted = src.convertTo(dst.format); uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1); // Copy srcRect from src surface to dst surface const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top); int xx = _x; int yy = _y; if (xx < 0) xx = 0; if (yy < 0) yy = 0; if (_x >= dst.w || _y >= dst.h) { srcAdapted->free(); delete srcAdapted; return; } byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy); int32 w = srcRect.width(); int32 h = srcRect.height(); for (int32 y = 0; y < h; y++) { switch (srcAdapted->format.bytesPerPixel) { case 1: { const uint *srcTemp = (const uint *)srcBuffer; uint *dstTemp = (uint *)dstBuffer; for (int32 x = 0; x < w; x++) { if (*srcTemp != keycolor) *dstTemp = *srcTemp; srcTemp++; dstTemp++; } } break; case 2: { const uint16 *srcTemp = (const uint16 *)srcBuffer; uint16 *dstTemp = (uint16 *)dstBuffer; for (int32 x = 0; x < w; x++) { if (*srcTemp != keycolor) *dstTemp = *srcTemp; srcTemp++; dstTemp++; } } break; case 4: { const uint32 *srcTemp = (const uint32 *)srcBuffer; uint32 *dstTemp = (uint32 *)dstBuffer; for (int32 x = 0; x < w; x++) { if (*srcTemp != keycolor) *dstTemp = *srcTemp; srcTemp++; dstTemp++; } } break; default: break; } srcBuffer += srcAdapted->pitch; dstBuffer += dst.pitch; } srcAdapted->free(); delete srcAdapted; }