Short Contents

9.4 DSO Shadeops

It is possible to extend the capabilities of the shading language by calling C or C++ functions from inside shaders. When compiling a shader, if the compiler encounters a function it doesn't now, it automatically searches all the directories specified by the `-I' command line option (see section Using the Shader Compiler - shaderdl) looking for a DSO containing a definition of the unknown function.
A DSO must contain a data table for each shadeop it implements. One such table simply describes the possible return values of the shadeops and its init and cleanup functions.

All this is better explained by an example:

#include "shadeop.h"
#include <stdio.h>

/*
  A simple DSO shadeops.
	
  Notes that 'extern "C"' is not necessary for '.c' files.
  Only c++ files need that.
*/

extern "C" {
	SHADEOP_TABLE(sqr) =
	{
		{"float sqr(float)", "sqr_init", "sqr_cleanup"},
		{"point sqr_p(point)", "sqr_init", "sqr_cleanup"},
		{""}
	};
}

extern "C" SHADEOP_INIT(sqr_init)
{
	return 0x0; /* No init data */
}

/*
	returns the given float, squared.
	
	NOTES
	- argv[0] contains a pointer to the result, in this case a float.
	- 
*/
extern "C" SHADEOP( sqr )
{
	float *result = (float *)argv[0];
	float f = *((float*)argv[1]);
	*result = f * f;

	return 0;
}

/*
	returns the given point, squared.
*/
extern "C" SHADEOP(sqr_p)
{
	float *result = (float *)argv[0];
	float *f = ((float*)argv[1]);

	result[0] = f[0] * f[0];
	result[1] = f[1] * f[1];
	result[2] = f[2] * f[2];

	return 0;
}

extern "C" SHADEOP_CLEANUP( sqr_cleanup )
{
	/* Nothing to do */
}

Here is how to compile a DSO under different environments:

Linux
g++ -shared -o sqr.so -I$DELIGHT/include sqr.cpp
IRIX
CC -shared -o sqr.so -I$DELIGHT/include sqr.cpp
MacOS X
g++ -dynamiclib -o sqr.so -I$DELIGHT/include sqr.cpp
Windows
cl -I"%DELIGHT%/include" -LD sqr.cpp

To avoid memory leaks, use the macro ASSIGN_STRING (declared in `shadeop.h' code to copy strings as return values. This macro deletes (if needed) the old string before assigning the new one. This macro also ensures that the memory managment is done by the 3Delight library only, which is important on Windows platforms where different (and incompatible) memory managment functions may coexist. Here is an example that illustrates how to use the macro:

SHADEOP_TABLE(test) =
{
    {"string teststring(string)", "", ""},
    {""}
};

extern "C" SHADEOP(teststring)
{
    const char **res = (const char **)(argv[0]);
    const char **arg1 = (const char **)(argv[1]);

    ASSIGN_STRING(*res, "Hello");
    ASSIGN_STRING(*arg1, "World");
}

3Delight 8.5. Copyright 2000-2009 The 3Delight Team. All Rights Reserved.