Esempio n. 1
0
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);
		}
	}
}
Esempio n. 2
0
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;
    }
}
Esempio n. 3
0
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;
		}
	}
}
Esempio n. 4
0
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;
				}
			}
		}
	}
}
Esempio n. 5
0
void KernelMessages::processText(int msgIndex) {
	Scene &scene = _vm->_game->_scene;
	KernelMessage &msg = _entries[msgIndex];
	uint32 currentTimer = scene._frameStartTime;
	bool flag = false;

	if ((msg._flags & KMSG_EXPIRE) != 0) {
		scene._textDisplay.expire(msg._textDisplayIndex);
		msg._flags &= ~KMSG_ACTIVE;
		return;
	}

	if ((msg._flags & KMSG_SCROLL) == 0) {
		msg._timeout -= 3;
	}

	if (msg._flags & KMSG_SEQ_ENTRY) {
		SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
		if (seqEntry._doneFlag || !seqEntry._active)
			msg._timeout = 0;
	}

	if (msg._flags & KMSG_ANIM) {
		warning("TODO: Implement animated text");
	}

	if ((msg._timeout <= 0) && (_vm->_game->_trigger == 0)) {
		msg._flags |= KMSG_EXPIRE;
		if (msg._trigger != 0) {
			_vm->_game->_trigger = msg._trigger;
			_vm->_game->_triggerMode = msg._abortMode;

			if (_vm->_game->_triggerMode != SEQUENCE_TRIGGER_DAEMON) {
				scene._action._activeAction = msg._actionDetails;
			}
		}
	}

	msg._frameTimer = currentTimer + 3;
	int x1 = 0, y1 = 0;

	if (msg._flags & KMSG_SEQ_ENTRY) {
		SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
		if (!seqEntry._nonFixed) {
			SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex];
			MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1);
			x1 = frame->getBounds().left;
			y1 = frame->getBounds().top;
		} else {
			x1 = seqEntry._position.x;
			y1 = seqEntry._position.y;
		}
	}

	Player &player = _vm->_game->_player;
	if (msg._flags & KMSG_PLAYER_TIMEOUT) {
		if (player._beenVisible) {
			SpriteAsset &asset = *_vm->_game->_scene._sprites[player._spritesStart + player._spritesIdx];
			MSprite *frame = asset.getFrame(player._frameNumber - 1);

			int yAmount = player._currentScale * player._centerOfGravity / 100;
			x1 = player._playerPos.x;
			y1 = (frame->h * player._currentScale / -100) + yAmount +
				player._playerPos.y - 15;
		} else {
			x1 = 160;
			y1 = 78;
		}
	}

	x1 += msg._position.x;
	y1 += msg._position.y;

	Common::String displayMsg = msg._msg;

	if ((msg._flags & KMSG_SCROLL) && (msg._frameTimer >= currentTimer)) {
		++msg._msgOffset;

		if (msg._msgOffset >= msg._msg.size()) {
			// End of message
			msg._flags &= ~KMSG_SCROLL;
		} else {
			displayMsg = Common::String(msg._msg.c_str(), msg._msg.c_str() + msg._msgOffset);
		}

		msg._frameTimer = msg._frameTimer2 = currentTimer + msg._numTicks;
		flag = true;
	}

	int strWidth = _talkFont->getWidth(displayMsg, scene._textSpacing);

	if (msg._flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) {
		x1 -= (msg._flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth;
	}

	// Make sure text appears entirely on-screen
	int x2 = x1 + strWidth;
	if (x2 > MADS_SCREEN_WIDTH)
		x1 -= x2 - MADS_SCREEN_WIDTH;
	if (x1 > (MADS_SCREEN_WIDTH - 1))
		x1 = MADS_SCREEN_WIDTH - 1;
	if (x1 < 0)
		x1 = 0;

	if (y1 >(MADS_SCENE_HEIGHT - 1))
		y1 = MADS_SCENE_HEIGHT - 1;
	if (y1 < 0)
		y1 = 0;

	if (msg._textDisplayIndex >= 0) {
		TextDisplay &textEntry = scene._textDisplay[msg._textDisplayIndex];

		if (flag || (textEntry._bounds.left != x1) || (textEntry._bounds.top != y1)) {
			// Mark the associated text entry as deleted, so it can be re-created
			scene._textDisplay.expire(msg._textDisplayIndex);
			msg._textDisplayIndex = -1;
		}
	}

	if (msg._textDisplayIndex < 0) {
		// Need to create a new text display entry for this message
		int idx = scene._textDisplay.add(x1, y1, msg._color1 | (msg._color2 << 8),
			scene._textSpacing, displayMsg, _talkFont);
		if (idx >= 0)
			msg._textDisplayIndex = idx;
	}
}