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

Stellarium / stellarium / 10609521019

29 Aug 2024 05:56AM UTC coverage: 12.113% (-0.03%) from 12.138%
10609521019

Pull #3847

github

alex-w
[SSE] Add info for total candidates for addiing...
Pull Request #3847: Threaded planet computation (and a few more speedups)

30 of 686 new or added lines in 51 files covered. (4.37%)

41 existing lines in 18 files now uncovered.

14434 of 119159 relevant lines covered (12.11%)

19024.8 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
namespace
47
{
48
static const int TEX_CACHE_LIMIT = 7000000;
49

50
// These raw pointers are never deleted, because the only time their pointees
51
// need to be destroyed is when the whole program is exiting, and at this point
52
// we may not even have an OpenGL context anymore, so we'll never need to
53
// delete these objects manually.
54
QOpenGLVertexArrayObject* vao;
55
QOpenGLBuffer* verticesVBO;
56
QOpenGLBuffer* indicesVBO;
57
}
58

59
#ifndef NDEBUG
60
QMutex* StelPainter::globalMutex = new QMutex();
61
#endif
62

63
QCache<QByteArray, StringTexture> StelPainter::texCache(TEX_CACHE_LIMIT);
64
QOpenGLShaderProgram* StelPainter::texturesShaderProgram=Q_NULLPTR;
65
QOpenGLShaderProgram* StelPainter::textShaderProgram=Q_NULLPTR;
66
QOpenGLShaderProgram* StelPainter::basicShaderProgram=Q_NULLPTR;
67
QOpenGLShaderProgram* StelPainter::colorShaderProgram=Q_NULLPTR;
68
QOpenGLShaderProgram* StelPainter::texturesColorShaderProgram=Q_NULLPTR;
69
QOpenGLShaderProgram* StelPainter::wideLineShaderProgram=Q_NULLPTR;
70
QOpenGLShaderProgram* StelPainter::colorfulWideLineShaderProgram=Q_NULLPTR;
71
StelPainter::BasicShaderVars StelPainter::basicShaderVars;
72
StelPainter::TexturesShaderVars StelPainter::texturesShaderVars;
73
StelPainter::TextShaderVars StelPainter::textShaderVars;
74
StelPainter::BasicShaderVars StelPainter::colorShaderVars;
75
StelPainter::TexturesColorShaderVars StelPainter::texturesColorShaderVars;
76
StelPainter::WideLineShaderVars StelPainter::wideLineShaderVars;
77
StelPainter::ColorfulWideLineShaderVars StelPainter::colorfulWideLineShaderVars;
78
bool StelPainter::multisamplingEnabled=false;
79

80
StelPainter::GLState::GLState(QOpenGLFunctions* gl)
×
81
        : blend(false),
×
82
          blendSrc(GL_SRC_ALPHA), blendDst(GL_ONE_MINUS_SRC_ALPHA),
×
83
          depthTest(false),
×
84
          depthMask(false),
×
85
          cullFace(false),
×
86
          lineSmooth(false),
×
87
          lineWidth(1.0f),
×
88
          gl(gl)
×
89
{
90
}
×
91

92
void StelPainter::GLState::apply()
×
93
{
94
        if(blend)
×
95
                gl->glEnable(GL_BLEND);
×
96
        else
97
                gl->glDisable(GL_BLEND);
×
98
        gl->glBlendFunc(blendSrc,blendDst);
×
99
        if(depthTest)
×
100
                gl->glEnable(GL_DEPTH_TEST);
×
101
        else
102
                gl->glDisable(GL_DEPTH_TEST);
×
103
        gl->glDepthMask(depthMask);
×
104
        if(cullFace)
×
105
                gl->glEnable(GL_CULL_FACE);
×
106
        else
107
                gl->glDisable(GL_CULL_FACE);
×
108
        gl->glLineWidth(lineWidth);
×
109
#ifdef GL_LINE_SMOOTH
110
        if(!QOpenGLContext::currentContext()->isOpenGLES())
×
111
        {
112
                if (lineSmooth)
×
113
                        gl->glEnable(GL_LINE_SMOOTH);
×
114
                else
115
                        gl->glDisable(GL_LINE_SMOOTH);
×
116
        }
117
#endif
118
}
×
119

120
void StelPainter::GLState::reset()
×
121
{
122
        *this = GLState(gl);
×
123
        apply();
×
124
}
×
125

126
bool StelPainter::linkProg(QOpenGLShaderProgram* prog, const QString& name)
×
127
{
128
        bool ret = prog->link();
×
129
        QString log = prog->log();
×
130
        if (!ret || (!log.isEmpty() && !log.contains("Link was successful") && !(log=="No errors."))) //"No errors." returned on some Intel drivers
×
131
                qWarning().noquote() << QString("StelPainter: Warnings while linking %1 shader program:\n%2").arg(name, prog->log());
×
132
        return ret;
×
133
}
×
134

135
StelPainter::StelPainter(const StelProjectorP& proj)
×
136
        : QOpenGLFunctions(QOpenGLContext::currentContext())
137
        , glState(this)
×
138
{
139
        Q_ASSERT(proj);
×
140

141
#ifndef NDEBUG
142
        Q_ASSERT(globalMutex);
×
143
        
144
        GLenum er = glGetError();
×
145
        if (er!=GL_NO_ERROR)
×
146
        {
147
                if (er==GL_INVALID_OPERATION)
×
148
                        qFatal("Invalid openGL operation. It is likely that you used openGL calls without having a valid instance of StelPainter");
×
149
        }
150

151
        // Lock the global mutex ensuring that no other instances of StelPainter are currently being used
152
        if (globalMutex->tryLock()==false)
×
153
        {
154
                qFatal("There can be only 1 instance of StelPainter at a given time");
×
155
        }
156
#endif
157

158
        //TODO: is this still required, and is there some Qt way to fix it? 0x11111111 is a bit peculiar, how was it chosen?
159
        // Fix some problem when using Qt OpenGL2 engine
160
        glStencilMask(0x11111111);
×
161
        glState.apply(); //apply default OpenGL state
×
162
        setProjector(proj);
×
163

NEW
164
        if(!vao)
×
165
        {
166
                // First ever creation of StelPainter, initialize the objects
NEW
167
                vao = new QOpenGLVertexArrayObject;
×
NEW
168
                verticesVBO = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
×
NEW
169
                indicesVBO = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
×
170

NEW
171
                vao->create();
×
NEW
172
                indicesVBO->create();
×
NEW
173
                indicesVBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
NEW
174
                verticesVBO->create();
×
NEW
175
                verticesVBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
176
        }
UNCOV
177
}
×
178

179
void StelPainter::setProjector(const StelProjectorP& p)
×
180
{
181
        prj=p;
×
182
        // Init GL viewport to current projector values
183
        glViewport(prj->viewportXywh[0], prj->viewportXywh[1], prj->viewportXywh[2], prj->viewportXywh[3]);
×
184
        glFrontFace(prj->needGlFrontFaceCW()?GL_CW:GL_CCW);
×
185
}
×
186

187
StelPainter::~StelPainter()
×
188
{
189
        //reset opengl state
190
        glState.reset();
×
191

192
#ifndef NDEBUG
193
        GLenum er = glGetError();
×
194
        if (er!=GL_NO_ERROR)
×
195
        {
196
                if (er==GL_INVALID_OPERATION)
×
197
                        qFatal("Invalid openGL operation detected in ~StelPainter()");
×
198
        }
199

200
        // We are done with this StelPainter
201
        globalMutex->unlock();
×
202
#endif
203
}
×
204

205

206
void StelPainter::setFont(const QFont& font)
×
207
{
208
        currentFont = font;
×
209
}
×
210

211
void StelPainter::setColor(float r, float g, float b, float a)
×
212
{
213
        currentColor.set(r,g,b,a);
×
214
}
×
215

216
void StelPainter::setColor(Vec3f rgb, float a)
×
217
{
218
        currentColor.set(rgb[0],rgb[1],rgb[2],a);
×
219
}
×
220

221
void StelPainter::setColor(Vec4f rgba)
×
222
{
223
        currentColor=rgba;
×
224
}
×
225

226
Vec4f StelPainter::getColor() const
×
227
{
228
        return currentColor;
×
229
}
230

231
QFontMetrics StelPainter::getFontMetrics() const
×
232
{
233
        return QFontMetrics(currentFont);
×
234
}
235

236
void StelPainter::setBlending(bool enableBlending, GLenum blendSrc, GLenum blendDst)
×
237
{
238
        if(enableBlending != glState.blend)
×
239
        {
240
                glState.blend = enableBlending;
×
241
                if(enableBlending)
×
242
                        glEnable(GL_BLEND);
×
243
                else
244
                        glDisable(GL_BLEND);
×
245
        }
246
        if(enableBlending)
×
247
        {
248
                if(blendSrc!=glState.blendSrc||blendDst!=glState.blendDst)
×
249
                {
250
                        glState.blendSrc = blendSrc;
×
251
                        glState.blendDst = blendDst;
×
252
                        glBlendFunc(blendSrc,blendDst);
×
253
                }
254
        }
255
}
×
256

257
bool StelPainter::getBlending(GLenum *src, GLenum *dst) const
×
258
{
259
        if (dst!=Q_NULLPTR)
×
260
                *dst=glState.blendDst;
×
261
        if (src!=Q_NULLPTR)
×
262
                *src=glState.blendSrc;
×
263
        return glState.blend;
×
264
}
265

266
void StelPainter::setDepthTest(bool enable)
×
267
{
268
        if(glState.depthTest != enable)
×
269
        {
270
                glState.depthTest = enable;
×
271
                if(enable)
×
272
                        glEnable(GL_DEPTH_TEST);
×
273
                else
274
                        glDisable(GL_DEPTH_TEST);
×
275
        }
276
}
×
277

278
void StelPainter::setDepthMask(bool enable)
×
279
{
280
        if(glState.depthMask != enable)
×
281
        {
282
                glState.depthMask = enable;
×
283
                if(enable)
×
284
                        glDepthMask(GL_TRUE);
×
285
                else
286
                        glDepthMask(GL_FALSE);
×
287
        }
288
}
×
289

290
void StelPainter::setCullFace(bool enable)
×
291
{
292
        if(glState.cullFace!=enable)
×
293
        {
294
                glState.cullFace = enable;
×
295
                if(enable)
×
296
                        glEnable(GL_CULL_FACE);
×
297
                else
298
                        glDisable(GL_CULL_FACE);
×
299
        }
300
}
×
301

302
void StelPainter::setLineSmooth(bool enable)
×
303
{
304
#ifdef GL_LINE_SMOOTH
305
        if (!QOpenGLContext::currentContext()->isOpenGLES() && enable!=glState.lineSmooth)
×
306
        {
307
                glState.lineSmooth = enable;
×
308
                if(enable)
×
309
                        glEnable(GL_LINE_SMOOTH);
×
310
                else
311
                        glDisable(GL_LINE_SMOOTH);
×
312
        }
313
#else
314
        Q_UNUSED(enable); //noop
315
#endif
316
}
×
317

318
void StelPainter::setLineWidth(float width)
×
319
{
320
        if(fabs(glState.lineWidth - width) < 1.e-10f)
×
321
                return;
×
322

323
        glState.lineWidth = width;
×
324

325
        if(width > 1 && StelMainView::getInstance().getGLInformation().isCoreProfile)
×
326
                return;
×
327

328
        glLineWidth(width);
×
329
}
330

331
///////////////////////////////////////////////////////////////////////////
332
// Standard methods for drawing primitives
333

334
// Fill with black around the circle
335
void StelPainter::drawViewportShape(void)
×
336
{
337
        if (prj->maskType != StelProjector::MaskDisk)
×
338
                return;
×
339

340
        bool oldBlendState = glState.blend;
×
341
        glDisable(GL_BLEND);
×
342
        setColor(0.f,0.f,0.f);
×
343

344
        GLfloat innerRadius = 0.5f*static_cast<float>(prj->viewportFovDiameter);
×
345
        GLfloat outerRadius = static_cast<float>(prj->getViewportWidth()+prj->getViewportHeight());
×
346
        GLint slices = 239;
×
347

348
        GLfloat sinCache[240];
349
        GLfloat cosCache[240];
350
        GLfloat vertices[(240+1)*2][3];
351
        GLfloat deltaRadius;
352
        GLfloat radiusHigh;
353

354
        if (outerRadius<=0.0f || innerRadius<0.0f ||innerRadius > outerRadius)
×
355
        {
356
                Q_ASSERT(0);
×
357
                return;
358
        }
359

360
        /* Compute length (needed for normal calculations) */
361
        deltaRadius=outerRadius-innerRadius;
×
362

363
        /* Cache is the vertex locations cache */
364
        for (int i=0; i<=slices; i++)
×
365
        {
366
                GLfloat angle=(M_PIf*2.0f)*static_cast<float>(i)/static_cast<float>(slices);
×
367
                sinCache[i]=static_cast<GLfloat>(sin(angle));
×
368
                cosCache[i]=static_cast<GLfloat>(cos(angle));
×
369
        }
370

371
        sinCache[slices]=sinCache[0];
×
372
        cosCache[slices]=cosCache[0];
×
373

374
        /* Enable arrays */
375
        enableClientStates(true);
×
376
        setVertexPointer(3, GL_FLOAT, vertices);
×
377

378
        radiusHigh=outerRadius-deltaRadius;
×
379
        for (int i=0; i<=slices; i++)
×
380
        {
381
                vertices[i*2][0]= static_cast<float>(prj->viewportCenter[0]) + outerRadius*sinCache[i];
×
382
                vertices[i*2][1]= static_cast<float>(prj->viewportCenter[1]) + outerRadius*cosCache[i];
×
383
                vertices[i*2][2] = 0.0f;
×
384
                vertices[i*2+1][0]= static_cast<float>(prj->viewportCenter[0]) + radiusHigh*sinCache[i];
×
385
                vertices[i*2+1][1]= static_cast<float>(prj->viewportCenter[1]) + radiusHigh*cosCache[i];
×
386
                vertices[i*2+1][2] = 0.0f;
×
387
        }
388
        drawFromArray(TriangleStrip, (slices+1)*2, 0, false);
×
389
        enableClientStates(false);
×
390
        if(oldBlendState)
×
391
                glEnable(GL_BLEND);
×
392
}
393

394
void StelPainter::computeFanDisk(float radius, uint innerFanSlices, uint level, QVector<Vec3d>& vertexArr, QVector<Vec2f>& texCoordArr)
×
395
{
396
        Q_ASSERT(level<32);
×
397
        float rad[64];
398
        uint i,j;
399
        rad[level] = radius;
×
400
#pragma warning(suppress: 4146)
401
        for (i=level-1u;i!=-1u;--i)
×
402
        {
403
                rad[i] = rad[i+1]*(1.f-M_PIf/(innerFanSlices<<(i+1)))*2.f/3.f;
×
404
        }
405
        uint slices = innerFanSlices<<level;
×
406

407
        float* cos_sin_theta = StelUtils::ComputeCosSinTheta(static_cast<uint>(slices));
×
408
        float* cos_sin_theta_p;
409
        uint slices_step = 2;
×
410
        float x,y,xa,ya;
411
        radius*=2.f;
×
412
        vertexArr.resize(0);
×
413
        texCoordArr.resize(0);
×
414
        for (i=level;i>0;--i,slices_step<<=1)
×
415
        {
416
                for (j=0,cos_sin_theta_p=cos_sin_theta; j<slices-1; j+=slices_step,cos_sin_theta_p+=2*slices_step)
×
417
                {
418
                        xa = rad[i]*cos_sin_theta_p[slices_step];
×
419
                        ya = rad[i]*cos_sin_theta_p[slices_step+1];
×
420
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
421
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
422

423
                        x = rad[i]*cos_sin_theta_p[2*slices_step];
×
424
                        y = rad[i]*cos_sin_theta_p[2*slices_step+1];
×
425
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
426
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
427

428
                        x = rad[i-1]*cos_sin_theta_p[2*slices_step];
×
429
                        y = rad[i-1]*cos_sin_theta_p[2*slices_step+1];
×
430
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
431
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
432

433
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
434
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
435
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
436
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
437

438
                        x = rad[i-1]*cos_sin_theta_p[0];
×
439
                        y = rad[i-1]*cos_sin_theta_p[1];
×
440
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
441
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
442

443
                        texCoordArr << Vec2f(0.5f+xa/radius, 0.5f+ya/radius);
×
444
                        vertexArr << Vec3d(static_cast<double>(xa), static_cast<double>(ya), 0);
×
445
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
446
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
447

448
                        x = rad[i]*cos_sin_theta_p[0];
×
449
                        y = rad[i]*cos_sin_theta_p[1];
×
450
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
451
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
452
                }
453
        }
454
        // draw the inner polygon
455
        slices_step>>=1;
×
456
        cos_sin_theta_p=cos_sin_theta;
×
457

458
        if (slices==1)
×
459
        {
460
                x = rad[0]*cos_sin_theta_p[0];
×
461
                y = rad[0]*cos_sin_theta_p[1];
×
462
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
463
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
464
                cos_sin_theta_p+=2*slices_step;
×
465
                x = rad[0]*cos_sin_theta_p[0];
×
466
                y = rad[0]*cos_sin_theta_p[1];
×
467
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
468
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
469
                cos_sin_theta_p+=2*slices_step;
×
470
                x = rad[0]*cos_sin_theta_p[0];
×
471
                y = rad[0]*cos_sin_theta_p[1];
×
472
                texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
473
                vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
474
        }
475
        else
476
        {
477
                j=0;
×
478
                while (j<slices)
×
479
                {
480
                        texCoordArr << Vec2f(0.5f, 0.5f);
×
481
                        vertexArr << Vec3d(0, 0, 0);
×
482
                        x = rad[0]*cos_sin_theta_p[0];
×
483
                        y = rad[0]*cos_sin_theta_p[1];
×
484
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
485
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
486
                        j+=slices_step;
×
487
                        cos_sin_theta_p+=2*slices_step;
×
488
                        x = rad[0]*cos_sin_theta_p[0];
×
489
                        y = rad[0]*cos_sin_theta_p[1];
×
490
                        texCoordArr << Vec2f(0.5f+x/radius, 0.5f+y/radius);
×
491
                        vertexArr << Vec3d(static_cast<double>(x), static_cast<double>(y), 0);
×
492
                }
493
        }
494
}
×
495

496
static void sSphereMapTexCoordFast(float rho_div_fov, const float costheta, const float sintheta, QVector<float>& out)
×
497
{
498
        if (rho_div_fov>0.5f)
×
499
                rho_div_fov=0.5f;
×
500
        out << 0.5f + rho_div_fov * costheta << 0.5f + rho_div_fov * sintheta;
×
501
}
×
502

503
void StelPainter::sSphereMap(double radius, unsigned int slices, unsigned int stacks, float textureFov, int orientInside)
×
504
{
505
        float rho;
506
        double x,y,z;
507
        unsigned int i, j;
508
        const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
509
        const float* cos_sin_rho_p;
510

511
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
512
        const float* cos_sin_theta_p;
513

514
        float drho = M_PIf / static_cast<float>(stacks);
×
515
        drho/=textureFov;
×
516

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

521
        const unsigned int imax = stacks;
×
522

523
        static QVector<double> vertexArr;
×
524
        static QVector<float> texCoordArr;
×
525

526
        // draw intermediate stacks as quad strips
527
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
528
        if (!orientInside) // nsign==1
×
529
        {
530
                for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.f; i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
×
531
                {
532
                        vertexArr.resize(0);
×
533
                        texCoordArr.resize(0);
×
534
                        for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j,cos_sin_theta_p+=2)
×
535
                        {
536
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
537
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
538
                                z = static_cast<double>(cos_sin_rho_p[0]);
×
539
                                sSphereMapTexCoordFast(rho, cos_sin_theta_p[0], cos_sin_theta_p[1], texCoordArr);
×
540
                                vertexArr << x*radius << y*radius << z*radius;
×
541

542
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
543
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
544
                                z = static_cast<double>(cos_sin_rho_p[2]);
×
545
                                sSphereMapTexCoordFast(rho + drho, cos_sin_theta_p[0], cos_sin_theta_p[1], texCoordArr);
×
546
                                vertexArr << x*radius << y*radius << z*radius;
×
547
                        }
548
                        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
549
                        drawFromArray(TriangleStrip, vertexArr.size()/3);
×
550
                }
551
        }
552
        else
553
        {
554
                for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.f; i < imax; ++i,cos_sin_rho_p+=2,rho+=drho)
×
555
                {
556
                        vertexArr.resize(0);
×
557
                        texCoordArr.resize(0);
×
558
                        for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j,cos_sin_theta_p+=2)
×
559
                        {
560
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
561
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
562
                                z = static_cast<double>(cos_sin_rho_p[2]);
×
563
                                sSphereMapTexCoordFast(rho + drho, cos_sin_theta_p[0], -cos_sin_theta_p[1], texCoordArr);
×
564
                                vertexArr << x*radius << y*radius << z*radius;
×
565

566
                                x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
567
                                y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
568
                                z = static_cast<double>(cos_sin_rho_p[0]);
×
569
                                sSphereMapTexCoordFast(rho, cos_sin_theta_p[0], -cos_sin_theta_p[1], texCoordArr);
×
570
                                vertexArr << x*radius << y*radius << z*radius;
×
571
                        }
572
                        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
573
                        drawFromArray(TriangleStrip, vertexArr.size()/3);
×
574
                }
575
        }
576
}
×
577

578
void StelPainter::drawTextGravity180(float x, float y, const QString& ws, float xshift, float yshift)
×
579
{
580
        const float dx = x - static_cast<float>(prj->viewportCenter[0]);
×
581
        const float dy = y - static_cast<float>(prj->viewportCenter[1]);
×
582
        const float d = std::sqrt(dx*dx + dy*dy);
×
583
        const float limit = 120.;
×
584

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

589
        const float ppx = static_cast<float>(prj->getDevicePixelsPerPixel());
×
590
        const float cWidth = static_cast<float>(getFontMetrics().boundingRect(ws).width())/ws.length(); // average character width
×
591
        const float stdWidth = static_cast<float>(getFontMetrics().boundingRect("n").width());
×
592
        const float theta_o = M_PIf + std::atan2(dx, dy - 1);
×
593
        float theta = std::atan2(dy - 1, dx);
×
594
        float psi = std::atan2(ppx*cWidth*1.2, d + 1) * M_180_PIf; // Factor 1.2 is empirical.
×
595
        if (psi>5)
×
596
                psi = 5;
×
597

598
        const float xVc = static_cast<float>(prj->viewportCenter[0]) + xshift;
×
599
        const float yVc = static_cast<float>(prj->viewportCenter[1]) + yshift;
×
600
        const float cosr = std::cos(-theta_o * M_PI_180f);
×
601
        const float sinr = std::sin(-theta_o * M_PI_180f);
×
602
        float xom = x + xshift*cosr - yshift*sinr;
×
603
        float yom = y + yshift*sinr + xshift*cosr;
×
604
        float width;
605
        QChar s;
×
606

607
        if (!StelApp::getInstance().getLocaleMgr().isSkyRTL())
×
608
        {
609
                for (int i=0; i<ws.length(); ++i)
×
610
                {
611
                        s = ws[i];
×
612
                        if (d<limit)
×
613
                        {
614
                                drawText(xom, yom, s, -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
×
615
                                xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
616
                                yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
617
                        }
618
                        else
619
                        {
620
                                x = d * std::cos(theta) + xVc ;
×
621
                                y = d * std::sin(theta) + yVc ;
×
622
                                drawText(x, y, s, 90.f + theta*M_180_PIf, 0., 0.);
×
623
                                // Compute how much the character contributes to the angle
624
                                if (s.isSpace())
×
625
                                        width = stdWidth;
×
626
                                else
627
                                        width = static_cast<float>(getFontMetrics().boundingRect(s).width());
×
628
                                theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
×
629
                        }
630
                }
631
        }
632
        else
633
        {
634
                int slen = ws.length();
×
635
                for (int i=0;i<slen;i++)
×
636
                {
637
                        s = ws[slen-1-i];
×
638
                        if (d<limit)
×
639
                        {
640
                                drawText(xom, yom, s, -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
×
641
                                xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
642
                                yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
×
643
                        }
644
                        else
645
                        {
646
                                x = d * std::cos(theta) + xVc;
×
647
                                y = d * std::sin(theta) + yVc;
×
648
                                drawText(x, y, s, 90.f + theta*M_180_PIf, 0., 0.);
×
649
                                if (s.isSpace())
×
650
                                        width = stdWidth;
×
651
                                else
652
                                        width = static_cast<float>(getFontMetrics().boundingRect(s).width());
×
653
                                theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
×
654
                        }
655
                }
656
        }
657
}
658

659
void StelPainter::drawText(const Vec3d& v, const QString& str, float angleDeg, float xshift, float yshift, bool noGravity)
×
660
{
661
        Vec3d win;
×
662
        if (prj->project(v, win))
×
663
                drawText(static_cast<float>(win[0]), static_cast<float>(win[1]), str, angleDeg, xshift, yshift, noGravity);
×
664
}
×
665

666
/*************************************************************************
667
 Draw the string at the given position and angle with the given font
668
*************************************************************************/
669

670
// Methods taken from text-use-opengl-buffer
671
// Container for one cached string texture
672
struct StringTexture
673
{
674
        QOpenGLTexture* texture;
675
        QSize size;
676
        QPoint baselineShift;
677
        QSizeF getTexSize() const {
×
678
                return QSizeF(static_cast<qreal>(size.width())  / static_cast<qreal>(texture->width()),
×
679
                              static_cast<qreal>(size.height()) / static_cast<qreal>(texture->height()));
×
680
        }
681

682
        StringTexture(QOpenGLTexture* tex, const QSize& size, const QPoint& baselineShift) :
×
683
             texture(tex), size(size), baselineShift(baselineShift) {}
×
684
        ~StringTexture() {delete texture;}
×
685
};
686

687
StringTexture* StelPainter::getTextTexture(const QString& str, int pixelSize) const
×
688
{
689
        QByteArray hash = str.toUtf8() + QByteArray::number(pixelSize);
×
690
        StringTexture* cachedTex = texCache.object(hash);
×
691
        if (cachedTex)
×
692
                return cachedTex;
×
693
        QFont tmpFont = currentFont;
×
694
        tmpFont.setPixelSize(currentFont.pixelSize()*static_cast<int>(prj->getDevicePixelsPerPixel()));
×
695
        tmpFont.setStyleStrategy(QFont::NoSubpixelAntialias); // The text may rotate, which would break subpixel AA
×
696
        QRect strRect = QFontMetrics(tmpFont).boundingRect(str);
×
697
        int w = strRect.width()+1+static_cast<int>(0.02f*strRect.width());
×
698
        int h = strRect.height();
×
699

700
        QImage strImage(StelUtils::getBiggerPowerOfTwo(w), StelUtils::getBiggerPowerOfTwo(h),
701
                        QImage::Format_RGBX8888);
×
702
        strImage.fill(Qt::black);
×
703
        QPainter painter(&strImage);
×
704
        painter.setRenderHints(QPainter::TextAntialiasing);
×
705
        painter.setFont(tmpFont);
×
706
        painter.setPen(Qt::white);
×
707
        painter.drawText(-strRect.x(), -strRect.y(), str);
×
708
        StringTexture* newTex = new StringTexture(new QOpenGLTexture(strImage), QSize(w, h), QPoint(strRect.x(), -(strRect.y()+h)));
×
709
        newTex->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
×
710
        texCache.insert(hash, newTex, static_cast<long>(w)*h*3);
×
711
        // simply returning newTex is dangerous as the object is owned by the cache now. (Coverity Scan barks.)
712
        return texCache.object(hash);
×
713
}
×
714

715
void StelPainter::drawText(float x, float y, const QString& str, float angleDeg, float xshift, float yshift, bool noGravity)
×
716
{
717
        if (prj->gravityLabels && !noGravity)
×
718
        {
719
                drawTextGravity180(x, y, str, xshift, yshift);
×
720
        }
721
        else
722
        {
723
                StringTexture* tex = getTextTexture(str, currentFont.pixelSize());
×
724
                Q_ASSERT(tex);
×
725
                if (!noGravity)
×
726
                        angleDeg += prj->defaultAngleForGravityText;
×
727
                GLint oldTex = 0;
×
728
                glActiveTexture(GL_TEXTURE0);
×
729
                glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
×
730
                tex->texture->bind(0);
×
731
                x += tex->baselineShift.x();
×
732
                y += tex->baselineShift.y();
×
733

734
                static float vertexData[8];
735
                // compute the vertex coordinates applying the translation and the rotation
736
                static const float vertexBase[] = {0., 0., 1., 0., 0., 1., 1., 1.};
737
                if (std::fabs(angleDeg)>1.f*M_PI_180f)
×
738
                {
739
                        const float cosr = std::cos(angleDeg * M_PI_180f);
×
740
                        const float sinr = std::sin(angleDeg * M_PI_180f);
×
741
                        for (int i = 0; i < 8; i+=2)
×
742
                        {
743
                                vertexData[i]   = int(x + (tex->size.width()*vertexBase[i]+xshift) * cosr - (tex->size.height()*vertexBase[i+1]+yshift) * sinr);
×
744
                                vertexData[i+1] = int(y + (tex->size.width()*vertexBase[i]+xshift) * sinr + (tex->size.height()*vertexBase[i+1]+yshift) * cosr);
×
745
                        }
746
                }
747
                else
748
                {
749
                        for (int i = 0; i < 8; i+=2)
×
750
                        {
751
                                vertexData[i]   = int(x + tex->size.width()*vertexBase[i]+xshift);
×
752
                                vertexData[i+1] = int(y + tex->size.height()*vertexBase[i+1]+yshift);
×
753
                        }
754
                }
755

756
                float texCoords[8];
757
                for (int i=0;i<4;i++)
×
758
                {
759
                        texCoords[i*2+0] = static_cast<float>(tex->getTexSize().width()) * (i % 2);
×
760
                        texCoords[i*2+1] = static_cast<float>(tex->getTexSize().height()) * (1 - i / 2);
×
761
                }
762
                setTexCoordPointer(2, GL_FLOAT, texCoords);
×
763

764
                //text drawing requires blending, but we reset GL state afterwards if necessary
765
                bool oldBlending = glState.blend;
×
766
                GLenum oldSrc = glState.blendSrc, oldDst = glState.blendDst;
×
767
                setBlending(true);
×
768
                enableClientStates(true, true);
×
769
                setVertexPointer(2, GL_FLOAT, vertexData);
×
770

771
                const Mat4f& m = getProjector()->getProjectionMatrix();
×
772
                const QMatrix4x4 qMat(m[0], m[4], m[8], m[12],
773
                                      m[1], m[5], m[9], m[13],
774
                                      m[2], m[6], m[10], m[14],
775
                                      m[3], m[7], m[11], m[15]);
×
776

777
                vao->bind();
×
778
                verticesVBO->bind();
×
779
                const GLsizeiptr vertexCount = 4;
×
780

781
                auto& pr = *textShaderProgram;
×
782
                pr.bind();
×
783

784
                const auto bufferSize = vertexArray.vertexSizeInBytes()*vertexCount +
×
785
                                        texCoordArray.vertexSizeInBytes()*vertexCount;
×
786
                verticesVBO->allocate(bufferSize);
×
787
                const auto vertexDataSize = vertexArray.vertexSizeInBytes()*vertexCount;
×
788
                verticesVBO->write(0, vertexArray.pointer, vertexDataSize);
×
789
                const auto texCoordDataOffset = vertexDataSize;
×
790
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*vertexCount;
×
791
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
792

793
                pr.setAttributeBuffer(textShaderVars.vertex, vertexArray.type, 0, vertexArray.size);
×
794
                pr.enableAttributeArray(textShaderVars.vertex);
×
795
                pr.setUniformValue(textShaderVars.projectionMatrix, qMat);
×
796
                pr.setUniformValue(textShaderVars.textColor, currentColor.toQVector());
×
797
                pr.setAttributeBuffer(textShaderVars.texCoord, texCoordArray.type,
×
798
                                      texCoordDataOffset, texCoordArray.size);
799
                pr.enableAttributeArray(textShaderVars.texCoord);
×
800

801
                glDrawArrays(TriangleStrip, 0, vertexCount);
×
802

803
                verticesVBO->release();
×
804
                vao->release();
×
805

806
                pr.release();
×
807

808
                setBlending(oldBlending, oldSrc, oldDst);
×
809
                enableClientStates(false, false);
×
810
                glBindTexture(GL_TEXTURE_2D, oldTex);
×
811
        }
812
}
×
813

814
// Recursive method cutting a small circle in small segments
815
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)
×
816
{
817
        const bool crossDiscontinuity = checkCrossDiscontinuity && prj->intersectViewportDiscontinuity(p1+center, p2+center);
×
818
        if (crossDiscontinuity && nbI>=10)
×
819
        {
820
                win1[2]=-2.;
×
821
                win2[2]=-2.;
×
822
                vertexList.insert(iter, win1);
×
823
                vertexList.insert(iter, win2);
×
824
                return;
×
825
        }
826

827
        Vec3d newVertex(p1); newVertex+=p2;
×
828
        newVertex.normalize();
×
829
        newVertex*=radius;
×
830
        Vec3d win3(newVertex[0]+center[0], newVertex[1]+center[1], newVertex[2]+center[2]);
×
831
        const bool isValidVertex = prj->projectInPlace(win3);
×
832

833
        const float v10=static_cast<float>(win1[0]-win3[0]);
×
834
        const float v11=static_cast<float>(win1[1]-win3[1]);
×
835
        const float v20=static_cast<float>(win2[0]-win3[0]);
×
836
        const float v21=static_cast<float>(win2[1]-win3[1]);
×
837

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

849
// Used by the method below
850
QVector<Vec3f> StelPainter::smallCircleVertexArray;
851
QVector<Vec4f> StelPainter::smallCircleColorArray;
852

853
void StelPainter::drawSmallCircleVertexArray()
×
854
{
855
        if (smallCircleVertexArray.size() == 1)
×
856
        {
857
                smallCircleVertexArray.resize(0);
×
858
                smallCircleColorArray.resize(0);
×
859
                return;
×
860
        }
861
        if (smallCircleVertexArray.isEmpty())
×
862
                return;
×
863

864
        enableClientStates(true, false, !smallCircleColorArray.isEmpty());
×
865
        setVertexPointer(3, GL_FLOAT, smallCircleVertexArray.constData());
×
866
        if (!smallCircleColorArray.isEmpty())
×
867
                setColorPointer(4, GL_FLOAT, smallCircleColorArray.constData());
×
868
        drawFromArray(LineStrip, smallCircleVertexArray.size(), 0, false);
×
869
        enableClientStates(false);
×
870
        smallCircleVertexArray.resize(0);
×
871
        smallCircleColorArray.resize(0);
×
872
}
873

874
void StelPainter::drawGreatCircleArc(const Vec3d& start, const Vec3d& stop, const SphericalCap* clippingCap,
×
875
        void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, void* userData), void* userData)
876
 {
877
         if (clippingCap)
×
878
         {
879
                 Vec3d pt1=start;
×
880
                 Vec3d pt2=stop;
×
881
                 if (clippingCap->clipGreatCircle(pt1, pt2))
×
882
                 {
883
                        drawSmallCircleArc(pt1, pt2, Vec3d(0.), viewportEdgeIntersectCallback, userData);
×
884
                 }
885
                 return;
×
886
        }
887
        drawSmallCircleArc(start, stop, Vec3d(0.), viewportEdgeIntersectCallback, userData);
×
888
 }
889

890
/*************************************************************************
891
 Draw a small circle arc in the current frame
892
*************************************************************************/
893
void StelPainter::drawSmallCircleArc(const Vec3d& start, const Vec3d& stop, const Vec3d& rotCenter, void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, void* userData), void* userData)
×
894
{
895
        Q_ASSERT(smallCircleVertexArray.empty());
×
896

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

903

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

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

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

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

969
        for (int i = 0; i+1 != points.size(); i++)
×
970
        {
971
                const Vec3d p1 = points[i];
×
972
                const Vec3d p2 = points[i + 1];
×
973
                if (!prj->intersectViewportDiscontinuity(p1, p2))
×
974
                {
975
                        bool visible = prj->project(p1, win);
×
976

977
                        if (!visible && skipHiddenPoints)
×
978
                        {
979
                                drawSmallCircleVertexArray();
×
980
                                continue;
×
981
                        }
982

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

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

1029
        Vec3d e0=vertices[0];
×
1030
        Vec3d e1=vertices[1];
×
1031
        Vec3d e2=vertices[2];
×
1032
        bool valid = prj->projectInPlace(e0);
×
1033
        valid = prj->projectInPlace(e1) || valid;
×
1034
        valid = prj->projectInPlace(e2) || valid;
×
1035
        // Clip polygons behind the viewer
1036
        if (!valid)
×
1037
                return;
×
1038

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

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

1076
        if (nbI > 4)
×
1077
        {
1078
                // If we reached the limit number of iterations and still have a discontinuity,
1079
                // discards the triangle.
1080
                if (cd1 || cd2 || cd3)
×
1081
                        return;
×
1082

1083
                // Else display it, it will be suboptimal though.
1084
                outVertices->append(e0.toVec3f()); outVertices->append(e1.toVec3f()); outVertices->append(e2.toVec3f());
×
1085
                if (outTexturePos)
×
1086
                        outTexturePos->append(texturePos,3);
×
1087
                if (outColors)
×
1088
                        outColors->append(colors,3);
×
1089
                return;
×
1090
        }
1091

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

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

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

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

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

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

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

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

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

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

1324

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

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

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

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

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

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

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

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

1488
        return;
×
1489
}
1490

1491
static QVarLengthArray<Vec3f, 4096> polygonVertexArray;
1492
static QVarLengthArray<Vec2f, 4096> polygonTextureCoordArray;
1493
static QVarLengthArray<Vec3f, 4096> polygonColorArray;
1494
static QVarLengthArray<unsigned int, 4096> indexArray;
1495

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

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

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

1570
        // Draw the resulting arrays
1571
        void drawResult()
×
1572
        {
1573
                painter->setVertexPointer(3, GL_FLOAT, outVertices->constData());
×
1574
                if (outTexturePos)
×
1575
                        painter->setTexCoordPointer(2, GL_FLOAT, outTexturePos->constData());
×
1576
                if (outColors)
×
1577
                        painter->setColorPointer(3, GL_FLOAT, outColors->constData());
×
1578

1579
                painter->enableClientStates(true, outTexturePos != Q_NULLPTR, outColors != Q_NULLPTR);
×
1580
                painter->drawFromArray(StelPainter::Triangles, outVertices->size(), 0, false);
×
1581
                painter->enableClientStates(false);
×
1582
        }
×
1583

1584
private:
1585
        StelPainter* painter;
1586
        const SphericalCap* clippingCap;
1587
        QVarLengthArray<Vec3f, 4096>* outVertices;
1588
        QVarLengthArray<Vec3f, 4096>* outColors;
1589
        QVarLengthArray<Vec2f, 4096>* outTexturePos;
1590
        double maxSqDistortion;
1591
};
1592

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

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

1644
        enableClientStates(false);
×
1645
}
1646

1647
void StelPainter::drawSphericalTriangles(const StelVertexArray& va, bool textured, bool colored, const SphericalCap* clippingCap, bool doSubDivide, double maxSqDistortion)
×
1648
{
1649
        if (va.vertex.isEmpty())
×
1650
                return;
×
1651

1652
        Q_ASSERT(va.vertex.size()>2);
×
1653
        polygonVertexArray.clear();
×
1654
        polygonTextureCoordArray.clear();
×
1655

1656
        indexArray.clear();
×
1657

1658
        if (!doSubDivide)
×
1659
        {
1660
                // The simplest case, we don't need to iterate through the triangles at all.
1661
                drawStelVertexArray(va);
×
1662
                return;
×
1663
        }
1664

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

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

1680
        bool oldCullFace = glState.cullFace;
×
1681

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

1701
                        setCullFace(oldCullFace);
×
1702
                        break;
×
1703
                default:
×
1704
                        Q_ASSERT(0);
×
1705
        }
1706
}
1707

1708

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

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

1743
// rx: radius in x axis
1744
// ry: radius in y axis
1745
// angle rotation (counterclockwise), radians [0..2pi]
1746
void StelPainter::drawEllipse(double x, double y, double rX, double rY, double angle)
×
1747
{
1748
        if (rX <= 1.0 || rY <= 1.0)
×
1749
                return;
×
1750

1751
        //const float radiusY = 0.35 * size;
1752
        //const float radiusX = aspectRatio * radiusY;
1753
        const int numPoints = std::lround(std::clamp(qMax(rX, rY)/3, 32., 1024.));
×
1754
        std::vector<float> vertexData;
×
1755
        vertexData.reserve(numPoints*2);
×
1756
        const float*const cossin = StelUtils::ComputeCosSinTheta(numPoints);
×
1757
        const auto cosa = std::cos(angle);
×
1758
        const auto sina = std::sin(angle);
×
1759
        for(int n = 0; n < numPoints; ++n)
×
1760
        {
1761
                const auto cosb = cossin[2*n], sinb = cossin[2*n+1];
×
1762
                const auto pointX = rX*sinb;
×
1763
                const auto pointY = rY*cosb;
×
1764
                vertexData.push_back(x + pointX*cosa - pointY*sina);
×
1765
                vertexData.push_back(y + pointY*cosa + pointX*sina);
×
1766
        }
1767
        const auto vertCount = vertexData.size() / 2;
×
1768
        setLineSmooth(true);
×
1769
        setLineWidth(std::clamp(qMax(rX, rY)/40, 1., 2.));
×
1770
        enableClientStates(true);
×
1771
        setVertexPointer(2, GL_FLOAT, vertexData.data());
×
1772
        drawFromArray(StelPainter::LineLoop, vertCount, 0, false);
×
1773
        enableClientStates(false);
×
1774
}
×
1775

1776
void StelPainter::drawSprite2dMode(float x, float y, float radius)
×
1777
{
1778
        static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
1779
        static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
1780
        
1781
        // Takes into account device pixel density and global scale ratio, as we are drawing 2D stuff.
1782
        radius *= static_cast<float>(prj->getDevicePixelsPerPixel());
×
1783
        
1784
        vertexData[0]=x-radius; vertexData[1]=y-radius;
×
1785
        vertexData[2]=x+radius; vertexData[3]=y-radius;
×
1786
        vertexData[4]=x-radius; vertexData[5]=y+radius;
×
1787
        vertexData[6]=x+radius; vertexData[7]=y+radius;
×
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::drawSprite2dModeNoDeviceScale(float x, float y, float radius)
×
1796
{
1797
        drawSprite2dMode(x, y, radius/(static_cast<float>(prj->getDevicePixelsPerPixel())));
×
1798
}
×
1799

1800
void StelPainter::drawSprite2dMode(const Vec3d& v, float radius)
×
1801
{
1802
        Vec3d win;
×
1803
        if (prj->project(v, win))
×
1804
                drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), radius);
×
1805
}
×
1806

1807
void StelPainter::drawSprite2dMode(float x, float y, float radius, float rotation)
×
1808
{
1809
        static float vertexData[8];
1810
        static const float texCoordData[] = {0.f,0.f, 1.f,0.f, 0.f,1.f, 1.f,1.f};
1811

1812
        // compute the vertex coordinates applying the translation and the rotation
1813
        static const float vertexBase[] = {-1., -1., 1., -1., -1., 1., 1., 1.};
1814
        const float cosr = std::cos(rotation * M_PI_180f);
×
1815
        const float sinr = std::sin(rotation * M_PI_180f);
×
1816
        
1817
        // Takes into account device pixel density and global scale ratio, as we are drawing 2D stuff.
1818
        radius *= static_cast<float>(prj->getDevicePixelsPerPixel());
×
1819
        
1820
        for (int i = 0; i < 8; i+=2)
×
1821
        {
1822
                vertexData[i] = x + radius * vertexBase[i] * cosr - radius * vertexBase[i+1] * sinr;
×
1823
                vertexData[i+1] = y + radius * vertexBase[i] * sinr + radius * vertexBase[i+1] * cosr;
×
1824
        }
1825

1826
        enableClientStates(true, true);
×
1827
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1828
        setTexCoordPointer(2, GL_FLOAT, texCoordData);
×
1829
        drawFromArray(TriangleStrip, 4, 0, false);
×
1830
        enableClientStates(false);
×
1831
}
×
1832

1833
void StelPainter::drawRect2d(float x, float y, float width, float height, bool textured)
×
1834
{
1835
        static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
1836
        static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
1837
        vertexData[0]=x; vertexData[1]=y;
×
1838
        vertexData[2]=x+width; vertexData[3]=y;
×
1839
        vertexData[4]=x; vertexData[5]=y+height;
×
1840
        vertexData[6]=x+width; vertexData[7]=y+height;
×
1841
        if (textured)
×
1842
        {
1843
                enableClientStates(true, true);
×
1844
                setVertexPointer(2, GL_FLOAT, vertexData);
×
1845
                setTexCoordPointer(2, GL_FLOAT, texCoordData);
×
1846
        }
1847
        else
1848
        {
1849
                enableClientStates(true);
×
1850
                setVertexPointer(2, GL_FLOAT, vertexData);
×
1851
        }
1852
        drawFromArray(TriangleStrip, 4, 0, false);
×
1853
        enableClientStates(false);
×
1854
}
×
1855

1856
/*************************************************************************
1857
 Draw a GL_POINT at the given position
1858
*************************************************************************/
1859
void StelPainter::drawPoint2d(float x, float y)
×
1860
{
1861
        static float vertexData[] = {0.,0.};
1862
        vertexData[0]=x;
×
1863
        vertexData[1]=y;
×
1864

1865
        enableClientStates(true);
×
1866
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1867
        drawFromArray(Points, 1, 0, false);
×
1868
        enableClientStates(false);
×
1869
}
×
1870

1871

1872
/*************************************************************************
1873
 Draw a line between the 2 points.
1874
*************************************************************************/
1875
void StelPainter::drawLine2d(const float x1, const float y1, const float x2, const float y2)
×
1876
{
1877
        static float vertexData[] = {0.,0.,0.,0.};
1878
        vertexData[0]=x1;
×
1879
        vertexData[1]=y1;
×
1880
        vertexData[2]=x2;
×
1881
        vertexData[3]=y2;
×
1882

1883
        enableClientStates(true);
×
1884
        setVertexPointer(2, GL_FLOAT, vertexData);
×
1885
        drawFromArray(Lines, 2, 0, false);
×
1886
        enableClientStates(false);
×
1887
}
×
1888

1889
///////////////////////////////////////////////////////////////////////////
1890
// Drawing methods for general (non-linear) mode.
1891
// This used to draw a full sphere. Since 0.13 it's possible to have a spherical zone only.
1892
void StelPainter::sSphere(const double radius, const double oneMinusOblateness,
×
1893
                          const unsigned int slices, const unsigned int stacks,
1894
                          const bool orientInside, const bool flipTexture, const float topAngle, const float bottomAngle)
1895
{
1896
        double x, y, z;
1897
        GLfloat s=0.f, t=0.f;
×
1898
        GLfloat nsign;
1899

1900
        if (orientInside)
×
1901
        {
1902
                nsign = -1.f;
×
1903
                t=0.f; // from inside texture is reversed
×
1904
        }
1905
        else
1906
        {
1907
                nsign = 1.f;
×
1908
                t=1.f;
×
1909
        }
1910

1911
        const float* cos_sin_rho = Q_NULLPTR;
×
1912
        Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top.
×
1913
        if ((bottomAngle>3.1415f) && (topAngle<0.0001f)) // safety margin.
×
1914
                cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
1915
        else
1916
        {
1917
                const float drho = (bottomAngle-topAngle) / static_cast<float>(stacks); // deltaRho:  originally just 180degrees/stacks, now the range clamped.
×
1918
                cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PIf-bottomAngle);
×
1919
        }
1920
        // Allow parameters so that pole regions may remain free.
1921
        const float* cos_sin_rho_p;
1922

1923
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
1924
        const float *cos_sin_theta_p;
1925

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

1933
        // draw intermediate as quad strips
1934
        static QVector<double> vertexArr;
×
1935
        static QVector<float> texCoordArr;
×
1936
        static QVector<float> colorArr;
×
1937
        static QVector<unsigned short> indiceArr;
×
1938

1939
        texCoordArr.resize(0);
×
1940
        vertexArr.resize(0);
×
1941
        colorArr.resize(0);
×
1942
        indiceArr.resize(0);
×
1943

1944
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
1945
        uint i, j;
1946
        for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2)
×
1947
        {
1948
                s = flipTexture ? 1.f : 0.f;
×
1949
                for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2)
×
1950
                {
1951
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
1952
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
1953
                        z = static_cast<double>(nsign * cos_sin_rho_p[0]);
×
1954
                        texCoordArr << s << t;
×
1955
                        vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
×
1956
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
1957
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
1958
                        z = static_cast<double>(nsign * cos_sin_rho_p[2]);
×
1959
                        texCoordArr << s << t - dt;
×
1960
                        vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
×
1961
                        s += ds;
×
1962
                }
1963
                unsigned int offset = i*(slices+1)*2;
×
1964
                for (j = 2;j<slices*2+2;j+=2)
×
1965
                {
1966
                        indiceArr << static_cast<unsigned short>(offset+j-2) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j);
×
1967
                        indiceArr << static_cast<unsigned short>(offset+j) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j+1);
×
1968
                }
1969
                t -= dt;
×
1970
        }
1971

1972
        // Draw the array now
1973
        setArrays(reinterpret_cast<const Vec3d*>(vertexArr.constData()), reinterpret_cast<const Vec2f*>(texCoordArr.constData()));
×
1974
        drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData());
×
1975
}
×
1976

1977
StelVertexArray StelPainter::computeSphereNoLight(double radius, double oneMinusOblateness, unsigned int slices, unsigned int stacks,
×
1978
                          int orientInside, bool flipTexture, float topAngle, float bottomAngle)
1979
{
1980
        StelVertexArray result(StelVertexArray::Triangles);
×
1981
        double x, y, z;
1982
        GLfloat s=0.f, t=0.f;
×
1983
        GLuint i, j;
1984
        GLfloat nsign;
1985
        if (orientInside)
×
1986
        {
1987
                nsign = -1.f;
×
1988
                t=0.f; // from inside texture is reversed
×
1989
        }
1990
        else
1991
        {
1992
                nsign = 1.f;
×
1993
                t=1.f;
×
1994
        }
1995

1996
        const float* cos_sin_rho = Q_NULLPTR; //StelUtils::ComputeCosSinRho(stacks);
×
1997
        Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top.
×
1998
        if ((bottomAngle>3.1415f) && (topAngle<0.0001f)) // safety margin.
×
1999
                cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
×
2000
        else
2001
        {
2002
                const float drho = (bottomAngle-topAngle) / static_cast<float>(stacks); // deltaRho:  originally just 180degrees/stacks, now the range clamped.
×
2003
                cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PIf-bottomAngle);
×
2004
        }
2005
        // Allow parameters so that pole regions may remain free.
2006
        const float* cos_sin_rho_p;
2007

2008
        const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
×
2009
        const float *cos_sin_theta_p;
2010

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

2018
        // draw intermediate as quad strips
2019
        // LGTM comments: the floats are always <=1. We still prefer float multiplication (with insignificant accuracy loss) for speed.
2020
        for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2)
×
2021
        {
2022
                s = !flipTexture ? 0.f : 1.f;
×
2023
                for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2)
×
2024
                {
2025
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[1]);
×
2026
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[1]);
×
2027
                        z = static_cast<double>(nsign * cos_sin_rho_p[0]);
×
2028
                        result.texCoords << Vec2f(s,t);
×
2029
                        result.vertex << Vec3d(x*radius, y*radius, z*oneMinusOblateness*radius);
×
2030
                        x = static_cast<double>(-cos_sin_theta_p[1] * cos_sin_rho_p[3]);
×
2031
                        y = static_cast<double>(cos_sin_theta_p[0] * cos_sin_rho_p[3]);
×
2032
                        z = static_cast<double>(nsign * cos_sin_rho_p[2]);
×
2033
                        result.texCoords << Vec2f(s, t-dt);
×
2034
                        result.vertex << Vec3d(x*radius, y*radius, z*oneMinusOblateness*radius);
×
2035
                        s += ds;
×
2036
                }
2037
                unsigned int offset = i*(slices+1)*2;
×
2038
                for (j = 2;j<slices*2+2;j+=2)
×
2039
                {
2040
                        result.indices << static_cast<unsigned short>(offset+j-2) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j);
×
2041
                        result.indices << static_cast<unsigned short>(offset+j) << static_cast<unsigned short>(offset+j-1) << static_cast<unsigned short>(offset+j+1);
×
2042
                }
2043
                t -= dt;
×
2044
        }
2045
        return result;
×
2046
}
×
2047

2048
// Reimplementation of gluCylinder : glu is overridden for non standard projection
2049
void StelPainter::sCylinder(double radius, double height, int slices, int orientInside)
×
2050
{
2051
        if (orientInside)
×
2052
                glCullFace(GL_FRONT);
×
2053

2054
        static QVarLengthArray<Vec2f, 512> texCoordArray;
×
2055
        static QVarLengthArray<Vec3d, 512> vertexArray;
×
2056
        texCoordArray.clear();
×
2057
        vertexArray.clear();
×
2058
        float s = 0.f;
×
2059
        double x, y;
2060
        const float ds = 1.f / static_cast<float>(slices);
×
2061
        const double da = 2. * M_PI / slices;
×
2062
        for (int i = 0; i <= slices; ++i)
×
2063
        {
2064
                x = std::sin(da*i);
×
2065
                y = std::cos(da*i);
×
2066
                texCoordArray.append(Vec2f(s, 0.f));
×
2067
                vertexArray.append(Vec3d(x*radius, y*radius, 0.));
×
2068
                texCoordArray.append(Vec2f(s, 1.f));
×
2069
                vertexArray.append(Vec3d(x*radius, y*radius, height));
×
2070
                s += ds;
×
2071
        }
2072
        setArrays(vertexArray.constData(), texCoordArray.constData());
×
2073
        drawFromArray(TriangleStrip, vertexArray.size());
×
2074

2075
        if (orientInside)
×
2076
                glCullFace(GL_BACK);
×
2077
}
×
2078

2079
void StelPainter::initGLShaders()
×
2080
{
2081
        qDebug() << "Initializing basic GL shaders... ";
×
2082
        // Basic shader: just vertex filled with plain color
2083
        QOpenGLShader vshader3(QOpenGLShader::Vertex);
×
2084
        const auto vsrc3 =
2085
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2086
                "ATTRIBUTE mediump vec3 vertex;\n"
2087
                "uniform mediump mat4 projectionMatrix;\n"
2088
                "void main(void)\n"
2089
                "{\n"
2090
                "    gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
2091
                "}\n";
×
2092
        vshader3.compileSourceCode(vsrc3);
×
2093
        if (!vshader3.log().isEmpty())
×
2094
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader3: " << vshader3.log();
×
2095
        QOpenGLShader fshader3(QOpenGLShader::Fragment);
×
2096
        const auto fsrc3 =
2097
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2098
                "uniform mediump vec4 color;\n"
2099
                "void main(void)\n"
2100
                "{\n"
2101
                "    FRAG_COLOR = color;\n"
2102
                "}\n";
×
2103
        fshader3.compileSourceCode(fsrc3);
×
2104
        if (!fshader3.log().isEmpty())
×
2105
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader3: " << fshader3.log();
×
2106
        basicShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2107
        basicShaderProgram->addShader(&vshader3);
×
2108
        basicShaderProgram->addShader(&fshader3);
×
2109
        linkProg(basicShaderProgram, "basicShaderProgram");
×
2110
        basicShaderVars.projectionMatrix = basicShaderProgram->uniformLocation("projectionMatrix");
×
2111
        basicShaderVars.color = basicShaderProgram->uniformLocation("color");
×
2112
        basicShaderVars.vertex = basicShaderProgram->attributeLocation("vertex");
×
2113
        
2114

2115
        // Basic shader: vertex filled with interpolated color
2116
        QOpenGLShader vshaderInterpolatedColor(QOpenGLShader::Vertex);
×
2117
        const auto vshaderInterpolatedColorSrc =
2118
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2119
                "ATTRIBUTE mediump vec3 vertex;\n"
2120
                "ATTRIBUTE mediump vec4 color;\n"
2121
                "uniform mediump mat4 projectionMatrix;\n"
2122
                "VARYING mediump vec4 fragcolor;\n"
2123
                "void main(void)\n"
2124
                "{\n"
2125
                "    gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
2126
                "    fragcolor = color;\n"
2127
                "}\n";
×
2128
        vshaderInterpolatedColor.compileSourceCode(vshaderInterpolatedColorSrc);
×
2129
        if (!vshaderInterpolatedColor.log().isEmpty()) {
×
2130
          qWarning().noquote() << "StelPainter: Warnings while compiling vshaderInterpolatedColor: " << vshaderInterpolatedColor.log();
×
2131
        }
2132
        QOpenGLShader fshaderInterpolatedColor(QOpenGLShader::Fragment);
×
2133
        const auto fshaderInterpolatedColorSrc =
2134
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2135
                "VARYING mediump vec4 fragcolor;\n"
2136
                "void main(void)\n"
2137
                "{\n"
2138
                "    FRAG_COLOR = fragcolor;\n"
2139
                "}\n";
×
2140
        fshaderInterpolatedColor.compileSourceCode(fshaderInterpolatedColorSrc);
×
2141
        if (!fshaderInterpolatedColor.log().isEmpty()) {
×
2142
          qWarning().noquote() << "StelPainter: Warnings while compiling fshaderInterpolatedColor: " << fshaderInterpolatedColor.log();
×
2143
        }
2144
        colorShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2145
        colorShaderProgram->addShader(&vshaderInterpolatedColor);
×
2146
        colorShaderProgram->addShader(&fshaderInterpolatedColor);
×
2147
        linkProg(colorShaderProgram, "colorShaderProgram");
×
2148
        colorShaderVars.projectionMatrix = colorShaderProgram->uniformLocation("projectionMatrix");
×
2149
        colorShaderVars.color = colorShaderProgram->attributeLocation("color");
×
2150
        colorShaderVars.vertex = colorShaderProgram->attributeLocation("vertex");
×
2151
        
2152
        // Text shader program
2153
        QOpenGLShader textVShader(QOpenGLShader::Vertex);
×
2154
        const auto textVSrc =
2155
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) + R"(
×
2156
ATTRIBUTE highp vec3 vertex;
2157
ATTRIBUTE mediump vec2 texCoord;
2158
uniform mediump mat4 projectionMatrix;
2159
VARYING mediump vec2 texc;
2160
void main()
2161
{
2162
        gl_Position = projectionMatrix * vec4(vertex, 1.);
2163
        texc = texCoord;
2164
})";
2165
        textVShader.compileSourceCode(textVSrc);
×
2166
        if (!textVShader.log().isEmpty())
×
2167
                qWarning().noquote() << "StelPainter: Warnings while compiling text vertex shader: " << textVShader.log();
×
2168

2169
        QOpenGLShader textFShader(QOpenGLShader::Fragment);
×
2170
        const auto textFSrc =
2171
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) + R"(
×
2172
VARYING mediump vec2 texc;
2173
uniform sampler2D tex;
2174
uniform mediump vec4 textColor;
2175
void main()
2176
{
2177
        float mask = texture2D(tex, texc).r;
2178
        FRAG_COLOR = vec4(textColor.rgb, textColor.a*mask);
2179
})";
2180
        textFShader.compileSourceCode(textFSrc);
×
2181
        if (!textFShader.log().isEmpty())
×
2182
                qWarning().noquote() << "StelPainter: Warnings while compiling text fragment shader: " << textFShader.log();
×
2183

2184
        textShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2185
        textShaderProgram->addShader(&textVShader);
×
2186
        textShaderProgram->addShader(&textFShader);
×
2187
        linkProg(textShaderProgram, "textShaderProgram");
×
2188
        textShaderVars.projectionMatrix = textShaderProgram->uniformLocation("projectionMatrix");
×
2189
        textShaderVars.texCoord = textShaderProgram->attributeLocation("texCoord");
×
2190
        textShaderVars.vertex = textShaderProgram->attributeLocation("vertex");
×
2191
        textShaderVars.textColor = textShaderProgram->uniformLocation("textColor");
×
2192
        textShaderVars.texture = textShaderProgram->uniformLocation("tex");
×
2193

2194
        // Basic texture shader program
2195
        QOpenGLShader vshader2(QOpenGLShader::Vertex);
×
2196
        const auto vsrc2 =
2197
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2198
                "ATTRIBUTE highp vec3 vertex;\n"
2199
                "ATTRIBUTE mediump vec2 texCoord;\n"
2200
                "uniform mediump mat4 projectionMatrix;\n"
2201
                "VARYING mediump vec2 texc;\n"
2202
                "void main(void)\n"
2203
                "{\n"
2204
                "    gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
2205
                "    texc = texCoord;\n"
2206
                "}\n";
×
2207
        vshader2.compileSourceCode(vsrc2);
×
2208
        if (!vshader2.log().isEmpty())
×
2209
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader2: " << vshader2.log();
×
2210

2211
        QOpenGLShader fshader2(QOpenGLShader::Fragment);
×
2212
        const auto fsrc2 =
2213
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2214
                "VARYING mediump vec2 texc;\n"
2215
                "uniform sampler2D tex;\n"
2216
                "uniform mediump vec4 texColor;\n"
2217
                "void main(void)\n"
2218
                "{\n"
2219
                "    FRAG_COLOR = texture2D(tex, texc)*texColor;\n"
2220
                "}\n";
×
2221
        fshader2.compileSourceCode(fsrc2);
×
2222
        if (!fshader2.log().isEmpty())
×
2223
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader2: " << fshader2.log();
×
2224

2225
        texturesShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2226
        texturesShaderProgram->addShader(&vshader2);
×
2227
        texturesShaderProgram->addShader(&fshader2);
×
2228
        linkProg(texturesShaderProgram, "texturesShaderProgram");
×
2229
        texturesShaderVars.projectionMatrix = texturesShaderProgram->uniformLocation("projectionMatrix");
×
2230
        texturesShaderVars.texCoord = texturesShaderProgram->attributeLocation("texCoord");
×
2231
        texturesShaderVars.vertex = texturesShaderProgram->attributeLocation("vertex");
×
2232
        texturesShaderVars.texColor = texturesShaderProgram->uniformLocation("texColor");
×
2233
        texturesShaderVars.texture = texturesShaderProgram->uniformLocation("tex");
×
2234

2235
        // Texture shader program + interpolated color per vertex
2236
        QOpenGLShader vshader4(QOpenGLShader::Vertex);
×
2237
        const auto vsrc4 =
2238
                StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) +
×
2239
                "ATTRIBUTE highp vec3 vertex;\n"
2240
                "ATTRIBUTE mediump vec2 texCoord;\n"
2241
                "ATTRIBUTE mediump vec4 color;\n"
2242
                "uniform mediump mat4 projectionMatrix;\n"
2243
                "VARYING mediump vec2 texc;\n"
2244
                "VARYING mediump vec4 outColor;\n"
2245
                "void main(void)\n"
2246
                "{\n"
2247
                "    gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
2248
                "    texc = texCoord;\n"
2249
                "    outColor = color;\n"
2250
                "}\n";
×
2251
        vshader4.compileSourceCode(vsrc4);
×
2252
        if (!vshader4.log().isEmpty())
×
2253
                qWarning().noquote() << "StelPainter: Warnings while compiling vshader4: " << vshader4.log();
×
2254

2255
        QOpenGLShader fshader4(QOpenGLShader::Fragment);
×
2256
        const auto fsrc4 =
2257
                StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) +
×
2258
                makeSaturationShader()+
×
2259
                "VARYING mediump vec2 texc;\n"
2260
                "VARYING mediump vec4 outColor;\n"
2261
                "uniform sampler2D tex;\n"
2262
                "uniform lowp float saturation;\n"
2263
                "void main(void)\n"
2264
                "{\n"
2265
                "    FRAG_COLOR = texture2D(tex, texc)*outColor;\n"
2266
                "    if (saturation != 1.0)\n"
2267
                "        FRAG_COLOR.rgb = saturate(FRAG_COLOR.rgb, saturation);\n"
2268
                "}\n";
×
2269
        fshader4.compileSourceCode(fsrc4);
×
2270
        if (!fshader4.log().isEmpty())
×
2271
                qWarning().noquote() << "StelPainter: Warnings while compiling fshader4: " << fshader4.log();
×
2272

2273
        texturesColorShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2274
        texturesColorShaderProgram->addShader(&vshader4);
×
2275
        texturesColorShaderProgram->addShader(&fshader4);
×
2276
        linkProg(texturesColorShaderProgram, "texturesColorShaderProgram");
×
2277
        texturesColorShaderVars.projectionMatrix = texturesColorShaderProgram->uniformLocation("projectionMatrix");
×
2278
        texturesColorShaderVars.texCoord = texturesColorShaderProgram->attributeLocation("texCoord");
×
2279
        texturesColorShaderVars.vertex = texturesColorShaderProgram->attributeLocation("vertex");
×
2280
        texturesColorShaderVars.color = texturesColorShaderProgram->attributeLocation("color");
×
2281
        texturesColorShaderVars.texture = texturesColorShaderProgram->uniformLocation("tex");
×
2282
        texturesColorShaderVars.saturation = texturesColorShaderProgram->uniformLocation("saturation");
×
2283

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

2288
                // Common template for the geometry shader
2289
                const QByteArray geomSrc = 1+R"(
×
2290
#version 330
2291

2292
layout(lines) in;
2293
layout(triangle_strip, max_vertices=4) out;
2294
uniform vec2 viewportSize;
2295
uniform float lineWidth;
2296
#if @VARYING_COLOR@
2297
in vec4 varyingColor[2];
2298
out vec4 geomColor;
2299
#endif
2300

2301
void main()
2302
{
2303
        vec4 clip0 = gl_in[0].gl_Position;
2304
        vec4 clip1 = gl_in[1].gl_Position;
2305

2306
        vec3 ndc0 = clip0.xyz / clip0.w;
2307
        vec3 ndc1 = clip1.xyz / clip1.w;
2308

2309
        vec2 lineDir2d = normalize((ndc1.xy - ndc0.xy) * viewportSize);
2310
        vec2 perpendicularDir2d = vec2(-lineDir2d.y, lineDir2d.x);
2311

2312
        vec2 offset2d = (lineWidth / viewportSize) * perpendicularDir2d;
2313

2314
        gl_Position = vec4(clip0.xy + offset2d*clip0.w, clip0.zw);
2315
#if @VARYING_COLOR@
2316
        geomColor = varyingColor[0];
2317
#endif
2318
        EmitVertex();
2319

2320
        gl_Position = vec4(clip0.xy - offset2d*clip0.w, clip0.zw);
2321
#if @VARYING_COLOR@
2322
        geomColor = varyingColor[0];
2323
#endif
2324
        EmitVertex();
2325

2326
        gl_Position = vec4(clip1.xy + offset2d*clip1.w, clip1.zw);
2327
#if @VARYING_COLOR@
2328
        geomColor = varyingColor[1];
2329
#endif
2330
        EmitVertex();
2331

2332
        gl_Position = vec4(clip1.xy - offset2d*clip1.w, clip1.zw);
2333
#if @VARYING_COLOR@
2334
        geomColor = varyingColor[1];
2335
#endif
2336
        EmitVertex();
2337

2338
        EndPrimitive();
2339
}
2340
)";
2341

2342
                // First a basic shader using constant line color
2343
                QOpenGLShader wideLineVertShader(QOpenGLShader::Vertex);
×
2344
                wideLineVertShader.compileSourceCode(1+R"(
×
2345
#version 330
2346
in vec3 vertex;
2347
uniform mat4 projectionMatrix;
2348
void main()
2349
{
2350
    gl_Position = projectionMatrix*vec4(vertex, 1.);
2351
}
2352
)");
2353
                if (!wideLineVertShader.log().isEmpty())
×
2354
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line vertex shader: " << wideLineVertShader.log();
×
2355

2356
                QOpenGLShader wideLineGeomShader(QOpenGLShader::Geometry);
×
2357
                wideLineGeomShader.compileSourceCode(QByteArray(geomSrc).replace("@VARYING_COLOR@","0"));
×
2358
                if (!wideLineGeomShader.log().isEmpty())
×
2359
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line geometry shader: " << wideLineGeomShader.log();
×
2360

2361
                QOpenGLShader wideLineFragShader(QOpenGLShader::Fragment);
×
2362
                wideLineFragShader.compileSourceCode(1+R"(
×
2363
#version 330
2364
uniform vec4 color;
2365
out vec4 outputColor;
2366
void main()
2367
{
2368
    outputColor = color;
2369
}
2370
)");
2371
                if (!wideLineFragShader.log().isEmpty())
×
2372
                        qWarning().noquote() << "StelPainter: Warnings while compiling wide line fragment shader: " << wideLineFragShader.log();
×
2373
                wideLineShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2374
                wideLineShaderProgram->addShader(&wideLineVertShader);
×
2375
                wideLineShaderProgram->addShader(&wideLineGeomShader);
×
2376
                wideLineShaderProgram->addShader(&wideLineFragShader);
×
2377
                linkProg(wideLineShaderProgram, "wideLineShaderProgram");
×
2378
                wideLineShaderVars.projectionMatrix = wideLineShaderProgram->uniformLocation("projectionMatrix");
×
2379
                wideLineShaderVars.viewportSize     = wideLineShaderProgram->uniformLocation("viewportSize");
×
2380
                wideLineShaderVars.lineWidth        = wideLineShaderProgram->uniformLocation("lineWidth");
×
2381
                wideLineShaderVars.color            = wideLineShaderProgram->uniformLocation("color");
×
2382
                wideLineShaderVars.vertex = wideLineShaderProgram->attributeLocation("vertex");
×
2383

2384
                // Now a version of the shader that supports color interpolated along the line
2385
                QOpenGLShader colorfulWideLineVertShader(QOpenGLShader::Vertex);
×
2386
                colorfulWideLineVertShader.compileSourceCode(1+R"(
×
2387
#version 330
2388
in vec3 vertex;
2389
in vec4 color;
2390
out vec4 varyingColor;
2391
uniform mat4 projectionMatrix;
2392
void main()
2393
{
2394
    gl_Position = projectionMatrix*vec4(vertex, 1.);
2395
        varyingColor = color;
2396
}
2397
)");
2398
                if (!colorfulWideLineVertShader.log().isEmpty())
×
2399
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line vertex shader: " << colorfulWideLineVertShader.log();
×
2400

2401
                QOpenGLShader colorfulWideLineGeomShader(QOpenGLShader::Geometry);
×
2402
                colorfulWideLineGeomShader.compileSourceCode(QByteArray(geomSrc).replace("@VARYING_COLOR@","1"));
×
2403
                if (!colorfulWideLineGeomShader.log().isEmpty())
×
2404
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line geometry shader: " << colorfulWideLineGeomShader.log();
×
2405

2406
                QOpenGLShader colorfulWideLineFragShader(QOpenGLShader::Fragment);
×
2407
                colorfulWideLineFragShader.compileSourceCode(1+R"(
×
2408
#version 330
2409
in vec4 geomColor;
2410
out vec4 outputColor;
2411
void main()
2412
{
2413
    outputColor = geomColor;
2414
}
2415
)");
2416
                if (!colorfulWideLineFragShader.log().isEmpty())
×
2417
                        qWarning().noquote() << "StelPainter: Warnings while compiling colorful wide line fragment shader: " << colorfulWideLineFragShader.log();
×
2418
                colorfulWideLineShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
2419
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineVertShader);
×
2420
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineGeomShader);
×
2421
                colorfulWideLineShaderProgram->addShader(&colorfulWideLineFragShader);
×
2422
                linkProg(colorfulWideLineShaderProgram, "colorfulWideLineShaderProgram");
×
2423
                colorfulWideLineShaderVars.projectionMatrix = colorfulWideLineShaderProgram->uniformLocation("projectionMatrix");
×
2424
                colorfulWideLineShaderVars.viewportSize     = colorfulWideLineShaderProgram->uniformLocation("viewportSize");
×
2425
                colorfulWideLineShaderVars.lineWidth        = colorfulWideLineShaderProgram->uniformLocation("lineWidth");
×
2426
                colorfulWideLineShaderVars.color  = colorfulWideLineShaderProgram->attributeLocation("color");
×
2427
                colorfulWideLineShaderVars.vertex = colorfulWideLineShaderProgram->attributeLocation("vertex");
×
2428
        }
×
2429

2430
        multisamplingEnabled = StelApp::getInstance().getSettings()->value("video/multisampling", 0).toUInt() != 0;
×
2431
}
×
2432

2433

2434
void StelPainter::deinitGLShaders()
×
2435
{
2436
        delete basicShaderProgram;
×
2437
        basicShaderProgram = Q_NULLPTR;
×
2438
        delete colorShaderProgram;
×
2439
        colorShaderProgram = Q_NULLPTR;
×
2440
        delete texturesShaderProgram;
×
2441
        texturesShaderProgram = Q_NULLPTR;
×
2442
        delete texturesColorShaderProgram;
×
2443
        texturesColorShaderProgram = Q_NULLPTR;
×
2444
        delete wideLineShaderProgram;
×
2445
        wideLineShaderProgram = Q_NULLPTR;
×
2446
        delete colorfulWideLineShaderProgram;
×
2447
        colorfulWideLineShaderProgram = Q_NULLPTR;
×
2448
        texCache.clear();
×
2449
}
×
2450

2451

2452
void StelPainter::setArrays(const Vec3d* vertices, const Vec2f* texCoords, const Vec3f* colorArray, const Vec3f* normalArray)
×
2453
{
2454
        enableClientStates(vertices, texCoords, colorArray, normalArray);
×
2455
        setVertexPointer(3, GL_DOUBLE, vertices);
×
2456
        setTexCoordPointer(2, GL_FLOAT, texCoords);
×
2457
        setColorPointer(3, GL_FLOAT, colorArray);
×
2458
        setNormalPointer(GL_FLOAT, normalArray);
×
2459
}
×
2460

2461
void StelPainter::setArrays(const Vec3f* vertices, const Vec2f* texCoords, const Vec3f* colorArray, const Vec3f* normalArray)
×
2462
{
2463
        enableClientStates(vertices, texCoords, colorArray, normalArray);
×
2464
        setVertexPointer(3, GL_FLOAT, vertices);
×
2465
        setTexCoordPointer(2, GL_FLOAT, texCoords);
×
2466
        setColorPointer(3, GL_FLOAT, colorArray);
×
2467
        setNormalPointer(GL_FLOAT, normalArray);
×
2468
}
×
2469

2470
void StelPainter::enableClientStates(bool vertex, bool texture, bool color, bool normal)
×
2471
{
2472
        vertexArray.enabled = vertex;
×
2473
        texCoordArray.enabled = texture;
×
2474
        colorArray.enabled = color;
×
2475
        normalArray.enabled = normal;
×
2476
}
×
2477

2478
void StelPainter::drawFixedColorWideLinesAsQuads(const ArrayDesc& vertexArray, int count, int offset,
×
2479
                                                                                                         const Mat4f& projMat, const DrawingMode mode)
2480
{
2481
        if(count < 2) return;
×
2482

2483
        GLint viewport[4] = {};
×
2484
        glGetIntegerv(GL_VIEWPORT, viewport);
×
2485
        const auto viewportSize = Vec2f(viewport[2], viewport[3]);
×
2486

2487
        std::vector<Vec4f> newVertices;
×
2488
        if(mode == LineStrip)
×
2489
                newVertices.reserve((count-1)*6);
×
2490
        else
2491
                newVertices.reserve(count*6);
×
2492
        newVertices.resize((count-1)*6);
×
2493
        Q_ASSERT(vertexArray.type == GL_FLOAT);
×
2494
        const auto lineVertData = static_cast<const float*>(vertexArray.pointer) + vertexArray.size*offset;
×
2495
        const int step = mode==Lines ? 2 : 1;
×
2496
        for(int n = 0; n < count-1; n += step)
×
2497
        {
2498
                Vec4f in0;
×
2499
                Vec4f in1;
×
2500
                switch(vertexArray.size)
×
2501
                {
2502
                case 4:
×
2503
                        in0 = Vec4f(lineVertData+4*(n+0));
×
2504
                        in1 = Vec4f(lineVertData+4*(n+1));
×
2505
                        break;
×
2506
                case 3:
×
2507
                        in0 = Vec4f(lineVertData[3*(n+0)], lineVertData[3*(n+0)+1], lineVertData[3*(n+0)+2], 1);
×
2508
                        in1 = Vec4f(lineVertData[3*(n+1)], lineVertData[3*(n+1)+1], lineVertData[3*(n+1)+2], 1);
×
2509
                        break;
×
2510
                case 2:
×
2511
                        in0 = Vec4f(lineVertData[2*(n+0)], lineVertData[2*(n+0)+1], 0, 1);
×
2512
                        in1 = Vec4f(lineVertData[2*(n+1)], lineVertData[2*(n+1)+1], 0, 1);
×
2513
                        break;
×
2514
                case 1:
×
2515
                        in0 = Vec4f(lineVertData[n+0], 0,0,1);
×
2516
                        in1 = Vec4f(lineVertData[n+1], 0,0,1);
×
2517
                        break;
×
2518
                default:
×
2519
                        in0 = Vec4f(0.f);
×
2520
                        in1 = Vec4f(0.f);
×
2521
                        qCritical("Bad number of elements in vertex array"); // or qFatal()?
×
2522
                }
2523

2524
                const Vec4f clip0 = projMat * Vec4f(in0);
×
2525
                const Vec4f clip1 = projMat * Vec4f(in1);
×
2526

2527
                const Vec3f ndc0 = Vec3f(clip0.v) / clip0[3];
×
2528
                const Vec3f ndc1 = Vec3f(clip1.v) / clip1[3];
×
2529

2530
                const Vec2f lineDir2d = normalize((Vec2f(ndc1.v) - Vec2f(ndc0.v)) * viewportSize);
×
2531
                const Vec2f perpendicularDir2d = Vec2f(-lineDir2d[1], lineDir2d[0]);
×
2532

2533
                const Vec2f offset2d = (Vec2f(glState.lineWidth) / viewportSize) * perpendicularDir2d;
×
2534

2535
                // 2D screen coordinates of the new pairs (a,b) of vertices for each input vertex (0,1)
2536
                const Vec2f v0a_xy = Vec2f(clip0.v) + offset2d*clip0[3];
×
2537
                const Vec2f v0b_xy = Vec2f(clip0.v) - offset2d*clip0[3];
×
2538
                const Vec2f v1a_xy = Vec2f(clip1.v) + offset2d*clip1[3];
×
2539
                const Vec2f v1b_xy = Vec2f(clip1.v) - offset2d*clip1[3];
×
2540

2541
                // Final 4D coordinates of the new vertices
2542
                const auto v0a = Vec4f(v0a_xy[0], v0a_xy[1], clip0[2], clip0[3]);
×
2543
                const auto v0b = Vec4f(v0b_xy[0], v0b_xy[1], clip0[2], clip0[3]);
×
2544
                const auto v1a = Vec4f(v1a_xy[0], v1a_xy[1], clip1[2], clip1[3]);
×
2545
                const auto v1b = Vec4f(v1b_xy[0], v1b_xy[1], clip1[2], clip1[3]);
×
2546

2547
                newVertices[6*n+0] = v0a;
×
2548
                newVertices[6*n+1] = v0b;
×
2549
                newVertices[6*n+2] = v1a;
×
2550

2551
                newVertices[6*n+3] = v1a;
×
2552
                newVertices[6*n+4] = v0b;
×
2553
                newVertices[6*n+5] = v1b;
×
2554
        }
2555
        if(mode == LineLoop)
×
2556
        {
2557
                // Connect the ends
2558
                const auto lastN = newVertices.size()-1;
×
2559
                Q_ASSERT(lastN >= 2);
×
2560
                newVertices.push_back(newVertices[lastN-2]);
×
2561
                newVertices.push_back(newVertices[lastN]);
×
2562
                newVertices.push_back(newVertices[0]);
×
2563

2564
                newVertices.push_back(newVertices[0]);
×
2565
                newVertices.push_back(newVertices[lastN]);
×
2566
                newVertices.push_back(newVertices[1]);
×
2567
        }
2568
        vao->bind();
×
2569
        verticesVBO->bind();
×
2570

2571
        verticesVBO->allocate(newVertices.data(), newVertices.size() * sizeof newVertices[0]);
×
2572

2573
        const auto& pr = basicShaderProgram;
×
2574
        pr->bind();
×
2575
        pr->setAttributeBuffer(basicShaderVars.vertex, vertexArray.type, 0, 4);
×
2576
        pr->enableAttributeArray(basicShaderVars.vertex);
×
2577
        pr->setUniformValue(basicShaderVars.projectionMatrix, QMatrix4x4{});
×
2578
        pr->setUniformValue(basicShaderVars.color, currentColor.toQVector());
×
2579

2580
#ifdef GL_MULTISAMPLE
2581
        const bool multisampleWasOn = multisamplingEnabled && glIsEnabled(GL_MULTISAMPLE);
×
2582
        if(multisamplingEnabled && glState.lineSmooth)
×
2583
                glEnable(GL_MULTISAMPLE);
×
2584
#endif
2585

2586
        // TODO: convert this to a triangle strip, but mind the overlaps and gaps of non-parallel lines' corners
2587
        glDrawArrays(GL_TRIANGLES, 0, newVertices.size());
×
2588

2589
        verticesVBO->release();
×
2590
        vao->release();
×
2591

2592
        if (pr) pr->release();
×
2593

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

2600
void StelPainter::drawFromArray(DrawingMode mode, int count, int offset, bool doProj, const unsigned short* indices)
×
2601
{
2602
        if(!count) return;
×
2603

2604
        ArrayDesc projectedVertexArray = vertexArray;
×
2605
        if (doProj)
×
2606
        {
2607
                // Project the vertex array using current projection
2608
                if (indices)
×
2609
                        projectedVertexArray = projectArray(vertexArray, 0, count, indices + offset);
×
2610
                else
2611
                        projectedVertexArray = projectArray(vertexArray, offset, count, Q_NULLPTR);
×
2612
        }
2613

2614
        QOpenGLShaderProgram* pr=Q_NULLPTR;
×
2615

2616
        const Mat4f& m = getProjector()->getProjectionMatrix();
×
2617
        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]);
×
2618

2619
        const bool lineMode = mode==LineStrip || mode==LineLoop || mode==Lines;
×
2620
        const bool isCoreProfile = StelMainView::getInstance().getGLInformation().isCoreProfile;
×
2621
        const bool isGLES = StelMainView::getInstance().getGLInformation().isGLES;
×
2622
        const bool wideLineMode = lineMode && glState.lineWidth>1;
×
2623
        if(wideLineMode && (isCoreProfile || isGLES) && projectedVertexArray.type == GL_FLOAT)
×
2624
        {
2625
                const bool fixedColor = !texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled;
×
2626
                if(fixedColor && !indices)
×
2627
                {
2628
                        // Optimized version that doesn't use geometry shader, which appears to be slow on some GPUs.
2629
                        // Ideally, we'd like to get rid of the geometry shader completely,
2630
                        // but this will result in more code for small performance gain.
2631
                        drawFixedColorWideLinesAsQuads(projectedVertexArray, count, offset, m, mode);
×
2632
                        return;
×
2633
                }
2634
        }
2635
        const bool coreProfileWideLineMode = wideLineMode && isCoreProfile;
×
2636

2637
        vao->bind();
×
2638
        verticesVBO->bind();
×
2639
        GLsizeiptr numberOfVerticesToCopy = count + offset;
×
2640
        if(indices)
×
2641
        {
2642
                indicesVBO->bind();
×
2643
                indicesVBO->allocate(indices+offset, count * sizeof indices[0]);
×
2644
                numberOfVerticesToCopy = 1 + *std::max_element(indices + offset, indices + offset + count);
×
2645
        }
2646

2647
#ifdef GL_MULTISAMPLE
2648
        const bool multisampleWasOn = multisamplingEnabled && glIsEnabled(GL_MULTISAMPLE);
×
2649
#endif
2650

2651
        if (!texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled)
×
2652
        {
2653
                pr = coreProfileWideLineMode ? wideLineShaderProgram : basicShaderProgram;
×
2654
                pr->bind();
×
2655

2656
                verticesVBO->allocate(projectedVertexArray.pointer, projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy);
×
2657

2658
#ifdef GL_MULTISAMPLE
2659
                if(multisamplingEnabled && glState.lineSmooth)
×
2660
                        glEnable(GL_MULTISAMPLE);
×
2661
#endif
2662
                if(coreProfileWideLineMode)
×
2663
                {
2664
                        pr->setAttributeBuffer(wideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2665
                        pr->enableAttributeArray(wideLineShaderVars.vertex);
×
2666
                        pr->setUniformValue(wideLineShaderVars.projectionMatrix, qMat);
×
2667
                        pr->setUniformValue(wideLineShaderVars.color, currentColor.toQVector());
×
2668
                        pr->setUniformValue(wideLineShaderVars.lineWidth, glState.lineWidth);
×
2669
                        GLint viewport[4] = {};
×
2670
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2671
                        pr->setUniformValue(wideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2672
                }
2673
                else
2674
                {
2675
                        pr->setAttributeBuffer(basicShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2676
                        pr->enableAttributeArray(basicShaderVars.vertex);
×
2677
                        pr->setUniformValue(basicShaderVars.projectionMatrix, qMat);
×
2678
                        pr->setUniformValue(basicShaderVars.color, currentColor.toQVector());
×
2679
                }
2680
        }
×
2681
        else if (texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2682
        {
2683
                pr = texturesShaderProgram;
×
2684
                pr->bind();
×
2685

2686
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2687
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2688
                verticesVBO->allocate(bufferSize);
×
2689
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2690
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2691
                const auto texCoordDataOffset = vertexDataSize;
×
2692
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2693
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2694

2695
                pr->setAttributeBuffer(texturesShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2696
                pr->enableAttributeArray(texturesShaderVars.vertex);
×
2697
                pr->setUniformValue(texturesShaderVars.projectionMatrix, qMat);
×
2698
                pr->setUniformValue(texturesShaderVars.texColor, currentColor.toQVector());
×
2699
                pr->setAttributeBuffer(texturesShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2700
                pr->enableAttributeArray(texturesShaderVars.texCoord);
×
2701
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2702
        }
×
2703
        else if (texCoordArray.enabled && colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2704
        {
2705
                pr = texturesColorShaderProgram;
×
2706
                pr->bind();
×
2707

2708
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2709
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2710
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2711
                verticesVBO->allocate(bufferSize);
×
2712
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2713
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2714
                const auto texCoordDataOffset = vertexDataSize;
×
2715
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2716
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2717
                const auto colorDataOffset = vertexDataSize + texCoordDataSize;
×
2718
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2719
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2720

2721
                pr->setAttributeBuffer(texturesColorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2722
                pr->enableAttributeArray(texturesColorShaderVars.vertex);
×
2723
                pr->setUniformValue(texturesColorShaderVars.projectionMatrix, qMat);
×
2724
                pr->setAttributeBuffer(texturesColorShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2725
                pr->enableAttributeArray(texturesColorShaderVars.texCoord);
×
2726
                pr->setAttributeBuffer(texturesColorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2727
                pr->enableAttributeArray(texturesColorShaderVars.color);
×
2728
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2729
                pr->setUniformValue(texturesColorShaderVars.saturation, saturation);
×
2730
        }
×
2731
        else if (!texCoordArray.enabled && colorArray.enabled && !normalArray.enabled)
×
2732
        {
2733
                pr = coreProfileWideLineMode ? colorfulWideLineShaderProgram : colorShaderProgram;
×
2734
                pr->bind();
×
2735

2736
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2737
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2738
                verticesVBO->allocate(bufferSize);
×
2739
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2740
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2741
                const auto colorDataOffset = vertexDataSize;
×
2742
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2743
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2744

2745
                if(coreProfileWideLineMode)
×
2746
                {
2747
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2748
                        pr->enableAttributeArray(colorfulWideLineShaderVars.vertex);
×
2749
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2750
                        pr->enableAttributeArray(colorfulWideLineShaderVars.color);
×
2751
                        pr->setUniformValue(colorfulWideLineShaderVars.projectionMatrix, qMat);
×
2752
                        pr->setUniformValue(colorfulWideLineShaderVars.lineWidth, glState.lineWidth);
×
2753
                        GLint viewport[4] = {};
×
2754
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2755
                        pr->setUniformValue(colorfulWideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2756
                }
2757
                else
2758
                {
2759
                        pr->setAttributeBuffer(colorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2760
                        pr->enableAttributeArray(colorShaderVars.vertex);
×
2761
                        pr->setUniformValue(colorShaderVars.projectionMatrix, qMat);
×
2762
                        pr->setAttributeBuffer(colorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2763
                        pr->enableAttributeArray(colorShaderVars.color);
×
2764
                }
2765
#ifdef GL_MULTISAMPLE
2766
                if(multisamplingEnabled && glState.lineSmooth)
×
2767
                        glEnable(GL_MULTISAMPLE);
×
2768
#endif
2769
        }
×
2770
        else
2771
        {
2772
                qDebug() << "Unhandled parameters." << texCoordArray.enabled << colorArray.enabled << normalArray.enabled << wideLineMode;
×
2773
                Q_ASSERT(0);
×
2774
                return;
2775
        }
2776
        
2777
        if (indices)
×
2778
                glDrawElements(mode, count, GL_UNSIGNED_SHORT, 0);
×
2779
        else
2780
                glDrawArrays(mode, offset, count);
×
2781

2782
        verticesVBO->release();
×
2783
        indicesVBO->release();
×
2784
        vao->release();
×
2785

2786
        if (pr)
×
2787
                pr->release();
×
2788

2789
#ifdef GL_MULTISAMPLE
2790
        if(multisamplingEnabled && !multisampleWasOn && wideLineMode && glState.lineSmooth)
×
2791
                glDisable(GL_MULTISAMPLE);
×
2792
#endif
2793
}
2794

2795
size_t StelPainter::ArrayDesc::vertexSizeInBytes() const
×
2796
{
2797
        size_t elemSize = 1;
×
2798
        switch(type)
×
2799
        {
2800
        case GL_SHORT:
×
2801
                elemSize = sizeof(GLshort);
×
2802
                break;
×
2803
        case GL_INT:
×
2804
                elemSize = sizeof(GLint);
×
2805
                break;
×
2806
        case GL_FLOAT:
×
2807
                elemSize = sizeof(GLfloat);
×
2808
                break;
×
2809
#if GL_DOUBLE != GL_FLOAT // see StelOpenGL.hpp
2810
        case GL_DOUBLE:
×
2811
                elemSize = sizeof(GLdouble);
×
2812
                break;
×
2813
#endif
2814
        default:
×
2815
                Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected element type");
×
2816
                break;
2817
        }
2818
        return elemSize * size;
×
2819
}
2820

2821
StelPainter::ArrayDesc StelPainter::projectArray(const StelPainter::ArrayDesc& array, int offset, int count, const unsigned short* indices)
×
2822
{
2823
        // XXX: we should use a more generic way to test whether or not to do the projection.
2824
        if (dynamic_cast<StelProjector2d*>(prj.data()))
×
2825
        {
2826
                return array;
×
2827
        }
2828

2829
        Q_ASSERT(array.size == 3);
×
2830
        Q_ASSERT(array.type == GL_DOUBLE);
×
2831
        const Vec3d* vecArray = reinterpret_cast<const Vec3d *>(const_cast<void*>(array.pointer));
×
2832

2833
        // We have two different cases :
2834
        // 1) We are not using an indice array.  In that case the size of the array is known
2835
        // 2) We are using an indice array.  In that case we have to find the max value by iterating through the indices.
2836
        if (!indices)
×
2837
        {
2838
                polygonVertexArray.resize(offset + count);
×
2839
                prj->project(count, vecArray + offset, polygonVertexArray.data() + offset);
×
2840
        } else
2841
        {
2842
                // we need to find the max value of the indices !
2843
                unsigned short max = 0;
×
2844
                for (int i = offset; i < offset + count; ++i)
×
2845
                {
2846
                        max = std::max(max, indices[i]);
×
2847
                }
2848
                polygonVertexArray.resize(max+1);
×
2849
                prj->project(max + 1, vecArray + offset, polygonVertexArray.data() + offset);
×
2850
        }
2851

2852
        ArrayDesc ret;
×
2853
        ret.size = 3;
×
2854
        ret.type = GL_FLOAT;
×
2855
        ret.pointer = polygonVertexArray.constData();
×
2856
        ret.enabled = array.enabled;
×
2857
        return ret;
×
2858
}
2859

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