/* @(#)maps.sl	1.7 (Pixar - RenderMan Division) 12/31/90 */

/*-______________________________________________________________________
** 
** Copyright (c) 1989 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
** 3240 Kerner Blvd.
** San Rafael, CA  94901
** 
** ______________________________________________________________________
*/

/*
 * This file contains functions to perform decal mapping, which is especially
 * useful for putting texture maps onto surfaces consisting of many small
 * polygons.
 *
 * Major function is decalmap, which calls the mapping functions:
 * cylinmap, planemap, sphermap, automap (and bilerp).
 *
 */

/*----------------------------------------------------------------------
 *
 * bilerp does a bilinear interpolation of one number between the
 * four given corners in texture space to the given point in parameter
 * space.
 *
 * uu,vv - point in parameter space
 * x1,x2,x3,x4 - corners in texture space
 *
 *--------------------------------------------------------------------*/

float
bilerp(float uu,vv,x1,x2,x3,x4)
{
    varying float left, right;

    left = x1 + uu * (x2 - x1);
    right = x3+ uu * (x4 - x3);
    return(left + vv * (right - left));
}

/*----------------------------------------------------------------------
 *
 * cylinmap performs a cylindrical projection to create texture coordinates
 *	uu and vv
 * 
 * p - point on surface to be projected
 * uu,vv - new projected coordinates
 * maporigin - the bottom point of the center axis of the cylindrical proj.
 * xaxis, yaxis, zaxis - 3 points defining the coordinate system of
 *        the cylinder.  The central axis is along zaxis-maporigin.
 *	  The point on the equator where (uu,vv)==(0,0) is mapped is at xaxis.
 *--------------------------------------------------------------------*/

float cylinmap(point p;
	float uu,vv;
	point maporigin, xaxis, yaxis, zaxis)
{
    varying vector	V,Vn,
			XX, YY, ZZ;
    varying float	xx, yy;


    V = p - maporigin;
    Vn = normalize(V);

    XX = normalize(xaxis - maporigin);
    YY = normalize(yaxis - maporigin);
    ZZ = normalize(zaxis - maporigin);
    xx = Vn.XX;
    yy = Vn.YY;

    vv = V.ZZ;

    uu = atan(yy, xx) / (2*PI);  /* -.5 -> .5 */
    uu = uu + step(0,-uu); /* remaps to 0 -> 1 */
}



/*---------------------------------------------------------------------
 * planemap performs a planar projection to create texture coordinates
 *	uu and vv
 * 
 * p - point on surface to be projected
 * uu,vv - new projected coordinates
 * maporigin, xaxis, yaxis - The projection is performed as if the texture
 *	  map were placed with (uu,vv)==(0,0) at 'maporigin', uu==0 along
 *        yaxis-maporigin and vv==0 along xaxis-maporigin.  The map is then
 *        projected parallel to itself onto the surface.
 *--------------------------------------------------------------------*/

float planemap(point p;
	float uu,vv;
	point maporigin, xaxis, yaxis)
{
    varying vector	V,
			XX, YY;
    varying float	xx, yy;


    V = p - maporigin;

    XX = normalize(xaxis - maporigin);
    YY = normalize(yaxis - maporigin);
    uu = V.XX;
    vv = V.YY;
}




/*--------------------------------------------------------------------
 *
 * sphermap performs a spherical projection to create texture coordinates
 *	uu and vv
 * 
 * p - point on surface to be projected
 * uu,vv - new projected coordinates
 * maporigin - the center of the spherical projection.
 * xaxis, yaxis, zaxis - 3 points defining the coordinate system of
 *        the sphere.  The north pole is at zaxis.
 *	  The point on the equator where uu==0 is mapped is at xaxis.
 *--------------------------------------------------------------------*/

float sphermap(point p;
	float uu,vv;
	point maporigin, xaxis, yaxis, zaxis)
{
    varying vector	V,
			XX, YY, ZZ;
    varying float	xx, yy, zz;


    V = normalize(p - maporigin);

    XX = normalize(xaxis - maporigin);
    YY = normalize(yaxis - maporigin);
    ZZ = normalize(zaxis - maporigin);
    xx = V.XX;
    yy = V.YY;
    zz = V.ZZ;

    uu = atan(yy, xx) / (2*PI);  /* -.5 -> .5 */
    uu = uu + step(0,-uu); /* remaps to 0 -> 1 */
    vv = acos(-zz) / PI;

}


/*---------------------------------------------------------------------
 * automap performs a planar projection using the normal to the surface
 *	as the normal to the plane to create texture coordinates
 *	uu and vv
 * NOTE: this will only work very well on faceted (polygonal or bilinear)
 *	surfaces.
 * 
 * p - point on surface to be projected
 * uu,vv - new projected coordinates
 * maporigin, yaxis - The projection is performed as if the texture
 *	  map were placed with (uu,vv)==(0,0) at 'maporigin', uu==0 along
 *        yaxis-maporigin and vv==0 along the vector perpendicular to
 *	  both yaxis-maporigin and the normal to the surface.  The map is
 *	  then projected parallel to itself onto the surface.  This has
 *	  the effect of giving each facet of a surface a separate planar
 *	  projection.  This will work better for periodic textures than
 *	  for non-periodic textures.  For surfaces that are perpendicular
 *	  to the yaxis-maporigin vector, a reasonable guess at a good
 *	  "up" vector is attempted.
 * n - surface normal
 *--------------------------------------------------------------------*/

float automap(point p;
	float uu,vv;
	point maporigin, yaxis, n)
{
    varying vector	V,
			XX, YY, ZZ;
    varying float	xx, yy,
			dot;
    uniform vector	yvector, zvector;


    /*
     * The yvector and zvector are the axes of shader space, but expressed
     * in shader space coordinates, not in current coordinates, so no
     * space conversion is required.  Everything else has already been
     * put into shader space coordinates by the callers of this routine.
     */

    yvector = point (0,1,0);
    zvector = point (0,0,1);

    V = p - maporigin;

    ZZ = normalize(n);
    YY = normalize(yaxis - maporigin);
    dot = ZZ . YY;
    /* if "up" (YY) vector parallel to "at" (ZZ) vector, find new "up" */
    if ((dot > (1-0.01))||(dot < (-1+0.01))) {
	dot = ZZ . yvector;
	if ((dot > (1-0.01))||(dot < (-1+0.01))) YY = zvector;
	else YY = yvector;
    }
    /* get orthogonal coordinate system */
    XX = YY ^ ZZ;
    YY = ZZ ^ XX;

    uu = V.XX;
    vv = V.YY;
}




/*--------------------------------------------------------------------
 *
 * decalmap - perform decal mapping. Calls one of the above mapping functions.
 *
 * p - point on surface
 * s, t - unmapped texture coordinates
 * ss, tt - returned mapped texture coordinates
 * maptype - the type of mapping (0 for planar, 1 for cylinder, 2 for sphere,
 *	3 for "standard" mapping using textcoords, 4 for "auto-planar"
 *	mapping - planar perpendicular to surface normal)
 * maporigin - the center of the projection.
 * xaxis, yaxis, zaxis - a local coordinate system that defines the
 *        orientation of the projection.
 * s1,t1,... - corner points for parameter mapping as in textcoords
 * n - normal to the surface
 *--------------------------------------------------------------------*/

float decalmap(point p;
	float s,t;
	float ss, tt;
	float maptype;
	point maporigin, xaxis, yaxis, zaxis;
	float s1,t1,s2,t2,s3,t3,s4,t4;
	varying point n)
{
	varying float uu, vv;

	if (maptype == 0) {
		planemap(p, uu, vv, maporigin, xaxis, yaxis);
	} else if (maptype == 1) {
		cylinmap(p, uu, vv, maporigin, xaxis, yaxis, zaxis);
	} else if (maptype == 2) {
		sphermap(p, uu, vv, maporigin, xaxis, yaxis, zaxis);
	} else if (maptype == 4) {
		automap(p, uu, vv, maporigin, yaxis, n);
	}
	if (maptype != 3) {
	   /* bilinear interpolation to get texture parameters */
	    ss=bilerp(uu,vv,s1,s2,s3,s4);
	    tt=bilerp(uu,vv,t1,t2,t3,t4);
	} else {
		ss = s;
		tt = t;
	}
}