title: SDL2 with OpenGL 4.4: Triangle Not Rendering Properly
body: <p>I'm using OpenGL 4.4 with SDL2. I am trying to render a simple triangle with the vertices (-1, -1, 0), (1, -1, 0), (0, 1, 0). However, when I think I'm doing everything correctly, nothing is drawn.</p>
  
  <p>I extracted and reorganized the relevant code from my project: </p>
  
  <pre><code>#include &lt;cerrno&gt;
  #include &lt;cstring&gt;
  #include &lt;exception&gt;
  #include &lt;fstream&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  #include &lt;GL/glew.h&gt;
  #include &lt;GL/glu.h&gt;
  #include &lt;SDL2/SDL.h&gt;
  #include &lt;SDL2/SDL_opengl.h&gt;
  
  void init();
  void cleanUp();
  std::string loadShader(std::string filepath);
  void checkShaderSuccess(GLuint shader);
  
  SDL_Window* win;
  SDL_GLContext glContext;
  GLuint program, vertShader, fragShader, vao, vbo;
  
  class GenError: public std::exception {
   public:
          GenError():
                  exception(), msg("") {}
  
          GenError(const std::string&amp; m):
                  exception(), msg(m) {}
  
          virtual ~GenError() throw() {}
  
          virtual const char* what() const throw() {
                  return msg.c_str();
          }
   private:
          std::string msg;
  };
  
  int main() {
          init();
  
          program = glCreateProgram();
          if (program == 0) {
                  throw GenError("Shader creation failed: "
                                    "Could not find valid memory location in "
                                    "constructor");
          }
  
          vertShader = glCreateShader(GL_VERTEX_SHADER);
          fragShader = glCreateShader(GL_FRAGMENT_SHADER);
          if (vertShader == 0 || fragShader == 0) {
                  std::string m;
                  m += "Shader creation failed: "
                          "Could not find valid memory location when "
                          "adding shader: ";
                  m += (char *)gluErrorString(glGetError());
                  throw GenError(m);
          }
  
          std::cout &lt;&lt; "Creating vertex shader..." &lt;&lt; std::endl;
          std::string data = loadShader("./shaders/basicVertex.vs");
          const GLchar* data_c = data.c_str();
          glShaderSource(vertShader, 1, &amp;data_c, NULL);
          glCompileShader(vertShader);
          checkShaderSuccess(vertShader);
          glAttachShader(program, vertShader);
          std::cout &lt;&lt; "Vertex shader created" &lt;&lt; std::endl;
  
          std::cout &lt;&lt; "Creating fragment shader..." &lt;&lt; std::endl;
          data = loadShader("./shaders/basicFragment.fs");
          data_c = data.c_str();
          glShaderSource(fragShader, 1, &amp;data_c, NULL);
          glCompileShader(fragShader);
          checkShaderSuccess(fragShader);
          glAttachShader(program, fragShader);
          std::cout &lt;&lt; "Fragment shader created" &lt;&lt; std::endl;
  
          glLinkProgram(program);
  
          GLint success;
          glGetProgramiv(program, GL_LINK_STATUS, &amp;success);
          if (success == GL_FALSE) {
                  GLint logLen = 0;
                  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &amp;logLen);
                  GLchar programLog[logLen];
                  glGetProgramInfoLog(program, logLen, &amp;logLen, programLog);
                  std::string m;
                  m += "Failed to link program: ";
                  m += (char *)gluErrorString(glGetError());
                  m += ": ";
                  m += (char *)programLog;
                  throw GenError(m);
          }
  
          glValidateProgram(program);
  
          glGetProgramiv(program, GL_VALIDATE_STATUS, &amp;success);
          if (success == GL_FALSE) {
                  GLint logLen = 0;
                  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &amp;logLen);
                  GLchar programLog[logLen];
                  glGetProgramInfoLog(program, logLen, &amp;logLen, programLog);
                  std::string m;
                  m += "Failed to validate program: ";
                  m += (char *)gluErrorString(glGetError());
                  m += ": ";
                  m += (char *)programLog;
                  throw GenError(m);
          }
  
          glGenVertexArrays(1, &amp;vao);
          glBindVertexArray(vao);
          glGenBuffers(1, &amp;vbo);
  
          const GLfloat verts[] = {
                  -1.0f, -1.0f, 0.0f,
                   1.0f, -1.0f, 0.0f,
                   0.0f,  1.0f, 0.0f
          };
          glBindBuffer(GL_ARRAY_BUFFER, vbo);
          glBufferData(GL_ARRAY_BUFFER,
                       sizeof(verts),
                       verts,
                       GL_STATIC_DRAW );
  
          SDL_Event ev;
          bool running = true;
          while (true) {
                  while (SDL_PollEvent(&amp;ev)) {
                          if (ev.type == SDL_WINDOWEVENT &amp;&amp;
                              ev.window.event == SDL_WINDOWEVENT_CLOSE) {
                                  std::cout &lt;&lt; "Closing window..." &lt;&lt; std::endl;
                                  running = false;
                                  break;
                          }
                  }
  
                  if (!running) break;
  
                  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                  glUseProgram(program);
  
                  glEnableVertexAttribArray(0);
                  glBindBuffer(GL_ARRAY_BUFFER, vbo);
                  glVertexAttribPointer(0,
                                        3,
                                        GL_FLOAT,
                                        GL_FALSE,
                                        3*sizeof(GLfloat),
                                        (GLvoid*)0 );
  
                  glDrawArrays(GL_TRIANGLES, 0, 3);
                  glDisableVertexAttribArray(0);
  
                  SDL_GL_SwapWindow(win);
          }
          std::cout &lt;&lt; "Window closed" &lt;&lt; std::endl;
  
          glDeleteBuffers(1, &amp;vbo);
          glDeleteVertexArrays(1, &amp;vao);
          glDeleteProgram(program);
          glDeleteShader(vertShader);
          glDeleteShader(fragShader);
  
          cleanUp();
  
          return 0;
  }
  
  void init() {
          std::cout &lt;&lt; "Initializing..." &lt;&lt; std::endl;
  
          if (SDL_Init(SDL_INIT_VIDEO) != 0) {
                  std::string m;
                  m.append("Error initializing SDL2: ");
                  m.append(SDL_GetError());
                  throw GenError(m);
          }
  
          SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
          SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
          SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
          SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
  
          win = SDL_CreateWindow("Triangle Test",
                                 SDL_WINDOWPOS_UNDEFINED,
                                 SDL_WINDOWPOS_UNDEFINED,
                                 800, 600,
                                 SDL_WINDOW_OPENGL );
          if (win == NULL) {
                  throw GenError(SDL_GetError());
          }
  
          glContext = SDL_GL_CreateContext(win);
          if (glContext == NULL) {
                  std::string m;
                  m.append("Error associating window with OpenGL: SDL Error: ");
                  m.append(SDL_GetError());
                  throw GenError(m);
          }
  
          glewExperimental = GL_TRUE;
          GLenum glewErr = glewInit();
          if (glewErr != GLEW_OK) {
                  std::string m;
                  m.append("Error initializing OpenGL GLEW extension: ");
                  m.append((const char*)glewGetErrorString(glewErr));
                  throw GenError(m);
          } else {
                  /* GLEW does not play nice with OpenGL 4.4.
                   * GLEW thinks OpenGL 4.4 is "pretentious" and
                   * "entitled". GLEW likes to throw an invalid
                   * enumerant error the next time glGetError is
                   * called after GLEW's initialization.
                   * glGetError must be envoked to discard this
                   * faulty error. GLEW makes my code look sloppy.
                   * We do not like GLEW. We tolerate GLEW.
                   */
                  GLenum junk = glGetError();
          }
  
          glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
          glFrontFace(GL_CW);
          glCullFace(GL_BACK);
          glEnable(GL_CULL_FACE);
          glEnable(GL_DEPTH_TEST);
  
          glEnable(GL_FRAMEBUFFER_SRGB);
  
          if(SDL_GL_SetSwapInterval(1) &lt; 0) {
                  std::cerr &lt;&lt; "Warning: Unable to set VSync! "
                            &lt;&lt; "SDL Error: "
                            &lt;&lt; SDL_GetError() &lt;&lt; std::endl;
          }
  
          GLenum error = glGetError();
          if (error != GL_NO_ERROR) {
                  std::string m;
                  m.append("Error initializing OpenGL: OpenGL Error: ");
                  m.append(reinterpret_cast&lt;const char*&gt;(gluErrorString(error)));
                  throw GenError(m);
          }
  
          std::cout &lt;&lt; "Initialized" &lt;&lt; std::endl;
  }
  
  void cleanUp() {
          std::cout &lt;&lt; "Cleaning up..." &lt;&lt; std::endl;
          SDL_GL_DeleteContext(glContext);
          SDL_DestroyWindow(win);
          SDL_Quit();
          std::cout &lt;&lt; "Cleaned" &lt;&lt; std::endl;
  }
  
  std::string loadShader(std::string filepath) {
          std::ifstream shaderFile(filepath.c_str());
          if (!shaderFile.is_open()) {
                  std::cerr &lt;&lt; "Could not load shader: "
                            &lt;&lt; "Error opening "
                            &lt;&lt; filepath
                            &lt;&lt; ": " &lt;&lt; std::strerror(errno)
                            &lt;&lt; std::endl;
                  return std::string("");
          }
  
          std::string content, line;
          while (std::getline(shaderFile, line)) {
                  content += line + '\n';
          }
  
          shaderFile.close();
  
          return content;
  }
  
  void checkShaderSuccess(GLuint shader) {
          GLint success;
          glGetShaderiv(shader, GL_COMPILE_STATUS, &amp;success);
          if (success == GL_FALSE) {
                  GLint logLen = 0;
                  glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &amp;logLen);
                  GLchar shaderLog[logLen];
                  glGetShaderInfoLog(shader, logLen, &amp;logLen, shaderLog);
                  std::string m;
                  m += "Shader compilation failed: ";
                  m += (char *)gluErrorString(glGetError());
                  m += ": ";
                  m += (char *)shaderLog;
                  glDeleteShader(shader);
                  throw GenError(m);
          }
  }
  </code></pre>
  
  <p>...without error catching (for faster skimming): </p>
  
  <pre><code>#include &lt;cerrno&gt;
  #include &lt;cstring&gt;
  #include &lt;exception&gt;
  #include &lt;fstream&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  #include &lt;GL/glew.h&gt;
  #include &lt;GL/glu.h&gt;
  #include &lt;SDL2/SDL.h&gt;
  #include &lt;SDL2/SDL_opengl.h&gt;
  
  void init();
  void cleanUp();
  std::string loadShader(std::string filepath);
  
  SDL_Window* win;
  SDL_GLContext glContext;
  GLuint program, vertShader, fragShader, vao, vbo;
  
  int main() {
          init();
  
          program = glCreateProgram();
  
          vertShader = glCreateShader(GL_VERTEX_SHADER);
          fragShader = glCreateShader(GL_FRAGMENT_SHADER);
  
          std::cout &lt;&lt; "Creating vertex shader..." &lt;&lt; std::endl;
          std::string data = loadShader("./shaders/basicVertex.vs");
          const GLchar* data_c = data.c_str();
          glShaderSource(vertShader, 1, &amp;data_c, NULL);
          glCompileShader(vertShader);
          glAttachShader(program, vertShader);
          std::cout &lt;&lt; "Vertex shader created" &lt;&lt; std::endl;
  
          std::cout &lt;&lt; "Creating fragment shader..." &lt;&lt; std::endl;
          data = loadShader("./shaders/basicFragment.fs");
          data_c = data.c_str();
          glShaderSource(fragShader, 1, &amp;data_c, NULL);
          glCompileShader(fragShader);
          glAttachShader(program, fragShader);
          std::cout &lt;&lt; "Fragment shader created" &lt;&lt; std::endl;
  
          glLinkProgram(program);
  
          glGenVertexArrays(1, &amp;vao);
          glBindVertexArray(vao);
          glGenBuffers(1, &amp;vbo);
  
          const GLfloat verts[] = {
                  -1.0f, -1.0f, 0.0f,
                   1.0f, -1.0f, 0.0f,
                   0.0f,  1.0f, 0.0f
          };
          glBindBuffer(GL_ARRAY_BUFFER, vbo);
          glBufferData(GL_ARRAY_BUFFER,
                       sizeof(verts),
                       verts,
                       GL_STATIC_DRAW );
  
          SDL_Event ev;
          bool running = true;
          while (true) {
                  while (SDL_PollEvent(&amp;ev)) {
                          if (ev.type == SDL_WINDOWEVENT &amp;&amp;
                              ev.window.event == SDL_WINDOWEVENT_CLOSE) {
                                  std::cout &lt;&lt; "Closing window..." &lt;&lt; std::endl;
                                  running = false;
                                  break;
                          }
                  }
  
                  if (!running) break;
  
                  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                  glUseProgram(program);
  
                  glEnableVertexAttribArray(0);
                  glBindBuffer(GL_ARRAY_BUFFER, vbo);
                  glVertexAttribPointer(0,
                                        3,
                                        GL_FLOAT,
                                        GL_FALSE,
                                        3*sizeof(GLfloat),
                                        (GLvoid*)0 );
  
                  glDrawArrays(GL_TRIANGLES, 0, 3);
                  glDisableVertexAttribArray(0);
  
                  SDL_GL_SwapWindow(win);
          }
          std::cout &lt;&lt; "Window closed" &lt;&lt; std::endl;
  
          glDeleteBuffers(1, &amp;vbo);
          glDeleteVertexArrays(1, &amp;vao);
          glDeleteProgram(program);
          glDeleteShader(vertShader);
          glDeleteShader(fragShader);
  
          cleanUp();
  
          return 0;
  }
  
  void init() {
          std::cout &lt;&lt; "Initializing..." &lt;&lt; std::endl;
  
          SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
          SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
          SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
          SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
          SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
  
          win = SDL_CreateWindow("Triangle Test",
                                 SDL_WINDOWPOS_UNDEFINED,
                                 SDL_WINDOWPOS_UNDEFINED,
                                 800, 600,
                                 SDL_WINDOW_OPENGL );
  
          glContext = SDL_GL_CreateContext(win);
  
          glewExperimental = GL_TRUE;
          GLenum glewErr = glewInit();
  
          glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
          glFrontFace(GL_CW);
          glCullFace(GL_BACK);
          glEnable(GL_CULL_FACE);
          glEnable(GL_DEPTH_TEST);
  
          glEnable(GL_FRAMEBUFFER_SRGB);
  
          std::cout &lt;&lt; "Initialized" &lt;&lt; std::endl;
  }
  
  void cleanUp() {
          std::cout &lt;&lt; "Cleaning up..." &lt;&lt; std::endl;
          SDL_GL_DeleteContext(glContext);
          SDL_DestroyWindow(win);
          SDL_Quit();
          std::cout &lt;&lt; "Cleaned" &lt;&lt; std::endl;
  }
  
  std::string loadShader(std::string filepath) {
          std::ifstream shaderFile(filepath.c_str());
  
          std::string content, line;
          while (std::getline(shaderFile, line)) {
                  content += line + '\n';
          }
  
          shaderFile.close();
  
          return content;
  }
  </code></pre>
  
  <p>...my vertex shader (GLSL): </p>
  
  <pre><code>#version 440
  
  layout (location = 0) in vec3 position;
  
  void main() {
       gl_Position = vec4(0.5 * position, 1.0);
  }
  </code></pre>
  
  <p>...and my fragment shader:</p>
  
  <pre><code>#version 440
  
  out vec4 fragColor;
  
  void main() {
       fragColor = vec4(0.0, 1.0, 1.0, 1.0);
  }
  </code></pre>
  
  <p>Now oddly enough, when I change line 148 in my C++ code (with error catching) from this...</p>
  
  <pre><code>3*sizeof(GLfloat),
  </code></pre>
  
  <p>...to this (in other words, changing the stride)...</p>
  
  <pre><code>3*sizeof(GLdouble),
  </code></pre>
  
  <p>...compiling and running produces a triangle with the vertices (-1, -1, 0), (0, 0, 0), (0, 1, 0). The second vertex is apparently getting obscured. Instead of an isosceles triangle, I get a scalene triangle.</p>
  
  <p>I would like to 1) figure out how to fix my program so that it displays a triangle with the specified vertices, and 2) understand what I did wrong initially that caused my such an odd result when modifying the aforementioned line of code.</p>
  
  <p>I have been tinkering with this for almost a week. <strong>Any</strong> insight is appreciated. Thanks!</p>