Allolib  1.0
C++ Components For Interactive Multimedia
al_PickableRotateHandle.hpp
1 
2 #ifndef __AL_ROTATE_HANDLE_HPP__
3 #define __AL_ROTATE_HANDLE_HPP__
4 
5 #include <al/ui/al_Pickable.hpp>
6 #include <cfloat>
7 
8 namespace al {
9 
13  Vec3f downPos, newPos;
14  Vec3f downDir, newDir;
15  Quatf rotate;
16  bool hover[3] = {false, false, false};
17  bool selected[3] = {false, false, false};
18 
19  float size = 1.0f;
20  float dr = 0.1f;
21 
22  PickableRotateHandle() { rotate = Quatf::identity(); }
23 
24  void addCircle(Mesh &m, float r, int n) {
25  double inc = M_2PI / n;
26  double phase = 0.0;
27  for (int i = 0; i <= n; i++) {
28  float x = cos(phase) * r;
29  float y = sin(phase) * r;
30  m.vertex(x, y, 0);
31  phase += inc;
32  }
33  }
34 
35  void set(PickableRotateHandle &rh) {
36  downPos.set(rh.downPos);
37  downDir.set(rh.downDir);
38  newPos.set(rh.newPos);
39  newDir.set(rh.newDir);
40  rotate.set(rh.rotate);
41  for (int i = 0; i < 3; i++) {
42  hover[i] = rh.hover[i];
43  selected[i] = rh.selected[i];
44  }
45  }
46 
47  void draw(Graphics &g) {
48  // glPushAttrib(GL_ALL_ATTRIB_BITS);
49  Mesh m;
50  m.primitive(Mesh::LINE_STRIP);
51 
52  Quatf q;
53  for (int i = 0; i < 3; i++) {
54  m.reset();
55  addCircle(m, size, 30);
56  g.pushMatrix();
57  g.translate(pose.get().pos());
58  g.color(i == 0, i == 1, i == 2);
59  switch (i) {
60  case 0:
61  q.fromEuler(M_PI / 2, 0, 0);
62  break;
63  case 1:
64  q.fromEuler(0, -M_PI / 2, 0);
65  break;
66  case 2:
67  q.fromEuler(0, 0, 0);
68  break;
69  }
70  g.rotate(q);
71  if (hover[i])
72  addCircle(m, size - dr,
73  30); //{ m.ribbonize(.03f);
74  // m.primitive(Mesh::TRIANGLE_STRIP);}//g.lineWidth(3);
75  // else g.lineWidth(1);
76  g.draw(m);
77  g.popMatrix();
78  }
79 
80  for (int i = 0; i < 3; i++) {
81  if (selected[i]) {
82  m.reset();
83  m.primitive(Mesh::LINES);
84  m.vertex(pose.get().pos());
85  m.vertex(pose.get().pos() + newDir.normalized() * (size));
86  m.vertex(pose.get().pos());
87  m.vertex(pose.get().pos() + downDir.normalized() * (size));
88  g.color(i == 0, i == 1, i == 2);
89  g.draw(m);
90  }
91  }
92  // glPopAttrib();
93  }
94 
95  Hit intersect(Rayd r) override {
96  double t = r.intersectSphere(pose.get().pos(), size);
97  if (t > 0)
98  return Hit(true, r, t, this);
99  else
100  return Hit(false, r, t, this);
101  }
102 
103  bool onEvent(PickEvent e, Hit h) override {
104  switch (e.type) {
105  case Point:
106  if (h.ray.intersectsSphere(pose.get().pos(), size)) {
107  float t = -1;
108  float min = FLT_MAX;
109  int minIdx = -1;
110  for (int i = 0; i < 3; i++) {
111  hover[i] = false;
112  t = h.ray.intersectCircle(pose.get().pos(),
113  Vec3f(i == 0, i == 1, i == 2), size,
114  size - dr);
115  if (t > 0 && t < min) {
116  min = t;
117  minIdx = i;
118  }
119  }
120  if (minIdx >= 0) {
121  hover[minIdx] = true;
122  return true;
123  }
124  } else
125  for (int i = 0; i < 3; i++) hover[i] = false;
126  return false;
127  break;
128 
129  case Pick:
130  if (h.ray.intersectsSphere(pose.get().pos(), size)) {
131  float t = -1;
132  float min = FLT_MAX;
133  int minIdx = -1;
134  for (int i = 0; i < 3; i++) {
135  selected[i] = false;
136  t = h.ray.intersectCircle(pose.get().pos(),
137  Vec3f(i == 0, i == 1, i == 2), size,
138  size - dr);
139  if (t > 0 && t < min) {
140  min = t;
141  minIdx = i;
142  }
143  }
144  if (minIdx >= 0) {
145  selected[minIdx] = true;
146  downDir.set(h.ray(min) - pose.get().pos());
147  newDir.set(h.ray(min) - pose.get().pos());
148  if (parent) {
149  parent->prevPose.set(parent->pose.get());
150  }
151  return true;
152  }
153  }
154  return false;
155  break;
156 
157  case Drag:
158  for (int i = 0; i < 3; i++) {
159  if (selected[i]) {
160  float t = h.ray.intersectPlane(pose.get().pos(),
161  Vec3f(i == 0, i == 1, i == 2));
162  if (t > 0) {
163  newDir.set(h.ray(t) - pose.get().pos());
164  rotate = Quatf::getRotationTo(downDir.normalized(),
165  newDir.normalized());
166  if (parent) {
167  // rotate parent around rotation handle offset, probably a
168  // better way to do this :p
169  Vec3f p1 = parent->transformVecWorld(pose.get().pos());
170  parent->pose.setQuat(parent->pose.get().quat() * rotate);
171  Vec3f p2 = parent->transformVecWorld(pose.get().pos());
172  parent->pose.setPos(parent->pose.get().pos() + p1 - p2);
173  }
174  return true;
175  }
176  }
177  }
178  return false;
179  break;
180 
181  case Unpick:
182  for (int i = 0; i < 3; i++) selected[i] = false;
183  return false;
184  break;
185 
186  default:
187  break;
188  }
189  return false;
190  }
191 };
192 
193 } // namespace al
194 
195 #endif
Interface for loading fonts and rendering text.
Definition: al_Graphics.hpp:63
Stores buffers related to rendering graphical objects.
Definition: al_Mesh.hpp:62
void vertex(float x, float y, float z=0)
Append vertex to vertex buffer.
Definition: al_Mesh.hpp:317
Mesh & reset()
Reset all buffers.
virtual ParameterType get()
get the parameter's value
Vec3d & pos()
Get "position" vector.
Definition: al_Pose.hpp:100
Quatd & quat()
Get quaternion component (represents orientation)
Definition: al_Pose.hpp:108
Pose & set(Pose &src)
Copy all attributes from another Pose.
Definition: al_Pose.hpp:165
Quat & fromEuler(const Vec< 3, T > &aeb)
Set as versor rotated by YXZ Euler angles, in radians.
Definition: al_Quat.hpp:301
static Quat getRotationTo(const Vec< 3, float > &usrc, const Vec< 3, float > &udst)
Definition: al_Quat.hpp:985
static Quat identity()
Returns identity.
Definition: al_Quat.hpp:133
void rotate(float angle, float x=0., float y=0., float z=1.)
void translate(float x, float y, float z=0.)
Translate current matrix.
void popMatrix()
Pop current matrix stack.
void pushMatrix()
Push current matrix stack.
Vec & set(const Vec< N, T2 > &v)
Set elements from another vector.
Definition: al_Vec.hpp:301
Vec normalized(T scale=T(1)) const
Return closest vector lying on unit sphere.
Definition: al_Vec.hpp:489
T min(const T &v1, const T &v2, const T &v3)
Definition: al_App.hpp:23
Vec3f transformVecWorld(const Vec3f &v, float w=1)
transfrom a vector in local space to world space
Hit intersect(Rayd r) override
intersection test must be implemented
bool onEvent(PickEvent e, Hit h) override
override callback