For context, this is on Windows and all OpenGL functions are either included from GL.h or the Kronos extension headers where I also have to use wglGetProcAddress. I am using VS Code as my editor and MSVC build tools as my compiler.
Here is an example of how I load my OpenGL 1.1+ functions:
inline PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(wglGetProcAddress("glActiveTexture"));
if (glActiveTexture == nullptr)
std::cerr << "Error: Failed to load glActiveTexture." << std::endl;
<code>// header file
inline PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
...
// source file
glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(wglGetProcAddress("glActiveTexture"));
if (glActiveTexture == nullptr)
std::cerr << "Error: Failed to load glActiveTexture." << std::endl;
...
</code>
// header file
inline PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
...
// source file
glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(wglGetProcAddress("glActiveTexture"));
if (glActiveTexture == nullptr)
std::cerr << "Error: Failed to load glActiveTexture." << std::endl;
...
Now, for the problem. When I call glDrawElements I get this error message: Exception thrown at 0x00000204DBDFFF5A in Project.exe: 0xC0000005: Access violation reading location 0x0000000000000000. Also, glGetError returns 0.
Here is where in the code the error occurs:
<code>void Renderer::render(const Texture& texture) {
shader.setUniform("image", static_cast<GLint>(texture.unit - GL_TEXTURE0));
std::cout << glGetError() << std::endl;
glDrawElements(GL_TRIANGLES, elements.getCount(), GL_UNSIGNED_INT, nullptr);
<code>void Renderer::render(const Texture& texture) {
texture.bind();
shader.setUniform("image", static_cast<GLint>(texture.unit - GL_TEXTURE0));
std::cout << glGetError() << std::endl;
glDrawElements(GL_TRIANGLES, elements.getCount(), GL_UNSIGNED_INT, nullptr);
}
</code>
void Renderer::render(const Texture& texture) {
texture.bind();
shader.setUniform("image", static_cast<GLint>(texture.unit - GL_TEXTURE0));
std::cout << glGetError() << std::endl;
glDrawElements(GL_TRIANGLES, elements.getCount(), GL_UNSIGNED_INT, nullptr);
}
Here is where I assign the image data to the texture:
<code>void Texture::setData(const std::string& file) {
stbi_set_flip_vertically_on_load(1);
stbi_uc* image = stbi_load(file.c_str(), &width, &height, &bpp, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
<code>void Texture::setData(const std::string& file) {
bind();
stbi_set_flip_vertically_on_load(1);
int width, height, bpp;
stbi_uc* image = stbi_load(file.c_str(), &width, &height, &bpp, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_INT, image);
stbi_image_free(image);
}
</code>
void Texture::setData(const std::string& file) {
bind();
stbi_set_flip_vertically_on_load(1);
int width, height, bpp;
stbi_uc* image = stbi_load(file.c_str(), &width, &height, &bpp, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_INT, image);
stbi_image_free(image);
}
Here is how I set my vertex and element buffer data:
<code>void VertexBuffer::addVertices(const std::vector<GLfloat>& vertices) {
glBufferData(GL_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLfloat) * vertices.size()),
vertices.data(), GL_STATIC_DRAW);
void ElementBuffer::addElements(const std::vector<GLuint>& elements) {
count = static_cast<GLsizei>(elements.size());
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLuint) * count), elements.data(),
<code>void VertexBuffer::addVertices(const std::vector<GLfloat>& vertices) {
bind();
glBufferData(GL_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLfloat) * vertices.size()),
vertices.data(), GL_STATIC_DRAW);
}
void ElementBuffer::addElements(const std::vector<GLuint>& elements) {
bind();
count = static_cast<GLsizei>(elements.size());
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLuint) * count), elements.data(),
GL_STATIC_DRAW);
}
</code>
void VertexBuffer::addVertices(const std::vector<GLfloat>& vertices) {
bind();
glBufferData(GL_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLfloat) * vertices.size()),
vertices.data(), GL_STATIC_DRAW);
}
void ElementBuffer::addElements(const std::vector<GLuint>& elements) {
bind();
count = static_cast<GLsizei>(elements.size());
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
static_cast<GLsizeiptr>(sizeof(GLuint) * count), elements.data(),
GL_STATIC_DRAW);
}
Here is how I assign vertex array data:
<code>void BufferLayout::push(unsigned int count) {
size_t BufferLayout::getCount() const {
unsigned int BufferLayout::getCount(size_t index) const {
if (index >= layout.size())
unsigned int BufferLayout::getStride() const {
for (unsigned int count : layout)
unsigned int BufferLayout::getOffset(size_t index) const {
if (index >= layout.size())
for (unsigned int i = 0; i < index; ++i)
void VertexArray::addBuffer(const VertexBuffer& vertices,
const BufferLayout& layout) {
for (size_t i = 0; i < layout.getCount(); ++i) {
glEnableVertexAttribArray(static_cast<GLuint>(i));
glVertexAttribPointer(static_cast<GLuint>(i),
static_cast<GLint>(layout.getCount(i)), GL_FLOAT, GL_FALSE,
static_cast<GLsizei>(sizeof(GLfloat) * layout.getStride()), i > 0 ?
reinterpret_cast<void*>(sizeof(GLfloat) * layout.getOffset(i)) :
<code>void BufferLayout::push(unsigned int count) {
layout.push_back(count);
}
size_t BufferLayout::getCount() const {
return layout.size();
}
unsigned int BufferLayout::getCount(size_t index) const {
if (index >= layout.size())
return 0;
return layout.at(index);
}
unsigned int BufferLayout::getStride() const {
unsigned int stride = 0;
for (unsigned int count : layout)
stride += count;
return stride;
}
unsigned int BufferLayout::getOffset(size_t index) const {
if (index >= layout.size())
return 0;
unsigned int offset = 0;
for (unsigned int i = 0; i < index; ++i)
offset += layout.at(i);
return offset;
}
void VertexArray::addBuffer(const VertexBuffer& vertices,
const BufferLayout& layout) {
bind();
vertices.bind();
for (size_t i = 0; i < layout.getCount(); ++i) {
glEnableVertexAttribArray(static_cast<GLuint>(i));
glVertexAttribPointer(static_cast<GLuint>(i),
static_cast<GLint>(layout.getCount(i)), GL_FLOAT, GL_FALSE,
static_cast<GLsizei>(sizeof(GLfloat) * layout.getStride()), i > 0 ?
reinterpret_cast<void*>(sizeof(GLfloat) * layout.getOffset(i)) :
nullptr);
}
}
</code>
void BufferLayout::push(unsigned int count) {
layout.push_back(count);
}
size_t BufferLayout::getCount() const {
return layout.size();
}
unsigned int BufferLayout::getCount(size_t index) const {
if (index >= layout.size())
return 0;
return layout.at(index);
}
unsigned int BufferLayout::getStride() const {
unsigned int stride = 0;
for (unsigned int count : layout)
stride += count;
return stride;
}
unsigned int BufferLayout::getOffset(size_t index) const {
if (index >= layout.size())
return 0;
unsigned int offset = 0;
for (unsigned int i = 0; i < index; ++i)
offset += layout.at(i);
return offset;
}
void VertexArray::addBuffer(const VertexBuffer& vertices,
const BufferLayout& layout) {
bind();
vertices.bind();
for (size_t i = 0; i < layout.getCount(); ++i) {
glEnableVertexAttribArray(static_cast<GLuint>(i));
glVertexAttribPointer(static_cast<GLuint>(i),
static_cast<GLint>(layout.getCount(i)), GL_FLOAT, GL_FALSE,
static_cast<GLsizei>(sizeof(GLfloat) * layout.getStride()), i > 0 ?
reinterpret_cast<void*>(sizeof(GLfloat) * layout.getOffset(i)) :
nullptr);
}
}
Here is where I set up my OpenGL objects:
(This happens before any calls to glDrawElements)
const std::vector<GLfloat> vertexData = {
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f
const std::vector<GLuint> elementData = {
const std::string vertexShader = R"(
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
gl_Position = vec4(aPosition, 1.0);
const std::string fragmentShader = R"(
color = texture(image, texCoord);
buffer.addVertices(vertexData);
vertices.addBuffer(buffer, layout);
elements.addElements(elementData);
shader.compile(vertexShader, fragmentShader);
<code>// header file
class Renderer {
...
private:
VertexArray vertices;
ElementBuffer elements;
Shader shader;
};
// source file
Renderer::Renderer() {
const std::vector<GLfloat> vertexData = {
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f
};
const std::vector<GLuint> elementData = {
0, 1, 2,
2, 3, 0
};
const std::string vertexShader = R"(
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main() {
gl_Position = vec4(aPosition, 1.0);
texCoord = aTexCoord;
}
)";
const std::string fragmentShader = R"(
#version 330 core
in vec2 texCoord;
out vec4 color;
uniform sampler2D image;
void main() {
color = texture(image, texCoord);
}
)";
VertexBuffer buffer;
buffer.addVertices(vertexData);
BufferLayout layout;
layout.push(3);
layout.push(2);
vertices.addBuffer(buffer, layout);
elements.addElements(elementData);
shader.compile(vertexShader, fragmentShader);
vertices.bind();
elements.bind();
shader.bind();
}
</code>
// header file
class Renderer {
...
private:
VertexArray vertices;
ElementBuffer elements;
Shader shader;
};
// source file
Renderer::Renderer() {
const std::vector<GLfloat> vertexData = {
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f
};
const std::vector<GLuint> elementData = {
0, 1, 2,
2, 3, 0
};
const std::string vertexShader = R"(
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main() {
gl_Position = vec4(aPosition, 1.0);
texCoord = aTexCoord;
}
)";
const std::string fragmentShader = R"(
#version 330 core
in vec2 texCoord;
out vec4 color;
uniform sampler2D image;
void main() {
color = texture(image, texCoord);
}
)";
VertexBuffer buffer;
buffer.addVertices(vertexData);
BufferLayout layout;
layout.push(3);
layout.push(2);
vertices.addBuffer(buffer, layout);
elements.addElements(elementData);
shader.compile(vertexShader, fragmentShader);
vertices.bind();
elements.bind();
shader.bind();
}
I’ve used the majority of this code, especially the wrapper classes for OpenGL, in other projects. I’ve never had this issue before. I’ve tried placing calls to glGetError() throughout the code as the issue continued but would always get a return value of 0. I am not sure what I am doing differently here that’s triggering it. I’d be happy to share more code if needed. Thank you in advance!