• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 3996069357

pending completion
3996069357

push

github

Ruslan Kabatsayev
Shorten some lines

5 of 5 new or added lines in 1 file covered. (100.0%)

14663 of 124076 relevant lines covered (11.82%)

22035.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/StelPainter.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2008 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., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18
 */
19

20
#include "StelPainter.hpp"
21

22
#include "StelApp.hpp"
23
#include "StelMainView.hpp"
24
#include "StelLocaleMgr.hpp"
25
#include "StelProjector.hpp"
26
#include "StelProjectorClasses.hpp"
27
#include "StelUtils.hpp"
28
#include "StelTextureMgr.hpp"
29
#include "SaturationShader.hpp"
30

31
#include <QDebug>
32
#include <QString>
33
#include <QSettings>
34
#include <QPainter>
35
#include <QMutex>
36
#include <QVarLengthArray>
37
#include <QPaintEngine>
38
#include <QCache>
39
#include <QOpenGLVertexArrayObject>
40
#include <QOpenGLPaintDevice>
41
#include <QOpenGLBuffer>
42
#include <QOpenGLShader>
43
#include <QOpenGLTexture>
44
#include <QApplication>
45

46
static const int TEX_CACHE_LIMIT = 7000000;
47

48
#ifndef NDEBUG
49
QMutex* StelPainter::globalMutex = new QMutex();
50
#endif
51

52
QCache<QByteArray, StringTexture> StelPainter::texCache(TEX_CACHE_LIMIT);
53
QOpenGLShaderProgram* StelPainter::texturesShaderProgram=Q_NULLPTR;
54
QOpenGLShaderProgram* StelPainter::basicShaderProgram=Q_NULLPTR;
55
QOpenGLShaderProgram* StelPainter::colorShaderProgram=Q_NULLPTR;
56
QOpenGLShaderProgram* StelPainter::texturesColorShaderProgram=Q_NULLPTR;
57
QOpenGLShaderProgram* StelPainter::wideLineShaderProgram=Q_NULLPTR;
58
QOpenGLShaderProgram* StelPainter::colorfulWideLineShaderProgram=Q_NULLPTR;
59
StelPainter::BasicShaderVars StelPainter::basicShaderVars;
60
StelPainter::TexturesShaderVars StelPainter::texturesShaderVars;
61
StelPainter::BasicShaderVars StelPainter::colorShaderVars;
62
StelPainter::TexturesColorShaderVars StelPainter::texturesColorShaderVars;
63
StelPainter::WideLineShaderVars StelPainter::wideLineShaderVars;
64
StelPainter::ColorfulWideLineShaderVars StelPainter::colorfulWideLineShaderVars;
65
bool StelPainter::multisamplingEnabled=false;
66

67
StelPainter::GLState::GLState(QOpenGLFunctions* gl)
×
68
        : blend(false),
×
69
          blendSrc(GL_SRC_ALPHA), blendDst(GL_ONE_MINUS_SRC_ALPHA),
×
70
          depthTest(false),
×
71
          depthMask(false),
×
72
          cullFace(false),
×
73
          lineSmooth(false),
×
74
          lineWidth(1.0f),
×
75
          gl(gl)
×
76
{
77
}
×
78

79
void StelPainter::GLState::apply()
×
80
{
81
        if(blend)
×
82
                gl->glEnable(GL_BLEND);
×
83
        else
84
                gl->glDisable(GL_BLEND);
×
85
        gl->glBlendFunc(blendSrc,blendDst);
×
86
        if(depthTest)
×
87
                gl->glEnable(GL_DEPTH_TEST);
×
88
        else
89
                gl->glDisable(GL_DEPTH_TEST);
×
90
        gl->glDepthMask(depthMask);
×
91
        if(cullFace)
×
92
                gl->glEnable(GL_CULL_FACE);
×
93
        else
94
                gl->glDisable(GL_CULL_FACE);
×
95
#ifdef GL_LINE_SMOOTH
96
        if(!QOpenGLContext::currentContext()->isOpenGLES())
×
97
        {
98
                if (lineSmooth)
×
99
                        gl->glEnable(GL_LINE_SMOOTH);
×
100
                else
101
                        gl->glDisable(GL_LINE_SMOOTH);
×
102
        }
103
#endif
104
}
×
105

106
void StelPainter::GLState::reset()
×
107
{
108
        *this = GLState(gl);
×
109
        apply();
×
110
}
×
111

112
bool StelPainter::linkProg(QOpenGLShaderProgram* prog, const QString& name)
×
113
{
114
        bool ret = prog->link();
×
115
        QString log = prog->log();
×
116
        if (!ret || (!log.isEmpty() && !log.contains("Link was successful") && !(log=="No errors."))) //"No errors." returned on some Intel drivers
×
117
                qWarning().noquote() << QString("StelPainter: Warnings while linking %1 shader program:\n%2").arg(name, prog->log());
×
118
        return ret;
×
119
}
×
120

121
StelPainter::StelPainter(const StelProjectorP& proj)
×
122
        : QOpenGLFunctions(QOpenGLContext::currentContext())
123
        , glState(this)
×
124
        , vao(new QOpenGLVertexArrayObject)
×
125
        , verticesVBO(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer))
×
126
        , indicesVBO(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer))
×
127
{
128
        Q_ASSERT(proj);
×
129

130
#ifndef NDEBUG
131
        Q_ASSERT(globalMutex);
×
132
        
133
        GLenum er = glGetError();
×
134
        if (er!=GL_NO_ERROR)
×
135
        {
136
                if (er==GL_INVALID_OPERATION)
×
137
                        qFatal("Invalid openGL operation. It is likely that you used openGL calls without having a valid instance of StelPainter");
×
138
        }
139

140
        // Lock the global mutex ensuring that no other instances of StelPainter are currently being used
141
        if (globalMutex->tryLock()==false)
×
142
        {
143
                qFatal("There can be only 1 instance of StelPainter at a given time");
×
144
        }
145
#endif
146

147
        //TODO: is this still required, and is there some Qt way to fix it? 0x11111111 is a bit peculiar, how was it chosen?
148
        // Fix some problem when using Qt OpenGL2 engine
149
        glStencilMask(0x11111111);
×
150
        glState.apply(); //apply default OpenGL state
×
151
        setProjector(proj);
×
152

153
        vao->create();
×
154
        indicesVBO->create();
×
155
        indicesVBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
156
        verticesVBO->create();
×
157
        verticesVBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
158
}
×
159

160
void StelPainter::setProjector(const StelProjectorP& p)
×
161
{
162
        prj=p;
×
163
        // Init GL viewport to current projector values
164
        glViewport(prj->viewportXywh[0], prj->viewportXywh[1], prj->viewportXywh[2], prj->viewportXywh[3]);
×
165
        glFrontFace(prj->needGlFrontFaceCW()?GL_CW:GL_CCW);
×
166
}
×
167

168
StelPainter::~StelPainter()
×
169
{
170
        //reset opengl state
171
        glState.reset();
×
172

173
#ifndef NDEBUG
174
        GLenum er = glGetError();
×
175
        if (er!=GL_NO_ERROR)
×
176
        {
177
                if (er==GL_INVALID_OPERATION)
×
178
                        qFatal("Invalid openGL operation detected in ~StelPainter()");
×
179
        }
180

181
        // We are done with this StelPainter
182
        globalMutex->unlock();
×
183
#endif
184
}
×
185

186

187
void StelPainter::setFont(const QFont& font)
×
188
{
189
        currentFont = font;
×
190
}
×
191

192
void StelPainter::setColor(float r, float g, float b, float a)
×
193
{
194
        currentColor.set(r,g,b,a);
×
195
}
×
196

197
void StelPainter::setColor(Vec3f rgb, float a)
×
198
{
199
        currentColor.set(rgb[0],rgb[1],rgb[2],a);
×
200
}
×
201

202
void StelPainter::setColor(Vec4f rgba)
×
203
{
204
        currentColor=rgba;
×
205
}
×
206

207
Vec4f StelPainter::getColor() const
×
208
{
209
        return currentColor;
×
210
}
211

212
QFontMetrics StelPainter::getFontMetrics() const
×
213
{
214
        return QFontMetrics(currentFont);
×
215
}
216

217
void StelPainter::setBlending(bool enableBlending, GLenum blendSrc, GLenum blendDst)
×
218
{
219
        if(enableBlending != glState.blend)
×
220
        {
221
                glState.blend = enableBlending;
×
222
                if(enableBlending)
×
223
                        glEnable(GL_BLEND);
×
224
                else
225
                        glDisable(GL_BLEND);
×
226
        }
227
        if(enableBlending)
×
228
        {
229
                if(blendSrc!=glState.blendSrc||blendDst!=glState.blendDst)
×
230
                {
231
                        glState.blendSrc = blendSrc;
×
232
                        glState.blendDst = blendDst;
×
233
                        glBlendFunc(blendSrc,blendDst);
×
234
                }
235
        }
236
}
×
237

238
bool StelPainter::getBlending(GLenum *src, GLenum *dst) const
×
239
{
240
        if (dst!=Q_NULLPTR)
×
241
                *dst=glState.blendDst;
×
242
        if (src!=Q_NULLPTR)
×
243
                *src=glState.blendSrc;
×
244
        return glState.blend;
×
245
}
246

247
void StelPainter::setDepthTest(bool enable)
×
248
{
249
        if(glState.depthTest != enable)
×
250
        {
251
                glState.depthTest = enable;
×
252
                if(enable)
×
253
                        glEnable(GL_DEPTH_TEST);
×
254
                else
255
                        glDisable(GL_DEPTH_TEST);
×
256
        }
257
}
×
258

259
void StelPainter::setDepthMask(bool enable)
×
260
{
261
        if(glState.depthMask != enable)
×
262
        {
263
                glState.depthMask = enable;
×
264
                if(enable)
×
265
                        glDepthMask(GL_TRUE);
×
266
                else
267
                        glDepthMask(GL_FALSE);
×
268
        }
269
}
×
270

271
void StelPainter::setCullFace(bool enable)
×
272
{
273
        if(glState.cullFace!=enable)
×
274
        {
275
                glState.cullFace = enable;
×
276
                if(enable)
×
277
                        glEnable(GL_CULL_FACE);
×
278
                else
279
                        glDisable(GL_CULL_FACE);
×
280
        }
281
}
×
282

283
void StelPainter::setLineSmooth(bool enable)
×
284
{
285
#ifdef GL_LINE_SMOOTH
286
        if (!QOpenGLContext::currentContext()->isOpenGLES() && enable!=glState.lineSmooth)
×
287
        {
288
                glState.lineSmooth = enable;
×
289
                if(enable)
×
290
                        glEnable(GL_LINE_SMOOTH);
×
291
                else
292
                        glDisable(GL_LINE_SMOOTH);
×
293
        }
294
#else
295
        Q_UNUSED(enable); //noop
296
#endif
297
}
×
298

299
void StelPainter::setLineWidth(float width)
×
300
{
301
        if(fabs(glState.lineWidth - width) < 1.e-10f)
×
302
                return;
×
303

304
        glState.lineWidth = width;
×
305

306
        if(width > 1 && StelMainView::getInstance().getGLInformation().isCoreProfile)
×
307
                return;
×
308

309
        glLineWidth(width);
×
310
}
311

312
///////////////////////////////////////////////////////////////////////////
313
// Standard methods for drawing primitives
314

315
// Fill with black around the circle
316
void StelPainter::drawViewportShape(void)
×
317
{
318
        if (prj->maskType != StelProjector::MaskDisk)
×
319
                return;
×
320

321
        bool oldBlendState = glState.blend;
×
322
        glDisable(GL_BLEND);
×
323
        setColor(0.f,0.f,0.f);
×
324

325
        GLfloat innerRadius = 0.5f*static_cast<float>(prj->viewportFovDiameter);
×
326
        GLfloat outerRadius = static_cast<float>(prj->getViewportWidth()+prj->getViewportHeight());
×
327
        GLint slices = 239;
×
328

329
        GLfloat sinCache[240];
330
        GLfloat cosCache[240];
331
        GLfloat vertices[(240+1)*2][3];
332
        GLfloat deltaRadius;
333
        GLfloat radiusHigh;
334

335
        if (outerRadius<=0.0f || innerRadius<0.0f ||innerRadius > outerRadius)
×
336
        {
337
                Q_ASSERT(0);
×
338
                return;
339
        }
340

341
        /* Compute length (needed for normal calculations) */
342
        deltaRadius=outerRadius-innerRadius;
×
343

344
        /* Cache is the vertex locations cache */
345
        for (int i=0; i<=slices; i++)
×
346
        {
347
                GLfloat angle=(M_PIf*2.0f)*static_cast<float>(i)/static_cast<float>(slices);
×
348
                sinCache[i]=static_cast<GLfloat>(sin(angle));
×
349
                cosCache[i]=static_cast<GLfloat>(cos(angle));
×
350
        }
351

352
        sinCache[slices]=sinCache[0];
×
353
        cosCache[slices]=cosCache[0];
×
354

355
        /* Enable arrays */
356
        enableClientStates(true);
×
357
        setVertexPointer(3, GL_FLOAT, vertices);
×
358

359
        radiusHigh=outerRadius-deltaRadius;
×
360
        for (int i=0; i<=slices; i++)
×
361
        {
362
                vertices[i*2][0]= static_cast<float>(prj->viewportCenter[0]) + outerRadius*sinCache[i];
×
363
                vertices[i*2][1]= static_cast<float>(prj->viewportCenter[1]) + outerRadius*cosCache[i];
×
364
                vertices[i*2][2] = 0.0f;
×
365
                vertices[i*2+1][0]= static_cast<float>(prj->viewportCenter[0]) + radiusHigh*sinCache[i];
×
366
                vertices[i*2+1][1]= static_cast<float>(prj->viewportCenter[1]) + radiusHigh*cosCache[i];
×
367
                vertices[i*2+1][2] = 0.0f;
×
368
        }
369
        drawFromArray(TriangleStrip, (slices+1)*2, 0, false);
×
370
        enableClientStates(false);
×
371
        if(oldBlendState)
×
372
                glEnable(GL_BLEND);
×
373
}
374

375
void StelPainter::computeFanDisk(float radius, uint innerFanSlices, uint level, QVector<Vec3d>& vertexArr, QVector<Vec2f>& texCoordArr)
×
376
{
377
        Q_ASSERT(level<32);
×
378
        float rad[64];
379
        uint i,j;
380
        rad[level] = radius;
×
381
#pragma warning(suppress: 4146)
382
        for (i=level-1u;i!=-1u;--i)
×
383
        {
384
                rad[i] = rad[i+1]*(1.f-M_PIf/(innerFanSlices<<(i+1)))*2.f/3.f;
×
385
        }
386
        uint slices = innerFanSlices<<level;
×
387

388
        float* cos_sin_theta = StelUtils::ComputeCosSinTheta(static_cast<uint>(slices));
×
389
        float* cos_sin_theta_p;
390
        uint slices_step = 2;
×
391
        float x,y,xa,ya;
392
        radius*=2.f;
×
393
        vertexArr.resize(0);
×
394
        texCoordArr.resize(0);
×
395
        for (i=level;i>0;--i,slices_step<<=1)
×
396
        {
397
                for (j=0,cos_sin_theta_p=cos_sin_theta; j<slices-1; j+=slices_step,cos_sin_theta_p+=2*slices_step)
×
398
                {
399
                        xa = rad[i]*cos_sin_theta_p[slices_step];
×
400
                        ya = rad[i]*cos_sin_theta_p[slices_step+1];
×
401
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
402
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
403

404
                        x = rad[i]*cos_sin_theta_p[2*slices_step];
×
405
                        y = rad[i]*cos_sin_theta_p[2*slices_step+1];
×
406
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
407
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
408

409
                        x = rad[i-1]*cos_sin_theta_p[2*slices_step];
×
410
                        y = rad[i-1]*cos_sin_theta_p[2*slices_step+1];
×
411
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
412
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
413

414
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
415
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
416
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
417
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
418

419
                        x = rad[i-1]*cos_sin_theta_p[0];
×
420
                        y = rad[i-1]*cos_sin_theta_p[1];
×
421
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
422
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
423

424
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
425
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
426
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
427
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
428

429
                        x = rad[i]*cos_sin_theta_p[0];
×
430
                        y = rad[i]*cos_sin_theta_p[1];
×
431
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
432
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
433
                }
434
        }
435
        // draw the inner polygon
436
        slices_step>>=1;
×
437
        cos_sin_theta_p=cos_sin_theta;
×
438

439
        if (slices==1)
×
440
        {
441
                x = rad[0]*cos_sin_theta_p[0];
×
442
                y = rad[0]*cos_sin_theta_p[1];
×
443
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
444
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
445
                cos_sin_theta_p+=2*slices_step;
×
446
                x = rad[0]*cos_sin_theta_p[0];
×
447
                y = rad[0]*cos_sin_theta_p[1];
×
448
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
449
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
450
                cos_sin_theta_p+=2*slices_step;
×
451
                x = rad[0]*cos_sin_theta_p[0];
×
452
                y = rad[0]*cos_sin_theta_p[1];
×
453
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
454
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
455
        }
456
        else
457
        {
458
                j=0;
×
459
                while (j<slices)
×
460
                {
461
                        texCoordArr << Vec2f(0.5f, 0.5f);
×
462
                        vertexArr << Vec3d(0, 0, 0);
×
463
                        x = rad[0]*cos_sin_theta_p[0];
×
464
                        y = rad[0]*cos_sin_theta_p[1];
×
465
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
466
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
467
                        j+=slices_step;
×
468
                        cos_sin_theta_p+=2*slices_step;
×
469
                        x = rad[0]*cos_sin_theta_p[0];
×
470
                        y = rad[0]*cos_sin_theta_p[1];
×
471
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
472
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
473
                }
474
        }
475
}
×
476

477
static void sSphereMapTexCoordFast(float rho_div_fov, const float costheta, const float sintheta, QVector<float>& out)
×
478
{
479
        if (rho_div_fov>0.5f)
×
480
                rho_div_fov=0.5f;
×
481
        out << 0.5f + rho_div_fov * costheta << 0.5f + rho_div_fov * sintheta;
×
482
}
×
483

484
void StelPainter::sSphereMap(double radius, unsigned int slices, unsigned int stacks, float textureFov, int orientInside)
×
485
{
486
        float rho;
487
        double x,y,z;
488
        unsigned int i, j;
489
        const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
490
        const float* cos_sin_rho_p;
491

492
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
493
        const float* cos_sin_theta_p;
494

495
        float drho = M_PIf / static_cast<float>(stacks);
×
496
        drho/=textureFov;
×
497

498
        // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
499
        // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
500
        // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
501

502
        const unsigned int imax = stacks;
×
503

504
        static QVector<double> vertexArr;
×
505
        static QVector<float> texCoordArr;
×
506

507
        // draw intermediate stacks as quad strips
508
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
509
        if (!orientInside) // nsign==1
×
510
        {
511
                for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.f; i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
×
512
                {
513
                        vertexArr.resize(0);
×
514
                        texCoordArr.resize(0);
×
515
                        for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j,cos_sin_theta_p+=2)
×
516
                        {
517
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
518
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
519
                                z = static_cast<double>(cos_sin_rho_p[0]);
×
520
                                sSphereMapTexCoordFast(rho, cos_sin_theta_p[0], cos_sin_theta_p[1], texCoordArr);
×
521
                                vertexArr << x*radius << y*radius << z*radius;
×
522

523
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
524
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
525
                                z = static_cast<double>(cos_sin_rho_p[2]);
×
526
                                sSphereMapTexCoordFast(rho + drho, cos_sin_theta_p[0], cos_sin_theta_p[1], texCoordArr);
×
527
                                vertexArr << x*radius << y*radius << z*radius;
×
528
                        }
529
                        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
530
                        drawFromArray(TriangleStrip, vertexArr.size()/3);
×
531
                }
532
        }
533
        else
534
        {
535
                for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.f; i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
×
536
                {
537
                        vertexArr.resize(0);
×
538
                        texCoordArr.resize(0);
×
539
                        for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j,cos_sin_theta_p+=2)
×
540
                        {
541
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
542
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
543
                                z = static_cast<double>(cos_sin_rho_p[2]);
×
544
                                sSphereMapTexCoordFast(rho + drho, cos_sin_theta_p[0], -cos_sin_theta_p[1], texCoordArr);
×
545
                                vertexArr << x*radius << y*radius << z*radius;
×
546

547
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
548
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
549
                                z = static_cast<double>(cos_sin_rho_p[0]);
×
550
                                sSphereMapTexCoordFast(rho, cos_sin_theta_p[0], -cos_sin_theta_p[1], texCoordArr);
×
551
                                vertexArr << x*radius << y*radius << z*radius;
×
552
                        }
553
                        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
554
                        drawFromArray(TriangleStrip, vertexArr.size()/3);
×
555
                }
556
        }
557
}
×
558

559
void StelPainter::drawTextGravity180(float x, float y, const QString& ws, float xshift, float yshift)
×
560
{
561
        float dx, dy, d, theta, theta_o, psi, width;
562
        dx = x - static_cast<float>(prj->viewportCenter[0]);
×
563
        dy = y - static_cast<float>(prj->viewportCenter[1]);
×
564
        d = std::sqrt(dx*dx + dy*dy);
×
565
        float limit = 120.;
×
566

567
        // If the text is too far away to be visible in the screen return
568
        if (d>qMax(prj->viewportXywh[3], prj->viewportXywh[2])*2 || ws.isEmpty())
×
569
                return;
×
570

571
        float ppx = static_cast<float>(prj->getDevicePixelsPerPixel());
×
572
        float cWidth = static_cast<float>(getFontMetrics().boundingRect(ws).width())/ws.length();
×
573
        float stdWidth = static_cast<float>(getFontMetrics().boundingRect("a").width());
×
574
        theta = std::atan2(dy - 1, dx);
×
575
        theta_o = M_PIf + std::atan2(dx, dy - 1);        
×
576
        psi = std::atan2(ppx*cWidth, d + 1) * M_180_PIf;
×
577
        if (psi>5)
×
578
                psi = 5;
×
579

580
        float xVc = static_cast<float>(prj->viewportCenter[0]) + xshift;
×
581
        float yVc = static_cast<float>(prj->viewportCenter[1]) + yshift;
×
582
        const float cosr = std::cos(-theta_o * M_PI_180f);
×
583
        const float sinr = std::sin(-theta_o * M_PI_180f);
×
584
        float xom = x + xshift*cosr - yshift*sinr;
×
585
        float yom = y + yshift*sinr + yshift*cosr;
×
586

587
        if (!StelApp::getInstance().getLocaleMgr().isAppRTL())
×
588
        {
589
                for (int i=0; i<ws.length(); ++i)
×
590
                {
591
                        if (d<limit)
×
592
                        {
593
                                drawText(xom, yom, ws[i], -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
×
594
                                xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
595
                                yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
596
                        }
597
                        else
598
                        {
599
                                x = d * std::cos(theta) + xVc ;
×
600
                                y = d * std::sin(theta) + yVc ;
×
601
                                drawText(x, y, ws[i], 90.f + theta*M_180_PIf, 0., 0.);
×
602
                                // Compute how much the character contributes to the angle
603
                                if (ws[i].isSpace())
×
604
                                        width = stdWidth;
×
605
                                else
606
                                        width = static_cast<float>(getFontMetrics().boundingRect(ws[i]).width());
×
607
                                theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
×
608
                        }
609
                }
610
        }
611
        else
612
        {
613
                int slen = ws.length();
×
614
                for (int i=0;i<slen;i++)
×
615
                {
616
                        if (d<limit)
×
617
                        {
618
                                drawText(xom, yom, ws[slen-1-i], -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
×
619
                                xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
620
                                yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
621
                        }
622
                        else
623
                        {
624
                                x = d * std::cos(theta) + xVc;
×
625
                                y = d * std::sin(theta) + yVc;
×
626
                                drawText(x, y, ws[slen-1-i], 90.f + theta*M_180_PIf, 0., 0.);
×
627
                                if (ws[slen-1-i].isSpace())
×
628
                                        width = stdWidth;
×
629
                                else
630
                                        width = static_cast<float>(getFontMetrics().boundingRect(ws[slen-1-i]).width());
×
631
                                theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
×
632
                        }
633
                }
634
        }
635
}
636

637
void StelPainter::drawText(const Vec3d& v, const QString& str, float angleDeg, float xshift, float yshift, bool noGravity)
×
638
{
639
        Vec3d win;
×
640
        if (prj->project(v, win))
×
641
                drawText(static_cast<float>(win[0]), static_cast<float>(win[1]), str, angleDeg, xshift, yshift, noGravity);
×
642
}
×
643

644
/*************************************************************************
645
 Draw the string at the given position and angle with the given font
646
*************************************************************************/
647

648
// Methods taken from text-use-opengl-buffer
649
// Container for one cached string texture
650
struct StringTexture
651
{
652
        QOpenGLTexture* texture;
653
        QSize size;
654
        QSizeF getTexSize() const {
×
655
                return QSizeF(static_cast<qreal>(size.width())  / static_cast<qreal>(texture->width()),
×
656
                              static_cast<qreal>(size.height()) / static_cast<qreal>(texture->height()));
×
657
        }
658

659
        StringTexture(QOpenGLTexture* tex, const QSize& size) :
×
660
             texture(tex), size(size) {}
×
661
        ~StringTexture() {delete texture;}
×
662
};
663

664
StringTexture* StelPainter::getTexTexture(const QString& str, int pixelSize) const
×
665
{
666
        // Render first the text into a QPixmap, then create a QOpenGLTexture
667
        // from it.  We could optimize by directly using a QImage, but for some
668
        // reason the result is not exactly the same than with a QPixmap.
669
        QByteArray hash = str.toUtf8() + QByteArray::number(pixelSize);
×
670
        StringTexture* cachedTex = texCache.object(hash);
×
671
        if (cachedTex)
×
672
                return cachedTex;
×
673
        QFont tmpFont = currentFont;
×
674
        tmpFont.setPixelSize(currentFont.pixelSize()*static_cast<int>(static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio()));
×
675
        QRect strRect = QFontMetrics(tmpFont).boundingRect(str);
×
676
        int w = strRect.width()+1+static_cast<int>(0.02f*strRect.width());
×
677
        int h = strRect.height();
×
678

679
        QPixmap strImage = QPixmap(StelUtils::getBiggerPowerOfTwo(w), StelUtils::getBiggerPowerOfTwo(h));
×
680
        strImage.fill(Qt::transparent);
×
681
        QPainter painter(&strImage);
×
682
        tmpFont.setStyleStrategy(QFont::NoAntialias);
×
683
        painter.setFont(tmpFont);
×
684
        //painter.setRenderHints(QPainter::TextAntialiasing);
685
        painter.setPen(Qt::white);
×
686
        painter.drawText(-strRect.x(), -strRect.y(), str);
×
687
        StringTexture* newTex = new StringTexture(new QOpenGLTexture(strImage.toImage()), QSize(w, h));
×
688
        texCache.insert(hash, newTex, 3*w*h);
×
689
        // simply returning newTex is dangerous as the object is owned by the cache now. (Coverity Scan barks.)
690
        return texCache.object(hash);
×
691
}
×
692

693
void StelPainter::drawText(float x, float y, const QString& str, float angleDeg, float xshift, float yshift, bool noGravity)
×
694
{
695
        if (prj->gravityLabels && !noGravity)
×
696
        {
697
                drawTextGravity180(x, y, str, xshift, yshift);
×
698
        }
699
        else if (qApp->property("text_texture")==true) // CLI option -t given?
×
700
        {
701
                //qDebug() <<  "Text texture" << str;
702
                // This is taken from branch text-use-opengl-buffer. This is essential on devices like Raspberry Pi (2016-03).
703
                StringTexture* tex = getTexTexture(str, currentFont.pixelSize());
×
704
                Q_ASSERT(tex);
×
705
                if (!noGravity)
×
706
                        angleDeg += prj->defaultAngleForGravityText;
×
707
                tex->texture->bind();
×
708

709
                static float vertexData[8];
710
                // compute the vertex coordinates applying the translation and the rotation
711
                static const float vertexBase[] = {0., 0., 1., 0., 0., 1., 1., 1.};
712
                if (std::fabs(angleDeg)>1.f*static_cast<float>(M_PI)/180.f)
×
713
                {
714
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
×
715
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
×
716
                        const float cosr = std::cos(angleDeg * static_cast<float>(M_PI/180.));
×
717
                        const float sinr = std::sin(angleDeg * static_cast<float>(M_PI/180.));
×
718
                        for (int i = 0; i < 8; i+=2)
×
719
                        {
720
                                vertexData[i]   = int(x + (tex->size.width()*vertexBase[i]+xshift) * cosr - (tex->size.height()*vertexBase[i+1]+yshift) * sinr);
×
721
                                vertexData[i+1] = int(y + (tex->size.width()*vertexBase[i]+xshift) * sinr + (tex->size.height()*vertexBase[i+1]+yshift) * cosr);
×
722
                        }
723
                }
724
                else
725
                {
726
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
×
727
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
×
728
                        for (int i = 0; i < 8; i+=2)
×
729
                        {
730
                                vertexData[i]   = int(x + tex->size.width()*vertexBase[i]+xshift);
×
731
                                vertexData[i+1] = int(y + tex->size.height()*vertexBase[i+1]+yshift);
×
732
                        }
733
                }
734

735
                float* texCoords = new float[8];
×
736
                for (int i=0;i<4;i++)
×
737
                {
738
                        texCoords[i*2+0] = static_cast<float>(tex->getTexSize().width()) * (i % 2);
×
739
                        texCoords[i*2+1] = static_cast<float>(tex->getTexSize().height()) * (1 - static_cast<float>(i) / 2);
×
740
                }
741
                setTexCoordPointer(2, GL_FLOAT, texCoords);
×
742

743
                //text drawing requires blending, but we reset GL state afterwards if necessary
744
                bool oldBlending = glState.blend;
×
745
                GLenum oldSrc = glState.blendSrc, oldDst = glState.blendDst;
×
746
                setBlending(true);
×
747
                enableClientStates(true, true);
×
748
                setVertexPointer(2, GL_FLOAT, vertexData);
×
749
                drawFromArray(TriangleStrip, 4, 0, false);
×
750
                setBlending(oldBlending, oldSrc, oldDst);
×
751
                enableClientStates(false, false);
×
752
                tex->texture->release();
×
753
                delete[] texCoords;
×
754
        }
755
        else
756
        {
757
                QOpenGLPaintDevice device;
×
758
                device.setSize(QSize(prj->getViewportWidth(), prj->getViewportHeight()));
×
759
                // This doesn't seem to work correctly, so implement the hack below instead.
760
                // Maybe check again later, or check on mac with retina..
761
                // device.setDevicePixelRatio(prj->getDevicePixelsPerPixel());
762
                // painter.setFont(currentFont);
763
                
764
                QPainter painter(&device);
×
765
                
766
                QFont tmpFont = currentFont;
×
767
                tmpFont.setPixelSize(currentFont.pixelSize()*static_cast<int>(static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio()));
×
768
                painter.setFont(tmpFont);
×
769
                painter.setPen(currentColor.toQColor());
×
770
                
771
                float scaleRatio = StelApp::getInstance().getGlobalScalingRatio();
×
772
                xshift*=scaleRatio;
×
773
                yshift*=scaleRatio;
×
774
                
775
                y = prj->getViewportHeight()-y;
×
776
                yshift = -yshift;
×
777

778
                // Translate/rotate
779
                if (!noGravity)
×
780
                        angleDeg += prj->defaultAngleForGravityText;
×
781

782
                if (std::fabs(angleDeg)>1.f)
×
783
                {
784
                        QTransform m;
×
785
                        m.translate(static_cast<qreal>(x), static_cast<qreal>(y));
×
786
                        m.rotate(static_cast<qreal>(-angleDeg));
×
787
                        painter.setTransform(m);
×
788
                        painter.drawText(qRound(xshift), qRound(yshift), str);
×
789
                }
790
                else
791
                {
792
                        painter.drawText(qRound(x+xshift), qRound(y+yshift), str);
×
793
                }
794
                
795
                //important to call this before GL state restore
796
                painter.end();
×
797

798
                //fix for bug 1628072 caused by QTBUG-56798
799
#ifndef QT_NO_DEBUG
800
                StelOpenGL::clearGLErrors();
×
801
#endif
802

803
                //QPainter messes up some GL state, begin/endNativePainting or save/restore does not help
804
                glState.apply();
×
805
        }
×
806
}
×
807

808
// Recursive method cutting a small circle in small segments
809
inline void fIter(const StelProjectorP& prj, const Vec3d& p1, const Vec3d& p2, Vec3d& win1, Vec3d& win2, std::list<Vec3d>& vertexList, const std::list<Vec3d>::const_iterator& iter, double radius, const Vec3d& center, int nbI=0, bool checkCrossDiscontinuity=true)
×
810
{
811
        const bool crossDiscontinuity = checkCrossDiscontinuity && prj->intersectViewportDiscontinuity(p1+center, p2+center);
×
812
        if (crossDiscontinuity && nbI>=10)
×
813
        {
814
                win1[2]=-2.;
×
815
                win2[2]=-2.;
×
816
                vertexList.insert(iter, win1);
×
817
                vertexList.insert(iter, win2);
×
818
                return;
×
819
        }
820

821
        Vec3d newVertex(p1); newVertex+=p2;
×
822
        newVertex.normalize();
×
823
        newVertex*=radius;
×
824
        Vec3d win3(newVertex[0]+center[0], newVertex[1]+center[1], newVertex[2]+center[2]);
×
825
        const bool isValidVertex = prj->projectInPlace(win3);
×
826

827
        const float v10=static_cast<float>(win1[0]-win3[0]);
×
828
        const float v11=static_cast<float>(win1[1]-win3[1]);
×
829
        const float v20=static_cast<float>(win2[0]-win3[0]);
×
830
        const float v21=static_cast<float>(win2[1]-win3[1]);
×
831

832
        const float dist = std::sqrt((v10*v10+v11*v11)*(v20*v20+v21*v21));
×
833
        const float cosAngle = (v10*v20+v11*v21)/dist;
×
834
        if ((cosAngle>-0.999f || dist>50*50 || crossDiscontinuity) && nbI<10)
×
835
        {
836
                // Use the 3rd component of the vector to store whether the vertex is valid
837
                win3[2]= isValidVertex ? 1.0 : -1.;
×
838
                fIter(prj, p1, newVertex, win1, win3, vertexList, vertexList.insert(iter, win3), radius, center, nbI+1, crossDiscontinuity || dist>50*50);
×
839
                fIter(prj, newVertex, p2, win3, win2, vertexList, iter, radius, center, nbI+1, crossDiscontinuity || dist>50*50 );
×
840
        }
841
}
842

843
// Used by the method below
844
QVector<Vec3f> StelPainter::smallCircleVertexArray;
845
QVector<Vec4f> StelPainter::smallCircleColorArray;
846

847
void StelPainter::drawSmallCircleVertexArray()
×
848
{
849
        if (smallCircleVertexArray.size() == 1)
×
850
        {
851
                smallCircleVertexArray.resize(0);
×
852
                smallCircleColorArray.resize(0);
×
853
                return;
×
854
        }
855
        if (smallCircleVertexArray.isEmpty())
×
856
                return;
×
857

858
        enableClientStates(true, false, !smallCircleColorArray.isEmpty());
×
859
        setVertexPointer(3, GL_FLOAT, smallCircleVertexArray.constData());
×
860
        if (!smallCircleColorArray.isEmpty())
×
861
                setColorPointer(4, GL_FLOAT, smallCircleColorArray.constData());
×
862
        drawFromArray(LineStrip, smallCircleVertexArray.size(), 0, false);
×
863
        enableClientStates(false);
×
864
        smallCircleVertexArray.resize(0);
×
865
        smallCircleColorArray.resize(0);
×
866
}
867

868
static Vec3d pt1, pt2;
869
void StelPainter::drawGreatCircleArc(const Vec3d& start, const Vec3d& stop, const SphericalCap* clippingCap,
×
870
        void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, void* userData), void* userData)
871
 {
872
         if (clippingCap)
×
873
         {
874
                 pt1=start;
×
875
                 pt2=stop;
×
876
                 if (clippingCap->clipGreatCircle(pt1, pt2))
×
877
                 {
878
                        drawSmallCircleArc(pt1, pt2, Vec3d(0.), viewportEdgeIntersectCallback, userData);
×
879
                 }
880
                 return;
×
881
        }
882
        drawSmallCircleArc(start, stop, Vec3d(0.), viewportEdgeIntersectCallback, userData);
×
883
 }
884

885
/*************************************************************************
886
 Draw a small circle arc in the current frame
887
*************************************************************************/
888
void StelPainter::drawSmallCircleArc(const Vec3d& start, const Vec3d& stop, const Vec3d& rotCenter, void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, void* userData), void* userData)
×
889
{
890
        Q_ASSERT(smallCircleVertexArray.empty());
×
891

892
        std::list<Vec3d> tessArc;        // Contains the list of projected points from the tesselated arc. (QLinkedList no longer available in Qt6.)
×
893
        Vec3d win1, win2;
×
894
        win1[2] = prj->project(start, win1) ? 1.0 : -1.;
×
895
        win2[2] = prj->project(stop, win2) ? 1.0 : -1.;
×
896
        tessArc.push_back(win1);
×
897

898

899
        if (rotCenter.normSquared()<1e-11)
×
900
        {
901
                // Great circle
902
                // Perform the tesselation of the arc in small segments in a way so that the lines look smooth
903
                fIter(prj, start, stop, win1, win2, tessArc, tessArc.insert(tessArc.end(), win2), 1, rotCenter);
×
904
        }
905
        else
906
        {
907
                Vec3d tmp = (rotCenter^start)/rotCenter.norm();
×
908
                const double radius = fabs(tmp.norm());
×
909
                // Perform the tesselation of the arc in small segments in a way so that the lines look smooth
910
                fIter(prj, start-rotCenter, stop-rotCenter, win1, win2, tessArc, tessArc.insert(tessArc.end(), win2), radius, rotCenter);
×
911
        }
912

913
        // And draw.
914
        std::list<Vec3d>::const_iterator i = tessArc.cbegin();
×
915
        //while (i<tessArc.cend())
916
        while (std::next(i, 1) != tessArc.cend())
×
917
        {
918
                const Vec3d& p1 = *i;
×
919
                const Vec3d& p2 = *(++i);
×
920
                const bool p1InViewport = prj->checkInViewport(p1);
×
921
                const bool p2InViewport = prj->checkInViewport(p2);
×
922
                if ((p1[2]>0 && p1InViewport) || (p2[2]>0 && p2InViewport))
×
923
                {
924
                        smallCircleVertexArray.append(p1.toVec3f()); //Vec3f(static_cast<float>(p1[0]), static_cast<float>(p1[1]), static_cast<float>(p1[2])));
×
925
                        if (std::next(i,1)==tessArc.cend())
×
926
                        {
927
                                smallCircleVertexArray.append(p2.toVec3f()); //Vec3f(static_cast<float>(p2[0]), static_cast<float>(p2[1]), static_cast<float>(p2[2])));
×
928
                                drawSmallCircleVertexArray();
×
929
                        }
930
                        if (viewportEdgeIntersectCallback && p1InViewport!=p2InViewport)
×
931
                        {
932
                                // We crossed the edge of the view port
933
                                if (p1InViewport)
×
934
                                        viewportEdgeIntersectCallback(prj->viewPortIntersect(p1, p2), p2-p1, userData);
×
935
                                else
936
                                        viewportEdgeIntersectCallback(prj->viewPortIntersect(p2, p1), p1-p2, userData);
×
937
                        }
938
                }
939
                else
940
                {
941
                        // Break the line, draw the stored vertex and flush the list
942
                        if (!smallCircleVertexArray.isEmpty())
×
943
                                smallCircleVertexArray.append(Vec3f(static_cast<float>(p1[0]), static_cast<float>(p1[1]), static_cast<float>(p1[2])));
×
944
                        drawSmallCircleVertexArray();
×
945
                }
946
        }
947
        Q_ASSERT(smallCircleVertexArray.isEmpty());
×
948
}
×
949

950
void StelPainter::drawPath(const QVector<Vec3d> &points, const QVector<Vec4f> &colors)
×
951
{
952
        // Because the path may intersect a viewport discontinuity, we cannot render
953
        // it in one OpenGL drawing call.
954
        Q_ASSERT(smallCircleVertexArray.isEmpty());
×
955
        Q_ASSERT(smallCircleColorArray.isEmpty());
×
956
        Q_ASSERT(points.size() == colors.size());
×
957
        Vec3d win;
×
958

959
        // In general we should add all the points, even if they are hidden, since otherwise we don't
960
        // have proper clipping on the sides.  We make an exception for the orthographic projection because
961
        // its clipping doesn't work well.  A better solution would be to use a culling test I think.
962
        bool skipHiddenPoints = dynamic_cast<StelProjectorOrthographic*>(prj.data());
×
963

964
        for (int i = 0; i+1 != points.size(); i++)
×
965
        {
966
                const Vec3d p1 = points[i];
×
967
                const Vec3d p2 = points[i + 1];
×
968
                if (!prj->intersectViewportDiscontinuity(p1, p2))
×
969
                {
970
                        bool visible = prj->project(p1, win);
×
971

972
                        if (!visible && skipHiddenPoints)
×
973
                        {
974
                                drawSmallCircleVertexArray();
×
975
                                continue;
×
976
                        }
977

978
                        smallCircleVertexArray.append(Vec3f(static_cast<float>(win[0]), static_cast<float>(win[1]), static_cast<float>(win[2])));
×
979
                        smallCircleColorArray.append(colors[i]);
×
980
                        if (i+2==points.size())
×
981
                        {
982
                                prj->project(p2, win);
×
983
                                smallCircleVertexArray.append(Vec3f(static_cast<float>(win[0]), static_cast<float>(win[1]), static_cast<float>(win[2])));
×
984
                                smallCircleColorArray.append(colors[i + 1]);
×
985
                                drawSmallCircleVertexArray();
×
986
                        }
987
                }
988
                else
989
                {
990
                        // Break the line, draw the stored vertex and flush the list
991
                        if (!smallCircleVertexArray.isEmpty())
×
992
                        {
993
                                prj->project(p1, win);
×
994
                                smallCircleVertexArray.append(Vec3f(static_cast<float>(win[0]), static_cast<float>(win[1]), static_cast<float>(win[2])));
×
995
                                smallCircleColorArray.append(colors[i]);
×
996
                        }
997
                        drawSmallCircleVertexArray();
×
998
                }
999
        }
1000
        Q_ASSERT(smallCircleVertexArray.isEmpty());
×
1001
        Q_ASSERT(smallCircleColorArray.isEmpty());
×
1002
}
×
1003

1004
// Project the passed triangle on the screen ensuring that it will look smooth, even for non linear distortion
1005
// by splitting it into subtriangles.
1006
void StelPainter::projectSphericalTriangle(const SphericalCap* clippingCap, const Vec3d* vertices, QVarLengthArray<Vec3f, 4096>* outVertices,
×
1007
        const Vec2f* texturePos, QVarLengthArray<Vec2f, 4096>* outTexturePos, const Vec3f *colors, QVarLengthArray<Vec3f, 4096> *outColors,
1008
        double maxSqDistortion, int nbI, bool checkDisc1, bool checkDisc2, bool checkDisc3) const
1009
{
1010
        Q_ASSERT(fabs(vertices[0].norm()-1.)<0.00001);
×
1011
        Q_ASSERT(fabs(vertices[1].norm()-1.)<0.00001);
×
1012
        Q_ASSERT(fabs(vertices[2].norm()-1.)<0.00001);
×
1013
        if (clippingCap && clippingCap->containsTriangle(vertices))
×
1014
                clippingCap = Q_NULLPTR;
×
1015
        if (clippingCap && !clippingCap->intersectsTriangle(vertices))
×
1016
                return;
×
1017
        bool cDiscontinuity1 = checkDisc1 && prj->intersectViewportDiscontinuity(vertices[0], vertices[1]);
×
1018
        bool cDiscontinuity2 = checkDisc2 && prj->intersectViewportDiscontinuity(vertices[1], vertices[2]);
×
1019
        bool cDiscontinuity3 = checkDisc3 && prj->intersectViewportDiscontinuity(vertices[0], vertices[2]);
×
1020
        const bool cd1=cDiscontinuity1;
×
1021
        const bool cd2=cDiscontinuity2;
×
1022
        const bool cd3=cDiscontinuity3;
×
1023

1024
        Vec3d e0=vertices[0];
×
1025
        Vec3d e1=vertices[1];
×
1026
        Vec3d e2=vertices[2];
×
1027
        bool valid = prj->projectInPlace(e0);
×
1028
        valid = prj->projectInPlace(e1) || valid;
×
1029
        valid = prj->projectInPlace(e2) || valid;
×
1030
        // Clip polygons behind the viewer
1031
        if (!valid)
×
1032
                return;
×
1033

1034
        if (checkDisc1 && cDiscontinuity1==false)
×
1035
        {
1036
                // If the distortion at segment e0,e1 is too big, flags it for subdivision
1037
                Vec3d win3 = vertices[0]; win3+=vertices[1];
×
1038
                prj->projectInPlace(win3);
×
1039
                win3[0]-=(e0[0]+e1[0])*0.5; win3[1]-=(e0[1]+e1[1])*0.5;
×
1040
                cDiscontinuity1 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDistortion;
×
1041
        }
1042
        if (checkDisc2 && cDiscontinuity2==false)
×
1043
        {
1044
                // If the distortion at segment e1,e2 is too big, flags it for subdivision
1045
                Vec3d win3 = vertices[1]; win3+=vertices[2];
×
1046
                prj->projectInPlace(win3);
×
1047
                win3[0]-=(e2[0]+e1[0])*0.5; win3[1]-=(e2[1]+e1[1])*0.5;
×
1048
                cDiscontinuity2 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDistortion;
×
1049
        }
1050
        if (checkDisc3 && cDiscontinuity3==false)
×
1051
        {
1052
                // If the distortion at segment e2,e0 is too big, flags it for subdivision
1053
                Vec3d win3 = vertices[2]; win3+=vertices[0];
×
1054
                prj->projectInPlace(win3);
×
1055
                win3[0] -= (e0[0]+e2[0])*0.5;
×
1056
                win3[1] -= (e0[1]+e2[1])*0.5;
×
1057
                cDiscontinuity3 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDistortion;
×
1058
        }
1059

1060
        if (!cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
×
1061
        {
1062
                // The triangle is clean, appends it
1063
                outVertices->append(e0.toVec3f()); outVertices->append(e1.toVec3f()); outVertices->append(e2.toVec3f());
×
1064
                if (outTexturePos)
×
1065
                        outTexturePos->append(texturePos,3);
×
1066
                if (outColors)
×
1067
                        outColors->append(colors,3);
×
1068
                return;
×
1069
        }
1070

1071
        if (nbI > 4)
×
1072
        {
1073
                // If we reached the limit number of iterations and still have a discontinuity,
1074
                // discards the triangle.
1075
                if (cd1 || cd2 || cd3)
×
1076
                        return;
×
1077

1078
                // Else display it, it will be suboptimal though.
1079
                outVertices->append(e0.toVec3f()); outVertices->append(e1.toVec3f()); outVertices->append(e2.toVec3f());
×
1080
                if (outTexturePos)
×
1081
                        outTexturePos->append(texturePos,3);
×
1082
                if (outColors)
×
1083
                        outColors->append(colors,3);
×
1084
                return;
×
1085
        }
1086

1087
        // Recursively splits the triangle into sub triangles.
1088
        // Depending on which combination of sides of the triangle has to be split a different strategy is used.
1089
        Vec3d va[3];
×
1090
        Vec2f ta[3];
×
1091
        Vec3f ca[3];
×
1092
        // Only 1 side has to be split: split the triangle in 2
1093
        if (cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
×
1094
        {
1095
                va[0]=vertices[0];
×
1096
                va[1]=vertices[0];va[1]+=vertices[1];
×
1097
                va[1].normalize();
×
1098
                va[2]=vertices[2];
×
1099
                if (outTexturePos)
×
1100
                {
1101
                        ta[0]=texturePos[0];
×
1102
                        ta[1]=(texturePos[0]+texturePos[1])*0.5;
×
1103
                        ta[2]=texturePos[2];
×
1104
                }
1105
                if (outColors)
×
1106
                {
1107
                        ca[0]=colors[0];
×
1108
                        ca[1]=(colors[0]+colors[1])*0.5;
×
1109
                        ca[2]=colors[2];
×
1110
                }
1111
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, true, false);
×
1112

1113
                //va[0]=vertices[0]+vertices[1];
1114
                //va[0].normalize();
1115
                va[0]=va[1];
×
1116
                va[1]=vertices[1];
×
1117
                va[2]=vertices[2];
×
1118
                if (outTexturePos)
×
1119
                {
1120
                        ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1121
                        ta[1]=texturePos[1];
×
1122
                        ta[2]=texturePos[2];
×
1123
                }
1124
                if (outColors)
×
1125
                {
1126
                        ca[0]=(colors[0]+colors[1])*0.5;
×
1127
                        ca[1]=colors[1];
×
1128
                        ca[2]=colors[2];
×
1129
                }
1130
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, false, true);
×
1131
                return;
×
1132
        }
1133

1134
        if (!cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
×
1135
        {
1136
                va[0]=vertices[0];
×
1137
                va[1]=vertices[1];
×
1138
                va[2]=vertices[1];va[2]+=vertices[2];
×
1139
                va[2].normalize();
×
1140
                if (outTexturePos)
×
1141
                {
1142
                        ta[0]=texturePos[0];
×
1143
                        ta[1]=texturePos[1];
×
1144
                        ta[2]=(texturePos[1]+texturePos[2])*0.5;
×
1145
                }
1146
                if (outColors)
×
1147
                {
1148
                        ca[0]=colors[0];
×
1149
                        ca[1]=colors[1];
×
1150
                        ca[2]=(colors[1]+colors[2])*0.5;
×
1151
                }
1152
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, false, true, true);
×
1153

1154
                va[0]=vertices[0];
×
1155
                //va[1]=vertices[1]+vertices[2];
1156
                //va[1].normalize();
1157
                va[1]=va[2];
×
1158
                va[2]=vertices[2];
×
1159
                if (outTexturePos)
×
1160
                {
1161
                        ta[0]=texturePos[0];
×
1162
                        ta[1]=(texturePos[1]+texturePos[2])*0.5;
×
1163
                        ta[2]=texturePos[2];
×
1164
                }
1165
                if (outColors)
×
1166
                {
1167
                        ca[0]=colors[0];
×
1168
                        ca[1]=(colors[1]+colors[2])*0.5;
×
1169
                        ca[2]=colors[2];
×
1170
                }
1171
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, true, false);
×
1172
                return;
×
1173
        }
1174

1175
        if (!cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
×
1176
        {
1177
                va[0]=vertices[0];
×
1178
                va[1]=vertices[1];
×
1179
                va[2]=vertices[0];va[2]+=vertices[2];
×
1180
                va[2].normalize();
×
1181
                if (outTexturePos)
×
1182
                {
1183
                        ta[0]=texturePos[0];
×
1184
                        ta[1]=texturePos[1];
×
1185
                        ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1186
                }
1187
                if (outColors)
×
1188
                {
1189
                        ca[0]=colors[0];
×
1190
                        ca[1]=colors[1];
×
1191
                        ca[2]=(colors[0]+colors[2])*0.5;
×
1192
                }
1193
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, false, true, true);
×
1194

1195
                //va[0]=vertices[0]+vertices[2];
1196
                //va[0].normalize();
1197
                va[0]=va[2];
×
1198
                va[1]=vertices[1];
×
1199
                va[2]=vertices[2];
×
1200
                if (outTexturePos)
×
1201
                {
1202
                        ta[0]=(texturePos[0]+texturePos[2])*0.5;
×
1203
                        ta[1]=texturePos[1];
×
1204
                        ta[2]=texturePos[2];
×
1205
                }
1206
                if (outColors)
×
1207
                {
1208
                        ca[0]=(colors[0]+colors[2])*0.5;
×
1209
                        ca[1]=colors[1];
×
1210
                        ca[2]=colors[2];
×
1211
                }
1212
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, false, true);
×
1213
                return;
×
1214
        }
1215

1216
        // 2 sides have to be split: split the triangle in 3
1217
        if (cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
×
1218
        {
1219
                va[0]=vertices[0];
×
1220
                va[1]=vertices[0];va[1]+=vertices[1];
×
1221
                va[1].normalize();
×
1222
                va[2]=vertices[1];va[2]+=vertices[2];
×
1223
                va[2].normalize();
×
1224
                if (outTexturePos)
×
1225
                {
1226
                        ta[0]=texturePos[0];
×
1227
                        ta[1]=(texturePos[0]+texturePos[1])*0.5;
×
1228
                        ta[2]=(texturePos[1]+texturePos[2])*0.5;
×
1229
                }
1230
                if (outColors)
×
1231
                {
1232
                        ca[0]=colors[0];
×
1233
                        ca[1]=(colors[0]+colors[1])*0.5;
×
1234
                        ca[2]=(colors[1]+colors[2])*0.5;
×
1235
                }
1236
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1237

1238
                //va[0]=vertices[0]+vertices[1];
1239
                //va[0].normalize();
1240
                va[0]=va[1];
×
1241
                va[1]=vertices[1];
×
1242
                //va[2]=vertices[1]+vertices[2];
1243
                //va[2].normalize();
1244
                if (outTexturePos)
×
1245
                {
1246
                        ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1247
                        ta[1]=texturePos[1];
×
1248
                        ta[2]=(texturePos[1]+texturePos[2])*0.5;
×
1249
                }
1250
                if (outColors)
×
1251
                {
1252
                        ca[0]=(colors[0]+colors[1])*0.5;
×
1253
                        ca[1]=colors[1];
×
1254
                        ca[2]=(colors[1]+colors[2])*0.5;
×
1255
                }
1256
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1257

1258
                va[0]=vertices[0];
×
1259
                //va[1]=vertices[1]+vertices[2];
1260
                //va[1].normalize();
1261
                va[1]=va[2];
×
1262
                va[2]=vertices[2];
×
1263
                if (outTexturePos)
×
1264
                {
1265
                        ta[0]=texturePos[0];
×
1266
                        ta[1]=(texturePos[1]+texturePos[2])*0.5;
×
1267
                        ta[2]=texturePos[2];
×
1268
                }
1269
                if (outColors)
×
1270
                {
1271
                        ca[0]=colors[0];
×
1272
                        ca[1]=(colors[1]+colors[2])*0.5;
×
1273
                        ca[2]=colors[2];
×
1274
                }
1275
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, true, false);
×
1276
                return;
×
1277
        }
1278
        if (cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
×
1279
        {
1280
                va[0]=vertices[0];
×
1281
                va[1]=vertices[0];va[1]+=vertices[1];
×
1282
                va[1].normalize();
×
1283
                va[2]=vertices[0];va[2]+=vertices[2];
×
1284
                va[2].normalize();
×
1285
                if (outTexturePos)
×
1286
                {
1287
                        ta[0]=texturePos[0];
×
1288
                        ta[1]=(texturePos[0]+texturePos[1])*0.5;
×
1289
                        ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1290
                }
1291
                if (outColors)
×
1292
                {
1293
                        ca[0]=colors[0];
×
1294
                        ca[1]=(colors[0]+colors[1])*0.5;
×
1295
                        ca[2]=(colors[0]+colors[2])*0.5;
×
1296
                }
1297
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1298

1299
                //va[0]=vertices[0]+vertices[1];
1300
                //va[0].normalize();
1301
                va[0]=va[1];
×
1302
                va[1]=vertices[2];
×
1303
                //va[2]=vertices[0]+vertices[2];
1304
                //va[2].normalize();
1305
                if (outTexturePos)
×
1306
                {
1307
                        ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1308
                        ta[1]=texturePos[2];
×
1309
                        ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1310
                }
1311
                if (outColors)
×
1312
                {
1313
                        ca[0]=(colors[0]+colors[1])*0.5;
×
1314
                        ca[1]=colors[2];
×
1315
                        ca[2]=(colors[0]+colors[2])*0.5;
×
1316
                }
1317
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1318

1319

1320
                //va[0]=vertices[0]+vertices[1];
1321
                //va[0].normalize();
1322
                va[1]=vertices[1];
×
1323
                va[2]=vertices[2];
×
1324
                if (outTexturePos)
×
1325
                {
1326
                        ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1327
                        ta[1]=texturePos[1];
×
1328
                        ta[2]=texturePos[2];
×
1329
                }
1330
                if (outColors)
×
1331
                {
1332
                        ca[0]=(colors[0]+colors[1])*0.5;
×
1333
                        ca[1]=colors[1];
×
1334
                        ca[2]=colors[2];
×
1335
                }
1336
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, true, false, true);
×
1337

1338
                return;
×
1339
        }
1340
        if (!cDiscontinuity1 && cDiscontinuity2 && cDiscontinuity3)
×
1341
        {
1342
                va[0]=vertices[0];
×
1343
                va[1]=vertices[1];
×
1344
                va[2]=vertices[1];va[2]+=vertices[2];
×
1345
                va[2].normalize();
×
1346
                if (outTexturePos)
×
1347
                {
1348
                        ta[0]=texturePos[0];
×
1349
                        ta[1]=texturePos[1];
×
1350
                        ta[2]=(texturePos[1]+texturePos[2])*0.5;
×
1351
                }
1352
                if (outColors)
×
1353
                {
1354
                        ca[0]=colors[0];
×
1355
                        ca[1]=colors[1];
×
1356
                        ca[2]=(colors[1]+colors[2])*0.5;
×
1357
                }
1358
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1, false, true, true);
×
1359

1360
                //va[0]=vertices[1]+vertices[2];
1361
                //va[0].normalize();
1362
                va[0]=va[2];
×
1363
                va[1]=vertices[2];
×
1364
                va[2]=vertices[0];va[2]+=vertices[2];
×
1365
                va[2].normalize();
×
1366
                if (outTexturePos)
×
1367
                {
1368
                        ta[0]=(texturePos[1]+texturePos[2])*0.5;
×
1369
                        ta[1]=texturePos[2];
×
1370
                        ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1371
                }
1372
                if (outColors)
×
1373
                {
1374
                        ca[0]=(colors[1]+colors[2])*0.5;
×
1375
                        ca[1]=colors[2];
×
1376
                        ca[2]=(colors[0]+colors[2])*0.5;
×
1377
                }
1378
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1379

1380
                va[1]=va[0];
×
1381
                va[0]=vertices[0];
×
1382
                //va[1]=vertices[1]+vertices[2];
1383
                //va[1].normalize();
1384
                //va[2]=vertices[0]+vertices[2];
1385
                //va[2].normalize();
1386
                if (outTexturePos)
×
1387
                {
1388
                        ta[0]=texturePos[0];
×
1389
                        ta[1]=(texturePos[1]+texturePos[2])*0.5;
×
1390
                        ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1391
                }
1392
                if (outColors)
×
1393
                {
1394
                        ca[0]=colors[0];
×
1395
                        ca[1]=(colors[1]+colors[2])*0.5;
×
1396
                        ca[2]=(colors[0]+colors[2])*0.5;
×
1397
                }
1398
                projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1399
                return;
×
1400
        }
1401

1402
        // Last case: the 3 sides have to be split: cut in 4 triangles a' la HTM
1403
        va[0]=vertices[0];va[0]+=vertices[1];
×
1404
        va[0].normalize();
×
1405
        va[1]=vertices[1];va[1]+=vertices[2];
×
1406
        va[1].normalize();
×
1407
        va[2]=vertices[0];va[2]+=vertices[2];
×
1408
        va[2].normalize();
×
1409
        if (outTexturePos)
×
1410
        {
1411
                ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1412
                ta[1]=(texturePos[1]+texturePos[2])*0.5;
×
1413
                ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1414
        }
1415
        if (outColors)
×
1416
        {
1417
                ca[0]=(colors[0]+colors[1])*0.5;
×
1418
                ca[1]=(colors[1]+colors[2])*0.5;
×
1419
                ca[2]=(colors[0]+colors[2])*0.5;
×
1420
        }
1421
        projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1422

1423
        va[1]=va[0];
×
1424
        va[0]=vertices[0];
×
1425
        //va[1]=vertices[0]+vertices[1];
1426
        //va[1].normalize();
1427
        //va[2]=vertices[0]+vertices[2];
1428
        //va[2].normalize();
1429
        if (outTexturePos)
×
1430
        {
1431
                ta[0]=texturePos[0];
×
1432
                ta[1]=(texturePos[0]+texturePos[1])*0.5;
×
1433
                ta[2]=(texturePos[0]+texturePos[2])*0.5;
×
1434
        }
1435
        if (outColors)
×
1436
        {
1437
                ca[0]=colors[0];
×
1438
                ca[1]=(colors[0]+colors[1])*0.5;
×
1439
                ca[2]=(colors[0]+colors[2])*0.5;
×
1440
        }
1441
        projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1442

1443
        //va[0]=vertices[0]+vertices[1];
1444
        //va[0].normalize();
1445
        va[0]=va[1];
×
1446
        va[1]=vertices[1];
×
1447
        va[2]=vertices[1];va[2]+=vertices[2];
×
1448
        va[2].normalize();
×
1449
        if (outTexturePos)
×
1450
        {
1451
                ta[0]=(texturePos[0]+texturePos[1])*0.5;
×
1452
                ta[1]=texturePos[1];
×
1453
                ta[2]=(texturePos[1]+texturePos[2])*0.5;
×
1454
        }
1455
        if (outColors)
×
1456
        {
1457
                ca[0]=(colors[0]+colors[1])*0.5;
×
1458
                ca[1]=colors[1];
×
1459
                ca[2]=(colors[1]+colors[2])*0.5;
×
1460
        }
1461
        projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1462

1463
        va[0]=vertices[0];va[0]+=vertices[2];
×
1464
        va[0].normalize();
×
1465
        //va[1]=vertices[1]+vertices[2];
1466
        //va[1].normalize();
1467
        va[1]=va[2];
×
1468
        va[2]=vertices[2];
×
1469
        if (outTexturePos)
×
1470
        {
1471
                ta[0]=(texturePos[0]+texturePos[2])*0.5;
×
1472
                ta[1]=(texturePos[1]+texturePos[2])*0.5;
×
1473
                ta[2]=texturePos[2];
×
1474
        }
1475
        if (outColors)
×
1476
        {
1477
                ca[0]=(colors[0]+colors[2])*0.5;
×
1478
                ca[1]=(colors[1]+colors[2])*0.5;
×
1479
                ca[2]=colors[2];
×
1480
        }
1481
        projectSphericalTriangle(clippingCap, va, outVertices, ta, outTexturePos, ca, outColors, maxSqDistortion, nbI+1);
×
1482

1483
        return;
×
1484
}
1485

1486
static QVarLengthArray<Vec3f, 4096> polygonVertexArray;
1487
static QVarLengthArray<Vec2f, 4096> polygonTextureCoordArray;
1488
static QVarLengthArray<Vec3f, 4096> polygonColorArray;
1489
static QVarLengthArray<unsigned int, 4096> indexArray;
1490

1491
void StelPainter::drawGreatCircleArcs(const StelVertexArray& va, const SphericalCap* clippingCap)
×
1492
{
1493
        Q_ASSERT(va.vertex.size()!=1);
×
1494
        Q_ASSERT(!va.isIndexed());        // Indexed unsupported yet
×
1495
        switch (va.primitiveType)
×
1496
        {
1497
                case StelVertexArray::Lines:
×
1498
                        Q_ASSERT(va.vertex.size()%2==0);
×
1499
                        for (int i=0;i<va.vertex.size();i+=2)
×
1500
                                drawGreatCircleArc(va.vertex.at(i), va.vertex.at(i+1), clippingCap);
×
1501
                        return;
×
1502
                case StelVertexArray::LineStrip:
×
1503
                        for (int i=0;i<va.vertex.size()-1;++i)
×
1504
                                drawGreatCircleArc(va.vertex.at(i), va.vertex.at(i+1), clippingCap);
×
1505
                        return;
×
1506
                case StelVertexArray::LineLoop:
×
1507
                        for (int i=0;i<va.vertex.size()-1;++i)
×
1508
                                drawGreatCircleArc(va.vertex.at(i), va.vertex.at(i+1), clippingCap);
×
1509
                        drawGreatCircleArc(va.vertex.last(), va.vertex.first(), clippingCap);
×
1510
                        return;
×
1511
                default:
×
1512
                        Q_ASSERT(0); // Unsupported primitive yype
×
1513
        }
1514
}
1515

1516
// The function object that we use as an interface between VertexArray::foreachTriangle and
1517
// StelPainter::projectSphericalTriangle.
1518
//
1519
// This is used by drawSphericalTriangles to project all the triangles coordinates in a StelVertexArray into our global
1520
// vertex array buffer.
1521
class VertexArrayProjector
1522
{
1523
public:
1524
        VertexArrayProjector(const StelVertexArray& ar, StelPainter* apainter, const SphericalCap* aclippingCap,
×
1525
                                                 QVarLengthArray<Vec3f, 4096>* aoutVertices, QVarLengthArray<Vec2f, 4096>* aoutTexturePos=Q_NULLPTR, QVarLengthArray<Vec3f, 4096>* aoutColors=Q_NULLPTR, double amaxSqDistortion=5.)
1526
                   : //vertexArray(ar),
×
1527
                     painter(apainter), clippingCap(aclippingCap), outVertices(aoutVertices),
×
1528
                         outColors(aoutColors), outTexturePos(aoutTexturePos), maxSqDistortion(amaxSqDistortion)
×
1529
        {
1530
                Q_UNUSED(ar)
1531
        }
×
1532

1533
        // Project a single triangle and add it into the output arrays
1534
        inline void operator()(const Vec3d* v0, const Vec3d* v1, const Vec3d* v2,
×
1535
                                                   const Vec2f* t0, const Vec2f* t1, const Vec2f* t2,
1536
                                                   const Vec3f* c0, const Vec3f* c1, const Vec3f* c2,
1537
                                                   unsigned int, unsigned int, unsigned) const
1538
        {
1539
                // XXX: we may optimize more by putting the declaration and the test outside of this method.
1540
                Vec3d tmpVertex[3] = {*v0, *v1, *v2};
×
1541
                // required, else assertion at begin of projectSphericalTriangle() fails!
1542
                tmpVertex[0].normalize();
×
1543
                tmpVertex[1].normalize();
×
1544
                tmpVertex[2].normalize();
×
1545
                if ( (outTexturePos) && (outColors))
×
1546
                {
1547
                        const Vec2f tmpTexture[3] = {*t0, *t1, *t2};
×
1548
                        const Vec3f tmpColor[3] = {*c0, *c1, *c2};
×
1549
                        painter->projectSphericalTriangle(clippingCap, tmpVertex, outVertices, tmpTexture, outTexturePos, tmpColor, outColors, maxSqDistortion);
×
1550
                }
×
1551
                else if (outTexturePos)
×
1552
                {
1553
                        const Vec2f tmpTexture[3] = {*t0, *t1, *t2};
×
1554
                        painter->projectSphericalTriangle(clippingCap, tmpVertex, outVertices, tmpTexture, outTexturePos, Q_NULLPTR, Q_NULLPTR, maxSqDistortion);
×
1555
                }
1556
                else if (outColors)
×
1557
                {
1558
                        const Vec3f tmpColor[3] = {*c0, *c1, *c2};
×
1559
                        painter->projectSphericalTriangle(clippingCap, tmpVertex, outVertices, Q_NULLPTR, Q_NULLPTR, tmpColor, outColors, maxSqDistortion);
×
1560
                }
1561
                else
1562
                        painter->projectSphericalTriangle(clippingCap, tmpVertex, outVertices, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, maxSqDistortion);
×
1563
        }
×
1564

1565
        // Draw the resulting arrays
1566
        void drawResult()
×
1567
        {
1568
                painter->setVertexPointer(3, GL_FLOAT, outVertices->constData());
×
1569
                if (outTexturePos)
×
1570
                        painter->setTexCoordPointer(2, GL_FLOAT, outTexturePos->constData());
×
1571
                if (outColors)
×
1572
                        painter->setColorPointer(3, GL_FLOAT, outColors->constData());
×
1573

1574
                painter->enableClientStates(true, outTexturePos != Q_NULLPTR, outColors != Q_NULLPTR);
×
1575
                painter->drawFromArray(StelPainter::Triangles, outVertices->size(), 0, false);
×
1576
                painter->enableClientStates(false);
×
1577
        }
×
1578

1579
private:
1580
        StelPainter* painter;
1581
        const SphericalCap* clippingCap;
1582
        QVarLengthArray<Vec3f, 4096>* outVertices;
1583
        QVarLengthArray<Vec3f, 4096>* outColors;
1584
        QVarLengthArray<Vec2f, 4096>* outTexturePos;
1585
        double maxSqDistortion;
1586
};
1587

1588
void StelPainter::drawStelVertexArray(const StelVertexArray& arr, bool checkDiscontinuity, Vec3d aberration)
×
1589
{
1590
        if (checkDiscontinuity && prj->hasDiscontinuity())
×
1591
        {
1592
                // The projection has discontinuities, so we need to make sure that no triangle is crossing them.
1593
                drawStelVertexArray(arr.removeDiscontinuousTriangles(this->getProjector().data()), false, aberration);
×
1594
                return;
×
1595
        }
1596

1597
        if (aberration==Vec3d(0.))
×
1598
        {
1599
                setVertexPointer(3, GL_DOUBLE, arr.vertex.constData());
×
1600
        }
1601
        else
1602
        {
1603
                QVector<Vec3d> aberredVertex(arr.vertex.size());
×
1604
                for (int i=0; i<arr.vertex.size(); i++)
×
1605
                {
1606
                        Q_ASSERT(qFuzzyCompare(arr.vertex.at(i).normSquared(), 1.0));
×
1607
                        Vec3d vec=arr.vertex.at(i)+aberration;
×
1608
                        vec.normalize();
×
1609
                        aberredVertex[i]=vec;
×
1610
                }
1611
                setVertexPointer(3, GL_DOUBLE, aberredVertex.constData());
×
1612
        }
×
1613
        if (arr.isTextured())
×
1614
        {
1615
                setTexCoordPointer(2, GL_FLOAT, arr.texCoords.constData());
×
1616
                if (arr.isColored())
×
1617
                {
1618
                        setColorPointer(3, GL_FLOAT, arr.colors.constData());
×
1619
                        enableClientStates(true, true, true);
×
1620
                }
1621
                else
1622
                        enableClientStates(true, true, false);
×
1623
        }
1624
        else
1625
        {
1626
                if (arr.isColored())
×
1627
                {
1628
                        setColorPointer(3, GL_FLOAT, arr.colors.constData());
×
1629
                        enableClientStates(true, false, true);
×
1630
                }
1631
                else
1632
                        enableClientStates(true, false, false);
×
1633
        }
1634
        if (arr.isIndexed())
×
1635
                drawFromArray(static_cast<StelPainter::DrawingMode>(arr.primitiveType), arr.indices.size(), 0, true, arr.indices.constData());
×
1636
        else
1637
                drawFromArray(static_cast<StelPainter::DrawingMode>(arr.primitiveType), arr.vertex.size());
×
1638

1639
        enableClientStates(false);
×
1640
}
1641

1642
void StelPainter::drawSphericalTriangles(const StelVertexArray& va, bool textured, bool colored, const SphericalCap* clippingCap, bool doSubDivide, double maxSqDistortion)
×
1643
{
1644
        if (va.vertex.isEmpty())
×
1645
                return;
×
1646

1647
        Q_ASSERT(va.vertex.size()>2);
×
1648
        polygonVertexArray.clear();
×
1649
        polygonTextureCoordArray.clear();
×
1650

1651
        indexArray.clear();
×
1652

1653
        if (!doSubDivide)
×
1654
        {
1655
                // The simplest case, we don't need to iterate through the triangles at all.
1656
                drawStelVertexArray(va);
×
1657
                return;
×
1658
        }
1659

1660
        // the last case.  It is the slowest, it process the triangles one by one.
1661
        {
1662
                // Project all the triangles of the VertexArray into our buffer arrays.
1663
                VertexArrayProjector result = va.foreachTriangle(VertexArrayProjector(va, this, clippingCap, &polygonVertexArray, textured ? &polygonTextureCoordArray : Q_NULLPTR, colored ? &polygonColorArray : Q_NULLPTR, maxSqDistortion));
×
1664
                result.drawResult();
×
1665
                return;
×
1666
        }
1667
}
1668

1669
// Draw the given SphericalPolygon.
1670
void StelPainter::drawSphericalRegion(SphericalRegion* poly, SphericalPolygonDrawMode drawMode, const SphericalCap* clippingCap, const bool doSubDivise, const double maxSqDistortion, const Vec3d &observerVelocity)
×
1671
{
1672
        if (!prj->getBoundingCap().intersects(poly->getBoundingCap()))
×
1673
                return;
×
1674

1675
        bool oldCullFace = glState.cullFace;
×
1676

1677
        switch (drawMode)
×
1678
        {
1679
                case SphericalPolygonDrawModeBoundary:
×
1680
                        if (doSubDivise || prj->intersectViewportDiscontinuity(poly->getBoundingCap()))
×
1681
                                drawGreatCircleArcs(poly->getOutlineVertexArray(), clippingCap);
×
1682
                        else
1683
                                drawStelVertexArray(poly->getOutlineVertexArray(), false);
×
1684
                        break;
×
1685
                case SphericalPolygonDrawModeFill:
×
1686
                case SphericalPolygonDrawModeTextureFill:
1687
                case SphericalPolygonDrawModeTextureFillColormodulated:
1688
                        setCullFace(true);
×
1689
                        // The polygon is already tessellated as triangles
1690
                        if (doSubDivise || prj->intersectViewportDiscontinuity(poly->getBoundingCap()))
×
1691
                                // flag for color-modulated textured mode (e.g. for Milky Way/extincted)
1692
                                drawSphericalTriangles(poly->getFillVertexArray(observerVelocity), drawMode>=SphericalPolygonDrawModeTextureFill, drawMode==SphericalPolygonDrawModeTextureFillColormodulated, clippingCap, doSubDivise, maxSqDistortion);
×
1693
                        else
1694
                                drawStelVertexArray(poly->getFillVertexArray(observerVelocity), false);
×
1695

1696
                        setCullFace(oldCullFace);
×
1697
                        break;
×
1698
                default:
×
1699
                        Q_ASSERT(0);
×
1700
        }
1701
}
1702

1703

1704
/*************************************************************************
1705
 draw a simple circle, 2d viewport coordinates in pixel
1706
*************************************************************************/
1707
void StelPainter::drawCircle(float x, float y, float r)
×
1708
{
1709
        if (r <= 1.0f)
×
1710
                return;
×
1711
        const Vec2f center(x,y);
×
1712
        const Vec2f v_center(0.5f*prj->viewportXywh[2],0.5f*prj->viewportXywh[3]);
×
1713
        const float R = v_center.norm();
×
1714
        const float d = (v_center-center).norm();
×
1715
        if (d > r+R || d < r-R)
×
1716
                return;
×
1717
        const int segments = 180;
×
1718
        const float phi = 2.0f*M_PIf/segments;
×
1719
        const float cp = std::cos(phi);
×
1720
        const float sp = std::sin(phi);
×
1721
        float dx = r;
×
1722
        float dy = 0;
×
1723
        static QVarLengthArray<Vec3f, 180> circleVertexArray(180);
×
1724

1725
        for (int i=0;i<segments;i++)
×
1726
        {
1727
                circleVertexArray[i].set(x+dx,y+dy,0);
×
1728
                r = dx*cp-dy*sp;
×
1729
                dy = dx*sp+dy*cp;
×
1730
                dx = r;
×
1731
        }
1732
        enableClientStates(true);
×
1733
        setVertexPointer(3, GL_FLOAT, circleVertexArray.data());
×
1734
        drawFromArray(LineLoop, 180, 0, false);
×
1735
        enableClientStates(false);
×
1736
}
1737

1738
void StelPainter::drawSprite2dMode(float x, float y, float radius)
×
1739
{
1740
        static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
1741
        static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
1742
        
1743
        // Takes into account device pixel density and global scale ratio, as we are drawing 2D stuff.
1744
        radius *= static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio();
×
1745
        
1746
        vertexData[0]=x-radius; vertexData[1]=y-radius;
×
1747
        vertexData[2]=x+radius; vertexData[3]=y-radius;
×
1748
        vertexData[4]=x-radius; vertexData[5]=y+radius;
×
1749
        vertexData[6]=x+radius; vertexData[7]=y+radius;
×
1750
        enableClientStates(true, true);
×
1751
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1752
        setTexCoordPointer(2, GL_FLOAT, texCoordData);
×
1753
        drawFromArray(TriangleStrip, 4, 0, false);
×
1754
        enableClientStates(false);
×
1755
}
×
1756

1757
void StelPainter::drawSprite2dModeNoDeviceScale(float x, float y, float radius)
×
1758
{
1759
        drawSprite2dMode(x, y, radius/(static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio()));
×
1760
}
×
1761

1762
void StelPainter::drawSprite2dMode(const Vec3d& v, float radius)
×
1763
{
1764
        Vec3d win;
×
1765
        if (prj->project(v, win))
×
1766
                drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), radius);
×
1767
}
×
1768

1769
void StelPainter::drawSprite2dMode(float x, float y, float radius, float rotation)
×
1770
{
1771
        static float vertexData[8];
1772
        static const float texCoordData[] = {0.f,0.f, 1.f,0.f, 0.f,1.f, 1.f,1.f};
1773

1774
        // compute the vertex coordinates applying the translation and the rotation
1775
        static const float vertexBase[] = {-1., -1., 1., -1., -1., 1., 1., 1.};
1776
        const float cosr = std::cos(rotation * M_PI_180f);
×
1777
        const float sinr = std::sin(rotation * M_PI_180f);
×
1778
        
1779
        // Takes into account device pixel density and global scale ratio, as we are drawing 2D stuff.
1780
        radius *= static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio();
×
1781
        
1782
        for (int i = 0; i < 8; i+=2)
×
1783
        {
1784
                vertexData[i] = x + radius * vertexBase[i] * cosr - radius * vertexBase[i+1] * sinr;
×
1785
                vertexData[i+1] = y + radius * vertexBase[i] * sinr + radius * vertexBase[i+1] * cosr;
×
1786
        }
1787

1788
        enableClientStates(true, true);
×
1789
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1790
        setTexCoordPointer(2, GL_FLOAT, texCoordData);
×
1791
        drawFromArray(TriangleStrip, 4, 0, false);
×
1792
        enableClientStates(false);
×
1793
}
×
1794

1795
void StelPainter::drawRect2d(float x, float y, float width, float height, bool textured)
×
1796
{
1797
        static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
1798
        static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
1799
        vertexData[0]=x; vertexData[1]=y;
×
1800
        vertexData[2]=x+width; vertexData[3]=y;
×
1801
        vertexData[4]=x; vertexData[5]=y+height;
×
1802
        vertexData[6]=x+width; vertexData[7]=y+height;
×
1803
        if (textured)
×
1804
        {
1805
                enableClientStates(true, true);
×
1806
                setVertexPointer(2, GL_FLOAT, vertexData);
×
1807
                setTexCoordPointer(2, GL_FLOAT, texCoordData);
×
1808
        }
1809
        else
1810
        {
1811
                enableClientStates(true);
×
1812
                setVertexPointer(2, GL_FLOAT, vertexData);
×
1813
        }
1814
        drawFromArray(TriangleStrip, 4, 0, false);
×
1815
        enableClientStates(false);
×
1816
}
×
1817

1818
/*************************************************************************
1819
 Draw a GL_POINT at the given position
1820
*************************************************************************/
1821
void StelPainter::drawPoint2d(float x, float y)
×
1822
{
1823
        static float vertexData[] = {0.,0.};
1824
        vertexData[0]=x;
×
1825
        vertexData[1]=y;
×
1826

1827
        enableClientStates(true);
×
1828
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1829
        drawFromArray(Points, 1, 0, false);
×
1830
        enableClientStates(false);
×
1831
}
×
1832

1833

1834
/*************************************************************************
1835
 Draw a line between the 2 points.
1836
*************************************************************************/
1837
void StelPainter::drawLine2d(const float x1, const float y1, const float x2, const float y2)
×
1838
{
1839
        static float vertexData[] = {0.,0.,0.,0.};
1840
        vertexData[0]=x1;
×
1841
        vertexData[1]=y1;
×
1842
        vertexData[2]=x2;
×
1843
        vertexData[3]=y2;
×
1844

1845
        enableClientStates(true);
×
1846
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1847
        drawFromArray(Lines, 2, 0, false);
×
1848
        enableClientStates(false);
×
1849
}
×
1850

1851
///////////////////////////////////////////////////////////////////////////
1852
// Drawing methods for general (non-linear) mode.
1853
// This used to draw a full sphere. Since 0.13 it's possible to have a spherical zone only.
1854
void StelPainter::sSphere(const double radius, const double oneMinusOblateness,
×
1855
                          const unsigned int slices, const unsigned int stacks,
1856
                          const bool orientInside, const bool flipTexture, const float topAngle, const float bottomAngle)
1857
{
1858
        double x, y, z;
1859
        GLfloat s=0.f, t=0.f;
×
1860
        GLfloat nsign;
1861

1862
        if (orientInside)
×
1863
        {
1864
                nsign = -1.f;
×
1865
                t=0.f; // from inside texture is reversed
×
1866
        }
1867
        else
1868
        {
1869
                nsign = 1.f;
×
1870
                t=1.f;
×
1871
        }
1872

1873
        const float* cos_sin_rho = Q_NULLPTR;
×
1874
        Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top.
×
1875
        if ((bottomAngle>3.1415f) && (topAngle<0.0001f)) // safety margin.
×
1876
                cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
1877
        else
1878
        {
1879
                const float drho = (bottomAngle-topAngle) / static_cast<float>(stacks); // deltaRho:  originally just 180degrees/stacks, now the range clamped.
×
1880
                cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PIf-bottomAngle);
×
1881
        }
1882
        // Allow parameters so that pole regions may remain free.
1883
        const float* cos_sin_rho_p;
1884

1885
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
1886
        const float *cos_sin_theta_p;
1887

1888
        // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
1889
        // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
1890
        // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
1891
        // If the texture is flipped, we iterate the coordinates backward.
1892
        const GLfloat ds = (flipTexture ? -1.f : 1.f) / static_cast<float>(slices);
×
1893
        const GLfloat dt = nsign / static_cast<float>(stacks); // from inside texture is reversed
×
1894

1895
        // draw intermediate as quad strips
1896
        static QVector<double> vertexArr;
×
1897
        static QVector<float> texCoordArr;
×
1898
        static QVector<float> colorArr;
×
1899
        static QVector<unsigned short> indiceArr;
×
1900

1901
        texCoordArr.resize(0);
×
1902
        vertexArr.resize(0);
×
1903
        colorArr.resize(0);
×
1904
        indiceArr.resize(0);
×
1905

1906
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
1907
        uint i, j;
1908
        for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2)
×
1909
        {
1910
                s = flipTexture ? 1.f : 0.f;
×
1911
                for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2)
×
1912
                {
1913
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
1914
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
1915
                        z = static_cast<double>(nsign * cos_sin_rho_p[0]);
×
1916
                        texCoordArr << s << t;
×
1917
                        vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
×
1918
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
1919
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
1920
                        z = static_cast<double>(nsign * cos_sin_rho_p[2]);
×
1921
                        texCoordArr << s << t - dt;
×
1922
                        vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
×
1923
                        s += ds;
×
1924
                }
1925
                unsigned int offset = i*(slices+1)*2;
×
1926
                for (j = 2;j<slices*2+2;j+=2)
×
1927
                {
1928
                        indiceArr << static_cast<unsigned short>(offset+j-2) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j);
×
1929
                        indiceArr << static_cast<unsigned short>(offset+j) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j+1);
×
1930
                }
1931
                t -= dt;
×
1932
        }
1933

1934
        // Draw the array now
1935
        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
1936
        drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData());
×
1937
}
×
1938

1939
StelVertexArray StelPainter::computeSphereNoLight(double radius, double oneMinusOblateness, unsigned int slices, unsigned int stacks,
×
1940
                          int orientInside, bool flipTexture, float topAngle, float bottomAngle)
1941
{
1942
        StelVertexArray result(StelVertexArray::Triangles);
×
1943
        double x, y, z;
1944
        GLfloat s=0.f, t=0.f;
×
1945
        GLuint i, j;
1946
        GLfloat nsign;
1947
        if (orientInside)
×
1948
        {
1949
                nsign = -1.f;
×
1950
                t=0.f; // from inside texture is reversed
×
1951
        }
1952
        else
1953
        {
1954
                nsign = 1.f;
×
1955
                t=1.f;
×
1956
        }
1957

1958
        const float* cos_sin_rho = Q_NULLPTR; //StelUtils::ComputeCosSinRho(stacks);
×
1959
        Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top.
×
1960
        if ((bottomAngle>3.1415f) && (topAngle<0.0001f)) // safety margin.
×
1961
                cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
1962
        else
1963
        {
1964
                const float drho = (bottomAngle-topAngle) / static_cast<float>(stacks); // deltaRho:  originally just 180degrees/stacks, now the range clamped.
×
1965
                cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PIf-bottomAngle);
×
1966
        }
1967
        // Allow parameters so that pole regions may remain free.
1968
        const float* cos_sin_rho_p;
1969

1970
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
1971
        const float *cos_sin_theta_p;
1972

1973
        // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
1974
        // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
1975
        // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
1976
        // If the texture is flipped, we iterate the coordinates backward.
1977
        const GLfloat ds = (flipTexture ? -1.f : 1.f) / static_cast<float>(slices);
×
1978
        const GLfloat dt = nsign / static_cast<float>(stacks); // from inside texture is reversed
×
1979

1980
        // draw intermediate as quad strips
1981
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
1982
        for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2)
×
1983
        {
1984
                s = !flipTexture ? 0.f : 1.f;
×
1985
                for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2)
×
1986
                {
1987
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
1988
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
1989
                        z = static_cast<double>(nsign * cos_sin_rho_p[0]);
×
1990
                        result.texCoords << Vec2f(s,t);
×
1991
                        result.vertex << Vec3d(x*radius, y*radius, z*oneMinusOblateness*radius);
×
1992
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
1993
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
1994
                        z = static_cast<double>(nsign * cos_sin_rho_p[2]);
×
1995
                        result.texCoords << Vec2f(s, t-dt);
×
1996
                        result.vertex << Vec3d(x*radius, y*radius, z*oneMinusOblateness*radius);
×
1997
                        s += ds;
×
1998
                }
1999
                unsigned int offset = i*(slices+1)*2;
×
2000
                for (j = 2;j<slices*2+2;j+=2)
×
2001
                {
2002
                        result.indices << static_cast<unsigned short>(offset+j-2) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j);
×
2003
                        result.indices << static_cast<unsigned short>(offset+j) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j+1);
×
2004
                }
2005
                t -= dt;
×
2006
        }
2007
        return result;
×
2008
}
×
2009

2010
// Reimplementation of gluCylinder : glu is overridden for non standard projection
2011
void StelPainter::sCylinder(double radius, double height, int slices, int orientInside)
×
2012
{
2013
        if (orientInside)
×
2014
                glCullFace(GL_FRONT);
×
2015

2016
        static QVarLengthArray<Vec2f, 512> texCoordArray;
×
2017
        static QVarLengthArray<Vec3d, 512> vertexArray;
×
2018
        texCoordArray.clear();
×
2019
        vertexArray.clear();
×
2020
        float s = 0.f;
×
2021
        double x, y;
2022
        const float ds = 1.f / static_cast<float>(slices);
×
2023
        const double da = 2. * M_PI / slices;
×
2024
        for (int i = 0; i <= slices; ++i)
×
2025
        {
2026
                x = std::sin(da*i);
×
2027
                y = std::cos(da*i);
×
2028
                texCoordArray.append(Vec2f(s, 0.f));
×
2029
                vertexArray.append(Vec3d(x*radius, y*radius, 0.));
×
2030
                texCoordArray.append(Vec2f(s, 1.f));
×
2031
                vertexArray.append(Vec3d(x*radius, y*radius, height));
×
2032
                s += ds;
×
2033
        }
2034
        setArrays(vertexArray.constData(), texCoordArray.constData());
×
2035
        drawFromArray(TriangleStrip, vertexArray.size());
×
2036

2037
        if (orientInside)
×
2038
                glCullFace(GL_BACK);
×
2039
}
×
2040

2041
void StelPainter::initGLShaders()
×
2042
{
2043
        qDebug() << "Initializing basic GL shaders... ";
×
2044
        // Basic shader: just vertex filled with plain color
2045
        QOpenGLShader vshader3(QOpenGLShader::Vertex);
×
2046
        const auto vsrc3 =
2047
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2048
                "ATTRIBUTE mediump vec3 vertex;\n"
2049
                "uniform mediump mat4 projectionMatrix;\n"
2050
                "void main(void)\n"
2051
                "{\n"
2052
                "    gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
2053
                "}\n";
×
2054
        vshader3.compileSourceCode(vsrc3);
×
2055
        if (!vshader3.log().isEmpty())
×
2056
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader3: " << vshader3.log();
×
2057
        QOpenGLShader fshader3(QOpenGLShader::Fragment);
×
2058
        const auto fsrc3 =
2059
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2060
                "uniform mediump vec4 color;\n"
2061
                "void main(void)\n"
2062
                "{\n"
2063
                "    FRAG_COLOR = color;\n"
2064
                "}\n";
×
2065
        fshader3.compileSourceCode(fsrc3);
×
2066
        if (!fshader3.log().isEmpty())
×
2067
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader3: " << fshader3.log();
×
2068
        basicShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2069
        basicShaderProgram->addShader(&vshader3);
×
2070
        basicShaderProgram->addShader(&fshader3);
×
2071
        linkProg(basicShaderProgram, "basicShaderProgram");
×
2072
        basicShaderVars.projectionMatrix = basicShaderProgram->uniformLocation("projectionMatrix");
×
2073
        basicShaderVars.color = basicShaderProgram->uniformLocation("color");
×
2074
        basicShaderVars.vertex = basicShaderProgram->attributeLocation("vertex");
×
2075
        
2076

2077
        // Basic shader: vertex filled with interpolated color
2078
        QOpenGLShader vshaderInterpolatedColor(QOpenGLShader::Vertex);
×
2079
        const auto vshaderInterpolatedColorSrc =
2080
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2081
                "ATTRIBUTE mediump vec3 vertex;\n"
2082
                "ATTRIBUTE mediump vec4 color;\n"
2083
                "uniform mediump mat4 projectionMatrix;\n"
2084
                "VARYING mediump vec4 fragcolor;\n"
2085
                "void main(void)\n"
2086
                "{\n"
2087
                "    gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
2088
                "    fragcolor = color;\n"
2089
                "}\n";
×
2090
        vshaderInterpolatedColor.compileSourceCode(vshaderInterpolatedColorSrc);
×
2091
        if (!vshaderInterpolatedColor.log().isEmpty()) {
×
2092
          qWarning().noquote() << "StelPainter: Warnings while compiling vshaderInterpolatedColor: " << vshaderInterpolatedColor.log();
×
2093
        }
2094
        QOpenGLShader fshaderInterpolatedColor(QOpenGLShader::Fragment);
×
2095
        const auto fshaderInterpolatedColorSrc =
2096
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2097
                "VARYING mediump vec4 fragcolor;\n"
2098
                "void main(void)\n"
2099
                "{\n"
2100
                "    FRAG_COLOR = fragcolor;\n"
2101
                "}\n";
×
2102
        fshaderInterpolatedColor.compileSourceCode(fshaderInterpolatedColorSrc);
×
2103
        if (!fshaderInterpolatedColor.log().isEmpty()) {
×
2104
          qWarning().noquote() << "StelPainter: Warnings while compiling fshaderInterpolatedColor: " << fshaderInterpolatedColor.log();
×
2105
        }
2106
        colorShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2107
        colorShaderProgram->addShader(&vshaderInterpolatedColor);
×
2108
        colorShaderProgram->addShader(&fshaderInterpolatedColor);
×
2109
        linkProg(colorShaderProgram, "colorShaderProgram");
×
2110
        colorShaderVars.projectionMatrix = colorShaderProgram->uniformLocation("projectionMatrix");
×
2111
        colorShaderVars.color = colorShaderProgram->attributeLocation("color");
×
2112
        colorShaderVars.vertex = colorShaderProgram->attributeLocation("vertex");
×
2113
        
2114
        // Basic texture shader program
2115
        QOpenGLShader vshader2(QOpenGLShader::Vertex);
×
2116
        const auto vsrc2 =
2117
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2118
                "ATTRIBUTE highp vec3 vertex;\n"
2119
                "ATTRIBUTE mediump vec2 texCoord;\n"
2120
                "uniform mediump mat4 projectionMatrix;\n"
2121
                "VARYING mediump vec2 texc;\n"
2122
                "void main(void)\n"
2123
                "{\n"
2124
                "    gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
2125
                "    texc = texCoord;\n"
2126
                "}\n";
×
2127
        vshader2.compileSourceCode(vsrc2);
×
2128
        if (!vshader2.log().isEmpty())
×
2129
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader2: " << vshader2.log();
×
2130

2131
        QOpenGLShader fshader2(QOpenGLShader::Fragment);
×
2132
        const auto fsrc2 =
2133
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2134
                makeDitheringShader()+
×
2135
                "VARYING mediump vec2 texc;\n"
2136
                "uniform sampler2D tex;\n"
2137
                "uniform mediump vec4 texColor;\n"
2138
                "void main(void)\n"
2139
                "{\n"
2140
                "    FRAG_COLOR = dither(texture2D(tex, texc)*texColor);\n"
2141
                "}\n";
×
2142
        fshader2.compileSourceCode(fsrc2);
×
2143
        if (!fshader2.log().isEmpty())
×
2144
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader2: " << fshader2.log();
×
2145

2146
        texturesShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2147
        texturesShaderProgram->addShader(&vshader2);
×
2148
        texturesShaderProgram->addShader(&fshader2);
×
2149
        linkProg(texturesShaderProgram, "texturesShaderProgram");
×
2150
        texturesShaderVars.projectionMatrix = texturesShaderProgram->uniformLocation("projectionMatrix");
×
2151
        texturesShaderVars.texCoord = texturesShaderProgram->attributeLocation("texCoord");
×
2152
        texturesShaderVars.vertex = texturesShaderProgram->attributeLocation("vertex");
×
2153
        texturesShaderVars.texColor = texturesShaderProgram->uniformLocation("texColor");
×
2154
        texturesShaderVars.texture = texturesShaderProgram->uniformLocation("tex");
×
2155
        texturesShaderVars.ditherPattern = texturesShaderProgram->uniformLocation("ditherPattern");
×
2156
        texturesShaderVars.rgbMaxValue = texturesShaderProgram->uniformLocation("rgbMaxValue");
×
2157

2158
        // Texture shader program + interpolated color per vertex
2159
        QOpenGLShader vshader4(QOpenGLShader::Vertex);
×
2160
        const auto vsrc4 =
2161
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2162
                "ATTRIBUTE highp vec3 vertex;\n"
2163
                "ATTRIBUTE mediump vec2 texCoord;\n"
2164
                "ATTRIBUTE mediump vec4 color;\n"
2165
                "uniform mediump mat4 projectionMatrix;\n"
2166
                "VARYING mediump vec2 texc;\n"
2167
                "VARYING mediump vec4 outColor;\n"
2168
                "void main(void)\n"
2169
                "{\n"
2170
                "    gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
2171
                "    texc = texCoord;\n"
2172
                "    outColor = color;\n"
2173
                "}\n";
×
2174
        vshader4.compileSourceCode(vsrc4);
×
2175
        if (!vshader4.log().isEmpty())
×
2176
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader4: " << vshader4.log();
×
2177

2178
        QOpenGLShader fshader4(QOpenGLShader::Fragment);
×
2179
        const auto fsrc4 =
2180
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2181
                makeDitheringShader()+
×
2182
                makeSaturationShader()+
×
2183
                "VARYING mediump vec2 texc;\n"
2184
                "VARYING mediump vec4 outColor;\n"
2185
                "uniform sampler2D tex;\n"
2186
                "uniform lowp float saturation;\n"
2187
                "void main(void)\n"
2188
                "{\n"
2189
                "    FRAG_COLOR = dither(texture2D(tex, texc)*outColor);\n"
2190
                "    if (saturation != 1.0)\n"
2191
                "        FRAG_COLOR.rgb = saturate(FRAG_COLOR.rgb, saturation);\n"
2192
                "}\n";
×
2193
        fshader4.compileSourceCode(fsrc4);
×
2194
        if (!fshader4.log().isEmpty())
×
2195
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader4: " << fshader4.log();
×
2196

2197
        texturesColorShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2198
        texturesColorShaderProgram->addShader(&vshader4);
×
2199
        texturesColorShaderProgram->addShader(&fshader4);
×
2200
        linkProg(texturesColorShaderProgram, "texturesColorShaderProgram");
×
2201
        texturesColorShaderVars.projectionMatrix = texturesColorShaderProgram->uniformLocation("projectionMatrix");
×
2202
        texturesColorShaderVars.texCoord = texturesColorShaderProgram->attributeLocation("texCoord");
×
2203
        texturesColorShaderVars.vertex = texturesColorShaderProgram->attributeLocation("vertex");
×
2204
        texturesColorShaderVars.color = texturesColorShaderProgram->attributeLocation("color");
×
2205
        texturesColorShaderVars.texture = texturesColorShaderProgram->uniformLocation("tex");
×
2206
        texturesColorShaderVars.ditherPattern = texturesColorShaderProgram->uniformLocation("ditherPattern");
×
2207
        texturesColorShaderVars.rgbMaxValue = texturesColorShaderProgram->uniformLocation("rgbMaxValue");
×
2208
        texturesColorShaderVars.saturation = texturesColorShaderProgram->uniformLocation("saturation");
×
2209

2210
        if(StelMainView::getInstance().getGLInformation().isCoreProfile)
×
2211
        {
2212
                // In Core profile wide lines (width>1px) are not supported, so this shader is used to render them with triangles.
2213

2214
                // Common template for the geometry shader
2215
                const QByteArray geomSrc = 1+R"(
×
2216
#version 330
2217

2218
layout(lines) in;
2219
layout(triangle_strip, max_vertices=4) out;
2220
uniform vec2 viewportSize;
2221
uniform float lineWidth;
2222
#if @VARYING_COLOR@
2223
in vec4 varyingColor[2];
2224
out vec4 geomColor;
2225
#endif
2226

2227
void main()
2228
{
2229
        vec4 clip0 = gl_in[0].gl_Position;
2230
        vec4 clip1 = gl_in[1].gl_Position;
2231

2232
        vec3 ndc0 = clip0.xyz / clip0.w;
2233
        vec3 ndc1 = clip1.xyz / clip1.w;
2234

2235
        vec2 lineDir2d = normalize(ndc1.xy - ndc0.xy);
2236
        vec2 perpendicularDir2d = vec2(-lineDir2d.y, lineDir2d.x);
2237

2238
        vec2 offset2d = (lineWidth / viewportSize) * perpendicularDir2d;
2239

2240
        gl_Position = vec4(clip0.xy + offset2d*clip0.w, clip0.zw);
2241
#if @VARYING_COLOR@
2242
        geomColor = varyingColor[0];
2243
#endif
2244
        EmitVertex();
2245

2246
        gl_Position = vec4(clip0.xy - offset2d*clip0.w, clip0.zw);
2247
#if @VARYING_COLOR@
2248
        geomColor = varyingColor[0];
2249
#endif
2250
        EmitVertex();
2251

2252
        gl_Position = vec4(clip1.xy + offset2d*clip1.w, clip1.zw);
2253
#if @VARYING_COLOR@
2254
        geomColor = varyingColor[1];
2255
#endif
2256
        EmitVertex();
2257

2258
        gl_Position = vec4(clip1.xy - offset2d*clip1.w, clip1.zw);
2259
#if @VARYING_COLOR@
2260
        geomColor = varyingColor[1];
2261
#endif
2262
        EmitVertex();
2263

2264
        EndPrimitive();
2265
}
2266
)";
2267

2268
                // First a basic shader using constant line color
2269
                QOpenGLShader wideLineVertShader(QOpenGLShader::Vertex);
×
2270
                wideLineVertShader.compileSourceCode(1+R"(
×
2271
#version 330
2272
in vec3 vertex;
2273
uniform mat4 projectionMatrix;
2274
void main()
2275
{
2276
    gl_Position = projectionMatrix*vec4(vertex, 1.);
2277
}
2278
)");
2279
                if (!wideLineVertShader.log().isEmpty())
×
2280
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line vertex shader: " << wideLineVertShader.log();
×
2281

2282
                QOpenGLShader wideLineGeomShader(QOpenGLShader::Geometry);
×
2283
                wideLineGeomShader.compileSourceCode(QByteArray(geomSrc).replace("@VARYING_COLOR@","0"));
×
2284
                if (!wideLineGeomShader.log().isEmpty())
×
2285
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line geometry shader: " << wideLineGeomShader.log();
×
2286

2287
                QOpenGLShader wideLineFragShader(QOpenGLShader::Fragment);
×
2288
                wideLineFragShader.compileSourceCode(1+R"(
×
2289
#version 330
2290
uniform vec4 color;
2291
out vec4 outputColor;
2292
void main()
2293
{
2294
    outputColor = color;
2295
}
2296
)");
2297
                if (!wideLineFragShader.log().isEmpty())
×
2298
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line fragment shader: " << wideLineFragShader.log();
×
2299
                wideLineShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2300
                wideLineShaderProgram->addShader(&wideLineVertShader);
×
2301
                wideLineShaderProgram->addShader(&wideLineGeomShader);
×
2302
                wideLineShaderProgram->addShader(&wideLineFragShader);
×
2303
                linkProg(wideLineShaderProgram, "wideLineShaderProgram");
×
2304
                wideLineShaderVars.projectionMatrix = wideLineShaderProgram->uniformLocation("projectionMatrix");
×
2305
                wideLineShaderVars.viewportSize     = wideLineShaderProgram->uniformLocation("viewportSize");
×
2306
                wideLineShaderVars.lineWidth        = wideLineShaderProgram->uniformLocation("lineWidth");
×
2307
                wideLineShaderVars.color            = wideLineShaderProgram->uniformLocation("color");
×
2308
                wideLineShaderVars.vertex = wideLineShaderProgram->attributeLocation("vertex");
×
2309

2310
                // Now a version of the shader that supports color interpolated along the line
2311
                QOpenGLShader colorfulWideLineVertShader(QOpenGLShader::Vertex);
×
2312
                colorfulWideLineVertShader.compileSourceCode(1+R"(
×
2313
#version 330
2314
in vec3 vertex;
2315
in vec4 color;
2316
out vec4 varyingColor;
2317
uniform mat4 projectionMatrix;
2318
void main()
2319
{
2320
    gl_Position = projectionMatrix*vec4(vertex, 1.);
2321
        varyingColor = color;
2322
}
2323
)");
2324
                if (!colorfulWideLineVertShader.log().isEmpty())
×
2325
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line vertex shader: " << colorfulWideLineVertShader.log();
×
2326

2327
                QOpenGLShader colorfulWideLineGeomShader(QOpenGLShader::Geometry);
×
2328
                colorfulWideLineGeomShader.compileSourceCode(QByteArray(geomSrc).replace("@VARYING_COLOR@","1"));
×
2329
                if (!colorfulWideLineGeomShader.log().isEmpty())
×
2330
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line geometry shader: " << colorfulWideLineGeomShader.log();
×
2331

2332
                QOpenGLShader colorfulWideLineFragShader(QOpenGLShader::Fragment);
×
2333
                colorfulWideLineFragShader.compileSourceCode(1+R"(
×
2334
#version 330
2335
in vec4 geomColor;
2336
out vec4 outputColor;
2337
void main()
2338
{
2339
    outputColor = geomColor;
2340
}
2341
)");
2342
                if (!colorfulWideLineFragShader.log().isEmpty())
×
2343
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line fragment shader: " << colorfulWideLineFragShader.log();
×
2344
                colorfulWideLineShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2345
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineVertShader);
×
2346
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineGeomShader);
×
2347
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineFragShader);
×
2348
                linkProg(colorfulWideLineShaderProgram, "colorfulWideLineShaderProgram");
×
2349
                colorfulWideLineShaderVars.projectionMatrix = colorfulWideLineShaderProgram->uniformLocation("projectionMatrix");
×
2350
                colorfulWideLineShaderVars.viewportSize     = colorfulWideLineShaderProgram->uniformLocation("viewportSize");
×
2351
                colorfulWideLineShaderVars.lineWidth        = colorfulWideLineShaderProgram->uniformLocation("lineWidth");
×
2352
                colorfulWideLineShaderVars.color  = colorfulWideLineShaderProgram->attributeLocation("color");
×
2353
                colorfulWideLineShaderVars.vertex = colorfulWideLineShaderProgram->attributeLocation("vertex");
×
2354
        }
×
2355

2356
        multisamplingEnabled = StelApp::getInstance().getSettings()->value("video/multisampling", 0).toUInt() != 0;
×
2357
}
×
2358

2359

2360
void StelPainter::deinitGLShaders()
×
2361
{
2362
        delete basicShaderProgram;
×
2363
        basicShaderProgram = Q_NULLPTR;
×
2364
        delete colorShaderProgram;
×
2365
        colorShaderProgram = Q_NULLPTR;
×
2366
        delete texturesShaderProgram;
×
2367
        texturesShaderProgram = Q_NULLPTR;
×
2368
        delete texturesColorShaderProgram;
×
2369
        texturesColorShaderProgram = Q_NULLPTR;
×
2370
        delete wideLineShaderProgram;
×
2371
        wideLineShaderProgram = Q_NULLPTR;
×
2372
        delete colorfulWideLineShaderProgram;
×
2373
        colorfulWideLineShaderProgram = Q_NULLPTR;
×
2374
        texCache.clear();
×
2375
}
×
2376

2377

2378
void StelPainter::setArrays(const Vec3d* vertices, const Vec2f* texCoords, const Vec3f* colorArray, const Vec3f* normalArray)
×
2379
{
2380
        enableClientStates(vertices, texCoords, colorArray, normalArray);
×
2381
        setVertexPointer(3, GL_DOUBLE, vertices);
×
2382
        setTexCoordPointer(2, GL_FLOAT, texCoords);
×
2383
        setColorPointer(3, GL_FLOAT, colorArray);
×
2384
        setNormalPointer(GL_FLOAT, normalArray);
×
2385
}
×
2386

2387
void StelPainter::setArrays(const Vec3f* vertices, const Vec2f* texCoords, const Vec3f* colorArray, const Vec3f* normalArray)
×
2388
{
2389
        enableClientStates(vertices, texCoords, colorArray, normalArray);
×
2390
        setVertexPointer(3, GL_FLOAT, vertices);
×
2391
        setTexCoordPointer(2, GL_FLOAT, texCoords);
×
2392
        setColorPointer(3, GL_FLOAT, colorArray);
×
2393
        setNormalPointer(GL_FLOAT, normalArray);
×
2394
}
×
2395

2396
void StelPainter::enableClientStates(bool vertex, bool texture, bool color, bool normal)
×
2397
{
2398
        vertexArray.enabled = vertex;
×
2399
        texCoordArray.enabled = texture;
×
2400
        colorArray.enabled = color;
×
2401
        normalArray.enabled = normal;
×
2402
}
×
2403

2404
void StelPainter::drawFromArray(DrawingMode mode, int count, int offset, bool doProj, const unsigned short* indices)
×
2405
{
2406
        if(!count) return;
×
2407

2408
        ArrayDesc projectedVertexArray = vertexArray;
×
2409
        if (doProj)
×
2410
        {
2411
                // Project the vertex array using current projection
2412
                if (indices)
×
2413
                        projectedVertexArray = projectArray(vertexArray, 0, count, indices + offset);
×
2414
                else
2415
                        projectedVertexArray = projectArray(vertexArray, offset, count, Q_NULLPTR);
×
2416
        }
2417

2418
        QOpenGLShaderProgram* pr=Q_NULLPTR;
×
2419

2420
        const Mat4f& m = getProjector()->getProjectionMatrix();
×
2421
        const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]);
×
2422

2423
        vao->bind();
×
2424
        verticesVBO->bind();
×
2425
        GLsizeiptr numberOfVerticesToCopy = count + offset;
×
2426
        if(indices)
×
2427
        {
2428
                indicesVBO->bind();
×
2429
                indicesVBO->allocate(indices+offset, count * sizeof indices[0]);
×
2430
                numberOfVerticesToCopy = 1 + *std::max_element(indices + offset, indices + offset + count);
×
2431
        }
2432

2433
        const bool wideLineMode = (mode==LineStrip || mode==LineLoop) && StelMainView::getInstance().getGLInformation().isCoreProfile;
×
2434
#ifdef GL_MULTISAMPLE
2435
        const bool multisampleWasOn = multisamplingEnabled && glIsEnabled(GL_MULTISAMPLE);
×
2436
#endif
2437

2438
        const auto core = StelApp::getInstance().getCore();
×
2439
        const auto rgbMaxValue=calcRGBMaxValue(core->getDitheringMode());
×
2440
        if (!texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled)
×
2441
        {
2442
                pr = wideLineMode ? wideLineShaderProgram : basicShaderProgram;
×
2443
                pr->bind();
×
2444

2445
                verticesVBO->allocate(projectedVertexArray.pointer, projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy);
×
2446

2447
                if(wideLineMode)
×
2448
                {
2449
                        pr->setAttributeBuffer(wideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2450
                        pr->enableAttributeArray(wideLineShaderVars.vertex);
×
2451
                        pr->setUniformValue(wideLineShaderVars.projectionMatrix, qMat);
×
2452
                        pr->setUniformValue(wideLineShaderVars.color, currentColor[0], currentColor[1], currentColor[2], currentColor[3]);
×
2453
                        pr->setUniformValue(wideLineShaderVars.lineWidth, glState.lineWidth);
×
2454
                        GLint viewport[4] = {};
×
2455
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2456
                        pr->setUniformValue(wideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2457
#ifdef GL_MULTISAMPLE
2458
                        if(multisamplingEnabled && glState.lineSmooth)
×
2459
                                glEnable(GL_MULTISAMPLE);
×
2460
#endif
2461
                }
2462
                else
2463
                {
2464
                        pr->setAttributeBuffer(basicShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2465
                        pr->enableAttributeArray(basicShaderVars.vertex);
×
2466
                        pr->setUniformValue(basicShaderVars.projectionMatrix, qMat);
×
2467
                        pr->setUniformValue(basicShaderVars.color, currentColor[0], currentColor[1], currentColor[2], currentColor[3]);
×
2468
                }
2469
        }
×
2470
        else if (texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2471
        {
2472
                pr = texturesShaderProgram;
×
2473
                pr->bind();
×
2474

2475
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2476
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2477
                verticesVBO->allocate(bufferSize);
×
2478
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2479
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2480
                const auto texCoordDataOffset = vertexDataSize;
×
2481
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2482
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2483

2484
                pr->setAttributeBuffer(texturesShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2485
                pr->enableAttributeArray(texturesShaderVars.vertex);
×
2486
                pr->setUniformValue(texturesShaderVars.projectionMatrix, qMat);
×
2487
                pr->setUniformValue(texturesShaderVars.texColor, currentColor[0], currentColor[1], currentColor[2], currentColor[3]);
×
2488
                pr->setAttributeBuffer(texturesShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2489
                pr->enableAttributeArray(texturesShaderVars.texCoord);
×
2490
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2491
                const int ditherTexSampler = 1;
×
2492
                if(!ditherPatternTex)
×
2493
                        ditherPatternTex = StelApp::getInstance().getTextureManager().getDitheringTexture(ditherTexSampler);
×
2494
                else
2495
                        ditherPatternTex->bind(ditherTexSampler);
×
2496
                pr->setUniformValue(texturesShaderVars.ditherPattern, ditherTexSampler);
×
2497
                pr->setUniformValue(texturesShaderVars.rgbMaxValue, rgbMaxValue[0], rgbMaxValue[1], rgbMaxValue[2]);
×
2498
        }
×
2499
        else if (texCoordArray.enabled && colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2500
        {
2501
                pr = texturesColorShaderProgram;
×
2502
                pr->bind();
×
2503

2504
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2505
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2506
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2507
                verticesVBO->allocate(bufferSize);
×
2508
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2509
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2510
                const auto texCoordDataOffset = vertexDataSize;
×
2511
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2512
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2513
                const auto colorDataOffset = vertexDataSize + texCoordDataSize;
×
2514
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2515
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2516

2517
                pr->setAttributeBuffer(texturesColorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2518
                pr->enableAttributeArray(texturesColorShaderVars.vertex);
×
2519
                pr->setUniformValue(texturesColorShaderVars.projectionMatrix, qMat);
×
2520
                pr->setAttributeBuffer(texturesColorShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2521
                pr->enableAttributeArray(texturesColorShaderVars.texCoord);
×
2522
                pr->setAttributeBuffer(texturesColorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2523
                pr->enableAttributeArray(texturesColorShaderVars.color);
×
2524
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2525
                const int ditherTexSampler = 1;
×
2526
                if(!ditherPatternTex)
×
2527
                        ditherPatternTex = StelApp::getInstance().getTextureManager().getDitheringTexture(ditherTexSampler);
×
2528
                else
2529
                        ditherPatternTex->bind(ditherTexSampler);
×
2530
                pr->setUniformValue(texturesColorShaderVars.ditherPattern, ditherTexSampler);
×
2531
                pr->setUniformValue(texturesColorShaderVars.rgbMaxValue, rgbMaxValue[0], rgbMaxValue[1], rgbMaxValue[2]);
×
2532
                pr->setUniformValue(texturesColorShaderVars.saturation, saturation);
×
2533
        }
×
2534
        else if (!texCoordArray.enabled && colorArray.enabled && !normalArray.enabled)
×
2535
        {
2536
                pr = wideLineMode ? colorfulWideLineShaderProgram : colorShaderProgram;
×
2537
                pr->bind();
×
2538

2539
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2540
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2541
                verticesVBO->allocate(bufferSize);
×
2542
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2543
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2544
                const auto colorDataOffset = vertexDataSize;
×
2545
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2546
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2547

2548
                if(wideLineMode)
×
2549
                {
2550
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2551
                        pr->enableAttributeArray(colorfulWideLineShaderVars.vertex);
×
2552
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2553
                        pr->enableAttributeArray(colorfulWideLineShaderVars.color);
×
2554
                        pr->setUniformValue(colorfulWideLineShaderVars.projectionMatrix, qMat);
×
2555
                        pr->setUniformValue(colorfulWideLineShaderVars.lineWidth, glState.lineWidth);
×
2556
                        GLint viewport[4] = {};
×
2557
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2558
                        pr->setUniformValue(colorfulWideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2559
#ifdef GL_MULTISAMPLE
2560
                        if(multisamplingEnabled && glState.lineSmooth)
×
2561
                                glEnable(GL_MULTISAMPLE);
×
2562
#endif
2563
                }
2564
                else
2565
                {
2566
                        pr->setAttributeBuffer(colorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2567
                        pr->enableAttributeArray(colorShaderVars.vertex);
×
2568
                        pr->setUniformValue(colorShaderVars.projectionMatrix, qMat);
×
2569
                        pr->setAttributeBuffer(colorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2570
                        pr->enableAttributeArray(colorShaderVars.color);
×
2571
                }
2572
        }
×
2573
        else
2574
        {
2575
                qDebug() << "Unhandled parameters." << texCoordArray.enabled << colorArray.enabled << normalArray.enabled << wideLineMode;
×
2576
                Q_ASSERT(0);
×
2577
                return;
2578
        }
2579
        
2580
        if (indices)
×
2581
                glDrawElements(mode, count, GL_UNSIGNED_SHORT, 0);
×
2582
        else
2583
                glDrawArrays(mode, offset, count);
×
2584

2585
        verticesVBO->release();
×
2586
        indicesVBO->release();
×
2587
        vao->release();
×
2588

2589
        if (pr)
×
2590
                pr->release();
×
2591

2592
#ifdef GL_MULTISAMPLE
2593
        if(multisamplingEnabled && !multisampleWasOn && wideLineMode && glState.lineSmooth)
×
2594
                glDisable(GL_MULTISAMPLE);
×
2595
#endif
2596
}
2597

2598
size_t StelPainter::ArrayDesc::vertexSizeInBytes() const
×
2599
{
2600
        size_t elemSize = 1;
×
2601
        switch(type)
×
2602
        {
2603
        case GL_SHORT:
×
2604
                elemSize = sizeof(GLshort);
×
2605
                break;
×
2606
        case GL_INT:
×
2607
                elemSize = sizeof(GLint);
×
2608
                break;
×
2609
        case GL_FLOAT:
×
2610
                elemSize = sizeof(GLfloat);
×
2611
                break;
×
2612
#if GL_DOUBLE != GL_FLOAT // see StelOpenGL.hpp
2613
        case GL_DOUBLE:
×
2614
                elemSize = sizeof(GLdouble);
×
2615
                break;
×
2616
#endif
2617
        default:
×
2618
                Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected element type");
×
2619
                break;
2620
        }
2621
        return elemSize * size;
×
2622
}
2623

2624
StelPainter::ArrayDesc StelPainter::projectArray(const StelPainter::ArrayDesc& array, int offset, int count, const unsigned short* indices)
×
2625
{
2626
        // XXX: we should use a more generic way to test whether or not to do the projection.
2627
        if (dynamic_cast<StelProjector2d*>(prj.data()))
×
2628
        {
2629
                return array;
×
2630
        }
2631

2632
        Q_ASSERT(array.size == 3);
×
2633
        Q_ASSERT(array.type == GL_DOUBLE);
×
2634
        const Vec3d* vecArray = reinterpret_cast<const Vec3d *>(const_cast<void*>(array.pointer));
×
2635

2636
        // We have two different cases :
2637
        // 1) We are not using an indice array.  In that case the size of the array is known
2638
        // 2) We are using an indice array.  In that case we have to find the max value by iterating through the indices.
2639
        if (!indices)
×
2640
        {
2641
                polygonVertexArray.resize(offset + count);
×
2642
                prj->project(count, vecArray + offset, polygonVertexArray.data() + offset);
×
2643
        } else
2644
        {
2645
                // we need to find the max value of the indices !
2646
                unsigned short max = 0;
×
2647
                for (int i = offset; i < offset + count; ++i)
×
2648
                {
2649
                        max = std::max(max, indices[i]);
×
2650
                }
2651
                polygonVertexArray.resize(max+1);
×
2652
                prj->project(max + 1, vecArray + offset, polygonVertexArray.data() + offset);
×
2653
        }
2654

2655
        ArrayDesc ret;
×
2656
        ret.size = 3;
×
2657
        ret.type = GL_FLOAT;
×
2658
        ret.pointer = polygonVertexArray.constData();
×
2659
        ret.enabled = array.enabled;
×
2660
        return ret;
×
2661
}
2662

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc