babylon.tools.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. module BABYLON {
  2. declare var FilesTextures; //ANY
  3. export interface IAnimatable {
  4. animations: Array<Animation>;
  5. }
  6. export interface ISize {
  7. width: number;
  8. height: number;
  9. }
  10. // FPS
  11. var fpsRange = 60;
  12. var previousFramesDuration = [];
  13. var fps = 60;
  14. var deltaTime = 0;
  15. var cloneValue = (source, destinationObject) => {
  16. if (!source)
  17. return null;
  18. if (source instanceof Mesh) {
  19. return null;
  20. }
  21. if (source instanceof SubMesh) {
  22. return source.clone(destinationObject);
  23. } else if (source.clone) {
  24. return source.clone();
  25. }
  26. return null;
  27. };
  28. export class Tools {
  29. public static BaseUrl = "";
  30. public static GetFilename(path: string): string {
  31. var index = path.lastIndexOf("/");
  32. if (index < 0)
  33. return path;
  34. return path.substring(index + 1);
  35. }
  36. public static GetDOMTextContent(element: HTMLElement): string {
  37. var result = "";
  38. var child = element.firstChild;
  39. while (child) {
  40. if (child.nodeType == 3) {
  41. result += child.textContent;
  42. }
  43. child = child.nextSibling;
  44. }
  45. return result;
  46. }
  47. public static ToDegrees(angle: number): number {
  48. return angle * 180 / Math.PI;
  49. }
  50. public static ToRadians(angle: number): number {
  51. return angle * Math.PI / 180;
  52. }
  53. public static ExtractMinAndMax(positions: number[], start: number, count: number): { minimum: Vector3; maximum: Vector3 } {
  54. var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  55. var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  56. for (var index = start; index < start + count; index++) {
  57. var current = new Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
  58. minimum = BABYLON.Vector3.Minimize(current, minimum);
  59. maximum = BABYLON.Vector3.Maximize(current, maximum);
  60. }
  61. return {
  62. minimum: minimum,
  63. maximum: maximum
  64. };
  65. }
  66. public static MakeArray(obj, allowsNullUndefined: boolean): Array<any> {
  67. if (allowsNullUndefined !== true && (obj === undefined || obj == null))
  68. return undefined;
  69. return Array.isArray(obj) ? obj : [obj];
  70. }
  71. // Misc.
  72. public static GetPointerPrefix(): string {
  73. var eventPrefix = "pointer";
  74. // Check if hand.js is referenced or if the browser natively supports pointer events
  75. if (!navigator.pointerEnabled) {
  76. eventPrefix = "mouse";
  77. }
  78. return eventPrefix;
  79. }
  80. public static QueueNewFrame(func): void {
  81. if (window.requestAnimationFrame)
  82. window.requestAnimationFrame(func);
  83. else if (window.msRequestAnimationFrame)
  84. window.msRequestAnimationFrame(func);
  85. else if (window.webkitRequestAnimationFrame)
  86. window.webkitRequestAnimationFrame(func);
  87. else if (window.mozRequestAnimationFrame)
  88. window.mozRequestAnimationFrame(func);
  89. else if (window.oRequestAnimationFrame)
  90. window.oRequestAnimationFrame(func);
  91. else {
  92. window.setTimeout(func, 16);
  93. }
  94. }
  95. public static RequestFullscreen(element): void {
  96. if (element.requestFullscreen)
  97. element.requestFullscreen();
  98. else if (element.msRequestFullscreen)
  99. element.msRequestFullscreen();
  100. else if (element.webkitRequestFullscreen)
  101. element.webkitRequestFullscreen();
  102. else if (element.mozRequestFullScreen)
  103. element.mozRequestFullScreen();
  104. }
  105. public static ExitFullscreen(): void {
  106. if (document.exitFullscreen) {
  107. document.exitFullscreen();
  108. }
  109. else if (document.mozCancelFullScreen) {
  110. document.mozCancelFullScreen();
  111. }
  112. else if (document.webkitCancelFullScreen) {
  113. document.webkitCancelFullScreen();
  114. }
  115. else if (document.msCancelFullScreen) {
  116. document.msCancelFullScreen();
  117. }
  118. }
  119. // External files
  120. public static LoadImage(url: string, onload, onerror, database): HTMLImageElement {
  121. var img = new Image();
  122. img.crossOrigin = 'anonymous';
  123. img.onload = () => {
  124. onload(img);
  125. };
  126. img.onerror = err => {
  127. onerror(img, err);
  128. };
  129. var noIndexedDB = () => {
  130. img.src = url;
  131. };
  132. var loadFromIndexedDB = () => {
  133. database.loadImageFromDB(url, img);
  134. };
  135. //ANY database to do!
  136. if (database && database.enableTexturesOffline) { //ANY } && BABYLON.Database.isUASupportingBlobStorage) {
  137. database.openAsync(loadFromIndexedDB, noIndexedDB);
  138. }
  139. else {
  140. if (url.indexOf("file:") === -1) {
  141. noIndexedDB();
  142. }
  143. else {
  144. try {
  145. var textureName = url.substring(5);
  146. var blobURL;
  147. try {
  148. blobURL = URL.createObjectURL(FilesTextures[textureName], { oneTimeOnly: true });
  149. }
  150. catch (ex) {
  151. // Chrome doesn't support oneTimeOnly parameter
  152. blobURL = URL.createObjectURL(FilesTextures[textureName]);
  153. }
  154. img.src = blobURL;
  155. }
  156. catch (e) {
  157. console.log("Error while trying to load texture: " + textureName);
  158. img.src = null;
  159. }
  160. }
  161. }
  162. return img;
  163. }
  164. //ANY
  165. public static LoadFile(url: string, callback: (data: any) => void, progressCallBack?: () => void, database?, useArrayBuffer?: boolean): void {
  166. var noIndexedDB = () => {
  167. var request = new XMLHttpRequest();
  168. var loadUrl = Tools.BaseUrl + url;
  169. request.open('GET', loadUrl, true);
  170. if (useArrayBuffer) {
  171. request.responseType = "arraybuffer";
  172. }
  173. request.onprogress = progressCallBack;
  174. request.onreadystatechange = () => {
  175. if (request.readyState == 4) {
  176. if (request.status == 200) {
  177. callback(!useArrayBuffer ? request.responseText : request.response);
  178. } else { // Failed
  179. throw new Error("Error status: " + request.status + " - Unable to load " + loadUrl);
  180. }
  181. }
  182. };
  183. request.send(null);
  184. };
  185. var loadFromIndexedDB = () => {
  186. database.loadSceneFromDB(url, callback, progressCallBack, noIndexedDB);
  187. };
  188. // Caching only scenes files
  189. if (database && url.indexOf(".babylon") !== -1 && (database.enableSceneOffline)) {
  190. database.openAsync(loadFromIndexedDB, noIndexedDB);
  191. }
  192. else {
  193. noIndexedDB();
  194. }
  195. }
  196. public static ReadFile(fileToLoad, callback, progressCallBack): void {
  197. var reader = new FileReader();
  198. reader.onload = e => {
  199. callback(e.target.result);
  200. };
  201. reader.onprogress = progressCallBack;
  202. // Asynchronous read
  203. reader.readAsText(fileToLoad);
  204. }
  205. // Misc.
  206. public static WithinEpsilon(a: number, b: number): boolean {
  207. var num = a - b;
  208. return -1.401298E-45 <= num && num <= 1.401298E-45;
  209. }
  210. public static DeepCopy(source, destination, doNotCopyList?: string[], mustCopyList?: string[]): void {
  211. for (var prop in source) {
  212. if (prop[0] === "_" && (!mustCopyList || mustCopyList.indexOf(prop) === -1)) {
  213. continue;
  214. }
  215. if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) {
  216. continue;
  217. }
  218. var sourceValue = source[prop];
  219. var typeOfSourceValue = typeof sourceValue;
  220. if (typeOfSourceValue == "function") {
  221. continue;
  222. }
  223. if (typeOfSourceValue == "object") {
  224. if (sourceValue instanceof Array) {
  225. destination[prop] = [];
  226. if (sourceValue.length > 0) {
  227. if (typeof sourceValue[0] == "object") {
  228. for (var index = 0; index < sourceValue.length; index++) {
  229. var clonedValue = cloneValue(sourceValue[index], destination);
  230. if (destination[prop].indexOf(clonedValue) === -1) { // Test if auto inject was not done
  231. destination[prop].push(clonedValue);
  232. }
  233. }
  234. } else {
  235. destination[prop] = sourceValue.slice(0);
  236. }
  237. }
  238. } else {
  239. destination[prop] = cloneValue(sourceValue, destination);
  240. }
  241. } else {
  242. destination[prop] = sourceValue;
  243. }
  244. }
  245. }
  246. public static IsEmpty(obj): boolean {
  247. for (var i in obj) {
  248. return false;
  249. }
  250. return true;
  251. }
  252. public static GetFps(): number {
  253. return fps;
  254. }
  255. public static GetDeltaTime(): number {
  256. return deltaTime;
  257. }
  258. public static _MeasureFps(): void {
  259. previousFramesDuration.push((new Date).getTime());
  260. var length = previousFramesDuration.length;
  261. if (length >= 2) {
  262. deltaTime = previousFramesDuration[length - 1] - previousFramesDuration[length - 2];
  263. }
  264. if (length >= fpsRange) {
  265. if (length > fpsRange) {
  266. previousFramesDuration.splice(0, 1);
  267. length = previousFramesDuration.length;
  268. }
  269. var sum = 0;
  270. for (var id = 0; id < length - 1; id++) {
  271. sum += previousFramesDuration[id + 1] - previousFramesDuration[id];
  272. }
  273. fps = 1000.0 / (sum / (length - 1));
  274. }
  275. }
  276. }
  277. }