loadShaders function
Reads flutter3d_shaders out of the nearest package config.
Throws StateError with a message worth showing a person when the package
is not there or has no shaders/ in it.
Implementation
ShaderSet loadShaders({String? from}) {
final root = packageRoot('flutter3d_shaders', from: from);
final shaders = Directory('$root/shaders');
if (!shaders.existsSync()) throw StateError('no shaders/ in $root');
final sources = <String, String>{};
for (final file in shaders.listSync(recursive: true).whereType<File>()) {
final path = file.path;
if (!path.endsWith('.glsl') &&
!path.endsWith('.frag') &&
!path.endsWith('.vert')) {
continue;
}
sources[path.substring(shaders.path.length + 1)] = file.readAsStringSync();
}
// The same manifest impellerc reads and the WebGL generator reads. One list
// of entry points for every backend, so a shader added for one cannot be
// quietly missing from another — the engine asks for a name and all of them
// must answer to it.
final manifestFile = File('${shaders.path}/flutter3d.shaderbundle.json');
if (!manifestFile.existsSync()) {
throw StateError('no manifest at ${manifestFile.path}');
}
final manifest =
jsonDecode(manifestFile.readAsStringSync()) as Map<String, dynamic>;
final stages = <String, ({String file, bool fragment})>{};
manifest.forEach((name, spec) {
final entry = spec as Map<String, dynamic>;
final file = (entry['file'] as String).replaceFirst('shaders/', '');
if (!sources.containsKey(file)) {
throw StateError('$name names $file, which is not in shaders/');
}
stages[name] = (file: file, fragment: entry['type'] == 'fragment');
});
return (root: shaders.path, sources: sources, stages: stages);
}