#include <maya/MFnStringData.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MGlobal.h>
#include <maya/MDGModifier.h>
#include <maya/MImage.h>
#include <maya/MPlugArray.h>
#include <maya/MFileIO.h>
#include <maya/MMatrix.h>
#include <maya/MFnMesh.h>
#include <maya/MString.h>
#include <maya/MStringResource.h>
#include <maya/MStringResourceId.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#include "Platform.h"
#include "GLSLShaderNode.h"
#include "AshliShaderStrings.h"
#include "glExtensions.h"
#include "ResourceManager.h"
#include <maya/MHWShaderSwatchGenerator.h>
#include <maya/MHardwareRenderer.h>
#include <maya/MGeometryData.h>
#include <maya/MImage.h>
MTypeId glslShaderNode::sId( 0x81022);
MObject glslShaderNode::sShader;
MObject glslShaderNode::sTechnique;
MObject glslShaderNode::sTechniqueList;
MObject glslShaderNode::sShaderPath;
MObject glslShaderNode::sNakedTexCoords[8];
MObject glslShaderNode::sNakedColors[2];
shader *glslShaderNode::sDefShader = NULL;
std::vector<glslShaderNode*> glslShaderNode::sNodeList;
const char *glslShaderNode::nakedSetNames[8] = { "map1", "tangent", "binormal", "", "", "", "", ""};
glslShaderNode::glslShaderNode() : m_shader(NULL), m_shaderDirty(false), m_parsedUserAttribList( false) {
InitializeExtensions();
for (int ii=0; ii<8; ii++) {
m_nakedTexSets[ii] = nakedSetNames[ii];
m_setNums[ii] = -1;
m_mayaType[ii] = kNonMaya;
}
}
glslShaderNode::~glslShaderNode() {
if (MGlobal::mayaState() != MGlobal::kBatch)
{
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (pRenderer)
{
const MString & backEndStr = pRenderer->backEndString();
MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
if (status != MStatus::kSuccess) {
MStatus strStat;
MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
MGlobal::displayError(status.errorString());
}
}
}
for (std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin(); it<m_samplerAttribList.end(); it++) {
ResourceManager::destroyTexture( it->texName);
}
{
std::vector<glslShaderNode*>::iterator it = std::find( sNodeList.begin(), sNodeList.end(), this);
if (it != sNodeList.end()) {
sNodeList.erase(it);
}
else {
}
}
delete m_shader;
}
void glslShaderNode::postConstructor() {
}
MStatus glslShaderNode::compute( const MPlug& plug, MDataBlock& data) {
if ((plug == outColor) || (plug.parent() == outColor))
{
MFloatVector color(.95f, .1f, .07f);
MDataHandle outputHandle = data.outputValue( outColor );
outputHandle.asFloatVector() = color;
outputHandle.setClean();
return MS::kSuccess;
}
return MS::kUnknownParameter;
}
void* glslShaderNode::creator() {
glslShaderNode *ret = new glslShaderNode;
sNodeList.push_back(ret);
return ret;
}
MStatus glslShaderNode::initialize() {
MFnTypedAttribute typedAttr;
MFnStringData stringData;
MStatus stat;
MObject string;
string = stringData.create(&stat);
if (stat != MS::kSuccess)
return MS::kFailure;
sShader = typedAttr.create("shader", "s", MFnData::kString, string, &stat);
if (stat != MS::kSuccess)
return MS::kFailure;
stat = typedAttr.setInternal(true);
if (stat != MS::kSuccess)
return MS::kFailure;
if ( addAttribute(sShader) != MS::kSuccess)
return MS::kFailure;
string = stringData.create(&stat);
if (stat != MS::kSuccess)
return MS::kFailure;
sTechnique = typedAttr.create("technique", "t", MFnData::kString, string, &stat);
if (stat != MS::kSuccess)
return MS::kFailure;
stat = typedAttr.setInternal(true);
if (stat != MS::kSuccess)
return MS::kFailure;
if ( addAttribute(sTechnique) != MS::kSuccess)
return MS::kFailure;
sTechniqueList = typedAttr.create("techniqueList", "tl", MFnData::kString, string, &stat);
if (stat != MS::kSuccess)
return MS::kFailure;
stat = typedAttr.setInternal(true);
if (stat != MS::kSuccess)
return MS::kFailure;
typedAttr.setWritable( false );
typedAttr.setStorable( false );
typedAttr.setHidden( true );
typedAttr.setConnectable( false );
if ( addAttribute(sTechniqueList) != MS::kSuccess)
return MS::kFailure;
sShaderPath = typedAttr.create("shaderPath", "sp", MFnData::kString, string, &stat);
if (stat != MS::kSuccess)
return MS::kFailure;
stat = typedAttr.setInternal(true);
if (stat != MS::kSuccess)
return MS::kFailure;
typedAttr.setWritable( false );
typedAttr.setStorable( false );
typedAttr.setHidden( true );
typedAttr.setConnectable( false );
if ( addAttribute(sShaderPath) != MS::kSuccess)
return MS::kFailure;
int ii;
for (ii=0; ii<8; ii++) {
string = stringData.create( MString(nakedSetNames[ii]));
sNakedTexCoords[ii] = typedAttr.create( MString("TexCoord") + ii, MString("t")+ ii, MFnData::kString, string);
typedAttr.setInternal( true);
typedAttr.setKeyable( true );
addAttribute( sNakedTexCoords[ii]);
}
for (ii=0; ii<2; ii++) {
sNakedColors[ii] = typedAttr.create( MString("Color") + ii, MString("c")+ ii, MFnData::kString);
typedAttr.setInternal( true);
typedAttr.setKeyable( true );
addAttribute( sNakedColors[ii]);
}
return MS::kSuccess;
}
void glslShaderNode::rejigShaders( void *data) {
for (std::vector<glslShaderNode*>::iterator it = sNodeList.begin(); it < sNodeList.end(); it++) {
(*it)->rebuildShader();
}
}
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;
}
bool glslShaderNode::rebuildShader()
{
bool rebuiltAnything = false;
GL_CHECK;
if (m_shaderDirty) {
MGlobal::displayInfo(MString("Rebuild shader : ") + m_shaderPath.asChar() );
delete m_shader;
GL_CHECK;
m_shader = shader::create(m_shaderPath.asChar());
GL_CHECK;
if (!m_shader) {
MStatus strStat;
MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedLoadShader, strStat));
MGlobal::displayError(shader::sError.c_str());
}
else {
rebuiltAnything = true;
bool foundExistingTechnique = false;
if (m_techniqueName.length())
{
for (int ii=0; ii<m_shader->techniqueCount(); ii++) {
if (m_techniqueName == m_shader->techniqueName(ii)) {
m_shader->setTechnique(ii);
foundExistingTechnique = true;
break;
}
}
}
if (!foundExistingTechnique)
{
m_techniqueName = m_shader->techniqueName(0);
}
m_techniqueList = m_techniqueName ;
for (int ii=1; ii<m_shader->techniqueCount(); ii++)
m_techniqueList = m_techniqueList + " " + m_shader->techniqueName(ii);
configureAttribs();
GL_CHECK;
}
m_shaderDirty = false;
}
m_techniqueList = "";
if (m_shader && m_shader->techniqueCount())
{
for (int ii=0; ii<m_shader->techniqueCount(); ii++)
m_techniqueList = m_techniqueList + " " + m_shader->techniqueName(ii);
}
return rebuiltAnything;
}
MObject glslShaderNode::findFileTextureNode( const MPlug &plug) {
MPlugArray arr;
MStatus stat;
plug.connectedTo(arr, true, false, &stat);
MObject srcNode;
if (stat != MStatus::kSuccess)
return MObject::kNullObj;
if (arr.length() == 1)
srcNode = arr[0].node();
else if (arr.length() == 0 ) {
return MObject::kNullObj;
}
else {
MGlobal::displayWarning("Texture plug is connected to multiple nodes");
return MObject::kNullObj;
}
if( srcNode != MObject::kNullObj) {
MStatus rc;
MFnDependencyNode dgFn( srcNode, &rc);
MPlug fnPlug = dgFn.findPlug( "fileTextureName", &rc);
if (rc == MStatus::kSuccess) {
MStatus tStat;
MObject fTex = fnPlug.node(&tStat);
if ( tStat != MStatus::kSuccess)
return MObject::kNullObj;
else
return fTex;
}
}
return MObject::kNullObj;
}
MObject glslShaderNode::findEnvCubeNode( const MPlug &plug) {
MPlugArray arr;
plug.connectedTo(arr, true, false);
MObject srcNode;
if (arr.length() == 1)
srcNode = arr[0].node();
else if (arr.length() == 0 ) {
return MObject::kNullObj;
}
else {
MGlobal::displayWarning("Texture plug is connected to multiple nodes");
return MObject::kNullObj;
}
if( srcNode != MObject::kNullObj) {
MStatus rc;
MFnDependencyNode dgFn( srcNode, &rc);
MPlug fnPlug = dgFn.findPlug( "left", &rc);
if (rc == MStatus::kSuccess) {
MStatus tStat;
MObject fCube = fnPlug.node(&tStat);
if ( tStat != MStatus::kSuccess)
return MObject::kNullObj;
else
return fCube;
}
}
return MObject::kNullObj;
}
void glslShaderNode::loadCubeFace( glslShaderNode::CubeFace cf, MObject &cube, MFnDependencyNode &dn){
const char* faceNames[] = { "left", "right", "top", "bottom", "front", "back"};
const GLenum targets[] = {GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
float rgb[3];
MObject face = dn.attribute( faceNames[cf]);
MPlug plug( cube, face);
MObject fTex = findFileTextureNode( plug);
if (fTex != MObject::kNullObj) {
MImage img;
unsigned int width, height;
img.readFromTextureNode(fTex);
MStatus status = img.getSize( width, height);
bool resizeToBeSquare = false;
if (width != height)
{
width = height;
resizeToBeSquare = true;
}
if (width > 0 && height > 0 && (status != MStatus::kFailure) )
{
if (!glTextureNonPowerOfTwo || resizeToBeSquare )
{
if (width > 2 && height > 2)
{
unsigned int p2Width, p2Height;
bool widthPowerOfTwo = textureInitPowerOfTwo(width, p2Width);
bool heightPowerOfTwo = textureInitPowerOfTwo(height, p2Height);
if(!widthPowerOfTwo || !heightPowerOfTwo || resizeToBeSquare)
{
width = p2Width;
height = p2Height;
img.resize( p2Width, p2Height, false );
}
}
}
glTexImage2D( targets[cf], 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
GL_CHECK;
}
}
else {
MObject data;
plug.getValue( data);
MFnNumericData val(data);
val.getData( rgb[0], rgb[1], rgb[2]);
glTexImage2D( targets[cf], 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_FLOAT, rgb);
}
}
void glslShaderNode::BindSamplerData() {
for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
if (it->dirty) {
it->dirty = false;
MPlug plug(thisMObject(), it->attrib);
MObject data;
plug.getValue(data);
MFnNumericData val(data);
float rgb[3];
if (it->texName == 0) {
glGenTextures( 1, &(it->texName));
m_shader->updateSampler( it->pNum, it->texName);
GL_CHECK;
}
switch (m_shader->samplerType(it->pNum) ) {
case shader::st1D:
val.getData( rgb[0], rgb[1], rgb[2]);
glBindTexture( GL_TEXTURE_1D, it->texName);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, it->minFilter);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, it->magFilter);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, it->wrapMode);
glTexParameterf( GL_TEXTURE_1D, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
glTexParameteri( GL_TEXTURE_1D, GL_GENERATE_MIPMAP, GL_TRUE);
}
else {
glTexParameteri( GL_TEXTURE_1D, GL_GENERATE_MIPMAP, GL_FALSE);
}
glTexImage1D( GL_TEXTURE_1D, 0, GL_RGB8, 1, 0, GL_RGB, GL_FLOAT, rgb);
GL_CHECK;
break;
case shader::st1DShadow:
break;
case shader::st2D:
{
bool done = false;
glBindTexture( GL_TEXTURE_2D, it->texName);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, it->minFilter);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, it->magFilter);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, it->wrapMode);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, it->wrapMode);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
}
else {
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
}
MObject fTex = findFileTextureNode( plug);
if (fTex != MObject::kNullObj) {
MImage img;
unsigned int width, height;
img.readFromTextureNode(fTex);
MStatus status = img.getSize( width, height);
if (width > 0 && height > 0 && (status != MStatus::kFailure) )
{
if (!glTextureNonPowerOfTwo)
{
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 );
}
}
}
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
GL_CHECK;
done = true;
}
}
if (!done) {
val.getData( rgb[0], rgb[1], rgb[2]);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_FLOAT, rgb);
}
GL_CHECK;
}
break;
case shader::stCube:
{
glBindTexture( GL_TEXTURE_CUBE_MAP, it->texName);
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, it->minFilter);
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, it->magFilter);
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, it->wrapMode);
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, it->wrapMode);
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
}
else {
glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_FALSE);
}
MObject cube = findEnvCubeNode( plug);
if ( cube != MObject::kNullObj) {
MFnDependencyNode dn(cube);
loadCubeFace( cfLeft, cube, dn);
loadCubeFace( cfRight, cube, dn);
loadCubeFace( cfTop, cube, dn);
loadCubeFace( cfBottom, cube, dn);
loadCubeFace( cfFront, cube, dn);
loadCubeFace( cfBack, cube, dn);
}
}
break;
case shader::st2DShadow:
case shader::st3D:
break;
default:
break;
};
}
}
}
void glslShaderNode::BindUniformData() {
for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
if (it->dirty) {
#endif
it->dirty = false;
MPlug plug(thisMObject(), it->attrib);
MObject data;
plug.getValue(data);
MFnNumericData val(data);
float fTemp[4];
int iTemp[4];
bool bTemp[4];
switch (m_shader->uniformType(it->pNum)) {
case shader::dtBool:
plug.getValue(bTemp[0]);
m_shader->updateUniformBool( it->pNum, bTemp[0]);
break;
case shader::dtBVec2:
case shader::dtBVec3:
case shader::dtBVec4:
break;
case shader::dtInt:
plug.getValue(iTemp[0]);
m_shader->updateUniformInt( it->pNum, iTemp[0]);
break;
case shader::dtIVec2:
val.getData( iTemp[0], iTemp[1]);
m_shader->updateUniformIVec( it->pNum, iTemp);
break;
case shader::dtIVec3:
val.getData( iTemp[0], iTemp[1], iTemp[2]);
m_shader->updateUniformIVec( it->pNum, iTemp);
break;
case shader::dtIVec4:
break;
case shader::dtFloat:
plug.getValue(fTemp[0]);
m_shader->updateUniformFloat( it->pNum, fTemp[0]);
break;
case shader::dtVec2:
val.getData( fTemp[0], fTemp[1]);
m_shader->updateUniformVec( it->pNum, fTemp);
break;
case shader::dtVec3:
val.getData( fTemp[0], fTemp[1], fTemp[2]);
m_shader->updateUniformVec( it->pNum, fTemp);
break;
case shader::dtVec4:
{
MPlug plug2(thisMObject(), it->attrib2);
val.getData( fTemp[0], fTemp[1], fTemp[2]);
plug2.getValue( fTemp[3]);
m_shader->updateUniformVec( it->pNum, fTemp);
}
break;
case shader::dtMat4:
{
MFnMatrixData mValue(data);
MMatrix matrix = mValue.matrix();
m_shader->updateUniformMat( it->pNum, (double*)matrix.matrix);
}
break;
case shader::dtMat2:
case shader::dtMat3:
break;
default:
break;
};
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
}
#endif
}
bool glslShaderNode::supportsBatching() const
{
return true;
}
MStatus glslShaderNode::glBind(const MDagPath& shapePath) {
if (!InitializeExtensions()) {
MStatus strStat;
MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeAshliFailedFindExtensions, strStat));
return MStatus::kFailure;
}
GL_CHECK;
ResourceManager::recover();
if (!sDefShader)
sDefShader = new defaultShader;
GL_CHECK;
if (m_shader) {
if (!m_shader->build())
MGlobal::displayError(MString(m_shader->errorString()));
BindUniformData();
BindSamplerData();
}
glDisable(GL_POINT_SMOOTH);
glDisable( GL_LINE_SMOOTH);
if ((m_shader != NULL) && (m_shader->valid()))
{
m_passCount = m_shader->passCount();
if (!m_shader->build()) {
m_passCount = 0;
}
if( m_passCount == 1)
{
m_shader->setPass( 0);
m_shader->bind();
}
}
else
{
m_passCount = -1;
m_maxSetNum = 1;
sDefShader->bind();
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
GL_CHECK;
return MS::kSuccess;
}
MStatus glslShaderNode::glUnbind(const MDagPath& shapePath) {
for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++)
glDisableVertexAttribArray( it->handle);
for( int ii = 0; ii < m_maxSetNum; ii++)
m_glState.disableTexCoord( ii);
m_glState.activeTexture( 0);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
if( m_passCount < 0)
sDefShader->unbind();
else if( m_passCount == 1)
m_shader->unbind();
m_parsedUserAttribList = false;
return MS::kSuccess;
}
void glslShaderNode::updateBoundAttributes( const MDagPath& shapePath) {
MMatrix world;
MMatrix temp;
MMatrix proj;
MMatrix view;
MMatrix worldview;
if (shapePath.isValid())
world = shapePath.inclusiveMatrix();
else
world.setToIdentity();
glGetDoublev( GL_PROJECTION_MATRIX, (double*)proj.matrix);
glGetDoublev( GL_MODELVIEW_MATRIX, (double*)worldview.matrix);
view = world.inverse() * worldview;
for (std::vector<boundUniform>::iterator it = m_boundUniformList.begin(); it < m_boundUniformList.end(); it++) {
switch ( it->usage) {
case shader::smWorld:
m_shader->updateUniformMat( it->pNum, (double*)world.matrix);
break;
case shader::smView:
m_shader->updateUniformMat( it->pNum, (double*)view.matrix);
break;
case shader::smProjection:
m_shader->updateUniformMat( it->pNum, (double*)proj.matrix);
break;
case shader::smWorldView:
m_shader->updateUniformMat( it->pNum, (double*)worldview.matrix);
break;
case shader::smViewProjection:
temp = view * proj;
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewProjection:
temp = worldview * proj;
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldI:
temp = world.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewI:
temp = view.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smProjectionI:
temp = proj.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewI:
temp = worldview.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewProjectionI:
temp = view * proj;
temp = temp.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewProjectionI:
temp = worldview * proj;
temp = temp.inverse();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldT:
temp = world.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewT:
temp = view.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smProjectionT:
temp = proj.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewT:
temp = worldview.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewProjectionT:
temp = view * proj;
temp = temp.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewProjectionT:
temp = worldview * proj;
temp = temp.transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldIT:
temp = world.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewIT:
temp = view.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smProjectionIT:
temp = proj.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewIT:
temp = worldview.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewProjectionIT:
temp = view * proj;
temp = temp.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smWorldViewProjectionIT:
temp = worldview * proj;
temp = temp.inverse().transpose();
m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
break;
case shader::smViewPosition:
{
float vec[4];
temp = view.inverse();
vec[0] = (float)temp[3][0];
vec[1] = (float)temp[3][1];
vec[2] = (float)temp[3][2];
vec[3] = (float)temp[3][3];
m_shader->updateUniformVec( it->pNum, vec);
}
break;
case shader::smTime:
m_shader->updateUniformFloat( it->pNum, 0.0f);
break;
case shader::smViewportSize:
{
float vp[4];
glGetFloatv( GL_VIEWPORT, vp);
m_shader->updateUniformVec( it->pNum, &vp[2]);
}
break;
default:
break;
};
}
}
void glslShaderNode::configureTexCoords( int normalCount, const float ** normalArrays,
int texCoordCount,
const float ** texCoordArrays,
int colorCount,
const float ** colorArrays)
{
int ii;
for (ii=0; ii<m_maxSetNum; ii++) {
if (m_setNums[ii] == -1) {
glMultiTexCoord2f( GL_TEXTURE0 + ii, 0.0f, 0.0f);
m_glState.disableTexCoord( ii);
continue;
}
else if (m_mayaType[ii] == kNormal) {
if ( (normalCount > 0) && normalArrays[0]) {
m_glState.enableAndActivateTexCoord( ii);
glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[0]);
}
else {
glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 0.0f, 1.0f);
m_glState.disableTexCoord( ii);
}
continue;
}
else if (m_mayaType[ii] == kTangent) {
if ( m_numNormals > 1 && normalCount > 1)
{
int offset = 0;
if (m_numNormals > 2)
offset = ( m_setNums[ii] * 3 ) + 1;
else
offset = ( m_setNums[ii] * 2 ) + 1;
if (offset > normalCount)
{
if (normalCount >= 2)
offset = 1;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset]) {
m_glState.enableAndActivateTexCoord( ii);
glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
}
else {
glMultiTexCoord3f( GL_TEXTURE0 + ii, 1.0f, 0.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
}
else
{
glMultiTexCoord3f( GL_TEXTURE0 + ii, 1.0f, 0.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
continue;
}
else if (m_mayaType[ii] == kBinormal) {
if ( m_numNormals > 2 && normalCount > 1)
{
int offset = ( m_setNums[ii] * 3 ) + 2;
if (offset > normalCount)
{
if (normalCount >= 3)
offset = 2;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset] )
{
m_glState.enableAndActivateTexCoord( ii);
glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
}
else
{
glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
}
else
{
glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
continue;
}
else if (m_mayaType[ii] == kColorSet) {
if ( (m_setNums[ii] < colorCount) && colorArrays[m_setNums[ii]]) {
m_glState.enableAndActivateTexCoord( ii);
glTexCoordPointer( 4, GL_FLOAT, 0, colorArrays[m_setNums[ii]]);
}
else {
glMultiTexCoord4f( GL_TEXTURE0 + ii, 0.0f, 0.0f, 0.0f, 1.0f);
m_glState.disableTexCoord( ii);
}
continue;
}
if ( (m_setNums[ii] < texCoordCount) && texCoordArrays[m_setNums[ii]]) {
m_glState.enableAndActivateTexCoord( ii);
glTexCoordPointer( 2, GL_FLOAT, 0, texCoordArrays[m_setNums[ii]]);
}
else {
glMultiTexCoord2f( GL_TEXTURE0 + ii, 0.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
}
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
if (m_colorSetNums[0] == -1) {
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
else if (m_colorMayaType[0] == kNormal) {
if ( (normalCount > 0) && normalArrays[0]) {
glColorPointer( 3, GL_FLOAT, 0, normalArrays[0]);
glEnableClientState( GL_COLOR_ARRAY);
}
else {
glColor4f( 0.0f, 0.0f, 1.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
else if (m_colorMayaType[0] == kTangent) {
if ( m_numNormals > 1 && normalCount > 1)
{
int offset = 0;
if (m_numNormals > 2)
offset = ( m_colorSetNums[0] * 3 ) + 1;
else
offset = ( m_colorSetNums[0] * 2 ) + 1;
if (offset > normalCount)
{
if (normalCount >= 2)
offset = 1;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset]) {
glColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
glEnableClientState( GL_COLOR_ARRAY);
}
else {
glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
else {
glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
else if (m_colorMayaType[0] == kBinormal) {
if ( m_numNormals > 2 && normalCount > 1)
{
int offset = ( m_colorSetNums[0] * 3 ) + 2;
if (offset > normalCount)
{
if (normalCount >= 3)
offset = 2;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset] )
{
glColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
glEnableClientState( GL_COLOR_ARRAY);
}
else
{
glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
m_glState.disableTexCoord( ii);
}
}
else
{
glColor4f( 0.0f, 1.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
else if (m_colorMayaType[0] == kColorSet) {
if ( (m_colorSetNums[0] < colorCount) && colorArrays[m_colorSetNums[0]]) {
glColorPointer( 4, GL_FLOAT, 0, colorArrays[m_colorSetNums[0]]);
glEnableClientState( GL_COLOR_ARRAY);
}
else {
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
else if (m_colorMayaType[0] == kUvSet) {
if ( (m_colorSetNums[0] < texCoordCount) && texCoordArrays[m_colorSetNums[0]]) {
glColorPointer( 2, GL_FLOAT, 0, texCoordArrays[m_colorSetNums[0]]);
glEnableClientState( GL_COLOR_ARRAY);
}
else {
glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
if (glSecondaryColorSupport) {
glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
if (m_colorSetNums[1] == -1) {
glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
else if (m_colorMayaType[1] == kNormal) {
if ( (normalCount > 0) && normalArrays[0]) {
glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[0]);
glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
}
else {
glSecondaryColor3f( 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
else if (m_colorMayaType[1] == kTangent) {
if ( m_numNormals > 1 && normalCount > 1)
{
int offset = 0;
if (m_numNormals > 2)
offset = ( m_colorSetNums[1] * 3 ) + 1;
else
offset = ( m_colorSetNums[1] * 2 ) + 1;
if (offset > normalCount)
{
if (normalCount >= 2)
offset = 1;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset]) {
glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
}
else {
glSecondaryColor3f( 1.0f, 0.0f, 0.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
else {
glSecondaryColor3f( 1.0f, 0.0f, 0.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
else if (m_colorMayaType[1] == kBinormal) {
if ( m_numNormals > 2 && normalCount > 1 )
{
int offset = ( m_colorSetNums[1] * 3 ) + 2;
if (offset > normalCount)
{
if (normalCount >= 3)
offset = 2;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset] )
{
glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
}
else
{
glSecondaryColor3f( 0.0f, 1.0f, 0.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
else
{
glSecondaryColor3f( 0.0f, 1.0f, 0.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
else if (m_colorMayaType[1] == kColorSet) {
if ( (m_colorSetNums[1] < colorCount) && colorArrays[m_colorSetNums[1]]) {
glSecondaryColorPointer( 4, GL_FLOAT, 0, colorArrays[m_colorSetNums[1]]);
glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
}
else {
glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
}
}
#if 0
else if (m_colorMayaType[1] == kUvSet) {
if ( (m_colorSetNums[1] < texCoordCount) && texCoordArrays[m_colorSetNums[1]]) {
glSecondaryColorPointer( 2, GL_FLOAT, 0, texCoordArrays[m_colorSetNums[1]]);
glEnableClientState( GL_COLOR_ARRAY);
}
else {
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f);
glDisableClientState( GL_COLOR_ARRAY);
}
}
#endif
}
for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
it->handle = m_shader->attributeHandle(it->pNum);
if (it->set == -1) {
glDisableVertexAttribArray( it->handle);
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
continue;
}
else if (it->mtype == kNormal) {
if (( normalCount > 0) && normalArrays[0]) {
glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[0]);
glEnableVertexAttribArray( it->handle);
}
else {
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
continue;
}
else if (it->mtype == kTangent) {
if ( m_numNormals > 1 && normalCount > 1)
{
int offset = 0;
if (m_numNormals > 2)
offset = ( it->set * 3 ) + 1;
else
offset = ( it->set * 2 ) + 1;
if (offset > normalCount)
{
if (normalCount >= 2)
offset = 1;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset]) {
glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[offset]);
glEnableVertexAttribArray( it->handle);
}
else {
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
}
else {
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
continue;
}
else if (it->mtype == kBinormal) {
if ( m_numNormals > 2 && normalCount > 1)
{
int offset = ( it->set * 3 ) + 2;
if (offset > normalCount)
{
if (normalCount >= 3)
offset = 2;
else
offset = -1;
}
if ((offset > 0) && normalArrays[offset] )
{
glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[offset]);
glEnableVertexAttribArray( it->handle);
}
else
{
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
}
else
{
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
continue;
}
else if (it->mtype == kColorSet) {
if (( it->set < colorCount ) && colorArrays[it->set]) {
glVertexAttribPointer( it->handle, 4, GL_FLOAT, GL_FALSE, 0, colorArrays[it->set]);
glEnableClientState( it->handle );
}
else {
glVertexAttrib4f( it->handle, 0.0f, 0.0f, 0.0f, 1.0f);
glDisableVertexAttribArray( it->handle);
}
continue;
}
if (( it->set < texCoordCount ) && texCoordArrays[it->set]) {
glVertexAttribPointer( it->handle, 2, GL_FLOAT, GL_FALSE, 0, texCoordArrays[it->set]);
glEnableVertexAttribArray( it->handle);
}
else {
glVertexAttrib2f( it->handle, 0.0f, 0.0f);
glDisableVertexAttribArray( it->handle);
}
}
m_glState.activeTexture( 0);
}
MStatus glslShaderNode::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) {
if (!(glShadingLanguageSupport && glMultiTextureSupport && glTexture3DSupport && glAsmProgramSupport))
return MStatus::kFailure;
if( m_passCount > 0)
updateBoundAttributes(shapePath);
int passCount = m_passCount >= 0 ? m_passCount : 1;
for( int jj=0; jj < passCount; jj++)
{
if( passCount > 1)
{
m_shader->setPass( jj);
m_shader->bind();
}
if( m_passCount > 0)
{
m_shader->setShapeDependentState();
}
else
{
sDefShader->setShapeDependentState();
}
glVertexPointer( 3, GL_FLOAT, 0, vertexArray);
if (normalCount && normalArrays[0] ) {
glNormalPointer( GL_FLOAT, 0, &normalArrays[0][0]);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
glDisableClientState(GL_NORMAL_ARRAY);
}
configureTexCoords( normalCount, normalArrays, texCoordCount, texCoordArrays,
colorCount, colorArrays );
GL_CHECK;
glDrawElements( prim, indexCount, GL_UNSIGNED_INT, indexArray);
if( m_passCount > 1)
{
m_shader->unbind();
}
GL_CHECK;
}
if( m_passCount > 1)
m_shader->setPass(0);
return MS::kSuccess;
}
MStatus
glslShaderNode::connectionMade( const MPlug& plug,
const MPlug& otherPlug,
bool asSrc )
{
const MPlug &root = plug.isChild() ? plug.parent() : plug;
{
for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
if ( root == it->attrib) {
it->dirty = true;
break;
}
}
}
{
for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
if ( root == it->attrib) {
it->dirty = true;
break;
}
}
}
return MS::kUnknownParameter;
}
MStatus
glslShaderNode::connectionBroken( const MPlug& plug,
const MPlug& otherPlug,
bool asSrc )
{
const MPlug &root = plug.isChild() ? plug.parent() : plug;
{
for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
if ( root == it->attrib) {
it->dirty = true;
break;
}
}
}
{
for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
if ( root == it->attrib) {
it->dirty = true;
break;
}
}
}
return MS::kUnknownParameter;
}
bool glslShaderNode::getInternalValueInContext( const MPlug &plug,
MDataHandle &handle,
MDGContext& )
{
bool retVal = false;
if ( plug == sShader) {
handle.set(m_shaderName);
retVal = true;
}
else if ( plug == sTechnique) {
handle.set(m_techniqueName);
retVal = true;
}
else if ( plug == sTechniqueList )
{
handle.set(m_techniqueList);
retVal = true;
}
else if ( plug == sShaderPath )
{
handle.set(m_shaderPath);
retVal = true;
}
else {
int ii;
for (ii=0; ii<8; ii++) {
if ( plug == sNakedTexCoords[ii]) {
handle.set(m_nakedTexSets[ii]);
retVal = true;
break;
}
}
for (ii=0; ii<2; ii++) {
if (plug == sNakedColors[ii]) {
handle.set(m_nakedColorSets[ii]);
retVal = true;
break;
}
}
for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
if (plug == it->attrib) {
handle.set(it->setName);
retVal = true;
break;
}
}
}
return retVal;
}
bool glslShaderNode::setInternalValueInContext( const MPlug &plug,
const MDataHandle &handle,
MDGContext & )
{
bool retVal = false;
bool reading = MFileIO::isReadingFile();
if (reading)
m_shader = NULL;
if ( plug == sShader) {
m_shaderName = handle.asString();
m_shaderPath = m_shaderName;
if (locateFile( m_shaderName, m_shaderPath)) {
m_shaderDirty = true;
if (!reading) {
if (MGlobal::mayaState() == MGlobal::kBatch)
rebuildShader();
else
{
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (pRenderer)
{
const MString & backEndStr = pRenderer->backEndString();
MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
if (status != MStatus::kSuccess) {
MStatus strStat;
MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
MGlobal::displayError(status.errorString());
}
else
rebuildShader();
}
}
}
}
else {
MGlobal::displayError(MString("Couldn't find shader file: '") + m_shaderPath + "'");
}
retVal = true;
}
else if ( plug == sTechnique) {
MString temp = handle.asString();
if (reading)
{
m_techniqueName = temp;
retVal = true;
}
else
{
if (m_shader) {
for (int ii=0; ii<m_shader->techniqueCount(); ii++) {
if (temp == m_shader->techniqueName(ii)) {
m_shader->setTechnique(ii);
retVal = true;
break;
}
}
}
if (retVal)
m_techniqueName = temp;
else
{
MGlobal::displayWarning(MString("Unknown technique: ") + temp +
MString(" for shader: ") + m_shaderPath.asChar());
}
}
retVal = true;
}
else if ( plug == sTechniqueList )
{
}
else {
int ii;
for (ii=0; ii<8; ii++) {
if (plug == sNakedTexCoords[ii]) {
m_nakedTexSets[ii] = handle.asString();
return true;
}
}
for (ii=0; ii<2; ii++) {
if (plug == sNakedColors[ii]) {
m_nakedColorSets[ii] = handle.asString();
return true;
}
}
for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
if (plug == it->attrib) {
it->setName = handle.asString();
return true;
}
}
if (!reading) {
const MPlug &root = plug.isChild() ? plug.parent() : plug;
for ( std::vector<uniformAttrib>::iterator it2 = m_uniformAttribList.begin(); it2 < m_uniformAttribList.end(); it2++) {
if ( ( root == it2->attrib) || ( root == it2->attrib2) ){
it2->dirty = true;
break;
}
}
for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
if (root == it->attrib) {
it->dirty = true;
break;
}
if (root == it->anisoAttrib) {
it->dirty = true;
it->maxAniso = handle.asFloat();
break;
}
if (root == it->magFilterAttrib) {
it->dirty = true;
switch (handle.asShort()) {
case 0:
it->magFilter = GL_NEAREST;
break;
case 1:
it->magFilter = GL_LINEAR;
break;
default:
it->magFilter = GL_LINEAR;
break;
};
break;
}
if (root == it->minFilterAttrib) {
it->dirty = true;
switch (handle.asShort()) {
case 0:
it->minFilter = GL_NEAREST;
break;
case 1:
it->minFilter = GL_LINEAR;
break;
case 2:
it->minFilter = GL_LINEAR_MIPMAP_NEAREST;
break;
case 3:
it->minFilter = GL_LINEAR_MIPMAP_LINEAR;
break;
default:
it->minFilter = GL_LINEAR;
break;
};
break;
}
if (root == it->wrapAttrib) {
it->dirty = true;
switch (handle.asShort()) {
case 0:
it->wrapMode = GL_REPEAT;
break;
case 1:
it->wrapMode = GL_CLAMP_TO_EDGE;
break;
case 2:
it->wrapMode = GL_MIRRORED_REPEAT;
break;
default:
it->wrapMode = GL_REPEAT;
break;
};
break;
}
}
}
}
GL_CHECK;
return retVal;
}
void glslShaderNode::copyInternalData( MPxNode* pMPx )
{
glslShaderNode* pNode = dynamic_cast<glslShaderNode*>( pMPx );
m_shader = NULL;
m_shaderDirty = false;
m_uniformAttribList.clear();
m_samplerAttribList.clear();
m_attributeAttribList.clear();
m_boundUniformList.clear();
m_parsedUserAttribList = false;
m_numUVsets = 0;
m_uvSetNames.clear();
m_numColorSets = 0;
m_colorSetNames.clear();
m_numNormals = 3;
m_maxSetNum = pNode->m_maxSetNum;
if( pNode )
{
for(int ii=0; ii<8; ii++)
{
m_nakedTexSets[ii] = pNode->m_nakedTexSets[ii];
m_setNums[ii] = pNode->m_setNums[ii];
m_mayaType[ii] = pNode->m_mayaType[ii];
}
m_nakedColorSets[0] = pNode->m_nakedColorSets[0];
m_nakedColorSets[1] = pNode->m_nakedColorSets[1];
m_colorSetNums[0] = pNode->m_colorSetNums[0];
m_colorSetNums[1] = pNode->m_colorSetNums[1];
m_colorMayaType[0] = pNode->m_colorMayaType[0];
m_colorMayaType[1] = pNode->m_colorMayaType[1];
m_shaderName = pNode->m_shaderName;
m_shaderPath = m_shaderName;
m_techniqueList = "";
m_techniqueName = "";
if (locateFile( m_shaderName, m_shaderPath))
{
m_techniqueName = pNode->m_techniqueName;
m_shaderDirty = true;
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (pRenderer)
{
const MString & backEndStr = pRenderer->backEndString();
MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
if (status != MStatus::kSuccess) {
MStatus strStat;
MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
MGlobal::displayError(status.errorString());
}
else
rebuildShader();
}
else
rebuildShader();
}
}
}
int glslShaderNode::colorsPerVertex() {
return 1;
}
int glslShaderNode::texCoordsPerVertex() {
return 0;
}
#if MAYA_API_VERSION >= 700
void glslShaderNode::parseUserAttributeList()
{
if (m_parsedUserAttribList)
return;
m_numUVsets = 0;
m_numColorSets = 0;
m_uvSetNames.clear();
m_colorSetNames.clear();
m_numNormals = 3;
MStringArray uvSetNames;
MStringArray colorSetNames;
bool haveNurbs = false;
MString nurbsDefaultUV("Nurbs Tri UVs");
const MDagPath & path = currentPath();
if (path.hasFn( MFn::kMesh ) )
{
MFnMesh fnMesh( path.node() );
if (fnMesh.numUVSets())
fnMesh.getUVSetNames(uvSetNames);
if (fnMesh.numColorSets())
fnMesh.getColorSetNames(colorSetNames);
}
else
{
haveNurbs = true;
uvSetNames.append(nurbsDefaultUV);
}
int ii = 0;
for (; ii<8; ii++)
{
m_setNums[ii] = -1;
m_mayaType[ii] = kNonMaya;
}
const char _splitChar = ':';
ii = 0;
for (; ii<8; ii++)
{
MStringArray splitStrings;
MString comparisonString = m_nakedTexSets[ii];
if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
comparisonString = splitStrings[0];
}
if (haveNurbs && comparisonString == "map1")
{
m_setNums[ii] = m_uvSetNames.length();
m_uvSetNames.append(nurbsDefaultUV);
m_mayaType[ii] = kUvSet;
continue;
}
else if (comparisonString == "normal") {
m_setNums[ii] = 0;
m_mayaType[ii] = kNormal;
continue;
}
else if (comparisonString == "tangent") {
m_setNums[ii] = 0;
m_mayaType[ii] = kTangent;
continue;
}
else if (comparisonString == "binormal") {
m_setNums[ii] = 0;
m_mayaType[ii] = kBinormal;
continue;
}
else if (comparisonString == "") {
m_setNums[ii] = -1;
m_mayaType[ii] = kNonMaya;
continue;
}
else {
bool matchUVSet = false;
unsigned int numNames = uvSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames; jj++) {
if (comparisonString == uvSetNames[jj])
{
m_setNums[ii] = m_uvSetNames.length();
m_uvSetNames.append( uvSetNames[jj] );
m_mayaType[ii] = kUvSet;
matchUVSet = true;
break;
}
}
}
if (!matchUVSet)
{
numNames = colorSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames ; jj++) {
if (comparisonString == colorSetNames[jj])
{
m_setNums[ii] = m_colorSetNames.length();
m_colorSetNames.append( colorSetNames[jj] );
m_mayaType[ii] = kColorSet;
break;
}
}
}
}
}
}
ii = 0;
for (; ii<2; ii++)
{
m_colorSetNums[ii] = -1;
m_colorMayaType[ii] = kNonMaya;
}
ii = 0;
for (; ii<2; ii++)
{
MStringArray splitStrings;
MString comparisonString = m_nakedColorSets[ii];
if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
comparisonString = splitStrings[0];
}
if (comparisonString == "normal") {
m_colorSetNums[ii] = 0;
m_colorMayaType[ii] = kNormal;
continue;
}
else if (comparisonString == "tangent") {
m_colorSetNums[ii] = 0;
m_colorMayaType[ii] = kTangent;
continue;
}
else if (comparisonString == "binormal") {
m_colorSetNums[ii] = 0;
m_colorMayaType[ii] = kBinormal;
continue;
}
else if (comparisonString == "") {
m_colorSetNums[ii] = -1;
m_colorMayaType[ii] = kNonMaya;
continue;
}
else {
bool matchUVSet = false;
unsigned int numNames = colorSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames ; jj++) {
if (comparisonString == colorSetNames[jj])
{
m_colorSetNums[ii] = m_colorSetNames.length();
m_colorSetNames.append( colorSetNames[jj] );
m_colorMayaType[ii] = kColorSet;
matchUVSet = true;
break;
}
}
}
#ifdef _INTERACTIVE_SHADING_WORKS_FOR_ROUTING_TEXCOORDS_TO_COLOUR
numNames = uvSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames; jj++) {
if (comparisonString == uvSetNames[jj])
{
m_colorSetNums[ii] = m_uvSetNames.length();
m_uvSetNames.append( uvSetNames[jj] );
m_colorMayaType[ii] = kUvSet;
break;
}
}
}
#endif
}
}
for (std::vector<attributeAttrib>::iterator it = m_attributeAttribList.begin();
it<m_attributeAttribList.end(); it++)
{
MStringArray splitStrings;
MString comparisonString( it->setName );
if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
comparisonString = splitStrings[0];
}
if (comparisonString == "normal") {
it->mtype = kNormal;
it->set = 0;
continue;
}
else if (comparisonString == "tangent") {
it->mtype = kTangent;
it->set = 0;
continue;
}
else if (comparisonString == "binormal") {
it->mtype = kBinormal;
it->set = 0;
continue;
}
else if (comparisonString == "") {
it->set = -1;
continue;
}
else {
bool matchUVSet = false;
unsigned int numNames = uvSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames; jj++)
{
if (comparisonString == uvSetNames[jj])
{
it->set = m_uvSetNames.length();
m_uvSetNames.append( uvSetNames[jj] );
it->mtype = kUvSet;
matchUVSet = true;
break;
}
}
}
if (!matchUVSet)
{
numNames = colorSetNames.length();
if (numNames)
{
unsigned int jj = 0;
for (jj=0; jj<numNames ; jj++) {
if (m_nakedTexSets[ii] == colorSetNames[jj])
{
m_colorSetNames.append( colorSetNames[jj] );
it->set = m_colorSetNames.length();
it->mtype = kColorSet;
break;
}
}
}
}
}
}
unsigned int numUVSets = uvSetNames.length();
if (numUVSets)
{
for (ii=0; ii<8; ii++)
{
if (m_mayaType[ii] == kTangent || m_mayaType[ii] == kBinormal)
{
MStringArray splitStrings;
MString origString( m_nakedTexSets[ii] );
if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
unsigned int jj = 0;
for (jj=0; jj<numUVSets; jj++)
{
if (uvSetNames[jj] == splitStrings[1])
{
int foundSet = -1;
for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
{
if (splitStrings[1] == m_uvSetNames[kk])
{
foundSet = kk;
break;
}
}
if (foundSet > 0)
{
m_setNums[ii] = foundSet;
}
else
{
m_setNums[ii] = m_uvSetNames.length();
m_uvSetNames.append( splitStrings[1] );
}
break;
}
}
}
}
}
}
if (numUVSets)
{
for (ii=0; ii<2; ii++)
{
if (m_colorMayaType[ii] == kTangent || m_colorMayaType[ii] == kBinormal)
{
MStringArray splitStrings;
MString origString( m_nakedColorSets[ii] );
if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
unsigned int jj = 0;
for (jj=0; jj<numUVSets; jj++)
{
if (uvSetNames[jj] == splitStrings[1])
{
int foundSet = -1;
for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
{
if (splitStrings[1] == m_uvSetNames[kk])
{
foundSet = kk;
break;
}
}
if (foundSet > 0)
{
m_colorSetNums[ii] = foundSet;
}
else
{
m_colorSetNums[ii] = m_uvSetNames.length();
m_uvSetNames.append( splitStrings[1] );
}
break;
}
}
}
}
}
}
if (numUVSets)
{
for (std::vector<attributeAttrib>::iterator it2 = m_attributeAttribList.begin();
it2<m_attributeAttribList.end(); it2++)
{
if (it2->mtype == kTangent || it2->mtype == kBinormal)
{
MStringArray splitStrings;
MString origString( it2->setName );
if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
splitStrings.length() > 1)
{
unsigned int jj = 0;
for (jj=0; jj<numUVSets; jj++)
{
if (uvSetNames[jj] == splitStrings[1])
{
int foundSet = -1;
for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
{
if (splitStrings[1] == m_uvSetNames[kk])
{
foundSet = kk;
break;
}
}
if (foundSet > 0)
{
it2->set = foundSet;
}
else
{
it2->set = m_uvSetNames.length();
m_uvSetNames.append( splitStrings[1] );
}
break;
}
}
}
}
}
}
m_numUVsets = m_uvSetNames.length();
m_numColorSets = m_colorSetNames.length();
m_maxSetNum = 0;
for ( ii = 0; ii<8; ii++)
if( m_mayaType[ii] != kNonMaya)
m_maxSetNum = ii + 1;
m_parsedUserAttribList = true;
}
#else // if MAYA_7
void glslShaderNode::parseUserAttributeList()
{
if (m_parsedUserAttribList)
return;
m_numUVsets = 0;
m_numColorSets = 0;
m_uvSetNames.clear();
m_colorSetNames.clear();
m_uvSetNames.append("map1");
int ii = 0;
for (; ii<8; ii++)
{
m_setNums[ii] = -1;
m_mayaType[ii] = kNonMaya;
}
ii = 0;
for (; ii<8; ii++)
{
if ( m_nakedTexSets[ii] == "map1")
{
m_setNums[ii] = 0;
m_mayaType[ii] = kUvSet;
continue;
}
else if (m_nakedTexSets[ii] == "normal") {
m_setNums[ii] = 0;
m_mayaType[ii] = kNormal;
continue;
}
else if (m_nakedTexSets[ii] == "tangent") {
m_setNums[ii] = 0;
m_mayaType[ii] = kTangent;
continue;
}
else if (m_nakedTexSets[ii] == "binormal") {
m_setNums[ii] = 0;
m_mayaType[ii] = kBinormal;
continue;
}
else if (m_nakedTexSets[ii] == "") {
m_setNums[ii] = -1;
m_mayaType[ii] = kNonMaya;
continue;
}
else {
m_setNums[ii] = m_uvSetNames.length();
m_uvSetNames.append( m_nakedTexSets[ii] );
m_mayaType[ii] = kUvSet;
}
}
unsigned int setNum = 0;
for (std::vector<attributeAttrib>::iterator it = m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
if (it->setName == "normal") {
it->mtype = kNormal;
it->set = 0;
continue;
}
else if (it->setName == "tangent") {
it->mtype = kTangent;
it->set = 0;
continue;
}
else if (it->setName == "binormal") {
it->mtype = kBinormal;
it->set = 0;
continue;
}
else if (it->setName == "") {
it->set = -1;
continue;
}
else {
it->set = m_uvSetNames.length();
m_uvSetNames.append( it->setName );
it->mtype = kUvSet;
}
}
m_numUVsets = m_uvSetNames.length();
m_numColorSets = m_colorSetNames.length();
m_maxSetNum = 0;
for ( ii = 0; ii<8; ii++)
if( m_mayaType[ii] != kNonMaya)
m_maxSetNum = ii + 1;
m_parsedUserAttribList = true;
}
#endif // if MAYA_7
int glslShaderNode::getColorSetNames(MStringArray& names)
{
if (!m_parsedUserAttribList)
parseUserAttributeList();
names = m_colorSetNames;
return m_numColorSets;
}
int glslShaderNode::getTexCoordSetNames( MStringArray &names)
{
if (!m_parsedUserAttribList)
parseUserAttributeList();
names = m_uvSetNames;
return m_numUVsets;
}
int glslShaderNode::normalsPerVertex() {
m_numNormals = 3;
return m_numNormals;
}
void glslShaderNode::configureUniformAttrib( MString &name, int pNum, shader::DataType type, shader::Semantic sm, float *defVal,
MFnDependencyNode &dn, MDGModifier &mod) {
uniformAttrib ua;
MFnNumericAttribute nAttrib;
MFnTypedAttribute tAttrib;
MStatus stat;
ua.name = name;
ua.pNum = pNum;
ua.dirty = true;
ua.type = type;
ua.attrib = MObject::kNullObj;
ua.attrib2 = MObject::kNullObj;
float min=0.0f, max=0.0f;
bool color = shader::isColor(sm);
bool clamped = shader::isClamped(sm);
shader::getLimits( sm, min, max);
switch (ua.type) {
case shader::dtFloat:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::kFloat);
if (clamped) {
nAttrib.setMin(min);
nAttrib.setMax(max);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0]);
else
nAttrib.setDefault( -1.0 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtVec2:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::k2Float);
if (clamped) {
nAttrib.setMin( min, min);
nAttrib.setMax( max, max);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0], defVal[1] );
else
nAttrib.setDefault( -1.0, -1.0 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtVec3:
if ( !dn.hasAttribute( name )) {
if (color) {
ua.attrib = nAttrib.createColor( name, name);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
}
else {
ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Float);
if (clamped) {
nAttrib.setMin( min, min, min);
nAttrib.setMax( max, max, max);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
else
nAttrib.setDefault( -1.0, -1.0, -1.0 );
}
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtVec4:
if ( !dn.hasAttribute( name )) {
if (color) {
ua.attrib = nAttrib.createColor( name, name);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
stat = mod.addAttribute( thisMObject(), ua.attrib );
ua.attrib2 = nAttrib.create( name + "Alpha", name + "Alpha", MFnNumericData::kFloat);
if (clamped) {
nAttrib.setMin( 0.0f);
nAttrib.setMax( 1.0f);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[3]);
else
nAttrib.setDefault( 1.0 );
stat = mod.addAttribute( thisMObject(), ua.attrib2 );
}
else {
ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Float);
if (clamped) {
nAttrib.setMin( min, min, min);
nAttrib.setMax( max, max, max);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
else
nAttrib.setDefault( -1.0, -1.0, -1.0 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
ua.attrib2 = nAttrib.create( name + "W", name + "W", MFnNumericData::kFloat);
if (clamped) {
nAttrib.setMin( min);
nAttrib.setMax( max);
}
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( defVal[3]);
else
nAttrib.setDefault( -1.0 );
stat = mod.addAttribute( thisMObject(), ua.attrib2 );
}
}
else {
ua.attrib = dn.attribute(name, &stat);
ua.attrib2 = dn.attribute( name + "W", &stat);
}
break;
case shader::dtBool:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::kBoolean);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
nAttrib.setDefault( true );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtInt:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::kInt);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
if (defVal)
nAttrib.setDefault( (int)defVal[0]);
else
nAttrib.setDefault( -1 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtIVec2:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::k2Int);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
nAttrib.setDefault( -1, -1 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtIVec3:
if ( !dn.hasAttribute( name )) {
ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Int);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
nAttrib.setInternal(true);
#endif
nAttrib.setKeyable( true );
nAttrib.setDefault( -1, -1, -1 );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtMat4:
if ( !dn.hasAttribute( name )) {
MFnMatrixAttribute mAttrib;
ua.attrib = mAttrib.create( name, name, MFnMatrixAttribute::kFloat);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
mAttrib.setInternal(true);
#endif
mAttrib.setKeyable( true );
stat = mod.addAttribute( thisMObject(), ua.attrib );
}
else {
ua.attrib = dn.attribute(name, &stat);
}
break;
case shader::dtBVec2:
case shader::dtBVec3:
case shader::dtIVec4:
case shader::dtBVec4:
case shader::dtMat2:
case shader::dtMat3:
return;
default:
MGlobal::displayWarning(MString("Unknown uniform parameter type for: ") + name);
};
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name);
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
m_uniformAttribList.push_back(ua);
}
void glslShaderNode::configureAttribs() {
MDGModifier mod;
{
for (std::vector<uniformAttrib>::iterator it=m_uniformAttribList.begin(); it<m_uniformAttribList.end(); it++) {
it->pNum = -1;
}
}
{
for (std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin(); it<m_samplerAttribList.end(); it++) {
it->pNum = -1;
}
}
{
for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
it->pNum = -1;
}
}
m_boundUniformList.clear();
MFnDependencyNode dn(thisMObject());
int ii;
if (m_shader && m_shader->valid()) {
for (ii=0; ii<m_shader->uniformCount(); ii++) {
MString name(m_shader->uniformName(ii));
if ( shader::isBound(m_shader->uniformSemantic(ii))) {
boundUniform bu;
bu.name = name;
bu.usage = m_shader->uniformSemantic(ii);
bu.pNum = ii;
m_boundUniformList.push_back(bu);
}
else {
std::vector<uniformAttrib>::iterator it=m_uniformAttribList.begin();
while (it < m_uniformAttribList.end()) {
if (it->name == name)
break;
it++;
}
if (it !=m_uniformAttribList.end()) {
if ( it->type == m_shader->uniformType(ii)) {
it->pNum = ii;
it->dirty = true;
continue;
}
else {
mod.removeAttribute( thisMObject(), it->attrib);
it->attrib = MObject::kNullObj;
if (it->attrib2 != MObject::kNullObj) {
mod.removeAttribute( thisMObject(), it->attrib2);
it->attrib2 = MObject::kNullObj;
}
}
}
configureUniformAttrib( name, ii, m_shader->uniformType(ii), m_shader->uniformSemantic(ii),
m_shader->uniformDefault(ii), dn, mod);
GL_CHECK;
}
}
for (ii=0; ii<m_shader->samplerCount(); ii++) {
MString name(m_shader->samplerName(ii));
std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin();
while (it < m_samplerAttribList.end()) {
if (it->name == name)
break;
it++;
}
if (it !=m_samplerAttribList.end()) {
it->pNum = ii;
it->dirty = false;
m_shader->updateSampler( ii, it->texName);
}
else {
samplerAttrib sa;
MFnNumericAttribute nAttrib;
MFnEnumAttribute eAttrib;
MStatus stat;
sa.name = name;
sa.pNum = ii;
sa.dirty = true;
sa.texName = 0;
sa.minFilter = GL_LINEAR;
sa.magFilter = GL_LINEAR;
sa.wrapMode = GL_REPEAT;
sa.maxAniso = 1.0f;
if ( !dn.hasAttribute( name )) {
sa.attrib = nAttrib.createColor( name, name);
nAttrib.setInternal(true);
stat = mod.addAttribute( thisMObject(), sa.attrib);
}
else {
sa.attrib = dn.attribute(name, &stat);
}
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name);
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
if ( !dn.hasAttribute( name +"MinFilter")) {
sa.minFilterAttrib = eAttrib.create( name+"MinFilter", name+"MinFilter");
eAttrib.addField( "Nearest", 0);
eAttrib.addField( "Linear", 1);
eAttrib.addField( "Linear, Mipmaped", 2);
eAttrib.addField( "Trilinear", 3);
eAttrib.setDefault( 1);
eAttrib.setInternal(true);
stat = mod.addAttribute( thisMObject(), sa.minFilterAttrib);
}
else {
sa.minFilterAttrib = dn.attribute(name+"MinFilter", &stat);
MPlug plug(thisMObject(), sa.minFilterAttrib);
short val;
plug.getValue(val);
switch (val) {
case 0:
sa.minFilter = GL_NEAREST;
break;
case 1:
sa.minFilter = GL_LINEAR;
break;
case 2:
sa.minFilter = GL_LINEAR_MIPMAP_NEAREST;
break;
case 3:
sa.minFilter = GL_LINEAR_MIPMAP_LINEAR;
break;
default:
sa.minFilter = GL_LINEAR;
break;
};
}
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name + "MinFilter");
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
if ( !dn.hasAttribute( name +"MagFilter")) {
sa.magFilterAttrib = eAttrib.create( name+"MagFilter", name+"MagFilter");
eAttrib.addField( "Nearest", 0);
eAttrib.addField( "Linear", 1);
eAttrib.setDefault( 1);
eAttrib.setInternal(true);
stat = mod.addAttribute( thisMObject(), sa.magFilterAttrib);
}
else {
sa.magFilterAttrib = dn.attribute(name+"MagFilter", &stat);
MPlug plug(thisMObject(), sa.magFilterAttrib);
short val;
plug.getValue(val);
switch (val) {
case 0:
sa.magFilter = GL_NEAREST;
break;
case 1:
sa.magFilter = GL_LINEAR;
break;
default:
sa.magFilter = GL_LINEAR;
break;
};
}
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name + "MagFilter");
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
if ( !dn.hasAttribute( name+"Wrap" )) {
sa.wrapAttrib = eAttrib.create( name+"Wrap", name+"Wrap");
eAttrib.addField( "Repeat", 0);
eAttrib.addField( "Clamp", 1);
eAttrib.addField( "Mirror", 2);
eAttrib.setDefault( 0);
eAttrib.setInternal(true);
stat = mod.addAttribute( thisMObject(), sa.wrapAttrib);
}
else {
sa.wrapAttrib = dn.attribute(name+"Wrap", &stat);
MPlug plug(thisMObject(), sa.wrapAttrib);
short val;
plug.getValue(val);
switch (val) {
case 0:
sa.wrapMode = GL_REPEAT;
break;
case 1:
sa.wrapMode = GL_CLAMP_TO_EDGE;
break;
case 2:
sa.wrapMode = GL_MIRRORED_REPEAT;
break;
default:
sa.wrapMode = GL_REPEAT;
break;
};
}
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name + "Wrap");
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
if ( !dn.hasAttribute( name+"MaxAniso" )) {
sa.anisoAttrib = nAttrib.create( name+"MaxAniso", name+"MaxAniso", MFnNumericData::kFloat, 1.0);
nAttrib.setInternal(true);
nAttrib.setMin( 1.0);
nAttrib.setMax( 16.0);
stat = mod.addAttribute( thisMObject(), sa.anisoAttrib);
}
else {
sa.anisoAttrib = dn.attribute(name+"MaxAniso", &stat);
MPlug plug(thisMObject(), sa.anisoAttrib);
float val;
plug.getValue(val);
sa.maxAniso = val;
}
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
error.format(error, name + "MaxAniso");
MGlobal::displayError(error);
MGlobal::displayError(stat.errorString());
}
m_samplerAttribList.push_back(sa);
GL_CHECK;
}
}
for (ii=0; ii<m_shader->attributeCount(); ii++) {
MString name(m_shader->attributeName(ii));
std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin();
while (it < m_attributeAttribList.end()) {
if (it->name == name)
break;
it++;
}
if (it !=m_attributeAttribList.end()) {
it->pNum = ii;
it->handle = m_shader->attributeHandle( ii);
it->set = -1;
}
else {
MFnTypedAttribute tAttrib;
attributeAttrib aa;
MStatus stat;
aa.name = name;
aa.setName = name;
aa.pNum = ii;
aa.handle = m_shader->attributeHandle(ii);
aa.set = -1;
aa.mtype = kNonMaya;
if ( !dn.hasAttribute( name )) {
aa.attrib = tAttrib.create( name, name, MFnData::kString);
tAttrib.setInternal(true);
tAttrib.setKeyable( true );
stat = mod.addAttribute( thisMObject(), aa.attrib);
}
else {
aa.attrib = dn.attribute(name, &stat);
}
m_attributeAttribList.push_back(aa);
}
}
}
for (ii=0; ii< (int)m_uniformAttribList.size(); ) {
if (m_uniformAttribList[ii].pNum == -1) {
if (m_uniformAttribList[ii].attrib != MObject::kNullObj ) {
mod.removeAttribute( thisMObject(), m_uniformAttribList[ii].attrib);
m_uniformAttribList[ii].attrib = MObject::kNullObj;
}
if ( m_uniformAttribList[ii].attrib2 != MObject::kNullObj ) {
mod.removeAttribute( thisMObject(), m_uniformAttribList[ii].attrib2);
m_uniformAttribList[ii].attrib2 = MObject::kNullObj;
}
m_uniformAttribList.erase(m_uniformAttribList.begin()+ii);
}
else {
ii++;
}
}
for (ii=0; ii<(int)m_samplerAttribList.size(); ) {
MStatus stat, stat2, stat3, stat4, stat5;
if (m_samplerAttribList[ii].pNum == -1) {
if ( m_samplerAttribList[ii].attrib != MObject::kNullObj )
stat = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].attrib);
if ( m_samplerAttribList[ii].magFilterAttrib != MObject::kNullObj )
stat2 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].magFilterAttrib);
if ( m_samplerAttribList[ii].minFilterAttrib != MObject::kNullObj )
stat3 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].minFilterAttrib);
if ( m_samplerAttribList[ii].wrapAttrib != MObject::kNullObj )
stat4 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].wrapAttrib);
if ( m_samplerAttribList[ii].anisoAttrib != MObject::kNullObj )
stat5 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].anisoAttrib);
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedDestroyAttribute, strStat);
error.format(error, m_samplerAttribList[ii].name);
MGlobal::displayError(error);
MGlobal::displayError(MString(" ") + stat.errorString());
}
ResourceManager::destroyTexture( m_samplerAttribList[ii].texName);
m_samplerAttribList[ii].attrib = MObject::kNullObj;
m_samplerAttribList.erase(m_samplerAttribList.begin()+ii);
}
else {
ii++;
}
}
for (ii=0; ii<(int)m_attributeAttribList.size(); ) {
MStatus stat;
if (m_attributeAttribList[ii].pNum == -1) {
stat = mod.removeAttribute( thisMObject(), m_attributeAttribList[ii].attrib);
if (stat != MStatus::kSuccess) {
MStatus strStat;
MString error = MStringResource::getString(rGLSLShaderNodeFailedDestroyAttribute, strStat);
error.format(error, m_attributeAttribList[ii].name);
MGlobal::displayError(MString(" ") + stat.errorString());
}
m_attributeAttribList[ii].attrib = MObject::kNullObj;
m_attributeAttribList.erase(m_attributeAttribList.begin()+ii);
}
else {
ii++;
}
}
GL_CHECK;
mod.doIt();
}
bool glslShaderNode::locateFile( const MString &name, MString &path) {
MString proj;
struct stat fstats;
MString temp;
MGlobal::executeCommand( MString("workspace -q -rd;"), proj);
if ( stat(name.asChar(), &fstats) == 0){
path = name;
return true;
}
char buffer[MAX_PATH_LENGTH];
if ( getcwd( buffer, MAX_PATH_LENGTH ) != NULL)
{
temp = MString(buffer) + "\\" + name;
if ( stat(temp.asChar(), &fstats) == 0){
path = temp;
return true;
}
}
temp = proj + "shaders/" + name;
if ( stat(temp.asChar(), &fstats) == 0){
path = temp;
return true;
}
temp = proj + name;
if ( stat(temp.asChar(), &fstats) == 0){
path = temp;
return true;
}
return false;
}
MStatus glslShaderNode::renderSwatchImage( MImage & outImage )
{
MStatus status = MStatus::kFailure;
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 );
return status2;
}
{
float light_pos[4];
pRenderer->getSwatchLightDirection( light_pos[0], light_pos[1], light_pos[2], light_pos[3] );
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, light_pos );
glPopMatrix();
float light_ambt[4] = {1.0f, 1.0f, 1.0f, 1.0};
float light_diff[4] = {1.0f, 1.0f, 1.0f, 1.0};
float light_spec[4] = {1.0f, 1.0f, 1.0f, 1.0};
glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambt );
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diff );
glLightfv( GL_LIGHT0, GL_SPECULAR, light_spec );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
GL_CHECK;
}
{
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 );
GL_CHECK;
}
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);
GL_CHECK;
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() );
unsigned int normalCount = 0;
float ** normalArrays = new float * [3];
if (normalData)
{
normalArrays[0] = normalData;
normalCount++;
}
else
normalArrays[0] = NULL;
if (tangentData)
{
normalArrays[1] = tangentData;
normalCount++;
}
else
normalArrays[1] = NULL;
if (binormalData)
{
normalArrays[2] = binormalData;
normalCount++;
}
else
normalArrays[2] = NULL;
unsigned int uvCount = 0;
float ** texCoordArrays = new float * [1];
if (uvData)
{
texCoordArrays[0] = uvData;
uvCount = 1;
}
else
texCoordArrays[0] = NULL;
m_setNums[0] = 0;
m_setNums[1] = 0;
m_setNums[2] = 0;
m_setNums[3] = 0;
m_setNums[4] = 0;
m_setNums[5] = 0;
m_setNums[6] = 0;
m_setNums[7] = 0;
m_mayaType[0] = kUvSet;
m_mayaType[1] = kTangent;
m_mayaType[2] = kBinormal;
m_mayaType[3] = kUvSet;
m_mayaType[4] = kUvSet;
m_mayaType[5] = kUvSet;
m_mayaType[6] = kUvSet;
m_mayaType[7] = kUvSet;
m_colorSetNums[0] = -1;
m_colorSetNums[1] = -1;
m_colorMayaType[0] = kColorSet;
m_colorMayaType[1] = kColorSet;
glGeometry( dummyPath,
GL_TRIANGLES,
false,
indexCount,
pIndexing,
0,
NULL,
vertexData,
normalCount,
(const float **) normalArrays,
0,
NULL,
uvCount,
(const float **) texCoordArrays);
glUnbind( dummyPath );
glFinish();
normalArrays[0] = NULL;
normalArrays[1] = NULL;
delete[] normalArrays;
texCoordArrays[0] = NULL;
delete[] texCoordArrays;
pRenderer->readSwatchContextPixels( backEndStr, outImage );
outImage.getSize( width, height );
if (width != origWidth || height != origHeight)
{
status = MStatus::kFailure;
}
else
{
status = MStatus::kSuccess;
}
}
GL_CHECK;
return status;
}
bool glslShaderNode::printVertexShader( int pass) {
if ( m_shader) {
const char *shader = m_shader->getVertexShader( pass);
if (shader) {
MGlobal::displayInfo(shader);
return true;
}
}
return false;
}
bool glslShaderNode::printPixelShader( int pass) {
if ( m_shader) {
const char *shader = m_shader->getPixelShader( pass);
if (shader) {
MGlobal::displayInfo(shader);
return true;
}
}
return false;
}
glslShaderNode* glslShaderNode::findNodeByName(const MString &name) {
for (std::vector<glslShaderNode*>::iterator it = sNodeList.begin(); it < sNodeList.end(); it++) {
if ( (*it)->name() == name)
return *it;
}
return NULL;
}