bool FilterMutualInfoPlugin::UpdateGraph(MeshDocument &md, SubGraph graph, int n)
{
	Solver solver;
	MutualInfo mutual;
	
	align.mesh=&md.mm()->cm;

	vcg::Point3f *vertices = new vcg::Point3f[align.mesh->vn];
	vcg::Point3f *normals = new vcg::Point3f[align.mesh->vn];
	vcg::Color4b *colors = new vcg::Color4b[align.mesh->vn];
	unsigned int *indices = new unsigned int[align.mesh->fn*3];

	for(int i = 0; i < align.mesh->vn; i++) {
	vertices[i] = align.mesh->vert[i].P();
	normals[i] = align.mesh->vert[i].N();
	colors[i] = align.mesh->vert[i].C();
	}

	for(int i = 0; i < align.mesh->fn; i++) 
	for(int k = 0; k < 3; k++) 
	indices[k+i*3] = align.mesh->face[i].V(k) - &*align.mesh->vert.begin();

	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.vbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
	  vertices, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.nbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
	  normals, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.cbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Color4b), 
	  colors, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.ibo);
	glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.mesh->fn*3*sizeof(unsigned int), 
	  indices, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);


	// it is safe to delete after copying data to VBO
	delete []vertices;
	delete []normals;
	delete []colors;
	delete []indices;
	
	for (int h=0; h<graph.nodes.size(); h++)
		for (int l=0; l<graph.nodes[h].arcs.size(); l++)
		{
			if(graph.nodes[h].arcs[l].imageId==n || graph.nodes[h].arcs[l].projId==n)
			{
//////////////////
				int imageId=graph.nodes[h].arcs[l].imageId;
				int imageProj=graph.nodes[h].arcs[l].projId;

				//this->glContext->makeCurrent();
				
				align.image=&md.rasterList[imageId]->currentPlane->image;
				align.shot=md.rasterList[imageId]->shot;

				//this->initGL();
				align.resize(800);

				

				//align.shot=par.getShotf("Shot");

				align.shot.Intrinsics.ViewportPx[0]=int((double)align.shot.Intrinsics.ViewportPx[1]*align.image->width()/align.image->height());
				align.shot.Intrinsics.CenterPx[0]=(int)(align.shot.Intrinsics.ViewportPx[0]/2);

				/*align.mode=AlignSet::COMBINE;
				align.renderScene(align.shot, 3, true);
				align.comb=align.rend;*/

				align.mode=AlignSet::PROJIMG;
				align.shotPro=md.rasterList[imageProj]->shot;
				align.imagePro=&md.rasterList[imageProj]->currentPlane->image;
				align.ProjectedImageChanged(*align.imagePro);
				float countTot=0.0;
				float countCol=0.0;
				align.RenderShadowMap();
				align.renderScene(align.shot, 1, true);
				//align.readRender(1);
				/*for (int x=0; x<align.wt; x++)
					for (int y=0; y<align.ht; y++)
					{
						QColor color;
						color.setRgb(align.comb.pixel(x,y));
						if (color!=qRgb(0,0,0))
						{
							countTot++;
							if (align.comb.pixel(x,y)!=align.rend.pixel(x,y))
								countCol++;
						}
					}
				graph.nodes[h].arcs[l].area=countCol/countTot;*/
				graph.nodes[h].arcs[l].mutual=mutual.info(align.wt,align.ht,align.target,align.render);
					
					
				//this->glContext->doneCurrent();

//////////////////////////77

			}
		}


	return true;

}
std::vector<AlignPair> FilterMutualInfoPlugin::CalcPairs(MeshDocument &md, bool globalign)
{
	Solver solver;
	MutualInfo mutual;
	
	std::vector<AlignPair> list;

	align.mesh=&md.mm()->cm;
	
	/*solver.optimize_focal=true;
	solver.fine_alignment=true;*/

	{
		vcg::Point3f *vertices = new vcg::Point3f[align.mesh->vn];
		vcg::Point3f *normals = new vcg::Point3f[align.mesh->vn];
		vcg::Color4b *colors = new vcg::Color4b[align.mesh->vn];
		unsigned int *indices = new unsigned int[align.mesh->fn*3];

		for(int i = 0; i < align.mesh->vn; i++) {
			vertices[i] = align.mesh->vert[i].P();
			normals[i] = align.mesh->vert[i].N();
			colors[i] = align.mesh->vert[i].C();
		}

		for(int i = 0; i < align.mesh->fn; i++) 
		for(int k = 0; k < 3; k++) 
		indices[k+i*3] = align.mesh->face[i].V(k) - &*align.mesh->vert.begin();

		glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.vbo);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
				  vertices, GL_STATIC_DRAW_ARB);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.nbo);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
				  normals, GL_STATIC_DRAW_ARB);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.cbo);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Color4b), 
				  colors, GL_STATIC_DRAW_ARB);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.ibo);
		glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.mesh->fn*3*sizeof(unsigned int), 
				  indices, GL_STATIC_DRAW_ARB);
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

		// it is safe to delete after copying data to VBO
		delete []vertices;
		delete []normals;
		delete []colors;
		delete []indices;
	}

	//align.mode=AlignSet::PROJIMG;
		
	//this->glContext->makeCurrent();
	for (int r=0; r<md.rasterList.size(); r++)
	{
		if(md.rasterList[r]->visible)
		{
			AlignPair pair;
			align.image=&md.rasterList[r]->currentPlane->image;
			align.shot=md.rasterList[r]->shot;

			//this->initGL();
			align.resize(800);

			//align.shot=par.getShotf("Shot");

			align.shot.Intrinsics.ViewportPx[0]=int((double)align.shot.Intrinsics.ViewportPx[1]*align.image->width()/align.image->height());
			align.shot.Intrinsics.CenterPx[0]=(int)(align.shot.Intrinsics.ViewportPx[0]/2);

			align.mode=AlignSet::COMBINE;
			align.renderScene(align.shot, 3, true);
			align.comb=align.rend;
			QImage covered=align.comb;
			std::vector<AlignPair> weightList;

			for (int p=0; p<md.rasterList.size(); p++)
			{
				if (p!=r)
				{
					align.mode=AlignSet::PROJIMG;
					align.shotPro=md.rasterList[p]->shot;
					align.imagePro=&md.rasterList[p]->currentPlane->image;
					align.ProjectedImageChanged(*align.imagePro);
					float countTot=0.0;
					float countCol=0.0;
					float countCov=0.0;
					align.RenderShadowMap();
					align.renderScene(align.shot, 2, true);
					//align.readRender(1);
					for (int x=0; x<align.wt; x++)
						for (int y=0; y<align.ht; y++)
						{
							QColor color;
							color.setRgb(align.comb.pixel(x,y));
							if (color!=qRgb(0,0,0))
							{
								countTot++;
								if (align.comb.pixel(x,y)!=align.rend.pixel(x,y))
								{
									countCol++;
								}
							}
						}
						pair.area=countCol/countTot;
											
						if (pair.area>0.2)
						{
							pair.mutual=mutual.info(align.wt,align.ht,align.target,align.render);
							pair.imageId=r;
							pair.projId=p;
							pair.weight=pair.area*pair.mutual;
							weightList.push_back(pair);

						}
				}
			}

			Log(0, "Image %d completed",r);
			if (!globalign)
			{
				for (int i=0; i<weightList.size(); i++)
				{
					Log(0, "Area %3.2f, Mutual %3.2f",weightList[i].area,weightList[i].mutual);
					list.push_back(weightList[i]);

				}

				//Log(0, "Tot arcs %d, Valid arcs %d",(md.rasterList.size())*(md.rasterList.size()-1),list.size());
				//return list;

			}
			else
			{


				std::sort(weightList.begin(), weightList.end(), orderingW());

				///////////////////////////////////////7
				for (int i=0; i<weightList.size(); i++)
				{
					int p=weightList[i].projId;
					align.mode=AlignSet::PROJIMG;
					align.shotPro=md.rasterList[p]->shot;
					align.imagePro=&md.rasterList[p]->currentPlane->image;
					align.ProjectedImageChanged(*align.imagePro);
					float countTot=0.0;
					float countCol=0.0;
					float countCov=0.0;
					align.RenderShadowMap();
					align.renderScene(align.shot, 2, true);
					//align.readRender(1);
					for (int x=0; x<align.wt; x++)
						for (int y=0; y<align.ht; y++)
						{
							QColor color;
							color.setRgb(align.comb.pixel(x,y));
							if (color!=qRgb(0,0,0))
							{
								countTot++;
								if (align.comb.pixel(x,y)!=align.rend.pixel(x,y))
								{
									if (covered.pixel(x,y)!=qRgb(255,0,0))
									{
										countCov++;
										covered.setPixel(x,y,qRgb(255,0,0));
									}
									countCol++;
								}
							}
						}
						pair.area=countCol/countTot;
						/*covered.save("covered.jpg");
						align.rend.save("rend.jpg");
						align.comb.save("comb.jpg");*/
						
						pair.area*=countCov/countTot;
						pair.mutual=mutual.info(align.wt,align.ht,align.target,align.render);
						pair.imageId=r;
						pair.projId=p;
						pair.weight=weightList[i].weight;
						list.push_back(pair);
						Log(0, "Area %3.2f, Mutual %3.2f",pair.area,pair.mutual);
					}
			}
			
		}
		}
//////////////////////////////////////////////////////

	

	Log(0, "Tot arcs %d, Valid arcs %d",(md.rasterList.size())*(md.rasterList.size()-1),list.size());
		
	
		//emit md.rasterSetChanged();
	//this->glContext->doneCurrent();
	return list;

}
bool FilterMutualInfoPlugin::AlignNode(MeshDocument &md, Node node)
{
	Solver solver;
	MutualInfo mutual;

	align.mode=AlignSet::NODE;
	align.node=&node;

	align.image=&md.rasterList[node.id]->currentPlane->image;
	align.shot=md.rasterList[node.id]->shot;

	align.mesh=&md.mm()->cm;

	for (int l=0; l<node.arcs.size(); l++)
	{
		align.arcImages.push_back(&md.rasterList[node.arcs[l].projId]->currentPlane->image);
		align.arcShots.push_back(&md.rasterList[node.arcs[l].projId]->shot);
		align.arcMI.push_back(node.arcs[l].mutual);

	}

	if(align.arcImages.size()==0)
		return true;
	else if(align.arcImages.size()==1)
	{
		align.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image);
		align.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot);
		align.arcMI.push_back(node.arcs[0].mutual);
		align.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image);
		align.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot);
		align.arcMI.push_back(node.arcs[0].mutual);
	}
	else if(align.arcImages.size()==2)
	{
		align.arcImages.push_back(&md.rasterList[node.arcs[0].projId]->currentPlane->image);
		align.arcShots.push_back(&md.rasterList[node.arcs[0].projId]->shot);
		align.arcMI.push_back(node.arcs[0].mutual);
	}

	align.ProjectedMultiImageChanged();
	
	/*solver.optimize_focal=true;
	solver.fine_alignment=true;*/

	//this->glContext->makeCurrent();
	/*this->initGL();*/
	align.resize(800);

	vcg::Point3f *vertices = new vcg::Point3f[align.mesh->vn];
	vcg::Point3f *normals = new vcg::Point3f[align.mesh->vn];
	vcg::Color4b *colors = new vcg::Color4b[align.mesh->vn];
	unsigned int *indices = new unsigned int[align.mesh->fn*3];

	for(int i = 0; i < align.mesh->vn; i++) {
	vertices[i] = align.mesh->vert[i].P();
	normals[i] = align.mesh->vert[i].N();
	colors[i] = align.mesh->vert[i].C();
	}

	for(int i = 0; i < align.mesh->fn; i++) 
	for(int k = 0; k < 3; k++) 
	indices[k+i*3] = align.mesh->face[i].V(k) - &*align.mesh->vert.begin();

	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.vbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
			  vertices, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.nbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
			  normals, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.cbo);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Color4b), 
			  colors, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.ibo);
	glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.mesh->fn*3*sizeof(unsigned int), 
			  indices, GL_STATIC_DRAW_ARB);
	glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);


	// it is safe to delete after copying data to VBO
	delete []vertices;
	delete []normals;
	delete []colors;
	delete []indices;
	
    //align.shot=par.getShotf("Shot");
		
	align.shot.Intrinsics.ViewportPx[0]=int((double)align.shot.Intrinsics.ViewportPx[1]*align.image->width()/align.image->height());
	align.shot.Intrinsics.CenterPx[0]=(int)(align.shot.Intrinsics.ViewportPx[0]/2);
	
	int iter;
	if (solver.fine_alignment)
		iter=solver.optimize(&align, &mutual, align.shot);
	else
		solver.iterative(&align, &mutual, align.shot);
	//align.renderScene(align.shot, 3);
	//align.readRender(0);
		
	
	//md.rasterList[node.id]->shot=align.shot;
	md.rasterList[node.id]->shot=align.shot;
	float ratio=(float)md.rasterList[node.id]->currentPlane->image.height()/(float)align.shot.Intrinsics.ViewportPx[1];
	md.rasterList[node.id]->shot.Intrinsics.ViewportPx[0]=md.rasterList[node.id]->currentPlane->image.width();
	md.rasterList[node.id]->shot.Intrinsics.ViewportPx[1]=md.rasterList[node.id]->currentPlane->image.height();
	md.rasterList[node.id]->shot.Intrinsics.PixelSizeMm[1]/=ratio;
	md.rasterList[node.id]->shot.Intrinsics.PixelSizeMm[0]/=ratio;
	md.rasterList[node.id]->shot.Intrinsics.CenterPx[0]=(int)((float)md.rasterList[node.id]->shot.Intrinsics.ViewportPx[0]/2.0);
	md.rasterList[node.id]->shot.Intrinsics.CenterPx[1]=(int)((float)md.rasterList[node.id]->shot.Intrinsics.ViewportPx[1]/2.0);
	//this->glContext->doneCurrent();
	//emit md.rasterSetChanged();
	for (int l=0; l<align.arcImages.size(); l++)
	{
		align.arcImages.pop_back();
		align.arcMI.pop_back();
		align.arcShots.pop_back();
		align.arcImages.clear();
		align.arcMI.clear();
		align.arcShots.clear();
		align.prjMats.clear();
	}

	return true;
}
bool FilterMutualInfoPlugin::preAlignment(MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb)
{
	Solver solver;
	MutualInfo mutual;
	if (md.rasterList.size()==0)
	{
		 Log(0, "You need a Raster Model to apply this filter!");
		 return false;
	}
	else {

	align.mesh=&md.mm()->cm;
	
	solver.optimize_focal=par.getBool("Estimate Focal");
	solver.fine_alignment=par.getBool("Fine");

	int rendmode= par.getEnum("RenderingMode");
			
			switch(rendmode){ 
				case 0: 
					align.mode=AlignSet::COMBINE;
					break;
				case 1: 
					align.mode=AlignSet::NORMALMAP;
					break;
				case 2: 
					align.mode=AlignSet::COLOR;
					break;
				case 3: 
					align.mode=AlignSet::SPECULAR;
					break;
				case 4: 
					align.mode=AlignSet::SILHOUETTE;
					break;
				case 5: 
					align.mode=AlignSet::SPECAMB;
					break;
				default:
					align.mode=AlignSet::COMBINE;
					break;
			}

	vcg::Point3f *vertices = new vcg::Point3f[align.mesh->vn];
  vcg::Point3f *normals = new vcg::Point3f[align.mesh->vn];
  vcg::Color4b *colors = new vcg::Color4b[align.mesh->vn];
  unsigned int *indices = new unsigned int[align.mesh->fn*3];

  for(int i = 0; i < align.mesh->vn; i++) {
    vertices[i] = align.mesh->vert[i].P();
    normals[i] = align.mesh->vert[i].N();
    colors[i] = align.mesh->vert[i].C();
  }

  for(int i = 0; i < align.mesh->fn; i++) 
    for(int k = 0; k < 3; k++) 
      indices[k+i*3] = align.mesh->face[i].V(k) - &*align.mesh->vert.begin();

  glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.vbo);
  glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
                  vertices, GL_STATIC_DRAW_ARB);
  glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.nbo);
  glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), 
                  normals, GL_STATIC_DRAW_ARB);
  glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.cbo);
  glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Color4b), 
                  colors, GL_STATIC_DRAW_ARB);
  glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

  glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.ibo);
  glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.mesh->fn*3*sizeof(unsigned int), 
                  indices, GL_STATIC_DRAW_ARB);
  glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);


  // it is safe to delete after copying data to VBO
  delete []vertices;
  delete []normals;
  delete []colors;
  delete []indices;

	for (int r=0; r<md.rasterList.size();r++)
	{
		if(md.rasterList[r]->visible)
		{
				align.image=&md.rasterList[r]->currentPlane->image;
				align.shot=md.rasterList[r]->shot;
				
				align.resize(800);

				align.shot.Intrinsics.ViewportPx[0]=int((double)align.shot.Intrinsics.ViewportPx[1]*align.image->width()/align.image->height());
				align.shot.Intrinsics.CenterPx[0]=(int)(align.shot.Intrinsics.ViewportPx[0]/2);

				if (solver.fine_alignment)
				solver.optimize(&align, &mutual, align.shot);
				else
				{
				solver.iterative(&align, &mutual, align.shot);
				Log(0, "Vado di rough",r);
				}
				
				md.rasterList[r]->shot=align.shot;
				float ratio=(float)md.rasterList[r]->currentPlane->image.height()/(float)align.shot.Intrinsics.ViewportPx[1];
				md.rasterList[r]->shot.Intrinsics.ViewportPx[0]=md.rasterList[r]->currentPlane->image.width();
				md.rasterList[r]->shot.Intrinsics.ViewportPx[1]=md.rasterList[r]->currentPlane->image.height();
				md.rasterList[r]->shot.Intrinsics.PixelSizeMm[1]/=ratio;
				md.rasterList[r]->shot.Intrinsics.PixelSizeMm[0]/=ratio;
				md.rasterList[r]->shot.Intrinsics.CenterPx[0]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[0]/2.0);
				md.rasterList[r]->shot.Intrinsics.CenterPx[1]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[1]/2.0);

				Log(0, "Image %d completed",r);
				
		}
		else
			Log(0, "Image %d skipped",r);
		}
	}
	
	return true;
}