#include "ShadowMapping.h"
#include "..\Utilities\util.h"

ShadowMapping::ShadowMapping(DeviceStateManager* const device) 
{
	m_Device = device;
	mUseLispSM = false;
	mB = NULL;
	mLVS = NULL;
	m_UseIDBuffer = false;
	m_UseNVShadowMap = false;
	
	m_NVShadowMap = NULL;
	m_ShadowMap = NULL;
	m_SMWorldSize = 1;
	m_N = 1;

	m_ParamSMMatrix.SetValue("SM_matSM", &mMatSM, sizeof(DXMatrix));
	m_ParamSMSize.SetValue("SM_ShadowMapSize", &m_ShadowMapSize, sizeof(float));
	m_TexParamSM.Handle = "SM_ShadowMap";
	m_TexParamSM.Surface = NULL;
	m_TexParamID.Handle = "SM_IDBuffer";
	m_TexParamID.Surface = NULL;

	m_JitterType = (SMJITTERTYPE)-1;
	SetJitterType(SMJT_NONE);

	SetShadowMapSize(1024);
}

ShadowMapping::~ShadowMapping(void)
{
	delete mB;
	delete mLVS;
}

void ShadowMapping::Update(const AABB &aabbScene, const Camera &cam, const DXVector3 &lightDir)
{
	mCam = cam;
	mLightDir = lightDir;
	
	UpdateB(aabbScene);

	Camera camLight;
	
	camLight.SetPosition(mCam.GetPosition());  
	camLight.SetLookAt(mCam.GetPosition()+mLightDir, mCam.GetViewDirVector());
	//camLight.SetLookAt(mCam.GetPosition()+mLightDir, DXVector3(1,0,0));

	//camLight.SetPosition(obbScene.GetMin() + (obbScene.GetMax() - obbScene.GetMin()) * 0.5f);
	//camLight.SetLookAt(camLight.GetPosition()+mLightDir, mCam.GetViewDirVector());
	
	mCosGamma = D3DXVec3Dot(lightDir, cam.GetViewDirVector());

	//swap coordiante system y <-> z
	DXMatrix matSwap;
	D3DXMatrixIdentity((D3DXMATRIX*)&matSwap); 
	matSwap._22 = 0; 
	matSwap._23 = 1; //z -> y
	matSwap._32 = -1;//y ->-z
	matSwap._33 = 0;

	camLight.SetProjMatrix(camLight.GetProjMatrix() * matSwap);

	if (mUseLispSM && mCosGamma < 0.95)
	{ 
		DXMatrix matVP;
		D3DXMatrixMultiply((D3DXMATRIX*)&matVP, (D3DXMATRIX*)&camLight.GetViewMatrix(), (D3DXMATRIX*)&camLight.GetProjMatrix());
		DXVector3 projViewDir = GetProjViewDir_ls(matVP);

		DXMatrix m;
		// look from 0,0,0 to projViewDir, up = y
		D3DXMatrixLookAtLH((D3DXMATRIX*)&m, DXVector3(0,0,0), projViewDir, DXVector3(0,1,0));
		camLight.SetProjMatrix(camLight.GetProjMatrix() * m);

		m_CamLispSM = camLight;

		camLight.SetProjMatrix(camLight.GetProjMatrix() * CalcLispSMMtx(camLight.GetViewMatrix() * camLight.GetProjMatrix(), 1));
	}
	else
	{
		int i = 0;
	}

	BoundingMesh B_ls(*mB);
	B_ls.TransformPoints(camLight.GetViewMatrix() * camLight.GetProjMatrix());
	AABB obbLightVolume = B_ls.BuildAABB();  
	DXMatrix matFit;
	//by this calculation z only is mapped from 0 to 1
	float dy = obbLightVolume.GetMax().y - obbLightVolume.GetMin().y;
	float dz = obbLightVolume.GetMax().z - obbLightVolume.GetMin().z;
	//y should be -1 to 0  
	//z should be -1 to 1 

	D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&matFit,obbLightVolume.GetMin().x, obbLightVolume.GetMax().x, 
								obbLightVolume.GetMin().y, obbLightVolume.GetMax().y + dy,  
								obbLightVolume.GetMin().z + dz/2, obbLightVolume.GetMax().z);
	 
	camLight.SetProjMatrix(camLight.GetProjMatrix() * matFit);

	m_SMWorldSize = _max(obbLightVolume.GetMax().x - obbLightVolume.GetMin().x, obbLightVolume.GetMax().z - obbLightVolume.GetMin().z);

	DXMatrix matSwapBack; 
	D3DXMatrixIdentity((D3DXMATRIX*)&matSwapBack);
	matSwapBack._22 = 0;
	matSwapBack._23 = -1;//z ->-y 
	matSwapBack._32 = 1; //y -> z
	matSwapBack._33 = 0;
	camLight.SetProjMatrix(camLight.GetProjMatrix() * matSwapBack);

	SetLightViewProj(camLight.GetViewMatrix(), camLight.GetProjMatrix());
}

void ShadowMapping::SetLightViewProj(const DXMatrix& view, const DXMatrix& proj)
{
	mMatLightView = view;
	mMatLightProj = proj;
	mMatSM = mMatLightView * mMatLightProj;

	//mMatSM *= DXMatrix::TranslationMatrix(0, 0, 0) * DXMatrix::ScalingMatrix(1, 1, 1);
	//mMatSM *= DXMatrix::ScalingMatrix(2, 2, 1) * DXMatrix::TranslationMatrix(-1, 1, 0);

	float fOffsetX = 0.5f + (0.5f / m_ShadowMapSize);
    float fOffsetY = 0.5f + (0.5f / m_ShadowMapSize);
    unsigned int range = 1;
	float fBias = 0; //constant bias, implemented elsewhere
    DXMatrix texScaleBiasMat = D3DXMATRIX( 0.5f,     0.0f,     0.0f,         0.0f,
										0.0f,    -0.5f,     0.0f,         0.0f,
										0.0f,     0.0f,     (float)range, 0.0f,
										fOffsetX, fOffsetY, fBias,         1.0f );
	mMatSMTex = mMatSM * texScaleBiasMat;

	m_ParamSMMatrix.UpdateValue(&mMatSM);
}

void ShadowMapping::UpdateB(const AABB &aabbScene)
{
	const ViewFrustum viewFrust(mCam);

	delete mLVS;
	mLVS = new BoundingMesh(viewFrust);

	//(V n S)
	mLVS->ClipByAABB(aabbScene);

	//points that extend b in lightdirection, to include shadowcasters
	DXVector3* points = new DXVector3[mLVS->GetTriangleCount()*3 * 2];
	memcpy(points, mLVS->GetPoints(), sizeof(DXVector3) * mLVS->GetTriangleCount()*3);
	for(int i=0; i < mLVS->GetTriangleCount()*3; i++)
	{
		DXVector3 np = points[i] - mLightDir * 1000;

		//clip again with Scene 
		//TODO this is only a ceap way
		/*if(np.x < aabbScene.GetMin().x)
			np.x = aabbScene.GetMin().x;
		else if(np.x > aabbScene.GetMax().x)
			np.x = aabbScene.GetMax().x;

		if(np.y < aabbScene.GetMin().y)
			np.y = aabbScene.GetMin().y;
		else if(np.y > aabbScene.GetMax().y)
			np.y = aabbScene.GetMax().y;

		if(np.z < aabbScene.GetMin().z)
			np.z = aabbScene.GetMin().z;
		else if(np.z > aabbScene.GetMax().z)
			np.z = aabbScene.GetMax().z;*/

		points[i + mLVS->GetTriangleCount()*3] = np;
	}

	delete mB;
	mB = new BoundingMesh(points, mLVS->GetTriangleCount()*2);
	delete points;
}

DXVector3 ShadowMapping::GetProjViewDir_ls(const DXMatrix& lv) const
{
	DXVector3 e = GetNearCameraPointE();
	
	DXVector3 b = e + mCam.GetViewDirVector();

	DXVector3 e_ls, b_ls;

	D3DXVec3TransformCoord(e_ls, e, (D3DXMATRIX*)&lv);
	D3DXVec3TransformCoord(b_ls, b, (D3DXMATRIX*)&lv);

	DXVector3 projViewDir = b_ls - e_ls;
	projViewDir.y = 0;

	return projViewDir;
} 

DXVector3 ShadowMapping::GetNearCameraPointE(void) const
{
	//transform points in viewspace
	DXVector3* points = new DXVector3[mLVS->GetTriangleCount()*3];
	D3DXVec3TransformCoordArray((D3DXVECTOR3*)points, sizeof(DXVector3), (D3DXVECTOR3*)mLVS->GetPoints(), sizeof(DXVector3), (D3DXMATRIX*)&mCam.GetViewMatrix(), mLVS->GetTriangleCount()*3);
	
	//find nearest point
	DXVector3 e = points[0];
	for(int i=1; i<mLVS->GetTriangleCount()*3;i++)
	{
		if(e.z > points[i].z)
			e = points[i];
	}
	delete [] points;
	
	//transform e back to wordspace
	D3DXMATRIX iv;
	D3DXMatrixInverse(&iv, NULL, (D3DXMATRIX*)&mCam.GetViewMatrix());
	D3DXVec3TransformCoord(e, e, &iv);

	return e;
}

DXMatrix ShadowMapping::CalcLispSMMtx(const DXMatrix& matLight, const float nscale)
{
	BoundingMesh B_ls(*mB);
	B_ls.TransformPoints(matLight);
	AABB obbB_ls = B_ls.BuildAABB();
	//const float n = 200;//GetN(matLight, obbB_ls); 
	m_N = GetN(matLight, obbB_ls) * nscale * 2; 

	DXMatrix lightProj;
	if(ISNAN(m_N))
	{
		//uniform shadowmapping
		D3DXMatrixIdentity((D3DXMATRIX*)&lightProj);
	}
	else  
	{
		//get the coordinates of the near camera point in light space
		DXVector3 e_ls;
		D3DXVec3TransformCoord(e_ls, GetNearCameraPointE(), (D3DXMATRIX*)&matLight);

		//c start has the x and y coordinate of e, the z coord of B.min() 
		const DXVector3 Cstart_lp(e_ls.x, e_ls.y, obbB_ls.GetMin().z);
  
		//we work along a negative axis so we transform +n*<the positive axis> == -n*<neg axis>
		const DXVector3 C = -(Cstart_lp - m_N * DXVector3(0,0,1));    
   
		//construct a translation that moves to the projection center
		DXMatrix projectionCenter; 
 		D3DXMatrixTranslation((D3DXMATRIX*)&projectionCenter, C.x, C.y, C.z); 

		//calc d the perspective transform depth or light space y extents
		const float dz = abs(obbB_ls.GetMax().z - obbB_ls.GetMin().z);
 
		DXMatrix P;  
		D3DXMatrixPerspectiveOffCenterLH((D3DXMATRIX*)&P, -1, 1, -1, 1, m_N, m_N+dz);  
		//D3DXMatrixPerspectiveLH(&P, 2.f*obbB_ls.GetMax().x*n, 2.f*n*obbB_ls.GetMax().y, n, n+dz);  
 
		lightProj = projectionCenter * P;
	}

	return lightProj;
}

float ShadowMapping::GetN(const DXMatrix& matLight, const AABB& obbB_ls) const
{
	DXMatrix invLightSpace;
	D3DXMatrixInverse((D3DXMATRIX*)&invLightSpace, NULL, (D3DXMATRIX*)&matLight);

	const DXVector3 z0_ls = GetZ0_ls(matLight, GetNearCameraPointE(), obbB_ls.GetMax().z, mCam.GetViewDirVector());
	const DXVector3 z1_ls(z0_ls.x, z0_ls.y, obbB_ls.GetMin().z);

	//to world
	DXVector3 z0_ws, z1_ws;
	D3DXVec3TransformCoord(z0_ws, z0_ls, (D3DXMATRIX*)&invLightSpace);
	D3DXVec3TransformCoord(z1_ws, z1_ls, (D3DXMATRIX*)&invLightSpace);
	
	//to eye
	DXVector3 z0_cs, z1_cs;
	D3DXVec3TransformCoord(z0_cs, z0_ws, (D3DXMATRIX*)&mCam.GetViewMatrix());
	D3DXVec3TransformCoord(z1_cs, z1_ws, (D3DXMATRIX*)&mCam.GetViewMatrix());

	const float z0 = z0_cs.z;
	const float z1 = z1_cs.z;
	const float d = abs(obbB_ls.GetMax().z - obbB_ls.GetMin().z);

	return d / (sqrt(z1 / z0) - 1.f);
}

DXVector3 ShadowMapping::GetZ0_ls(const DXMatrix& matLight, const DXVector3& e, const float B_lsZmax, const DXVector3& camDir) const
{
	//to calculate the parallel plane to the near plane through e we 
	//calculate the plane A with the three points
	D3DXPLANE A;
	D3DXPlaneFromPointNormal(&A, e, camDir);
	//to transform plane A into lightSpace calculate transposed inverted lightSpace
	DXMatrix invLightSpaceT;
	D3DXMatrixInverse((D3DXMATRIX*)&invLightSpaceT, NULL, (D3DXMATRIX*)&matLight);
	D3DXMatrixTranspose((D3DXMATRIX*)&invLightSpaceT, (D3DXMATRIX*)&invLightSpaceT);
	//and transform the plane equation with it
	D3DXPlaneTransform(&A, &A, (D3DXMATRIX*)&invLightSpaceT);
	//get the parameters of A from the plane equation n dot d = 0
	const float d = A.d;
	const DXVector3 n((float*)&A);
	//transform to light space
	DXVector3 e_ls;
	D3DXVec3TransformCoord(e_ls, e, (D3DXMATRIX*)&matLight);
	//z_0 has the x coordinate of e, the y coord of B.max() 
	//and the z coord of the plane intersection
	return DXVector3(e_ls.x, (d - n.z * B_lsZmax - n.x * e_ls.x) / n.y, B_lsZmax);
}

void ShadowMapping::Jitter(const int Iteration)
{
	if(m_JitterType == SMJT_RANDOM || m_JitterType == SMJT_HALTON)
	{
		//+/- a half pixel in screen space
		float rx = 2 * (m_Jitter[Iteration*2 + 0] - 0.5f) / m_ShadowMapSize;
		float ry = 2 * (m_Jitter[Iteration*2 + 1] - 0.5f) / m_ShadowMapSize;
		/*float rx = 2 * (frand() - 0.5f) / ShadowMapSize;
		float ry = 2 * (frand() - 0.5f) / ShadowMapSize;*/

		/*if(Iteratrion)
			rx = ry = -0.9/ ShadowMapSize;
		else 
			rx = ry = 0.9/ ShadowMapSize; */

		DXMatrix matJitter; 
		D3DXMatrixTranslation((D3DXMATRIX*)&matJitter, rx, ry, 0);

		mMatSM = mMatLightView * mMatLightProj * matJitter;
	 
		float fOffsetX = 0.5f + (0.5f / m_ShadowMapSize);
		float fOffsetY = 0.5f + (0.5f / m_ShadowMapSize);
		unsigned int range = 1;
		DXMatrix texScaleBiasMat = D3DXMATRIX( 0.5f,     0.0f,     0.0f,         0.0f,
											0.0f,    -0.5f,     0.0f,         0.0f,
											0.0f,     0.0f,     (float)range, 0.0f,
											fOffsetX, fOffsetY, 0.0f,         1.0f );
		mMatSMTex = mMatSM * texScaleBiasMat;

		//would overwrite lightview and lightproj
		//SetLightViewProj(mMatLightView, mMatLightProj * matJitter);
	}
	else if(m_JitterType == SMJT_ROTATION)
	{
		//rotate lightview
		AABB obbLight = mB->BuildAABB();

		DXVector3 half = (obbLight.GetMax() - obbLight.GetMin()) * 0.5f;

		//Camera camLight;
		//camLight.SetViewMatrix(mMatLightView);
		//camLight.SetProjMatrix(mMatLightProj);

		//camLight.RotateOriented(DXVector3(0, 0, m_Jitter[Iteratrion] * D3DX_PI));
		//DXMatrix rotatedLV = camLight.GetViewMatrix(); 

		//DXVector3 half(0.5, 0.5, 0); 
		//DXMatrix rotCenter;
		//D3DXMatrixTranslation((D3DXMATRIX*)&rotCenter, half.x, half.y, 0);
		//DXMatrix invRotCenter;
		//D3DXMatrixTranslation((D3DXMATRIX*)&rotCenter, -half.x, -half.y, 0);
		DXMatrix rotZ;
		//bad halton sequence member are: 0, 4, 8, 12, ... //they are waste
		int ji = Iteration;
		ji += (Iteration / 3) + 1;
		float s = m_Jitter[ji];
		D3DXMatrixRotationZ((D3DXMATRIX*)&rotZ, s * D3DX_PI); 
		//rotZ = rotZ * rotCenter;

		DXMatrix rotatedLV = mMatLightView * mMatLightProj * rotZ;
		//DXMatrix rotatedLV = mMatLightView * rotZ;
		//DXMatrix rotatedLP = mMatLightProj;// * rotZ; 
  
		BoundingMesh B_ls(*mB);
		B_ls.TransformPoints(rotatedLV); 
		AABB obbLightVolume = B_ls.BuildAABB();  
		DXMatrix matFit;
		//by this calculation z only is mapped from 0 to 1
		float dy = obbLightVolume.GetMax().y - obbLightVolume.GetMin().y;
		float dz = obbLightVolume.GetMax().z - obbLightVolume.GetMin().z;
		
		D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&matFit,obbLightVolume.GetMin().x, obbLightVolume.GetMax().x, 
									obbLightVolume.GetMin().y, obbLightVolume.GetMax().y,  
									obbLightVolume.GetMin().z, obbLightVolume.GetMax().z + dz);
	 
		DXMatrix lvProj = mMatLightProj * matFit;  
 
		//mMatLightView = camLight.GetViewMatrix();
		//mMatLightProj = camLight.GetProjMatrix();

		//would overwrite lightview and lightproj
		//SetLightViewProj(rotatedLV, mMatLightProj * matFit);

		mMatSM = rotatedLV * lvProj;
		//mMatSM = rotatedLV * matFit;

		float fOffsetX = 0.5f + (0.5f / m_ShadowMapSize);
		float fOffsetY = 0.5f + (0.5f / m_ShadowMapSize);
		unsigned int range = 1;
		DXMatrix texScaleBiasMat = D3DXMATRIX( 0.5f,     0.0f,     0.0f,         0.0f,
											0.0f,    -0.5f,     0.0f,         0.0f,
											0.0f,     0.0f,     (float)range, 0.0f,
											fOffsetX, fOffsetY, 0.0f,         1.0f );
		mMatSMTex = mMatSM * texScaleBiasMat;
	}
	else if(m_JitterType == SMJT_LISPSMN && mUseLispSM)// && mCosGamma < 0.99)
	{
		float nscale = (m_Jitter[Iteration]+0.5)*8*((Iteration%2)+0.3) + 0.4;
		
		Camera camLight = m_CamLispSM; 
		camLight.SetProjMatrix(camLight.GetProjMatrix() * CalcLispSMMtx(camLight.GetViewMatrix() * camLight.GetProjMatrix(), nscale));
	
		BoundingMesh B_ls(*mB);
		B_ls.TransformPoints(camLight.GetViewMatrix() * camLight.GetProjMatrix());
		AABB obbLightVolume = B_ls.BuildAABB();  
		DXMatrix matFit;
		//by this calculation z only is mapped from 0 to 1
		float dy = obbLightVolume.GetMax().y - obbLightVolume.GetMin().y;
		float dz = obbLightVolume.GetMax().z - obbLightVolume.GetMin().z;
		//y should be -1 to 0  
		//z should be -1 to 1 

		D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&matFit,obbLightVolume.GetMin().x, obbLightVolume.GetMax().x, 
									obbLightVolume.GetMin().y, obbLightVolume.GetMax().y + dy,  
									obbLightVolume.GetMin().z + dz/2, obbLightVolume.GetMax().z);
	 
		camLight.SetProjMatrix(camLight.GetProjMatrix() * matFit);
 
		DXMatrix matSwapBack; 
		D3DXMatrixIdentity((D3DXMATRIX*)&matSwapBack);
		matSwapBack._22 = 0;
		matSwapBack._23 = -1;//z ->-y 
		matSwapBack._32 = 1; //y -> z
		matSwapBack._33 = 0;
		camLight.SetProjMatrix(camLight.GetProjMatrix() * matSwapBack);

		
		//mMatSM = camLight.GetViewMatrix() * camLight.GetProjMatrix();
	 
		//additional halton jittering

		//+/- a half pixel in screen space
		float rx = 2 * (m_Jitter[Iteration*2 + 0] - 0.5f) / m_ShadowMapSize;
		float ry = 2 * (m_Jitter[Iteration*2 + 1] - 0.5f) / m_ShadowMapSize;

		DXMatrix matJitter; 
		D3DXMatrixTranslation((D3DXMATRIX*)&matJitter, rx, ry, 0);

		mMatSM *= matJitter;

		//would overwrite lightview and lightproj
		//SetLightViewProj(camLight.GetViewMatrix(), camLight.GetProjMatrix() * matJitter);

		//

		float fOffsetX = 0.5f + (0.5f / m_ShadowMapSize);
		float fOffsetY = 0.5f + (0.5f / m_ShadowMapSize);
		unsigned int range = 1;
		DXMatrix texScaleBiasMat = D3DXMATRIX( 0.5f,     0.0f,     0.0f,         0.0f,
											0.0f,    -0.5f,     0.0f,         0.0f,
											0.0f,     0.0f,     (float)range, 0.0f,
											fOffsetX, fOffsetY, 0.0f,         1.0f );
		mMatSMTex = mMatSM * texScaleBiasMat;
	}

	m_ParamSMMatrix.UpdateValue(&mMatSM);
}

void ShadowMapping::SetIDBufferEnable(const bool ena)
{ 
	if (ena != m_UseIDBuffer)
	{
		m_UseIDBuffer = ena; 
		SetShadowMapSize(m_ShadowMapSize);
	}
}

void ShadowMapping::SetShadowMapSize(const unsigned size)
{
	if(size < 1)
		return;

	if(size > _min(m_Device->GetCaps()->MaxTextureHeight, m_Device->GetCaps()->MaxTextureWidth))
		return;

	SAFERELEASE(m_ShadowMap);
	SAFERELEASE(m_NVShadowMap);

	if (m_UseNVShadowMap)
	{
		m_NVShadowMap = m_Device->GetTextureManager()->CreateDepthStencilTexture(size, size, FMT_D24X8);

		if (!m_NVShadowMap->GetSurface()->GetSurface())
		{
			SAFERELEASE(m_NVShadowMap);
		}
	}
	
	//have to create rendertarget even with nv shadow maps because dx does not support to render without rendertarget
	m_ShadowMap = m_Device->GetTextureManager()->CreateRenderTexture(size, size, m_UseIDBuffer ? FMT_G32R32F : FMT_R32F);

	if (!m_NVShadowMap) //create ds surface for rendertarget
		m_ShadowMap->CreateDepthStencil(FMT_D24X8);
	
	m_ShadowMapSize = size;

	m_TexParamSM.Surface = m_NVShadowMap ? m_NVShadowMap->GetSurface() : m_ShadowMap->GetSurface();
	m_TexParamID.Surface = m_ShadowMap->GetSurface();
	m_ParamSMSize.UpdateValue(&m_ShadowMapSize);
}

void ShadowMapping::SetJitterType(const SMJITTERTYPE type)
{
	if (type != m_JitterType)
	{
		if(type == SMJT_HALTON || type == SMJT_ROTATION || type == SMJT_LISPSMN)
		{
			const int dim_num = 2;
			int haltonbase[dim_num] = {2 ,3};
			int haltonleap[dim_num] = {1, 1};
			int haltonseed[dim_num] = {0, 0};
			const int n = MAXJITTER;
			int seed2[n];
			int step = 1;
			
			for (int i = 0; i < dim_num; i++ )
			{
				for (int j = 0; j < n; j++ )
				{
					seed2[j] = haltonseed[i] + ( step + j ) * haltonleap[i];
				}

				for (int j = 0; j < n; j++ )
				{
					m_Jitter[i+j*dim_num] = 0;
				}

				for (int j = 0; j < n; j++ )
				{
					float base_inv = 1.0 / ( ( float ) haltonbase[i] );

					while ( seed2[j] != 0 )
					{
						int digit = seed2[j] % haltonbase[i];
						m_Jitter[i+j*dim_num] = m_Jitter[i+j*dim_num] + ( ( float ) digit ) * base_inv;
						base_inv = base_inv / ( ( float ) haltonbase[i] );
						seed2[j] = seed2[j] / haltonbase[i];
					}
				}
			}
		}
		else if(type == SMJT_RANDOM)
		{
			for(int i = 0; i < MAXJITTER*2; i++)
				m_Jitter[i] = frand();
		}
		else
		{
			ZeroMemory(m_Jitter, sizeof(float) * MAXJITTER * 2);
		}
		
		m_JitterType = type;
	}
}