slim 1 extensions cutter {
extensions fundza cutr {
    template multiple PaperCup {
        description {Connect "output->ridges" to the "float displacement" input of GPSurface.<BR>
                     Use "output->mask" and a ColorMix node to control the coloration of a<BR>
                    cylinder that is used to model a paper cup.}
        previewinfo {
            shadingrate 1
            objectsize 1
            objectshape Cylinder
            frame 1
            }
        parameter float context {
            label "Rendering Context"
            description { }
            subtype selector
            range {"Automatic" 0 "Maya Final" 1 "Preview" 2}
            default 0
            }
        parameter float cup_height {
            description "Set this to attenuate the output->ridges - zero at the base, 
                         maximum at the top of the cup."
            label {Cup Height}
            detail varying
            default 1.5
            subtype slider
            range {0 5}
            }
        parameter float freq {
            description "Number of ridges around the cup's circumference."
            label {Number of Ridges}
            detail varying
            default 30
            subtype slider
            range {1 40 2}
            }
        parameter float atten_upper {
            description "The height above the base where ridges will be fully formed."
            label "Ridge Max"
            detail varying
            default 0.2
            subtype slider
            range {0 2}
            }            
        parameter float atten_lower {
            description "The height above the base where ridges are \"flattened\"."
            label "Ridge Min"
            detail varying
            default 0.05
            subtype slider
            range {0 2}
            }
        parameter float atten_ridges {
            label "Attenuate Ridges"
            description "Use this if the cup height has been set accurately."
            subtype switch
            range {0 1}
            provider variable
            default 1
            }
        parameter float ridge_sharpness {
            description "Controls the curvature of the ridges."
            label {Ridge Sharpness}
            detail varying
            default 0
            subtype slider
            range {0 1}
            }
        parameter float ridge_distortion_src {
            description "Connect to a Noise or Turbulance node to vary the ridges."
            label {Ridge Distortion Input}
            detail varying
            default 0
            subtype slider
            range {0 1}
            }
        parameter float ridge_distortion_scale {
            description "A scaling factor for the distortion."
            label {Ridge Distortion Scale}
            detail varying
            default 0
            subtype slider
            range {0 1}
            }
            
        collection void label {
            state closed
            drawmode all
            label {Masks}
            description "Use these to control color mixing and vertical attenuation
                         of the displacement of the ridges of the paper cup."
            parameter float mask_amp {
                description {Controls the height of mask.}
                label {Mask Amplitude}
                detail varying
                default 0.25
                subtype slider
                range {0 1}
                }
            parameter float mask_offset {
                description "Controls the vertical position of the mask."
                label {Mask Vertical Offset}
                detail varying
                default 0.75
                subtype slider
                range {0 1}
                }    
            parameter float invert_mask {
                label "Invert Mask"
                description "Switch the black and white areas of the mask."
                subtype switch
                range {0.0 1.0}
                default 1
                }
            }
  
        parameter float ridges {
                access output
                display hidden
                }
        parameter float mask {
                access output
                display hidden
                }
        RSLFunction {
        void
        cutrPaperCup (
                float context;
                float cup_height;
                float freq;
                float atten_upper;
                float atten_lower;
                float atten_ridges;
                
                float ridge_sharpness;
                float ridge_distortion_src;
                float ridge_distortion_scale;
                
                float mask_amp;
                float mask_offset;
                float invert_mask;
                output float ridges;
                output float mask;
                )
        {
        point p = transform("object", P);
        float x = p[0], y = 0, z = 0;
        float obj_height = cup_height;     // Assume the user has set the true height of
                                          // the maya paper cup.
        float obj_depth = 0.0;            // Paper cup level with the Maya X-Z plane.
        
        // The "it" preview uses a cylinder aligned to the 'z' axis. It also has
        // a negative depth of 0.45 and a height of 0.45. The paper cup in the Maya
        // scene, on the other hand, will have a depth of 0.0 and a height of
        // approximately 1.5. Because our calculations are based on "object"
        // dimensions we must take the "rendering context" into account when
        // determining what should be considered to be the Y axis - either the true 
        // Y axis (Maya) or the Z axis (preview).
        float axis, preview;
        if(context == 0) {
            if(option("user:PreviewRender", preview))
                axis = 2; // "preview"
            else
                axis = 1; // "maya"
            }
        else
            axis = context;
        
        if(axis == 1) { // direct maya render
            y = p[1];
            z = p[2];
            }
        else // "preview" render
            {
            y = p[2];
            z = p[1];
            obj_depth = -0.45;    
            obj_height = 0.45;
            }
        // Some irregularity is added to the angle theta is so the ridges of the 
        // paper cup will appear slightly uneven.
        // Note: atan() returns values in the range -PI to +PI. 
        float theta = atan(x,z) + ridge_distortion_src * ridge_distortion_scale;
        ridges = sin(theta * freq);
        float i, harmonics = ridge_sharpness * 10;
        
        // The loop sharpens the ridges of the cup (thanks Aki).
        for (i = 1.0; i < harmonics; i+=1.0) {
            float h = i * 2.0 + 1.0;
            float wave = sin(theta * freq * h)/pow(h,2.0);
            if (mod(i,2.0) == 0.0) 
                ridges += wave;
            else 
                ridges -= wave;
            }
        // To compensate for any "sharpening" of the ridges a value slightly 
        // greater than 1.0 should be added.
        ridges += 1;
        
        // Apply a ramp so the ridges so the displacement produced by GPSurface 
        // reduces to zero at the base of the paper cup..
        if(atten_ridges)
            ridges *= smoothstep(atten_lower, atten_upper, y);
  
        // Remap the y position of the shading point to the range 0 to 1.0
        y = y/obj_height;
            
        // Remap the y position of the shading point to the range 0 to 1.
        float vert_offset = (axis == 2) ? 1 - mask_offset : mask_offset;
        mask = (ridges + 2) * smoothstep(vert_offset, vert_offset + mask_amp, y);
        mask = smoothstep(0.0, 0.85, mask);
        if(invert_mask == 1)
            mask = 1 - mask;
        
        if(axis == 2)
            mask = 1 - mask;
        }
} } } }