Is it possible to use the Visual Studio debugger to debug my GLFW/OpenGL code? I get an exception on a glDrawElements() call which provides useless info. Obviously I have not set things up correctly, but with errors occurring in library calls, how do I find out what I did wrong? Is there a way to take advantage of the availability of the GLFW source? I just set up the VS project the way GLFW directs.
The code is a modified version of one of learnopengl.com's first examples, so it is pretty simple. I am in the middle of trying to convert drawing of the first triangle from just VBO/VAO buffers to using an EBO buffer.
I commented the line that throws this in RenderAll() near the bottom.
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();
}

typedef struct S_Tripletis "C" syntax, just usestruct T_Triplet{ ... };in C++. And why are you not usingstd::string,std::string_viewetc. butchar*?glGenVertexArrays(2, renderContext.VAO)twice. I suspect that the second call is meant to beglGenVertexArrays(2, renderContext.VBO). Not the answer to your question I know.EBOwithout creating them.