/************************************************************************
 * project.h - Routines for texture projection
 *
 * Entropy and BMRT are:
 * (c) Copyright 2001 Exluna, Inc.  Portions (c) 1990-2000 Larry Gritz.
 * All rights reserved.
 *
 * $Revision: 1.3 $    $Date: 2001/06/15 23:45:26 $
 *
 ************************************************************************/



#ifndef PROJECT_H
#define PROJECT_H 1

/* Project 3-D points onto a unit sphere centered at the origin */
void
spherical_projection (point p, output float ss, output float tt)
{
    vector V = normalize(p);
    ss = (-atan (V[1] / V[0]) + M_PI) / (2*M_PI);
    tt = 0.5 - acos(V[2]) / M_PI;
}
    


/* Project 3-D points onto a cylinder about the z-axis between z=0 and z=1 */
void
cylindrical_projection (point p, output float ss, output float tt)
{
    vector V = normalize(p);
    ss = (-atan (V[1] / V[0]) + M_PI) / (2*M_PI);
    tt = V[2];
}




void
ProjectTo2D (string projection,
	     point P, string whichspace,
	     matrix xform,
		 float s, float t,
	     output float ss, output float tt )
{
    point Pproj;
    if (projection == "st") {
	Pproj = point (s, t, 0);
    } else {
        Pproj = transform (whichspace, P);
    }
    Pproj = transform (xform, Pproj);
    if (projection == "planar" || projection == "st") {
	ss = Pproj[0];
	tt = Pproj[1];
   }
    else if (projection == "perspective") {
	float z = max (Pproj[2], 1.0e-6);  /* avoid zero division */
	ss = Pproj[0] / z;
	tt = Pproj[1] / z;
    }
    /* Special cases for the projections that may wrap */
    else if (projection == "spherical")
	spherical_projection (Pproj, ss, tt);
    else if (projection == "cylindrical")
	cylindrical_projection (Pproj, ss, tt);
}



color
GetColorTextureAndAlpha (string texturename,
			 string projection,
			 point P, string whichspace,
			 matrix xform,
			 float s, float t,
			 float blur,
			 float alphachannel,
			 output float alpha
    )
{
    float ss, tt, ds, dt;
    ProjectTo2D (projection, P, whichspace, xform, s, t, ss, tt);
    ds *= 0.5;  dt *= 0.5;
    color Ct = texture (texturename, ss, tt, "blur", blur);
    alpha = texture (texturename, ss, tt,
			   "blur", blur, "fill", 1, "firstchannel", (int)alphachannel);
    return Ct;
}



float
GetFloatTextureAndAlpha (string texturename,
			 string projection,
			 point P, string whichspace,
			 matrix xform,
			 float s, float t,
			 float blur,
			 float alphachannel,
			 output float alpha
    )
{
    float ss, tt;
    ProjectTo2D (projection, P, whichspace, xform, s, t, ss, tt);
    float val = texture (texturename, ss, tt, "blur", blur);
    alpha = texture (texturename, ss, tt,
			   "blur", blur, "fill", 1, "firstchannel", (int)alphachannel);
    return val;
}



color
ApplyColorTextureOver (color basecolor,
		       string texturename,
		       string projection,
		       point P, string whichspace,
		       matrix xform,
			   float s, float t,
		       float blur
    )
{
    float alpha;
    color Ct = GetColorTextureAndAlpha (texturename, projection, P, whichspace,
					xform, s, t, blur, 3, alpha);
    return Ct + (1-alpha)*basecolor;
}



float
ApplyFloatTextureOver (float baseval,
		       string texturename,
		       string projection,
		       point P, string whichspace,
		       matrix xform,
			   float s, float t,
		       float blur
    )
{
    float alpha;
    float x = GetFloatTextureAndAlpha (texturename, projection, P, whichspace,
					xform, s, t, blur, 3, alpha);
    return x + (1-alpha)*baseval;
}


/* Helper function to convert arrays of 16 floats to matrices */
matrix array_to_mx (float mx[16])
{
    return matrix (mx[0], mx[1], mx[2], mx[3],
		   mx[4], mx[5], mx[6], mx[7],
		   mx[8], mx[9], mx[10], mx[11],
		   mx[12], mx[13], mx[14], mx[15]);
}




#endif /* PROJECT_H */
