Logo Search packages:      
Sourcecode: openexr version File versions  Download package

ImageViewFragShader.cpp

///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

//
// Authors:
//   Simon Green <SGreen@nvidia.com>
//   Drew Hess <dhess@ilm.com>
//

//----------------------------------------------------------------------------
//
//    class ImageViewFragShader
//
//----------------------------------------------------------------------------

#include <ImageViewFragShader.h>

#if defined PLATFORM_DARWIN_PPC
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#define GLH_EXT_SINGLE_FILE
#include <glh/glh_extensions.h>

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ImathFun.h>
#include <ImathMath.h>
#include <Iex.h>


ImageViewFragShader::ImageViewFragShader (int x, int y,
                                int width, int height,
                                const char label[],
                                const Imf::Rgba pixels[],
                                int dw, int dh,
                                int dx, int dy,
                                float exposure,
                                float defog,
                                float kneeLow,
                                float kneeHigh,
                                const std::string & filename)
:
    ImageView (x, y,
             width, height,
             label,
             pixels,
             dw, dh,
             dx, dy,
             exposure,
             defog,
             kneeLow, 
             kneeHigh),
    _useSoftware (false),
    _fsFilename (filename)
{
}


bool
ImageViewFragShader::initGL ()
{
    bool status = true;

    try
    {
      if (!glh_init_extensions("GL_ARB_multitexture "
                         "GL_NV_vertex_program "
                         "GL_NV_fragment_program "))
      {
          THROW (Iex::BaseExc, "GL extensions required for fragment " <<
               "shader support are not available: " << std::endl <<
               "    " << glh_get_unsupported_extensions ());
      }         

      if (_fsFilename.empty ())
          loadBuiltinFragShader ();
      else
          loadFragShaderFromFile ();

      loadTexture ();
    }
    catch (const Iex::BaseExc & e)
    {
      std::cerr << e.what () << std::endl;
      std::cerr << "Falling back to software rendering." << std::endl;
      status = false;
    }

    return status;
}


void
ImageViewFragShader::loadTexture ()
{
    //
    // load OpenEXR image as OpenGL texture
    //

    GLenum target = GL_TEXTURE_RECTANGLE_NV;
    glGenTextures (1, &_texture);
    glBindTexture (target, _texture);
    glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    
    glTexImage2D (target, 0, GL_FLOAT_RGBA16_NV, _dw, _dh, 0, 
              GL_RGBA, GL_HALF_FLOAT_NV, _rawPixels);
    
    //
    // Check for errors
    //
    
    GLenum error = glGetError ();
    if (error != GL_NO_ERROR)
    {
      do
      {
          std::cerr << "Error loading texture: " <<
            (char *) gluErrorString (error) << std::endl;
      } while ((error = glGetError ()) != GL_NO_ERROR);
      
      THROW (Iex::BaseExc, "Unable to load OpenEXR image as a texture.");
    }
    
}


void
ImageViewFragShader::draw()
{
    if (!valid())
    {
      if (!initGL ())
          _useSoftware = true;

      //
      // Set up camera.
      //

      glMatrixMode (GL_PROJECTION);
      glLoadIdentity ();
      glViewport (0, 0, w (), h ());
      glOrtho (0, w (), h (), 0, -1, 1);
      glMatrixMode (GL_MODELVIEW);
      glLoadIdentity ();
    }

    if (_useSoftware)
    {
      ImageView::updateScreenPixels ();
      ImageView::draw ();
      return;
    }

    glClearColor (0.3, 0.3, 0.3, 1.0);
    glClear (GL_COLOR_BUFFER_BIT);

    //
    // Set fragment program parameters.  See ImageView.cpp for details
    // on what the parameters mean.
    //

    setCgNamedParameter ("exposure",
                  Imath::Math<float>::pow (2, _exposure + 2.47393));
    setCgNamedParameter ("defog", _defog * _fogR, _defog * _fogG, 
                   _defog * _fogB);
    setCgNamedParameter ("gamma", 0.4545f);
    setCgNamedParameter ("grayTarget", 84.66/255.0);

    float kl = Imath::Math<float>::pow (2, _kneeLow);

    setCgNamedParameter ("kneeLow", kl);
    setCgNamedParameter ("kneeF", findKneeF (Imath::Math<float>::pow (2, _kneeHigh) - kl,
                                   Imath::Math<float>::pow (2, 3.5) - kl));

    //
    // draw a textured quad
    //

    glEnable (GL_FRAGMENT_PROGRAM_NV);
    glEnable (GL_TEXTURE_RECTANGLE_NV);
    glBegin (GL_QUADS);
    glTexCoord2f (0.0, 0.0); glVertex2f(0.0, 0.0);
    glTexCoord2f (_dw, 0.0); glVertex2f(_dw, 0.0);
    glTexCoord2f (_dw, _dh); glVertex2f(_dw, _dh);
    glTexCoord2f (0.0, _dh); glVertex2f(0.0, _dh);
    glEnd ();
    glDisable (GL_TEXTURE_RECTANGLE_NV);
    glDisable (GL_FRAGMENT_PROGRAM_NV);
}


void
ImageViewFragShader::loadFragShaderFromFile ()
{
    FILE * f = 0;
    char * code = 0;

    try
    {
      f = fopen (_fsFilename.c_str (), "rb");
      if (!f)
      {
          THROW_ERRNO ("Can't load fragment shader file " << _fsFilename <<
                   " (%T)");
      }

      fseek (f, 0, SEEK_END);
      int len = ftell (f);
      fseek (f, 0, SEEK_SET);
      
      code = new char[len + 1];
      
      int read = fread (code, 1, len, f);
      if (read != len)
      {
          THROW (Iex::BaseExc, "Expected " << len << " bytes in fragment " <<
             "shader file " << _fsFilename << ", only got " << read);
      }

      code[read] = '\0';    // null-terminate

      if (!loadFragShader (code))
      {
          THROW (Iex::BaseExc, "Can't download fragment shader " << 
               _fsFilename);
      }

      delete [] code;
      fclose (f);
    }
    catch (Iex::BaseExc & e)
    {
      delete [] code;
      if (f)
          fclose (f);

      throw e;
    }
}


namespace
{

//
// This is the built-in fragment shader.  It was generated by
// running:
//
//   cgc -profile fp30 -o exrdisplay.fp30 exrdisplay.cg
//
// and then trimming the comments out and formatting it as a C string.
//

const char *
theFragShader =
    "!!FP1.0\n" \
    "DECLARE defog;\n" \
    "DECLARE exposure;\n" \
    "DECLARE gamma;\n" \
    "DECLARE zerovec;\n" \
    "DECLARE grayTarget;\n" \
    "DECLARE kneeLow;\n" \
    "DECLARE kneeF;\n" \
    "TEX  H0.xyz, f[TEX0].xyxx, TEX0, RECT;\n" \
    "ADDR R0.xyz, H0.xyzx, -defog.xyzx;\n" \
    "MAXH H0.xyz, zerovec.xyzx, R0.xyzx;\n" \
    "MULR R0.xyz, H0.xyzx, exposure.x;\n" \
    "ADDH H0.xyz, R0.xyzx, -kneeLow.x;\n" \
    "MOVH H0.w, {1, 1, 1}.x;\n" \
    "MADH H0.xyz, H0.xyzx, kneeF.x, H0.w;\n" \
    "LG2H H0.w, H0.x;\n" \
    "MOVH H1.x, H0.w;\n" \
    "LG2H H0.w, H0.y;\n" \
    "MOVH H1.y, H0.w;\n" \
    "LG2H H0.x, H0.z;\n" \
    "MOVH H1.z, H0.x;\n" \
    "MULH H1.xyz, H1.xyzx, {0.69335938, 0.69335938, 0.69335938}.x;\n" \
    "RCPH H0.x, kneeF.x;\n" \
    "MADH H0.xyz, H1.xyzx, H0.x, kneeLow.x;\n" \
    "MOVR H1.xyz, R0.xyzx;\n" \
    "SGTH H2.xyz, R0.xyzx, kneeLow.x;\n" \
    "MOVXC HC.xyz, H2.xyzx;\n" \
    "MOVH H1.xyz(GT.xyzx), H0.xyzx;\n" \
    "POWH H0.x, H1.x, gamma.x;\n" \
    "POWH H0.w, H1.y, gamma.x;\n" \
    "MOVH H0.y, H0.w;\n" \
    "POWH H0.w, H1.z, gamma.x;\n" \
    "MOVH H0.z, H0.w;\n" \
    "MULH H0.xyz, H0.xyzx, grayTarget.x;\n" \
    "MOVH o[COLH].xyz, H0.xyzx;\n" \
    "END\n" \
    "\0";

}


void
ImageViewFragShader::loadBuiltinFragShader ()
{
    //
    // Use the built-in fragment shader
    //

    if (!loadFragShader (theFragShader))
      THROW (Iex::BaseExc, "There was a roblem downloading built-in " <<
             "fragment shader.");
}


bool
ImageViewFragShader::loadFragShader (const char * code)
{
    int len = strlen (code);
    
    //
    // load the fragment shader into the card
    //
    
    glGenProgramsNV (1, &_fprog);
    glBindProgramNV (GL_FRAGMENT_PROGRAM_NV, _fprog);
    glLoadProgramNV (GL_FRAGMENT_PROGRAM_NV, _fprog, len, 
                 (const GLubyte *) code);

    //
    // check for errors
    //
    
    GLint errpos;
    glGetIntegerv (GL_PROGRAM_ERROR_POSITION_NV, &errpos);
    if (errpos != -1)
    {
      std::cerr << "Fragment shader error:" << std::endl << std::endl;
      
      int begin = (errpos - 20) < 0 ? 0 : errpos - 20;
      char errtxt[81];
      
      strncpy (errtxt, code + begin, 80);
      errtxt[80] = '\0';
      
      std::cerr << errtxt << std::endl << std::endl;
    }

    return errpos == -1;
}


void
ImageViewFragShader::setCgNamedParameter (const char * name,
                                float x,
                                float y,
                                float z,
                                float w)
{
    glProgramNamedParameter4fNV (_fprog, strlen (name), (GLubyte *) name,
                         x, y, z, w);
}

Generated by  Doxygen 1.6.0   Back to index