Hi everyone, I was making a shader class header which loads the shader from files, compiles and links them into the final shader object. It’s based on this: https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader_s.h
I remade it using the C way of reading files to read the files and it works perfectly fine when reading the file into the pointer. However, once I try to create a fragment shader like this:
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
, it doesn’t allow me and says
Thread 1: EXC_BAD_ACCESS (code = 1, address = 0x1298)
I tried to use glGet Error to see if I could get the error code but the program crashes once it gets to the line with glCreateShader, so I can’t get the error code.
If I try to run the program, it results in a glitchy screen when you press q and then if the q button is pressed a second time, I get the screen filled with a green colour. I think this is happening because the shader isn’t working, although even when I did it without the shader class and just wrote out the shader as a pointer and compiled/linked it without wrapping it in a class*, it still gave me glitchy output.
*The shader did compile and link that time, so I don’t understand why it’s glitching.
#ifndef shader_h
#define shader_h
#include <iostream>
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#include <stdlib.h>
class Shader{
public:
Shader(const char * vshaderFile, const char * fshaderFile); // parameters are:
// path to vertex shader, path to fragment shader.
//geometry shader to be added later.
~Shader();
void Use() { glUseProgram (this->shaderProgram); }
private:
GLuint shaderProgram;
};
Shader::Shader(const char * vshaderFile, const char * fshaderFile){
//read vertex shader
long length;
char * vertexBuf;
FILE * vertexFile = fopen(vshaderFile, "r");
if(!vertexFile) { std::cout << "Could not open vertex shader" << std::endl; }
fseek(vertexFile, 0, SEEK_END);
length = ftell(vertexFile);
vertexBuf = new char [length + 1];
fseek(vertexFile, 0, SEEK_SET);
fread(vertexBuf, length, 1, vertexFile);
fclose(vertexFile);
vertexBuf[length] = 0; //makes the terminating character null
//read fragment shader
long length2;
char * fragmentBuf;
FILE * fragmentFile = fopen(fshaderFile, "r");
if(!fragmentFile){ std::cout << "Could not open fragment shader" << std::endl; }
fseek(fragmentFile, 0, SEEK_END);
length2 = ftell(fragmentFile);
fragmentBuf = new char [length2 + 1];
fseek(fragmentFile, 0, SEEK_SET);
fread(fragmentBuf, length2, 1, fragmentFile);
fclose(fragmentFile);
fragmentBuf[length2] = 0;
//makes the source pointers the buffers
GLchar * vShaderSource = vertexBuf;
GLchar * fShaderSource = fragmentBuf;
GLuint vertexShader, fragmentShader;
//compiles shaders
//fragment
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); //HERE is where it crashes. It reads the file just fine.
//std::cout << glGetError() << std::endl;
glShaderSource(fragmentShader, 1, &fShaderSource, NULL);
glCompileShader(fragmentShader);
//vertex
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vShaderSource, NULL);
glCompileShader(vertexShader);
//releases buffers
delete fragmentBuf;
delete vertexBuf;
//links program
this->shaderProgram = glCreateProgram();
glAttachShader(this->shaderProgram, vertexShader);
glAttachShader(this->shaderProgram, fragmentShader);
glLinkProgram(this->shaderProgram);
//deletes unneeded shaders
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
};
Shader::~Shader(){
glDeleteProgram(this->shaderProgram);
};
#endif /* shader_h */
and then
#include <iostream>
#include <SDL2/SDL.h>
#include "shader.hpp"
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
SDL_GLContext context;
SDL_Window * window;
bool initWindow(){
if (SDL_Init(SDL_INIT_VIDEO)<0){
std::cout << "Can't make SDL" << std::endl;
}
//what version we are using
SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
//SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
window = SDL_CreateWindow("Rectangle", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 512, 512, SDL_WINDOW_OPENGL);
if (!window){
std::cout << "No window created" << std::endl;
//window = NULL;
return false;
}
context = SDL_GL_CreateContext(window);
if (!context){
std::cout << "No context created" << std::endl;
return false;
}
//double buffering - 24bit z buffer (might need changing for different systems)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//Makes buffer swap sync with VBLANK
SDL_GL_SetSwapInterval(1);
glViewport(0, 0, 512, 512);
std:: cout << "Initialised" << std::endl;
return true;
};
int main(int argc, const char * argv[]) {
Shader shader ("fragment.txt", "vertex.txt");
//This is copypasted from the tutorial
//until the event loop
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
bool loop = true;
while (loop) {
SDL_Event e;
while(SDL_PollEvent(&e)){
if (e.type == SDL_QUIT) loop = false;
if (e.type == SDL_KEYDOWN){
switch(e.key.keysym.sym){
case SDLK_ESCAPE:
loop = false;
break;
case SDLK_q:
shader.Use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLfloat*)0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
//std::cout << glCheckError() << std::endl;
break;
case SDLK_y:
std::cout << glGetString(GL_VERSION) << std::endl;
break;
case SDLK_r:
glClearColor(0.3f, 0.5f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
break;
}
std::cout << "Error: " << SDL_GetError() << std::endl;
std::cout << glGetError() << std::endl;
}
}
}
}