@adatechnology/game-vehicles 0.4.5 → 0.4.7
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 +666 -184
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +633 -151
- 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
|
+
}
|
|
1003
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];
|
|
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
|
|
@@ -4745,8 +5047,15 @@ function installGlassDamage(kit) {
|
|
|
4745
5047
|
x.arc(cx, cy, 26 * s, 0, PI * 2);
|
|
4746
5048
|
x.fill();
|
|
4747
5049
|
}
|
|
5050
|
+
const NO_CANVAS = new Proxy(function() {
|
|
5051
|
+
}, { get: () => NO_CANVAS, apply: () => NO_CANVAS, set: () => true });
|
|
4748
5052
|
function crackGlass(c, msh, p, force, sc) {
|
|
4749
5053
|
const G = msh.userData.glass;
|
|
5054
|
+
if (G.cracksFreed) {
|
|
5055
|
+
drawWeb(NO_CANVAS, 0, 0, sc != null ? sc : 0.6 + force * 0.5, Math.max(0.4, G.aspect || 1), c.rand);
|
|
5056
|
+
G.hits++;
|
|
5057
|
+
return;
|
|
5058
|
+
}
|
|
4750
5059
|
if (!G.cv) {
|
|
4751
5060
|
G.cv = document2.createElement("canvas");
|
|
4752
5061
|
G.cv.width = G.cv.height = 256;
|
|
@@ -4829,6 +5138,14 @@ function installGlassDamage(kit) {
|
|
|
4829
5138
|
const G = msh.userData.glass;
|
|
4830
5139
|
if (G.broken) return;
|
|
4831
5140
|
G.broken = true;
|
|
5141
|
+
const freeCracks = function() {
|
|
5142
|
+
if (!G.tex) return;
|
|
5143
|
+
if (msh.material !== MATERIALS.glassEdge && msh.material?.map === G.tex) msh.material.dispose();
|
|
5144
|
+
G.tex.dispose();
|
|
5145
|
+
G.tex = null;
|
|
5146
|
+
G.cv = null;
|
|
5147
|
+
G.cracksFreed = true;
|
|
5148
|
+
};
|
|
4832
5149
|
const cubesAt = [];
|
|
4833
5150
|
if (G.outline && G.T !== void 0) {
|
|
4834
5151
|
const out = G.outline;
|
|
@@ -4862,6 +5179,7 @@ function installGlassDamage(kit) {
|
|
|
4862
5179
|
geo.computeVertexNormals();
|
|
4863
5180
|
msh.geometry.dispose();
|
|
4864
5181
|
msh.geometry = geo;
|
|
5182
|
+
freeCracks();
|
|
4865
5183
|
msh.material = MATERIALS.glassEdge;
|
|
4866
5184
|
let minx = 1e9;
|
|
4867
5185
|
let maxx = -1e9;
|
|
@@ -4885,8 +5203,12 @@ function installGlassDamage(kit) {
|
|
|
4885
5203
|
if (rim) {
|
|
4886
5204
|
msh.geometry.dispose();
|
|
4887
5205
|
msh.geometry = rim;
|
|
5206
|
+
freeCracks();
|
|
4888
5207
|
msh.material = MATERIALS.glassEdge;
|
|
4889
|
-
} else
|
|
5208
|
+
} else {
|
|
5209
|
+
freeCracks();
|
|
5210
|
+
msh.visible = false;
|
|
5211
|
+
}
|
|
4890
5212
|
for (let j = 0; j < 36; j++)
|
|
4891
5213
|
cubesAt.push(
|
|
4892
5214
|
new V3(
|
|
@@ -6721,6 +7043,8 @@ function installZoneDecals(kit) {
|
|
|
6721
7043
|
const pos = g && g.attributes && g.attributes.position;
|
|
6722
7044
|
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
7045
|
}
|
|
7046
|
+
let _keep = new Uint32Array(0);
|
|
7047
|
+
let _box = new Float32Array(0);
|
|
6724
7048
|
function proxyIn(o, Mw, R) {
|
|
6725
7049
|
_pm.copy(o.matrixWorld).invert().multiply(Mw);
|
|
6726
7050
|
const lo = [Infinity, Infinity, Infinity];
|
|
@@ -6733,39 +7057,48 @@ function installZoneDecals(kit) {
|
|
|
6733
7057
|
}
|
|
6734
7058
|
}
|
|
6735
7059
|
const g = o.geometry;
|
|
6736
|
-
const
|
|
7060
|
+
const ti = triIndexOf(g);
|
|
7061
|
+
if (!ti) return null;
|
|
6737
7062
|
const ix = g.index ? g.index.array : null;
|
|
6738
|
-
const
|
|
6739
|
-
const
|
|
7063
|
+
const boxes = ti.boxes;
|
|
7064
|
+
const blocks = ti.blocks;
|
|
7065
|
+
if (_keep.length < ti.triangles * 3) {
|
|
7066
|
+
_keep = new Uint32Array(ti.triangles * 3);
|
|
7067
|
+
_box = new Float32Array(ti.triangles * 6);
|
|
7068
|
+
}
|
|
7069
|
+
const keep = _keep;
|
|
7070
|
+
const box = _box;
|
|
6740
7071
|
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;
|
|
7072
|
+
let nt = 0;
|
|
7073
|
+
for (let blk = 0, t0 = 0; t0 < ti.triangles; blk++, t0 += TRI_BLOCK) {
|
|
7074
|
+
const j = blk * 6;
|
|
7075
|
+
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;
|
|
7076
|
+
const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
|
|
7077
|
+
for (let t = t0; t < t1; t++) {
|
|
7078
|
+
const q = t * 6;
|
|
7079
|
+
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;
|
|
7080
|
+
keep[nk++] = ix ? ix[t * 3] : t * 3;
|
|
7081
|
+
keep[nk++] = ix ? ix[t * 3 + 1] : t * 3 + 1;
|
|
7082
|
+
keep[nk++] = ix ? ix[t * 3 + 2] : t * 3 + 2;
|
|
7083
|
+
for (let k = 0; k < 6; k++) box[nt * 6 + k] = boxes[q + k];
|
|
7084
|
+
nt++;
|
|
6756
7085
|
}
|
|
6757
7086
|
}
|
|
6758
7087
|
if (!nk) return null;
|
|
6759
7088
|
const kept = keep.slice(0, nk);
|
|
6760
|
-
const
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
const b =
|
|
6764
|
-
const d = kept[t + 2] * 3;
|
|
7089
|
+
const keptBox = box.slice(0, nt * 6);
|
|
7090
|
+
const keptBlocks = new Float32Array(Math.ceil(nt / TRI_BLOCK) * 6);
|
|
7091
|
+
for (let blk = 0; blk * TRI_BLOCK < nt; blk++) {
|
|
7092
|
+
const b = blk * 6;
|
|
6765
7093
|
for (let k = 0; k < 3; k++) {
|
|
6766
|
-
|
|
6767
|
-
|
|
7094
|
+
keptBlocks[b + k] = Infinity;
|
|
7095
|
+
keptBlocks[b + 3 + k] = -Infinity;
|
|
6768
7096
|
}
|
|
7097
|
+
for (let t = blk * TRI_BLOCK, t1 = Math.min(nt, t + TRI_BLOCK); t < t1; t++)
|
|
7098
|
+
for (let k = 0; k < 3; k++) {
|
|
7099
|
+
if (keptBox[t * 6 + k] < keptBlocks[b + k]) keptBlocks[b + k] = keptBox[t * 6 + k];
|
|
7100
|
+
if (keptBox[t * 6 + 3 + k] > keptBlocks[b + 3 + k]) keptBlocks[b + 3 + k] = keptBox[t * 6 + 3 + k];
|
|
7101
|
+
}
|
|
6769
7102
|
}
|
|
6770
7103
|
const pg = new THREE.BufferGeometry();
|
|
6771
7104
|
pg.setAttribute("position", g.attributes.position);
|
|
@@ -6776,7 +7109,8 @@ function installZoneDecals(kit) {
|
|
|
6776
7109
|
proxy.layers.mask = o.layers.mask;
|
|
6777
7110
|
proxy.proxyOf = o;
|
|
6778
7111
|
proxy.kept = kept;
|
|
6779
|
-
proxy.keptBox =
|
|
7112
|
+
proxy.keptBox = keptBox;
|
|
7113
|
+
proxy.keptBlocks = keptBlocks;
|
|
6780
7114
|
return proxy;
|
|
6781
7115
|
}
|
|
6782
7116
|
function narrowTo(rc, proxy) {
|
|
@@ -6796,13 +7130,21 @@ function installZoneDecals(kit) {
|
|
|
6796
7130
|
const hi2 = Math.max(z0, _pv.z) + 1e-4;
|
|
6797
7131
|
const K = proxy.kept;
|
|
6798
7132
|
const X = proxy.keptBox;
|
|
7133
|
+
const KB = proxy.keptBlocks;
|
|
7134
|
+
const nt = K.length / 3;
|
|
6799
7135
|
const dst = proxy.geometry.index.array;
|
|
6800
7136
|
let m = 0;
|
|
6801
|
-
for (let
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
7137
|
+
for (let blk = 0, t0 = 0; t0 < nt; blk++, t0 += TRI_BLOCK) {
|
|
7138
|
+
const b = blk * 6;
|
|
7139
|
+
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;
|
|
7140
|
+
const t1 = Math.min(nt, t0 + TRI_BLOCK);
|
|
7141
|
+
for (let t = t0; t < t1; t++) {
|
|
7142
|
+
const j = t * 6;
|
|
7143
|
+
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;
|
|
7144
|
+
dst[m++] = K[t * 3];
|
|
7145
|
+
dst[m++] = K[t * 3 + 1];
|
|
7146
|
+
dst[m++] = K[t * 3 + 2];
|
|
7147
|
+
}
|
|
6806
7148
|
}
|
|
6807
7149
|
proxy.geometry.setDrawRange(0, m);
|
|
6808
7150
|
}
|
|
@@ -7220,6 +7562,8 @@ function installZoneDent(kit) {
|
|
|
7220
7562
|
irel.copy(rel).invert();
|
|
7221
7563
|
const pos = g.attributes.position;
|
|
7222
7564
|
let changed = false;
|
|
7565
|
+
const liveIndex = liveTriIndex(g);
|
|
7566
|
+
const movedVertices = [];
|
|
7223
7567
|
const near = boxInFrame(B, irel, v);
|
|
7224
7568
|
for (let i = 0; i < pos.count; i++) {
|
|
7225
7569
|
v.fromBufferAttribute(pos, i);
|
|
@@ -7231,6 +7575,7 @@ function installZoneDent(kit) {
|
|
|
7231
7575
|
if (opt.extra) opt.extra(v, f);
|
|
7232
7576
|
v.applyMatrix4(irel);
|
|
7233
7577
|
pos.setXYZ(i, v.x, v.y, v.z);
|
|
7578
|
+
movedVertices.push(i);
|
|
7234
7579
|
changed = true;
|
|
7235
7580
|
}
|
|
7236
7581
|
if (opt.extraAll) {
|
|
@@ -7239,12 +7584,14 @@ function installZoneDent(kit) {
|
|
|
7239
7584
|
if (opt.extraAll(v)) {
|
|
7240
7585
|
v.applyMatrix4(irel);
|
|
7241
7586
|
pos.setXYZ(j, v.x, v.y, v.z);
|
|
7587
|
+
movedVertices.push(j);
|
|
7242
7588
|
changed = true;
|
|
7243
7589
|
}
|
|
7244
7590
|
}
|
|
7245
7591
|
}
|
|
7246
7592
|
if (changed) {
|
|
7247
7593
|
pos.needsUpdate = true;
|
|
7594
|
+
if (liveIndex) touchTriIndex(g, liveIndex, movedVertices);
|
|
7248
7595
|
dirty.add(msh);
|
|
7249
7596
|
}
|
|
7250
7597
|
if (changed || boundsDue) {
|
|
@@ -7275,6 +7622,26 @@ function installZoneDent(kit) {
|
|
|
7275
7622
|
});
|
|
7276
7623
|
return { field, moved, ax, a, cu, cv, hu, hv, outer };
|
|
7277
7624
|
}
|
|
7625
|
+
function panelBoundsIn(rel, rect, B, a, ax) {
|
|
7626
|
+
const det = rel.determinant();
|
|
7627
|
+
if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return void 0;
|
|
7628
|
+
const back = rel.clone().invert();
|
|
7629
|
+
const lo = [Infinity, Infinity, Infinity];
|
|
7630
|
+
const hi = [-Infinity, -Infinity, -Infinity];
|
|
7631
|
+
const q = new V3();
|
|
7632
|
+
for (let i = 0; i < 8; i++) {
|
|
7633
|
+
q.setComponent(ax[0], i & 1 ? rect[1] : rect[0]);
|
|
7634
|
+
q.setComponent(ax[1], i & 2 ? rect[3] : rect[2]);
|
|
7635
|
+
q.setComponent(a, i & 4 ? I.boxHi(B, a) : I.boxLo(B, a));
|
|
7636
|
+
q.applyMatrix4(back);
|
|
7637
|
+
for (let k = 0; k < 3; k++) {
|
|
7638
|
+
lo[k] = Math.min(lo[k], q.getComponent(k));
|
|
7639
|
+
hi[k] = Math.max(hi[k], q.getComponent(k));
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
const pad = 1e-3;
|
|
7643
|
+
return { lo: lo.map((x) => x - pad), hi: hi.map((x) => x + pad) };
|
|
7644
|
+
}
|
|
7278
7645
|
function cutPanel(c, z, rect, keep, dirty, o) {
|
|
7279
7646
|
o = o || {};
|
|
7280
7647
|
const B = z.box;
|
|
@@ -7307,6 +7674,7 @@ function installZoneDent(kit) {
|
|
|
7307
7674
|
}
|
|
7308
7675
|
const test = {
|
|
7309
7676
|
tag: "part",
|
|
7677
|
+
pieces: keep ? o.pieceTasks ? "later" : "crease" : "none",
|
|
7310
7678
|
sel: o.anyN || z.cutAll ? null : function(n) {
|
|
7311
7679
|
nv.copy(n).applyMatrix3(nm).normalize();
|
|
7312
7680
|
return nv.dot(outN) > 0.3;
|
|
@@ -7325,13 +7693,12 @@ function installZoneDent(kit) {
|
|
|
7325
7693
|
return q;
|
|
7326
7694
|
}
|
|
7327
7695
|
};
|
|
7328
|
-
const r = cutGeometry(g, [test]);
|
|
7696
|
+
const r = cutGeometry(g, [{ ...test, bounds: panelBoundsIn(rel, rect, B, a, ax) }]);
|
|
7329
7697
|
const cg = r.cut.part;
|
|
7330
7698
|
if (!cg || !cg.attributes.position.count) return;
|
|
7331
7699
|
g.dispose();
|
|
7332
7700
|
msh.geometry = r.geo;
|
|
7333
|
-
r.geo
|
|
7334
|
-
r.geo.computeBoundingBox();
|
|
7701
|
+
I.refreshBounds(r.geo);
|
|
7335
7702
|
dirty.add(msh);
|
|
7336
7703
|
if (!keep) {
|
|
7337
7704
|
cg.dispose();
|
|
@@ -7344,6 +7711,7 @@ function installZoneDent(kit) {
|
|
|
7344
7711
|
rel.decompose(pm.position, pm.quaternion, pm.scale);
|
|
7345
7712
|
c.vehicle.add(pm);
|
|
7346
7713
|
pm.updateMatrixWorld(true);
|
|
7714
|
+
if (o.pieceTasks) o.pieceTasks.set(pm, r.tasks.part);
|
|
7347
7715
|
pieces.push({ mesh: pm, cut: true });
|
|
7348
7716
|
});
|
|
7349
7717
|
return pieces;
|
|
@@ -10983,7 +11351,15 @@ var VehicleVisuals = class {
|
|
|
10983
11351
|
__publicField(this, "gone", /* @__PURE__ */ new Set());
|
|
10984
11352
|
/** Shows or hides the plate and the recess of a door or lid by its state (see `showWhenOpen`). */
|
|
10985
11353
|
__publicField(this, "syncPlates", /* @__PURE__ */ new Map());
|
|
11354
|
+
/** 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). */
|
|
11355
|
+
__publicField(this, "skins", /* @__PURE__ */ new Map());
|
|
10986
11356
|
__publicField(this, "lightsOn", true);
|
|
11357
|
+
/** Heavy body meshes whose triangle index is still to build (null once done). */
|
|
11358
|
+
__publicField(this, "warming");
|
|
11359
|
+
/** A panel was torn off since the last `pump`: that frame already paid for the cut, the smoothing starts on the next one. */
|
|
11360
|
+
__publicField(this, "tornThisFrame", false);
|
|
11361
|
+
/** Normal smoothing still running, by mesh: a mesh cut again gets a new task and the old one is dropped. */
|
|
11362
|
+
__publicField(this, "smoothing", /* @__PURE__ */ new Map());
|
|
10987
11363
|
__publicField(this, "hood");
|
|
10988
11364
|
this.kit = kit;
|
|
10989
11365
|
this.c = c;
|
|
@@ -10993,6 +11369,8 @@ var VehicleVisuals = class {
|
|
|
10993
11369
|
for (const p of model.parts) this.byId.set(p.id, p);
|
|
10994
11370
|
c.root.updateMatrixWorld(true);
|
|
10995
11371
|
this.hood = this.nameHood();
|
|
11372
|
+
this.warming = c.deform.filter((msh) => msh.geometry && msh.geometry.attributes.position && msh.geometry.attributes.position.count >= 1500);
|
|
11373
|
+
if (!this.warming.length) this.warming = null;
|
|
10996
11374
|
for (const p of model.parts) {
|
|
10997
11375
|
if (p.role === "door" || p.role === "lid") this.makePlate(p);
|
|
10998
11376
|
else if (p.role === "mirror" && !this.mirrorObjects(p).length) this.makeMirror(p);
|
|
@@ -11128,11 +11506,21 @@ var VehicleVisuals = class {
|
|
|
11128
11506
|
* 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
11507
|
*/
|
|
11130
11508
|
showWhenOpen(id, piv, panel, recess) {
|
|
11509
|
+
let busy = false;
|
|
11131
11510
|
const sync = () => {
|
|
11511
|
+
if (busy) return;
|
|
11132
11512
|
const r = piv.rotation;
|
|
11133
11513
|
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
|
-
|
|
11514
|
+
if (open && !this.gone.has(id) && piv.parent === this.c.vehicle && !this.skins.has(id)) {
|
|
11515
|
+
busy = true;
|
|
11516
|
+
try {
|
|
11517
|
+
this.skins.set(id, this.takeSkin(id, piv));
|
|
11518
|
+
} finally {
|
|
11519
|
+
busy = false;
|
|
11520
|
+
}
|
|
11521
|
+
}
|
|
11522
|
+
panel.visible = open && !this.skins.get(id);
|
|
11523
|
+
recess.visible = open && !this.skins.get(id);
|
|
11136
11524
|
};
|
|
11137
11525
|
const euler = piv.rotation;
|
|
11138
11526
|
const quaternion = piv.quaternion;
|
|
@@ -11149,6 +11537,58 @@ var VehicleVisuals = class {
|
|
|
11149
11537
|
this.syncPlates.set(id, sync);
|
|
11150
11538
|
sync();
|
|
11151
11539
|
}
|
|
11540
|
+
/**
|
|
11541
|
+
* 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
|
|
11542
|
+
* window over it, on the hinge. Done with the hinge closed, so every piece keeps its place; answers whether there was skin to take.
|
|
11543
|
+
*/
|
|
11544
|
+
takeSkin(id, piv) {
|
|
11545
|
+
const p = this.byId.get(id);
|
|
11546
|
+
const z = p && this.zone(p);
|
|
11547
|
+
if (!p || !z) return false;
|
|
11548
|
+
const I = this.I;
|
|
11549
|
+
const B = z.box;
|
|
11550
|
+
const q = piv.quaternion.clone();
|
|
11551
|
+
piv.quaternion.identity();
|
|
11552
|
+
this.c.root.updateMatrixWorld(true);
|
|
11553
|
+
const inv = I.worldInverseOf(this.c);
|
|
11554
|
+
let objs = [];
|
|
11555
|
+
try {
|
|
11556
|
+
if (p.role === "door") {
|
|
11557
|
+
const dirty = /* @__PURE__ */ new Set();
|
|
11558
|
+
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];
|
|
11559
|
+
const pcs = I.cutPanel(this.c, z, rect, true, dirty).map((x) => x.mesh).filter((m) => !!m);
|
|
11560
|
+
this.mend(dirty);
|
|
11561
|
+
if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv), ...I.windowsOver(this.c, z, inv)];
|
|
11562
|
+
} else {
|
|
11563
|
+
const pcs = this.cutZone(z);
|
|
11564
|
+
if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv)];
|
|
11565
|
+
}
|
|
11566
|
+
} catch {
|
|
11567
|
+
objs = [];
|
|
11568
|
+
}
|
|
11569
|
+
const deform = this.c.deform ?? [];
|
|
11570
|
+
for (const o of objs) {
|
|
11571
|
+
if (!o.parent || o === piv) continue;
|
|
11572
|
+
piv.attach(o);
|
|
11573
|
+
o.traverse((x) => {
|
|
11574
|
+
x.userData.noFollow = true;
|
|
11575
|
+
});
|
|
11576
|
+
const di = deform.indexOf(o);
|
|
11577
|
+
if (di >= 0) deform.splice(di, 1);
|
|
11578
|
+
}
|
|
11579
|
+
piv.quaternion.copy(q);
|
|
11580
|
+
this.c.root.updateMatrixWorld(true);
|
|
11581
|
+
return objs.length > 0;
|
|
11582
|
+
}
|
|
11583
|
+
mend(dirty) {
|
|
11584
|
+
dirty.forEach((msh) => {
|
|
11585
|
+
const g = msh.geometry;
|
|
11586
|
+
if (g.userData.crease || !g.index) this.I.crease(g, 42);
|
|
11587
|
+
else g.computeVertexNormals();
|
|
11588
|
+
g.computeBoundingSphere();
|
|
11589
|
+
g.computeBoundingBox();
|
|
11590
|
+
});
|
|
11591
|
+
}
|
|
11152
11592
|
makeMirror(p) {
|
|
11153
11593
|
const [cx, cy, cz] = p.box.center;
|
|
11154
11594
|
const s = cz < 0 ? -1 : 1;
|
|
@@ -11286,6 +11726,31 @@ var VehicleVisuals = class {
|
|
|
11286
11726
|
this.I.flattenTire(w, Math.min(0.5, 0.12 + 0.38 * melt));
|
|
11287
11727
|
}
|
|
11288
11728
|
}
|
|
11729
|
+
/** Smooths the normals of a cut mesh a slice per frame (see `pump`); until then it draws with flat face normals. */
|
|
11730
|
+
smoothLater(msh) {
|
|
11731
|
+
this.smoothing.set(msh, this.I.creaseTask(msh.geometry, 42));
|
|
11732
|
+
this.tornThisFrame = true;
|
|
11733
|
+
}
|
|
11734
|
+
/** Spends at most `budgetMs` finishing the pending normal smoothing. Call once per frame. */
|
|
11735
|
+
pump(budgetMs = 2.5) {
|
|
11736
|
+
if (this.tornThisFrame) {
|
|
11737
|
+
this.tornThisFrame = false;
|
|
11738
|
+
return;
|
|
11739
|
+
}
|
|
11740
|
+
if (!this.smoothing.size && !this.warming) return;
|
|
11741
|
+
const deadline = performance.now() + budgetMs;
|
|
11742
|
+
for (const [msh, task] of this.smoothing) {
|
|
11743
|
+
if (msh.geometry !== task.geo || task.step(deadline)) this.smoothing.delete(msh);
|
|
11744
|
+
if (performance.now() >= deadline) return;
|
|
11745
|
+
}
|
|
11746
|
+
this.warmIndexes(deadline);
|
|
11747
|
+
}
|
|
11748
|
+
/** Measures the triangles of the heavy body meshes once, a slice per frame, so the first panel torn off finds them ready (see `triIndexOf`). */
|
|
11749
|
+
warmIndexes(deadline) {
|
|
11750
|
+
if (!this.warming) return;
|
|
11751
|
+
this.warming = this.warming.filter((msh) => !warmTriIndex(msh.geometry, deadline));
|
|
11752
|
+
if (!this.warming.length) this.warming = null;
|
|
11753
|
+
}
|
|
11289
11754
|
/** Moves the panel of a lost zone out of the body (the kit's torn-off look). */
|
|
11290
11755
|
tearOff(p) {
|
|
11291
11756
|
const z = this.zone(p);
|
|
@@ -11298,10 +11763,9 @@ var VehicleVisuals = class {
|
|
|
11298
11763
|
}
|
|
11299
11764
|
dirty.forEach((msh) => {
|
|
11300
11765
|
const g = msh.geometry;
|
|
11301
|
-
if (g.userData.crease || !g.index) this.
|
|
11766
|
+
if (g.userData.crease || !g.index) this.smoothLater(msh);
|
|
11302
11767
|
else g.computeVertexNormals();
|
|
11303
|
-
|
|
11304
|
-
g.computeBoundingBox();
|
|
11768
|
+
this.I.refreshBounds(g);
|
|
11305
11769
|
});
|
|
11306
11770
|
this.gone.add(p.id);
|
|
11307
11771
|
}
|
|
@@ -11444,17 +11908,19 @@ var VehicleVisuals = class {
|
|
|
11444
11908
|
const mg = Math.min(0.05, (u1 - u0) * 0.08, (v1 - v0) * 0.08);
|
|
11445
11909
|
const dirty = /* @__PURE__ */ new Set();
|
|
11446
11910
|
let pcs = [];
|
|
11911
|
+
const pieceTasks = /* @__PURE__ */ new Map();
|
|
11447
11912
|
try {
|
|
11448
|
-
pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty);
|
|
11913
|
+
pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty, { pieceTasks });
|
|
11449
11914
|
} catch {
|
|
11450
11915
|
pcs = [];
|
|
11451
11916
|
}
|
|
11917
|
+
pieceTasks.forEach((task, mesh) => this.smoothing.set(mesh, task));
|
|
11918
|
+
this.tornThisFrame = true;
|
|
11452
11919
|
dirty.forEach((msh) => {
|
|
11453
11920
|
const g = msh.geometry;
|
|
11454
|
-
if (g.userData.crease || !g.index)
|
|
11921
|
+
if (g.userData.crease || !g.index) this.smoothLater(msh);
|
|
11455
11922
|
else g.computeVertexNormals();
|
|
11456
|
-
|
|
11457
|
-
g.computeBoundingBox();
|
|
11923
|
+
I.refreshBounds(g);
|
|
11458
11924
|
});
|
|
11459
11925
|
return pcs.map((q) => q.mesh).filter((m) => !!m);
|
|
11460
11926
|
}
|
|
@@ -12233,7 +12699,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12233
12699
|
specCache = { name: options.name ?? c.spec.name ?? c.key, parts, joints, tags: ["vehicle", kindOf(c)] };
|
|
12234
12700
|
return specCache;
|
|
12235
12701
|
};
|
|
12236
|
-
const
|
|
12702
|
+
const buildState = () => {
|
|
12237
12703
|
const parts = model.parts.map((d) => {
|
|
12238
12704
|
const p = ps.get(d.id);
|
|
12239
12705
|
const marked = p.dents.length > 0 || p.holes.length > 0 || p.cracks.length > 0;
|
|
@@ -12270,7 +12736,15 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12270
12736
|
}));
|
|
12271
12737
|
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
12738
|
};
|
|
12739
|
+
let stateCache;
|
|
12740
|
+
const state = () => stateCache ?? (stateCache = buildState());
|
|
12741
|
+
const isSimulating = () => {
|
|
12742
|
+
if (leaks.size > 0) return true;
|
|
12743
|
+
for (const p of ps.values()) if (!p.lost && (p.burning || p.temp > AMBIENT)) return true;
|
|
12744
|
+
return false;
|
|
12745
|
+
};
|
|
12273
12746
|
const hit = (h) => {
|
|
12747
|
+
stateCache = void 0;
|
|
12274
12748
|
const out = [];
|
|
12275
12749
|
const hh = h.space === "local" ? { ...h, space: "world", point: toWorld(h.point) } : h;
|
|
12276
12750
|
if (hh.space === "local" || !hh.point) return out;
|
|
@@ -12297,6 +12771,8 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12297
12771
|
clock += dt;
|
|
12298
12772
|
const out = queue;
|
|
12299
12773
|
queue = [];
|
|
12774
|
+
const wasSimulating = isSimulating();
|
|
12775
|
+
const handledBefore = (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0);
|
|
12300
12776
|
const hood = c.hood;
|
|
12301
12777
|
if (hood) {
|
|
12302
12778
|
const sign = hood.sign || 1;
|
|
@@ -12317,12 +12793,15 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12317
12793
|
afterBlast(out);
|
|
12318
12794
|
afterRoll(out);
|
|
12319
12795
|
applyEffects();
|
|
12796
|
+
vis?.pump();
|
|
12797
|
+
if (wasSimulating || out.length > 0 || handledBefore !== (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0)) stateCache = void 0;
|
|
12320
12798
|
return out;
|
|
12321
12799
|
};
|
|
12322
12800
|
const disassemble = (jointId, tool, dt) => {
|
|
12323
12801
|
const j = js.find((x) => x.def.id === jointId);
|
|
12324
12802
|
if (!j || !j.def.tools.includes(tool)) return -1;
|
|
12325
12803
|
if (j.open) return 1;
|
|
12804
|
+
stateCache = void 0;
|
|
12326
12805
|
j.progress = Math.min(1, j.progress + dt / j.def.seconds);
|
|
12327
12806
|
const step = Math.floor(j.progress * 4) / 4;
|
|
12328
12807
|
if (step > j.reported && j.progress < 1) {
|
|
@@ -12338,6 +12817,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12338
12817
|
return j.progress;
|
|
12339
12818
|
};
|
|
12340
12819
|
const extinguish = (partId) => {
|
|
12820
|
+
stateCache = void 0;
|
|
12341
12821
|
for (const p of ps.values()) {
|
|
12342
12822
|
if (partId && p.def.id !== partId) continue;
|
|
12343
12823
|
if (p.burning) {
|
|
@@ -12351,6 +12831,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12351
12831
|
}
|
|
12352
12832
|
};
|
|
12353
12833
|
const reset = () => {
|
|
12834
|
+
stateCache = void 0;
|
|
12354
12835
|
const old = c;
|
|
12355
12836
|
const parent = old.root.parent;
|
|
12356
12837
|
const next = kit.build(old.key, old.state, old.scenario != null ? { scenario: old.scenario } : void 0);
|
|
@@ -12368,6 +12849,7 @@ function createVehicleDestructible(kit, vehicleCtx, options = {}) {
|
|
|
12368
12849
|
setup();
|
|
12369
12850
|
};
|
|
12370
12851
|
const rollover = (side2 = 1) => {
|
|
12852
|
+
stateCache = void 0;
|
|
12371
12853
|
if (kit.roll(c, side2)) rolled = true;
|
|
12372
12854
|
void rolled;
|
|
12373
12855
|
};
|