UNPKG

8.65 kBJavaScriptView Raw
1"use strict";
2var constants = require("@pixi/constants"), runner = require("@pixi/runner"), utils = require("@pixi/utils"), Attribute = require("./Attribute.js"), Buffer = require("./Buffer.js"), interleaveTypedArrays = require("./utils/interleaveTypedArrays.js");
3const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
4let UID = 0;
5const map = {
6 Float32Array,
7 Uint32Array,
8 Int32Array,
9 Uint8Array,
10 Uint16Array
11};
12class Geometry {
13 /**
14 * @param buffers - An array of buffers. optional.
15 * @param attributes - Of the geometry, optional structure of the attributes layout
16 */
17 constructor(buffers = [], attributes = {}) {
18 this.buffers = buffers, this.indexBuffer = null, this.attributes = attributes, this.glVertexArrayObjects = {}, this.id = UID++, this.instanced = !1, this.instanceCount = 1, this.disposeRunner = new runner.Runner("disposeGeometry"), this.refCount = 0;
19 }
20 /**
21 *
22 * Adds an attribute to the geometry
23 * Note: `stride` and `start` should be `undefined` if you dont know them, not 0!
24 * @param id - the name of the attribute (matching up to a shader)
25 * @param {PIXI.Buffer|number[]} buffer - the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it.
26 * @param size - the size of the attribute. If you have 2 floats per vertex (eg position x and y) this would be 2
27 * @param normalized - should the data be normalized.
28 * @param [type=PIXI.TYPES.FLOAT] - what type of number is the attribute. Check {@link PIXI.TYPES} to see the ones available
29 * @param [stride=0] - How far apart, in bytes, the start of each value is. (used for interleaving data)
30 * @param [start=0] - How far into the array to start reading values (used for interleaving data)
31 * @param instance - Instancing flag
32 * @returns - Returns self, useful for chaining.
33 */
34 addAttribute(id, buffer, size = 0, normalized = !1, type, stride, start, instance = !1) {
35 if (!buffer)
36 throw new Error("You must pass a buffer when creating an attribute");
37 buffer instanceof Buffer.Buffer || (buffer instanceof Array && (buffer = new Float32Array(buffer)), buffer = new Buffer.Buffer(buffer));
38 const ids = id.split("|");
39 if (ids.length > 1) {
40 for (let i = 0; i < ids.length; i++)
41 this.addAttribute(ids[i], buffer, size, normalized, type);
42 return this;
43 }
44 let bufferIndex = this.buffers.indexOf(buffer);
45 return bufferIndex === -1 && (this.buffers.push(buffer), bufferIndex = this.buffers.length - 1), this.attributes[id] = new Attribute.Attribute(bufferIndex, size, normalized, type, stride, start, instance), this.instanced = this.instanced || instance, this;
46 }
47 /**
48 * Returns the requested attribute.
49 * @param id - The name of the attribute required
50 * @returns - The attribute requested.
51 */
52 getAttribute(id) {
53 return this.attributes[id];
54 }
55 /**
56 * Returns the requested buffer.
57 * @param id - The name of the buffer required.
58 * @returns - The buffer requested.
59 */
60 getBuffer(id) {
61 return this.buffers[this.getAttribute(id).buffer];
62 }
63 /**
64 *
65 * Adds an index buffer to the geometry
66 * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer.
67 * @param {PIXI.Buffer|number[]} [buffer] - The buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it.
68 * @returns - Returns self, useful for chaining.
69 */
70 addIndex(buffer) {
71 return buffer instanceof Buffer.Buffer || (buffer instanceof Array && (buffer = new Uint16Array(buffer)), buffer = new Buffer.Buffer(buffer)), buffer.type = constants.BUFFER_TYPE.ELEMENT_ARRAY_BUFFER, this.indexBuffer = buffer, this.buffers.includes(buffer) || this.buffers.push(buffer), this;
72 }
73 /**
74 * Returns the index buffer
75 * @returns - The index buffer.
76 */
77 getIndex() {
78 return this.indexBuffer;
79 }
80 /**
81 * This function modifies the structure so that all current attributes become interleaved into a single buffer
82 * This can be useful if your model remains static as it offers a little performance boost
83 * @returns - Returns self, useful for chaining.
84 */
85 interleave() {
86 if (this.buffers.length === 1 || this.buffers.length === 2 && this.indexBuffer)
87 return this;
88 const arrays = [], sizes = [], interleavedBuffer = new Buffer.Buffer();
89 let i;
90 for (i in this.attributes) {
91 const attribute = this.attributes[i], buffer = this.buffers[attribute.buffer];
92 arrays.push(buffer.data), sizes.push(attribute.size * byteSizeMap[attribute.type] / 4), attribute.buffer = 0;
93 }
94 for (interleavedBuffer.data = interleaveTypedArrays.interleaveTypedArrays(arrays, sizes), i = 0; i < this.buffers.length; i++)
95 this.buffers[i] !== this.indexBuffer && this.buffers[i].destroy();
96 return this.buffers = [interleavedBuffer], this.indexBuffer && this.buffers.push(this.indexBuffer), this;
97 }
98 /** Get the size of the geometries, in vertices. */
99 getSize() {
100 for (const i in this.attributes) {
101 const attribute = this.attributes[i];
102 return this.buffers[attribute.buffer].data.length / (attribute.stride / 4 || attribute.size);
103 }
104 return 0;
105 }
106 /** Disposes WebGL resources that are connected to this geometry. */
107 dispose() {
108 this.disposeRunner.emit(this, !1);
109 }
110 /** Destroys the geometry. */
111 destroy() {
112 this.dispose(), this.buffers = null, this.indexBuffer = null, this.attributes = null;
113 }
114 /**
115 * Returns a clone of the geometry.
116 * @returns - A new clone of this geometry.
117 */
118 clone() {
119 const geometry = new Geometry();
120 for (let i = 0; i < this.buffers.length; i++)
121 geometry.buffers[i] = new Buffer.Buffer(this.buffers[i].data.slice(0));
122 for (const i in this.attributes) {
123 const attrib = this.attributes[i];
124 geometry.attributes[i] = new Attribute.Attribute(
125 attrib.buffer,
126 attrib.size,
127 attrib.normalized,
128 attrib.type,
129 attrib.stride,
130 attrib.start,
131 attrib.instance
132 );
133 }
134 return this.indexBuffer && (geometry.indexBuffer = geometry.buffers[this.buffers.indexOf(this.indexBuffer)], geometry.indexBuffer.type = constants.BUFFER_TYPE.ELEMENT_ARRAY_BUFFER), geometry;
135 }
136 /**
137 * Merges an array of geometries into a new single one.
138 *
139 * Geometry attribute styles must match for this operation to work.
140 * @param geometries - array of geometries to merge
141 * @returns - Shiny new geometry!
142 */
143 static merge(geometries) {
144 const geometryOut = new Geometry(), arrays = [], sizes = [], offsets = [];
145 let geometry;
146 for (let i = 0; i < geometries.length; i++) {
147 geometry = geometries[i];
148 for (let j = 0; j < geometry.buffers.length; j++)
149 sizes[j] = sizes[j] || 0, sizes[j] += geometry.buffers[j].data.length, offsets[j] = 0;
150 }
151 for (let i = 0; i < geometry.buffers.length; i++)
152 arrays[i] = new map[utils.getBufferType(geometry.buffers[i].data)](sizes[i]), geometryOut.buffers[i] = new Buffer.Buffer(arrays[i]);
153 for (let i = 0; i < geometries.length; i++) {
154 geometry = geometries[i];
155 for (let j = 0; j < geometry.buffers.length; j++)
156 arrays[j].set(geometry.buffers[j].data, offsets[j]), offsets[j] += geometry.buffers[j].data.length;
157 }
158 if (geometryOut.attributes = geometry.attributes, geometry.indexBuffer) {
159 geometryOut.indexBuffer = geometryOut.buffers[geometry.buffers.indexOf(geometry.indexBuffer)], geometryOut.indexBuffer.type = constants.BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;
160 let offset = 0, stride = 0, offset2 = 0, bufferIndexToCount = 0;
161 for (let i = 0; i < geometry.buffers.length; i++)
162 if (geometry.buffers[i] !== geometry.indexBuffer) {
163 bufferIndexToCount = i;
164 break;
165 }
166 for (const i in geometry.attributes) {
167 const attribute = geometry.attributes[i];
168 (attribute.buffer | 0) === bufferIndexToCount && (stride += attribute.size * byteSizeMap[attribute.type] / 4);
169 }
170 for (let i = 0; i < geometries.length; i++) {
171 const indexBufferData = geometries[i].indexBuffer.data;
172 for (let j = 0; j < indexBufferData.length; j++)
173 geometryOut.indexBuffer.data[j + offset2] += offset;
174 offset += geometries[i].buffers[bufferIndexToCount].data.length / stride, offset2 += indexBufferData.length;
175 }
176 }
177 return geometryOut;
178 }
179}
180exports.Geometry = Geometry;
181//# sourceMappingURL=Geometry.js.map