/*
To the POV team:

The code below is the bump_map section of the file "image.c"
from the DOS version of POVray 3.1 sourcecode, downloaded from
www.povray.org 10/1/98. (POVMSD_S.ZIP)

While no changes have been made, comments have been added in four
places identifying several very simple simple errors, and giving the
required changes. 

The purpose of these corrections is to address serious distortions
in the bump_map code that have apparently (somehow) survived
undiscovered through all versions of POVray. There seem to be two
types of distortion; one: a tendency for portions of the bump_maps
to invert depending on the rotation of the object and the angle of
camera/lighting/object,..and two: a twisting of the map as it is applied
to the object, also affected by the above.

Chris Young was kind enough to review a test scene last week and has
confirmed the existence of problems. At that time he was unable to
predict when someone on the POV team would have time to diagnose and
the errors.

In order to put this process on a faster track, I asked my brother,
Justin Odhner to look at the code.  Justin is a C++ programmer and is
also familiar with raytracing in particular.

Justin has found several logical errors in the code which would
account for at least some, and possibly all of the distortion.
However, his work schedule will not permitt him to get involved with
the recompiling part of testing these changes, so we are requesting
help in this area. We assume there are people already set up for this.
We are more than happy to continue work on the fix, analyze the
results of the changes, and track down any further errors if any
distortions still remain after eliminating the obvious ones.

In addition to this text file, there is a jpeg attachment
called "badbump.jpg" which shows the bump_map errors. In the test
scene,(also attached as "badbump.pov"). a 3X3 array of spheres is lit
by a single light centered in line with the camera view which is
facing the array. It is easy to see at what angle the light is hitting
each sphere by looking at the phong highlight. There is a bump_map
centered on each sphere consisting of a white radial gradient on a
black background. ("badbump.tga").

This should result in a "nipple" on the front of each sphere,however,
none are entirely correct in both phong and shadow, and most are way off.
The same result is demonstrated without phong (i.e. diffuse only)
however, the phong highlight helps to illustrate the errors). Note also
that rotating the spheres around the camera view after the texture has
been applied changes the result, even though this is irrelevent to the
camera/light/object relationship, and should therefore have no affect.

We can show that bump_maps are distorted regardless of the shape of
the object or the method of projection. (This makes sense, since the
bump_map code is independant).

////////////

There are two changes to be made concerning the 
bump_map distortion problem. They are marked by $$$$$

Explanation:
The points on the bit map that are used as the source for the color
intensities used in the bump_normal calculations have this relationship:
                          x x
                           x
The points that are used in the calculations have this relationship:
                           xx
                           x
This is causing the tilting/rotating effect.

There is also a possible problem with the xprime unit(?) vector not 
being normalized. This is also marked with $$$$$$

Please review this material and take whatever steps you feel are
appropriate at this time. Alternatively, we encourage you to take
advantage of our offer to follow up on this, by making the changes,
recompiling and letting us test the executable.

We appreciate the POV team for developing the greatest raytracer of all
time (as freeware!), and are happy to do this troubleshooting and testing.
Of course, we wish to receive no credit for our efforts.  Our only wish is
to have the bump_maps working without having to wait for a version 4.0.

Thanks,

Kevin & Justin Odhner
jko@home.com

*/

/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/

void bump_map(VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
{
  DBL xcoor = 0.0, ycoor = 0.0;
  int index, index2, index3;
  COLOUR colour1, colour2, colour3;
  VECTOR p1, p2, p3;
  VECTOR bump_normal;
  VECTOR xprime, yprime, zprime, Temp;
  DBL Length;
  DBL Amount = Tnormal->Amount;
  IMAGE *Image = Tnormal->Vals.Image;

  Make_ColourA(colour1, 0.0, 0.0, 0.0, 0.0, 0.0);
  Make_ColourA(colour2, 0.0, 0.0, 0.0, 0.0, 0.0);
  Make_ColourA(colour3, 0.0, 0.0, 0.0, 0.0, 0.0);

  /* going to have to change this */
  /* need to know if bump point is off of image for all 3 points */

  if (map(EPoint, (TPATTERN *) Tnormal, &xcoor, &ycoor))
  {
    return;
  }
  else
  {
    image_colour_at(Image, xcoor, ycoor, colour1, &index);
  }

  xcoor--;
  ycoor++;

  if (xcoor < 0.0)
  {
    xcoor += (DBL)Image->iwidth;
  }
  else
  {
    if (xcoor >= Image->iwidth)
    {
      xcoor -= (DBL)Image->iwidth;
    }
  }

  if (ycoor < 0.0)
  {
    ycoor += (DBL)Image->iheight;
  }
  else
  {
    if (ycoor >= (DBL)Image->iheight)
    {
      ycoor -= (DBL)Image->iheight;
    }
  }

  image_colour_at(Image, xcoor, ycoor, colour2, &index2);

  xcoor += 2.0;

  if (xcoor < 0.0)
  {
    xcoor += (DBL)Image->iwidth;
  }
  else
  {
    if (xcoor >= Image->iwidth)
    {
      xcoor -= (DBL)Image->iwidth;
    }
  }

  image_colour_at(Image, xcoor, ycoor, colour3, &index3);

  if (Image->Colour_Map == NULL || Image->Use_Colour_Flag)
  {
    p1[X] = 0;
    p1[Y] = Amount * (0.229 * colour1[RED] + 0.587 * colour1[GREEN] + 0.114 * colour1[BLUE]);
    p1[Z] = 0;

    p2[X] = 0;/////change to -1  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    p2[Y] = Amount * (0.229 * colour2[RED] + 0.587 * colour2[GREEN] + 0.114 * colour2[BLUE]);
    p2[Z] = 1;

    p3[X] = 1;
    p3[Y] = Amount * (0.229 * colour3[RED] + 0.587 * colour3[GREEN] + 0.114 * colour3[BLUE]);
    p3[Z] = 1;
  }
  else
  {
    p1[X] = 0;
    p1[Y] = Amount * index;
    p1[Z] = 0;

    p2[X] = 0;/////  change to -1  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    p2[Y] = Amount * index2;
    p2[Z] = 1;

    p3[X] = 1;
    p3[Y] = Amount * index3;
    p3[Z] = 1;
  }

  /* we have points 1,2,3 for a triangle now we need the surface normal for it */

  VSub(xprime, p1, p2);
  VSub(yprime, p3, p2);
  VCross(bump_normal, yprime, xprime);
  VNormalize(bump_normal, bump_normal);

  Assign_Vector(yprime, normal);
  Make_Vector(Temp, 0.0, 1.0, 0.0);
  VCross(xprime, yprime, Temp);
  VLength(Length, xprime);

  if (Length < EPSILON)
  {
    if (fabs(normal[Y] - 1.0) < Small_Tolerance)
    {
      Make_Vector(yprime, 0.0, 1.0, 0.0);
      Make_Vector(xprime, 1.0, 0.0, 0.0);
      Length = 1.0;
    }
    else
    {
      Make_Vector(yprime, 0.0, -1.0, 0.0);
      Make_Vector(xprime, 1.0, 0.0, 0.0);
      Length = 1.0;
    }
  }

  VScaleEq(xprime, 1.0 / Length); ////// normalize xprime instead of scale? $$$$$$$$$
  VCross(zprime, xprime, yprime);
  VNormalizeEq(zprime); /////// If you normalize xprime then you can delete this line $$$$$$$$
  VScaleEq(xprime, bump_normal[X]);
  VScaleEq(yprime, bump_normal[Y]);
  VScaleEq(zprime, bump_normal[Z]);
  VAdd(Temp, xprime, yprime);
  VAdd(normal, Temp, zprime);
}
