// PlaceQuadricsProc.cpp
// Receives the vertex coordinates for the placement of quadrics
// and the rotations that must be applied in order to align the
// quadrics Y-axis to the vertex normal.
// Malcolm Kesson
// May 14 2020
#include <ri.h>
#include <RixInterfaces.h>
#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C"
{
PRMANEXPORT RtPointer ConvertParameters ( RtString paramStr );
PRMANEXPORT RtVoid Subdivide ( RtPointer data, RtFloat detail );
PRMANEXPORT RtVoid Free ( RtPointer data );
}
typedef struct {
RtFloat *coords; // an array of x,y,z coordinates
RtFloat *rotations; // the x,y,z rotations that will align a quadric to the vertex normal
RtInt num_coords;
} ParamData;
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);
char *copyStr = (char*)calloc(len + 1, sizeof(char));
memcpy(copyStr, paramStr, len + 1);
// Allocate a block of memory to store one instance of ParamData.
ParamData *dataPtr = (ParamData*)calloc(1, sizeof(ParamData));
// Irrespective of how many values are specified by the paramStr we
// know the first one is the number of coordinates that define the
// 3D locations of the vertices of the base mesh.
sscanf(copyStr, "%d", &dataPtr->num_coords);
// Allocate memory to store an array of vertex coordinates
RtInt num_coords = dataPtr->num_coords;
dataPtr->coords = (RtFloat*)calloc(num_coords, sizeof(RtFloat));
// Allocate memory to store an array of rotations
dataPtr->rotations = (RtFloat*)calloc(num_coords, sizeof(RtFloat));
char *strPtr = strtok(copyStr, " ");
strPtr = strtok(NULL, " "); // eat the num coordinates value
long count = 0;
while(strPtr && count < num_coords) {
dataPtr->coords[count] = strtod(strPtr, NULL);
count++;
strPtr = strtok(NULL, " "); // grab the next part of copyStr.
}
// Finally, read the rotations.
count = 0;
while(strPtr && count < num_coords) {
dataPtr->rotations[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 data, RtFloat detail) {
RtInt num_coords = ((ParamData*)data)->num_coords;
RtFloat *coords = ((ParamData*)data)->coords;
RtFloat *rot = ((ParamData*)data)->rotations;
srand(3);
RtFloat value = 0.1;
RiAttribute("displacementbound", "float sphere", &value, RI_NULL);
for(int n = 0; n < num_coords; n = n + 3) {
RtFloat x = coords[n];
RtFloat y = coords[n + 1];
RtFloat z = coords[n + 2];
RtFloat majrad = randBetween(0.03, 0.12); // Torus
RtFloat minrad = randBetween(0.008, 0.01); // Torus
RtFloat rad = randBetween(0.02, 0.08); // Sphere
RiTransformBegin();
RiTranslate(x,y,z);
RiRotate(rot[n+2], 0,0,1);
RiRotate(rot[n+1], 0,1,0);
RiRotate(rot[n], 1,0,0);
RiTransformBegin();
RiTorus(majrad, minrad, 0, 360, 360, RI_NULL);
//RiTranslate(0,rad,0);
//RiSphere(rad, -rad, rad, 360, RI_NULL);
RiTransformEnd();
RiTransformEnd();
}
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
free(((ParamData*)data)->coords);
free(((ParamData*)data)->rotations);
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}