// PlaceBlobbyProc.cpp
#include <ri.h>
#include <RixInterfaces.h>
#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// A RiProcedural must implement these functions. This is a fixed requirement.
extern "C"
{
PRMANEXPORT RtPointer ConvertParameters ( RtString paramStr );
PRMANEXPORT RtVoid Subdivide ( RtPointer data, RtFloat detail );
PRMANEXPORT RtVoid Free ( RtPointer data );
}
typedef struct {
RtFloat *coords;
RtInt num_blobs;
RtInt total_num_codes;
RtInt *codes;
RtInt num_matrix_values; // 16 x num_blobs
RtFloat *matrix;
} BlobbyData;
// Declare our utility functions...
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtPointer ConvertParameters(RtString paramStr) {
// The strtok() function cannot be used on the paramStr directly because
// it modifies the string.
long len = strlen(paramStr);
// Allocate a block of memory to store one instance of BlobbyData.
BlobbyData *blobbyDataPtr = (BlobbyData*)malloc(sizeof(BlobbyData));
// An error has occurred...
if(len == 0) {
blobbyDataPtr->num_blobs = 0;
return (RtPointer)blobbyDataPtr;
}
// We could directly create a copy of the input paramStr as an array and
// use strcpy() to copy the string. For example,
//char copyStr[len];
//strcpy(copyStr, paramStr);
// However, because the paramStr can be very large we allocate memory
// from the main memory pool (the "heap") and then perform a block
// copy of the contents of paramStr.
char *copyStr = (char*)calloc(len + 1, sizeof(char));
memcpy(copyStr, paramStr, len + 1);
// Irrespective of how many values are specified by the paramStr we
// know the first two values provide the scale of the blobs
// and the number of coordinates that define their 3D locations.
double scale;
RtInt num_coords;
sscanf(copyStr, "%lf %d", &scale, &num_coords);
blobbyDataPtr->num_blobs = num_coords/3;
RtInt num_ellipsoid_codes = blobbyDataPtr->num_blobs * 2;
RtInt num_blending_codes = 2 + blobbyDataPtr->num_blobs;
blobbyDataPtr->total_num_codes = num_ellipsoid_codes + num_blending_codes;
// Allocate a block of memory for the array of coordinates.
blobbyDataPtr->coords = (RtFloat*)calloc(num_coords, sizeof(RtFloat));
// Tokenize the input string but ignore the first two values because
// they were read by the ssanf() funtion.
char *strPtr = strtok(copyStr, " ");
strtok(NULL, " "); // eat the scale value
strtok(NULL, " "); // eat the num_coords value
RtInt count = 0;
while(strPtr) {
blobbyDataPtr->coords[count++] = strtod(strPtr, NULL);
strPtr = strtok(NULL, " ");
}
// Allocate the memory for the array of codes.
blobbyDataPtr->codes = (RtInt*)calloc(blobbyDataPtr->total_num_codes, sizeof(RtInt));
// Begin assigning the codes_______________________________________________
RtInt n = 0, matrix_index_counter = 0;
while(n < num_ellipsoid_codes) {
blobbyDataPtr->codes[n] = 1001;
blobbyDataPtr->codes[n+1] = matrix_index_counter;
matrix_index_counter += 16;
n += 2;
}
blobbyDataPtr->codes[n++] = 0; // code to additively blend the blobs
blobbyDataPtr->codes[n++] = blobbyDataPtr->num_blobs;
RtInt blob_index = 0;
while(n < blobbyDataPtr->total_num_codes)
blobbyDataPtr->codes[n++] = blob_index++;
// End assigning the codes________________________________________________
// Allocate the memory for an array of matrix elements.
blobbyDataPtr->num_matrix_values = blobbyDataPtr->num_blobs * 16;
blobbyDataPtr->matrix = (RtFloat*)calloc(blobbyDataPtr->num_matrix_values, sizeof(RtFloat));
// Assign the matrix values_______________________________________________
RtInt coord_counter = 0;
for(int n = 0; n < blobbyDataPtr->num_matrix_values; n += 16) {
blobbyDataPtr->matrix[n] = blobbyDataPtr->matrix[n+5] = blobbyDataPtr->matrix[n+10] = scale;
blobbyDataPtr->matrix[n+12] = blobbyDataPtr->coords[coord_counter++];
blobbyDataPtr->matrix[n+13] = blobbyDataPtr->coords[coord_counter++];
blobbyDataPtr->matrix[n+14] = blobbyDataPtr->coords[coord_counter++];
blobbyDataPtr->matrix[n+15] = 1.0;
}
free(copyStr);
return (RtPointer)blobbyDataPtr;
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer data, RtFloat detail) {
if(((BlobbyData*)data)->num_blobs == 0)
return;
RtToken token[1] = { "\0" };
RiBlobby(((BlobbyData*)data)->num_blobs,
((BlobbyData*)data)->total_num_codes,
((BlobbyData*)data)->codes,
((BlobbyData*)data)->num_matrix_values,
((BlobbyData*)data)->matrix, 1, token, RI_NULL );
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
if( ((BlobbyData*)data)->num_blobs > 0) {
free(((BlobbyData*)data)->codes);
free(((BlobbyData*)data)->matrix);
free(((BlobbyData*)data)->coords);
}
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}