Integrated from CeeSol Perforce, changelist 203

AppFwk tests.
Added rotation to locator.
Caf::FrameAnimationControl : Set current frame to 0 if a framecount
change makes the current frame invalid
This commit is contained in:
sigurdp
2013-11-01 16:54:24 +01:00
parent bbebebadd5
commit df5f1f85af
61 changed files with 31246 additions and 33 deletions

View File

@@ -159,6 +159,7 @@ LocatorPanWalkRotate::LocatorPanWalkRotate(Camera* camera)
: m_camera(camera),
m_operation(PAN),
m_pos(0, 0, 0),
m_rotQuat(0, 0, 0, 1),
m_lastPosX(0),
m_lastPosY(0)
{
@@ -202,6 +203,24 @@ Vec3d LocatorPanWalkRotate::position() const
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::setOrientation(const Mat3d& m)
{
m_rotQuat = Quatd::fromRotationMatrix(Mat4d(m));
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Mat3d LocatorPanWalkRotate::orientation() const
{
return m_rotQuat.toMatrix3();
}
//--------------------------------------------------------------------------------------------------
/// The window coordinates are in OpenGL style coordinates, which means a right handed
/// coordinate system with the origin in the lower left corner of the window.
@@ -221,31 +240,39 @@ bool LocatorPanWalkRotate::update(int x, int y)
{
CVF_ASSERT(m_camera.notNull());
if (x == m_lastPosX && y == m_lastPosY) return false;
if (x == m_lastPosX && y == m_lastPosY)
{
return false;
}
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
if (vpPixSizeX <= 0 || vpPixSizeY <= 0) return false;
// Need a non-zero viewport
if (m_camera->viewport()->width() <= 0 ||
m_camera->viewport()->height() <= 0)
{
return false;
}
// Normalized movement in screen plane
const double tx = (x - m_lastPosX)/vpPixSizeX;
const double ty = (y - m_lastPosY)/vpPixSizeY;
Vec3d oldPos = m_pos;
Quatd oldRotQuat = m_rotQuat;
if (m_operation == PAN)
{
updatePan(tx, ty);
updatePan(x, y);
}
else if (m_operation == WALK)
{
updateWalk(ty);
updateWalk(y);
}
else if (m_operation == ROTATE)
{
updateRotation(x, y);
}
m_lastPosX = x;
m_lastPosY = y;
if (m_pos == oldPos)
if (m_pos == oldPos && m_rotQuat == oldRotQuat)
{
return false;
}
@@ -259,10 +286,17 @@ bool LocatorPanWalkRotate::update(int x, int y)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updatePan(double tx, double ty)
void LocatorPanWalkRotate::updatePan(int oglWinCoordX, int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
// Normalized movement in screen plane [0, 1]
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeX > 0 && vpPixSizeY > 0);
const double tx = (oglWinCoordX - m_lastPosX)/vpPixSizeX;
const double ty = (oglWinCoordY - m_lastPosY)/vpPixSizeY;
// Viewport size in world coordinates
const double aspect = m_camera->aspectRatio();
const double vpWorldSizeY = m_camera->frontPlaneFrustumHeight();
@@ -303,10 +337,15 @@ void LocatorPanWalkRotate::updatePan(double tx, double ty)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updateWalk(double ty)
void LocatorPanWalkRotate::updateWalk(int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
// Normalized movement in screen plane [0, 1]
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeY > 0);
const double ty = (oglWinCoordY - m_lastPosY)/vpPixSizeY;
const double vpWorldSizeY = m_camera->frontPlaneFrustumHeight();
const Vec3d camDir = m_camera->direction();
@@ -337,5 +376,127 @@ void LocatorPanWalkRotate::updateWalk(double ty)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updateRotation(int oglWinCoordX, int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeX > 0 && vpPixSizeY > 0);
// Scale the new/last positions to the range [-1.0, 1.0]
const double newPosX = 2.0*(oglWinCoordX/vpPixSizeX) - 1.0;
const double newPosY = 2.0*((vpPixSizeY - oglWinCoordY)/vpPixSizeY) - 1.0;
const double oldPosX = 2.0*(m_lastPosX/vpPixSizeX) - 1.0;
const double oldPosY = 2.0*((vpPixSizeY - m_lastPosY)/vpPixSizeY) - 1.0;
// For now, use hard-coded value for trackball radius and sensitivity
// Sensitivity could be exposed directly, but trackball rotation needs more consideration.
// An idea would be for the user to be able to set an approximate size of the locator's visual representation in world coords,
// and then we could estimate its current size relative to viewport, and then use that as trackball radius.
// See trackballRotation() for some more info on trackballRadius (we've always used 0.8 as an approximation)
const double trackballRadius = 0.8;
const double rotateSensitivity = 1.0;
Mat4d viewMat = m_camera->viewMatrix();
Quatd incrementalRotationQuat = trackballRotation(oldPosX, -oldPosY, newPosX, -newPosY, viewMat, trackballRadius, rotateSensitivity);
// Update rotation quaternion
Mat4d incRotationMatrix = incrementalRotationQuat.toMatrix4();
incRotationMatrix.translatePostMultiply(-m_pos);
incRotationMatrix.translatePreMultiply(m_pos);
Mat4d rotMat = m_rotQuat.toMatrix4();
rotMat = incRotationMatrix*rotMat;
m_rotQuat = Quatd::fromRotationMatrix(rotMat);
}
//--------------------------------------------------------------------------------------------------
/// Compute quaternion rotation
///
/// \param oldPosX x coordinate of the last position of the mouse, in the range [-1.0, 1.0]
/// \param oldPosY y coordinate of the last position of the mouse, in the range [-1.0, 1.0]
/// \param newPosX x coordinate of current position of the mouse, in the range [-1.0, 1.0]
/// \param newPosY y coordinate of current position of the mouse, in the range [-1.0, 1.0]
/// \param currViewMatrix Current transformation matrix. The inverse is used when calculating the rotation
/// \param sensitivityFactor Mouse sensitivity factor
///
/// Simulate a track-ball. Project the points onto the virtual trackball, then figure out the axis
/// of rotation. This is a deformed trackball-- is a trackball in the center, but is deformed into a
/// hyperbolic sheet of rotation away from the center.
//--------------------------------------------------------------------------------------------------
Quatd LocatorPanWalkRotate::trackballRotation(double oldPosX, double oldPosY, double newPosX, double newPosY, const Mat4d& currViewMatrix, double trackballRadius, double sensitivityFactor)
{
// This particular function was chosen after trying out several variations.
// Implemented by Gavin Bell, lots of ideas from Thant Tessman and the August '88
// issue of Siggraph's "Computer Graphics," pp. 121-129.
// This size should really be based on the distance from the center of rotation to the point on
// the object underneath the mouse. That point would then track the mouse as closely as possible.
//const double TRACKBALL_RADIUS = 0.8f;
// Clamp to valid range
oldPosX = Math::clamp(oldPosX, -1.0, 1.0);
oldPosY = Math::clamp(oldPosY, -1.0, 1.0);
newPosX = Math::clamp(newPosX, -1.0, 1.0);
newPosY = Math::clamp(newPosY, -1.0, 1.0);
// First, figure out z-coordinates for projection of P1 and P2 to deformed sphere
Vec3d p1 = projectToSphere(trackballRadius, oldPosX, oldPosY);
Vec3d p2 = projectToSphere(trackballRadius, newPosX, newPosY);
// Axis of rotation is the cross product of P1 and P2
Vec3d a = p1 ^ p2;
// Figure out how much to rotate around that axis.
Vec3d d = p1 - p2;
double t = d.length()/(2.0*trackballRadius);
// Avoid problems with out-of-control values...
t = Math::clamp(t, -1.0, 1.0);
double phi = 2.0*Math::asin(t);
// Scale by sensitivity factor
phi *= sensitivityFactor;
// Use inverted matrix to find rotation axis
Mat4d invMatr = currViewMatrix.getInverted();
a.transformVector(invMatr);
// Get quaternion to be returned by pointer
Quatd quat = Quatd::fromAxisAngle(a, phi);
return quat;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Vec3d LocatorPanWalkRotate::projectToSphere(double radius, double posX, double posY)
{
double d = Math::sqrt(posX*posX + posY*posY);
if (d < radius*SQRT1_2_D)
{
// Inside sphere
double projectedZ = Math::sqrt(radius*radius - d*d);
return Vec3d(posX, posY, projectedZ);
}
else
{
// On hyperbola
double t = radius/SQRT2_D;
double projectedZ = t*t/d;
return Vec3d(posX, posY, projectedZ);
}
}
} // namespace cvf

View File

@@ -38,6 +38,7 @@
#pragma once
#include "cvfPlane.h"
#include "cvfQuat.h"
namespace cvf {
@@ -97,8 +98,8 @@ public:
enum Operation
{
PAN,
WALK
//ROTATE // TODO
WALK,
ROTATE
};
public:
@@ -106,20 +107,29 @@ public:
~LocatorPanWalkRotate();
void setOperation(Operation op);
void setPosition(const Vec3d& position);
virtual Vec3d position() const;
void setOrientation(const Mat3d& m);
Mat3d orientation() const;
virtual void start(int x, int y);
virtual bool update(int x, int y);
private:
void updatePan(double tx, double ty);
void updateWalk(double ty);
void updatePan(int oglWinCoordX, int oglWinCoordY);
void updateWalk(int oglWinCoordY);
void updateRotation(int oglWinCoordX, int oglWinCoordY);
static Quatd trackballRotation(double oldPosX, double oldPosY, double newPosX, double newPosY, const Mat4d& currViewMatrix, double trackballRadius, double sensitivityFactor);
static Vec3d projectToSphere(double radius, double posX, double posY);
private:
ref<Camera> m_camera;
Operation m_operation; // Default operation is PAN
Vec3d m_pos;
int m_lastPosX;
Quatd m_rotQuat;
int m_lastPosX; // Last position, window coords, origin lower left (OpenGL style)
int m_lastPosY;
};

View File

@@ -40,7 +40,6 @@
#include "cvfCamera.h"
#include "cvfViewport.h"
#include <cmath>
#include <cstdlib>
namespace cvf {
@@ -296,7 +295,7 @@ bool ManipulatorTrackball::zoom(int posX, int posY)
Camera::ProjectionType projType = m_camera->projection();
if (projType == Camera::PERSPECTIVE)
{
double fovY = 2*atan((newFrustumHeight/2)/nearPlane);
double fovY = 2*Math::atan((newFrustumHeight/2)/nearPlane);
if (fovY > 0)
{
m_camera->setProjectionAsPerspective(Math::toDegrees(fovY), nearPlane, farPlane);
@@ -407,7 +406,7 @@ Quatd ManipulatorTrackball::trackballRotation(double oldPosX, double oldPosY, do
// Avoid problems with out-of-control values...
t = Math::clamp(t, -1.0, 1.0);
double phi = 2.0*asin(t);
double phi = 2.0*Math::asin(t);
// Scale by sensitivity factor
phi *= sensitivityFactor;
@@ -437,12 +436,12 @@ Quatd ManipulatorTrackball::trackballRotation(double oldPosX, double oldPosY, do
//--------------------------------------------------------------------------------------------------
Vec3d ManipulatorTrackball::projectToSphere(double radius, double posX, double posY)
{
double d = sqrt(posX*posX + posY*posY);
double d = Math::sqrt(posX*posX + posY*posY);
if (d < radius*SQRT1_2_D)
{
// Inside sphere
double projectedZ = sqrt(radius*radius - d*d);
double projectedZ = Math::sqrt(radius*radius - d*d);
return Vec3d(posX, posY, projectedZ);
}

View File

@@ -231,9 +231,20 @@ void Manipulators::onPaintEvent(PostEventAction* postEventAction)
m_camera->applyOpenGL();
GeometryBuilderDrawableGeo builder;
GeometryUtils::createBox(Vec3f(m_activeLocator->position()), 0.2f, 0.2f, 0.2f, &builder);
GeometryUtils::createBox(Vec3f::ZERO, 0.2f, 0.2f, 0.2f, &builder);
ref<DrawableGeo> boxGeo = builder.drawableGeo();
Mat4d transform;
if (dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p()))
{
LocatorPanWalkRotate* loc = dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p());
transform.setFromMatrix3(loc->orientation());
}
transform.translatePreMultiply(m_activeLocator->position());
boxGeo->transform(transform);
boxGeo->computeNormals();
RenderStateLighting_FF lighting;
@@ -262,15 +273,19 @@ void Manipulators::onMousePressEvent(MouseButton buttonPressed, MouseEvent* mous
if (dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p()))
{
LocatorPanWalkRotate* loc = dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p());
if (mouseEvent->buttons() == MiddleButton ||
mouseEvent->buttons() == (LeftButton | RightButton))
{
loc->setOperation(LocatorPanWalkRotate::WALK);
}
else
if (mouseEvent->buttons() == LeftButton)
{
loc->setOperation(LocatorPanWalkRotate::PAN);
}
else if (mouseEvent->buttons() == RightButton)
{
loc->setOperation(LocatorPanWalkRotate::ROTATE);
}
else if (mouseEvent->buttons() == MiddleButton ||
mouseEvent->buttons() == (LeftButton | RightButton))
{
loc->setOperation(LocatorPanWalkRotate::WALK);
}
}
m_activeLocator->start(x, y);
@@ -293,9 +308,10 @@ void Manipulators::onMouseMoveEvent(MouseEvent* mouseEvent)
{
int x = mouseEvent->x();
int y = mouseEvent->y();
m_activeLocator->update(x, y);
mouseEvent->setRequestedAction(REDRAW);
if (m_activeLocator->update(x, y))
{
mouseEvent->setRequestedAction(REDRAW);
}
return;
}