lessons-worker-helper.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright 2019, Gregg Tavares.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Gregg Tavares. nor the names of his
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /* global */
  32. 'use strict'; // eslint-disable-line
  33. ( function () {
  34. const lessonSettings = self.lessonSettings || {};
  35. function isInEditor() {
  36. return self.location.href.substring( 0, 4 ) === 'blob';
  37. }
  38. function sendMessage( data ) {
  39. self.postMessage( {
  40. type: '__editor__',
  41. data,
  42. } );
  43. }
  44. const origConsole = {};
  45. function setupConsole() {
  46. function wrapFunc( obj, logType ) {
  47. const origFunc = obj[ logType ].bind( obj );
  48. origConsole[ logType ] = origFunc;
  49. return function ( ...args ) {
  50. origFunc( ...args );
  51. sendMessage( {
  52. type: 'log',
  53. logType,
  54. msg: [ ...args ].join( ' ' ),
  55. } );
  56. };
  57. }
  58. self.console.log = wrapFunc( self.console, 'log' );
  59. self.console.warn = wrapFunc( self.console, 'warn' );
  60. self.console.error = wrapFunc( self.console, 'error' );
  61. }
  62. /**
  63. * Gets a WebGL context.
  64. * makes its backing store the size it is displayed.
  65. * @param {OffscreenCanvas} canvas a canvas element.
  66. * @memberOf module:webgl-utils
  67. */
  68. let setupLesson = function ( canvas ) {
  69. // only once
  70. setupLesson = function () {};
  71. if ( canvas ) {
  72. canvas.addEventListener( 'webglcontextlost', function () {
  73. // the default is to do nothing. Preventing the default
  74. // means allowing context to be restored
  75. // e.preventDefault(); // can't do this because firefox bug - https://bugzilla.mozilla.org/show_bug.cgi?id=1633280
  76. sendMessage( {
  77. type: 'lostContext',
  78. } );
  79. } );
  80. }
  81. };
  82. function captureJSErrors() {
  83. // capture JavaScript Errors
  84. self.addEventListener( 'error', function ( e ) {
  85. const msg = e.message || e.error;
  86. const url = e.filename;
  87. const lineNo = e.lineno || 1;
  88. const colNo = e.colno || 1;
  89. sendMessage( {
  90. type: 'jsError',
  91. lineNo,
  92. colNo,
  93. url,
  94. msg,
  95. } );
  96. } );
  97. }
  98. const isWebGLRE = /^(webgl|webgl2|experimental-webgl)$/i;
  99. function installWebGLLessonSetup() {
  100. OffscreenCanvas.prototype.getContext = ( function ( oldFn ) { // eslint-disable-line compat/compat
  101. return function () {
  102. const type = arguments[ 0 ];
  103. const isWebGL = isWebGLRE.test( type );
  104. if ( isWebGL ) {
  105. setupLesson( this );
  106. }
  107. const args = [].slice.apply( arguments );
  108. args[ 1 ] = {
  109. powerPreference: 'low-power',
  110. ...args[ 1 ],
  111. };
  112. return oldFn.apply( this, args );
  113. };
  114. }( OffscreenCanvas.prototype.getContext ) ); // eslint-disable-line compat/compat
  115. }
  116. function installWebGLDebugContextCreator() {
  117. if ( ! self.webglDebugHelper ) {
  118. return;
  119. }
  120. const {
  121. makeDebugContext,
  122. glFunctionArgToString,
  123. glEnumToString,
  124. } = self.webglDebugHelper;
  125. // capture GL errors
  126. OffscreenCanvas.prototype.getContext = ( function ( oldFn ) { // eslint-disable-line compat/compat
  127. return function () {
  128. let ctx = oldFn.apply( this, arguments );
  129. // Using bindTexture to see if it's WebGL. Could check for instanceof WebGLRenderingContext
  130. // but that might fail if wrapped by debugging extension
  131. if ( ctx && ctx.bindTexture ) {
  132. ctx = makeDebugContext( ctx, {
  133. maxDrawCalls: 100,
  134. errorFunc: function ( err, funcName, args ) {
  135. const numArgs = args.length;
  136. const enumedArgs = [].map.call( args, function ( arg, ndx ) {
  137. let str = glFunctionArgToString( funcName, numArgs, ndx, arg );
  138. // shorten because of long arrays
  139. if ( str.length > 200 ) {
  140. str = str.substring( 0, 200 ) + '...';
  141. }
  142. return str;
  143. } );
  144. {
  145. const error = new Error();
  146. sendMessage( {
  147. type: 'jsErrorWithStack',
  148. stack: error.stack,
  149. msg: `${glEnumToString( err )} in ${funcName}(${enumedArgs.join( ', ' )})`,
  150. } );
  151. }
  152. },
  153. } );
  154. }
  155. return ctx;
  156. };
  157. }( OffscreenCanvas.prototype.getContext ) ); // eslint-disable-line compat/compat
  158. }
  159. installWebGLLessonSetup();
  160. if ( isInEditor() ) {
  161. setupConsole();
  162. captureJSErrors();
  163. if ( lessonSettings.glDebug !== false ) {
  164. installWebGLDebugContextCreator();
  165. }
  166. }
  167. }() );