0

Below I've included glfw-quick-test.c, which is basically copied verbatim from http://www.glfw.org/docs/latest/quick.html - except for removed use of glad, added background color, a couple of defines so it compiles on Ubuntu 14.04 (64-bit), and a preprocessor #ifdef switch (macro DO_OPENGL_THREE) to change requested OpenGL version.


When I compile with:

gcc -g -o glfw-quick-test.exe glfw-quick-test.c -lglfw -lGLU -lGL -lm
./glfw-quick-test.exe

... then I get the message "GLFW Requesting OpenGL 2.1" and drawing is fine:

glfw3A


When I compile with:

gcc -g -DDO_OPENGL_THREE -o glfw-quick-test.exe glfw-quick-test.c -lglfw -lGLU -lGL -lm
./glfw-quick-test.exe

... then I get the message "GLFW Requesting OpenGL 3.2" and the rotating triangle is not drawn at all - only the background color is preserved:

glfw3B


Can anyone explain why does this happen? Can I somehow get GLFW3 to draw even if OpenGL 3.2 is requested, and if so, how?

(I'm aware that the original source code says "// NOTE: OpenGL error checks have been omitted for brevity", but I'm not sure what sort of error checks I should add, to see what the problem would be with OpenGL 3.2 drawing ...)

The code, glfw-quick-test.c (EDIT: now with error checking):

// http://www.glfw.org/docs/latest/quick.html

#define UBUNTU14
#ifdef UBUNTU14 // assume Ubuntu 14.04
 // strange; Ubuntu 14 GLFW/glfw3.h doesn't have GLFW_TRUE, GLFW_FALSE, mentions GL_TRUE GL_FALSE
 #define GLFW_TRUE GL_TRUE
 #define GLFW_FALSE GL_FALSE
#endif

//~ #include <glad/glad.h> // "GL/GLES/EGL/GLX/WGL Loader-Generator based on the official specs."
#include <GLFW/glfw3.h>
#include "linmath.h"
#include <stdlib.h>
#include <stdio.h>
static const struct
{
  float x, y;
  float r, g, b;
} vertices[3] =
{
  { -0.6f, -0.4f, 1.f, 0.f, 0.f },
  {  0.6f, -0.4f, 0.f, 1.f, 0.f },
  {   0.f,  0.6f, 0.f, 0.f, 1.f }
};
static const char* vertex_shader_text =
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
"  gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
"  color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"varying vec3 color;\n"
"void main()\n"
"{\n"
"  gl_FragColor = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
  fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window, GLFW_TRUE);
}
void checkGLerrors(char *label) {
    // check OpenGL error
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR) {
    char* errorstr = "";
    switch(err) {
      case GL_INVALID_OPERATION:  errorstr="INVALID_OPERATION";  break;
      case GL_INVALID_ENUM:       errorstr="INVALID_ENUM";     break;
      case GL_INVALID_VALUE:      errorstr="INVALID_VALUE";    break;
      case GL_OUT_OF_MEMORY:      errorstr="OUT_OF_MEMORY";    break;
      case GL_INVALID_FRAMEBUFFER_OPERATION:  errorstr="INVALID_FRAMEBUFFER_OPERATION";  break;
    }
    printf("OpenGL error ('%s'): %d %s\n", label, err, errorstr);
    }
}

int main(void)
{
  GLFWwindow* window;
  GLuint vertex_buffer, vertex_shader, fragment_shader, program;
  GLint mvp_location, vpos_location, vcol_location;
  glfwSetErrorCallback(error_callback);
  if (!glfwInit())
    exit(EXIT_FAILURE);
  // NB: Ubuntu will not draw if 3.2 (just black screen) - only if 2.0 or 2.1?
  #ifdef DO_OPENGL_THREE
  printf("GLFW Requesting OpenGL 3.2\n");
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // only 3.2+
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); //only 3.0+
  glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // https://stackoverflow.com/q/23834680/
  #else
  printf("GLFW Requesting OpenGL 2.1\n");
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // 2);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // 0);
  #endif
  checkGLerrors("post hint");
  window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
  if (!window)
  {
    glfwTerminate();
    exit(EXIT_FAILURE);
  }
  checkGLerrors("post glfwCreateWindow");
  glfwSetKeyCallback(window, key_callback);
  glfwMakeContextCurrent(window);
  //~ gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
  glfwSwapInterval(1);
  // NOTE: OpenGL error checks have been omitted for brevity
  glGenBuffers(1, &vertex_buffer);
  checkGLerrors("post glGenBuffers");
  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
  glCompileShader(vertex_shader);
  fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
  glCompileShader(fragment_shader);
  program = glCreateProgram();
  glAttachShader(program, vertex_shader);
  glAttachShader(program, fragment_shader);
  glLinkProgram(program);
  checkGLerrors("post glLinkProgram");
  mvp_location = glGetUniformLocation(program, "MVP");
  vpos_location = glGetAttribLocation(program, "vPos");
  vcol_location = glGetAttribLocation(program, "vCol");
  checkGLerrors("post gl locations");
  glEnableVertexAttribArray(vpos_location);
  checkGLerrors("post gl EnableVertexAttribArray");
  glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
              sizeof(float) * 5, (void*) 0);
  checkGLerrors("post glVertexAttribPointer");
  glEnableVertexAttribArray(vcol_location);
  checkGLerrors("post glEnableVertexAttribArray");
  glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
              sizeof(float) * 5, (void*) (sizeof(float) * 2));
  checkGLerrors("post glVertexAttribPointer");
  while (!glfwWindowShouldClose(window))
  {
    float ratio;
    int width, height;
    mat4x4 m, p, mvp;
    glfwGetFramebufferSize(window, &width, &height);
    ratio = width / (float) height;
    glViewport(0, 0, width, height);
    glClearColor(0.784314, 0.780392, 0.305882, 1.0); // add background color
    glClear(GL_COLOR_BUFFER_BIT);
    mat4x4_identity(m);
    mat4x4_rotate_Z(m, m, (float) glfwGetTime());
    mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
    mat4x4_mul(mvp, p, m);
    glUseProgram(program);
    glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glfwSwapBuffers(window);
    glfwPollEvents();
  }
  glfwDestroyWindow(window);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}
sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 3
    Did you check what `glGetError` tells you? In a core profile you have to use a VAO. – BDL Oct 09 '17 at 07:40
  • Thanks @BDL - no, had no idea I should do that, will try to do so now... EDIT: did that, and for 3.2 am getting "`OpenGL error ('post glVertexAttribPointer'): 1282 INVALID_OPERATION`"... – sdaau Oct 09 '17 at 08:04

1 Answers1

1

Thanks to @BDL and his comment about VAO (vertex array objects), I found How to use VBOs without VAOs with OpenGL core profile? - and by trying out stuff from there, I found that the only change to the above OP code, needed so drawing is shown in OpenGL 3.2, is this:

...
  //~ gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
  glfwSwapInterval(1);
  #ifdef DO_OPENGL_THREE
  // https://stackoverflow.com/a/30057424/277826:
  // "You can however just create and bind a VAO and forget about it (keep it bound)."
  GLuint VAO;
  glGenVertexArrays(1, &VAO);
  glBindVertexArray(VAO);
  #endif
  // NOTE: OpenGL error checks have been omitted for brevity
  glGenBuffers(1, &vertex_buffer);
...

Once this section with VAO is in, there are no more OpenGL errors printed, and drawing is OK.

sdaau
  • 36,975
  • 46
  • 198
  • 278