//Draws a line for each ray that is slightly transparent
void RayTree::setupVBOs() {
	raytree_verts.clear();
	raytree_edge_indices.clear();

	//Sets different colors for each type and the constant for making the lines transparent
	double alpha = .5;
	Vec main_color(.7,.7,.7);
	Vec shadow_color(.1,.9,.1);
	Vec reflected_color(.9,.1,.1);
	Vec single_scatter_color(.1,.1,.9);
	Vec multiple_scatter_color(.9,.1,.9);

	unsigned int i;
	int count = 0;
	for(i = 0;i < main_segments.size();++i){
		raytree_verts.push_back(VBOPosColor4(main_segments[i].getStart(),main_color,alpha));
		raytree_verts.push_back(VBOPosColor4(main_segments[i].getEnd(),main_color,alpha));
		raytree_edge_indices.push_back(VBOIndexedEdge(count,count+1));
		count+=2;
	}
	for(i = 0;i < shadow_segments.size();++i){
		raytree_verts.push_back(VBOPosColor4(shadow_segments[i].getStart(),shadow_color,alpha));
		raytree_verts.push_back(VBOPosColor4(shadow_segments[i].getEnd(),shadow_color,alpha));
		raytree_edge_indices.push_back(VBOIndexedEdge(count,count+1));
		count+=2;
	}
	for(i = 0;i < reflected_segments.size();++i){
		raytree_verts.push_back(VBOPosColor4(reflected_segments[i].getStart(),reflected_color,alpha));
		raytree_verts.push_back(VBOPosColor4(reflected_segments[i].getEnd(),reflected_color,alpha));
		raytree_edge_indices.push_back(VBOIndexedEdge(count,count+1));
		count+=2;
	}
	for(i = 0;i < single_scatter_segments.size();++i){
		raytree_verts.push_back(VBOPosColor4(single_scatter_segments[i].getStart(),single_scatter_color,alpha));
		raytree_verts.push_back(VBOPosColor4(single_scatter_segments[i].getEnd(),single_scatter_color,alpha));
		raytree_edge_indices.push_back(VBOIndexedEdge(count,count+1));
		count+=2;
	}
	for(i = 0;i < multiple_scatter_segments.size();++i){
		raytree_verts.push_back(VBOPosColor4(multiple_scatter_segments[i].getStart(),multiple_scatter_color,alpha));
		raytree_verts.push_back(VBOPosColor4(multiple_scatter_segments[i].getEnd(),multiple_scatter_color,alpha));
		raytree_edge_indices.push_back(VBOIndexedEdge(count,count+1));
		count+=2;
	}

	int ne = raytree_edge_indices.size();

	cleanupVBOs();

	if(ne > 0) {
		glBindBuffer(GL_ARRAY_BUFFER,raytree_verts_VBO);
		glBufferData(GL_ARRAY_BUFFER,sizeof(VBOPosColor4) * ne *2,&raytree_verts[0],GL_STATIC_DRAW);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,raytree_edge_indices_VBO);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(VBOIndexedEdge) * ne,&raytree_edge_indices[0],GL_STATIC_DRAW);
	}
}
void PhotonMapping::setupVBOs() {
  photon_verts.clear();
  photon_direction_indices.clear();
  kdtree_verts.clear();
  kdtree_edge_indices.clear();

  // initialize the data
  int dir_count = 0;
  int edge_count = 0;
  BoundingBox *bb = mesh->getBoundingBox();
  double max_dim = bb->maxDim();

  if (kdtree == NULL) return;
  std::vector<const KDTree*> todo;  
  todo.push_back(kdtree);
  while (!todo.empty()) {
    const KDTree *node = todo.back();
    todo.pop_back(); 
    if (node->isLeaf()) {
      const std::vector<Photon> &photons = node->getPhotons();
      int num_photons = photons.size();
      for (int i = 0; i < num_photons; i++) {
	const Photon &p = photons[i];
	Vec3f energy = p.getEnergy()*args->num_photons_to_shoot;
	const Vec3f &position = p.getPosition();
	Vec3f other = position + p.getDirectionFrom()*0.02*max_dim;
	photon_verts.push_back(VBOPosColor(position,energy));
	photon_verts.push_back(VBOPosColor(other,energy));
	photon_direction_indices.push_back(VBOIndexedEdge(dir_count,dir_count+1)); dir_count+=2;
      }

      // initialize kdtree vbo
      const Vec3f& min = node->getMin();
      const Vec3f& max = node->getMax();
      kdtree_verts.push_back(VBOPos(Vec3f(min.x(),min.y(),min.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(min.x(),min.y(),max.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(min.x(),max.y(),min.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(min.x(),max.y(),max.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(max.x(),min.y(),min.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(max.x(),min.y(),max.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(max.x(),max.y(),min.z())));
      kdtree_verts.push_back(VBOPos(Vec3f(max.x(),max.y(),max.z())));

      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count  ,edge_count+1)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+1,edge_count+3)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+3,edge_count+2)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+2,edge_count  )); 

      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+4,edge_count+5)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+5,edge_count+7)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+7,edge_count+6)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+6,edge_count+4)); 

      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count  ,edge_count+4)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+1,edge_count+5)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+2,edge_count+6)); 
      kdtree_edge_indices.push_back(VBOIndexedEdge(edge_count+3,edge_count+7)); 


      edge_count += 8;

    } else {
      todo.push_back(node->getChild1());
      todo.push_back(node->getChild2());
    } 
  }
  assert (2*photon_direction_indices.size() == photon_verts.size());
  int num_directions = photon_direction_indices.size();
  int num_edges = kdtree_edge_indices.size();

  // cleanup old buffer data (if any)
  cleanupVBOs();

  // copy the data to each VBO
  if (num_directions > 0) {
    glBindBuffer(GL_ARRAY_BUFFER,photon_verts_VBO); 
    glBufferData(GL_ARRAY_BUFFER,
		 sizeof(VBOPosColor) * num_directions * 2,
		 &photon_verts[0],
		 GL_STATIC_DRAW); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,photon_direction_indices_VBO); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
		 sizeof(VBOIndexedEdge) * num_directions,
		 &photon_direction_indices[0], GL_STATIC_DRAW);
  } 

  if (num_edges > 0) {
    glBindBuffer(GL_ARRAY_BUFFER,kdtree_verts_VBO); 
    glBufferData(GL_ARRAY_BUFFER,
		 sizeof(VBOPos) * num_edges * 2,
		 &kdtree_verts[0],
		 GL_STATIC_DRAW); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,kdtree_edge_indices_VBO); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
		 sizeof(VBOIndexedEdge) * num_edges,
		 &kdtree_edge_indices[0], GL_STATIC_DRAW);
  } 
}
//binds data to VBO buffers
void BoundingBox::setupVBOs(){
	HandleGLError("setup VBOs a ");
	VBOPos bb_verts[8];
	VBOIndexedEdge bb_edges[12];

	bb_verts[0] = VBOPos(Vec(minimum.x(),minimum.y(),minimum.z()));
	bb_verts[1] = VBOPos(Vec(minimum.x(),minimum.y(),maximum.z()));
	bb_verts[2] = VBOPos(Vec(minimum.x(),maximum.y(),minimum.z()));
	bb_verts[3] = VBOPos(Vec(minimum.x(),maximum.y(),maximum.z()));
	bb_verts[4] = VBOPos(Vec(maximum.x(),minimum.y(),minimum.z()));
	bb_verts[5] = VBOPos(Vec(maximum.x(),minimum.y(),maximum.z()));
	bb_verts[6] = VBOPos(Vec(maximum.x(),maximum.y(),minimum.z()));
	bb_verts[7] = VBOPos(Vec(maximum.x(),maximum.y(),maximum.z()));

	bb_edges[ 0] = VBOIndexedEdge(0,1);
	bb_edges[ 1] = VBOIndexedEdge(1,3);
	bb_edges[ 2] = VBOIndexedEdge(3,2);
	bb_edges[ 3] = VBOIndexedEdge(2,0);
	bb_edges[ 4] = VBOIndexedEdge(0,4);
	bb_edges[ 5] = VBOIndexedEdge(1,5);
	bb_edges[ 6] = VBOIndexedEdge(2,6);
	bb_edges[ 7] = VBOIndexedEdge(3,7);
	bb_edges[ 8] = VBOIndexedEdge(4,5);
	bb_edges[ 9] = VBOIndexedEdge(5,7);
	bb_edges[10] = VBOIndexedEdge(7,6);
	bb_edges[11] = VBOIndexedEdge(6,4);

	HandleGLError("setup VBOs b ");
	glBindBuffer(GL_ARRAY_BUFFER,bb_verts_VBO);
	HandleGLError("setup VBOs c ");
	glBufferData(GL_ARRAY_BUFFER,sizeof(VBOPos)*8,bb_verts,GL_STATIC_DRAW);
	HandleGLError("setup VBOs d ");
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,bb_edge_indices_VBO);
	HandleGLError("setup VBOs e ");
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(VBOIndexedEdge)*12,bb_edges,GL_STATIC_DRAW);
	HandleGLError("setup VBOs bf ");
}