@expofp/renderer 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +70 -26
- package/dist/index.js +666 -566
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,372 +2,16 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
var _a;
|
|
5
|
-
import {
|
|
5
|
+
import { DataTexture, FloatType, UnsignedIntType, IntType, RGBAFormat, RGBAIntegerFormat, RGFormat, RGIntegerFormat, RedFormat, RedIntegerFormat, BatchedMesh as BatchedMesh$1, BufferAttribute, StreamDrawUsage, Color, Matrix4, Vector3, Vector4, AlwaysDepth, DoubleSide, MeshBasicMaterial, Texture, Group, PlaneGeometry, SRGBColorSpace, Vector2, Quaternion, BufferGeometry, Mesh, LessEqualDepth, LinearSRGBColorSpace, Plane, Raycaster, Sphere, Box3, Spherical, PerspectiveCamera, Camera, Scene, MathUtils, Clock, WebGLRenderer } from "three";
|
|
6
6
|
import { traverseAncestorsGenerator } from "three/examples/jsm/utils/SceneUtils.js";
|
|
7
|
-
import { BatchedText as BatchedText$1, Text as Text$1 } from "troika-three-text";
|
|
8
7
|
import createLog from "debug";
|
|
8
|
+
import { BatchedText as BatchedText$1, Text as Text$1 } from "troika-three-text";
|
|
9
9
|
import { LineMaterial, LineSegmentsGeometry } from "three/examples/jsm/Addons.js";
|
|
10
10
|
import { MaxRectsPacker, Rectangle } from "maxrects-packer";
|
|
11
11
|
import { extend, colord } from "colord";
|
|
12
12
|
import namesPlugin from "colord/plugins/names";
|
|
13
13
|
import { RAD2DEG, DEG2RAD as DEG2RAD$1 } from "three/src/math/MathUtils.js";
|
|
14
14
|
import { EventManager, Rotate, Pan } from "mjolnir.js";
|
|
15
|
-
const floatsPerMember = 32;
|
|
16
|
-
const tempColor = new Color();
|
|
17
|
-
const defaultStrokeColor = 8421504;
|
|
18
|
-
const tempMat4 = new Matrix4();
|
|
19
|
-
const tempVec3a = new Vector3();
|
|
20
|
-
const tempVec3b = new Vector3();
|
|
21
|
-
const origin = new Vector3();
|
|
22
|
-
const defaultOrient = "+x+y";
|
|
23
|
-
class BatchedText extends BatchedText$1 {
|
|
24
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
25
|
-
constructor() {
|
|
26
|
-
super();
|
|
27
|
-
__publicField(this, "mapInstanceIdToText", /* @__PURE__ */ new Map());
|
|
28
|
-
__publicField(this, "textArray", []);
|
|
29
|
-
__publicField(this, "textureNeedsUpdate", false);
|
|
30
|
-
}
|
|
31
|
-
/** Number of texts in the batch */
|
|
32
|
-
get size() {
|
|
33
|
-
return this._members.size;
|
|
34
|
-
}
|
|
35
|
-
/** Base material before patching */
|
|
36
|
-
get baseMaterial() {
|
|
37
|
-
return this._baseMaterial;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Get the {@link Text} object by instance id
|
|
41
|
-
* @param instanceId Instance id
|
|
42
|
-
* @returns Text object
|
|
43
|
-
*/
|
|
44
|
-
getText(instanceId) {
|
|
45
|
-
return this.mapInstanceIdToText.get(instanceId);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Set the visibility of the {@link Text} object by instance id.
|
|
49
|
-
* This is for interface compatibility with {@link BatchedMesh}.
|
|
50
|
-
* @param instanceId Instance id
|
|
51
|
-
* @param visible Visibility flag
|
|
52
|
-
*/
|
|
53
|
-
setVisibleAt(instanceId, visible) {
|
|
54
|
-
const text = this.getText(instanceId);
|
|
55
|
-
text.visible = visible;
|
|
56
|
-
}
|
|
57
|
-
addText(text, instanceId) {
|
|
58
|
-
super.addText(text);
|
|
59
|
-
if (instanceId !== void 0) {
|
|
60
|
-
this.mapInstanceIdToText.set(instanceId, text);
|
|
61
|
-
}
|
|
62
|
-
this.textArray.push(text);
|
|
63
|
-
}
|
|
64
|
-
dispose() {
|
|
65
|
-
super.dispose();
|
|
66
|
-
this.dispatchEvent({ type: "dispose" });
|
|
67
|
-
}
|
|
68
|
-
// TODO: Check performance
|
|
69
|
-
_prepareForRender(material) {
|
|
70
|
-
var _a2;
|
|
71
|
-
const isOutline = material.isTextOutlineMaterial;
|
|
72
|
-
material.uniforms.uTroikaIsOutline.value = isOutline;
|
|
73
|
-
let texture = this._dataTextures[isOutline ? "outline" : "main"];
|
|
74
|
-
const dataLength = Math.pow(2, Math.ceil(Math.log2(this._members.size * floatsPerMember)));
|
|
75
|
-
if (!texture || dataLength !== texture.image.data.length) {
|
|
76
|
-
if (texture) texture.dispose();
|
|
77
|
-
const width = Math.min(dataLength / 4, 1024);
|
|
78
|
-
texture = this._dataTextures[isOutline ? "outline" : "main"] = new DataTexture(
|
|
79
|
-
new Float32Array(dataLength),
|
|
80
|
-
width,
|
|
81
|
-
dataLength / 4 / width,
|
|
82
|
-
RGBAFormat,
|
|
83
|
-
FloatType
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
const texData = texture.image.data;
|
|
87
|
-
this.textureNeedsUpdate = false;
|
|
88
|
-
for (const text of this.textArray) {
|
|
89
|
-
const index = ((_a2 = this._members.get(text)) == null ? void 0 : _a2.index) ?? -1;
|
|
90
|
-
const textRenderInfo = text.textRenderInfo;
|
|
91
|
-
if (index < 0 || !textRenderInfo) continue;
|
|
92
|
-
const startIndex = index * floatsPerMember;
|
|
93
|
-
if (!text.visible) {
|
|
94
|
-
for (let i = 0; i < 16; i++) {
|
|
95
|
-
this.setTexData(startIndex + i, 0, texData);
|
|
96
|
-
}
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const matrix = text.matrix.elements;
|
|
100
|
-
for (let i = 0; i < 16; i++) {
|
|
101
|
-
this.setTexData(startIndex + i, matrix[i], texData);
|
|
102
|
-
}
|
|
103
|
-
text._prepareForRender(material);
|
|
104
|
-
const {
|
|
105
|
-
uTroikaTotalBounds,
|
|
106
|
-
uTroikaClipRect,
|
|
107
|
-
uTroikaPositionOffset,
|
|
108
|
-
uTroikaEdgeOffset,
|
|
109
|
-
uTroikaBlurRadius,
|
|
110
|
-
uTroikaStrokeWidth,
|
|
111
|
-
uTroikaStrokeColor,
|
|
112
|
-
uTroikaStrokeOpacity,
|
|
113
|
-
uTroikaFillOpacity,
|
|
114
|
-
uTroikaCurveRadius
|
|
115
|
-
} = material.uniforms;
|
|
116
|
-
for (let i = 0; i < 4; i++) {
|
|
117
|
-
this.setTexData(startIndex + 16 + i, uTroikaTotalBounds.value.getComponent(i), texData);
|
|
118
|
-
}
|
|
119
|
-
for (let i = 0; i < 4; i++) {
|
|
120
|
-
this.setTexData(startIndex + 20 + i, uTroikaClipRect.value.getComponent(i), texData);
|
|
121
|
-
}
|
|
122
|
-
let color = isOutline ? text.outlineColor || 0 : text.color;
|
|
123
|
-
color ?? (color = this.color);
|
|
124
|
-
color ?? (color = this.material.color);
|
|
125
|
-
color ?? (color = 16777215);
|
|
126
|
-
this.setTexData(startIndex + 24, tempColor.set(color).getHex(), texData);
|
|
127
|
-
this.setTexData(startIndex + 25, uTroikaFillOpacity.value, texData);
|
|
128
|
-
this.setTexData(startIndex + 26, uTroikaCurveRadius.value, texData);
|
|
129
|
-
if (isOutline) {
|
|
130
|
-
this.setTexData(startIndex + 28, uTroikaPositionOffset.value.x, texData);
|
|
131
|
-
this.setTexData(startIndex + 29, uTroikaPositionOffset.value.y, texData);
|
|
132
|
-
this.setTexData(startIndex + 30, uTroikaEdgeOffset.value, texData);
|
|
133
|
-
this.setTexData(startIndex + 31, uTroikaBlurRadius.value, texData);
|
|
134
|
-
} else {
|
|
135
|
-
this.setTexData(startIndex + 28, uTroikaStrokeWidth.value, texData);
|
|
136
|
-
this.setTexData(startIndex + 29, tempColor.set(uTroikaStrokeColor.value).getHex(), texData);
|
|
137
|
-
this.setTexData(startIndex + 30, uTroikaStrokeOpacity.value, texData);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
texture.needsUpdate = this.textureNeedsUpdate;
|
|
141
|
-
material.setMatrixTexture(texture);
|
|
142
|
-
}
|
|
143
|
-
setTexData(index, value, texData) {
|
|
144
|
-
if (value !== texData[index]) {
|
|
145
|
-
texData[index] = value;
|
|
146
|
-
this.textureNeedsUpdate = true;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
class Text extends Text$1 {
|
|
151
|
-
_prepareForRender(material) {
|
|
152
|
-
const isOutline = material.isTextOutlineMaterial;
|
|
153
|
-
const uniforms = material.uniforms;
|
|
154
|
-
const textInfo = this.textRenderInfo;
|
|
155
|
-
if (textInfo) {
|
|
156
|
-
const { sdfTexture, blockBounds } = textInfo;
|
|
157
|
-
const { width, height } = sdfTexture.image;
|
|
158
|
-
uniforms.uTroikaSDFTexture.value = sdfTexture;
|
|
159
|
-
uniforms.uTroikaSDFTextureSize.value.set(width, height);
|
|
160
|
-
uniforms.uTroikaSDFGlyphSize.value = textInfo.sdfGlyphSize;
|
|
161
|
-
uniforms.uTroikaSDFExponent.value = textInfo.sdfExponent;
|
|
162
|
-
uniforms.uTroikaTotalBounds.value.fromArray(blockBounds);
|
|
163
|
-
uniforms.uTroikaUseGlyphColors.value = !isOutline && !!textInfo.glyphColors;
|
|
164
|
-
let distanceOffset = 0;
|
|
165
|
-
let blurRadius = 0;
|
|
166
|
-
let strokeWidth = 0;
|
|
167
|
-
let fillOpacity;
|
|
168
|
-
let strokeOpacity = 1;
|
|
169
|
-
let strokeColor;
|
|
170
|
-
let offsetX = 0;
|
|
171
|
-
let offsetY = 0;
|
|
172
|
-
if (isOutline) {
|
|
173
|
-
const { outlineWidth, outlineOffsetX, outlineOffsetY, outlineBlur, outlineOpacity } = this;
|
|
174
|
-
distanceOffset = this._parsePercent(outlineWidth) || 0;
|
|
175
|
-
blurRadius = Math.max(0, this._parsePercent(outlineBlur) || 0);
|
|
176
|
-
fillOpacity = outlineOpacity;
|
|
177
|
-
offsetX = this._parsePercent(outlineOffsetX) || 0;
|
|
178
|
-
offsetY = this._parsePercent(outlineOffsetY) || 0;
|
|
179
|
-
} else {
|
|
180
|
-
strokeWidth = Math.max(0, this._parsePercent(this.strokeWidth) || 0);
|
|
181
|
-
if (strokeWidth) {
|
|
182
|
-
strokeColor = this.strokeColor;
|
|
183
|
-
uniforms.uTroikaStrokeColor.value.set(strokeColor ?? defaultStrokeColor);
|
|
184
|
-
strokeOpacity = this.strokeOpacity;
|
|
185
|
-
strokeOpacity ?? (strokeOpacity = 1);
|
|
186
|
-
}
|
|
187
|
-
fillOpacity = this.fillOpacity;
|
|
188
|
-
}
|
|
189
|
-
uniforms.uTroikaEdgeOffset.value = distanceOffset;
|
|
190
|
-
uniforms.uTroikaPositionOffset.value.set(offsetX, offsetY);
|
|
191
|
-
uniforms.uTroikaBlurRadius.value = blurRadius;
|
|
192
|
-
uniforms.uTroikaStrokeWidth.value = strokeWidth;
|
|
193
|
-
uniforms.uTroikaStrokeOpacity.value = strokeOpacity;
|
|
194
|
-
uniforms.uTroikaFillOpacity.value = fillOpacity ?? 1;
|
|
195
|
-
uniforms.uTroikaCurveRadius.value = this.curveRadius || 0;
|
|
196
|
-
const clipRect = this.clipRect;
|
|
197
|
-
if (clipRect && Array.isArray(clipRect) && clipRect.length === 4) {
|
|
198
|
-
uniforms.uTroikaClipRect.value.fromArray(clipRect);
|
|
199
|
-
} else {
|
|
200
|
-
const pad = (this.fontSize || 0.1) * 100;
|
|
201
|
-
uniforms.uTroikaClipRect.value.set(
|
|
202
|
-
blockBounds[0] - pad,
|
|
203
|
-
blockBounds[1] - pad,
|
|
204
|
-
blockBounds[2] + pad,
|
|
205
|
-
blockBounds[3] + pad
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
this.geometry.applyClipRect(uniforms.uTroikaClipRect.value);
|
|
209
|
-
}
|
|
210
|
-
uniforms.uTroikaSDFDebug.value = !!this.debugSDF;
|
|
211
|
-
material.polygonOffset = !!this.depthOffset;
|
|
212
|
-
material.polygonOffsetFactor = material.polygonOffsetUnits = this.depthOffset || 0;
|
|
213
|
-
const color = isOutline ? this.outlineColor || 0 : this.color;
|
|
214
|
-
if (color == null) {
|
|
215
|
-
delete material.color;
|
|
216
|
-
} else {
|
|
217
|
-
const colorObj = material.hasOwnProperty("color") ? material.color : material.color = new Color();
|
|
218
|
-
if (color !== colorObj._input || typeof color === "object") {
|
|
219
|
-
colorObj.set(colorObj._input = color);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
let orient = this.orientation || defaultOrient;
|
|
223
|
-
if (orient !== material._orientation) {
|
|
224
|
-
const rotMat = uniforms.uTroikaOrient.value;
|
|
225
|
-
orient = orient.replace(/[^-+xyz]/g, "");
|
|
226
|
-
const match = orient !== defaultOrient && /^([-+])([xyz])([-+])([xyz])$/.exec(orient);
|
|
227
|
-
if (match) {
|
|
228
|
-
const [, hSign, hAxis, vSign, vAxis] = match;
|
|
229
|
-
tempVec3a.set(0, 0, 0)[hAxis] = hSign === "-" ? 1 : -1;
|
|
230
|
-
tempVec3b.set(0, 0, 0)[vAxis] = vSign === "-" ? -1 : 1;
|
|
231
|
-
tempMat4.lookAt(origin, tempVec3a.cross(tempVec3b), tempVec3b);
|
|
232
|
-
rotMat.setFromMatrix4(tempMat4);
|
|
233
|
-
} else {
|
|
234
|
-
rotMat.identity();
|
|
235
|
-
}
|
|
236
|
-
material._orientation = orient;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function setDimming(root, dim) {
|
|
241
|
-
root.userData["uDim"] = dim === void 0 ? void 0 : +dim;
|
|
242
|
-
}
|
|
243
|
-
function toggleInstanceDim(object, instanceId, dim) {
|
|
244
|
-
const value = dim === void 0 ? 0 : (+dim - 0.5) * 2;
|
|
245
|
-
if (object instanceof BatchedMesh) {
|
|
246
|
-
object.setUniformAt(instanceId, "skipDimInstance", value);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
const skipDimTexture = object.userData["skipDimTexture"];
|
|
250
|
-
if (skipDimTexture) {
|
|
251
|
-
const skipDimData = skipDimTexture.image.data;
|
|
252
|
-
skipDimData[instanceId] = value;
|
|
253
|
-
skipDimTexture.needsUpdate = true;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
function addDimToMaterial(material) {
|
|
257
|
-
if (material.userData.hasDimShader) return;
|
|
258
|
-
const onBeforeCompile = material.onBeforeCompile.bind(material);
|
|
259
|
-
const onBeforeRender = material.onBeforeRender.bind(material);
|
|
260
|
-
material.onBeforeCompile = (shader, renderer) => {
|
|
261
|
-
onBeforeCompile(shader, renderer);
|
|
262
|
-
shader.uniforms["uDim"] = { value: material.userData.uDim ?? 0 };
|
|
263
|
-
shader.uniforms["skipDimTexture"] = { value: material.userData.skipDimTexture ?? null };
|
|
264
|
-
shader.vertexShader = shader.vertexShader.replace("void main() {", `${dimColorVertexDefs}
|
|
265
|
-
void main() {`).replace(
|
|
266
|
-
"#include <fog_vertex>",
|
|
267
|
-
/*glsl*/
|
|
268
|
-
`
|
|
269
|
-
#include <fog_vertex>
|
|
270
|
-
setDimAmount();
|
|
271
|
-
`
|
|
272
|
-
).concat(dimColorVertexImpl);
|
|
273
|
-
shader.fragmentShader = /*glsl*/
|
|
274
|
-
`
|
|
275
|
-
${dimColorFrag}
|
|
276
|
-
${shader.fragmentShader}
|
|
277
|
-
`.replace(
|
|
278
|
-
"#include <colorspace_fragment>",
|
|
279
|
-
/*glsl*/
|
|
280
|
-
`
|
|
281
|
-
gl_FragColor = dimColor(gl_FragColor);
|
|
282
|
-
#include <colorspace_fragment>
|
|
283
|
-
`
|
|
284
|
-
);
|
|
285
|
-
material.userData.shader = shader;
|
|
286
|
-
};
|
|
287
|
-
material.onBeforeRender = (renderer, scene, camera, geometry, object, group) => {
|
|
288
|
-
onBeforeRender(renderer, scene, camera, geometry, object, group);
|
|
289
|
-
const skipDimTexture = object.userData["skipDimTexture"];
|
|
290
|
-
let uDim = object.userData["uDim"];
|
|
291
|
-
if (uDim === void 0) {
|
|
292
|
-
for (const ancestor of traverseAncestorsGenerator(object)) {
|
|
293
|
-
if (ancestor.userData["uDim"] !== void 0) {
|
|
294
|
-
uDim = ancestor.userData["uDim"];
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const shader = material.userData.shader;
|
|
300
|
-
if (!shader) {
|
|
301
|
-
material.userData.uDim = uDim;
|
|
302
|
-
material.userData.skipDimTexture = object.userData["skipDimTexture"];
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
shader.uniforms["uDim"].value = uDim ?? 0;
|
|
306
|
-
shader.uniforms["skipDimTexture"].value = skipDimTexture ?? null;
|
|
307
|
-
};
|
|
308
|
-
material.userData.hasDimShader = true;
|
|
309
|
-
}
|
|
310
|
-
function addDim(mesh) {
|
|
311
|
-
if (mesh instanceof BatchedMesh) mesh.addPerInstanceUniforms({ vertex: { skipDimInstance: "float" } });
|
|
312
|
-
if (mesh instanceof BatchedText) addSkipDimTexture(mesh);
|
|
313
|
-
}
|
|
314
|
-
function addSkipDimTexture(text) {
|
|
315
|
-
const count = text.size;
|
|
316
|
-
const size = Math.ceil(Math.sqrt(count));
|
|
317
|
-
const array = new Float32Array(size * size);
|
|
318
|
-
array.fill(0);
|
|
319
|
-
const texture = new DataTexture(array, size, size, RedFormat, FloatType);
|
|
320
|
-
texture.needsUpdate = true;
|
|
321
|
-
text.userData["skipDimTexture"] = texture;
|
|
322
|
-
text.addEventListener("dispose", () => texture.dispose());
|
|
323
|
-
return texture;
|
|
324
|
-
}
|
|
325
|
-
const dimColorVertexDefs = (
|
|
326
|
-
/*glsl*/
|
|
327
|
-
`
|
|
328
|
-
uniform float uDim;
|
|
329
|
-
out float dimAmount;
|
|
330
|
-
#ifdef TROIKA_DERIVED_MATERIAL_1
|
|
331
|
-
uniform sampler2D skipDimTexture;
|
|
332
|
-
#endif
|
|
333
|
-
void setDimAmount();
|
|
334
|
-
`
|
|
335
|
-
);
|
|
336
|
-
const dimColorVertexImpl = (
|
|
337
|
-
/*glsl*/
|
|
338
|
-
`
|
|
339
|
-
void setDimAmount() {
|
|
340
|
-
float instanceDim = 0.;
|
|
341
|
-
#ifdef USE_BATCH_UNIFORMS
|
|
342
|
-
instanceDim = batch_skipDimInstance;
|
|
343
|
-
#endif
|
|
344
|
-
#ifdef TROIKA_DERIVED_MATERIAL_1
|
|
345
|
-
float indirectIndex = aTroikaTextBatchMemberIndex;
|
|
346
|
-
int size = textureSize(skipDimTexture, 0).x;
|
|
347
|
-
int i = int(indirectIndex);
|
|
348
|
-
int x = i % size;
|
|
349
|
-
int y = i / size;
|
|
350
|
-
instanceDim = texelFetch(skipDimTexture, ivec2(x, y), 0).r;
|
|
351
|
-
#endif
|
|
352
|
-
dimAmount = instanceDim == 0. ? uDim : instanceDim / 2. + 0.5;
|
|
353
|
-
}
|
|
354
|
-
`
|
|
355
|
-
);
|
|
356
|
-
const dimColorFrag = (
|
|
357
|
-
/*glsl*/
|
|
358
|
-
`
|
|
359
|
-
in float dimAmount;
|
|
360
|
-
|
|
361
|
-
const vec3 grayWeights = vec3(0.299, 0.587, 0.114);
|
|
362
|
-
const float darkenFactor = pow(2., 2.2); // Gamma corrected
|
|
363
|
-
|
|
364
|
-
vec4 dimColor(vec4 col) {
|
|
365
|
-
vec3 color = col.rgb / col.a;
|
|
366
|
-
vec3 gray = vec3(dot(grayWeights, color));
|
|
367
|
-
vec3 m = mix(color, gray / darkenFactor, dimAmount);
|
|
368
|
-
return vec4(m * col.a, col.a);
|
|
369
|
-
}`
|
|
370
|
-
);
|
|
371
15
|
function createLogger(namespace) {
|
|
372
16
|
const fullNamespace = namespace ? `renderer:${namespace}` : "renderer";
|
|
373
17
|
const info = createLog(fullNamespace);
|
|
@@ -653,7 +297,7 @@ class SquareDataTexture extends DataTexture {
|
|
|
653
297
|
const componentsArray = ["r", "g", "b", "a"];
|
|
654
298
|
const batchIdName = "batchId";
|
|
655
299
|
const logger$a = createLogger("BatchedMesh");
|
|
656
|
-
|
|
300
|
+
class BatchedMesh extends BatchedMesh$1 {
|
|
657
301
|
/**
|
|
658
302
|
* @param instanceCount the max number of individual geometries planned to be added.
|
|
659
303
|
* @param vertexCount the max number of vertices to be used by all geometries.
|
|
@@ -672,12 +316,6 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
|
|
|
672
316
|
__publicField(this, "mapGeometryToInstanceId", /* @__PURE__ */ new Map());
|
|
673
317
|
material.forceSinglePass = true;
|
|
674
318
|
addDim(this);
|
|
675
|
-
this.addEventListener("added", () => {
|
|
676
|
-
if (!_BatchedMesh.useMultiDraw && this.geometry.index !== null) {
|
|
677
|
-
this.geometry = this.geometry.toNonIndexed();
|
|
678
|
-
this.resizeToFitGeometry(this.geometry);
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
319
|
}
|
|
682
320
|
/**
|
|
683
321
|
* Appends uniform definitions to the current schema, and creates a new {@link SquareDataTexture} if needed.
|
|
@@ -698,45 +336,18 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
|
|
|
698
336
|
if (!this.isMaterialPatched) this.patchMaterial(this.material);
|
|
699
337
|
}
|
|
700
338
|
addGeometry(geometry, reservedVertexRange, reservedIndexRange) {
|
|
701
|
-
|
|
702
|
-
this.addBatchIdBuffer(geometry, this.instanceCount);
|
|
703
|
-
const geometryId = super.addGeometry(geometry, reservedVertexRange, reservedIndexRange);
|
|
704
|
-
this.geometryById.set(geometryId, geometry);
|
|
705
|
-
return geometryId;
|
|
339
|
+
return super.addGeometry(geometry, reservedVertexRange, reservedIndexRange);
|
|
706
340
|
}
|
|
707
341
|
addInstance(geometryId) {
|
|
708
|
-
|
|
709
|
-
if (this.mapGeometryToInstanceId.has(geometryId)) {
|
|
710
|
-
const geometry = this.geometryById.get(geometryId);
|
|
711
|
-
this.resizeToFitGeometry(geometry);
|
|
712
|
-
geometryId = this.addGeometry(geometry);
|
|
713
|
-
}
|
|
714
|
-
const instanceId = super.addInstance(geometryId);
|
|
715
|
-
this.mapGeometryToInstanceId.set(geometryId, instanceId);
|
|
716
|
-
return instanceId;
|
|
342
|
+
return super.addInstance(geometryId);
|
|
717
343
|
}
|
|
718
344
|
onBeforeRender(renderer, scene, camera, geometry, material, group) {
|
|
719
345
|
var _a2;
|
|
720
346
|
(_a2 = this.uniformsTexture) == null ? void 0 : _a2.update();
|
|
721
|
-
|
|
722
|
-
if (!this.indexBuffer) {
|
|
723
|
-
const vertexCount = geometry.getAttribute("position").count;
|
|
724
|
-
this.indexBuffer = new BufferAttribute(new Uint32Array(vertexCount), 1).setUsage(StreamDrawUsage);
|
|
725
|
-
}
|
|
726
|
-
super.onBeforeRender(renderer, scene, camera, geometry, material, group);
|
|
727
|
-
this.batchCount = this.updateIndexBuffer(geometry);
|
|
728
|
-
this._multiDrawCount = 0;
|
|
347
|
+
return super.onBeforeRender(renderer, scene, camera, geometry, material, group);
|
|
729
348
|
}
|
|
730
349
|
onAfterRender(renderer, scene, camera, geometry) {
|
|
731
|
-
|
|
732
|
-
if (_BatchedMesh.useMultiDraw) return;
|
|
733
|
-
const batchCount = this.batchCount;
|
|
734
|
-
const gl = renderer.getContext();
|
|
735
|
-
if (geometry.index == null) return logger$a.debug("No index buffer", (_a2 = this.parent) == null ? void 0 : _a2.name);
|
|
736
|
-
const type = this.getIndexType(gl, geometry.index);
|
|
737
|
-
gl.drawElements(gl.TRIANGLES, batchCount, type, 0);
|
|
738
|
-
renderer.info.update(batchCount, gl.TRIANGLES, 1);
|
|
739
|
-
geometry.setIndex(null);
|
|
350
|
+
return;
|
|
740
351
|
}
|
|
741
352
|
/**
|
|
742
353
|
* Retrieves the value of a uniform at the specified instance ID.
|
|
@@ -845,19 +456,7 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
|
|
|
845
456
|
vertex: "",
|
|
846
457
|
fragment: ""
|
|
847
458
|
};
|
|
848
|
-
const patch = (
|
|
849
|
-
/*glsl*/
|
|
850
|
-
`
|
|
851
|
-
#ifdef gl_DrawID
|
|
852
|
-
#define _gl_DrawID ${batchIdName}
|
|
853
|
-
#else
|
|
854
|
-
#define gl_DrawID ${batchIdName}
|
|
855
|
-
#endif
|
|
856
|
-
in int ${batchIdName};
|
|
857
|
-
`
|
|
858
|
-
);
|
|
859
459
|
const main = "void main() {";
|
|
860
|
-
if (!_BatchedMesh.useMultiDraw) shader.vertexShader = shader.vertexShader.replace(main, `${patch}${main}`);
|
|
861
460
|
if (vertex) shader.vertexShader = shader.vertexShader.replace(main, vertex);
|
|
862
461
|
if (fragment) shader.fragmentShader = shader.fragmentShader.replace(main, fragment);
|
|
863
462
|
};
|
|
@@ -881,66 +480,421 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
|
|
|
881
480
|
uniforms.push({ name, type, size });
|
|
882
481
|
fetchInFragmentShader = false;
|
|
883
482
|
}
|
|
884
|
-
for (const name in fragmentSchema) {
|
|
885
|
-
if (!vertexSchema[name]) {
|
|
886
|
-
const type = fragmentSchema[name];
|
|
887
|
-
const size = this.getUniformSize(type);
|
|
888
|
-
totalSize += size;
|
|
889
|
-
uniforms.push({ name, type, size });
|
|
483
|
+
for (const name in fragmentSchema) {
|
|
484
|
+
if (!vertexSchema[name]) {
|
|
485
|
+
const type = fragmentSchema[name];
|
|
486
|
+
const size = this.getUniformSize(type);
|
|
487
|
+
totalSize += size;
|
|
488
|
+
uniforms.push({ name, type, size });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
uniforms.sort((a, b) => b.size - a.size);
|
|
492
|
+
const tempOffset = [];
|
|
493
|
+
for (const { name, size, type } of uniforms) {
|
|
494
|
+
const offset = this.getUniformOffset(size, tempOffset);
|
|
495
|
+
uniformMap.set(name, { offset, size, type });
|
|
496
|
+
}
|
|
497
|
+
const pixelsPerInstance = Math.ceil(totalSize / 4);
|
|
498
|
+
const channels = Math.min(totalSize, 4);
|
|
499
|
+
return { channels, texelsPerInstance: pixelsPerInstance, uniformMap, fetchInFragmentShader };
|
|
500
|
+
}
|
|
501
|
+
getUniformOffset(size, tempOffset) {
|
|
502
|
+
if (size < 4) {
|
|
503
|
+
for (let i = 0; i < tempOffset.length; i++) {
|
|
504
|
+
if (tempOffset[i] + size <= 4) {
|
|
505
|
+
const offset2 = i * 4 + tempOffset[i];
|
|
506
|
+
tempOffset[i] += size;
|
|
507
|
+
return offset2;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const offset = tempOffset.length * 4;
|
|
512
|
+
for (; size > 0; size -= 4) {
|
|
513
|
+
tempOffset.push(size);
|
|
514
|
+
}
|
|
515
|
+
return offset;
|
|
516
|
+
}
|
|
517
|
+
getUniformSize(type) {
|
|
518
|
+
switch (type) {
|
|
519
|
+
case "float":
|
|
520
|
+
return 1;
|
|
521
|
+
case "vec2":
|
|
522
|
+
return 2;
|
|
523
|
+
case "vec3":
|
|
524
|
+
return 3;
|
|
525
|
+
case "vec4":
|
|
526
|
+
return 4;
|
|
527
|
+
case "mat3":
|
|
528
|
+
return 9;
|
|
529
|
+
case "mat4":
|
|
530
|
+
return 16;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
getIndexType(gl, index) {
|
|
534
|
+
const array = index.array;
|
|
535
|
+
if (array instanceof Uint16Array) return gl.UNSIGNED_SHORT;
|
|
536
|
+
if (array instanceof Uint32Array) return gl.UNSIGNED_INT;
|
|
537
|
+
return gl.UNSIGNED_BYTE;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/** Whether to use WebGL_multi_draw extension or less performant fallback */
|
|
541
|
+
__publicField(BatchedMesh, "useMultiDraw", true);
|
|
542
|
+
const floatsPerMember = 32;
|
|
543
|
+
const tempColor = new Color();
|
|
544
|
+
const defaultStrokeColor = 8421504;
|
|
545
|
+
const tempMat4 = new Matrix4();
|
|
546
|
+
const tempVec3a = new Vector3();
|
|
547
|
+
const tempVec3b = new Vector3();
|
|
548
|
+
const origin = new Vector3();
|
|
549
|
+
const defaultOrient = "+x+y";
|
|
550
|
+
class BatchedText extends BatchedText$1 {
|
|
551
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
552
|
+
constructor() {
|
|
553
|
+
super();
|
|
554
|
+
__publicField(this, "mapInstanceIdToText", /* @__PURE__ */ new Map());
|
|
555
|
+
__publicField(this, "textArray", []);
|
|
556
|
+
__publicField(this, "textureNeedsUpdate", false);
|
|
557
|
+
}
|
|
558
|
+
/** Number of texts in the batch */
|
|
559
|
+
get size() {
|
|
560
|
+
return this._members.size;
|
|
561
|
+
}
|
|
562
|
+
/** Base material before patching */
|
|
563
|
+
get baseMaterial() {
|
|
564
|
+
return this._baseMaterial;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Get the {@link Text} object by instance id
|
|
568
|
+
* @param instanceId Instance id
|
|
569
|
+
* @returns Text object
|
|
570
|
+
*/
|
|
571
|
+
getText(instanceId) {
|
|
572
|
+
return this.mapInstanceIdToText.get(instanceId);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Set the visibility of the {@link Text} object by instance id.
|
|
576
|
+
* This is for interface compatibility with {@link BatchedMesh}.
|
|
577
|
+
* @param instanceId Instance id
|
|
578
|
+
* @param visible Visibility flag
|
|
579
|
+
*/
|
|
580
|
+
setVisibleAt(instanceId, visible) {
|
|
581
|
+
const text = this.getText(instanceId);
|
|
582
|
+
text.visible = visible;
|
|
583
|
+
}
|
|
584
|
+
addText(text, instanceId) {
|
|
585
|
+
super.addText(text);
|
|
586
|
+
if (instanceId !== void 0) {
|
|
587
|
+
this.mapInstanceIdToText.set(instanceId, text);
|
|
588
|
+
}
|
|
589
|
+
this.textArray.push(text);
|
|
590
|
+
}
|
|
591
|
+
dispose() {
|
|
592
|
+
super.dispose();
|
|
593
|
+
this.dispatchEvent({ type: "dispose" });
|
|
594
|
+
}
|
|
595
|
+
// TODO: Check performance
|
|
596
|
+
_prepareForRender(material) {
|
|
597
|
+
var _a2;
|
|
598
|
+
const isOutline = material.isTextOutlineMaterial;
|
|
599
|
+
material.uniforms.uTroikaIsOutline.value = isOutline;
|
|
600
|
+
let texture = this._dataTextures[isOutline ? "outline" : "main"];
|
|
601
|
+
const dataLength = Math.pow(2, Math.ceil(Math.log2(this._members.size * floatsPerMember)));
|
|
602
|
+
if (!texture || dataLength !== texture.image.data.length) {
|
|
603
|
+
if (texture) texture.dispose();
|
|
604
|
+
const width = Math.min(dataLength / 4, 1024);
|
|
605
|
+
texture = this._dataTextures[isOutline ? "outline" : "main"] = new DataTexture(
|
|
606
|
+
new Float32Array(dataLength),
|
|
607
|
+
width,
|
|
608
|
+
dataLength / 4 / width,
|
|
609
|
+
RGBAFormat,
|
|
610
|
+
FloatType
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
const texData = texture.image.data;
|
|
614
|
+
this.textureNeedsUpdate = false;
|
|
615
|
+
for (const text of this.textArray) {
|
|
616
|
+
const index = ((_a2 = this._members.get(text)) == null ? void 0 : _a2.index) ?? -1;
|
|
617
|
+
const textRenderInfo = text.textRenderInfo;
|
|
618
|
+
if (index < 0 || !textRenderInfo) continue;
|
|
619
|
+
const startIndex = index * floatsPerMember;
|
|
620
|
+
if (!text.visible) {
|
|
621
|
+
for (let i = 0; i < 16; i++) {
|
|
622
|
+
this.setTexData(startIndex + i, 0, texData);
|
|
623
|
+
}
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const matrix = text.matrix.elements;
|
|
627
|
+
for (let i = 0; i < 16; i++) {
|
|
628
|
+
this.setTexData(startIndex + i, matrix[i], texData);
|
|
629
|
+
}
|
|
630
|
+
text._prepareForRender(material);
|
|
631
|
+
const {
|
|
632
|
+
uTroikaTotalBounds,
|
|
633
|
+
uTroikaClipRect,
|
|
634
|
+
uTroikaPositionOffset,
|
|
635
|
+
uTroikaEdgeOffset,
|
|
636
|
+
uTroikaBlurRadius,
|
|
637
|
+
uTroikaStrokeWidth,
|
|
638
|
+
uTroikaStrokeColor,
|
|
639
|
+
uTroikaStrokeOpacity,
|
|
640
|
+
uTroikaFillOpacity,
|
|
641
|
+
uTroikaCurveRadius
|
|
642
|
+
} = material.uniforms;
|
|
643
|
+
for (let i = 0; i < 4; i++) {
|
|
644
|
+
this.setTexData(startIndex + 16 + i, uTroikaTotalBounds.value.getComponent(i), texData);
|
|
645
|
+
}
|
|
646
|
+
for (let i = 0; i < 4; i++) {
|
|
647
|
+
this.setTexData(startIndex + 20 + i, uTroikaClipRect.value.getComponent(i), texData);
|
|
648
|
+
}
|
|
649
|
+
let color = isOutline ? text.outlineColor || 0 : text.color;
|
|
650
|
+
color ?? (color = this.color);
|
|
651
|
+
color ?? (color = this.material.color);
|
|
652
|
+
color ?? (color = 16777215);
|
|
653
|
+
this.setTexData(startIndex + 24, tempColor.set(color).getHex(), texData);
|
|
654
|
+
this.setTexData(startIndex + 25, uTroikaFillOpacity.value, texData);
|
|
655
|
+
this.setTexData(startIndex + 26, uTroikaCurveRadius.value, texData);
|
|
656
|
+
if (isOutline) {
|
|
657
|
+
this.setTexData(startIndex + 28, uTroikaPositionOffset.value.x, texData);
|
|
658
|
+
this.setTexData(startIndex + 29, uTroikaPositionOffset.value.y, texData);
|
|
659
|
+
this.setTexData(startIndex + 30, uTroikaEdgeOffset.value, texData);
|
|
660
|
+
this.setTexData(startIndex + 31, uTroikaBlurRadius.value, texData);
|
|
661
|
+
} else {
|
|
662
|
+
this.setTexData(startIndex + 28, uTroikaStrokeWidth.value, texData);
|
|
663
|
+
this.setTexData(startIndex + 29, tempColor.set(uTroikaStrokeColor.value).getHex(), texData);
|
|
664
|
+
this.setTexData(startIndex + 30, uTroikaStrokeOpacity.value, texData);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
texture.needsUpdate = this.textureNeedsUpdate;
|
|
668
|
+
material.setMatrixTexture(texture);
|
|
669
|
+
}
|
|
670
|
+
setTexData(index, value, texData) {
|
|
671
|
+
if (value !== texData[index]) {
|
|
672
|
+
texData[index] = value;
|
|
673
|
+
this.textureNeedsUpdate = true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
class Text extends Text$1 {
|
|
678
|
+
_prepareForRender(material) {
|
|
679
|
+
const isOutline = material.isTextOutlineMaterial;
|
|
680
|
+
const uniforms = material.uniforms;
|
|
681
|
+
const textInfo = this.textRenderInfo;
|
|
682
|
+
if (textInfo) {
|
|
683
|
+
const { sdfTexture, blockBounds } = textInfo;
|
|
684
|
+
const { width, height } = sdfTexture.image;
|
|
685
|
+
uniforms.uTroikaSDFTexture.value = sdfTexture;
|
|
686
|
+
uniforms.uTroikaSDFTextureSize.value.set(width, height);
|
|
687
|
+
uniforms.uTroikaSDFGlyphSize.value = textInfo.sdfGlyphSize;
|
|
688
|
+
uniforms.uTroikaSDFExponent.value = textInfo.sdfExponent;
|
|
689
|
+
uniforms.uTroikaTotalBounds.value.fromArray(blockBounds);
|
|
690
|
+
uniforms.uTroikaUseGlyphColors.value = !isOutline && !!textInfo.glyphColors;
|
|
691
|
+
let distanceOffset = 0;
|
|
692
|
+
let blurRadius = 0;
|
|
693
|
+
let strokeWidth = 0;
|
|
694
|
+
let fillOpacity;
|
|
695
|
+
let strokeOpacity = 1;
|
|
696
|
+
let strokeColor;
|
|
697
|
+
let offsetX = 0;
|
|
698
|
+
let offsetY = 0;
|
|
699
|
+
if (isOutline) {
|
|
700
|
+
const { outlineWidth, outlineOffsetX, outlineOffsetY, outlineBlur, outlineOpacity } = this;
|
|
701
|
+
distanceOffset = this._parsePercent(outlineWidth) || 0;
|
|
702
|
+
blurRadius = Math.max(0, this._parsePercent(outlineBlur) || 0);
|
|
703
|
+
fillOpacity = outlineOpacity;
|
|
704
|
+
offsetX = this._parsePercent(outlineOffsetX) || 0;
|
|
705
|
+
offsetY = this._parsePercent(outlineOffsetY) || 0;
|
|
706
|
+
} else {
|
|
707
|
+
strokeWidth = Math.max(0, this._parsePercent(this.strokeWidth) || 0);
|
|
708
|
+
if (strokeWidth) {
|
|
709
|
+
strokeColor = this.strokeColor;
|
|
710
|
+
uniforms.uTroikaStrokeColor.value.set(strokeColor ?? defaultStrokeColor);
|
|
711
|
+
strokeOpacity = this.strokeOpacity;
|
|
712
|
+
strokeOpacity ?? (strokeOpacity = 1);
|
|
713
|
+
}
|
|
714
|
+
fillOpacity = this.fillOpacity;
|
|
715
|
+
}
|
|
716
|
+
uniforms.uTroikaEdgeOffset.value = distanceOffset;
|
|
717
|
+
uniforms.uTroikaPositionOffset.value.set(offsetX, offsetY);
|
|
718
|
+
uniforms.uTroikaBlurRadius.value = blurRadius;
|
|
719
|
+
uniforms.uTroikaStrokeWidth.value = strokeWidth;
|
|
720
|
+
uniforms.uTroikaStrokeOpacity.value = strokeOpacity;
|
|
721
|
+
uniforms.uTroikaFillOpacity.value = fillOpacity ?? 1;
|
|
722
|
+
uniforms.uTroikaCurveRadius.value = this.curveRadius || 0;
|
|
723
|
+
const clipRect = this.clipRect;
|
|
724
|
+
if (clipRect && Array.isArray(clipRect) && clipRect.length === 4) {
|
|
725
|
+
uniforms.uTroikaClipRect.value.fromArray(clipRect);
|
|
726
|
+
} else {
|
|
727
|
+
const pad = (this.fontSize || 0.1) * 100;
|
|
728
|
+
uniforms.uTroikaClipRect.value.set(
|
|
729
|
+
blockBounds[0] - pad,
|
|
730
|
+
blockBounds[1] - pad,
|
|
731
|
+
blockBounds[2] + pad,
|
|
732
|
+
blockBounds[3] + pad
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
this.geometry.applyClipRect(uniforms.uTroikaClipRect.value);
|
|
736
|
+
}
|
|
737
|
+
uniforms.uTroikaSDFDebug.value = !!this.debugSDF;
|
|
738
|
+
material.polygonOffset = !!this.depthOffset;
|
|
739
|
+
material.polygonOffsetFactor = material.polygonOffsetUnits = this.depthOffset || 0;
|
|
740
|
+
const color = isOutline ? this.outlineColor || 0 : this.color;
|
|
741
|
+
if (color == null) {
|
|
742
|
+
delete material.color;
|
|
743
|
+
} else {
|
|
744
|
+
const colorObj = material.hasOwnProperty("color") ? material.color : material.color = new Color();
|
|
745
|
+
if (color !== colorObj._input || typeof color === "object") {
|
|
746
|
+
colorObj.set(colorObj._input = color);
|
|
890
747
|
}
|
|
891
748
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
749
|
+
let orient = this.orientation || defaultOrient;
|
|
750
|
+
if (orient !== material._orientation) {
|
|
751
|
+
const rotMat = uniforms.uTroikaOrient.value;
|
|
752
|
+
orient = orient.replace(/[^-+xyz]/g, "");
|
|
753
|
+
const match = orient !== defaultOrient && /^([-+])([xyz])([-+])([xyz])$/.exec(orient);
|
|
754
|
+
if (match) {
|
|
755
|
+
const [, hSign, hAxis, vSign, vAxis] = match;
|
|
756
|
+
tempVec3a.set(0, 0, 0)[hAxis] = hSign === "-" ? 1 : -1;
|
|
757
|
+
tempVec3b.set(0, 0, 0)[vAxis] = vSign === "-" ? -1 : 1;
|
|
758
|
+
tempMat4.lookAt(origin, tempVec3a.cross(tempVec3b), tempVec3b);
|
|
759
|
+
rotMat.setFromMatrix4(tempMat4);
|
|
760
|
+
} else {
|
|
761
|
+
rotMat.identity();
|
|
762
|
+
}
|
|
763
|
+
material._orientation = orient;
|
|
897
764
|
}
|
|
898
|
-
const pixelsPerInstance = Math.ceil(totalSize / 4);
|
|
899
|
-
const channels = Math.min(totalSize, 4);
|
|
900
|
-
return { channels, texelsPerInstance: pixelsPerInstance, uniformMap, fetchInFragmentShader };
|
|
901
765
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
766
|
+
}
|
|
767
|
+
function setDimming(root, dim) {
|
|
768
|
+
root.userData["uDim"] = dim === void 0 ? void 0 : +dim;
|
|
769
|
+
}
|
|
770
|
+
function toggleInstanceDim(object, instanceId, dim) {
|
|
771
|
+
const value = dim === void 0 ? 0 : (+dim - 0.5) * 2;
|
|
772
|
+
if (object instanceof BatchedMesh) {
|
|
773
|
+
object.setUniformAt(instanceId, "skipDimInstance", value);
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
const skipDimTexture = object.userData["skipDimTexture"];
|
|
777
|
+
if (skipDimTexture) {
|
|
778
|
+
const skipDimData = skipDimTexture.image.data;
|
|
779
|
+
skipDimData[instanceId] = value;
|
|
780
|
+
skipDimTexture.needsUpdate = true;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
function addDimToMaterial(material) {
|
|
784
|
+
if (material.userData.hasDimShader) return;
|
|
785
|
+
const onBeforeCompile = material.onBeforeCompile.bind(material);
|
|
786
|
+
const onBeforeRender = material.onBeforeRender.bind(material);
|
|
787
|
+
material.onBeforeCompile = (shader, renderer) => {
|
|
788
|
+
onBeforeCompile(shader, renderer);
|
|
789
|
+
shader.uniforms["uDim"] = { value: material.userData.uDim ?? 0 };
|
|
790
|
+
shader.uniforms["skipDimTexture"] = { value: material.userData.skipDimTexture ?? null };
|
|
791
|
+
shader.vertexShader = shader.vertexShader.replace("void main() {", `${dimColorVertexDefs}
|
|
792
|
+
void main() {`).replace(
|
|
793
|
+
"#include <fog_vertex>",
|
|
794
|
+
/*glsl*/
|
|
795
|
+
`
|
|
796
|
+
#include <fog_vertex>
|
|
797
|
+
setDimAmount();
|
|
798
|
+
`
|
|
799
|
+
).concat(dimColorVertexImpl);
|
|
800
|
+
shader.fragmentShader = /*glsl*/
|
|
801
|
+
`
|
|
802
|
+
${dimColorFrag}
|
|
803
|
+
${shader.fragmentShader}
|
|
804
|
+
`.replace(
|
|
805
|
+
"#include <colorspace_fragment>",
|
|
806
|
+
/*glsl*/
|
|
807
|
+
`
|
|
808
|
+
gl_FragColor = dimColor(gl_FragColor);
|
|
809
|
+
#include <colorspace_fragment>
|
|
810
|
+
`
|
|
811
|
+
);
|
|
812
|
+
material.userData.shader = shader;
|
|
813
|
+
};
|
|
814
|
+
material.onBeforeRender = (renderer, scene, camera, geometry, object, group) => {
|
|
815
|
+
onBeforeRender(renderer, scene, camera, geometry, object, group);
|
|
816
|
+
const skipDimTexture = object.userData["skipDimTexture"];
|
|
817
|
+
let uDim = object.userData["uDim"];
|
|
818
|
+
if (uDim === void 0) {
|
|
819
|
+
for (const ancestor of traverseAncestorsGenerator(object)) {
|
|
820
|
+
if (ancestor.userData["uDim"] !== void 0) {
|
|
821
|
+
uDim = ancestor.userData["uDim"];
|
|
822
|
+
break;
|
|
909
823
|
}
|
|
910
824
|
}
|
|
911
825
|
}
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
}
|
|
918
|
-
getUniformSize(type) {
|
|
919
|
-
switch (type) {
|
|
920
|
-
case "float":
|
|
921
|
-
return 1;
|
|
922
|
-
case "vec2":
|
|
923
|
-
return 2;
|
|
924
|
-
case "vec3":
|
|
925
|
-
return 3;
|
|
926
|
-
case "vec4":
|
|
927
|
-
return 4;
|
|
928
|
-
case "mat3":
|
|
929
|
-
return 9;
|
|
930
|
-
case "mat4":
|
|
931
|
-
return 16;
|
|
826
|
+
const shader = material.userData.shader;
|
|
827
|
+
if (!shader) {
|
|
828
|
+
material.userData.uDim = uDim;
|
|
829
|
+
material.userData.skipDimTexture = object.userData["skipDimTexture"];
|
|
830
|
+
return;
|
|
932
831
|
}
|
|
832
|
+
shader.uniforms["uDim"].value = uDim ?? 0;
|
|
833
|
+
shader.uniforms["skipDimTexture"].value = skipDimTexture ?? null;
|
|
834
|
+
};
|
|
835
|
+
material.userData.hasDimShader = true;
|
|
836
|
+
}
|
|
837
|
+
function addDim(mesh) {
|
|
838
|
+
if (mesh instanceof BatchedMesh) mesh.addPerInstanceUniforms({ vertex: { skipDimInstance: "float" } });
|
|
839
|
+
if (mesh instanceof BatchedText) addSkipDimTexture(mesh);
|
|
840
|
+
}
|
|
841
|
+
function addSkipDimTexture(text) {
|
|
842
|
+
const count = text.size;
|
|
843
|
+
const size = Math.ceil(Math.sqrt(count));
|
|
844
|
+
const array = new Float32Array(size * size);
|
|
845
|
+
array.fill(0);
|
|
846
|
+
const texture = new DataTexture(array, size, size, RedFormat, FloatType);
|
|
847
|
+
texture.needsUpdate = true;
|
|
848
|
+
text.userData["skipDimTexture"] = texture;
|
|
849
|
+
text.addEventListener("dispose", () => texture.dispose());
|
|
850
|
+
return texture;
|
|
851
|
+
}
|
|
852
|
+
const dimColorVertexDefs = (
|
|
853
|
+
/*glsl*/
|
|
854
|
+
`
|
|
855
|
+
uniform float uDim;
|
|
856
|
+
out float dimAmount;
|
|
857
|
+
#ifdef TROIKA_DERIVED_MATERIAL_1
|
|
858
|
+
uniform sampler2D skipDimTexture;
|
|
859
|
+
#endif
|
|
860
|
+
void setDimAmount();
|
|
861
|
+
`
|
|
862
|
+
);
|
|
863
|
+
const dimColorVertexImpl = (
|
|
864
|
+
/*glsl*/
|
|
865
|
+
`
|
|
866
|
+
void setDimAmount() {
|
|
867
|
+
float instanceDim = 0.;
|
|
868
|
+
#ifdef USE_BATCH_UNIFORMS
|
|
869
|
+
instanceDim = batch_skipDimInstance;
|
|
870
|
+
#endif
|
|
871
|
+
#ifdef TROIKA_DERIVED_MATERIAL_1
|
|
872
|
+
float indirectIndex = aTroikaTextBatchMemberIndex;
|
|
873
|
+
int size = textureSize(skipDimTexture, 0).x;
|
|
874
|
+
int i = int(indirectIndex);
|
|
875
|
+
int x = i % size;
|
|
876
|
+
int y = i / size;
|
|
877
|
+
instanceDim = texelFetch(skipDimTexture, ivec2(x, y), 0).r;
|
|
878
|
+
#endif
|
|
879
|
+
dimAmount = instanceDim == 0. ? uDim : instanceDim / 2. + 0.5;
|
|
933
880
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
881
|
+
`
|
|
882
|
+
);
|
|
883
|
+
const dimColorFrag = (
|
|
884
|
+
/*glsl*/
|
|
885
|
+
`
|
|
886
|
+
in float dimAmount;
|
|
887
|
+
|
|
888
|
+
const vec3 grayWeights = vec3(0.299, 0.587, 0.114);
|
|
889
|
+
const float darkenFactor = pow(2., 2.2); // Gamma corrected
|
|
890
|
+
|
|
891
|
+
vec4 dimColor(vec4 col) {
|
|
892
|
+
vec3 color = col.rgb / col.a;
|
|
893
|
+
vec3 gray = vec3(dot(grayWeights, color));
|
|
894
|
+
vec3 m = mix(color, gray / darkenFactor, dimAmount);
|
|
895
|
+
return vec4(m * col.a, col.a);
|
|
896
|
+
}`
|
|
897
|
+
);
|
|
944
898
|
const sharedParameters = {
|
|
945
899
|
side: DoubleSide,
|
|
946
900
|
transparent: true,
|
|
@@ -1451,14 +1405,15 @@ class ImageSystem extends RenderableSystem {
|
|
|
1451
1405
|
logger$9.debug(`New memory usage after resizing: ${newTotal} bytes`);
|
|
1452
1406
|
}
|
|
1453
1407
|
updateDefImpl(imageDef, mesh, instanceIds) {
|
|
1408
|
+
const instanceId = instanceIds[0];
|
|
1454
1409
|
const bounds = imageDef.bounds;
|
|
1455
1410
|
const origin2 = imageDef.origin ?? [0.5, 0.5];
|
|
1456
1411
|
this.originTranslationMatrix.makeTranslation(0.5 - origin2[0], 0.5 - origin2[1], 0);
|
|
1457
1412
|
this.globalTranslationMatrix.makeTranslation(bounds.center.x, bounds.center.y, 0);
|
|
1458
|
-
this.scaleMatrix.makeScale(bounds.size.
|
|
1413
|
+
this.scaleMatrix.makeScale(bounds.size.x, bounds.size.y, 1);
|
|
1459
1414
|
this.rotationMatrix.makeRotationZ(bounds.rotation);
|
|
1460
1415
|
const matrix = this.originTranslationMatrix.premultiply(this.scaleMatrix).premultiply(this.rotationMatrix).premultiply(this.globalTranslationMatrix);
|
|
1461
|
-
mesh.setMatrixAt(
|
|
1416
|
+
mesh.setMatrixAt(instanceId, matrix);
|
|
1462
1417
|
}
|
|
1463
1418
|
packImages(images) {
|
|
1464
1419
|
this.packer.reset();
|
|
@@ -1472,8 +1427,8 @@ class ImageSystem extends RenderableSystem {
|
|
|
1472
1427
|
const sourceWidth = image.source.width;
|
|
1473
1428
|
const sourceHeight = image.source.height;
|
|
1474
1429
|
const sourceArea = sourceWidth * sourceHeight;
|
|
1475
|
-
const boundsWidth = image.bounds.size.
|
|
1476
|
-
const boundsHeight = image.bounds.size.
|
|
1430
|
+
const boundsWidth = image.bounds.size.x;
|
|
1431
|
+
const boundsHeight = image.bounds.size.y;
|
|
1477
1432
|
const boundsArea = boundsWidth * boundsHeight;
|
|
1478
1433
|
const ratio = sourceArea / boundsArea;
|
|
1479
1434
|
if (ratio > 1e3) {
|
|
@@ -1593,13 +1548,10 @@ class LineSystem extends RenderableSystem {
|
|
|
1593
1548
|
}
|
|
1594
1549
|
}
|
|
1595
1550
|
function createVector2(vector2) {
|
|
1596
|
-
if (vector2 instanceof Vector2) return vector2;
|
|
1597
1551
|
if (Array.isArray(vector2)) return new Vector2(vector2[0], vector2[1]);
|
|
1598
1552
|
return new Vector2(vector2.x, vector2.y);
|
|
1599
1553
|
}
|
|
1600
1554
|
function createVector3(vector3) {
|
|
1601
|
-
if (vector3 instanceof Vector2) return new Vector3(vector3.x, vector3.y, 0);
|
|
1602
|
-
if (vector3 instanceof Vector3) return vector3;
|
|
1603
1555
|
if (Array.isArray(vector3)) return new Vector3(vector3[0], vector3[1], vector3[2] ?? 0);
|
|
1604
1556
|
return new Vector3(vector3.x, vector3.y, "z" in vector3 ? vector3.z : 0);
|
|
1605
1557
|
}
|
|
@@ -1610,28 +1562,53 @@ class Rect {
|
|
|
1610
1562
|
* @param rotation Optional rotation of the rectangle. In radians, around center. Positive values rotate clockwise.
|
|
1611
1563
|
*/
|
|
1612
1564
|
constructor(min, max, rotation) {
|
|
1613
|
-
/** Top left corner of the rectangle. */
|
|
1614
|
-
__publicField(this, "min");
|
|
1615
|
-
/** Bottom right corner of the rectangle. */
|
|
1616
|
-
__publicField(this, "max");
|
|
1617
1565
|
/** Optional rotation of the rectangle. In radians, around center. Positive values rotate clockwise. */
|
|
1618
1566
|
__publicField(this, "rotation");
|
|
1619
|
-
__publicField(this, "
|
|
1620
|
-
__publicField(this, "
|
|
1621
|
-
this
|
|
1622
|
-
this
|
|
1567
|
+
__publicField(this, "_min");
|
|
1568
|
+
__publicField(this, "_max");
|
|
1569
|
+
__publicField(this, "_center", new Vector2());
|
|
1570
|
+
__publicField(this, "_size", new Vector2());
|
|
1571
|
+
this._min = createVector2(min);
|
|
1572
|
+
this._max = createVector2(max);
|
|
1623
1573
|
this.rotation = rotation ?? 0;
|
|
1574
|
+
this.updateCenterAndSize();
|
|
1624
1575
|
}
|
|
1625
|
-
/**
|
|
1576
|
+
/** Top left corner of the rectangle. */
|
|
1577
|
+
get min() {
|
|
1578
|
+
return this._min;
|
|
1579
|
+
}
|
|
1580
|
+
/** Set top left corner of the rectangle. */
|
|
1581
|
+
set min(min) {
|
|
1582
|
+
this._min.copy(min);
|
|
1583
|
+
this.updateCenterAndSize();
|
|
1584
|
+
}
|
|
1585
|
+
/** Bottom right corner of the rectangle. */
|
|
1586
|
+
get max() {
|
|
1587
|
+
return this._max;
|
|
1588
|
+
}
|
|
1589
|
+
/** Set bottom right corner of the rectangle. */
|
|
1590
|
+
set max(max) {
|
|
1591
|
+
this._max.copy(max);
|
|
1592
|
+
this.updateCenterAndSize();
|
|
1593
|
+
}
|
|
1594
|
+
/** Center of the rectangle. */
|
|
1626
1595
|
get center() {
|
|
1627
|
-
this._center ?? (this._center = this.min.clone().add(this.max).multiplyScalar(0.5));
|
|
1628
1596
|
return this._center;
|
|
1629
1597
|
}
|
|
1630
|
-
/**
|
|
1598
|
+
/** Set center of the rectangle. */
|
|
1599
|
+
set center(center) {
|
|
1600
|
+
this._center.copy(center);
|
|
1601
|
+
this.updateMinAndMax();
|
|
1602
|
+
}
|
|
1603
|
+
/** Size of the rectangle. */
|
|
1631
1604
|
get size() {
|
|
1632
|
-
this._size ?? (this._size = this.max.clone().sub(this.min));
|
|
1633
1605
|
return this._size;
|
|
1634
1606
|
}
|
|
1607
|
+
/** Set size of the rectangle. */
|
|
1608
|
+
set size(size) {
|
|
1609
|
+
this._size.copy(size);
|
|
1610
|
+
this.updateMinAndMax();
|
|
1611
|
+
}
|
|
1635
1612
|
/**
|
|
1636
1613
|
* Creates a rectangle from an SVG rectangle element.
|
|
1637
1614
|
* @param rect {@link SVGRectElement} or {@link SVGImageElement}
|
|
@@ -1646,18 +1623,37 @@ class Rect {
|
|
|
1646
1623
|
return new Rect([x, y], [x + width, y + height], rotation);
|
|
1647
1624
|
}
|
|
1648
1625
|
/**
|
|
1649
|
-
*
|
|
1650
|
-
* @param
|
|
1651
|
-
* @
|
|
1626
|
+
* Moves the rectangle by the given offset.
|
|
1627
|
+
* @param offset Offset to move the rectangle by.
|
|
1628
|
+
* @returns this {@link Rect} instance
|
|
1629
|
+
*/
|
|
1630
|
+
translate(offset) {
|
|
1631
|
+
this._center.add(offset);
|
|
1632
|
+
this.updateMinAndMax();
|
|
1633
|
+
return this;
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Expands the rectangle by the given amount on all sides.
|
|
1637
|
+
* Use positive values to increase the size of the rectangle, negative values to decrease it.
|
|
1638
|
+
* @param expansion Can be a single number or a 2D vector. If a single number is provided, both horizontal and vertical sizes will be expanded by the same amount.
|
|
1652
1639
|
* @returns this {@link Rect} instance
|
|
1653
1640
|
*/
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
this.
|
|
1657
|
-
this.
|
|
1658
|
-
this._size
|
|
1641
|
+
expand(expansion) {
|
|
1642
|
+
const expansionVector = typeof expansion === "number" ? { x: expansion, y: expansion } : expansion;
|
|
1643
|
+
this._min.sub(expansionVector);
|
|
1644
|
+
this._max.add(expansionVector);
|
|
1645
|
+
this._size.subVectors(this._max, this._min);
|
|
1659
1646
|
return this;
|
|
1660
1647
|
}
|
|
1648
|
+
updateCenterAndSize() {
|
|
1649
|
+
this._center.addVectors(this._min, this._max).multiplyScalar(0.5);
|
|
1650
|
+
this._size.subVectors(this._max, this._min);
|
|
1651
|
+
}
|
|
1652
|
+
updateMinAndMax() {
|
|
1653
|
+
const halfSize = tempVector2.copy(this._size).multiplyScalar(0.5);
|
|
1654
|
+
this._min.subVectors(this._center, halfSize);
|
|
1655
|
+
this._max.addVectors(this._center, halfSize);
|
|
1656
|
+
}
|
|
1661
1657
|
}
|
|
1662
1658
|
class Polygon {
|
|
1663
1659
|
/**
|
|
@@ -1665,12 +1661,24 @@ class Polygon {
|
|
|
1665
1661
|
* @param indices Array of polygon indices. Each index is a triplet of vertex indices forming a triangle.
|
|
1666
1662
|
*/
|
|
1667
1663
|
constructor(vertices, indices) {
|
|
1668
|
-
|
|
1669
|
-
__publicField(this, "
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
this.
|
|
1673
|
-
this.
|
|
1664
|
+
__publicField(this, "_indices");
|
|
1665
|
+
__publicField(this, "_vertices");
|
|
1666
|
+
__publicField(this, "_bbox");
|
|
1667
|
+
this._vertices = vertices.map(createVector3);
|
|
1668
|
+
this._indices = indices;
|
|
1669
|
+
this._bbox = this.computeBoundingRect();
|
|
1670
|
+
}
|
|
1671
|
+
/** Array of polygon vertices. */
|
|
1672
|
+
get vertices() {
|
|
1673
|
+
return this._vertices;
|
|
1674
|
+
}
|
|
1675
|
+
/** Array of polygon indices. Each index is a triplet of vertex indices forming a triangle. */
|
|
1676
|
+
get indices() {
|
|
1677
|
+
return this._indices;
|
|
1678
|
+
}
|
|
1679
|
+
/** Bounding rectangle of the polygon. */
|
|
1680
|
+
get bounds() {
|
|
1681
|
+
return this._bbox;
|
|
1674
1682
|
}
|
|
1675
1683
|
/**
|
|
1676
1684
|
* Converts a {@link Rect} to a {@link Polygon}.
|
|
@@ -1699,28 +1707,76 @@ class Polygon {
|
|
|
1699
1707
|
let indexOffset = 0;
|
|
1700
1708
|
const vertices = [];
|
|
1701
1709
|
const indices = [];
|
|
1702
|
-
for (const
|
|
1703
|
-
vertices.push(...
|
|
1704
|
-
indices.push(...
|
|
1705
|
-
indexOffset +=
|
|
1710
|
+
for (const p of polygons) {
|
|
1711
|
+
vertices.push(...p.vertices);
|
|
1712
|
+
indices.push(...p.indices.map(([i1, i2, i3]) => [i1 + indexOffset, i2 + indexOffset, i3 + indexOffset]));
|
|
1713
|
+
indexOffset += p.vertices.length;
|
|
1706
1714
|
}
|
|
1707
1715
|
return new Polygon(vertices, indices);
|
|
1708
1716
|
}
|
|
1709
1717
|
/**
|
|
1710
|
-
*
|
|
1718
|
+
* Translates all vertices of the polygon by the given offset.
|
|
1719
|
+
* @param offset Offset to translate the polygon by. Can be a 2D or 3D vector.
|
|
1720
|
+
* @returns this {@link Polygon} instance
|
|
1721
|
+
*/
|
|
1722
|
+
translate(offset) {
|
|
1723
|
+
var _a2;
|
|
1724
|
+
const vec3 = { z: 0, ...offset };
|
|
1725
|
+
this._vertices.forEach((vertex) => vertex.add(vec3));
|
|
1726
|
+
(_a2 = this._bbox) == null ? void 0 : _a2.translate(offset);
|
|
1727
|
+
return this;
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Rotates all vertices of the polygon around the given center. Only 2D rotation (around Z axis) is supported.
|
|
1711
1731
|
* @param rotation Rotation angle in radians. Positive values rotate clockwise.
|
|
1712
|
-
* @param center Center of the rotation.
|
|
1732
|
+
* @param center Center of the rotation. If omitted, defaults to the bounding rectangle center.
|
|
1733
|
+
* @returns this {@link Polygon} instance
|
|
1734
|
+
*/
|
|
1735
|
+
rotate(rotation, center = this.bounds.center) {
|
|
1736
|
+
this._vertices.forEach((vertex) => {
|
|
1737
|
+
tempVector2.set(vertex.x, vertex.y).rotateAround(center, rotation);
|
|
1738
|
+
vertex.set(tempVector2.x, tempVector2.y, vertex.z);
|
|
1739
|
+
});
|
|
1740
|
+
this._bbox = this.computeBoundingRect();
|
|
1741
|
+
return this;
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1744
|
+
* Scales the polygon around the given origin.
|
|
1745
|
+
* @param scaleFactor Can be a single number or a 2D vector. If a single number is provided, both horizontal and vertical axes will be scaled by the same factor.
|
|
1746
|
+
* @param origin Origin of the scaling. If omitted, defaults to the bounding rectangle center.
|
|
1713
1747
|
* @returns this {@link Polygon} instance
|
|
1714
1748
|
*/
|
|
1715
|
-
|
|
1716
|
-
const
|
|
1717
|
-
this.
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
vertex.set(tempVec2.x, tempVec2.y, vertex.z);
|
|
1749
|
+
scale(scaleFactor, origin2 = this.bounds.center) {
|
|
1750
|
+
const scaleVector = typeof scaleFactor === "number" ? { x: scaleFactor, y: scaleFactor } : scaleFactor;
|
|
1751
|
+
this._vertices.forEach((vertex) => {
|
|
1752
|
+
tempVector2.set(vertex.x, vertex.y).sub(origin2).multiply(scaleVector).add(origin2);
|
|
1753
|
+
vertex.set(tempVector2.x, tempVector2.y, vertex.z);
|
|
1721
1754
|
});
|
|
1755
|
+
this._bbox = this.computeBoundingRect();
|
|
1722
1756
|
return this;
|
|
1723
1757
|
}
|
|
1758
|
+
computeBoundingRect() {
|
|
1759
|
+
let minX = Infinity;
|
|
1760
|
+
let minY = Infinity;
|
|
1761
|
+
let maxX = -Infinity;
|
|
1762
|
+
let maxY = -Infinity;
|
|
1763
|
+
for (const vertex of this.vertices) {
|
|
1764
|
+
minX = Math.min(minX, vertex.x);
|
|
1765
|
+
minY = Math.min(minY, vertex.y);
|
|
1766
|
+
maxX = Math.max(maxX, vertex.x);
|
|
1767
|
+
maxY = Math.max(maxY, vertex.y);
|
|
1768
|
+
}
|
|
1769
|
+
return new Rect([minX, minY], [maxX, maxY]);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
const tempVector2 = new Vector2();
|
|
1773
|
+
function countGeometry(geometry) {
|
|
1774
|
+
var _a2;
|
|
1775
|
+
if (geometry.index == null) return { vertices: geometry.getAttribute("position").count, indices: 0 };
|
|
1776
|
+
return {
|
|
1777
|
+
vertices: geometry.getAttribute("position").count,
|
|
1778
|
+
indices: ((_a2 = geometry.index) == null ? void 0 : _a2.count) ?? 0
|
|
1779
|
+
};
|
|
1724
1780
|
}
|
|
1725
1781
|
const logger$7 = createLogger("mesh");
|
|
1726
1782
|
extend([namesPlugin]);
|
|
@@ -1731,8 +1787,19 @@ class MeshSystem extends RenderableSystem {
|
|
|
1731
1787
|
*/
|
|
1732
1788
|
constructor(materialSystem, renderer) {
|
|
1733
1789
|
super("mesh", renderer, logger$7);
|
|
1734
|
-
__publicField(this, "
|
|
1790
|
+
__publicField(this, "color", new Color());
|
|
1791
|
+
__publicField(this, "position", new Vector3());
|
|
1792
|
+
__publicField(this, "rotation", new Quaternion());
|
|
1793
|
+
__publicField(this, "scale", new Vector3());
|
|
1794
|
+
__publicField(this, "matrix", new Matrix4());
|
|
1795
|
+
__publicField(this, "rectGeometry", new PlaneGeometry(1, 1));
|
|
1796
|
+
__publicField(this, "placeholderPolygonGeometry", new BufferGeometry());
|
|
1797
|
+
__publicField(this, "mapInstanceIdToShapeType", /* @__PURE__ */ new Map());
|
|
1735
1798
|
this.materialSystem = materialSystem;
|
|
1799
|
+
this.rectGeometry.deleteAttribute("normal");
|
|
1800
|
+
this.rectGeometry.deleteAttribute("uv");
|
|
1801
|
+
this.placeholderPolygonGeometry.setAttribute("position", new BufferAttribute(new Float32Array(), 3));
|
|
1802
|
+
this.placeholderPolygonGeometry.index = new BufferAttribute(new Uint32Array(), 0);
|
|
1736
1803
|
}
|
|
1737
1804
|
buildLayer(layer) {
|
|
1738
1805
|
const shapes = layer.children;
|
|
@@ -1769,60 +1836,78 @@ class MeshSystem extends RenderableSystem {
|
|
|
1769
1836
|
return group;
|
|
1770
1837
|
}
|
|
1771
1838
|
updateDefImpl(shapeDef, mesh, instanceIds) {
|
|
1839
|
+
const instanceId = instanceIds[0];
|
|
1840
|
+
this.updateShape(shapeDef, mesh, instanceId);
|
|
1841
|
+
this.updateColor(shapeDef, mesh, instanceId);
|
|
1842
|
+
}
|
|
1843
|
+
updateShape(shapeDef, mesh, instanceId) {
|
|
1844
|
+
const geometryId = mesh.getGeometryIdAt(instanceId);
|
|
1845
|
+
const expectedShapeType = this.mapInstanceIdToShapeType.get(instanceId);
|
|
1846
|
+
const shape = shapeDef.shape;
|
|
1847
|
+
const isPolygon = shape instanceof Polygon;
|
|
1848
|
+
const isRect = shape instanceof Rect;
|
|
1849
|
+
if (expectedShapeType === "polygon" && !isPolygon || expectedShapeType === "rect" && !isRect) {
|
|
1850
|
+
logger$7.warn("Shape type changing not supported %O", shapeDef);
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
if (isPolygon) {
|
|
1854
|
+
const geometryRange = mesh.getGeometryRangeAt(geometryId);
|
|
1855
|
+
if (!geometryRange || shape.vertices.length != geometryRange.reservedVertexCount || shape.indices.length * 3 != geometryRange.reservedIndexCount) {
|
|
1856
|
+
logger$7.warn("Polygon geometry changing not supported %O", shapeDef);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
mesh.setGeometryAt(geometryId, this.buildPolygonGeometry(shape));
|
|
1860
|
+
} else if (isRect) {
|
|
1861
|
+
this.position.set(shape.center.x, shape.center.y, 0);
|
|
1862
|
+
this.rotation.setFromAxisAngle(new Vector3(0, 0, 1), shape.rotation ?? 0);
|
|
1863
|
+
this.scale.set(shape.size.x, shape.size.y, 1);
|
|
1864
|
+
this.matrix.compose(this.position, this.rotation, this.scale);
|
|
1865
|
+
mesh.setMatrixAt(instanceId, this.matrix);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
updateColor(shapeDef, mesh, instanceId) {
|
|
1772
1869
|
const color = this.normalizeColor(shapeDef.color);
|
|
1773
1870
|
if (!color) {
|
|
1774
1871
|
logger$7.warn(`Invalid color: ${shapeDef.color} %O`, shapeDef);
|
|
1775
1872
|
return;
|
|
1776
1873
|
}
|
|
1777
|
-
|
|
1778
|
-
mesh.setColorAt(instanceId, this.meshColor.setRGB(color.r / 255, color.g / 255, color.b / 255, SRGBColorSpace));
|
|
1779
|
-
}
|
|
1874
|
+
mesh.setColorAt(instanceId, this.color.setRGB(color.r / 255, color.g / 255, color.b / 255, SRGBColorSpace));
|
|
1780
1875
|
}
|
|
1781
1876
|
buildBatchedMesh(shapes, opacity = 1) {
|
|
1782
|
-
var _a2, _b;
|
|
1783
1877
|
let vertexCount = 0;
|
|
1784
1878
|
let indexCount = 0;
|
|
1785
|
-
let
|
|
1879
|
+
let rectAdded = false;
|
|
1786
1880
|
const shapeDefToGeometry = /* @__PURE__ */ new Map();
|
|
1787
1881
|
for (const shapeDef of shapes) {
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
indexCount += ((_a2 = rectGeometry.index) == null ? void 0 : _a2.count) ?? 0;
|
|
1882
|
+
let vertices = 0;
|
|
1883
|
+
let indices = 0;
|
|
1884
|
+
if (shapeDef.shape instanceof Rect && !rectAdded) {
|
|
1885
|
+
rectAdded = true;
|
|
1886
|
+
({ vertices, indices } = countGeometry(this.rectGeometry));
|
|
1794
1887
|
} else if (shapeDef.shape instanceof Polygon) {
|
|
1795
1888
|
const geometry = this.buildPolygonGeometry(shapeDef.shape);
|
|
1796
1889
|
shapeDefToGeometry.set(shapeDef, geometry);
|
|
1797
|
-
|
|
1798
|
-
indexCount += ((_b = geometry.index) == null ? void 0 : _b.count) ?? 0;
|
|
1890
|
+
({ vertices, indices } = countGeometry(geometry));
|
|
1799
1891
|
}
|
|
1892
|
+
vertexCount += vertices;
|
|
1893
|
+
indexCount += indices;
|
|
1800
1894
|
}
|
|
1801
1895
|
const material = this.materialSystem.createColorMaterial({ opacity });
|
|
1802
1896
|
const batchedMesh = new BatchedMesh(shapes.length, vertexCount, indexCount, material);
|
|
1803
|
-
const rectGeometryId =
|
|
1897
|
+
const rectGeometryId = rectAdded ? batchedMesh.addGeometry(this.rectGeometry) : void 0;
|
|
1804
1898
|
batchedMesh.setCustomSort((list) => this.sortInstances(batchedMesh, list));
|
|
1805
|
-
const
|
|
1806
|
-
|
|
1807
|
-
const scale = new Vector3();
|
|
1808
|
-
const matrix = new Matrix4();
|
|
1809
|
-
const [rects, polygons] = partition(shapes, (shapeDef) => shapeDef.shape instanceof Rect);
|
|
1810
|
-
const sortedShapes = [...rects, ...polygons];
|
|
1811
|
-
for (const shapeDef of sortedShapes) {
|
|
1812
|
-
let instanceId = void 0;
|
|
1899
|
+
for (const shapeDef of shapes) {
|
|
1900
|
+
let instanceId;
|
|
1813
1901
|
if (shapeDef.shape instanceof Rect && rectGeometryId !== void 0) {
|
|
1814
1902
|
instanceId = batchedMesh.addInstance(rectGeometryId);
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
scale.set(shapeDef.shape.size.x, shapeDef.shape.size.y, 1);
|
|
1818
|
-
matrix.compose(position, rotation, scale);
|
|
1819
|
-
batchedMesh.setMatrixAt(instanceId, matrix);
|
|
1820
|
-
} else if (shapeDef.shape instanceof Polygon) {
|
|
1903
|
+
this.mapInstanceIdToShapeType.set(instanceId, "rect");
|
|
1904
|
+
} else {
|
|
1821
1905
|
const geometry = shapeDefToGeometry.get(shapeDef);
|
|
1822
|
-
const
|
|
1906
|
+
const { vertices, indices } = countGeometry(geometry);
|
|
1907
|
+
const polygonGeometryId = batchedMesh.addGeometry(this.placeholderPolygonGeometry, vertices, indices);
|
|
1823
1908
|
instanceId = batchedMesh.addInstance(polygonGeometryId);
|
|
1909
|
+
this.mapInstanceIdToShapeType.set(instanceId, "polygon");
|
|
1824
1910
|
}
|
|
1825
|
-
if (instanceId === void 0) continue;
|
|
1826
1911
|
this.registerDefObject(shapeDef, batchedMesh, instanceId);
|
|
1827
1912
|
}
|
|
1828
1913
|
return batchedMesh;
|
|
@@ -1834,8 +1919,7 @@ class MeshSystem extends RenderableSystem {
|
|
|
1834
1919
|
return color.toRgb();
|
|
1835
1920
|
}
|
|
1836
1921
|
buildPolygonGeometry(polygon) {
|
|
1837
|
-
|
|
1838
|
-
return geometry;
|
|
1922
|
+
return new BufferGeometry().setFromPoints(polygon.vertices).setIndex(polygon.indices.flat());
|
|
1839
1923
|
}
|
|
1840
1924
|
sortInstances(mesh, list) {
|
|
1841
1925
|
const shapeDefs = this.getDefsByObject(mesh);
|
|
@@ -2005,11 +2089,10 @@ class TextSystem extends RenderableSystem {
|
|
|
2005
2089
|
return lines;
|
|
2006
2090
|
}
|
|
2007
2091
|
calculateStartInBoundsPosition(textDef, lines, alignmentDirection, alignmentOffset, inBoundsPosition) {
|
|
2008
|
-
const [w, h] = textDef.bounds.size;
|
|
2009
2092
|
const padding = textDef.padding;
|
|
2010
2093
|
const alignment = textDef.alignment;
|
|
2011
2094
|
alignmentDirection.set(...getAlignmentDirection(alignment));
|
|
2012
|
-
inBoundsPosition.
|
|
2095
|
+
inBoundsPosition.copy(textDef.bounds.size).multiplyScalar(0.5);
|
|
2013
2096
|
if (alignment.vertical === "center") {
|
|
2014
2097
|
const totalTextHeight = lines.filter((l) => l.height !== void 0).reduce((acc, l) => acc + l.height, 0) * this.renderer.context.getPixelRatio();
|
|
2015
2098
|
alignmentOffset.set(0, -(textDef.bounds.size.y - totalTextHeight) / 2);
|
|
@@ -4785,9 +4868,9 @@ class CameraController extends CameraControls {
|
|
|
4785
4868
|
*/
|
|
4786
4869
|
constructor(camera) {
|
|
4787
4870
|
super(camera);
|
|
4871
|
+
__publicField(this, "touchCancelListener");
|
|
4788
4872
|
this.dollyToCursor = true;
|
|
4789
4873
|
this.draggingSmoothTime = 0;
|
|
4790
|
-
void this.rotatePolarTo(0, false);
|
|
4791
4874
|
this.mouseButtons = {
|
|
4792
4875
|
left: CameraController.ACTION.NONE,
|
|
4793
4876
|
middle: CameraController.ACTION.NONE,
|
|
@@ -4799,6 +4882,7 @@ class CameraController extends CameraControls {
|
|
|
4799
4882
|
two: CameraController.ACTION.NONE,
|
|
4800
4883
|
three: CameraController.ACTION.NONE
|
|
4801
4884
|
};
|
|
4885
|
+
this.touchCancelListener = () => this.cancel();
|
|
4802
4886
|
}
|
|
4803
4887
|
update(delta) {
|
|
4804
4888
|
const needsUpdate = super.update(delta);
|
|
@@ -4811,6 +4895,15 @@ class CameraController extends CameraControls {
|
|
|
4811
4895
|
}
|
|
4812
4896
|
return needsUpdate;
|
|
4813
4897
|
}
|
|
4898
|
+
connect(domElement) {
|
|
4899
|
+
super.connect(domElement);
|
|
4900
|
+
domElement.addEventListener("touchcancel", this.touchCancelListener);
|
|
4901
|
+
}
|
|
4902
|
+
disconnect() {
|
|
4903
|
+
var _a2;
|
|
4904
|
+
(_a2 = this._domElement) == null ? void 0 : _a2.removeEventListener("touchcancel", this.touchCancelListener);
|
|
4905
|
+
super.disconnect();
|
|
4906
|
+
}
|
|
4814
4907
|
}
|
|
4815
4908
|
class CameraSystem {
|
|
4816
4909
|
/**
|
|
@@ -4834,9 +4927,8 @@ class CameraSystem {
|
|
|
4834
4927
|
const h = renderer.size[1];
|
|
4835
4928
|
this.prevViewportHeightPx = h;
|
|
4836
4929
|
this.camera = new PerspectiveCamera(this.defaultFov);
|
|
4837
|
-
this.camera.up.set(0, 0, -1);
|
|
4838
4930
|
this.controller = new CameraController(this.camera);
|
|
4839
|
-
this.controller.
|
|
4931
|
+
void this.controller.rotatePolarTo(0, false);
|
|
4840
4932
|
}
|
|
4841
4933
|
/** Current camera zoom factor. */
|
|
4842
4934
|
get zoomFactor() {
|
|
@@ -4858,6 +4950,12 @@ class CameraSystem {
|
|
|
4858
4950
|
initCamera(zoomBounds) {
|
|
4859
4951
|
this.zoomBounds = zoomBounds;
|
|
4860
4952
|
this.updateCamera();
|
|
4953
|
+
this.camera.up.set(0, -1, 0);
|
|
4954
|
+
this.camera.position.set(0, 0, -this.zoomIdentityDistance);
|
|
4955
|
+
this.camera.lookAt(0, 0, 0);
|
|
4956
|
+
this.camera.updateMatrixWorld();
|
|
4957
|
+
this.camera.up.set(0, 0, -1);
|
|
4958
|
+
this.controller.updateCameraUp();
|
|
4861
4959
|
}
|
|
4862
4960
|
/** Updates the camera when the renderer size changes. */
|
|
4863
4961
|
updateCamera() {
|
|
@@ -5059,7 +5157,10 @@ class SceneSystem {
|
|
|
5059
5157
|
__publicField(this, "worldMatrix", new Matrix4());
|
|
5060
5158
|
/** Inverse world matrix - world → model transform */
|
|
5061
5159
|
__publicField(this, "inverseWorldMatrix", new Matrix4());
|
|
5160
|
+
/** Used as a scratch vector for coordinate space conversions */
|
|
5062
5161
|
__publicField(this, "tempVector3", new Vector3());
|
|
5162
|
+
/** Used as a scratch vector for matrix calculations */
|
|
5163
|
+
__publicField(this, "tempVector2", new Vector2());
|
|
5063
5164
|
__publicField(this, "translationMatrix", new Matrix4());
|
|
5064
5165
|
__publicField(this, "scaleMatrix", new Matrix4());
|
|
5065
5166
|
__publicField(this, "visibleRectOffsetMatrix", new Matrix4());
|
|
@@ -5110,14 +5211,14 @@ class SceneSystem {
|
|
|
5110
5211
|
composeMatrices(viewbox) {
|
|
5111
5212
|
const dpr = this.renderer.context.getPixelRatio();
|
|
5112
5213
|
const visibleRect = this.renderer.visibleRect;
|
|
5113
|
-
const
|
|
5114
|
-
|
|
5115
|
-
const scaleFactor = Math.min(
|
|
5116
|
-
const
|
|
5214
|
+
const visibleRectSize = visibleRect ? this.tempVector2.copy(visibleRect.size).multiplyScalar(dpr) : this.tempVector2.set(...this.renderer.size);
|
|
5215
|
+
visibleRectSize.divide(viewbox.size);
|
|
5216
|
+
const scaleFactor = Math.min(visibleRectSize.width, visibleRectSize.height);
|
|
5217
|
+
const { x: centerX, y: centerY } = viewbox.center;
|
|
5117
5218
|
this.translationMatrix.makeTranslation(-centerX, -centerY, 0);
|
|
5118
5219
|
this.scaleMatrix.makeScale(scaleFactor, scaleFactor, 1);
|
|
5119
5220
|
if (visibleRect) {
|
|
5120
|
-
const visibleRectCenter = visibleRect.center
|
|
5221
|
+
const visibleRectCenter = this.tempVector2.copy(visibleRect.center).multiplyScalar(dpr);
|
|
5121
5222
|
const canvasCenter = { x: this.renderer.size[0] / 2, y: this.renderer.size[1] / 2 };
|
|
5122
5223
|
const offset = visibleRectCenter.sub(canvasCenter);
|
|
5123
5224
|
this.visibleRectOffsetMatrix.makeTranslation(offset.x, offset.y, 0);
|
|
@@ -5187,7 +5288,7 @@ class ViewportSystem {
|
|
|
5187
5288
|
*/
|
|
5188
5289
|
initViewport(sceneDef) {
|
|
5189
5290
|
if (!this.renderer.isExternalMode) this.sceneSystem.initScene(sceneDef.viewbox);
|
|
5190
|
-
this.cameraSystem.initCamera([0.1, sceneDef.viewbox.size.
|
|
5291
|
+
this.cameraSystem.initCamera([0.1, sceneDef.viewbox.size.x > 1e5 ? 100 : 35]);
|
|
5191
5292
|
}
|
|
5192
5293
|
/** Updates the viewport when the renderer size changes. */
|
|
5193
5294
|
updateViewport() {
|
|
@@ -5344,27 +5445,23 @@ class ControlsSystem {
|
|
|
5344
5445
|
const dpr = this.renderer.context.getPixelRatio();
|
|
5345
5446
|
const visibleRect = this.renderer.visibleRect;
|
|
5346
5447
|
const bearingAngle = -this.controller.azimuthAngle;
|
|
5347
|
-
const
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
const worldPolygon = Polygon.fromRect(worldRect).rotate(bearingAngle, worldRect.center);
|
|
5351
|
-
const xValues = worldPolygon.vertices.map((p) => p.x);
|
|
5352
|
-
const yValues = worldPolygon.vertices.map((p) => p.y);
|
|
5353
|
-
const sourceRect = new Rect(
|
|
5354
|
-
[Math.min(...xValues), Math.min(...yValues)],
|
|
5355
|
-
[Math.max(...xValues), Math.max(...yValues)]
|
|
5448
|
+
const worldRect = new Rect(
|
|
5449
|
+
this.viewportSystem.modelToWorld(rect.min),
|
|
5450
|
+
this.viewportSystem.modelToWorld(rect.max)
|
|
5356
5451
|
);
|
|
5452
|
+
const sourceRect = Polygon.fromRect(worldRect).rotate(bearingAngle).bounds;
|
|
5357
5453
|
if (sourceRect.size.x <= 0 || sourceRect.size.y <= 0) {
|
|
5358
5454
|
logger$1.warn("zoomTo: sourceRect size is 0");
|
|
5359
5455
|
return;
|
|
5360
5456
|
}
|
|
5361
|
-
const targetRect = visibleRect ? new Rect(visibleRect.min.
|
|
5362
|
-
if (paddingPercent)
|
|
5457
|
+
const targetRect = visibleRect ? new Rect([visibleRect.min.x * dpr, visibleRect.min.y * dpr], [visibleRect.max.x * dpr, visibleRect.max.y * dpr]) : new Rect([0, 0], [...this.renderer.size]);
|
|
5458
|
+
if (paddingPercent)
|
|
5459
|
+
targetRect.expand({ x: -targetRect.size.x * paddingPercent, y: -targetRect.size.y * paddingPercent });
|
|
5363
5460
|
const zoomByWidth = targetRect.size.x / sourceRect.size.x;
|
|
5364
5461
|
const zoomByHeight = targetRect.size.y / sourceRect.size.y;
|
|
5365
5462
|
const minZoom = Math.min(zoomByWidth, zoomByHeight);
|
|
5366
5463
|
const zoom = maxZoom ? Math.min(minZoom, maxZoom) : minZoom;
|
|
5367
|
-
const translate = sourceRect.center;
|
|
5464
|
+
const translate = new Vector2().copy(sourceRect.center);
|
|
5368
5465
|
if (visibleRect) {
|
|
5369
5466
|
const offset = new Vector2(...this.renderer.size).multiplyScalar(0.5).sub(targetRect.center).multiplyScalar(1 / (zoom || 1)).rotateAround({ x: 0, y: 0 }, bearingAngle);
|
|
5370
5467
|
translate.add(offset);
|
|
@@ -6269,8 +6366,7 @@ class Renderer {
|
|
|
6269
6366
|
this.controlsSystem = new ControlsSystem(this, this.viewportSystem, this.interactionsSystem);
|
|
6270
6367
|
this.canvas.addEventListener("webglcontextlost", (e) => this.onContextLost(e), false);
|
|
6271
6368
|
this.canvas.addEventListener("webglcontextrestored", (e) => this.onContextRestored(e), false);
|
|
6272
|
-
this.
|
|
6273
|
-
BatchedMesh.useMultiDraw = this.renderer.extensions.has("WEBGL_multi_draw");
|
|
6369
|
+
this.initStatsContext(this.renderer.getContext());
|
|
6274
6370
|
}
|
|
6275
6371
|
/**
|
|
6276
6372
|
* {@link ControlsAPI} instance for controlling the viewport
|
|
@@ -6483,7 +6579,11 @@ class Renderer {
|
|
|
6483
6579
|
const logMarker = `memoryInfo [${elapsedTime.toFixed(2)}ms since start]`;
|
|
6484
6580
|
logger.debug(logMarker, memoryInfo);
|
|
6485
6581
|
this.memoryInfo = memoryInfo;
|
|
6486
|
-
this.ui.memoryInfoPanel.textContent = JSON.stringify(
|
|
6582
|
+
this.ui.memoryInfoPanel.textContent = JSON.stringify(
|
|
6583
|
+
memoryInfo,
|
|
6584
|
+
(_, value) => typeof value === "number" ? value.toLocaleString() : value,
|
|
6585
|
+
2
|
|
6586
|
+
).replaceAll('"', "");
|
|
6487
6587
|
}
|
|
6488
6588
|
}
|
|
6489
6589
|
}
|
|
@@ -6496,7 +6596,7 @@ class Renderer {
|
|
|
6496
6596
|
if (stats && "deleteQuery" in context) {
|
|
6497
6597
|
const gpuQueries = stats.gpuQueries;
|
|
6498
6598
|
for (const queryInfo of gpuQueries) {
|
|
6499
|
-
|
|
6599
|
+
context.deleteQuery(queryInfo.query);
|
|
6500
6600
|
}
|
|
6501
6601
|
stats.gpuQueries = [];
|
|
6502
6602
|
if (stats.gpuPanel) {
|
|
@@ -6510,11 +6610,11 @@ class Renderer {
|
|
|
6510
6610
|
onContextRestored(event) {
|
|
6511
6611
|
event.preventDefault();
|
|
6512
6612
|
logger.debug("webglcontextrestored event", event);
|
|
6513
|
-
this.
|
|
6613
|
+
this.initStatsContext(this.renderer.getContext());
|
|
6514
6614
|
this.needsRedraw = true;
|
|
6515
6615
|
this.start();
|
|
6516
6616
|
}
|
|
6517
|
-
|
|
6617
|
+
initStatsContext(context) {
|
|
6518
6618
|
var _a2, _b;
|
|
6519
6619
|
this.memoryInfoExtension = context.getExtension("GMAN_webgl_memory");
|
|
6520
6620
|
void ((_b = (_a2 = this.ui) == null ? void 0 : _a2.stats) == null ? void 0 : _b.init(context));
|