File indexing completed on 2024-12-01 09:41:27

0001 /*
0002     SPDX-FileCopyrightText: 2010 Henry de Valence <hdevalence@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifdef _WIN32
0008 #include <windows.h>
0009 #endif
0010 #include "skyglpainter.h"
0011 
0012 #include <cstddef>
0013 #include <Eigen/Geometry>
0014 
0015 #include <GL/gl.h>
0016 #include <QGLWidget>
0017 
0018 #include "skymap.h"
0019 #include "kstarsdata.h"
0020 #include "Options.h"
0021 
0022 #include "texturemanager.h"
0023 
0024 #include "skycomponents/linelist.h"
0025 #include "skycomponents/skiphashlist.h"
0026 #include "skycomponents/linelistlabel.h"
0027 #include "skycomponents/skymapcomposite.h"
0028 #include "skycomponents/flagcomponent.h"
0029 #include "skycomponents/satellitescomponent.h"
0030 #include "skycomponents/supernovaecomponent.h"
0031 #include "skycomponents/constellationartcomponent.h"
0032 #include "skyobjects/kscomet.h"
0033 #include "skyobjects/ksasteroid.h"
0034 #include "skyobjects/trailobject.h"
0035 #include "skyobjects/satellite.h"
0036 #include "skyobjects/supernova.h"
0037 #include "skyobjects/constellationsart.h"
0038 
0039 Eigen::Vector2f SkyGLPainter::m_vertex[NUMTYPES][6 * BUFSIZE];
0040 Eigen::Vector2f SkyGLPainter::m_texcoord[NUMTYPES][6 * BUFSIZE];
0041 Eigen::Vector3f SkyGLPainter::m_color[NUMTYPES][6 * BUFSIZE];
0042 int SkyGLPainter::m_idx[NUMTYPES];
0043 bool SkyGLPainter::m_init = false;
0044 
0045 SkyGLPainter::SkyGLPainter(QGLWidget *widget) : SkyPainter()
0046 {
0047     m_widget = widget;
0048     if (!m_init)
0049     {
0050         qDebug() << "Initializing texcoord arrays...\n";
0051         for (int i = 0; i < NUMTYPES; ++i)
0052         {
0053             m_idx[i] = 0;
0054             for (int j = 0; j < BUFSIZE; ++j)
0055             {
0056                 m_texcoord[i][6 * j + 0] = Eigen::Vector2f(0, 0);
0057                 m_texcoord[i][6 * j + 1] = Eigen::Vector2f(1, 0);
0058                 m_texcoord[i][6 * j + 2] = Eigen::Vector2f(0, 1);
0059                 m_texcoord[i][6 * j + 3] = Eigen::Vector2f(0, 1);
0060                 m_texcoord[i][6 * j + 4] = Eigen::Vector2f(1, 0);
0061                 m_texcoord[i][6 * j + 5] = Eigen::Vector2f(1, 1);
0062             }
0063         }
0064         //Generate textures that were loaded before the SkyMap was
0065         m_init = true;
0066     }
0067 }
0068 
0069 void SkyGLPainter::drawBuffer(int type)
0070 {
0071     // Prevent crash if type > UNKNOWN
0072     if (type > SkyObject::TYPE_UNKNOWN)
0073         type = SkyObject::TYPE_UNKNOWN;
0074 
0075     //printf("Drawing buffer for type %d, has %d objects\n", type, m_idx[type]);
0076     if (m_idx[type] == 0)
0077         return;
0078 
0079     glEnable(GL_TEXTURE_2D);
0080     switch (type)
0081     {
0082         case 3:
0083         case 13:
0084             TextureManager::bindTexture("open-cluster", m_widget);
0085             break;
0086         case 4:
0087             TextureManager::bindTexture("globular-cluster", m_widget);
0088             break;
0089         case 6:
0090             TextureManager::bindTexture("planetary-nebula", m_widget);
0091             break;
0092         case 5:
0093         case 7:
0094         case 15:
0095             TextureManager::bindTexture("gaseous-nebula", m_widget);
0096             break;
0097         case 8:
0098         case 16:
0099             TextureManager::bindTexture("galaxy", m_widget);
0100             break;
0101         case 14:
0102             TextureManager::bindTexture("galaxy-cluster", m_widget);
0103             break;
0104         case 0:
0105         case 1:
0106         default:
0107             TextureManager::bindTexture("star", m_widget);
0108             break;
0109     }
0110 
0111     glEnable(GL_BLEND);
0112     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0113     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
0114     glEnableClientState(GL_VERTEX_ARRAY);
0115     glEnableClientState(GL_COLOR_ARRAY);
0116     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
0117 
0118     glVertexPointer(2, GL_FLOAT, 0, &m_vertex[type]);
0119     glTexCoordPointer(2, GL_FLOAT, 0, &m_texcoord[type]);
0120     glColorPointer(3, GL_FLOAT, 0, &m_color[type]);
0121 
0122     glDrawArrays(GL_TRIANGLES, 0, 6 * m_idx[type]);
0123     m_idx[type] = 0;
0124 
0125     glDisableClientState(GL_VERTEX_ARRAY);
0126     glDisableClientState(GL_COLOR_ARRAY);
0127     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
0128 }
0129 
0130 bool SkyGLPainter::addItem(SkyPoint *p, int type, float width, char sp)
0131 {
0132     bool visible = false;
0133     Eigen::Vector2f vec = m_proj->toScreenVec(p, true, &visible);
0134     if (!visible)
0135         return false;
0136 
0137     // Prevent crash if type > UNKNOWN
0138     if (type > SkyObject::TYPE_UNKNOWN)
0139         type = SkyObject::TYPE_UNKNOWN;
0140 
0141     //If the buffer is full, flush it
0142     if (m_idx[type] == BUFSIZE)
0143     {
0144         drawBuffer(type);
0145     }
0146 
0147     int i   = 6 * m_idx[type];
0148     float w = width / 2.;
0149 
0150     m_vertex[type][i + 0] = vec + Eigen::Vector2f(-w, -w);
0151     m_vertex[type][i + 1] = vec + Eigen::Vector2f(w, -w);
0152     m_vertex[type][i + 2] = vec + Eigen::Vector2f(-w, w);
0153     m_vertex[type][i + 3] = vec + Eigen::Vector2f(-w, w);
0154     m_vertex[type][i + 4] = vec + Eigen::Vector2f(w, -w);
0155     m_vertex[type][i + 5] = vec + Eigen::Vector2f(w, w);
0156 
0157     Eigen::Vector3f c(1., 1., 1.);
0158     if (sp != 'x' && Options::starColorMode() != 0)
0159     {
0160         // We have a star and aren't drawing real star colors
0161         switch (Options::starColorMode())
0162         {
0163             case 1: // solid red
0164                 c = Eigen::Vector3f(255. / 255., 0., 0.);
0165                 break;
0166             case 2: // solid black
0167                 c = Eigen::Vector3f(0., 0., 0.);
0168                 break;
0169             case 3: // Solid white
0170                 c = Eigen::Vector3f(1., 1., 1.);
0171                 break;
0172         }
0173     }
0174     else
0175     {
0176         QColor starColor;
0177 
0178         // Set RGB values into QColor
0179         switch (sp)
0180         {
0181             case 'o':
0182             case 'O':
0183                 starColor.setRgb(153, 153, 255);
0184                 break;
0185             case 'b':
0186             case 'B':
0187                 starColor.setRgb(151, 233, 255);
0188                 break;
0189             case 'a':
0190             case 'A':
0191                 starColor.setRgb(153, 255, 255);
0192                 break;
0193             case 'f':
0194             case 'F':
0195                 starColor.setRgb(219, 255, 135);
0196                 break;
0197             case 'g':
0198             case 'G':
0199                 starColor.setRgb(255, 255, 153);
0200                 break;
0201             case 'k':
0202             case 'K':
0203                 starColor.setRgb(255, 193, 153);
0204                 break;
0205             case 'm':
0206             case 'M':
0207                 starColor.setRgb(255, 153, 153);
0208                 break;
0209             case 'x':
0210                 starColor.setRgb(m_pen[0] * 255, m_pen[1] * 255, m_pen[2] * 255);
0211                 break;
0212             default:
0213                 starColor.setRgb(153, 255, 255);
0214                 break; // If we don't know what spectral type, we use the same as 'A' (See SkyQPainter)
0215         }
0216 
0217         // Convert to HSV space using QColor's methods and adjust saturation.
0218         int h, s, v;
0219         starColor.getHsv(&h, &s, &v);
0220         s = (Options::starColorIntensity() / 10.) *
0221             200.; // Rewrite the saturation based on the star color intensity setting, 200 is the hard-wired max saturation, just to approximately match up with QPainter mode.
0222         starColor.setHsv(h, s, v);
0223 
0224         // Get RGB ratios and put them in 'c'
0225         c = Eigen::Vector3f(starColor.redF(), starColor.greenF(), starColor.blueF());
0226     }
0227     for (int j = 0; j < 6; ++j)
0228     {
0229         m_color[type][i + j] = c;
0230     }
0231 
0232     ++m_idx[type];
0233     return true;
0234 }
0235 
0236 void SkyGLPainter::drawTexturedRectangle(const QImage &img, const Eigen::Vector2f &pos, const float angle, const float sizeX,
0237                                          const float sizeY)
0238 {
0239     // Set up texture
0240     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0241     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
0242     glEnable(GL_TEXTURE_2D);
0243     TextureManager::bindFromImage(img, m_widget);
0244 
0245     // Render rectangle
0246     glPushMatrix();
0247     glTranslatef(pos.x(), pos.y(), 0);
0248     glRotatef(angle, 0, 0, 1);
0249     glScalef(sizeX, sizeY, 1);
0250 
0251     glBegin(GL_QUADS);
0252     // Note! Y coordinate of texture is mirrored w.r.t. to
0253     // vertex coordinates to account for difference between
0254     // OpenGL and QPainter coordinate system.
0255     // Otherwise image would appear mirrored
0256     glTexCoord2f(0, 1);
0257     glVertex2f(-0.5, -0.5);
0258 
0259     glTexCoord2f(1, 1);
0260     glVertex2f(0.5, -0.5);
0261 
0262     glTexCoord2f(1, 0);
0263     glVertex2f(0.5, 0.5);
0264 
0265     glTexCoord2f(0, 0);
0266     glVertex2f(-0.5, 0.5);
0267     glEnd();
0268 
0269     glPopMatrix();
0270 }
0271 
0272 bool SkyGLPainter::drawPlanet(KSPlanetBase *planet)
0273 {
0274     //If it's surely not visible, just stop now
0275     if (!m_proj->checkVisibility(planet))
0276         return false;
0277 
0278     float zoom         = Options::zoomFactor();
0279     float fakeStarSize = (10.0 + log10(zoom) - log10(MINZOOM)) * (10 - planet->mag()) / 10;
0280     fakeStarSize       = qMin(fakeStarSize, 20.f);
0281 
0282     float size = planet->angSize() * dms::PI * zoom / 10800.0;
0283     if (size < fakeStarSize || planet->image().isNull())
0284     {
0285         // Draw them as bright stars of appropriate color instead of images
0286         char spType;
0287         //FIXME: do these need i18n?
0288         if (planet->name() == xi18n("Sun"))
0289         {
0290             spType = 'G';
0291         }
0292         else if (planet->name() == xi18n("Mars"))
0293         {
0294             spType = 'K';
0295         }
0296         else if (planet->name() == xi18n("Jupiter") || planet->name() == xi18n("Mercury") ||
0297                  planet->name() == xi18n("Saturn"))
0298         {
0299             spType = 'F';
0300         }
0301         else
0302         {
0303             spType = 'B';
0304         }
0305         return addItem(planet, planet->type(), qMin(fakeStarSize, (float)20.), spType);
0306     }
0307     else
0308     {
0309         // Draw them as textures
0310         bool visible = false;
0311         Eigen::Vector2f pos = m_proj->toScreenVec(planet, true, &visible);
0312         if (!visible)
0313             return false;
0314 
0315         //Because Saturn has rings, we inflate its image size by a factor 2.5
0316         if (planet->name() == "Saturn")
0317             size *= 2.5;
0318 
0319         drawTexturedRectangle(planet->image(), pos, m_proj->findPA(planet, pos.x(), pos.y()), size, size);
0320         return true;
0321     }
0322 }
0323 
0324 bool SkyGLPainter::drawPointSource(const SkyPoint *loc, float mag, char sp)
0325 {
0326     //If it's surely not visible, just stop now
0327     if (!m_proj->checkVisibility(loc))
0328         return false;
0329     return addItem(loc, SkyObject::STAR, starWidth(mag), sp);
0330 }
0331 
0332 void SkyGLPainter::drawSkyPolygon(LineList *list)
0333 {
0334     SkyList *points = list->points();
0335     bool isVisible, isVisibleLast;
0336     SkyPoint *pLast = points->last();
0337     Eigen::Vector2f oLast  = m_proj->toScreenVec(pLast, true, &isVisibleLast);
0338     // & with the result of checkVisibility to clip away things below horizon
0339     isVisibleLast &= m_proj->checkVisibility(pLast);
0340 
0341     //Guess that we will require around the same number of items as in points.
0342     QVector<Eigen::Vector2f> polygon;
0343     polygon.reserve(points->size());
0344     for (int i = 0; i < points->size(); ++i)
0345     {
0346         SkyPoint *pThis = points->at(i);
0347         Eigen::Vector2f oThis  = m_proj->toScreenVec(pThis, true, &isVisible);
0348         // & with the result of checkVisibility to clip away things below horizon
0349         isVisible &= m_proj->checkVisibility(pThis);
0350 
0351         if (isVisible && isVisibleLast)
0352         {
0353             polygon << oThis;
0354         }
0355         else if (isVisibleLast)
0356         {
0357             Eigen::Vector2f oMid = m_proj->clipLineVec(pLast, pThis);
0358             polygon << oMid;
0359         }
0360         else if (isVisible)
0361         {
0362             Eigen::Vector2f oMid = m_proj->clipLineVec(pThis, pLast);
0363             polygon << oMid;
0364             polygon << oThis;
0365         }
0366 
0367         pLast         = pThis;
0368         oLast         = oThis;
0369         isVisibleLast = isVisible;
0370     }
0371 
0372 // false -> makes kstars slower but is always accurate
0373 // true -> faster but potentially results in incorrect rendering
0374 #define KSTARS_ASSUME_CONVEXITY false
0375     if (polygon.size())
0376     {
0377         drawPolygon(polygon, KSTARS_ASSUME_CONVEXITY);
0378     }
0379 }
0380 
0381 void SkyGLPainter::drawPolygon(const QVector<Eigen::Vector2f> &polygon, bool convex, bool flush_buffers)
0382 {
0383     //Flush all buffers
0384     if (flush_buffers)
0385     {
0386         for (int i = 0; i < NUMTYPES; ++i)
0387         {
0388             drawBuffer(i);
0389         }
0390     }
0391     glDisable(GL_TEXTURE_2D);
0392     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0393     if (!convex)
0394     {
0395         //Set up the stencil buffer and disable the color buffer
0396         glClear(GL_STENCIL_BUFFER_BIT);
0397         glColorMask(0, 0, 0, 0);
0398         glEnable(GL_STENCIL_TEST);
0399         glStencilFunc(GL_ALWAYS, 0, 0);
0400         glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
0401         //Now draw a triangle fan. Because of the GL_INVERT,
0402         //this will fill the stencil buffer with odd-even fill.
0403         glEnableClientState(GL_VERTEX_ARRAY);
0404         glVertexPointer(2, GL_FLOAT, 0, polygon.data());
0405         glDrawArrays(GL_TRIANGLE_FAN, 0, polygon.size());
0406         glDisableClientState(GL_VERTEX_ARRAY);
0407 
0408         //Now draw the stencil:
0409         glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
0410         glColorMask(1, 1, 1, 1);
0411         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
0412         glBegin(GL_QUADS);
0413         glVertex2f(0, 0);
0414         glVertex2f(0, m_widget->height());
0415         glVertex2f(m_widget->width(), m_widget->height());
0416         glVertex2f(m_widget->width(), 0);
0417         glEnd();
0418         glDisable(GL_STENCIL_TEST);
0419     }
0420     else
0421     {
0422         glEnableClientState(GL_VERTEX_ARRAY);
0423         glVertexPointer(2, GL_FLOAT, 0, polygon.data());
0424         glDrawArrays(GL_POLYGON, 0, polygon.size());
0425         glDisableClientState(GL_VERTEX_ARRAY);
0426     }
0427 }
0428 
0429 void SkyGLPainter::drawHorizon(bool filled, SkyPoint *labelPoint, bool *drawLabel)
0430 {
0431     QVector<Eigen::Vector2f> ground = m_proj->groundPoly(labelPoint, drawLabel);
0432 
0433     if (ground.size())
0434     {
0435         if (filled)
0436         {
0437             glDisableClientState(GL_COLOR_ARRAY);
0438             drawPolygon(ground, false, false);
0439         }
0440         else
0441         {
0442             glDisable(GL_TEXTURE_2D);
0443             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0444             glEnableClientState(GL_VERTEX_ARRAY);
0445             glVertexPointer(2, GL_FLOAT, 0, ground.data());
0446             glDrawArrays(GL_LINE_LOOP, 0, ground.size());
0447             glDisableClientState(GL_VERTEX_ARRAY);
0448         }
0449     }
0450 }
0451 
0452 //This implementation is *correct* but slow.
0453 void SkyGLPainter::drawSkyPolyline(LineList *list, SkipHashList *skipList, LineListLabel *label)
0454 {
0455     glDisable(GL_TEXTURE_2D);
0456     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0457     glBegin(GL_LINE_STRIP);
0458     SkyList *points = list->points();
0459     bool isVisible, isVisibleLast;
0460     Eigen::Vector2f oLast = m_proj->toScreenVec(points->first(), true, &isVisibleLast);
0461     // & with the result of checkVisibility to clip away things below horizon
0462     isVisibleLast &= m_proj->checkVisibility(points->first());
0463     if (isVisibleLast)
0464     {
0465         glVertex2fv(oLast.data());
0466     }
0467 
0468     for (int i = 1; i < points->size(); ++i)
0469     {
0470         Eigen::Vector2f oThis = m_proj->toScreenVec(points->at(i), true, &isVisible);
0471         // & with the result of checkVisibility to clip away things below horizon
0472         isVisible &= m_proj->checkVisibility(points->at(i));
0473 
0474         bool doSkip = (skipList ? skipList->skip(i) : false);
0475         //This tells us whether we need to end the current line or whether we
0476         //are to keep drawing into it. If we skip, then we are going to have to end.
0477         bool shouldEnd = doSkip;
0478 
0479         if (!doSkip)
0480         {
0481             if (isVisible && isVisibleLast)
0482             {
0483                 glVertex2fv(oThis.data());
0484                 if (label)
0485                 {
0486                     label->updateLabelCandidates(oThis.x(), oThis.y(), list, i);
0487                 }
0488             }
0489             else if (isVisibleLast)
0490             {
0491                 Eigen::Vector2f oMid = m_proj->clipLineVec(points->at(i - 1), points->at(i));
0492                 glVertex2fv(oMid.data());
0493                 //If the last point was visible but this one isn't we are at
0494                 //the end of a strip, so we need to end
0495                 shouldEnd = true;
0496             }
0497             else if (isVisible)
0498             {
0499                 Eigen::Vector2f oMid = m_proj->clipLineVec(points->at(i), points->at(i - 1));
0500                 glVertex2fv(oMid.data());
0501                 glVertex2fv(oThis.data());
0502             }
0503         }
0504 
0505         if (shouldEnd)
0506         {
0507             glEnd();
0508             glBegin(GL_LINE_STRIP);
0509             if (isVisible)
0510             {
0511                 glVertex2fv(oThis.data());
0512             }
0513         }
0514 
0515         isVisibleLast = isVisible;
0516     }
0517     glEnd();
0518 }
0519 
0520 //FIXME: implement these two
0521 
0522 void SkyGLPainter::drawObservingList(const QList<SkyObject *> &obs)
0523 {
0524     // TODO: Generalize to drawTargetList or something like that. Make
0525     // texture changeable etc.
0526     // TODO: Draw labels when required
0527 
0528     foreach (SkyObject *obj, obs)
0529     {
0530         if (!m_proj->checkVisibility(obj))
0531             continue;
0532         bool visible;
0533         Eigen::Vector2f vec = m_proj->toScreenVec(obj, true, &visible);
0534         if (!visible || !m_proj->onScreen(vec))
0535             continue;
0536         const float size = 30.;
0537         QImage obsmarker = TextureManager::getImage("obslistsymbol");
0538         drawTexturedRectangle(obsmarker, vec, 0, size, size);
0539     }
0540 }
0541 
0542 void SkyGLPainter::drawFlags()
0543 {
0544     KStarsData *data = KStarsData::Instance();
0545     SkyPoint *point;
0546     QImage image;
0547     const QString label;
0548     bool visible = false;
0549     Eigen::Vector2f vec;
0550     int i;
0551 
0552     for (i = 0; i < data->skyComposite()->flags()->size(); i++)
0553     {
0554         point = data->skyComposite()->flags()->pointList().at(i);
0555         image = data->skyComposite()->flags()->image(i);
0556 
0557         // Set Horizontal coordinates
0558         point->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0559 
0560         // Get flag position on screen
0561         vec = m_proj->toScreenVec(point, true, &visible);
0562 
0563         // Return if flag is not visible
0564         if (!visible || !m_proj->onScreen(vec))
0565             continue;
0566 
0567         const QImage &img =
0568             data->skyComposite()->flags()->imageName(i) == "Default" ? TextureManager::getImage("defaultflag") : image;
0569 
0570         drawTexturedRectangle(img, vec, 0, img.width(), img.height());
0571         drawText(vec.x(), vec.y(), data->skyComposite()->flags()->label(i), QFont("Courier New", 10, QFont::Bold),
0572                  data->skyComposite()->flags()->labelColor(i));
0573     }
0574 }
0575 
0576 void SkyGLPainter::drawText(int x, int y, const QString text, QFont font, QColor color)
0577 {
0578     // Return if text is empty
0579     if (text.isEmpty())
0580         return;
0581 
0582     int longest, tex_size = 2;
0583 
0584     // Get size of text
0585     QFontMetrics fm(font);
0586     const QRect bounding_rect = fm.boundingRect(text);
0587 
0588     // Compute texture size
0589     if (bounding_rect.width() > bounding_rect.height())
0590         longest = bounding_rect.width();
0591     else
0592         longest = bounding_rect.height();
0593 
0594     while (tex_size < longest)
0595     {
0596         tex_size *= 2;
0597     }
0598 
0599     // Create image of text
0600     QImage text_image(tex_size, tex_size, QImage::Format_ARGB32);
0601     text_image.fill(Qt::transparent);
0602     QPainter p(&text_image);
0603     p.setFont(font);
0604     p.setPen(color);
0605     p.drawText(0, tex_size / 2, text);
0606     p.end();
0607 
0608     // Create texture
0609     float w  = text_image.width();
0610     float h  = text_image.height();
0611     float vx = x + 0.5 * w + 10;
0612     float vy = y - 10;
0613     drawTexturedRectangle(text_image, Eigen::Vector2f(vx, vy), 0, w, h);
0614 }
0615 
0616 bool SkyGLPainter::drawConstellationArtImage(ConstellationsArt *obj)
0617 {
0618 }
0619 
0620 void SkyGLPainter::drawSkyLine(SkyPoint *a, SkyPoint *b)
0621 {
0622     bool aVisible, bVisible;
0623     Eigen::Vector2f aScreen = m_proj->toScreenVec(a, true, &aVisible);
0624     Eigen::Vector2f bScreen = m_proj->toScreenVec(b, true, &bVisible);
0625 
0626     glDisable(GL_TEXTURE_2D);
0627     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0628     glBegin(GL_LINE_STRIP);
0629 
0630     //THREE CASES:
0631     if (aVisible && bVisible)
0632     {
0633         //Both a,b visible, so paint the line normally:
0634         glVertex2fv(aScreen.data());
0635         glVertex2fv(bScreen.data());
0636     }
0637     else if (aVisible)
0638     {
0639         //a is visible but b isn't:
0640         glVertex2fv(aScreen.data());
0641         glVertex2fv(m_proj->clipLineVec(a, b).data());
0642     }
0643     else if (bVisible)
0644     {
0645         //b is visible but a isn't:
0646         glVertex2fv(bScreen.data());
0647         glVertex2fv(m_proj->clipLineVec(b, a).data());
0648     } //FIXME: what if both are offscreen but the line isn't?
0649 
0650     glEnd();
0651 }
0652 
0653 void SkyGLPainter::drawSkyBackground()
0654 {
0655     glDisable(GL_TEXTURE_2D);
0656     QColor bg = KStarsData::Instance()->colorScheme()->colorNamed("SkyColor");
0657     glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF());
0658     glClear(GL_COLOR_BUFFER_BIT);
0659 }
0660 
0661 void SkyGLPainter::end()
0662 {
0663     for (int i = 0; i < NUMTYPES; ++i)
0664     {
0665         drawBuffer(i);
0666     }
0667 }
0668 
0669 void SkyGLPainter::begin()
0670 {
0671     m_proj = m_sm->projector();
0672 
0673     //Load ortho projection
0674     glViewport(0, 0, m_widget->width(), m_widget->height());
0675     glMatrixMode(GL_PROJECTION);
0676     glLoadIdentity();
0677     glOrtho(0, m_widget->width(), m_widget->height(), 0, -1, 1);
0678 
0679     //reset modelview matrix
0680     glMatrixMode(GL_MODELVIEW);
0681     glLoadIdentity();
0682 
0683     //Set various parameters
0684     glDisable(GL_LIGHTING);
0685     glDisable(GL_COLOR_MATERIAL);
0686     glDisable(GL_CULL_FACE);
0687     glDisable(GL_DEPTH_TEST);
0688     glDepthMask(GL_FALSE);
0689     glPointSize(1.);
0690     glEnable(GL_POINT_SMOOTH);
0691     glEnable(GL_LINE_SMOOTH);
0692     glEnable(GL_POLYGON_SMOOTH);
0693     glLineStipple(1, 0xCCCC);
0694     glEnable(GL_BLEND);
0695 
0696     glClearStencil(0);
0697 }
0698 
0699 void SkyGLPainter::setBrush(const QBrush &brush)
0700 {
0701     Q_UNUSED(brush);
0702     /*
0703     QColor c = brush.color();
0704     m_pen = Eigen::Vector4f( c.redF(), c.greenF(), c.blueF(), c.alphaF() );
0705     glColor4fv( m_pen.data() );
0706     */
0707 }
0708 
0709 void SkyGLPainter::setPen(const QPen &pen)
0710 {
0711     QColor c = pen.color();
0712     m_pen    = Eigen::Vector4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
0713     glColor4fv(m_pen.data());
0714     glLineWidth(pen.widthF());
0715     if (pen.style() != Qt::SolidLine)
0716     {
0717         glEnable(GL_LINE_STIPPLE);
0718     }
0719     else
0720     {
0721         glDisable(GL_LINE_STIPPLE);
0722     }
0723 }
0724 
0725 void SkyGLPainter::drawSatellite(Satellite *sat)
0726 {
0727     KStarsData *data = KStarsData::Instance();
0728     bool visible     = false;
0729     Eigen::Vector2f pos, vertex;
0730 
0731     sat->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0732 
0733     pos = m_proj->toScreenVec(sat, true, &visible);
0734 
0735     if (!visible || !m_proj->onScreen(pos))
0736         return;
0737 
0738     if (Options::drawSatellitesLikeStars())
0739     {
0740         drawPointSource(sat, 3.5, 'B');
0741     }
0742     else
0743     {
0744         if (sat->isVisible())
0745             setPen(data->colorScheme()->colorNamed("VisibleSatColor"));
0746         else
0747             setPen(data->colorScheme()->colorNamed("SatColor"));
0748 
0749         glDisable(GL_TEXTURE_2D);
0750         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0751         glBegin(GL_QUADS);
0752 
0753         vertex = pos + Eigen::Vector2f(-1.0, -1.0);
0754         glVertex2fv(vertex.data());
0755         vertex = pos + Eigen::Vector2f(1.0, -1.0);
0756         glVertex2fv(vertex.data());
0757         vertex = pos + Eigen::Vector2f(1.0, 1.0);
0758         glVertex2fv(vertex.data());
0759         vertex = pos + Eigen::Vector2f(-1.0, 1.0);
0760         glVertex2fv(vertex.data());
0761 
0762         glEnd();
0763     }
0764 
0765     if (Options::showSatellitesLabels())
0766         data->skyComposite()->satellites()->drawLabel(sat, QPointF(pos.x(), pos.y()));
0767 }
0768 
0769 bool SkyGLPainter::drawSupernova(Supernova *sup)
0770 {
0771     KStarsData *data = KStarsData::Instance();
0772     bool visible     = false;
0773     Eigen::Vector2f pos, vertex;
0774 
0775     sup->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0776 
0777     pos = m_proj->toScreenVec(sup, true, &visible);
0778 
0779     if (!visible || !m_proj->onScreen(pos))
0780         return false;
0781     setPen(data->colorScheme()->colorNamed("SupernovaColor"));
0782 
0783     glDisable(GL_TEXTURE_2D);
0784     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0785 
0786     glBegin(GL_LINES);
0787     vertex = pos + Eigen::Vector2f(2.0, 0.0);
0788     glVertex2fv(vertex.data());
0789     vertex = pos + Eigen::Vector2f(-2.0, 0.0);
0790     glVertex2fv(vertex.data());
0791     glEnd();
0792 
0793     glBegin(GL_LINES);
0794     vertex = pos + Eigen::Vector2f(0.0, 2.0);
0795     glVertex2fv(vertex.data());
0796     vertex = pos + Eigen::Vector2f(0.0, -2.0);
0797     glVertex2fv(vertex.data());
0798     glEnd();
0799 
0800     return true;
0801 }