int main( int argc, char** argv )
{
  const int numFixedArguments = 3;
  if( argc < numFixedArguments )
  {
    std::cout << "Merges several obj meshes into one. This routine uses the \"objMesh\" class to load the meshes. It can also merge materials." << std::endl;
    std::cout << "Usage: " << argv[0] << " [list of obj files] [output file] [-m]" << std::endl;
    std::cout << "  -m : also output materials" << std::endl;
    std::cout << "  -d : (if -m) also remove duplicate materials" << std::endl;
    return 1;
  }

  bool outputMaterials = false; 
  bool removeDuplicatedMaterials = false; 
  char * objListFilename = argv[1];
  char * objMeshname = argv[2];

  opt_t opttable[] =
  {
    { (char*)"m", OPTBOOL, &outputMaterials },
    { (char*)"d", OPTBOOL, &removeDuplicatedMaterials },
    { NULL, 0, NULL }
  };
  
  argv += numFixedArguments-1;
  argc -= numFixedArguments-1;
  int optup = getopts(argc,argv,opttable);
  if (optup != argc)
  {
    printf("Error parsing options. Error at option %s.\n",argv[optup]);
    return 1;
  }

  ObjMesh outputObjMesh;

  char s[4096];
  FILE * fin;
  char fileMode[96] = "r";
  OpenFile_(objListFilename, &fin, fileMode);

  while(fgets(s,4096,fin) != 0)
  {
    if(s[strlen(s)-1] == '\n')
      s[strlen(s)-1] = '\0';

    printf("%s\n",s);

    ObjMesh * objMesh = new ObjMesh(s);

    // add vertices
    int numVerticesCurrent = outputObjMesh.getNumVertices();
    for(unsigned int i=0; i<objMesh->getNumVertices(); i++)
      outputObjMesh.addVertexPosition(objMesh->getPosition(i));

    // add normals
    int numNormalsCurrent = outputObjMesh.getNumNormals();
    for(unsigned int i=0; i<objMesh->getNumNormals(); i++)
      outputObjMesh.addVertexNormal(objMesh->getNormal(i));
   
    // add texture coordinates
    int numTextureCoordinatesCurrent = outputObjMesh.getNumTextureCoordinates();
    for(unsigned int i=0; i<objMesh->getNumTextureCoordinates(); i++)
      outputObjMesh.addTextureCoordinate(objMesh->getTextureCoordinate(i));

    // add materials
    int numMaterialsCurrent = outputObjMesh.getNumMaterials();
    for(unsigned int i=0; i<objMesh->getNumMaterials(); i++)
      outputObjMesh.addMaterial(objMesh->getMaterial(i));

    for(unsigned int i=0; i<objMesh->getNumGroups(); i++)
    {
      const ObjMesh::Group * group = objMesh->getGroupHandle(i);
      outputObjMesh.addGroup(group->getName());
      unsigned int newGroupID = outputObjMesh.getNumGroups() - 1;
      ObjMesh::Group * newGroup = (ObjMesh::Group*) outputObjMesh.getGroupHandle(newGroupID);
      newGroup->setMaterialIndex(numMaterialsCurrent + group->getMaterialIndex());

      // over all faces in the group of the current obj file
      for(unsigned int j=0; j<group->getNumFaces(); j++)
      {
        const ObjMesh::Face * face = group->getFaceHandle(j);
        for(unsigned int k=0; k<face->getNumVertices(); k++)
        {
          ObjMesh::Vertex * vertex = (ObjMesh::Vertex*) face->getVertexHandle(k);
          vertex->setPositionIndex(vertex->getPositionIndex() + numVerticesCurrent);
          if (vertex->hasNormalIndex())
            vertex->setNormalIndex(vertex->getNormalIndex() + numNormalsCurrent);
          if (vertex->hasTextureCoordinateIndex())
            vertex->setTextureCoordinateIndex(vertex->getTextureCoordinateIndex() + numTextureCoordinatesCurrent);
        }
        outputObjMesh.addFaceToGroup(*face,newGroupID);
      }
    }

    delete(objMesh);
  }
  
  fclose(fin);

  if (outputMaterials)
  {
    if (removeDuplicatedMaterials)
    {
      printf("Removing duplicated materials..."); fflush(NULL);
      int numNewMaterials = outputObjMesh.removeDuplicatedMaterials();
      printf(" retained %d materials.\n", numNewMaterials);
    }
    outputObjMesh.save(objMeshname, 1);
  }
  else
  {
    outputObjMesh.save(objMeshname);
  }

  return(0);
}
int main(int argc, char ** argv)
{
  if (argc < 4)
  {
    printf("Generates an interpolant between a given volumetric mesh and a surface obj mesh.\n");
    printf("Usage: %s <volumetric mesh file> <target obj file> <output interpolant file> [-s volumetric mesh element list output filename] [-z threshold] [-S] [-T]\n",argv[0]);
    printf("-s : output list of (1-indexed) volumetric mesh elements that contain at least one obj mesh vertex\n");
    printf("-z : assign zero interpolation to vertices too far away from the volumetric mesh\n");
    return 0;
  }

  char * meshFile = argv[1];
  char * objMeshname = argv[2];
  char * outputFilename = argv[3];

  char outputElementFilename[4096] = "__none";
  char zeroThresholdString[4096] = "__none";

  opt_t opttable[] =
  {
    { (char*)"s", OPTSTR, &outputElementFilename },
    { (char*)"z", OPTSTR, &zeroThresholdString },
    { NULL, 0, NULL }
  };

  argv += 3;
  argc -= 3;
  int optup = getopts(argc,argv,opttable);
  if (optup != argc)
  {
    printf("Error parsing options. Error at option %s.\n",argv[optup]);
    return 1;
  }

  double threshold;
  if (strcmp(zeroThresholdString,"__none") == 0)
    threshold = -1;
  else
    threshold = strtod(zeroThresholdString, NULL);

  VolumetricMesh * volumetricMesh = VolumetricMeshLoader::load(meshFile);
  
  if (volumetricMesh == NULL)
  {
    printf("Error: unable to load the volumetric mesh from %s.\n", meshFile);
    exit(1);
  }
 
  int n = volumetricMesh->getNumVertices();
  int nel = volumetricMesh->getNumElements();
  printf("Info on %s:\n", meshFile);
  printf("Num vertices: %d\n", n);
  printf("Num elements: %d\n", nel);

  ObjMesh * objMesh = new ObjMesh(objMeshname);

  int numInterpolationLocations = objMesh->getNumVertices();
  double * interpolationLocations = (double*) malloc (sizeof(double) * 3 * numInterpolationLocations);
  for(int i=0; i< numInterpolationLocations; i++)
  {
    Vec3d pos = objMesh->getPosition(i);
    interpolationLocations[3*i+0] = pos[0];
    interpolationLocations[3*i+1] = pos[1];
    interpolationLocations[3*i+2] = pos[2];
  }

  int * vertices;
  double * weights;

  int * elementList;
  int ** elementListp = NULL;
  if (strcmp(outputElementFilename, "__none") != 0)
  {
    elementListp = &elementList;    
  }

  int verbose = 1;
  int numExternalVertices;
  numExternalVertices = volumetricMesh->generateInterpolationWeights(numInterpolationLocations, interpolationLocations, &vertices, &weights, threshold, elementListp, verbose);

  printf("Saving weights to %s...\n", outputFilename); fflush(NULL);
  volumetricMesh->saveInterpolationWeights(outputFilename, numInterpolationLocations, volumetricMesh->getNumElementVertices(), vertices, weights);

  if (strcmp(outputElementFilename, "__none") != 0)
  {
    set<int> uniqueElementSet;
    for(unsigned int i=0; i<numInterpolationLocations; i++)
      uniqueElementSet.insert(elementList[i]);

    vector<int> uniqueElementList;
    for(set<int>::iterator iter = uniqueElementSet.begin(); iter != uniqueElementSet.end(); iter++)
      uniqueElementList.push_back(*iter);

    LoadList saveList;
    sort(uniqueElementList.begin(), uniqueElementList.end());
    int oneIndexed = 1;
    saveList.save(outputElementFilename, uniqueElementList.size(), &uniqueElementList[0], oneIndexed);
  }
  printf("\n");

  return 0;
}