rendererComponent.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import * as React from "react";
  2. import { GlobalState } from '../globalState';
  3. import {Engine} from "babylonjs/Engines/engine"
  4. import { Nullable } from 'babylonjs/types';
  5. import { Scene } from 'babylonjs/scene';
  6. import { Utilities } from '../tools/utilities';
  7. require("../scss/rendering.scss");
  8. interface IRenderingComponentProps {
  9. globalState: GlobalState;
  10. }
  11. export class RenderingComponent extends React.Component<IRenderingComponentProps> {
  12. private _engine: Nullable<Engine>;
  13. private _scene: Nullable<Scene>;
  14. private _canvasRef: React.RefObject<HTMLCanvasElement>;
  15. public constructor(props: IRenderingComponentProps) {
  16. super(props);
  17. this._canvasRef = React.createRef();
  18. // Create the global handleException
  19. (window as any).handleException = (e: Error) => {
  20. console.error(e);
  21. }
  22. this.props.globalState.onRunRequiredObservable.add(() => {
  23. this.compileAndRun();
  24. })
  25. }
  26. componentDidMount() {
  27. this.compileAndRun();
  28. }
  29. compileAndRun() {
  30. if (this._engine) {
  31. try {
  32. this._engine.dispose();
  33. }
  34. catch (ex) {
  35. // just ignore
  36. }
  37. this._engine = null;
  38. }
  39. let globalObject = window as any;
  40. let canvas = this._canvasRef.current!;
  41. globalObject.canvas = canvas;
  42. globalObject.createDefaultEngine = function () {
  43. return new Engine(canvas, true, {
  44. preserveDrawingBuffer: true,
  45. stencil: true
  46. });
  47. }
  48. // let zipVariables = "var engine = null;\r\nvar scene = null;\r\nvar sceneToRender = null;\r\n";
  49. // let defaultEngineZip = "var createDefaultEngine = function() { return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true }); }";
  50. let code = this.props.globalState.currentCode;
  51. let createEngineFunction = "createDefaultEngine";
  52. let createSceneFunction = "";
  53. let checkCamera = true;
  54. let checkSceneCount = true;
  55. if (code.indexOf("createEngine") !== -1) {
  56. createEngineFunction = "createEngine";
  57. }
  58. // Check for different typos
  59. if (code.indexOf("delayCreateScene") !== -1) { // delayCreateScene
  60. createSceneFunction = "delayCreateScene";
  61. checkCamera = false;
  62. } else if (code.indexOf("createScene") !== -1) { // createScene
  63. createSceneFunction = "createScene";
  64. } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
  65. createSceneFunction = "CreateScene";
  66. } else if (code.indexOf("createscene") !== -1) { // createscene
  67. createSceneFunction = "createscene";
  68. }
  69. if (!createSceneFunction) {
  70. this._engine = globalObject.createDefaultEngine() as Engine;
  71. this._scene = new Scene(this._engine);
  72. globalObject.engine = this._engine;
  73. globalObject.scene = this._scene;
  74. let runScript:any = null;
  75. Utilities.FastEval("runScript = function(scene, canvas) {" + code + "}");
  76. runScript(this._scene, canvas);
  77. //parent.zipTool.ZipCode = zipVariables + defaultEngineZip + "var engine = createDefaultEngine();" + ";\r\nvar scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
  78. } else {
  79. code += `
  80. var engine;
  81. try {
  82. engine = ${createEngineFunction}();
  83. } catch(e) {
  84. console.log("the available createEngine function failed. Creating the default engine instead");
  85. engine = createDefaultEngine();
  86. }`;
  87. code += "\r\nif (!engine) throw 'engine should not be null.';";
  88. if (this.props.globalState.language === "JS") {
  89. code += "\r\n" + "scene = " + createSceneFunction + "();";
  90. } else {
  91. var startCar = code.search('var ' + createSceneFunction);
  92. code = code.substr(0, startCar) + code.substr(startCar + 4);
  93. code += "\n" + "scene = " + createSceneFunction + "();";
  94. }
  95. // Execute the code
  96. Utilities.FastEval(code);
  97. this._engine = globalObject.engine;
  98. if (!this._engine) {
  99. this.props.globalState.onErrorObservable.notifyObservers("createEngine function must return an engine.");
  100. return;
  101. }
  102. if (!globalObject.scene) {
  103. this.props.globalState.onErrorObservable.notifyObservers(createSceneFunction + " function must return a scene.");
  104. return;
  105. }
  106. let sceneToRenderCode = 'sceneToRender = scene';
  107. // if scene returns a promise avoid checks
  108. if (globalObject.scene.then) {
  109. checkCamera = false;
  110. checkSceneCount = false;
  111. sceneToRenderCode = 'scene.then(returnedScene => { sceneToRender = returnedScene; });\r\n';
  112. }
  113. // let createEngineZip = (createEngineFunction === "createEngine") ?
  114. // zipVariables :
  115. // zipVariables + defaultEngineZip;
  116. // parent.zipTool.zipCode =
  117. // createEngineZip + ";\r\n" +
  118. // code + ";\r\n" +
  119. // sceneToRenderCode;
  120. }
  121. if (globalObject.scene.then) {
  122. globalObject.scene.then((s : Scene) => {
  123. this._scene = s;
  124. globalObject.scene = this._scene;
  125. });
  126. } else {
  127. this._scene = globalObject.scene as Scene;
  128. }
  129. this._engine.runRenderLoop(() => {
  130. if (!this._scene || !this._engine) {
  131. return;
  132. }
  133. if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
  134. this._engine.resize();
  135. }
  136. if (this._scene.activeCamera || this._scene.activeCameras.length > 0) {
  137. this._scene.render();
  138. }
  139. // Update FPS if camera is not a webxr camera
  140. if(!(this._scene.activeCamera &&
  141. this._scene.activeCamera.getClassName &&
  142. this._scene.activeCamera.getClassName() === 'WebXRCamera')) {
  143. this.props.globalState.fpsElement.innerHTML = this._engine.getFps().toFixed() + " fps";
  144. }
  145. });
  146. if (checkSceneCount && this._engine.scenes.length === 0) {
  147. this.props.globalState.onErrorObservable.notifyObservers("You must at least create a scene.");
  148. return;
  149. }
  150. if (checkCamera && this._engine.scenes[0].activeCamera == null) {
  151. this.props.globalState.onErrorObservable.notifyObservers("You must at least create a camera.");
  152. return;
  153. } else if (globalObject.scene.then) {
  154. globalObject.scene.then(function () {
  155. });
  156. } else {
  157. this._engine.scenes[0].executeWhenReady(function () {
  158. });
  159. }
  160. }
  161. public render() {
  162. return (
  163. <canvas id="renderingCanvas" ref={this._canvasRef}></canvas>
  164. )
  165. }
  166. }