Browse Source

Merge pull request #16245 from gkjohnson/ldraw-fixes

LDrawLoader: Fix stack overflow exceptions
Mr.doob 6 years ago
parent
commit
e8d421904d
1 changed files with 48 additions and 76 deletions
  1. 48 76
      examples/js/loaders/LDrawLoader.js

+ 48 - 76
examples/js/loaders/LDrawLoader.js

@@ -271,18 +271,6 @@ THREE.LDrawLoader = ( function () {
 
 			}, onProgress, onError );
 
-			function subobjectLoad( url, onLoad, onProgress, onError, subobject ) {
-
-				var fileLoader = new THREE.FileLoader( scope.manager );
-				fileLoader.setPath( scope.path );
-				fileLoader.load( url, function ( text ) {
-
-					processObject( text, onLoad, subobject );
-
-				}, onProgress, onError );
-
-			}
-
 			function processObject( text, onProcessed, subobject ) {
 
 				var parseScope = scope.newParseScopeLevel();
@@ -292,6 +280,12 @@ THREE.LDrawLoader = ( function () {
 
 				// Add to cache
 				var currentFileName = parentParseScope.currentFileName;
+				if ( currentFileName !== null ) {
+
+					currentFileName = parentParseScope.currentFileName.toLowerCase();
+
+				}
+
 				if ( scope.subobjectCache[ currentFileName ] === undefined ) {
 
 					scope.subobjectCache[ currentFileName ] = text;
@@ -308,37 +302,39 @@ THREE.LDrawLoader = ( function () {
 				parseScope.numSubobjects = parseScope.subobjects.length;
 				parseScope.subobjectIndex = 0;
 
-				if ( parseScope.numSubobjects > 0 ) {
+				var finishedCount = 0;
+				onSubobjectFinish();
 
-					// Load the first subobject
-					var subobjectGroup = loadSubobject( parseScope.subobjects[ 0 ], true );
+				return objGroup;
 
-					// Optimization for loading pack: If subobjects are obtained from cache, keep loading them iteratively rather than recursively
-					if ( subobjectGroup ) {
+				function onSubobjectFinish() {
 
-						while ( subobjectGroup && parseScope.subobjectIndex < parseScope.numSubobjects - 1 ) {
+					finishedCount ++;
 
-							subobjectGroup = loadSubobject( parseScope.subobjects[ ++ parseScope.subobjectIndex ], true );
+					if ( finishedCount === parseScope.subobjects.length + 1 ) {
 
-						}
-
-						if ( subobjectGroup ) {
+						finalizeObject();
 
-							finalizeObject();
+					} else {
 
-						}
+						// Once the previous subobject has finished we can start processing the next one in the list.
+						// The subobject processing shares scope in processing so it's important that they be loaded serially
+						// to avoid race conditions.
+						// Promise.resolve is used as an approach to asynchronously schedule a task _before_ this frame ends to
+						// avoid stack overflow exceptions when loading many subobjects from the cache. RequestAnimationFrame
+						// will work but causes the load to happen after the next frame which causes the load to take significantly longer.
+						var subobject = parseScope.subobjects[ parseScope.subobjectIndex ];
+						Promise.resolve().then( function () {
 
-					}
+							loadSubobject( subobject );
 
-				} else {
+						} );
+						parseScope.subobjectIndex ++;
 
-					// No subobjects, finish object
-					finalizeObject();
+					}
 
 				}
 
-				return objGroup;
-
 				function finalizeObject() {
 
 					if ( ! scope.separateObjects && ! parentParseScope.isFromParse ) {
@@ -368,7 +364,7 @@ THREE.LDrawLoader = ( function () {
 
 				}
 
-				function loadSubobject( subobject, sync ) {
+				function loadSubobject( subobject ) {
 
 					parseScope.mainColourCode = subobject.material.userData.code;
 					parseScope.mainEdgeColourCode = subobject.material.userData.edgeMaterial.userData.code;
@@ -382,16 +378,15 @@ THREE.LDrawLoader = ( function () {
 					}
 
 					// If subobject was cached previously, use the cached one
-					var cached = scope.subobjectCache[ subobject.originalFileName ];
+					var cached = scope.subobjectCache[ subobject.originalFileName.toLowerCase() ];
 					if ( cached ) {
 
-						var subobjectGroup = processObject( cached, sync ? undefined : onSubobjectLoaded, subobject );
-						if ( sync ) {
+						processObject( cached, function ( subobjectGroup ) {
 
-							addSubobject( subobject, subobjectGroup );
-							return subobjectGroup;
+							onSubobjectLoaded( subobjectGroup, subobject );
+							onSubobjectFinish();
 
-						}
+						}, subobject );
 
 						return;
 
@@ -451,22 +446,6 @@ THREE.LDrawLoader = ( function () {
 							// All location possibilities have been tried, give up loading this object
 							console.warn( 'LDrawLoader: Subobject "' + subobject.originalFileName + '" could not be found.' );
 
-							// Try to read the next subobject
-							parseScope.subobjectIndex ++;
-
-							if ( parseScope.subobjectIndex >= parseScope.numSubobjects ) {
-
-								// All subojects have been loaded. Finish parent object
-								scope.removeScopeLevel();
-								onProcessed( objGroup );
-
-							} else {
-
-								// Load next subobject
-								loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
-
-							}
-
 							return;
 
 					}
@@ -481,15 +460,22 @@ THREE.LDrawLoader = ( function () {
 					fileLoader.setPath( scope.path );
 					fileLoader.load( subobjectURL, function ( text ) {
 
-						processObject( text, onSubobjectLoaded, subobject );
+						processObject( text, function ( subobjectGroup ) {
 
-					}, undefined, onSubobjectError );
+							onSubobjectLoaded( subobjectGroup, subobject );
+							onSubobjectFinish();
 
-				}
+						}, subobject );
+
+					}, undefined, function ( err ) {
+
+						onSubobjectError( err, subobject );
+
+					}, subobject );
 
-				function onSubobjectLoaded( subobjectGroup ) {
+				}
 
-					var subobject = parseScope.subobjects[ parseScope.subobjectIndex ];
+				function onSubobjectLoaded( subobjectGroup, subobject ) {
 
 					if ( subobjectGroup === null ) {
 
@@ -502,20 +488,6 @@ THREE.LDrawLoader = ( function () {
 					// Add the subobject just loaded
 					addSubobject( subobject, subobjectGroup );
 
-					// Proceed to load the next subobject, or finish the parent object
-
-					parseScope.subobjectIndex ++;
-
-					if ( parseScope.subobjectIndex < parseScope.numSubobjects ) {
-
-						loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
-
-					} else {
-
-						finalizeObject();
-
-					}
-
 				}
 
 				function addSubobject( subobject, subobjectGroup ) {
@@ -533,10 +505,10 @@ THREE.LDrawLoader = ( function () {
 
 				}
 
-				function onSubobjectError( err ) {
+				function onSubobjectError( err, subobject ) {
 
 					// Retry download from a different default possible location
-					loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
+					loadSubobject( subobject );
 
 				}
 
@@ -1071,7 +1043,7 @@ THREE.LDrawLoader = ( function () {
 					if ( line.startsWith( '0 FILE ' ) ) {
 
 						// Save previous embedded file in the cache
-						this.subobjectCache[ currentEmbeddedFileName ] = currentEmbeddedText;
+						this.subobjectCache[ currentEmbeddedFileName.toLowerCase() ] = currentEmbeddedText;
 
 						// New embedded text file
 						currentEmbeddedFileName = line.substring( 7 );
@@ -1436,7 +1408,7 @@ THREE.LDrawLoader = ( function () {
 
 			if ( parsingEmbeddedFiles ) {
 
-				this.subobjectCache[ currentEmbeddedFileName ] = currentEmbeddedText;
+				this.subobjectCache[ currentEmbeddedFileName.toLowerCase() ] = currentEmbeddedText;
 
 			}