You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
imGuIZMO.quat/imguizmo_quat/vGizmo3D.h

939 lines
40 KiB
C++

//------------------------------------------------------------------------------
// Copyright (c) 2018-2025 Michele Morrone
// All rights reserved.
//
// https://michelemorrone.eu - https://brutpitt.com
//
// X: https://x.com/BrutPitt - GitHub: https://github.com/BrutPitt
//
// direct mail: brutpitt(at)gmail.com - me(at)michelemorrone.eu
//
// This software is distributed under the terms of the BSD 2-Clause license
//------------------------------------------------------------------------------
#pragma once
#include "vGizmo3D_config.h"
#define VGIZMO_H_FILE
//#define VGIZMO_USES_GLM
#ifdef VGIZMO_USES_GLM
#ifndef VGM_USES_TEMPLATE
#define VGM_USES_TEMPLATE // glm uses template ==> vGizmo needs to know
#endif
#define VG_T_TYPE float
#include <glm/glm.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <glm/gtx/exterior_product.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
using tVec2 = glm::tvec2<VG_T_TYPE>;
using tVec3 = glm::tvec3<VG_T_TYPE>;
using tVec4 = glm::tvec4<VG_T_TYPE>;
using tQuat = glm::tquat<VG_T_TYPE>;
using tMat3 = glm::tmat3x3<VG_T_TYPE>;
using tMat4 = glm::tmat4x4<VG_T_TYPE>;
#define T_PI glm::pi<VG_T_TYPE>()
#define T_INV_PI glm::one_over_pi<VG_T_TYPE>()
#define VGIZMO_BASE_CLASS virtualGizmoBaseClass<T>
#define imGuIZMO_BASE_CLASS virtualGizmoBaseClass<float>
#define TEMPLATE_TYPENAME_T template<typename T>
#if !defined(VGM_DISABLE_AUTO_NAMESPACE)
using namespace glm;
#endif
#else // use vgMath
#include "vgMath.h"
#ifdef VGM_USES_TEMPLATE
#define VGIZMO_BASE_CLASS virtualGizmoBaseClass<T>
#define imGuIZMO_BASE_CLASS virtualGizmoBaseClass<float>
#else
#define VGIZMO_BASE_CLASS virtualGizmoBaseClass
#define imGuIZMO_BASE_CLASS VGIZMO_BASE_CLASS
#define T VG_T_TYPE
#endif
#if !defined(VGM_DISABLE_AUTO_NAMESPACE)
using namespace vgm;
#endif
#endif
typedef int vgButtons;
typedef int vgModifiers;
namespace vg {
// Default values for button and modifiers.
// This values are aligned with GLFW defines (for my comfort),
// but they are loose from any platform library: simply initialize
// the virtualGizmo with your values:
// look at "onInit" in glWindow.cpp example.
//--------------------------------------------------------------------
enum {
evLeftButton ,
evRightButton ,
evMiddleButton
};
enum {
evButton1 ,
evButton2 ,
evButton3 ,
evButton4 ,
evButton5 ,
evButton6 ,
evButton7 ,
evButton8 ,
evButton9 ,
evButton10
};
enum {
evNoModifier = 0,
evShiftModifier = 1 ,
evControlModifier = 1<<1,
evAltModifier = 1<<2,
evSuperModifier = 1<<3
};
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//
// Base manipulator class
//
//--------------------------------------------------------------------
//--------------------------------------------------------------------
TEMPLATE_TYPENAME_T class virtualGizmoBaseClass {
public:
virtualGizmoBaseClass() : tbControlButton(evLeftButton), tbControlModifiers(evNoModifier),
tbSecControlButton(evRightButton), tbSecControlModifiers(evNoModifier),
tbRotationButton(evLeftButton),
xRotationModifier(evShiftModifier),
yRotationModifier(evControlModifier),
zRotationModifier(evAltModifier|evSuperModifier)
{
#if defined(VGIZMO3D_FLIP_ROT_ON_X)
flipRotOnX();
#endif
#if defined(VGIZMO3D_FLIP_ROT_ON_Y)
flipRotOnY();
#endif
#if defined(VGIZMO3D_FLIP_ROT_ON_Z)
flipRotOnZ();
#endif
#if defined(VGIZMO3D_FLIP_PAN_X)
isFlipPanX = true;
#endif
#if defined(VGIZMO3D_FLIP_PAN_Y)
isFlipPanY = true;
#endif
#if defined(VGIZMO3D_FLIP_DOLLY)
isFlipDolly = true;
#endif
viewportSize(T(256), T(256)); //initial dummy value
}
virtual ~virtualGizmoBaseClass() {}
// Call to initialize and on reshape
//--------------------------------------------------------------------------
/// Adjoust mouse sensitivity in base to viewport dimensions
///@param[in] w T : current WIDTH of window/viewport/screen
///@param[in] h T : current HEIGHT of window/viewport/screen
///@code
/// vg::vGizmo3D track;
///
/// // call on initialization and on window/viewport resize
/// track.viewportSize(width, height);
///@endcode
virtual void viewportSize(T w, T h) {
width = w; height = h;
minVal = T(width < height ? width*T(0.5) : height*T(0.5));
offset = tVec3(T(0.5) * width, T(0.5) * height, T(0));
}
void inline testRotModifier(int x, int y, vgModifiers mod) { }
/// Start/End mouse capture: call on mouse BUTTON event or on state change
///@param[in] b enum vgButtons : button pressed/released (BUTTON ID)
///@param[in] m enum vgModifiers : current KEY modifier ID (if active) or evNoModifier = 0
///@param[in] pressed bool : mouse button pressed = true, released = false
///@param[in] x T : current X screen coord of mouse cursor
///@param[in] y T : current Y screen coord of mouse cursor
///@code
/// vg::vGizmo3D track;
///
/// // call on mouse BUTTON event or check in main render loop
/// track.mouse((vgButtons) button, (vgModifiers) modifier, pressed, x, y);
///@endcode
virtual void mouse( vgButtons button, vgModifiers mod, bool pressed, T x, T y)
{
if ( (button == tbControlButton) && pressed && (tbControlModifiers ? tbControlModifiers & mod : tbControlModifiers == mod) ) {
tbActive = true;
activateMouse(x,y);
}
if((button == tbSecControlButton) && pressed && (tbSecControlModifiers ? tbSecControlModifiers & mod : tbSecControlModifiers == mod) ) {
tbSecActive = true;
activateMouse(x,y);
}
if ( (button == tbSecControlButton || button == tbControlButton) && !pressed) {
deactivateMouse();
tbActive = false;
tbSecActive = false;
}
if((button == tbRotationButton) && pressed) {
if (xRotationModifier & mod) { tbActive = true; rotationVector = tVec3(T(1), T(0), T(0)); activateMouse(x,y); }
else if (yRotationModifier & mod) { tbActive = true; rotationVector = tVec3(T(0), T(1), T(0)); activateMouse(x,y); }
else if (zRotationModifier & mod) { tbActive = true; rotationVector = tVec3(T(0), T(0), T(1)); activateMouse(x,y); }
} else if((button == tbRotationButton) && !pressed) {
deactivateMouse(); rotationVector = tVec3(T(1)); tbActive = false;
}
}
/// Update rotations/positions in base to mouse movements: call on mouse MOTION event
///@param[in] x T : current X screen coord of mouse cursor
///@param[in] y T : current Y screen coord of mouse cursor
///@code
/// vg::vGizmo3D track;
///
/// // call on mouse MOTION event or check in main render loop
/// if((glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) ||
/// (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) )
/// track.motion((int)x, (int)y);
///@endcode
virtual void motion( T x, T y) {
delta.x = x - pos.x; delta.y = y - pos.y;
pos.x = x; pos.y = y;
update();
}
// Call on Pinching
//--------------------------------------------------------------------------
void pinching(T d, T z = T(0)) {
delta.y = d * z;
update();
}
/// <b>Call in main render loop to implement a continue slow rotation </b><br>
/// <br>
/// This rotation depends on speed of last mouse movements and maintains same spin <br>
/// The speed can be adjusted from <b>setIdleRotSpeed(1.0)</b>
/// It can be stopped by click on screen (without mouse movement)
///@code
/// while (!glfwWindowShouldClose(glfwWindow)) {
/// ...
/// track.idle(); // get continuous rotation on Idle
///@endcode
void idle() { qtRot = qtIdle*qtRot; }
/// <b>Call in main render loop to implement a continue slow rotation for secondary trackball</b><br>
/// <br>
/// This rotation depends on speed of last mouse movements and maintains same spin <br>
/// The speed can be adjusted from <b>setIdleRotSpeed(1.0)</b>
/// It can be stopped by click on screen (without mouse movement)
///@code
/// while (!glfwWindowShouldClose(glfwWindow)) {
/// ...
/// track.idleSecond(); // get continuous rotation on Idle
///@endcode
void idleSecond() { qtSecondRot = qtIdleSec*qtSecondRot; }
// Call after changed settings
//--------------------------------------------------------------------------
virtual void update() = 0;
void updateGizmo()
{
if(delta.x == 0 && delta.y == 0) {
qtStep = tQuat(T(1), T(0), T(0), T(0)); //no rotation
qtStepSec = tQuat(T(1), T(0), T(0), T(0)); //no rotation
if(tbActive) qtIdle = tQuat(T(1), T(0), T(0), T(0));
if(tbSecActive) qtIdleSec = tQuat(T(1), T(0), T(0), T(0));
return;
}
tVec3 a(T(pos.x-delta.x), T(pos.y-delta.y), T(0));
tVec3 b(T(pos.x ), T(pos.y ), T(0));
auto vecFromPos = [&] (tVec3 &v) {
v -= offset;
v /= minVal;
const T len = length(v);
v.z = len>T(0) ? pow(T(2), -T(.5) * len) : T(1);
return normalize(v);
};
a = vecFromPos(a);
b = vecFromPos(b);
tVec3 axis = normalize(cross(a, b));
T AdotB = dot(a, b);
T angle = acos( AdotB>T(1) ? T(1) : (AdotB<-T(1) ? -T(1) : AdotB)); // clamp necessary!!! corss float is approximate to FLT_EPSILON
auto flipRotation = [=] (quat q) {
return quat(q.w, rotOnX * q.x, rotOnY * q.y, rotOnZ * -q.z);
};
auto getNormalizedQuat = [&] (float factor = T(1)) {
return normalize(angleAxis(angle * tbScale * fpsRatio * factor, axis * rotationVector));
};
if(tbActive) {
qtStep = flipRotation(getNormalizedQuat());
qtIdle = flipRotation(getNormalizedQuat(qIdleSpeedRatio * qIdleReduction));
qtRot = qtStep*qtRot;
}
if(tbSecActive) {
qtStepSec = flipRotation(getNormalizedQuat());
qtIdleSec = flipRotation(getNormalizedQuat(qIdleSpeedRatio * qIdleReduction));
qtSecondRot = qtStepSec*qtSecondRot;
}
}
/// Set the mouse sensitivity for vGizmo3D
///@param[in] scale float : values > 1.0 more, values < 1.0 less
void setGizmoFeeling( T scale) { tbScale = scale; }
// Call with current fps (every rendering) to adjust "auto" sensitivity
//////////////////////////////////////////////////////////////////
void setGizmoFPS(T fps) { fpsRatio = T(60.0)/fps;}
// Apply rotation
//////////////////////////////////////////////////////////////////
inline void applyRotation(tMat4 &m) { m = m * mat4_cast(qtRot); }
// Set the point around which the virtualGizmo will rotate.
//////////////////////////////////////////////////////////////////
void setRotationCenter( const tVec3& c) { rotationCenter = c; }
tVec3& getRotationCenter() { return rotationCenter; }
/// Set mouse BUTTON and KEY modifier for main rotation
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Initialize main rotation
/// track.setGizmoRotControl (vg::evButton1 /* or vg::evLeftButton */, 0 /* vg::evNoModifier */ );
///
/// // Rotations around specific axis: mouse button and key modifier
/// track.setGizmoRotXControl (vg::evButton1 /* or vg::evLeftButton */, vg::evShiftModifier);
/// track.setGizmoRotYControl (vg::evButton1 /* or vg::evLeftButton */, vg::evControlModifier);
/// track.setGizmoRotZControl (vg::evButton1 /* or vg::evLeftButton */, vg::evAltModifier | vg::evSuperModifier);
///
/// // Set vGizmo3D control for secondary rotation
/// track.setGizmoSecondRotControl(vg::evButton2 /* or vg::evRightButton */, 0 /* vg::evNoModifier */ );
///
/// // Pan and Dolly/Zoom: mouse button and key modifier
/// track.setDollyControl (vg::evButton2 /* or vg::evRightButton */, vg::evControlModifier);
/// track.setPanControl (vg::evButton2 /* or vg::evRightButton */, vg::evShiftModifier);
///@endcode
///@note the example values are also DEFAULT values: you can omit to set they and to override only the associations that you want modify
void setGizmoRotControl( vgButtons b, vgModifiers m = evNoModifier) {
tbControlButton = b;
tbControlModifiers = m;
}
/// Set mouse BUTTON and KEY modifier for a secondary rotation
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Initialize main rotation
/// track.setGizmoRotControl (vg::evButton1 /* or vg::evLeftButton */, 0 /* vg::evNoModifier */ );
///
/// // Rotations around specific axis: mouse button and key modifier
/// track.setGizmoRotXControl (vg::evButton1 /* or vg::evLeftButton */, vg::evShiftModifier);
/// track.setGizmoRotYControl (vg::evButton1 /* or vg::evLeftButton */, vg::evControlModifier);
/// track.setGizmoRotZControl (vg::evButton1 /* or vg::evLeftButton */, vg::evAltModifier | vg::evSuperModifier);
///
/// // Set vGizmo3D control for secondary rotation
/// track.setGizmoSecondRotControl(vg::evButton2 /* or vg::evRightButton */, 0 /* vg::evNoModifier */ );
///
/// // Pan and Dolly/Zoom: mouse button and key modifier
/// track.setDollyControl (vg::evButton2 /* or vg::evRightButton */, vg::evControlModifier);
/// track.setPanControl (vg::evButton2 /* or vg::evRightButton */, vg::evShiftModifier);
///@endcode
///@note the example values are also DEFAULT values: you can omit to set they and to override only the associations that you want modify
void setGizmoSecondRotControl( vgButtons b, vgModifiers m = evNoModifier) {
tbSecControlButton = b;
tbSecControlModifiers = m;
}
/// Set mouse BUTTON and KEY modifier to enable rotation around X axis
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Rotations around specific axis: mouse button and key modifier
/// track.setGizmoRotXControl (vg::evButton1 /* or vg::evLeftButton */, vg::evShiftModifier);
/// track.setGizmoRotYControl (vg::evButton1 /* or vg::evLeftButton */, vg::evControlModifier);
/// track.setGizmoRotZControl (vg::evButton1 /* or vg::evLeftButton */, vg::evAltModifier | vg::evSuperModifier);
///@endcode
///@note the example values are also DEFAULT values: you can omit to set they and to override only the associations that you want modify
void setGizmoRotXControl( vgButtons b, vgModifiers m = evNoModifier) {
tbRotationButton = b;
xRotationModifier = m;
}
/// Set mouse BUTTON and KEY modifier to enable rotation around Y axis
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Rotations around specific axis: mouse button and key modifier
/// track.setGizmoRotXControl (vg::evButton1 /* or vg::evLeftButton */, vg::evShiftModifier);
/// track.setGizmoRotYControl (vg::evButton1 /* or vg::evLeftButton */, vg::evControlModifier);
/// track.setGizmoRotZControl (vg::evButton1 /* or vg::evLeftButton */, vg::evAltModifier | vg::evSuperModifier);
///@endcode
///@note the example values are also DEFAULT values: you can omit to set they and to override only the associations that you want modify
void setGizmoRotYControl( vgButtons b, vgModifiers m = evNoModifier) {
tbRotationButton = b;
yRotationModifier = m;
}
/// Set mouse BUTTON and KEY modifier to enable rotation around Z axis
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Rotations around specific axis: mouse button and key modifier
/// track.setGizmoRotXControl (vg::evButton1 /* or vg::evLeftButton */, vg::evShiftModifier);
/// track.setGizmoRotYControl (vg::evButton1 /* or vg::evLeftButton */, vg::evControlModifier);
/// track.setGizmoRotZControl (vg::evButton1 /* or vg::evLeftButton */, vg::evAltModifier | vg::evSuperModifier);
///@endcode
///@note the example values are also DEFAULT values: you can omit to set they and to override only the associations that you want modify
void setGizmoRotZControl( vgButtons b, vgModifiers m = evNoModifier) {
tbRotationButton = b;
zRotationModifier = m;
}
/// Returns the quaternion containing current vGizmo3D rotation
///@retval quat : quaternion contain actual rotation
virtual tQuat getRotation() { return qtRot; }
/// Returns the reference to quaternion containing current vGizmo3D rotation
/// @retval quat& : reference to vGizmo3D quaternion containing actual rotation
/// to acquire and modify, very useful to use directly in ImGuUIZMO_quat
virtual tQuat &refRotation() { return qtRot; }
/// Returns the quaternion containing current vGizmo3D secondary
/// rotation (usually used to rotate light)
/// @retval quat : quaternion contain actual rotation */
virtual tQuat getSecondRot() { return qtSecondRot; }
/// Returns the reference to quaternion containing current vGizmo3D secondary
/// rotation (usually used to rotate light)
/// @retval quat& : reference to vGizmo3D quaternion containing actual rotation
/// to acquire and modify, very useful to use directly in ImGuUIZMO_quat */
virtual tQuat &refSecondRot() { return qtSecondRot; }
/// Set current rotation of vGizmo3D
///@param[in] q quat& : reference quaternion containing rotation to set
void setRotation(const tQuat &q) { qtRot = q; }
/// Set current rotation of vGizmo3D
///@param[in] q quat& : reference quaternion containing rotation to set
void setSecondRot(const tQuat &q) { qtSecondRot = q; }
/// flip X Rot
///@param[in] b bool
void flipRotOnX(bool b = true) { rotOnX = b ? -T(1) : T(1); }
/// flip Y Rot
///@param[in] b bool
void flipRotOnY(bool b = true) { rotOnY = b ? -T(1) : T(1); }
/// flip Z Rot
///@param[in] b bool
void flipRotOnZ(bool b = true) { rotOnZ = b ? -T(1) : T(1); }
/// flip Dolly mouse coord
///@param[in] b bool
void setFlipDolly(bool b) { isFlipDolly = b; }
/// flip Pan X mouse coord
///@param[in] b bool
void setFlipPanX(bool b) { isFlipPanX = b; }
/// flip Pan Y mouse coord
///@param[in] b bool
void setFlipPanY(bool b) { isFlipPanY = b; }
/// get flip Rot X status
/// @retval bool : current flip Rot X status
bool getFlipRotOnX() { return rotOnX < 0; }
/// get flip Rot Y status
/// @retval bool : current flip Rot Y status
bool getFlipRotOnY() { return rotOnY < 0; }
/// get flip Rot Z status
/// @retval bool : current flip Rot Z status
bool getFlipRotOnZ() { return rotOnZ < 0; }
/// get flip Pan X status
/// @retval bool : current flip Pan X status
bool getFlipPanX() { return isFlipPanX; }
/// get flip Pan Y status
/// @retval bool : current flip Pan Y status
bool getFlipPanY() { return isFlipPanY; }
/// get flip Dolly status
/// @retval bool : current flip Dolly status
bool getFlipDolly() { return isFlipDolly; }
// attenuation<1.0 / increment>1.0 of rotation speed in idle
//--------------------------------------------------------------------------
void setIdleRotSpeed(T f) { qIdleSpeedRatio = f; }
T getIdleRotSpeed() { return qIdleSpeedRatio; }
// return current transformations as 4x4 matrix.
//--------------------------------------------------------------------------
virtual tMat4 getTransform() = 0;
//--------------------------------------------------------------------------
virtual void applyTransform(tMat4 &model) = 0;
// Immediate mode helpers
//--------------------------------------------------------------------
// for imGuIZMO or immediate mode control
//////////////////////////////////////////////////////////////////
void motionImmediateLeftButton( T x, T y, T dx, T dy) {
tbActive = true;
delta = tVec2(dx, dy);
pos = tVec2( x, y);
update();
}
// for imGuIZMO or immediate mode control
//////////////////////////////////////////////////////////////////
virtual void motionImmediateMode( T x, T y, T dx, T dy, vgModifiers mod) {
tbActive = true;
delta = tVec2(dx, dy);
pos = tVec2( x, y);
if (xRotationModifier & mod) { rotationVector = tVec3(T(1), T(0), T(0)); }
else if (yRotationModifier & mod) { rotationVector = tVec3(T(0), T(1), T(0)); }
else if (zRotationModifier & mod) { rotationVector = tVec3(T(0), T(0), T(1)); }
update();
}
protected:
void inline activateMouse(T x, T y) {
pos.x = x;
pos.y = y;
delta.x = delta.y = 0;
}
void inline deactivateMouse() {
if(delta.x == 0 && delta.y == 0) update();
delta.x = delta.y = 0;
}
// set the rotation increment
//////////////////////////////////////////////////////////////////
void setStepRotation(const tQuat &q) { qtStep = q; }
void setStepSecondRot(const tQuat &q) { qtStepSec = q; }
// get the rotation increment
//////////////////////////////////////////////////////////////////
tQuat getStepRotation() { return qtStep; }
tQuat getStepSecondRot() { return qtStepSec; }
T panFlipX(T x) { return isFlipPanX ? -x : x; }
T panFlipY(T y) { return isFlipPanY ? -y : y; }
T dollyFlip(T z) { return isFlipDolly ? -z : z; }
tVec2 pos {0} , delta {0};
// UI commands that this virtualGizmo responds to (defaults to left mouse button with no modifier key)
vgButtons tbControlButton, tbRotationButton;
vgButtons tbSecControlButton, tbSecControlModifiers;
vgModifiers tbControlModifiers, xRotationModifier, yRotationModifier, zRotationModifier;
//tVec3 rotationVector = tVec3(T(1));
tQuat qtRot = tQuat(T(1), T(0), T(0), T(0));
tQuat qtSecondRot = tQuat(T(1), T(0), T(0), T(0));
tQuat qtStep = tQuat(T(1), T(0), T(0), T(0));
tQuat qtStepSec = tQuat(T(1), T(0), T(0), T(0));
tQuat qtIdle = tQuat(T(1), T(0), T(0), T(0));
tQuat qtIdleSec = tQuat(T(1), T(0), T(0), T(0));
#ifdef BACKEND_IS_VULKAN
#else // OPEGL / WEBGL
tVec3 rotVecModifier = tVec3(1.0);
#endif
tVec3 rotationVector = tVec3(T(1));
tVec3 rotationCenter = tVec3(T(0));
// settings for the sensitivity
//////////////////////////////////////////////////////////////////
T tbScale = T(1); //base scale sensibility
T fpsRatio = T(1); //auto adjust by FPS (call idle with current FPS)
T qIdleSpeedRatio = T(1); //autoRotation factor to speedup/slowdown
const T qIdleReduction = T(.25); //autoRotation factor to speedup/slowdown
T minVal;
tVec3 offset;
bool tbActive = false; // trackbal activated via mouse
bool tbSecActive = false;
T rotOnX {1}, rotOnY = {1}, rotOnZ = {1};
bool isFlipPanX = false, isFlipPanY = false, isFlipDolly = false;
T width {640}, height {320}; // init to dummy values
};
/// vGizmo / virtualGizmo 2D class
///
/// @deprecated will removed on next version: use <b>vGizmo3D</b>
TEMPLATE_TYPENAME_T class virtualGizmoClass : public VGIZMO_BASE_CLASS {
public:
[[deprecated("Use virtualGizmo3D / vGizmo3D instead.")]] virtualGizmoClass() { }
//////////////////////////////////////////////////////////////////
void motion( T x, T y) { if(this->tbActive || this->tbSecActive ) VGIZMO_BASE_CLASS::motion(x,y); }
//////////////////////////////////////////////////////////////////
void update() { this->updateGizmo(); }
//////////////////////////////////////////////////////////////////
void applyTransform(tMat4 &model) {
model = translate(model, -this->rotationCenter);
VGIZMO_BASE_CLASS::applyRotation(model);
model = translate(model, this->rotationCenter);
}
//////////////////////////////////////////////////////////////////
tMat4 getTransform() {
tMat4 trans, invTrans, rotation;
rotation = mat4_cast(this->qtRot);
trans = translate(tMat4(T(1)),this->rotationCenter);
invTrans = translate(tMat4(T(1)),-this->rotationCenter);
return invTrans * rotation * trans;
}
// Set the speed for the virtualGizmo.
//////////////////////////////////////////////////////////////////
//void setGizmoScale( T scale) { scale = scale; }
// get the rotation quaternion
tQuat &refRotation() { return this->qtRot; }
};
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//
// virtualGizmo3DClass
// 3D trackball: rotation interface with pan and dolly operations
//
//--------------------------------------------------------------------
//--------------------------------------------------------------------
TEMPLATE_TYPENAME_T class virtualGizmo3DClass : public VGIZMO_BASE_CLASS {
using VGIZMO_BASE_CLASS::delta;
using VGIZMO_BASE_CLASS::qtRot;
public:
//////////////////////////////////////////////////////////////////
virtualGizmo3DClass() : dollyControlButton(evRightButton), panControlButton(evRightButton),
dollyControlModifiers(evShiftModifier), panControlModifiers(evControlModifier) { }
/// Start/End mouse capture: call on mouse BUTTON event or on state change
///@param[in] b enum vgButtons : button pressed/released (BUTTON ID)
///@param[in] m enum vgModifiers : current KEY modifier ID (if active) or evNoModifier = 0
///@param[in] pressed bool : mouse button pressed => true, released => false
///@param[in] x T : current X screen coord of mouse cursor
///@param[in] y T : current Y screen coord of mouse cursor
///@code
/// vg::vGizmo3D track;
///
/// // call on mouse BUTTON event or check BUTTON state change in main render loop
/// track.mouse((vgButtons) button, (vgModifiers) modifier, pressed, x, y);
///@endcode
void mouse( vgButtons button, vgModifiers mod, bool pressed, T x, T y)
{
VGIZMO_BASE_CLASS::mouse(button, mod, pressed, x, y);
if ( button == dollyControlButton && pressed && (dollyControlModifiers ? dollyControlModifiers & mod : dollyControlModifiers == mod) ) {
dollyActive = true;
this->activateMouse(x,y);
}
else if ( button == dollyControlButton && !pressed) {
this->deactivateMouse();
dollyActive = false;
}
if ( button == panControlButton && pressed && (panControlModifiers ? panControlModifiers & mod : panControlModifiers == mod) ) {
panActive = true;
this->activateMouse(x,y);
}
else if ( button == panControlButton && !pressed) {
this->deactivateMouse();
panActive = false;
}
//if(!panActive || !dollyActive)
}
// Call on wheel (only for Dolly/Zoom)
//--------------------------------------------------------------------------
void wheel( T x, T y, T z=T(0)) {
povPanDollyFactor = abs(z) * distScale * constDistScale;;
vecPanDolly.z += (y * dollyScale * wheelScale * (povPanDollyFactor>T(0) ? povPanDollyFactor : T(1)));
}
//////////////////////////////////////////////////////////////////
//void motion( int x, int y, T z=T(0)) { motion( T(x), T(y), z); }
void motion( T x, T y, T z=T(0)) {
povPanDollyFactor = abs(z) * distScale * constDistScale;
if( this->tbActive || this->tbSecActive) VGIZMO_BASE_CLASS::motion(x, y);
else if(panActive || dollyActive) VGIZMO_BASE_CLASS::motion(x, y);
}
//////////////////////////////////////////////////////////////////
void updatePan() {
const T pdFactor = (povPanDollyFactor>T(0) ? povPanDollyFactor : T(1));
vecPanDolly.x += this->panFlipX(delta.x) * panScale * pdFactor * constPanDollyScale.x;
vecPanDolly.y += this->panFlipY(delta.y) * panScale * pdFactor * constPanDollyScale.y;
}
//////////////////////////////////////////////////////////////////
void updateDolly() {
vecPanDolly.z += this->dollyFlip(delta.y) * dollyScale * constPanDollyScale.z * (povPanDollyFactor>T(0) ? povPanDollyFactor : T(1));
}
//////////////////////////////////////////////////////////////////
void update() {
if (this->tbActive || this->tbSecActive) VGIZMO_BASE_CLASS::updateGizmo();
if (dollyActive) updateDolly();
if (panActive) updatePan();
}
//////////////////////////////////////////////////////////////////
void applyTransform(tMat4 &m) {
m = translate(m, vecPanDolly);
m = translate(m, -this->rotationCenter);
VGIZMO_BASE_CLASS::applyRotation(m);
m = translate(m, this->rotationCenter);
}
//////////////////////////////////////////////////////////////////
tMat4 getTransform() {
tMat4 trans, invTrans, rotation;
tMat4 panDollyMat;
//create pan and dolly translations
panDollyMat = translate(tMat4(T(1)),vecPanDolly);
//create the virtualGizmo rotation
rotation = mat4_cast(qtRot);
//create the translations to move the center of rotation to the origin and back
trans = translate(tMat4(T(1)), this->rotationCenter);
invTrans = translate(tMat4(T(1)),-this->rotationCenter);
//concatenate all the tranforms
return panDollyMat * invTrans * rotation * trans;
}
/// Set mouse BUTTON and KEY modifier to control Dolly movements
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Pan and Dolly/Zoom: mouse button and key modifier
/// t.setDollyControl((vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) 0 /* evNoModifier */);
/// t.setPanControl((vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) GLFW_MOD_ALT | GLFW_MOD_SHIFT);
///@endcode
void setDollyControl( vgButtons b, vgModifiers m = evNoModifier) {
dollyControlButton = b;
dollyControlModifiers = m;
}
/// Set mouse BUTTON and KEY modifier to control Pan movements
///@param[in] b enum vgButtons : associate your / framework (GLFW/SDL/WIN32/etc)
/// mouse BUTTON ID
///@param[in] m enum vgModifiers : associate your / framework (GLFW/SDL/WIN32/etc)
/// KEY modifier ID : CTRL / ALT / SUPER / SHIFT
///@code
/// static vg::vGizmo3D track;
/// ...
/// // Pan and Dolly/Zoom: mouse button and key modifier
/// t.setDollyControl((vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) 0 /* evNoModifier */);
/// t.setPanControl((vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) GLFW_MOD_ALT | GLFW_MOD_SHIFT);
///@endcode
void setPanControl( vgButtons b, vgModifiers m = evNoModifier) {
panControlButton = b;
panControlModifiers = m;
}
int getPanControlButton() { return panControlButton; }
int getPanControlModifier() { return panControlModifiers; }
/// Set mouse wheel sensitivity (in %) for Dolly movements
/// @param[in] T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>setPanScale(T scale)</b>
[[deprecated("Use setWheelScale(T scale) instead.")]]
void setNormalizedWheelScale( T scale) { wheelScale = scale*constWheelScale; }
/// Get current mouse wheel sensitivity (in %) for Dolly movements
/// @retval T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>getPanScale()</b>
[[deprecated("Use getWheelScale() instead.")]]
T getNormalizedWheelScale() { return wheelScale/constWheelScale; }
/// Set mouse sensitivity (in %) for Dolly movements
/// @param[in] T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>setPanScale(T scale)</b>
[[deprecated("Use setDollyScale(T scale) instead.")]]
void setNormalizedDollyScale(T scale) { dollyScale = scale*constPanDollyScale.z; }
/// Get current mouse sensitivity (in %) for Dolly movements
/// @retval T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>getPanScale()>/b>
[[deprecated("Use getDollyScale() instead.")]]
T getNormalizedDollyScale() { return dollyScale/constPanDollyScale.z; }
/// Set mouse sensitivity (in %) for Pan movements
/// @param[in] T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>setPanScale(T scale)</b>
[[deprecated("Use setPanScale(T scale) instead.")]]
void setNormalizedPanScale(T scale) { panScale = scale*constPanDollyScale.x; }
/// Get current mouse sensitivity (in %) for Pan movements
/// @retval T scale : sensitivity ==> less < 100 < more
/// @deprecated will removed on next version: use <b>getPanScale()</b>
[[deprecated("Use getPanScale() instead.")]]
T getNormalizedPanScale() { return panScale/constPanDollyScale.x; }
/// Set mouse wheel sensitivity for Dolly movements
/// @param[in] T scale : sensitivity ==> less < 1.0 < more
void setWheelScale( T scale) { wheelScale = scale; }
/// Get current mouse sensitivity for Dolly movements
/// @retval T scale : sensitivity ==> less < 1.0 < more
T getWheelScale() { return wheelScale; }
/// Set mouse sensitivity for Dolly movements
/// @param[in] T scale : sensitivity ==> less < 1.0 < more
void setDollyScale( T scale) { dollyScale = scale; }
/// Get current mouse sensitivity for Dolly movements
/// @retval T scale : sensitivity ==> less < 1.0 < more
T getDollyScale() { return dollyScale; }
/// Set mouse sensitivity for Pan movements
/// @param[in] T scale : sensitivity ==> less < 1.0 < more
void setPanScale( T scale) { panScale = scale; }
/// Get current mouse sensitivity for Pan movements
/// @retval T scale : sensitivity ==> less < 1.0 < more
T getPanScale() { return panScale; }
void setDistScale( T scale) { distScale = scale; }
T getDistScale() { return distScale; }
// Set the Dolly to a specified distance.
//////////////////////////////////////////////////////////////////
void setDollyPosition(T pos) { vecPanDolly.z = pos; }
void setDollyPosition(const tVec3 &pos) { vecPanDolly.z = pos.z; }
// Set the Dolly to a specified distance.
//////////////////////////////////////////////////////////////////
void setPanPosition(const tVec3 &pos) { vecPanDolly.x = pos.x; vecPanDolly.y = pos.y;}
// Get dolly pos... use as Zoom factor
//////////////////////////////////////////////////////////////////
tVec3 getDollyPosition() const { return tVec3 {0, 0, vecPanDolly.z}; }
// Get Pan pos... use as Zoom factor
//////////////////////////////////////////////////////////////////
tVec3 getPanPosition() const { return tVec3 {vecPanDolly.x, vecPanDolly.y, 0}; }
// Get Pan (xy) & Dolly (z) position
//////////////////////////////////////////////////////////////////
tVec3 getPosition() { return vecPanDolly; }
tVec3 &refPosition() { return vecPanDolly; }
void setPosition(const tVec3 &pos) { vecPanDolly = pos; }
bool isDollyActive() { return dollyActive; }
bool isPanActive() { return panActive; }
void motionImmediateMode( T x, T y, T dx, T dy, vgModifiers mod) {
this->tbActive = true;
this->delta = tVec2(dx,dy);
this->pos = tVec2(x, y);
if (dollyControlModifiers & mod) dollyActive = true;
else if (panControlModifiers & mod) panActive = true;
update();
}
void viewportSize(T w, T h) {
VGIZMO_BASE_CLASS::viewportSize(w, h);
const T y = T(10) / h;
constPanDollyScale = tVec3(T(10) / h, y, y);
}
private:
// UI commands that this virtualGizmo responds to (defaults to left mouse button with no modifier key)
vgButtons dollyControlButton, panControlButton;
vgModifiers dollyControlModifiers, panControlModifiers;
// Variable used to determine if the manipulator is presently tracking the mouse
bool dollyActive = false;
bool panActive = false;
tVec3 vecPanDolly = tVec3(T(0));
// dummy starting vaalue (binding to viewport size call)
T constWheelScale = T(20); //dolly multiply for wheel step
tVec3 constPanDollyScale = tVec3 (.05); //pan scale
const T constDistScale = T( .01); //speed by distance sensibility
T dollyScale = T(1.0); //dolly scale
T panScale = T(1.0); //pan scale
T wheelScale = T(1.0); //dolly multiply for wheel step
T distScale = T(1.0); //speed by distance sensibility
T povPanDollyFactor = T(0); // internal use, maintain memory of current distance (pan/zoom speed by distance)
};
#ifdef VGM_USES_TEMPLATE
#ifdef VGM_USES_DOUBLE_PRECISION
using vGizmo = virtualGizmoClass<double>;
using vGizmo3D = virtualGizmo3DClass<double>;
#else
using vGizmo = virtualGizmoClass<float>;
using vGizmo3D = virtualGizmo3DClass<float>;
#endif
#ifndef IMGUIZMO_USE_ONLY_ROT
using vImGuIZMO = virtualGizmo3DClass<float>;
#else
using vImGuIZMO = virtualGizmoClass<float>;
#endif
#else
#ifndef IMGUIZMO_USE_ONLY_ROT
using vImGuIZMO = virtualGizmo3DClass;
#else
using vImGuIZMO = virtualGizmoClass;
#endif
using vGizmo = virtualGizmoClass;
using vGizmo3D = virtualGizmo3DClass;
#endif
} // end namespace vg::
#undef T // if used T as #define, undef it
#undef VGIZMO_H_FILE