Search code examples
copenglglslfreeglutvao

Can't change background color in OpenGL


I've just started to experiment with OpenGL (using freeglut and GLEW). I can get a window to pop up, but nothing gets drawn to it, I can't even get it to change background color.

Here's what the main function looks like:

int
main(int argc, char **argv)
{ 
  GLenum err;

  /* Initialize GLUT library */
  glutInit(&argc, argv);

  /* Set window mode */
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

  /* Choose OpenGL version */
  glutInitContextVersion(3, 3);

  /* Choose OpenGL profile */
  glutInitContextFlags(GLUT_CORE_PROFILE);

  /* Create a GLUT window */
  glutCreateWindow("OpenGL 2D");

  /* Initialize GLEW library */
  glewExperimental = GL_TRUE;
  err = glewInit();
  if(err != GLEW_OK) {
    printf("Cannot initialize GLEW: %s\n",
       glewGetErrorString(err));
    return 1;
  }

  /* WORKAROUND: Ignore all GLEW errors */
  while(glGetError() != GL_NO_ERROR)
    ;

  (void) printf("OpenGL vendor: \"%s\"\n"
        "       renderer: \"%s\"\n"
        "       version: \"%s\"\n"
        "       SL version: \"%s\"\n",
        glGetString(GL_VENDOR),
        glGetString(GL_RENDERER),
        glGetString(GL_VERSION),
        glGetString(GL_SHADING_LANGUAGE_VERSION));

  /* Set up callback function for "reshape" event */
  printf("Setting callback functions\n");
  glutReshapeFunc(canvas_reshape);

  /* Set up callback function for "display" event */
  glutDisplayFunc(canvas_display);

  /* Set up callback function for "keyboard" event */
  glutKeyboardFunc(canvas_keyboard);

  /* Set up callback function for "timer" event */
  glutTimerFunc(30, canvas_timer, 0);

  /* Initialize OpenGL */
  init();

  /* Choose the window's position */
  glutPositionWindow(100, 100);

  /* Choose the window's size */
  glutReshapeWindow(800, 600);

  /* Start main loop */
  printf("Entering main loop\n");
  glutMainLoop();

  return 0;
}

Here's what init looks like:

init()
{
  const GLchar *vertex_shader_source[] = {
    "#version 330 core\n",
    "\n",
    "layout(location=0) in vec4 position;\n",
    "out vec4 color;\n",
    "uniform mat4 viewtrans;\n",
    "\n",
    "void\n",
    "main()\n",
    "{\n",
    "  gl_Position = viewtrans * position;\n"
    "  color =  vec4(1.0, 1.0, 1.0, 1.0);\n"
    "}\n" };
  const GLchar *fragment_shader_source[] = {
    "#version 330 core\n",
    "in vec4 color;\n",
    "layout(location=0) out vec4 fcolor;\n",
    "void\n",
    "main()\n",
    "{\n",
    "  fcolor = color;\n",
    "}\n" };
  char compiler_log[LOGSIZE];

  /* Obtain an unused name for our vertex array */
  printf("Creating vertex array\n");
  glGenVertexArrays(1, &vertex_array);
  check_error("glGenVertexArrays");

  /* Tell OpenGL to use the new vertex array */
  glBindVertexArray(vertex_array);
  check_error("glBindVertexArray");

  /* Obtain an unused name for our vertex buffer */
  printf("Creating vertex buffer\n");
  glGenBuffers(1, &vertex_buffer);
  check_error("glGenBuffers");

  /* Tell OpenGL to use the new vertex buffer as the
   * vertex array */
  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  check_error("glBindBuffer");

  /* We want to get two coordinates from the vertex buffer and
   * feed them as the first parameter to the vertex shader */
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0);

  /* Create vertex shader */
  printf("Creating vertex shader\n");
  vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  check_error("glCreateShader");

  /* Assign vertex shader source code */
  glShaderSource(vertex_shader, sizeof(vertex_shader_source) / sizeof(GLchar *),
         vertex_shader_source, 0);
  check_error("glShaderSource");

  /* Compile vertex shader */
  glCompileShader(vertex_shader);
  check_error("glCompileShader");

  /* Get compiler log *//* Set up callback function for "timer" event */
  glGetShaderInfoLog(vertex_shader, LOGSIZE, 0, compiler_log);
  printf("  Compiler log: \"%s\"\n", compiler_log);

  /* Create fragment shader */
  printf("Creating fragment shader\n");
  fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  check_error("glCreateShader");

  /* Assign fragment shader source code */
  glShaderSource(fragment_shader, sizeof(fragment_shader_source) / sizeof(GLchar *),
         fragment_shader_source, 0);
  check_error("glShaderSource");

  /* Compile fragment shader */
  glCompileShader(fragment_shader);
  check_error("glCompileShader");

  /* Get compiler log */
  glGetShaderInfoLog(fragment_shader, LOGSIZE, 0, compiler_log);
  printf("  Compiler log: \"%s\"\n", compiler_log);

  /* Create shader program */
  printf("Creating shader program\n");
  shader_program = glCreateProgram();
  check_error("glCreateProgram");

  /* Attach vertex shader */
  glAttachShader(shader_program, vertex_shader);
  check_error("glAttachShader");

  /* Attach fragment shader */
  glAttachShader(shader_program, fragment_shader);
  check_error("glAttachShader");

  /* Link shader program */
  glLinkProgram(shader_program);
  check_error("glLinkProgram");

  /* Get linker log */
  glGetProgramInfoLog(shader_program, LOGSIZE, 0, compiler_log);
  printf("  Linker log: \"%s\"\n", compiler_log);

  /* Get location of "viewtrans" matrix */
  viewtrans = glGetUniformLocation(shader_program, "viewtrans");
  check_error("glGetUniformLocation");

  /* Tell OpenGL to use the new shader program */
  glUseProgram(shader_program);

  /* Choose background color */
  glClearColor(1.0, 0.0, 1.0, 0.0);
}

Here's what I use to draw:

static void
canvas_display()
{
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

This is all based off of a tutorial. What actually happens is something like a 300 x 300 white window shows up, gets reshaped into a 800 x 600 black window, BUT with still a 300 x 300 white square in the middle or in a corner, whose pixels (partially) turn black when resizing the window such that (part of) the square disappears (either manually or through code). I've also written code to draw triangles, but that doesn't work either, as one might expect. But here's the code for that anyway:

static void
canvas_display()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    GLfloat vertices[] =
    { 0.0, 0.0,
      0.5, 0.5,
      0.5, 0.0 };

    glGenVertexArrays(1, &vertex_array);
    glBindVertexArray(vertex_array);

    glGenBuffers(1, &vertex_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 2, vertices);

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

Solution

  • Do not continuously specify the new vertex array objects. Create 1 Vertex Array Object at initialization. The vertex array is contained in the Vertex Buffer Object. When a named buffer object is bound to the ARRAY_BUFFER target, then the last parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store. Thus the offset has to be NULL:

    void init()
    {
        // [...]
    
        GLfloat vertices[] =
        { 0.0, 0.0,
          0.5, 0.5,
          0.5, 0.0 };
    
        glGenVertexArrays(1, &vertex_array);
        glBindVertexArray(vertex_array);
    
        glGenBuffers(1, &vertex_buffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 2, NULL);
    }
    

    Ensure that the program is installed and the VAO is bound when the geometry is drawn. By default the values of uniforms are initialized by zero. At least you have to set the Identity matrix then matrix uniform viewtrans.
    Since you use double buffering (GLUT_DOUBLE), you have to swaps the buffers of the current window after drawing all the geometry by glutSwapBuffers

    void canvas_display()
    {
        glClearColor(1.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glUseProgram(shader_program);
        GLfloat identity_mat[] = { 1,0,0,0,  0,1,0,0, 0,0,1,0, 0,0,0,1 };
        glUniformMatrix4fv(viewtrans, 1, GL_FALSE, identity_mat);
    
        glBindVertexArray(vertex_array);
        glDrawArrays(GL_TRIANGLES, 0, 3);
    
        glutSwapBuffers();
        glutPostRedisplay();
    }