""" ## Written And Maintained By: David Bailey ## Contributors: Kristine Middlemiss ## Description: A list of commonly used functions to create scene objects and to simplify and speed ## up tool production. This also signifies a turning point to minimise the duplication ## of code in new tools. ## ## Rules: Definitions: Prefixed with "rs_" ## Global Variables: Prefixed with "g" ## Local Variables: Prefixed with "l" ## Iteration Variables: Prefixed with "i" ## Arguments: Prefixed with "p" ## """ from pyfbsdk import * import os import re import sys import webbrowser import RS.Globals as glo import RS.Config from RS.Utils.Scene.Component import SetProperties from RS.Utils.Scene import Constraint ############################################################################################################### ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ## ## Description: The yellow Rockstar Banner that should be used at the top of EVERY tool ## ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ############################################################################################################### def rs_OnEmailClickCallback(pControl, pEvent): if gCc == None: os.startfile("mailto:" + gEmailTo + "&Subject= "+ gToolName+ "&Body=" +gToolPath) else: os.startfile("mailto:" + gEmailTo + "?CC=" + gCc + "&Subject= "+ gToolName+ "&Body=" +gToolPath) def rs_OnInfoClickCallback(pControl, pEvent): if gWikiLink == None: FBMessageBox("Information", "Sorry, there is no Wiki page for this UI...YET :)", "Ok") else: lNew = 2 webbrowser.open(gWikiLink) def rs_CreateBanner( parentLyt, lToolName, lEmailTo, lToolPath, lCc=None, lWikiLink=None): # HouseKeeping global gToolName gToolName = lToolName global gEmailTo gEmailTo = lEmailTo global gToolPath gToolPath = lToolPath global gCc gCc = lCc global gWikiLink gWikiLink = lWikiLink # Rockstar Logo titlex = FBAddRegionParam(0,FBAttachType.kFBAttachLeft,"") titley = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"") titlew = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) titleh = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) parentLyt.AddRegion("Title","Title", titlex,titley,titlew,titleh) titleImg = FBImageContainer() titleImg.Filename = "{0}\\YellowRockstarLogo_30x30.jpg".format( RS.Config.Script.Path.ToolImages ) parentLyt.SetControl("Title",titleImg) # Spacer spacerx = FBAddRegionParam(30,FBAttachType.kFBAttachLeft,"") spacery = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"") spacerw = FBAddRegionParam(-60,FBAttachType.kFBAttachRight,"") spacerh = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) parentLyt.AddRegion("Spacer","Spacer", spacerx,spacery,spacerw,spacerh) spacerImg = FBImageContainer() spacerImg.Filename = "{0}\\YellowSpacerBanner.jpg".format( RS.Config.Script.Path.ToolImages ) parentLyt.SetControl("Spacer",spacerImg) # Send an email about the tool logo lEmailX = FBAddRegionParam(-60,FBAttachType.kFBAttachRight,"") lEmailY = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"") lEmailW = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) lEmailH = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) parentLyt.AddRegion( "lEmail","lEmail", lEmailX, lEmailY, lEmailW, lEmailH ) lEmailContainer = FBVisualContainer() parentLyt.SetControl( "lEmail", lEmailContainer) lEmailContainer.OnChange.Add(rs_OnEmailClickCallback) lEmailImage = "{0}\\email_icon_yellow.tif".format( RS.Config.Script.Path.ToolImages ) lEmailContainer.Items.append("") lEmailContainer.ItemIconSet(0, lEmailImage) lEmailContainer.ItemWidth = 27 lEmailContainer.ItemHeight = 44 lEmailContainer.ItemWrap = True # Find more information on the wiki about the tool logo lInfoX = FBAddRegionParam(-30,FBAttachType.kFBAttachRight,"") lInfoY = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"") lInfoW = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) lInfoH = FBAddRegionParam(30,FBAttachType.kFBAttachNone,None) parentLyt.AddRegion( "lInfo","lInfo", lInfoX, lInfoY, lInfoW, lInfoH ) lInfoContainer = FBVisualContainer() parentLyt.SetControl( "lInfo", lInfoContainer) lInfoContainer.OnChange.Add(rs_OnInfoClickCallback) lInfoImage = "{0}\\information_icon_yellow.tif".format( RS.Config.Script.Path.ToolImages ) lInfoContainer.Items.append("") lInfoContainer.ItemIconSet(0, lInfoImage) lInfoContainer.ItemWidth = 27 lInfoContainer.ItemHeight = 44 lInfoContainer.ItemWrap = True return parentLyt def rs_CreateFolder(pName, pLocation): """ Creates a folder with a specific name under the given location Arguments: pName (string): name for the folder pLocation (string or FBComponent): location to put folder under, accepts strings and pyfbsdk classes that inherit FBComponent Return: FBFolder """ FBMethodDictionary = { "Actor Faces" : "FBActorFace", "Actors" : "FBActor", "Audio Clips" : "FBAudioClip", "Cameras" : "FBCamera", "Character Extensions": "FBCharacterExtension", "Character Faces": "FBCharacterFace", "Character Poses": "FBCharacterPose", "Characters" : "FBCharacter", "Constraints 1" : "FBConstraintSolver", "Constraints" : "FBConstraintSolver", "Control Rigs" : "FBControlSet", "Lights" : "FBLight", "Materials" : "FBMaterial", "Notes" : "FBNote", "Poses" : "FBPose", "Sets" : "FBSet", "Shaders" : ["FBShaderManager", "CreateShader(ZShader)"], "Takes" : ["FBTake", "CopyTake"], "Textures" : "FBTexture", "VideoClips" : "FBVideoClipImage", "Videos" : "FBVideoClipImage", "FBShader" : ["FBShaderManager", "CreateShader(ZShader)"], "FBTake" : ["FBTake", "CopyTake"], "FBConstraint" : "FBConstraintSolver", "FBConstraintRelation": "FBConstraintSolver" } fbtype = None # Check if the location passed is a class from the pyfbsdk and if it is to # get the name of that class if hasattr(pLocation, "__module__") and pLocation.__module__ == "pyfbsdk": fbtype = FBMethodDictionary.get(pLocation.__name__, pLocation.__name__) if FBMethodDictionary.get(pLocation, None) is None and fbtype is None: return methodList = FBMethodDictionary.get(pLocation, None) or fbtype if not isinstance(methodList, list): methodList = [methodList] method = sys.modules["pyfbsdk"] for eachMethod in methodList: # Regular Expression to extract arguments from methods # It returns a list of all strings between arguments = re.findall("(?<=\()[0-9a-z._ ]+(?=\))", eachMethod, re.I) eachMethod = eachMethod.split("(")[0] method = getattr(method, eachMethod) if eachMethod == methodList[-1] and not arguments: arguments = ["ToBeDeleted"] method = method(*arguments) temporaryModel = method folder = FBFolder(pName, temporaryModel) temporaryModel.FBDelete() return folder ############################################################################################################### ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ## ## Description: Create Folders and Add Component(s) in, if they exist ## ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ############################################################################################################### def rs_CreateFolderAddComponents(pComponent, pComponentStr, name="", excludeByTypes=[]): if not name: name = pComponentStr lFolder = None for folder in RS.Globals.Folders: if folder.Name == name: lFolder = folder break if lFolder == None: lFolder = rs_CreateFolder(name, pComponentStr) for iComp in filter(None, pComponent): if not IsPyfbsdkType(iComp, *excludeByTypes): lFolder.ConnectSrc(iComp) return lFolder ############################################################################################################### ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ## ## Description: Create Constraint Folder and Add Component(s) in, if they exist. Exclude FBCharacter & ## FBCharacterSolver url:bugstar:1264071 ## ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ############################################################################################################### def rs_CreateConstraintFolderAddComponents(pComponent, pComponentStr): lFolder = rs_CreateFolderAddComponents(pComponent, "Constraints", name=pComponentStr, excludeByTypes=[FBCharacterSolver, FBCharacter]) FBSystem().Scene.Evaluate() def IsPyfbsdkType(pComponent, *pyfbsdkTypes): """ Checks if a model/component from motion builder is of a certain type :param pComponent: FBComponent() or any object that inherits FBComponent; object to check type :param pyfbsdkTypes: :return: """ pyfbsdk = sys.modules["pyfbsdk"] result_list = [] for eachType in pyfbsdkTypes: if isinstance(eachType, basestring): eachType = getattr(pyfbsdk, eachType) result_list.append(isinstance(pComponent, eachType)) return True in result_list def CreatePath(name, *points, **kwargs): """ Creates a Path3D object in the scene with keys at the given points :param name: :param points: :return: """ curve = FBModelPath3D(name) curve.Show = True EditPath(curve, *points, **kwargs) return curve def EditPath(curve, *points, **kwargs): plot = kwargs.get("Plot", False) frame = kwargs.get("Frame", FBSystem().LocalTime.GetFrame()) for index, point in enumerate(points): position = FBVector4d(*point) try: # We call PathKeyGet to check if a key already exists # it will error out if it doesn't if curve.PathKeyGet(index): curve.PathKeySet(index, position) except IndexError: curve.Segment_PathKeyAdd(index, position) # Sometimes the first point isn't set # So we set it again if not index: curve.PathKeySet(index, position) if plot: property = curve.PropertyList.Find("Point_{}".format(index)) property.SetAnimated(True) animationNode = curve.PropertyList.Find("Point_{}".format(index)).GetAnimationNode() animationNode.KeyAdd(FBTime(0, 0, 0, frame), [each for each in position]) return curve def CreateConstraint(type, name="", *references, **properties): """ DEPRECATED FUCNTION! Use: from RS.Utils.Scene import Constraint Constraint.CreateConstraint """ constraintTypes = { "Aim" : Constraint.AIM, "Expression" : Constraint.EXPRESSION, "Multi Referential" : Constraint.MULTI_REFERENTIAL, "Parent/Child" : Constraint.PARENT_CHILD, "Path" : Constraint.PATH, "Path Constraint" : Constraint.PATH, "Position" : Constraint.POSITION, "Range" : Constraint.RANGE, "Relation" : Constraint.RELATION, "Rigid Body" : Constraint.RIGID_BODY, "3 Points" : Constraint.THREE_POINT, "Rotation" : Constraint.ROTATION, "Scale" : Constraint.SCALE, "Mapping" : Constraint.MAPPING, "Chain IK" : Constraint.CHAIN_IK} constraint = Constraint.CreateConstraint(constraintTypes[type]) if name: constraint.Name = name [constraint.ReferenceAdd(index, component) for index, component in enumerate(references) if component != None] SetProperties(constraint, **properties) return constraint """ Legacy Code""" ############################################################################################################### ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ## ## Description: Create Null Object and name it. This Null object was introduced to the character asset setup ## to keep the scenes clean. ## Requested by Animation ## ##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ############################################################################################################### def rs_CreateNullElement(pName, pXpos, pYpos, pZpos): lNull = FBModelNull(pName) lNull.Show = False lNull.Translation = FBVector3d(pXpos, pYpos, pZpos) return lNull