GLProgramming.com

home :: about :: development guides :: irc :: forums :: search :: paste :: links :: contribute :: code dump

-> Click here to learn how to get live help <-


New Paste :: Recent Pastes:: No Line Numbers


A Paste by godecho
1
 
/*
this is pretty rough, and far from finished. if you have any questions, catch me on irc to ask.  i'll end up working this into a development guide or something.
*/

// glslang.h
#ifndef _GLSLANG_H
#define _GLSLANG_H

#ifdef _WIN32
    #include <windows.h>        // If you dont have this, gl.h will not compile
    #define _snscanf snscanf
#endif

#include <GL/gl.h>

#include <map>
#include <string>
#include <vector>

#include "glextensions.h"

using namespace std;

struct ShaderObj
{
    ShaderObj()    :    handle(0)    {}
    ~ShaderObj();
        
    inline bool operator < (const ShaderObj &right) const    {    return ((filename < right.filename) ? true : false);    }
    inline bool operator > (const ShaderObj &right) const    {    return ((filename > right.filename) ? true : false);    }    

    string        filename;
    GLenum        type;
    GLhandleARB    handle;
};

struct ProgObj
{
    ProgObj()    :    handle(0)    {}
    ~ProgObj();

    bool AttachAndLink();

    vector<ShaderObj *>    shaders;
    string                filename;
    GLhandleARB            handle;    
};

namespace GLslangMgr
{
    static const GLhandleARB DISABLESHADERS = 0;
    
    typedef map<string, ShaderObj *>::iterator            ShdrItr;
    typedef map<string, ShaderObj *>::const_iterator    ShdrCItr;
    
    class GLslangHandler
    {
        public:
    
            GLslangHandler();
            ~GLslangHandler();

            GLhandleARB    LoadProgram(const char *filename);
            ShaderObj    *LoadShader(const char *filename, const GLenum &type);
            
            void Reload();
            void UseProgram(const GLhandleARB &prog)    const;
            
            inline void DisableShaders()    const    {    glUseProgramObjectARB(0);    }

        private:

            map        <string, ShaderObj *>    shaders;
            vector    <ProgObj *>                programs;

            mutable GLhandleARB currProg;

            void Flush();
    };

    inline GLslangHandler *Inst()
    {
        static GLslangHandler GLslangHandler;
        return &GLslangHandler;
    }

    void PrintInfoLog(const GLhandleARB &handle);
}

#endif

// glslang.cpp
#include "glslang.h"

#include <cstdio>
#include <cstring>
#include <iostream>

#include "console.h"
#include "screen.h"    // included temporarily for getting opengl errors

ShaderObj::~ShaderObj()
{
    if(handle)
    {
        glDeleteObjectARB(handle);
    }    
}

ProgObj::~ProgObj()
{
    if(handle)
    {
        glDeleteObjectARB(handle);
    }
}

bool ProgObj::AttachAndLink()
{
    if(shaders.size() > 0)
    {
        handle = glCreateProgramObjectARB();

        for(unsigned int x = 0; x < shaders.size(); ++x)
        {
            glAttachObjectARB(handle, shaders[x]->handle);
        }

        glLinkProgramARB(handle);
        GLint goodLink;
                
        glGetObjectParameterivARB(handle, GL_OBJECT_LINK_STATUS_ARB, &goodLink);

        if(goodLink == GL_TRUE)
        {
            return true;
        }
        else
        {
            GLslangMgr::PrintInfoLog(handle);
            ConsoleMgr::Inst()->AddText("* Error linking program object %s", filename.c_str());
            return false;
        }
    }
    else
    {
        ConsoleMgr::Inst()->AddText("* Error, attempting to link program object %s, with no attached shaders.", filename.c_str());
        return false;
    }
}

GLslangMgr::GLslangHandler::GLslangHandler()
    :    currProg(0)
{

}

GLslangMgr::GLslangHandler::~GLslangHandler()
{
    for(unsigned int x = 0; x < programs.size(); ++x)
    {
        delete programs[x];
    }

    for(ShdrItr itr = shaders.begin(); itr != shaders.end(); itr++)
    {
        delete itr->second;
    }

    //Flush();    // These will be lost when the context is destroyed, flushing them explicitly is unnecessary.
}

GLhandleARB GLslangMgr::GLslangHandler::LoadProgram(const char *filename)
{
    FILE *file = fopen(filename, "rt");

    if(file)
    {
        GLenum type;
        char buffer[128];
        vector<ShaderObj *> shaders;
        
        ProgObj *prog = new ProgObj;
        if(!prog)    {    cerr << "Error allocating new ProgObj in GLslangHandler::LoadShader.  This is Bad." << endl;    exit(EXIT_FAILURE);    }
        
        prog->filename = filename;

        cerr << "this fscanf is dangerous, possible overruns." << endl;
        while(fscanf(file, "%s\n", buffer) == 1)
        {
            char ftype = buffer[strlen(buffer)-3];

            switch(ftype)
            {
                case 'v':    type = GL_VERTEX_SHADER_ARB;    break;
                case 'f':    type = GL_FRAGMENT_SHADER_ARB;    break;

                default:    ConsoleMgr::Inst()->AddText("* Unknown shader type %s", buffer);    
                            return 0;
            }
            
            ShaderObj *shader = LoadShader(buffer, type);
            
            if(shader)
            {
                shaders.push_back(shader);
            }
            else
            {
                return 0;
            }
        }
        
        // If all goes well...
        prog->shaders = shaders;
        
        if(prog->AttachAndLink())
        {
            programs.push_back(prog);
            return prog->handle;
        }
        else
        {
            delete prog;
        }
    }
    else
    {
        ConsoleMgr::Inst()->AddText("* Can't open shader propram object file %s.", filename);
    }
    
    return 0;
}

ShaderObj *GLslangMgr::GLslangHandler::LoadShader(const char *filename, const GLenum &type)
{
    ShaderObj *shader = new ShaderObj;    if(!shader)    {    cerr << "Error allocating new shader in GLslangHandler::LoadShader.  This is Bad." << endl;    exit(EXIT_FAILURE);    }
    shader->handle = glCreateShaderObjectARB(type);

    FILE *stream;
    const GLcharARB *strings[1];

    stream = fopen(filename, "rb");

    if(stream)
    {
        fseek(stream, 0, SEEK_END);
        const GLint size = ftell(stream);
        fseek(stream, 0, SEEK_SET);

        if(size > 0)
        {
            GLcharARB *buffer = new GLcharARB[size];    if(!buffer)    {    cerr << "Error allocating new GLcharARB[] in GLslangHandler::LoadShader.  This is Bad." << endl;    exit(EXIT_FAILURE);    }
            fread(buffer, sizeof(char), size, stream);
            fclose(stream);

            strings[0] = buffer;
            
            glShaderSourceARB(shader->handle, 1, strings, &size);
            delete [] buffer;
            
            glCompileShaderARB(shader->handle);

            GLint goodCompile;
            
            glGetObjectParameterivARB(shader->handle, GL_OBJECT_COMPILE_STATUS_ARB, &goodCompile);
            
            if(goodCompile == GL_TRUE)
            {
                shaders[filename] = shader;
                return shader;
            }
            else
            {
                GLslangMgr::PrintInfoLog(shader->handle);
                delete shader;
                ConsoleMgr::Inst()->AddText("* Error compiling shader %s", filename);
            }
        }
        else
        {
            ConsoleMgr::Inst()->AddText("* Error, attempting compiling an empty shader file %s.", filename);
        }
    }
    else
    {
        ConsoleMgr::Inst()->AddText("* Can't open shader file %s.", filename);
    }
    
    return 0;
}

void GLslangMgr::GLslangHandler::Reload()
{

}

void GLslangMgr::GLslangHandler::UseProgram(const GLhandleARB &prog) const
{
    if(prog != currProg)
    {
        glUseProgramObjectARB(prog);    // If called with 0, the programmable processors will be disabled and fixed functionality will be used for both vertex and fragment processing.
        currProg = prog;
    }
}

void GLslangMgr::GLslangHandler::Flush()
{

}

void GLslangMgr::PrintInfoLog(const GLhandleARB &handle)
{
    GLint infoLength    = 0;
    GLint charsWritten    = 0;
    glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLength);

    GLcharARB *info = new GLcharARB[infoLength];    if(!info)    {    cerr << "Error allocating new GLcharARB[] in GLslangMgr::PrintInfoLog.  This is Bad." << endl;    exit(EXIT_FAILURE);    }

    glGetInfoLogARB(handle, infoLength, &charsWritten, info);

    ConsoleMgr::Inst()->AddText("%s", info);

    delete [] info;
}