I'm coding a college assignment in which I need to create an openGL scene using Textures/Materials. My idea is to allow the user to decide whether to use Textures or Materials (note that this is already implemented) however, the loading of the Texture images takes too long, which makes the whole scene to hault when launching until they are all loaded up. I would like to load the images from the disk in some way (maybe threads? although I read this was not possible) while the scene is rendered with Materials, so the scene can load faster. My code for loading the Texture images looks like this:
Texture imgGold;
imgGold.initTexture("resources/textures/gold/gold.png");
And the initTexture function is provided by the teacher (we can change it tho). The Texture.cpp file looks like this:
#include "Texture.h"
//------------------------
// Crea la textura
//------------------------
void Texture::initTexture(const char *textureFile) {
// Creamos la textura a configurar
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Cargamos la imagen
unsigned int w, h;
unsigned char *pixels = loadTexture(textureFile, w, h);
// Creamos la textura
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixels);
glGenerateMipmap(GL_TEXTURE_2D);
// Configuramos la textura (GL_REPEAT repite textura; GL_CLAMP no, GL_LINEAR y tal mirar la teoria)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
float aniso;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
}
//--------------------------------------------------
// Carga una textura mediante la librería Freeimage
//--------------------------------------------------
unsigned char* Texture::loadTexture(const char *textureFile, unsigned int &w, unsigned int &h) {
FreeImage_Initialise(TRUE);
// Leemos la textura
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(textureFile,0);
if(format==FIF_UNKNOWN) format = FreeImage_GetFIFFromFilename(textureFile);
if((format==FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(format)) {
std::cout << "Formato de la textura " << textureFile << " no está soportado." << std::endl;
std::cin.get();
exit(1);
}
FIBITMAP *texture = FreeImage_Load(format,textureFile);
if(texture==NULL) {
std::cout << "El fichero " << textureFile << " no se puede abrir." << std::endl;
std::cin.get();
exit(1);
}
FIBITMAP *temp = texture;
texture = FreeImage_ConvertTo32Bits(texture);
FreeImage_Unload(temp);
// De BGRA a RGBA
w = FreeImage_GetWidth(texture);
h = FreeImage_GetHeight(texture);
unsigned char *pixelsBGRA = (unsigned char *)FreeImage_GetBits(texture);
unsigned char *pixelsRGBA = new unsigned char[4*w*h];
for(int j=0; j<w*h; j++){
pixelsRGBA[j*4+0] = pixelsBGRA[j*4+2];
pixelsRGBA[j*4+1] = pixelsBGRA[j*4+1];
pixelsRGBA[j*4+2] = pixelsBGRA[j*4+0];
pixelsRGBA[j*4+3] = pixelsBGRA[j*4+3];
}
FreeImage_Unload(texture);
FreeImage_DeInitialise();
return pixelsRGBA;
}
//-----------------------------------------
// Devuelve el identificador de la textura
//-----------------------------------------
unsigned int Texture::getTexture() {
return texture;
}
//-----------------------
// Destructor de la clase
//-----------------------
Texture::~Texture() {
glDeleteTextures(1,&texture);
}
and Texture.h looks like this:
#ifndef TEXTURE_H
#define TEXTURE_H
#include <iostream>
#include <GL/glew.h>
#include <FreeImage.h>
class Texture {
public:
void initTexture(const char *textureFile);
unsigned int getTexture();
virtual ~Texture();
private:
unsigned int texture;
unsigned char *loadTexture(const char *textureFile, unsigned int &w, unsigned int &h);
};
#endif /* TEXTURE_H */
Note: Once loaded, the images are used to create a Textures object, which looks like this:
struct Textures {
unsigned int diffuse;
unsigned int specular;
unsigned int emissive;
unsigned int normal;
float shininess;
};
This was also provided by our teacher.
How can I achieve this?
I tried calling a new thread when I load the Texture images but nothing was loaded.
In order to use multiple threads, you'll need multiple contexts bound (make current) to a specific thread. Most of the OpenGL objects (textures are one of them) can be shared among different contexts.
In EGL you would use the following operations:
To create a (shared) context
To make a context current on a thread
After that you're free to create/load a texture in one thread/context and use it in another thread/context.
If you're not able to use multiple contexts, then load the image data (e.g. from disk) from another thread and then create a texture and upload the data in the thread, where the context is bound to.
In your case, that would mean, that you call the
loadTexturefunction from another thread and leave the rest in the thread where the context is bound to.Reference