opengl glBindTexture为何失败

      半年没有写点东西总结下了。有时候脑中想法很多,却又感觉文字功底着实有限,无法把自由散漫的思想分门别类地记下来,好在可以与人交流,掏空自己,然后吸收些新东西;有时候却什么都不想,就翻翻书,享受前人的精神盛宴。

      还是写技术性的东西好,可以有章可循,写得不好,就算别人看不大懂,自己肯定是理解,若干日月后翻出来看还可以嘲笑以前的自己,知道自己走过了哪些里程碑。

      这一两年涉及太广,也没专心下了深入研究一门,最近又学了点opengl,简单记录下遇到的一些问题。

     

      虽然windows上opengl的库才1.1版本,但最后发现也够了,我只是为了一个窗口显示多通道视频而已。版本问题很麻烦,因为程序手册不一样,入门去学的路径也不一样了。之前企图用最新版的4.3,更新了显卡驱动,又用了诸如glew和glut的扩展库,按照红宝书的来,却发现glsl语言相关的函数怎么也编译不过,网上资料又少,无奈,此路不通。本来,我只是写一个低层库,opengl的扩展库能不用就尽量不用,于是决定学下nehe的"legacy tutorials",窗口创建之类的虽然有点麻烦,但也能验证问题。


      我的库给别人用的,别人的工程时mfc工程,有自己窗口,如果要绘图,需要获取别人的窗口句柄和画布,创建自己的Rendering Context,这里有段代码,之前也没仔细研究,后面发现问题就出现在这上面:

bool CGLDevice::InitialWnd(HWND hwnd)
{
#ifdef WIN32

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		32,											// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};

	HDC	hDC=NULL;									// Private GDI Device Context
	GLuint		PixelFormat;						// Holds The Results After Searching For A Match

	if (!(hDC=GetDC(hwnd)))							// Did We Get A Device Context?
	{
		return false;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{						
		return false;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{							
		return false;								// Return FALSE
	}

	if (!(m_hrc=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{							
		return false;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,m_hrc))					// Try To Activate The Rendering Context
	{							
		return false;								// Return FALSE
	}

	//ShowWindow (hwnd, SW_NORMAL);								// Make The Window Visible


#endif

	return true;
}

这段代码如果使用glut的话很简单,几行搞定:

	glutInitWindowPosition(400, 0);
	glutInitWindowSize(m_WindowWidth, m_WindowHeight);
	glutCreateWindow("test");
用了上面的代码,出了些摸不着头脑的问题: glGenTextures和glBindTexture失败,后来想到是不是线程的问题,把窗口、画布初始化和opengl的操作放在同一个线程才把问题解决。也不知道为什么会有这样的直觉,后来研究了这段代码,发现原因:

wglMakeCurrent——The wglMakeCurrent function makes a specified OpenGL rendering context the calling thread's current rendering context.这个函数是把调用该函数的线程的渲染环境指定为opengl的渲染环境。原来如此,果然是线程相关的。


另外还有一些小细节,比如RGB转到YUV后,是要把top和bottom颠倒的:在做这样的一段输出图片的操作前交换坐标

			float tmp;
			tmp = m_SurfaceStruct.SourceRectF.top;
			m_SurfaceStruct.SourceRectF.top = m_SurfaceStruct.SourceRectF.bottom;
			m_SurfaceStruct.SourceRectF.bottom = tmp;
			glTexCoord2f(m_SurfaceStruct.SourceRectF.left, m_SurfaceStruct.SourceRectF.bottom); 
			glVertex2f(m_SurfaceStruct.ViewRectF.left, m_SurfaceStruct.ViewRectF.bottom);

			glTexCoord2f(m_SurfaceStruct.SourceRectF.right, m_SurfaceStruct.SourceRectF.bottom); 
			glVertex2f(m_SurfaceStruct.ViewRectF.right, m_SurfaceStruct.ViewRectF.bottom);

			glTexCoord2f(m_SurfaceStruct.SourceRectF.right, m_SurfaceStruct.SourceRectF.top); 
			glVertex2f(m_SurfaceStruct.ViewRectF.right, m_SurfaceStruct.ViewRectF.top);

			glTexCoord2f(m_SurfaceStruct.SourceRectF.left, m_SurfaceStruct.SourceRectF.top); 
			glVertex2f(m_SurfaceStruct.ViewRectF.left, m_SurfaceStruct.ViewRectF.top);


下面贴一段windows平台的测试程序,这里直接用了glut。程序的功能是把两幅图交替显示,模拟动画的效果,且进行了简单的遮罩:

//#include "GL/glew.h"
#include "GL/glut.h"
#include <stdio.h>
#include <time.h>

static GLint     ImageWidth[4];
static GLint     ImageHeight[4];
static GLubyte*  PixelData[4] = {0};
static GLubyte*  tmpData[4] = {0};
static const GLint BMP_INFO_OFFSET = 0x0012;
static const GLint BMP_DATA_OFFSET = 0x0036;

static const unsigned short WindowWidth = 1024;
static const unsigned short WindowHeight = 768;

GLuint	Texture[4];

class KsTime
{
private:    
	__int64 m_base, m_start, m_stop;    
	bool m_print;
public:
	KsTime(bool e_print = false);         
	~KsTime();
	void restart();
	void elapsed();        
	double get_elapsed();        
	void set_print(bool e_print);
};
KsTime::KsTime(bool e_print) : m_print(e_print)
{        
	QueryPerformanceFrequency((LARGE_INTEGER *)(&m_base)); 
	restart();
}
KsTime::~KsTime() {    if (m_print) elapsed(); }
void KsTime::restart(){ QueryPerformanceCounter((LARGE_INTEGER *)(&m_start)); }
void KsTime::elapsed()
{        
	QueryPerformanceCounter((LARGE_INTEGER *)(&m_stop));
	printf("%.6f\n", (double)(m_stop - m_start) / m_base);                    
}
double KsTime::get_elapsed()
{        
	QueryPerformanceCounter((LARGE_INTEGER *)(&m_stop));
	return (double)(m_stop - m_start) / m_base;                    
}
void KsTime::set_print(bool e_print) { m_print = e_print; }

void myDisplay();

KsTime kst;
void timeFunc(int value)
{
	kst.restart();
	myDisplay();
	// 大约25fps
	int d = 40 - (int)(kst.get_elapsed()*1000);
	if (d <= 0) d = 0;
	glutTimerFunc(d, timeFunc, 0);
}

void Init()
{
	for (int i=0; i<2; i++)
	{
		glGenTextures(1, &Texture[i]);
		glBindTexture(GL_TEXTURE_2D, Texture[i]);

		//每一个都要设定
		//下面两个GL_CLAMP的设定去掉后是无缝的效果
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 

		//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth[i], ImageHeight[i], 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, PixelData[i]);// 生成空纹理

	}

	{//color fill
		glGenTextures(1, &Texture[2]);
		glBindTexture(GL_TEXTURE_2D, Texture[2]);

		//每一个都要设定
		//下面两个GL_CLAMP的设定去掉后是无缝的效果
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
	}


	glClearColor (0.0f, 0.0f, 0.0f, 0.0f);								// Black Background

	glClearDepth (1.0f);												// Depth Buffer Setup
	glDepthFunc (GL_LEQUAL);											// The Type Of Depth Testing
	glEnable (GL_DEPTH_TEST);											// Enable Depth Testing

	glEnable(GL_COLOR_MATERIAL);										// Enable Color Material (Allows Us To Tint Textures)
	//glEnable(GL_TEXTURE_2D);											// Enable Texture Mapping
}

void myDisplay()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
	//glLoadIdentity();

	static int dis = 0;
	if (dis++ % 2 == 0)
	{
		memcpy(tmpData[0], PixelData[0], ImageWidth[0]*ImageHeight[0]*3);
		memcpy(tmpData[1], PixelData[1], ImageWidth[0]*ImageHeight[0]*3);
	}
	else
	{
		memcpy(tmpData[0], PixelData[1], ImageWidth[0]*ImageHeight[0]*3);//为方便,两幅图长宽一样
		memcpy(tmpData[1], PixelData[0], ImageWidth[0]*ImageHeight[0]*3);
	}

	glEnable(GL_TEXTURE_2D);
	{//bmp1

		glBindTexture(GL_TEXTURE_2D, Texture[0]);
		if (glIsTexture(Texture[0]))
		{
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth[0], ImageHeight[0], 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, tmpData[0]);

			glBegin(GL_QUADS);											// Begin Drawing A Single Quad
			// We Fill The Entire 1/4 Section With A Single Textured Quad.
			glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, 0.0f); //把原图的坐标(glTexCoord2f)  绑定到视图坐标(glVertex2f)
			glTexCoord2f(1.0f, 0.0f); glVertex2f(0.0f, 0.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex2f(0.0f, 1.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
			glEnd();	
		}
	
	}


	{//bmp2

 		glBindTexture(GL_TEXTURE_2D, Texture[1]);
		if (glIsTexture(Texture[1]))
		{
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth[1], ImageHeight[1], 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, tmpData[1]);

			glBegin(GL_QUADS);											// Begin Drawing A Single Quad
			// We Fill The Entire 1/4 Section With A Single Textured Quad.
			glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); //把原图的坐标(glTexCoord2f)  绑定到视图坐标(glVertex2f)
			glTexCoord2f(0.5f, 0.0f); glVertex2f(1.0f, 0.0f);
			glTexCoord2f(0.5f, 0.5f); glVertex2f(1.0f, 1.0f);
			glTexCoord2f(0.0f, 0.5f); glVertex2f(0.0f, 1.0f);
			glEnd();
		}
	}

	{//color fill
		glBindTexture(GL_TEXTURE_2D, Texture[2]);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, PixelData[2]);

		glBegin(GL_QUADS);											// Begin Drawing A Single Quad
		// We Fill The Entire 1/4 Section With A Single Textured Quad.
		glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); //把原图的坐标(glTexCoord2f)  绑定到视图坐标(glVertex2f)
		glTexCoord2f(1.0f, 0.0f); glVertex2f(0.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex2f(0.0f, 0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 0.0f);
		
		glEnd();
	}

	glDisable(GL_TEXTURE_2D);

	glFlush();
	//glutSwapBuffers();
}


//读出来的BMP文件是BGR的顺序  不是RGB的顺序
int LoadImg(const char* pFileName, GLubyte*& pPixelBuf, GLubyte*& pTmpData, GLint &width, GLint &height)
{
	FILE *pFile = fopen(pFileName, "rb");
	if (!pFile)
	{
		return -1;
	}
	// 读取图像大小信息
	fseek(pFile, BMP_INFO_OFFSET, SEEK_SET);
	fread(&width, sizeof(width), 1, pFile);
	fread(&height, sizeof(height), 1, pFile);

	GLint PixelLength = width * 3;
	if (PixelLength % 4  != 0)
	{
		PixelLength += (4 - PixelLength % 4);// BMP图像是4像素对齐的
	}
	GLint count = PixelLength * height;
	pPixelBuf = new GLubyte[count];
	if (!pPixelBuf)
	{
		return -1;
	}
	pTmpData = new GLubyte[count];
	memset(pTmpData, 0, count);
	memset(pPixelBuf, 0, count);

	fseek(pFile, 0, SEEK_END);
	int ll = ftell(pFile);
	fseek(pFile, BMP_DATA_OFFSET, SEEK_SET);
	GLint Len = 0, ret = 0;
	if(count != ll - BMP_DATA_OFFSET)
	{
		return -1;
	}
	while(ret>=0 && Len < count)
	{
		if (count - Len > 1024 * 20)
		{
			ret = fread(pPixelBuf + Len, sizeof(GLubyte), 1024 * 20, pFile);
		}
		else
		{
			ret = fread(pPixelBuf + Len, sizeof(GLubyte), count - Len, pFile);
		}

		Len += ret;
		if (ret == 0)
		{
			int err = ferror(pFile);
			if (feof(pFile))
			{
				printf("file eof\n");
			}
		}
	}

	fclose(pFile);

	return 0;
}

int main(int argc, char *argv[])
{
	if (LoadImg("test.bmp", PixelData[0], tmpData[0], ImageWidth[0], ImageHeight[0]) < 0)
	{
		return 0;
	}
 	if (LoadImg("test2.bmp", PixelData[1], tmpData[1], ImageWidth[1], ImageHeight[1]) < 0)
 	{
 		return 0;
 	}
	PixelData[2] = new GLubyte[3];
	PixelData[2][0] = 0;
	PixelData[2][1] = 0;
	PixelData[2][2] = 255;
	ImageWidth[2] = 1;
	ImageHeight[2] = 1;

	int tmp;
 	glutInit(&tmp, NULL);
 	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
 	glutInitWindowPosition(400, 0);
 	glutInitWindowSize(WindowWidth, WindowHeight);
 	glutCreateWindow("test");

	const char* version = (const char*)glGetString(GL_VERSION);
 	//const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
 	printf("OpenGL 版本:%s\n", version);

	Init();
 	glutDisplayFunc(&myDisplay);

	glutTimerFunc(400, timeFunc, 0); 

 	glutMainLoop();

	for (int i=0; i<4; i++)
	{
		if (PixelData[i])
		{
			delete PixelData[i];
		}
		if (tmpData[i])
		{
			delete tmpData[i];
		}
	}

	return 0;
}

其中定时那部分的代码是网上找的,觉得很蹊跷..看了下glutTimerFunc的源码,发现glut本身是有定时器的,因此不需要上面代码中的KsTime,直接把回调函数写成这样就行:

void timeFunc(int value)
{
	myDisplay();
	glutTimerFunc(100, timeFunc, 0);
}


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页