Cpp API Overview (XSISDK)

Table of contents

Introduction

XSI has included a C++ API since version 3.0, which replaces the COM programming that was necessary in older versions of XSI. The C++ API makes no use of Microsoft header files, so it is easy to use with Linux.

The API is very similar to the Scripting Object Model. Many efforts have been made to try to achieve consistency and equivalent functionality. Because of this similarity, C++ API developers should refer to the Scripting Object Model documentation to find additional relevant examples.

Documentation


Advantages over Scripting

  • C++ offers faster results and less memory consumption, especially for processing numbers.
  • C++ is the best language for communicating with many 3rd party libraries, for example opengl, win32 and directX
  • Source code can be kept secret

Disadvantages over Scripting

  • Requires knowledge of C++, which is harder to learn than scripting languages
  • C++ is picky about data types and does not provide a good API for string manipulation.
  • Less examples have been written
  • Some parts of the Object Model are not available directly in the C++ API (requiring use of the CComAPIHandler)
  • Code must be compiled. This requiers a more challenging machine configuration. Any fix to the code isn't visible until the .dll is recompiled. You cannot recompile a dll that is held open by XSI.
  • Requires a compiler. On linux the compiler is free but the debugging tools are weak. On Windows Visual Studio .Net (2003) is the recommended compiler, which has powerful debugging tools but an associated cost.
  • Overall it is often faster to write a plug-in with scripting, and in many cases the scripting version is "good enough".

Converting Object Fullname String into C++ Object

The CRef::Set method makes it very easy to turn the full name of an object into its equivalent C++ object.

CRef refRateParam ;
refRateParam.Set( L"PlayControl.Rate" ) ;
app.LogMessage( Parameter(refRateParam).GetValue().GetAsText() ) ;

In this case we are reading the value of a Parameter, so notice how a temporary Parameter object is used to give access to the Parameter::GetValue method.

Strings

Wide Characters

C++ API strings are represented as Unicode strings, where each character is two bytes long instead of a single "char". The use of an L character is necessary when strings are embedded into the code,

CString str = L"Foo" ;

CString Object

The XSI::CString (http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1CString.html) object (not to be confused with the MFC CString) is used in most places to represent strings, rather than dealing with raw character arrays. It offers some basic string helper methods, but for additional string manipulation the C stdlib, STL, Win32 or other non-Softimage libraries can be used to manipulate wide character strings.

Warning - Use GetWideString and GetAsciiString carefully

The pointers to string buffers returned by CString::GetWideString() or CString::GetAsciiString must never be referenced after the CString object has been deleted.

Wessam Bahnassi contributed a real life scenario where he ran into this problem, "After spending a couple of days trying to pinpoint a damn memory corruption bug in our XSI plug-in, I found that it's all caused by a casual use of XSI::CString class...

Look at this code snip:

XSI::Parameter param; // Assume this is a valid XSI param object...
const char *pszString = param.GetName().GetAsciiString();
printf(pszString); // Potential crash!

What happens is that param.GetName() returns a temp XSI::CString object. And after the call to GetAsciiString(), this temp string object is destroyed, rendering the pointer pszString potentially invalid...

//Safe version
XSI::Parameter param; // Assume this is a valid XSI param object...
// Assign the CString to a variable so that is remains valid
// within the current scope
XSI::CString name = param.GetName() ;  
const char *pszString = name.GetAsciiString();
printf(pszString); 


Of course in our code we do a lot more stuff instead of printf(), and that put me in endless wonders why many of the strings I receive are garbage!

I hope this saves some poor souls out there as I don't like to see people suffering from this mistake..."

An ascii string class example

Here's an example to demonstrate how CString can be extended for handling ascii strings more easily.

class CStringAscii : public CString
{
	public:
	CStringAscii( const char* p )
	{
		PutAsciiString(p);
	}

	CString& CStringAscii::operator +=(const char* in_pstr)
	{
		CStringAscii s(in_pstr);			
		CString::operator +=( s.GetWideString() );
		return *this;
	}		
};
	
CStringAscii str("hello");
	
str += " world";	
Application().LogMessage( CString( str.IsEqualNoCase( L"hello world" ) );

Backward Compatibility

A lot of effort goes into supporting Binary backward compatibility between versions of XSI, so that it is not necessary to recompile a plug-in between XSI versions. XSI does this by avoiding the use of virtual functions in its C++ classes and encapsulating all data. Signatures of methods are not changed, instead new methods are added to supplement functionality of each class.

Some plug-in may break between versions if the fundamental functionality of XSI changes, or if the plug-in was depending on a bug or other unintended or undocumented behavior of the API. Normally the amount of work to port the plug-in to a new version is minimal.

The 64-bit version of XSI cannot load 32-bit dlls. But recompiling a plug-in for 64-bits is normally a straightfoward process.

In the past, some updates to the GCC compiler used on Linux, has changed the binary format of .so files, hence breaking binary backward compatibility. A simple recompilationis necessary after such a compiler update. Softimage avoids this scenario whenever possible but does not have control over the GCC compiler output.

There is binary compatibility between Visual Studio v6 and Visual Studio .Net so plug-ins can be compiled with either package.

Object Lifetime

C++ SDK objects have a life time that is independent of the life time of the underlying XSI object. For example when a sphere is created using the C++ API a X3DObject is returned referencing the sphere. When this X3DObject is destroyed it does not automatically remove the sphere from the scene (calling DeleteObj command is a way to remove it).

This also implies that an object may be removed from the scene but a C++ API object still remain in memory that references it. In that case the underlying XSI object may still exist (because of reference counting) but because it is not part of the scene it is in an invalid state and cannot be used in any way. Such an object is called a "Zombie". Normally good common sense avoids this being a problem in real life plug-ins - e.g. it doesn't make sense to try to read values from an object that has just been deleted.

Objects of the Scripting Object Model have exactly the same behavior.

Converting the fullname of an XSI object into an C++ API object

CRef::Set (http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1CRef.html) is a very useful method for building a CRef from the string name of an object. Once a CRef() is available it can be used to construct the specific C++ API object associated with the XSI object.

Calling a Command

You can call any XSI command, including custom commands from the C++ API.

To call a command use the Application::ExecuteCommand (http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1Application.html#a23) method, which requires that all the arguments are filled in via an array. See the C++ API reference for more details.

CValueArray args(3);
args[0] = CValue(L"Sphere");
args[1] = CValue(L"MeshSurface");
args[2] = CValue(L"MySphere");
Application app;
CValue valSphereReturnValue;
app.ExecuteCommand( L"CreatePrim", args, valSphereReturnValue );


The cmdstubs.js script that is part of the XSI installation is a useful utility for generating C++ API code to make it easier to call commands.

CComAPIHandler

This is a useful class because it can be used to make calls from the C++ API into the Scripting Object Model. So practically any Property or Method available for scripting can be called from C++. Because a few objects are not fully ported to the C++ API it is sometimes necessary to use this approach.

However, for any Windows developer familiar with COM, it is also possible to communicate with XSI directly via COM interfaces rather than using CComAPIHandler. Code using COM interfaces tends to be much more difficult to write and understand than regular C++ API code. (This was the only C++ solution before the introduction of the C++ API so some existing plug-ins still use this approach extensively.)

On Linux it is not normally possible to compile code with raw COM calls, so the CComAPIHandler (http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1CComAPIHandler.html) is a good cross-platform solution.

Shaders and the C++ API

Mental Ray shaders are compiled and various callbacks are invoked just like self-installed plug-ins. However the callbacks are called in the context of Mental Ray, not XSI, so the C++ API is not available to read scene data. Normally any scene data that is needed must be packaged into Mental Ray User Data via an XSI UserDataBlob (http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1UserDataBlob.html). This is demonstrated in the Wireframe SDK example.

Real-Time Shaders execute inside the context of XSI so it is possible to use the C++ API inside a real-time shader callback. However attempting to change the scene content during rendering can lead to unexpected results. One common use of the C++ API inside a real-time shader is to read parameter values from a CustomProperty, which can be nested directly under the Shader node.

COM API and the C++ API

The entire Scripting Object Model is available via COM interfaces. Before the C++ API was introduced this was the only way to program XSI plug-ins with C++. Using these interfaces is generally more difficult than using the C++ API, and it is normally only possible on the Windows platform. However for programmers on the Windows platform it still remains an option and it is possible to mix both APIs together. The CComAPIHandler is a cross platform way to mix some COM API calls into a C++ API plug-in.

Logging stdout to Script History

The normal and recommended way to log content to the script history window is via the Application::LogMessage() call.

Windows: When running in non-batch mode XSI will use the script history to log any content sent to stdout and stderr (which includes calls to printf), but only when some strict conditions are meet. The main condition is that the plugin dll must be compiled to use exactly the same version of msvcrt that XSI uses . msvcrt is the C library that includes the definition of stdout. XSI uses the release dll-based version as shipped with Visual Studio .Net 2003. All output the stdout and stderr must also occur within the main XSI thread (which is the thread that all plugins execute in unless they are spawning their own threads).

These specifics are subject to change in the future so unless your output is only temporary debugging information it is best to use Application::LogMessage().

Use the XSI_NOSTD_REDIRECT environmental variable to disable the redirection of the stdout and stderr to the Script History windows. This is sometimes useful on the Linux platform where you may prefer to see output logged on the command prompt.


This page was last modified 11:02, 22 Apr 2006.
This page has been accessed 29154 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy