/****************************************************************************************

	NonUniformScale.cpp

	Copyright (c)1990 - 1999 MetaCreations. All rights reserved.

	Author:	Jonathan Trachtenberg

	Date:	06/09/99

	Revision History

	when		who			what & why
	=========== ===========	=============================================================
	08/20/99	cph			Put in Extension3DInit() and Extension3DCleanup() methods
	06/18/99	Jonathan	Functionally Complete
	06/18/99	Arnaud		Fixed BBox size error
	06/09/99	Jonathan	Created

****************************************************************************************/

#include "NonUniformScale.h"
#include "MCCountedPtrHelper.h"

const MCGUID CLSID_NonUniformScale(R_CLSID_NonUniformScale);


void Extension3DInit(IMCUnknown* utilities)
{
	// Perform your dll initialization here
}

void Extension3DCleanup()
{
	// Perform any nec clean-up here
}

TBasicUnknown* MakeCOMObject(const MCCLSID& classId)	// This method instanciate
{														// the object ColorBalance
	TBasicUnknown* res = NULL;

	if (classId == CLSID_NonUniformScale) res = new NonUniformScale;

	return res;
}

uint32 NonUniformScale::AddRef()
{
	return TBasicDeformModifier::AddRef();
}

MCCOMErr NonUniformScale::QueryInterface(const MCIID& riid, void** ppvObj)
{
	if ( (TBasicWireframe::QueryInterface(riid, ppvObj) == MC_S_OK) && (*ppvObj) )
	{
		return MC_S_OK;
	}
	return TBasicDeformModifier::QueryInterface(riid, ppvObj);
}

NonUniformScale::NonUniformScale()
{
		fData.fAxis = kRadioZ_id;
		fData.fUBegScale = 1.0;
		fData.fUEndScale = 1.0;
		fData.fVBegScale = 1.0;
		fData.fVEndScale = 1.0;
		fData.fBoundingBox.fMin[0] = 0.0;
		fData.fBoundingBox.fMin[1] = 0.0;
		fData.fBoundingBox.fMin[2] = 0.0;
		fData.fBoundingBox.fMax[0] = 0.0;
		fData.fBoundingBox.fMax[1] = 0.0;
		fData.fBoundingBox.fMax[2] = 0.0;
}

void* NonUniformScale::GetExtensionDataBuffer()
{
	return &fData;
}

void NonUniformScale::SetBoundingBox(const TBBox3D& bbox)
{
	fData.fBoundingBox = bbox;
}

MCCOMErr NonUniformScale::DeformPoint(const TVector3& point, TVector3& result)
{

	int16	u, v, w;
	real	wrelative;

	switch (fData.fAxis)
	{
	case kRadioX_id:
		u=1; //Y Axis
		v=2; //Z Axis
		w=0; //X Axis
		break;
	case kRadioY_id:
		u=2; //Z Axis
		v=0; //X Axis
		w=1; //Y Axis
		break;
	case kRadioZ_id:
		u=0; //X Axis
		v=1; //Y Axis
		w=2; //Z Axis
		break;
	default:
		break;
	}
	if ((fData.fBoundingBox.fMax[w]-fData.fBoundingBox.fMin[w])==0.0)
	{
		result = point;
		return MC_S_OK;
	}
	wrelative=(point[w] - fData.fBoundingBox.fMin[w])/(fData.fBoundingBox.fMax[w]-fData.fBoundingBox.fMin[w]);
	if ((fData.fUEndScale+fData.fUBegScale)==0.0)
	{
		
		result[u]=0.0;
	}
	else
	{
		result[u] = point[u] * (fData.fUBegScale + wrelative * (fData.fUEndScale-fData.fUBegScale));
	}
	if ((fData.fVEndScale+fData.fVBegScale)==0.0)
	{ 
		result[v] = 0.0;
	}
	else
	{
		result[v] = point[v] * (fData.fVBegScale + wrelative * (fData.fVEndScale-fData.fVBegScale));
	}
	result[w] = point[w];

	return MC_S_OK;
}

MCCOMErr NonUniformScale::DeformBBox(const TBBox3D &in,TBBox3D &out)
{

	TVector3	TempPoint[2];

	TVector3	point, deformed;

	TempPoint[0] = in.fMin;
	TempPoint[1] = in.fMax;

	int XX, YY, ZZ, checkbound;  //Loop Controls

	out=in;

	for (XX=1; XX>=0; XX--)
	{
		point[0]=TempPoint[XX][0];
		for (YY=1; YY>=0; YY--)
		{
			point[1]=TempPoint[YY][1];
			for (ZZ=1; ZZ>=0; ZZ--)
			{
				point[2]=TempPoint[ZZ][2];
				DeformPoint(point, deformed);
				for (checkbound=2; checkbound>=0; checkbound--)
				{
					if (deformed[checkbound] < out.fMin[checkbound])
						out.fMin[checkbound] = deformed[checkbound];
					if (deformed[checkbound] > out.fMax[checkbound])
						out.fMax[checkbound] = deformed[checkbound];
				}	
			}
		}
	}
	return MC_S_OK;
}

// -------- Wireframes ------------

MCCOMErr NonUniformScale::TrackWireFrame (I3DShWireFrame* wireFrame, int16 proj, I3DShTreeElement* tree, int16 handle, const TRACKINFO& startinfo, const TRACKINFO& previnfo, const TRACKINFO& nextinfo)
{																				
	int16	axis, //Axis Control
			p1,
			p2,
			bit, //Handle case
			bit1,
			bit2;

	int16	ii;  //loop control

	TVector3 position,
			 center,
			 OrigTrack;

	real *scaleU, *scaleV;
	

	for (ii=2; ii>=0; ii--) 
		center[ii]=((fData.fBoundingBox.fMin[ii]+fData.fBoundingBox.fMax[ii])*0.5);

	switch (fData.fAxis)
	{
		case kRadioX_id:
			axis=0;
			p1=1;
			p2=2;
			bit=4;
			bit1=2;
			bit2=1;
			break;
		case kRadioY_id:
			axis=1;
			p1=2;
			p2=0;
			bit=2;
			bit1=1;
			bit2=4;
			break;
		case kRadioZ_id:
			axis=2;
			p1=0;
			p2=1;
			bit=1;
			bit1=4;
			bit2=2;
			break;
	}

	if (proj==3)
	{
		if (nextinfo.fModifiers & kWFOption)
			position=nextinfo.fOrthoLoc;
		else 
			position=nextinfo.fLoc;
	}
	else
	{
		WFData wf;
		wireFrame->GetWireFrame(wf);
		if (startinfo.fLoc[0]==nextinfo.fLoc[0] && startinfo.fLoc[1]==nextinfo.fLoc[1] && startinfo.fLoc[2]==nextinfo.fLoc[2])
		{
			position=wf.fPoints[handle].fLoc;
			OrigTrack=position;
		}
		else
		{
			for (ii=2; ii>=0; ii--)
				position[ii]=nextinfo.fLoc[ii]+OrigTrack[ii]-startinfo.fLoc[ii];
		}
	}

	if (handle & bit)
	{
		scaleU=&fData.fUEndScale;
		scaleV=&fData.fVEndScale;
	}
	else
	{
		scaleU=&fData.fUBegScale;
		scaleV=&fData.fVBegScale;
	}

	*scaleU=(center[p1]-position[p1])/(fData.fBoundingBox.fMax[p1]-center[p1]);
	*scaleV=(center[p2]-position[p2])/(fData.fBoundingBox.fMax[p2]-center[p2]);

	if (handle & bit1)
		*scaleU= -*scaleU;

	if (handle & bit2)
		*scaleV= -*scaleV;

	if (*scaleU<0)
		*scaleU=0;
	if (*scaleV<0)
		*scaleV=0;
	if (*scaleU>10)
		*scaleU=10;
	if (*scaleV>10)
		*scaleV=10;

	WFUpdatePoints(wireFrame);

	return MC_S_OK;
}

void NonUniformScale::WFUpdatePoints(I3DShWireFrame* wireFrame)
{
	// update the points that can move
	TVector3 cur, def;
	TVector3 min=fData.fBoundingBox.fMin;
	TVector3 max=fData.fBoundingBox.fMax;
	int ii, jj, kk, pt;

	pt=0;
	cur[0]=min[0];
	for (ii=1; ii>=0; ii--)
	{
		cur[1]=min[1];
		for (jj=1; jj>=0; jj--)
		{
			cur[2]=min[2];
			for (kk=1; kk>=0; kk--)
			{
				DeformPoint(cur, def);
				wireFrame->SetPoint(pt++, kWFSquareHandle, def);
				cur[2]=max[2];
			}
			cur[1]=max[1];
		}
		cur[0]=max[0];
	}
}

MCCOMErr NonUniformScale::DataToWireFrame (I3DShWireFrame* wireFrame, int16 proj, I3DShTreeElement* tree)
{
	int ii, jj, pt;

	wireFrame->AllocateWireFrame(8, 12);
	pt=0;
	for (ii=0; ii<8; ii++)
	{
		for (jj=1; jj<8; jj<<=1)
		{
			if ((ii^jj)<ii)
				wireFrame->Connect(pt++, ii, ii^jj);
		}
	}

	WFUpdatePoints(wireFrame);
	return MC_S_OK;
}
