PINK: reworked sprite class(ActionCEL) and his inheritors.

This commit is contained in:
whiterandrek 2018-06-11 23:29:46 +03:00 committed by Eugene Sandulenko
parent 3ca2c13893
commit 2fb268b155
19 changed files with 217 additions and 165 deletions

View File

@ -53,20 +53,6 @@ bool CelDecoder::loadStream(Common::SeekableReadStream *stream) {
return true;
}
int32 CelDecoder::getX(){
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
if (!track)
return -1;
return track->getX();
}
int32 CelDecoder::getY() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
if (!track)
return -1;
return track->getY();
}
uint16 CelDecoder::getTransparentColourIndex() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
@ -89,21 +75,6 @@ Common::Point CelDecoder::getCenter() {
return track->getCenter();
}
Common::Rect &CelDecoder::getRectangle() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
return track->getRect();
}
void CelDecoder::setX(int32 x) {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
track->setX(x);
}
void CelDecoder::setY(int32 y) {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
track->setY(y);
}
void CelDecoder::skipFrame() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
track->skipFrame();
@ -139,7 +110,6 @@ void CelDecoder::CelVideoTrack::readPrefixChunk() {
_fileStream->skip(subchunkSize - 6);
break;
}
_rect = Common::Rect::center(_center.x, _center.y, _surface->w, _surface->h);
}
void CelDecoder::CelVideoTrack::readHeader() {
@ -157,14 +127,6 @@ void CelDecoder::CelVideoTrack::readHeader() {
_fileStream->seek(_offsetFrame1);
}
int32 CelDecoder::CelVideoTrack::getX() const {
return (_center.x - getWidth() / 2) < 0 ? 0 : _center.x - getWidth() / 2;
}
int32 CelDecoder::CelVideoTrack::getY() const {
return (_center.y - getHeight() / 2) < 0 ? 0 : _center.y - getHeight() / 2;
}
uint16 CelDecoder::CelVideoTrack::getTransparentColourIndex() {
return _transparentColourIndex;
}
@ -177,10 +139,6 @@ Common::Point CelDecoder::CelVideoTrack::getCenter() {
return _center;
}
Common::Rect &CelDecoder::CelVideoTrack::getRect() {
return _rect;
}
#define FRAME_TYPE 0xF1FA
void CelDecoder::CelVideoTrack::skipFrame() {
@ -240,12 +198,20 @@ const Graphics::Surface *CelDecoder::CelVideoTrack::decodeNextFrame() {
return _surface;
}
void CelDecoder::CelVideoTrack::setX(int32 x) {
_center.x = x ;//+ getWidth() / 2;
}
bool CelDecoder::CelVideoTrack::rewind() {
// this method is overriden for 2 reasons:
// 1) bug in Flic rewind(curFrame)
// 2) I changed behaviour of endOfTrack
_nextFrameStartTime = 0;
void CelDecoder::CelVideoTrack::setY(int32 y) {
_center.y = y;//+ getHeight() / 2;
if (getCurFrame() >= getFrameCount() - 1 && _fileStream->pos() < _fileStream->size())
_atRingFrame = true;
else
_fileStream->seek(_offsetFrame1);
_curFrame = -1;
_frameDelay = _startFrameDelay;
return true;
}
} // End of namepsace Pink

View File

@ -31,18 +31,12 @@ class CelDecoder : public Video::FlicDecoder {
public:
virtual bool loadStream(Common::SeekableReadStream *stream);
int32 getX();
int32 getY();
uint16 getTransparentColourIndex();
Common::Point getCenter();
Common::Rect &getRectangle();
const Graphics::Surface *getCurrentFrame();
void skipFrame();
void setX(int32 x);
void setY(int32 y);
protected:
class CelVideoTrack : public FlicVideoTrack {
public:
@ -53,20 +47,24 @@ protected:
int32 getY() const;
uint16 getTransparentColourIndex();
// Hack. Pink needs so that Track needed an update after lastFrame delay ends
bool endOfTrack() const override { return getCurFrame() >= getFrameCount(); }
Common::Point getCenter();
Common::Rect &getRect();
const Graphics::Surface *getCurrentFrame();
void setX(int32 x);
void setY(int32 y);
void skipFrame();
bool rewind() override;
private:
const Graphics::Surface *decodeNextFrame();
void readPrefixChunk();
Common::Point _center;
Common::Rect _rect;
byte _transparentColourIndex;
};
};

View File

@ -42,7 +42,8 @@ void Director::update() {
_sounds[i]->update();
}
for (uint i = 0; i < _sprites.size(); ++i) {
_sprites[i]->update();
if (_sprites[i]->needsUpdate())
_sprites[i]->update();
}
draw();
@ -67,7 +68,6 @@ void Director::addSprite(ActionCEL *sprite) {
break;
}
_sprites[i] = sprite;
_dirtyRects.push_back(sprite->getDecoder()->getRectangle());
}
void Director::removeSprite(ActionCEL *sprite) {
@ -77,7 +77,7 @@ void Director::removeSprite(ActionCEL *sprite) {
break;
}
}
_dirtyRects.push_back(sprite->getDecoder()->getRectangle());
_dirtyRects.push_back(sprite->getBounds());
}
void Director::removeSound(ActionSound *sound) {
@ -113,7 +113,7 @@ Actor *Director::getActorByPoint(const Common::Point point) {
for (int i = _sprites.size() - 1; i >= 0; --i) {
CelDecoder *decoder = _sprites[i]->getDecoder();
const Graphics::Surface *frame = decoder->getCurrentFrame();
const Common::Rect &rect = decoder->getRectangle();
const Common::Rect &rect = _sprites[i]->getBounds();
if (rect.contains(point)) {
byte spritePixel = *(const byte*) frame->getBasePtr(point.x - rect.left, point.y - rect.top);
if (spritePixel != decoder->getTransparentColourIndex())
@ -125,13 +125,6 @@ Actor *Director::getActorByPoint(const Common::Point point) {
}
void Director::draw() {
for (uint i = 0; i < _sprites.size(); ++i) {
if (_sprites[i]->getDecoder()->needsUpdate()) {
_sprites[i]->getDecoder()->decodeNextFrame();
addDirtyRects(_sprites[i]);
}
}
if (!_dirtyRects.empty()) {
mergeDirtyRects();
@ -165,8 +158,12 @@ void Director::mergeDirtyRects() {
}
}
void Director::addDirtyRect(const Common::Rect &rect) {
_dirtyRects.push_back(rect);
}
void Director::addDirtyRects(ActionCEL *sprite) {
const Common::Rect spriteRect = sprite->getDecoder()->getRectangle();
const Common::Rect spriteRect = sprite->getBounds();
const Common::List<Common::Rect> *dirtyRects = sprite->getDecoder()->getDirtyRects();
if (dirtyRects->size() > 100) {
_dirtyRects.push_back(spriteRect);
@ -183,7 +180,7 @@ void Director::addDirtyRects(ActionCEL *sprite) {
void Director::drawRect(const Common::Rect &rect) {
_surface.fillRect(rect, 0);
for (uint i = 0; i < _sprites.size(); ++i) {
const Common::Rect &spriteRect = _sprites[i]->getDecoder()->getRectangle();
const Common::Rect &spriteRect = _sprites[i]->getBounds();
Common::Rect interRect = rect.findIntersectingRect(spriteRect);
if (interRect.isEmpty())
continue;

View File

@ -47,6 +47,9 @@ public:
void addSprite(ActionCEL *sprite);
void removeSprite(ActionCEL *sprite);
void addDirtyRect(const Common::Rect &rect);
void addDirtyRects(ActionCEL *sprite);
void addSound(ActionSound* sound) { _sounds.push_back(sound); };
void removeSound(ActionSound* sound);
@ -66,7 +69,6 @@ public:
private:
void draw();
void addDirtyRects(ActionCEL *sprite);
void mergeDirtyRects();
void drawRect(const Common::Rect &rect);

View File

@ -21,6 +21,7 @@
*/
#include "common/debug.h"
#include "common/substream.h"
#include "pink/archive.h"
#include "pink/cel_decoder.h"
@ -31,9 +32,6 @@
namespace Pink {
ActionCEL::ActionCEL()
: _decoder(nullptr) {}
ActionCEL::~ActionCEL() {
end();
}
@ -45,53 +43,79 @@ void ActionCEL::deserialize(Archive &archive) {
}
bool ActionCEL::initPalette(Director *director) {
if (!_decoder)
_decoder = _actor->getPage()->loadCel(_fileName);
if (_decoder->getCurFrame() == -1) {
_decoder->decodeNextFrame();
_decoder->rewind();
loadDecoder();
if (_decoder.getCurFrame() == -1) {
_decoder.decodeNextFrame();
_decoder.rewind();
}
debug("%u", _decoder->isPaused());
director->setPallette(_decoder->getPalette());
director->setPallette(_decoder.getPalette());
return true;
}
void ActionCEL::start() {
if (!_decoder)
_decoder = _actor->getPage()->loadCel(_fileName);
loadDecoder();
Common::Point point = _decoder.getCenter();
_bounds = Common::Rect::center(point.x, point.y, _decoder.getWidth(), _decoder.getHeight());
_decoder.start();
this->onStart();
_actor->getPage()->getGame()->getDirector()->addSprite(this);
}
void ActionCEL::end() {
if (!_decoder)
if (!_decoder.isVideoLoaded())
return;
_actor->getPage()->getGame()->getDirector()->removeSprite(this);
delete _decoder;
_decoder = nullptr;
}
void ActionCEL::update() {
if (_decoder->endOfVideo()) {
_decoder->stop();
_actor->endAction();
}
closeDecoder();
}
void ActionCEL::pause(bool paused) {
_decoder->pauseVideo(paused);
_decoder.pauseVideo(paused);
}
Coordinates ActionCEL::getCoordinates() {
if (!_decoder)
_decoder = _actor->getPage()->loadCel(_fileName);
loadDecoder();
Coordinates coords;
coords.x = _decoder->getX() + _decoder->getWidth() / 2;
coords.y = _decoder->getY() + _decoder->getHeight() / 2;
Common::Point point = _decoder.getCenter();
coords.x = point.x;
coords.y = point.y;
coords.z = getZ();
return coords;
}
void ActionCEL::loadDecoder() {
if (!_decoder.isVideoLoaded())
_decoder.loadStream(_actor->getPage()->getResourceStream(_fileName));
}
void ActionCEL::closeDecoder() {
_actor->getPage()->getGame()->getDirector()->removeSprite(this);
_decoder.close();
}
void ActionCEL::setFrame(uint frame) {
_decoder.rewind();
for (uint i = 0; i < frame; ++i) {
_decoder.skipFrame();
}
_decoder.clearDirtyRects();
}
void ActionCEL::decodeNext() {
_decoder.decodeNextFrame();
_actor->getPage()->getGame()->getDirector()->addDirtyRects(this);
}
void ActionCEL::setCenter(const Common::Point &center) {
_actor->getPage()->getGame()->getDirector()->addDirtyRect(_bounds);
_bounds = Common::Rect::center(center.x, center.y, _decoder.getWidth(), _decoder.getHeight());
_actor->getPage()->getGame()->getDirector()->addDirtyRect(_bounds);
}
} // End of namespace Pink

View File

@ -23,6 +23,7 @@
#ifndef PINK_ACTION_CEL_H
#define PINK_ACTION_CEL_H
#include "pink/cel_decoder.h"
#include "pink/objects/actions/action.h"
namespace Pink {
@ -31,7 +32,6 @@ class CelDecoder;
class ActionCEL : public Action {
public:
ActionCEL();
~ActionCEL() override;
void deserialize(Archive &archive) override;
@ -41,20 +41,31 @@ public:
void start() override;
void end() override;
virtual void update();
bool needsUpdate() { return _decoder.needsUpdate(); }
virtual void update() {};
void pause(bool paused) override;
Coordinates getCoordinates() override;
const Common::Rect &getBounds() const { return _bounds; }
uint32 getZ() { return _z; }
CelDecoder *getDecoder() { return _decoder; }
CelDecoder *getDecoder() { return &_decoder; }
void setCenter(const Common::Point &center);
protected:
virtual void onStart() = 0;
CelDecoder *_decoder;
void loadDecoder();
void closeDecoder();
void setFrame(uint frame);
void decodeNext();
CelDecoder _decoder;
Common::String _fileName;
Common::Rect _bounds;
uint32 _z;
};

View File

@ -20,10 +20,13 @@
*
*/
#include "pink/archive.h"
#include "common/random.h"
#include "pink/pink.h"
#include "pink/cel_decoder.h"
#include "pink/objects/actions/action_loop.h"
#include "pink/objects/actors/actor.h"
#include "pink/objects/pages/page.h"
namespace Pink {
@ -34,10 +37,10 @@ void ActionLoop::deserialize(Archive &archive) {
style = archive.readWORD();
switch (style) {
case kPingPong:
_style = kPingPong;
_style = kPingPong;
break;
case kRandom:
_style = kRandom;
_style = kRandom; // haven't seen
break;
default:
_style = kForward;
@ -51,18 +54,68 @@ void ActionLoop::toConsole() {
}
void ActionLoop::update() {
// for now it supports only forward loop animation
if (_style == kForward) {
if (_decoder->endOfVideo() || _decoder->getCurFrame() == _stopFrame) {
//debug("ACTION LOOP : NEXT ITERATION");
_decoder->rewind();
ActionCEL::update();
int frame = _decoder.getCurFrame();
if (!_inLoop) {
if (frame < _startFrame) {
decodeNext();
return;
}
else
_inLoop = true;
}
switch (_style) {
case kPingPong:
if (_forward) {
if (frame < _stopFrame) {
decodeNext();
} else {
_forward = false;
setFrame(_stopFrame - 1);
decodeNext();
}
}
else {
if (frame > _startFrame) {
setFrame(frame - 1);
} else {
_forward = true;
}
decodeNext();
}
break;
case kRandom: { // Not tested
Common::RandomSource &rnd = _actor->getPage()->getGame()->getRnd();
setFrame(rnd.getRandomNumberRng(_startFrame, _stopFrame));
break;
}
case kForward:
if (frame == _stopFrame) {
setFrame(_startFrame);
}
decodeNext();
break;
}
}
void ActionLoop::onStart() {
ActionPlay::onStart();
_actor->endAction();
if (_intro) {
uint startFrame = _startFrame;
_startFrame = 0;
ActionPlay::onStart();
_startFrame = startFrame;
_inLoop = false;
} else {
ActionPlay::onStart();
_inLoop = true;
}
if (!isTalk())
_actor->endAction();
_forward = true;
}
} // End of namespace Pink

View File

@ -37,14 +37,17 @@ public:
protected:
void onStart() override;
virtual bool isTalk() { return false; }
enum Style {
kPingPong = 2,
kRandom = 3,
kForward = 4
};
uint _intro;
Style _style;
bool _intro;
bool _inLoop;
bool _forward;
};
} // End of namespace Pink

View File

@ -45,10 +45,11 @@ void ActionPlay::end() {
}
void ActionPlay::update() {
if (_decoder->endOfVideo() || _decoder->getCurFrame() == _stopFrame) {
_decoder->stop();
ActionCEL::update();
if (_decoder.getCurFrame() >= _stopFrame)
_actor->endAction();
}
else
decodeNext();
}
void ActionPlay::pause(bool paused) {
@ -57,12 +58,11 @@ void ActionPlay::pause(bool paused) {
void ActionPlay::onStart() {
debug("Actor %s has now ActionPlay %s", _actor->getName().c_str(), _name.c_str());
_decoder->start();
assert(_startFrame <= _decoder->getFrameCount());
for (uint i = 0; i < _startFrame; ++i) {
_decoder->skipFrame();
}
_decoder->decodeNextFrame();
if (_stopFrame == -1)
_stopFrame = _decoder.getFrameCount() - 1;
assert(_startFrame < _decoder.getFrameCount());
setFrame(_startFrame);
// doesn't need to decode startFrame here. Update method will decode
}
} // End of namespace Pink

View File

@ -50,32 +50,25 @@ void ActionPlayWithSfx::toConsole() {
}
void ActionPlayWithSfx::update() {
if ((_decoder->endOfVideo() || _decoder->getCurFrame() == _stopFrame) && _isLoop) {
_decoder->rewind();
} else if (_decoder->endOfVideo() || _decoder->getCurFrame() == _stopFrame) {
_decoder->stop();
_actor->endAction();
}
int currFrame = _decoder.getCurFrame();
if (_isLoop && currFrame == _stopFrame) {
assert(_stopFrame == _decoder.getFrameCount() - 1); // to use ring frame
assert(_startFrame == 0); // same
_decoder.rewind();
decodeNext();
} else
ActionPlay::update();
updateSound();
for (uint i = 0; i < _sfxArray.size(); ++i) {
if (_sfxArray[i]->getFrame() == currFrame)
_sfxArray[i]->play();
}
}
void ActionPlayWithSfx::onStart() {
ActionPlay::onStart();
if (_isLoop) {
if (_isLoop)
_actor->endAction();
}
updateSound();
}
void ActionPlayWithSfx::updateSound() {
if (!_actor->isPlaying() && !_isLoop)
return;
for (uint i = 0; i < _sfxArray.size(); ++i) {
if (_sfxArray[i]->getFrame() == _decoder->getCurFrame())
_sfxArray[i]->play();
}
}
void ActionSfx::deserialize(Pink::Archive &archive) {
@ -93,7 +86,7 @@ void ActionSfx::toConsole() {
void ActionSfx::play() {
Page *page = _sprite->getActor()->getPage();
if (!_sound.isPlaying()) {
int8 balance = (_sprite->getDecoder()->getX() * 396875 / 1000000) - 127;
int8 balance = (_sprite->getDecoder()->getCenter().x * 396875 / 1000000) - 127;
_sound.play(page->getResourceStream(_sfxName), Audio::Mixer::kSFXSoundType, _volume, balance);
}
}

View File

@ -44,8 +44,6 @@ protected:
void onStart() override;
private:
void updateSound();
Array<ActionSfx *> _sfxArray;
uint32 _isLoop;
};
@ -60,14 +58,14 @@ public:
void play();
uint32 getFrame() { return _frame; }
int32 getFrame() { return _frame; }
private:
ActionPlayWithSfx *_sprite;
Common::String _sfxName;
Sound _sound;
uint32 _volume;
uint32 _frame;
int32 _volume;
int32 _frame;
};
} // End of namespace Pink

View File

@ -48,13 +48,16 @@ void ActionStill::pause(bool paused) {}
void ActionStill::onStart() {
debug("Actor %s has now ActionStill %s", _actor->getName().c_str(), _name.c_str());
if (_startFrame >= _decoder->getFrameCount())
if (_startFrame >= _decoder.getFrameCount())
_startFrame = 0;
for (uint i = 0; i < _startFrame; ++i) {
_decoder->skipFrame();
}
_decoder->decodeNextFrame();
_decoder->stop();
setFrame(_startFrame); // seek to frame before startFrame
decodeNext(); // decode startFrame
_decoder.pauseVideo(1); // pause so that decoder doesn't need updates.
assert(!_decoder.needsUpdate());
_actor->endAction();
}

View File

@ -43,7 +43,7 @@ void ActionTalk::toConsole() {
void ActionTalk::update() {
ActionLoop::update();
if (!_sound.isPlaying()) {
_decoder->stop();
_decoder.pauseVideo(1);
_actor->endAction();
}
}
@ -59,10 +59,10 @@ void ActionTalk::pause(bool paused) {
}
void ActionTalk::onStart() {
ActionPlay::onStart();
ActionLoop::onStart();
//sound balance is calculated different than in ActionSfx(probably a bug in original)
// 30.0 - x * -0.0625 disasm (0 - 100)
int8 balance = (_decoder->getX() * 396875 / 1000000) - 127;
int8 balance = (_decoder.getCenter().x * 396875 / 1000000) - 127;
_sound.play(_actor->getPage()->getResourceStream(_vox), Audio::Mixer::kSpeechSoundType, 100, balance);
}

View File

@ -43,6 +43,7 @@ public:
protected:
void onStart() override;
bool isTalk() override { return true; }
private:
Common::String _vox;

View File

@ -23,6 +23,7 @@
#include "pink/archive.h"
#include "pink/cel_decoder.h"
#include "pink/objects/actions/walk_action.h"
#include "pink/objects/actors/actor.h"
namespace Pink {
@ -38,7 +39,15 @@ void WalkAction::toConsole() {
}
void WalkAction::onStart() {
_decoder->start();
// not implemented
}
void WalkAction::update() {
ActionCEL::update();
if (_decoder.getCurFrame() < (int)_decoder.getFrameCount() - 1)
decodeNext();
else
_actor->endAction();
}
} // End of namespace Pink

View File

@ -33,6 +33,8 @@ public:
void toConsole() override;
void update() override;
protected:
void onStart() override;

View File

@ -47,7 +47,6 @@ public:
LeadActor *getLeadActor() { return _leadActor; }
Common::SafeSeekableSubReadStream *getResourceStream(const Common::String &fileName) { return _resMgr.getResourceStream(fileName); }
CelDecoder *loadCel(Common::String &fileName) { return _resMgr.loadCEL(fileName); }
virtual void clear();
void pause(bool paused);

View File

@ -53,12 +53,6 @@ void ResourceMgr::clear() {
_resDescTable = nullptr;
}
CelDecoder *ResourceMgr::loadCEL(Common::String &name) {
CelDecoder *decoder = new CelDecoder();
decoder->loadStream(getResourceStream(name));
return decoder;
}
Common::String ResourceMgr::loadText(Common::String &name) {
Common::SeekableReadStream *stream = getResourceStream(name);
char *txt = new char[stream->size()];

View File

@ -52,7 +52,6 @@ public:
Common::SafeSeekableSubReadStream *getResourceStream(const Common::String &name);
CelDecoder *loadCEL(Common::String &name);
Common::String loadText(Common::String &name);
PinkEngine *getGame() const { return _game; }