/home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/generation/geometryBuilder.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/generation/geometryBuilder.js

  1. /**
  2. A **GeometryBuilder** is a builder that you can use to procedurally generate {{#crossLink "Geometry"}}Geometries{{/crossLink}}.
  3.  
  4. <a href="../../examples/#geometry_generation_wavyBlocks"><img src="http://i.giphy.com/26gJAMkOxAW5fWlb2.gif"></img></a>
  5.  
  6. ## Overview
  7.  
  8. * Implements the [Builder pattern](https://en.wikipedia.org/wiki/Builder_pattern).
  9. * Helps us improve WebGL performance by combining many shapes into the same {{#crossLink "Geometry"}}Geometries{{/crossLink}},
  10. thus reducing the number of draw calls.
  11. * A plain JavaScript class, ie. not a xeogl {{#crossLink "Component"}}{{/crossLink}} subclass.
  12.  
  13. ## Examples
  14.  
  15. * [Generating a 3D sine wave from boxes](../../examples/#geometry_generation_wavyBlocks)
  16.  
  17. ## Usage
  18.  
  19. * Works by accumulating additions to an internal buffer of geometry vertex and index arrays.
  20. * Call {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}} to set its current mesh, and
  21. {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} to set its current modelling transform.
  22. * Then, whenever you call {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}, it appends the shape, transformed
  23. by the matrix, to its internal buffer.
  24. * Finally, call {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} to dump its buffer into a target {{#crossLink "Geometry"}}{{/crossLink}}.
  25. * Retains its buffer so that you can call {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} again, to dump its
  26. buffer into other {{#crossLink "Geometry"}}Geometries{{/crossLink}} as needed.
  27. * Call {{#crossLink "GeometryBuilder/reset:method"}}reset(){{/crossLink}} to empty its buffer.
  28.  
  29. In the example below we'll use a GeometryBuilder to create something like the screen capture shown above.
  30.  
  31. ````javascript
  32. // Intatiate a GeometryBuilder; note that it's a
  33. // plain JavaScript object, not a xeogl Component subtype
  34. var geometryBuilder = new xeogl.GeometryBuilder();
  35.  
  36. // Set the current shape we'll be adding to our GeometryBuilder;
  37. // this can be a Geometry, or just an object containing vertex and indices arrays.
  38. geometryBuilder.setShape(new xeogl.BoxGeometry());
  39.  
  40. // Now add that shape many times, each time setting a different modelling matrix
  41. // on the GeometryBuilder. As we do this, we are accumulating geometry in a buffer
  42. // within the GeometryBuilder.
  43.  
  44. var matrix = xeogl.math.mat4();
  45. var height = 3;
  46. var height2 = height * 2;
  47. var x;
  48. var y;
  49. var z;
  50. var size = 200;
  51.  
  52. for (x = -size; x <= size; x += 2) {
  53. for (z = -size; z <= size; z += 2) {
  54.  
  55. y = ((Math.sin(x * 0.05) * height + Math.sin(z * 0.05) * height)) + height2;
  56.  
  57. xeogl.math.identityMat4(matrix); // Fresh matrix
  58. xeogl.math.scaleMat4c(.90, y, .90, matrix); // Post-concatenate scaling
  59. xeogl.math.translateMat4c(x, y, z, matrix); // Post-concatenate translation
  60.  
  61. geometryBuilder.setMatrix(matrix); // Set the current modeling transform matrix
  62.  
  63. geometryBuilder.addShape(); // Add current shape to the buffer, transformed by the matrix
  64. }
  65. }
  66.  
  67. var geometry = new xeogl.Geometry(); // Dump the buffer into a Geometry component
  68.  
  69. geometryBuilder.build(geometry);
  70.  
  71. var mesh = new xeogl.Mesh({ // Create an Mesh with our Geometry attached
  72. geometry: geometry,
  73. material: new xeogl.PhongMaterial({
  74. diffuse: [0.6, 0.6, 0.7]
  75. })
  76. });
  77.  
  78. mesh.scene.camera.eye = [-200, 50, -200]; // Set initial Camera position
  79.  
  80. new xeogl.CameraControl(); // Allow camera interaction
  81. ````
  82. @class GeometryBuilder
  83. @module xeogl
  84. @submodule generation
  85. @constructor
  86. */
  87. (function () {
  88.  
  89. "use strict";
  90.  
  91. xeogl.GeometryBuilder = function () {
  92. this.reset();
  93. };
  94.  
  95. /**
  96. * Sets the shape that will be added to this GeometryBuilder on each subsequent call to {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}.
  97. *
  98. * The shape can be either a {{#crossLink "Geometry"}}{{/crossLink}} or a JavaScript object containing vertex and index arrays.
  99. *
  100. * @method setShape
  101. * @param {Geometry|*} shape The shape to add.
  102. * @returns this
  103. */
  104. xeogl.GeometryBuilder.prototype.setShape = function (shape) {
  105. this._shape = shape;
  106. return this;
  107. };
  108.  
  109. /**
  110. * Sets the modeling transform matrix to apply to each shape added with subsequent calls to {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}.
  111. *
  112. * @method setMatrix
  113. * @param {Float32Array} matrix a 16-element transform matrix.
  114. * @returns this
  115. */
  116. xeogl.GeometryBuilder.prototype.setMatrix = function (matrix) {
  117. this._matrix.set(matrix);
  118. return this;
  119. };
  120.  
  121. /**
  122. * Adds a shape to this GeometryBuilder. The shape geometry is the one last added
  123. * by {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}, and will be transformed by the
  124. * matrix that was set by the last call to {{#crossLink "GeometryBuilder/build:method"}}setMatrix(){{/crossLink}}.
  125. *
  126. * A subsequent call to {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} will add all the
  127. * accumulated transformed shapes to a target {{#crossLink "Geometry"}}{{/crossLink}}.
  128. *
  129. * @method addShape
  130. * @returns this
  131. */
  132. xeogl.GeometryBuilder.prototype.addShape = (function () {
  133.  
  134. var math = xeogl.math;
  135.  
  136. var tempVec3a = math.vec3();
  137. var tempVec3b = math.vec3();
  138.  
  139. return function () {
  140.  
  141. var i;
  142. var len;
  143. var indicesBump = (this._positions) ? (this._positions.length / 3) : 0;
  144.  
  145. if (this._shape.positions) {
  146.  
  147. if (!this._positions) {
  148. this._positions = [];
  149. }
  150.  
  151. var positions = this._shape.positions;
  152.  
  153. if (!this._matrix) {
  154.  
  155. for (i = 0, len = positions.length; i < len; i++) {
  156. this._positions.push(positions[i]);
  157. }
  158.  
  159. } else {
  160.  
  161. for (i = 0, len = positions.length; i < len; i += 3) {
  162.  
  163. tempVec3a[0] = positions[i + 0];
  164. tempVec3a[1] = positions[i + 1];
  165. tempVec3a[2] = positions[i + 2];
  166.  
  167. math.transformPoint3(this._matrix, tempVec3a, tempVec3b);
  168.  
  169. this._positions.push(tempVec3b[0]);
  170. this._positions.push(tempVec3b[1]);
  171. this._positions.push(tempVec3b[2]);
  172. }
  173. }
  174. }
  175.  
  176. if (this._shape.normals) {
  177. if (!this._normals) {
  178. this._normals = [];
  179. }
  180. for (i = 0, len = this._shape.normals.length; i < len; i++) {
  181. this._normals.push(this._shape.normals[i]);
  182. }
  183. }
  184.  
  185. if (this._shape.uv) {
  186. if (!this._uv) {
  187. this._uv = [];
  188. }
  189. for (i = 0, len = this._shape.uv.length; i < len; i++) {
  190. this._uv.push(this._shape.uv[i]);
  191. }
  192. }
  193.  
  194. if (this._shape.colors) {
  195. if (!this._colors) {
  196. this._colors = [];
  197. }
  198. for (i = 0, len = this._shape.colors.length; i < len; i++) {
  199. this._colors.push(this._shape.colors[i]);
  200. }
  201. }
  202.  
  203. if (this._shape.indices) {
  204. if (!this._indices) {
  205. this._indices = [];
  206. }
  207. for (i = 0, len = this._shape.indices.length; i < len; i++) {
  208. this._indices.push(this._shape.indices[i] + indicesBump);
  209. }
  210. }
  211. };
  212. })();
  213.  
  214. /**
  215. * Returns the accumulated state from previous calls to {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} and
  216. * {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}}.
  217. *
  218. * Retains all that state afterwards, so that you can continue to call this method to add the state to
  219. * other {{#crossLink "Geometry"}}Geometries{{/crossLink}}.
  220. *
  221. * @method build
  222. * @returns {Object}
  223. */
  224. xeogl.GeometryBuilder.prototype.build = function (geometry) {
  225. return {
  226. primitive: this.primitive || "triangles",
  227. positions: this._positions,
  228. normals: this._normals,
  229. uv: this._uv,
  230. colors: this._colors,
  231. indices: this._indices
  232. };
  233. };
  234.  
  235. /**
  236. *
  237. * Resets this GeometryBuilder, clearing all the state previously accumulated with {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} and
  238. * {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}}.
  239. * @method reset
  240. * @returns this
  241. */
  242. xeogl.GeometryBuilder.prototype.reset = function () {
  243. this._positions = null;
  244. this._normals = null;
  245. this._uv = null;
  246. this._colors = null;
  247. this._indices = null;
  248. this._matrix = xeogl.math.identityMat4(xeogl.math.mat4());
  249. return this;
  250. };
  251.  
  252. })();
  253.