简单地在Windows上写GLES

Opengl ES2.0 Programming Guide 书中附带的exmaple,创建了一个Windows窗口,通过几个简单的回调函数传递事件,交互起来实在太繁琐了。所以改用SDL2显示GLES2,SDL的事件更加便于交互。
当然了 Webgl Programming Guide 讲述了如何在浏览器中使用GLES2,调试分享起来也非常便捷,并且没有了繁琐的环境搭建过程,也不失为一种好的方法。

这里可以找到示例代码

bug: msys2安装的angle无法使用glDrawElements函数

哪里得到OpenGL ES

如果使用Linux,你可以在包管理中轻而易举地找到关于GLES的开发包。但是Windows上哪里找呢? Angle是由谷歌发起的项目,在各个平台上实现了GLES2甚至GLES3,被大名鼎鼎的Chrome和Qt也使用,Webgl也是基于他实现的!

如果有能连接Google的网络环境,可以自己编译。简便的方法是安装msys2,在包管理中安装angle,不要忘了,一起安装SDL2和编译器

pacman -Ss angle # 你可以在pacman中搜索到angleproject

···
mingw32/mingw-w64-i686-angleproject-git 2.1.r6846-1
    ANGLE project built from git source (mingw-w64)
···
mingw64/mingw-w64-x86_64-angleproject-git 2.1.r6846-1 [installed]
    ANGLE project built from git source (mingw-w64)
···

pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-angleproject-git mingw-w64-x86_64-SDL2 mingw-w64-x86_64-pkg-config

SDL2与EGL

Angle包含了GLESv2和EGL,EGL用来管理GLES的上下文环境,如同WGL(Windows)、GLX(X Window, Linux)…一样。 GLES是与平台无关的图形库,如开头所说的Windows窗口,需要通过EGL与GLES关联起来才可以显示。但是GLES的EGL与WGL,GLX这些管理GL上下文的库是不相通用的,所以EGL在不同平台都有相应的实现。

根据不同平台,SDL自动选择WGL、GLX…来创建OpenGL上下文环境,并关联到SDL窗口。 如果一开始在Windows平台上创建GLES Context是不行的,即便是你添加了一下代码,也是毫无反应的。

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

我一开始在网上找了一大圈,发现很多类似问题。SDL2的release note上却说,SDL2的某次更新支持了在Windows上通过Angle来调用GLES API。这是因为msys2中的SDL2在编译时根据platform和config选择了WGL管理GL上下文环境,而不是EGL,因而无论如何配置都不能起作用。

// SDL_windowsvideo.c
#if SDL_VIDEO_OPENGL_WGL
    device->GL_LoadLibrary = WIN_GL_LoadLibrary;
    ···
#elif SDL_VIDEO_OPENGL_EGL        
    /* Use EGL based functions */
    device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
    ···
#endif

对应的函数在 SDL_windowsopengles.c 中均有实现,只是没有被加载。

开始

但这并不意味着你需要重新编译,你只需要获取SDL在Windows上的的窗口句柄,自己初始化EGL,使用 eglSwapBuffers 进行绘图更新就可以了。

#include <SDL2/SDL_egl.h>
#include <SDL2/SDL_opengles2.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>

int Init_Angle_EGL(SDL_Window *win, EGL_Swap *swap)
{
    EGLint configAttribList[] =
        {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 8,
            EGL_STENCIL_SIZE, 8,
            EGL_SAMPLE_BUFFERS, 1,
            EGL_NONE};
    EGLint surfaceAttribList[] =
        {
            EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE,
            EGL_NONE, EGL_NONE};

    EGLint numConfigs;
    EGLint majorVersion;
    EGLint minorVersion;
    EGLDisplay display;
    EGLContext context;
    EGLSurface surface;
    EGLConfig config;
    EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE};

    SDL_SysWMinfo info;
    SDL_VERSION(&info.version); // initialize info structure with SDL version info
    SDL_bool get_win_info = SDL_GetWindowWMInfo(win, &info);
    SDL_assert_release(get_win_info);
    EGLNativeWindowType hWnd = info.info.win.window;

    // Get Display
    display = eglGetDisplay(GetDC(hWnd)); // EGL_DEFAULT_DISPLAY
    if (display == EGL_NO_DISPLAY)
    {
        return EGL_FALSE;
    }

    // Initialize EGL
    if (!eglInitialize(display, &majorVersion, &minorVersion))
    {
        return EGL_FALSE;
    }

    // Get configs
    if (!eglGetConfigs(display, NULL, 0, &numConfigs))
    {
        return EGL_FALSE;
    }

    // Choose config
    if (!eglChooseConfig(display, configAttribList, &config, 1, &numConfigs))
    {
        return EGL_FALSE;
    }

    // Create a surface
    surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, surfaceAttribList);
    if (surface == EGL_NO_SURFACE)
    {
        return EGL_FALSE;
    }

    // Create a GL context
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
    if (context == EGL_NO_CONTEXT)
    {
        return EGL_FALSE;
    }

    // Make the context current
    if (!eglMakeCurrent(display, surface, surface, context))
    {
        return EGL_FALSE;
    }

    printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
    printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
    printf("GL_SHADING_LANGUAGE_VERSION: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
    swap->display = display;
    swap->surface = surface;
    return EGL_TRUE;
}

int main(int argc, char *argv[])
{
    ...
    SDL_Window *win = SDL_CreateWindow(...);
    Init_Angle_EGL(win, &swap);
    ...
    while (run)
    {
        ...
        glClear(GL_COLOR_BUFFER_BIT);
        eglSwapBuffers(swap.display, swap.surface);
    }
    ...
    return 0;
}

你可以看到关于Angle的一些信息

GL_RENDERER: ANGLE (Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0)
GL_VERSION: OpenGL ES 2.0 (ANGLE 2.1.0.unknown hash)
GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 1.00 (ANGLE 2.1.0.unknown hash)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值