parseMtl function
Parses a .mtl library.
Exposed separately because it is a self-contained text format, which makes it testable without constructing an OBJ file around it.
warnings hears the directives this reader does not know, once each,
exactly as ObjLoader.load does for the .obj half. Without it the two
halves disagreed about the same promise: a file missing its texture file
got a sentence, and a file whose .mtl carried a map_Bump — a normal
map, the commonest thing in a .mtl this does not read — loaded flat and
said nothing.
Implementation
Map<String, MtlMaterial> parseMtl(String text, {List<String>? warnings}) {
final result = <String, MtlMaterial>{};
final unknownDirectives = <String>{};
String? name;
Vector3? diffuse;
Vector3? specular;
double? exponent;
var opacity = 1.0;
String? diffuseTexture;
void flush() {
final current = name;
if (current == null) return;
result[current] = MtlMaterial(
name: current,
diffuse: diffuse,
specular: specular,
specularExponent: exponent,
opacity: opacity,
diffuseTexturePath: diffuseTexture,
);
}
for (final rawLine in _logicalLines(text)) {
final line = rawLine.trim();
if (line.isEmpty || line.startsWith('#')) continue;
final tokens = line.split(RegExp(r'\s+'));
final keyword = tokens.first;
final args = tokens.sublist(1);
switch (keyword) {
case 'newmtl':
flush();
name = args.isEmpty ? '' : args.join(' ');
diffuse = null;
specular = null;
exponent = null;
opacity = 1.0;
diffuseTexture = null;
case 'Kd':
diffuse = _toVector3(args);
case 'Ks':
specular = _toVector3(args);
case 'Ns':
if (args.isNotEmpty) exponent = _toDouble(args[0]);
case 'd':
if (args.isNotEmpty) opacity = _toDouble(args[0]);
case 'Tr':
// Transparency is the complement of opacity, and files use one or the
// other.
if (args.isNotEmpty) opacity = 1.0 - _toDouble(args[0]);
case 'map_Kd':
// Options such as `-s 1 1 1` may precede the filename; the path is the
// last token that is not an option value.
if (args.isNotEmpty) diffuseTexture = args.last;
default:
unknownDirectives.add(keyword);
}
}
flush();
if (unknownDirectives.isNotEmpty) {
warnings?.add(
'Ignored unsupported material directives: '
'${unknownDirectives.join(', ')}.',
);
}
return result;
}