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

	Fog.cpp

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

	Author:	Jerome Bignon

	Date:	04/20/99

	Revision History

	when		who			what & why
	=========== ===========	=============================================================
	08/20/99	cph			Put in Extension3DInit() and Extension3DCleanup() methods
	7/6/99		Pierre-E	modification of an identifier in the methods SegmentFilter
							and DirectionFilter: filterOut --> inOutFilter
	04/22/99	Jerome		Finals comments

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

#include "math.h"
#include "Fog.h"

const MCGUID CLSID_Fog(R_CLSID_Fog);

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 Fog
	TBasicUnknown* res = NULL;

	if (classId == CLSID_Fog) res = new Fog;

	return res;
}


Fog::Fog()												// In this constructor we perform
{														// all the the Fog's initializations
	fData.fColor.TMCColorRGB::Set(1.0f, 1.0f, 1.0f);	// White color ( We use the TMCColorRGB::Set method so we don't have to specify the alpha value )
	fData.fZmax = 20.0f;								// Minimal altitude of the Fog
	fData.fZmin = 0.0f;									// Maximal altitude of the Fog
	fData.fVisibility = 40.0f;							// Distance of visibility of the fog
}

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

MCCOMErr Fog::SegmentFilter(TVector3& beg, TVector3& end, TMCColorRGB& inOutFilter, boolean indirectLight, boolean isShadowCasting, boolean isSunLightShadowCasting)
{
  real		distanceInTheFog;
  TVector3	beamVector;
  real		zmin, zmax;
  real		filtercoef;

  distanceInTheFog = (end - beg).GetMagnitude();

  if (beg.z < end.z)
  {
	  zmin = beg.z;
	  zmax = end.z;
  }
  else
  {
	  zmin = end.z;
	  zmax = beg.z;
  }

  if ((zmin > fData.fZmax) || (zmax < fData.fZmin))
  { 
	 distanceInTheFog = 0; // the light beam is not in the fog don't do anything
  }
  else
  {
	  if (zmin != zmax)
	  {
		distanceInTheFog /= (zmax - zmin);

		  if (zmin < fData.fZmin)
			  zmin = fData.fZmin;

		  if (zmax > fData.fZmax)
			  zmax = fData.fZmax;

		distanceInTheFog *= (zmax - zmin);
	  }
  }

    filtercoef = 1.0f - distanceInTheFog / fData.fVisibility;
    if (filtercoef < 0.0f)
	{
      filtercoef = 0.0f;
    }
    inOutFilter = inOutFilter * filtercoef + fData.fColor * (1.0f - filtercoef);
  return MC_S_OK;
}

MCCOMErr Fog::DirectionFilter(TVector3& origin, TVector3& direction, TMCColorRGB& inOutFilter, boolean indirectLight)
{
  real		distanceInTheFog;
  TVector3	beamVector;
  TVector3	beaminfogbeg, beaminfogend;
  real		filtercoef;
  
  if ((origin.z > fData.fZmax) && (direction.z >= 0.0f))
  {
    // Don't do anything
  }
  else if ((origin.z < fData.fZmin) && (direction.z <= 0.0f))
  {
    // Don't do anything
  }

  else
  {
    if ((origin.z > fData.fZmax) || (origin.z < fData.fZmin))
	{
      beaminfogbeg = origin + direction * (fData.fZmax - origin.z) / direction.z;
      beaminfogend = origin + direction * (fData.fZmin - origin.z) / direction.z;
    }
    else if (direction.z > 0.0f)
	{
      beaminfogbeg = origin;
      beaminfogend = origin + direction * (fData.fZmax - origin.z) / direction.z;
    }
    else if (direction.z < 0.0f)
	{
      beaminfogbeg = origin;
      beaminfogend = origin + direction * (fData.fZmin - origin.z) / direction.z;
    }
    else
	{
	  // direction->z=0.0
      inOutFilter = fData.fColor;
      return MC_S_OK; 
    }
    beamVector = beaminfogend - beaminfogbeg;
    distanceInTheFog = beamVector.GetMagnitude();
    filtercoef = 1.0f - distanceInTheFog / fData.fVisibility;
    if (filtercoef < 0.0f)
	{
      filtercoef = 0.0f;
    }
    inOutFilter = inOutFilter * filtercoef + fData.fColor * (1.0f - filtercoef);
  }
  return MC_S_OK;
}
