298 lines
11 KiB
C++
Executable File
298 lines
11 KiB
C++
Executable File
/*
|
|
* Copyright (C) 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef CAMUTILS_MANIPULATOR_H
|
|
#define CAMUTILS_MANIPULATOR_H
|
|
|
|
#include <camutils/Bookmark.h>
|
|
|
|
#include <math/vec2.h>
|
|
#include <math/vec3.h>
|
|
#include <math/vec4.h>
|
|
|
|
#include <cstdint>
|
|
|
|
namespace filament {
|
|
namespace camutils {
|
|
|
|
enum class Fov { VERTICAL, HORIZONTAL };
|
|
|
|
/**
|
|
* Helper that enables camera interaction similar to sketchfab or Google Maps.
|
|
*
|
|
* Clients notify the camera manipulator of various mouse or touch events, then periodically call
|
|
* its getLookAt() method so that they can adjust their camera(s). Three modes are supported: ORBIT,
|
|
* MAP, and FREE_FLIGHT. To construct a manipulator instance, the desired mode is passed into the
|
|
* create method.
|
|
*
|
|
* Usage example:
|
|
*
|
|
* using CameraManipulator = camutils::Manipulator<float>;
|
|
* CameraManipulator* manip;
|
|
*
|
|
* void init() {
|
|
* manip = CameraManipulator::Builder()
|
|
* .viewport(1024, 768)
|
|
* .build(camutils::Mode::ORBIT);
|
|
* }
|
|
*
|
|
* void onMouseDown(int x, int y) {
|
|
* manip->grabBegin(x, y, false);
|
|
* }
|
|
*
|
|
* void onMouseMove(int x, int y) {
|
|
* manip->grabUpdate(x, y);
|
|
* }
|
|
*
|
|
* void onMouseUp(int x, int y) {
|
|
* manip->grabEnd();
|
|
* }
|
|
*
|
|
* void gameLoop() {
|
|
* while (true) {
|
|
* filament::math::float3 eye, center, up;
|
|
* manip->getLookAt(&eye, ¢er, &up);
|
|
* camera->lookAt(eye, center, up);
|
|
* render();
|
|
* }
|
|
* }
|
|
*
|
|
* @see Bookmark
|
|
*/
|
|
template <typename FLOAT>
|
|
class Manipulator {
|
|
public:
|
|
using vec2 = filament::math::vec2<FLOAT>;
|
|
using vec3 = filament::math::vec3<FLOAT>;
|
|
using vec4 = filament::math::vec4<FLOAT>;
|
|
|
|
/** Opaque handle to a viewing position and orientation to facilitate camera animation. */
|
|
using Bookmark = filament::camutils::Bookmark<FLOAT>;
|
|
|
|
/** Optional raycasting function to enable perspective-correct panning. */
|
|
typedef bool (*RayCallback)(const vec3& origin, const vec3& dir, FLOAT* t, void* userdata);
|
|
|
|
/** Builder state, direct access is allowed but Builder methods are preferred. **/
|
|
struct Config {
|
|
int viewport[2];
|
|
vec3 targetPosition;
|
|
vec3 upVector;
|
|
FLOAT zoomSpeed;
|
|
vec3 orbitHomePosition;
|
|
vec2 orbitSpeed;
|
|
Fov fovDirection;
|
|
FLOAT fovDegrees;
|
|
FLOAT farPlane;
|
|
vec2 mapExtent;
|
|
FLOAT mapMinDistance;
|
|
vec3 flightStartPosition;
|
|
FLOAT flightStartPitch;
|
|
FLOAT flightStartYaw;
|
|
FLOAT flightMaxSpeed;
|
|
FLOAT flightSpeedSteps;
|
|
vec2 flightPanSpeed;
|
|
FLOAT flightMoveDamping;
|
|
vec4 groundPlane;
|
|
RayCallback raycastCallback;
|
|
void* raycastUserdata;
|
|
};
|
|
|
|
struct Builder {
|
|
// Common properties
|
|
Builder& viewport(int width, int height); //! Width and height of the viewing area
|
|
Builder& targetPosition(FLOAT x, FLOAT y, FLOAT z); //! World-space position of interest, defaults to (0,0,0)
|
|
Builder& upVector(FLOAT x, FLOAT y, FLOAT z); //! Orientation for the home position, defaults to (0,1,0)
|
|
Builder& zoomSpeed(FLOAT val); //! Multiplied with scroll delta, defaults to 0.01
|
|
|
|
// Orbit mode properties
|
|
Builder& orbitHomePosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,1)
|
|
Builder& orbitSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01
|
|
|
|
// Map mode properties
|
|
Builder& fovDirection(Fov fov); //! The axis that's held constant when viewport changes
|
|
Builder& fovDegrees(FLOAT degrees); //! The full FOV (not the half-angle)
|
|
Builder& farPlane(FLOAT distance); //! The distance to the far plane
|
|
Builder& mapExtent(FLOAT worldWidth, FLOAT worldHeight); //! The ground size for computing home position
|
|
Builder& mapMinDistance(FLOAT mindist); //! Constrains the zoom-in level
|
|
|
|
// Free flight properties
|
|
Builder& flightStartPosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,0)
|
|
Builder& flightStartOrientation(FLOAT pitch, FLOAT yaw); //! Initial orientation in pitch and yaw, defaults to (0,0)
|
|
Builder& flightMaxMoveSpeed(FLOAT maxSpeed); //! The maximum camera speed in world units per second, defaults to 10
|
|
Builder& flightSpeedSteps(int steps); //! The number of speed steps adjustable with scroll wheel, defaults to 80
|
|
Builder& flightPanSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01,0.01
|
|
Builder& flightMoveDamping(FLOAT damping); //! Applies a deceleration to camera movement, defaults to 0 (no damping)
|
|
//! Lower values give slower damping times, a good default is 15
|
|
//! Too high a value may lead to instability
|
|
|
|
// Raycast properties
|
|
Builder& groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d); //! Plane equation used as a raycast fallback
|
|
Builder& raycastCallback(RayCallback cb, void* userdata); //! Raycast function for accurate grab-and-pan
|
|
|
|
/**
|
|
* Creates a new camera manipulator, either ORBIT, MAP, or FREE_FLIGHT.
|
|
*
|
|
* Clients can simply use "delete" to destroy the manipulator.
|
|
*/
|
|
Manipulator* build(Mode mode);
|
|
|
|
Config details = {};
|
|
};
|
|
|
|
virtual ~Manipulator() = default;
|
|
|
|
/**
|
|
* Gets the immutable mode of the manipulator.
|
|
*/
|
|
Mode getMode() const { return mMode; }
|
|
|
|
/**
|
|
* Sets the viewport dimensions. The manipulator uses this to process grab events and raycasts.
|
|
*/
|
|
void setViewport(int width, int height);
|
|
|
|
/**
|
|
* Gets the current orthonormal basis; this is usually called once per frame.
|
|
*/
|
|
void getLookAt(vec3* eyePosition, vec3* targetPosition, vec3* upward) const;
|
|
|
|
/**
|
|
* Given a viewport coordinate, picks a point in the ground plane, or in the actual scene if the
|
|
* raycast callback was provided.
|
|
*/
|
|
bool raycast(int x, int y, vec3* result) const;
|
|
|
|
/**
|
|
* Given a viewport coordinate, computes a picking ray (origin + direction).
|
|
*/
|
|
void getRay(int x, int y, vec3* origin, vec3* dir) const;
|
|
|
|
/**
|
|
* Starts a grabbing session (i.e. the user is dragging around in the viewport).
|
|
*
|
|
* In MAP mode, this starts a panning session.
|
|
* In ORBIT mode, this starts either rotating or strafing.
|
|
* In FREE_FLIGHT mode, this starts a nodal panning session.
|
|
*
|
|
* @param x X-coordinate for point of interest in viewport space
|
|
* @param y Y-coordinate for point of interest in viewport space
|
|
* @param strafe ORBIT mode only; if true, starts a translation rather than a rotation
|
|
*/
|
|
virtual void grabBegin(int x, int y, bool strafe) = 0;
|
|
|
|
/**
|
|
* Updates a grabbing session.
|
|
*
|
|
* This must be called at least once between grabBegin / grabEnd to dirty the camera.
|
|
*/
|
|
virtual void grabUpdate(int x, int y) = 0;
|
|
|
|
/**
|
|
* Ends a grabbing session.
|
|
*/
|
|
virtual void grabEnd() = 0;
|
|
|
|
/**
|
|
* Keys used to translate the camera in FREE_FLIGHT mode.
|
|
* FORWARD and BACKWARD dolly the camera forwards and backwards.
|
|
* LEFT and RIGHT strafe the camera left and right.
|
|
* UP and DOWN boom the camera upwards and downwards.
|
|
*/
|
|
enum class Key {
|
|
FORWARD,
|
|
LEFT,
|
|
BACKWARD,
|
|
RIGHT,
|
|
UP,
|
|
DOWN,
|
|
|
|
COUNT
|
|
};
|
|
|
|
/**
|
|
* Signals that a key is now in the down state.
|
|
*
|
|
* In FREE_FLIGHT mode, the camera is translated forward and backward and strafed left and right
|
|
* depending on the depressed keys. This allows WASD-style movement.
|
|
*/
|
|
virtual void keyDown(Key key);
|
|
|
|
/**
|
|
* Signals that a key is now in the up state.
|
|
*
|
|
* @see keyDown
|
|
*/
|
|
virtual void keyUp(Key key);
|
|
|
|
/**
|
|
* In MAP and ORBIT modes, dollys the camera along the viewing direction.
|
|
* In FREE_FLIGHT mode, adjusts the move speed of the camera.
|
|
*
|
|
* @param x X-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode
|
|
* @param y Y-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode
|
|
* @param scrolldelta In MAP and ORBIT modes, negative means "zoom in", positive means "zoom out"
|
|
* In FREE_FLIGHT mode, negative means "slower", positive means "faster"
|
|
*/
|
|
virtual void scroll(int x, int y, FLOAT scrolldelta) = 0;
|
|
|
|
/**
|
|
* Processes input and updates internal state.
|
|
*
|
|
* This must be called once every frame before getLookAt is valid.
|
|
*
|
|
* @param deltaTime The amount of time, in seconds, passed since the previous call to update.
|
|
*/
|
|
virtual void update(FLOAT deltaTime);
|
|
|
|
/**
|
|
* Gets a handle that can be used to reset the manipulator back to its current position.
|
|
*
|
|
* @see jumpToBookmark
|
|
*/
|
|
virtual Bookmark getCurrentBookmark() const = 0;
|
|
|
|
/**
|
|
* Gets a handle that can be used to reset the manipulator back to its home position.
|
|
*
|
|
* @see jumpToBookmark
|
|
*/
|
|
virtual Bookmark getHomeBookmark() const = 0;
|
|
|
|
/**
|
|
* Sets the manipulator position and orientation back to a stashed state.
|
|
*
|
|
* @see getCurrentBookmark, getHomeBookmark
|
|
*/
|
|
virtual void jumpToBookmark(const Bookmark& bookmark) = 0;
|
|
|
|
protected:
|
|
Manipulator(Mode mode, const Config& props);
|
|
|
|
virtual void setProperties(const Config& props);
|
|
|
|
vec3 raycastFarPlane(int x, int y) const;
|
|
|
|
const Mode mMode;
|
|
Config mProps;
|
|
vec3 mEye;
|
|
vec3 mTarget;
|
|
};
|
|
|
|
} // namespace camutils
|
|
} // namespace filament
|
|
|
|
#endif /* CAMUTILS_MANIPULATOR_H */
|