- Main Page
- Related Pages
- Modules
- Classes
- Examples

# cgfxVector.cpp

    //
    // 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 1995,2006,2008 Autodesk, Inc. All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk
    // license agreement provided at the time of installation or download,
    // or which otherwise accompanies this software in either electronic
    // or hard copy form.
    // ==========================================================================
    //+
    #include "cgfxShaderCommon.h"

    #include "cgfxVector.h"

    #include <maya/MMatrix.h>
    #include <maya/MFnMatrixAttribute.h>
    #include <maya/MFnMatrixData.h>
    #include <maya/MFnNumericAttribute.h>
    #include <maya/MPlug.h>

    // 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 <stdarg.h>

    #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;
    }