upload method

Future<GpuModel> upload(
  1. ModelData data
)

Uploads data: buffers now, then each texture it uses, decoded once per image and colour space, with a full mip chain when its sampler mipmaps.

Implementation

Future<GpuModel> upload(ModelData data) async {
  final meshes = [
    for (final mesh in data.meshes)
      [for (final p in mesh.primitives) _primitive(p)],
  ];
  final cache = <(int, bool), Future<GpuTexture?>>{};
  Future<(GpuTexture, GpuSampler)> texture(
    TextureRef? ref,
    GpuTexture fallback, {
    required bool srgb,
  }) async {
    if (ref == null || ref.texture >= data.textures.length) {
      return (fallback, GpuSampler.linearRepeat);
    }
    final tex = data.textures[ref.texture];
    final gpu = await (cache[(ref.texture, srgb)] ??= _texture(
      data,
      tex,
      srgb,
    ));
    return (gpu ?? fallback, _sampler(tex.sampler));
  }

  final materials = <GpuMaterial>[];
  for (final m in data.materials) {
    materials.add(
      GpuMaterial._(m, [
        await texture(m.baseColorTexture, defaults.whiteSrgb, srgb: true),
        await texture(
          m.metallicRoughnessTexture,
          defaults.white,
          srgb: false,
        ),
        await texture(m.normalTexture, defaults.flatNormal, srgb: false),
        await texture(m.occlusionTexture, defaults.white, srgb: false),
        await texture(m.emissiveTexture, defaults.whiteSrgb, srgb: true),
      ]),
    );
  }
  final fallback = GpuMaterial._(MaterialData.fallback, [
    (defaults.whiteSrgb, GpuSampler.linearRepeat),
    (defaults.white, GpuSampler.linearRepeat),
    (defaults.flatNormal, GpuSampler.linearRepeat),
    (defaults.white, GpuSampler.linearRepeat),
    (defaults.whiteSrgb, GpuSampler.linearRepeat),
  ]);
  return GpuModel._(data, meshes, materials, fallback);
}