Short Contents

10.2 3Delight APIs

10.2.1 The Rx API

The Rx library provides access to some useful internal functions to SL DSOs writers. Also, it allows RiProcedural writers to query internal state of the renderer.

10.2.1.1 Noise functions

There are three noise functions. They access respectively the internal implementations of noise, pnoise and cellnoise in the shading language (see section Noise and Random). They are accessible to both DSO shadeops and RiProcedural code.

RtInt RxNoise ( RtInt i_inDimension, RtFloat *i_in, RtInt i_outDimension, RtFloat *o_out )
RtInt RxPNoise ( RtInt i_inDimension, RtFloat *i_in, RtFloat *i_period, RtInt i_outDimension, RtFloat *o_out )
RtInt RxCellNoise ( RtInt i_inDimension, RtFloat *i_in, RtInt i_outDimension, RtFloat *o_out )

As input, these functions take one to four floats. The number of floats is passed by i_inDimension and the values by i_in. The expected number of dimensions as a result should be passed by i_outDimension (only one and three are accepted). It is important to provide a big enough o_out buffer to contain the output. The i_period parameter for RxPNoise should contain as many periods as there are input dimensions. A return value of `0' indicates a sucess.

RtFloat RxRandom ( )

returns a random number, exactly as the float random() shadeop.

10.2.1.2 Texture lookup functions

There are three texture lookup functions with several variants for each. They call respectively the implementations of environment, shadow and texture in the shading language (see section Texture Mapping).

RtInt RxEnvironmentPoints1 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, RtInt i_nChannels, const RtPoint *i_dir, RtFloat *o_result, ... )
RtInt RxShadowPoints1 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, const RtPoint *i_P, RtFloat *o_result, ... )
RtInt RxTexturePoints1 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, RtInt i_nChannels, const RtFloat *i_s, const RtFloat *i_t, RtFloat *o_result, ... )

Each function takes a texture name and an input point specifying the texture location to be sampled. When these are called over all the points being shaded at once, proper derivatives are automatically computed for smooth filtering. Otherwise, the corresponding function below is called with the same point duplicated four times (ie. no filtering). i_nChannels channels is retrieved starting at channel i_firstChannel in the texture i_fileName. Optional parameters (described in Table 6.16) provided as name-value pairs as accepted. Named parameters which are varying must be explicitely declared as such inline (eg. "varying float blur") or they will be read as uniform. All read channels are stored in o_result. These three functions also have their vector versions (RxEnvironmentPoints1V, RxShadowPoints1V and RxTexturePoints1V) which take a vector of tokens and a vector of values, similar to Ri calls. A return value of `0' indicates a sucess.

RtInt RxEnvironmentPoints4 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, RtInt i_nChannels, const RtPoint *i_dir0, const RtPoint *i_dir1, const RtPoint *i_dir2, const RtPoint *i_dir3, RtFloat *o_result, ... )
RtInt RxShadowPoints4 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, const RtPoint *i_P0, const RtPoint *i_P1, const RtPoint *i_P2, const RtPoint *i_P3, RtFloat *o_result, ... )
RtInt RxTexturePoints4 ( RtString i_fileName, RtInt i_nPoints, RtInt i_firstChannel, RtInt i_nChannels, const RtFloat *i_s0, const RtFloat *i_t0, const RtFloat *i_s1, const RtFloat *i_t1, const RtFloat *i_s2, const RtFloat *i_t2, const RtFloat *i_s3, const RtFloat *i_t3, RtFloat *o_result, ... )

These functions are the same as the previous three except that they take four points to explicitely specify the filtering area.

RtInt RxEnvironment ( RtString i_fileName, RtInt i_firstChannel, RtInt i_nChannels, RtPoint i_dir0, RtPoint i_dir1, RtPoint i_dir2, RtPoint i_dir3, RtFloat *o_result, ... )
RtInt RxShadow ( RtString i_fileName, RtInt i_firstChannel, RtPoint i_P0, RtPoint i_P1, RtPoint i_P2, RtPoint i_P3, RtFloat *o_result, ... )
RtInt RxTexture (RtString i_fileName, RtInt i_firstChannel, RtInt i_nChannels, RtFloat i_s0, RtFloat i_t0, RtFloat i_s1, RtFloat i_t1, RtFloat i_s2, RtFloat i_t2, RtFloat i_s3, RtFloat i_t3, RtFloat *o_result, ... )

These functions perform a single lookup at a time and do not provide automatic derivatives. They are present for compatibility and should not be used in new code when there are several lookups to perform. Using the Points version instead.

10.2.1.3 Transformation functions

There is a single space transformation function: RxTransformPoints. It looks a lot like the transform shadeop in the shading language (Geometry, Matrices and Colors), except that it passes an array of points to transform and accepts a time parameter (useful with motion blurred geometry). There is also RxTransform which allows a transformation matrix to be retrieved without actually transforming anything.

RtInt RxTransformPoints ( RtToken i_fromspace, RtToken i_tospace, RtInt i_n, RtPoint io_p[], RtFloat i_time )

The points in io_p are transformed from i_fromspace to i_tospace, at time i_time. If there is some motion blur and i_time is somewhere inside the shutter time interval, the transformation interpolates points between the two enclosing time steps. A return value of `0' means success.

RtInt RxTransform ( RtToken i_fromspace, RtToken i_tospace, RtFloat i_time, RtMatrix o_matrix )

Computes, in o_matrix, the matrix to transform points from i_fromspace to i_tospace at time i_time. A return value of `0' means success.

10.2.1.4 Message passing and info functions

These functions access state and general information. They are respectively the equivalent of attribute(), option(), rendererinfo() and textureinfo() shadeops in the shading language (see section Message Passing and Information).

RtInt RxAttribute ( RtString i_name, RtPointer o_result, RtInt i_resultLen, RxInfoType_t *o_resulttype, RtInt *o_resultcount )
RtInt RxOption ( RtString i_name, RtPointer o_result, RtInt i_resultLen, RxInfoType_t *o_resulttype, RtInt *o_resultcount)
RtInt RxRendererInfo ( RtString i_name, RtPointer o_result, RtInt i_resultLen, RxInfoType_t *o_resulttype, RtInt *o_resultcount)
RtInt RxTextureInfo ( RtString i_texture, RtString i_name, RtPointer o_result, RtInt i_resultLen, RxInfoType_t *o_resulttype, RtInt *o_resultcount)

The information i_name is retrieved and stored into o_result, which has a size of at least i_resultLen in bytes. The type is returned in o_resulttype and the number of base elements (of type RtString or RtFloat) contained in o_result is stored in o_resultcount. These two values may be useful for user defined attributes or options. For RxAttribute and RxOption, a return value N > 0 indicates that the call failed due to a too small buffer (N indicating the number of missing bytes). In this case, take a look at o_resulttype and o_resultcount for more explanations. A return value of 0 indicates a success. A negative return value indicates an error.

10.2.1.5 File functions

RtString RxCacheFile ( RtString i_filename )

This function allows access to 3Delight's network cache (see section Network Cache). When the network cache is enabled, the given file is cached and a path to the cached file is returned. If caching fails, is disabled or is not required, i_filename is returned. This function is useful when the caching of extra resources is necessary due to excessive network loads. Example resources that could benefit from caching:

  • Scene data. Such as Maya scene files or specific custom DSO data.
  • Executables. Executing files through the network is a non negligible part of the total network traffic.

Note that 3DELIGHT already caches RIB archives so caching them using this call is not a good idea.

RtString RxFindFile ( RtString i_category, RtString i_filename )

This function allows access to 3Delight's searchpath system. It will look for the requested file in the searchpaths of the given category (as given by the "searchpath" option). It will also apply any required directory mapping (see section Search Paths Options).

10.2.1.6 Example

Here is a simple example of a DSO using the RxTexture function. Note that the `rx.h' file is included instead of the `ri.h' file.


#include "shadeop.h"
#include "rx.h"

/*
	A simple DSO shadeop using the Rx Library

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

extern "C"
{
	SHADEOP_TABLE(rxTexture) =
	{
		{"color rxTexture(string, float, float, float, float, float, "
		 "float, float, float, float)", "rx_init", "rx_cleanup"},
		{""}
	};
}

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

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

/*
	Given a texture file, texture coordinates and a width,
	return texture color using a gaussian filter.
	Note that the filename in argv[1] is a pointer of a string.
*/

extern "C" SHADEOP(rxTexture)
{
	RtString filter = "gaussian";
	
	return RxTexture(
		*((RtString *)argv[1]), 0, 3,
		*((RtFloat *) argv[2]), *((RtFloat *) argv[3]),
		*((RtFloat *) argv[4]), *((RtFloat *) argv[5]),
		*((RtFloat *) argv[6]), *((RtFloat *) argv[7]),
		*((RtFloat *) argv[8]), *((RtFloat *) argv[9]),
		(RtFloat *) argv[0],
		"width", (RtFloat*)argv[10],
		"filter", &filter,
		0);
}

The DSO has to be compiled with the `-shared' flag activated, as shown below for each platform:

Linux
g++ -shared -o rxexample.so -I$DELIGHT/include rxexample.cpp
MacOS X
g++ -dynamiclib -o rxexample.dylib -I$DELIGHT/include rxexample.cpp
Windows
cl -I"%DELIGHT%/include" "%DELIGHT%/lib/3delight.lib" -LD rxexample.cpp

10.2.2 The Gx API

This API allows the evaluation of RenderMan geometry. The design principal is to provide the user with an interface that is easy to use and coherent with the rest of the RenderMan protocol. All geometry types that are supported by 3Delight can be evaluated using this API, this includes: subdivision surfaces (including hierarchical subdivision surfaces), polygons, NURBS, conics, ... Etc. To use the interface one must include the `gx.h' header file.

10.2.2.1 Entry Points

GxGeometryHandle GxGetGeometry ( RtObjectHandle i_object, ... )
GxGeometryHandle GxGetGeometryV ( RtObjectHandle i_object,

RtInt i_n, RtToken i_tokens[], RtPointer i_params[] );

Prepares a stored object for processing with this API. The object must be declared using a RiObjectBegin/RiObjectEnd block. The i_object parameter is the one returned by RiObjectBegin.

void GxFreeGeometry ( GxGeometryHandle i_geo )

Release memory and resources that have been allocated by GxGetGeometry. This should be done when the object and all the other resources derived from it will no longer be used.

unsigned GxGetFaceCount ( GxGeometryHandle i_geo )

Returns the number of faces for a given piece of geometry. This can be different from what is specified through the RI interface as 3Delight may transform some types of geometry into a different internal representation.

int GxCreateSurfacePoint ( GxGeometryHandle i_geo, unsigned i_face, float i_u, float i_v, float i_time, GxSurfacePoint *o_point )

Initializes a surface point handle directly with a face number of parametric coordinates on the face. Parameters are:

i_geo
The geometry to evaluate.
i_face
The face number. Must be in the [0 .. GxGetFaceCount(i_geo)[ range.
u
v
The parametric coordinates on the face (local to the face).
i_time
Time. Currently unimplemented(71).
o_point
A pointer to the handle to be initialized. The initialized handle must be cleaned up with FreeSurfacePoint or resources will leak.

Possible return values all:

RIE_NOERROR
Everything went well.
RIE_RANGE
Invalid face id.
RIE_BADHANDLE
Invalid i_geo.
void GxFreeSurfacePoint ( GxSurfacePoint i_point )

Releases the memory associated with a surface point handle that was previously allocated by GxCreateSurfacePoint.

int GxEvaluateSurface ( unsigned i_npoints, GxSurfacePoint *i_points, RtToken i_variable, unsigned i_width, float *o_values )

Evaluates a primitive variable at the given surface points.

i_npoints
Length of the i_points array.
i_points
A pre-allocated array of GxSurfacePoints.
i_variable
The name of the primitive variable to evaluate (eg. "P"). Any primitive variable that is attached to the geometry can be evaluated using this function. Note that "dPdu", "dPdv", "N" and "Ng" can always be passed to this function (these variables are inherent to the geometry and don't have to be passed as a primitive variable).
i_width
The number of components of i_variable (eg. 3 for "P").
o_values
A buffer to receive the results. This should be i_npoints * i_width long.

Possible return values are:

RIE_NOERROR
Everything went well.
RIE_BADHANDLE
At least one the the evaluation points is invalid.
RIE_MISSINGDATA
The provided token (i_varibale) cannot be found in the geometry.
RIE_CONSISTENCY
i_width is not equal to the with of the primitive variable declared in the geometry.
RIE_BADTOKEN
i_variable is of type RtString so it cannot be evaluated.

10.2.2.2 Example Usage

A complete example can be found in `$DELIGHT/examples/gx'. The directory contains code for a procedural that transforms RenderMan geometry into particles. To run the example of a Linux or Mac OS X system, open a shell and execute the following commands:

cd $DELIGHT/examples/gx
make

A framebuffer should popup and some primtives will be rendered as points. The primitives are all described in `points.rib'.

10.2.3 The Sx API

This API allows the evaluation of RenderMan shaders on arbitrary user data. The API doesn't expect any scene description so its usable from a variety of contexts. Usage examples include:

The library operates in SIMD so many points can be evaluated at once.

10.2.3.1 Entry Points

SxContext SxCreateContext ( SxContext i_parent = 0 )

Creates a shader evaluation context.

i_parent
Specifies the parent context.
void SxDestroyContext ( SxContext io_context )

Destroys the provide io_context.

void SxSetOption ( SxContext i_context, const char* i_optionName, SxType i_optionType, SxData i_values, unsigned i_arraySize )
void SxSetAttribute ( SxContext i_context, const char* i_optionName, SxType i_optionType, SxData i_values, unsigned i_arraySize )

Sets a rendering option or attribute in the given context. All options are accessible from inside the shader through the option() and attribute() shadeops (see section Message Passing and Information). This is similar in spirit to the RiOption and RiAttribute RenderMan commands.

i_context
The SxContext as returned by SxCreateContext().
i_optionType
Type of the option.
i_values
Pointer to the actual values.
i_arraySize
Total number of elements in the array (0 if the variable is not an array).

Note that all options are uniform.

void SxDefineSpace ( SxContext i_context, const char* i_spaceName, float *i_matrix )

Binds a matrix to the specified space in the specified context. Any name can be specify except `current' which is reserved by this library. This function must be called before SxCreateShader for each space of interest for the new shader.

SxParameterList SxCreateParameterList ( SxContext i_context, unsigned i_numPoints, const char* i_spaceName )

Creates a parameter list for use in either intializing a shader instance or running a shader on a set of points. i_numPoints specifies the number of values for varying parameters when evaluating the shader. If the list is used to create a shader then this should be 1 as only the first value is use to set the shader's intance parameters. The optional i_spaceName indicates the space in which the parameters are declared (this matters in case of points, vectors, normals and matrices). It defaults to "shader" if the list is used to create a new shader and "current" if it is used to evaluate a shader. The parameter list will be automatically freed when the context specified by i_context is destroyed. However, SxDestroyParameterList() may also be used to destroy the parameter list earlier. This is mostly useful for the list passed to SxCallShader().

void SxSetParameterListGridTopology ( SxParameterList i_paramList, unsigned i_numGrids, const unsigned *i_uRes, const unsigned *i_vRes )

Sets a parameter list to be interpreted as grids instead of independent points. i_uRes and i_vRes are two arrays of i_numGrids values which specify the number of points of each grid in both axis. Using this function affects the behavior of area and filtered functions in the shader.

void SxSetPredefinedParameter ( SxParameterList i_paramList, const char* i_predefParamName, SxData i_values, bool i_varying = true )

Sets (or adds) a predefined variable to the specified parameter list. Predefined parameters are P, u, v, etc ...

i_paramList
Specified parameter list
i_predefParamName
Predefined variable's name
i_values
Predefined variable's values
i_varying
Predefined variable's class (optional). True for varying, false for uniform.
void SxDestroyParameterList ( SxParameterList i_parameterList )

Destroys a previous constructed parameter lists.

SxShader SxCreateShader ( SxContext i_context, SxParameterList i_paramList, const char *i_shaderName, const char *i_shaderHandle )

Creates a shader in the specified context.

i_context
The context where the shader is created and to which it will belong.
i_paramList
The parameter list which contains the shader instance parameter values. These are the values which will not change for different calls to the shader. This parameter may be null if no list is needed.
i_shaderName
The name of the shader file to load (without the .sdl part).
i_shaderHandle
The name by which the shader will be referenced. This should be null for shaders which you do not intend to use as co-shaders.
unsigned SxGetNumParameters ( SxShader i_shader )

Returns the number of parameters declared for the specified shader.

unsigned SxGetPredefinedParameters ( SxShader i_shader, const char* o_names[], unsigned i_maxNames )

Returns the number of predefined parameters needed by i_shader and fills o_names with pointers to their names.

i_shader
The shader of interest.
o_names
An array that will be filled with the parameters' names. May be null when i_maxNames is set to 0.
i_maxNames
The maximum number of strings that can be written to o_names. It can be useful to set this parameter to 0 when only the number of predefined parameters (and not their names) is needed.
const char* SxGetParameterInfo ( SxShader i_shader, unsigned i_index, SxType* o_type, bool* o_varying, SxData* o_defValues, unsigned * o_arraySize, const char** o_spaceName = 0, bool* o_output = 0 )

Returns parameter's name and all information about the parameter which matches the specified index for the specified shader.

i_shader
The shader of interest.
i_index
Specified index
o_type
Parameter's type (would be one of SxFloat, SxPoint, SxColor, SxString, SxMatrix, SxVector or SxNormal).
o_varying
Parameter's class (would be true for varying, false for uniform).
o_defValues
Parameter's default values.
o_arraySize
Parameter's array size. Would be 0 if not an array.
o_spaceName
Parameter's space for the default value (optional).
o_output
Parameter's output state (optional). Would be true for output, false otherwise.
unsigned SxGetParameter ( SxParameterList i_paramList, const char* i_paramName, SxData* o_values )

Returns the number of values associated with the specified output variable.

i_paramList
The parameter list from which to retrieve values. Normally this will be a list which was passed to SxCallShader.
i_paramName
Variable's name.
o_values
Values of the predefined or output variable.
bool SxCallShader ( SxShader i_shader, SxParameterList i_paramList )

Calls (executes) a shader.

i_shader
Shader to evaluate.
i_paramList
Parameter list to use (created by SxcreateParameterList).

Result of the evaluation can be queried using the SxGetParameter() function on i_paramList. The shader is run with the lights and co-shaders which were created in the same Sx context. Any light shader created is added to the active light list and any shader created with a non null handle name is added to the co-shaders list.

10.2.3.2 Example Usage

10.2.4 The Point Cloud API

An easy to use C++ API is provided with 3Delight to read and write point cloud files as those generated by the bake3d() shadeop. To use the API, one has to include the `pointcloud.h' header file that is distributed in the package and link the application with the 3Delight library (see section Linking with 3Delight).

10.2.4.1 Point Cloud API Data Types

Only one type is defined in `pointcloud.h'

typedef void * PtcPointCloud

This typedef is used as a handle to a point cloud file on disk.

10.2.4.2 Point Cloud Reading

PtcPointCloud PtcSafeOpenPointCloudFile ( const char *filename )

This function opens a given file for reading and returns a file handle than shall be used in other reading calls.


PtcPointCloud PtcOpenPointCloudFile ( const char *filename, int *nvars, const char **vartypes, const char **varnames )

This function opens a given file for reading and returns a file handle than shall be used in other reading calls.

filename
The complete path to the point cloud file
nvars
A pointer to an int that will be filled with the total number of channels in the point cloud file.
varnames
A pointer to an array of const char * that will hold the name of each variable.
vartypes
A pointer to an array of const char * that will hold the type of each variable. Types are string representing the type of the variable as declared in the shading language (color, point, float, normal, … etc).

This function could fail if the file is not accessible or is not a valid point cloud file, in which case null is returned. Data allocated by this function is managed by the library and not user intervention is necessary to deallocate it.

NOTE

This API call is badly designed since the caller cannot know the size of vartypes and varnames in advance. But for compatibly reasons with other software we decided to provide this API entry. A safe way to open a point-cloud file is to call PtcSafeOpenPointCloudFile() and then call PtcGetPointCloudInfo() to get nvars, varnames and vartypes.

int PtcGetPointCloudInfo ( PtcPointCloud pointcloud, const char *request, void *result )

This function returns informations about a point cloud file. Accepted requests are:

pointcloud
A handle to the point cloud file as returned by PtcOpenPointCloudFile
request
The name of the information needed. The following requests are accepted:
` npoints'
Number of points in the point cloud file. C++ data type is int
` bbox'
The bounding box of the point cloud. Will return an array of six floats: min x, min y, min z, max x, max y and max z.
` datasize'
` pointdatasize'
The number of floats needed to store each data point. C++ data type is int.
` world2eye'
The world to eye (world to camera) transformation matrix. Will return an array of 16 floats.
` world2ndc'
The world to NDC transformation matrix. Will return an array of 16 floats.
` format'
The resolution of the render that generated the point cloud file. Three floats will be returned: x resolution, y resolution and aspect ratio.
` nvars'
Total number of variables attached to each point. In this case, result is considered to be of type int *.
` varnames'
` pointvarnames'
The name of each variable. In this case, result is considered to be of type char **.
` vartypes'
` pointvartypes'
The type of each variable. In this case, result is considered to be of type char **.
result
A pointer to an array large enough to hold the returned informations.

Returns 1 if the request is successful, 0 otherwise.

NOTE

Some point cloud files generated with older 3Delight versions may not contain the `format' information.

int PtcReadDataPoint ( PtcPointCloud pointcloud, float *point, float *normal, float *radius, float *user_data )

Reads next point from the point cloud file. The parameters are:

pointcloud
The handle to the point cloud file as returned by PtcOpenPointCloudFile.
point
A pointer to a point (three floats) that will be filled with current point's position.
normal
A pointer to a point (three floats) that will be filled with current point's normal.
radius
A pointer to float that will be filled with point's radius. The area of the micro-polygon that generated this sample is radius * radius * PI.
user_data
A pointer to a user buffer of a size big enough to hold all the variables attached to a point. The size of the buffer, in floats, can be obtained by calling PtcGetPointCloudInfo with request set to `datasize'.

Returns 1 if the operation is successful, 0 otherwise.

NOTE

point, normal, radius and user_data can be null if their value is not neede.

void PtcClosePointCloudFile ( PtcPointCloud pointcloud )

Closes a file opened with PtcOpenPointCloudFile. This function releases all memory allocated by PtcOpenPointCloudFile.

10.2.4.3 Point Cloud Writing

PtcPointCloud PtcCreatePointCloudFile ( const char *filename, int nvars, const char **vartypes, const char **varnames, float *world2eye, float *world2ndc, float *format)

Creates the specified point cloud file. If the point cloud file already exists, it will be overwritten.

filename
Complete path to point cloud file.
nvars
Number of variables to save in the point cloud.
vartype
A type for each variable. Types are the same as in the shading language: point, normal, color, float, matrix ... Etc.
varname
A name for each variable.
world2eye
A world to camera transformation matrix.
world2ndc
A world to NDC transformation matrix.
format
The X resolution, Y resolution and aspect ratio of the image.
int PtcWriteDataPoint ( PtcPointCloud pointcloud, float *point, float *normal, float radius, float *data)

Adds a point, along with its data, to a point cloud file.

pointcloud
A handle to a point cloud file as returned by PtcCreatePointCloudFile.
point
normal
radius
Position, orientation and radius of the point and data. point and normal cannot be null.
data
Array of floats containing data for all variables, continuously in memory. The data must be of the same size as the sum of sizes of the variables passed to PtcCreatePointCloudFile.

Returns 1 if the operation is successful, 0 otherwise.

void PtcFinishPointCloudFile ( PtcPointCloud pointcloud)

Writes out all data to disk and closes the file.

10.2.4.4 API Example

An example is available in `$DELIGHT/examples/ptc2rib' directory. This simple application transforms a point cloud file into a RIB that is renderable using renderdl. An example usage is:

ptc2rib cloud.ptc | renderdl -d

10.2.5 The Slo API

Shader interrogation is possible by using the shaderinfo command line tool (see section Using shaderinfo to Interrogate Shaders). It is also possible to "manually" interrogate shaders by using a number of calls implemented in `lib3delight'. The interrogating application should include `slo.h' (found in `$DELIGHT/include') and link with `lib3delight' (see section Linking with 3Delight).

Here is the complete list for shader interrogation calls:

void Slo_SetPath ( char* i_path )

Set the paths where the library looks for shaders. It accepts a colon separated list of paths. Refer to Search Paths Options for more information on search paths which also applies to this function.

int Slo_SetShader ( char* i_name )

Find and open the shader named i_name. Close any shader that was previously opened by Slo_SetShader. Returns 0 when the shader was successfully loaded.

char* Slo_GetName ( void )

Returns the name of the currently opened shader.

SLO_TYPE Slo_GetType ( void )

Return the type of the currently opened shader. See the file `slo.h' for details about SLO_TYPE.

int Slo_GetNArgs ( void )

Return the number of parameters accepted by this shader.

SLO_VISSYMDEF* Slo_GetArgById ( int i )

Return information about the i-th parameter of the shader. The first parameter has an id of 1. See `slo.h' for details about SLO_VISSYMDEF structure.

SLO_VISSYMDEF* Slo_GetArgByName ( char *i_name )

Return information about the parameter named i_name. See the file `slo.h' for details about SLO_VISSYMDEF.

SLO_VISSYMDEF* Slo_GetArrayArgElement ( SLO_VISSYMDEF *i_array, int i_index )

If a parameter is an array (as specified by Slo_GetArgById() or Slo_GetArgByName), each of its element should be accessed using this function.

int Slo_GetNAnnotations ( void )

Return the number of annotations contained in this shader. Annotations are further discussed in Attaching annotations to shaders.

char* Slo_GetAnnotationKeyById ( int i_id )

Returns an annotation key by it's index i_id. Acceptable indexes range from 1 to n, where n is the number of annotations available. Any index outside this range returns 0x0 (null pointer).

char* Slo_GetAnnotationByKey ( const char *i_key )

Returns an annotation specified by it's key. If i_key doesn't refer to any annotation, 0 (null pointer) is returned. It is possible to retrieve the different possible keys with Slo_GetAnnotationKeyById.

void Slo_EndShader ( void )

Close the current shader.

char* Slo_TypetoStr ( SLO_TYPE i_type )

Get a string representation of type i_type.

char* Slo_StortoStr ( SLO_STORAGE i_storage )

Get a string representation of storage class i_storage.

char* Slo_DetailtoStr ( SLO_DETAIL i_detail )

Get a string representation of variable detail i_detail.

const char*const* Slo_GetMethodNames ( )

Returns a null terminated array of strings containing the names of the methods in the current shader.

Next is the complete source code of the shaderinfo utility, it is compilable on all supported platforms, see Linking with 3Delight.

/******************************************************************************/
/*                                                                            */
/*    Copyright (c)The 3Delight Team.                                         */
/*    All Rights Reserved.                                                    */
/*                                                                            */
/******************************************************************************/

// ===========================================================================
// = VERSION
//     $Revision$
// = DATE RELEASED
//     $Date$
// = RCSID
//     $Id$
// ===========================================================================

#include "slo.h"
#include "dlMsgShaderInfo.h"
#include "dlVersion.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <assert.h>

typedef enum
{
	e_prman = 1,
	e_ribout,
	e_table,
	e_source,
	e_annotations,
	e_methods
} Format;

void PrintDefaultValue( const SLO_VISSYMDEF* arg )
{
	switch(arg->svd_type)
	{
	case SLO_TYPE_SCALAR:
		printf( "%g", *arg->svd_default.scalarval );
		break;
	case SLO_TYPE_STRING:
		printf( "%s", arg->svd_default.stringval );
		break;
	case SLO_TYPE_POINT:
	case SLO_TYPE_COLOR:
	case SLO_TYPE_VECTOR:
	case SLO_TYPE_NORMAL:
		printf( "%g %g %g",
			arg->svd_default.pointval->xval,
			arg->svd_default.pointval->yval,
			arg->svd_default.pointval->zval );
		break;
	case SLO_TYPE_MATRIX:
	{
		unsigned i=0;
		for( ; i < 15; ++i )
			printf( "%g ", arg->svd_default.matrixval[i] );
		printf( "%g", arg->svd_default.matrixval[i] );
		break;
	}
	case SLO_TYPE_SHADER:
		printf( "nil" );
		break;

	default: ;
	}
}

/*
	Function to print one parameter.
*/
void PrintOneParameter( const SLO_VISSYMDEF *parameter, const Format i_format )
{	
	const char *storage = Slo_StortoStr( parameter->svd_storage );
	const char *name = parameter->svd_name;
	const char *detail = Slo_DetailtoStr( parameter->svd_detail );
	const char *type = Slo_TypetoStr( parameter->svd_type );
	unsigned arraylen = parameter->svd_arraylen;
	bool is_array = parameter->svd_isarray;

	if( i_format == e_ribout )
	{
		/* Output a string suitable for RIB syntax */

		if( !is_array )
			printf( "Declare \"%s\" \"%s %s\"\n", name, detail, type );
		else
			printf( "Declare \"%s\" \"%s %s[%d]\"\n",
					name, detail, type, arraylen );

		return;
	}
	else if( i_format == e_table )
	{
		printf( "%s,%s,%s,%s,%s,%d,",
				name, storage, detail, type,
				parameter->svd_spacename[0] ?
				parameter->svd_spacename : "<none>",
				arraylen );

		/* Print all default values */
		if( !is_array )
		{
			PrintDefaultValue( parameter );
		}
		else
		{
			for( int i = 0; i < parameter->svd_arraylen; i++ )
			{
				if( i != 0 )
				{
					printf( " " );
				}
				PrintDefaultValue(
					Slo_GetArrayArgElement((SLO_VISSYMDEF *)parameter, i) );
			}
		}

		printf( "\n" );
		return;
	}

	assert( i_format == e_prman );

	printf( "    \"%s\" \"%s %s %s", name, storage, detail, type );

	if( is_array )
	{
		if( arraylen == 0 )
			printf( "[]" );
		else
			printf( "[%d]", arraylen );
	}

	printf( "\"\n" );
	printf( "\t\t%s", DlGetText(DlText_1725_default) );

	switch( parameter->svd_type )
	{
		case SLO_TYPE_COLOR:

			// Even if color has a different spacename,
			// it has been converted by evaluation.

			printf( "\"rgb\" ");
			break;

		case SLO_TYPE_POINT:
		case SLO_TYPE_VECTOR:
		case SLO_TYPE_NORMAL:
		case SLO_TYPE_MATRIX:

			if( parameter->svd_spacename[0] != (char)0 )
				printf( "\"%s\" ", parameter->svd_spacename );

			break;

		default:
			break;
	}

	if( is_array )
	{
		printf( "{" );
	}

	int num_elements = is_array ? arraylen : 1;

	for( int k=0; k<num_elements; k++ )
	{
		const SLO_VISSYMDEF *elem =
			Slo_GetArrayArgElement( (SLO_VISSYMDEF *)parameter, k );

		if( !elem )
		{
			printf( "<error>" );
			continue;
		}

		switch( parameter->svd_type )
		{
			case SLO_TYPE_SCALAR:
				printf( "%g", *elem->svd_default.scalarval );
				break;

			case SLO_TYPE_POINT:
			case SLO_TYPE_VECTOR:
			case SLO_TYPE_NORMAL:
			case SLO_TYPE_COLOR:
				printf( "[%g %g %g]",
						elem->svd_default.pointval->xval,
						elem->svd_default.pointval->yval,
						elem->svd_default.pointval->zval );
				break;

			case SLO_TYPE_MATRIX:
				printf( "[%g ",  elem->svd_default.matrixval[0] );

				for( int kk = 1; kk < 15; kk++ )
					printf( "%g ", elem->svd_default.matrixval[kk] );

				printf( "%g]",  elem->svd_default.matrixval[15] );
				break;

			case SLO_TYPE_STRING:
				printf( "\"%s\"", elem->svd_default.stringval );
				break;

			case SLO_TYPE_SHADER:
				printf( "null" );
				break;

			default:
				break;
		}

		if( k != (num_elements-1) )
		{
			printf( ", " );
		}
	}

	if( is_array )
		printf( "}" );

	printf( "\n" );
}	

void printArgs( const Format i_format )
{
	if( i_format == e_table )
	{
		printf( "%d\n", Slo_GetNArgs() );
	}
	
	for( int j = 0; j < Slo_GetNArgs(); j++ )
	{
		SLO_VISSYMDEF *parameter = Slo_GetArgById( j+1 );

		if( !parameter )
		{
			fprintf( stderr, DlGetText(DlText_2259_param), j );
			continue;
		}

		PrintOneParameter( parameter, i_format );
	}
	
	if( i_format == e_prman )
	{
		printf( "\n" );
	}
}

int main( int argc, char ** argv )
{
	int i;
	int exitCode = 0;

	Format format = e_prman;

	int start = 1;

	/* DlDebug::InitErrorSignalsHandling(); */

	if ( argc <= 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") )
	{
		printf(
			"Usage: shaderinfo [<option>] [file1 ... fileN]\n"
			"Options\n"
			"  -d         : Outputs declarations in RIB format\n"
			"  -t         : Outputs declarations in parsable table format\n"
			"  -a         : Outputs available annotation keys\n"
			"  --source   : Outputs shader's source (if embedded)\n"
			"  --methods  : Outputs shader's methods\n"
			"  -v         : Shows version to console\n"
			"  --version  : Same as -v\n"
			"  -h         : Shows this help\n\n"
			"Notes:\n"
			"- No arguments is the equivalent of passing -h\n"
			"- All options are exclusive. Use no more than one\n"
			"- The options -h, -v, and --version should not be used with shader names\n"
		);

		return 0;
	}

	if( argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) )
	{
		const char* v = DlGetVersionString();
		const char* copyright = DlGetCopyrightString();

		fprintf(stderr, "shaderinfo version %s.\n%s\n", v, copyright);

		return 0;
	}

	if ( argc == 1 )
	{
		start++;
	}
	else if (!strcmp(argv[1], "-d"))
	{
		format = e_ribout;
		start++;
	}
	else if( !strcmp(argv[1], "-t") )
	{
		format = e_table;
		start++;
	}
	else if (!strcmp(argv[1], "-a"))
	{
		format = e_annotations;
		start++;
	}
	else if (!strcmp(argv[1], "-source") || !strcmp(argv[1], "--source") )
	{
		format = e_source;
		start ++;
	}
	else if (!strcmp(argv[1], "--methods") )
	{
		format = e_methods;
		start ++;
	}

	/*
		Add '.' to the default path so shaders are still found in the current
		directory even if the default path is modified not to include '.'
	*/
	Slo_SetPath( ".:@" );

	for( i = start; i < argc; i++ )
	{
		int err = Slo_SetShader( argv[i] );

		if( err != 0 )
		{
			fprintf( stderr, DlGetText(DlText_2260_open), argv[i], err );
			exitCode = 1;
			continue;
		}

		/* Print a header indicating which shader this is */
		if( format == e_table )
		{
			printf( "%s\n%s\n",
				Slo_GetName(), Slo_TypetoStr(Slo_GetType()) );
		}
		else if( format == e_prman )
		{
			printf( "\n%s \"%s\"\n",
				Slo_TypetoStr(Slo_GetType()), Slo_GetName() );
		}
		else if( format == e_methods )
		{
			/* PrMan doesn't seem to print a header in --methods mode. */
		}
		else if( format == e_source )
		{
			/* We want the source that is output directly compilable. So we don't
			   want the name the shader in the listing. */
		}
		else
		{
			printf( "%s %s\n",
				Slo_TypetoStr(Slo_GetType()), Slo_GetName() );
		}

		if( format == e_annotations )
		{
			if( Slo_GetNAnnotations() == 0 )
			{
				fprintf( stderr, DlGetText(DlText_2261_nokey), argv[i] );
				continue;
			}

			printf( "%d\n", Slo_GetNAnnotations() );
			for( int id=0; id<Slo_GetNAnnotations(); id++ )
			{
				const char *key = Slo_GetAnnotationKeyById( id+1 );

				if( !key )
				{
					assert( false );
					fprintf(stderr, DlGetText(DlText_1727_nokey), id, argv[i]);
					return 1;
				}
				
				const char *annotation = Slo_GetAnnotationByKey(key);

				printf( "\"%s\" \"%s\"\n", key, annotation );
			}
		}
		else if ( format == e_source )
		{
			const char *value = Slo_GetAnnotationByKey( "source" );

			if( value )
			{
				printf( "%s\n", value );
			}
			else
			{
				fprintf( stderr, DlGetText(DlText_1796_no_source) );
			}
		}
		else if ( format == e_methods )
		{
			const char *const *method_names = Slo_GetMethodNames();

			while( *method_names )
			{
				printf( "%s\n", *method_names );
				method_names ++;
			}
		}
		else
		{
			printArgs( format );
		}

		Slo_EndShader();		
	}

	return exitCode;
}

10.2.6 The Rix Interface API

The "Rix" API is a collection of classes giving access to useful methods. These classes and methods can be used from inside RSL plug-ins for example (see section RSL Plug-ins). All classes are declared in file `$DELIGHT/include/RixInterface.h' and are further described in the following sections.

The RixContext class

All Rix Interface class live in a Rix Context. The only useful method in this class is GetRixInterface.

RixInterface* RixContext::GetRixInterface ( RixInterfaceID i_id )

This method constructs and returns the Rix Interface specified by i_id. The i_id variable can take one of the following values:

k_RixThreadUtils
k_RixMessages
k_RixStats
k_RixThreadData
k_RixLocalData
k_RixGlobalTokenData
Returns an instance of the corresponding class (RixThreadutils, RixMessages, RixThreadData, etc...).

This method returns a pointer to RxInterface that needs to be cast into the appropriate class. For example:

/* Get a context */
RixContext *context = RxGetRixContext();
RixMessage *error_handler = (RixMessages*) context->GetRixInterface( k_RixMessages );
error_handler->Info( "This is an example" );

The RixInterface class

This is the base class for all other Rix classes. There is no particular functionality provided by this class apart from returning the version of the API and being the base type returned by GetRixInterface.

int RixInterface::GetVersion ( ) const

Returns the version of the interface.

The RixStorage class

This class provides data storage and retrieval methods. Data is associated with a key and is accessible across plug-in boundaries when retrieved with the same key. Such a class is created through a RixContext object and can return local, global or thread-local data. For example:

RixContext *context = RxGetRixContext( );
RixStorate *thread_storage = (RixStorage *)context->GetRixInterface( k_RixThreadData );
thread->storage->Set( "example", somedata );
void* RixStorage::Get ( const char *i_key )

Returns the data associated with the give key. NULL is returned if there is no data attached to the given key.

void* RixStorage::Set ( const char *i_key, void *i_data, RixCleanupFunction i_clean = NULL )

Sets the data associated with the given key. If the key has associated data, it will be cleared and it associated cleanup function will be called (if provided with the previous Set function).

void RixStorage::Lock ( )
void RixStorage::Unlock ( )

Lock or unlocks this object. Only necessary when accessing global storage.

The RixThreadUtils class

This class provides access to thread related methods. As of now, only one method is accessible to provide a mutex object.

RiMutex RixThreadUtils::NewMutex ( ) const

Returns a RiMutex object. Mutexes are necessary to serialize concurrent access to globally memory. Please refer to The RiMutex class for more information. All mutex objects allocated using this method must be de-allocated using the delete operator.

The RixMessage class

Provides functions to print messages using 3Delight's error handler.

The RiMutex class

A cross-platform locking mechanism is provided through this class.

void RiMutex::Lock ( )
void RiMutex::Unlock ( )

Locks or unlocks this object.

10.2.7 The VolumeTracer API

This API provides functions to trace rays in a voxel grid as suitable for volume rendering. It is available through a RSL plug-in so it is callable from inside regular RenderMan shaders. In summary, the VolumeTracer API allows a shader to:

These provided functionalities make it easy to write efficient volume shaders without hassle.

10.2.7.1 Working Principles

To use the library one has to write at least two RenderMan shaders:

  1. A classical ray-marching volume shader that uses the provided calls to trace rays, in SIMD, through 3D space.
  2. A small shader that returns the volume attributes (there can be many) at any position in the volume. In practice, this shader will be called to query volume quantities at each grid vertex. Most commonly, this shader would return the density of the volume but other usages are of course possible. The name of this shader is provided to the initialization function of API (see section Entry Points) and is handled by the plug-in(72). It must have a single output parameter : an array of floats. Any number of input parameters are allowed and can be initialized when creating the grid (usually to provide the name of a point cloud file).

The RSL plug-in library is located in `$DELIGHT/shaders/'.

10.2.7.2 Entry Points

float VolumeTracer_InitGrid ( uniform string gridName; ... )

Creates and initializes a 3D grid to be used by the other API functions. Parameters are:

gridName
Name of the grid. Might be used later by VolumeTracer_NbAttributes or VolumeTracer_InitRay_Function.

The other parameters of the grid are specified through name/value pairs :

uniform string paramName
Name of the grid parameter.
uniform <type> paramValue
Value of the parameter.

Supported grid parameters are :

`grid:center' (point)
Center position of the grid in 3D space.
`grid:size' (vector)
Size of the grid in each dimension, in the same 3D space as the position.
`grid:nbcells' (vector)
Number of cells in the grid in each dimension.
`grid:shader' (string)
Name of a surface shader that will be used to compute the attributes of the volume at selected sample points in the grid. The shader must have a single output parameter of type "float[]" (the array can be of any constant size), plus any number of input parameters. This defines an attribute category for the grid. The size of the output array determines the number of attributes in the category. This parameter can be specified up to 3 times with different shader names in order to create multiple attribute categories.

In addition to this, parameters that need to be passed to the grid's shaders can also be specified through additional name/value pairs :

uniform string paramName
Name of the shader parameter, prefixed with the shader name (as specified for the `grid:shader' grid parameter) and the ":" parameter. For example to specifiy the parameter "pointCloudFile" of a shader named "density", paramName would be "density:pointCloudFile".
uniform <type> paramValue
Value of the shader parameter.

This function returns a uniform float which indicates the total number of attributes the grid will handle.

float VolumeTracer_GetParameters ( uniform string gridName; ... )

Retrieves some parameters of a previously created grid. The first parameter of this function, gridName, is the name of a grid previously created with VolumeTracer_InitGrid. The following parameters are an optional list of name/value pairs : each pair is composed of the name of a grid parameter to be retrieved, followed by a uniform variable of the appropriate type where the grid parameter's value is to be stored. The following grid parameters are supported:

` nbattributes'
A float indicating the number of volume attributes managed by the grid (defined by the number of attributes returned by the grid's shaders). This is the number of attributes that will be returned by the VolumeTracer_StepRay function.
` cellsize'
A vector indicating the size of the cells in each dimension.
` nbcells'
A vector indicating the number of cells in each dimension of the grid.

This function returns the number of grid parameters successfully retrieved (might be 0 if none were requested(73)), or a negative value if the grid was not found or the function was called with invalid arguments.

float VolumeTracer_InitRay ( uniform string gridName; varying point start, end; varying float stepLength; uniform string interpolation )

Initializes a ray to be traced across the grid. Note that this function is SIMD so it will initialize many rays in practice. Parameters are:

gridName
Name of the grid in which ray-tracing takes place.
start
Starting position of the ray.
end
Ending position of the ray.
stepLength
Approximative length of steps to be made along the ray.
interpolation
Type of interpolation to be used when computing the volume's attributes along the ray. The following values are accepted :
` trunc'
No interpolation - sample position is truncated to a grid vertex position
` nearest'
No interpolation - nearest grid vertex is used
` linear'
Linear interpolation between surrounding grid vertices
` cubic'
Cubic interpolation between surrounding grid vertices
` exact'
No interpolation - the grid is ignored and the exact value is computed directly by the grid's shaders (very expensive; meant for low resolution testing only)
This function returns a varying float which is an identifier for the newly created ray. This identifier can then be passed to VolumeTracer_StepRay_Function.
float VolumeTracer_StepRay ( varying float rayID; output varying float length )
float VolumeTracer_StepRay ( varying float rayID; output varying float length; output varying float[] attributes )

Advances one step along a ray (in SIMD) and returns the volume's attribute midway along the step. All rays must belong to the same grid. Parameters are:

rayID
Identifier of a ray previously created with VolumeTracer_InitRay.
length
The length of this step.
attributes (optional)
The volume's attributes computed near midpoint along the current step, using the shaders specified to VolumeTracer_InitGrid and the interpolation mode specified to VolumeTracer_InitRay.

This function returns a varying float which indicates the fraction of the distance between the ray's start and end points that was covered until now. When 1.0 is returned, the end point has been reached and the ray cannot be advanced anymore.

float VolumeTracer_EvaluateStep ( varying float rayID; output varying float[] attributes )
float VolumeTracer_EvaluateStep ( varying float rayID; output varying float[] attributes ; uniform string[] shaders )

Evaluates the volume's attribute midway along the previous step (in SIMD). All rays must belong to the same grid. Parameters are:

rayID
Identifier of a ray previously created with VolumeTracer_InitRay.
attributes
The volume's attributes computed near midpoint along the current step, using the density shader specified to VolumeTracer_InitGrid and the interpolation mode specified to VolumeTracer_InitRay.
shaders (optional)
The list of attribute categories that should be evaluated, those categories are identified by the name of the shader that computes them, as provided in the `grid:shader' parameter of VolumeTracer_InitGrid. By default, all attributes will be evaluated, but disabling a few of them can improve performance.

This function returns a varying float success (1.0) or failure (1.0).

10.2.7.3 Usage Example

Follows a code snippet showing how to use the API:

uniform string objectName = ... ;
uniform vector bboxCenter = ... ;
uniform vector bboxSize = ... ;
uniform vector nbCells = ... ;

uniform float nbAttributes;

/* Test grid existence */
if(VolumeTracer_GetParameters(objectName, "nbattributes", nbAttributes) < 0)
{
    /* Create grid */
    nbAttributes = 
        VolumeTracer_InitGrid(
            objectName,
            "grid:center", bboxCenter,
            "grid:size", bboxSize,
            "grid:nbcells", nbCells,
            "grid:shader", "noisy",
            "noisy:intensity", 0.7);
}

/* Create ray */
float stepLength = ... ;
uniform string interpolation = "linear";
float rayID = VolumeTracer_InitRay(objectName, transform("object", P-I),
        transform("object", P), stepLength, interpolation);

float progress = 0.0;

float attributes[];
resize(attributes, nbAttributes);

while(progress < 1.0)
{
    float step;
    progress = VolumeTracer_StepRay(rayID, step, attributes);

    /* Use attributes ... */
}

The `noisy.sl' shader has to define a varying output array of floats, as in:

surface noisy(
    uniform float intensity;
    output varying float density[3]; )
{
    color D = noise( P ) * intensity;

    density[0] = D[0];
    density[1] = D[1];
    density[2] = D[2];
}

10.2.8 The interactive edit API

This API allows some changes to be applied to the scene being rendered with quick feedback of their effect on the image. Some limits are placed on the allowed changes so that they can be rendered immediately, without any startup delay. Although this API can be accessed through RIB, it makes more sense when used with the C binding within an application with a user interface.

Using the API requires few changes from a regular render. The first one is that the editable and progressive hider options must be enabled. Also note that the raytrace hider must be used.

RtInt on = 1;
RiHider( RI_RAYTRACE,
    "int editable", &on,
    "int progressive", &on,
    RI_NULL );

The scene is then output as usual. The next notable difference is that RiWorldEnd will begin rendering in a background thread instead of blocking until the render is finished. Edits to the scene can now be applied with RiEditBegin / RiEditEnd blocks. Rendering stops on the next RiFrameEnd or RiEnd call.

RtVoid RiEditBegin ( RtToken name, ... )
RtVoid RiEditBeginV ( RtToken name, RtInt n, RtToken tokens[], RtPointer params[] )
RtVoid RiEditEnd ()

These functions are used to specify changes to the scene. The possible edit types specified by the name parameter along with their optional parameters are:

"attribute"
This is a generic method of changing attributes on objects. The objects to edit are selected by these optional parameters:
"string exactscopename"
The provided value must exactly match an object's "identifier" "string name" attribute for it to be edited.
"string scopename"
The provided value is a regular expression which is matched against the object's "identifier" "string name" attribute to decide if it must be edited.
"string scopetype"
This can be either "all" or "geometry". If "geometry" is given, the scope parameters above will match only on geometry. If "all" is given, they will also match parent attribute scopes of the geometry. The default behavior is "all" when a scope name is specified and "geometry" when none is given (all geometry will match).
Most attributes can be changed inside the edit block. New light sources can also be created.
"shader"
This allows replacing a shader by handle for the entire scene. It can be much simpler and more efficient than performing several "attribute" edits. The shader is identified by adding a special "string __edithandleid" parameter to its parameter list. When an edit is done, all shaders of the same type with a matching handle are replaced.
"light"
This allows replacing a light shader by a new instance. It can be the same shader with different parameters or shader space or an entirely different shader. The shader replaces the previous shader with the same handle everywhere.
"option"
This allows editing options or other global objects such as the imager shader, the camera or named coordinate systems. Note that updating the camera requires a RiCamera( "world", RI_NULL ) call once the new camera has been set up.
"texture"
This specifies that a texture file was updated and should be reloaded by the renderer. The file is identified by the "string filename" named parameter. No other calls should be made between RiEditBegin and RiEditEnd.
"suspendrendering"
This is not a real edit type but will simply suspend rendering until RiEditEnd is called. It is possible to specify edits with RiEditBegin/RiEditEnd pairs before resuming rendering with a final RiEditEnd.

Edit blocks begin in world space except for "option" edits which begin with no transform in place. A complete example follows which demonstrates most types of edits.

/*
    3Delight editable render API example.

    This is not meant to do anything useful besides demonstrating how the API
    works.
*/

#include <ri.h>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef __linux__
#   include <unistd.h>
#endif

#ifdef _WIN32
#   include <windows.h>
#endif

void milisleep( unsigned ms )
{
#ifdef _WIN32
    Sleep( ms );
#else
    timespec delay;
    delay.tv_sec = ms / 1000u;
    delay.tv_nsec = (ms % 1000u) * 1000000u;

    nanosleep( &delay, 0x0 );
#endif
}

void OutputCamera( float fov )
{
    RiProjection( RI_PERSPECTIVE, RI_FOV, &fov, RI_NULL );
    RiTranslate( 0.0f, 0.0f, 5.0f );
    RiRotate( 40.0f, 1.0f, 0.0f, 0.0f );
}

void OutputSpotlight(
    RtFloat aimangle,
    RtFloat coneangle,
    RtString handle )
{
    RiTranslate( 0.0f, 0.0f, -7.0f );
    RiRotate( aimangle, 0.0f, 1.0f, 0.0f );

    RtFloat conedeltaangle = 0.01f;
    RtFloat intensity = 25.0f;
    RiLightSource(
        "spotlight",
        RI___HANDLEID, &handle,
        "float coneangle", &coneangle,
        "float conedeltaangle", &conedeltaangle,
        "float intensity", &intensity,
        RI_NULL );
}

void Identify( const char *i_name )
{
    RiAttribute( "identifier", "name", &i_name, RI_NULL );
}

int main( int argc, char *argv[] )
{
    RiBegin( RI_NULL );

    RiDisplay( "edit example", "idisplay", RI_RGBA, RI_NULL );
    RiFormat( 1280, 720, 1.0f );
    RiPixelFilter( RiBoxFilter, 1.0f, 1.0f );
    RiPixelSamples( 4.0f, 4.0f );

    RtInt on = 1;
    RiHider( RI_RAYTRACE,
        "int editable", &on,
        "int progressive", &on,
        RI_NULL );

    OutputCamera( 25.0f );

    RtString edithandle1 = "shadinggroup1";

    RiWorldBegin();
        RiTransformBegin();
            OutputSpotlight( 0.0f, 0.10f, "light1" );
        RiTransformEnd();
        RiTransformBegin();
            OutputSpotlight( -4.0f, 0.15f, "light2" );
        RiTransformEnd();
        RiIlluminate( (RtLightHandle)"light2", RI_FALSE );

        RiAttributeBegin();
            RtPoint patchPl[4] =
                { {-2, 1.1, 0}, {2, 1.1, 0}, {-2, -1.1, 0}, {2, -1.1, 0} };
            Identify( "plane" );
            RiSurface( "plastic",
                "string __edithandleid", &edithandle1, RI_NULL );
            RiPatch( RI_BILINEAR, RI_P, patchPl, RI_NULL );
        RiAttributeEnd();

        RiAttributeBegin();
            Identify( "sphere_left" );
            RiSurface( "plastic", RI_NULL );
            RiTranslate( -1.0f, 0.0f, -0.3f );
            RiSphere( 0.3f, -0.3f, 0.0f, 360.0f, RI_NULL );
        RiAttributeEnd();

        RiAttributeBegin();
            Identify( "sphere_right" );
            RiSurface( "plastic", RI_NULL );
            RiTranslate( 1.0f, 0.0f, -0.3f );
            RiSphere( 0.3f, -0.3f, 0.0f, 360.0f, RI_NULL );
        RiAttributeEnd();

        RiAttributeBegin();
            Identify( "cube" );
            RiSurface( "plastic",
                "string __edithandleid", &edithandle1, RI_NULL );
            RiTranslate( 0.0f, 0.0f, -0.5f );
            RiRotate( 55.0f, 0.0f, 0.0f, 1.0f );
            RiRotate( 45.0f, 1.0f, 0.0f, 0.0f );
            RiRotate( 45.0f, 0.0f, 1.0f, 0.0f );
            RiScale( 0.5f, 0.5f, 0.5f );
            RiGeometry( "cube", RI_NULL );
        RiAttributeEnd();

    RiWorldEnd();
    milisleep( 3000 );

    /* Aim light1 a bit more to the right. Changes the light shader's space. */
    RiEditBegin( "light", RI_NULL );
        OutputSpotlight( 4.0f, 0.10f, "light1" );
    RiEditEnd();
    milisleep( 1000 );

    /* Increase light's cone angle. Changes the light shader. */
    RiEditBegin( "light", RI_NULL );
        OutputSpotlight( 4.0f, 0.15f, "light1" );
    RiEditEnd();
    milisleep( 2000 );

    /* Turn on the second spotlight. */
    RiEditBegin( "attribute", RI_NULL );
        RiIlluminate( (RtLightHandle)"light2", RI_TRUE );
    RiEditEnd();
    milisleep( 2000 );

    /* Add a third spotlight. */
    RiEditBegin( "attribute", RI_NULL );
        OutputSpotlight( 0.0f, 0.05f, "light3" );
    RiEditEnd();
    milisleep( 2000 );

    /* Turn it off for the plane. */
    RtString plane = "plane";
    RiEditBegin( "attribute", "string exactscopename", &plane, RI_NULL );
        RiIlluminate( (RtLightHandle)"light3", RI_FALSE );
    RiEditEnd();
    milisleep( 2000 );

    /* Change an attribute (color) on the left sphere. */
    RtString leftsphere = "sphere_left";
    RiEditBegin( "attribute", "string exactscopename", &leftsphere, RI_NULL );
        RtColor newcolor = { 0.7f, 0.5f, 0.9f };
        RiColor( newcolor );
    RiEditEnd();
    milisleep( 2000 );

    /* Change (in this case add) the imager shader. */
    RiEditBegin( "option", RI_NULL );
        RtColor red = { 1.0f, 0.0f, 0.0f };
        RiImager( "background", "color bgcolor", red, RI_NULL );
    RiEditEnd();
    milisleep( 2000 );

    /* Give both spheres a matte shader, using a regular expression. */
    RtString spheres = "^sphere.*";
    RiEditBegin( "attribute", "string scopename", &spheres, RI_NULL );
        RiSurface( "matte", RI_NULL );
    RiEditEnd();
    milisleep( 2000 );

    /* Change the camera. */
    RiEditBegin( "option", RI_NULL );
        OutputCamera( 20.0f );
        RiCamera( RI_WORLD, RI_NULL );
    RiEditEnd();
    milisleep( 2000 );

    /* Edit shaders by handle. We only change Kd here but could also use a
       different shader. */
    RiEditBegin( "shader", RI_NULL );
        float Kd = 0.2;
        RiSurface( "plastic",
            "string __edithandleid", &edithandle1,
            "float Kd", &Kd, RI_NULL );
    RiEditEnd();
    milisleep( 250 );

    /* Pause rendering for a short time. */
    RiEditBegin( "suspendrendering", RI_NULL );
    milisleep( 1500 );
    RiEditEnd();

    milisleep( 5000 );

    /* Stop rendering. */
    RiEnd();
}

3Delight 10.0. Copyright 2000-2011 The 3Delight Team. All Rights Reserved.