C++ glGenTextures可以工作,但每次都返回相同的纹理名称
我有一个叫做C++ glGenTextures可以工作,但每次都返回相同的纹理名称,c++,opengl,C++,Opengl,我有一个叫做Texture的类。此类负责管理纹理。在程序启动时,OpenGL上下文被正确初始化(这使得这个问题不同于大多数涉及意外GlgenTexture行为的问题)纹理从glGenTextures()获取纹理名称,然后在函数texGLInit()中将该纹理名称的图像数据加载并绑定到内存中。 这可以工作,并且纹理的显示完全符合预期 但是,我还希望我的纹理能够更改当用户单击按钮并从OpenFileDiaglog中的硬盘中选择一个按钮时显示的纹理。此函数称为reloadTexture()。此函数尝试
Texture
的类。此类负责管理纹理。在程序启动时,OpenGL上下文被正确初始化(这使得这个问题不同于大多数涉及意外GlgenTexture行为的问题)<代码>纹理从glGenTextures()
获取纹理名称,然后在函数texGLInit()
中将该纹理名称的图像数据加载并绑定到内存中。
这可以工作,并且纹理的显示完全符合预期
但是,我还希望我的纹理能够更改当用户单击按钮并从OpenFileDiaglog
中的硬盘中选择一个按钮时显示的纹理。此函数称为reloadTexture()
。此函数尝试从内存中删除旧图像/像素数据,并用用户选择的文件中的新数据替换。
但是,当发生这种情况时,它会使用gldeleteetextures
删除纹理名称,然后指定一个新的纹理名称,并使用函数texGLInit()
将新的像素数据加载到内存中。但纹理名称在100%的情况下与之前的名称完全相同(通常为“1”)
发生这种情况后显示的图像是奇数。它有新的图像尺寸,但仍然是旧的图像像素。简单地说,它将旧图像扭曲为新图像的大小。它仍在使用假定已删除的像素数据进行绘制。应该发生的是,屏幕现在在屏幕上显示新的图像文件。我相信这与纹理名称不唯一有关
代码包括以下内容:
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.
}
有谁能告诉我为什么OpenGL不会从我加载到其中的新像素数据中加载和绘制?正如我所说,我怀疑这与glGenTextures没有给我一个新的纹理名称有关。您正在调用
glTexImage2D
并传递指向客户端内存的指针。注意,文件上说:
如果在指定纹理图像时将非零命名缓冲区对象绑定到GL\u PIXEL\u UNPACK\u buffer
目标(请参见glBindBuffer
),则数据将被视为缓冲区对象数据存储中的字节偏移量
您可能希望调用glBindBuffer(GL\u PIXEL\u UNPACK\u BUFFER,0)
解除任何缓冲区对象的绑定,以确保安全。我看不出glGenTextures给您旧的纹理名称有任何问题。它明确地说:“删除纹理后,它没有内容或维度,其名称可以自由重用(例如由glGenTextures)。我不明白为什么textureID是数组。嗯,是的,它是有效的…但是…为什么?简单变量有什么问题?@datenwolf我以前使用简单的GLUint,当我看到其他人在示例中使用数组时,我尝试使用数组。毕竟,文档确实说第二个参数指定了一个数组。我只是还没有调回::@dfan我可能应该提到。我还尝试过从构造中创建一个全新的纹理,即不使用myTex->reloadTexture(filename.png)
,而只使用myTex=new texture(filename.png)
。这在任何时候都不会调用glDeleteTextures。我仍然得到了相同的纹理名称(1
)。@GuyJoelMcLean:C中的单个变量可以被视为0维数组,即只有一个元素的数组。您建议在尝试重新绑定之前执行此操作吗?@Guy:No,我会在glTexImage2D(…,&image[0])之前使用该调用
,以确保OpenGL不会在某个绑定缓冲区中查找像素数据,而不是从图像
数组中读取。我终于让glew的东西开始工作了。但是,如上所述使用的glBindBuffer会导致崩溃<代码>Spritey.exe中发生“System.AccessViolationException”类型的未处理异常。其他信息:尝试读取或写入受保护内存。这通常表示其他内存已损坏。
我很确定我这次没有使用对象取消分配任何内存。@Guy:Ahh然后您有一些代码使用像素缓冲区,一些代码使用客户端内存中的数组。您需要调用glBindBuffer
根据需要来回切换。在您的代码中查找其他glBindBuffer
调用。我只有您建议的一个。我必须包含glew库并创建一个指向.lib文件的路径,以便VisualStudio链接到它。您知道openGL中还有其他调用与glBindBuffer做类似的事情吗。
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);
}