GL01-04:GLFW的上下文與事件交互

本文主要說明OpenGL技術(shù)中g(shù)lfw的GL上下文與事件處理:
??1.glfw創(chuàng)建GL上下文;
??2.鼠標(biāo)事件;
??3.鍵盤事件;
??4.文件刪除事件;
??5.計(jì)時(shí)操作;


OpenGL上下文創(chuàng)建

關(guān)于上下文

上下文的創(chuàng)建與釋放

  1. 創(chuàng)建

    • 使用glfwCreateWindow函數(shù)創(chuàng)建窗體的時(shí)候,就同時(shí)創(chuàng)建兩兩個(gè)環(huán)境:窗體與OpenGL或者OpenGL ES上下文;
  2. 釋放

    • 上下文的釋放與窗體與整個(gè)應(yīng)用的釋放一起,就是調(diào)用glfwDestroyWindow或者glfwTerminate函數(shù)的時(shí)候;

上下文的設(shè)置

  • 上下問的設(shè)置使用glfwWindowHint函數(shù)設(shè)置,并且在調(diào)用glfwCreateWindow之前。

兩個(gè)窗體共享上下文

  • 在使用glfwCreateWindow創(chuàng)建窗體的時(shí)候,指定GLFWwindow * share參數(shù)即可。

離屏上下文

  • GLFW不支持在沒有關(guān)聯(lián)窗口的情況下創(chuàng)建上下文。但是,可以使用GLFW_VISIBLE窗體創(chuàng)建提示創(chuàng)建具有隱藏窗口的上下文。

  • 但是在Mac系統(tǒng)中,窗體創(chuàng)建的時(shí)候會(huì)自動(dòng)創(chuàng)建菜單條,可以使用GLFW_COCOA_MENUBAR提示設(shè)置隱藏。

沒有上下文的窗體

  • 創(chuàng)建窗體的時(shí)候,可以不創(chuàng)建上下文,只要使用GLFW_CLIENT_API提示的值為:GLFW_NO_API。
  • 沒有上下文的窗體不能傳遞給如下兩個(gè)函數(shù):
    • glfwMakeContextCurrent
    • glfwSwapBuffers

當(dāng)前上下文

  1. 在進(jìn)行OpenGL或OpenGL ES調(diào)用之前,需要具有正確類型的當(dāng)前上下文。

    • 一個(gè)上下文一次只能是單個(gè)線程的當(dāng)前上下文,而一個(gè)線程一次只能有一個(gè)當(dāng)前上下文。
    • 在線程之間移動(dòng)上下文時(shí),必須先使舊線程上的上下文變成非當(dāng)前,然后使其成為新線程上的當(dāng)前上下文(否則兩個(gè)線程都是當(dāng)前上下文,就麻煩了)。
    • 設(shè)置當(dāng)前上下文,使用函數(shù)glfwMakeContextCurrent
    • 返回當(dāng)前上下文,使用函數(shù)glfwGetCurrentContext
  2. glfwMakeContextCurrent函數(shù)說明

    void glfwMakeContextCurrent (   GLFWwindow *    window  )   

  1. glfwGetCurrentContext函數(shù)說明
    
    GLFWwindow* glfwGetCurrentContext   (   void        )   

  1. 下面幾個(gè)函數(shù)調(diào)用,必須有當(dāng)前上下文,否則會(huì)產(chǎn)生錯(cuò)誤GLFW_NO_CURRENT_CONTEXT
    • glfwSwapInterval
    • glfwExtensionSupported
    • glfwGetProcAddress

關(guān)于OpenGL的擴(kuò)展

  1. 關(guān)于擴(kuò)展

    • OpenGL和OpenGLES的一個(gè)好處是它們的可擴(kuò)展性。硬件供應(yīng)商可能在其實(shí)現(xiàn)中包含擴(kuò)展,這些擴(kuò)展在新版本的OpenGL或OpenGL ES規(guī)范中包含該功能之前對(duì)API進(jìn)行擴(kuò)展,并且某些擴(kuò)展永遠(yuǎn)不會(huì)包含在其中,并且在它們過時(shí)之前一直作為擴(kuò)展保留。
    • OpenGL和Direct3D比較起來,最大的一個(gè)長(zhǎng)處就是其擴(kuò)展機(jī)制。硬件廠商開發(fā)出一個(gè)新功能,可以針對(duì)新功能開發(fā)OpenGL擴(kuò)展,軟件開發(fā)人員通過這個(gè)擴(kuò)展就可以使用新的硬件功能。所以雖然顯卡的發(fā)展速度比OpenGL版本更新速度快得多,但程序員仍然可以通過OpenGL使用最新的硬件功能。而Direct3D則沒有擴(kuò)展機(jī)制,硬件的新功能要等到微軟發(fā)布新版DirectX后才可能支持。
  2. glad擴(kuò)展

    • https://glad.dav1d.de

在上下文上開始3D繪制

  • 基本步驟是:
    1. 創(chuàng)建上下文(通過創(chuàng)建窗體實(shí)現(xiàn))
    2. 設(shè)置當(dāng)前上下文;
    3. 初始化OpenGL
    4. 開始繪制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>


int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    // 1. 第一步:設(shè)置當(dāng)前上下文
    glfwMakeContextCurrent(window);
    // 2. 第二部:初始化OpenGL
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){
        // 3. 設(shè)置清屏顏色
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  trangle.cpp  -lglfw -lglew -framework opengl

  • 運(yùn)行效果:
    • 窗體上的清屏繪制

鍵盤事件

鍵盤事件實(shí)現(xiàn)

  • 鍵盤事件使用回調(diào)函數(shù)實(shí)現(xiàn):glfwSetKeyCallback
  1. 函數(shù)說明:
GLFWkeyfun glfwSetKeyCallback   (   
    GLFWwindow *    window,
    GLFWkeyfun  cbfun 
)   
  1. 回調(diào)函數(shù)GLFWkeyfun原型說明
typedef void(* GLFWkeyfun) (GLFWwindow *, int, int, int, int)
  • 參數(shù)說明:
    • window :發(fā)生事件的窗體
    • key :激發(fā)的鍵值
    • scancode :鍵值的系統(tǒng)掃描碼
    • action:動(dòng)作GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT.
    • mods: 輔助鍵ALT,CTRL,SHIFT,META等
  1. 事件實(shí)現(xiàn)代碼
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

void cb_key(GLFWwindow * win, int key, int code, int action, int mods){
    printf("key:%d, code:%d, action:%d, mods:%d\n", key, code, action, mods);
}

int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    // 處理事件
    glfwSetKeyCallback(window, cb_key);
    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){
        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl02_key_event.cpp  -lglfw -lglew -framework opengl

鍵值定義


    #define     GLFW_KEY_UNKNOWN   -1
    #define     GLFW_KEY_SPACE   32
    #define     GLFW_KEY_APOSTROPHE   39 /* ' */
    #define     GLFW_KEY_COMMA   44 /* , */
    #define     GLFW_KEY_MINUS   45 /* - */
    #define     GLFW_KEY_PERIOD   46 /* . */
    #define     GLFW_KEY_SLASH   47 /* / */
    #define     GLFW_KEY_0   48
    #define     GLFW_KEY_1   49
    #define     GLFW_KEY_2   50
    #define     GLFW_KEY_3   51
    #define     GLFW_KEY_4   52
    #define     GLFW_KEY_5   53
    #define     GLFW_KEY_6   54
    #define     GLFW_KEY_7   55
    #define     GLFW_KEY_8   56
    #define     GLFW_KEY_9   57
    #define     GLFW_KEY_SEMICOLON   59 /* ; */
    #define     GLFW_KEY_EQUAL   61 /* = */
    #define     GLFW_KEY_A   65
    #define     GLFW_KEY_B   66
    #define     GLFW_KEY_C   67
    #define     GLFW_KEY_D   68
    #define     GLFW_KEY_E   69
    #define     GLFW_KEY_F   70
    #define     GLFW_KEY_G   71
    #define     GLFW_KEY_H   72
    #define     GLFW_KEY_I   73
    #define     GLFW_KEY_J   74
    #define     GLFW_KEY_K   75
    #define     GLFW_KEY_L   76
    #define     GLFW_KEY_M   77
    #define     GLFW_KEY_N   78
    #define     GLFW_KEY_O   79
    #define     GLFW_KEY_P   80
    #define     GLFW_KEY_Q   81
    #define     GLFW_KEY_R   82
    #define     GLFW_KEY_S   83
    #define     GLFW_KEY_T   84
    #define     GLFW_KEY_U   85 
    #define     GLFW_KEY_V   86
    #define     GLFW_KEY_W   87
    #define     GLFW_KEY_X   88
    #define     GLFW_KEY_Y   89
    #define     GLFW_KEY_Z   90
    #define     GLFW_KEY_LEFT_BRACKET   91 /* [ */
    #define     GLFW_KEY_BACKSLASH   92 /* \ */
    #define     GLFW_KEY_RIGHT_BRACKET   93 /* ] */
    #define     GLFW_KEY_GRAVE_ACCENT   96 /* ` */
    #define     GLFW_KEY_WORLD_1   161 /* non-US #1 */
    #define     GLFW_KEY_WORLD_2   162 /* non-US #2 */
    #define     GLFW_KEY_ESCAPE   256
    #define     GLFW_KEY_ENTER   257
    #define     GLFW_KEY_TAB   258
    #define     GLFW_KEY_BACKSPACE   259
    #define     GLFW_KEY_INSERT   260
    #define     GLFW_KEY_DELETE   261
    #define     GLFW_KEY_RIGHT   262
    #define     GLFW_KEY_LEFT   263
    #define     GLFW_KEY_DOWN   264
    #define     GLFW_KEY_UP   265
    #define     GLFW_KEY_PAGE_UP   266
    #define     GLFW_KEY_PAGE_DOWN   267
    #define     GLFW_KEY_HOME   268
    #define     GLFW_KEY_END   269
    #define     GLFW_KEY_CAPS_LOCK   280
    #define     GLFW_KEY_SCROLL_LOCK   281
    #define     GLFW_KEY_NUM_LOCK   282
    #define     GLFW_KEY_PRINT_SCREEN   283
    #define     GLFW_KEY_PAUSE   284
    #define     GLFW_KEY_F1   290
    #define     GLFW_KEY_F2   291
    #define     GLFW_KEY_F3   292
    #define     GLFW_KEY_F4   293
    #define     GLFW_KEY_F5   294
    #define     GLFW_KEY_F6   295
    #define     GLFW_KEY_F7   296
    #define     GLFW_KEY_F8   297
    #define     GLFW_KEY_F9   298
    #define     GLFW_KEY_F10   299
    #define     GLFW_KEY_F11   300
    #define     GLFW_KEY_F12   301
    #define     GLFW_KEY_F13   302
    #define     GLFW_KEY_F14   303
    #define     GLFW_KEY_F15   304
    #define     GLFW_KEY_F16   305
    #define     GLFW_KEY_F17   306
    #define     GLFW_KEY_F18   307
    #define     GLFW_KEY_F19   308
    #define     GLFW_KEY_F20   309
    #define     GLFW_KEY_F21   310
    #define     GLFW_KEY_F22   311
    #define     GLFW_KEY_F23   312
    #define     GLFW_KEY_F24   313
    #define     GLFW_KEY_F25   314
    #define     GLFW_KEY_KP_0   320
    #define     GLFW_KEY_KP_1   321
    #define     GLFW_KEY_KP_2   322
    #define     GLFW_KEY_KP_3   323
    #define     GLFW_KEY_KP_4   324
    #define     GLFW_KEY_KP_5   325
    #define     GLFW_KEY_KP_6   326
    #define     GLFW_KEY_KP_7   327
    #define     GLFW_KEY_KP_8   328
    #define     GLFW_KEY_KP_9   329
    #define     GLFW_KEY_KP_DECIMAL   330
    #define     GLFW_KEY_KP_DIVIDE   331
    #define     GLFW_KEY_KP_MULTIPLY   332
    #define     GLFW_KEY_KP_SUBTRACT   333
    #define     GLFW_KEY_KP_ADD   334
    #define     GLFW_KEY_KP_ENTER   335
    #define     GLFW_KEY_KP_EQUAL   336
    #define     GLFW_KEY_LEFT_SHIFT   340
    #define     GLFW_KEY_LEFT_CONTROL   341
    #define     GLFW_KEY_LEFT_ALT   342
    #define     GLFW_KEY_LEFT_SUPER   343
    #define     GLFW_KEY_RIGHT_SHIFT   344
    #define     GLFW_KEY_RIGHT_CONTROL   345
    #define     GLFW_KEY_RIGHT_ALT   346
    #define     GLFW_KEY_RIGHT_SUPER   347
    #define     GLFW_KEY_MENU   348
    #define     GLFW_KEY_LAST   GLFW_KEY_MENU

修飾鍵定義

#define     GLFW_MOD_SHIFT   0x0001
#define     GLFW_MOD_CONTROL   0x0002
#define     GLFW_MOD_ALT   0x0004
#define     GLFW_MOD_SUPER   0x0008
#define     GLFW_MOD_CAPS_LOCK   0x0010
#define     GLFW_MOD_NUM_LOCK   0x0020

鍵值轉(zhuǎn)換為掃描碼

  • 使用函數(shù)
  1. glfwGetKeyScancode函數(shù)說明
int glfwGetKeyScancode  (   int     key )   

獲取鍵值的狀態(tài)

  • 獲取某個(gè)鍵在制定窗體最后的狀態(tài),用來判定一個(gè)鍵是否按下,還是釋放:glfwGetKey
  1. glfwGetKey函數(shù)說明

int glfwGetKey  (   
    GLFWwindow *    window,
    int     key 
)   
  1. GLFW_STICKY_KEYS粘附鍵設(shè)置

    • 如果模式是GLFW_STICKY_KEYS,則該值必須為GLFW_TRUE才能啟用粘滯鍵,或者GLFW_FALSE才能禁用該模式。

    • 如果啟用了粘滯鍵,按鍵將確保下次調(diào)用glfwGetKey時(shí)返回GLFW_PRESS,即使在調(diào)用之前已釋放該鍵。當(dāng)您只關(guān)心按鍵是否已按下,而不關(guān)心按鍵的時(shí)間或順序時(shí),這一點(diǎn)非常有用。

    • 設(shè)置輸入模式使用:glfwSetInputMode

  2. glfwSetInputMode函數(shù)說明:


void glfwSetInputMode   (   
    GLFWwindow *    window,
    int     mode,
    int     value )     

  • 其中的mode定義只能是如下值:
    • GLFW_CURSOR:這個(gè)只能設(shè)置為:GLFW_CURSOR_NORMAL,GLFW_CURSOR_HIDDEN,GLFW_CURSOR_DISABLED。
    • GLFW_STICKY_KEYS,
    • GLFW_STICKY_MOUSE_BUTTONS,
    • GLFW_LOCK_KEY_MODS,
    • GLFW_RAW_MOUSE_MOTION

文件輸入

  • 使用glfwSetCharCallback函數(shù)實(shí)現(xiàn)文本輸入,既輸入的是文本,包含unicode字符(一般是UTF-8編碼)。
  1. glfwSetCharCallback函數(shù)說明:
GLFWcharfun glfwSetCharCallback (   
    GLFWwindow *    window,
    GLFWcharfun     cbfun 
)   
  1. 回調(diào)函數(shù)GLFWcharfun原型說明

typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int)

  1. 文本輸入的例子代碼
    • 包含UTF-8字符的輸出;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <sstream>
using namespace std;

// 把codeppint轉(zhuǎn)換為native字符。
void utf8chr(int cp, char c[5]){  //一個(gè)unicode最多占5個(gè)字節(jié)。
    // char c[5]={ 0x00,0x00,0x00,0x00,0x00 };
    if (cp<=0x7F) {   // 127的常規(guī)字符
        c[0] = cp;    
    }
    else if(cp<=0x7FF) {   
        c[0] = (cp>>6)+192; 
        c[1] = (cp&63)+128; 
    }
    else if(0xd800<=cp && cp<=0xdfff) {
        // 無效utf-8的codepoint區(qū)
    } //invalid block of utf8
    else if(cp<=0xFFFF) { 
        c[0] = (cp>>12)+224; 
        c[1]= ((cp>>6)&63)+128; 
        c[2]=(cp&63)+128; }
    else if(cp<=0x10FFFF) { 
        c[0] = (cp>>18)+240; 
        c[1] = ((cp>>12)&63)+128; 
        c[2] = ((cp>>6)&63)+128; 
        c[3]=(cp&63)+128; 
    }
}

void cb_char(GLFWwindow *win, unsigned int ch){
    char c[5]={ 0x00,0x00,0x00,0x00,0x00 };  // 一個(gè)unicode字符最多4字節(jié),包含一個(gè)空終止符。
    utf8chr(ch, c);
    printf("輸入的字符:%s\n", c);
}


int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    glfwSetCharCallback (window, cb_char);  
    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){


        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl04_char.cpp  -lglfw -lglew -framework opengl

  • 其中utf8chr函數(shù)是實(shí)現(xiàn)把codepoint轉(zhuǎn)換為本地字符串。
    • codepoint轉(zhuǎn)換為本地字符串最多4字節(jié)就是int32整數(shù),當(dāng)然使用5的長(zhǎng)度是保證最后那個(gè)NULL字符。

鍵的名字

  • 上面對(duì)codepint解碼,如果不了解codeoint與unicode,不了解utf-8的編碼規(guī)則,一般不太容易理解。
  • GLFW提供函數(shù)處理:glfwGetKeyName
  1. glfwGetKeyName函數(shù)說明
const char* glfwGetKeyName  (   
    int     key,
    int     scancode 
)       
  • 如果key是GLFW_KEY_UNKNOWN,則對(duì)scancode解釋。對(duì)key解釋,則scancode為0。
  1. glfwGetKeyName函數(shù)使用例子
// glfwSetKeyCallback(window, cb_key);
void cb_key(GLFWwindow * win, int key, int code, int action, int mods){
    const char *str_ch = glfwGetKeyName(key, code);
    printf("glfwGetKeyName:%s\n", str_ch);

}

鼠標(biāo)事件

光標(biāo)位置

  • 鼠標(biāo)的光標(biāo)位置通過回調(diào)傳遞,回調(diào)函數(shù)通過函數(shù)glfwSetCursorPosCallback設(shè)置;
  • 也可以使用函數(shù)glfwGetCursorPos直接獲取鼠標(biāo)位置。
  1. glfwSetCursorPosCallback函數(shù)說明

GLFWcursorposfun glfwSetCursorPosCallback   (   
    GLFWwindow *    window,
    GLFWcursorposfun    cbfun 
)   
  1. 回調(diào)函數(shù)GLFWcursorposfun的原型說明

typedef void(* GLFWcursorposfun) (GLFWwindow *, double, double)

  1. glfwGetCursorPos函數(shù)說明
void glfwGetCursorPos   (   
    GLFWwindow *    window,
    double *    xpos,
    double *    ypos 
)   

光標(biāo)模式

  • glfwSetInputMode函數(shù)可以控制鼠標(biāo)光標(biāo)模式

void glfwSetInputMode   (   
    GLFWwindow *    window,
    int     mode,
    int     value 
)   
  • 其中mode設(shè)置為光標(biāo)的模式,光標(biāo)模式包含3個(gè)值
    • GLFW_CURSOR,其值為:
      • GLFW_CURSOR_NORMAL:正常
      • GLFW_CURSOR_HIDDEN:隱藏
      • GLFW_CURSOR_DISABLED:隱藏和抓取光標(biāo),提供虛擬和無限的光標(biāo)移動(dòng)。

鼠標(biāo)原生動(dòng)作

  • 禁用光標(biāo)時(shí),可以啟用原生(未縮放和未加速)鼠標(biāo)運(yùn)動(dòng)(如果可用)。

  • 原生鼠標(biāo)運(yùn)動(dòng)更接近鼠標(biāo)在曲面上的實(shí)際運(yùn)動(dòng)。它不受應(yīng)用于桌面光標(biāo)運(yùn)動(dòng)的縮放和加速的影響。該處理適用于光標(biāo),而原生運(yùn)動(dòng)更適合控制例如3D相機(jī)。因此,只有在禁用光標(biāo)時(shí)才提供原生鼠標(biāo)運(yùn)動(dòng)。

  • 調(diào)用glfwRawMouseMotionSupported函數(shù)檢查當(dāng)前機(jī)器是否提供原始運(yùn)動(dòng),并將GLFW_RAW_MOUSE_MOTION輸入模式設(shè)置為啟用。

  • 默認(rèn)情況下禁用。

光標(biāo)位置與模式的使用例子

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

void cb_pos(GLFWwindow *win, double x, double y){
    char title[50];
    bzero(title, sizeof(title));
    sprintf(title, "坐標(biāo):(%8.2f,%8.2f)", x, y);
    glfwSetWindowTitle(win, title);

    double xpos, ypos;
    glfwGetCursorPos(win, &xpos, &ypos);   //與上面?zhèn)鬟f的位置完全一樣。
    printf("坐標(biāo):(%8.2f,%8.2f)\n", xpos, ypos);
}


int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    // 鼠標(biāo)光標(biāo)模式
    // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
    if (glfwRawMouseMotionSupported()){
        printf("原生鼠標(biāo)模式\n");
        glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
        
    }else{
        printf("原生不支持鼠標(biāo)模式\n");
    }
    // 處理事件
    glfwSetCursorPosCallback(window, cb_pos);
    glfwMakeContextCurrent(window); 
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){
        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl06_cursor.cpp  -lglfw -lglew -framework opengl

光標(biāo)對(duì)象

創(chuàng)建光標(biāo)

  • 光標(biāo)對(duì)象是一個(gè)結(jié)構(gòu)體
    • typedef struct GLFWcursor GLFWcursor

創(chuàng)建標(biāo)準(zhǔn)光標(biāo)

  • 創(chuàng)建標(biāo)準(zhǔn)光標(biāo)使用glfwCreateStandardCursor函數(shù)
  1. glfwCreateStandardCursor函數(shù)說明

    GLFWcursor* glfwCreateStandardCursor(int  shape)    

  • 創(chuàng)建好的光標(biāo)使用下面的設(shè)置光標(biāo)函數(shù)設(shè)置即可使用。
  1. 標(biāo)準(zhǔn)光標(biāo)類型
    #define     GLFW_ARROW_CURSOR   0x00036001
    #define     GLFW_IBEAM_CURSOR   0x00036002
    #define     GLFW_CROSSHAIR_CURSOR   0x00036003
    #define     GLFW_HAND_CURSOR   0x00036004
    #define     GLFW_HRESIZE_CURSOR   0x00036005
    #define     GLFW_VRESIZE_CURSOR   0x00036006       

創(chuàng)建定制光標(biāo)

  • 自定義光標(biāo)是使用glfwCreateCursor函數(shù)創(chuàng)建的,它返回創(chuàng)建的光標(biāo)對(duì)象的句柄。
  1. glfwCreateCursor函數(shù)說明

GLFWcursor* glfwCreateCursor    (   
    const GLFWimage *   image,
    int     xhot,
    int     yhot    //光標(biāo)的參照點(diǎn)(熱點(diǎn)hotspot)
)   

釋放光標(biāo)

  • 使用glfwDestroyCursor函數(shù)釋放光標(biāo)

    void glfwDestroyCursor  (   GLFWcursor *    cursor  )   

設(shè)置窗體光標(biāo)

  • 當(dāng)創(chuàng)建好光標(biāo)后,就可以設(shè)置光標(biāo)來使用,該函數(shù)為glfwSetCursor
  1. glfwSetCursor函數(shù)說明

void glfwSetCursor  (   
    GLFWwindow *    window,
    GLFWcursor *    cursor 
)   

使用光標(biāo)對(duì)象的例子

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



int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    // 創(chuàng)建光標(biāo)對(duì)象
    GLFWcursor  *cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);

    // 創(chuàng)建一個(gè)定制光標(biāo)
    unsigned char pixels[16 * 16 * 4];  // 光標(biāo)的圖像數(shù)據(jù)
    memset(pixels, 0xff, sizeof(pixels));  // 圖像結(jié)構(gòu)體
    GLFWimage image;
    image.width = 16;
    image.height = 16;
    image.pixels = pixels;
    GLFWcursor* c_cursor = glfwCreateCursor(&image, 0, 0);  // 使用圖像創(chuàng)建光標(biāo)

    // 設(shè)置光標(biāo)
    // glfwSetCursor(window, cursor);
    glfwSetCursor(window, c_cursor);
    // 釋放光標(biāo)
    // glfwDestroyCursor(cursor);     // 釋放光標(biāo),光標(biāo)恢復(fù)成缺省光標(biāo)
    glfwMakeContextCurrent(window); 
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){
        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl07_cursor_object.cpp  -lglfw -lglew -framework opengl

光標(biāo)進(jìn)出窗體事件

  • 光標(biāo)進(jìn)出狀態(tài)通過兩種方式:
    • 回調(diào)的事件方式:glfwSetCursorEnterCallback
    • 查詢獲取方式:glfwGetWindowAttrib + GLFW_HOVERED;
  1. glfwSetCursorEnterCallback函數(shù)說明

GLFWcursorenterfun glfwSetCursorEnterCallback   (   
    GLFWwindow *    window,
    GLFWcursorenterfun  cbfun 
)   
  1. 回調(diào)函數(shù)GLFWcursorenterfun原型說明

typedef void(* GLFWcursorenterfun) (GLFWwindow *, int)
    
    // 第二個(gè)參數(shù)是GLFW_TRUE:進(jìn),否則GLFW_FALSE:出

鼠標(biāo)按鈕輸入

鼠標(biāo)按鈕事件處理

  • 這是通過回調(diào)函數(shù)的方式實(shí)現(xiàn):glfwSetMouseButtonCallback
  1. glfwSetMouseButtonCallback函數(shù)說明
GLFWmousebuttonfun glfwSetMouseButtonCallback   (   
    GLFWwindow *    window,
    GLFWmousebuttonfun  cbfun 

  1. GLFWmousebuttonfun回調(diào)函數(shù)原型說明
typedef void(* GLFWmousebuttonfun) (GLFWwindow *, int, int, int)
        // 第二個(gè)參數(shù):button
        // 第三個(gè)參數(shù):action:GLFW_PRESS 或者 GLFW_RELEASE
        // 第四個(gè)參數(shù):mods:輔助鍵狀態(tài)

  1. 鼠標(biāo)按鈕定義
    #define     GLFW_MOUSE_BUTTON_1   0

    #define     GLFW_MOUSE_BUTTON_2   1

    #define     GLFW_MOUSE_BUTTON_3   2

    #define     GLFW_MOUSE_BUTTON_4   3

    #define     GLFW_MOUSE_BUTTON_5   4

    #define     GLFW_MOUSE_BUTTON_6   5

    #define     GLFW_MOUSE_BUTTON_7   6

    #define     GLFW_MOUSE_BUTTON_8   7

    #define     GLFW_MOUSE_BUTTON_LAST   GLFW_MOUSE_BUTTON_8

    #define     GLFW_MOUSE_BUTTON_LEFT   GLFW_MOUSE_BUTTON_1

    #define     GLFW_MOUSE_BUTTON_RIGHT   GLFW_MOUSE_BUTTON_2

    #define     GLFW_MOUSE_BUTTON_MIDDLE   GLFW_MOUSE_BUTTON_3
 

鼠標(biāo)按鈕的輪詢

  • 就是鼠標(biāo)輸入的另外一種方式:輪詢,不是聽過事件;而是通過函數(shù)調(diào)用來查詢狀態(tài)。
    • 查詢函數(shù)是:glfwGetMouseButton
  1. glfwGetMouseButton函數(shù)說明
int glfwGetMouseButton  (   
    GLFWwindow *    window,
    int     button 
)   
  • 返回值是:

    • GLFW_PRESS :按下過;
    • GLFW_RELEASE:沒有按下過;
  • 參數(shù)button就是需要對(duì)按下判定的按鈕。

  1. 為了防止在輪詢的時(shí)候,按下動(dòng)作已經(jīng)完成,這樣輪詢?nèi)菀族e(cuò)失那次鼠標(biāo)按鈕操作,解決這個(gè)問題與鍵盤的處理一樣,通過設(shè)置輸入模式來解決。
    • glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GLFW_TRUE);

鼠標(biāo)滾輪輸入

  • 鼠標(biāo)滾輪事件也是回調(diào)函數(shù)的方式來實(shí)現(xiàn)輸入與處理。
    • 函數(shù)是:glfwSetScrollCallback
  1. glfwSetScrollCallback 函數(shù)說明
GLFWscrollfun glfwSetScrollCallback (   
    GLFWwindow *    window,
    GLFWscrollfun   cbfun 
)   
  1. 回調(diào)函數(shù)GLFWscrollfun原型說明
    typedef void(* GLFWscrollfun) (GLFWwindow *, double, double)

鼠標(biāo)進(jìn)出、滾輪與按鈕事件的例子

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

// 鼠標(biāo)進(jìn)出回調(diào)觸發(fā)函數(shù)
void cursor_enter_callback(GLFWwindow *win, int enter_or_leave){
    if (enter_or_leave){
        printf("鼠標(biāo)進(jìn)入!\n");
    }
    else{
        printf("鼠標(biāo)出去!\n");
    }
}

// 鼠標(biāo)按鈕
void mouse_button_callback(GLFWwindow *win, int button, int action, int mods){
    printf("鼠標(biāo)按鈕:button=%d,action=%d,mods=%d\n", button, action, mods);
}

// 鼠標(biāo)滾輪
void scroll_callback(GLFWwindow *win, double xoffset, double yoffset){
    printf("鼠標(biāo)滾輪:xoffset=%8.2f,yoffset=%8.2f\n", xoffset, yoffset);
}


int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 

    // 鼠標(biāo)的粘附輸入模式
    glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GLFW_TRUE);

    // 鼠標(biāo)進(jìn)出判定 
    glfwSetCursorEnterCallback(window, cursor_enter_callback);

    // 鼠標(biāo)按鈕操作判定
    glfwSetMouseButtonCallback(window, mouse_button_callback);

    // 鼠標(biāo)滾輪
    glfwSetScrollCallback(window, scroll_callback);
    
    glfwMakeContextCurrent(window); 
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){

        // move輪詢
        if (glfwGetWindowAttrib(window, GLFW_HOVERED)){
            printf("輪詢:進(jìn)入\n");
        }
        else{
            printf("輪詢:出去\n");
        }

        //按鍵輪詢
        int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
        if(state == GLFW_PRESS){
            printf("左鍵按下!\n");
        }

        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl08_button_scroll_move.cpp  -lglfw -lglew -framework opengl

文件刪除事件

  • 一旦用戶刪除文件,可以通過函數(shù)glfwSetDropCallback處理;
  1. glfwSetDropCallback函數(shù)說明
GLFWdropfun glfwSetDropCallback (   
    GLFWwindow *    window,
    GLFWdropfun     cbfun 
)   
  1. 回調(diào)函數(shù)GLFWdropfun原型說明

typedef void(* GLFWdropfun) (GLFWwindow *, int, const char **)
        // 第二個(gè)參數(shù):count:刪除文件個(gè)數(shù)
        // 第三個(gè)參數(shù):paths:返回刪除的文件列表

時(shí)間計(jì)時(shí)

  • GLFW提供四個(gè)與時(shí)間有關(guān)的函數(shù):
    • glfwGetTime:獲取從glfwInit初始化以來的時(shí)間,單位是秒;
    • glfwSetTime:修改從glfwInit初始化以來的時(shí)間,單位是秒;
    • glfwGetTimerValue:獲取真實(shí)的定時(shí)器的時(shí)間值,單位是\dfrac{1}{frequency}秒;
    • glfwGetTimerFrequency:獲取時(shí)間頻率;
  • 注意:
    • 四個(gè)函數(shù)比較簡(jiǎn)單,這里不詳細(xì)說明,下面是使用例子。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

int main(int argc, char const *argv[]){
    // 初始化
    glfwInit();
            // 1. 初始化opengl

    // 創(chuàng)建窗體
    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL的UI窗體", NULL, NULL); 
    
    glfwMakeContextCurrent(window); 
    if (glewInit() != GLEW_OK){
        printf("OpenGL初始化失敗:glew\n");
        exit(-1);
    }
    while (! glfwWindowShouldClose(window)){
        double seconds = glfwGetTime();
        uint64_t value = glfwGetTimerValue();
        uint64_t freqency = glfwGetTimerFrequency();
        printf("相對(duì)時(shí)間:%8.2f,真實(shí)時(shí)間:%lld,頻率:%lld\n", seconds, value, freqency);

        glfwSetTime(0.0);

        // 3. 設(shè)置清屏顏色
        glClearColor(0.0f, 0.6f, 0.6f, 1.0f);
        // 4. 清屏
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwWaitEvents(); 
    }
    // 釋放
    glfwTerminate();
    return 0;
}

// 編譯命令:g++ -omain  gl09_timer.cpp  -lglfw -lglew -framework opengl


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容