In addition to the display drivers supplied with PRMan, users may extend the system by writing their own custom drivers. This allows for new image or geometry types or framebuffers to be directly supported for rendering.
Display drivers are written as dynamic shared objects (DSOs), which are also known as dynamic link libraries. (You should consult the documentation for your compiler on how to compile and link these objects.) You may compile your display DSO's either with a 'C' or 'C++' compiler, but you must use 'C' linkage -- i.e. if you use C++, you need to use extern "C" to guarantee C-style linkage. A header file has been provided, ndspy.h, which contains function prototype declarations which should be used when writing display drivers, as these prototypes should guarantee that the correct linking and exporting of symbols occurs across various platforms.
Please note, however, that RenderMan Pro Server for OSX display driver DSOs do not support Objective C (ObjC).
Display driver DSOs must export and implement at least four required functions:
Data to the display drivers will be provided in a variety of formats and byte orders. The display driver can then choose which formats and byte orders it would prefer that data in. Constants for those formats are defined in ndspy.h. The names should be self explanatory: PkDspyFloat32, PkDspyUnsigned32, PkDspySigned32, PkDspyUnsigned16, PkDspySigned16, PkDspyUnsigned8 and PkDspySigned8.
A few more types are defined for optional parameters: PkDspyString, PkDspyMatrix.
If byte orders aren't specified, the machine default is assumed. Byte order can be specified by "or"ing in one of two values:
All functions return one of the following enumerated error codes:
PtDspyError DspyImageOpen(PtDspyImageHandle * image, const char *drivername, const char *filename, int width, int height, int paramCount, const UserParameter *parameters, int formatCount, PtDspyDevFormat *format, PtFlagStuff *flagstuff);
This opens an image called filename and puts a handle to any local data into *image. If width or height is 0, it chooses an appropriate default value for them.
drivername is the name before the /display/dso or /display/dsomapping translation. This allows a single driver to change its behavior based on the name used in the RIB file.
Image types which can include various other tag information might investigate the parameters, which are passed through from the RIB Display line. A list of the commonly interpreted ones appears later in this document. Two important points: The data pointed to by both the parameters structures and the format structures is valid only for the duration of this function call, copy any information that you plan to reuse to your own structures; and the values pointed to by the UserParameter structure are not necessarily aligned, which is why all of the helper functions copy this information to your own variables rather than trying to use them in place.
formatCount and format describe the data as it will be sent to the driver. Display drivers should reorder the format array into the order it expects to deal with data (it is important that the format.name fields point to the original strings!), and set format[x].type to types and byte orders that it can deal with. Geometry drivers (those that have responded to the PkPointCloudQuery) will be supplied information about the format of the extended data they will receive in DspyImageDeepData. The format.name field will contain data types and names formatted with the syntax:
(uniform|varying) float|point|vector|normal|color|matrix name.XXX
The trailing .XXX information exists to ensure a unique channel * identifier, and can be ignored.
Finally, flagstuff allows the driver to request that data be sent in different ways. Three flags can be "OR"ed into flagstuff->flags:
If you don't use PkDspyFlagsWantsScanLineOrder the renderer won't call DspyImageData for regions of the image where it doesn't draw anything. Don't assume that the entire image (or even any of the image, if none of the geometry is visible) will be filled in.
This example will implement a trivial image format. It makes no allowances for differences between platforms. The format is just an "int" which is the number of channels being sent to this image, that many strings, which name them all, and that many floating point values per pixel for the rest of the image.
#include <ndspy.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { FILE *file; int channels; int width, height; } *MyImageType; PtDspyError DspyImageOpen(PtDspyImageHandle *pvImage, const char *drivername, const char *filename, int width, int height, int paramCount, const UserParameter *parameters, int formatCount, PtDspyDevFormat *format, PtFlagStuff *flagstuff) { PtDspyError ret; MyImageType image; /* We want to receive the pixels one after the other */ flagstuff->flags |= PkDspyFlagsWantsScanLineOrder; /* Do stupidity checking */ if (0 == width) width = 640; if (0 == height) height = 480; image = NULL; ret = PkDspyErrorNone; image = (MyImageType) malloc(sizeof(*image)); if (NULL != image) { int i; image->channels = formatCount; image->width = width; image->height = height; image->file = fopen(filename, "wb"); if (image->file) { fwrite(&formatCount, sizeof(formatCount), 1, image->file); for (i = 0; i < formatCount; i++) { format[i].type = PkDspyFloat32; fwrite(format[i].name, strlen(format[i].name) + 1, 1, image->file); } } else { free(image); image = NULL; ret = PkDspyErrorNoResource; } } else ret = PkDspyErrorNoMemory; *pvImage = image; return ret; }
PtDspyError DspyImageQuery(PtDspyImageHandle pvImage, PtDspyQueryType type, size_t size, void *p);
DspyImageQuery
is used to communicate state
information about the features of the display driver and the image
the display driver can produce. Each query is made by calling
DspyImageQuery
with a query-type and corresponding
query-structure passed as p. DspyImageQuery
fills
values in the query-structure and returns a value indicating the
sucess or failure of the query.
The following query-types may be passed to
DspyImageQuery
:
PkSizeQuery: Asks for the size of the image, or a default size of no image is supplied (pvImage may be NULL!). It will be called with an image handle when the DspyImageOpen was called with a 0 width and height. It will also be called without an image handle for applications which want to query for a fixed image size (as might happen with a framebuffer).
PkOverwriteQuery: Asks whether the driver in question actually overwrites the file name given, and is used to keep the user from accidentally overwriting an image. The response structure, PtDspyOverwiteInfo, has two fields. The .overwrite field tries to keep the user from doing damage when using tools like sho for image conversion, or when writing to the "framebuffer" display device which may be mapped to something destructive. The .interactive field isn't yet used in any tools, the hope was that it would make batch tools a little bit smarter.
PkSupportsCheckpointing: Asks whether the display driver
supports image checkpointing. Image checkpointing allows the
render to skip a portion of a render if the "-recover 1" option is
passed to render. The PkSupportsCheckpointing
is
first issued by the render to all display drivers that are used in
the render. If all respond positively to the
PkSupportsCheckpointing
query, the display drivers
are initialized with DspyImageOpen
, and the
PkRenderingStartQuery
is issued to determine where
restart the render. PkSupportsCheckpointing
is issued
with a NULL pvImage. Any data that needs to be
communicated to the display driver before the
DspyImageOpen
method needs to be initialized upon
receiving PkSupportsCheckpointing
. If the display
driver supports image checkpointing, DspyImageOpen
needs to determine where the render should start.
PkPointCloudQuery: Asks whether the display driver supports geometry (can be used by the bake3d() shadeop). A display driver that sets the supportsPointsClouds field of the PtDspyPointCloudQuery to 1 indicates that it has implemented the DspyImageDeepData routine and is able to handle a collection of point data. The driver will be supplied information about the format of this point data in the DspyImageOpen routine.
PkGridQuery: Asks whether the display driver supports geometry with topological information (can be used by the bake3d() shadeop). A driver that supports this query must also support the PkPointCloudQuery and set the supportsPointClouds field therein to 1. A display driver that sets the supportsGrids field of the PtDspyGridQuery to 1 indicates that it has implemented the DspyImageDeepData routine and is able to handle a collection of point data along with topological information. The driver will be supplied information about the format of this point data in the DspyImageOpen routine.
PkRenderingStartQuery: Asks where the display driver
can recover to. After issuing a
PkSupportsCheckpointing
query, the render knows if it
is possible to recover. The render needs to know how far along in
the image the display driver can recover. The
PtDspyRenderingStartQuery
return structure indicates,
in image space, where the display driver contains its last piece
of valid image data. The render will compile all of the rendering
start locations from all the display drivers to determine where to
start rendering. PkRenderingStartQuery
is called
with a valid pvImage so any information that needs to be
passed to the DspyImageData
needs to be initialized
here. If the display driver supports image checkpointing, the
display driver must ignore all data passed to
DspyImageData
that is less than the value returned in
the PtDspyRenderingStartQuery
structure.
PtDspyError DspyImageQuery(PtDspyImageHandle pvImage, PtDspyQueryType querytype, int datalen, void *data) { PtDspyError ret; MyImageType image = (MyImageType )pvImage; ret = PkDspyErrorNone; if (datalen > 0 && NULL != data) { switch (querytype) { case PkOverwriteQuery: { PtDspyOverwriteInfo overwriteInfo; if (datalen > sizeof(overwriteInfo)) datalen = sizeof(overwriteInfo); overwriteInfo.overwrite = 1; overwriteInfo.interactive = 0; memcpy(data, &overwriteInfo, datalen); break; } case PkSizeQuery : { PtDspySizeInfo sizeInfo; if (datalen > sizeof(sizeInfo)) { datalen = sizeof(sizeInfo); } if (image) { if (0 == image->width || 0 == image->height) { image->width = 640; image->height = 480; } sizeInfo.width = image->width; sizeInfo.height = image->height; sizeInfo.aspectRatio = 1.0f; } else { sizeInfo.width = 640; sizeInfo.height = 480; sizeInfo.aspectRatio = 1.0f; } memcpy(data, &sizeInfo, datalen); break; } case PkRenderingStartQuery : { PtDspyRenderingStartQuery startLocation; if (datalen > sizeof(startLocation)) datalen = sizeof(startLocation); if (image) { /* * initialize values in startLocation */ memcpy(data, &startLocation, datalen); } else { ret = PkDspyErrorUndefined; } break; } default : ret = PkDspyErrorUnsupported; break; } } else { ret = PkDspyErrorBadParams; } return ret; } PtDspyError DspyImageData(PtDspyImageHandle pvImage, int xmin, int xmax_plusone, int ymin, int ymax_plusone, int entrysize, const unsigned char *data) { PtDspyError ret; MyImageType image = (MyImageType )pvImage; int oldx; oldx = xmin; for (;ymin < ymax_plusone; ymin++) { for (xmin = oldx; xmin < xmax_plusone; xmin++) { fwrite(data, sizeof(float), image->channels, image->file); data += entrysize; } } return ret; } PtDspyError DspyImageClose(PtDspyImageHandle pvImage) { PtDspyError ret; MyImageType image = (MyImageType )pvImage; fclose(image->file); free(image); ret = PkDspyErrorNone; return ret; }
PtDspyError DspyImageData(PtDspyImageHandle image, int xmin, int xmax_plusone, int ymin, int ymax_plusone, int entrysize, const unsigned char *data);
Write data for the image area described. entrysize is the skip in bytes to the next pixel in data. Unlike the old dspy system, xmax_plusone and ymax_plusone are 1 more than the last pixel to be written, that is that the width of the region to be written is xmax_plusone-xmin and not xmax-xmin+1.
PtDspyError DspyImageData(PtDspyImageHandle pvImage, int xmin, int xmax_plusone, int ymin, int ymax_plusone, int entrysize, const unsigned char *data) { PtDspyError ret; MyImageType image = (MyImageType )pvImage; int oldx; oldx = xmin; for (;ymin < ymax_plusone; ymin++) { for (xmin = oldx; xmin < xmax_plusone; xmin++) { fwrite(data, sizeof(float), image->channels, image->file); data += entrysize; } } }
PtDspyError DspyImageData(PtDspyImageHandle image, int xmin, int xmax, /* npoints, 0 */ int ymin, int ymax, /* ignored (0) */ char *data, /* filename and point data */ int totalsize, /* total size of all data (in bytes) */ int *pixeloffsets, /* (ignored) */ int *pixelsizes) /* (ignored) */
This entry point is used by geometry drivers (those useable by bake3d()). A geometry driver will receive a list of points with associated data. The points are homogeneous, ie. each point * has the same amount of data. If the driver indicates support for the PkPointCloudQuery only, each point in the input (*data) consists of a position (3 floats), a normal (3 floats), a radius (1 float), and shader specified data (any number of floats), with the last being described in the DspyImageOpen routine. An example of such usage is:
typedef struct { FILE *file; int nvars; char **varnames; int *varsizes; } *PtDspyImage; /*ARGSUSED*/ PtDspyError DspyImageOpen(PtDspyImageHandle *pvImage, const char *drivername, const char *filename, int width, int height, int paramCount, const UserParameter *parameters, int formatCount, PtDspyDevFormat *format, PtFlagStuff *flagstuff) { PtDspyError ret = PkDspyErrorNone; PtDspyImage image; int i, v; int words; char mode[80], type[80], name[256]; image = (PtDspyImage) calloc(1, sizeof(*image)); if (!image) { ret = PkDspyErrorNoMemory; goto error; } image->nvars = formatCount; image->varsizes = (int *) malloc(formatCount * sizeof(int)); image->varnames = (char**) calloc(formatCount, sizeof(char*)); if (!image->varsizes || !image->varnames) { ret = PkDspyErrorNoMemory; goto error; } /* * We require data in this machine's native byte order, so modify * to inform the renderer of this fact. */ for (i = 0; i < formatCount; i++) { format[i].type = (format[i].type & ~PkDspyMaskOrder) | PkDspyByteOrderNative; } /* Look at filename, make sure it's not null. If it is, override */ if (filename == NULL || *filename == '\0') { filename = "ri.ptc"; /* default must be display specific */ } image->file = fopen(filename, "w+b"); if (!image->file) { ret = PkDspyErrorNoResource; goto error; } /* * Extract data types and names from the format information. This * will come in on the format[v].name parameter with the syntax: * * (uniform|varying) float|point|vector|normal|color|matrix name.XXX * * The trailing .XXX information exists to ensure a unique channel * identifier, and can be ignored. */ for (v = 0; v < formatCount; v++) { /* Skip file name */ char* typename = strchr(format[v].name, '|'); if (!typename) { ret = PkDspyErrorUndefined; goto error; } typename++; words = sscanf(typename, "%s %s %s", mode, type, name); if (words == 2) words = sscanf(typename, "%s %s", type, name); for (i = 0; i < strlen(name); i++) /* find first '.' in name */ if (name[i] == '.') break; image->varnames[v] = (char*) malloc(strlen(name)+1); if (!image->varnames[v]) { goto error; } if (strlen(type) == 0) { DspyError(drivername, "Bad type declaration - missing DisplayChannel?\n"); ret = PkDspyErrorBadParams; goto error; } /* Deduce data size */ if (strcmp(type, "float") == 0) { image->varsizes[v] = 1; } else if (strcmp(type, "point") == 0 || strcmp(type, "vector") == 0 || strcmp(type, "normal") == 0 || strcmp(type, "color") == 0) { image->varsizes[v] = 3; } else if (strcmp(type, "matrix") == 0) { image->varsizes[v] = 16; } else { printf("error: unknown variable type '%s' in pointcloud display driver\n", type); /* * Let's just hope that a varsize of 1 will work, better * than leaving this uninitialized. */ image->varsizes[v] = 1; } strncpy(image->varnames[v], name, i); /* clip off ".x" */ image->varnames[v][i] = '\0'; } *pvImage = image; return ret; error: if (image) { if (image->file) fclose(image->file); if (image->varsizes) free(image->varsizes); if (image->varnames) { for (i = 0; i < image->nvars; ++i) { if (image->varnames[i]) { free(image->varnames[i]); } } free(image->varnames); } free(image); } *pvImage = NULL; return ret; } PtDspyError DspyImageDeepData(PtDspyImageHandle pvImage, int xmin, int xmax, /* npoints, 0 */ int ymin, int ymax, /* ignored (0) */ char *data, /* filename and point data */ int totalsize, /* total size of all data (in bytes) */ int *pixeloffsets, /* (ignored) */ int *pixelsizes) /* (ignored) */ { PtDspyImage image = (PtDspyImage )pvImage; float *fdata = (float *)data; float *ptdata; int npoints = xmax - xmin + 1; int i, j, k; int fsize = totalsize / (npoints * sizeof(float)); fprintf(image->file, "Number of points: %d\n", npoints); /* * Pry point positions, normals, radii and data out of the * "unorganized" data list. */ for (i = 0; i < npoints; i++) { ptdata = fdata; /* Position */ fprintf(image->file, "point: %f %f %f\n", ptdata[0], ptdata[1], ptdata[2]); ptdata += 3; /* Normal */ fprintf(image->file, "normal: %f %f %f\n", ptdata[0], ptdata[1], ptdata[2]); ptdata += 3; /* Radius */ fprintf(image->file, "radius: %f\n", ptdata[0]); ptdata++; /* Rest of the data */ for (j = 0; j < image->nvars; ++j) { fprintf(image->file, "%s: ", image->varnames[j]); for (k = 0; k < image->varsizes[j]; ++k) { if (k == image->varsizes[j] - 1) { fprintf(image->file, "%f", *ptdata++); } else { fprintf(image->file, "%f ", *ptdata++); } } fprintf(image->file, "\n"); } fdata += fsize; } fprintf(image->file, "\n"); return PkDspyErrorNone; }
If the driver indicates support for the PkGridQuery as well, the data passed to the driver has the following format:
1 float - style: enum PtDspyGridStyle {PkDspyGridConnected, PkDspyGridLines, PkDspyGridPoints} 1 float - npoints: number of vertices 1 float - npolys: number of polys 1 float - fsize: size of per-vertex data npoints * fsize floats - per vertex data // this is the data as what we would have gotten in the // case where only PkPointCloudQuery was supported. npolys floats: per poly vertex count sum(per poly vertex count) floats - per poly vertex indices
In cases where the style is Lines or Points, the last two fields are not sent and npolys == 0. Otherwise, those fields contain topological information in the same style as style of RiPointsPolygons (i.e. polygon vertex counts followed by polygon vertex indices). Example usage (from the RIB driver) is:
/*ARGSUSED*/ PtDspyError DspyImageDeepData(PtDspyImageHandle pvImage, int xmin, int xmax, /* npoints, 0 */ int ymin, int ymax, /* ignored (0) */ char *data, /* filename and point data */ int totalsize, /* total size of all data (in bytes) */ int *pixeloffsets, /* (ignored) */ int *pixelsizes) /* (ignored) */ { PtDspyImage image = (PtDspyImage )pvImage; // Save renderer context RtContextHandle renderContext = RiGetContext(); // Switch to RIB context RiContext(image->context); RiAttributeBegin(); float *fdata = (float *)data; int style = (int) *fdata++; int npoints = (int) *fdata++; int npolys = (int) *fdata++; int fsize = (int) *fdata++; fsize /= sizeof(float); int i, j, k, offset; // We'll need a buffer to store data to present to the RI interface // in uninterleaved form RtToken *tokens = (RtToken*) malloc((4 + image->nvars) * sizeof(RtToken)); RtPointer *values = (RtPointer*) malloc((4 + image->nvars) * sizeof(RtPointer)); RtFloat *ridata = (RtFloat*) malloc(fsize * npoints * sizeof(RtFloat)); RtFloat *ridataptr = ridata; if (!tokens || !values || !ridata) { RiContext(renderContext); return PkDspyErrorNoMemory; } offset = 0; ridataptr = ridata; // Positions tokens[0] = RI_P; values[0] = ridataptr; float *ptdata = fdata; for (i = 0; i < npoints; i++) { *ridataptr++ = ptdata[0]; *ridataptr++ = ptdata[1]; *ridataptr++ = ptdata[2]; ptdata += fsize; } offset += 3; // Normals tokens[1] = RI_N; values[1] = ridataptr; ptdata = fdata + offset; for (i = 0; i < npoints; i++) { *ridataptr++ = ptdata[0]; *ridataptr++ = ptdata[1]; *ridataptr++ = ptdata[2]; ptdata += fsize; } offset += 3; // Radii - multiplied by two to become width tokens[2] = "varying float width"; values[2] = ridataptr; ptdata = fdata + offset; for (i = 0; i < npoints; i++) { *ridataptr++ = 2.0f * ptdata[0]; ptdata += fsize; } offset += 1; // Rest of the data for (j = 0; j < image->nvars; ++j) { tokens[j + 3] = (RtToken) malloc(strlen("varying") + strlen(image->typenames[j]) + strlen(image->varnames[j]) + 3); if (!tokens[j+3]) { RiContext(renderContext); return PkDspyErrorNoMemory; } sprintf(tokens[j + 3], "varying %s %s", image->typenames[j], image->varnames[j]); values[j + 3] = ridataptr; ptdata = fdata + offset; for (i = 0; i < npoints; i++) { for (k = 0; k < image->varsizes[j]; ++k) { *ridataptr++ = ptdata[k]; } ptdata += fsize; } offset += image->varsizes[j]; } if (style == PkDspyGridConnected) { RtFloat* trimdata = (RtFloat*) malloc(npoints * sizeof(RtFloat)); if (!trimdata) { for (j = 0; j < image->nvars; ++j) { free(tokens[j+3]); } free(tokens); free(values); free(ridata); return PkDspyErrorNoMemory; } RtInt *nvertices = (RtInt*) malloc(npolys * sizeof(RtInt)); if (!nvertices) { RiContext(renderContext); return PkDspyErrorNoMemory; } // Skip ahead to the face information fdata = ((float*) data) + 4 + npoints * fsize; int vsize = 0; for (i = 0; i < npolys; ++i) { nvertices[i] = (RtInt) (*fdata++); vsize += nvertices[i]; } RtInt *vertices = (RtInt*) malloc(vsize * sizeof(int)); if (!vertices) { RiContext(renderContext); return PkDspyErrorNoMemory; } RtInt *verticeptr = vertices; for (i = 0; i < npolys; ++i) { for (j = 0; j < nvertices[i]; ++j) { *verticeptr++ = (RtInt) (*fdata++); } } // Output trim information tokens[image->nvars + 3] = "uniform float __needstrim"; values[image->nvars + 3] = trimdata; for (i = 0; i < npolys; ++i) { trimdata[i] = (RtFloat) (*fdata++); } RiPointsPolygonsV(npolys, nvertices, vertices, image->nvars + 4, tokens, values); free(nvertices); free(vertices); free(trimdata); } else if (style == PkDspyGridPoints) { RiPointsV(npoints, image->nvars + 3, tokens, values); } else if (style == PkDspyGridLines) { RiCurvesV(RI_LINEAR, 1, &npoints, RI_NONPERIODIC, image->nvars + 3, tokens, values); } RiAttributeEnd(); // Switch back to renderer context RiContext(renderContext); for (j = 0; j < image->nvars; ++j) { free(tokens[j+3]); } free(tokens); free(values); free(ridata); return PkDspyErrorNone; }
PtDspyError DspyImageClose(PtDspyImageHandle);
Simply free any resources associated with the image handle.
PtDspyError DspyImageClose(PtDspyImageHandle pvImage) { PtDspyError ret; MyImageType image = (MyImageType )pvImage; fclose(image->file); free(image); ret = PkDspyErrorNone; }
PtDspyError DspyImageDelayClose(PtDspyImageHandle);
There are situations where a display manager might want to keep running after the renderer has finished sending data. For instance, a driver which displays images in a window may want to keep that window available for user manipulation. This function is the perfect place to put a display loop; simply don't return until the window is closed.
If this function exists in the display driver, then the display driver will run in a separate process from the main renderer and the renderer itself will exit as soon as the image is complete. This is important for two reasons:
In order to use the shared object, the renderer must be able to find it. When you pass a format name in via the type (second) parameter to RiDisplay:
Common usage is to put the driver into ${RMANTREE}/etc/ named d_type.so or d_type.dll.
There are a set of basic functions that nearly every image implementation needs to do. Many of these have to do with accessing parameters, which are either predefined or passed through from the RIB Display line. These are automatically made available by the renderer, and do not require linking with any further files.
PtDspyError DspyFindStringInParamList(const char *string, char **result, int paramCount, const UserParameter *parameters)If string is found in parameters, put a pointer to it in *result and return PkDspyErrorNone, else return PkDspyErrorNoResource.
char *result = NULL; DspyFindStringInParamList("secondchoice", &result, paramCount, parameters); DspyFindStringInParamList("firstchoice", &result, paramCount, parameters); if (result) { ...
void DspyMemReverseCopy(unsigned char *target, const unsigned char *source, int len);
Fairly self explanatory. Reverse len bytes from source to target.
PtDspyError DspyFindMatrixInParamList(const char *string, float *result, int paramCount, UserParameter *parameters)
Example:
float matrix[16]; if (DspyFindMatrixInParamList("NP", matrix, paramCount, parameters)) { ...
PtDspyError DspyFindFloatInParamList(const char *string, float *result, int paramCount, const UserParameter *parameters)
Get a floating point value from the parameter list. Here's an example of getting the near clipping plane from the parameter list:
float nearClip; DspyFindFloatInParamList("near", &nearClip, paramCount, parameters);
PtDspyError DspyFindFloatsInParamList(const char *string, int *resultCount, float *result, int paramCount, const UserParameter *parameters)
Get a floating point array from the parameter list. Similar to DspyFindFloatInParamList except that *resultCount is the maximum number of floats available at result, and is set to the number actually copied into result.
PtDspyError DspyFindIntInParamList(const char *string, int *result, int paramCount, const UserParameter *parameters)
Get an integer value from the parameter list. Used similarly to DspyFindFloatInParamList().
PtDspyError DspyFindIntsInParamList(const char *string, int *resultCount, int *result, int paramCount, const UserParameter *parameters)
Get an integer value from the parameter list. Used similarly to DspyFindFloatsInParamList().
PtDspyError DspyReorderFormatting(int formatCount, PtDspyDevFormat *format, int outFormatCount, const PtDspyDevFormat *outFormat)
Attempt to reorder format to look like outFormat. We can't save users from themselves, but if we expect to get "abgr", we can use this to try to order the incoming parameters to look more like "abgr" than "rgba" or whatever other random format our caller may request.
Obviously users can provide any set of parameters they want. The renderer will also provide a standard set of parameters:
Name | Type | Description |
---|---|---|
NP | matrix | world to screen space |
Nl | matrix | world to camera space |
near | float | near clipping plane (useful for scaled Z buffer formats) |
far | float | far clipping plane |
origin | int[2] | with crop windows provides the origin of this image within the larger image, in pixels. |
OriginalSize | int[2] | with crop windows provides the size of the larger image into which this image fits. |
PixelAspectRatio | float | pixel aspect ratio |
Software | string | renderer version |
HostComputer | string | host name |
Pixar Animation Studios
|