SeExpr Plugins

Writing Custom Expression Plugins

Writing Custom Expression Plugins

The steps are:
  1. Create a ".cpp" source file with one or more functions.
  2. Define an SeExprPluginInit function.
  3. Compile the plugin.
  4. Add the plugin to the $SE_EXPR_PLUGINS path.

1. Create a ".cpp" source file with one or more functions.

Here's a trivial example, myfunc.cpp:

#include "SeExprFunc.h"
#include "SeExprBuiltins.h"

double myfunc(double a, double b, double c)
{
    return a * b + c;
}

2. Define an SeExprPluginInit function.

This is also in myfunc.cpp:

extern "C" void SeExprPluginInit(SeExprFunc::Define define)
{
    define("myfunc", myfunc);
}

3. Compile the plugin.

Here's a sample Makefile:

myfunc.so : myfunc.cpp $(shell pathfinder find_first "lib64/libSeExpr.so")
    $(CXX) -O2 -I$(shell pathfinder find_package SeExpr)/include -shared -o $@ $^

Or, you can just run the compiler directly:

g++ -O2 -I$(shell pathfinder find_package SeExpr)/include -shared -o myfunc.so myfunc.cpp $(shell pathfinder find_first "lib64/libSeExpr.so")

Note: there are both static (.a) and dynamic (.so) versions of the expression library available.  If you link with the static version, your plugin will be slightly larger, but you'll be insulated from changes to the expression library.  To use the static version, just change libSeExpr.so to libSeExpr.a on the command line above.

4. Add the plugin to the $SE_EXPR_PLUGINS path.

The $SE_EXPR_PLUGINS environment variable contains a colon-separated list of plugin filenames and/or names of directories containing plugins.  If a directory name is used, the plugin name must match the pattern "SeExpr*.so".  If the plugin is explicitly listed, it may be named anything.

setenv SE_EXPR_PLUGINS $PWD/myfunc.so

Note: the ctaddenv command can be used in a shell script to add the plugin without worrying whether SE_EXPR_PLUGINS is already defined or not:

setenv SE_EXPR_PLUGINS `ctaddenv SE_EXPR_PLUGINS $PWD/myfunc.so`

Supported function types:

scalar result, no args
double myfunc()
scalar result, 1 arg
double myfunc(double)
scalar result, 2 args double myfunc(double, double)
scalar result, 3 args double myfunc(double, double, double)
scalar result, 4 args double myfunc(double, double, double, double)
scalar result, 5 args double myfunc(double, double, double, double, double)
scalar result, 6 args double myfunc(double, double, double, double, double, double)
scalar result, 1 vector arg
double myfunc(const SeVec3d&)
scalar result, 2 vector args double myfunc(const SeVec3d&, const SeVec3d&)
vector result, 1 vector arg SeVec3d myfunc(const SeVec3d&)
vector result, 2 vector args SeVec3d myfunc(const SeVec3d&, const SeVec3d&)
scalar result, variable number of args
double myfunc(int n, double* params)
scalar result, variable number of vector args double myfunc(int n, const SeVec3d* params)
vector result, variable number of vector args SeVec3d myfunc(int n, const SeVec3d* params)
Extension class (see note below)
class myfunc : public SeExprFuncX {...}

Note: the SeExprFuncX extension class can accept any type or number of args, including strings, and can produce a vector or scalar result.  Also, the extension function has access to the internal expression objects for caching data, etc.

For functions that take a variable number of arguments, the min and max argument count must be given when the function is registered:

define("brick3d", SeExprFunc(brick3d, 1, 5)); // require 1..5 args

Note: the maxargs param can be set to -1 to allow an unlimited number of arguments:

define("foo", SeExprFunc(foo, 4, -1)); // require at least 4 args

Detailed Example

#include "SeExprFunc.h"
#include "SeExprBuiltins.h"

// provide access to SeExpr built-in functions
using namespace SeExpr;

// wrapper to allow calling noise with 1 argument
double noise(const SeVec3d& P)
{
    return noise(1, &P);
}

// wood(vector P)
double wood(const SeVec3d& P)
{
    double noiseP = noise(P)*4;
    double noiseP15 = noise(P*15)/16;
    double noiseP50 = noise(P*50);

    double L = length(P*10 + noiseP + noiseP15 + SeVec3d(40,60,20));
    double Lf = fmod(L, 1);

    return mix(pow(noise(P*60 + noiseP) + noiseP15, 2) *
               cellnoise(L - 0.1) * 0.5 + 0.25,
               invert(pow(invert(noiseP50),2)),
               smoothstep(0, .1, Lf) *
               smoothstep(.2, 1, invert(Lf)));
}

// brick3d(vector P, float type=1), type can be 1 or 2.
double brick3d(int nargs, const SeVec3d* args)
{
    SeVec3d p = 0.0;
    int type = 1;
    switch (nargs) {
    case 2: type = int(args[1][0]);
    case 1: p = args[0];
    }

    double p0 = -0.05 + p[0]/31.8;
    double p1 = p[1]/24;
    double p2 = -0.05 + p[2]/31.8;
    double t1 = trunc(101 + (p1 + 100) * 7) / 2;
    double t2 = trunc(100 + (p1 + 100) * 7) / 2;
    if (type==1)
    {
        double val =
            smoothstep(0, 0.15, fmod((p0 + 100) * 3 + t1, 1)) *
            smoothstep(0, 0.15, fmod((p2 + 100) * 3 + t2, 1)) *
            smoothstep(0, 0.15, fmod((invert(p0) + 100) * 3 + t1, 1)) *
            smoothstep(0, 0.15, fmod((invert(p2) + 100) * 3 + t2, 1)) *
            smoothstep(0, 0.3,  fmod((p1 + 100) * 7, 1)) *
            smoothstep(0, 0.3,  fmod((invert(p1) + 100) * 7, 1));
        return pow( invert( val ), 8 );
    }
    else if (type==2)
    {
        float result;
        SeVec3d cell;
        cell[0] = (p0 + 100) * 3 + t1;
        cell[1] = (p1 + 100) * 7;
        cell[2] = (p2 + 100) * 3 + t2;
        return cellnoise(cell);
    }
    return 0;
}

extern "C" void SeExprPluginInit(
SeExprFunc::Define define)
{
    define("wood", wood);
    define("brick3d", SeExprFunc(brick3d, 1, 2));
}


Generated on 25 Jul 2013 for SeExpr by  doxygen 1.6.1