ldr 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -80
- package/dist/cdn.d.ts +62 -0
- package/dist/cli.js +148 -19
- package/dist/index.d.ts +4 -2
- package/dist/index.js +962 -204
- package/dist/node/build-pack.d.ts +6 -0
- package/dist/node/compile.d.ts +4 -0
- package/dist/node/index.js +1098 -219
- package/dist/node/lod.d.ts +17 -0
- package/dist/render.d.ts +43 -1
- package/dist/scene.d.ts +16 -2
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/spec.ts
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
function parseColor(tok) {
|
|
4
4
|
if (/^0x/i.test(tok))
|
|
@@ -647,7 +647,7 @@ function fileStepViews(f) {
|
|
|
647
647
|
viewMemo.set(f, out);
|
|
648
648
|
return out;
|
|
649
649
|
}
|
|
650
|
-
// src/model.ts
|
|
650
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/model.ts
|
|
651
651
|
function flatten(doc, opts = {}) {
|
|
652
652
|
const out = [];
|
|
653
653
|
const maxDepth = opts.maxDepth ?? 64;
|
|
@@ -768,7 +768,7 @@ function parseLDConfig(text) {
|
|
|
768
768
|
}
|
|
769
769
|
return out;
|
|
770
770
|
}
|
|
771
|
-
// src/render.ts
|
|
771
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/render.ts
|
|
772
772
|
import * as THREE from "three";
|
|
773
773
|
async function loadPack(url) {
|
|
774
774
|
const res = await fetch(url);
|
|
@@ -796,19 +796,60 @@ function decodePack(buf) {
|
|
|
796
796
|
const header = JSON.parse(new TextDecoder().decode(new Uint8Array(buf, 4, hl)));
|
|
797
797
|
const base = 4 + hl;
|
|
798
798
|
const arr = (r) => r && (r[2] === "f32" ? new Float32Array(buf, base + r[0], r[1]) : r[2] === "u16" ? new Uint16Array(buf, base + r[0], r[1]) : r[2] === "u8" ? new Uint8Array(buf, base + r[0], r[1]) : new Uint32Array(buf, base + r[0], r[1]));
|
|
799
|
-
return { header, arr, bytes: buf.byteLength };
|
|
799
|
+
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
800
800
|
}
|
|
801
|
-
|
|
801
|
+
var toI8 = (a) => {
|
|
802
|
+
const o = new Int8Array(a.length);
|
|
803
|
+
for (let i = 0;i < a.length; i++)
|
|
804
|
+
o[i] = Math.round(Math.max(-1, Math.min(1, a[i])) * 127);
|
|
805
|
+
return o;
|
|
806
|
+
};
|
|
807
|
+
var toU8 = (a) => {
|
|
808
|
+
const o = new Uint8Array(a.length);
|
|
809
|
+
for (let i = 0;i < a.length; i++)
|
|
810
|
+
o[i] = Math.round(Math.max(0, Math.min(1, a[i])) * 255);
|
|
811
|
+
return o;
|
|
812
|
+
};
|
|
813
|
+
function flatNormals(pos, idx) {
|
|
814
|
+
const n = new Float32Array(pos.length);
|
|
815
|
+
for (let t = 0;t < idx.length; t += 3) {
|
|
816
|
+
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
817
|
+
const ux = pos[b] - pos[a], uy = pos[b + 1] - pos[a + 1], uz = pos[b + 2] - pos[a + 2], vx = pos[c] - pos[a], vy = pos[c + 1] - pos[a + 1], vz = pos[c + 2] - pos[a + 2];
|
|
818
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
819
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
820
|
+
nx /= l;
|
|
821
|
+
ny /= l;
|
|
822
|
+
nz /= l;
|
|
823
|
+
for (const o of [a, b, c]) {
|
|
824
|
+
n[o] = nx;
|
|
825
|
+
n[o + 1] = ny;
|
|
826
|
+
n[o + 2] = nz;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return n;
|
|
830
|
+
}
|
|
831
|
+
var geomCache = new WeakMap;
|
|
832
|
+
function geom(b, arr, quant = true) {
|
|
802
833
|
if (!b)
|
|
803
834
|
return null;
|
|
804
|
-
|
|
835
|
+
let c = geomCache.get(arr);
|
|
836
|
+
if (!c)
|
|
837
|
+
geomCache.set(arr, c = new Map);
|
|
838
|
+
const ck = quant ? b : b.pos;
|
|
839
|
+
let g = c.get(ck);
|
|
840
|
+
if (g)
|
|
841
|
+
return g;
|
|
842
|
+
g = new THREE.BufferGeometry;
|
|
805
843
|
g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
|
|
806
|
-
|
|
807
|
-
|
|
844
|
+
const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
|
|
845
|
+
const col = arr(b.col);
|
|
846
|
+
g.setAttribute("normal", quant ? new THREE.BufferAttribute(toI8(nrm), 3, true) : new THREE.BufferAttribute(nrm, 3));
|
|
847
|
+
g.setAttribute("ldrColor", col instanceof Uint8Array ? new THREE.BufferAttribute(col, 4, true) : quant ? new THREE.BufferAttribute(toU8(col), 4, true) : new THREE.BufferAttribute(col, 4));
|
|
808
848
|
if (b.idx)
|
|
809
849
|
g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
|
|
810
850
|
if (b.uv)
|
|
811
851
|
g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
|
|
852
|
+
c.set(ck, g);
|
|
812
853
|
return g;
|
|
813
854
|
}
|
|
814
855
|
function makeMaterial(side) {
|
|
@@ -1012,120 +1053,544 @@ function instancedLines(pos, mats, count) {
|
|
|
1012
1053
|
l.frustumCulled = false;
|
|
1013
1054
|
return l;
|
|
1014
1055
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1056
|
+
function writeM4(t, o, m, mo = 0) {
|
|
1057
|
+
t[o] = m[mo + 3];
|
|
1058
|
+
t[o + 1] = m[mo + 6];
|
|
1059
|
+
t[o + 2] = m[mo + 9];
|
|
1060
|
+
t[o + 3] = 0;
|
|
1061
|
+
t[o + 4] = m[mo + 4];
|
|
1062
|
+
t[o + 5] = m[mo + 7];
|
|
1063
|
+
t[o + 6] = m[mo + 10];
|
|
1064
|
+
t[o + 7] = 0;
|
|
1065
|
+
t[o + 8] = m[mo + 5];
|
|
1066
|
+
t[o + 9] = m[mo + 8];
|
|
1067
|
+
t[o + 10] = m[mo + 11];
|
|
1068
|
+
t[o + 11] = 0;
|
|
1069
|
+
t[o + 12] = m[mo];
|
|
1070
|
+
t[o + 13] = m[mo + 1];
|
|
1071
|
+
t[o + 14] = m[mo + 2];
|
|
1072
|
+
t[o + 15] = 1;
|
|
1073
|
+
}
|
|
1074
|
+
function newIM(g, mat, n) {
|
|
1075
|
+
const im = new THREE.InstancedMesh(g, mat, 0);
|
|
1076
|
+
im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
|
|
1077
|
+
im.count = n;
|
|
1078
|
+
return im;
|
|
1079
|
+
}
|
|
1080
|
+
function fillInstances(im, ids, insts, color) {
|
|
1081
|
+
const M = im.instanceMatrix.array;
|
|
1082
|
+
const C = new Float32Array(ids.length * 3);
|
|
1083
|
+
for (let k = 0;k < ids.length; k++) {
|
|
1084
|
+
const it = insts[ids[k]];
|
|
1085
|
+
writeM4(M, k * 16, it.m);
|
|
1086
|
+
color(it.color).toArray(C, k * 3);
|
|
1087
|
+
}
|
|
1088
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1089
|
+
}
|
|
1090
|
+
var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
|
|
1091
|
+
var prepCache = new WeakMap;
|
|
1092
|
+
function prepPart(H, part) {
|
|
1093
|
+
let c = prepCache.get(H);
|
|
1094
|
+
if (!c)
|
|
1095
|
+
prepCache.set(H, c = new Map);
|
|
1096
|
+
let r = c.get(part);
|
|
1097
|
+
if (r !== undefined)
|
|
1098
|
+
return r;
|
|
1099
|
+
const p = H.parts[part];
|
|
1100
|
+
if (!p) {
|
|
1101
|
+
c.set(part, null);
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
const n = p.studs.length;
|
|
1105
|
+
const studM = new Float64Array(n * 12);
|
|
1106
|
+
const kind = [], color = [];
|
|
1107
|
+
p.studs.forEach((s, i) => {
|
|
1108
|
+
kind.push(s[0]);
|
|
1109
|
+
color.push(s[1]);
|
|
1110
|
+
for (let k = 0;k < 12; k++)
|
|
1111
|
+
studM[i * 12 + k] = s[2 + k];
|
|
1112
|
+
});
|
|
1113
|
+
let mask = null, nx = 0, nz = 0;
|
|
1114
|
+
if (p.mask) {
|
|
1115
|
+
nx = p.mask[0];
|
|
1116
|
+
nz = p.mask[1];
|
|
1117
|
+
const bits = p.mask[2];
|
|
1118
|
+
mask = new Uint8Array(bits.length);
|
|
1119
|
+
for (let i = 0;i < bits.length; i++)
|
|
1120
|
+
mask[i] = bits.charCodeAt(i) === 49 ? 1 : 0;
|
|
1121
|
+
}
|
|
1122
|
+
c.set(part, r = { nStuds: n, studM, kind, color, mask, nx, nz });
|
|
1123
|
+
return r;
|
|
1124
|
+
}
|
|
1125
|
+
function mul12To(a, b, bo, w, ao = 0) {
|
|
1126
|
+
const b0 = b[bo], b1 = b[bo + 1], b2 = b[bo + 2];
|
|
1127
|
+
w[0] = a[ao] + a[ao + 3] * b0 + a[ao + 4] * b1 + a[ao + 5] * b2;
|
|
1128
|
+
w[1] = a[ao + 1] + a[ao + 6] * b0 + a[ao + 7] * b1 + a[ao + 8] * b2;
|
|
1129
|
+
w[2] = a[ao + 2] + a[ao + 9] * b0 + a[ao + 10] * b1 + a[ao + 11] * b2;
|
|
1130
|
+
for (let i = 0;i < 3; i++)
|
|
1131
|
+
for (let j = 0;j < 3; j++)
|
|
1132
|
+
w[3 + i * 3 + j] = a[ao + 3 + i * 3] * b[bo + 3 + j] + a[ao + 4 + i * 3] * b[bo + 6 + j] + a[ao + 5 + i * 3] * b[bo + 9 + j];
|
|
1133
|
+
}
|
|
1134
|
+
var det12 = (m) => m[3] * (m[7] * m[11] - m[8] * m[10]) - m[4] * (m[6] * m[11] - m[8] * m[9]) + m[5] * (m[6] * m[10] - m[7] * m[9]);
|
|
1135
|
+
var cellKey = (lv2, cx, cz) => lv2 < -1048576 || lv2 >= 1048576 || cx < -32768 || cx >= 32768 || cz < -32768 || cz >= 32768 ? -1 : (lv2 + 1048576) * 4294967296 + (cx + 32768) * 65536 + (cz + 32768);
|
|
1136
|
+
var topKey = (x, y, z) => {
|
|
1137
|
+
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1138
|
+
return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
|
|
1019
1139
|
};
|
|
1020
|
-
|
|
1021
|
-
|
|
1140
|
+
|
|
1141
|
+
class NumTable {
|
|
1142
|
+
keys;
|
|
1143
|
+
vals;
|
|
1144
|
+
mask;
|
|
1145
|
+
size = 0;
|
|
1146
|
+
constructor(cap = 1024) {
|
|
1147
|
+
let n = 1024;
|
|
1148
|
+
while (n < cap * 2)
|
|
1149
|
+
n *= 2;
|
|
1150
|
+
this.keys = new Float64Array(n).fill(-1);
|
|
1151
|
+
this.vals = new Int32Array(n);
|
|
1152
|
+
this.mask = n - 1;
|
|
1153
|
+
}
|
|
1154
|
+
slot(k) {
|
|
1155
|
+
const lo = k >>> 0, hi = k / 4294967296 >>> 0;
|
|
1156
|
+
let h = Math.imul(lo ^ Math.imul(hi, 2654435761), 2246822507);
|
|
1157
|
+
h ^= h >>> 15;
|
|
1158
|
+
return h & this.mask;
|
|
1159
|
+
}
|
|
1160
|
+
get(k) {
|
|
1161
|
+
const K = this.keys;
|
|
1162
|
+
let i = this.slot(k);
|
|
1163
|
+
for (;; ) {
|
|
1164
|
+
const x = K[i];
|
|
1165
|
+
if (x === k)
|
|
1166
|
+
return this.vals[i];
|
|
1167
|
+
if (x === -1)
|
|
1168
|
+
return -1;
|
|
1169
|
+
i = i + 1 & this.mask;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
put(k, v) {
|
|
1173
|
+
if ((this.size + 1) * 2 > this.keys.length)
|
|
1174
|
+
this.grow();
|
|
1175
|
+
const K = this.keys;
|
|
1176
|
+
let i = this.slot(k);
|
|
1177
|
+
for (;; ) {
|
|
1178
|
+
const x = K[i];
|
|
1179
|
+
if (x === k) {
|
|
1180
|
+
const o = this.vals[i];
|
|
1181
|
+
this.vals[i] = v;
|
|
1182
|
+
return o;
|
|
1183
|
+
}
|
|
1184
|
+
if (x === -1) {
|
|
1185
|
+
K[i] = k;
|
|
1186
|
+
this.vals[i] = v;
|
|
1187
|
+
this.size++;
|
|
1188
|
+
return -1;
|
|
1189
|
+
}
|
|
1190
|
+
i = i + 1 & this.mask;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
grow() {
|
|
1194
|
+
const ok = this.keys, ov = this.vals;
|
|
1195
|
+
const n = ok.length * 2;
|
|
1196
|
+
this.keys = new Float64Array(n).fill(-1);
|
|
1197
|
+
this.vals = new Int32Array(n);
|
|
1198
|
+
this.mask = n - 1;
|
|
1199
|
+
this.size = 0;
|
|
1200
|
+
for (let i = 0;i < ok.length; i++)
|
|
1201
|
+
if (ok[i] !== -1)
|
|
1202
|
+
this.put(ok[i], ov[i]);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
var STEP_NEVER = 2147483647;
|
|
1206
|
+
function forEachStud(insts, H, fn) {
|
|
1207
|
+
const w = new Float64Array(12);
|
|
1208
|
+
let j = 0;
|
|
1209
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1210
|
+
const it = insts[idx];
|
|
1211
|
+
const pp = prepPart(H, it.part);
|
|
1212
|
+
if (!pp)
|
|
1213
|
+
continue;
|
|
1214
|
+
for (let s = 0;s < pp.nStuds; s++) {
|
|
1215
|
+
mul12To(it.m, pp.studM, s * 12, w);
|
|
1216
|
+
const c = pp.color[s];
|
|
1217
|
+
fn(j++, idx, w, pp.kind[s], c === "16" ? it.color : c, s);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function cullCore(insts, H, steps) {
|
|
1022
1222
|
const CELL = 40;
|
|
1023
|
-
const
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1223
|
+
const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
|
|
1224
|
+
const cells = new NumTable(insts.length * 2);
|
|
1225
|
+
const nextE = [], rectE = [];
|
|
1226
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1227
|
+
const it = insts[idx];
|
|
1228
|
+
const m = it.m;
|
|
1026
1229
|
const p = H.parts[it.part];
|
|
1027
|
-
if (!p || !p.mask || !upright(
|
|
1028
|
-
|
|
1230
|
+
if (!p || !p.mask || !upright(m))
|
|
1231
|
+
continue;
|
|
1029
1232
|
const b = p.bbox;
|
|
1030
|
-
|
|
1031
|
-
for (
|
|
1032
|
-
for (
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
|
|
1233
|
+
let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
|
|
1234
|
+
for (let cxi = 0;cxi < 2; cxi++)
|
|
1235
|
+
for (let czi = 0;czi < 2; czi++) {
|
|
1236
|
+
const x = cxi ? b[3] : b[0], z = czi ? b[5] : b[2];
|
|
1237
|
+
const wx = m[0] + m[3] * x + m[5] * z, wz = m[2] + m[9] * x + m[11] * z;
|
|
1238
|
+
if (wx < x0)
|
|
1239
|
+
x0 = wx;
|
|
1240
|
+
if (wx > x1)
|
|
1241
|
+
x1 = wx;
|
|
1242
|
+
if (wz < z0)
|
|
1243
|
+
z0 = wz;
|
|
1244
|
+
if (wz > z1)
|
|
1245
|
+
z1 = wz;
|
|
1036
1246
|
}
|
|
1037
|
-
const
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1247
|
+
const ri = rInst.length;
|
|
1248
|
+
rx0.push(x0);
|
|
1249
|
+
rx1.push(x1);
|
|
1250
|
+
rz0.push(z0);
|
|
1251
|
+
rz1.push(z1);
|
|
1252
|
+
rInst.push(idx);
|
|
1253
|
+
rPrep.push(prepPart(H, it.part));
|
|
1254
|
+
rBx.push(b[0]);
|
|
1255
|
+
rBz.push(b[2]);
|
|
1256
|
+
const lv2 = Math.round((m[1] + b[4]) * 2);
|
|
1257
|
+
for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
|
|
1258
|
+
for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
|
|
1259
|
+
const k = cellKey(lv2, cx, cz);
|
|
1260
|
+
if (k < 0)
|
|
1261
|
+
continue;
|
|
1262
|
+
const e = rectE.length;
|
|
1263
|
+
rectE.push(ri);
|
|
1264
|
+
nextE.push(cells.put(k, e));
|
|
1043
1265
|
}
|
|
1044
|
-
}
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1266
|
+
}
|
|
1267
|
+
const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
|
|
1268
|
+
const coverStep = (x, y, z, self) => {
|
|
1269
|
+
const k = cellKey(Math.round(y * 2), Math.floor(x / CELL), Math.floor(z / CELL));
|
|
1270
|
+
if (k < 0)
|
|
1271
|
+
return STEP_NEVER;
|
|
1272
|
+
let best = STEP_NEVER;
|
|
1273
|
+
for (let e = cells.get(k);e >= 0; e = nextE[e]) {
|
|
1274
|
+
const ri = rectE[e];
|
|
1275
|
+
if (rInst[ri] === self || !(x - 6 >= rx0[ri] - 0.5 && x + 6 <= rx1[ri] + 0.5 && z - 6 >= rz0[ri] - 0.5 && z + 6 <= rz1[ri] + 0.5))
|
|
1051
1276
|
continue;
|
|
1052
|
-
const
|
|
1053
|
-
const
|
|
1054
|
-
const
|
|
1277
|
+
const m = insts[rInst[ri]].m;
|
|
1278
|
+
const pp = rPrep[ri];
|
|
1279
|
+
const bx = rBx[ri], bz = rBz[ri];
|
|
1055
1280
|
const dx = x - m[0], dy = y - m[1], dz = z - m[2];
|
|
1056
1281
|
const lx = m[3] * dx + m[6] * dy + m[9] * dz, lz = m[5] * dx + m[8] * dy + m[11] * dz;
|
|
1057
|
-
const
|
|
1282
|
+
const { nx, nz, mask: bits } = pp;
|
|
1058
1283
|
let ok = true;
|
|
1059
|
-
for (
|
|
1060
|
-
const ca = Math.floor((lx +
|
|
1061
|
-
if (ca < 0 || cb < 0 || ca >= nx || cb >= nz || bits[ca * nz + cb] !==
|
|
1284
|
+
for (let s = 0;s < 5; s++) {
|
|
1285
|
+
const ca = Math.floor((lx + SX[s] - bx) / 20), cb = Math.floor((lz + SZ[s] - bz) / 20);
|
|
1286
|
+
if (ca < 0 || cb < 0 || ca >= nx || cb >= nz || bits[ca * nz + cb] !== 1) {
|
|
1062
1287
|
ok = false;
|
|
1063
1288
|
break;
|
|
1064
1289
|
}
|
|
1065
1290
|
}
|
|
1066
|
-
if (ok)
|
|
1067
|
-
|
|
1291
|
+
if (ok) {
|
|
1292
|
+
if (!steps)
|
|
1293
|
+
return 0;
|
|
1294
|
+
const st = steps[rInst[ri]];
|
|
1295
|
+
if (st < best)
|
|
1296
|
+
best = st;
|
|
1297
|
+
}
|
|
1068
1298
|
}
|
|
1069
|
-
return
|
|
1299
|
+
return best;
|
|
1070
1300
|
};
|
|
1071
|
-
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1301
|
+
let nStuds = 0;
|
|
1302
|
+
for (const it of insts) {
|
|
1303
|
+
const pp = prepPart(H, it.part);
|
|
1304
|
+
if (pp)
|
|
1305
|
+
nStuds += pp.nStuds;
|
|
1306
|
+
}
|
|
1307
|
+
const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
|
|
1308
|
+
const tops = new NumTable(nStuds);
|
|
1309
|
+
let studsHidden = 0;
|
|
1310
|
+
const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
|
|
1311
|
+
forEachStud(insts, H, (j, idx, w) => {
|
|
1312
|
+
if (!upright(w))
|
|
1077
1313
|
return;
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
if (
|
|
1084
|
-
|
|
1314
|
+
studUp[j] = 1;
|
|
1315
|
+
const cs = coverStep(w[0], w[1], w[2], idx);
|
|
1316
|
+
if (cs !== STEP_NEVER) {
|
|
1317
|
+
studHidden[j] = 1;
|
|
1318
|
+
studsHidden++;
|
|
1319
|
+
if (studHideStep)
|
|
1320
|
+
studHideStep[j] = cs;
|
|
1085
1321
|
}
|
|
1322
|
+
const k = topKey(w[0], w[1], w[2]);
|
|
1323
|
+
if (k < 0)
|
|
1324
|
+
return;
|
|
1325
|
+
if (!steps) {
|
|
1326
|
+
tops.put(k, 1);
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const st = steps[idx], o = tops.get(k);
|
|
1330
|
+
if (o < 0 || st < o)
|
|
1331
|
+
tops.put(k, st);
|
|
1086
1332
|
});
|
|
1087
|
-
const underHidden = insts.
|
|
1333
|
+
const underHidden = new Uint8Array(insts.length);
|
|
1334
|
+
const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
|
|
1335
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1336
|
+
const it = insts[idx];
|
|
1088
1337
|
const p = H.parts[it.part];
|
|
1089
1338
|
if (!p || !p.under || !upright(it.m))
|
|
1090
|
-
|
|
1339
|
+
continue;
|
|
1091
1340
|
const b = p.bbox;
|
|
1092
1341
|
const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
|
|
1093
1342
|
if (!nx || !nz || nx * nz > 4096)
|
|
1094
|
-
|
|
1095
|
-
|
|
1343
|
+
continue;
|
|
1344
|
+
const m = it.m;
|
|
1345
|
+
let all = true, at = 0;
|
|
1346
|
+
for (let a = 0;a < nx && all; a++)
|
|
1096
1347
|
for (let c = 0;c < nz; c++) {
|
|
1097
1348
|
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1098
|
-
const x =
|
|
1099
|
-
|
|
1100
|
-
|
|
1349
|
+
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1350
|
+
const k = topKey(x, m[1] + b[4], z);
|
|
1351
|
+
const t = k < 0 ? -1 : tops.get(k);
|
|
1352
|
+
if (t < 0) {
|
|
1353
|
+
all = false;
|
|
1354
|
+
break;
|
|
1355
|
+
}
|
|
1356
|
+
if (t > at)
|
|
1357
|
+
at = t;
|
|
1101
1358
|
}
|
|
1102
|
-
|
|
1359
|
+
if (all) {
|
|
1360
|
+
underHidden[idx] = 1;
|
|
1361
|
+
if (underHideStep)
|
|
1362
|
+
underHideStep[idx] = at;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
|
|
1366
|
+
}
|
|
1367
|
+
function computeCulling(insts, H) {
|
|
1368
|
+
const c = cullCore(insts, H);
|
|
1369
|
+
const studs = new Array(c.nStuds);
|
|
1370
|
+
forEachStud(insts, H, (j, _i, w, kind, color) => {
|
|
1371
|
+
studs[j] = { kind, color, w: Array.from(w), hidden: c.studHidden[j] === 1 };
|
|
1103
1372
|
});
|
|
1104
|
-
return { studs, underHidden };
|
|
1373
|
+
return { studs, underHidden: Array.from(c.underHidden, (x) => x === 1) };
|
|
1374
|
+
}
|
|
1375
|
+
function gridClusters(n, x, z, k) {
|
|
1376
|
+
if (n <= k || !isFinite(k)) {
|
|
1377
|
+
const a = new Int32Array(n);
|
|
1378
|
+
for (let i = 0;i < n; i++)
|
|
1379
|
+
a[i] = i;
|
|
1380
|
+
return [a];
|
|
1381
|
+
}
|
|
1382
|
+
let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
|
|
1383
|
+
for (let i = 0;i < n; i++) {
|
|
1384
|
+
const a = x(i), b = z(i);
|
|
1385
|
+
if (a < x0)
|
|
1386
|
+
x0 = a;
|
|
1387
|
+
if (a > x1)
|
|
1388
|
+
x1 = a;
|
|
1389
|
+
if (b < z0)
|
|
1390
|
+
z0 = b;
|
|
1391
|
+
if (b > z1)
|
|
1392
|
+
z1 = b;
|
|
1393
|
+
}
|
|
1394
|
+
const G = Math.max(1, Math.ceil(Math.sqrt(n / k)));
|
|
1395
|
+
const sx = (x1 - x0) / G || 1, sz = (z1 - z0) / G || 1;
|
|
1396
|
+
const cell = new Int32Array(n), cnt = new Int32Array(G * G);
|
|
1397
|
+
for (let i = 0;i < n; i++) {
|
|
1398
|
+
const c = Math.min(G - 1, Math.floor((x(i) - x0) / sx)) * G + Math.min(G - 1, Math.floor((z(i) - z0) / sz));
|
|
1399
|
+
cell[i] = c;
|
|
1400
|
+
cnt[c]++;
|
|
1401
|
+
}
|
|
1402
|
+
const out = [];
|
|
1403
|
+
const at = new Int32Array(G * G).fill(-1);
|
|
1404
|
+
const fill = new Int32Array(G * G);
|
|
1405
|
+
for (let c = 0;c < G * G; c++)
|
|
1406
|
+
if (cnt[c]) {
|
|
1407
|
+
at[c] = out.length;
|
|
1408
|
+
out.push(new Int32Array(cnt[c]));
|
|
1409
|
+
}
|
|
1410
|
+
for (let i = 0;i < n; i++) {
|
|
1411
|
+
const c = cell[i];
|
|
1412
|
+
out[at[c]][fill[c]++] = i;
|
|
1413
|
+
}
|
|
1414
|
+
return out;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
class LdrLodRoot extends THREE.LOD {
|
|
1418
|
+
clusters = [];
|
|
1419
|
+
vpH = 1080;
|
|
1420
|
+
px = 0.5;
|
|
1421
|
+
edgePpl = 0.025;
|
|
1422
|
+
enabled = true;
|
|
1423
|
+
apply = () => {};
|
|
1424
|
+
inv = new THREE.Matrix4;
|
|
1425
|
+
cp = new THREE.Vector3;
|
|
1426
|
+
constructor() {
|
|
1427
|
+
super();
|
|
1428
|
+
this.autoUpdate = true;
|
|
1429
|
+
}
|
|
1430
|
+
raycast() {}
|
|
1431
|
+
update(camera) {
|
|
1432
|
+
if (!this.enabled || !this.clusters.length)
|
|
1433
|
+
return;
|
|
1434
|
+
const pm = camera.projectionMatrix.elements;
|
|
1435
|
+
const persp = camera.isPerspectiveCamera || pm[15] === 0;
|
|
1436
|
+
const k = this.vpH / 2 * Math.abs(pm[5]);
|
|
1437
|
+
this.inv.copy(this.matrixWorld).invert();
|
|
1438
|
+
this.cp.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(this.inv);
|
|
1439
|
+
const { x, y, z } = this.cp;
|
|
1440
|
+
const tau = this.px, eppl = this.edgePpl;
|
|
1441
|
+
for (const c of this.clusters) {
|
|
1442
|
+
const cx = c.s.center.x - x, cy = c.s.center.y - y, cz = c.s.center.z - z;
|
|
1443
|
+
const d = Math.sqrt(cx * cx + cy * cy + cz * cz) - c.s.radius;
|
|
1444
|
+
const ppl = persp ? d > 0.000001 ? k / d : Infinity : k;
|
|
1445
|
+
let L = 0;
|
|
1446
|
+
for (let i = c.lv.length - 1;i > 0; i--)
|
|
1447
|
+
if (c.lv[i].err * ppl <= tau) {
|
|
1448
|
+
L = i;
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
const e = ppl >= eppl;
|
|
1452
|
+
if (L !== c.cur || e !== c.edgeOk) {
|
|
1453
|
+
c.cur = L;
|
|
1454
|
+
c.edgeOk = e;
|
|
1455
|
+
this.apply(c);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, colorIndex) {
|
|
1461
|
+
const bucketOf = new Map;
|
|
1462
|
+
const bKind = [], bMirror = [];
|
|
1463
|
+
const bAll = [];
|
|
1464
|
+
const studBucket = new Uint16Array(cull.nStuds);
|
|
1465
|
+
const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
|
|
1466
|
+
forEachStud(insts, H, (j, _i, w, kind) => {
|
|
1467
|
+
const neg = det12(w) < 0;
|
|
1468
|
+
const k = neg ? kind + "#m" : kind;
|
|
1469
|
+
let b = bucketOf.get(k);
|
|
1470
|
+
if (b === undefined) {
|
|
1471
|
+
b = bKind.length;
|
|
1472
|
+
bucketOf.set(k, b);
|
|
1473
|
+
bKind.push(kind);
|
|
1474
|
+
bMirror.push(neg);
|
|
1475
|
+
bAll.push(0);
|
|
1476
|
+
}
|
|
1477
|
+
studBucket[j] = b;
|
|
1478
|
+
bAll[b]++;
|
|
1479
|
+
sx[j] = w[0];
|
|
1480
|
+
sz[j] = w[2];
|
|
1481
|
+
});
|
|
1482
|
+
const bIds = bAll.map((n) => new Int32Array(n));
|
|
1483
|
+
{
|
|
1484
|
+
const f = bAll.map(() => 0);
|
|
1485
|
+
for (let j = 0;j < cull.nStuds; j++) {
|
|
1486
|
+
const b = studBucket[j];
|
|
1487
|
+
bIds[b][f[b]++] = j;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
|
|
1491
|
+
const sMesh = [];
|
|
1492
|
+
bKind.forEach((kind, b) => {
|
|
1493
|
+
const g = geom(H.studKinds[kind].body, arr, Q);
|
|
1494
|
+
const ids = bIds[b];
|
|
1495
|
+
for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
|
|
1496
|
+
const ci = sMesh.length;
|
|
1497
|
+
let v = 0;
|
|
1498
|
+
for (const i of c)
|
|
1499
|
+
if (!cull.studHidden[ids[i]])
|
|
1500
|
+
v++;
|
|
1501
|
+
let vc = 0, hc = v;
|
|
1502
|
+
for (const i of c) {
|
|
1503
|
+
const j = ids[i];
|
|
1504
|
+
studCl[j] = ci;
|
|
1505
|
+
studSlot[j] = cull.studHidden[j] ? hc++ : vc++;
|
|
1506
|
+
}
|
|
1507
|
+
if (!g) {
|
|
1508
|
+
sMesh.push(null);
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
const im = newIM(g, bMirror[b] ? matB : matF, c.length);
|
|
1512
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(new Float32Array(c.length * 3), 3);
|
|
1513
|
+
const n = c.length;
|
|
1514
|
+
sMesh.push({ im, kind, vis: v, ...steps ? { slots: { own: new Int32Array(n), hide: new Int32Array(n), inst: new Int32Array(n), stud: new Int16Array(n), col: new Uint16Array(n) } } : {} });
|
|
1515
|
+
}
|
|
1516
|
+
});
|
|
1517
|
+
forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
|
|
1518
|
+
const sm = sMesh[studCl[j]];
|
|
1519
|
+
if (!sm)
|
|
1520
|
+
return;
|
|
1521
|
+
const im = sm.im;
|
|
1522
|
+
const slot = studSlot[j];
|
|
1523
|
+
if (sm.slots) {
|
|
1524
|
+
const t = sm.slots;
|
|
1525
|
+
t.own[slot] = steps[owner];
|
|
1526
|
+
t.hide[slot] = cull.studHideStep[j];
|
|
1527
|
+
t.inst[slot] = owner;
|
|
1528
|
+
t.stud[slot] = si;
|
|
1529
|
+
t.col[slot] = colorIndex(col);
|
|
1530
|
+
}
|
|
1531
|
+
writeM4(im.instanceMatrix.array, slot * 16, w);
|
|
1532
|
+
color(col).toArray(im.instanceColor.array, slot * 3);
|
|
1533
|
+
});
|
|
1534
|
+
return sMesh;
|
|
1105
1535
|
}
|
|
1106
1536
|
function buildLdrScene(insts, pack, P, color, mark) {
|
|
1107
1537
|
const { header: H, arr } = pack;
|
|
1108
|
-
const
|
|
1538
|
+
const Q = P.quant !== false;
|
|
1539
|
+
const LOD = P.lod !== false;
|
|
1540
|
+
const root = new LdrLodRoot;
|
|
1541
|
+
root.enabled = LOD;
|
|
1542
|
+
root.px = P.lodPx ?? 0.5;
|
|
1543
|
+
root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
|
|
1544
|
+
const trackVp = (r) => {
|
|
1545
|
+
const rt = r.getRenderTarget();
|
|
1546
|
+
const h = rt ? rt.height : r.getContext().drawingBufferHeight;
|
|
1547
|
+
if (h)
|
|
1548
|
+
root.vpH = h;
|
|
1549
|
+
};
|
|
1109
1550
|
const matF = makeMaterial(P.side === "front" ? THREE.FrontSide : THREE.DoubleSide), matB = makeMaterial(P.side === "front" ? THREE.BackSide : THREE.DoubleSide);
|
|
1110
1551
|
const matD = makeMaterial(THREE.DoubleSide);
|
|
1111
1552
|
let nUncert = 0;
|
|
1112
|
-
const det = (m) => m[3] * (m[7] * m[11] - m[8] * m[10]) - m[4] * (m[6] * m[11] - m[8] * m[9]) + m[5] * (m[6] * m[10] - m[7] * m[9]);
|
|
1113
1553
|
const byPart = new Map;
|
|
1114
1554
|
insts.forEach((it, i) => {
|
|
1115
1555
|
if (H.parts[it.part]) {
|
|
1116
|
-
const k = it.part + (
|
|
1556
|
+
const k = it.part + (det12(it.m) < 0 ? "#m" : "");
|
|
1117
1557
|
(byPart.get(k) || byPart.set(k, []).get(k)).push(i);
|
|
1118
1558
|
}
|
|
1119
1559
|
});
|
|
1120
|
-
const
|
|
1560
|
+
const steps = P.steps;
|
|
1561
|
+
let cull = cullCore(insts, H, steps);
|
|
1121
1562
|
mark("culling");
|
|
1563
|
+
const stepBatches = [];
|
|
1564
|
+
const instM = steps ? new Float64Array(insts.length * 12) : null;
|
|
1565
|
+
const instPP = [];
|
|
1566
|
+
const palette = [];
|
|
1567
|
+
const palIdx = new Map;
|
|
1568
|
+
const colorIndex = (c) => {
|
|
1569
|
+
let i = palIdx.get(c);
|
|
1570
|
+
if (i === undefined) {
|
|
1571
|
+
i = palette.length;
|
|
1572
|
+
palette.push(color(c));
|
|
1573
|
+
palIdx.set(c, i);
|
|
1574
|
+
}
|
|
1575
|
+
return i;
|
|
1576
|
+
};
|
|
1577
|
+
const instCol = steps ? new Uint16Array(insts.length) : null;
|
|
1578
|
+
if (instM)
|
|
1579
|
+
insts.forEach((it, i) => {
|
|
1580
|
+
for (let k = 0;k < 12; k++)
|
|
1581
|
+
instM[i * 12 + k] = it.m[k];
|
|
1582
|
+
instPP.push(prepPart(H, it.part));
|
|
1583
|
+
instCol[i] = colorIndex(it.color);
|
|
1584
|
+
});
|
|
1122
1585
|
const edgeObjs = [];
|
|
1123
1586
|
const condObjs = [];
|
|
1124
1587
|
const wantCond = P.cond !== false && (P.edges === "idx" || P.edges === true);
|
|
1125
1588
|
let condMat = null;
|
|
1126
1589
|
const cmat = () => condMat ??= condLineMat();
|
|
1590
|
+
let lineMatShared = null;
|
|
1591
|
+
const lmat = () => lineMatShared ??= sharedLineMat();
|
|
1127
1592
|
const condCache = new Map;
|
|
1128
|
-
const addCond = (entry, im, which = "body") => {
|
|
1593
|
+
const addCond = (entry, im, cl, which = "body") => {
|
|
1129
1594
|
if (!wantCond)
|
|
1130
1595
|
return null;
|
|
1131
1596
|
const ck = which === "under" ? entry.condlu : entry.condl;
|
|
@@ -1142,12 +1607,40 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1142
1607
|
const l = condEdges(cb, im, cmat());
|
|
1143
1608
|
edgeObjs.push(l);
|
|
1144
1609
|
condObjs.push(l);
|
|
1610
|
+
cl.cond.push(l);
|
|
1145
1611
|
root.add(l);
|
|
1146
1612
|
return l;
|
|
1147
1613
|
};
|
|
1148
|
-
const
|
|
1614
|
+
const lineCache = new Map;
|
|
1615
|
+
const addLines = (ref, im, cl) => {
|
|
1616
|
+
let w = lineCache.get(ref);
|
|
1617
|
+
if (!w) {
|
|
1618
|
+
const r = weldLines(arr(ref));
|
|
1619
|
+
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
|
|
1620
|
+
}
|
|
1621
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1622
|
+
g.setAttribute("position", w.P);
|
|
1623
|
+
g.setIndex(w.I);
|
|
1624
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1625
|
+
g.instanceCount = im.count;
|
|
1626
|
+
const l = new THREE.LineSegments(g, lmat());
|
|
1627
|
+
l.frustumCulled = false;
|
|
1628
|
+
edgeObjs.push(l);
|
|
1629
|
+
cl.lines.push(l);
|
|
1630
|
+
root.add(l);
|
|
1631
|
+
return l;
|
|
1632
|
+
};
|
|
1633
|
+
const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
|
|
1149
1634
|
const toggles = [];
|
|
1150
1635
|
const studMeshes = [];
|
|
1636
|
+
const countTo = (objs) => ({ set count(n) {
|
|
1637
|
+
for (const o of objs()) {
|
|
1638
|
+
if (o.isInstancedMesh)
|
|
1639
|
+
o.count = n;
|
|
1640
|
+
else
|
|
1641
|
+
o.geometry.instanceCount = n;
|
|
1642
|
+
}
|
|
1643
|
+
} });
|
|
1151
1644
|
const wantTex = P.tex !== false && !!H.textures;
|
|
1152
1645
|
const texCache = new Map;
|
|
1153
1646
|
const texMats = new Map;
|
|
@@ -1169,160 +1662,256 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1169
1662
|
return m;
|
|
1170
1663
|
};
|
|
1171
1664
|
let texBatches = 0;
|
|
1172
|
-
|
|
1665
|
+
const newCluster = (s) => {
|
|
1666
|
+
const c = { s, lv: [], lines: [], cond: [], cur: 0, edgeOk: true };
|
|
1667
|
+
root.clusters.push(c);
|
|
1668
|
+
return c;
|
|
1669
|
+
};
|
|
1670
|
+
const lodLevels = (b, base, mat) => !LOD || P.lodMesh === false || !b?.lod ? [] : b.lod.map((l) => {
|
|
1671
|
+
const im = new THREE.InstancedMesh(geom(l, arr, Q), mat, 0);
|
|
1672
|
+
im.instanceMatrix = base.instanceMatrix;
|
|
1673
|
+
im.count = base.count;
|
|
1674
|
+
im.instanceColor = base.instanceColor;
|
|
1675
|
+
im.boundingSphere = base.boundingSphere;
|
|
1676
|
+
im.visible = false;
|
|
1677
|
+
im.onBeforeRender = trackVp;
|
|
1678
|
+
im.userData.ldrLod = true;
|
|
1679
|
+
root.add(im);
|
|
1680
|
+
return { objs: [im], err: l.err };
|
|
1681
|
+
});
|
|
1682
|
+
const tris = (b) => b ? b.tris ?? 0 : 0;
|
|
1683
|
+
const kFor = (t) => LOD ? Math.max(256, Math.min(16384, Math.round(262144 / Math.max(1, t)))) : Infinity;
|
|
1684
|
+
for (const [pk, idsAll] of byPart) {
|
|
1173
1685
|
const part = pk.replace(/#m$/, "");
|
|
1174
1686
|
const p = H.parts[part];
|
|
1175
1687
|
const mat = P.uncertDouble !== false && p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
|
|
1176
1688
|
const textured = wantTex && !!p.tex;
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
im
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const g = geom(tb, arr);
|
|
1194
|
-
const im = new THREE.InstancedMesh(g, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
1195
|
-
texBatches++;
|
|
1196
|
-
if (bodyIm) {
|
|
1197
|
-
im.instanceMatrix = bodyIm.instanceMatrix;
|
|
1198
|
-
im.instanceColor = bodyIm.instanceColor;
|
|
1199
|
-
im.boundingSphere = bodyIm.boundingSphere;
|
|
1200
|
-
root.add(im);
|
|
1201
|
-
} else {
|
|
1202
|
-
place(im);
|
|
1203
|
-
bodyIm = im;
|
|
1204
|
-
}
|
|
1689
|
+
const bodyB = textured ? p.tbody : p.body;
|
|
1690
|
+
const body = geom(bodyB, arr, Q);
|
|
1691
|
+
const groups = gridClusters(idsAll.length, (i) => insts[idsAll[i]].m[0], (i) => insts[idsAll[i]].m[2], textured ? Infinity : kFor(tris(p.body) + tris(p.under)));
|
|
1692
|
+
for (const g of groups) {
|
|
1693
|
+
const ids = Array.from(g, (i) => idsAll[i]);
|
|
1694
|
+
let bodyIm = null;
|
|
1695
|
+
const lv0 = [];
|
|
1696
|
+
const place = (im) => {
|
|
1697
|
+
fillInstances(im, ids, insts, color);
|
|
1698
|
+
im.computeBoundingSphere();
|
|
1699
|
+
root.add(im);
|
|
1700
|
+
};
|
|
1701
|
+
if (body) {
|
|
1702
|
+
const im = bodyIm = newIM(body, mat, ids.length);
|
|
1703
|
+
place(im);
|
|
1704
|
+
lv0.push(im);
|
|
1205
1705
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1706
|
+
if (textured)
|
|
1707
|
+
for (const tb of p.tex) {
|
|
1708
|
+
const gg = geom(tb, arr, Q);
|
|
1709
|
+
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
1710
|
+
texBatches++;
|
|
1711
|
+
lv0.push(im);
|
|
1712
|
+
if (bodyIm) {
|
|
1713
|
+
im.instanceMatrix = bodyIm.instanceMatrix;
|
|
1714
|
+
im.instanceColor = bodyIm.instanceColor;
|
|
1715
|
+
im.boundingSphere = bodyIm.boundingSphere;
|
|
1716
|
+
root.add(im);
|
|
1717
|
+
} else {
|
|
1718
|
+
place(im);
|
|
1719
|
+
bodyIm = im;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
if (bodyIm) {
|
|
1723
|
+
const cl = newCluster(bodyIm.boundingSphere);
|
|
1724
|
+
lv0.forEach((o) => o.onBeforeRender = trackVp);
|
|
1725
|
+
cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
|
|
1726
|
+
if (P.edges === "idx" && p.edges)
|
|
1727
|
+
addLines(p.edges, bodyIm, cl);
|
|
1728
|
+
addCond(p, bodyIm, cl);
|
|
1729
|
+
if (steps)
|
|
1730
|
+
stepBatches.push({ im: bodyIm, objs: [...cl.lv.flatMap((l) => l.objs), ...cl.lines, ...cl.cond], own: Int32Array.from(ids, (id) => steps[id]), hide: null, flag: "body", inst: Int32Array.from(ids), stud: null, col: Uint16Array.from(ids, (id) => instCol[id]) });
|
|
1731
|
+
if (P.edges === true && p.edges) {
|
|
1732
|
+
const mats = new Float32Array(ids.length * 16);
|
|
1733
|
+
ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
|
|
1734
|
+
{
|
|
1735
|
+
const l = instancedLines(arr(p.edges), mats, ids.length);
|
|
1736
|
+
edgeObjs.push(l);
|
|
1737
|
+
cl.lines.push(l);
|
|
1738
|
+
root.add(l);
|
|
1739
|
+
}
|
|
1235
1740
|
}
|
|
1236
1741
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1742
|
+
const under = geom(p.under, arr, Q);
|
|
1743
|
+
if (under) {
|
|
1744
|
+
const ord = [...ids.filter((i) => !cull.underHidden[i]), ...ids.filter((i) => cull.underHidden[i])];
|
|
1745
|
+
const vis = ids.length - ids.reduce((a, i) => a + cull.underHidden[i], 0);
|
|
1746
|
+
stats.undersTotal += ids.length;
|
|
1747
|
+
stats.undersHidden += ids.length - vis;
|
|
1748
|
+
const im = newIM(under, mat, ids.length);
|
|
1749
|
+
fillInstances(im, ord, insts, color);
|
|
1750
|
+
im.onBeforeRender = trackVp;
|
|
1751
|
+
im.computeBoundingSphere();
|
|
1752
|
+
im.count = P.cullUnder ? vis : ids.length;
|
|
1753
|
+
root.add(im);
|
|
1754
|
+
const cl = newCluster(im.boundingSphere);
|
|
1755
|
+
cl.lv.push({ objs: [im], err: 0 }, ...lodLevels(p.under, im, mat));
|
|
1756
|
+
addCond(p, im, cl, "under");
|
|
1757
|
+
const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
|
|
1758
|
+
objs.forEach((o) => {
|
|
1759
|
+
if (!o.isInstancedMesh)
|
|
1760
|
+
o.geometry.instanceCount = im.count;
|
|
1761
|
+
});
|
|
1762
|
+
toggles.push({ mesh: countTo(() => objs), all: ids.length, visible: vis, flag: "under" });
|
|
1763
|
+
if (steps)
|
|
1764
|
+
stepBatches.push({ im, objs, own: Int32Array.from(ord, (id) => steps[id]), hide: Int32Array.from(ord, (id) => cull.underHideStep[id]), flag: "under", inst: Int32Array.from(ord), stud: null, col: Uint16Array.from(ord, (id) => instCol[id]) });
|
|
1245
1765
|
}
|
|
1246
1766
|
}
|
|
1247
1767
|
}
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const
|
|
1768
|
+
const sMesh = buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, steps && colorIndex);
|
|
1769
|
+
const sKind = sMesh.map((x) => x?.kind ?? "");
|
|
1770
|
+
const sVis = sMesh.map((x) => x?.vis ?? 0);
|
|
1771
|
+
const STUD_ERR = 12;
|
|
1772
|
+
sMesh.forEach((sm, ci) => {
|
|
1773
|
+
if (!sm)
|
|
1774
|
+
return;
|
|
1775
|
+
const im = sm.im;
|
|
1776
|
+
const kind = sKind[ci];
|
|
1256
1777
|
const k = H.studKinds[kind];
|
|
1257
|
-
const
|
|
1258
|
-
if (!g)
|
|
1259
|
-
continue;
|
|
1260
|
-
const ord = [...list.filter((s) => !s.hidden), ...list.filter((s) => s.hidden)];
|
|
1261
|
-
const vis = list.filter((s) => !s.hidden).length;
|
|
1262
|
-
const im = new THREE.InstancedMesh(g, mat, ord.length);
|
|
1263
|
-
ord.forEach((s, i) => {
|
|
1264
|
-
im.setMatrixAt(i, toM4(s.w));
|
|
1265
|
-
im.setColorAt(i, color(s.color));
|
|
1266
|
-
});
|
|
1778
|
+
const vis = sVis[ci], all = im.instanceMatrix.count;
|
|
1267
1779
|
im.computeBoundingSphere();
|
|
1268
|
-
im.count = P.cullStuds ? vis :
|
|
1780
|
+
im.count = P.cullStuds ? vis : all;
|
|
1781
|
+
im.onBeforeRender = trackVp;
|
|
1782
|
+
im.userData.ldrStud = true;
|
|
1269
1783
|
root.add(im);
|
|
1270
|
-
toggles.push({ mesh: im, all: ord.length, visible: vis, flag: "studs" });
|
|
1271
1784
|
studMeshes.push({ im, kind });
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}
|
|
1281
|
-
{
|
|
1282
|
-
const cl = P.condStuds === false ? null : addCond(k, im);
|
|
1283
|
-
if (cl) {
|
|
1284
|
-
toggles.push({ mesh: { set count(n) {
|
|
1285
|
-
cl.geometry.instanceCount = n;
|
|
1286
|
-
} }, all: ord.length, visible: vis, flag: "studs" });
|
|
1287
|
-
cl.geometry.instanceCount = im.count;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1785
|
+
const cl = newCluster(im.boundingSphere);
|
|
1786
|
+
cl.lv.push({ objs: [im], err: 0 });
|
|
1787
|
+
if (LOD && P.lodStuds !== false)
|
|
1788
|
+
cl.lv.push({ objs: [], err: STUD_ERR });
|
|
1789
|
+
if (P.edges === "idx" && k.edges)
|
|
1790
|
+
addLines(k.edges, im, cl);
|
|
1791
|
+
if (P.condStuds !== false)
|
|
1792
|
+
addCond(k, im, cl);
|
|
1290
1793
|
if (P.edges === true && k.edges) {
|
|
1291
|
-
const
|
|
1292
|
-
ord.forEach((s, i) => toM4(s.w).toArray(mats, i * 16));
|
|
1293
|
-
const l = instancedLines(arr(k.edges), mats, P.cullStuds ? vis : ord.length);
|
|
1794
|
+
const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
|
|
1294
1795
|
edgeObjs.push(l);
|
|
1796
|
+
cl.lines.push(l);
|
|
1295
1797
|
root.add(l);
|
|
1296
|
-
toggles.push({ mesh: { set count(n) {
|
|
1297
|
-
l.geometry.instanceCount = n;
|
|
1298
|
-
} }, all: ord.length, visible: vis, flag: "studs" });
|
|
1299
1798
|
}
|
|
1300
|
-
|
|
1799
|
+
const objs = [im, ...cl.lines, ...cl.cond];
|
|
1800
|
+
objs.forEach((o) => {
|
|
1801
|
+
if (!o.isInstancedMesh)
|
|
1802
|
+
o.geometry.instanceCount = im.count;
|
|
1803
|
+
});
|
|
1804
|
+
toggles.push({ mesh: countTo(() => objs), all, visible: vis, flag: "studs" });
|
|
1805
|
+
if (sm.slots)
|
|
1806
|
+
stepBatches.push({ im, objs, flag: "studs", ...sm.slots });
|
|
1807
|
+
});
|
|
1301
1808
|
stats.uncertParts = Object.values(H.parts).filter((x) => x.uncert).length;
|
|
1302
1809
|
stats.uncertBatches = nUncert;
|
|
1303
1810
|
let condOn = true, edgesOn = true;
|
|
1811
|
+
root.apply = (c) => {
|
|
1812
|
+
c.lv.forEach((l, i) => {
|
|
1813
|
+
for (const o of l.objs)
|
|
1814
|
+
o.visible = i === c.cur;
|
|
1815
|
+
});
|
|
1816
|
+
const lineVis = edgesOn && c.edgeOk && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
1817
|
+
for (const o of c.lines)
|
|
1818
|
+
o.visible = lineVis;
|
|
1819
|
+
for (const o of c.cond)
|
|
1820
|
+
o.visible = lineVis && condOn;
|
|
1821
|
+
};
|
|
1822
|
+
const refresh = () => root.clusters.forEach(root.apply);
|
|
1304
1823
|
const setEdges = (v) => {
|
|
1305
1824
|
edgesOn = v;
|
|
1306
|
-
|
|
1825
|
+
refresh();
|
|
1307
1826
|
};
|
|
1308
1827
|
const setCond = (v) => {
|
|
1309
1828
|
condOn = v;
|
|
1310
|
-
|
|
1829
|
+
refresh();
|
|
1311
1830
|
};
|
|
1831
|
+
refresh();
|
|
1312
1832
|
stats.condBatches = condObjs.length;
|
|
1313
1833
|
stats.texBatches = texBatches;
|
|
1314
1834
|
stats.textures = texCache.size;
|
|
1835
|
+
stats.clusters = root.clusters.length;
|
|
1315
1836
|
const texturesReady = Promise.all(pending).then(() => {});
|
|
1837
|
+
let stepS = STEP_NEVER - 1, cullS = !!P.cullStuds, cullU = !!P.cullUnder;
|
|
1838
|
+
const applySteps = () => {
|
|
1839
|
+
const st = { studsTotal: 0, studsHidden: 0, undersTotal: 0, undersHidden: 0 };
|
|
1840
|
+
const S = stepS;
|
|
1841
|
+
const wm = new Float64Array(12);
|
|
1842
|
+
for (const b of stepBatches) {
|
|
1843
|
+
const MA = b.im.instanceMatrix.array, CA = b.im.instanceColor.array;
|
|
1844
|
+
const useHide = b.flag === "studs" ? cullS : b.flag === "under" ? cullU : false;
|
|
1845
|
+
const { own, hide, inst, stud, col } = b;
|
|
1846
|
+
let w = 0;
|
|
1847
|
+
for (let i = 0;i < own.length; i++) {
|
|
1848
|
+
if (own[i] > S)
|
|
1849
|
+
continue;
|
|
1850
|
+
const hid = !!hide && hide[i] <= S;
|
|
1851
|
+
if (b.flag === "studs") {
|
|
1852
|
+
st.studsTotal++;
|
|
1853
|
+
if (hid)
|
|
1854
|
+
st.studsHidden++;
|
|
1855
|
+
} else if (b.flag === "under") {
|
|
1856
|
+
st.undersTotal++;
|
|
1857
|
+
if (hid)
|
|
1858
|
+
st.undersHidden++;
|
|
1859
|
+
}
|
|
1860
|
+
if (useHide && hid)
|
|
1861
|
+
continue;
|
|
1862
|
+
const n = inst[i];
|
|
1863
|
+
if (stud) {
|
|
1864
|
+
mul12To(instM, instPP[n].studM, stud[i] * 12, wm, n * 12);
|
|
1865
|
+
writeM4(MA, w * 16, wm);
|
|
1866
|
+
} else
|
|
1867
|
+
writeM4(MA, w * 16, instM, n * 12);
|
|
1868
|
+
palette[col[i]].toArray(CA, w * 3);
|
|
1869
|
+
w++;
|
|
1870
|
+
}
|
|
1871
|
+
b.im.instanceMatrix.needsUpdate = true;
|
|
1872
|
+
b.im.instanceColor.needsUpdate = true;
|
|
1873
|
+
for (const o of b.objs) {
|
|
1874
|
+
if (o.isInstancedMesh)
|
|
1875
|
+
o.count = w;
|
|
1876
|
+
else
|
|
1877
|
+
o.geometry.instanceCount = w;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return st;
|
|
1881
|
+
};
|
|
1316
1882
|
const setCull = (studs, under) => {
|
|
1883
|
+
cullS = studs;
|
|
1884
|
+
cullU = under;
|
|
1885
|
+
if (steps) {
|
|
1886
|
+
applySteps();
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1317
1889
|
for (const t of toggles)
|
|
1318
1890
|
t.mesh.count = (t.flag === "studs" ? studs : under) ? t.visible : t.all;
|
|
1319
1891
|
};
|
|
1892
|
+
const setStep = (s) => {
|
|
1893
|
+
if (!steps)
|
|
1894
|
+
throw new Error("buildLdrScene: setStep needs P.steps");
|
|
1895
|
+
stepS = s == null ? STEP_NEVER - 1 : s;
|
|
1896
|
+
return applySteps();
|
|
1897
|
+
};
|
|
1320
1898
|
const box = new THREE.Box3;
|
|
1321
1899
|
for (const it of insts) {
|
|
1322
|
-
|
|
1323
|
-
if (!p)
|
|
1900
|
+
if (!H.parts[it.part])
|
|
1324
1901
|
continue;
|
|
1325
|
-
|
|
1902
|
+
const m = it.m;
|
|
1903
|
+
if (m[0] < box.min.x)
|
|
1904
|
+
box.min.x = m[0];
|
|
1905
|
+
if (m[1] < box.min.y)
|
|
1906
|
+
box.min.y = m[1];
|
|
1907
|
+
if (m[2] < box.min.z)
|
|
1908
|
+
box.min.z = m[2];
|
|
1909
|
+
if (m[0] > box.max.x)
|
|
1910
|
+
box.max.x = m[0];
|
|
1911
|
+
if (m[1] > box.max.y)
|
|
1912
|
+
box.max.y = m[1];
|
|
1913
|
+
if (m[2] > box.max.z)
|
|
1914
|
+
box.max.z = m[2];
|
|
1326
1915
|
}
|
|
1327
1916
|
const setSide = (front) => {
|
|
1328
1917
|
matF.side = front ? THREE.FrontSide : THREE.DoubleSide;
|
|
@@ -1339,13 +1928,26 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1339
1928
|
for (const s of studMeshes) {
|
|
1340
1929
|
const k2 = alt.header.studKinds[s.kind] ? s.kind : Object.keys(alt.header.studKinds).find((k) => k.replace("p/8/", "p/") === s.kind.replace("p/8/", "p/"));
|
|
1341
1930
|
if (k2)
|
|
1342
|
-
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr);
|
|
1931
|
+
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
|
|
1343
1932
|
}
|
|
1344
1933
|
return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
|
|
1345
1934
|
};
|
|
1346
|
-
|
|
1935
|
+
const setLod = (on) => {
|
|
1936
|
+
root.enabled = on && LOD;
|
|
1937
|
+
if (!root.enabled) {
|
|
1938
|
+
for (const c of root.clusters) {
|
|
1939
|
+
c.cur = 0;
|
|
1940
|
+
c.edgeOk = true;
|
|
1941
|
+
}
|
|
1942
|
+
refresh();
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
insts = null;
|
|
1946
|
+
cull = null;
|
|
1947
|
+
byPart.clear();
|
|
1948
|
+
return { root, stats, setCull, setSide, setEdges, setCond, swapStuds, setLod, setStep, box, texturesReady };
|
|
1347
1949
|
}
|
|
1348
|
-
// src/scene.ts
|
|
1950
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/scene.ts
|
|
1349
1951
|
import * as THREE2 from "three";
|
|
1350
1952
|
function colorFn(src, pack, fallback) {
|
|
1351
1953
|
const table = new Map;
|
|
@@ -1430,11 +2032,11 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1430
2032
|
}
|
|
1431
2033
|
cur = null;
|
|
1432
2034
|
};
|
|
1433
|
-
const
|
|
2035
|
+
const multiStep = uniq.length > 1;
|
|
2036
|
+
const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
|
|
2037
|
+
const build = () => {
|
|
1434
2038
|
const t0 = performance.now();
|
|
1435
|
-
|
|
1436
|
-
const insts = step == null ? all : all.filter((_, k) => stepOf[k] <= step);
|
|
1437
|
-
cur = buildLdrScene(insts, pack, { pack: "", cullStuds: cs, cullUnder: cu, edges: edges ? "idx" : false, side, cond, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false }, color, () => {});
|
|
2039
|
+
cur = buildLdrScene(all, pack, { pack: "", cullStuds: cs, cullUnder: cu, edges: edges ? "idx" : false, side, cond, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false, lod: o.lod !== false, lodPx: o.lodPx, lodEdgePx: o.lodEdgePx, steps: multiStep ? stepOf : undefined }, color, () => {});
|
|
1438
2040
|
pairs.clear();
|
|
1439
2041
|
if (o.material === "plastic")
|
|
1440
2042
|
cur.root.traverse((x) => {
|
|
@@ -1449,17 +2051,25 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1449
2051
|
if (!cond)
|
|
1450
2052
|
cur.setCond(false);
|
|
1451
2053
|
object.add(cur.root);
|
|
1452
|
-
Object.assign(stats, { drawn:
|
|
2054
|
+
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, clusters: cur.stats.clusters ?? 0, buildMs: performance.now() - t0 });
|
|
1453
2055
|
api.texturesReady = cur.texturesReady;
|
|
1454
2056
|
};
|
|
2057
|
+
const setStep = (step) => {
|
|
2058
|
+
if (!multiStep)
|
|
2059
|
+
return;
|
|
2060
|
+
const t0 = performance.now();
|
|
2061
|
+
Object.assign(stats, cur.setStep(step), { drawn: drawnAt(step), buildMs: performance.now() - t0 });
|
|
2062
|
+
};
|
|
1455
2063
|
const api = { texturesReady: Promise.resolve() };
|
|
1456
|
-
build(
|
|
2064
|
+
build();
|
|
2065
|
+
if (o.step != null)
|
|
2066
|
+
setStep(o.step);
|
|
1457
2067
|
return Object.assign(api, {
|
|
1458
2068
|
object,
|
|
1459
2069
|
stats,
|
|
1460
2070
|
stepCount: uniq.length,
|
|
1461
2071
|
stepViews,
|
|
1462
|
-
setStep
|
|
2072
|
+
setStep,
|
|
1463
2073
|
setEdges: (v) => {
|
|
1464
2074
|
edges = v;
|
|
1465
2075
|
cur.setEdges(v);
|
|
@@ -1473,6 +2083,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1473
2083
|
cu = b;
|
|
1474
2084
|
cur.setCull(a, b);
|
|
1475
2085
|
},
|
|
2086
|
+
setLod: (v) => cur.setLod(v),
|
|
1476
2087
|
setSide: (s) => {
|
|
1477
2088
|
side = s;
|
|
1478
2089
|
cur.setSide(s === "front");
|
|
@@ -1485,7 +2096,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1485
2096
|
object.updateMatrixWorld(true);
|
|
1486
2097
|
target.makeEmpty();
|
|
1487
2098
|
object.traverse((x) => {
|
|
1488
|
-
if (x.isInstancedMesh && x.count) {
|
|
2099
|
+
if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
|
|
1489
2100
|
x.computeBoundingBox();
|
|
1490
2101
|
const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
|
|
1491
2102
|
target.union(b);
|
|
@@ -1496,7 +2107,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1496
2107
|
dispose: disposeCur
|
|
1497
2108
|
});
|
|
1498
2109
|
}
|
|
1499
|
-
// src/pack-io.ts
|
|
2110
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/pack-io.ts
|
|
1500
2111
|
import { decompress } from "fzstd";
|
|
1501
2112
|
async function decompressPack(data) {
|
|
1502
2113
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1507,7 +2118,148 @@ async function decompressPack(data) {
|
|
|
1507
2118
|
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
1508
2119
|
return own(u);
|
|
1509
2120
|
}
|
|
2121
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/cdn.ts
|
|
2122
|
+
import { decompress as decompress2 } from "fzstd";
|
|
2123
|
+
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
2124
|
+
var indexCache = new Map;
|
|
2125
|
+
var shardCache = new Map;
|
|
2126
|
+
function loadPartsIndex(cdn = DEFAULT_PARTS_CDN, f = fetch) {
|
|
2127
|
+
let p = indexCache.get(cdn);
|
|
2128
|
+
if (!p) {
|
|
2129
|
+
p = f(cdn + "parts.json").then((r) => {
|
|
2130
|
+
if (!r.ok)
|
|
2131
|
+
throw new Error(`ldr: parts CDN index ${r.status} (${cdn}parts.json)`);
|
|
2132
|
+
return r.json();
|
|
2133
|
+
});
|
|
2134
|
+
p.catch(() => indexCache.delete(cdn));
|
|
2135
|
+
indexCache.set(cdn, p);
|
|
2136
|
+
}
|
|
2137
|
+
return p;
|
|
2138
|
+
}
|
|
2139
|
+
var isRange = (v) => Array.isArray(v) && v.length === 3 && typeof v[0] === "number" && typeof v[1] === "number" && (v[2] === "f32" || v[2] === "u16" || v[2] === "u8" || v[2] === "u32");
|
|
2140
|
+
var rebase = (v, d) => isRange(v) ? [v[0] + d, v[1], v[2]] : Array.isArray(v) ? v.map((x) => rebase(x, d)) : v && typeof v === "object" ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, rebase(x, d)])) : v;
|
|
2141
|
+
function mergePacks(packs, extra = {}) {
|
|
2142
|
+
const payloads = [];
|
|
2143
|
+
let off = 0;
|
|
2144
|
+
const parts = {}, studKinds = {};
|
|
2145
|
+
for (const p of packs) {
|
|
2146
|
+
const buf = p.buffer;
|
|
2147
|
+
if (!buf)
|
|
2148
|
+
throw new Error("ldr: mergePacks needs packs from decodePack/loadPack");
|
|
2149
|
+
const hl = new DataView(buf).getUint32(0, true);
|
|
2150
|
+
const pay = new Uint8Array(buf, 4 + hl);
|
|
2151
|
+
const d = off;
|
|
2152
|
+
payloads.push(pay);
|
|
2153
|
+
off += pay.byteLength;
|
|
2154
|
+
const pad = (4 - off % 4) % 4;
|
|
2155
|
+
if (pad) {
|
|
2156
|
+
payloads.push(new Uint8Array(pad));
|
|
2157
|
+
off += pad;
|
|
2158
|
+
}
|
|
2159
|
+
for (const [k, v] of Object.entries(p.header.parts ?? {}))
|
|
2160
|
+
if (!(k in parts))
|
|
2161
|
+
parts[k] = rebase(v, d);
|
|
2162
|
+
for (const [k, v] of Object.entries(p.header.studKinds ?? {}))
|
|
2163
|
+
if (!(k in studKinds))
|
|
2164
|
+
studKinds[k] = rebase(v, d);
|
|
2165
|
+
}
|
|
2166
|
+
const h0 = packs[0]?.header ?? { version: 1, weld: true };
|
|
2167
|
+
const header = new TextEncoder().encode(JSON.stringify({ ...h0, parts, studKinds, ...extra }));
|
|
2168
|
+
const hpad = (4 - (4 + header.length) % 4) % 4;
|
|
2169
|
+
const base = 4 + header.length + hpad;
|
|
2170
|
+
const out = new Uint8Array(base + off);
|
|
2171
|
+
new DataView(out.buffer).setUint32(0, header.length + hpad, true);
|
|
2172
|
+
out.set(header, 4);
|
|
2173
|
+
out.fill(32, 4 + header.length, base);
|
|
2174
|
+
let o = base;
|
|
2175
|
+
for (const p of payloads) {
|
|
2176
|
+
out.set(p, o);
|
|
2177
|
+
o += p.byteLength;
|
|
2178
|
+
}
|
|
2179
|
+
return decodePack(out.buffer);
|
|
2180
|
+
}
|
|
2181
|
+
async function loadParts(names, o = {}) {
|
|
2182
|
+
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 65536;
|
|
2183
|
+
const idx = await loadPartsIndex(cdn, f);
|
|
2184
|
+
const want = [...new Set([...names].map(norm))];
|
|
2185
|
+
const missing = [];
|
|
2186
|
+
const todo = [];
|
|
2187
|
+
for (const n of want) {
|
|
2188
|
+
if (shardCache.has(cdn + n))
|
|
2189
|
+
continue;
|
|
2190
|
+
const e = idx.parts[n];
|
|
2191
|
+
if (e)
|
|
2192
|
+
todo.push({ name: n, off: e[0], len: e[1], file: e[2] ?? 0 });
|
|
2193
|
+
else
|
|
2194
|
+
missing.push(n);
|
|
2195
|
+
}
|
|
2196
|
+
todo.sort((a, b) => a.file - b.file || a.off - b.off);
|
|
2197
|
+
const groups = [];
|
|
2198
|
+
for (const t of todo) {
|
|
2199
|
+
const g = groups[groups.length - 1];
|
|
2200
|
+
if (g && g.file === t.file && t.off - g.end <= gap) {
|
|
2201
|
+
g.end = Math.max(g.end, t.off + t.len);
|
|
2202
|
+
g.items.push(t);
|
|
2203
|
+
} else
|
|
2204
|
+
groups.push({ file: t.file, start: t.off, end: t.off + t.len, items: [t] });
|
|
2205
|
+
}
|
|
2206
|
+
let bytes = 0;
|
|
2207
|
+
let next = 0;
|
|
2208
|
+
const worker = async () => {
|
|
2209
|
+
while (next < groups.length) {
|
|
2210
|
+
const g = groups[next++];
|
|
2211
|
+
const r = await f(new URL(idx.archives[g.file], cdn).href, { headers: { Range: `bytes=${g.start}-${g.end - 1}` } });
|
|
2212
|
+
if (!r.ok)
|
|
2213
|
+
throw new Error(`ldr: parts CDN ${r.status}`);
|
|
2214
|
+
let buf = new Uint8Array(await r.arrayBuffer());
|
|
2215
|
+
if (r.status === 200)
|
|
2216
|
+
buf = buf.subarray(g.start, g.end);
|
|
2217
|
+
bytes += buf.byteLength;
|
|
2218
|
+
for (const t of g.items) {
|
|
2219
|
+
const raw = decompress2(buf.subarray(t.off - g.start, t.off - g.start + t.len));
|
|
2220
|
+
const ab = raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength);
|
|
2221
|
+
shardCache.set(cdn + t.name, decodePack(ab));
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 6, groups.length) }, worker));
|
|
2226
|
+
const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
|
|
2227
|
+
const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
|
|
2228
|
+
return { pack, missing, requests: groups.length, bytes };
|
|
2229
|
+
}
|
|
2230
|
+
function emptyPack(colors) {
|
|
2231
|
+
const h = new TextEncoder().encode(JSON.stringify({ version: 1, weld: true, parts: {}, studKinds: {}, colors }));
|
|
2232
|
+
const pad = (4 - (4 + h.length) % 4) % 4;
|
|
2233
|
+
const b = new Uint8Array(4 + h.length + pad).fill(32);
|
|
2234
|
+
new DataView(b.buffer).setUint32(0, h.length + pad, true);
|
|
2235
|
+
b.set(h, 4);
|
|
2236
|
+
return b.buffer;
|
|
2237
|
+
}
|
|
2238
|
+
async function loadModel(source, o = {}) {
|
|
2239
|
+
const t0 = performance.now();
|
|
2240
|
+
const f = o.fetch ?? fetch;
|
|
2241
|
+
const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
|
|
2242
|
+
const text = o.text ? source : await f(source).then((r) => {
|
|
2243
|
+
if (!r.ok)
|
|
2244
|
+
throw new Error(`ldr: ${r.status} fetching ${source}`);
|
|
2245
|
+
return r.text();
|
|
2246
|
+
});
|
|
2247
|
+
const t1 = performance.now();
|
|
2248
|
+
const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2249
|
+
const insts = parseModel(text, name, { looseGeometry: false });
|
|
2250
|
+
const t2 = performance.now();
|
|
2251
|
+
await idxP;
|
|
2252
|
+
const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
|
|
2253
|
+
const t3 = performance.now();
|
|
2254
|
+
const obj = createLdrObject(insts, pack, o);
|
|
2255
|
+
for (const m of missing)
|
|
2256
|
+
if (!obj.stats.missing.includes(m))
|
|
2257
|
+
obj.stats.missing.push(m);
|
|
2258
|
+
const t4 = performance.now();
|
|
2259
|
+
return Object.assign(obj, { pack, instances: insts, requests, bytes, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, build: t4 - t3, total: t4 - t0 } });
|
|
2260
|
+
}
|
|
1510
2261
|
export {
|
|
2262
|
+
DEFAULT_PARTS_CDN,
|
|
1511
2263
|
I as IDENTITY,
|
|
1512
2264
|
buildLdrScene,
|
|
1513
2265
|
colorToken,
|
|
@@ -1517,20 +2269,26 @@ export {
|
|
|
1517
2269
|
createInstancedConditionalEdges,
|
|
1518
2270
|
createInstancedEdges,
|
|
1519
2271
|
createLdrObject,
|
|
2272
|
+
cullCore,
|
|
1520
2273
|
decodePack,
|
|
1521
2274
|
decompressPack,
|
|
1522
2275
|
fileKind,
|
|
1523
2276
|
fileStepViews,
|
|
1524
2277
|
flatten,
|
|
2278
|
+
forEachStud,
|
|
1525
2279
|
hash32,
|
|
1526
2280
|
invert,
|
|
1527
2281
|
isDirectColor,
|
|
2282
|
+
loadModel,
|
|
1528
2283
|
loadPack,
|
|
2284
|
+
loadParts,
|
|
2285
|
+
loadPartsIndex,
|
|
1529
2286
|
looseFile,
|
|
1530
2287
|
loosePartName,
|
|
1531
2288
|
looseSource,
|
|
1532
2289
|
looseSteps,
|
|
1533
2290
|
makeMaterial,
|
|
2291
|
+
mergePacks,
|
|
1534
2292
|
mul,
|
|
1535
2293
|
norm,
|
|
1536
2294
|
parse,
|