Loader: Server basics

A Loader is a plug-in server that can recognize external file formats and read as nexus objects. Typically the objects are of image and scene types. Image loading can be done direct or opaque.

Overview

When the modo user selects a file to load, the system searches for loaders that can support the desired object type, like image. The Recognize() method is called for all those loaders and the first one that succeeds loads the file using one of the Load*() methods. The Cleanup() method is called after the loader is tried or used to revert to a pristine state. Loaders can also present option dialogs after recognize and before the load.

Headers

  • ‘’’io (lx-io.hpp)’’’
    • ‘’CLxImpl_Loader’’

    • ‘’CLxUser_Monitor’’

    • ‘’LXtLoadAccess’’

  • ‘’’image (lx-image.hpp)’’’
    • ‘’CLxUser_WriteImage’’

    • ‘’LXtImageTarget’’

  • LXsLOD_CLASSLIST – whitespace separated list of class GUIDs or aliases for the object types that can be loaded (e.g. LXa_IMAGE)
    • LXsLOD_DOSPATTERN – DOS-style filename pattern for recognized filenames (e.g. “.jpg;.jpeg;*.jp2”)

The plug-in server class derives from CLxImpl_Loader, and exports the ILxLoader interface.

Loader::Recognize()

The Recognize() method is called with a LXtLoadAccess structure, containing the filename to read. If the format is recognized then the method returns OK after setting some data fields in the load struct. The found field is the GUID of the object type found, in this example an image. The target pointer is set to a persistent object that depends on the found object. In this case it’s an LXtImageTarget struct which will hold the pixel type and dimension.

1
2
         LXiImageTarget         img_target;
         ...
1
2
3
4
5
6
         LxResult
 load_Recognize (
         LXtLoadAccess         *load)     LXx_OVERRIDE
 {
         if (!open_data_file (load->filename))
                 return LXe_FAILED;
1
2
         if (!data_header_is_ok ())
                 return LXe_NOTFOUND;
1
2
3
         img_target.type   = LXiIMP_RGB24;
         img_target.width  = width_from_header ();
         img_target.height = height_from_header ();
1
2
3
4
5
         load->found  = lx::LookupGUID (LXa_IMAGE);
         load->target = &img_target;
         load->opaque = 0;
         return LXe_OK;
 }

Loader::LoadObject()

Scene loads and normal image loads are done directly, which means that nexus creates the destination object and passes it to the loader to be filled in. This is why the image recognize method has to return the image dimensions, so a suitable destination can be allocated. Normally the load method is called directly after recognize, so the file can be assumed to still be open. In some cases – such as when using loader options – the load method may be called more directly so the file has to be open.

The rest of the code shows reading source pixels and writing them to a destination image. There are faster ways to access images as well. This also shows using a Monitor Interface to provide user feedback on how long it will take. The Step() method can return LXe_ABORT if the user changes their mind.

1
2
3
4
5
6
7
8
         LxResult
 load_LoadObject (
         LXtLoadAccess         *load,
         ILxUnknownID            destination)     LXx_OVERRIDE
 {
         CLxUser_ImageWrite      dst (destination);
         CLxUser_Monitor         mon (load->monitor);
         LxResult                rc;
1
2
         if (!open_data_file_if_not_open_already (load->filename))
                 return LXe_FAILED;
1
         mon.Init (img_target.height);
1
2
3
4
         for (unsigned y = 0; y < img_target.height; y++) {
                 for (unsigned x = 0; x < img_target.width; x++) {
                         if (!read_pixel_value ())
                                 return LXe_IO_ERROR;
1
2
3
4
                         rc = dst.SetPixel (x, y, LXiIMP_RGB24, pixel_value ());
                         if (LXx_FAIL (rc))
                                 return rc;
                 }
1
2
3
4
                 rc = mon.Step ();
                 if (LXx_FAIL (rc))
                         return rc;
         }
1
2
         return LXe_OK;
 }

Loader::Cleanup()

Cleanup() is called after a recognize/load cycle completes, and allows the loader to reset its state for another attempt to load a file. The possible call sequences are:

# File not recognized: #* Recognize() – returns failure #* Cleanup() # File loaded right away: #* Recognize() – returns success #* LoadObject() #* Cleanup() # File loaded after options: #* Recognize() – returns success #* Cleanup() #* LoadObject() #* Cleanup()

1
2
3
4
5
6
7
         LxResult
 load_Cleanup (
         LXtLoadAccess         *load)     LXx_OVERRIDE
 {
         close_file_if_open ();
         return LXe_OK;
 }

Helper Classes

The CLxSceneLoader class can be used to write scene loaders. See scene (lxu-scene.hpp).

See also