void SpriteSlots::drawBackground() { Scene &scene = _vm->_game->_scene; // Initial draw loop for any active sprites in the background for (uint i = 0; i < size(); ++i) { SpriteSlot &spriteSlot = (*this)[i]; DirtyArea &dirtyArea = scene._dirtyAreas[i]; if (spriteSlot._flags >= IMG_STATIC) { // Foreground sprite, so we can ignore it dirtyArea._active = false; } else { dirtyArea._active = true; dirtyArea.setSpriteSlot(&spriteSlot); if (spriteSlot._flags == IMG_DELTA) { // Background object, so need to draw it assert(spriteSlot._frameNumber > 0); SpriteAsset *asset = scene._sprites[spriteSlot._spritesIndex]; MSprite *frame = asset->getFrame(spriteSlot._frameNumber - 1); Common::Point pt = spriteSlot._position; if (spriteSlot._scale != -1) { // Adjust the drawing position pt.x -= frame->w / 2; pt.y -= frame->h - 1; } if (spriteSlot._depth <= 1) { scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex()); } else if (scene._depthStyle == 0) { scene._backgroundSurface.copyFrom(*frame, pt, spriteSlot._depth, &scene._depthSurface, -1, false, frame->getTransparencyIndex()); } else { scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex()); } } } } // Mark any remaning sprite slot dirty areas as inactive for (uint i = size(); i < SPRITE_SLOTS_MAX_SIZE; ++i) scene._dirtyAreas[i]._active = false; // Flag any active text display for (uint i = 0; i < scene._textDisplay.size(); ++i) { TextDisplay &textDisplay = scene._textDisplay[i]; DirtyArea &dirtyArea = scene._dirtyAreas[i + SPRITE_SLOTS_MAX_SIZE]; if (textDisplay._expire >= 0 || !textDisplay._active) { dirtyArea._active = false; } else { dirtyArea._active = true; dirtyArea.setTextDisplay(&textDisplay); } } }
void EventsManager::changeCursor() { if (_cursorSprites) { MSprite *cursor = _cursorSprites->getFrame(_cursorId - 1); assert(cursor->w == cursor->h); byte transIndex = cursor->getTransparencyIndex(); // Check for hotspot indication pixels along the right-hand and bottom // row. Put together, these give the cursor's hotspot x,y int hotspotX = 0, hotspotY = 0; byte *cursorData = cursor->getData(); for (int idx = 0; idx < cursor->w; ++idx) { if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex) hotspotX = idx; if (cursorData[(idx + 1) * cursor->w - 1] != transIndex) hotspotY = idx; } // Reduce the cursor data to remove the last column from each row, since // the cursor routines don't have a pitch option byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)]; byte *srcP = cursorData; byte *destP = destCursor; for (int idx = 0; idx < (cursor->h - 1); ++idx) { Common::copy(srcP, srcP + cursor->w - 1, destP); srcP += cursor->w; destP += cursor->w - 1; } // Set the raw cursor data to use CursorMan.replaceCursor(destCursor, cursor->w - 1, cursor->h - 1, hotspotX, hotspotY, transIndex); showCursor(); delete[] destCursor; } }
void UISlots::draw(bool updateFlag, bool delFlag) { Scene &scene = _vm->_game->_scene; UserInterface &userInterface = scene._userInterface; DirtyArea *dirtyAreaPtr = nullptr; // Loop through setting up the dirty areas for (uint idx = 0; idx < size(); ++idx) { DirtyArea &dirtyArea = userInterface._dirtyAreas[idx]; UISlot &slot = (*this)[idx]; if (slot._flags >= IMG_STATIC) { dirtyArea._active = false; } else { dirtyArea.setUISlot(&slot); dirtyArea._textActive = true; if (slot._segmentId == IMG_SPINNING_OBJECT && slot._flags == IMG_FULL_UPDATE) { dirtyArea._active = false; dirtyAreaPtr = &dirtyArea; } } } userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size()); if (dirtyAreaPtr) dirtyAreaPtr->_active = true; // Copy parts of the user interface background that need to be erased for (uint idx = 0; idx < size(); ++idx) { DirtyArea &dirtyArea = userInterface._dirtyAreas[idx]; UISlot &slot = (*this)[idx]; if (dirtyArea._active && dirtyArea._bounds.width() > 0 && dirtyArea._bounds.height() > 0 && slot._flags > -20) { if (slot._flags >= IMG_ERASE) { // Merge area userInterface.mergeFrom(&userInterface._surface, dirtyArea._bounds, Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top)); } else { // Copy area userInterface._surface.copyTo(&userInterface, dirtyArea._bounds, Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top)); } } } for (uint idx = 0; idx < size(); ++idx) { DirtyArea &dirtyArea = userInterface._dirtyAreas[idx]; UISlot &slot = (*this)[idx]; int slotType = slot._flags; if (slotType >= IMG_STATIC) { dirtyArea.setUISlot(&slot); if (!updateFlag) slotType &= ~0x40; dirtyArea._textActive = slotType > 0; slot._flags &= 0x40; } } userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size()); for (uint idx = 0; idx < size(); ++idx) { DirtyArea *dirtyArea = &userInterface._dirtyAreas[idx]; UISlot &slot = (*this)[idx]; if (slot._flags >= IMG_STATIC && !(slot._flags & 0x40)) { if (!dirtyArea->_active) { do { dirtyArea = dirtyArea->_mergedArea; } while (!dirtyArea->_active); } if (dirtyArea->_textActive) { SpriteAsset *asset = scene._sprites[slot._spritesIndex]; // Get the frame details int frameNumber = ABS(slot._frameNumber); bool flipped = slot._frameNumber < 0; if (slot._segmentId == IMG_SPINNING_OBJECT) { MSprite *sprite = asset->getFrame(frameNumber - 1); sprite->copyTo(&userInterface, slot._position, sprite->getTransparencyIndex()); } else { MSprite *sprite = asset->getFrame(frameNumber - 1); if (flipped) { MSurface *spr = sprite->flipHorizontal(); userInterface.mergeFrom(spr, spr->getBounds(), slot._position, sprite->getTransparencyIndex()); delete spr; } else { userInterface.mergeFrom(sprite, sprite->getBounds(), slot._position, sprite->getTransparencyIndex()); } } } } } // Mark areas of the screen surface for updating if (updateFlag) { for (uint idx = 0; idx < size(); ++idx) { DirtyArea &dirtyArea = userInterface._dirtyAreas[idx]; if (dirtyArea._active && dirtyArea._textActive && dirtyArea._bounds.width() > 0 && dirtyArea._bounds.height() > 0) { // Flag area of screen as needing update Common::Rect r = dirtyArea._bounds; r.translate(0, scene._interfaceY); _vm->_screen.copyRectToScreen(r); } } } // Post-processing to remove slots no longer needed for (int idx = (int)size() - 1; idx >= 0; --idx) { UISlot &slot = (*this)[idx]; if (slot._flags < IMG_STATIC) { if (delFlag || updateFlag) remove_at(idx); else if (slot._flags > -20) slot._flags -= 20; } else { if (updateFlag) slot._flags &= ~0x40; else slot._flags |= 0x40; } } }
void SpriteSlots::drawSprites(MSurface *s) { DepthList depthList; Scene &scene = _vm->_game->_scene; // Get a list of sprite object depths for active objects for (uint i = 0; i < size(); ++i) { SpriteSlot &spriteSlot = (*this)[i]; if (spriteSlot._flags >= IMG_STATIC) { DepthEntry rec(16 - spriteSlot._depth, i); depthList.push_back(rec); } } // Sort the list in order of the depth Common::sort(depthList.begin(), depthList.end(), sortHelper); // Loop through each of the objects DepthList::iterator i; for (i = depthList.begin(); i != depthList.end(); ++i) { DepthEntry &de = *i; SpriteSlot &slot = (*this)[de.index]; assert(slot._spritesIndex < (int)scene._sprites.size()); SpriteAsset &spriteSet = *scene._sprites[slot._spritesIndex]; // Get the sprite frame int frameNumber = ABS(slot._frameNumber); bool flipped = slot._frameNumber < 0; assert(frameNumber > 0); MSprite *sprite = spriteSet.getFrame(frameNumber - 1); if ((slot._scale < 100) && (slot._scale != -1)) { // Scaled drawing s->copyFrom(*sprite, slot._position, slot._depth, &scene._depthSurface, slot._scale, flipped, sprite->getTransparencyIndex()); } else { int xp, yp; if (slot._scale == -1) { xp = slot._position.x - scene._posAdjust.x; yp = slot._position.y - scene._posAdjust.y; } else { xp = slot._position.x - (sprite->w / 2) - scene._posAdjust.x; yp = slot._position.y - sprite->h - scene._posAdjust.y + 1; } if (slot._depth > 1) { // Draw the frame with depth processing s->copyFrom(*sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface, -1, flipped, sprite->getTransparencyIndex()); } else { MSurface *spr = sprite; if (flipped) { // Create a flipped copy of the sprite temporarily spr = sprite->flipHorizontal(); } // No depth, so simply draw the image s->transBlitFrom(*spr, Common::Point(xp, yp), sprite->getTransparencyIndex()); // Free sprite if it was a flipped one if (flipped) { spr->free(); delete spr; } } } } }