#ifndef CGFXSHADER_VERSION
#define CGFXSHADER_VERSION "4.4"
#endif
#include "cgfxShaderNode.h"
#include "cgfxFindImage.h"
#include <maya/MDagPath.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MEventMessage.h>
#include <maya/MFloatVector.h>
#include <maya/MFnMesh.h>
#include <maya/MFnStringArrayData.h>
#include <maya/MFnStringData.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MDGModifier.h>
#include <maya/MFileIO.h>
#include <maya/MNodeMessage.h>
#include <maya/MFileObject.h>
#if defined(_SWATCH_RENDERING_SUPPORTED_)
#include <maya/MHardwareRenderer.h>
#include <maya/MGeometryData.h>
#include <maya/MHWShaderSwatchGenerator.h>
#endif
#include <maya/MImage.h>
#include "nv_dds.h"
#ifdef _WIN32
#else
# include <sys/timeb.h>
# include <string.h>
#
# define stricmp strcasecmp
# define strnicmp strncasecmp
#endif
PFNGLCLIENTACTIVETEXTUREARBPROC glStateCache::glClientActiveTexture = 0;
PFNGLVERTEXATTRIBPOINTERARBPROC glStateCache::glVertexAttribPointer = 0;
PFNGLENABLEVERTEXATTRIBARRAYARBPROC glStateCache::glEnableVertexAttribArray = 0;
PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glStateCache::glDisableVertexAttribArray = 0;
PFNGLVERTEXATTRIB4FARBPROC glStateCache::glVertexAttrib4f = 0;
PFNGLSECONDARYCOLORPOINTEREXTPROC glStateCache::glSecondaryColorPointer = 0;
PFNGLSECONDARYCOLOR3FEXTPROC glStateCache::glSecondaryColor3f = 0;
PFNGLMULTITEXCOORD4FARBPROC glStateCache::glMultiTexCoord4fARB = 0;
int glStateCache::sMaxTextureUnits = 0;
glStateCache::glStateCache()
{
reset();
}
glStateCache glStateCache::gInstance;
void glStateCache::activeTexture( int i)
{
if( i != fActiveTextureUnit)
{
fActiveTextureUnit = i;
if( glStateCache::glClientActiveTexture)
glStateCache::glClientActiveTexture( GL_TEXTURE0_ARB + i );
}
}
void glStateCache::enableVertexAttrib( int i)
{
if( !(fEnabledRegisters & (1 << (glRegister::kVertexAttrib + i))))
{
if( glStateCache::glEnableVertexAttribArray)
glStateCache::glEnableVertexAttribArray( i);
fEnabledRegisters |= (1 << (glRegister::kVertexAttrib + i));
}
fRequiredRegisters |= (1 << (glRegister::kVertexAttrib + i));
}
void glStateCache::flushState()
{
long redundantRegisters = fEnabledRegisters & ~fRequiredRegisters;
if( redundantRegisters & (1 << glRegister::kPosition))
glDisableClientState(GL_VERTEX_ARRAY);
if( redundantRegisters & (1 << glRegister::kNormal))
glDisableClientState(GL_NORMAL_ARRAY);
if( redundantRegisters & (1 << glRegister::kColor))
glDisableClientState(GL_COLOR_ARRAY);
if( redundantRegisters & (1 << glRegister::kSecondaryColor))
glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
for( int i = glRegister::kTexCoord; i <= glRegister::kLastTexCoord; i++)
{
if( redundantRegisters & (1 << i))
{
activeTexture( i - glRegister::kTexCoord);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
for( int i = glRegister::kVertexAttrib; i <= glRegister::kLastVertexAttrib; i++)
{
if( redundantRegisters & (1 << i))
{
if( glStateCache::glDisableVertexAttribArray)
glStateCache::glDisableVertexAttribArray( i - glRegister::kVertexAttrib);
}
}
fEnabledRegisters = fRequiredRegisters;
fRequiredRegisters = 0;
}
#ifdef _WIN32
MTypeId cgfxShaderNode::sId( 4084862000 );
#else
MTypeId cgfxShaderNode::sId( 0xF37A0C30 );
#endif
CGcontext cgfxShaderNode::sCgContext;
MObject cgfxShaderNode::sShader;
MObject cgfxShaderNode::sTechnique;
MObject cgfxShaderNode::sAttributeList;
MObject cgfxShaderNode::sVertexAttributeList;
MObject cgfxShaderNode::sVertexAttributeSource;
MObject cgfxShaderNode::sTexCoordSource;
MObject cgfxShaderNode::sColorSource;
MObject cgfxShaderNode::sTexturesByName;
enum ETexCoord
{
etcNull = -1,
etcConstant = -2,
etcNormal = -3,
etcTangent = -4,
etcBinormal = -5,
etcDataSet = -6,
};
cgfxShaderNode::cgfxShaderNode()
: fEffect(0)
, fAttrDefList(0)
, fVertexAttributes( NULL)
#ifdef TEXTURES_BY_NAME
, fTexturesByName( true )
#else
, fTexturesByName( false )
#endif
, fNormalsPerVertex( 3 )
, fConstructed(false)
, fErrorCount( 0 )
, fErrorLimit( 8 )
, fTechniqueHasBlending( false )
, fShaderFxFile()
, fShaderFxFileChanged( false )
{
MStringArray sa;
sa.append( "map1" );
sa.append( "tangent" );
sa.append( "binormal" );
MStringArray sa2;
sa2.append( "colorSet1" );
setDataSources( &sa, &sa2 );
}
void
cgfxShaderNode::postConstructor()
{
fConstructed = true;
}
cgfxShaderNode::~cgfxShaderNode()
{
#ifdef KH_DEBUG
MString ss = " .. ~node ";
if ( fConstructed )
{
MFnDependencyNode fnNode( thisMObject() );
ss += fnNode.name();
}
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
MMessage::removeCallbacks( fCallbackIds );
fCallbackIds.clear();
if (fAttrDefList)
{
fAttrDefList->release();
fAttrDefList = 0;
}
if (fEffect)
{
cgDestroyEffect(fEffect);
fEffect = 0;
}
}
MStatus cgfxShaderNode::compute( const MPlug& plug, MDataBlock& data )
{
MStatus returnStatus;
if ((plug == outColor) || (plug.parent() == outColor))
{
MFloatVector color(.07f, .8f, .07f);
MDataHandle outputHandle = data.outputValue( outColor );
outputHandle.asFloatVector() = color;
outputHandle.setClean();
return MS::kSuccess;
}
return MS::kUnknownParameter;
}
void* cgfxShaderNode::creator()
{
return new cgfxShaderNode();
}
MStatus
cgfxShaderNode::initialize()
{
MStatus ms;
try
{
initializeNodeAttrs();
}
catch ( cgfxShaderCommon::InternalError* e )
{
size_t ee = (size_t)e;
MString es = "cgfxShaderNode internal error ";
es += (int)ee;
MGlobal::displayError( es );
ms = MS::kFailure;
}
catch ( ... )
{
MString es = "cgfxShaderNode internal error: Unhandled exception in initialize";
MGlobal::displayError( es );
ms = MS::kFailure;
}
return ms;
}
void
cgfxShaderNode::initializeNodeAttrs()
{
MFnTypedAttribute typedAttr;
MFnNumericAttribute numericAttr;
MFnStringData stringData;
MFnStringArrayData stringArrayData;
MStatus stat, stat2;
sShader = typedAttr.create("shader", "s", MFnData::kString, stringData.create(&stat2), &stat);
M_CHECK( stat2 );
M_CHECK( stat );
stat = typedAttr.setKeyable(true);
M_CHECK( stat );
stat = typedAttr.setInternal(true);
M_CHECK( stat );
stat = addAttribute(sShader);
M_CHECK( stat );
sTechnique = typedAttr.create("technique", "t", MFnData::kString,
stringData.create(&stat2), &stat);
M_CHECK( stat2 );
M_CHECK( stat );
typedAttr.setInternal(true);
typedAttr.setKeyable(true);
stat = addAttribute(sTechnique);
M_CHECK( stat );
sAttributeList = typedAttr.create("attributeList", "al", MFnData::kStringArray,
stringArrayData.create(&stat2), &stat);
M_CHECK( stat2 );
M_CHECK( stat );
stat = typedAttr.setKeyable(false);
M_CHECK( stat );
stat = typedAttr.setConnectable(false);
M_CHECK( stat );
stat = typedAttr.setArray(false);
M_CHECK( stat );
stat = typedAttr.setInternal(true);
M_CHECK( stat );
stat = typedAttr.setHidden(true);
M_CHECK( stat );
stat = addAttribute(sAttributeList);
M_CHECK( stat );
sVertexAttributeList = typedAttr.create("vertexAttributeList", "val", MFnData::kStringArray,
stringArrayData.create(&stat2), &stat);
M_CHECK( stat2 );
M_CHECK( stat );
stat = typedAttr.setKeyable(false);
M_CHECK( stat );
stat = typedAttr.setConnectable(false);
M_CHECK( stat );
stat = typedAttr.setArray(false);
M_CHECK( stat );
stat = typedAttr.setInternal(true);
M_CHECK( stat );
stat = typedAttr.setHidden(true);
M_CHECK( stat );
stat = addAttribute(sVertexAttributeList);
M_CHECK( stat );
sVertexAttributeSource = typedAttr.create( "vertexAttributeSource", "vas", MFnData::kStringArray,
MObject::kNullObj, &stat );
M_CHECK( stat );
stat = typedAttr.setInternal( true );
M_CHECK( stat );
stat = addAttribute( sVertexAttributeSource );
M_CHECK( stat );
sTexCoordSource = typedAttr.create( "texCoordSource", "tcs", MFnData::kStringArray,
MObject::kNullObj, &stat );
M_CHECK( stat );
stat = typedAttr.setInternal( true );
M_CHECK( stat );
stat = addAttribute( sTexCoordSource );
M_CHECK( stat );
sColorSource = typedAttr.create( "colorSource", "cs", MFnData::kStringArray,
MObject::kNullObj, &stat );
M_CHECK( stat );
stat = typedAttr.setInternal( true );
M_CHECK( stat );
stat = addAttribute( sColorSource );
M_CHECK( stat );
sTexturesByName = numericAttr.create( "texturesByName", "tbn", MFnNumericData::kBoolean,
0, &stat );
M_CHECK( stat );
stat = numericAttr.setInternal(true);
M_CHECK( stat );
stat = numericAttr.setHidden(true);
M_CHECK( stat );
numericAttr.setKeyable(false);
stat = addAttribute( sTexturesByName );
M_CHECK( stat );
}
void
cgfxShaderNode::copyInternalData( MPxNode* pSrc )
{
const cgfxShaderNode& src = *(cgfxShaderNode*)pSrc;
setTexturesByName( src.getTexturesByName() );
setShaderFxFile( src.shaderFxFile() );
setShaderFxFileChanged( true );
setTechnique( src.getTechnique() );
setDataSources( &src.getTexCoordSource(), &src.getColorSource() );
MString fileName = cgfxFindFile(shaderFxFile());
bool hasFile = (fileName.asChar() != NULL) && strcmp(fileName.asChar(), "");
if ( hasFile )
{
MStringArray fileOptions;
cgfxGetFxIncludePath( fileName, fileOptions );
const char *opts[_CGFX_PLUGIN_MAX_COMPILER_ARGS_];
unsigned int numOpts = fileOptions.length();
if (numOpts)
{
numOpts = (numOpts > _CGFX_PLUGIN_MAX_COMPILER_ARGS_) ? _CGFX_PLUGIN_MAX_COMPILER_ARGS_ : numOpts;
for (unsigned int i=0; i<numOpts; i++)
opts[i] = fileOptions[i].asChar();
opts[numOpts] = NULL;
}
CGeffect cgEffect = cgCreateEffectFromFile(sCgContext, fileName.asChar(), opts);
if (cgEffect)
{
cgfxAttrDefList* effectList = NULL;
MStringArray attributeList;
MDGModifier dagMod;
cgfxAttrDef::updateNode(cgEffect, this, &dagMod, effectList, attributeList);
MStatus status = dagMod.doIt();
assert(status == MS::kSuccess);
setAttrDefList(effectList);
setAttributeList(attributeList);
setEffect(cgEffect);
if( effectList )
effectList->release();
}
}
}
bool cgfxShaderNode::setInternalValueInContext( const MPlug& plug,
const MDataHandle& handle,
MDGContext&)
{
bool retVal = true;
try
{
#ifdef KH_DEBUG
MString ss = " .. seti ";
ss += plug.partialName( true, true, true, false, false, true );
if (plug == sShader ||
plug == sTechnique)
{
ss += " \"";
ss += handle.asString();
ss += "\"";
}
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
if (plug == sShader)
{
setShaderFxFile(handle.asString());
}
else if (plug == sTechnique)
{
setTechnique(handle.asString());
}
else if (plug == sAttributeList)
{
MDataHandle nonConstHandle(handle);
MObject saData = nonConstHandle.data();
MFnStringArrayData fnSaData(saData);
setAttributeList(fnSaData.array());
}
else if (plug == sVertexAttributeList)
{
MDataHandle nonConstHandle(handle);
MObject saData = nonConstHandle.data();
MFnStringArrayData fnSaData(saData);
const MStringArray& attributeList = fnSaData.array();
cgfxVertexAttribute* attributes = NULL;
cgfxVertexAttribute** nextAttribute = &attributes;
int numAttributes = attributeList.length() / 4;
for( int i = 0; i < numAttributes; i++)
{
cgfxVertexAttribute* attribute = new cgfxVertexAttribute();
attribute->fName = attributeList[ i * 4 + 0];
attribute->fType = attributeList[ i * 4 + 1];
attribute->fUIName = attributeList[ i * 4 + 2];
attribute->fSemantic = attributeList[ i * 4 + 3];
*nextAttribute = attribute;
nextAttribute = &attribute->fNext;
}
setVertexAttributes( attributes);
}
else if ( plug == sVertexAttributeSource )
{
MDataHandle nonConstHandle( handle );
MObject saData = nonConstHandle.data();
MFnStringArrayData fnSaData( saData );
MStringArray values = fnSaData.array();
setVertexAttributeSource( values);
}
else if ( plug == sTexCoordSource )
{
MDataHandle nonConstHandle( handle );
MObject saData = nonConstHandle.data();
MFnStringArrayData fnSaData( saData );
MStringArray values = fnSaData.array();
setDataSources( &values, NULL );
}
else if ( plug == sColorSource )
{
MDataHandle nonConstHandle( handle );
MObject saData = nonConstHandle.data();
MFnStringArrayData fnSaData( saData );
MStringArray values = fnSaData.array();
setDataSources( NULL, &values );
}
else if ( plug == sTexturesByName )
{
setTexturesByName( handle.asBool(), !MFileIO::isReadingFile());
}
else
{
retVal = MPxHwShaderNode::setInternalValue(plug, handle);
}
}
catch ( cgfxShaderCommon::InternalError* e )
{
reportInternalError( __FILE__, (size_t)e );
retVal = false;
}
catch ( ... )
{
reportInternalError( __FILE__, __LINE__ );
retVal = false;
}
return retVal;
}
bool cgfxShaderNode::getInternalValueInContext( const MPlug& plug,
MDataHandle& handle,
MDGContext&)
{
bool retVal = true;
try
{
#ifdef KH_DEBUG
MString ss = " .. geti ";
ss += plug.partialName( true, true, true, false, false, true );
if ( plug == sShader )
ss += " \"" + fShaderFxFile + "\"";
else if (plug == sTechnique)
ss += " \"" + fTechnique + "\"";
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
if (plug == sShader)
{
handle.set(fShaderFxFile);
}
else if (plug == sTechnique)
{
handle.set(fTechnique);
}
else if (plug == sAttributeList)
{
MFnStringArrayData saData;
handle.set(saData.create(fAttributeListArray));
}
else if (plug == sVertexAttributeList)
{
MStringArray attributeList;
cgfxVertexAttribute* attribute = fVertexAttributes;
while( attribute)
{
attributeList.append( attribute->fName);
attributeList.append( attribute->fType);
attributeList.append( attribute->fUIName);
attributeList.append( attribute->fSemantic);
attribute = attribute->fNext;
}
MFnStringArrayData saData;
handle.set(saData.create( attributeList));
}
else if ( plug == sVertexAttributeSource )
{
MStringArray attributeSources;
cgfxVertexAttribute* attribute = fVertexAttributes;
while( attribute)
{
attributeSources.append( attribute->fSourceName);
attribute = attribute->fNext;
}
MFnStringArrayData saData;
handle.set( saData.create( attributeSources ) );
}
else if ( plug == sTexCoordSource )
{
MFnStringArrayData saData;
handle.set( saData.create( fTexCoordSource ) );
}
else if ( plug == sColorSource )
{
MFnStringArrayData saData;
handle.set( saData.create( fColorSource ) );
}
else if (plug == sTexturesByName)
{
handle.set(fTexturesByName);
}
else
{
retVal = MPxHwShaderNode::getInternalValue(plug, handle);
}
}
catch ( cgfxShaderCommon::InternalError* e )
{
reportInternalError( __FILE__, (size_t)e );
retVal = false;
}
catch ( ... )
{
reportInternalError( __FILE__, __LINE__ );
retVal = false;
}
return retVal;
}
static void checkGlErrors(const char* msg)
{
#if defined(CGFX_DEBUG)
#define MYERR(n) case n: OutputDebugStrings(" ", #n); break
GLenum err;
bool errors = false;
while ((err = glGetError()) != GL_NO_ERROR)
{
if (!errors)
{
OutputDebugStrings("OpenGl errors: ", msg);
}
errors = true;
switch (err)
{
MYERR(GL_INVALID_ENUM);
MYERR(GL_INVALID_VALUE);
MYERR(GL_INVALID_OPERATION);
MYERR(GL_STACK_OVERFLOW);
MYERR(GL_STACK_UNDERFLOW);
MYERR(GL_OUT_OF_MEMORY);
default:
{
char tmp[32];
sprintf(tmp, "%d", err);
OutputDebugStrings(" GL Error #", tmp);
}
}
}
#undef MYERR
#endif
}
void textureChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* aDef)
{
((cgfxAttrDef*)aDef)->releaseCallback();
}
#if defined(_SWATCH_RENDERING_SUPPORTED_)
MStatus cgfxShaderNode::renderSwatchImage( MImage & outImage )
{
MStatus status = MStatus::kFailure;
if( sCgContext == 0 ) return status;
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (pRenderer)
{
const MString& backEndStr = pRenderer->backEndString();
unsigned int* pIndexing = 0;
unsigned int numberOfData = 0;
unsigned int indexCount = 0;
MHardwareRenderer::GeometricShape gshape = MHardwareRenderer::kDefaultSphere;
MGeometryData* pGeomData =
pRenderer->referenceDefaultGeometry( gshape, numberOfData, pIndexing, indexCount );
if( !pGeomData )
{
return MStatus::kFailure;
}
unsigned int width, height;
outImage.getSize( width, height );
unsigned int origWidth = width;
unsigned int origHeight = height;
MStatus status2 = pRenderer->makeSwatchContextCurrent( backEndStr, width, height );
if( status2 != MS::kSuccess )
{
pRenderer->dereferenceGeometry( pGeomData, numberOfData );
}
{
float light_pos[4];
pRenderer->getSwatchLightDirection( light_pos[0], light_pos[1], light_pos[2], light_pos[3] );
}
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double l, r, b, t, n, f;
pRenderer->getSwatchPerspectiveCameraSetting( l, r, b, t, n, f );
glFrustum( l, r, b, t, n, f );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float x, y, z, w;
pRenderer->getSwatchPerspectiveCameraTranslation( x, y, z, w );
glTranslatef( x, y, z );
}
float r, g, b, a;
MHWShaderSwatchGenerator::getSwatchBackgroundColor( r, g, b, a );
glClearColor( r, g, b, a );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
MDagPath dummyPath;
glBind( dummyPath );
float *vertexData = (float *)( pGeomData[0].data() );
float *normalData = (float *)( pGeomData[1].data() );
float *uvData = (float *)( pGeomData[2].data() );
float *tangentData = (float *)( pGeomData[3].data() );
float *binormalData = (float *)( pGeomData[4].data() );
int uvCount = fTexCoordSource.length();
float ** texCoordArrays = uvCount ? new float * [ uvCount] : NULL;
for( int uv = 0; uv < uvCount; uv++)
{
texCoordArrays[ uv] = uvData;
}
int normalCount = uvCount > 0 ? uvCount : 1;
float ** normalArrays = new float * [ fNormalsPerVertex * normalCount];
for( int n = 0; n < normalCount; n++)
{
if( fNormalsPerVertex > 0)
{
normalArrays[ n * fNormalsPerVertex + 0] = normalData;
if( fNormalsPerVertex > 1)
{
normalArrays[ n * fNormalsPerVertex + 1] = tangentData;
if( fNormalsPerVertex > 2)
{
normalArrays[ n * fNormalsPerVertex + 2] = binormalData;
}
}
}
}
glGeometry( dummyPath,
GL_TRIANGLES,
false,
indexCount,
pIndexing,
pGeomData[0].elementCount(),
NULL,
vertexData,
fNormalsPerVertex,
(const float **) normalArrays,
0,
NULL,
uvCount,
(const float **) texCoordArrays);
glUnbind( dummyPath );
if( normalArrays) delete[] normalArrays;
if( texCoordArrays) delete[] texCoordArrays;
pRenderer->readSwatchContextPixels( backEndStr, outImage );
outImage.getSize( width, height );
if (width != origWidth || height != origHeight)
{
status = MStatus::kFailure;
}
else
{
status = MStatus::kSuccess;
}
}
return status;
}
#endif
bool cgfxShaderNode::supportsBatching() const
{
return true;
}
bool cgfxShaderNode::invertTexCoords() const
{
return true;
}
bool cgfxShaderNode::createEffect()
{
bool rc = false;
if (shaderFxFileChanged())
{
MString fileName = cgfxFindFile(shaderFxFile());
if(fileName.asChar() != NULL && strcmp(fileName.asChar(), ""))
{
MStringArray fileOptions;
cgfxGetFxIncludePath( fileName, fileOptions );
const char *opts[_CGFX_PLUGIN_MAX_COMPILER_ARGS_];
unsigned int numOpts = fileOptions.length();
if (numOpts)
{
numOpts = (numOpts > _CGFX_PLUGIN_MAX_COMPILER_ARGS_) ? _CGFX_PLUGIN_MAX_COMPILER_ARGS_ : numOpts;
for (unsigned int i=0; i<numOpts; i++)
opts[i] = fileOptions[i].asChar();
opts[numOpts] = NULL;
}
CGeffect cgEffect = cgCreateEffectFromFile(sCgContext, fileName.asChar(), opts);
if (cgEffect)
{
cgfxAttrDefList* effectList = NULL;
MStringArray attributeList;
MDGModifier dagMod;
cgfxAttrDef::updateNode(cgEffect, this, &dagMod, effectList, attributeList);
MStatus status = dagMod.doIt();
assert(status == MS::kSuccess);
setAttrDefList(effectList);
setAttributeList(attributeList);
setEffect(cgEffect);
setTechnique( fTechnique);
rc = true;
if( effectList )
effectList->release();
}
}
setShaderFxFileChanged( false );
}
return rc;
}
MStatus cgfxShaderNode::glBind(const MDagPath& shapePath)
{
glStateCache::instance().reset();
MStatus stat;
#ifdef KH_DEBUG
MString ss = " .. bind ";
if ( this && fConstructed )
ss += name();
ss += " ";
ss += request.multiPath().fullPathName();
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
try
{
if ( glStateCache::sMaxTextureUnits <= 0 )
{
#ifdef _WIN32
#define RESOLVE_GL_EXTENSION( fn, ext) wglGetProcAddress( #fn #ext)
#elif defined LINUX
#define RESOLVE_GL_EXTENSION( fn, ext) &fn ## ext
#else
#define RESOLVE_GL_EXTENSION( fn, ext) &fn
#endif
glStateCache::glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC) RESOLVE_GL_EXTENSION( glClientActiveTexture, ARB);
glStateCache::glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERARBPROC) RESOLVE_GL_EXTENSION( glVertexAttribPointer, ARB);
glStateCache::glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) RESOLVE_GL_EXTENSION( glEnableVertexAttribArray, ARB);
glStateCache::glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) RESOLVE_GL_EXTENSION( glDisableVertexAttribArray, ARB);
glStateCache::glVertexAttrib4f = (PFNGLVERTEXATTRIB4FARBPROC) RESOLVE_GL_EXTENSION( glVertexAttrib4f, ARB);
glStateCache::glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTEREXTPROC) RESOLVE_GL_EXTENSION( glSecondaryColorPointer, EXT);
glStateCache::glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FEXTPROC) RESOLVE_GL_EXTENSION( glSecondaryColor3f, EXT);
glStateCache::glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) RESOLVE_GL_EXTENSION( glMultiTexCoord4f, ARB);
GLint tval;
glGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &tval );
GLint mic = 0;
glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &mic );
if (mic < tval)
tval = mic;
glStateCache::sMaxTextureUnits = tval;
if (!glStateCache::glClientActiveTexture || glStateCache::sMaxTextureUnits < 1)
glStateCache::sMaxTextureUnits = 1;
else if (glStateCache::sMaxTextureUnits > CGFXSHADERNODE_GL_TEXTURE_MAX)
glStateCache::sMaxTextureUnits = CGFXSHADERNODE_GL_TEXTURE_MAX;
}
if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
{
bindAttrValues();
if (fTechniqueHasBlending)
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glGetBooleanv( GL_DEPTH_TEST, &fDepthEnableState);
glGetIntegerv( GL_DEPTH_FUNC, &fDepthFunc);
glGetIntegerv( GL_BLEND_SRC, &fBlendSourceFactor);
glGetIntegerv( GL_BLEND_DST, &fBlendDestFactor);
glDepthFunc(GL_LEQUAL);
if( !fNewEffect.fTechnique->fMultiPass && fNewEffect.fTechnique->fPasses)
cgSetPassState( fNewEffect.fTechnique->fPasses->fPass);
}
else
{
glPushAttrib( GL_LIGHTING);
static float diffuse_color[4] = {1.0, 0.5, 0.5, 1.0};
static float specular_color[4] = {1.0, 1.0, 1.0, 1.0};
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor4fv(diffuse_color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 100.0);
}
checkGlErrors("cgfxShaderNode::glBind");
}
catch ( cgfxShaderCommon::InternalError* e )
{
reportInternalError( __FILE__, (size_t)e );
stat = MS::kFailure;
}
catch ( ... )
{
reportInternalError( __FILE__, __LINE__ );
stat = MS::kFailure;
}
return stat;
}
static bool textureInitPowerOfTwo(unsigned int val, unsigned int & retval)
{
unsigned int res = 0;
if (val)
{
val <<= 1;
unsigned int low = 3;
res = 1;
while (val > low)
{
low <<= 1;
res <<= 1;
}
}
retval = res;
return (res == (val>>1)) ? 1 : 0;
}
void cgfxShaderNode::bindAttrValues()
{
if ( !fEffect || !fTechnique.length() )
return;
MStatus status;
MObject oNode = thisMObject();
for ( cgfxAttrDefList::iterator it( fAttrDefList ); it; ++it )
{
cgfxAttrDef* aDef = *it;
try
{
switch (aDef->fType)
{
case cgfxAttrDef::kAttrTypeBool:
{
bool tmp;
aDef->getValue(oNode, tmp);
cgSetParameter1i(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeInt:
{
int tmp;
aDef->getValue(oNode, tmp);
cgSetParameter1i(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeFloat:
{
float tmp;
aDef->getValue(oNode, tmp);
cgSetParameter1f(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeString:
{
MString tmp;
aDef->getValue(oNode, tmp);
cgSetStringParameterValue(aDef->fParameterHandle, tmp.asChar());
break;
}
case cgfxAttrDef::kAttrTypeVector2:
{
float tmp[2];
aDef->getValue(oNode, tmp[0], tmp[1]);
cgSetParameter2fv(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeVector3:
case cgfxAttrDef::kAttrTypeColor3:
{
float tmp[3];
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
cgSetParameter3fv(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeVector4:
case cgfxAttrDef::kAttrTypeColor4:
{
float tmp[4];
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
cgSetParameter4fv(aDef->fParameterHandle, tmp);
break;
}
case cgfxAttrDef::kAttrTypeWorldDir:
case cgfxAttrDef::kAttrTypeWorldPos:
{
float tmp[4];
if (aDef->fSize == 3)
{
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
tmp[3] = 1.0;
}
else
{
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
}
int base = cgfxAttrDef::kAttrTypeFirstPos;
if (aDef->fType <= cgfxAttrDef::kAttrTypeLastDir)
base = cgfxAttrDef::kAttrTypeFirstDir;
int space = aDef->fType - base;
MMatrix mat;
switch (space)
{
case 1: break;
}
if (base == cgfxAttrDef::kAttrTypeFirstPos)
{
MPoint point(tmp[0], tmp[1], tmp[2], tmp[3]);
point *= mat;
tmp[0] = (float)point.x;
tmp[1] = (float)point.y;
tmp[2] = (float)point.z;
tmp[3] = (float)point.w;
}
else
{
MVector vec(tmp[0], tmp[1], tmp[2]);
vec *= mat;
tmp[0] = (float)vec.x;
tmp[1] = (float)vec.y;
tmp[2] = (float)vec.z;
tmp[3] = 1.F;
}
cgSetParameterValuefr(aDef->fParameterHandle, aDef->fSize, tmp);
break;
}
case cgfxAttrDef::kAttrTypeMatrix:
{
MMatrix tmp;
float tmp2[4][4];
aDef->getValue(oNode, tmp);
if (aDef->fInvertMatrix)
{
tmp = tmp.inverse();
}
if (!aDef->fTransposeMatrix)
{
tmp = tmp.transpose();
}
tmp.get(tmp2);
cgSetMatrixParameterfr(aDef->fParameterHandle, &tmp2[0][0]);
break;
}
case cgfxAttrDef::kAttrTypeColor1DTexture:
case cgfxAttrDef::kAttrTypeColor2DTexture:
case cgfxAttrDef::kAttrTypeColor3DTexture:
case cgfxAttrDef::kAttrTypeColor2DRectTexture:
case cgfxAttrDef::kAttrTypeNormalTexture:
case cgfxAttrDef::kAttrTypeBumpTexture:
case cgfxAttrDef::kAttrTypeCubeTexture:
case cgfxAttrDef::kAttrTypeEnvTexture:
case cgfxAttrDef::kAttrTypeNormalizationTexture:
{
MString tmp;
MObject textureNode = MObject::kNullObj;
if( fTexturesByName)
{
aDef->getValue(oNode, tmp);
}
else
{
MPlug srcPlug;
aDef->getSource(oNode, srcPlug);
MObject srcNode = srcPlug.node();
if( srcNode != MObject::kNullObj)
{
MStatus rc;
MFnDependencyNode dgFn( srcNode);
MPlug filenamePlug = dgFn.findPlug( "fileTextureName", &rc);
if( rc == MStatus::kSuccess)
{
filenamePlug.getValue( tmp);
textureNode = filenamePlug.node(&rc);
}
if( aDef->fTextureMonitor == kNullCallback && textureNode != MObject::kNullObj)
{
aDef->releaseTexture();
aDef->fTextureMonitor = MNodeMessage::addAttributeChangedCallback( textureNode, textureChangedCallback, aDef);
}
}
}
if (aDef->fTextureId == 0 || tmp != aDef->fStringDef)
{
if (aDef->fTextureId == 0)
{
GLuint val;
glGenTextures(1, &val);
aDef->fTextureId = val;
}
aDef->fStringDef = tmp;
nv_dds::CDDSImage image;
MString path = cgfxFindFile(tmp);
if (path.asChar() == NULL || !strcmp(path.asChar(), ""))
{
MFileObject effectFile;
effectFile.setRawFullName( fShaderFxFile);
path = cgfxFindFile( effectFile.path() + tmp);
}
if (path.asChar() != NULL && strcmp(path.asChar(), ""))
{
switch (aDef->fType)
{
case cgfxAttrDef::kAttrTypeEnvTexture:
case cgfxAttrDef::kAttrTypeCubeTexture:
case cgfxAttrDef::kAttrTypeNormalizationTexture:
image.load(path.asChar(),false);
break;
default:
image.load(path.asChar(), !invertTexCoords() );
break;
}
}
static unsigned char whitePixel[ 4] = { 255, 255, 255, 255};
switch (aDef->fType)
{
case cgfxAttrDef::kAttrTypeColor1DTexture:
glBindTexture(GL_TEXTURE_1D,aDef->fTextureId);
if( image.is_valid())
{
glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
image.upload_texture1D();
}
else
{
glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
case cgfxAttrDef::kAttrTypeColor2DTexture:
case cgfxAttrDef::kAttrTypeNormalTexture:
case cgfxAttrDef::kAttrTypeBumpTexture:
#if !defined(WIN32) && !defined(LINUX)
case cgfxAttrDef::kAttrTypeColor2DRectTexture:
#endif
glBindTexture(GL_TEXTURE_2D,aDef->fTextureId);
if( image.is_valid())
{
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
image.upload_texture2D();
}
else
{
if (textureNode != MObject::kNullObj)
{
MImage img;
unsigned int width, height;
if (MS::kSuccess == img.readFromTextureNode(textureNode))
{
if( invertTexCoords() )
{
img.verticalFlip();
}
MStatus status = img.getSize( width, height);
if (width > 0 && height > 0 && (status != MStatus::kFailure) )
{
if (width > 2 && height > 2)
{
unsigned int p2Width, p2Height;
bool widthPowerOfTwo = textureInitPowerOfTwo(width, p2Width);
bool heightPowerOfTwo = textureInitPowerOfTwo(height, p2Height);
if(!widthPowerOfTwo || !heightPowerOfTwo)
{
width = p2Width;
height = p2Height;
img.resize( p2Width, p2Height, false );
}
}
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, true);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
}
break;
case cgfxAttrDef::kAttrTypeEnvTexture:
case cgfxAttrDef::kAttrTypeCubeTexture:
case cgfxAttrDef::kAttrTypeNormalizationTexture:
{
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, aDef->fTextureId);
if( image.is_valid())
{
GLenum target;
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
for (int n = 0; n < 6; ++n)
{
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+n;
image.upload_texture2D(image.is_cubemap() ? n : 0, target);
}
}
break;
}
case cgfxAttrDef::kAttrTypeColor3DTexture:
glBindTexture(GL_TEXTURE_3D,aDef->fTextureId);
if( image.is_valid())
{
image.upload_texture3D();
}
break;
#if defined(WIN32) || defined(LINUX)
case cgfxAttrDef::kAttrTypeColor2DRectTexture:
glBindTexture(GL_TEXTURE_RECTANGLE_NV, aDef->fTextureId);
if( image.is_valid())
{
image.upload_textureRectangle();
}
else
{
glTexImage2D( GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
#endif
default:
assert(false);
}
}
checkGlErrors("After loading texture");
cgGLSetupSampler(aDef->fParameterHandle, aDef->fTextureId);
break;
}
#ifdef _WIN32
case cgfxAttrDef::kAttrTypeTime:
{
int ival = timeGetTime() & 0xffffff;
float val = (float)ival * 0.001f;
cgSetParameter1f(aDef->fParameterHandle, val);
break;
}
#endif
case cgfxAttrDef::kAttrTypeOther:
case cgfxAttrDef::kAttrTypeUnknown:
break;
case cgfxAttrDef::kAttrTypeObjectDir:
case cgfxAttrDef::kAttrTypeViewDir:
case cgfxAttrDef::kAttrTypeProjectionDir:
case cgfxAttrDef::kAttrTypeScreenDir:
case cgfxAttrDef::kAttrTypeObjectPos:
case cgfxAttrDef::kAttrTypeViewPos:
case cgfxAttrDef::kAttrTypeProjectionPos:
case cgfxAttrDef::kAttrTypeScreenPos:
case cgfxAttrDef::kAttrTypeWorldMatrix:
case cgfxAttrDef::kAttrTypeViewMatrix:
case cgfxAttrDef::kAttrTypeProjectionMatrix:
case cgfxAttrDef::kAttrTypeWorldViewMatrix:
case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
break;
default:
M_CHECK( false );
}
}
catch ( cgfxShaderCommon::InternalError* e )
{
if ( ++fErrorCount <= fErrorLimit )
{
size_t ee = (size_t)e;
MFnDependencyNode fnNode( oNode );
MString sMsg = "cgfxShader warning ";
sMsg += (int)ee;
sMsg += ": ";
sMsg += fnNode.name();
sMsg += " internal error while setting parameter \"";
sMsg += aDef->fName;
sMsg += "\" of effect \"";
sMsg += fShaderFxFile;
sMsg += "\" for shape ";
sMsg += currentPath().partialPathName();
MGlobal::displayWarning( sMsg );
}
}
}
}
void
cgfxShaderNode::bindViewAttrValues(const MDagPath& shapePath)
{
if ( !fEffect ||
!fTechnique.length() )
return;
MStatus status;
MObject oNode = thisMObject();
MMatrix wMatrix, vMatrix, pMatrix, sMatrix;
MMatrix wvMatrix, wvpMatrix, wvpsMatrix;
{
float tmp[4][4];
if (shapePath.isValid())
wMatrix = shapePath.inclusiveMatrix();
else
wMatrix.setToIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX, &tmp[0][0]);
wvMatrix = MMatrix(tmp);
vMatrix = wMatrix.inverse() * wvMatrix;
glGetFloatv(GL_PROJECTION_MATRIX, &tmp[0][0]);
pMatrix = MMatrix(tmp);
wvpMatrix = wvMatrix * pMatrix;
float vpt[4];
float depth[2];
glGetFloatv(GL_VIEWPORT, vpt);
glGetFloatv(GL_DEPTH_RANGE, depth);
float x0, y0, z0, w, h, d;
x0 = vpt[0];
y0 = vpt[1];
z0 = depth[0];
w = vpt[2];
h = vpt[3];
d = depth[1] - z0;
double* s = &sMatrix.matrix[0][0];
s[ 0] = w/2; s[ 1] = 0.0; s[ 2] = 0.0; s[ 3] = 0.0;
s[ 4] = 0.0; s[ 5] = h/2; s[ 6] = 0.0; s[ 7] = 0.0;
s[ 8] = 0.0; s[ 9] = 0.0; s[10] = d/2; s[11] = 0.0;
s[12] = x0+w/2; s[13] = y0+h/2; s[14] = z0+d/2; s[15] = 1.0;
wvpsMatrix = wvpMatrix * sMatrix;
}
for ( cgfxAttrDefList::iterator it( fAttrDefList ); it; ++it )
{
cgfxAttrDef* aDef = *it;
try
{
switch (aDef->fType)
{
case cgfxAttrDef::kAttrTypeObjectDir:
case cgfxAttrDef::kAttrTypeViewDir:
case cgfxAttrDef::kAttrTypeProjectionDir:
case cgfxAttrDef::kAttrTypeScreenDir:
case cgfxAttrDef::kAttrTypeObjectPos:
case cgfxAttrDef::kAttrTypeViewPos:
case cgfxAttrDef::kAttrTypeProjectionPos:
case cgfxAttrDef::kAttrTypeScreenPos:
{
float tmp[4];
if (aDef->fSize == 3)
{
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
tmp[3] = 1.0;
}
else
{
aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
}
MVector vec(tmp[0], tmp[1], tmp[2]);
int space = aDef->fType - cgfxAttrDef::kAttrTypeFirstPos;
if (space < 0)
{
space = aDef->fType - cgfxAttrDef::kAttrTypeFirstDir;
}
MMatrix mat;
switch (space)
{
case 0: break;
case 1: mat = wMatrix; break;
case 2: mat = wvMatrix; break;
case 3: mat = wvpMatrix; break;
case 4: mat = wvpsMatrix; break;
}
int base = cgfxAttrDef::kAttrTypeFirstPos;
if (aDef->fType <= cgfxAttrDef::kAttrTypeLastDir)
base = cgfxAttrDef::kAttrTypeFirstDir;
if (base == cgfxAttrDef::kAttrTypeFirstPos)
{
MPoint point(tmp[0], tmp[1], tmp[2], tmp[3]);
point *= wMatrix.inverse() * mat;
tmp[0] = (float)point.x;
tmp[1] = (float)point.y;
tmp[2] = (float)point.z;
tmp[3] = (float)point.w;
}
else
{
MVector vec(tmp[0], tmp[1], tmp[2]);
vec *= wMatrix.inverse() * mat;
tmp[0] = (float)vec.x;
tmp[1] = (float)vec.y;
tmp[2] = (float)vec.z;
tmp[3] = 1.F;
}
cgSetParameterValuefc(aDef->fParameterHandle, aDef->fSize, tmp);
break;
}
case cgfxAttrDef::kAttrTypeWorldMatrix:
case cgfxAttrDef::kAttrTypeViewMatrix:
case cgfxAttrDef::kAttrTypeProjectionMatrix:
case cgfxAttrDef::kAttrTypeWorldViewMatrix:
case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
{
MMatrix mat;
switch (aDef->fType)
{
case cgfxAttrDef::kAttrTypeWorldMatrix:
mat = wMatrix; break;
case cgfxAttrDef::kAttrTypeViewMatrix:
mat = vMatrix; break;
case cgfxAttrDef::kAttrTypeProjectionMatrix:
mat = pMatrix; break;
case cgfxAttrDef::kAttrTypeWorldViewMatrix:
mat = wvMatrix; break;
case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
mat = wvpMatrix; break;
default:
break;
}
if (aDef->fInvertMatrix)
{
mat = mat.inverse();
}
if (!aDef->fTransposeMatrix)
{
mat = mat.transpose();
}
float tmp[4][4];
mat.get(tmp);
cgSetMatrixParameterfr(aDef->fParameterHandle, &tmp[0][0]);
break;
}
default:
break;
}
}
catch ( cgfxShaderCommon::InternalError* e )
{
if ( ++fErrorCount <= fErrorLimit )
{
size_t ee = (size_t)e;
MFnDependencyNode fnNode( oNode );
MString sMsg = "cgfxShader warning ";
sMsg += (int)ee;
sMsg += ": ";
sMsg += fnNode.name();
sMsg += " internal error while setting parameter \"";
sMsg += aDef->fName;
sMsg += "\" of effect \"";
sMsg += fShaderFxFile;
sMsg += "\" for shape ";
if (shapePath.isValid())
sMsg += shapePath.partialPathName();
else
sMsg += "SWATCH GEOMETRY";
MGlobal::displayWarning( sMsg );
}
}
}
}
MStatus cgfxShaderNode::glUnbind(const MDagPath& shapePath)
{
if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
{
if( !fNewEffect.fTechnique->fMultiPass)
cgResetPassState( fNewEffect.fTechnique->fPasses->fPass);
if( fDepthEnableState)
glEnable( GL_DEPTH_TEST);
else
glDisable( GL_DEPTH_TEST);
glDepthFunc( fDepthFunc);
glBlendFunc( fBlendSourceFactor, fBlendDestFactor);
if (fTechniqueHasBlending)
glPopAttrib();
}
else
{
glPopAttrib();
}
glStateCache::instance().disableAll();
glStateCache::instance().activeTexture( 0);
#ifdef KH_DEBUG
MString ss = " .. unbd ";
if ( this && fConstructed )
ss += name();
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
return MS::kSuccess;
}
MStatus cgfxShaderNode::glGeometry(const MDagPath& shapePath,
int prim,
unsigned int writable,
int indexCount,
const unsigned int * indexArray,
int vertexCount,
const int * vertexIDs,
const float * vertexArray,
int normalCount,
const float ** normalArrays,
int colorCount,
const float ** colorArrays,
int texCoordCount,
const float ** texCoordArrays)
{
MStatus stat;
#ifdef KH_DEBUG
MString ss = " .. geom ";
if ( this && fConstructed )
ss += name();
ss += " ";
ss += indexCount;
ss += "i ";
ss += vertexCount;
ss += "v ";
ss += normalCount;
ss += "n ";
ss += colorCount;
ss += "c ";
ss += texCoordCount;
ss += "t ";
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
try
{
if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
{
bindViewAttrValues(shapePath);
if( dirtyMask() != kDirtyNone)
fNewEffect.flushCache( shapePath);
cgfxPass* pass = fNewEffect.fTechnique->fPasses;
while( pass)
{
pass->bind( shapePath, vertexCount, vertexArray, fNormalsPerVertex, normalCount, normalArrays, colorCount, colorArrays, texCoordCount, texCoordArrays);
glStateCache::instance().flushState();
if( fNewEffect.fTechnique->fMultiPass) cgSetPassState( pass->fPass);
glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray);
if( fNewEffect.fTechnique->fMultiPass) cgResetPassState( pass->fPass);
pass = pass->fNext;
}
}
else
{
glStateCache::instance().enablePosition();
glVertexPointer(3, GL_FLOAT, 0, vertexArray);
if ( normalCount > 0 && normalArrays[ 0 ] )
{
glStateCache::instance().enableNormal();
glNormalPointer(GL_FLOAT, 0, normalArrays[0]);
}
else
{
glStateCache::instance().disableNormal();
glNormal3f(0.0, 0.0, 1.0);
}
glStateCache::instance().flushState();
glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray);
}
checkGlErrors("After effects End");
}
catch ( cgfxShaderCommon::InternalError* e )
{
reportInternalError( __FILE__, (size_t)e );
stat = MS::kFailure;
}
catch ( ... )
{
reportInternalError( __FILE__, __LINE__ );
stat = MS::kFailure;
}
return stat;
}
int
cgfxShaderNode::getTexCoordSetNames( MStringArray& names )
{
names = fUVSets;
return names.length();
}
#if MAYA_API_VERSION >= 700
int
cgfxShaderNode::getColorSetNames( MStringArray& names )
{
names = fColorSets;
return names.length();
}
#else
int cgfxShaderNode::colorsPerVertex()
{
fColorType.setLength(1);
fColorIndex.setLength(1);
fColorType[0] = 0;
fColorIndex[0] = 0;
return 1;
}
#endif
int cgfxShaderNode::normalsPerVertex()
{
#ifdef KH_DEBUG
MString ss = " .. npv ";
if ( this && fConstructed )
ss += name();
ss += " ";
ss += fNormalsPerVertex;
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
if (fEffect == NULL) {
#ifdef _WIN32
::OutputDebugString( "CGFX: fEffect was NULL\n");
#endif
createEffect();
}
return fNormalsPerVertex;
}
void
cgfxShaderNode::setAttrDefList( cgfxAttrDefList* list )
{
if (fAttrDefList)
cgfxAttrDef::purgeMObjectCache( fAttrDefList );
if ( list )
{
list->addRef();
cgfxAttrDef::validateMObjectCache( thisMObject(), list );
}
if (fAttrDefList)
fAttrDefList->release();
fAttrDefList = list;
}
void cgfxShaderNode::getAttributeList(MStringArray& attrList) const
{
MString tmp;
int len = fAttributeListArray.length();
attrList.clear();
for (int i = 0; i < len; ++i)
{
tmp = fAttributeListArray[i];
attrList.append(tmp);
}
}
void cgfxShaderNode::setAttributeList(const MStringArray& attrList)
{
MString tmp;
int len = attrList.length();
fAttributeListArray.clear();
for (int i = 0; i < len; ++i)
{
tmp = attrList[i];
fAttributeListArray.append(tmp);
}
}
void
cgfxShaderNode::setVertexAttributes( cgfxVertexAttribute* attributeList)
{
if( fTexCoordSource.length())
{
int length = fTexCoordSource.length();
for( int i = 0; i < length; i++)
{
MString semantic( "TEXCOORD");
if( i)
semantic += i;
else
semantic += "0";
MString source( fTexCoordSource[ i]);
if( source.index( ':') < 0)
source = "uv:" + source;
cgfxVertexAttribute* newAttribute = attributeList;
while( newAttribute)
{
if( newAttribute->fSemantic == semantic ||
(i == 6 && (newAttribute->fSemantic == "TANGENT" || newAttribute->fSemantic == "TANGENT0")) ||
(i == 7 && (newAttribute->fSemantic == "BINORMAL" || newAttribute->fSemantic == "BINORMAL0")))
newAttribute->fSourceName = source;
newAttribute = newAttribute->fNext;
}
}
fTexCoordSource.clear();
}
if( fColorSource.length())
{
int length = fColorSource.length();
for( int i = 0; i < length; i++)
{
MString semantic( "COLOR");
if( i)
semantic += i;
else
semantic += "0";
MString source( fColorSource[ i]);
if( source.index( ':') < 0)
source = "color:" + source;
cgfxVertexAttribute* newAttribute = attributeList;
while( newAttribute)
{
if( newAttribute->fSemantic == semantic)
newAttribute->fSourceName = source;
newAttribute = newAttribute->fNext;
}
}
fColorSource.clear();
}
cgfxVertexAttribute* oldAttributes = fVertexAttributes;
while( oldAttributes)
{
cgfxVertexAttribute* oldAttribute = oldAttributes;
oldAttributes = oldAttributes->fNext;
cgfxVertexAttribute* newAttribute = attributeList;
while( newAttribute)
{
if( newAttribute->fName == oldAttribute->fName)
{
newAttribute->fSourceName = oldAttribute->fSourceName;
newAttribute->fSourceType = oldAttribute->fSourceType;
}
newAttribute = newAttribute->fNext;
}
delete oldAttribute;
}
fVertexAttributes = attributeList;
analyseVertexAttributes();
}
void
cgfxShaderNode::setVertexAttributeSource( const MStringArray& sources)
{
fNewEffect.flushCache();
int i = 0;
int numSources = sources.length();
cgfxVertexAttribute* attribute = fVertexAttributes;
while( attribute)
{
attribute->fSourceName = ( i < numSources) ? sources[ i++] : "";
attribute = attribute->fNext;
}
analyseVertexAttributes();
}
inline int findOrInsert( const MString& value, MStringArray& list)
{
int length = list.length();
for( int i = 0; i < length; i++)
if( list[ i] == value)
return i;
list.append( value);
return length;
}
void
cgfxShaderNode::analyseVertexAttributes()
{
fUVSets.clear();
fColorSets.clear();
fNormalsPerVertex = 0;
cgfxVertexAttribute* attribute = fVertexAttributes;
while( attribute)
{
MString source( attribute->fSourceName);
source.toLowerCase();
if( attribute->fSourceName.length() == 0)
{
attribute->fSourceType = cgfxVertexAttribute::kNone;
}
else if( source == "position")
{
attribute->fSourceType = cgfxVertexAttribute::kPosition;
}
else if( source == "normal")
{
attribute->fSourceType = cgfxVertexAttribute::kNormal;
if( fNormalsPerVertex < 1)
fNormalsPerVertex = 1;
}
else
{
MString set = attribute->fSourceName;
int colon = set.index( ':');
MString type;
if( colon >= 0)
{
if( colon > 0) type = source.substring( 0, colon - 1);
set = set.substring( colon + 1, set.length() - 1);
}
if( type == "uv")
{
attribute->fSourceType = cgfxVertexAttribute::kUV;
attribute->fSourceIndex = findOrInsert( set, fUVSets);
}
else if( type == "tangent")
{
attribute->fSourceType = cgfxVertexAttribute::kTangent;
if( fNormalsPerVertex < 2)
fNormalsPerVertex = 2;
attribute->fSourceIndex = findOrInsert( set, fUVSets);
}
else if( type == "binormal")
{
attribute->fSourceType = cgfxVertexAttribute::kBinormal;
if( fNormalsPerVertex < 3)
fNormalsPerVertex = 3;
attribute->fSourceIndex = findOrInsert( set, fUVSets);
}
else if( type == "color")
{
attribute->fSourceType = cgfxVertexAttribute::kColor;
attribute->fSourceIndex = findOrInsert( set, fColorSets);
}
else
{
attribute->fSourceType = cgfxVertexAttribute::kUnknown;
}
}
attribute = attribute->fNext;
}
}
const MStringArray&
cgfxShaderNode::getTexCoordSource() const
{
#ifdef KH_DEBUG
MString ss = " .. gtcs ";
if ( this && fConstructed )
ss += name();
ss += " ";
for ( int ii = 0; ii < fTexCoordSource.length(); ++ii )
{
ss += "\"";
ss += fTexCoordSource[ii];
ss += "\" ";
}
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
return fTexCoordSource;
}
const MStringArray&
cgfxShaderNode::getColorSource() const
{
#ifdef KH_DEBUG
MString ss = " .. gtcs ";
if ( this && fConstructed )
ss += name();
ss += " ";
for ( int ii = 0; ii < fColorSource.length(); ++ii )
{
ss += "\"";
ss += fColorSource[ii];
ss += "\" ";
}
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
return fColorSource;
}
void
cgfxShaderNode::setDataSources( const MStringArray* texCoordSources,
const MStringArray* colorSources)
{
if( texCoordSources )
{
int length_TC = texCoordSources->length();
if ( length_TC > CGFXSHADERNODE_GL_TEXTURE_MAX )
length_TC = CGFXSHADERNODE_GL_TEXTURE_MAX;
fTexCoordSource.clear();
for ( int i = 0; i < length_TC; ++i )
{
fTexCoordSource.append( (*texCoordSources)[ i ] );
}
}
if( colorSources )
{
int length_CS = colorSources->length();
if ( length_CS > CGFXSHADERNODE_GL_COLOR_MAX )
length_CS = CGFXSHADERNODE_GL_COLOR_MAX;
fColorSource.setLength( length_CS );
for ( int i = 0; i < length_CS; ++i )
fColorSource[ i ] = (*colorSources)[ i ];
}
fDataSetNames.clear();
fNormalsPerVertex = 1;
updateDataSource( fTexCoordSource, fTexCoordType, fTexCoordIndex);
updateDataSource( fColorSource, fColorType, fColorIndex);
}
void
cgfxShaderNode::updateDataSource( MStringArray& v, MIntArray& typeList, MIntArray& indexList)
{
#ifdef KH_DEBUG
MString ss = " .. stcs ";
if ( this && fConstructed )
ss += name();
ss += " ";
for ( int ii = 0; ii < v.length(); ++ii )
{
ss += "\"";
ss += v[ii];
ss += "\" ";
}
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
int nDataSets = v.length();
typeList.setLength( nDataSets );
indexList.setLength( nDataSets );
for ( int iDataSet = 0; iDataSet < nDataSets; ++iDataSet )
{
MString s;
int iType = etcNull;
int iBuf = 0;
const char* bp = v[ iDataSet ].asChar();
const char* ep = v[ iDataSet ].length() + bp;
#ifdef _WIN32
while ( bp < ep && *bp <= ' ' && *bp >= '\0') ++bp;
#else
while ( bp < ep && *bp <= ' ') ++bp;
#endif
#ifdef _WIN32
while ( bp < ep && ep[-1] <= ' ' && ep[-1] >= '\0' ) --ep;
#else
while ( bp < ep && ep[-1] <= ' ' ) --ep;
#endif
if ( bp == ep )
iType = etcNull;
else if ( (*bp >= '0' && *bp <= '9') ||
*bp == '-' ||
*bp == '+' ||
*bp == '.' )
{
const char* cp = bp;
int nValues = 0;
while ( cp < ep &&
nValues < 4 )
{
float x;
int nc = 0;
int nv = sscanf( cp, " %f%n", &x, &nc );
if ( nv != 1 )
break;
++nValues;
cp += nc;
}
if ( nValues > 0 )
{
s.set( bp, (int)(cp - bp) );
for ( ; nValues < 4; ++nValues )
s += " 0";
iType = etcConstant;
}
}
else
{
s.set( bp, (int)(ep - bp) );
MStringArray splitStrings;
#define kDefaultUVSet "map1"
if ((MStatus::kSuccess == s.split( ':', splitStrings)) && splitStrings.length() > 1)
{
s = splitStrings[0];
iBuf = findOrAppend( fDataSetNames, splitStrings[1]);
}
bp = s.asChar();
if ( 0 == stricmp( "normal", bp ) )
{
s = "normal";
iType = etcNormal;
}
else if ( 0 == stricmp( "tangent", bp ) )
{
s = "tangent";
if( splitStrings.length() < 2)
{
splitStrings.setLength( 2);
splitStrings[ 1] = kDefaultUVSet;
iBuf = findOrAppend( fDataSetNames, kDefaultUVSet);
}
s += ":" + splitStrings[1];
iType = etcTangent;
if( fNormalsPerVertex < 2)
fNormalsPerVertex = 2;
}
else if ( 0 == stricmp( "binormal", bp ) )
{
s = "binormal";
if( splitStrings.length() < 2)
{
splitStrings.setLength( 2);
splitStrings[ 1] = kDefaultUVSet;
iBuf = findOrAppend( fDataSetNames, kDefaultUVSet);
}
s += ":" + splitStrings[1];
iType = etcBinormal;
fNormalsPerVertex = 3;
}
else
{
iType = etcDataSet;
iBuf = findOrAppend( fDataSetNames, s );
}
}
typeList[ iDataSet ] = iType;
indexList[ iDataSet ] = iBuf;
v[ iDataSet ] = s;
}
}
const MStringArray&
cgfxShaderNode::getEmptyUVSets() const
{
static const MStringArray saNull;
return saNull;
}
const MObjectArray&
cgfxShaderNode::getEmptyUVSetShapes() const
{
static const MObjectArray oaNull;
return oaNull;
}
void
cgfxShaderNode::setEffect(CGeffect pNewEffect)
{
#ifdef KH_DEBUG
char ssbuf[64];
MString ss = " .. se ";
ss += name();
ss += " ";
sprintf( ssbuf, "new=%X old=%X", pNewEffect, fEffect );
ss += ssbuf;
ss += "\n";
::OutputDebugString( ss.asChar() );
#endif
if (fEffect)
cgDestroyEffect(fEffect);
fEffect = pNewEffect;
fNewEffect.setEffect( fEffect);
fTechniqueList.clear();
if (fEffect)
{
CGtechnique cgTechnique = cgGetFirstTechnique(fEffect);
while (cgTechnique)
{
MString s;
const char* techniqueName = cgGetTechniqueName(cgTechnique);
if (techniqueName)
{
s += techniqueName;
}
if (cgValidateTechnique(cgTechnique) == CG_TRUE)
{
int numPasses = 0;
CGpass cgPass = cgGetFirstPass(cgTechnique);
while (cgPass)
{
++numPasses;
cgPass = cgGetNextPass(cgPass);
}
s += "\t";
s += numPasses;
}
else
{
s += "\t0";
}
fTechniqueList.append(s);
cgTechnique = cgGetNextTechnique(cgTechnique);
}
}
}
bool cgfxShaderNode::hasTransparency()
{
return false;
}
unsigned int cgfxShaderNode::transparencyOptions()
{
if (fTechniqueHasBlending)
{
return ( kIsTransparent | kNoTransparencyFrontBackCull | kNoTransparencyPolygonSort );
}
return 0;
}
void cgfxShaderNode::setTechniqueHasBlending( CGtechnique technique)
{
fTechniqueHasBlending = false;
CGpass cgPass = cgGetFirstPass(technique);
bool foundBlendEnabled = false;
bool foundBlendFunc = false;
if (cgPass)
{
CGstateassignment stateAssignment = cgGetFirstStateAssignment(cgPass);
while ( stateAssignment )
{
CGstate state = cgGetStateAssignmentState( stateAssignment);
const char *stateName = cgGetStateName(state);
if (!foundBlendEnabled && stricmp( stateName, "BlendEnable") == 0)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(stateAssignment, &numValues);
if (values && numValues)
{
if (values[0])
{
foundBlendEnabled = true;
}
}
}
else if (!foundBlendFunc && stricmp( stateName, "BlendFunc") == 0)
{
int numValues = 0;
const int * values = cgGetIntStateAssignmentValues(stateAssignment, &numValues);
if (values && numValues==2)
{
#if defined(CGFX_DEBUG_BLEND_FUNCTIONS)
MString blendStringTable[6] =
{
"GL_SRC_COLOR",
"GL_ONE_MINUS_SRC_COLOR",
"GL_SRC_ALPHA",
"GL_ONE_MINUS_SRC_ALPHA",
"GL_DST_ALPHA",
"GL_ONE_MINUS_DST_ALPHA"
};
#endif
if ((values[0] >= GL_SRC_COLOR) && (values[0] <= GL_ONE_MINUS_DST_ALPHA) &&
(values[1] >= GL_SRC_COLOR) && (values[1] <= GL_ONE_MINUS_DST_ALPHA) )
{
#if defined(CGFX_DEBUG_BLEND_FUNCTIONS)
printf("Found blend function = %s, %s\n",
blendStringTable[ values[0]-GL_SRC_COLOR].asChar(),
blendStringTable[ values[1]-GL_SRC_COLOR].asChar());
#endif
foundBlendFunc = true;
}
}
}
fTechniqueHasBlending = foundBlendEnabled && foundBlendFunc;
if (fTechniqueHasBlending)
break;
stateAssignment = cgGetNextStateAssignment( stateAssignment);
}
}
}
void
cgfxShaderNode::setTechnique( const MString& techn )
{
if (!fEffect)
{
fTechnique = techn;
fTechniqueHasBlending = false;
return;
}
CGtechnique technique = cgGetNamedTechnique(fEffect, techn.asChar());
if (cgValidateTechnique(technique) == CG_TRUE)
{
fTechnique = techn;
setTechniqueHasBlending( technique );
fNewEffect.setupAttributes( this);
return;
}
technique = cgGetNamedTechnique(fEffect, fTechnique.asChar());
if (cgValidateTechnique(technique) == CG_TRUE)
{
setTechniqueHasBlending( technique );
return;
}
technique = cgGetFirstTechnique(fEffect);
while (technique)
{
if (cgValidateTechnique(technique) == CG_TRUE)
{
fTechnique = cgGetTechniqueName(technique);
setTechniqueHasBlending( technique );
fNewEffect.setupAttributes( this);
return;
}
technique = cgGetNextTechnique(technique);
}
fTechnique = techn;
fTechniqueHasBlending = false;
}
MStatus cgfxShaderNode::shouldSave ( const MPlug & plug, bool & ret )
{
if (plug == sAttributeList)
{
ret = true;
return MS::kSuccess;
}
else if (plug == sVertexAttributeList)
{
ret = true;
return MS::kSuccess;
}
return MPxNode::shouldSave(plug, ret);
}
void cgfxShaderNode::setTexturesByName(bool texturesByName, bool updateAttributes)
{
if( updateAttributes && fTexturesByName != texturesByName)
{
MDGModifier dgMod;
cgfxAttrDefList* nodeList = attrDefList();
cgfxAttrDefList::iterator nmIt;
bool foundTextures = false;
for (nmIt = nodeList->begin(); nmIt; ++nmIt)
{
cgfxAttrDef* adef = (*nmIt);
if(adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture && adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
{
MObject theMObject = thisMObject();
adef->destroyAttribute( theMObject, &dgMod);
foundTextures = true;
}
}
fTexturesByName = texturesByName;
if( foundTextures)
{
dgMod.doIt();
for (nmIt = nodeList->begin(); nmIt; ++nmIt)
{
cgfxAttrDef* adef = (*nmIt);
if( adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture && adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
{
adef->createAttribute(thisMObject(), &dgMod, this);
}
}
dgMod.doIt();
if( fTexturesByName)
{
for (nmIt = nodeList->begin(); nmIt; ++nmIt)
{
cgfxAttrDef* adef = (*nmIt);
if( adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture &&
adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
{
MObject theMObject = thisMObject();
adef->setTexture( theMObject, adef->fStringDef, &dgMod);
}
}
}
}
}
else
{
fTexturesByName = texturesByName;
}
}
MString
cgfxShaderNode::getPluginVersion()
{
MString sVer = "cgfxShader ";
sVer += CGFXSHADER_VERSION;
sVer += " for Maya ";
sVer += (int)(MAYA_API_VERSION / 100);
sVer += ".";
sVer += (int)(MAYA_API_VERSION % 100 / 10);
sVer += " (";
sVer += __DATE__;
sVer += ")";
return sVer;
}
void
cgfxShaderNode::reportInternalError( const char* function, size_t errcode )
{
MString es = "cgfxShader";
try
{
if ( this &&
fConstructed )
{
if ( ++fErrorCount > fErrorLimit )
return;
MString s;
s += "\"";
s += name();
s += "\": ";
s += typeName();
es = s;
}
}
catch ( ... )
{}
es += " internal error ";
es += (int)errcode;
es += " in ";
es += function;
#ifdef KH_DEBUG
::OutputDebugString( es.asChar() );
::OutputDebugString( "\n" );
#endif
MGlobal::displayError( es );
}
void
cgfxShaderNode::cgErrorCallBack()
{
MGlobal::displayInfo(__FUNCTION__);
CGerror cgLastError = cgGetError();
if(cgLastError)
{
MGlobal::displayError(cgGetErrorString(cgLastError));
MGlobal::displayError(cgGetLastListing(sCgContext));
}
}
void
cgfxShaderNode::cgErrorHandler(CGcontext cgContext, CGerror cgError, void* userData)
{
MGlobal::displayError(cgGetErrorString(cgError));
MGlobal::displayError(cgGetLastListing(sCgContext));
}