StelPainter.cpp   StelPainter.cpp 
skipping to change at line 20 skipping to change at line 20
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, U SA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, U SA.
*/ */
#include "GLee.h" #include "StelPainter.hpp"
#include "fixx11h.h"
#if defined(__APPLE__) && defined(__MACH__) #include <QtOpenGL>
#include <OpenGL/glu.h> /* Header File For The GLU Library */
#else
#include <GL/glu.h> /* Header File For The GLU Library */
#endif
#include "StelProjector.hpp" #include "StelProjector.hpp"
#include "StelPainter.hpp" #include "StelProjectorClasses.hpp"
#include "StelApp.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "StelFont.hpp"
#include <QDebug> #include <QDebug>
#include <QString> #include <QString>
#include <QSettings> #include <QSettings>
#include <QLinkedList> #include <QLinkedList>
#include <QPainter> #include <QPainter>
#include <QMutex> #include <QMutex>
#include <QVarLengthArray>
#include <QPaintEngine>
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
#ifndef NDEBUG
QMutex* StelPainter::globalMutex = new QMutex(); QMutex* StelPainter::globalMutex = new QMutex();
bool StelPainter::flagGlPointSprite = false; #endif
QPainter* StelPainter::qPainter = NULL;
#ifdef STELPAINTER_GL2
QGLShaderProgram* StelPainter::colorShaderProgram=NULL;
QGLShaderProgram* StelPainter::texturesShaderProgram=NULL;
QGLShaderProgram* StelPainter::basicShaderProgram=NULL;
QGLShaderProgram* StelPainter::texturesColorShaderProgram=NULL;
StelPainter::BasicShaderVars StelPainter::basicShaderVars;
StelPainter::TexturesShaderVars StelPainter::texturesShaderVars;
StelPainter::TexturesColorShaderVars StelPainter::texturesColorShaderVars;
#endif
void StelPainter::setQPainter(QPainter* p)
{
qPainter=p;
}
StelPainter::StelPainter(const StelProjectorP& proj) : prj(proj) StelPainter::StelPainter(const StelProjectorP& proj) : prj(proj)
{ {
Q_ASSERT(proj); Q_ASSERT(proj);
Q_ASSERT(globalMutex);
// GLenum er = glGetError(); #ifndef NDEBUG
// if (er!=GL_NO_ERROR) Q_ASSERT(globalMutex);
// { GLenum er = glGetError();
// if (er==GL_INVALID_OPERATION) if (er!=GL_NO_ERROR)
// qFatal("Invalid openGL operation. It is likely that {
you used openGL calls without having a valid instance of StelPainter"); if (er==GL_INVALID_OPERATION)
// } qFatal("Invalid openGL operation. It is likely that
you used openGL calls without having a valid instance of StelPainter");
}
// Lock the global mutex ensuring that no other instances of StelPai nter are currently being used // Lock the global mutex ensuring that no other instances of StelPai nter are currently being used
if (globalMutex->tryLock()==false) if (globalMutex->tryLock()==false)
{ {
qFatal("There can be only 1 instance of StelPainter at a giv en time"); qFatal("There can be only 1 instance of StelPainter at a giv en time");
} }
#endif
switchToNativeOpenGLPainting(); Q_ASSERT(qPainter);
qPainter->beginNativePainting();
// Init GL viewport to current projector values
glViewport(prj->viewportXywh[0], prj->viewportXywh[1], prj->viewport
Xywh[2], prj->viewportXywh[3]);
initGlMatrixOrtho2d();
glShadeModel(GL_FLAT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_MULTISAMPLE);
glDisable(GL_DITHER);
glDisable(GL_ALPHA_TEST);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_TEXTURE_2D);
glFrontFace(prj->needGlFrontFaceCW()?GL_CW:GL_CCW);
}
StelPainter::~StelPainter()
{
revertToQtPainting();
// We are done with this StelPainter
globalMutex->unlock();
}
//! Switch to native OpenGL painting, i.e not using QPainter #ifndef STELPAINTER_GL2
//! After this call revertToQtPainting MUST be called
void StelPainter::switchToNativeOpenGLPainting()
{
// Save openGL projection state // Save openGL projection state
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_TEXTURE); glMatrixMode(GL_TEXTURE);
glPushMatrix(); glPushMatrix();
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glPushMatrix(); glPushMatrix();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glShadeModel(GL_FLAT); glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
//glDisable(GL_MULTISAMPLE); doesn't work on win32 glDisable(GL_MULTISAMPLE);
glDisable(GL_DITHER); glDisable(GL_DITHER);
glDisable(GL_ALPHA_TEST); glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D); glEnable(GL_LINE_SMOOTH);
#endif
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// Fix some problem when using Qt OpenGL2 engine
glStencilMask(0x11111111);
// Deactivate drawing in depth buffer by default
glDepthMask(GL_FALSE);
enableTexture2d(false);
setShadeModel(StelPainter::ShadeModelFlat);
setProjector(proj);
} }
//! Revert openGL state so that Qt painting works again void StelPainter::setProjector(const StelProjectorP& p)
void StelPainter::revertToQtPainting()
{ {
prj=p;
// Init GL viewport to current projector values
glViewport(prj->viewportXywh[0], prj->viewportXywh[1], prj->viewport
Xywh[2], prj->viewportXywh[3]);
glFrontFace(prj->needGlFrontFaceCW()?GL_CW:GL_CCW);
#ifndef STELPAINTER_GL2
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the real openGL projection and modelview matrix to 2d orthogr
aphic projection
// thus we never need to change to 2dMode from now on before drawing
glMultMatrixf(prj->getProjectionMatrix());
glMatrixMode(GL_MODELVIEW);
#endif
}
StelPainter::~StelPainter()
{
Q_ASSERT(qPainter);
#ifndef STELPAINTER_GL2
// Restore openGL projection state for Qt drawings // Restore openGL projection state for Qt drawings
glMatrixMode(GL_TEXTURE); glMatrixMode(GL_TEXTURE);
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPopMatrix(); glPopMatrix();
glPopAttrib(); #endif
glPopClientAttrib();
#ifndef NDEBUG #ifndef NDEBUG
GLenum er = glGetError(); GLenum er = glGetError();
if (er!=GL_NO_ERROR) if (er!=GL_NO_ERROR)
{ {
if (er==GL_INVALID_OPERATION) if (er==GL_INVALID_OPERATION)
qFatal("Invalid openGL operation in StelPainter::rev ertToQtPainting()"); qFatal("Invalid openGL operation detected in ~StelPa inter()");
} }
#endif #endif
qPainter->endNativePainting();
#ifndef NDEBUG
// We are done with this StelPainter
globalMutex->unlock();
#endif
} }
void StelPainter::initSystemGLInfo() void StelPainter::setFont(const QFont& font)
{ {
// TODO move that in static code Q_ASSERT(qPainter);
QSettings* conf = StelApp::getInstance().getSettings(); qPainter->setFont(font);
Q_ASSERT(conf);
flagGlPointSprite = conf->value("projection/flag_use_gl_point_sprite
",false).toBool();
flagGlPointSprite = flagGlPointSprite && GLEE_ARB_point_sprite;
if (flagGlPointSprite)
{
glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRU
E );
glEnable(GL_POINT_SPRITE_ARB);
glEnable(GL_POINT_SMOOTH);
qDebug() << "INFO: using GL_ARB_point_sprite";
}
else
{
//qDebug() << "WARNING: GL_ARB_point_sprite not avai
lable";
}
} }
/************************************************************************* void StelPainter::setColor(float r, float g, float b, float a)
Init the real openGL Matrices to a 2d orthographic projection
*************************************************************************/
void StelPainter::initGlMatrixOrtho2d(void) const
{ {
// Set the real openGL projection and modelview matrix to orthograph #ifndef STELPAINTER_GL2
ic projection glColor4f(r,g,b,a);
// thus we never need to change to 2dMode from now on before drawing #else
glMatrixMode(GL_PROJECTION); currentColor.set(r,g,b,a);
glLoadIdentity(); #endif
glOrtho(prj->viewportXywh[0], prj->viewportXywh[0] + prj->viewportXy }
wh[2],
prj->viewportXywh[1], prj->viewportXywh[1] + prj->vi Vec4f StelPainter::getColor() const
ewportXywh[3], -1, 1); {
glMatrixMode(GL_MODELVIEW); #ifndef STELPAINTER_GL2
glLoadIdentity(); GLfloat tmpColor[4];
glGetFloatv(GL_CURRENT_COLOR, tmpColor);
return Vec4f(tmpColor[0], tmpColor[1], tmpColor[2], tmpColor[3]);
#else
return currentColor;
#endif
}
QFontMetrics StelPainter::getFontMetrics() const
{
Q_ASSERT(qPainter);
return qPainter->fontMetrics();
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Standard methods for drawing primitives // Standard methods for drawing primitives
// Fill with black around the circle // Fill with black around the circle
void StelPainter::drawViewportShape(void) const void StelPainter::drawViewportShape(void)
{ {
if (prj->maskType != StelProjector::MaskDisk) if (prj->maskType != StelProjector::MaskDisk)
return; return;
glDisable(GL_BLEND); glDisable(GL_BLEND);
glColor3f(0.f,0.f,0.f); setColor(0.f,0.f,0.f);
glPushMatrix();
glTranslated(prj->viewportCenter[0],prj->viewportCenter[1],0.0); GLfloat innerRadius = 0.5*prj->viewportFovDiameter;
GLUquadricObj * p = gluNewQuadric(); GLfloat outerRadius = prj->getViewportWidth()+prj->getViewportHeight
gluDisk(p, 0.5*prj->viewportFovDiameter, prj->getViewportWidth()+prj ();
->getViewportHeight(), 256, 1); // should always cover whole screen GLint slices = 256;
gluDeleteQuadric(p); GLfloat sweepAngle = 360.;
glPopMatrix();
GLfloat sinCache[240];
GLfloat cosCache[240];
GLfloat vertices[(240+1)*2][3];
GLfloat deltaRadius;
GLfloat radiusHigh;
if (slices>=240)
{
slices=240-1;
}
if (outerRadius<=0.0 || innerRadius<0.0 ||innerRadius > outerRadius)
{
Q_ASSERT(0);
return;
}
/* Compute length (needed for normal calculations) */
deltaRadius=outerRadius-innerRadius;
/* Cache is the vertex locations cache */
for (int i=0; i<=slices; i++)
{
GLfloat angle=((M_PI*sweepAngle)/180.0f)*i/slices;
sinCache[i]=(GLfloat)sin(angle);
cosCache[i]=(GLfloat)cos(angle);
}
sinCache[slices]=sinCache[0];
cosCache[slices]=cosCache[0];
/* Enable arrays */
enableClientStates(true);
setVertexPointer(3, GL_FLOAT, vertices);
radiusHigh=outerRadius-deltaRadius;
for (int i=0; i<=slices; i++)
{
vertices[i*2][0]= prj->viewportCenter[0] + outerRadius*sinCa
che[i];
vertices[i*2][1]= prj->viewportCenter[1] + outerRadius*cosCa
che[i];
vertices[i*2][2] = 0.0;
vertices[i*2+1][0]= prj->viewportCenter[0] + radiusHigh*sinC
ache[i];
vertices[i*2+1][1]= prj->viewportCenter[1] + radiusHigh*cosC
ache[i];
vertices[i*2+1][2] = 0.0;
}
drawFromArray(TriangleStrip, (slices+1)*2, 0, false);
enableClientStates(false);
} }
#define MAX_STACKS 4096 #define MAX_STACKS 4096
static double cos_sin_rho[2*(MAX_STACKS+1)]; static double cos_sin_rho[2*(MAX_STACKS+1)];
#define MAX_SLICES 4096 #define MAX_SLICES 4096
static double cos_sin_theta[2*(MAX_SLICES+1)]; static double cos_sin_theta[2*(MAX_SLICES+1)];
static static
void ComputeCosSinTheta(double phi,int segments) { void ComputeCosSinTheta(double phi,int segments) {
double *cos_sin = cos_sin_theta; double *cos_sin = cos_sin_theta;
skipping to change at line 209 skipping to change at line 275
const double s = sin(phi); const double s = sin(phi);
*cos_sin++ = 1.0; *cos_sin++ = 1.0;
*cos_sin++ = 0.0; *cos_sin++ = 0.0;
*--cos_sin_rev = -cos_sin[-1]; *--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2]; *--cos_sin_rev = cos_sin[-2];
*cos_sin++ = c; *cos_sin++ = c;
*cos_sin++ = s; *cos_sin++ = s;
*--cos_sin_rev = -cos_sin[-1]; *--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2]; *--cos_sin_rev = cos_sin[-2];
while (cos_sin < cos_sin_rev) { while (cos_sin < cos_sin_rev) {
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
cos_sin += 2; cos_sin += 2;
*--cos_sin_rev = -cos_sin[-1]; *--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2]; *--cos_sin_rev = cos_sin[-2];
} }
} }
static static
void ComputeCosSinRho(double phi,int segments) { void ComputeCosSinRho(double phi,int segments) {
double *cos_sin = cos_sin_rho; double *cos_sin = cos_sin_rho;
double *cos_sin_rev = cos_sin + 2*(segments+1); double *cos_sin_rev = cos_sin + 2*(segments+1);
const double c = cos(phi); const double c = cos(phi);
const double s = sin(phi); const double s = sin(phi);
*cos_sin++ = 1.0; *cos_sin++ = 1.0;
*cos_sin++ = 0.0; *cos_sin++ = 0.0;
*--cos_sin_rev = cos_sin[-1]; *--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2]; *--cos_sin_rev = -cos_sin[-2];
*cos_sin++ = c; *cos_sin++ = c;
*cos_sin++ = s; *cos_sin++ = s;
*--cos_sin_rev = cos_sin[-1]; *--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2]; *--cos_sin_rev = -cos_sin[-2];
while (cos_sin < cos_sin_rev) { while (cos_sin < cos_sin_rev) {
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
cos_sin += 2; cos_sin += 2;
*--cos_sin_rev = cos_sin[-1]; *--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2]; *--cos_sin_rev = -cos_sin[-2];
segments--; segments--;
} }
} }
void StelPainter::sFanDisk(double radius, int innerFanSlices, int level) co nst void StelPainter::sFanDisk(double radius, int innerFanSlices, int level)
{ {
Q_ASSERT(level<64); Q_ASSERT(level<64);
double rad[64]; double rad[64];
int i,j; int i,j;
rad[level] = radius; rad[level] = radius;
// for (i=level-1;i>=0;i--) {
// double f = ((i+1)/(double)(level+1));
// rad[i] = radius*f*f;
// }
for (i=level-1;i>=0;--i) for (i=level-1;i>=0;--i)
{ {
rad[i] = rad[i+1]*(1.0-M_PI/(innerFanSlices<<(i+1)))*2.0/3.0 ; rad[i] = rad[i+1]*(1.0-M_PI/(innerFanSlices<<(i+1)))*2.0/3.0 ;
} }
int slices = innerFanSlices<<level; int slices = innerFanSlices<<level;
const double dtheta = 2.0 * M_PI / slices; const double dtheta = 2.0 * M_PI / slices;
Q_ASSERT(slices<=MAX_SLICES); Q_ASSERT(slices<=MAX_SLICES);
ComputeCosSinTheta(dtheta,slices); ComputeCosSinTheta(dtheta,slices);
double *cos_sin_theta_p; double *cos_sin_theta_p;
int slices_step = 2; int slices_step = 2;
static QVector<double> vertexArr;
static QVector<float> texCoordArr;
double x,y;
for (i=level;i>0;--i,slices_step<<=1) for (i=level;i>0;--i,slices_step<<=1)
{ {
for (j=0,cos_sin_theta_p=cos_sin_theta; j<slices; j+=slices_ step,cos_sin_theta_p+=2*slices_step) for (j=0,cos_sin_theta_p=cos_sin_theta; j<slices; j+=slices_ step,cos_sin_theta_p+=2*slices_step)
{ {
glBegin(GL_TRIANGLE_FAN); vertexArr.resize(0);
double x = rad[i]*cos_sin_theta_p[slices_step]; texCoordArr.resize(0);
double y = rad[i]*cos_sin_theta_p[slices_step+1]; x = rad[i]*cos_sin_theta_p[slices_step];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); y = rad[i]*cos_sin_theta_p[slices_step+1];
drawVertex3(x,y,0); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radi
us);
vertexArr << x << y << 0;
x = rad[i]*cos_sin_theta_p[2*slices_step]; x = rad[i]*cos_sin_theta_p[2*slices_step];
y = rad[i]*cos_sin_theta_p[2*slices_step+1]; y = rad[i]*cos_sin_theta_p[2*slices_step+1];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radi
drawVertex3(x,y,0); us);
vertexArr << x << y << 0;
x = rad[i-1]*cos_sin_theta_p[2*slices_step]; x = rad[i-1]*cos_sin_theta_p[2*slices_step];
y = rad[i-1]*cos_sin_theta_p[2*slices_step+1]; y = rad[i-1]*cos_sin_theta_p[2*slices_step+1];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radi
drawVertex3(x,y,0); us);
vertexArr << x << y << 0;
x = rad[i-1]*cos_sin_theta_p[0]; x = rad[i-1]*cos_sin_theta_p[0];
y = rad[i-1]*cos_sin_theta_p[1]; y = rad[i-1]*cos_sin_theta_p[1];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radi
drawVertex3(x,y,0); us);
vertexArr << x << y << 0;
x = rad[i]*cos_sin_theta_p[0]; x = rad[i]*cos_sin_theta_p[0];
y = rad[i]*cos_sin_theta_p[1]; y = rad[i]*cos_sin_theta_p[1];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radi
drawVertex3(x,y,0); us);
glEnd(); vertexArr << x << y << 0;
setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)tex
CoordArr.constData());
drawFromArray(TriangleFan, vertexArr.size()/3);
} }
} }
// draw the inner polygon // draw the inner polygon
slices_step>>=1; slices_step>>=1;
glBegin(GL_POLYGON); vertexArr.resize(0);
texCoordArr.resize(0);
texCoordArr << 0.5 << 0.5;
vertexArr << 0 << 0 << 0;
for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; j+=slices_step,co s_sin_theta_p+=2*slices_step) for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; j+=slices_step,co s_sin_theta_p+=2*slices_step)
{ {
double x = rad[0]*cos_sin_theta_p[0]; x = rad[0]*cos_sin_theta_p[0];
double y = rad[0]*cos_sin_theta_p[1]; y = rad[0]*cos_sin_theta_p[1];
glTexCoord2d(0.5*(1.0+x/radius),0.5*(1.0+y/radius)); texCoordArr << 0.5*(1.0+x/radius) << 0.5*(1.0+y/radius);
drawVertex3(x,y,0); vertexArr << x << y << 0;
}
glEnd();
}
// Draw a disk with a special texturing mode having texture center at disk
center
void StelPainter::sDisk(GLdouble radius, GLint slices, GLint stacks, int or
ientInside) const
{
GLint i,j;
const GLfloat nsign = orientInside ? -1 : 1;
double r;
const double dr = radius / stacks;
const double dtheta = 2.0 * M_PI / slices;
if (slices < 0) slices = -slices;
Q_ASSERT(slices<=MAX_SLICES);
ComputeCosSinTheta(dtheta,slices);
double *cos_sin_theta_p;
// draw intermediate stacks as quad strips
for (i = 0, r = 0.0; i < stacks; i++, r+=dr)
{
glBegin(GL_QUAD_STRIP);
for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;
j++,cos_sin_theta_p+=2)
{
double x = r*cos_sin_theta_p[0];
double y = r*cos_sin_theta_p[1];
glNormal3f(0, 0, nsign);
glTexCoord2d(0.5+0.5*x/radius, 0.5+0.5*y/radius);
drawVertex3(x, y, 0);
x = (r+dr)*cos_sin_theta_p[0];
y = (r+dr)*cos_sin_theta_p[1];
glNormal3f(0, 0, nsign);
glTexCoord2d(0.5+0.5*x/radius, 0.5+0.5*y/radius);
drawVertex3(x, y, 0);
}
glEnd();
} }
setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constDa
ta());
drawFromArray(TriangleFan, vertexArr.size()/3);
} }
void StelPainter::sRing(GLdouble rMin, GLdouble rMax, GLint slices, GLint s tacks, int orientInside) const void StelPainter::sRing(double rMin, double rMax, int slices, int stacks, i nt orientInside)
{ {
double x,y; double x,y;
int j; int j;
const double nsign = (orientInside)?-1.0:1.0; const double nsign = (orientInside)?-1.0:1.0;
const double dr = (rMax-rMin) / stacks; const double dr = (rMax-rMin) / stacks;
const double dtheta = 2.0 * M_PI / slices; const double dtheta = 2.0 * M_PI / slices;
if (slices < 0) slices = -slices; if (slices < 0) slices = -slices;
Q_ASSERT(slices<=MAX_SLICES); Q_ASSERT(slices<=MAX_SLICES);
ComputeCosSinTheta(dtheta,slices); ComputeCosSinTheta(dtheta,slices);
double *cos_sin_theta_p; double *cos_sin_theta_p;
static QVector<double> vertexArr;
static QVector<float> texCoordArr;
static QVector<float> normalArr;
// draw intermediate stacks as quad strips // draw intermediate stacks as quad strips
for (double r = rMin; r < rMax; r+=dr) for (double r = rMin; r < rMax; r+=dr)
{ {
const double tex_r0 = (r-rMin)/(rMax-rMin); const double tex_r0 = (r-rMin)/(rMax-rMin);
const double tex_r1 = (r+dr-rMin)/(rMax-rMin); const double tex_r1 = (r+dr-rMin)/(rMax-rMin);
glBegin(GL_QUAD_STRIP /*GL_TRIANGLE_STRIP*/); vertexArr.resize(0);
for (j=0,cos_sin_theta_p=cos_sin_theta; texCoordArr.resize(0);
j<=slices; normalArr.resize(0);
j++,cos_sin_theta_p+=2) for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_s
in_theta_p+=2)
{ {
x = r*cos_sin_theta_p[0]; x = r*cos_sin_theta_p[0];
y = r*cos_sin_theta_p[1]; y = r*cos_sin_theta_p[1];
glNormal3d(0, 0, nsign); normalArr << 0 << 0 << nsign;
glTexCoord2d(tex_r0, 0.5); texCoordArr << tex_r0 << 0.5;
drawVertex3(x, y, 0); vertexArr << x << y << 0;
x = (r+dr)*cos_sin_theta_p[0]; x = (r+dr)*cos_sin_theta_p[0];
y = (r+dr)*cos_sin_theta_p[1]; y = (r+dr)*cos_sin_theta_p[1];
glNormal3d(0, 0, nsign); normalArr << 0 << 0 << nsign;
glTexCoord2d(tex_r1, 0.5); texCoordArr << tex_r1 << 0.5;
drawVertex3(x, y, 0); vertexArr << x << y << 0;
} }
glEnd(); setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr
.constData(), NULL, (Vec3f*)normalArr.constData());
drawFromArray(TriangleStrip, vertexArr.size()/3);
} }
} }
static void sSphereMapTexCoordFast(double rho_div_fov, double costheta, dou ble sintheta) static void sSphereMapTexCoordFast(double rho_div_fov, double costheta, dou ble sintheta, QVector<float>& out)
{ {
if (rho_div_fov>0.5) if (rho_div_fov>0.5)
rho_div_fov=0.5; rho_div_fov=0.5;
glTexCoord2d(0.5 + rho_div_fov * costheta, out << 0.5 + rho_div_fov * costheta << 0.5 + rho_div_fov * sintheta;
0.5 + rho_div_fov * sintheta);
} }
void StelPainter::sSphereMap(GLdouble radius, GLint slices, GLint stacks, d ouble textureFov, int orientInside) const void StelPainter::sSphereMap(double radius, int slices, int stacks, double textureFov, int orientInside)
{ {
double rho,x,y,z; double rho,x,y,z;
int i, j; int i, j;
const double nsign = orientInside?-1:1;
double drho = M_PI / stacks; double drho = M_PI / stacks;
Q_ASSERT(stacks<=MAX_STACKS); Q_ASSERT(stacks<=MAX_STACKS);
ComputeCosSinRho(drho,stacks); ComputeCosSinRho(drho,stacks);
double *cos_sin_rho_p; double *cos_sin_rho_p;
const double dtheta = 2.0 * M_PI / slices; const double dtheta = 2.0 * M_PI / slices;
Q_ASSERT(slices<=MAX_SLICES); Q_ASSERT(slices<=MAX_SLICES);
ComputeCosSinTheta(dtheta,slices); ComputeCosSinTheta(dtheta,slices);
double *cos_sin_theta_p; double *cos_sin_theta_p;
drho/=textureFov; drho/=textureFov;
// texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y ax is // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y ax is
// t goes from -1.0/+1.0 at z = -radius/+radius (linear along longit udes) // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longit udes)
// cannot use triangle fan on texturing (s coord. at top/bottom tip varies) // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
const int imax = stacks; const int imax = stacks;
static QVector<double> vertexArr;
static QVector<float> texCoordArr;
// draw intermediate stacks as quad strips // draw intermediate stacks as quad strips
if (!orientInside) // nsign==1 if (!orientInside) // nsign==1
{ {
for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0; i < imax; ++i, cos_sin_rho_p+=2,rho+=drho) for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0; i < imax; ++i, cos_sin_rho_p+=2,rho+=drho)
{ {
glBegin(GL_QUAD_STRIP); vertexArr.resize(0);
texCoordArr.resize(0);
for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j ,cos_sin_theta_p+=2) for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j ,cos_sin_theta_p+=2)
{ {
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
y = cos_sin_theta_p[0] * cos_sin_rho_p[1]; y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
z = cos_sin_rho_p[0]; z = cos_sin_rho_p[0];
glNormal3d(x * nsign, y * nsign, z * nsign); sSphereMapTexCoordFast(rho, cos_sin_theta_p[
sSphereMapTexCoordFast(rho, cos_sin_theta_p[ 0], cos_sin_theta_p[1], texCoordArr);
0], cos_sin_theta_p[1]); vertexArr << x*radius << y*radius << z*radiu
drawVertex3(x * radius, y * radius, z * radi s;
us);
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
y = cos_sin_theta_p[0] * cos_sin_rho_p[3]; y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
z = cos_sin_rho_p[2]; z = cos_sin_rho_p[2];
glNormal3d(x * nsign, y * nsign, z * nsign); sSphereMapTexCoordFast(rho + drho, cos_sin_t
sSphereMapTexCoordFast(rho + drho, cos_sin_t heta_p[0], cos_sin_theta_p[1], texCoordArr);
heta_p[0], cos_sin_theta_p[1]); vertexArr << x*radius << y*radius << z*radiu
drawVertex3(x * radius, y * radius, z * radi s;
us);
} }
glEnd(); setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)tex
CoordArr.constData());
drawFromArray(TriangleStrip, vertexArr.size()/3);
} }
} }
else else
{ {
for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0; i < imax; ++i, cos_sin_rho_p+=2,rho+=drho) for (i = 0,cos_sin_rho_p=cos_sin_rho,rho=0.0; i < imax; ++i, cos_sin_rho_p+=2,rho+=drho)
{ {
glBegin(GL_QUAD_STRIP); vertexArr.resize(0);
texCoordArr.resize(0);
for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j ,cos_sin_theta_p+=2) for (j=0,cos_sin_theta_p=cos_sin_theta;j<=slices;++j ,cos_sin_theta_p+=2)
{ {
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
y = cos_sin_theta_p[0] * cos_sin_rho_p[3]; y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
z = cos_sin_rho_p[2]; z = cos_sin_rho_p[2];
glNormal3d(x * nsign, y * nsign, z * nsign); sSphereMapTexCoordFast(rho + drho, cos_sin_t
sSphereMapTexCoordFast(rho + drho, cos_sin_t heta_p[0], -cos_sin_theta_p[1], texCoordArr);
heta_p[0], -cos_sin_theta_p[1]); vertexArr << x*radius << y*radius << z*radiu
drawVertex3(x * radius, y * radius, z * radi s;
us);
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
y = cos_sin_theta_p[0] * cos_sin_rho_p[1]; y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
z = cos_sin_rho_p[0]; z = cos_sin_rho_p[0];
glNormal3d(x * nsign, y * nsign, z * nsign); sSphereMapTexCoordFast(rho, cos_sin_theta_p[
sSphereMapTexCoordFast(rho, cos_sin_theta_p[ 0], -cos_sin_theta_p[1], texCoordArr);
0], -cos_sin_theta_p[1]); vertexArr << x*radius << y*radius << z*radiu
drawVertex3(x * radius, y * radius, z * radi s;
us);
} }
glEnd(); setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)tex
CoordArr.constData());
drawFromArray(TriangleStrip, vertexArr.size()/3);
} }
} }
} }
void StelPainter::drawTextGravity180(const StelFont* font, float x, float y void StelPainter::drawTextGravity180(float x, float y, const QString& ws, f
, const QString& ws, loat xshift, float yshift) const
bool speedOptimize, float xshift, float
yshift) const
{ {
static float dx, dy, d, theta, psi; float dx, dy, d, theta, psi;
dx = x - prj->viewportCenter[0]; dx = x - prj->viewportCenter[0];
dy = y - prj->viewportCenter[1]; dy = y - prj->viewportCenter[1];
d = sqrt(dx*dx + dy*dy); d = std::sqrt(dx*dx + dy*dy);
// If the text is too far away to be visible in the screen return // If the text is too far away to be visible in the screen return
if (d>qMax(prj->viewportXywh[3], prj->viewportXywh[2])*2) if (d>qMax(prj->viewportXywh[3], prj->viewportXywh[2])*2)
return; return;
theta = M_PI + std::atan2(dx, dy - 1); theta = M_PI + std::atan2(dx, dy - 1);
psi = std::atan2((float)font->getStrLen(ws)/ws.length(),d + 1) * 180 psi = std::atan2((float)qPainter->fontMetrics().width(ws)/ws.length(
./M_PI; ),d + 1) * 180./M_PI;
if (psi>5) if (psi>5)
psi = 5; psi = 5;
glPushAttrib(GL_ALL_ATTRIB_BITS); qPainter->translate(x, y);
glPushMatrix();
glTranslatef(x,y,0);
if (prj->gravityLabels) if (prj->gravityLabels)
glRotatef(theta*180./M_PI,0,0,-1); qPainter->rotate(-theta*180./M_PI);
glTranslatef(xshift, -yshift, 0); qPainter->translate(xshift, yshift);
glScalef(1, -1, 1); qPainter->scale(1, -1);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transpa
rency mode
for (int i=0;i<ws.length();++i) for (int i=0;i<ws.length();++i)
{ {
if( !speedOptimize ) qPainter->drawText(0,0,ws[i]);
{
font->printCharOutlined(ws[i]);
}
else
{
font->printChar(ws[i]);
}
// with typeface need to manually advance // with typeface need to manually advance
// TODO, absolute rotation would be better than relative // TODO, absolute rotation would be better than relative
// TODO: would look better with kerning information... // TODO: would look better with kerning information...
glTranslatef(font->getStrLen(ws.mid(i,1)) * 1.05, 0, 0); qPainter->translate((float)qPainter->fontMetrics().width(ws.
mid(i,1)) * 1.05, 0);
if( !speedOptimize ) qPainter->rotate(-psi);
{
psi = std::atan2((float)font->getStrLen(ws.mid(i,1))
*1.05f,(float)d) * 180./M_PI;
if (psi>5)
psi = 5;
}
glRotatef(psi,0,0,-1);
} }
glPopMatrix(); }
glPopAttrib();
void StelPainter::drawText(const Vec3d& v, const QString& str, float angleD
eg, float xshift, float yshift, bool noGravity) const
{
Vec3d win;
prj->project(v, win);
drawText(win[0], win[1], str, angleDeg, xshift, yshift, noGravity);
} }
/************************************************************************* /*************************************************************************
Draw the string at the given position and angle with the given font Draw the string at the given position and angle with the given font
*************************************************************************/ *************************************************************************/
void StelPainter::drawText(const StelFont* font, float x, float y, const QS tring& str, float angleDeg, float xshift, float yshift, bool noGravity) con st void StelPainter::drawText(float x, float y, const QString& str, float angl eDeg, float xshift, float yshift, bool noGravity) const
{ {
Q_ASSERT(qPainter);
float color[4];
#ifndef STELPAINTER_GL2
// Save openGL state
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glGetFloatv(GL_CURRENT_COLOR, color);
#else
color[0]=currentColor[0];
color[1]=currentColor[1];
color[2]=currentColor[2];
color[3]=currentColor[3];
#endif
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qPainter->endNativePainting();
qPainter->save();
qPainter->resetTransform();
qPainter->resetMatrix();
qPainter->setRenderHints(QPainter::TextAntialiasing | QPainter::High
QualityAntialiasing); //
const QColor qCol=QColor::fromRgbF(qMax(qMin(1.f,color[0]),0.f), qMa
x(qMin(1.f,color[1]),0.f), qMax(qMin(1.f,color[2]),0.f), qMax(qMin(1.f,colo
r[3]),0.f));
qPainter->setPen(qCol);
if (prj->gravityLabels && !noGravity) if (prj->gravityLabels && !noGravity)
{ {
drawTextGravity180(font, x, y, str, true, xshift, yshift); drawTextGravity180(x, y, str, xshift, yshift);
return;
} }
else
{
// There are 2 version here depending on the OpenGL engine
// OpenGL 1 need to reverse the text vertically, not OpenGL
2...
// This sounds like a Qt bug
if (qPainter->paintEngine()->type()==QPaintEngine::OpenGL2)
{
qPainter->translate(x+xshift, prj->viewportXywh[3]-y
-yshift);
}
else
{
qPainter->translate(x+xshift, y+yshift);
qPainter->scale(1, -1);
}
qPainter->drawText(0, 0, str);
}
qPainter->restore();
// QPainter* painter = StelAppGraphicsScene::getInstance().switchToQPai qPainter->beginNativePainting();
nting();
// if (painter==NULL)
// {
// StelAppGraphicsScene::getInstance().revertToOpenGL();
// qDebug() << "NULL Painter";
// return;
// }
// painter->setRenderHints(QPainter::TextAntialiasing | QPainter::HighQ
ualityAntialiasing);
// painter->translate(QPointF(x+xshift, y+yshift));
// //painter->scale(1, -1.00001);
// painter->setBrush(QColor(255,255,0));
// painter->setPen(QColor(255,255,0));
// QPainterPath text;
// text.addText(QPointF(0,0), QFont(), str);
// painter->drawPath(text);
// //painter->drawText(QPointF(xshift, -yshift), str);
// StelAppGraphicsScene::getInstance().revertToOpenGL();
glPushMatrix(); #ifndef STELPAINTER_GL2
glTranslatef(x,y,0); glMatrixMode(GL_TEXTURE);
glRotatef(angleDeg,0,0,1);
glTranslatef(0,font->getLineHeight(),0);
font->print(xshift, yshift, str);
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopClientAttrib();
glPopAttrib();
#endif
} }
// Recursive method cutting a small circle in small segments // Recursive method cutting a small circle in small segments
void fIter(const StelProjectorP& prj, const Vec3d& p1, const Vec3d& p2, Vec 3d& win1, Vec3d& win2, QLinkedList<Vec3d>& vertexList, const QLinkedList<Ve c3d>::iterator& iter, double radius, const Vec3d& center, int nbI=0, bool c heckCrossDiscontinuity=true) inline void fIter(const StelProjectorP& prj, const Vec3d& p1, const Vec3d& p2, Vec3d& win1, Vec3d& win2, QLinkedList<Vec3d>& vertexList, const QLinked List<Vec3d>::iterator& iter, double radius, const Vec3d& center, int nbI=0, bool checkCrossDiscontinuity=true)
{ {
const bool crossDiscontinuity = checkCrossDiscontinuity && prj->inte rsectViewportDiscontinuity(p1+center, p2+center); const bool crossDiscontinuity = checkCrossDiscontinuity && prj->inte rsectViewportDiscontinuity(p1+center, p2+center);
if (crossDiscontinuity && nbI>=10) if (crossDiscontinuity && nbI>=10)
{ {
win1[2]=-2.; win1[2]=-2.;
win2[2]=-2.; win2[2]=-2.;
vertexList.insert(iter, win1); vertexList.insert(iter, win1);
vertexList.insert(iter, win2); vertexList.insert(iter, win2);
return; return;
} }
Vec3d win3; Vec3d newVertex(p1); newVertex+=p2;
Vec3d newVertex(p1+p2);
newVertex.normalize(); newVertex.normalize();
newVertex*=radius; newVertex*=radius;
const bool isValidVertex = prj->project(newVertex+center, win3); Vec3d win3(newVertex[0]+center[0], newVertex[1]+center[1], newVertex
[2]+center[2]);
const bool isValidVertex = prj->projectInPlace(win3);
const Vec3d v1(win1[0]-win3[0], win1[1]-win3[1], 0); const double v10=win1[0]-win3[0];
const Vec3d v2(win2[0]-win3[0], win2[1]-win3[1], 0); const double v11=win1[1]-win3[1];
const double v20=win2[0]-win3[0];
const double v21=win2[1]-win3[1];
const double dist = std::sqrt((v1[0]*v1[0]+v1[1]*v1[1])*(v2[0]*v2[0] const double dist = std::sqrt((v10*v10+v11*v11)*(v20*v20+v21*v21));
+v2[1]*v2[1])); const double cosAngle = (v10*v20+v11*v21)/dist;
const double cosAngle = (v1[0]*v2[0]+v1[1]*v2[1])/dist;
if ((cosAngle>-0.999 || dist>50*50 || crossDiscontinuity) && nbI<10) if ((cosAngle>-0.999 || dist>50*50 || crossDiscontinuity) && nbI<10)
{ {
// Use the 3rd component of the vector to store whether the vertex is valid // Use the 3rd component of the vector to store whether the vertex is valid
win3[2]= isValidVertex ? 1.0 : -1.; win3[2]= isValidVertex ? 1.0 : -1.;
fIter(prj, p1, newVertex, win1, win3, vertexList, vertexList .insert(iter, win3), radius, center, nbI+1, crossDiscontinuity || dist>50*5 0); fIter(prj, p1, newVertex, win1, win3, vertexList, vertexList .insert(iter, win3), radius, center, nbI+1, crossDiscontinuity || dist>50*5 0);
fIter(prj, newVertex, p2, win3, win2, vertexList, iter, radi us, center, nbI+1, crossDiscontinuity || dist>50*50 ); fIter(prj, newVertex, p2, win3, win2, vertexList, iter, radi us, center, nbI+1, crossDiscontinuity || dist>50*50 );
} }
} }
// Used by the method below // Used by the method below
static QVector<Vec3d> smallCircleVertexArray; QVector<Vec2f> StelPainter::smallCircleVertexArray;
void drawSmallCircleVertexArray() void StelPainter::drawSmallCircleVertexArray()
{ {
if (smallCircleVertexArray.isEmpty()) if (smallCircleVertexArray.isEmpty())
return; return;
Q_ASSERT(smallCircleVertexArray.size()>1); Q_ASSERT(smallCircleVertexArray.size()>1);
glEnableClientState(GL_VERTEX_ARRAY); enableClientStates(true);
// Load the vertex array setVertexPointer(2, GL_FLOAT, smallCircleVertexArray.constData());
glVertexPointer(3, GL_DOUBLE, 0, smallCircleVertexArray.constData()) drawFromArray(LineStrip, smallCircleVertexArray.size(), 0, false);
; enableClientStates(false);
// And draw everything at once smallCircleVertexArray.resize(0);
glDrawArrays(GL_LINE_STRIP, 0, smallCircleVertexArray.size()); }
glDisableClientState(GL_VERTEX_ARRAY);
smallCircleVertexArray.clear(); static Vec3d pt1, pt2;
} void StelPainter::drawGreatCircleArc(const Vec3d& start, const Vec3d& stop,
const SphericalCap* clippingCap,
void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const
Vec3d& direction, void* userData), void* userData)
{
if (clippingCap)
{
pt1=start;
pt2=stop;
if (clippingCap->clipGreatCircle(pt1, pt2))
{
drawSmallCircleArc(pt1, pt2, Vec3d(0), viewportEdgeI
ntersectCallback, userData);
}
return;
}
drawSmallCircleArc(start, stop, Vec3d(0), viewportEdgeIntersectCallb
ack, userData);
}
/************************************************************************* /*************************************************************************
Draw a small circle arc in the current frame Draw a small circle arc in the current frame
*************************************************************************/ *************************************************************************/
void StelPainter::drawSmallCircleArc(const Vec3d& start, const Vec3d& stop, const Vec3d& rotCenter, void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, const void* userData), const void* user Data) const void StelPainter::drawSmallCircleArc(const Vec3d& start, const Vec3d& stop, const Vec3d& rotCenter, void (*viewportEdgeIntersectCallback)(const Vec3d& screenPos, const Vec3d& direction, void* userData), void* userData)
{ {
Q_ASSERT(smallCircleVertexArray.empty()); Q_ASSERT(smallCircleVertexArray.empty());
QLinkedList<Vec3d> tessArc; // Contains the list of projected po ints from the tesselated arc QLinkedList<Vec3d> tessArc; // Contains the list of projected po ints from the tesselated arc
Vec3d win1, win2; Vec3d win1, win2;
win1[2] = prj->project(start, win1) ? 1.0 : -1.; win1[2] = prj->project(start, win1) ? 1.0 : -1.;
win2[2] = prj->project(stop, win2) ? 1.0 : -1.; win2[2] = prj->project(stop, win2) ? 1.0 : -1.;
tessArc.append(win1); tessArc.append(win1);
double radius; if (rotCenter.lengthSquared()<0.00000001)
if (rotCenter==Vec3d(0,0,0))
{ {
// Great circle // Great circle
radius=1; // Perform the tesselation of the arc in small segments in a
way so that the lines look smooth
fIter(prj, start, stop, win1, win2, tessArc, tessArc.insert(
tessArc.end(), win2), 1, rotCenter);
} }
else else
{ {
Vec3d tmp = (rotCenter^start)/rotCenter.length(); Vec3d tmp = (rotCenter^start)/rotCenter.length();
radius = fabs(tmp.length()); const double radius = fabs(tmp.length());
// Perform the tesselation of the arc in small segments in a
way so that the lines look smooth
fIter(prj, start-rotCenter, stop-rotCenter, win1, win2, tess
Arc, tessArc.insert(tessArc.end(), win2), radius, rotCenter);
} }
// Perform the tesselation of the arc in small segments in a way so
that the lines look smooth
fIter(prj, start-rotCenter, stop-rotCenter, win1, win2, tessArc, tes
sArc.insert(tessArc.end(), win2), radius, rotCenter);
// And draw. // And draw.
QLinkedList<Vec3d>::ConstIterator i = tessArc.begin(); QLinkedList<Vec3d>::ConstIterator i = tessArc.begin();
while (i+1 != tessArc.end()) while (i+1 != tessArc.end())
{ {
const Vec3d& p1 = *i; const Vec3d& p1 = *i;
const Vec3d& p2 = *(++i); const Vec3d& p2 = *(++i);
const bool p1InViewport = prj->checkInViewport(p1); const bool p1InViewport = prj->checkInViewport(p1);
const bool p2InViewport = prj->checkInViewport(p2); const bool p2InViewport = prj->checkInViewport(p2);
if ((p1[2]>0 && p1InViewport) || (p2[2]>0 && p2InViewport)) if ((p1[2]>0 && p1InViewport) || (p2[2]>0 && p2InViewport))
{ {
smallCircleVertexArray.append(p1); smallCircleVertexArray.append(Vec2f(p1[0], p1[1]));
if (i+1==tessArc.end()) if (i+1==tessArc.end())
{ {
smallCircleVertexArray.append(p2); smallCircleVertexArray.append(Vec2f(p2[0], p 2[1]));
drawSmallCircleVertexArray(); drawSmallCircleVertexArray();
} }
if (viewportEdgeIntersectCallback && p1InViewport!=p 2InViewport) if (viewportEdgeIntersectCallback && p1InViewport!=p 2InViewport)
{ {
// We crossed the edge of the view port // We crossed the edge of the view port
if (p1InViewport) if (p1InViewport)
viewportEdgeIntersectCallback(prj->v iewPortIntersect(p1, p2), p2-p1, userData); viewportEdgeIntersectCallback(prj->v iewPortIntersect(p1, p2), p2-p1, userData);
else else
viewportEdgeIntersectCallback(prj->v iewPortIntersect(p2, p1), p1-p2, userData); viewportEdgeIntersectCallback(prj->v iewPortIntersect(p2, p1), p1-p2, userData);
} }
} }
else else
{ {
// Break the line, draw the stored vertex and flush the list // Break the line, draw the stored vertex and flush the list
if (!smallCircleVertexArray.isEmpty()) if (!smallCircleVertexArray.isEmpty())
smallCircleVertexArray.append(p1); smallCircleVertexArray.append(Vec2f(p1[0], p 1[1]));
drawSmallCircleVertexArray(); drawSmallCircleVertexArray();
} }
} }
Q_ASSERT(smallCircleVertexArray.isEmpty()); Q_ASSERT(smallCircleVertexArray.isEmpty());
} }
// Project the passed triangle on the screen ensuring that it will look smo
oth, even for non linear distortion
// by splitting it into subtriangles.
void StelPainter::projectSphericalTriangle(const SphericalCap* clippingCap,
const Vec3d* vertices, QVarLengthArray<Vec3f, 4096>* outVertices,
const Vec2f* texturePos, QVarLengthArray<Vec2f, 4096>* outTe
xturePos,
int nbI, bool checkDisc1, bool checkDisc2, bool checkDisc3)
const
{
Q_ASSERT(fabs(vertices[0].length()-1.)<0.00001);
Q_ASSERT(fabs(vertices[1].length()-1.)<0.00001);
Q_ASSERT(fabs(vertices[2].length()-1.)<0.00001);
if (clippingCap && clippingCap->containsTriangle(vertices))
clippingCap = NULL;
if (clippingCap && !clippingCap->intersectsTriangle(vertices))
return;
bool cDiscontinuity1 = checkDisc1 && prj->intersectViewportDiscontin
uity(vertices[0], vertices[1]);
bool cDiscontinuity2 = checkDisc2 && prj->intersectViewportDiscontin
uity(vertices[1], vertices[2]);
bool cDiscontinuity3 = checkDisc3 && prj->intersectViewportDiscontin
uity(vertices[0], vertices[2]);
const bool cd1=cDiscontinuity1;
const bool cd2=cDiscontinuity2;
const bool cd3=cDiscontinuity3;
Vec3d e0=vertices[0];
Vec3d e1=vertices[1];
Vec3d e2=vertices[2];
bool valid = prj->projectInPlace(e0);
valid = prj->projectInPlace(e1) || valid;
valid = prj->projectInPlace(e2) || valid;
// Clip polygons behind the viewer
if (!valid)
return;
static const double maxSqDistortion = 5.;
if (checkDisc1 && cDiscontinuity1==false)
{
// If the distortion at segment e0,e1 is too big, flags it f
or subdivision
Vec3d win3 = vertices[0]; win3+=vertices[1];
prj->projectInPlace(win3);
win3[0]-=(e0[0]+e1[0])*0.5; win3[1]-=(e0[1]+e1[1])*0.5;
cDiscontinuity1 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (checkDisc2 && cDiscontinuity2==false)
{
// If the distortion at segment e1,e2 is too big, flags it f
or subdivision
Vec3d win3 = vertices[1]; win3+=vertices[2];
prj->projectInPlace(win3);
win3[0]-=(e2[0]+e1[0])*0.5; win3[1]-=(e2[1]+e1[1])*0.5;
cDiscontinuity2 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (checkDisc3 && cDiscontinuity3==false)
{
// If the distortion at segment e2,e0 is too big, flags it f
or subdivision
Vec3d win3 = vertices[2]; win3+=vertices[0];
prj->projectInPlace(win3);
win3[0] -= (e0[0]+e2[0])*0.5;
win3[1] -= (e0[1]+e2[1])*0.5;
cDiscontinuity3 = (win3[0]*win3[0]+win3[1]*win3[1])>maxSqDis
tortion;
}
if (!cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
{
// The triangle is clean, appends it
outVertices->append(Vec3f(e0[0], e0[1], e0[2])); outVertices
->append(Vec3f(e1[0], e1[1], e1[2])); outVertices->append(Vec3f(e2[0], e2[1
], e2[2]));
if (outTexturePos)
outTexturePos->append(texturePos,3);
return;
}
if (nbI > 4)
{
// If we reached the limit number of iterations and still ha
ve a discontinuity,
// discards the triangle.
if (cd1 || cd2 || cd3)
return;
// Else display it, it will be suboptimal though.
outVertices->append(Vec3f(e0[0], e0[1], e0[2])); outVertices
->append(Vec3f(e1[0], e1[1], e2[2])); outVertices->append(Vec3f(e2[0], e2[1
], e2[2]));
if (outTexturePos)
outTexturePos->append(texturePos,3);
return;
}
// Recursively splits the triangle into sub triangles.
// Depending on which combination of sides of the triangle has to be
split a different strategy is used.
Vec3d va[3];
Vec2f ta[3];
// Only 1 side has to be split: split the triangle in 2
if (cDiscontinuity1 && !cDiscontinuity2 && !cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[0];va[1]+=vertices[1];
va[1].normalize();
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[0]+texturePos[1])*0.5;
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, true, false);
//va[0]=vertices[0]+vertices[1];
//va[0].normalize();
va[0]=va[1];
va[1]=vertices[1];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=texturePos[1];
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, false, true);
return;
}
if (!cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[1];
va[2]=vertices[1];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=texturePos[1];
ta[2]=(texturePos[1]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, false, true, true);
va[0]=vertices[0];
//va[1]=vertices[1]+vertices[2];
//va[1].normalize();
va[1]=va[2];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[1]+texturePos[2])*0.5;
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, true, false);
return;
}
if (!cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[1];
va[2]=vertices[0];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=texturePos[1];
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, false, true, true);
//va[0]=vertices[0]+vertices[2];
//va[0].normalize();
va[0]=va[2];
va[1]=vertices[1];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[2])*0.5;
ta[1]=texturePos[1];
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, false, true);
return;
}
// 2 sides have to be split: split the triangle in 3
if (cDiscontinuity1 && cDiscontinuity2 && !cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[0];va[1]+=vertices[1];
va[1].normalize();
va[2]=vertices[1];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[0]+texturePos[1])*0.5;
ta[2]=(texturePos[1]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
//va[0]=vertices[0]+vertices[1];
//va[0].normalize();
va[0]=va[1];
va[1]=vertices[1];
//va[2]=vertices[1]+vertices[2];
//va[2].normalize();
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=texturePos[1];
ta[2]=(texturePos[1]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
va[0]=vertices[0];
//va[1]=vertices[1]+vertices[2];
//va[1].normalize();
va[1]=va[2];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[1]+texturePos[2])*0.5;
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, true, false);
return;
}
if (cDiscontinuity1 && !cDiscontinuity2 && cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[0];va[1]+=vertices[1];
va[1].normalize();
va[2]=vertices[0];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[0]+texturePos[1])*0.5;
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
//va[0]=vertices[0]+vertices[1];
//va[0].normalize();
va[0]=va[1];
va[1]=vertices[2];
//va[2]=vertices[0]+vertices[2];
//va[2].normalize();
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=texturePos[2];
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
//va[0]=vertices[0]+vertices[1];
//va[0].normalize();
va[1]=vertices[1];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=texturePos[1];
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, true, false, true);
return;
}
if (!cDiscontinuity1 && cDiscontinuity2 && cDiscontinuity3)
{
va[0]=vertices[0];
va[1]=vertices[1];
va[2]=vertices[1];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=texturePos[1];
ta[2]=(texturePos[1]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1, false, true, true);
//va[0]=vertices[1]+vertices[2];
//va[0].normalize();
va[0]=va[2];
va[1]=vertices[2];
va[2]=vertices[0];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=(texturePos[1]+texturePos[2])*0.5;
ta[1]=texturePos[2];
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
va[1]=va[0];
va[0]=vertices[0];
//va[1]=vertices[1]+vertices[2];
//va[1].normalize();
//va[2]=vertices[0]+vertices[2];
//va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[1]+texturePos[2])*0.5;
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, o
utTexturePos, nbI+1);
return;
}
// Last case: the 3 sides have to be split: cut in 4 triangles a' la
HTM
va[0]=vertices[0];va[0]+=vertices[1];
va[0].normalize();
va[1]=vertices[1];va[1]+=vertices[2];
va[1].normalize();
va[2]=vertices[0];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=(texturePos[1]+texturePos[2])*0.5;
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, outTextur
ePos, nbI+1);
va[1]=va[0];
va[0]=vertices[0];
//va[1]=vertices[0]+vertices[1];
//va[1].normalize();
//va[2]=vertices[0]+vertices[2];
//va[2].normalize();
if (outTexturePos)
{
ta[0]=texturePos[0];
ta[1]=(texturePos[0]+texturePos[1])*0.5;
ta[2]=(texturePos[0]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, outTextur
ePos, nbI+1);
//va[0]=vertices[0]+vertices[1];
//va[0].normalize();
va[0]=va[1];
va[1]=vertices[1];
va[2]=vertices[1];va[2]+=vertices[2];
va[2].normalize();
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[1])*0.5;
ta[1]=texturePos[1];
ta[2]=(texturePos[1]+texturePos[2])*0.5;
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, outTextur
ePos, nbI+1);
va[0]=vertices[0];va[0]+=vertices[2];
va[0].normalize();
//va[1]=vertices[1]+vertices[2];
//va[1].normalize();
va[1]=va[2];
va[2]=vertices[2];
if (outTexturePos)
{
ta[0]=(texturePos[0]+texturePos[2])*0.5;
ta[1]=(texturePos[1]+texturePos[2])*0.5;
ta[2]=texturePos[2];
}
projectSphericalTriangle(clippingCap, va, outVertices, ta, outTextur
ePos, nbI+1);
return;
}
static QVarLengthArray<Vec3f, 4096> polygonVertexArray;
static QVarLengthArray<Vec2f, 4096> polygonTextureCoordArray;
// XXX: We should change the type to unsigned int
static QVarLengthArray<unsigned int, 4096> indexArray;
void StelPainter::drawGreatCircleArcs(const StelVertexArray& va, const Sphe
ricalCap* clippingCap, bool doSubDivise)
{
Q_ASSERT(va.vertex.size()!=1);
switch (va.primitiveType)
{
case StelVertexArray::Lines:
Q_ASSERT(va.vertex.size()%2==0);
for (int i=0;i<va.vertex.size();i+=2)
drawGreatCircleArc(va.vertex.at(i), va.verte
x.at(i+1), clippingCap);
return;
case StelVertexArray::LineStrip:
for (int i=0;i<va.vertex.size()-1;++i)
drawGreatCircleArc(va.vertex.at(i), va.verte
x.at(i+1), clippingCap);
return;
case StelVertexArray::LineLoop:
for (int i=0;i<va.vertex.size()-1;++i)
drawGreatCircleArc(va.vertex.at(i), va.verte
x.at(i+1), clippingCap);
drawGreatCircleArc(va.vertex.last(), va.vertex.first
(), clippingCap);
return;
default:
Q_ASSERT(0); // Unsupported primitive yype
}
}
// The function object that we use as an interface between VertexArray::for
eachTriangle and
// StelPainter::projectSphericalTriangle.
//
// This is used by drawSphericalTriangles to project all the triangles coor
dinates in a StelVertexArray into our global
// vertex array buffer.
class VertexArrayProjector
{
public:
VertexArrayProjector(const StelVertexArray& ar, StelPainter* apainte
r, const SphericalCap* aclippingCap,
QVarLengthArray<Vec3f, 4096
>* aoutVertices, QVarLengthArray<Vec2f, 4096>* aoutTexturePos=NULL)
: vertexArray(ar), painter(apainter), clippingCap(aclippi
ngCap), outVertices(aoutVertices),
outTexturePos(aoutTexturePos)
{
}
// Project a single triangle and add it into the output arrays
inline void operator()(const Vec3d* v0, const Vec3d* v1, const Vec3d
* v2,
const Vec2f* t0, const Ve
c2f* t1, const Vec2f* t2,
unsigned int i0, unsigned
int i1, unsigned i2)
{
// XXX: we may optimize more by putting the declaration and
the test outside of this method.
const Vec3d tmpVertex[3] = {*v0, *v1, *v2};
if (outTexturePos)
{
const Vec2f tmpTexture[3] = {*t0, *t1, *t2};
painter->projectSphericalTriangle(clippingCap, tmpVe
rtex, outVertices, tmpTexture, outTexturePos);
}
else
painter->projectSphericalTriangle(clippingCap, tmpVe
rtex, outVertices, NULL, NULL);
}
// Draw the resulting arrays
void drawResult()
{
painter->setVertexPointer(3, GL_FLOAT, outVertices->constDat
a());
if (outTexturePos)
painter->setTexCoordPointer(2, GL_FLOAT, outTextureP
os->constData());
painter->enableClientStates(true, outTexturePos != NULL);
painter->drawFromArray(StelPainter::Triangles, outVertices->
size(), 0, false);
painter->enableClientStates(false);
}
private:
const StelVertexArray& vertexArray;
StelPainter* painter;
const SphericalCap* clippingCap;
QVarLengthArray<Vec3f, 4096>* outVertices;
QVarLengthArray<Vec2f, 4096>* outTexturePos;
};
void StelPainter::drawSphericalTriangles(const StelVertexArray& va, bool te
xtured, const SphericalCap* clippingCap, bool doSubDivide)
{
if (va.vertex.isEmpty())
return;
// Never need to do clipping if the projection doesn't have a discon
tinuity
const bool doClip = prj->hasDiscontinuity();
Q_ASSERT(va.vertex.size()>2);
#ifndef STELPAINTER_GL2
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
polygonVertexArray.clear();
polygonTextureCoordArray.clear();
indexArray.clear();
// The simplest case, we don't need to iterate through the triangles
at all.
if (!doClip && !doSubDivide)
{
va.draw(this);
return;
}
if (doClip && !doSubDivide)
{
StelVertexArray cleanVa = va.removeDiscontinuousTriangles(th
is->getProjector().data());
cleanVa.draw(this);
return;
}
// the last case. It is the slowest, it process the triangles one b
y one.
{
// Project all the triangles of the VertexArray into our buf
fer arrays.
VertexArrayProjector result = va.foreachTriangle(VertexArray
Projector(va, this, clippingCap, &polygonVertexArray, textured ? &polygonTe
xtureCoordArray : NULL));
result.drawResult();
return;
}
}
// Draw the given SphericalPolygon.
void StelPainter::drawSphericalRegion(const SphericalRegion* poly, Spherica
lPolygonDrawMode drawMode, const SphericalCap* clippingCap, bool doSubDivis
e)
{
switch (drawMode)
{
case SphericalPolygonDrawModeBoundary:
drawGreatCircleArcs(poly->getOutlineVertexArray(), c
lippingCap, doSubDivise);
break;
case SphericalPolygonDrawModeFill:
case SphericalPolygonDrawModeTextureFill:
glEnable(GL_CULL_FACE);
// Assumes the polygon is already tesselated as tria
ngles
drawSphericalTriangles(poly->getFillVertexArray(), d
rawMode==SphericalPolygonDrawModeTextureFill, clippingCap, doSubDivise);
glDisable(GL_CULL_FACE);
break;
default:
Q_ASSERT(0);
}
}
/************************************************************************* /*************************************************************************
draw a simple circle, 2d viewport coordinates in pixel draw a simple circle, 2d viewport coordinates in pixel
*************************************************************************/ *************************************************************************/
void StelPainter::drawCircle(double x,double y,double r) const void StelPainter::drawCircle(double x,double y,double r)
{ {
if (r <= 1.0) if (r <= 1.0)
return; return;
const Vec2d center(x,y); const Vec2d center(x,y);
const Vec2d v_center(0.5*prj->viewportXywh[2],0.5*prj->viewportXywh[ 3]); const Vec2d v_center(0.5*prj->viewportXywh[2],0.5*prj->viewportXywh[ 3]);
const double R = v_center.length(); const double R = v_center.length();
const double d = (v_center-center).length(); const double d = (v_center-center).length();
if (d > r+R || d < r-R) if (d > r+R || d < r-R)
return; return;
const int segments = 180; const int segments = 180;
const double phi = 2.0*M_PI/segments; const double phi = 2.0*M_PI/segments;
const double cp = cos(phi); const double cp = cos(phi);
const double sp = sin(phi); const double sp = sin(phi);
double dx = r; double dx = r;
double dy = 0; double dy = 0;
glBegin(GL_LINE_LOOP); static QVarLengthArray<Vec3f, 180> circleVertexArray(180);
for (int i=0;i<=segments;i++)
for (int i=0;i<segments;i++)
{ {
glVertex2d(x+dx,y+dy); circleVertexArray[i].set(x+dx,y+dy,0);
r = dx*cp-dy*sp; r = dx*cp-dy*sp;
dy = dx*sp+dy*cp; dy = dx*sp+dy*cp;
dx = r; dx = r;
} }
glEnd(); enableClientStates(true);
setVertexPointer(3, GL_FLOAT, circleVertexArray.data());
drawFromArray(LineLoop, 180, 0, false);
enableClientStates(false);
}
void StelPainter::drawSprite2dMode(double x, double y, float radius)
{
static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
vertexData[0]=x-radius; vertexData[1]=y-radius;
vertexData[2]=x+radius; vertexData[3]=y-radius;
vertexData[4]=x-radius; vertexData[5]=y+radius;
vertexData[6]=x+radius; vertexData[7]=y+radius;
enableClientStates(true, true);
setVertexPointer(2, GL_FLOAT, vertexData);
setTexCoordPointer(2, GL_FLOAT, texCoordData);
drawFromArray(TriangleStrip, 4, 0, false);
enableClientStates(false);
} }
/************************************************************************* void StelPainter::drawSprite2dMode(const Vec3d& v, float radius)
Same function but gives the already projected 2d position in input
*************************************************************************/
void StelPainter::drawSprite2dMode(double x, double y, double size) const
{ {
// Use GL_POINT_SPRITE_ARB extension if available Vec3d win;
if (flagGlPointSprite) prj->project(v, win);
{ drawSprite2dMode(win[0], win[1], radius);
glPointSize(size);
glBegin(GL_POINTS);
glVertex2f(x,y);
glEnd();
return;
}
const double radius = size*0.5;
glBegin(GL_QUADS );
glTexCoord2i(0,0);
glVertex2f(x-radius,y-radius);
glTexCoord2i(1,0);
glVertex2f(x+radius,y-radius);
glTexCoord2i(1,1);
glVertex2f(x+radius,y+radius);
glTexCoord2i(0,1);
glVertex2f(x-radius,y+radius);
glEnd();
} }
/************************************************************************* void StelPainter::drawSprite2dMode(double x, double y, float radius, float
Same function but with a rotation angle rotation)
*************************************************************************/
void StelPainter::drawSprite2dMode(double x, double y, double size, double
rotation) const
{ {
glPushMatrix(); static float vertexData[8];
glTranslatef(x, y, 0.0); static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
glRotatef(rotation,0.,0.,1.);
const double radius = size*0.5; // compute the vertex coordinates applying the translation and the r
glBegin(GL_QUADS ); otation
glTexCoord2i(0,0); static const float vertexBase[] = {-1., -1., 1., -1., -1., 1., 1., 1
glVertex2f(-radius,-radius); .};
glTexCoord2i(1,0); const float cosr = std::cos(rotation / 180 * M_PI);
glVertex2f(+radius,-radius); const float sinr = std::sin(rotation / 180 * M_PI);
glTexCoord2i(1,1); for (int i = 0; i < 8; i+=2)
glVertex2f(+radius,+radius); {
glTexCoord2i(0,1); vertexData[i] = x + radius * vertexBase[i] * cosr - radius *
glVertex2f(-radius,+radius); vertexBase[i+1] * sinr;
glEnd(); vertexData[i+1] = y + radius * vertexBase[i] * sinr + radius
glPopMatrix(); * vertexBase[i+1] * cosr;
}
enableClientStates(true, true);
setVertexPointer(2, GL_FLOAT, vertexData);
setTexCoordPointer(2, GL_FLOAT, texCoordData);
drawFromArray(TriangleStrip, 4, 0, false);
enableClientStates(false);
} }
/************************************************************************* void StelPainter::drawRect2d(float x, float y, float width, float height, b
Draw the given polygon ool textured)
*************************************************************************/
void StelPainter::drawPolygon(const StelGeom::Polygon& poly) const
{ {
const int size = poly.size(); static float vertexData[] = {-10.,-10.,10.,-10., 10.,10., -10.,10.};
if (size<3) static const float texCoordData[] = {0.,0., 1.,0., 0.,1., 1.,1.};
return; vertexData[0]=x; vertexData[1]=y;
vertexData[2]=x+width; vertexData[3]=y;
Vec3d win; vertexData[4]=x; vertexData[5]=y+height;
glBegin(GL_LINE_LOOP); vertexData[6]=x+width; vertexData[7]=y+height;
for (int i=0;i<size;++i) if (textured)
{
enableClientStates(true, true);
setVertexPointer(2, GL_FLOAT, vertexData);
setTexCoordPointer(2, GL_FLOAT, texCoordData);
}
else
{ {
prj->project(poly[i], win); enableClientStates(true);
glVertex3dv(win); setVertexPointer(2, GL_FLOAT, vertexData);
} }
glEnd(); drawFromArray(TriangleStrip, 4, 0, false);
enableClientStates(false);
} }
/************************************************************************* /*************************************************************************
Draw a GL_POINT at the given position Draw a GL_POINT at the given position
*************************************************************************/ *************************************************************************/
void StelPainter::drawPoint2d(double x, double y) const void StelPainter::drawPoint2d(double x, double y)
{ {
if (flagGlPointSprite) static float vertexData[] = {0.,0.};
{ vertexData[0]=x;
glDisable(GL_POINT_SPRITE_ARB); vertexData[1]=y;
glBegin(GL_POINTS);
glVertex2f(x, y); enableClientStates(true);
glEnd(); setVertexPointer(2, GL_FLOAT, vertexData);
glEnable(GL_POINT_SPRITE_ARB); drawFromArray(Points, 1, 0, false);
return; enableClientStates(false);
}
glBegin(GL_POINTS);
glVertex2f(x, y);
glEnd();
} }
/************************************************************************* /*************************************************************************
Draw a rotated rectangle using the current texture at the given position Draw a line between the 2 points.
*************************************************************************/ *************************************************************************/
void StelPainter::drawRectSprite2dMode(double x, double y, double sizex, do uble sizey, double rotation) const void StelPainter::drawLine2d(double x1, double y1, double x2, double y2)
{ {
glPushMatrix(); static float vertexData[] = {0.,0.,0.,0.};
glTranslatef(x, y, 0.0); vertexData[0]=x1;
glRotatef(rotation,0.,0.,1.); vertexData[1]=y1;
const double radiusx = sizex*0.5; vertexData[2]=x2;
const double radiusy = sizey*0.5; vertexData[3]=y2;
glBegin(GL_QUADS );
glTexCoord2i(0,0); enableClientStates(true);
glVertex2f(-radiusx,-radiusy); setVertexPointer(2, GL_FLOAT, vertexData);
glTexCoord2i(1,0); drawFromArray(Lines, 2, 0, false);
glVertex2f(+radiusx,-radiusy); enableClientStates(false);
glTexCoord2i(1,1);
glVertex2f(+radiusx,+radiusy);
glTexCoord2i(0,1);
glVertex2f(-radiusx,+radiusy);
glEnd();
glPopMatrix();
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Drawing methods for general (non-linear) mode // Drawing methods for general (non-linear) mode
void StelPainter::sSphere(double radius, double oneMinusOblateness, int sli
void StelPainter::sSphere(GLdouble radius, GLdouble oneMinusOblateness, GLi ces, int stacks, int orientInside, bool flipTexture)
nt slices, GLint stacks, int orientInside) const
{ {
// It is really good for performance to have Vec4f,Vec3f objects // It is really good for performance to have Vec4f,Vec3f objects
// static rather than on the stack. But why? // static rather than on the stack. But why?
// Is the constructor/destructor so expensive? // Is the constructor/destructor so expensive?
static Vec3f lightPos3; static Vec3f lightPos3;
GLboolean isLightOn;
float c; float c;
static Vec4f ambientLight; static Vec4f ambientLight;
static Vec4f diffuseLight; static Vec4f diffuseLight;
glGetBooleanv(GL_LIGHTING, &isLightOn); bool isLightOn = light.isEnabled();
if (isLightOn) if (isLightOn)
{ {
glGetLightfv(GL_LIGHT0, GL_POSITION, lightPos3); lightPos3.set(light.getPosition()[0], light.getPosition()[1] , light.getPosition()[2]);
lightPos3 -= prj->modelViewMatrix * Vec3d(0.,0.,0.); // -pos CenterEye lightPos3 -= prj->modelViewMatrix * Vec3d(0.,0.,0.); // -pos CenterEye
lightPos3 = prj->modelViewMatrix.transpose().multiplyWithout Translation(lightPos3); lightPos3 = prj->modelViewMatrix.transpose().multiplyWithout Translation(lightPos3);
lightPos3.normalize(); lightPos3.normalize();
glGetLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); ambientLight = light.getAmbient();
glGetLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); diffuseLight = light.getDiffuse();
glDisable(GL_LIGHTING); light.disable();
} }
GLfloat x, y, z; GLfloat x, y, z;
GLfloat s, t; GLfloat s=0.f, t=0.f;
GLint i, j; GLint i, j;
GLfloat nsign; GLfloat nsign;
if (orientInside) if (orientInside)
{ {
nsign = -1.0; nsign = -1.0;
t=0.0; // from inside texture is reversed t=0.0; // from inside texture is reversed
} }
else else
{ {
skipping to change at line 875 skipping to change at line 1437
double *cos_sin_rho_p; double *cos_sin_rho_p;
const double dtheta = 2.0 * M_PI / slices; const double dtheta = 2.0 * M_PI / slices;
Q_ASSERT(slices<=MAX_SLICES); Q_ASSERT(slices<=MAX_SLICES);
ComputeCosSinTheta(dtheta,slices); ComputeCosSinTheta(dtheta,slices);
const double *cos_sin_theta_p; const double *cos_sin_theta_p;
// texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y ax is // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y ax is
// t goes from -1.0/+1.0 at z = -radius/+radius (linear along longit udes) // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longit udes)
// cannot use triangle fan on texturing (s coord. at top/bottom tip varies) // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
const GLfloat ds = 1.0 / slices; // If the texture is flipped, we iterate the coordinates backward.
const GLfloat ds = ((flipTexture) ? -1 : 1) * 1.0 / slices;
const GLfloat dt = nsign / stacks; // from inside texture is reverse d const GLfloat dt = nsign / stacks; // from inside texture is reverse d
// draw intermediate as quad strips // draw intermediate as quad strips
static QVector<double> vertexArr;
static QVector<float> texCoordArr;
static QVector<float> colorArr;
for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_ p+=2) for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_ p+=2)
{ {
glBegin(GL_QUAD_STRIP); texCoordArr.resize(0);
s = 0.0; vertexArr.resize(0);
colorArr.resize(0);
s = (!flipTexture) ? 0.0 : 1.0;
for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;++j, cos_sin_theta_p+=2) for (j = 0,cos_sin_theta_p = cos_sin_theta; j <= slices;++j, cos_sin_theta_p+=2)
{ {
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
y = cos_sin_theta_p[0] * cos_sin_rho_p[1]; y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
z = nsign * cos_sin_rho_p[0]; z = nsign * cos_sin_rho_p[0];
glTexCoord2f(s, t); texCoordArr << s << t;
if (isLightOn) if (isLightOn)
{ {
c = nsign * lightPos3.dot(Vec3f(x * oneMinus Oblateness, y * oneMinusOblateness, z)); c = nsign * (lightPos3[0]*x*oneMinusOblatene ss + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z);
if (c<0) {c=0;} if (c<0) {c=0;}
glColor3f(c*diffuseLight[0] + ambientLight[0 colorArr << c*diffuseLight[0] + ambientLight
], [0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLi
c*diffuseLight[1] + ambientLight[1 ght[2];
],
c*diffuseLight[2] + ambientLight[2
]);
} }
drawVertex3(x * radius, y * radius, z * oneMinusObla teness * radius); vertexArr << x * radius << y * radius << z * oneMinu sOblateness * radius;
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3]; x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
y = cos_sin_theta_p[0] * cos_sin_rho_p[3]; y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
z = nsign * cos_sin_rho_p[2]; z = nsign * cos_sin_rho_p[2];
glTexCoord2f(s, t - dt); texCoordArr << s << t - dt;
if (isLightOn) if (isLightOn)
{ {
c = nsign * lightPos3.dot(Vec3f(x * oneMinus Oblateness,y * oneMinusOblateness,z)); c = nsign * (lightPos3[0]*x*oneMinusOblatene ss + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z);
if (c<0) {c=0;} if (c<0) {c=0;}
glColor3f(c*diffuseLight[0] + ambientLight[0 colorArr << c*diffuseLight[0] + ambientLight
], [0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLi
c*diffuseLight[1] + ambientLight[1 ght[2];
],
c*diffuseLight[2] + ambientLight[2
]);
} }
drawVertex3(x * radius, y * radius, z * oneMinusObla teness * radius); vertexArr << x * radius << y * radius << z * oneMinu sOblateness * radius;
s += ds; s += ds;
} }
glEnd(); // Draw the array now
if (isLightOn)
setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)tex
CoordArr.constData(), (Vec3f*)colorArr.constData());
else
setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)tex
CoordArr.constData());
drawFromArray(TriangleStrip, vertexArr.size()/3);
t -= dt; t -= dt;
} }
if (isLightOn) if (isLightOn)
glEnable(GL_LIGHTING); light.enable();
} }
// Reimplementation of gluCylinder : glu is overrided for non standard proj ection // Reimplementation of gluCylinder : glu is overrided for non standard proj ection
void StelPainter::sCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks, int orientInside) const void StelPainter::sCylinder(double radius, double height, int slices, int o rientInside)
{ {
static GLdouble da, r, dz;
static GLfloat z, nsign;
static GLint i, j;
nsign = 1.0;
if (orientInside) if (orientInside)
glCullFace(GL_FRONT); glCullFace(GL_FRONT);
//nsign = -1.0;
//else nsign = 1.0;
da = 2.0 * M_PI / slices; const float da = 2.0 * M_PI / slices;
dz = height / stacks;
GLfloat ds = 1.0 / slices; float ds = 1.0 / slices;
GLfloat dt = 1.0 / stacks; QVarLengthArray<Vec2f, 128> texCoordArray;
GLfloat t = 0.0; QVarLengthArray<Vec3d, 128> vertexArray;
z = 0.0; float s = 0.f;
r = radius; float x, y;
for (j = 0; j < stacks; j++) for (int i = 0; i <= slices; i++)
{ {
GLfloat s = 0.0; if (i == slices)
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= slices; i++)
{ {
GLfloat x, y; x = 0.f;
if (i == slices) y = 1.f;
{ }
x = std::sin(0.0f); else
y = std::cos(0.0f); {
} x = std::sin(da*i);
else y = std::cos(da*i);
{ }
x = std::sin(i * da); texCoordArray.append(Vec2f(s, 0.f));
y = std::cos(i * da); vertexArray.append(Vec3d(x*radius, y*radius, 0.));
} texCoordArray.append(Vec2f(s, 1.f));
glNormal3f(x * nsign, y * nsign, 0); vertexArray.append(Vec3d(x*radius, y*radius, height));
glTexCoord2f(s, t); s += ds;
drawVertex3(x * r, y * r, z); }
glNormal3f(x * nsign, y * nsign, 0); setArrays(vertexArray.constData(), texCoordArray.constData());
glTexCoord2f(s, t + dt); drawFromArray(TriangleStrip, vertexArray.size());
drawVertex3(x * r, y * r, z + dz);
s += ds;
} /* for slices */
glEnd();
t += dt;
z += dz;
} /* for stacks */
if (orientInside) if (orientInside)
glCullFace(GL_BACK); glCullFace(GL_BACK);
} }
void StelPainter::setPointSize(qreal size)
{
#ifndef STELPAINTER_GL2
glPointSize(size);
#else
#warning GL ES2 to be done
#endif
}
void StelPainter::setShadeModel(ShadeModel m)
{
#ifndef STELPAINTER_GL2
glShadeModel(m);
#else
#warning GL ES2 to be done
#endif
}
void StelPainter::enableTexture2d(bool b)
{
#ifndef STELPAINTER_GL2
if (b)
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
#else
texture2dEnabled = b;
#endif
}
void StelPainter::initSystemGLInfo()
{
#ifdef STELPAINTER_GL2
// Basic shader: just vertex filled with plain color
QGLShader *vshader3 = new QGLShader(QGLShader::Vertex);
const char *vsrc3 =
"attribute mediump vec3 vertex;\n"
"uniform mediump mat4 projectionMatrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
"}\n";
vshader3->compileSourceCode(vsrc3);
QGLShader *fshader3 = new QGLShader(QGLShader::Fragment);
const char *fsrc3 =
"uniform mediump vec4 color;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
fshader3->compileSourceCode(fsrc3);
basicShaderProgram = new QGLShaderProgram(QGLContext::currentContext
());
basicShaderProgram->addShader(vshader3);
basicShaderProgram->addShader(fshader3);
basicShaderProgram->link();
basicShaderVars.projectionMatrix = basicShaderProgram->uniformLocati
on("projectionMatrix");
basicShaderVars.color = basicShaderProgram->uniformLocation("color")
;
basicShaderVars.vertex = basicShaderProgram->attributeLocation("vert
ex");
// Color shader program: color specified per vertex
QGLShader *vshader1 = new QGLShader(QGLShader::Vertex);
const char *vsrc1 =
"attribute highp vec3 vertex;\n"
"attribute mediump vec4 color;\n"
"uniform mediump mat4 projectionMatrix;\n"
"varying mediump vec4 outColor;\n"
"void main(void)\n"
"{\n"
" outColor = color;\n"
" gl_Position = projectionMatrix*vec4(vertex, 1.);\n"
"}\n";
vshader1->compileSourceCode(vsrc1);
QGLShader *fshader1 = new QGLShader(QGLShader::Fragment);
const char *fsrc1 =
"varying mediump vec4 outColor;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = outColor;\n"
"}\n";
fshader1->compileSourceCode(fsrc1);
colorShaderProgram = new QGLShaderProgram(QGLContext::currentContext
());
colorShaderProgram->addShader(vshader1);
colorShaderProgram->addShader(fshader1);
colorShaderProgram->link();
// Basic texture shader program
QGLShader *vshader2 = new QGLShader(QGLShader::Vertex);
const char *vsrc2 =
"attribute highp vec3 vertex;\n"
"attribute mediump vec2 texCoord;\n"
"uniform mediump mat4 projectionMatrix;\n"
"varying mediump vec2 texc;\n"
"void main(void)\n"
"{\n"
" gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
" texc = texCoord;\n"
"}\n";
vshader2->compileSourceCode(vsrc2);
QGLShader *fshader2 = new QGLShader(QGLShader::Fragment);
const char *fsrc2 =
"varying mediump vec2 texc;\n"
"uniform sampler2D tex;\n"
"uniform mediump vec4 texColor;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(tex, texc)*texColor;\n"
"}\n";
fshader2->compileSourceCode(fsrc2);
texturesShaderProgram = new QGLShaderProgram(QGLContext::currentCont
ext());
texturesShaderProgram->addShader(vshader2);
texturesShaderProgram->addShader(fshader2);
texturesShaderProgram->link();
texturesShaderVars.projectionMatrix = texturesShaderProgram->uniform
Location("projectionMatrix");
texturesShaderVars.texCoord = texturesShaderProgram->attributeLocati
on("texCoord");
texturesShaderVars.vertex = texturesShaderProgram->attributeLocation
("vertex");
texturesShaderVars.texColor = texturesShaderProgram->uniformLocation
("texColor");
// Texture shader program + interpolated color per vertex
QGLShader *vshader4 = new QGLShader(QGLShader::Vertex);
const char *vsrc4 =
"attribute highp vec3 vertex;\n"
"attribute mediump vec2 texCoord;\n"
"attribute mediump vec4 color;\n"
"uniform mediump mat4 projectionMatrix;\n"
"varying mediump vec2 texc;\n"
"varying mediump vec4 outColor;\n"
"void main(void)\n"
"{\n"
" gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
" texc = texCoord;\n"
" outColor = color;\n"
"}\n";
vshader4->compileSourceCode(vsrc4);
QGLShader *fshader4 = new QGLShader(QGLShader::Fragment);
const char *fsrc4 =
"varying mediump vec2 texc;\n"
"varying mediump vec4 outColor;\n"
"uniform sampler2D tex;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(tex, texc)*outColor;\n"
"}\n";
fshader4->compileSourceCode(fsrc4);
texturesColorShaderProgram = new QGLShaderProgram(QGLContext::curren
tContext());
texturesColorShaderProgram->addShader(vshader4);
texturesColorShaderProgram->addShader(fshader4);
texturesColorShaderProgram->link();
texturesColorShaderVars.projectionMatrix = texturesColorShaderProgra
m->uniformLocation("projectionMatrix");
texturesColorShaderVars.texCoord = texturesColorShaderProgram->attri
buteLocation("texCoord");
texturesColorShaderVars.vertex = texturesColorShaderProgram->attribu
teLocation("vertex");
texturesColorShaderVars.color = texturesColorShaderProgram->attribut
eLocation("color");
#endif
}
void StelPainter::setArrays(const Vec3d* vertice, const Vec2f* texCoords, c
onst Vec3f* colorArray, const Vec3f* normalArray)
{
enableClientStates(vertice, texCoords, colorArray, normalArray);
setVertexPointer(3, GL_DOUBLE, vertice);
setTexCoordPointer(2, GL_FLOAT, texCoords);
setColorPointer(3, GL_FLOAT, colorArray);
setNormalPointer(GL_FLOAT, normalArray);
}
void StelPainter::enableClientStates(bool vertex, bool texture, bool color,
bool normal)
{
vertexArray.enabled = vertex;
texCoordArray.enabled = texture;
colorArray.enabled = color;
normalArray.enabled = normal;
}
void StelPainter::drawFromArray(DrawingMode mode, int count, int offset, bo
ol doProj, const unsigned int* indices)
{
ArrayDesc projectedVertexArray = vertexArray;
if (doProj)
{
// Project the vertex array using current projection
if (indices)
projectedVertexArray = projectArray(vertexArray, 0,
count, indices + offset);
else
projectedVertexArray = projectArray(vertexArray, off
set, count, NULL);
}
#ifndef STELPAINTER_GL2
// Enable the client state and set the opengl array for each array
Q_ASSERT(projectedVertexArray.enabled);
Q_ASSERT(projectedVertexArray.pointer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(projectedVertexArray.size, projectedVertexArray.type
, 0, projectedVertexArray.pointer);
if (texCoordArray.enabled)
{
Q_ASSERT(texCoordArray.pointer);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(texCoordArray.size, texCoordArray.type, 0,
texCoordArray.pointer);
}
if (normalArray.enabled)
{
Q_ASSERT(normalArray.pointer);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(normalArray.type, 0, normalArray.pointer);
}
if (colorArray.enabled)
{
Q_ASSERT(colorArray.pointer);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(colorArray.size, colorArray.type, 0, colorArr
ay.pointer);
}
#else
QGLShaderProgram* pr=NULL;
const Mat4f& m = getProjector()->getProjectionMatrix();
const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[1
3], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]);
if (!texCoordArray.enabled && !colorArray.enabled && !normalArray.en
abled)
{
pr = basicShaderProgram;
pr->bind();
pr->setAttributeArray(basicShaderVars.vertex, (const GLfloat
*)projectedVertexArray.pointer, projectedVertexArray.size);
pr->enableAttributeArray(basicShaderVars.vertex);
pr->setUniformValue(basicShaderVars.projectionMatrix, qMat);
pr->setUniformValue(basicShaderVars.color, currentColor[0],
currentColor[1], currentColor[2], currentColor[3]);
}
else if (texCoordArray.enabled && !colorArray.enabled && !normalArra
y.enabled)
{
pr = texturesShaderProgram;
pr->bind();
pr->setAttributeArray(texturesShaderVars.vertex, (const GLfl
oat*)projectedVertexArray.pointer, projectedVertexArray.size);
pr->enableAttributeArray(texturesShaderVars.vertex);
pr->setUniformValue(texturesShaderVars.projectionMatrix, qMa
t);
pr->setUniformValue(texturesShaderVars.texColor, currentColo
r[0], currentColor[1], currentColor[2], currentColor[3]);
pr->setAttributeArray(texturesShaderVars.texCoord, (const GL
float*)texCoordArray.pointer, 2);
pr->enableAttributeArray(texturesShaderVars.texCoord);
}
else if (texCoordArray.enabled && colorArray.enabled && !normalArray
.enabled)
{
pr = texturesColorShaderProgram;
pr->bind();
pr->setAttributeArray(texturesColorShaderVars.vertex, (const
GLfloat*)projectedVertexArray.pointer, projectedVertexArray.size);
pr->enableAttributeArray(texturesColorShaderVars.vertex);
pr->setUniformValue(texturesColorShaderVars.projectionMatrix
, qMat);
pr->setAttributeArray(texturesColorShaderVars.texCoord, (con
st GLfloat*)texCoordArray.pointer, 2);
pr->enableAttributeArray(texturesColorShaderVars.texCoord);
pr->setAttributeArray(texturesColorShaderVars.color, (const
GLfloat*)colorArray.pointer, colorArray.size);
pr->enableAttributeArray(texturesColorShaderVars.color);
}
else
{
qDebug() << "Unhandled parameters." << texCoordArray.enabled
<< colorArray.enabled << normalArray.enabled;
qDebug() << "Light: " << light.isEnabled();
return;
}
#endif
if (indices)
glDrawElements(mode, count, GL_UNSIGNED_INT, indices + offse
t);
else
glDrawArrays(mode, offset, count);
#ifndef STELPAINTER_GL2
glDisableClientState(GL_VERTEX_ARRAY);
if (texCoordArray.enabled)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (normalArray.enabled)
glDisableClientState(GL_NORMAL_ARRAY);
if (colorArray.enabled)
glDisableClientState(GL_COLOR_ARRAY);
#else
if (pr==texturesColorShaderProgram)
{
pr->disableAttributeArray(texturesColorShaderVars.texCoord);
pr->disableAttributeArray(texturesColorShaderVars.vertex);
pr->disableAttributeArray(texturesColorShaderVars.color);
}
else if (pr==texturesShaderProgram)
{
pr->disableAttributeArray(texturesShaderVars.texCoord);
pr->disableAttributeArray(texturesShaderVars.vertex);
}
else if (pr == texturesShaderProgram)
{
pr->disableAttributeArray(basicShaderVars.vertex);
}
if (pr)
pr->release();
#endif
}
StelPainter::ArrayDesc StelPainter::projectArray(const StelPainter::ArrayDe
sc& array, int offset, int count, const unsigned int* indices)
{
// XXX: we should use a more generic way to test whether or not to d
o the projection.
if (dynamic_cast<StelProjector2d*>(prj.data()))
{
return array;
}
Q_ASSERT(array.size == 3);
Q_ASSERT(array.type == GL_DOUBLE);
Vec3d* vecArray = (Vec3d*)array.pointer;
// We have two different cases :
// 1) We are not using an indice array. In that case the size of th
e array is known
// 2) We are using an indice array. In that case we have to find th
e max value by iterating through the indices.
if (!indices)
{
polygonVertexArray.resize(offset + count);
prj->project(count, vecArray + offset, polygonVertexArray.da
ta() + offset);
} else
{
// we need to find the max value of the indices !
unsigned int max = 0;
for (int i = offset; i < offset + count; ++i)
{
max = std::max(max, indices[i]);
}
polygonVertexArray.resize(max+1);
prj->project(max + 1, vecArray + offset, polygonVertexArray.
data() + offset);
}
ArrayDesc ret;
ret.size = 3;
ret.type = GL_FLOAT;
ret.pointer = polygonVertexArray.constData();
ret.enabled = array.enabled;
return ret;
}
// Light methods
void StelPainterLight::setPosition(const Vec4f& v)
{
position = v;
#ifndef STELPAINTER_GL2
glLightfv(GL_LIGHT0 + light, GL_POSITION, v);
#endif
}
void StelPainterLight::setDiffuse(const Vec4f& v)
{
diffuse = v;
#ifndef STELPAINTER_GL2
glLightfv(GL_LIGHT0 + light, GL_DIFFUSE, v);
#endif
}
void StelPainterLight::setSpecular(const Vec4f& v)
{
specular = v;
#ifndef STELPAINTER_GL2
glLightfv(GL_LIGHT0 + light, GL_SPECULAR, v);
#endif
}
void StelPainterLight::setAmbient(const Vec4f& v)
{
ambient = v;
#ifndef STELPAINTER_GL2
glLightfv(GL_LIGHT0 + light, GL_AMBIENT, v);
#endif
}
void StelPainterLight::setEnable(bool v)
{
if (v)
enable();
else
disable();
}
void StelPainterLight::enable()
{
enabled = true;
#ifndef STELPAINTER_GL2
glEnable(GL_LIGHTING);
#endif
}
void StelPainterLight::disable()
{
enabled = false;
#ifndef STELPAINTER_GL2
glDisable(GL_LIGHTING);
#endif
}
// material functions
StelPainterMaterial::StelPainterMaterial()
: specular(0, 0, 0, 1), ambient(0.2, 0.2, 0.2, 1.0), emission(0, 0,
0, 1), shininess(0)
{
}
void StelPainterMaterial::setSpecular(const Vec4f& v)
{
specular = v;
#ifndef STELPAINTER_GL2
glMaterialfv(GL_FRONT, GL_SPECULAR, v);
#endif
}
void StelPainterMaterial::setAmbient(const Vec4f& v)
{
ambient = v;
#ifndef STELPAINTER_GL2
glMaterialfv(GL_FRONT, GL_AMBIENT, v);
#endif
}
void StelPainterMaterial::setEmission(const Vec4f& v)
{
emission = v;
#ifndef STELPAINTER_GL2
glMaterialfv(GL_FRONT, GL_EMISSION, v);
#endif
}
void StelPainterMaterial::setShininess(float v)
{
shininess = v;
#ifndef STELPAINTER_GL2
glMaterialfv(GL_FRONT, GL_SHININESS, &v);
#endif
}
 End of changes. 136 change blocks. 
496 lines changed or deleted 1139 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/