GLFW--Getting started
這篇文章是GLFW使用的簡介。算是翻譯吧:原文在here
Step by step
包含頭文件
在使用OpenGL或GLFW工程源文件里需要包含GLFW3頭文件。
#include <GLFW/glfw3.h>
這個頭文件中定義了GLFW API所有的常量,類型和函數原型,同時也包含了OpenGL頭文件并定義了在本系統平臺上需要用到的所有常量和類型。
例如:在windows平臺下,通常要求在GL/gl.h之前包含windows.h,這使得源文件與Windows綁定在一起,同時會將整個Win32 API與代碼空間混淆。
然后,其實不用包含windows.h,GLFW頭文件就會處理這些問題。GLFW并不是簡單的復制windows.h文件,而是使用它的一部分而已。所以,當在源文件里包含了windows.h的時候,GLFW頭文件就不會試著去重定義那些符號了(those symbols)。
也就是說:
- 不要包含OpenGL頭文件,GLFW會為你包含的
- 不要包含
windows.h頭文件或者與系統相關的頭文件,除非你想直接使用這些API。 - 如果確實需要包含這些頭文件,那么要在GLFW之前把他們包含進去,以便能先檢測到這些頭文件。
從3.0版本開始,GLU頭文件glu.h就不再是默認包含了。如果要使用,需要在GLFW頭文件之前定義GLFW_INCLUDE_GLU
#definne GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>
初始化和終止GLFW
在使用GLFW之前要對其進行初始化,初始化成功返回GL_TRUE,如果有錯誤則返回GL_FALSE。
if(!glfwInit())exit(EXIT_FAILURE);
GLFW使用完成之后,在應用退出之前要終止GLFW
glfwTerminate();
設置錯誤回調函數(error callback)
大多數事件是由回調報告,比如某個鍵是否按下,GLFW窗口是否被移動,錯誤是否產生。回調(Callback)是簡單地C函數(或者C++靜態方法)。這些回調由帶有描述事件的參數的GLFW調用。
如果GLFW函數調用失敗,那么錯誤就會報告給GLFW的粗無回調函數(error callback)。你可以收到帶有錯誤回調的報告。函數必須要有如下的簽名(signature)。這個簡單的錯誤回調函數只是簡單的把錯誤描述打印到stderr。
void error_callback(int error, const char *description)
{fputs(description, stderr);
}
必須設置回調函數,這樣GLFW才能調用他們。錯誤回調函數是GLFW函數初始化之前要調用的函數的一部分,這樣在初始化時和初始化之后顯示出錯誤。
glfwSetErrorCallback(error_callback);
創建窗口和上下文(Context)
利用一個調用就可以創建一個窗口和它的上下文,并返回一個句柄(Handle)。例如,如下創建一個640x480的窗口和OpenGL 上下文
GLFWwindow *window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);
如果窗口和上下文創建失敗就返回NULL,所以要檢測其返回值。
if(!window)
{glfwTerminate();exit(EXIT_FAILURE);
}
窗口句柄會傳遞給所有與window相關的函數和所有與window相關的調用,這樣就可以決定哪個window接受消息。
當不需要窗口是,就銷毀它。
glfwDestoryWindow(window);
設置OpenGL的上下文
在使用OpenGL API之前,必須設置OpenGL上下文環境。
glfwMakeContextCurrent(window);
檢測窗口關閉標志
每個窗口都有標志指示一個窗口是否應該關閉。
當用戶試圖關閉窗口(不管是點擊標題欄上的關閉部件還是使用混合鍵Alt+F4),這個標志就會置1。注意:此時窗口并沒有真正關閉,所以要檢測這個標志或者由這個標志銷毀窗口或者給用戶一些反饋信息。
while(!glfwWindowShouldClose(window))
{//keep running
}
當用戶要關閉窗口時可以通過glfwSetWindowCloseCallBack設置一個關閉回調函數(Close Callback)來通知用戶。當關閉標志置1時立刻調用關閉回調函數。
接收輸入事件
每個窗口都有很多回調函數用來接收各種各樣事件。為了接收鍵盤按鍵和釋放的事件,可以創建一個按鍵回調函數。
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);
}
同其他窗口相關的調用一樣,每個窗口都有對應按鍵回調函數。
glfwSetKeyCallback(window, key_callback);
當事件產生時,為了事件回調函數能夠被調用,應該按如下方法處理事件。
與OpenGL一起渲染
當有了OpenGL上下文環境之后,就可以正常的使用OpenGL了。在這個教程里,將會繪制一個多顏色的三角形。為了使用glViewport要獲取幀緩沖區的大小
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0,0, width, height);
讀計時器
為了創建平滑的動畫,需要time source. GLFW 提供一個計時器可以返回開始初始化到當前的時間間隔。time source 是系統最精確的通常是毫秒或者是微妙。
double time = glfwGetTime();
交換緩沖區(Swapping buffers)
GLFW默認使用雙緩沖區,這表示每個窗口都有兩個渲染緩沖區:前緩沖區和后緩沖區;前緩沖區是正在繪制的緩沖區,后緩沖區是等待繪制的緩沖區。
當一個幀繪制完成后,兩個緩沖區需要交換,此時后緩沖區變為前緩沖區,反之亦然。
glfwSwaBuffers(window);
交換間隔是指要交換兩個緩沖區之間的幀數,即vsync。默認情況下,交換間隔為0,即交換會立刻進行。在很快的一些機器上,不會看到這些幀,因為屏幕始終以60-70/s的速度更新,這會浪費很多CPU或GPU周期。
同樣,因為緩沖區交換發生在屏幕更新中間,就會造成屏幕撕裂問題screen tearing
由于這個原因,應用通常會把交換間隔設置為1。也可以設置更高的值,但是通常不建議這樣,因為這會導致輸入延遲。
glfwSwapInterval(1);
處理事件
GLFW需要和窗口系統經常交流,為了接收事件和顯示應用沒有鎖住。在有可見窗口時必須進行事件處理,通常在每幀緩沖區交換后。
有兩種方法處理掛起事件(pending event):輪詢(polling)和等待(waiting)。這個例子將會使用輪詢,即僅僅在已經接收到事件時處理并立即返回。
glfwPollEvents();
在連續繪制時這是最好的選擇,大多數游戲也是這樣做的。如果你僅僅在接收到新的輸入時需要這樣做,那么glfwWaitEvents是個更好的選擇。它等待至少接收到一個事件,將線程設置為休眠狀態,并處理所有接收到的事件。這樣做會節省大量的CPU周期,通常用于編輯工具。
總結Demo
現在,你已經知道了如何初始化GLFW、創建窗口并輪詢鍵盤輸入。此時,可以創建一個簡單的程序。
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
static void error_callback(int error, const char* description)
{fputs(description, stderr);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);
}
int main(void)
{GLFWwindow* window;glfwSetErrorCallback(error_callback);if (!glfwInit())exit(EXIT_FAILURE);window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);if (!window){glfwTerminate();exit(EXIT_FAILURE);}glfwMakeContextCurrent(window);glfwSwapInterval(1);glfwSetKeyCallback(window, key_callback);while (!glfwWindowShouldClose(window)){float ratio;int width, height;glfwGetFramebufferSize(window, &width, &height);ratio = width / (float) height;glViewport(0, 0, width, height);glClear(GL_COLOR_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);glBegin(GL_TRIANGLES);glColor3f(1.f, 0.f, 0.f);glVertex3f(-0.6f, -0.4f, 0.f);glColor3f(0.f, 1.f, 0.f);glVertex3f(0.6f, -0.4f, 0.f);glColor3f(0.f, 0.f, 1.f);glVertex3f(0.f, 0.6f, 0.f);glEnd();glfwSwapBuffers(window);glfwPollEvents();}glfwDestroyWindow(window);glfwTerminate();exit(EXIT_SUCCESS);
}
?
總結
以上是生活随笔為你收集整理的GLFW--Getting started的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++关于map的find和count的
- 下一篇: c++ Lambda