viewer.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. import { Helper } from "../../../commons/helper";
  2. import { assert, expect, should } from "../viewerReference";
  3. import { DefaultViewer, AbstractViewer, Version, viewerManager } from "../../../../src";
  4. export let name = "viewer Tests";
  5. /**
  6. * To prevent test-state-leakage ensure that there is a viewer.dispose() for every new DefaultViewer
  7. */
  8. describe('Viewer', function () {
  9. it('should initialize a new viewer and its internal variables', (done) => {
  10. let viewer = Helper.getNewViewerInstance();
  11. assert.isDefined(viewer.baseId, "base id should be defined");
  12. assert.isDefined(viewer.templateManager, "template manager should be defined");
  13. assert.isDefined(viewer.sceneManager, "scene manager should be defined");
  14. assert.isDefined(viewer.modelLoader, "model loader should be defined");
  15. viewer.onInitDoneObservable.add(() => {
  16. assert.isDefined(viewer, "Viewer can not be instantiated.");
  17. viewer.dispose();
  18. done();
  19. });
  20. });
  21. it('should be added to the viewer manager', (done) => {
  22. let viewer = Helper.getNewViewerInstance();
  23. viewer.onInitDoneObservable.add(() => {
  24. assert.isDefined(viewerManager.getViewerById(viewer.baseId), "Viewer was not added to the viewer manager.");
  25. viewer.dispose();
  26. done();
  27. });
  28. });
  29. it('should have a defined canvas', (done) => {
  30. let viewer = Helper.getNewViewerInstance();
  31. viewer.onInitDoneObservable.add(() => {
  32. assert.isDefined(viewer.canvas, "Canvas is not defined");
  33. assert.isTrue(viewer.canvas instanceof HTMLCanvasElement, "Canvas is not a canvas");
  34. viewer.dispose();
  35. done();
  36. });
  37. });
  38. it('should not initialize if element is undefined', (done) => {
  39. try {
  40. // force typescript to "think" that the element exist with "!"
  41. let viewer = Helper.getNewViewerInstance(document.getElementById('doesntexist')!);
  42. expect(viewer).not.to.exist;
  43. if (viewer) viewer.dispose();
  44. } catch (e) {
  45. // exception was thrown, we are happy
  46. assert.isTrue(true);
  47. }
  48. done();
  49. });
  50. it('should be shown and hidden', (done) => {
  51. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  52. viewer.onInitDoneObservable.add(() => {
  53. // default visibility is not none
  54. expect(viewer.containerElement.style.display).not.to.equal('none');
  55. viewer.hide().then(() => {
  56. // element is hidden
  57. assert.equal(viewer.containerElement.style.display, 'none', "Viewer is still visible");
  58. viewer.show().then(() => {
  59. //element is shown
  60. assert.notEqual(viewer.containerElement.style.display, 'none', "Viewer is not visible");
  61. viewer.dispose();
  62. done();
  63. });
  64. });
  65. });
  66. });
  67. it('should execute registered functions on every rendered frame', (done) => {
  68. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  69. let renderCount = 0;
  70. let sceneRenderCount = 0;
  71. viewer.onSceneInitObservable.add((scene) => {
  72. viewer.sceneManager.scene.registerBeforeRender(() => {
  73. sceneRenderCount++;
  74. });
  75. viewer.onFrameRenderedObservable.add(() => {
  76. renderCount++;
  77. assert.equal(renderCount, sceneRenderCount, "function was not executed with each frame");
  78. if (renderCount === 20) {
  79. viewer.dispose();
  80. done();
  81. }
  82. });
  83. });
  84. });
  85. it('should disable and enable rendering', (done) => {
  86. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  87. let renderCount = 0;
  88. viewer.onInitDoneObservable.add(() => {
  89. viewer.onFrameRenderedObservable.add(() => {
  90. renderCount++;
  91. });
  92. assert.equal(renderCount, 0);
  93. window.requestAnimationFrame(function () {
  94. assert.equal(renderCount, 1, "render loop should have been executed");
  95. viewer.runRenderLoop = false;
  96. window.requestAnimationFrame(function () {
  97. assert.equal(renderCount, 1, "Render loop should not have been executed");
  98. viewer.runRenderLoop = true;
  99. window.requestAnimationFrame(function () {
  100. assert.equal(renderCount, 2, "render loop should have been executed again");
  101. viewer.dispose();
  102. done();
  103. });
  104. });
  105. });
  106. });
  107. });
  108. it('should have a version', (done) => {
  109. assert.exists(Version, "Viewer should have a version");
  110. assert.equal(Version, BABYLON.Engine.Version, "Viewer version should equal to Babylon's engine version");
  111. done();
  112. });
  113. it('should resize the viewer correctly', (done) => {
  114. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  115. let resizeCount = 0;
  116. //wait for the engine to init
  117. viewer.onEngineInitObservable.add((engine) => {
  118. // mock the resize function
  119. engine.resize = () => {
  120. resizeCount++;
  121. }
  122. });
  123. viewer.onInitDoneObservable.add(() => {
  124. assert.equal(resizeCount, 0);
  125. viewer.forceResize();
  126. assert.equal(resizeCount, 1, "Engine should resize when Viewer.forceResize() is called.");
  127. viewer.updateConfiguration({
  128. engine: {
  129. disableResize: true
  130. }
  131. });
  132. viewer.forceResize();
  133. assert.equal(resizeCount, 1, "Engine should not resize when disableResize is enabled");
  134. viewer.updateConfiguration({
  135. engine: {
  136. disableResize: false
  137. }
  138. });
  139. viewer.canvas.style.width = '0px';
  140. viewer.canvas.style.height = '0px';
  141. viewer.forceResize();
  142. assert.equal(resizeCount, 1, "Engine should not resize when the canvas has width/height 0.");
  143. viewer.dispose();
  144. // any since it is protected
  145. viewer.forceResize();
  146. assert.equal(resizeCount, 1, "Engine should not resize when if Viewer has been disposed.");
  147. done();
  148. });
  149. });
  150. it('should render in background if set to true', (done) => {
  151. let viewer = Helper.getNewViewerInstance();
  152. viewer.onInitDoneObservable.add(() => {
  153. assert.isTrue(viewer.engine.renderEvenInBackground, "Engine is rendering in background");
  154. viewer.updateConfiguration({
  155. scene: {
  156. renderInBackground: false
  157. }
  158. });
  159. assert.isFalse(viewer.engine.renderEvenInBackground, "Engine is not rendering in background");
  160. viewer.dispose();
  161. done();
  162. });
  163. });
  164. it('should attach and detach camera control correctly', (done) => {
  165. let viewer = Helper.getNewViewerInstance();
  166. viewer.onInitDoneObservable.add(() => {
  167. assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera is not attached per default");
  168. viewer.updateConfiguration({
  169. scene: {
  170. disableCameraControl: true
  171. }
  172. });
  173. assert.isNull(viewer.sceneManager.camera.inputs.attachedElement, "Camera is still attached");
  174. viewer.updateConfiguration({
  175. scene: {
  176. disableCameraControl: false
  177. }
  178. });
  179. assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera not attached");
  180. viewer.dispose();
  181. done();
  182. });
  183. });
  184. it('should take screenshot when called', (done) => {
  185. let viewer = Helper.getNewViewerInstance();
  186. viewer.onInitDoneObservable.add(() => {
  187. Helper.MockScreenCapture(viewer, Helper.mockScreenCaptureData());
  188. viewer.takeScreenshot(function (data) {
  189. assert.equal(data, Helper.mockScreenCaptureData(), "Screenshot failed.");
  190. viewer.dispose();
  191. done();
  192. });
  193. });
  194. });
  195. it('should notify observers correctly during init', (done) => {
  196. let viewer = Helper.getNewViewerInstance();
  197. let shouldBeRendering = false;
  198. viewer.onFrameRenderedObservable.add(() => {
  199. assert.isTrue(shouldBeRendering, "rendered before init done");
  200. viewer.dispose();
  201. done();
  202. });
  203. viewer.onEngineInitObservable.add((engine) => {
  204. assert.equal(engine, viewer.engine, "engine instance is not the same");
  205. assert.isUndefined(viewer.sceneManager.scene, "scene exists before initScene");
  206. });
  207. viewer.onSceneInitObservable.add((scene) => {
  208. assert.equal(scene, viewer.sceneManager.scene, "scene instance is not the same");
  209. })
  210. viewer.onInitDoneObservable.add((viewerInstance) => {
  211. assert.isDefined(viewerInstance.sceneManager.scene, "scene is not defined");
  212. //scene exists, it should now start rendering
  213. shouldBeRendering = true;
  214. });
  215. });
  216. it('should render if forceRender was called', (done) => {
  217. let viewer = Helper.getNewViewerInstance();
  218. viewer.runRenderLoop = false;
  219. viewer.onInitDoneObservable.add(() => {
  220. viewer.onFrameRenderedObservable.add(() => {
  221. assert.isTrue(true, "not rendered");
  222. viewer.dispose();
  223. done();
  224. });
  225. viewer.forceRender();
  226. });
  227. });
  228. });
  229. //}
  230. /*
  231. QUnit.test('Viewer disable ctrl for panning', function (assert) {
  232. let viewer = new DefaultViewer(Helper.getCanvas());
  233. QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning, "Viewer should use CTRL for panning by default.");
  234. viewer.dispose();
  235. viewer = null;
  236. viewer = new DefaultViewer(Helper.getCanvas(), {
  237. disableCtrlForPanning: true
  238. });
  239. QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning === false, "Viewer should not use CTRL for panning with disableCameraControl set to true.");
  240. viewer.dispose();
  241. });
  242. QUnit.test('Viewer get models', function (assert) {
  243. let viewer = new DefaultViewer(Helper.getCanvas());
  244. let mesh1 = Helper.createMockMesh(viewer);
  245. let mesh2 = Helper.createMockMesh(viewer);
  246. let model1 = new SPECTRE.Model(viewer, "Model 1");
  247. let model2 = new SPECTRE.Model(viewer, "Model 2");
  248. model1.setMesh(mesh1);
  249. model2.setMesh(mesh2);
  250. viewer.Scene.addModel(model1, false);
  251. viewer.Scene.addModel(model2, false);
  252. QUnit.assert.equal(viewer.Scene.Models.length, 2, "Viewer.getModels should return all models in the scene by default.");
  253. // Further tests fail unless this viewer is disposed
  254. // TODO fully isolate tests
  255. viewer.dispose();
  256. });
  257. QUnit.test('Viewer model add/remove', function (assert) {
  258. let modelsInScene = 0;
  259. let viewer = new DefaultViewer(Helper.getCanvas(), {
  260. onModelAdd: function () {
  261. modelsInScene += 1;
  262. },
  263. onModelRemove: function () {
  264. modelsInScene -= 1;
  265. }
  266. });
  267. let mesh1 = Helper.createMockMesh(viewer);
  268. let model = new SPECTRE.Model(viewer, "Model");
  269. model.setMesh(mesh1);
  270. viewer.Scene.addModel(model, false);
  271. QUnit.assert.equal(modelsInScene, 1, "onModelAdd should be called when a model is registered");
  272. viewer.Scene.removeModel(model, false);
  273. QUnit.assert.equal(modelsInScene, 0, "onModelRemove should be called when a model is unregistered");
  274. viewer.dispose();
  275. });
  276. QUnit.test('Viewer typical case with dispose', function (assert) {
  277. let done = assert.async();
  278. let viewer = new DefaultViewer(Helper.getCanvas(), {
  279. environmentAssetsRootURL: 'base/assets/environment/',
  280. environmentMap: 'legacy/joa-256.env',
  281. unifiedConfiguration: 'base/assets/UnifiedConfiguration.json'
  282. });
  283. //load different models sequentially to simulate typical use
  284. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  285. completeCallback: (model) => {
  286. model.EngineModel.translate(new BABYLON.Vector3(1, 0, 0), 0.1);
  287. setTimeout(() => {
  288. viewer.Scene.removeModel(model, true, () => {
  289. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  290. readyCallback: () => {
  291. //starting loading a few assets and ensure there's no failure when disposing
  292. viewer.loadEnvironment('legacy/joa-256.env', () => {
  293. assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
  294. });
  295. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  296. readyCallback: () => {
  297. assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
  298. },
  299. });
  300. try {
  301. console.log('Disposing viewer');
  302. viewer.dispose();
  303. viewer = null;
  304. console.log('Viewer disposed');
  305. } catch (e) {
  306. assert.ok(false, `Viewer failed to dispose without exception ${e}`);
  307. }
  308. setTimeout(() => {
  309. //wait some time to verify there were no exceptions no complete callbacks fire unexpectedly
  310. assert.strictEqual(viewer, null, 'Viewer should be set to null');
  311. done();
  312. }, 2000);
  313. }
  314. });
  315. });
  316. }, 3000);
  317. }
  318. });
  319. });
  320. QUnit.test('Test getEnvironmentAssetUrl relative no root', function (assert) {
  321. var viewer = Helper.createViewer();
  322. assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "foo.png", "Relative url should be return unmodified without configuration.");
  323. });
  324. QUnit.test('Test getEnvironmentAssetUrl absolute no root', function (assert) {
  325. var viewer = Helper.createViewer();
  326. assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined without configuration.");
  327. });
  328. QUnit.test('Test getEnvironmentAssetUrl relative root', function (assert) {
  329. var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
  330. assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "https://foo/foo.png", "Relative url should not be be undefined with configuration.");
  331. });
  332. QUnit.test('Test getEnvironmentAssetUrl absolute root', function (assert) {
  333. var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
  334. assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined with configuration.");
  335. });
  336. QUnit.test('unlockBabylonFeatures', function () {
  337. let viewer = Helper.createViewer();
  338. QUnit.assert.ok(viewer.Scene.EngineScene.shadowsEnabled, "shadowsEnabled");
  339. QUnit.assert.ok(!viewer.Scene.EngineScene.particlesEnabled, "particlesEnabled");
  340. QUnit.assert.ok(!viewer.Scene.EngineScene.collisionsEnabled, "collisionsEnabled");
  341. QUnit.assert.ok(viewer.Scene.EngineScene.lightsEnabled, "lightsEnabled");
  342. QUnit.assert.ok(viewer.Scene.EngineScene.texturesEnabled, "texturesEnabled");
  343. QUnit.assert.ok(!viewer.Scene.EngineScene.lensFlaresEnabled, "lensFlaresEnabled");
  344. QUnit.assert.ok(!viewer.Scene.EngineScene.proceduralTexturesEnabled, "proceduralTexturesEnabled");
  345. QUnit.assert.ok(viewer.Scene.EngineScene.renderTargetsEnabled, "renderTargetsEnabled");
  346. QUnit.assert.ok(!viewer.Scene.EngineScene.spritesEnabled, "spritesEnabled");
  347. QUnit.assert.ok(viewer.Scene.EngineScene.skeletonsEnabled, "skeletonsEnabled");
  348. QUnit.assert.ok(!viewer.Scene.EngineScene.audioEnabled, "audioEnabled");
  349. viewer.unlockBabylonFeatures();
  350. QUnit.assert.ok(viewer.Scene.EngineScene.shadowsEnabled, "shadowsEnabled");
  351. QUnit.assert.ok(viewer.Scene.EngineScene.particlesEnabled, "particlesEnabled");
  352. QUnit.assert.ok(viewer.Scene.EngineScene.postProcessesEnabled, "postProcessesEnabled");
  353. QUnit.assert.ok(viewer.Scene.EngineScene.collisionsEnabled, "collisionsEnabled");
  354. QUnit.assert.ok(viewer.Scene.EngineScene.lightsEnabled, "lightsEnabled");
  355. QUnit.assert.ok(viewer.Scene.EngineScene.texturesEnabled, "texturesEnabled");
  356. QUnit.assert.ok(viewer.Scene.EngineScene.lensFlaresEnabled, "lensFlaresEnabled");
  357. QUnit.assert.ok(viewer.Scene.EngineScene.proceduralTexturesEnabled, "proceduralTexturesEnabled");
  358. QUnit.assert.ok(viewer.Scene.EngineScene.renderTargetsEnabled, "renderTargetsEnabled");
  359. QUnit.assert.ok(viewer.Scene.EngineScene.spritesEnabled, "spritesEnabled");
  360. QUnit.assert.ok(viewer.Scene.EngineScene.skeletonsEnabled, "skeletonsEnabled");
  361. QUnit.assert.ok(viewer.Scene.EngineScene.audioEnabled, "audioEnabled");
  362. });
  363. */