Mac 平台搭建 OpenGL 环境

作者:Évariste Gao

本文是对这篇文章的补充,因为原文鲜有提及 Mac 平台上环境的搭建. 阅读本文前最好先阅读该篇文章作为对 OpenGL,GLFW,Glad 的了解.

环境:

  • Mac OSX Mojava 10.14
  • Xcode 11

安装 glfw

GLFW 是一个跨平台的 OpenGL 应用框架,它为我们实现了创建窗口、接受输入和事件等功能。mac 上安装的方法主要有两种。

使用 Homebrew 安装 (不推荐)

brew install glfw

由于 Mac 系统更新比较激进,有可能升级之后 glfw 与其不兼容.
所以比较推荐通过源码来安装.

下载源码并使用 cmake 完成编译和安装

(我 clone 时的 glfw 版本是 3.4)

git clone https://github.com/glfw/glfw.git
cd glfw
mkdir build
cd build
# MACOSX_DEPLOYMENT_TARGET=10.14
# 可以用 ccmake 自己配置一下
cmake .. -D GLFW_NATIVE_API=1 -D CMAKE_OSX_ARCHITECTURES="x86_64" -D BUILD_SHARED_LIBS=OFF
make
make install

安装 glad

由于 OpenGL 的驱动版本众多,OpenGL 的函数地址通常并不能在确定下来,我们需要手动去加载函数的地址,如下所示:
(参考原文)


但幸好有其他库可以帮我们完成这些步骤,glad 就是其中之一。
我们可以去 glad 官网上选择 OpenGL 的版本,生成相应的glad.hglad.c文件然后下载下来。

然后有两种选择,一是直接编译成库,二是生成项目时与源码一并编译,这里我选择直接编译成库

cd glad
gcc -c src/glad.c -o glad.o -Iinclude
ar rcs libglad.a glad.o

编译选项

头文件

头文件的搜索路径需添加(相当于gcc -I)

  • glfw3.h的所在路径
  • 下载下来的 glad 目录下面的 include 子目录.

库文件

(动态链接与静态链接均可以)

库文件的搜索路径需添加(相当于gcc -L)

  • libglfw3.a所在的路径

另外在Link Binary With Libraries中需添加(相当于gcc -l)

  • libglfw3.a
  • libglad.a(如果先将其编译成库的话)

Frameworks 的添加

Link Binary With Libraries中还需添加几个 Frameworks(相当于gcc -framework)

  • OpenGL.framework
  • IOKit.framework
  • Cocoa.framework
  • CoreVideo.framework

警告选项

编译时有可能 clang 报了一堆文档的警告,可以使用 -Wno-documentation 抑制.

示例

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}