A procedure couldn’t be found in library


When you get an error like this

A procedure couldn’t be found in library Addons\SItoA\Application\bin\nt-x86-64\sitoa.dll. The library will not be loaded.

it usually doesn’t mean that Softimage couldn’t find the DLL (sitoa.dll in this case).

Typically, this error is caused by a missing DLL dependency, or the wrong version of a dependent DLL. You can use Dependency Walker and Process Monitor to track down what’s going wrong. A “DLL dependency” or “dependent DLL” is another file that sitoa.dll depends on. When Softimage loads sitoa.dll, that other DLL isn’t found, or if it is, it’s the wrong version. And so you get the error.

A new beginning…


After my stay at Autodesk ended seven weeks ago, I never got to say anything like “I’ll be back”, because I never really went away. Posting here continued more or less as normal. But now, I’m back at work: today is my first day at Solid Angle SL as one of the Solids, as they’re [apparently] sometimes called 🙂

I’ll be working from my home office, with occasional visits to Madrid. My job? Senior Support Engineer.

The workspace, all set up and ready to go…

Having an expresso and figuring out the Soft Lighting parameters…

Harley, the “Montreal office” mascot

Saturday snippet: short-circuit evaluation


If you’re new[ish] to scripting, here’s a Python snippet that illustrates short-circuit evaluation of boolean expressions.

In this snippet, short-circuit evaluation is used to avoid errors. For example, if there is no such ICE attribute (nb is not None) then there is no attempt to try and use the ICE attribute methods like IsDefined.

The expression in the print statement also relies on operator precedence (not has higher precedence than and, so everything works as expected).

# Assume a polymesh is selected...
o = Application.Selection(0)

# Check the intrinsic ICE attribute
nb =  o.ActivePrimitive.ICEAttributes("NbPoints")
print nb is not None and nb.IsDefined and nb.DataArray[0] <= 0

The above snippet also relies on operator precedence (not has higher precedence than and, so everything works as expected).

Since or has higher precedence than and, you could write something like this:

nb.IsDefined and nb.DataArray[0] <= 0 or o.ActivePrimitive.Geometry.Polygons.Count <= 0

But I’d probably put in the parentheses just to be clear:

(nb.IsDefined and nb.DataArray[0] <= 0) or o.ActivePrimitive.Geometry.Polygons.Count <= 0

Finding empty polygon meshes


Now that there are intrinsic ICE attributes like NbPoints and NbPolygons, there a couple of ways you can check for an empty mesh:

# Assume a polymesh is selected...
o = Application.Selection(0)

# Check the intrinsic ICE attribute
nb =  o.ActivePrimitive.ICEAttributes("NbPoints")
print nb.IsDefined and nb.DataArray[0] <= 0

# Check using the object model
print o.ActivePrimitive.Geometry.Points.Count <= 0

The typical way to package this up for users it to define a filter. Then a user just has to select the filter and press CTRL+A. Here’s the Match callback for a filter that finds empty polygon meshes. Note that I switched to checking the number of polygons. That way, if somehow there was something weird like a mesh with just one point, you’d still find it.

The intrinsic attribute NbPolygons should always exist, but just to be sure I check IsDefined, and if that is False, I fall back to checking Geometry.Polygons.Count.

# Match callback for the EmptyPolygonMesh custom filter.
def EmptyPolygonMesh_Match( in_ctxt ):
	Application.LogMessage("EmptyPolygonMesh_Match called",constants.siVerbose)

	o = in_ctxt.GetAttribute( 'Input' )
	if o.type == 'polymsh':
		nb =  o.ActivePrimitive.ICEAttributes("NbPolygons")
		return (nb.IsDefined and nb.DataArray[0] <= 0) or o.ActivePrimitive.Geometry.Polygons.Count <= 0
	else:
		return False

I packaged the filter as an addon. Get it here.

Tip – UI color widgets have a visual cue for gamma correction


In the Display > Color Management preferences, you can turn on gamma correction for UI widgets like the color chip. On the PPG, there’s a visual cue (a “dotted highlight”) that tells you whether gamma correction is on.

Gamma-corrected color widget:

Image

Regular color widget (no gamma correction):

Image

Also, you can right-click the color chip to toggle gamma correction on and off for that specific widget.

This is all in the docs, but I have to admit I found that out only after I noticed this on my own. Too bad, because if I had known this, I would have figured out sooner why my color chips looked so “faded”:

Image

(because at some unknown point in time I had enabled the display of gamma correction for UI widgets, and then set the Profile Source to “From LUT File”)

Importing multiple FBX files with drag-and-drop


As an exercise, I updated Tim Crowson’s Multi_ImporterPPG addon with a DragAndDrop event, so you can import multiple files with a single drag-and-drop. You can download the modified version here.

Here’s the DragAndDrop event handler. The doit() function is also used by the Import menu command; I just had to generalize it a bit to work in either case (menu or drag-and-drop).

def Multi_Importer_DragAndDrop_OnEvent( in_ctxt ):

	action = in_ctxt.GetAttribute( "DragAndDropAction" )
	source = in_ctxt.GetAttribute( "DragSource" )

	if action == constants.siSourceDragAction:
		if re.search( r"\obj$", source, re.I ):
			in_ctxt.SetAttribute( "DragSourceSupported", True )
		elif re.search( r"fbx$", source, re.I ): 
			in_ctxt.SetAttribute( "DragSourceSupported", True )
		elif re.search( r"emdl$", source, re.I ): 
			in_ctxt.SetAttribute( "DragSourceSupported", True )
		elif re.search( r"lwo$", source, re.I ): 
			in_ctxt.SetAttribute( "DragSourceSupported", True )
		else:
			in_ctxt.SetAttribute( "DragSourceSupported", False )
		
	
	if action == constants.siSourceDropAction:

		Application.SetValue('preferences.Interaction.autoinspect', False, '')

		if not Application.ActiveSceneRoot.Properties( 'Multi_Importer' ):
			vtcol = Application.AddProp('Multi_Importer','Scene_Root')
			p = Application.Dictionary.GetObject( vtcol.Value("Value") )

			# Set the flag that hides certain parts of the PPG layout
			p.Parameters("bMenuCommand").Value = False

			# Inspect the PPG in modal mode
			Application.InspectObj( vtcol.Value("Value"), "", "", 4 )

			p.Parameters("bMenuCommand").Value = True
			
		p = Application.ActiveSceneRoot.Properties('Multi_Importer')

		options = { 
			'OBJgrouping' : p.Parameters('importOBJgrouping').Value,
			'OBJhrc' : p.Parameters('importOBJhrc').Value,
			'importOBJnormals' : p.Parameters('importOBJNormals').Value,
			'includeOBJmat' : p.Parameters('includeOBJMaterial').Value,
			'includeOBJuv' : p.Parameters('includeOBJUV').Value,
			'includeOBJwrap' : p.Parameters('includeOBJUVWrap').Value,
			'fbxScale' : p.Parameters('fbxScale').Value,
			'importEMDLasRef' : p.Parameters('importEMDLasRef').Value,
			'lwoScaleFactor' : p.Parameters('lwoScaleFactor').Value
			}
		
		doit( source, options )
	
	return True