File: /home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/generation/geometryBuilder.js
- /**
- A **GeometryBuilder** is a builder that you can use to procedurally generate {{#crossLink "Geometry"}}Geometries{{/crossLink}}.
-
- <a href="../../examples/#geometry_generation_wavyBlocks"><img src="http://i.giphy.com/26gJAMkOxAW5fWlb2.gif"></img></a>
-
- ## Overview
-
- * Implements the [Builder pattern](https://en.wikipedia.org/wiki/Builder_pattern).
- * Helps us improve WebGL performance by combining many shapes into the same {{#crossLink "Geometry"}}Geometries{{/crossLink}},
- thus reducing the number of draw calls.
- * A plain JavaScript class, ie. not a xeogl {{#crossLink "Component"}}{{/crossLink}} subclass.
-
- ## Examples
-
- * [Generating a 3D sine wave from boxes](../../examples/#geometry_generation_wavyBlocks)
-
- ## Usage
-
- * Works by accumulating additions to an internal buffer of geometry vertex and index arrays.
- * Call {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}} to set its current mesh, and
- {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} to set its current modelling transform.
- * Then, whenever you call {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}, it appends the shape, transformed
- by the matrix, to its internal buffer.
- * Finally, call {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} to dump its buffer into a target {{#crossLink "Geometry"}}{{/crossLink}}.
- * Retains its buffer so that you can call {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} again, to dump its
- buffer into other {{#crossLink "Geometry"}}Geometries{{/crossLink}} as needed.
- * Call {{#crossLink "GeometryBuilder/reset:method"}}reset(){{/crossLink}} to empty its buffer.
-
- In the example below we'll use a GeometryBuilder to create something like the screen capture shown above.
-
- ````javascript
- // Intatiate a GeometryBuilder; note that it's a
- // plain JavaScript object, not a xeogl Component subtype
- var geometryBuilder = new xeogl.GeometryBuilder();
-
- // Set the current shape we'll be adding to our GeometryBuilder;
- // this can be a Geometry, or just an object containing vertex and indices arrays.
- geometryBuilder.setShape(new xeogl.BoxGeometry());
-
- // Now add that shape many times, each time setting a different modelling matrix
- // on the GeometryBuilder. As we do this, we are accumulating geometry in a buffer
- // within the GeometryBuilder.
-
- var matrix = xeogl.math.mat4();
- var height = 3;
- var height2 = height * 2;
- var x;
- var y;
- var z;
- var size = 200;
-
- for (x = -size; x <= size; x += 2) {
- for (z = -size; z <= size; z += 2) {
-
- y = ((Math.sin(x * 0.05) * height + Math.sin(z * 0.05) * height)) + height2;
-
- xeogl.math.identityMat4(matrix); // Fresh matrix
- xeogl.math.scaleMat4c(.90, y, .90, matrix); // Post-concatenate scaling
- xeogl.math.translateMat4c(x, y, z, matrix); // Post-concatenate translation
-
- geometryBuilder.setMatrix(matrix); // Set the current modeling transform matrix
-
- geometryBuilder.addShape(); // Add current shape to the buffer, transformed by the matrix
- }
- }
-
- var geometry = new xeogl.Geometry(); // Dump the buffer into a Geometry component
-
- geometryBuilder.build(geometry);
-
- var mesh = new xeogl.Mesh({ // Create an Mesh with our Geometry attached
- geometry: geometry,
- material: new xeogl.PhongMaterial({
- diffuse: [0.6, 0.6, 0.7]
- })
- });
-
- mesh.scene.camera.eye = [-200, 50, -200]; // Set initial Camera position
-
- new xeogl.CameraControl(); // Allow camera interaction
- ````
- @class GeometryBuilder
- @module xeogl
- @submodule generation
- @constructor
- */
- (function () {
-
- "use strict";
-
- xeogl.GeometryBuilder = function () {
- this.reset();
- };
-
- /**
- * Sets the shape that will be added to this GeometryBuilder on each subsequent call to {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}.
- *
- * The shape can be either a {{#crossLink "Geometry"}}{{/crossLink}} or a JavaScript object containing vertex and index arrays.
- *
- * @method setShape
- * @param {Geometry|*} shape The shape to add.
- * @returns this
- */
- xeogl.GeometryBuilder.prototype.setShape = function (shape) {
- this._shape = shape;
- return this;
- };
-
- /**
- * Sets the modeling transform matrix to apply to each shape added with subsequent calls to {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}.
- *
- * @method setMatrix
- * @param {Float32Array} matrix a 16-element transform matrix.
- * @returns this
- */
- xeogl.GeometryBuilder.prototype.setMatrix = function (matrix) {
- this._matrix.set(matrix);
- return this;
- };
-
- /**
- * Adds a shape to this GeometryBuilder. The shape geometry is the one last added
- * by {{#crossLink "GeometryBuilder/addShape:method"}}addShape(){{/crossLink}}, and will be transformed by the
- * matrix that was set by the last call to {{#crossLink "GeometryBuilder/build:method"}}setMatrix(){{/crossLink}}.
- *
- * A subsequent call to {{#crossLink "GeometryBuilder/build:method"}}build(){{/crossLink}} will add all the
- * accumulated transformed shapes to a target {{#crossLink "Geometry"}}{{/crossLink}}.
- *
- * @method addShape
- * @returns this
- */
- xeogl.GeometryBuilder.prototype.addShape = (function () {
-
- var math = xeogl.math;
-
- var tempVec3a = math.vec3();
- var tempVec3b = math.vec3();
-
- return function () {
-
- var i;
- var len;
- var indicesBump = (this._positions) ? (this._positions.length / 3) : 0;
-
- if (this._shape.positions) {
-
- if (!this._positions) {
- this._positions = [];
- }
-
- var positions = this._shape.positions;
-
- if (!this._matrix) {
-
- for (i = 0, len = positions.length; i < len; i++) {
- this._positions.push(positions[i]);
- }
-
- } else {
-
- for (i = 0, len = positions.length; i < len; i += 3) {
-
- tempVec3a[0] = positions[i + 0];
- tempVec3a[1] = positions[i + 1];
- tempVec3a[2] = positions[i + 2];
-
- math.transformPoint3(this._matrix, tempVec3a, tempVec3b);
-
- this._positions.push(tempVec3b[0]);
- this._positions.push(tempVec3b[1]);
- this._positions.push(tempVec3b[2]);
- }
- }
- }
-
- if (this._shape.normals) {
- if (!this._normals) {
- this._normals = [];
- }
- for (i = 0, len = this._shape.normals.length; i < len; i++) {
- this._normals.push(this._shape.normals[i]);
- }
- }
-
- if (this._shape.uv) {
- if (!this._uv) {
- this._uv = [];
- }
- for (i = 0, len = this._shape.uv.length; i < len; i++) {
- this._uv.push(this._shape.uv[i]);
- }
- }
-
- if (this._shape.colors) {
- if (!this._colors) {
- this._colors = [];
- }
- for (i = 0, len = this._shape.colors.length; i < len; i++) {
- this._colors.push(this._shape.colors[i]);
- }
- }
-
- if (this._shape.indices) {
- if (!this._indices) {
- this._indices = [];
- }
- for (i = 0, len = this._shape.indices.length; i < len; i++) {
- this._indices.push(this._shape.indices[i] + indicesBump);
- }
- }
- };
- })();
-
- /**
- * Returns the accumulated state from previous calls to {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} and
- * {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}}.
- *
- * Retains all that state afterwards, so that you can continue to call this method to add the state to
- * other {{#crossLink "Geometry"}}Geometries{{/crossLink}}.
- *
- * @method build
- * @returns {Object}
- */
- xeogl.GeometryBuilder.prototype.build = function (geometry) {
- return {
- primitive: this.primitive || "triangles",
- positions: this._positions,
- normals: this._normals,
- uv: this._uv,
- colors: this._colors,
- indices: this._indices
- };
- };
-
- /**
- *
- * Resets this GeometryBuilder, clearing all the state previously accumulated with {{#crossLink "GeometryBuilder/setMatrix:method"}}setMatrix(){{/crossLink}} and
- * {{#crossLink "GeometryBuilder/setShape:method"}}setShape(){{/crossLink}}.
- * @method reset
- * @returns this
- */
- xeogl.GeometryBuilder.prototype.reset = function () {
- this._positions = null;
- this._normals = null;
- this._uv = null;
- this._colors = null;
- this._indices = null;
- this._matrix = xeogl.math.identityMat4(xeogl.math.mat4());
- return this;
- };
-
- })();
-
-