Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect src_rect, uint zoom) const { if (src_rect.isEmpty()) { src_rect = Common::Rect(0, 0, w, h); } Common::Rect dst_rect(x + dx, y + dy, x + dx + zoom * src_rect.width() / 256, y + dy + zoom * src_rect.height() / 256); if (dst_rect.left < 0) { src_rect.left = -dst_rect.left; dst_rect.left = 0; } if (dst_rect.right > surface->w) { src_rect.right -= dst_rect.right - surface->w; dst_rect.right = surface->w; } if (dst_rect.top < 0) { src_rect.top -= dst_rect.top; dst_rect.top = 0; } if (dst_rect.bottom > surface->h) { src_rect.bottom -= dst_rect.bottom - surface->h; dst_rect.bottom = surface->h; } if (src_rect.isEmpty() || dst_rect.isEmpty()) return Common::Rect(); if (zoom == 256) { const byte *src = (const byte *)getBasePtr(0, src_rect.top); byte *dst_base = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top); for (int i = src_rect.top; i < src_rect.bottom; ++i) { byte *dst = dst_base; for (int j = src_rect.left; j < src_rect.right; ++j) { byte p = src[(mirror? w - j - 1: j)]; if (p != 0xff) *dst++ = p; else ++dst; } dst_base += surface->pitch; src += pitch; } } else { byte *dst = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top); for(int i = 0; i < dst_rect.height(); ++i) { for (int j = 0; j < dst_rect.width(); ++j) { int px = j * 256 / zoom; const byte *src = (const byte *)getBasePtr(src_rect.left + (mirror? w - px - 1: px), src_rect.top + i * 256 / zoom); byte p = *src; if (p != 0xff) dst[j] = p; } dst += surface->pitch; } } return dst_rect; }
int BbvsEngine::rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects) { int count = 0; Common::Rect workRect = rect1.findIntersectingRect(rect2); if (!workRect.isEmpty()) { count = 0; outRects[count] = Common::Rect(rect2.width(), workRect.top - rect2.top); if (!outRects[count].isEmpty()) { outRects[count].translate(rect2.left, rect2.top); ++count; } outRects[count] = Common::Rect(workRect.left - rect2.left, workRect.height()); if (!outRects[count].isEmpty()) { outRects[count].translate(rect2.left, workRect.top); ++count; } outRects[count] = Common::Rect(rect2.right - workRect.right, workRect.height()); if (!outRects[count].isEmpty()) { outRects[count].translate(workRect.right, workRect.top); ++count; } outRects[count] = Common::Rect(rect2.width(), rect2.bottom - workRect.bottom); if (!outRects[count].isEmpty()) { outRects[count].translate(rect2.left, workRect.bottom); ++count; } } else { outRects[0] = rect2; count = 1; } return count; }
void ThemeEngine::addDirtyRect(Common::Rect r) { // Clip the rect to screen coords r.clip(_screen.w, _screen.h); // If it is empty after clipping, we are done if (r.isEmpty()) return; // Check if the new rectangle is contained within another in the list Common::List<Common::Rect>::iterator it; for (it = _dirtyScreen.begin(); it != _dirtyScreen.end();) { // If we find a rectangle which fully contains the new one, // we can abort the search. if (it->contains(r)) return; // Conversely, if we find rectangles which are contained in // the new one, we can remove them if (r.contains(*it)) it = _dirtyScreen.erase(it); else ++it; } // If we got here, we can safely add r to the list of dirty rects. _dirtyScreen.push_back(r); }
bool PaintControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; if (_rectangle.contains(backgroundImageSpacePos)) { int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); if (eligeblity(mouseItem)) { _engine->getCursorManager()->changeCursor(_cursor); if (_mouseDown) { Common::Rect bkgRect = paint(backgroundImageSpacePos); if (!bkgRect.isEmpty()) { Common::Rect imgRect = bkgRect; imgRect.translate(-_rectangle.left, -_rectangle.top); Graphics::Surface imgUpdate = _bkg->getSubArea(imgRect); _engine->getRenderManager()->blitSurfaceToBkg(imgUpdate, bkgRect.left, bkgRect.top, _colorKey); } } return true; } } return false; }
Common::Rect PaintControl::paint(const Common::Point &point) { Common::Rect paintRect = Common::Rect(_brush->w, _brush->h); paintRect.moveTo(point); paintRect.clip(_rectangle); if (!paintRect.isEmpty()) { Common::Rect brushRect = paintRect; brushRect.translate(-point.x, -point.y); Common::Rect bkgRect = paintRect; bkgRect.translate(-_rectangle.left, -_rectangle.top); for (int yy = 0; yy < brushRect.height(); yy++) { uint16 *mask = (uint16 *)_brush->getBasePtr(brushRect.left, brushRect.top + yy); uint16 *from = (uint16 *)_paint->getBasePtr(bkgRect.left, bkgRect.top + yy); uint16 *to = (uint16 *)_bkg->getBasePtr(bkgRect.left, bkgRect.top + yy); for (int xx = 0; xx < brushRect.width(); xx++) { if (*mask != 0) *(to + xx) = *(from + xx); mask++; } } } return paintRect; }
void Render::addDirtyRect(Common::Rect r) { if (_fullRefresh) return; // Clip rectangle r.clip(_backGroundSurface.w, _backGroundSurface.h); // If it is empty after clipping, we are done if (r.isEmpty()) return; // Check if the new rectangle is contained within another in the list Common::List<Common::Rect>::iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ) { // If we find a rectangle which fully contains the new one, // we can abort the search. if (it->contains(r)) return; // Conversely, if we find rectangles which are contained in // the new one, we can remove them if (r.contains(*it)) it = _dirtyRects.erase(it); else ++it; } // If we got here, we can safely add r to the list of dirty rects. if (_vm->_interface->getFadeMode() != kFadeOut) _dirtyRects.push_back(r); }
/** * Creates the union of two rectangles. * Returns True if there is a union. * @param pDest destination rectangle that is to receive the new union * @param pSrc1 a source rectangle * @param pSrc2 a source rectangle */ bool UnionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { pDest.left = MIN(pSrc1.left, pSrc2.left); pDest.top = MIN(pSrc1.top, pSrc2.top); pDest.right = MAX(pSrc1.right, pSrc2.right); pDest.bottom = MAX(pSrc1.bottom, pSrc2.bottom); return !pDest.isEmpty(); }
void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte color, byte priority, byte control) { Common::Rect r = rect; r.clip(_ports->_curPort->rect); if (r.isEmpty()) // nothing to fill return; int16 oldPenMode = _ports->_curPort->penMode; _ports->offsetRect(r); int16 x, y; byte curVisual; // Doing visual first if (drawFlags & GFX_SCREEN_MASK_VISUAL) { if (oldPenMode == 2) { // invert mode for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { curVisual = _screen->getVisual(x, y); if (curVisual == color) { _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, priority, 0, 0); } else if (curVisual == priority) { _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0); } } } } else { // just fill rect with color for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { //20140521 // if(y >= 0) _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0); } } } } if (drawFlags < 2) return; drawFlags &= GFX_SCREEN_MASK_PRIORITY|GFX_SCREEN_MASK_CONTROL; // we need to isolate the bits, sierra sci saved priority and control inside one byte, we don't priority &= 0x0f; control &= 0x0f; if (oldPenMode != 2) { for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { _screen->putPixel(x, y, drawFlags, 0, priority, control); } } } else { for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { _screen->putPixel(x, y, drawFlags, 0, !_screen->getPriority(x, y), !_screen->getControl(x, y)); } } } }
void TattooMap::restoreArea(const Common::Rect &bounds) { Screen &screen = *_vm->_screen; Common::Rect r = bounds; r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h())); if (!r.isEmpty()) screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r); }
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y) { 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); // 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++) { memcpy(dstBuffer, srcBuffer, w * srcAdapted->format.bytesPerPixel); srcBuffer += srcAdapted->pitch; dstBuffer += dst.pitch; } srcAdapted->free(); delete srcAdapted; }
bool GraphicsManager::draw(Drawable *drawable, BackgroundType type, bool transition) { // TODO handle transition properly if (transition) clear(type); // TODO store rect for later use Common::Rect rect = drawable->draw(getSurface(type)); return (!rect.isEmpty()); }
void Surface::allocateSurface(const Common::Rect &bounds) { deallocateSurface(); if (bounds.isEmpty()) return; _bounds = bounds; _surface = new Graphics::Surface(); _surface->create(bounds.width(), bounds.height(), g_system->getScreenFormat()); _ownsSurface = true; }
// This version of drawCel is not supposed to call BitsShow()! void GfxPaint16::drawCel(GfxView *view, int16 loopNo, int16 celNo, const Common::Rect &celRect, byte priority, uint16 paletteNo, uint16 scaleX, uint16 scaleY) { Common::Rect clipRect = celRect; clipRect.clip(_ports->_curPort->rect); if (clipRect.isEmpty()) // nothing to draw return; Common::Rect clipRectTranslated = clipRect; _ports->offsetRect(clipRectTranslated); if (scaleX == 128 && scaleY == 128) view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo, false); else view->drawScaled(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, scaleX, scaleY); }
void Director::drawRect(const Common::Rect &rect) { _surface.fillRect(rect, 0); for (uint i = 0; i < _sprites.size(); ++i) { const Common::Rect &spriteRect = _sprites[i]->getBounds(); Common::Rect interRect = rect.findIntersectingRect(spriteRect); if (interRect.isEmpty()) continue; Common::Rect srcRect(interRect); srcRect.translate(-spriteRect.left, -spriteRect.top); _surface.transBlitFrom(*_sprites[i]->getDecoder()->getCurrentFrame(), srcRect, interRect, _sprites[i]->getDecoder()->getTransparentColourIndex()); } }
Graphics::Surface *RenderManager::getBkgRect(Common::Rect &rect) { Common::Rect dst = rect; dst.clip(_backgroundWidth, _backgroundHeight); if (dst.isEmpty() || !dst.isValidRect()) return NULL; Graphics::Surface *srf = new Graphics::Surface; srf->create(dst.width(), dst.height(), _currentBackgroundImage.format); srf->copyRectToSurface(_currentBackgroundImage, 0, 0, Common::Rect(dst)); return srf; }
void OpenGLGfxDriver::drawSurface(const Graphics::Surface *surface, Common::Point dest, Common::Rect rect) { // Draw the whole surface by default if (rect.isEmpty()) rect = Common::Rect(surface->w, surface->h); start2DMode(); float rasterX = (2 * (float)dest.x / (float)_screenWidth); float rasterY = (2 * (float)dest.y / (float)_screenHeight); glRasterPos2f(-1.0f + rasterX, 1.0f - rasterY); glDrawPixels(surface->w, surface->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); //glBegin(GL_QUADS); glVertex3i(-1, -1, -1); glVertex3i(1, -1, -1); glVertex3i(1, 1, -1); glVertex3i(-1, 1, -1); glEnd(); end2DMode(); }
// used in SCI0early exclusively void GfxPaint16::invertRectViaXOR(const Common::Rect &rect) { Common::Rect r = rect; int16 x, y; byte curVisual; r.clip(_ports->_curPort->rect); if (r.isEmpty()) // nothing to invert return; _ports->offsetRect(r); for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { curVisual = _screen->getVisual(x, y); _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, curVisual ^ 0x0f, 0, 0); } } }
/** * @brief Marks a dirty rectangle on the surface * @param r The rectangle to be marked dirty */ void Surface::markDirtyRect(Common::Rect r) { Common::List<Common::Rect>::iterator it; r.clip(w, h); if (r.isEmpty()) return; it = _dirtyRects.begin(); while (it != _dirtyRects.end()) { if (it->contains(r)) return; if (r.contains(*it)) it = _dirtyRects.erase(it); else ++it; } _dirtyRects.push_back(r); }
// Like pixelation but uses 8x8 blocks - works against the whole screen. // TODO: it seems this needs to get applied on _picRect only if possible void GfxTransitions::blocks(bool blackoutFlag) { uint16 mask = 0x40, stepNr = 0; Common::Rect blockRect; uint32 msecCount = 0; do { mask = (mask & 1) ? (mask >> 1) ^ 0x240 : mask >> 1; if (mask >= 40 * 25) continue; blockRect.left = (mask % 40) << 3; blockRect.right = blockRect.left + 8; blockRect.top = (mask / 40) << 3; blockRect.bottom = blockRect.top + 8; blockRect.clip(_picRect); if (!blockRect.isEmpty()) copyRectToScreen(blockRect, blackoutFlag); if ((stepNr & 7) == 0) { msecCount += 5; updateScreenAndWait(msecCount); } stepNr++; } while (mask != 0x40); }
// Pixelates the new picture over the old one - works against the whole screen. // TODO: it seems this needs to get applied on _picRect only if possible void GfxTransitions::pixelation(bool blackoutFlag) { uint16 mask = 0x40, stepNr = 0; Common::Rect pixelRect; uint32 msecCount = 0; do { mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1; if (mask >= _screen->getWidth() * _screen->getHeight()) continue; pixelRect.left = mask % _screen->getWidth(); pixelRect.right = pixelRect.left + 1; pixelRect.top = mask / _screen->getWidth(); pixelRect.bottom = pixelRect.top + 1; pixelRect.clip(_picRect); if (!pixelRect.isEmpty()) copyRectToScreen(pixelRect, blackoutFlag); if ((stepNr & 0x3FF) == 0) { msecCount += 9; updateScreenAndWait(msecCount); } stepNr++; } while (mask != 0x40); }
uint16 GfxCompare::isOnControl(uint16 screenMask, const Common::Rect &rect) { int16 x, y; uint16 result = 0; if (rect.isEmpty()) return 0; if (screenMask & GFX_SCREEN_MASK_PRIORITY) { for (y = rect.top; y < rect.bottom; y++) { for (x = rect.left; x < rect.right; x++) { result |= 1 << _screen->getPriority(x, y); } } } else { for (y = rect.top; y < rect.bottom; y++) { for (x = rect.left; x < rect.right; x++) { result |= 1 << _screen->getControl(x, y); } } } return result; }
void GfxAnimate::updateScreen(byte oldPicNotValid) { AnimateList::iterator it; const AnimateList::iterator end = _list.end(); Common::Rect lsRect; Common::Rect workerRect; for (it = _list.begin(); it != end; ++it) { if (it->showBitsFlag || !(it->signal & (kSignalRemoveView | kSignalNoUpdate) || (!(it->signal & kSignalRemoveView) && (it->signal & kSignalNoUpdate) && oldPicNotValid))) { lsRect.left = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsLeft)); lsRect.top = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsTop)); lsRect.right = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsRight)); lsRect.bottom = readSelectorValue(_s->_segMan, it->object, SELECTOR(lsBottom)); workerRect = lsRect; workerRect.clip(it->celRect); if (!workerRect.isEmpty()) { workerRect = lsRect; workerRect.extend(it->celRect); } else { _paint16->bitsShow(lsRect); workerRect = it->celRect; } writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsLeft), it->celRect.left); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsTop), it->celRect.top); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsRight), it->celRect.right); writeSelectorValue(_s->_segMan, it->object, SELECTOR(lsBottom), it->celRect.bottom); // may get used for debugging //_paint16->frameRect(workerRect); _paint16->bitsShow(workerRect); if (it->signal & kSignalHidden) it->signal |= kSignalRemoveView; } } // use this for debug purposes // _screen->copyToScreen(); }
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; if (vid.getWidth() != dst.width() || vid.getHeight() != dst.height()) 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.getPixels()) { _renderManager->scaleBuffer(frame->getPixels(), scaled.getPixels(), frame->getWidth(), frame->getHeight(), frame->getFormat().bytesPerPixel, scaled.getWidth(), scaled.getHeight()); 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(); }
void Sprite::blit(const Sprite &from, const Common::Rect &area, int32 x, int32 y, bool transp) { // Sanity checks assert((x >= 0) && (y >= 0) && (x <= 0x7FFF) && (y <= 0x7FFF)); if (!exists() || !from.exists()) return; Common::Rect toArea = getArea(true); toArea.left = x; toArea.top = y; if (toArea.isEmpty()) return; Common::Rect fromArea = from.getArea(); fromArea.clip(area); fromArea.setWidth (MIN(fromArea.width() , toArea.width())); fromArea.setHeight(MIN(fromArea.height(), toArea.height())); if (fromArea.isEmpty() || !fromArea.isValidRect()) return; int32 w = fromArea.width(); int32 h = fromArea.height(); const int32 fromTop = fracToInt(fromArea.top * from._scaleInverse); const int32 fromLeft = fracToInt(fromArea.left * from._scaleInverse); const byte *src = (const byte *) from._surfaceTrueColor.getBasePtr(fromLeft, fromTop); byte *dst = ( byte *) _surfaceTrueColor.getBasePtr(x, y); const uint8 *srcT = from._transparencyMap + fromTop * from._surfaceTrueColor.w + fromLeft; uint8 *dstT = _transparencyMap + y * _surfaceTrueColor.w + x; frac_t posW = 0, posH = 0; while (h-- > 0) { posW = 0; const byte *srcRow = src; byte *dstRow = dst; const uint8 *srcRowT = srcT; uint8 *dstRowT = dstT; for (int32 j = 0; j < w; j++, dstRow += _surfaceTrueColor.bytesPerPixel, dstRowT++) { if (!transp || (*srcRowT == 0)) { // Ignore transparency or source is solid => copy memcpy(dstRow, srcRow, _surfaceTrueColor.bytesPerPixel); *dstRowT = *srcRowT; } else if (*srcRowT == 2) { // Half-transparent if (*dstRowT == 1) // But destination is transparent => propagate memcpy(dstRow, srcRow, _surfaceTrueColor.bytesPerPixel); else // Destination is solid => mix ImgConv.mixTrueColor(dstRow, srcRow); *dstRowT = *srcRowT; } // Advance source data posW += from._scaleInverse; while (posW >= ((frac_t) FRAC_ONE)) { srcRow += from._surfaceTrueColor.bytesPerPixel; srcRowT++; posW -= FRAC_ONE; } } dst += _surfaceTrueColor.pitch; dstT += _surfaceTrueColor.w; // Advance source data posH += from._scaleInverse; while (posH >= ((frac_t) FRAC_ONE)) { src += from._surfaceTrueColor.pitch; srcT += from._surfaceTrueColor.w; posH -= FRAC_ONE; } } }
void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect, bool skippable) { byte bytesPerPixel = videoDecoder.getPixelFormat().bytesPerPixel; uint16 origWidth = videoDecoder.getWidth(); uint16 origHeight = videoDecoder.getHeight(); uint scale = 1; // If destRect is empty, no specific scaling was requested. However, we may choose to do scaling anyway if (destRect.isEmpty()) { // Most videos are very small. Therefore we do a simple 2x scale if (origWidth * 2 <= 640 && origHeight * 2 <= 480) { scale = 2; } } else { // Assume bilinear scaling. AKA calculate the scale from just the width. // Also assume that the scaling is in integral intervals. AKA no 1.5x scaling // TODO: Test ^these^ assumptions scale = destRect.width() / origWidth; // TODO: Test if we need to support downscale. } uint16 pitch = origWidth * bytesPerPixel; uint16 finalWidth = origWidth * scale; uint16 finalHeight = origHeight * scale; byte *scaledVideoFrameBuffer; if (scale != 1) { scaledVideoFrameBuffer = new byte[finalWidth * finalHeight * bytesPerPixel]; } uint16 x = ((WINDOW_WIDTH - finalWidth) / 2) + destRect.left; uint16 y = ((WINDOW_HEIGHT - finalHeight) / 2) + destRect.top; _clock.stop(); videoDecoder.start(); // Only continue while the video is still playing while (!shouldQuit() && !videoDecoder.endOfVideo() && videoDecoder.isPlaying()) { // Check for engine quit and video stop key presses while (!videoDecoder.endOfVideo() && videoDecoder.isPlaying() && _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) { videoDecoder.stop(); } break; default: break; } default: break; } } if (videoDecoder.needsUpdate()) { const Graphics::Surface *frame = videoDecoder.decodeNextFrame(); if (frame) { if (scale != 1) { scaleBuffer((const byte *)frame->getPixels(), scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel, scale); _system->copyRectToScreen(scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight); } else { _system->copyRectToScreen((const byte *)frame->getPixels(), pitch, x, y, finalWidth, finalHeight); } } } // Always update the screen so the mouse continues to render _system->updateScreen(); _system->delayMillis(videoDecoder.getTimeToNextFrame()); } _clock.start(); if (scale != 1) { delete[] scaledVideoFrameBuffer; } }
bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { destRect = src1; destRect.extend(src2); return !destRect.isEmpty(); }
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; }
void RenderManager::prepareBackground() { _backgroundDirtyRect.clip(_backgroundWidth, _backgroundHeight); RenderTable::RenderState state = _renderTable.getRenderState(); if (state == RenderTable::PANORAMA) { // Calculate the visible portion of the background Common::Rect viewPort(_workingWidth, _workingHeight); viewPort.translate(-(_screenCenterX - _backgroundOffset), 0); Common::Rect drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); // Render the visible portion if (!drawRect.isEmpty()) { blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - _backgroundOffset + drawRect.left, drawRect.top); } // Mark the dirty portion of the surface _backgroundSurfaceDirtyRect = _backgroundDirtyRect; _backgroundSurfaceDirtyRect.translate(_screenCenterX - _backgroundOffset, 0); // Panorama mode allows the user to spin in circles. Therefore, we need to render // the portion of the image that wrapped to the other side of the screen if (_backgroundOffset < _screenCenterX) { viewPort.moveTo(-(_screenCenterX - (_backgroundOffset + _backgroundWidth)), 0); drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); if (!drawRect.isEmpty()) blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - (_backgroundOffset + _backgroundWidth) + drawRect.left, drawRect.top); Common::Rect tmp = _backgroundDirtyRect; tmp.translate(_screenCenterX - (_backgroundOffset + _backgroundWidth), 0); if (!tmp.isEmpty()) _backgroundSurfaceDirtyRect.extend(tmp); } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) { viewPort.moveTo(-(_screenCenterX + _backgroundWidth - _backgroundOffset), 0); drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); if (!drawRect.isEmpty()) blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX + _backgroundWidth - _backgroundOffset + drawRect.left, drawRect.top); Common::Rect tmp = _backgroundDirtyRect; tmp.translate(_screenCenterX + _backgroundWidth - _backgroundOffset, 0); if (!tmp.isEmpty()) _backgroundSurfaceDirtyRect.extend(tmp); } } else if (state == RenderTable::TILT) { // Tilt doesn't allow wrapping, so we just do a simple clip Common::Rect viewPort(_workingWidth, _workingHeight); viewPort.translate(0, -(_screenCenterY - _backgroundOffset)); Common::Rect drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); if (!drawRect.isEmpty()) blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, drawRect.left, _screenCenterY - _backgroundOffset + drawRect.top); // Mark the dirty portion of the surface _backgroundSurfaceDirtyRect = _backgroundDirtyRect; _backgroundSurfaceDirtyRect.translate(0, _screenCenterY - _backgroundOffset); } else { if (!_backgroundDirtyRect.isEmpty()) blitSurfaceToSurface(_currentBackgroundImage, _backgroundDirtyRect, _backgroundSurface, _backgroundDirtyRect.left, _backgroundDirtyRect.top); _backgroundSurfaceDirtyRect = _backgroundDirtyRect; } // Clear the dirty rect since everything is clean now _backgroundDirtyRect = Common::Rect(); _backgroundSurfaceDirtyRect.clip(_workingWidth, _workingHeight); }