2

我打算重写一个小型 C++ OpenGL 字体库,因为我最近发现了对较新 OpenGL 版本的更改,所以我使用 FreeType 2 做了一段时间。我的代码使用立即模式,并且我很确定现在不推荐使用某些函数调用,例如 glLineStipple。

我非常希望支持一系列 OpenGL 版本,以便代码在可能的情况下使用例如 VBO,或者在没有其他可用的情况下回退到立即模式等等。我不知道该怎么做。Afaik,您无法进行编译时检查,因为您需要在运行时创建有效的 OpenGL 上下文。到目前为止,我提出了以下建议(灵感来自其他线程/站点):

  • 使用 GLEW 在绘图函数中进行运行时检查并检查函数支持(例如 glLineStipple)

  • 使用可以在编译时指定的一些 #define 和其他预处理器指令来编译适用于不同 OpenGL 版本的不同版本

  • 编译支持不同 OpenGL 版本的不同版本,并将每个版本作为单独的下载提供

  • 使用脚本 (Python/Perl) 交付库,该脚本检查系统上的 OpenGL 版本(如果可能/可靠)并对源进行适当的修改,使其适合用户的 OpenGL 版本

  • 仅针对较新的 OpenGL 版本并放弃对以下任何内容的支持

无论如何,我可能会使用 GLEW 轻松加载扩展。

跟进: 根据您非常有用的答案,我尝试根据我的旧代码编写几行代码,这是一个片段(未经测试/完成)。我在配置头中声明了适当的函数指针,然后在初始化库时,我尝试获取正确的函数指针。如果 VBO 失败(指针为空),我会退回到显示列表(在 3.0 中已弃用),然后最后到顶点数组。如果 fx,我应该(也许?)也检查可用的 ARB 扩展。VBO 无法加载还是工作量太大?这会是一个可靠的方法吗?评论表示赞赏:)

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
    #define OFL_WINDOWS
    // other stuff...
    #ifndef OFL_USES_GLEW
        // Check which extensions are supported
    #else
        // Declare vertex buffer object extension function pointers
        PFNGLGENBUFFERSPROC          glGenBuffers          = NULL;
        PFNGLBINDBUFFERPROC          glBindBuffer          = NULL;
        PFNGLBUFFERDATAPROC          glBufferData          = NULL;
        PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL;
        PFNGLDELETEBUFFERSPROC       glDeleteBuffers       = NULL;
        PFNGLMULTIDRAWELEMENTSPROC   glMultiDrawElements   = NULL;
        PFNGLBUFFERSUBDATAPROC       glBufferSubData       = NULL;
        PFNGLMAPBUFFERPROC           glMapBuffer           = NULL;
        PFNGLUNMAPBUFFERPROC         glUnmapBuffer         = NULL;
    #endif
#elif some_other_system

初始化函数:

#ifdef OFL_WINDOWS
    bool loaded = true;

    // Attempt to load vertex buffer obejct extensions
    loaded = ((glGenBuffers          = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers"))                   != NULL && loaded);
    loaded = ((glBindBuffer          = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer"))                   != NULL && loaded);
    loaded = ((glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer")) != NULL && loaded);
    loaded = ((glDeleteBuffers       = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers"))             != NULL && loaded);
    loaded = ((glMultiDrawElements   = (PFNGLMULTIDRAWELEMENTSPROC)wglGetProcAddress("glMultiDrawElements"))     != NULL && loaded);
    loaded = ((glBufferSubData       = (PFNGLBUFFERSUBDATAPROC)wglGetProcAddress("glBufferSubData"))             != NULL && loaded);
    loaded = ((glMapBuffer           = (PFNGLMAPBUFFERPROC)wglGetProcAddress("glMapBuffer"))                     != NULL && loaded);
    loaded = ((glUnmapBuffer         = (PFNGLUNMAPBUFFERPROC)wglGetProcAddress("glUnmapBuffer"))                 != NULL && loaded);

     if (!loaded)
        std::cout << "OFL: Current OpenGL context does not support vertex buffer objects" << std::endl;
    else {
        #define OFL_USES_VBOS
        std::cout << "OFL: Loaded vertex buffer object extensions successfully"
        return true;
    }

    if (glMajorVersion => 3.f) {
        std::cout << "OFL: Using vertex arrays" << std::endl;
        #define OFL_USES_VERTEX_ARRAYS
    } else {
        // Display lists were deprecated in 3.0 (although still available through ARB extensions)
        std::cout << "OFL: Using display lists"
        #define OFL_USES_DISPLAY_LISTS
    }
#elif some_other_system
4

2 回答 2

5

首先,你会很安全,因为它在任何地方都受支持:重写你的字体渲染器以使用Vertex Arrays。从 VA 到 VBO 只是一小步,但各地都支持 VA。您只需要一小组扩展功能;也许手动加载是有意义的,而不是依赖于 GLEW。静态链接它是巨大的矫枉过正。

然后将调用放入包装函数中,您可以通过函数指针引用它们,以便您可以通过这种方式切换渲染路径。例如添加一个函数“stipple_it”左右,并在内部调用 glLineStipple 或为其构建和设置适当的片段着色器。

glVertexPointer 与 glVertexAttribPointer 类似。

于 2012-05-29T12:19:44.910 回答
3

如果您确实想手动进行每项检查,那么您将无法摆脱一些#defines,因为 Android/iOS 仅支持 OpenGL ES,然后运行时检查会有所不同。

运行时检查也几乎是不可避免的,因为(根据个人经验)来自不同硬件供应商的不同驱动程序有很多警告(当然,对于 OpenGL 1.0 以上的任何驱动程序)。

“只针对较新的 OpenGL 版本并放弃对以下任何内容的支持”将是一个可行的选择,因为 ATI/nVidia 甚至英特尔的大多数视频卡都支持某些版本的 OpenGL 2.0+,这大致相当于 GL ES 2.0。

GLEW 是一种简化 GL 扩展获取的好方法。尽管如此,嵌入式平台上的 GL ES 仍然存在问题。

现在加载过程:

  1. 在 win32/linux 上,只需检查函数指针是否为 NULL 并使用 GL 的 ExtensionString 来了解此具体硬件支持的内容

  2. iOS/Android/MacOSX 的“加载”只是存储指针,甚至是“什么都不做”。Android 是一个不同的野兽,这里有静态指针,但需要检查扩展。即使经过这些检查,您也可能不确定某些被报告为“工作”的东西(我说的是“无名”Android 设备或简单的 gfx 硬件)。因此,您将根据视频卡的名称添加自己的(!)检查。

  3. OSX/iOS OpenGL 实现“正常工作”。因此,如果您在 10.5 上运行,您将获得 GL2.1;10.6 - 2.1 + 一些使其几乎像 3.1/3.2 的扩展;10.7 - 3.2 核心配置文件。还没有适用于 Mac 的 GL4.0,这主要是 3.2 的演变。

如果您对我的个人意见感兴趣,那么我主要来自“重塑一切”阵营,多年来我们一直在使用一些自动生成的扩展加载器。

最重要的是,您走在正确的轨道上:对 VBO/VA/Shaders/NoFFP 的重写将为您带来重大的性能提升。

于 2012-05-29T12:20:09.083 回答