| 
									
										
										
										
											2024-05-12 04:16:02 +02:00
										 |  |  | const Features = { | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @param {number=} [majorVersion=1] The major WebGL version to check for. | 
					
						
							|  |  |  | 	 * @returns {boolean} If the given major version of WebGL is available. | 
					
						
							|  |  |  | 	 * @function Engine.isWebGLAvailable | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isWebGLAvailable: function (majorVersion = 1) { | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]); | 
					
						
							|  |  |  | 		} catch (e) { /* Not available */ } | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether the Fetch API available and supports streaming responses. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {boolean} If the Fetch API is available and supports streaming responses. | 
					
						
							|  |  |  | 	 * @function Engine.isFetchAvailable | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isFetchAvailable: function () { | 
					
						
							|  |  |  | 		return 'fetch' in window && 'Response' in window && 'body' in window.Response.prototype; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether the engine is running in a Secure Context. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {boolean} If the engine is running in a Secure Context. | 
					
						
							|  |  |  | 	 * @function Engine.isSecureContext | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isSecureContext: function () { | 
					
						
							|  |  |  | 		return window['isSecureContext'] === true; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether the engine is cross origin isolated. | 
					
						
							|  |  |  | 	 * This value is dependent on Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers sent by the server. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {boolean} If the engine is running in a Secure Context. | 
					
						
							|  |  |  | 	 * @function Engine.isSecureContext | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isCrossOriginIsolated: function () { | 
					
						
							|  |  |  | 		return window['crossOriginIsolated'] === true; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether SharedBufferArray is available. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Most browsers require the page to be running in a secure context, and the | 
					
						
							|  |  |  | 	 * the server to provide specific CORS headers for SharedArrayBuffer to be available. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {boolean} If SharedArrayBuffer is available. | 
					
						
							|  |  |  | 	 * @function Engine.isSharedArrayBufferAvailable | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isSharedArrayBufferAvailable: function () { | 
					
						
							|  |  |  | 		return 'SharedArrayBuffer' in window; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Check whether the AudioContext supports AudioWorkletNodes. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {boolean} If AudioWorkletNode is available. | 
					
						
							|  |  |  | 	 * @function Engine.isAudioWorkletAvailable | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	isAudioWorkletAvailable: function () { | 
					
						
							|  |  |  | 		return 'AudioContext' in window && 'audioWorklet' in AudioContext.prototype; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Return an array of missing required features (as string). | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * @returns {Array<string>} A list of human-readable missing features. | 
					
						
							|  |  |  | 	 * @function Engine.getMissingFeatures | 
					
						
							| 
									
										
										
										
											2024-04-26 09:38:38 +02:00
										 |  |  | 	 * @param {{threads: (boolean|undefined)}} supportedFeatures | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2023-12-01 13:39:09 -05:00
										 |  |  | 	getMissingFeatures: function (supportedFeatures = {}) { | 
					
						
							|  |  |  | 		const { | 
					
						
							| 
									
										
										
										
											2024-04-18 10:50:34 -04:00
										 |  |  | 			// Quotes are needed for the Closure compiler.
 | 
					
						
							|  |  |  | 			'threads': supportsThreads = true, | 
					
						
							| 
									
										
										
										
											2023-12-01 13:39:09 -05:00
										 |  |  | 		} = supportedFeatures; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		const missing = []; | 
					
						
							|  |  |  | 		if (!Features.isWebGLAvailable(2)) { | 
					
						
							| 
									
										
										
										
											2022-10-23 19:12:57 +02:00
										 |  |  | 			missing.push('WebGL2 - Check web browser configuration and hardware support'); | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!Features.isFetchAvailable()) { | 
					
						
							| 
									
										
										
										
											2022-10-23 19:12:57 +02:00
										 |  |  | 			missing.push('Fetch - Check web browser version'); | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!Features.isSecureContext()) { | 
					
						
							| 
									
										
										
										
											2022-10-23 19:12:57 +02:00
										 |  |  | 			missing.push('Secure Context - Check web server configuration (use HTTPS)'); | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-01 13:39:09 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (supportsThreads) { | 
					
						
							|  |  |  | 			if (!Features.isCrossOriginIsolated()) { | 
					
						
							|  |  |  | 				missing.push('Cross-Origin Isolation - Check that the web server configuration sends the correct headers.'); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!Features.isSharedArrayBufferAvailable()) { | 
					
						
							|  |  |  | 				missing.push('SharedArrayBuffer - Check that the web server configuration sends the correct headers.'); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-01 13:39:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-17 10:16:34 +02:00
										 |  |  | 		// Audio is normally optional since we have a dummy fallback.
 | 
					
						
							|  |  |  | 		return missing; | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; |