多次调用glGetTexImage时出现缓冲区溢出错误

时间:2013-12-06 23:13:49

标签: c++ opengl glut glfw

我正在创建一个使用OpenGL管理图像的类。 要加载图像我正在使用SOIL加载PNG。 因为我需要检查碰撞我想获得透明像素。 所以我试图使用:glGetTexImage

来获取数据

构造函数加载图像:

Image::Image(string imagePath, unsigned int flags){
    this->imagePath=imagePath;
    this->pxData=NULL;
    texture=SOIL_load_OGL_texture
    (
     imagePath.c_str(),
     SOIL_LOAD_AUTO,
     SOIL_CREATE_NEW_ID,
     flags
    );

    //Use that to subdivide in sprites the texture
    glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_WIDTH, &textureWidth);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_HEIGHT, &textureHeight);
    glBindTexture(GL_TEXTURE_2D, this->texture);
    //cout << "Real Dimensions - " << textureWidth << "-" << textureHeight;

    loadPixels(); //multiple instances of image generates error here
}

LoadPixels在我的结构中加载像素数据。

typedef struct PixelData{
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
} PixelData;
PixelData* pxData;

然后在loadPixels中存储该数据:

void Image::loadPixels(){
    pxData = new PixelData[textureHeight*textureWidth];
    glGetTexImage(GL_TEXTURE_2D, 1, GL_RGBA, GL_UNSIGNED_BYTE , pxData);
}

问题是,如果我创建一个图像:

Image img("/Developer/img.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);

工作正常。

如果我创建了很多图片:

    Image img("/Developer/img.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img2("/Developer/img2.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img3("/Developer/img3.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img4("/Developer/img4.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img5("/Developer/img5.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img6("/Developer/img6.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img7("/Developer/img7.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img8("/Developer/img8.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img9("/Developer/img9.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img10("/Developer/img10.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);

然后我的程序崩溃了:

错误是:

OpenGL Game Engine(35463,0x7fff7b121310) malloc: *** error for object 0x104017808: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

如果我评论glGetTexImage(GL_TEXTURE_2D,1,GL_RGBA,GL_UNSIGNED_BYTE,pxData);它工作正常,所以我想问题不是分配。

我只需要获取像素数据来存储它,我想使用这些像素创建一些数据,所以我需要获得纹理的像素。

注:

如果我取消注释loadPixels,程序会停止在带有sigabort的imagePath.c_str(),如果我对它进行注释,它会加载所有纹理

感谢Audrey我获得了更多信息。

glGetTexLevelParameteriv(GL_TEXTURE_2D, this->texture, GL_TEXTURE_WIDTH, &textureWidth);
glGetTexLevelParameteriv(GL_TEXTURE_2D, this->texture, GL_TEXTURE_HEIGHT, &textureHeight);

Real Dimensions - 128-128
Real Dimensions - 64-64
Real Dimensions - 32-32
Real Dimensions - 16-16

它是相同的图像,但尺寸越来越小。

我检查了ID,每次都会创建一个新ID,那么为什么尺寸会变得混乱?

是否有另一种获取数据的方法,我在这里缺少什么? 另一个问题,这个方法获取绑定纹理,有没有办法使用纹理ID获取纹理数据?

2 个答案:

答案 0 :(得分:2)

根据评论中的讨论,看起来getGlTexImage溢出了pxData缓冲区。如果您发布了给您textureWidthtextureHeight的函数输出的内容,我们可能会发现错误。 (例如,你确定getter函数的返回类型和变量textureWidth等之间的兼容性吗?)

修改:我会检查您的<Gl.h>以查看函数glGetTexLevelParametersiv的签名。我在网上浏览了一下,其中微软WINAPI版本的签名与OpenGL.org上的签名不同,并且都不同意您使用的签名。

尝试重新排序并重写:

glBindTexture(GL_TEXTURE_2D, this->texture);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &textureWidth);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &textureHeight);

答案 1 :(得分:1)

glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_HEIGHT, &textureHeight);

第二个参数不带纹理ID。这是一个mipmap级别。你需要绑定纹理 first ,然后在你放置纹理的地方调用这个函数。

具体来说,您的纹理ID几乎肯定会被实例化为“0”,“1”,“2”等...每次使用连续值调用glGetTexLevelParameteriv时,您都要求使用较小的mipmap 当前绑定纹理的级别。你的第一次电话没有失败的事实让我怀疑SOIL_load_OGL_texture实际上并没有在它返回之前解除它。

请记住,几乎没有OpenGL函数将纹理,缓冲区或着色器ID作为参数,而是作用于当前绑定的对象。您通常使用实际ID的唯一函数是创建,销毁或绑定对象的函数,例如glGenTexturesglDeleteTexturesglBindTexture