Commit 4bb749b5 authored by Khudyakov Alexey's avatar Khudyakov Alexey
Browse files

It required rewrite of TextureManager. Now its API became much simpler

there are just 3(+1) static functions. One to obtain image and two
to bind texture.

Most important changes:

* Texture IDs are cached by Qt so there no point cache them twice
* Texture manager do not own GL context any more. Instead it is
  passed as parameter of QGLWidget* type.
* Texture class is not used anywhere but is still here.
* All Q_ASSERTS on QGLContext are gone
* Planet and deep-skyes store their images as QImage not as
  textures. Also they are loaded at construction time.

Unfortunately this is rather large changeset but there is no
obvious way to implement these changes incrementally.

CCMAIL: kstars-devel@kde.org
BUG: 266933
parent 868a67b7
......@@ -32,7 +32,6 @@ using Eigen::Rotation2Df;
#include "Options.h"
#include "texturemanager.h"
#include "texture.h"
#include "skycomponents/linelist.h"
#include "skycomponents/skiplist.h"
......@@ -53,7 +52,7 @@ Vector3f SkyGLPainter::m_color[NUMTYPES][6*BUFSIZE];
int SkyGLPainter::m_idx[NUMTYPES];
bool SkyGLPainter::m_init = false;
SkyGLPainter::SkyGLPainter( const QGLWidget *widget ) : SkyPainter()
SkyGLPainter::SkyGLPainter( QGLWidget *widget ) : SkyPainter()
{
m_widget = widget;
if( !m_init ) {
......@@ -70,7 +69,6 @@ SkyGLPainter::SkyGLPainter( const QGLWidget *widget ) : SkyPainter()
}
}
//Generate textures that were loaded before the SkyMap was
TextureManager::genTextures();
m_init = true;
}
}
......@@ -81,17 +79,15 @@ void SkyGLPainter::drawBuffer(int type)
if( m_idx[type] == 0 ) return;
glEnable(GL_TEXTURE_2D);
const Texture *tex = 0;
switch( type ) {
case 3: case 13: tex = TextureManager::getTexture("open-cluster"); break;
case 4: tex = TextureManager::getTexture("globular-cluster"); break;
case 6: tex = TextureManager::getTexture("planetary-nebula"); break;
case 5: case 7: case 15: tex = TextureManager::getTexture("gaseous-nebula"); break;
case 8: case 16: tex = TextureManager::getTexture("galaxy"); break;
case 14: tex = TextureManager::getTexture("galaxy-cluster"); break;
case 0: case 1: default: tex = TextureManager::getTexture("star"); break;
case 3: case 13: TextureManager::bindTexture("open-cluster", m_widget); break;
case 4: TextureManager::bindTexture("globular-cluster", m_widget); break;
case 6: TextureManager::bindTexture("planetary-nebula", m_widget); break;
case 5: case 7: case 15: TextureManager::bindTexture("gaseous-nebula", m_widget); break;
case 8: case 16: TextureManager::bindTexture("galaxy", m_widget); break;
case 14: TextureManager::bindTexture("galaxy-cluster", m_widget); break;
case 0: case 1: default: TextureManager::bindTexture("star", m_widget); break;
}
tex->bind();
glBlendFunc(GL_ONE, GL_ONE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
......@@ -168,7 +164,7 @@ bool SkyGLPainter::drawPlanet(KSPlanetBase* planet)
if( planet->name() == "Sun" || planet->name() == "Moon" )
sizemin = 8.0;
if( size < fakeStarSize || !planet->texture()->isReady() )
if( size < fakeStarSize || planet->image().isNull() )
{
// Draw them as bright stars of appropriate color instead of images
char spType;
......@@ -184,11 +180,11 @@ bool SkyGLPainter::drawPlanet(KSPlanetBase* planet)
}
return addItem(planet, planet->type(), qMin(fakeStarSize,(float)20.),spType);
} else {
//Draw images
Q_ASSERT(planet->texture()->isReady());
// Draw them as textures
bool visible = false;
Vector2f pos = m_proj->toScreenVec(planet,true,&visible);
if( !visible ) return false;
if( !visible )
return false;
//Because Saturn has rings, we inflate its image size by a factor 2.5
if( planet->name() == "Saturn" )
......@@ -202,9 +198,7 @@ bool SkyGLPainter::drawPlanet(KSPlanetBase* planet)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_TEXTURE_2D);
bool bound = planet->texture()->bind();
if( !bound ) return false;
TextureManager::bindFromImage( planet->image(), m_widget );
glBegin(GL_QUADS);
vec = pos + rot*Vector2f(-s,-s);
glTexCoord2f(0.,0.);
......@@ -248,16 +242,12 @@ bool SkyGLPainter::drawDeepSkyObject(DeepSkyObject* obj, bool drawImage)
float h = w * obj->e();
//Init texture if it doesn't exist and we would be drawing it anyways
if( drawImage && !obj->texture() )
obj->loadTexture();
const Texture *tex = obj->texture();
if( drawImage && tex && tex->isReady() ) {
if( drawImage && !obj->image().isNull() ) {
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Vector2f vertex;
tex->bind();
TextureManager::bindFromImage( obj->image(), m_widget );
glBegin(GL_QUADS);
vertex = vec + r*Vector2f(-w,-h);
glTexCoord2f(0.,0.);
......@@ -493,8 +483,7 @@ void SkyGLPainter::drawObservingList(const QList< SkyObject* >& obs)
++i;
}
const Texture *tex = TextureManager::getTexture("obslistsymbol");
tex->bind();
TextureManager::bindTexture("obslistsymbol", m_widget);
glBlendFunc(GL_ONE, GL_ONE);
glEnableClientState(GL_VERTEX_ARRAY);
......@@ -514,7 +503,6 @@ void SkyGLPainter::drawFlags()
KStarsData *data = KStarsData::Instance();
SkyPoint* point;
QImage image;
const Texture *tex;
const QString label;
bool visible = false;
Vector2f vec;
......@@ -535,33 +523,28 @@ void SkyGLPainter::drawFlags()
// Get texture from TextureManager
if ( data->skyComposite()->flags()->imageName( i ) == "Default" )
tex = TextureManager::getTexture("defaultflag");
else
tex = TextureManager::createTexture( image );
tex->bind();
// Draw image
if( tex->isReady() ) {
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Vector2f vertex;
glBegin(GL_QUADS);
vertex = vec + Vector2f( image.width()/2 * -1, image.height()/2 );
glTexCoord2f(0.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2, image.height()/2 );
glTexCoord2f(1.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2, image.height()/2 * -1 );
glTexCoord2f(1.,1.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2 * -1, image.height()/2 * -1 );
glTexCoord2f(0.,1.);
glVertex2fv(vertex.data());
glEnd();
}
TextureManager::bindTexture("defaultflag", m_widget);
else
TextureManager::bindFromImage( image, m_widget );
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Vector2f vertex;
glBegin(GL_QUADS);
vertex = vec + Vector2f( image.width()/2 * -1, image.height()/2 );
glTexCoord2f(0.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2, image.height()/2 );
glTexCoord2f(1.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2, image.height()/2 * -1 );
glTexCoord2f(1.,1.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( image.width()/2 * -1, image.height()/2 * -1 );
glTexCoord2f(0.,1.);
glVertex2fv(vertex.data());
glEnd();
// Draw label
drawText( vec.x(), vec.y(), data->skyComposite()->flags()->label( i ), QFont( "Courier New", 10, QFont::Bold ), data->skyComposite()->flags()->labelColor( i ) );
......@@ -600,31 +583,26 @@ void SkyGLPainter::drawText( int x, int y, const QString text, QFont font, QColo
p.end();
// Create texture
Texture *texture = TextureManager::createTexture( text_image );
texture->bind();
// Render image
if( texture->isReady() ) {
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Vector2f vec( x, y );
Vector2f vertex;
glBegin(GL_QUADS);
vertex = vec + Vector2f( 10, text_image.height()/2 -10 );
glTexCoord2f(0.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( text_image.width() + 10, text_image.height()/2 -10 );
glTexCoord2f(1.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( text_image.width() + 10, text_image.height()/2*(-1) - 10 );
glTexCoord2f(1.,1.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( 10, text_image.height()/2*(-1) - 10 );;
glTexCoord2f(0.,1.);
glVertex2fv(vertex.data());
glEnd();
}
TextureManager::bindFromImage( text_image, m_widget );
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Vector2f vec( x, y );
Vector2f vertex;
glBegin(GL_QUADS);
vertex = vec + Vector2f( 10, text_image.height()/2 -10 );
glTexCoord2f(0.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( text_image.width() + 10, text_image.height()/2 -10 );
glTexCoord2f(1.,0.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( text_image.width() + 10, text_image.height()/2*(-1) - 10 );
glTexCoord2f(1.,1.);
glVertex2fv(vertex.data());
vertex = vec + Vector2f( 10, text_image.height()/2*(-1) - 10 );;
glTexCoord2f(0.,1.);
glVertex2fv(vertex.data());
glEnd();
}
void SkyGLPainter::drawSkyLine(SkyPoint* a, SkyPoint* b)
......
......@@ -32,7 +32,7 @@ class QGLWidget;
class SkyGLPainter : public SkyPainter
{
public:
SkyGLPainter( const QGLWidget *widget );
SkyGLPainter( QGLWidget *widget );
virtual bool drawPlanet(KSPlanetBase* planet);
virtual bool drawDeepSkyObject(DeepSkyObject* obj, bool drawImage = false);
virtual bool drawPointSource(SkyPoint* loc, float mag, char sp = 'A');
......@@ -65,7 +65,7 @@ private:
static Vector3f m_color[NUMTYPES][6*BUFSIZE];
static int m_idx[NUMTYPES];
static bool m_init; ///< keep track of whether we have filled the texcoord array
const QGLWidget* m_widget; // Pointer to (GL) widget on which we are painting
QGLWidget* m_widget; // Pointer to (GL) widget on which we are painting
};
#endif // SKYGLPAINTER_H
......@@ -207,9 +207,6 @@ SkyMap::SkyMap() :
m_objBox, SLOT( slotPointChanged(SkyPoint*) ) );
#ifdef HAVE_OPENGL
Q_ASSERT( TextureManager::getContext() ); // Should not fail, because TextureManager should be already created.
m_SkyMapQDraw = new SkyMapQDraw( this );
m_SkyMapQDraw->setMouseTracking( true );
m_SkyMapGLDraw = new SkyMapGLDraw( this );
......@@ -221,9 +218,7 @@ SkyMap::SkyMap() :
m_SkyMapDraw = m_SkyMapGLDraw;
else
m_SkyMapDraw = m_SkyMapQDraw;
#else
m_SkyMapDraw = new SkyMapQDraw( this );
m_SkyMapDraw->setMouseTracking( true );
#endif
......@@ -1088,8 +1083,6 @@ void SkyMap::slotToggleGL() {
Options::setUseGL( true );
Q_ASSERT( TextureManager::getContext() ); // Should not fail, because TextureManager should be already created.
m_SkyMapDraw = m_SkyMapGLDraw;
KStars::Instance()->actionCollection()->action( "opengl" )->setText(i18n("Switch to QPainter backend"));
}
......
......@@ -21,12 +21,10 @@
#include "skymap.h"
SkyMapGLDraw::SkyMapGLDraw( SkyMap *sm ) : QGLWidget( TextureManager::getContext(), sm ),SkyMapDrawAbstract( sm ) {
// We must have the context ready before we create our
// GLWidget. This is a check on that.
Q_ASSERT( TextureManager::getContext() );
SkyMapGLDraw::SkyMapGLDraw( SkyMap *sm ) :
QGLWidget( sm ),
SkyMapDrawAbstract( sm )
{
if( !format().testOption( QGL::SampleBuffers ) )
qWarning() << "No sample buffer; can't use multisampling (antialiasing)";
if( !format().testOption( QGL::StencilBuffer ) )
......
......@@ -44,7 +44,7 @@ DeepSkyObject::DeepSkyObject( const DeepSkyObject &o ) :
PGC( o.PGC ),
MajorAxis( o.MajorAxis ),
MinorAxis( o.MinorAxis ),
m_texture( o.texture() )
m_image( o.m_image )
{
customCat = NULL;
Flux = 0;
......@@ -57,7 +57,8 @@ DeepSkyObject::DeepSkyObject( int t, dms r, dms d, float m,
const QString &n, const QString &n2,
const QString &lname, const QString &cat,
float a, float b, double pa, int pgc, int ugc )
: SkyObject( t, r, d, m, n, n2, lname ) {
: SkyObject( t, r, d, m, n, n2, lname )
{
MajorAxis = a;
MinorAxis = b;
PositionAngle = pa;
......@@ -65,16 +66,17 @@ DeepSkyObject::DeepSkyObject( int t, dms r, dms d, float m,
UGC = ugc;
setCatalog( cat );
updateID = updateNumID = 0;
m_texture = 0;
customCat = NULL;
Flux = 0;
loadImage();
}
DeepSkyObject::DeepSkyObject( int t, double r, double d, float m,
const QString &n, const QString &n2,
const QString &lname, const QString &cat,
float a, float b, double pa, int pgc, int ugc )
: SkyObject( t, r, d, m, n, n2, lname ) {
: SkyObject( t, r, d, m, n, n2, lname )
{
MajorAxis = a;
MinorAxis = b;
PositionAngle = pa;
......@@ -82,9 +84,9 @@ DeepSkyObject::DeepSkyObject( int t, double r, double d, float m,
UGC = ugc;
setCatalog( cat );
updateID = updateNumID = 0;
m_texture = 0;
customCat = NULL;
Flux = 0;
loadImage();
}
DeepSkyObject* DeepSkyObject::clone() const
......@@ -116,15 +118,10 @@ void DeepSkyObject::setCatalog( const QString &cat ) {
else Catalog = (unsigned char)CAT_UNKNOWN;
}
void DeepSkyObject::loadTexture()
void DeepSkyObject::loadImage()
{
QString tname = name().toLower().remove(' ');
m_texture = TextureManager::getTexture( tname );
}
const Texture* DeepSkyObject::texture() const
{
return m_texture;
m_image = TextureManager::getImage( tname );
}
double DeepSkyObject::labelOffset() const {
......
......@@ -27,7 +27,6 @@
class QImage;
class QString;
class KSPopupMenu;
class Texture;
class CustomCatalogComponent;
/**
......@@ -180,16 +179,11 @@ public:
*/
inline int pgc() const { return PGC; }
/**
* @return a pointer to the object's texture.
* @note do check for null pointers...
*/
const Texture* texture() const;
/** @return an object's image */
const QImage& image() const { return m_image; }
/**
* Try to load the object's texture
*/
void loadTexture();
/** Try to load the object's image */
void loadImage();
/**
*@return true if the object is in the Messier catalog
......@@ -226,7 +220,7 @@ private:
double PositionAngle;
int UGC, PGC;
float MajorAxis, MinorAxis, Flux;
const Texture *m_texture;
QImage m_image;
CustomCatalogComponent *customCat;
};
......
......@@ -238,7 +238,7 @@ void KSMoon::findPhase() {
double DegPhase = dms( Phase ).reduce().Degrees();
iPhase = int( 0.1*DegPhase+0.5 ) % 36; // iPhase must be in [0,36) range
m_tex = TextureManager::getTexture(
m_image = TextureManager::getImage(
QString("moon%1").arg(iPhase,2,10,QChar('0')));
}
......
......@@ -56,14 +56,13 @@ const SkyObject::UID KSPlanetBase::UID_SOL_COMET = 2;
KSPlanetBase::KSPlanetBase( const QString &s, const QString &image_file, const QColor &c, double pSize ) :
TrailObject( 2, 0.0, 0.0, 0.0, s ),
Rearth(0.0),
m_tex(0)
Rearth(0.0)
{
init( s, image_file, c, pSize );
}
void KSPlanetBase::init( const QString &s, const QString &image_file, const QColor &c, double pSize ) {
m_tex = TextureManager::getTexture(image_file);
m_image = TextureManager::getImage( image_file );
PositionAngle = 0.0;
PhysicalSize = pSize;
m_Color = c;
......
......@@ -28,7 +28,6 @@
#include "trailobject.h"
class Texture;
class KSNumbers;
class KSPopupMenu;
......@@ -121,7 +120,7 @@ public:
void EquatorialToEcliptic( const dms *Obliquity );
/** @return pointer to this planet's texture */
const Texture* texture() { return m_tex; }
const QImage& image() { return m_image; }
/**@return distance from Sun, in Astronomical Units (1 AU is Earth-Sun distance) */
double rsun() const { return ep.radius; }
......@@ -243,8 +242,7 @@ protected:
EclipticPosition helEcPos;
double Rearth;
double Phase;
const Texture *m_tex;
QImage m_image;
private:
/**
......
......@@ -24,7 +24,6 @@
#include "kstarsdata.h"
#include "Options.h"
#include "skymap.h"
#include "texture.h"
#include "skycomponents/linelist.h"
#include "skycomponents/skiplist.h"
......@@ -322,9 +321,9 @@ bool SkyQPainter::drawPlanet(KSPlanetBase* planet)
sizemin = 8.0;
float size = planet->angSize() * dms::PI * Options::zoomFactor()/10800.0;
if ( size < sizemin )
if( size < sizemin )
size = sizemin;
if ( Options::showPlanetImages() && planet->texture()->isReady() ) {
if( Options::showPlanetImages() && !planet->image().isNull() ) {
//Because Saturn has rings, we inflate its image size by a factor 2.5
if( planet->name() == "Saturn" )
size = int(2.5*size);
......@@ -333,7 +332,7 @@ bool SkyQPainter::drawPlanet(KSPlanetBase* planet)
translate(pos);
rotate( m_proj->findPA( planet, pos.x(), pos.y() ) );
drawImage( QRect(-0.5*size, -0.5*size, size, size),
planet->texture()->image() );
planet->image() );
restore();
} else { //Otherwise, draw a simple circle.
drawEllipse( pos, size, size );
......@@ -387,9 +386,6 @@ bool SkyQPainter::drawDeepSkyObject(DeepSkyObject* obj, bool drawImage)
bool SkyQPainter::drawDeepSkyImage(const QPointF& pos, DeepSkyObject* obj, float positionAngle)
{
if ( !obj->texture() ) obj->loadTexture();
if ( !obj->texture()->isReady() ) return false;
double zoom = Options::zoomFactor();
double w = obj->a() * dms::PI * zoom/10800.0;
double h = obj->e() * w;
......@@ -397,7 +393,7 @@ bool SkyQPainter::drawDeepSkyImage(const QPointF& pos, DeepSkyObject* obj, float
save();
translate(pos);
rotate( positionAngle );
drawImage( QRect(-0.5*w, -0.5*h, w, h), obj->texture()->image() );
drawImage( QRect(-0.5*w, -0.5*h, w, h), obj->image() );
restore();
return true;
......
......@@ -67,16 +67,16 @@ void Texture::setImage(const QImage& img)
#ifdef HAVE_OPENGL
void Texture::genTexture()
{
//FIXME do proper mipmapping
if( Options::useGL() ) {
if( !m_image.isNull() ) {
Q_ASSERT( TextureManager::getContext() );
m_tid = TextureManager::getContext()->bindTexture(m_image, GL_TEXTURE_2D, GL_RGBA, QGLContext::DefaultBindOption);
m_ready = (m_tid != 0);
Q_ASSERT( m_ready );
} else
m_ready = false;
}
// //FIXME do proper mipmapping
// if( Options::useGL() ) {
// if( !m_image.isNull() ) {
// Q_ASSERT( TextureManager::getContext() );
// m_tid = TextureManager::getContext()->bindTexture(m_image, GL_TEXTURE_2D, GL_RGBA, QGLContext::DefaultBindOption);
// m_ready = (m_tid != 0);
// Q_ASSERT( m_ready );
// } else
// m_ready = false;
// }
}
#endif
......
......@@ -8,7 +8,8 @@
This program is distributed in the hope that it will be useful,
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.
You should have received a copy of the GNU General Public License along
......@@ -24,62 +25,74 @@
#include <kstandarddirs.h>
#ifdef HAVE_OPENGL
#include <QGLWidget>
QGLContext* TextureManager::m_context = 0;
# include <QGLWidget>
#endif
// We returning reference to image. We refer to this image when search
// for image fails
const static QImage emptyImage;
TextureManager* TextureManager::m_p;
const Texture* TextureManager::getTexture(const QString& name)
{
TextureManager *TextureManager::Create() {
if( !m_p )
m_p = new TextureManager();
return m_p;
}
const QImage& TextureManager::getImage(const QString& name)
{
Create();
CacheIter it = findTexture( name );
if( it != m_p->m_textures.end() ) {
return *it;
} else {
return emptyImage;
}
}
Texture *tex = m_p->m_textures.value(name,0);
if( !tex ) {
TextureManager::CacheIter TextureManager::findTexture(const QString& name)
{
Create();
// Lookup in cache first
CacheIter it = m_p->m_textures.find( name );
if( it != m_p->m_textures.end() ) {
return it;
} else {
// Try to load from file
QString filename = KStandardDirs::locate("appdata",QString("textures/%1.png").arg(name));
tex = new Texture(m_p);
if( !filename.isNull() ) {
QImage img(filename);
tex->setImage(img);
return m_p->m_textures.insert( name, QImage(filename) );
} else {
qWarning() << "Could not find texture" << name;
qWarning() << "Could not find texture: " << name;
return m_p->m_textures.end();
}
m_p->m_textures.insert(name,tex);
}
return tex;
}
#ifdef HAVE_OPENGL
void TextureManager::genTextures()
static void bindImage(const QImage& img, QGLWidget* cxt)
{
//If there's no instance, there are no textures to bind!
if(!m_p) return;
for( QHash<QString, Texture*>::const_iterator it = m_p->m_textures.constBegin();
it != m_p->m_textures.constEnd();
++it )