Browse Source

LDrawLoader: 2 bugs and 7 improvements (#24257)

* LDrawLoader: 2 bugs and 7 improvements

* Fix typo

* Don't clone missing pink material. LUMINANCE token single quotes

* Small variable optimization

* Make missing material generic

* Make missing material generic, fix

* Add missing line which sets userData.fileName

* Fix returned edge material in getMainEdgeMaterial()

* Just added a small check to getMainEdgeMaterial()
Juan Jose Luna Espinosa 3 years ago
parent
commit
5c6990ea33
1 changed files with 136 additions and 74 deletions
  1. 136 74
      examples/jsm/loaders/LDrawLoader.js

+ 136 - 74
examples/jsm/loaders/LDrawLoader.js

@@ -28,10 +28,10 @@ const FINISH_TYPE_METAL = 5;
 
 // State machine to search a subobject path.
 // The LDraw standard establishes these various possible subfolders.
-const FILE_LOCATION_AS_IS = 0;
-const FILE_LOCATION_TRY_PARTS = 1;
-const FILE_LOCATION_TRY_P = 2;
-const FILE_LOCATION_TRY_MODELS = 3;
+const FILE_LOCATION_TRY_PARTS = 0;
+const FILE_LOCATION_TRY_P = 1;
+const FILE_LOCATION_TRY_MODELS = 2;
+const FILE_LOCATION_AS_IS = 3;
 const FILE_LOCATION_TRY_RELATIVE = 4;
 const FILE_LOCATION_TRY_ABSOLUTE = 5;
 const FILE_LOCATION_NOT_FOUND = 6;
@@ -688,7 +688,9 @@ class LDrawParsedCache {
 		result.type = original.type;
 		result.category = original.category;
 		result.keywords = original.keywords;
+		result.author = original.author;
 		result.subobjects = original.subobjects;
+		result.fileName = original.fileName;
 		result.totalFaces = original.totalFaces;
 		result.startingConstructionStep = original.startingConstructionStep;
 		result.materials = original.materials;
@@ -700,7 +702,7 @@ class LDrawParsedCache {
 	async fetchData( fileName ) {
 
 		let triedLowerCase = false;
-		let locationState = FILE_LOCATION_AS_IS;
+		let locationState = FILE_LOCATION_TRY_PARTS;
 		while ( locationState !== FILE_LOCATION_NOT_FOUND ) {
 
 			let subobjectURL = fileName;
@@ -743,7 +745,7 @@ class LDrawParsedCache {
 						fileName = fileName.toLowerCase();
 						subobjectURL = fileName;
 						triedLowerCase = true;
-						locationState = FILE_LOCATION_AS_IS;
+						locationState = FILE_LOCATION_TRY_PARTS;
 
 					}
 
@@ -794,6 +796,7 @@ class LDrawParsedCache {
 		let type = 'Model';
 		let category = null;
 		let keywords = null;
+		let author = null;
 		let totalFaces = 0;
 
 		// split into lines
@@ -995,6 +998,12 @@ class LDrawParsedCache {
 
 								break;
 
+							case 'Author:':
+
+								author = lp.getToken();
+
+								break;
+
 							default:
 								// Other meta directives are not implemented
 								break;
@@ -1221,6 +1230,7 @@ class LDrawParsedCache {
 			type,
 			category,
 			keywords,
+			author,
 			subobjects,
 			totalFaces,
 			startingConstructionStep,
@@ -1356,6 +1366,9 @@ class LDrawPartsGeometryCache {
 			const group = new Group();
 			group.userData.category = info.category;
 			group.userData.keywords = info.keywords;
+			group.userData.author = info.author;
+			group.userData.type = info.type;
+			group.userData.fileName = info.fileName;
 			info.group = group;
 
 			const subobjectInfos = await Promise.all( promises );
@@ -1380,6 +1393,7 @@ class LDrawPartsGeometryCache {
 					subobjectGroup.name = subobject.fileName;
 
 					loader.applyMaterialsToMesh( subobjectGroup, subobject.colorCode, info.materials );
+					subobjectGroup.userData.colorCode = subobject.colorCode;
 
 					group.add( subobjectGroup );
 					continue;
@@ -1473,6 +1487,7 @@ class LDrawPartsGeometryCache {
 			if ( subobject ) {
 
 				loader.applyMaterialsToMesh( group, subobject.colorCode, info.materials );
+				group.userData.colorCode = subobject.colorCode;
 
 			}
 
@@ -1883,6 +1898,16 @@ class LDrawLoader extends Loader {
 		// The path to load parts from the LDraw parts library from.
 		this.partsLibraryPath = '';
 
+		// Material assigned to not available colors for meshes and edges
+		this.missingColorMaterial = new MeshStandardMaterial( { color: 0xFF00FF, roughness: 0.3, metalness: 0 } );
+		this.missingColorMaterial.name = 'Missing material';
+		this.missingEdgeColorMaterial = new LineBasicMaterial( { color: 0xFF00FF } );
+		this.missingEdgeColorMaterial.name = 'Missing material - Edge';
+		this.missingConditionalEdgeColorMaterial = new LDrawConditionalLineMaterial( { fog: true, color: 0xFF00FF } );
+		this.missingConditionalEdgeColorMaterial.name = 'Missing material - Conditional Edge';
+		this.missingColorMaterial.userData.edgeMaterial = this.missingEdgeColorMaterial;
+		this.missingEdgeColorMaterial.userData.conditionalEdgeMaterial = this.missingConditionalEdgeColorMaterial;
+
 	}
 
 	setPartsLibraryPath( path ) {
@@ -1934,6 +1959,7 @@ class LDrawLoader extends Loader {
 
 					this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
 					this.computeConstructionSteps( group );
+					group.userData.fileName = url;
 					onLoad( group );
 
 				} )
@@ -1949,7 +1975,9 @@ class LDrawLoader extends Loader {
 			.parseModel( text, this.materialLibrary )
 			.then( group => {
 
+				this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
 				this.computeConstructionSteps( group );
+				group.userData.fileName = '';
 				onLoad( group );
 
 			} );
@@ -2080,8 +2108,11 @@ class LDrawLoader extends Loader {
 				material = loader.getMaterial( colorCode );
 				if ( material === null ) {
 
-					// otherwise throw an error if this is final opportunity to set the material
-					throw new Error( `LDrawLoader: Material properties for code ${ colorCode } not available.` );
+					// otherwise throw a warning if this is final opportunity to set the material
+					console.warn( `LDrawLoader: Material properties for code ${ colorCode } not available.` );
+
+					// And return the 'missing color' material
+					material = loader.missingColorMaterial;
 
 				}
 
@@ -2118,8 +2149,8 @@ class LDrawLoader extends Loader {
 
 	getMainEdgeMaterial() {
 
-		const mainMat = this.getMainMaterial();
-		return mainMat && mainMat.userData ? mainMat.userData.edgeMaterial : null;
+		const mat = this.getMaterial( MAIN_EDGE_COLOUR_CODE );
+		return mat ? mat.userData.edgeMaterial : null;
 
 	}
 
@@ -2162,113 +2193,113 @@ class LDrawLoader extends Loader {
 
 			}
 
-			switch ( token.toUpperCase() ) {
+			if ( ! parseLuminance( token ) ) {
 
-				case 'CODE':
+				switch ( token.toUpperCase() ) {
 
-					code = lineParser.getToken();
-					break;
+					case 'CODE':
 
-				case 'VALUE':
+						code = lineParser.getToken();
+						break;
 
-					color = lineParser.getToken();
-					if ( color.startsWith( '0x' ) ) {
+					case 'VALUE':
 
-						color = '#' + color.substring( 2 );
+						color = lineParser.getToken();
+						if ( color.startsWith( '0x' ) ) {
 
-					} else if ( ! color.startsWith( '#' ) ) {
+							color = '#' + color.substring( 2 );
 
-						throw new Error( 'LDrawLoader: Invalid color while parsing material' + lineParser.getLineNumberString() + '.' );
+						} else if ( ! color.startsWith( '#' ) ) {
 
-					}
+							throw new Error( 'LDrawLoader: Invalid color while parsing material' + lineParser.getLineNumberString() + '.' );
 
-					break;
+						}
 
-				case 'EDGE':
+						break;
 
-					edgeColor = lineParser.getToken();
-					if ( edgeColor.startsWith( '0x' ) ) {
+					case 'EDGE':
 
-						edgeColor = '#' + edgeColor.substring( 2 );
+						edgeColor = lineParser.getToken();
+						if ( edgeColor.startsWith( '0x' ) ) {
 
-					} else if ( ! edgeColor.startsWith( '#' ) ) {
+							edgeColor = '#' + edgeColor.substring( 2 );
 
-						// Try to see if edge color is a color code
-						edgeMaterial = this.getMaterial( edgeColor );
-						if ( ! edgeMaterial ) {
+						} else if ( ! edgeColor.startsWith( '#' ) ) {
 
-							throw new Error( 'LDrawLoader: Invalid edge color while parsing material' + lineParser.getLineNumberString() + '.' );
+							// Try to see if edge color is a color code
+							edgeMaterial = this.getMaterial( edgeColor );
+							if ( ! edgeMaterial ) {
 
-						}
+								throw new Error( 'LDrawLoader: Invalid edge color while parsing material' + lineParser.getLineNumberString() + '.' );
 
-						// Get the edge material for this triangle material
-						edgeMaterial = edgeMaterial.userData.edgeMaterial;
+							}
 
-					}
+							// Get the edge material for this triangle material
+							edgeMaterial = edgeMaterial.userData.edgeMaterial;
 
-					break;
+						}
 
-				case 'ALPHA':
+						break;
 
-					alpha = parseInt( lineParser.getToken() );
+					case 'ALPHA':
 
-					if ( isNaN( alpha ) ) {
+						alpha = parseInt( lineParser.getToken() );
 
-						throw new Error( 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + '.' );
+						if ( isNaN( alpha ) ) {
 
-					}
+							throw new Error( 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + '.' );
 
-					alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
+						}
 
-					if ( alpha < 1 ) {
+						alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
 
-						isTransparent = true;
+						if ( alpha < 1 ) {
 
-					}
+							isTransparent = true;
 
-					break;
+						}
 
-				case 'LUMINANCE':
+						break;
 
-					luminance = parseInt( lineParser.getToken() );
+					case 'LUMINANCE':
 
-					if ( isNaN( luminance ) ) {
+						if ( ! parseLuminance( lineParser.getToken() ) ) {
 
-						throw new Error( 'LDrawLoader: Invalid luminance value in material definition' + LineParser.getLineNumberString() + '.' );
+							throw new Error( 'LDrawLoader: Invalid luminance value in material definition' + LineParser.getLineNumberString() + '.' );
 
-					}
+						}
 
-					luminance = Math.max( 0, Math.min( 1, luminance / 255 ) );
+						break;
 
-					break;
+					case 'CHROME':
+						finishType = FINISH_TYPE_CHROME;
+						break;
 
-				case 'CHROME':
-					finishType = FINISH_TYPE_CHROME;
-					break;
+					case 'PEARLESCENT':
+						finishType = FINISH_TYPE_PEARLESCENT;
+						break;
 
-				case 'PEARLESCENT':
-					finishType = FINISH_TYPE_PEARLESCENT;
-					break;
+					case 'RUBBER':
+						finishType = FINISH_TYPE_RUBBER;
+						break;
 
-				case 'RUBBER':
-					finishType = FINISH_TYPE_RUBBER;
-					break;
+					case 'MATTE_METALLIC':
+						finishType = FINISH_TYPE_MATTE_METALLIC;
+						break;
 
-				case 'MATTE_METALLIC':
-					finishType = FINISH_TYPE_MATTE_METALLIC;
-					break;
+					case 'METAL':
+						finishType = FINISH_TYPE_METAL;
+						break;
 
-				case 'METAL':
-					finishType = FINISH_TYPE_METAL;
-					break;
+					case 'MATERIAL':
+						// Not implemented
+						lineParser.setToEnd();
+						break;
 
-				case 'MATERIAL':
-					// Not implemented
-					lineParser.setToEnd();
-					break;
+					default:
+						throw new Error( 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + '.' );
 
-				default:
-					throw new Error( 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + '.' );
+				}
 
 			}
 
@@ -2358,6 +2389,8 @@ class LDrawLoader extends Loader {
 
 			} );
 			edgeMaterial.userData.conditionalEdgeMaterial.color.convertSRGBToLinear();
+			edgeMaterial.userData.conditionalEdgeMaterial.userData.code = code;
+			edgeMaterial.userData.conditionalEdgeMaterial.name = name + ' - Conditional Edge';
 
 		}
 
@@ -2370,6 +2403,35 @@ class LDrawLoader extends Loader {
 
 		return material;
 
+		function parseLuminance( token ) {
+
+			// Returns success
+
+			let lum;
+
+			if ( token.startsWith( 'LUMINANCE' ) ) {
+
+				lum = parseInt( token.substring( 9 ) );
+
+			}
+			else {
+
+				lum = parseInt( token );
+
+			}
+
+			if ( isNaN( lum ) ) {
+
+				return false;
+
+			}
+
+			luminance = Math.max( 0, Math.min( 1, lum / 255 ) );
+
+			return true;
+
+		}
+
 	}
 
 	computeConstructionSteps( model ) {