ldr 0.4.1 → 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 +23 -17
- 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/node/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
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
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;
|
|
1043
1246
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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));
|
|
1265
|
+
}
|
|
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))
|
|
1313
|
+
return;
|
|
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;
|
|
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);
|
|
1077
1327
|
return;
|
|
1078
|
-
for (const s of p.studs) {
|
|
1079
|
-
const w = mul12(it.m, s.slice(2));
|
|
1080
|
-
const color = s[1] === "16" ? it.color : s[1];
|
|
1081
|
-
const up = upright(w);
|
|
1082
|
-
studs.push({ kind: s[0], color, w, hidden: up && covered(w[0], w[1], w[2], idx) });
|
|
1083
|
-
if (up)
|
|
1084
|
-
studTops.add(key3(w[0], w[1], w[2]));
|
|
1085
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);
|
|
1611
|
+
root.add(l);
|
|
1612
|
+
return l;
|
|
1613
|
+
};
|
|
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);
|
|
1145
1630
|
root.add(l);
|
|
1146
1631
|
return l;
|
|
1147
1632
|
};
|
|
1148
|
-
const stats = { studsTotal: cull.
|
|
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,147 @@ 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
|
}
|
|
1510
|
-
// src/
|
|
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
|
+
}
|
|
2261
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/library.ts
|
|
1511
2262
|
import { existsSync, readFileSync } from "fs";
|
|
1512
2263
|
import { join } from "path";
|
|
1513
2264
|
var xf = (m, x, y, z) => [m[3] * x + m[4] * y + m[5] * z + m[0], m[6] * x + m[7] * y + m[8] * z + m[1], m[9] * x + m[10] * y + m[11] * z + m[2]];
|
|
@@ -1759,11 +2510,11 @@ class Library {
|
|
|
1759
2510
|
return insts;
|
|
1760
2511
|
}
|
|
1761
2512
|
}
|
|
1762
|
-
// src/node/build-pack.ts
|
|
2513
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/build-pack.ts
|
|
1763
2514
|
import fs3 from "node:fs";
|
|
1764
2515
|
import path3 from "node:path";
|
|
1765
2516
|
|
|
1766
|
-
// src/node/resolver.ts
|
|
2517
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/resolver.ts
|
|
1767
2518
|
import fs from "node:fs";
|
|
1768
2519
|
import path from "node:path";
|
|
1769
2520
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -2035,9 +2786,118 @@ function collectDeps(lib, refs) {
|
|
|
2035
2786
|
return out;
|
|
2036
2787
|
}
|
|
2037
2788
|
|
|
2038
|
-
// src/node/compile.ts
|
|
2789
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/compile.ts
|
|
2039
2790
|
import fs2 from "node:fs";
|
|
2040
2791
|
import path2 from "node:path";
|
|
2792
|
+
|
|
2793
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/lod.ts
|
|
2794
|
+
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
2795
|
+
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
2796
|
+
function reorderMesh(P, N, C, I) {
|
|
2797
|
+
const idx = Uint32Array.from(I);
|
|
2798
|
+
const n = P.length / 3;
|
|
2799
|
+
const [remap] = MeshoptEncoder.reorderMesh(idx, true, false);
|
|
2800
|
+
const P2 = new Float32Array(P.length), N2 = new Float32Array(N.length), C2 = new Float32Array(C.length);
|
|
2801
|
+
for (let v = 0;v < n; v++) {
|
|
2802
|
+
const r = remap[v];
|
|
2803
|
+
if (r === 4294967295)
|
|
2804
|
+
continue;
|
|
2805
|
+
P2[r * 3] = P[v * 3];
|
|
2806
|
+
P2[r * 3 + 1] = P[v * 3 + 1];
|
|
2807
|
+
P2[r * 3 + 2] = P[v * 3 + 2];
|
|
2808
|
+
N2[r * 3] = N[v * 3];
|
|
2809
|
+
N2[r * 3 + 1] = N[v * 3 + 1];
|
|
2810
|
+
N2[r * 3 + 2] = N[v * 3 + 2];
|
|
2811
|
+
for (let k = 0;k < 4; k++)
|
|
2812
|
+
C2[r * 4 + k] = C[v * 4 + k];
|
|
2813
|
+
}
|
|
2814
|
+
return { P: P2, N: N2, C: C2, I: idx };
|
|
2815
|
+
}
|
|
2816
|
+
var TARGETS = [0.25, 0.08];
|
|
2817
|
+
var MIN_TRIS = 64;
|
|
2818
|
+
function flatMesh(tris) {
|
|
2819
|
+
const map = new Map;
|
|
2820
|
+
const P = [], N = [], C = [], I = [];
|
|
2821
|
+
for (const { p, i: idx, col } of tris)
|
|
2822
|
+
for (let t = 0;t < idx.length; t += 3) {
|
|
2823
|
+
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
2824
|
+
const ux = p[b] - p[a], uy = p[b + 1] - p[a + 1], uz = p[b + 2] - p[a + 2], vx = p[c] - p[a], vy = p[c + 1] - p[a + 1], vz = p[c + 2] - p[a + 2];
|
|
2825
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
2826
|
+
const l = Math.hypot(nx, ny, nz);
|
|
2827
|
+
if (!(l > 0.000000001))
|
|
2828
|
+
continue;
|
|
2829
|
+
nx /= l;
|
|
2830
|
+
ny /= l;
|
|
2831
|
+
nz /= l;
|
|
2832
|
+
for (const o of [a, b, c]) {
|
|
2833
|
+
const k = `${p[o].toFixed(3)},${p[o + 1].toFixed(3)},${p[o + 2].toFixed(3)},${nx.toFixed(3)},${ny.toFixed(3)},${nz.toFixed(3)},${col.join()}`;
|
|
2834
|
+
let j = map.get(k);
|
|
2835
|
+
if (j === undefined) {
|
|
2836
|
+
j = P.length / 3;
|
|
2837
|
+
map.set(k, j);
|
|
2838
|
+
P.push(p[o], p[o + 1], p[o + 2]);
|
|
2839
|
+
N.push(nx, ny, nz);
|
|
2840
|
+
C.push(...col);
|
|
2841
|
+
}
|
|
2842
|
+
I.push(j);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
return { P: new Float32Array(P), N: new Float32Array(N), C: new Float32Array(C), I: new Uint32Array(I) };
|
|
2846
|
+
}
|
|
2847
|
+
function lodChain(P, C, I) {
|
|
2848
|
+
const nTris = I.length / 3;
|
|
2849
|
+
if (nTris < MIN_TRIS)
|
|
2850
|
+
return [];
|
|
2851
|
+
const groups = new Map;
|
|
2852
|
+
for (let t = 0;t < I.length; t += 3) {
|
|
2853
|
+
const v = I[t] * 4;
|
|
2854
|
+
const col = [C[v], C[v + 1], C[v + 2], C[v + 3]];
|
|
2855
|
+
const k = col.join();
|
|
2856
|
+
let g = groups.get(k);
|
|
2857
|
+
if (!g)
|
|
2858
|
+
groups.set(k, g = { col, tri: [] });
|
|
2859
|
+
g.tri.push(I[t], I[t + 1], I[t + 2]);
|
|
2860
|
+
}
|
|
2861
|
+
const welded = [...groups.values()].map(({ col, tri }) => {
|
|
2862
|
+
const map = new Map;
|
|
2863
|
+
const pos = [];
|
|
2864
|
+
const idx = new Uint32Array(tri.length);
|
|
2865
|
+
for (let i = 0;i < tri.length; i++) {
|
|
2866
|
+
const o = tri[i] * 3;
|
|
2867
|
+
const k = `${P[o].toFixed(3)},${P[o + 1].toFixed(3)},${P[o + 2].toFixed(3)}`;
|
|
2868
|
+
let j = map.get(k);
|
|
2869
|
+
if (j === undefined) {
|
|
2870
|
+
j = pos.length / 3;
|
|
2871
|
+
map.set(k, j);
|
|
2872
|
+
pos.push(P[o], P[o + 1], P[o + 2]);
|
|
2873
|
+
}
|
|
2874
|
+
idx[i] = j;
|
|
2875
|
+
}
|
|
2876
|
+
return { col, p: new Float32Array(pos), i: idx };
|
|
2877
|
+
});
|
|
2878
|
+
const out = [];
|
|
2879
|
+
let prevTris = nTris;
|
|
2880
|
+
for (let li = 0;li < TARGETS.length; li++) {
|
|
2881
|
+
let err = 0;
|
|
2882
|
+
const parts = [];
|
|
2883
|
+
for (const g of welded) {
|
|
2884
|
+
const target = Math.max(3, Math.floor(g.i.length * TARGETS[li] / 3) * 3);
|
|
2885
|
+
const [idx, e] = MeshoptSimplifier.simplify(g.i, g.p, 3, target, 1e9, li ? ["ErrorAbsolute", "Prune"] : ["ErrorAbsolute"]);
|
|
2886
|
+
err = Math.max(err, e);
|
|
2887
|
+
if (idx.length)
|
|
2888
|
+
parts.push({ p: g.p, i: idx, col: g.col });
|
|
2889
|
+
}
|
|
2890
|
+
const m = flatMesh(parts);
|
|
2891
|
+
const t = m.I.length / 3;
|
|
2892
|
+
if (t > prevTris * 0.7 || !t)
|
|
2893
|
+
continue;
|
|
2894
|
+
out.push({ ...m, err: +Math.max(err, 0.001).toFixed(3) });
|
|
2895
|
+
prevTris = t;
|
|
2896
|
+
}
|
|
2897
|
+
return out;
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/compile.ts
|
|
2041
2901
|
function loadColors(root) {
|
|
2042
2902
|
const map = new Map;
|
|
2043
2903
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -2454,7 +3314,8 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2454
3314
|
return r;
|
|
2455
3315
|
};
|
|
2456
3316
|
let lastPos = [];
|
|
2457
|
-
|
|
3317
|
+
let anyLod = false;
|
|
3318
|
+
const bucket = (b, lod = false) => {
|
|
2458
3319
|
const n = b.pos.length / 3;
|
|
2459
3320
|
lastPos = [];
|
|
2460
3321
|
if (!n)
|
|
@@ -2493,9 +3354,20 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2493
3354
|
}
|
|
2494
3355
|
I.push(j);
|
|
2495
3356
|
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
3357
|
+
let m = { P, N, C, I };
|
|
3358
|
+
if (options.reorder && I.length >= 3)
|
|
3359
|
+
m = reorderMesh(P, N, C, I);
|
|
3360
|
+
const vcount = m.P.length / 3;
|
|
3361
|
+
lastPos = m.P;
|
|
3362
|
+
const out = { pos: put(Float32Array.from(m.P)), nrm: put(Float32Array.from(m.N)), col: put(Float32Array.from(m.C)), idx: put(vcount < 65536 ? Uint16Array.from(m.I) : Uint32Array.from(m.I)), tris: n / 3 };
|
|
3363
|
+
if (lod && options.lod) {
|
|
3364
|
+
const chain = lodChain(P, C, I).map((l) => options.reorder ? { ...l, ...reorderMesh(l.P, l.N, l.C, l.I) } : l);
|
|
3365
|
+
if (chain.length) {
|
|
3366
|
+
anyLod = true;
|
|
3367
|
+
out.lod = chain.map((l) => ({ pos: put(l.P), col: put(Uint8Array.from(l.C, (x) => Math.round(x * 255))), idx: put(l.P.length / 3 < 65536 ? new Uint16Array(l.I) : l.I), tris: l.I.length / 3, err: l.err }));
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
return out;
|
|
2499
3371
|
};
|
|
2500
3372
|
let anyCond = false;
|
|
2501
3373
|
const condl = (a, pools) => {
|
|
@@ -2586,18 +3458,18 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2586
3458
|
});
|
|
2587
3459
|
return { tbody: bucket(c.tbody), tex };
|
|
2588
3460
|
};
|
|
2589
|
-
const enc = (c) => {
|
|
2590
|
-
const body = bucket(c.body), bodyP = lastPos, under = bucket(c.under), underP = lastPos;
|
|
3461
|
+
const enc = (c, lod = false) => {
|
|
3462
|
+
const body = bucket(c.body, lod), bodyP = lastPos, under = bucket(c.under, lod), underP = lastPos;
|
|
2591
3463
|
const edges = c.edges.length ? put(new Float32Array(c.edges)) : null;
|
|
2592
3464
|
const condlB = condl(c.cond, [bodyP, underP, c.edges]), condlU = condl(c.condUnder, [bodyP, underP, c.edges]);
|
|
2593
3465
|
return { body, under, edges, cond: c.condLines, condl: condlB, condlu: condlU, studs: c.studs.map((s) => [s.kind, s.color, ...s.m.map((x) => +x.toFixed(4))]), bbox: c.bbox, fullBottom: c.fullBottom, uncert: !!c.uncertified, mask: c.bottomMask ? [c.bottomMask.nx, c.bottomMask.nz, c.bottomMask.bits.join("")] : null, ...encTex(c) };
|
|
2594
3466
|
};
|
|
2595
|
-
const encParts = Object.fromEntries([...parts].map(([k, c]) => [k, enc(c)])), encKinds = Object.fromEntries([...studKinds].map(([k, c]) => [k, enc(c)]));
|
|
3467
|
+
const encParts = Object.fromEntries([...parts].map(([k, c]) => [k, enc(c, true)])), encKinds = Object.fromEntries([...studKinds].map(([k, c]) => [k, enc(c)]));
|
|
2596
3468
|
const textures = texNames.map((name) => {
|
|
2597
3469
|
const b = options.texture?.(name);
|
|
2598
3470
|
return b ? { name, mime: "image/png", data: put(b) } : { name, missing: true };
|
|
2599
3471
|
});
|
|
2600
|
-
const features = [...anyCond ? ["cond"] : [], ...texNames.length ? ["tex"] : []];
|
|
3472
|
+
const features = [...anyCond ? ["cond"] : [], ...texNames.length ? ["tex"] : [], ...anyLod ? ["lod"] : []];
|
|
2601
3473
|
const header = { version: features.length ? 2 : 1, ...features.length ? { features } : {}, weld, parts: encParts, studKinds: encKinds, ...texNames.length ? { textures } : {}, ...extra };
|
|
2602
3474
|
const hj = new TextEncoder().encode(JSON.stringify(header));
|
|
2603
3475
|
const hpad = (4 - (4 + hj.length) % 4) % 4;
|
|
@@ -2608,7 +3480,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2608
3480
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
2609
3481
|
}
|
|
2610
3482
|
|
|
2611
|
-
// src/node/build-pack.ts
|
|
3483
|
+
// ../../../../../../../tmp/ldr-build-qIdKSv/src/node/build-pack.ts
|
|
2612
3484
|
function buildPack(o) {
|
|
2613
3485
|
const lib = new Library2(o.ldrawRoot);
|
|
2614
3486
|
const refs = new Map;
|
|
@@ -2668,10 +3540,11 @@ function buildPack(o) {
|
|
|
2668
3540
|
return b ? new Uint8Array(Buffer.from(b, "base64")) : comp.texture(n);
|
|
2669
3541
|
};
|
|
2670
3542
|
const warnings = [...lib.conflicts].map((n) => `${n}: defined differently by two models; the first definition is used`);
|
|
2671
|
-
return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
|
|
3543
|
+
return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
|
|
2672
3544
|
}
|
|
2673
3545
|
export {
|
|
2674
3546
|
Compiler,
|
|
3547
|
+
DEFAULT_PARTS_CDN,
|
|
2675
3548
|
I as IDENTITY,
|
|
2676
3549
|
Library,
|
|
2677
3550
|
Library2 as ResolverLibrary,
|
|
@@ -2685,6 +3558,7 @@ export {
|
|
|
2685
3558
|
createInstancedConditionalEdges,
|
|
2686
3559
|
createInstancedEdges,
|
|
2687
3560
|
createLdrObject,
|
|
3561
|
+
cullCore,
|
|
2688
3562
|
decodePack,
|
|
2689
3563
|
decompressPack,
|
|
2690
3564
|
encodePack,
|
|
@@ -2692,16 +3566,21 @@ export {
|
|
|
2692
3566
|
fileStepViews,
|
|
2693
3567
|
flatten,
|
|
2694
3568
|
flatten2 as flattenWithLibrary,
|
|
3569
|
+
forEachStud,
|
|
2695
3570
|
hash32,
|
|
2696
3571
|
invert,
|
|
2697
3572
|
isDirectColor,
|
|
2698
3573
|
loadColors,
|
|
3574
|
+
loadModel,
|
|
2699
3575
|
loadPack,
|
|
3576
|
+
loadParts,
|
|
3577
|
+
loadPartsIndex,
|
|
2700
3578
|
looseFile,
|
|
2701
3579
|
loosePartName,
|
|
2702
3580
|
looseSource,
|
|
2703
3581
|
looseSteps,
|
|
2704
3582
|
makeMaterial,
|
|
3583
|
+
mergePacks,
|
|
2705
3584
|
mul,
|
|
2706
3585
|
norm,
|
|
2707
3586
|
parse,
|