Source: mesh/Mesh.js

mesh/Mesh.js

  1. import * as core from '../core';
  2. import Texture from '../core/textures/Texture';
  3. const tempPoint = new core.Point();
  4. const tempPolygon = new core.Polygon();
  5. /**
  6. * Base mesh class
  7. * @class
  8. * @extends PIXI.Container
  9. * @memberof PIXI.mesh
  10. */
  11. export default class Mesh extends core.Container
  12. {
  13. /**
  14. * @param {PIXI.Texture} texture - The texture to use
  15. * @param {Float32Array} [vertices] - if you want to specify the vertices
  16. * @param {Float32Array} [uvs] - if you want to specify the uvs
  17. * @param {Uint16Array} [indices] - if you want to specify the indices
  18. * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts
  19. */
  20. constructor(texture, vertices, uvs, indices, drawMode)
  21. {
  22. super();
  23. /**
  24. * The texture of the Mesh
  25. *
  26. * @member {PIXI.Texture}
  27. * @default PIXI.Texture.EMPTY
  28. * @private
  29. */
  30. this._texture = texture || Texture.EMPTY;
  31. /**
  32. * The Uvs of the Mesh
  33. *
  34. * @member {Float32Array}
  35. */
  36. this.uvs = uvs || new Float32Array([
  37. 0, 0,
  38. 1, 0,
  39. 1, 1,
  40. 0, 1]);
  41. /**
  42. * An array of vertices
  43. *
  44. * @member {Float32Array}
  45. */
  46. this.vertices = vertices || new Float32Array([
  47. 0, 0,
  48. 100, 0,
  49. 100, 100,
  50. 0, 100]);
  51. /**
  52. * An array containing the indices of the vertices
  53. *
  54. * @member {Uint16Array}
  55. */
  56. // TODO auto generate this based on draw mode!
  57. this.indices = indices || new Uint16Array([0, 1, 3, 2]);
  58. /**
  59. * Version of mesh uvs are dirty or not
  60. *
  61. * @member {number}
  62. */
  63. this.dirty = 0;
  64. /**
  65. * Version of mesh indices
  66. *
  67. * @member {number}
  68. */
  69. this.indexDirty = 0;
  70. /**
  71. * Version of mesh verticies array
  72. *
  73. * @member {number}
  74. */
  75. this.vertexDirty = 0;
  76. /**
  77. * For backwards compatibility the default is to re-upload verticies each render call.
  78. * Set this to `false` and increase `vertexDirty` to manually re-upload the buffer.
  79. *
  80. * @member {boolean}
  81. */
  82. this.autoUpdate = true;
  83. /**
  84. * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove
  85. * any blend mode.
  86. *
  87. * @member {number}
  88. * @default PIXI.BLEND_MODES.NORMAL
  89. * @see PIXI.BLEND_MODES
  90. */
  91. this.blendMode = core.BLEND_MODES.NORMAL;
  92. /**
  93. * Triangles in canvas mode are automatically antialiased, use this value to force triangles
  94. * to overlap a bit with each other.
  95. *
  96. * @member {number}
  97. */
  98. this.canvasPadding = core.settings.MESH_CANVAS_PADDING;
  99. /**
  100. * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts
  101. *
  102. * @member {number}
  103. * @see PIXI.mesh.Mesh.DRAW_MODES
  104. */
  105. this.drawMode = drawMode || Mesh.DRAW_MODES.TRIANGLE_MESH;
  106. /**
  107. * The default shader that is used if a mesh doesn't have a more specific one.
  108. *
  109. * @member {PIXI.Shader}
  110. */
  111. this.shader = null;
  112. /**
  113. * The tint applied to the mesh. This is a [r,g,b] value. A value of [1,1,1] will remove any
  114. * tint effect.
  115. *
  116. * @member {number}
  117. */
  118. this.tintRgb = new Float32Array([1, 1, 1]);
  119. /**
  120. * A map of renderer IDs to webgl render data
  121. *
  122. * @private
  123. * @member {object<number, object>}
  124. */
  125. this._glDatas = {};
  126. /**
  127. * transform that is applied to UV to get the texture coords
  128. * its updated independently from texture uvTransform
  129. * updates of uvs are tied to that thing
  130. *
  131. * @member {PIXI.TextureMatrix}
  132. * @private
  133. */
  134. this._uvTransform = new core.TextureMatrix(this._texture);
  135. /**
  136. * whether or not upload uvTransform to shader
  137. * if its false, then uvs should be pre-multiplied
  138. * if you change it for generated mesh, please call 'refresh(true)'
  139. * @member {boolean}
  140. * @default false
  141. */
  142. this.uploadUvTransform = false;
  143. /**
  144. * Plugin that is responsible for rendering this element.
  145. * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods.
  146. * @member {string}
  147. * @default 'mesh'
  148. */
  149. this.pluginName = 'mesh';
  150. }
  151. /**
  152. * Renders the object using the WebGL renderer
  153. *
  154. * @private
  155. * @param {PIXI.WebGLRenderer} renderer - a reference to the WebGL renderer
  156. */
  157. _renderWebGL(renderer)
  158. {
  159. this.refresh();
  160. renderer.setObjectRenderer(renderer.plugins[this.pluginName]);
  161. renderer.plugins[this.pluginName].render(this);
  162. }
  163. /**
  164. * Renders the object using the Canvas renderer
  165. *
  166. * @private
  167. * @param {PIXI.CanvasRenderer} renderer - The canvas renderer.
  168. */
  169. _renderCanvas(renderer)
  170. {
  171. this.refresh();
  172. renderer.plugins[this.pluginName].render(this);
  173. }
  174. /**
  175. * When the texture is updated, this event will fire to update the scale and frame
  176. *
  177. * @private
  178. */
  179. _onTextureUpdate()
  180. {
  181. this._uvTransform.texture = this._texture;
  182. this.refresh();
  183. }
  184. /**
  185. * multiplies uvs only if uploadUvTransform is false
  186. * call it after you change uvs manually
  187. * make sure that texture is valid
  188. */
  189. multiplyUvs()
  190. {
  191. if (!this.uploadUvTransform)
  192. {
  193. this._uvTransform.multiplyUvs(this.uvs);
  194. }
  195. }
  196. /**
  197. * Refreshes uvs for generated meshes (rope, plane)
  198. * sometimes refreshes vertices too
  199. *
  200. * @param {boolean} [forceUpdate=false] if true, matrices will be updated any case
  201. */
  202. refresh(forceUpdate)
  203. {
  204. if (this.autoUpdate)
  205. {
  206. this.vertexDirty++;
  207. }
  208. if (this._uvTransform.update(forceUpdate))
  209. {
  210. this._refresh();
  211. }
  212. }
  213. /**
  214. * re-calculates mesh coords
  215. * @protected
  216. */
  217. _refresh()
  218. {
  219. /* empty */
  220. }
  221. /**
  222. * Returns the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account.
  223. *
  224. */
  225. _calculateBounds()
  226. {
  227. // TODO - we can cache local bounds and use them if they are dirty (like graphics)
  228. this._bounds.addVertices(this.transform, this.vertices, 0, this.vertices.length);
  229. }
  230. /**
  231. * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH
  232. *
  233. * @param {PIXI.Point} point - the point to test
  234. * @return {boolean} the result of the test
  235. */
  236. containsPoint(point)
  237. {
  238. if (!this.getBounds().contains(point.x, point.y))
  239. {
  240. return false;
  241. }
  242. this.worldTransform.applyInverse(point, tempPoint);
  243. const vertices = this.vertices;
  244. const points = tempPolygon.points;
  245. const indices = this.indices;
  246. const len = this.indices.length;
  247. const step = this.drawMode === Mesh.DRAW_MODES.TRIANGLES ? 3 : 1;
  248. for (let i = 0; i + 2 < len; i += step)
  249. {
  250. const ind0 = indices[i] * 2;
  251. const ind1 = indices[i + 1] * 2;
  252. const ind2 = indices[i + 2] * 2;
  253. points[0] = vertices[ind0];
  254. points[1] = vertices[ind0 + 1];
  255. points[2] = vertices[ind1];
  256. points[3] = vertices[ind1 + 1];
  257. points[4] = vertices[ind2];
  258. points[5] = vertices[ind2 + 1];
  259. if (tempPolygon.contains(tempPoint.x, tempPoint.y))
  260. {
  261. return true;
  262. }
  263. }
  264. return false;
  265. }
  266. /**
  267. * The texture that the mesh uses.
  268. *
  269. * @member {PIXI.Texture}
  270. */
  271. get texture()
  272. {
  273. return this._texture;
  274. }
  275. set texture(value) // eslint-disable-line require-jsdoc
  276. {
  277. if (this._texture === value)
  278. {
  279. return;
  280. }
  281. this._texture = value;
  282. if (value)
  283. {
  284. // wait for the texture to load
  285. if (value.baseTexture.hasLoaded)
  286. {
  287. this._onTextureUpdate();
  288. }
  289. else
  290. {
  291. value.once('update', this._onTextureUpdate, this);
  292. }
  293. }
  294. }
  295. /**
  296. * The tint applied to the mesh. This is a hex value. A value of 0xFFFFFF will remove any tint effect.
  297. *
  298. * @member {number}
  299. * @default 0xFFFFFF
  300. */
  301. get tint()
  302. {
  303. return core.utils.rgb2hex(this.tintRgb);
  304. }
  305. set tint(value) // eslint-disable-line require-jsdoc
  306. {
  307. this.tintRgb = core.utils.hex2rgb(value, this.tintRgb);
  308. }
  309. /**
  310. * Destroys the Mesh object.
  311. *
  312. * @param {object|boolean} [options] - Options parameter. A boolean will act as if all
  313. * options have been set to that value
  314. * @param {boolean} [options.children=false] - if set to true, all the children will have
  315. * their destroy method called as well. 'options' will be passed on to those calls.
  316. * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true
  317. * Should it destroy the texture of the child sprite
  318. * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true
  319. * Should it destroy the base texture of the child sprite
  320. */
  321. destroy(options)
  322. {
  323. // for each webgl data entry, destroy the WebGLGraphicsData
  324. for (const id in this._glDatas)
  325. {
  326. const data = this._glDatas[id];
  327. if (data.destroy)
  328. {
  329. data.destroy();
  330. }
  331. else
  332. {
  333. if (data.vertexBuffer)
  334. {
  335. data.vertexBuffer.destroy();
  336. data.vertexBuffer = null;
  337. }
  338. if (data.indexBuffer)
  339. {
  340. data.indexBuffer.destroy();
  341. data.indexBuffer = null;
  342. }
  343. if (data.uvBuffer)
  344. {
  345. data.uvBuffer.destroy();
  346. data.uvBuffer = null;
  347. }
  348. if (data.vao)
  349. {
  350. data.vao.destroy();
  351. data.vao = null;
  352. }
  353. }
  354. }
  355. this._glDatas = null;
  356. super.destroy(options);
  357. }
  358. }
  359. /**
  360. * Different drawing buffer modes supported
  361. *
  362. * @static
  363. * @constant
  364. * @type {object}
  365. * @property {number} TRIANGLE_MESH
  366. * @property {number} TRIANGLES
  367. */
  368. Mesh.DRAW_MODES = {
  369. TRIANGLE_MESH: 0,
  370. TRIANGLES: 1,
  371. };