#define PI			3.1415916
#define TWOPI		6.2831832
#define HALFPI	1.5707958

typedef enum {TT_PLANAR,TT_CYLINDRICAL,TT_SPHERICAL} TxType;
typedef enum{ TA_X,TA_Y,TA_Z} TxAxis;

typedef struct {
	float xTextureCenter;
	float yTextureCenter;
	float zTextureCenter;
	float xTextureSize;
	float yTextureSize;
	float zTextureSize;
	TxAxis textureAxis;
	TxType textureType;
} Texture;

float fract(float x)
{
	return((float)(x-floor(x)));
}

void xyztoh(float x,float y,float z,float *h)
{
    if (x == 0.0 && z == 0.0)
        *h = 0.0;
    else {
        if (z == 0.0)
            *h = (x < 0.0) ? HALFPI : -HALFPI;
        else if (z < 0.0)
            *h = -atan(x / z) + PI;
        else
            *h = -atan(x / z);
    }
}

void xyztohp(float x,float y,float z,float *h,float *p)
{
    if (x == 0.0 && z == 0.0) {
        *h = 0.0;
        if (y != 0.0)
            *p = (y < 0.0) ? -HALFPI : HALFPI;
        else
            *p = 0.0;
    }
    else {
        if (z == 0.0)
            *h = (x < 0.0) ? HALFPI : -HALFPI;
        else if (z < 0.0)
            *h = -atan(x / z) + PI;
        else
            *h = -atan(x / z);
        x = sqrt(x * x + z * z);
        if (x == 0.0)
            *p = (y < 0.0) ? -HALFPI : HALFPI;
        else
            *p = atan(y / x);
    }
}

void TextureUV(Texture *tx,float x,float y,float z,float *u, float *v,int widthTiling, int heightTiling)
{
		float t,s,lon,lat;
    x -= tx->xTextureCenter;
    y -= tx->yTextureCenter;
    z -= tx->zTextureCenter;
    if (tx->textureType == TT_PLANAR) {
        s = (tx->textureAxis == TA_X) ? z / tx->zTextureSize + .5 :
          x / tx->xTextureSize + .5;
        t = (tx->textureAxis == TA_Y) ? -z / tx->zTextureSize + .5 :
          -y / tx->yTextureSize + .5;
        *u = fract(s);
        *v = fract(t);
    }
    else if (tx->textureType == TT_CYLINDRICAL) {
        if (tx->textureAxis == TA_X) {
            xyztoh(z,x,-y,&lon);
            t = -x / tx->xTextureSize + .5;
        }
        else if (tx->textureAxis == TA_Y) {
            xyztoh(-x,y,z,&lon);
            t = -y / tx->yTextureSize + .5;
        }
        else {
            xyztoh(-x,z,-y,&lon);
            t = -z / tx->zTextureSize + .5;
        }
        lon = 1.0 - lon / TWOPI;
        if (widthTiling != 1.0)
            lon = fract(lon) * widthTiling;
        *u = fract(lon);
        *v = fract(t);
    }
    else if (tx->textureType == TT_SPHERICAL) {
        if (tx->textureAxis == TA_X)
            xyztohp(z,x,-y,&lon,&lat);
        else if (tx->textureAxis == TA_Y)
            xyztohp(-x,y,z,&lon,&lat);
        else
            xyztohp(-x,z,-y,&lon,&lat);
        lon = 1.0 - lon / TWOPI;
        lat = .5 - lat / PI;
        if (widthTiling != 1.0)
            lon = fract(lon) * widthTiling;
        if (heightTiling != 1.0)
            lat = fract(lat) * heightTiling;
        *u = fract(lon);
        *v = fract(lat);
    }
}

