/*
GenSpheresProc.cpp
A relatively simple example of a RiProcedural. For info see,
https://rmanwiki.pixar.com/display/REN22/Procedural+Primitives
Also refer to,
http://fundza.com/rfm/procedural/starter/index.html
M.A.Kesson
22 March 2020
*/
#include <ri.h>
#include <RixInterfaces.h>
#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_RAD 1
#define DEFAULT_NUM 1
// A RiProcedural must implement these functions.
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
typedef struct {
RtFloat radius;
RtInt num;
RtFloat min_circumference;
RtFloat max_circumference;
RtFloat spread;
} SpheresData;
// Declare our utility functions...This is the equivalent of pythons
// random.uniform() function.
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
//
RtPointer ConvertParameters(RtString paramStr) {
// Allocate a block of memory to store one instance of our custom data structure.
SpheresData *dataPtr = (SpheresData*)calloc(1, sizeof(SpheresData));
sscanf(paramStr, "%f %d %f %f %f", &dataPtr->radius,
&dataPtr->num,
&dataPtr->min_circumference,
&dataPtr->max_circumference,
&dataPtr->spread);
return (RtPointer)dataPtr;
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer data, RtFloat detail) {
RtFloat radius = ((SpheresData*)data)->radius;
RtInt num = ((SpheresData*)data)->num;
RtFloat min_circum = ((SpheresData*)data)->min_circumference;
RtFloat max_circum = ((SpheresData*)data)->max_circumference;
RtFloat spread = ((SpheresData*)data)->spread;
srand(1);
RtFloat value = 0.1;
RiAttribute("displacementbound", "float sphere", &value, RI_NULL);
// Output randomly located spheres
for(int n = 0; n < num; n++) {
RtFloat x = randBetween(-spread,spread);
RtFloat y = randBetween(-spread,spread);
RtFloat z = randBetween(-spread,spread);
RtFloat circum = randBetween(min_circum, max_circum);
// Unless we put each sphere inside its own group the translations
// compound on each other.
RiTransformBegin();
RiTranslate(x,y,z);
RtColor tint[1] = { {randBetween(0.8,1),randBetween(0.8,1),randBetween(0.8,1) } } ;
RtFloat gain[1] = { randBetween(0.2, 1.0) };
RtFloat disp[1] = { randBetween(0.0,0.2) };
RiSphere(radius, -radius, radius, 360,
"constant color Tint", (RtPointer)tint,
"constant float Gain", (RtPointer)gain,
"constant float Disp", (RtPointer)disp, RI_NULL);
//RiSphere(radius, -radius, radius, circum, RI_NULL);
RiTransformEnd();
}
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}