void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) { if (_disableDirtyRects) { RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); ticket->_wantsDraw = true; _renderQueue.push_back(ticket); drawFromSurface(ticket); return; } // Skip rects that are completely outside the screen: if ((dstRect->left < 0 && dstRect->right < 0) || (dstRect->top < 0 && dstRect->bottom < 0)) { return; } if (owner) { // Fade-tickets are owner-less RenderTicket compare(owner, nullptr, srcRect, dstRect, transform); RenderQueueIterator it = _lastFrameIter; ++it; // Avoid calling end() and operator* every time, when potentially going through // LOTS of tickets. RenderQueueIterator endIterator = _renderQueue.end(); RenderTicket *compareTicket = nullptr; for (; it != endIterator; ++it) { compareTicket = *it; if (*(compareTicket) == compare && compareTicket->_isValid) { if (_disableDirtyRects) { drawFromSurface(compareTicket); } else { drawFromQueuedTicket(it); } return; } } } RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); if (!_disableDirtyRects) { drawFromTicket(ticket); } else { ticket->_wantsDraw = true; _renderQueue.push_back(ticket); drawFromSurface(ticket); } }
void BaseRenderOSystem::drawTickets() { RenderQueueIterator it = _renderQueue.begin(); // Clean out the old tickets // Note: We draw invalid tickets too, otherwise we wouldn't be honouring // the draw request they obviously made BEFORE becoming invalid, either way // we have a copy of their data, so their invalidness won't affect us. uint32 decrement = 0; while (it != _renderQueue.end()) { if ((*it)->_wantsDraw == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; decrement++; } else { (*it)->_drawNum -= decrement; ++it; } } if (!_dirtyRect || _dirtyRect->width() == 0 || _dirtyRect->height() == 0) { it = _renderQueue.begin(); while (it != _renderQueue.end()) { RenderTicket *ticket = *it; ticket->_wantsDraw = false; ++it; } return; } // The color-mods are stored in the RenderTickets on add, since we set that state again during // draw, we need to keep track of what it was prior to draw. uint32 oldColorMod = _colorMod; // Apply the clear-color to the dirty rect. _renderSurface->fillRect(*_dirtyRect, _clearColor); _drawNum = 1; for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) { RenderTicket *ticket = *it; assert(ticket->_drawNum == _drawNum); ++_drawNum; if (ticket->_dstRect.intersects(*_dirtyRect)) { // dstClip is the area we want redrawn. Common::Rect dstClip(ticket->_dstRect); // reduce it to the dirty rect dstClip.clip(*_dirtyRect); // we need to keep track of the position to redraw the dirty rect Common::Rect pos(dstClip); int16 offsetX = ticket->_dstRect.left; int16 offsetY = ticket->_dstRect.top; // convert from screen-coords to surface-coords. dstClip.translate(-offsetX, -offsetY); _colorMod = ticket->_transform._rgbaMod; drawFromSurface(ticket, &pos, &dstClip); _needsFlip = true; } // Some tickets want redraw but don't actually clip the dirty area (typically the ones that shouldnt become clear-color) ticket->_wantsDraw = false; } g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_dirtyRect->left, _dirtyRect->top), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); // Revert the colorMod-state. _colorMod = oldColorMod; it = _renderQueue.begin(); // Clean out the old tickets decrement = 0; while (it != _renderQueue.end()) { if ((*it)->_isValid == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; decrement++; } else { (*it)->_drawNum -= decrement; ++it; } } }
void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) { if (_tempDisableDirtyRects || _disableDirtyRects) { RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); ticket->_transform._rgbaMod = _colorMod; ticket->_wantsDraw = true; _renderQueue.push_back(ticket); _previousTicket = ticket; drawFromSurface(ticket); return; } // Start searching from the beginning for the first and second items (since it's empty the first time around // then keep incrementing the start-position, to avoid comparing against already used tickets. if (_drawNum == 0 || _drawNum == 1) { _lastAddedTicket = _renderQueue.begin(); } // Skip rects that are completely outside the screen: if ((dstRect->left < 0 && dstRect->right < 0) || (dstRect->top < 0 && dstRect->bottom < 0)) { return; } if (owner) { // Fade-tickets are owner-less RenderTicket compare(owner, nullptr, srcRect, dstRect, transform); compare._batchNum = _batchNum; if (_spriteBatch) { _batchNum++; } RenderQueueIterator it; // Avoid calling end() and operator* every time, when potentially going through // LOTS of tickets. RenderQueueIterator endIterator = _renderQueue.end(); RenderTicket *compareTicket = nullptr; for (it = _lastAddedTicket; it != endIterator; ++it) { compareTicket = *it; if (*(compareTicket) == compare && compareTicket->_isValid) { compareTicket->_transform._rgbaMod = transform._rgbaMod; if (_disableDirtyRects) { drawFromSurface(compareTicket); } else { drawFromTicket(compareTicket); _previousTicket = compareTicket; } if (_renderQueue.size() > DIRTY_RECT_LIMIT) { drawTickets(); _tempDisableDirtyRects = 3; } return; } } } RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); if (!_disableDirtyRects) { drawFromTicket(ticket); _previousTicket = ticket; } else { ticket->_wantsDraw = true; _renderQueue.push_back(ticket); _previousTicket = ticket; drawFromSurface(ticket); } }
void BaseRenderOSystem::drawTickets() { RenderQueueIterator it = _renderQueue.begin(); // Clean out the old tickets // Note: We draw invalid tickets too, otherwise we wouldn't be honoring // the draw request they obviously made BEFORE becoming invalid, either way // we have a copy of their data, so their invalidness won't affect us. while (it != _renderQueue.end()) { if ((*it)->_wantsDraw == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; } else { ++it; } } if (!_dirtyRect || _dirtyRect->width() == 0 || _dirtyRect->height() == 0) { it = _renderQueue.begin(); while (it != _renderQueue.end()) { RenderTicket *ticket = *it; ticket->_wantsDraw = false; ++it; } return; } it = _renderQueue.begin(); _lastFrameIter = _renderQueue.end(); // A special case: If the screen has one giant OPAQUE rect to be drawn, then we skip filling // the background color. Typical use-case: Fullscreen FMVs. // Caveat: The FPS-counter will invalidate this. if (it != _lastFrameIter && _renderQueue.front() == _renderQueue.back() && (*it)->_transform._alphaDisable == true) { // If our single opaque rect fills the dirty rect, we can skip filling. if (*_dirtyRect != (*it)->_dstRect) { // Apply the clear-color to the dirty rect. _renderSurface->fillRect(*_dirtyRect, _clearColor); } // Otherwise Do NOT fill. } else { // Apply the clear-color to the dirty rect. _renderSurface->fillRect(*_dirtyRect, _clearColor); } for (; it != _renderQueue.end(); ++it) { RenderTicket *ticket = *it; if (ticket->_dstRect.intersects(*_dirtyRect)) { // dstClip is the area we want redrawn. Common::Rect dstClip(ticket->_dstRect); // reduce it to the dirty rect dstClip.clip(*_dirtyRect); // we need to keep track of the position to redraw the dirty rect Common::Rect pos(dstClip); int16 offsetX = ticket->_dstRect.left; int16 offsetY = ticket->_dstRect.top; // convert from screen-coords to surface-coords. dstClip.translate(-offsetX, -offsetY); drawFromSurface(ticket, &pos, &dstClip); _needsFlip = true; } // Some tickets want redraw but don't actually clip the dirty area (typically the ones that shouldnt become clear-color) ticket->_wantsDraw = false; } g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_dirtyRect->left, _dirtyRect->top), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); it = _renderQueue.begin(); // Clean out the old tickets while (it != _renderQueue.end()) { if ((*it)->_isValid == false) { RenderTicket *ticket = *it; addDirtyRect((*it)->_dstRect); it = _renderQueue.erase(it); delete ticket; } else { ++it; } } }