@almadar/ui 5.141.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 +1326 -1240
- package/dist/avl/index.js +355 -269
- package/dist/{avl-schema-parser-B8Onmfsu.d.cts → avl-schema-parser-0hkiHOq3.d.ts} +233 -2
- package/dist/{avl-schema-parser-B8Onmfsu.d.ts → avl-schema-parser-BZ8pICOS.d.cts} +233 -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 +1310 -1224
- package/dist/components/index.d.cts +13 -6
- package/dist/components/index.d.ts +13 -6
- package/dist/components/index.js +346 -260
- package/dist/lib/drawable/three/index.cjs +560 -194
- package/dist/lib/drawable/three/index.d.cts +14 -173
- package/dist/lib/drawable/three/index.d.ts +14 -173
- package/dist/lib/drawable/three/index.js +536 -170
- 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 +1209 -1123
- package/dist/providers/index.js +330 -244
- package/dist/runtime/index.cjs +1187 -1101
- package/dist/runtime/index.js +335 -249
- package/package.json +8 -8
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import React3, { forwardRef, useRef, useState,
|
|
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
|
+
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
|
|
7
8
|
import { Grid, OrbitControls, Billboard, Text, Stars, Sparkles, Html, RoundedBox } from '@react-three/drei';
|
|
8
9
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
import { Bloom, Vignette, EffectComposer, DepthOfField } from '@react-three/postprocessing';
|
|
9
11
|
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
10
12
|
import { clone } from 'three/examples/jsm/utils/SkeletonUtils';
|
|
11
13
|
import { clsx } from 'clsx';
|
|
@@ -13,7 +15,6 @@ import { twMerge } from 'tailwind-merge';
|
|
|
13
15
|
import { OrbitControls as OrbitControls$1 } from 'three/examples/jsm/controls/OrbitControls.js';
|
|
14
16
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
15
17
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
16
|
-
import { EffectComposer, Bloom, DepthOfField, Vignette } from '@react-three/postprocessing';
|
|
17
18
|
import { useTranslate } from '@almadar/ui/hooks';
|
|
18
19
|
|
|
19
20
|
var __defProp = Object.defineProperty;
|
|
@@ -450,6 +451,10 @@ function Lighting3D({
|
|
|
450
451
|
directionalIntensity = 0.8,
|
|
451
452
|
directionalColor = "#ffffff",
|
|
452
453
|
directionalPosition = [10, 20, 10],
|
|
454
|
+
hemisphereIntensity = 0.3,
|
|
455
|
+
hemisphereColor = "#87ceeb",
|
|
456
|
+
hemisphereGroundColor = "#362d1d",
|
|
457
|
+
points,
|
|
453
458
|
shadows = true,
|
|
454
459
|
shadowMapSize = 2048,
|
|
455
460
|
shadowCameraSize = 20,
|
|
@@ -482,22 +487,63 @@ function Lighting3D({
|
|
|
482
487
|
/* @__PURE__ */ jsx(
|
|
483
488
|
"hemisphereLight",
|
|
484
489
|
{
|
|
485
|
-
intensity:
|
|
486
|
-
color:
|
|
487
|
-
groundColor:
|
|
490
|
+
intensity: hemisphereIntensity,
|
|
491
|
+
color: hemisphereColor,
|
|
492
|
+
groundColor: hemisphereGroundColor
|
|
488
493
|
}
|
|
489
494
|
),
|
|
495
|
+
points?.map((p, i) => /* @__PURE__ */ jsx(
|
|
496
|
+
"pointLight",
|
|
497
|
+
{
|
|
498
|
+
position: p.position,
|
|
499
|
+
intensity: p.intensity,
|
|
500
|
+
color: p.color,
|
|
501
|
+
distance: p.distance,
|
|
502
|
+
decay: p.decay
|
|
503
|
+
},
|
|
504
|
+
i
|
|
505
|
+
)),
|
|
490
506
|
showHelpers && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
491
507
|
"directionalLightHelper",
|
|
492
508
|
{
|
|
493
509
|
args: [
|
|
494
|
-
new
|
|
510
|
+
new THREE11.DirectionalLight(directionalColor, directionalIntensity),
|
|
495
511
|
5
|
|
496
512
|
]
|
|
497
513
|
}
|
|
498
514
|
) })
|
|
499
515
|
] });
|
|
500
516
|
}
|
|
517
|
+
function Effects3D({ post }) {
|
|
518
|
+
if (!post || !post.bloom && !post.vignette) return null;
|
|
519
|
+
const passes = [];
|
|
520
|
+
if (post.bloom) {
|
|
521
|
+
passes.push(
|
|
522
|
+
/* @__PURE__ */ jsx(
|
|
523
|
+
Bloom,
|
|
524
|
+
{
|
|
525
|
+
intensity: post.bloom.intensity ?? 1,
|
|
526
|
+
luminanceThreshold: post.bloom.threshold ?? 0.9,
|
|
527
|
+
luminanceSmoothing: post.bloom.smoothing ?? 0.3
|
|
528
|
+
},
|
|
529
|
+
"bloom"
|
|
530
|
+
)
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
if (post.vignette) {
|
|
534
|
+
passes.push(
|
|
535
|
+
/* @__PURE__ */ jsx(
|
|
536
|
+
Vignette,
|
|
537
|
+
{
|
|
538
|
+
offset: post.vignette.offset ?? 0.3,
|
|
539
|
+
darkness: post.vignette.darkness ?? 0.6
|
|
540
|
+
},
|
|
541
|
+
"vignette"
|
|
542
|
+
)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
return /* @__PURE__ */ jsx(EffectComposer, { children: passes });
|
|
546
|
+
}
|
|
501
547
|
function CameraController3D({
|
|
502
548
|
onCameraChange
|
|
503
549
|
}) {
|
|
@@ -518,8 +564,8 @@ function FollowCamera3D({
|
|
|
518
564
|
offset
|
|
519
565
|
}) {
|
|
520
566
|
const { camera } = useThree();
|
|
521
|
-
const look = useRef(new
|
|
522
|
-
const goal = useRef(new
|
|
567
|
+
const look = useRef(new THREE11.Vector3(target[0], target[1], target[2]));
|
|
568
|
+
const goal = useRef(new THREE11.Vector3());
|
|
523
569
|
useFrame((_, delta) => {
|
|
524
570
|
const t = Math.min(1, delta * 5);
|
|
525
571
|
goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
|
|
@@ -540,6 +586,179 @@ function create3DProjector(opts = {}) {
|
|
|
540
586
|
toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
|
|
541
587
|
};
|
|
542
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;
|
|
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 = [
|
|
692
|
+
"offsetX",
|
|
693
|
+
"offsetY",
|
|
694
|
+
"rotate",
|
|
695
|
+
"opacity",
|
|
696
|
+
"radiusX",
|
|
697
|
+
"radiusY",
|
|
698
|
+
"width",
|
|
699
|
+
"height",
|
|
700
|
+
"strokeWidth",
|
|
701
|
+
"strokeDashOffset",
|
|
702
|
+
"blur"
|
|
703
|
+
];
|
|
704
|
+
function isAnimatedShape(node) {
|
|
705
|
+
return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
|
|
706
|
+
}
|
|
707
|
+
var lerp2 = (a, b, k) => a + (b - a) * k;
|
|
708
|
+
function applyShapeAnimation(node, timeMs) {
|
|
709
|
+
const anim = node.animation;
|
|
710
|
+
if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
|
|
711
|
+
const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
|
|
712
|
+
const cycle = timeMs / anim.durationMs;
|
|
713
|
+
const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
|
|
714
|
+
const out = { ...node };
|
|
715
|
+
const trackValue = (key) => {
|
|
716
|
+
const defined = frames.filter((f) => f[key] !== void 0);
|
|
717
|
+
if (defined.length === 0) return void 0;
|
|
718
|
+
let prev;
|
|
719
|
+
let next;
|
|
720
|
+
for (const f of defined) {
|
|
721
|
+
if (f.at <= t) prev = f;
|
|
722
|
+
else if (!next) next = f;
|
|
723
|
+
}
|
|
724
|
+
if (!prev) return defined[0][key];
|
|
725
|
+
if (!next) return prev[key];
|
|
726
|
+
const span = next.at - prev.at;
|
|
727
|
+
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
728
|
+
const a = prev[key];
|
|
729
|
+
const b = next[key];
|
|
730
|
+
if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
|
|
731
|
+
return a;
|
|
732
|
+
};
|
|
733
|
+
for (const key of NUMERIC_TRACKS2) {
|
|
734
|
+
const v = trackValue(key);
|
|
735
|
+
if (v !== void 0) out[key] = v;
|
|
736
|
+
}
|
|
737
|
+
const fill = trackValue("fill");
|
|
738
|
+
if (fill !== void 0) out.fill = fill;
|
|
739
|
+
const stroke = trackValue("stroke");
|
|
740
|
+
if (stroke !== void 0) out.stroke = stroke;
|
|
741
|
+
const shadowFrames = frames.filter((f) => f.shadow !== void 0);
|
|
742
|
+
if (shadowFrames.length > 0) {
|
|
743
|
+
const sh = trackValue("shadow");
|
|
744
|
+
if (sh !== void 0) {
|
|
745
|
+
let prevSh;
|
|
746
|
+
let nextSh;
|
|
747
|
+
for (const f of shadowFrames) {
|
|
748
|
+
if (f.at <= t) prevSh = f;
|
|
749
|
+
else if (!nextSh) nextSh = f;
|
|
750
|
+
}
|
|
751
|
+
if (prevSh?.shadow && nextSh?.shadow) {
|
|
752
|
+
const span = nextSh.at - prevSh.at;
|
|
753
|
+
const k = span > 0 ? (t - prevSh.at) / span : 1;
|
|
754
|
+
out.shadow = { color: prevSh.shadow.color, blur: lerp2(prevSh.shadow.blur, nextSh.shadow.blur, k) };
|
|
755
|
+
} else {
|
|
756
|
+
out.shadow = sh;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return out;
|
|
761
|
+
}
|
|
543
762
|
|
|
544
763
|
// lib/atlasSlice.ts
|
|
545
764
|
var atlasCache = /* @__PURE__ */ new Map();
|
|
@@ -675,12 +894,12 @@ function ModelLoader({
|
|
|
675
894
|
if (!loadedModel) return null;
|
|
676
895
|
const cloned = clone(loadedModel);
|
|
677
896
|
cloned.updateMatrixWorld(true);
|
|
678
|
-
const tintColor = tint ? new
|
|
897
|
+
const tintColor = tint ? new THREE11.Color(tint) : null;
|
|
679
898
|
cloned.traverse((child) => {
|
|
680
|
-
if (child instanceof
|
|
899
|
+
if (child instanceof THREE11.Mesh) {
|
|
681
900
|
child.castShadow = castShadow;
|
|
682
901
|
child.receiveShadow = receiveShadow;
|
|
683
|
-
if (tintColor && child.material instanceof
|
|
902
|
+
if (tintColor && child.material instanceof THREE11.MeshStandardMaterial) {
|
|
684
903
|
const mat = child.material.clone();
|
|
685
904
|
mat.color.multiply(tintColor);
|
|
686
905
|
child.material = mat;
|
|
@@ -689,7 +908,7 @@ function ModelLoader({
|
|
|
689
908
|
});
|
|
690
909
|
return cloned;
|
|
691
910
|
}, [loadedModel, castShadow, receiveShadow, tint]);
|
|
692
|
-
const mixer = useMemo(() => model ? new
|
|
911
|
+
const mixer = useMemo(() => model ? new THREE11.AnimationMixer(model) : null, [model]);
|
|
693
912
|
useEffect(() => {
|
|
694
913
|
if (!mixer || !animation || clips.length === 0) return;
|
|
695
914
|
const wanted = animation.toLowerCase();
|
|
@@ -706,8 +925,8 @@ function ModelLoader({
|
|
|
706
925
|
});
|
|
707
926
|
const normFactor = useMemo(() => {
|
|
708
927
|
if (!model) return 1;
|
|
709
|
-
const box = new
|
|
710
|
-
const size = new
|
|
928
|
+
const box = new THREE11.Box3().setFromObject(model);
|
|
929
|
+
const size = new THREE11.Vector3();
|
|
711
930
|
box.getSize(size);
|
|
712
931
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
713
932
|
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
@@ -797,7 +1016,7 @@ var warnUnsupported3d = (kind) => {
|
|
|
797
1016
|
warnedUnsupported.add(kind);
|
|
798
1017
|
mesh3dLog.warn("unsupported drawable kind on the 3D backend \u2014 skipped", { kind });
|
|
799
1018
|
};
|
|
800
|
-
var CrossOriginTextureLoader = class extends
|
|
1019
|
+
var CrossOriginTextureLoader = class extends THREE11.TextureLoader {
|
|
801
1020
|
constructor() {
|
|
802
1021
|
super();
|
|
803
1022
|
this.crossOrigin = "anonymous";
|
|
@@ -815,7 +1034,7 @@ function useBillboardTexture(url) {
|
|
|
815
1034
|
url,
|
|
816
1035
|
(texture) => {
|
|
817
1036
|
if (!active) return;
|
|
818
|
-
texture.colorSpace =
|
|
1037
|
+
texture.colorSpace = THREE11.SRGBColorSpace;
|
|
819
1038
|
setState({ texture, error: false });
|
|
820
1039
|
},
|
|
821
1040
|
void 0,
|
|
@@ -868,7 +1087,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
868
1087
|
}, [texture, frame, node.height, node.width, anchor, cellSize]);
|
|
869
1088
|
const groundGeometry = React3.useMemo(() => {
|
|
870
1089
|
if (anchor !== "top-left" || !texture || !atlasReady) return null;
|
|
871
|
-
const g = new
|
|
1090
|
+
const g = new THREE11.PlaneGeometry(size.width, size.height);
|
|
872
1091
|
g.rotateX(-Math.PI / 2);
|
|
873
1092
|
return g;
|
|
874
1093
|
}, [anchor, texture, atlasReady, size.width, size.height]);
|
|
@@ -876,15 +1095,15 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
876
1095
|
if (anchor === "top-left") {
|
|
877
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: [
|
|
878
1097
|
/* @__PURE__ */ jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
879
|
-
/* @__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 })
|
|
880
1099
|
] }) });
|
|
881
1100
|
}
|
|
882
1101
|
return /* @__PURE__ */ jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxs("mesh", { children: [
|
|
883
1102
|
/* @__PURE__ */ jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
884
|
-
/* @__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 })
|
|
885
1104
|
] }) });
|
|
886
1105
|
}
|
|
887
|
-
texture.magFilter = texture.minFilter =
|
|
1106
|
+
texture.magFilter = texture.minFilter = THREE11.NearestFilter;
|
|
888
1107
|
texture.needsUpdate = true;
|
|
889
1108
|
if (frame) {
|
|
890
1109
|
texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
|
|
@@ -897,7 +1116,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
897
1116
|
map: texture,
|
|
898
1117
|
transparent: true,
|
|
899
1118
|
alphaTest: 0.1,
|
|
900
|
-
side:
|
|
1119
|
+
side: THREE11.DoubleSide,
|
|
901
1120
|
opacity: (node.opacity ?? 1) * groupOpacity
|
|
902
1121
|
}
|
|
903
1122
|
) }) });
|
|
@@ -910,7 +1129,7 @@ function SpriteBillboard({ node, world, cellSize = 1, groupOpacity = 1 }) {
|
|
|
910
1129
|
map: texture,
|
|
911
1130
|
transparent: true,
|
|
912
1131
|
alphaTest: 0.1,
|
|
913
|
-
side:
|
|
1132
|
+
side: THREE11.DoubleSide,
|
|
914
1133
|
opacity: node.opacity ?? 1
|
|
915
1134
|
}
|
|
916
1135
|
)
|
|
@@ -941,8 +1160,27 @@ function Sprite3D({ node, projector, groupOpacity = 1 }) {
|
|
|
941
1160
|
return /* @__PURE__ */ jsx(SpriteBillboard, { node, world: projector.toWorld(node.position), cellSize: projector.cellSize, groupOpacity });
|
|
942
1161
|
}
|
|
943
1162
|
function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
944
|
-
|
|
945
|
-
const
|
|
1163
|
+
const groupRef = React3.useRef(null);
|
|
1164
|
+
const materialRef = React3.useRef(null);
|
|
1165
|
+
const animated = isAnimatedShape(node);
|
|
1166
|
+
const validPos = isValidScenePos(node.position);
|
|
1167
|
+
const world = validPos ? projector.toWorld(node.position) : [0, 0, 0];
|
|
1168
|
+
useFrame(({ clock }) => {
|
|
1169
|
+
if (!animated || !groupRef.current) return;
|
|
1170
|
+
const view = applyShapeAnimation(node, clock.elapsedTime * 1e3);
|
|
1171
|
+
groupRef.current.position.set(
|
|
1172
|
+
world[0] + (view.offsetX ?? 0) * projector.cellSize,
|
|
1173
|
+
world[1] + 0.02,
|
|
1174
|
+
world[2] + (view.offsetY ?? 0) * projector.cellSize
|
|
1175
|
+
);
|
|
1176
|
+
groupRef.current.rotation.y = -(view.rotate ?? 0);
|
|
1177
|
+
const mat = materialRef.current;
|
|
1178
|
+
if (mat) {
|
|
1179
|
+
mat.opacity = (view.opacity ?? node.opacity ?? 1) * groupOpacity;
|
|
1180
|
+
if (view.fill) mat.color.set(view.fill);
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
if (!validPos) return null;
|
|
946
1184
|
const color = node.fill ?? node.stroke ?? "#ffffff";
|
|
947
1185
|
let geometry;
|
|
948
1186
|
switch (node.shape) {
|
|
@@ -960,7 +1198,7 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
960
1198
|
}
|
|
961
1199
|
case "poly": {
|
|
962
1200
|
if (!node.points || node.points.length === 0) return null;
|
|
963
|
-
const s = new
|
|
1201
|
+
const s = new THREE11.Shape();
|
|
964
1202
|
node.points.forEach((p, i) => {
|
|
965
1203
|
if (i === 0) s.moveTo(p.x, p.y);
|
|
966
1204
|
else s.lineTo(p.x, p.y);
|
|
@@ -976,12 +1214,12 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
|
|
|
976
1214
|
default:
|
|
977
1215
|
return null;
|
|
978
1216
|
}
|
|
979
|
-
return /* @__PURE__ */
|
|
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: [
|
|
980
1218
|
geometry,
|
|
981
|
-
/* @__PURE__ */ jsx("meshBasicMaterial", { color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side:
|
|
982
|
-
] });
|
|
1219
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE11.DoubleSide })
|
|
1220
|
+
] }) });
|
|
983
1221
|
}
|
|
984
|
-
function Text3D({ node, projector }) {
|
|
1222
|
+
function Text3D({ node, projector, groupOpacity = 1 }) {
|
|
985
1223
|
if (!isValidScenePos(node.position)) return null;
|
|
986
1224
|
const world = projector.toWorld(node.position);
|
|
987
1225
|
return /* @__PURE__ */ jsx(Billboard, { position: [world[0], world[1] + 1.2, world[2]], children: /* @__PURE__ */ jsx(
|
|
@@ -993,68 +1231,52 @@ function Text3D({ node, projector }) {
|
|
|
993
1231
|
anchorY: "middle",
|
|
994
1232
|
outlineWidth: 0.02,
|
|
995
1233
|
outlineColor: "#000000",
|
|
1234
|
+
fillOpacity: groupOpacity,
|
|
1235
|
+
outlineOpacity: groupOpacity,
|
|
996
1236
|
children: node.text
|
|
997
1237
|
}
|
|
998
1238
|
) });
|
|
999
1239
|
}
|
|
1000
|
-
var
|
|
1001
|
-
function
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
let
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
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
|
+
}
|
|
1034
1274
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
const span = next.at - prev.at;
|
|
1038
|
-
const k = span > 0 ? (t - prev.at) / span : 1;
|
|
1039
|
-
const a = prev[key];
|
|
1040
|
-
const b = next[key];
|
|
1041
|
-
if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
|
|
1042
|
-
return a;
|
|
1043
|
-
};
|
|
1044
|
-
const num = {};
|
|
1045
|
-
for (const key of NUMERIC_TRACKS) {
|
|
1046
|
-
const v = trackValue(key);
|
|
1047
|
-
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));
|
|
1048
1277
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
|
|
1052
|
-
scale: num.scale ?? 1,
|
|
1053
|
-
opacity: num.opacity,
|
|
1054
|
-
emissiveIntensity: num.emissiveIntensity,
|
|
1055
|
-
color: trackValue("color"),
|
|
1056
|
-
emissive: trackValue("emissive")
|
|
1057
|
-
};
|
|
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 };
|
|
1058
1280
|
}
|
|
1059
1281
|
function meshGeometry(node, cellSize) {
|
|
1060
1282
|
const seg = clampSegments(node.segments);
|
|
@@ -1082,17 +1304,20 @@ function meshGeometry(node, cellSize) {
|
|
|
1082
1304
|
return { element: /* @__PURE__ */ jsx("torusGeometry", { args: [r, tube, Math.max(3, Math.round(seg / 2)), seg] }), lift: r + tube, size: (r + tube) * 2 };
|
|
1083
1305
|
}
|
|
1084
1306
|
case "plane":
|
|
1085
|
-
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 };
|
|
1086
1308
|
case "circle":
|
|
1087
|
-
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);
|
|
1088
1312
|
default:
|
|
1089
1313
|
return null;
|
|
1090
1314
|
}
|
|
1091
1315
|
}
|
|
1316
|
+
var warnedPolyhedronOutline = false;
|
|
1092
1317
|
var SIDE_MAP = {
|
|
1093
|
-
front:
|
|
1094
|
-
back:
|
|
1095
|
-
double:
|
|
1318
|
+
front: THREE11.FrontSide,
|
|
1319
|
+
back: THREE11.BackSide,
|
|
1320
|
+
double: THREE11.DoubleSide
|
|
1096
1321
|
};
|
|
1097
1322
|
function meshMaterial(mat, opacity, ref) {
|
|
1098
1323
|
const m = mat ?? {};
|
|
@@ -1136,6 +1361,53 @@ function meshMaterial(mat, opacity, ref) {
|
|
|
1136
1361
|
);
|
|
1137
1362
|
}
|
|
1138
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
|
+
}
|
|
1139
1411
|
function Mesh3D({
|
|
1140
1412
|
node,
|
|
1141
1413
|
projector,
|
|
@@ -1148,6 +1420,10 @@ function Mesh3D({
|
|
|
1148
1420
|
const validPos = isValidScenePos(node.position);
|
|
1149
1421
|
const baseWorld = validPos ? projector.toWorld(node.position) : [0, 0, 0];
|
|
1150
1422
|
const geo = useMemo(() => meshGeometry(node, projector.cellSize), [node, projector.cellSize]);
|
|
1423
|
+
useEffect(() => {
|
|
1424
|
+
const g = geo?.geometry;
|
|
1425
|
+
return () => g?.dispose();
|
|
1426
|
+
}, [geo]);
|
|
1151
1427
|
useFrame(({ clock }) => {
|
|
1152
1428
|
if (!animated || !groupRef.current) return;
|
|
1153
1429
|
const state = applyMeshAnimation(node, clock.elapsedTime * 1e3);
|
|
@@ -1160,8 +1436,13 @@ function Mesh3D({
|
|
|
1160
1436
|
);
|
|
1161
1437
|
groupRef.current.scale.setScalar(state.scale);
|
|
1162
1438
|
if (meshRef.current) {
|
|
1439
|
+
const shapeRot = geo?.baseRotation ?? [0, 0, 0];
|
|
1163
1440
|
const base = node.rotation ?? [0, 0, 0];
|
|
1164
|
-
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
|
+
);
|
|
1165
1446
|
}
|
|
1166
1447
|
const mat = materialRef.current;
|
|
1167
1448
|
if (mat) {
|
|
@@ -1178,13 +1459,28 @@ function Mesh3D({
|
|
|
1178
1459
|
if (!validPos || !geo) return null;
|
|
1179
1460
|
const lift = (node.pivot ?? "bottom") === "bottom" ? geo.lift : 0;
|
|
1180
1461
|
const opacity = (node.opacity ?? 1) * (node.material?.opacity ?? 1) * groupOpacity;
|
|
1181
|
-
|
|
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
|
+
];
|
|
1182
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 } : {};
|
|
1183
1478
|
return /* @__PURE__ */ jsxs("group", { ref: groupRef, position: baseWorld, children: [
|
|
1184
1479
|
/* @__PURE__ */ jsxs(
|
|
1185
1480
|
"mesh",
|
|
1186
1481
|
{
|
|
1187
1482
|
ref: meshRef,
|
|
1483
|
+
...geometryProp,
|
|
1188
1484
|
position: [0, lift, 0],
|
|
1189
1485
|
rotation,
|
|
1190
1486
|
castShadow: node.castShadow ?? true,
|
|
@@ -1195,13 +1491,13 @@ function Mesh3D({
|
|
|
1195
1491
|
]
|
|
1196
1492
|
}
|
|
1197
1493
|
),
|
|
1198
|
-
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: [
|
|
1199
1495
|
geo.element,
|
|
1200
1496
|
/* @__PURE__ */ jsx(
|
|
1201
1497
|
"meshBasicMaterial",
|
|
1202
1498
|
{
|
|
1203
1499
|
color: node.outline.color ?? "#101014",
|
|
1204
|
-
side:
|
|
1500
|
+
side: THREE11.BackSide,
|
|
1205
1501
|
transparent: opacity < 1,
|
|
1206
1502
|
opacity
|
|
1207
1503
|
}
|
|
@@ -1216,7 +1512,7 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1216
1512
|
case "draw-shape":
|
|
1217
1513
|
return /* @__PURE__ */ jsx(Shape3D, { node, projector, groupOpacity });
|
|
1218
1514
|
case "draw-text":
|
|
1219
|
-
return /* @__PURE__ */ jsx(Text3D, { node, projector });
|
|
1515
|
+
return /* @__PURE__ */ jsx(Text3D, { node, projector, groupOpacity });
|
|
1220
1516
|
case "draw-mesh":
|
|
1221
1517
|
return /* @__PURE__ */ jsx(Mesh3D, { node, projector, groupOpacity });
|
|
1222
1518
|
case "draw-sprite-layer":
|
|
@@ -1224,18 +1520,57 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
|
|
|
1224
1520
|
case "draw-shape-layer":
|
|
1225
1521
|
return /* @__PURE__ */ jsx(Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsx(Shape3D, { node: item, projector, groupOpacity }, i)) });
|
|
1226
1522
|
case "draw-text-layer":
|
|
1227
|
-
return /* @__PURE__ */ jsx(Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsx(Text3D, { node: item, projector }, i)) });
|
|
1523
|
+
return /* @__PURE__ */ jsx(Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsx(Text3D, { node: item, projector, groupOpacity }, i)) });
|
|
1228
1524
|
case "draw-group": {
|
|
1229
1525
|
if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
|
|
1230
1526
|
if (node.clip) warnUnsupported3d("draw-group:clip");
|
|
1231
|
-
|
|
1232
|
-
const inner = create3DProjector({ cellSize: projector.cellSize });
|
|
1233
|
-
const opacity = (node.opacity ?? 1) * groupOpacity;
|
|
1234
|
-
const s = node.scale ?? 1;
|
|
1235
|
-
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 });
|
|
1236
1528
|
}
|
|
1237
1529
|
}
|
|
1238
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
|
+
}
|
|
1239
1574
|
|
|
1240
1575
|
// lib/drawable/three/game3dTheme.ts
|
|
1241
1576
|
var GRID_COLORS_3D = {
|
|
@@ -1248,6 +1583,20 @@ function cn(...inputs) {
|
|
|
1248
1583
|
}
|
|
1249
1584
|
var DEFAULT_GRID_CONFIG = {
|
|
1250
1585
|
cellSize: 1};
|
|
1586
|
+
function RoomEnvironment3D() {
|
|
1587
|
+
const { gl, scene } = useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
|
|
1588
|
+
useEffect(() => {
|
|
1589
|
+
const pmremGenerator = new THREE11.PMREMGenerator(gl);
|
|
1590
|
+
const envTexture = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
|
|
1591
|
+
scene.environment = envTexture;
|
|
1592
|
+
return () => {
|
|
1593
|
+
scene.environment = null;
|
|
1594
|
+
envTexture.dispose();
|
|
1595
|
+
pmremGenerator.dispose();
|
|
1596
|
+
};
|
|
1597
|
+
}, [gl, scene]);
|
|
1598
|
+
return null;
|
|
1599
|
+
}
|
|
1251
1600
|
var Canvas3DHost = forwardRef(
|
|
1252
1601
|
({
|
|
1253
1602
|
cameraMode = "isometric",
|
|
@@ -1273,6 +1622,8 @@ var Canvas3DHost = forwardRef(
|
|
|
1273
1622
|
keyUpMap,
|
|
1274
1623
|
pixelsPerUnit,
|
|
1275
1624
|
fov,
|
|
1625
|
+
lighting,
|
|
1626
|
+
post,
|
|
1276
1627
|
children,
|
|
1277
1628
|
drawables
|
|
1278
1629
|
}, ref) => {
|
|
@@ -1281,6 +1632,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1281
1632
|
const [internalError, setInternalError] = useState(null);
|
|
1282
1633
|
const eventBus = useEventBus();
|
|
1283
1634
|
const keysRef = useRef(/* @__PURE__ */ new Set());
|
|
1635
|
+
const allDrawables = useMemo(() => drawables ?? [], [drawables]);
|
|
1284
1636
|
useEffect(() => {
|
|
1285
1637
|
if (!keyMap && !keyUpMap) return;
|
|
1286
1638
|
const down = (e) => {
|
|
@@ -1314,7 +1666,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1314
1666
|
unitAnimationEvent,
|
|
1315
1667
|
cameraChangeEvent
|
|
1316
1668
|
});
|
|
1317
|
-
const drawnItems = useMemo(() => collectDrawnItems(
|
|
1669
|
+
const drawnItems = useMemo(() => collectDrawnItems(allDrawables), [allDrawables]);
|
|
1318
1670
|
const scenePositions = useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
|
|
1319
1671
|
const hitIndex = useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
|
|
1320
1672
|
const gridBounds = useMemo(() => {
|
|
@@ -1350,6 +1702,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1350
1702
|
}),
|
|
1351
1703
|
[gridBounds, cellSize]
|
|
1352
1704
|
);
|
|
1705
|
+
const boneStore = useMemo(() => new BoneStore(), []);
|
|
1353
1706
|
const drawableProjector = useMemo(
|
|
1354
1707
|
() => create3DProjector({
|
|
1355
1708
|
cellSize: gridConfig.cellSize,
|
|
@@ -1362,7 +1715,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1362
1715
|
getCameraPosition: () => {
|
|
1363
1716
|
if (controlsRef.current) {
|
|
1364
1717
|
const pos = controlsRef.current.object.position;
|
|
1365
|
-
return new
|
|
1718
|
+
return new THREE11.Vector3(pos.x, pos.y, pos.z);
|
|
1366
1719
|
}
|
|
1367
1720
|
return null;
|
|
1368
1721
|
},
|
|
@@ -1407,6 +1760,8 @@ var Canvas3DHost = forwardRef(
|
|
|
1407
1760
|
return { position: [cx + d, d * 0.8, cz + d], fov: fovDeg };
|
|
1408
1761
|
case "top-down":
|
|
1409
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 };
|
|
1410
1765
|
case "follow":
|
|
1411
1766
|
return { position: [cx, d * 0.5, cz + d], fov: fovDeg };
|
|
1412
1767
|
case "perspective":
|
|
@@ -1473,6 +1828,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1473
1828
|
Canvas,
|
|
1474
1829
|
{
|
|
1475
1830
|
shadows,
|
|
1831
|
+
flat: lighting?.toneMapping === "none",
|
|
1476
1832
|
camera: {
|
|
1477
1833
|
position: cameraConfig.position,
|
|
1478
1834
|
fov: cameraConfig.fov,
|
|
@@ -1496,9 +1852,19 @@ var Canvas3DHost = forwardRef(
|
|
|
1496
1852
|
shadowNormalBias: 0.04,
|
|
1497
1853
|
shadowCameraSize: 5,
|
|
1498
1854
|
shadowCameraNear: 0.5,
|
|
1499
|
-
shadowCameraFar: 500
|
|
1855
|
+
shadowCameraFar: 500,
|
|
1856
|
+
ambientIntensity: lighting?.ambient?.intensity,
|
|
1857
|
+
ambientColor: lighting?.ambient?.color,
|
|
1858
|
+
directionalIntensity: lighting?.directional?.intensity,
|
|
1859
|
+
directionalColor: lighting?.directional?.color,
|
|
1860
|
+
directionalPosition: lighting?.directional?.position,
|
|
1861
|
+
hemisphereIntensity: lighting?.hemisphere?.intensity,
|
|
1862
|
+
hemisphereColor: lighting?.hemisphere?.color,
|
|
1863
|
+
hemisphereGroundColor: lighting?.hemisphere?.groundColor,
|
|
1864
|
+
points: lighting?.points
|
|
1500
1865
|
}
|
|
1501
1866
|
),
|
|
1867
|
+
lighting?.environment === "room" && /* @__PURE__ */ jsx(RoomEnvironment3D, {}),
|
|
1502
1868
|
showGrid && /* @__PURE__ */ jsx(
|
|
1503
1869
|
Grid,
|
|
1504
1870
|
{
|
|
@@ -1521,7 +1887,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1521
1887
|
fadeStrength: 1
|
|
1522
1888
|
}
|
|
1523
1889
|
),
|
|
1524
|
-
|
|
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)) }) }),
|
|
1525
1891
|
(tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxs(
|
|
1526
1892
|
"mesh",
|
|
1527
1893
|
{
|
|
@@ -1546,7 +1912,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1546
1912
|
]
|
|
1547
1913
|
}
|
|
1548
1914
|
),
|
|
1549
|
-
|
|
1915
|
+
post && (post.bloom || post.vignette) ? /* @__PURE__ */ jsx(Effects3D, { post }) : null,
|
|
1550
1916
|
/* @__PURE__ */ jsx(
|
|
1551
1917
|
OrbitControls,
|
|
1552
1918
|
{
|
|
@@ -1557,7 +1923,7 @@ var Canvas3DHost = forwardRef(
|
|
|
1557
1923
|
dampingFactor: 0.05,
|
|
1558
1924
|
enableZoom: true,
|
|
1559
1925
|
enablePan: true,
|
|
1560
|
-
touches: { ONE:
|
|
1926
|
+
touches: { ONE: THREE11.TOUCH.ROTATE, TWO: THREE11.TOUCH.DOLLY_PAN },
|
|
1561
1927
|
minDistance: 2,
|
|
1562
1928
|
maxDistance: 100,
|
|
1563
1929
|
maxPolarAngle: Math.PI / 2 - 0.1
|
|
@@ -1580,15 +1946,15 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
|
1580
1946
|
if (initializedRef.current) return;
|
|
1581
1947
|
initializedRef.current = true;
|
|
1582
1948
|
if (background.startsWith("#") || background.startsWith("rgb")) {
|
|
1583
|
-
scene.background = new
|
|
1949
|
+
scene.background = new THREE11.Color(background);
|
|
1584
1950
|
} else {
|
|
1585
|
-
const loader = new
|
|
1951
|
+
const loader = new THREE11.TextureLoader();
|
|
1586
1952
|
loader.load(background, (texture) => {
|
|
1587
1953
|
scene.background = texture;
|
|
1588
1954
|
});
|
|
1589
1955
|
}
|
|
1590
1956
|
if (fog) {
|
|
1591
|
-
scene.fog = new
|
|
1957
|
+
scene.fog = new THREE11.Fog(fog.color, fog.near, fog.far);
|
|
1592
1958
|
}
|
|
1593
1959
|
return () => {
|
|
1594
1960
|
scene.background = null;
|
|
@@ -1611,14 +1977,14 @@ var Camera3D = forwardRef(
|
|
|
1611
1977
|
}, ref) => {
|
|
1612
1978
|
const { camera, set, viewport } = useThree();
|
|
1613
1979
|
const controlsRef = useRef(null);
|
|
1614
|
-
const initialPosition = useRef(new
|
|
1615
|
-
const initialTarget = useRef(new
|
|
1980
|
+
const initialPosition = useRef(new THREE11.Vector3(...position));
|
|
1981
|
+
const initialTarget = useRef(new THREE11.Vector3(...target));
|
|
1616
1982
|
useEffect(() => {
|
|
1617
1983
|
let newCamera;
|
|
1618
1984
|
if (mode === "isometric") {
|
|
1619
1985
|
const aspect = viewport.aspect;
|
|
1620
1986
|
const size = 10 / zoom;
|
|
1621
|
-
newCamera = new
|
|
1987
|
+
newCamera = new THREE11.OrthographicCamera(
|
|
1622
1988
|
-size * aspect,
|
|
1623
1989
|
size * aspect,
|
|
1624
1990
|
size,
|
|
@@ -1627,7 +1993,7 @@ var Camera3D = forwardRef(
|
|
|
1627
1993
|
1e3
|
|
1628
1994
|
);
|
|
1629
1995
|
} else {
|
|
1630
|
-
newCamera = new
|
|
1996
|
+
newCamera = new THREE11.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
|
|
1631
1997
|
}
|
|
1632
1998
|
newCamera.position.copy(initialPosition.current);
|
|
1633
1999
|
newCamera.lookAt(initialTarget.current.x, initialTarget.current.y, initialTarget.current.z);
|
|
@@ -1668,8 +2034,8 @@ var Camera3D = forwardRef(
|
|
|
1668
2034
|
}
|
|
1669
2035
|
},
|
|
1670
2036
|
getViewBounds: () => {
|
|
1671
|
-
const min = new
|
|
1672
|
-
const max = new
|
|
2037
|
+
const min = new THREE11.Vector3(-10, -10, -10);
|
|
2038
|
+
const max = new THREE11.Vector3(10, 10, 10);
|
|
1673
2039
|
return { min, max };
|
|
1674
2040
|
}
|
|
1675
2041
|
}));
|
|
@@ -1711,7 +2077,7 @@ var AssetLoader = class {
|
|
|
1711
2077
|
__publicField(this, "textureCache");
|
|
1712
2078
|
__publicField(this, "loadingPromises");
|
|
1713
2079
|
this.objLoader = new OBJLoader();
|
|
1714
|
-
this.textureLoader = new
|
|
2080
|
+
this.textureLoader = new THREE11.TextureLoader();
|
|
1715
2081
|
this.modelCache = /* @__PURE__ */ new Map();
|
|
1716
2082
|
this.textureCache = /* @__PURE__ */ new Map();
|
|
1717
2083
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
@@ -1785,7 +2151,7 @@ var AssetLoader = class {
|
|
|
1785
2151
|
return this.loadingPromises.get(`texture:${url}`);
|
|
1786
2152
|
}
|
|
1787
2153
|
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
1788
|
-
texture.colorSpace =
|
|
2154
|
+
texture.colorSpace = THREE11.SRGBColorSpace;
|
|
1789
2155
|
this.textureCache.set(url, texture);
|
|
1790
2156
|
this.loadingPromises.delete(`texture:${url}`);
|
|
1791
2157
|
return texture;
|
|
@@ -1859,7 +2225,7 @@ var AssetLoader = class {
|
|
|
1859
2225
|
});
|
|
1860
2226
|
this.modelCache.forEach((model) => {
|
|
1861
2227
|
model.scene.traverse((child) => {
|
|
1862
|
-
if (child instanceof
|
|
2228
|
+
if (child instanceof THREE11.Mesh) {
|
|
1863
2229
|
child.geometry.dispose();
|
|
1864
2230
|
if (Array.isArray(child.material)) {
|
|
1865
2231
|
child.material.forEach((m) => m.dispose());
|
|
@@ -1896,7 +2262,7 @@ var DEFAULT_OPTIONS = {
|
|
|
1896
2262
|
gridSize: 20,
|
|
1897
2263
|
assetLoader: new AssetLoader()
|
|
1898
2264
|
};
|
|
1899
|
-
function
|
|
2265
|
+
function useThree5(options = {}) {
|
|
1900
2266
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1901
2267
|
const containerRef = useRef(null);
|
|
1902
2268
|
const canvasRef = useRef(null);
|
|
@@ -1909,21 +2275,21 @@ function useThree4(options = {}) {
|
|
|
1909
2275
|
const [isReady, setIsReady] = useState(false);
|
|
1910
2276
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
|
1911
2277
|
const initialCameraPosition = useMemo(
|
|
1912
|
-
() => new
|
|
2278
|
+
() => new THREE11.Vector3(...opts.cameraPosition),
|
|
1913
2279
|
[]
|
|
1914
2280
|
);
|
|
1915
2281
|
useEffect(() => {
|
|
1916
2282
|
if (!containerRef.current) return;
|
|
1917
2283
|
const container = containerRef.current;
|
|
1918
2284
|
const { clientWidth, clientHeight } = container;
|
|
1919
|
-
const scene = new
|
|
1920
|
-
scene.background = new
|
|
2285
|
+
const scene = new THREE11.Scene();
|
|
2286
|
+
scene.background = new THREE11.Color(opts.backgroundColor);
|
|
1921
2287
|
sceneRef.current = scene;
|
|
1922
2288
|
let camera;
|
|
1923
2289
|
const aspect = clientWidth / clientHeight;
|
|
1924
2290
|
if (opts.cameraMode === "isometric") {
|
|
1925
2291
|
const size = 10;
|
|
1926
|
-
camera = new
|
|
2292
|
+
camera = new THREE11.OrthographicCamera(
|
|
1927
2293
|
-size * aspect,
|
|
1928
2294
|
size * aspect,
|
|
1929
2295
|
size,
|
|
@@ -1932,11 +2298,11 @@ function useThree4(options = {}) {
|
|
|
1932
2298
|
1e3
|
|
1933
2299
|
);
|
|
1934
2300
|
} else {
|
|
1935
|
-
camera = new
|
|
2301
|
+
camera = new THREE11.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
1936
2302
|
}
|
|
1937
2303
|
camera.position.copy(initialCameraPosition);
|
|
1938
2304
|
cameraRef.current = camera;
|
|
1939
|
-
const renderer = new
|
|
2305
|
+
const renderer = new THREE11.WebGLRenderer({
|
|
1940
2306
|
antialias: true,
|
|
1941
2307
|
alpha: true,
|
|
1942
2308
|
canvas: canvasRef.current || void 0
|
|
@@ -1944,7 +2310,7 @@ function useThree4(options = {}) {
|
|
|
1944
2310
|
renderer.setSize(clientWidth, clientHeight);
|
|
1945
2311
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
1946
2312
|
renderer.shadowMap.enabled = opts.shadows;
|
|
1947
|
-
renderer.shadowMap.type =
|
|
2313
|
+
renderer.shadowMap.type = THREE11.PCFSoftShadowMap;
|
|
1948
2314
|
rendererRef.current = renderer;
|
|
1949
2315
|
const controls = new OrbitControls$1(camera, renderer.domElement);
|
|
1950
2316
|
controls.enableDamping = true;
|
|
@@ -1953,16 +2319,16 @@ function useThree4(options = {}) {
|
|
|
1953
2319
|
controls.maxDistance = 100;
|
|
1954
2320
|
controls.maxPolarAngle = Math.PI / 2 - 0.1;
|
|
1955
2321
|
controlsRef.current = controls;
|
|
1956
|
-
const ambientLight = new
|
|
2322
|
+
const ambientLight = new THREE11.AmbientLight(16777215, 0.6);
|
|
1957
2323
|
scene.add(ambientLight);
|
|
1958
|
-
const directionalLight = new
|
|
2324
|
+
const directionalLight = new THREE11.DirectionalLight(16777215, 0.8);
|
|
1959
2325
|
directionalLight.position.set(10, 20, 10);
|
|
1960
2326
|
directionalLight.castShadow = opts.shadows;
|
|
1961
2327
|
directionalLight.shadow.mapSize.width = 2048;
|
|
1962
2328
|
directionalLight.shadow.mapSize.height = 2048;
|
|
1963
2329
|
scene.add(directionalLight);
|
|
1964
2330
|
if (opts.showGrid) {
|
|
1965
|
-
const gridHelper = new
|
|
2331
|
+
const gridHelper = new THREE11.GridHelper(
|
|
1966
2332
|
opts.gridSize,
|
|
1967
2333
|
opts.gridSize,
|
|
1968
2334
|
4473924,
|
|
@@ -1980,10 +2346,10 @@ function useThree4(options = {}) {
|
|
|
1980
2346
|
const handleResize = () => {
|
|
1981
2347
|
const { clientWidth: width, clientHeight: height } = container;
|
|
1982
2348
|
setDimensions({ width, height });
|
|
1983
|
-
if (camera instanceof
|
|
2349
|
+
if (camera instanceof THREE11.PerspectiveCamera) {
|
|
1984
2350
|
camera.aspect = width / height;
|
|
1985
2351
|
camera.updateProjectionMatrix();
|
|
1986
|
-
} else if (camera instanceof
|
|
2352
|
+
} else if (camera instanceof THREE11.OrthographicCamera) {
|
|
1987
2353
|
const aspect2 = width / height;
|
|
1988
2354
|
const size = 10;
|
|
1989
2355
|
camera.left = -size * aspect2;
|
|
@@ -2014,7 +2380,7 @@ function useThree4(options = {}) {
|
|
|
2014
2380
|
let newCamera;
|
|
2015
2381
|
if (opts.cameraMode === "isometric") {
|
|
2016
2382
|
const size = 10;
|
|
2017
|
-
newCamera = new
|
|
2383
|
+
newCamera = new THREE11.OrthographicCamera(
|
|
2018
2384
|
-size * aspect,
|
|
2019
2385
|
size * aspect,
|
|
2020
2386
|
size,
|
|
@@ -2023,7 +2389,7 @@ function useThree4(options = {}) {
|
|
|
2023
2389
|
1e3
|
|
2024
2390
|
);
|
|
2025
2391
|
} else {
|
|
2026
|
-
newCamera = new
|
|
2392
|
+
newCamera = new THREE11.PerspectiveCamera(45, aspect, 0.1, 1e3);
|
|
2027
2393
|
}
|
|
2028
2394
|
newCamera.position.copy(currentPos);
|
|
2029
2395
|
cameraRef.current = newCamera;
|
|
@@ -2353,8 +2719,8 @@ function useSceneGraph() {
|
|
|
2353
2719
|
}
|
|
2354
2720
|
function useRaycaster(options) {
|
|
2355
2721
|
const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
|
|
2356
|
-
const raycaster = useRef(new
|
|
2357
|
-
const mouse = useRef(new
|
|
2722
|
+
const raycaster = useRef(new THREE11.Raycaster());
|
|
2723
|
+
const mouse = useRef(new THREE11.Vector2());
|
|
2358
2724
|
const clientToNDC = useCallback(
|
|
2359
2725
|
(clientX, clientY) => {
|
|
2360
2726
|
if (!canvas) {
|
|
@@ -2424,8 +2790,8 @@ function useRaycaster(options) {
|
|
|
2424
2790
|
const ndc = clientToNDC(clientX, clientY);
|
|
2425
2791
|
mouse.current.set(ndc.x, ndc.y);
|
|
2426
2792
|
raycaster.current.setFromCamera(mouse.current, camera);
|
|
2427
|
-
const plane = new
|
|
2428
|
-
const target = new
|
|
2793
|
+
const plane = new THREE11.Plane(new THREE11.Vector3(0, 1, 0), 0);
|
|
2794
|
+
const target = new THREE11.Vector3();
|
|
2429
2795
|
const intersection = raycaster.current.ray.intersectPlane(plane, target);
|
|
2430
2796
|
if (intersection) {
|
|
2431
2797
|
const gridX = Math.round((target.x - offsetX) / cellSize);
|
|
@@ -2463,7 +2829,7 @@ function useRaycaster(options) {
|
|
|
2463
2829
|
return {
|
|
2464
2830
|
gridX: gridCoords.x,
|
|
2465
2831
|
gridZ: gridCoords.z,
|
|
2466
|
-
worldPosition: new
|
|
2832
|
+
worldPosition: new THREE11.Vector3(
|
|
2467
2833
|
gridCoords.x * cellSize + offsetX,
|
|
2468
2834
|
0,
|
|
2469
2835
|
gridCoords.z * cellSize + offsetZ
|
|
@@ -2493,7 +2859,7 @@ var DEFAULT_CONFIG = {
|
|
|
2493
2859
|
};
|
|
2494
2860
|
function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
|
|
2495
2861
|
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
2496
|
-
return new
|
|
2862
|
+
return new THREE11.Vector3(
|
|
2497
2863
|
gridX * opts.cellSize + opts.offsetX,
|
|
2498
2864
|
opts.elevation,
|
|
2499
2865
|
gridZ * opts.cellSize + opts.offsetZ
|
|
@@ -2507,17 +2873,17 @@ function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
|
|
|
2507
2873
|
};
|
|
2508
2874
|
}
|
|
2509
2875
|
function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
|
|
2510
|
-
const raycaster = new
|
|
2511
|
-
const mouse = new
|
|
2876
|
+
const raycaster = new THREE11.Raycaster();
|
|
2877
|
+
const mouse = new THREE11.Vector2(mouseX, mouseY);
|
|
2512
2878
|
raycaster.setFromCamera(mouse, camera);
|
|
2513
|
-
const plane = new
|
|
2514
|
-
const target = new
|
|
2879
|
+
const plane = new THREE11.Plane(new THREE11.Vector3(0, 1, 0), -planeY);
|
|
2880
|
+
const target = new THREE11.Vector3();
|
|
2515
2881
|
const intersection = raycaster.ray.intersectPlane(plane, target);
|
|
2516
2882
|
return intersection ? target : null;
|
|
2517
2883
|
}
|
|
2518
2884
|
function raycastToObjects(camera, mouseX, mouseY, objects) {
|
|
2519
|
-
const raycaster = new
|
|
2520
|
-
const mouse = new
|
|
2885
|
+
const raycaster = new THREE11.Raycaster();
|
|
2886
|
+
const mouse = new THREE11.Vector2(mouseX, mouseY);
|
|
2521
2887
|
raycaster.setFromCamera(mouse, camera);
|
|
2522
2888
|
const intersects = raycaster.intersectObjects(objects, true);
|
|
2523
2889
|
return intersects.length > 0 ? intersects[0] : null;
|
|
@@ -2569,14 +2935,14 @@ function getCellsInRadius(centerX, centerZ, radius) {
|
|
|
2569
2935
|
return cells;
|
|
2570
2936
|
}
|
|
2571
2937
|
function createGridHighlight(color = 16776960, opacity = 0.3) {
|
|
2572
|
-
const geometry = new
|
|
2573
|
-
const material = new
|
|
2938
|
+
const geometry = new THREE11.PlaneGeometry(0.95, 0.95);
|
|
2939
|
+
const material = new THREE11.MeshBasicMaterial({
|
|
2574
2940
|
color,
|
|
2575
2941
|
transparent: true,
|
|
2576
2942
|
opacity,
|
|
2577
|
-
side:
|
|
2943
|
+
side: THREE11.DoubleSide
|
|
2578
2944
|
});
|
|
2579
|
-
const mesh = new
|
|
2945
|
+
const mesh = new THREE11.Mesh(geometry, material);
|
|
2580
2946
|
mesh.rotation.x = -Math.PI / 2;
|
|
2581
2947
|
mesh.position.y = 0.01;
|
|
2582
2948
|
return mesh;
|
|
@@ -2589,31 +2955,31 @@ function normalizeMouseCoordinates(clientX, clientY, element) {
|
|
|
2589
2955
|
};
|
|
2590
2956
|
}
|
|
2591
2957
|
function isInFrustum(position, camera, padding = 0) {
|
|
2592
|
-
const frustum = new
|
|
2593
|
-
const projScreenMatrix = new
|
|
2958
|
+
const frustum = new THREE11.Frustum();
|
|
2959
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2594
2960
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2595
2961
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2596
|
-
const sphere = new
|
|
2962
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2597
2963
|
return frustum.intersectsSphere(sphere);
|
|
2598
2964
|
}
|
|
2599
2965
|
function filterByFrustum(positions, camera, padding = 0) {
|
|
2600
|
-
const frustum = new
|
|
2601
|
-
const projScreenMatrix = new
|
|
2966
|
+
const frustum = new THREE11.Frustum();
|
|
2967
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2602
2968
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2603
2969
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2604
2970
|
return positions.filter((position) => {
|
|
2605
|
-
const sphere = new
|
|
2971
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2606
2972
|
return frustum.intersectsSphere(sphere);
|
|
2607
2973
|
});
|
|
2608
2974
|
}
|
|
2609
2975
|
function getVisibleIndices(positions, camera, padding = 0) {
|
|
2610
|
-
const frustum = new
|
|
2611
|
-
const projScreenMatrix = new
|
|
2976
|
+
const frustum = new THREE11.Frustum();
|
|
2977
|
+
const projScreenMatrix = new THREE11.Matrix4();
|
|
2612
2978
|
const visible = /* @__PURE__ */ new Set();
|
|
2613
2979
|
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
2614
2980
|
frustum.setFromProjectionMatrix(projScreenMatrix);
|
|
2615
2981
|
positions.forEach((position, index) => {
|
|
2616
|
-
const sphere = new
|
|
2982
|
+
const sphere = new THREE11.Sphere(position, padding);
|
|
2617
2983
|
if (frustum.intersectsSphere(sphere)) {
|
|
2618
2984
|
visible.add(index);
|
|
2619
2985
|
}
|
|
@@ -2637,7 +3003,7 @@ function updateInstanceLOD(instancedMesh, positions, camera, lodDistances) {
|
|
|
2637
3003
|
return lodIndices;
|
|
2638
3004
|
}
|
|
2639
3005
|
function cullInstancedMesh(instancedMesh, positions, visibleIndices) {
|
|
2640
|
-
const dummy = new
|
|
3006
|
+
const dummy = new THREE11.Object3D();
|
|
2641
3007
|
let visibleCount = 0;
|
|
2642
3008
|
positions.forEach((position, index) => {
|
|
2643
3009
|
if (visibleIndices.has(index)) {
|
|
@@ -5420,12 +5786,12 @@ function useAvl3DConfig() {
|
|
|
5420
5786
|
}
|
|
5421
5787
|
function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
5422
5788
|
const { camera } = useThree();
|
|
5423
|
-
const targetPosVec = useRef(new
|
|
5424
|
-
const targetLookVec = useRef(new
|
|
5789
|
+
const targetPosVec = useRef(new THREE11.Vector3(...targetPosition));
|
|
5790
|
+
const targetLookVec = useRef(new THREE11.Vector3(...targetLookAt));
|
|
5425
5791
|
const isAnimating = useRef(false);
|
|
5426
5792
|
useEffect(() => {
|
|
5427
|
-
const newTarget = new
|
|
5428
|
-
const newLookAt = new
|
|
5793
|
+
const newTarget = new THREE11.Vector3(...targetPosition);
|
|
5794
|
+
const newLookAt = new THREE11.Vector3(...targetLookAt);
|
|
5429
5795
|
if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
|
|
5430
5796
|
targetPosVec.current.copy(newTarget);
|
|
5431
5797
|
targetLookVec.current.copy(newLookAt);
|
|
@@ -5440,9 +5806,9 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
|
5440
5806
|
useFrame((_, delta) => {
|
|
5441
5807
|
if (!isAnimating.current) return;
|
|
5442
5808
|
const speed = 3;
|
|
5443
|
-
camera.position.x =
|
|
5444
|
-
camera.position.y =
|
|
5445
|
-
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);
|
|
5446
5812
|
camera.lookAt(targetLookVec.current);
|
|
5447
5813
|
const dist = camera.position.distanceTo(targetPosVec.current);
|
|
5448
5814
|
if (dist < 0.05) {
|
|
@@ -5457,7 +5823,7 @@ function SceneFade({ animating, children }) {
|
|
|
5457
5823
|
useFrame((_, delta) => {
|
|
5458
5824
|
if (!groupRef.current) return;
|
|
5459
5825
|
const target = animating ? 0 : 1;
|
|
5460
|
-
opacityRef.current =
|
|
5826
|
+
opacityRef.current = THREE11.MathUtils.damp(opacityRef.current, target, 5, delta);
|
|
5461
5827
|
groupRef.current.visible = opacityRef.current > 0.05;
|
|
5462
5828
|
const s = 0.9 + opacityRef.current * 0.1;
|
|
5463
5829
|
groupRef.current.scale.setScalar(s);
|
|
@@ -5710,4 +6076,4 @@ var Avl3DViewer = ({
|
|
|
5710
6076
|
};
|
|
5711
6077
|
Avl3DViewer.displayName = "Avl3DViewer";
|
|
5712
6078
|
|
|
5713
|
-
export { AVL_3D_COLORS, AssetLoader, Avl3DApplicationScene, Avl3DContext, Avl3DEffects, Avl3DOrbitalScene, Avl3DTraitScene, Avl3DTransitionScene, Avl3DViewer, CAMERA_POSITIONS, Camera3D, Canvas3DErrorBoundary, Canvas3DHost, Canvas3DLoadingState, Canvas3DHost as GameCanvas3D, Lighting3D, ModelLoader, Scene3D, SpatialHashGrid, arcCurve3D, assetLoader, calculateLODLevel, createGridHighlight, cullInstancedMesh, fibonacciSpherePositions, filterByFrustum, getCellsInRadius, getNeighbors, getVisibleIndices, goldenSpiralPositions, gridDistance, gridManhattanDistance, gridToWorld, isInBounds, isInFrustum, normalizeMouseCoordinates, orbitRingPositions, raycastToObjects, raycastToPlane, selfLoopCurve3D, treeLayout3D, updateInstanceLOD, useAssetLoader, useAvl3DConfig, useGameCanvas3DEvents, useRaycaster, useSceneGraph,
|
|
6079
|
+
export { AVL_3D_COLORS, AssetLoader, Avl3DApplicationScene, Avl3DContext, Avl3DEffects, Avl3DOrbitalScene, Avl3DTraitScene, Avl3DTransitionScene, Avl3DViewer, CAMERA_POSITIONS, Camera3D, Canvas3DErrorBoundary, Canvas3DHost, Canvas3DLoadingState, Canvas3DHost as GameCanvas3D, Lighting3D, ModelLoader, Scene3D, SpatialHashGrid, arcCurve3D, assetLoader, calculateLODLevel, createGridHighlight, cullInstancedMesh, fibonacciSpherePositions, filterByFrustum, getCellsInRadius, getNeighbors, getVisibleIndices, goldenSpiralPositions, gridDistance, gridManhattanDistance, gridToWorld, isInBounds, isInFrustum, normalizeMouseCoordinates, orbitRingPositions, raycastToObjects, raycastToPlane, selfLoopCurve3D, treeLayout3D, updateInstanceLOD, useAssetLoader, useAvl3DConfig, useGameCanvas3DEvents, useRaycaster, useSceneGraph, useThree5 as useThree, worldToGrid };
|