@expofp/renderer 2.2.1 → 2.3.1
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 +10 -16
- package/dist/index.js +295 -74
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { default as default_2 } from 'stats-gl';
|
|
2
|
-
import { Vector2 } from 'three';
|
|
3
2
|
import { Vector2Like } from 'three';
|
|
4
3
|
import { Vector2Tuple } from 'three';
|
|
5
|
-
import { Vector3 } from 'three';
|
|
6
4
|
import { Vector3Like } from 'three';
|
|
7
5
|
import { Vector3Tuple } from 'three';
|
|
8
6
|
import { WebGLRenderer } from 'three';
|
|
@@ -132,20 +130,6 @@ export declare interface ControlsAPI {
|
|
|
132
130
|
getCameraState: () => CameraState;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
/**
|
|
136
|
-
* Converts multiple vector2 representations to a {@link Vector2} instance.
|
|
137
|
-
* @param vector2 Vector2 representation as a tuple/POJO
|
|
138
|
-
* @returns Vector2 instance
|
|
139
|
-
*/
|
|
140
|
-
export declare function createVector2(vector2: IVector2): Vector2;
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Converts multiple vector3 representations to a {@link Vector3} instance.
|
|
144
|
-
* @param vector3 Vector3 representation as a tuple/POJO
|
|
145
|
-
* @returns Vector3 instance
|
|
146
|
-
*/
|
|
147
|
-
export declare function createVector3(vector3: IVector3 | IVector2): Vector3;
|
|
148
|
-
|
|
149
133
|
/**
|
|
150
134
|
* Mapping of engine-wide events to their payloads
|
|
151
135
|
*/
|
|
@@ -691,6 +675,16 @@ export declare interface ViewportAPI {
|
|
|
691
675
|
* @param dynamicTransformMatrix dynamic transform matrix (changes every frame)
|
|
692
676
|
*/
|
|
693
677
|
setDynamicTransform: (dynamicTransformMatrix: number[]) => void;
|
|
678
|
+
/**
|
|
679
|
+
* Set the maximum zoom factor. Default is 35.
|
|
680
|
+
* @param maxZoom Maximum zoom factor
|
|
681
|
+
*/
|
|
682
|
+
setMaxZoom: (maxZoom: number) => void;
|
|
683
|
+
/**
|
|
684
|
+
* Set the minimum zoom factor. Default is 0.1.
|
|
685
|
+
* @param minZoom Minimum zoom factor
|
|
686
|
+
*/
|
|
687
|
+
setMinZoom: (minZoom: number) => void;
|
|
694
688
|
}
|
|
695
689
|
|
|
696
690
|
/** Options for the {@link ControlsAPI.zoomTo} method. */
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ 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 { 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,
|
|
5
|
+
import { DataTexture, FloatType, UnsignedIntType, IntType, RGBAFormat, RGBAIntegerFormat, RGFormat, RGIntegerFormat, RedFormat, RedIntegerFormat, BatchedMesh as BatchedMesh$1, BufferAttribute, StreamDrawUsage, Color, Matrix4, Vector3, Frustum, Sphere, Box3, DynamicDrawUsage, Vector4, AlwaysDepth, DoubleSide, MeshBasicMaterial, Texture, Group, PlaneGeometry, SRGBColorSpace, Vector2, Quaternion, BufferGeometry, Mesh, LessEqualDepth, LinearSRGBColorSpace, Plane, Raycaster, Spherical, PerspectiveCamera, Camera, Scene, MathUtils, Clock, WebGLRenderer } from "three";
|
|
6
6
|
import { traverseAncestorsGenerator } from "three/examples/jsm/utils/SceneUtils.js";
|
|
7
7
|
import createLog from "debug";
|
|
8
8
|
import { BatchedText as BatchedText$1, Text as Text$1 } from "troika-three-text";
|
|
@@ -540,20 +540,57 @@ class BatchedMesh extends BatchedMesh$1 {
|
|
|
540
540
|
/** Whether to use WebGL_multi_draw extension or less performant fallback */
|
|
541
541
|
__publicField(BatchedMesh, "useMultiDraw", true);
|
|
542
542
|
const floatsPerMember = 32;
|
|
543
|
-
const tempColor = new Color();
|
|
544
543
|
const defaultStrokeColor = 8421504;
|
|
544
|
+
const defaultOrient = "+x+y";
|
|
545
|
+
const glyphBoundsAttrName = "aTroikaGlyphBounds";
|
|
546
|
+
const glyphIndexAttrName = "aTroikaGlyphIndex";
|
|
547
|
+
const memberIndexAttrName = "aTroikaTextBatchMemberIndex";
|
|
548
|
+
const syncStartEvent = { type: "syncstart" };
|
|
549
|
+
const syncCompleteEvent = { type: "synccomplete" };
|
|
550
|
+
const SYNCABLE_PROPS = [
|
|
551
|
+
"font",
|
|
552
|
+
"fontSize",
|
|
553
|
+
"fontStyle",
|
|
554
|
+
"fontWeight",
|
|
555
|
+
"lang",
|
|
556
|
+
"letterSpacing",
|
|
557
|
+
"lineHeight",
|
|
558
|
+
"maxWidth",
|
|
559
|
+
"overflowWrap",
|
|
560
|
+
"text",
|
|
561
|
+
"direction",
|
|
562
|
+
"textAlign",
|
|
563
|
+
"textIndent",
|
|
564
|
+
"whiteSpace",
|
|
565
|
+
"anchorX",
|
|
566
|
+
"anchorY",
|
|
567
|
+
"colorRanges",
|
|
568
|
+
"sdfGlyphSize"
|
|
569
|
+
];
|
|
570
|
+
const tempColor = new Color();
|
|
545
571
|
const tempMat4 = new Matrix4();
|
|
546
572
|
const tempVec3a = new Vector3();
|
|
547
573
|
const tempVec3b = new Vector3();
|
|
548
574
|
const origin = new Vector3();
|
|
549
|
-
const
|
|
575
|
+
const frustum = new Frustum();
|
|
576
|
+
const sphere = new Sphere();
|
|
577
|
+
const box = new Box3();
|
|
550
578
|
class BatchedText extends BatchedText$1 {
|
|
551
579
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
552
580
|
constructor() {
|
|
553
581
|
super();
|
|
554
|
-
__publicField(this, "
|
|
582
|
+
__publicField(this, "_needsRepack", false);
|
|
555
583
|
__publicField(this, "textArray", []);
|
|
556
584
|
__publicField(this, "textureNeedsUpdate", false);
|
|
585
|
+
__publicField(this, "boundsNeedsUpdate", false);
|
|
586
|
+
__publicField(this, "batchNeedsSync", true);
|
|
587
|
+
this.addEventListener("synccomplete", () => {
|
|
588
|
+
this.boundsNeedsUpdate = true;
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
/** Mark the batch as needing a sync pass. */
|
|
592
|
+
requestSync() {
|
|
593
|
+
this.batchNeedsSync = true;
|
|
557
594
|
}
|
|
558
595
|
/** Number of texts in the batch */
|
|
559
596
|
get size() {
|
|
@@ -569,7 +606,13 @@ class BatchedText extends BatchedText$1 {
|
|
|
569
606
|
* @returns Text object
|
|
570
607
|
*/
|
|
571
608
|
getText(instanceId) {
|
|
572
|
-
return this.
|
|
609
|
+
return this.textArray[instanceId];
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Mark this BatchedText as needing bounds update. This should be called when changing text transforms.
|
|
613
|
+
*/
|
|
614
|
+
invalidateBounds() {
|
|
615
|
+
this.boundsNeedsUpdate = true;
|
|
573
616
|
}
|
|
574
617
|
/**
|
|
575
618
|
* Set the visibility of the {@link Text} object by instance id.
|
|
@@ -583,17 +626,112 @@ class BatchedText extends BatchedText$1 {
|
|
|
583
626
|
}
|
|
584
627
|
addText(text, instanceId) {
|
|
585
628
|
super.addText(text);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
this.
|
|
629
|
+
text._batchParent = this;
|
|
630
|
+
if (instanceId !== void 0) this.textArray[instanceId] = text;
|
|
631
|
+
this.batchNeedsSync = true;
|
|
632
|
+
this.boundsNeedsUpdate = true;
|
|
633
|
+
}
|
|
634
|
+
removeText(text) {
|
|
635
|
+
super.removeText(text);
|
|
636
|
+
if (text._batchParent === this) text._batchParent = void 0;
|
|
637
|
+
this.textArray.splice(this.textArray.indexOf(text), 1);
|
|
638
|
+
this.batchNeedsSync = true;
|
|
639
|
+
this.boundsNeedsUpdate = true;
|
|
590
640
|
}
|
|
591
641
|
dispose() {
|
|
592
642
|
super.dispose();
|
|
643
|
+
this.textArray.length = 0;
|
|
593
644
|
this.dispatchEvent({ type: "dispose" });
|
|
594
645
|
}
|
|
595
|
-
|
|
596
|
-
|
|
646
|
+
updateBounds() {
|
|
647
|
+
if (this.boundsNeedsUpdate) {
|
|
648
|
+
const bbox = this.geometry.boundingBox.makeEmpty();
|
|
649
|
+
for (const text of this.textArray) {
|
|
650
|
+
if (!text.visible) continue;
|
|
651
|
+
if (text.matrixAutoUpdate) text.updateMatrix();
|
|
652
|
+
box.copy(text.geometry.boundingBox).applyMatrix4(text.matrix);
|
|
653
|
+
bbox.union(box);
|
|
654
|
+
}
|
|
655
|
+
bbox.getBoundingSphere(this.geometry.boundingSphere);
|
|
656
|
+
this.boundsNeedsUpdate = false;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
onBeforeRender(renderer, scene, camera, geometry, material) {
|
|
660
|
+
if (this.batchNeedsSync) this.sync();
|
|
661
|
+
if ("isTroikaTextMaterial" in material && material.isTroikaTextMaterial) {
|
|
662
|
+
this.prepareForRender(material, scene, camera);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Sync members and repack the batched geometry if needed.
|
|
667
|
+
* @param callback Optional callback invoked after sync completes.
|
|
668
|
+
*/
|
|
669
|
+
sync(callback) {
|
|
670
|
+
if (!this.batchNeedsSync) return;
|
|
671
|
+
this.batchNeedsSync = false;
|
|
672
|
+
let needsRepack = this._needsRepack;
|
|
673
|
+
this._needsRepack = false;
|
|
674
|
+
const pendingSyncs = [];
|
|
675
|
+
this._members.forEach((packingInfo, text) => {
|
|
676
|
+
const needsMemberSync = text._needsSync;
|
|
677
|
+
if (packingInfo.dirty || needsMemberSync) {
|
|
678
|
+
packingInfo.dirty = false;
|
|
679
|
+
needsRepack = true;
|
|
680
|
+
if (needsMemberSync) pendingSyncs.push(new Promise((resolve) => text.sync(resolve)));
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
if (!needsRepack) return;
|
|
684
|
+
this.dispatchEvent(syncStartEvent);
|
|
685
|
+
const repack = () => {
|
|
686
|
+
this.repackBatchedGeometry();
|
|
687
|
+
this.dispatchEvent(syncCompleteEvent);
|
|
688
|
+
if (callback) callback();
|
|
689
|
+
};
|
|
690
|
+
if (pendingSyncs.length) {
|
|
691
|
+
void Promise.all(pendingSyncs).then(repack);
|
|
692
|
+
} else {
|
|
693
|
+
repack();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
repackBatchedGeometry() {
|
|
697
|
+
var _a2, _b, _c;
|
|
698
|
+
const geometry = this.geometry;
|
|
699
|
+
const batchedAttributes = geometry.attributes;
|
|
700
|
+
let memberIndexes = ((_a2 = batchedAttributes[memberIndexAttrName]) == null ? void 0 : _a2.array) ?? new Uint16Array(0);
|
|
701
|
+
let batchedGlyphIndexes = ((_b = batchedAttributes[glyphIndexAttrName]) == null ? void 0 : _b.array) ?? new Float32Array(0);
|
|
702
|
+
let batchedGlyphBounds = ((_c = batchedAttributes[glyphBoundsAttrName]) == null ? void 0 : _c.array) ?? new Float32Array(0);
|
|
703
|
+
let totalGlyphCount = 0;
|
|
704
|
+
this._members.forEach((_, { textRenderInfo }) => {
|
|
705
|
+
if (textRenderInfo) {
|
|
706
|
+
totalGlyphCount += textRenderInfo.glyphAtlasIndices.length;
|
|
707
|
+
this._textRenderInfo = textRenderInfo;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
if (totalGlyphCount !== memberIndexes.length) {
|
|
711
|
+
memberIndexes = cloneAndResize(memberIndexes, totalGlyphCount);
|
|
712
|
+
batchedGlyphIndexes = cloneAndResize(batchedGlyphIndexes, totalGlyphCount);
|
|
713
|
+
batchedGlyphBounds = cloneAndResize(batchedGlyphBounds, totalGlyphCount * 4);
|
|
714
|
+
}
|
|
715
|
+
let memberIndex = 0;
|
|
716
|
+
let glyphIndex = 0;
|
|
717
|
+
this._members.forEach((packingInfo, { textRenderInfo }) => {
|
|
718
|
+
if (textRenderInfo) {
|
|
719
|
+
const glyphCount = textRenderInfo.glyphAtlasIndices.length;
|
|
720
|
+
memberIndexes.fill(memberIndex, glyphIndex, glyphIndex + glyphCount);
|
|
721
|
+
batchedGlyphIndexes.set(textRenderInfo.glyphAtlasIndices, glyphIndex);
|
|
722
|
+
batchedGlyphBounds.set(textRenderInfo.glyphBounds, glyphIndex * 4);
|
|
723
|
+
glyphIndex += glyphCount;
|
|
724
|
+
packingInfo.index = memberIndex++;
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
geometry.updateAttributeData(memberIndexAttrName, memberIndexes, 1);
|
|
728
|
+
geometry.getAttribute(memberIndexAttrName).setUsage(DynamicDrawUsage);
|
|
729
|
+
geometry.updateAttributeData(glyphIndexAttrName, batchedGlyphIndexes, 1);
|
|
730
|
+
geometry.updateAttributeData(glyphBoundsAttrName, batchedGlyphBounds, 4);
|
|
731
|
+
this.boundsNeedsUpdate = true;
|
|
732
|
+
this.updateBounds();
|
|
733
|
+
}
|
|
734
|
+
prepareForRender(material, scene, camera) {
|
|
597
735
|
var _a2;
|
|
598
736
|
const isOutline = material.isTextOutlineMaterial;
|
|
599
737
|
material.uniforms.uTroikaIsOutline.value = isOutline;
|
|
@@ -612,12 +750,15 @@ class BatchedText extends BatchedText$1 {
|
|
|
612
750
|
}
|
|
613
751
|
const texData = texture.image.data;
|
|
614
752
|
this.textureNeedsUpdate = false;
|
|
753
|
+
tempMat4.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse).multiply(scene.matrixWorld);
|
|
754
|
+
frustum.setFromProjectionMatrix(tempMat4, camera.coordinateSystem);
|
|
615
755
|
for (const text of this.textArray) {
|
|
616
756
|
const index = ((_a2 = this._members.get(text)) == null ? void 0 : _a2.index) ?? -1;
|
|
617
757
|
const textRenderInfo = text.textRenderInfo;
|
|
618
758
|
if (index < 0 || !textRenderInfo) continue;
|
|
619
759
|
const startIndex = index * floatsPerMember;
|
|
620
|
-
|
|
760
|
+
const isHidden = !text.visible || !frustum.intersectsSphere(sphere.copy(text.geometry.boundingSphere).applyMatrix4(text.matrix));
|
|
761
|
+
if (isHidden) {
|
|
621
762
|
for (let i = 0; i < 16; i++) {
|
|
622
763
|
this.setTexData(startIndex + i, 0, texData);
|
|
623
764
|
}
|
|
@@ -675,6 +816,11 @@ class BatchedText extends BatchedText$1 {
|
|
|
675
816
|
}
|
|
676
817
|
}
|
|
677
818
|
class Text extends Text$1 {
|
|
819
|
+
constructor() {
|
|
820
|
+
super(...arguments);
|
|
821
|
+
/** Parent batch for sync invalidation. */
|
|
822
|
+
__publicField(this, "_batchParent");
|
|
823
|
+
}
|
|
678
824
|
_prepareForRender(material) {
|
|
679
825
|
const isOutline = material.isTextOutlineMaterial;
|
|
680
826
|
const uniforms = material.uniforms;
|
|
@@ -732,7 +878,7 @@ class Text extends Text$1 {
|
|
|
732
878
|
blockBounds[3] + pad
|
|
733
879
|
);
|
|
734
880
|
}
|
|
735
|
-
this.geometry.applyClipRect(uniforms.uTroikaClipRect.value);
|
|
881
|
+
if (!this._batchParent) this.geometry.applyClipRect(uniforms.uTroikaClipRect.value);
|
|
736
882
|
}
|
|
737
883
|
uniforms.uTroikaSDFDebug.value = !!this.debugSDF;
|
|
738
884
|
material.polygonOffset = !!this.depthOffset;
|
|
@@ -764,6 +910,29 @@ class Text extends Text$1 {
|
|
|
764
910
|
}
|
|
765
911
|
}
|
|
766
912
|
}
|
|
913
|
+
SYNCABLE_PROPS.forEach((prop) => {
|
|
914
|
+
const privateKey = `_private_${prop}`;
|
|
915
|
+
Object.defineProperty(Text.prototype, prop, {
|
|
916
|
+
get() {
|
|
917
|
+
return this[privateKey];
|
|
918
|
+
},
|
|
919
|
+
set(value) {
|
|
920
|
+
var _a2;
|
|
921
|
+
const target = this;
|
|
922
|
+
if (value !== target[privateKey]) {
|
|
923
|
+
target[privateKey] = value;
|
|
924
|
+
target._needsSync = true;
|
|
925
|
+
(_a2 = target._batchParent) == null ? void 0 : _a2.requestSync();
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
});
|
|
930
|
+
function cloneAndResize(source, newLength) {
|
|
931
|
+
const constructor = source.constructor;
|
|
932
|
+
const copy = new constructor(newLength);
|
|
933
|
+
copy.set(source.subarray(0, newLength));
|
|
934
|
+
return copy;
|
|
935
|
+
}
|
|
767
936
|
function setDimming(root, dim) {
|
|
768
937
|
root.userData["uDim"] = dim === void 0 ? void 0 : +dim;
|
|
769
938
|
}
|
|
@@ -2001,19 +2170,30 @@ class TextSystem extends RenderableSystem {
|
|
|
2001
2170
|
group.add(newBatchedText);
|
|
2002
2171
|
}
|
|
2003
2172
|
updateDefImpl(textDef, mesh, instanceIds) {
|
|
2004
|
-
|
|
2173
|
+
const lines = [];
|
|
2174
|
+
for (let i = 0; i < textDef.lines.length; i++) {
|
|
2175
|
+
const line = textDef.lines[i];
|
|
2005
2176
|
const text = mesh.getText(instanceIds[i]);
|
|
2006
|
-
if (
|
|
2007
|
-
text.
|
|
2008
|
-
|
|
2009
|
-
text.font = line.fontUrl;
|
|
2010
|
-
if (line.stroke) {
|
|
2011
|
-
text.outlineColor = line.stroke.color;
|
|
2012
|
-
text.outlineWidth = line.stroke.width / line.fontSize;
|
|
2013
|
-
}
|
|
2177
|
+
if (line.fontSize === 0) {
|
|
2178
|
+
text.visible = false;
|
|
2179
|
+
continue;
|
|
2014
2180
|
}
|
|
2181
|
+
text.visible = true;
|
|
2182
|
+
text.text = line.text;
|
|
2183
|
+
text.color = this.textColor.set(line.color).getHex(LinearSRGBColorSpace);
|
|
2184
|
+
text.font = line.fontUrl;
|
|
2185
|
+
if (line.stroke) {
|
|
2186
|
+
text.outlineColor = line.stroke.color;
|
|
2187
|
+
text.outlineWidth = line.fontSize == 0 ? 0 : line.stroke.width / line.fontSize;
|
|
2188
|
+
}
|
|
2189
|
+
const fontSize = line.fontSize;
|
|
2190
|
+
const height = line.text.split("\n").length * text.lineHeight * fontSize;
|
|
2191
|
+
lines.push({ text, fontSize, height });
|
|
2192
|
+
}
|
|
2193
|
+
if (lines.length > 0) {
|
|
2194
|
+
if (textDef.alignment.vertical === "bottom") lines.reverse();
|
|
2195
|
+
this.updateScale(textDef, mesh, lines);
|
|
2015
2196
|
}
|
|
2016
|
-
this.updateScale(textDef);
|
|
2017
2197
|
}
|
|
2018
2198
|
buildBatchedText(layer) {
|
|
2019
2199
|
const textDefs = layer.children;
|
|
@@ -2028,6 +2208,7 @@ class TextSystem extends RenderableSystem {
|
|
|
2028
2208
|
text.fontSize = 1;
|
|
2029
2209
|
text.lineHeight = 1.1;
|
|
2030
2210
|
text.whiteSpace = "nowrap";
|
|
2211
|
+
text.clipRect = [0, 0, 0, 0];
|
|
2031
2212
|
batchedText.addText(text, instanceId);
|
|
2032
2213
|
instanceIds.push(instanceId);
|
|
2033
2214
|
instanceId++;
|
|
@@ -2047,9 +2228,8 @@ class TextSystem extends RenderableSystem {
|
|
|
2047
2228
|
return batchedText;
|
|
2048
2229
|
}
|
|
2049
2230
|
// TODO: Simplify
|
|
2050
|
-
updateScale(textDef) {
|
|
2231
|
+
updateScale(textDef, mesh, lines) {
|
|
2051
2232
|
const dpr = this.renderer.context.getPixelRatio();
|
|
2052
|
-
const lines = this.getTextLines(textDef);
|
|
2053
2233
|
this.calculateStartInBoundsPosition(
|
|
2054
2234
|
textDef,
|
|
2055
2235
|
lines,
|
|
@@ -2057,41 +2237,18 @@ class TextSystem extends RenderableSystem {
|
|
|
2057
2237
|
this.alignmentOffset,
|
|
2058
2238
|
this.localPosition
|
|
2059
2239
|
);
|
|
2060
|
-
for (const { text, fontSize, height
|
|
2061
|
-
|
|
2062
|
-
text.visible = false;
|
|
2063
|
-
continue;
|
|
2064
|
-
}
|
|
2065
|
-
text.visible = true;
|
|
2066
|
-
setAnchorsAndAlignment(text, alignment);
|
|
2240
|
+
for (const { text, fontSize, height } of lines) {
|
|
2241
|
+
setAnchorsAndAlignment(text, textDef.alignment);
|
|
2067
2242
|
this.worldPosition.copy(this.localPosition).rotateAround({ x: 0, y: 0 }, textDef.bounds.rotation).add(textDef.bounds.center);
|
|
2068
2243
|
this.textScale.copy(this.initialTextScale).multiplyScalar(fontSize * dpr);
|
|
2069
2244
|
text.scale.set(this.textScale.x, this.textScale.y, 1);
|
|
2070
2245
|
text.position.set(this.worldPosition.x, this.worldPosition.y, 0);
|
|
2071
2246
|
text.rotation.set(0, 0, textDef.bounds.rotation);
|
|
2072
|
-
text.
|
|
2073
|
-
textDef,
|
|
2074
|
-
this.localPosition,
|
|
2075
|
-
this.textScale,
|
|
2076
|
-
this.localToMin,
|
|
2077
|
-
this.localToMax
|
|
2078
|
-
);
|
|
2247
|
+
this.calculateClipRect(text, textDef, this.localPosition, this.textScale, this.localToMin, this.localToMax);
|
|
2079
2248
|
this.localPosition.y += height * dpr;
|
|
2249
|
+
mesh.invalidateBounds();
|
|
2080
2250
|
}
|
|
2081
2251
|
}
|
|
2082
|
-
getTextLines(textDef) {
|
|
2083
|
-
const { object: mesh, instanceIds } = this.getObjectInstanceByDef(textDef);
|
|
2084
|
-
const alignment = textDef.alignment;
|
|
2085
|
-
const lines = instanceIds.map((instanceId, i) => {
|
|
2086
|
-
const text = mesh.getText(instanceId);
|
|
2087
|
-
const line = textDef.lines[i];
|
|
2088
|
-
const fontSize = line.fontSize;
|
|
2089
|
-
const height = fontSize ? text.text.split("\n").length * text.lineHeight * fontSize : 0;
|
|
2090
|
-
return { text, fontSize, height, alignment };
|
|
2091
|
-
});
|
|
2092
|
-
if (alignment.vertical === "bottom") lines.reverse();
|
|
2093
|
-
return lines;
|
|
2094
|
-
}
|
|
2095
2252
|
calculateStartInBoundsPosition(textDef, lines, alignmentDirection, alignmentOffset, inBoundsPosition) {
|
|
2096
2253
|
const padding = textDef.padding;
|
|
2097
2254
|
const alignment = textDef.alignment;
|
|
@@ -2106,10 +2263,13 @@ class TextSystem extends RenderableSystem {
|
|
|
2106
2263
|
}
|
|
2107
2264
|
inBoundsPosition.multiply(alignmentDirection);
|
|
2108
2265
|
}
|
|
2109
|
-
calculateClipRect(textDef, inBoundsPosition, textScale, toMin, toMax) {
|
|
2266
|
+
calculateClipRect(text, textDef, inBoundsPosition, textScale, toMin, toMax) {
|
|
2110
2267
|
toMin.subVectors(textDef.bounds.min, textDef.bounds.center).multiply(this.initialTextScale).sub(inBoundsPosition).divide(textScale);
|
|
2111
2268
|
toMax.subVectors(textDef.bounds.max, textDef.bounds.center).multiply(this.initialTextScale).sub(inBoundsPosition).divide(textScale);
|
|
2112
|
-
|
|
2269
|
+
text.clipRect[0] = toMin.x;
|
|
2270
|
+
text.clipRect[1] = toMin.y;
|
|
2271
|
+
text.clipRect[2] = toMax.x;
|
|
2272
|
+
text.clipRect[3] = toMax.y;
|
|
2113
2273
|
}
|
|
2114
2274
|
}
|
|
2115
2275
|
function getAlignmentDirection(alignment) {
|
|
@@ -2147,7 +2307,8 @@ class LayerSystem {
|
|
|
2147
2307
|
__publicField(this, "mapLayerDefToParent", /* @__PURE__ */ new Map());
|
|
2148
2308
|
__publicField(this, "layerDefRenderOrder", []);
|
|
2149
2309
|
__publicField(this, "pendingDefs", /* @__PURE__ */ new Set());
|
|
2150
|
-
__publicField(this, "
|
|
2310
|
+
__publicField(this, "culledDefs", /* @__PURE__ */ new Set());
|
|
2311
|
+
__publicField(this, "useUpdateBuffering", true);
|
|
2151
2312
|
this.renderer = renderer;
|
|
2152
2313
|
this.materialSystem = new MaterialSystem();
|
|
2153
2314
|
this.meshSystem = new MeshSystem(this.materialSystem, this.renderer);
|
|
@@ -2181,30 +2342,57 @@ class LayerSystem {
|
|
|
2181
2342
|
*/
|
|
2182
2343
|
updateDefs(defs) {
|
|
2183
2344
|
for (const def of defs) {
|
|
2184
|
-
if (this.useUpdateBuffering)
|
|
2185
|
-
|
|
2345
|
+
if (this.useUpdateBuffering) {
|
|
2346
|
+
this.pendingDefs.add(def);
|
|
2347
|
+
this.culledDefs.delete(def);
|
|
2348
|
+
} else this.updateDef(def);
|
|
2186
2349
|
}
|
|
2187
2350
|
}
|
|
2188
2351
|
/**
|
|
2189
2352
|
* Drain the queued updates within a time budget.
|
|
2190
2353
|
* Returns true if any def was updated during this call.
|
|
2354
|
+
* @param scene {@link Scene} instance to get the world matrix from
|
|
2355
|
+
* @param camera {@link Camera} instance to do frustum culling against
|
|
2191
2356
|
* @param timeBudgetMs frame time budget to perform updates in milliseconds
|
|
2192
2357
|
* @returns true if any def was updated during this call
|
|
2193
2358
|
*/
|
|
2194
|
-
processPendingUpdates(timeBudgetMs =
|
|
2359
|
+
processPendingUpdates(scene, camera, timeBudgetMs = -1) {
|
|
2195
2360
|
if (!this.useUpdateBuffering) return false;
|
|
2196
|
-
if (this.pendingDefs.size === 0) return false;
|
|
2361
|
+
if (this.pendingDefs.size === 0 && this.culledDefs.size === 0) return false;
|
|
2197
2362
|
const startTime = performance.now();
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2363
|
+
_matrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse).multiply(scene.matrixWorld);
|
|
2364
|
+
_frustum.setFromProjectionMatrix(_matrix, camera.coordinateSystem);
|
|
2365
|
+
let processedCount = 0;
|
|
2366
|
+
const overBudget = () => timeBudgetMs > 0 && performance.now() - startTime >= timeBudgetMs;
|
|
2367
|
+
for (const def of this.pendingDefs) {
|
|
2368
|
+
if (overBudget()) break;
|
|
2369
|
+
let culled = false;
|
|
2201
2370
|
this.pendingDefs.delete(def);
|
|
2371
|
+
if (isTextDef(def) || isImageDef(def)) {
|
|
2372
|
+
const bounds = def.bounds;
|
|
2373
|
+
_box.min.set(bounds.min.x, bounds.min.y, 0);
|
|
2374
|
+
_box.max.set(bounds.max.x, bounds.max.y, 0);
|
|
2375
|
+
culled = !_frustum.intersectsBox(_box);
|
|
2376
|
+
}
|
|
2377
|
+
if (culled) this.culledDefs.add(def);
|
|
2378
|
+
else {
|
|
2379
|
+
this.updateDef(def);
|
|
2380
|
+
processedCount++;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
for (const def of this.culledDefs) {
|
|
2384
|
+
if (overBudget()) break;
|
|
2385
|
+
this.culledDefs.delete(def);
|
|
2202
2386
|
this.updateDef(def);
|
|
2203
|
-
|
|
2387
|
+
processedCount++;
|
|
2204
2388
|
}
|
|
2205
2389
|
const took = (performance.now() - startTime).toFixed(2);
|
|
2206
|
-
if (
|
|
2207
|
-
|
|
2390
|
+
if (processedCount > 0) {
|
|
2391
|
+
const culled = this.culledDefs.size;
|
|
2392
|
+
const remaining = this.pendingDefs.size;
|
|
2393
|
+
logger$5.debug(`processed ${processedCount} defs (${culled} culled, ${remaining} remaining) in ${took}ms`);
|
|
2394
|
+
}
|
|
2395
|
+
return processedCount > 0;
|
|
2208
2396
|
}
|
|
2209
2397
|
/**
|
|
2210
2398
|
* Build the scene graph from the given scene definition.
|
|
@@ -2337,6 +2525,9 @@ class LayerSystem {
|
|
|
2337
2525
|
return fullName;
|
|
2338
2526
|
}
|
|
2339
2527
|
}
|
|
2528
|
+
const _matrix = new Matrix4();
|
|
2529
|
+
const _frustum = new Frustum();
|
|
2530
|
+
const _box = new Box3();
|
|
2340
2531
|
/*!
|
|
2341
2532
|
* camera-controls
|
|
2342
2533
|
* https://github.com/yomotsu/camera-controls
|
|
@@ -4947,6 +5138,17 @@ class CameraSystem {
|
|
|
4947
5138
|
if (zoomFactor <= 0) return this.zoomIdentityDistance;
|
|
4948
5139
|
return this.zoomIdentityDistance / zoomFactor;
|
|
4949
5140
|
}
|
|
5141
|
+
/**
|
|
5142
|
+
* Set the zoom factor bounds.
|
|
5143
|
+
* @param minZoom Minimum zoom factor. Default is 0.1.
|
|
5144
|
+
* @param maxZoom Maximum zoom factor. Default is 35.
|
|
5145
|
+
*/
|
|
5146
|
+
setZoomBounds(minZoom, maxZoom) {
|
|
5147
|
+
if (!this.zoomBounds) return;
|
|
5148
|
+
if (minZoom) this.zoomBounds[0] = minZoom;
|
|
5149
|
+
if (maxZoom) this.zoomBounds[1] = maxZoom;
|
|
5150
|
+
this.updateCamera();
|
|
5151
|
+
}
|
|
4950
5152
|
/**
|
|
4951
5153
|
* Initializes the camera with the given zoom bounds.
|
|
4952
5154
|
* @param zoomBounds [minZoom, maxZoom]
|
|
@@ -5292,7 +5494,7 @@ class ViewportSystem {
|
|
|
5292
5494
|
*/
|
|
5293
5495
|
initViewport(sceneDef) {
|
|
5294
5496
|
if (!this.renderer.isExternalMode) this.sceneSystem.initScene(sceneDef.viewbox);
|
|
5295
|
-
this.cameraSystem.initCamera([0.1, sceneDef.viewbox.size.x >
|
|
5497
|
+
this.cameraSystem.initCamera([0.1, sceneDef.viewbox.size.x > 1e4 ? 100 : 35]);
|
|
5296
5498
|
}
|
|
5297
5499
|
/** Updates the viewport when the renderer size changes. */
|
|
5298
5500
|
updateViewport() {
|
|
@@ -5397,12 +5599,28 @@ class ViewportSystem {
|
|
|
5397
5599
|
zoomFactorToDistance(zoomFactor) {
|
|
5398
5600
|
return this.cameraSystem.zoomFactorToDistance(zoomFactor);
|
|
5399
5601
|
}
|
|
5602
|
+
/**
|
|
5603
|
+
* Set the maximum zoom factor. Default is 35.
|
|
5604
|
+
* @param maxZoom Maximum zoom factor
|
|
5605
|
+
*/
|
|
5606
|
+
setMaxZoom(maxZoom) {
|
|
5607
|
+
this.cameraSystem.setZoomBounds(void 0, maxZoom);
|
|
5608
|
+
}
|
|
5609
|
+
/**
|
|
5610
|
+
* Set the minimum zoom factor. Default is 0.1.
|
|
5611
|
+
* @param minZoom Minimum zoom factor
|
|
5612
|
+
*/
|
|
5613
|
+
setMinZoom(minZoom) {
|
|
5614
|
+
this.cameraSystem.setZoomBounds(minZoom, void 0);
|
|
5615
|
+
}
|
|
5400
5616
|
}
|
|
5401
5617
|
function asViewportAPI(viewportSystem) {
|
|
5402
5618
|
return {
|
|
5403
5619
|
canvasToSvg: viewportSystem.canvasToSvg.bind(viewportSystem),
|
|
5404
5620
|
setStaticTransform: viewportSystem.setStaticTransform.bind(viewportSystem),
|
|
5405
|
-
setDynamicTransform: viewportSystem.setDynamicTransform.bind(viewportSystem)
|
|
5621
|
+
setDynamicTransform: viewportSystem.setDynamicTransform.bind(viewportSystem),
|
|
5622
|
+
setMaxZoom: viewportSystem.setMaxZoom.bind(viewportSystem),
|
|
5623
|
+
setMinZoom: viewportSystem.setMinZoom.bind(viewportSystem)
|
|
5406
5624
|
};
|
|
5407
5625
|
}
|
|
5408
5626
|
function eventToCanvas(event) {
|
|
@@ -6418,10 +6636,13 @@ class Renderer {
|
|
|
6418
6636
|
const api = asViewportAPI(this.viewportSystem);
|
|
6419
6637
|
const guard = (name) => this.assertInitialized(`viewport.${name}`) && this.assertNotDisposed(`viewport.${name}`);
|
|
6420
6638
|
const guardExternal = (name) => guard(name) && this.assertExternalMode(`viewport.${name}`);
|
|
6639
|
+
const guardNotExternal = (name) => guard(name) && this.assertNotExternalMode(`viewport.${name}`);
|
|
6421
6640
|
this.viewportAPI = {
|
|
6422
6641
|
canvasToSvg: guardFn(guard, api.canvasToSvg, { x: 0, y: 0 }),
|
|
6423
6642
|
setStaticTransform: guardFn(guardExternal, api.setStaticTransform),
|
|
6424
|
-
setDynamicTransform: guardFn(guardExternal, api.setDynamicTransform)
|
|
6643
|
+
setDynamicTransform: guardFn(guardExternal, api.setDynamicTransform),
|
|
6644
|
+
setMaxZoom: guardFn(guardNotExternal, api.setMaxZoom),
|
|
6645
|
+
setMinZoom: guardFn(guardNotExternal, api.setMinZoom)
|
|
6425
6646
|
};
|
|
6426
6647
|
return this.viewportAPI;
|
|
6427
6648
|
}
|
|
@@ -6521,12 +6742,13 @@ class Renderer {
|
|
|
6521
6742
|
(_b = (_a2 = this.ui) == null ? void 0 : _a2.stats) == null ? void 0 : _b.begin();
|
|
6522
6743
|
if (this.isExternalMode) this.renderer.resetState();
|
|
6523
6744
|
else this.resizeCanvasToDisplaySize();
|
|
6524
|
-
this.viewportSystem
|
|
6525
|
-
const hasDefsUpdated = this.layerSystem.processPendingUpdates();
|
|
6745
|
+
const { scene, camera } = this.viewportSystem;
|
|
6526
6746
|
const hasControlsUpdated = this.interactionsSystem.updateControls(this.clock.getDelta());
|
|
6747
|
+
this.viewportSystem.updatePtScale();
|
|
6748
|
+
const hasDefsUpdated = this.layerSystem.processPendingUpdates(scene, camera, 3);
|
|
6527
6749
|
const needsRedraw = this.needsRedraw || hasControlsUpdated || hasDefsUpdated || this.isExternalMode || this.ui;
|
|
6528
6750
|
if (needsRedraw) {
|
|
6529
|
-
this.renderer.render(
|
|
6751
|
+
this.renderer.render(scene, camera);
|
|
6530
6752
|
this.needsRedraw = false;
|
|
6531
6753
|
}
|
|
6532
6754
|
(_d = (_c = this.ui) == null ? void 0 : _c.stats) == null ? void 0 : _d.end();
|
|
@@ -6562,7 +6784,8 @@ class Renderer {
|
|
|
6562
6784
|
// https://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
|
|
6563
6785
|
resizeCanvasToDisplaySize() {
|
|
6564
6786
|
const dpr = window.devicePixelRatio;
|
|
6565
|
-
const
|
|
6787
|
+
const width = this.canvas.clientWidth;
|
|
6788
|
+
const height = this.canvas.clientHeight;
|
|
6566
6789
|
const displayWidth = Math.floor(width * dpr);
|
|
6567
6790
|
const displayHeight = Math.floor(height * dpr);
|
|
6568
6791
|
if (this.canvas.width !== displayWidth || this.canvas.height !== displayHeight || this.renderer.getPixelRatio() !== dpr) {
|
|
@@ -6670,8 +6893,6 @@ export {
|
|
|
6670
6893
|
Polygon,
|
|
6671
6894
|
Rect,
|
|
6672
6895
|
Renderer,
|
|
6673
|
-
createVector2,
|
|
6674
|
-
createVector3,
|
|
6675
6896
|
isImageDef,
|
|
6676
6897
|
isImageLayer,
|
|
6677
6898
|
isLayerDef,
|