SDL 中使用 OpenGL
什么是OpenGL,这里摘取LearnOpenGL中的一段介绍: 一般它被认为是一个API,包含了一系列可以操作图形、图像的函数。然而,实际上 OpenGL 本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范
OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现的,将由OpenGL库的开发者自行决定。因为OpenGL规范并没有规定实现的细节,具体的OpenGL库允许使用不同的实现,只要其功能和结果与规范相匹配(亦即,作为用户不会感受到功能上的差异)
实际的OpenGL库的开发者通常是显卡的生产商。你购买的显卡所支持的OpenGL版本都为这个系列的显卡专门开发的。当你使用Apple系统的时候,OpenGL库是由Apple自身维护的。在Linux下,也有显卡生产商提供的OpenGL库,同时还有一些爱好者改编的版本。这也意味着任何时候OpenGL库表现的行为与规范规定的不一致时,基本都是库的开发者留下的bug。
由于OpenGL的大多数实现都是由显卡厂商编写的,当产生一个bug时通常可以通过升级显卡驱动来解决。这些驱动会包括你的显卡能支持的最新版本的OpenGL,这也是为什么总是建议你偶尔更新一下显卡驱动。
可以看到,因为OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,在Windows上会是类似这样:
// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);
你可以看到代码非常复杂,而且很繁琐,我们需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程,比如GLEW或者GLAD,其中GLAD是目前最新,也是最流行的库。
下面分别安装讲述怎么安装使用这两种库:
安装 GLEW 或者 GLAD
安装 GLEW
-
官网下载
因为我使用的是 mingw 环境来开发,所以使用上面的地址,如果想在 vs 上开发,则应该去这个网址下载
mingw环境下载地址
选择最新版32位或64位,这里我选择了64位,mingw-w64-glew-2.1.0 for 64bit
下载解压放到你能方便记住的文件夹下面,比如我放到了D:\msys2\opt\glew
并命名为glew
-
设置环境
OK,安装完成
-
安装 GLAD
安装 GLAD 更是简单直接,到官网下载
安装 glad
填写如下信息,然后选择底下的 CREATE 创建,他就根据你的显卡型号帮你生成代码,下载得到一个压缩包,里面包含一个源文件和两个头文件,你只需要添加到你的项目即可
安装GLFW(可选)
GLFW是继 GLUT,FreeGLUT 之后,当前最新的用来创建 OpenGL上下文,以及操作窗口的第三方库。但是我们有了 SDL,因为 SDL 本身也能作为 OpenGL 容器,提供窗口创建,事件获取,而且还能提供音频播放等,所以如果用SDL,就大可不必再安装GLFW,只是有的时候想跑 LearnOpenGL 的demo,因为很多网上教程都是 GLFW,或者 GLUT 的,所以安装一下还是比较方便的
选择64位还是32位看自己的选择,下载完解压
安装
我的因为是 mingw,我用到的是 lib-mingw-64文件夹,里面有
.dll
和 .a
文件,然后我创建了一个 bin
, include
,lib
文件夹然后把 dll 和 .a 文件放进入,在到下载的压缩包里面,将 include 放到同一目录下得到:安装习惯
安装完成了,很多第三方库安装思路都是这样了,下载解压,然后在编译时指定目录使用就行了
demo (SDL+GLEW)
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <iostream>
// openGL 绘制部分
void opengldraw()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
int main(int argc, char *argv[])
{
// 设置 SQL 版本和信息
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("SDL+OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 300, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(1);
glewInit();
bool quit = false;
SDL_Event event;
while (quit == false) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) quit = true;
}
opengldraw();
SDL_GL_SwapWindow(window);
SDL_Delay(1000 / 60);
}
SDL_DestroyWindow(window);
return 0;
}
makefile
# 源文件
SRC = demo.cpp
# 头文件文件夹
INC_DIR += -ID:\msys2\opt\SDL2\include
INC_DIR += -ID:\msys2\opt\glfw\include
INC_DIR += -ID:\msys2\opt\glew\include
# 库文件文件夹
LIB_DIR += -LD:\msys2\opt\SDL2\lib
LIB_DIR += -LD:\msys2\opt\glfw\lib
LIB_DIR += -LD:\msys2\opt\glew\lib
# 链接库
LIB = -lmingw32 -lSDL2main -lSDL2 -lglew32 -lglfw3 -lopengl32
# 编译参数
CFLAGS = $(INC_DIR) $(LIB_DIR) $(LIB) -O2 -mwindows
# 选择编译器
CC = D:\msys2\mingw64\bin\g++.exe
a.exe: $(SRC)
$(CC) $(SRC) $(CFLAGS) -o a.exe
运行结果:
如果运行出错,提示dll找不到,你需要复制该dll到该目录,或者把dll添加到环境变量,详见这篇文章的中间部分
demo (GLFW+GLEW)
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
// openGL 绘制部分
void opengldraw()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
int main()
{
// 初始化窗口
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 设置opengl
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
glewExperimental = true;
glewInit();
while (!glfwWindowShouldClose(window)) {
opengldraw();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
makefike 几乎不用改,就是一点 -mwindows 必须要使用上,glfw 的 dll 比 sdl 小,所以做一些展示使用还是挺方便的
demo (GLFW+GALD)
这是目前版本LearnOpenGL推荐的组合,他们的demo目前都是这两个库。GALD 直接使用源文件会比较好,不过也可以自己打包成链接库。
#include "glad/glad.h"
#include <GLFW/glfw3.h>
#include <iostream>
// openGL 绘制部分
void opengldraw()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
int main()
{
// 初始化窗口
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 设置opengl
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
while (!glfwWindowShouldClose(window)) {
opengldraw();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
demo (SDL+GLAD) (推荐)
结合GLAD支持的最新OpenGL协议,加上SDL的多媒体支持,这就比较方便了
#include "glad/glad.h"
#include <SDL2/SDL.h>
#include <iostream>
// openGL 绘制部分
void opengldraw()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
int main(int argc, char *argv[])
{
// 设置 SQL 版本和信息
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("SDL+OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 300, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(1);
gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress);
bool quit = false;
SDL_Event event;
while (quit == false) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) quit = true;
}
opengldraw();
SDL_GL_SwapWindow(window);
SDL_Delay(1000 / 60);
}
SDL_DestroyWindow(window);
return 0;
}