Ri Filters

Ri Filters

Introduction

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.

Fundamentally, the idea is to construct a chain of parameterized rifs. If your chains grow complex it may be useful to delineate functional collections in the ordered collection of rifs with markers. It may be also be useful to edit the chain from different points in the production pipeline. The editing operations, append, insert and delete, leverage rif markers. Two reserved markers, begin and end, are built in to the system.

Once a rif chain is described, 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.

prman can be instructed to load and edit a chain of Rif plugins in a number of ways:

Command Line Options

These options can be passed either to prman on the command-line or via the PRManBegin procedure.

-rif plug-in [-rifargs arg arg... -rifend]
adds a rif to the next slot in the chain. You can have any number of rif blocks.
-rifmarker m1
appends a marker at the next slot in the chain. You can have any number of rif markers.
-allowrifedits [0|1]
controls whether downstream chain edits are allowed.

RIB Structure

The following options can be included in a RIB file. If you are using a RIB client library, the syntax is:

RiArchiveRecord(RI_STRUCTURE, "%s ...", RI_RIFCONTROL, ...

where the ellipsis would be replaced with your rifcontrol blocks. The actual RIB looks like this:

##rifcontrol insert marker rifblocks
inserts the collection of blocks before marker. The rif blocks follow the form of the command-line and can include the introduction of new markers.
##rifcontrol append marker rifblocks
performs the same operation as insert only after the provided marker.
##rifcontrol delete startmarker endmarker
deletes members of the the current rif chain between two markers. The markers themselves aren't deleted.

C Entrypoints

Rif Plugins can modify the current rif chain through a collection of Rif API procedures. These modifications can be made both during plugin-manufacturing or during the Ri processing phase. The idea of editing an active rif-chain is both powerful and potentially perilous. Care must be taken to prevent infinite recursion and invalid runtime conditions. Currently we disallow rif-chain editing from within procedural primitives and generally suggest that some rigor be employed in the specification of constraints over chain editing. Here are the C entrypoints for editing the rif chain:

RifLoadPlugin(const char *plugin, int argc, char const *argv[])
loads and manufactures a RifPlugin for inclusion in the current chain via either RifInit or RifSetChain. The RifPlugin * returned is owned by the renderer and should not be deleted by the API client.
RifInit(int nplugins, RifPlugin *plugins[])
allows the rif chain to be specified or re-specified in a multi-session context without having to re-issue a PRManBegin() call.
RifGetChain(RifPlugin *chaincopy[], int *count)
fills the chaincopy array with the current chain. The API assumes that the size of the array is large enough to accomate the entire chain. Prior to making this call, clients should obtain the current rif chain size via RifGetChainInfo. RifGetChain doesn't include rif markers, so the length of the chain returned by RifGetChainInfo may be larger than than that returned by this procedure.
RifSetChain(RifPlugin *newchain[], int count)
resets the current chain to newchain.
RifPushChain(), RifPopChain()
maintains a stack for rif chains to facilitate the temporary manipulation of the rif chain stack. Typically clients push, edit, process, then pop the rif chain.

Python Entrypoints

Python-based rifs can be installed through a special variant of RifInit that accepts a list of rif objects.

ri = prman.Ri()
rif1 = myRif(ri)
rif2 = anotherRif(ri)
rifchain = [rif1, rif2]
prman.RifInit(rifchain)
execfile("testri.py") # load a collection of ri calls,
                      # to be filtered by rifchain

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 RifFilter dispatch table. The GetFilter() member returns a pointer to that dispatch table. Your subclass can have any number of RifFilter 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.


Filter 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 ();

  ... (filtered Ri procedures go here) ...
  RtToken         (*Declare)(char *name, char *declaration);
  RtVoid          (*FrameBegin)(RtInt frame);
  RtVoid          (*FrameEnd)();
  RtVoid          (*WorldBegin)();
  RtVoid          (*WorldEnd)();
  ... (more Ri procedures) ...
};

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.

RifPlugin* RifGetCurrentPlugin();

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.

RifGetChain(RifPlugin *chaincopy[], int *count)

This routine fills the chaincopy array with the current chain. The API assumes that the size of the array is large enough to accomate the entire chain. Prior to making this call, clients should obtain the current rif chain size via RifGetChainInfo. RifGetChain doesn't include rif markers, so the length of the chain returned by RifGetChainInfo may be larger than than that returned by this procedure.

RifSetChain(RifPlugin *newchain[], int count)

This routine resets the current chain to newchain.

RifPushChain(), RifPopChain()

This routines manipulate the rif chain stack and facilitate its temporary manipulation. Typically clients push, edit, process, then pop the rif chain.


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.

RtToken RifGetToken(const char *str);

This function takes a pointer to a string and returns a token that can be used for equality comparison to other builtin RtTokens or other strings that have been tokenized by this function.

RtVoid RifGetCurrentBasisSteps(int *usteps, int *vsteps);

This function returns the current basis settings in the usteps and vsteps parameters. This can be used to determine the size of primitive variables for the RiPatchMesh and RiCurves primitives.


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 "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<const char *, unsigned>::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);
}