@adatechnology/game-vehicles 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.global.js +645 -183
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +612 -150
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -661,7 +661,7 @@ function installMaterials(kit) {
|
|
|
661
661
|
const I = kit._;
|
|
662
662
|
const document2 = kit.document;
|
|
663
663
|
const RUST = new THREE.Color("#5e3220");
|
|
664
|
-
const
|
|
664
|
+
const cache2 = {};
|
|
665
665
|
let envTex = null;
|
|
666
666
|
function studioEnvironment() {
|
|
667
667
|
if (envTex) return envTex;
|
|
@@ -706,7 +706,7 @@ function installMaterials(kit) {
|
|
|
706
706
|
const key = "s" + c.getHexString() + JSON.stringify(o, function(k, v) {
|
|
707
707
|
return v && v.isColor ? "#" + v.getHexString() : v && v.isTexture ? v.uuid : v;
|
|
708
708
|
});
|
|
709
|
-
if (!
|
|
709
|
+
if (!cache2[key]) {
|
|
710
710
|
const o2 = Object.assign({}, o);
|
|
711
711
|
delete o2.noEnv;
|
|
712
712
|
const mt = new THREE.MeshStandardMaterial(Object.assign({ color: c, roughness: 0.8, metalness: 0, flatShading: false }, o2));
|
|
@@ -714,9 +714,9 @@ function installMaterials(kit) {
|
|
|
714
714
|
mt.envMap = studioEnvironment();
|
|
715
715
|
if (o.envMapIntensity == null) mt.envMapIntensity = 0.55 + (mt.metalness - 0.6) * 1.6;
|
|
716
716
|
}
|
|
717
|
-
|
|
717
|
+
cache2[key] = mt;
|
|
718
718
|
}
|
|
719
|
-
return
|
|
719
|
+
return cache2[key];
|
|
720
720
|
}
|
|
721
721
|
function makeFlatMaterial(color, o) {
|
|
722
722
|
return makeMaterial(color, Object.assign({ flatShading: true, roughness: 0.92 }, o || {}));
|
|
@@ -831,7 +831,131 @@ function installMaterials(kit) {
|
|
|
831
831
|
return t;
|
|
832
832
|
}
|
|
833
833
|
kit.textTexture = textTexture;
|
|
834
|
-
Object.assign(I, { RUST, cache, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE, toColor, MATERIALS, paintColor, texCache, textTexture });
|
|
834
|
+
Object.assign(I, { RUST, cache: cache2, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE, toColor, MATERIALS, paintColor, texCache, textTexture });
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/tri-index.ts
|
|
838
|
+
var TRI_BLOCK = 32;
|
|
839
|
+
var cache = /* @__PURE__ */ new WeakMap();
|
|
840
|
+
function trianglesOf(geo) {
|
|
841
|
+
return Math.floor((geo.index ? geo.index.count : geo.attributes.position.count) / 3);
|
|
842
|
+
}
|
|
843
|
+
function supports(geo) {
|
|
844
|
+
const pos = geo.attributes && geo.attributes.position;
|
|
845
|
+
return !!pos && !pos.isInterleavedBufferAttribute && pos.itemSize === 3;
|
|
846
|
+
}
|
|
847
|
+
function isCurrent(geo, ti) {
|
|
848
|
+
const pos = geo.attributes.position;
|
|
849
|
+
return ti.position === pos && ti.positionVersion === pos.version && ti.index === (geo.index || null) && ti.indexVersion === (geo.index ? geo.index.version : 0) && ti.triangles === trianglesOf(geo);
|
|
850
|
+
}
|
|
851
|
+
function blockCount(triangles) {
|
|
852
|
+
return Math.ceil(triangles / TRI_BLOCK);
|
|
853
|
+
}
|
|
854
|
+
function boxBlock(ti, block) {
|
|
855
|
+
const B = ti.boxes;
|
|
856
|
+
const t0 = block * TRI_BLOCK;
|
|
857
|
+
const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
|
|
858
|
+
const o = block * 6;
|
|
859
|
+
for (let k = 0; k < 3; k++) {
|
|
860
|
+
ti.blocks[o + k] = Infinity;
|
|
861
|
+
ti.blocks[o + 3 + k] = -Infinity;
|
|
862
|
+
}
|
|
863
|
+
for (let t = t0; t < t1; t++) {
|
|
864
|
+
const j = t * 6;
|
|
865
|
+
for (let k = 0; k < 3; k++) {
|
|
866
|
+
if (B[j + k] < ti.blocks[o + k]) ti.blocks[o + k] = B[j + k];
|
|
867
|
+
if (B[j + 3 + k] > ti.blocks[o + 3 + k]) ti.blocks[o + 3 + k] = B[j + 3 + k];
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
function boxTriangle(geo, ti, t) {
|
|
872
|
+
const P = geo.attributes.position.array;
|
|
873
|
+
const ix = geo.index ? geo.index.array : null;
|
|
874
|
+
const a = (ix ? ix[t * 3] : t * 3) * 3;
|
|
875
|
+
const b = (ix ? ix[t * 3 + 1] : t * 3 + 1) * 3;
|
|
876
|
+
const c = (ix ? ix[t * 3 + 2] : t * 3 + 2) * 3;
|
|
877
|
+
const j = t * 6;
|
|
878
|
+
for (let k = 0; k < 3; k++) {
|
|
879
|
+
ti.boxes[j + k] = Math.min(P[a + k], P[b + k], P[c + k]);
|
|
880
|
+
ti.boxes[j + 3 + k] = Math.max(P[a + k], P[b + k], P[c + k]);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function advance(geo, ti, deadline) {
|
|
884
|
+
const total = blockCount(ti.triangles);
|
|
885
|
+
while (ti.builtBlocks < total) {
|
|
886
|
+
const block = ti.builtBlocks;
|
|
887
|
+
const t1 = Math.min(ti.triangles, (block + 1) * TRI_BLOCK);
|
|
888
|
+
for (let t = block * TRI_BLOCK; t < t1; t++) boxTriangle(geo, ti, t);
|
|
889
|
+
boxBlock(ti, block);
|
|
890
|
+
ti.builtBlocks++;
|
|
891
|
+
if (deadline !== Infinity && performance.now() >= deadline) break;
|
|
892
|
+
}
|
|
893
|
+
return ti.builtBlocks === total;
|
|
894
|
+
}
|
|
895
|
+
function start(geo) {
|
|
896
|
+
const pos = geo.attributes.position;
|
|
897
|
+
const triangles = trianglesOf(geo);
|
|
898
|
+
const ti = {
|
|
899
|
+
position: pos,
|
|
900
|
+
positionVersion: pos.version,
|
|
901
|
+
index: geo.index || null,
|
|
902
|
+
indexVersion: geo.index ? geo.index.version : 0,
|
|
903
|
+
triangles,
|
|
904
|
+
boxes: new Float64Array(triangles * 6),
|
|
905
|
+
blocks: new Float64Array(blockCount(triangles) * 6),
|
|
906
|
+
builtBlocks: 0
|
|
907
|
+
};
|
|
908
|
+
cache.set(geo, ti);
|
|
909
|
+
return ti;
|
|
910
|
+
}
|
|
911
|
+
function triIndexOf(geo) {
|
|
912
|
+
if (!supports(geo)) return void 0;
|
|
913
|
+
let ti = cache.get(geo);
|
|
914
|
+
if (!ti || !isCurrent(geo, ti)) ti = start(geo);
|
|
915
|
+
advance(geo, ti, Infinity);
|
|
916
|
+
return ti;
|
|
917
|
+
}
|
|
918
|
+
function warmTriIndex(geo, deadline) {
|
|
919
|
+
if (!supports(geo)) return true;
|
|
920
|
+
let ti = cache.get(geo);
|
|
921
|
+
if (!ti || !isCurrent(geo, ti)) ti = start(geo);
|
|
922
|
+
return advance(geo, ti, deadline);
|
|
923
|
+
}
|
|
924
|
+
function storeTriIndex(geo, boxes) {
|
|
925
|
+
const ti = start(geo);
|
|
926
|
+
ti.boxes = boxes;
|
|
927
|
+
const total = blockCount(ti.triangles);
|
|
928
|
+
for (let b = 0; b < total; b++) boxBlock(ti, b);
|
|
929
|
+
ti.builtBlocks = total;
|
|
930
|
+
}
|
|
931
|
+
function liveTriIndex(geo) {
|
|
932
|
+
if (geo.index || !supports(geo)) return void 0;
|
|
933
|
+
const ti = cache.get(geo);
|
|
934
|
+
return ti && isCurrent(geo, ti) && ti.builtBlocks === blockCount(ti.triangles) ? ti : void 0;
|
|
935
|
+
}
|
|
936
|
+
function touchTriIndex(geo, ti, vertices) {
|
|
937
|
+
if (ti.positionVersion + 1 !== geo.attributes.position.version) return;
|
|
938
|
+
const blocks = /* @__PURE__ */ new Set();
|
|
939
|
+
for (const v of vertices) {
|
|
940
|
+
const t = Math.floor(v / 3);
|
|
941
|
+
if (t >= ti.triangles) continue;
|
|
942
|
+
boxTriangle(geo, ti, t);
|
|
943
|
+
blocks.add(Math.floor(t / TRI_BLOCK));
|
|
944
|
+
}
|
|
945
|
+
blocks.forEach((b) => boxBlock(ti, b));
|
|
946
|
+
ti.positionVersion = geo.attributes.position.version;
|
|
947
|
+
}
|
|
948
|
+
function boundsFromIndex(geo) {
|
|
949
|
+
if (geo.index || !supports(geo)) return void 0;
|
|
950
|
+
const ti = cache.get(geo);
|
|
951
|
+
if (!ti || !isCurrent(geo, ti) || ti.builtBlocks !== blockCount(ti.triangles) || !ti.triangles || geo.attributes.position.count !== ti.triangles * 3) return void 0;
|
|
952
|
+
const box = new Float64Array([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
|
|
953
|
+
for (let b = 0, n = blockCount(ti.triangles); b < n; b++)
|
|
954
|
+
for (let k = 0; k < 3; k++) {
|
|
955
|
+
box[k] = Math.min(box[k], ti.blocks[b * 6 + k]);
|
|
956
|
+
box[3 + k] = Math.max(box[3 + k], ti.blocks[b * 6 + 3 + k]);
|
|
957
|
+
}
|
|
958
|
+
return { box, version: ti.positionVersion };
|
|
835
959
|
}
|
|
836
960
|
|
|
837
961
|
// src/geometry.ts
|
|
@@ -928,7 +1052,8 @@ function installGeometry(kit) {
|
|
|
928
1052
|
g.userData.crease = true;
|
|
929
1053
|
return g;
|
|
930
1054
|
}
|
|
931
|
-
|
|
1055
|
+
const latestCrease = /* @__PURE__ */ new WeakMap();
|
|
1056
|
+
function creaseTask(geo, deg) {
|
|
932
1057
|
if (geo.index) {
|
|
933
1058
|
const ni = geo.toNonIndexed();
|
|
934
1059
|
Object.keys(ni.attributes).forEach(function(k) {
|
|
@@ -936,30 +1061,22 @@ function installGeometry(kit) {
|
|
|
936
1061
|
});
|
|
937
1062
|
geo.setIndex(null);
|
|
938
1063
|
}
|
|
939
|
-
const
|
|
940
|
-
const n =
|
|
1064
|
+
const P = geo.attributes.position.array;
|
|
1065
|
+
const n = geo.attributes.position.count;
|
|
941
1066
|
const faces = n / 3;
|
|
942
1067
|
const FN = new Float64Array(faces * 3);
|
|
943
|
-
const
|
|
944
|
-
const RANGE = 65536;
|
|
945
|
-
function key(i) {
|
|
946
|
-
const x = Math.round(p.getX(i) * 2e3);
|
|
947
|
-
const y = Math.round(p.getY(i) * 2e3);
|
|
948
|
-
const z = Math.round(p.getZ(i) * 2e3);
|
|
949
|
-
if (Math.abs(x) < RANGE && Math.abs(y) < RANGE && Math.abs(z) < RANGE) return ((x + RANGE) * 131072 + (y + RANGE)) * 131072 + (z + RANGE);
|
|
950
|
-
return x + "," + y + "," + z;
|
|
951
|
-
}
|
|
952
|
-
const keys = new Array(n);
|
|
1068
|
+
const out = new Float32Array(n * 3);
|
|
953
1069
|
for (let f = 0; f < faces; f++) {
|
|
954
|
-
const
|
|
955
|
-
const
|
|
956
|
-
const
|
|
957
|
-
const
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
const
|
|
961
|
-
const
|
|
962
|
-
const
|
|
1070
|
+
const o = 9 * f;
|
|
1071
|
+
const ax = P[o];
|
|
1072
|
+
const ay = P[o + 1];
|
|
1073
|
+
const az = P[o + 2];
|
|
1074
|
+
const bx = P[o + 3];
|
|
1075
|
+
const by = P[o + 4];
|
|
1076
|
+
const bz = P[o + 5];
|
|
1077
|
+
const cx = P[o + 6];
|
|
1078
|
+
const cy = P[o + 7];
|
|
1079
|
+
const cz = P[o + 8];
|
|
963
1080
|
const e1x = cx - bx;
|
|
964
1081
|
const e1y = cy - by;
|
|
965
1082
|
const e1z = cz - bz;
|
|
@@ -979,41 +1096,109 @@ function installGeometry(kit) {
|
|
|
979
1096
|
FN[3 * f + 1] = ny;
|
|
980
1097
|
FN[3 * f + 2] = nz;
|
|
981
1098
|
for (let k = 0; k < 3; k++) {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1099
|
+
out[9 * f + 3 * k] = nx;
|
|
1100
|
+
out[9 * f + 3 * k + 1] = ny;
|
|
1101
|
+
out[9 * f + 3 * k + 2] = nz;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
const normal = new THREE.BufferAttribute(out, 3);
|
|
1105
|
+
geo.setAttribute("normal", normal);
|
|
1106
|
+
const token = {};
|
|
1107
|
+
latestCrease.set(geo, token);
|
|
1108
|
+
let size = 16;
|
|
1109
|
+
while (size < n * 2) size *= 2;
|
|
1110
|
+
const mask = size - 1;
|
|
1111
|
+
const slot = new Int32Array(size).fill(-1);
|
|
1112
|
+
const gx = new Int32Array(n);
|
|
1113
|
+
const gy = new Int32Array(n);
|
|
1114
|
+
const gz = new Int32Array(n);
|
|
1115
|
+
const groupOf = new Int32Array(n);
|
|
1116
|
+
let groups = 0;
|
|
1117
|
+
let start2;
|
|
1118
|
+
let members;
|
|
1119
|
+
const cs = Math.cos(deg * PI / 180);
|
|
1120
|
+
let phase = 0;
|
|
1121
|
+
let at = 0;
|
|
1122
|
+
function hashSlice(deadline) {
|
|
1123
|
+
for (; at < n; at++) {
|
|
1124
|
+
if ((at & 1023) === 0 && performance.now() > deadline) return false;
|
|
1125
|
+
const x = Math.round(P[3 * at] * 2e3) | 0;
|
|
1126
|
+
const y = Math.round(P[3 * at + 1] * 2e3) | 0;
|
|
1127
|
+
const z = Math.round(P[3 * at + 2] * 2e3) | 0;
|
|
1128
|
+
let h = (Math.imul(x, 73856093) ^ Math.imul(y, 19349663) ^ Math.imul(z, 83492791)) & mask;
|
|
1129
|
+
let g = slot[h];
|
|
1130
|
+
while (g >= 0 && (gx[g] !== x || gy[g] !== y || gz[g] !== z)) {
|
|
1131
|
+
h = h + 1 & mask;
|
|
1132
|
+
g = slot[h];
|
|
1133
|
+
}
|
|
1134
|
+
if (g < 0) {
|
|
1135
|
+
g = groups++;
|
|
1136
|
+
slot[h] = g;
|
|
1137
|
+
gx[g] = x;
|
|
1138
|
+
gy[g] = y;
|
|
1139
|
+
gz[g] = z;
|
|
1140
|
+
}
|
|
1141
|
+
groupOf[at] = g;
|
|
987
1142
|
}
|
|
1143
|
+
return true;
|
|
988
1144
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
let
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
if (
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1145
|
+
function gather() {
|
|
1146
|
+
start2 = new Int32Array(groups + 1);
|
|
1147
|
+
for (let i = 0; i < n; i++) start2[groupOf[i] + 1]++;
|
|
1148
|
+
for (let g = 0; g < groups; g++) start2[g + 1] += start2[g];
|
|
1149
|
+
const fill = start2.slice(0, groups);
|
|
1150
|
+
members = new Int32Array(n);
|
|
1151
|
+
for (let i = 0; i < n; i++) members[fill[groupOf[i]]++] = i / 3 | 0;
|
|
1152
|
+
}
|
|
1153
|
+
function smoothSlice(deadline) {
|
|
1154
|
+
for (; at < n; at++) {
|
|
1155
|
+
if ((at & 1023) === 0 && performance.now() > deadline) return false;
|
|
1156
|
+
const fi = (at / 3 | 0) * 3;
|
|
1157
|
+
const g = groupOf[at];
|
|
1158
|
+
let sx = 0;
|
|
1159
|
+
let sy = 0;
|
|
1160
|
+
let sz = 0;
|
|
1161
|
+
for (let j = start2[g], end = start2[g + 1]; j < end; j++) {
|
|
1162
|
+
const o = members[j] * 3;
|
|
1163
|
+
if (FN[o] * FN[fi] + FN[o + 1] * FN[fi + 1] + FN[o + 2] * FN[fi + 2] >= cs) {
|
|
1164
|
+
sx += FN[o];
|
|
1165
|
+
sy += FN[o + 1];
|
|
1166
|
+
sz += FN[o + 2];
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (sx * sx + sy * sy + sz * sz < 1e-20) {
|
|
1170
|
+
sx = FN[fi];
|
|
1171
|
+
sy = FN[fi + 1];
|
|
1172
|
+
sz = FN[fi + 2];
|
|
1003
1173
|
}
|
|
1174
|
+
const inv = 1 / (Math.sqrt(sx * sx + sy * sy + sz * sz) || 1);
|
|
1175
|
+
out[3 * at] = sx * inv;
|
|
1176
|
+
out[3 * at + 1] = sy * inv;
|
|
1177
|
+
out[3 * at + 2] = sz * inv;
|
|
1004
1178
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
function step(deadline) {
|
|
1182
|
+
if (latestCrease.get(geo) !== token) return true;
|
|
1183
|
+
if (phase === 0) {
|
|
1184
|
+
if (!hashSlice(deadline)) return false;
|
|
1185
|
+
gather();
|
|
1186
|
+
phase = 1;
|
|
1187
|
+
at = 0;
|
|
1188
|
+
}
|
|
1189
|
+
if (phase === 1) {
|
|
1190
|
+
const done = smoothSlice(deadline);
|
|
1191
|
+
if (deadline !== Infinity) normal.needsUpdate = true;
|
|
1192
|
+
if (!done) return false;
|
|
1193
|
+
phase = 2;
|
|
1194
|
+
geo.userData.crease = true;
|
|
1009
1195
|
}
|
|
1010
|
-
|
|
1011
|
-
out[3 * i] = sx * inv;
|
|
1012
|
-
out[3 * i + 1] = sy * inv;
|
|
1013
|
-
out[3 * i + 2] = sz * inv;
|
|
1196
|
+
return true;
|
|
1014
1197
|
}
|
|
1015
|
-
geo
|
|
1016
|
-
|
|
1198
|
+
return { geo, step };
|
|
1199
|
+
}
|
|
1200
|
+
function crease(geo, deg) {
|
|
1201
|
+
creaseTask(geo, deg).step(Infinity);
|
|
1017
1202
|
return geo;
|
|
1018
1203
|
}
|
|
1019
1204
|
function pathShape(items) {
|
|
@@ -1160,28 +1345,28 @@ function installGeometry(kit) {
|
|
|
1160
1345
|
return g;
|
|
1161
1346
|
}
|
|
1162
1347
|
function cutGeometry(geo, tests) {
|
|
1163
|
-
const
|
|
1348
|
+
const idx = geo.index ? geo.index.array : null;
|
|
1164
1349
|
const names = ["position"].concat(
|
|
1165
1350
|
["color", "uv"].filter(function(n2) {
|
|
1166
|
-
return !!
|
|
1351
|
+
return !!geo.attributes[n2];
|
|
1167
1352
|
})
|
|
1168
1353
|
);
|
|
1169
1354
|
const sizes = names.map(function(n2) {
|
|
1170
|
-
return
|
|
1355
|
+
return geo.attributes[n2].itemSize;
|
|
1171
1356
|
});
|
|
1172
1357
|
const arrs = names.map(function(n2) {
|
|
1173
|
-
return
|
|
1358
|
+
return geo.attributes[n2].array;
|
|
1174
1359
|
});
|
|
1175
|
-
const nv =
|
|
1176
|
-
|
|
1177
|
-
for (let f = 0; f < nv; f += 3) {
|
|
1360
|
+
const nv = idx ? idx.length : geo.attributes.position.count;
|
|
1361
|
+
function readTri(f) {
|
|
1178
1362
|
const t = [];
|
|
1179
1363
|
for (let k = 0; k < 3; k++) {
|
|
1364
|
+
const vi = idx ? idx[f + k] : f + k;
|
|
1180
1365
|
const v = [];
|
|
1181
|
-
for (let a = 0; a < names.length; a++) for (let q = 0; q < sizes[a]; q++) v.push(arrs[a][
|
|
1366
|
+
for (let a = 0; a < names.length; a++) for (let q = 0; q < sizes[a]; q++) v.push(arrs[a][vi * sizes[a] + q]);
|
|
1182
1367
|
t.push(v);
|
|
1183
1368
|
}
|
|
1184
|
-
|
|
1369
|
+
return t;
|
|
1185
1370
|
}
|
|
1186
1371
|
const cut = {};
|
|
1187
1372
|
const n = new V3();
|
|
@@ -1207,60 +1392,177 @@ function installGeometry(kit) {
|
|
|
1207
1392
|
function fan(poly, arr) {
|
|
1208
1393
|
for (let i = 1; i < poly.length - 1; i++) arr.push([poly[0], poly[i], poly[i + 1]]);
|
|
1209
1394
|
}
|
|
1210
|
-
|
|
1211
|
-
const
|
|
1395
|
+
function testTri(T, t, next, rem) {
|
|
1396
|
+
const A = t[0];
|
|
1397
|
+
const B = t[1];
|
|
1398
|
+
const C = t[2];
|
|
1399
|
+
e1.set(B[0] - A[0], B[1] - A[1], B[2] - A[2]);
|
|
1400
|
+
e2.set(C[0] - A[0], C[1] - A[1], C[2] - A[2]);
|
|
1401
|
+
n.crossVectors(e1, e2);
|
|
1402
|
+
const len = n.length();
|
|
1403
|
+
if (len < 1e-12) {
|
|
1404
|
+
next.push(t);
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
n.multiplyScalar(1 / len);
|
|
1408
|
+
ce.set((A[0] + B[0] + C[0]) / 3, (A[1] + B[1] + C[1]) / 3, (A[2] + B[2] + C[2]) / 3);
|
|
1409
|
+
if (T.sel && !T.sel(n, ce)) {
|
|
1410
|
+
next.push(t);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
const d = [T.sdf(A[0], A[1], A[2]), T.sdf(B[0], B[1], B[2]), T.sdf(C[0], C[1], C[2])];
|
|
1414
|
+
const ins = (d[0] < 0 ? 1 : 0) + (d[1] < 0 ? 1 : 0) + (d[2] < 0 ? 1 : 0);
|
|
1415
|
+
if (ins === 0) next.push(t);
|
|
1416
|
+
else if (ins === 3) {
|
|
1417
|
+
if (rem) rem.push(t);
|
|
1418
|
+
} else {
|
|
1419
|
+
fan(clip(t, d, 1), next);
|
|
1420
|
+
if (rem) fan(clip(t, d, -1), rem);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
const segments = [];
|
|
1424
|
+
let total = 0;
|
|
1425
|
+
const ti = tests.length === 1 && tests[0].bounds ? triIndexOf(geo) : void 0;
|
|
1426
|
+
if (ti) {
|
|
1427
|
+
const T = tests[0];
|
|
1428
|
+
const lo = T.bounds.lo;
|
|
1429
|
+
const hi = T.bounds.hi;
|
|
1212
1430
|
const rem = T.tag ? cut[T.tag] = cut[T.tag] || [] : null;
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
if (T.sel && !T.sel(n, ce)) {
|
|
1228
|
-
next.push(t);
|
|
1229
|
-
return;
|
|
1431
|
+
const boxes = ti.boxes;
|
|
1432
|
+
const blocks = ti.blocks;
|
|
1433
|
+
let runFrom = -1;
|
|
1434
|
+
const closeRun = function(end) {
|
|
1435
|
+
if (runFrom < 0) return;
|
|
1436
|
+
segments.push([runFrom, end]);
|
|
1437
|
+
total += end - runFrom;
|
|
1438
|
+
runFrom = -1;
|
|
1439
|
+
};
|
|
1440
|
+
for (let blk = 0, t0 = 0; t0 < ti.triangles; blk++, t0 += TRI_BLOCK) {
|
|
1441
|
+
const j = blk * 6;
|
|
1442
|
+
if (blocks[j + 3] < lo[0] || blocks[j] > hi[0] || blocks[j + 4] < lo[1] || blocks[j + 1] > hi[1] || blocks[j + 5] < lo[2] || blocks[j + 2] > hi[2]) {
|
|
1443
|
+
if (runFrom < 0) runFrom = t0;
|
|
1444
|
+
continue;
|
|
1230
1445
|
}
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1446
|
+
const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
|
|
1447
|
+
for (let t = t0; t < t1; t++) {
|
|
1448
|
+
const q = t * 6;
|
|
1449
|
+
if (boxes[q + 3] < lo[0] || boxes[q] > hi[0] || boxes[q + 4] < lo[1] || boxes[q + 1] > hi[1] || boxes[q + 5] < lo[2] || boxes[q + 2] > hi[2]) {
|
|
1450
|
+
if (runFrom < 0) runFrom = t;
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1453
|
+
closeRun(t);
|
|
1454
|
+
const next = [];
|
|
1455
|
+
testTri(T, readTri(t * 3), next, rem);
|
|
1456
|
+
if (next.length) {
|
|
1457
|
+
segments.push(next);
|
|
1458
|
+
total += next.length;
|
|
1459
|
+
}
|
|
1239
1460
|
}
|
|
1461
|
+
}
|
|
1462
|
+
closeRun(ti.triangles);
|
|
1463
|
+
} else {
|
|
1464
|
+
let tris = [];
|
|
1465
|
+
for (let f = 0; f < nv; f += 3) tris.push(readTri(f));
|
|
1466
|
+
tests.forEach(function(T) {
|
|
1467
|
+
const next = [];
|
|
1468
|
+
const rem = T.tag ? cut[T.tag] = cut[T.tag] || [] : null;
|
|
1469
|
+
tris.forEach(function(t) {
|
|
1470
|
+
testTri(T, t, next, rem);
|
|
1471
|
+
});
|
|
1472
|
+
tris = next;
|
|
1240
1473
|
});
|
|
1241
|
-
tris
|
|
1242
|
-
|
|
1243
|
-
|
|
1474
|
+
segments.push(tris);
|
|
1475
|
+
total = tris.length;
|
|
1476
|
+
}
|
|
1477
|
+
function fill(segs, count, boxesOut2) {
|
|
1244
1478
|
const g = new THREE.BufferGeometry();
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1479
|
+
const dst = names.map(function(_nm, a) {
|
|
1480
|
+
return new Float32Array(count * 3 * sizes[a]);
|
|
1481
|
+
});
|
|
1482
|
+
const w = names.map(function() {
|
|
1483
|
+
return 0;
|
|
1484
|
+
});
|
|
1485
|
+
let wb = 0;
|
|
1486
|
+
segs.forEach(function(seg) {
|
|
1487
|
+
if (typeof seg[0] === "number") {
|
|
1488
|
+
for (let a = 0; a < names.length; a++) {
|
|
1489
|
+
const size = sizes[a];
|
|
1490
|
+
if (!idx) {
|
|
1491
|
+
dst[a].set(arrs[a].subarray(seg[0] * 3 * size, seg[1] * 3 * size), w[a]);
|
|
1492
|
+
w[a] += (seg[1] - seg[0]) * 3 * size;
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
for (let f = seg[0] * 3; f < seg[1] * 3; f++) for (let q = 0; q < size; q++) dst[a][w[a]++] = arrs[a][idx[f] * size + q];
|
|
1496
|
+
}
|
|
1497
|
+
if (boxesOut2 && ti) {
|
|
1498
|
+
boxesOut2.set(ti.boxes.subarray(seg[0] * 6, seg[1] * 6), wb);
|
|
1499
|
+
wb += (seg[1] - seg[0]) * 6;
|
|
1500
|
+
}
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
seg.forEach(function(t) {
|
|
1504
|
+
if (boxesOut2) {
|
|
1505
|
+
for (let k = 0; k < 3; k++) {
|
|
1506
|
+
boxesOut2[wb + k] = Math.fround(Math.min(t[0][k], t[1][k], t[2][k]));
|
|
1507
|
+
boxesOut2[wb + 3 + k] = Math.fround(Math.max(t[0][k], t[1][k], t[2][k]));
|
|
1508
|
+
}
|
|
1509
|
+
wb += 6;
|
|
1510
|
+
}
|
|
1511
|
+
let off = 0;
|
|
1512
|
+
for (let a = 0; a < names.length; a++) {
|
|
1513
|
+
for (let k = 0; k < 3; k++) for (let q = 0; q < sizes[a]; q++) dst[a][w[a]++] = t[k][off + q];
|
|
1514
|
+
off += sizes[a];
|
|
1515
|
+
}
|
|
1251
1516
|
});
|
|
1252
|
-
|
|
1253
|
-
|
|
1517
|
+
});
|
|
1518
|
+
names.forEach(function(nm, a) {
|
|
1519
|
+
g.setAttribute(nm, new THREE.BufferAttribute(dst[a], sizes[a]));
|
|
1254
1520
|
});
|
|
1255
1521
|
g.userData.crease = true;
|
|
1256
1522
|
return g;
|
|
1257
1523
|
}
|
|
1258
|
-
const
|
|
1524
|
+
const boxesOut = ti ? new Float64Array(total * 6) : void 0;
|
|
1525
|
+
const out = { geo: fill(segments, total, boxesOut), cut: {}, tasks: {} };
|
|
1526
|
+
if (boxesOut) storeTriIndex(out.geo, boxesOut);
|
|
1259
1527
|
Object.keys(cut).forEach(function(k) {
|
|
1260
|
-
|
|
1528
|
+
const piece = fill([cut[k]], cut[k].length);
|
|
1529
|
+
const mode = tests.find(function(T) {
|
|
1530
|
+
return T.tag === k;
|
|
1531
|
+
}).pieces;
|
|
1532
|
+
if (mode === "none") out.cut[k] = piece;
|
|
1533
|
+
else if (mode === "later") {
|
|
1534
|
+
out.cut[k] = piece;
|
|
1535
|
+
out.tasks[k] = creaseTask(piece, 42);
|
|
1536
|
+
} else out.cut[k] = crease(piece, 42);
|
|
1261
1537
|
});
|
|
1262
1538
|
return out;
|
|
1263
1539
|
}
|
|
1540
|
+
function refreshBounds(geo) {
|
|
1541
|
+
const found = boundsFromIndex(geo);
|
|
1542
|
+
if (!found) {
|
|
1543
|
+
geo.computeBoundingSphere();
|
|
1544
|
+
geo.computeBoundingBox();
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
if (geo.boundingBox && geo.boundingSphere && boundsDone.get(geo) === found.version) return;
|
|
1548
|
+
const b = found.box;
|
|
1549
|
+
if (!geo.boundingBox) geo.boundingBox = new THREE.Box3();
|
|
1550
|
+
geo.boundingBox.min.set(b[0], b[1], b[2]);
|
|
1551
|
+
geo.boundingBox.max.set(b[3], b[4], b[5]);
|
|
1552
|
+
if (!geo.boundingSphere) geo.boundingSphere = new THREE.Sphere();
|
|
1553
|
+
const center = geo.boundingBox.getCenter(geo.boundingSphere.center);
|
|
1554
|
+
const P = geo.attributes.position.array;
|
|
1555
|
+
let maxRadiusSq = 0;
|
|
1556
|
+
for (let i = 0; i < P.length; i += 3) {
|
|
1557
|
+
const dx = center.x - P[i];
|
|
1558
|
+
const dy = center.y - P[i + 1];
|
|
1559
|
+
const dz = center.z - P[i + 2];
|
|
1560
|
+
maxRadiusSq = Math.max(maxRadiusSq, dx * dx + dy * dy + dz * dz);
|
|
1561
|
+
}
|
|
1562
|
+
geo.boundingSphere.radius = Math.sqrt(maxRadiusSq);
|
|
1563
|
+
boundsDone.set(geo, found.version);
|
|
1564
|
+
}
|
|
1565
|
+
const boundsDone = /* @__PURE__ */ new WeakMap();
|
|
1264
1566
|
function mergeGeometries(list) {
|
|
1265
1567
|
const pos = [];
|
|
1266
1568
|
const nor = [];
|
|
@@ -1391,7 +1693,7 @@ function installGeometry(kit) {
|
|
|
1391
1693
|
}
|
|
1392
1694
|
};
|
|
1393
1695
|
};
|
|
1394
|
-
Object.assign(I, { roundedBoxGeometry, taper, subdivide, crease, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject });
|
|
1696
|
+
Object.assign(I, { roundedBoxGeometry, taper, subdivide, crease, creaseTask, refreshBounds, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject });
|
|
1395
1697
|
}
|
|
1396
1698
|
|
|
1397
1699
|
// src/context.ts
|
|
@@ -6721,6 +7023,8 @@ function installZoneDecals(kit) {
|
|
|
6721
7023
|
const pos = g && g.attributes && g.attributes.position;
|
|
6722
7024
|
return o.raycast === THREE.Mesh.prototype.raycast && !o.isSkinnedMesh && !Array.isArray(o.material) && pos && !pos.isInterleavedBufferAttribute && pos.itemSize === 3 && !g.groups.length && !(g.morphAttributes && g.morphAttributes.position) && (g.index ? g.index.count : pos.count) / 3 >= PROXY_MIN_TRIANGLES;
|
|
6723
7025
|
}
|
|
7026
|
+
let _keep = new Uint32Array(0);
|
|
7027
|
+
let _box = new Float32Array(0);
|
|
6724
7028
|
function proxyIn(o, Mw, R) {
|
|
6725
7029
|
_pm.copy(o.matrixWorld).invert().multiply(Mw);
|
|
6726
7030
|
const lo = [Infinity, Infinity, Infinity];
|
|
@@ -6733,39 +7037,48 @@ function installZoneDecals(kit) {
|
|
|
6733
7037
|
}
|
|
6734
7038
|
}
|
|
6735
7039
|
const g = o.geometry;
|
|
6736
|
-
const
|
|
7040
|
+
const ti = triIndexOf(g);
|
|
7041
|
+
if (!ti) return null;
|
|
6737
7042
|
const ix = g.index ? g.index.array : null;
|
|
6738
|
-
const
|
|
6739
|
-
const
|
|
7043
|
+
const boxes = ti.boxes;
|
|
7044
|
+
const blocks = ti.blocks;
|
|
7045
|
+
if (_keep.length < ti.triangles * 3) {
|
|
7046
|
+
_keep = new Uint32Array(ti.triangles * 3);
|
|
7047
|
+
_box = new Float32Array(ti.triangles * 6);
|
|
7048
|
+
}
|
|
7049
|
+
const keep = _keep;
|
|
7050
|
+
const box = _box;
|
|
6740
7051
|
let nk = 0;
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
const
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
for (let
|
|
6747
|
-
const
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
keep[nk++] = ix ? ix[t + 1] : t + 1;
|
|
6755
|
-
keep[nk++] = ix ? ix[t + 2] : t + 2;
|
|
7052
|
+
let nt = 0;
|
|
7053
|
+
for (let blk = 0, t0 = 0; t0 < ti.triangles; blk++, t0 += TRI_BLOCK) {
|
|
7054
|
+
const j = blk * 6;
|
|
7055
|
+
if (blocks[j + 3] < lo[0] || blocks[j] > hi[0] || blocks[j + 4] < lo[1] || blocks[j + 1] > hi[1] || blocks[j + 5] < lo[2] || blocks[j + 2] > hi[2]) continue;
|
|
7056
|
+
const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
|
|
7057
|
+
for (let t = t0; t < t1; t++) {
|
|
7058
|
+
const q = t * 6;
|
|
7059
|
+
if (boxes[q + 3] < lo[0] || boxes[q] > hi[0] || boxes[q + 4] < lo[1] || boxes[q + 1] > hi[1] || boxes[q + 5] < lo[2] || boxes[q + 2] > hi[2]) continue;
|
|
7060
|
+
keep[nk++] = ix ? ix[t * 3] : t * 3;
|
|
7061
|
+
keep[nk++] = ix ? ix[t * 3 + 1] : t * 3 + 1;
|
|
7062
|
+
keep[nk++] = ix ? ix[t * 3 + 2] : t * 3 + 2;
|
|
7063
|
+
for (let k = 0; k < 6; k++) box[nt * 6 + k] = boxes[q + k];
|
|
7064
|
+
nt++;
|
|
6756
7065
|
}
|
|
6757
7066
|
}
|
|
6758
7067
|
if (!nk) return null;
|
|
6759
7068
|
const kept = keep.slice(0, nk);
|
|
6760
|
-
const
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
const b =
|
|
6764
|
-
const d = kept[t + 2] * 3;
|
|
7069
|
+
const keptBox = box.slice(0, nt * 6);
|
|
7070
|
+
const keptBlocks = new Float32Array(Math.ceil(nt / TRI_BLOCK) * 6);
|
|
7071
|
+
for (let blk = 0; blk * TRI_BLOCK < nt; blk++) {
|
|
7072
|
+
const b = blk * 6;
|
|
6765
7073
|
for (let k = 0; k < 3; k++) {
|
|
6766
|
-
|
|
6767
|
-
|
|
7074
|
+
keptBlocks[b + k] = Infinity;
|
|
7075
|
+
keptBlocks[b + 3 + k] = -Infinity;
|
|
6768
7076
|
}
|
|
7077
|
+
for (let t = blk * TRI_BLOCK, t1 = Math.min(nt, t + TRI_BLOCK); t < t1; t++)
|
|
7078
|
+
for (let k = 0; k < 3; k++) {
|
|
7079
|
+
if (keptBox[t * 6 + k] < keptBlocks[b + k]) keptBlocks[b + k] = keptBox[t * 6 + k];
|
|
7080
|
+
if (keptBox[t * 6 + 3 + k] > keptBlocks[b + 3 + k]) keptBlocks[b + 3 + k] = keptBox[t * 6 + 3 + k];
|
|
7081
|
+
}
|
|
6769
7082
|
}
|
|
6770
7083
|
const pg = new THREE.BufferGeometry();
|
|
6771
7084
|
pg.setAttribute("position", g.attributes.position);
|
|
@@ -6776,7 +7089,8 @@ function installZoneDecals(kit) {
|
|
|
6776
7089
|
proxy.layers.mask = o.layers.mask;
|
|
6777
7090
|
proxy.proxyOf = o;
|
|
6778
7091
|
proxy.kept = kept;
|
|
6779
|
-
proxy.keptBox =
|
|
7092
|
+
proxy.keptBox = keptBox;
|
|
7093
|
+
proxy.keptBlocks = keptBlocks;
|
|
6780
7094
|
return proxy;
|
|
6781
7095
|
}
|
|
6782
7096
|
function narrowTo(rc, proxy) {
|
|
@@ -6796,13 +7110,21 @@ function installZoneDecals(kit) {
|
|
|
6796
7110
|
const hi2 = Math.max(z0, _pv.z) + 1e-4;
|
|
6797
7111
|
const K = proxy.kept;
|
|
6798
7112
|
const X = proxy.keptBox;
|
|
7113
|
+
const KB = proxy.keptBlocks;
|
|
7114
|
+
const nt = K.length / 3;
|
|
6799
7115
|
const dst = proxy.geometry.index.array;
|
|
6800
7116
|
let m = 0;
|
|
6801
|
-
for (let
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
7117
|
+
for (let blk = 0, t0 = 0; t0 < nt; blk++, t0 += TRI_BLOCK) {
|
|
7118
|
+
const b = blk * 6;
|
|
7119
|
+
if (KB[b + 3] < lo0 || KB[b] > hi0 || KB[b + 4] < lo1 || KB[b + 1] > hi1 || KB[b + 5] < lo2 || KB[b + 2] > hi2) continue;
|
|
7120
|
+
const t1 = Math.min(nt, t0 + TRI_BLOCK);
|
|
7121
|
+
for (let t = t0; t < t1; t++) {
|
|
7122
|
+
const j = t * 6;
|
|
7123
|
+
if (X[j + 3] < lo0 || X[j] > hi0 || X[j + 4] < lo1 || X[j + 1] > hi1 || X[j + 5] < lo2 || X[j + 2] > hi2) continue;
|
|
7124
|
+
dst[m++] = K[t * 3];
|
|
7125
|
+
dst[m++] = K[t * 3 + 1];
|
|
7126
|
+
dst[m++] = K[t * 3 + 2];
|
|
7127
|
+
}
|
|
6806
7128
|
}
|
|
6807
7129
|
proxy.geometry.setDrawRange(0, m);
|
|
6808
7130
|
}
|
|
@@ -7220,6 +7542,8 @@ function installZoneDent(kit) {
|
|
|
7220
7542
|
irel.copy(rel).invert();
|
|
7221
7543
|
const pos = g.attributes.position;
|
|
7222
7544
|
let changed = false;
|
|
7545
|
+
const liveIndex = liveTriIndex(g);
|
|
7546
|
+
const movedVertices = [];
|
|
7223
7547
|
const near = boxInFrame(B, irel, v);
|
|
7224
7548
|
for (let i = 0; i < pos.count; i++) {
|
|
7225
7549
|
v.fromBufferAttribute(pos, i);
|
|
@@ -7231,6 +7555,7 @@ function installZoneDent(kit) {
|
|
|
7231
7555
|
if (opt.extra) opt.extra(v, f);
|
|
7232
7556
|
v.applyMatrix4(irel);
|
|
7233
7557
|
pos.setXYZ(i, v.x, v.y, v.z);
|
|
7558
|
+
movedVertices.push(i);
|
|
7234
7559
|
changed = true;
|
|
7235
7560
|
}
|
|
7236
7561
|
if (opt.extraAll) {
|
|
@@ -7239,12 +7564,14 @@ function installZoneDent(kit) {
|
|
|
7239
7564
|
if (opt.extraAll(v)) {
|
|
7240
7565
|
v.applyMatrix4(irel);
|
|
7241
7566
|
pos.setXYZ(j, v.x, v.y, v.z);
|
|
7567
|
+
movedVertices.push(j);
|
|
7242
7568
|
changed = true;
|
|
7243
7569
|
}
|
|
7244
7570
|
}
|
|
7245
7571
|
}
|
|
7246
7572
|
if (changed) {
|
|
7247
7573
|
pos.needsUpdate = true;
|
|
7574
|
+
if (liveIndex) touchTriIndex(g, liveIndex, movedVertices);
|
|
7248
7575
|
dirty.add(msh);
|
|
7249
7576
|
}
|
|
7250
7577
|
if (changed || boundsDue) {
|
|
@@ -7275,6 +7602,26 @@ function installZoneDent(kit) {
|
|
|
7275
7602
|
});
|
|
7276
7603
|
return { field, moved, ax, a, cu, cv, hu, hv, outer };
|
|
7277
7604
|
}
|
|
7605
|
+
function panelBoundsIn(rel, rect, B, a, ax) {
|
|
7606
|
+
const det = rel.determinant();
|
|
7607
|
+
if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return void 0;
|
|
7608
|
+
const back = rel.clone().invert();
|
|
7609
|
+
const lo = [Infinity, Infinity, Infinity];
|
|
7610
|
+
const hi = [-Infinity, -Infinity, -Infinity];
|
|
7611
|
+
const q = new V3();
|
|
7612
|
+
for (let i = 0; i < 8; i++) {
|
|
7613
|
+
q.setComponent(ax[0], i & 1 ? rect[1] : rect[0]);
|
|
7614
|
+
q.setComponent(ax[1], i & 2 ? rect[3] : rect[2]);
|
|
7615
|
+
q.setComponent(a, i & 4 ? I.boxHi(B, a) : I.boxLo(B, a));
|
|
7616
|
+
q.applyMatrix4(back);
|
|
7617
|
+
for (let k = 0; k < 3; k++) {
|
|
7618
|
+
lo[k] = Math.min(lo[k], q.getComponent(k));
|
|
7619
|
+
hi[k] = Math.max(hi[k], q.getComponent(k));
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7622
|
+
const pad = 1e-3;
|
|
7623
|
+
return { lo: lo.map((x) => x - pad), hi: hi.map((x) => x + pad) };
|
|
7624
|
+
}
|
|
7278
7625
|
function cutPanel(c, z, rect, keep, dirty, o) {
|
|
7279
7626
|
o = o || {};
|
|
7280
7627
|
const B = z.box;
|
|
@@ -7307,6 +7654,7 @@ function installZoneDent(kit) {
|
|
|
7307
7654
|
}
|
|
7308
7655
|
const test = {
|
|
7309
7656
|
tag: "part",
|
|
7657
|
+
pieces: keep ? o.pieceTasks ? "later" : "crease" : "none",
|
|
7310
7658
|
sel: o.anyN || z.cutAll ? null : function(n) {
|
|
7311
7659
|
nv.copy(n).applyMatrix3(nm).normalize();
|
|
7312
7660
|
return nv.dot(outN) > 0.3;
|
|
@@ -7325,13 +7673,12 @@ function installZoneDent(kit) {
|
|
|
7325
7673
|
return q;
|
|
7326
7674
|
}
|
|
7327
7675
|
};
|
|
7328
|
-
const r = cutGeometry(g, [test]);
|
|
7676
|
+
const r = cutGeometry(g, [{ ...test, bounds: panelBoundsIn(rel, rect, B, a, ax) }]);
|
|
7329
7677
|
const cg = r.cut.part;
|
|
7330
7678
|
if (!cg || !cg.attributes.position.count) return;
|
|
7331
7679
|
g.dispose();
|
|
7332
7680
|
msh.geometry = r.geo;
|
|
7333
|
-
r.geo
|
|
7334
|
-
r.geo.computeBoundingBox();
|
|
7681
|
+
I.refreshBounds(r.geo);
|
|
7335
7682
|
dirty.add(msh);
|
|
7336
7683
|
if (!keep) {
|
|
7337
7684
|
cg.dispose();
|
|
@@ -7344,6 +7691,7 @@ function installZoneDent(kit) {
|
|
|
7344
7691
|
rel.decompose(pm.position, pm.quaternion, pm.scale);
|
|
7345
7692
|
c.vehicle.add(pm);
|
|
7346
7693
|
pm.updateMatrixWorld(true);
|
|
7694
|
+
if (o.pieceTasks) o.pieceTasks.set(pm, r.tasks.part);
|
|
7347
7695
|
pieces.push({ mesh: pm, cut: true });
|
|
7348
7696
|
});
|
|
7349
7697
|
return pieces;
|
|
@@ -10983,7 +11331,15 @@ var VehicleVisuals = class {
|
|
|
10983
11331
|
__publicField(this, "gone", /* @__PURE__ */ new Set());
|
|
10984
11332
|
/** Shows or hides the plate and the recess of a door or lid by its state (see `showWhenOpen`). */
|
|
10985
11333
|
__publicField(this, "syncPlates", /* @__PURE__ */ new Map());
|
|
11334
|
+
/** Doors and lids whose own skin was cut from the body and hung on the hinge (true), or that had none to take and keep the plate (false). */
|
|
11335
|
+
__publicField(this, "skins", /* @__PURE__ */ new Map());
|
|
10986
11336
|
__publicField(this, "lightsOn", true);
|
|
11337
|
+
/** Heavy body meshes whose triangle index is still to build (null once done). */
|
|
11338
|
+
__publicField(this, "warming");
|
|
11339
|
+
/** A panel was torn off since the last `pump`: that frame already paid for the cut, the smoothing starts on the next one. */
|
|
11340
|
+
__publicField(this, "tornThisFrame", false);
|
|
11341
|
+
/** Normal smoothing still running, by mesh: a mesh cut again gets a new task and the old one is dropped. */
|
|
11342
|
+
__publicField(this, "smoothing", /* @__PURE__ */ new Map());
|
|
10987
11343
|
__publicField(this, "hood");
|
|
10988
11344
|
this.kit = kit;
|
|
10989
11345
|
this.c = c;
|
|
@@ -10993,6 +11349,8 @@ var VehicleVisuals = class {
|
|
|
10993
11349
|
for (const p of model.parts) this.byId.set(p.id, p);
|
|
10994
11350
|
c.root.updateMatrixWorld(true);
|
|
10995
11351
|
this.hood = this.nameHood();
|
|
11352
|
+
this.warming = c.deform.filter((msh) => msh.geometry && msh.geometry.attributes.position && msh.geometry.attributes.position.count >= 1500);
|
|
11353
|
+
if (!this.warming.length) this.warming = null;
|
|
10996
11354
|
for (const p of model.parts) {
|
|
10997
11355
|
if (p.role === "door" || p.role === "lid") this.makePlate(p);
|
|
10998
11356
|
else if (p.role === "mirror" && !this.mirrorObjects(p).length) this.makeMirror(p);
|
|
@@ -11128,11 +11486,21 @@ var VehicleVisuals = class {
|
|
|
11128
11486
|
* keeps the shape of its model instead of flat panels over its curved sides. Follows the hinge's rotation, whoever turns it (the clips of a host, `detach`).
|
|
11129
11487
|
*/
|
|
11130
11488
|
showWhenOpen(id, piv, panel, recess) {
|
|
11489
|
+
let busy = false;
|
|
11131
11490
|
const sync = () => {
|
|
11491
|
+
if (busy) return;
|
|
11132
11492
|
const r = piv.rotation;
|
|
11133
11493
|
const open = Math.abs(r.x) + Math.abs(r.y) + Math.abs(r.z) > 1e-3 || this.gone.has(id) || piv.parent !== this.c.vehicle;
|
|
11134
|
-
|
|
11135
|
-
|
|
11494
|
+
if (open && !this.gone.has(id) && piv.parent === this.c.vehicle && !this.skins.has(id)) {
|
|
11495
|
+
busy = true;
|
|
11496
|
+
try {
|
|
11497
|
+
this.skins.set(id, this.takeSkin(id, piv));
|
|
11498
|
+
} finally {
|
|
11499
|
+
busy = false;
|
|
11500
|
+
}
|
|
11501
|
+
}
|
|
11502
|
+
panel.visible = open && !this.skins.get(id);
|
|
11503
|
+
recess.visible = open && !this.skins.get(id);
|
|
11136
11504
|
};
|
|
11137
11505
|
const euler = piv.rotation;
|
|
11138
11506
|
const quaternion = piv.quaternion;
|
|
@@ -11149,6 +11517,58 @@ var VehicleVisuals = class {
|
|
|
11149
11517
|
this.syncPlates.set(id, sync);
|
|
11150
11518
|
sync();
|
|
11151
11519
|
}
|
|
11520
|
+
/**
|
|
11521
|
+
* Cuts the skin of a door or lid zone out of the body (as the damage's hanging door does) and hangs it, with the thin parts on it (trim, handle) and, for a door, the side
|
|
11522
|
+
* window over it, on the hinge. Done with the hinge closed, so every piece keeps its place; answers whether there was skin to take.
|
|
11523
|
+
*/
|
|
11524
|
+
takeSkin(id, piv) {
|
|
11525
|
+
const p = this.byId.get(id);
|
|
11526
|
+
const z = p && this.zone(p);
|
|
11527
|
+
if (!p || !z) return false;
|
|
11528
|
+
const I = this.I;
|
|
11529
|
+
const B = z.box;
|
|
11530
|
+
const q = piv.quaternion.clone();
|
|
11531
|
+
piv.quaternion.identity();
|
|
11532
|
+
this.c.root.updateMatrixWorld(true);
|
|
11533
|
+
const inv = I.worldInverseOf(this.c);
|
|
11534
|
+
let objs = [];
|
|
11535
|
+
try {
|
|
11536
|
+
if (p.role === "door") {
|
|
11537
|
+
const dirty = /* @__PURE__ */ new Set();
|
|
11538
|
+
const rect = [B.x0 + 0.03, B.x1 - 0.03, B.y0 + Math.min(0.08, (B.y1 - B.y0) * 0.1), B.y1 - 0.02];
|
|
11539
|
+
const pcs = I.cutPanel(this.c, z, rect, true, dirty).map((x) => x.mesh).filter((m) => !!m);
|
|
11540
|
+
this.mend(dirty);
|
|
11541
|
+
if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv), ...I.windowsOver(this.c, z, inv)];
|
|
11542
|
+
} else {
|
|
11543
|
+
const pcs = this.cutZone(z);
|
|
11544
|
+
if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv)];
|
|
11545
|
+
}
|
|
11546
|
+
} catch {
|
|
11547
|
+
objs = [];
|
|
11548
|
+
}
|
|
11549
|
+
const deform = this.c.deform ?? [];
|
|
11550
|
+
for (const o of objs) {
|
|
11551
|
+
if (!o.parent || o === piv) continue;
|
|
11552
|
+
piv.attach(o);
|
|
11553
|
+
o.traverse((x) => {
|
|
11554
|
+
x.userData.noFollow = true;
|
|
11555
|
+
});
|
|
11556
|
+
const di = deform.indexOf(o);
|
|
11557
|
+
if (di >= 0) deform.splice(di, 1);
|
|
11558
|
+
}
|
|
11559
|
+
piv.quaternion.copy(q);
|
|
11560
|
+
this.c.root.updateMatrixWorld(true);
|
|
11561
|
+
return objs.length > 0;
|
|
11562
|
+
}
|
|
11563
|
+
mend(dirty) {
|
|
11564
|
+
dirty.forEach((msh) => {
|
|
11565
|
+
const g = msh.geometry;
|
|
11566
|
+
if (g.userData.crease || !g.index) this.I.crease(g, 42);
|
|
11567
|
+
else g.computeVertexNormals();
|
|
11568
|
+
g.computeBoundingSphere();
|
|
11569
|
+
g.computeBoundingBox();
|
|
11570
|
+
});
|
|
11571
|
+
}
|
|
11152
11572
|
makeMirror(p) {
|
|
11153
11573
|
const [cx, cy, cz] = p.box.center;
|
|
11154
11574
|
const s = cz < 0 ? -1 : 1;
|
|
@@ -11286,6 +11706,31 @@ var VehicleVisuals = class {
|
|
|
11286
11706
|
this.I.flattenTire(w, Math.min(0.5, 0.12 + 0.38 * melt));
|
|
11287
11707
|
}
|
|
11288
11708
|
}
|
|
11709
|
+
/** Smooths the normals of a cut mesh a slice per frame (see `pump`); until then it draws with flat face normals. */
|
|
11710
|
+
smoothLater(msh) {
|
|
11711
|
+
this.smoothing.set(msh, this.I.creaseTask(msh.geometry, 42));
|
|
11712
|
+
this.tornThisFrame = true;
|
|
11713
|
+
}
|
|
11714
|
+
/** Spends at most `budgetMs` finishing the pending normal smoothing. Call once per frame. */
|
|
11715
|
+
pump(budgetMs = 2.5) {
|
|
11716
|
+
if (this.tornThisFrame) {
|
|
11717
|
+
this.tornThisFrame = false;
|
|
11718
|
+
return;
|
|
11719
|
+
}
|
|
11720
|
+
if (!this.smoothing.size && !this.warming) return;
|
|
11721
|
+
const deadline = performance.now() + budgetMs;
|
|
11722
|
+
for (const [msh, task] of this.smoothing) {
|
|
11723
|
+
if (msh.geometry !== task.geo || task.step(deadline)) this.smoothing.delete(msh);
|
|
11724
|
+
if (performance.now() >= deadline) return;
|
|
11725
|
+
}
|
|
11726
|
+
this.warmIndexes(deadline);
|
|
11727
|
+
}
|
|
11728
|
+
/** Measures the triangles of the heavy body meshes once, a slice per frame, so the first panel torn off finds them ready (see `triIndexOf`). */
|
|
11729
|
+
warmIndexes(deadline) {
|
|
11730
|
+
if (!this.warming) return;
|
|
11731
|
+
this.warming = this.warming.filter((msh) => !warmTriIndex(msh.geometry, deadline));
|
|
11732
|
+
if (!this.warming.length) this.warming = null;
|
|
11733
|
+
}
|
|
11289
11734
|
/** Moves the panel of a lost zone out of the body (the kit's torn-off look). */
|
|
11290
11735
|
tearOff(p) {
|
|
11291
11736
|
const z = this.zone(p);
|
|
@@ -11298,10 +11743,9 @@ var VehicleVisuals = class {
|
|
|
11298
11743
|
}
|
|
11299
11744
|
dirty.forEach((msh) => {
|
|
11300
11745
|
const g = msh.geometry;
|
|
11301
|
-
if (g.userData.crease || !g.index) this.
|
|
11746
|
+
if (g.userData.crease || !g.index) this.smoothLater(msh);
|
|
11302
11747
|
else g.computeVertexNormals();
|
|
11303
|
-
|
|
11304
|
-
g.computeBoundingBox();
|
|
11748
|
+
this.I.refreshBounds(g);
|
|
11305
11749
|
});
|
|
11306
11750
|
this.gone.add(p.id);
|
|
11307
11751
|
}
|
|
@@ -11444,17 +11888,19 @@ var VehicleVisuals = class {
|
|
|
11444
11888
|
const mg = Math.min(0.05, (u1 - u0) * 0.08, (v1 - v0) * 0.08);
|
|
11445
11889
|
const dirty = /* @__PURE__ */ new Set();
|
|
11446
11890
|
let pcs = [];
|
|
11891
|
+
const pieceTasks = /* @__PURE__ */ new Map();
|
|
11447
11892
|
try {
|
|
11448
|
-
pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty);
|
|
11893
|
+
pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty, { pieceTasks });
|
|
11449
11894
|
} catch {
|
|
11450
11895
|
pcs = [];
|
|
11451
11896
|
}
|
|
11897
|
+
pieceTasks.forEach((task, mesh) => this.smoothing.set(mesh, task));
|
|
11898
|
+
this.tornThisFrame = true;
|
|
11452
11899
|
dirty.forEach((msh) => {
|
|
11453
11900
|
const g = msh.geometry;
|
|
11454
|
-
if (g.userData.crease || !g.index)
|
|
11901
|
+
if (g.userData.crease || !g.index) this.smoothLater(msh);
|
|
11455
11902
|
else g.computeVertexNormals();
|
|
11456
|
-
|
|
11457
|
-
g.computeBoundingBox();
|
|
11903
|
+
I.refreshBounds(g);
|
|
11458
11904
|
});
|
|
11459
11905
|
return pcs.map((q) => q.mesh).filter((m) => !!m);
|
|
11460
11906
|
}
|
|
@@ -12233,7 +12679,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12233
12679
|
specCache = { name: options.name ?? c.spec.name ?? c.key, parts, joints, tags: ["vehicle", kindOf(c)] };
|
|
12234
12680
|
return specCache;
|
|
12235
12681
|
};
|
|
12236
|
-
const
|
|
12682
|
+
const buildState = () => {
|
|
12237
12683
|
const parts = model.parts.map((d) => {
|
|
12238
12684
|
const p = ps.get(d.id);
|
|
12239
12685
|
const marked = p.dents.length > 0 || p.holes.length > 0 || p.cracks.length > 0;
|
|
@@ -12270,7 +12716,15 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12270
12716
|
}));
|
|
12271
12717
|
return { id, name: options.name ?? c.spec.name ?? c.key, position: [0, 0, 0], rotation: [0, 0, 0, 1], parts, joints, groups: groupsCache.map((g) => [...g]), destroyed: parts.every((p) => p.status === "broken" || p.status === "melted" || p.status === "ashes") };
|
|
12272
12718
|
};
|
|
12719
|
+
let stateCache;
|
|
12720
|
+
const state = () => stateCache ?? (stateCache = buildState());
|
|
12721
|
+
const isSimulating = () => {
|
|
12722
|
+
if (leaks.size > 0) return true;
|
|
12723
|
+
for (const p of ps.values()) if (!p.lost && (p.burning || p.temp > AMBIENT)) return true;
|
|
12724
|
+
return false;
|
|
12725
|
+
};
|
|
12273
12726
|
const hit = (h) => {
|
|
12727
|
+
stateCache = void 0;
|
|
12274
12728
|
const out = [];
|
|
12275
12729
|
const hh = h.space === "local" ? { ...h, space: "world", point: toWorld(h.point) } : h;
|
|
12276
12730
|
if (hh.space === "local" || !hh.point) return out;
|
|
@@ -12297,6 +12751,8 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12297
12751
|
clock += dt;
|
|
12298
12752
|
const out = queue;
|
|
12299
12753
|
queue = [];
|
|
12754
|
+
const wasSimulating = isSimulating();
|
|
12755
|
+
const handledBefore = (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0);
|
|
12300
12756
|
const hood = c.hood;
|
|
12301
12757
|
if (hood) {
|
|
12302
12758
|
const sign = hood.sign || 1;
|
|
@@ -12317,12 +12773,15 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12317
12773
|
afterBlast(out);
|
|
12318
12774
|
afterRoll(out);
|
|
12319
12775
|
applyEffects();
|
|
12776
|
+
vis?.pump();
|
|
12777
|
+
if (wasSimulating || out.length > 0 || handledBefore !== (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0)) stateCache = void 0;
|
|
12320
12778
|
return out;
|
|
12321
12779
|
};
|
|
12322
12780
|
const disassemble = (jointId, tool, dt) => {
|
|
12323
12781
|
const j = js.find((x) => x.def.id === jointId);
|
|
12324
12782
|
if (!j || !j.def.tools.includes(tool)) return -1;
|
|
12325
12783
|
if (j.open) return 1;
|
|
12784
|
+
stateCache = void 0;
|
|
12326
12785
|
j.progress = Math.min(1, j.progress + dt / j.def.seconds);
|
|
12327
12786
|
const step = Math.floor(j.progress * 4) / 4;
|
|
12328
12787
|
if (step > j.reported && j.progress < 1) {
|
|
@@ -12338,6 +12797,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12338
12797
|
return j.progress;
|
|
12339
12798
|
};
|
|
12340
12799
|
const extinguish = (partId) => {
|
|
12800
|
+
stateCache = void 0;
|
|
12341
12801
|
for (const p of ps.values()) {
|
|
12342
12802
|
if (partId && p.def.id !== partId) continue;
|
|
12343
12803
|
if (p.burning) {
|
|
@@ -12351,6 +12811,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12351
12811
|
}
|
|
12352
12812
|
};
|
|
12353
12813
|
const reset = () => {
|
|
12814
|
+
stateCache = void 0;
|
|
12354
12815
|
const old = c;
|
|
12355
12816
|
const parent = old.root.parent;
|
|
12356
12817
|
const next = kit.build(old.key, old.state, old.scenario != null ? { scenario: old.scenario } : void 0);
|
|
@@ -12368,6 +12829,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12368
12829
|
setup();
|
|
12369
12830
|
};
|
|
12370
12831
|
const rollover = (side2 = 1) => {
|
|
12832
|
+
stateCache = void 0;
|
|
12371
12833
|
if (kit.roll(c, side2)) rolled = true;
|
|
12372
12834
|
void rolled;
|
|
12373
12835
|
};
|