GL01-02:OpenGL环境初始化与异常处理

本文主要说明OpenGL的编程模式:
  1. OpenGK环境与上下文初始化;
  2. 错误处理;
  3. 版本管理;


  • 说明
    • GLFW与GLEW无关,可以独立调用;主要负责UI部分。

一. GLFW的官方文档

1. 官方参考

  • https://www.glfw.org/docs/latest/modules.html

2. 在线教程

  • https://www.glfw.org/docs/latest/

  • GLFW的官方教程主题
  • 教程分成6个主题来说明:
    • 初始化:其实就是编程模式;
    • Window:创建窗体组件;
    • Context:OpenGL与OpenGL ES的上下文环境;
    • Vulkan:一个跨平台的2D和3D绘图应用程序接口(API);
    • Monitor:监视器与视频工作模式;
    • Input:交互事件处理:键盘与鼠标交互输入;

二. GLFW编程模式

1. 初始化与释放终止

1.1. 函数说明

  1. GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);

    1. 函数说明:
      • 获取运行时GLFW的版本;
    2. 函数参数:
      • 返回主版本号,副版本号,修订号
    3. 函数返回值:
    4. 说明:
      • 该函数的调用,无需调用glfwInit函数。
  2. GLFWAPI const char* glfwGetVersionString(void);

    • 与上面函数一样,只是返回字符串格式的版本号;
  3. GLFWAPI int glfwGetError(const char** description);

    1. 函数说明:
      • 用来获取上次执行函数发生的错误,某些函数没有返回值,从而无法返回错误状态,使用该函数就非常方便。
    2. 函数参数:
      • 返回错误的字符串描述;需要双指针,一个存放地址的地址,这意味着错误描述的字符串空间是函数分配的。
      • 没有错误发生,返回NULL。
    3. 函数返回值:
      • 返回上次函数执行产生的错误码;
    4. 说明:
      • 返回GLFW_NO_ERROR表示没有错误发生。GLFW_NO_ERROR的定义如下:
        • #define GLFW_NO_ERROR 0
  1. GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
    • 函数说明:
      • 用来设置函数错误发生时候的回调函数。
    • 函数参数:
      • 回调函数,该函数原型定义如下(两个参数,用来传递错误码与错误描述):
        • typedef void (* GLFWerrorfun)(int,const char*);
    • 函数返回值:
      • 返回上次设置的错误回调函数,上次没有设置则返回NULL。
  1. GLFWAPI void glfwInitHint(int hint, int value);

    1. 函数说明:
      • 在glfwinit之前调用用来设置初始化提示,提示设置会影响初始化行为,并最终影响库的行为,直到环境终止。
    2. 函数参数:
      • int hint:设置提示的类型;

        GLFW_JOYSTICK_HAT_BUTTONS(缺省值:GLFW_TRUE 支持值:GLFW_TRUE 或者 GLFW_FALSE)
        GLFW_COCOA_CHDIR_RESOURCES(缺省值:GLFW_TRUE 支持值:GLFW_TRUE 或者 GLFW_FALSE)
        GLFW_COCOA_MENUBAR(缺省值:GLFW_TRUE 支持值:GLFW_TRUE 或者 GLFW_FALSE)
        - int value:设置提示的值;支持的值:
        - GLFW_TRUE
        - GLFW_FALSE
        3. 函数返回值:
        - 无
        4. 说明:
        - 某些平台有自己特殊的提示设置。
        - 可能产生的错误有:GLFW_INVALID_ENUM 与 GLFW_INVALID_VALUE;

  2. GLFWAPI int glfwInit(void);

    1. 函数说明:
      • 此函数初始化glfw库。在大多数glfw函数可以使用之前,必须初始化glfw,并且在应用程序终止之前,应该终止glfw,以便释放初始化期间或之后分配的任何资源。

      • 如果此函数失败,则在返回之前调用glfwterminate函数。

      • 如果成功,则应在应用程序退出之前调用glfwterminate函数。

      • 如果还函数已经成功初始化,则再此调用将立即返回GLFW_TRUE。

      • 此函数将应用程序的当前目录更改为应用程序包的“Contents/Resources”子目录(如果存在)。这可以通过GLFW_COCOA_CHDIR_RESOURCES的init hint禁用。

    2. 函数参数
    3. 函数返回值:
      • 成功返回GLFW_TRUE
      • 失败返回GLFW_FALSE
    4. 说明:
      • GLFW_TRUE与GLFW_FALSE的定义:
        • #define GLFW_TRUE 1
        • #define GLFW_FALSE 0
      • 可能得错误:GLFW_PLATFORM_ERROR,使用函数error_handling处理。
  1. GLFWAPI void glfwTerminate(void);
    1. 函数说明:
      • 此函数销毁所有剩余的窗口和光标,恢复任何修改过的gamma渐变并释放任何其他分配的资源。 调用此函数后,必须再次成功调用glfwInit,才能使用大多数glfw函数。
      • 如果glfw已成功初始化,则应在应用程序退出之前调用此函数。
      • 如果初始化失败,则无需调用此函数,因为它在返回failure之前由glfwinit调用。
      • 该函数不要在回调函数中调用;
      • 该函数只能在主线程中调用;
    2. 函数参数:
    3. 函数返回值:

1.2. 关于GLFWAPI

  • GLFWAPI是一个使用#define定义的宏,用来说明函数来自DLL库。

    • __declspec(dllexport)
  • 说明:

    • dllexport是在这些类、函数以及数据的申明的时候使用。用他表明这些东西可以被外部函数使用,即(dllexport)是把 DLL中的相关代码(类,函数,数据)暴露出来为其他应用程序使用。

    • 使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。

    • dllimport是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL 内部代码(类,函数,全局变量)时,只需要在程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。

    • _declspec(dllexport)与_declspec(dllimport)是相互呼应,只有在DLL内部用dllexport作了声明,才能在外部函数中用dllimport导入相关代码。

    /* GLFWAPI is used to declare public API functions for export
     * from the DLL / shared library / dynamic library.
     */
    #if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
     /* We are building GLFW as a Win32 DLL */
     #define GLFWAPI __declspec(dllexport)
    #elif defined(_WIN32) && defined(GLFW_DLL)
     /* We are calling GLFW as a Win32 DLL */
     #define GLFWAPI __declspec(dllimport)
    #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
     /* We are building GLFW as a shared / dynamic library */
     #define GLFWAPI __attribute__((visibility("default")))
    #else
     /* We are building or calling GLFW as a static library */
     #define GLFWAPI
    #endif

1.3. 运行初始化与释放

  • 第一个运行的函数必须是glfwInit,该函数必须在其他任何函数调用之前调用;
  • 如果使用glfwInit初始化了运行环境,必须使用glfwTerminate释放。
    #include 
    #include 
    #include 
    #include 

    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        printf("初始化GLFW环境成功!\n");
        //程序结束前一定要释放
        glfwTerminate();
        printf("释放退出!\n");

        return 0;
    }

    // 编译命令:g++ -omain  gl01_01_init_terminate.cpp  -lglfw

2. 初始化前的提示(hint)

  • 初始化提示在glfwInit之前设置,并影响库的行为,直到终止。提示使用glfwInitHint设置。
    #include 
    #include 
    #include 
    #include 

    int main(int argc, char const *argv[]){

        glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE);  // 游戏杆作为按钮
        glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_TRUE);    //菜单条
        glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);   //切换到资源路径
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        printf("初始化GLFW环境成功!\n");
        //程序结束前一定要释放
        glfwTerminate();
        printf("释放退出!\n");

        return 0;
    }

    // 编译命令:g++ -omain  gl01_02_init_hint.cpp  -lglfw

3. 错误处理

  • GLFW提供两种错误处理方式:
    1. 使用函数glfwGetError返回错误代码,货返返回错误描述。
    2. 设置错误回调函数,在错误发生时,回调函数得到调用,从而错误得到处理的机会。

3.1. 错误信息获取

  • 使用返回值返回错误码;
  • 使用参数返回错误描述;
    #include 
    #include 
    #include 
    #include 

    int main(int argc, char const *argv[]){

        glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE);  // 游戏杆作为按钮
        // 处理错误
        int err_code = glfwGetError(NULL);
        if (err_code == GLFW_NO_ERROR){
            printf("Hint没有发生错误!\n");
        }
        else{
            printf("Hint发生错误:%d\n", err_code);
            exit(-1);
        }
        glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_TRUE);    //菜单条
        glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);   //切换到资源路径

        const char *msg;
        err_code = glfwGetError(&msg);
        if (err_code == GLFW_NO_ERROR){
            printf("Hint没有发生错误:%s\n", msg);
        }
        else{
            printf("Hint发生错误:%s\n", msg);
            exit(-1);
        }
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        printf("初始化GLFW环境成功!\n");
        //程序结束前一定要释放
        glfwTerminate();
        printf("释放退出!\n");

        return 0;
    }

    // 编译命令:g++ -omain  gl01_03_error.cpp  -lglfw

3.2. 错误回调函数

  • 错误回调函数与上面方式差不多,差别在于错误发生时候,回调函数会被自动调用。
  • 回调函数类型为:typedef void (* GLFWerrorfun)(int,const char*);
#include 
#include 
#include 
#include 

void error_callback(int code , const char *msg){
    // 处理错误
    if (code == GLFW_NO_ERROR){
        printf("Hint没有发生错误:%d:%s\n", code, msg);
    }
    else{
        printf("Hint发生错误:%d:%s\n", code, msg);
        exit(-1);
    }
}

int main(int argc, char const *argv[]){

    // 设置错误回调:typedef void (* GLFWerrorfun)(int,const char*)
    // 返回原来的错误回调函数
    GLFWerrorfun old_callback = glfwSetErrorCallback(error_callback);
    printf("旧回调函数:%p\n", (void*)old_callback);

    glfwInitHint(45, GLFW_FALSE);  // 故意构造一个错误
    glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_TRUE);    //菜单条
    glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);   //切换到资源路径

    // 初始化
    int re = glfwInit();
    if(re == GLFW_FALSE){
        printf("初始化GLFW环境失败!\n");
        exit(-1);
    }
    printf("初始化GLFW环境成功!\n");
    //程序结束前一定要释放
    glfwTerminate();
    printf("释放退出!\n");
    
    return 0;
}

// 编译命令:g++ -omain  gl01_04_error_callback.cpp  -lglfw

4. 版本管理

4.1. 编译时版本

  • 编译时版本通过宏提供;
    • GLFW_VERSION_MAJOR,
    • GLFW_VERSION_MINOR,
    • GLFW_VERSION_REVISION

4.2. 运行时版本

  • 使用两个函数获取:
    • 数字:glfwGetVersion
    • 字符串:glfwGetVersionString

4.3. 代码

    #include 
    #include 
    #include 
    #include 

    int main(int argc, char const *argv[]){

        // 获取编译时版本号
        printf("编译时版本:%d.%d.%d\n", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION);

        // 获取运行时版本号
        int major, minor,revision;
        glfwGetVersion(&major, &minor, &revision);
        printf("版本:%d.%d.%d\n", major, minor,revision);  // 输出:3.3.0

        printf("字符串版本:%s\n", glfwGetVersionString());   // 输出:3.3.0 Cocoa NSGL EGL OSMesa dynamic

        return 0;
    }

    // 编译命令:g++ -omain  gl01_05_version.cpp  -lglfw


三. 附录

1.宏定义

#define GLFW_TRUE 1

#define GLFW_FALSE 0

#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001

#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001

#define GLFW_COCOA_MENUBAR 0x00051002

2. 类型定义

typedef void(* GLFWerrorfun) (int, const char *)

3. 函数定义

int glfwInit (void)

void glfwTerminate (void)

void glfwInitHint (int hint, int value)

void glfwGetVersion (int *major, int *minor, int *rev)

const char * glfwGetVersionString (void)

int glfwGetError (const char **description)

GLFWerrorfun glfwSetErrorCallback (GLFWerrorfun cbfun)


你可能感兴趣的:(GL01-02:OpenGL环境初始化与异常处理)