How to load a GLSL shader in OpenGL using C++

Got asked how to load a GLSL shader today and as I had an OpenGL wrapper containing this code, I thought it would be nice to share it with you. It also includes loading the files as well as debugging info. Enjoy 😉

GLShader.hpp

#ifndef GLSHADER_H
#define GLSHADER_H

#include "GL/glew.h"

GLuint LoadShader(const char *vertex_path, const char *fragment_path);

#endif

GLShader.cpp:

#include "GLShader.hpp"

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>


std::string readFile(const char *filePath) {
    std::string content;
    std::ifstream fileStream(filePath, std::ios::in);

    if(!fileStream.is_open()) {
        std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
        return "";
    }

    std::string line = "";
    while(!fileStream.eof()) {
        std::getline(fileStream, line);
        content.append(line + "\n");
    }

    fileStream.close();
    return content;
}


GLuint LoadShader(const char *vertex_path, const char *fragment_path) {
    GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);

    // Read shaders
    std::string vertShaderStr = readFile(vertex_path);
    std::string fragShaderStr = readFile(fragment_path);
    const char *vertShaderSrc = vertShaderStr.c_str();
    const char *fragShaderSrc = fragShaderStr.c_str();

    GLint result = GL_FALSE;
    int logLength;

    // Compile vertex shader
    std::cout << "Compiling vertex shader." << std::endl;
    glShaderSource(vertShader, 1, &vertShaderSrc, NULL);
    glCompileShader(vertShader);

    // Check vertex shader
    glGetShaderiv(vertShader, GL_COMPILE_STATUS, &result);
    glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &logLength);
    std::vector vertShaderError((logLength > 1) ? logLength : 1);
    glGetShaderInfoLog(vertShader, logLength, NULL, &vertShaderError[0]);
    std::cout << &vertShaderError[0] << std::endl;

    // Compile fragment shader
    std::cout << "Compiling fragment shader." << std::endl;
    glShaderSource(fragShader, 1, &fragShaderSrc, NULL);
    glCompileShader(fragShader);

    // Check fragment shader
    glGetShaderiv(fragShader, GL_COMPILE_STATUS, &result);
    glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength);
    std::vector fragShaderError((logLength > 1) ? logLength : 1);
    glGetShaderInfoLog(fragShader, logLength, NULL, &fragShaderError[0]);
    std::cout << &fragShaderError[0] << std::endl;

    std::cout << "Linking program" << std::endl;
    GLuint program = glCreateProgram();
    glAttachShader(program, vertShader);
    glAttachShader(program, fragShader);
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &result);
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    std::vector<char> programError( (logLength > 1) ? logLength : 1 );
    glGetProgramInfoLog(program, logLength, NULL, &programError[0]);
    std::cout << &programError[0] << std::endl;

    glDeleteShader(vertShader);
    glDeleteShader(fragShader);

    return program;
}

This is loaded by calling the following code:

GLuint program = LoadShader("shader.vert", "shader.frag");
glUseProgram(program);

It can also be used to load multiple shaders by calling glUseProgram on different GLuints or 0 as the parameter to disable.

9 Comments

  • Stephan says:

    Thank you very much!

    There’s an error at the line:

    content.append(line + "n");

    in readFile.
    I suppose it should be

    content.append(line + "\n");

  • Joe says:

    Thanks!

    Just wanted to let you know that in using this today I was getting out of bounds errors. I found that when you check errors on the fragment and vertex shaders, it doesn’t check if logLength is less than one like you did after linking the program. I changed the lines to:

    std::vector vertShaderError((logLength > 1) ? logLength : 1);

    and

    std::vector fragShaderError((logLength > 1) ? logLength : 1);

    Thanks again!

  • Kim Einar Larsen says:

    Takk!
    Jeg holder på å lærer meg OpenGL/GLSL så dette var lærerikt. Før jeg kom over dette eksempelet så hadde jeg problemer med å bruke std::string i glShaderSource da jeg ikke ønsket å bruke const char* så jeg googlet meg frem til dette.
    Note: vector —> vector

  • Joe Kerman says:

    just wanted to point out at this line:
    std::vector vertShaderError((logLength > 1) ? logLength : 1);
    You didn’t specify the type. Its should be:
    std::vector vertShaderError((logLength > 1) ? logLength : 1);
    Thanks

  • nadim farhat says:

    2 years laters. Thanks a lot

  • woop says:

    u missing the template argument where …
    std::vector vertShaderError((logLength > 1) ? logLength : 1); and std::vector fragShaderError((logLength > 1) ? logLength : 1);
    that should be (if i didn’t … …)
    change the std::vector to std::vector

  • some faster!!
    std::string readFile(const char* filepath)
    {
    std::ifstream myFile(filepath);
    std::string content((std::istreambuf_iterator(myFile)),
    std::istreambuf_iterator());
    return content;
    }

Leave a Reply

Your email address will not be published. Required fields are marked *