top of page

// 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;
    }

 

bottom of page