Reputation: 3931
I'm following along with this OpenGL example somewhat, and my code compiles, but it doesn't work properly.
I'd expect to see a white rectangle, but instead nothing is rendered but the clear color. After I call glDrawArrays
, glGetError
tells me that error 1282 has been raised. I'm sure the problem is very obvious, but I can't see where I'm going wrong. Here's my simple example of the problem:
#include <errno.h>
#include <stdio.h>
#include <GLFW/glfw3.h>
#include <GL/gl.h>
#define WINDOW_W 300
#define WINDOW_H 300
static const GLchar *vertex_shader_src = {
"#version 440\n"
"in vec4 position;\n"
"uniform mat4 projection;\n"
"void main()\n"
"{\n"
"\tgl_Position = projection * position;\n"
"}\n"
};
static const GLchar *fragment_shader_src = {
"#version 440\n"
"uniform vec4 color;\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
"outputColor = color;\n"
"}\n"
};
static GLuint program = 0;
static GLuint vao = 0;
static const GLfloat rect_vertices[] = {
5.0f, 5.0f,
WINDOW_W - 5.0f, 5.0f,
WINDOW_W - 5.0f, 5.0f,
WINDOW_W - 5.0f, WINDOW_H - 5.0f,
WINDOW_W - 5.0f, WINDOW_H - 5.0f,
5.0f, WINDOW_H - 5.0f,
5.0f, WINDOW_H - 5.0f,
5.0f, 5.0f
};
static GLuint rect_vbo = 0;
int init_program()
{
GLint status;
GLuint vertexShader;
GLuint fragmentShader;
// Initialize our vertex shader.
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertex_shader_src, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE)
return -EINVAL;
// Initialize our fragment shader.
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragment_shader_src, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE)
return -EINVAL;
// Initialize the program.
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &status);
if(status == GL_FALSE)
return -EINVAL;
// Detach the shaders, now that the program is linked.
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
// Done!
return 0;
}
void ortho_matrix(GLfloat *m, GLfloat l, GLfloat r,
GLfloat b, GLfloat t, GLfloat n, GLfloat f)
{
m[0] = 2.0f / (r - l);
m[1] = 0.0f;
m[2] = 0.0f;
m[3] = 0.0f;
m[4] = 0.0f;
m[5] = 2.0f / (t - b);
m[6] = 0.0f;
m[7] = 0.0f;
m[8] = 0.0f;
m[9] = 0.0f;
m[10] = -2.0f / (f - n);
m[11] = 0.0f;
m[12] = 0.0f;
m[13] = 0.0f;
m[14] = 0.0f;
m[15] = 1.0f;
}
int gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
GLint colorVec;
GLfloat color[4] = {r, g, b, a};
colorVec = glGetUniformLocation(program, "color");
if(colorVec == -1)
return -EINVAL;
glUniform4fv(colorVec, 1, color);
return 0;
}
int set_uniforms(int width, int height)
{
int r;
GLint orthoMatrix;
GLfloat matrix[16];
// Set our orthographic projection uniform.
orthoMatrix = glGetUniformLocation(program, "projection");
if(orthoMatrix == -1)
return -EINVAL;
ortho_matrix(matrix, -0.5f, ((GLfloat) (width - 1)) + 0.5f,
((GLfloat) (height - 1)) + 0.5f, -0.5f, 0.0f, 1.0f);
glUniformMatrix4fv(orthoMatrix, 1, GL_FALSE, matrix);
// Set our rendering color uniform.
r = gl_color(1.0f, 1.0f, 1.0f, 1.0f);
if(r < 0)
return r;
// Done!
return 0;
}
int init_vbo()
{
glGenBuffers(1, &rect_vbo);
glBindBuffer(GL_ARRAY_BUFFER, rect_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(rect_vertices),
rect_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return 0;
}
int render()
{
GLenum err;
glBindBuffer(GL_ARRAY_BUFFER, rect_vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / sizeof(GLfloat));
err = glGetError();
while(err != GL_NO_ERROR)
{
printf("glDrawArrays err: %d\n", err);
err = glGetError();
}
glDisableVertexAttribArray(0);
return 0;
}
int main(void)
{
int r;
GLFWwindow *window;
int width;
int height;
if(!glfwInit())
return -EINVAL;
window = glfwCreateWindow(WINDOW_W, WINDOW_H,
"My Window", NULL, NULL);
if(!window)
{
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
r = init_program();
if(r < 0)
{
glfwTerminate();
return 1;
}
r = init_vbo();
if(r < 0)
{
glfwTerminate();
return 1;
}
while(!glfwWindowShouldClose(window))
{
// Initialize the GL viewport.
glfwGetFramebufferSize(window, &width, &height);
r = set_uniforms(width, height);
if(r < 0)
{
glfwTerminate();
return r;
}
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
// Call the user-provided rendering function.
r = render();
if(r < 0)
{
glfwTerminate();
return r;
}
// End GL rendering, swap the buffer, and poll for events.
glUseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
I've tried searching for this error number, and I've found e.g. this, but I don't really see any way to find out what specifically is going wrong.
What am I doing wrong or, alternatively, how can I found out?
Upvotes: 0
Views: 205
Reputation: 54572
The only obvious problem I see is the arguments to glDrawArrays()
:
glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / sizeof(GLfloat));
The 3rd argument is the number of vertices, while the value passed here is the number of float values. Since the vertices in this code use 2 float coordinates per vertex, this should be:
glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / (2 * sizeof(GLfloat)));
In an ideal world, you would look up the possible errors in the Errors section of the official man page. The unfortunate reality is that the man pages are often incomplete, particularly when it comes to error conditions. So it's a good starting point, but not always the final word.
To get to the bottom of things if the man page looks questionable, there are the spec document. I did look there, and I'm frankly still not entirely clear about what exactly is causing your GL_INVALID_OPERATION
. I found one candidate here:
An INVALID_OPERATION error is generated if the command would source data beyond the end of the buffer object.
But this is actually under glDrawArraysInstanced()
, so it's not clear to me if it also applies to glDrawArrays()
.
Another option is that you got a Core Profile context. But you're not requesting that, and from my understanding of the GLFW documentation, it's not the default. In the Core Profile, you have to use a VAO (Vertex Array Object) for setting up vertex state.
Upvotes: 1
Reputation: 3931
I actually found out what was wrong. The error actually occurred much earlier than I originally thought, where I was setting my uniforms. This page had the answer - in particular:
glUniform doesn't work
You probably did not bind the correct shader first. Call glUseProgram(myprogram) first.
Moving my call to set_uniforms
down below my call to glUseProgram
allows the rendering to work properly.
Upvotes: 0