UNPKG

@smoud/tiny

Version:

Fast and tiny JavaScript library for HTML5 game and playable ads creation.

156 lines (104 loc) 4.75 kB
/** * @param {Array<Tiny.Geometry>} geometries * @return {Tiny.Geometry} */ export function mergeGeometries(geometries) { var isIndexed = geometries[0].index !== null; var attributesUsed = Object.keys(geometries[0].attributes); var attributes = {}; var mergedGeometry = new Tiny.Geometry(); for (var i = 0; i < geometries.length; ++i) { // @TODO remove this fix later, make merge don't require clone of geometry if (geometries[i].gl) { geometries[i] = geometries[i].clone(); } var geometry = geometries[i]; var attributesCount = 0; // ensure that all geometries are indexed, or none if (isIndexed !== (geometry.index !== null)) { console.error('Tiny.GeometryUtils.mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.'); return null; } // gather attributes, exit early if they're different for (var name in geometry.attributes) { if (attributesUsed.indexOf(name) === -1) { console.error('Tiny.GeometryUtils.mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.'); return null; } if (attributes[name] === undefined) attributes[name] = []; attributes[name].push(geometry.attributes[name].clone()); attributesCount++; } // ensure geometries have the same number of attributes if (attributesCount !== attributesUsed.length) { console.error('Tiny.GeometryUtils.mergeGeometries() failed with geometry at index ' + i + '. Make sure all geometries have the same number of attributes.'); return null; } } // merge indices if (isIndexed) { var indexOffset = 0; var mergedIndex = []; for (var i = 0; i < geometries.length; ++i) { var index = geometries[i].index; for (var j = 0; j < index.count; ++j) { mergedIndex.push(index.getX(j) + indexOffset); } indexOffset += geometries[i].attributes.position.count; } mergedGeometry.setIndex(new Tiny.Uint16Attribute(mergedIndex)); } // merge attributes for (var name in attributes) { var mergedAttribute = mergeAttributes(attributes[name]); if (!mergedAttribute) { console.error('Tiny.GeometryUtils.mergeGeometries() failed while trying to merge the ' + name + ' attribute.'); return null; } mergedGeometry.attributes[name] = mergedAttribute; } return mergedGeometry; } /** * @param {Array<Tiny.Attribute>} attributes * @return {Tiny.Attribute} */ function mergeAttributes( attributes ) { var TypedArray; var size; var normalized; var arrayLength = 0; for ( var i = 0; i < attributes.length; ++ i ) { var attribute = attributes[ i ]; if ( TypedArray === undefined ) TypedArray = attribute.array.constructor; if ( TypedArray !== attribute.array.constructor ) { console.error( 'Tiny.GeometryUtils.mergeGeometries() failed. Attribute.array must be of consistent array types across matching attributes.' ); return null; } if ( size === undefined ) size = attribute.itemSize; if ( size !== attribute.itemSize ) { console.error( 'Tiny.GeometryUtils.mergeGeometries() failed. Attribute.itemSize must be consistent across matching attributes.' ); return null; } if ( normalized === undefined ) normalized = attribute.normalized; if ( normalized !== attribute.normalized ) { console.error( 'Tiny.GeometryUtils.mergeGeometries() failed. BufferAttribute.normalized must be consistent across matching attributes.' ); return null; } arrayLength += attribute.array.length; } var array = new TypedArray( arrayLength ); var offset = 0; for ( var i = 0; i < attributes.length; ++ i ) { array.set( attributes[ i ].array, offset ); offset += attributes[ i ].array.length; } var result = attributes[0].clone(); Object.assign(result, { array, itemSize: size, normalized, count: array.length / size }); return result; }