UNPKG

@awayjs/scene

Version:
267 lines (266 loc) 11.1 kB
import { AttributesBuffer } from '@awayjs/stage'; import { TriangleElements } from '@awayjs/renderer'; import { Shape } from '@awayjs/graphics'; import { Sprite } from '../display/Sprite'; /** * Class Merge merges two or more static sprites into one.<code>Merge</code> */ var Merge = /** @class */ (function () { /** * @param keepMaterial [optional] * Determines if the merged object uses the recevier sprite material information or keeps its source material(s). * Defaults to false. * If false and receiver object has multiple materials, * the last material found in receiver subsprites is applied to the merged subsprite(es). * @param disposeSources [optional] * Determines if the sprite and geometry source(s) used for the merging are disposed. Defaults to false. * If true, only receiver geometry and resulting sprite are kept in memory. * @param objectSpace [optional] * Determines if source sprite(es) is/are merged using objectSpace or worldspace. Defaults to false. */ function Merge(keepMaterial, disposeSources, objectSpace) { if (keepMaterial === void 0) { keepMaterial = false; } if (disposeSources === void 0) { disposeSources = false; } if (objectSpace === void 0) { objectSpace = false; } this._keepMaterial = keepMaterial; this._disposeSources = disposeSources; this._objectSpace = objectSpace; } Object.defineProperty(Merge.prototype, "disposeSources", { get: function () { return this._disposeSources; }, /** * Determines if the sprite and geometry source(s) used for the merging are disposed. Defaults to false. */ set: function (b) { this._disposeSources = b; }, enumerable: false, configurable: true }); Object.defineProperty(Merge.prototype, "keepMaterial", { get: function () { return this._keepMaterial; }, /** * Determines if the material source(s) used for the merging are disposed. Defaults to false. */ set: function (b) { this._keepMaterial = b; }, enumerable: false, configurable: true }); Object.defineProperty(Merge.prototype, "objectSpace", { get: function () { return this._objectSpace; }, /** * Determines if source sprite(es) is/are merged using objectSpace or worldspace. Defaults to false. */ set: function (b) { this._objectSpace = b; }, enumerable: false, configurable: true }); /** * Merges all the children of a container into a single Sprite. * If no Sprite object is found, method returns the receiver without modification. * * @param receiver The Sprite to receive the merged contents of the container. * @param objectContainer The DisplayObjectContainer holding the sprites to be mergd. * * @return The merged Sprite instance. */ Merge.prototype.applyToContainer = function (receiver, objectContainer) { this.reset(); //collect container sprites this.parseContainer(receiver, objectContainer); //collect receiver this.collect(receiver, false); //merge to receiver this.merge(receiver, this._disposeSources); }; /** * Merges all the sprites found in the Array&lt;Sprite&gt; into a single Sprite. * * @param receiver The Sprite to receive the merged contents of the sprites. * @param sprites A series of Sprites to be merged with the reciever sprite. */ Merge.prototype.applyToSprites = function (receiver, sprites) { this.reset(); if (!sprites.length) return; //collect sprites in vector for (var i = 0; i < sprites.length; i++) if (sprites[i] != receiver) this.collect(sprites[i], this._disposeSources); //collect receiver this.collect(receiver, false); //merge to receiver this.merge(receiver, this._disposeSources); }; /** * Merges 2 sprites into one. * It is recommand to use apply when 2 sprites are to be merged. * If more need to be merged, use either applyToSprites or applyToContainer methods. * * @param receiver The Sprite to receive the merged contents of both sprites. * @param sprite The Sprite to be merged with the receiver sprite */ Merge.prototype.apply = function (receiver, sprite) { this.reset(); //collect sprite this.collect(sprite, this._disposeSources); //collect receiver this.collect(receiver, false); //merge to receiver this.merge(receiver, this._disposeSources); }; Merge.prototype.reset = function () { this._toDispose = new Array(); this._shapeVOs = new Array(); }; Merge.prototype.merge = function (destSprite, dispose) { var i; var destGraphics = destSprite.graphics; var useSubMaterials = (this._shapeVOs.length > 1); for (i = 0; i < this._shapeVOs.length; i++) { var elements = new TriangleElements(new AttributesBuffer()); elements.autoDeriveNormals = false; elements.autoDeriveTangents = false; var data = this._shapeVOs[i]; elements.setIndices(data.indices); elements.setPositions(data.vertices); elements.setNormals(data.normals); elements.setTangents(data.tangents); elements.setUVs(data.uvs); if (this._keepMaterial && useSubMaterials) destGraphics.addShape(Shape.getShape(elements, data.material)); else destGraphics.addShape(Shape.getShape(elements)); } if (this._keepMaterial && !useSubMaterials && this._shapeVOs.length) destSprite.material = this._shapeVOs[0].material; if (dispose) { var len = this._toDispose.length; for (i; i < len; i++) this._toDispose[i].dispose(); } this._toDispose = null; }; Merge.prototype.collect = function (sprite, dispose) { var subIdx; var calc; for (subIdx = 0; subIdx < sprite.graphics.count; subIdx++) { var i = void 0; var len = void 0; var iIdx = void 0, vIdx = void 0, nIdx = void 0, tIdx = void 0; var elements = sprite.graphics.getShapeAt(subIdx).elements; // Get (or create) a VO for this material var vo = this.getShapeData(sprite.graphics.getShapeAt(subIdx).material); // Vertices and normals are copied to temporary vectors, to be transformed // before concatenated onto those of the data. This is unnecessary if no // transformation will be performed, i.e. for object space merging. var vertices = (this._objectSpace) ? vo.vertices : []; var normals = (this._objectSpace) ? vo.normals : []; var tangents = (this._objectSpace) ? vo.tangents : []; // Copy over vertex attributes vIdx = vertices.length; nIdx = normals.length; tIdx = tangents.length; var uIdx = vo.uvs.length; this.copyAttributes(elements.positions, vertices, elements.numVertices, vIdx); this.copyAttributes(elements.normals, normals, elements.numVertices, nIdx); this.copyAttributes(elements.tangents, tangents, elements.numVertices, tIdx); this.copyAttributes(elements.uvs, vo.uvs, elements.numVertices, uIdx); // Copy over triangle indices var indexOffset = (!this._objectSpace) ? vo.vertices.length / 3 : 0; iIdx = vo.indices.length; len = elements.numElements; var ind = elements.indices.get(len); for (i = 0; i < len; i++) { calc = i * 3; vo.indices[iIdx++] = ind[calc] + indexOffset; vo.indices[iIdx++] = ind[calc + 1] + indexOffset; vo.indices[iIdx++] = ind[calc + 2] + indexOffset; } if (!this._objectSpace) { sprite.transform.matrix3D.transformVectors(vertices, vertices); sprite.transform.matrix3D.deltaTransformVectors(normals, normals); sprite.transform.matrix3D.deltaTransformVectors(tangents, tangents); // Copy vertex data from temporary (transformed) vectors vIdx = vo.vertices.length; nIdx = vo.normals.length; tIdx = vo.tangents.length; len = vertices.length; for (i = 0; i < len; i++) { vo.vertices[vIdx++] = vertices[i]; vo.normals[nIdx++] = normals[i]; vo.tangents[tIdx++] = tangents[i]; } } } if (dispose) this._toDispose.push(sprite); }; Merge.prototype.copyAttributes = function (attributes, array, count, startIndex) { var vertices = attributes.get(count); var dim = attributes.dimensions; var stride = attributes.stride; var len = count * stride; for (var i = 0; i < len; i += stride) for (var j = 0; j < dim; j++) array[startIndex++] = vertices[i + j]; }; Merge.prototype.getShapeData = function (material) { var data; if (this._keepMaterial) { var i = void 0; var len = this._shapeVOs.length; for (i = 0; i < len; i++) { if (this._shapeVOs[i].material == material) { data = this._shapeVOs[i]; break; } } } else if (this._shapeVOs.length) { // If materials are not to be kept, all data can be // put into a single VO, so return that one. data = this._shapeVOs[0]; } // No data (for this material) found, create new. if (!data) { data = new ShapeVO(); data.vertices = new Array(); data.normals = new Array(); data.tangents = new Array(); data.uvs = new Array(); data.indices = new Array(); data.material = material; this._shapeVOs.push(data); } return data; }; Merge.prototype.parseContainer = function (receiver, object) { var child; var i; if (object instanceof Sprite && object != receiver) this.collect(object, this._disposeSources); for (i = 0; i < object.numChildren; ++i) { child = object.getChildAt(i); this.parseContainer(receiver, child); } }; return Merge; }()); export { Merge }; var ShapeVO = /** @class */ (function () { function ShapeVO() { } return ShapeVO; }()); export { ShapeVO };