void Raytracer::Sampling(int threadID, int randID) {
	srand(randID);
	Vector3 ray_O = camera->GetO();

	for ( int i = 0 ; i < H ; i++ ) {
		if (!completeRow[i].try_lock()) continue;
		for ( int j = 0 ; j < W ; j++ ) {
			if (camera->GetAperture() < EPS) {
				Vector3 ray_V = camera->Emit( i , j );
				sample[i][j] = 0;
				Color color = camera->GetColor(i, j);
				color += RayTracing(ray_O, ray_V, 1, false, &sample[i][j], i * W + j, Color(1, 1, 1));
				camera->SetColor(i, j, color.Confine());
			} else {
				int dofSample = camera->GetDofSample();
				int iteration = (camera->GetAlgorithm() == "SPPM") ? 1 : dofSample;
				Color color = camera->GetColor(i, j);
				for (int k = 0; k < iteration; k++) {
					Vector3 dof_O, dof_V;
					camera->DofEmit(i, j, &dof_O, &dof_V);
					color += RayTracing(dof_O, dof_V, 1, false, NULL, i * W + j, Color(1, 1, 1) / dofSample) / dofSample;
				}
				camera->SetColor(i, j, color.Confine());
			}

			
			if (j == W - 1) {
				printf("Sampling=%d/%d\n", i, H);
				if (((i & 7) == 0) && (camera->GetAlgorithm() == "PPM" || camera->GetAlgorithm() == "SPPM"))
					printf("Stored hitpoints=%d\n", hitpointMap->GetStoredHitpoints());
			}
		}
	}
	completeThread[threadID] = true;
}
void Raytracer::Resampling(int threadID, int randID) {
	srand(randID);
	Vector3 ray_O = camera->GetO();
	
	for ( int i = 0 ; i < H ; i++ ) {
		if (!completeRow[i].try_lock()) continue;
		for ( int j = 0 ; j < W ; j++ ) {
			if (!((i == 0 || sample[i][j] == sample[i - 1][j])&&(i == H - 1 || sample[i][j] == sample[i + 1][j])&&(j == 0 || sample[i][j] == sample[i][j - 1])&&(j == W - 1 || sample[i][j] == sample[i][j + 1]))) {
				Color color = camera->GetColor(i, j) / 5;
				for ( int r = -1 ; r <= 1 ; r++ )
					for ( int c = -1 ; c <= 1 ; c++ ) {
						if (((r + c) & 1) == 0) continue;
						Vector3 ray_V = camera->Emit( i + ( double ) r / 3 , j + ( double ) c / 3 );
						color += RayTracing(ray_O, ray_V, 1, false, NULL, i * W + j, Color(1, 1, 1) / 5) / 5;
					}
				camera->SetColor( i , j , color.Confine() );
			}

			if (j == W - 1) {
				printf("Resampling=%d/%d\n", i, H);
				if (((i & 7) == 0) && (camera->GetAlgorithm() == "PPM" || camera->GetAlgorithm() == "SPPM"))
					printf("Stored hitpoints=%d\n", hitpointMap->GetStoredHitpoints());
			}
		}
	}
	completeThread[threadID] = true;
}
Color Raytracer::RayTracing( Vector3 ray_O , Vector3 ray_V , int dep , bool refracted , int* hash, int rc, Color weight) {
	if ( dep > MAX_RAYTRACING_DEP ) return Color();
	if ( hash != NULL ) *hash = ( *hash * HASH_FAC ) % HASH_MOD;

	Color ret;
	Collider* collider = scene->FindNearestCollide(ray_O, ray_V);
	LightCollider* lightCollider = scene->FindNearestLight(ray_O, ray_V);
	
	if (lightCollider != NULL) {
		Light* nearest_light = lightCollider->GetLight();
		if (collider == NULL || lightCollider->dist < collider->dist) {
			if ( hash != NULL ) *hash = ( *hash + nearest_light->GetSample() ) % HASH_MOD;
			ret += nearest_light->GetColor() / nearest_light->GetColor().RGBMax();
		}
		delete lightCollider;
	}
	
	if ( collider != NULL ) {
		Primitive* nearest_primitive = collider->GetPrimitive();		
		if ( hash != NULL ) *hash = ( *hash + nearest_primitive->GetSample() ) % HASH_MOD;
		if ( nearest_primitive->GetMaterial()->diff > EPS ) ret += CalnDiffusion( collider , hash, rc, weight);
		if (camera->GetAlgorithm() != "RC") {
			if ( nearest_primitive->GetMaterial()->refl > EPS ) ret += CalnReflection( collider , ray_V , dep , refracted , hash, rc, weight);
			if ( nearest_primitive->GetMaterial()->refr > EPS ) ret += CalnRefraction( collider , ray_V , dep , refracted , hash, rc, weight);
		}
		delete collider;
	}

	if ( dep == 1 ) ret = ret.Confine();
	return ret;
}
void Raytracer::ProgressivePhotonMapping(int SPPMIter) {
	if (camera->GetAlgorithm() != "SPPM")
		GenerateImage("picture_RT.bmp");
	
	int storedHitpoints = hitpointMap->GetStoredHitpoints();
	printf("Stored Hitpoints: %d\n", storedHitpoints);
	printf("HitpointMap Balancing...\n");
	hitpointMap->Balance();
	
	Color** rtColor = new Color*[H];
	for (int i = 0; i < H; i++) {
		rtColor[i] = new Color[W];
		for (int j = 0; j < W; j++)
			rtColor[i][j] = camera->GetColor(i, j);
	}
	
	Photontracer* photontracer = new Photontracer;
	photontracer->SetScene( scene );
	photontracer->SetHitpointMap(hitpointMap);
	for (int iter = 1; iter <= camera->GetIterations(); iter++) {
		photontracer->Run(SPPMIter * camera->GetIterations());
		Hitpoint* hitpoints = hitpointMap->GetHitpoints();
		
		hitpointMap->MaintainHitpoints();
		for (int r = 0; r < H; r++)
			for (int c = 0; c < W; c++)
				camera->SetColor(r, c, rtColor[r][c]);
		
		double minR2 = camera->GetSampleDist(), maxR2 = 0;
		double minNum = 1000000000, maxNum = 0;
		for (int i = 1; i <= storedHitpoints; i++) {
			int r = hitpoints[i].rc / W;
			int c = hitpoints[i].rc % W;
			Color color = camera->GetColor(r, c) + hitpoints[i].color * hitpoints[i].weight * (4.0 / (hitpoints[i].R2 * camera->GetEmitPhotons() * iter));
			camera->SetColor(r, c, color.Confine());
			
			if (hitpoints[i].R2 < minR2) minR2 = hitpoints[i].R2;
			if (hitpoints[i].R2 > maxR2) maxR2 = hitpoints[i].R2;
			if (hitpoints[i].num < minNum) minNum = hitpoints[i].num;
			if (hitpoints[i].num > maxNum) maxNum = hitpoints[i].num;
		}
		printf("Iter=%d, Num=%.2lf~%.2lf, Radius=%.6lf~%.6lf\n", iter, minNum, maxNum, sqrt(minR2), sqrt(maxR2));
		
		if (iter % 10 == 0)
			GenerateImage(output);
	}
	
	if (camera->GetAlgorithm() == "SPPM")
		GenerateImage(output);
	
	delete photontracer;
	for (int i = 0; i < H; i++)
		delete[] rtColor[i];
	delete[] rtColor;
}