StelTexture.cpp   StelTexture.cpp 
skipping to change at line 21 skipping to change at line 21
* 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 <cstdlib> #include <cstdlib>
#include "StelTexture.hpp"
#include "StelTextureMgr.hpp" #include "StelTextureMgr.hpp"
#include "StelTexture.hpp"
#include "glues.h"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelUtils.hpp"
#include "StelMainGraphicsView.hpp"
#include <QThread> #include <QThread>
#include <QMutexLocker> #include <QMutexLocker>
#include <QSemaphore> #include <QSemaphore>
#include <QImageReader> #include <QImageReader>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QSize> #include <QSize>
#include <QHttp> #include <QHttp>
#include <QDebug> #include <QDebug>
#include <QUrl> #include <QUrl>
#include <QImage> #include <QImage>
#include <QGLWidget>
#include <QNetworkReply> #include <QNetworkReply>
#include <QGLWidget>
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/glu.h> /* Header File For The GLU Library */
#else
#include <GL/glu.h> /* Header File For The GLU Library */
#endif
// Initialize statics // Initialize statics
QSemaphore* StelTexture::maxLoadThreadSemaphore = new QSemaphore(5); QSemaphore* StelTexture::maxLoadThreadSemaphore = new QSemaphore(5);
/************************************************************************* // Class used to load an image and set the texture parameters in a thread
Class used to load an image and set the texture parameters in a thread
*************************************************************************/
class ImageLoadThread : public QThread class ImageLoadThread : public QThread
{ {
public: public:
ImageLoadThread(StelTexture* tex) : QThread((QObject*)tex), texture(tex) {;} ImageLoadThread(StelTexture* tex) : QThread((QObject*)tex), texture(tex) {;}
virtual void run(); virtual void run();
private: private:
StelTexture* texture; StelTexture* texture;
}; };
void ImageLoadThread::run() void ImageLoadThread::run()
{ {
StelTexture::maxLoadThreadSemaphore->acquire(1); StelTexture::maxLoadThreadSemaphore->acquire(1);
texture->imageLoad(); texture->imageLoad();
StelTexture::maxLoadThreadSemaphore->release(1); StelTexture::maxLoadThreadSemaphore->release(1);
} }
/*************************************************************************
Constructor
*************************************************************************/
StelTexture::StelTexture() : httpReply(NULL), loadThread(NULL), downloaded( false), isLoadingImage(false), StelTexture::StelTexture() : httpReply(NULL), loadThread(NULL), downloaded( false), isLoadingImage(false),
errorOccured(false), id(0), avgLuminance( -1.f), texels(NULL), type(GL_UNSIGNED_BYTE) errorOccured(false), id(0), avgLuminance( -1.f)
{ {
mutex = new QMutex(); mutex = new QMutex();
texCoordinates[0].set(1., 0.);
texCoordinates[1].set(0., 0.);
texCoordinates[2].set(1., 1.);
texCoordinates[3].set(0., 1.);
width = -1; width = -1;
height = -1; height = -1;
} }
StelTexture::~StelTexture() StelTexture::~StelTexture()
{ {
if (httpReply || (loadThread && loadThread->isRunning())) if (httpReply || (loadThread && loadThread->isRunning()))
{ {
reportError("Aborted (texture deleted)"); reportError("Aborted (texture deleted)");
} }
skipping to change at line 108 skipping to change at line 94
httpReply = NULL; httpReply = NULL;
} }
if (loadThread && loadThread->isRunning()) if (loadThread && loadThread->isRunning())
{ {
// The thread is currently running, it needs to be properly stopped // The thread is currently running, it needs to be properly stopped
loadThread->terminate(); loadThread->terminate();
loadThread->wait(500); loadThread->wait(500);
} }
if (texels)
TexMalloc::free(texels);
texels = NULL;
if (id!=0) if (id!=0)
{ {
if (glIsTexture(id)==GL_FALSE) if (glIsTexture(id)==GL_FALSE)
{ {
qDebug() << "WARNING: in StelTexture::~StelTexture() tried to delete invalid texture with ID=" << id << " Current GL ERROR stat us is " << glGetError(); qDebug() << "WARNING: in StelTexture::~StelTexture() tried to delete invalid texture with ID=" << id << " Current GL ERROR stat us is " << glGetError();
} }
else else
{ {
glDeleteTextures(1, &id); StelMainGraphicsView::getInstance().getOpenGLWin()-> deleteTexture(id);
} }
id = 0; id = 0;
} }
delete mutex; delete mutex;
mutex = NULL; mutex = NULL;
} }
/************************************************************************* /*************************************************************************
This method should be called if the texture loading failed for any reasons This method should be called if the texture loading failed for any reasons
*************************************************************************/ *************************************************************************/
skipping to change at line 146 skipping to change at line 129
} }
/************************************************************************* /*************************************************************************
Bind the texture so that it can be used for openGL drawing (calls glBindTe xture) Bind the texture so that it can be used for openGL drawing (calls glBindTe xture)
*************************************************************************/ *************************************************************************/
bool StelTexture::bind() bool StelTexture::bind()
{ {
if (id!=0) if (id!=0)
{ {
// The texture is already fully loaded, just bind and return true; // The texture is already fully loaded, just bind and return true;
StelApp::makeMainGLContextCurrent();
#ifdef USE_OPENGL_ES2
glActiveTexture(GL_TEXTURE0);
#endif
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
return true; return true;
} }
if (errorOccured) if (errorOccured)
return false; return false;
// The texture is not yet fully loaded // The texture is not yet fully loaded
if (downloaded==false && httpReply==NULL && fullPath.startsWith("htt p://")) if (downloaded==false && httpReply==NULL && fullPath.startsWith("htt p://"))
{ {
// We need to start download // We need to start download
QNetworkRequest req = QNetworkRequest(QUrl(fullPath)); QNetworkRequest req = QNetworkRequest(QUrl(fullPath));
// Define that preference should be given to cached files (n o etag checks) // Define that preference should be given to cached files (n o etag checks)
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
req.setRawHeader("User-Agent", StelApp::getApplicationName() .toAscii()); req.setRawHeader("User-Agent", StelUtils::getApplicationName ().toAscii());
httpReply = StelApp::getInstance().getNetworkAccessManager() ->get(req); httpReply = StelApp::getInstance().getNetworkAccessManager() ->get(req);
connect(httpReply, SIGNAL(finished()), this, SLOT(downloadFi nished())); connect(httpReply, SIGNAL(finished()), this, SLOT(downloadFi nished()));
return false; return false;
} }
// From this point we assume that fullPath is valid // From this point we assume that fullPath is valid
// Start loading the image in a thread and return imediately // Start loading the image in a thread and return imediately
if (!isLoadingImage && downloaded==true) if (!isLoadingImage && downloaded==true)
{ {
isLoadingImage = true; isLoadingImage = true;
skipping to change at line 192 skipping to change at line 179
downloadedData = httpReply->readAll(); downloadedData = httpReply->readAll();
downloaded=true; downloaded=true;
if (httpReply->error()!=QNetworkReply::NoError || errorOccured) if (httpReply->error()!=QNetworkReply::NoError || errorOccured)
{ {
if (httpReply->error()!=QNetworkReply::OperationCanceledErro r) if (httpReply->error()!=QNetworkReply::OperationCanceledErro r)
qWarning() << "Texture download failed for " + fullP ath+ ": " + httpReply->errorString(); qWarning() << "Texture download failed for " + fullP ath+ ": " + httpReply->errorString();
errorOccured = true; errorOccured = true;
} }
httpReply->deleteLater(); httpReply->deleteLater();
httpReply=NULL; httpReply=NULL;
// Call bind to activate data loading
//bind();
} }
/************************************************************************* /*************************************************************************
Called when the file loading thread has terminated Called when the file loading thread has terminated
*************************************************************************/ *************************************************************************/
void StelTexture::fileLoadFinished() void StelTexture::fileLoadFinished()
{ {
glLoad(); glLoad();
} }
/************************************************************************* /*************************************************************************
Return the average texture luminance, 0 is black, 1 is white
*************************************************************************/
bool StelTexture::getAverageLuminance(float& lum)
{
if (id==0)
return false;
QMutexLocker lock(mutex);
if (avgLuminance<0)
{
int size = width*height;
glBindTexture(GL_TEXTURE_2D, id);
GLfloat* p = (GLfloat*)calloc(size, sizeof(GLfloat));
Q_ASSERT(p);
glGetTexImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_FLOAT, p);
float sum = 0.f;
for (int i=0;i<size;++i)
{
sum += p[i];
}
free(p);
avgLuminance = sum/size;
}
lum = avgLuminance;
return true;
}
/*************************************************************************
Return the width and heigth of the texture in pixels Return the width and heigth of the texture in pixels
*************************************************************************/ *************************************************************************/
bool StelTexture::getDimensions(int &awidth, int &aheight) bool StelTexture::getDimensions(int &awidth, int &aheight)
{ {
QMutexLocker lock(mutex);
if (width<0 || height<0) if (width<0 || height<0)
{ {
// Try to get the size from the file without loading data // Try to get the size from the file without loading data
QImageReader im(fullPath); QImageReader im(fullPath);
if (!im.canRead()) if (!im.canRead())
{ {
return false; return false;
} }
QSize size = im.size(); QSize size = im.size();
width = size.width(); width = size.width();
height = size.height(); height = size.height();
} }
awidth = width; awidth = width;
aheight = height; aheight = height;
return true; return true;
} }
/************************************************************************* // Load the image data
Load the image data
*************************************************************************/
bool StelTexture::imageLoad() bool StelTexture::imageLoad()
{ {
bool res=true;
if (downloadedData.isEmpty()) if (downloadedData.isEmpty())
{ {
// Load the data from the file // Load the data from the file
QMutexLocker lock(mutex); QMutexLocker lock(mutex);
res = StelApp::getInstance().getTextureManager().loadImage(t his); qImage = QImage(fullPath);
} }
else else
{ {
// Load the image from the buffer, not from a file qImage = QImage::fromData(downloadedData);
if (fullPath.endsWith(".jpg", Qt::CaseInsensitive) || fullPa
th.endsWith(".jpeg", Qt::CaseInsensitive))
{
// Special case optimized for loading jpeg
// Could be even more optimized by re-using the texe
ls buffers instead of allocating one for each textures
ImageLoader::TexInfo texInfo;
res = JpgLoader::loadFromMemory(downloadedData, texI
nfo);
if (!res)
return false;
{
QMutexLocker lock(mutex);
format = texInfo.format;
width = texInfo.width;
height = texInfo.height;
type = GL_UNSIGNED_BYTE;
internalFormat = texInfo.internalFormat;
texels = texInfo.texels;
}
}
else
{
// Use Qt QImage which is slower but works for many
formats
// This is quite slow because Qt allocates twice the
memory and needs to swap from ARGB to RGBA
qImage = QGLWidget::convertToGLFormat(QImage::fromDa
ta(downloadedData));
// Update texture parameters from loaded image
{
QMutexLocker lock(mutex);
format = GL_RGBA;
width = qImage.width();
height = qImage.height();
type = GL_UNSIGNED_BYTE;
internalFormat = 4;
}
}
// Release the memory // Release the memory
downloadedData = QByteArray(); downloadedData = QByteArray();
} }
return res; return !qImage.isNull();
} }
/************************************************************************* // Actually load the texture to openGL memory
Actually load the texture already in the RAM to openGL memory
*************************************************************************/
bool StelTexture::glLoad() bool StelTexture::glLoad()
{ {
if (qImage.isNull() && !texels) if (qImage.isNull())
{ {
errorOccured = true; errorOccured = true;
reportError("Unknown error"); reportError("Unknown error");
return false; return false;
} }
// generate texture #ifdef USE_OPENGL_ES2
glGenTextures (1, &id); glActiveTexture(GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, id); #endif
// setup some parameters for texture filters and mipmapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
if (!qImage.isNull())
{
// Load from qImage
if (mipmapsMode==true)
gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, wid
th, height, format, type, qImage.bits());
else
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width
, height, 0, format, type, qImage.bits());
// Release shared memory QGLContext::BindOptions opt = QGLContext::InvertedYBindOption;
qImage = QImage(); if (loadParams.filtering==GL_LINEAR)
opt |= QGLContext::LinearFilteringBindOption;
// Mipmap seems to be pretty buggy on windows..
#ifndef Q_OS_WIN
if (loadParams.generateMipmaps==true)
opt |= QGLContext::MipmapBindOption;
#endif
GLint glformat;
if (qImage.isGrayscale())
{
glformat = qImage.hasAlphaChannel() ? GL_LUMINANCE_ALPHA : G
L_LUMINANCE;
} }
else else if (qImage.hasAlphaChannel())
{ {
// Fixed the bug which caused shifted loading for LUMINANCE glformat = GL_RGBA;
images with non multiple of 4 widths! }
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); else
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glformat = GL_RGB;
id = StelMainGraphicsView::getInstance().getOpenGLWin()->bindTexture
// Load from texels buffer (qImage, GL_TEXTURE_2D, glformat, opt);
if (mipmapsMode==true) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, loadParams.wrapMod
gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, wid e);
th, height, format, type, texels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, loadParams.wrapMod
else e);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width
, height, 0, format, type, texels);
glPopClientAttrib(); StelApp::makeMainGLContextCurrent();
// OpenGL has its own copy of texture data // Release shared memory
TexMalloc::free (texels); qImage = QImage();
texels = NULL;
}
// Report success of texture loading // Report success of texture loading
emit(loadingProcessFinished(false)); emit(loadingProcessFinished(false));
return true; return true;
} }
 End of changes. 30 change blocks. 
151 lines changed or deleted 51 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/