For practice purpose, I have converted OpenGL Red Book 9ed ex. 3.7 from "old" functions to 4.5 functions. I have done it before, and it has worked on my system, but this time, it's not displaying anything, just the glClearBufferfv()
color. I tried to follow the example to a tee, and I didn't omit anything. I just converted glBufferData()
to glNamedBufferStorage()
. And a a few other things. Here's the original code as it appears in the book. But let me copy-paste my own code and shaders:
Main.cpp
#include <iostream>
#include <glad/glad.h>
#include <KHR/khrplatform.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL2/SOIL2.h>
#include <Shader.h>
#include <Camera.h>
enum VAO_IDs { Triangles, NumVAOs, ID3 };
enum Buffer_IDs { ArrayBuffer1, ArrayBuffer2, EBOBuffer, NumBuffers
};
enum Attrib_IDs { vPosition = 0, cPosition = 1 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
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;
void init()
{
GLfloat cube_positions[] = {
-1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
GLfloat cube_colors[] = {
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f
};
GLushort cube_indices[] = {
0, 1, 2, 3, 6, 7, 4, 5,
0xFFFF,
2, 6, 0, 4, 1, 5, 3, 7
};
glCreateVertexArrays(NumVAOs, VAOs);
glCreateBuffers(NumBuffers, Buffers);
glNamedBufferStorage(Buffers[ArrayBuffer1], sizeof(cube_positions), cube_positions, GL_ARRAY_BUFFER);
glNamedBufferStorage(Buffers[ArrayBuffer2], sizeof(cube_colors), cube_colors, GL_ARRAY_BUFFER);
glNamedBufferStorage(Buffers[EBOBuffer], sizeof(cube_indices), cube_indices, GL_ELEMENT_ARRAY_BUFFER);
Shader myShader("TirangleVert.glsl", "TriangleFrag.glsl");
myShader.Use();
glBindVertexArray(VAOs[Triangles]);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer1]);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer2]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffers[EBOBuffer]);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(cPosition, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) sizeof(cube_positions));
glEnableVertexAttribArray(vPosition);
glEnableVertexAttribArray(cPosition);
}
void display()
{
GLfloat black[] = { 0.2f, 0.5f, 0.6f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray(VAOs[Triangles]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffers[EBOBuffer]);
glLineWidth(20);
glPointSize(20);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(0xFFFF);
glDrawElements(GL_TRIANGLE_STRIP, 17, GL_UNSIGNED_SHORT, NULL);
//glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);
//glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT,
// (const GLvoid *)(9 * sizeof(GLushort)));
}
void dealloc()
{
glDeleteVertexArrays(NumVAOs, VAOs);
glDeleteBuffers(NumBuffers, Buffers);
}
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 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;
}
init();
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
display();
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
dealloc();
// 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);
}
TirangleVert.glsl:
#version 450 core
layout (location = 0) in vec4 cube_pos;
layout (location = 1) in vec4 colors;
out vec4 myColor;
void main()
{
gl_Position = cube_pos;
myColor = colors;
}
TriangleFrag.glsl:
#version 450 core
layout (location = 0) in vec4 myColor;
out vec4 color;
void main()
{
color = myColor;
}
PS: I realize that there's a typo in the name of the vertex shader, but it's all accounted for. Also, there's no problem with Shader.h, as I have used it before with no issues.
Many thanks.
The last parameter of the glNamedBufferStorage
is the bitfield, which specifies the intended usage of the buffer's data store, rather than GL_ARRAY_BUFFER
or GL_ELEMENT_ARRAY_BUFFER
. This will cause a GL_INVALID_VALUE
error:
GLbitfield flags = GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
glNamedBufferStorage(Buffers[ArrayBuffer1], sizeof(cube_positions), cube_positions, flags);
glNamedBufferStorage(Buffers[ArrayBuffer2], sizeof(cube_colors), cube_colors, flags);
glNamedBufferStorage(Buffers[EBOBuffer], sizeof(cube_indices), cube_indices, flags);
glVertexAttribPointer
specifies a vertex array which is refers to the array buffer which is currently bound.
The proper buffer has to be bound by glBindBuffer
before glVertexAttribPointer
is called. Note, there is only 1 buffer which can be currently bound.
If a buffer is bound, then the last parameter (pointer) is treated as a byte offset into the buffer object's data store. In your case this parameter has to be 0. Note, in a core profile context you have to use an array buffer, a directly addressed memory is not valid.
glBindVertexArray(VAOs[Triangles]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffers[EBOBuffer]);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer1]);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer2]);
glVertexAttribPointer(cPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vPosition);
glEnableVertexAttribArray(cPosition);