advancedDynamicTexture.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /// <reference path="../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.GUI {
  3. export class AdvancedDynamicTexture extends DynamicTexture {
  4. private _isDirty = false;
  5. private _renderObserver: Observer<Camera>;
  6. private _resizeObserver: Observer<Engine>;
  7. private _pointerMoveObserver: Observer<PointerInfoPre>;
  8. private _pointerObserver: Observer<PointerInfo>;
  9. private _canvasBlurObserver: Observer<Engine>;
  10. private _background: string;
  11. public _rootContainer = new Container("root");
  12. public _lastControlOver: Control;
  13. public _lastControlDown: Control;
  14. public _capturingControl: Control;
  15. public _shouldBlockPointer: boolean;
  16. public _layerToDispose: Layer;
  17. public _linkedControls = new Array<Control>();
  18. private _isFullscreen = false;
  19. private _fullscreenViewport = new Viewport(0, 0, 1, 1);
  20. private _idealWidth = 0;
  21. private _idealHeight = 0;
  22. private _renderAtIdealSize = false;
  23. public get background(): string {
  24. return this._background;
  25. }
  26. public set background(value: string) {
  27. if (this._background === value) {
  28. return;
  29. }
  30. this._background = value;
  31. this.markAsDirty();
  32. }
  33. public get idealWidth(): number {
  34. return this._idealWidth;
  35. }
  36. public set idealWidth(value: number) {
  37. if (this._idealWidth === value) {
  38. return;
  39. }
  40. this._idealWidth = value;
  41. this.markAsDirty();
  42. this._rootContainer._markAllAsDirty();
  43. }
  44. public get idealHeight(): number {
  45. return this._idealHeight;
  46. }
  47. public set idealHeight(value: number) {
  48. if (this._idealHeight === value) {
  49. return;
  50. }
  51. this._idealHeight = value;
  52. this.markAsDirty();
  53. this._rootContainer._markAllAsDirty();
  54. }
  55. public get renderAtIdealSize(): boolean {
  56. return this._renderAtIdealSize;
  57. }
  58. public set renderAtIdealSize(value: boolean) {
  59. if (this._renderAtIdealSize === value) {
  60. return;
  61. }
  62. this._renderAtIdealSize = value;
  63. this._onResize();
  64. }
  65. public get layer(): Layer {
  66. return this._layerToDispose;
  67. }
  68. public get rootContainer(): Container {
  69. return this._rootContainer;
  70. }
  71. constructor(name: string, width = 0, height = 0, scene: Scene, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE) {
  72. super(name, {width: width, height: height}, scene, generateMipMaps, samplingMode, Engine.TEXTUREFORMAT_RGBA);
  73. this._renderObserver = this.getScene().onBeforeCameraRenderObservable.add((camera: Camera) => this._checkUpdate(camera));
  74. this._rootContainer._link(null, this);
  75. this.hasAlpha = true;
  76. if (!width || !height) {
  77. this._resizeObserver = this.getScene().getEngine().onResizeObservable.add(() => this._onResize());
  78. this._onResize();
  79. }
  80. this._texture.isReady = true;
  81. }
  82. public executeOnAllControls(func: (control: Control) => void, container?: Container) {
  83. if (!container) {
  84. container = this._rootContainer;
  85. }
  86. for (var child of container.children) {
  87. if ((<any>child).children) {
  88. this.executeOnAllControls(func, (<Container>child));
  89. continue;
  90. }
  91. func(child);
  92. }
  93. }
  94. public markAsDirty() {
  95. this._isDirty = true;
  96. }
  97. public addControl(control: Control): AdvancedDynamicTexture {
  98. this._rootContainer.addControl(control);
  99. return this;
  100. }
  101. public removeControl(control: Control): AdvancedDynamicTexture {
  102. this._rootContainer.removeControl(control);
  103. return this;
  104. }
  105. public dispose() {
  106. this.getScene().onBeforeCameraRenderObservable.remove(this._renderObserver);
  107. if (this._resizeObserver) {
  108. this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
  109. }
  110. if (this._pointerMoveObserver) {
  111. this.getScene().onPrePointerObservable.remove(this._pointerMoveObserver);
  112. }
  113. if (this._pointerObserver) {
  114. this.getScene().onPointerObservable.remove(this._pointerObserver);
  115. }
  116. if (this._canvasBlurObserver) {
  117. this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
  118. }
  119. if (this._layerToDispose) {
  120. this._layerToDispose.texture = null;
  121. this._layerToDispose.dispose();
  122. this._layerToDispose = null;
  123. }
  124. super.dispose();
  125. }
  126. private _onResize(): void {
  127. // Check size
  128. var engine = this.getScene().getEngine();
  129. var textureSize = this.getSize();
  130. var renderWidth = engine.getRenderWidth();
  131. var renderHeight = engine.getRenderHeight();
  132. if (this._renderAtIdealSize) {
  133. if (this._idealWidth) {
  134. renderHeight = (renderHeight * this._idealWidth) / renderWidth;
  135. renderWidth = this._idealWidth;
  136. } else if (this._idealHeight) {
  137. renderWidth = (renderWidth * this._idealHeight) / renderHeight;
  138. renderHeight = this._idealHeight;
  139. }
  140. }
  141. if (textureSize.width !== renderWidth || textureSize.height !== renderHeight) {
  142. this.scaleTo(renderWidth, renderHeight);
  143. this.markAsDirty();
  144. if (this._idealWidth || this._idealHeight) {
  145. this._rootContainer._markAllAsDirty();
  146. }
  147. }
  148. }
  149. public _getGlobalViewport(scene: Scene): Viewport {
  150. var engine = scene.getEngine();
  151. return this._fullscreenViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  152. }
  153. private _checkUpdate(camera: Camera): void {
  154. if (this._layerToDispose) {
  155. if ((camera.layerMask & this._layerToDispose.layerMask) === 0) {
  156. return;
  157. }
  158. }
  159. if (this._isFullscreen && this._linkedControls.length) {
  160. var scene = this.getScene();
  161. var globalViewport = this._getGlobalViewport(scene);
  162. for (var control of this._linkedControls) {
  163. if (!control.isVisible) {
  164. continue;
  165. }
  166. var mesh = control._linkedMesh;
  167. if (mesh.isDisposed()) {
  168. Tools.SetImmediate(()=>{
  169. control.linkWithMesh(null);
  170. });
  171. continue;
  172. }
  173. var position = mesh.getBoundingInfo().boundingSphere.center;
  174. var projectedPosition = Vector3.Project(position, mesh.getWorldMatrix(), scene.getTransformMatrix(), globalViewport);
  175. if (projectedPosition.z < 0 || projectedPosition.z > 1) {
  176. control.notRenderable = true;
  177. continue;
  178. }
  179. control.notRenderable = false;
  180. control._moveToProjectedPosition(projectedPosition);
  181. }
  182. }
  183. if (!this._isDirty && !this._rootContainer.isDirty) {
  184. return;
  185. }
  186. this._isDirty = false;
  187. this._render();
  188. this.update();
  189. }
  190. private _render(): void {
  191. var engine = this.getScene().getEngine();
  192. var textureSize = this.getSize();
  193. var renderWidth = textureSize.width;
  194. var renderHeight = textureSize.height;
  195. // Clear
  196. var context = this.getContext();
  197. context.clearRect(0, 0, renderWidth, renderHeight);
  198. if (this._background) {
  199. context.save();
  200. context.fillStyle = this._background;
  201. context.fillRect(0, 0, renderWidth, renderHeight);
  202. context.restore();
  203. }
  204. // Render
  205. context.font = "18px Arial";
  206. var measure = new Measure(0, 0, renderWidth, renderHeight);
  207. this._rootContainer._draw(measure, context);
  208. }
  209. private _doPicking(x: number, y: number, type: number): void {
  210. var scene = this.getScene();
  211. var engine = scene.getEngine();
  212. var textureSize = this.getSize();
  213. if (this._isFullscreen) {
  214. x = x * (textureSize.width / engine.getRenderWidth());
  215. y = y * (textureSize.height / engine.getRenderHeight());
  216. }
  217. if (this._capturingControl) {
  218. this._capturingControl._processObservables(type, x, y);
  219. return;
  220. }
  221. if (!this._rootContainer._processPicking(x, y, type)) {
  222. if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
  223. if (this._lastControlOver) {
  224. this._lastControlOver._onPointerOut();
  225. }
  226. this._lastControlOver = null;
  227. }
  228. }
  229. }
  230. public attach(): void {
  231. var scene = this.getScene();
  232. this._pointerMoveObserver = scene.onPrePointerObservable.add((pi, state) => {
  233. if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
  234. && pi.type !== BABYLON.PointerEventTypes.POINTERUP
  235. && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
  236. return;
  237. }
  238. let camera = scene.activeCamera;
  239. let engine = scene.getEngine();
  240. let viewport = camera.viewport;
  241. let x = (scene.pointerX - viewport.x * engine.getRenderWidth()) / viewport.width;
  242. let y = (scene.pointerY - viewport.y * engine.getRenderHeight()) / viewport.height;
  243. this._shouldBlockPointer = false;
  244. this._doPicking(x, y, pi.type);
  245. pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
  246. });
  247. this._attachToOnBlur(scene);
  248. }
  249. public attachToMesh(mesh: AbstractMesh, supportPointerMove = true): void {
  250. var scene = this.getScene();
  251. this._pointerObserver = scene.onPointerObservable.add((pi, state) => {
  252. if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
  253. && pi.type !== BABYLON.PointerEventTypes.POINTERUP
  254. && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
  255. return;
  256. }
  257. if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
  258. var uv = pi.pickInfo.getTextureCoordinates();
  259. var size = this.getSize();
  260. this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type);
  261. } else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
  262. if (this._lastControlDown) {
  263. this._lastControlDown.forcePointerUp();
  264. }
  265. this._lastControlDown = null;
  266. } else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
  267. if (this._lastControlOver) {
  268. this._lastControlOver._onPointerOut();
  269. }
  270. this._lastControlOver = null;
  271. }
  272. });
  273. mesh.enablePointerMoveEvents = supportPointerMove;
  274. this._attachToOnBlur(scene);
  275. }
  276. private _attachToOnBlur(scene: Scene): void {
  277. this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(() => {
  278. if (this._lastControlOver) {
  279. this._lastControlOver._onPointerOut();
  280. }
  281. this._lastControlOver = null;
  282. if (this._lastControlDown) {
  283. this._lastControlDown.forcePointerUp();
  284. }
  285. this._lastControlDown = null;
  286. });
  287. }
  288. // Statics
  289. public static CreateForMesh(mesh: AbstractMesh, width = 1024, height = 1024, supportPointerMove = true): AdvancedDynamicTexture {
  290. var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, Texture.TRILINEAR_SAMPLINGMODE);
  291. var material = new BABYLON.StandardMaterial("AdvancedDynamicTextureMaterial", mesh.getScene());
  292. material.backFaceCulling = false;
  293. material.diffuseColor = BABYLON.Color3.Black();
  294. material.specularColor = BABYLON.Color3.Black();
  295. material.emissiveTexture = result;
  296. material.opacityTexture = result;
  297. mesh.material = material;
  298. result.attachToMesh(mesh, supportPointerMove);
  299. return result;
  300. }
  301. public static CreateFullscreenUI(name: string, foreground: boolean = true, scene: Scene = null): AdvancedDynamicTexture {
  302. var result = new AdvancedDynamicTexture(name, 0, 0, scene);
  303. // Display
  304. var layer = new BABYLON.Layer(name + "_layer", null, scene, !foreground);
  305. layer.texture = result;
  306. result._layerToDispose = layer;
  307. result._isFullscreen = true;
  308. // Attach
  309. result.attach();
  310. return result;
  311. }
  312. }
  313. }