reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const { // Most of SCI32 graphics code converts rects from the VM to exclusive // rects before operating on them, but this call leverages SCI16 engine // code that operates on inclusive rects, so the rect's bottom-right // point is not modified like in other SCI32 kernel calls Common::Rect checkRect; // At least LSL6 hires passes invalid rectangles which trigger the // isValidRect assertion in the Rect constructor; this is avoided by // assigning the properties after construction and then testing the // rect for validity ourselves here. SSCI does not care about whether // or not the rects are valid checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); if (!checkRect.isValidRect()) { return make_reg(0, 0); } uint16 result = 0; uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); const uint16 signalFlags = kSignalIgnoreActor | kSignalHidden; if ((signal & signalFlags) == 0) { List *list = _segMan->lookupList(listReference); if (!list) { error("kCantBeHere called with non-list as parameter"); } result = !canBeHereCheckRectList(curObject, checkRect, list, signalFlags).isNull(); } return make_reg(0, result); }
void Scalpel3DOScreen::SHblitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { if (!_vm->_isScreenDoubled) { ScalpelScreen::SHblitFrom(src, pt, srcBounds); return; } Common::Rect srcRect = srcBounds; Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height()); if (!srcRect.isValidRect() || !clip(srcRect, destRect)) return; // Add dirty area remapped to the 640x200 surface addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2)); // Transfer the area, doubling each pixel for (int yp = 0; yp < srcRect.height(); ++yp) { const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp); uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2); for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) { *destP = *srcP; *(destP + 1) = *srcP; *(destP + 640) = *srcP; *(destP + 640 + 1) = *srcP; } } }
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 Screen::slamRect(const Common::Rect &r) { if (r.width() && r.height() > 0) { Common::Rect srcRect = r, destRect = r; destRect.translate(-_currentScroll.x, -_currentScroll.y); if (destRect.left < 0) { srcRect.left += -destRect.left; destRect.left = 0; } if (destRect.top < 0) { srcRect.top += -destRect.top; destRect.top = 0; } if (destRect.right > SHERLOCK_SCREEN_WIDTH) { srcRect.right -= (destRect.left - SHERLOCK_SCREEN_WIDTH); destRect.right = SHERLOCK_SCREEN_WIDTH; } if (destRect.bottom > SHERLOCK_SCREEN_HEIGHT) { srcRect.bottom -= (destRect.bottom - SHERLOCK_SCREEN_HEIGHT); destRect.bottom = SHERLOCK_SCREEN_HEIGHT; } if (srcRect.isValidRect()) SHblitFrom(_backBuffer, Common::Point(destRect.left, destRect.top), srcRect); } }
reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) { Common::Rect checkRect; uint16 result; checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft)); checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop)); checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight)); checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom)); uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal)); if (!checkRect.isValidRect()) { // can occur in Iceman and Mother Goose - HACK? TODO: is this really occuring in sierra sci? check this warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom); return NULL_REG; // this means "can be here" } Common::Rect adjustedRect = _coordAdjuster->onControl(checkRect); uint16 controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits)); result = isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask; if ((!result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) { List *list = _segMan->lookupList(listReference); if (!list) error("kCanBeHere called with non-list as parameter"); return canBeHereCheckRectList(curObject, checkRect, list, kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate); } return make_reg(0, result); }
/** * Check if the two rectangles are next to each other. * @param pSrc1 a source rectangle * @param pSrc2 a source rectangle */ static bool LooseIntersectRectangle(const Common::Rect &pSrc1, const Common::Rect &pSrc2) { Common::Rect pDest; pDest.left = MAX(pSrc1.left, pSrc2.left); pDest.top = MAX(pSrc1.top, pSrc2.top); pDest.right = MIN(pSrc1.right, pSrc2.right); pDest.bottom = MIN(pSrc1.bottom, pSrc2.bottom); return pDest.isValidRect(); }
void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) { Common::Rect srcRect = srcBounds; Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height()); if (srcRect.isValidRect() && clip(srcRect, destRect)) { // Surface is at least partially or completely on-screen addDirtyRect(destRect); _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect); } }
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(); }
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 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; }
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; } } } }
void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos, int transparencyIndex) { // Validation of the rectangle and position int destX = destPos.x, destY = destPos.y; if ((destX >= w) || (destY >= h)) return; Common::Rect copyRect = srcBounds; if (destX < 0) { copyRect.left += -destX; destX = 0; } else if (destX + copyRect.width() > w) { copyRect.right -= destX + copyRect.width() - w; } if (destY < 0) { copyRect.top += -destY; destY = 0; } else if (destY + copyRect.height() > h) { copyRect.bottom -= destY + copyRect.height() - h; } if (!copyRect.isValidRect()) return; // Copy the specified area byte *data = src->getData(); byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left); byte *destPtr = (byte *)this->pixels + (destY * getWidth()) + destX; for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { // Process each line of the area for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) { // Check for the range used for the user interface background, // which are the only pixels that can be replaced if ((destPtr[xCtr] >= 8 && destPtr[xCtr] <= 15) && (int)srcPtr[xCtr] != transparencyIndex) destPtr[xCtr] = srcPtr[xCtr]; } srcPtr += src->getWidth(); destPtr += getWidth(); } }
/** * Copies a section of the game frame in a circle bounded by the specified rectangle */ void RMWindow::getNewFrameWipe(byte *lpBuf, Common::Rect &rcBoundEllipse) { // Clear the screen g_system->fillScreen(0); if (!rcBoundEllipse.isValidRect()) return; Common::Point center(rcBoundEllipse.left + rcBoundEllipse.width() / 2, rcBoundEllipse.top + rcBoundEllipse.height() / 2); // The rectangle technically defines the area inside the ellipse, with the corners touching // the ellipse boundary. Since we're currently simulating the ellipse using a plain circle, // we need to calculate a necessary width using the hypotenuse of X/2 & Y/2 int x2y2 = (rcBoundEllipse.width() / 2) * (rcBoundEllipse.width() / 2) + (rcBoundEllipse.height() / 2) * (rcBoundEllipse.height() / 2); int radius = 0; while ((radius * radius) < x2y2) ++radius; // Proceed copying a circular area of the frame with the calculated radius onto the screen int error = -radius; int x = radius; int y = 0; while (x >= y) { plotSplices(lpBuf, center, x, y); error += y; ++y; error += y; if (error >= 0) { error -= x; --x; error -= x; } } }
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 Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { if (scale == 100) { // use optimized path bltMaskNoScale(r, data, surf, z, transparentColor); return; } // unscaled rectangle size uint width = r.width(); uint height = r.height(); // scaled rectangle size uint scaledWidth = r.width() * scale / 100; uint scaledHeight = r.height() * scale / 100; // scaled rectangle origin uint scaledLeft = r.left + (width - scaledWidth) / 2; uint scaledTop = r.top + (height - scaledHeight); // clipped scaled destination rectangle Common::Rect dstRect(scaledWidth, scaledHeight); dstRect.moveTo(scaledLeft, scaledTop); Common::Rect clipper(surf->w, surf->h); dstRect.clip(clipper); if (!dstRect.isValidRect()) return; // clipped source rectangle Common::Rect srcRect; srcRect.left = (dstRect.left - scaledLeft) * 100 / scale; srcRect.top = (dstRect.top - scaledTop) * 100 / scale; srcRect.setWidth(dstRect.width() * 100 / scale); srcRect.setHeight(dstRect.height() * 100 / scale); if (!srcRect.isValidRect()) return; Common::Point dp; dp.x = dstRect.left; dp.y = dstRect.top; byte *s = data + srcRect.left + srcRect.top * width; byte *d = (byte *)surf->getBasePtr(dp.x, dp.y); uint line = 0, col = 0; uint xAccum = 0, yAccum = 0; uint inc = width * (100 - scale); uint thr = width * 100; for (uint16 i = 0; i < srcRect.height(); i++) { yAccum += inc; if (yAccum >= thr) { yAccum -= thr; s += width; continue; } xAccum = 0; byte *d2 = d; col = 0; for (uint16 j = 0; j < srcRect.width(); j++) { xAccum += inc; if (xAccum >= thr) { xAccum -= thr; s++; continue; } if (*s != transparentColor) { if (_backgroundInfo->hasMask()) { byte v = _backgroundInfo->_mask->getValue(dp.x + col, dp.y + line); if (z >= v) *d2 = *s; } else { *d2 = *s; } } s++; d2++; col++; } s += width - srcRect.width(); d += surf->w; line++; } }
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; }
bool RenderObject::getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result) { result = pObject->getBbox(); result.clip(_bbox); return result.isValidRect(); }