/*
 * Copyright 1993 by Cub'x Systemes
 * 
 * All Rights Reserved
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for the  purpose of making new intuitiv'3d modules.
 * This copyright notice must appears in all copies that you distribute.
 * The name of Cub'x Systeme should not be used in advertising or publicity
 * without specific, written prior permission. 
 * CUB'X SYSTEMES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * CUB'X SYSTEMES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*****************************************************************************
 *
 *  CustomObject module
 *  -------------------
 *
 * File: TorusWave.m
 *
 * Contents: A TorusWave object from the book "The RenderMan companion" Steve
 *           Upstill Addison Wesley
 *
 *****************************************************************************/

#import "TorusWave.h"
#import "TorusWaveInsp.h"

#define TORUS_WAVE_VERSION_NUMBER 1

@implementation TorusWave : CX3DObject
{
  unsigned int waveCount; /* Number of waves that you want to display */
  float    thetamax;      /* The torus thetamax                      */
  float    radius;        /* The radius of the torus wave            */
}

/*******************************************************************************
 *                                                                             *
 *                                Class methods                                *
 *                                                                             *
 *******************************************************************************/

/*
 *  This is a good idea to set a version number to your class
 *  This is useful when you have to keep a backward compatibility
 *  when reading a stream
 */
+ initialize
{
  [self setVersion:TORUS_WAVE_VERSION_NUMBER];
  return self;
}

/*
 *  ExportedVariables allows you to speed-up the implementation of the read: and
 *  write: methods. Please read the documentation.
 */
+ (ExportedVariable*) exportedVariableFor:(long)version
{
  switch (version) {
  default:
  case 1: {
    static ExportedVariable ev[] = {
      {"waveCount",EV_LONG, 0},
      {"thetamax", EV_FLOAT,0},
      {"radius",   EV_FLOAT,0},
      {"",0,0}
	};
	return ev;
  }
  }
}

/*******************************************************************************
 *                                                                             *
 *                               Instance methods                              *
 *                                                                             *
 *******************************************************************************/
/*
 *  The init method should set some default values to your instance variables.
 */
- init
{
  [super init];
  
  /*
   *  Here, intialize your instance variables
   */
  waveCount = 3;
  thetamax  = 360.0;
  radius    = .25;

  /*
   *  Here sets your icon.
   *  You can use any tiff picture placed into the bundle
   */
  [self setIconByName: "TorusWave"];
  [self setTitle:"Torus Wave"];
  return self;
}


/*
 *  The copy method should be implemented. 
 *  Duplicate the receiver.
 */
- copy
{
  TorusWave *theCopy = [super copy];
  theCopy->waveCount = waveCount;
  theCopy->thetamax  = thetamax;
  theCopy->radius    = radius;
  return theCopy;
}

/*
 *  This method renders the object.
 *  You can use Renderman function inside
 *  this method. You should begin this method
 *  by if( [super render] ) { ... 
 */
- render
{
  if( [super render] )
    {
      float innerrad,outerrad;
      int   wave;

      /*
       * Divide the net radius among the waves and the hemisphere 
       */
      innerrad = radius / (4.0 * waveCount + 2.0 );
    
      /*
       *  Create the cap for the center of the wave
       */
      RiSphere( innerrad, -innerrad, innerrad,thetamax, RI_NULL );

      for( outerrad = 0.0, wave = 1 ; wave <= waveCount ; wave++ ) {
	/*
	 *  Each iteration creates a downward-opening half-torus
	 *  and a larger upward-opening half-torus
	 */
	outerrad += (innerrad * 2);
	RiTorus( outerrad,innerrad,0.0,180.0,thetamax,RI_NULL);
	outerrad += (innerrad * 2);
	RiTorus( outerrad,innerrad,180.0,360.0,thetamax,RI_NULL);
      }
    }
  return self;
}


/*
 *  This method should return the bounding box of your instance.
 *  You have to implement this method.
 */
- getBoundingBox:(RtBound) aBox
{
  float innerrad = radius / (4.0 * waveCount + 2.0);

  BB_MINX(aBox) = -radius;
  BB_MAXX(aBox) =  radius;
  BB_MINY(aBox) = -radius;
  BB_MAXY(aBox) =  radius;
  BB_MINZ(aBox) = -innerrad;
  BB_MAXZ(aBox) =  innerrad;
  return self;
}

/*
 *  This methods are used by the TorusWave inspector. Please see
 *  TorusWaveInsp.m
 */
- setWaveCount:(unsigned int) aValue
{
  waveCount = aValue;
  return self;
}

- (unsigned int) waveCount
{
  return waveCount;
}

- setThetamax: (float) aFloat
{
  thetamax = aFloat;
  return self;
}

- (float) thetamax
{
  return thetamax;
}

- setRadius: (float) aFloat
{
  radius = aFloat;
  return self;
}

- (float) radius
{
  return radius;
}

/*
 *  This method returns the class of the inspector you want to use
 *  for your new object. You can return nil.
 */
- attributeInspClass
{
  return [TorusWaveInsp class];
}


@end


