def read_off(file_path):
    """
    Read .off file.
    :param file_path:
    :return: vertices, faces, vertex_colors
    """

    def skip_empty_lines(file):
        cursor = file.tell()
        line = file.readline()
        while line:
            line = line.strip()
            if not line.startswith('#') and line != '':
                break

            cursor = file.tell()
            line = file.readline()

        file.seek(cursor)

    with open(file_path, 'r') as fp:
        header = fp.readline().strip()
        if header != 'OFF' and header != 'COFF':
            raise ValueError('Not a valid OFF header')

        has_color = header == 'COFF'

        skip_empty_lines(fp)
        
        # get number of elements
        n_vertices = 0
        n_faces = 0
        n_edges = 0
        has_sizes = False
        while not has_sizes:
            line = fp.readline()
            if not line:
                break
            else:
                line = line.strip()

            if not has_sizes:
                n_vertices, n_faces, n_edges = tuple([int(s) for s in line.strip().split(' ')])
                has_sizes = True

        if not has_sizes:
            raise ValueError('Element count not found')

        skip_empty_lines(fp)

        # get vertices and faces
        vertices = [[float(s.strip()) for s in fp.readline().strip().split(' ')
                     if s.strip() != ''] for i_vert in range(n_vertices)]
        faces = [[int(s.strip()) for s in fp.readline().strip().split(' ')
                  if s.strip() != ''][1:] for i_face in range(n_faces)]

        vertices = np.asarray(vertices).astype(np.float32)
        faces = np.asarray(faces)

        if has_color:
            vertex_colors = vertices[:, [3, 4, 5]]
            vertices = vertices[:, [0, 1, 2]]
        else:
            vertex_colors = None

    return vertices, faces, vertex_colors

    Read .off file.
    :param file_path:
    :return: vertices, faces, vertex_colors
    
source/base/mesh_io.py