Source: core/graphics/webgl/GraphicsRenderer.js

core/graphics/webgl/GraphicsRenderer.js

  1. import { hex2rgb } from '../../utils';
  2. import { SHAPES } from '../../const';
  3. import ObjectRenderer from '../../renderers/webgl/utils/ObjectRenderer';
  4. import WebGLRenderer from '../../renderers/webgl/WebGLRenderer';
  5. import WebGLGraphicsData from './WebGLGraphicsData';
  6. import PrimitiveShader from './shaders/PrimitiveShader';
  7. import buildPoly from './utils/buildPoly';
  8. import buildRectangle from './utils/buildRectangle';
  9. import buildRoundedRectangle from './utils/buildRoundedRectangle';
  10. import buildCircle from './utils/buildCircle';
  11. /**
  12. * Renders the graphics object.
  13. *
  14. * @class
  15. * @memberof PIXI
  16. * @extends PIXI.ObjectRenderer
  17. */
  18. export default class GraphicsRenderer extends ObjectRenderer
  19. {
  20. /**
  21. * @param {PIXI.WebGLRenderer} renderer - The renderer this object renderer works for.
  22. */
  23. constructor(renderer)
  24. {
  25. super(renderer);
  26. this.graphicsDataPool = [];
  27. this.primitiveShader = null;
  28. this.gl = renderer.gl;
  29. // easy access!
  30. this.CONTEXT_UID = 0;
  31. }
  32. /**
  33. * Called when there is a WebGL context change
  34. *
  35. * @private
  36. *
  37. */
  38. onContextChange()
  39. {
  40. this.gl = this.renderer.gl;
  41. this.CONTEXT_UID = this.renderer.CONTEXT_UID;
  42. this.primitiveShader = new PrimitiveShader(this.gl);
  43. }
  44. /**
  45. * Destroys this renderer.
  46. *
  47. */
  48. destroy()
  49. {
  50. ObjectRenderer.prototype.destroy.call(this);
  51. for (let i = 0; i < this.graphicsDataPool.length; ++i)
  52. {
  53. this.graphicsDataPool[i].destroy();
  54. }
  55. this.graphicsDataPool = null;
  56. }
  57. /**
  58. * Renders a graphics object.
  59. *
  60. * @param {PIXI.Graphics} graphics - The graphics object to render.
  61. */
  62. render(graphics)
  63. {
  64. const renderer = this.renderer;
  65. const gl = renderer.gl;
  66. let webGLData;
  67. let webGL = graphics._webGL[this.CONTEXT_UID];
  68. if (!webGL || graphics.dirty !== webGL.dirty)
  69. {
  70. this.updateGraphics(graphics);
  71. webGL = graphics._webGL[this.CONTEXT_UID];
  72. }
  73. // This could be speeded up for sure!
  74. const shader = this.primitiveShader;
  75. renderer.bindShader(shader);
  76. renderer.state.setBlendMode(graphics.blendMode);
  77. for (let i = 0, n = webGL.data.length; i < n; i++)
  78. {
  79. webGLData = webGL.data[i];
  80. const shaderTemp = webGLData.shader;
  81. renderer.bindShader(shaderTemp);
  82. shaderTemp.uniforms.translationMatrix = graphics.transform.worldTransform.toArray(true);
  83. shaderTemp.uniforms.tint = hex2rgb(graphics.tint);
  84. shaderTemp.uniforms.alpha = graphics.worldAlpha;
  85. renderer.bindVao(webGLData.vao);
  86. if (webGLData.nativeLines)
  87. {
  88. gl.drawArrays(gl.LINES, 0, webGLData.points.length / 6);
  89. }
  90. else
  91. {
  92. webGLData.vao.draw(gl.TRIANGLE_STRIP, webGLData.indices.length);
  93. }
  94. }
  95. }
  96. /**
  97. * Updates the graphics object
  98. *
  99. * @private
  100. * @param {PIXI.Graphics} graphics - The graphics object to update
  101. */
  102. updateGraphics(graphics)
  103. {
  104. const gl = this.renderer.gl;
  105. // get the contexts graphics object
  106. let webGL = graphics._webGL[this.CONTEXT_UID];
  107. // if the graphics object does not exist in the webGL context time to create it!
  108. if (!webGL)
  109. {
  110. webGL = graphics._webGL[this.CONTEXT_UID] = { lastIndex: 0, data: [], gl, clearDirty: -1, dirty: -1 };
  111. }
  112. // flag the graphics as not dirty as we are about to update it...
  113. webGL.dirty = graphics.dirty;
  114. // if the user cleared the graphics object we will need to clear every object
  115. if (graphics.clearDirty !== webGL.clearDirty)
  116. {
  117. webGL.clearDirty = graphics.clearDirty;
  118. // loop through and return all the webGLDatas to the object pool so than can be reused later on
  119. for (let i = 0; i < webGL.data.length; i++)
  120. {
  121. this.graphicsDataPool.push(webGL.data[i]);
  122. }
  123. // clear the array and reset the index..
  124. webGL.data.length = 0;
  125. webGL.lastIndex = 0;
  126. }
  127. let webGLData;
  128. let webGLDataNativeLines;
  129. // loop through the graphics datas and construct each one..
  130. // if the object is a complex fill then the new stencil buffer technique will be used
  131. // other wise graphics objects will be pushed into a batch..
  132. for (let i = webGL.lastIndex; i < graphics.graphicsData.length; i++)
  133. {
  134. const data = graphics.graphicsData[i];
  135. // TODO - this can be simplified
  136. webGLData = this.getWebGLData(webGL, 0);
  137. if (data.nativeLines && data.lineWidth)
  138. {
  139. webGLDataNativeLines = this.getWebGLData(webGL, 0, true);
  140. webGL.lastIndex++;
  141. }
  142. if (data.type === SHAPES.POLY)
  143. {
  144. buildPoly(data, webGLData, webGLDataNativeLines);
  145. }
  146. if (data.type === SHAPES.RECT)
  147. {
  148. buildRectangle(data, webGLData, webGLDataNativeLines);
  149. }
  150. else if (data.type === SHAPES.CIRC || data.type === SHAPES.ELIP)
  151. {
  152. buildCircle(data, webGLData, webGLDataNativeLines);
  153. }
  154. else if (data.type === SHAPES.RREC)
  155. {
  156. buildRoundedRectangle(data, webGLData, webGLDataNativeLines);
  157. }
  158. webGL.lastIndex++;
  159. }
  160. this.renderer.bindVao(null);
  161. // upload all the dirty data...
  162. for (let i = 0; i < webGL.data.length; i++)
  163. {
  164. webGLData = webGL.data[i];
  165. if (webGLData.dirty)
  166. {
  167. webGLData.upload();
  168. }
  169. }
  170. }
  171. /**
  172. *
  173. * @private
  174. * @param {WebGLRenderingContext} gl - the current WebGL drawing context
  175. * @param {number} type - TODO @Alvin
  176. * @param {number} nativeLines - indicate whether the webGLData use for nativeLines.
  177. * @return {*} TODO
  178. */
  179. getWebGLData(gl, type, nativeLines)
  180. {
  181. let webGLData = gl.data[gl.data.length - 1];
  182. if (!webGLData || webGLData.nativeLines !== nativeLines || webGLData.points.length > 320000)
  183. {
  184. webGLData = this.graphicsDataPool.pop()
  185. || new WebGLGraphicsData(this.renderer.gl, this.primitiveShader, this.renderer.state.attribsState);
  186. webGLData.nativeLines = nativeLines;
  187. webGLData.reset(type);
  188. gl.data.push(webGLData);
  189. }
  190. webGLData.dirty = true;
  191. return webGLData;
  192. }
  193. }
  194. WebGLRenderer.registerPlugin('graphics', GraphicsRenderer);