Visual Studio 调试器对于调试我的 OpenGL 代码有用吗?

问题描述 投票:0回答:1

是否可以使用 Visual Studio 调试器来调试我的 GLFW/OpenGL 代码?我在 glDrawElements() 调用上遇到异常,它提供了无用的信息。显然我没有正确设置,但是在库调用中发生错误,我如何找出我做错了什么?有没有办法利用 GLFW 源的可用性?我只是按照 GLFW 指示的方式设置了 VS 项目。

该代码是 learnopengl.com 第一个示例的修改版本,因此非常简单。我正在尝试将第一个三角形的绘制从 VBO/VAO 缓冲区转换为使用 EBO 缓冲区。

我评论了在底部附近的 RenderAll() 中引发此问题的行。

Exception thrown at 0x00007FFC6A0F4A03 (nvoglv64.dll) in GLFW3TestProj.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>
using namespace std;

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

typedef struct {
    GLFWwindow* window;
    unsigned int shaderProgram1;
    unsigned int shaderProgram2;
    unsigned int VBO[2];
    unsigned int VAO[2];
    unsigned int EBO[2];
} T_RenderContext;
void RenderAll();
T_RenderContext renderContext;

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
    // --------------------
    renderContext.window = glfwCreateWindow(1250, 1000, "LearnOpenGL", NULL, NULL);
    if (renderContext.window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(renderContext.window);
    glfwSetFramebufferSizeCallback(renderContext.window, framebuffer_size_callback);

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


    // build and compile our shader program
    // ------------------------------------
    // vertex shader
    const char* vertexShaderSource = "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
        "}\0";
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader 1
    const char* fragmentShaderSource1 = "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "   FragColor = vec4(0.937f, 0.608f, 0.0f, 1.0f);\n"
        "}\n\0";
    unsigned int fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader1, 1, &fragmentShaderSource1, NULL);
    glCompileShader(fragmentShader1);
    // check for shader compile errors
    glGetShaderiv(fragmentShader1, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader1, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT1::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader 2
    const char* fragmentShaderSource2 = "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main()\n"
        "{\n"
        "   FragColor = vec4(0.937f, 0.0f, 0.608f, 1.0f);\n"
        "}\n\0";
    unsigned int fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader2, 1, &fragmentShaderSource2, NULL);
    glCompileShader(fragmentShader2);
    // check for shader compile errors
    glGetShaderiv(fragmentShader2, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader2, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT2::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    renderContext.shaderProgram1 = glCreateProgram();
    glAttachShader(renderContext.shaderProgram1, vertexShader);
    glAttachShader(renderContext.shaderProgram1, fragmentShader1);
    glLinkProgram(renderContext.shaderProgram1);

    renderContext.shaderProgram2 = glCreateProgram();
    glAttachShader(renderContext.shaderProgram2, vertexShader);
    glAttachShader(renderContext.shaderProgram2, fragmentShader2);
    glLinkProgram(renderContext.shaderProgram2);

    // check for linking errors
    glGetProgramiv(renderContext.shaderProgram1, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(renderContext.shaderProgram1, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM1::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glGetProgramiv(renderContext.shaderProgram2, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(renderContext.shaderProgram2, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM2::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader1);
    glDeleteShader(fragmentShader2);


    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    typedef struct S_Triplet {
        float x; float y; float z;
    } T_Triplet;
    
    T_Triplet triangle1[3];
    triangle1[0] = { -0.5F, 0.1F, 0.0F };
    triangle1[1] = { 0.5F, 0.2F, 0.0F };
    triangle1[2] = { 0.0F, 0.866F, 0.0F };

    T_Triplet triangle2[3];
    triangle2[0] = { -0.5F, -0.2F, 0.0F };
    triangle2[1] = { 0.5F, -0.1F, 0.0F };
    triangle2[2] = { 0.0F, -0.866F, 0.0F };

    unsigned int indices1[] = { 0, 1, 2 };
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    unsigned int indices2[] = { 0, 1, 2 };
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);

    glGenVertexArrays(2, renderContext.VAO);
    glGenBuffers(2, renderContext.VBO);
    glGenVertexArrays(2, renderContext.VAO); // we can also generate multiple VAOs or buffers at the same time
    // first triangle setup
    // --------------------
    glBindVertexArray(renderContext.VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, renderContext.VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle1), triangle1, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);   // Vertex attributes stay the same
    glEnableVertexAttribArray(0);
    // glBindVertexArray(0); // no need to unbind at all as we directly bind a different VAO the next few lines
    // second triangle setup
    // ---------------------
    glBindVertexArray(renderContext.VAO[1]);    // note that we bind to a different VAO now
    glBindBuffer(GL_ARRAY_BUFFER, renderContext.VBO[1]);    // and a different VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); // because the vertex data is tightly packed we can also specify 0 as the vertex attribute's stride to let OpenGL figure it out
    glEnableVertexAttribArray(0);
    // glBindVertexArray(0); // not really necessary as well, but beware of calls that could affect VAOs while this one is bound (like binding element buffer objects, or enabling/disabling vertex attributes)


    // render loop
    // -----------
    while (!glfwWindowShouldClose(renderContext.window))
    {
        RenderAll();
    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, renderContext.VAO);
    glDeleteBuffers(1, renderContext.VBO);
    glDeleteProgram(renderContext.shaderProgram1);
    glDeleteProgram(renderContext.shaderProgram2);

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

// Render all
void RenderAll() {
    // input
    // -----
    processInput(renderContext.window);

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

    // now when we draw the triangle we first use the vertex and orange fragment shader from the first program
    glUseProgram(renderContext.shaderProgram1);
    // draw the first triangle using the data from our first VAO
    glBindVertexArray(renderContext.VAO[0]);
    ///////////glDrawArrays(GL_TRIANGLES, 0, 3);    // this call should output an orange triangle
//** THROWS EXCEPTION ** Exception thrown at 0x00007FFC6A0F4A03 (nvoglv64.dll) in GLFW3TestProj.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
    // then we draw the second triangle using the data from the second VAO
    // when we draw the second triangle we want to use a different shader program so we switch to the shader program with our magenta fragment shader.
    glUseProgram(renderContext.shaderProgram2);
    glBindVertexArray(renderContext.VAO[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);   // this call should output a magenta triangle

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

// 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);

    RenderAll();
}
c++ opengl glsl glfw access-violation
1个回答
0
投票

一些事情:

  • OpenGL 调试上下文和调试消息回调:

    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
    
    ...
    
    if(GLFW_TRUE == glfwGetWindowAttrib(renderContext.window, GLFW_OPENGL_DEBUG_CONTEXT)) {
        glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS );
        glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE );
        glDebugMessageCallback( []( GLenum, GLenum, GLuint,  GLenum, GLsizei, const GLchar* message, const void* )
        {
            std::cerr << "GL: " << message << std::endl;
        }, 0 );
    }
    

    ...显示四个

    glBufferData()
    调用抛出
    GL_INVALID_OPERATION

    GL: GL_INVALID_OPERATION in glBufferData(no buffer bound)
    GL: GL_INVALID_OPERATION in glBufferData(no buffer bound)
    GL: GL_INVALID_OPERATION in glBufferData(no buffer bound)
    GL: GL_INVALID_OPERATION in glBufferData(no buffer bound)
    Segmentation fault (core dumped)
    

    std::terminate()
    添加到调试回调并在 GDB 下运行会显示第一个有问题的调用:

    $ DEBUGINFOD_URLS="https://debuginfod.debian.net" gdb ./main
    GNU gdb (Debian 13.1-3) 13.1
    Reading symbols from ./main...
    (gdb) r
    Starting program: /tmp/q/main 
    [Thread debugging using libthread_db enabled]                                                                                                                                                                                               
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    [New Thread 0x7fffe9e006c0 (LWP 70907)]                                                                                                                                                                                                     
    [New Thread 0x7fffe94006c0 (LWP 70908)]
    [New Thread 0x7fffe8a006c0 (LWP 70909)]
    [New Thread 0x7fffe3e006c0 (LWP 70910)]
    [New Thread 0x7fffe32006c0 (LWP 70911)]
    [New Thread 0x7fffe26006c0 (LWP 70912)]
    GL: GL_INVALID_OPERATION in glBufferData(no buffer bound)
    terminate called without an active exception
    
    Thread 1 "main" received signal SIGABRT, Aborted.
    __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
    Download failed: Invalid argument.  Continuing without source file ./nptl/./nptl/pthread_kill.c.                                                                                                                                            
    44      ./nptl/pthread_kill.c: No such file or directory.
    (gdb) bt
    #0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
    #1  0x00007ffff7aa9f1f in __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
    #2  0x00007ffff7a5afb2 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
    #3  0x00007ffff7a45472 in __GI_abort () at ./stdlib/abort.c:79
    #4  0x00007ffff7c9d919 in __gnu_cxx::__verbose_terminate_handler () at ../../../../src/libstdc++-v3/libsupc++/vterminate.cc:95
    #5  0x00007ffff7ca8e1a in __cxxabiv1::__terminate (handler=<optimized out>) at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48
    #6  0x00007ffff7ca8e85 in std::terminate () at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:58
    #7  0x0000555555555523 in operator() (__closure=0x0, message=0x7fffffffcaf0 "GL_INVALID_OPERATION in glBufferData(no buffer bound)") at main.cpp:110
    #8  0x0000555555555566 in _FUN () at main.cpp:111
    #9  0x00007ffff4a6f6fa in _mesa_error (ctx=0x5555557ea270, error=1282, fmtString=<optimized out>) at ../src/mesa/main/errors.c:366
    #10 0x0000555555555907 in main () at main.cpp:150
    (gdb) frame 10
    #10 0x0000555555555907 in main () at main.cpp:150
    150         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    (gdb) l
    145
    146         //glGenBuffers(2, renderContext.EBO);
    147
    148         unsigned int indices1[] = { 0, 1, 2 };
    149         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[0]);
    150         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    151         unsigned int indices2[] = { 0, 1, 2 };
    152         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[1]);
    153         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
    154
    (gdb) 
    
  • 正如@rafix07指出的,您正在尝试绑定

    renderContext.EBO
    ,而无需先为其生成缓冲区。

    使用

    glGenBuffers()
    填充
    renderContext.EBO
    :

    glGenBuffers(2, renderContext.EBO);
    
  • 原始字符串文字使内联GLSL更具可读性,不需要换行符或过多的引号:

    const char* const vert = R"GLSL(
    #version 330 core
    layout( location = 0 ) in vec4 position;
    void main()
    {
        gl_Position = position;
    };
    )GLSL";
    

大家一起:

screenshot of orange and pink triangles

// g++ -g -o main main.cpp src/glad.c -Iinclude $(pkg-config --cflags --libs glfw3)
// DEBUGINFOD_URLS="https://debuginfod.debian.net" gdb ./main
#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

void CheckStatus( GLuint obj, bool isShader )
{
    GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
    ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
    if( status == GL_TRUE ) return;
    ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
    std::cerr << (GLchar*)log << "\n";
    std::exit( EXIT_FAILURE );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader, true );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

const char* const vert = R"GLSL(
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
)GLSL";

const char* const frag1 = R"GLSL(
#version 330 core
out vec4 FragColor;
void main()
{
    FragColor = vec4(0.937f, 0.608f, 0.0f, 1.0f);
}
)GLSL";

const char* const frag2 = R"GLSL(
#version 330 core
out vec4 FragColor;
void main()
{
    FragColor = vec4(0.937f, 0.0f, 0.608f, 1.0f);
}
)GLSL";

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

typedef struct {
    GLFWwindow* window;
    unsigned int shaderProgram1;
    unsigned int shaderProgram2;
    unsigned int VBO[2];
    unsigned int VAO[2];
    unsigned int EBO[2];
} T_RenderContext;
void RenderAll();
T_RenderContext renderContext;

int main()
{
    glfwSetErrorCallback( []( int, const char* desc ) { std::cerr << desc << "\n"; std::exit( EXIT_FAILURE ); } );

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);

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

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

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

    if(GLFW_TRUE == glfwGetWindowAttrib(renderContext.window, GLFW_OPENGL_DEBUG_CONTEXT)) {
        glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS );
        glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE );
        glDebugMessageCallback( []( GLenum, GLenum, GLuint,  GLenum, GLsizei, const GLchar* message, const void* )
        {
            std::cerr << "GL: " << message << std::endl;
        }, 0 );
    }

    GLuint prog;

    prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag1 );
    glLinkProgram( prog );
    CheckStatus( prog, false );
    renderContext.shaderProgram1 = prog;

    prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag2 );
    glLinkProgram( prog );
    CheckStatus( prog, false );
    renderContext.shaderProgram2 = prog;

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    typedef struct S_Triplet {
        float x; float y; float z;
    } T_Triplet;

    T_Triplet triangle1[3];
    triangle1[0] = { -0.5F, 0.1F, 0.0F };
    triangle1[1] = { 0.5F, 0.2F, 0.0F };
    triangle1[2] = { 0.0F, 0.866F, 0.0F };

    T_Triplet triangle2[3];
    triangle2[0] = { -0.5F, -0.2F, 0.0F };
    triangle2[1] = { 0.5F, -0.1F, 0.0F };
    triangle2[2] = { 0.0F, -0.866F, 0.0F };

    glGenBuffers(2, renderContext.EBO);

    unsigned int indices1[] = { 0, 1, 2 };
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    unsigned int indices2[] = { 0, 1, 2 };
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);

    glGenVertexArrays(2, renderContext.VAO);
    glGenBuffers(2, renderContext.VBO);

    // first triangle setup
    // --------------------
    glBindVertexArray(renderContext.VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, renderContext.VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle1), triangle1, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // second triangle setup
    // ---------------------
    glBindVertexArray(renderContext.VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, renderContext.VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderContext.EBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(0);


    // render loop
    // -----------
    while (!glfwWindowShouldClose(renderContext.window))
    {
        RenderAll();
    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, renderContext.VAO);
    glDeleteBuffers(1, renderContext.VBO);
    glDeleteProgram(renderContext.shaderProgram1);
    glDeleteProgram(renderContext.shaderProgram2);

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

// Render all
void RenderAll() {
    // input
    // -----
    processInput(renderContext.window);

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

    // now when we draw the triangle we first use the vertex and orange fragment shader from the first program
    glUseProgram(renderContext.shaderProgram1);
    // draw the first triangle using the data from our first VAO
    glBindVertexArray(renderContext.VAO[0]);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

    // then we draw the second triangle using the data from the second VAO
    // when we draw the second triangle we want to use a different shader program so we switch to the shader program with our magenta fragment shader.
    glUseProgram(renderContext.shaderProgram2);
    glBindVertexArray(renderContext.VAO[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);   // this call should output a magenta triangle

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

// 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);

    RenderAll();
}
© www.soinside.com 2019 - 2024. All rights reserved.