DI-Guy Graphics API, diguyOglGraphicsShaderProgram

diguyOglGraphicsShaderProgram.cpp

DI-Guy API Version 12.5.1

This file was automatically generated from diguyOglGraphicsShaderProgram.cpp. Do not edit this file directly; the changes will be lost.
Introduction
Most rendering environments use some type of shader system that offloads rendering operations from the CPU to a GPU. Terminology varies, but DI-Guy uses the term "shader" to refer to a pair of sub-programs: a vertex shader and a pixel shader (AKA fragment shader in OpenGL).

Shader programs are shared among characters; if two characters use the same shader, the same shader object is used for both. If character-specific data is needed it can be stored in a diguyGraphicsShaderInstance object.

The class diguyOglGraphicsShaderProgram is an example of a diguyGraphicsShaderProgram subclass for an immediate mode renderer using the DI-Guy Loader. The example subclass shows how to use the accessors of the diguyGraphicsShaderProgram class and which virtual functions should be overridden for an immediate mode renderer such as OpenGL.

Header files and forward declarations
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <cstring>
#include <math.h>
#include <libbdilog.h>

// needed for diguyTextureMapType enum
#include <diguyGraphicsTexture.h>
#include <diguyApp.h>
#include <diguyScenario.h>

#include "diguyOglGraphicsShaderProgram.h"
/*
 *  Static variable showing whether an OpenGL shader extension is available.
 */
extern GLboolean s_shader_extension_available;
Constructor
Description:

Initialize data members of the class to a known state.

Base class data will not be fully initialized until during the Build Stage, so base class accessors should not be called here.

diguyOglGraphicsShaderProgram::diguyOglGraphicsShaderProgram(void* internal_data)
    :
    diguyGraphicsShaderProgram(internal_data),
    m_gl_program_object(0),

    m_bind_location_attr_weight_array(-1),
    m_bind_location_attr_index_array(-1),
    m_bind_location_attr_tangent(-1),
    m_bind_location_ufrm_apply_matrices_flag(-1),
    m_bind_location_ufrm_link_matrix(-1),
    m_bind_location_ufrm_link_matrices(-1),
    m_bind_location_ufrm_inverse_transform_matrix(-1),
    m_bind_location_ufrm_link_colors(-1),
    m_bind_location_ufrm_light_dir_os(-1),
    m_bind_location_ufrm_eye_point_os(-1),
    m_bind_location_ufrm_textures_enabled(-1),
    m_bind_location_ufrm_bump_map_enabled(-1),
    m_bind_location_ufrm_specular_map_enabled(-1),
    m_bind_location_ufrm_component_map_enabled(-1),
    m_bind_location_ufrm_misc_1_map_enabled(-1),
    m_bind_location_ufrm_misc_2_map_enabled(-1),
    m_bind_location_ufrm_light_array(-1),

    m_vertex_shader_loaded(false),
    m_gl_vertex_shader_object(-1),

    m_pixel_shader_loaded(false),
    m_gl_pixel_shader_object(-1),

    m_linked(false),
    m_include_point_lights(0)
{
    m_vertex_shader_filename[0] = '\0';
    m_pixel_shader_filename[0]  = '\0';

    /*
     *  Create an OpenGL program object.  Note that we don't access any data
     *   from the base class here.
     */
    m_gl_program_object = glCreateProgramObjectARB();

    /*
     *  Create OpenGL shader objects, one for the vertex shader, one for the
     *   pixel (AKA fragment) shader.  Delay loading and linking source
     *   code until the appropriate virtual functions are called.
     */
    m_gl_vertex_shader_object = glCreateShaderObjectARB(GL_VERTEX_SHADER);
    m_gl_pixel_shader_object = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);

    /*
     *  Test code for diguyGraphicsShaderInstance variable functions.
     *
    int num_variables = get_num_variables();
    int i;
    for (i=0; i<num_variables; i++)
    {
        const char* variable_name = get_variable_name_at_index(i);
        const char* variable_type = get_variable_type(variable_name);

        bdi_log_printf(BDI_LOG_WARN,
            "Variable %d of shader instance is '%s', with type '%s'.\n",
            i,
            variable_name,
            variable_type);
    }
    */
}
Destructor
Description:

Free OpenGL objects allocated in the constructor.

diguyOglGraphicsShaderProgram::~diguyOglGraphicsShaderProgram()
{
    glDeleteObjectARB(m_gl_program_object);

    glDeleteObjectARB(m_gl_vertex_shader_object);
    glDeleteObjectARB(m_gl_pixel_shader_object);
}
load_vertex_shader_source
Build Stage

Description:

Override of diguyGraphicsShaderProgram::load_vertex_shader_source().

The load_vertex_shader_source() function should load the source code of the shader's vertex shader part. The source code should be linked in the link() function instead of here, as usually the pixel shader source needs to be loaded too before the link() call.

This implementation calls the helper function load_and_compile_shader().

int
diguyOglGraphicsShaderProgram::load_vertex_shader_source(const char* filename_base)
{
    /*
     *  Use the function
     *   diguyGraphicsShaderProgram::derive_diguy_shader_source_filename()
     *   to derive default DI-Guy shader filenames.
     */
    derive_diguy_shader_source_filename(m_vertex_shader_filename,
        511,
        filename_base,
        "glsl",
        "vert",
        1);

    int retval = load_and_compile_shader(m_gl_vertex_shader_object,
        m_vertex_shader_filename,
        m_vertex_shader_loaded);

    return retval;
}
load_pixel_shader_source
Build Stage

Description:

Override of diguyGraphicsShaderProgram::load_pixel_shader_source().

The load_pixel_shader_source() function should load the source code of the shader's pixel shader part. The source code should be linked in the link() function instead of here, as usually the vertex shader source needs to be loaded too before the link() call.

This implementation calls the helper function load_and_compile_shader().

int
diguyOglGraphicsShaderProgram::load_pixel_shader_source(const char* filename_base)
{
    derive_diguy_shader_source_filename(m_pixel_shader_filename,
        511,
        filename_base,
        "glsl",
        "frag",
        1);

    int retval = load_and_compile_shader(m_gl_pixel_shader_object,
        m_pixel_shader_filename,
        m_pixel_shader_loaded);

    return retval;
}
link
Build Stage

Description:

Override of diguyGraphicsShaderProgram::link().

The link() function should take the necessary actions to link the shader sub-programs loaded in the load_vertex_shader_source() and load_pixel_shader_source() functions.

This implementation links the shaders objects. The status of the link is then checked; errors are reported to the DI-Guy log.

int
diguyOglGraphicsShaderProgram::link()
{
    int retval = 0;
    m_linked = true;

    /*
     *  If shader objects aren't loaded, can't link.
     */
    if (!m_vertex_shader_loaded &&
        !m_pixel_shader_loaded)
    {
        bdi_log_printf(BDI_LOG_WARN,
            "WARNING: Failed to link shader '%s' because neither a vertex "
            "nor pixel shader source file was loaded.\n",
            get_name());
        return -1;
    }

    /*
     *  Attach shader objects to program object.
     */
    if (m_vertex_shader_loaded)
        glAttachObjectARB(m_gl_program_object, m_gl_vertex_shader_object);
    if (m_pixel_shader_loaded)
        glAttachObjectARB(m_gl_program_object, m_gl_pixel_shader_object);

    /*
     *  Link the program object.
     */
    glLinkProgram(m_gl_program_object);

    /*
     *  Check the info log to see if there were any problems.
     */
    GLint   info_log_length = 0;
    GLint   link_status = 0;

    glGetObjectParameterivARB(m_gl_program_object, GL_OBJECT_LINK_STATUS_ARB, &link_status);
    glGetObjectParameterivARB(m_gl_program_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);

    bdi_log_printf(BDI_LOG_INFO,
        "INFO: Shader program '%s' link status: %d\n",
        get_name(),
        link_status);

    if (info_log_length > 1)
    {
        if (info_log_length > 1000)
            info_log_length = 1000;

        char* info_log = new char[info_log_length];

        glGetInfoLogARB(m_gl_program_object, info_log_length, NULL, info_log);
        info_log[info_log_length-1] = '\0';
        info_log_length--;

        /*
         *  Radeon adds some extra newlines.
         */
        while ((info_log[info_log_length-1] == '\n') &&
            (info_log_length > 0))
        {
            info_log[info_log_length-1] = '\0';
            info_log_length--;
        }

        if (strstr(info_log, "error"))
        {
            bdi_log_printf(BDI_LOG_WARN,
                "WARNING: Shader program '%s' link info log: %s\n",
                get_name(),
                info_log);
        }
        else
        {
            bdi_log_printf(BDI_LOG_DEBUG,
                "DEBUG: Shader program '%s' link info log: %s\n",
                get_name(),
                info_log);
        }

        delete[] info_log;
    }

    glValidateProgramARB(m_gl_program_object);

    GLint validated = 0;
    glGetObjectParameterivARB(m_gl_program_object, GL_OBJECT_VALIDATE_STATUS_ARB, &validated);
    if (!validated)
    {
        glGetObjectParameterivARB(m_gl_program_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);

        char* info_log = new char[info_log_length+1];
        glGetInfoLogARB(m_gl_program_object, info_log_length, &info_log_length, info_log);
        info_log[info_log_length] = '\0';

        bdi_log_printf(BDI_LOG_WARN,
            "WARNING: Shader program '%s' validate info log: %s\n",
            get_name(),
            info_log);

        delete[] info_log;

        m_linked = false;
        retval = -1;
    }
    else
    {
        m_linked = true;
        retval = 0;
    }

    if (m_linked)
    {
        /*
         *  Use the program so the defaults set below take effect
         */
        glUseProgramObjectARB(m_gl_program_object);

        /*
         *  Look up bind locations for diguy_object shader attribute and
         *   uniform variables.
         */
        m_bind_location_attr_weight_array  = glGetAttribLocation(m_gl_program_object,  "attr_weight_array");
        m_bind_location_attr_index_array   = glGetAttribLocation(m_gl_program_object,  "attr_index_array");
        m_bind_location_attr_tangent       = glGetAttribLocation(m_gl_program_object,  "attr_tangent");
        m_bind_location_ufrm_link_matrix   = glGetUniformLocation(m_gl_program_object, "ufrm_link_matrix");

        m_bind_location_ufrm_link_matrices = glGetUniformLocation(m_gl_program_object, "ufrm_link_matrices[0]");
        if (m_bind_location_ufrm_link_matrices == -1)
        {
            // some drivers aren't happy with [0] above
            m_bind_location_ufrm_link_matrices = glGetUniformLocation(m_gl_program_object, "ufrm_link_matrices");
        }
        m_bind_location_ufrm_inverse_transform_matrix  = glGetUniformLocation(m_gl_program_object, "ufrm_inverse_transform_matrix");

        m_bind_location_ufrm_link_colors = glGetUniformLocation(m_gl_program_object, "ufrm_link_colors[0]");
        if (m_bind_location_ufrm_link_colors == -1)
        {
            m_bind_location_ufrm_link_colors = glGetUniformLocation(m_gl_program_object, "ufrm_link_colors");
        }

        m_bind_location_ufrm_light_dir_os = glGetUniformLocation(m_gl_program_object, "ufrm_light_dir_os");
        m_bind_location_ufrm_eye_point_os = glGetUniformLocation(m_gl_program_object, "ufrm_eye_point_os");

        /*
         *  In order to use the same shader program for both skinned and
         *   segmented meshes, we need a way to tell the shader whether or not
         *   to apply the ufrm_link_matrices values.
         */
        m_bind_location_ufrm_apply_matrices_flag = glGetUniformLocation(m_gl_program_object, "ufrm_apply_matrices_flag");

        /*
         *  m_bind_location_ufrm_textures_enabled is not directly set by
         *   DI-Guy.  It can be used to manually turn textures on and off in
         *   most DI-Guy stock shaders.  Its value should be set in bind().
         */
        m_bind_location_ufrm_textures_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_textures_enabled");

        /*
         *  needed by advanced lighting examples
         */
        m_bind_location_ufrm_light_array  = glGetUniformLocation(m_gl_program_object, "ufrm_light_array");
        if (m_bind_location_ufrm_light_array == -1)
        {
            m_bind_location_ufrm_light_array = glGetUniformLocation(m_gl_program_object, "ufrm_light_array[0]");
        }

        /*
         *  Various secondary textures.
         */
        m_bind_location_ufrm_bump_map_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_bump_map_enabled");
        m_bind_location_ufrm_specular_map_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_specular_map_enabled");

        m_bind_location_ufrm_component_map_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_component_map_enabled");
        m_bind_location_ufrm_misc_1_map_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_misc_1_map_enabled");
        m_bind_location_ufrm_misc_2_map_enabled = glGetUniformLocation(m_gl_program_object, "ufrm_misc_2_map_enabled");

        /*
         *  Hook up the uniform with the desired texture unit.  Update a bit
         *   field that diguy needs to keep track of which textures to bind
         *   for a shader.
         */
        int textures_used_mask = 0;
        int val = glGetUniformLocation(m_gl_program_object,   "ufrm_diffuse_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_DIFFUSE);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_DIFFUSE;
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_specular_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_SPECULAR);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_SPECULAR;
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_bump_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_BUMP);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_BUMP;
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_bump_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_BUMP);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_BUMP;
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_component_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_COMPONENTS);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_COMPONENTS;
        }
        
        val = glGetUniformLocation(m_gl_program_object,   "ufrm_component_ramp");
        if (val != -1)
        {
            glUniform1i(val, DIGUY_TEXTURE_MAP_TYPE_COMPONENT_RAMP);
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_misc_1_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_MISC_1);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_MISC_1;
        }

        val = glGetUniformLocation(m_gl_program_object,   "ufrm_misc_2_map");
        if (val != -1)
        {
            glUniform1i(val, (int) DIGUY_TEXTURE_MAP_TYPE_MISC_2);
            textures_used_mask |= DIGUY_TEXTURE_MAP_MASK_MISC_2;
        }
        /*
         *  let diguyGraphicsShaderProgram know what textures are available
         */
        set_textures_used_bitmask(textures_used_mask);
    }

    glUseProgramObjectARB(0);

    return retval;
}
get_attrib_bind_location
Build Stage

Description:

Override of diguyGraphicsShaderProgram::get_attrib_bind_location(). Lets DI-Guy core engine know more about this shader's capabilities.

int
diguyOglGraphicsShaderProgram::get_attrib_bind_location(const char* name)
{
    return glGetAttribLocation(m_gl_program_object, name);
}
get_uniform_bind_location
Build Stage

Description:

Override of diguyGraphicsShaderProgram::get_uniform_bind_location(). Lets diguy core engine store uniform locations internally to allow setting material and shape uniforms in the future via bind_uniform_with_location().

int
diguyOglGraphicsShaderProgram::get_uniform_bind_location(const char* name)
{
    return glGetUniformLocation(m_gl_program_object, name);
}
bind
Draw Stage

Description:

Override of diguyGraphicsShaderProgram::bind().

The bind() function should perform the necessary steps to load this shader program into the GPU. It can also set other shader state such as program level uniform values, etc., that will be used in the shader.

Description:

Demonstrates using weapon fire flashes to create dynamic point lights

int
diguyOglGraphicsShaderProgram::bind()
{
    if (m_gl_program_object == 0)
        return -1;

    /*
     *  Bind the shader program object so that subsequent shader calls such
     *   as bind_link_matrices() use this program.
     */
    glUseProgramObjectARB(m_gl_program_object);

    if (m_bind_location_ufrm_textures_enabled != -1)
    {
        glUniform1i(m_bind_location_ufrm_textures_enabled, 1);
    }

    update_light_uniforms();

    return 0;
}

void
diguyOglGraphicsShaderProgram::update_light_uniforms()
{

    diguyScenario * scenario = diguyApp::get_app()->get_scenario_at_index(0);

    // don't send multiple times a frame
    if(fabs(m_last_light_update_time - scenario->get_t()) < .001){
        return;
    }
    m_last_light_update_time = scenario->get_t();

    int num_effects = scenario->get_num_active_fire_effects();
    
    // Note: light index 0 is reserved for the global directional light.
    // This makes all the logic and indexing slightly wonky.
    float light_positions[8][4];
    light_positions[0][0] = 0.0f; light_positions[0][1] = 0.0f; light_positions[0][2] = 0.0f;
    light_positions[0][3] = 1.0f; 

    int i;
    for(i = 1; i < (num_effects+1) && i < 8; i++)
    {
        float radius = 0;
        float color[4];
        float falloff_r = 1;
        float falloff_rsq = 1;
        scenario->get_weapon_fire_effect_data(i-1, &radius, 
            &light_positions[i][0], &light_positions[i][1], &light_positions[i][2], 
            &color[0], &color[1], &color[2], &falloff_r, &falloff_rsq);
        color[3] = 0;
        light_positions[i][3] = 1;
        glLightfv(GL_LIGHT0+i, GL_DIFFUSE, &color[0]);
        glLightfv(GL_LIGHT0+i, GL_POSITION, &light_positions[i][0]);
        glLightf (GL_LIGHT0+i, GL_CONSTANT_ATTENUATION, falloff_r);
        glLightf (GL_LIGHT0+i, GL_QUADRATIC_ATTENUATION, falloff_rsq);
        glLightf (GL_LIGHT0+i, GL_SPOT_EXPONENT, 0);
    }
    // zero out any additional lights
    for(; i < 8; i++)
    {
        float color[4]={0,0,0,0};
        glLightfv(GL_LIGHT0+i, GL_DIFFUSE, &color[0]);
        glLightf (GL_LIGHT0+i, GL_CONSTANT_ATTENUATION, 1);
        glLightf (GL_LIGHT0+i, GL_QUADRATIC_ATTENUATION, 1);
        glLightf (GL_LIGHT0+i, GL_SPOT_EXPONENT, 0);
    }
    // this uniform is required for bump mapped characters
    if (m_bind_location_ufrm_light_array != -1)
    {
        glUniform4fv(m_bind_location_ufrm_light_array, 8, &light_positions[0][0]);
    }
}
unbind
Draw Stage

Description:

Override of diguyGraphicsShaderProgram::unbind().

The unbind() function should perform the necessary steps to unload this shader program from the GPU.

int
diguyOglGraphicsShaderProgram::unbind()
{
    if (m_gl_program_object == 0)
        return -1;

    m_last_matrix_data = NULL;

    /*
     *  Unbind the shader program object so that subsequent shader calls
     *   don't use this program.
     */
    glUseProgramObjectARB(0);

    return 0;
}
reload
Description:

Override of diguyGraphicsShaderProgram::reload().

The reload() function should reload previously loaded shader source code, and relink the program. It can be called during any stage, but is usually called during the Update Stage.

int
diguyOglGraphicsShaderProgram::reload()
{
    if (m_linked)
    {
        m_linked = false;
    }

    /*
     *  Reload the vertex shader using the previously derived filenames.
     */
    int retval = load_and_compile_shader(m_gl_vertex_shader_object,
        m_vertex_shader_filename,
        m_vertex_shader_loaded);

    if (retval != 0)
    {
        bdi_log_printf(BDI_LOG_WARN,
            "WARNING: Failed to reload vertex shader source file '%s' for "
            "shader program '%s'.\n",
            m_vertex_shader_filename,
            get_name());
        return -1;
    }

    /*
     *  Reload the pixel shader using the previously derived filenames.
     */
    retval = load_and_compile_shader(m_gl_pixel_shader_object,
        m_pixel_shader_filename,
        m_pixel_shader_loaded);

    if (retval != 0)
    {
        bdi_log_printf(BDI_LOG_WARN,
            "WARNING: Failed to reload pixel shader source file '%s' for "
            "shader program '%s'.\n",
            m_pixel_shader_filename,
            get_name());
        return -1;
    }

    /*
     *  Relink the shader program.
     */
    retval = link();

    if (retval != 0)
    {
        bdi_log_printf(BDI_LOG_WARN,
            "WARNING: Failed to relink shader program '%s'.\n",
            get_name());
        return -1;
    }

    return 0;
}
load_and_compile_shader
Description:

Protected utility function for loading and compiling a shader object.

int
diguyOglGraphicsShaderProgram::load_and_compile_shader(GLhandleARB shader_object,
    const char* shader_filename,
    bool& shader_loaded)
{
    /*
     *  Needed to suport reloading.
     */
    if (shader_loaded)
        glDetachObjectARB(m_gl_program_object, shader_object);

    int retval = 0;

    shader_loaded = false;

    /*
     *  Load source file using utility function load_shader_source().
     */
    char* source_text = load_shader_source(shader_filename);
    if (!source_text)
    {
        /*
         *  Note that this might not be an error if the shader file doesn't
         *   exist, or does exist but contains no code.
         */
        return 0;
    }

    /*
     *  Set up a #define for gamma correction factor.
     */
    const char* gamma_defines = NULL;

    // Set up #defines to enable various shader features before compiling
    std::string my_defines = "";
    std::string my_version = "#version 120\n";

    if (diguyApp::get_app()->get_use_sRGB_textures())
    {
        my_defines = "#define GAMMA_FACTOR 2.2 \n";
    }
    else
    {
        my_defines = "#define GAMMA_FACTOR 1.0 \n";
    }

    // the point light support is slow it's worth having a second set of shaders 
    // and just activating when needed.
    if(m_include_point_lights){
        my_defines += "#define POINT_LIGHT_SUPPORT \n";
    }
    if(get_use_4x3_shader_matrix_data()){
        my_defines +=  "#define MATRIX_4x3_SUPPORT\n";
    }

    my_defines += "#define COMPONENT_MAP_SUPPORT \n";
    
    my_defines += "#define SHADOW_SUPPORT \n";

    const char * shader_strings[4];
    shader_strings[0] = my_version.c_str();
    shader_strings[1] = my_defines.c_str();
    // reset the line number for error handling
    shader_strings[2] = "#line 0 0\n";
    shader_strings[3] = source_text;

    glShaderSource(shader_object, 4, shader_strings, NULL);

    /*
     *  Compile shader_object.
     */
    {
        glCompileShader(shader_object);

        /*
         *  Do this to see if the compile succeeded.
         */
        GLchar* info_log;
        GLint   info_log_length = 0;
        GLint   compile_status = 0;

        glGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);
        glGetObjectParameterivARB(shader_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);

        bdi_log_printf(BDI_LOG_INFO,
            "INFO: Shader source '%s' compile status: %d\n",
            shader_filename,
            compile_status);

        if (info_log_length > 1)
        {
            info_log = (GLchar*) malloc(info_log_length);

            glGetInfoLogARB(shader_object, info_log_length, NULL, info_log);

            info_log[info_log_length-1] = '\0';
            info_log_length--;

            /*
             *  Radeon adds some extra newlines.
             */
            while ((info_log[info_log_length-1] == '\n') &&
                (info_log_length > 0))
            {
                info_log[info_log_length-1] = '\0';
                info_log_length--;
            }

            /*
             *  Take into account that Radeon compiler returns an info log
             *   even on success.
             */
            if ((strstr(info_log, "error")) &&
                (!strstr(info_log, "No errors")))
            {
                bdi_log_printf(BDI_LOG_WARN,
                    "WARNING: Shader source file '%s' compile info: %s\n",
                    shader_filename,
                    info_log);
                retval = -1;
            }
            else
            {
                bdi_log_printf(BDI_LOG_DEBUG,
                    "DEBUG: Shader source file '%s' compile info: %s\n",
                    shader_filename,
                    info_log);
                retval = 0;
            }

            free(info_log);
        }
        else
        {
            retval = 0;
        }
    }

    /*
     *  Free source.
     */
    free_shader_source(source_text);

    shader_loaded = true;
    return retval;
}
load_shader_source
Description:

Protected utility function for loading shader program source code.

char*
diguyOglGraphicsShaderProgram::load_shader_source(const char* shader_filename)
{
    FILE* fp = NULL;
    char* shader_source;
    int length;

    /*
     *  Try shader_filename straight up.
     */
    fp = fopen(shader_filename, "r");

    if (!fp)
    {
        bdi_log_printf(BDI_LOG_WARN, "WARNING: Failed to load shader source "
            "file '%s'.\n",
            shader_filename);
        return NULL;
    }

    /*
     *  Check the length of the file.
     */
    fseek(fp, 0, SEEK_END);
    length = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    /*
     *  If length is less than some small amount (less than a legal shader
     *   program length), decide that the shader program isn't valid and
     *   return NULL.
     */
    const int MIN_LENGTH = 24;
    if (length < MIN_LENGTH)
    {
        bdi_log_printf(BDI_LOG_DEBUG,
            "DEBUG: Shader source file '%s' length is less than %d, and will "
            "not be loaded.\n",
            shader_filename,
            MIN_LENGTH);
        fclose(fp);

        return NULL;
    }

    shader_source = new char[length+1];
    memset(shader_source, 0, length);

    fread(shader_source, 1, length, fp);
    shader_source[length] = '\0'; // make it a regular C string so str* functions work
    fclose(fp);

    return shader_source;
}
free_shader_source
Description:

Protected utility function for freeing shader program source code allocated during load_shader_source().

void
diguyOglGraphicsShaderProgram::free_shader_source(char* shader_source)
{
    delete[] shader_source;
}
bind_link_matrices
Draw Stage

Description:

Override of diguyGraphicsShaderInstance::bind_link_matrices().

The bind_link_matrices() function should pass link transformation matrices generated from DI-Guy motion data to the GPU.

int
diguyOglGraphicsShaderProgram::bind_link_matrices(int num_mats,
    const float* mat_data)
{
    if (m_gl_program_object == 0)
        return -1;

    if (m_bind_location_ufrm_link_matrices == -1)
        return -1;

    if(mat_data == m_last_matrix_data){
        return 0;
    }

    m_last_matrix_data = mat_data;

    /*
     *  Pass the link matrices generated from DI-Guy motion data to the GPU.
     */
    if(get_use_4x3_shader_matrix_data())
    {
        glUniformMatrix4x3fv(m_bind_location_ufrm_link_matrices,   // uniform var location
            num_mats,    // number of matrices
            GL_TRUE,    // whether to transpose matrix
            mat_data);   // pointer to matrix data
    }
    else{
        glUniformMatrix4fv(m_bind_location_ufrm_link_matrices,   // uniform var location
            num_mats,    // number of matrices
            !get_transposed_matrix_data(),    // whether to transpose matrix
            mat_data);   // pointer to matrix data
    }

    return 0;
}
bind_color_array
Draw Stage

Description:

Override of diguyGraphicsShaderInstance::bind_color_array().

The bind_color_array() function should pass the link colors array generated by DI-Guy to the GPU.

int
diguyOglGraphicsShaderProgram::bind_color_array(int num_colors,
    const float* color_data)
{
    if (m_bind_location_ufrm_link_colors == -1)
        return -1;

    glUniform4fv(m_bind_location_ufrm_link_colors,
        num_colors,     // number of colors
        color_data);    // pointer to color data

    return 0;
}
set_apply_matrices_flag
Draw Stage

Description:

Override of diguyGraphicsShaderInstance::set_apply_matrices_flag().

The set_apply_matrices_flag() function should pass the specifiead apply_matrices_flag to the GPU, typically through a uniform variable.

Note that this implementation is specific to the reference DI-Guy shader implementation, which checks the flag to determine if the matrices passed in the bind_link_matrices() call will be applied.

The matrices should be applied for skinned appearances, not applied for unskinned/segmented appearances. The reference shader will do the right thing based on the value of this flag. Custom shader code should do something similar.

void
diguyOglGraphicsShaderProgram::set_apply_matrices_flag(int apply_matrices_flag)
{

    if (m_bind_location_ufrm_apply_matrices_flag == -1)
        return;

    glUniform1f(m_bind_location_ufrm_apply_matrices_flag,
        (float) apply_matrices_flag);
}
bind_uniform_with_location
Draw Stage

Description:

Used to send float values to the shader. Should be used when sending DI-Guy shader constants to the shader. This will only happen if get_uniform_bind_location() is implemented and returns something other then -1. This function must be implemented for advanced DI-Guy materials to work.

int
diguyOglGraphicsShaderProgram::bind_uniform_with_location(int location,
    const char* name,
    int value_size,
    float* values)
{
    if (value_size == 1)
        glUniform1f(location, values[0]);
    else if (value_size == 2)
        glUniform2f(location, values[0], values[1]);
    else if (value_size == 3)
        glUniform3f(location, values[0], values[1], values[2]);
    else if (value_size == 4)
        glUniform4f(location, values[0], values[1], values[2], values[3]);

    return 0;
}
bind_uniform_with_location
Draw Stage

Description:

Used to send int values to the shader.

int
diguyOglGraphicsShaderProgram::bind_uniform_with_location(int location,
    const char* name,
    int value_size,
    int* values)
{
    if (value_size == 1)
        glUniform1i(location, values[0]);
    else if (value_size == 2)
        glUniform2i(location, values[0], values[1]);
    else if (value_size == 3)
        glUniform3i(location, values[0], values[1], values[2]);
    else if (value_size == 4)
        glUniform4i(location, values[0], values[1], values[2], values[3]);

    return 0;
}
Create function definition
Create and return an object of a subclass of diguyGraphicsShaderProgram. This function will be called whenever DI-Guy requires a shader program object.

diguyGraphicsShaderProgram*
diguyOglGraphicsShaderProgram_create_func(void* internal_data)
{
    if (!s_shader_extension_available)
    {
        bdi_log_printf(BDI_LOG_ERROR,
            "ERROR: Cannot create shader program; OpenGL shader extension "
            "not available.\n");
        return NULL;
    }

    return new diguyOglGraphicsShaderProgram(internal_data);
}



Copyright (C) 1992-2012 Boston Dynamics

ALL RIGHTS RESERVED.

These coded instructions, statements, and computer programs contain unpublished proprietary information of Boston Dynamics and are protected by Copyright Laws of the United States. They may not be used, duplicated, or disclosed in any form, in whole or in part, without the prior written consent from Boston Dynamics.

RESTRICTED RIGHTS LEGEND

Use, duplication, or disclosure by the government is subject to restrictions as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Sofware clause at DFARS 252.227-7013 and/or in similar or successor clauses in the FAR, or the DOD or NASA FAR Supplement, or to subparagraphs (c)(1) and (c)(2) of the Commercial Computer Software--Restricted Rights at 48 CFR 52.227-19, as applicable. Unpublished-rights reserved under the Copyright Laws of the United States.

Contractor/Manufacturer is:

Boston Dynamics/78 Fourth Avenue/Waltham MA 02451.