DI-Guy Graphics API, diguyOsgGraphicsShaderProgram

diguyOsgGraphicsShaderProgram.cpp

DI-Guy API Version 12.5.1

This file was automatically generated from diguyOsgGraphicsShaderProgram.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 or fragment shader.

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 shader instance.

The class diguyOsgGraphicsShaderProgram is an example of a diguyGraphicsShaderProgram subclass for an scene graph 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 a scene graph renderer such as OSG.

Header files and forward declarations
#include <stdlib.h>
#include <stdio.h>

#include <fstream>

#include <osg/Drawable>
#include <osg/Version>

#include "diguyOsgGraphicsShaderProgram.h"
#include "diguyOsgGraphicsShaderInstance.h"
#include "diguyOsgGraphicsLink.h"
#include "diguyOsgGraphicsShape.h"
#include <diguyApp.h>
#include <libbdilog.h>

#include <string.h>
Constructor
Description:

Initialize data members of the class to a known state.

Most base class data is not fully initialized until during the Build Stage, so most base class accessors should not be called here.

diguyOsgGraphicsShaderProgram::diguyOsgGraphicsShaderProgram(void* internal_data)
    :
    diguyGraphicsShaderProgram(internal_data),
    m_program(NULL),
    m_vertex_shader(NULL),
    m_fragment_shader(NULL)
{
    m_vertex_shader_filename[0] = NULL;
    m_fragment_shader_filename[0]  = NULL;

    /*
     *  Create an OSG program.
     */
    m_program = new osg::Program;
    m_program->setName(get_name());

    /*
     *  Add vertex and fragment shaders to it.  Note that source code is not
     *   loaded here, but in load_vertex_shader_source() and
     *   load_pixel_shader_source().
     */
    m_vertex_shader   = new osg::Shader(osg::Shader::VERTEX);
    m_fragment_shader = new osg::Shader(osg::Shader::FRAGMENT);

    m_program->addShader(m_vertex_shader);
    m_program->addShader(m_fragment_shader);

    /*
     *  Add attributes (GLSL attributes, not OSG Attributes).
     *
     *  I'm not yet sure about how to properly choose explicit indices, so
     *   I'm going to use the ATTRIBUTE_6 and ATTRIBUTE_7 values
     *   from osg::Drawable.
     *
     *  From osg_glsl_july2005.pdf:
     *
     *  - GL supports both explicit and automatic attribute binding
     *  - GLSL will dynamically assign attribute indices if not otherwise
     *    specified
     *  - However, OSG currently supports only explicit binding, so app
     *    must assign indices
     *  - Automatic binding makes display lists dependent on osg::Program,
     *    and has impact on DL sharing
     *  - GLSL specifies much freedom in selecting attribute indices, but
     *    some current drivers impose restrictions
     */
    m_program->addBindAttribLocation("attr_weight_array", osg::Drawable::ATTRIBUTE_6);
    m_program->addBindAttribLocation("attr_index_array",  osg::Drawable::ATTRIBUTE_7);
    m_program->addBindAttribLocation("attr_tangent",  osg::Drawable::SECONDARY_COLORS);
}
Destructor
Description:

Dereference OSG objects created in the constructor.

diguyOsgGraphicsShaderProgram::~diguyOsgGraphicsShaderProgram()
{
    m_vertex_shader_filename[0] = NULL;
    m_fragment_shader_filename[0]  = NULL;

    m_program = NULL;
    m_vertex_shader = NULL;
    m_fragment_shader = NULL;
}
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 uses OSG to load the shader source code.

int
diguyOsgGraphicsShaderProgram::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);

    bool retval = m_vertex_shader->loadShaderSourceFromFile(m_vertex_shader_filename);

    /*
     *  Prepend #define OSG_INTERSECTION to the shader to allow
     *  the intersection shader to work with OSG.
     *
     *  Prepend #version at the top to comply with 
     *  ATI shader strictness.
     *  
     */
    const std::string my_version = "#version 120\n";
    const std::string my_defines = "#define OSG_INTERSECTION\n";
    const std::string my_line_reset = "#line 0 0\n";
    const std::string& shader_source = m_vertex_shader->getShaderSource();

    std::string new_source = my_version + my_defines + my_line_reset + shader_source;

    m_vertex_shader->setShaderSource(new_source);

    if (retval == true)
        return 0;

    return -1;
}
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 uses OSG to load the shader source code.

int
diguyOsgGraphicsShaderProgram::load_pixel_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_fragment_shader_filename,
        511,
        filename_base,
        "glsl",
        "frag",
        1);

    /*
     *  Because sRGB textures aren't currently supported in OSG, we need to
     *   disable them in the shader.  To do so we're using a #define in the
     *   shader source.  Below is a modified version of the
     *   osg::Shader::loadShaderSourceFromFile() function's internal code
     *   that adds the #define where we want it.
     */

    /*
     *  Old way:
     */
    //bool retval = m_fragment_shader->loadShaderSourceFromFile(m_fragment_shader_filename);

    std::ifstream source_file;

    source_file.open(m_fragment_shader_filename, std::ios::binary);
    if (!source_file)
    {
        bdi_log_printf(BDI_LOG_ERROR,
            "ERROR: Can't open shader source file '%s'.\n",
            m_fragment_shader_filename);
        return -1;
    }

    source_file.seekg(0, std::ios::end);
    int length = source_file.tellg();
    char* text = new char[length + 1];
    source_file.seekg(0, std::ios::beg);
    source_file.read(text, length);
    source_file.close();
    text[length] = '\0';

    std::string shader_source = text;
    std::string version = "#version 120\n";
    // OSG Doesn't support SRGB texture targets at the moment so make the pow 
    // gamma no op.
    std::string my_defines;
    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";
    }
    
    // No support for point lights in osg samples yet
    //my_defines += "#define POINT_LIGHT_SUPPORT\n";
    
    // No support for shadow maps in osg samples yet
    //my_defines += "#define SHADOW_SUPPORT\n";

    my_defines += "#define COMPONENT_MAP_SUPPORT\n";
    // reset line numbers for error reporting
    my_defines += "#line 0 0\n";

    // catonate defines and source together
    shader_source = my_defines + text;

    m_fragment_shader->setShaderSource(shader_source.c_str());
    delete[] text;

    return 0;
}
link
Build Stage

Description:

Override of diguyGraphicsShaderProgram::link().

int
diguyOsgGraphicsShaderProgram::link()
{
    // Options for the uniform array name.
    static char* ufrm = "ufrm_link_matrices";
    static char* ufrm0 = "ufrm_link_matrices[0]";

    static char* ufrm_color = "ufrm_link_colors";
    static char* ufrm0_color = "ufrm_link_colors[0]";

    /*
     *  Work done internally by OSG.
     *
     *  Work around for uniform array bug in OSG. Compile and link the
     *   program to determine if the the graphics driver will return
     *   "ufrm_link_matrices" or "ufrm_link_matrices[0]" for the array of
     *   uniforms in the shader.  Give the string to the diguyOsgGraphicsShape
     *   so it can properly set and use the uniform name.
     */
    if (!diguyOsgGraphicsShape::s_ufrm_link_matrices_string)
    {
        static bool warn_once = true;
        osgViewer::Viewer::Contexts contexts;
        osgViewer::Viewer* viewer = diguyOsgGraphicsLink::get_viewer();
        if (!viewer) 
        {
            if (warn_once)
            {
                warn_once = false;
                bdi_log_printf(BDI_LOG_WARN,
                    "WARNING: Can't detect shader uniform array name "
                    "(diguyGraphicsLink::s_viewer is NULL).  Set viewer using "
                    "diguyOsgGraphicsLink::set_viewer().\n");

                // Just guess at one...
                diguyOsgGraphicsShape::s_ufrm_link_matrices_string = ufrm0;
            }

            return 0;
        }

        viewer->getContexts(contexts);

        m_program->compileGLObjects(*(contexts[0]->getState()));

        osg::Program::PerContextProgram* pcp_program = m_program->getPCP(contexts[0]->getState()->getContextID());

#if OPENSCENEGRAPH_MAJOR_VERSION == 2
        pcp_program->linkProgram();
#else
        pcp_program->linkProgram(*(contexts[0]->getState()));
#endif

        if (!diguyOsgGraphicsShape::s_ufrm_link_matrices_string)
        {
            if (pcp_program->getUniformLocation("ufrm_link_matrices") != -1)
            {
                diguyOsgGraphicsShape::s_ufrm_link_matrices_string = ufrm;
            }
            else
            {
                diguyOsgGraphicsShape::s_ufrm_link_matrices_string = ufrm0;
            }
        }
    }

    if (!diguyOsgGraphicsShape::s_ufrm_link_colors_string)
    {
        static bool warn_once = true;
        osgViewer::Viewer::Contexts contexts;
        osgViewer::Viewer* viewer = diguyOsgGraphicsLink::get_viewer();
        if (!viewer) 
        {
            if (warn_once)
            {
                warn_once = false;
                bdi_log_printf(BDI_LOG_WARN,
                    "WARNING: Can't detect shader uniform array name "
                    "(diguyGraphicsLink::s_viewer is NULL).  Set viewer using "
                    "diguyOsgGraphicsLink::set_viewer().\n");

                // Just guess at one...
                diguyOsgGraphicsShape::s_ufrm_link_colors_string = ufrm0;
            }

            return 0;
        }

        viewer->getContexts(contexts);

        m_program->compileGLObjects(*(contexts[0]->getState()));

        osg::Program::PerContextProgram* pcp_program = m_program->getPCP(contexts[0]->getState()->getContextID());

#if OPENSCENEGRAPH_MAJOR_VERSION == 2
        pcp_program->linkProgram();
#else
        pcp_program->linkProgram(*(contexts[0]->getState()));
#endif

        if (!diguyOsgGraphicsShape::s_ufrm_link_colors_string)
        {
            if (pcp_program->getUniformLocation("ufrm_link_colors") != -1)
            {
                diguyOsgGraphicsShape::s_ufrm_link_colors_string = ufrm_color;
            }
            else if (pcp_program->getUniformLocation("ufrm_link_colors[0]") != -1)
            {
                diguyOsgGraphicsShape::s_ufrm_link_colors_string = ufrm0_color;
            }
        }
    }

    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
diguyOsgGraphicsShaderProgram::reload()
{
    /*
     *  The shader will internally be set to out-of-date, and will
     *   automatically be relinked when needed.
     */
    m_vertex_shader->loadShaderSourceFromFile(m_vertex_shader_filename);
    m_fragment_shader->loadShaderSourceFromFile(m_fragment_shader_filename);

    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*
diguyOsgGraphicsShaderProgram_create_func(void* internal_data)
{
    return new diguyOsgGraphicsShaderProgram(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.