Skip to content

Instantly share code, notes, and snippets.

@Twinklebear
Last active August 29, 2015 14:00

Revisions

  1. Twinklebear revised this gist Apr 18, 2014. 2 changed files with 228 additions and 0 deletions.
    188 changes: 188 additions & 0 deletions util.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,188 @@
    #include <vector>
    #include <array>
    #include <map>
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <string>
    #include <tuple>
    #include <SDL.h>
    #include "gl_core_3_3.h"
    #include "util.h"

    std::string util::read_file(const std::string &fName){
    std::ifstream file(fName);
    if (!file.is_open()){
    std::cout << "Failed to open file: " << fName << std::endl;
    return "";
    }
    return std::string((std::istreambuf_iterator<char>(file)),
    std::istreambuf_iterator<char>());
    }
    GLint util::load_shader(GLenum type, const std::string &file){
    GLuint shader = glCreateShader(type);
    std::string src = read_file(file);
    const char *csrc = src.c_str();
    glShaderSource(shader, 1, &csrc, 0);
    glCompileShader(shader);

    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE){
    std::cerr << "loadShader: ";
    switch (type){
    case GL_VERTEX_SHADER:
    std::cerr << "Vertex shader: ";
    break;
    case GL_FRAGMENT_SHADER:
    std::cerr << "Fragment shader: ";
    break;
    case GL_GEOMETRY_SHADER:
    std::cerr << "Geometry shader: ";
    break;
    default:
    std::cerr << "Other shader type: ";
    }
    std::cerr << file << " failed to compile. Compilation log:\n";
    GLint len;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
    char *log = new char[len];
    glGetShaderInfoLog(shader, len, 0, log);
    std::cerr << log << "\n";
    delete[] log;
    glDeleteShader(shader);
    return -1;
    }
    return shader;
    }
    GLint util::load_program(const std::vector<std::tuple<GLenum, std::string>> &shaders){
    std::vector<GLuint> glshaders;
    for (const std::tuple<GLenum, std::string> &s : shaders){
    GLint h = load_shader(std::get<0>(s), std::get<1>(s));
    if (h == -1){
    std::cerr << "loadProgram: A required shader failed to compile, aborting\n";
    for (GLuint g : glshaders){
    glDeleteShader(g);
    }
    return -1;
    }
    glshaders.push_back(h);
    }
    GLuint program = glCreateProgram();
    for (GLuint s : glshaders){
    glAttachShader(program, s);
    }
    glLinkProgram(program);
    GLint status;
    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE){
    std::cerr << "loadProgram: Program failed to link, log:\n";
    GLint len;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
    char *log = new char[len];
    glGetProgramInfoLog(program, len, 0, log);
    std::cerr << log << "\n";
    delete[] log;
    }
    for (GLuint s : glshaders){
    glDetachShader(program, s);
    glDeleteShader(s);
    }
    if (status == GL_FALSE){
    glDeleteProgram(program);
    return -1;
    }
    return program;
    }
    bool util::log_glerror(const std::string &msg){
    GLenum err = glGetError();
    if (err != GL_NO_ERROR){
    std::cerr << "OpenGL Error: ";
    switch (err){
    case GL_INVALID_ENUM:
    std::cerr << "Invalid enum";
    break;
    case GL_INVALID_VALUE:
    std::cerr << "Invalid value";
    break;
    case GL_INVALID_OPERATION:
    std::cerr << "Invalid operation";
    break;
    case GL_OUT_OF_MEMORY:
    std::cerr << "Out of memory";
    break;
    case GL_INVALID_FRAMEBUFFER_OPERATION:
    std::cerr << "Invalid FrameBuffer operation";
    break;
    default:
    std::cerr << std::hex << err << std::dec;
    }
    std::cerr << " - " << msg << "\n";
    return true;
    }
    return false;
    }
    #if _MSC_VER
    void APIENTRY util::gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity,
    GLsizei len, const GLchar *msg, const GLvoid *user)
    #else
    void util::gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity,
    GLsizei len, const GLchar *msg, const GLvoid *user)
    #endif
    {
    //Print a time stamp for the message
    float sec = SDL_GetTicks() / 1000.f;
    int min = static_cast<int>(sec / 60.f);
    sec -= sec / 60.f;
    std::cout << "[" << min << ":"
    << std::setprecision(3) << sec << "] OpenGL Debug -";
    switch (severity){
    case GL_DEBUG_SEVERITY_HIGH_ARB:
    std::cout << " High severity";
    break;
    case GL_DEBUG_SEVERITY_MEDIUM_ARB:
    std::cout << " Medium severity";
    break;
    case GL_DEBUG_SEVERITY_LOW_ARB:
    std::cout << " Low severity";
    }
    switch (src){
    case GL_DEBUG_SOURCE_API_ARB:
    std::cout << " API";
    break;
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
    std::cout << " Window system";
    break;
    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
    std::cout << " Shader compiler";
    break;
    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
    std::cout << " Third party";
    break;
    case GL_DEBUG_SOURCE_APPLICATION_ARB:
    std::cout << " Application";
    break;
    default:
    std::cout << " Other";
    }
    switch (type){
    case GL_DEBUG_TYPE_ERROR_ARB:
    std::cout << " Error";
    break;
    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
    std::cout << " Deprecated behavior";
    break;
    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
    std::cout << " Undefined behavior";
    break;
    case GL_DEBUG_TYPE_PORTABILITY_ARB:
    std::cout << " Portability";
    break;
    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
    std::cout << " Performance";
    break;
    default:
    std::cout << " Other";
    }
    std::cout << ":\n\t" << msg << "\n";
    }
    40 changes: 40 additions & 0 deletions util.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,40 @@
    #ifndef UTIL_H
    #define UTIL_H

    #include <string>
    #include <vector>
    #include <tuple>
    #include "gl_core_3_3.h"

    namespace util {
    /*
    * Read the entire contents of a file into a string, if an error occurs
    * the string will be empty
    */
    std::string read_file(const std::string &fName);
    /*
    * Load a GLSL shader from some file, returns -1 if loading failed
    */
    GLint load_shader(GLenum type, const std::string &file);
    /*
    * Build a shader program from the list of shaders passed
    */
    GLint load_program(const std::vector<std::tuple<GLenum, std::string>> &shaders);
    /*
    * Check for an OpenGL error and log it along with the message passed
    * if an error occured. Will return true if an error occured & was logged
    */
    bool log_glerror(const std::string &msg);
    /*
    * A debug callback for the GL_ARB_debug_out extension
    */
    #ifdef _WIN32
    void APIENTRY gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity,
    GLsizei len, const GLchar *msg, const GLvoid *user);
    #else
    void gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity,
    GLsizei len, const GLchar *msg, const GLvoid *user);
    #endif
    }

    #endif
  2. Twinklebear revised this gist Apr 18, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions vertex.glsl
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ const vec2 uvs[16] = vec2[16](
    );

    //vectors for the horiziontal/vertical directions to expand the quad in
    const vec2 signs[4] = vec2[4](
    const vec2 dirs[4] = vec2[4](
    vec2(0, 0),
    vec2(0, -1),
    vec2(1, 0),
    @@ -31,5 +31,5 @@ void main(void){
    float x = pos.x * char_dim.x - 1;
    float y = -1 * (pos.y * char_dim.y - 1);
    vec4 p = vec4(x, y, 0, 1);
    gl_Position = p + char_dim.x * right * signs[gl_VertexID].x + char_dim.y * up * signs[gl_VertexID].y;
    gl_Position = p + char_dim.x * right * dirs[gl_VertexID].x + char_dim.y * up * dirs[gl_VertexID].y;
    }
  3. Twinklebear revised this gist Apr 18, 2014. 1 changed file with 5 additions and 28 deletions.
    33 changes: 5 additions & 28 deletions fragment.glsl
    Original file line number Diff line number Diff line change
    @@ -1,35 +1,12 @@
    #version 330 core

    const vec2 uvs[16] = vec2[16](
    vec2(0, 0), vec2(0.5, 0), vec2(0, 0.5), vec2(0.5, 0.5),
    vec2(0.5, 0), vec2(1, 0), vec2(0.5, 0.5), vec2(1, 0.5),
    vec2(0, 0.5), vec2(0, 1), vec2(0.5, 0.5), vec2(0.5, 1),
    vec2(0.5, 0.5), vec2(0.5, 1), vec2(1, 1), vec2(1, 0.5)
    );
    //Sampler defaults to unit 0 which is where our texture is bound
    uniform sampler2D tex;

    //vectors for the horiziontal/vertical directions to expand the quad in
    const vec2 signs[4] = vec2[4](
    vec2(0, 0),
    vec2(0, -1),
    vec2(1, 0),
    vec2(1, -1)
    );
    in vec2 fuv;

    const vec4 up = vec4(0, 1, 0, 0);
    const vec4 right = vec4(1, 0, 0, 0);
    const ivec2 dim = ivec2(64, 16);
    const vec2 char_dim = vec2(2.f / dim.x, 2.f / dim.y);

    layout(location = 0) in ivec2 pos;
    layout(location = 1) in int tex_idx;

    out vec2 fuv;
    out vec4 color;

    void main(void){
    fuv = uvs[4 * tex_idx + gl_VertexID];
    //Scale positions into NDC and flip y to put 0,0 at top-left
    float x = pos.x * char_dim.x - 1;
    float y = -1 * (pos.y * char_dim.y - 1);
    vec4 p = vec4(x, y, 0, 1);
    gl_Position = p + char_dim.x * right * signs[gl_VertexID].x + char_dim.y * up * signs[gl_VertexID].y;
    color = texture(tex, fuv);
    }
  4. Twinklebear created this gist Apr 18, 2014.
    35 changes: 35 additions & 0 deletions fragment.glsl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    #version 330 core

    const vec2 uvs[16] = vec2[16](
    vec2(0, 0), vec2(0.5, 0), vec2(0, 0.5), vec2(0.5, 0.5),
    vec2(0.5, 0), vec2(1, 0), vec2(0.5, 0.5), vec2(1, 0.5),
    vec2(0, 0.5), vec2(0, 1), vec2(0.5, 0.5), vec2(0.5, 1),
    vec2(0.5, 0.5), vec2(0.5, 1), vec2(1, 1), vec2(1, 0.5)
    );

    //vectors for the horiziontal/vertical directions to expand the quad in
    const vec2 signs[4] = vec2[4](
    vec2(0, 0),
    vec2(0, -1),
    vec2(1, 0),
    vec2(1, -1)
    );

    const vec4 up = vec4(0, 1, 0, 0);
    const vec4 right = vec4(1, 0, 0, 0);
    const ivec2 dim = ivec2(64, 16);
    const vec2 char_dim = vec2(2.f / dim.x, 2.f / dim.y);

    layout(location = 0) in ivec2 pos;
    layout(location = 1) in int tex_idx;

    out vec2 fuv;

    void main(void){
    fuv = uvs[4 * tex_idx + gl_VertexID];
    //Scale positions into NDC and flip y to put 0,0 at top-left
    float x = pos.x * char_dim.x - 1;
    float y = -1 * (pos.y * char_dim.y - 1);
    vec4 p = vec4(x, y, 0, 1);
    gl_Position = p + char_dim.x * right * signs[gl_VertexID].x + char_dim.y * up * signs[gl_VertexID].y;
    }
    112 changes: 112 additions & 0 deletions test.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,112 @@
    #include <iostream>
    #include <iomanip>
    #include <SDL.h>
    #include "gl_core_3_3.h"
    #include "util.h"

    int main(int argc, char **argv){
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
    std::cout << "SDL_Init error: " << SDL_GetError() << "\n";
    return 1;
    }
    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_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);

    SDL_Window *win = SDL_CreateWindow("Text Test", SDL_WINDOWPOS_CENTERED,
    SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
    SDL_GLContext context = SDL_GL_CreateContext(win);

    if (ogl_LoadFunctions() == ogl_LOAD_FAILED){
    std::cout << "ogl load failed\n";
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 1;
    }

    std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << "\n"
    << "OpenGL Vendor: " << glGetString(GL_VENDOR) << "\n"
    << "OpenGL Renderer: " << glGetString(GL_RENDERER) << "\n"
    << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n";

    glClearColor(0, 0, 0, 1);
    glClearDepth(1.f);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
    glDebugMessageCallbackARB(util::gldebug_callback, NULL);
    glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);

    GLint program = util::load_program({std::make_tuple(GL_VERTEX_SHADER, "../vertex.glsl"),
    std::make_tuple(GL_FRAGMENT_SHADER, "../fragment.glsl")});
    if (program == -1){
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 1;
    }
    glUseProgram(program);

    const GLubyte img[] = {
    255, 0, 0, 255, 0, 255, 0, 255,
    0, 0, 255, 255, 255, 255, 0, 255
    };
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
    //No mip-maps & use nearest-neighbor filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    GLuint vao, vbo;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    const int instances = 10;
    const int vars_per_instance = 3;
    //Instance data is: { x, y, uv_idx }
    GLint pos[instances * vars_per_instance] = {
    0, 0, 0,
    1, 0, 1,
    2, 0, 2,
    3, 0, 3,
    0, 1, 1,
    1, 1, 2,
    2, 1, 3,
    0, 2, 2,
    63, 15, 0,
    62, 15, 2
    };
    glBufferData(GL_ARRAY_BUFFER, vars_per_instance * instances * sizeof(GLint), pos, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    //Note: must use IPointer for integer types if you don't want them to be converted
    glVertexAttribIPointer(0, 2, GL_INT, vars_per_instance * sizeof(GLint), 0);
    glVertexAttribDivisor(0, 1);
    glEnableVertexAttribArray(1);
    glVertexAttribIPointer(1, 1, GL_INT, vars_per_instance * sizeof(GLint), (void*)(2 * sizeof(GLint)));
    glVertexAttribDivisor(1, 1);

    bool quit = false;
    while (!quit){
    SDL_Event e;
    while (SDL_PollEvent(&e)){
    if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)){
    quit = true;
    break;
    }
    }
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, instances);
    SDL_GL_SwapWindow(win);
    }
    glDeleteProgram(program);
    glDeleteVertexArrays(1, &vao);
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 0;
    }
    35 changes: 35 additions & 0 deletions vertex.glsl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    #version 330 core

    const vec2 uvs[16] = vec2[16](
    vec2(0, 0), vec2(0.5, 0), vec2(0, 0.5), vec2(0.5, 0.5),
    vec2(0.5, 0), vec2(1, 0), vec2(0.5, 0.5), vec2(1, 0.5),
    vec2(0, 0.5), vec2(0, 1), vec2(0.5, 0.5), vec2(0.5, 1),
    vec2(0.5, 0.5), vec2(0.5, 1), vec2(1, 1), vec2(1, 0.5)
    );

    //vectors for the horiziontal/vertical directions to expand the quad in
    const vec2 signs[4] = vec2[4](
    vec2(0, 0),
    vec2(0, -1),
    vec2(1, 0),
    vec2(1, -1)
    );

    const vec4 up = vec4(0, 1, 0, 0);
    const vec4 right = vec4(1, 0, 0, 0);
    const ivec2 dim = ivec2(64, 16);
    const vec2 char_dim = vec2(2.f / dim.x, 2.f / dim.y);

    layout(location = 0) in ivec2 pos;
    layout(location = 1) in int tex_idx;

    out vec2 fuv;

    void main(void){
    fuv = uvs[4 * tex_idx + gl_VertexID];
    //Scale positions into NDC and flip y to put 0,0 at top-left
    float x = pos.x * char_dim.x - 1;
    float y = -1 * (pos.y * char_dim.y - 1);
    vec4 p = vec4(x, y, 0, 1);
    gl_Position = p + char_dim.x * right * signs[gl_VertexID].x + char_dim.y * up * signs[gl_VertexID].y;
    }