下面的代码创建一个窗口,使用wglGetProcAddress加载一些OpenGL过程,然后在绿色背景的中心绘制一个红色方块。在我的机器上程序工作正常,但在朋友的笔记本电脑上,它在调用xglDrawArrays()时崩溃,并抱怨该函数试图取消引用0x00000000。请注意,我在朋友的机器上的xglDrawArrays指针本身是非NULL的,正如我在调试器中验证的那样。让我再次强调,错误不是由于xglDrawArrays为NULL,而是由于xglDrawArrays在内部访问NULL数据。
现在,最奇怪的是,当我改变" xglDrawArrays" to" glDrawArrays"在他的机器上,代码突然起作用。这让我怀疑这个错误是由于一些误用WGL造成的。
相关的顶点和片段着色器非常简单:
/* Vertex Shader */
attribute vec2 pos;
void main() {
gl_Position = vec4(pos.x, pos.y, 0, 1)
}
/* Fragment Shader */
void main() {
gl_FragColor = vec4(1, 0, 0, 1)
}
相关代码在这里:
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <gl/gl.h>
#include "glext.h"
typedef void (__stdcall *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
PFNGLCREATESHADERPROC xglCreateShader;
PFNGLSHADERSOURCEPROC xglShaderSource;
PFNGLCOMPILESHADERPROC xglCompileShader;
PFNGLGETSHADERIVPROC xglGetShaderiv;
PFNGLGETSHADERINFOLOGPROC xglGetShaderInfoLog;
PFNGLCREATEPROGRAMPROC xglCreateProgram;
PFNGLATTACHSHADERPROC xglAttachShader;
PFNGLLINKPROGRAMPROC xglLinkProgram;
PFNGLGETPROGRAMIVPROC xglGetProgramiv;
PFNGLUSEPROGRAMPROC xglUseProgram;
PFNGLGENBUFFERSPROC xglGenBuffers;
PFNGLBUFFERDATAPROC xglBufferData;
PFNGLVERTEXATTRIBPOINTERPROC xglVertexAttribPointer;
PFNGLGETATTRIBLOCATIONPROC xglGetAttribLocation;
PFNGLENABLEVERTEXATTRIBARRAYPROC xglEnableVertexAttribArray;
PFNGLDRAWARRAYSPROC xglDrawArrays;
PFNGLBINDBUFFERPROC xglBindBuffer;
void
LoadOpenGLProcs(void)
{
xglCreateShader = (void*)wglGetProcAddress("glCreateShader");
xglShaderSource = (void*)wglGetProcAddress("glShaderSource");
xglCompileShader = (void*)wglGetProcAddress("glCompileShader");
xglGetShaderiv = (void*)wglGetProcAddress("glGetShaderiv");
xglGetShaderInfoLog = (void*)wglGetProcAddress("glGetShaderInfoLog");
xglCreateProgram = (void*)wglGetProcAddress("glCreateProgram");
xglAttachShader = (void*)wglGetProcAddress("glAttachShader");
xglLinkProgram = (void*)wglGetProcAddress("glLinkProgram");
xglGetProgramiv = (void*)wglGetProcAddress("glGetProgramiv");
xglUseProgram = (void*)wglGetProcAddress("glUseProgram");
xglGenBuffers = (void*)wglGetProcAddress("glGenBuffers");
xglBufferData = (void*)wglGetProcAddress("glBufferData");
xglVertexAttribPointer = (void*)wglGetProcAddress("glVertexAttribPointer");
xglGetAttribLocation = (void*)wglGetProcAddress("glGetAttribLocation");
xglEnableVertexAttribArray = (void*)wglGetProcAddress("glEnableVertexAttribArray");
xglDrawArrays = (void*)wglGetProcAddress("glDrawArrays");
xglBindBuffer = (void*)wglGetProcAddress("glBindBuffer");
}
HGLRC openglContext;
GLuint programID;
GLint posID;
GLuint bufferID;
char*
ReadEntireFile(const wchar_t* path)
{
char* buff = malloc(1);
size_t buffSize = 1;
HANDLE fileHandle = CreateFile(
path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if( fileHandle == INVALID_HANDLE_VALUE )
{
MessageBox(NULL, L"CreateFile failed", L"ERROR", MB_OK);
exit(0);
}
while(1)
{
char ch;
BOOL success;
DWORD numBytesRead;
success = ReadFile(fileHandle, &ch, 1, &numBytesRead, NULL);
if( ! success ) {
MessageBox(NULL, L"ReadFile failed", L"ERROR", MB_OK);
exit(0);
}
if( numBytesRead == 0 )
break;
buff[buffSize-1] = ch;
buffSize++;
buff = realloc(buff, buffSize);
}
buff[buffSize-1] = 0;
return buff;
}
void
DieUponGLError(void)
{
if( glGetError() != GL_NO_ERROR )
{
MessageBox(NULL, L"glGetError returned an error", L"ERROR", MB_OK);
exit(0);
}
}
void
LoadShaders(void)
{
const char* fileData;
GLint compileStatus;
GLint linkStatus;
char errorString[1024];
GLuint vertShaderID = xglCreateShader(GL_VERTEX_SHADER);
GLuint fragShaderID = xglCreateShader(GL_FRAGMENT_SHADER);
_cprintf("vert shader id: %d\n", vertShaderID);
_cprintf("frag shader id: %d\n", fragShaderID);
fileData = ReadEntireFile(
L"C:\\Users\\myname\\Desktop\\simple.vs");
xglShaderSource(vertShaderID, 1, &fileData, NULL);
DieUponGLError();
free((void*)fileData);
fileData = ReadEntireFile(
L"C:\\Users\\myname\\Desktop\\simple.fs");
xglShaderSource(fragShaderID, 1, &fileData, NULL);
DieUponGLError();
free((void*)fileData);
xglCompileShader(vertShaderID);
xglGetShaderiv(vertShaderID, GL_COMPILE_STATUS, &compileStatus);
if( compileStatus != GL_TRUE )
{
xglGetShaderInfoLog(vertShaderID, 1024, NULL, errorString);
_cprintf("[SHADER COMPILE ERROR]\n");
_cprintf("%s\n", errorString);
MessageBox(
NULL, L"glCompileShader(vertShaderID) failed", L"ERROR", MB_OK);
exit(0);
}
xglCompileShader(fragShaderID);
xglGetShaderiv(fragShaderID, GL_COMPILE_STATUS, &compileStatus);
if( compileStatus != GL_TRUE )
{
MessageBox(
NULL, L"glCompileShader(fragShaderID) failed", L"ERROR", MB_OK);
exit(0);
}
_cprintf("vert shader compile status: %d\n", compileStatus);
_cprintf("frag shader compile status: %d\n", compileStatus);
programID = xglCreateProgram();
xglAttachShader(programID, vertShaderID);
xglAttachShader(programID, fragShaderID);
xglLinkProgram(programID);
xglGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
if( linkStatus != GL_TRUE )
{
MessageBox(
NULL, L"glLinkShader(programID) failed", L"ERROR", MB_OK);
exit(0);
}
xglUseProgram(programID);
DieUponGLError();
_cprintf("Shader program successfully linked and installed\n");
posID = xglGetAttribLocation(programID, "pos");
if( posID == -1 )
{
MessageBox(
NULL, L"glGetAttribLocation(\"pos\") failed", L"ERROR", MB_OK);
exit(0);
}
}
void
LoadGeometry(void)
{
GLfloat squarePoints[] =
{
-0.5, +0.5,
-0.5, -0.5,
+0.5, +0.5,
+0.5, -0.5
};
xglGenBuffers(1, &bufferID);
xglBindBuffer(GL_ARRAY_BUFFER, bufferID);
xglBufferData(
GL_ARRAY_BUFFER, sizeof(squarePoints), squarePoints, GL_STATIC_DRAW);
}
void
DrawGeometry(void)
{
xglBindBuffer(GL_ARRAY_BUFFER, bufferID);
xglVertexAttribPointer(posID, 2, GL_FLOAT, GL_FALSE, 0, 0);
xglEnableVertexAttribArray(posID);
xglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
double
TimeSec(void)
{
LARGE_INTEGER value;
static LARGE_INTEGER freq;
static BOOL firstRun = TRUE;
if( firstRun )
{
firstRun = FALSE;
QueryPerformanceFrequency(&freq);
}
QueryPerformanceCounter(&value);
return (double)value.QuadPart / (double)freq.QuadPart;
}
LRESULT CALLBACK MainWindowProc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
if( msg == WM_DESTROY )
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
int
WINAPI
WinMain(
HINSTANCE appInstance,
HINSTANCE prevAppInstance,
LPSTR lpCmdLine,
int showCmd)
{
MSG msg;
HWND win;
WNDCLASSEX cls;
HDC dc;
GLuint pixelFormatID;
PIXELFORMATDESCRIPTOR pixelFormatDescriptor =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, // cColorBits
0, // cRedBits
0, // cRedShift
0, // cGreenBits
0, // cGreenShift
0, // cBlueBits
0, // cBlueShift
0, // cAlphaBits
0, // cAlphaShift
0, // cAccumBits
0, // cAccumRedBits
0, // cAccumGreenBits
0, // cAccumBlueBits
0, // cAccumAlphaBits
24, // Size of the depth buffer (in bits)
0, // Size of stencil buffer (in bits)
0, // Number of aux buffers
0, // iLayerType (ignored)
0, // bReserved
0, // dwLayerMask (ignored)
0, // dwVisibleMask (0 means black)
0 // dwDamageMask (ignored)
};
cls.cbSize = sizeof(cls);
cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
cls.lpfnWndProc = MainWindowProc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = appInstance;
cls.hIcon = NULL;
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
cls.lpszMenuName = L"MainMenu";
cls.lpszClassName = L"MainWindowClass";
cls.hIconSm = NULL;
if( RegisterClassEx(&cls) == 0 )
{
MessageBox(NULL, L"RegisterClassEx failed", L"ERROR", MB_OK);
return 0;
}
win = CreateWindowEx(
0,
L"MainWindowClass",
L"Main Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
NULL,
NULL,
appInstance,
NULL);
if( win == NULL )
{
MessageBox(NULL, L"CreateWindowEx failed", L"ERROR", MB_OK);
return 0;
}
dc = GetDC(win);
if( dc == NULL )
{
MessageBox(NULL, L"GetDC() failed", L"ERROR", MB_OK);
return 0;
}
pixelFormatID = ChoosePixelFormat(dc, &pixelFormatDescriptor);
if (pixelFormatID == 0 )
{
MessageBox(NULL, L"ChoosePixelFormat() failed", L"ERROR", MB_OK);
return 0;
}
if( ! SetPixelFormat(dc, pixelFormatID, &pixelFormatDescriptor) )
{
MessageBox(NULL, L"SetPixelFormat", L"ERROR", MB_OK);
return 0;
}
openglContext = wglCreateContext(dc);
if( openglContext == NULL )
{
MessageBox(NULL, L"wglCreateContext() failed", L"ERROR", MB_OK);
return 0;
}
if( ! wglMakeCurrent(dc, openglContext) )
{
MessageBox(NULL, L"wglMakeCurrent() failed", L"ERROR", MB_OK);
return 0;
}
ShowWindow(win, showCmd);
AllocConsole();
_cprintf("GL_VERSION: %s\n", glGetString(GL_VERSION));
LoadOpenGLProcs();
LoadShaders();
LoadGeometry();
DieUponGLError();
while(1)
{
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
DrawGeometry();
SwapBuffers(dc);
}
return 0;
}
最后,我使用的glext.h文件就在这里:glxext.h
答案 0 :(得分:0)
首先,wglGetProcAddress
如果你要求的功能不是微软软件的'扩展',那么DrawElements
可能会返回NULL(这是 - 高于GL 1.1的所有内容; APIENTRY
不在上面)。
其次,您需要将函数类型定义为typedef void (APIENTRY *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
,例如:
{{1}}
最后,如果你有权访问调试器,为什么不至少附加stacktrace?