Hello World

From The Foundry MODO SDK wiki
Revision as of 01:51, 1 February 2012 by Shf (Talk | contribs) (Headers)

Jump to: navigation, search

So you've decided to write a plug-in. Good for you! This "Hello World!" tutorial will cover the absolute minimum steps required to create a plug-in and get feedback inside the application.


Build Environment Setup

You need to do three things to be ready to start coding a plug-in.

  1. Include headers. The lxsdk header directory needs to be on the compiler search path.
  2. Build common lib. The common code library archive needs to be built using your compiler and environment. You will link your plug-in to this library to get base implementations for the shared classes and objects.
  3. Empty .cpp file ready to compile and link.

You should be able to get started with this using the provided IDE projects for VC and XCode.

Decide on Your Server Type

A plug-in can't do anything unless it provides one of the proscribed server types for nexus to access. Is this a command, an item type, a tool? Perhaps the plug-in will have multiple servers that all work together. This is something for you to decide.

For the purpose of this tutorial we'll be making an image saver, which is one of the simplest types.

Writing Code


The first part of your plug-in source file will include the required headers. There are two types of headers you will typically want to use:

  • lx_<system>.hpp -- the user header for any given nexus system will have an L-X-underscore prefix and be of the hpp type. Check the documentation to see which interfaces are defined as part of a given system.
  • lxu_<name>.hpp -- utility headers have an L-X-U-underscore prefix, and contain helper classes of various kinds.

In this case we want the io system and image system headers. I/O gives us the definitions for savers and loaders, and Image defines the interfaces for image objects. Since we're going to say hello to the world we also need the log system.

#include <lxsdk/lx_io.hpp>
#include <lxsdk/lx_image.hpp>
#include <lxsdk/lx_log.hpp>

The Server Class

The heart of any plug-in is a C++ class that you write to implement a server interface. The interface is the set of standard methods that nexus uses to integrate your server into the application. This is done by inheriting from multiple implementation classes. In this case we're going to inherit from the Saver implementation:

class CHWSaver : public CLxImpl_Saver

The Saver super-class defines two methods: sav_Verify() and sav_Save(). The sav prefix is unique to the Saver implementation class, and allows multiple implementations with the same or similar methods to be inherited by the same server. We're going to implement the Save() method, adding this line to our class definition above:

        LxResult   sav_Save (ILxUnknownID source, const char *filename, ILxUnknownID monitor)  LXx_OVERRIDE;

The override keyword is optional but very useful. It declares to the compiler that you intend for your method to be derived from an identical method is a super-class. That means that if the method in the implementation class changes the compiler will throw an error. If you don't use the override keywork (or if your compiler doesn't support it -- it's not standard) then you get no error, but your method will never be called.

Server Methods

To flesh out the save method we'll declare a code body with the same arguments as above.

CHWSaver::sav_Save (
        ILxUnknownID            source,
        const char             *filename,
        ILxUnknownID            monitor)

The source is the object to be saved, in this case an image. This is an ILxUnknownID pointer type -- a general handle to a COM object -- and can be queried for any number of Image object interfaces. The filename is the full path of the file to be written in platform-specific format. The monitor is another object used for tracking the progress of the save and is discussed later.

The first thing we want to do is query the image object for an Image interface that will allow us to read the size for the "hello world" message. This is done simply by declaring a localized C++ image user class and initializing it to the source object.

        CLxUser_Image           image (source);

CLxUser_ classes are wrappers that allow COM objects to be accessed through common C++ syntax, with C++-friendly APIs. Once initialized with a COM object, they can be used like any other C++ object. In our case we're going to read the size of the image.

        unsigned                w, h;
        image.Size (&w, &h);

Instead of writing an image file as would be expected for a plug-in of this type, instead we're going to generate test output just to alert the world that we exist.