OBJLoader2Parallel.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @author Kai Salmen / https://kaisalmen.de
  3. * Development repository: https://github.com/kaisalmen/WWOBJLoader
  4. */
  5. // Imports only related to wrapper
  6. import {
  7. CodeBuilderInstructions,
  8. WorkerExecutionSupport
  9. } from "./obj2/worker/main/WorkerExecutionSupport.js";
  10. import { CodeSerializer } from "./obj2/utils/CodeSerializer.js";
  11. import { OBJLoader2 } from "./OBJLoader2.js";
  12. // Imports only related to worker (when standard workers (modules aren't supported) are used)
  13. import { OBJLoader2Parser } from "./obj2/worker/parallel/OBJLoader2Parser.js";
  14. import { ObjectManipulator } from "./obj2/utils/ObjectManipulator.js";
  15. import {
  16. WorkerRunner,
  17. DefaultWorkerPayloadHandler
  18. } from "./obj2/worker/parallel/WorkerRunner.js";
  19. /**
  20. * Extends {OBJLoader2} with the capability to run the parser {OBJLoader2Parser} in web worker
  21. * with help of {WorkerExecutionSupport}.
  22. *
  23. * @param [LoadingManager] manager
  24. * @constructor
  25. */
  26. const OBJLoader2Parallel = function ( manager ) {
  27. OBJLoader2.call( this, manager );
  28. this.preferJsmWorker = false;
  29. this.callbacks.onParseComplete = null;
  30. this.executeParallel = true;
  31. this.workerExecutionSupport = new WorkerExecutionSupport();
  32. };
  33. OBJLoader2Parallel.prototype = Object.create( OBJLoader2.prototype );
  34. OBJLoader2Parallel.prototype.constructor = OBJLoader2Parallel;
  35. OBJLoader2.OBJLOADER2_PARALLEL_VERSION = '3.0.0-beta2';
  36. console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2.OBJLOADER2_PARALLEL_VERSION );
  37. OBJLoader2Parallel.prototype.setPreferJsmWorker = function ( preferJsmWorker ) {
  38. this.preferJsmWorker = preferJsmWorker === true;
  39. return this;
  40. };
  41. /**
  42. * If this call back is not set, then the completion message from worker will not be received.
  43. *
  44. * @param {function} onParseComplete
  45. * @return {OBJLoader2Parallel}
  46. */
  47. OBJLoader2Parallel.prototype.setCallbackOnParseComplete = function ( onParseComplete ) {
  48. if ( onParseComplete !== undefined && onParseComplete !== null ) {
  49. this.callbacks.onParseComplete = onParseComplete;
  50. }
  51. else {
  52. throw "No callbackOnLoad was provided! Aborting!";
  53. }
  54. return this;
  55. };
  56. /**
  57. * Execution of parse in parallel via Worker is default, but normal {OBJLoader2} parsing can be enforced via false here.
  58. *
  59. * @param executeParallel
  60. * @return {OBJLoader2Parallel}
  61. */
  62. OBJLoader2Parallel.prototype.setExecuteParallel = function ( executeParallel ) {
  63. this.executeParallel = executeParallel === true;
  64. return this;
  65. };
  66. /**
  67. * Allow to get hold of {WorkerExecutionSupport} for configuratin purposes
  68. *
  69. * @return {WorkerExecutionSupport|WorkerExecutionSupport}
  70. */
  71. OBJLoader2Parallel.prototype.getWorkerExecutionSupport = function () {
  72. return this.workerExecutionSupport;
  73. };
  74. /**
  75. * Provides instructions on what is to be contained in the worker
  76. *
  77. * @return {CodeBuilderInstructions}
  78. */
  79. OBJLoader2Parallel.prototype.buildWorkerCode = function () {
  80. let codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker );
  81. if ( codeBuilderInstructions.isSupportsJsmWorker() ) {
  82. codeBuilderInstructions.setJsmWorkerFile( '../../src/loaders/worker/parallel/jsm/OBJLoader2Worker.js' );
  83. }
  84. if ( codeBuilderInstructions.isSupportsStandardWorker() ) {
  85. let codeOBJLoader2Parser = CodeSerializer.serializeClass( 'OBJLoader2Parser', OBJLoader2Parser );
  86. let codeObjectManipulator = CodeSerializer.serializeObject( 'ObjectManipulator', ObjectManipulator );
  87. let codeParserPayloadHandler = CodeSerializer.serializeClass( 'DefaultWorkerPayloadHandler', DefaultWorkerPayloadHandler );
  88. let codeWorkerRunner = CodeSerializer.serializeClass( 'WorkerRunner', WorkerRunner );
  89. codeBuilderInstructions.addCodeFragment( codeOBJLoader2Parser );
  90. codeBuilderInstructions.addCodeFragment( codeObjectManipulator );
  91. codeBuilderInstructions.addCodeFragment( codeParserPayloadHandler );
  92. codeBuilderInstructions.addCodeFragment( codeWorkerRunner );
  93. // allows to include full libraries as importScripts
  94. // codeBuilderInstructions.addLibraryImport( '../../node_modules/three/build/three.js' );
  95. codeBuilderInstructions.addStartCode( 'new WorkerRunner( new DefaultWorkerPayloadHandler( new OBJLoader2Parser() ) );' );
  96. }
  97. return codeBuilderInstructions;
  98. };
  99. /**
  100. * @private
  101. */
  102. OBJLoader2Parallel.prototype._configure = function () {
  103. if ( this.callbacks.onParseComplete === null ) {
  104. "No callbackOnLoad was provided! Aborting!"
  105. }
  106. // check if worker is already available and if so, then fast-fail
  107. if ( this.workerExecutionSupport.isWorkerLoaded( this.preferJsmWorker ) ) return;
  108. this.workerExecutionSupport.buildWorker( this.buildWorkerCode() );
  109. let scope = this;
  110. let scopedOnAssetAvailable = function ( payload ) {
  111. scope._onAssetAvailable( payload );
  112. };
  113. this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, this.callbacks.onParseComplete );
  114. };
  115. /**
  116. * Load is intercepted from {OBJLoader2}. It replaces the regular onLoad callback as the final worker result will be
  117. * returned later by its own callbackOnLoad.
  118. *
  119. * @param {string} url A string containing the path/URL of the file to be loaded.
  120. * @param {function} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument.
  121. * @param {function} [onFileLoadProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes.
  122. * @param {function} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument.
  123. * @param {function} [onMeshAlter] Called after worker successfully delivered a single mesh
  124. */
  125. OBJLoader2Parallel.prototype.load = function( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
  126. this.setCallbackOnParseComplete( onLoad );
  127. OBJLoader2.prototype.load.call( this, content, function () {}, onFileLoadProgress, onError, onMeshAlter );
  128. };
  129. /**
  130. * Parses OBJ data in parallel with web worker.
  131. *
  132. * @param {arraybuffer} content OBJ data as Uint8Array or String
  133. */
  134. OBJLoader2Parallel.prototype.parse = function( content ) {
  135. if ( this.executeParallel ) {
  136. this._configure();
  137. this.workerExecutionSupport.executeParallel(
  138. {
  139. params: {
  140. modelName: this.modelName,
  141. instanceNo: this.instanceNo,
  142. useIndices: this.useIndices,
  143. disregardNormals: this.disregardNormals,
  144. materialPerSmoothingGroup: this.materialPerSmoothingGroup,
  145. useOAsMesh: this.useOAsMesh,
  146. },
  147. materials: this.materialHandler.getMaterialsJSON(),
  148. data: {
  149. input: content,
  150. options: null
  151. },
  152. logging: {
  153. enabled: this.logging.enabled,
  154. debug: this.logging.debug
  155. }
  156. } );
  157. } else {
  158. this.callbacks.onParseComplete( OBJLoader2.prototype.parse.call( this, content ) );
  159. }
  160. };
  161. export { OBJLoader2Parallel }