advancedDynamicTexture.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. public get background(): string {
  23. return this._background;
  24. }
  25. public set background(value: string) {
  26. if (this._background === value) {
  27. return;
  28. }
  29. this._background = value;
  30. this.markAsDirty();
  31. }
  32. public get idealWidth(): number {
  33. return this._idealWidth;
  34. }
  35. public set idealWidth(value: number) {
  36. if (this._idealWidth === value) {
  37. return;
  38. }
  39. this._idealWidth = value;
  40. this.markAsDirty();
  41. this._rootContainer._markAllAsDirty();
  42. }
  43. public get idealHeight(): number {
  44. return this._idealHeight;
  45. }
  46. public set idealHeight(value: number) {
  47. if (this._idealHeight === value) {
  48. return;
  49. }
  50. this._idealHeight = value;
  51. this.markAsDirty();
  52. this._rootContainer._markAllAsDirty();
  53. }
  54. public get layer(): Layer {
  55. return this._layerToDispose;
  56. }
  57. constructor(name: string, width = 0, height = 0, scene: Scene, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE) {
  58. super(name, {width: width, height: height}, scene, generateMipMaps, samplingMode, Engine.TEXTUREFORMAT_RGBA);
  59. this._renderObserver = this.getScene().onBeforeCameraRenderObservable.add((camera: Camera) => this._checkUpdate(camera));
  60. this._rootContainer._link(null, this);
  61. this.hasAlpha = true;
  62. if (!width || !height) {
  63. this._resizeObserver = this.getScene().getEngine().onResizeObservable.add(() => this._onResize());
  64. this._onResize();
  65. }
  66. this._texture.isReady = true;
  67. }
  68. public executeOnAllControls(func: (control: Control) => void, container?: Container) {
  69. if (!container) {
  70. container = this._rootContainer;
  71. }
  72. for (var child of container.children) {
  73. if ((<any>child).children) {
  74. this.executeOnAllControls(func, (<Container>child));
  75. continue;
  76. }
  77. func(child);
  78. }
  79. }
  80. public markAsDirty() {
  81. this._isDirty = true;
  82. }
  83. public addControl(control: Control): AdvancedDynamicTexture {
  84. this._rootContainer.addControl(control);
  85. return this;
  86. }
  87. public removeControl(control: Control): AdvancedDynamicTexture {
  88. this._rootContainer.removeControl(control);
  89. return this;
  90. }
  91. public dispose() {
  92. this.getScene().onBeforeCameraRenderObservable.remove(this._renderObserver);
  93. if (this._resizeObserver) {
  94. this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
  95. }
  96. if (this._pointerMoveObserver) {
  97. this.getScene().onPrePointerObservable.remove(this._pointerMoveObserver);
  98. }
  99. if (this._pointerObserver) {
  100. this.getScene().onPointerObservable.remove(this._pointerObserver);
  101. }
  102. if (this._canvasBlurObserver) {
  103. this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
  104. }
  105. if (this._layerToDispose) {
  106. this._layerToDispose.texture = null;
  107. this._layerToDispose.dispose();
  108. this._layerToDispose = null;
  109. }
  110. super.dispose();
  111. }
  112. private _onResize(): void {
  113. // Check size
  114. var engine = this.getScene().getEngine();
  115. var textureSize = this.getSize();
  116. var renderWidth = engine.getRenderWidth();
  117. var renderHeight = engine.getRenderHeight();
  118. if (textureSize.width !== renderWidth || textureSize.height !== renderHeight) {
  119. this.scaleTo(renderWidth, renderHeight);
  120. this.markAsDirty();
  121. if (this._idealWidth || this._idealHeight) {
  122. this._rootContainer._markAllAsDirty();
  123. }
  124. }
  125. }
  126. private _checkUpdate(camera: Camera): void {
  127. if (this._layerToDispose) {
  128. if ((camera.layerMask & this._layerToDispose.layerMask) === 0) {
  129. return;
  130. }
  131. }
  132. if (this._isFullscreen && this._linkedControls.length) {
  133. var scene = this.getScene();
  134. var engine = scene.getEngine();
  135. var globalViewport = this._fullscreenViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  136. for (var control of this._linkedControls) {
  137. var mesh = control._linkedMesh;
  138. var position = mesh.getBoundingInfo().boundingSphere.center;
  139. var projectedPosition = Vector3.Project(position, mesh.getWorldMatrix(), scene.getTransformMatrix(), globalViewport);
  140. if (projectedPosition.z < 0 || projectedPosition.z > 1) {
  141. control.isVisible = false;
  142. continue;
  143. }
  144. control.isVisible = true;
  145. control._moveToProjectedPosition(projectedPosition);
  146. }
  147. }
  148. if (!this._isDirty && !this._rootContainer.isDirty) {
  149. return;
  150. }
  151. this._isDirty = false;
  152. this._render();
  153. this.update();
  154. }
  155. private _render(): void {
  156. var textureSize = this.getSize();
  157. var renderWidth = textureSize.width;
  158. var renderHeight = textureSize.height;
  159. // Clear
  160. var context = this.getContext();
  161. context.clearRect(0, 0, renderWidth, renderHeight);
  162. if (this._background) {
  163. context.save();
  164. context.fillStyle = this._background;
  165. context.fillRect(0, 0, renderWidth, renderHeight);
  166. context.restore();
  167. }
  168. // Render
  169. context.font = "18px Arial";
  170. var measure = new Measure(0, 0, renderWidth, renderHeight);
  171. this._rootContainer._draw(measure, context);
  172. }
  173. private _doPicking(x: number, y: number, type: number): void {
  174. if (this._capturingControl) {
  175. this._capturingControl._processObservables(type, x, y);
  176. return;
  177. }
  178. if (!this._rootContainer._processPicking(x, y, type)) {
  179. if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
  180. if (this._lastControlOver && this._lastControlOver.onPointerOutObservable.hasObservers()) {
  181. this._lastControlOver.onPointerOutObservable.notifyObservers(this._lastControlOver);
  182. }
  183. this._lastControlOver = null;
  184. }
  185. }
  186. }
  187. public attach(): void {
  188. var scene = this.getScene();
  189. this._pointerMoveObserver = scene.onPrePointerObservable.add((pi, state) => {
  190. if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
  191. && pi.type !== BABYLON.PointerEventTypes.POINTERUP
  192. && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
  193. return;
  194. }
  195. this._shouldBlockPointer = false;
  196. this._doPicking(scene.pointerX, scene.pointerY, pi.type);
  197. pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
  198. });
  199. this._attachToOnBlur(scene);
  200. }
  201. public attachToMesh(mesh: AbstractMesh): void {
  202. var scene = this.getScene();
  203. this._pointerObserver = scene.onPointerObservable.add((pi, state) => {
  204. if (pi.type !== BABYLON.PointerEventTypes.POINTERUP && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
  205. return;
  206. }
  207. if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
  208. var uv = pi.pickInfo.getTextureCoordinates();
  209. var size = this.getSize();
  210. this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type);
  211. } else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
  212. if (this._lastControlDown) {
  213. this._lastControlDown.forcePointerUp();
  214. }
  215. this._lastControlDown = null;
  216. }
  217. });
  218. this._attachToOnBlur(scene);
  219. }
  220. private _attachToOnBlur(scene: Scene): void {
  221. this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(() => {
  222. if (this._lastControlOver && this._lastControlOver.onPointerOutObservable.hasObservers()) {
  223. this._lastControlOver.onPointerOutObservable.notifyObservers(this._lastControlOver);
  224. }
  225. this._lastControlOver = null;
  226. if (this._lastControlDown) {
  227. this._lastControlDown.forcePointerUp();
  228. }
  229. this._lastControlDown = null;
  230. });
  231. }
  232. // Statics
  233. public static CreateForMesh(mesh: AbstractMesh, width = 1024, height = 1024): AdvancedDynamicTexture {
  234. var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, Texture.TRILINEAR_SAMPLINGMODE);
  235. var material = new BABYLON.StandardMaterial("AdvancedDynamicTextureMaterial", mesh.getScene());
  236. material.backFaceCulling = false;
  237. material.diffuseColor = BABYLON.Color3.Black();
  238. material.specularColor = BABYLON.Color3.Black();
  239. material.emissiveTexture = result;
  240. material.opacityTexture = result;
  241. mesh.material = material;
  242. result.attachToMesh(mesh);
  243. return result;
  244. }
  245. public static CreateFullscreenUI(name: string, foreground: boolean = true, scene: Scene = null): AdvancedDynamicTexture {
  246. var result = new AdvancedDynamicTexture(name, 0, 0, scene);
  247. // Display
  248. var layer = new BABYLON.Layer(name + "_layer", null, scene, !foreground);
  249. layer.texture = result;
  250. result._layerToDispose = layer;
  251. result._isFullscreen = true;
  252. // Attach
  253. result.attach();
  254. return result;
  255. }
  256. }
  257. }