我在检索和存储指向OpenGL函数的指针时遇到了一些麻烦,这是我的代码的“简化代码段”版本:
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
class CGLManager
{
public:
// Manager functions
bool GetAnyGLFuncAddress( const char *_cName, void *_pFunc );
bool LoadFunctions( void );
// OpenGL functions
void (APIENTRY *glBegin)( GLenum mode );
void (APIENTRY *glEnd)( void );
void (APIENTRY *glVertex3f)( GLfloat x, GLfloat y, GLfloat z );
private:
#ifdef WIN32
HMODULE m_hLib; // opengl32.dll
#else
void *m_hLib; // libGL.so
#endif
};
这是来源:
extern CGLManager gGL;
// GetAnyGLFuncAddress - Attempt to retrieve the OpenGL function named "_cName" and store it in "_pFunc", returns true if success or false otherwise
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
#ifdef WIN32
// Similar to https://www.opengl.org/wiki/Load_OpenGL_Functions#Windows
_pFunc = (void *)wglGetProcAddress( _cName );
if ( _pFunc == 0 || (_pFunc == (void *)0x1) || (_pFunc == (void *)0x2) || (_pFunc == (void *)0x3) || (_pFunc == (void *)-1) )
_pFunc = (void *)GetProcAddress( m_hLib, _cName );
#else
// TODO: Test this
// According to some websites, NVIDIA drivers prefer the ARB implementation over the core one
_pFunc = (void *)glXGetProcAddressARB( _cName );
if ( _pFunc == 0 || (_pFunc == (void *)0x1) || (_pFunc == (void *)0x2) || (_pFunc == (void *)0x3) || (_pFunc == (void *)-1) )
_pFunc = (void *)glXGetProcAddress( _cName );
#endif
return (_pFunc != NULL);
}
// LoadFunctions - Attempt to retrieve all used OpenGL functions, returns true if all of them were retrieved or false if there is a single failure
bool CGLManager::LoadFunctions( void )
{
if ( !(GetAnyGLFuncAddress( "glBegin", &gGL.glBegin )) )
return false;
if ( !(GetAnyGLFuncAddress( "glEnd", &gGL.glEnd )) )
return false;
if ( !(GetAnyGLFuncAddress( "glVertex3f", &gGL.glVertex3f )) )
return false;
return true;
}
以下是我的经理一般工作的方式:首先检查游戏引擎使用的渲染器(软件,OpenGL或Direct3D),如果不是OpenGL,那么我们就不再进一步了解。否则,我们加载库(opengl32.dll
或libGL.so
)并检查它是否好(再次,如果失败,我们停止),我们检索并存储指向OpenGL函数的指针({{1 {}},glBegin
,glEnd
)使用glVertex3f
方法,如果一切正常或发生了错误,我们会返回。
现在问题: LoadFunctions
方法成功检索OpenGL函数(换句话说,GetAnyGLFuncAddress
将返回true,glBegin
将返回false)但是某些原因,glARandomMethodThatDontExist
中的gGL.glBegin
(以及它的“朋友”)没有得到更新,它将始终为NULL,从而导致崩溃。
我一直在尝试通过在Internet和StackOverflow上搜索找到解决方案,但我没有找到任何可以解决问题的答案。
在StackOverflow上发现的许多网站和答案中,很多人建议使用像GLEW这样的OpenGL加载库,甚至OpenGL维基也推荐它。 但是,由于我正在处理的环境的性质,我不能使用那些类型的库,也不能直接使用OpenGL函数,我知道我正在经历通过手动完成所有事情的痛苦方式,但我别无选择。
感谢您的回答。
答案 0 :(得分:4)
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
这只是普通的,破碎的C ++。 _pFunc
是void*
。指针是值。更改_pFunc
的值不会更改传入的变量的值。
您应该只返回指针(NULL表示失败条件),或_pFunc
应该是void**
。这可能需要来自调用者的强制转换,并且GetAnyGLFuncAddress
需要*_pFunc =
来设置值。
如果您要返回函数指针,则需要在返回之前将返回的void*
强制转换为相应的函数指针类型。这就是为什么你经常看到OpenGL加载器使用typedef作为函数指针类型。
typedef void (APIENTRY *(PFN_GLBEGIN))( GLenum );
...
PFN_GLBEGIN glBegin;
...
glBegin = static_cast<PFN_GLBEGIN>(GetAnyGLFuncAddress("glBegin"));
类似的东西。
答案 1 :(得分:-1)
*gl*GetProcAddres
仅指定用于扩展功能的返回入口点地址。它不需要返回操作系统OpenGL ABI要求中的函数的地址(OpenGL-1.1 for Windows,OpenGL-1.2 for Linux Softare Base(LSB)4,OpenGL-2.1 for LSB-5)。
通常,如果您的程序二进制文件直接链接到API库(存根)(与使用在运行时动态加载API库(存根)的加载程序相反),它就是&#39 ; s quity愚蠢地检索函数是操作系统与*gl*GetProcAddress
的OpenGL ABI合同的一部分,因为这些函数无论如何都可以通过常规API库获得。 wglGetProcAddress
与OpenGL-1.1函数一起导出,glXGetProcAddress
与所有OpenGL-1.2函数一起导出(至少),因此如果您的程序看到*GetProcAddress
函数,它也会看到其他OpenGL函数
通过GetProcAddress加载所有 OpenGL符号的唯一原因是,如果您使用LoadLibrary加载opengl32.dll
或使用dlopen加载libGL.so
。
答案 2 :(得分:-1)
忘记你的最终目标是什么,我看到了基本的C ++错误。
让我们删除所有不相关的代码并专注于此:
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
_pFunc = (void *)wglGetProcAddress( _cName ); // <-- This sets the local pointer
//...
}
然后你打电话给上面这样:
bool CGLManager::LoadFunctions( void )
{
if ( !(GetAnyGLFuncAddress( "glBegin", &gGL.glBegin )) )
return false;
}
您在第二个参数中传递了地址,但在函数GetAnyGLFuncAddress
中,您没有更新该值,以便将新值反映回调用者。您改为设置本地值,因此将不会设置gGL.glBegin
(以及其他两个呼叫中的所有其他地址)。
在GetAnyGLFuncAddress
内部,我原本希望这可行:
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
*_pFunc = (void *)wglGetProcAddress( _cName ); // <-- Note the *
//...
}
pFunc
内GetAnyGLFuncAddress
的任何后续使用也应该反映出取消引用的值。
另一个解决方案(因为这个是 C ++),你可以放弃void *
类C编码,并使函数成为一个模板,它将函数指针类型作为模板参数:
template <typename FnPtr>
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, FnPtr* _pFunc )
{
*_pFunc = reinterpret_cast<FnPtr>(wglGetProcAddress( _cName ));
//...
}
由于类型现在为FnPtr*
,因此无论您传入的是什么,都会自动FnPtr
属于该类型。不再有void *
(wglGetProcAddress
的返回值除外)。