GL01-02:OpenGL環(huán)境初始化與異常處理

本文主要說(shuō)明OpenGL的編程模式:
??1. OpenGK環(huán)境與上下文初始化现恼;
??2. 錯(cuò)誤處理凛澎;
??3. 版本管理;


  • 說(shuō)明
    • GLFW與GLEW無(wú)關(guān)适掰,可以獨(dú)立調(diào)用孕荠;主要負(fù)責(zé)UI部分。

一. GLFW的官方文檔

1. 官方參考

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

2. 在線(xiàn)教程

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

  • GLFW的官方教程主題
  • 教程分成6個(gè)主題來(lái)說(shuō)明:
    • 初始化:其實(shí)就是編程模式攻谁;
    • Window:創(chuàng)建窗體組件;
    • Context:OpenGL與OpenGL ES的上下文環(huán)境弯予;
    • Vulkan:一個(gè)跨平臺(tái)的2D和3D繪圖應(yīng)用程序接口(API)戚宦;
    • Monitor:監(jiān)視器與視頻工作模式;
    • Input:交互事件處理:鍵盤(pán)與鼠標(biāo)交互輸入锈嫩;

二. GLFW編程模式

1. 初始化與釋放終止

1.1. 函數(shù)說(shuō)明

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

    1. 函數(shù)說(shuō)明:
      • 獲取運(yùn)行時(shí)GLFW的版本受楼;
    2. 函數(shù)參數(shù):
      • 返回主版本號(hào)垦搬,副版本號(hào),修訂號(hào)
    3. 函數(shù)返回值:
      • 無(wú)
    4. 說(shuō)明:
      • 該函數(shù)的調(diào)用艳汽,無(wú)需調(diào)用glfwInit函數(shù)猴贰。
  2. GLFWAPI const char* glfwGetVersionString(void);

    • 與上面函數(shù)一樣,只是返回字符串格式的版本號(hào)河狐;
  3. GLFWAPI int glfwGetError(const char** description);

    1. 函數(shù)說(shuō)明:
      • 用來(lái)獲取上次執(zhí)行函數(shù)發(fā)生的錯(cuò)誤米绕,某些函數(shù)沒(méi)有返回值,從而無(wú)法返回錯(cuò)誤狀態(tài)馋艺,使用該函數(shù)就非常方便栅干。
    2. 函數(shù)參數(shù):
      • 返回錯(cuò)誤的字符串描述;需要雙指針捐祠,一個(gè)存放地址的地址碱鳞,這意味著錯(cuò)誤描述的字符串空間是函數(shù)分配的。
      • 沒(méi)有錯(cuò)誤發(fā)生踱蛀,返回NULL窿给。
    3. 函數(shù)返回值:
      • 返回上次函數(shù)執(zhí)行產(chǎn)生的錯(cuò)誤碼;
    4. 說(shuō)明:
      • 返回GLFW_NO_ERROR表示沒(méi)有錯(cuò)誤發(fā)生率拒。GLFW_NO_ERROR的定義如下:
        • #define GLFW_NO_ERROR 0
  1. GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
    • 函數(shù)說(shuō)明:
      • 用來(lái)設(shè)置函數(shù)錯(cuò)誤發(fā)生時(shí)候的回調(diào)函數(shù)崩泡。
    • 函數(shù)參數(shù):
      • 回調(diào)函數(shù),該函數(shù)原型定義如下(兩個(gè)參數(shù)俏橘,用來(lái)傳遞錯(cuò)誤碼與錯(cuò)誤描述):
        • typedef void (* GLFWerrorfun)(int,const char*);
    • 函數(shù)返回值:
      • 返回上次設(shè)置的錯(cuò)誤回調(diào)函數(shù)允华,上次沒(méi)有設(shè)置則返回NULL。
  1. GLFWAPI void glfwInitHint(int hint, int value);

    1. 函數(shù)說(shuō)明:
      • 在glfwinit之前調(diào)用用來(lái)設(shè)置初始化提示寥掐,提示設(shè)置會(huì)影響初始化行為靴寂,并最終影響庫(kù)的行為,直到環(huán)境終止召耘。
    2. 函數(shù)參數(shù):
      • int hint:設(shè)置提示的類(lèi)型百炬;

        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:設(shè)置提示的值;支持的值:
        - GLFW_TRUE
        - GLFW_FALSE
        3. 函數(shù)返回值:
        - 無(wú)
        4. 說(shuō)明:
        - 某些平臺(tái)有自己特殊的提示設(shè)置污它。
        - 可能產(chǎn)生的錯(cuò)誤有:GLFW_INVALID_ENUM 與 GLFW_INVALID_VALUE剖踊;

  2. GLFWAPI int glfwInit(void);

    1. 函數(shù)說(shuō)明:
      • 此函數(shù)初始化glfw庫(kù)。在大多數(shù)glfw函數(shù)可以使用之前衫贬,必須初始化glfw德澈,并且在應(yīng)用程序終止之前,應(yīng)該終止glfw固惯,以便釋放初始化期間或之后分配的任何資源梆造。

      • 如果此函數(shù)失敗,則在返回之前調(diào)用glfwterminate函數(shù)葬毫。

      • 如果成功镇辉,則應(yīng)在應(yīng)用程序退出之前調(diào)用glfwterminate函數(shù)屡穗。

      • 如果還函數(shù)已經(jīng)成功初始化,則再此調(diào)用將立即返回GLFW_TRUE忽肛。

      • 此函數(shù)將應(yīng)用程序的當(dāng)前目錄更改為應(yīng)用程序包的“Contents/Resources”子目錄(如果存在)村砂。這可以通過(guò)GLFW_COCOA_CHDIR_RESOURCES的init hint禁用。

    2. 函數(shù)參數(shù)
      • 無(wú)
    3. 函數(shù)返回值:
      • 成功返回GLFW_TRUE
      • 失敗返回GLFW_FALSE
    4. 說(shuō)明:
      • GLFW_TRUE與GLFW_FALSE的定義:
        • #define GLFW_TRUE 1
        • #define GLFW_FALSE 0
      • 可能得錯(cuò)誤:GLFW_PLATFORM_ERROR屹逛,使用函數(shù)error_handling處理础废。
  1. GLFWAPI void glfwTerminate(void);
    1. 函數(shù)說(shuō)明:
      • 此函數(shù)銷(xiāo)毀所有剩余的窗口和光標(biāo),恢復(fù)任何修改過(guò)的gamma漸變并釋放任何其他分配的資源煎源。 調(diào)用此函數(shù)后色迂,必須再次成功調(diào)用glfwInit,才能使用大多數(shù)glfw函數(shù)手销。
      • 如果glfw已成功初始化歇僧,則應(yīng)在應(yīng)用程序退出之前調(diào)用此函數(shù)。
      • 如果初始化失敗锋拖,則無(wú)需調(diào)用此函數(shù)诈悍,因?yàn)樗诜祷豧ailure之前由glfwinit調(diào)用。
      • 該函數(shù)不要在回調(diào)函數(shù)中調(diào)用兽埃;
      • 該函數(shù)只能在主線(xiàn)程中調(diào)用侥钳;
    2. 函數(shù)參數(shù):
      • 無(wú)
    3. 函數(shù)返回值:
      • 無(wú)

1.2. 關(guān)于GLFWAPI

  • GLFWAPI是一個(gè)使用#define定義的宏,用來(lái)說(shuō)明函數(shù)來(lái)自DLL庫(kù)柄错。

    • __declspec(dllexport)
  • 說(shuō)明:

    • dllexport是在這些類(lèi)舷夺、函數(shù)以及數(shù)據(jù)的申明的時(shí)候使用珍策。用他表明這些東西可以被外部函數(shù)使用笼吟,即(dllexport)是把 DLL中的相關(guān)代碼(類(lèi),函數(shù)先朦,數(shù)據(jù))暴露出來(lái)為其他應(yīng)用程序使用颂跨。

    • 使用了(dllexport)關(guān)鍵字敢伸,相當(dāng)于聲明了緊接在(dllexport)關(guān)鍵字后面的相關(guān)內(nèi)容是可以為其他程序使用的。

    • dllimport是在外部程序需要使用DLL內(nèi)相關(guān)內(nèi)容時(shí)使用的關(guān)鍵字恒削。當(dāng)一個(gè)外部程序要使用DLL 內(nèi)部代碼(類(lèi)池颈,函數(shù),全局變量)時(shí)钓丰,只需要在程序內(nèi)部使用(dllimport)關(guān)鍵字聲明需要使用的代碼就可以了躯砰,即(dllimport)關(guān)鍵字是在外部程序需要使用DLL內(nèi)部相關(guān)內(nèi)容的時(shí)候才使用。(dllimport)作用是把DLL中的相關(guān)代碼插入到應(yīng)用程序中携丁。

    • _declspec(dllexport)與_declspec(dllimport)是相互呼應(yīng)琢歇,只有在DLL內(nèi)部用dllexport作了聲明,才能在外部函數(shù)中用dllimport導(dǎo)入相關(guān)代碼。

    /* 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. 運(yùn)行初始化與釋放

  • 第一個(gè)運(yùn)行的函數(shù)必須是glfwInit矿微,該函數(shù)必須在其他任何函數(shù)調(diào)用之前調(diào)用;
  • 如果使用glfwInit初始化了運(yùn)行環(huán)境尚揣,必須使用glfwTerminate釋放涌矢。
    #include <GLFW/glfw3.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

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

        return 0;
    }

    // 編譯命令:g++ -omain  gl01_01_init_terminate.cpp  -lglfw

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

  • 初始化提示在glfwInit之前設(shè)置快骗,并影響庫(kù)的行為娜庇,直到終止。提示使用glfwInitHint設(shè)置方篮。
    #include <GLFW/glfw3.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

    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環(huán)境失敗!\n");
            exit(-1);
        }
        printf("初始化GLFW環(huán)境成功!\n");
        //程序結(jié)束前一定要釋放
        glfwTerminate();
        printf("釋放退出名秀!\n");

        return 0;
    }

    // 編譯命令:g++ -omain  gl01_02_init_hint.cpp  -lglfw

3. 錯(cuò)誤處理

  • GLFW提供兩種錯(cuò)誤處理方式:
    1. 使用函數(shù)glfwGetError返回錯(cuò)誤代碼,貨返返回錯(cuò)誤描述藕溅。
    2. 設(shè)置錯(cuò)誤回調(diào)函數(shù)匕得,在錯(cuò)誤發(fā)生時(shí),回調(diào)函數(shù)得到調(diào)用巾表,從而錯(cuò)誤得到處理的機(jī)會(huì)汁掠。

3.1. 錯(cuò)誤信息獲取

  • 使用返回值返回錯(cuò)誤碼;
  • 使用參數(shù)返回錯(cuò)誤描述集币;
    #include <GLFW/glfw3.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

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

        glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE);  // 游戲桿作為按鈕
        // 處理錯(cuò)誤
        int err_code = glfwGetError(NULL);
        if (err_code == GLFW_NO_ERROR){
            printf("Hint沒(méi)有發(fā)生錯(cuò)誤!\n");
        }
        else{
            printf("Hint發(fā)生錯(cuò)誤:%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沒(méi)有發(fā)生錯(cuò)誤:%s\n", msg);
        }
        else{
            printf("Hint發(fā)生錯(cuò)誤:%s\n", msg);
            exit(-1);
        }
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW環(huán)境失敗!\n");
            exit(-1);
        }
        printf("初始化GLFW環(huán)境成功!\n");
        //程序結(jié)束前一定要釋放
        glfwTerminate();
        printf("釋放退出考阱!\n");

        return 0;
    }

    // 編譯命令:g++ -omain  gl01_03_error.cpp  -lglfw

3.2. 錯(cuò)誤回調(diào)函數(shù)

  • 錯(cuò)誤回調(diào)函數(shù)與上面方式差不多,差別在于錯(cuò)誤發(fā)生時(shí)候鞠苟,回調(diào)函數(shù)會(huì)被自動(dòng)調(diào)用乞榨。
  • 回調(diào)函數(shù)類(lèi)型為:typedef void (* GLFWerrorfun)(int,const char*);
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void error_callback(int code , const char *msg){
    // 處理錯(cuò)誤
    if (code == GLFW_NO_ERROR){
        printf("Hint沒(méi)有發(fā)生錯(cuò)誤:%d:%s\n", code, msg);
    }
    else{
        printf("Hint發(fā)生錯(cuò)誤:%d:%s\n", code, msg);
        exit(-1);
    }
}

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

    // 設(shè)置錯(cuò)誤回調(diào):typedef void (* GLFWerrorfun)(int,const char*)
    // 返回原來(lái)的錯(cuò)誤回調(diào)函數(shù)
    GLFWerrorfun old_callback = glfwSetErrorCallback(error_callback);
    printf("舊回調(diào)函數(shù):%p\n", (void*)old_callback);

    glfwInitHint(45, GLFW_FALSE);  // 故意構(gòu)造一個(gè)錯(cuò)誤
    glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_TRUE);    //菜單條
    glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);   //切換到資源路徑

    // 初始化
    int re = glfwInit();
    if(re == GLFW_FALSE){
        printf("初始化GLFW環(huán)境失敗!\n");
        exit(-1);
    }
    printf("初始化GLFW環(huán)境成功!\n");
    //程序結(jié)束前一定要釋放
    glfwTerminate();
    printf("釋放退出!\n");
    
    return 0;
}

// 編譯命令:g++ -omain  gl01_04_error_callback.cpp  -lglfw

4. 版本管理

4.1. 編譯時(shí)版本

  • 編譯時(shí)版本通過(guò)宏提供当娱;
    • GLFW_VERSION_MAJOR,
    • GLFW_VERSION_MINOR,
    • GLFW_VERSION_REVISION

4.2. 運(yùn)行時(shí)版本

  • 使用兩個(gè)函數(shù)獲瘸约取:
    • 數(shù)字:glfwGetVersion
    • 字符串:glfwGetVersionString

4.3. 代碼

    #include <GLFW/glfw3.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

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

        // 獲取編譯時(shí)版本號(hào)
        printf("編譯時(shí)版本:%d.%d.%d\n", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION);

        // 獲取運(yùn)行時(shí)版本號(hào)
        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. 類(lèi)型定義

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

3. 函數(shù)定義

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)


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市趾访,隨后出現(xiàn)的幾起案子态秧,更是在濱河造成了極大的恐慌,老刑警劉巖扼鞋,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件申鱼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡云头,警方通過(guò)查閱死者的電腦和手機(jī)捐友,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)溃槐,“玉大人匣砖,你說(shuō)我怎么就攤上這事。” “怎么了猴鲫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵对人,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拂共,道長(zhǎng)牺弄,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任宜狐,我火速辦了婚禮势告,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抚恒。我一直安慰自己咱台,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布俭驮。 她就那樣靜靜地躺著回溺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪表鳍。 梳的紋絲不亂的頭發(fā)上馅而,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音譬圣,去河邊找鬼瓮恭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛厘熟,可吹牛的內(nèi)容都是我干的屯蹦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绳姨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼登澜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起飘庄,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脑蠕,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后跪削,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谴仙,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年碾盐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晃跺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毫玖,死狀恐怖掀虎,靈堂內(nèi)的尸體忽然破棺而出凌盯,到底是詐尸還是另有隱情,我是刑警寧澤烹玉,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布驰怎,位于F島的核電站,受9級(jí)特大地震影響二打,放射性物質(zhì)發(fā)生泄漏砸西。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一址儒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衅疙,春花似錦莲趣、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绩郎,卻和暖如春潘鲫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肋杖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工溉仑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人状植。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓浊竟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親津畸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子振定,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容