im learning about OpenGL and i wrote the following code in C++ using this guide and this video. Also i am using GLFW for context creation and GLEW for GL functions Most of the Shader class is copied from the video up linked,
The problem is that using glDrawElements() to render inside the main loop gets me a segmentation fault:
Segmentation fault
------------------
(program exited with code: 139)
Press return to continue
while with glDrawArrays() i can draw with no problems.
Does anyone know what this could be caused by? I think the error might depend on the implementation of the Shader class, because i used glDrawArrays() in other programs that did not used this class and that cared about shaders in the main function.
program.cpp
//INCLUDE AND DECLARATIONS
#include <iostream>
#include <fstream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include "Shader.h"
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
unsigned long getFileLength(std::ifstream& file);
int loadshader(char* filename, GLchar** ShaderSource, unsigned long* len);
const GLuint WIDTH = 800, HEIGHT = 600;
//VERTEX DATA
float data[] = {
// X Y R G B
-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 1.0f, 1.0f, 1.0f // Bottom-left
};
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
//main
int main()
{ //INIT GLFW AND WINDOW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = GL_TRUE;
glewInit();
glViewport(0, 0, WIDTH, HEIGHT);
//ALLOCATE BUFFERS
//VERTEX ARRAY BUFFER
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
//ELEMENT ARRAY BUFFER
GLuint ebo;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
//CREATE SHADER
Shader shader("./shaders/basicShader");
// main loop
while (!glfwWindowShouldClose(window))
{
shader.Bind();
glfwPollEvents(); //window events
glClearColor(1.0f, 0.0f, 0.5f, 0.5f); //background
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window); //update window
}
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glfwTerminate();
return 0;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
Shader.h
#include <iostream>
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
class Shader
{
public:
Shader(const std::string& filepath);
~Shader();
void Bind();
private:
static const GLuint NUM_SHADERS = 2;
GLuint program;
GLuint shaders[NUM_SHADERS];
std::string LoadShader(const std::string& fileName);
void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage);
GLuint CreateShader(const std::string& text, unsigned int type);
};
Shader.cpp
#include "Shader.h"
Shader::Shader(const std::string& filepath)
{
program = glCreateProgram();
shaders[0] = CreateShader(LoadShader(filepath + ".vs"), GL_VERTEX_SHADER);
shaders[1] = CreateShader(LoadShader(filepath + ".fs"), GL_FRAGMENT_SHADER);
for(unsigned int i = 0; i < NUM_SHADERS; i++)
{
glAttachShader(program, shaders[i]);
}
glBindAttribLocation(program, 0, "position");
glBindFragDataLocation(program, 0, "outColor");
glLinkProgram(program);
CheckShaderError(program, GL_LINK_STATUS, true, "Error linking shader program");
glValidateProgram(program);
CheckShaderError(program, GL_LINK_STATUS, true, "Invalid shader program");
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLint posAttrib = glGetAttribLocation(program, "position");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0);
glEnableVertexAttribArray(posAttrib);
GLint AttribColor = glGetAttribLocation(program, "color");
glVertexAttribPointer(AttribColor, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float)));
glEnableVertexAttribArray(AttribColor);
}
Shader::~Shader()
{
for(unsigned int i = 0; i < NUM_SHADERS; i++)
{
glDetachShader(program, shaders[i]);
glDeleteShader(shaders[i]);
}
glDeleteProgram(program);
}
void Shader::Bind()
{
glUseProgram(program);
}
//loads shaders from files
std::string Shader::LoadShader(const std::string& fileName)
{
std::ifstream file;
file.open((fileName).c_str());
std::string output;
std::string line;
if(file.is_open())
{
while(file.good())
{
getline(file, line);
output.append(line + "\n");
}
}
else
{
std::cerr << "Unable to load shader: " << fileName << std::endl;
}
return output;
}
//Checks for eventual errors in shaders
void Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage)
{
GLint success = 0;
GLchar error[1024] = { 0 };
if(isProgram)
glGetProgramiv(shader, flag, &success);
else
glGetShaderiv(shader, flag, &success);
if(success == GL_FALSE)
{
if(isProgram)
glGetProgramInfoLog(shader, sizeof(error), NULL, error);
else
glGetShaderInfoLog(shader, sizeof(error), NULL, error);
std::cerr << errorMessage << ": '" << error << "'" << std::endl;
}
}
GLuint Shader::CreateShader(const std::string& text, unsigned int type)
{
GLuint shader = glCreateShader(type);
if(shader == 0)
std::cerr << "error allocating shader" << std:: endl;
const GLchar* p[1];
p[0] = text.c_str();
GLint lengths[1];
lengths[0] = text.length();
glShaderSource(shader, 1, p, lengths);
glCompileShader(shader);
CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");
return shader;
}