From 6cfd1710de34881b871b6b94a26e3aefc4174226 Mon Sep 17 00:00:00 2001 From: Meow J Date: Mon, 15 Jun 2015 22:37:29 +0800 Subject: [PATCH 1/4] Test --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c51dce9..9c5434b 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ learnopengl.com系列教程的中文翻译,目前正在翻译中。 ####关于如何认领翻译? -由于我们的志愿者来自五湖四海, -为了避免冲突。请志愿者们先fork Geequlim/LearnOpenGL-CN。同步到本地后找到要翻译的文章,创建一个如下所示的只包含作者、翻译者和原文链接信息的markdown文件并提交发布请求: +由于我们的志愿者来自五湖四海,为了避免冲突。请志愿者们先fork Geequlim/LearnOpenGL-CN。同步到本地后找到要翻译的文章,创建一个如下所示的只包含作者、翻译者和原文链接信息的markdown文件并提交发布请求: 本文作者JoeyDeVries,由Geequlim翻译自http://learnopengl.com From 415d882c2cc1a96add1568b93201a9a5cfe5fe98 Mon Sep 17 00:00:00 2001 From: Geequlim Date: Mon, 15 Jun 2015 23:02:46 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9ReadMe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c5434b..eee54c1 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ learnopengl.com系列教程的中文翻译,目前正在翻译中。 --- ###翻译组成员请注意 -####关于如何认领翻译? +####如何认领翻译? -由于我们的志愿者来自五湖四海,为了避免冲突。请志愿者们先fork Geequlim/LearnOpenGL-CN。同步到本地后找到要翻译的文章,创建一个如下所示的只包含作者、翻译者和原文链接信息的markdown文件并提交发布请求: +由于我们的志愿者来自五湖四海,为了避免冲突。请志愿者们先clone这个Repository 。同步到本地后找到要翻译的文章,创建一个如下所示的只包含作者、翻译者和原文链接信息的MarkDown文件: 本文作者JoeyDeVries,由Geequlim翻译自http://learnopengl.com @@ -18,4 +18,6 @@ learnopengl.com系列教程的中文翻译,目前正在翻译中。 05 Advanced Lighting/03 Shadows/02 Point Shadows.md +加入LearnOpenGL-CN组织,然后提交并push您的文章。 + 欢迎志愿者们加入翻译组交流QQ群:383745868 \ No newline at end of file From 4582ceb007d9afdc487f0b3f2485741d760c7b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gjy=5F=E7=AE=A1?= Date: Tue, 16 Jun 2015 01:05:09 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=88=9D=E7=BF=BB=E5=AE=8C=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E7=AB=A0=E7=AC=AC=E4=BA=8C=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01 Getting started/01 OpenGL.md | 1 - 01 Getting started/02 Creating a window.md | 145 +++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 01 Getting started/02 Creating a window.md diff --git a/01 Getting started/01 OpenGL.md b/01 Getting started/01 OpenGL.md index 4cd6cf8..46b1695 100644 --- a/01 Getting started/01 OpenGL.md +++ b/01 Getting started/01 OpenGL.md @@ -2,7 +2,6 @@ ##OpenGL -未翻译完成... --- 在进行这段旅程之前我们先解释下OpenGL到底是什么。它一般被认为是一个**应用程序编程接口**(API),包含了一系列可以操作图形、画像的方法。然而,OpenGL本身并不是一个API,仅仅是一个规范,由[Khronos组织](http://www.khronos.org/)制定并维护。 diff --git a/01 Getting started/02 Creating a window.md b/01 Getting started/02 Creating a window.md new file mode 100644 index 0000000..389ae1f --- /dev/null +++ b/01 Getting started/02 Creating a window.md @@ -0,0 +1,145 @@ +本文作者JoeyDeVries,由gjy_1992翻译自[http://learnopengl.com](http://learnopengl.com/#!Getting-started/Creating-a-window) + +##创建一个窗口 + +在我们画出出色的效果之前,首先要做的就是创建一个OpenGL上下文和一个用于显示的窗口。然而,这些操作是操作系统相关的,OpenGL的目的是从这些操作中抽象出公共的部分。这意味着我们只得自己去处理创建窗口,定义OpenGL上下文以及处理用户输入。 + +幸运的是,有一些库已经提供了我们所需的功能,一部分是特别针对OpenGL的。这些库节省了我们书写平台相关代码的时间,提供给我们一个窗口和上下文用来渲染。最流行的几个库有GLUT,SDL,SFML和GLFW。在我们的教程里使用GLFW。 + +##GLFW + +GLFW是一个C库,专门针对OpenGL,提供了一些渲染物件所需的最低限度的接口。它允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入。 + +这一节和下一节的内容是建立GLFW环境,并成功用它来创建窗口和OpenGL上下文。本教程会一步步从获取,编译,链接GLFW库讲起。我们使用Microsoft Visual Studio 2012 **IDE**(集成开发环境),如果你用的不是它请不要担心,大多数IDE上的步骤都是类似的。Visual Studio 2012(或其他版本)可以从微软网站上免费下载(选择express版本或community版本)。 + +##生成GLFW + +GLFW可以从它们网站的[下载页](http://www.glfw.org/download.html)上获取。GLFW已经有针对Visual Studio 2012/2013的预编译的二进制版本和相应的头文件,但是为了完整性我们将从编译源代码开始,所以需要下载**源代码包**。 + + +
+当你下载二进制版本时,请下载32位的版本而不是64位的除非你清楚你在做什么。64位版本被报告出现很多奇怪的问题。 +
+ + +一旦下载完了源码包,解压到某处。我们只关心里面的这些内容: + +-编译生成的库 +-**include**文件夹 + +从源代码编译库可以保证生成的目标代码是针对你的操作系统和CPU的,而一个预编译的二进制代码并不保证总是适合。提供源代码的一个问题是不是每个人都用相同的IDE来编译,因而提供的工程文件可能和一些人的IDE不兼容。所以人们只能从.cpp和.h文件来自己建立工程,这是一项笨重的工作。因此诞生了一个叫做CMake的工具。 + +##CMake + +CMake是一个工程文件生成工具,可以使用预定义好的CMake脚本,根据用户的选择生成不同IDE的工程文件。这允许我们从GLFW源码里创建一个Visual Studio 2012工程文件。首先,我们需要从[这里](http://www.cmake.org/cmake/resources/software.html)下载安装CMake。我们选择Win32安装程序。 + +一旦CMake安装成功,你可以选择从命令行或者GUI启动CMake,为了简易我们选择后者。CMake需要一个源代码目录和一个存放编译结果的目标文件目录。源代码目录我们选择GLFW的源代码的根目录,然后我们新建一个_build_文件夹来作为目标目录。 + +![](http://learnopengl.com/img/getting-started/cmake.png) + +之后,点击Configure(设置)按钮,我们选择生成的目标平台为Visual Studio 11(因为Visual Studio 2012的内部版本号是11.0)。CMake会显示可选的编译选项,这里我们使用默认设置,再次点击Configure(设置)按钮,保存这些设置。保存之后,我们可以点击Generate(生成)按钮,生成的工程文件就会出现在你的_build_文件夹中。 + +##编译 + +在_build_文件夹里可以找到GLFW.sln文件,用Visual Studio 2012打开。因为CMake已经配置好了项目所以我们直接点击**生成解决方案**然后编译的结果glfw3.lib就会出现在src/Debug文件夹内。(注意我们用的是glfw的版本3) + +生成库之后,我们需要让IDE知道库和include头文件的正确放置位置。有两种方法去做这件事: + +1. 找到IDE/**Compiler**(编译器)的/lib和/include文件夹然后把glfw3.lib所在目录和include文件夹复制进去。这不是推荐的方式,因为很难去追踪library/include文件夹,而且重新安装IDE/Compiler可能会导致文件丢失。 +2. 推荐的方式是建立一个新的目录包含所有的第三方库文件和头文件,并且在你的IDE/Compiler中指定这些文件夹。我个人使用一个单独的文件夹包含Libs和Include文件夹,在这里存放OpenGL工程用到的所有第三方库和头文件。这样我的所有第三方库都在同一个路径(并且应该在你的多台电脑间共享),然而要求是每次新建一个工程我们都需要告诉IDE/Compiler这些目录是什么。 + +完成上面步骤后,我们就可以使用GLFW创建我们的第一个OpenGL工程了! + +##我们的第一个工程 + +现在,让我们打开Visual Studio,创建一个新的工程。如果提供了多个选项,选择Visual C++,然后选择**空工程**(Empty Project),别忘了给你的工程起一个合适的名字。现在我们有了一个空的工程去创建我们的OpenGL程序。 + +##链接 + +为了使我们的程序使用GLFW,我们需要把GLFW库链接进工程。于是我们需要在链接器的设置里写上glfw3.lib。但是我们的工程还不知道在哪寻找这个文件于是我们首先需要将我们放第三方库的目录添加进设置。 + +为了添加这些目录,我们首先进入project properties(工程属性)(在解决方案窗口里右键项目),然后选择VC++ Directories选项卡(如下图)。在下面的两栏添加目录: + +![](http://learnopengl.com/img/getting-started/vc_directories.png) + +从这里你可以把自己的目录加进去从而工程知道从哪去寻找库文件和头文件。可以手动把目录加在后面,也可以点Edit按钮,出现下图: + +![](http://learnopengl.com/img/getting-started/include_directories.png) + +这里可以添加任意多个目录,IDE会从这些目录里寻找头文件。所以一旦你将GLFW的文件夹加进路径中,你就可以使用来引用头文件。库文件也是一样的。 + +现在VS可以找到我们链接GLFW需要的所有文件了。最后需要在Linker(链接器)选项卡里的Input选项卡里添加glfw3.lib这个文件: + +![](http://learnopengl.com/img/getting-started/linker_input.png) + +要链接一个库必须指定它的文件名。于是我们在Additional Dependencies域添加这个文件。这样GLFW就会被链接进我们的工程。除了GLFW,根据系统的不同可能还要链接OpenGL库。 + +###Windows上的OpenGL库 + +如果你是Windows平台,opengl32.lib已经随着Microsoft SDK装进了Visual Studio的默认目录,所以Windows上我们只需将opengl32.lib添加进Additional Dependencies。 + +###Linux上的OpenGL库 + +在Linux下你需要链接libGl.so,所以要添加-lGL到你的链接器设置里。如果找不到这个库你可能需要安装Mesa,NVidia 或AMD的开发包,这部分因平台而异就不仔细讲解了。 + +现在,如果你添加好了GLFW和OpenGL库,你可以用如下方式添加GLFW头文件: + +```c++ + #include +``` + +这个头文件包含了GLFW的设置。 + +##GLEW + +到这里,我们仍然有一件事要做。OpenGL只是一个规范,具体的实现由显卡生产商提供。由于显卡驱动版本众多,大多数函数都无法在编译时确定下来,需要在运行时获取。开发者需要运行时获取函数地址并保存下来供以后使用。取得地址的方法因平台而异,Windows下看起来类似这样: + +```c++ +// 定义函数类型 +typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*); +// 找到正确的函数并赋值给函数指针 +GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers"); +// 现在函数可以被正常调用了 +GLuint buffer; +glGenBuffers(1, &buffer); +``` + +你可以看到代码复杂而笨重,因为我们对于每个函数都必须这样。幸运的是,有一个针对此目的的库,GLEW,是目前最流行的做这件事的方式。 + +###编译和链接GLEW + +GLEW代表OpenGL Extension Wrangler Library,管理我们上面提到的繁琐的任务。因为GLEW也是一个库,我们同样需要链接进工程。GLEW可以从[这里](http://glew.sourceforge.net/index.html)下载,你可以选择下载二进制版本或者下载源码编译。记住,优先选择32位的二进制版本。 + +我们使用GLEW的静态版本glew32s.lib(注意这里的's'),用如上的方式添加其库文件和头文件,最后在链接器的选项里加上glew32s.lib。注意GLFW3也是编译成了一个静态库。 + + +
+静态链接是指编译时就将库代码里的内容合并进二进制文件。优点就是你不需要再放额外的文件,只需要发布你最终的二进制代码文件。缺点就是你的程序会变得更大,另外当库有升级版本时,你必须重新进行编译。 +
+动态链接是指一个库通过.dll或.so的方式存在,它的代码与你的二进制文件的代码是分离的。优点是使你的程序大小变小并且更容易升级,缺点是你发布时必须带上这些dll。 +
+ + +如果你希望静态链接GLEW,必须在包含GLEW头文件之前定义预编译宏GLEW\_STATIC: + +```c++ + #define GLEW_STATIC + #include +``` + +如果你希望动态链接那么不要定义这个宏。几乎动态链接的话你需要拷贝一份dll文件到你的应用程序同目录。 + + +
+对于Linux用户建议使用这个命令行-lGLEW -lglfw3 -lGL -lX11 -lpthread -lXrandr -lXi。没有正确链接相应的库会产生undefined reference errors.(未定义的引用) +
+ + +我们现在成功编译了GLFW和GLEW库,我们将进入[下一节](http://www.learnopengl.com/#!Getting-Started/Hello-Window)(第一章第三节)去使用GLFW和GLEW来设置OpenGL上下文并创建窗口。记住确保你的头文件和库文件的目录设置正确,以及链接器里引用的库文件名正确。如果仍然遇到错误,请参考额外资源中的例子。 + +##额外的资源 + +- [Building applications](http://www.opengl-tutorial.org/miscellaneous/building-your-own-c-application/): 提供了很多编译链接相关的信息以及一大批错误的解决方法。 +- [GLFW with Code::Blocks](http://wiki.codeblocks.org/index.php?title=Using_GLFW_with_Code::Blocks):使用Code::Blocks IDE编译GLFW。 +- [Running CMake](http://www.cmake.org/runningcmake/): 简要的介绍如何在Windows和Linux上使用CMake。 +- [Writing a build system under Linux](http://learnopengl.com/demo/autotools_tutorial.txt): Wouter Verholst写的一个自动工具的教程,关于如何在Linux上建立编译环境,尤其是针对这些教程。 \ No newline at end of file From 00f41976baec78b4edf8a8b53ec0dd93fcbfac21 Mon Sep 17 00:00:00 2001 From: Geequlim Date: Tue, 16 Jun 2015 01:14:55 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=AE=8C=E6=88=90=E3=80=8AHello=20Window?= =?UTF-8?q?=E3=80=8B=E7=9A=84=E7=BF=BB=E8=AF=91=EF=BC=8C=E6=89=8B=E6=9C=BA?= =?UTF-8?q?=E6=B5=81=E9=87=8F=E4=B8=8A=E4=BC=A0=E3=80=82=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01 Getting started/03 Hello Window.md | 176 ++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 9 deletions(-) diff --git a/01 Getting started/03 Hello Window.md b/01 Getting started/03 Hello Window.md index ca9f95b..67e8fea 100644 --- a/01 Getting started/03 Hello Window.md +++ b/01 Getting started/03 Hello Window.md @@ -1,18 +1,176 @@ 本文作者JoeyDeVries,由Geequlim翻译自[http://learnopengl.com](http://learnopengl.com/#!Getting-started/Hello-Window) -上一节中我们获取到了GLFW和GLEW这两个开源库,现在我们就可以使用它们来我们创建一个OpenGL绘图窗口了。首先,新建一个 .cpp文件,然后把下面的代码粘贴到该文件的最前面。注意为之所以定义GLEW_STATIC宏,是因为我们使用GLEW的静态链接库。 +##你好,窗口 - // GLEW - #define GLEW_STATIC - #include - // GLFW - #include +上一节中我们获取到了GLFW和GLEW这两个开源库,现在我们就可以使用它们来创建一个OpenGL绘图窗口了。首先,新建一个 .cpp文件,然后把下面的代码粘贴到该文件的最前面。注意,之所以定义GLEW_STATIC宏,是因为我们使用GLEW的静态链接库。 + +```c++ +// GLEW +#define GLEW_STATIC +#include +// GLFW +#include +``` + +> 请确认在包含GLFW的头文件之前包含了GLEW的头文件。在包含glew.h头文件时会引入许多OpenGL必要的头文件(例如GL/gl.h),所以#include < GL/glew.h\>应放在引入其他头文件的代码之前。 + +接下来我们创建main函数,并做一些初始化GLFW的操作: + +```c++ +int main() +{ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + return 0; +} +``` +首先我们在main函数中调用glfwInit函数来初始化GLFW,然后我们可以使用glfwWindowHint函数来配置GLFW。glfwWindowHint函数的第一个参数表示我们要进行什么样的配置,我们可以选择大量以“GLFW\_”开头的枚举值;第二个参数接受一个整形,用来设置这个配置的值。该函数的所有的选项以及对应的值都可以在 [GLFW's window handling](http://www.glfw.org/docs/latest/window.html#window_hints) 这篇文档中找到。如果你现在编译你的cpp文件会得到大量的连接错误,这是因为你还需要设置GLFW的链接库。 -> Be sure to include GLEW before GLFW. The include file for GLEW contains the correct OpenGL header includes (like GL/gl.h) so including GLEW before other header files that require OpenGL does the trick. +由于本网站的教程都是基于OpenGL3.3以后的版本展开讨论的,所以我们需要告诉GLFW我们要使用的OpenGL版本是3.3,这样GLFW会在创建OpenGL上下文时做出适当的调整。这也可以确保用户在没有适当的OpenGL版本支持的情况下无法运行。在这里我们告诉GLFW想要的OpenGL版本号是3.3,并且不允许用户调整窗口的大小。我们明确地告诉GLFW我们想要使用核心模式(core-profile),这将导致我们无法使用那些已经废弃的API,而这不正是一个很好的提醒吗?当我们不小心用了旧功能时报错,就能避免使用一些被废弃的用法了。如果你使用的是Mac OSX系统你还需要加下面这行代码这些配置才能起作用: -> 请确认在包含GLFW头文件之前包含了GLEW, +```c++ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +``` +>请确认您的系统支持OpenGL3.3或更高版本,否则此应用有可能会崩溃或者出现不可预知的错误。可以通过运行glew附带的glxinfo程序或者其他的工具(例如[OpenGL Extension Viewer ](http://download.cnet.com/OpenGL-Extensions-Viewer/3000-18487_4-34442.html)来查看的OpenGL版本。如果您的OpenGL版本低于3.3请更新您的驱动程序或者有必要的话更新您的设备。 +接下来我们创建一个窗口对象,这个窗口对象中具有关和窗口相关的许多数据,而且会被GLFW的其他函数频繁地用到。 - +```c++ +GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr); +if (window == nullptr) +{ + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; +} +glfwMakeContextCurrent(window); + +``` + +glfwCreateWindow函数需要窗口的宽和高作为它的前两个参数;第三个参数表示只这个窗口的名称(标题),这里我们使用"LearnOpenGL",当然你可以使用你喜欢的名称;最后两个参数我们暂时忽略,先置为空指针就行。它的返回值GLFWwindow对象的指针会在其他的GLFW操作中使用到。创建完窗口我们就可以通知GLFW给我们的窗口在当前的线程中创建我们等待已久的OpenGL上下文了。 + +###GLEW + +在之前的教程中已经提到过,GLEW是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLEW。 + +```c++ +glewExperimental = GL_TRUE; +if (glewInit() != GLEW_OK) +{ + std::cout << "Failed to initialize GLEW" << std::endl; + return -1; +} +``` +请注意,我们在初始化GLEW之前设置glewExperimental变量的值为GL_TRUE,这样做能让GLEW在管理OpenGL的函数指针时更多地使用现代化的技术,如果把它设置为GL_FALSE的话可能会在使用OpenGL的核心模式(core-profile)时出现一些问题。 + +###视口(Viewport) + +在我们绘制之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小,这样OpenGL才只能知道要显示数据的窗口坐标。我们可以通过调用glViewport函数来设置这些维度: + +```c++ +glViewport(0, 0, 800, 600); +``` +前两个参数设置窗口左下角的位置。第三个和第四个参数设置渲染窗口的宽度和高度,我们设置成与GLFW的窗口的宽高大小,我们也可以将这个值设置成比窗口小的数值,然后所有的OpenGL渲染将会显示在一个较小的区域。 + +>OpenGL 使用glViewport定义的位置和宽高进行位置坐标的转换,将OpenGL中的位置坐标转换为你的屏幕坐标。例如,OpenGL中的坐标(0.5,0.5)有可能被转换为屏幕中的坐标(200,450)。注意,OpenGL只会把-1到1之间的坐标转换为屏幕坐标,因此在此例中(-1,1)转换为屏幕坐标是(0,600)。 + +###准备好你的引擎 + +我们可不希望只绘制一个图像之后我们的应用程序就关闭窗口并立即退出。我们希望程序在我们明确地关闭它之前一直保持运行状态并能够接受用户输入。因此,我们需要在程序中添加一个while循环,我们可以把它称之为游戏循环(game loop),这样我们的程序就能在我们让GLFW退出前保持运行了。下面几行的代码就实现了一个简单的游戏循环: + +```c++ +while(!glfwWindowShouldClose(window)) +{ + glfwPollEvents(); + glfwSwapBuffers(window); +} +``` + +* glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否准备好要退出,如果是这样的话该函数返回true然后游戏循环便结束了,之后为我们就可以关闭应用程序了。 +* glfwPollEvents函数检查有没有触发什么事件(比如键盘有按钮按下、鼠标移动等)然后调用对应的回调函数(我们可以手动设置这些回调函数)。我们一般在游戏循环的一开始就检查事件。 +* 调用glfwSwapBuffers会交换缓冲区(储存着GLFW窗口每一个像素颜色的缓冲区) + +>双缓冲区 + +>应用程序使用单缓冲区绘图可能会存在图像闪烁的问题。 这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。因为这些不是在瞬间显示给用户,而是通过一步一步地计算结果绘制的,这可能会花费一些时间。为了规避这些问题,我们应用双缓冲区渲染窗口应用程序。前面的缓冲区保存着计算后可显示给用户的图像,被显示到屏幕上;所有的的渲染命令被传递到后台的缓冲区进行计算。当所有的渲染命令执行结束后,我们交换前台缓冲和后台缓冲,这样图像就立即呈显出来,之后清空缓冲区。 + +###最后一件事 + +当游戏循环结束后我们需要释放之前的操作分配的资源,我们可以在main函数的最后调用glfwTerminate函数来释放GLFW分配的内存。 + +```c++ +glfwTerminate(); +return 0; +``` +这样便能清空GLFW分配的内存然后正确地退出应用程序。现在你可以尝试编译并运行你的应用程序了,你将会看到如下的一个黑色窗口: + +![](http://learnopengl.com/img/getting-started/hellowindow.png) + +如果你没有编译通过或者有什么问题的话,首先请检查你程序的的链接选项是否正确 +。然后对比本教程的代码,检查你的代码是不是哪里写错了,你也可以[点击这里](http://learnopengl.com/code_viewer.php?code=getting-started/hellowindow)获取我的完整代码。 + +###输入 + +我们可以通过多种用户输入来控制GLFW,这是通过设置GLFW的回调函数来实现的。回调函数事实上是一个函数指针,当我们为GLFW设置回调函数后,GLWF会在恰当的时候调用它。按键回调(KeyCallback)是众多回调函数中的一种,当我们为GLFW设置按键回调之后,GLFW会在用户有键盘交互时调用它。该回调函数的原型如下所示: + +```c++ +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); +``` +按键回调函数接受一个GLFWwindow指针作为它的第一个参数;第二个整形参数用来表示事件的按键;第三个整形参数描述用户是否有第二个键按下或释放;第四个整形参数表示事件类型,如按下或释放;最后一个参数是表示是否有Ctrl、Shift等按钮的操作。GLFW会在恰当的时候调用它,并为各个参数传入适当的值。 + +```c++ +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) +{ + // 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true + // 关闭应用程序 + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} +``` +当用户按下ESC键时我们设置窗口的WindowShouldClose(窗口是否应该被关闭)属性的值为真。当执行下一次游戏循环时,glfwWindowShouldClose(window)返回真,此时游戏循环便不再继续,然后释放资源结束程序。 + +最后我们还要为GLFW注册这个按键回调函数,这样它才能被GLFW在触发按键事件时被调用。 + +```c++ +glfwSetKeyCallback(window, key_callback); +``` +除了按键回调函数之外,我们还能为GLFW注册其他的回调函数。例如,我们可以注册一个函数来处理窗口尺寸变化、处理一些错误信息等。我们可以在创建窗口之后到开始游戏循环之前注册各种回调函数。 + +###渲染 + +我们要把所有的渲染操作放到游戏循环中,因为我们想让这些渲染操作在每次游戏循环迭代的时候都能被执行。我们将做如下的操作: + +```c++ +// 程序循环 +while(!glfwWindowShouldClose(window)) +{ + // 检查事件 + glfwPollEvents(); + + // 在这里执行各种渲染操作 + ... + + //交换缓冲区 + glfwSwapBuffers(window); +} +``` +为了测试一切都正常,我们想让屏幕清空为一种我们选择的颜色。在每次执行新的渲染之前我们都希望清除上一次循环的渲染结果,除非我们想要看到上一次的结果。我们可以通过调用glClear函数来清空屏幕缓冲区的颜色,他接受一个整形常量参数来指定要清空的缓冲区,这个常量可以是GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT和 GL_STENCIL_BUFFER_BIT。由于现在我们只关心颜色值,所以我们只清空颜色缓冲区。 + +```c++ +glClearColor(0.2f, 0.3f, 0.3f, 1.0f); +glClear(GL_COLOR_BUFFER_BIT); +``` +注意,除了glClear之外,我们还要调用glClearColor来设置要清空缓冲的颜色。当调用glClear函数之后,整个指定清空的缓冲区都被填充为glClearColor所设置的颜色。在这里,我们将屏幕设置为了类似黑板的深蓝绿色。 + +>你应该能够想起来我们在 [OpenGL]() 教程的内容, glClearColor函数是一个状态设置函数,而glClear函数则是一个状态应用的函数。 + +![](http://learnopengl.com/img/getting-started/hellowindow2.png) + +此程序的完整源代码可以在[这里](http://learnopengl.com/code_viewer.php?code=getting-started/hellowindow2)找到。 + +好了,到目前为止我们已经做好开始在游戏循环中添加许多渲染操作的准备了,我认为我们的闲扯已经够多了,从[设置:::::下一篇教程](http://www.learnopengl.com/#!Getting-started/Hello-Triangle)开始我们将真正的征程 \ No newline at end of file