I’ve been writing OpenGL programs for many years and I’ve used texturing successfully in the past but I’ve run into a bug that I can not figure out. I’m converting a rendering engine that I wrote in python(with pyglet) to c++(GL/SDL/Magick++/Boost) and I’m having a problem with textures.
It seems that each time I create a texture it overwrites all the data of previous textures. So that no matter which texture I bind they all look like the most recently created texture. I have confirmed that I’m using different GLuints created by glGenTexture and I have confirmed that the correct texture id is bound when the texture data is attached.
Has this happened to anyone? And ideas on what I’m doing wrong?
[captain obvious]
Seeing srccode of working tutorials will show you the bug
[/captain obvious]
Thankyou very little…
There must be an error in your code somewhere. A bug as huge could have never appear in production drivers.
My question is, assuming I am dealing with multiple texture units, how could I accidentally overwrite the pixel data of one texture with the pixel data of a subsequently loaded texture?
Anyone have a clue?
Your problem is strange, a piece of code may help us. At the moment, I see only two ways to replace (not erase) a texture data, bind this one and call glTexImage*, glCopyTexImage*, glCopyTexSubImage*, drawing to texture using fbos or using pbos.
Tell us what hardware, driver version and OS you are using.
I think the following code is all the relevant stuff. The “equivalent” code works perfectly in python(with pyglet) on the same system. I’m running ubuntu(hardy) on a core2 duo with a modern nvidia card with the newest possible drivers.
Sorry for the messiness of the code…
#include <iostream>
#include <sstream>
#include <GL/glew.h>
#include "Texture.hpp"
Texture::KeyIndexedTextures Texture::__texture_registry;
Texture::BoundMap Texture::__current_texture;
Texture::ModeMap Texture::__mode_to_glmode;
const unsigned Texture::REPEAT(1);
const unsigned Texture::NO_MIPMAP(2);
Texture::Texture():
__width(0)
,__height(0)
,__mode("NONE")
,__flags(0)
,__dimension(GL_TEXTURE_2D)
,__texture_id(0)
{
return;
}
Texture::Texture(const Texture& other):
__width(other.__width)
,__height(other.__height)
,__mode(other.__mode)
,__flags(other.__flags)
,__dimension(other.__dimension)
,__texture_id(other.__texture_id)
{
return;
}
Texture::Texture(const GLvoid* data
,unsigned width
,unsigned height
,const std::string mode
,const unsigned flags):
__width(width)
,__height(height)
,__mode(mode)
,__flags(flags)
,__dimension(GL_TEXTURE_2D)
//__dimension = if_then_else(len(size) == 2, GL_TEXTURE_2D, GL_TEXTURE_3D)
,__texture_id(0)
{
glGenTextures(1, &__texture_id);
__set_texture_data(data);
}
Texture::~Texture()
{
//glDeleteTextures(1, &__texture_id);
//if __texture_id in Texture::__texture_registry.values():
//for n, id in Texture::__texture_registry.iteritems():
//if id == __texture_id:
//del Texture::__texture_registry[n]
}
/* static */
void Texture::init()
{
Texture::__current_texture[GL_TEXTURE0] = 0;
Texture::__current_texture[GL_TEXTURE1] = 0;
Texture::__current_texture[GL_TEXTURE2] = 0;
Texture::__current_texture[GL_TEXTURE3] = 0;
Texture::__current_texture[GL_TEXTURE4] = 0;
Texture::__current_texture[GL_TEXTURE5] = 0;
Texture::__current_texture[GL_TEXTURE6] = 0;
Texture::__current_texture[GL_TEXTURE7] = 0;
Texture::__mode_to_glmode["RGB"] = GL_RGB;
Texture::__mode_to_glmode["RGBA"] = GL_RGBA;
Texture::__mode_to_glmode["L"] = GL_LUMINANCE;
Texture::__mode_to_glmode["LA"] = GL_LUMINANCE_ALPHA;
}
void Texture::__set_texture_data(const GLvoid* data)
{
bind();
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//if(__dimension == GL_TEXTURE_2D) {
glTexImage2D(GL_TEXTURE_2D
,0
,__mode.length()
,__width
,__height
,0
,__mode_to_glmode[__mode]
,GL_UNSIGNED_BYTE
,data);
//} else if(__dimension == GL_TEXTURE_3D) {
//std::cout << "Building 3D texture..." << __size << std::endl;
//for i, d, size in data:
//glTexImage3D(GL_TEXTURE_3D, i, len(__mode), \
size[0], size[1], size[2], 0, \
__mode_to_glmode[__mode], GL_UNSIGNED_BYTE, d)
//} else {
//std::cerr << "ERROR: Invalid texture dimension!" << __dimension << std::endl;
//}
glTexParameterf(__dimension, GL_TEXTURE_WRAP_S, __flags & Texture::REPEAT ? GL_REPEAT : GL_CLAMP);
glTexParameterf(__dimension, GL_TEXTURE_WRAP_T, __flags & Texture::REPEAT ? GL_REPEAT : GL_CLAMP);
//if 'no mipmap' not in __flags and __dimension == GL_TEXTURE_2D:
glTexParameterf(__dimension, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(__dimension, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameterf(__dimension, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
//gluBuild2DMipmaps(GL_TEXTURE_2D, __mode_to_glmode[__mode],
//__width, __height, __mode_to_glmode[__mode],
//GL_UNSIGNED_BYTE, data );
//else:
//glTexParameterf(__dimension, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
done();
}
void Texture::reset_image(Magick::Image& image)
{
Magick::Blob blob;
image.write(&blob, "RGBA");
__set_texture_data(blob.data());
}
void Texture::bind(unsigned number)
{
if(Texture::__current_texture[number] == __texture_id) {
return; //# The texture is already bound
}
glActiveTexture(number);
glEnable( __dimension );
glBindTexture(__dimension, __texture_id);
Texture::__current_texture[number] = __texture_id;
}
void Texture::done(unsigned number)
{
//std::cout << "Done texture " << number << " " << __dimension << " " << __texture_id << "
";
glActiveTexture(number);
glDisable(__dimension );
Texture::__current_texture[number] = 0;
}
/* static */
void Texture::reset()
{
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D );
}
/* static */
void Texture::disable()
{
glActiveTexture(GL_TEXTURE0);
glDisable( GL_TEXTURE_2D );
glDisable( GL_TEXTURE_3D );
}
/* static */
std::string Texture::__make_key(std::string pref, unsigned flags)
{
std::stringstream ss;
ss << pref << flags;
return ss.str();
}
/* static */
Texture::Ptr Texture::from_file(std::string file,
unsigned flags,
boost::filesystem::path prefix)
{
std::string key = Texture::__make_key(file, flags);
if(Texture::__texture_registry.find(key) != Texture::__texture_registry.end()) {
return Texture::__texture_registry[key];
}
Magick::Image image((prefix /= file).string().c_str());
return Texture::from_image(image, file, flags);
}
/* static */
Texture::Ptr Texture::from_image(Magick::Image& image,
std::string prekey,
unsigned flags)
{
std::string key(Texture::__make_key(prekey, flags));
if(Texture::__texture_registry.find(key) != Texture::__texture_registry.end()) {
return Texture::__texture_registry[key];
}
Magick::Blob blob;
image.write(&blob, "RGBA");
Texture::__texture_registry[key] = Texture::Ptr(new Texture(blob.data(), image.columns(), image.rows(), "RGBA", flags));
return Texture::__texture_registry[key];
}
From opengl.h:
#define GL_TEXTURE0 0x84C0
From your code:
Texture::__current_texture[GL_TEXTURE0] = 0;
void Texture::bind(unsigned number){…} // here, what is the default value? Is it a number between 0…7 or is it GL_TEXTURE0?
I’d say the culprit is somewhere in your code, where you call Texture::bind(int WrongValue).
Btw, very scripty code… Maybe access to some of those maps (instead of arrays) got incorrectly ported to C++.
void Texture::bind(unsigned number){…} // here, what is the default value? Is it a number between 0…7 or is it GL_TEXTURE0?
It’s GL_TEXTURE0.
The __current_texture map keeps track of which textures are bound for each unit, so I don’t rebind them if they’re already bound.
Yeah the code is scripty. I wanted to complete the python -> c++ port before starting to optimize and refactor. So yeah. This all worked perfectly in python… So strange.
Any more suggestions?