scummvm/engines/twp/camera.cpp
2024-04-19 20:31:13 +02:00

118 lines
3.8 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/>.
*
*/
#include "twp/twp.h"
#include "twp/object.h"
#include "twp/room.h"
namespace Twp {
void Camera::clamp(const Math::Vector2d &at) {
if (_room) {
Math::Vector2d roomSize = _room->_roomSize;
Math::Vector2d screenSize = _room->getScreenSize();
// fix assertion when screen size is greater than room height
if (screenSize.getY() > roomSize.getY()) {
screenSize.setY(roomSize.getY());
}
_pos.setX(CLIP(at.getX(), screenSize.getX() / 2.f + _bounds.left(), screenSize.getX() / 2 + _bounds.right()));
_pos.setY(CLIP(at.getY(), _bounds.bottom(), _bounds.top() - screenSize.getY() / 2));
_pos.setX(CLIP(_pos.getX(), screenSize.getX() / 2.f, MAX(roomSize.getX() - screenSize.getX() / 2.f, 0.f)));
_pos.setY(CLIP(_pos.getY(), screenSize.getY() / 2, MAX(roomSize.getY() - screenSize.getY() / 2, 0.f)));
}
}
void Camera::setAtCore(const Math::Vector2d &at) {
Math::Vector2d screenSize = _room->getScreenSize();
_pos = at;
clamp(_pos);
g_twp->getGfx().cameraPos(_pos - screenSize / 2.f);
}
void Camera::setAt(const Math::Vector2d &at) {
setAtCore(at);
_target = _pos;
_time = 0;
_moving = false;
}
void Camera::panTo(const Math::Vector2d &target, float time, InterpolationKind interpolation) {
if (!_moving) {
_moving = true;
_init = _pos;
_elapsed = 0.f;
}
_function = easing(interpolation);
_target = target;
_time = time;
}
void Camera::update(Common::SharedPtr<Room> room, Common::SharedPtr<Object> follow, float elapsed) {
_room = room;
_elapsed += elapsed;
bool isMoving = _elapsed < _time;
if (_moving && !isMoving) {
_moving = false;
_time = 0.f;
setAt(_target);
}
if (isMoving) {
float t = _elapsed / _time;
Math::Vector2d d = _target - _init;
Math::Vector2d pos = _init + (d * _function.func(t));
setAtCore(pos);
return;
}
if (follow && follow->_node->isVisible() && follow->_room == room) {
Math::Vector2d screen = room->getScreenSize();
Math::Vector2d pos = follow->_node->getPos();
Math::Vector2d margin(screen.getX() / 6.f, screen.getY() / 6.f);
Math::Vector2d cameraPos = getAt();
Math::Vector2d d = pos - cameraPos;
Math::Vector2d delta = d * elapsed;
bool sameActor = _follow == follow;
float x, y;
if (sameActor && (pos.getX() > (cameraPos.getX() + margin.getX())))
x = pos.getX() - margin.getX();
else if (sameActor && (pos.getX() < (cameraPos.getX() - margin.getX())))
x = pos.getX() + margin.getX();
else
x = cameraPos.getX() + (d.getX() > 0 ? MIN(delta.getX(), d.getX()) : MAX(delta.getX(), d.getX()));
if (sameActor && (pos.getY() > (cameraPos.getY() + margin.getY())))
y = pos.getY() - margin.getY();
else if (sameActor && (pos.getY() < (cameraPos.getY() - margin.getY())))
y = pos.getY() + margin.getY();
else
y = cameraPos.getY() + (d.getY() > 0 ? MIN(delta.getY(), d.getY()) : MAX(delta.getY(), d.getY()));
setAtCore(Math::Vector2d(x, y));
if (!sameActor && (fabs(pos.getX() - x) < 1.f) && (fabs(pos.getY() - y) < 1.f))
_follow = follow;
}
}
} // namespace Twp