parseShaderUniforms function

ShaderUniformBindings parseShaderUniforms(
  1. String shaderSource, {
  2. Map<String, dynamic>? propertiesJson,
})

Parses all uniform declarations from a GLSL shader source string.

This parser supports two inputs:

  • Flutter compiled shader payload metadata (sksl.uniforms).
  • Plain GLSL source text with uniform declarations.

Returns explicit index bindings for float and sampler uniforms.

Throws FormatException if shader source is invalid.

Implementation

ShaderUniformBindings parseShaderUniforms(
  String shaderSource, {
  Map<String, dynamic>? propertiesJson,
}) {
  if (shaderSource.isEmpty) {
    throw FormatException('Shader source cannot be empty');
  }

  final compiledBindings = _parseCompiledShaderUniforms(shaderSource);
  if (compiledBindings != null) {
    debugPrint(
        'parseShaderUniforms.compiled.bindings: ${compiledBindings.toNamesByType()}');
    return compiledBindings;
  }

  final uniformRegex = RegExp(
    r'uniform\s+(\w+)\s+(\w+)(\s*\[\s*\d*\s*\])?\s*;',
    multiLine: true,
  );

  final matches = uniformRegex.allMatches(shaderSource);
  final floatBindings = <UniformBinding>[];
  final samplerBindings = <UniformBinding>[];

  final propertyIndices = _parsePropertyIndices(propertiesJson);
  var fallbackFloatIndex = 0;
  var fallbackSamplerIndex = 0;

  for (final match in matches) {
    final type = match.group(1)!;
    final name = match.group(2)!;

    if (type == SupportedUniformTypes.float) {
      final index = propertyIndices.floatIndices[name] ?? fallbackFloatIndex;
      floatBindings.add(UniformBinding(name: name, index: index));
      if (!propertyIndices.floatIndices.containsKey(name)) {
        fallbackFloatIndex++;
      }
      continue;
    }

    if (type == SupportedUniformTypes.sampler2D ||
        type == SupportedUniformTypes.flutterSampler2D) {
      final index =
          propertyIndices.samplerIndices[name] ?? fallbackSamplerIndex;
      samplerBindings.add(UniformBinding(name: name, index: index));
      if (!propertyIndices.samplerIndices.containsKey(name)) {
        fallbackSamplerIndex++;
      }
    }
  }

  final bindings = ShaderUniformBindings(
    floatBindings: floatBindings,
    sampler2DBindings: samplerBindings,
  );
  debugPrint('parseShaderUniforms.bindings: ${bindings.toNamesByType()}');
  return bindings;
}