~ubuntu-branches/debian/squeeze/stellarium/squeeze

« back to all changes in this revision

Viewing changes to src/Projector.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cédric Delfosse
  • Date: 2008-05-19 21:28:23 UTC
  • mfrom: (3.1.5 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080519212823-m5nfiuntxstxzxj7
Tags: 0.9.1-4
Add libxcursor-dev, libxfixes-dev, libxinerama-dev, libqt4-opengl-dev to
build-deps (Closes: #479906)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Stellarium
 
3
 * Copyright (C) 2003 Fabien Chereau
 
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
 * 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.
 
14
 *
 
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.
 
18
 */
 
19
 
 
20
#include <iostream>
 
21
#include <sstream>
 
22
#include <cstdio>
 
23
#include <cassert>
 
24
#include <map>
 
25
#include "GLee.h"
 
26
 
 
27
#if defined(__APPLE__) && defined(__MACH__)
 
28
#include <OpenGL/glu.h> /* Header File For The GLU Library */
 
29
#else
 
30
#include <GL/glu.h>     /* Header File For The GLU Library */
 
31
#endif
 
32
 
 
33
#include "Projector.hpp"
 
34
#include "InitParser.hpp"
 
35
#include "MappingClasses.hpp"
 
36
#include "StelApp.hpp"
 
37
#include <QDebug>
 
38
 
 
39
const char *Projector::maskTypeToString(PROJECTOR_MASK_TYPE type)
 
40
{
 
41
        if(type == DISK )
 
42
                return "disk";
 
43
        else
 
44
                return "none";
 
45
}
 
46
 
 
47
Projector::PROJECTOR_MASK_TYPE Projector::stringToMaskType(const string &s)
 
48
{
 
49
        if (s=="disk")
 
50
                return DISK;
 
51
        return NONE;
 
52
}
 
53
 
 
54
void Projector::registerProjectionMapping(Mapping *c)
 
55
{
 
56
        if (c) projectionMapping[c->getName()] = c;
 
57
}
 
58
 
 
59
void Projector::init(const InitParser& conf)
 
60
{
 
61
        // Video Section
 
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);
 
76
        const int viewport_x
 
77
          = conf.get_int("projection","viewport_x",
 
78
                         (screen_w-viewport_width)/2);
 
79
        const int viewport_y
 
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);
 
92
 
 
93
 
 
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;
 
99
        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;
 
104
        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;
 
109
        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;
 
114
        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;
 
119
        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;
 
124
 
 
125
        setFlagGravityLabels( conf.get_boolean("viewing:flag_gravity_labels") );
 
126
 
 
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());
 
134
 
 
135
        tmpstr = conf.get_str("projection:type");
 
136
        setCurrentProjection(tmpstr);
 
137
 
 
138
        initFov = conf.get_double ("navigation","init_fov",60.);
 
139
        setFov(initFov);
 
140
 
 
141
        //glFrontFace(needGlFrontFaceCW()?GL_CW:GL_CCW);
 
142
 
 
143
        flagGlPointSprite = conf.get_boolean("projection","flag_use_gl_point_sprite",false);
 
144
        flagGlPointSprite = flagGlPointSprite && GLEE_ARB_point_sprite;
 
145
        if (flagGlPointSprite)
 
146
        {
 
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;
 
151
        } else {
 
152
                //cerr << "WARNING: GL_ARB_point_sprite not available" << endl;
 
153
        }
 
154
}
 
155
 
 
156
void Projector::windowHasBeenResized(int width,int height)
 
157
{
 
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));
 
160
}
 
161
 
 
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])),
 
169
                gravityLabels(0),
 
170
                mapping(NULL)
 
171
{
 
172
        flip_horz = 1.0;
 
173
        flip_vert = 1.0;
 
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);
 
179
 
 
180
        setFov(_fov);
 
181
}
 
182
 
 
183
Projector::~Projector()
 
184
{}
 
185
 
 
186
 
 
187
void Projector::setViewport(int x, int y, int w, int h,
 
188
                            double cx,double cy,double fov_diam)
 
189
{
 
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();
 
201
}
 
202
 
 
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
 
208
{
 
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]));
 
214
        return result;
 
215
}
 
216
 
 
217
/*************************************************************************
 
218
 Return a convex polygon on the sphere which includes the viewport in the 
 
219
 current frame
 
220
*************************************************************************/
 
221
StelGeom::ConvexPolygon Projector::getViewportConvexPolygon(double marginX, double marginY) const
 
222
{
 
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);
 
228
        e0.normalize();
 
229
        e1.normalize();
 
230
        e2.normalize();
 
231
        e3.normalize();
 
232
        return StelGeom::ConvexPolygon(e0, e3, e2, e1);
 
233
}
 
234
 
 
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) &&
 
243
      fov < 360.0) {
 
244
    Vec3d e0,e1,e2,e3;
 
245
    bool ok;
 
246
    if (maskType == DISK) {
 
247
      if (fov >= 120.0) {
 
248
        unProject(viewport_center[0],viewport_center[1],e0);
 
249
        StelGeom::ConvexS rval(1);
 
250
        rval[0].n = e0;
 
251
        rval[0].d = (fov<360.0) ? cos(fov*(M_PI/360.0)) : -1.0;
 
252
        return rval;
 
253
      }
 
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);
 
263
          } else {
 
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);
 
268
          }
 
269
    } else {
 
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);
 
276
      } else {
 
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);
 
279
      }
 
280
    }
 
281
    if (ok) {
 
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);
 
291
        rval[0] = h0;
 
292
        rval[1] = h1;
 
293
        rval[2] = h2;
 
294
        rval[3] = h3;
 
295
        return rval;
 
296
      } else {
 
297
        Vec3d middle;
 
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;
 
302
          if (d > h) d = h;
 
303
          h = middle*e2;
 
304
          if (d > h) d = h;
 
305
          h = middle*e3;
 
306
          if (d > h) d = h;
 
307
          StelGeom::ConvexS rval(1);
 
308
          rval[0].n = middle;
 
309
          rval[0].d = d;
 
310
          return rval;
 
311
        }
 
312
      }
 
313
    }
 
314
  }
 
315
  StelGeom::ConvexS rval(1);
 
316
  rval[0].n = Vec3d(1.0,0.0,0.0);
 
317
  rval[0].d = -2.0;
 
318
  return rval;
 
319
}
 
320
 
 
321
void Projector::setFov(double f)
 
322
{
 
323
 
 
324
//      cout << "Set fov to " << f << " " << max_fov << " " << min_fov << endl;
 
325
        fov = f;
 
326
        if (f>max_fov)
 
327
                fov = max_fov;
 
328
        if (f<min_fov)
 
329
                fov = min_fov;
 
330
        pixel_per_rad = 0.5 * viewport_fov_diameter
 
331
          / (mapping ? mapping->fovToViewScalingFactor(fov*(M_PI/360.0)) : 1.0);
 
332
}
 
333
 
 
334
 
 
335
void Projector::setMaxFov(double max)
 
336
{
 
337
        max_fov = max;
 
338
        if (fov > max)
 
339
        {
 
340
                setFov(max);
 
341
        }
 
342
 
 
343
}
 
344
 
 
345
void Projector::set_clipping_planes(double znear, double zfar)
 
346
{
 
347
        zNear = znear;
 
348
        zFar = zfar;
 
349
}
 
350
 
 
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)
 
356
{
 
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;
 
361
}
 
362
 
 
363
 
 
364
/*************************************************************************
 
365
 Set the frame in which we want to draw from now on
 
366
*************************************************************************/
 
367
void Projector::setCurrentFrame(FRAME_TYPE frameType) const
 
368
{
 
369
        switch (frameType)
 
370
        {
 
371
        case FRAME_LOCAL:
 
372
                setCustomFrame(mat_local_to_eye);
 
373
                break;
 
374
        case FRAME_HELIO:
 
375
                setCustomFrame(mat_helio_to_eye);
 
376
                break;
 
377
        case FRAME_EARTH_EQU:
 
378
                setCustomFrame(mat_earth_equ_to_eye);
 
379
                break;
 
380
        case FRAME_J2000:
 
381
                setCustomFrame(mat_j2000_to_eye);
 
382
                break;
 
383
        default:
 
384
                cerr << "Unknown reference frame type: " << (int)frameType << "." << endl;
 
385
        }
 
386
}
 
387
 
 
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
 
393
{
 
394
        modelViewMatrix = m;
 
395
}
 
396
 
 
397
/*************************************************************************
 
398
 Init the real openGL Matrices to a 2d orthographic projection
 
399
*************************************************************************/
 
400
void Projector::initGlMatrixOrtho2d(void) const
 
401
{
 
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);
 
405
        glLoadIdentity();
 
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);
 
409
        glLoadIdentity();
 
410
}
 
411
 
 
412
/*************************************************************************
 
413
 Return an openGL Matrix for a perspective projection.
 
414
*************************************************************************/
 
415
//Mat4d Projector::getGlMatrixPerspective(void) const
 
416
//{
 
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.);    
 
423
//}
 
424
 
 
425
/*************************************************************************
 
426
 Set the current projection mapping to use
 
427
*************************************************************************/
 
428
void Projector::setCurrentProjection(const std::string& projectionName)
 
429
{
 
430
        if (currentProjectionType==projectionName)
 
431
                return;
 
432
 
 
433
        std::map<std::string,const Mapping*>::const_iterator
 
434
                i(projectionMapping.find(projectionName));
 
435
        if (i!=projectionMapping.end())
 
436
        {
 
437
                currentProjectionType = projectionName;
 
438
 
 
439
                // Redefine the projection functions
 
440
                mapping = i->second;
 
441
                min_fov = mapping->minFov;
 
442
                max_fov = mapping->maxFov;
 
443
 
 
444
                setFov(fov);
 
445
                initGlMatrixOrtho2d();
 
446
        }
 
447
        else
 
448
        {
 
449
                cerr << "Unknown projection type: " << projectionName << "." << endl;
 
450
        }
 
451
}
 
452
 
 
453
/*************************************************************************
 
454
 Project the vector v from the current frame into the viewport
 
455
*************************************************************************/
 
456
// bool Projector::project(const Vec3d &v, Vec3d &win) const
 
457
// {
 
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);
 
473
//      return rval;
 
474
// }
 
475
 
 
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
 
480
{
 
481
        v[0] = flip_horz * (x - viewport_center[0]) / pixel_per_rad;
 
482
        v[1] = flip_vert * (y - viewport_center[1]) / pixel_per_rad;
 
483
        v[2] = 0;
 
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.
 
489
 
 
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;
 
496
 
 
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);
 
501
        return rval;
 
502
}
 
503
 
 
504
 
 
505
 
 
506
 
 
507
///////////////////////////////////////////////////////////////////////////
 
508
// Standard methods for drawing primitives
 
509
 
 
510
// Fill with black around the circle
 
511
void Projector::draw_viewport_shape(void)
 
512
{
 
513
        if (maskType != DISK)
 
514
                return;
 
515
 
 
516
        glDisable(GL_BLEND);
 
517
        glColor3f(0.f,0.f,0.f);
 
518
        glPushMatrix();
 
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
 
523
        gluDeleteQuadric(p);
 
524
        glPopMatrix();
 
525
}
 
526
 
 
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)];
 
531
 
 
532
static
 
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);
 
538
  *cos_sin++ = 1.0;
 
539
  *cos_sin++ = 0.0;
 
540
  *--cos_sin_rev = -cos_sin[-1];
 
541
  *--cos_sin_rev =  cos_sin[-2];
 
542
  *cos_sin++ = c;
 
543
  *cos_sin++ = s;
 
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;
 
549
    cos_sin += 2;
 
550
    *--cos_sin_rev = -cos_sin[-1];
 
551
    *--cos_sin_rev =  cos_sin[-2];
 
552
  }
 
553
}
 
554
 
 
555
static
 
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);
 
561
  *cos_sin++ = 1.0;
 
562
  *cos_sin++ = 0.0;
 
563
  *--cos_sin_rev =  cos_sin[-1];
 
564
  *--cos_sin_rev = -cos_sin[-2];
 
565
  *cos_sin++ = c;
 
566
  *cos_sin++ = s;
 
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;
 
572
    cos_sin += 2;
 
573
    *--cos_sin_rev =  cos_sin[-1];
 
574
    *--cos_sin_rev = -cos_sin[-2];
 
575
    segments--;
 
576
  }
 
577
}
 
578
 
 
579
 
 
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
 
583
{
 
584
        glPushMatrix();
 
585
        glLoadMatrixd(modelViewMatrix);
 
586
 
 
587
        if (one_minus_oblateness == 1.0)
 
588
        { // gluSphere seems to have hardware acceleration
 
589
                GLUquadricObj * p = gluNewQuadric();
 
590
                gluQuadricTexture(p,GL_TRUE);
 
591
                if (orient_inside)
 
592
                        gluQuadricOrientation(p, GLU_INSIDE);
 
593
                gluSphere(p, radius, slices, stacks);
 
594
                gluDeleteQuadric(p);
 
595
        }
 
596
        else
 
597
        {
 
598
                GLfloat x, y, z;
 
599
                GLfloat s, t, ds, dt;
 
600
                GLint i, j;
 
601
                GLfloat nsign;
 
602
 
 
603
                if (orient_inside)
 
604
                        nsign = -1.0;
 
605
                else
 
606
                        nsign = 1.0;
 
607
 
 
608
                const double drho = M_PI / stacks;
 
609
                assert(stacks<=MAX_STACKS);
 
610
                ComputeCosSinRho(drho,stacks);
 
611
                double *cos_sin_rho_p;
 
612
 
 
613
                const double dtheta = 2.0 * M_PI / slices;
 
614
                assert(slices<=MAX_SLICES);
 
615
                ComputeCosSinTheta(dtheta,slices);
 
616
                double *cos_sin_theta_p;
 
617
 
 
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)
 
621
                ds = 1.0 / slices;
 
622
                dt = 1.0 / stacks;
 
623
                t = 1.0;            // because loop now runs from 0
 
624
 
 
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)
 
628
                {
 
629
                        glBegin(GL_QUAD_STRIP);
 
630
                        s = 0.0;
 
631
                        for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;
 
632
                             j++,cos_sin_theta_p+=2)
 
633
                        {
 
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,
 
639
                                           z * nsign);
 
640
                                glTexCoord2f(s, t);
 
641
                                glVertex3d(x * radius,
 
642
                                           y * 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,
 
649
                                           z * nsign);
 
650
                                glTexCoord2f(s, t - dt);
 
651
                                s += ds;
 
652
                                glVertex3d(x * radius,
 
653
                                           y * radius,
 
654
                                           one_minus_oblateness * z * radius);
 
655
                        }
 
656
                        glEnd();
 
657
                        t -= dt;
 
658
                }
 
659
        }
 
660
 
 
661
        glPopMatrix();
 
662
}
 
663
 
 
664
 
 
665
void Projector::sFanDisk(double radius,int inner_fan_slices,int level) const {
 
666
  assert(level<64);
 
667
  double rad[64];
 
668
  int i,j;
 
669
  rad[level] = radius;
 
670
//  for (i=level-1;i>=0;i--) {
 
671
//    double f = ((i+1)/(double)(level+1));
 
672
//    rad[i] = radius*f*f;
 
673
//  }
 
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;
 
676
  }
 
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;
 
682
  int slices_step = 2;
 
683
  for (i=level;i>0;i--,slices_step<<=1) {
 
684
    for (j=0,cos_sin_theta_p=cos_sin_theta;
 
685
         j<slices;
 
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));
 
691
      drawVertex3(x,y,0);
 
692
 
 
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));
 
696
      drawVertex3(x,y,0);
 
697
 
 
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));
 
701
      drawVertex3(x,y,0);
 
702
 
 
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));
 
706
      drawVertex3(x,y,0);
 
707
 
 
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));
 
711
      drawVertex3(x,y,0);
 
712
      glEnd();
 
713
    }
 
714
  }
 
715
    // draw the inner polygon
 
716
  slices_step>>=1;
 
717
  glBegin(GL_POLYGON);
 
718
  for (j=0,cos_sin_theta_p=cos_sin_theta;
 
719
       j<=slices;
 
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));
 
724
    drawVertex3(x,y,0);
 
725
  }
 
726
  glEnd();
 
727
}
 
728
 
 
729
 
 
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
 
732
{
 
733
        GLint i,j;
 
734
        const GLfloat nsign = orient_inside ? -1 : 1;
 
735
    double r;
 
736
        const double dr = radius / stacks;
 
737
 
 
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;
 
743
 
 
744
        // draw intermediate stacks as quad strips
 
745
        for (i = 0, r = 0.0; i < stacks; i++, r+=dr)
 
746
        {
 
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)
 
750
                {
 
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);
 
761
                }
 
762
                glEnd();
 
763
        }
 
764
}
 
765
 
 
766
void Projector::sRing(GLdouble r_min, GLdouble r_max, GLint slices, GLint stacks, int orient_inside) const
 
767
{
 
768
        double x,y;
 
769
        int j;
 
770
 
 
771
        const double nsign = (orient_inside)?-1.0:1.0;
 
772
 
 
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;
 
779
 
 
780
 
 
781
        // draw intermediate stacks as quad strips
 
782
        for (double r = r_min; r < r_max; r+=dr)
 
783
        {
 
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;
 
788
                        j<=slices;
 
789
                        j++,cos_sin_theta_p+=2)
 
790
                {
 
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);
 
801
                }
 
802
                glEnd();
 
803
        }
 
804
}
 
805
 
 
806
static void sSphereMapTexCoordFast(double rho_div_fov, double costheta, double sintheta)
 
807
{
 
808
        if (rho_div_fov>0.5)
 
809
                rho_div_fov=0.5;
 
810
        glTexCoord2d(0.5 + rho_div_fov * costheta,
 
811
                     0.5 + rho_div_fov * sintheta);
 
812
}
 
813
 
 
814
void Projector::sSphere_map(GLdouble radius, GLint slices, GLint stacks,
 
815
                            double texture_fov, int orient_inside) const
 
816
{
 
817
        double rho,x,y,z;
 
818
        int i, j;
 
819
        const double nsign = orient_inside?-1:1;
 
820
 
 
821
        const double drho = M_PI / stacks;
 
822
        assert(stacks<=MAX_STACKS);
 
823
        ComputeCosSinRho(drho,stacks);
 
824
        double *cos_sin_rho_p;
 
825
 
 
826
        const double dtheta = 2.0 * M_PI / slices;
 
827
        assert(slices<=MAX_SLICES);
 
828
 
 
829
        ComputeCosSinTheta(dtheta,slices);
 
830
        double *cos_sin_theta_p;
 
831
 
 
832
 
 
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)
 
836
 
 
837
        const int imax = stacks;
 
838
 
 
839
        // draw intermediate stacks as quad strips
 
840
        if (!orient_inside) // nsign==1
 
841
        {
 
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)
 
844
                {
 
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)
 
848
                        {
 
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,
 
854
                                                       cos_sin_theta_p[0],
 
855
                                                       cos_sin_theta_p[1]);
 
856
                                drawVertex3(x * radius, y * radius, z * radius);
 
857
 
 
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,
 
863
                                                       cos_sin_theta_p[0],
 
864
                                                       cos_sin_theta_p[1]);
 
865
                                drawVertex3(x * radius, y * radius, z * radius);
 
866
                        }
 
867
                        glEnd();
 
868
                }
 
869
        }
 
870
        else
 
871
        {
 
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)
 
874
                {
 
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)
 
878
                        {
 
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,
 
884
                                                       cos_sin_theta_p[0],
 
885
                                                       -cos_sin_theta_p[1]);
 
886
                                drawVertex3(x * radius, y * radius, z * radius);
 
887
 
 
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,
 
893
                                                       cos_sin_theta_p[0],
 
894
                                                       -cos_sin_theta_p[1]);
 
895
                                drawVertex3(x * radius, y * radius, z * radius);
 
896
                        }
 
897
                        glEnd();
 
898
                }
 
899
        }
 
900
}
 
901
 
 
902
 
 
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
 
905
{
 
906
        glPushMatrix();
 
907
        glLoadMatrixd(modelViewMatrix);
 
908
        GLUquadricObj * p = gluNewQuadric();
 
909
        gluQuadricTexture(p,GL_TRUE);
 
910
        if (orient_inside)
 
911
        {
 
912
                glCullFace(GL_FRONT);
 
913
        }
 
914
        gluCylinder(p, radius, radius, height, slices, stacks);
 
915
        gluDeleteQuadric(p);
 
916
        glPopMatrix();
 
917
        if (orient_inside)
 
918
        {
 
919
                glCullFace(GL_BACK);
 
920
        }
 
921
}
 
922
 
 
923
 
 
924
void Projector::drawTextGravity180(const SFont* font, float x, float y, const wstring& ws,
 
925
                                   bool speed_optimize, float xshift, float yshift) const
 
926
{
 
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);
 
931
 
 
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)
 
934
                return;
 
935
 
 
936
        theta = M_PI + std::atan2(dx, dy - 1);
 
937
        psi = std::atan2((float)font->getStrLen(ws)/ws.length(),d + 1) * 180./M_PI;
 
938
 
 
939
        if (psi>5)
 
940
                psi = 5;
 
941
        glPushMatrix();
 
942
        glTranslatef(x,y,0);
 
943
        if(gravityLabels)
 
944
                glRotatef(theta*180./M_PI,0,0,-1);
 
945
        glTranslatef(xshift, -yshift, 0);
 
946
        glScalef(1, -1, 1);
 
947
 
 
948
        glEnable(GL_BLEND);
 
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)
 
952
        {
 
953
                if( !speed_optimize )
 
954
                {
 
955
                        font->print_char_outlined(ws[i]);
 
956
                }
 
957
                else
 
958
                {
 
959
                        font->print_char(ws[i]);
 
960
                }
 
961
 
 
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);
 
966
 
 
967
                if( !speed_optimize )
 
968
                {
 
969
                        psi = std::atan2((float)font->getStrLen(ws.substr(i,1))*1.05f,(float)d) * 180./M_PI;
 
970
                        if (psi>5)
 
971
                                psi = 5;
 
972
                }
 
973
                
 
974
                glRotatef(psi,0,0,-1);
 
975
        }
 
976
        glPopMatrix();
 
977
}
 
978
 
 
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
 
983
{
 
984
        if (gravityLabels && !noGravity)
 
985
        {
 
986
                drawTextGravity180(font, x, y, str, true, xshift, yshift);
 
987
                return;
 
988
        }
 
989
        
 
990
        glPushMatrix();
 
991
        glTranslatef(x,y,0);
 
992
        glRotatef(angleDeg,0,0,1);
 
993
        glTranslatef(0,font->getLineHeight(),0);
 
994
        font->print(xshift, yshift, str);
 
995
        glPopMatrix();
 
996
}
 
997
 
 
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
 
1002
{
 
1003
        if (nbSeg==-1)
 
1004
                nbSeg = 4 + (int)(length*44./(2.*M_PI));
 
1005
        const Mat4d dRa = Mat4d::zrotation(length/nbSeg);
 
1006
 
 
1007
        Vec3d v(start);
 
1008
        Vec3d pt1;
 
1009
        glBegin(GL_LINE_STRIP);
 
1010
        for (int i=0;i<=nbSeg;++i)
 
1011
        {
 
1012
                project(v, pt1);
 
1013
                glVertex2f(pt1[0],pt1[1]);
 
1014
                dRa.transfo(v);
 
1015
        }
 
1016
        glEnd();
 
1017
 
 
1018
        // Draw label if needed
 
1019
        if (labelAxis)
 
1020
        {
 
1021
                static GLfloat tmpColor[4];
 
1022
                if (textColor)
 
1023
                {
 
1024
                        glGetFloatv(GL_CURRENT_COLOR, tmpColor);
 
1025
                        glColor4fv(*textColor);
 
1026
                }
 
1027
                double lon, lat;
 
1028
                StelUtils::rect_to_sphe(&lon, &lat, start);
 
1029
                Vec3d win0, win1;
 
1030
                Vec3d v1, v2;
 
1031
                StelUtils::sphe_to_rect(lon+0.0000001, lat, v2);
 
1032
                project(start, win0);
 
1033
                project(v2, win1);
 
1034
                double angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
 
1035
                const wstring str = StelUtils::radToDmsStrAdapt(lat).toStdWString();
 
1036
                float xshift=5;
 
1037
                if (angleDeg>90. || angleDeg<-90.)
 
1038
                {
 
1039
                        angleDeg+=180.;
 
1040
                        xshift=-font->getStrLen(str)-5.f;
 
1041
                }
 
1042
                drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
 
1043
 
 
1044
                // Label at end of the arc
 
1045
                StelUtils::sphe_to_rect(lon+length-0.0000001, lat, v2);
 
1046
                project(v, win0);
 
1047
                project(v2, win1);
 
1048
                angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
 
1049
                xshift=5;
 
1050
                if (angleDeg>90. || angleDeg<-90.)
 
1051
                {
 
1052
                        angleDeg+=180.;
 
1053
                        xshift=-font->getStrLen(str)-5.f;
 
1054
                }
 
1055
                drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
 
1056
                
 
1057
                if (textColor)
 
1058
                        glColor4fv(tmpColor);
 
1059
        }
 
1060
}
 
1061
 
 
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
 
1066
{
 
1067
        if (nbSeg==-1)
 
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);
 
1071
 
 
1072
        Vec3d v(start);
 
1073
        Vec3d pt1;
 
1074
        glBegin(GL_LINE_STRIP);
 
1075
        for (int i=0;i<=nbSeg;++i)
 
1076
        {
 
1077
                project(v, pt1);
 
1078
                glVertex2f(pt1[0],pt1[1]);
 
1079
                dDe.transfo(v);
 
1080
        }
 
1081
        glEnd();
 
1082
 
 
1083
        // Draw label if needed
 
1084
        if (labelAxis)
 
1085
        {
 
1086
                static GLfloat tmpColor[4];
 
1087
                if (textColor)
 
1088
                {
 
1089
                        glGetFloatv(GL_CURRENT_COLOR, tmpColor);
 
1090
                        glColor4fv(*textColor);
 
1091
                }
 
1092
                double lon, lat;
 
1093
                StelUtils::rect_to_sphe(&lon, &lat, start);
 
1094
                Vec3d win0, win1;
 
1095
                Vec3d v2;
 
1096
                StelUtils::sphe_to_rect(lon, lat+0.0000001*(start[1]>=0 ? 1.:-1.), v2);
 
1097
                project(start, win0);
 
1098
                project(v2, win1);
 
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();;
 
1102
                float xshift=20;
 
1103
                if (angleDeg>90. || angleDeg<-90.)
 
1104
                {
 
1105
                        angleDeg+=180.;
 
1106
                        xshift=-font->getStrLen(str)-20.f;
 
1107
                }
 
1108
                drawText(font, win1[0], win1[1], str, angleDeg, xshift, 3);
 
1109
 
 
1110
                // Label at end of the arc
 
1111
                StelUtils::sphe_to_rect(lon, lat+(length-0.0000001)*(start[1]>=0 ? 1.:-1.), v2);
 
1112
                project(v, win0);
 
1113
                project(v2, win1);
 
1114
                angleDeg = std::atan2(win1[1]-win0[1], win1[0]-win0[0])*180./M_PI;
 
1115
                xshift=20;
 
1116
                if (angleDeg>90. || angleDeg<-90.)
 
1117
                {
 
1118
                        angleDeg+=180.;
 
1119
                        xshift=-font->getStrLen(str)-20.f;
 
1120
                }
 
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);
 
1124
                
 
1125
                if (textColor)
 
1126
                        glColor4fv(tmpColor);
 
1127
        }
 
1128
}
 
1129
 
 
1130
 
 
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);
 
1146
  double dx = r;
 
1147
  double dy = 0;
 
1148
  glBegin(GL_LINE_LOOP);
 
1149
  for (int i=0;i<=segments;i++) {
 
1150
    glVertex2d(x+dx,y+dy);
 
1151
    r = dx*cp-dy*sp;
 
1152
    dy = dx*sp+dy*cp;
 
1153
    dx = r;
 
1154
  }
 
1155
  glEnd();
 
1156
}
 
1157
 
 
1158
 
 
1159
 
 
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
 
1164
{
 
1165
        // Use GL_POINT_SPRITE_ARB extension if available
 
1166
        if (flagGlPointSprite)
 
1167
        {
 
1168
                glPointSize(size);
 
1169
                glBegin(GL_POINTS);
 
1170
                        glVertex2f(x,y);
 
1171
                glEnd();
 
1172
                return;
 
1173
        }
 
1174
 
 
1175
        const double radius = size*0.5;
 
1176
        glBegin(GL_QUADS );
 
1177
                glTexCoord2i(0,0);
 
1178
                glVertex2f(x-radius,y-radius);
 
1179
                glTexCoord2i(1,0);
 
1180
                glVertex2f(x+radius,y-radius);
 
1181
                glTexCoord2i(1,1);
 
1182
                glVertex2f(x+radius,y+radius);
 
1183
                glTexCoord2i(0,1);
 
1184
                glVertex2f(x-radius,y+radius);
 
1185
        glEnd();
 
1186
}
 
1187
 
 
1188
/*************************************************************************
 
1189
 Same function but with a rotation angle
 
1190
*************************************************************************/
 
1191
void Projector::drawSprite2dMode(double x, double y, double size, double rotation) const
 
1192
{
 
1193
        glPushMatrix();
 
1194
        glTranslatef(x, y, 0.0);
 
1195
        glRotatef(rotation,0.,0.,1.);
 
1196
        const double radius = size*0.5;
 
1197
        glBegin(GL_QUADS );
 
1198
                glTexCoord2i(0,0);
 
1199
                glVertex2f(-radius,-radius);
 
1200
                glTexCoord2i(1,0);
 
1201
                glVertex2f(+radius,-radius);
 
1202
                glTexCoord2i(1,1);
 
1203
                glVertex2f(+radius,+radius);
 
1204
                glTexCoord2i(0,1);
 
1205
                glVertex2f(-radius,+radius);
 
1206
        glEnd();
 
1207
        glPopMatrix();
 
1208
}
 
1209
 
 
1210
/*************************************************************************
 
1211
 Draw the given polygon
 
1212
*************************************************************************/
 
1213
void Projector::drawPolygon(const StelGeom::Polygon& poly) const
 
1214
{
 
1215
        const int size = poly.size();
 
1216
        if (size<3)
 
1217
                return;
 
1218
 
 
1219
        Vec3d win;      
 
1220
        glBegin(GL_LINE_LOOP);
 
1221
        for (int i=0;i<size;++i)
 
1222
        {
 
1223
                project(poly[i], win);
 
1224
                glVertex3dv(win);
 
1225
        }
 
1226
        glEnd();
 
1227
}
 
1228
        
 
1229
 
 
1230
/*************************************************************************
 
1231
 Draw a GL_POINT at the given position
 
1232
*************************************************************************/
 
1233
void Projector::drawPoint2d(double x, double y) const
 
1234
{
 
1235
        if (flagGlPointSprite)
 
1236
        {
 
1237
                glDisable(GL_POINT_SPRITE_ARB);
 
1238
                glBegin(GL_POINTS);
 
1239
                        glVertex2f(x, y);
 
1240
                glEnd();
 
1241
                glEnable(GL_POINT_SPRITE_ARB);
 
1242
                return;
 
1243
        }
 
1244
        
 
1245
        glBegin(GL_POINTS);
 
1246
                glVertex2f(x, y);
 
1247
        glEnd();
 
1248
}
 
1249
 
 
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
 
1254
{
 
1255
        glPushMatrix();
 
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;
 
1260
        glBegin(GL_QUADS );
 
1261
                glTexCoord2i(0,0);
 
1262
                glVertex2f(-radiusx,-radiusy);
 
1263
                glTexCoord2i(1,0);
 
1264
                glVertex2f(+radiusx,-radiusy);
 
1265
                glTexCoord2i(1,1);
 
1266
                glVertex2f(+radiusx,+radiusy);
 
1267
                glTexCoord2i(0,1);
 
1268
                glVertex2f(-radiusx,+radiusy);
 
1269
        glEnd();
 
1270
        glPopMatrix();
 
1271
}
 
1272
 
 
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
 
1278
{
 
1279
        Vec3d win;
 
1280
        project(v, win);
 
1281
        glVertex3dv(win);
 
1282
}
 
1283
 
 
1284
 
 
1285
///////////////////////////////////////////////////////////////////////////
 
1286
// Drawing methods for general (non-linear) mode
 
1287
 
 
1288
void Projector::sSphere(GLdouble radius, GLdouble one_minus_oblateness,
 
1289
                        GLint slices, GLint stacks, int orient_inside) const
 
1290
{
 
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;
 
1296
        float c;
 
1297
 
 
1298
        static Vec4f ambientLight;
 
1299
        static Vec4f diffuseLight;
 
1300
 
 
1301
        glGetBooleanv(GL_LIGHTING, &isLightOn);
 
1302
 
 
1303
        if (isLightOn)
 
1304
        {
 
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);
 
1312
        }
 
1313
 
 
1314
        GLfloat x, y, z;
 
1315
        GLfloat s, t;
 
1316
        GLint i, j;
 
1317
        GLfloat nsign;
 
1318
 
 
1319
        if (orient_inside)
 
1320
        {
 
1321
                nsign = -1.0;
 
1322
                t=0.0; // from inside texture is reversed
 
1323
        }
 
1324
        else
 
1325
        {
 
1326
                nsign = 1.0;
 
1327
                t=1.0;
 
1328
        }
 
1329
 
 
1330
        const double drho = M_PI / stacks;
 
1331
        assert(stacks<=MAX_STACKS);
 
1332
        ComputeCosSinRho(drho,stacks);
 
1333
        double *cos_sin_rho_p;
 
1334
 
 
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;
 
1339
 
 
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
 
1345
 
 
1346
 
 
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)
 
1350
        {
 
1351
                glBegin(GL_QUAD_STRIP);
 
1352
                s = 0.0;
 
1353
                for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;j++,cos_sin_theta_p+=2)
 
1354
                {
 
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];
 
1358
                        glTexCoord2f(s, t);
 
1359
                        if (isLightOn)
 
1360
                        {
 
1361
                                c = nsign * lightPos3.dot(Vec3f(x * one_minus_oblateness,
 
1362
                                                                y * one_minus_oblateness,
 
1363
                                                                z));
 
1364
                                if (c<0) {c=0;}
 
1365
                                glColor3f(c*diffuseLight[0] + ambientLight[0],
 
1366
                                          c*diffuseLight[1] + ambientLight[1],
 
1367
                                          c*diffuseLight[2] + ambientLight[2]);
 
1368
                        }
 
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);
 
1374
                        if (isLightOn)
 
1375
                        {
 
1376
                                c = nsign * lightPos3.dot(Vec3f(x * one_minus_oblateness,
 
1377
                                                                y * one_minus_oblateness,
 
1378
                                                                z));
 
1379
                                if (c<0) {c=0;}
 
1380
                                glColor3f(c*diffuseLight[0] + ambientLight[0],
 
1381
                                          c*diffuseLight[1] + ambientLight[1],
 
1382
                                          c*diffuseLight[2] + ambientLight[2]);
 
1383
                        }
 
1384
                        drawVertex3(x * radius, y * radius, z * one_minus_oblateness * radius);
 
1385
                        s += ds;
 
1386
                }
 
1387
                glEnd();
 
1388
                t -= dt;
 
1389
        }
 
1390
 
 
1391
        if (isLightOn)
 
1392
                glEnable(GL_LIGHTING);
 
1393
}
 
1394
 
 
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
 
1397
{
 
1398
        static GLdouble da, r, dz;
 
1399
        static GLfloat z, nsign;
 
1400
        static GLint i, j;
 
1401
 
 
1402
        nsign = 1.0;
 
1403
        if (orient_inside)
 
1404
                glCullFace(GL_FRONT);
 
1405
        //nsign = -1.0;
 
1406
        //else nsign = 1.0;
 
1407
 
 
1408
        da = 2.0 * M_PI / slices;
 
1409
        dz = height / stacks;
 
1410
 
 
1411
        GLfloat ds = 1.0 / slices;
 
1412
        GLfloat dt = 1.0 / stacks;
 
1413
        GLfloat t = 0.0;
 
1414
        z = 0.0;
 
1415
        r = radius;
 
1416
        for (j = 0; j < stacks; j++)
 
1417
        {
 
1418
                GLfloat s = 0.0;
 
1419
                glBegin(GL_QUAD_STRIP);
 
1420
                for (i = 0; i <= slices; i++)
 
1421
                {
 
1422
                        GLfloat x, y;
 
1423
                        if (i == slices)
 
1424
                        {
 
1425
                                x = std::sin(0.0f);
 
1426
                                y = std::cos(0.0f);
 
1427
                        }
 
1428
                        else
 
1429
                        {
 
1430
                                x = std::sin(i * da);
 
1431
                                y = std::cos(i * da);
 
1432
                        }
 
1433
                        glNormal3f(x * nsign, y * nsign, 0);
 
1434
                        glTexCoord2f(s, t);
 
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);
 
1439
                        s += ds;
 
1440
                }                       /* for slices */
 
1441
                glEnd();
 
1442
                t += dt;
 
1443
                z += dz;
 
1444
        }                               /* for stacks */
 
1445
 
 
1446
        if (orient_inside)
 
1447
                glCullFace(GL_BACK);
 
1448
}