STARK: Implement the exploding image animation
Used when getting an inventory item
This commit is contained in:
parent
1f9df9edb8
commit
375c89fd54
12 changed files with 338 additions and 20 deletions
|
@ -98,6 +98,7 @@ MODULE_OBJS := \
|
|||
ui/world/gamewindow.o \
|
||||
ui/world/inventorywindow.o \
|
||||
visual/actor.o \
|
||||
visual/explodingimage.o \
|
||||
visual/image.o \
|
||||
visual/prop.o \
|
||||
visual/smacker.o \
|
||||
|
|
|
@ -40,7 +40,7 @@ KnowledgeSet::KnowledgeSet(Object *parent, byte subType, uint16 index, const Com
|
|||
void KnowledgeSet::printData() {
|
||||
}
|
||||
|
||||
Gfx::RenderEntryArray KnowledgeSet::getInventoryRenderEntries() {
|
||||
Gfx::RenderEntryArray KnowledgeSet::getInventoryRenderEntries() const {
|
||||
Common::Array<Resources::Item *> inventoryItems = listChildren<Resources::Item>(Resources::Item::kItemInventory);
|
||||
|
||||
// First add the inventory items from old saves which don't have an order
|
||||
|
@ -97,5 +97,12 @@ void KnowledgeSet::saveLoad(ResourceSerializer *serializer) {
|
|||
}
|
||||
}
|
||||
|
||||
Visual *KnowledgeSet::getInventoryItemVisual(uint16 itemIndex) {
|
||||
InventoryItem *item = findChildWithIndex<InventoryItem>(itemIndex, Item::kItemInventory);
|
||||
assert(item);
|
||||
|
||||
return item->getCursorVisual();
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -66,7 +66,10 @@ public:
|
|||
void removeItem(InventoryItem *item);
|
||||
|
||||
/** Get the render entries for the inventory items, in the order they were obtained */
|
||||
Gfx::RenderEntryArray getInventoryRenderEntries();
|
||||
Gfx::RenderEntryArray getInventoryRenderEntries() const;
|
||||
|
||||
/** Get a cursor style visual for an inventory item */
|
||||
Visual *getInventoryItemVisual(uint16 itemIndex);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <engines/stark/resources/animscript.h>
|
||||
#include "engines/stark/services/staticprovider.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/animscript.h"
|
||||
#include "engines/stark/resources/container.h"
|
||||
#include "engines/stark/resources/image.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
|
||||
#include "engines/stark/visual/explodingimage.h"
|
||||
#include "engines/stark/visual/image.h"
|
||||
#include "engines/stark/visual/text.h"
|
||||
|
||||
|
@ -38,27 +39,34 @@ Button::Button(const Common::String &text, StaticProvider::UIElement stockElemen
|
|||
_hintPosition(hintPos),
|
||||
_align(align),
|
||||
_mouseText(nullptr),
|
||||
_renderHint(false) {
|
||||
_renderHint(false),
|
||||
_explodingImageAnimation(nullptr) {
|
||||
}
|
||||
|
||||
Button::~Button() {
|
||||
delete _explodingImageAnimation;
|
||||
delete _mouseText;
|
||||
}
|
||||
|
||||
void Button::render() {
|
||||
VisualImageXMG *image = StarkStaticProvider->getUIElement(_stockElement);
|
||||
image->render(_position, false);
|
||||
|
||||
if (_explodingImageAnimation) {
|
||||
_explodingImageAnimation->render(_position);
|
||||
}
|
||||
|
||||
if (_renderHint) {
|
||||
Common::Point pos(_hintPosition);
|
||||
if (_align == kAlignRight) {
|
||||
pos.x -= _mouseText->getRect().width();
|
||||
}
|
||||
_mouseText->render(pos);
|
||||
_renderHint = false;
|
||||
}
|
||||
_renderHint = false;
|
||||
}
|
||||
|
||||
bool Button::containsPoint(Common::Point point) {
|
||||
bool Button::containsPoint(const Common::Point &point) {
|
||||
VisualImageXMG *image = StarkStaticProvider->getUIElement(_stockElement);
|
||||
|
||||
Common::Rect r;
|
||||
|
@ -89,4 +97,17 @@ void Button::goToAnimStatement(int animScriptItemIndex) {
|
|||
StarkStaticProvider->goToAnimScriptStatement(_stockElement, animScriptItemIndex);
|
||||
}
|
||||
|
||||
void Button::startImageExplosion(VisualImageXMG *image) {
|
||||
assert(image);
|
||||
|
||||
stopImageExplosion();
|
||||
_explodingImageAnimation = new VisualExplodingImage(StarkGfx);
|
||||
_explodingImageAnimation->initFromSurface(image->getSurface());
|
||||
}
|
||||
|
||||
void Button::stopImageExplosion() {
|
||||
delete _explodingImageAnimation;
|
||||
_explodingImageAnimation = nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
namespace Stark {
|
||||
|
||||
class VisualExplodingImage;
|
||||
class VisualImageXMG;
|
||||
class VisualText;
|
||||
|
||||
|
@ -49,7 +50,7 @@ public:
|
|||
/** Set hint to render for one frame */
|
||||
void showButtonHint();
|
||||
void render();
|
||||
bool containsPoint(Common::Point point);
|
||||
bool containsPoint(const Common::Point &point);
|
||||
|
||||
/** Reset the hint text visual so it is rebuilt with the appropriate texture size */
|
||||
void resetHintVisual();
|
||||
|
@ -57,12 +58,19 @@ public:
|
|||
/** Move execution of the button's icon anim script to the specified item */
|
||||
void goToAnimStatement(int animScriptItemIndex);
|
||||
|
||||
/** Start overlaying an explosion animation of an image on top of the button */
|
||||
void startImageExplosion(VisualImageXMG *image);
|
||||
|
||||
/** Remove the currently playing exploding image animation, if any */
|
||||
void stopImageExplosion();
|
||||
|
||||
private:
|
||||
StaticProvider::UIElement _stockElement;
|
||||
Common::Point _position;
|
||||
Common::Point _hintPosition;
|
||||
Common::String _text;
|
||||
VisualText *_mouseText;
|
||||
VisualExplodingImage *_explodingImageAnimation;
|
||||
const HintAlign _align;
|
||||
bool _renderHint;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
|
||||
#include "engines/stark/resources/knowledgeset.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
|
@ -69,6 +70,7 @@ void TopMenu::onRender() {
|
|||
_forceVisibleTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
|
||||
if (_forceVisibleTimeRemaining <= 0) {
|
||||
_inventoryButton->stopImageExplosion();
|
||||
_inventoryButton->goToAnimStatement(12);
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +136,9 @@ void TopMenu::onScreenChanged() {
|
|||
void TopMenu::notifyInventoryItemEnabled(uint16 itemIndex) {
|
||||
_forceVisibleTimeRemaining = 128 * 33; // 128 frames at 30 fps
|
||||
_inventoryButton->goToAnimStatement(2);
|
||||
|
||||
Visual *inventoryItemImage = StarkGlobal->getInventory()->getInventoryItemVisual(itemIndex);
|
||||
_inventoryButton->startImageExplosion(inventoryItemImage->get<VisualImageXMG>());
|
||||
_inventoryNewItemSound->stop();
|
||||
_inventoryNewItemSound->play();
|
||||
}
|
||||
|
|
172
engines/stark/visual/explodingimage.cpp
Normal file
172
engines/stark/visual/explodingimage.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/visual/explodingimage.h"
|
||||
|
||||
#include "common/random.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/gfx/surfacerenderer.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
VisualExplodingImage::VisualExplodingImage(Gfx::Driver *gfx) :
|
||||
Visual(TYPE),
|
||||
_gfx(gfx),
|
||||
_texture(nullptr),
|
||||
_surface(nullptr) {
|
||||
_surfaceRenderer = _gfx->createSurfaceRenderer();
|
||||
}
|
||||
|
||||
VisualExplodingImage::~VisualExplodingImage() {
|
||||
if (_surface) {
|
||||
_surface->free();
|
||||
}
|
||||
delete _surface;
|
||||
delete _texture;
|
||||
delete _surfaceRenderer;
|
||||
}
|
||||
|
||||
void VisualExplodingImage::initFromSurface(const Graphics::Surface *surface) {
|
||||
assert(!_surface && !_texture);
|
||||
|
||||
// Decode the XMG
|
||||
_surface = new Graphics::Surface();
|
||||
_surface->copyFrom(*surface);
|
||||
_texture = _gfx->createTexture(_surface);
|
||||
|
||||
// Create an explosion unit for each pixel in the surface
|
||||
_units.resize(_surface->w * _surface->h);
|
||||
|
||||
Common::Point explosionCenter(_surface->w / 2, _surface->h / 2);
|
||||
Common::Point explosionAmplitude(48, 16);
|
||||
|
||||
uint index = 0;
|
||||
for (uint y = 0; y < _surface->h; y++) {
|
||||
for (uint x = 0; x < _surface->w; x++, index++) {
|
||||
_units[index].setPosition(x, y);
|
||||
_units[index].setExplosionSettings(explosionCenter, explosionAmplitude);
|
||||
_units[index].setColor(*static_cast<uint32 *>(_surface->getBasePtr(x, y)), _surface->format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisualExplodingImage::render(const Common::Point &position) {
|
||||
// Fill with transparent color
|
||||
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
|
||||
|
||||
for (uint i = 0; i < _units.size(); i++) {
|
||||
_units[i].update();
|
||||
_units[i].draw(_surface);
|
||||
}
|
||||
|
||||
_texture->update(_surface);
|
||||
_surfaceRenderer->render(_texture, position);
|
||||
}
|
||||
|
||||
VisualExplodingImage::ExplosionUnit::ExplosionUnit() :
|
||||
_stillImageTimeRemaining(33 * 33),
|
||||
_explosionFastAccelerationTimeRemaining(25 * 33) {
|
||||
|
||||
}
|
||||
|
||||
void VisualExplodingImage::ExplosionUnit::setPosition(int x, int y) {
|
||||
_position = Math::Vector2d(x, y);
|
||||
}
|
||||
|
||||
void VisualExplodingImage::ExplosionUnit::setExplosionSettings(const Common::Point ¢er, const Common::Point &litude) {
|
||||
_center = Math::Vector2d(center.x, center.y);
|
||||
|
||||
_speed.setX(cos(StarkRandomSource->getRandomNumber(M_PI * 100)) * (float)amplitude.x);
|
||||
_speed.setY(sin(StarkRandomSource->getRandomNumber(M_PI * 100)) * (float)amplitude.y);
|
||||
|
||||
// WTF, ensuring all fragments go in the same direction?
|
||||
float magnitude = _position.getDistanceTo(_speed);
|
||||
_speed -= _position;
|
||||
_speed = _speed / _speed.getMagnitude() * -magnitude;
|
||||
}
|
||||
|
||||
void VisualExplodingImage::ExplosionUnit::setColor(uint32 color, const Graphics::PixelFormat &format) {
|
||||
_mainColor = color;
|
||||
|
||||
byte a, r, g, b;
|
||||
format.colorToARGB(color, a, r, g, b);
|
||||
r >>= 1;
|
||||
g >>= 1;
|
||||
b >>= 1;
|
||||
|
||||
_darkColor = format.ARGBToColor(a, r, g, b);
|
||||
}
|
||||
|
||||
void VisualExplodingImage::ExplosionUnit::update() {
|
||||
if (_stillImageTimeRemaining > 0) {
|
||||
_stillImageTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_position.getDistanceTo(_center) <= 1.f) {
|
||||
// Units near the center stay there (to make it look like they enter the chest)
|
||||
return;
|
||||
}
|
||||
|
||||
Math::Vector2d speed = _speed.getNormalized() * 0.6f;
|
||||
_position += speed;
|
||||
|
||||
// Update the acceleration to units move towards the center
|
||||
Math::Vector2d acceleration = _center - _position;
|
||||
if (_explosionFastAccelerationTimeRemaining > 0) {
|
||||
acceleration *= 3.0f;
|
||||
_explosionFastAccelerationTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
}
|
||||
|
||||
_speed += acceleration;
|
||||
_speed -= speed * 2.5f;
|
||||
}
|
||||
|
||||
void VisualExplodingImage::ExplosionUnit::draw(Graphics::Surface *surface) {
|
||||
if (_position.getX() <= 1.f || _position.getX() >= surface->w - 1
|
||||
|| _position.getY() <= 1.f || _position.getY() >= surface->h - 1) {
|
||||
return; // Ignore units outside of the surface
|
||||
}
|
||||
|
||||
if (_stillImageTimeRemaining <= 0 && _position.getDistanceTo(_center) <= 2.f) {
|
||||
return; // Ignore units close to the center (to make it look like they enter the chest)
|
||||
}
|
||||
|
||||
uint32 *pixel = static_cast<uint32 *>(surface->getBasePtr(_position.getX(), _position.getY() - 1));
|
||||
*pixel = _darkColor;
|
||||
|
||||
pixel = static_cast<uint32 *>(surface->getBasePtr(_position.getX() - 1, _position.getY()));
|
||||
*pixel++ = _darkColor;
|
||||
*pixel++ = _mainColor;
|
||||
*pixel = _darkColor;
|
||||
|
||||
pixel = static_cast<uint32 *>(surface->getBasePtr(_position.getX(), _position.getY() + 1));
|
||||
*pixel = _darkColor;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
95
engines/stark/visual/explodingimage.h
Normal file
95
engines/stark/visual/explodingimage.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_VISUAL_EXPLODING_IMAGE_H
|
||||
#define STARK_VISUAL_EXPLODING_IMAGE_H
|
||||
|
||||
#include "engines/stark/visual/visual.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
#include "math/vector2d.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Gfx {
|
||||
class Driver;
|
||||
class SurfaceRenderer;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* An image with an animated explosion effect
|
||||
*
|
||||
* Used by the top bar when picking up an inventory item
|
||||
*/
|
||||
class VisualExplodingImage : public Visual {
|
||||
public:
|
||||
static const VisualType TYPE = Visual::kExplodingImage;
|
||||
|
||||
explicit VisualExplodingImage(Gfx::Driver *gfx);
|
||||
~VisualExplodingImage() override;
|
||||
|
||||
/** Prepare exploding the specified image */
|
||||
void initFromSurface(const Graphics::Surface *surface);
|
||||
|
||||
/** Render the image at the specified position */
|
||||
void render(const Common::Point &position);
|
||||
|
||||
private:
|
||||
struct ExplosionUnit {
|
||||
ExplosionUnit();
|
||||
|
||||
void setPosition(int x, int y);
|
||||
void setExplosionSettings(const Common::Point ¢er, const Common::Point &litude);
|
||||
void setColor(uint32 color, const Graphics::PixelFormat &format);
|
||||
void update();
|
||||
void draw(Graphics::Surface *surface);
|
||||
|
||||
Math::Vector2d _position;
|
||||
Math::Vector2d _speed;
|
||||
Math::Vector2d _center;
|
||||
|
||||
int _stillImageTimeRemaining;
|
||||
int _explosionFastAccelerationTimeRemaining;
|
||||
uint32 _mainColor;
|
||||
uint32 _darkColor;
|
||||
};
|
||||
|
||||
Gfx::Driver *_gfx;
|
||||
Gfx::SurfaceRenderer *_surfaceRenderer;
|
||||
Gfx::Texture *_texture;
|
||||
Graphics::Surface *_surface;
|
||||
|
||||
Common::Array<ExplosionUnit> _units;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_VISUAL_EXPLODING_IMAGE_H
|
|
@ -24,13 +24,10 @@
|
|||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/xmg.h"
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/gfx/surfacerenderer.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
#include "engines/stark/scene.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
|
@ -94,4 +91,9 @@ int VisualImageXMG::getHeight() const {
|
|||
return _surface->h;
|
||||
}
|
||||
|
||||
const Graphics::Surface *VisualImageXMG::getSurface() const {
|
||||
assert(_surface);
|
||||
return _surface;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -73,6 +73,9 @@ public:
|
|||
/** Get the height in pixels */
|
||||
int getHeight() const;
|
||||
|
||||
/** Get a read only pointer to the surface backing the image */
|
||||
const Graphics::Surface *getSurface() const;
|
||||
|
||||
private:
|
||||
Gfx::Driver *_gfx;
|
||||
Gfx::SurfaceRenderer *_surfaceRenderer;
|
||||
|
|
|
@ -30,16 +30,17 @@ namespace Stark {
|
|||
class Visual {
|
||||
public:
|
||||
enum VisualType {
|
||||
kImageXMG = 2,
|
||||
kRendered = 3,
|
||||
kImageText = 4,
|
||||
kSmackerStream = 5,
|
||||
kActor = 6,
|
||||
kSmackerFMV = 7,
|
||||
kEffectFish = 8,
|
||||
kEffectBubbles = 9,
|
||||
kEffectFirefly = 10,
|
||||
kEffectSmoke = 11
|
||||
kImageXMG = 2,
|
||||
kRendered = 3,
|
||||
kImageText = 4,
|
||||
kSmackerStream = 5,
|
||||
kActor = 6,
|
||||
kSmackerFMV = 7,
|
||||
kEffectFish = 8,
|
||||
kEffectBubbles = 9,
|
||||
kEffectFirefly = 10,
|
||||
kEffectSmoke = 11,
|
||||
kExplodingImage = 100,
|
||||
};
|
||||
|
||||
explicit Visual(VisualType type) : _type(type) {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue