Plug-in Ri Filters

Required Entry Points

Callback Entry Points

State Queries

Parameter Parsing

RIB Parsing

Example


The Rif API allows the user to develop plugins that modify Ri streams as they are presented to the renderer. This API can be combined with the Rx and Ri APIs to generate filters for a wide variety of uses.

prman is instructed to load a chain of Rif plugins via the -rif command line argument. Arguments can be passed to the plugins via the -rifarg command line argument, where -rifend delineates the end of the arguments for a given plugin. The -catrib argument can be used to cause the RIB stream to be processed by the plugins and written to a file (by default stdout).

prman loads all of the specified plugins and invokes the RifPluginManufacture method to construct the filter associated with a given plugin. Then as PRMan parses RIB, the callbacks from a given filter are triggered and executed. Execution of callbacks triggered from the same parsed Ri call, occurs in the order that the plugins are specified on the command line.

Ri Filter API

Required Entry Points

class RifPlugin
{
public:
  virtual             ~RifPlugin() {} /* virtual destructor */
  virtual RifFilter & GetFilter() =  0;
};

All Plug-in Ri Filters must subclass this pure-virtual class. The constructor for this class normally intializes a RiFilter dispatch table. The GetFilter() member returns a pointer to that dispatch table. Your subclass can have any number of RiFilter objects and can choose which to return based on its own state.

 
RifPlugin* RifPluginManufacture(int argc, char **argv);

Plug-in Ri Filters must implement the RifPluginManufacture procedure. This procedure constructs an instance of a RifPlugin subclass.

Callback Entry Points

struct RifFilter
{
  enum     { k_UnknownVersion = 0, k_CurrentVersion = 1 };
  enum     DefaultFiltering { k_Continue, k_Terminate };
  short    Version;        /* the version of the table */
  void*    ClientData;     /* a place for the plug-in to hang its hat */
  char     Reserved[64];   /* for future use */

  DefaultFiltering Filtering;
  RifFilter ();

  RtToken         (*Declare)(char *name, char *declaration);
  RtVoid          (*FrameBegin)(RtInt frame);
  RtVoid          (*FrameEnd)();
  RtVoid          (*WorldBegin)();
  RtVoid          (*WorldEnd)();
  ...
};

The RifFilter data structure contains a constructor, some versioning information, a filtering mode (DefaultFiltering), and function pointers for every function in the Ri Interface. When a given Ri function is parsed, the overridden callback is called instead. Then if the DefaultFiltering is set to k_Continue, the next filter in the chain is called. If the mode is set to k_Terminate, then no further calls are made and the parsing terminates.

State Queries

typedef enum { k_RifRIB, k_RifRenderer } RifEmbedding;
RifEmbedding RifGetEmbedding();

This routine returns the parsing state of the filter. If it returns k_RifRIB this means the filter is being called from within the catrib program, if k_RifRenderer it means it is being called from within prman.

 
RtVoid RifGetChainInfo(RtInt *current, RtInt *total );

This routine returns the current level in the Ri Filter chain, and also returns the total number of plugins that are being used in this particular chain. The total will be zero-index based, and RifGetChainInfo() will return invalid results when called from within RifPluginManufacture().

 
void* RifGetCurrentPlugin(void);

This routine provides a way for the dispatch table callbacks to gain access to the current state of the plugin. A static cast is normally used to recover the RifPlugin subclass object.

Parameter Parsing

typedef enum { k_RifFloat=0, k_RifPoint, k_RifColor,  k_RifInteger,
	   k_RifString, k_RifVector, k_RifNormal, k_RifHPoint,
	   k_RifMatrix, k_RifMPoint
	 } RifTokenType;

typedef enum { k_RifConstant=0, k_RifUniform, k_RifVarying,
	   k_RifVertex,     k_RifFaceVarying
	 } RifTokenDetail;

RtInt RifGetDeclaration(RtToken nm, RifTokenType *tokType, 
			   RifTokenDetail *tokDetail, RtInt *arraylen);

This is a helper routine to help parse token value pairs that are a part of parameter lists of various Ri calls. Typical usage involves iterating over the number of tokens in a parameter list, passing each token nm into RifGetDeclaration. The routine returns 0 if it is able to determine the type and detail of the token, which are returned in tokType and tokDetail, respectively. If the token is an array type, the length of the array is returned in arraylen. If the type or detail cannot be determined, 1 is returned to signal the error.

RIB Parsing

typedef enum { k_RifParseNextLayer, k_RifParseThisLayer, 
	       k_RifParseFirstlayer
	     } RifParseMode;
	     
RtVoid RifParseFile(const char *filename, RifParseMode m);

RtVoid RifParseBuffer(const char *buf, unsigned size, RifParseMode m);

These routines allow the Ri Filter to insert RIB streams from either a file or from memory as the filter is running. The different modes determine where in the chain this incoming RIB is processed from. If the mode is k_RifParseNextLayer, the incoming RIB is parsed by the next Ri Filter in the chain. If the mode is k_RifParseThisLayer, the RIB is parsed by the current Ri Filter. If the mode is k_RifParseFirstLayer, then the RIB is sent through the whole Ri Filter chain starting from the beginning. With RifParseFile, the RIB to be processed is pointed at by filename. With RibParseBuffer, a region of memory, buf, contains the RIB and the size of the buffer is passed as size.

Example

#include "ri.h"
#include "librif/RifPlugin.h"
#include <stdio.h>
#include <string.h>
#include <ext/hash_map>
#include <iostream>

static const char *c_gprims = "gprims";
static const char *c_polyfacets = "polygon facets";
static const char *c_quadrics = "quadrics";
static const char *c_shaders = "shaders";

class RIBCounter : public RifPlugin
{
public:
		    RIBCounter();
virtual 	    ~RIBCounter();
virtual RifFilter & GetFilter();

private:
RifFilter   	    m_rifFilter;

void		    incrementCount(const char *, unsigned num);

__gnu_cxx::hash_map<const char *, unsigned>	m_totals;

// attributes:
static RtLightHandle lightSourceV(RtToken name,
		    RtInt, RtToken[], RtPointer[]);
static RtVoid   atmosphereV(RtToken name,
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   displacementV(RtToken name,     
		    RtInt, RtToken[], RtPointer[]);       
static RtVoid   surfaceV(RtToken name,
                    RtInt, RtToken[], RtPointer[]); 
// primitives:
static RtVoid   blobbyV(RtInt nleaf, RtInt ninst, RtInt inst[],
                    RtInt nflt, RtFloat flt[],
                    RtInt nstr, RtToken str[],     
                    RtInt, RtToken[], RtPointer[]);
static RtVoid  	coneV(RtFloat height, RtFloat radius, RtFloat tmax,
                    RtInt, RtToken[], RtPointer[]);
static RtVoid  	curvesV(RtToken type, RtInt ncurves, RtInt nvert[],
                    RtToken wrap, RtInt, RtToken[], RtPointer[]);
static RtVoid   cylinderV(RtFloat rad, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[]);
static RtVoid   diskV(RtFloat height, RtFloat radius, RtFloat tmax,
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   generalPolygonV(RtInt nloops, RtInt nverts[],
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   geometryV(RtToken type, RtInt, RtToken[], RtPointer[]);
static RtVoid   hyperboloidV(RtPoint point1, RtPoint point2,
                    RtFloat tmax,
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   nuPatchV(RtInt nu, RtInt uorder, RtFloat uknot[],
                    RtFloat umin, RtFloat umax, RtInt nv, RtInt vorder,
                    RtFloat vknot[], RtFloat vmin, RtFloat vmax,
                    RtInt, RtToken[], RtPointer[]); 
static RtVoid   paraboloidV(RtFloat rmax, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[]);
static RtVoid   patchMeshV(RtToken type, RtInt nu, RtToken uwrap,
                    RtInt nv, RtToken vwrap,
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   patchV(RtToken type, RtInt, RtToken[], RtPointer[]);
static RtVoid   pointsGeneralPolygonsV(RtInt npolys, RtInt nloops[],
                    RtInt nverts[], RtInt verts[],
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   pointsPolygonsV(RtInt npolys, RtInt nverts[],
                    RtInt verts[], RtInt, RtToken[], RtPointer[]);
static RtVoid   pointsV(RtInt nverts, RtInt, RtToken[], RtPointer[]);
static RtVoid   polygonV(RtInt nverts, RtInt, RtToken[], RtPointer[]);
static RtVoid   procedural(RtPointer data, RtBound bound,
                    RtProcSubdivFunc sdfunc, RtProcFreeFunc freefunc);
static RtVoid   sphereV(RtFloat radius, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[]);
static RtVoid   subdivisionMeshV(RtToken mask, RtInt nf, RtInt nverts[],
                    RtInt verts[], RtInt nt, RtToken tags[],
                    RtInt nargs[], RtInt intargs[], RtFloat floatargs[],
                    RtInt, RtToken[], RtPointer[]);
static RtVoid   torusV(RtFloat majrad, RtFloat minrad,
                    RtFloat phimin, RtFloat phimax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[]);    
static RtVoid   trimCurve(RtInt nloops, RtInt ncurves[],      
                    RtInt order[], RtFloat knot[],
                    RtFloat min[], RtFloat max[], RtInt n[],
                    RtFloat u[], RtFloat v[], RtFloat w[]);
};

RifPlugin *
RifPluginManufacture(int argc, char **argv)
{
    fprintf(stdout, "Manufacturing RIBCounter with %d args\n", argc);
    return new RIBCounter();
}

RIBCounter::RIBCounter()
{
    m_rifFilter.ClientData = static_cast<void *>(this);

    // attributes --------------------------------------------------
    m_rifFilter.AtmosphereV = atmosphereV;
    m_rifFilter.DisplacementV = displacementV;
    m_rifFilter.LightSourceV = lightSourceV;
    m_rifFilter.SurfaceV = surfaceV;

    // primitives --------------------------------------------------
    m_rifFilter.BlobbyV = blobbyV;
    m_rifFilter.ConeV = coneV;
    m_rifFilter.CurvesV = curvesV;
    m_rifFilter.CylinderV = cylinderV;
    m_rifFilter.DiskV = diskV;
    m_rifFilter.GeneralPolygonV = generalPolygonV;
    m_rifFilter.GeometryV = geometryV;
    m_rifFilter.HyperboloidV = hyperboloidV;
    m_rifFilter.NuPatchV = nuPatchV;
    m_rifFilter.ParaboloidV = paraboloidV;
    m_rifFilter.PatchMeshV = patchMeshV;
    m_rifFilter.PatchV = patchV;
    m_rifFilter.PointsGeneralPolygonsV = pointsGeneralPolygonsV;
    m_rifFilter.PointsPolygonsV = pointsPolygonsV;
    m_rifFilter.PointsV = pointsV;
    m_rifFilter.PolygonV = polygonV;
    m_rifFilter.Procedural = procedural;
    m_rifFilter.SphereV = sphereV;
    m_rifFilter.SubdivisionMeshV = subdivisionMeshV;
    m_rifFilter.TorusV = torusV;
    m_rifFilter.TrimCurve = trimCurve;

    m_rifFilter.Filtering = RifFilter::k_Terminate;
}

RIBCounter::~RIBCounter()
{
    std::cout << "RIBCounter results:-----------------------------\n";
    __gnu_cxx::hash_map::iterator a, b;
    a = m_totals.begin();
    b = m_totals.end();
    while(a != b)
    {
	std::cout << a->first << " " << a->second << std::endl;
	a++;
    }
}

RifFilter &
RIBCounter::GetFilter()
{
    return m_rifFilter;
}

void
RIBCounter::incrementCount(const char *nm, unsigned num)
{
    m_totals[nm] += 1;
}

// attributes ------------------------------------------------------------
RtLightHandle
RIBCounter::lightSourceV(RtToken name,
		    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiLightSources", 1);
    obj->incrementCount(c_shaders, 1);
    obj->incrementCount(name, 1);
    return 0L;
}

RtVoid
RIBCounter::atmosphereV(RtToken name,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiAtmospheres", 1);
    obj->incrementCount(c_shaders, 1);
    obj->incrementCount(name, 1);
}

RtVoid
RIBCounter::displacementV(RtToken name,     
		    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiDisplacements", 1);
    obj->incrementCount(c_shaders, 1);
    obj->incrementCount(name, 1);
}

RtVoid
RIBCounter::surfaceV(RtToken name,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiSurfaces", 1);
    obj->incrementCount(c_shaders, 1);
    obj->incrementCount(name, 1);
}

// primitives ------------------------------------------------------------
RtVoid
RIBCounter::blobbyV(RtInt nleaf, RtInt ninst, RtInt inst[],
                    RtInt nflt, RtFloat flt[],
                    RtInt nstr, RtToken str[],     
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiBlobbys", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::coneV(RtFloat height, RtFloat radius, RtFloat tmax,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiCones", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::curvesV(RtToken type, RtInt ncurves, RtInt nvert[],
                    RtToken wrap, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiCurves", 1);
    obj->incrementCount("curves", ncurves);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::cylinderV(RtFloat rad, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiCylinders", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::diskV(RtFloat height, RtFloat radius, RtFloat tmax,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiDisks", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::generalPolygonV(RtInt nloops, RtInt nverts[],
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiGeneralPolygons", 1);
    obj->incrementCount(c_polyfacets, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::geometryV(RtToken type, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiGeometry", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::hyperboloidV(RtPoint point1, RtPoint point2,
                    RtFloat tmax,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiHyperboloids", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::nuPatchV(RtInt nu, RtInt uorder, RtFloat uknot[],
                    RtFloat umin, RtFloat umax, RtInt nv, RtInt vorder,
                    RtFloat vknot[], RtFloat vmin, RtFloat vmax,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiNuPatches", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::paraboloidV(RtFloat rmax, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiParaboloids", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::patchMeshV(RtToken type, RtInt nu, RtToken uwrap,
                    RtInt nv, RtToken vwrap,
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPatchMeshes", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::patchV(RtToken type, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPatches", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::pointsGeneralPolygonsV(RtInt npolys, RtInt nloops[],
                    RtInt nverts[], RtInt verts[],
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPointsGeneralPolygons", 1);
    obj->incrementCount(c_polyfacets, npolys);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::pointsPolygonsV(RtInt npolys, RtInt nverts[],
                    RtInt verts[], RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPointsPolygons", 1);
    obj->incrementCount(c_polyfacets, npolys);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::pointsV(RtInt nverts, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPoints", 1);
    obj->incrementCount("points", nverts);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::polygonV(RtInt nverts, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiPolygons", 1);
    obj->incrementCount(c_polyfacets, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::procedural(RtPointer data, RtBound bound,
                    RtProcSubdivFunc sdfunc, RtProcFreeFunc freefunc)
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiProcedurals", 1);
    if( sdfunc == RiProcDelayedReadArchive )
    	obj->incrementCount("RiDelayedReadArchives", 1);
    else
    if( sdfunc == RiProcRunProgram )
    	obj->incrementCount("RiRunPrograms", 1);
    else
    if( sdfunc == RiProcDynamicLoad )
    	obj->incrementCount("RiDynamicLoads", 1);
    else
    	obj->incrementCount("custom procedurals", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::sphereV(RtFloat radius, RtFloat zmin, RtFloat zmax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiSpheres", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::subdivisionMeshV(RtToken mask, RtInt nf, RtInt nverts[],
                    RtInt verts[], RtInt nt, RtToken tags[],
                    RtInt nargs[], RtInt intargs[], RtFloat floatargs[],
                    RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiSubdivisionMesh", 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::torusV(RtFloat majrad, RtFloat minrad,
                    RtFloat phimin, RtFloat phimax,
                    RtFloat tmax, RtInt, RtToken[], RtPointer[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiTorii", 1);
    obj->incrementCount(c_quadrics, 1);
    obj->incrementCount(c_gprims, 1);
}

RtVoid
RIBCounter::trimCurve(RtInt nloops, RtInt ncurves[],      
                    RtInt order[], RtFloat knot[],
                    RtFloat min[], RtFloat max[], RtInt n[],
                    RtFloat u[], RtFloat v[], RtFloat w[])
{
    RIBCounter *obj = static_cast<RIBCounter *>( RifGetCurrentPlugin() );
    obj->incrementCount("RiTrimCurves", 1);
}
 

Pixar Animation Studios
(510) 752-3000 (voice)   (510) 752-3151 (fax)
Copyright © 1996- Pixar. All rights reserved.
RenderMan® is a registered trademark of Pixar.