updateFromMetadata method
Re-reads parameter declarations from a regenerated shader and metadata
(a hot-reloaded .fmat), preserving values the caller explicitly set.
For a parameter present before and after with the same type: an
explicitly-set value is kept; otherwise the new default is taken, so
editing a default in the .fmat takes effect live. New parameters take
their new default; removed parameters are dropped. Sampler bindings are
preserved by name. A parameter declared in metadata but absent from the
compiled block (a transient bundle/metadata mismatch mid-reload) is
skipped rather than throwing.
Implementation
void updateFromMetadata(gpu.Shader shader, Map<String, Object?> metadata) {
final newBlockName =
(metadata['uniform_block'] as String?) ?? 'MaterialParams';
final slot = shader.getUniformSlot(newBlockName);
final newLayout = <String, _ParamSlot>{};
final newDefaults = <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) continue;
final offset = slot.getMemberOffsetInBytes(name);
if (offset == null) continue;
final hint = (p['hint'] as Map?)?.cast<String, Object?>();
newLayout[name] = _ParamSlot(
type,
offset,
sourceColor: hint?['kind'] == 'source_color',
);
final defaultValue = p['default'];
if (defaultValue != null) newDefaults[name] = defaultValue;
}
final newSamplerHints = <String, FmatHintKind?>{};
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?>();
newSamplerHints[s['name'] as String] = _hintKind(
hint?['kind'] as String?,
);
}
_applyRefresh(
newBlockName,
slot.sizeInBytes ?? 0,
newLayout,
newDefaults,
newSamplerHints,
);
}