Extensions to the RenderMan Interface

This document describes extensions to the RenderMan Interface and RIB format supported by RenderDotC.

Contents:
- RiDeclare: new classes
- RiReadArchive
- RiProcedural: new forms
- RiCoordSysTransform
- RiPoints
- RiCurves
- RiNuCurves
- RiSubdivisionMesh
- RiDisplay: arbitrary output variables
- RiQuantize: separate alpha
- RiPixelFilter: new filters
- RiObjectFree and RiLightFree
- Inline token declarations
- gzipped RIB
- Client library extensions


RiDeclare: constant, vertex, vector, normal, hpoint

The specification says that variables may be declared to have uniform or varying class (or vertex for predefined tokens only).  RenderDotC allows user-defined variables to have any of four classes:
  • constant
  • uniform
  • varying
  • vertex
  • Variables that are defined constant carry exactly one value per primitive. That value is ultimately passed to the shader as a uniform variable.  Note that variables may not be declared "constant" in shaders.

    Vertex variables carry one value per control vertex (e.g. "P").  These values are then handled and interpolated just like the control vertices themselves and are ultimately delivered to the shader as varying variables. Note that variables may not be declared "vertex" in shaders.

    RenderDotC also supports three new variable types: vector, normal and hpoint. Vector and normal variables are like points except that they are transformed differently when projected to the "current" coordinate system of the shader. Homogeneous points contain four components (x, y, z, w) and may be declared using the hpoint type.  After being projected to "current" coordinates, hpoints are divided through by w and delivered to the shader as regular points.  There is not hpoint type in SL.


    RiReadArchive

    A call has been added for including a RIB file from another RIB file or at any point during a program using the RenderMan Interface:
    RiReadArchive(RtToken name, RtCallbackFunc callback, ...)
    RiReadArchiveV(RtToken name, RtCallbackFunc callback, RtInt n,
        RtToken tokens[], RtPointer parms[]);
    In RIB:
    ReadArchive "name"
    The RIB version is essentially a #include.  The C bindings provide an additional callback function.  This feature is currently unimplemented.


    RiProcedural: DelayedReadArchive, RunProgram, and DynamicLoad

    New forms of procedural primitives are available that can be used from RIB.  They are detailed in the document "Writing Procedural Primitives".


    RiCoordSysTransform

    This function sets the current transformation to match a predefined or previously user-defined space:
    RiCoordSysTransform(RtToken space)
    In RIB:
    CoordSysTransform "space"
    The space may be predefined such as "object", "world", "camera", "screen", "NDC", or "raster".  Alternatively, the space may have been defined earlier in the stream with a call to RiCoordinateSystem.


    RiPoints

    A new primitive has been added for efficiently rendering a large number of particles.  For particle systems, this primitive should be used instead of other primitives such as spheres:
    RiPoints(RtInt nverts, ...)
    RiPointsV(RtInt nverts, RtInt n, RtToken tokens[], RtPointer parms[])
    In RIB:
    Points parameterlist
    The parameterlist must contain at least positional information "P" or "Pw". There is one position per point.  The surface shader is evaluated only once per point, with P being right at the center.  Other shader variables such as du, dv, and N are meaningless and should be ignored by the shader.

    After being shaded, each point is rendered as a hexagon oriented to face the camera.  This orientation may not be changed.  Points should never be culled due to backfacing.

    The diameter of each hexagon is specified in object coordinates (not pixels) and defaults to 1.0.  If all points in a set are to be the same width, the "constantwidth" variable may be used in the parameterlist.  Being declared "constant float", "constantwidth" takes one value regardless of the number of vertices. To set the width of each point independently, use the "width" parameter. It's a varying float and thus takes nverts distinct width values.


    RiCurves

    Two primitives have been added for drawing 3D curves.  RiCurves is described here and RiNuCurves is described in the next section.  Each curve can be thought of as a ribbon.  It is ideal for modeling hair, grass, and narrow tubes:
    RiCurves(RtToken type, RtInt ncurves, RtInt nvertices[], RtToken wrap, ...)
    RiCurvesV(RtToken type, RtInt ncurves, RtInt nvertices[], RtToken wrap,
        RtInt n, RtToken tokens[], RtPointer parms[]),
    In RIB:
    Curves "type" [nvertices] "wrap" parameterlist
    The spine can twist smoothly around in 3D.  Across the width of the curve (perpendicular to the spine) the primitive is always flat.  For this reason, a narrow width is often chosen.  If the primitive must curve across its width, a bicubic patch should be used instead.

    The first argument must be either "linear" or "cubic" (note: not "bilinear" nor "bicubic").  A linear curve is really a 3D polyline with some thickness. Cubic curves obey the vbasis from the RiBasis function.  The basis may be predefined such as bezier and b-spline, or it may be defined by the user.

    The second argument says how many distinct curves to render.  Unlike trim curves, there is no requirement that consecutive curves line up head to tail or form a closed loop.

    The number of vertices in curve number i is given by nvertices[i].  For linear curves, the number of vertices may be any number greater than or equal to 2.  For cubic curves, there must be four or more vertices in each curve.  An additional constraint is put on the number of vertices in a cubic curve. A nonperiodic cubic curve must have (vstep * k + 4) vertices where k is an integer greater than or equal to 0 and vstep is the step size of the current v basis. A periodic cubic curve must have (nvstep * k) vertices for k greater than 0.  For example, a nonperiodic Bezier curve may have 4 or 7 vertices but not 5 nor 6.

    The wrap argument may be either "periodic" or "nonperiodic".  Periodic curves automatically repeat the first (4 - vstep) vertices in order to form closed loops.  If "periodic" is specified, every curve in the set will close on itself.  Nonperiodic curves have two distinct ends.

    The parameterlist must contain at least position data "P" or "Pw".  If normals "N" are specified, the curve will twist to remain perpendicular to the N. This may cause part of the curve to face away from the camera.  Becuase N is a varying variable, one value is given for each end of the curve and for every joint between consecutive curve segments. The normal is linearly interpolated in between.  In the case of a cubic curve, this will be less than the number of vertices.  If normals are not specified, the curve will automatically turn to face the camera for its entire length.

    The width of the curve is specified in object coordinates (not pixels) and defaults to 1.0.  If the curve is to have a uniform width, the "constantwidth" variable may be used in the parameterlist.  Being declared "constant float", "constantwidth" takes one value regardless of the number of vertices. To make the width of the curve vary, use the "width" parameter. A width is given for each end of the curve and for every joint between consecutive curve segments. The width is linearly interpolated in between.  For even greater control over the width of a curve, redeclare width as a vertex parameter:

        Declare "width" "vertex float"

    After that, specify a different width value for every vertex.  The width will be linearly interpolated in between.

    The surface shader will be evaluated many times along the length of the curve (in the v direction) and at least twice across the width (the u direction).  For wide curves, it may be evaluated even more often across the width.  All of the shading variables are meaningful within the shader including du, dv, and N.  One caveat is that user vertex data is not interpolated across the width of curves.  Instead, the same value is duplicated in the u direction.  This means that the "make sticky" procedure is ineffective with curves if color variation across the curve width is important.

    The number of values for each class of variable is as follows:

    constant: 1 for entire RiCurves
    uniform: ncurves
    varying: (totalsegs + ncurves) if wrap is "nonperiodic"
                  totalsegs if wrap is "periodic"
    vertex: totalverts
    Where totalverts = sum(nvertices[i]) and
    totalsegs =
    sum(nvertices[i]) for periodic, linear curves
    sum(nvertices[i] - 1) for nonperiodic, linear curves
    sum(nvertices[i] / vstep) for periodic, cubic curves
    sum((nvertices[i] - 4) / vstep + 1) for nonperiodic, cubic curves


    RiNuCurves

    A more general form of curve is provided by RenderDotC: the nurb curve. RiCurves is to RiPatch as RiNuCurves is to RiNuPatch.  The spine of each nurb curve is specified as a non-uniform rational B-spline curve in homogeneous space:
    RiNuCurves(RtInt ncurves, RtInt nvertices[], RtInt order[],
        RtFloat knot[], RtFloat min[], RtFloat max[], ...)
    RiNuCurvesV(RtInt ncurves, RtInt nvertices[], RtInt order[],
        RtFloat knot[], RtFloat min[], RtFloat max[], RtInt n,
        RtToken tokens[], RtPointer parms[])
    In RIB:
    NuCurves [nvertices] [order] [knot] [min] [max] parameterlist
    Note the similarities between RiNuCurves and RiTrimCurves.

    The spine can twist smoothly around in 3D.  Across the width of the curve (perpendicular to the spine) the primitive is always flat.  For this reason, a narrow width is often chosen.  If the primitive must curve across its width, a nurb patch should be used instead.

    The first argument says how many distinct curves to render.  Unlike trim curves, there is no requirement that consecutive curves line up head to tail or form a closed loop.

    The number of vertices in curve number i is given by nvertices[i].

    The order of each curve must be positive and is equal to the degree of the polynomial basis plus 1.  There must be at least order[i] vertices in curve number i.

    Each curve has (nvertices[i] + order[i]) knots.  These knots must appear in non-decreasing order.  The knots for all of the curves are concatenated into a single array.

    Each curve is defined in the parametric space from min[i] to max[i].  Each min[i] must be less than max[i].  Also, min[i] should be greater than or equal to the corresponding (order[i] - 1)th knot value and max[i] should be less than or equal to the (nvertices[i])th knot value for curve i.

    The parameterlist must contain at least position data "P" or "Pw".  If normals "N" are specified, the curve will twist to remain perpendicular to the N. This may cause part of the curve to face away from the camera.  Becuase N is a varying variable, one value is given for each end of the curve and for every joint between consecutive curve segments. The normal is linearly interpolated in between. If normals are not specified, the curve will automatically turn to face the camera for its entire length.

    The width of the curve is specified in object coordinates (not pixels) and defaults to 1.0.  If the curve is to have a uniform width, the "constantwidth" variable may be used in the parameterlist.  Being declared "constant float", "constantwidth" takes one value regardless of the number of vertices. To make the width of the curve vary, use the "width" parameter. A width is given for each end of the curve and for every joint between consecutive curve segments. The width is linearly interpolated in between.  For even greater control over the width of a curve, redeclare width as a vertex parameter:

        Declare "width" "vertex float"

    After that, specify a different width value for every vertex.  The width will be linearly interpolated in between.

    The surface shader will be evaluated many times along the length of the curve (in the v direction) and at least twice across the width (the u direction).  For wide curves, it may be evaluated even more often across the width.  All of the shading variables are meaningful within the shader including du, dv, and N.  One caveat is that user vertex data is not interpolated across the width of curves.  Instead, the same value is duplicated in the u direction.  This means that the "make sticky" procedure is ineffective with curves if color variation across the curve width is important.

    The number of values for each class of variable is as follows:

    constant: 1 for entire RiNuCurves
    uniform: ncurves
    varying: (totalsegs + ncurves)
    vertex: totalverts
    Where totalverts = sum(nvertices[i]) and
    totalsegs = sum(nvertices[i] - order[i] + 1)


    RiSubdivisionMesh

    RenderDotC now supports Catmull-Clark subdivision surfaces.  The RiSubdivisionMesh primitive is specified in a manner similar to RiPointsPolygons, with additional tags to control corners, creases, etc:

        RiSubdivisionMesh(RtToken scheme, RtInt nfaces, RtInt nvertices[],
            RtInt vertices[], RtInt ntags, RtToken tags[], RtInt nargs[],
            RtInt intargs[], RtFloat floatargs[], ...)
        RiSubdivisionMeshV(RtToken scheme, RtInt nfaces, RtInt nvertices[],
            RtInt vertices[], RtInt ntags, RtToken tags[], RtInt nargs[],
            RtInt intargs[], RtFloat floatargs[], RtInt n, RtToken tokens[],
            RtPointer parms[]);

    In RIB:

        SubdivisionMesh scheme [nvertices] [vertices]
            {[tags] [nargs] [intargs] [floatargs]} parameterlist

    In all cases, scheme must be "catmull-clark".

    At the top level, a subdivision mesh consists of a set of faces.  The number of faces is given by nfaces.  The nvertices[] array says how many vertices make up each face.  The length of the nvertices[] array is nfaces.  Next is the vertices[] array, containing a 0-based  index into the vertex data of the parameter list for each vertex of each face.  The length of the vertices[] array is equal to the sum of all the elements of the nvertices[] array.  This part of the syntax is identical to RiPointsPolygons.

    Additional subdivision control is provided through "tags".  RenderDotC currently implements the tags in the following table.  Additional tags may not be defined by the user (i.e. the set of available tags is fixed by the renderer).
     
    Tag name: Applies to: Integer arguments: Float arguments:
    "hole" faces n 0
    "corner" vertices n 1 or n
    "crease" chain of edges n 1
    "interpolateboundary" mesh 0 0
    Each tag is predefined to apply to subdivision vertices, edges, faces, or the mesh as a whole.  Each tag may have integer and/or floating point arguments.  Let's look at the semantics of one of the available tags as an example before digging into the general syntax of tags.

    Hole

    This tag indicates that one or more faces are holes and should not be visible.  Holes are useful when a face exists only for its influence over adjacent faces.  The "hole" tag takes any number of integer arguments, each of which is the index of a face to be tagged as a hole.  This is how you would tag faces 2 and 6 as holes in RIB:

        ["hole"] [2 0] [2 6] []

    [This example and those below are excerpts of just the tag information.  A complete example would start with "SubdivisionMesh" and end with "P" followed by the positions of the control mesh.]

    Reading left to right, this says that tag "hole" takes 2 integer arguments and 0 floating point arguments.  The integer arguments are 2 and 6, the indeces of the faces to be tagged as holes.  There aren't any floating point arguments, so the final list is empty.

    Tag syntax

    In general, ntags may be zero, one or more.  The tags[] array contains ntags tokens.  Only the tokens in the table above will be recognized.  For each element of tags[], there will be two numbers in the nargs[] array representing the number of integer and floating point arguments.  The table above governs the allowable values in nargs[].  The size of nargs[] is ntags times 2.  All of the integer arguments for the tags should be concatenated, in order, and placed in the intargs[] array.  Likewise for the floating point arguments and the floatargs[] array.  The length of intargs[] is the sum of all even numbered entries in nargs[].  The length of floatargs is the sum of the odd numbered entries in nargs[].

    If there are no tags at all, then all of the tag parameters may be omitted in the RIB binding.

    Corner

    Vertices that are tagged as corners remain at their original position and are not smoothed.  The "corner" tag takes n integer arguments specifying the indeces of the vertices that should be corners.  It takes 1 or n floating point arguments specifying the sharpnesses of the corners.  RenderDotC currently allows corners to be either perfectly sharp or smooth.  Values of sharpness greater than or equal to 10 represent infinitely sharp.  Anything less than 10 is interpreted as smooth.

    An example:

        ["corner"] [4 1] [0 1 4 5] [10]

    This tags vertices 0, 1, 4, and 5 as infinitely sharp.

    Crease

    Creases are sharp edges.  They always follow a straight line between the vertices at either end of the edge.  The "crease" tag takes 2 or more integer arguments specifying the indeces of a series of vertices.  The edges to be creased are found by "connecting the dots" between these vertices.  It is an error to pass a list of vertices that cannot be traversed by single edges in the original mesh.  If you need to specifiy two or more disconnected chains of edges, use additional "crease" tags.  The "crease" tag takes 1 floating point argument that should be 10 or more to indicate infinitely sharp edges.  Anything less than 10 is smooth, which is what the edge would be anyway if it weren't marked as a crease.

    For example:

        ["crease"] [5 1] [0 1 4 5 0] [10]

    This marks a loop of 4 edges as infinitely sharp creases.

    Interpolate Boundary

    The "interpolateboundary" tag says that any boundary edge (i.e. an edge referenced by only one face) should be tagged as infinitely sharp crease and that every corner vertex (i.e. with two incident edges) should be tagged as an infinitely sharp corner.  This has the effect of rendering the subdivision surface all the way out to the original circumference of the control mesh.  The "interpolateboundary" tag takes 0 integer arguments and 0 floating point arguments:

        ["interpolateboundary"] [0 0] [] []

    A complex example

    When specifying more than one tag, the nargs[], intargs[] and floatargs[] arrays are simply concatenated in the same order as the tags.  Combining all of the examples above into one would result in:

        ["hole" "corner" "crease" "interpolateboundary"] [2 0 4 1 5 1 0 0] [2 6 0 1 4 5 0 1 4 5 0] [10 10]

    Compare this example to those above to see how it was constructed.


    RiDisplay: arbitrary output variables

    In the RenderMan API

    RiDisplay supports a new syntax for specifying multiple simultaneous display streams.  Initially, the list of display streams is empty.  If the first parameter of RiDisplay starts with a plus sign '+', then the display stream is added to the current list.  There is no arbitrary limit on the maximum number of display streams.  If the name follows the old syntax and does not start with a plus sign, then the list is cleared before adding the new display.  For example:

    RtString midpoint = "midpoint";
    RiDisplay("patch.tif", "file", "rgb", RI_NULL);
    RiDisplay("+patch.z", "zfile", "z", "filter", &midpoint, RI_NULL);
    Note that it's acceptable for every RiDisplay to begin with a '+' including the first.  The way the rules are worded, the list is initially empty and you can just start adding to the list using the plus sign syntax.  If there are no Display commands at all, Display "RenderDotC" "framebuffer" "rgb" is added by default at WorldBegin.  If any argument to RiFormat is negative, default values are queried from the first display driver in the list.

    Besides the standard combinations of "rgb", "a", and "z", the mode parameter may be any of the following RenderMan globals:

    P, N, Ng, dPdu, dPdv, Ci, Oi, s, t, u, v, du, dv, Cs, or Os
    Mode may also be the name of a shader variable declared as "output" in the surface shader.  In this case, the variable must be RiDeclared before it is referenced in RiDisplay, and the type must be point, vector, normal, float, or color.  The global variables in the list above are predeclared by RenderDotC and do not need to be redeclared.  If no surface shader output variable with a matching name is found, then the display channel will be filled with zeros.

    Output variables of type color are hidden just like "rgb" in that partially transparent objects attenuate the color of the objects behind them.  Variables of all other types (float, point, vector, and normal) are only affected by the closest surface, regardless of its opacity.

    Again, the first RiDisplay is as flexible as subsequent displays.  The mode of the first display can be any of the above, not just rgb/a/z.  Subsequent displays can also have any mode, including rgb/a/z.

    In surface shaders

    To export a shader variable for display, declare it as "output" in a surface shader:

    surface glow(output varying color Cg = 0;
                 output varying color Og = 0)
    Variables output from non-surface shaders (e.g. displacement) may not be displayed.  Uniform output variables are acceptable.  They will be promoted to varying by the renderer at display time.

    Exposure

    The traditional RiExposure command now affects only display streams with mode "rgb".  The exposure of any channel may be explicitly set with the "gain" and "gamma" parameters:

    Display "name" "driver" "var" "gain" [1.5] "gamma" [2.1]
    The default value for both gain and gamma is 1.0 except for "rgb" display streams, which get their defaults from RiExposure.

    Quantization

    The recommended way to set the quantization of a display stream is explicitly in the Display command:

    Display "name" "driver" "var" "quantize" [zero one min max] "dither" [ampl]
    Where zero, one, min and max are integers and ampl is floating point.  This is the only way to specify a value for zero other than 0.0 (the RiQuantize command only sets one, min, max, and ampl).  The classic example of a case where zero might not equal 0.0 is when displaying normalized vector data.  Each component of a normalized vector ranges in value from -1.0 to 1.0.  To display such data on a 24-bit framebuffer:
    Display "vector" "framebuffer" "Nf" "quantize" [128 255 0 255] "dither" [0.5]
    This will map -1.0 to black, 0.0 to gray, and 1.0 to white.

    If the quantization parameters are not specified in the Display command,  the renderer honors an Quantize command whose type matches the mode of the Display:

    Declare "Cg" "varying color"
    Display "+glow.tif" "tiff" "Cg"
    Quantize "Cg" 65535 0 65535 0.5
    The Quantize command must appear after the corresponding Display command.

    For display streams where neither of the above methods is used, quantization defaults to the values specified in Quantize "rgb" or Quantize "z" depending on the choice of filter (see below).

    Filtering

    The PixelFilter command sets the default filter kernel and filterwidths for all display streams.  Individual display streams may be filtered differently by passing parameters to the Display command:

    Display "name" "driver" "var" "filter" ["sinc"] "filterwidth" [4 4]
    This display stream will be treated as a depth channel if filter is set to "min", "midpoint", "average" or "max".  Depth channels may be hidden, quantized, and filtered differently than other channels.  For example, surfaces whose opacity does not meet the zthreshold option are ignored when hiding depth channels.  For non-depth channels, choices for filter include "bartlett", "bessel", "catmull-rom", "disk", "gaussian", "sinc", and "triangle".

    Each display stream may have different filterwidths, the largest of which impacts how much "off-screen" geometry needs to be considered by the hider.


    RiQuantize: separate alpha

    The RenderMan Specification says that RiQuantize may be applied to color and alpha (RI_RGBA) or depth (RI_Z).  RenderDotC allows separate quantization control of color (RI_RGB) and alpha (RI_A).  For example:

        RiQuantize(RI_RGB, 4095, 0, 65535, 0.5);
        RiQuantize(RI_A, 65535, 0, 65535, 0.5);

    For an understanding of why this might be useful, see Color Quantization For Film.

    Specifying the type RI_RGBA is equivalent to setting RI_RGB and RI_A to the same parameters:

        RiQuantize(RI_RGBA, 65535, 0, 65535, 0.5);

    is equivalent to:

        RiQuantize(RI_RGB, 65535, 0, 65535, 0.5);
        RiQuantize(RI_A, 65535, 0, 65535, 0.5);


    RiPixelFilter: RiBesselFilter, RiDiskFilter, and RiBartlettFilter

    Exactly five pixel filters were defined in the RenderMan Interface Specification: Box, Triangle, Gaussian, Sinc, and Catmull-Rom.  RenderDotC provides three additional filters: Bessel, Disk, and Bartlett.  They may be selected as follows:

        RiPixelFilter(RiBesselFilter, 4, 4);
        RiPixelFilter(RiDiskFilter, 2, 2);
        RiPixelFilter(RiBartlettFilter, 4, 4);

    Or, in RIB:

        PixelFilter "bessel" 4 4
        PixelFilter "disk" 2 2
        PixelFilter "bartlett" 4 4

    Like the Sinc and Catmull-Rom filters, the Bessel filter is not widened or narrowed by adjusting xwidth and ywidth.  Rather it is clipped: the filter retains it shape and is only evaluated over the bounds determined by xwidth and ywidth.

    The Disk filter is identical to the Box filter except that it is elliptical when viewed from above (round if xwidth equals ywidth).  The Box filter is square.

    The Disk filter shown in the figure above is for xwidth = ywidth = 2.

    The Bartlett filter is identical to the Triangle filter except that it is separable (i.e. the product of two 2D triangle filters).  Along the x and y axes, the Triangle and Bartlett filters are identical.  Along diagonals such as x = y, Bartlett becomes parabolic.


    RiObjectFree and RiLightFree

    When a retained geometry object created with RiObjectBegin() is no longer needed, the RenderDotC user may reclaim memory by calling RiObjectFree():
    RtObjectHandle handle;
    handle = RiObjectBegin();
    ...
    RiObjectEnd();
    RiObjectInstance(handle);
    ...
    RiObjectFree(handle);
    In RIB, a user-provided integer is used for the handle:
    ObjectBegin 7
    ...
    ObjectEnd
    ObjectInstance 7
    ...
    ObjectFree 7
    Likewise, lights may be freed when no longer needed:
    RtLightHandle handle;
    handle = RiLightSource(...);
    ...
    RiLightFree(handle);
    Or, in RIB:
    LightSource "barn" 4 ...
    ...
    LightFree 4
    There are two circumstances where RenderDotC will automatically free lights and objects.  The first is if the light or object is defined within a scope such as a Frame block or World block.  When a scope ends, all lights and objects defined within it are freed.  The second case is when an object handle is reused in the RIB binding.  Because the new use of the handle will hide the old one, the old object is automatically freed.  Reusing light handles does not cause the light to be freed because the old light may still be in the illuminated list.  No harm is caused if a light or object is manually freed prior to when it would be automatically freed.  It is an error to instantiate an object after it has been manually freed or gone out of scope.  It is also an error to manually free a light or object after it has been automatically freed.


    Inline token declarations

    The RenderMan 3.1 spec required that all tokens be RiDeclared before being used as parameters.  RenderDotC now allows tokens to be declared "inline" as they are being used:
    Surface "hair" "uniform color rootcolor" [0.15 0.05 0.01]
    The syntax of the declaration is similar to that of RiDeclare except that the name of the token appears at the end of the declaration string.


    gzipped RIB

    The RenderMan Interface Specification 3.1 described two RIB formats: ascii and binary.  The RenderDotC client library can automatically compress either format using the gzip library.  This is equivalent to generating the RIB first and then compressing it with gzip.

    The renderdc program is now capable of directly reading gzipped RIB.  The program catribdc can be used to translate between ASCII, binary, and gzipped RIB.


    Client library extensions

    RenderDotC's RIB client library, ribdc, fully adheres to the RenderMan 3.2 specification.  As such, it implements the following functions:
    RiBlobby(RtInt nleaf, RtInt ninst, RtInt inst[], RtInt nflt,
        RtFloat flt[], RtInt nstr, RtToken str[], ...)
    RiBlobbyV(RtInt nleaf, RtInt ninst, RtInt inst[], RtInt nflt,
        RtFloat flt[], RtInt nstr, RtToken str[], RtInt n,
        RtToken tokens[], RtPointer parms[])
    RtContextHandle RiGetContext(void)
    RtVoid RiContext(RtContextHandle context)
    RiArchiveRecord("verbatim", ...)
    It also recognizes the "mpoint" token type used by the RiBlobby primitive.


    Copyright © 1999-2006 Dot C Software, Inc. All rights reserved.
    Dot C Software, Inc., 182 Kuuhale St., Kailua, HI 96734
    (808) 262-6715 (voice) (808) 261-2039 (fax)
    The RenderMan® Interface Procedure and RIB Protocol are:
    Copyright © 1988, 1989, Pixar.  All rights reserved.
    RenderMan® is a registered trademark of Pixar.