materialLanguageCompiler function

CpuStage materialLanguageCompiler(
  1. String stage,
  2. String source
)

A CpuMaterialCompiler for the engine's material language — P8: the source parsed and specialised at its declared defaults, as the build does for the GPU sections beside it, and run by MaterialProgramStage.

Handed to CpuDevice(materialCompiler: ...), a bundle the build made from a .f3dmat loads on the software backend with nothing registered by hand. A source that does not parse is refused with its line and column.

Every stage a source becomes — version 2. A bundle carries the source under each stage's name: the material's own, answered by MaterialProgramStage or, for a full-screen stage, MaterialFullscreenStage; and <name>Vertex and <name>VertexSkinned, answered by MaterialVertexStage, which the library hands out as a vertex stage.

Implementation

CpuStage materialLanguageCompiler(String stage, String source) {
  final program = parseMaterial(source);
  final specialised = specializeMaterial(
    program,
    MaterialVariant(program.name),
  );
  final vertex = program.vertexStageName;
  if (vertex != null && stage == vertex) {
    return CpuStage.vertex(MaterialVertexStage(specialised));
  }
  if (vertex != null && stage == '${vertex}Skinned') {
    return CpuStage.vertex(MaterialVertexStage(specialised, skinned: true));
  }
  // Version 3: the instanced and lightmapped halves.
  for (final MapEntry(key: variant, value: name) in materialVertexVariantStages(
    program,
  ).entries) {
    if (stage == name) {
      return CpuStage.vertex(
        MaterialVertexStage(
          specialised,
          instanced: variant == VertexStageVariant.instanced,
          lightmapped: variant == VertexStageVariant.lightmapped,
        ),
      );
    }
  }
  if (program.name != stage) {
    throw MaterialBundleException(
      'the source is material "${program.name}" and the bundle calls it '
      '"$stage"',
    );
  }
  return switch (program.kind) {
    MaterialStageKind.fullscreen => CpuStage.fragment(
      MaterialFullscreenStage(specialised),
    ),
    MaterialStageKind.compute => throw MaterialBundleException(
      '"$stage" is a compute stage, which a bundle carries as its lowered '
      'kernel in the kernel section, not as a material: build it again, or '
      'load lowerMaterialCompute(program).kernel through kernelBundle',
    ),
    _ => CpuStage.fragment(MaterialProgramStage(specialised)),
  };
}