Clarisse 5.0 SP8 SDK  5.0.5.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Embedding Clarisse in C++ Host

Table of Contents

Clarisse SDK provides a special static library clarisse_engine which allows to embed Clarisse in custom C++ applications. Embedding Clarisse engine can be very useful if you are looking manage scenes or to launch renders, for example, in external application.

Licensing requirement

Creating a Clarisse Engine instance requires a free CNode license. If no CNode license is available, your application will fail to create a ClarisseEngine instance. Moreover, you should note that embedding Clarisse Engine in 3rd party applications requires a special license agreement. For more information, please contact suppo.nosp@m.rt@i.nosp@m.sotro.nosp@m.pix..nosp@m.com.

Linking to Clarisse Engine library

To embed Clarisse, you must link your application or plugin to clarisse_engine static library which is provided with Clarisse SDK files. To use Clarisse Engine you must include the file clarisse_engine.h which defines both ClarisseEngine and ClarisseEngineHandler classes.

What is a Clarisse Engine instance?

An instance of Clarisse Engine is an interface to a Clarisse application running in a background thread attached to the running process. Due to the massively parallel nature of Clarisse core, Clarisse Engine comes with the limitation of not being able to make directly fully safe Clarisse API calls within the execution of your main process. To make your Clarisse API calls you must provide a ClarisseEngineCallback and use ClarisseEngineHandler::execute which handles synchronicity issues.

Depending on your needs, ClarisseEngineHandler::execute provides two modes of execution: one synchronous (which means the call is blocking) and a second asynchronous one.

Creating a Clarisse Engine instance

The first thing you must do is to create an instance of ClarisseEngine by calling ClarisseEngine::create. Note that there can't be multiple instances of ClarisseEngine per application. Once the instance of Clarisse Engine has been created, the pointer to the running Clarisse Engine can be retrieved using ClarisseEngine::get_engine.

Please also note that once the instance of ClarisseEngine is created it must be used throughout the lifetime of the host process as an application can only create a single single instance of Clarisse Engine. This means that calling ClarisseEngineHandler::quit will prevent you of any further use of ClarisseEngine in your application.

The following example creates a Clarisse Engine instance and loads a project:

#include <core.h>
#include <app_object.h>
#include <clarisse_engine.h>
// Load project callback arguments
struct LoadProjectArgs {
CoreString filename;
bool ret;
};
// Load project callback
void
load_project(AppObject& app, void *data)
{
// getting arguments
LoadProjectArgs *args = (LoadProjectArgs *) data;
args->ret = app.load_project(args->filename);
}
int
main(int argc, char **argv)
{
// Creating Clarisse engine instance with no argc, argv but specifying the location of Clarisse modules
ClarisseEngineHandler *engine = ClarisseEngine::create(0, 0, "./module");
LoadProjectArgs args;
args.filename = "/path/to/my/clarisse.project";
engine->execute(ClarisseEngineHandler::EXEC_MODE_SYNC, load_project, &args);
if (!args.ret) {
LOG_INFO("Failed to load specified project file\n");
}
// Quitting Clarisse Engine to free up all ressources
clarisse_engine->quit();
return 1;
}

A more complete example

As we could see on the previous example, working exclusively with callbacks could be somewhat daunting for developers because of its lack of visibility. What we recommend you is to organize your code differently by creating a API handling callback wrapping to write clearer code specially if you have to share your code with others. In the next example we will:

  1. create 2 callbacks one to load a project and a second one to render an image of the project
  2. create a wrapper class
  3. create a Clarisse Engine instance
  4. use the wrapper class to load and render an image
#include <core.h>
#include <app_object.h>
#include <clarisse_engine.h>
#include <image_handle.h>
#include <module_image.h>
// Load project callback arguments
struct LoadProjectArgs {
CoreString filename;
bool ret;
};
// Load project callback
void
load_project(AppObject& app, void *data)
{
// getting arguments
LoadProjectArgs *args = (LoadProjectArgs *) data;
args->ret = app.load_project(args->filename);
}
// Render image callback arguments
struct RenderImageArgs {
CoreString image;
ImageHandle render;
bool ret;
};
// Render image callback
void
render_image(AppObject& app, void *data)
{
// getting arguments
RenderImageArgs *args = (RenderImageArgs *) data;
args->ret = false;
// checking if the specified item exists in the project
OfItem *item = app.get_factory().item_exists(args->image);
if (item != 0 && item->is_object()) {
OfObject *image_object = item->to_object();
// checking if the specified item is an Image
if (image_object->is_kindof("Image")) {
ModuleImage *image_module = (ModuleImage *) image_object->get_module();
// checking if the image needs to be computed
if (image_module->is_image_dirty(ModuleImage::QUALITY_FULL)) {
// request to evaluate the image at maximum quality without progressive rendering
image_module->compute_image(ModuleImage::QUALITY_FULL, ModuleImage::QUALITY_FULL, 0, false);
}
// wait the render to be completed
while (image_module->is_image_dirty(ModuleImage::QUALITY_FULL)) {
// call the event loop to minimize CPU usage
}
// retrieve the rendered image
args->render = image_module->get_image(ModuleImage::QUALITY_FULL);
args->ret = true;
} else {
LOG_ERROR("The specified item '" << args->image << "' isn't of class Image.\n");
}
} else {
LOG_ERROR("The specified item '" << args->image << "' doesn't exist.\n");
}
}
class MyClarisseEngineAPI {
public:
MyClarisseEngineAPI(ClarisseEngineHandler& engine) : m_engine(engine) {}
bool load_project(const CoreString& filename) const {
LoadProjectArgs args;
args.filename = filename;
m_engine.execute(ClarisseEngineHandler::EXEC_MODE_SYNC, ::load_project, &args);
return args.ret;
}
ImageHandle render_image(const CoreString& image) const {
RenderImageArgs args;
args.image = image;
m_engine.execute(ClarisseEngineHandler::EXEC_MODE_SYNC, ::render_image, &args);
return args.render;
}
private:
};
int
main(int argc, char **argv)
{
// Creating Clarisse engine instance
ClarisseEngineHandler *clarisse_engine = ClarisseEngine::create(0, 0, "./module");
// Creating an instance of ClarisseEngineAPI to simplify API calls
MyClarisseEngineAPI api(*clarisse_engine);
// Loading sphere.project
api.load_project("sphere.project");
// Rendering project://scene/image
ImageHandle img = api.render_image("project://scene/image");
// Quitting Clarisse Engine
clarisse_engine->quit();
return 1;
}