// only light sampling..
// left only for reference
inline void EstimateDirectIllumination (
	const Scene * thisScene,
	const Intersection * intersectionInfo,
	const Ray & ray,
	double & light_pdf,
	Spectrum & lightSourceSamplingContribution
)
{
	Objects * obj = intersectionInfo->object;
	BRDFModels * brdf = obj->brdf_model;

	Vector newRayDirection;
	Vector normalDirection;

	normalDirection = intersectionInfo->normal;

	Attenuation attenuationFactor;
	bool delta_brdf_hitEmissive = false;
	bool occludedByObjects = true;

	Spectrum lightIntensity;

	light_pdf = 0; // to be added

	if ( brdf->surfaceFlag == surface_delta )
	{
		return;
	}

	//		Spectrum lightSourceSamplingContribution;
	//		Spectrum brdfSamplingContribution;

	// light source sampling evaluation
	Objects * light;
	light = thisScene->AquireOneOfEmissiveObjects();

	Pnt3D pointOnLight;
	int i = 0;
	while ( i < 2 && occludedByObjects == true )
	{
		pointOnLight = light->samplePointOnObject();
		occludedByObjects = thisScene->Occluded(
			intersectionInfo->intersectionPoint,
			pointOnLight,
			light
		);

		i++;
	}


	if ( occludedByObjects == false )
	{
		newRayDirection = Normalize( pointOnLight - intersectionInfo->intersectionPoint );

		brdf->BRDF(
			ray.direction,
			newRayDirection,
			attenuationFactor
		);

		attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color );

		// light pdf in angular form
		// should be returned for MIS
		light_pdf = light->PDF_in_solid_angle ( pointOnLight, intersectionInfo->intersectionPoint, newRayDirection );

		// not sure !!!
		double pointSamplePdf = light->PDF();

		Ray nextRay( intersectionInfo->intersectionPoint, newRayDirection );

		Vector normal_on_light;
		light->getNormalDirection( pointOnLight, normal_on_light );
		double geometryTerm = GeometricTerm( nextRay, normalDirection, pointOnLight, normal_on_light );

		lightIntensity = light->emission;
		lightSourceSamplingContribution = Attenuate_Light_Spectrum(
			attenuationFactor,
			lightIntensity
		) * geometryTerm / pointSamplePdf;
	}
	else
	{
		if ( DebugMode )
		{
			printf( "Direct illimination can not sample a point on light source" );
		}
	}
}
inline Spectrum EstimateDirectIllumination (
	const Scene * thisScene,
	const Intersection * intersectionInfo,
	const Ray & ray
)
{
	Spectrum intensity;

	Objects * obj = intersectionInfo->object;
	BRDFModels * brdf = obj->brdf_model;

	Vector newRayDirection;
	Vector normalDirection;

	normalDirection = intersectionInfo->normal;

	Attenuation attenuationFactor;
	bool delta_brdf_hitEmissive = false;
	bool occludedByObjects = true;

	Spectrum lightIntensity;

	if ( obj->brdf_model->surfaceFlag == surface_delta )
	{
		// get reflection direction
		// generate new ray
		// intersect with scene to see if the ray hit a light source
		normalDirection = intersectionInfo->normal;

		attenuationFactor = brdf->SampleBRDF(
			ray.direction,
			newRayDirection,
			normalDirection
		);

		Ray newRay( intersectionInfo->intersectionPoint, newRayDirection );

		Intersection newIntersectionInfo;

		if ( !thisScene->IntersectionWithScene( newRay, newIntersectionInfo ) )
			return Spectrum();

		if ( newIntersectionInfo.object->emitter == true )
		{
			delta_brdf_hitEmissive = true;
			lightIntensity = newIntersectionInfo.object->emission;

			attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color );

			intensity = Attenuate_Light_Spectrum(
				attenuationFactor,
				lightIntensity
			);
		}
	}
	else
	{
		Spectrum lightSourceSamplingContribution;
		Spectrum brdfSamplingContribution;

		// light source sampling evaluation
		Objects * light;
		light = thisScene->AquireOneOfEmissiveObjects();


		double light_pdf = 0; // to be added
		double brdf_pdf = 0;
		double light_weight = 0;
		double brdf_weight = 0;

		Pnt3D pointOnLight;
		int i = 0;
		while ( i < 2 && occludedByObjects == true )
		{
			pointOnLight = light->samplePointOnObject();
			occludedByObjects = thisScene->Occluded(
				intersectionInfo->intersectionPoint,
				pointOnLight,
				light
			);

			i++;
		}

		if ( occludedByObjects == false )
		{
			newRayDirection = pointOnLight - intersectionInfo->intersectionPoint;

			brdf->BRDF(
				ray.direction,
				newRayDirection,
				attenuationFactor
			);

			attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color );

			// light pdf 
			light_pdf = light->PDF_in_solid_angle ( pointOnLight, intersectionInfo->intersectionPoint, newRayDirection );

			//	brdf_pdf = obj->brdf_model->PDF ( ray.direction , newRayDirection );

			// geomery term????
			// according to PBRT page 765, geometric term cancel out ???

			Vector normal_on_light;
			light->getNormalDirection( pointOnLight, normal_on_light );
			double geometryTerm = GeometricTerm( ray, normalDirection, pointOnLight, normal_on_light );

			lightIntensity = light->emission;
			lightSourceSamplingContribution =
				Attenuate_Light_Spectrum(
					attenuationFactor,
					lightIntensity
				) * geometryTerm / light_pdf;
		}

		// evaluate BRDF sampling
		if ( light->isDeltaEmitter == false )
		{
			attenuationFactor = brdf->SampleBRDF(
				ray.direction,
				newRayDirection,
				normalDirection
			);

			Ray newRay( intersectionInfo->intersectionPoint, newRayDirection );

			Intersection newIntersectionInfo;

			if ( thisScene->IntersectionWithScene( newRay, newIntersectionInfo ) )
				if ( newIntersectionInfo.object->emitter == true )
				{
					{
						brdf_pdf = obj->brdf_model->PDF( ray.direction, newIntersectionInfo.normal, newRayDirection );
						//	weight = BalanceHeuristic ( 1 , brdf_pdf , 1 , light_pdf );
						attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color );

						double cos_i = AbsDot( ray.direction, normalDirection );

						brdfSamplingContribution += Attenuate_Light_Spectrum(
							attenuationFactor,
							newIntersectionInfo.object->emission
						) * cos_i / brdf_pdf;
					}
				}
		}

		light_weight = light_pdf / ( brdf_pdf + light_pdf );
		brdf_weight = brdf_pdf / ( brdf_pdf + light_pdf );

		intensity += lightSourceSamplingContribution * light_weight;
		intensity += brdfSamplingContribution * brdf_weight;

		if ( intensity.HasNaNs() )
		//	printf ( "has nan" );
			return Spectrum();

		return intensity;
	}
}