#include "cgfxShaderCommon.h"
#include <float.h>
#include <limits.h>
#include <string.h>
#include <maya/MIOStream.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MStringArray.h>
#include <maya/MFnStringData.h>
#include <maya/MFnStringArrayData.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnCompoundAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MDGModifier.h>
#include <maya/MFnMatrixData.h>
#include <maya/MPlugArray.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MSelectionList.h>
#include "cgfxAttrDef.h"
#include "cgfxShaderNode.h"
#include "cgfxFindImage.h"
#define N_MAX_STRING_LENGTH 1024
#ifdef _WIN32
#else
# define stricmp strcasecmp
# define strnicmp strncasecmp
#endif
cgfxAttrDef::cgfxAttrDef()
: fType( kAttrTypeUnknown )
, fSize( 0 )
, fHint( kVectorHintNone )
, fNumericMin( NULL )
, fNumericMax( NULL )
, fNumericSoftMin( NULL )
, fNumericSoftMax( NULL )
, fUnits( MDistance::kInvalid )
, fNumericDef( NULL )
, fTextureId(0 )
, fTextureMonitor(kNullCallback)
, fParameterHandle(0)
, fInvertMatrix( false )
, fTransposeMatrix( false )
, fTweaked( false )
, fInitOnUndo( false )
{
};
cgfxAttrDef::~cgfxAttrDef()
{
release();
delete [] fNumericMin;
delete [] fNumericMax;
delete [] fNumericSoftMin;
delete [] fNumericSoftMax;
delete [] fNumericDef;
};
void cgfxAttrDef::release()
{
releaseTexture();
releaseCallback();
}
void cgfxAttrDef::releaseTexture()
{
if( fTextureId != 0 )
{
glDeleteTextures( 1, &fTextureId);
fTextureId = 0;
}
}
void cgfxAttrDef::releaseCallback()
{
if( fTextureMonitor != kNullCallback)
{
MMessage::removeCallback( fTextureMonitor);
fTextureMonitor = kNullCallback;
}
}
void cgfxAttrDef::setTextureType(CGparameter cgParameter)
{
fType = kAttrTypeColor2DTexture;
const char* semantic = cgGetParameterSemantic(cgParameter);
if (!semantic) return;
if (semantic)
{
if (stricmp(semantic, "normal") == 0)
{
fType = kAttrTypeNormalTexture;
}
else if (stricmp(semantic, "height") == 0)
{
fType = kAttrTypeBumpTexture;
}
else if (stricmp(semantic, "environment") == 0)
{
fType = kAttrTypeEnvTexture;
}
else if (stricmp(semantic, "environmentnormal") == 0)
{
fType = kAttrTypeNormalizationTexture;
}
}
CGannotation cgAnnotation = cgGetFirstParameterAnnotation(cgParameter);
while (cgAnnotation)
{
const char* annotationName = cgGetAnnotationName(cgAnnotation);
const char* annotationValue = cgGetStringAnnotationValue(cgAnnotation);
if (stricmp(annotationName, "resourcetype") == 0)
{
if (stricmp(annotationValue, "1d") == 0)
{
fType = kAttrTypeColor1DTexture;
}
else if (stricmp(annotationValue, "2d") == 0)
{
fType = kAttrTypeColor2DTexture;
}
else if (stricmp(annotationValue, "rect") == 0)
{
fType = kAttrTypeColor2DRectTexture;
}
else if (stricmp(annotationValue, "3d") == 0)
{
fType = kAttrTypeColor3DTexture;
}
else if (stricmp(annotationValue, "cube") == 0)
{
fType = kAttrTypeCubeTexture;
}
}
else if (stricmp(annotationName, "resourcename") == 0)
{
fStringDef = annotationValue;
}
cgAnnotation = cgGetNextAnnotation(cgAnnotation);
}
}
void cgfxAttrDef::setSamplerType(CGparameter cgParameter)
{
CGstateassignment cgStateAssignment = cgGetNamedSamplerStateAssignment(cgParameter, "texture");
setTextureType(cgGetTextureStateAssignmentValue(cgStateAssignment));
}
void cgfxAttrDef::setMatrixType(CGparameter cgParameter)
{
fType = kAttrTypeMatrix;
const char* semantic = cgGetParameterSemantic(cgParameter);
if (!semantic)
return;
if (stricmp(semantic, "world") == 0)
{
fType = kAttrTypeWorldMatrix;
fInvertMatrix = false;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldinverse") == 0)
{
fType = kAttrTypeWorldMatrix;
fInvertMatrix = true;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldtranspose") == 0)
{
fType = kAttrTypeWorldMatrix;
fInvertMatrix = false;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "worldinversetranspose") == 0)
{
fType = kAttrTypeWorldMatrix;
fInvertMatrix = true;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "worldview") == 0)
{
fType = kAttrTypeWorldViewMatrix;
fInvertMatrix = false;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldviewtranspose") == 0)
{
fType = kAttrTypeWorldViewMatrix;
fInvertMatrix = false;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "worldviewinverse") == 0)
{
fType = kAttrTypeWorldViewMatrix;
fInvertMatrix = true;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldviewinversetranspose") == 0)
{
fType = kAttrTypeWorldViewMatrix;
fInvertMatrix = true;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "worldviewprojection") == 0)
{
fType = kAttrTypeWorldViewProjectionMatrix;
fInvertMatrix = false;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldviewprojectiontranspose") == 0)
{
fType = kAttrTypeWorldViewProjectionMatrix;
fInvertMatrix = false;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "worldviewprojectioninverse") == 0)
{
fType = kAttrTypeWorldViewProjectionMatrix;
fInvertMatrix = true;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "worldviewprojectioninversetranspose") == 0)
{
fType = kAttrTypeWorldViewProjectionMatrix;
fInvertMatrix = true;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "view") == 0)
{
fType = kAttrTypeViewMatrix;
fInvertMatrix = false;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "viewinverse") == 0)
{
fType = kAttrTypeViewMatrix;
fInvertMatrix = true;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "viewtranspose") == 0)
{
fType = kAttrTypeViewMatrix;
fInvertMatrix = false;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "viewinversetranspose") == 0)
{
fType = kAttrTypeViewMatrix;
fInvertMatrix = true;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "projection") == 0)
{
fType = kAttrTypeProjectionMatrix;
fInvertMatrix = false;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "projectioninverse") == 0)
{
fType = kAttrTypeProjectionMatrix;
fInvertMatrix = true;
fTransposeMatrix = false;
}
else if (stricmp(semantic, "projectiontranspose") == 0)
{
fType = kAttrTypeProjectionMatrix;
fInvertMatrix = false;
fTransposeMatrix = true;
}
else if (stricmp(semantic, "projectioninversetranspose") == 0)
{
fType = kAttrTypeProjectionMatrix;
fInvertMatrix = true;
fTransposeMatrix = true;
}
}
void cgfxAttrDef::setVectorType(CGparameter cgParameter)
{
#if 0
static char* colorList[] =
{
"diffuse",
"specular",
"ambient",
"emissive",
};
#endif
const char* semantic = cgGetParameterSemantic(cgParameter);
if ((semantic == NULL || strcmp(semantic,"") == 0) == false)
{
if (stricmp(semantic, "diffuse") == 0 ||
stricmp(semantic, "specular") == 0 ||
stricmp(semantic, "ambient") == 0 ||
stricmp(semantic, "emissive") == 0)
{
fType = (fSize == 3) ? kAttrTypeColor3 : kAttrTypeColor4;
}
else if (stricmp(semantic, "direction") == 0)
{
fType = kAttrTypeFirstDir;
}
else if (stricmp(semantic, "position") == 0)
{
fType = kAttrTypeFirstPos;
}
}
CGannotation cgAnnotation = cgGetFirstParameterAnnotation(cgParameter);
while (cgAnnotation)
{
const char* annotationName = cgGetAnnotationName(cgAnnotation);
const char* annotationValue = cgGetStringAnnotationValue(cgAnnotation);
if (stricmp(annotationName, "type") == 0)
{
if (strlen(annotationValue) != 0)
{
if (stricmp(annotationValue, "color") == 0)
{
fType = (fSize == 3) ? kAttrTypeColor3 : kAttrTypeColor4;
}
}
}
else if (stricmp(annotationName, "space") == 0)
{
if (stricmp(annotationValue, "world") == 0)
{
fType = (cgfxAttrType)(fType + kAttrTypeWorldDir - kAttrTypeFirstDir);
}
else if (stricmp(annotationValue, "view") == 0 ||
stricmp(annotationValue, "devicelightspace") == 0)
{
fType = (cgfxAttrType)(fType + kAttrTypeViewDir - kAttrTypeFirstDir);
}
else if (stricmp(annotationValue, "projection") == 0)
{
fType = (cgfxAttrType)(fType + kAttrTypeProjectionDir - kAttrTypeFirstDir);
}
else if (stricmp(annotationValue, "screen") == 0)
{
fType = (cgfxAttrType)(fType + kAttrTypeScreenDir - kAttrTypeFirstDir);
}
}
else if (stricmp(annotationName, "object") == 0)
{
fHint = kVectorHintNone;
if (stricmp(annotationValue, "dirlight") == 0)
{
fHint = kVectorHintDirLight;
}
else if (stricmp(annotationValue, "spotlight") == 0)
{
fHint = kVectorHintSpotLight;
}
else if (stricmp(annotationValue, "pointlight") == 0)
{
fHint = kVectorHintPointLight;
}
else if (stricmp(annotationValue, "camera") == 0 || stricmp(annotationValue, "eye") == 0)
{
fHint = kVectorHintEye;
}
}
cgAnnotation = cgGetNextAnnotation(cgAnnotation);
}
return;
}
cgfxAttrDefList* cgfxAttrDef::attrsFromEffect(CGeffect cgEffect, CGtechnique cgTechnique)
{
if (!cgEffect)
return NULL;
cgfxAttrDefList* list = 0;
try
{
list = new cgfxAttrDefList;
CGparameter cgParameter = cgGetFirstEffectParameter(cgEffect);
int i = 0;
while (cgParameter)
{
cgfxAttrDef* aDef = new cgfxAttrDef;
aDef->fName = cgGetParameterName(cgParameter);
aDef->fType = kAttrTypeOther;
aDef->fSize = cgGetParameterRows(cgParameter) * cgGetParameterColumns(cgParameter);
aDef->fParameterHandle = cgParameter;
aDef->fSemantic = cgGetParameterSemantic(cgParameter);
CGtype cgParameterType = cgGetParameterType(cgParameter);
switch (cgParameterType)
{
case CG_BOOL : aDef->fType = kAttrTypeBool; break ;
case CG_INT : aDef->fType = kAttrTypeInt; break ;
case CG_HALF :
case CG_FLOAT :
#ifdef _WIN32
if (stricmp(aDef->fSemantic.asChar() , "Time")==0)
aDef->fType = kAttrTypeTime;
else
#endif
aDef->fType = kAttrTypeFloat;
break;
case CG_HALF2 :
case CG_FLOAT2 :
aDef->fType = kAttrTypeVector2;
break ;
case CG_HALF3 :
case CG_FLOAT3 :
aDef->fType = kAttrTypeVector3;
break ;
case CG_HALF4 :
case CG_FLOAT4 :
aDef->fType = kAttrTypeVector4;
break ;
case CG_HALF4x4 :
case CG_FLOAT4x4 :
aDef->setMatrixType(cgParameter);
break ;
case CG_STRING :
aDef->fType = kAttrTypeString;
break ;
case CG_TEXTURE :
break ;
case CG_SAMPLER1D :
case CG_SAMPLER2D :
case CG_SAMPLER3D :
case CG_SAMPLERRECT :
case CG_SAMPLERCUBE :
aDef->setSamplerType(cgParameter);
break ;
case CG_ARRAY :
case CG_STRUCT :
break ;
default :
MString msg = cgGetTypeString(cgParameterType);
msg += " not yet supported";
MGlobal::displayError(msg);
M_CHECK( false );
}
if (aDef->fType == kAttrTypeVector3 || aDef->fType == kAttrTypeVector4)
{
aDef->setVectorType(cgParameter);
}
MString sUIName;
CGannotation cgAnnotation = cgGetFirstParameterAnnotation(cgParameter);
while (cgAnnotation)
{
const char* annotationName = cgGetAnnotationName(cgAnnotation);
const char* annotationValue = cgGetStringAnnotationValue(cgAnnotation);
CGtype cgAnnotationType = cgGetAnnotationType(cgAnnotation);
if (stricmp(annotationName, "uihelp") == 0)
{
aDef->fDescription = MString(annotationValue);
}
else if (stricmp(annotationName, "uiname" ) == 0 )
{
sUIName = MString(annotationValue);
}
else if( stricmp( annotationName, "units") == 0)
{
if( stricmp( annotationValue, "inches") == 0)
{
aDef->fUnits = MDistance::kInches;
}
else if( stricmp( annotationValue, "millimetres") == 0 || stricmp( annotationValue, "millimeters") == 0 || stricmp( annotationValue, "mm") == 0)
{
aDef->fUnits = MDistance::kMillimeters;
}
else if( stricmp( annotationValue, "centimetres") == 0 || stricmp( annotationValue, "centimeters") == 0 || stricmp( annotationValue, "cm") == 0)
{
aDef->fUnits = MDistance::kCentimeters;
}
else if( stricmp( annotationValue, "metres") == 0 || stricmp( annotationValue, "meters") == 0 || stricmp( annotationValue, "m") == 0)
{
aDef->fUnits = MDistance::kMeters;
}
else if( stricmp( annotationValue, "kilometres") == 0 || stricmp( annotationValue, "kilometers") == 0 || stricmp( annotationValue, "km") == 0)
{
aDef->fUnits = MDistance::kKilometers;
}
else if( stricmp( annotationValue, "feet") == 0)
{
aDef->fUnits = MDistance::kFeet;
}
}
else if ((aDef->fType >= kAttrTypeFirstTexture && aDef->fType <= kAttrTypeLastTexture))
{
if (stricmp(annotationName, "resourcetype") == 0)
{
if (stricmp(annotationValue, "1d") == 0)
{
aDef->fType = kAttrTypeColor1DTexture;
}
else if (stricmp(annotationValue, "2d") == 0)
{
aDef->fType = kAttrTypeColor2DTexture;
}
else if (stricmp(annotationValue, "3d") == 0)
{
aDef->fType = kAttrTypeColor3DTexture;
}
else if (stricmp(annotationValue, "cube") == 0)
{
aDef->fType = kAttrTypeCubeTexture;
}
else if (stricmp(annotationValue, "rect") == 0)
{
aDef->fType = kAttrTypeColor2DRectTexture;
}
}
else if (stricmp(annotationName, "resourcename") == 0)
{
aDef->fStringDef = annotationValue;
}
}
else if (cgAnnotationType == CG_BOOL )
{}
else if (stricmp(annotationName, "min") == 0 ||
stricmp(annotationName, "max") == 0 ||
stricmp(annotationName, "uimin") == 0 ||
stricmp(annotationName, "uimax") == 0 )
{
double * tmp = new double [aDef->fSize];
switch (cgAnnotationType)
{
case CG_INT:
{
int nValues;
const int* annotationValues = cgGetIntAnnotationValues(cgAnnotation, &nValues);
for (int iValue = 0; iValue < nValues; ++iValue)
tmp[iValue] = static_cast<double>(annotationValues[iValue]);
}
break;
case CG_FLOAT:
{
int nValues;
const float* annotationValues = cgGetFloatAnnotationValues(cgAnnotation, &nValues);
for (int iValue = 0; iValue < nValues; ++iValue)
tmp[iValue] = static_cast<double>(annotationValues[iValue]);
}
break;
default:
delete [] tmp;
tmp = 0;
break;
}
if (stricmp(annotationName, "min") == 0)
{
aDef->fNumericMin = tmp;
}
else if (stricmp(annotationName, "max") == 0)
{
aDef->fNumericMax = tmp;
}
else if (stricmp(annotationName, "uimin") == 0)
{
aDef->fNumericSoftMin = tmp;
}
else
{
aDef->fNumericSoftMax = tmp;
}
}
cgAnnotation = cgGetNextAnnotation(cgAnnotation);
}
if ( aDef->fType == kAttrTypeColor3 || aDef->fType == kAttrTypeColor4 )
{
if ( !aDef->fNumericMin )
{
aDef->fNumericMin = new double[4];
aDef->fNumericMin[0] = 0.0;
aDef->fNumericMin[1] = 0.0;
aDef->fNumericMin[2] = 0.0;
aDef->fNumericMin[3] = 0.0;
}
if ( !aDef->fNumericMax )
{
aDef->fNumericMax = new double[4];
aDef->fNumericMax[0] = 1.0;
aDef->fNumericMax[1] = 1.0;
aDef->fNumericMax[2] = 1.0;
aDef->fNumericMax[3] = 1.0;
}
}
if ( !aDef->fDescription.length() )
aDef->fDescription = sUIName;
double* tmp = new double [aDef->fSize];
CGtype cgParameterBaseType = cgGetParameterBaseType(cgParameter);
switch (cgParameterBaseType)
{
case CG_BOOL:
{
int val;
if (cgGetParameterValueic(cgParameter, 1, &val) != 1)
{
delete [] tmp;
tmp = 0;
break;
}
for (int k = 0; k < aDef->fSize; ++k)
{
tmp[k] = val ? 1 : 0;
}
}
break;
case CG_INT:
{
int val;
if (cgGetParameterValueic(cgParameter, 1, &val) != 1)
{
delete [] tmp;
tmp = 0;
break;
}
for (int k = 0; k < aDef->fSize; ++k)
{
tmp[k] = val;
}
}
break;
case CG_FLOAT:
{
if (aDef->fSize == 1)
{
float val;
if (cgGetParameterValuefc(cgParameter, 1, &val) != 1)
{
delete [] tmp;
tmp = 0;
break;
}
tmp[0] = val;
}
else if (aDef->fSize <= 4 || aDef->fType == kAttrTypeMatrix)
{
float val[16];
if (aDef->fType == kAttrTypeMatrix)
{
cgGetMatrixParameterfc(cgParameter, val);
}
else
{
unsigned int vecSize = aDef->fSize;
cgGetParameterValuefc(cgParameter, vecSize, val);
}
for (int k = 0; k < aDef->fSize; ++k)
{
tmp[k] = val[k];
}
}
}
break;
case CG_STRING:
{
#ifdef _WIN32
LPCSTR val;
#else
const char* val = NULL;
#endif
val = cgGetStringParameterValue(cgParameter);
aDef->fStringDef = val;
}
default:
delete [] tmp;
tmp = 0;
}
if ( tmp )
{
int k;
if ( aDef->fSize == 16 )
{
const double* d = &MMatrix::identity[0][0];
for ( k = 0; k < aDef->fSize; ++k )
if ( tmp[ k ] != d[ k ] )
break;
}
else
{
for ( k = 0; k < aDef->fSize; ++k )
if ( tmp[ k ] != 0.0 )
break;
}
if ( k == aDef->fSize )
{
delete [] tmp;
tmp = 0;
}
}
aDef->fNumericDef = tmp;
list->add(aDef);
cgParameter = cgGetNextParameter(cgParameter);
++i;
}
}
catch (...)
{
if (list)
{
list->release();
list = 0;
}
throw;
}
return list;
}
cgfxAttrDefList* cgfxAttrDef::attrsFromNode(MObject& oNode)
{
MStatus status;
cgfxAttrDefList* list = 0;
MFnDependencyNode fnNode(oNode, &status);
M_CHECK( status );
M_CHECK( fnNode.typeId() == cgfxShaderNode::sId );
cgfxShaderNode* pNode = (cgfxShaderNode *) fnNode.userNode();
M_CHECK( pNode );
list = pNode->attrDefList();
if (!list)
{
buildAttrDefList(oNode);
list = pNode->attrDefList();
}
return list;
}
void cgfxAttrDef::buildAttrDefList(MObject& oNode)
{
MStatus status;
cgfxAttrDefList* list = 0;
try
{
MFnDependencyNode fnNode(oNode, &status);
M_CHECK( status &&
fnNode.typeId() == cgfxShaderNode::sId );
cgfxShaderNode* pNode = (cgfxShaderNode *) fnNode.userNode();
M_CHECK( pNode &&
!pNode->attrDefList() );
list = new cgfxAttrDefList;
MStringArray saList;
pNode->getAttributeList(saList);
unsigned int i;
for (i = 0; i < saList.length(); ++i)
{
MString item = saList[i];
MStringArray splitItem;
MObject oAttr;
item.split('\t', splitItem);
cgfxAttrDef* attrDef = attrFromNode( fnNode,
splitItem[0],
(cgfxAttrType)(splitItem[1].asInt()),
splitItem[2],
splitItem[3]);
if ( attrDef )
{
list->add( attrDef );
}
}
pNode->setAttrDefList(list);
}
catch (...)
{
if (list)
{
list->release();
list = 0;
}
throw;
}
list->release();
}
cgfxAttrDef*
cgfxAttrDef::attrFromNode( const MFnDependencyNode& fnNode,
const MString& sAttrName,
const cgfxAttrType eAttrType,
const MString& sDescription,
const MString& sSemantic)
{
MStatus status;
cgfxAttrDef* attrDef = NULL;
try
{
MObject obNode = fnNode.object();
MObject obAttr = fnNode.attribute( sAttrName, &status );
if ( !status )
return NULL;
attrDef = new cgfxAttrDef;
attrDef->fName = sAttrName;
attrDef->fType = eAttrType;
attrDef->fDescription = sDescription;
attrDef->fSemantic = sSemantic;
attrDef->fAttr = obAttr;
MFnCompoundAttribute fnCompound;
MFnNumericAttribute fnNumeric;
MFnTypedAttribute fnTyped;
MPlug plug( obNode, obAttr );
double numericMin[4];
double numericMax[4];
double numericValue[4];
bool hasMin = false;
bool hasMax = false;
bool isNumeric = false;
if ( fnCompound.setObject( obAttr ) )
{
hasMin = true;
hasMax = true;
isNumeric = true;
MObject obChild;
MStringArray saChild;
int iChild;
int nChild = fnCompound.numChildren();
M_CHECK( nChild >= 2 && nChild <= 3 );
for ( iChild = 0; iChild < nChild; ++iChild )
{
if ( iChild < 3 )
{
obChild = fnCompound.child( iChild, &status );
M_CHECK( status );
}
status = fnNumeric.setObject( obChild );
M_CHECK( status );
if ( fnNumeric.hasMin() )
fnNumeric.getMin( numericMin[ iChild ] );
else
hasMin = false;
if ( fnNumeric.hasMax() )
fnNumeric.getMax( numericMax[ iChild ] );
else
hasMax = false;
MPlug plChild( obNode, obChild );
status = plChild.getValue( numericValue[ iChild ] );
M_CHECK( status );
saChild.append( fnNumeric.name() );
if ( iChild == 2 )
{
const char* suffix = NULL;
if ( saChild[0] == sAttrName + "X" &&
saChild[1] == sAttrName + "Y" &&
saChild[2] == sAttrName + "Z" )
suffix = "W";
else if ( saChild[0] == sAttrName + "R" &&
saChild[1] == sAttrName + "G" &&
saChild[2] == sAttrName + "B" )
suffix = "Alpha";
if ( suffix )
{
MString sName2 = sAttrName + suffix;
obChild = fnNode.attribute( sName2, &status );
MFnNumericData::Type ndt = fnNumeric.unitType();
if ( status &&
fnNumeric.setObject( obChild ) &&
fnNumeric.unitType() == ndt )
{
attrDef->fAttr2 = obChild;
nChild = 4;
}
}
}
}
attrDef->fSize = nChild;
}
else if ( fnNumeric.setObject( obAttr ) )
{
MFnNumericAttribute fnNumeric( obAttr, &status );
M_CHECK( status );
attrDef->fSize = 1;
isNumeric = true;
if ( fnNumeric.hasMin() )
{
fnNumeric.getMin( numericMin[0] );
hasMin = true;
}
if ( fnNumeric.hasMax() )
{
fnNumeric.getMax( numericMax[0] );
hasMax = true;
}
if ( fnNumeric.hasSoftMin() )
{
attrDef->fNumericSoftMin = new double[1];
fnNumeric.getSoftMin( attrDef->fNumericSoftMin[0] );
}
if ( fnNumeric.hasSoftMax() )
{
attrDef->fNumericSoftMax = new double[1];
fnNumeric.getSoftMax( attrDef->fNumericSoftMax[0] );
}
status = plug.getValue( numericValue[0] );
M_CHECK( status );
}
else if ( fnTyped.setObject( obAttr ) &&
fnTyped.attrType() == MFnData::kString )
{
attrDef->fSize = 1;
status = plug.getValue( attrDef->fStringDef );
M_CHECK( status );
}
else if ( fnTyped.setObject( obAttr ) &&
fnTyped.attrType() == MFnData::kMatrix )
{
MObject obData;
status = plug.getValue( obData );
M_CHECK( status );
MFnMatrixData fnMatrixData( obData, &status );
M_CHECK( status );
const MMatrix& mat = fnMatrixData.matrix( &status );
M_CHECK( status );
attrDef->fSize = 16;
attrDef->fNumericDef = new double[ attrDef->fSize ];
const double* p = &mat.matrix[0][0];
for ( int i = 0; i < 16; ++i )
attrDef->fNumericDef[ i ] = p[ i ];
M_CHECK( status );
}
else
M_CHECK( false );
if ( isNumeric )
{
attrDef->fNumericDef = new double[ attrDef->fSize ];
memcpy( attrDef->fNumericDef, numericValue, attrDef->fSize * sizeof( numericValue[0] ) );
if ( hasMin )
{
attrDef->fNumericMin = new double[ attrDef->fSize ];
memcpy( attrDef->fNumericMin, numericMin, attrDef->fSize * sizeof( numericMin[0] ) );
}
if ( hasMax )
{
attrDef->fNumericMax = new double[ attrDef->fSize ];
memcpy( attrDef->fNumericMax, numericMax, attrDef->fSize * sizeof( numericMax[0] ) );
}
}
attrDef->setAttributeFlags();
}
catch ( cgfxShaderCommon::InternalError* e )
{
size_t ee = (size_t)e;
MString sMsg = "(";
sMsg += (int)ee;
sMsg += ") cgfxShader node \"";
sMsg += fnNode.name();
sMsg += "\" has invalid attribute \"";
sMsg += sAttrName;
sMsg += "\" - ignored";
MGlobal::displayWarning( sMsg );
delete attrDef;
attrDef = NULL;
}
catch (...)
{
delete attrDef;
M_CHECK( false );
}
return attrDef;
}
bool
cgfxAttrDef::createAttribute( const MObject& oNode, MDGModifier* mod, cgfxShaderNode* pNode)
{
MFnDependencyNode fnNode( oNode );
MObject obExistingAttr = fnNode.attribute( fName );
if ( !obExistingAttr.isNull() )
{
return false;
}
try
{
MStatus status;
MObject oAttr, oAttr2;
MFnNumericAttribute nAttr;
MFnTypedAttribute tAttr;
MFnMatrixAttribute mAttr;
MObject oSrcNode, oDstNode;
MFnDependencyNode fnFile;
MObject oSrcAttr, oDstAttr;
bool doConnection = false;
switch (fType)
{
case kAttrTypeBool:
oAttr = nAttr.create( fName, fName, MFnNumericData::kBoolean,
0.0, &status );
M_CHECK( status );
nAttr.setKeyable( true );
nAttr.setAffectsAppearance( true );
break;
case kAttrTypeInt:
oAttr = nAttr.create( fName, fName, MFnNumericData::kInt,
0.0, &status );
M_CHECK( status );
nAttr.setKeyable( true );
nAttr.setAffectsAppearance( true );
break;
case kAttrTypeFloat:
oAttr = nAttr.create( fName, fName, MFnNumericData::kFloat,
0.0, &status );
M_CHECK( status );
nAttr.setKeyable( true );
nAttr.setAffectsAppearance( true );
break;
case kAttrTypeString:
oAttr = tAttr.create(fName, fName, MFnData::kString,
MObject::kNullObj, &status );
tAttr.setAffectsAppearance( true );
M_CHECK( status );
break;
case kAttrTypeVector2:
case kAttrTypeVector3:
case kAttrTypeVector4:
case kAttrTypeColor3:
case kAttrTypeColor4:
case kAttrTypeObjectDir:
case kAttrTypeWorldDir:
case kAttrTypeViewDir:
case kAttrTypeProjectionDir:
case kAttrTypeScreenDir:
case kAttrTypeObjectPos:
case kAttrTypeWorldPos:
case kAttrTypeViewPos:
case kAttrTypeProjectionPos:
case kAttrTypeScreenPos:
{
const char** suffixes = compoundAttrSuffixes( fType );
MString sChild;
MObject oaChildren[4];
M_CHECK( fSize <= 4 );
for ( int iChild = 0; iChild < fSize; ++iChild )
{
const char* suffix = suffixes[ iChild ];
sChild = fName + suffix;
oaChildren[ iChild ] = nAttr.create( sChild,
sChild,
MFnNumericData::kFloat,
0.0,
&status );
M_CHECK( status );
}
if ( fSize == 4 )
{
oAttr2 = oaChildren[3];
if ( fType == kAttrTypeColor3 ||
fType == kAttrTypeColor4 ||
fDescription.length() > 0 )
nAttr.setKeyable( true );
}
oAttr = nAttr.create( fName,
fName,
oaChildren[0],
oaChildren[1],
oaChildren[2],
&status );
M_CHECK( status );
if ( fType == kAttrTypeColor3 ||
fType == kAttrTypeColor4 )
{
nAttr.setKeyable( true );
nAttr.setUsedAsColor( true );
}
else if ( fDescription.length() > 0 )
nAttr.setKeyable( true );
nAttr.setAffectsAppearance( true );
break;
}
case kAttrTypeMatrix:
oAttr = mAttr.create(fName, fName,
MFnMatrixAttribute::kFloat, &status );
M_CHECK( status );
mAttr.setAffectsAppearance( true );
break;
case kAttrTypeWorldMatrix:
case kAttrTypeViewMatrix:
case kAttrTypeProjectionMatrix:
case kAttrTypeWorldViewMatrix:
case kAttrTypeWorldViewProjectionMatrix:
break;
case kAttrTypeColor1DTexture:
case kAttrTypeColor2DTexture:
case kAttrTypeColor3DTexture:
case kAttrTypeColor2DRectTexture:
case kAttrTypeNormalTexture:
case kAttrTypeBumpTexture:
case kAttrTypeCubeTexture:
case kAttrTypeEnvTexture:
case kAttrTypeNormalizationTexture:
if( pNode->getTexturesByName())
{
oAttr = tAttr.create(fName, fName, MFnData::kString,
MObject::kNullObj, &status );
M_CHECK( status );
tAttr.setAffectsAppearance( true );
}
else
{
const char* suffix1 = "R";
const char* suffix2 = "G";
const char* suffix3 = "B";
MObject oChild1 = nAttr.create(fName + suffix1,
fName + suffix1,
MFnNumericData::kFloat,
0.0, &status);
MObject oChild2 = nAttr.create(fName + suffix2,
fName + suffix2,
MFnNumericData::kFloat,
0.0, &status);
MObject oChild3 = nAttr.create(fName + suffix3,
fName + suffix3,
MFnNumericData::kFloat,
0.0, &status);
oAttr = nAttr.create( fName,
fName,
oChild1,
oChild2,
oChild3,
&status );
M_CHECK( status );
nAttr.setUsedAsColor( true );
nAttr.setAffectsAppearance( true );
}
break;
#ifdef _WIN32
case kAttrTypeTime:
#endif
case kAttrTypeOther:
break;
default:
M_CHECK( false );
}
if (oAttr.isNull())
{
return false;
}
status = mod->addAttribute( oNode, oAttr );
M_CHECK( status );
if (!oAttr2.isNull())
{
status = mod->addAttribute( oNode, oAttr2 );
M_CHECK( status );
}
fAttr = oAttr;
fAttr2 = oAttr2;
if (doConnection)
{
status = mod->connect(oSrcNode, oSrcAttr, oDstNode, oDstAttr);
M_CHECK( status );
}
return true;
}
catch ( cgfxShaderCommon::InternalError* e )
{
size_t ee = (size_t)e;
fType = kAttrTypeUnknown;
MString sMsg = "(";
sMsg += (int)ee;
sMsg += ") cgfxShader node \"";
sMsg += fnNode.name();
sMsg += "\": unable to add attribute \"";
sMsg += fName;
sMsg += "\"";
MGlobal::displayWarning( sMsg );
return false;
}
catch (...)
{
M_CHECK( false );
}
return true;
}
bool
cgfxAttrDef::destroyAttribute( MObject& oNode, MDGModifier* dgMod)
{
MStatus status;
if( fType >= kAttrTypeFirstTexture && fType <= kAttrTypeLastTexture)
setTexture( oNode, "", dgMod);
status = dgMod->removeAttribute( oNode, fAttr );
if ( !fAttr2.isNull() )
status = dgMod->removeAttribute( oNode, fAttr2 );
fAttr = MObject::kNullObj;
fAttr2 = MObject::kNullObj;
return status == MStatus::kSuccess;
}
void
cgfxAttrDef::updateNode( CGeffect effect,
cgfxShaderNode* pNode,
MDGModifier* dgMod,
cgfxAttrDefList*& effectList,
MStringArray& attributeList )
{
MStatus status;
effectList = NULL;
try
{
MObject oNode = pNode->thisMObject();
MFnDependencyNode fnNode( oNode );
MFnAttribute fnAttr;
effectList = attrsFromEffect( effect, cgGetNamedTechnique(effect, pNode->getTechnique().asChar()) );
cgfxAttrDefList* nodeList = attrsFromNode( oNode );
cgfxAttrDefList::iterator emIt;
cgfxAttrDefList::iterator nmIt;
cgfxAttrDef* adef;
for (nmIt = nodeList->begin(); nmIt; ++nmIt)
{
adef = (*nmIt);
if ( adef->fAttr.isNull() )
continue;
emIt = effectList->find( adef->fName );
if ( !emIt ||
(*emIt)->fType != adef->fType )
{
adef->destroyAttribute( oNode, dgMod);
}
else if( emIt &&
(*emIt)->fType >= kAttrTypeFirstTexture &&
(*emIt)->fType <= kAttrTypeLastTexture)
{
MFnTypedAttribute typedFn( adef->fAttr);
bool usesName = typedFn.attrType() == MFnData::kString;
pNode->setTexturesByName( usesName);
if( !usesName)
(*emIt)->fTweaked = true;
}
}
dgMod->doIt();
for (emIt = effectList->begin(); emIt; ++emIt)
{
adef = (*emIt);
nmIt = nodeList->find( adef->fName );
cgfxAttrDef* cdef = NULL;
if ( nmIt &&
!(*nmIt)->fAttr.isNull() )
cdef = attrFromNode( fnNode,
(*nmIt)->fName,
(*nmIt)->fType,
(*nmIt)->fDescription,
(*nmIt)->fSemantic);
if ( !cdef )
adef->createAttribute( oNode, dgMod, pNode );
else
{
adef->fAttr = (*nmIt)->fAttr;
adef->fAttr2 = (*nmIt)->fAttr2;
if ( (*nmIt)->fTweaked )
adef->fTweaked = true;
else if ( !pNode->effect() )
{
if ( !adef->isInitialValueEqual( *cdef ) )
adef->fTweaked = true;
}
else if ( !(*nmIt)->isInitialValueEqual( *cdef ) )
adef->fTweaked = true;
else
(*nmIt)->fInitOnUndo = true;
delete cdef;
}
}
MString tmpStr;
attributeList.clear();
cgfxAttrDefList::iterator it(effectList);
while (it)
{
cgfxAttrDef* aDef = *it;
tmpStr = aDef->fName;
tmpStr += "\t";
tmpStr += (int)aDef->fType;
tmpStr += "\t";
tmpStr += aDef->fDescription;
tmpStr += "\t";
tmpStr += aDef->fSemantic;
const char* bp = tmpStr.asChar();
const char* ep;
for ( ep = bp + tmpStr.length(); bp < ep; --ep )
if ( ep[-1] != '\t' )
break;
attributeList.append( MString( bp, (int)(ep - bp) ) );
++it;
}
}
catch ( cgfxShaderCommon::InternalError* )
{
if ( effectList )
effectList->release();
effectList = NULL;
throw;
}
catch (...)
{
if ( effectList )
effectList->release();
effectList = NULL;
M_CHECK( false );
}
}
bool
cgfxAttrDef::isInitialValueEqual( const cgfxAttrDef& that ) const
{
if ( fStringDef != that.fStringDef )
return false;
const double* thisNumericDef = fNumericDef;
const double* thatNumericDef = that.fNumericDef;
if ( thisNumericDef == thatNumericDef )
return true;
if( fType == that.fType && fType >= kAttrTypeFirstTexture && fType <= kAttrTypeLastTexture)
return true;
if ( !thisNumericDef )
{
thisNumericDef = thatNumericDef;
thatNumericDef = fNumericDef;
}
if ( !thatNumericDef )
{
if ( fType == kAttrTypeMatrix )
{
thatNumericDef = &MMatrix::identity.matrix[0][0];
M_CHECK( fSize == 16 && that.fSize == 16 );
}
else
{
static const double d0[4] = {0.0, 0.0, 0.0, 0.0};
thatNumericDef = d0;
M_CHECK( fSize <= sizeof(d0)/sizeof(d0[0]) );
if ( fSize != that.fSize )
MGlobal::displayWarning( "CgFX attribute size mismatch" );
}
}
double eps = 0.0001;
int i;
for ( i = 0; i < fSize; ++i )
if ( thisNumericDef[ i ] + eps < thatNumericDef[ i ] ||
thatNumericDef[ i ] + eps < thisNumericDef[ i ] )
return false;
return true;
}
void
cgfxAttrDef::setInitialValue( const cgfxAttrDef& from )
{
if ( from.fNumericDef )
{
M_CHECK( fSize == from.fSize );
if ( !fNumericDef )
fNumericDef = new double[ fSize ];
memcpy( fNumericDef, from.fNumericDef, fSize * sizeof( *fNumericDef ) );
}
else
{
delete fNumericDef;
fStringDef = from.fStringDef;
}
}
void cgfxAttrDef::setAttributeFlags()
{
MFnAttribute attribute;
if(!attribute.setObject(fAttr))
return ;
switch (fType)
{
case kAttrTypeColor3:
case kAttrTypeColor4:
attribute.setKeyable( true );
attribute.setUsedAsColor( true );
attribute.setAffectsAppearance( true );
break;
case kAttrTypeBool:
case kAttrTypeInt:
case kAttrTypeFloat:
attribute.setKeyable( true );
attribute.setAffectsAppearance( true );
break;
case kAttrTypeVector2:
case kAttrTypeVector3:
case kAttrTypeVector4:
case kAttrTypeObjectDir:
case kAttrTypeWorldDir:
case kAttrTypeViewDir:
case kAttrTypeProjectionDir:
case kAttrTypeScreenDir:
case kAttrTypeObjectPos:
case kAttrTypeWorldPos:
case kAttrTypeViewPos:
case kAttrTypeProjectionPos:
case kAttrTypeScreenPos:
if( fDescription.length() > 0)
attribute.setKeyable( true );
attribute.setAffectsAppearance( true );
break;
case kAttrTypeString:
case kAttrTypeMatrix:
attribute.setAffectsAppearance( true );
break;
case kAttrTypeWorldMatrix:
case kAttrTypeViewMatrix:
case kAttrTypeProjectionMatrix:
case kAttrTypeWorldViewMatrix:
case kAttrTypeWorldViewProjectionMatrix:
break;
case kAttrTypeColor1DTexture:
case kAttrTypeColor2DTexture:
case kAttrTypeColor3DTexture:
case kAttrTypeColor2DRectTexture:
case kAttrTypeNormalTexture:
case kAttrTypeBumpTexture:
case kAttrTypeCubeTexture:
case kAttrTypeEnvTexture:
case kAttrTypeNormalizationTexture:
attribute.setAffectsAppearance( true );
break;
#ifdef _WIN32
case kAttrTypeTime:
#endif
case kAttrTypeOther:
break;
default:
M_CHECK( false );
}
}
void
cgfxAttrDef::initializeAttributes( MObject& oNode, cgfxAttrDefList* list, bool bUndoing, MDGModifier* dgMod )
{
MStatus status;
MFnMatrixAttribute fnMatrix;
MFnNumericAttribute fnNumeric;
MFnTypedAttribute fnTyped;
for ( cgfxAttrDefList::iterator it( list ); it; ++it )
{
cgfxAttrDef* aDef = (*it);
if ( aDef->fAttr.isNull() )
continue;
bool bSetValue = bUndoing ? aDef->fInitOnUndo
: !aDef->fTweaked;
try
{
if ( aDef->fType == kAttrTypeBool )
{
if ( bSetValue )
aDef->setValue( oNode, aDef->fNumericDef && aDef->fNumericDef[0] );
}
else if( aDef->fType >= kAttrTypeFirstTexture &&
aDef->fType <= kAttrTypeLastTexture)
{
if ( bSetValue )
aDef->setTexture( oNode, aDef->fStringDef, dgMod);
}
else if ( fnNumeric.setObject( aDef->fAttr ) )
{
double vMin = -FLT_MAX;
double vMax = FLT_MAX;
if ( aDef->fType == kAttrTypeInt )
{
vMin = INT_MIN;
vMax = INT_MAX;
}
switch ( aDef->fSize )
{
case 1:
if ( aDef->fNumericMin )
fnNumeric.setMin( aDef->fNumericMin[0] );
else if ( fnNumeric.hasMin() )
fnNumeric.setMin( vMin );
if ( aDef->fNumericMax )
fnNumeric.setMax( aDef->fNumericMax[0] );
else if ( fnNumeric.hasMax() )
fnNumeric.setMax( vMax );
if ( aDef->fNumericSoftMin )
fnNumeric.setSoftMin( aDef->fNumericSoftMin[0] );
else if ( fnNumeric.hasSoftMin() )
fnNumeric.setSoftMin( vMin );
if ( aDef->fNumericSoftMax )
fnNumeric.setSoftMax( aDef->fNumericSoftMax[0] );
else if ( fnNumeric.hasSoftMax() )
fnNumeric.setSoftMax( vMax );
break;
case 2:
if ( aDef->fNumericMin )
fnNumeric.setMin( aDef->fNumericMin[0],
aDef->fNumericMin[1] );
else if ( fnNumeric.hasMin() )
fnNumeric.setMin( vMin, vMin );
if ( aDef->fNumericMax )
fnNumeric.setMax( aDef->fNumericMax[0],
aDef->fNumericMax[1] );
else if ( fnNumeric.hasMax() )
fnNumeric.setMax( vMax, vMax );
break;
case 3:
case 4:
if ( aDef->fNumericMin )
fnNumeric.setMin( aDef->fNumericMin[0],
aDef->fNumericMin[1],
aDef->fNumericMin[2] );
else if ( fnNumeric.hasMin() )
fnNumeric.setMin( vMin, vMin, vMin );
if ( aDef->fNumericMax )
fnNumeric.setMax( aDef->fNumericMax[0],
aDef->fNumericMax[1],
aDef->fNumericMax[2] );
else if ( fnNumeric.hasMax() )
fnNumeric.setMax( vMax, vMax, vMax );
break;
default:
M_CHECK( false );
}
if ( bSetValue )
{
static const double d0[4] = {0.0, 0.0, 0.0, 0.0};
const double* pNumericDef = aDef->fNumericDef ? aDef->fNumericDef
: d0;
switch ( aDef->fSize )
{
case 1:
if ( aDef->fType == kAttrTypeInt )
aDef->setValue( oNode, (int)pNumericDef[0] );
else
aDef->setValue( oNode, (float)pNumericDef[0] );
break;
case 2:
aDef->setValue( oNode,
(float)pNumericDef[0],
(float)pNumericDef[1] );
break;
case 3:
aDef->setValue( oNode,
(float)pNumericDef[0],
(float)pNumericDef[1],
(float)pNumericDef[2] );
break;
case 4:
status = fnNumeric.setObject( aDef->fAttr2 );
M_CHECK( status );
if ( aDef->fNumericMin )
fnNumeric.setMin( aDef->fNumericMin[3] );
else if ( fnNumeric.hasMin() )
fnNumeric.setMin( vMin );
if ( aDef->fNumericMax )
fnNumeric.setMax( aDef->fNumericMax[3] );
else if ( fnNumeric.hasMax() )
fnNumeric.setMax( vMax );
aDef->setValue( oNode,
(float)pNumericDef[0],
(float)pNumericDef[1],
(float)pNumericDef[2],
(float)pNumericDef[3] );
break;
default:
M_CHECK( false );
}
}
}
else if ( fnTyped.setObject( aDef->fAttr ) &&
fnTyped.attrType() == MFnData::kString )
{
if ( bSetValue )
aDef->setValue( oNode, aDef->fStringDef );
}
else if ( fnMatrix.setObject( aDef->fAttr ) )
{
if ( !bSetValue )
{}
else if ( aDef->fNumericDef )
{
MMatrix m;
double* p = &m.matrix[0][0];
for ( int k = 0; k < 16; ++k )
p[ k ] = aDef->fNumericDef[ k ];
aDef->setValue( oNode, m );
}
else
aDef->setValue( oNode, MMatrix::identity );
}
}
catch ( cgfxShaderCommon::InternalError* e )
{
size_t ee = (size_t)e;
MFnDependencyNode fnNode( oNode );
MString sMsg = "(";
sMsg += (int)ee;
sMsg += ") cgfxShader node \"";
sMsg += fnNode.name();
sMsg += "\": unable to initialize attribute \"";
sMsg += aDef->fName;
sMsg += "\"";
MGlobal::displayWarning( sMsg );
}
}
}
void cgfxAttrDef::purgeMObjectCache( cgfxAttrDefList* list )
{
cgfxAttrDefList::iterator it( list );
for ( ; it; ++it )
{
cgfxAttrDef* aDef = (*it);
aDef->fAttr = MObject::kNullObj;
aDef->fAttr2 = MObject::kNullObj;
}
}
void cgfxAttrDef::validateMObjectCache( const MObject& obCgfxShader,
cgfxAttrDefList* list )
{
MStatus status;
MString sName2;
MFnDependencyNode fnNode( obCgfxShader, &status );
cgfxAttrDefList::iterator it( list );
for ( ; it; ++it )
{
cgfxAttrDef* aDef = (*it);
aDef->fAttr = fnNode.attribute( aDef->fName, &status );
const char* suffix = aDef->getExtraAttrSuffix();
if ( suffix )
aDef->fAttr2 = fnNode.attribute( aDef->fName + suffix, &status );
}
}
const char*
cgfxAttrDef::getExtraAttrSuffix() const
{
if ( fSize == 4 )
return compoundAttrSuffixes( fType )[ 3 ];
return NULL;
}
const char* cgfxAttrDef::typeName( cgfxAttrType type )
{
#define CASE(name) case kAttrType##name: return #name
switch (type)
{
default:
CASE(Unknown);
CASE(Bool);
CASE(Int);
CASE(Float);
CASE(String);
CASE(Vector2);
CASE(Vector3);
CASE(Vector4);
CASE(ObjectDir);
CASE(WorldDir);
CASE(ViewDir);
CASE(ProjectionDir);
CASE(ScreenDir);
CASE(ObjectPos);
CASE(WorldPos);
CASE(ViewPos);
CASE(ProjectionPos);
CASE(ScreenPos);
CASE(Color3);
CASE(Color4);
CASE(Matrix);
CASE(WorldMatrix);
CASE(ViewMatrix);
CASE(ProjectionMatrix);
CASE(WorldViewMatrix);
CASE(WorldViewProjectionMatrix);
CASE(Color1DTexture);
CASE(Color2DTexture);
CASE(Color3DTexture);
CASE(Color2DRectTexture);
CASE(NormalTexture);
CASE(BumpTexture);
CASE(CubeTexture);
CASE(EnvTexture);
CASE(NormalizationTexture);
#ifdef _WIN32
CASE(Time);
#endif
CASE(Other);
}
}
const char**
cgfxAttrDef::compoundAttrSuffixes( cgfxAttrType eAttrType )
{
static const char* simple[] = { NULL, NULL, NULL, NULL, NULL };
static const char* vector[] = { "X", "Y", "Z", "W", NULL };
static const char* color[] = { "R", "G", "B", "Alpha", NULL };
const char** p;
switch ( eAttrType )
{
case kAttrTypeVector2:
case kAttrTypeVector3:
case kAttrTypeVector4:
case kAttrTypeObjectDir:
case kAttrTypeWorldDir:
case kAttrTypeViewDir:
case kAttrTypeProjectionDir:
case kAttrTypeScreenDir:
case kAttrTypeObjectPos:
case kAttrTypeWorldPos:
case kAttrTypeViewPos:
case kAttrTypeProjectionPos:
case kAttrTypeScreenPos:
p = vector;
break;
case kAttrTypeColor3:
case kAttrTypeColor4:
p = color;
break;
default:
p = simple;
break;
}
return p;
}
void
cgfxAttrDef::getValue( MObject& oNode, bool& value ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.getValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::getValue( MObject& oNode, int& value ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.getValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::getValue( MObject& oNode, float& value ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.getValue(value);
if( fUnits != MDistance::kInvalid)
{
value = (float)MDistance( value, fUnits).as( MDistance::internalUnit());
}
M_CHECK( status );
}
void
cgfxAttrDef::getValue( MObject& oNode, MString& value ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.getValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::getValue( MObject& oNode, float& v1, float& v2 ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
MObject oData;
status = plug.getValue(oData);
M_CHECK( status );
MFnNumericData fnData(oData, &status);
M_CHECK( status );
status = fnData.getData(v1, v2);
M_CHECK( status );
if( fUnits != MDistance::kInvalid)
{
v1 = (float)MDistance( v1, fUnits).as( MDistance::internalUnit());
v2 = (float)MDistance( v2, fUnits).as( MDistance::internalUnit());
}
}
void
cgfxAttrDef::getValue( MObject& oNode,
float& v1, float& v2, float& v3 ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
MObject oData;
status = plug.getValue(oData);
M_CHECK( status );
MFnNumericData fnData(oData, &status);
M_CHECK( status );
status = fnData.getData(v1, v2, v3);
M_CHECK( status );
if( fUnits != MDistance::kInvalid)
{
v1 = (float)MDistance( v1, fUnits).as( MDistance::internalUnit());
v2 = (float)MDistance( v2, fUnits).as( MDistance::internalUnit());
v3 = (float)MDistance( v3, fUnits).as( MDistance::internalUnit());
}
}
void
cgfxAttrDef::getValue( MObject& oNode,
float& v1, float& v2, float& v3, float& v4 ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
MPlug plug2(oNode, fAttr2);
MObject oData;
status = plug.getValue(oData);
M_CHECK( status );
MFnNumericData fnData(oData, &status);
M_CHECK( status );
status = fnData.getData(v1, v2, v3);
M_CHECK( status );
status = plug2.getValue(v4);
M_CHECK( status );
if( fUnits != MDistance::kInvalid)
{
v1 = (float)MDistance( v1, fUnits).as( MDistance::internalUnit());
v2 = (float)MDistance( v2, fUnits).as( MDistance::internalUnit());
v3 = (float)MDistance( v3, fUnits).as( MDistance::internalUnit());
v4 = (float)MDistance( v4, fUnits).as( MDistance::internalUnit());
}
}
void
cgfxAttrDef::getValue( MObject& oNode, MMatrix& value ) const
{
MStatus status;
MPlug plug(oNode, fAttr);
MObject oData;
status = plug.getValue(oData);
M_CHECK( status );
MFnMatrixData fnData(oData, &status);
M_CHECK( status );
value = fnData.matrix(&status);
M_CHECK( status );
}
void
cgfxAttrDef::getValue( MObject& oNode, MImage& value ) const
{
MStatus status = MS::kFailure;
MPlug plug(oNode, fAttr);
if (fType >= kAttrTypeFirstTexture &&
fType <= kAttrTypeLastTexture)
{
MPlugArray plugArray;
plug.connectedTo(plugArray, true, false, &status);
M_CHECK( status );
if (plugArray.length() != 1)
M_CHECK( status );
MPlug srcPlug = plugArray[0];
MObject oSrcNode = srcPlug.node();
value.release();
status = value.readFromTextureNode(oSrcNode);
M_CHECK( status );
}
M_CHECK( status );
}
void
cgfxAttrDef::getSource( MObject& oNode, MPlug& src) const
{
MStatus status = MS::kFailure;
MPlug plug(oNode, fAttr);
MPlugArray plugArray;
plug.connectedTo(plugArray, true, false, &status);
M_CHECK( status && plugArray.length() <= 1);
if (plugArray.length() == 1)
src = plugArray[0];
}
void
cgfxAttrDef::setValue( MObject& oNode, bool value )
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.setValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, int value )
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.setValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, float value )
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.setValue(value);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, const MString& value )
{
MStatus status;
MPlug plug(oNode, fAttr);
status = plug.setValue((MString &)value);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, float v1, float v2 )
{
MStatus status;
MPlug plug(oNode, fAttr);
MFnNumericData fnData;
MObject oData = fnData.create(MFnNumericData::k2Float, &status);
M_CHECK( status );
fnData.setData(v1, v2);
status = plug.setValue(oData);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, float v1, float v2, float v3 )
{
MStatus status;
MPlug plug(oNode, fAttr);
MFnNumericData fnData;
MObject oData = fnData.create(MFnNumericData::k3Float, &status);
M_CHECK( status );
fnData.setData(v1, v2, v3);
status = plug.setValue(oData);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, float v1, float v2, float v3, float v4 )
{
MStatus status;
MPlug plug(oNode, fAttr);
MPlug plug2(oNode, fAttr2);
MFnNumericData fnData;
MObject oData = fnData.create(MFnNumericData::k3Float, &status);
M_CHECK( status );
fnData.setData(v1, v2, v3);
status = plug.setValue(oData);
M_CHECK( status );
status = plug2.setValue(v4);
M_CHECK( status );
}
void
cgfxAttrDef::setValue( MObject& oNode, const MMatrix& v )
{
MStatus status;
MFnMatrixData fnData;
MObject oData = fnData.create( v, &status );
M_CHECK( status );
MPlug plug( oNode, fAttr );
status = plug.setValue( oData );
M_CHECK( status );
}
bool isUsedElsewhere( MObject node, MObject user)
{
for( MItDependencyGraph iter( node); !iter.isDone(); iter.next())
{
if( iter.thisNode() != node)
{
if( iter.thisNode() != user)
{
MPlugArray src;
iter.thisPlug().connectedTo( src, true, false);
if( src.length() == 1 && src[ 0].partialName() != "msg")
{
MFnDependencyNode dgFn( iter.thisNode());
if( dgFn.name() != "swatchShadingGroup")
{
return true;
}
}
}
iter.prune();
}
}
return false;
}
void
cgfxAttrDef::setTexture( MObject& oNode, const MString& value, MDGModifier* dgMod)
{
MStatus status;
MPlug plug(oNode, fAttr);
MFnAttribute attrFn( fAttr);
if( attrFn.isUsedAsColor() )
{
if( plug.isConnected())
{
MPlugArray src;
plug.connectedTo( src, true, false, &status);
M_CHECK( status );
if( src.length() > 0)
{
MObject textureNode = src[ 0].node();
if( !isUsedElsewhere( textureNode, oNode))
{
MFnDependencyNode textureFn( textureNode);
MPlug uvPlug = textureFn.findPlug( "uv", &status);
if( status == MS::kSuccess)
{
MPlugArray placementNode;
uvPlug.connectedTo( placementNode, true, false, &status);
M_CHECK( status );
if( placementNode.length() > 0 &&
!isUsedElsewhere( placementNode[ 0].node(), textureNode))
M_CHECK( dgMod->deleteNode( placementNode[ 0].node()) );
}
M_CHECK( dgMod->deleteNode( textureNode) );
}
else
{
M_CHECK( dgMod->disconnect( src[ 0], plug) );
}
}
}
if( value.length() > 0)
{
MString relativePath = cgfxFindFile( value, true );
if( relativePath.length() == 0) relativePath = value;
MObject textureNode, placementNode;
MSelectionList originalSelection, newlyCreatedNode;
MGlobal::getActiveSelectionList( originalSelection);
MGlobal::executeCommand( "shadingNode -asTexture file", false, true);
MGlobal::getActiveSelectionList( newlyCreatedNode);
M_CHECK( newlyCreatedNode.length() > 0 && newlyCreatedNode.getDependNode( 0, textureNode));
MGlobal::executeCommand( "shadingNode -asUtility place2dTexture", false, true);
MGlobal::getActiveSelectionList( newlyCreatedNode);
M_CHECK( newlyCreatedNode.length() > 0 && newlyCreatedNode.getDependNode( 0, placementNode));
MGlobal::setActiveSelectionList( originalSelection);
MFnDependencyNode fileTextureFn( textureNode, &status);
M_CHECK( status );
MFnDependencyNode placementFn( placementNode, &status);
M_CHECK( status );
M_CHECK( dgMod->connect( placementFn.findPlug( "coverage"), fileTextureFn.findPlug( "coverage")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "translateFrame"), fileTextureFn.findPlug( "translateFrame")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "rotateFrame"), fileTextureFn.findPlug( "rotateFrame")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "mirrorU"), fileTextureFn.findPlug( "mirrorU")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "mirrorV"), fileTextureFn.findPlug( "mirrorV")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "stagger"), fileTextureFn.findPlug( "stagger")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "wrapU"), fileTextureFn.findPlug( "wrapU")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "wrapV"), fileTextureFn.findPlug( "wrapV")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "repeatUV"), fileTextureFn.findPlug( "repeatUV")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "offset"), fileTextureFn.findPlug( "offset")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "rotateUV"), fileTextureFn.findPlug( "rotateUV")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "noiseUV"), fileTextureFn.findPlug( "noiseUV")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "vertexUvOne"), fileTextureFn.findPlug( "vertexUvOne")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "vertexUvTwo"), fileTextureFn.findPlug( "vertexUvTwo")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "vertexUvThree"), fileTextureFn.findPlug( "vertexUvThree")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "vertexCameraOne"), fileTextureFn.findPlug( "vertexCameraOne")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "outUV"), fileTextureFn.findPlug( "uv")) );
M_CHECK( dgMod->connect( placementFn.findPlug( "outUvFilterSize"), fileTextureFn.findPlug( "uvFilterSize")) );
M_CHECK( dgMod->connect( fileTextureFn.findPlug( "outColor"), plug) );
status = fileTextureFn.findPlug( "fileTextureName").setValue( relativePath);
M_CHECK( status );
}
M_CHECK( dgMod->doIt() );
}
else
{
MFnTypedAttribute fnTyped;
if( fnTyped.setObject( fAttr ) &&
fnTyped.attrType() == MFnData::kString )
{
status = plug.setValue((MString &)value);
M_CHECK( status );
}
}
}
cgfxAttrDefList::iterator
cgfxAttrDefList::findInsensitive( const MString& name )
{
const char* pName = name.asChar();
unsigned lName = name.length();
iterator it( this );
for ( ; it; ++it )
if ( lName == (*it)->fName.length() &&
0 == stricmp( pName, (*it)->fName.asChar() ) )
break;
return it;
};
void cgfxAttrDefList::release()
{
--refcount;
if (refcount <= 0)
{
delete this;
}
else
{
iterator it(this);
while (it)
{
(*it)->release();
++it;
}
}
};