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