mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-05 00:36:57 +00:00
5dcdfd2600
The major contributors provided their consent: DrMcCoy, Strangerke, sdelamarre, sev. The goal is to allow the re-release of this code under Switch, which is incompatible with pure GPL
318 lines
7.3 KiB
C++
318 lines
7.3 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* This file is dual-licensed.
|
|
* In addition to the GPLv3 license mentioned above, this code is also
|
|
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
|
* full text of the license.
|
|
*
|
|
*/
|
|
|
|
#include "gob/surface.h"
|
|
#include "gob/anifile.h"
|
|
#include "gob/cmpfile.h"
|
|
#include "gob/aniobject.h"
|
|
|
|
namespace Gob {
|
|
|
|
ANIObject::ANIObject(const ANIFile &ani) : _ani(&ani), _cmp(nullptr),
|
|
_visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
|
|
|
|
setAnimation(0);
|
|
setPosition();
|
|
}
|
|
|
|
ANIObject::ANIObject(const CMPFile &cmp) : _ani(nullptr), _cmp(&cmp),
|
|
_visible(false), _paused(false), _mode(kModeContinuous), _x(0), _y(0) {
|
|
|
|
setAnimation(0);
|
|
setPosition();
|
|
}
|
|
|
|
ANIObject::~ANIObject() {
|
|
}
|
|
|
|
void ANIObject::setVisible(bool visible) {
|
|
_visible = visible;
|
|
}
|
|
|
|
bool ANIObject::isVisible() const {
|
|
return _visible;
|
|
}
|
|
|
|
void ANIObject::setPause(bool pause) {
|
|
_paused = pause;
|
|
}
|
|
|
|
bool ANIObject::isPaused() const {
|
|
return _paused;
|
|
}
|
|
|
|
void ANIObject::setMode(Mode mode) {
|
|
_mode = mode;
|
|
}
|
|
|
|
void ANIObject::setAnimation(uint16 animation) {
|
|
_animation = animation;
|
|
_frame = 0;
|
|
}
|
|
|
|
void ANIObject::rewind() {
|
|
_frame = 0;
|
|
}
|
|
|
|
void ANIObject::setFrame(uint16 frame) {
|
|
_frame = frame % _ani->getAnimationInfo(_animation).frameCount;
|
|
}
|
|
|
|
void ANIObject::setPosition() {
|
|
// CMP "animations" have no default position
|
|
if (_cmp)
|
|
return;
|
|
|
|
if (_animation >= _ani->getAnimationCount())
|
|
return;
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
|
|
_x = animation.x;
|
|
_y = animation.y;
|
|
}
|
|
|
|
void ANIObject::setPosition(int16 x, int16 y) {
|
|
_x = x;
|
|
_y = y;
|
|
}
|
|
|
|
void ANIObject::getPosition(int16 &x, int16 &y) const {
|
|
x = _x;
|
|
y = _y;
|
|
}
|
|
|
|
void ANIObject::getFramePosition(int16 &x, int16 &y, uint16 n) const {
|
|
// CMP "animations" have no specific frame positions
|
|
if (_cmp) {
|
|
getPosition(x, y);
|
|
return;
|
|
}
|
|
|
|
if (_animation >= _ani->getAnimationCount())
|
|
return;
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
if (_frame >= animation.frameCount)
|
|
return;
|
|
|
|
// If we're paused, we don't advance any frames
|
|
if (_paused)
|
|
n = 0;
|
|
|
|
// Number of cycles run through after n frames
|
|
uint16 cycles = (_frame + n) / animation.frameCount;
|
|
// Frame position after n frames
|
|
uint16 frame = (_frame + n) % animation.frameCount;
|
|
|
|
// Only doing one cycle?
|
|
if (_mode == kModeOnce)
|
|
cycles = MAX<uint16>(cycles, 1);
|
|
|
|
x = _x + animation.frameAreas[frame].left + cycles * animation.deltaX;
|
|
y = _y + animation.frameAreas[frame].top + cycles * animation.deltaY;
|
|
}
|
|
|
|
void ANIObject::getFrameSize(int16 &width, int16 &height, uint16 n) const {
|
|
if (_cmp) {
|
|
width = _cmp->getWidth (_animation);
|
|
height = _cmp->getHeight(_animation);
|
|
|
|
return;
|
|
}
|
|
|
|
if (_animation >= _ani->getAnimationCount())
|
|
return;
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
if (_frame >= animation.frameCount)
|
|
return;
|
|
|
|
// If we're paused, we don't advance any frames
|
|
if (_paused)
|
|
n = 0;
|
|
|
|
// Frame position after n frames
|
|
uint16 frame = (_frame + n) % animation.frameCount;
|
|
|
|
width = animation.frameAreas[frame].right - animation.frameAreas[frame].left + 1;
|
|
height = animation.frameAreas[frame].bottom - animation.frameAreas[frame].top + 1;
|
|
}
|
|
|
|
bool ANIObject::isIn(int16 x, int16 y) const {
|
|
if (!isVisible())
|
|
return false;
|
|
|
|
int16 frameX, frameY, frameWidth, frameHeight;
|
|
getFramePosition(frameX, frameY);
|
|
getFrameSize(frameWidth, frameHeight);
|
|
|
|
if ((x < frameX) || (y < frameY))
|
|
return false;
|
|
if ((x > (frameX + frameWidth)) || (y > (frameY + frameHeight)))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ANIObject::isIn(const ANIObject &obj) const {
|
|
if (!isVisible() || !obj.isVisible())
|
|
return false;
|
|
|
|
int16 frameX, frameY, frameWidth, frameHeight;
|
|
getFramePosition(frameX, frameY);
|
|
getFrameSize(frameWidth, frameHeight);
|
|
|
|
return obj.isIn(frameX , frameY ) ||
|
|
obj.isIn(frameX + frameWidth - 1, frameY ) ||
|
|
obj.isIn(frameX , frameY + frameHeight - 1) ||
|
|
obj.isIn(frameX + frameWidth - 1, frameY + frameHeight - 1);
|
|
}
|
|
|
|
bool ANIObject::draw(Surface &dest, int16 &left, int16 &top,
|
|
int16 &right, int16 &bottom) {
|
|
|
|
if (!_visible)
|
|
return false;
|
|
|
|
if (_cmp)
|
|
return drawCMP(dest, left, top, right, bottom);
|
|
else if (_ani)
|
|
return drawANI(dest, left, top, right, bottom);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top,
|
|
int16 &right, int16 &bottom) {
|
|
|
|
if (!hasBuffer()) {
|
|
uint16 width, height;
|
|
|
|
_cmp->getMaxSize(width, height);
|
|
|
|
resizeBuffer(width, height);
|
|
}
|
|
|
|
left = _x;
|
|
top = _y;
|
|
right = _x + _cmp->getWidth (_animation) - 1;
|
|
bottom = _y + _cmp->getHeight(_animation) - 1;
|
|
|
|
if (!saveScreen(dest, left, top, right, bottom))
|
|
return false;
|
|
|
|
_cmp->draw(dest, _animation, _x, _y, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top,
|
|
int16 &right, int16 &bottom) {
|
|
|
|
if (!hasBuffer()) {
|
|
uint16 width, height;
|
|
|
|
_ani->getMaxSize(width, height);
|
|
|
|
resizeBuffer(width, height);
|
|
}
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
if (_frame >= animation.frameCount)
|
|
return false;
|
|
|
|
const ANIFile::FrameArea &area = animation.frameAreas[_frame];
|
|
|
|
left = _x + area.left;
|
|
top = _y + area.top;
|
|
right = _x + area.right;
|
|
bottom = _y + area.bottom;
|
|
|
|
if (!saveScreen(dest, left, top, right, bottom))
|
|
return false;
|
|
|
|
_ani->draw(dest, _animation, _frame, _x, _y);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ANIObject::clear(Surface &dest, int16 &left, int16 &top,
|
|
int16 &right, int16 &bottom) {
|
|
|
|
return restoreScreen(dest, left, top, right, bottom);
|
|
}
|
|
|
|
void ANIObject::advance() {
|
|
if (_paused)
|
|
return;
|
|
|
|
// CMP "animations" have only one frame
|
|
if (_cmp)
|
|
return;
|
|
|
|
if (_animation >= _ani->getAnimationCount())
|
|
return;
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
|
|
_frame = (_frame + 1) % animation.frameCount;
|
|
|
|
if (_frame == 0) {
|
|
_x += animation.deltaX;
|
|
_y += animation.deltaY;
|
|
|
|
if (_mode == kModeOnce) {
|
|
_paused = true;
|
|
_visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16 ANIObject::getAnimation() const {
|
|
return _animation;
|
|
}
|
|
|
|
uint16 ANIObject::getFrame() const {
|
|
return _frame;
|
|
}
|
|
|
|
bool ANIObject::lastFrame() const {
|
|
// CMP "animations" have only one frame
|
|
if (_cmp)
|
|
return true;
|
|
|
|
if (_animation >= _ani->getAnimationCount())
|
|
return true;
|
|
|
|
const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation);
|
|
|
|
return (_frame + 1) >= animation.frameCount;
|
|
}
|
|
|
|
} // End of namespace Gob
|