1 | import { ENV, BUFFER_TYPE } from "@pixi/constants";
|
2 | import { ExtensionType, extensions } from "@pixi/extensions";
|
3 | import { settings } from "@pixi/settings";
|
4 | const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
|
5 | class GeometrySystem {
|
6 |
|
7 | constructor(renderer) {
|
8 | this.renderer = renderer, this._activeGeometry = null, this._activeVao = null, this.hasVao = !0, this.hasInstance = !0, this.canUseUInt32ElementIndex = !1, this.managedGeometries = {};
|
9 | }
|
10 |
|
11 | contextChange() {
|
12 | this.disposeAll(!0);
|
13 | const gl = this.gl = this.renderer.gl, context = this.renderer.context;
|
14 | if (this.CONTEXT_UID = this.renderer.CONTEXT_UID, context.webGLVersion !== 2) {
|
15 | let nativeVaoExtension = this.renderer.context.extensions.vertexArrayObject;
|
16 | settings.PREFER_ENV === ENV.WEBGL_LEGACY && (nativeVaoExtension = null), nativeVaoExtension ? (gl.createVertexArray = () => nativeVaoExtension.createVertexArrayOES(), gl.bindVertexArray = (vao) => nativeVaoExtension.bindVertexArrayOES(vao), gl.deleteVertexArray = (vao) => nativeVaoExtension.deleteVertexArrayOES(vao)) : (this.hasVao = !1, gl.createVertexArray = () => null, gl.bindVertexArray = () => null, gl.deleteVertexArray = () => null);
|
17 | }
|
18 | if (context.webGLVersion !== 2) {
|
19 | const instanceExt = gl.getExtension("ANGLE_instanced_arrays");
|
20 | instanceExt ? (gl.vertexAttribDivisor = (a, b) => instanceExt.vertexAttribDivisorANGLE(a, b), gl.drawElementsInstanced = (a, b, c, d, e) => instanceExt.drawElementsInstancedANGLE(a, b, c, d, e), gl.drawArraysInstanced = (a, b, c, d) => instanceExt.drawArraysInstancedANGLE(a, b, c, d)) : this.hasInstance = !1;
|
21 | }
|
22 | this.canUseUInt32ElementIndex = context.webGLVersion === 2 || !!context.extensions.uint32ElementIndex;
|
23 | }
|
24 | |
25 |
|
26 |
|
27 |
|
28 |
|
29 | bind(geometry, shader) {
|
30 | shader = shader || this.renderer.shader.shader;
|
31 | const { gl } = this;
|
32 | let vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID], incRefCount = !1;
|
33 | vaos || (this.managedGeometries[geometry.id] = geometry, geometry.disposeRunner.add(this), geometry.glVertexArrayObjects[this.CONTEXT_UID] = vaos = {}, incRefCount = !0);
|
34 | const vao = vaos[shader.program.id] || this.initGeometryVao(geometry, shader, incRefCount);
|
35 | this._activeGeometry = geometry, this._activeVao !== vao && (this._activeVao = vao, this.hasVao ? gl.bindVertexArray(vao) : this.activateVao(geometry, shader.program)), this.updateBuffers();
|
36 | }
|
37 |
|
38 | reset() {
|
39 | this.unbind();
|
40 | }
|
41 |
|
42 | updateBuffers() {
|
43 | const geometry = this._activeGeometry, bufferSystem = this.renderer.buffer;
|
44 | for (let i = 0; i < geometry.buffers.length; i++) {
|
45 | const buffer = geometry.buffers[i];
|
46 | bufferSystem.update(buffer);
|
47 | }
|
48 | }
|
49 | |
50 |
|
51 |
|
52 |
|
53 |
|
54 | checkCompatibility(geometry, program) {
|
55 | const geometryAttributes = geometry.attributes, shaderAttributes = program.attributeData;
|
56 | for (const j in shaderAttributes)
|
57 | if (!geometryAttributes[j])
|
58 | throw new Error(`shader and geometry incompatible, geometry missing the "${j}" attribute`);
|
59 | }
|
60 | |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | getSignature(geometry, program) {
|
67 | const attribs = geometry.attributes, shaderAttributes = program.attributeData, strings = ["g", geometry.id];
|
68 | for (const i in attribs)
|
69 | shaderAttributes[i] && strings.push(i, shaderAttributes[i].location);
|
70 | return strings.join("-");
|
71 | }
|
72 | |
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | initGeometryVao(geometry, shader, incRefCount = !0) {
|
81 | const gl = this.gl, CONTEXT_UID = this.CONTEXT_UID, bufferSystem = this.renderer.buffer, program = shader.program;
|
82 | program.glPrograms[CONTEXT_UID] || this.renderer.shader.generateProgram(shader), this.checkCompatibility(geometry, program);
|
83 | const signature = this.getSignature(geometry, program), vaoObjectHash = geometry.glVertexArrayObjects[this.CONTEXT_UID];
|
84 | let vao = vaoObjectHash[signature];
|
85 | if (vao)
|
86 | return vaoObjectHash[program.id] = vao, vao;
|
87 | const buffers = geometry.buffers, attributes = geometry.attributes, tempStride = {}, tempStart = {};
|
88 | for (const j in buffers)
|
89 | tempStride[j] = 0, tempStart[j] = 0;
|
90 | for (const j in attributes)
|
91 | !attributes[j].size && program.attributeData[j] ? attributes[j].size = program.attributeData[j].size : attributes[j].size || console.warn(`PIXI Geometry attribute '${j}' size cannot be determined (likely the bound shader does not have the attribute)`), tempStride[attributes[j].buffer] += attributes[j].size * byteSizeMap[attributes[j].type];
|
92 | for (const j in attributes) {
|
93 | const attribute = attributes[j], attribSize = attribute.size;
|
94 | attribute.stride === void 0 && (tempStride[attribute.buffer] === attribSize * byteSizeMap[attribute.type] ? attribute.stride = 0 : attribute.stride = tempStride[attribute.buffer]), attribute.start === void 0 && (attribute.start = tempStart[attribute.buffer], tempStart[attribute.buffer] += attribSize * byteSizeMap[attribute.type]);
|
95 | }
|
96 | vao = gl.createVertexArray(), gl.bindVertexArray(vao);
|
97 | for (let i = 0; i < buffers.length; i++) {
|
98 | const buffer = buffers[i];
|
99 | bufferSystem.bind(buffer), incRefCount && buffer._glBuffers[CONTEXT_UID].refCount++;
|
100 | }
|
101 | return this.activateVao(geometry, program), vaoObjectHash[program.id] = vao, vaoObjectHash[signature] = vao, gl.bindVertexArray(null), bufferSystem.unbind(BUFFER_TYPE.ARRAY_BUFFER), vao;
|
102 | }
|
103 | |
104 |
|
105 |
|
106 |
|
107 |
|
108 | disposeGeometry(geometry, contextLost) {
|
109 | if (!this.managedGeometries[geometry.id])
|
110 | return;
|
111 | delete this.managedGeometries[geometry.id];
|
112 | const vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID], gl = this.gl, buffers = geometry.buffers, bufferSystem = this.renderer?.buffer;
|
113 | if (geometry.disposeRunner.remove(this), !!vaos) {
|
114 | if (bufferSystem)
|
115 | for (let i = 0; i < buffers.length; i++) {
|
116 | const buf = buffers[i]._glBuffers[this.CONTEXT_UID];
|
117 | buf && (buf.refCount--, buf.refCount === 0 && !contextLost && bufferSystem.dispose(buffers[i], contextLost));
|
118 | }
|
119 | if (!contextLost) {
|
120 | for (const vaoId in vaos)
|
121 | if (vaoId[0] === "g") {
|
122 | const vao = vaos[vaoId];
|
123 | this._activeVao === vao && this.unbind(), gl.deleteVertexArray(vao);
|
124 | }
|
125 | }
|
126 | delete geometry.glVertexArrayObjects[this.CONTEXT_UID];
|
127 | }
|
128 | }
|
129 | |
130 |
|
131 |
|
132 |
|
133 | disposeAll(contextLost) {
|
134 | const all = Object.keys(this.managedGeometries);
|
135 | for (let i = 0; i < all.length; i++)
|
136 | this.disposeGeometry(this.managedGeometries[all[i]], contextLost);
|
137 | }
|
138 | |
139 |
|
140 |
|
141 |
|
142 |
|
143 | activateVao(geometry, program) {
|
144 | const gl = this.gl, CONTEXT_UID = this.CONTEXT_UID, bufferSystem = this.renderer.buffer, buffers = geometry.buffers, attributes = geometry.attributes;
|
145 | geometry.indexBuffer && bufferSystem.bind(geometry.indexBuffer);
|
146 | let lastBuffer = null;
|
147 | for (const j in attributes) {
|
148 | const attribute = attributes[j], buffer = buffers[attribute.buffer], glBuffer = buffer._glBuffers[CONTEXT_UID];
|
149 | if (program.attributeData[j]) {
|
150 | lastBuffer !== glBuffer && (bufferSystem.bind(buffer), lastBuffer = glBuffer);
|
151 | const location = program.attributeData[j].location;
|
152 | if (gl.enableVertexAttribArray(location), gl.vertexAttribPointer(
|
153 | location,
|
154 | attribute.size,
|
155 | attribute.type || gl.FLOAT,
|
156 | attribute.normalized,
|
157 | attribute.stride,
|
158 | attribute.start
|
159 | ), attribute.instance)
|
160 | if (this.hasInstance)
|
161 | gl.vertexAttribDivisor(location, attribute.divisor);
|
162 | else
|
163 | throw new Error("geometry error, GPU Instancing is not supported on this device");
|
164 | }
|
165 | }
|
166 | }
|
167 | |
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 | draw(type, size, start, instanceCount) {
|
178 | const { gl } = this, geometry = this._activeGeometry;
|
179 | if (geometry.indexBuffer) {
|
180 | const byteSize = geometry.indexBuffer.data.BYTES_PER_ELEMENT, glType = byteSize === 2 ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT;
|
181 | byteSize === 2 || byteSize === 4 && this.canUseUInt32ElementIndex ? geometry.instanced ? gl.drawElementsInstanced(type, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize, instanceCount || 1) : gl.drawElements(type, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize) : console.warn("unsupported index buffer type: uint32");
|
182 | } else
|
183 | geometry.instanced ? gl.drawArraysInstanced(type, start, size || geometry.getSize(), instanceCount || 1) : gl.drawArrays(type, start, size || geometry.getSize());
|
184 | return this;
|
185 | }
|
186 |
|
187 | unbind() {
|
188 | this.gl.bindVertexArray(null), this._activeVao = null, this._activeGeometry = null;
|
189 | }
|
190 | destroy() {
|
191 | this.renderer = null;
|
192 | }
|
193 | }
|
194 | GeometrySystem.extension = {
|
195 | type: ExtensionType.RendererSystem,
|
196 | name: "geometry"
|
197 | };
|
198 | extensions.add(GeometrySystem);
|
199 | export {
|
200 | GeometrySystem
|
201 | };
|
202 |
|