private void readSurfaces(String filepath) {
    // System.out.println("\nBuilding surfaces...");
    // This method is the last to be called out of all of the methods in this class.  Once all
    // of the vertex information has been read in, as well as the materials, they are arranged
    // into the surfaces and polygons that form that object itself...See the included file
    // CustomOBJSpecs.txt for more details

    int curMat = 0; // this is a reference to the current material to be used
    // int curIndex = 0;			//This is a temporary variable for reading in vertices of polygons
    SurfCell curSurf; // the current surface being worked with
    // PolyCell curPoly;			//the current polygon in the surface
    String matName; // This is the material name from the obj file.  It will be used to find the
    // material in the list
    String line; // the current line being analyzed
    StringTokenizer token; // For tokenizing the string to grab the different components of the line
    // StringTokenizer vertTokens;	//For tokenizing the vertex entries in a polygon (surface) line
    FileReader fr; // Just a file reading stream for the file
    BufferedReader objFile; // this wraps around the file reader so we can do things like readLine()
    boolean inSmooth = false; // a flag for whether or not a given face is in a surface

    try {
      fr = new FileReader(filepath);
      objFile = new BufferedReader(fr);
      line = objFile.readLine();
      curSurf = surfHead;
      while (line != null) {
        if (line.length() > 0) {
          switch (line.charAt(0)) {
            case '#':
            case '!':
            case '$':
            case '\n':
            case 'v': // These are all comments or vertex info...skip them :-)
              break;
            case 'u':
              token = new StringTokenizer(line);
              line = token.nextToken(); // "eat" up the usemtl keyword
              matName = token.nextToken(); // actually grab the material name
              boolean found = false;
              int i = 0;
              while (!found && i < numMats)
              // for(int i = 0; i < numMats; i++)
              {
                // simply compare the stored material name to the name retrieved from the OBJ file.
                // if they match, set curMat to whatever index that material is at
                if (materials[i].materialName.toUpperCase().compareTo(matName.toUpperCase()) == 0) {
                  curMat = i; // Set curMat to the current material index
                  found = true;
                }
                i++;
              }
              if (!found) {
                System.out.printf(
                    "Group %s material %s not found - using default\n", curSurf.name, matName);
                curSurf.material = 0;
              } else curSurf.material = curMat;
              break;
            case 's':
              token = new StringTokenizer(line);
              line = token.nextToken(); // "eat" up the s at the beginning of the line
              // If there are more tokens on the line (specifically, the word "off")
              // then we will read them in.  The only one that we really care about is if it's
              // an "off" but it must be read if it's there.
              if (token.hasMoreTokens()) line = token.nextToken();
              // if smooth groups are turned off and no new smooth group is specified...
              if (line.toUpperCase().compareTo("OFF") == 0) {
                inSmooth = false;
              } else // We are simply starting a new smooth group
              {
                inSmooth = true;
                // curSurf.smooth = inSmooth;
              } // end else
              break;
            case 'f':
              if (curSurf != null) {
                addPolyToSurf(curSurf, line, inSmooth);
              } else // no active surface - create a "default" surface and add this poly to it
              {
                System.out.printf("ReadSurfaces: No active surface available\n");
                System.out.printf("Creating a default surface\n");
                if (inSmooth) surfHead = new SurfCell("default");
                else surfHead = new SurfCell("default");
                curSurf = surfHead;
                addPolyToSurf(curSurf, line, inSmooth);
              }
              curSurf.numPoly++; // Surface level count of the polygons
              numPolys++; // PMesh level count of the polygons
              break;

            case 'g': // Starts a new surface - if inSmooth is true set the smooth flag in
              // that surface
              token = new StringTokenizer(line);
              line = token.nextToken(); // "eat" up the g at the beginning of the line
              // If there are more tokens on the line (specifically a group name)
              // then we will read it in.
              if (token.hasMoreTokens()) line = token.nextToken();
              if (line == null) line = new String("Group" + numSurf);
              if (surfHead == null) // Create first surface
              {
                surfHead = new SurfCell(line);
                curSurf = surfHead;
              } else // Advance to next surface
              {
                curSurf.next = new SurfCell(line);
                curSurf = curSurf.next;
              }
              // Assign beginning variables
              numSurf++; // PMesh level count of surfaces							break;
            default:
              break;
          } // end switch
        } // end if(line.length() > 0)
        line = objFile.readLine(); // grab the next line for reading
      } // end while(line != null)
      objFile.close();
      fr.close();
    } // end try
    catch (IOException exception) {
      System.out.println("Error while reading surface data from: " + filepath);
    } // end catch
    System.out.printf("\n %d vertices  %d surfaces\n", numVerts, numSurf);
    // System.out.println("\n" + numSurf + " surfaces found");
  } // end method readSurfaces