hlslFXShader.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

#include <maya/MGlobal.h>

#include "Platform.h"
#include "hlslFXShader.h"

#include "ResourceManager.h"

//
//
//
hlslFXShader::hlslFXShader() :  m_valid(false), m_fShader(0), m_vShader(0), m_activePass(0), m_activeTechnique(0),
  m_stale(false), m_color(true), m_normal(true), m_tangent(true), m_binormal(true), m_texMask(0x1), m_error("") {

  
}

//
//
//
hlslFXShader::~hlslFXShader() {

  for (std::vector<passState*>::iterator it=m_stateList.begin(); it<m_stateList.end(); it++) {
    delete *it;
  }

  //assumes deleting 0 is OK
  deleteShaders();
}

//
//
//
void hlslFXShader::deleteShaders() {

  {
  for (std::vector<GLuint>::iterator it = m_vShader.begin(); it < m_vShader.end(); it++) {
    ResourceManager::destroyAsmProgram( *it);
  }
  }

  m_vShader.clear();

  {
  for (std::vector<GLuint>::iterator it = m_fShader.begin(); it < m_fShader.end(); it++) {
    ResourceManager::destroyAsmProgram( *it);
  }
  }

  m_fShader.clear();

}

//
//
//
bool hlslFXShader::createFromFile( const char *filename) {
  m_error = ""; 
  IAshliFX *fx = new IAshliFX;
  fx->init();
  fx->setBinding( IAshliFX::DXSL);
  fx->setFX( filename);  //may need to do some path searching here
  m_stale = true;
  

  try {
    if (!fx->parse()) {
      //should store a string describing the failure for query
      m_error = "Unable to load FX file\n  ";
      m_error += fx->getError();
      delete fx;
      return false;
    }
  } catch(...){
    printf("Unexpected Error!!\n");
  };


  if ( fx->getNumTechniques()) {
  }
  else {
    //message about no valid first technique/incorrect number of passes
    delete fx;
    m_error = "FX file lacked a valid shader";
    return false;
  }
  
  //this will move to bind time
  //if (!buildShaders())
  //  return false;

  if (!parseParameters(fx))
    return false;

  //need to extract all shader data from the fx file here 
  //these are to hold the ASHLIFX data
  m_techniqueCount = fx->getNumTechniques();
  m_techniqueNames.clear();
  m_passCount.clear();
  m_techniqueOffset.clear();
  m_vertexShaders.clear();
  m_fragmentShaders.clear();
  m_orgVertexShaders.clear();
  m_orgFragmentShaders.clear();
  for (std::vector<passState*>::iterator it=m_stateList.begin(); it<m_stateList.end(); it++) {
    delete *it;
  }
  m_stateList.clear();
  int totalPasses =0;

  stateObserver *observer = new stateObserver;

  fx->attach( (IObserveFX*)observer);

  for (int ii=0; ii<m_techniqueCount; ii++) {
    int passCount = fx->getNumPasses(ii);
    m_techniqueOffset.push_back(totalPasses);
    ITechniqueFX tech;
    fx->getTechnique(ii, tech);
    m_techniqueNames.push_back(tech.getId());
    m_passCount.push_back(passCount);
    for (int jj=0; jj<passCount; jj++) {
      std::string vString;
      std::string fString;
      std::string orgVString;
      std::string orgFString;
      
      //allocate an ashli for this pass
      IAshli *ashli = new IAshli;
      ashli->setNative(IAshli::DXSL);
      ashli->setFlag( IAshli::UnpackedScalars, true);
      ashli->setFlag( IAshli::ContiguousMatrix, true);
      ashli->setFlag( IAshli::ContiguousArray, true);
      ashli->setFlag( IAshli::MultiPass, false);
      ashli->init( IAshli::Stream, IAshli::GL, IAshli::Stream);
      if ( !fx->isVertexNull( ii, jj)) {
        orgVString = fx->getVertexShader( ii, jj);
        ashli->addShaderItem( orgVString.c_str());
        ashli->addShaderInstance( ashli->addShader( IAshli::Vertex, fx->getVertexEntry( ii, jj)));
      }
      if ( !fx->isPixelNull( ii, jj)) {
        orgFString = fx->getPixelShader( ii, jj);
        ashli->addShaderItem( orgFString.c_str());
        ashli->addShaderInstance( ashli->addShader( IAshli::Pixel, fx->getPixelEntry( ii, jj)));
      }
      if ( ashli->invoke("")) {
        //compile succeeded 
        fx->setMetadata( ii, jj, ashli->getFormals());
        fx->setVertexAssembly( ii, jj, ashli->getVertexShader());
        fx->setPixelAssembly( ii, jj, ashli->getPixelShader());
        if (fx->getVertexAssembly( ii, jj))
          vString = fx->getVertexAssembly( ii, jj);
        if (fx->getPixelAssembly( ii, jj))
          fString = fx->getPixelAssembly( ii, jj);
      }
      else {
        //compile failed
        const char* error = ashli->getError();
        m_error = "Shader failed to compile\n";
        m_error += error;
        m_error += std::string("\n");
        // would like to print the offending text, but the parsing seems to difficult
      }

      m_vertexShaders.push_back(vString);
      m_fragmentShaders.push_back(fString);

      m_orgVertexShaders.push_back(orgVString);
      m_orgFragmentShaders.push_back(orgFString);

      //accumulate the state data
      m_stateList.push_back(new passState);
      observer->setPassMonitor(m_stateList.back());
      for (int kk=0; kk<fx->getNumStates( ii,jj); kk++) {
        fx->getStateItem( ii, jj, kk);
      }
      observer->finalizePassMonitor();
      delete ashli;
    }
    totalPasses += passCount;
  }
    
  fx->attach(NULL);
  delete observer;
  delete fx;

  m_valid = true;

  return true;
}

//
//
//
bool hlslFXShader::createFromFX( IAshliFX *fx) {
  m_error = ""; 
  m_stale = true;
  m_valid = false;
  int maxVInstructions, maxVTemps, maxVParameters, maxALU, maxTexInst, maxTexIndirections,
    maxFInstructions, maxFTemps, maxFParameters; /* maxTextures, maxVAttribs, */

  if (fx->getNumTechniques()) {
  }
  else {
    //message about no valid first technique/incorrect number of passes
    m_error = "FX file lacked a valid shader";
    return false;
  }
  
  if (!parseParameters(fx))
    return false;

  //query for all the limits
  glGetProgramivARB( GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &maxVInstructions);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &maxFInstructions);
  glGetProgramivARB( GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, &maxVTemps);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, &maxFTemps);
  glGetProgramivARB( GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, &maxVParameters);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, &maxFParameters);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, &maxALU);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, &maxTexInst);
  glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, &maxTexIndirections);
/*
  maxFTemps += maxFTemps>>2 ;
  maxFInstructions += maxFInstructions>>2 ;
  maxALU += maxALU>>2 ;
*/
  //need to extract all shader data from the fx file here 
  //these are to hold the ASHLIFX data
  m_techniqueCount = fx->getNumTechniques();
  m_techniqueNames.clear();
  m_passCount.clear();
  m_techniqueOffset.clear();
  m_vertexShaders.clear();
  m_fragmentShaders.clear();
  m_orgVertexShaders.clear();
  m_orgFragmentShaders.clear();
  for (std::vector<passState*>::iterator it=m_stateList.begin(); it<m_stateList.end(); it++) {
    delete *it;
  }
  m_stateList.clear();
  int totalPasses =0;

  stateObserver *observer = new stateObserver;

  fx->attach( (IObserveFX*)observer);

  bool success = true;

  for (int ii=0; ii<m_techniqueCount; ii++) {
    int passCount = fx->getNumPasses(ii);
    m_techniqueOffset.push_back(totalPasses);
    ITechniqueFX tech;
    fx->getTechnique(ii, tech);
    m_techniqueNames.push_back(tech.getId());
    m_passCount.push_back(passCount);
    for (int jj=0; jj<passCount; jj++) {
      std::string vString;
      std::string fString;
      std::string orgVString;
      std::string orgFString;
      
      //allocate an ashli for this pass
      IAshli *ashli = new IAshli;
      ashli->setNative(IAshli::DXSL);
      ashli->setFlag( IAshli::UnpackedScalars, true);
      ashli->setFlag( IAshli::ContiguousMatrix, true);
      ashli->setFlag( IAshli::ContiguousArray, true);
      ashli->setFlag( IAshli::MultiPass, false);
      ashli->init( IAshli::Stream, IAshli::GL, IAshli::Stream);
      
      ashli->setResource( IAshli::Vertex, IAshli::InstructionSlots, maxVInstructions);
      ashli->setResource( IAshli::Vertex, IAshli::ALUInstructions, maxVInstructions);
      ashli->setResource( IAshli::Vertex, IAshli::FloatConstantRegisters, maxVParameters);
      ashli->setResource( IAshli::Vertex, IAshli::TemporaryRegisters, maxVTemps);
      ashli->setResource( IAshli::Pixel, IAshli::InstructionSlots, maxFInstructions);
      ashli->setResource( IAshli::Pixel, IAshli::ALUInstructions, maxALU);
      ashli->setResource( IAshli::Pixel, IAshli::TextureInstructions, maxTexInst);
      ashli->setResource( IAshli::Pixel, IAshli::TextureDependency, maxTexIndirections);
      ashli->setResource( IAshli::Pixel, IAshli::FloatConstantRegisters, maxFParameters);
      ashli->setResource( IAshli::Pixel, IAshli::TemporaryRegisters, maxFTemps);
      
      
      //ashli->setResource( IAshli::Vertex, IAshli::AllResources, 2048);
      //ashli->setResource( IAshli::Pixel, IAshli::AllResources, 2048);
      
      if ( !fx->isVertexNull( ii, jj)) {
        orgVString = fx->getVertexShader( ii, jj);
        ashli->addShaderItem( orgVString.c_str());
        ashli->addShaderInstance( ashli->addShader( IAshli::Vertex, fx->getVertexEntry( ii, jj)));
      }
      if ( !fx->isPixelNull( ii, jj)) {
        orgFString = fx->getPixelShader( ii, jj);
        ashli->addShaderItem( orgFString.c_str());
        ashli->addShaderInstance( ashli->addShader( IAshli::Pixel, fx->getPixelEntry( ii, jj)));
      }
      if ( ashli->invoke("")) {
        if ( ashli->getNumSegments() == 1 ) {
        //compile succeeded 
        fx->setMetadata( ii, jj, ashli->getFormals());
        fx->setVertexAssembly( ii, jj, ashli->getVertexShader());
        fx->setPixelAssembly( ii, jj, ashli->getPixelShader());
        if (fx->getVertexAssembly( ii, jj))
          vString = fx->getVertexAssembly( ii, jj);
        if (fx->getPixelAssembly( ii, jj))
          fString = fx->getPixelAssembly( ii, jj);
      }
      else {
        //compile failed
          success = false;
          m_error = "Shader exceeded available resources\n";
        }
      }
      else {
        //compile failed
        success = false;
        const char* error = ashli->getError();
        m_error = "Shader failed to compile\n";
        m_error += error;
        m_error += std::string("\n");
        // would like to print the offending text, but the parsing seems to difficult
      }

      m_vertexShaders.push_back(vString);
      m_fragmentShaders.push_back(fString);

      m_orgVertexShaders.push_back(orgVString);
      m_orgFragmentShaders.push_back(orgFString);

      //accumulate the state data
      m_stateList.push_back(new passState);
      observer->setPassMonitor(m_stateList.back());
      for (int kk=0; kk<fx->getNumStates( ii,jj); kk++) {
        fx->getStateItem( ii, jj, kk);
      }
      observer->finalizePassMonitor();
          // Commented out as this causes a access violation.
      //delete ashli;
    }
    totalPasses += passCount;
  }
    
  fx->attach(NULL);
  delete observer;

  m_valid = success;

  return success;
}

//
//
//
//new method, parsing parameters from AshliFX
bool hlslFXShader::parseParameters(const IAshliFX *fx) {

  int passCount =0, ii;
  
  for (ii=0; ii<fx->getNumTechniques(); ii++) {
    passCount = std::max<int>( fx->getNumPasses(ii), passCount);
  }

  //process the exposed shader parameters
  for (ii=0; ii<fx->getNumParameters(); ii++) {
    IParameterFX parm;
    fx->getParameter( "", ii, parm);
    const char *usage = parm.getUsage();
    const char *type = parm.getType();
    const char *name = parm.getId();
    const char *semantic = parm.getSemantic();
    const char *expression = parm.getExpression();
    if (strcmp( "const", usage)) {
      if (strncmp( "sampler", type, 7)) {
        // this is a regular uniform (not a sampler)

        //should verify the compatibility of the following pieces of data
        shader::DataType dt = parseUniformType( type);
        shader::Semantic sm = parseUniformSemantic( semantic);
        uniform u;
        u.type = dt;
        u.fReg.resize( passCount, -1);
        u.vReg.resize( passCount, -1);
        u.usage = sm;
        u.name = name;
        //parse the expression to extract a default value
        parseExpression( u, expression);

        //skip adding strings for now, maybe add them somewhere else later
        if (dt != shader::dtString)
        m_uniformList.push_back(u);
      }
      else {
        // this is a sampler uniform
        shader::SamplerType st = parseSamplerType( type);
        sampler s;
        s.texUnit.resize( passCount, -1);
        s.type = st;
        s.name = name;
        m_samplerList.push_back(s);
      }
    }
    else {
      //don't know what else we could encounter, might want to create warnings
    }
  }

  return true;
}

//
//
//
shader::DataType hlslFXShader::parseUniformType( const char *type) {
  if (!strcmp( "float", type)) {
    return shader::dtFloat;
  }
  else if (!strcmp( "float1", type)) {
    return shader::dtFloat;
  }
  else if (!strcmp( "float2", type)) {
    return shader::dtVec2;
  }
  else if (!strcmp( "float3", type)) {
    return shader::dtVec3;
  }
  else if (!strcmp( "float4", type)) {
    return shader::dtVec4;
  }
  else if (!strcmp( "int", type)) {
    return shader::dtInt;
  }
  else if (!strcmp( "int1", type)) {
    return shader::dtInt;
  }
  else if (!strcmp( "int2", type)) {
    return shader::dtIVec2;
  }
  else if (!strcmp( "int3", type)) {
    return shader::dtIVec3;
  }
  else if (!strcmp( "int4", type)) {
    return shader::dtIVec4;
  }
  else if (!strcmp( "bool", type)) {
    return shader::dtBool;
  }
  else if (!strcmp( "bool1", type)) {
    return shader::dtBVec2;
  }
  else if (!strcmp( "bool2", type)) {
    return shader::dtBVec2;
  }
  else if (!strcmp( "bool3", type)) {
    return shader::dtBVec3;
  }
  else if (!strcmp( "bool4", type)) {
    return shader::dtBVec4;
  }
  else if (!strcmp( "float2x2", type)) {
    return shader::dtMat2;
  }
  else if (!strcmp( "float3x3", type)) {
    return shader::dtMat3;
  }
  else if (!strcmp( "float4x4", type)) {
    return shader::dtMat4;
  }
  
  return shader::dtUnknown;
}

//
//
//
shader::Semantic hlslFXShader::parseUniformSemantic( const char *semantic) {

  if (semantic == NULL)
    return shader::smNone;

  //this would be more efficient as a map
  if (!strcasecmp( "World", semantic)) {
    return shader::smWorld;
  }
  else if (!strcasecmp( "View", semantic)) {
    return shader::smView;
  }
  else if (!strcasecmp( "Projection", semantic)) {
    return shader::smProjection;
  }
  else if (!strcasecmp( "WorldView", semantic)) {
    return shader::smWorldView;
  }
  else if (!strcasecmp( "ViewProjection", semantic)) {
    return shader::smViewProjection;
  }
  else if (!strcasecmp( "WorldViewProjection", semantic)) {
    return shader::smWorldViewProjection;
  }
  else if ( (!strcasecmp( "WorldI", semantic)) || (!strcasecmp( "WorldInverse", semantic))) {
    return shader::smWorldI;
  }
  else if ( (!strcasecmp( "ViewI", semantic)) || (!strcasecmp( "ViewInverse", semantic)) ) {
    return shader::smViewI;
  }
  else if ( (!strcasecmp( "ProjectionI", semantic)) || (!strcasecmp( "ProjectionInverse", semantic)) ) {
    return shader::smProjectionI;
  }
  else if ( (!strcasecmp( "WorldViewI", semantic)) || (!strcasecmp( "WorldViewInverse", semantic)) ) {
    return shader::smWorldViewI;
  }
  else if ( (!strcasecmp( "ViewProjectionI", semantic)) || (!strcasecmp( "ViewProjectionInverse", semantic)) ) {
    return shader::smViewProjectionI;
  }
  else if ( (!strcasecmp( "WorldViewProjectionI", semantic)) || (!strcasecmp( "WorldViewProjectionInverse", semantic)) ) {
    return shader::smWorldViewProjectionI;
  }
  else if ( (!strcasecmp( "WorldT", semantic)) || (!strcasecmp( "WorldTranspose", semantic)) ) {
    return shader::smWorldT;
  }
  else if ( (!strcasecmp( "ViewT", semantic)) || (!strcasecmp( "ViewTranspose", semantic)) ) {
    return shader::smViewT;
  }
  else if ( (!strcasecmp( "ProjectionT", semantic)) || (!strcasecmp( "ProjectionTranspose", semantic)) ) {
    return shader::smProjectionT;
  }
  else if ( (!strcasecmp( "WorldViewT", semantic)) || (!strcasecmp( "WorldViewTranspose", semantic)) ) {
    return shader::smWorldViewT;
  }
  else if ( (!strcasecmp( "ViewProjectionT", semantic)) || (!strcasecmp( "ViewProjectionTranspose", semantic)) ) {
    return shader::smViewProjectionT;
  }
  else if ( (!strcasecmp( "WorldViewProjectionT", semantic)) || (!strcasecmp( "WorldViewProjectionTranspose", semantic)) ) {
    return shader::smWorldViewProjectionT;
  }
  else if ( (!strcasecmp( "WorldIT", semantic)) || (!strcasecmp( "WorldInverseTranspose", semantic)) ) {
    return shader::smWorldIT;
  }
  else if ( (!strcasecmp( "ViewIT", semantic)) || (!strcasecmp( "ViewInverseTranspose", semantic)) ) {
    return shader::smViewIT;
  }
  else if ( (!strcasecmp( "ProjectionIT", semantic)) || (!strcasecmp( "ProjectionInverseTranspose", semantic)) ) {
    return shader::smProjectionIT;
  }
  else if ( (!strcasecmp( "WorldViewIT", semantic)) || (!strcasecmp( "WorldViewInverseTranspose", semantic)) ) {
    return shader::smWorldViewIT;
  }
  else if ( (!strcasecmp( "ViewProjectionIT", semantic)) || (!strcasecmp( "ViewProjectionInverseTranspose", semantic)) ) {
    return shader::smViewProjectionIT;
  }
  else if ( (!strcasecmp( "WorldViewProjectionIT", semantic)) || (!strcasecmp( "WorldViewProjectionInverseTranspose", semantic)) ) {
    return shader::smWorldViewProjectionIT;
  }
  else if (!strcasecmp( "ViewPosition", semantic)) {
    return smViewPosition;
  }
  else if (!strcasecmp( "Time", semantic)) {
    return smTime;
  }
  else if (!strcasecmp( "RenderTargetDimensions", semantic)) {
    return smViewportSize;
  }
  else if (!strcasecmp( "Ambient", semantic)) {
    return smAmbient;
  }
  else if (!strcasecmp( "Diffuse", semantic)) {
    return smDiffuse;
  }
  else if (!strcasecmp( "Emissive", semantic)) {
    return smEmissive;
  }
  else if (!strcasecmp( "Specular", semantic)) {
    return smSpecular;
  }
  else if (!strcasecmp( "Opacity", semantic)) {
    return smOpacity;
  }
  else if (!strcasecmp( "SpecularPower", semantic)) {
    return smSpecularPower;
  }
  else if (!strcasecmp( "Height", semantic)) {
    return smHeight;
  }
  else if (!strcasecmp( "Normal", semantic)) {
    return smNormal;
  }

  return shader::smUnknown;
}

//
//
//
void hlslFXShader::parseExpression( hlslFXShader::uniform &u, const char *exp) {
  //this function should call a real parser, until then only handle a subset of types

  for (int ii=0; ii<16; ii++)
    u.defaultVal[ii] = 0.0f;

  switch ( u.type) {
    case shader::dtInt:
      if ( 1 == sscanf( exp, " int ( %f )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " int1 ( %f )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " %f ", &u.defaultVal[0])) {
      }
      else {
        u.defaultVal[0] = 0.0f;
      }
      break;
    case shader::dtFloat:
      if ( 1 == sscanf( exp, " float ( %f )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " float1 ( %f )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " %f ", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " float ( %ff )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " float1 ( %ff )", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " %ff ", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " { %f } ", &u.defaultVal[0])) {
      }
      else if ( 1 == sscanf( exp, " { %ff } ", &u.defaultVal[0])) {
      }
      else {
        u.defaultVal[0] = 0.0f;
      }
      break;
    case shader::dtVec2:
      if ( 2 == sscanf( exp, " float2 ( %f , %f )", &u.defaultVal[0], &u.defaultVal[1])) {
      }
      else if ( 2 == sscanf( exp, " { %f , %f }", &u.defaultVal[0], &u.defaultVal[1])) {
      }
      else if ( 2 == sscanf( exp, " float2 ( %ff , %ff )", &u.defaultVal[0], &u.defaultVal[1])) {
      }
      else if ( 2 == sscanf( exp, " { %ff , %ff }", &u.defaultVal[0], &u.defaultVal[1])) {
      }
      else {
        u.defaultVal[0] = 0.0f;
        u.defaultVal[1] = 0.0f;
      }
      break;
    case shader::dtVec3:
      if ( 3 == sscanf( exp, " float3 ( %f , %f , %f )", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2])) {
      }
      else if ( 3 == sscanf( exp, " { %f , %f , %f }", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2])) {
      }
      else if ( 3 == sscanf( exp, " float3 ( %ff , %ff , %ff )", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2])) {
      }
      else if ( 3 == sscanf( exp, " { %ff , %ff , %ff }", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2])) {
      }
      else {
        u.defaultVal[0] = 0.0f;
        u.defaultVal[1] = 0.0f;
        u.defaultVal[2] = 0.0f;
      }
      break;
    case shader::dtVec4:
      if ( 4 == sscanf( exp, " float4 ( %f , %f , %f , %f )", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2], &u.defaultVal[3])) {
      }
      else if ( 4 == sscanf( exp, " float4 ( %ff , %ff , %ff , %ff )", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2], &u.defaultVal[3])) {
      }
      else if ( 4 == sscanf( exp, " { %f , %f , %f , %f }", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2], &u.defaultVal[3])) {
      }
      else if ( 4 == sscanf( exp, " { %ff , %ff , %ff , %ff }", &u.defaultVal[0], &u.defaultVal[1], &u.defaultVal[2], &u.defaultVal[3])) {
      }
      else {
        u.defaultVal[0] = 0.0f;
        u.defaultVal[1] = 0.0f;
        u.defaultVal[2] = 0.0f;
        u.defaultVal[3] = 0.0f;
      }
      break;
    default:
      //make gcc happy
      break;
  };
}

//
//
//
shader::SamplerType hlslFXShader::parseSamplerType( const char *type) {
  if (!strcmp( "sampler1D", type)) {
    return shader::st1D;
  }
  else if (!strcmp( "sampler2D", type)) {
    return shader::st2D;
  }
  else if (!strcmp( "sampler3D", type)) {
    return shader::st3D;
  }
  else if (!strcmp( "samplerCUBE", type)) {
    return shader::stCube;
  }

  //add sampler RECT stuff here

  return shader::stUnknown;
}

//
//
//
void hlslFXShader::updateHandles() {
  int offset = m_techniqueOffset[m_activeTechnique];

  for ( int jj=0; jj<m_passCount[m_activeTechnique]; jj++) {


    //now apply the information
    for (std::vector<uniform>::iterator it = m_uniformList.begin(); it < m_uniformList.end(); it++) {
      std::map< std::string, int>::const_iterator it2 = m_stateList[offset+jj]->m_vRegMap.find(it->name);
      if ( it2 != m_stateList[offset+jj]->m_vRegMap.end()) 
        it->vReg[jj] = it2->second;
      else
        it->vReg[jj] = -1;

      it2 = m_stateList[offset+jj]->m_fRegMap.find(it->name);
      if ( it2 != m_stateList[offset+jj]->m_fRegMap.end()) 
        it->fReg[jj] = it2->second;
      else
        it->fReg[jj] = -1;

      it->dirty = true;
    }

          {
    for (std::vector<sampler>::iterator it = m_samplerList.begin(); it < m_samplerList.end(); it++) {
      std::map< std::string, int>::const_iterator it2 = m_stateList[offset+jj]->m_fRegMap.find(it->name);

      if ( it2 != m_stateList[offset+jj]->m_fRegMap.end()) 
        it->texUnit[jj] = it2->second;
      else {
        it->texUnit[jj] = -1;
      }

      //this should only happen once per compile, we never remap samplers
      it->dirty = true;
    }
          }
/*
    //workaround for AshliFX bug    
    {
      
      for (std::vector<sampler>::iterator it = m_samplerList.begin(); it < m_samplerList.end(); it++) {
        const char *formals=m_ashliList[jj]->getFormals();
        formals = strstr( formals, "s ");
        int i0;
        char c0[64], c1[64], c2[64];
        if (formals) {
          while (true) {
            sscanf( formals, " s %d %s %s %s", &i0, c0, c1, c2);
            if ( c2 == it->name) {
              break;
            }
            formals++;
            formals = strstr( formals, "s ");
            if (formals == NULL) {
              i0 = -1;
              break;
            }
          }
        }

        it->texUnit[jj] = i0;

        //this should only happen once per compile, we never remap samplers
        it->dirty = true;
      }
    }
*/

    for (std::vector<attribute>::iterator it2 = m_attributeList.begin(); it2 < m_attributeList.end(); it2++) {
      //it->handle = glGetAttribLocation( m_program, it->name);
      //nothing to mark dirty
    }
  }
}

//
//
//
bool hlslFXShader::buildShaders() {

  //clean up any old shaders
  void deleteShaders();

  m_vShader.resize(m_passCount[m_activeTechnique], 0);
  m_fShader.resize(m_passCount[m_activeTechnique], 0);

  bool fail = false;

  int offset = m_techniqueOffset[m_activeTechnique];

  GL_CHECK;

  for (int ii=0; ii<m_passCount[m_activeTechnique]; ii++) {

    if ( m_vertexShaders[offset+ii].length() > 0) {
      //compile the vertex program
      const char *program = m_vertexShaders[offset+ii].c_str();
      //clear any the errors
      while ( glGetError() != GL_NO_ERROR) ;

      glGenProgramsARB( 1, &m_vShader[ii]);
      glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vShader[ii]);
      glProgramStringARB( GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(program), program);

      if (glGetError() != GL_NO_ERROR) {
        //program failed compile, get the info
        fail = true;
        const char* error = (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
        m_error += "Vertex shader failed compile\n  ";
        m_error += error;
        m_error += "\n";
      }
    }
    if ( m_fragmentShaders[offset+ii].length() > 0) {
      //compile the fragment program
      const char *program = m_fragmentShaders[offset+ii].c_str();
      //clear any the errors
      while ( glGetError() != GL_NO_ERROR) ;

      glGenProgramsARB( 1, &m_fShader[ii]);
      glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fShader[ii]);
      glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(program), program);

      if (glGetError() != GL_NO_ERROR) {
        //program failed compile, get the info
        fail = true;
        const char* error = (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
        m_error += "Fragment shader failed compile\n  ";
        m_error += error;
      }
    }
  }

  if (fail)
    return false;


  return true;
}

//
//
//
bool hlslFXShader::valid() {
  return m_valid;
}

//
//
//
int hlslFXShader::passCount() {
  if (m_techniqueCount)
    return m_passCount[m_activeTechnique];
  return 0;
}

//
//
//
int hlslFXShader::techniqueCount() {
  return m_techniqueCount;
}

//
//
//
const char* hlslFXShader::techniqueName( int n) {
  if ( n<m_techniqueCount)
    return m_techniqueNames[n].c_str();

  return NULL;
}

//
//
//
bool hlslFXShader::build() {

  //need to try to compile the shaders here if they don't exist yet

  if (m_stale) {
    m_stale = false;
    if (!buildShaders())
      return false;
    updateHandles();
  }

  return true;
}

//
//
//
void hlslFXShader::bind() {

  GL_CHECK;

  if (m_fShader[m_activePass]) {
    glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fShader[m_activePass]);
    glEnable( GL_FRAGMENT_PROGRAM_ARB);
  }

  if (m_vShader[m_activePass]) {
    glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vShader[m_activePass]);
    glEnable( GL_VERTEX_PROGRAM_ARB);
  }

  GL_CHECK;

  GLenum targets[] = { GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_1D, GL_TEXTURE_2D};

  //update dirty samplers
  for (std::vector<sampler>::iterator it2 = m_samplerList.begin(); it2<m_samplerList.end(); it2++) {
    if (it2->texUnit[m_activePass] >= 0) {
      glActiveTexture( GL_TEXTURE0_ARB + it2->texUnit[m_activePass]);
      glBindTexture( targets[it2->type], it2->texObject);
    }
  }
  glActiveTexture( GL_TEXTURE0_ARB);

  GL_CHECK;

  //set up the render states
  m_stateList[m_techniqueOffset[m_activeTechnique] + m_activePass]->setState();

  return;
}

//
//
//
void hlslFXShader::setShapeDependentState() {

  GL_CHECK;

  //update dirty values
  for (std::vector<uniform>::iterator it = m_uniformList.begin(); it<m_uniformList.end(); it++) {
    if ( it->dirty) {
      if (m_activePass == (m_passCount[m_activeTechnique]-1)) {
        //only mark it clean on the last pass
      it->dirty = false;
      }
      
      switch (it->type) {
        case shader::dtBool:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          break;
        case shader::dtBVec2:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          break;
        case shader::dtBVec3:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          break;
        case shader::dtBVec4:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal);
          break;
        case shader::dtInt:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          break;
        case shader::dtIVec2:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          break;
        case shader::dtIVec3:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          break;
        case shader::dtIVec4:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal);
          break;
        case shader::dtFloat:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[0], it->fVal[0], it->fVal[0]);
          break;
        case shader::dtVec2:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], 0.0f, 0.0f);
          break;
        case shader::dtVec3:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[1], it->fVal[2], 0.0f);
          break;
        case shader::dtVec4:
          if ( it->vReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal);
          if ( it->fReg[m_activePass] >= 0) 
            glProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal);
          break;
        case shader::dtMat2:
          if ( it->vReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[2], 0.0f, 0.0f);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+1, it->fVal[1], it->fVal[3], 0.0f, 0.0f);
          }
          if ( it->fReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[2], 0.0f, 0.0f);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+1, it->fVal[1], it->fVal[3], 0.0f, 0.0f);
          }
          break;
        case shader::dtMat3:
          if ( it->vReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[3], it->fVal[6], 0.0f);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+1, it->fVal[1], it->fVal[4], it->fVal[7], 0.0f);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+2, it->fVal[2], it->fVal[5], it->fVal[8], 0.0f);
          }
          if ( it->fReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[3], it->fVal[6], 0.0f);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+1, it->fVal[1], it->fVal[4], it->fVal[7], 0.0f);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+2, it->fVal[2], it->fVal[5], it->fVal[8], 0.0f);
          }
          break;
        case shader::dtMat4:
          if ( it->vReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass], it->fVal[0], it->fVal[4], it->fVal[8], it->fVal[12]);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+1, it->fVal[1], it->fVal[5], it->fVal[9], it->fVal[13]);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+2, it->fVal[2], it->fVal[6], it->fVal[10], it->fVal[14]);
            glProgramLocalParameter4fARB( GL_VERTEX_PROGRAM_ARB, it->vReg[m_activePass]+3, it->fVal[3], it->fVal[7], it->fVal[11], it->fVal[15]);
          }
          if ( it->fReg[m_activePass] >= 0) {
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass], it->fVal[0], it->fVal[4], it->fVal[8], it->fVal[12]);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+1, it->fVal[1], it->fVal[5], it->fVal[9], it->fVal[13]);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+2, it->fVal[2], it->fVal[6], it->fVal[10], it->fVal[14]);
            glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, it->fReg[m_activePass]+3, it->fVal[3], it->fVal[7], it->fVal[11], it->fVal[15]);
          }
          break;
        default:
          //make gcc happy
          break;
      };
      GL_CHECK;
      
    }
  }
  return;
}

//
//
//
void hlslFXShader::unbind() {
  glDisable( GL_FRAGMENT_PROGRAM_ARB);
  glDisable( GL_VERTEX_PROGRAM_ARB);
  GL_CHECK;
}

//
//
//
void hlslFXShader::setTechnique( int t) {
  if ( t != m_activeTechnique) {
    m_activeTechnique = t;
    m_stale = true;
  }
}

//
//
//
void hlslFXShader::setPass( int p) {
  m_activePass = p;
}

//
//
//
int hlslFXShader::uniformCount() {
  return (int)m_uniformList.size();
}

//
//
//
int hlslFXShader::samplerCount() {
  return (int)m_samplerList.size();
}

//
//
//
int hlslFXShader::attributeCount() {
  return (int)m_attributeList.size();
}

//
//
//
const char* hlslFXShader::uniformName(int i) {
  //should check for array bounds
  return m_uniformList[i].name.c_str();
}

//
//
//
shader::DataType hlslFXShader::uniformType(int i) {
  //should check for array bounds
  return m_uniformList[i].type;
}

//
//
//
shader::Semantic hlslFXShader::uniformSemantic(int i) {
  //might want to check array bounds
  return m_uniformList[i].usage;
}

//
//
//
float* hlslFXShader::uniformDefault(int i) {
  //might want to check array bounds
  return m_uniformList[i].defaultVal;
}

//
//
//
const char* hlslFXShader::samplerName(int i) {
  //should check for array bounds
  return m_samplerList[i].name.c_str();
}

//
//
//
shader::SamplerType hlslFXShader::samplerType(int i) {
  //should check for array bounds
  return m_samplerList[i].type;
}

//
//
//
const char* hlslFXShader::attributeName(int i) {
  //should check for array bounds
  return m_attributeList[i].name.c_str();
}

//
//
//
shader::DataType hlslFXShader::attributeType(int i) {
  return m_attributeList[i].type;
}

//
//
//
void hlslFXShader::updateUniformBool( int i, bool val) {
  m_uniformList[i].fVal[0] = val ? 1.0f : 0.0f;
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformInt( int i, int val) {
  m_uniformList[i].fVal[0] = (float)val;
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformFloat( int i, float val) {
  m_uniformList[i].fVal[0] = val;
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformBVec( int i, const bool* val) {
  for (int ii=0; ii<size(m_uniformList[i].type); ii++) {
    m_uniformList[i].fVal[ii] = val[ii] ? 0.0f : 1.0f;
  }
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformIVec( int i, const int* val) {
  for (int ii=0; ii<size(m_uniformList[i].type); ii++) {
    m_uniformList[i].fVal[ii] = (float)val[ii];
  }
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformVec( int i, const float* val) {
  for (int ii=0; ii<size(m_uniformList[i].type); ii++) {
    m_uniformList[i].fVal[ii] = val[ii];
  }
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformMat( int i, const float* val) {
  for (int ii=0; ii<size(m_uniformList[i].type); ii++) {
    m_uniformList[i].fVal[ii] = val[ii];
  }
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateUniformMat( int i, const double* val) {
  for (int ii=0; ii<size(m_uniformList[i].type); ii++) {
    m_uniformList[i].fVal[ii] = (float)val[ii];
  }
  m_uniformList[i].dirty = true;
}

//
//
//
void hlslFXShader::updateSampler( int i, unsigned int val) {
  m_samplerList[i].texObject = val;
  //m_samplerList[i].dirty = true;
}

//
//
//
bool hlslFXShader::usesColor() {
  return m_color;
}

//
//
//
bool hlslFXShader::usesNormal() {
  return m_normal;
}

//
//
//
bool hlslFXShader::usesTexCoord( int set) {
  return ((m_texMask>>set) & 0x1) == 1;
}

//
//
//
bool hlslFXShader::usesTangent() {
  return m_tangent;
}

//
//
//
bool hlslFXShader::usesBinormal() {
  return m_binormal;
}

//
//
//
int hlslFXShader::tangentSlot() {
  return m_tangentSlot;
}

//
//
//
int hlslFXShader::binormalSlot() {
  return m_binormalSlot;
}

//
//
//
const char* hlslFXShader::errorString() {
  return m_error.c_str();
}

//
//
//
const char* hlslFXShader::getVertexShader( int pass) {
  if (m_activeTechnique < m_techniqueCount) {
    if ( pass < m_passCount[m_activeTechnique]) {
      return m_orgVertexShaders[m_techniqueOffset[m_activeTechnique]+pass].c_str();
    }
  }

  return NULL;
}

//
//
//
const char* hlslFXShader::getPixelShader( int pass) {
  if (m_activeTechnique < m_techniqueCount) {
    if ( pass < m_passCount[m_activeTechnique]) {
      return m_orgFragmentShaders[m_techniqueOffset[m_activeTechnique]+pass].c_str();
    }
  }

  return NULL;
}


Autodesk® Maya® 2011 © 1997-2010 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6