// PlaceArchivesProc.cpp
#include <ri.h>
//#include <RixInterfaces.h>
//#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include "getFiles.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 );
}
// A custom data structure for defining an arbitrary number of spheres
// positioned at locations defined by the "coords" array.
typedef struct {
std::vector <std::string> archivePaths; // a list of paths of the archives
RtFloat scale;
RtFloat *coords; // effectively an array of x,y,z coordinates
RtInt num_coords;
} ArchivesData;
// Declare our utility function
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
//
RtPointer ConvertParameters(RtString paramStr) {
long len = strlen(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);
// Allocate a block of memory to store one instance of ArchivesData.
ArchivesData *dataPtr = (ArchivesData*)calloc(1, sizeof(ArchivesData));
// Irrespective of how many values are specified by the paramStr we
// know the first 3 values will specify the:
// 1 full path to the directory containing rib archives,
// 2 scaling factor to be applied to the archives, and
// 3 number of coordinates that define the locations of
// the rib archives that will be selected randomly.
char temp[512];
sscanf(copyStr, "%s %f %d", temp, &dataPtr->scale, &dataPtr->num_coords);
//printf("ribs path \"%s\"\n", temp);
std::string ribsDirPath(temp); // convert to a C++ style string
dataPtr->archivePaths = getFiles(ribsDirPath);
// Allocate memory to store an array of coordinates
RtInt num_floats = dataPtr->num_coords;
dataPtr->coords = (RtFloat*)calloc(num_floats, sizeof(RtFloat));
char *strPtr = strtok(copyStr, " ");
strPtr = strtok(NULL, " "); // eat the path to the ribs directory
strPtr = strtok(NULL, " "); // eat the scale value
strPtr = strtok(NULL, " "); // eat the num coordinates value
long count = 0;
while(strPtr) {
// Convert each string to a double precision floating point number
dataPtr->coords[count] = strtod(strPtr, NULL);
count++;
strPtr = strtok(NULL, " "); // grab the next part of copyStr.
}
// Don't forget to free the memory that was allocated for the copied text.
free(copyStr);
return (RtPointer)dataPtr;
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer dataPtr, RtFloat detail) {
RtFloat scale = ((ArchivesData*)dataPtr)->scale;
RtInt num_coords = ((ArchivesData*)dataPtr)->num_coords;
RtFloat *coords = ((ArchivesData*)dataPtr)->coords;
std::vector <std::string> paths = ((ArchivesData*)dataPtr)->archivePaths;
if(paths.size() < 1) {
//printf("Error: no ribs");
return;
}
for(int n = 0; n < num_coords; n = n + 3) {
RtFloat x = coords[n];
RtFloat y = coords[n + 1];
RtFloat z = coords[n + 2];
RiTransformBegin();
RiTranslate(x, y, z);
RiScale(scale, scale, scale);
// Use the nifty function from C++ to randomly select a rib archive
std::random_shuffle( paths.begin(), paths.end() );
//printf("%s\n", paths[0].c_str());
RiReadArchiveV(paths[0].c_str(), NULL, 0, NULL, NULL );
RiTransformEnd();
}
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
free(((ArchivesData*)data)->coords);
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}