Source: core/utils/index.js

core/utils/index.js

  1. import { DATA_URI, URL_FILE_EXTENSION, SVG_SIZE, VERSION } from '../const';
  2. import settings from '../settings';
  3. import EventEmitter from 'eventemitter3';
  4. import pluginTarget from './pluginTarget';
  5. import * as mixins from './mixin';
  6. // 修改依赖库应对小程序环境
  7. import * as isMobile from '../../dependencies/isMobile';
  8. // import * as isMobile from 'ismobilejs';
  9. import removeItems from 'remove-array-items';
  10. import mapPremultipliedBlendModes from './mapPremultipliedBlendModes';
  11. import earcut from 'earcut';
  12. //引入小程序补丁
  13. import {windowAlias, documentAlias, navigator} from '@ali/pixi-miniprogram-adapter';
  14. let nextUid = 0;
  15. let saidHello = false;
  16. /**
  17. * Generalized convenience utilities for PIXI.
  18. * @example
  19. * // Extend PIXI's internal Event Emitter.
  20. * class MyEmitter extends PIXI.utils.EventEmitter {
  21. * constructor() {
  22. * super();
  23. * console.log("Emitter created!");
  24. * }
  25. * }
  26. *
  27. * // Get info on current device
  28. * console.log(PIXI.utils.isMobile);
  29. *
  30. * // Convert hex color to string
  31. * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
  32. * @namespace PIXI.utils
  33. */
  34. export {
  35. /**
  36. * @see {@link https://github.com/kaimallea/isMobile}
  37. *
  38. * @memberof PIXI.utils
  39. * @function isMobile
  40. * @type {Object}
  41. */
  42. isMobile,
  43. /**
  44. * @see {@link https://github.com/mreinstein/remove-array-items}
  45. *
  46. * @memberof PIXI.utils
  47. * @function removeItems
  48. * @type {Object}
  49. */
  50. removeItems,
  51. /**
  52. * @see {@link https://github.com/primus/eventemitter3}
  53. *
  54. * @memberof PIXI.utils
  55. * @class EventEmitter
  56. * @type {EventEmitter}
  57. */
  58. EventEmitter,
  59. /**
  60. * @memberof PIXI.utils
  61. * @function pluginTarget
  62. * @type {mixin}
  63. */
  64. pluginTarget,
  65. mixins,
  66. /**
  67. * @see {@link https://github.com/mapbox/earcut}
  68. *
  69. * @memberof PIXI.utils
  70. * @function earcut
  71. * @param {number[]} vertices - A flat array of vertice coordinates
  72. * @param {number[]} [holes] - An array of hole indices
  73. * @param {number} [dimensions=2] The number of coordinates per vertice in the input array
  74. * @return {number[]} Triangulated polygon
  75. */
  76. earcut,
  77. };
  78. /**
  79. * Gets the next unique identifier
  80. *
  81. * @memberof PIXI.utils
  82. * @function uid
  83. * @return {number} The next unique identifier to use.
  84. */
  85. export function uid()
  86. {
  87. return ++nextUid;
  88. }
  89. /**
  90. * Converts a hex color number to an [R, G, B] array
  91. *
  92. * @memberof PIXI.utils
  93. * @function hex2rgb
  94. * @param {number} hex - The number to convert
  95. * @param {number[]} [out=[]] If supplied, this array will be used rather than returning a new one
  96. * @return {number[]} An array representing the [R, G, B] of the color.
  97. */
  98. export function hex2rgb(hex, out)
  99. {
  100. out = out || [];
  101. out[0] = ((hex >> 16) & 0xFF) / 255;
  102. out[1] = ((hex >> 8) & 0xFF) / 255;
  103. out[2] = (hex & 0xFF) / 255;
  104. return out;
  105. }
  106. /**
  107. * Converts a hex color number to a string.
  108. *
  109. * @memberof PIXI.utils
  110. * @function hex2string
  111. * @param {number} hex - Number in hex
  112. * @return {string} The string color.
  113. */
  114. export function hex2string(hex)
  115. {
  116. hex = hex.toString(16);
  117. hex = '000000'.substr(0, 6 - hex.length) + hex;
  118. return `#${hex}`;
  119. }
  120. /**
  121. * Converts a color as an [R, G, B] array to a hex number
  122. *
  123. * @memberof PIXI.utils
  124. * @function rgb2hex
  125. * @param {number[]} rgb - rgb array
  126. * @return {number} The color number
  127. */
  128. export function rgb2hex(rgb)
  129. {
  130. return (((rgb[0] * 255) << 16) + ((rgb[1] * 255) << 8) + (rgb[2] * 255 | 0));
  131. }
  132. /**
  133. * get the resolution / device pixel ratio of an asset by looking for the prefix
  134. * used by spritesheets and image urls
  135. *
  136. * @memberof PIXI.utils
  137. * @function getResolutionOfUrl
  138. * @param {string} url - the image path
  139. * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set.
  140. * @return {number} resolution / device pixel ratio of an asset
  141. */
  142. export function getResolutionOfUrl(url, defaultValue)
  143. {
  144. const resolution = settings.RETINA_PREFIX.exec(url);
  145. if (resolution)
  146. {
  147. return parseFloat(resolution[1]);
  148. }
  149. return defaultValue !== undefined ? defaultValue : 1;
  150. }
  151. /**
  152. * Typedef for decomposeDataUri return object.
  153. *
  154. * @typedef {object} PIXI.utils~DecomposedDataUri
  155. * @property {mediaType} Media type, eg. `image`
  156. * @property {subType} Sub type, eg. `png`
  157. * @property {encoding} Data encoding, eg. `base64`
  158. * @property {data} The actual data
  159. */
  160. /**
  161. * Split a data URI into components. Returns undefined if
  162. * parameter `dataUri` is not a valid data URI.
  163. *
  164. * @memberof PIXI.utils
  165. * @function decomposeDataUri
  166. * @param {string} dataUri - the data URI to check
  167. * @return {PIXI.utils~DecomposedDataUri|undefined} The decomposed data uri or undefined
  168. */
  169. export function decomposeDataUri(dataUri)
  170. {
  171. const dataUriMatch = DATA_URI.exec(dataUri);
  172. if (dataUriMatch)
  173. {
  174. return {
  175. mediaType: dataUriMatch[1] ? dataUriMatch[1].toLowerCase() : undefined,
  176. subType: dataUriMatch[2] ? dataUriMatch[2].toLowerCase() : undefined,
  177. charset: dataUriMatch[3] ? dataUriMatch[3].toLowerCase() : undefined,
  178. encoding: dataUriMatch[4] ? dataUriMatch[4].toLowerCase() : undefined,
  179. data: dataUriMatch[5],
  180. };
  181. }
  182. return undefined;
  183. }
  184. /**
  185. * Get type of the image by regexp for extension. Returns undefined for unknown extensions.
  186. *
  187. * @memberof PIXI.utils
  188. * @function getUrlFileExtension
  189. * @param {string} url - the image path
  190. * @return {string|undefined} image extension
  191. */
  192. export function getUrlFileExtension(url)
  193. {
  194. const extension = URL_FILE_EXTENSION.exec(url);
  195. if (extension)
  196. {
  197. return extension[1].toLowerCase();
  198. }
  199. return undefined;
  200. }
  201. /**
  202. * Typedef for Size object.
  203. *
  204. * @typedef {object} PIXI.utils~Size
  205. * @property {width} Width component
  206. * @property {height} Height component
  207. */
  208. /**
  209. * Get size from an svg string using regexp.
  210. *
  211. * @memberof PIXI.utils
  212. * @function getSvgSize
  213. * @param {string} svgString - a serialized svg element
  214. * @return {PIXI.utils~Size|undefined} image extension
  215. */
  216. export function getSvgSize(svgString)
  217. {
  218. const sizeMatch = SVG_SIZE.exec(svgString);
  219. const size = {};
  220. if (sizeMatch)
  221. {
  222. size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[3]));
  223. size[sizeMatch[5]] = Math.round(parseFloat(sizeMatch[7]));
  224. }
  225. return size;
  226. }
  227. /**
  228. * Skips the hello message of renderers that are created after this is run.
  229. *
  230. * @function skipHello
  231. * @memberof PIXI.utils
  232. */
  233. export function skipHello()
  234. {
  235. saidHello = true;
  236. }
  237. /**
  238. * Logs out the version and renderer information for this running instance of PIXI.
  239. * If you don't want to see this message you can run `PIXI.utils.skipHello()` before
  240. * creating your renderer. Keep in mind that doing that will forever makes you a jerk face.
  241. *
  242. * @static
  243. * @function sayHello
  244. * @memberof PIXI.utils
  245. * @param {string} type - The string renderer type to log.
  246. */
  247. export function sayHello(type)
  248. {
  249. if (saidHello)
  250. {
  251. return;
  252. }
  253. console.log(`Ali Miniprogram PixiJS ${VERSION} - ${type} - http://www.pixijs.com/`);
  254. saidHello = true;
  255. }
  256. /**
  257. * Helper for checking for webgl support
  258. *
  259. * @memberof PIXI.utils
  260. * @function isWebGLSupported
  261. * @return {boolean} is webgl supported
  262. */
  263. export function isWebGLSupported()
  264. {
  265. const contextOptions = { stencil: true, failIfMajorPerformanceCaveat: true };
  266. // //!!!!!!注意 小程序安卓端gl某些方法返回为空,暂时return如下逻辑,避免报错
  267. // return true;
  268. try
  269. {
  270. // 小程序中window无 WebGLRenderingContext故 去除此项判断
  271. // if (!windowAlias.WebGLRenderingContext)
  272. // {
  273. // return false;
  274. // }
  275. const canvas = documentAlias.createElement('canvas');
  276. let gl = canvas.getContext('webgl', contextOptions) || canvas.getContext('experimental-webgl', contextOptions);
  277. //小程序中webgl 的 getContextAttributes 无stencil 故 去除此项判断
  278. //const success = !!(gl && gl.getContextAttributes().stencil);
  279. const success = !!(gl);
  280. if (gl)
  281. {
  282. const loseContext = gl.getExtension('WEBGL_lose_context');
  283. if (loseContext)
  284. {
  285. loseContext.loseContext();
  286. }
  287. }
  288. gl = null;
  289. return success;
  290. }
  291. catch (e)
  292. {
  293. return false;
  294. }
  295. }
  296. /**
  297. * Returns sign of number
  298. *
  299. * @memberof PIXI.utils
  300. * @function sign
  301. * @param {number} n - the number to check the sign of
  302. * @returns {number} 0 if `n` is 0, -1 if `n` is negative, 1 if `n` is positive
  303. */
  304. export function sign(n)
  305. {
  306. if (n === 0) return 0;
  307. return n < 0 ? -1 : 1;
  308. }
  309. /**
  310. * @todo Describe property usage
  311. *
  312. * @memberof PIXI.utils
  313. * @private
  314. */
  315. export const TextureCache = Object.create(null);
  316. /**
  317. * @todo Describe property usage
  318. *
  319. * @memberof PIXI.utils
  320. * @private
  321. */
  322. export const BaseTextureCache = Object.create(null);
  323. /**
  324. * Destroys all texture in the cache
  325. *
  326. * @memberof PIXI.utils
  327. * @function destroyTextureCache
  328. */
  329. export function destroyTextureCache()
  330. {
  331. let key;
  332. for (key in TextureCache)
  333. {
  334. TextureCache[key].destroy();
  335. }
  336. for (key in BaseTextureCache)
  337. {
  338. BaseTextureCache[key].destroy();
  339. }
  340. }
  341. /**
  342. * Removes all textures from cache, but does not destroy them
  343. *
  344. * @memberof PIXI.utils
  345. * @function clearTextureCache
  346. */
  347. export function clearTextureCache()
  348. {
  349. let key;
  350. for (key in TextureCache)
  351. {
  352. delete TextureCache[key];
  353. }
  354. for (key in BaseTextureCache)
  355. {
  356. delete BaseTextureCache[key];
  357. }
  358. }
  359. /**
  360. * maps premultiply flag and blendMode to adjusted blendMode
  361. * @memberof PIXI.utils
  362. * @const premultiplyBlendMode
  363. * @type {Array<number[]>}
  364. */
  365. export const premultiplyBlendMode = mapPremultipliedBlendModes();
  366. /**
  367. * changes blendMode according to texture format
  368. *
  369. * @memberof PIXI.utils
  370. * @function correctBlendMode
  371. * @param {number} blendMode supposed blend mode
  372. * @param {boolean} premultiplied whether source is premultiplied
  373. * @returns {number} true blend mode for this texture
  374. */
  375. export function correctBlendMode(blendMode, premultiplied)
  376. {
  377. return premultiplyBlendMode[premultiplied ? 1 : 0][blendMode];
  378. }
  379. /**
  380. * premultiplies tint
  381. *
  382. * @memberof PIXI.utils
  383. * @param {number} tint integet RGB
  384. * @param {number} alpha floating point alpha (0.0-1.0)
  385. * @returns {number} tint multiplied by alpha
  386. */
  387. export function premultiplyTint(tint, alpha)
  388. {
  389. if (alpha === 1.0)
  390. {
  391. return (alpha * 255 << 24) + tint;
  392. }
  393. if (alpha === 0.0)
  394. {
  395. return 0;
  396. }
  397. let R = ((tint >> 16) & 0xFF);
  398. let G = ((tint >> 8) & 0xFF);
  399. let B = (tint & 0xFF);
  400. R = ((R * alpha) + 0.5) | 0;
  401. G = ((G * alpha) + 0.5) | 0;
  402. B = ((B * alpha) + 0.5) | 0;
  403. return (alpha * 255 << 24) + (R << 16) + (G << 8) + B;
  404. }
  405. /**
  406. * combines rgb and alpha to out array
  407. *
  408. * @memberof PIXI.utils
  409. * @param {Float32Array|number[]} rgb input rgb
  410. * @param {number} alpha alpha param
  411. * @param {Float32Array} [out] output
  412. * @param {boolean} [premultiply=true] do premultiply it
  413. * @returns {Float32Array} vec4 rgba
  414. */
  415. export function premultiplyRgba(rgb, alpha, out, premultiply)
  416. {
  417. out = out || new Float32Array(4);
  418. if (premultiply || premultiply === undefined)
  419. {
  420. out[0] = rgb[0] * alpha;
  421. out[1] = rgb[1] * alpha;
  422. out[2] = rgb[2] * alpha;
  423. }
  424. else
  425. {
  426. out[0] = rgb[0];
  427. out[1] = rgb[1];
  428. out[2] = rgb[2];
  429. }
  430. out[3] = alpha;
  431. return out;
  432. }
  433. /**
  434. * converts integer tint and float alpha to vec4 form, premultiplies by default
  435. *
  436. * @memberof PIXI.utils
  437. * @param {number} tint input tint
  438. * @param {number} alpha alpha param
  439. * @param {Float32Array} [out] output
  440. * @param {boolean} [premultiply=true] do premultiply it
  441. * @returns {Float32Array} vec4 rgba
  442. */
  443. export function premultiplyTintToRgba(tint, alpha, out, premultiply)
  444. {
  445. out = out || new Float32Array(4);
  446. out[0] = ((tint >> 16) & 0xFF) / 255.0;
  447. out[1] = ((tint >> 8) & 0xFF) / 255.0;
  448. out[2] = (tint & 0xFF) / 255.0;
  449. if (premultiply || premultiply === undefined)
  450. {
  451. out[0] *= alpha;
  452. out[1] *= alpha;
  453. out[2] *= alpha;
  454. }
  455. out[3] = alpha;
  456. return out;
  457. }