|
@@ -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 ) {
|