Part 3 – Plugins that take Input and give Output.

Today I’m going to start backwards.

Output:

To set a plugin to give Output is really, really easy. All we need to do is change the line at the end of the plugin’s “_Execute( )” function from:

return true

to

return [Whatever we want]

We can return a string, an object, a list, a list of objects and pretty much every other python data structure we could ever want.

The reason I may want a plugin to give output is if I have a scenario where I need to do something, and some of the code is already in the plugin but the same plugin is also used by other tools so I can’t change the actual way the plugin works or other tools may break.

So for this example what I want to do is to select all the polymeshes in my scene except any called “cube”. Now I already have a plugin that selects all the polymeshes in my scene (called SelectAll_PolyMeshes). So all I need to do is to get that list and see if there are any objects called “cube” in it and if so, remove them from the selection. Simple 🙂

First I need to set my SelectAll_PolyMeshes command to output (return)  the list of polymeshes so the plugin looks like:

# SelectAll_PolyMeshesPlugin
# Initial code generated by Softimage SDK Wizard
# Executed Thu Jul 19 18:18:51 UTC+0200 2012 by jared.glass
#
# Tip: To add a command to this plug-in, right-click in the
# script editor and choose Tools > Add Command.
import win32com.client
from win32com.client import constants

null = None
false = 0
true = 1

def XSILoadPlugin( in_reg ):
    in_reg.Author = "jared.glass"
    in_reg.Name = "SelectAll_PolyMeshesPlugin"
    in_reg.Major = 1
    in_reg.Minor = 0

    in_reg.RegisterCommand("SelectAll_PolyMeshes","SelectAll_PolyMeshes")
    #RegistrationInsertionPoint - do not remove this line

    return true

def XSIUnloadPlugin( in_reg ):
    strPluginName = in_reg.Name
    Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
    return true

def SelectAll_PolyMeshes_Init( in_ctxt ):
    oCmd = in_ctxt.Source
    oCmd.Description = ""
    oCmd.ReturnValue = true

    return true

def SelectAll_PolyMeshes_Execute( ):

    Application.LogMessage("SelectAll_PolyMeshes_Execute called",constants.siVerbose)

    # Find all the polymeshes in the scene and store them in a python list.
    polymesh_lst = list(Application.ActiveSceneRoot.FindChildren("*", "polymsh"))

    # Create a list to store the meshes names in
    polymeshName_lst= []
    # Loop through the mesh objects and store their names
        for polymesh in polymesh_lst:
            # Add the meshes name to the mesh name list
            polymeshName_lst.append(polymesh.FullName)

    # Join the names in the list into a string and sepperate each name by a comma. eg "sphere, cone, cube"
    polymeshSel_str = ", ".join(polymeshName_lst)

    # Tell Xsi to select the names in the polymeshSel_str
    Application.Selection.SetAsText(polymeshSel_str)

    # The return that we will change
    return true

Now, we want the list of polymesh objects to check for “cube” in the name and then to remove the object from the selection. All we need to do is to change the

return true

right at the end to

return polymesh_lst

After you’ve added that save the “”SelectAll_PolyMeshes” plugin to update it in Xsi.

now if we:

print Application.SelectAll_PolyMeshes()

we should get something that looks like:

# [<COMObject <unknown>>,  <COMObject <unknown>>, <COMObject <unknown>>, <COMObject <unknown>>]

Thats the list of Xsi objects.

From that I can do

polymesh_lst = Application.SelectAll_PolyMeshes()

instead of printing it so I can actually store the data in a list.

From here the rest is cake. So in the end my code looks like this :

    # Get the list of polymeshes from the plugin.
    polymesh_lst = Application.SelectAll_PolyMeshes()
    # Loop through the polymeshes and check the names.
    for polymesh in polymesh_lst:
        # Check if the polymeshe's name is cube
        if polymesh.name == "cube":
            # If it is, remove it from the selection
            Application.Selection.Remove(polymesh)

Input:

(Also called Arguments)

Setting up a plugin to take input is just as easy, it just requires a few more lines of code to be replaced. For this example we’re going to change the “SelectAll_PolyMeshes” Plugin, but in such a way that it won’t change the way it works with any of the other tools that may use it (like the one we just made that removes cube from the selection). This is a lot easier than it sounds. So we’re going to set the plugin to take in part of an objects name, and only if that part of the name is in a PolyMeshe’s name, does the PolyMesh get selected.

So we will be able to call the command Application.SelectAll_PolyMeshes()

like Application.SelectAll_PolyMeshes("part_of_some_object_name")

First thing we need to do is to add a variable to the plugin’s “Init” (The Init is run when the plugin is initially compiled by Xsi – When you launch Xsi or Reload the plugin by Saving it from the Script Editor). This variable will tell Xsi that the plugin takes some input.

So in the “SelectAll_PolyMeshes_Init” we add:

oArgs = oCmd.Arguments
oArgs.Add([Argument Name],constants.siArgumentInput,[Default Value])

I’m going to call the argument “part_of_name” and the default will be None.

This means that if something just calls Application.SelectAll_PolyMeshes(), part_of_name will be set to None and I can tell the plugin to ignore the part of name search and run as it had before my changes.

Next bit is to pass the argument (part_of_name) into the _Execute function. This will allow us to use part_of_name inside the _Execute.

After this I can edit the actual code within the _Execute as I please:

    # Loop through the mesh objects and store their names
    for polymesh in polymesh_lst:
        # If the part_of_name was specified and therefore is not the default None...
        if not part_of_name == None:
            # If the part_of_name is in the object's name...
            if part_of_name in polymesh.Name:
                # Add the meshes name to the mesh name list
                polymeshName_lst.append(polymesh.FullName)
            else:
                # Add the meshes name to the mesh name list
                polymeshName_lst.append(polymesh.FullName)

So my entire plugin looks like:

# SelectAll_PolyMeshesPlugin
# Initial code generated by Softimage SDK Wizard
# Executed Thu Jul 19 18:18:51 UTC+0200 2012 by jared.glass
#
# Tip: To add a command to this plug-in, right-click in the
# script editor and choose Tools > Add Command.
import win32com.client
from win32com.client import constants

null = None
false = 0
true = 1

def XSILoadPlugin( in_reg ):
in_reg.Author = "jared.glass"
in_reg.Name = "SelectAll_PolyMeshesPlugin"
in_reg.Major = 1
in_reg.Minor = 0

in_reg.RegisterCommand("SelectAll_PolyMeshes","SelectAll_PolyMeshes")
#RegistrationInsertionPoint - do not remove this line

return true

def XSIUnloadPlugin( in_reg ):
    strPluginName = in_reg.Name
    Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
    return true

def SelectAll_PolyMeshes_Init( in_ctxt ):
    oCmd = in_ctxt.Source
    oCmd.Description = ""
    oCmd.ReturnValue = true

    oArgs = oCmd.Arguments
    oArgs.Add("part_of_name",constants.siArgumentInput,None)
    return true

def SelectAll_PolyMeshes_Execute( part_of_name ):

    Application.LogMessage("SelectAll_PolyMeshes_Execute called",constants.siVerbose)

    # Find all the polymeshes in the scene and store them in a python list.
    polymesh_lst = list(Application.ActiveSceneRoot.FindChildren("*", "polymsh"))

    # Create a list to store the meshes names in
    polymeshName_lst= []
    # Loop through the mesh objects and store their names
    for polymesh in polymesh_lst:
        # If the part_of_name was specified and therefore is not the default None...
        if not part_of_name == None:
            # If the part_of_name is in the object's name...
            if part_of_name in polymesh.Name:
                # Add the meshes name to the mesh name list
                polymeshName_lst.append(polymesh.FullName)
            else:
                # Add the meshes name to the mesh name list
                polymeshName_lst.append(polymesh.FullName)

    # Join the names in the list into a string and sepperate each name by a comma. eg "sphere, cone, cube"
    polymeshSel_str = ", ".join(polymeshName_lst)

    # Tell Xsi to select the names in the polymeshSel_str
    Application.Selection.SetAsText(polymeshSel_str)

    return polymeshName_lst

And if I want to select ALL the PolyMeshes I run Application.SelectAll_PolyMeshes()

but if I only want to select PolyMeshes with say “sphere” in the name, I run Application.SelectAll_PolyMeshes("sphere"). This sets the part_of_name variable from None to "sphere".

Note:

When creating a plugin you also get the option to add input arguments:

I do use this but I find I end up changing existing plugins that don’t take arguments (or that I want to take even more arguments) much more than I use this tool to create them.

2 thoughts on “Part 3 – Plugins that take Input and give Output.

  1. Pingback: Start Here!!! « Conquering the Code in Softimage Xsi

  2. Pingback: Start Here!!! | Conquering the Code in Softimage Xsi

Leave a comment