Skip to content

Instantly share code, notes, and snippets.

@yamahigashi
Created June 7, 2016 02:32
Show Gist options
  • Save yamahigashi/392620e0b2ed6cdbab7d579450d1f8d8 to your computer and use it in GitHub Desktop.
Save yamahigashi/392620e0b2ed6cdbab7d579450d1f8d8 to your computer and use it in GitHub Desktop.
# in maya
# -*- coding: utf-8 -*-
import re
import json
import maya.mel as mel
from maya.api import OpenMaya as OpenMaya2
import FabricEngine.Core as fe
import FabricEngine.CAPI as capi
def convert_safe_json(string):
def _maketrans(m):
try:
return {
"\\'": '',
'\\"': '',
'\t': ' ',
'\n': '',
'\r': '',
'\\n': '',
'\\r': ''
}[m.group(1)]
except KeyError:
return ''
string = re.sub(r'''(\n|\r|\t)''', _maketrans, string)
string = re.sub(r'''[^\\](\\"|\\')''', _maketrans, string)
string = re.sub(r'''[^\\](\\"|\\')''', _maketrans, string)
string = re.sub(r'''(\\n|\\r)''', _maketrans, string)
# j = json.loads(string)
return string
def json_from_dfgexec(dfgexec):
j = dfgexec.exportJSON()
j = convert_safe_json(j)
return json.loads(j)
class CanvasPortInfo(object):
'''
type: 0 DFGPortType_In
type: 1 DFGPortType_IO
type: 2 DFGPortType_Out
'''
def __init__(self, container, index):
self.container = container
self.name = container.getExecPortName(index)
self.portType = container.getExecPortType(index)
self.hasSrc
def __str__(self):
return " " * (self.container.depth + 1) + self.name
@property
def isConnected(self):
if "exec" in self.name:
return False
def _inner(x, t, c=0):
try:
if t in [0, 1]: # In and IO
return x.hasSrcPorts(self.path)
else:
return x.hasDstPorts(self.path)
except Exception as e:
print e
if c > 10:
raise
print "fallback" * c, x.isPreset()
if x.parent:
_inner(x.parent, t, c + 1)
else:
print "gave up", self.path
return False
_inner(self.container, self.portType)
@property
def hasSrc(self):
if (self.container.parent and self.container.parent.isPreset):
return True
if self.portType == 2:
return True
return self.isConnected
@property
def path(self):
if self.container.path:
return "{}.{}".format(self.container.path, self.name)
else:
return self.name
class CanvasDFGExe(capi.DFGExec):
def __init__(self, dfg, parent=None, name=None):
super(CanvasDFGExe, self).__init__(dfg)
if name:
self.name = name
else:
self.name = self.getTitle()
self.parent = parent
self.depth = self.parent.depth + 1 if self.parent else 0
self.subNodes = self._searchSubNodes() or []
self.ports = self._searchPorts() or []
@property
def execType(self):
''' return Exec type
0: graph
1: func
'''
return self.getType()
@property
def nodeType(self):
'''
DFGNodeType_Inst
DFGNodeType_Get
DFGNodeType_Set
DFGNodeType_Var
DFGNodeType_User
'''
if not self.parent:
return 0
return self.parent.getNodeType(self.name)
@property
def presetName(self):
return self.getPresetName()
@property
def presetPath(self):
if not self.parent:
return ""
# FIXME:
ppath = self.parent.dfgexec.getNodeDesc(self.name)
ppath = json.loads(ppath).get('presetPath', self.presetName)
return ppath
@property
def path(self):
if self.parent and len(self.parent.name) > 0:
res = "{}.{}".format(self.parent.path, self.name)
else:
# node in top level graph
res = self.name
return res
@property
def isGraph(self):
return self.execType == 0
def _searchSubNodes(self):
if not self.isGraph:
return []
kids = []
for i in xrange(self.getNodeCount()):
sub_name = self.getNodeName(i)
sub_type = self.getNodeType(sub_name)
if _ignoreNodeType(sub_type):
continue
sub_exec = CanvasDFGExe(self.getSubExec(sub_name), parent=self, name=sub_name)
kids.append(sub_exec)
return kids
def _searchPorts(self):
if _ignoreNodeType(self.nodeType):
return []
ports = []
for i in xrange(self.getExecPortCount()):
port = CanvasPortInfo(self, i)
# print port
ports.append(port)
return ports
def _ignoreNodeType(t):
return t not in [0, 4]
# -------------------------------------------------------------------------- #
def get_dfgexe(maya_node_name):
ctxt_id = mel.eval('FabricCanvasGetContextID;')
bind_id = mel.eval('FabricCanvasGetBindingID -node "{}";'.format(maya_node_name))
# capi_client = capi.FEC_ClientBind(None, None, ctxt_id) # dones not use
core_client = fe.createClient({'contextID': ctxt_id})
host = core_client.DFG.host
dfgbinding = host.getBindingForID(bind_id)
dfgexec = dfgbinding.getExec()
return dfgexec
def dump(node):
for kid in node.subNodes:
print " " * kid.depth, ">", kid.name
for p in node.ports:
print " " * (kid.depth + 1), p.name, p.hasSrc
dump(kid)
def collapse(node):
all_nodes = [node]
def __inner__(node):
for kid in node.subNodes:
all_nodes.append(kid)
__inner__(kid)
__inner__(node)
return all_nodes
def extract_by_preset_name(top_node, preset_name):
all = collapse(top_node)
return [x for x in all if preset_name == x.presetName]
# ********* prepare **********************
# access canvas dfgexec object
# :ref: http://docs.fabric-engine.com/FabricEngine/2.2.0/HTML/CAPIProgrammingGuide/canvas.html
# canvas_node_name = "canvasNode1"
canvas_node_name = cmds.ls(sl=True)[0]
dfgexec = get_dfgexe(canvas_node_name)
# ********* A ********************
# loaded_json = json_from_dfgexec(dfgexec)
# todo: parse this json
# ********* B ********************
# object oriented way for parse node hierarchy down
p = CanvasDFGExe(dfgexec)
# dump(p)
x = extract_by_preset_name(p, 'Cache')
for y in x:
print y.path
print 'done!! ----------------------------'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment