loadModelData function

Future<ModelData> loadModelData(
  1. Uint8List bytes, {
  2. required String name,
  3. ModelFetch? fetch,
})

Reads a glTF model — .glb or .gltf — into ModelData.

External buffers and images are fetched with fetch first; the heavy part (reading accessors, building vertices) then runs in a background isolate. Throws UnsupportedError for a file this renderer can't show (Draco, meshopt, KTX2) and FormatException for a malformed one.

Implementation

Future<ModelData> loadModelData(
  Uint8List bytes, {
  required String name,
  ModelFetch? fetch,
}) async {
  final Map<String, dynamic> json;
  ByteData? binary;
  if (isGlb(bytes)) {
    final parts = parseGlb(bytes);
    json = parts.json;
    binary = parts.binary;
  } else {
    json = jsonDecode(utf8.decode(bytes)) as Map<String, dynamic>;
  }

  final uris = <String, Uint8List>{};
  for (final uri in externalUris(json)) {
    if (fetch == null) {
      throw StateError('$name refers to "$uri", and no fetch was given.');
    }
    uris[uri] = await fetch(Uri.decodeFull(uri));
  }

  final buffers = <ByteData>[];
  for (final buffer
      in (json['buffers'] as List<dynamic>? ?? const [])
          .cast<Map<String, dynamic>>()) {
    final uri = buffer['uri'] as String?;
    if (uri == null) {
      buffers.add(
        binary ?? (throw FormatException('$name: a buffer has no data.')),
      );
    } else if (uri.startsWith('data:')) {
      buffers.add(ByteData.sublistView(decodeDataUri(uri)));
    } else {
      buffers.add(ByteData.sublistView(uris[uri]!));
    }
  }

  return compute(_build, _Job(json, GltfSources(buffers, uris), name));
}