/*****************************************************************************
* Routines to compute various textures color values. Wood, Marble currently. *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Bassarab Dmitri & Plavnik Michael       Ver 0.2, Apr. 1995    *
*****************************************************************************/

#include "program.h"

#define PIXEL_SIZE  1024
#define SIN_12      0.208
#define COS_12      0.978

static void InitNoise(void);
static double Noise(double x, double y, double z);
static double Turbulence(double x, double y, double z);

static double NoiseLattice[MAX_NOISE][MAX_NOISE][MAX_NOISE];

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Gets image pixel by two real coordinates u and v from the Image data.    M
*   Access function.                                                         M
*                                                                            *
* PARAMETERS:                                                                M
*   i:       IN, pointer to the Image data structure.                        M
*   v:       IN, real coordinate of the image pixel.                         M
*   u:       IN, real coordinate of the image pixel.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   PixelStruct *:  value of the image pixel at (u,v) point.                 M
*                                                                            *
* KEYWORDS:                                                                  M
*   ImageGetPixel, image, texture                                            M
*****************************************************************************/
PixelStruct *ImageGetPixel(ImageStruct *i, RealType v, RealType u)
{
    int y = ((int) (v * i -> ySize)) % (i -> ySize + 1),
	x = ((int) (u * i -> xSize)) % (i -> xSize + 1);

    return &i -> data[y * (i -> xSize + 1) + x];
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Initialize "NoiseLattice" module variable with noise values.             *
*   Should be called before "Noise" function is actualy called.              *
*                                                                            *
* PARAMETERS:                                                                *
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void InitNoise(void)
{
    int x, y, z, xx, yy, zz;

    for (x = 0; x < MAX_NOISE; x++)
        for (y = 0; y < MAX_NOISE; y++)
            for (z = 0; z < MAX_NOISE; z++) {
                NoiseLattice[x][y][z] = IritRandom(0, 1);
                xx = (x + 1 == MAX_NOISE) ? 0 : x;
                yy = (y + 1 == MAX_NOISE) ? 0 : y;
                zz = (z + 1 == MAX_NOISE) ? 0 : z;
                NoiseLattice[x][y][z] = NoiseLattice[xx][yy][zz];
            }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Determines actual noise value for the (x,y,z) space point.               *
*   Assumes that InitNoise function is called before to initialize           *
*   NoiseLattice module-variable. Aux. function for Turbulence.              *
*                                                                            *
* PARAMETERS:                                                                *
*   x:       IN, x coordinate of the point.                                  *
*   y:       IN, y coordinate of the point.                                  *
*   z:       IN, z coordinate of the point.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   double:  noise value computed.                                           *
*****************************************************************************/
static double Noise(double x, double y, double z)
{
    int ix, iy, iz;
    double ox, oy, oz, n00, n01, n10, n11;

    x += SQR(PIXEL_SIZE);
    y += SQR(PIXEL_SIZE);
    z += SQR(PIXEL_SIZE);

    ix = ((int) x) % (MAX_NOISE - 1);
    iy = ((int) y) % (MAX_NOISE - 1);
    iz = ((int) z) % (MAX_NOISE - 1);
    ox = x - (int) x;
    oy = y - (int) y;
    oz = z - (int) z;
    n00 = NoiseLattice[ix][iy][iz];
    n00 = n00 + ox * (NoiseLattice[ix + 1][iy][iz] - n00);
    n01 = NoiseLattice[ix][iy][iz + 1];
    n01 = n01 + ox * (NoiseLattice[ix + 1][iy][iz + 1] - n01);
    n10 = NoiseLattice[ix][iy + 1][iz];
    n10 = n10 + ox * (NoiseLattice[ix + 1][iy + 1][iz] - n10);
    n11 = NoiseLattice[ix][iy + 1][iz + 1];
    n11 = n11 + ox * (NoiseLattice[ix + 1][iy + 1][iz + 1] - n11);
    n00 = n00 + oy * (n10 - n00);
    n01 = n01 + oy * (n11 - n01);
    return n00 + oz * (n01 - n00);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Aux. function for MarbleTexture. Computes turbulence kind of noise       *
*   for the specific point in space.                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   x:       IN, x coordinate of the point.                                  *
*   y:       IN, y coordinate of the point.                                  *
*   z:       IN, z coordinate of the point.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   double:  noise value computed.                                           *
*****************************************************************************/
static double Turbulence(double x, double y, double z)
{
    static double t, Scale;

    for (t = 0, Scale = 1; Scale < PIXEL_SIZE; Scale += Scale) {
        t += fabs(Noise(x, y, z)) / Scale;
	x += x;
	y += y;
	z += z;
    }
    return t;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "marble" texture.                                                        M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   MarbleTexture, texture, image warping                                    M
*****************************************************************************/
void MarbleTexture(PointType Point,
                   NormalType Normal,
                   ColorType Color,
                   TextureStruct *Text)
{
    RealType c;
    PointType Pt;
    static int
	First = TRUE;

    if (First) {
        InitNoise();
        First = FALSE;
    }
    PT_COPY(Pt, Point);
    PT_SCALE(Pt, MAX_NOISE);
    c = (sin(Pt[Z] + Turbulence(Pt[X], Pt[Y], Pt[Z]) * 10.0) + 1.0) * 0.5;

    PT_SCALE(Color, c);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "wood" texture.                                                          M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   WoodTexture                                                              M
*****************************************************************************/
void Wood1Texture(PointType Point,
		  NormalType Normal,
		  ColorType Color,
		  TextureStruct *Text)
{
    RealType r;

    Point[Y] *= 1.1;
    r = Point[X] * COS_12 - Point[Z] * SIN_12;
    Point[Z] = Point[X] * SIN_12 + Point[Z] * COS_12;
    Point[X] = r;
  
    r = 50 * (sqrt(SQR(Point[X]) + SQR(Point[Y]))
	      + 0.005 * sin(15 * atan2(Point[X], Point[Y]) + 4 * Point[Z]));

    if (REAL_TO_INT(r) % 3)
        PT_COPY(Color, Colors[14]);                               /* Yellow. */
    else
        PT_COPY(Color, Colors[6]);                                 /* Brown. */
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "wood" texture.                                                          M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   WoodTexture                                                              M
*****************************************************************************/
void Wood2Texture(PointType Point,
		  NormalType Normal,
		  ColorType Color,
		  TextureStruct *Text)
{
    RealType c;
    PointType Pt;
    static int
	First = TRUE;

    if (First) {
        InitNoise();
        First = FALSE;
    }

    PT_COPY(Pt, Point);

    c = sin(Pt[X] * 23 + Pt[Y] * 13 + Pt[Z] * 7) +
        5 * Turbulence(Pt[X], Pt[Y], Pt[Z]);
    c = 2 * fabs(c - 0.5 - ((int) c));

    PT_SCALE(Color, c);
}



/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "wood" texture.                                                          M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   WoodTexture                                                              M
*****************************************************************************/
void WoodTexture(PointType Point,
		 NormalType Normal,
		 ColorType Color,
		 TextureStruct *Text)
{
    RealType c;
    PointType Pt;
    static int
	First = TRUE;

    if (First) {
        InitNoise();
        First = FALSE;
    }

    PT_COPY(Pt, Point);

    c = fabs(Pt[X] * 11 + Pt[Y] * 13 + Pt[Z] * 7) +
        10 * Turbulence(Pt[X], Pt[Y], Pt[Z]);
    c = 2 * fabs(c - 0.5 - floor(c));

    PT_SCALE(Color, c);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "contour" texture.                                                       M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   ContourTexture, texture, image warping                                   M
*****************************************************************************/
void ContourTexture(PointType Point,
		    NormalType Normal,
		    ColorType Color,
		    TextureStruct *Text)
{
    int i;
    PointType Pt;

    for (i = 0; i < 3; i++) {
	Pt[i] = Point[i] - ((int) Point[i]);
	if (Pt[i] < 0.0)
	    Pt[i] += 1.0;
    }

    if ((Pt[0] > 0 && Pt[0] < Text -> Width) ||
	(Pt[1] > 0 && Pt[1] < Text -> Width) ||
	(Pt[2] > 0 && Pt[2] < Text -> Width)) {
	Color[0] = Text -> Color.r;
	Color[1] = Text -> Color.g;
	Color[2] = Text -> Color.b;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluates pertubation on color value at given point in order to get      M
*   "ncontour" texture.                                                      M
*                                                                            *
* PARAMETERS:                                                                M
*   Point:  IN, coordinate of the point in object space.                     M
*   Normal: IN, normal at the point.                                         M
*   Color:  IN OUT, color value at the point.                                M
*   Text:   IN, pointer to the texture structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   ContourTexture, texture, image warping                                   M
*****************************************************************************/
void ContourNormalTexture(PointType Point,
			  NormalType Normal,
			  ColorType Color,
			  TextureStruct *Text)
{
    int i,
	DrawContour = FALSE;

    for (i = 0; i < 3; i++) {  /* Check angle of normal with the X/Y/Z axes. */
	RealType Angle,
	    Scale = Text -> tScale[i];

	if (APX_EQ(Scale, 0.0))
	    continue;
	Scale = 1.0 / Scale;

	for (Angle = 0; Angle < 90; Angle += Scale) {
	    RealType
		CosAngle = cos(Angle * M_PI / 180.0);

	    if (APX_EQ_EPS(CosAngle, fabs(Normal[i]), Text -> Width)) {
		DrawContour = TRUE;
		break;
	    }
	}
    }

    if (DrawContour) {
	Color[0] = Text -> Color.r;
	Color[1] = Text -> Color.g;
	Color[2] = Text -> Color.b;
    }
}
