keywords: OpenGL, OpenGL开发环境搭建, Windows

网上资料很多都是基于Cygwin来搭建的环境,这里介绍一种非Cygwin搭建Windows上的OpenGL开发环境。

1,OpenGL Loader Generator下载安装
OpenGL Loader是一个标准规范,定义了如何在运行时期间加载OpenGL相关函数的指针。 这是windows上开发OpenGL程序才需要的lib,因为从1.1版本开始,windows不在对OpenGL 后续版本的 ABI(application binary interface)提供支持(可能是微软的DX出来后与OGL商业竞争吧),所以开发者无法直接获取OGL新版本的相关函数,不过有好心人写了工具,在运行时期间获取OGL的新版函数,这里介绍两个开源库:
glad
https://github.com/Dav1dde/glad
glloadgen
https://bitbucket.org/alfonse/glloadgen/wiki/Home

我是用的是glad,这个开源库的开发者还提供了在线生成工具,可以不用下载安装Load Generator,直接在线生成指定版本的OpenGL Loader: http://glad.dav1d.de/

2,编译OpenGL Loader的静态库
通过glad生成的代码,编译一个lib, 以便后面的的示例工程调用。因为这些代码开发者不用做修改,只是调用,所以最好编译成lib,而不要直接加到自己的项目代码中。

3,下载GLM(OpenGL Mathematics)
这是OpenGL的数学库
https://github.com/g-truc/glm/releases

4,下载GLFW
这是一个提供了OpenGL, OpenGL ES和Vulkan相关接口的跨平台的开源库,有这个库你就可以访问他们的最新API。 https://github.com/glfw/glfw/releases

5,新建一个C++工程并设置OpenGL相关的头文件和静态库

指定头文件的目录

指定静态库的目录

在代码需要包含的头文件以及lib:

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

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glad.lib")
#pragma comment(lib, "glfw3.lib")

新建的测试工程叫GLTest,目录结构如下: 新加了两个分别叫include和lib的目录,用于存放第三方库的头文件和库文件

完整的测试的代码:

#pragma once

#include <iostream>
#include <windows.h>

#include <fstream>
#include <sstream>
#include <string>

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

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glad.lib")
#pragma comment(lib, "glfw3.lib")

using std::string;
using std::ifstream;

GLFWwindow *window;

static HMODULE libGL;

GLuint vaoHandle;

int width, height;

void update(float t);

void render();

void mainLoop() {
    while (!glfwWindowShouldClose(window) && !glfwGetKey(window, GLFW_KEY_ESCAPE)) {

        update(float(glfwGetTime()));
        render();
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}

void dumpGLInfo(bool dumpExtensions) {
    const GLubyte *renderer = glGetString(GL_RENDERER);
    const GLubyte *vendor = glGetString(GL_VENDOR);
    const GLubyte *version = glGetString(GL_VERSION);
    const GLubyte *glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);

    GLint major, minor;
    glGetIntegerv(GL_MAJOR_VERSION, &major);
    glGetIntegerv(GL_MINOR_VERSION, &minor);

    printf("-------------------------------------------------------------\n");
    printf("GL Vendor    : %s\n", vendor);
    printf("GL Renderer  : %s\n", renderer);
    printf("GL Version   : %s\n", version);
    printf("GL Version   : %d.%d\n", major, minor);
    printf("GLSL Version : %s\n", glslVersion);
    printf("-------------------------------------------------------------\n");

    if (dumpExtensions) {
        GLint nExtensions;
        glGetIntegerv(GL_NUM_EXTENSIONS, &nExtensions);
        for (int i = 0; i < nExtensions; i++) {
            printf("%s\n", glGetStringi(GL_EXTENSIONS, i));
        }
    }
}

void linkMe(GLint vertShader, GLint fragShader)
{
    // Create the program object
    GLuint programHandle = glCreateProgram();
    if (0 == programHandle) {
        fprintf(stderr, "Error creating program object.\n");
        exit(1);
    }

    // Bind index 0 to the shader input variable "VertexPosition"
    //glBindAttribLocation(programHandle, 0, "VertexPosition");
    // Bind index 1 to the shader input variable "VertexColor"
    //glBindAttribLocation(programHandle, 1, "VertexColor");

    // Attach the shaders to the program object
    glAttachShader(programHandle, vertShader);
    glAttachShader(programHandle, fragShader);

    // Link the program
    glLinkProgram(programHandle);

    // Check for successful linking
    GLint status;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &status);
    if (GL_FALSE == status) {

        fprintf(stderr, "Failed to link shader program!\n");

        GLint logLen;
        glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &logLen);

        if (logLen > 0) {
            char * log = (char *)malloc(logLen);

            GLsizei written;
            glGetProgramInfoLog(programHandle, logLen, &written, log);

            fprintf(stderr, "Program log: \n%s", log);

            free(log);
        }
    }
    else {
        glUseProgram(programHandle);
    }
    glDeleteShader(vertShader);
    glDeleteShader(fragShader);
}

void initScene(){
    //////////////////////////////////////////////////////
    /////////// Vertex shader //////////////////////////
    //////////////////////////////////////////////////////

    // Load contents of file
    ifstream inFile("shader/basic.vert");
    if (!inFile) {
        fprintf(stderr, "Error opening file: shader/basic.vert\n");
        exit(1);
    }

    std::stringstream code;
    code << inFile.rdbuf();
    inFile.close();
    string codeStr(code.str());

    // Create the shader object
    GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
    if (0 == vertShader) {
        fprintf(stderr, "Error creating vertex shader.\n");
        exit(EXIT_FAILURE);
    }

    // Load the source code into the shader object
    const GLchar* codeArray[] = { codeStr.c_str() };
    glShaderSource(vertShader, 1, codeArray, NULL);

    // Compile the shader
    glCompileShader(vertShader);

    // Check compilation status
    GLint result;
    glGetShaderiv(vertShader, GL_COMPILE_STATUS, &result);
    if (GL_FALSE == result) {
        fprintf(stderr, "Vertex shader compilation failed!\n");

        GLint logLen;
        glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &logLen);

        if (logLen > 0) {
            char * log = (char *)malloc(logLen);

            GLsizei written;
            glGetShaderInfoLog(vertShader, logLen, &written, log);

            fprintf(stderr, "Shader log: \n%s", log);

            free(log);
        }
    }

    //////////////////////////////////////////////////////
    /////////// Fragment shader //////////////////////////
    //////////////////////////////////////////////////////

    // Load contents of file into shaderCode here
    ifstream fragFile("shader/basic.frag");
    if (!fragFile) {
        fprintf(stderr, "Error opening file: shader/basic.frag\n");
        exit(1);
    }

    std::stringstream fragCode;
    fragCode << fragFile.rdbuf();
    fragFile.close();
    codeStr = fragCode.str();

    // Create the shader object
    GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    if (0 == fragShader) {
        fprintf(stderr, "Error creating fragment shader.\n");
        exit(1);
    }

    // Load the source code into the shader object
    codeArray[0] = codeStr.c_str();
    glShaderSource(fragShader, 1, codeArray, NULL);

    // Compile the shader
    glCompileShader(fragShader);

    // Check compilation status
    glGetShaderiv(fragShader, GL_COMPILE_STATUS, &result);
    if (GL_FALSE == result) {
        fprintf(stderr, "Fragment shader compilation failed!\n");

        GLint logLen;
        glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLen);

        if (logLen > 0) {
            char * log = (char *)malloc(logLen);

            GLsizei written;
            glGetShaderInfoLog(fragShader, logLen, &written, log);

            fprintf(stderr, "Shader log: \n%s", log);

            free(log);
        }
    }

    linkMe(vertShader, fragShader);

    /////////////////// Create the VBO ////////////////////
    float positionData[] = {
        -0.8f, -0.8f, 0.0f,
        0.8f, -0.8f, 0.0f,
        0.0f,  0.8f, 0.0f };
    float colorData[] = {
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f };


    // Create and populate the buffer objects
    GLuint vboHandles[2];
    glGenBuffers(2, vboHandles);
    GLuint positionBufferHandle = vboHandles[0];
    GLuint colorBufferHandle = vboHandles[1];

    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), positionData, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), colorData, GL_STATIC_DRAW);

    // Create and set-up the vertex array object
    glGenVertexArrays(1, &vaoHandle);
    glBindVertexArray(vaoHandle);

    glEnableVertexAttribArray(0);  // Vertex position
    glEnableVertexAttribArray(1);  // Vertex color

    ////break current vertex array object binding.
    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL);

    glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL);
    glBindVertexArray(0);
}

void update(float t)
{

}

void render()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(vaoHandle);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
}

void resize(int w, int h)
{
    width = w;
    height = h;
    glViewport(0, 0, w, h);
}


void initializeGL() {
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    initScene();
}


int main(int argc, char* argv[])
{
    // Initialize GLFW
    if (!glfwInit()) exit(EXIT_FAILURE);

#ifdef __APPLE__
    // Select OpenGL 4.1
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#else
    // Select OpenGL 4.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#endif
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, false);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);

    // Open the window
    string title = "OpenGLTest";
    window = glfwCreateWindow(500, 500, title.c_str(), NULL, NULL);
    if (!window) {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);

    // Get framebuffer size
    int fbw, fbh;
    glfwGetFramebufferSize(window, &fbw, &fbh);

    // Load the OpenGL functions.
    if (!gladLoadGL()) { exit(-1); }

    dumpGLInfo(false);

    // Initialization
    initializeGL();

    // Enter the main loop
    mainLoop();

    // Close window and terminate GLFW
    glfwTerminate();
    // Exit program
    exit(EXIT_SUCCESS);

    return 0;
}

最终效果:

测试工程下载地址:
http://pan.baidu.com/s/1nvp6kUt
只保证Release模式下正常运行,Debug版本需要指定第三方库的debug版本

示例代码参考自:
https://github.com/daw42/glslcookbook/blob/master/chapter01/scenebasic.cpp


只愿君心似我心,定不负,相思意。---李之仪《卜算子》