Files
2026-02-02 04:50:13 +01:00

227 lines
7.6 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/>.
*
*/
//=============================================================================
//
// Definition for the game viewports and cameras.
//
//=============================================================================
#ifndef AGS_ENGINE_GAME_VIEWPORT_H
#define AGS_ENGINE_GAME_VIEWPORT_H
#include "common/std/memory.h"
#include "common/std/vector.h"
#include "ags/shared/util/geometry.h"
#include "ags/shared/util/scaling.h"
namespace AGS3 {
class Camera;
class Viewport;
typedef std::shared_ptr<Camera> PCamera;
typedef std::shared_ptr<Viewport> PViewport;
typedef std::weak_ptr<Camera> CameraRef;
typedef std::weak_ptr<Viewport> ViewportRef;
// TODO: move to utility header
// From https://stackoverflow.com/questions/45507041/how-to-check-if-weak-ptr-is-empty-non-assigned
// Tests that weak_ptr is empty (was not initialized with valid reference)
template <typename T>
bool is_uninitialized(std::weak_ptr<T> const &weak) {
using wt = std::weak_ptr<T>;
return !weak.owner_before(wt{}) &&!wt{} .owner_before(weak);
}
// Camera defines a "looking eye" inside the room, its position and size.
// It does not render anywhere on its own, instead it is linked to a viewport
// and latter draws what that camera sees.
// One camera may be linked to multiple viewports.
// Camera does not move on its own, this is performed by separate behavior
// algorithm. But it provides "lock" property that tells if its position is
// currently owned by user script.
class Camera {
public:
// Gets camera ID (serves as an index)
inline int GetID() const {
return _id;
}
// Sets new camera ID
void SetID(int id);
// Returns Room camera position and size inside the room (in room coordinates)
const Rect &GetRect() const;
// Sets explicit room camera's orthographic size
void SetSize(const Size sz);
// Puts room camera to the new location in the room
void SetAt(int x, int y);
// Tells if camera is currently locked at custom position
bool IsLocked() const;
// Locks room camera at its current position
void Lock();
// Similar to SetAt, but also locks camera preventing it from following player character
void LockAt(int x, int y);
// Releases camera lock, letting it follow player character
void Release();
// Link this camera to a new viewport; this does not unlink any linked ones
void LinkToViewport(ViewportRef viewport);
// Unlinks this camera from a given viewport; does nothing if link did not exist
void UnlinkFromViewport(int id);
// Get the array of linked viewport references
const std::vector<ViewportRef> &GetLinkedViewports() const;
// Tell if this camera has changed recently
inline bool HasChangedPosition() const {
return _hasChangedPosition;
}
inline bool HasChangedSize() const {
return _hasChangedSize;
}
// Clears the changed flags
void ClearChangedFlags() {
_hasChangedPosition = false;
_hasChangedSize = false;
}
private:
int _id = -1;
// Actual position and orthographic size
Rect _position;
// Locked or following player automatically
bool _locked = false;
// Linked viewport refs, used to notify viewports of camera changes
std::vector<ViewportRef> _viewportRefs;
// Flags that tell whether this camera's position on screen has changed recently
bool _hasChangedPosition = false;
bool _hasChangedSize = false;
};
// A result of coordinate conversion between screen and the room,
// tells which viewport was used to pass the "touch" through.
typedef std::pair<Point, int> VpPoint;
// Viewport class defines a rectangular area on game screen where the contents
// of a Camera are rendered.
// Viewport may have one linked camera at a time.
class Viewport {
public:
// Gets viewport ID (serves as an index)
inline int GetID() const {
return _id;
}
// Sets new viewport ID
void SetID(int id);
// Returns viewport's position on screen
inline const Rect &GetRect() const {
return _position;
}
// Returns viewport's room-to-screen transformation
inline const AGS::Shared::PlaneScaling &GetTransform() const {
return _transform;
}
// Set viewport's rectangle on screen
void SetRect(const Rect &rc);
// Sets viewport size
void SetSize(const Size sz);
// Sets viewport's position on screen
void SetAt(int x, int y);
// Tells whether viewport content is rendered on screen
bool IsVisible() const {
return _visible;
}
// Changes viewport visibility
void SetVisible(bool on);
// Gets the order viewport is displayed on screen
int GetZOrder() const {
return _zorder;
}
// Sets the viewport's z-order on screen
void SetZOrder(int zorder);
// Calculates room-to-viewport coordinate conversion.
void AdjustTransformation();
// Returns linked camera
PCamera GetCamera() const;
// Links new camera to this viewport, overriding existing link;
// pass nullptr to leave viewport without a camera link
void LinkCamera(PCamera cam);
// TODO: provide a Transform object here that does these conversions instead
// Converts room coordinates to the game screen coordinates through this viewport;
// if clipping is on, the function will fail for room coordinates outside of camera
VpPoint RoomToScreen(int roomx, int roomy, bool clip = false) const;
// Converts game screen coordinates to the room coordinates through this viewport;
// if clipping is on, the function will fail for screen coordinates outside of viewport;
// convert_cam_to_data parameter converts camera "game" coordinates to "data" units (legacy mode)
VpPoint ScreenToRoom(int scrx, int scry, bool clip = false, bool convert_cam_to_data = false) const;
// Following functions tell if this viewport has changed recently
inline bool HasChangedPosition() const {
return _hasChangedPosition;
}
inline bool HasChangedSize() const {
return _hasChangedSize;
}
inline bool HasChangedVisible() const {
return _hasChangedVisible;
}
inline void SetChangedVisible() {
_hasChangedVisible = true;
}
// Clears the changed flags
inline void ClearChangedFlags() {
_hasChangedPosition = false;
_hasChangedSize = false;
_hasChangedVisible = false;
}
private:
// Parameterized implementation of screen-to-room coordinate conversion
VpPoint ScreenToRoomImpl(int scrx, int scry, bool clip, bool convert_cam_to_data);
int _id = -1;
// Position of the viewport on screen
Rect _position;
// TODO: Camera reference (when supporting multiple cameras)
// Coordinate transform between camera and viewport
// TODO: need to add rotate conversion to let script API support that;
// (maybe use full 3D matrix for that)
AGS::Shared::PlaneScaling _transform;
// Linked camera reference
CameraRef _camera;
bool _visible = true;
int _zorder = 0;
// Flags that tell whether this viewport's position on screen has changed recently
bool _hasChangedPosition = false;
bool _hasChangedOffscreen = false;
bool _hasChangedSize = false;
bool _hasChangedVisible = false;
};
} // namespace AGS3
#endif // AGS_ENGINE_AC_VIEWPORT_H