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 }