/*
	name:	texture.c

	Textures
	--------

	Texture-calculation and texture-handling.

*/


#include  "defs.h"


void CreateDefTexture(TEXTURE *t)
{
	t->CMap.Colors[0].r=1.0; t->CMap.Colors[0].g=0.3; t->CMap.Colors[0].b=0.0;
	t->CMap.Colors[1].r=0.0; t->CMap.Colors[1].g=0.0; t->CMap.Colors[1].b=0.0;
	t->CMap.LastBound=1;
	t->Pattern=PATTERN_NONE;
	t->Reflect.r=t->Reflect.g=t->Reflect.b=0.0;
	t->Filter.r=t->Filter.g=t->Filter.b=0.0;
	t->Ior=0.0;
	t->Ambient=0.2;
	t->Diffuse=0.8;
	t->Phong=0.3; t->PhongSize=10.0;
	ClearTransform(&t->Transform);
}



void CopyTexture(TEXTURE *t2, TEXTURE *t1)
{
	long	i,lbound;

	lbound=t1->CMap.LastBound;
	for(i=0;i<=lbound;i++) {
		t2->CMap.Bounds[i]=t1->CMap.Bounds[i];
		t2->CMap.Colors[i].r=t1->CMap.Colors[i].r;
		t2->CMap.Colors[i].g=t1->CMap.Colors[i].g;
		t2->CMap.Colors[i].b=t1->CMap.Colors[i].b;
	}
	t2->CMap.LastBound=lbound;
	t2->Pattern=t1->Pattern;
	t2->Reflect.r=t1->Reflect.r;
	t2->Reflect.g=t1->Reflect.g;
	t2->Reflect.b=t1->Reflect.b;
	t2->Filter.r=t1->Filter.r;
	t2->Filter.g=t1->Filter.g;
	t2->Filter.b=t1->Filter.b;
	t2->Ior=t1->Ior;
	t2->Ambient=t1->Ambient;
	t2->Diffuse=t1->Diffuse;
	t2->Phong=t1->Phong;
	t2->PhongSize=t1->PhongSize;
	CopyTransform(&t2->Transform,&t1->Transform);
}



void CopyColor(COLOR *c2, COLOR *c1)
{
	c2->r=c1->r; c2->g=c1->g; c2->b=c1->b;
}

/**************************************************************
 *
 *     Here are some useful (more or less) texture-patterns.
 *
 **************************************************************/

void GetSurfaceColor(COLOR *Color, TEXTURE *t, POINT *ip)
{
	double	MapValue;
	int	indx,foundindx,i;
	COLORMAP *cm;
	VECTOR	tempv;
	POINT	temppoint;

	CopyPoint(&temppoint,ip);

	if((t->Transform.NumTransforms>0)&&(t->Pattern!=PATTERN_NONE)) {
	    for(i=t->Transform.NumTransforms-1L;i>=0L;i--) {
		switch(t->Transform.Entry[i].Type) {
		    case TRANSFORM_SCALE:
			temppoint.x=temppoint.x/t->Transform.Entry[i].Values.x;
			temppoint.y=temppoint.y/t->Transform.Entry[i].Values.y;
			temppoint.z=temppoint.z/t->Transform.Entry[i].Values.z;
			break;
		    case TRANSFORM_MOVE:
			temppoint.x=temppoint.x-t->Transform.Entry[i].Values.x;
			temppoint.y=temppoint.y-t->Transform.Entry[i].Values.y;
			temppoint.z=temppoint.z-t->Transform.Entry[i].Values.z;
			break;
		    case TRANSFORM_ROTATE:
			NegVector(&tempv,&t->Transform.Entry[i].Values);
			RotatePoint(&temppoint,&tempv);
			break;
		    case TRANSFORM_NONE:
		    default:
			break;
		}
	    }
	}

	switch(t->Pattern) {
	    case PATTERN_CHECKER:
		MapValue=PatternChecker(&temppoint);
		break;
	    case PATTERN_CIRCLES:
		MapValue=PatternCircles(&temppoint);
		break;
	    case PATTERN_RINGS:
		MapValue=PatternRings(&temppoint);
		break;
	    case PATTERN_SPOTS:
		MapValue=PatternSpots(&temppoint);
		break;
	    case PATTERN_GRADIENT:
		MapValue=PatternGradient(&temppoint);
		break;
	    case PATTERN_NONE:
	    default:
		MapValue=0.0;
		break;
	}

	cm=&t->CMap;
	foundindx=-1;

	if(MapValue>EPSILON) {
	    indx=0;
	    while((indx<cm->LastBound)&&(foundindx!=0)) {
		if((MapValue>=cm->Bounds[indx])&&(MapValue<=cm->Bounds[indx+1]))
			foundindx=0;
		else indx++;
	    }
	}
	if(foundindx==0) {
	    Color->r=(cm->Colors[indx].r*(cm->Bounds[indx+1]-MapValue)+cm->Colors[indx+1].r*(MapValue-cm->Bounds[indx]))/(cm->Bounds[indx+1]-cm->Bounds[indx]);
	    Color->g=(cm->Colors[indx].g*(cm->Bounds[indx+1]-MapValue)+cm->Colors[indx+1].g*(MapValue-cm->Bounds[indx]))/(cm->Bounds[indx+1]-cm->Bounds[indx]);
	    Color->b=(cm->Colors[indx].b*(cm->Bounds[indx+1]-MapValue)+cm->Colors[indx+1].b*(MapValue-cm->Bounds[indx]))/(cm->Bounds[indx+1]-cm->Bounds[indx]);
	}
	else {
	    Color->r=cm->Colors[0].r;
	    Color->g=cm->Colors[0].g;
	    Color->b=cm->Colors[0].b;
	}
}


double PatternChecker(POINT *ip)
{
	return( (double)(((long)floor(ip->x+EPSILON)+(long)floor(ip->y+EPSILON)+(long)floor(ip->z+EPSILON))&1L) );
}


double PatternCircles(POINT *ip)
{
	return(fmod(sqrt(ip->x*ip->x+ip->y*ip->y+ip->z*ip->z),1.0));
}

double PatternRings(POINT *ip)
{
	return(fmod(sqrt(ip->x*ip->x+ip->y*ip->y),1.0));
}

double PatternSpots(POINT *ip)
{
	double	d;
	POINT	dgrid;

	dgrid.x=ip->x-floor(ip->x+0.5);
	dgrid.y=ip->y-floor(ip->y+0.5);
	dgrid.z=ip->z-floor(ip->z+0.5);

	d=2.0*sqrt(dgrid.x*dgrid.x+dgrid.y*dgrid.y+dgrid.z*dgrid.z);
	if(d>1.0) d=1.0;
	return(d);
}

double PatternGradient(POINT *ip)
{
	if(ip->z>0) return(fmod(fabs(ip->z),1.0));
	else return(fmod(1.0-fabs(ip->z),1.0));
}


