@almadar/ui 5.142.0 → 5.143.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/avl/index.cjs +92 -29
- package/dist/avl/index.js +92 -29
- package/dist/{avl-schema-parser-DAs12kxP.d.ts → avl-schema-parser-0hkiHOq3.d.ts} +6 -2
- package/dist/{avl-schema-parser-wOkfbwAh.d.cts → avl-schema-parser-BZ8pICOS.d.cts} +6 -2
- package/dist/{cn-rwc3svaX.d.cts → cn-CvImTgKH.d.cts} +1 -1
- package/dist/{cn-BDwC4QpH.d.ts → cn-DryTiahe.d.ts} +1 -1
- package/dist/components/index.cjs +92 -29
- package/dist/components/index.d.cts +5 -5
- package/dist/components/index.d.ts +5 -5
- package/dist/components/index.js +92 -29
- package/dist/lib/drawable/three/index.cjs +384 -183
- package/dist/lib/drawable/three/index.d.cts +3 -3
- package/dist/lib/drawable/three/index.d.ts +3 -3
- package/dist/lib/drawable/three/index.js +360 -159
- package/dist/lib/index.d.cts +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/{paintDispatch-BQn5Lyx1.d.cts → paintDispatch-D3-5_cOb.d.cts} +72 -32
- package/dist/{paintDispatch-BQn5Lyx1.d.ts → paintDispatch-D3-5_cOb.d.ts} +72 -32
- package/dist/providers/index.cjs +92 -29
- package/dist/providers/index.js +92 -29
- package/dist/runtime/index.cjs +92 -29
- package/dist/runtime/index.js +92 -29
- package/package.json +8 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React3, { forwardRef, useRef, useState, useMemo, useEffect, useImperativeHandle, useCallback,
|
|
1
|
+
import React3, { createContext, forwardRef, useRef, useState, useMemo, useEffect, useImperativeHandle, useCallback, useContext, Component, useReducer } from 'react';
|
|
2
2
|
import { EventBusContext, useTraitScopeChain } from '@almadar/ui/providers';
|
|
3
3
|
import { createLogger } from '@almadar/logger';
|
|
4
4
|
import { Canvas, useThree, useFrame } from '@react-three/fiber';
|
|
5
|
-
import * as
|
|
5
|
+
import * as THREE11 from 'three';
|
|
6
6
|
import { Vector3, QuadraticBezierCurve3, MathUtils, Quaternion } from 'three';
|
|
7
7
|
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
|
|
8
8
|
import { Grid, OrbitControls, Billboard, Text, Stars, Sparkles, Html, RoundedBox } from '@react-three/drei';
|
|
@@ -507,7 +507,7 @@ function Lighting3D({
|
|
|
507
507
|
"directionalLightHelper",
|
|
508
508
|
{
|
|
509
509
|
args: [
|
|
510
|
-
new
|
|
510
|
+
new THREE11.DirectionalLight(directionalColor, directionalIntensity),
|
|
511
511
|
5
|
|
512
512
|
]
|
|
513
513
|
}
|
|
@@ -564,8 +564,8 @@ function FollowCamera3D({
|
|
|
564
564
|
offset
|
|
565
565
|
}) {
|
|
566
566
|
const { camera } = useThree();
|
|
567
|
-
const look = useRef(new
|
|
568
|
-
const goal = useRef(new
|
|
567
|
+
const look = useRef(new THREE11.Vector3(target[0], target[1], target[2]));
|
|
568
|
+
const goal = useRef(new THREE11.Vector3());
|
|
569
569
|
useFrame((_, delta) => {
|
|
570
570
|
const t = Math.min(1, delta * 5);
|
|
571
571
|
goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
|
|
@@ -586,7 +586,109 @@ function create3DProjector(opts = {}) {
|
|
|
586
586
|
toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
|
|
587
587
|
};
|
|
588
588
|
}
|
|
589
|
+
var BoneStore = class {
|
|
590
|
+
constructor() {
|
|
591
|
+
__publicField(this, "bones", /* @__PURE__ */ new Map());
|
|
592
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
593
|
+
}
|
|
594
|
+
register(name, bone) {
|
|
595
|
+
this.bones.set(name, bone);
|
|
596
|
+
this.notify();
|
|
597
|
+
return () => {
|
|
598
|
+
if (this.bones.get(name) === bone) {
|
|
599
|
+
this.bones.delete(name);
|
|
600
|
+
this.notify();
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
get(name) {
|
|
605
|
+
return this.bones.get(name);
|
|
606
|
+
}
|
|
607
|
+
subscribe(listener) {
|
|
608
|
+
this.listeners.add(listener);
|
|
609
|
+
return () => this.listeners.delete(listener);
|
|
610
|
+
}
|
|
611
|
+
notify() {
|
|
612
|
+
for (const l of this.listeners) l();
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
var BoneRegistryContext = createContext(null);
|
|
616
|
+
function isAnimatedGroup(node) {
|
|
617
|
+
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
618
|
+
}
|
|
619
|
+
var MESH_SEGMENTS_DEFAULT = 24;
|
|
620
|
+
function polyhedronBounds(vertices) {
|
|
621
|
+
if (!vertices || vertices.length < 3) return null;
|
|
622
|
+
const min = [Infinity, Infinity, Infinity];
|
|
623
|
+
const max = [-Infinity, -Infinity, -Infinity];
|
|
624
|
+
for (const v of vertices) {
|
|
625
|
+
if (v.length < 3 || !v.every((c) => Number.isFinite(c))) return null;
|
|
626
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
627
|
+
min[axis] = Math.min(min[axis], v[axis]);
|
|
628
|
+
max[axis] = Math.max(max[axis], v[axis]);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return { min, max };
|
|
632
|
+
}
|
|
633
|
+
function clampSegments(segments) {
|
|
634
|
+
const s = segments ?? MESH_SEGMENTS_DEFAULT;
|
|
635
|
+
return Math.min(64, Math.max(3, Math.round(s)));
|
|
636
|
+
}
|
|
637
|
+
function isAnimatedMesh(node) {
|
|
638
|
+
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
639
|
+
}
|
|
640
|
+
var lerp = (a, b, k) => a + (b - a) * k;
|
|
589
641
|
var NUMERIC_TRACKS = [
|
|
642
|
+
"offsetX",
|
|
643
|
+
"offsetY",
|
|
644
|
+
"offsetZ",
|
|
645
|
+
"rotateX",
|
|
646
|
+
"rotateY",
|
|
647
|
+
"rotateZ",
|
|
648
|
+
"scale",
|
|
649
|
+
"opacity",
|
|
650
|
+
"emissiveIntensity"
|
|
651
|
+
];
|
|
652
|
+
function applyMeshAnimation(node, timeMs) {
|
|
653
|
+
const anim = node.animation;
|
|
654
|
+
if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
|
|
655
|
+
const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
|
|
656
|
+
const cycle = timeMs / anim.durationMs;
|
|
657
|
+
const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
|
|
658
|
+
const trackValue = (key) => {
|
|
659
|
+
const defined = frames.filter((f) => f[key] !== void 0);
|
|
660
|
+
if (defined.length === 0) return void 0;
|
|
661
|
+
let prev;
|
|
662
|
+
let next;
|
|
663
|
+
for (const f of defined) {
|
|
664
|
+
if (f.at <= t) prev = f;
|
|
665
|
+
else if (!next) next = f;
|
|
666
|
+
}
|
|
667
|
+
if (!prev) return defined[0][key];
|
|
668
|
+
if (!next) return prev[key];
|
|
669
|
+
const span = next.at - prev.at;
|
|
670
|
+
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
671
|
+
const a = prev[key];
|
|
672
|
+
const b = next[key];
|
|
673
|
+
if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
|
|
674
|
+
return a;
|
|
675
|
+
};
|
|
676
|
+
const num = {};
|
|
677
|
+
for (const key of NUMERIC_TRACKS) {
|
|
678
|
+
const v = trackValue(key);
|
|
679
|
+
if (v !== void 0) num[key] = v;
|
|
680
|
+
}
|
|
681
|
+
return {
|
|
682
|
+
offset: [num.offsetX ?? 0, num.offsetY ?? 0, num.offsetZ ?? 0],
|
|
683
|
+
rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
|
|
684
|
+
scale: num.scale ?? 1,
|
|
685
|
+
opacity: num.opacity,
|
|
686
|
+
emissiveIntensity: num.emissiveIntensity,
|
|
687
|
+
color: trackValue("color"),
|
|
688
|
+
emissive: trackValue("emissive")
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
var NUMERIC_TRACKS2 = [
|
|
590
692
|
"offsetX",
|
|
591
693
|
"offsetY",
|
|
592
694
|
"rotate",
|
|
@@ -602,7 +704,7 @@ var NUMERIC_TRACKS = [
|
|
|
602
704
|
function isAnimatedShape(node) {
|
|
603
705
|
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
604
706
|
}
|
|
605
|
-
var
|
|
707
|
+
var lerp2 = (a, b, k) => a + (b - a) * k;
|
|
606
708
|
function applyShapeAnimation(node, timeMs) {
|
|
607
709
|
const anim = node.animation;
|
|
608
710
|
if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
|
|
@@ -625,10 +727,10 @@ function applyShapeAnimation(node, timeMs) {
|
|
|
625
727
|
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
626
728
|
const a = prev[key];
|
|
627
729
|
const b = next[key];
|
|
628
|
-
if (typeof a === "number" && typeof b === "number") return
|
|
730
|
+
if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
|
|
629
731
|
return a;
|
|
630
732
|
};
|
|
631
|
-
for (const key of
|
|
733
|
+
for (const key of NUMERIC_TRACKS2) {
|
|
632
734
|
const v = trackValue(key);
|
|
633
735
|
if (v !== void 0) out[key] = v;
|
|
634
736
|
}
|
|
@@ -649,7 +751,7 @@ function applyShapeAnimation(node, timeMs) {
|
|
|
649
751
|
if (prevSh?.shadow && nextSh?.shadow) {
|
|
650
752
|
const span = nextSh.at - prevSh.at;
|
|
651
753
|
const k = span > 0 ? (t - prevSh.at) / span : 1;
|
|
652
|
-
out.shadow = { color: prevSh.shadow.color, blur:
|
|
754
|
+
out.shadow = { color: prevSh.shadow.color, blur: lerp2(prevSh.shadow.blur, nextSh.shadow.blur, k) };
|
|
653
755
|
} else {
|
|
654
756
|
out.shadow = sh;
|
|
655
757
|
}
|
|
@@ -792,12 +894,12 @@ function ModelLoader({
|
|
|
792
894
|
if (!loadedModel) return null;
|
|
793
895
|
const cloned = clone(loadedModel);
|
|
794
896
|
cloned.updateMatrixWorld(true);
|
|
795
|
-
const tintColor = tint ? new
|
|
897
|
+
const tintColor = tint ? new THREE11.Color(tint) : null;
|
|
796
898
|
cloned.traverse((child) => {
|
|
797
|
-
if (child instanceof
|
|
899
|
+
if (child instanceof THREE11.Mesh) {
|
|
798
900
|
child.castShadow = castShadow;
|
|
799
901
|
child.receiveShadow = receiveShadow;
|
|
800
|
-
if (tintColor && child.material instanceof
|
|
902
|
+
if (tintColor && child.material instanceof THREE11.MeshStandardMaterial) {
|
|
801
903
|
const mat = child.material.clone();
|
|
802
904
|
mat.color.multiply(tintColor);
|
|
803
905
|
child.material = mat;
|
|
@@ -806,7 +908,7 @@ function ModelLoader({
|
|
|
806
908
|
});
|
|
807
909
|
return cloned;
|
|
808
910
|
}, [loadedModel, castShadow, receiveShadow, tint]);
|
|
809
|
-
const mixer = useMemo(() => model ? new
|
|
911
|
+
const mixer = useMemo(() => model ? new THREE11.AnimationMixer(model) : null, [model]);
|
|
810
912
|
useEffect(() => {
|
|
811
913
|
if (!mixer || !animation || clips.length === 0) return;
|
|
812
914
|
const wanted = animation.toLowerCase();
|
|
@@ -823,8 +925,8 @@ function ModelLoader({
|
|
|
823
925
|
});
|
|
824
926
|
const normFactor = useMemo(() => {
|
|
825
927
|
if (!model) return 1;
|
|
826
|
-
const box = new
|
|
827
|
-
const size = new
|
|
928
|
+
const box = new THREE11.Box3().setFromObject(model);
|
|
929
|
+
const size = new THREE11.Vector3();
|
|
828
930
|
box.getSize(size);
|
|
829
931
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
830
932
|
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
@@ -914,7 +1016,7 @@ var warnUnsupported3d = (kind) => {
|
|
|
914
1016
|
warnedUnsupported.add(kind);
|
|
915
1017
|
mesh3dLog.warn("unsupported drawable kind on the 3D backend \u2014 skipped", { kind });
|
|
916
1018
|
};
|
|
917
|
-
var CrossOriginTextureLoader = class extends
|
|
1019
|
+
var CrossOriginTextureLoader = class extends THREE11.TextureLoader {
|
|
918
1020
|
constructor() {
|
|
919
1021
|
super();
|
|
920
1022
|
this.crossOrigin = "anonymous";
|
|
@@ -932,7 +1034,7 @@ function useBillboardTexture(url) {
|
|
|
932
1034
|
url,
|
|
933
1035
|
(texture) => {
|
|
934
1036
|
if (!active) return;
|
|
935
|
-
texture.colorSpace =
|
|
1037
|
+
texture.colorSpace = THREE11.SRGBColorSpace;
|
|
936
1038
|
setState({ texture, error: false });
|
|
937
1039
|
},
|
|
938
1040
|
void 0,
|
|
@@ -985,7 +1087,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
985
1087
|
}, [texture, frame, node.height, node.width, anchor, cellSize]);
|
|
986
1088
|
const groundGeometry = React3.useMemo(() => {
|
|
987
1089
|
if (anchor !== "top-left" || !texture || !atlasReady) return null;
|
|
988
|
-
const g = new
|
|
1090
|
+
const g = new THREE11.PlaneGeometry(size.width, size.height);
|
|
989
1091
|
g.rotateX(-Math.PI / 2);
|
|
990
1092
|
return g;
|
|
991
1093
|
}, [anchor, texture, atlasReady, size.width, size.height]);
|
|
@@ -993,15 +1095,15 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
993
1095
|
if (anchor === "top-left") {
|
|
994
1096
|
return /* @__PURE__ */ jsx("group", { position: [world[0] + size.width / 2, 0.02, world[2] + size.height / 2], children: /* @__PURE__ */ jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
|
|
995
1097
|
/* @__PURE__ */ jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
996
|
-
/* @__PURE__ */ jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side:
|
|
1098
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE11.DoubleSide })
|
|
997
1099
|
] }) });
|
|
998
1100
|
}
|
|
999
1101
|
return /* @__PURE__ */ jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxs("mesh", { children: [
|
|
1000
1102
|
/* @__PURE__ */ jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
1001
|
-
/* @__PURE__ */ jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side:
|
|
1103
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE11.DoubleSide })
|
|
1002
1104
|
] }) });
|
|
1003
1105
|
}
|
|
1004
|
-
texture.magFilter = texture.minFilter =
|
|
1106
|
+
texture.magFilter = texture.minFilter = THREE11.NearestFilter;
|
|
1005
1107
|
texture.needsUpdate = true;
|
|
1006
1108
|
if (frame) {
|
|
1007
1109
|
texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
|
|
@@ -1014,7 +1116,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1014
1116
|
map: texture,
|
|
1015
1117
|
transparent: true,
|
|
1016
1118
|
alphaTest: 0.1,
|
|
1017
|
-
side:
|
|
1119
|
+
side: THREE11.DoubleSide,
|
|
1018
1120
|
opacity: (node.opacity ?? 1) * groupOpacity
|
|
1019
1121
|
}
|
|
1020
1122
|
) }) });
|
|
@@ -1027,7 +1129,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
1027
1129
|
map: texture,
|
|
1028
1130
|
transparent: true,
|
|
1029
1131
|
alphaTest: 0.1,
|
|
1030
|
-
side:
|
|
1132
|
+
side: THREE11.DoubleSide,
|
|
1031
1133
|
opacity: node.opacity ?? 1
|
|
1032
1134
|
}
|
|
1033
1135
|
)
|
|
@@ -1096,7 +1198,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1096
1198
|
}
|
|
1097
1199
|
case "poly": {
|
|
1098
1200
|
if (!node.points || node.points.length === 0) return null;
|
|
1099
|
-
const s = new
|
|
1201
|
+
const s = new THREE11.Shape();
|
|
1100
1202
|
node.points.forEach((p, i) => {
|
|
1101
1203
|
if (i === 0) s.moveTo(p.x, p.y);
|
|
1102
1204
|
else s.lineTo(p.x, p.y);
|
|
@@ -1114,7 +1216,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1114
1216
|
}
|
|
1115
1217
|
return /* @__PURE__ */ jsx("group", { ref: groupRef, position: [world[0], world[1] + 0.02, world[2]], children: /* @__PURE__ */ jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
|
|
1116
1218
|
geometry,
|
|
1117
|
-
/* @__PURE__ */ jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side:
|
|
1219
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE11.DoubleSide })
|
|
1118
1220
|
] }) });
|
|
1119
1221
|
}
|
|
1120
1222
|
function Text3D({ node, projector, groupOpacity = 1 }) {
|
|
@@ -1135,64 +1237,46 @@ function Text3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1135
1237
|
}
|
|
1136
1238
|
) });
|
|
1137
1239
|
}
|
|
1138
|
-
var
|
|
1139
|
-
function
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
let
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1240
|
+
var GROUND_ROTATION = [-Math.PI / 2, 0, 0];
|
|
1241
|
+
function polyhedronGeometry(node, cellSize) {
|
|
1242
|
+
const verts = node.vertices;
|
|
1243
|
+
const faces = node.faces;
|
|
1244
|
+
const bounds = polyhedronBounds(verts);
|
|
1245
|
+
if (!verts || !bounds || !faces || faces.length === 0) return null;
|
|
1246
|
+
const positions = new Float32Array(verts.length * 3);
|
|
1247
|
+
for (let i = 0; i < verts.length; i++) {
|
|
1248
|
+
positions[i * 3] = verts[i][0] * cellSize;
|
|
1249
|
+
positions[i * 3 + 1] = verts[i][2] * cellSize;
|
|
1250
|
+
positions[i * 3 + 2] = verts[i][1] * cellSize;
|
|
1251
|
+
}
|
|
1252
|
+
const index = [];
|
|
1253
|
+
for (const face of faces) {
|
|
1254
|
+
if (face.length < 3) continue;
|
|
1255
|
+
const [a, b, c] = face;
|
|
1256
|
+
if (a === b || b === c || a === c) continue;
|
|
1257
|
+
if (![a, b, c].every((i) => Number.isInteger(i) && i >= 0 && i < verts.length)) continue;
|
|
1258
|
+
index.push(a, c, b);
|
|
1259
|
+
}
|
|
1260
|
+
if (index.length === 0) return null;
|
|
1261
|
+
const geometry = new THREE11.BufferGeometry();
|
|
1262
|
+
geometry.setAttribute("position", new THREE11.BufferAttribute(positions, 3));
|
|
1263
|
+
geometry.setIndex(index);
|
|
1264
|
+
geometry.computeVertexNormals();
|
|
1265
|
+
const skin = node.skin;
|
|
1266
|
+
if (skin && skin.indices.length === verts.length && skin.weights.length === verts.length) {
|
|
1267
|
+
const skinIndex = new Uint16Array(verts.length * 4);
|
|
1268
|
+
const skinWeight = new Float32Array(verts.length * 4);
|
|
1269
|
+
for (let i = 0; i < verts.length; i++) {
|
|
1270
|
+
for (let k = 0; k < 4; k++) {
|
|
1271
|
+
skinIndex[i * 4 + k] = skin.indices[i][k] ?? 0;
|
|
1272
|
+
skinWeight[i * 4 + k] = skin.weights[i][k] ?? 0;
|
|
1273
|
+
}
|
|
1172
1274
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
const span = next.at - prev.at;
|
|
1176
|
-
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
1177
|
-
const a = prev[key];
|
|
1178
|
-
const b = next[key];
|
|
1179
|
-
if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
|
|
1180
|
-
return a;
|
|
1181
|
-
};
|
|
1182
|
-
const num = {};
|
|
1183
|
-
for (const key of NUMERIC_TRACKS2) {
|
|
1184
|
-
const v = trackValue(key);
|
|
1185
|
-
if (v !== void 0) num[key] = v;
|
|
1275
|
+
geometry.setAttribute("skinIndex", new THREE11.BufferAttribute(skinIndex, 4));
|
|
1276
|
+
geometry.setAttribute("skinWeight", new THREE11.BufferAttribute(skinWeight, 4));
|
|
1186
1277
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
|
|
1190
|
-
scale: num.scale ?? 1,
|
|
1191
|
-
opacity: num.opacity,
|
|
1192
|
-
emissiveIntensity: num.emissiveIntensity,
|
|
1193
|
-
color: trackValue("color"),
|
|
1194
|
-
emissive: trackValue("emissive")
|
|
1195
|
-
};
|
|
1278
|
+
const size = Math.max(bounds.max[0] - bounds.min[0], bounds.max[1] - bounds.min[1], bounds.max[2] - bounds.min[2]) * cellSize;
|
|
1279
|
+
return { geometry, lift: -bounds.min[2] * cellSize, size };
|
|
1196
1280
|
}
|
|
1197
1281
|
function meshGeometry(node, cellSize) {
|
|
1198
1282
|
const seg = clampSegments(node.segments);
|
|
@@ -1220,17 +1304,20 @@ function meshGeometry(node, cellSize) {
|
|
|
1220
1304
|
return { element: /* @__PURE__ */ jsx("torusGeometry", { args: [r, tube, Math.max(3, Math.round(seg / 2)), seg] }), lift: r + tube, size: (r + tube) * 2 };
|
|
1221
1305
|
}
|
|
1222
1306
|
case "plane":
|
|
1223
|
-
return { element: /* @__PURE__ */ jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d) };
|
|
1307
|
+
return { element: /* @__PURE__ */ jsx("planeGeometry", { args: [w, d] }), lift: 0, size: Math.max(w, d), baseRotation: GROUND_ROTATION };
|
|
1224
1308
|
case "circle":
|
|
1225
|
-
return { element: /* @__PURE__ */ jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2 };
|
|
1309
|
+
return { element: /* @__PURE__ */ jsx("circleGeometry", { args: [r, seg] }), lift: 0, size: r * 2, baseRotation: GROUND_ROTATION };
|
|
1310
|
+
case "polyhedron":
|
|
1311
|
+
return polyhedronGeometry(node, cellSize);
|
|
1226
1312
|
default:
|
|
1227
1313
|
return null;
|
|
1228
1314
|
}
|
|
1229
1315
|
}
|
|
1316
|
+
var warnedPolyhedronOutline = false;
|
|
1230
1317
|
var SIDE_MAP = {
|
|
1231
|
-
front:
|
|
1232
|
-
back:
|
|
1233
|
-
double:
|
|
1318
|
+
front: THREE11.FrontSide,
|
|
1319
|
+
back: THREE11.BackSide,
|
|
1320
|
+
double: THREE11.DoubleSide
|
|
1234
1321
|
};
|
|
1235
1322
|
function meshMaterial(mat, opacity, ref) {
|
|
1236
1323
|
const m = mat ?? {};
|
|
@@ -1274,6 +1361,53 @@ function meshMaterial(mat, opacity, ref) {
|
|
|
1274
1361
|
);
|
|
1275
1362
|
}
|
|
1276
1363
|
}
|
|
1364
|
+
function SkinnedPolyhedron3D({
|
|
1365
|
+
node,
|
|
1366
|
+
skin,
|
|
1367
|
+
geometry,
|
|
1368
|
+
cellSize,
|
|
1369
|
+
opacity
|
|
1370
|
+
}) {
|
|
1371
|
+
const boneStore = useContext(BoneRegistryContext);
|
|
1372
|
+
const meshRef = useRef(null);
|
|
1373
|
+
const [registryTick, setRegistryTick] = useState(0);
|
|
1374
|
+
useEffect(() => boneStore?.subscribe(() => setRegistryTick((t) => t + 1)), [boneStore]);
|
|
1375
|
+
useEffect(() => {
|
|
1376
|
+
const mesh = meshRef.current;
|
|
1377
|
+
if (!mesh || !boneStore) return;
|
|
1378
|
+
const bones = [];
|
|
1379
|
+
for (const name of skin.bones) {
|
|
1380
|
+
const bone = boneStore.get(name);
|
|
1381
|
+
if (!bone) return;
|
|
1382
|
+
bones.push(bone);
|
|
1383
|
+
}
|
|
1384
|
+
if (mesh.skeleton && mesh.skeleton.bones.length === bones.length && mesh.skeleton.bones.every((b, i) => b === bones[i])) return;
|
|
1385
|
+
if (skin.inverseBindMatrices.length !== bones.length) return;
|
|
1386
|
+
const inverses = skin.inverseBindMatrices.map((m) => {
|
|
1387
|
+
const mat = new THREE11.Matrix4().fromArray(m);
|
|
1388
|
+
mat.elements[12] *= cellSize;
|
|
1389
|
+
mat.elements[13] *= cellSize;
|
|
1390
|
+
mat.elements[14] *= cellSize;
|
|
1391
|
+
return mat;
|
|
1392
|
+
});
|
|
1393
|
+
mesh.bind(new THREE11.Skeleton(bones, inverses), new THREE11.Matrix4());
|
|
1394
|
+
}, [registryTick, skin, boneStore, geometry, cellSize]);
|
|
1395
|
+
useEffect(() => {
|
|
1396
|
+
const mesh = meshRef.current;
|
|
1397
|
+
return () => mesh?.skeleton?.dispose();
|
|
1398
|
+
}, []);
|
|
1399
|
+
return /* @__PURE__ */ jsx(
|
|
1400
|
+
"skinnedMesh",
|
|
1401
|
+
{
|
|
1402
|
+
ref: meshRef,
|
|
1403
|
+
geometry,
|
|
1404
|
+
frustumCulled: false,
|
|
1405
|
+
castShadow: node.castShadow ?? true,
|
|
1406
|
+
receiveShadow: node.receiveShadow ?? true,
|
|
1407
|
+
children: meshMaterial(node.material, opacity)
|
|
1408
|
+
}
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1277
1411
|
function Mesh3D({
|
|
1278
1412
|
node,
|
|
1279
1413
|
projector,
|
|
@@ -1286,6 +1420,10 @@ function Mesh3D({
|
|
|
1286
1420
|
const validPos = isValidScenePos(node.position);
|
|
1287
1421
|
const baseWorld = validPos ? projector.toWorld(node.position) : [0, 0, 0];
|
|
1288
1422
|
const geo = useMemo(() => meshGeometry(node, projector.cellSize), [node, projector.cellSize]);
|
|
1423
|
+
useEffect(() => {
|
|
1424
|
+
const g = geo?.geometry;
|
|
1425
|
+
return () => g?.dispose();
|
|
1426
|
+
}, [geo]);
|
|
1289
1427
|
useFrame(({ clock }) => {
|
|
1290
1428
|
if (!animated || !groupRef.current) return;
|
|
1291
1429
|
const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
|
|
@@ -1298,8 +1436,13 @@ function Mesh3D({
|
|
|
1298
1436
|
);
|
|
1299
1437
|
groupRef.current.scale.setScalar(state.scale);
|
|
1300
1438
|
if (meshRef.current) {
|
|
1439
|
+
const shapeRot = geo?.baseRotation ?? [0, 0, 0];
|
|
1301
1440
|
const base = node.rotation ?? [0, 0, 0];
|
|
1302
|
-
meshRef.current.rotation.set(
|
|
1441
|
+
meshRef.current.rotation.set(
|
|
1442
|
+
shapeRot[0] + base[0] + state.rotate[0],
|
|
1443
|
+
shapeRot[1] + base[1] + state.rotate[1],
|
|
1444
|
+
shapeRot[2] + base[2] + state.rotate[2]
|
|
1445
|
+
);
|
|
1303
1446
|
}
|
|
1304
1447
|
const mat = materialRef.current;
|
|
1305
1448
|
if (mat) {
|
|
@@ -1316,13 +1459,28 @@ function Mesh3D({
|
|
|
1316
1459
|
if (!validPos || !geo) return null;
|
|
1317
1460
|
const lift = (node.pivot ?? "bottom") === "bottom" ? geo.lift : 0;
|
|
1318
1461
|
const opacity = (node.opacity ?? 1) * (node.material?.opacity ?? 1) * groupOpacity;
|
|
1319
|
-
|
|
1462
|
+
if (node.skin && geo.geometry) {
|
|
1463
|
+
return /* @__PURE__ */ jsx("group", { position: baseWorld, children: /* @__PURE__ */ jsx(SkinnedPolyhedron3D, { node, skin: node.skin, geometry: geo.geometry, cellSize: projector.cellSize, opacity }) });
|
|
1464
|
+
}
|
|
1465
|
+
const nodeRotation = node.rotation ?? [0, 0, 0];
|
|
1466
|
+
const shapeRotation = geo.baseRotation ?? [0, 0, 0];
|
|
1467
|
+
const rotation = [
|
|
1468
|
+
shapeRotation[0] + nodeRotation[0],
|
|
1469
|
+
shapeRotation[1] + nodeRotation[1],
|
|
1470
|
+
shapeRotation[2] + nodeRotation[2]
|
|
1471
|
+
];
|
|
1320
1472
|
const outlineScale = geo.size > 0 ? 1 + (node.outline?.width ?? 0.05) * projector.cellSize / geo.size : 1;
|
|
1473
|
+
if (node.outline && geo.geometry && !warnedPolyhedronOutline) {
|
|
1474
|
+
warnedPolyhedronOutline = true;
|
|
1475
|
+
console.warn('[draw-mesh] outline is not yet supported on shape "polyhedron" \u2014 skipped');
|
|
1476
|
+
}
|
|
1477
|
+
const geometryProp = geo.geometry ? { geometry: geo.geometry } : {};
|
|
1321
1478
|
return /* @__PURE__ */ jsxs("group", { ref: groupRef, position: baseWorld, children: [
|
|
1322
1479
|
/* @__PURE__ */ jsxs(
|
|
1323
1480
|
"mesh",
|
|
1324
1481
|
{
|
|
1325
1482
|
ref: meshRef,
|
|
1483
|
+
...geometryProp,
|
|
1326
1484
|
position: [0, lift, 0],
|
|
1327
1485
|
rotation,
|
|
1328
1486
|
castShadow: node.castShadow ?? true,
|
|
@@ -1333,13 +1491,13 @@ function Mesh3D({
|
|
|
1333
1491
|
]
|
|
1334
1492
|
}
|
|
1335
1493
|
),
|
|
1336
|
-
node.outline && /* @__PURE__ */ jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
|
|
1494
|
+
node.outline && !geo.geometry && /* @__PURE__ */ jsxs("mesh", { position: [0, lift, 0], rotation, scale: outlineScale, children: [
|
|
1337
1495
|
geo.element,
|
|
1338
1496
|
/* @__PURE__ */ jsx(
|
|
1339
1497
|
"meshBasicMaterial",
|
|
1340
1498
|
{
|
|
1341
1499
|
color: node.outline.color ?? "#101014",
|
|
1342
|
-
side:
|
|
1500
|
+
side: THREE11.BackSide,
|
|
1343
1501
|
transparent: opacity < 1,
|
|
1344
1502
|
opacity
|
|
1345
1503
|
}
|
|
@@ -1366,14 +1524,53 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1366
1524
|
case "draw-group": {
|
|
1367
1525
|
if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
|
|
1368
1526
|
if (node.clip) warnUnsupported3d("draw-group:clip");
|
|
1369
|
-
|
|
1370
|
-
const inner = create3DProjector({ cellSize: projector.cellSize });
|
|
1371
|
-
const opacity = (node.opacity ?? 1) * groupOpacity;
|
|
1372
|
-
const s = node.scale ?? 1;
|
|
1373
|
-
return /* @__PURE__ */ jsx("group", { position: world, rotation: [0, -(node.rotate ?? 0), 0], scale: [s, s, s], children: node.items.map((item, i) => /* @__PURE__ */ jsx(Drawable3D, { node: item, projector: inner, groupOpacity: opacity }, i)) });
|
|
1527
|
+
return /* @__PURE__ */ jsx(Group3D, { node, projector, groupOpacity });
|
|
1374
1528
|
}
|
|
1375
1529
|
}
|
|
1376
1530
|
}
|
|
1531
|
+
function Group3D({
|
|
1532
|
+
node,
|
|
1533
|
+
projector,
|
|
1534
|
+
groupOpacity
|
|
1535
|
+
}) {
|
|
1536
|
+
const ref = useRef(null);
|
|
1537
|
+
const animated = isAnimatedGroup(node);
|
|
1538
|
+
const world = projector.toWorld(node.position);
|
|
1539
|
+
const inner = create3DProjector({ cellSize: projector.cellSize });
|
|
1540
|
+
const opacity = (node.opacity ?? 1) * groupOpacity;
|
|
1541
|
+
const s = node.scale ?? 1;
|
|
1542
|
+
const baseRotation = node.rotation ?? [0, -(node.rotate ?? 0), 0];
|
|
1543
|
+
const parentStore = useContext(BoneRegistryContext);
|
|
1544
|
+
const scopedStore = useMemo(() => node.skeleton ? new BoneStore() : null, [node.skeleton]);
|
|
1545
|
+
const boneStore = scopedStore ?? parentStore;
|
|
1546
|
+
const boneObject = useMemo(() => node.bone ? new THREE11.Bone() : null, [node.bone]);
|
|
1547
|
+
useEffect(() => {
|
|
1548
|
+
if (!node.bone || !boneStore || !boneObject) return;
|
|
1549
|
+
return boneStore.register(node.bone, boneObject);
|
|
1550
|
+
}, [node.bone, boneStore, boneObject]);
|
|
1551
|
+
useFrame(({ clock }) => {
|
|
1552
|
+
if (!animated || !ref.current) return;
|
|
1553
|
+
const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
|
|
1554
|
+
if (!state) return;
|
|
1555
|
+
const cell = projector.cellSize;
|
|
1556
|
+
ref.current.position.set(
|
|
1557
|
+
world[0] + state.offset[0] * cell,
|
|
1558
|
+
world[1] + state.offset[2] * cell,
|
|
1559
|
+
world[2] + state.offset[1] * cell
|
|
1560
|
+
);
|
|
1561
|
+
ref.current.rotation.set(
|
|
1562
|
+
baseRotation[0] + state.rotate[0],
|
|
1563
|
+
baseRotation[1] + state.rotate[1],
|
|
1564
|
+
baseRotation[2] + state.rotate[2]
|
|
1565
|
+
);
|
|
1566
|
+
ref.current.scale.setScalar(s * state.scale);
|
|
1567
|
+
});
|
|
1568
|
+
const children = /* @__PURE__ */ jsxs("group", { ref, position: world, rotation: baseRotation, scale: [s, s, s], children: [
|
|
1569
|
+
boneObject && /* @__PURE__ */ jsx("primitive", { object: boneObject }),
|
|
1570
|
+
node.items.map((item, i) => /* @__PURE__ */ jsx(Drawable3D, { node: item, projector: inner, groupOpacity: opacity }, i))
|
|
1571
|
+
] });
|
|
1572
|
+
return scopedStore ? /* @__PURE__ */ jsx(BoneRegistryContext.Provider, { value: scopedStore, children }) : children;
|
|
1573
|
+
}
|
|
1377
1574
|
|
|
1378
1575
|
// lib/drawable/three/game3dTheme.ts
|
|
1379
1576
|
var GRID_COLORS_3D = {
|
|
@@ -1389,7 +1586,7 @@ var DEFAULT_GRID_CONFIG = {
|
|
|
1389
1586
|
function RoomEnvironment3D() {
|
|
1390
1587
|
const { gl, scene } = useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
|
|
1391
1588
|
useEffect(() => {
|
|
1392
|
-
const pmremGenerator = new
|
|
1589
|
+
const pmremGenerator = new THREE11.PMREMGenerator(gl);
|
|
1393
1590
|
const envTexture = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
|
|
1394
1591
|
scene.environment = envTexture;
|
|
1395
1592
|
return () => {
|
|
@@ -1505,6 +1702,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1505
1702
|
}),
|
|
1506
1703
|
[gridBounds, cellSize]
|
|
1507
1704
|
);
|
|
1705
|
+
const boneStore = useMemo(() => new BoneStore(), []);
|
|
1508
1706
|
const drawableProjector = useMemo(
|
|
1509
1707
|
() => create3DProjector({
|
|
1510
1708
|
cellSize: gridConfig.cellSize,
|
|
@@ -1517,7 +1715,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1517
1715
|
getCameraPosition: () => {
|
|
1518
1716
|
if (controlsRef.current) {
|
|
1519
1717
|
const pos = controlsRef.current.object.position;
|
|
1520
|
-
return new
|
|
1718
|
+
return new THREE11.Vector3(pos.x, pos.y, pos.z);
|
|
1521
1719
|
}
|
|
1522
1720
|
return null;
|
|
1523
1721
|
},
|
|
@@ -1562,6 +1760,8 @@ var Canvas3DHost = forwardRef(
|
|
|
1562
1760
|
return { position: [cx + d, d * 0.8, cz + d], fov: fovDeg };
|
|
1563
1761
|
case "top-down":
|
|
1564
1762
|
return { position: [cx, d * 2, cz + d * 0.35], fov: fovDeg };
|
|
1763
|
+
case "front":
|
|
1764
|
+
return { position: [cx, d * 0.32, cz + d * 1.15], fov: fovDeg };
|
|
1565
1765
|
case "follow":
|
|
1566
1766
|
return { position: [cx, d * 0.5, cz + d], fov: fovDeg };
|
|
1567
1767
|
case "perspective":
|
|
@@ -1628,6 +1828,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1628
1828
|
Canvas,
|
|
1629
1829
|
{
|
|
1630
1830
|
shadows,
|
|
1831
|
+
flat: lighting?.toneMapping === "none",
|
|
1631
1832
|
camera: {
|
|
1632
1833
|
position: cameraConfig.position,
|
|
1633
1834
|
fov: cameraConfig.fov,
|
|
@@ -1686,7 +1887,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1686
1887
|
fadeStrength: 1
|
|
1687
1888
|
}
|
|
1688
1889
|
),
|
|
1689
|
-
allDrawables.length > 0 && /* @__PURE__ */ jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
|
|
1890
|
+
allDrawables.length > 0 && /* @__PURE__ */ jsx(BoneRegistryContext.Provider, { value: boneStore, children: /* @__PURE__ */ jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsx(Drawable3D, { node, projector: drawableProjector }, i)) }) }),
|
|
1690
1891
|
(tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxs(
|
|
1691
1892
|
"mesh",
|
|
1692
1893
|
{
|
|
@@ -1722,7 +1923,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1722
1923
|
dampingFactor: 0.05,
|
|
1723
1924
|
enableZoom: true,
|
|
1724
1925
|
enablePan: true,
|
|
1725
|
-
touches: { ONE:
|
|
1926
|
+
touches: { ONE: THREE11.TOUCH.ROTATE, TWO: THREE11.TOUCH.DOLLY_PAN },
|
|
1726
1927
|
minDistance: 2,
|
|
1727
1928
|
maxDistance: 100,
|
|
1728
1929
|
maxPolarAngle: Math.PI / 2 - 0.1
|
|
@@ -1745,15 +1946,15 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
|
1745
1946
|
if (initializedRef.current) return;
|
|
1746
1947
|
initializedRef.current = true;
|
|
1747
1948
|
if (background.startsWith("#") || background.startsWith("rgb")) {
|
|
1748
|
-
scene.background = new
|
|
1949
|
+
scene.background = new THREE11.Color(background);
|
|
1749
1950
|
} else {
|
|
1750
|
-
const loader = new
|
|
1951
|
+
const loader = new THREE11.TextureLoader();
|
|
1751
1952
|
loader.load(background, (texture) => {
|
|
1752
1953
|
scene.background = texture;
|
|
1753
1954
|
});
|
|
1754
1955
|
}
|
|
1755
1956
|
if (fog) {
|
|
1756
|
-
scene.fog = new
|
|
1957
|
+
scene.fog = new THREE11.Fog(fog.color, fog.near, fog.far);
|
|
1757
1958
|
}
|
|
1758
1959
|
return () => {
|
|
1759
1960
|
scene.background = null;
|
|
@@ -1776,14 +1977,14 @@ var Camera3D = forwardRef(
|
|
|
1776
1977
|
}, ref) => {
|
|
1777
1978
|
const { camera, set, viewport } = useThree();
|
|
1778
1979
|
const controlsRef = useRef(null);
|
|
1779
|
-
const initialPosition = useRef(new
|
|
1780
|
-
const initialTarget = useRef(new
|
|
1980
|
+
const initialPosition = useRef(new THREE11.Vector3(...position));
|
|
1981
|
+
const initialTarget = useRef(new THREE11.Vector3(...target));
|
|
1781
1982
|
useEffect(() => {
|
|
1782
1983
|
let newCamera;
|
|
1783
1984
|
if (mode === "isometric") {
|
|
1784
1985
|
const aspect = viewport.aspect;
|
|
1785
1986
|
const size = 10 / zoom;
|
|
1786
|
-
newCamera = new
|
|
1987
|
+
newCamera = new THREE11.OrthographicCamera(
|
|
1787
1988
|
-size * aspect,
|
|
1788
1989
|
size * aspect,
|
|
1789
1990
|
size,
|
|
@@ -1792,7 +1993,7 @@ var Camera3D = forwardRef(
|
|
|
1792
1993
|
1e3
|
|
1793
1994
|
);
|
|
1794
1995
|
} else {
|
|
1795
|
-
newCamera = new
|
|
1996
|
+
newCamera = new THREE11.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
|
|
1796
1997
|
}
|
|
1797
1998
|
newCamera.position.copy(initialPosition.current);
|
|
1798
1999
|
newCamera.lookAt(initialTarget.current.x, initialTarget.current.y, initialTarget.current.z);
|
|
@@ -1833,8 +2034,8 @@ var Camera3D = forwardRef(
|
|
|
1833
2034
|
}
|
|
1834
2035
|
},
|
|
1835
2036
|
getViewBounds: () => {
|
|
1836
|
-
const min = new
|
|
1837
|
-
const max = new
|
|
2037
|
+
const min = new THREE11.Vector3(-10, -10, -10);
|
|
2038
|
+
const max = new THREE11.Vector3(10, 10, 10);
|
|
1838
2039
|
return { min, max };
|
|
1839
2040
|
}
|
|
1840
2041
|
}));
|
|
@@ -1876,7 +2077,7 @@ var AssetLoader = class {
|
|
|
1876
2077
|
__publicField(this, "textureCache");
|
|
1877
2078
|
__publicField(this, "loadingPromises");
|
|
1878
2079
|
this.objLoader = new OBJLoader();
|
|
1879
|
-
this.textureLoader = new
|
|
2080
|
+
this.textureLoader = new THREE11.TextureLoader();
|
|
1880
2081
|
this.modelCache = /* @__PURE__ */ new Map();
|
|
1881
2082
|
this.textureCache = /* @__PURE__ */ new Map();
|
|
1882
2083
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
@@ -1950,7 +2151,7 @@ var AssetLoader = class {
|
|
|
1950
2151
|
return this.loadingPromises.get(`texture:${url}`);
|
|
1951
2152
|
}
|
|
1952
2153
|
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
1953
|
-
texture.colorSpace =
|
|
2154
|
+
texture.colorSpace = THREE11.SRGBColorSpace;
|
|
1954
2155
|
this.textureCache.set(url, texture);
|
|
1955
2156
|
this.loadingPromises.delete(`texture:${url}`);
|
|
1956
2157
|
return texture;
|
|
@@ -2024,7 +2225,7 @@ var AssetLoader = class {
|
|
|
2024
2225
|
});
|
|
2025
2226
|
this.modelCache.forEach((model) => {
|
|
2026
2227
|
model.scene.traverse((child) => {
|
|
2027
|
-
if (child instanceof
|
|
2228
|
+
if (child instanceof THREE11.Mesh) {
|
|
2028
2229
|
child.geometry.dispose();
|
|
2029
2230
|
if (Array.isArray(child.material)) {
|
|
2030
2231
|
child.material.forEach((m) => m.dispose());
|
|
@@ -2074,21 +2275,21 @@ function useThree5(options = {}) {
|
|
|
2074
2275
|
const [isReady, setIsReady] = useState(false);
|
|
2075
2276
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
|
2076
2277
|
const initialCameraPosition = useMemo(
|
|
2077
|
-
() => new
|
|
2278
|
+
() => new THREE11.Vector3(...opts.cameraPosition),
|
|
2078
2279
|
[]
|
|
2079
2280
|
);
|
|
2080
2281
|
useEffect(() => {
|
|
2081
2282
|
if (!containerRef.current) return;
|
|
2082
2283
|
const container = containerRef.current;
|
|
2083
2284
|
const { clientWidth, clientHeight } = container;
|
|
2084
|
-
const scene = new
|
|
2085
|
-
scene.background = new
|
|
2285
|
+
const scene = new THREE11.Scene();
|
|
2286
|
+
scene.background = new THREE11.Color(opts.backgroundColor);
|
|
2086
2287
|
sceneRef.current = scene;
|
|
2087
2288
|
let camera;
|
|
2088
2289
|
const aspect = clientWidth / clientHeight;
|
|
2089
2290
|
if (opts.cameraMode === "isometric") {
|
|
2090
2291
|
const size = 10;
|
|
2091
|
-
camera = new
|
|
2292
|
+
camera = new THREE11.OrthographicCamera(
|
|
2092
2293
|
-size * aspect,
|
|
2093
2294
|
size * aspect,
|
|
2094
2295
|
size,
|
|
@@ -2097,11 +2298,11 @@ function useThree5(options = {}) {
|
|
|
2097
2298
|
1e3
|
|
2098
2299
|
);
|
|
2099
2300
|
} else {
|
|
2100
|
-
camera = new
|
|
2301
|
+
camera = new THREE11.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
2101
2302
|
}
|
|
2102
2303
|
camera.position.copy(initialCameraPosition);
|
|
2103
2304
|
cameraRef.current = camera;
|
|
2104
|
-
const renderer = new
|
|
2305
|
+
const renderer = new THREE11.WebGLRenderer({
|
|
2105
2306
|
antialias: true,
|
|
2106
2307
|
alpha: true,
|
|
2107
2308
|
canvas: canvasRef.current || void 0
|
|
@@ -2109,7 +2310,7 @@ function useThree5(options = {}) {
|
|
|
2109
2310
|
renderer.setSize(clientWidth, clientHeight);
|
|
2110
2311
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
2111
2312
|
renderer.shadowMap.enabled = opts.shadows;
|
|
2112
|
-
renderer.shadowMap.type =
|
|
2313
|
+
renderer.shadowMap.type = THREE11.PCFSoftShadowMap;
|
|
2113
2314
|
rendererRef.current = renderer;
|
|
2114
2315
|
const controls = new OrbitControls$1(camera, renderer.domElement);
|
|
2115
2316
|
controls.enableDamping = true;
|
|
@@ -2118,16 +2319,16 @@ function useThree5(options = {}) {
|
|
|
2118
2319
|
controls.maxDistance = 100;
|
|
2119
2320
|
controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
2120
2321
|
controlsRef.current = controls;
|
|
2121
|
-
const ambientLight = new
|
|
2322
|
+
const ambientLight = new THREE11.AmbientLight(16777215, 0.6);
|
|
2122
2323
|
scene.add(ambientLight);
|
|
2123
|
-
const directionalLight = new
|
|
2324
|
+
const directionalLight = new THREE11.DirectionalLight(16777215, 0.8);
|
|
2124
2325
|
directionalLight.position.set(10, 20, 10);
|
|
2125
2326
|
directionalLight.castShadow = opts.shadows;
|
|
2126
2327
|
directionalLight.shadow.mapSize.width = 2048;
|
|
2127
2328
|
directionalLight.shadow.mapSize.height = 2048;
|
|
2128
2329
|
scene.add(directionalLight);
|
|
2129
2330
|
if (opts.showGrid) {
|
|
2130
|
-
const gridHelper = new
|
|
2331
|
+
const gridHelper = new THREE11.GridHelper(
|
|
2131
2332
|
opts.gridSize,
|
|
2132
2333
|
opts.gridSize,
|
|
2133
2334
|
4473924,
|
|
@@ -2145,10 +2346,10 @@ function useThree5(options = {}) {
|
|
|
2145
2346
|
const handleResize = () => {
|
|
2146
2347
|
const { clientWidth: width, clientHeight: height } = container;
|
|
2147
2348
|
setDimensions({ width, height });
|
|
2148
|
-
if (camera instanceof
|
|
2349
|
+
if (camera instanceof THREE11.PerspectiveCamera) {
|
|
2149
2350
|
camera.aspect = width / height;
|
|
2150
2351
|
camera.updateProjectionMatrix();
|
|
2151
|
-
} else if (camera instanceof
|
|
2352
|
+
} else if (camera instanceof THREE11.OrthographicCamera) {
|
|
2152
2353
|
const aspect2 = width / height;
|
|
2153
2354
|
const size = 10;
|
|
2154
2355
|
camera.left = -size * aspect2;
|
|
@@ -2179,7 +2380,7 @@ function useThree5(options = {}) {
|
|
|
2179
2380
|
let newCamera;
|
|
2180
2381
|
if (opts.cameraMode === "isometric") {
|
|
2181
2382
|
const size = 10;
|
|
2182
|
-
newCamera = new
|
|
2383
|
+
newCamera = new THREE11.OrthographicCamera(
|
|
2183
2384
|
-size * aspect,
|
|
2184
2385
|
size * aspect,
|
|
2185
2386
|
size,
|
|
@@ -2188,7 +2389,7 @@ function useThree5(options = {}) {
|
|
|
2188
2389
|
1e3
|
|
2189
2390
|
);
|
|
2190
2391
|
} else {
|
|
2191
|
-
newCamera = new
|
|
2392
|
+
newCamera = new THREE11.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
2192
2393
|
}
|
|
2193
2394
|
newCamera.position.copy(currentPos);
|
|
2194
2395
|
cameraRef.current = newCamera;
|
|
@@ -2518,8 +2719,8 @@ function useSceneGraph() {
|
|
|
2518
2719
|
}
|
|
2519
2720
|
function useRaycaster(options) {
|
|
2520
2721
|
const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
|
|
2521
|
-
const raycaster = useRef(new
|
|
2522
|
-
const mouse = useRef(new
|
|
2722
|
+
const raycaster = useRef(new THREE11.Raycaster());
|
|
2723
|
+
const mouse = useRef(new THREE11.Vector2());
|
|
2523
2724
|
const clientToNDC = useCallback(
|
|
2524
2725
|
(clientX, clientY) => {
|
|
2525
2726
|
if (!canvas) {
|
|
@@ -2589,8 +2790,8 @@ function useRaycaster(options) {
|
|
|
2589
2790
|
const ndc = clientToNDC(clientX, clientY);
|
|
2590
2791
|
mouse.current.set(ndc.x, ndc.y);
|
|
2591
2792
|
raycaster.current.setFromCamera(mouse.current, camera);
|
|
2592
|
-
const plane = new
|
|
2593
|
-
const target = new
|
|
2793
|
+
const plane = new THREE11.Plane(new THREE11.Vector3(0, 1, 0), 0);
|
|
2794
|
+
const target = new THREE11.Vector3();
|
|
2594
2795
|
const intersection = raycaster.current.ray.intersectPlane(plane, target);
|
|
2595
2796
|
if (intersection) {
|
|
2596
2797
|
const gridX = Math.round((target.x - offsetX) / cellSize);
|
|
@@ -2628,7 +2829,7 @@ function useRaycaster(options) {
|
|
|
2628
2829
|
return {
|
|
2629
2830
|
gridX: gridCoords.x,
|
|
2630
2831
|
gridZ: gridCoords.z,
|
|
2631
|
-
worldPosition: new
|
|
2832
|
+
worldPosition: new THREE11.Vector3(
|
|
2632
2833
|
gridCoords.x * cellSize + offsetX,
|
|
2633
2834
|
0,
|
|
2634
2835
|
gridCoords.z * cellSize + offsetZ
|
|
@@ -2658,7 +2859,7 @@ var DEFAULT_CONFIG = {
|
|
|
2658
2859
|
};
|
|
2659
2860
|
function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
|
|
2660
2861
|
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
2661
|
-
return new
|
|
2862
|
+
return new THREE11.Vector3(
|
|
2662
2863
|
gridX * opts.cellSize + opts.offsetX,
|
|
2663
2864
|
opts.elevation,
|
|
2664
2865
|
gridZ * opts.cellSize + opts.offsetZ
|
|
@@ -2672,17 +2873,17 @@ function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
|
|
|
2672
2873
|
};
|
|
2673
2874
|
}
|
|
2674
2875
|
function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
|
|
2675
|
-
const raycaster = new
|
|
2676
|
-
const mouse = new
|
|
2876
|
+
const raycaster = new THREE11.Raycaster();
|
|
2877
|
+
const mouse = new THREE11.Vector2(mouseX, mouseY);
|
|
2677
2878
|
raycaster.setFromCamera(mouse, camera);
|
|
2678
|
-
const plane = new
|
|
2679
|
-
const target = new
|
|
2879
|
+
const plane = new THREE11.Plane(new THREE11.Vector3(0, 1, 0), -planeY);
|
|
2880
|
+
const target = new THREE11.Vector3();
|
|
2680
2881
|
const intersection = raycaster.ray.intersectPlane(plane, target);
|
|
2681
2882
|
return intersection ? target : null;
|
|
2682
2883
|
}
|
|
2683
2884
|
function raycastToObjects(camera, mouseX, mouseY, objects) {
|
|
2684
|
-
const raycaster = new
|
|
2685
|
-
const mouse = new
|
|
2885
|
+
const raycaster = new THREE11.Raycaster();
|
|
2886
|
+
const mouse = new THREE11.Vector2(mouseX, mouseY);
|
|
2686
2887
|
raycaster.setFromCamera(mouse, camera);
|
|
2687
2888
|
const intersects = raycaster.intersectObjects(objects, true);
|
|
2688
2889
|
return intersects.length > 0 ? intersects[0] : null;
|
|
@@ -2734,14 +2935,14 @@ function getCellsInRadius(centerX, centerZ, radius) {
|
|
|
2734
2935
|
return cells;
|
|
2735
2936
|
}
|
|
2736
2937
|
function createGridHighlight(color = 16776960, opacity = 0.3) {
|
|
2737
|
-
const geometry = new
|
|
2738
|
-
const material = new
|
|
2938
|
+
const geometry = new THREE11.PlaneGeometry(0.95, 0.95);
|
|
2939
|
+
const material = new THREE11.MeshBasicMaterial({
|
|
2739
2940
|
color,
|
|
2740
2941
|
transparent: true,
|
|
2741
2942
|
opacity,
|
|
2742
|
-
side:
|
|
2943
|
+
side: THREE11.DoubleSide
|
|
2743
2944
|
});
|
|
2744
|
-
const mesh = new
|
|
2945
|
+
const mesh = new THREE11.Mesh(geometry, material);
|
|
2745
2946
|
mesh.rotation.x = -Math.PI / 2;
|
|
2746
2947
|
mesh.position.y = 0.01;
|
|
2747
2948
|
return mesh;
|
|
@@ -2754,31 +2955,31 @@ function normalizeMouseCoordinates(clientX, clientY, element) {
|
|
|
2754
2955
|
};
|
|
2755
2956
|
}
|
|
2756
2957
|
function isInFrustum(position, camera, padding = 0) {
|
|
2757
|
-
const frustum = new
|
|
2758
|
-
const projScreenMatrix = new
|
|
2958
|
+
const frustum = new THREE11.Frustum();
|
|
2959
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2759
2960
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2760
2961
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2761
|
-
const sphere = new
|
|
2962
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2762
2963
|
return frustum.intersectsSphere(sphere);
|
|
2763
2964
|
}
|
|
2764
2965
|
function filterByFrustum(positions, camera, padding = 0) {
|
|
2765
|
-
const frustum = new
|
|
2766
|
-
const projScreenMatrix = new
|
|
2966
|
+
const frustum = new THREE11.Frustum();
|
|
2967
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2767
2968
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2768
2969
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2769
2970
|
return positions.filter((position) => {
|
|
2770
|
-
const sphere = new
|
|
2971
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2771
2972
|
return frustum.intersectsSphere(sphere);
|
|
2772
2973
|
});
|
|
2773
2974
|
}
|
|
2774
2975
|
function getVisibleIndices(positions, camera, padding = 0) {
|
|
2775
|
-
const frustum = new
|
|
2776
|
-
const projScreenMatrix = new
|
|
2976
|
+
const frustum = new THREE11.Frustum();
|
|
2977
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2777
2978
|
const visible = /* @__PURE__ */ new Set();
|
|
2778
2979
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2779
2980
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2780
2981
|
positions.forEach((position, index) => {
|
|
2781
|
-
const sphere = new
|
|
2982
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2782
2983
|
if (frustum.intersectsSphere(sphere)) {
|
|
2783
2984
|
visible.add(index);
|
|
2784
2985
|
}
|
|
@@ -2802,7 +3003,7 @@ function updateInstanceLOD(instancedMesh, positions, camera, lodDistances) {
|
|
|
2802
3003
|
return lodIndices;
|
|
2803
3004
|
}
|
|
2804
3005
|
function cullInstancedMesh(instancedMesh, positions, visibleIndices) {
|
|
2805
|
-
const dummy = new
|
|
3006
|
+
const dummy = new THREE11.Object3D();
|
|
2806
3007
|
let visibleCount = 0;
|
|
2807
3008
|
positions.forEach((position, index) => {
|
|
2808
3009
|
if (visibleIndices.has(index)) {
|
|
@@ -5585,12 +5786,12 @@ function useAvl3DConfig() {
|
|
|
5585
5786
|
}
|
|
5586
5787
|
function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
5587
5788
|
const { camera } = useThree();
|
|
5588
|
-
const targetPosVec = useRef(new
|
|
5589
|
-
const targetLookVec = useRef(new
|
|
5789
|
+
const targetPosVec = useRef(new THREE11.Vector3(...targetPosition));
|
|
5790
|
+
const targetLookVec = useRef(new THREE11.Vector3(...targetLookAt));
|
|
5590
5791
|
const isAnimating = useRef(false);
|
|
5591
5792
|
useEffect(() => {
|
|
5592
|
-
const newTarget = new
|
|
5593
|
-
const newLookAt = new
|
|
5793
|
+
const newTarget = new THREE11.Vector3(...targetPosition);
|
|
5794
|
+
const newLookAt = new THREE11.Vector3(...targetLookAt);
|
|
5594
5795
|
if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
|
|
5595
5796
|
targetPosVec.current.copy(newTarget);
|
|
5596
5797
|
targetLookVec.current.copy(newLookAt);
|
|
@@ -5605,9 +5806,9 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
|
5605
5806
|
useFrame((_, delta) => {
|
|
5606
5807
|
if (!isAnimating.current) return;
|
|
5607
5808
|
const speed = 3;
|
|
5608
|
-
camera.position.x =
|
|
5609
|
-
camera.position.y =
|
|
5610
|
-
camera.position.z =
|
|
5809
|
+
camera.position.x = THREE11.MathUtils.damp(camera.position.x, targetPosVec.current.x, speed, delta);
|
|
5810
|
+
camera.position.y = THREE11.MathUtils.damp(camera.position.y, targetPosVec.current.y, speed, delta);
|
|
5811
|
+
camera.position.z = THREE11.MathUtils.damp(camera.position.z, targetPosVec.current.z, speed, delta);
|
|
5611
5812
|
camera.lookAt(targetLookVec.current);
|
|
5612
5813
|
const dist = camera.position.distanceTo(targetPosVec.current);
|
|
5613
5814
|
if (dist < 0.05) {
|
|
@@ -5622,7 +5823,7 @@ function SceneFade({ animating, children }) {
|
|
|
5622
5823
|
useFrame((_, delta) => {
|
|
5623
5824
|
if (!groupRef.current) return;
|
|
5624
5825
|
const target = animating ? 0 : 1;
|
|
5625
|
-
opacityRef.current =
|
|
5826
|
+
opacityRef.current = THREE11.MathUtils.damp(opacityRef.current, target, 5, delta);
|
|
5626
5827
|
groupRef.current.visible = opacityRef.current > 0.05;
|
|
5627
5828
|
const s = 0.9 + opacityRef.current * 0.1;
|
|
5628
5829
|
groupRef.current.scale.setScalar(s);
|