docs: public static Vector3i load(InputStream stream, TFloatList positions, TFloatList normals, TFloatList textureCoords, TIntList indices) {
          int positionSize = -1;
          final TFloatList rawTextureCoords = new TFloatArrayList();
          int textureCoordSize = -1;
          final TFloatList rawNormalComponents = new TFloatArrayList();
          int normalSize = -1;
          final TIntList textureCoordIndices = new TIntArrayList();
          final TIntList normalIndices = new TIntArrayList();
          String line = null;
          try (Scanner scanner = new Scanner(stream)) {
              while (scanner.hasNextLine()) {
                  line = scanner.nextLine();
                  if (line.startsWith(POSITION_LIST_PREFIX + COMPONENT_SEPARATOR)) {
                      parseComponents(positions, line);
                      if (positionSize == -1) {
                          positionSize = positions.size();
                      }
                  } else if (textureCoords != null && line.startsWith(TEXTURE_LIST_PREFIX + COMPONENT_SEPARATOR)) {
                      parseComponents(rawTextureCoords, line);
                      if (textureCoordSize == -1) {
                          textureCoordSize = rawTextureCoords.size();
                      }
                  } else if (normals != null && line.startsWith(NORMAL_LIST_PREFIX + COMPONENT_SEPARATOR)) {
                      parseComponents(rawNormalComponents, line);
                      if (normalSize == -1) {
                          normalSize = rawNormalComponents.size();
                      }
                  } else if (line.startsWith(INDEX_LIST_PREFIX + COMPONENT_SEPARATOR)) {
                      parseIndices(indices, textureCoordIndices, normalIndices, line);
                  }
              }
              line = null;
              final boolean hasTextureCoords;
              final boolean hasNormals;
              if (!textureCoordIndices.isEmpty() && !rawTextureCoords.isEmpty()) {
                  textureCoords.fill(0, positions.size() / positionSize * textureCoordSize, 0);
                  hasTextureCoords = true;
              } else {
                  hasTextureCoords = false;
              }
              if (!normalIndices.isEmpty() && !rawNormalComponents.isEmpty()) {
                  normals.fill(0, positions.size() / positionSize * normalSize, 0);
                  hasNormals = true;
              } else {
                  hasNormals = false;
              }
              if (hasTextureCoords) {
                  for (int i = 0; i < textureCoordIndices.size(); i++) {
                      final int textureCoordIndex = textureCoordIndices.get(i) * textureCoordSize;
                      final int positionIndex = indices.get(i) * textureCoordSize;
                      for (int ii = 0; ii < textureCoordSize; ii++) {
                          textureCoords.set(positionIndex + ii, rawTextureCoords.get(textureCoordIndex + ii));
                      }
                  }
              }
              if (hasNormals) {
                  for (int i = 0; i < normalIndices.size(); i++) {
                      final int normalIndex = normalIndices.get(i) * normalSize;
                      final int positionIndex = indices.get(i) * normalSize;
                      for (int ii = 0; ii < normalSize; ii++) {
                          normals.set(positionIndex + ii, rawNormalComponents.get(normalIndex + ii));
                      }
                  }
              }
          } catch (Exception ex) {
              throw new MalformedObjFileException(line, ex);
          }
          return new Vector3i(positionSize, normalSize, textureCoordSize).max(0, 0, 0);
      }