├── CMakeLists.txt ├── LICENSE ├── README.md ├── plug-ins ├── linux-maya2016 │ └── xformArrayNodes.so ├── linux-maya2017 │ └── xformArrayNodes.so ├── windows-maya2016 │ └── xformArrayNodes.mll └── windows-maya2017 │ └── xformArrayNodes.mll └── src ├── commands ├── getArrayAttrCmd.cpp └── getArrayAttrCmd.h ├── data ├── angleArrayData.cpp ├── angleArrayData.h ├── arrayData.cpp ├── arrayData.h ├── eulerArrayData.cpp ├── eulerArrayData.h ├── quatArrayData.cpp └── quatArrayData.h ├── nodes ├── angleNodes │ ├── angleArrayCtorNode.cpp │ ├── angleArrayCtorNode.h │ ├── angleArrayIterNode.cpp │ ├── angleArrayIterNode.h │ ├── angleToDoubleArrayNode.cpp │ ├── angleToDoubleArrayNode.h │ ├── doubleToAngleArrayNode.cpp │ └── doubleToAngleArrayNode.h ├── eulerNodes │ ├── packEulerArrayNode.cpp │ ├── packEulerArrayNode.h │ ├── unpackEulerArrayNode.cpp │ └── unpackEulerArrayNode.h ├── matrixNodes │ ├── composeMatrixArrayNode.cpp │ ├── composeMatrixArrayNode.h │ ├── decomposeMatrixArrayNode.cpp │ ├── decomposeMatrixArrayNode.h │ ├── matrixArrayOpNode.cpp │ ├── matrixArrayOpNode.h │ ├── packMatrixArrayNode.cpp │ ├── packMatrixArrayNode.h │ ├── unpackMatrixArrayNode.cpp │ └── unpackMatrixArrayNode.h ├── nodeData.h ├── quatNodes │ ├── eulerToQuatArrayNode.cpp │ ├── eulerToQuatArrayNode.h │ ├── packQuatArrayNode.cpp │ ├── packQuatArrayNode.h │ ├── quatArrayBinaryOpNode.cpp │ ├── quatArrayBinaryOpNode.h │ ├── quatArrayUnaryOpNode.cpp │ ├── quatArrayUnaryOpNode.h │ ├── quatToEulerArrayNode.cpp │ ├── quatToEulerArrayNode.h │ ├── slerpQuatArrayNode.cpp │ ├── slerpQuatArrayNode.h │ ├── unpackQuatArrayNode.cpp │ └── unpackQuatArrayNode.h └── vectorNodes │ ├── lerpVectorArrayNode.cpp │ ├── lerpVectorArrayNode.h │ ├── packVectorArrayNode.cpp │ ├── packVectorArrayNode.h │ ├── pointToVectorArrayNode.cpp │ ├── pointToVectorArrayNode.h │ ├── rotateVectorArrayNode.cpp │ ├── rotateVectorArrayNode.h │ ├── unpackVectorArrayNode.cpp │ ├── unpackVectorArrayNode.h │ ├── vectorArrayBinaryOpNode.cpp │ ├── vectorArrayBinaryOpNode.h │ ├── vectorArrayMatrixOpNode.cpp │ ├── vectorArrayMatrixOpNode.h │ ├── vectorArrayScalarOpNode.cpp │ ├── vectorArrayScalarOpNode.h │ ├── vectorArrayToDoubleOpNode.cpp │ ├── vectorArrayToDoubleOpNode.h │ ├── vectorArrayUnaryOpNode.cpp │ ├── vectorArrayUnaryOpNode.h │ ├── vectorToPointArrayNode.cpp │ └── vectorToPointArrayNode.h └── pluginMain.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | # Download Chad Vernon's cgcmake package (https://github.com/chadmv/cgcmake/) 4 | # and make sure your CMAKE_MODULES_PATH environment variable points at it. 5 | 6 | set(CMAKE_MODULE_PATH "$ENV{CMAKE_MODULE_PATH}") 7 | 8 | project(xformArrayNodes) 9 | file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" "src/*.h") 10 | find_package(Maya REQUIRED) 11 | 12 | include_directories(${MAYA_INCLUDE_DIR}) 13 | link_directories(${MAYA_LIBRARY_DIR}) 14 | 15 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) 16 | target_link_libraries(${PROJECT_NAME} ${MAYA_LIBRARIES}) 17 | 18 | MAYA_PLUGIN(${PROJECT_NAME}) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ryan Porter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### xformArrayNodes 2 | Maya plugin with nodes designed to operate on transform components. 3 | 4 | #### Description 5 | See the [Wiki](https://github.com/yantor3d/xformArrayNodes/wiki) for full details. 6 | 7 | ## Plugin Contents 8 | ### Commands 9 | - getArrayAttr 10 | 11 | ### Data 12 | - angleArray 13 | - eulerArray 14 | - quatArray 15 | 16 | ### Nodes 17 | ##### Angle Array Nodes 18 | - angleArrayCtor 19 | - angleArrayIter 20 | - angleToDoubleArray 21 | - doubleToAngleArray 22 | ##### Euler Rotation Array Nodes 23 | - packEulerArray 24 | - unpackEulerArray 25 | ##### Matrix Array Nodes 26 | - composeMatrixArray 27 | - decomposeMatrixArray 28 | - matrixArrayOp 29 | - packMatrixArray 30 | - unpackMatrixArray 31 | ##### Quaternion Array Nodes 32 | - eulerToQuatArray 33 | - packQuatArray 34 | - quatArrayBinaryOp 35 | - quatArrayUnaryOp 36 | - quatToEulerArray 37 | - slerpQuatArray 38 | - unpackQuatArray 39 | ##### Vector Array Nodes 40 | - lerpVectorArray 41 | - packVectorArray 42 | - pointToVectorArray 43 | - rotateVectorArray 44 | - unpackVectorArray 45 | - vectorArrayBinaryOp 46 | - vectorArrayMatrixOp 47 | - vectorArrayScalarOp 48 | - vectorArrayToDoubleOp 49 | - vectorArrayUnaryOp 50 | - vectorToPointArray -------------------------------------------------------------------------------- /plug-ins/linux-maya2016/xformArrayNodes.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yantor3d/xformArrayNodes/2affb8c1818255c3e86d766a91a978bcdca819b9/plug-ins/linux-maya2016/xformArrayNodes.so -------------------------------------------------------------------------------- /plug-ins/linux-maya2017/xformArrayNodes.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yantor3d/xformArrayNodes/2affb8c1818255c3e86d766a91a978bcdca819b9/plug-ins/linux-maya2017/xformArrayNodes.so -------------------------------------------------------------------------------- /plug-ins/windows-maya2016/xformArrayNodes.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yantor3d/xformArrayNodes/2affb8c1818255c3e86d766a91a978bcdca819b9/plug-ins/windows-maya2016/xformArrayNodes.mll -------------------------------------------------------------------------------- /plug-ins/windows-maya2017/xformArrayNodes.mll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yantor3d/xformArrayNodes/2affb8c1818255c3e86d766a91a978bcdca819b9/plug-ins/windows-maya2017/xformArrayNodes.mll -------------------------------------------------------------------------------- /src/commands/getArrayAttrCmd.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class GetArrayAttrCmd : public MPxCommand 17 | { 18 | public: 19 | GetArrayAttrCmd(); 20 | virtual ~GetArrayAttrCmd(); 21 | 22 | static void* creator(); 23 | static MSyntax getSyntax(); 24 | 25 | virtual MStatus doIt(const MArgList& argList); 26 | virtual MStatus redoIt(); 27 | 28 | virtual bool isUndoable() const { return false; } 29 | virtual bool hasSyntax() const { return true; } 30 | 31 | private: 32 | void warnEmptyArray(); 33 | 34 | public: 35 | static MString COMMAND_NAME; 36 | 37 | private: 38 | MPlug requestedAttribute; 39 | }; -------------------------------------------------------------------------------- /src/data/angleArrayData.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | angleArray data 8 | Custom data type for a variable length array of doubleAngle values. 9 | This array is contiguous, unlike a multi-attribute, which may be sparse. 10 | */ 11 | 12 | #include "angleArrayData.h" 13 | #include "arrayData.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | AngleArrayData::AngleArrayData() {} 29 | 30 | AngleArrayData::~AngleArrayData() {} 31 | 32 | void* AngleArrayData::creator() 33 | { 34 | return new AngleArrayData; 35 | } 36 | 37 | 38 | unsigned int AngleArrayData::length() 39 | { 40 | return (unsigned int) this->data.size(); 41 | } 42 | 43 | 44 | MStatus AngleArrayData::readASCII(const MArgList& args, unsigned int &end) 45 | { 46 | MStatus status; 47 | 48 | std::vector values = readASCIIData(1, args, end, &status); 49 | if (status) { this->setValues(values); } 50 | 51 | return status; 52 | } 53 | 54 | 55 | MStatus AngleArrayData::writeASCII(std::ostream &out) 56 | { 57 | MStatus status; 58 | 59 | std::vector values = this->getValues(); 60 | status = writeASCIIData(values, this->length(), out); 61 | 62 | return status; 63 | } 64 | 65 | 66 | MStatus AngleArrayData::readBinary(std::istream &in, unsigned int length) 67 | { 68 | MStatus status; 69 | 70 | std::vector values = readBinaryData(1, in, length, &status); 71 | if (status) { this->setValues(values); } 72 | 73 | return status; 74 | } 75 | 76 | 77 | MStatus AngleArrayData::writeBinary(std::ostream &out) 78 | { 79 | MStatus status; 80 | 81 | std::vector values = this->getValues(); 82 | status = writeBinaryData(values, this->length(), out); 83 | 84 | return status; 85 | } 86 | 87 | 88 | std::vector AngleArrayData::getArray() 89 | { 90 | return std::vector(this->data); 91 | } 92 | 93 | 94 | void AngleArrayData::setArray(std::vector &array) 95 | { 96 | this->data.resize(array.size()); 97 | std::copy( 98 | array.begin(), 99 | array.end(), 100 | this->data.begin() 101 | ); 102 | } 103 | 104 | 105 | void AngleArrayData::setValues(std::vector &values) 106 | { 107 | MAngle::Unit u = MAngle::uiUnit(); 108 | size_t numberOfItems = values.size(); 109 | this->data.resize(numberOfItems); 110 | 111 | for (size_t i = 0; i < numberOfItems; i++) 112 | { 113 | this->data[i] = MAngle(values[i], u); 114 | } 115 | } 116 | 117 | 118 | std::vector AngleArrayData::getValues() 119 | { 120 | std::vector values; 121 | size_t numberOfItems = data.size(); 122 | values.resize(numberOfItems); 123 | 124 | for (size_t i = 0; i < numberOfItems; i++) 125 | { 126 | values[i] = data[i].value(); 127 | } 128 | 129 | return values; 130 | } 131 | 132 | 133 | void AngleArrayData::copy(const MPxData& other) 134 | { 135 | if (this->typeId() == other.typeId()) 136 | { 137 | const AngleArrayData &otherData = (const AngleArrayData &) other; 138 | this->data.resize(otherData.data.size()); 139 | std::copy( 140 | otherData.data.begin(), 141 | otherData.data.end(), 142 | this->data.begin() 143 | ); 144 | } 145 | } 146 | 147 | MTypeId AngleArrayData::typeId() const 148 | { 149 | return AngleArrayData::TYPE_ID; 150 | } 151 | 152 | 153 | MString AngleArrayData::name() const 154 | { 155 | return AngleArrayData::TYPE_NAME; 156 | } -------------------------------------------------------------------------------- /src/data/angleArrayData.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class AngleArrayData : public MPxData 20 | { 21 | public: 22 | AngleArrayData(); 23 | virtual ~AngleArrayData(); 24 | static void* creator(); 25 | 26 | virtual MStatus readASCII(const MArgList &argList, unsigned int &end); 27 | virtual MStatus writeASCII(std::ostream &out); 28 | 29 | virtual MStatus readBinary(std::istream &in, unsigned int length); 30 | virtual MStatus writeBinary(std::ostream &out); 31 | 32 | virtual void copy(const MPxData &src); 33 | 34 | virtual unsigned int length(); 35 | virtual std::vector getArray(); 36 | virtual void setArray(std::vector &array); 37 | 38 | virtual MTypeId typeId() const; 39 | virtual MString name() const; 40 | 41 | public: 42 | static const MTypeId TYPE_ID; 43 | static const MString TYPE_NAME; 44 | 45 | private: 46 | virtual void setValues(std::vector &values); 47 | virtual std::vector getValues(); 48 | 49 | private: 50 | std::vector data; 51 | }; -------------------------------------------------------------------------------- /src/data/arrayData.cpp: -------------------------------------------------------------------------------- 1 | #include "arrayData.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | std::vector readASCIIData(unsigned numberOfElementsPerItem, const MArgList &args, unsigned int &end, MStatus *ReturnStatus) 15 | { 16 | std::vector result; 17 | MStatus status; 18 | 19 | unsigned numberOfItems = (unsigned) args.asInt(end++, &status); 20 | unsigned int numberOfArguments = args.length() - end; 21 | unsigned int numberOfValues = numberOfItems * numberOfElementsPerItem; 22 | 23 | if (status) 24 | { 25 | if ( 26 | numberOfItems != numberOfArguments && 27 | (numberOfItems * numberOfElementsPerItem) != numberOfArguments 28 | ) { 29 | status = MStatus::kInvalidParameter; 30 | } 31 | } 32 | 33 | if (status) 34 | { 35 | int valuesParsed = 0; 36 | 37 | result.resize(numberOfItems * numberOfElementsPerItem); 38 | 39 | bool argumentsAreInTuples = numberOfElementsPerItem > 1 && (numberOfItems == numberOfArguments); 40 | 41 | if (argumentsAreInTuples) 42 | { 43 | unsigned n = numberOfElementsPerItem; 44 | 45 | for (unsigned i = 0; i < numberOfItems; i++) 46 | { 47 | unsigned int idx = end; end++; 48 | MStringArray argStr = args.asStringArray(idx, &status); 49 | 50 | if (status && argStr.length() == n) 51 | { 52 | for (unsigned j = 0; j < n; j++) 53 | { 54 | if (argStr[j].isDouble()) 55 | { 56 | result[(i*n)+j] = argStr[j].asDouble(); 57 | valuesParsed++; 58 | } 59 | } 60 | } 61 | } 62 | } else { 63 | for (unsigned i = 0; i < numberOfArguments; i++) 64 | { 65 | MString arg = args.asString(end++, &status); 66 | 67 | if (status && arg.isDouble()) 68 | { 69 | result[i] = arg.asDouble(); 70 | valuesParsed++; 71 | } 72 | } 73 | } 74 | 75 | status = valuesParsed == numberOfValues ? MStatus::kSuccess : MStatus::kFailure; 76 | } 77 | 78 | 79 | if (ReturnStatus) { *ReturnStatus = status; } 80 | 81 | return result; 82 | } 83 | 84 | 85 | std::vector readBinaryData(unsigned numberOfElementsPerItem, std::istream &in, unsigned int length, MStatus *ReturnStatus) 86 | { 87 | bool readFailed = false; 88 | 89 | std::vector result; 90 | 91 | if (length > 0) 92 | { 93 | unsigned numberOfItems; 94 | in.read((char*) &numberOfItems, sizeof(numberOfItems)); 95 | 96 | if (in.fail()) 97 | { 98 | readFailed = true; 99 | } else { 100 | result.resize(numberOfItems * numberOfElementsPerItem); 101 | 102 | for (unsigned i = 0; i < numberOfItems * numberOfElementsPerItem; i++) 103 | { 104 | in.read((char*) &result[i], sizeof(result[i])); 105 | readFailed = in.fail(); 106 | 107 | if (readFailed) { break; } 108 | } 109 | } 110 | } 111 | 112 | if (ReturnStatus) 113 | { 114 | *ReturnStatus = readFailed ? MStatus::kFailure : MStatus::kSuccess; 115 | } 116 | 117 | return result; 118 | } 119 | 120 | 121 | MStatus writeASCIIData(std::vector values, unsigned numberOfItems, std::ostream &out) 122 | { 123 | MStatus status; 124 | 125 | size_t numberOfValues = values.size(); 126 | 127 | out << numberOfItems << " "; 128 | 129 | if (out.fail()) 130 | { 131 | status = MStatus::kFailure; 132 | } else { 133 | for (size_t i = 0; i < numberOfValues; i++) 134 | { 135 | out << values[i] << " "; 136 | 137 | if (out.fail()) 138 | { 139 | status = MStatus::kFailure; 140 | break; 141 | } 142 | } 143 | } 144 | 145 | return status; 146 | } 147 | 148 | 149 | MStatus writeBinaryData(std::vector values, unsigned numberOfItems, std::ostream &out) 150 | { 151 | MStatus status; 152 | 153 | size_t numberOfValues = values.size(); 154 | out.write((char*) &numberOfItems, sizeof(numberOfItems)); 155 | 156 | if (out.fail()) 157 | { 158 | status = MStatus::kFailure; 159 | } else { 160 | for (size_t i = 0; i < numberOfValues; i++) 161 | { 162 | out.write((char*) &values[i], sizeof(values[i])); 163 | 164 | if (out.fail()) 165 | { 166 | status = MStatus::kFailure; 167 | break; 168 | } 169 | } 170 | } 171 | 172 | return status; 173 | } 174 | -------------------------------------------------------------------------------- /src/data/arrayData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | std::vector readASCIIData(unsigned numberOfElementsPerItem, const MArgList &args, unsigned int &end, MStatus *ReturnStatus=NULL); 11 | std::vector readBinaryData(unsigned numberOfElementsPerItem, std::istream &in, unsigned int length, MStatus *ReturnStatus=NULL); 12 | 13 | MStatus writeASCIIData(std::vector values, unsigned numberOfItems, std::ostream &out); 14 | MStatus writeBinaryData(std::vector values, unsigned numberOfItems, std::ostream &out); 15 | -------------------------------------------------------------------------------- /src/data/eulerArrayData.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | eulerArray data 8 | Custom data type for a variable length array of euler rotations. 9 | This array is contiguous, unlike a multi-attribute, which may be sparse. 10 | */ 11 | 12 | #include "eulerArrayData.h" 13 | #include "arrayData.h" 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | EulerArrayData::EulerArrayData() {} 36 | EulerArrayData::~EulerArrayData() {} 37 | 38 | void* EulerArrayData::creator() 39 | { 40 | return new EulerArrayData; 41 | } 42 | 43 | 44 | unsigned int EulerArrayData::length() 45 | { 46 | return (unsigned int) this->data.size(); 47 | } 48 | 49 | 50 | MStatus EulerArrayData::readASCII(const MArgList& args, unsigned int &end) 51 | { 52 | MStatus status; 53 | 54 | std::vector values = readASCIIData(3, args, end, &status); 55 | if (status) { this->setValues(values); } 56 | 57 | return status; 58 | } 59 | 60 | 61 | MStatus EulerArrayData::writeASCII(std::ostream &out) 62 | { 63 | MStatus status; 64 | 65 | std::vector values = this->getValues(); 66 | status = writeASCIIData(values, this->length(), out); 67 | 68 | return status; 69 | } 70 | 71 | 72 | MStatus EulerArrayData::readBinary(std::istream &in, unsigned int length) 73 | { 74 | MStatus status; 75 | 76 | std::vector values = readBinaryData(3, in, length, &status); 77 | if (status) { this->setValues(values); } 78 | 79 | return status; 80 | } 81 | 82 | 83 | MStatus EulerArrayData::writeBinary(std::ostream &out) 84 | { 85 | MStatus status; 86 | 87 | std::vector values = this->getValues(); 88 | status = writeBinaryData(values, this->length(), out); 89 | 90 | return status; 91 | } 92 | 93 | 94 | std::vector EulerArrayData::getArray() 95 | { 96 | return std::vector(this->data); 97 | } 98 | 99 | 100 | void EulerArrayData::setArray(std::vector &array) 101 | { 102 | this->data.resize(array.size()); 103 | std::copy( 104 | array.begin(), 105 | array.end(), 106 | this->data.begin() 107 | ); 108 | } 109 | 110 | 111 | void EulerArrayData::setValues(std::vector &values) 112 | { 113 | size_t numberOfValues = values.size(); 114 | size_t numberOfItems = numberOfValues / 3; 115 | this->data.resize(numberOfItems); 116 | 117 | MAngle::Unit unit = MAngle::uiUnit(); 118 | 119 | for (size_t i = 0; i < numberOfItems; i++) 120 | { 121 | this->data[i] = MEulerRotation( 122 | MAngle(values[(i*3)+0], unit).asRadians(), 123 | MAngle(values[(i*3)+1], unit).asRadians(), 124 | MAngle(values[(i*3)+2], unit).asRadians(), 125 | MEulerRotation::RotationOrder::kXYZ 126 | ); 127 | } 128 | } 129 | 130 | 131 | std::vector EulerArrayData::getValues() 132 | { 133 | std::vector values; 134 | size_t numberOfItems = this->data.size(); 135 | values.resize(numberOfItems * 3); 136 | 137 | for (size_t i = 0; i < numberOfItems; i++) 138 | { 139 | MEulerRotation &rot = this->data[i]; 140 | values[(i*3)+0] = rot.x; 141 | values[(i*3)+1] = rot.y; 142 | values[(i*3)+2] = rot.z; 143 | } 144 | 145 | return values; 146 | } 147 | 148 | void EulerArrayData::copy(const MPxData& other) 149 | { 150 | if (this->typeId() == other.typeId()) 151 | { 152 | const EulerArrayData &otherData = (const EulerArrayData &) other; 153 | this->data.resize(otherData.data.size()); 154 | std::copy( 155 | otherData.data.begin(), 156 | otherData.data.end(), 157 | this->data.begin() 158 | ); 159 | } 160 | } 161 | 162 | MTypeId EulerArrayData::typeId() const 163 | { 164 | return EulerArrayData::TYPE_ID; 165 | } 166 | 167 | 168 | MString EulerArrayData::name() const 169 | { 170 | return EulerArrayData::TYPE_NAME; 171 | } -------------------------------------------------------------------------------- /src/data/eulerArrayData.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class EulerArrayData : public MPxData 20 | { 21 | public: 22 | EulerArrayData(); 23 | virtual ~EulerArrayData(); 24 | static void* creator(); 25 | 26 | virtual MStatus readASCII(const MArgList &argList, unsigned int &end); 27 | virtual MStatus writeASCII(std::ostream &out); 28 | 29 | virtual MStatus readBinary(std::istream &in, unsigned int length); 30 | virtual MStatus writeBinary(std::ostream &out); 31 | 32 | virtual void copy(const MPxData &src); 33 | 34 | virtual unsigned int length(); 35 | virtual std::vector getArray(); 36 | virtual void setArray(std::vector &array); 37 | 38 | virtual MTypeId typeId() const; 39 | virtual MString name() const; 40 | 41 | static const MTypeId TYPE_ID; 42 | static const MString TYPE_NAME; 43 | 44 | private: 45 | virtual void setValues(std::vector &values); 46 | virtual std::vector getValues(); 47 | 48 | private: 49 | std::vector data; 50 | }; -------------------------------------------------------------------------------- /src/data/quatArrayData.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | quatArray data 8 | Custom data type for a variable length array of quaternion rotations. 9 | This array is contiguous, unlike a multi-attribute, which may be sparse. 10 | */ 11 | 12 | #include "quatArrayData.h" 13 | #include "arrayData.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | QuatArrayData::QuatArrayData() {} 28 | QuatArrayData::~QuatArrayData() {} 29 | 30 | void* QuatArrayData::creator() 31 | { 32 | return new QuatArrayData; 33 | } 34 | 35 | 36 | unsigned int QuatArrayData::length() 37 | { 38 | return (unsigned int) this->data.size(); 39 | } 40 | 41 | 42 | MStatus QuatArrayData::readASCII(const MArgList& args, unsigned int &end) 43 | { 44 | MStatus status; 45 | 46 | std::vector values = readASCIIData(4, args, end, &status); 47 | if (status) { this->setValues(values); } 48 | 49 | return status; 50 | } 51 | 52 | 53 | MStatus QuatArrayData::writeASCII(std::ostream &out) 54 | { 55 | MStatus status; 56 | 57 | std::vector values = this->getValues(); 58 | status = writeASCIIData(values, this->length(), out); 59 | 60 | return status; 61 | } 62 | 63 | 64 | MStatus QuatArrayData::readBinary(std::istream &in, unsigned int length) 65 | { 66 | MStatus status; 67 | 68 | std::vector values = readBinaryData(4, in, length, &status); 69 | if (status) { this->setValues(values); } 70 | 71 | return status; 72 | } 73 | 74 | 75 | MStatus QuatArrayData::writeBinary(std::ostream &out) 76 | { 77 | MStatus status; 78 | 79 | std::vector values = this->getValues(); 80 | status = writeBinaryData(values, this->length(), out); 81 | 82 | return status; 83 | } 84 | 85 | 86 | std::vector QuatArrayData::getArray() 87 | { 88 | return std::vector(this->data); 89 | } 90 | 91 | 92 | void QuatArrayData::setArray(std::vector &array) 93 | { 94 | this->data.resize(array.size()); 95 | std::copy( 96 | array.begin(), 97 | array.end(), 98 | this->data.begin() 99 | ); 100 | } 101 | 102 | 103 | void QuatArrayData::setValues(std::vector &values) 104 | { 105 | size_t numberOfValues = values.size(); 106 | size_t numberOfItems = numberOfValues / 4; 107 | this->data.resize(numberOfItems); 108 | 109 | for (size_t i = 0; i < numberOfItems; i++) 110 | { 111 | this->data[i] = MQuaternion( 112 | values[(i*4)+0], 113 | values[(i*4)+1], 114 | values[(i*4)+2], 115 | values[(i*4)+3] 116 | ); 117 | } 118 | } 119 | 120 | 121 | std::vector QuatArrayData::getValues() 122 | { 123 | std::vector values; 124 | size_t numberOfItems = this->data.size(); 125 | values.resize(numberOfItems * 4); 126 | 127 | for (size_t i = 0; i < numberOfItems; i++) 128 | { 129 | MQuaternion &q = this->data[i]; 130 | values[(i*4)+0] = q.x; 131 | values[(i*4)+1] = q.y; 132 | values[(i*4)+2] = q.z; 133 | values[(i*4)+3] = q.w; 134 | } 135 | 136 | return values; 137 | } 138 | 139 | 140 | void QuatArrayData::copy(const MPxData& other) 141 | { 142 | if (this->typeId() == other.typeId()) 143 | { 144 | const QuatArrayData &otherData = (const QuatArrayData &) other; 145 | this->data.resize(otherData.data.size()); 146 | std::copy( 147 | otherData.data.begin(), 148 | otherData.data.end(), 149 | this->data.begin() 150 | ); 151 | } 152 | } 153 | 154 | 155 | MTypeId QuatArrayData::typeId() const 156 | { 157 | return QuatArrayData::TYPE_ID; 158 | } 159 | 160 | 161 | MString QuatArrayData::name() const 162 | { 163 | return QuatArrayData::TYPE_NAME; 164 | } -------------------------------------------------------------------------------- /src/data/quatArrayData.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class QuatArrayData : public MPxData 20 | { 21 | public: 22 | QuatArrayData(); 23 | virtual ~QuatArrayData(); 24 | static void* creator(); 25 | 26 | virtual MStatus readASCII(const MArgList &argList, unsigned int &end); 27 | virtual MStatus writeASCII(std::ostream &out); 28 | 29 | virtual MStatus readBinary(std::istream &in, unsigned int length); 30 | virtual MStatus writeBinary(std::ostream &out); 31 | 32 | virtual void copy(const MPxData &src); 33 | 34 | virtual unsigned int length(); 35 | virtual std::vector getArray(); 36 | virtual void setArray(std::vector &array); 37 | 38 | virtual MTypeId typeId() const; 39 | virtual MString name() const; 40 | 41 | static const MTypeId TYPE_ID; 42 | static const MString TYPE_NAME; 43 | 44 | private: 45 | virtual void setValues(std::vector &values); 46 | virtual std::vector getValues(); 47 | 48 | private: 49 | std::vector data; 50 | }; -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleArrayCtorNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | angleArrayCtor node 8 | This node outputs a contiguous array of doubleAngle values. 9 | 10 | input (i) doubleAngle[] 11 | An array of doubleAngle values. 12 | 13 | fillValue (fv) doubleAngle3 14 | Default value. Indices that are missing from the input array will be filled with this value. 15 | 16 | size (s) int 17 | Size of the output array. 18 | 19 | output (o) arrayAngle 20 | An array of doubleAngle values. 21 | */ 22 | 23 | #include 24 | 25 | #include "../nodeData.h" 26 | #include "../../data/angleArrayData.h" 27 | #include "angleArrayCtorNode.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | MObject AngleArrayCtorNode::inputAttr; 42 | MObject AngleArrayCtorNode::fillValueAttr; 43 | MObject AngleArrayCtorNode::sizeAttr; 44 | 45 | MObject AngleArrayCtorNode::outputAttr; 46 | 47 | 48 | void* AngleArrayCtorNode::creator() 49 | { 50 | return new AngleArrayCtorNode(); 51 | } 52 | 53 | 54 | MStatus AngleArrayCtorNode::initialize() 55 | { 56 | MStatus status; 57 | 58 | MFnNumericAttribute N; 59 | MFnTypedAttribute T; 60 | MFnUnitAttribute U; 61 | 62 | inputAttr = U.create("input", "i", MFnUnitAttribute::kAngle, 0, &status); 63 | U.setArray(true); 64 | 65 | fillValueAttr = U.create("fillValue", "fv", MFnUnitAttribute::kAngle, 0, &status); 66 | U.setChannelBox(true); 67 | U.setKeyable(true); 68 | 69 | sizeAttr = N.create("size", "s", MFnNumericData::kInt, 8, &status); 70 | N.setMin(0); 71 | N.setChannelBox(true); 72 | N.setKeyable(true); 73 | 74 | addAttribute(inputAttr); 75 | addAttribute(fillValueAttr); 76 | addAttribute(sizeAttr); 77 | 78 | outputAttr = T.create("output", "o", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 79 | T.setStorable(false); 80 | 81 | addAttribute(outputAttr); 82 | 83 | attributeAffects(inputAttr, outputAttr); 84 | attributeAffects(fillValueAttr, outputAttr); 85 | attributeAffects(sizeAttr, outputAttr); 86 | 87 | return MStatus::kSuccess; 88 | } 89 | 90 | 91 | MStatus AngleArrayCtorNode::compute(const MPlug& plug, MDataBlock& data) 92 | { 93 | MStatus status; 94 | 95 | if (plug != outputAttr) 96 | { 97 | return MStatus::kInvalidParameter; 98 | } 99 | 100 | MArrayDataHandle inputArrayHandle = data.inputArrayValue(inputAttr); 101 | MAngle fillValue = data.inputValue(fillValueAttr).asAngle(); 102 | unsigned size = (unsigned) data.inputValue(sizeAttr).asInt(); 103 | 104 | std::vector values = getArrayElements( 105 | inputArrayHandle, 106 | &AngleArrayCtorNode::getElement, 107 | size, 108 | fillValue 109 | ); 110 | 111 | MDataHandle outputHandle = data.outputValue(outputAttr); 112 | 113 | setUserArray(outputHandle, values); 114 | 115 | return MStatus::kSuccess; 116 | } 117 | 118 | 119 | MAngle AngleArrayCtorNode::getElement(MDataHandle &elementHandle) 120 | { 121 | return elementHandle.asAngle(); 122 | } -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleArrayCtorNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class AngleArrayCtorNode : public MPxNode 17 | { 18 | public: 19 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 20 | static void* creator(); 21 | static MStatus initialize(); 22 | 23 | static MAngle getElement(MDataHandle &elementHandle); 24 | 25 | public: 26 | static MTypeId NODE_ID; 27 | static MString NODE_NAME; 28 | 29 | static MObject inputAttr; 30 | static MObject fillValueAttr; 31 | static MObject sizeAttr; 32 | 33 | static MObject outputAttr; 34 | }; -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleArrayIterNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | angleArrayIter node 8 | This node outputs the elements of a contiguous doubleAngle array. 9 | 10 | input (i) angleArray 11 | An array of doubleAngle values. 12 | 13 | output (o) doubleAngle[] 14 | An array of doubleAngle values. 15 | 16 | */ 17 | 18 | #include "../../data/angleArrayData.h" 19 | #include "../nodeData.h" 20 | #include "angleArrayIterNode.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | MObject AngleArrayIterNode::inputAttr; 39 | 40 | MObject AngleArrayIterNode::outputAttr; 41 | 42 | 43 | void* AngleArrayIterNode::creator() 44 | { 45 | return new AngleArrayIterNode(); 46 | } 47 | 48 | 49 | MStatus AngleArrayIterNode::initialize() 50 | { 51 | MStatus status; 52 | 53 | MFnTypedAttribute T; 54 | MFnUnitAttribute U; 55 | 56 | inputAttr = T.create("input", "i", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 57 | 58 | addAttribute(inputAttr); 59 | 60 | outputAttr = U.create("output", "o", MFnUnitAttribute::kAngle, 0, &status); 61 | U.setArray(true); 62 | U.setStorable(false); 63 | U.setUsesArrayDataBuilder(true); 64 | 65 | addAttribute(outputAttr); 66 | 67 | attributeAffects(inputAttr, outputAttr); 68 | 69 | return MStatus::kSuccess; 70 | } 71 | 72 | 73 | MStatus AngleArrayIterNode::compute(const MPlug& plug, MDataBlock& data) 74 | { 75 | MStatus status; 76 | 77 | if (plug != outputAttr) 78 | { 79 | return MStatus::kInvalidParameter; 80 | } 81 | 82 | MDataHandle inputHandle = data.inputValue(inputAttr); 83 | std::vector values = getUserArray(inputHandle); 84 | 85 | MArrayDataHandle outputArrayHandle = data.outputArrayValue(outputAttr, &status); 86 | status = setArrayElements(outputArrayHandle, values, &AngleArrayIterNode::setElement); 87 | 88 | return status; 89 | } 90 | 91 | MStatus AngleArrayIterNode::setElement(MDataHandle &elementHandle, MAngle value) 92 | { 93 | elementHandle.setMAngle(value); 94 | return MStatus::kSuccess; 95 | } -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleArrayIterNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class AngleArrayIterNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | static MStatus setElement(MDataHandle &elementHandle, MAngle value); 22 | 23 | public: 24 | static MTypeId NODE_ID; 25 | static MString NODE_NAME; 26 | 27 | static MObject inputAttr; 28 | 29 | static MObject outputAttr; 30 | }; -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleToDoubleArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | angleToDoubleArray node 8 | This node converts an array of doubleAngle values to an array of double values. 9 | 10 | input (i) angleArray 11 | An array of doubleAngle values. 12 | 13 | output (o) doubleArray 14 | An array of double values. 15 | 16 | */ 17 | 18 | #include "../../data/angleArrayData.h" 19 | #include "../nodeData.h" 20 | #include "angleToDoubleArrayNode.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | MObject AngleToDoubleArrayNode::inputAttr; 37 | 38 | MObject AngleToDoubleArrayNode::outputAttr; 39 | 40 | 41 | void* AngleToDoubleArrayNode::creator() 42 | { 43 | return new AngleToDoubleArrayNode(); 44 | } 45 | 46 | 47 | MStatus AngleToDoubleArrayNode::initialize() 48 | { 49 | MStatus status; 50 | 51 | MFnTypedAttribute T; 52 | 53 | inputAttr = T.create("input", "i", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 54 | 55 | addAttribute(inputAttr); 56 | 57 | outputAttr = T.create("output", "o", MFnData::kDoubleArray, MObject::kNullObj, &status); 58 | T.setStorable(false); 59 | 60 | addAttribute(outputAttr); 61 | 62 | attributeAffects(inputAttr, outputAttr); 63 | 64 | return MStatus::kSuccess; 65 | } 66 | 67 | 68 | MStatus AngleToDoubleArrayNode::compute(const MPlug& plug, MDataBlock& data) 69 | { 70 | MStatus status; 71 | 72 | if (plug != outputAttr) 73 | { 74 | return MStatus::kInvalidParameter; 75 | } 76 | 77 | MDataHandle inputHandle = data.inputValue(inputAttr); 78 | std::vector input = getUserArray(inputHandle); 79 | 80 | std::vector output(input.size()); 81 | 82 | MAngle::Unit unit = MAngle::uiUnit(); 83 | 84 | for (size_t i = 0; i < input.size(); i++) 85 | { 86 | output[i] = input[i].as(unit); 87 | } 88 | 89 | MDataHandle outputHandle = data.outputValue(outputAttr); 90 | setMayaArray(outputHandle, output); 91 | 92 | return MStatus::kSuccess; 93 | } -------------------------------------------------------------------------------- /src/nodes/angleNodes/angleToDoubleArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class AngleToDoubleArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputAttr; 26 | 27 | static MObject outputAttr; 28 | }; -------------------------------------------------------------------------------- /src/nodes/angleNodes/doubleToAngleArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | doubleToAngleArray node 8 | This node converts an array of double values to an array of doubleAngle values. 9 | 10 | input (i) doubleArray 11 | An array of double values. 12 | 13 | output (o) angleArray 14 | An array of doubleAngle values. 15 | 16 | */ 17 | 18 | #include "../../data/angleArrayData.h" 19 | #include "../nodeData.h" 20 | #include "doubleToAngleArrayNode.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | MObject DoubleToAngleArrayNode::inputAttr; 36 | 37 | MObject DoubleToAngleArrayNode::outputAttr; 38 | 39 | 40 | void* DoubleToAngleArrayNode::creator() 41 | { 42 | return new DoubleToAngleArrayNode(); 43 | } 44 | 45 | 46 | MStatus DoubleToAngleArrayNode::initialize() 47 | { 48 | MStatus status; 49 | 50 | MFnTypedAttribute T; 51 | 52 | inputAttr = T.create("input", "i", MFnData::kDoubleArray, MObject::kNullObj, &status); 53 | 54 | addAttribute(inputAttr); 55 | 56 | outputAttr = T.create("output", "o", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 57 | T.setStorable(false); 58 | 59 | addAttribute(outputAttr); 60 | 61 | attributeAffects(inputAttr, outputAttr); 62 | 63 | return MStatus::kSuccess; 64 | } 65 | 66 | 67 | MStatus DoubleToAngleArrayNode::compute(const MPlug& plug, MDataBlock& data) 68 | { 69 | MStatus status; 70 | 71 | if (plug != outputAttr) 72 | { 73 | return MStatus::kInvalidParameter; 74 | } 75 | 76 | MDataHandle inputHandle = data.inputValue(inputAttr); 77 | std::vector input = getMayaArray(inputHandle); 78 | 79 | std::vector output(input.size()); 80 | 81 | MAngle::Unit unit = MAngle::uiUnit(); 82 | 83 | for (size_t i = 0; i < input.size(); i++) 84 | { 85 | output[i] = MAngle(input[i], unit); 86 | } 87 | 88 | MDataHandle outputHandle = data.outputValue(outputAttr); 89 | setUserArray(outputHandle, output); 90 | 91 | return MStatus::kSuccess; 92 | } -------------------------------------------------------------------------------- /src/nodes/angleNodes/doubleToAngleArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class DoubleToAngleArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputAttr; 26 | 27 | static MObject outputAttr; 28 | }; -------------------------------------------------------------------------------- /src/nodes/eulerNodes/packEulerArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | packEulerArray node 8 | This node outputs an array of euler rotation values. 9 | 10 | inputRotate (ir) doubleAngle3[] 11 | Trios of angles that describe an array of euler rotations. 12 | 13 | inputAngleX (iax) angleArray 14 | Angles that describe the X component of a euler rotation. 15 | 16 | inputAngleY (iay) angleArray 17 | Angles that describe the Y component of a euler rotation. 18 | 19 | inputAngleZ (iaz) angleArray 20 | Angles that describe the Z component of a euler rotation. 21 | 22 | fillValue (fv) doubleAngle3 23 | Trio of angles that describe an euler rotation. 24 | 25 | size (s) int 26 | Size of the output array. If the output is larger than the input, 27 | missing values will be filled in with the fillValue. 28 | 29 | inputMethod (im) enum 30 | Specifies the source of the angle components. 31 | 32 | Elements (0) uses the components in the "inputRotate" list. 33 | Components (1) uses the components in the "inputAngle" arrays. 34 | 35 | outputRotate (or) eulerArray 36 | An array of euler rotation values. 37 | 38 | */ 39 | 40 | #include "../../data/angleArrayData.h" 41 | #include "../../data/eulerArrayData.h" 42 | #include "../nodeData.h" 43 | #include "packEulerArrayNode.h" 44 | 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | 64 | MObject PackEulerArrayNode::inputRotateAttr; 65 | MObject PackEulerArrayNode::inputRotateXAttr; 66 | MObject PackEulerArrayNode::inputRotateYAttr; 67 | MObject PackEulerArrayNode::inputRotateZAttr; 68 | MObject PackEulerArrayNode::inputAngleXAttr; 69 | MObject PackEulerArrayNode::inputAngleYAttr; 70 | MObject PackEulerArrayNode::inputAngleZAttr; 71 | MObject PackEulerArrayNode::fillValueAttr; 72 | MObject PackEulerArrayNode::fillValueXAttr; 73 | MObject PackEulerArrayNode::fillValueYAttr; 74 | MObject PackEulerArrayNode::fillValueZAttr; 75 | MObject PackEulerArrayNode::inputMethodAttr; 76 | MObject PackEulerArrayNode::sizeAttr; 77 | 78 | MObject PackEulerArrayNode::outputRotateAttr; 79 | 80 | 81 | void* PackEulerArrayNode::creator() 82 | { 83 | return new PackEulerArrayNode(); 84 | } 85 | 86 | 87 | MStatus PackEulerArrayNode::initialize() 88 | { 89 | MStatus status; 90 | 91 | MFnCompoundAttribute C; 92 | MFnEnumAttribute E; 93 | MFnNumericAttribute N; 94 | MFnTypedAttribute T; 95 | MFnUnitAttribute U; 96 | 97 | inputRotateXAttr = U.create("inputRotateX", "irX", MFnUnitAttribute::kAngle, 0, &status); 98 | inputRotateYAttr = U.create("inputRotateY", "irY", MFnUnitAttribute::kAngle, 0, &status); 99 | inputRotateZAttr = U.create("inputRotateZ", "irZ", MFnUnitAttribute::kAngle, 0, &status); 100 | inputRotateAttr = C.create("inputRotate", "ir", &status); 101 | C.setArray(true); 102 | C.addChild(inputRotateXAttr); 103 | C.addChild(inputRotateYAttr); 104 | C.addChild(inputRotateZAttr); 105 | 106 | inputAngleXAttr = T.create("inputAngleX", "iax", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 107 | inputAngleYAttr = T.create("inputAngleY", "iay", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 108 | inputAngleZAttr = T.create("inputAngleZ", "iaz", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 109 | 110 | fillValueXAttr = U.create("fillValueX", "fvx", MFnUnitAttribute::kAngle, 0, &status); 111 | fillValueYAttr = U.create("fillValueY", "fvy", MFnUnitAttribute::kAngle, 0, &status); 112 | fillValueZAttr = U.create("fillValueZ", "fvz", MFnUnitAttribute::kAngle, 0, &status); 113 | fillValueAttr = C.create("fillValue", "fv", &status); 114 | C.addChild(fillValueXAttr); 115 | C.addChild(fillValueYAttr); 116 | C.addChild(fillValueZAttr); 117 | C.setChannelBox(true); 118 | C.setKeyable(true); 119 | 120 | sizeAttr = N.create("size", "s", MFnNumericData::kInt, 8, &status); 121 | N.setChannelBox(true); 122 | N.setKeyable(true); 123 | N.setMin(0); 124 | 125 | inputMethodAttr = E.create("inputMethod", "im", 0, &status); 126 | E.setChannelBox(true); 127 | E.setKeyable(true); 128 | E.addField("From Rotate", 0); 129 | E.addField("From Angles", 1); 130 | 131 | addAttribute(sizeAttr); 132 | addAttribute(inputRotateAttr); 133 | addAttribute(inputAngleXAttr); 134 | addAttribute(inputAngleYAttr); 135 | addAttribute(inputAngleZAttr); 136 | addAttribute(fillValueAttr); 137 | addAttribute(inputMethodAttr); 138 | 139 | outputRotateAttr = T.create("outputRotate", "or", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 140 | T.setStorable(false); 141 | 142 | addAttribute(outputRotateAttr); 143 | 144 | attributeAffects(sizeAttr, outputRotateAttr); 145 | attributeAffects(inputRotateAttr, outputRotateAttr); 146 | attributeAffects(inputAngleXAttr, outputRotateAttr); 147 | attributeAffects(inputAngleYAttr, outputRotateAttr); 148 | attributeAffects(inputAngleZAttr, outputRotateAttr); 149 | attributeAffects(fillValueAttr, outputRotateAttr); 150 | attributeAffects(inputMethodAttr, outputRotateAttr); 151 | 152 | return MStatus::kSuccess; 153 | } 154 | 155 | 156 | MStatus PackEulerArrayNode::compute(const MPlug& plug, MDataBlock& data) 157 | { 158 | MStatus status; 159 | 160 | if (plug != outputRotateAttr) 161 | { 162 | return MStatus::kInvalidParameter; 163 | } 164 | 165 | short inputMethod = data.inputValue(inputMethodAttr).asShort(); 166 | unsigned size = (unsigned) data.inputValue(sizeAttr).asInt(); 167 | std::vector outputRotate; 168 | 169 | MDataHandle fillValueHandle = data.inputValue(fillValueAttr); 170 | 171 | MAngle fillValueX = fillValueHandle.child(fillValueXAttr).asAngle(); 172 | MAngle fillValueY = fillValueHandle.child(fillValueYAttr).asAngle(); 173 | MAngle fillValueZ = fillValueHandle.child(fillValueZAttr).asAngle(); 174 | 175 | MEulerRotation fillValue( 176 | fillValueX.value(), 177 | fillValueY.value(), 178 | fillValueZ.value() 179 | ); 180 | 181 | if (inputMethod == 0) 182 | { 183 | MArrayDataHandle inputRotateArrayHandle = data.inputArrayValue(inputRotateAttr); 184 | 185 | outputRotate = getArrayElements( 186 | inputRotateArrayHandle, 187 | &PackEulerArrayNode::getElement, 188 | size, 189 | fillValue 190 | ); 191 | } else if (inputMethod == 1) { 192 | MDataHandle inputXHandle = data.inputValue(inputAngleXAttr); 193 | MDataHandle inputYHandle = data.inputValue(inputAngleYAttr); 194 | MDataHandle inputZHandle = data.inputValue(inputAngleZAttr); 195 | 196 | std::vector inputRotateX = getUserArray(inputXHandle); 197 | std::vector inputRotateY = getUserArray(inputYHandle); 198 | std::vector inputRotateZ = getUserArray(inputZHandle); 199 | 200 | unsigned numberOfInputs = 0; 201 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRotateX.size()); 202 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRotateY.size()); 203 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRotateZ.size()); 204 | 205 | inputRotateX.resize(numberOfInputs, fillValueX.value()); 206 | inputRotateY.resize(numberOfInputs, fillValueY.value()); 207 | inputRotateZ.resize(numberOfInputs, fillValueZ.value()); 208 | outputRotate.resize(size, fillValue); 209 | 210 | unsigned numberOfOutputs = std::min(size, numberOfInputs); 211 | 212 | for (unsigned i = 0; i < numberOfOutputs; i++) 213 | { 214 | outputRotate[i] = MEulerRotation( 215 | inputRotateX[i].asRadians(), 216 | inputRotateY[i].asRadians(), 217 | inputRotateZ[i].asRadians() 218 | ); 219 | } 220 | } 221 | 222 | MDataHandle outputHandle = data.outputValue(outputRotateAttr); 223 | setUserArray(outputHandle, outputRotate); 224 | 225 | return MStatus::kSuccess; 226 | } 227 | 228 | MEulerRotation PackEulerArrayNode::getElement(MDataHandle &elementHandle) 229 | { 230 | return MEulerRotation( 231 | elementHandle.child(inputRotateXAttr).asAngle().asRadians(), 232 | elementHandle.child(inputRotateYAttr).asAngle().asRadians(), 233 | elementHandle.child(inputRotateZAttr).asAngle().asRadians() 234 | ); 235 | } -------------------------------------------------------------------------------- /src/nodes/eulerNodes/packEulerArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class PackEulerArrayNode : public MPxNode 17 | { 18 | public: 19 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 20 | static void* creator(); 21 | static MStatus initialize(); 22 | 23 | static MEulerRotation getElement(MDataHandle &elementHandle); 24 | 25 | public: 26 | static MTypeId NODE_ID; 27 | static MString NODE_NAME; 28 | 29 | static MObject sizeAttr; 30 | static MObject inputRotateAttr; 31 | static MObject inputRotateXAttr; 32 | static MObject inputRotateYAttr; 33 | static MObject inputRotateZAttr; 34 | static MObject inputAngleXAttr; 35 | static MObject inputAngleYAttr; 36 | static MObject inputAngleZAttr; 37 | static MObject fillValueAttr; 38 | static MObject fillValueXAttr; 39 | static MObject fillValueYAttr; 40 | static MObject fillValueZAttr; 41 | static MObject inputMethodAttr; 42 | 43 | static MObject outputRotateAttr; 44 | }; -------------------------------------------------------------------------------- /src/nodes/eulerNodes/unpackEulerArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | unpackEulerArray node 8 | This node outputs arrays of the angles that make up euler rotation values. 9 | 10 | inputRotate (ir) eulerArray 11 | Array of euler rotation values. 12 | 13 | outputRotate (or) doubleAngle3[] 14 | Trios of angles that describe an array of euler rotations. 15 | 16 | outputAngleX (oax) angleArray 17 | Angles that describe the X component of a euler rotation. 18 | 19 | outputAngleY (oay) angleArray 20 | Angles that describe the Y component of a euler rotation. 21 | 22 | outputAngleZ (oaz) angleArray 23 | Angles that describe the Z component of a euler rotation. 24 | 25 | */ 26 | 27 | #include "../../data/angleArrayData.h" 28 | #include "../../data/eulerArrayData.h" 29 | #include "../nodeData.h" 30 | #include "unpackEulerArrayNode.h" 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | 49 | MObject UnpackEulerArrayNode::inputRotateAttr; 50 | 51 | MObject UnpackEulerArrayNode::outputRotateAttr; 52 | MObject UnpackEulerArrayNode::outputRotateXAttr; 53 | MObject UnpackEulerArrayNode::outputRotateYAttr; 54 | MObject UnpackEulerArrayNode::outputRotateZAttr; 55 | MObject UnpackEulerArrayNode::outputAngleXAttr; 56 | MObject UnpackEulerArrayNode::outputAngleYAttr; 57 | MObject UnpackEulerArrayNode::outputAngleZAttr; 58 | 59 | 60 | void* UnpackEulerArrayNode::creator() 61 | { 62 | return new UnpackEulerArrayNode(); 63 | } 64 | 65 | 66 | MStatus UnpackEulerArrayNode::initialize() 67 | { 68 | MStatus status; 69 | 70 | MFnNumericAttribute N; 71 | MFnTypedAttribute T; 72 | MFnUnitAttribute U; 73 | 74 | inputRotateAttr = T.create("inputRotate", "ir", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 75 | 76 | addAttribute(inputRotateAttr); 77 | 78 | outputRotateXAttr = U.create("outputRotateX", "orX", MFnUnitAttribute::kAngle, 0, &status); 79 | outputRotateYAttr = U.create("outputRotateY", "orY", MFnUnitAttribute::kAngle, 0, &status); 80 | outputRotateZAttr = U.create("outputRotateZ", "orZ", MFnUnitAttribute::kAngle, 0, &status); 81 | outputRotateAttr = N.create("outputRotate", "or", outputRotateXAttr, outputRotateYAttr, outputRotateZAttr, &status); 82 | N.setArray(true); 83 | N.setStorable(false); 84 | N.setUsesArrayDataBuilder(true); 85 | 86 | outputAngleXAttr = T.create("outputAngleX", "oax", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 87 | T.setStorable(false); 88 | 89 | outputAngleYAttr = T.create("outputAngleY", "oay", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 90 | T.setStorable(false); 91 | 92 | outputAngleZAttr = T.create("outputAngleZ", "oaz", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 93 | T.setStorable(false); 94 | 95 | addAttribute(outputRotateAttr); 96 | addAttribute(outputAngleXAttr); 97 | addAttribute(outputAngleYAttr); 98 | addAttribute(outputAngleZAttr); 99 | 100 | attributeAffects(inputRotateAttr, outputRotateAttr); 101 | attributeAffects(inputRotateAttr, outputAngleXAttr); 102 | attributeAffects(inputRotateAttr, outputAngleYAttr); 103 | attributeAffects(inputRotateAttr, outputAngleZAttr); 104 | 105 | return MStatus::kSuccess; 106 | } 107 | 108 | 109 | MStatus UnpackEulerArrayNode::compute(const MPlug& plug, MDataBlock& data) 110 | { 111 | MStatus status; 112 | 113 | if ( 114 | plug != outputRotateAttr && 115 | plug != outputAngleXAttr && 116 | plug != outputAngleYAttr && 117 | plug != outputAngleZAttr 118 | ) { 119 | return MStatus::kInvalidParameter; 120 | } 121 | 122 | MDataHandle inputHandle = data.inputValue(inputRotateAttr); 123 | std::vector inputRotate = getUserArray(inputHandle); 124 | unsigned numberOfInputs = (unsigned) inputRotate.size(); 125 | 126 | MArrayDataHandle outputRotateArrayHandle = data.outputArrayValue(outputRotateAttr); 127 | 128 | setArrayElements( 129 | outputRotateArrayHandle, 130 | inputRotate, 131 | &UnpackEulerArrayNode::setElement 132 | ); 133 | 134 | { 135 | std::vector outputX(numberOfInputs); 136 | std::vector outputY(numberOfInputs); 137 | std::vector outputZ(numberOfInputs); 138 | 139 | for (unsigned i = 0; i < numberOfInputs; i++) 140 | { 141 | MEulerRotation &r = inputRotate[i]; 142 | outputX[i] = MAngle(r.x); 143 | outputY[i] = MAngle(r.y); 144 | outputZ[i] = MAngle(r.z); 145 | } 146 | 147 | MDataHandle outputXHandle = data.outputValue(outputAngleXAttr); 148 | MDataHandle outputYHandle = data.outputValue(outputAngleYAttr); 149 | MDataHandle outputZHandle = data.outputValue(outputAngleZAttr); 150 | 151 | setUserArray(outputXHandle, outputX); 152 | setUserArray(outputYHandle, outputY); 153 | setUserArray(outputZHandle, outputZ); 154 | } 155 | 156 | return MStatus::kSuccess; 157 | } 158 | 159 | MStatus UnpackEulerArrayNode::setElement(MDataHandle &elementHandle, MEulerRotation value) 160 | { 161 | MDataHandle outputRotateXHandle = elementHandle.child(outputRotateXAttr); 162 | MDataHandle outputRotateYHandle = elementHandle.child(outputRotateYAttr); 163 | MDataHandle outputRotateZHandle = elementHandle.child(outputRotateZAttr); 164 | 165 | outputRotateXHandle.setMAngle(MAngle(value.x)); 166 | outputRotateYHandle.setMAngle(MAngle(value.y)); 167 | outputRotateZHandle.setMAngle(MAngle(value.z)); 168 | 169 | return MStatus::kSuccess; 170 | } -------------------------------------------------------------------------------- /src/nodes/eulerNodes/unpackEulerArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class UnpackEulerArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | static MStatus setElement(MDataHandle &elementHandle, MEulerRotation value); 22 | 23 | public: 24 | static MTypeId NODE_ID; 25 | static MString NODE_NAME; 26 | 27 | static MObject inputRotateAttr; 28 | 29 | static MObject outputRotateAttr; 30 | static MObject outputRotateXAttr; 31 | static MObject outputRotateYAttr; 32 | static MObject outputRotateZAttr; 33 | static MObject outputAngleXAttr; 34 | static MObject outputAngleYAttr; 35 | static MObject outputAngleZAttr; 36 | }; -------------------------------------------------------------------------------- /src/nodes/matrixNodes/composeMatrixArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | composeMatrixArray node 8 | This node constructs matrices from transform components. 9 | 10 | inputTranslate (it) pointArray 11 | Translate component of a transform. 12 | 13 | inputRotate (it) eulerArray 14 | Rotation component of a transform as an euler rotation. 15 | 16 | inputQuat (iq) quatArray 17 | Rotation component of a transform as an quaternion rotation. 18 | 19 | inputScale (is) vectorArray 20 | Scale component of a transform. 21 | 22 | inputShear (ish) vectorArray 23 | Shear component of a transform. 24 | 25 | inputRotateOrder (iro) enum 26 | Rotation order of an euler rotation. 27 | 28 | useEulerRotation (uer) bool 29 | If true, the matrices' will be built using the euler rotation input. 30 | Otherwise, the matrices' will be built using the quaternion input. 31 | 32 | outputMatrix (om) matrixArray 33 | The matrices composed from transform components. 34 | 35 | */ 36 | 37 | #include "composeMatrixArrayNode.h" 38 | 39 | #include "../nodeData.h" 40 | #include "../../data/angleArrayData.h" 41 | #include "../../data/eulerArrayData.h" 42 | #include "../../data/quatArrayData.h" 43 | 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | 69 | MObject ComposeMatrixArrayNode::inputTranslateAttr; 70 | MObject ComposeMatrixArrayNode::inputRotateAttr; 71 | MObject ComposeMatrixArrayNode::inputQuatAttr; 72 | MObject ComposeMatrixArrayNode::inputScaleAttr; 73 | MObject ComposeMatrixArrayNode::inputShearAttr; 74 | MObject ComposeMatrixArrayNode::inputRotateOrderAttr; 75 | MObject ComposeMatrixArrayNode::useEulerRotationAttr; 76 | 77 | MObject ComposeMatrixArrayNode::outputMatrixAttr; 78 | 79 | 80 | void* ComposeMatrixArrayNode::creator() 81 | { 82 | return new ComposeMatrixArrayNode(); 83 | } 84 | 85 | 86 | MStatus ComposeMatrixArrayNode::initialize() 87 | { 88 | MStatus status; 89 | 90 | MFnEnumAttribute E; 91 | MFnNumericAttribute N; 92 | MFnTypedAttribute T; 93 | 94 | inputTranslateAttr = T.create("inputTranslate", "it", MFnData::kVectorArray, MObject::kNullObj, &status); 95 | inputRotateAttr = T.create("inputRotate", "ir", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 96 | inputQuatAttr = T.create("inputQuat", "iq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 97 | inputScaleAttr = T.create("inputScale", "is", MFnData::kVectorArray, MObject::kNullObj, &status); 98 | inputShearAttr = T.create("inputShear", "ish", MFnData::kVectorArray, MObject::kNullObj, &status); 99 | 100 | useEulerRotationAttr = N.create("useEulerRotation", "uer", MFnNumericData::kBoolean, true, &status); 101 | N.setChannelBox(true); 102 | N.setKeyable(true); 103 | 104 | inputRotateOrderAttr = E.create("inputRotateOrder", "iro", 0, &status); 105 | E.setChannelBox(true); 106 | E.setKeyable(true); 107 | E.addField("xyz", 0); 108 | E.addField("yzx", 1); 109 | E.addField("zxy", 2); 110 | E.addField("xzy", 3); 111 | E.addField("yxz", 4); 112 | E.addField("zyx", 5); 113 | 114 | addAttribute(inputTranslateAttr); 115 | addAttribute(inputRotateAttr); 116 | addAttribute(inputRotateOrderAttr); 117 | addAttribute(useEulerRotationAttr); 118 | addAttribute(inputQuatAttr); 119 | addAttribute(inputScaleAttr); 120 | addAttribute(inputShearAttr); 121 | 122 | outputMatrixAttr = T.create("outputMatrix", "om", MFnData::kMatrixArray, MObject::kNullObj, &status); 123 | T.setStorable(false); 124 | 125 | addAttribute(outputMatrixAttr); 126 | 127 | attributeAffects(inputTranslateAttr, outputMatrixAttr); 128 | attributeAffects(inputRotateAttr, outputMatrixAttr); 129 | attributeAffects(inputQuatAttr, outputMatrixAttr); 130 | attributeAffects(inputScaleAttr, outputMatrixAttr); 131 | attributeAffects(inputShearAttr, outputMatrixAttr); 132 | attributeAffects(inputRotateOrderAttr, outputMatrixAttr); 133 | attributeAffects(useEulerRotationAttr, outputMatrixAttr); 134 | 135 | return MStatus::kSuccess; 136 | } 137 | 138 | 139 | MStatus ComposeMatrixArrayNode::compute(const MPlug& plug, MDataBlock& data) 140 | { 141 | MStatus status; 142 | 143 | if (plug != outputMatrixAttr) 144 | { 145 | return MStatus::kInvalidParameter; 146 | } 147 | 148 | MDataHandle inputTranslateHandle = data.inputValue(inputTranslateAttr); 149 | MDataHandle inputRotateHandle = data.inputValue(inputRotateAttr); 150 | MDataHandle inputQuatHandle = data.inputValue(inputQuatAttr); 151 | MDataHandle inputScaleHandle = data.inputValue(inputScaleAttr); 152 | MDataHandle inputShearHandle = data.inputValue(inputShearAttr); 153 | 154 | std::vector translate = getMayaArray(inputTranslateHandle); 155 | std::vector scale = getMayaArray(inputScaleHandle); 156 | std::vector shear = getMayaArray(inputShearHandle); 157 | 158 | std::vector eulerRotate = getUserArray(inputRotateHandle); 159 | std::vector quatRotate = getUserArray(inputQuatHandle); 160 | 161 | bool useEulerRotation = data.inputValue(useEulerRotationAttr).asBool(); 162 | 163 | size_t numberOfTranslates = translate.size(); 164 | size_t numberOfEulerRotates = eulerRotate.size(); 165 | size_t numberOfQuatRotates = quatRotate.size(); 166 | size_t numberOfScales = scale.size(); 167 | size_t numberOfShears = shear.size(); 168 | 169 | size_t numberOfOutputs = 0; 170 | numberOfOutputs = std::max(numberOfOutputs, numberOfTranslates); 171 | numberOfOutputs = std::max(numberOfOutputs, useEulerRotation ? numberOfEulerRotates : numberOfQuatRotates); 172 | numberOfOutputs = std::max(numberOfOutputs, numberOfScales); 173 | numberOfOutputs = std::max(numberOfOutputs, numberOfShears); 174 | 175 | double values[3] {0.0, 0.0, 0.0}; 176 | std::vector matrix(numberOfOutputs); 177 | 178 | for (size_t i = 0; i < numberOfTranslates; i++) 179 | { 180 | matrix[i].setTranslation(translate[i], MSpace::Space::kWorld); 181 | } 182 | 183 | if (useEulerRotation) 184 | { 185 | short rotateOrderIdx = data.inputValue(inputRotateOrderAttr).asShort(); 186 | MTransformationMatrix::RotationOrder rotateOrder = (MTransformationMatrix::RotationOrder) rotateOrderIdx; 187 | 188 | for (size_t i = 0; i < numberOfEulerRotates; i++) 189 | { 190 | MEulerRotation &e = eulerRotate[i]; 191 | matrix[i].rotateTo(e); 192 | } 193 | } else { 194 | for (size_t i = 0; i < numberOfQuatRotates; i++) 195 | { 196 | MQuaternion &q = quatRotate[i]; 197 | matrix[i].rotateTo(q); 198 | } 199 | } 200 | 201 | for (size_t i = 0; i < numberOfScales; i++) 202 | { 203 | MVector &s = scale[i]; 204 | values[0] = s.x; 205 | values[1] = s.y; 206 | values[2] = s.z; 207 | matrix[i].setScale(values, MSpace::Space::kWorld); 208 | } 209 | 210 | for (size_t i = 0; i < numberOfShears; i++) 211 | { 212 | MVector &sh = shear[i]; 213 | values[0] = sh.x; 214 | values[1] = sh.y; 215 | values[2] = sh.z; 216 | matrix[i].setShear(values, MSpace::Space::kWorld); 217 | } 218 | 219 | std::vector output(numberOfOutputs); 220 | 221 | for (size_t i = 0; i < numberOfOutputs; i++) 222 | { 223 | output[i] = matrix[i].asMatrix(); 224 | } 225 | 226 | MDataHandle outputHandle = data.outputValue(outputMatrixAttr); 227 | setMayaArray(outputHandle, output); 228 | 229 | return MStatus::kSuccess; 230 | } -------------------------------------------------------------------------------- /src/nodes/matrixNodes/composeMatrixArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class ComposeMatrixArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputTranslateAttr; 26 | static MObject inputRotateAttr; 27 | static MObject inputQuatAttr; 28 | static MObject inputScaleAttr; 29 | static MObject inputShearAttr; 30 | static MObject inputRotateOrderAttr; 31 | static MObject useEulerRotationAttr; 32 | 33 | static MObject outputMatrixAttr; 34 | }; -------------------------------------------------------------------------------- /src/nodes/matrixNodes/decomposeMatrixArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | decomposeMatrixArray node 8 | This node decomposes matrices into their transform components. 9 | 10 | inputMatrix (im) matrixArray 11 | List of matrices to be decomposed. 12 | 13 | inputRotateOrder (ori) enum 14 | Rotation order for the output rotate component. 15 | 16 | outputTranslate (ot) vectorArray 17 | Translate component of the matrices. 18 | 19 | outputRotate (ot) eulerArray 20 | Rotation component of the matrices as euler rotations. 21 | 22 | outputQuat (oq) quatArray 23 | Rotation component of the matrices as quaternion rotations. 24 | 25 | outputScale (os) vectorArray 26 | Scale component of the matrices. 27 | 28 | outputShear (osh) vectorArray 29 | Shear component of the matrices. 30 | 31 | */ 32 | 33 | #include "decomposeMatrixArrayNode.h" 34 | 35 | #include "../nodeData.h" 36 | #include "../../data/angleArrayData.h" 37 | #include "../../data/eulerArrayData.h" 38 | #include "../../data/quatArrayData.h" 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | 61 | MObject DecomposeMatrixArrayNode::inputMatrixAttr; 62 | MObject DecomposeMatrixArrayNode::inputRotateOrderAttr; 63 | 64 | MObject DecomposeMatrixArrayNode::outputAttr; 65 | MObject DecomposeMatrixArrayNode::outputTranslateAttr; 66 | MObject DecomposeMatrixArrayNode::outputRotateAttr; 67 | MObject DecomposeMatrixArrayNode::outputQuatAttr; 68 | MObject DecomposeMatrixArrayNode::outputScaleAttr; 69 | MObject DecomposeMatrixArrayNode::outputShearAttr; 70 | 71 | 72 | void* DecomposeMatrixArrayNode::creator() 73 | { 74 | return new DecomposeMatrixArrayNode(); 75 | } 76 | 77 | 78 | MStatus DecomposeMatrixArrayNode::initialize() 79 | { 80 | MStatus status; 81 | 82 | MFnCompoundAttribute C; 83 | MFnEnumAttribute E; 84 | MFnTypedAttribute T; 85 | 86 | inputMatrixAttr = T.create("inputMatrix", "im", MFnData::kMatrixArray, MObject::kNullObj, &status); 87 | 88 | inputRotateOrderAttr = E.create("inputRotateOrder", "ori", 0, &status); 89 | E.setChannelBox(true); 90 | E.setKeyable(true); 91 | E.addField("xyz", 0); 92 | E.addField("yzx", 1); 93 | E.addField("zxy", 2); 94 | E.addField("xzy", 3); 95 | E.addField("yxz", 4); 96 | E.addField("zyx", 5); 97 | 98 | addAttribute(inputMatrixAttr); 99 | addAttribute(inputRotateOrderAttr); 100 | 101 | outputTranslateAttr = T.create("outputTranslate", "ot", MFnData::kVectorArray, MObject::kNullObj, &status); 102 | T.setStorable(false); 103 | 104 | outputRotateAttr = T.create("outputRotate", "or", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 105 | T.setStorable(false); 106 | 107 | outputQuatAttr = T.create("outputQuat", "oq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 108 | T.setStorable(false); 109 | 110 | outputScaleAttr = T.create("outputScale", "os", MFnData::kVectorArray, MObject::kNullObj, &status); 111 | T.setStorable(false); 112 | 113 | outputShearAttr = T.create("outputShear", "osh", MFnData::kVectorArray, MObject::kNullObj, &status); 114 | T.setStorable(false); 115 | 116 | outputAttr = C.create("output", "o", &status); 117 | C.addChild(outputTranslateAttr); 118 | C.addChild(outputRotateAttr); 119 | C.addChild(outputQuatAttr); 120 | C.addChild(outputScaleAttr); 121 | C.addChild(outputShearAttr); 122 | C.setStorable(false); 123 | 124 | addAttribute(outputAttr); 125 | 126 | attributeAffects(inputMatrixAttr, outputAttr); 127 | attributeAffects(inputRotateOrderAttr, outputAttr); 128 | 129 | return MStatus::kSuccess; 130 | } 131 | 132 | 133 | MStatus DecomposeMatrixArrayNode::compute(const MPlug& plug, MDataBlock& data) 134 | { 135 | MStatus status; 136 | 137 | if (plug != outputAttr && plug.parent() != outputAttr) 138 | { 139 | return MStatus::kInvalidParameter; 140 | } 141 | 142 | short rotateOrderIdx = data.inputValue(inputRotateOrderAttr).asShort(); 143 | MEulerRotation::RotationOrder rotateOrder = (MEulerRotation::RotationOrder) rotateOrderIdx; 144 | 145 | MDataHandle inputMatrixHandle = data.inputValue(inputMatrixAttr); 146 | 147 | std::vector inputMatrix = getMayaArray(inputMatrixHandle); 148 | 149 | size_t numberOfOutputs = inputMatrix.size(); 150 | 151 | std::vector outputTranslate(numberOfOutputs); 152 | std::vector outputRotate(numberOfOutputs); 153 | std::vector outputQuat(numberOfOutputs); 154 | std::vector outputScale(numberOfOutputs); 155 | std::vector outputShear(numberOfOutputs); 156 | 157 | double values[3] {0.0, 0.0, 0.0}; 158 | 159 | for (size_t i = 0; i < numberOfOutputs; i++) 160 | { 161 | MTransformationMatrix matrix(inputMatrix[i]); 162 | 163 | outputTranslate[i] = matrix.getTranslation(MSpace::Space::kWorld); 164 | outputRotate[i] = MEulerRotation::decompose(inputMatrix[i], rotateOrder); 165 | outputQuat[i] = matrix.rotation(); 166 | 167 | matrix.getScale(values, MSpace::Space::kWorld); 168 | outputScale[i] = MVector(values); 169 | 170 | matrix.getShear(values, MSpace::Space::kWorld); 171 | outputShear[i] = MVector(values); 172 | } 173 | 174 | MDataHandle outputTranslateHandle = data.outputValue(outputTranslateAttr); 175 | MDataHandle outputRotateHandle = data.outputValue(outputRotateAttr); 176 | MDataHandle outputQuatHandle = data.outputValue(outputQuatAttr); 177 | MDataHandle outputScaleHandle = data.outputValue(outputScaleAttr); 178 | MDataHandle outputShearHandle = data.outputValue(outputShearAttr); 179 | 180 | setMayaArray(outputTranslateHandle, outputTranslate); 181 | setMayaArray(outputScaleHandle, outputScale); 182 | setMayaArray(outputShearHandle, outputShear); 183 | 184 | setUserArray(outputRotateHandle, outputRotate); 185 | setUserArray(outputQuatHandle, outputQuat); 186 | 187 | return MStatus::kSuccess; 188 | } -------------------------------------------------------------------------------- /src/nodes/matrixNodes/decomposeMatrixArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class DecomposeMatrixArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputMatrixAttr; 26 | static MObject inputRotateOrderAttr; 27 | 28 | static MObject outputAttr; 29 | static MObject outputTranslateAttr; 30 | static MObject outputRotateAttr; 31 | static MObject outputQuatAttr; 32 | static MObject outputScaleAttr; 33 | static MObject outputShearAttr; 34 | }; -------------------------------------------------------------------------------- /src/nodes/matrixNodes/matrixArrayOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | matrixArrayOp node 8 | This node computes the result of a matrix operation. 9 | 10 | inputMatrix1 (im1) matrixArray 11 | First array of matrices, used for all operations. 12 | 13 | inputMatrix2 (im2) matrixArray 14 | Second array of matrices, used for the "Multiply" operation. 15 | 16 | operation (op) enum 17 | Computation to be performed. If the computation is unary, only the 18 | values of inputMatrix1 are used. 19 | 20 | No Operation (0) outputs the input matrices. 21 | Multiply (1) outputs the product of the matrices. 22 | Invert (2) outputs the inverse of the matrices. 23 | Transpose (3) outputs the transposed matrices. 24 | As Translate (4) outputs the matrices as a position matrix. 25 | As Rotate (5) outputs the matrices as a rotation matrix. 26 | As Scale (6) outputs the matrices as a scale matrix. 27 | 28 | outputMatrix (om) matrixArray 29 | List of output matrices. 30 | 31 | */ 32 | 33 | #include "matrixArrayOpNode.h" 34 | #include "../nodeData.h" 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | 53 | MObject MatrixArrayOpNode::inputMatrix1Attr; 54 | MObject MatrixArrayOpNode::inputMatrix2Attr; 55 | MObject MatrixArrayOpNode::operationAttr; 56 | 57 | MObject MatrixArrayOpNode::outputMatrixAttr; 58 | 59 | 60 | const short NO_OPERATION = 0; 61 | const short MULTIPY = 1; 62 | const short INVERT = 2; 63 | const short TRANSPOSE = 3; 64 | const short AS_TRANSLATE = 4; 65 | const short AS_ROTATE = 5; 66 | const short AS_SCALE = 6; 67 | 68 | 69 | void* MatrixArrayOpNode::creator() 70 | { 71 | return new MatrixArrayOpNode(); 72 | } 73 | 74 | 75 | MStatus MatrixArrayOpNode::initialize() 76 | { 77 | MStatus status; 78 | 79 | MFnEnumAttribute E; 80 | MFnTypedAttribute T; 81 | 82 | inputMatrix1Attr = T.create("inputMatrix1", "im1", MFnData::kMatrixArray, MObject::kNullObj, &status); 83 | inputMatrix2Attr = T.create("inputMatrix2", "im2", MFnData::kMatrixArray, MObject::kNullObj, &status); 84 | 85 | operationAttr = E.create("operation", "op", 1, &status); 86 | E.setChannelBox(true); 87 | E.setKeyable(true); 88 | E.addField("No Operation", NO_OPERATION); 89 | E.addField("Multiply", MULTIPY); 90 | E.addField("Invert", INVERT); 91 | E.addField("Transpose", TRANSPOSE); 92 | E.addField("As Translate Matrix", AS_TRANSLATE); 93 | E.addField("As Rotate Matrix", AS_ROTATE); 94 | E.addField("As Scale Matrix", AS_SCALE); 95 | 96 | addAttribute(inputMatrix1Attr); 97 | addAttribute(inputMatrix2Attr); 98 | addAttribute(operationAttr); 99 | 100 | outputMatrixAttr = T.create("outputMatrix", "om", MFnData::kMatrixArray, MObject::kNullObj, &status); 101 | T.setStorable(false); 102 | 103 | addAttribute(outputMatrixAttr); 104 | 105 | attributeAffects(inputMatrix1Attr, outputMatrixAttr); 106 | attributeAffects(inputMatrix2Attr, outputMatrixAttr); 107 | attributeAffects(operationAttr, outputMatrixAttr); 108 | 109 | return MStatus::kSuccess; 110 | } 111 | 112 | 113 | MStatus MatrixArrayOpNode::compute(const MPlug& plug, MDataBlock& data) 114 | { 115 | MStatus status; 116 | 117 | if (plug != outputMatrixAttr) 118 | { 119 | return MStatus::kInvalidParameter; 120 | } 121 | 122 | short operation = data.inputValue(operationAttr).asShort(); 123 | 124 | MDataHandle inputMatrix1Handle = data.inputValue(inputMatrix1Attr); 125 | std::vector inputMatrix1 = getMayaArray(inputMatrix1Handle); 126 | 127 | unsigned numberOfInputs = (unsigned) inputMatrix1.size(); 128 | 129 | std::vector outputMatrix(numberOfInputs); 130 | 131 | if (operation == MULTIPY) 132 | { 133 | MDataHandle inputMatrix2Handle = data.inputValue(inputMatrix2Attr); 134 | std::vector inputMatrix2 = getMayaArray(inputMatrix2Handle); 135 | 136 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputMatrix2.size()); 137 | 138 | inputMatrix1.resize(numberOfInputs); 139 | inputMatrix2.resize(numberOfInputs); 140 | outputMatrix.resize(numberOfInputs); 141 | 142 | for (unsigned i = 0; i < numberOfInputs; i++) 143 | { 144 | outputMatrix[i] = inputMatrix1[i] * inputMatrix2[i]; 145 | } 146 | } else if (operation == INVERT) { 147 | for (unsigned i = 0; i < numberOfInputs; i++) 148 | { 149 | outputMatrix[i] = inputMatrix1[i].inverse(); 150 | } 151 | } else if (operation == TRANSPOSE) { 152 | for (unsigned i = 0; i < numberOfInputs; i++) 153 | { 154 | outputMatrix[i] = inputMatrix1[i].transpose(); 155 | } 156 | } else if (operation == AS_TRANSLATE) { 157 | MTransformationMatrix xformMatrix; 158 | 159 | for (unsigned i = 0; i < numberOfInputs; i++) 160 | { 161 | MMatrix &m = inputMatrix1[i]; 162 | MVector t(m(3, 0), m(3, 1), m(3, 2)); 163 | xformMatrix.setTranslation(t, MSpace::Space::kWorld); 164 | outputMatrix[i] = xformMatrix.asMatrix(); 165 | } 166 | } else if (operation == AS_ROTATE) { 167 | for (unsigned i = 0; i < numberOfInputs; i++) 168 | { 169 | MTransformationMatrix xformMatrix(inputMatrix1[i]); 170 | MMatrix rotateMatrix = xformMatrix.asRotateMatrix(); 171 | MMatrix scaleMatrix = xformMatrix.asScaleMatrix(); 172 | outputMatrix[i] = rotateMatrix * scaleMatrix.inverse(); 173 | } 174 | } else if (operation == AS_SCALE) { 175 | for (unsigned i = 0; i < numberOfInputs; i++) 176 | { 177 | MTransformationMatrix xformMatrix(inputMatrix1[i]); 178 | outputMatrix[i] = xformMatrix.asScaleMatrix(); 179 | } 180 | } else { 181 | std::copy( 182 | inputMatrix1.begin(), 183 | inputMatrix1.end(), 184 | outputMatrix.begin() 185 | ); 186 | } 187 | 188 | MDataHandle outputMatrixHandle = data.outputValue(outputMatrixAttr); 189 | setMayaArray(outputMatrixHandle, outputMatrix); 190 | 191 | return MStatus::kSuccess; 192 | } -------------------------------------------------------------------------------- /src/nodes/matrixNodes/matrixArrayOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class MatrixArrayOpNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputMatrix1Attr; 26 | static MObject inputMatrix2Attr; 27 | static MObject operationAttr; 28 | 29 | static MObject outputMatrixAttr; 30 | }; -------------------------------------------------------------------------------- /src/nodes/matrixNodes/packMatrixArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | packMatrixArray node 8 | This node outputs an array of 4x4 matrices based on the input values. 9 | 10 | inputMatrix (im) matrix[] 11 | List of 4x4 matrices. 12 | 13 | inputRows (ir) compound 14 | 15 | inputRow0 (ir0) vectorArray 16 | List of values describing the first row of a matrix. 17 | 18 | inputRow1 (ir1) vectorArray 19 | List of values describing the second row of a matrix. 20 | 21 | inputRow2 (ir2) vectorArray 22 | List of values describing the third row of a matrix. 23 | 24 | inputRow3 (ir3) vectorArray 25 | List of values describing the last row of a matrix. 26 | 27 | fillValue (fv) matrix 28 | Default value for the output array. 29 | 30 | size (s) int 31 | Size of the output array. If the output is larger than the input, 32 | missing values will be filled in with the fillValue. 33 | 34 | inputMethod (im) enum 35 | Specifies the source of the matrix components. 36 | 37 | Elements (0) uses the values in the "inputMatrix" list. 38 | Components (1) uses the rows in the "inputRow" arrays. 39 | 40 | outputMatrix (om) matrixArray 41 | Array of matrices. 42 | 43 | */ 44 | 45 | #include "packMatrixArrayNode.h" 46 | #include "../nodeData.h" 47 | 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | 73 | 74 | MObject PackMatrixArrayNode::inputMatrixAttr; 75 | MObject PackMatrixArrayNode::inputRow0Attr; 76 | MObject PackMatrixArrayNode::inputRow1Attr; 77 | MObject PackMatrixArrayNode::inputRow2Attr; 78 | MObject PackMatrixArrayNode::inputRow3Attr; 79 | MObject PackMatrixArrayNode::fillValueAttr; 80 | MObject PackMatrixArrayNode::inputMethodAttr; 81 | MObject PackMatrixArrayNode::sizeAttr; 82 | 83 | MObject PackMatrixArrayNode::outputMatrixAttr; 84 | 85 | 86 | void* PackMatrixArrayNode::creator() 87 | { 88 | return new PackMatrixArrayNode(); 89 | } 90 | 91 | 92 | MStatus PackMatrixArrayNode::initialize() 93 | { 94 | MStatus status; 95 | 96 | MFnEnumAttribute E; 97 | MFnMatrixAttribute M; 98 | MFnNumericAttribute N; 99 | MFnTypedAttribute T; 100 | 101 | inputMatrixAttr = T.create("inputMatrix", "im", MFnData::kMatrix, MObject::kNullObj, &status); 102 | T.setArray(true); 103 | 104 | inputRow0Attr = T.create("inputRow0", "ir0", MFnData::kVectorArray, MObject::kNullObj, &status); 105 | inputRow1Attr = T.create("inputRow1", "ir1", MFnData::kVectorArray, MObject::kNullObj, &status); 106 | inputRow2Attr = T.create("inputRow2", "ir2", MFnData::kVectorArray, MObject::kNullObj, &status); 107 | inputRow3Attr = T.create("inputRow3", "ir3", MFnData::kVectorArray, MObject::kNullObj, &status); 108 | 109 | fillValueAttr = M.create("fillValue", "fv", MFnMatrixAttribute::kDouble, &status); 110 | 111 | sizeAttr = N.create("size", "s", MFnNumericData::kInt, 8, &status); 112 | N.setMin(0); 113 | 114 | inputMethodAttr = E.create("inputMethod", "mtd", 0, &status); 115 | E.setChannelBox(true); 116 | E.setKeyable(true); 117 | E.addField("Elements", 0); 118 | E.addField("Components", 1); 119 | 120 | addAttribute(inputMatrixAttr); 121 | addAttribute(inputRow0Attr); 122 | addAttribute(inputRow1Attr); 123 | addAttribute(inputRow2Attr); 124 | addAttribute(inputRow3Attr); 125 | addAttribute(fillValueAttr); 126 | addAttribute(sizeAttr); 127 | addAttribute(inputMethodAttr); 128 | 129 | outputMatrixAttr = T.create("outputMatrix", "om", MFnData::kMatrixArray, MObject::kNullObj, &status); 130 | T.setStorable(false); 131 | 132 | addAttribute(outputMatrixAttr); 133 | 134 | attributeAffects(inputMatrixAttr, outputMatrixAttr); 135 | attributeAffects(inputRow0Attr, outputMatrixAttr); 136 | attributeAffects(inputRow1Attr, outputMatrixAttr); 137 | attributeAffects(inputRow2Attr, outputMatrixAttr); 138 | attributeAffects(inputRow3Attr, outputMatrixAttr); 139 | attributeAffects(fillValueAttr, outputMatrixAttr); 140 | attributeAffects(sizeAttr, outputMatrixAttr); 141 | attributeAffects(inputMethodAttr, outputMatrixAttr); 142 | 143 | return MStatus::kSuccess; 144 | } 145 | 146 | 147 | MStatus PackMatrixArrayNode::compute(const MPlug& plug, MDataBlock& data) 148 | { 149 | MStatus status; 150 | 151 | if (plug != outputMatrixAttr) 152 | { 153 | return MStatus::kInvalidParameter; 154 | } 155 | 156 | MFnMatrixData fnMatrixData; 157 | 158 | MMatrix fillValue = data.inputValue(fillValueAttr).asMatrix(); 159 | short inputMethod = data.inputValue(inputMethodAttr).asShort(); 160 | unsigned size = (unsigned) data.inputValue(sizeAttr).asInt(); 161 | 162 | std::vector outputMatrix; 163 | 164 | if (inputMethod == 0) 165 | { 166 | MArrayDataHandle inputMatrixArrayHandle = data.inputArrayValue(inputMatrixAttr); 167 | 168 | outputMatrix = getArrayElements( 169 | inputMatrixArrayHandle, 170 | &PackMatrixArrayNode::getElement, 171 | size, 172 | fillValue 173 | ); 174 | } else { 175 | MDataHandle inputRow0Handle = data.inputValue(inputRow0Attr); 176 | MDataHandle inputRow1Handle = data.inputValue(inputRow1Attr); 177 | MDataHandle inputRow2Handle = data.inputValue(inputRow2Attr); 178 | MDataHandle inputRow3Handle = data.inputValue(inputRow3Attr); 179 | 180 | std::vector inputRow0 = getMayaArray(inputRow0Handle); 181 | std::vector inputRow1 = getMayaArray(inputRow1Handle); 182 | std::vector inputRow2 = getMayaArray(inputRow2Handle); 183 | std::vector inputRow3 = getMayaArray(inputRow3Handle); 184 | 185 | unsigned numberOfInputs = 0; 186 | 187 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRow0.size()); 188 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRow1.size()); 189 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRow2.size()); 190 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputRow3.size()); 191 | 192 | inputRow0.resize(numberOfInputs, MVector::xAxis); 193 | inputRow1.resize(numberOfInputs, MVector::yAxis); 194 | inputRow2.resize(numberOfInputs, MVector::zAxis); 195 | inputRow3.resize(numberOfInputs, MVector::zero); 196 | outputMatrix.resize(size, fillValue); 197 | 198 | double m[4][4] = { 199 | {1.0, 0.0, 0.0, 0.0}, 200 | {0.0, 1.0, 0.0, 0.0}, 201 | {0.0, 0.0, 1.0, 0.0}, 202 | {1.0, 0.0, 0.0, 1.0} 203 | }; 204 | 205 | unsigned numberOfOutputs = std::min(size, numberOfInputs); 206 | 207 | for (unsigned i = 0; i < numberOfOutputs; i++) 208 | { 209 | MVector &row0 = inputRow0[i]; 210 | MVector &row1 = inputRow1[i]; 211 | MVector &row2 = inputRow2[i]; 212 | MVector &row3 = inputRow3[i]; 213 | 214 | m[0][0] = row0.x; m[0][1] = row0.y; m[0][2] = row0.z; 215 | m[1][0] = row1.x; m[1][1] = row1.y; m[1][2] = row1.z; 216 | m[2][0] = row2.x; m[2][1] = row2.y; m[2][2] = row2.z; 217 | m[3][0] = row3.x; m[3][1] = row3.y; m[3][2] = row3.z; 218 | 219 | outputMatrix[i] = MMatrix(m); 220 | } 221 | } 222 | 223 | MDataHandle outputMatrixHandle = data.outputValue(outputMatrixAttr); 224 | setMayaArray(outputMatrixHandle, outputMatrix); 225 | 226 | return MStatus::kSuccess; 227 | } 228 | 229 | MMatrix PackMatrixArrayNode::getElement(MDataHandle &elementHandle) 230 | { 231 | MObject data = elementHandle.data(); 232 | MFnMatrixData fnData(data); 233 | 234 | return fnData.matrix(); 235 | } -------------------------------------------------------------------------------- /src/nodes/matrixNodes/packMatrixArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class PackMatrixArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | static MMatrix getElement(MDataHandle &elementHandle); 22 | 23 | public: 24 | static MTypeId NODE_ID; 25 | static MString NODE_NAME; 26 | 27 | static MObject inputMatrixAttr; 28 | static MObject inputRow0Attr; 29 | static MObject inputRow1Attr; 30 | static MObject inputRow2Attr; 31 | static MObject inputRow3Attr; 32 | static MObject fillValueAttr; 33 | static MObject sizeAttr; 34 | static MObject inputMethodAttr; 35 | 36 | static MObject outputMatrixAttr; 37 | }; -------------------------------------------------------------------------------- /src/nodes/matrixNodes/unpackMatrixArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | unpackMatrixArray node 8 | This node outputs the rows of 4x4 matrices. 9 | 10 | inputMatrix (im) matrixArray 11 | Array of matrices to be unpacked. 12 | 13 | outputMatrix (om) matrix[] 14 | List of unpacked matrices. 15 | 16 | outputRows (or) compound 17 | 18 | outputRow0 (or0) vectorArray 19 | List of the first row of the unpacked matrices. 20 | 21 | outputRow1 (or1) vectorArray 22 | List of the second row of the unpacked matrices. 23 | 24 | outputRow2 (or2) vectorArray 25 | List of the third row of the unpacked matrices. 26 | 27 | outputRow3 (or3) vectorArray 28 | List of the fourth row of the unpacked matrices. 29 | 30 | */ 31 | 32 | #include 33 | 34 | #include "../nodeData.h" 35 | #include "unpackMatrixArrayNode.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | 57 | MObject UnpackMatrixArrayNode::inputMatrixAttr; 58 | 59 | MObject UnpackMatrixArrayNode::outputMatrixAttr; 60 | MObject UnpackMatrixArrayNode::outputRow0Attr; 61 | MObject UnpackMatrixArrayNode::outputRow1Attr; 62 | MObject UnpackMatrixArrayNode::outputRow2Attr; 63 | MObject UnpackMatrixArrayNode::outputRow3Attr; 64 | 65 | 66 | void* UnpackMatrixArrayNode::creator() 67 | { 68 | return new UnpackMatrixArrayNode(); 69 | } 70 | 71 | 72 | MStatus UnpackMatrixArrayNode::initialize() 73 | { 74 | MStatus status; 75 | 76 | MFnCompoundAttribute C; 77 | MFnTypedAttribute T; 78 | 79 | inputMatrixAttr = T.create("inputMatrix", "im", MFnData::kMatrixArray, MObject::kNullObj, &status); 80 | 81 | addAttribute(inputMatrixAttr); 82 | 83 | outputMatrixAttr = T.create("outputMatrix", "om", MFnData::kMatrix, MObject::kNullObj, &status); 84 | T.setArray(true); 85 | T.setStorable(false); 86 | T.setUsesArrayDataBuilder(true); 87 | 88 | outputRow0Attr = T.create("outputRow0", "or0", MFnData::kVectorArray, MObject::kNullObj, &status); 89 | T.setStorable(false); 90 | 91 | outputRow1Attr = T.create("outputRow1", "or1", MFnData::kVectorArray, MObject::kNullObj, &status); 92 | T.setStorable(false); 93 | 94 | outputRow2Attr = T.create("outputRow2", "or2", MFnData::kVectorArray, MObject::kNullObj, &status); 95 | T.setStorable(false); 96 | 97 | outputRow3Attr = T.create("outputRow3", "or3", MFnData::kVectorArray, MObject::kNullObj, &status); 98 | T.setStorable(false); 99 | 100 | addAttribute(outputMatrixAttr); 101 | addAttribute(outputMatrixAttr); 102 | addAttribute(outputRow0Attr); 103 | addAttribute(outputRow1Attr); 104 | addAttribute(outputRow2Attr); 105 | addAttribute(outputRow3Attr); 106 | 107 | attributeAffects(inputMatrixAttr, outputMatrixAttr); 108 | attributeAffects(inputMatrixAttr, outputRow0Attr); 109 | attributeAffects(inputMatrixAttr, outputRow1Attr); 110 | attributeAffects(inputMatrixAttr, outputRow2Attr); 111 | attributeAffects(inputMatrixAttr, outputRow3Attr); 112 | 113 | return MStatus::kSuccess; 114 | } 115 | 116 | 117 | MStatus UnpackMatrixArrayNode::compute(const MPlug& plug, MDataBlock& data) 118 | { 119 | MStatus status; 120 | 121 | if ( 122 | plug != outputMatrixAttr && 123 | plug.parent() != outputMatrixAttr && 124 | plug != outputRow0Attr && 125 | plug != outputRow1Attr && 126 | plug != outputRow2Attr && 127 | plug != outputRow3Attr 128 | ) { 129 | return MStatus::kInvalidParameter; 130 | } 131 | 132 | MDataHandle inputMatrixHandle = data.inputValue(inputMatrixAttr); 133 | std::vector inputMatrix = getMayaArray(inputMatrixHandle); 134 | 135 | unsigned numberOfValues = (unsigned) inputMatrix.size(); 136 | 137 | MArrayDataHandle outputArrayHandle = data.outputArrayValue(outputMatrixAttr); 138 | 139 | setArrayElements( 140 | outputArrayHandle, 141 | inputMatrix, 142 | &UnpackMatrixArrayNode::setElement 143 | ); 144 | 145 | std::vector row0(numberOfValues); 146 | std::vector row1(numberOfValues); 147 | std::vector row2(numberOfValues); 148 | std::vector row3(numberOfValues); 149 | 150 | for (unsigned i = 0; i < numberOfValues; i++) 151 | { 152 | MMatrix &m = inputMatrix[i]; 153 | 154 | row0[i] = MVector(m(0, 0), m(0, 1), m(0, 2)); 155 | row1[i] = MVector(m(1, 0), m(1, 1), m(1, 2)); 156 | row2[i] = MVector(m(2, 0), m(2, 1), m(2, 2)); 157 | row3[i] = MVector(m(3, 0), m(3, 1), m(3, 2)); 158 | } 159 | 160 | MDataHandle outputRow0Handle = data.outputValue(outputRow0Attr); 161 | MDataHandle outputRow1Handle = data.outputValue(outputRow1Attr); 162 | MDataHandle outputRow2Handle = data.outputValue(outputRow2Attr); 163 | MDataHandle outputRow3Handle = data.outputValue(outputRow3Attr); 164 | 165 | setMayaArray(outputRow0Handle, row0); 166 | setMayaArray(outputRow1Handle, row1); 167 | setMayaArray(outputRow2Handle, row2); 168 | setMayaArray(outputRow3Handle, row3); 169 | 170 | return MStatus::kSuccess; 171 | } 172 | 173 | 174 | MStatus UnpackMatrixArrayNode::setElement(MDataHandle &elementHandle, MMatrix value) 175 | { 176 | MStatus status; 177 | 178 | MFnMatrixData fnData; 179 | MObject data = fnData.create(value, &status); 180 | CHECK_MSTATUS_AND_RETURN_IT(status); 181 | 182 | status = elementHandle.setMObject(data); 183 | CHECK_MSTATUS_AND_RETURN_IT(status); 184 | 185 | return MStatus::kSuccess; 186 | } -------------------------------------------------------------------------------- /src/nodes/matrixNodes/unpackMatrixArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class UnpackMatrixArrayNode : public MPxNode 17 | { 18 | public: 19 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 20 | static void* creator(); 21 | static MStatus initialize(); 22 | 23 | static MStatus setElement(MDataHandle &elementHandle, MMatrix value); 24 | 25 | public: 26 | static MTypeId NODE_ID; 27 | static MString NODE_NAME; 28 | 29 | static MObject inputMatrixAttr; 30 | 31 | static MObject outputMatrixAttr; 32 | static MObject outputRow0Attr; 33 | static MObject outputRow1Attr; 34 | static MObject outputRow2Attr; 35 | static MObject outputRow3Attr; 36 | }; -------------------------------------------------------------------------------- /src/nodes/nodeData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../data/angleArrayData.h" 7 | #include "../data/eulerArrayData.h" 8 | #include "../data/quatArrayData.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | template 35 | std::vector getMayaArray(MDataHandle &arrayHandle) 36 | { 37 | std::vector result; 38 | 39 | MObject dataObj = arrayHandle.data(); 40 | 41 | if (!dataObj.isNull()) 42 | { 43 | FN arrayData(dataObj); 44 | result.resize(arrayData.length()); 45 | 46 | for (unsigned i = 0; i < arrayData.length(); i++) 47 | { 48 | result[i] = T(arrayData[i]); 49 | } 50 | } 51 | 52 | return result; 53 | } 54 | 55 | template std::vector getMayaArray (MDataHandle &arrayHandle); 56 | template std::vector getMayaArray (MDataHandle &arrayHandle); 57 | template std::vector getMayaArray (MDataHandle &arrayHandle); 58 | template std::vector getMayaArray (MDataHandle &arrayHandle); 59 | 60 | template 61 | MStatus setMayaArray(MDataHandle &arrayHandle, std::vector &values) 62 | { 63 | MStatus status; 64 | 65 | unsigned numberOfValues = (unsigned) values.size(); 66 | MA output(numberOfValues); 67 | 68 | for (unsigned i = 0; i < numberOfValues; i++) 69 | { 70 | output[i] = values[i]; 71 | } 72 | 73 | FN fnData; 74 | MObject dataObj = fnData.create(output, &status); 75 | CHECK_MSTATUS_AND_RETURN_IT(status); 76 | 77 | status = arrayHandle.setMObject(dataObj); 78 | CHECK_MSTATUS_AND_RETURN_IT(status); 79 | 80 | arrayHandle.setClean(); 81 | 82 | return MStatus::kSuccess; 83 | } 84 | 85 | template MStatus setMayaArray(MDataHandle &arrayHandle, std::vector &values); 86 | template MStatus setMayaArray(MDataHandle &arrayHandle, std::vector &values); 87 | template MStatus setMayaArray(MDataHandle &arrayHandle, std::vector &values); 88 | template MStatus setMayaArray(MDataHandle &arrayHandle, std::vector &values); 89 | 90 | template 91 | std::vector getUserArray(MDataHandle& arrayHandle) 92 | { 93 | std::vector result; 94 | 95 | MObject dataObj = arrayHandle.data(); 96 | 97 | if (!dataObj.isNull()) 98 | { 99 | MFnPluginData fnData(dataObj); 100 | DATA* userData = (DATA*) fnData.data(); 101 | result = userData->getArray(); 102 | } 103 | 104 | return result; 105 | } 106 | 107 | template std::vector getUserArray(MDataHandle& arrayHandle); 108 | template std::vector getUserArray(MDataHandle& arrayHandle); 109 | template std::vector getUserArray(MDataHandle& arrayHandle); 110 | 111 | template 112 | MStatus setUserArray(MDataHandle& arrayHandle, std::vector &data) 113 | { 114 | MStatus status; 115 | 116 | MFnPluginData fnData; 117 | MObject dataObj = fnData.create(DATA::TYPE_ID, &status); 118 | 119 | DATA* userData = (DATA*) fnData.data(&status); 120 | userData->setArray(data); 121 | 122 | status = arrayHandle.setMPxData(userData); 123 | CHECK_MSTATUS_AND_RETURN_IT(status); 124 | 125 | arrayHandle.setClean(); 126 | 127 | return status; 128 | } 129 | 130 | template MStatus setUserArray(MDataHandle& arrayHandle, std::vector &data); 131 | template MStatus setUserArray(MDataHandle& arrayHandle, std::vector &data); 132 | template MStatus setUserArray (MDataHandle& arrayHandle, std::vector &data); 133 | 134 | template 135 | std::vector getArrayElements(MArrayDataHandle& arrayHandle, T (*getElement)(MDataHandle&), unsigned size, T fillValue) 136 | { 137 | std::vector result(size, fillValue); 138 | 139 | unsigned numberOfInputs = (unsigned) arrayHandle.elementCount(); 140 | 141 | std::vector values(numberOfInputs); 142 | std::vector indices(numberOfInputs); 143 | 144 | for (unsigned i = 0; i < numberOfInputs; i++) 145 | { 146 | MDataHandle elementHandle = arrayHandle.inputValue(); 147 | 148 | values[i] = getElement(elementHandle); 149 | indices[i] = arrayHandle.elementIndex(); 150 | 151 | arrayHandle.next(); 152 | } 153 | 154 | for (unsigned i = 0; i < numberOfInputs; i++) 155 | { 156 | if (indices[i] < size) 157 | { 158 | result[indices[i]] = values[i]; 159 | } 160 | } 161 | 162 | return result; 163 | } 164 | 165 | template std::vector getArrayElements(MArrayDataHandle& arrayHandle, MAngle (*getElement)(MDataHandle&), unsigned size, MAngle fillValue); 166 | template std::vector getArrayElements(MArrayDataHandle& arrayHandle, MEulerRotation (*getElement)(MDataHandle&), unsigned size, MEulerRotation fillValue); 167 | template std::vector getArrayElements(MArrayDataHandle& arrayHandle, MMatrix (*getElement)(MDataHandle&), unsigned size, MMatrix fillValue); 168 | template std::vector getArrayElements(MArrayDataHandle& arrayHandle, MQuaternion (*getElement)(MDataHandle&), unsigned size, MQuaternion fillValue); 169 | template std::vector getArrayElements(MArrayDataHandle& arrayHandle, MVector (*getElement)(MDataHandle&), unsigned size, MVector fillValue); 170 | 171 | template 172 | MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values, MStatus (*setElement)(MDataHandle&, T)) 173 | { 174 | MStatus status; 175 | MArrayDataBuilder outputArray = arrayHandle.builder(&status); 176 | CHECK_MSTATUS_AND_RETURN_IT(status); 177 | 178 | unsigned numberOfValues = (unsigned) values.size(); 179 | 180 | for (unsigned i = 0; i < numberOfValues; i++) 181 | { 182 | MDataHandle outputHandle = outputArray.addElement(i, &status); 183 | CHECK_MSTATUS_AND_RETURN_IT(status); 184 | 185 | status = setElement(outputHandle, values[i]); 186 | CHECK_MSTATUS_AND_RETURN_IT(status); 187 | } 188 | 189 | status = arrayHandle.set(outputArray); 190 | CHECK_MSTATUS_AND_RETURN_IT(status); 191 | 192 | status = arrayHandle.setAllClean(); 193 | CHECK_MSTATUS_AND_RETURN_IT(status); 194 | 195 | return status; 196 | } 197 | 198 | template MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values, MStatus (*setElement)(MDataHandle&, MAngle)); 199 | template MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values, MStatus (*setElement)(MDataHandle&, MEulerRotation)); 200 | template MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values , MStatus (*setElement)(MDataHandle&, MMatrix)); 201 | template MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values, MStatus (*setElement)(MDataHandle&, MQuaternion)); 202 | template MStatus setArrayElements(MArrayDataHandle& arrayHandle, std::vector &values, MStatus (*setElement)(MDataHandle&, MVector)); 203 | -------------------------------------------------------------------------------- /src/nodes/quatNodes/eulerToQuatArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | eulerToQuatArray node 8 | This node converts euler rotations to quaternion rotations. 9 | 10 | inputRotate (ir) eulerArray 11 | Array of euler rotations. 12 | 13 | inputRotateOrder (iro) enum 14 | Rotation order of the euler rotations. 15 | 16 | outputQuat (oq) quatArray 17 | Array of quaternion rotations. 18 | 19 | */ 20 | 21 | #include "../../data/eulerArrayData.h" 22 | #include "../../data/quatArrayData.h" 23 | #include "../nodeData.h" 24 | #include "eulerToQuatArrayNode.h" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | MObject EulerToQuatArrayNode::inputRotateAttr; 41 | MObject EulerToQuatArrayNode::inputRotateOrderAttr; 42 | 43 | MObject EulerToQuatArrayNode::outputQuatAttr; 44 | 45 | 46 | void* EulerToQuatArrayNode::creator() 47 | { 48 | return new EulerToQuatArrayNode(); 49 | } 50 | 51 | 52 | MStatus EulerToQuatArrayNode::initialize() 53 | { 54 | MStatus status; 55 | 56 | MFnEnumAttribute E; 57 | MFnTypedAttribute T; 58 | 59 | inputRotateAttr = T.create("inputRotate", "ir", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 60 | 61 | inputRotateOrderAttr = E.create("inputRotateOrder", "iro", 0, &status); 62 | E.setChannelBox(true); 63 | E.setKeyable(true); 64 | E.addField("xyz", 0); 65 | E.addField("yzx", 1); 66 | E.addField("zxy", 2); 67 | E.addField("xzy", 3); 68 | E.addField("yxz", 4); 69 | E.addField("zyx", 5); 70 | 71 | addAttribute(inputRotateAttr); 72 | addAttribute(inputRotateOrderAttr); 73 | 74 | outputQuatAttr = T.create("outputQuat", "oq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 75 | T.setStorable(false); 76 | 77 | addAttribute(outputQuatAttr); 78 | 79 | attributeAffects(inputRotateAttr, outputQuatAttr); 80 | attributeAffects(inputRotateOrderAttr, outputQuatAttr); 81 | 82 | return MStatus::kSuccess; 83 | } 84 | 85 | 86 | MStatus EulerToQuatArrayNode::compute(const MPlug& plug, MDataBlock& data) 87 | { 88 | MStatus status; 89 | 90 | if (plug != outputQuatAttr) 91 | { 92 | return MStatus::kInvalidParameter; 93 | } 94 | 95 | MDataHandle inputHandle = data.inputValue(inputRotateAttr); 96 | std::vector input = getUserArray(inputHandle); 97 | 98 | std::vector output(input.size()); 99 | 100 | for (size_t i = 0; i < input.size(); i++) 101 | { 102 | output[i] = input[i].asQuaternion(); 103 | } 104 | 105 | MDataHandle outputHandle = data.outputValue(outputQuatAttr); 106 | setUserArray(outputHandle, output); 107 | 108 | return MStatus::kSuccess; 109 | } -------------------------------------------------------------------------------- /src/nodes/quatNodes/eulerToQuatArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class EulerToQuatArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputRotateAttr; 26 | static MObject inputRotateOrderAttr; 27 | 28 | static MObject outputQuatAttr; 29 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/packQuatArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class PackQuatArrayNode : public MPxNode 19 | { 20 | public: 21 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 22 | static void* creator(); 23 | static MStatus initialize(); 24 | 25 | static MQuaternion getElement(MDataHandle &elementHandle); 26 | 27 | private: 28 | MStatus fromArrayElements(MDataBlock& data, size_t size, MQuaternion fillValue, std::vector &output); 29 | MStatus fromComponents(MDataBlock& data, size_t size, MQuaternion fillValue, std::vector &output); 30 | MStatus fromAxisAngle(MDataBlock& data, size_t size, MQuaternion fillValue, std::vector &output); 31 | MStatus fromVectors(MDataBlock& data, size_t size, MQuaternion fillValue, std::vector &output); 32 | 33 | public: 34 | static MTypeId NODE_ID; 35 | static MString NODE_NAME; 36 | 37 | static MObject inputQuatAttr; 38 | static MObject inputQuatXAttr; 39 | static MObject inputQuatYAttr; 40 | static MObject inputQuatZAttr; 41 | static MObject inputQuatWAttr; 42 | 43 | static MObject inputXAttr; 44 | static MObject inputYAttr; 45 | static MObject inputZAttr; 46 | static MObject inputWAttr; 47 | 48 | static MObject inputVector1Attr; 49 | static MObject inputVector2Attr; 50 | 51 | static MObject inputAxisAttr; 52 | static MObject inputAngleAttr; 53 | 54 | static MObject fillValueAttr; 55 | static MObject fillValueXAttr; 56 | static MObject fillValueYAttr; 57 | static MObject fillValueZAttr; 58 | static MObject fillValueWAttr; 59 | 60 | static MObject sizeAttr; 61 | static MObject inputMethodAttr; 62 | 63 | static MObject outputQuatAttr; 64 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatArrayBinaryOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | quatArrayBinaryOp node 8 | This node performs a binary operation on pairs of quaternions. 9 | 10 | inputQuat1 (iq1) quatArray 11 | First array of quaternions, used for all computations. 12 | 13 | inputQuat2 (iq1) quatArray 14 | Second array of quaternions, used for all computations. 15 | 16 | operation (op) enum 17 | Specifies the binary operation to be performed. 18 | 19 | No Operation (0) copies the values of "inputQuat" to "outputQuat". 20 | Add (2) calculates the sum of pairs of quaternions. 21 | Subtract (3) calculates the difference between pairs of quaternions. 22 | Product (4) calculates the product of pairs of quaternions. 23 | 24 | outputQuat (oq) quatArray 25 | Results of the binary operations. 26 | 27 | */ 28 | 29 | #include "../../data/quatArrayData.h" 30 | #include "../nodeData.h" 31 | #include "quatArrayBinaryOpNode.h" 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | const short ADD = 1; 45 | const short SUBTRACT = 2; 46 | const short PRODUCT = 3; 47 | 48 | MObject QuatArrayBinaryOpNode::inputQuat1Attr; 49 | MObject QuatArrayBinaryOpNode::inputQuat2Attr; 50 | MObject QuatArrayBinaryOpNode::operationAttr; 51 | 52 | MObject QuatArrayBinaryOpNode::outputQuatAttr; 53 | 54 | 55 | void* QuatArrayBinaryOpNode::creator() 56 | { 57 | return new QuatArrayBinaryOpNode(); 58 | } 59 | 60 | 61 | MStatus QuatArrayBinaryOpNode::initialize() 62 | { 63 | MStatus status; 64 | 65 | MFnEnumAttribute E; 66 | MFnTypedAttribute T; 67 | 68 | inputQuat1Attr = T.create("inputQuat1", "iq1", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 69 | inputQuat2Attr = T.create("inputQuat2", "iq1", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 70 | 71 | operationAttr = E.create("operation", "op", 1, &status); 72 | E.setChannelBox(true); 73 | E.setKeyable(true); 74 | E.addField("No Operation", 0); 75 | E.addField("Add", ADD); 76 | E.addField("Subtract", SUBTRACT); 77 | E.addField("Product", PRODUCT); 78 | 79 | addAttribute(inputQuat1Attr); 80 | addAttribute(inputQuat2Attr); 81 | addAttribute(operationAttr); 82 | 83 | outputQuatAttr = T.create("outputQuat", "oq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 84 | T.setStorable(false); 85 | 86 | addAttribute(outputQuatAttr); 87 | 88 | attributeAffects(inputQuat1Attr, outputQuatAttr); 89 | attributeAffects(inputQuat2Attr, outputQuatAttr); 90 | attributeAffects(operationAttr, outputQuatAttr); 91 | 92 | return MStatus::kSuccess; 93 | } 94 | 95 | 96 | MStatus QuatArrayBinaryOpNode::compute(const MPlug& plug, MDataBlock& data) 97 | { 98 | MStatus status; 99 | 100 | if (plug != outputQuatAttr) 101 | { 102 | return MStatus::kInvalidParameter; 103 | } 104 | 105 | MDataHandle input1Handle = data.inputValue(inputQuat1Attr); 106 | MDataHandle input2Handle = data.inputValue(inputQuat2Attr); 107 | short operation = data.inputValue(operationAttr).asShort(); 108 | 109 | std::vector input1 = getUserArray(input1Handle); 110 | std::vector input2 = getUserArray(input2Handle); 111 | 112 | size_t numberOfValues = std::max(input1.size(), input2.size()); 113 | 114 | input1.resize(numberOfValues); 115 | input2.resize(numberOfValues); 116 | 117 | std::vector output(numberOfValues); 118 | 119 | MQuaternion (*F)(MQuaternion, MQuaternion) = &QuatArrayBinaryOpNode::quatNop; 120 | 121 | switch (operation) 122 | { 123 | case ADD: F = &QuatArrayBinaryOpNode::quatAdd; break; 124 | case SUBTRACT: F = &QuatArrayBinaryOpNode::quatSub; break; 125 | case PRODUCT: F = &QuatArrayBinaryOpNode::quatProd; break; 126 | } 127 | 128 | for (size_t i = 0; i < numberOfValues; i++) 129 | { 130 | output[i] = F(input1[i], input2[i]); 131 | } 132 | 133 | MDataHandle outputHandle = data.outputValue(outputQuatAttr); 134 | setUserArray(outputHandle, output); 135 | 136 | return MStatus::kSuccess; 137 | } 138 | 139 | MQuaternion QuatArrayBinaryOpNode::quatAdd(MQuaternion q1, MQuaternion q2) { return q1 + q2; } 140 | MQuaternion QuatArrayBinaryOpNode::quatSub(MQuaternion q1, MQuaternion q2) { return q1 - q2; } 141 | MQuaternion QuatArrayBinaryOpNode::quatProd(MQuaternion q1, MQuaternion q2) { return q1 * q2; } 142 | MQuaternion QuatArrayBinaryOpNode::quatNop(MQuaternion q1, MQuaternion q2) { return MQuaternion(q1); } -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatArrayBinaryOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class QuatArrayBinaryOpNode : public MPxNode 16 | { 17 | public: 18 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 19 | static void* creator(); 20 | static MStatus initialize(); 21 | 22 | private: 23 | static inline MQuaternion quatNop(MQuaternion q1, MQuaternion q2); 24 | static inline MQuaternion quatAdd(MQuaternion q1, MQuaternion q2); 25 | static inline MQuaternion quatSub(MQuaternion q1, MQuaternion q2); 26 | static inline MQuaternion quatProd(MQuaternion q1, MQuaternion q2); 27 | 28 | public: 29 | static MTypeId NODE_ID; 30 | static MString NODE_NAME; 31 | 32 | static MObject inputQuat1Attr; 33 | static MObject inputQuat2Attr; 34 | static MObject operationAttr; 35 | 36 | static MObject outputQuatAttr; 37 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatArrayUnaryOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | quatArrayUnaryOp node 8 | This node performs unary operations on quaternions. 9 | 10 | inputQuat (iq) quatArray 11 | An array of quaternions. 12 | 13 | operation (op) enum 14 | Specifies the unary operation to be performed. 15 | 16 | No Operation (0) copies the values of "inputQuat" to "outputQuat". 17 | Conjugate (1) calculates the conjugate of each input. 18 | Inverse (2) calculates the inverse of each input. 19 | Negate (3) calculates the negative of each input. 20 | Normalize (4) calculates the normal of each input. 21 | 22 | outputQuat (oq) 23 | Results of the unary operations. 24 | 25 | */ 26 | 27 | #include "../../data/quatArrayData.h" 28 | #include "../nodeData.h" 29 | #include "quatArrayUnaryOpNode.h" 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | const short CONJUGATE = 1; 44 | const short INVERSE = 2; 45 | const short NEGATE = 3; 46 | const short NORMALIZE = 4; 47 | 48 | MObject QuatArrayUnaryOpNode::inputQuatAttr; 49 | MObject QuatArrayUnaryOpNode::operationAttr; 50 | 51 | MObject QuatArrayUnaryOpNode::outputQuatAttr; 52 | 53 | 54 | void* QuatArrayUnaryOpNode::creator() 55 | { 56 | return new QuatArrayUnaryOpNode(); 57 | } 58 | 59 | 60 | MStatus QuatArrayUnaryOpNode::initialize() 61 | { 62 | MStatus status; 63 | 64 | MFnEnumAttribute E; 65 | MFnTypedAttribute T; 66 | 67 | inputQuatAttr = T.create("inputQuat", "iq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 68 | 69 | operationAttr = E.create("operation", "op", NORMALIZE, &status); 70 | E.setChannelBox(true); 71 | E.setKeyable(true); 72 | E.addField("No Operation", 0); 73 | E.addField("Conjugate", CONJUGATE); 74 | E.addField("Inverse", INVERSE); 75 | E.addField("Negate", NEGATE); 76 | E.addField("Normalize", NORMALIZE); 77 | 78 | addAttribute(inputQuatAttr); 79 | addAttribute(operationAttr); 80 | 81 | outputQuatAttr = T.create("outputQuat", "oq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 82 | T.setStorable(false); 83 | 84 | addAttribute(outputQuatAttr); 85 | 86 | attributeAffects(inputQuatAttr, outputQuatAttr); 87 | attributeAffects(operationAttr, outputQuatAttr); 88 | 89 | return MStatus::kSuccess; 90 | } 91 | 92 | 93 | MStatus QuatArrayUnaryOpNode::compute(const MPlug& plug, MDataBlock& data) 94 | { 95 | MStatus status; 96 | 97 | if (plug != outputQuatAttr) 98 | { 99 | return MStatus::kInvalidParameter; 100 | } 101 | 102 | MDataHandle inputHandle = data.inputValue(inputQuatAttr); 103 | short operation = data.inputValue(operationAttr).asShort(); 104 | 105 | std::vector values = getUserArray(inputHandle); 106 | 107 | void (*F)(MQuaternion&) = &QuatArrayUnaryOpNode::quatNop; 108 | 109 | switch (operation) 110 | { 111 | case CONJUGATE: F = &QuatArrayUnaryOpNode::quatConjugate; break; 112 | case INVERSE: F = &QuatArrayUnaryOpNode::quatInverse; break; 113 | case NEGATE: F = &QuatArrayUnaryOpNode::quatNegate; break; 114 | case NORMALIZE: F = &QuatArrayUnaryOpNode::quatNormalize; break; 115 | } 116 | 117 | for (size_t i = 0; i < values.size(); i++) 118 | { 119 | F(values[i]); 120 | } 121 | 122 | MDataHandle outputHandle = data.outputValue(outputQuatAttr); 123 | setUserArray(outputHandle, values); 124 | 125 | return MStatus::kSuccess; 126 | } 127 | 128 | void QuatArrayUnaryOpNode::quatNop(MQuaternion &q) {} 129 | void QuatArrayUnaryOpNode::quatConjugate(MQuaternion &q) {q.conjugateIt(); } 130 | void QuatArrayUnaryOpNode::quatInverse(MQuaternion &q) {q.invertIt(); } 131 | void QuatArrayUnaryOpNode::quatNegate(MQuaternion &q) {q.negateIt(); } 132 | void QuatArrayUnaryOpNode::quatNormalize(MQuaternion &q) {q.normalizeIt(); } -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatArrayUnaryOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class QuatArrayUnaryOpNode : public MPxNode 16 | { 17 | public: 18 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 19 | static void* creator(); 20 | static MStatus initialize(); 21 | 22 | private: 23 | static inline void quatNop(MQuaternion &q); 24 | static inline void quatConjugate(MQuaternion &q); 25 | static inline void quatInverse(MQuaternion &q); 26 | static inline void quatNegate(MQuaternion &q); 27 | static inline void quatNormalize(MQuaternion &q); 28 | 29 | public: 30 | static MTypeId NODE_ID; 31 | static MString NODE_NAME; 32 | 33 | static MObject inputQuatAttr; 34 | static MObject operationAttr; 35 | 36 | static MObject outputQuatAttr; 37 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatToEulerArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | quatToEulerArray node 8 | This node converts quaternion rotations to euler rotations. 9 | 10 | inputQuat (iq) quatArray 11 | Array of quaternion rotations. 12 | 13 | inputRotateOrder (iro) enum 14 | Rotation order of the euler rotations. 15 | 16 | outputRotate (or) eulerArray 17 | Array of euler rotations. 18 | 19 | */ 20 | 21 | #include "../../data/eulerArrayData.h" 22 | #include "../../data/quatArrayData.h" 23 | #include "../nodeData.h" 24 | #include "quatToEulerArrayNode.h" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | MObject QuatToEulerArrayNode::inputQuatAttr; 38 | MObject QuatToEulerArrayNode::inputRotateOrderAttr; 39 | 40 | MObject QuatToEulerArrayNode::outputRotateAttr; 41 | 42 | 43 | void* QuatToEulerArrayNode::creator() 44 | { 45 | return new QuatToEulerArrayNode(); 46 | } 47 | 48 | 49 | MStatus QuatToEulerArrayNode::initialize() 50 | { 51 | MStatus status; 52 | 53 | MFnEnumAttribute E; 54 | MFnTypedAttribute T; 55 | 56 | inputQuatAttr = T.create("inputQuat", "iq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 57 | 58 | inputRotateOrderAttr = E.create("inputRotateOrder", "iro", 0, &status); 59 | E.setChannelBox(true); 60 | E.setKeyable(true); 61 | E.addField("xyz", 0); 62 | E.addField("yzx", 1); 63 | E.addField("zxy", 2); 64 | E.addField("xzy", 3); 65 | E.addField("yxz", 4); 66 | E.addField("zyx", 5); 67 | 68 | addAttribute(inputQuatAttr); 69 | addAttribute(inputRotateOrderAttr); 70 | 71 | outputRotateAttr = T.create("outputRotate", "or", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 72 | T.setStorable(false); 73 | 74 | addAttribute(outputRotateAttr); 75 | 76 | attributeAffects(inputQuatAttr, outputRotateAttr); 77 | attributeAffects(inputRotateOrderAttr, outputRotateAttr); 78 | 79 | return MStatus::kSuccess; 80 | } 81 | 82 | 83 | MStatus QuatToEulerArrayNode::compute(const MPlug& plug, MDataBlock& data) 84 | { 85 | MStatus status; 86 | 87 | if (plug != outputRotateAttr) 88 | { 89 | return MStatus::kInvalidParameter; 90 | } 91 | 92 | MDataHandle inputHandle = data.inputValue(inputQuatAttr); 93 | std::vector input = getUserArray(inputHandle); 94 | 95 | short rotateOrderIndex = data.inputValue(inputRotateOrderAttr).asShort(); 96 | MEulerRotation::RotationOrder rotateOrder = (MEulerRotation::RotationOrder) rotateOrderIndex; 97 | 98 | std::vector output(input.size()); 99 | 100 | for (size_t i = 0; i < input.size(); i++) 101 | { 102 | output[i] = input[i].asEulerRotation(); 103 | output[i].reorderIt(rotateOrder); 104 | } 105 | 106 | MDataHandle outputHandle = data.outputValue(outputRotateAttr); 107 | setUserArray(outputHandle, output); 108 | 109 | return MStatus::kSuccess; 110 | } -------------------------------------------------------------------------------- /src/nodes/quatNodes/quatToEulerArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class QuatToEulerArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputQuatAttr; 26 | static MObject inputRotateOrderAttr; 27 | 28 | static MObject outputRotateAttr; 29 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/slerpQuatArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | slerpQuatArray node 8 | This node computes the slerp (Spherical linear interpolation) of pairs of quaternions. 9 | 10 | inputQuat1 (iq1) quatArray 11 | Array of quaternions to rotate from. 12 | 13 | inputQuat2 (iq1) quatArray 14 | Array of quaternions to rotate to. 15 | 16 | tween (t) double 17 | Interpolation values. 18 | 19 | spin (s) int 20 | Number of complete revolutions around the axis. 21 | 22 | outputQuat (oq) quatArray 23 | Array of iterpolated quaternions. 24 | 25 | */ 26 | 27 | #include "../../data/quatArrayData.h" 28 | #include "../nodeData.h" 29 | #include "slerpQuatArrayNode.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | 44 | MObject SlerpQuatArrayNode::inputQuat1Attr; 45 | MObject SlerpQuatArrayNode::inputQuat2Attr; 46 | MObject SlerpQuatArrayNode::tweenAttr; 47 | MObject SlerpQuatArrayNode::spinAttr; 48 | 49 | MObject SlerpQuatArrayNode::outputQuatAttr; 50 | 51 | 52 | void* SlerpQuatArrayNode::creator() 53 | { 54 | return new SlerpQuatArrayNode(); 55 | } 56 | 57 | 58 | MStatus SlerpQuatArrayNode::initialize() 59 | { 60 | MStatus status; 61 | 62 | MFnNumericAttribute N; 63 | MFnTypedAttribute T; 64 | 65 | inputQuat1Attr = T.create("inputQuat1", "iq1", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 66 | inputQuat2Attr = T.create("inputQuat2", "iq1", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 67 | 68 | tweenAttr = N.create("tween", "t", MFnNumericData::kDouble, 0.5, &status); 69 | N.setMin(0.0); 70 | N.setMax(1.0); 71 | 72 | spinAttr = N.create("spin", "s", MFnNumericData::kInt, 1, &status); 73 | N.setMin(-1); 74 | 75 | addAttribute(inputQuat1Attr); 76 | addAttribute(inputQuat2Attr); 77 | addAttribute(tweenAttr); 78 | addAttribute(spinAttr); 79 | 80 | outputQuatAttr = T.create("outputQuat", "oq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 81 | T.setStorable(false); 82 | 83 | addAttribute(outputQuatAttr); 84 | 85 | attributeAffects(inputQuat1Attr, outputQuatAttr); 86 | attributeAffects(inputQuat2Attr, outputQuatAttr); 87 | attributeAffects(tweenAttr, outputQuatAttr); 88 | attributeAffects(spinAttr, outputQuatAttr); 89 | 90 | return MStatus::kSuccess; 91 | } 92 | 93 | 94 | MStatus SlerpQuatArrayNode::compute(const MPlug& plug, MDataBlock& data) 95 | { 96 | MStatus status; 97 | 98 | if (plug != outputQuatAttr) 99 | { 100 | return MStatus::kInvalidParameter; 101 | } 102 | 103 | MDataHandle input1Handle = data.inputValue(inputQuat1Attr); 104 | MDataHandle input2Handle = data.inputValue(inputQuat2Attr); 105 | 106 | double tween = data.inputValue(tweenAttr).asDouble(); 107 | short spin = (short) data.inputValue(spinAttr).asInt(); 108 | 109 | if (spin == 0) { spin = 1; } 110 | 111 | std::vector input1 = getUserArray(input1Handle); 112 | std::vector input2 = getUserArray(input2Handle); 113 | 114 | size_t numberOfValues = std::max(input1.size(), input2.size()); 115 | 116 | input1.resize(numberOfValues); 117 | input2.resize(numberOfValues); 118 | 119 | std::vector output(numberOfValues); 120 | 121 | for (size_t i = 0; i < numberOfValues; i++) 122 | { 123 | output[i] = slerp(input1[i], input2[i], tween, spin); 124 | } 125 | 126 | MDataHandle outputHandle = data.outputValue(outputQuatAttr); 127 | setUserArray(outputHandle, output); 128 | 129 | return MStatus::kSuccess; 130 | } -------------------------------------------------------------------------------- /src/nodes/quatNodes/slerpQuatArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class SlerpQuatArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputQuat1Attr; 26 | static MObject inputQuat2Attr; 27 | static MObject tweenAttr; 28 | static MObject spinAttr; 29 | 30 | static MObject outputQuatAttr; 31 | }; -------------------------------------------------------------------------------- /src/nodes/quatNodes/unpackQuatArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | unpackQuatArray node 8 | This node unpacks quaternion rotation components from an array. 9 | 10 | inputQuat (iq) quatArray 11 | Array of quaternion rotations to unpack. 12 | 13 | outputQuat (oq) compound[] 14 | Unpacked quaternion rotations. 15 | 16 | outputQuatX (oqx) double 17 | X component of a quaternion rotation. 18 | 19 | outputQuatY (oqy) double 20 | Y component of a quaternion rotation. 21 | 22 | outputQuatZ (oqz) double 23 | Z component of a quaternion rotation. 24 | 25 | outputQuatW (oqw) double 26 | W component of a quaternion rotation. 27 | 28 | outputX (ox) doubleArray 29 | X components of thequaternion rotations. 30 | 31 | outputY (oy) doubleArray 32 | Y components of the quaternion rotations. 33 | 34 | outputZ (oz) doubleArray 35 | Z components of the quaternion rotations. 36 | 37 | outputW (ow) doubleArray 38 | W components of the quaternion rotations. 39 | 40 | outputAxis (oax) vectorArray 41 | Pivot axes of the quaternion rotations. 42 | 43 | outputAngle (oa) angleArray 44 | Rotations about the pivot axes of the quaternion rotations. 45 | 46 | */ 47 | 48 | #include "unpackQuatArrayNode.h" 49 | #include "../nodeData.h" 50 | #include "../../data/angleArrayData.h" 51 | #include "../../data/quatArrayData.h" 52 | 53 | #include 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | 76 | MObject UnpackQuatArrayNode::inputQuatAttr; 77 | 78 | MObject UnpackQuatArrayNode::outputQuatAttr; 79 | MObject UnpackQuatArrayNode::outputQuatXAttr; 80 | MObject UnpackQuatArrayNode::outputQuatYAttr; 81 | MObject UnpackQuatArrayNode::outputQuatZAttr; 82 | MObject UnpackQuatArrayNode::outputQuatWAttr; 83 | MObject UnpackQuatArrayNode::outputXAttr; 84 | MObject UnpackQuatArrayNode::outputYAttr; 85 | MObject UnpackQuatArrayNode::outputZAttr; 86 | MObject UnpackQuatArrayNode::outputWAttr; 87 | MObject UnpackQuatArrayNode::outputAxisAttr; 88 | MObject UnpackQuatArrayNode::outputAngleAttr; 89 | 90 | 91 | void* UnpackQuatArrayNode::creator() 92 | { 93 | return new UnpackQuatArrayNode(); 94 | } 95 | 96 | 97 | MStatus UnpackQuatArrayNode::initialize() 98 | { 99 | MStatus status; 100 | 101 | MFnCompoundAttribute C; 102 | MFnNumericAttribute N; 103 | MFnTypedAttribute T; 104 | 105 | inputQuatAttr = T.create("inputQuat", "iq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 106 | 107 | addAttribute(inputQuatAttr); 108 | 109 | outputQuatXAttr = N.create("outputQuatX", "oqx", MFnNumericData::kDouble, 0, &status); 110 | outputQuatYAttr = N.create("outputQuatY", "oqy", MFnNumericData::kDouble, 0, &status); 111 | outputQuatZAttr = N.create("outputQuatZ", "oqz", MFnNumericData::kDouble, 0, &status); 112 | outputQuatWAttr = N.create("outputQuatW", "oqw", MFnNumericData::kDouble, 0, &status); 113 | outputQuatAttr = C.create("outputQuat", "oq", &status); 114 | C.setArray(true); 115 | C.setUsesArrayDataBuilder(true); 116 | C.addChild(outputQuatXAttr); 117 | C.addChild(outputQuatYAttr); 118 | C.addChild(outputQuatZAttr); 119 | C.addChild(outputQuatWAttr); 120 | 121 | outputXAttr = T.create("outputX", "ox", MFnData::kDoubleArray, MObject::kNullObj, &status); 122 | T.setStorable(false); 123 | outputYAttr = T.create("outputY", "oy", MFnData::kDoubleArray, MObject::kNullObj, &status); 124 | T.setStorable(false); 125 | outputZAttr = T.create("outputZ", "oz", MFnData::kDoubleArray, MObject::kNullObj, &status); 126 | T.setStorable(false); 127 | outputWAttr = T.create("outputW", "ow", MFnData::kDoubleArray, MObject::kNullObj, &status); 128 | T.setStorable(false); 129 | 130 | outputAxisAttr = T.create("outputAxis", "oax", MFnData::kVectorArray, MObject::kNullObj, &status); 131 | T.setStorable(false); 132 | outputAngleAttr = T.create("outputAngle", "oa", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 133 | T.setStorable(false); 134 | 135 | addAttribute(outputQuatAttr); 136 | addAttribute(outputXAttr); 137 | addAttribute(outputYAttr); 138 | addAttribute(outputZAttr); 139 | addAttribute(outputWAttr); 140 | addAttribute(outputAxisAttr); 141 | addAttribute(outputAngleAttr); 142 | 143 | attributeAffects(inputQuatAttr, outputQuatAttr); 144 | attributeAffects(inputQuatAttr, outputXAttr); 145 | attributeAffects(inputQuatAttr, outputYAttr); 146 | attributeAffects(inputQuatAttr, outputZAttr); 147 | attributeAffects(inputQuatAttr, outputWAttr); 148 | attributeAffects(inputQuatAttr, outputAxisAttr); 149 | attributeAffects(inputQuatAttr, outputAngleAttr); 150 | 151 | return MStatus::kSuccess; 152 | } 153 | 154 | 155 | MStatus UnpackQuatArrayNode::compute(const MPlug& plug, MDataBlock& data) 156 | { 157 | MStatus status; 158 | 159 | if ( 160 | plug != outputQuatAttr && 161 | plug.parent() != outputQuatAttr && 162 | plug != outputXAttr && 163 | plug != outputYAttr && 164 | plug != outputZAttr && 165 | plug != outputWAttr && 166 | plug != outputAxisAttr && 167 | plug != outputAngleAttr 168 | ) { 169 | return MStatus::kInvalidParameter; 170 | } 171 | 172 | MDataHandle inputHandle = data.inputValue(inputQuatAttr); 173 | 174 | std::vector input = getUserArray(inputHandle); 175 | 176 | size_t numberOfValues = input.size(); 177 | 178 | std::vector outputX(numberOfValues); 179 | std::vector outputY(numberOfValues); 180 | std::vector outputZ(numberOfValues); 181 | std::vector outputW(numberOfValues); 182 | 183 | std::vector outputAxis(numberOfValues); 184 | std::vector outputAngle(numberOfValues); 185 | 186 | double theta = 0.0; 187 | 188 | for (size_t i = 0; i < numberOfValues; i++) 189 | { 190 | MQuaternion &q = input[i]; 191 | 192 | q.getAxisAngle(outputAxis[i], theta); 193 | outputAngle[i] = MAngle(theta); 194 | 195 | outputX[i] = q.x; 196 | outputY[i] = q.y; 197 | outputZ[i] = q.z; 198 | outputW[i] = q.w; 199 | } 200 | 201 | MArrayDataHandle outputArrayHandle = data.outputArrayValue(outputQuatAttr); 202 | setArrayElements(outputArrayHandle, input, &UnpackQuatArrayNode::setElement); 203 | 204 | MDataHandle outputXHandle = data.outputValue(outputXAttr); 205 | MDataHandle outputYHandle = data.outputValue(outputYAttr); 206 | MDataHandle outputZHandle = data.outputValue(outputZAttr); 207 | MDataHandle outputWHandle = data.outputValue(outputWAttr); 208 | 209 | setMayaArray(outputXHandle, outputX); 210 | setMayaArray(outputYHandle, outputY); 211 | setMayaArray(outputZHandle, outputZ); 212 | setMayaArray(outputWHandle, outputW); 213 | 214 | MDataHandle outputAxisHandle = data.outputValue(outputAxisAttr); 215 | MDataHandle outputAngleHandle = data.outputValue(outputAngleAttr); 216 | 217 | setMayaArray(outputAxisHandle, outputAxis); 218 | setUserArray(outputAngleHandle, outputAngle); 219 | 220 | return MStatus::kSuccess; 221 | } 222 | 223 | MStatus UnpackQuatArrayNode::setElement(MDataHandle &elementHandle, MQuaternion q) 224 | { 225 | MDataHandle xHandle = elementHandle.child(outputQuatXAttr); 226 | MDataHandle yHandle = elementHandle.child(outputQuatYAttr); 227 | MDataHandle zHandle = elementHandle.child(outputQuatZAttr); 228 | MDataHandle wHandle = elementHandle.child(outputQuatWAttr); 229 | 230 | xHandle.setDouble(q.x); 231 | yHandle.setDouble(q.y); 232 | zHandle.setDouble(q.z); 233 | wHandle.setDouble(q.w); 234 | 235 | xHandle.setClean(); 236 | yHandle.setClean(); 237 | zHandle.setClean(); 238 | wHandle.setClean(); 239 | 240 | return MStatus::kSuccess; 241 | } -------------------------------------------------------------------------------- /src/nodes/quatNodes/unpackQuatArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class UnpackQuatArrayNode : public MPxNode 17 | { 18 | public: 19 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 20 | static void* creator(); 21 | static MStatus initialize(); 22 | 23 | public: 24 | static MStatus setElement(MDataHandle &elementHandle, MQuaternion q); 25 | 26 | public: 27 | static MTypeId NODE_ID; 28 | static MString NODE_NAME; 29 | 30 | static MObject inputQuatAttr; 31 | 32 | static MObject outputQuatAttr; 33 | static MObject outputQuatXAttr; 34 | static MObject outputQuatYAttr; 35 | static MObject outputQuatZAttr; 36 | static MObject outputQuatWAttr; 37 | static MObject outputXAttr; 38 | static MObject outputYAttr; 39 | static MObject outputZAttr; 40 | static MObject outputWAttr; 41 | static MObject outputAxisAttr; 42 | static MObject outputAngleAttr; 43 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/lerpVectorArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | lerpVectorArray node 8 | This node interpolates vectors using either linear or spherical interpolation. 9 | 10 | inputVector1 (iv1) vectorArray 11 | Array of vectors to interpolate from. 12 | 13 | inputVector2 (iv2) vectorArray 14 | Array of vectors to interpolate to. 15 | 16 | tween (t) double 17 | Placeholder description for tween 18 | 19 | slerp (slerp) bool 20 | If true, compute the slerp (spherical linear interpolation) between pairs of vectors. 21 | Otherwise, calculate the lerp (linear interpolation). 22 | 23 | outputVector (ov) vectorArray 24 | Array of vectors calculated by this node. 25 | 26 | */ 27 | 28 | #include "../nodeData.h" 29 | #include "lerpVectorArrayNode.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | 50 | MObject LerpVectorArrayNode::inputVector1Attr; 51 | MObject LerpVectorArrayNode::inputVector2Attr; 52 | MObject LerpVectorArrayNode::tweenAttr; 53 | MObject LerpVectorArrayNode::slerpAttr; 54 | 55 | MObject LerpVectorArrayNode::outputVectorAttr; 56 | 57 | 58 | void* LerpVectorArrayNode::creator() 59 | { 60 | return new LerpVectorArrayNode(); 61 | } 62 | 63 | 64 | MStatus LerpVectorArrayNode::initialize() 65 | { 66 | MStatus status; 67 | 68 | MFnNumericAttribute N; 69 | MFnTypedAttribute T; 70 | 71 | inputVector1Attr = T.create("inputVector1", "iv1", MFnData::kVectorArray, MObject::kNullObj, &status); 72 | inputVector2Attr = T.create("inputVector2", "iv2", MFnData::kVectorArray, MObject::kNullObj, &status); 73 | 74 | tweenAttr = N.create("tween", "t", MFnNumericData::kDouble, 0.5, &status); 75 | N.setChannelBox(true); 76 | N.setKeyable(true); 77 | N.setMin(0.0); 78 | N.setMax(1.0); 79 | 80 | slerpAttr = N.create("slerp", "slerp", MFnNumericData::kBoolean, true, &status); 81 | N.setChannelBox(true); 82 | N.setKeyable(true); 83 | 84 | addAttribute(inputVector1Attr); 85 | addAttribute(inputVector2Attr); 86 | addAttribute(tweenAttr); 87 | addAttribute(slerpAttr); 88 | 89 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 90 | T.setStorable(false); 91 | 92 | addAttribute(outputVectorAttr); 93 | 94 | attributeAffects(inputVector1Attr, outputVectorAttr); 95 | attributeAffects(inputVector2Attr, outputVectorAttr); 96 | attributeAffects(tweenAttr, outputVectorAttr); 97 | attributeAffects(slerpAttr, outputVectorAttr); 98 | 99 | return MStatus::kSuccess; 100 | } 101 | 102 | 103 | MStatus LerpVectorArrayNode::compute(const MPlug& plug, MDataBlock& data) 104 | { 105 | MStatus status; 106 | 107 | if (plug != outputVectorAttr) 108 | { 109 | return MStatus::kInvalidParameter; 110 | } 111 | 112 | MDataHandle input1Handle = data.inputValue(inputVector1Attr); 113 | MDataHandle input2Handle = data.inputValue(inputVector2Attr); 114 | double tween = data.inputValue(tweenAttr).asDouble(); 115 | tween = std::min(1.0, std::max(0.0, tween)); 116 | 117 | bool useSlerp = data.inputValue(slerpAttr).asBool(); 118 | 119 | std::vector input1 = getMayaArray(input1Handle); 120 | std::vector input2 = getMayaArray(input2Handle); 121 | 122 | size_t numberOfValues = std::max(input1.size(), input2.size()); 123 | 124 | std::vector output(numberOfValues); 125 | 126 | input1.resize(numberOfValues); 127 | input2.resize(numberOfValues); 128 | 129 | MVector (*INTERP)(MVector, MVector, double) = useSlerp ? &LerpVectorArrayNode::vectorSlerp : &LerpVectorArrayNode::lerp; 130 | 131 | for (size_t i = 0; i < numberOfValues; i++) 132 | { 133 | output[i] = INTERP(input1[i], input2[i], tween); 134 | } 135 | 136 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 137 | 138 | setMayaArray(outputHandle, output); 139 | 140 | return MStatus::kSuccess; 141 | } 142 | 143 | 144 | MVector LerpVectorArrayNode::lerp(MVector start, MVector end, double tween) 145 | { 146 | return start + ((end - start) * tween); 147 | } 148 | 149 | 150 | MVector LerpVectorArrayNode::vectorSlerp(MVector start, MVector end, double tween) 151 | { 152 | double dot = std::min(1.0, std::max(0.0, start * end)); 153 | double theta = std::acos(dot) * tween; 154 | 155 | MVector v = (end - start * dot); 156 | 157 | return (start * std::cos(theta)) + (v * std::sin(theta)); 158 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/lerpVectorArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class LerpVectorArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | private: 22 | static MVector lerp(MVector start, MVector end, double tween); 23 | static MVector vectorSlerp(MVector start, MVector end, double tween); 24 | 25 | public: 26 | static MTypeId NODE_ID; 27 | static MString NODE_NAME; 28 | 29 | static MObject inputVector1Attr; 30 | static MObject inputVector2Attr; 31 | static MObject tweenAttr; 32 | static MObject slerpAttr; 33 | 34 | static MObject outputVectorAttr; 35 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/packVectorArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | packVectorArray node 8 | This node constructs vectors from trios of values. 9 | 10 | inputVector (iv) compound[] 11 | Trios of vector component values. 12 | 13 | inputVectorX (ivx) double 14 | X component of a vector. 15 | 16 | inputVectorY (ivy) double 17 | Y component of a vector. 18 | 19 | inputVectorZ (ivz) double 20 | Z component of a vector. 21 | 22 | inputX (ix) 23 | X components of vectors. 24 | 25 | inputY (iy) 26 | Y components of vectors. 27 | 28 | inputZ (iz) 29 | Z components of vectors. 30 | 31 | fillValue (fv) double3 32 | Default value. 33 | 34 | fillValueX (fvx) double 35 | X component of the default value. 36 | 37 | fillValueY (fvy) double 38 | Y component of the default value. 39 | 40 | fillValueZ (fvz) double 41 | Z component of the default value. 42 | 43 | size (s) int 44 | Size of the output array. If the output is larger than the input, 45 | missing values will be filled in with the fillValue. 46 | 47 | inputMethod (im) enum 48 | Specifies the source of the vector components. 49 | 50 | Elements (0) creates vectors from trios of components. 51 | Components (1) creates vectors from a trio of component arrays. 52 | 53 | outputVector (ov) vectorArray 54 | Array of vectors calculated by this node. 55 | 56 | */ 57 | 58 | #include "../nodeData.h" 59 | #include "packVectorArrayNode.h" 60 | 61 | #include 62 | #include 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | 81 | 82 | MObject PackVectorArrayNode::inputVectorAttr; 83 | MObject PackVectorArrayNode::inputVectorXAttr; 84 | MObject PackVectorArrayNode::inputVectorYAttr; 85 | MObject PackVectorArrayNode::inputVectorZAttr; 86 | MObject PackVectorArrayNode::inputXAttr; 87 | MObject PackVectorArrayNode::inputYAttr; 88 | MObject PackVectorArrayNode::inputZAttr; 89 | MObject PackVectorArrayNode::fillValueAttr; 90 | MObject PackVectorArrayNode::fillValueXAttr; 91 | MObject PackVectorArrayNode::fillValueYAttr; 92 | MObject PackVectorArrayNode::fillValueZAttr; 93 | MObject PackVectorArrayNode::inputMethodAttr; 94 | MObject PackVectorArrayNode::sizeAttr; 95 | 96 | MObject PackVectorArrayNode::outputVectorAttr; 97 | 98 | 99 | void* PackVectorArrayNode::creator() 100 | { 101 | return new PackVectorArrayNode(); 102 | } 103 | 104 | 105 | MStatus PackVectorArrayNode::initialize() 106 | { 107 | MStatus status; 108 | 109 | MFnCompoundAttribute C; 110 | MFnEnumAttribute E; 111 | MFnNumericAttribute N; 112 | MFnTypedAttribute T; 113 | 114 | inputVectorXAttr = N.create("inputVectorX", "ivx", MFnNumericData::kDouble, 0, &status); 115 | inputVectorYAttr = N.create("inputVectorY", "ivy", MFnNumericData::kDouble, 0, &status); 116 | inputVectorZAttr = N.create("inputVectorZ", "ivz", MFnNumericData::kDouble, 0, &status); 117 | inputVectorAttr = C.create("inputVector", "iv", &status); 118 | C.setArray(true); 119 | C.addChild(inputVectorXAttr); 120 | C.addChild(inputVectorYAttr); 121 | C.addChild(inputVectorZAttr); 122 | 123 | inputXAttr = T.create("inputX", "ix", MFnData::kDoubleArray, MObject::kNullObj, &status); 124 | inputYAttr = T.create("inputY", "iy", MFnData::kDoubleArray, MObject::kNullObj, &status); 125 | inputZAttr = T.create("inputZ", "iz", MFnData::kDoubleArray, MObject::kNullObj, &status); 126 | 127 | fillValueXAttr = N.create("fillValueX", "fvx", MFnNumericData::kDouble, 0, &status); 128 | fillValueYAttr = N.create("fillValueY", "fvy", MFnNumericData::kDouble, 0, &status); 129 | fillValueZAttr = N.create("fillValueZ", "fvz", MFnNumericData::kDouble, 0, &status); 130 | fillValueAttr = C.create("fillValue", "fv", &status); 131 | C.addChild(fillValueXAttr); 132 | C.addChild(fillValueYAttr); 133 | C.addChild(fillValueZAttr); 134 | C.setChannelBox(true); 135 | C.setKeyable(true); 136 | 137 | sizeAttr = N.create("size", "s", MFnNumericData::kInt, 8, &status); 138 | N.setMin(0); 139 | N.setChannelBox(true); 140 | N.setKeyable(true); 141 | 142 | inputMethodAttr = E.create("inputMethod", "im", 0, &status); 143 | E.setChannelBox(true); 144 | E.setKeyable(true); 145 | E.addField("Elements", 0); 146 | E.addField("Components", 1); 147 | 148 | addAttribute(inputVectorAttr); 149 | addAttribute(inputXAttr); 150 | addAttribute(inputYAttr); 151 | addAttribute(inputZAttr); 152 | addAttribute(fillValueAttr); 153 | addAttribute(sizeAttr); 154 | addAttribute(inputMethodAttr); 155 | 156 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 157 | T.setStorable(false); 158 | 159 | addAttribute(outputVectorAttr); 160 | 161 | attributeAffects(inputVectorAttr, outputVectorAttr); 162 | attributeAffects(inputXAttr, outputVectorAttr); 163 | attributeAffects(inputYAttr, outputVectorAttr); 164 | attributeAffects(inputZAttr, outputVectorAttr); 165 | attributeAffects(fillValueAttr, outputVectorAttr); 166 | attributeAffects(sizeAttr, outputVectorAttr); 167 | attributeAffects(inputMethodAttr, outputVectorAttr); 168 | 169 | return MStatus::kSuccess; 170 | } 171 | 172 | 173 | MStatus PackVectorArrayNode::compute(const MPlug& plug, MDataBlock& data) 174 | { 175 | MStatus status; 176 | 177 | if (plug != outputVectorAttr) 178 | { 179 | return MStatus::kInvalidParameter; 180 | } 181 | 182 | short inputMethod = data.inputValue(inputMethodAttr).asShort(); 183 | unsigned size = (unsigned) data.inputValue(sizeAttr).asInt(); 184 | 185 | MDataHandle fillValueHandle = data.inputValue(fillValueAttr); 186 | MVector fillValue( 187 | fillValueHandle.child(fillValueXAttr).asDouble(), 188 | fillValueHandle.child(fillValueYAttr).asDouble(), 189 | fillValueHandle.child(fillValueZAttr).asDouble() 190 | ); 191 | 192 | std::vector output; 193 | 194 | if (inputMethod == 0) 195 | { 196 | MArrayDataHandle inputArrayHandle = data.inputArrayValue(inputVectorAttr); 197 | 198 | output = getArrayElements( 199 | inputArrayHandle, 200 | &PackVectorArrayNode::getElement, 201 | size, 202 | fillValue 203 | ); 204 | } else { 205 | MDataHandle inputXHandle = data.inputValue(inputXAttr); 206 | MDataHandle inputYHandle = data.inputValue(inputYAttr); 207 | MDataHandle inputZHandle = data.inputValue(inputZAttr); 208 | 209 | std::vector inputX = getMayaArray(inputXHandle); 210 | std::vector inputY = getMayaArray(inputYHandle); 211 | std::vector inputZ = getMayaArray(inputZHandle); 212 | 213 | unsigned numberOfInputs = 0; 214 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputX.size()); 215 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputY.size()); 216 | numberOfInputs = std::max(numberOfInputs, (unsigned) inputZ.size()); 217 | 218 | inputX.resize(numberOfInputs, fillValue.x); 219 | inputY.resize(numberOfInputs, fillValue.y); 220 | inputZ.resize(numberOfInputs, fillValue.z); 221 | output.resize(size, fillValue); 222 | 223 | unsigned numberOfOutputs = std::min(size, numberOfInputs); 224 | 225 | for (unsigned i = 0; i < numberOfOutputs; i++) 226 | { 227 | output[i] = MVector( 228 | inputX[i], 229 | inputY[i], 230 | inputZ[i] 231 | ); 232 | } 233 | } 234 | 235 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 236 | setMayaArray(outputHandle, output); 237 | 238 | return MStatus::kSuccess; 239 | } 240 | 241 | 242 | MVector PackVectorArrayNode::getElement(MDataHandle &elementHandle) 243 | { 244 | MVector result( 245 | elementHandle.child(inputVectorXAttr).asDouble(), 246 | elementHandle.child(inputVectorYAttr).asDouble(), 247 | elementHandle.child(inputVectorZAttr).asDouble() 248 | ); 249 | 250 | return result; 251 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/packVectorArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class PackVectorArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | static MVector getElement(MDataHandle &elementHandle); 22 | 23 | public: 24 | static MTypeId NODE_ID; 25 | static MString NODE_NAME; 26 | 27 | static MObject inputVectorAttr; 28 | static MObject inputVectorXAttr; 29 | static MObject inputVectorYAttr; 30 | static MObject inputVectorZAttr; 31 | static MObject inputXAttr; 32 | static MObject inputYAttr; 33 | static MObject inputZAttr; 34 | static MObject fillValueAttr; 35 | static MObject fillValueXAttr; 36 | static MObject fillValueYAttr; 37 | static MObject fillValueZAttr; 38 | static MObject sizeAttr; 39 | static MObject inputMethodAttr; 40 | 41 | static MObject outputVectorAttr; 42 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/pointToVectorArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | pointToVectorArray node 8 | This node converts points to vectors. 9 | 10 | inputPoint (ip) pointArray 11 | Array of points. 12 | 13 | outputVector (ov) vectorArray 14 | Array of vectors. 15 | 16 | */ 17 | 18 | #include "../nodeData.h" 19 | #include "pointToVectorArrayNode.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | 39 | MObject PointToVectorArrayNode::inputPointAttr; 40 | 41 | MObject PointToVectorArrayNode::outputVectorAttr; 42 | 43 | 44 | void* PointToVectorArrayNode::creator() 45 | { 46 | return new PointToVectorArrayNode(); 47 | } 48 | 49 | 50 | MStatus PointToVectorArrayNode::initialize() 51 | { 52 | MStatus status; 53 | 54 | MFnTypedAttribute T; 55 | 56 | inputPointAttr = T.create("inputPoint", "ip", MFnData::kPointArray, MObject::kNullObj, &status); 57 | 58 | addAttribute(inputPointAttr); 59 | 60 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 61 | T.setStorable(false); 62 | 63 | addAttribute(outputVectorAttr); 64 | 65 | attributeAffects(inputPointAttr, outputVectorAttr); 66 | 67 | return MStatus::kSuccess; 68 | } 69 | 70 | 71 | MStatus PointToVectorArrayNode::compute(const MPlug& plug, MDataBlock& data) 72 | { 73 | MStatus status; 74 | 75 | if (plug != outputVectorAttr) 76 | { 77 | return MStatus::kInvalidParameter; 78 | } 79 | 80 | MDataHandle inputHandle = data.inputValue(inputPointAttr); 81 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 82 | 83 | std::vector input = getMayaArray(inputHandle); 84 | size_t numberOfValues = input.size(); 85 | std::vector output(numberOfValues); 86 | 87 | for (size_t i = 0; i < numberOfValues; i++) 88 | { 89 | output[i] = MVector(input[i]); 90 | } 91 | 92 | setMayaArray(outputHandle, output); 93 | 94 | return MStatus::kSuccess; 95 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/pointToVectorArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class PointToVectorArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputPointAttr; 26 | 27 | static MObject outputVectorAttr; 28 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/rotateVectorArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | rotateVectorArray node 8 | This node computes the result of rotating vectors. 9 | 10 | inputVector (iv) vectorArray 11 | Array of vectors to rotate. 12 | 13 | inputQuat (iq) quatArray 14 | Rotations to be applied to the vectors as expressed by quaternions. 15 | 16 | inputRotate (ir) eulerArray 17 | Rotations to be applied to the vectors as expressed by euler rotations. 18 | 19 | inputAxis (iax) vectorArray 20 | Pivot axes of the rotations to be applied to the vectors. 21 | 22 | inputAngle (ia) angleArray 23 | Rotations about an axis to be applied to the vectors. 24 | 25 | operation (op) enum 26 | Specifies how the vectors are rotated. 27 | 28 | No Operation (0) does not rotate the vectors 29 | By Axis/Angle (1) rotates the vectors using the "inputAxis" and "inputAngle" values. 30 | By Euler Rotation (2) rotates the vectors using the "inputRotate" values. 31 | By Quaternion (3) rotates the vectors using the "inputQuat" values. 32 | 33 | outputVector (ov) vectorArray 34 | Array of vectors calculated by this node. 35 | 36 | */ 37 | 38 | #include "../../data/angleArrayData.h" 39 | #include "../../data/eulerArrayData.h" 40 | #include "../../data/quatArrayData.h" 41 | #include "../nodeData.h" 42 | #include "rotateVectorArrayNode.h" 43 | 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | const short AXIS_ANGLE = 1; 62 | const short EULER_ROTATE = 2; 63 | const short QUATERNION = 3; 64 | 65 | MObject RotateVectorArrayNode::inputVectorAttr; 66 | MObject RotateVectorArrayNode::inputQuatAttr; 67 | MObject RotateVectorArrayNode::inputRotateAttr; 68 | MObject RotateVectorArrayNode::inputAxisAttr; 69 | MObject RotateVectorArrayNode::inputAngleAttr; 70 | MObject RotateVectorArrayNode::operationAttr; 71 | 72 | MObject RotateVectorArrayNode::outputVectorAttr; 73 | 74 | 75 | void* RotateVectorArrayNode::creator() 76 | { 77 | return new RotateVectorArrayNode(); 78 | } 79 | 80 | 81 | MStatus RotateVectorArrayNode::initialize() 82 | { 83 | MStatus status; 84 | 85 | MFnEnumAttribute E; 86 | MFnTypedAttribute T; 87 | 88 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 89 | inputQuatAttr = T.create("inputQuat", "iq", QuatArrayData::TYPE_ID, MObject::kNullObj, &status); 90 | inputRotateAttr = T.create("inputRotate", "ir", EulerArrayData::TYPE_ID, MObject::kNullObj, &status); 91 | inputAxisAttr = T.create("inputAxis", "iax", MFnData::kVectorArray, MObject::kNullObj, &status); 92 | inputAngleAttr = T.create("inputAngle", "ia", AngleArrayData::TYPE_ID, MObject::kNullObj, &status); 93 | 94 | operationAttr = E.create("operation", "op", 1, &status); 95 | E.setChannelBox(true); 96 | E.setKeyable(true); 97 | E.addField("No Operation", 0); 98 | E.addField("Rotate by Axis/Angle", AXIS_ANGLE); 99 | E.addField("Rotate by Euler Rotation", EULER_ROTATE); 100 | E.addField("Rotate by Quaternion", QUATERNION); 101 | 102 | addAttribute(inputVectorAttr); 103 | addAttribute(inputQuatAttr); 104 | addAttribute(inputRotateAttr); 105 | addAttribute(inputAxisAttr); 106 | addAttribute(inputAngleAttr); 107 | addAttribute(operationAttr); 108 | 109 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 110 | T.setStorable(false); 111 | 112 | addAttribute(outputVectorAttr); 113 | 114 | attributeAffects(inputVectorAttr, outputVectorAttr); 115 | attributeAffects(inputQuatAttr, outputVectorAttr); 116 | attributeAffects(inputRotateAttr, outputVectorAttr); 117 | attributeAffects(inputAxisAttr, outputVectorAttr); 118 | attributeAffects(inputAngleAttr, outputVectorAttr); 119 | attributeAffects(operationAttr, outputVectorAttr); 120 | 121 | return MStatus::kSuccess; 122 | } 123 | 124 | 125 | MStatus RotateVectorArrayNode::compute(const MPlug& plug, MDataBlock& data) 126 | { 127 | MStatus status; 128 | 129 | if (plug != outputVectorAttr) 130 | { 131 | return MStatus::kInvalidParameter; 132 | } 133 | 134 | short operation = data.inputValue(operationAttr).asShort(); 135 | 136 | MDataHandle inputHandle = data.inputValue(inputVectorAttr); 137 | std::vector input = getMayaArray(inputHandle); 138 | 139 | size_t numberOfValues = input.size(); 140 | 141 | std::vector output(numberOfValues); 142 | 143 | if (operation == AXIS_ANGLE) 144 | { 145 | MDataHandle axisHandle = data.inputValue(inputAxisAttr); 146 | MDataHandle angleHandle = data.inputValue(inputAngleAttr); 147 | 148 | std::vector axis = getMayaArray(axisHandle); 149 | std::vector angle = getUserArray(angleHandle); 150 | 151 | axis.resize(numberOfValues); 152 | angle.resize(numberOfValues); 153 | 154 | for (size_t i = 0; i < numberOfValues; i++) 155 | { 156 | // todo: write equation that does this; 157 | } 158 | } else if (operation == EULER_ROTATE) { 159 | MDataHandle rotateHandle = data.inputValue(inputRotateAttr); 160 | 161 | std::vector rotate = getUserArray(rotateHandle); 162 | rotate.resize(numberOfValues); 163 | 164 | for (size_t i = 0; i < numberOfValues; i++) 165 | { 166 | output[i] = input[i].rotateBy(rotate[i]); 167 | } 168 | } else if (operation == AXIS_ANGLE) { 169 | MDataHandle rotateHandle = data.inputValue(inputQuatAttr); 170 | 171 | std::vector rotate = getUserArray(rotateHandle); 172 | rotate.resize(numberOfValues); 173 | 174 | for (size_t i = 0; i < numberOfValues; i++) 175 | { 176 | output[i] = input[i].rotateBy(rotate[i]); 177 | } 178 | } 179 | 180 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 181 | setMayaArray(outputHandle, output); 182 | 183 | return MStatus::kSuccess; 184 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/rotateVectorArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class RotateVectorArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputVectorAttr; 26 | static MObject inputQuatAttr; 27 | static MObject inputRotateAttr; 28 | static MObject inputAxisAttr; 29 | static MObject inputAngleAttr; 30 | static MObject operationAttr; 31 | 32 | static MObject outputVectorAttr; 33 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/unpackVectorArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | unpackVectorArray node 8 | This node unpacks vectors into their components. 9 | 10 | inputVector (iv) vectorArray 11 | Array of vectors to be unpacked. 12 | 13 | outputVector (ov) double3[] 14 | List of vector components. 15 | 16 | outputVectorX (ovx) double 17 | X component of a vector. 18 | 19 | outputVectorY (ovy) double 20 | Y component of a vector. 21 | 22 | outputVectorZ (ovz) double 23 | Z component of a vector. 24 | 25 | outputX (ox) doubleArray 26 | X components of the input vectors. 27 | 28 | outputY (oy) doubleArray 29 | Y components of the input vectors. 30 | 31 | outputZ (oz) doubleArray 32 | Z components of the input vectors. 33 | 34 | */ 35 | 36 | #include "../nodeData.h" 37 | #include "unpackVectorArrayNode.h" 38 | 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | 58 | MObject UnpackVectorArrayNode::inputVectorAttr; 59 | 60 | MObject UnpackVectorArrayNode::outputVectorAttr; 61 | MObject UnpackVectorArrayNode::outputVectorXAttr; 62 | MObject UnpackVectorArrayNode::outputVectorYAttr; 63 | MObject UnpackVectorArrayNode::outputVectorZAttr; 64 | MObject UnpackVectorArrayNode::outputXAttr; 65 | MObject UnpackVectorArrayNode::outputYAttr; 66 | MObject UnpackVectorArrayNode::outputZAttr; 67 | 68 | 69 | void* UnpackVectorArrayNode::creator() 70 | { 71 | return new UnpackVectorArrayNode(); 72 | } 73 | 74 | 75 | MStatus UnpackVectorArrayNode::initialize() 76 | { 77 | MStatus status; 78 | 79 | MFnCompoundAttribute C; 80 | MFnNumericAttribute N; 81 | MFnTypedAttribute T; 82 | 83 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 84 | 85 | addAttribute(inputVectorAttr); 86 | 87 | outputVectorXAttr = N.create("outputVectorX", "ovx", MFnNumericData::kDouble, 0, &status); 88 | outputVectorYAttr = N.create("outputVectorY", "ovy", MFnNumericData::kDouble, 0, &status); 89 | outputVectorZAttr = N.create("outputVectorZ", "ovz", MFnNumericData::kDouble, 0, &status); 90 | outputVectorAttr = C.create("outputVector", "ov", &status); 91 | C.setArray(true); 92 | C.setStorable(false); 93 | C.setUsesArrayDataBuilder(true); 94 | C.setStorable(false); 95 | C.addChild(outputVectorXAttr); 96 | C.addChild(outputVectorYAttr); 97 | C.addChild(outputVectorZAttr); 98 | 99 | outputXAttr = T.create("outputX", "ox", MFnData::kDoubleArray, MObject::kNullObj, &status); 100 | T.setStorable(false); 101 | outputYAttr = T.create("outputY", "oy", MFnData::kDoubleArray, MObject::kNullObj, &status); 102 | T.setStorable(false); 103 | outputZAttr = T.create("outputZ", "oz", MFnData::kDoubleArray, MObject::kNullObj, &status); 104 | T.setStorable(false); 105 | 106 | addAttribute(outputVectorAttr); 107 | addAttribute(outputXAttr); 108 | addAttribute(outputYAttr); 109 | addAttribute(outputZAttr); 110 | 111 | attributeAffects(inputVectorAttr, outputVectorAttr); 112 | attributeAffects(inputVectorAttr, outputXAttr); 113 | attributeAffects(inputVectorAttr, outputYAttr); 114 | attributeAffects(inputVectorAttr, outputZAttr); 115 | 116 | return MStatus::kSuccess; 117 | } 118 | 119 | 120 | MStatus UnpackVectorArrayNode::compute(const MPlug& plug, MDataBlock& data) 121 | { 122 | MStatus status; 123 | 124 | if ( 125 | plug != outputVectorAttr && 126 | plug.parent() != outputVectorAttr && 127 | plug != outputXAttr && 128 | plug != outputYAttr && 129 | plug != outputZAttr 130 | ) { 131 | return MStatus::kInvalidParameter; 132 | } 133 | 134 | MDataHandle inputHandle = data.inputValue(inputVectorAttr); 135 | 136 | std::vector input = getMayaArray(inputHandle); 137 | 138 | size_t numberOfValues = input.size(); 139 | 140 | std::vector outputX(numberOfValues); 141 | std::vector outputY(numberOfValues); 142 | std::vector outputZ(numberOfValues); 143 | 144 | for (size_t i = 0; i < numberOfValues; i++) 145 | { 146 | MVector &v = input[i]; 147 | 148 | outputX[i] = v.x; 149 | outputY[i] = v.y; 150 | outputZ[i] = v.z; 151 | } 152 | 153 | MArrayDataHandle outputArrayHandle = data.outputArrayValue(outputVectorAttr); 154 | setArrayElements(outputArrayHandle, input, &UnpackVectorArrayNode::setElement); 155 | 156 | MDataHandle outputXHandle = data.outputValue(outputXAttr); 157 | MDataHandle outputYHandle = data.outputValue(outputYAttr); 158 | MDataHandle outputZHandle = data.outputValue(outputZAttr); 159 | 160 | setMayaArray(outputXHandle, outputX); 161 | setMayaArray(outputYHandle, outputY); 162 | setMayaArray(outputZHandle, outputZ); 163 | 164 | return MStatus::kSuccess; 165 | } 166 | 167 | 168 | MStatus UnpackVectorArrayNode::setElement(MDataHandle &elementHandle, MVector v) 169 | { 170 | MDataHandle xHandle = elementHandle.child(outputVectorXAttr); 171 | MDataHandle yHandle = elementHandle.child(outputVectorYAttr); 172 | MDataHandle zHandle = elementHandle.child(outputVectorZAttr); 173 | 174 | xHandle.setDouble(v.x); 175 | yHandle.setDouble(v.y); 176 | zHandle.setDouble(v.z); 177 | 178 | xHandle.setClean(); 179 | yHandle.setClean(); 180 | zHandle.setClean(); 181 | 182 | return MStatus::kSuccess; 183 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/unpackVectorArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class UnpackVectorArrayNode : public MPxNode 17 | { 18 | public: 19 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 20 | static void* creator(); 21 | static MStatus initialize(); 22 | 23 | static MStatus setElement(MDataHandle &elementHandle, MVector v); 24 | public: 25 | static MTypeId NODE_ID; 26 | static MString NODE_NAME; 27 | 28 | static MObject inputVectorAttr; 29 | 30 | static MObject outputVectorAttr; 31 | static MObject outputVectorXAttr; 32 | static MObject outputVectorYAttr; 33 | static MObject outputVectorZAttr; 34 | static MObject outputXAttr; 35 | static MObject outputYAttr; 36 | static MObject outputZAttr; 37 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayBinaryOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorArrayBinaryOp node 8 | This node performs binary operations of pairs of vectors. 9 | 10 | inputVector1 (iv1) vectorArray 11 | First array of vectors. 12 | 13 | inputVector2 (iv2) vectorArray 14 | Second array of vectors. 15 | 16 | operation (op) enum 17 | Specifies the binary operation performed. 18 | 19 | No Operation (0) returns the first array of vectors. 20 | Add (1) returns the sums of the first and second vectors. 21 | Subtract (2) returns the differences between the first and second vectors. 22 | Cross Product (3) returns the cross products of the first and second vectors. 23 | 24 | outputVector (ov) vectorArray 25 | Array of vectors calculated by this node. 26 | 27 | */ 28 | 29 | #include "../nodeData.h" 30 | #include "vectorArrayBinaryOpNode.h" 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | 49 | const short ADD = 1; 50 | const short SUBTRACT = 2; 51 | const short CROSS = 3 ; 52 | 53 | 54 | MObject VectorArrayBinaryOpNode::inputVector1Attr; 55 | MObject VectorArrayBinaryOpNode::inputVector2Attr; 56 | MObject VectorArrayBinaryOpNode::operationAttr; 57 | 58 | MObject VectorArrayBinaryOpNode::outputVectorAttr; 59 | 60 | 61 | void* VectorArrayBinaryOpNode::creator() 62 | { 63 | return new VectorArrayBinaryOpNode(); 64 | } 65 | 66 | 67 | MStatus VectorArrayBinaryOpNode::initialize() 68 | { 69 | MStatus status; 70 | 71 | MFnEnumAttribute E; 72 | MFnTypedAttribute T; 73 | 74 | inputVector1Attr = T.create("inputVector1", "iv1", MFnData::kVectorArray, MObject::kNullObj, &status); 75 | inputVector2Attr = T.create("inputVector2", "iv2", MFnData::kVectorArray, MObject::kNullObj, &status); 76 | 77 | operationAttr = E.create("operation", "op", 1, &status); 78 | E.setChannelBox(true); 79 | E.setKeyable(true); 80 | E.addField("No Operation", 0); 81 | E.addField("Add", ADD); 82 | E.addField("Subtract", SUBTRACT); 83 | E.addField("Cross Product", CROSS); 84 | 85 | addAttribute(inputVector1Attr); 86 | addAttribute(inputVector2Attr); 87 | addAttribute(operationAttr); 88 | 89 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 90 | T.setStorable(false); 91 | 92 | addAttribute(outputVectorAttr); 93 | 94 | attributeAffects(inputVector1Attr, outputVectorAttr); 95 | attributeAffects(inputVector2Attr, outputVectorAttr); 96 | attributeAffects(operationAttr, outputVectorAttr); 97 | 98 | return MStatus::kSuccess; 99 | } 100 | 101 | 102 | MStatus VectorArrayBinaryOpNode::compute(const MPlug& plug, MDataBlock& data) 103 | { 104 | MStatus status; 105 | 106 | if (plug != outputVectorAttr) 107 | { 108 | return MStatus::kInvalidParameter; 109 | } 110 | 111 | short operation = data.inputValue(operationAttr).asShort(); 112 | 113 | MDataHandle input1Handle = data.inputValue(inputVector1Attr); 114 | MDataHandle input2Handle = data.inputValue(inputVector2Attr); 115 | 116 | std::vector input1 = getMayaArray(input1Handle); 117 | std::vector input2 = getMayaArray(input2Handle); 118 | 119 | size_t numberOfValues = std::max(input1.size(), input2.size()); 120 | 121 | input1.resize(numberOfValues); 122 | input2.resize(numberOfValues); 123 | 124 | std::vector output(numberOfValues); 125 | 126 | MVector (*F)(MVector, MVector) = &VectorArrayBinaryOpNode::nop; 127 | 128 | switch (operation) 129 | { 130 | case ADD: F = &VectorArrayBinaryOpNode::add; break; 131 | case SUBTRACT: F = &VectorArrayBinaryOpNode::subtract; break; 132 | case CROSS: F = &VectorArrayBinaryOpNode::cross; break; 133 | } 134 | 135 | for (size_t i = 0; i < numberOfValues; i++) 136 | { 137 | output[i] = F(input1[i], input2[i]); 138 | } 139 | 140 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 141 | setMayaArray(outputHandle, output); 142 | 143 | return MStatus::kSuccess; 144 | } 145 | 146 | MVector VectorArrayBinaryOpNode::nop(MVector v1, MVector v2) { return v1; } 147 | MVector VectorArrayBinaryOpNode::add(MVector v1, MVector v2) { return v1 + v2; } 148 | MVector VectorArrayBinaryOpNode::subtract(MVector v1, MVector v2) { return v1 - v2; } 149 | MVector VectorArrayBinaryOpNode::cross(MVector v1, MVector v2) { return v1 ^ v2; } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayBinaryOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class VectorArrayBinaryOpNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | private: 22 | static inline MVector nop(MVector v1, MVector v2); 23 | static inline MVector add(MVector v1, MVector v2); 24 | static inline MVector subtract(MVector v1, MVector v2); 25 | static inline MVector cross(MVector v1, MVector v2); 26 | 27 | public: 28 | static MTypeId NODE_ID; 29 | static MString NODE_NAME; 30 | 31 | static MObject inputVector1Attr; 32 | static MObject inputVector2Attr; 33 | static MObject operationAttr; 34 | 35 | static MObject outputVectorAttr; 36 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayMatrixOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorArrayMatrixOp node 8 | This node performs binary operations on vector/matrix pairs. 9 | 10 | inputVector (iv) vectorArray 11 | Array of vectors. 12 | 13 | inputMatrix (im) matrixArray 14 | Array of matrices. 15 | 16 | operation (op) enum 17 | Specifies the operation to be performed. 18 | 19 | No Operation (0) returns the array of vectors. 20 | Vector Matrix Product (1) returns the result of vector matrix multiplication. 21 | Point Matrix Product (2) returns the result of point matrix multiplication. 22 | 23 | outputVector (ov) vectorArray 24 | Array of vectors calculated by this node. 25 | 26 | */ 27 | 28 | #include "../nodeData.h" 29 | #include "vectorArrayMatrixOpNode.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | const short VECTOR_MATRIX_PRODUCT = 1; 52 | const short POINT_MATRIX_PRODUCT = 2; 53 | 54 | MObject VectorArrayMatrixOpNode::inputVectorAttr; 55 | MObject VectorArrayMatrixOpNode::inputMatrixAttr; 56 | MObject VectorArrayMatrixOpNode::operationAttr; 57 | 58 | MObject VectorArrayMatrixOpNode::outputVectorAttr; 59 | 60 | 61 | void* VectorArrayMatrixOpNode::creator() 62 | { 63 | return new VectorArrayMatrixOpNode(); 64 | } 65 | 66 | 67 | MStatus VectorArrayMatrixOpNode::initialize() 68 | { 69 | MStatus status; 70 | 71 | MFnEnumAttribute E; 72 | MFnTypedAttribute T; 73 | 74 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 75 | inputMatrixAttr = T.create("inputMatrix", "im", MFnData::kMatrixArray, MObject::kNullObj, &status); 76 | 77 | operationAttr = E.create("operation", "op", 1, &status); 78 | E.setChannelBox(true); 79 | E.setKeyable(true); 80 | E.addField("No Operation", 0); 81 | E.addField("Vector Matrix Product", 1); 82 | E.addField("Point Matrix Product", 2); 83 | 84 | addAttribute(inputVectorAttr); 85 | addAttribute(inputMatrixAttr); 86 | addAttribute(operationAttr); 87 | 88 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 89 | T.setStorable(false); 90 | 91 | addAttribute(outputVectorAttr); 92 | 93 | attributeAffects(inputVectorAttr, outputVectorAttr); 94 | attributeAffects(inputMatrixAttr, outputVectorAttr); 95 | attributeAffects(operationAttr, outputVectorAttr); 96 | 97 | return MStatus::kSuccess; 98 | } 99 | 100 | 101 | MStatus VectorArrayMatrixOpNode::compute(const MPlug& plug, MDataBlock& data) 102 | { 103 | MStatus status; 104 | 105 | if (plug != outputVectorAttr) 106 | { 107 | return MStatus::kInvalidParameter; 108 | } 109 | 110 | short operation = data.inputValue(operationAttr).asShort(); 111 | 112 | MDataHandle inputVectorHandle = data.inputValue(inputVectorAttr); 113 | MDataHandle inputMatrixHandle = data.inputValue(inputMatrixAttr); 114 | 115 | std::vector vector_ = getMayaArray(inputVectorHandle); 116 | std::vector matrix = getMayaArray(inputMatrixHandle); 117 | 118 | size_t numberOfValues = std::max(vector_.size(), matrix.size()); 119 | 120 | vector_.resize(numberOfValues); 121 | matrix.resize(numberOfValues); 122 | 123 | std::vector output(numberOfValues); 124 | 125 | MVector (*F)(MVector, MMatrix) = &VectorArrayMatrixOpNode::nop; 126 | 127 | switch (operation) 128 | { 129 | case VECTOR_MATRIX_PRODUCT: F = &VectorArrayMatrixOpNode::vectorMatrixProduct; break; 130 | case POINT_MATRIX_PRODUCT: F = &VectorArrayMatrixOpNode::pointMatrixProduct; break; 131 | } 132 | 133 | for (size_t i = 0; i < numberOfValues; i++) 134 | { 135 | output[i] = F(vector_[i], matrix[i]); 136 | } 137 | 138 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 139 | setMayaArray(outputHandle, output); 140 | 141 | return MStatus::kSuccess; 142 | } 143 | 144 | MVector VectorArrayMatrixOpNode::nop(MVector v, MMatrix m) { return v; } 145 | MVector VectorArrayMatrixOpNode::vectorMatrixProduct(MVector v, MMatrix m) { return v * m; } 146 | MVector VectorArrayMatrixOpNode::pointMatrixProduct(MVector v, MMatrix m) { return MVector(MPoint(v) * m); } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayMatrixOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class VectorArrayMatrixOpNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | private: 22 | static inline MVector nop(MVector v, MMatrix m); 23 | static inline MVector vectorMatrixProduct(MVector v, MMatrix m); 24 | static inline MVector pointMatrixProduct(MVector v, MMatrix m); 25 | 26 | public: 27 | static MTypeId NODE_ID; 28 | static MString NODE_NAME; 29 | 30 | static MObject inputVectorAttr; 31 | static MObject inputMatrixAttr; 32 | static MObject operationAttr; 33 | 34 | static MObject outputVectorAttr; 35 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayScalarOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorArrayScalarOp node 8 | This node performs scalar operations on vectors. 9 | 10 | inputVector (iv) vectorArray 11 | Array of vectors. 12 | 13 | scalar (sc) double 14 | Scalar value. 15 | 16 | operation (op) enum 17 | Specifies the operation to be performed. 18 | 19 | No Operation (0) returns the array of vectors. 20 | Multiply (1) returns the result of vector scalar multiplication. 21 | Divide (2) returns the result of point scalar division. 22 | 23 | outputVector (ov) vectorArray 24 | Array of vectors calculated by this node. 25 | */ 26 | 27 | #include "../nodeData.h" 28 | #include "vectorArrayScalarOpNode.h" 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | 47 | const short MULTIPLY = 1; 48 | const short DIVIDE = 2; 49 | 50 | MObject VectorArrayScalarOpNode::inputVectorAttr; 51 | MObject VectorArrayScalarOpNode::scalarAttr; 52 | MObject VectorArrayScalarOpNode::operationAttr; 53 | 54 | MObject VectorArrayScalarOpNode::outputVectorAttr; 55 | 56 | 57 | void* VectorArrayScalarOpNode::creator() 58 | { 59 | return new VectorArrayScalarOpNode(); 60 | } 61 | 62 | 63 | MStatus VectorArrayScalarOpNode::initialize() 64 | { 65 | MStatus status; 66 | 67 | MFnEnumAttribute E; 68 | MFnNumericAttribute N; 69 | MFnTypedAttribute T; 70 | 71 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 72 | 73 | scalarAttr = T.create("scalar", "sc", MFnData::kDoubleArray, MObject::kNullObj, &status); 74 | 75 | operationAttr = E.create("operation", "op", 1, &status); 76 | E.setChannelBox(true); 77 | E.setKeyable(true); 78 | E.addField("No Operation", 0); 79 | E.addField("Multiply", MULTIPLY); 80 | E.addField("Divide", DIVIDE); 81 | 82 | addAttribute(inputVectorAttr); 83 | addAttribute(scalarAttr); 84 | addAttribute(operationAttr); 85 | 86 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 87 | T.setStorable(false); 88 | 89 | addAttribute(outputVectorAttr); 90 | 91 | attributeAffects(inputVectorAttr, outputVectorAttr); 92 | attributeAffects(operationAttr, outputVectorAttr); 93 | attributeAffects(scalarAttr, outputVectorAttr); 94 | 95 | return MStatus::kSuccess; 96 | } 97 | 98 | 99 | MStatus VectorArrayScalarOpNode::compute(const MPlug& plug, MDataBlock& data) 100 | { 101 | MStatus status; 102 | 103 | if (plug != outputVectorAttr) 104 | { 105 | return MStatus::kInvalidParameter; 106 | } 107 | 108 | short operation = data.inputValue(operationAttr).asShort(); 109 | 110 | MDataHandle inputVectorHandle = data.inputValue(inputVectorAttr); 111 | MDataHandle inputScalarHandle = data.inputValue(scalarAttr); 112 | 113 | std::vector vector_ = getMayaArray(inputVectorHandle); 114 | std::vector scalar = getMayaArray(inputScalarHandle); 115 | 116 | size_t numberOfValues = vector_.size(); 117 | scalar.resize(numberOfValues, 1); 118 | 119 | std::vector output(numberOfValues); 120 | 121 | MVector (*F)(MVector, double) = &VectorArrayScalarOpNode::nop; 122 | 123 | switch (operation) 124 | { 125 | case MULTIPLY: F = &VectorArrayScalarOpNode::multiply; break; 126 | case DIVIDE: F = &VectorArrayScalarOpNode::divide; break; 127 | } 128 | 129 | for (size_t i = 0; i < numberOfValues; i++) 130 | { 131 | output[i] = F(vector_[i], scalar[i]); 132 | } 133 | 134 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 135 | setMayaArray(outputHandle, output); 136 | 137 | return MStatus::kSuccess; 138 | } 139 | 140 | 141 | MVector VectorArrayScalarOpNode::nop(MVector v, double s) { return v; } 142 | MVector VectorArrayScalarOpNode::multiply(MVector v, double s) { return v * s; } 143 | MVector VectorArrayScalarOpNode::divide(MVector v, double s) { return v / s; } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayScalarOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class VectorArrayScalarOpNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | private: 22 | static inline MVector nop(MVector v, double s); 23 | static inline MVector multiply(MVector v, double s); 24 | static inline MVector divide(MVector v, double s); 25 | 26 | public: 27 | static MTypeId NODE_ID; 28 | static MString NODE_NAME; 29 | 30 | static MObject inputVectorAttr; 31 | static MObject operationAttr; 32 | static MObject scalarAttr; 33 | 34 | static MObject outputVectorAttr; 35 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayToDoubleOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorArrayToDoubleOp node 8 | This node performs calculates using pairs of vectors and returning a scalar. 9 | 10 | inputVector1 (iv1) vectorArray 11 | First array of vectors, used for all operations. 12 | 13 | inputVector2 (iv2) vectorArray 14 | Second array of vectors, used for the Dot Product and Distance Between operations only. 15 | 16 | operation (op) enum 17 | Specifies the operation that will be performed. 18 | 19 | No Operation (0) performs no calculation and returns 0. 20 | Dot Product (1) calculates the dot products between pairs of vectors. 21 | Length (2) calculates the lengths of the first array of vectors. 22 | Distance Between (3) calculates the distances between the ends of pairs of vectors. 23 | 24 | output (o) doubleArray 25 | Array of values calculated by this node. 26 | 27 | */ 28 | 29 | #include "../nodeData.h" 30 | #include "vectorArrayToDoubleOpNode.h" 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | 50 | const short DOT_PRODUCT = 1; 51 | const short LENGTH = 2; 52 | const short DISTANCE_BETWEEN = 3; 53 | 54 | 55 | MObject VectorArrayToDoubleOpNode::inputVector1Attr; 56 | MObject VectorArrayToDoubleOpNode::inputVector2Attr; 57 | MObject VectorArrayToDoubleOpNode::operationAttr; 58 | 59 | MObject VectorArrayToDoubleOpNode::outputAttr; 60 | 61 | 62 | void* VectorArrayToDoubleOpNode::creator() 63 | { 64 | return new VectorArrayToDoubleOpNode(); 65 | } 66 | 67 | 68 | MStatus VectorArrayToDoubleOpNode::initialize() 69 | { 70 | MStatus status; 71 | 72 | MFnEnumAttribute E; 73 | MFnTypedAttribute T; 74 | 75 | inputVector1Attr = T.create("inputVector1", "iv1", MFnData::kVectorArray, MObject::kNullObj, &status); 76 | inputVector2Attr = T.create("inputVector2", "iv2", MFnData::kVectorArray, MObject::kNullObj, &status); 77 | 78 | operationAttr = E.create("operation", "op", 1, &status); 79 | E.setChannelBox(true); 80 | E.setKeyable(true); 81 | E.addField("No Operation", 0); 82 | E.addField("Dot Product", 1); 83 | E.addField("Vector Length", 2); 84 | E.addField("Distance Between", 3); 85 | 86 | addAttribute(inputVector1Attr); 87 | addAttribute(inputVector2Attr); 88 | addAttribute(operationAttr); 89 | 90 | outputAttr = T.create("output", "o", MFnData::kDoubleArray, MObject::kNullObj, &status); 91 | T.setStorable(true); 92 | 93 | addAttribute(outputAttr); 94 | 95 | attributeAffects(inputVector1Attr, outputAttr); 96 | attributeAffects(inputVector2Attr, outputAttr); 97 | attributeAffects(operationAttr, outputAttr); 98 | 99 | return MStatus::kSuccess; 100 | } 101 | 102 | 103 | MStatus VectorArrayToDoubleOpNode::compute(const MPlug& plug, MDataBlock& data) 104 | { 105 | MStatus status; 106 | 107 | if (plug != outputAttr) 108 | { 109 | return MStatus::kInvalidParameter; 110 | } 111 | 112 | short operation = data.inputValue(operationAttr).asShort(); 113 | 114 | MDataHandle input1Handle = data.inputValue(inputVector1Attr); 115 | MDataHandle input2Handle = data.inputValue(inputVector2Attr); 116 | 117 | std::vector input1 = getMayaArray(input1Handle); 118 | std::vector input2 = getMayaArray(input2Handle); 119 | 120 | size_t numberOfValues = std::max(input1.size(), input2.size()); 121 | 122 | input1.resize(numberOfValues); 123 | input2.resize(numberOfValues); 124 | 125 | std::vector output(numberOfValues); 126 | 127 | double (*F)(MVector, MVector) = &VectorArrayToDoubleOpNode::nop; 128 | 129 | switch (operation) 130 | { 131 | case DISTANCE_BETWEEN: F = &VectorArrayToDoubleOpNode::distanceBetween; break; 132 | case DOT_PRODUCT: F = &VectorArrayToDoubleOpNode::dotProduct; break; 133 | case LENGTH: F = &VectorArrayToDoubleOpNode::length; break; 134 | } 135 | 136 | for (size_t i = 0; i < numberOfValues; i++) 137 | { 138 | output[i] = F(input1[i], input2[i]); 139 | } 140 | 141 | MDataHandle outputHandle = data.outputValue(outputAttr); 142 | setMayaArray(outputHandle, output); 143 | 144 | return MStatus::kSuccess; 145 | } 146 | 147 | 148 | double VectorArrayToDoubleOpNode::nop(MVector v1, MVector v2) { return 0.0;} 149 | double VectorArrayToDoubleOpNode::distanceBetween(MVector v1, MVector v2) { return MPoint(v1).distanceTo(MPoint(v2)); } 150 | double VectorArrayToDoubleOpNode::dotProduct(MVector v1, MVector v2) { return v1 * v2; } 151 | double VectorArrayToDoubleOpNode::length(MVector v1, MVector v2) { return v1.length(); } 152 | -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayToDoubleOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class VectorArrayToDoubleOpNode : public MPxNode 16 | { 17 | public: 18 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 19 | static void* creator(); 20 | static MStatus initialize(); 21 | 22 | private: 23 | static inline double nop(MVector v1, MVector v2); 24 | static inline double distanceBetween(MVector v1, MVector v2); 25 | static inline double dotProduct(MVector v1, MVector v2); 26 | static inline double length(MVector v1, MVector v2); 27 | 28 | public: 29 | static MTypeId NODE_ID; 30 | static MString NODE_NAME; 31 | 32 | static MObject inputVector1Attr; 33 | static MObject inputVector2Attr; 34 | static MObject operationAttr; 35 | 36 | static MObject outputAttr; 37 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayUnaryOpNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorArrayUnaryOp node 8 | This node performs unary operations on an array of vectors. 9 | 10 | inputVector (iv) vectorArray 11 | Array of vectors. 12 | 13 | operation (op) enum 14 | Specifies the unary operation to perform. 15 | 16 | No Operation (0) returns the input vectors. 17 | Normalize (1) attempts to return the normalized input vectors. 18 | Invert (2) returns the vectors opposite the input vectors. 19 | 20 | outputVector (ov) vectorArray 21 | Array of vectors calculated by this node. 22 | */ 23 | 24 | #include "../nodeData.h" 25 | #include "vectorArrayUnaryOpNode.h" 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | 43 | const short NORMALIZE = 1; 44 | const short INVERT = 2; 45 | 46 | 47 | MObject VectorArrayUnaryOpNode::inputVectorAttr; 48 | MObject VectorArrayUnaryOpNode::operationAttr; 49 | 50 | MObject VectorArrayUnaryOpNode::outputVectorAttr; 51 | 52 | 53 | void* VectorArrayUnaryOpNode::creator() 54 | { 55 | return new VectorArrayUnaryOpNode(); 56 | } 57 | 58 | 59 | MStatus VectorArrayUnaryOpNode::initialize() 60 | { 61 | MStatus status; 62 | 63 | MFnEnumAttribute E; 64 | MFnTypedAttribute T; 65 | 66 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 67 | 68 | operationAttr = E.create("operation", "op", 1, &status); 69 | E.setChannelBox(true); 70 | E.setKeyable(true); 71 | E.addField("No Operation", 0); 72 | E.addField("Normalize", NORMALIZE); 73 | E.addField("Invert", INVERT); 74 | 75 | addAttribute(inputVectorAttr); 76 | addAttribute(operationAttr); 77 | 78 | outputVectorAttr = T.create("outputVector", "ov", MFnData::kVectorArray, MObject::kNullObj, &status); 79 | T.setStorable(false); 80 | 81 | addAttribute(outputVectorAttr); 82 | 83 | attributeAffects(inputVectorAttr, outputVectorAttr); 84 | attributeAffects(operationAttr, outputVectorAttr); 85 | 86 | return MStatus::kSuccess; 87 | } 88 | 89 | 90 | MStatus VectorArrayUnaryOpNode::compute(const MPlug& plug, MDataBlock& data) 91 | { 92 | MStatus status; 93 | 94 | if (plug != outputVectorAttr) 95 | { 96 | return MStatus::kInvalidParameter; 97 | } 98 | 99 | short operation = data.inputValue(operationAttr).asShort(); 100 | 101 | MDataHandle inputHandle = data.inputValue(inputVectorAttr); 102 | 103 | std::vector values = getMayaArray(inputHandle); 104 | 105 | if (operation == NORMALIZE) 106 | { 107 | for (size_t i = 0; i < values.size(); i++) 108 | { 109 | values[i].normalize(); 110 | } 111 | } else if (operation == INVERT) { 112 | for (size_t i = 0; i < values.size(); i++) 113 | { 114 | values[i] *= -1.0; 115 | } 116 | } 117 | 118 | MDataHandle outputHandle = data.outputValue(outputVectorAttr); 119 | setMayaArray(outputHandle, values); 120 | 121 | return MStatus::kSuccess; 122 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorArrayUnaryOpNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class VectorArrayUnaryOpNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputVectorAttr; 26 | static MObject operationAttr; 27 | 28 | static MObject outputVectorAttr; 29 | }; -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorToPointArrayNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | /** 7 | vectorToPointArray node 8 | This node converts vectors to points. 9 | 10 | inputVector (iv1) vectorArray 11 | Array of vectors. 12 | 13 | outputPoint (op) pointArray 14 | Array of points. 15 | Array of vectors calculated by this node. 16 | 17 | */ 18 | 19 | #include "../nodeData.h" 20 | #include "vectorToPointArrayNode.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | MObject VectorToPointArrayNode::inputVectorAttr; 41 | 42 | MObject VectorToPointArrayNode::outputPointAttr; 43 | 44 | 45 | void* VectorToPointArrayNode::creator() 46 | { 47 | return new VectorToPointArrayNode(); 48 | } 49 | 50 | 51 | MStatus VectorToPointArrayNode::initialize() 52 | { 53 | MStatus status; 54 | 55 | MFnTypedAttribute T; 56 | 57 | inputVectorAttr = T.create("inputVector", "iv", MFnData::kVectorArray, MObject::kNullObj, &status); 58 | 59 | addAttribute(inputVectorAttr); 60 | 61 | outputPointAttr = T.create("outputPoint", "op", MFnData::kPointArray, MObject::kNullObj, &status); 62 | T.setStorable(false); 63 | 64 | addAttribute(outputPointAttr); 65 | 66 | attributeAffects(inputVectorAttr, outputPointAttr); 67 | 68 | return MStatus::kSuccess; 69 | } 70 | 71 | 72 | MStatus VectorToPointArrayNode::compute(const MPlug& plug, MDataBlock& data) 73 | { 74 | MStatus status; 75 | 76 | if (plug != outputPointAttr) 77 | { 78 | return MStatus::kInvalidParameter; 79 | } 80 | 81 | MDataHandle inputHandle = data.inputValue(inputVectorAttr); 82 | MDataHandle outputHandle = data.outputValue(outputPointAttr); 83 | 84 | std::vector input = getMayaArray(inputHandle); 85 | size_t numberOfValues = input.size(); 86 | std::vector output(numberOfValues); 87 | 88 | for (size_t i = 0; i < numberOfValues; i++) 89 | { 90 | output[i] = MPoint(input[i]); 91 | } 92 | 93 | setMayaArray(outputHandle, output); 94 | 95 | return MStatus::kSuccess; 96 | } -------------------------------------------------------------------------------- /src/nodes/vectorNodes/vectorToPointArrayNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2017 Ryan Porter 3 | You may use, distribute, or modify this code under the terms of the MIT license. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class VectorToPointArrayNode : public MPxNode 15 | { 16 | public: 17 | virtual MStatus compute(const MPlug& plug, MDataBlock& data); 18 | static void* creator(); 19 | static MStatus initialize(); 20 | 21 | public: 22 | static MTypeId NODE_ID; 23 | static MString NODE_NAME; 24 | 25 | static MObject inputVectorAttr; 26 | 27 | static MObject outputPointAttr; 28 | }; --------------------------------------------------------------------------------