OBJLoader2Parallel.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. Object3D
  8. } from "../../../build/three.module.js";
  9. import {
  10. CodeBuilderInstructions,
  11. WorkerExecutionSupport
  12. } from "./obj2/worker/main/WorkerExecutionSupport.js";
  13. import { CodeSerializer } from "./obj2/utils/CodeSerializer.js";
  14. import { OBJLoader2 } from "./OBJLoader2.js";
  15. // Imports only related to worker (when standard workers (modules aren't supported) are used)
  16. import { OBJLoader2Parser } from "./obj2/worker/parallel/OBJLoader2Parser.js";
  17. import {
  18. WorkerRunner,
  19. DefaultWorkerPayloadHandler,
  20. ObjectManipulator
  21. } from "./obj2/worker/parallel/WorkerRunner.js";
  22. /**
  23. * Creates a new OBJLoader2Parallel. Use it to load OBJ data from files or to parse OBJ data from arraybuffer.
  24. * It extends {@link OBJLoader2} with the capability to run the parser in a web worker.
  25. *
  26. * @param [LoadingManager] manager The loadingManager for the loader to use. Default is {@link LoadingManager}
  27. * @constructor
  28. */
  29. const OBJLoader2Parallel = function ( manager ) {
  30. OBJLoader2.call( this, manager );
  31. this.preferJsmWorker = false;
  32. this.executeParallel = true;
  33. this.workerExecutionSupport = new WorkerExecutionSupport();
  34. };
  35. OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION = '3.1.2';
  36. console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION );
  37. OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototype ), {
  38. constructor: OBJLoader2Parallel,
  39. /**
  40. * Execution of parse in parallel via Worker is default, but normal {OBJLoader2} parsing can be enforced via false here.
  41. *
  42. * @param executeParallel True or False
  43. * @return {OBJLoader2Parallel}
  44. */
  45. setExecuteParallel: function ( executeParallel ) {
  46. this.executeParallel = executeParallel === true;
  47. return this;
  48. },
  49. /**
  50. * Set whether jsm modules in workers should be used. This requires browser support which is currently only experimental.
  51. * @param preferJsmWorker True or False
  52. * @return {OBJLoader2Parallel}
  53. */
  54. setPreferJsmWorker: function ( preferJsmWorker ) {
  55. this.preferJsmWorker = preferJsmWorker === true;
  56. return this;
  57. },
  58. /**
  59. * Allow to get hold of {@link WorkerExecutionSupport} for configuration purposes.
  60. * @return {WorkerExecutionSupport}
  61. */
  62. getWorkerExecutionSupport: function () {
  63. return this.workerExecutionSupport;
  64. },
  65. /**
  66. * Provide instructions on what is to be contained in the worker.
  67. * @return {CodeBuilderInstructions}
  68. */
  69. buildWorkerCode: function () {
  70. let codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker );
  71. if ( codeBuilderInstructions.isSupportsJsmWorker() ) {
  72. codeBuilderInstructions.setJsmWorkerFile( '../examples/loaders/jsm/obj2/worker/parallel/jsm/OBJLoader2Worker.js' );
  73. }
  74. if ( codeBuilderInstructions.isSupportsStandardWorker() ) {
  75. let codeOBJLoader2Parser = CodeSerializer.serializeClass( 'OBJLoader2Parser', OBJLoader2Parser );
  76. let codeObjectManipulator = CodeSerializer.serializeObject( 'ObjectManipulator', ObjectManipulator );
  77. let codeParserPayloadHandler = CodeSerializer.serializeClass( 'DefaultWorkerPayloadHandler', DefaultWorkerPayloadHandler );
  78. let codeWorkerRunner = CodeSerializer.serializeClass( 'WorkerRunner', WorkerRunner );
  79. codeBuilderInstructions.addCodeFragment( codeOBJLoader2Parser );
  80. codeBuilderInstructions.addCodeFragment( codeObjectManipulator );
  81. codeBuilderInstructions.addCodeFragment( codeParserPayloadHandler );
  82. codeBuilderInstructions.addCodeFragment( codeWorkerRunner );
  83. codeBuilderInstructions.addStartCode( 'new WorkerRunner( new DefaultWorkerPayloadHandler( new OBJLoader2Parser() ) );' );
  84. }
  85. return codeBuilderInstructions;
  86. },
  87. /**
  88. * See {@link OBJLoader2.load}
  89. */
  90. load: function ( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
  91. let scope = this;
  92. function interceptOnLoad( object3d, message ) {
  93. if ( object3d.name === 'OBJLoader2ParallelDummy' ) {
  94. if ( scope.parser.logging.enabled && scope.parser.logging.debug ) {
  95. console.debug( 'Received dummy answer from OBJLoader2Parallel#parse' );
  96. }
  97. } else {
  98. onLoad( object3d, message );
  99. }
  100. }
  101. OBJLoader2.prototype.load.call( this, content, interceptOnLoad, onFileLoadProgress, onError, onMeshAlter );
  102. },
  103. /**
  104. * See {@link OBJLoader2.parse}
  105. * The callback onLoad needs to be set to be able to receive the content if used in parallel mode.
  106. * Fallback is possible via {@link OBJLoader2Parallel#setExecuteParallel}.
  107. */
  108. parse: function ( content ) {
  109. if ( this.executeParallel ) {
  110. if ( this.parser.callbacks.onLoad === this.parser._onLoad ) {
  111. throw "No callback other than the default callback was provided! Aborting!";
  112. }
  113. // check if worker has been initialize before. If yes, skip init
  114. if ( ! this.workerExecutionSupport.isWorkerLoaded( this.preferJsmWorker ) ) {
  115. this.workerExecutionSupport.buildWorker( this.buildWorkerCode() );
  116. let scope = this;
  117. let scopedOnAssetAvailable = function ( payload ) {
  118. scope._onAssetAvailable( payload );
  119. };
  120. function scopedOnLoad( message ) {
  121. scope.parser.callbacks.onLoad( scope.baseObject3d, message );
  122. }
  123. this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, scopedOnLoad );
  124. }
  125. // Create default materials beforehand, but do not override previously set materials (e.g. during init)
  126. this.materialHandler.createDefaultMaterials( false );
  127. this.workerExecutionSupport.executeParallel(
  128. {
  129. params: {
  130. modelName: this.modelName,
  131. instanceNo: this.instanceNo,
  132. useIndices: this.parser.useIndices,
  133. disregardNormals: this.parser.disregardNormals,
  134. materialPerSmoothingGroup: this.parser.materialPerSmoothingGroup,
  135. useOAsMesh: this.parser.useOAsMesh,
  136. materials: this.materialHandler.getMaterialsJSON()
  137. },
  138. data: {
  139. input: content,
  140. options: null
  141. },
  142. logging: {
  143. enabled: this.parser.logging.enabled,
  144. debug: this.parser.logging.debug
  145. }
  146. } );
  147. let dummy = new Object3D();
  148. dummy.name = 'OBJLoader2ParallelDummy';
  149. return dummy;
  150. } else {
  151. return OBJLoader2.prototype.parse.call( this, content );
  152. }
  153. },
  154. } );
  155. export { OBJLoader2Parallel };