Scripting with Python
January 2024
The Python integration into SFM is a work in progress and experimental. The main purpose in the past was enabling rigging scripts for models. At the moment we support on Windows the version 2.7.5 compiled with Visual Studio 2010. The implementation can change at any time.
The best way to learn which modules are available, is the execution of the following script in the Script Editor:
import sys lst = sys.modules.keys() print filter(lambda x: 'sfm' in x,lst)
This prints at the time: ['sfmConsole', 'sfmApp', 'sfm', 'sfmUtils', 'sfmClipEditor']
. The ‘sfm’ object is special, because it is only available during the execution of the script in the Animation Set Editor though the context menu and the ‘Rig’ menu and other context menus. Additionally, among others, the module ‘vs’ is available. The data layer in the SFM is wrapped with SWIG, and the module ‘vs’ gives access.
To learn more about the functionality of a module the python dir command can be used:
print ( dir ( sfmClipEditor ) )
This returns: ['GetSelectedClips', 'GetSelectedShots', '__doc__', '__name__', '__package__']
Also PySide is available, which gives Python bindings for Qt. Qt is the cross-platform application framework used to create most of the user interface of the SFM. That should enable the script writer to create visual user interfaces.
The following script removes any color on clips in the current document and pops up a message box telling the user how many clips were modified:
import vs
import sfmApp
import sfmClipEditor
from PySide import QtGui
if sfmApp.HasDocument():
shots = sfmClipEditor.GetSelectedShots()
nCounter = 0
for shot in shots:
shot.color = vs.Color( 0, 0, 0, 0 )
nCounter += 1
message = "Removed color in %d shots" % nCounter
QtGui.QMessageBox.information( None, " ", message )
else:
QtGui.QMessageBox.information( None, " ", "No current document..." )
This script and some other example scripts can be found in Main Menu > Scripts > Examples and ‘Open in Explorer’ opens the file location of these scripts. You can add more scripts to the menu in storing python files there. The filename will be used to create the menu entry, where underscores will be converted into spaces in the name.
At startup the script at <yourmod>/scripts/sfm/sfm_init.py and platform/scripts/sfm/sfm_init.py get executed. This should be used really carefully.
During runtime the sfmApp object emits the following signals, which are unfortunately not discoverable:
InteractiveRenderFinished, LevelLoadingStarted, LevelLoadingFinished, DocumentLoaded, DocumentSaved, DocumentClosed, RescanMenusFinished
This should give enough hooks to - for example - load a document and export a rendered image of the beginning of each shot.
With sfmApp.RegisterTabWindow( <identifier>, <title>, <Pointer to the window in shiboken> )
you can register windows to show up inside of tabs in the SFM. Here is an example that can be stored in sfm_init.py:
# Initial Script after SFM started up, and the main window got focus from PySide import QtGui from PySide import QtCore from PySide import shiboken class TabWindowExample(QtGui.QWidget): def __init__(self): super( TabWindowExample, self ).__init__() self.initUI() def initUI(self): self.lbl = QtGui.QLabel( self ) self.lbl.setText( "No Value Yet" ) sld = QtGui.QSlider(QtCore.Qt.Horizontal, self) sld.setFocusPolicy(QtCore.Qt.NoFocus) sld.setRange(1, 750) sld.setValue(75) sld.valueChanged[int].connect(self.changeValue) vbox = QtGui.QVBoxLayout() vbox.addWidget( sld ) vbox.addWidget( self.lbl ) vbox.addStretch(1) self.setLayout(vbox) def changeValue(self, value): print "Value: " + repr( value ) self.lbl.setText( "Value: " + repr( value ) ) exampleWindow = TabWindowExample() sfmApp.RegisterTabWindow( "TabWindowExample", "Tab Window Example", shiboken.getCppPointer( exampleWindow )[0] ) print "TabWindowExample: Python initial startup complete"