3
* Copyright (C) 2003 Fabien Chereau
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.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
#if defined(__APPLE__) && defined(__MACH__)
28
#include <OpenGL/glu.h> /* Header File For The GLU Library */
30
#include <GL/glu.h> /* Header File For The GLU Library */
33
#include "Projector.hpp"
34
#include "InitParser.hpp"
35
#include "MappingClasses.hpp"
36
#include "StelApp.hpp"
39
const char *Projector::maskTypeToString(PROJECTOR_MASK_TYPE type)
47
Projector::PROJECTOR_MASK_TYPE Projector::stringToMaskType(const string &s)
54
void Projector::registerProjectionMapping(Mapping *c)
56
if (c) projectionMapping[c->getName()] = c;
59
void Projector::init(const InitParser& conf)
62
string tmpstr = conf.get_str("projection:viewport");
63
const Projector::PROJECTOR_MASK_TYPE
64
projMaskType = Projector::stringToMaskType(tmpstr);
65
setMaskType(projMaskType);
66
const bool maximized = (tmpstr=="maximized");
67
const int screen_w = StelApp::getInstance().getScreenW();
68
const int screen_h = StelApp::getInstance().getScreenH();
69
const int screen_min_wh = MY_MIN(screen_w,screen_h);
70
const int viewport_width
71
= conf.get_int("projection","viewport_width",
72
maximized ? screen_w : screen_min_wh);
73
const int viewport_height
74
= conf.get_int("projection","viewport_height",
75
maximized ? screen_h : screen_min_wh);
77
= conf.get_int("projection","viewport_x",
78
(screen_w-viewport_width)/2);
80
= conf.get_int("projection","viewport_y",
81
(screen_h-viewport_height)/2);
82
const double viewport_center_x
83
= conf.get_double("projection","viewport_center_x",0.5*viewport_width);
84
const double viewport_center_y
85
= conf.get_double("projection","viewport_center_y",0.5*viewport_height);
86
const double viewport_fov_diameter
87
= conf.get_double("projection","viewport_fov_diameter",
88
MY_MIN(viewport_width,viewport_height));
89
setViewport(viewport_x,viewport_y,viewport_width,viewport_height,
90
viewport_center_x,viewport_center_y,
91
viewport_fov_diameter);
94
double overwrite_max_fov
95
= conf.get_double("projection","equal_area_max_fov",0.0);
96
if (overwrite_max_fov > 360.0) overwrite_max_fov = 360.0;
97
if (overwrite_max_fov > 0.0)
98
MappingEqualArea::getMapping()->maxFov = overwrite_max_fov;
100
= conf.get_double("projection","stereographic_max_fov",0.0);
101
if (overwrite_max_fov > 359.999999) overwrite_max_fov = 359.999999;
102
if (overwrite_max_fov > 0.0)
103
MappingStereographic::getMapping()->maxFov = overwrite_max_fov;
105
= conf.get_double("projection","fisheye_max_fov",0.0);
106
if (overwrite_max_fov > 360.0) overwrite_max_fov = 360.0;
107
if (overwrite_max_fov > 0.0)
108
MappingFisheye::getMapping()->maxFov = overwrite_max_fov;
110
= conf.get_double("projection","cylinder_max_fov",0.0);
111
if (overwrite_max_fov > 540.0) overwrite_max_fov = 540.0;
112
if (overwrite_max_fov > 0.0)
113
MappingCylinder::getMapping()->maxFov = overwrite_max_fov;
115
= conf.get_double("projection","perspective_max_fov",0.0);
116
if (overwrite_max_fov > 179.999999) overwrite_max_fov = 179.999999;
117
if (overwrite_max_fov > 0.0)
118
MappingPerspective::getMapping()->maxFov = overwrite_max_fov;
120
= conf.get_double("projection","orthographic_max_fov",0.0);
121
if (overwrite_max_fov > 180.0) overwrite_max_fov = 180.0;
122
if (overwrite_max_fov > 0.0)
123
MappingOrthographic::getMapping()->maxFov = overwrite_max_fov;
125
setFlagGravityLabels( conf.get_boolean("viewing:flag_gravity_labels") );
127
// Register the default mappings
128
registerProjectionMapping(MappingEqualArea::getMapping());
129
registerProjectionMapping(MappingStereographic::getMapping());
130
registerProjectionMapping(MappingFisheye::getMapping());
131
registerProjectionMapping(MappingCylinder::getMapping());
132
registerProjectionMapping(MappingPerspective::getMapping());
133
registerProjectionMapping(MappingOrthographic::getMapping());
135
tmpstr = conf.get_str("projection:type");
136
setCurrentProjection(tmpstr);
138
initFov = conf.get_double ("navigation","init_fov",60.);
141
//glFrontFace(needGlFrontFaceCW()?GL_CW:GL_CCW);
143
flagGlPointSprite = conf.get_boolean("projection","flag_use_gl_point_sprite",false);
144
flagGlPointSprite = flagGlPointSprite && GLEE_ARB_point_sprite;
145
if (flagGlPointSprite)
147
glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );
148
glEnable(GL_POINT_SPRITE_ARB);
149
glEnable(GL_POINT_SMOOTH);
150
cout << "INFO: using GL_ARB_point_sprite" << endl;
152
//cerr << "WARNING: GL_ARB_point_sprite not available" << endl;
156
void Projector::windowHasBeenResized(int width,int height)
158
// Maximize display when resized since it invalidates previous options anyway
159
setViewport(0,0,width,height, 0.5*width, 0.5*height,MY_MIN(width,height));
162
Projector::Projector(const Vector4<GLint>& viewport, double _fov)
163
:maskType(NONE), fov(_fov), min_fov(0.0001), max_fov(100),
164
zNear(0.1), zFar(10000),
165
viewport_xywh(viewport),
166
viewport_center(Vec2d(viewport_xywh[0]+0.5*viewport_xywh[2],
167
viewport_xywh[1]+0.5*viewport_xywh[3])),
168
viewport_fov_diameter(MY_MIN(viewport_xywh[2],viewport_xywh[3])),
174
setViewport(viewport_xywh[0],viewport_xywh[1],
175
viewport_xywh[2],viewport_xywh[3],
176
viewport_center[0]-viewport_xywh[0],
177
viewport_center[1]-viewport_xywh[1],
178
viewport_fov_diameter);
183
Projector::~Projector()
187
void Projector::setViewport(int x, int y, int w, int h,
188
double cx,double cy,double fov_diam)
190
viewport_xywh[0] = x;
191
viewport_xywh[1] = y;
192
viewport_xywh[2] = w;
193
viewport_xywh[3] = h;
194
viewport_center[0] = x+cx;
195
viewport_center[1] = y+cy;
196
viewport_fov_diameter = fov_diam;
197
pixel_per_rad = 0.5 * viewport_fov_diameter
198
/ (mapping ? mapping->fovToViewScalingFactor(fov*(M_PI/360.0)) : 1.0);
199
glViewport(x, y, w, h);
200
initGlMatrixOrtho2d();
203
/*************************************************************************
204
Return a polygon matching precisely the real viewport defined by the area on the screen
205
where projection is valid.
206
*************************************************************************/
207
std::vector<Vec2d> Projector::getViewportVertices2d() const
209
std::vector<Vec2d> result;
210
result.push_back(Vec2d(viewport_xywh[0], viewport_xywh[1]));
211
result.push_back(Vec2d(viewport_xywh[0]+viewport_xywh[2], viewport_xywh[1]));
212
result.push_back(Vec2d(viewport_xywh[0]+viewport_xywh[2], viewport_xywh[1]+viewport_xywh[3]));
213
result.push_back(Vec2d(viewport_xywh[0], viewport_xywh[1]+viewport_xywh[3]));
217
/*************************************************************************
218
Return a convex polygon on the sphere which includes the viewport in the
220
*************************************************************************/
221
StelGeom::ConvexPolygon Projector::getViewportConvexPolygon(double marginX, double marginY) const
223
Vec3d e0, e1, e2, e3;
224
unProject(0-marginX,0-marginY,e0);
225
unProject(getViewportWidth()+marginX,0-marginY,e1);
226
unProject(getViewportWidth()+marginX,getViewportHeight()+marginY,e2);
227
unProject(0-marginX,getViewportHeight()+marginY,e3);
232
return StelGeom::ConvexPolygon(e0, e3, e2, e1);
235
StelGeom::ConvexS Projector::unprojectViewport(void) const {
236
// This is quite ugly, but already better than nothing.
237
// In fact this function should have different implementations
238
// for the different mapping types. And maskType, viewport_fov_diameter,
239
// viewport_center, viewport_xywh must be taken into account, too.
240
// Last not least all halfplanes n*x>d really should have d<=0
241
// or at least very small d/n.length().
242
if ((dynamic_cast<const MappingCylinder*>(mapping) == 0 || fov < 90) &&
246
if (maskType == DISK) {
248
unProject(viewport_center[0],viewport_center[1],e0);
249
StelGeom::ConvexS rval(1);
251
rval[0].d = (fov<360.0) ? cos(fov*(M_PI/360.0)) : -1.0;
254
ok = unProject(viewport_center[0] - 0.5*viewport_fov_diameter,
255
viewport_center[1] - 0.5*viewport_fov_diameter,e0);
256
ok &= unProject(viewport_center[0] + 0.5*viewport_fov_diameter,
257
viewport_center[1] + 0.5*viewport_fov_diameter,e2);
258
if (needGlFrontFaceCW()) {
259
ok &= unProject(viewport_center[0] - 0.5*viewport_fov_diameter,
260
viewport_center[1] + 0.5*viewport_fov_diameter,e3);
261
ok &= unProject(viewport_center[0] + 0.5*viewport_fov_diameter,
262
viewport_center[1] - 0.5*viewport_fov_diameter,e1);
264
ok &= unProject(viewport_center[0] - 0.5*viewport_fov_diameter,
265
viewport_center[1] + 0.5*viewport_fov_diameter,e1);
266
ok &= unProject(viewport_center[0] + 0.5*viewport_fov_diameter,
267
viewport_center[1] - 0.5*viewport_fov_diameter,e3);
270
ok = unProject(viewport_xywh[0],viewport_xywh[1],e0);
271
ok &= unProject(viewport_xywh[0]+viewport_xywh[2],
272
viewport_xywh[1]+viewport_xywh[3],e2);
273
if (needGlFrontFaceCW()) {
274
ok &= unProject(viewport_xywh[0],viewport_xywh[1]+viewport_xywh[3],e3);
275
ok &= unProject(viewport_xywh[0]+viewport_xywh[2],viewport_xywh[1],e1);
277
ok &= unProject(viewport_xywh[0],viewport_xywh[1]+viewport_xywh[3],e1);
278
ok &= unProject(viewport_xywh[0]+viewport_xywh[2],viewport_xywh[1],e3);
282
StelGeom::HalfSpace h0(e0^e1);
283
StelGeom::HalfSpace h1(e1^e2);
284
StelGeom::HalfSpace h2(e2^e3);
285
StelGeom::HalfSpace h3(e3^e0);
286
if (h0.contains(e2) && h0.contains(e3) &&
287
h1.contains(e3) && h1.contains(e0) &&
288
h2.contains(e0) && h2.contains(e1) &&
289
h3.contains(e1) && h3.contains(e2)) {
290
StelGeom::ConvexS rval(4);
298
if (unProject(viewport_xywh[0]+0.5*viewport_xywh[2],
299
viewport_xywh[1]+0.5*viewport_xywh[3],middle)) {
300
double d = middle*e0;
301
double h = middle*e1;
307
StelGeom::ConvexS rval(1);
315
StelGeom::ConvexS rval(1);
316
rval[0].n = Vec3d(1.0,0.0,0.0);
321
void Projector::setFov(double f)
324
// cout << "Set fov to " << f << " " << max_fov << " " << min_fov << endl;
330
pixel_per_rad = 0.5 * viewport_fov_diameter
331
/ (mapping ? mapping->fovToViewScalingFactor(fov*(M_PI/360.0)) : 1.0);
335
void Projector::setMaxFov(double max)
345
void Projector::set_clipping_planes(double znear, double zfar)
351
// Set the standard modelview matrices used for projection
352
void Projector::set_modelview_matrices( const Mat4d& _mat_earth_equ_to_eye,
353
const Mat4d& _mat_helio_to_eye,
354
const Mat4d& _mat_local_to_eye,
355
const Mat4d& _mat_j2000_to_eye)
357
mat_earth_equ_to_eye = _mat_earth_equ_to_eye;
358
mat_j2000_to_eye = _mat_j2000_to_eye;
359
mat_helio_to_eye = _mat_helio_to_eye;
360
mat_local_to_eye = _mat_local_to_eye;
364
/*************************************************************************
365
Set the frame in which we want to draw from now on
366
*************************************************************************/
367
void Projector::setCurrentFrame(FRAME_TYPE frameType) const
372
setCustomFrame(mat_local_to_eye);
375
setCustomFrame(mat_helio_to_eye);
377
case FRAME_EARTH_EQU:
378
setCustomFrame(mat_earth_equ_to_eye);
381
setCustomFrame(mat_j2000_to_eye);
384
cerr << "Unknown reference frame type: " << (int)frameType << "." << endl;
388
/*************************************************************************
389
Set a custom model view matrix, it is valid until the next call to
390
setCurrentFrame or setCustomFrame
391
*************************************************************************/
392
void Projector::setCustomFrame(const Mat4d& m) const
397
/*************************************************************************
398
Init the real openGL Matrices to a 2d orthographic projection
399
*************************************************************************/
400
void Projector::initGlMatrixOrtho2d(void) const
402
// Set the real openGL projection and modelview matrix to orthographic projection
403
// thus we never need to change to 2dMode from now on before drawing
404
glMatrixMode(GL_PROJECTION);
406
glOrtho(viewport_xywh[0], viewport_xywh[0] + viewport_xywh[2],
407
viewport_xywh[1], viewport_xywh[1] + viewport_xywh[3], -1, 1);
408
glMatrixMode(GL_MODELVIEW);
412
/*************************************************************************
413
Return an openGL Matrix for a perspective projection.
414
*************************************************************************/
415
//Mat4d Projector::getGlMatrixPerspective(void) const
417
// const double f = 1./std::tan(fov*M_PI/360.);
418
// const double ratio = (double)getViewportHeight()/getViewportWidth();
419
// return Mat4d( flip_horz*f*ratio, 0., 0., 0.,
420
// 0., flip_vert*f, 0., 0.,
421
// 0., 0., (zFar + zNear)/(zNear - zFar), -1.,
422
// 0., 0., (2.*zFar*zNear)/(zNear - zFar), 0.);
425
/*************************************************************************
426
Set the current projection mapping to use
427
*************************************************************************/
428
void Projector::setCurrentProjection(const std::string& projectionName)
430
if (currentProjectionType==projectionName)
433
std::map<std::string,const Mapping*>::const_iterator
434
i(projectionMapping.find(projectionName));
435
if (i!=projectionMapping.end())
437
currentProjectionType = projectionName;
439
// Redefine the projection functions
441
min_fov = mapping->minFov;
442
max_fov = mapping->maxFov;
445
initGlMatrixOrtho2d();
449
cerr << "Unknown projection type: " << projectionName << "." << endl;
453
/*************************************************************************
454
Project the vector v from the current frame into the viewport
455
*************************************************************************/
456
// bool Projector::project(const Vec3d &v, Vec3d &win) const
458
// // really important speedup:
459
// win[0] = modelViewMatrix.r[0]*v[0] + modelViewMatrix.r[4]*v[1]
460
// + modelViewMatrix.r[8]*v[2] + modelViewMatrix.r[12];
461
// win[1] = modelViewMatrix.r[1]*v[0] + modelViewMatrix.r[5]*v[1]
462
// + modelViewMatrix.r[9]*v[2] + modelViewMatrix.r[13];
463
// win[2] = modelViewMatrix.r[2]*v[0] + modelViewMatrix.r[6]*v[1]
464
// + modelViewMatrix.r[10]*v[2] + modelViewMatrix.r[14];
465
// const bool rval = mapping->forward(win);
466
// // very important: even when the projected point comes from an
467
// // invisible region of the sky (rval=false), we must finish
468
// // reprojecting, so that OpenGl can successfully eliminate
469
// // polygons by culling.
470
// win[0] = viewport_center[0] + flip_horz * pixel_per_rad * win[0];
471
// win[1] = viewport_center[1] + flip_vert * pixel_per_rad * win[1];
472
// win[2] = (win[2] - zNear) / (zNear - zFar);
476
/*************************************************************************
477
Project the vector v from the viewport frame into the current frame
478
*************************************************************************/
479
bool Projector::unProject(double x, double y, Vec3d &v) const
481
v[0] = flip_horz * (x - viewport_center[0]) / pixel_per_rad;
482
v[1] = flip_vert * (y - viewport_center[1]) / pixel_per_rad;
484
const bool rval = mapping->backward(v);
485
// Even when the reprojected point comes from an region of the screen,
486
// where nothing is projected to (rval=false), we finish reprojecting.
487
// This looks good for atmosphere rendering, and it helps avoiding
488
// discontinuities when dragging around with the mouse.
490
x = v[0] - modelViewMatrix.r[12];
491
y = v[1] - modelViewMatrix.r[13];
492
const double z = v[2] - modelViewMatrix.r[14];
493
v[0] = modelViewMatrix.r[0]*x + modelViewMatrix.r[1]*y + modelViewMatrix.r[2]*z;
494
v[1] = modelViewMatrix.r[4]*x + modelViewMatrix.r[5]*y + modelViewMatrix.r[6]*z;
495
v[2] = modelViewMatrix.r[8]*x + modelViewMatrix.r[9]*y + modelViewMatrix.r[10]*z;
497
// Johannes: Get rid of the inverseModelViewMatrix.
498
// We need no matrix inversion because we always work with orthogonal matrices
499
// (where the transposed is the inverse).
500
// v.transfo4d(inverseModelViewMatrix);
507
///////////////////////////////////////////////////////////////////////////
508
// Standard methods for drawing primitives
510
// Fill with black around the circle
511
void Projector::draw_viewport_shape(void)
513
if (maskType != DISK)
517
glColor3f(0.f,0.f,0.f);
519
glTranslated(viewport_center[0],viewport_center[1],0.0);
520
GLUquadricObj * p = gluNewQuadric();
521
gluDisk(p, 0.5*viewport_fov_diameter,
522
getViewportWidth()+getViewportHeight(), 256, 1); // should always cover whole screen
527
#define MAX_STACKS 4096
528
static double cos_sin_rho[2*(MAX_STACKS+1)];
529
#define MAX_SLICES 4096
530
static double cos_sin_theta[2*(MAX_SLICES+1)];
533
void ComputeCosSinTheta(double phi,int segments) {
534
double *cos_sin = cos_sin_theta;
535
double *cos_sin_rev = cos_sin + 2*(segments+1);
536
const double c = cos(phi);
537
const double s = sin(phi);
540
*--cos_sin_rev = -cos_sin[-1];
541
*--cos_sin_rev = cos_sin[-2];
544
*--cos_sin_rev = -cos_sin[-1];
545
*--cos_sin_rev = cos_sin[-2];
546
while (cos_sin < cos_sin_rev) {
547
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
548
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
550
*--cos_sin_rev = -cos_sin[-1];
551
*--cos_sin_rev = cos_sin[-2];
556
void ComputeCosSinRho(double phi,int segments) {
557
double *cos_sin = cos_sin_rho;
558
double *cos_sin_rev = cos_sin + 2*(segments+1);
559
const double c = cos(phi);
560
const double s = sin(phi);
563
*--cos_sin_rev = cos_sin[-1];
564
*--cos_sin_rev = -cos_sin[-2];
567
*--cos_sin_rev = cos_sin[-1];
568
*--cos_sin_rev = -cos_sin[-2];
569
while (cos_sin < cos_sin_rev) {
570
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
571
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
573
*--cos_sin_rev = cos_sin[-1];
574
*--cos_sin_rev = -cos_sin[-2];
580
// Reimplementation of gluSphere : glu is overrided for non standard projection
581
void Projector::sSphereLinear(GLdouble radius, GLdouble one_minus_oblateness,
582
GLint slices, GLint stacks, int orient_inside) const
585
glLoadMatrixd(modelViewMatrix);
587
if (one_minus_oblateness == 1.0)
588
{ // gluSphere seems to have hardware acceleration
589
GLUquadricObj * p = gluNewQuadric();
590
gluQuadricTexture(p,GL_TRUE);
592
gluQuadricOrientation(p, GLU_INSIDE);
593
gluSphere(p, radius, slices, stacks);
599
GLfloat s, t, ds, dt;
608
const double drho = M_PI / stacks;
609
assert(stacks<=MAX_STACKS);
610
ComputeCosSinRho(drho,stacks);
611
double *cos_sin_rho_p;
613
const double dtheta = 2.0 * M_PI / slices;
614
assert(slices<=MAX_SLICES);
615
ComputeCosSinTheta(dtheta,slices);
616
double *cos_sin_theta_p;
618
// texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
619
// t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
620
// cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
623
t = 1.0; // because loop now runs from 0
625
// draw intermediate stacks as quad strips
626
for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks;
627
i++,cos_sin_rho_p+=2)
629
glBegin(GL_QUAD_STRIP);
631
for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;
632
j++,cos_sin_theta_p+=2)
634
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
635
y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
636
z = nsign * cos_sin_rho_p[0];
637
glNormal3f(x * one_minus_oblateness * nsign,
638
y * one_minus_oblateness * nsign,
641
glVertex3d(x * radius,
643
one_minus_oblateness * z * radius);
644
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
645
y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
646
z = nsign * cos_sin_rho_p[2];
647
glNormal3f(x * one_minus_oblateness * nsign,
648
y * one_minus_oblateness * nsign,
650
glTexCoord2f(s, t - dt);
652
glVertex3d(x * radius,
654
one_minus_oblateness * z * radius);
665
void Projector::sFanDisk(double radius,int inner_fan_slices,int level) const {
670
// for (i=level-1;i>=0;i--) {
671
// double f = ((i+1)/(double)(level+1));
672
// rad[i] = radius*f*f;
674
for (i=level-1;i>=0;i--) {
675
rad[i] = rad[i+1]*(1.0-M_PI/(inner_fan_slices<<(i+1)))*2.0/3.0;
677
int slices = inner_fan_slices<<level;
678
const double dtheta = 2.0 * M_PI / slices;
679
assert(slices<=MAX_SLICES);
680
ComputeCosSinTheta(dtheta,slices);
681
double *cos_sin_theta_p;
683
for (i=level;i>0;i--,slices_step<<=1) {
684
for (j=0,cos_sin_theta_p=cos_sin_theta;
686
j+=slices_step,cos_sin_theta_p+=2*slices_step) {
687
glBegin(GL_TRIANGLE_FAN);
688
double x = rad[i]*cos_sin_theta_p[slices_step];
689
double y = rad[i]*cos_sin_theta_p[slices_step+1];
690
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
693
x = rad[i]*cos_sin_theta_p[2*slices_step];
694
y = rad[i]*cos_sin_theta_p[2*slices_step+1];
695
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
698
x = rad[i-1]*cos_sin_theta_p[2*slices_step];
699
y = rad[i-1]*cos_sin_theta_p[2*slices_step+1];
700
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
703
x = rad[i-1]*cos_sin_theta_p[0];
704
y = rad[i-1]*cos_sin_theta_p[1];
705
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
708
x = rad[i]*cos_sin_theta_p[0];
709
y = rad[i]*cos_sin_theta_p[1];
710
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
715
// draw the inner polygon
718
for (j=0,cos_sin_theta_p=cos_sin_theta;
720
j+=slices_step,cos_sin_theta_p+=2*slices_step) {
721
double x = rad[0]*cos_sin_theta_p[0];
722
double y = rad[0]*cos_sin_theta_p[1];
723
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius));
730
// Draw a disk with a special texturing mode having texture center at disk center
731
void Projector::sDisk(GLdouble radius, GLint slices, GLint stacks, int orient_inside) const
734
const GLfloat nsign = orient_inside ? -1 : 1;
736
const double dr = radius / stacks;
738
const double dtheta = 2.0 * M_PI / slices;
739
if (slices < 0) slices = -slices;
740
assert(slices<=MAX_SLICES);
741
ComputeCosSinTheta(dtheta,slices);
742
double *cos_sin_theta_p;
744
// draw intermediate stacks as quad strips
745
for (i = 0, r = 0.0; i < stacks; i++, r+=dr)
747
glBegin(GL_QUAD_STRIP);
748
for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;
749
j++,cos_sin_theta_p+=2)
751
double x = r*cos_sin_theta_p[0];
752
double y = r*cos_sin_theta_p[1];
753
glNormal3f(0, 0, nsign);
754
glTexCoord2d(0.5+0.5*x/radius, 0.5+0.5*y/radius);
755
drawVertex3(x, y, 0);
756
x = (r+dr)*cos_sin_theta_p[0];
757
y = (r+dr)*cos_sin_theta_p[1];
758
glNormal3f(0, 0, nsign);
759
glTexCoord2d(0.5+0.5*x/radius, 0.5+0.5*y/radius);
760
drawVertex3(x, y, 0);
766
void Projector::sRing(GLdouble r_min, GLdouble r_max, GLint slices, GLint stacks, int orient_inside) const
771
const double nsign = (orient_inside)?-1.0:1.0;
773
const double dr = (r_max-r_min) / stacks;
774
const double dtheta = 2.0 * M_PI / slices;
775
if (slices < 0) slices = -slices;
776
assert(slices<=MAX_SLICES);
777
ComputeCosSinTheta(dtheta,slices);
778
double *cos_sin_theta_p;
781
// draw intermediate stacks as quad strips
782
for (double r = r_min; r < r_max; r+=dr)
784
const double tex_r0 = (r-r_min)/(r_max-r_min);
785
const double tex_r1 = (r+dr-r_min)/(r_max-r_min);
786
glBegin(GL_QUAD_STRIP /*GL_TRIANGLE_STRIP*/);
787
for (j=0,cos_sin_theta_p=cos_sin_theta;
789
j++,cos_sin_theta_p+=2)
791
x = r*cos_sin_theta_p[0];
792
y = r*cos_sin_theta_p[1];
793
glNormal3d(0, 0, nsign);
794
glTexCoord2d(tex_r0, 0.5);
795
drawVertex3(x, y, 0);
796
x = (r+dr)*cos_sin_theta_p[0];
797
y = (r+dr)*cos_sin_theta_p[1];
798
glNormal3d(0, 0, nsign);
799
glTexCoord2d(tex_r1, 0.5);
800
drawVertex3(x, y, 0);
806
static void sSphereMapTexCoordFast(double rho_div_fov, double costheta, double sintheta)
810
glTexCoord2d(0.5 + rho_div_fov * costheta,
811
0.5 + rho_div_fov * sintheta);
814
void Projector::sSphere_map(GLdouble radius, GLint slices, GLint stacks,
815
double texture_fov, int orient_inside) const
819
const double nsign = orient_inside?-1:1;
821
const double drho = M_PI / stacks;
822
assert(stacks<=MAX_STACKS);
823
ComputeCosSinRho(drho,stacks);
824
double *cos_sin_rho_p;
826
const double dtheta = 2.0 * M_PI / slices;
827
assert(slices<=MAX_SLICES);
829
ComputeCosSinTheta(dtheta,slices);
830
double *cos_sin_theta_p;
833
// texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
834
// t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
835
// cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
837
const int imax = stacks;
839
// draw intermediate stacks as quad strips
840
if (!orient_inside) // nsign==1
842
for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0;
843
i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
845
glBegin(GL_QUAD_STRIP);
846
for (j=0,cos_sin_theta_p=cos_sin_theta;
847
j<=slices;++j,cos_sin_theta_p+=2)
849
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
850
y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
851
z = cos_sin_rho_p[0];
852
glNormal3d(x * nsign, y * nsign, z * nsign);
853
sSphereMapTexCoordFast(rho/texture_fov,
856
drawVertex3(x * radius, y * radius, z * radius);
858
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
859
y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
860
z = cos_sin_rho_p[2];
861
glNormal3d(x * nsign, y * nsign, z * nsign);
862
sSphereMapTexCoordFast((rho + drho)/texture_fov,
865
drawVertex3(x * radius, y * radius, z * radius);
872
for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0;
873
i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
875
glBegin(GL_QUAD_STRIP);
876
for (j=0,cos_sin_theta_p=cos_sin_theta;
877
j<=slices;++j,cos_sin_theta_p+=2)
879
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
880
y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
881
z = cos_sin_rho_p[2];
882
glNormal3d(x * nsign, y * nsign, z * nsign);
883
sSphereMapTexCoordFast((rho + drho)/texture_fov,
885
-cos_sin_theta_p[1]);
886
drawVertex3(x * radius, y * radius, z * radius);
888
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
889
y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
890
z = cos_sin_rho_p[0];
891
glNormal3d(x * nsign, y * nsign, z * nsign);
892
sSphereMapTexCoordFast(rho/texture_fov,
894
-cos_sin_theta_p[1]);
895
drawVertex3(x * radius, y * radius, z * radius);
903
// Reimplementation of gluCylinder : glu is overrided for non standard projection
904
void Projector::sCylinderLinear(GLdouble radius, GLdouble height, GLint slices, GLint stacks, int orient_inside) const
907
glLoadMatrixd(modelViewMatrix);
908
GLUquadricObj * p = gluNewQuadric();
909
gluQuadricTexture(p,GL_TRUE);
912
glCullFace(GL_FRONT);
914
gluCylinder(p, radius, radius, height, slices, stacks);
924
void Projector::drawTextGravity180(const SFont* font, float x, float y, const wstring& ws,
925
bool speed_optimize, float xshift, float yshift) const
927
static float dx, dy, d, theta, psi;
928
dx = x - viewport_center[0];
929
dy = y - viewport_center[1];
930
d = sqrt(dx*dx + dy*dy);
932
// If the text is too far away to be visible in the screen return
933
if (d>MY_MAX(viewport_xywh[3], viewport_xywh[2])*2)
936
theta = M_PI + std::atan2(dx, dy - 1);
937
psi = std::atan2((float)font->getStrLen(ws)/ws.length(),d + 1) * 180./M_PI;
944
glRotatef(theta*180./M_PI,0,0,-1);
945
glTranslatef(xshift, -yshift, 0);
949
glEnable(GL_TEXTURE_2D);
950
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode
951
for (unsigned int i=0;i<ws.length();++i)
953
if( !speed_optimize )
955
font->print_char_outlined(ws[i]);
959
font->print_char(ws[i]);
962
// with typeface need to manually advance
963
// TODO, absolute rotation would be better than relative
964
// TODO: would look better with kerning information...
965
glTranslatef(font->getStrLen(ws.substr(i,1)) * 1.05, 0, 0);
967
if( !speed_optimize )
969
psi = std::atan2((float)font->getStrLen(ws.substr(i,1))*1.05f,(float)d) * 180./M_PI;
974
glRotatef(psi,0,0,-1);
979
/*************************************************************************
980
Draw the string at the given position and angle with the given font
981
*************************************************************************/
982
void Projector::drawText(const SFont* font, float x, float y, const wstring& str, float angleDeg, float xshift, float yshift, bool noGravity) const
984
if (gravityLabels && !noGravity)
986
drawTextGravity180(font, x, y, str, true, xshift, yshift);
992
glRotatef(angleDeg,0,0,1);
993
glTranslatef(0,font->getLineHeight(),0);
994
font->print(xshift, yshift, str);
998
/*************************************************************************
999
Draw a parallel arc in the current frame
1000
*************************************************************************/
1001
void Projector::drawParallel(const Vec3d& start, double length, bool labelAxis, const SFont* font, const Vec4f* textColor, int nbSeg) const
1004
nbSeg = 4 + (int)(length*44./(2.*M_PI));
1005
const Mat4d dRa = Mat4d::zrotation(length/nbSeg);
1009
glBegin(GL_LINE_STRIP);
1010
for (int i=0;i<=nbSeg;++i)
1013
glVertex2f(pt1[0],pt1[1]);
1018
// Draw label if needed
1021
static GLfloat tmpColor[4];
1024
glGetFloatv(GL_CURRENT_COLOR, tmpColor);
1025
glColor4fv(*textColor);
1028
StelUtils::rect_to_sphe(&lon, &lat, start);
1031
StelUtils::sphe_to_rect(lon+0.0000001, lat, v2);
1032
project(start, win0);
1034
double angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
1035
const wstring str = StelUtils::radToDmsStrAdapt(lat).toStdWString();
1037
if (angleDeg>90. || angleDeg<-90.)
1040
xshift=-font->getStrLen(str)-5.f;
1042
drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
1044
// Label at end of the arc
1045
StelUtils::sphe_to_rect(lon+length-0.0000001, lat, v2);
1048
angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
1050
if (angleDeg>90. || angleDeg<-90.)
1053
xshift=-font->getStrLen(str)-5.f;
1055
drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
1058
glColor4fv(tmpColor);
1062
/*************************************************************************
1063
Draw a meridian arc in the current frame
1064
*************************************************************************/
1065
void Projector::drawMeridian(const Vec3d& start, double length, bool labelAxis, const SFont* font, const Vec4f* textColor, int nbSeg) const
1068
nbSeg = 4 + (int)(length*54./(2.*M_PI));
1069
static const Vec3d oneZ(0,0,1);
1070
const Mat4d dDe = Mat4d::rotation(start^oneZ, (start[1]>=0 ? 1.:-1.) * length/nbSeg);
1074
glBegin(GL_LINE_STRIP);
1075
for (int i=0;i<=nbSeg;++i)
1078
glVertex2f(pt1[0],pt1[1]);
1083
// Draw label if needed
1086
static GLfloat tmpColor[4];
1089
glGetFloatv(GL_CURRENT_COLOR, tmpColor);
1090
glColor4fv(*textColor);
1093
StelUtils::rect_to_sphe(&lon, &lat, start);
1096
StelUtils::sphe_to_rect(lon, lat+0.0000001*(start[1]>=0 ? 1.:-1.), v2);
1097
project(start, win0);
1099
double angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
1100
//angleDeg += start[1]>=0 ? 1.:180.;
1101
wstring str = StelUtils::radToHmsStrAdapt(lon).toStdWString();;
1103
if (angleDeg>90. || angleDeg<-90.)
1106
xshift=-font->getStrLen(str)-20.f;
1108
drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
1110
// Label at end of the arc
1111
StelUtils::sphe_to_rect(lon, lat+(length-0.0000001)*(start[1]>=0 ? 1.:-1.), v2);
1114
angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
1116
if (angleDeg>90. || angleDeg<-90.)
1119
xshift=-font->getStrLen(str)-20.f;
1121
StelUtils::rect_to_sphe(&lon, &lat, v);
1122
str = StelUtils::radToHmsStrAdapt(lon).toStdWString();;
1123
drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
1126
glColor4fv(tmpColor);
1131
/*************************************************************************
1132
draw a simple circle, 2d viewport coordinates in pixel
1133
*************************************************************************/
1134
void Projector::drawCircle(double x,double y,double r) const {
1135
if (r <= 1.0) return;
1136
const Vec2d center(x,y);
1137
const Vec2d v_center(0.5*viewport_xywh[2],
1138
0.5*viewport_xywh[3]);
1139
const double R = v_center.length();
1140
const double d = (v_center-center).length();
1141
if (d > r+R || d < r-R) return;
1142
const int segments = 180;
1143
const double phi = 2.0*M_PI/segments;
1144
const double cp = cos(phi);
1145
const double sp = sin(phi);
1148
glBegin(GL_LINE_LOOP);
1149
for (int i=0;i<=segments;i++) {
1150
glVertex2d(x+dx,y+dy);
1160
/*************************************************************************
1161
Same function but gives the already projected 2d position in input
1162
*************************************************************************/
1163
void Projector::drawSprite2dMode(double x, double y, double size) const
1165
// Use GL_POINT_SPRITE_ARB extension if available
1166
if (flagGlPointSprite)
1175
const double radius = size*0.5;
1178
glVertex2f(x-radius,y-radius);
1180
glVertex2f(x+radius,y-radius);
1182
glVertex2f(x+radius,y+radius);
1184
glVertex2f(x-radius,y+radius);
1188
/*************************************************************************
1189
Same function but with a rotation angle
1190
*************************************************************************/
1191
void Projector::drawSprite2dMode(double x, double y, double size, double rotation) const
1194
glTranslatef(x, y, 0.0);
1195
glRotatef(rotation,0.,0.,1.);
1196
const double radius = size*0.5;
1199
glVertex2f(-radius,-radius);
1201
glVertex2f(+radius,-radius);
1203
glVertex2f(+radius,+radius);
1205
glVertex2f(-radius,+radius);
1210
/*************************************************************************
1211
Draw the given polygon
1212
*************************************************************************/
1213
void Projector::drawPolygon(const StelGeom::Polygon& poly) const
1215
const int size = poly.size();
1220
glBegin(GL_LINE_LOOP);
1221
for (int i=0;i<size;++i)
1223
project(poly[i], win);
1230
/*************************************************************************
1231
Draw a GL_POINT at the given position
1232
*************************************************************************/
1233
void Projector::drawPoint2d(double x, double y) const
1235
if (flagGlPointSprite)
1237
glDisable(GL_POINT_SPRITE_ARB);
1241
glEnable(GL_POINT_SPRITE_ARB);
1250
/*************************************************************************
1251
Draw a rotated rectangle using the current texture at the given position
1252
*************************************************************************/
1253
void Projector::drawRectSprite2dMode(double x, double y, double sizex, double sizey, double rotation) const
1256
glTranslatef(x, y, 0.0);
1257
glRotatef(rotation,0.,0.,1.);
1258
const double radiusx = sizex*0.5;
1259
const double radiusy = sizey*0.5;
1262
glVertex2f(-radiusx,-radiusy);
1264
glVertex2f(+radiusx,-radiusy);
1266
glVertex2f(+radiusx,+radiusy);
1268
glVertex2f(-radiusx,+radiusy);
1273
/*************************************************************************
1274
Generalisation of glVertex3v for non linear mode. This method does not
1275
set correct values for the lighting operations.
1276
*************************************************************************/
1277
void Projector::drawVertex3v(const Vec3d& v) const
1285
///////////////////////////////////////////////////////////////////////////
1286
// Drawing methods for general (non-linear) mode
1288
void Projector::sSphere(GLdouble radius, GLdouble one_minus_oblateness,
1289
GLint slices, GLint stacks, int orient_inside) const
1291
// It is really good for performance to have Vec4f,Vec3f objects
1292
// static rather than on the stack. But why?
1293
// Is the constructor/destructor so expensive?
1294
static Vec3f lightPos3;
1295
GLboolean isLightOn;
1298
static Vec4f ambientLight;
1299
static Vec4f diffuseLight;
1301
glGetBooleanv(GL_LIGHTING, &isLightOn);
1305
glGetLightfv(GL_LIGHT0, GL_POSITION, lightPos3);
1306
lightPos3 -= modelViewMatrix * Vec3d(0.,0.,0.); // -posCenterEye
1307
lightPos3 = modelViewMatrix.transpose().multiplyWithoutTranslation(lightPos3);
1308
lightPos3.normalize();
1309
glGetLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
1310
glGetLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
1311
glDisable(GL_LIGHTING);
1322
t=0.0; // from inside texture is reversed
1330
const double drho = M_PI / stacks;
1331
assert(stacks<=MAX_STACKS);
1332
ComputeCosSinRho(drho,stacks);
1333
double *cos_sin_rho_p;
1335
const double dtheta = 2.0 * M_PI / slices;
1336
assert(slices<=MAX_SLICES);
1337
ComputeCosSinTheta(dtheta,slices);
1338
const double *cos_sin_theta_p;
1340
// texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
1341
// t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
1342
// cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
1343
const GLfloat ds = 1.0 / slices;
1344
const GLfloat dt = nsign / stacks; // from inside texture is reversed
1347
// draw intermediate as quad strips
1348
for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks;
1349
i++,cos_sin_rho_p+=2)
1351
glBegin(GL_QUAD_STRIP);
1353
for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;j++,cos_sin_theta_p+=2)
1355
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
1356
y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
1357
z = nsign * cos_sin_rho_p[0];
1361
c = nsign * lightPos3.dot(Vec3f(x * one_minus_oblateness,
1362
y * one_minus_oblateness,
1365
glColor3f(c*diffuseLight[0] + ambientLight[0],
1366
c*diffuseLight[1] + ambientLight[1],
1367
c*diffuseLight[2] + ambientLight[2]);
1369
drawVertex3(x * radius, y * radius, z * one_minus_oblateness * radius);
1370
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
1371
y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
1372
z = nsign * cos_sin_rho_p[2];
1373
glTexCoord2f(s, t - dt);
1376
c = nsign * lightPos3.dot(Vec3f(x * one_minus_oblateness,
1377
y * one_minus_oblateness,
1380
glColor3f(c*diffuseLight[0] + ambientLight[0],
1381
c*diffuseLight[1] + ambientLight[1],
1382
c*diffuseLight[2] + ambientLight[2]);
1384
drawVertex3(x * radius, y * radius, z * one_minus_oblateness * radius);
1392
glEnable(GL_LIGHTING);
1395
// Reimplementation of gluCylinder : glu is overrided for non standard projection
1396
void Projector::sCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks, int orient_inside) const
1398
static GLdouble da, r, dz;
1399
static GLfloat z, nsign;
1404
glCullFace(GL_FRONT);
1408
da = 2.0 * M_PI / slices;
1409
dz = height / stacks;
1411
GLfloat ds = 1.0 / slices;
1412
GLfloat dt = 1.0 / stacks;
1416
for (j = 0; j < stacks; j++)
1419
glBegin(GL_QUAD_STRIP);
1420
for (i = 0; i <= slices; i++)
1430
x = std::sin(i * da);
1431
y = std::cos(i * da);
1433
glNormal3f(x * nsign, y * nsign, 0);
1435
drawVertex3(x * r, y * r, z);
1436
glNormal3f(x * nsign, y * nsign, 0);
1437
glTexCoord2f(s, t + dt);
1438
drawVertex3(x * r, y * r, z + dz);
1447
glCullFace(GL_BACK);