#pragma once
#include "ofCamera.h"
#include "ofEvents.h"
#include "ofRectangle.h"
#include "glm/gtc/quaternion.hpp"
/// \brief A super simple camera for interacting with objects in 3D space.
class ofEasyCam : public ofCamera {
public:
/// \name Constructor and Destructor
/// \{
/// \brief Create a default camera.
ofEasyCam();
/// \}
/// \name Rendering
/// \{
virtual void begin(const ofRectangle & viewport);
virtual void begin(){
begin(getViewport());
}
/// \brief Reset the camera position and orientation.
void reset();
/// \}
/// \name Camera Target
/// \{
/// \brief Set the camera's target.
/// \param target The position of the target.
void setTarget(const glm::vec3& target);
/// \brief Set the camera's target.
/// \param target The position of the target.
void setTarget(ofNode& target);
/// \brief Get the camera's target node reference.
/// \returns a reference the the camera's target node.
const ofNode& getTarget() const;
/// \}
/// \name Getters and Setters
/// \{
/// \brief Set the camera's distance to the target.
/// \param distance The distance to the target.
void setDistance(float distance);
/// \brief Get the distance to the target.
/// \returns the distance to the target.
float getDistance() const;
/// \brief Set the camera's drag coefficient.
///
/// Drag is affects how quickly the camera starts up and slows down when
/// a user interacts with its position using a pointer.
///
/// \param drag The normalized coefficient value between 0 and 1.
void setDrag(float drag);
/// \brief Get the camera's drag coefficient.
/// \returns the camera's drag coefficient.
float getDrag() const;
/// \brief Enable or disable camera autodistance.
///
/// Allow the camera to attempt to set the distance based on the camera's
/// current viewpoirt.
///
/// \param bAutoDistance true to enable auto distance.
void setAutoDistance(bool bAutoDistance);
void setEvents(ofCoreEvents & events);
/// \brief Set the input sensitivity of the rotation.
/// X and Y axes - when the value is 1.0, moving the mouse from one side to
/// the other of the arcball (min(viewport.width, viewport.height)) will
/// rotate 180 degrees. When the value is 0.5, the rotation will be 90
/// degrees.
/// \param value Scales the xyz axes rotation factor by these values.
void setRotationSensitivity(float x, float y, float z);
void setRotationSensitivity(const glm::vec3& sensitivity);
/// \brief Set the input sensitivity of the translation.
/// \param value Scales the xyz axes translation factor by these values.
void setTranslationSensitivity(float x, float y, float z);
void setTranslationSensitivity(const glm::vec3& sensitivity);
/// \brief Set the key used to switch between camera rotation and translation.
///
/// Translation will only happen when the translation key is pressed.
///
/// \param key The key code for the translation key.
/// \todo char is not the right data type for this. Should be int.
void setTranslationKey(char key);
/// \brief Get the current translation key code.
/// \returns the current translation key code.
char getTranslationKey() const;
/// \}
/// \name Mouse Input
/// \{
/// \brief Enable mouse camera control.
void enableMouseInput();
/// \brief Disable mouse camera control.
void disableMouseInput();
/// \brief Determine if mouse camera control is enabled.
/// \todo Rename to isMouseInputEnabled().
/// \returns true iff mouse camera control is enabled.
bool getMouseInputEnabled() const;
/// \brief Enable the mouse's middle button for camera control.
void enableMouseMiddleButton();
/// \brief Disable the mouse's middle button for camera control.
void disableMouseMiddleButton();
/// \brief Determine if the middle mouse button is enabled.
/// \todo Rename to isMouseMiddleButtonEnabled().
/// \returns true iff the mouse's middle button is enabled.
bool getMouseMiddleButtonEnabled() const;
/// \}
/// Uses Y axis relative to the camera orientation
///
/// By default the Y axis used for interactive rotation
/// is vec3(0,1,0) or whatever is set as up axis using
/// setUpAxis
void setRelativeYAxis(bool relative=true);
/// Determine if the Y axis is set to be relative to the
/// camera orientation
bool getRelativeYAxis() const;
/// Set the camera fixed up axis for interactive
/// manipulation.
void setUpAxis(const glm::vec3 & up);
/// Get the up axis.
const glm::vec3 & getUpAxis() const;
void enableInertia();
void disableInertia();
/// Determine if intertia is enabled.
bool getInertiaEnabled() const;
/// Set the area bounds for mouse control.
/// Uses the full viewport by default.
void setControlArea(const ofRectangle & controlArea);
/// Clears the area bounds for mouse control so that
/// the full viewport is used.
void clearControlArea();
/// Returns the area bounds used for mouse control.
ofRectangle getControlArea() const;
/// Transformation types available for mouse interaction.
enum TransformType{
TRANSFORM_NONE,
TRANSFORM_ROTATE,
TRANSFORM_TRANSLATE_XY,
TRANSFORM_TRANSLATE_Z,
TRANSFORM_SCALE
};
void addInteraction(TransformType type, int mouseButton, int key = -1);
void removeInteraction(TransformType type, int mouseButton, int key = -1);
bool hasInteraction(TransformType type, int mouseButton, int key = -1);
bool hasInteraction(int mouseButton, int key);
void removeAllInteractions();
protected:
virtual void onPositionChanged() ;
private:
void setDistance(float distance, bool save);
ofNode target;
bool bEnableMouseMiddleButton = true;
bool bApplyInertia = false;
bool bInsideArcball = false;
bool bMouseInputEnabled = true;
bool bDistanceSet = false;
bool bAutoDistance = true;
bool bEventsSet = false;
bool bIsScrolling = false;
float lastDistance = 0.f;
float drag = 0.9f;
/// rot and translated are used as a temporary values shared between the mouse callbacks and the update method.
/// How much the camera needs to be rotated.
glm::vec3 rot;
/// How much the camera needs to be translated.
glm::vec3 translate;
/// \brief Sensitivity
/// These varibles determine how sensitive is the interaction.
/// High values mean faster and bigger movements/rotations.
/// Low Values mean more presicion.
glm::vec3 sensitivityTranslate;
glm::vec3 sensitivityRot;
float sensitivityScroll = 1.0f;
/// \brief The previous mouse position.
glm::vec2 prevMouse;
/// \brief The mouse velocity (mouse position delta).
glm::vec2 mouseVel;
void updateRotation();
void updateTranslation();
void update(ofEventArgs & args);
void mousePressed(ofMouseEventArgs & mouse);
void mouseReleased(ofMouseEventArgs & mouse);
void mouseScrolled(ofMouseEventArgs & mouse);
void updateMouse(const glm::vec2 & mouse);
/// \brief Returns the up axis vector;
glm::vec3 up() const;
/// \brief The key used to differentiate between translation and rotation.
char doTranslationKey = 'm';
/// \brief The time of the last pointer down event.
unsigned long lastTap = 0;
/// \brief The current rotation quaternion.
glm::quat curRot;
/// \name On Press cache
/// \{
/// \brief camera properties when the mouse is pressed.
glm::vec3 lastPressAxisX;
glm::vec3 lastPressAxisY;
glm::vec3 lastPressAxisZ;
glm::vec3 lastPressPosition;
glm::quat lastPressOrientation;
glm::vec2 lastPressMouse;
/// \}
/// \brief the current viewport.
ofRectangle viewport;
/// \brief If set, the area mouse control is bound to.
ofRectangle controlArea;
ofEventListeners listeners;
ofCoreEvents * events = nullptr;
bool bRelativeYAxis = false;
bool doInertia = false;
glm::vec3 upAxis{0,1,0};
glm::vec2 mouseAtScroll;
/// \brief previous far and near clip.
float prevFarClip, prevNearClip;
TransformType currentTransformType;
/// \brief This struct holds the combination of mouse button and key press that will trigger a specific interaction.
struct interaction{
interaction():mouseButton(0), key(-1), transformType(TRANSFORM_NONE){}
interaction(TransformType type, int _mouseButton, int _key = -1):mouseButton(_mouseButton), key(_key), transformType(type){}
int mouseButton;
int key;
TransformType transformType;
};
std::vector<interaction> interactions;
};
Comments