/* $Id: //depot/branches/rmanprod/docs-13.0/renderman_pro_server/prman_technical_rendering/examples/balltest.c#1 $  (Pixar - RenderMan Division)  $Date: 2007/02/28 $ */
/*
** Copyright (c) 1998 PIXAR.  All rights reserved.  This program or
** documentation contains proprietary confidential information and trade
** secrets of PIXAR.  Reverse engineering of object code is prohibited.
** Use of copyright notice is precautionary and does not imply
** publication.
**
**                      RESTRICTED RIGHTS NOTICE
**
** Use, duplication, or disclosure by the Government is subject to the
** following restrictions:  For civilian agencies, subparagraphs (a) through
** (d) of the Commercial Computer Software--Restricted Rights clause at
** 52.227-19 of the FAR; and, for units of the Department of Defense, DoD
** Supplement to the FAR, clause 52.227-7013 (c)(1)(ii), Rights in
** Technical Data and Computer Software.
**
** Pixar
** 1001 West Cutting Blvd.
** Richmond, CA  94804
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "runuquads.h"

static void StarTrim(void);

int
main(int argc, char *argv[])
{
    static RtInt   yes = 1;
    static RtFloat one = 1.0;
    static RtFloat fov = 45.0;
    static RtPoint flat_points[4] =
		{ -10.0, 10.0, 4.0, 10.0, 10.0, 3.0,
		  -10.0, -10.0, 5.0, 10.0, -10.0, 4.0 };
    int background = 0;
    int star = 0;
    int ball = 0;
    int envir = 0;
    int hider = 0;
    char *envname;

    /*
     * Looks can be selected on the command like like so:
     *
     * 	% balltest #background #star #ball #envir #hider
     *
     */
    if (argc > 1) background = atoi(argv[1]);
    if (argc > 2) star = atoi(argv[2]);
    if (argc > 3) ball = atoi(argv[3]);
    if (argc > 4) envir = atoi(argv[4]);
    if (argc > 5) hider = atoi(argv[5]);

    /*
     * Select the environment map.
     * These are both in the standard textures in the release.
     */
    if (envir == 0) {
	envname = "desert.env";
    } else {
	envname = "street.env";
    }

#ifdef SIGFPE
    /* Some machines complain too much. */
    signal(SIGFPE, SIG_IGN);
#endif

    RiBegin(RI_NULL);

    /*
     * Demonstrates show to select the new hider Poisson disc sampling.
     */
    if (hider < 1) {
	RiHider("hidden", "jitter", &yes, RI_NULL);
	RiPixelFilter(RiGaussianFilter, 2.0, 2.0);
    } else {
	RiHider("hidden", "pdisc", &yes, RI_NULL);
	RiPixelFilter(RiSincFilter, 4.0, 4.0);
    }

    RiDisplay("ball.tif", "framebuffer", "rgba", RI_NULL);
    RiFormat((RtInt) 320, (RtInt) 320, (RtFloat) 1.0);
    RiClipping(0.001, 1000.0);
    RiProjection(RI_PERSPECTIVE, "fov", &fov, RI_NULL);
    RiTranslate(0.0, 0.0, 3.5);

    RiWorldBegin();

    /*
     * Establish the "worldspace" used by Looks.
     * Using a separate named coordinate system allows it to be
     * transformed separately from the regular "world" space if need be.
     * Transforms inside here affect the alignment of the
     * environment reflection on the ball.
     */
    RiTransformBegin();
        RiCoordinateSystem("worldspace");
    RiTransformEnd();

    /*
     * Set up some lights.
     * We use
     * 	- one regular old ambient light,
     *  - one point light
     *  - one window light
     *  - (optionally) one environment light
     *
     */
    {
	float bright;
	float angle;
	float amb = 0.15;

	RiLightSource("ambientlight", "intensity", &amb, RI_NULL);

	RiDeclare("Brightness", "uniform float");
	RiDeclare("ConeAngle", "uniform float");

	RiTransformBegin();
	RiTranslate(3.0, -4.5, -2.0);
	bright = 0.3;
	RiLightSource("_VFX_MLights|Basic|Point|pointlight",
		"Brightness", &bright,
		RI_NULL);
	RiTransformEnd();

	/*
	 * Window light.
	 */
	RiTransformBegin();
	RiRotate(25.0, 0.0, 1.0, 0.0);
	RiRotate(25.0, 1.0, 0.0, 0.0);
	RiTranslate(0.0, 0.0, -4.0);
	bright = 0.5;
	angle = 0.2;
	RiLightSource("_VFX_MLights|Typestry|Windowspot|windowspot",
		"ConeAngle", &angle,
		"Brightness", &bright,
		RI_NULL);
	RiTransformEnd();

	/*
	 * Environments 2,3 and above are done from a light source here.
	 * Environments 0 and 1 are done in the surface shader below.
	 */
	if (envir == 2) {
	    RiDeclare("Picture","uniform string");
	    bright = 0.3;
	    RiLightSource(
	  	"_VFX_MEnvironments|Starter|Use Your Picture|use_your_picture",
		"Picture", &envname,
		"Brightness", &bright,
		RI_NULL);
	} else if (envir == 3) {
	    bright = 0.3;
	    RiLightSource("_VFX_MEnvironments|Starter|Sunset|sunset",
		"Brightness", &bright,
		RI_NULL);

	} else if (envir > 3) {
	    bright = 0.3;
	    RiLightSource("_VFX_MEnvironments|Starter|Blobby|blobby",
		"Brightness", &bright,
		RI_NULL);
	}
    }

    /*
     * Background is just a flat patch with one of a selection of Looks.
     */
    RiAttributeBegin();

	RiTransformBegin();
        if (background == 0) {
	    RiScale(5.0, 5.0, 5.0);
	    RiSurface("_VFX_MStarter|Background|Sky|sky",
		RI_NULL);
        } else if (background == 1) {
	    RiScale(2.0, 2.0, 2.0);
	    RiSurface("_VFX_MGlimpse|Water|water",
		RI_NULL);
	} else {
	    float height;
	    float waviness;
	    float density;
	    char *shader = "shader"; /* "displacement"; */
            static RtColor bcolor = {0.7, 0.6, 0.8};
	    static RtColor dcolor = {0.6, 0.02, 0.02};

	    /*
	     * Combine a Displacement and a Surface Look together.
	     * Set the displacement bound appropriately.
	     */
	    RiDeclare("Displacement", "uniform float");
	    RiDeclare("BumpHeight", "uniform float");
	    RiDeclare("Waviness", "uniform float");
	    height = 0.2;
	    waviness = 0.35;
	    RiScale(2.0, 2.0, 2.0);
	    RiDisplacement("_VFX_MGlimpse|Wavy|wavy",
			"Displacement", &one,
			"BumpHeight", 	&height,
			"Waviness", 	&waviness,
			RI_NULL);
	    RiAttribute("displacementbound",
			"coordinatesystem", &shader,
			"sphere", 	    &height,
			RI_NULL);
	    RiDeclare("DotColor", "uniform color");
	    RiDeclare("DotDensity", "uniform float");
	    density = 0.6;
	    RiColor(bcolor);
	    RiScale(15.0, 15.0, 15.0);
	    RiSurface("_VFX_MStarter|Pattern|Polkadot|pxs00016",
		"DotColor",   dcolor,
		"DotDensity", &density,
		RI_NULL);
	}
	RiTransformEnd();

	/*
	 * Background patch.
	 */
	RiPatch(RI_BILINEAR, RI_P, flat_points, RI_NULL);

    RiAttributeEnd();

    /*
     * In the foreground we have a sphere, a little trimcurve
     * manipulation allows us to have a star as an "inlay"
     * which uses a different Look than the rest of the ball.
     * In order to use a trimcurve, we need a NURBS surface,
     * so we use the RuNuSphere (from runuquads.c) call to generate
     * a sphere NURBS for us.
     */

    RiAttributeBegin();

	/* Look at the side of the ball with the trim on it. */
	RiRotate(-90.0, 0.0, 0.0, 1.0);
	RiRotate(-90.0, 0.0, 1.0, 0.0);

	/* Set up the trim curve. */
	StarTrim();

	RiDeclare("EnvType", "uniform float");
	RiDeclare("Environment", "uniform float");
	RiDeclare("EnvName", "uniform string");

	/*
	 * First select the Look for the inlayed star.
	 */
	RiTransformBegin();
	{
	    float envt;
	    float env;
	    static RtColor scolor = {1.0, 0.6, 0.0};
	    char *sshader;

	    /*
	     * Enviroments 0 and 1 are done here.
	     * Environments 2,3 and above are done from a light source above.
	     */
	    if (envir > 1) envt = 0.0;
	    else envt = 2.0;

	    if (star == 0) {
		env = 0.7;
		sshader = "_VFX_MStarter|Metal|Smooth|pxs00014";
	    } else {
		env = 1.0;
		sshader = "_VFX_MStarter|Metal|Brushed|pxs00013";
	    }

	    RiColor(scolor);
	    RiScale(0.5, 0.5, 0.5);

	    RiSurface(sshader,
		"EnvType",     &envt,
		"Environment", &env,
		"EnvName",     &envname,
		RI_NULL);
	}
	RiTransformEnd();

	RuNuSphere(1.0, -1.0, 1.0, 360.0);

	/*
	 * Reverse the sense of the trim curve to draw the other
	 * part of the sphere with the same trim curve.
	 */
	{
	    char *outside = "outside";
	    RiAttribute("trimcurve", "sense", &outside, RI_NULL);
	}

	/*
	 * Now select the Look for the rest of the sphere.
	 */
	RiTransformBegin();
	{
	    float smooth = 0.7;
	    float envt = 2.0;
	    float env =  0.15;
	    char *bshader;

	    RiDeclare("Smoothness", "uniform float");
	    RiRotate(90.0, 1.0, 0.0, 0.0);

	    if (ball == 0) {
		RiScale(6.0, 6.0, 6.0);
		bshader = "_VFX_MStarter|Wood|Oak|pxs00011";
	    } else if (ball == 1) {
		RiScale(4.0, 4.0, 4.0);
		bshader = "_VFX_MStarter|Wood|Maple|pxs00012";
	    } else {
		RiScale(2.0, 2.0, 2.0);
		bshader = "_VFX_MStarter|Stone|Green Marble|pxs00019";
	    }

	    RiSurface(bshader,
		"Smoothness", &smooth,
		"EnvType",     &envt,
		"Environment", &env,
		"EnvName",     &envname,
		RI_NULL);
	}
	RiTransformEnd();
	RuNuSphere(1.0, -1.0, 1.0, 360.0);

    RiAttributeEnd();
    RiWorldEnd();
    RiEnd();

    return(0);
}

/*
 * Sets a trimcurve that is five pointed star.
 */
static void
StarTrim(void)
{
    RtInt ncurves[1] = {1};
    RtInt order[1] = {2};
    RtFloat knots[13] = {0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10};
    RtFloat mins[1] = {0};
    RtFloat maxes[1] = {10};
    RtInt   np[1] = {11};
    RtFloat u[11] = {0.5, 0.529389, 0.618882, 0.547553, 0.573473,
		     0.5, 0.426527, 0.452447, 0.381118, 0.470611, 0.5};
    RtFloat v[11] = {0.75, 0.580901, 0.577254, 0.460909, 0.297746,
		     0.4, 0.297746, 0.460909, 0.577254, 0.580901, 0.75};
    RtFloat w[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

    RiTrimCurve(1, ncurves, order, knots, mins, maxes, np, u, v, w);
}
