upload method
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);
}