/*
 * 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: DistortedCube.m
 *
 * Contents: A distorted cube class
 *     
 *
 *****************************************************************************/

#import "DistortedCube.h"
#import "DistortedCubeInsp.h"


#define DISTORTEDCUBE_VERSION_NUMBER  003

/*
 *  If you want to display distorted cube using patchs please
 *  set DC_DRAWWITHPATCHS to 1 and DC_DRAWWITHPOLYGONS to 0
 *  Otherwise, please set DC_DRAWWITHPATCHS to 0 and DC_DRAWWITHPOLYGONS to 1
 */
#define DC_DRAWWITHPATCHS		1
#define DC_DRAWWITHPOLYGONS		0
#define	max(a, b)				(a > b ? a : b)



@implementation DistortedCube



/*******************************************************************************
 *                                                                             *
 *                                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:DISTORTEDCUBE_VERSION_NUMBER];
  return self;
}


/*
 *  ExportedVariables allow you to speedup the implementation of the read: and
 *  write: methods. Please read the documentation.
 */
+ (ExportedVariable *)exportedVariable
{
  static ExportedVariable ev[] = {
    {"startWidth", EV_FLOAT, 0},
    {"startHeight", EV_FLOAT, 0},
    {"destWidth", EV_FLOAT, 0},
    {"destHeight", EV_FLOAT, 0},
    {"offsetForX", EV_FLOAT, 0},
    {"offsetForY", EV_FLOAT, 0},
    {"offsetForZ", EV_FLOAT, 0},
    {"", 0, 0}};
  return ev;
}

/*******************************************************************************
 *                                                                             *
 *                               Instance methods                              *
 *                                                                             *
 *******************************************************************************/
/*
 *  The init method should set some default values to your instance variables.
 */
- init
{
  [super init];
  startWidth = 0.3;
  startHeight = 0.3;
  destWidth = 0.15;
  destHeight = 0.15;
  offsetForX = 0.0;
  offsetForY = 0.0;
  offsetForZ = 0.3;
  [self setIconByName:"DistortedCube"];
  [self setTitle:"Distorted Cube"];
  return self;
}



/*
 *  The copy method should be implemented. 
 *  Duplicate the receiver.
 */
- copy
{
  DistortedCube *copy = [super copy];
  copy->startWidth = startWidth;
  copy->startHeight = startHeight;
  copy->destWidth = destWidth;
  copy->destHeight = destHeight;
  copy->offsetForX = offsetForX;
  copy->offsetForY = offsetForY;
  copy->offsetForZ = offsetForZ;
  return copy;
}


/*
 *  This method renders the object.
 *  You can use Renderman functions inside
 *  this method. You should begin this method
 *  by if( [super render] ) { ... 
 */
- render
{
  if ([super render])
    {
      RtPoint Cube[4];
      float ox = offsetForX / 2.0;
      float oy = offsetForY / 2.0;
      float oz = offsetForZ / 2.0;
      float sw1 = (startWidth / 2.0);
      float sh1 = (startHeight / 2.0);
      float dw1 = (destWidth / 2.0);
      float dh1 = (destHeight / 2.0);
      float sw2;
      float sh2;
      float dw2;
      float dh2;


      sw2 = sw1 - ox;
      sw1 = sw1 + ox;
      dw2 = dw1 + ox;
      dw1 = dw1 - ox;
      sh2 = sh1 - oy;
      sh1 = sh1 + oy;
      dh2 = dh1 + oy;
      dh1 = dh1 - oy;


#if DC_DRAWWITHPOLYGONS

      /*
       *  XY -Z
       */

      CX(Cube[0]) = -sw1; CY(Cube[0]) = -sh1; CZ(Cube[0]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  sw2; CY(Cube[2]) =  sh2; CZ(Cube[2]) = -oz;
      CX(Cube[3]) = -sw1; CY(Cube[3]) =  sh2; CZ(Cube[3]) = -oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);

			
      /*
       *  XY +Z
       */

      CX(Cube[0]) = -dw1; CY(Cube[0]) = -dh1; CZ(Cube[0]) =  oz;
      CX(Cube[1]) =  dw2; CY(Cube[1]) = -dh1; CZ(Cube[1]) =  oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) =  dh2; CZ(Cube[3]) =  oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);

		
      /*
       *  XZ -Y
       */

      CX(Cube[0]) = -sw1; CY(Cube[0]) = -sh1; CZ(Cube[0]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) = -dh1; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);

		
      /*
       *  XZ +Y
       */

      CX(Cube[0]) = -sw1; CY(Cube[0]) =  sh2; CZ(Cube[0]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[1]) =  sh2; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) =  dh2; CZ(Cube[3]) =  oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);

		
      /*
       *  ZY -X
       */

      CX(Cube[0]) = -sw1; CY(Cube[0]) = -sh1; CZ(Cube[0]) = -oz;
      CX(Cube[1]) = -sw1; CY(Cube[1]) =  sh2; CZ(Cube[1]) = -oz;
      CX(Cube[2]) = -dw1; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);

		
      /*
       *  ZY +X
       */

      CX(Cube[0]) =  sw2; CY(Cube[0]) = -sh1; CZ(Cube[0]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[1]) =  sh2; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) =  dw2; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPolygon( (RtInt) 4, RI_P, (RtPointer) Cube, RI_NULL);


#else


      /*
       *  XY -Z
       */

      CX(Cube[3]) = -sw1; CY(Cube[0]) =  sh2; CZ(Cube[0]) = -oz;
      CX(Cube[2]) = -sw1; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[2]) =  sh2; CZ(Cube[2]) = -oz;
      CX(Cube[0]) =  sw2; CY(Cube[3]) = -sh1; CZ(Cube[3]) = -oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


      /*
       *  XY +Z
       */

      CX(Cube[0]) = -dw1; CY(Cube[0]) =  dh2; CZ(Cube[0]) = oz;
      CX(Cube[1]) = -dw1; CY(Cube[1]) = -dh1; CZ(Cube[1]) = oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) = oz;
      CX(Cube[3]) =  dw2; CY(Cube[3]) = -dh1; CZ(Cube[3]) = oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


      /*
       *  ZY -X
       */

      CX(Cube[0]) = -sw1; CY(Cube[0]) =  sh2; CZ(Cube[0]) = -oz;
      CX(Cube[1]) = -sw1; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[2]) = -dw1; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


      /*
       *  ZY +X
       */

      CX(Cube[0]) =  sw2; CY(Cube[0]) =  sh2; CZ(Cube[0]) = -oz;
      CX(Cube[1]) =  sw2; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) =  dw2; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


      /*
       *  ZX -Y
       */

      CX(Cube[0]) =  sw2; CY(Cube[0]) = -sh1; CZ(Cube[0]) = -oz;
      CX(Cube[1]) = -sw1; CY(Cube[1]) = -sh1; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) = -dh1; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) = -dh1; CZ(Cube[3]) =  oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


      /*
       *  ZX +Y
       */

      CX(Cube[0]) =  sw2; CY(Cube[0]) =  sh2; CZ(Cube[0]) = -oz;
      CX(Cube[1]) = -sw1; CY(Cube[1]) =  sh2; CZ(Cube[1]) = -oz;
      CX(Cube[2]) =  dw2; CY(Cube[2]) =  dh2; CZ(Cube[2]) =  oz;
      CX(Cube[3]) = -dw1; CY(Cube[3]) =  dh2; CZ(Cube[3]) =  oz;
      RiPatch("bilinear",RI_P,(RtPointer) Cube,RI_NULL);


#endif
    }
  return self;
}


/*
 *  This method should returnûÈ the bounding box of your instance.
 *  You have to implement this method.
 */
- getBoundingBox:(RtBound)aBox
{
  BB_MINX(aBox) = - (max((startWidth + offsetForX), (destWidth - offsetForX)) / 2.0);
  BB_MAXX(aBox) =   (max((startWidth - offsetForX), (destWidth + offsetForX)) / 2.0);
  BB_MINY(aBox) = - (max((startHeight + offsetForY), (destHeight - offsetForY)) / 2.0);
  BB_MAXY(aBox) =   (max((startHeight - offsetForY), (destHeight + offsetForY)) / 2.0);
  BB_MINZ(aBox) = - offsetForZ / 2.0;
  BB_MAXZ(aBox) =   offsetForZ / 2.0;
  return self;
}

/*
 *  This methods are used by the DistortedCube inspector. Please see
 *  DistortedCubeInsp.m
 */
- setStartWidth:(float)aFloat
{
  startWidth = aFloat;
  return self;
}

- (float)startWidth
{
  return startWidth;
}

- setStartHeight:(float)aFloat
{
  startHeight = aFloat;
  return self;
}


- (float)startHeight
{
  return startHeight;
}

- setDestWidth:(float)aFloat
{
  destWidth = aFloat;
  return self;
}

- (float)destWidth
{
  return destWidth;
}

- setDestHeight:(float)aFloat
{
  destHeight = aFloat;
  return self;
}


- (float)destHeight
{
  return destHeight;
}


- setOffsetForX:(float)aFloat
{
  offsetForX = aFloat;
  return self;
}


- (float)offsetForX
{
  return offsetForX;
}

- setOffsetForY:(float)aFloat
{
  offsetForY = aFloat;
  return self;
}

- (float)offsetForY
{
  return offsetForY;
}

- setOffsetForZ:(float)aFloat
{
  offsetForZ = aFloat;
  return self;
}


- (float)offsetForZ
{
  return offsetForZ;
}


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



@end















