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); }
void Surface::fillRect(Common::Rect r, uint32 color) { r.clip(w, h); if (!r.isValidRect()) return; int width = r.width(); int height = r.height(); // int i; if (bytesPerPixel == 1) { byte *ptr = (byte *)getBasePtr(r.left, r.top); while (height--) { memset(ptr, (byte)color, width); ptr += pitch; } } else if (bytesPerPixel == 2) { uint16 *ptr = (uint16 *)getBasePtr(r.left, r.top); while (height--) { Common::set_to(ptr, ptr + width, (uint16)color); ptr += pitch/2; } } else { error("Surface::fillRect: bytesPerPixel must be 1 or 2"); } }
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); }
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 MicroTileArray::addRect(Common::Rect r) { int ux0, uy0, ux1, uy1; int tx0, ty0, tx1, ty1; int ix0, iy0, ix1, iy1; r.clip(Common::Rect(0, 0, 799, 599)); ux0 = r.left / TileSize; uy0 = r.top / TileSize; ux1 = r.right / TileSize; uy1 = r.bottom / TileSize; tx0 = r.left % TileSize; ty0 = r.top % TileSize; tx1 = r.right % TileSize; ty1 = r.bottom % TileSize; for (int yc = uy0; yc <= uy1; yc++) { for (int xc = ux0; xc <= ux1; xc++) { ix0 = (xc == ux0) ? tx0 : 0; ix1 = (xc == ux1) ? tx1 : TileSize - 1; iy0 = (yc == uy0) ? ty0 : 0; iy1 = (yc == uy1) ? ty1 : TileSize - 1; updateBoundingBox(_tiles[xc + yc * _tilesW], ix0, iy0, ix1, iy1); } } }
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)); } } } }
uint16 RobotDecoder::getFrameSize(Common::Rect &outRect) const { outRect.clip(0, 0); for (RobotScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) { ScreenItem &screenItem = *_screenItemList[i]; outRect.extend(screenItem.getNowSeenRect(*_plane)); } return _numFramesTotal; }
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 RenderManager::clipRectToWorkingWindow(Common::Rect &rect) { if (!_workingWindow.contains(rect)) { return false; } // We can't clip against the actual working window rect because it's in screen space // But rect is in working window space rect.clip(_workingWidth, _workingHeight); return true; }
void CSTimeGraphics::drawRect(Common::Rect rect, byte color) { rect.clip(Common::Rect(640, 480)); // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) return; Graphics::Surface *screen = _vm->_system->lockScreen(); screen->frameRect(rect, color); _vm->_system->unlockScreen(); }
// 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 ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) { if (!ready()) return; Common::Rect charArea = r; charArea.clip(_screen.w, _screen.h); uint32 rgbColor = _overlayFormat.RGBToColor(_textColors[color]->r, _textColors[color]->g, _textColors[color]->b); restoreBackground(charArea); font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor); addDirtyRect(charArea); }
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 ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha) { Common::Rect area = r; area.clip(_screen.w, _screen.h); ThemeItemBitmap *q = new ThemeItemBitmap(this, area, bitmap, alpha); if (_buffering) { _bufferQueue.push_back(q); } else { q->drawSelf(true, false); delete q; } }
// 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); } } }
void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg, bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax) { if (_texts[type] == 0) return; Common::Rect area = r; area.clip(_screen.w, _screen.h); ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, text, alignH, alignV, ellipsis, restoreBg, deltax); if (_buffering) { _screenQueue.push_back(q); } else { q->drawSelf(true, false); delete q; } }
void Surface::fillRect(Common::Rect r, uint32 color) { r.clip(w, h); if (!r.isValidRect()) return; int width = r.width(); int lineLen = width; int height = r.height(); bool useMemset = true; if (format.bytesPerPixel == 2) { lineLen *= 2; if ((uint16)color != ((color & 0xff) | (color & 0xff) << 8)) useMemset = false; } else if (format.bytesPerPixel == 4) { useMemset = false; } else if (format.bytesPerPixel != 1) { error("Surface::fillRect: bytesPerPixel must be 1, 2, or 4"); } if (useMemset) { byte *ptr = (byte *)getBasePtr(r.left, r.top); while (height--) { memset(ptr, (byte)color, lineLen); ptr += pitch; } } else { if (format.bytesPerPixel == 2) { uint16 *ptr = (uint16 *)getBasePtr(r.left, r.top); while (height--) { Common::set_to(ptr, ptr + width, (uint16)color); ptr += pitch / 2; } } else { uint32 *ptr = (uint32 *)getBasePtr(r.left, r.top); while (height--) { Common::set_to(ptr, ptr + width, color); ptr += pitch / 4; } } } }
// 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); }
/** * @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); }
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 GfxFrameout::kernelDeletePlane(reg_t object) { deletePlanePictures(object); for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { if (it->object == object) { _planes.erase(it); Common::Rect planeRect; planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight; planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth; planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight; planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth; planeRect.clip(screenRect); // we need to do this, at least in gk1 on cemetary we get bottom right -> 201, 321 // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; } } }
/********************************************************** * Drawing Queue management *********************************************************/ void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic, bool restore) { if (_widgets[type] == 0) return; Common::Rect area = r; area.clip(_screen.w, _screen.h); ThemeItemDrawData *q = new ThemeItemDrawData(this, _widgets[type], area, dynamic); if (_buffering) { if (_widgets[type]->_buffer) { _bufferQueue.push_back(q); } else { if (kDrawDataDefaults[type].parent != kDDNone && kDrawDataDefaults[type].parent != type) queueDD(kDrawDataDefaults[type].parent, r); _screenQueue.push_back(q); } } else { q->drawSelf(!_widgets[type]->_buffer, restore || _widgets[type]->_buffer); delete q; } }
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 ThemeEngine::restoreBackground(Common::Rect r) { r.clip(_screen.w, _screen.h); _vectorRenderer->blitSurface(&_backBuffer, r); }
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); }
void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const { TransparentSurface src(*getSurface(), false); bool doDelete = false; if (!clipRect) { doDelete = true; clipRect = new Common::Rect(); clipRect->setWidth(getSurface()->w * _transform._numTimesX); clipRect->setHeight(getSurface()->h * _transform._numTimesY); } if (_owner) { if (_transform._alphaDisable) { src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE); } else { src.setAlphaMode(_owner->getAlphaType()); } } if (_transform._numTimesX * _transform._numTimesY == 1) { src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height(), _transform._blendMode); } else { // clipRect is a subrect of the full numTimesX*numTimesY rect Common::Rect subRect; int y = 0; int w = getSurface()->w; int h = getSurface()->h; assert(w == _dstRect.width() / _transform._numTimesX); assert(h == _dstRect.height() / _transform._numTimesY); int basex = dstRect->left - clipRect->left; int basey = dstRect->top - clipRect->top; for (int ry = 0; ry < _transform._numTimesY; ++ry) { int x = 0; for (int rx = 0; rx < _transform._numTimesX; ++rx) { subRect.left = x; subRect.top = y; subRect.setWidth(w); subRect.setHeight(h); if (subRect.intersects(*clipRect)) { subRect.clip(*clipRect); subRect.translate(-x, -y); src.blit(*_targetSurface, basex + x + subRect.left, basey + y + subRect.top, _transform._flip, &subRect, _transform._rgbaMod, subRect.width(), subRect.height(), _transform._blendMode); } x += w; } y += h; } } if (doDelete) { delete clipRect; } }
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; } } }
reg_t GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) { const uint8 skipColor = color != kDefaultSkipColor ? kDefaultSkipColor : 0; // Line thickness is expected to be 2 * thickness + 1 thickness = (MAX<uint8>(1, thickness) - 1) | 1; const uint8 halfThickness = thickness >> 1; const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; outRect.left = MIN<int16>(startPoint.x, endPoint.x); outRect.top = MIN<int16>(startPoint.y, endPoint.y); outRect.right = MAX<int16>(startPoint.x, endPoint.x) + 1 + 1; // rect lower edge + thickness offset outRect.bottom = MAX<int16>(startPoint.y, endPoint.y) + 1 + 1; // rect lower edge + thickness offset outRect.grow(halfThickness); outRect.clip(Common::Rect(scriptWidth, scriptHeight)); reg_t bitmapId; SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, outRect.width(), outRect.height(), skipColor, 0, 0, scriptWidth, scriptHeight, 0, false, true); byte *pixels = bitmap.getPixels(); memset(pixels, skipColor, bitmap.getWidth() * bitmap.getHeight()); LineProperties properties; properties.bitmap = &bitmap; switch (style) { case kLineStyleSolid: pattern = 0xFFFF; properties.solid = true; break; case kLineStyleDashed: pattern = 0xFF00; properties.solid = false; break; case kLineStylePattern: properties.solid = pattern == 0xFFFF; break; } // Change coordinates to be relative to the bitmap const int16 x1 = startPoint.x - outRect.left; const int16 y1 = startPoint.y - outRect.top; const int16 x2 = endPoint.x - outRect.left; const int16 y2 = endPoint.y - outRect.top; if (!properties.solid) { for (int i = 0; i < ARRAYSIZE(properties.pattern); ++i) { properties.pattern[i] = (pattern & 0x8000); pattern <<= 1; } properties.patternIndex = 0; properties.horizontal = ABS(x2 - x1) > ABS(y2 - y1); properties.lastAddress = properties.horizontal ? x1 : y1; } if (thickness <= 1) { Graphics::drawLine(x1, y1, x2, y2, color, plotter, &properties); } else { Graphics::drawThickLine2(x1, y1, x2, y2, thickness, color, plotter, &properties); } return bitmapId; }