#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. 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
typedef struct {
    RtFloat radius;
    RtInt    num;
    } SpheresData;
  
// Declare our utility functions...    
RtFloat randBetween(RtFloat min, RtFloat max);
  
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
// stderr strpbrk remainder
  
RtPointer ConvertParameters(RtString paramStr) {
    // Allocate a block of memory to store one instance of our custom data structure.
    SpheresData *dataPtr = (SpheresData*)malloc(sizeof(SpheresData));
    
    // The user has forgotten to specify the number and size of the spheres in the
    // RenderManProcedural's data text field - so we use our default values.    
    if(paramStr == NULL || strlen(paramStr) == 0) {
        dataPtr->radius = DEFAULT_RAD;
        dataPtr->num = DEFAULT_NUM;
        }
    else
        // We assume the input string consists of a float and an integer.
        // For example, "0.2 200".
        // The sscanf function reads the data from the parameter string, converts
        // each item to the appropriate datatype and assigns their values to the 
        // appropriate "field" of our custom data structure.
        sscanf(paramStr, "%f %d", &dataPtr->radius, &dataPtr->num);
    return (RtPointer)dataPtr;
}
  
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer data, RtFloat detail) {
    RtFloat radius = ((SpheresData*)data)->radius;
    RtInt     num = ((SpheresData*)data)->num;
    srand(1);
    
    // Output randomly located spheres
    for(int n = 0; n < num; n++) {
        RtFloat x = randBetween(-5,5);
        RtFloat y = randBetween(-5,5);
        RtFloat z = randBetween(-5,5);
        RiTransformBegin();
            RiTranslate(x,y,z);
            // To assign a color to each sphere un-comment the next two lines
            // and comment line 73
            // RtColor cs[1] = { {randBetween(0,1),randBetween(0,1),randBetween(0,1) } } ;
            // RiSphere(radius, -radius, radius, 360, "constant color Cs", (RtPointer)cs, RI_NULL);
            RiSphere(radius, -radius, radius, 360, 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;
    }