1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This file is part of Eigen, a lightweight C++ template library
2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// for linear algebra.
3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This Source Code Form is subject to the terms of the Mozilla
7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Public License v. 2.0. If a copy of the MPL was not distributed
8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "quaternion_demo.h"
11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "icosphere.h"
12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <Eigen/Geometry>
14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <Eigen/QR>
15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <Eigen/LU>
16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <iostream>
18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QEvent>
19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QMouseEvent>
20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QInputDialog>
21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QGridLayout>
22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QButtonGroup>
23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QRadioButton>
24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QDockWidget>
25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QPushButton>
26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <QGroupBox>
27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathusing namespace Eigen;
29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathclass FancySpheres
31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
32c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  public:
33c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
34c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
35c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    FancySpheres()
36c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
37c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      const int levels = 4;
38c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      const float scale = 0.33;
39c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      float radius = 100;
40c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      std::vector<int> parents;
41c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
42c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // leval 0
43c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      mCenters.push_back(Vector3f::Zero());
44c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      parents.push_back(-1);
45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      mRadii.push_back(radius);
46c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // generate level 1 using icosphere vertices
48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      radius *= 0.45;
49c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
50c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        float dist = mRadii[0]*0.9;
51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        for (int i=0; i<12; ++i)
52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          mCenters.push_back(mIcoSphere.vertices()[i] * dist);
54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          mRadii.push_back(radius);
55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          parents.push_back(0);
56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
57c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      static const float angles [10] = {
60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        0, 0,
61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        M_PI, 0.*M_PI,
62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        M_PI, 0.5*M_PI,
63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        M_PI, 1.*M_PI,
64c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        M_PI, 1.5*M_PI
65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      };
66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // generate other levels
68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      int start = 1;
69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for (int l=1; l<levels; l++)
70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        radius *= scale;
72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        int end = mCenters.size();
73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        for (int i=start; i<end; ++i)
74c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Vector3f c = mCenters[i];
76c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Vector3f ax0 = (c - mCenters[parents[i]]).normalized();
77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Vector3f ax1 = ax0.unitOrthogonal();
78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Quaternionf q;
79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          q.setFromTwoVectors(Vector3f::UnitZ(), ax0);
80c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Affine3f t = Translation3f(c) * q * Scaling(mRadii[i]+radius);
81c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          for (int j=0; j<5; ++j)
82c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
83c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            Vector3f newC = c + ( (AngleAxisf(angles[j*2+1], ax0)
84c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath                                * AngleAxisf(angles[j*2+0] * (l==1 ? 0.35 : 0.5), ax1)) * ax0)
85c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath                                * (mRadii[i] + radius*0.8);
86c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            mCenters.push_back(newC);
87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            mRadii.push_back(radius);
88c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            parents.push_back(i);
89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        start = end;
92c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
94c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
95c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    void draw()
96c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
97c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      int end = mCenters.size();
98c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      glEnable(GL_NORMALIZE);
99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for (int i=0; i<end; ++i)
100c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Affine3f t = Translation3f(mCenters[i]) * Scaling(mRadii[i]);
102c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        gpu.pushMatrix(GL_MODELVIEW);
103c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        gpu.multMatrix(t.matrix(),GL_MODELVIEW);
104c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mIcoSphere.draw(2);
105c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        gpu.popMatrix(GL_MODELVIEW);
106c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
107c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      glDisable(GL_NORMALIZE);
108c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
109c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  protected:
110c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    std::vector<Vector3f> mCenters;
111c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    std::vector<float> mRadii;
112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    IcoSphere mIcoSphere;
113c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath};
114c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
115c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// generic linear interpolation method
117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename T> T lerp(float t, const T& a, const T& b)
118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return a*(1-t) + b*t;
120c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
121c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// quaternion slerp
123c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
124c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{ return a.slerp(t,b); }
125c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
126c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// linear interpolation of a frame using the type OrientationType
127c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// to perform the interpolation of the orientations
128c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename OrientationType>
129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathinline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b)
130c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
131c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return Frame(lerp(alpha,a.position,b.position),
132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath               Quaternionf(lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation))));
133c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
134c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename _Scalar> class EulerAngles
136c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
137c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathpublic:
138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  enum { Dim = 3 };
139c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef _Scalar Scalar;
140c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef Matrix<Scalar,3,3> Matrix3;
141c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef Matrix<Scalar,3,1> Vector3;
142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef Quaternion<Scalar> QuaternionType;
143c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
144c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathprotected:
145c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
146c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Vector3 m_angles;
147c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
148c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathpublic:
149c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
150c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  EulerAngles() {}
151c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  inline EulerAngles(Scalar a0, Scalar a1, Scalar a2) : m_angles(a0, a1, a2) {}
152c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  inline EulerAngles(const QuaternionType& q) { *this = q; }
153c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
154c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  const Vector3& coeffs() const { return m_angles; }
155c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Vector3& coeffs() { return m_angles; }
156c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
157c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  EulerAngles& operator=(const QuaternionType& q)
158c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
159c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    Matrix3 m = q.toRotationMatrix();
160c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    return *this = m;
161c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
162c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
163c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  EulerAngles& operator=(const Matrix3& m)
164c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
165c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // mat =  cy*cz          -cy*sz           sy
166c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    //        cz*sx*sy+cx*sz  cx*cz-sx*sy*sz -cy*sx
167c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    //       -cx*cz*sy+sx*sz  cz*sx+cx*sy*sz  cx*cy
168c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    m_angles.coeffRef(1) = std::asin(m.coeff(0,2));
169c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    m_angles.coeffRef(0) = std::atan2(-m.coeff(1,2),m.coeff(2,2));
170c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    m_angles.coeffRef(2) = std::atan2(-m.coeff(0,1),m.coeff(0,0));
171c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    return *this;
172c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
173c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
174c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Matrix3 toRotationMatrix(void) const
175c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
176c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    Vector3 c = m_angles.array().cos();
177c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    Vector3 s = m_angles.array().sin();
178c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    Matrix3 res;
179c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    res <<  c.y()*c.z(),                    -c.y()*s.z(),                   s.y(),
180c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            c.z()*s.x()*s.y()+c.x()*s.z(),  c.x()*c.z()-s.x()*s.y()*s.z(),  -c.y()*s.x(),
181c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            -c.x()*c.z()*s.y()+s.x()*s.z(), c.z()*s.x()+c.x()*s.y()*s.z(),  c.x()*c.y();
182c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    return res;
183c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
184c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
185c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  operator QuaternionType() { return QuaternionType(toRotationMatrix()); }
186c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath};
187c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
188c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Euler angles slerp
189c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<> EulerAngles<float> lerp(float t, const EulerAngles<float>& a, const EulerAngles<float>& b)
190c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
191c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  EulerAngles<float> res;
192c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  res.coeffs() = lerp(t, a.coeffs(), b.coeffs());
193c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return res;
194c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
195c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
196c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
197c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathRenderingWidget::RenderingWidget()
198c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
199c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mAnimate = false;
200c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCurrentTrackingMode = TM_NO_TRACK;
201c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mNavMode = NavTurnAround;
202c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mLerpMode = LerpQuaternion;
203c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mRotationMode = RotationStable;
204c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mTrackball.setCamera(&mCamera);
205c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
206c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // required to capture key press events
207c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  setFocusPolicy(Qt::ClickFocus);
208c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
209c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
210c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::grabFrame(void)
211c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
212c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // ask user for a time
213c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    bool ok = false;
214c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    double t = 0;
215c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if (!m_timeline.empty())
216c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      t = (--m_timeline.end())->first + 1.;
217c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    t = QInputDialog::getDouble(this, "Eigen's RenderingWidget", "time value: ",
218c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      t, 0, 1e3, 1, &ok);
219c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if (ok)
220c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
221c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      Frame aux;
222c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      aux.orientation = mCamera.viewMatrix().linear();
223c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      aux.position = mCamera.viewMatrix().translation();
224c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      m_timeline[t] = aux;
225c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
226c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
227c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
228c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::drawScene()
229c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
230c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  static FancySpheres sFancySpheres;
231c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  float length = 50;
232c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitX(), Color(1,0,0,1));
233c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitY(), Color(0,1,0,1));
234c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1));
235c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
236c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // draw the fractal object
237c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  float sqrt3 = internal::sqrt(3.);
238c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data());
239c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data());
240c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data());
241c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT0, GL_POSITION, Vector4f(-sqrt3,-sqrt3,sqrt3,0).data());
242c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
243c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT1, GL_AMBIENT, Vector4f(0,0,0,1).data());
244c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT1, GL_DIFFUSE, Vector4f(1,0.5,0.5,1).data());
245c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT1, GL_SPECULAR, Vector4f(1,1,1,1).data());
246c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightfv(GL_LIGHT1, GL_POSITION, Vector4f(-sqrt3,sqrt3,-sqrt3,0).data());
247c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
248c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Vector4f(0.7, 0.7, 0.7, 1).data());
249c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Vector4f(0.8, 0.75, 0.6, 1).data());
250c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Vector4f(1, 1, 1, 1).data());
251c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
252c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
253c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnable(GL_LIGHTING);
254c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnable(GL_LIGHT0);
255c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnable(GL_LIGHT1);
256c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
257c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  sFancySpheres.draw();
258c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
259c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glNormalPointer(GL_FLOAT, 0, mNormals[0].data());
260c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnableClientState(GL_VERTEX_ARRAY);
261c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnableClientState(GL_NORMAL_ARRAY);
262c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDrawArrays(GL_TRIANGLES, 0, mVertices.size());
263c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisableClientState(GL_VERTEX_ARRAY);
264c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisableClientState(GL_NORMAL_ARRAY);
265c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
266c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_LIGHTING);
267c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
268c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
269c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::animate()
270c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
271c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_alpha += double(m_timer.interval()) * 1e-3;
272c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
273c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  TimeLine::const_iterator hi = m_timeline.upper_bound(m_alpha);
274c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  TimeLine::const_iterator lo = hi;
275c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  --lo;
276c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
277c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Frame currentFrame;
278c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
279c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if(hi==m_timeline.end())
280c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
281c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // end
282c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    currentFrame = lo->second;
283c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    stopAnimation();
284c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
285c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  else if(hi==m_timeline.begin())
286c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
287c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // start
288c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    currentFrame = hi->second;
289c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
290c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  else
291c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
292c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    float s = (m_alpha - lo->first)/(hi->first - lo->first);
293c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if (mLerpMode==LerpEulerAngles)
294c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      currentFrame = ::lerpFrame<EulerAngles<float> >(s, lo->second, hi->second);
295c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    else if (mLerpMode==LerpQuaternion)
296c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
297c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    else
298c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
299c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      std::cerr << "Invalid rotation interpolation mode (abort)\n";
300c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      exit(2);
301c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
302c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    currentFrame.orientation.coeffs().normalize();
303c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
304c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
305c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  currentFrame.orientation = currentFrame.orientation.inverse();
306c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  currentFrame.position = - (currentFrame.orientation * currentFrame.position);
307c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setFrame(currentFrame);
308c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
309c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  updateGL();
310c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
311c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
312c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::keyPressEvent(QKeyEvent * e)
313c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
314c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    switch(e->key())
315c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
316c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_Up:
317c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCamera.zoom(2);
318c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
319c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_Down:
320c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCamera.zoom(-2);
321c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
322c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // add a frame
323c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_G:
324c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        grabFrame();
325c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
326c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // clear the time line
327c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_C:
328c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        m_timeline.clear();
329c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
330c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // move the camera to initial pos
331c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_R:
332c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        resetCamera();
333c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
334c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      // start/stop the animation
335c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      case Qt::Key_A:
336c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if (mAnimate)
337c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
338c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          stopAnimation();
339c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
340c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        else
341c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
342c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          m_alpha = 0;
343c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
344c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          m_timer.start(1000/30);
345c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          mAnimate = true;
346c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
347c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
348c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      default:
349c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        break;
350c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
351c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
352c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    updateGL();
353c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
354c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
355c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::stopAnimation()
356c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
357c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
358c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timer.stop();
359c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mAnimate = false;
360c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_alpha = 0;
361c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
362c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
363c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::mousePressEvent(QMouseEvent* e)
364c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
365c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
366c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  bool fly = (mNavMode==NavFly) || (e->modifiers()&Qt::ControlModifier);
367c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  switch(e->button())
368c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
369c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    case Qt::LeftButton:
370c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(fly)
371c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
372c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCurrentTrackingMode = TM_LOCAL_ROTATE;
373c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mTrackball.start(Trackball::Local);
374c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
375c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      else
376c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
377c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCurrentTrackingMode = TM_ROTATE_AROUND;
378c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mTrackball.start(Trackball::Around);
379c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
380c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      mTrackball.track(mMouseCoords);
381c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      break;
382c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    case Qt::MidButton:
383c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(fly)
384c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCurrentTrackingMode = TM_FLY_Z;
385c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      else
386c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCurrentTrackingMode = TM_ZOOM;
387c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      break;
388c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    case Qt::RightButton:
389c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        mCurrentTrackingMode = TM_FLY_PAN;
390c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      break;
391c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    default:
392c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      break;
393c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
394c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
395c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::mouseReleaseEvent(QMouseEvent*)
396c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
397c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mCurrentTrackingMode = TM_NO_TRACK;
398c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    updateGL();
399c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
400c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
401c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::mouseMoveEvent(QMouseEvent* e)
402c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
403c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // tracking
404c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(mCurrentTrackingMode != TM_NO_TRACK)
405c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
406c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        float dx =   float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
407c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
408c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
409c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        // speedup the transformations
410c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if(e->modifiers() & Qt::ShiftModifier)
411c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
412c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          dx *= 10.;
413c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          dy *= 10.;
414c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
415c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
416c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        switch(mCurrentTrackingMode)
417c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
418c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          case TM_ROTATE_AROUND:
419c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          case TM_LOCAL_ROTATE:
420c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            if (mRotationMode==RotationStable)
421c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            {
422c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              // use the stable trackball implementation mapping
423c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              // the 2D coordinates to 3D points on a sphere.
424c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
425c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            }
426c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            else
427c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            {
428c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              // standard approach mapping the x and y displacements as rotations
429c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              // around the camera's X and Y axes.
430c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              Quaternionf q = AngleAxisf( dx*M_PI, Vector3f::UnitY())
431c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath                            * AngleAxisf(-dy*M_PI, Vector3f::UnitX());
432c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              if (mCurrentTrackingMode==TM_LOCAL_ROTATE)
433c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath                mCamera.localRotate(q);
434c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath              else
435c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath                mCamera.rotateAroundTarget(q);
436c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            }
437c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            break;
438c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          case TM_ZOOM :
439c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            mCamera.zoom(dy*100);
440c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            break;
441c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          case TM_FLY_Z :
442c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            mCamera.localTranslate(Vector3f(0, 0, -dy*200));
443c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            break;
444c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          case TM_FLY_PAN :
445c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            mCamera.localTranslate(Vector3f(dx*200, dy*200, 0));
446c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            break;
447c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          default:
448c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            break;
449c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
450c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
451c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        updateGL();
452c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
453c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
454c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
455c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
456c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
457c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::paintGL()
458c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
459c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glEnable(GL_DEPTH_TEST);
460c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_CULL_FACE);
461c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
462c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_COLOR_MATERIAL);
463c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_BLEND);
464c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_ALPHA_TEST);
465c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_TEXTURE_1D);
466c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_TEXTURE_2D);
467c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDisable(GL_TEXTURE_3D);
468c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
469c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // Clear buffers
470c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
471c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
472c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.activateGL();
473c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
474c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  drawScene();
475c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
476c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
477c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::initializeGL()
478c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
479c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glClearColor(1., 1., 1., 0.);
480c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
481c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glDepthMask(GL_TRUE);
482c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
483c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
484c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setPosition(Vector3f(-200, -200, -200));
485c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setTarget(Vector3f(0, 0, 0));
486c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mInitFrame.orientation = mCamera.orientation().inverse();
487c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mInitFrame.position = mCamera.viewMatrix().translation();
488c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
489c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
490c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::resizeGL(int width, int height)
491c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
492c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mCamera.setViewport(width,height);
493c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
494c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
495c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::setNavMode(int m)
496c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
497c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mNavMode = NavMode(m);
498c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
499c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
500c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::setLerpMode(int m)
501c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
502c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mLerpMode = LerpMode(m);
503c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
504c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
505c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::setRotationMode(int m)
506c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
507c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mRotationMode = RotationMode(m);
508c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
509c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
510c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid RenderingWidget::resetCamera()
511c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
512c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if (mAnimate)
513c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    stopAnimation();
514c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timeline.clear();
515c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Frame aux0 = mCamera.frame();
516c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux0.orientation = aux0.orientation.inverse();
517c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux0.position = mCamera.viewMatrix().translation();
518c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timeline[0] = aux0;
519c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
520c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Vector3f currentTarget = mCamera.target();
521c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setTarget(Vector3f::Zero());
522c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
523c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // compute the rotation duration to move the camera to the target
524c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Frame aux1 = mCamera.frame();
525c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.orientation = aux1.orientation.inverse();
526c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.position = mCamera.viewMatrix().translation();
527c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  float duration = aux0.orientation.angularDistance(aux1.orientation) * 0.9;
528c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if (duration<0.1) duration = 0.1;
529c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
530c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // put the camera at that time step:
531c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1 = aux0.lerp(duration/2,mInitFrame);
532c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // and make it look at the target again
533c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.orientation = aux1.orientation.inverse();
534c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.position = - (aux1.orientation * aux1.position);
535c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setFrame(aux1);
536c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mCamera.setTarget(Vector3f::Zero());
537c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
538c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  // add this camera keyframe
539c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.orientation = aux1.orientation.inverse();
540c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  aux1.position = mCamera.viewMatrix().translation();
541c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timeline[duration] = aux1;
542c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
543c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timeline[2] = mInitFrame;
544c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_alpha = 0;
545c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  animate();
546c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
547c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  m_timer.start(1000/30);
548c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mAnimate = true;
549c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
550c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
551c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathQWidget* RenderingWidget::createNavigationControlWidget()
552c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
553c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  QWidget* panel = new QWidget();
554c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  QVBoxLayout* layout = new QVBoxLayout();
555c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
556c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
557c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QPushButton* but = new QPushButton("reset");
558c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("move the camera to initial position (with animation)");
559c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    layout->addWidget(but);
560c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    connect(but, SIGNAL(clicked()), this, SLOT(resetCamera()));
561c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
562c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
563c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // navigation mode
564c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QGroupBox* box = new QGroupBox("navigation mode");
565c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QVBoxLayout* boxLayout = new QVBoxLayout;
566c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QButtonGroup* group = new QButtonGroup(panel);
567c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QRadioButton* but;
568c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("turn around");
569c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("look around an object");
570c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, NavTurnAround);
571c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
572c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("fly");
573c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("free navigation like a spaceship\n(this mode can also be enabled pressing the \"shift\" key)");
574c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, NavFly);
575c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
576c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->button(mNavMode)->setChecked(true);
577c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int)));
578c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    box->setLayout(boxLayout);
579c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    layout->addWidget(box);
580c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
581c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
582c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // track ball, rotation mode
583c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QGroupBox* box = new QGroupBox("rotation mode");
584c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QVBoxLayout* boxLayout = new QVBoxLayout;
585c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QButtonGroup* group = new QButtonGroup(panel);
586c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QRadioButton* but;
587c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("stable trackball");
588c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, RotationStable);
589c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
590c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("use the stable trackball implementation mapping\nthe 2D coordinates to 3D points on a sphere");
591c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("standard rotation");
592c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, RotationStandard);
593c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
594c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("standard approach mapping the x and y displacements\nas rotations around the camera's X and Y axes");
595c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->button(mRotationMode)->setChecked(true);
596c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int)));
597c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    box->setLayout(boxLayout);
598c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    layout->addWidget(box);
599c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
600c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
601c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    // interpolation mode
602c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QGroupBox* box = new QGroupBox("spherical interpolation");
603c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QVBoxLayout* boxLayout = new QVBoxLayout;
604c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QButtonGroup* group = new QButtonGroup(panel);
605c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    QRadioButton* but;
606c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("quaternion slerp");
607c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, LerpQuaternion);
608c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
609c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("use quaternion spherical interpolation\nto interpolate orientations");
610c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but = new QRadioButton("euler angles");
611c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->addButton(but, LerpEulerAngles);
612c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    boxLayout->addWidget(but);
613c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    but->setToolTip("use Euler angles to interpolate orientations");
614c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    group->button(mNavMode)->setChecked(true);
615c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int)));
616c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    box->setLayout(boxLayout);
617c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    layout->addWidget(box);
618c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
619c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  layout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding));
620c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  panel->setLayout(layout);
621c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return panel;
622c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
623c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
624c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathQuaternionDemo::QuaternionDemo()
625c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
626c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mRenderingWidget = new RenderingWidget();
627c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  setCentralWidget(mRenderingWidget);
628c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
629c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  QDockWidget* panel = new QDockWidget("navigation", this);
630c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  panel->setAllowedAreas((QFlags<Qt::DockWidgetArea>)(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea));
631c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  addDockWidget(Qt::RightDockWidgetArea, panel);
632c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  panel->setWidget(mRenderingWidget->createNavigationControlWidget());
633c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
634c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
635c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathint main(int argc, char *argv[])
636c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
637c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "Navigation:\n";
638c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "  left button:           rotate around the target\n";
639c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "  middle button:         zoom\n";
640c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "  left button + ctrl     quake rotate (rotate around camera position)\n";
641c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "  middle button + ctrl   walk (progress along camera's z direction)\n";
642c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "  left button:           pan (translate in the XY camera's plane)\n\n";
643c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "R : move the camera to initial position\n";
644c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "A : start/stop animation\n";
645c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "C : clear the animation\n";
646c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  std::cout << "G : add a key frame\n";
647c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
648c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  QApplication app(argc, argv);
649c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  QuaternionDemo demo;
650c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  demo.resize(600,500);
651c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  demo.show();
652c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return app.exec();
653c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
654c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
655c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "quaternion_demo.moc"
656c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
657