glGenTextures工作,但每次返回相同的纹理名称 [英] glGenTextures works but returns the same texture name every single time

查看:969
本文介绍了glGenTextures工作,但每次返回相同的纹理名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 Texture 的类。这个类负责管理纹理。在程序启动时,OpenGL上下文被正确初始化(这是什么使得这个问题不同于最常见的glGenTextures行为)。 Texture glGenTextures()获取纹理名称,然后将图像数据加载并绑定到该纹理名称的内存int函数 texGLInit()

I have a class called Texture. This class is responsible for managing a texture. In the programs startup the OpenGL context is initialised properly (which is what makes this question different from most involving unexpected glGenTextures behaviour). Texture gets a texture name from glGenTextures() and then loads and binds image data into memory for that texture name int the function texGLInit(). This works, and the texture is displayed exactly as expected.

然而,我也希望我的纹理能够改变它显示的纹理,当一个用户单击按钮并在 OpenFileDiaglog 中从HDD中选择一个按钮。这个函数叫做 reloadTexture()。此功能尝试从存储器中删除旧的图像/像素数据,并用来自用户选择的文件的新数据替换它。
然而,当这种情况发生时,它使用 glDeleteTextures 删除纹理名称,然后分配一个新的纹理名称,并使用函数 texGLInit()。但是纹理名称与100之前的(通常为1)完全相同。

However, I also want my Texture to be able to change the texture that it displays when a user clicks a button and selects one from the HDD in an OpenFileDiaglog. The function for this is called reloadTexture(). This function attempts to delete the old image/pixel data from memory and replace it with new data from a file selected by the user. However when this happens, it deletes the texture name using glDeleteTextures, and then assigns a new texture name and loads the new pixel data into memory using the function texGLInit(). But the texture name is exactly the same as the one before (usually '1') 100% of the time.

此后显示的图像是奇数。它有新的图像尺寸,但仍然是旧的图像像素。简单地说,它扭曲旧的图像下降到新的图像大小。它仍然使用假设删除的像素数据绘图。应该发生的是,屏幕现在在屏幕上显示新的图像文件。我相信这是与纹理名称不是唯一的。

The image displayed after this happens is odd. It has the new images dimensions, but still the old images pixels. Put simply, it distorts the old image down to the new images size. It's still drawing using the supposedly deleted pixel data. What should happen is that the screen now displays the new image file on screen. I believe this is something to do with the texture name not being unique.

代码如下:

Texture::Texture(string filename)//---Constructor loads in the initial image. Works fine!
{
    textureID[0]=0;

    const char* fnPtr = filename.c_str(); //our image loader accepts a ptr to a char, not a string
    //printf(fnPtr);

    lodepng::load_file(buffer, fnPtr);//load the file into a buffer

    unsigned error = lodepng::decode(image,w,h,buffer);//lodepng's decode function will load the pixel data into image vector from the buffer
    //display any errors with the texture
    if(error)
    {
        cout << "\ndecoder error " << error << ": " << lodepng_error_text(error) <<endl;
    }
    //execute the code that'll throw exceptions to do with the images size
    checkPOT(w);
    checkPOT(h);


    //image now contains our pixeldata. All ready for OpenGL to do its thing

    //let's get this texture up in the video memory
    texGLInit();

    Draw_From_Corner = CENTER;  
}

void Texture::reloadTexture(string filename)//Reload texture replaces the texture name and image/pixel data bound to this texture
{
    //first and foremost clear the image and buffer vectors back down to nothing so we can start afresh 
    buffer.clear();
    image.clear();
    w = 0;
    h = 0;
    //also delete the texture name we were using before
    glDeleteTextures(1, &textureID[0]);




    const char* fnPtr = filename.c_str(); //our image loader accepts a ptr to a char, not a string
    //printf(fnPtr);

    lodepng::load_file(buffer, fnPtr);//load the file into a buffer

    unsigned error = lodepng::decode(image,w,h,buffer);//lodepng's decode function will load the pixel data into image vector from the buffer
    //display any errors with the texture
    if(error)
    {
        cout << "\ndecoder error " << error << ": " << lodepng_error_text(error) <<endl;
    }
    //execute the code that'll throw exceptions to do with the images size
    checkPOT(w);
    checkPOT(h);

    //image now contains our pixeldata. All ready for  to do its thing

    //let's get this texture up in the video memoryOpenGL
    texGLInit();

    Draw_From_Corner = CENTER;
}

void Texture::texGLInit()//Actually gets the new texture name loads the pixeldata into openGL
{
    glGenTextures(1, &textureID[0]);
    ////printf("\ntextureID = %u", textureID[0]);
    glBindTexture(GL_TEXTURE_2D, textureID[0]);//evrything we're about to do is about this texture
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    //glDisable(GL_COLOR_MATERIAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,w,h,0, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]);
    //we COULD free the image vectors memory right about now. But we'll do it when there's a need to. At the beginning of the reloadtexture func, makes sure it happens when we need it to.



}



这里是Texture类中的绘制函数。

For what it's worth here is the draw function in the Texture class.

void Texture::draw(point* origin, ANCHOR drawFrom)
{
    //let us set the DFC enum here.
    Draw_From_Corner = drawFrom;

    glEnable(GL_TEXTURE_2D);
    //printf("\nDrawing texture at (%f, %f)",centerPoint.x, centerPoint.y);
    glBindTexture(GL_TEXTURE_2D, textureID[0]);//bind the texture
    //create a quick vertex array for the primitive we're going to bind the texture to
    ////printf("TexID = %u",textureID[0]);
    GLfloat vArray[8];

#pragma region anchor switch
    switch (Draw_From_Corner)
    {
    case CENTER:

        vArray[0] = origin->x-(w/2); vArray[1] = origin->y-(h/2);//bottom left i0
        vArray[2] = origin->x-(w/2); vArray[3] = origin->y+(h/2);//top left i1
        vArray[4] = origin->x+(w/2); vArray[5] = origin->y+(h/2);//top right i2
        vArray[6] = origin->x+(w/2); vArray[7] = origin->y-(h/2);//bottom right i3
        break;

    case BOTTOMLEFT:

        vArray[0] = origin->x; vArray[1] = origin->y;//bottom left i0
        vArray[2] = origin->x; vArray[3] = origin->y+h;//top left i1
        vArray[4] = origin->x+w; vArray[5] = origin->y+h;//top right i2
        vArray[6] = origin->x+w; vArray[7] = origin->y;//bottom right i3

        break;

    case TOPLEFT:

        vArray[0] = origin->x; vArray[1] = origin->y-h;//bottom left i0
        vArray[2] = origin->x; vArray[3] = origin->y;//top left i1
        vArray[4] = origin->x+w; vArray[5] = origin->y;//top right i2
        vArray[6] = origin->x+w; vArray[7] = origin->y-h;//bottom right i3

        break;

    case TOPRIGHT:

        vArray[0] = origin->x-w; vArray[1] = origin->y-h;//bottom left i0
        vArray[2] = origin->x-w; vArray[3] = origin->y;//top left i1
        vArray[4] = origin->x; vArray[5] = origin->y;//top right i2
        vArray[6] = origin->x; vArray[7] = origin->y-h;//bottom right i3

        break;

    case BOTTOMRIGHT:

        vArray[0] = origin->x-w; vArray[1] = origin->y;//bottom left i0
        vArray[2] = origin->x-w; vArray[3] = origin->y+h;//top left i1
        vArray[4] = origin->x-h; vArray[5] = origin->y;//top right i2
        vArray[6] = origin->x; vArray[7] = origin->y;//bottom right i3

        break;

    default: //same as center

        vArray[0] = origin->x-(w/2); vArray[1] = origin->y-(h/2);//bottom left i0
        vArray[2] = origin->x-(w/2); vArray[3] = origin->y+(h/2);//top left i1
        vArray[4] = origin->x+(w/2); vArray[5] = origin->y+(h/2);//top right i2
        vArray[6] = origin->x+(w/2); vArray[7] = origin->y-(h/2);//bottom right i3

        break;


    }
#pragma  endregion          

    //create a quick texture array (we COULD create this on the heap rather than creating/destoying every cycle)
    GLfloat tArray[8] = 
    {
        //this has been tinkered with from my normal order. I think LodePNG is bringing the PD upside down. SO A QUICK FIX HERE WAS NECESSARY.
        0.0f,1.0f,//0
        0.0f,0.0f,//1
        1.0f,0.0f,//2
        1.0f,1.0f//3
    };

    //and finally.. the index array...remember, we draw in triangles....(and we'll go CW)
    GLubyte iArray[6] =
    {
        0,1,2,
        0,2,3
    };

    //Activate arrays
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    //Give openGL a pointer to our vArray and tArray
    glVertexPointer(2, GL_FLOAT, 0, &vArray[0]);
    glTexCoordPointer(2, GL_FLOAT, 0, &tArray[0]);

    //Draw it all
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, &iArray[0]);

    //glDrawArrays(GL_TRIANGLES,0,6);

    //Disable the vertex arrays
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_TEXTURE_2D);
}

任何人都可以告诉我为什么OpenGL不会加载和从新的像素我加载到它的数据?就像我说的,我怀疑这与glGenTextures没有给我一个新的纹理名称有关。

Could anybody tell me why OpenGL would not be loading and drawing from the new pixel data that I've loaded into it? Like I said, I suspect it's something to do with glGenTextures not giving me a new texture name.

推荐答案

code> glTexImage2D 并将指针传递到客户端内存。注意,文档说:

You're calling glTexImage2D and passing a pointer to client memory. Beware, the documentation says:


如果非零命名的缓冲区对象绑定到 GL_PIXEL_UNPACK_BUFFER target(参见 glBindBuffer ), data 缓冲对象的数据存储。

If a non-zero named buffer object is bound to the GL_PIXEL_UNPACK_BUFFER target (see glBindBuffer) while a texture image is specified, data is treated as a byte offset into the buffer object's data store.

您可能希望调用 glBindBuffer(GL_PIXEL_UNPACK_BUFFER,0)解除绑定任何缓冲对象只是为了安全。

You may wish to call glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) to unbind any buffer object just to be safe.

这篇关于glGenTextures工作,但每次返回相同的纹理名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆