loadShaders function

ShaderSet loadShaders({
  1. String? from,
})

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