# Maya C++ API Programming Tips

#### **How to get the value of the attribute at the specified time**

```cpp
int frame = 101;
MPlug plg( thisMObject(), "abc" );
MDGContext ctx( MTime( frame, MTime.uiUnit() ) );
double value = 0.0;
plg.getValue( value, ctx );
```

**How to get the data block outside compute() member function**

```cpp
MDataBlock block = forceCache();
```

**How to get playback time interval**

```cpp
const double dt = AnimControl::playbackBy();
```

**How to update DG node every frame without the input connection from time1**

```cpp
class MyNode{
private:
  MCallbackId timeChangeCallbackId;
public:
  void addedToModelCB();
  void removedFromModelCB();
  void update();
  ...
};
 
MyNode::MyNode{
  ...
  timeChangeCallbackId = 0;
  ...
}
 
static void TimeChangeCallback( MTime& time, void* clientData ){
  reinterpret_cast<ZShape*>(clientData)->update();
}
 
static void NodeAddedToModel( MObject& nodeObj, void* clientData ){
  MFnDependencyNode nodeFn( nodeObj );
 
  MyNode* nodePtr = (MyNode*)nodeFn.userNode();
  if( !nodePtr ) { return; }
 
  nodePtr->addedToModelCB();
}
 
static void NodeRemovedFromModel( MObject& nodeObj, void* clientData ){
  MFnDependencyNode nodeFn( nodeObj );
 
  MyNode* nodePtr = (MyNode*)nodeFn.userNode();
  if( !nodePtr ) { return; }
 
  nodePtr->removedFromModelCB();
}
 
void MyNode::postConstructor(){
  MModelMessage::addNodeAddedToModelCallback( thisMObject(), NodeAddedToModel );
  MModelMessage::addNodeRemovedFromModelCallback( thisMObject(), NodeRemovedFromModel );
}
 
void MyNode::addedToModelCB(){
  timeChangeCallbackId = MDGMessage::addTimeChangeCallback( TimeChangeCallback, this );
}
 
void MyNode::removedFromModelCB(){
  if( timeChangeCallbackId ){
    MDGMessage::removeCallback( timeChangeCallbackId );
    timeChangeCallbackId = 0;
  }
}
```

**How to handle the multiple outputs of a DG node**

```css
MStatus MyNode::initialize(){
  MFnNumericAttribute nAttr;
 
  outputsObj = nAttr.create( "outputs", "outputs", MFnNumericData.kFloat, 0.f );
  nAttr.setArray( true );
  addAttribute( outputsObj );
  ...
}
 
MStatus MyNode::compute( const MPlug& plug, MDataBlock& data ){
  if( plug != outputsObj ) { return MS::kUnknownParameter; }
 
  MArrayDataHandle outputsHnd = data.outputArrayValue( outputsObj );
 
  const int nOutputs = (int)outputsHnd.elementCount();
 
  for( int i=0; i<100; ++i ){
    outputsHnd.jumpToElement( i );
    outputsHnd.outputValue().set( i );
  }
 
  outputsHnd.setAllClean();
  return MS::kSuccess;
}
```

**How to capture the current viewport as an image file**

```cpp
MImage image;
M3dView view = M3dView::active3dView();
view.readColorBuffer( image, true );
image.writeToFile( "snapshot.jpg", "jpg" );

```

**How to save the current frame buffer to a JPG file**

```cpp
GLint viewport[4];
glGetIntegerv( GL_VIEWPORT, viewport );
 
int width = viewport[2];
int height = viewport[3];
int depth = 4;
 
unsigned char* pixels = new unsigned int[width*height*depth];
 
glReadBuffer( GL_FRONT );
glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
 
MImage image;
image.setPixels( pixels, width, height );
image.writeToFile( "snapshot.jopg", "jpg" );
 
delete[] pixels;
```

**How to set the names of a custom DG node and its parent node**

```cpp
void MyNode::postConstructor()
{
  MPxNode::postConstructor();
 
  MObject thisMObj = thisMObject();
  MFnDependencyNode nodeFn;
  nodeFn.setObject( thisMObj );
  nodeFn.setName( "MyNodeShape#" );
}
```

**How to compile my source code conditionally according to the Maya API version**

```cpp
#if MAYA_API_VERSION == 201300
...
#elif MAYA_API_VERSION == 201400
...
#elif MAYA_API_VERSION == 201500
...
#endif
```

**How to get the current Maya version**

```cpp
MString mayaVer = MGlobal::mayaVersion();
int apiVer = MGlobal::apiVersion();
```

**How to avoid the conflict with Cuda**

```cpp
...
#define short2 MAYA_short2
#define short3 MAYA_short3
#define long2 MAYA_long2
#define long3 MAYA_long3
#define int2 MAYA_int2
#define int3 MAYA_int3
#define float2 MAYA_float2
#define float3 MAYA_float3
#define double2 MAYA_double2
#define double3 MAYA_double3
#define double4 MAYA_double4
 
#include &amp;lt;cuda.h&amp;gt;
...
```

**How to set the MFloatPoint from a MPoint**

```cpp
MPoint dp; // double type
MFloatPoint fp; // float type
fp.setCast( dp );
```

**How to get the pixel values of an image**

```cpp
MImage img;
img.readFromFile( "filePathName" ); // load from a file
 
int w=0, h=0; // image width, height
img.getSize( w, h );
int d = img.depth(); // image depth
unsigned char* c = (unsigned char*)NULL;
 
if( img.pixelType() == MImage::kByte ){
  c = img.pixels();
}
 
for( int j=0; j&amp;lt;h; ++j ){
  for( int i=0; i&amp;lt;w; ++i ){
    int idx = d*(i+j*w);
    unsigned char pixelVal[4]; // RGB(d=3) or RGBA(d=4)
 
    for( int k=0; k&amp;lt;d; ++k ){
      pixelVal[k] = c[idx++];
    }
 
    ...
  }
}
```

**How to get the DAG path from a node name**

```cpp
MString nodeName( "nodeName" );
MDagPath dagPath;
MSelectionList sList;
if( MGlobal::getSelectionListByName( nodeName, sList ) ){
  sList.getDagPath( 0, dagPath );
}
```

**How to get the DG node object from a node name**

```cpp
MString nodeName( "nodeName" );
MObject nodeObj;
MSelectionList sList;
if( MGLobal::getSelectionListByName( nodeName, sList ) ){
  sList.getDependNode( 0, nodeObj );
}
```

**How to get the DAG path from a DAG node object**

```cpp
MObject dagNodeObj = ...;
MDagPath dagPath;
MFnDagNode dagFn( dagNodeObj );
dagFn.getPath( dagPath );
```

**How to get the node name from a node object**

```cpp
MObject nodeObj = ...;
MString nodeName;
 
if( nodeObj.hasFn( MFn::kDagNode ) ) {
  MFnDagNode dagNodeFn( nodeObj );
  nodeName = dagNode.fullPathName();
} else if( nodeObj.hasFn( MFn::kDependencyNode ) ) {
  MFnDependencyNode dgNodeFn( nodeObj );
  nodeName = dgNodeFn.name();
}
```

**How to get the parent DAG node object**

```cpp
MObject parentDagNodeObj;
MFnDagNode dagFn( thisMObject() );
MObject obj = dagFn.parent( 0 );
if( !obj.isNull() ){
  parentDagNodeObj = obj;
}
```

**How to get the shape node DAG path from a transform DAG path**

```cpp
MDagPath xformDagPath = ...
MDagPath shapeDagPath = xformDagPath;
shapeDagPath.extendToShape();
```

**How to get the DAG paths of selected mesh shape nodes**

```cpp
MDagPathArray dagPaths;
 
MSelectionList sList;
MGlobal::getActiveSelectionList( sList );
 
MItSelectionList itr( sList, MFn::kMesh );
for( ; !itr.isDone(); itr.next() ){
  MDagPath dagPath;
  itr.getDagPath( dagPath );
  MFnDagNode dagFn( dagPath );
  
  if( dagFn.isIntermediateObject() ) { continue; }
  
  dagPaths.append( dagPath );
}
```

**How to get the all of NURBS curve node objects in the current scene**

```cpp
MObjectArray curveObjs;
MItDag itr( MItDag::kDepthFirst, MFn::kNurbsCurve );
for( ; !itr.isDone(); itr.next() ){
  curveObjs.append( itr.item() );
}
```

**How to get the list of a selected mesh polygons**

```cpp
MIntArray selectedPolygonList;
 
MSelectionList sList;
MGlobal::getActiveSelectionList( sList );
MItSelectionList sItr( sList, MFn::kMeshPolygonComponent );
 
MDagPath dagPath;
MObject componentObj;
sItr.getDagPath( dagPath, componentObj );
 
MFnSingleIndexedComponent sCompFn( componentObj );
sCompFn.getElements( selectedPolygonList );
```

**How to get the all of fields in the current scene**

```cpp
MItDag itr( MItDag::kDepthFirst, MFn::kField );
for( ; !itr.isDone(); itr.next() ){
  MFnField fieldFn( itr.item() );
  ...
}
```

**How to get the local transformation matrix of the current shape node**

```cpp
MObject thisShapeNodeObj = thisMObject();
MFnDagNode thisShapeNodeFn( thisShapeNodeObj );
MObject parentXFormNodeObj = thisShapeNodeFn.parent( 0 );
MFnDagNode parentXFormNodeFn( parentXFormNodeObj );
MMatrix xformMatrix = parentXFormNodeFn.transformationMatrix();
```

**How to get the world matrix of the current shape node**

```cpp
MObject thisShapeNodeObj = thisMObject();
MFnDagNode thisShapeNodeFn( thisShapeNodeObj );
MObject parentXFormNodeObj = thisShapeNodeFn.parent( 0 );
MFnDependencyNode parentXFormNodeFn( parentXFormNodeObj );
MObject worldMatrixObj = parentXFormNodeFn.attribute( "worldMatrix" );
MPlug worldMatrixPlg( parentXFormNodeObj, worldMatrixObj );
worldMatrixPlg = worldMatrixPlg.elementByLogicalIndex( 0 );
worldMatrixPlg.getValue( worldMatrixObj );
MFnMatrixData worldMatrixData( worldMatrixObj );
MMatrix worldMatrix = worldMatrixData.matrix();
```

**How to connect the output plug to the parent automatically when a custom locator node is created**

```cpp
class MyLocator{
  ...
  bool connected;
  ...
};
 
MyLocator::MyLocator(){
  connected = false;
}
 
void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( !connected ){
    MObject thisNodeObj = thisMObject();
    MFnDagNode dagFn( thisNodeObj );
    MObject parentNodeObj = dagFn.parent( 0 );
    dagFn.setObject( parentNodeObj );
    MPlug parentPlg = dagFn.findPlug( "plugName" );
    MPlug outputPlg = MPlug( thisNodeObj, outputObj );
    if( !outputPlg.isConnected() ){
      MDGModifier dgMod;
      dgMod.connect( outputPlg, parentPlg );
      dgMod.doIt();
      connected = true;
    }
  }
  ...
}
```

**How to make a custom locator node un-selectable**

```cpp
void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( view.selectMode() ) { return; }
  ...
}
```

**How to detect which input attribute is changed**

```cpp
MStatus MyCustomNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data ){
  if( plug != outputObj ) { return MS::kUnknownParameter; }
 
  bool inputIsChanged = !data.isClean( inputObj );
  float input = data.inputValue( inputObj ).asFloat();
 
  ...
}
```

Note) It doesn’t work when inputObj is array type.

**How to detect whether the current state is batch mode**

```cpp
if( MGlobal::mayaState() == MGlobal::kBatch ){
  ...
}
```

**How to detect whether the current viewport is Viewport 2.0**

```cpp
M3dView view = M3dView::active3dView();
if( view.getRendererName() == M3dView::kViewport2Renderer ){
  ...
}
```

**How not to draw a custom locator node while mouse interactions (>=2015)**

```cpp
void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( MHWRender::MFrameContext::inUserInteraction() 
    || MHWRender::MFrameContext::userChangingViewContext() )
  {
    ...
  }
}
```

**How to draw a text in draw() of a custom locator node**

```cpp
void MyLocator::draw( M3dView&amp;amp; view, ...){
  ...
  view.beginGL();
  view.drawText( MString("text"), MPoint(0,0,0), M3dView::kLeft );
  view.endGL();
  ...
}
```

**How to copy the input mesh to the output mesh in compute() of a custom node**

```cpp
MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
  MFnMesh newMeshFn;
  MFnMeshData dataCreator;
  MObject newMeshData = dataCreator.create();
  newMeshFn.copy( data.inputValue( inMeshObj ).asMeshTransformed(), newMeshData );
  data.outputValue( outMeshObj ).set( newMeshData );
  ...
}
```

**How to deform the input mesh in compute() of a custom node like such a deformer**

```cpp
MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
   
  MPointArray deformedPoints = ...
 
  MFnMesh newMeshFn;
  MFnMeshData dataCreator;
  MObject newMeshData = dataCreator.create();
  newMeshFn.copy( data.inputValue( inMeshObj ).asMeshTransformed(), newMeshData );
  newMeshFn.setPoints( deformedPoints );
  data.outputValue( outMeshObj ).set( newMeshData );
 
  ...
}
```

**How to handle array attribute**

```cpp
class MyNode
{
  ...
  MObject valuesObj;
  ...
  MDoubleArray values;
};
 
MObject MyNode::valuesObj;
 
MStatus MyNode::initialize(){
  ...
  valuesObj = tAttr.create( "values", "values", MFnData::kDoubleArray );
  ...
}
 
MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
 
  // get
  MFnDoubleArrayData arrayData;
  MObject dataObj = data.inputValue( valuesObj ).data();
  arrayData.setObject( dataObj );
 
  int numValues = 100;
 
  // set
  if( arrayData.length() != numValues ){
    MDoubleArray array( numValues, 0.0 );
    dataObj = arrayData.create( array );
    data.outputValue( valuesObj ).set( dataObj );
  }
 
  ...
}
 
// MEL
makePaintable -at doubleArray MyNode values;
setAttr MyNode1.values -type doubleArray 3 1.0 2.0 3.0;
```

**How to get the value of an attribute anywhere in a custom node**

```cpp
MObject thisNodeObj = thisMObject();
 
double v0 = MPlug( thisNodeObj, attr0Obj ).asDouble();
float v1 = MPlug( thisNodeObj, attr1Obj ).asFloat();
int v2 = MPlug( thisNodeObj, attr2Obj ).asInt();
short v3 = MPlug( thisNodeObj, attr3Obj ).asShort();
bool v4 = MPlug( thisNodeObj, attr4Obj ).asBool();
MTime v5 = MPlug( thisNodeObj, attr5Obj ).asMTime();
char v6 = MPlug( thisNodeObj, attr6Obj ).asChar();
MString v7 = MPlug( thisNodeObj, attr7Obj ).asString();
 
MColor c;
MPlug plg( thisNodeObj, attrObj );
plg.child(0).getValue( c.r );
plg.child(1).getValue( c.g );
plg.child(2).getValue( c.b );
```

**How to get the pointer of the other connected node**

```cpp
OtherNodeClassName* otherNodePtr = (OtherNodeClassName*)NULL;
 
MObject thisNodeObj = thisMObject();
MFnDependencyNode thisNodeFn( thisNodeObj );
MPlug plg = thisNodeFn.findPlug( inputAttrObj );
 
MPlugArray connectedPlgs;
if( plg.isConnected() ){
  if( plg.isSource() ) {
    plg.connectedTo( connectedPlgs, false, true );
  } else if( plg.isDestination() ) {
    plg.connectedTo( connectedPlgs, true, false );
  }
 
  MFnDependencyNode otherNodeFn( connectedPlgs[0].node() );
 
  if( otherNodeFn.typeId() == OtherNodeClassName::id )  {
    otherNodePtr = (OtherNodeClassName*)otherNodeFn.userNode();
  }
}
```

**How to restore GL states in draw() of a custom locator node**

```cpp
void MyLocator::draw( M3dView&amp;amp; view, ...)
{
  float lastPointSize=0; glGetFloatv( GL_POINT_SIZE, &amp;amp;lastPointSize );
  float lastLineWidth=0; glGetFloatv( GL_LINE_WIDTH, &amp;amp;lastLineWidth );
  bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
 
  if( lightingWasOn ) { glDisable( GL_LIGHTING ); }
 
  view.beginGL();
  ...
  view.endGL();
 
  glPointSize( lastPointSize );
  glLineWidth( lastLineWidth );
  if( lightingWasOn ) { glEnable( GL_LIGHTING ); }
}
```

**How to call compute() of a custom locator without output connection**

```cpp
void MyLocator::draw( M3dView&amp;amp; view, ...)
{
  MObject thisNodeObj = thisMObject();
  MObject obj = MPlug( thisNodeObj, outputObj ).asMObject();
 
  ...
}
```

**How to get the normal vector of a current camera**

```cpp
M3dView view = M3dView::active3dView();
MDagPath camDagPath;
view.getCamera( camDagPath );
MVector cameraZ = MVector(0,0,1) * camDagPath.inclusiveMatrix();
```

**How to create attributes in initialize() of a custom node**

```cpp
MStatus MyLocator::initialize()
{
  MRampAttribute rAttr;
  MFnEnumAttribute eAttr;
  MFnUnitAttribute uAttr;
  MFnTypedAttribute tAttr;
  MFnNumericAttribute nAttr;
  MFnMessageAttribute gAttr;
 
  timeObj = uAttr.create( "time", "time", MFnUnitAttribute::kTime, 0.0 );
  addAttribute( timeObj );
 
  angleObj = uAttr.create( "angle", "angle", MFnUnitAttribute::kAngle, 0.0 );
  addAttribute( angleObj );
 
  boolObj = nAttr.create( "bool", "bool", MFnNumericData::kBoolean, false );
  addAttribute( boolObj );
 
  intObj = nAttr.create( "int", "int", MFnNumericData::kInt, 0 );
  addAttribute( intObj );
 
  floatObj = nAttr.create( "float", "float", MFnNumericData::kFloat, 0.f );
  addAttribute( floatObj );
 
  doubleObj = nAttr.create( "double", "double", MFnNumericData::kDouble, 0.0 );
  addAttribute( doubleObj );
 
  int2Obj = nAttr.create( "int2", "int2", MFnNumericData::k2Int, 0 );
  addAttribute( int2Obj );
 
  int3Obj = nAttr.create( "int3", "int3", MFnNumericData::k3Int, 0 );
  addAttribute( int3Obj );
 
  float2Obj = nAttr.create( "float2", "float2", MFnNumericData::k2Float, 0.f );
  addAttribute( float2Obj );
 
  float3Obj = nAttr.create( "float3", "float3", MFnNumericData::k3Float, 0.f );
  addAttribute( float3Obj );
 
  double2Obj = nAttr.create( "double2", "double2", MFnNumericData::k2Double, 0.0 );
  addAttribute( double2Obj );
 
  double3Obj = nAttr.create( "double3", "double3", MFnNumericData::k3Double, 0.0 );
  addAttribute( double3Obj );
 
  stringObj = tAttr.create( "string", "string", MFnData::kString, "abc" );
  addAttribute( stringObj );
 
  matrixObj = tAttr.create( "matrix", "matrix", MFnMatrixAttribute::kDouble );
  addAttribute( matrixObj );
 
  curveObj = tAttr.create( "curve", "curve", MFnData::kNurbsCurve );
  addAttribute( curveObj );
 
  meshObj = tAttr.create( "mesh", "mesh", MFnData::kMesh );
  addAttribute( meshObj );
 
  iaObj = tAttr.create( "iArray", "iArray", MFnData::kIntArray );
  addAttribute( iaObj );
 
  faObj = tAttr.create( "fArray", "fArray", MFnData::kFloatArray );
  addAttribute( faObj );
 
  daObj = tAttr.create( "dArray", "dArray", MFnData::kDoubleArray );
  addAttribute( daObj );
 
  paObj = tAttr.create( "pArray", "pArray", MFnData::kPointArray );
  addAttribute( paObj );
 
  vaObj = tAttr.create( "vArray", "vArray", MFnData::kVectorArray );
  addAttribute( vaObj );
 
  saObj = tAttr.create( "sArray", "sArray", MFnData::kStringArray );
  addAttribute( saObj );
 
  msgObj = gAttr.create( "message", "message" );
  addAttribute( msgObj );
 
  clrObj = nAttr.createColor( "color", "color" );
  addAttribute( clrObj );
 
  pntObj = nAttr.createPoint( "point", "point" );  
  addAttribute( pntObj );
 
  enumObj = eAttr.create( "enum", "enum" 0 );
  eAttr.addField( "A", 0 );
  eAttr.addField( "B", 0 );
  addAttribute( enumObj );
 
  crvRmpObj = rAttr.createCurveRampAttr( "crvRamp", "crvRamp" );
  addAttribute( crvRmpObj );
 
  clrRmpObj = rAttr.createColorRampAttr( "clrRamp", "clrRamp" );
  addAttribute( clrRmpObj );
 
  fileNameObj = tAttr.create( "fileName", "fileName", MFnData::kString );
  tAttr.setUsedAsFilename( true );
  addAttribute( fileNameObj );
 
  ...
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://stephanosterburg.gitbook.io/scrapbook/coding/cpp/maya-c++-api-programming-tips.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
