ldr 0.4.1 → 0.5.1
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 +966 -207
- package/dist/node/build-pack.d.ts +6 -0
- package/dist/node/compile.d.ts +4 -0
- package/dist/node/index.js +1102 -222
- 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 +6 -5
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/spec.ts
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/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-pIke9r/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-pIke9r/src/render.ts
|
|
772
772
|
import * as THREE from "three";
|
|
773
773
|
async function loadPack(url) {
|
|
774
774
|
const res = await fetch(url);
|
|
@@ -796,29 +796,71 @@ 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) {
|
|
815
856
|
const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
|
|
816
857
|
m.onBeforeCompile = (s) => {
|
|
817
858
|
s.vertexShader = `attribute vec4 ldrColor;
|
|
818
|
-
` + s.vertexShader.replace("#include <color_vertex>", `#
|
|
819
|
-
|
|
859
|
+
` + s.vertexShader.replace("#include <color_vertex>", `#include <color_vertex>
|
|
860
|
+
#ifdef USE_INSTANCING_COLOR
|
|
861
|
+
vColor.rgb = ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb; // baked LDConfig colours are sRGB
|
|
820
862
|
#else
|
|
821
|
-
vColor =
|
|
863
|
+
vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
|
|
822
864
|
#endif`);
|
|
823
865
|
};
|
|
824
866
|
m.customProgramCacheKey = () => "ldrColor";
|
|
@@ -1012,120 +1054,544 @@ function instancedLines(pos, mats, count) {
|
|
|
1012
1054
|
l.frustumCulled = false;
|
|
1013
1055
|
return l;
|
|
1014
1056
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1057
|
+
function writeM4(t, o, m, mo = 0) {
|
|
1058
|
+
t[o] = m[mo + 3];
|
|
1059
|
+
t[o + 1] = m[mo + 6];
|
|
1060
|
+
t[o + 2] = m[mo + 9];
|
|
1061
|
+
t[o + 3] = 0;
|
|
1062
|
+
t[o + 4] = m[mo + 4];
|
|
1063
|
+
t[o + 5] = m[mo + 7];
|
|
1064
|
+
t[o + 6] = m[mo + 10];
|
|
1065
|
+
t[o + 7] = 0;
|
|
1066
|
+
t[o + 8] = m[mo + 5];
|
|
1067
|
+
t[o + 9] = m[mo + 8];
|
|
1068
|
+
t[o + 10] = m[mo + 11];
|
|
1069
|
+
t[o + 11] = 0;
|
|
1070
|
+
t[o + 12] = m[mo];
|
|
1071
|
+
t[o + 13] = m[mo + 1];
|
|
1072
|
+
t[o + 14] = m[mo + 2];
|
|
1073
|
+
t[o + 15] = 1;
|
|
1074
|
+
}
|
|
1075
|
+
function newIM(g, mat, n) {
|
|
1076
|
+
const im = new THREE.InstancedMesh(g, mat, 0);
|
|
1077
|
+
im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
|
|
1078
|
+
im.count = n;
|
|
1079
|
+
return im;
|
|
1080
|
+
}
|
|
1081
|
+
function fillInstances(im, ids, insts, color) {
|
|
1082
|
+
const M = im.instanceMatrix.array;
|
|
1083
|
+
const C = new Float32Array(ids.length * 3);
|
|
1084
|
+
for (let k = 0;k < ids.length; k++) {
|
|
1085
|
+
const it = insts[ids[k]];
|
|
1086
|
+
writeM4(M, k * 16, it.m);
|
|
1087
|
+
color(it.color).toArray(C, k * 3);
|
|
1088
|
+
}
|
|
1089
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1090
|
+
}
|
|
1091
|
+
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;
|
|
1092
|
+
var prepCache = new WeakMap;
|
|
1093
|
+
function prepPart(H, part) {
|
|
1094
|
+
let c = prepCache.get(H);
|
|
1095
|
+
if (!c)
|
|
1096
|
+
prepCache.set(H, c = new Map);
|
|
1097
|
+
let r = c.get(part);
|
|
1098
|
+
if (r !== undefined)
|
|
1099
|
+
return r;
|
|
1100
|
+
const p = H.parts[part];
|
|
1101
|
+
if (!p) {
|
|
1102
|
+
c.set(part, null);
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
const n = p.studs.length;
|
|
1106
|
+
const studM = new Float64Array(n * 12);
|
|
1107
|
+
const kind = [], color = [];
|
|
1108
|
+
p.studs.forEach((s, i) => {
|
|
1109
|
+
kind.push(s[0]);
|
|
1110
|
+
color.push(s[1]);
|
|
1111
|
+
for (let k = 0;k < 12; k++)
|
|
1112
|
+
studM[i * 12 + k] = s[2 + k];
|
|
1113
|
+
});
|
|
1114
|
+
let mask = null, nx = 0, nz = 0;
|
|
1115
|
+
if (p.mask) {
|
|
1116
|
+
nx = p.mask[0];
|
|
1117
|
+
nz = p.mask[1];
|
|
1118
|
+
const bits = p.mask[2];
|
|
1119
|
+
mask = new Uint8Array(bits.length);
|
|
1120
|
+
for (let i = 0;i < bits.length; i++)
|
|
1121
|
+
mask[i] = bits.charCodeAt(i) === 49 ? 1 : 0;
|
|
1122
|
+
}
|
|
1123
|
+
c.set(part, r = { nStuds: n, studM, kind, color, mask, nx, nz });
|
|
1124
|
+
return r;
|
|
1125
|
+
}
|
|
1126
|
+
function mul12To(a, b, bo, w, ao = 0) {
|
|
1127
|
+
const b0 = b[bo], b1 = b[bo + 1], b2 = b[bo + 2];
|
|
1128
|
+
w[0] = a[ao] + a[ao + 3] * b0 + a[ao + 4] * b1 + a[ao + 5] * b2;
|
|
1129
|
+
w[1] = a[ao + 1] + a[ao + 6] * b0 + a[ao + 7] * b1 + a[ao + 8] * b2;
|
|
1130
|
+
w[2] = a[ao + 2] + a[ao + 9] * b0 + a[ao + 10] * b1 + a[ao + 11] * b2;
|
|
1131
|
+
for (let i = 0;i < 3; i++)
|
|
1132
|
+
for (let j = 0;j < 3; j++)
|
|
1133
|
+
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];
|
|
1134
|
+
}
|
|
1135
|
+
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]);
|
|
1136
|
+
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);
|
|
1137
|
+
var topKey = (x, y, z) => {
|
|
1138
|
+
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1139
|
+
return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
|
|
1019
1140
|
};
|
|
1020
|
-
|
|
1021
|
-
|
|
1141
|
+
|
|
1142
|
+
class NumTable {
|
|
1143
|
+
keys;
|
|
1144
|
+
vals;
|
|
1145
|
+
mask;
|
|
1146
|
+
size = 0;
|
|
1147
|
+
constructor(cap = 1024) {
|
|
1148
|
+
let n = 1024;
|
|
1149
|
+
while (n < cap * 2)
|
|
1150
|
+
n *= 2;
|
|
1151
|
+
this.keys = new Float64Array(n).fill(-1);
|
|
1152
|
+
this.vals = new Int32Array(n);
|
|
1153
|
+
this.mask = n - 1;
|
|
1154
|
+
}
|
|
1155
|
+
slot(k) {
|
|
1156
|
+
const lo = k >>> 0, hi = k / 4294967296 >>> 0;
|
|
1157
|
+
let h = Math.imul(lo ^ Math.imul(hi, 2654435761), 2246822507);
|
|
1158
|
+
h ^= h >>> 15;
|
|
1159
|
+
return h & this.mask;
|
|
1160
|
+
}
|
|
1161
|
+
get(k) {
|
|
1162
|
+
const K = this.keys;
|
|
1163
|
+
let i = this.slot(k);
|
|
1164
|
+
for (;; ) {
|
|
1165
|
+
const x = K[i];
|
|
1166
|
+
if (x === k)
|
|
1167
|
+
return this.vals[i];
|
|
1168
|
+
if (x === -1)
|
|
1169
|
+
return -1;
|
|
1170
|
+
i = i + 1 & this.mask;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
put(k, v) {
|
|
1174
|
+
if ((this.size + 1) * 2 > this.keys.length)
|
|
1175
|
+
this.grow();
|
|
1176
|
+
const K = this.keys;
|
|
1177
|
+
let i = this.slot(k);
|
|
1178
|
+
for (;; ) {
|
|
1179
|
+
const x = K[i];
|
|
1180
|
+
if (x === k) {
|
|
1181
|
+
const o = this.vals[i];
|
|
1182
|
+
this.vals[i] = v;
|
|
1183
|
+
return o;
|
|
1184
|
+
}
|
|
1185
|
+
if (x === -1) {
|
|
1186
|
+
K[i] = k;
|
|
1187
|
+
this.vals[i] = v;
|
|
1188
|
+
this.size++;
|
|
1189
|
+
return -1;
|
|
1190
|
+
}
|
|
1191
|
+
i = i + 1 & this.mask;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
grow() {
|
|
1195
|
+
const ok = this.keys, ov = this.vals;
|
|
1196
|
+
const n = ok.length * 2;
|
|
1197
|
+
this.keys = new Float64Array(n).fill(-1);
|
|
1198
|
+
this.vals = new Int32Array(n);
|
|
1199
|
+
this.mask = n - 1;
|
|
1200
|
+
this.size = 0;
|
|
1201
|
+
for (let i = 0;i < ok.length; i++)
|
|
1202
|
+
if (ok[i] !== -1)
|
|
1203
|
+
this.put(ok[i], ov[i]);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
var STEP_NEVER = 2147483647;
|
|
1207
|
+
function forEachStud(insts, H, fn) {
|
|
1208
|
+
const w = new Float64Array(12);
|
|
1209
|
+
let j = 0;
|
|
1210
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1211
|
+
const it = insts[idx];
|
|
1212
|
+
const pp = prepPart(H, it.part);
|
|
1213
|
+
if (!pp)
|
|
1214
|
+
continue;
|
|
1215
|
+
for (let s = 0;s < pp.nStuds; s++) {
|
|
1216
|
+
mul12To(it.m, pp.studM, s * 12, w);
|
|
1217
|
+
const c = pp.color[s];
|
|
1218
|
+
fn(j++, idx, w, pp.kind[s], c === "16" ? it.color : c, s);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function cullCore(insts, H, steps) {
|
|
1022
1223
|
const CELL = 40;
|
|
1023
|
-
const
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1224
|
+
const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
|
|
1225
|
+
const cells = new NumTable(insts.length * 2);
|
|
1226
|
+
const nextE = [], rectE = [];
|
|
1227
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1228
|
+
const it = insts[idx];
|
|
1229
|
+
const m = it.m;
|
|
1026
1230
|
const p = H.parts[it.part];
|
|
1027
|
-
if (!p || !p.mask || !upright(
|
|
1028
|
-
|
|
1231
|
+
if (!p || !p.mask || !upright(m))
|
|
1232
|
+
continue;
|
|
1029
1233
|
const b = p.bbox;
|
|
1030
|
-
|
|
1031
|
-
for (
|
|
1032
|
-
for (
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1234
|
+
let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
|
|
1235
|
+
for (let cxi = 0;cxi < 2; cxi++)
|
|
1236
|
+
for (let czi = 0;czi < 2; czi++) {
|
|
1237
|
+
const x = cxi ? b[3] : b[0], z = czi ? b[5] : b[2];
|
|
1238
|
+
const wx = m[0] + m[3] * x + m[5] * z, wz = m[2] + m[9] * x + m[11] * z;
|
|
1239
|
+
if (wx < x0)
|
|
1240
|
+
x0 = wx;
|
|
1241
|
+
if (wx > x1)
|
|
1242
|
+
x1 = wx;
|
|
1243
|
+
if (wz < z0)
|
|
1244
|
+
z0 = wz;
|
|
1245
|
+
if (wz > z1)
|
|
1246
|
+
z1 = wz;
|
|
1043
1247
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1248
|
+
const ri = rInst.length;
|
|
1249
|
+
rx0.push(x0);
|
|
1250
|
+
rx1.push(x1);
|
|
1251
|
+
rz0.push(z0);
|
|
1252
|
+
rz1.push(z1);
|
|
1253
|
+
rInst.push(idx);
|
|
1254
|
+
rPrep.push(prepPart(H, it.part));
|
|
1255
|
+
rBx.push(b[0]);
|
|
1256
|
+
rBz.push(b[2]);
|
|
1257
|
+
const lv2 = Math.round((m[1] + b[4]) * 2);
|
|
1258
|
+
for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
|
|
1259
|
+
for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
|
|
1260
|
+
const k = cellKey(lv2, cx, cz);
|
|
1261
|
+
if (k < 0)
|
|
1262
|
+
continue;
|
|
1263
|
+
const e = rectE.length;
|
|
1264
|
+
rectE.push(ri);
|
|
1265
|
+
nextE.push(cells.put(k, e));
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
|
|
1269
|
+
const coverStep = (x, y, z, self) => {
|
|
1270
|
+
const k = cellKey(Math.round(y * 2), Math.floor(x / CELL), Math.floor(z / CELL));
|
|
1271
|
+
if (k < 0)
|
|
1272
|
+
return STEP_NEVER;
|
|
1273
|
+
let best = STEP_NEVER;
|
|
1274
|
+
for (let e = cells.get(k);e >= 0; e = nextE[e]) {
|
|
1275
|
+
const ri = rectE[e];
|
|
1276
|
+
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
1277
|
continue;
|
|
1052
|
-
const
|
|
1053
|
-
const
|
|
1054
|
-
const
|
|
1278
|
+
const m = insts[rInst[ri]].m;
|
|
1279
|
+
const pp = rPrep[ri];
|
|
1280
|
+
const bx = rBx[ri], bz = rBz[ri];
|
|
1055
1281
|
const dx = x - m[0], dy = y - m[1], dz = z - m[2];
|
|
1056
1282
|
const lx = m[3] * dx + m[6] * dy + m[9] * dz, lz = m[5] * dx + m[8] * dy + m[11] * dz;
|
|
1057
|
-
const
|
|
1283
|
+
const { nx, nz, mask: bits } = pp;
|
|
1058
1284
|
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] !==
|
|
1285
|
+
for (let s = 0;s < 5; s++) {
|
|
1286
|
+
const ca = Math.floor((lx + SX[s] - bx) / 20), cb = Math.floor((lz + SZ[s] - bz) / 20);
|
|
1287
|
+
if (ca < 0 || cb < 0 || ca >= nx || cb >= nz || bits[ca * nz + cb] !== 1) {
|
|
1062
1288
|
ok = false;
|
|
1063
1289
|
break;
|
|
1064
1290
|
}
|
|
1065
1291
|
}
|
|
1066
|
-
if (ok)
|
|
1067
|
-
|
|
1292
|
+
if (ok) {
|
|
1293
|
+
if (!steps)
|
|
1294
|
+
return 0;
|
|
1295
|
+
const st = steps[rInst[ri]];
|
|
1296
|
+
if (st < best)
|
|
1297
|
+
best = st;
|
|
1298
|
+
}
|
|
1068
1299
|
}
|
|
1069
|
-
return
|
|
1300
|
+
return best;
|
|
1070
1301
|
};
|
|
1071
|
-
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1302
|
+
let nStuds = 0;
|
|
1303
|
+
for (const it of insts) {
|
|
1304
|
+
const pp = prepPart(H, it.part);
|
|
1305
|
+
if (pp)
|
|
1306
|
+
nStuds += pp.nStuds;
|
|
1307
|
+
}
|
|
1308
|
+
const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
|
|
1309
|
+
const tops = new NumTable(nStuds);
|
|
1310
|
+
let studsHidden = 0;
|
|
1311
|
+
const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
|
|
1312
|
+
forEachStud(insts, H, (j, idx, w) => {
|
|
1313
|
+
if (!upright(w))
|
|
1314
|
+
return;
|
|
1315
|
+
studUp[j] = 1;
|
|
1316
|
+
const cs = coverStep(w[0], w[1], w[2], idx);
|
|
1317
|
+
if (cs !== STEP_NEVER) {
|
|
1318
|
+
studHidden[j] = 1;
|
|
1319
|
+
studsHidden++;
|
|
1320
|
+
if (studHideStep)
|
|
1321
|
+
studHideStep[j] = cs;
|
|
1322
|
+
}
|
|
1323
|
+
const k = topKey(w[0], w[1], w[2]);
|
|
1324
|
+
if (k < 0)
|
|
1325
|
+
return;
|
|
1326
|
+
if (!steps) {
|
|
1327
|
+
tops.put(k, 1);
|
|
1077
1328
|
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
1329
|
}
|
|
1330
|
+
const st = steps[idx], o = tops.get(k);
|
|
1331
|
+
if (o < 0 || st < o)
|
|
1332
|
+
tops.put(k, st);
|
|
1086
1333
|
});
|
|
1087
|
-
const underHidden = insts.
|
|
1334
|
+
const underHidden = new Uint8Array(insts.length);
|
|
1335
|
+
const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
|
|
1336
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1337
|
+
const it = insts[idx];
|
|
1088
1338
|
const p = H.parts[it.part];
|
|
1089
1339
|
if (!p || !p.under || !upright(it.m))
|
|
1090
|
-
|
|
1340
|
+
continue;
|
|
1091
1341
|
const b = p.bbox;
|
|
1092
1342
|
const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
|
|
1093
1343
|
if (!nx || !nz || nx * nz > 4096)
|
|
1094
|
-
|
|
1095
|
-
|
|
1344
|
+
continue;
|
|
1345
|
+
const m = it.m;
|
|
1346
|
+
let all = true, at = 0;
|
|
1347
|
+
for (let a = 0;a < nx && all; a++)
|
|
1096
1348
|
for (let c = 0;c < nz; c++) {
|
|
1097
1349
|
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1098
|
-
const x =
|
|
1099
|
-
|
|
1100
|
-
|
|
1350
|
+
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1351
|
+
const k = topKey(x, m[1] + b[4], z);
|
|
1352
|
+
const t = k < 0 ? -1 : tops.get(k);
|
|
1353
|
+
if (t < 0) {
|
|
1354
|
+
all = false;
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
if (t > at)
|
|
1358
|
+
at = t;
|
|
1101
1359
|
}
|
|
1102
|
-
|
|
1360
|
+
if (all) {
|
|
1361
|
+
underHidden[idx] = 1;
|
|
1362
|
+
if (underHideStep)
|
|
1363
|
+
underHideStep[idx] = at;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
|
|
1367
|
+
}
|
|
1368
|
+
function computeCulling(insts, H) {
|
|
1369
|
+
const c = cullCore(insts, H);
|
|
1370
|
+
const studs = new Array(c.nStuds);
|
|
1371
|
+
forEachStud(insts, H, (j, _i, w, kind, color) => {
|
|
1372
|
+
studs[j] = { kind, color, w: Array.from(w), hidden: c.studHidden[j] === 1 };
|
|
1103
1373
|
});
|
|
1104
|
-
return { studs, underHidden };
|
|
1374
|
+
return { studs, underHidden: Array.from(c.underHidden, (x) => x === 1) };
|
|
1375
|
+
}
|
|
1376
|
+
function gridClusters(n, x, z, k) {
|
|
1377
|
+
if (n <= k || !isFinite(k)) {
|
|
1378
|
+
const a = new Int32Array(n);
|
|
1379
|
+
for (let i = 0;i < n; i++)
|
|
1380
|
+
a[i] = i;
|
|
1381
|
+
return [a];
|
|
1382
|
+
}
|
|
1383
|
+
let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
|
|
1384
|
+
for (let i = 0;i < n; i++) {
|
|
1385
|
+
const a = x(i), b = z(i);
|
|
1386
|
+
if (a < x0)
|
|
1387
|
+
x0 = a;
|
|
1388
|
+
if (a > x1)
|
|
1389
|
+
x1 = a;
|
|
1390
|
+
if (b < z0)
|
|
1391
|
+
z0 = b;
|
|
1392
|
+
if (b > z1)
|
|
1393
|
+
z1 = b;
|
|
1394
|
+
}
|
|
1395
|
+
const G = Math.max(1, Math.ceil(Math.sqrt(n / k)));
|
|
1396
|
+
const sx = (x1 - x0) / G || 1, sz = (z1 - z0) / G || 1;
|
|
1397
|
+
const cell = new Int32Array(n), cnt = new Int32Array(G * G);
|
|
1398
|
+
for (let i = 0;i < n; i++) {
|
|
1399
|
+
const c = Math.min(G - 1, Math.floor((x(i) - x0) / sx)) * G + Math.min(G - 1, Math.floor((z(i) - z0) / sz));
|
|
1400
|
+
cell[i] = c;
|
|
1401
|
+
cnt[c]++;
|
|
1402
|
+
}
|
|
1403
|
+
const out = [];
|
|
1404
|
+
const at = new Int32Array(G * G).fill(-1);
|
|
1405
|
+
const fill = new Int32Array(G * G);
|
|
1406
|
+
for (let c = 0;c < G * G; c++)
|
|
1407
|
+
if (cnt[c]) {
|
|
1408
|
+
at[c] = out.length;
|
|
1409
|
+
out.push(new Int32Array(cnt[c]));
|
|
1410
|
+
}
|
|
1411
|
+
for (let i = 0;i < n; i++) {
|
|
1412
|
+
const c = cell[i];
|
|
1413
|
+
out[at[c]][fill[c]++] = i;
|
|
1414
|
+
}
|
|
1415
|
+
return out;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
class LdrLodRoot extends THREE.LOD {
|
|
1419
|
+
clusters = [];
|
|
1420
|
+
vpH = 1080;
|
|
1421
|
+
px = 0.5;
|
|
1422
|
+
edgePpl = 0.025;
|
|
1423
|
+
enabled = true;
|
|
1424
|
+
apply = () => {};
|
|
1425
|
+
inv = new THREE.Matrix4;
|
|
1426
|
+
cp = new THREE.Vector3;
|
|
1427
|
+
constructor() {
|
|
1428
|
+
super();
|
|
1429
|
+
this.autoUpdate = true;
|
|
1430
|
+
}
|
|
1431
|
+
raycast() {}
|
|
1432
|
+
update(camera) {
|
|
1433
|
+
if (!this.enabled || !this.clusters.length)
|
|
1434
|
+
return;
|
|
1435
|
+
const pm = camera.projectionMatrix.elements;
|
|
1436
|
+
const persp = camera.isPerspectiveCamera || pm[15] === 0;
|
|
1437
|
+
const k = this.vpH / 2 * Math.abs(pm[5]);
|
|
1438
|
+
this.inv.copy(this.matrixWorld).invert();
|
|
1439
|
+
this.cp.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(this.inv);
|
|
1440
|
+
const { x, y, z } = this.cp;
|
|
1441
|
+
const tau = this.px, eppl = this.edgePpl;
|
|
1442
|
+
for (const c of this.clusters) {
|
|
1443
|
+
const cx = c.s.center.x - x, cy = c.s.center.y - y, cz = c.s.center.z - z;
|
|
1444
|
+
const d = Math.sqrt(cx * cx + cy * cy + cz * cz) - c.s.radius;
|
|
1445
|
+
const ppl = persp ? d > 0.000001 ? k / d : Infinity : k;
|
|
1446
|
+
let L = 0;
|
|
1447
|
+
for (let i = c.lv.length - 1;i > 0; i--)
|
|
1448
|
+
if (c.lv[i].err * ppl <= tau) {
|
|
1449
|
+
L = i;
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
const e = ppl >= eppl;
|
|
1453
|
+
if (L !== c.cur || e !== c.edgeOk) {
|
|
1454
|
+
c.cur = L;
|
|
1455
|
+
c.edgeOk = e;
|
|
1456
|
+
this.apply(c);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, colorIndex) {
|
|
1462
|
+
const bucketOf = new Map;
|
|
1463
|
+
const bKind = [], bMirror = [];
|
|
1464
|
+
const bAll = [];
|
|
1465
|
+
const studBucket = new Uint16Array(cull.nStuds);
|
|
1466
|
+
const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
|
|
1467
|
+
forEachStud(insts, H, (j, _i, w, kind) => {
|
|
1468
|
+
const neg = det12(w) < 0;
|
|
1469
|
+
const k = neg ? kind + "#m" : kind;
|
|
1470
|
+
let b = bucketOf.get(k);
|
|
1471
|
+
if (b === undefined) {
|
|
1472
|
+
b = bKind.length;
|
|
1473
|
+
bucketOf.set(k, b);
|
|
1474
|
+
bKind.push(kind);
|
|
1475
|
+
bMirror.push(neg);
|
|
1476
|
+
bAll.push(0);
|
|
1477
|
+
}
|
|
1478
|
+
studBucket[j] = b;
|
|
1479
|
+
bAll[b]++;
|
|
1480
|
+
sx[j] = w[0];
|
|
1481
|
+
sz[j] = w[2];
|
|
1482
|
+
});
|
|
1483
|
+
const bIds = bAll.map((n) => new Int32Array(n));
|
|
1484
|
+
{
|
|
1485
|
+
const f = bAll.map(() => 0);
|
|
1486
|
+
for (let j = 0;j < cull.nStuds; j++) {
|
|
1487
|
+
const b = studBucket[j];
|
|
1488
|
+
bIds[b][f[b]++] = j;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
|
|
1492
|
+
const sMesh = [];
|
|
1493
|
+
bKind.forEach((kind, b) => {
|
|
1494
|
+
const g = geom(H.studKinds[kind].body, arr, Q);
|
|
1495
|
+
const ids = bIds[b];
|
|
1496
|
+
for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
|
|
1497
|
+
const ci = sMesh.length;
|
|
1498
|
+
let v = 0;
|
|
1499
|
+
for (const i of c)
|
|
1500
|
+
if (!cull.studHidden[ids[i]])
|
|
1501
|
+
v++;
|
|
1502
|
+
let vc = 0, hc = v;
|
|
1503
|
+
for (const i of c) {
|
|
1504
|
+
const j = ids[i];
|
|
1505
|
+
studCl[j] = ci;
|
|
1506
|
+
studSlot[j] = cull.studHidden[j] ? hc++ : vc++;
|
|
1507
|
+
}
|
|
1508
|
+
if (!g) {
|
|
1509
|
+
sMesh.push(null);
|
|
1510
|
+
continue;
|
|
1511
|
+
}
|
|
1512
|
+
const im = newIM(g, bMirror[b] ? matB : matF, c.length);
|
|
1513
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(new Float32Array(c.length * 3), 3);
|
|
1514
|
+
const n = c.length;
|
|
1515
|
+
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) } } : {} });
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
|
|
1519
|
+
const sm = sMesh[studCl[j]];
|
|
1520
|
+
if (!sm)
|
|
1521
|
+
return;
|
|
1522
|
+
const im = sm.im;
|
|
1523
|
+
const slot = studSlot[j];
|
|
1524
|
+
if (sm.slots) {
|
|
1525
|
+
const t = sm.slots;
|
|
1526
|
+
t.own[slot] = steps[owner];
|
|
1527
|
+
t.hide[slot] = cull.studHideStep[j];
|
|
1528
|
+
t.inst[slot] = owner;
|
|
1529
|
+
t.stud[slot] = si;
|
|
1530
|
+
t.col[slot] = colorIndex(col);
|
|
1531
|
+
}
|
|
1532
|
+
writeM4(im.instanceMatrix.array, slot * 16, w);
|
|
1533
|
+
color(col).toArray(im.instanceColor.array, slot * 3);
|
|
1534
|
+
});
|
|
1535
|
+
return sMesh;
|
|
1105
1536
|
}
|
|
1106
1537
|
function buildLdrScene(insts, pack, P, color, mark) {
|
|
1107
1538
|
const { header: H, arr } = pack;
|
|
1108
|
-
const
|
|
1539
|
+
const Q = P.quant !== false;
|
|
1540
|
+
const LOD = P.lod !== false;
|
|
1541
|
+
const root = new LdrLodRoot;
|
|
1542
|
+
root.enabled = LOD;
|
|
1543
|
+
root.px = P.lodPx ?? 0.5;
|
|
1544
|
+
root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
|
|
1545
|
+
const trackVp = (r) => {
|
|
1546
|
+
const rt = r.getRenderTarget();
|
|
1547
|
+
const h = rt ? rt.height : r.getContext().drawingBufferHeight;
|
|
1548
|
+
if (h)
|
|
1549
|
+
root.vpH = h;
|
|
1550
|
+
};
|
|
1109
1551
|
const matF = makeMaterial(P.side === "front" ? THREE.FrontSide : THREE.DoubleSide), matB = makeMaterial(P.side === "front" ? THREE.BackSide : THREE.DoubleSide);
|
|
1110
1552
|
const matD = makeMaterial(THREE.DoubleSide);
|
|
1111
1553
|
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
1554
|
const byPart = new Map;
|
|
1114
1555
|
insts.forEach((it, i) => {
|
|
1115
1556
|
if (H.parts[it.part]) {
|
|
1116
|
-
const k = it.part + (
|
|
1557
|
+
const k = it.part + (det12(it.m) < 0 ? "#m" : "");
|
|
1117
1558
|
(byPart.get(k) || byPart.set(k, []).get(k)).push(i);
|
|
1118
1559
|
}
|
|
1119
1560
|
});
|
|
1120
|
-
const
|
|
1561
|
+
const steps = P.steps;
|
|
1562
|
+
let cull = cullCore(insts, H, steps);
|
|
1121
1563
|
mark("culling");
|
|
1564
|
+
const stepBatches = [];
|
|
1565
|
+
const instM = steps ? new Float64Array(insts.length * 12) : null;
|
|
1566
|
+
const instPP = [];
|
|
1567
|
+
const palette = [];
|
|
1568
|
+
const palIdx = new Map;
|
|
1569
|
+
const colorIndex = (c) => {
|
|
1570
|
+
let i = palIdx.get(c);
|
|
1571
|
+
if (i === undefined) {
|
|
1572
|
+
i = palette.length;
|
|
1573
|
+
palette.push(color(c));
|
|
1574
|
+
palIdx.set(c, i);
|
|
1575
|
+
}
|
|
1576
|
+
return i;
|
|
1577
|
+
};
|
|
1578
|
+
const instCol = steps ? new Uint16Array(insts.length) : null;
|
|
1579
|
+
if (instM)
|
|
1580
|
+
insts.forEach((it, i) => {
|
|
1581
|
+
for (let k = 0;k < 12; k++)
|
|
1582
|
+
instM[i * 12 + k] = it.m[k];
|
|
1583
|
+
instPP.push(prepPart(H, it.part));
|
|
1584
|
+
instCol[i] = colorIndex(it.color);
|
|
1585
|
+
});
|
|
1122
1586
|
const edgeObjs = [];
|
|
1123
1587
|
const condObjs = [];
|
|
1124
1588
|
const wantCond = P.cond !== false && (P.edges === "idx" || P.edges === true);
|
|
1125
1589
|
let condMat = null;
|
|
1126
1590
|
const cmat = () => condMat ??= condLineMat();
|
|
1591
|
+
let lineMatShared = null;
|
|
1592
|
+
const lmat = () => lineMatShared ??= sharedLineMat();
|
|
1127
1593
|
const condCache = new Map;
|
|
1128
|
-
const addCond = (entry, im, which = "body") => {
|
|
1594
|
+
const addCond = (entry, im, cl, which = "body") => {
|
|
1129
1595
|
if (!wantCond)
|
|
1130
1596
|
return null;
|
|
1131
1597
|
const ck = which === "under" ? entry.condlu : entry.condl;
|
|
@@ -1142,12 +1608,40 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1142
1608
|
const l = condEdges(cb, im, cmat());
|
|
1143
1609
|
edgeObjs.push(l);
|
|
1144
1610
|
condObjs.push(l);
|
|
1611
|
+
cl.cond.push(l);
|
|
1612
|
+
root.add(l);
|
|
1613
|
+
return l;
|
|
1614
|
+
};
|
|
1615
|
+
const lineCache = new Map;
|
|
1616
|
+
const addLines = (ref, im, cl) => {
|
|
1617
|
+
let w = lineCache.get(ref);
|
|
1618
|
+
if (!w) {
|
|
1619
|
+
const r = weldLines(arr(ref));
|
|
1620
|
+
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
|
|
1621
|
+
}
|
|
1622
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1623
|
+
g.setAttribute("position", w.P);
|
|
1624
|
+
g.setIndex(w.I);
|
|
1625
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1626
|
+
g.instanceCount = im.count;
|
|
1627
|
+
const l = new THREE.LineSegments(g, lmat());
|
|
1628
|
+
l.frustumCulled = false;
|
|
1629
|
+
edgeObjs.push(l);
|
|
1630
|
+
cl.lines.push(l);
|
|
1145
1631
|
root.add(l);
|
|
1146
1632
|
return l;
|
|
1147
1633
|
};
|
|
1148
|
-
const stats = { studsTotal: cull.
|
|
1634
|
+
const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
|
|
1149
1635
|
const toggles = [];
|
|
1150
1636
|
const studMeshes = [];
|
|
1637
|
+
const countTo = (objs) => ({ set count(n) {
|
|
1638
|
+
for (const o of objs()) {
|
|
1639
|
+
if (o.isInstancedMesh)
|
|
1640
|
+
o.count = n;
|
|
1641
|
+
else
|
|
1642
|
+
o.geometry.instanceCount = n;
|
|
1643
|
+
}
|
|
1644
|
+
} });
|
|
1151
1645
|
const wantTex = P.tex !== false && !!H.textures;
|
|
1152
1646
|
const texCache = new Map;
|
|
1153
1647
|
const texMats = new Map;
|
|
@@ -1169,160 +1663,256 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1169
1663
|
return m;
|
|
1170
1664
|
};
|
|
1171
1665
|
let texBatches = 0;
|
|
1172
|
-
|
|
1666
|
+
const newCluster = (s) => {
|
|
1667
|
+
const c = { s, lv: [], lines: [], cond: [], cur: 0, edgeOk: true };
|
|
1668
|
+
root.clusters.push(c);
|
|
1669
|
+
return c;
|
|
1670
|
+
};
|
|
1671
|
+
const lodLevels = (b, base, mat) => !LOD || P.lodMesh === false || !b?.lod ? [] : b.lod.map((l) => {
|
|
1672
|
+
const im = new THREE.InstancedMesh(geom(l, arr, Q), mat, 0);
|
|
1673
|
+
im.instanceMatrix = base.instanceMatrix;
|
|
1674
|
+
im.count = base.count;
|
|
1675
|
+
im.instanceColor = base.instanceColor;
|
|
1676
|
+
im.boundingSphere = base.boundingSphere;
|
|
1677
|
+
im.visible = false;
|
|
1678
|
+
im.onBeforeRender = trackVp;
|
|
1679
|
+
im.userData.ldrLod = true;
|
|
1680
|
+
root.add(im);
|
|
1681
|
+
return { objs: [im], err: l.err };
|
|
1682
|
+
});
|
|
1683
|
+
const tris = (b) => b ? b.tris ?? 0 : 0;
|
|
1684
|
+
const kFor = (t) => LOD ? Math.max(256, Math.min(16384, Math.round(262144 / Math.max(1, t)))) : Infinity;
|
|
1685
|
+
for (const [pk, idsAll] of byPart) {
|
|
1173
1686
|
const part = pk.replace(/#m$/, "");
|
|
1174
1687
|
const p = H.parts[part];
|
|
1175
1688
|
const mat = P.uncertDouble !== false && p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
|
|
1176
1689
|
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
|
-
}
|
|
1690
|
+
const bodyB = textured ? p.tbody : p.body;
|
|
1691
|
+
const body = geom(bodyB, arr, Q);
|
|
1692
|
+
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)));
|
|
1693
|
+
for (const g of groups) {
|
|
1694
|
+
const ids = Array.from(g, (i) => idsAll[i]);
|
|
1695
|
+
let bodyIm = null;
|
|
1696
|
+
const lv0 = [];
|
|
1697
|
+
const place = (im) => {
|
|
1698
|
+
fillInstances(im, ids, insts, color);
|
|
1699
|
+
im.computeBoundingSphere();
|
|
1700
|
+
root.add(im);
|
|
1701
|
+
};
|
|
1702
|
+
if (body) {
|
|
1703
|
+
const im = bodyIm = newIM(body, mat, ids.length);
|
|
1704
|
+
place(im);
|
|
1705
|
+
lv0.push(im);
|
|
1205
1706
|
}
|
|
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
|
-
|
|
1707
|
+
if (textured)
|
|
1708
|
+
for (const tb of p.tex) {
|
|
1709
|
+
const gg = geom(tb, arr, Q);
|
|
1710
|
+
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
1711
|
+
texBatches++;
|
|
1712
|
+
lv0.push(im);
|
|
1713
|
+
if (bodyIm) {
|
|
1714
|
+
im.instanceMatrix = bodyIm.instanceMatrix;
|
|
1715
|
+
im.instanceColor = bodyIm.instanceColor;
|
|
1716
|
+
im.boundingSphere = bodyIm.boundingSphere;
|
|
1717
|
+
root.add(im);
|
|
1718
|
+
} else {
|
|
1719
|
+
place(im);
|
|
1720
|
+
bodyIm = im;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
if (bodyIm) {
|
|
1724
|
+
const cl = newCluster(bodyIm.boundingSphere);
|
|
1725
|
+
lv0.forEach((o) => o.onBeforeRender = trackVp);
|
|
1726
|
+
cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
|
|
1727
|
+
if (P.edges === "idx" && p.edges)
|
|
1728
|
+
addLines(p.edges, bodyIm, cl);
|
|
1729
|
+
addCond(p, bodyIm, cl);
|
|
1730
|
+
if (steps)
|
|
1731
|
+
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]) });
|
|
1732
|
+
if (P.edges === true && p.edges) {
|
|
1733
|
+
const mats = new Float32Array(ids.length * 16);
|
|
1734
|
+
ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
|
|
1735
|
+
{
|
|
1736
|
+
const l = instancedLines(arr(p.edges), mats, ids.length);
|
|
1737
|
+
edgeObjs.push(l);
|
|
1738
|
+
cl.lines.push(l);
|
|
1739
|
+
root.add(l);
|
|
1740
|
+
}
|
|
1235
1741
|
}
|
|
1236
1742
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1743
|
+
const under = geom(p.under, arr, Q);
|
|
1744
|
+
if (under) {
|
|
1745
|
+
const ord = [...ids.filter((i) => !cull.underHidden[i]), ...ids.filter((i) => cull.underHidden[i])];
|
|
1746
|
+
const vis = ids.length - ids.reduce((a, i) => a + cull.underHidden[i], 0);
|
|
1747
|
+
stats.undersTotal += ids.length;
|
|
1748
|
+
stats.undersHidden += ids.length - vis;
|
|
1749
|
+
const im = newIM(under, mat, ids.length);
|
|
1750
|
+
fillInstances(im, ord, insts, color);
|
|
1751
|
+
im.onBeforeRender = trackVp;
|
|
1752
|
+
im.computeBoundingSphere();
|
|
1753
|
+
im.count = P.cullUnder ? vis : ids.length;
|
|
1754
|
+
root.add(im);
|
|
1755
|
+
const cl = newCluster(im.boundingSphere);
|
|
1756
|
+
cl.lv.push({ objs: [im], err: 0 }, ...lodLevels(p.under, im, mat));
|
|
1757
|
+
addCond(p, im, cl, "under");
|
|
1758
|
+
const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
|
|
1759
|
+
objs.forEach((o) => {
|
|
1760
|
+
if (!o.isInstancedMesh)
|
|
1761
|
+
o.geometry.instanceCount = im.count;
|
|
1762
|
+
});
|
|
1763
|
+
toggles.push({ mesh: countTo(() => objs), all: ids.length, visible: vis, flag: "under" });
|
|
1764
|
+
if (steps)
|
|
1765
|
+
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
1766
|
}
|
|
1246
1767
|
}
|
|
1247
1768
|
}
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const
|
|
1769
|
+
const sMesh = buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, steps && colorIndex);
|
|
1770
|
+
const sKind = sMesh.map((x) => x?.kind ?? "");
|
|
1771
|
+
const sVis = sMesh.map((x) => x?.vis ?? 0);
|
|
1772
|
+
const STUD_ERR = 12;
|
|
1773
|
+
sMesh.forEach((sm, ci) => {
|
|
1774
|
+
if (!sm)
|
|
1775
|
+
return;
|
|
1776
|
+
const im = sm.im;
|
|
1777
|
+
const kind = sKind[ci];
|
|
1256
1778
|
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
|
-
});
|
|
1779
|
+
const vis = sVis[ci], all = im.instanceMatrix.count;
|
|
1267
1780
|
im.computeBoundingSphere();
|
|
1268
|
-
im.count = P.cullStuds ? vis :
|
|
1781
|
+
im.count = P.cullStuds ? vis : all;
|
|
1782
|
+
im.onBeforeRender = trackVp;
|
|
1783
|
+
im.userData.ldrStud = true;
|
|
1269
1784
|
root.add(im);
|
|
1270
|
-
toggles.push({ mesh: im, all: ord.length, visible: vis, flag: "studs" });
|
|
1271
1785
|
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
|
-
}
|
|
1786
|
+
const cl = newCluster(im.boundingSphere);
|
|
1787
|
+
cl.lv.push({ objs: [im], err: 0 });
|
|
1788
|
+
if (LOD && P.lodStuds !== false)
|
|
1789
|
+
cl.lv.push({ objs: [], err: STUD_ERR });
|
|
1790
|
+
if (P.edges === "idx" && k.edges)
|
|
1791
|
+
addLines(k.edges, im, cl);
|
|
1792
|
+
if (P.condStuds !== false)
|
|
1793
|
+
addCond(k, im, cl);
|
|
1290
1794
|
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);
|
|
1795
|
+
const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
|
|
1294
1796
|
edgeObjs.push(l);
|
|
1797
|
+
cl.lines.push(l);
|
|
1295
1798
|
root.add(l);
|
|
1296
|
-
toggles.push({ mesh: { set count(n) {
|
|
1297
|
-
l.geometry.instanceCount = n;
|
|
1298
|
-
} }, all: ord.length, visible: vis, flag: "studs" });
|
|
1299
1799
|
}
|
|
1300
|
-
|
|
1800
|
+
const objs = [im, ...cl.lines, ...cl.cond];
|
|
1801
|
+
objs.forEach((o) => {
|
|
1802
|
+
if (!o.isInstancedMesh)
|
|
1803
|
+
o.geometry.instanceCount = im.count;
|
|
1804
|
+
});
|
|
1805
|
+
toggles.push({ mesh: countTo(() => objs), all, visible: vis, flag: "studs" });
|
|
1806
|
+
if (sm.slots)
|
|
1807
|
+
stepBatches.push({ im, objs, flag: "studs", ...sm.slots });
|
|
1808
|
+
});
|
|
1301
1809
|
stats.uncertParts = Object.values(H.parts).filter((x) => x.uncert).length;
|
|
1302
1810
|
stats.uncertBatches = nUncert;
|
|
1303
1811
|
let condOn = true, edgesOn = true;
|
|
1812
|
+
root.apply = (c) => {
|
|
1813
|
+
c.lv.forEach((l, i) => {
|
|
1814
|
+
for (const o of l.objs)
|
|
1815
|
+
o.visible = i === c.cur;
|
|
1816
|
+
});
|
|
1817
|
+
const lineVis = edgesOn && c.edgeOk && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
1818
|
+
for (const o of c.lines)
|
|
1819
|
+
o.visible = lineVis;
|
|
1820
|
+
for (const o of c.cond)
|
|
1821
|
+
o.visible = lineVis && condOn;
|
|
1822
|
+
};
|
|
1823
|
+
const refresh = () => root.clusters.forEach(root.apply);
|
|
1304
1824
|
const setEdges = (v) => {
|
|
1305
1825
|
edgesOn = v;
|
|
1306
|
-
|
|
1826
|
+
refresh();
|
|
1307
1827
|
};
|
|
1308
1828
|
const setCond = (v) => {
|
|
1309
1829
|
condOn = v;
|
|
1310
|
-
|
|
1830
|
+
refresh();
|
|
1311
1831
|
};
|
|
1832
|
+
refresh();
|
|
1312
1833
|
stats.condBatches = condObjs.length;
|
|
1313
1834
|
stats.texBatches = texBatches;
|
|
1314
1835
|
stats.textures = texCache.size;
|
|
1836
|
+
stats.clusters = root.clusters.length;
|
|
1315
1837
|
const texturesReady = Promise.all(pending).then(() => {});
|
|
1838
|
+
let stepS = STEP_NEVER - 1, cullS = !!P.cullStuds, cullU = !!P.cullUnder;
|
|
1839
|
+
const applySteps = () => {
|
|
1840
|
+
const st = { studsTotal: 0, studsHidden: 0, undersTotal: 0, undersHidden: 0 };
|
|
1841
|
+
const S = stepS;
|
|
1842
|
+
const wm = new Float64Array(12);
|
|
1843
|
+
for (const b of stepBatches) {
|
|
1844
|
+
const MA = b.im.instanceMatrix.array, CA = b.im.instanceColor.array;
|
|
1845
|
+
const useHide = b.flag === "studs" ? cullS : b.flag === "under" ? cullU : false;
|
|
1846
|
+
const { own, hide, inst, stud, col } = b;
|
|
1847
|
+
let w = 0;
|
|
1848
|
+
for (let i = 0;i < own.length; i++) {
|
|
1849
|
+
if (own[i] > S)
|
|
1850
|
+
continue;
|
|
1851
|
+
const hid = !!hide && hide[i] <= S;
|
|
1852
|
+
if (b.flag === "studs") {
|
|
1853
|
+
st.studsTotal++;
|
|
1854
|
+
if (hid)
|
|
1855
|
+
st.studsHidden++;
|
|
1856
|
+
} else if (b.flag === "under") {
|
|
1857
|
+
st.undersTotal++;
|
|
1858
|
+
if (hid)
|
|
1859
|
+
st.undersHidden++;
|
|
1860
|
+
}
|
|
1861
|
+
if (useHide && hid)
|
|
1862
|
+
continue;
|
|
1863
|
+
const n = inst[i];
|
|
1864
|
+
if (stud) {
|
|
1865
|
+
mul12To(instM, instPP[n].studM, stud[i] * 12, wm, n * 12);
|
|
1866
|
+
writeM4(MA, w * 16, wm);
|
|
1867
|
+
} else
|
|
1868
|
+
writeM4(MA, w * 16, instM, n * 12);
|
|
1869
|
+
palette[col[i]].toArray(CA, w * 3);
|
|
1870
|
+
w++;
|
|
1871
|
+
}
|
|
1872
|
+
b.im.instanceMatrix.needsUpdate = true;
|
|
1873
|
+
b.im.instanceColor.needsUpdate = true;
|
|
1874
|
+
for (const o of b.objs) {
|
|
1875
|
+
if (o.isInstancedMesh)
|
|
1876
|
+
o.count = w;
|
|
1877
|
+
else
|
|
1878
|
+
o.geometry.instanceCount = w;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
return st;
|
|
1882
|
+
};
|
|
1316
1883
|
const setCull = (studs, under) => {
|
|
1884
|
+
cullS = studs;
|
|
1885
|
+
cullU = under;
|
|
1886
|
+
if (steps) {
|
|
1887
|
+
applySteps();
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1317
1890
|
for (const t of toggles)
|
|
1318
1891
|
t.mesh.count = (t.flag === "studs" ? studs : under) ? t.visible : t.all;
|
|
1319
1892
|
};
|
|
1893
|
+
const setStep = (s) => {
|
|
1894
|
+
if (!steps)
|
|
1895
|
+
throw new Error("buildLdrScene: setStep needs P.steps");
|
|
1896
|
+
stepS = s == null ? STEP_NEVER - 1 : s;
|
|
1897
|
+
return applySteps();
|
|
1898
|
+
};
|
|
1320
1899
|
const box = new THREE.Box3;
|
|
1321
1900
|
for (const it of insts) {
|
|
1322
|
-
|
|
1323
|
-
if (!p)
|
|
1901
|
+
if (!H.parts[it.part])
|
|
1324
1902
|
continue;
|
|
1325
|
-
|
|
1903
|
+
const m = it.m;
|
|
1904
|
+
if (m[0] < box.min.x)
|
|
1905
|
+
box.min.x = m[0];
|
|
1906
|
+
if (m[1] < box.min.y)
|
|
1907
|
+
box.min.y = m[1];
|
|
1908
|
+
if (m[2] < box.min.z)
|
|
1909
|
+
box.min.z = m[2];
|
|
1910
|
+
if (m[0] > box.max.x)
|
|
1911
|
+
box.max.x = m[0];
|
|
1912
|
+
if (m[1] > box.max.y)
|
|
1913
|
+
box.max.y = m[1];
|
|
1914
|
+
if (m[2] > box.max.z)
|
|
1915
|
+
box.max.z = m[2];
|
|
1326
1916
|
}
|
|
1327
1917
|
const setSide = (front) => {
|
|
1328
1918
|
matF.side = front ? THREE.FrontSide : THREE.DoubleSide;
|
|
@@ -1339,13 +1929,26 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1339
1929
|
for (const s of studMeshes) {
|
|
1340
1930
|
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
1931
|
if (k2)
|
|
1342
|
-
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr);
|
|
1932
|
+
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
|
|
1343
1933
|
}
|
|
1344
1934
|
return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
|
|
1345
1935
|
};
|
|
1346
|
-
|
|
1936
|
+
const setLod = (on) => {
|
|
1937
|
+
root.enabled = on && LOD;
|
|
1938
|
+
if (!root.enabled) {
|
|
1939
|
+
for (const c of root.clusters) {
|
|
1940
|
+
c.cur = 0;
|
|
1941
|
+
c.edgeOk = true;
|
|
1942
|
+
}
|
|
1943
|
+
refresh();
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
insts = null;
|
|
1947
|
+
cull = null;
|
|
1948
|
+
byPart.clear();
|
|
1949
|
+
return { root, stats, setCull, setSide, setEdges, setCond, swapStuds, setLod, setStep, box, texturesReady };
|
|
1347
1950
|
}
|
|
1348
|
-
// src/scene.ts
|
|
1951
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/scene.ts
|
|
1349
1952
|
import * as THREE2 from "three";
|
|
1350
1953
|
function colorFn(src, pack, fallback) {
|
|
1351
1954
|
const table = new Map;
|
|
@@ -1430,11 +2033,11 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1430
2033
|
}
|
|
1431
2034
|
cur = null;
|
|
1432
2035
|
};
|
|
1433
|
-
const
|
|
2036
|
+
const multiStep = uniq.length > 1;
|
|
2037
|
+
const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
|
|
2038
|
+
const build = () => {
|
|
1434
2039
|
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, () => {});
|
|
2040
|
+
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
2041
|
pairs.clear();
|
|
1439
2042
|
if (o.material === "plastic")
|
|
1440
2043
|
cur.root.traverse((x) => {
|
|
@@ -1449,17 +2052,25 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1449
2052
|
if (!cond)
|
|
1450
2053
|
cur.setCond(false);
|
|
1451
2054
|
object.add(cur.root);
|
|
1452
|
-
Object.assign(stats, { drawn:
|
|
2055
|
+
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
2056
|
api.texturesReady = cur.texturesReady;
|
|
1454
2057
|
};
|
|
2058
|
+
const setStep = (step) => {
|
|
2059
|
+
if (!multiStep)
|
|
2060
|
+
return;
|
|
2061
|
+
const t0 = performance.now();
|
|
2062
|
+
Object.assign(stats, cur.setStep(step), { drawn: drawnAt(step), buildMs: performance.now() - t0 });
|
|
2063
|
+
};
|
|
1455
2064
|
const api = { texturesReady: Promise.resolve() };
|
|
1456
|
-
build(
|
|
2065
|
+
build();
|
|
2066
|
+
if (o.step != null)
|
|
2067
|
+
setStep(o.step);
|
|
1457
2068
|
return Object.assign(api, {
|
|
1458
2069
|
object,
|
|
1459
2070
|
stats,
|
|
1460
2071
|
stepCount: uniq.length,
|
|
1461
2072
|
stepViews,
|
|
1462
|
-
setStep
|
|
2073
|
+
setStep,
|
|
1463
2074
|
setEdges: (v) => {
|
|
1464
2075
|
edges = v;
|
|
1465
2076
|
cur.setEdges(v);
|
|
@@ -1473,6 +2084,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1473
2084
|
cu = b;
|
|
1474
2085
|
cur.setCull(a, b);
|
|
1475
2086
|
},
|
|
2087
|
+
setLod: (v) => cur.setLod(v),
|
|
1476
2088
|
setSide: (s) => {
|
|
1477
2089
|
side = s;
|
|
1478
2090
|
cur.setSide(s === "front");
|
|
@@ -1485,7 +2097,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1485
2097
|
object.updateMatrixWorld(true);
|
|
1486
2098
|
target.makeEmpty();
|
|
1487
2099
|
object.traverse((x) => {
|
|
1488
|
-
if (x.isInstancedMesh && x.count) {
|
|
2100
|
+
if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
|
|
1489
2101
|
x.computeBoundingBox();
|
|
1490
2102
|
const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
|
|
1491
2103
|
target.union(b);
|
|
@@ -1496,7 +2108,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1496
2108
|
dispose: disposeCur
|
|
1497
2109
|
});
|
|
1498
2110
|
}
|
|
1499
|
-
// src/pack-io.ts
|
|
2111
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/pack-io.ts
|
|
1500
2112
|
import { decompress } from "fzstd";
|
|
1501
2113
|
async function decompressPack(data) {
|
|
1502
2114
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1507,7 +2119,147 @@ async function decompressPack(data) {
|
|
|
1507
2119
|
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
1508
2120
|
return own(u);
|
|
1509
2121
|
}
|
|
1510
|
-
// src/
|
|
2122
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/cdn.ts
|
|
2123
|
+
import { decompress as decompress2 } from "fzstd";
|
|
2124
|
+
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
2125
|
+
var indexCache = new Map;
|
|
2126
|
+
var shardCache = new Map;
|
|
2127
|
+
function loadPartsIndex(cdn = DEFAULT_PARTS_CDN, f = fetch) {
|
|
2128
|
+
let p = indexCache.get(cdn);
|
|
2129
|
+
if (!p) {
|
|
2130
|
+
p = f(cdn + "parts.json").then((r) => {
|
|
2131
|
+
if (!r.ok)
|
|
2132
|
+
throw new Error(`ldr: parts CDN index ${r.status} (${cdn}parts.json)`);
|
|
2133
|
+
return r.json();
|
|
2134
|
+
});
|
|
2135
|
+
p.catch(() => indexCache.delete(cdn));
|
|
2136
|
+
indexCache.set(cdn, p);
|
|
2137
|
+
}
|
|
2138
|
+
return p;
|
|
2139
|
+
}
|
|
2140
|
+
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");
|
|
2141
|
+
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;
|
|
2142
|
+
function mergePacks(packs, extra = {}) {
|
|
2143
|
+
const payloads = [];
|
|
2144
|
+
let off = 0;
|
|
2145
|
+
const parts = {}, studKinds = {};
|
|
2146
|
+
for (const p of packs) {
|
|
2147
|
+
const buf = p.buffer;
|
|
2148
|
+
if (!buf)
|
|
2149
|
+
throw new Error("ldr: mergePacks needs packs from decodePack/loadPack");
|
|
2150
|
+
const hl = new DataView(buf).getUint32(0, true);
|
|
2151
|
+
const pay = new Uint8Array(buf, 4 + hl);
|
|
2152
|
+
const d = off;
|
|
2153
|
+
payloads.push(pay);
|
|
2154
|
+
off += pay.byteLength;
|
|
2155
|
+
const pad = (4 - off % 4) % 4;
|
|
2156
|
+
if (pad) {
|
|
2157
|
+
payloads.push(new Uint8Array(pad));
|
|
2158
|
+
off += pad;
|
|
2159
|
+
}
|
|
2160
|
+
for (const [k, v] of Object.entries(p.header.parts ?? {}))
|
|
2161
|
+
if (!(k in parts))
|
|
2162
|
+
parts[k] = rebase(v, d);
|
|
2163
|
+
for (const [k, v] of Object.entries(p.header.studKinds ?? {}))
|
|
2164
|
+
if (!(k in studKinds))
|
|
2165
|
+
studKinds[k] = rebase(v, d);
|
|
2166
|
+
}
|
|
2167
|
+
const h0 = packs[0]?.header ?? { version: 1, weld: true };
|
|
2168
|
+
const header = new TextEncoder().encode(JSON.stringify({ ...h0, parts, studKinds, ...extra }));
|
|
2169
|
+
const hpad = (4 - (4 + header.length) % 4) % 4;
|
|
2170
|
+
const base = 4 + header.length + hpad;
|
|
2171
|
+
const out = new Uint8Array(base + off);
|
|
2172
|
+
new DataView(out.buffer).setUint32(0, header.length + hpad, true);
|
|
2173
|
+
out.set(header, 4);
|
|
2174
|
+
out.fill(32, 4 + header.length, base);
|
|
2175
|
+
let o = base;
|
|
2176
|
+
for (const p of payloads) {
|
|
2177
|
+
out.set(p, o);
|
|
2178
|
+
o += p.byteLength;
|
|
2179
|
+
}
|
|
2180
|
+
return decodePack(out.buffer);
|
|
2181
|
+
}
|
|
2182
|
+
async function loadParts(names, o = {}) {
|
|
2183
|
+
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 65536;
|
|
2184
|
+
const idx = await loadPartsIndex(cdn, f);
|
|
2185
|
+
const want = [...new Set([...names].map(norm))];
|
|
2186
|
+
const missing = [];
|
|
2187
|
+
const todo = [];
|
|
2188
|
+
for (const n of want) {
|
|
2189
|
+
if (shardCache.has(cdn + n))
|
|
2190
|
+
continue;
|
|
2191
|
+
const e = idx.parts[n];
|
|
2192
|
+
if (e)
|
|
2193
|
+
todo.push({ name: n, off: e[0], len: e[1], file: e[2] ?? 0 });
|
|
2194
|
+
else
|
|
2195
|
+
missing.push(n);
|
|
2196
|
+
}
|
|
2197
|
+
todo.sort((a, b) => a.file - b.file || a.off - b.off);
|
|
2198
|
+
const groups = [];
|
|
2199
|
+
for (const t of todo) {
|
|
2200
|
+
const g = groups[groups.length - 1];
|
|
2201
|
+
if (g && g.file === t.file && t.off - g.end <= gap) {
|
|
2202
|
+
g.end = Math.max(g.end, t.off + t.len);
|
|
2203
|
+
g.items.push(t);
|
|
2204
|
+
} else
|
|
2205
|
+
groups.push({ file: t.file, start: t.off, end: t.off + t.len, items: [t] });
|
|
2206
|
+
}
|
|
2207
|
+
let bytes = 0;
|
|
2208
|
+
let next = 0;
|
|
2209
|
+
const worker = async () => {
|
|
2210
|
+
while (next < groups.length) {
|
|
2211
|
+
const g = groups[next++];
|
|
2212
|
+
const r = await f(new URL(idx.archives[g.file], cdn).href, { headers: { Range: `bytes=${g.start}-${g.end - 1}` } });
|
|
2213
|
+
if (!r.ok)
|
|
2214
|
+
throw new Error(`ldr: parts CDN ${r.status}`);
|
|
2215
|
+
let buf = new Uint8Array(await r.arrayBuffer());
|
|
2216
|
+
if (r.status === 200)
|
|
2217
|
+
buf = buf.subarray(g.start, g.end);
|
|
2218
|
+
bytes += buf.byteLength;
|
|
2219
|
+
for (const t of g.items) {
|
|
2220
|
+
const raw = decompress2(buf.subarray(t.off - g.start, t.off - g.start + t.len));
|
|
2221
|
+
const ab = raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength);
|
|
2222
|
+
shardCache.set(cdn + t.name, decodePack(ab));
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 6, groups.length) }, worker));
|
|
2227
|
+
const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
|
|
2228
|
+
const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
|
|
2229
|
+
return { pack, missing, requests: groups.length, bytes };
|
|
2230
|
+
}
|
|
2231
|
+
function emptyPack(colors) {
|
|
2232
|
+
const h = new TextEncoder().encode(JSON.stringify({ version: 1, weld: true, parts: {}, studKinds: {}, colors }));
|
|
2233
|
+
const pad = (4 - (4 + h.length) % 4) % 4;
|
|
2234
|
+
const b = new Uint8Array(4 + h.length + pad).fill(32);
|
|
2235
|
+
new DataView(b.buffer).setUint32(0, h.length + pad, true);
|
|
2236
|
+
b.set(h, 4);
|
|
2237
|
+
return b.buffer;
|
|
2238
|
+
}
|
|
2239
|
+
async function loadModel(source, o = {}) {
|
|
2240
|
+
const t0 = performance.now();
|
|
2241
|
+
const f = o.fetch ?? fetch;
|
|
2242
|
+
const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
|
|
2243
|
+
const text = o.text ? source : await f(source).then((r) => {
|
|
2244
|
+
if (!r.ok)
|
|
2245
|
+
throw new Error(`ldr: ${r.status} fetching ${source}`);
|
|
2246
|
+
return r.text();
|
|
2247
|
+
});
|
|
2248
|
+
const t1 = performance.now();
|
|
2249
|
+
const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2250
|
+
const insts = parseModel(text, name, { looseGeometry: false });
|
|
2251
|
+
const t2 = performance.now();
|
|
2252
|
+
await idxP;
|
|
2253
|
+
const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
|
|
2254
|
+
const t3 = performance.now();
|
|
2255
|
+
const obj = createLdrObject(insts, pack, o);
|
|
2256
|
+
for (const m of missing)
|
|
2257
|
+
if (!obj.stats.missing.includes(m))
|
|
2258
|
+
obj.stats.missing.push(m);
|
|
2259
|
+
const t4 = performance.now();
|
|
2260
|
+
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 } });
|
|
2261
|
+
}
|
|
2262
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/library.ts
|
|
1511
2263
|
import { existsSync, readFileSync } from "fs";
|
|
1512
2264
|
import { join } from "path";
|
|
1513
2265
|
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 +2511,11 @@ class Library {
|
|
|
1759
2511
|
return insts;
|
|
1760
2512
|
}
|
|
1761
2513
|
}
|
|
1762
|
-
// src/node/build-pack.ts
|
|
2514
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/build-pack.ts
|
|
1763
2515
|
import fs3 from "node:fs";
|
|
1764
2516
|
import path3 from "node:path";
|
|
1765
2517
|
|
|
1766
|
-
// src/node/resolver.ts
|
|
2518
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/resolver.ts
|
|
1767
2519
|
import fs from "node:fs";
|
|
1768
2520
|
import path from "node:path";
|
|
1769
2521
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -2035,9 +2787,118 @@ function collectDeps(lib, refs) {
|
|
|
2035
2787
|
return out;
|
|
2036
2788
|
}
|
|
2037
2789
|
|
|
2038
|
-
// src/node/compile.ts
|
|
2790
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/compile.ts
|
|
2039
2791
|
import fs2 from "node:fs";
|
|
2040
2792
|
import path2 from "node:path";
|
|
2793
|
+
|
|
2794
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/lod.ts
|
|
2795
|
+
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
2796
|
+
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
2797
|
+
function reorderMesh(P, N, C, I) {
|
|
2798
|
+
const idx = Uint32Array.from(I);
|
|
2799
|
+
const n = P.length / 3;
|
|
2800
|
+
const [remap] = MeshoptEncoder.reorderMesh(idx, true, false);
|
|
2801
|
+
const P2 = new Float32Array(P.length), N2 = new Float32Array(N.length), C2 = new Float32Array(C.length);
|
|
2802
|
+
for (let v = 0;v < n; v++) {
|
|
2803
|
+
const r = remap[v];
|
|
2804
|
+
if (r === 4294967295)
|
|
2805
|
+
continue;
|
|
2806
|
+
P2[r * 3] = P[v * 3];
|
|
2807
|
+
P2[r * 3 + 1] = P[v * 3 + 1];
|
|
2808
|
+
P2[r * 3 + 2] = P[v * 3 + 2];
|
|
2809
|
+
N2[r * 3] = N[v * 3];
|
|
2810
|
+
N2[r * 3 + 1] = N[v * 3 + 1];
|
|
2811
|
+
N2[r * 3 + 2] = N[v * 3 + 2];
|
|
2812
|
+
for (let k = 0;k < 4; k++)
|
|
2813
|
+
C2[r * 4 + k] = C[v * 4 + k];
|
|
2814
|
+
}
|
|
2815
|
+
return { P: P2, N: N2, C: C2, I: idx };
|
|
2816
|
+
}
|
|
2817
|
+
var TARGETS = [0.25, 0.08];
|
|
2818
|
+
var MIN_TRIS = 64;
|
|
2819
|
+
function flatMesh(tris) {
|
|
2820
|
+
const map = new Map;
|
|
2821
|
+
const P = [], N = [], C = [], I = [];
|
|
2822
|
+
for (const { p, i: idx, col } of tris)
|
|
2823
|
+
for (let t = 0;t < idx.length; t += 3) {
|
|
2824
|
+
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
2825
|
+
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];
|
|
2826
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
2827
|
+
const l = Math.hypot(nx, ny, nz);
|
|
2828
|
+
if (!(l > 0.000000001))
|
|
2829
|
+
continue;
|
|
2830
|
+
nx /= l;
|
|
2831
|
+
ny /= l;
|
|
2832
|
+
nz /= l;
|
|
2833
|
+
for (const o of [a, b, c]) {
|
|
2834
|
+
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()}`;
|
|
2835
|
+
let j = map.get(k);
|
|
2836
|
+
if (j === undefined) {
|
|
2837
|
+
j = P.length / 3;
|
|
2838
|
+
map.set(k, j);
|
|
2839
|
+
P.push(p[o], p[o + 1], p[o + 2]);
|
|
2840
|
+
N.push(nx, ny, nz);
|
|
2841
|
+
C.push(...col);
|
|
2842
|
+
}
|
|
2843
|
+
I.push(j);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
return { P: new Float32Array(P), N: new Float32Array(N), C: new Float32Array(C), I: new Uint32Array(I) };
|
|
2847
|
+
}
|
|
2848
|
+
function lodChain(P, C, I) {
|
|
2849
|
+
const nTris = I.length / 3;
|
|
2850
|
+
if (nTris < MIN_TRIS)
|
|
2851
|
+
return [];
|
|
2852
|
+
const groups = new Map;
|
|
2853
|
+
for (let t = 0;t < I.length; t += 3) {
|
|
2854
|
+
const v = I[t] * 4;
|
|
2855
|
+
const col = [C[v], C[v + 1], C[v + 2], C[v + 3]];
|
|
2856
|
+
const k = col.join();
|
|
2857
|
+
let g = groups.get(k);
|
|
2858
|
+
if (!g)
|
|
2859
|
+
groups.set(k, g = { col, tri: [] });
|
|
2860
|
+
g.tri.push(I[t], I[t + 1], I[t + 2]);
|
|
2861
|
+
}
|
|
2862
|
+
const welded = [...groups.values()].map(({ col, tri }) => {
|
|
2863
|
+
const map = new Map;
|
|
2864
|
+
const pos = [];
|
|
2865
|
+
const idx = new Uint32Array(tri.length);
|
|
2866
|
+
for (let i = 0;i < tri.length; i++) {
|
|
2867
|
+
const o = tri[i] * 3;
|
|
2868
|
+
const k = `${P[o].toFixed(3)},${P[o + 1].toFixed(3)},${P[o + 2].toFixed(3)}`;
|
|
2869
|
+
let j = map.get(k);
|
|
2870
|
+
if (j === undefined) {
|
|
2871
|
+
j = pos.length / 3;
|
|
2872
|
+
map.set(k, j);
|
|
2873
|
+
pos.push(P[o], P[o + 1], P[o + 2]);
|
|
2874
|
+
}
|
|
2875
|
+
idx[i] = j;
|
|
2876
|
+
}
|
|
2877
|
+
return { col, p: new Float32Array(pos), i: idx };
|
|
2878
|
+
});
|
|
2879
|
+
const out = [];
|
|
2880
|
+
let prevTris = nTris;
|
|
2881
|
+
for (let li = 0;li < TARGETS.length; li++) {
|
|
2882
|
+
let err = 0;
|
|
2883
|
+
const parts = [];
|
|
2884
|
+
for (const g of welded) {
|
|
2885
|
+
const target = Math.max(3, Math.floor(g.i.length * TARGETS[li] / 3) * 3);
|
|
2886
|
+
const [idx, e] = MeshoptSimplifier.simplify(g.i, g.p, 3, target, 1e9, li ? ["ErrorAbsolute", "Prune"] : ["ErrorAbsolute"]);
|
|
2887
|
+
err = Math.max(err, e);
|
|
2888
|
+
if (idx.length)
|
|
2889
|
+
parts.push({ p: g.p, i: idx, col: g.col });
|
|
2890
|
+
}
|
|
2891
|
+
const m = flatMesh(parts);
|
|
2892
|
+
const t = m.I.length / 3;
|
|
2893
|
+
if (t > prevTris * 0.7 || !t)
|
|
2894
|
+
continue;
|
|
2895
|
+
out.push({ ...m, err: +Math.max(err, 0.001).toFixed(3) });
|
|
2896
|
+
prevTris = t;
|
|
2897
|
+
}
|
|
2898
|
+
return out;
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/compile.ts
|
|
2041
2902
|
function loadColors(root) {
|
|
2042
2903
|
const map = new Map;
|
|
2043
2904
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -2454,7 +3315,8 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2454
3315
|
return r;
|
|
2455
3316
|
};
|
|
2456
3317
|
let lastPos = [];
|
|
2457
|
-
|
|
3318
|
+
let anyLod = false;
|
|
3319
|
+
const bucket = (b, lod = false) => {
|
|
2458
3320
|
const n = b.pos.length / 3;
|
|
2459
3321
|
lastPos = [];
|
|
2460
3322
|
if (!n)
|
|
@@ -2493,9 +3355,20 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2493
3355
|
}
|
|
2494
3356
|
I.push(j);
|
|
2495
3357
|
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
3358
|
+
let m = { P, N, C, I };
|
|
3359
|
+
if (options.reorder && I.length >= 3)
|
|
3360
|
+
m = reorderMesh(P, N, C, I);
|
|
3361
|
+
const vcount = m.P.length / 3;
|
|
3362
|
+
lastPos = m.P;
|
|
3363
|
+
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 };
|
|
3364
|
+
if (lod && options.lod) {
|
|
3365
|
+
const chain = lodChain(P, C, I).map((l) => options.reorder ? { ...l, ...reorderMesh(l.P, l.N, l.C, l.I) } : l);
|
|
3366
|
+
if (chain.length) {
|
|
3367
|
+
anyLod = true;
|
|
3368
|
+
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 }));
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
return out;
|
|
2499
3372
|
};
|
|
2500
3373
|
let anyCond = false;
|
|
2501
3374
|
const condl = (a, pools) => {
|
|
@@ -2586,18 +3459,18 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2586
3459
|
});
|
|
2587
3460
|
return { tbody: bucket(c.tbody), tex };
|
|
2588
3461
|
};
|
|
2589
|
-
const enc = (c) => {
|
|
2590
|
-
const body = bucket(c.body), bodyP = lastPos, under = bucket(c.under), underP = lastPos;
|
|
3462
|
+
const enc = (c, lod = false) => {
|
|
3463
|
+
const body = bucket(c.body, lod), bodyP = lastPos, under = bucket(c.under, lod), underP = lastPos;
|
|
2591
3464
|
const edges = c.edges.length ? put(new Float32Array(c.edges)) : null;
|
|
2592
3465
|
const condlB = condl(c.cond, [bodyP, underP, c.edges]), condlU = condl(c.condUnder, [bodyP, underP, c.edges]);
|
|
2593
3466
|
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
3467
|
};
|
|
2595
|
-
const encParts = Object.fromEntries([...parts].map(([k, c]) => [k, enc(c)])), encKinds = Object.fromEntries([...studKinds].map(([k, c]) => [k, enc(c)]));
|
|
3468
|
+
const encParts = Object.fromEntries([...parts].map(([k, c]) => [k, enc(c, true)])), encKinds = Object.fromEntries([...studKinds].map(([k, c]) => [k, enc(c)]));
|
|
2596
3469
|
const textures = texNames.map((name) => {
|
|
2597
3470
|
const b = options.texture?.(name);
|
|
2598
3471
|
return b ? { name, mime: "image/png", data: put(b) } : { name, missing: true };
|
|
2599
3472
|
});
|
|
2600
|
-
const features = [...anyCond ? ["cond"] : [], ...texNames.length ? ["tex"] : []];
|
|
3473
|
+
const features = [...anyCond ? ["cond"] : [], ...texNames.length ? ["tex"] : [], ...anyLod ? ["lod"] : []];
|
|
2601
3474
|
const header = { version: features.length ? 2 : 1, ...features.length ? { features } : {}, weld, parts: encParts, studKinds: encKinds, ...texNames.length ? { textures } : {}, ...extra };
|
|
2602
3475
|
const hj = new TextEncoder().encode(JSON.stringify(header));
|
|
2603
3476
|
const hpad = (4 - (4 + hj.length) % 4) % 4;
|
|
@@ -2608,7 +3481,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2608
3481
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
2609
3482
|
}
|
|
2610
3483
|
|
|
2611
|
-
// src/node/build-pack.ts
|
|
3484
|
+
// ../../../../../../../tmp/ldr-build-pIke9r/src/node/build-pack.ts
|
|
2612
3485
|
function buildPack(o) {
|
|
2613
3486
|
const lib = new Library2(o.ldrawRoot);
|
|
2614
3487
|
const refs = new Map;
|
|
@@ -2668,10 +3541,11 @@ function buildPack(o) {
|
|
|
2668
3541
|
return b ? new Uint8Array(Buffer.from(b, "base64")) : comp.texture(n);
|
|
2669
3542
|
};
|
|
2670
3543
|
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 } : {} };
|
|
3544
|
+
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
3545
|
}
|
|
2673
3546
|
export {
|
|
2674
3547
|
Compiler,
|
|
3548
|
+
DEFAULT_PARTS_CDN,
|
|
2675
3549
|
I as IDENTITY,
|
|
2676
3550
|
Library,
|
|
2677
3551
|
Library2 as ResolverLibrary,
|
|
@@ -2685,6 +3559,7 @@ export {
|
|
|
2685
3559
|
createInstancedConditionalEdges,
|
|
2686
3560
|
createInstancedEdges,
|
|
2687
3561
|
createLdrObject,
|
|
3562
|
+
cullCore,
|
|
2688
3563
|
decodePack,
|
|
2689
3564
|
decompressPack,
|
|
2690
3565
|
encodePack,
|
|
@@ -2692,16 +3567,21 @@ export {
|
|
|
2692
3567
|
fileStepViews,
|
|
2693
3568
|
flatten,
|
|
2694
3569
|
flatten2 as flattenWithLibrary,
|
|
3570
|
+
forEachStud,
|
|
2695
3571
|
hash32,
|
|
2696
3572
|
invert,
|
|
2697
3573
|
isDirectColor,
|
|
2698
3574
|
loadColors,
|
|
3575
|
+
loadModel,
|
|
2699
3576
|
loadPack,
|
|
3577
|
+
loadParts,
|
|
3578
|
+
loadPartsIndex,
|
|
2700
3579
|
looseFile,
|
|
2701
3580
|
loosePartName,
|
|
2702
3581
|
looseSource,
|
|
2703
3582
|
looseSteps,
|
|
2704
3583
|
makeMaterial,
|
|
3584
|
+
mergePacks,
|
|
2705
3585
|
mul,
|
|
2706
3586
|
norm,
|
|
2707
3587
|
parse,
|