A language-agnostic presentation of Pro Motion file I/O plug-in interface, aimed at helping developers design plug-ins in any programming language.

DISCLAIMER

This document is my personal attempt to contribute a language agnostic description of the File I/O interface. It’s not part of the official Pro Motion documentation and I’m acting solely as a Pro Motion NG user and enthusiast.

Therefore, I’m the only person responsible for any errors and inaccuracies herein contained.

Furthermore, the quality (or lack thereof) of this document is not representative of the quality of Cosmigo GmbH, its products and services; it’s just my personal effort to explore the subject of plug-in development as a hobbyist programmer and PMNG end user.

WARNING: DOCUMENTATION INCOMPLETE!

The document is still a draft, many aspects of the plug-in interface are still not fully covered and remain somehow obscure. The information herein presented is most likely insufficient to develop a full fledged plug-in.

At moment development of this document has reached a dead end due to lack of a full documentation of the interface details (see the Document Status Info section for more info).

Introduction

About File I/O Plug-ins

Pro Motion (>=v6.5) allows users to extend the supported images and animations file formats by means of third party file I/O plug-ins. Each file plug-in can target either images or animations, it may handle saving and/or loading (either one or both) from/to a specific file format, and will be associated with a specific file extension in the file I/O dialogs of Pro Motion.

A file I/O plug-in is a DLL (Dynamic-link library) shared library, located inside the plug-ins subfolder in the installation directory of Pro Motion. Depending on the bitness of your MS Windows operating system, the path of the plug-ins folder will be either:

32 bit OS:

%ProgramFiles%\cosmigo\Pro Motion NG\plug-ins\

64 bit OS:

%ProgramFiles(x86)%\cosmigo\Pro Motion NG\plug-ins\

Any plug-ins inside that folder will be automatically detected when Pro Motion is launched, and made available in the file load/save and import/export dialogs according to where the plug-in functionality fits in PMNG context. This means that during development, whenever you updated/recompile your DLL you’ll have to close and restart PM.

Since PM is a 32 bit application, the plug-in DLL must also be compiled as 32 bit.

At the time of this writing, Pro Motion NG is only available as a 32-bit application. In the future this might change, therefore always check the Cosmigo website for up-to-date information.

If a 64 bit version of PM NG should be released, all file I/O plug-ins would have to compiled to 64 bit in order to be usable (linkable) by the 64 bit version.

Choosing a Language

The good news about PM plug-ins is that developers are free to use a variety of different programming languages to create plug-ins with. This means that the creation of PM plug-ins is not restricted to C/C++ gurus, but can be also accomplished with some easier programming languages, including Basic.

The “bad news” (so to speak) is that the official Cosmigo plug-in interface documentation and code samples are intended for an audience with knowledge of either C++ or Delphi, which means that users willing to implement plug-ins in other languages will have to conduct extensive research on these languages in order to work out data types equivalences and how to overcome some memory management issues implicitly handled behind the scenes by Microsoft Visual Studio and Embarcadero Delphi XE2.

This guide was conceived to simplify the task of implementing PM plug-ins in any language, by presenting the plug-in interface, its data types and the data exchange mechanisms in a language agnostic way — i.e. without assuming that the reader has any knowledge of C/C++ or Delphi. Hopefully, this document will fill the C++/Delphi “experts gap” and open the doors of plug-ins development to programmers coming from all walks of programming life, including beginners who are willing to give it a go, and regardless of the languages they’re accustomed to work with.

An obvious limitation to this approach is that the guide is bound to provide fairly generic implementation guidelines, for different programming languages have different paradigms. It would be impossible to provide implementation-specific advice and preserve language-neutrality at the same time. Developers will need to adapt the information provided by this guide to the paradigm of their programming language. Programmers fluent in C++ or Delphi are better off reading the official Developer Interface document, for it provides implementation-specific details.

You can create a custom file I/O plug-in with any programming language that meets the following requirements:

  • Compile a 32-bit DLL (no thread-safety required).

  • Export DLL functions using the stdcall calling convention.

  • Support Unicode strings.

  • Support pointers and user define structures.

Most compiled programming languages for Windows should meet these requirements. Therefore, developers have an ample choice of languages to pick from for developing PM file I/O plug-ins, and are by no means bound to use MSVS or Embarcadero Delphi for the task.

Pseudocode Notation

To simplify representation of functions, their parameters and data types, this document employs an arbitrary and simple pseudocode notation and then describes the parameters in more detail, one by one. Hopefully, the adopted notation should be self explanatory.

Interface Overview

Pro Motion expects the plug-in DLL to export some functions with specific names, parameters and return values. When creating a custom plug-in, you must therefore ensure that all those functions are correctly implemented.

PM will invoke the DLL functions in a meaningful order, depending on the type of file operation requested by the user.

Data exchange is handled by passing pointers to and from the DLL. Sometimes pointers are used to pass data from PM to the plug-in, in which case a function parameter will be a pointer to the memory location storing the data which the plug-in should read. Other times, pointers are used to pass data from the plug-in to PM, either via a pointer parameter in the function call, which the plug-in should then use to store the requested data in, or by the function being expected to return a pointer to a string.

Some functions are expected to return boolean values (true/false) to inform PM whether a given feature is available. Error handling is done via the getErrorMessage plug-in function, which will should either return a NULL pointer (no error) or a pointer to string describing the error; PM will invoke this error function right after calling any plug-in function that may set error (not every plug-in function can set error).

The following table lists all the required DLL functions, and specifies which functions are invoked in file load and save operations, and whether the function might set an error or not.

Table 1. Plug-in DLL Functions Overview
function name load save error summary description

initialize

Called once when PM launches and registers all plug-ins.

setProgressCallback

Provides a pointer to PM’s progress status function.

getErrorMessage

PM calls it to get a pointer to the error message string.

getFileTypeId

Plug-in info: The unique plug-in ID, for internal PM use.

isReadSupported

Plug-in info: Does it support read operations?

isWriteSupported

Plug-in info: Does it support write operations?

isWriteTrueColorSupported

Plug-in info: Does it support writing true color data?

getFileBoxDescription

Plug-in info: Description for PM’s file types dialog drop down.

getFileExtension

Plug-in info: Associated file extension.

setFilename

Informs the plug-in on the filename about to the processed.

canHandle

PM needs the plug-in to confirm it can handle the file.

loadBasicData

PM needs the plug-in to confirm it extracted info from the file.

getWidth

PM wants to know the image with in pixels.

getHeight

PM wants to know the image height in pixels.

getImageCount

PM wants to know the number of image frames.

canExtractPalette

Plug-in info: Does it support extracting just the palette?

getRgbPalette

PM wants a pointer to the extracted 256-colors palette.

getTransparentColor

PM wants to know if and which indexed color is transparent.

isAlphaEnabled

PM wants to know if the image contains transparency layers.

loadNextImage

Called to obtain from the plug-in the current image data.

beginWrite

PM passes preliminary information about the upcoming image.

writeNextImage

Called to transfer to the plug-in the current image data.

finishProcessing

End of plug-in transactions, all resources must be freed.

Even though some of these DLL functions only apply to plug-ins that support either importing or exporting, you must still define all of them, because even though they will never be called (e.g. loadNextImage() would never be called with an export-only plug-in), at start-up PMNG will still check that they are properly defined, and will reject as “invalid” any file I/O plug-in that omits one or more of the above functions. (See 1018 and #6 )

Interface Data Types

Each programming language has its own native data types, and adopts a custom naming convention for the various types. To avoid confusion about the data types mentioned in this document, I’ll try to provide language-agnostic description of the data types used by plug-ins to exchange data with PM.

Strings

Strings are exchanged between PM and the plug-in via pointers. All strings are expected to be null-terminated and in Unicode (i.e., wide char, 16-bits characters, wchar_t), and not ASCII strings. If your language allows creating different types of strings, check that you are using the correct type.

Because many languages provide a simple syntax to define and work with sting variables (in order to hide the complexity of string pointers), you must ensure that when you pass to PM string pointers you’re passing a pointer to the memory location of the actual string contents, and not just a pointer to the string variable. In many languages the memory location of string variable contains just a pointer to the actual string, not the string itself.

Furthermore, in order for PM to able to gain read/write memory access to these plug-in strings, you’ll need to use some globally scoped strings which are visible outside the DLL. How this can be achieved will depend largely on the language you’re using, but chances are that if its syntax provides a ‘global’ keyword that should do the trick. Refer to the language documentation regarding strings, pointers, variables scope and visibility, and creating dynamically linked libraries (DLLs).

TO BE CONTINUED…​

Functions Description

initialize

bool : initialize(
                    *language  : char[2],
                    *version   : uint16,
                    *animation : bool
                 );
Parameters

*language

(in)

Points to two-characters (ASCII) representing the ISO language code currently used in PM user interface (e.g. 'en', 'de' or 'fr'). Can be used for localization if the plug-in supports multi-language messages, otherwise just ignore it.

*version

(out)

Pointer to uint16 representing the version number of the file I/O plug-in interface.
Must be set to “1” to be a valid plug-in, as this is the only interface version currently supported.

*animation

(out)

Pointer to boolean (1 byte/uint8). Plug-ins targeting animations must set it to true.

Control

Return value

true if successful, false otherwise.

May set error

Yes.

General initialization function, called once when PM launches and needs to register the available plug-ins.

The function informs the plug-in of the locale being used in PM, and provides pointers for retrieving the interface version for which the plug-in was designed (for future use, when new interface versions will be introduced) and to determine whether this is a plug-in for handling images or animations files.

If the plug-in targets animation files, then it must set to true the byte located at *animation. Plug-ins for image files, on the other hand, don’t need to do anything with *animation.

This will always be the first plug-in function invoked by PM.

Unlike other error-setting plug-in functions, which only need to ensure that getErrorMessage will return a pointer to an error string, initialize must also return false in case of error. This is because initialize is a special case, for it’s used to activate the plug-in, and it’s therefore expected to return a boolean indicating success/failure. In case of failure, it should still set an error description via getErrorMessage.

setProgressCallback

void : setProgressCallback( *progressCallback : function );
Parameters

*progressCallback

Pointer to a PM function that the plug-in must call when progress changes.
The PM function located at *progressCallback (stdcall) is representable as:

void : *progressCallback( int32 progress );

The plug-in must invoke it accordingly, using only its memory pointer as a means to interface with it.

Control

Return value

None.

May set error

No.

This function passes to the plug-in the memory address of a PM progress callback function that the plug-in should use to provide user feedback regarding the progress of image loading/saving operations.

The plug-in must interface to the above function (stdcall) using the pointer provided via the *progressCallback parameter. How this can be achieved will vary from language to language, but you should be looking for a way to call “foreign functions” via some Foreign function interface (FFI) mechanism.

The progress parameter in the callback function represents progress percentage expressed via an integer value (int32). A progress value of “0” will hide progress display in PM, while values in the range “1” to “100” will make the progress display visible.

PM NG no longer displays a true progress bar, because nowadays it’s mostly useless due to the speed at which most images are processed, but previous version of PM do; therefore, for the sake of backward compatibility, plug-ins should honor the progress callback.

The important thing here is to provide the end user with some kind of feedback on the ongoing plug-in operations, which in PM NG is now shown via a small emphasized panel at the bottom of the main window, along with the cursor shape turning “busy”.

Plug-in developers should call the *progressCallback function to update the user when progress status changes, passing to it progress indications from 1 to 100, if possible. At least, set it to a non-zero value when the plug-in is processing, and then back to zero when processing is over.

getErrorMessage

*string : getErrorMessage();
Control

Return value

Pointer to a string describing the error, or nil/NULL.

May set error

No.

If one of the plug-in functions that may set error does encounter an error, it can notify PM via indirect usage of this function, i.e. by setting the conditions that will make getErrorMessage() return a pointer to an error string instead of nil.

PM will call this function immediately after calling any plug-in function that may set error, and getErrorMessage() should either return nil if no error was encountered, or a pointer to a string containing the error description. PM expects the string to be a Unicode string (wide char, 16-bits characters), not an ASCII string; if your language allows creating different types of strings, check that you are using the correct type.

This means that within your plug-in DLL getErrorMessage() should be granted access to a string which is also visible to all functions that may set error (i.e. a global string), and check whether the string is currently empty or contains some text, in the former case it should return nil, in the latter it should return the memory address at which the string is stored, for it means that the last plug-in function called has set an error which must now be notified and passed on to PM.

A pseudocode example:

Global string ErrorMessage; // define a string visible to all DLL functions

*string : getErrorMessage()
{
  If ErrorMessage == ""
    Then
      // no error currently awaiting to be notified
      Return nil;
    Else
      // there is a pending error, return memory address of error string
      Return &ErrorMessage;
  EndIf
}

The nature of this indirect error messaging mechanism also requires that all functions that may set error should “reset” the aforementioned string to be empty at the beginning of each call, to avoid carrying over errors generated by previous functions calls. As soon as an error is encountered, the error string should be set to contain a meaningful message about the nature of the problem, and just let getErrorMessage() handle notification of the error to PM, and that the next plug-in function (which may set error) that gets called will handle resetting the error string.

Not every plug-in procedure can set error, only those explicitly indicated in this document (under “Control” in the description of each function, as well as in the “error” column of Table 1). This was done to avoid burdening PM with having to check for errors at each and every plug-in call, and limiting instead these checks to meaningful contexts.

getFileTypeId

*string : getFileTypeId();
Control

Return value

Pointer to a string with the unique identifier of the plug-in.

May set error

No.

PM calls this plug-in function in order to acquire a unique identifier for the plug-in. The Id is used by PM as an internal reference to the plug-in, and it’s not intended to be shown to end users. For example, if the user saved a file via this plug-in and later uses the ‘save again’ function, PM will rely on the file type Id to know which plug-in to use.

The plug-in must return a pointer to a string containing the plug-in file type Id.

The file extension is not unique enough to used as a Id, for there could be several load/save plug-ins for "bmp-files". The Id may be a series of numbers/characters like a GUID, or it may be like a Java package descriptor, e.g. "de.mycompany.promotion.ioplug-in.png".

isReadSupported

bool : isReadSupported();
Control

Return value

true, if read is supported, false otherwise.

May set error

No.

PM needs to know if the plug-in supports reading from the file format, to determine whether to include the plug-in in the file open/import dialogs.

isWriteSupported

bool : isWriteSupported();
Control

Return value

true, if write is supported, false otherwise.

May set error

No.

PM needs to know if the plug-in supports saving to the file format, to determine whether to include the plug-in in the file save/export dialogs.

isWriteTrueColorSupported

bool : isWriteTrueColorSupported();
Control

Return value

true, if write is supported, false otherwise.

May set error

No.

PM needs to know if the plug-in can write true color data to the file format. Some operations (e.g. automatically flattening layers) may result in colors that don’t fit into the 256 colors palette. In these cases the image data can be optionally stored as true color (24-bit color depth). If the plug-in doesn’t support true color then the image colors are reduced to 256 indexed colors.

getFileBoxDescription

*string : getFileBoxDescription();
Control

Return value

Pointer to a string with the file type description.

May set error

No.

PM needs a file type description string to represent the plug-in in the file I/O dialogs, e.g. “BMP Windows Bitmap RLE”. You should place the file type abbreviation (usually the file extension) at the beginning of the string so that it can be sorted correctly in the drop down menu, making it easier for end users to sift through the list of available file types.

If your plug-in supports internationalization, you should return a pointer to a string in the language matching the user’s locale (which the plug-in has already detected during the initialize() call).

getFileExtension

*string : getFileExtension();
Control

Return value

Pointer to a string with the file extension supported by this plug-in.

May set error

No.

This function must return the file extension (without “.”) to be used in the file filter.

setFilename

void : setFilename( *filename );
Parameters

filename

Pointer to a string with full path and name of the file to process.

Control

Return value

None.

May set error

No.

PM calls this function to inform the plug-in that a new file is about to be processed and provides a full path to the corresponding file. The plug-in should reset its internal structures and references if the file name is different from the previously set file.

At this stage, it is still undefined if the file is intended for read or write operations!

Calls to this function might be triggered by different contexts. For example, by the user when her/she selects in a file I/O dialog a file registered to the plug-in. But it might also be triggered multiple times by PM as a result of a multi file operation (e.g. File  Create from single Images…​, Animation  Save as single Images…​, etc.).

The plug-in at this stage only needs to acknowledge the file, memorize its references, and be prepared.

canHandle

bool : canHandle();
Control

Return value

true, if the file can be processed.
If false is returned then an error message must be set saying why it can not be handled.

May set error

Yes.

This function is called by PM to get confirmation that the plug-in is capable of handling reading the selected file (i.e. the file indicated via the setFilename() call). The plug-in should open the file and carry out the necessary checks and then return either true or false accordingly. In case the plug-in is unable to handle the file, it should also set an error with a sting describing the reason why the file can’t be handled.

Some image/animation formats may have many variants, yet share the same file extension, and a plug-in might support only some features of the format and not others. When this function is called the plug-in must check if the selected file is actually supported, by doing some basic checks on the file header, etc.

loadBasicData

bool : loadBasicData();
Control

Return value

true, if the file data could be loaded.

May set error

Yes.

Before actually reading any graphics data, PM calls this function so that the plug-in can extract some basic graphics data information from the target file, such as its dimensions, color palette, and other relevant data. Other functions will rely on this function having been called before them — for example getWidth().

getWidth

int32 : getWidth();
Control

Return value

The width in pixels of the image that is to be loaded, or -1 if the function fails.

May set error

No.

PM calls this function to learn from the plug-in the width of the image which is going to be loaded, so it can prepare to receive it accordingly.

The returned value must be a 32-bit signed integer.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

getHeight

int32 : getHeight();
Control

Return value

The height in pixels of the image that is to be loaded, or -1 if the function fails.

May set error

No.

PM calls this function to learn from the plug-in the height of the image which is going to be loaded, so it can prepare to receive it accordingly.

The returned value must be a 32-bit signed integer.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

getImageCount

int32 : getImageCount();
Control

Return value

The number of frames of the image/animation that is to be loaded or -1 on failure.

May set error

No.

PM calls this function to learn from the plug-in how many image frames are present in the file which is going to be loaded, so it can prepare to receive them accordingly.

This function must return a 32-bit signed integer with the number of frames available to load from the file. If the file consists of a single image then “1” is to be returned.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

canExtractPalette

bool : canExtractPalette();
Control

Return value

If the plug-in supports palette reading then this function must return true.

May set error

No.

PM allows users to load just the color palette from a graphic file, without loading the graphic/bitmap data. PM calls this function once, during plug-in initialization, to ask the plug-in if it’s capable of handling extracting just the palette from a target file.

getRgbPalette

*array : getRgbPalette();
Control

Return value

Pointer to the RGB palette or nil/NULL if palette extraction is not supported.

May set error

No.

For plug-ins that support extracting the palette data, this function must return a pointer to the memory location storing the 256-colors indexed palette. The palette must be defined as a 768 bytes (256 x 3) sequence of RGB triplets (one byte per channel) representing the indexed colors, starting with color “0”.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

getTransparentColor

int32 : getTransparentColor();
Control

Return value

The palette index of the transparent color, or -1 if none.

May set error

No.

If the image contains a transparent color then this function must return its palette color entry/index (first entry is 0).

The returned value must be a 32-bit signed integer.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

isAlphaEnabled

bool : isAlphaEnabled();
Control

Return value

If the image contains alpha data then this function must return true.

May set error

No.

PM wants to know whether the image/animation file which is going to be loaded contains alpha transparency data or not.

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

loadNextImage

bool : loadNextImage(
                      *colorFrame,         // getWidth() * getHeight() bytes
                      *colorFramePalette,  // 768 bytes (256 * R,G,B)
                      *alphaFrame,         // getWidth() * getHeight() bytes
                      *alphaFramePalette,  // 256 bytes
                      *delayMs : uint16
                    );
Parameters

*colorFrame

A pointer to the bitmap holding the color pixels (color palette indexes).
The memory portion has a size of getWidth() * getHeight() bytes!

*colorFramePalette

A pointer to the RGB color table.
There are 768 bytes being 256 colors with one byte for red, green and blue.

*alphaFrame

A pointer to the bitmap holding the alpha palette indexes.
The memory portion has a size of getWidth() * getHeight() bytes!
If alpha is not supported then this value is nil/NULL and must not be used.

*alphaFramePalette

A pointer to the alpha value table. There are 256 bytes. Each byte is an alpha value ranging from 0 to 255. If alpha is not supported then this value is nil/NULL and must not be used.

*delayMs

If the frame has a delay value (animations only) then it must be given here as milliseconds (uint16).

Control

Return value

If the data was transferred successfully it must return true.

May set error

Yes.

For plug-ins that support reading, this function is used to load the image data. After executing this function the plug-in must advance to the next frame, if any. The function will be called according to the number of frames returned by getImageCount().

loadBasicData() has been already been called by PM before using this function, to ensure that the plug-in has acquired this information.

beginWrite

bool : beginWrite(
              int32 width,
              int32 height,
              int32 transparentColor,
              bool  alphaEnabled,
              int32 numberOfFrames
                 );
Parameters

width

Width of the graphic (images).

height

Height of the graphic (images).

transparentColor

The palette index of the transparent color, or -1 if none.

alphaEnabled

If the graphic will store alpha data then this flag is set to true.

numberOfFrames

Number of frames that will be written.

Control

Return value

true on success

May set error

Yes.

Before writing graphic data, PM will call this function once to inform the plug-in about the dimensions of the data that will be stored.

The output file shall remain open until finishProcessing() is called.

writeNextImage

bool : writeNextImage(
                        *colorFrame,         // getWidth() * getHeight() bytes
                        *colorFramePalette,  // 768 bytes (256 * R,G,B)
                        *alphaFrame,         // getWidth() * getHeight() bytes
                        *alphaFramePalette,  // 256 bytes
                        *rgba,               // getWidth() * getHeight() * 4 bytes
                  uint16 delayMs
                     );
Parameters

*colorFrame

A pointer to the bitmap holding the color pixels (color palette indexes).
The memory portion has a size of getWidth() * getHeight() bytes!

*colorFramePalette

A pointer to the RGB color table.
There are 768 bytes being 256 colors with one byte for red, green and blue.

*alphaFrame

A pointer to the bitmap holding the alpha palette indexes.
The memory portion has a size of getWidth() * getHeight() bytes!
If alpha is not supported then this value is nil/NULL and must not be used.

*alphaFramePalette

A pointer to the alpha value table. There are 256 bytes.
Each byte is an alpha value ranging from 0 to 255.
If alpha is not supported then this value is nil/NULL and must not be used.

*rgba

A pointer to the bitmap holding the color pixels represented as RGBA (each pixel being a uint32/dword) where the lowest byte is the red channel.
The memory portion has a size of getWidth() * getHeight() * 4 bytes!

delayMs

If the frame has a delay value (animation only) then it’s provided here as milliseconds.

Control

Return value

If the data was transferred successfully it must return true.

May set error

Yes.

For plug-ins that support reading, this function is used to save the image data. The function will be called as often as there are more frames to be stored.

finishProcessing

void : finishProcessing();
Control

Return value

None.

May set error

No.

PM will call this function when the file read or write operation is completed. The plug-in must now close the file and carry out all the required wrap-up chores — destroy any memory data and references to the processed file, free memory, release handles, etc., but still be ready for further file I/O operations, for this call only confirms the termination of the current file I/O operation, but the plug-in still remains actively available at the service of PM for further (new) file operations.

When this function is called, the plug-in should basically just ensure that:

  • System memory and resources used during the file processing are now set free.

  • When the next file is processed, no information is carried over from the previous file operation.

If memory is not managed properly, the risk is that multiple plug-in invocations will end piling up garbage in memory, eat up system resource and/or lead to memory corruption. You must also ensure that the plug-in won’t end up keeping a handle on the processed file, which could prevent the user from deleting, renaming or moving the file until PM is running (this being a commonly occurring problem under MS Windows, which can be entirely avoided by good housekeeping during the wrap-up stage).

Document Status Info

Updated February 15, 2021.

Although I’ve started working on this document in March 2019, it’s still not complete — and, possibly, some plug-in advanced features (like true color data) are not usable in real case scenarios, and this document won’t be of much help except for very simple plug-in types. Nevertheless, I’ve managed to build a fully function export plug-in since working on this document, which also gave me a chance to get some “hands on” insight into how the File I/O interface actually works.

Currently, the only available sources of information on File I/O plug-ins are:

  1. The original Developer Interface document from Cosmigo.

  2. The two C++ sample plug-ins made available by Cosmigo.

The Developer Interface document unfortunately doesn’t cover in depth the various contexts in which the DLL functions are invoked, or how different images or animations might affect their parameters, leaving many aspects of the interface rather obscure, and for developers to work out by trial and error. But thanks to Jan’s support, I’ve managed to shed light on some of these aspects.

The two sample plug-ins (simImage and sanAnimation) are rather simple proofs of concept and don’t cover edge cases or more advanced aspects of exporting and importing images (e.g. handling true color), so their usefulness is somehow limited.

I’ve invested a considerable amount of hours trying to decode these undocumented aspects of the File I/O interface, which somehow allowed me to get a clearer picture, but still too far from a complete one. Pro Motion NG’s import/export functionality can get rather complex, for it encompasses various menus and different usage contexts, which may vary from the type of project being exported or the user options available in the load/save dialogs.

Although the DLL plug-in interface was introduced over ten years ago, with Pro Motion 6.5 (around 2009), there still aren’t any open source plug-ins available to study, except for the simImage and sanAnimation sample plug-ins. It’s hard to say whether no further energy was invested in the plug-in documentation due to lack of end users interests, or whether the lack of user-contributed File I/O plug-ins is due to the documentation being incomplete (probably both); but I’m confident that the more third party plug-in will be created, the more interest the plug-in interfaces will receive.

It’s a pity that the File I/O interface hasn’t been exploited more by Pro Motion’s end users, because it opened up a great potential, allowing users to extend the application to support new graphic formats (a much desirable feature, especially for game developers targeting modern game engines). Hopefully, in the future the official documentation for the File I/O interface will be updated and expanded on; in the meantime I’ll keep updating this document from time to time, and leave behind these status notes, in the hope that they might be of help to those wishing to dive into plug-ins development.

Some external links to useful resources on the topics covered in this article.

Wikipedia:

This document was written by Tristano Ajmone and published under the Apache License v2.0 terms.