1 // axisarrow.cpp
2 //
3 // Copyright (C) 2007, Celestia Development Team
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 
10 #include <algorithm>
11 #include <celmath/mathlib.h>
12 #include "gl.h"
13 #include "vecgl.h"
14 #include "axisarrow.h"
15 #include "selection.h"
16 #include "frame.h"
17 #include "body.h"
18 #include "timelinephase.h"
19 
20 using namespace std;
21 
22 static const unsigned int MaxArrowSections = 100;
23 
RenderArrow(float shaftLength,float headLength,float shaftRadius,float headRadius,unsigned int nSections)24 static void RenderArrow(float shaftLength,
25                         float headLength,
26                         float shaftRadius,
27                         float headRadius,
28                         unsigned int nSections)
29 {
30     float sintab[MaxArrowSections];
31     float costab[MaxArrowSections];
32 
33     unsigned int i;
34 
35     nSections = min(MaxArrowSections, nSections);
36 
37     // Initialize the trig tables
38     for (i = 0; i < nSections; i++)
39     {
40         double theta = (i * 2.0 * PI) / nSections;
41         sintab[i] = (float) sin(theta);
42         costab[i] = (float) cos(theta);
43     }
44 
45     // Render the circle at the botton of the arrow shaft
46     glBegin(GL_TRIANGLE_FAN);
47     glVertex3f(0.0f, 0.0f, 0.0f);
48     for (i = 0; i <= nSections; i++)
49     {
50         unsigned int n = (nSections - i) % nSections;
51         glVertex3f(shaftRadius * costab[n], shaftRadius * sintab[n], 0.0f);
52     }
53     glEnd();
54 
55     // Render the arrow shaft
56     glBegin(GL_QUAD_STRIP);
57     for (i = 0; i <= nSections; i++)
58     {
59         unsigned int n = i % nSections;
60         glVertex3f(shaftRadius * costab[n], shaftRadius * sintab[n], shaftLength);
61         glVertex3f(shaftRadius * costab[n], shaftRadius * sintab[n], 0.0f);
62     }
63     glEnd();
64 
65     // Render the annulus
66     glBegin(GL_QUAD_STRIP);
67     for (i = 0; i <= nSections; i++)
68     {
69         unsigned int n = i % nSections;
70         glVertex3f(headRadius * costab[n],  headRadius * sintab[n], shaftLength);
71         glVertex3f(shaftRadius * costab[n], shaftRadius * sintab[n], shaftLength);
72     }
73     glEnd();
74 
75     // Render the head of the arrow
76     glBegin(GL_TRIANGLE_FAN);
77     glVertex3f(0.0f, 0.0f, shaftLength + headLength);
78     for (i = 0; i <= nSections; i++)
79     {
80         unsigned int n = i % nSections;
81         glVertex3f(headRadius * costab[n], headRadius * sintab[n], shaftLength);
82     }
83     glEnd();
84 }
85 
86 
87 // Draw letter x in xz plane
RenderX()88 static void RenderX()
89 {
90     glBegin(GL_LINES);
91     glVertex3f(0, 0, 0);
92     glVertex3f(1, 0, 1);
93     glVertex3f(1, 0, 0);
94     glVertex3f(0, 0, 1);
95     glEnd();
96 }
97 
98 
99 // Draw letter y in xz plane
RenderY()100 static void RenderY()
101 {
102     glBegin(GL_LINES);
103     glVertex3f(0, 0, 1);
104     glVertex3f(0.5f, 0, 0.5f);
105     glVertex3f(1, 0, 1);
106     glVertex3f(0.5f, 0, 0.5f);
107     glVertex3f(0.5f, 0, 0);
108     glVertex3f(0.5f, 0, 0.5f);
109     glEnd();
110 }
111 
112 
113 // Draw letter z in xz plane
RenderZ()114 static void RenderZ()
115 {
116     glBegin(GL_LINE_STRIP);
117     glVertex3f(0, 0, 1);
118     glVertex3f(1, 0, 1);
119     glVertex3f(0, 0, 0);
120     glVertex3f(1, 0, 0);
121     glEnd();
122 }
123 
124 
125 #if 0
126 void RenderAxisArrows(const Quatf& orientation, float scale, float opacity)
127 {
128     glPushMatrix();
129     glRotate(orientation);
130     glScalef(scale, scale, scale);
131 
132     glDisable(GL_LIGHTING);
133 
134 #if 0
135     // Simple line axes
136     glBegin(GL_LINES);
137 
138     glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
139     glVertex3f(0.0f, 0.0f, 0.0f);
140     glVertex3f(-1.0f, 0.0f, 0.0f);
141 
142     glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
143     glVertex3f(0.0f, 0.0f, 0.0f);
144     glVertex3f(0.0f, 0.0f, 1.0f);
145 
146     glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
147     glVertex3f(0.0f, 0.0f, 0.0f);
148     glVertex3f(0.0f, 1.0f, 0.0f);
149 
150     glEnd();
151 #endif
152 
153     float shaftLength = 0.85f;
154     float headLength = 0.10f;
155     float shaftRadius = 0.010f;
156     float headRadius = 0.025f;
157     unsigned int nSections = 30;
158     float labelScale = 0.1f;
159 
160     // x-axis
161     glPushMatrix();
162     glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
163     glColor4f(1.0f, 0.0f, 0.0f, opacity);
164     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
165     glTranslatef(0.1f, 0.0f, 0.75f);
166     glScalef(labelScale, labelScale, labelScale);
167     RenderX();
168     glPopMatrix();
169 
170     // y-axis
171     glPushMatrix();
172     glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
173     glColor4f(0.0f, 1.0f, 0.0f, opacity);
174     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
175     glTranslatef(0.1f, 0.0f, 0.75f);
176     glScalef(labelScale, labelScale, labelScale);
177     RenderY();
178     glPopMatrix();
179 
180     // z-axis
181     glPushMatrix();
182     glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
183     glColor4f(0.0f, 0.0f, 1.0f, opacity);
184     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
185     glTranslatef(0.1f, 0.0f, 0.75f);
186     glScalef(labelScale, labelScale, labelScale);
187     RenderZ();
188     glPopMatrix();
189 
190     glPopMatrix();
191 }
192 #endif
193 
194 
RenderSunDirectionArrow(const Vec3f & direction,float scale,float opacity)195 void RenderSunDirectionArrow(const Vec3f& direction, float scale, float opacity)
196 {
197     glPushMatrix();
198     glRotate(Quatf::vecToVecRotation(Vec3f(0.0f, 0.0f, 1.0f), direction));
199     glScalef(scale, scale, scale);
200 
201     glDisable(GL_LIGHTING);
202 
203     float shaftLength = 0.85f;
204     float headLength = 0.10f;
205     float shaftRadius = 0.010f;
206     float headRadius = 0.025f;
207     unsigned int nSections = 30;
208 
209     glColor4f(1.0f, 1.0f, 0.0f, opacity);
210     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
211 
212     glPopMatrix();
213 }
214 
215 
RenderVelocityArrow(const Vec3f & direction,float scale,float opacity)216 void RenderVelocityArrow(const Vec3f& direction, float scale, float opacity)
217 {
218     glPushMatrix();
219     glRotate(Quatf::vecToVecRotation(Vec3f(0.0f, 0.0f, 1.0f), direction));
220     glScalef(scale, scale, scale);
221 
222     glDisable(GL_LIGHTING);
223 
224     float shaftLength = 0.85f;
225     float headLength = 0.10f;
226     float shaftRadius = 0.010f;
227     float headRadius = 0.025f;
228     unsigned int nSections = 30;
229 
230     glColor4f(0.6f, 0.6f, 0.9f, opacity);
231     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
232 
233     glPopMatrix();
234 }
235 
236 
237 /****** ArrowReferenceMark base class ******/
238 
ArrowReferenceMark(const Body & _body)239 ArrowReferenceMark::ArrowReferenceMark(const Body& _body) :
240     body(_body),
241     size(1.0),
242     color(1.0f, 1.0f, 1.0f),
243 #ifdef USE_HDR
244     opacity(0.0f)
245 #else
246     opacity(1.0f)
247 #endif
248 {
249 }
250 
251 
252 void
setSize(float _size)253 ArrowReferenceMark::setSize(float _size)
254 {
255     size = _size;
256 }
257 
258 
259 void
setColor(Color _color)260 ArrowReferenceMark::setColor(Color _color)
261 {
262     color = _color;
263 }
264 
265 
266 void
render(Renderer *,const Point3f &,float,double tdb) const267 ArrowReferenceMark::render(Renderer* /* renderer */,
268                            const Point3f& /* position */,
269                            float /* discSize */,
270                            double tdb) const
271 {
272     Vec3d v = getDirection(tdb);
273     if (v.length() < 1.0e-12)
274     {
275         // Skip rendering of zero-length vectors
276         return;
277     }
278 
279     v.normalize();
280     Quatd q = Quatd::vecToVecRotation(Vec3d(0.0, 0.0, 1.0), v);
281 
282     if (opacity == 1.0f)
283     {
284         // Enable depth buffering
285         glEnable(GL_DEPTH_TEST);
286         glDepthMask(GL_TRUE);
287         glDisable(GL_BLEND);
288     }
289     else
290     {
291         glEnable(GL_DEPTH_TEST);
292         glDepthMask(GL_FALSE);
293         glEnable(GL_BLEND);
294 #ifdef USE_HDR
295         glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
296 #else
297         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
298 #endif
299     }
300 
301     glPushMatrix();
302     glRotate(Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z));
303     glScalef(size, size, size);
304     glDisable(GL_LIGHTING);
305     glDisable(GL_TEXTURE_2D);
306 
307     float shaftLength = 0.85f;
308     float headLength = 0.10f;
309     float shaftRadius = 0.010f;
310     float headRadius = 0.025f;
311     unsigned int nSections = 30;
312 
313     glColor4f(color.red(), color.green(), color.blue(), opacity);
314     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
315 
316     glPopMatrix();
317 
318     glDisable(GL_DEPTH_TEST);
319     glDepthMask(GL_FALSE);
320     glEnable(GL_TEXTURE_2D);
321     glEnable(GL_BLEND);
322     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
323 }
324 
325 
326 /****** AxesReferenceMark base class ******/
327 
AxesReferenceMark(const Body & _body)328 AxesReferenceMark::AxesReferenceMark(const Body& _body) :
329     body(_body),
330     size(),
331 #ifdef USE_HDR
332     opacity(0.0f)
333 #else
334     opacity(1.0f)
335 #endif
336 {
337 }
338 
339 
340 void
setSize(float _size)341 AxesReferenceMark::setSize(float _size)
342 {
343     size = _size;
344 }
345 
346 
347 void
setOpacity(float _opacity)348 AxesReferenceMark::setOpacity(float _opacity)
349 {
350     opacity = _opacity;
351 #ifdef USE_HDR
352     opacity = 1.0f - opacity;
353 #endif
354 }
355 
356 
357 void
render(Renderer *,const Point3f &,float,double tdb) const358 AxesReferenceMark::render(Renderer* /* renderer */,
359                           const Point3f& /* position */,
360                           float /* discSize */,
361                           double tdb) const
362 {
363     Quatd q = getOrientation(tdb);
364 
365     if (opacity == 1.0f)
366     {
367         // Enable depth buffering
368         glEnable(GL_DEPTH_TEST);
369         glDepthMask(GL_TRUE);
370         glDisable(GL_BLEND);
371     }
372     else
373     {
374         glEnable(GL_DEPTH_TEST);
375         glDepthMask(GL_FALSE);
376         glEnable(GL_BLEND);
377 #ifdef USE_HDR
378         glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
379 #else
380         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
381 #endif
382     }
383 
384     glDisable(GL_TEXTURE_2D);
385 
386     glPushMatrix();
387     glRotate(Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z));
388     glScalef(size, size, size);
389 
390     glDisable(GL_LIGHTING);
391 
392 #if 0
393     // Simple line axes
394     glBegin(GL_LINES);
395 
396     glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
397     glVertex3f(0.0f, 0.0f, 0.0f);
398     glVertex3f(-1.0f, 0.0f, 0.0f);
399 
400     glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
401     glVertex3f(0.0f, 0.0f, 0.0f);
402     glVertex3f(0.0f, 0.0f, 1.0f);
403 
404     glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
405     glVertex3f(0.0f, 0.0f, 0.0f);
406     glVertex3f(0.0f, 1.0f, 0.0f);
407 
408     glEnd();
409 #endif
410 
411     float shaftLength = 0.85f;
412     float headLength = 0.10f;
413     float shaftRadius = 0.010f;
414     float headRadius = 0.025f;
415     unsigned int nSections = 30;
416     float labelScale = 0.1f;
417 
418     // x-axis
419     glPushMatrix();
420     glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
421     glColor4f(1.0f, 0.0f, 0.0f, opacity);
422     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
423     glTranslatef(0.1f, 0.0f, 0.75f);
424     glScalef(labelScale, labelScale, labelScale);
425     RenderX();
426     glPopMatrix();
427 
428     // y-axis
429     glPushMatrix();
430     glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
431     glColor4f(0.0f, 1.0f, 0.0f, opacity);
432     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
433     glTranslatef(0.1f, 0.0f, 0.75f);
434     glScalef(labelScale, labelScale, labelScale);
435     RenderY();
436     glPopMatrix();
437 
438     // z-axis
439     glPushMatrix();
440     glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
441     glColor4f(0.0f, 0.0f, 1.0f, opacity);
442     RenderArrow(shaftLength, headLength, shaftRadius, headRadius, nSections);
443     glTranslatef(0.1f, 0.0f, 0.75f);
444     glScalef(labelScale, labelScale, labelScale);
445     RenderZ();
446     glPopMatrix();
447 
448     glPopMatrix();
449 
450     glDisable(GL_DEPTH_TEST);
451     glDepthMask(GL_FALSE);
452     glEnable(GL_TEXTURE_2D);
453     glEnable(GL_BLEND);
454     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
455 }
456 
457 
458 /****** VelocityVectorArrow implementation ******/
459 
VelocityVectorArrow(const Body & _body)460 VelocityVectorArrow::VelocityVectorArrow(const Body& _body) :
461     ArrowReferenceMark(_body)
462 {
463     setTag("velocity vector");
464     setColor(Color(0.6f, 0.6f, 0.9f));
465     setSize(body.getRadius() * 2.0f);
466 }
467 
468 Vec3d
getDirection(double tdb) const469 VelocityVectorArrow::getDirection(double tdb) const
470 {
471     const TimelinePhase* phase = body.getTimeline()->findPhase(tdb);
472     return phase->orbit()->velocityAtTime(tdb) *
473         phase->orbitFrame()->getOrientation(tdb).toMatrix3();
474 }
475 
476 
477 /****** SunDirectionArrow implementation ******/
478 
SunDirectionArrow(const Body & _body)479 SunDirectionArrow::SunDirectionArrow(const Body& _body) :
480     ArrowReferenceMark(_body)
481 {
482     setTag("sun direction");
483     setColor(Color(1.0f, 1.0f, 0.4f));
484     setSize(body.getRadius() * 2.0f);
485 }
486 
487 Vec3d
getDirection(double tdb) const488 SunDirectionArrow::getDirection(double tdb) const
489 {
490     const Body* b = &body;
491     Star* sun = NULL;
492     while (b != NULL)
493     {
494         Selection center = b->getOrbitFrame(tdb)->getCenter();
495         if (center.star() != NULL)
496             sun = center.star();
497         b = center.body();
498     }
499 
500     if (sun != NULL)
501     {
502         return Selection(sun).getPosition(tdb) - body.getPosition(tdb);
503     }
504     else
505     {
506         return Vec3d(0.0, 0.0, 0.0);
507     }
508 }
509 
510 
511 /****** SpinVectorArrow implementation ******/
512 
SpinVectorArrow(const Body & _body)513 SpinVectorArrow::SpinVectorArrow(const Body& _body) :
514     ArrowReferenceMark(_body)
515 {
516     setTag("spin vector");
517     setColor(Color(0.6f, 0.6f, 0.6f));
518     setSize(body.getRadius() * 2.0f);
519 }
520 
521 Vec3d
getDirection(double tdb) const522 SpinVectorArrow::getDirection(double tdb) const
523 {
524     const TimelinePhase* phase = body.getTimeline()->findPhase(tdb);
525     return phase->rotationModel()->angularVelocityAtTime(tdb) *
526         phase->bodyFrame()->getOrientation(tdb).toMatrix3();
527 #if 0
528     return body.getRotationModel(tdb)->angularVelocityAtTime(tdb) *
529         body.getEclipticToFrame(tdb).toMatrix3();
530 #endif
531 }
532 
533 
534 /****** BodyToBodyDirectionArrow implementation ******/
535 
536 /*! Create a new body-to-body direction arrow pointing from the origin body toward
537  *  the specified target object.
538  */
BodyToBodyDirectionArrow(const Body & _body,const Selection & _target)539 BodyToBodyDirectionArrow::BodyToBodyDirectionArrow(const Body& _body, const Selection& _target) :
540     ArrowReferenceMark(_body),
541     target(_target)
542 {
543     setTag("body to body");
544     setColor(Color(0.0f, 0.5f, 0.0f));
545     setSize(body.getRadius() * 2.0f);
546 }
547 
548 
549 Vec3d
getDirection(double tdb) const550 BodyToBodyDirectionArrow::getDirection(double tdb) const
551 {
552     return target.getPosition(tdb) - body.getPosition(tdb);
553 }
554 
555 
556 /****** BodyAxisArrows implementation ******/
557 
BodyAxisArrows(const Body & _body)558 BodyAxisArrows::BodyAxisArrows(const Body& _body) :
559     AxesReferenceMark(_body)
560 {
561     setTag("body axes");
562     setOpacity(1.0);
563     setSize(body.getRadius() * 2.0f);
564 }
565 
566 Quatd
getOrientation(double tdb) const567 BodyAxisArrows::getOrientation(double tdb) const
568 {
569     return ~(Quatd::yrotation(PI) * body.getEclipticToBodyFixed(tdb));
570 }
571 
572 
573 /****** FrameAxisArrows implementation ******/
574 
FrameAxisArrows(const Body & _body)575 FrameAxisArrows::FrameAxisArrows(const Body& _body) :
576     AxesReferenceMark(_body)
577 {
578     setTag("frame axes");
579     setOpacity(0.5);
580     setSize(body.getRadius() * 2.0f);
581 }
582 
583 Quatd
getOrientation(double tdb) const584 FrameAxisArrows::getOrientation(double tdb) const
585 {
586     return ~body.getEclipticToFrame(tdb);
587 }
588