MaterialParameters.fromMetadata constructor
Builds parameters from a shader's reflection plus a .fmat sidecar entry.
Offsets and the block size come from shader; types, defaults, and hints
come from metadata. Throws if a parameter named in the metadata is not
present in the compiled shader block (a stale bundle or metadata).
Implementation
factory MaterialParameters.fromMetadata(
gpu.Shader shader,
Map<String, Object?> metadata,
) {
final blockName =
(metadata['uniform_block'] as String?) ?? 'MaterialParams';
final slot = shader.getUniformSlot(blockName);
final sizeInBytes = slot.sizeInBytes ?? 0;
final layout = <String, _ParamSlot>{};
final defaults = <String, Object>{};
for (final raw in (metadata['parameters'] as List?) ?? const []) {
final p = (raw as Map).cast<String, Object?>();
final name = p['name'] as String;
final type = FmatType.fromToken(p['type'] as String);
if (type == null) {
throw StateError('Unknown parameter type "${p['type']}" for "$name".');
}
final offset = slot.getMemberOffsetInBytes(name);
if (offset == null) {
throw StateError(
'Material parameter "$name" is not present in the compiled shader '
'block "$blockName" (stale bundle or metadata).',
);
}
final hint = (p['hint'] as Map?)?.cast<String, Object?>();
layout[name] = _ParamSlot(
type,
offset,
sourceColor: hint?['kind'] == 'source_color',
);
final defaultValue = p['default'];
if (defaultValue != null) defaults[name] = defaultValue;
}
final samplers = <String, _SamplerSlot>{};
for (final raw in (metadata['samplers'] as List?) ?? const []) {
final s = (raw as Map).cast<String, Object?>();
final hint = (s['hint'] as Map?)?.cast<String, Object?>();
samplers[s['name'] as String] = _SamplerSlot(
_hintKind(hint?['kind'] as String?),
);
}
final params = MaterialParameters._(
blockName,
ByteData(sizeInBytes),
layout,
samplers,
);
defaults.forEach(params._applyDefault);
return params;
}