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

Stellarium / stellarium / 4853788370

pending completion
4853788370

push

github

Alexander V. Wolf
Special patch for John Simple

3 of 3 new or added lines in 3 files covered. (100.0%)

14729 of 125046 relevant lines covered (11.78%)

20166.5 hits per line

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

0.0
/src/core/StelPainter.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2008 Fabien Chereau
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18
 */
19

20
#include "StelPainter.hpp"
21

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

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

46
static const int TEX_CACHE_LIMIT = 7000000;
47

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

186

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

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

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

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

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

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

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

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

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

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

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

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

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

304
        glState.lineWidth = width;
×
305

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

309
        glLineWidth(width);
×
310
}
311

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

502
        const unsigned int imax = stacks;
×
503

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

897

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1318

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

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

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

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

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

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

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

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

1482
        return;
×
1483
}
1484

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

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

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

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

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

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

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

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

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

1638
        enableClientStates(false);
×
1639
}
1640

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

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

1650
        indexArray.clear();
×
1651

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

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

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

1674
        bool oldCullFace = glState.cullFace;
×
1675

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

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

1702

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

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

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

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

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

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

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

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

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

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

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

1832

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2358

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

2376

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

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

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

2403
void StelPainter::drawFixedColorWideLinesAsQuads(const ArrayDesc& vertexArray, int count, int offset,
×
2404
                                                                                                         const Mat4f& projMat, const DrawingMode mode)
2405
{
2406
        if(count < 2) return;
×
2407

2408
        GLint viewport[4] = {};
×
2409
        glGetIntegerv(GL_VIEWPORT, viewport);
×
2410
        const auto viewportSize = Vec2f(viewport[2], viewport[3]);
×
2411

2412
        std::vector<Vec4f> newVertices;
×
2413
        if(mode == LineStrip)
×
2414
                newVertices.reserve((count-1)*6);
×
2415
        else
2416
                newVertices.reserve(count*6);
×
2417
        newVertices.resize((count-1)*6);
×
2418
        assert(vertexArray.type == GL_FLOAT);
×
2419
        const auto lineVertData = static_cast<const float*>(vertexArray.pointer) + vertexArray.size*offset;
×
2420
        const int step = mode==Lines ? 2 : 1;
×
2421
        for(int n = 0; n < count-1; n += step)
×
2422
        {
2423
                Vec4f in0;
×
2424
                Vec4f in1;
×
2425
                switch(vertexArray.size)
×
2426
                {
2427
                case 4:
×
2428
                        in0 = Vec4f(lineVertData+4*(n+0));
×
2429
                        in1 = Vec4f(lineVertData+4*(n+1));
×
2430
                        break;
×
2431
                case 3:
×
2432
                        in0 = Vec4f(lineVertData[3*(n+0)], lineVertData[3*(n+0)+1], lineVertData[3*(n+0)+2], 1);
×
2433
                        in1 = Vec4f(lineVertData[3*(n+1)], lineVertData[3*(n+1)+1], lineVertData[3*(n+1)+2], 1);
×
2434
                        break;
×
2435
                case 2:
×
2436
                        in0 = Vec4f(lineVertData[2*(n+0)], lineVertData[2*(n+0)+1], 0, 1);
×
2437
                        in1 = Vec4f(lineVertData[2*(n+1)], lineVertData[2*(n+1)+1], 0, 1);
×
2438
                        break;
×
2439
                case 1:
×
2440
                        in0 = Vec4f(lineVertData[n+0], 0,0,1);
×
2441
                        in1 = Vec4f(lineVertData[n+1], 0,0,1);
×
2442
                        break;
×
2443
                default:
×
2444
                        in0 = Vec4f(0.f);
×
2445
                        in1 = Vec4f(0.f);
×
2446
                        assert(!"Bad number of elements in vertex array");
×
2447
                }
2448

2449
                const Vec4f clip0 = projMat * Vec4f(in0);
×
2450
                const Vec4f clip1 = projMat * Vec4f(in1);
×
2451

2452
                const Vec3f ndc0 = Vec3f(clip0.v) / clip0[3];
×
2453
                const Vec3f ndc1 = Vec3f(clip1.v) / clip1[3];
×
2454

2455
                const Vec2f lineDir2d = normalize((Vec2f(ndc1.v) - Vec2f(ndc0.v)) * viewportSize);
×
2456
                const Vec2f perpendicularDir2d = Vec2f(-lineDir2d[1], lineDir2d[0]);
×
2457

2458
                const Vec2f offset2d = (Vec2f(glState.lineWidth) / viewportSize) * perpendicularDir2d;
×
2459

2460
                // 2D screen coordinates of the new pairs (a,b) of vertices for each input vertex (0,1)
2461
                const Vec2f v0a_xy = Vec2f(clip0.v) + offset2d*clip0[3];
×
2462
                const Vec2f v0b_xy = Vec2f(clip0.v) - offset2d*clip0[3];
×
2463
                const Vec2f v1a_xy = Vec2f(clip1.v) + offset2d*clip1[3];
×
2464
                const Vec2f v1b_xy = Vec2f(clip1.v) - offset2d*clip1[3];
×
2465

2466
                // Final 4D coordinates of the new vertices
2467
                const auto v0a = Vec4f(v0a_xy[0], v0a_xy[1], clip0[2], clip0[3]);
×
2468
                const auto v0b = Vec4f(v0b_xy[0], v0b_xy[1], clip0[2], clip0[3]);
×
2469
                const auto v1a = Vec4f(v1a_xy[0], v1a_xy[1], clip1[2], clip1[3]);
×
2470
                const auto v1b = Vec4f(v1b_xy[0], v1b_xy[1], clip1[2], clip1[3]);
×
2471

2472
                newVertices[6*n+0] = v0a;
×
2473
                newVertices[6*n+1] = v0b;
×
2474
                newVertices[6*n+2] = v1a;
×
2475

2476
                newVertices[6*n+3] = v1a;
×
2477
                newVertices[6*n+4] = v0b;
×
2478
                newVertices[6*n+5] = v1b;
×
2479
        }
2480
        if(mode == LineLoop)
×
2481
        {
2482
                // Connect the ends
2483
                const auto lastN = newVertices.size()-1;
×
2484
                assert(lastN >= 2);
×
2485
                newVertices.push_back(newVertices[lastN-2]);
×
2486
                newVertices.push_back(newVertices[lastN]);
×
2487
                newVertices.push_back(newVertices[0]);
×
2488

2489
                newVertices.push_back(newVertices[0]);
×
2490
                newVertices.push_back(newVertices[lastN]);
×
2491
                newVertices.push_back(newVertices[1]);
×
2492
        }
2493
        vao->bind();
×
2494
        verticesVBO->bind();
×
2495

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

2498
        const auto& pr = basicShaderProgram;
×
2499
        pr->bind();
×
2500
        pr->setAttributeBuffer(basicShaderVars.vertex, vertexArray.type, 0, 4);
×
2501
        pr->enableAttributeArray(basicShaderVars.vertex);
×
2502
        pr->setUniformValue(basicShaderVars.projectionMatrix, QMatrix4x4{});
×
2503
        pr->setUniformValue(basicShaderVars.color, currentColor.toQVector());
×
2504

2505
#ifdef GL_MULTISAMPLE
2506
        const bool multisampleWasOn = multisamplingEnabled && glIsEnabled(GL_MULTISAMPLE);
×
2507
        if(multisamplingEnabled && glState.lineSmooth)
×
2508
                glEnable(GL_MULTISAMPLE);
×
2509
#endif
2510

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

2514
        verticesVBO->release();
×
2515
        vao->release();
×
2516

2517
        if (pr) pr->release();
×
2518

2519
#ifdef GL_MULTISAMPLE
2520
        if(multisamplingEnabled && !multisampleWasOn && glState.lineSmooth)
×
2521
                glDisable(GL_MULTISAMPLE);
×
2522
#endif
2523
}
×
2524

2525
void StelPainter::drawFromArray(DrawingMode mode, int count, int offset, bool doProj, const unsigned short* indices)
×
2526
{
2527
        if(!count) return;
×
2528

2529
        ArrayDesc projectedVertexArray = vertexArray;
×
2530
        if (doProj)
×
2531
        {
2532
                // Project the vertex array using current projection
2533
                if (indices)
×
2534
                        projectedVertexArray = projectArray(vertexArray, 0, count, indices + offset);
×
2535
                else
2536
                        projectedVertexArray = projectArray(vertexArray, offset, count, Q_NULLPTR);
×
2537
        }
2538

2539
        QOpenGLShaderProgram* pr=Q_NULLPTR;
×
2540

2541
        const Mat4f& m = getProjector()->getProjectionMatrix();
×
2542
        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]);
×
2543

2544
        const bool lineMode = mode==LineStrip || mode==LineLoop || mode==Lines;
×
2545
        const bool isCoreProfile = StelMainView::getInstance().getGLInformation().isCoreProfile;
×
2546
        const bool isGLES = StelMainView::getInstance().getGLInformation().isGLES;
×
2547
        const bool wideLineMode = lineMode && glState.lineWidth>1;
×
2548
        if(wideLineMode && (isCoreProfile || isGLES) && projectedVertexArray.type == GL_FLOAT)
×
2549
        {
2550
                const bool fixedColor = !texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled;
×
2551
                if(fixedColor && !indices)
×
2552
                {
2553
                        // Optimized version that doesn't use geometry shader, which appears to be slow on some GPUs.
2554
                        // Ideally, we'd like to get rid of the geometry shader completely,
2555
                        // but this will result in more code for small performance gain.
2556
                        drawFixedColorWideLinesAsQuads(projectedVertexArray, count, offset, m, mode);
×
2557
                        return;
×
2558
                }
2559
        }
2560
        const bool coreProfileWideLineMode = wideLineMode && isCoreProfile;
×
2561

2562
        vao->bind();
×
2563
        verticesVBO->bind();
×
2564
        GLsizeiptr numberOfVerticesToCopy = count + offset;
×
2565
        if(indices)
×
2566
        {
2567
                indicesVBO->bind();
×
2568
                indicesVBO->allocate(indices+offset, count * sizeof indices[0]);
×
2569
                numberOfVerticesToCopy = 1 + *std::max_element(indices + offset, indices + offset + count);
×
2570
        }
2571

2572
#ifdef GL_MULTISAMPLE
2573
        const bool multisampleWasOn = multisamplingEnabled && glIsEnabled(GL_MULTISAMPLE);
×
2574
#endif
2575

2576
        const auto core = StelApp::getInstance().getCore();
×
2577
        const auto rgbMaxValue=calcRGBMaxValue(core->getDitheringMode());
×
2578
        if (!texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled)
×
2579
        {
2580
                pr = coreProfileWideLineMode ? wideLineShaderProgram : basicShaderProgram;
×
2581
                pr->bind();
×
2582

2583
                verticesVBO->allocate(projectedVertexArray.pointer, projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy);
×
2584

2585
#ifdef GL_MULTISAMPLE
2586
                if(multisamplingEnabled && glState.lineSmooth)
×
2587
                        glEnable(GL_MULTISAMPLE);
×
2588
#endif
2589
                if(coreProfileWideLineMode)
×
2590
                {
2591
                        pr->setAttributeBuffer(wideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2592
                        pr->enableAttributeArray(wideLineShaderVars.vertex);
×
2593
                        pr->setUniformValue(wideLineShaderVars.projectionMatrix, qMat);
×
2594
                        pr->setUniformValue(wideLineShaderVars.color, currentColor.toQVector());
×
2595
                        pr->setUniformValue(wideLineShaderVars.lineWidth, glState.lineWidth);
×
2596
                        GLint viewport[4] = {};
×
2597
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2598
                        pr->setUniformValue(wideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2599
                }
2600
                else
2601
                {
2602
                        pr->setAttributeBuffer(basicShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2603
                        pr->enableAttributeArray(basicShaderVars.vertex);
×
2604
                        pr->setUniformValue(basicShaderVars.projectionMatrix, qMat);
×
2605
                        pr->setUniformValue(basicShaderVars.color, currentColor.toQVector());
×
2606
                }
2607
        }
×
2608
        else if (texCoordArray.enabled && !colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2609
        {
2610
                pr = texturesShaderProgram;
×
2611
                pr->bind();
×
2612

2613
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2614
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2615
                verticesVBO->allocate(bufferSize);
×
2616
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2617
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2618
                const auto texCoordDataOffset = vertexDataSize;
×
2619
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2620
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2621

2622
                pr->setAttributeBuffer(texturesShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2623
                pr->enableAttributeArray(texturesShaderVars.vertex);
×
2624
                pr->setUniformValue(texturesShaderVars.projectionMatrix, qMat);
×
2625
                pr->setUniformValue(texturesShaderVars.texColor, currentColor.toQVector());
×
2626
                pr->setAttributeBuffer(texturesShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2627
                pr->enableAttributeArray(texturesShaderVars.texCoord);
×
2628
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2629
                const int ditherTexSampler = 1;
×
2630
                if(!ditherPatternTex)
×
2631
                        ditherPatternTex = StelApp::getInstance().getTextureManager().getDitheringTexture(ditherTexSampler);
×
2632
                else
2633
                        ditherPatternTex->bind(ditherTexSampler);
×
2634
                pr->setUniformValue(texturesShaderVars.ditherPattern, ditherTexSampler);
×
2635
                pr->setUniformValue(texturesShaderVars.rgbMaxValue, rgbMaxValue[0], rgbMaxValue[1], rgbMaxValue[2]);
×
2636
        }
×
2637
        else if (texCoordArray.enabled && colorArray.enabled && !normalArray.enabled && !wideLineMode)
×
2638
        {
2639
                pr = texturesColorShaderProgram;
×
2640
                pr->bind();
×
2641

2642
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2643
                                                                texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2644
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2645
                verticesVBO->allocate(bufferSize);
×
2646
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2647
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2648
                const auto texCoordDataOffset = vertexDataSize;
×
2649
                const auto texCoordDataSize = texCoordArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2650
                verticesVBO->write(texCoordDataOffset, texCoordArray.pointer, texCoordDataSize);
×
2651
                const auto colorDataOffset = vertexDataSize + texCoordDataSize;
×
2652
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2653
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2654

2655
                pr->setAttributeBuffer(texturesColorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2656
                pr->enableAttributeArray(texturesColorShaderVars.vertex);
×
2657
                pr->setUniformValue(texturesColorShaderVars.projectionMatrix, qMat);
×
2658
                pr->setAttributeBuffer(texturesColorShaderVars.texCoord, texCoordArray.type, texCoordDataOffset, texCoordArray.size);
×
2659
                pr->enableAttributeArray(texturesColorShaderVars.texCoord);
×
2660
                pr->setAttributeBuffer(texturesColorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2661
                pr->enableAttributeArray(texturesColorShaderVars.color);
×
2662
                //pr->setUniformValue(texturesShaderVars.texture, 0);    // use texture unit 0
2663
                const int ditherTexSampler = 1;
×
2664
                if(!ditherPatternTex)
×
2665
                        ditherPatternTex = StelApp::getInstance().getTextureManager().getDitheringTexture(ditherTexSampler);
×
2666
                else
2667
                        ditherPatternTex->bind(ditherTexSampler);
×
2668
                pr->setUniformValue(texturesColorShaderVars.ditherPattern, ditherTexSampler);
×
2669
                pr->setUniformValue(texturesColorShaderVars.rgbMaxValue, rgbMaxValue[0], rgbMaxValue[1], rgbMaxValue[2]);
×
2670
                pr->setUniformValue(texturesColorShaderVars.saturation, saturation);
×
2671
        }
×
2672
        else if (!texCoordArray.enabled && colorArray.enabled && !normalArray.enabled)
×
2673
        {
2674
                pr = coreProfileWideLineMode ? colorfulWideLineShaderProgram : colorShaderProgram;
×
2675
                pr->bind();
×
2676

2677
                const auto bufferSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy +
×
2678
                                                                colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2679
                verticesVBO->allocate(bufferSize);
×
2680
                const auto vertexDataSize = projectedVertexArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2681
                verticesVBO->write(0, projectedVertexArray.pointer, vertexDataSize);
×
2682
                const auto colorDataOffset = vertexDataSize;
×
2683
                const auto colorDataSize = colorArray.vertexSizeInBytes()*numberOfVerticesToCopy;
×
2684
                verticesVBO->write(colorDataOffset, colorArray.pointer, colorDataSize);
×
2685

2686
                if(coreProfileWideLineMode)
×
2687
                {
2688
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2689
                        pr->enableAttributeArray(colorfulWideLineShaderVars.vertex);
×
2690
                        pr->setAttributeBuffer(colorfulWideLineShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2691
                        pr->enableAttributeArray(colorfulWideLineShaderVars.color);
×
2692
                        pr->setUniformValue(colorfulWideLineShaderVars.projectionMatrix, qMat);
×
2693
                        pr->setUniformValue(colorfulWideLineShaderVars.lineWidth, glState.lineWidth);
×
2694
                        GLint viewport[4] = {};
×
2695
                        glGetIntegerv(GL_VIEWPORT, viewport);
×
2696
                        pr->setUniformValue(colorfulWideLineShaderVars.viewportSize, QVector2D(viewport[2], viewport[3]));
×
2697
                }
2698
                else
2699
                {
2700
                        pr->setAttributeBuffer(colorShaderVars.vertex, projectedVertexArray.type, 0, projectedVertexArray.size);
×
2701
                        pr->enableAttributeArray(colorShaderVars.vertex);
×
2702
                        pr->setUniformValue(colorShaderVars.projectionMatrix, qMat);
×
2703
                        pr->setAttributeBuffer(colorShaderVars.color, colorArray.type, colorDataOffset, colorArray.size);
×
2704
                        pr->enableAttributeArray(colorShaderVars.color);
×
2705
                }
2706
#ifdef GL_MULTISAMPLE
2707
                if(multisamplingEnabled && glState.lineSmooth)
×
2708
                        glEnable(GL_MULTISAMPLE);
×
2709
#endif
2710
        }
×
2711
        else
2712
        {
2713
                qDebug() << "Unhandled parameters." << texCoordArray.enabled << colorArray.enabled << normalArray.enabled << wideLineMode;
×
2714
                Q_ASSERT(0);
×
2715
                return;
2716
        }
2717
        
2718
        if (indices)
×
2719
                glDrawElements(mode, count, GL_UNSIGNED_SHORT, 0);
×
2720
        else
2721
                glDrawArrays(mode, offset, count);
×
2722

2723
        verticesVBO->release();
×
2724
        indicesVBO->release();
×
2725
        vao->release();
×
2726

2727
        if (pr)
×
2728
                pr->release();
×
2729

2730
#ifdef GL_MULTISAMPLE
2731
        if(multisamplingEnabled && !multisampleWasOn && wideLineMode && glState.lineSmooth)
×
2732
                glDisable(GL_MULTISAMPLE);
×
2733
#endif
2734
}
2735

2736
size_t StelPainter::ArrayDesc::vertexSizeInBytes() const
×
2737
{
2738
        size_t elemSize = 1;
×
2739
        switch(type)
×
2740
        {
2741
        case GL_SHORT:
×
2742
                elemSize = sizeof(GLshort);
×
2743
                break;
×
2744
        case GL_INT:
×
2745
                elemSize = sizeof(GLint);
×
2746
                break;
×
2747
        case GL_FLOAT:
×
2748
                elemSize = sizeof(GLfloat);
×
2749
                break;
×
2750
#if GL_DOUBLE != GL_FLOAT // see StelOpenGL.hpp
2751
        case GL_DOUBLE:
×
2752
                elemSize = sizeof(GLdouble);
×
2753
                break;
×
2754
#endif
2755
        default:
×
2756
                Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected element type");
×
2757
                break;
2758
        }
2759
        return elemSize * size;
×
2760
}
2761

2762
StelPainter::ArrayDesc StelPainter::projectArray(const StelPainter::ArrayDesc& array, int offset, int count, const unsigned short* indices)
×
2763
{
2764
        // XXX: we should use a more generic way to test whether or not to do the projection.
2765
        if (dynamic_cast<StelProjector2d*>(prj.data()))
×
2766
        {
2767
                return array;
×
2768
        }
2769

2770
        Q_ASSERT(array.size == 3);
×
2771
        Q_ASSERT(array.type == GL_DOUBLE);
×
2772
        const Vec3d* vecArray = reinterpret_cast<const Vec3d *>(const_cast<void*>(array.pointer));
×
2773

2774
        // We have two different cases :
2775
        // 1) We are not using an indice array.  In that case the size of the array is known
2776
        // 2) We are using an indice array.  In that case we have to find the max value by iterating through the indices.
2777
        if (!indices)
×
2778
        {
2779
                polygonVertexArray.resize(offset + count);
×
2780
                prj->project(count, vecArray + offset, polygonVertexArray.data() + offset);
×
2781
        } else
2782
        {
2783
                // we need to find the max value of the indices !
2784
                unsigned short max = 0;
×
2785
                for (int i = offset; i < offset + count; ++i)
×
2786
                {
2787
                        max = std::max(max, indices[i]);
×
2788
                }
2789
                polygonVertexArray.resize(max+1);
×
2790
                prj->project(max + 1, vecArray + offset, polygonVertexArray.data() + offset);
×
2791
        }
2792

2793
        ArrayDesc ret;
×
2794
        ret.size = 3;
×
2795
        ret.type = GL_FLOAT;
×
2796
        ret.pointer = polygonVertexArray.constData();
×
2797
        ret.enabled = array.enabled;
×
2798
        return ret;
×
2799
}
2800

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