// // Copyright (C) 2002 NVIDIA // // File: cgfxVector.cpp // // Dependency Graph Node: cgfxVector // // Description: // The cgfxVector node is used to convert a vector in the scene to // world coordinates. The inputs are a vector in local coordinates, // a flag indicating whether the vector is a position or a direction, // and a matrix that will transoform the vector to world coordinates. // This matrix is generally the worldInverseMatrix of the vector. // // Author: Jim Atkinson // //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ #include "cgfxShaderCommon.h" #include "cgfxVector.h" #include #include #include #include #include // The typeid is a unique 32bit indentifier that describes this node. // It is used to save and retrieve nodes of this type from the binary // file format. If it is not unique, it will cause file IO problems. // #ifdef _WIN32 MTypeId cgfxVector::sId( 4084862001 ); #else MTypeId cgfxVector::sId( 0xF37A0C31 ); #endif // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // // Input vector attribute // MObject cgfxVector::sVector; MObject cgfxVector::sVectorX; MObject cgfxVector::sVectorY; MObject cgfxVector::sVectorZ; // Input position/direction flag. If isDirection is set then // the vector represents a direction and the W coordinate is // 0.0. If it is not set then W is 1.0. // MObject cgfxVector::sIsDirection; // Input matrix attribute // MObject cgfxVector::sMatrix; // Output world coordinate vector attribute // MObject cgfxVector::sWorldVector; MObject cgfxVector::sWorldVectorX; MObject cgfxVector::sWorldVectorY; MObject cgfxVector::sWorldVectorZ; MObject cgfxVector::sWorldVectorW; cgfxVector::cgfxVector() { // Nothing to construct } /* virtual */ cgfxVector::~cgfxVector() { // Nothing to destruct } #ifdef CGFX_DEBUG #include #ifdef _WIN32 // Disable in Linux build, because // our Linux compiler setting makes it to complain for unused vars and methods // static void dprintf(char* format, ...) { char buffer[1024]; va_list args; va_start(args, format); vsprintf(buffer, format, args); OutputDebugString(buffer); va_end(args); } #endif #else static inline void dprintf(char* format, ...) { // nothing } #endif /* virtual */ MStatus cgfxVector::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; MFnData::Type dataType = MFnData::kInvalid; if( plug == sWorldVector || plug == sWorldVectorX || plug == sWorldVectorY || plug == sWorldVectorZ || plug == sWorldVectorW) { // We do isDirection first simply because if there is an // error, the isDirection error is more legible than the // vector or matrix error. // MDataHandle dhIsDirection = data.inputValue(sIsDirection, &status); if (!status) { status.perror("cgfxVector: isDirection handle"); return status; } dataType = dhIsDirection.type(); MDataHandle dhVector = data.inputValue(sVector, &status); if (!status) { status.perror("cgfxVector: vector handle"); return status; } dataType = dhVector.type(); MMatrix matrix; MPlug matrixPlug(thisMObject(), sMatrix); if (matrixPlug.isNull()) { OutputDebugString("matrixPlug is NULL!\n"); } // TODO: Fix this kludge. // // We should not have to do this but for some reason, // using data.inputValue() fails for the sMatrix attribute. // Instead, we get a plug to the attribute and then get // the value directly. // MObject oMatrix; matrixPlug.getValue(oMatrix); MFnMatrixData fndMatrix(oMatrix, &status); if (!status) { status.perror("cgfxVector: matrix data"); } matrix= fndMatrix.matrix(&status); if (!status) { status.perror("cgfxVector: get matrix"); } #if 0 // TODO: This is how we are supposed to do it. (I think). // MDataHandle dhMatrix = data.inputValue(sMatrix, &status); if (!status) { status.perror("cgfxVector: matrix handle"); } dataType = dhMatrix.type(); oMatrix = dhMatrix.data(); MFnMatrixData fnMatrix(oMatrix, &status); if (!status) { status.perror("cgfxVector: matrix function set"); } matrix = fnMatrix.matrix(); #endif /* 0 */ bool isDirection = dhIsDirection.asBool(); double3& vector = dhVector.asDouble3(); double mat[4][4]; matrix.get(mat); double ix, iy, iz, iw; // Input vector float ox, oy, oz, ow; // Output vector ix = vector[0]; iy = vector[1]; iz = vector[2]; iw = isDirection ? 0.0 : 1.0; ox = (float)(mat[0][0] * ix + mat[1][0] * iy + mat[2][0] * iz + mat[3][0] * iw); oy = (float)(mat[0][1] * ix + mat[1][1] * iy + mat[2][1] * iz + mat[3][1] * iw); oz = (float)(mat[0][2] * ix + mat[1][2] * iy + mat[2][2] * iz + mat[3][2] * iw); ow = (float)(mat[0][3] * ix + mat[1][3] * iy + mat[2][3] * iz + mat[3][3] * iw); MDataHandle dhWVector = data.outputValue(sWorldVector, &status); if (!status) { status.perror("cgfxVector: worldVector handle"); return status; } MDataHandle dhWVectorW = data.outputValue(sWorldVectorW, &status); if (!status) { status.perror("cgfxVector: worldVectorW handle"); return status; } dhWVector.set(ox, oy, oz); dhWVectorW.set(ow); data.setClean(sWorldVector); data.setClean(sWorldVectorW); } else { return MS::kUnknownParameter; } return MS::kSuccess; } /* static */ void* cgfxVector::creator() { return new cgfxVector; } /* static */ MStatus cgfxVector::initialize() { MStatus status; MFnNumericAttribute nAttr; MFnMatrixAttribute mAttr; sVectorX = nAttr.create("vectorX", "vx", MFnNumericData::kDouble, 0.0, &status); if (!status) { status.perror("cgfxVector: create vectorX"); return status; } nAttr.setKeyable(true); sVectorY = nAttr.create("vectorY", "vy", MFnNumericData::kDouble, 0.0, &status); if (!status) { status.perror("cgfxVector: create vectorY"); return status; } nAttr.setKeyable(true); sVectorZ = nAttr.create("vectorZ", "vz", MFnNumericData::kDouble, 0.0, &status); if (!status) { status.perror("cgfxVector: create vectorZ"); return status; } nAttr.setKeyable(true); sVector = nAttr.create("vector", "v", sVectorX, sVectorY, sVectorZ, &status); if (!status) { status.perror("cgfxVector: create vector"); return status; } nAttr.setKeyable(true); sIsDirection = nAttr.create("isDirection", "id", MFnNumericData::kBoolean, 0.0, &status); if (!status) { status.perror("cgfxVector: create isDirection"); return status; } nAttr.setKeyable(true); nAttr.setDefault(false); sMatrix = mAttr.create("matrix", "m", MFnMatrixAttribute::kDouble, &status); if (!status) { status.perror("cgfxVector: create matrix"); return status; } mAttr.setWritable(true); mAttr.setStorable(true); sWorldVectorX = nAttr.create("worldVectorX", "wvx", MFnNumericData::kFloat, 0.0, &status); if (!status) { status.perror("cgfxVector: create worldVectorX"); return status; } nAttr.setWritable(false); nAttr.setStorable(false); sWorldVectorY = nAttr.create("worldVectorY", "wvy", MFnNumericData::kFloat, 0.0, &status); if (!status) { status.perror("cgfxVector: create worldVectorY"); return status; } nAttr.setWritable(false); nAttr.setStorable(false); sWorldVectorZ = nAttr.create("worldVectorZ", "wvz", MFnNumericData::kFloat, 0.0, &status); if (!status) { status.perror("cgfxVector: create worldVectorZ"); return status; } nAttr.setWritable(false); nAttr.setStorable(false); sWorldVectorW = nAttr.create("worldVectorW", "wvw", MFnNumericData::kFloat, 0.0, &status); if (!status) { status.perror("cgfxVector: create worldVectorW"); return status; } nAttr.setWritable(false); nAttr.setStorable(false); sWorldVector = nAttr.create("worldVector", "wv", sWorldVectorX, sWorldVectorY, sWorldVectorZ, &status); if( !status ) { status.perror("cgfxVector: create worldVector"); return status; } nAttr.setWritable(false); nAttr.setStorable(false); status = addAttribute(sVector); if (!status) { status.perror("cgfxVector: addAttribute vector"); return status; } status = addAttribute(sIsDirection); if (!status) { status.perror("cgfxVector: addAttribute isDirection"); return status; } status = addAttribute(sMatrix); if (!status) { status.perror("cgfxVector: addAttribute matrix"); return status; } status = addAttribute(sWorldVector); if (!status) { status.perror("cgfxVector: addAttribute worldVector"); return status; } status = addAttribute(sWorldVectorW); if (!status) { status.perror("cgfxVector: addAttribute worldVectorW"); return status; } status = attributeAffects(sVector, sWorldVector); if (!status) { status.perror("cgfxVector: attributeAffects vector -> worldVector"); return status; } status = attributeAffects(sIsDirection, sWorldVector); if (!status) { status.perror("cgfxVector: attributeAffects isDirection -> worldVector"); return status; } status = attributeAffects(sMatrix, sWorldVector); if (!status) { status.perror("cgfxVector: attributeAffects matrix -> worldVector"); return status; } status = attributeAffects(sVector, sWorldVectorW); if (!status) { status.perror("cgfxVector: attributeAffects vector -> worldVectorW"); return status; } status = attributeAffects(sIsDirection, sWorldVectorW); if (!status) { status.perror("cgfxVector: attributeAffects isDirection -> worldVectorW"); return status; } status = attributeAffects(sMatrix, sWorldVectorW); if (!status) { status.perror("cgfxVector: attributeAffects matrix -> worldVectorW"); return status; } return MS::kSuccess; }