@adatechnology/game-floorplan-three 0.9.3 → 0.10.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/dist/{chunk-QUVGWVEC.js → chunk-Y3Y7NYOL.js} +547 -317
- package/dist/chunk-Y3Y7NYOL.js.map +1 -0
- package/dist/index.d.ts +100 -36
- package/dist/index.global.js +1232 -386
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +42 -6
- package/dist/index.js.map +1 -1
- package/dist/testing-BK7QmoUq.d.ts +1611 -0
- package/dist/testing.d.ts +12 -1
- package/dist/testing.js +1 -1
- package/package.json +24 -10
- package/dist/chunk-QUVGWVEC.js.map +0 -1
- package/dist/testing-ikPy2Nxl.d.ts +0 -379
package/dist/index.global.js
CHANGED
|
@@ -3,6 +3,7 @@ var GameFloorplanThree = (() => {
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
7
|
var __export = (target, all) => {
|
|
7
8
|
for (var name in all)
|
|
8
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -16,6 +17,7 @@ var GameFloorplanThree = (() => {
|
|
|
16
17
|
return to;
|
|
17
18
|
};
|
|
18
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
19
21
|
|
|
20
22
|
// src/index.ts
|
|
21
23
|
var index_exports = {};
|
|
@@ -70,7 +72,7 @@ var GameFloorplanThree = (() => {
|
|
|
70
72
|
shade: () => shade
|
|
71
73
|
});
|
|
72
74
|
|
|
73
|
-
// ../game-shapes/dist/chunk-
|
|
75
|
+
// ../game-shapes/dist/chunk-FZQTELDQ.js
|
|
74
76
|
function canonicalJson(value) {
|
|
75
77
|
if (value === null) return "null";
|
|
76
78
|
if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
@@ -982,17 +984,19 @@ var GameFloorplanThree = (() => {
|
|
|
982
984
|
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
|
|
983
985
|
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
|
|
984
986
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
987
|
+
var Node = class {
|
|
988
|
+
constructor(i, x, y) {
|
|
989
|
+
this.i = i;
|
|
990
|
+
this.x = x;
|
|
991
|
+
this.y = y;
|
|
992
|
+
this.prev = null;
|
|
993
|
+
this.next = null;
|
|
994
|
+
this.z = 0;
|
|
995
|
+
this.prevZ = null;
|
|
996
|
+
this.nextZ = null;
|
|
997
|
+
this.steiner = false;
|
|
998
|
+
}
|
|
999
|
+
};
|
|
996
1000
|
function signedArea(data, start, end, dim) {
|
|
997
1001
|
let sum = 0;
|
|
998
1002
|
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
@@ -1817,6 +1821,9 @@ var GameFloorplanThree = (() => {
|
|
|
1817
1821
|
return mesh2;
|
|
1818
1822
|
});
|
|
1819
1823
|
}
|
|
1824
|
+
function isMesh(o) {
|
|
1825
|
+
return !!o && o.isMesh === true;
|
|
1826
|
+
}
|
|
1820
1827
|
|
|
1821
1828
|
// ../game-props3d/dist/index.js
|
|
1822
1829
|
function rng(seed) {
|
|
@@ -3691,6 +3698,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3691
3698
|
const WITH_MAP = { roughcast: 1, block: 1 };
|
|
3692
3699
|
class Accumulator {
|
|
3693
3700
|
constructor() {
|
|
3701
|
+
__publicField(this, "cv");
|
|
3702
|
+
__publicField(this, "ci");
|
|
3703
|
+
__publicField(this, "p");
|
|
3704
|
+
__publicField(this, "n");
|
|
3705
|
+
__publicField(this, "c");
|
|
3706
|
+
__publicField(this, "u");
|
|
3707
|
+
__publicField(this, "i");
|
|
3708
|
+
__publicField(this, "nv");
|
|
3709
|
+
__publicField(this, "ni");
|
|
3710
|
+
__publicField(this, "lim");
|
|
3711
|
+
__publicField(this, "cur");
|
|
3712
|
+
__publicField(this, "piece0");
|
|
3713
|
+
__publicField(this, "mat", "");
|
|
3714
|
+
__publicField(this, "group", "");
|
|
3694
3715
|
this.cv = 2048;
|
|
3695
3716
|
this.ci = 3072;
|
|
3696
3717
|
this.p = new Float32Array(this.cv * 3);
|
|
@@ -3753,7 +3774,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3753
3774
|
g.position.copy(u.pose0.p);
|
|
3754
3775
|
g.quaternion.copy(u.pose0.q);
|
|
3755
3776
|
g.scale.copy(u.pose0.s);
|
|
3756
|
-
const
|
|
3777
|
+
const [ax, ay, az] = a.axis || [0, 1, 0];
|
|
3778
|
+
const e = new THREE.Vector3(ax, ay, az);
|
|
3757
3779
|
if (a.type === "swing" || a.type === "toggle") g.rotateOnAxis(e, (a.angle || 0) * t);
|
|
3758
3780
|
else if (a.type === "slide") g.translateOnAxis(e, (a.dist || 0) * t);
|
|
3759
3781
|
else if (a.type === "scale") {
|
|
@@ -3848,7 +3870,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3848
3870
|
}
|
|
3849
3871
|
if (uvr) {
|
|
3850
3872
|
let gu = G.u[k * 2], gv = G.u[k * 2 + 1];
|
|
3851
|
-
for (let r = uvr.rot | 0; r > 0; r--) {
|
|
3873
|
+
for (let r = (uvr.rot ?? 0) | 0; r > 0; r--) {
|
|
3852
3874
|
const t = gu;
|
|
3853
3875
|
gu = gv;
|
|
3854
3876
|
gv = 1 - t;
|
|
@@ -3946,14 +3968,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3946
3968
|
A.nv += n;
|
|
3947
3969
|
}
|
|
3948
3970
|
let bxImpl = bxBase;
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
K.getBx = () => bxImpl;
|
|
3953
|
-
K.setBx = (f) => {
|
|
3971
|
+
const bx = (...a) => bxImpl(...a);
|
|
3972
|
+
const getBx = () => bxImpl;
|
|
3973
|
+
const setBx = (f) => {
|
|
3954
3974
|
bxImpl = f;
|
|
3955
3975
|
};
|
|
3956
|
-
|
|
3976
|
+
const defined = { GEO, UV_SCALE, WITH_MAP, Accumulator, cursor, PARTS, MIRRORS, part, applyPart, _Y, _qa, _qb, pieceRecord, structurePiece, accFor, _q, _e, _col, rgbOf, put, boxC, bx, getBx, setBx, cylBase, polyFace };
|
|
3977
|
+
Object.assign(K, defined);
|
|
3957
3978
|
}
|
|
3958
3979
|
|
|
3959
3980
|
// src/kernel/noise.ts
|
|
@@ -3971,17 +3992,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3971
3992
|
const n = 0.5 * vnoise(x / 5.5, z / 5.5) + 0.32 * vnoise(x / 1.9 + 31, z / 1.9) + 0.18 * vnoise(x / 0.8 + 7, z / 0.8), m = vnoise(x / 9 + 100, z / 9 + 50) - 0.5, f = 0.76 + 0.5 * n;
|
|
3972
3993
|
return type === "dirt" ? [f * (1 + 0.14 * m), f * (1 + 0.03 * m), f * (1 - 0.18 * m)] : [f * (1 + 0.1 * m), f * (1 + 0.05 * m), f * (1 - 0.1 * m)];
|
|
3973
3994
|
}
|
|
3974
|
-
|
|
3995
|
+
const defined = { _h2, vnoise, macroGround };
|
|
3996
|
+
Object.assign(K, defined);
|
|
3975
3997
|
}
|
|
3976
3998
|
|
|
3977
3999
|
// src/materials/textures.ts
|
|
3978
4000
|
function installMaterialsTextures(K, _shared) {
|
|
3979
4001
|
const { DOC, THREE, cfg } = K;
|
|
3980
4002
|
function texture(n, f, rep = true, rx = 1, ry = 1) {
|
|
4003
|
+
if (!DOC) throw new Error("game-floorplan-three: the procedural textures need a document (options.document)");
|
|
3981
4004
|
const c = DOC.createElement("canvas");
|
|
3982
4005
|
c.width = n;
|
|
3983
4006
|
c.height = n;
|
|
3984
4007
|
const g = c.getContext("2d");
|
|
4008
|
+
if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
|
|
3985
4009
|
f(g, n);
|
|
3986
4010
|
const t = new THREE.CanvasTexture(c);
|
|
3987
4011
|
t.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -4100,10 +4124,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4100
4124
|
const TEX = {};
|
|
4101
4125
|
for (const k of Object.keys(TEXGEN)) TEX[k] = cfg.textures && cfg.textures[k] || TEXGEN[k]();
|
|
4102
4126
|
const ATLAS = {};
|
|
4103
|
-
|
|
4127
|
+
const defined = { texture, rngTexture, TEXGEN, TEX, ATLAS };
|
|
4128
|
+
Object.assign(K, defined);
|
|
4104
4129
|
}
|
|
4105
4130
|
|
|
4106
4131
|
// src/materials/materials.ts
|
|
4132
|
+
function context2d(c) {
|
|
4133
|
+
const g = c.getContext("2d");
|
|
4134
|
+
if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
|
|
4135
|
+
return g;
|
|
4136
|
+
}
|
|
4107
4137
|
function installMaterialsMaterials(K, _shared) {
|
|
4108
4138
|
const { THREE, cfg, ATLAS, TEX, rngTexture } = K;
|
|
4109
4139
|
function createMaterials(props) {
|
|
@@ -4115,7 +4145,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4115
4145
|
return t;
|
|
4116
4146
|
};
|
|
4117
4147
|
if (!(cfg.atlas && cfg.atlas.floorKind)) {
|
|
4118
|
-
const pc = props.atlas("floor").canvas, g = pc
|
|
4148
|
+
const pc = props.atlas("floor").canvas, g = context2d(pc);
|
|
4119
4149
|
for (const c of [0, 1]) {
|
|
4120
4150
|
g.save();
|
|
4121
4151
|
g.globalCompositeOperation = "screen";
|
|
@@ -4130,7 +4160,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4130
4160
|
g.restore();
|
|
4131
4161
|
}
|
|
4132
4162
|
if (!(cfg.atlas && cfg.atlas.floorKind)) {
|
|
4133
|
-
const pc = props.atlas("floor").canvas, g = pc
|
|
4163
|
+
const pc = props.atlas("floor").canvas, g = context2d(pc);
|
|
4134
4164
|
g.save();
|
|
4135
4165
|
g.fillStyle = "rgba(128,92,62,0.52)";
|
|
4136
4166
|
g.fillRect(256, 256, 256, 256);
|
|
@@ -4227,7 +4257,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4227
4257
|
}
|
|
4228
4258
|
const ORDER = { glass: 3, water: 2, screen: 3, building: 4 };
|
|
4229
4259
|
const NO_SHADOW = /* @__PURE__ */ new Set(["dirt", "glass", "water", "screen", "building", "picture", "floor", "emissive"]);
|
|
4230
|
-
|
|
4260
|
+
const defined = { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW };
|
|
4261
|
+
Object.assign(K, defined);
|
|
4231
4262
|
}
|
|
4232
4263
|
|
|
4233
4264
|
// src/kernel/close-scene.ts
|
|
@@ -4238,15 +4269,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4238
4269
|
const assembleVegetation = (...a) => K.assembleVegetation(...a);
|
|
4239
4270
|
function markMesh(m, A) {
|
|
4240
4271
|
const L = A.lim, fx = [];
|
|
4272
|
+
const pieces = shared.ctx.pieces;
|
|
4241
4273
|
for (let k = 0; k < L.length; k++) {
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4274
|
+
const lim = L[k], pc = lim.pc;
|
|
4275
|
+
if (!pc) continue;
|
|
4276
|
+
const next = L[k + 1];
|
|
4277
|
+
const v1 = next ? next.v : A.nv, i1 = next ? next.i : A.ni;
|
|
4278
|
+
if (v1 > lim.v) fx.push({ id: pc.id, v0: lim.v, v1, i0: lim.i, i1 });
|
|
4245
4279
|
}
|
|
4246
4280
|
if (!fx.length) return;
|
|
4247
4281
|
const u = m.userData, ids = [...new Set(fx.map((f) => f.id))], weight = {};
|
|
4248
4282
|
for (const f of fx) {
|
|
4249
|
-
const mt =
|
|
4283
|
+
const mt = pieces.get(f.id).mat;
|
|
4250
4284
|
weight[mt] = (weight[mt] || 0) + f.v1 - f.v0;
|
|
4251
4285
|
}
|
|
4252
4286
|
u.ranges = fx;
|
|
@@ -4254,7 +4288,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4254
4288
|
u.destructionMaterial = Object.keys(weight).sort((a, b) => weight[b] - weight[a])[0];
|
|
4255
4289
|
if (ids.length === 1) {
|
|
4256
4290
|
u.destructionPart = ids[0];
|
|
4257
|
-
const pc =
|
|
4291
|
+
const pc = pieces.get(ids[0]);
|
|
4258
4292
|
if (pc.role) u.structuralRole = pc.role;
|
|
4259
4293
|
}
|
|
4260
4294
|
}
|
|
@@ -4305,7 +4339,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4305
4339
|
assembleVegetation(groups);
|
|
4306
4340
|
return groups;
|
|
4307
4341
|
}
|
|
4308
|
-
|
|
4342
|
+
const defined = { markMesh, closeScene };
|
|
4343
|
+
Object.assign(K, defined);
|
|
4309
4344
|
}
|
|
4310
4345
|
|
|
4311
4346
|
// src/house/helpers.ts
|
|
@@ -4343,8 +4378,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4343
4378
|
for (const h of holes) L = L.flatMap((r) => subRect(r, h));
|
|
4344
4379
|
return L;
|
|
4345
4380
|
}
|
|
4346
|
-
const wallColor = (c) =>
|
|
4347
|
-
|
|
4381
|
+
const wallColor = (c) => {
|
|
4382
|
+
const k = c && c.color ? colorOf(c.color.wall) : null;
|
|
4383
|
+
return k != null ? k : 14999768;
|
|
4384
|
+
};
|
|
4385
|
+
const floorColor = (c) => {
|
|
4386
|
+
const k = c && c.color ? colorOf(c.color.floor) : null;
|
|
4387
|
+
return k != null ? k : 11577496;
|
|
4388
|
+
};
|
|
4348
4389
|
function stairFootprint(m) {
|
|
4349
4390
|
const c = Math.cos(m.ry), s = Math.sin(m.ry), pts = [[-m.w / 2, -m.d / 2], [m.w / 2, -m.d / 2], [m.w / 2, m.d / 2], [-m.w / 2, m.d / 2]].map(([a, b]) => [m.x + a * c + b * s, m.z - a * s + b * c]);
|
|
4350
4391
|
return [Math.min(...pts.map((p) => p[0])), Math.min(...pts.map((p) => p[1])), Math.max(...pts.map((p) => p[0])), Math.max(...pts.map((p) => p[1]))];
|
|
@@ -4355,12 +4396,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4355
4396
|
const pitch = A[f + 1].y0 - A[f].y0;
|
|
4356
4397
|
return h > pitch && h - pitch <= 0.45 ? pitch : h;
|
|
4357
4398
|
}
|
|
4358
|
-
|
|
4399
|
+
const defined = { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES3, NO_CEILING, OPEN_AREA, EPS: EPS3, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight };
|
|
4400
|
+
Object.assign(K, defined);
|
|
4359
4401
|
}
|
|
4360
4402
|
|
|
4361
4403
|
// src/house/walls.ts
|
|
4362
4404
|
function installHouseWalls(K, shared) {
|
|
4363
4405
|
const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
|
|
4406
|
+
const sh = (...a) => K.sh(...a);
|
|
4364
4407
|
function wallBox2(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
|
|
4365
4408
|
if (yb - ya < 1e-4 || b - a < 1e-4) return;
|
|
4366
4409
|
if (alongU) {
|
|
@@ -4404,8 +4447,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4404
4447
|
function walls() {
|
|
4405
4448
|
const R = shared.ctx.r, cut = shared.ctx.cut, nA = R.floors.length, vMin = Math.min(...R.walls.map((w) => w.axis === "u" ? w.v0 : Math.min(w.v0, w.v1)));
|
|
4406
4449
|
const corners = /* @__PURE__ */ new Map();
|
|
4450
|
+
const looks = /* @__PURE__ */ new Map();
|
|
4407
4451
|
for (const w of R.walls) {
|
|
4408
|
-
const f = w.floor;
|
|
4452
|
+
const f = w.floor, colliders = shared.ctx.colliders;
|
|
4409
4453
|
cursor.group = "f" + f;
|
|
4410
4454
|
cursor.pc = pieceOf(w);
|
|
4411
4455
|
const y0 = Y0(f), pitch = f + 1 < nA ? Y0(f + 1) - y0 : Infinity, th = w.thickness || 0.15, alongU = w.axis === "u";
|
|
@@ -4413,7 +4457,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4413
4457
|
const hh = cut ? Math.min(h, 1.2) : h, L = alongU ? w.v0 : w.u0, s0 = Math.min(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1), s1 = Math.max(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1);
|
|
4414
4458
|
const front = alongU && Math.abs(L - vMin) < 0.05;
|
|
4415
4459
|
const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
|
|
4416
|
-
|
|
4460
|
+
if (w.id) {
|
|
4461
|
+
const face = sideL.exterior ? sideL : sideH;
|
|
4462
|
+
looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
|
|
4463
|
+
}
|
|
4464
|
+
colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
|
|
4417
4465
|
if (w.type === "railing") {
|
|
4418
4466
|
const c0 = shared.ctx.colors.metal != null ? shared.ctx.colors.metal : 9080466;
|
|
4419
4467
|
const sx = alongU ? 1 : 0, sz = alongU ? 0 : 1, len = s1 - s0, n = Math.max(1, Math.round(len / 1.4));
|
|
@@ -4459,8 +4507,28 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4459
4507
|
cursor.group = "f" + e.f;
|
|
4460
4508
|
bx(e.color.mat, e.pu - e.th / 2, e.y0, e.pv - e.th / 2, e.pu + e.th / 2, e.y0 + e.hh, e.pv + e.th / 2, e.color.color);
|
|
4461
4509
|
}
|
|
4510
|
+
if (shared.ctx.showPillars) wallPillars(looks);
|
|
4511
|
+
}
|
|
4512
|
+
const PILLAR_IN_WALL = /^(wall_column_|column_\d|jamb_column_)/;
|
|
4513
|
+
const wallOf = (pillar, parts) => {
|
|
4514
|
+
const u = (pillar.aabb[0] + pillar.aabb[2]) / 2, v = (pillar.aabb[1] + pillar.aabb[3]) / 2;
|
|
4515
|
+
return parts.find((q) => (q.role === "wall" || q.role === "partition") && q.assembly !== void 0 && q.floor === pillar.floor && u >= q.aabb[0] - 1e-3 && u <= q.aabb[2] + 1e-3 && v >= q.aabb[1] - 1e-3 && v <= q.aabb[3] + 1e-3);
|
|
4516
|
+
};
|
|
4517
|
+
function wallPillars(looks) {
|
|
4518
|
+
const parts = Object.values(shared.ctx.structureIndex);
|
|
4519
|
+
for (const e of parts) {
|
|
4520
|
+
if (e.role !== "column" || !PILLAR_IN_WALL.test(e.id)) continue;
|
|
4521
|
+
const host = wallOf(e, parts);
|
|
4522
|
+
const look = host && looks.get(host.id);
|
|
4523
|
+
if (!host || !look) continue;
|
|
4524
|
+
cursor.group = "f" + e.floor;
|
|
4525
|
+
cursor.pc = structurePiece(host.id);
|
|
4526
|
+
bx(look.mat, e.aabb[0], e.y0, e.aabb[1], e.aabb[2], Math.min(e.y1, look.top), e.aabb[3], sh(look.color != null ? look.color : 15262420, 0.93));
|
|
4527
|
+
}
|
|
4528
|
+
cursor.pc = null;
|
|
4462
4529
|
}
|
|
4463
|
-
|
|
4530
|
+
const defined = { wallBox: wallBox2, sideOf, pieceOf, nearestWall, walls, wallPillars };
|
|
4531
|
+
Object.assign(K, defined);
|
|
4464
4532
|
}
|
|
4465
4533
|
|
|
4466
4534
|
// src/house/doors.ts
|
|
@@ -4479,7 +4547,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4479
4547
|
}
|
|
4480
4548
|
shared.doorState = /* @__PURE__ */ new Map();
|
|
4481
4549
|
function doors() {
|
|
4482
|
-
shared.ctx.leaves = [];
|
|
4550
|
+
const leaves = shared.ctx.leaves = [], doorState = shared.doorState, colliders = shared.ctx.colliders;
|
|
4483
4551
|
const R = shared.ctx.r, cut = shared.ctx.cut, C = shared.ctx.colors, wood = C.wood != null ? C.wood : 8016948, frame2 = sh(wood, 0.55);
|
|
4484
4552
|
for (const p of R.doors) {
|
|
4485
4553
|
const f = p.floor;
|
|
@@ -4510,21 +4578,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4510
4578
|
}
|
|
4511
4579
|
const leaf = (u0, u1, y_0, y_1, tt, color2, mat = "wood") => alongU ? bx(mat, u0, y0 + y_0, L - tt / 2, u1, y0 + y_1, L + tt / 2, color2) : bx(mat, L - tt / 2, y0 + y_0, u0, L + tt / 2, y0 + y_1, u1, color2);
|
|
4512
4580
|
const extC = wood;
|
|
4513
|
-
const open0 = p.blocked ? false :
|
|
4514
|
-
|
|
4581
|
+
const open0 = p.blocked ? false : doorState.has(p.id) ? doorState.get(p.id) === true : !!p.open;
|
|
4582
|
+
doorState.set(p.id, open0);
|
|
4515
4583
|
const dc = alongU ? [p.at, L] : [L, p.at];
|
|
4516
|
-
const fo = { id: p.id, floor: f, type: p.model === "steel" ? "steel" : "swing", open: open0, t: open0 ? 1 : 0, blockedFlag: !!p.blocked, locked: R.state === "fortified" && !!p.exterior, handleNames: [], hT: 0, cx: dc[0], cz: dc[1], visH, groups: [], col: null };
|
|
4584
|
+
const fo = { id: p.id, floor: f, type: p.model === "steel" ? "steel" : "swing", open: open0, t: open0 ? 1 : 0, blockedFlag: !!p.blocked, locked: R.state === "fortified" && !!p.exterior, handleNames: [], hT: 0, cx: dc[0], cz: dc[1], visH, groups: [], gs: [], col: null };
|
|
4517
4585
|
const colR = { type: "door", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b, off: open0 };
|
|
4518
|
-
|
|
4586
|
+
colliders.push(colR);
|
|
4519
4587
|
fo.col = colR;
|
|
4520
4588
|
const leafBox = (hu, d0, d1, y_0, y_1, tt, color2, mat) => alongU ? bx(mat, d0, y_0, -tt / 2, d1, y_1, tt / 2, color2) : bx(mat, -tt / 2, y_0, d0, tt / 2, y_1, d1, color2);
|
|
4521
|
-
const
|
|
4589
|
+
const newGroup2 = (k, hu, topY) => {
|
|
4522
4590
|
cursor.group = "dyn:" + p.id + ":" + k;
|
|
4523
4591
|
fo.groups.push({ name: cursor.group, pos: alongU ? [hu, topY != null ? y0 + topY : y0, L] : [L, topY != null ? y0 + topY : y0, hu] });
|
|
4524
4592
|
};
|
|
4525
4593
|
if (p.model === "steel") {
|
|
4526
|
-
const light = [14276044, 13223615, 14999766], pal = ((R.seed | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
|
|
4527
|
-
|
|
4594
|
+
const light = [14276044, 13223615, 14999766], pal = ((Number(R.seed) | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
|
|
4595
|
+
newGroup2(0, mid, visH);
|
|
4528
4596
|
const la = a + jw - mid, lb = b - jw - mid, nSec = Math.max(4, Math.round(visH / 0.5)), hs = visH / nSec, grv = sh(color2, 0.55);
|
|
4529
4597
|
leafBox(0, la, lb, -visH, 0, 0.05, color2, "metal");
|
|
4530
4598
|
for (let k = 1; k < nSec; k++) leafBox(0, la, lb, -k * hs - 0.012, -k * hs + 0.012, 0.07, grv, "metal");
|
|
@@ -4539,7 +4607,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4539
4607
|
for (let k = 0; k < nf; k++) {
|
|
4540
4608
|
const u0 = nf === 2 ? k ? (aa + bb) / 2 : aa : aa, u1 = nf === 2 ? k ? bb : (aa + bb) / 2 : bb, color2 = p.exterior ? extC : wood;
|
|
4541
4609
|
const hingeAt = nf === 2 ? k ? u1 : u0 : p.hinge === "end" ? u1 : u0, dir = hingeAt === u0 ? 1 : -1, len = u1 - u0;
|
|
4542
|
-
|
|
4610
|
+
newGroup2(k, hingeAt);
|
|
4543
4611
|
const d0 = dir > 0 ? 5e-3 : -len + 5e-3, d1 = dir > 0 ? len - 5e-3 : -5e-3;
|
|
4544
4612
|
leafBox(hingeAt, d0, d1, 0, visH, 0.04, color2, PMAT);
|
|
4545
4613
|
{
|
|
@@ -4575,7 +4643,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4575
4643
|
fo.rot = Math.atan2(n[0] * A[1] - n[1] * A[0], A[0] * n[0] + A[1] * n[1]);
|
|
4576
4644
|
}
|
|
4577
4645
|
}
|
|
4578
|
-
|
|
4646
|
+
leaves.push(fo);
|
|
4579
4647
|
cursor.group = "f" + f;
|
|
4580
4648
|
if (p.blocked) {
|
|
4581
4649
|
part("window_boards", [0, 0, 0], () => {
|
|
@@ -4603,11 +4671,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4603
4671
|
}
|
|
4604
4672
|
}
|
|
4605
4673
|
}, { id: "boards:" + p.id }, "f" + f);
|
|
4606
|
-
|
|
4674
|
+
colliders.push({ type: "board", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b });
|
|
4607
4675
|
}
|
|
4608
4676
|
}
|
|
4609
4677
|
}
|
|
4610
|
-
|
|
4678
|
+
const defined = { doorLineSides, doors };
|
|
4679
|
+
Object.assign(K, defined);
|
|
4611
4680
|
}
|
|
4612
4681
|
|
|
4613
4682
|
// src/house/windows.ts
|
|
@@ -4667,7 +4736,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4667
4736
|
}
|
|
4668
4737
|
}
|
|
4669
4738
|
}
|
|
4670
|
-
|
|
4739
|
+
const defined = { FRAME_COLORS, SILL_COLORS, windows };
|
|
4740
|
+
Object.assign(K, defined);
|
|
4671
4741
|
}
|
|
4672
4742
|
|
|
4673
4743
|
// src/house/floors.ts
|
|
@@ -4677,7 +4747,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4677
4747
|
if (shared.ctx._flights && shared.ctx._flights.r === shared.ctx.r) return shared.ctx._flights.l;
|
|
4678
4748
|
const R = shared.ctx.r, mp = /* @__PURE__ */ new Map();
|
|
4679
4749
|
for (const m of R.items) {
|
|
4680
|
-
if (m.type !== "stairs" || !m.link) continue;
|
|
4750
|
+
if (m.type !== "stairs" || !m.link || typeof m.link !== "object") continue;
|
|
4681
4751
|
const k = [m.link.from, m.link.to, m.x.toFixed(2), m.z.toFixed(2), (m.ry || 0).toFixed(2)].join("|");
|
|
4682
4752
|
if (!mp.has(k)) mp.set(k, { m, from: m.link.from, to: m.link.to, rect: stairFootprint(m) });
|
|
4683
4753
|
}
|
|
@@ -4696,7 +4766,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4696
4766
|
}
|
|
4697
4767
|
const panelRects = (p) => p.footprint && p.footprint.length ? p.footprint : [p.aabb];
|
|
4698
4768
|
function tilesOf(parent, rc) {
|
|
4699
|
-
const ps = parent
|
|
4769
|
+
const ps = parent ? shared.ctx.panelsOf && shared.ctx.panelsOf.get(parent) : void 0;
|
|
4700
4770
|
if (!ps) return [[parent ? structurePiece(parent) : null, rc]];
|
|
4701
4771
|
const out = [], taken = [];
|
|
4702
4772
|
for (const p of ps) for (const q of panelRects(p)) {
|
|
@@ -4760,13 +4830,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4760
4830
|
const { rectsOf: rectsOf2, Y0, boxC, bx, cursor, flights, stairFootprint, structurePiece } = K;
|
|
4761
4831
|
const sh = (...a) => K.sh(...a);
|
|
4762
4832
|
function buildStairs() {
|
|
4763
|
-
const R = shared.ctx.r;
|
|
4764
|
-
shared.ctx.stairs = [];
|
|
4833
|
+
const R = shared.ctx.r, stairs = shared.ctx.stairs = [];
|
|
4765
4834
|
for (const vo of flights()) {
|
|
4766
4835
|
const m = vo.m, f = vo.from, Dr = m.d - (vo.LP || 0);
|
|
4767
4836
|
cursor.group = "f" + f;
|
|
4768
4837
|
cursor.pc = structurePiece("stairs_" + vo.from + "_" + vo.to);
|
|
4769
|
-
const y0 = Y0(f), H = Y0(
|
|
4838
|
+
const y0 = Y0(f), H = Y0(vo.to) - y0, n = Math.max(8, Math.round(H / 0.18)), c = Math.cos(m.ry), s = Math.sin(m.ry);
|
|
4770
4839
|
const wood = shared.ctx.colors.wood != null ? shared.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
|
|
4771
4840
|
const P = (lx, lz) => [m.x + lx * c + lz * s, m.z - lx * s + lz * c];
|
|
4772
4841
|
const boxL = (mat, lx, y, lz, w, h, d, color2, rx = 0) => {
|
|
@@ -4789,7 +4858,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4789
4858
|
}
|
|
4790
4859
|
}
|
|
4791
4860
|
cursor.pc = null;
|
|
4792
|
-
|
|
4861
|
+
stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
|
|
4793
4862
|
}
|
|
4794
4863
|
}
|
|
4795
4864
|
function elevator() {
|
|
@@ -4806,7 +4875,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4806
4875
|
}
|
|
4807
4876
|
}
|
|
4808
4877
|
}
|
|
4809
|
-
|
|
4878
|
+
const defined = { buildStairs, elevator };
|
|
4879
|
+
Object.assign(K, defined);
|
|
4810
4880
|
}
|
|
4811
4881
|
|
|
4812
4882
|
// src/lights/fixtures.ts
|
|
@@ -4846,14 +4916,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4846
4916
|
c: (mat, x, y, z, r, h, color2, seg) => api.cylinder(M, mat, x, y0 + y, z, r, h, color2, 0, 0, seg),
|
|
4847
4917
|
e: (mat, x, y, z, r, h, color2) => api.cylinder(M, mat, x, y0 + y - h / 2, z, r, h, color2, 0, 0, "sphere"),
|
|
4848
4918
|
t(mat, p, q, r, color2, seg) {
|
|
4919
|
+
const tc = color2 ?? NaN;
|
|
4849
4920
|
const dx = q[0] - p[0], dy = q[1] - p[1], dz = q[2] - p[2], L = Math.hypot(dx, dy, dz);
|
|
4850
4921
|
if (L < 1e-5) return;
|
|
4851
4922
|
const nx = dx / L, ny = dy / L, nz = dz / L;
|
|
4852
4923
|
if (Math.abs(nx) < 1e-4 && Math.abs(nz) < 1e-4) {
|
|
4853
|
-
api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L,
|
|
4924
|
+
api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, tc, 0, 0, seg);
|
|
4854
4925
|
return;
|
|
4855
4926
|
}
|
|
4856
|
-
api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L,
|
|
4927
|
+
api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, tc, Math.atan2(nz, ny), -Math.asin(nx), seg);
|
|
4857
4928
|
},
|
|
4858
4929
|
polyFace: (mat, pts, color2, hint) => polyFace(mat, pts.map((p) => W(p[0], p[1], p[2])), color2, hint && [hint[0] * c + hint[2] * s, hint[1], -hint[0] * s + hint[2] * c]),
|
|
4859
4930
|
part(type, lx, ly, lz, fn, meta) {
|
|
@@ -5032,7 +5103,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5032
5103
|
K2.part("light_switch", x, 0, 0.011, () => K2.b("plain", x, -0.018, 0.0125, two ? 0.03 : 0.036, 0.034, 8e-3, 16513782, 0, -0.12), { id: "sw_" + M.seed + "_" + i, room: M.room, target: M.target || M.room, opens: { type: "toggle", axis: [1, 0, 0], angle: 0.24 }, on: !!M.on, t0: M.on ? 1 : 0 });
|
|
5033
5104
|
}
|
|
5034
5105
|
}
|
|
5035
|
-
|
|
5106
|
+
const defined = { hashString, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch };
|
|
5107
|
+
Object.assign(K, defined);
|
|
5036
5108
|
}
|
|
5037
5109
|
|
|
5038
5110
|
// src/lights/decor.ts
|
|
@@ -5099,7 +5171,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5099
5171
|
void sd;
|
|
5100
5172
|
}
|
|
5101
5173
|
}
|
|
5102
|
-
|
|
5174
|
+
const defined = { decorLights };
|
|
5175
|
+
Object.assign(K, defined);
|
|
5103
5176
|
}
|
|
5104
5177
|
|
|
5105
5178
|
// src/lot/terrain.ts
|
|
@@ -5152,7 +5225,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5152
5225
|
if (x < b) out.push([x, b]);
|
|
5153
5226
|
return out.filter((q) => q[1] - q[0] > 0.3);
|
|
5154
5227
|
}
|
|
5155
|
-
|
|
5228
|
+
const defined = { terrain, freeSpans };
|
|
5229
|
+
Object.assign(K, defined);
|
|
5156
5230
|
}
|
|
5157
5231
|
|
|
5158
5232
|
// src/lot/perimeter.ts
|
|
@@ -5172,7 +5246,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5172
5246
|
for (const s of lt.perimeter) {
|
|
5173
5247
|
const alongU = Math.abs(s.v1 - s.v0) < EPS3, L = alongU ? s.v0 : s.u0, a = Math.min(alongU ? s.u0 : s.v0, alongU ? s.u1 : s.v1), b = Math.max(alongU ? s.u0 : s.v0, alongU ? s.u1 : s.v1);
|
|
5174
5248
|
cursor.pc = pieceRecord("lot_wall:" + s.id, s.type === "wall" ? "brick" : s.type === "fence" ? "wood_soft" : "steel", null, { tags: ["wall"] });
|
|
5175
|
-
const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color)
|
|
5249
|
+
const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) ?? (C.wall || 12104874), len = b - a;
|
|
5176
5250
|
const B = (mat, u0, y0, u1, y1, t, c, off = 0) => alongU ? bx(mat, u0, y0, L + off - t / 2, u1, y1, L + off + t / 2, c) : bx(mat, L + off - t / 2, y0, u0, L + off + t / 2, y1, u1, c);
|
|
5177
5251
|
const col = { type: "lot_wall", f: -1, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b };
|
|
5178
5252
|
shared.ctx.colliders.push(col);
|
|
@@ -5246,7 +5320,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5246
5320
|
}
|
|
5247
5321
|
}
|
|
5248
5322
|
}
|
|
5249
|
-
|
|
5323
|
+
const defined = { perimeter, paths };
|
|
5324
|
+
Object.assign(K, defined);
|
|
5250
5325
|
}
|
|
5251
5326
|
|
|
5252
5327
|
// src/lot/gates.ts
|
|
@@ -5262,7 +5337,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5262
5337
|
cursor.group = "lot";
|
|
5263
5338
|
const structure = R.style, auto = structure !== "budget", wall = colorOf("wall") || 12104874, cu = (lt.rect[0] + lt.rect[2]) / 2, cz = (lt.rect[1] + lt.rect[3]) / 2;
|
|
5264
5339
|
for (const g of lt.gates) {
|
|
5265
|
-
const gc = colorOf(g.color)
|
|
5340
|
+
const gc = colorOf(g.color) ?? (C.gate != null ? C.gate : 2763310), a = g.u - g.width / 2, b = g.u + g.width / 2, v = g.v, h = g.height, t = 0.05, ped = g.model === "pedestrian", tilt = g.model === "tilting";
|
|
5266
5341
|
const sd = cz - v >= 0 ? 1 : -1;
|
|
5267
5342
|
const pil = (x0, x1, high) => {
|
|
5268
5343
|
bx("plaster", x0, 0, v - 0.13, x1, high, v + 0.13, wall);
|
|
@@ -5334,7 +5409,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5334
5409
|
if (!g.open || ped) shared.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
|
|
5335
5410
|
}
|
|
5336
5411
|
}
|
|
5337
|
-
|
|
5412
|
+
const defined = { slideDirection, gates };
|
|
5413
|
+
Object.assign(K, defined);
|
|
5338
5414
|
}
|
|
5339
5415
|
|
|
5340
5416
|
// src/roof/roofs.ts
|
|
@@ -5348,13 +5424,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5348
5424
|
function roofs() {
|
|
5349
5425
|
const R = shared.ctx.r, F = R.facade, C = shared.ctx.colors, nA = R.floors.length, type = F.roof;
|
|
5350
5426
|
cursor.group = "roof";
|
|
5351
|
-
shared.ctx.roofRects = [];
|
|
5352
|
-
shared.ctx.gutter = gutterConfig();
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5427
|
+
const roofRects = shared.ctx.roofRects = [];
|
|
5428
|
+
const G = shared.ctx.gutter = gutterConfig();
|
|
5429
|
+
G.ncond = 0;
|
|
5430
|
+
G.nbuz = 0;
|
|
5431
|
+
G.bz = /* @__PURE__ */ new Set();
|
|
5356
5432
|
shared.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
|
|
5357
|
-
const roofColor = C.roof != null ? C.roof : 11031610, gable = (R.seed | 0) % 2 === 0;
|
|
5433
|
+
const roofColor = C.roof != null ? C.roof : 11031610, gable = (Number(R.seed) | 0) % 2 === 0;
|
|
5358
5434
|
for (let f = 0; f < nA; f++) {
|
|
5359
5435
|
const rs = R.rooms.filter((c) => c.floor === f && c.type !== "void" && !c.outbuilding && !OPEN_AREA(c)).flatMap(rectsOf2), up = R.rooms.filter((c) => c.floor === f + 1 && c.type !== "void").flatMap(rectsOf2);
|
|
5360
5436
|
if (!rs.length) continue;
|
|
@@ -5376,7 +5452,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5376
5452
|
return Y0(f) + Math.max(...cs.map((c) => c.ceiling)) + 0.2;
|
|
5377
5453
|
};
|
|
5378
5454
|
if (type === "slab") {
|
|
5379
|
-
for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i))
|
|
5455
|
+
for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) roofRects.push({ f, r: [xs[i], zs[j], xs[i + 1], zs[j + 1]], slab: true, yb: pe(xs[i], zs[j], xs[i + 1], zs[j + 1]) + 0.03 });
|
|
5380
5456
|
slabs(f, xs, zs, O, U, nx, nz, full, pe, C);
|
|
5381
5457
|
cursor.pc = null;
|
|
5382
5458
|
continue;
|
|
@@ -5399,16 +5475,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5399
5475
|
if (U(q.j0 - 1, i)) touchesU[1] = 1;
|
|
5400
5476
|
if (U(q.j1 + 1, i)) touchesU[3] = 1;
|
|
5401
5477
|
}
|
|
5402
|
-
|
|
5478
|
+
roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
|
|
5403
5479
|
const ybq = pe(x0, z0, x1, z1);
|
|
5404
5480
|
roofRect(type, x0, z0, x1, z1, ybq, roofColor, gable && single, F, touchesU);
|
|
5405
5481
|
cursor.pc = null;
|
|
5406
|
-
if (
|
|
5482
|
+
if (G.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
|
|
5407
5483
|
}
|
|
5408
5484
|
}
|
|
5409
5485
|
for (const e of shared.ctx.outbuildingList || []) {
|
|
5410
5486
|
const [x0, z0, x1, z1] = e.aabb, yb = Y0(0) + (e.ceiling || 2.6) + 0.2;
|
|
5411
|
-
|
|
5487
|
+
roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
|
|
5412
5488
|
if (type === "slab") {
|
|
5413
5489
|
const c = C.facade != null ? C.facade : 14209216;
|
|
5414
5490
|
bx("plaster", x0 - 0.08, yb, z0 - 0.08, x1 + 0.08, yb + 0.03, z1 + 0.08, sh(C.ceiling != null ? C.ceiling : 12104876, 0.85));
|
|
@@ -5419,13 +5495,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5419
5495
|
roofRect(type, x0, z0, x1, z1, yb, roofColor, true, F, [0, 0, 0, 0]);
|
|
5420
5496
|
cursor.pc = null;
|
|
5421
5497
|
shared.ctx.noPiece = false;
|
|
5422
|
-
if (
|
|
5498
|
+
if (G.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
|
|
5423
5499
|
}
|
|
5424
5500
|
}
|
|
5425
|
-
|
|
5501
|
+
const defined = { roofs };
|
|
5502
|
+
Object.assign(K, defined);
|
|
5426
5503
|
}
|
|
5427
5504
|
|
|
5428
5505
|
// src/roof/gutters.ts
|
|
5506
|
+
var paletteMeta = (colors) => colors.meta;
|
|
5429
5507
|
function installRoofGutters(K, shared) {
|
|
5430
5508
|
const { boxC, bx, cursor, roomAt } = K;
|
|
5431
5509
|
const sh = (...a) => K.sh(...a);
|
|
@@ -5442,7 +5520,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5442
5520
|
const draw2 = rnd() < p, light = rnd() < 0.6;
|
|
5443
5521
|
void draw2;
|
|
5444
5522
|
const on = true;
|
|
5445
|
-
return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared.ctx.colors
|
|
5523
|
+
return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: paletteMeta(shared.ctx.colors)?.state === "abandoned" || R.state === "abandoned", fallback: false };
|
|
5446
5524
|
}
|
|
5447
5525
|
function gutter(type, f, X0, Z0, X1, Z1, yb, touchesU) {
|
|
5448
5526
|
const G = shared.ctx.gutter, o = type === "fiber_cement" ? 0.3 : 0.45, x0 = X0 - (touchesU[0] ? 0 : o), x1 = X1 + (touchesU[2] ? 0 : o), z0 = Z0 - (touchesU[1] ? 0 : o), z1 = Z1 + (touchesU[3] ? 0 : o), c = G.color, y = yb - 0.05;
|
|
@@ -5484,7 +5562,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5484
5562
|
const px = cx + sx * 0.06, pz = cz + sz * 0.06;
|
|
5485
5563
|
if (!freeAt(px, pz, sx, sz)) return false;
|
|
5486
5564
|
const floats = G.bad && G.ncond === 1, yt = yb - 0.1, ybx = floats ? 0.7 : 0.04;
|
|
5487
|
-
G.ncond
|
|
5565
|
+
G.ncond = (G.ncond ?? 0) + 1;
|
|
5488
5566
|
if (run2 >= 2) boxC("plain", (sides[run2][4] + px) / 2, yt, pz, Math.abs(sides[run2][4] - px), 0.07, 0.07, c);
|
|
5489
5567
|
else boxC("plain", px, yt, (sides[run2][4] + pz) / 2, 0.07, 0.07, Math.abs(sides[run2][4] - pz), c);
|
|
5490
5568
|
boxC("plain", px, (ybx + yt) / 2, pz, 0.08, yt - ybx, 0.08, c);
|
|
@@ -5518,7 +5596,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5518
5596
|
function drain(x, z, px, pz, c) {
|
|
5519
5597
|
const g0 = cursor.group;
|
|
5520
5598
|
cursor.group = "f0";
|
|
5521
|
-
if (px != null) boxC("plain", (px + x) / 2, 0.075, (pz + z) / 2, Math.abs(x - px) + 0.05, 0.05, Math.abs(z - pz) + 0.05, sh(c, 0.85));
|
|
5599
|
+
if (px != null && pz != null && c != null) boxC("plain", (px + x) / 2, 0.075, (pz + z) / 2, Math.abs(x - px) + 0.05, 0.05, Math.abs(z - pz) + 0.05, sh(c, 0.85));
|
|
5522
5600
|
const t = 0.045;
|
|
5523
5601
|
bx("plain", x - 0.12, 0, z - 0.12, x + 0.12, t - 6e-3, z + 0.12, 12170668);
|
|
5524
5602
|
bx("metal", x - 0.11, t, z - 0.11, x + 0.11, t + 0.012, z + 0.11, 5922145);
|
|
@@ -5529,7 +5607,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5529
5607
|
bx("metal", x - 0.085, t + 0.012, z - 6e-3, x + 0.085, t + 0.02, z + 6e-3, 9080466);
|
|
5530
5608
|
cursor.group = g0;
|
|
5531
5609
|
}
|
|
5532
|
-
|
|
5610
|
+
const defined = { gutterConfig, gutter, drain };
|
|
5611
|
+
Object.assign(K, defined);
|
|
5533
5612
|
}
|
|
5534
5613
|
|
|
5535
5614
|
// src/roof/slabs.ts
|
|
@@ -5563,15 +5642,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5563
5642
|
side(free(j, i + 1), x1 + o - t, z0 - ez0, x1 + o, z1 + ez1);
|
|
5564
5643
|
side(free(j - 1, i), x0 - ex0, z0 - o, x1 + ex1, z0 - o + t);
|
|
5565
5644
|
side(free(j + 1, i), x0 - ex0, z1 + o - t, x1 + ex1, z1 + o);
|
|
5566
|
-
|
|
5645
|
+
const G = shared.ctx.gutter;
|
|
5646
|
+
if (G && G.on && G.bz) for (const [ok, dx, dz] of [[free(j - 1, i), 0, -1], [free(j + 1, i), 0, 1], [free(j, i - 1), -1, 0], [free(j, i + 1), 1, 0]]) {
|
|
5567
5647
|
const kd = f + ":" + dx + ":" + dz;
|
|
5568
|
-
if (!ok ||
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
const mx = (x0 + x1) / 2, mz = (z0 + z1) / 2, ex = dx ? dx < 0 ? x0 - o : x1 + o : mx, ez = dz ? dz < 0 ? z0 - o : z1 + o : mz, cc =
|
|
5648
|
+
if (!ok || G.bz.has(kd)) continue;
|
|
5649
|
+
G.bz.add(kd);
|
|
5650
|
+
G.nbuz = (G.nbuz ?? 0) + 1;
|
|
5651
|
+
const mx = (x0 + x1) / 2, mz = (z0 + z1) / 2, ex = dx ? dx < 0 ? x0 - o : x1 + o : mx, ez = dz ? dz < 0 ? z0 - o : z1 + o : mz, cc = G.color;
|
|
5572
5652
|
boxC("plain", ex + dx * 0.15, yb + 0.1, ez + dz * 0.15, dx ? 0.42 : 0.14, 0.1, dz ? 0.42 : 0.14, cc);
|
|
5573
5653
|
boxC("plain", ex + dx * 0.36, yb + 0.1, ez + dz * 0.36, dx ? 0.04 : 0.18, 0.14, dz ? 0.04 : 0.18, sh(cc, 0.8));
|
|
5574
|
-
if (
|
|
5654
|
+
if (G.bad) boxC("plain", ex + dx * 0.05, yb + 0.5 * 0, ez + dz * 0.05, dx ? 0.06 : 0.3, 0.02, dz ? 0.06 : 0.3, 4868674);
|
|
5575
5655
|
{
|
|
5576
5656
|
const tx = ex + dx * 0.38, tz = ez + dz * 0.38;
|
|
5577
5657
|
let lv = true;
|
|
@@ -5591,7 +5671,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5591
5671
|
}
|
|
5592
5672
|
}
|
|
5593
5673
|
}
|
|
5594
|
-
|
|
5674
|
+
const defined = { slabs };
|
|
5675
|
+
Object.assign(K, defined);
|
|
5595
5676
|
}
|
|
5596
5677
|
|
|
5597
5678
|
// src/roof/tiles.ts
|
|
@@ -5724,7 +5805,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5724
5805
|
}
|
|
5725
5806
|
return m ? structurePiece(m.id) : null;
|
|
5726
5807
|
}
|
|
5727
|
-
|
|
5808
|
+
const defined = { R_STYLE, tileRelief, ridge, pieceOfPane };
|
|
5809
|
+
Object.assign(K, defined);
|
|
5728
5810
|
}
|
|
5729
5811
|
|
|
5730
5812
|
// src/roof/rect.ts
|
|
@@ -5770,7 +5852,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5770
5852
|
}
|
|
5771
5853
|
const rm = alongX ? dz / 2 : dx / 2;
|
|
5772
5854
|
{
|
|
5773
|
-
const
|
|
5855
|
+
const roofRects = shared.ctx.roofRects, rr = roofRects[roofRects.length - 1];
|
|
5774
5856
|
if (rr && !rr.yb) Object.assign(rr, { yb, tp, gable: !!gable, alongX, exterior: [x0, z0, x1, z1], rm });
|
|
5775
5857
|
}
|
|
5776
5858
|
if (gable) {
|
|
@@ -5807,7 +5889,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5807
5889
|
}
|
|
5808
5890
|
}
|
|
5809
5891
|
}
|
|
5810
|
-
|
|
5892
|
+
const defined = { roofRect };
|
|
5893
|
+
Object.assign(K, defined);
|
|
5811
5894
|
}
|
|
5812
5895
|
|
|
5813
5896
|
// src/mirrors.ts
|
|
@@ -5818,9 +5901,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5818
5901
|
function mirrorEnv() {
|
|
5819
5902
|
if (shared.mirrorEnv) return shared.mirrorEnv;
|
|
5820
5903
|
const mk = (f) => {
|
|
5904
|
+
if (!DOC) throw new Error("game-floorplan-three: the mirrors need a document (options.document)");
|
|
5821
5905
|
const c = DOC.createElement("canvas");
|
|
5822
5906
|
c.width = c.height = 64;
|
|
5823
5907
|
const g = c.getContext("2d");
|
|
5908
|
+
if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
|
|
5824
5909
|
f(g);
|
|
5825
5910
|
return c;
|
|
5826
5911
|
};
|
|
@@ -5879,7 +5964,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5879
5964
|
B.N.push(v.x, v.y, v.z);
|
|
5880
5965
|
B.U.push(ua.getX(i), ua.getY(i));
|
|
5881
5966
|
}
|
|
5882
|
-
for (const k of geo.index
|
|
5967
|
+
for (const k of geo.index?.array ?? []) B.I.push(B.nv + k);
|
|
5883
5968
|
B.nv += pa.count;
|
|
5884
5969
|
geo.dispose();
|
|
5885
5970
|
}
|
|
@@ -5957,7 +6042,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5957
6042
|
m.fake.visible = !on;
|
|
5958
6043
|
}
|
|
5959
6044
|
}
|
|
5960
|
-
|
|
6045
|
+
const defined = { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror };
|
|
6046
|
+
Object.assign(K, defined);
|
|
5961
6047
|
}
|
|
5962
6048
|
|
|
5963
6049
|
// src/cars.ts
|
|
@@ -5970,13 +6056,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5970
6056
|
high: ["electric_hatch", "hybrid_suv", "midsize_suv", "v8_coupe", "large_suv", "midsize_pickup", "crossover_pickup", "fastback_sedan"]
|
|
5971
6057
|
}, K.cfg.carKinds);
|
|
5972
6058
|
const CAR_CACHE = /* @__PURE__ */ new Map();
|
|
5973
|
-
function materialSignature(
|
|
6059
|
+
function materialSignature(material) {
|
|
6060
|
+
const m = material;
|
|
5974
6061
|
const f = (v) => v == null ? "" : typeof v === "number" ? v.toFixed(3) : v.isColor ? v.getHexString() : v.uuid || String(v);
|
|
5975
6062
|
return [m.type, f(m.color), f(m.roughness), f(m.metalness), f(m.opacity), m.transparent ? 1 : 0, m.side, f(m.map), f(m.emissive), f(m.emissiveIntensity), m.vertexColors ? 1 : 0, m.flatShading ? 1 : 0, f(m.envMapIntensity), f(m.alphaTest)].join("|");
|
|
5976
6063
|
}
|
|
5977
6064
|
const BUCKETS = /* @__PURE__ */ new Map();
|
|
5978
|
-
function bucketMaterial(
|
|
5979
|
-
if (
|
|
6065
|
+
function bucketMaterial(material) {
|
|
6066
|
+
if (material.type !== "MeshStandardMaterial") return null;
|
|
6067
|
+
const m = material;
|
|
6068
|
+
if (m.map || m.alphaTest || m.vertexColors || !m.color) return null;
|
|
5980
6069
|
const mt = m.metalness > 0.5 ? 2 : m.metalness > 0.2 ? 1 : 0, rg = m.roughness < 0.3 ? 0 : m.roughness < 0.6 ? 1 : 2, tr = m.transparent || m.opacity < 1, op = tr ? Math.max(0.2, Math.min(0.9, Math.round(m.opacity * 5) / 5)) : 1, sig = "bucket" + mt + rg + "s" + m.side + (tr ? "t" + op : "");
|
|
5981
6070
|
let b = BUCKETS.get(sig);
|
|
5982
6071
|
if (!b) {
|
|
@@ -5988,7 +6077,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5988
6077
|
}
|
|
5989
6078
|
function carModel(k, seed) {
|
|
5990
6079
|
const kc = k + "|" + shared.quality + "|" + (seed || 0);
|
|
5991
|
-
if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc);
|
|
6080
|
+
if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc) ?? null;
|
|
5992
6081
|
if (!FLEET) return null;
|
|
5993
6082
|
let res = null;
|
|
5994
6083
|
try {
|
|
@@ -5996,8 +6085,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5996
6085
|
c.root.updateMatrixWorld(true);
|
|
5997
6086
|
const inv = new THREE.Matrix4();
|
|
5998
6087
|
const byMaterial = /* @__PURE__ */ new Map(), tmp = new THREE.Matrix4(), v = new THREE.Vector3(), nm = new THREE.Matrix3(), bb = new THREE.Box3();
|
|
5999
|
-
c.g.traverse((
|
|
6000
|
-
if (!
|
|
6088
|
+
c.g.traverse((node) => {
|
|
6089
|
+
if (!isMesh(node)) return;
|
|
6090
|
+
const o = node;
|
|
6091
|
+
if (o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
|
|
6001
6092
|
for (let p = o; p; p = p.parent) if (p.visible === false) return;
|
|
6002
6093
|
const mats = Array.isArray(o.material) ? o.material : [o.material];
|
|
6003
6094
|
let geo = o.geometry;
|
|
@@ -6011,7 +6102,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6011
6102
|
const pa = geo.attributes.position, na = geo.attributes.normal, ua = geo.attributes.uv, total = pa.count;
|
|
6012
6103
|
const grs = Array.isArray(o.material) && o.geometry.groups.length ? o.geometry.groups : [{ start: 0, count: total, materialIndex: 0 }];
|
|
6013
6104
|
for (const gr of grs) {
|
|
6014
|
-
const m = mats[gr.materialIndex] || mats[0];
|
|
6105
|
+
const m = (gr.materialIndex != null ? mats[gr.materialIndex] : void 0) || mats[0];
|
|
6015
6106
|
if (!m) continue;
|
|
6016
6107
|
const a0 = Math.min(gr.start, total), n0 = Math.min(gr.count, total - a0) - Math.min(gr.count, total - a0) % 3;
|
|
6017
6108
|
if (n0 < 3) continue;
|
|
@@ -6112,7 +6203,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6112
6203
|
return g;
|
|
6113
6204
|
}
|
|
6114
6205
|
function assembleCars(groups) {
|
|
6115
|
-
if (shared.quality === "game")
|
|
6206
|
+
if (shared.quality === "game") {
|
|
6207
|
+
assembleMergedCars(groups);
|
|
6208
|
+
return;
|
|
6209
|
+
}
|
|
6116
6210
|
for (const C of CARS) {
|
|
6117
6211
|
const g = carGroup(C.k, C.w, C.d, C.seed);
|
|
6118
6212
|
if (!g) continue;
|
|
@@ -6163,7 +6257,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6163
6257
|
(groups[B.parent] || (groups[B.parent] = new THREE.Group())).add(m);
|
|
6164
6258
|
}
|
|
6165
6259
|
}
|
|
6166
|
-
|
|
6260
|
+
const defined = { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars };
|
|
6261
|
+
Object.assign(K, defined);
|
|
6167
6262
|
}
|
|
6168
6263
|
|
|
6169
6264
|
// src/house/building.ts
|
|
@@ -6219,14 +6314,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6219
6314
|
bx("plaster", Math.min(hall[0] - 3, color2[0]), ytop, Math.min(un[1] ? unitBox(un[1])[1] : 0, el[1]), Math.max(color2[2], un0[2]), ytop + 0.2, Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0), 11841704);
|
|
6220
6315
|
shared.ctx.limits = { x0: Math.min(hall[0] - 3, color2[0]), z0: Math.min(el[1], un[1] ? unitBox(un[1])[1] : 0), x1: Math.max(color2[2], un0[2]), z1: Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0) };
|
|
6221
6316
|
}
|
|
6222
|
-
|
|
6317
|
+
const defined = { building };
|
|
6318
|
+
Object.assign(K, defined);
|
|
6223
6319
|
}
|
|
6224
6320
|
|
|
6225
6321
|
// src/utilities/water.ts
|
|
6226
6322
|
function installUtilitiesWater(K, shared) {
|
|
6227
6323
|
const { THREE, _Y, _q, cursor, cylBase, part, pieceRecord, put } = K;
|
|
6228
6324
|
function createWater(r, state) {
|
|
6229
|
-
const H = r.utilities
|
|
6325
|
+
const H = r.utilities?.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
|
|
6230
6326
|
if (H) for (const p of H.points) {
|
|
6231
6327
|
points[p.id] = p;
|
|
6232
6328
|
itemPoint[p.item] = p.id;
|
|
@@ -6315,14 +6411,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6315
6411
|
}
|
|
6316
6412
|
const _v3 = new THREE.Vector3();
|
|
6317
6413
|
function waterPipes() {
|
|
6318
|
-
const H = shared.ctx.r.utilities
|
|
6414
|
+
const H = shared.ctx.r.utilities?.plumbing;
|
|
6319
6415
|
if (!H || !H.visibleRuns) return;
|
|
6320
6416
|
const nA = shared.ctx.r.floors.length;
|
|
6321
6417
|
const groupOf = (c) => c && c.floor >= 0 ? "f" + Math.min(c.floor, nA - 1) : "lot", xyz = (p) => [p[0], p[2], p[1]];
|
|
6322
6418
|
for (const tr of H.visibleRuns) {
|
|
6323
6419
|
const pts = tr.points.map(xyz), d = tr.diameter || 0.025;
|
|
6324
6420
|
if (tr.exposed === "wall") {
|
|
6325
|
-
const pt = H.points.find((p) => p.run === tr.id), com = shared.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
|
|
6421
|
+
const pt = H.points.find((p) => p.run === tr.id), com = tr.to != null ? shared.ctx.roomById[tr.to] : void 0, g2 = groupOf(com || pt && { floor: pt.floor });
|
|
6326
6422
|
part("wall_pipe", [0, 0, 0], () => {
|
|
6327
6423
|
for (let i = 0; i + 1 < pts.length; i++) pipe(pts[i], pts[i + 1], d, PIPE_COLOR);
|
|
6328
6424
|
for (const p of pts) cylBase("plain", p[0], p[1] - d, p[2], d * 0.7, d * 2, PIPE_COLOR);
|
|
@@ -6344,7 +6440,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6344
6440
|
cursor.pc = null;
|
|
6345
6441
|
}
|
|
6346
6442
|
}
|
|
6347
|
-
|
|
6443
|
+
const defined = { createWater, PIPE_COLOR, pipe, _v3, waterPipes };
|
|
6444
|
+
Object.assign(K, defined);
|
|
6348
6445
|
}
|
|
6349
6446
|
|
|
6350
6447
|
// src/utilities/electrical.ts
|
|
@@ -6352,10 +6449,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6352
6449
|
const { _Y, _q, _v3, bx, cursor, cylBase, pieceRecord, put } = K;
|
|
6353
6450
|
const sh = (...a) => K.sh(...a);
|
|
6354
6451
|
function electricalStructure() {
|
|
6355
|
-
const
|
|
6452
|
+
const R = shared.ctx.r, E = R.utilities?.electrical;
|
|
6356
6453
|
shared.ctx.electricalInfo = null;
|
|
6357
6454
|
if (!E) return;
|
|
6358
|
-
const
|
|
6455
|
+
const nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
|
|
6359
6456
|
const en3 = E.serviceEntrance, KV = shared.ctx.iv ? shared.ctx.iv.plane : null;
|
|
6360
6457
|
const wireL = (a, b, r_ = 8e-3) => {
|
|
6361
6458
|
const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
@@ -6460,7 +6557,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6460
6557
|
_q.setFromUnitVectors(_Y, _v3.set(dx / L, dy / L, dz / L));
|
|
6461
6558
|
put("plain", "cyl", (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2, _q, diameter, L, diameter, color2);
|
|
6462
6559
|
}
|
|
6463
|
-
|
|
6560
|
+
const defined = { electricalStructure, pipe2 };
|
|
6561
|
+
Object.assign(K, defined);
|
|
6464
6562
|
}
|
|
6465
6563
|
|
|
6466
6564
|
// src/house/baseboard.ts
|
|
@@ -6498,7 +6596,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6498
6596
|
strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
|
|
6499
6597
|
}
|
|
6500
6598
|
}
|
|
6501
|
-
|
|
6599
|
+
const defined = { baseboardAndSidewalk };
|
|
6600
|
+
Object.assign(K, defined);
|
|
6502
6601
|
}
|
|
6503
6602
|
|
|
6504
6603
|
// src/utilities/solar.ts
|
|
@@ -6513,6 +6612,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6513
6612
|
if (u >= a - 0.05 && u <= c + 0.05 && v >= b - 0.05 && v <= d + 0.05) y = Math.max(y == null ? -1e9 : y, rr.yb);
|
|
6514
6613
|
continue;
|
|
6515
6614
|
}
|
|
6615
|
+
if (!rr.exterior || rr.tp == null || rr.rm == null) continue;
|
|
6516
6616
|
const [x0, z0, x1, z1] = rr.exterior;
|
|
6517
6617
|
if (u < x0 || u > x1 || v < z0 || v > z1) continue;
|
|
6518
6618
|
const dz = Math.min(v - z0, z1 - v), dx = Math.min(u - x0, x1 - u), dd = rr.gable ? rr.alongX ? dz : dx : Math.min(dx, dz), h = rr.yb + rr.tp * Math.min(dd, rr.rm);
|
|
@@ -6521,7 +6621,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6521
6621
|
return y;
|
|
6522
6622
|
}
|
|
6523
6623
|
function solar() {
|
|
6524
|
-
const R = shared.ctx.r, S = R.utilities
|
|
6624
|
+
const R = shared.ctx.r, S = R.utilities?.solar;
|
|
6525
6625
|
shared.ctx.solarInfo = null;
|
|
6526
6626
|
if (!S || !S.panels || !S.panels.length) return;
|
|
6527
6627
|
cursor.group = "roof";
|
|
@@ -6564,13 +6664,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6564
6664
|
bx("plain", iv.u - W * 0.6, y0 + 0.05, iv.v + fa0, iv.u + W * 0.6, y0 + 0.17, iv.v + fa1, 2106924);
|
|
6565
6665
|
bx("emissive", iv.u - 0.03, y0 - 0.12, iv.v + fa0, iv.u + 0.03, y0 - 0.09, iv.v + fa1, 6479994);
|
|
6566
6666
|
}
|
|
6567
|
-
const top = Math.max(...(shared.ctx.roofRects || []).
|
|
6667
|
+
const top = Math.max(...(shared.ctx.roofRects || []).flatMap((t2) => t2.yb != null ? [t2.yb] : []), Y0(fa) + 2.8);
|
|
6568
6668
|
cylBase("plain", iv.u, y0 + h / 2, iv.v, 0.016, Math.max(0.2, top - 0.2 - (y0 + h / 2)), 15262936);
|
|
6569
6669
|
info.inverter = { id: iv.id, pos: [iv.u, y0, iv.v], side: iv.side, link: iv.link };
|
|
6570
6670
|
}
|
|
6571
6671
|
shared.ctx.solarInfo = info;
|
|
6572
6672
|
}
|
|
6573
|
-
|
|
6673
|
+
const defined = { roofHeightAt, solar };
|
|
6674
|
+
Object.assign(K, defined);
|
|
6574
6675
|
}
|
|
6575
6676
|
|
|
6576
6677
|
// src/house/outbuildings.ts
|
|
@@ -6585,7 +6686,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6585
6686
|
counts.set(w.floor, i + 1);
|
|
6586
6687
|
return w.id ? w : Object.assign({}, w, { id: `wall_${w.floor}_${i}` });
|
|
6587
6688
|
}) });
|
|
6588
|
-
const E = (r.outbuildings || []).filter((e) => e && e.walls && e.walls.length && e.interior && e.interior.length);
|
|
6689
|
+
const E = (r.outbuildings || []).filter((e) => !!(e && e.walls && e.walls.length && e.interior && e.interior.length));
|
|
6589
6690
|
if (!E.length) return r;
|
|
6590
6691
|
const rooms = r.rooms.slice(), walls = r.walls.slice(), doors = r.doors.slice(), windows = r.windows.slice(), items = r.items.filter((m) => m.type !== "outbuilding");
|
|
6591
6692
|
for (const e of E) {
|
|
@@ -6599,7 +6700,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6599
6700
|
const alongU = p.axis === "u", below = p.pos < (alongU ? cz : cx);
|
|
6600
6701
|
doors.push({ id: p.id, floor: 0, u: p.u, v: p.v, axis: p.axis, pos: p.pos, at: p.at, width: p.width, a: below ? "outside" : e.id, b: below ? e.id : "outside", opensTo: e.id, exterior: true, side: p.side, leaves: 1, model: "single", hinge: "start", zones: [], blocked: false, outbuilding: e.id });
|
|
6601
6702
|
}
|
|
6602
|
-
for (const j of e.windows || []) windows.push({
|
|
6703
|
+
for (const j of e.windows || []) windows.push({
|
|
6704
|
+
id: j.id,
|
|
6705
|
+
floor: 0,
|
|
6706
|
+
u: j.u,
|
|
6707
|
+
v: j.v,
|
|
6708
|
+
axis: j.axis,
|
|
6709
|
+
pos: j.pos,
|
|
6710
|
+
at: j.at,
|
|
6711
|
+
width: j.width,
|
|
6712
|
+
y0: j.y0 ?? 1,
|
|
6713
|
+
y1: j.y1 ?? 2,
|
|
6714
|
+
/* the structure always gives a window its sill and head (1.0, 2.0) */
|
|
6715
|
+
room: e.id,
|
|
6716
|
+
side: j.side,
|
|
6717
|
+
outbuilding: e.id
|
|
6718
|
+
});
|
|
6603
6719
|
(e.items || []).forEach((m, i) => items.push({ id: e.id + "." + m.type + i, type: m.type, category: m.category, x: m.u, z: m.v, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: 0.04, frontU: m.frontU, frontV: m.frontV, room: e.id, floor: 0, outdoor: false, aabb: m.aabb, color: "wood" }));
|
|
6604
6720
|
items.push({ id: e.id + ".ceiling_light", type: "ceiling_light", category: "ceiling_light", x: cx, z: cz, ry: 0, w: 0.35, d: 0.35, h: 0.1, y: pe - 0.1, room: e.id, floor: 0, outdoor: false, assembly: "ceiling", color: "metal", decor: true });
|
|
6605
6721
|
}
|
|
@@ -6620,7 +6736,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6620
6736
|
}
|
|
6621
6737
|
}
|
|
6622
6738
|
}
|
|
6623
|
-
|
|
6739
|
+
const defined = { OUTBUILDING_USE, applyOutbuildings, outbuildings };
|
|
6740
|
+
Object.assign(K, defined);
|
|
6624
6741
|
}
|
|
6625
6742
|
|
|
6626
6743
|
// src/furniture/api.ts
|
|
@@ -6685,7 +6802,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6685
6802
|
return { b: (mat, x, y, z, w, h, d, color2, ry, rx, rz) => A.box(M, mat, x, y0 + y, z, w, h, d, color2, ry || 0, rx || 0, rz || 0), c: (mat, x, y, z, r, h, color2, rx, rz, seg) => A.cylinder(M, mat, x, y0 + y, z, r, h, color2, rx || 0, rz || 0, seg), rnd: rngOf(M), wood: paletteColor(M, "wood", 8016948), met: paletteColor(M, "metal", 10133154) };
|
|
6686
6803
|
}
|
|
6687
6804
|
const PE = Math.PI / 2;
|
|
6688
|
-
|
|
6805
|
+
const defined = { MATERIAL_MAP: MATERIAL_MAP2, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE };
|
|
6806
|
+
Object.assign(K, defined);
|
|
6689
6807
|
}
|
|
6690
6808
|
|
|
6691
6809
|
// src/furniture/builders.ts
|
|
@@ -6813,7 +6931,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6813
6931
|
for (let s = 0; s < np; s++) lb("fabric", np === 1 ? 0 : (s ? 1 : -1) * w * 0.23, 0.5, -d / 2 + 0.3, w * (np === 1 ? 0.6 : 0.4), 0.12, 0.34, 15789798, (s ? 1 : -1) * 0.08);
|
|
6814
6932
|
},
|
|
6815
6933
|
wardrobe(M, A) {
|
|
6816
|
-
const { b: lb } = kk(M, A), w = M.w, d = M.d, h = M.h, wood =
|
|
6934
|
+
const { b: lb } = kk(M, A), w = M.w, d = M.d, h = M.h, wood = paletteColor(M, "wood", 5980208), np = Math.max(2, Math.round(w / 0.7));
|
|
6817
6935
|
lb("wood", 0, 0.06, 0, w, h - 0.06, d, wood);
|
|
6818
6936
|
lb("wood", 0, h, 0, w + 0.04, 0.04, d + 0.04, sh(wood, 0.8));
|
|
6819
6937
|
lb("wood", 0, 0, 0, w - 0.04, 0.06, d - 0.04, sh(wood, 0.4));
|
|
@@ -7205,7 +7323,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7205
7323
|
lb("metal", 0, h - 0.04, d / 2, w, 0.03, 0.03, 3815994);
|
|
7206
7324
|
}
|
|
7207
7325
|
};
|
|
7208
|
-
|
|
7326
|
+
const defined = { FURNITURE };
|
|
7327
|
+
Object.assign(K, defined);
|
|
7209
7328
|
}
|
|
7210
7329
|
|
|
7211
7330
|
// src/furniture/type-table.ts
|
|
@@ -7215,7 +7334,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7215
7334
|
function typeTable(props) {
|
|
7216
7335
|
const B = props.builders, T2 = {};
|
|
7217
7336
|
const mv = (type, id) => {
|
|
7218
|
-
|
|
7337
|
+
const f = B[id || type];
|
|
7338
|
+
if (f) T2[type] = { f, source: "props3d" };
|
|
7219
7339
|
};
|
|
7220
7340
|
const mine = (type, f, source = "game") => {
|
|
7221
7341
|
T2[type] = { f, source };
|
|
@@ -7354,7 +7474,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7354
7474
|
extraTypes(T2, props);
|
|
7355
7475
|
return T2;
|
|
7356
7476
|
}
|
|
7357
|
-
|
|
7477
|
+
const defined = { typeTable };
|
|
7478
|
+
Object.assign(K, defined);
|
|
7358
7479
|
}
|
|
7359
7480
|
|
|
7360
7481
|
// src/furniture/taps.ts
|
|
@@ -7418,7 +7539,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7418
7539
|
}, { id: id + "_a", target: id, hidden: true, fluid: "water" });
|
|
7419
7540
|
return id;
|
|
7420
7541
|
}
|
|
7421
|
-
|
|
7542
|
+
const defined = { counterTap, wallTap };
|
|
7543
|
+
Object.assign(K, defined);
|
|
7422
7544
|
}
|
|
7423
7545
|
|
|
7424
7546
|
// src/furniture/fixtures.ts
|
|
@@ -7531,7 +7653,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7531
7653
|
const a = rnd() * 6.283, u = Math.sqrt(rnd()), ph = (rnd() - 0.2) * 1.2, dx = Math.cos(a) * u * R * 0.75, dz = Math.sin(a) * u * R * 0.75, dy = (o.flatten ? 0.35 : 0.55) * R * (Math.sin(ph) * 0.5 + 0.5) * 1.5 - R * 0.15;
|
|
7532
7654
|
const r = R * (0.34 + rnd() * 0.22) * (1 - u * 0.25), alt = r * 2 * (o.flatten ? 0.75 : 0.95), f = 0.72 + Math.min(1, (dy + R * 0.2) / (R * 1.2)) * 0.32 + rnd() * 0.12;
|
|
7533
7655
|
K2.e("plant", cx + dx, cy + dy + r * 0.5, cz + dz, r, alt, sh(green2, f));
|
|
7534
|
-
if (o.flower && rnd() < o.flower) {
|
|
7656
|
+
if (o.flower && o.flowers && rnd() < o.flower) {
|
|
7535
7657
|
const fa = rnd() * 6.283;
|
|
7536
7658
|
K2.e("plain", cx + dx + Math.cos(fa) * r * 0.78, cy + dy + r * 0.5 + rnd() * r * 0.5, cz + dz + Math.sin(fa) * r * 0.78, 0.028 + rnd() * 0.012, 0.05, o.flowers[rnd() * o.flowers.length | 0]);
|
|
7537
7659
|
}
|
|
@@ -7644,7 +7766,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7644
7766
|
else blobs(K2, x, bh - 0.05, z, 0.24 + rnd() * 0.08, 6, green2, rnd, { flatten: true, flower: tp === "flower" ? 0.9 : 0.25, flowers: FLOWERS.slice(i % 3, i % 3 + 3) });
|
|
7645
7767
|
}
|
|
7646
7768
|
}
|
|
7647
|
-
|
|
7769
|
+
const defined = { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel };
|
|
7770
|
+
Object.assign(K, defined);
|
|
7648
7771
|
}
|
|
7649
7772
|
|
|
7650
7773
|
// src/furniture/yard.ts
|
|
@@ -7800,7 +7923,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7800
7923
|
};
|
|
7801
7924
|
FURNITURE.mailbox = function(M, A) {
|
|
7802
7925
|
const K2 = kit2(M, A, 0), w = M.w || 0.3, d = M.d || 0.22, h = M.h || 0.3, y = M.y != null && M.y > 0 ? M.y : 1, structure = STYLE(), pc = structure === "high" ? 2763824 : structure === "mid" ? 13676640 : 13126202, rnd = rngString(SEED() + "|" + seedKey(M.seed) + "|correio");
|
|
7803
|
-
if (M.pole !== false && !(M.y > 0)) {
|
|
7926
|
+
if (M.pole !== false && !(M.y != null && M.y > 0)) {
|
|
7804
7927
|
K2.b("plain", 0, 0, -d / 2 - 0.1, 0.12, y, 0.12, 12104874);
|
|
7805
7928
|
}
|
|
7806
7929
|
K2.b("metal", 0, y, 0, w, h * 0.78, d, pc);
|
|
@@ -7820,7 +7943,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7820
7943
|
);
|
|
7821
7944
|
K2.b("plain", 0, y + h * 0.62, d / 2 + 4e-3, 0.08, 0.05, 4e-3, 15921386);
|
|
7822
7945
|
};
|
|
7823
|
-
|
|
7946
|
+
const defined = { CLOTHES_COLORS, strip, garment };
|
|
7947
|
+
Object.assign(K, defined);
|
|
7824
7948
|
}
|
|
7825
7949
|
|
|
7826
7950
|
// src/furniture/extra-types.ts
|
|
@@ -7880,7 +8004,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7880
8004
|
tuft(K2, 0, 0, 0, Math.max(0.2, (M.w || 0.4) / 2), 16, 5212738, rnd);
|
|
7881
8005
|
});
|
|
7882
8006
|
}
|
|
7883
|
-
|
|
8007
|
+
const defined = { extraTypes };
|
|
8008
|
+
Object.assign(K, defined);
|
|
7884
8009
|
}
|
|
7885
8010
|
|
|
7886
8011
|
// src/furniture/place-items.ts
|
|
@@ -7902,8 +8027,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7902
8027
|
if (m.type === "stairs") continue;
|
|
7903
8028
|
const exterior = m.outdoor || m.floor < 0, f = exterior ? -1 : Math.min(m.floor, R.floors.length - 1);
|
|
7904
8029
|
cursor.group = exterior ? "lot" : "f" + f;
|
|
7905
|
-
const com = shared.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
|
|
7906
|
-
const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color)
|
|
8030
|
+
const com = m.room != null ? shared.ctx.roomById[m.room] : void 0, base = exterior ? 0 : Y0(f);
|
|
8031
|
+
const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) ?? void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared.ctx.night, light: shared.ctx.night, lit: shared.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
|
|
7907
8032
|
if (m.category === "ground_cover" && m.polygon) {
|
|
7908
8033
|
const xs = m.polygon.map((p) => p[0]), zs = m.polygon.map((p) => p[1]);
|
|
7909
8034
|
M.x = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
@@ -7980,7 +8105,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7980
8105
|
boxC("plain", m.x, M.base + (m.y || 0) + h / 2, m.z, m.w, h, m.d, color2, 0, m.ry || 0, 0);
|
|
7981
8106
|
shared.ctx.labels.push({ pos: new THREE.Vector3(m.x, M.base + (m.y || 0) + h + 0.15, m.z), text: m.type, group, type: "no_model" });
|
|
7982
8107
|
}
|
|
7983
|
-
|
|
8108
|
+
const defined = { houseItems, waterTankOfHouse, hashColor, labeledBox };
|
|
8109
|
+
Object.assign(K, defined);
|
|
7984
8110
|
}
|
|
7985
8111
|
|
|
7986
8112
|
// src/vegetation/bridge.ts
|
|
@@ -8015,7 +8141,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8015
8141
|
const ids = VEG_MAP[m.type], can = VEG_PLANTER[m.type];
|
|
8016
8142
|
if (!ids && !can) return false;
|
|
8017
8143
|
const rnd = rngString(SEED() + "|" + seedKey(m.id) + "|veg"), pick2 = (l) => l[Math.min(l.length - 1, rnd() * l.length | 0)], ok = (id) => {
|
|
8018
|
-
if (V.ok.has(id)) return V.ok.get(id);
|
|
8144
|
+
if (V.ok.has(id)) return V.ok.get(id) === true;
|
|
8019
8145
|
let r = true;
|
|
8020
8146
|
try {
|
|
8021
8147
|
V.S.toSpec(id);
|
|
@@ -8061,7 +8187,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8061
8187
|
obj.position.y = G.y;
|
|
8062
8188
|
obj.name = "vegetation";
|
|
8063
8189
|
obj.traverse((o) => {
|
|
8064
|
-
if (o
|
|
8190
|
+
if (isMesh(o)) {
|
|
8065
8191
|
o.castShadow = true;
|
|
8066
8192
|
o.receiveShadow = true;
|
|
8067
8193
|
o.name = "veg/" + o.name;
|
|
@@ -8076,7 +8202,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8076
8202
|
}
|
|
8077
8203
|
shared.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
|
|
8078
8204
|
}
|
|
8079
|
-
|
|
8205
|
+
const defined = { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation };
|
|
8206
|
+
Object.assign(K, defined);
|
|
8080
8207
|
}
|
|
8081
8208
|
|
|
8082
8209
|
// src/interaction/state.ts
|
|
@@ -8144,12 +8271,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8144
8271
|
shared.inter.msg = { text, until: performance.now() + MESSAGE_MS };
|
|
8145
8272
|
if (cfg.onMessage) cfg.onMessage(text);
|
|
8146
8273
|
};
|
|
8147
|
-
|
|
8274
|
+
const I = () => shared.inter;
|
|
8275
|
+
function definePiece(name, definition) {
|
|
8276
|
+
const def = definition;
|
|
8148
8277
|
def.name = name;
|
|
8149
8278
|
def.meshes = [];
|
|
8150
8279
|
def.t = def.target = shared.partState.has(name) ? shared.partState.get(name) : def.t0 || 0;
|
|
8151
|
-
|
|
8152
|
-
|
|
8280
|
+
I().defs.set(name, def);
|
|
8281
|
+
I().pieces.push(def);
|
|
8153
8282
|
return def;
|
|
8154
8283
|
}
|
|
8155
8284
|
const localOf = (M, lx, lz) => {
|
|
@@ -8161,17 +8290,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8161
8290
|
return true;
|
|
8162
8291
|
}
|
|
8163
8292
|
function assembleInteractive(gs) {
|
|
8164
|
-
|
|
8293
|
+
const inter = I();
|
|
8294
|
+
for (const [name, def] of inter.defs) {
|
|
8165
8295
|
const g = gs[name];
|
|
8166
8296
|
if (!g) continue;
|
|
8167
8297
|
delete gs[name];
|
|
8168
8298
|
const outer = new THREE.Group();
|
|
8169
|
-
outer.position.
|
|
8299
|
+
outer.position.fromArray(def.pivot);
|
|
8170
8300
|
outer.rotation.y = def.ry || 0;
|
|
8171
8301
|
outer.updateMatrix();
|
|
8172
|
-
const inv = new THREE.Matrix4().compose(new THREE.Vector3(
|
|
8302
|
+
const inv = new THREE.Matrix4().compose(new THREE.Vector3().fromArray(def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
|
|
8173
8303
|
g.traverse((o) => {
|
|
8174
|
-
if (o
|
|
8304
|
+
if (isMesh(o)) {
|
|
8175
8305
|
o.geometry.applyMatrix4(inv);
|
|
8176
8306
|
o.userData.piece = def;
|
|
8177
8307
|
def.meshes.push(o);
|
|
@@ -8183,13 +8313,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8183
8313
|
const parent = def.leaf ? def.leaf.gs[def.k] : gs[def.parent] || (gs[def.parent] = new THREE.Group());
|
|
8184
8314
|
if (parent) parent.add(outer);
|
|
8185
8315
|
if (def.roomId) {
|
|
8186
|
-
|
|
8187
|
-
|
|
8316
|
+
let lamps = inter.lights.get(def.roomId);
|
|
8317
|
+
if (!lamps) inter.lights.set(def.roomId, lamps = []);
|
|
8318
|
+
lamps.push(def);
|
|
8188
8319
|
}
|
|
8189
8320
|
applyPiece(def);
|
|
8190
8321
|
}
|
|
8191
|
-
for (const roomId of
|
|
8192
|
-
|
|
8322
|
+
for (const roomId of inter.litRooms) applyLight(roomId);
|
|
8323
|
+
inter.defs.forEach((d) => {
|
|
8193
8324
|
if (d.col) d.col.off = d.t > 0.5;
|
|
8194
8325
|
});
|
|
8195
8326
|
}
|
|
@@ -8197,6 +8328,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8197
8328
|
const n = p.inner;
|
|
8198
8329
|
if (!n) return;
|
|
8199
8330
|
switch (p.kind) {
|
|
8331
|
+
/* each kind always sets its dimensions (sgn, angle, travel, k, axis) */
|
|
8200
8332
|
case "swing":
|
|
8201
8333
|
n.rotation.y = p.sgn * p.t * p.angle;
|
|
8202
8334
|
break;
|
|
@@ -8229,8 +8361,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8229
8361
|
}
|
|
8230
8362
|
const DURATION = { swing: 0.55, drawer: 0.4, curtain: 0.9, gate_swing: 0.9, gate_tilt: 1.4, gate_slide: 1.6, lightSwitch: 0.12, part: 0.4 };
|
|
8231
8363
|
function animateInteractive(dt) {
|
|
8232
|
-
|
|
8233
|
-
|
|
8364
|
+
const inter = I();
|
|
8365
|
+
if (!inter.anim.size) return;
|
|
8366
|
+
for (const p of inter.anim) {
|
|
8234
8367
|
const step = dt / (DURATION[p.kind] || 0.5), d = p.target - p.t;
|
|
8235
8368
|
p.t = Math.abs(d) <= step ? p.target : p.t + Math.sign(d) * step;
|
|
8236
8369
|
applyPiece(p);
|
|
@@ -8238,7 +8371,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8238
8371
|
p.col.off = p.target > 0.5;
|
|
8239
8372
|
colliderChanged(p.col);
|
|
8240
8373
|
}
|
|
8241
|
-
if (p.t === p.target)
|
|
8374
|
+
if (p.t === p.target) inter.anim.delete(p);
|
|
8242
8375
|
}
|
|
8243
8376
|
invalidateShadow();
|
|
8244
8377
|
}
|
|
@@ -8249,7 +8382,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8249
8382
|
p.col.off = p.target > 0.5;
|
|
8250
8383
|
colliderChanged(p.col);
|
|
8251
8384
|
}
|
|
8252
|
-
|
|
8385
|
+
I().anim.add(p);
|
|
8253
8386
|
}
|
|
8254
8387
|
const lightBase = (roomId) => roomId == null ? true : shared.partState.has("light:" + roomId) ? !!shared.partState.get("light:" + roomId) : !!shared.ctx.night;
|
|
8255
8388
|
const lightOn = (roomId) => {
|
|
@@ -8257,20 +8390,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8257
8390
|
return S ? S.ef : lightBase(roomId);
|
|
8258
8391
|
};
|
|
8259
8392
|
function applyLight(roomId) {
|
|
8260
|
-
const on = lightOn(roomId);
|
|
8261
|
-
for (const d of
|
|
8262
|
-
const sw =
|
|
8393
|
+
const on = lightOn(roomId), inter = I(), mats = shared.mats;
|
|
8394
|
+
for (const d of inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? mats.emissive : mats.off;
|
|
8395
|
+
const sw = inter.defs.get("ix:int:" + roomId);
|
|
8263
8396
|
if (sw) {
|
|
8264
8397
|
sw.target = on ? 1 : 0;
|
|
8265
|
-
if (sw.t !== sw.target)
|
|
8398
|
+
if (sw.t !== sw.target) inter.anim.add(sw);
|
|
8266
8399
|
}
|
|
8267
8400
|
invalidate();
|
|
8268
8401
|
}
|
|
8269
8402
|
function toggleLight(roomId) {
|
|
8270
8403
|
const S = shared.ctx.iv && shared.ctx.iv.roomStates.get(roomId);
|
|
8271
8404
|
if (S) {
|
|
8272
|
-
|
|
8273
|
-
|
|
8405
|
+
const IV = shared.ctx.iv;
|
|
8406
|
+
ivRoomLight(IV, roomId, !S.ef);
|
|
8407
|
+
const ef = ivRoomEffective(IV, S);
|
|
8274
8408
|
if (ef !== S.ef) {
|
|
8275
8409
|
S.ef = ef;
|
|
8276
8410
|
applyLight(roomId);
|
|
@@ -8282,11 +8416,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8282
8416
|
applyLight(roomId);
|
|
8283
8417
|
if (cfg.onLight) cfg.onLight(roomId, lightOn(roomId));
|
|
8284
8418
|
}
|
|
8285
|
-
|
|
8419
|
+
const defined = { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight };
|
|
8420
|
+
Object.assign(K, defined);
|
|
8286
8421
|
}
|
|
8287
8422
|
|
|
8288
8423
|
// src/interaction/collision.ts
|
|
8289
8424
|
function installInteractionCollision(K, shared) {
|
|
8425
|
+
const inter = () => shared.inter;
|
|
8290
8426
|
const NO_COLLIDE = /(^|_)(rug|floor|concrete|dirt|lawn|deck|ceiling_light|pendant|chandelier|spot|picture|curtain|blinds|wall_shelving|plank_shelf|wall_ac|ac_condenser|pool|soaking_tub|pergola|stairs|mirror)/;
|
|
8291
8427
|
function registerCollision(m, M) {
|
|
8292
8428
|
const h = m.h || 0, y = M.y || 0;
|
|
@@ -8296,7 +8432,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8296
8432
|
w = Math.min(w, 0.5);
|
|
8297
8433
|
d = Math.min(d, 0.5);
|
|
8298
8434
|
}
|
|
8299
|
-
|
|
8435
|
+
inter().objs.push({ f: M.floor, cx: m.x, cz: m.z, c: Math.cos(M.ry), s: Math.sin(M.ry), hw: w / 2, hd: d / 2, type: m.type });
|
|
8300
8436
|
}
|
|
8301
8437
|
function objectDistance(o, x, z) {
|
|
8302
8438
|
const dx = x - o.cx, dz = z - o.cz, lx = dx * o.c - dz * o.s, lz = dx * o.s + dz * o.c, ex = Math.abs(lx) - o.hw, ez = Math.abs(lz) - o.hd;
|
|
@@ -8304,7 +8440,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8304
8440
|
}
|
|
8305
8441
|
function collideObject(x, z, fx, fz, floor) {
|
|
8306
8442
|
const R = 0.2;
|
|
8307
|
-
for (const o of
|
|
8443
|
+
for (const o of inter().objs) {
|
|
8308
8444
|
if (o.f !== -1 ? o.f !== floor : floor !== 0) continue;
|
|
8309
8445
|
const d1 = objectDistance(o, x, z);
|
|
8310
8446
|
if (d1 < R && d1 < objectDistance(o, fx, fz) - 1e-6) return true;
|
|
@@ -8324,7 +8460,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8324
8460
|
const de = opt.from || [x + 1e4, z + 1e4];
|
|
8325
8461
|
return collideObject(x, z, de[0], de[1], floor);
|
|
8326
8462
|
}
|
|
8327
|
-
|
|
8463
|
+
const defined = { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt };
|
|
8464
|
+
Object.assign(K, defined);
|
|
8328
8465
|
}
|
|
8329
8466
|
|
|
8330
8467
|
// src/interaction/items.ts
|
|
@@ -8333,6 +8470,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8333
8470
|
const DOOR_ITEM = /^(tv_unit|tv_unit_small|tv_unit_large|sideboard|china_cabinet|filing_cabinet|pantry|laundry_cabinet|wardrobe|wardrobe_small|wardrobe_large|closet_wardrobe|kitchen_cabinet|kitchen_cabinet_large|kitchen_cabinet_small|fridge|fridge_large|display_fridge_medium|display_fridge)$/;
|
|
8334
8471
|
const DRAWER_ITEM = /^(console_table|dresser|nightstand|vanity_table)$/;
|
|
8335
8472
|
const LIGHT_TYPES = /* @__PURE__ */ new Set(["ceiling_light", "pendant", "chandelier", "track_spot", "hanging_plant"]);
|
|
8473
|
+
const I = () => shared.inter;
|
|
8336
8474
|
function objectName(type, drawer) {
|
|
8337
8475
|
return drawer ? "drawer" : /^wardrobe/.test(type) ? "wardrobe" : /fridge|refrig|freezer/.test(type) ? "fridge" : /pantry/.test(type) ? "pantry" : "cabinet";
|
|
8338
8476
|
}
|
|
@@ -8361,8 +8499,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8361
8499
|
cursor.group = parent;
|
|
8362
8500
|
}
|
|
8363
8501
|
for (let i = n0; i < LIGHTS.length; i++) LIGHTS[i].roomId = m.room;
|
|
8364
|
-
if (!
|
|
8365
|
-
|
|
8502
|
+
if (!I().defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
|
|
8503
|
+
I().litRooms.add(m.room);
|
|
8366
8504
|
}
|
|
8367
8505
|
function curtainItem(m, M, ent, api, parent) {
|
|
8368
8506
|
M.open = false;
|
|
@@ -8390,12 +8528,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8390
8528
|
for (const c of body) api[c[0]](M, ...c[1]);
|
|
8391
8529
|
if (!parts.length) return;
|
|
8392
8530
|
const [ax, az] = localOf(M, 0, 0.2);
|
|
8393
|
-
|
|
8394
|
-
|
|
8531
|
+
const first = parts[0];
|
|
8532
|
+
I().items.push({ type: "curtain", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (m.h || 2) * 0.5, az], range: 2.4, angle: 1, pieces: parts, text: () => t(first.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.curtain") }), action: () => {
|
|
8533
|
+
const al = first.target > 0.5 ? 0 : 1;
|
|
8395
8534
|
for (const p of parts) {
|
|
8396
8535
|
p.target = al;
|
|
8397
8536
|
shared.partState.set(p.name, al);
|
|
8398
|
-
|
|
8537
|
+
I().anim.add(p);
|
|
8399
8538
|
}
|
|
8400
8539
|
} });
|
|
8401
8540
|
}
|
|
@@ -8416,7 +8555,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8416
8555
|
calls.forEach((c, i) => {
|
|
8417
8556
|
if (owner.has(i)) return;
|
|
8418
8557
|
const a = c[1];
|
|
8419
|
-
let x0, x1, y0, y1, ok = false, grip = 0, wide = false;
|
|
8558
|
+
let x0 = 0, x1 = 0, y0 = 0, y1 = 0, ok = false, grip = 0, wide = false;
|
|
8420
8559
|
if (c[0] === "box") {
|
|
8421
8560
|
const [mat, x, y, z, w, h, d, , ry, rx, rz] = a;
|
|
8422
8561
|
if (ry || rx || rz || d > 0.05 || z + d / 2 < front - 5e-3 || w > M.w * 1.01) return;
|
|
@@ -8448,8 +8587,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8448
8587
|
return;
|
|
8449
8588
|
}
|
|
8450
8589
|
candidate.sort((p, q) => overlap(x0, x1, q.x0, q.x1) - overlap(x0, x1, p.x0, p.x1));
|
|
8451
|
-
|
|
8452
|
-
|
|
8590
|
+
const best = candidate[0];
|
|
8591
|
+
owner.set(i, best);
|
|
8592
|
+
if (grip) best.grip = grip;
|
|
8453
8593
|
});
|
|
8454
8594
|
const name = objectName(m.type, drawer), parts = [];
|
|
8455
8595
|
panels.forEach((p, k) => {
|
|
@@ -8465,8 +8605,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8465
8605
|
p.def = def;
|
|
8466
8606
|
parts.push(def);
|
|
8467
8607
|
const [ax, az] = localOf(M, cx, front + 0.08);
|
|
8468
|
-
|
|
8469
|
-
def.item =
|
|
8608
|
+
I().items.push({ type: drawer ? "drawer" : "cabinet", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (p.y0 + p.y1) / 2, az], range: 1.6, angle: 0.4, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what." + name) }), action: () => togglePiece(def) });
|
|
8609
|
+
def.item = I().items[I().items.length - 1];
|
|
8470
8610
|
});
|
|
8471
8611
|
calls.forEach((c, i) => {
|
|
8472
8612
|
const p = owner.get(i);
|
|
@@ -8480,14 +8620,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8480
8620
|
}
|
|
8481
8621
|
cursor.group = parent;
|
|
8482
8622
|
}
|
|
8483
|
-
|
|
8623
|
+
const defined = { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem, lightItem, curtainItem, furnitureItem };
|
|
8624
|
+
Object.assign(K, defined);
|
|
8484
8625
|
}
|
|
8485
8626
|
|
|
8486
8627
|
// src/interaction/fittings.ts
|
|
8487
8628
|
function installInteractionFittings(K, shared) {
|
|
8488
8629
|
const { t, EPS: EPS3, OPEN_AREA, Y0, applyPiece, bx, cursor, definePiece, gates, lightOn, roomAt, slideDirection, toggleLight, togglePiece } = K;
|
|
8630
|
+
const I = () => shared.inter;
|
|
8631
|
+
const house = () => shared.ctx.r;
|
|
8489
8632
|
function gatesInteractive() {
|
|
8490
|
-
const lt =
|
|
8633
|
+
const lt = house().lot;
|
|
8491
8634
|
if (!lt) return;
|
|
8492
8635
|
const cz0 = (lt.rect[1] + lt.rect[3]) / 2;
|
|
8493
8636
|
const orig = K.getBx(), gs = lt.gates, opening = gs.map((g) => g.open), reg = gs.map((g) => {
|
|
@@ -8507,9 +8650,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8507
8650
|
return;
|
|
8508
8651
|
}
|
|
8509
8652
|
}
|
|
8510
|
-
|
|
8653
|
+
orig(mat, x0, y0, z0, x1, y1, z1, color2);
|
|
8511
8654
|
});
|
|
8512
|
-
const
|
|
8655
|
+
const colliders = shared.ctx.colliders, n0 = colliders.length;
|
|
8513
8656
|
try {
|
|
8514
8657
|
gs.forEach((g) => {
|
|
8515
8658
|
g.open = false;
|
|
@@ -8521,7 +8664,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8521
8664
|
g.open = opening[i];
|
|
8522
8665
|
});
|
|
8523
8666
|
}
|
|
8524
|
-
const cols =
|
|
8667
|
+
const cols = colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
|
|
8525
8668
|
reg.forEach((r, i) => {
|
|
8526
8669
|
const g = r.g;
|
|
8527
8670
|
if (!isFinite(r.x0)) return;
|
|
@@ -8530,25 +8673,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8530
8673
|
const p = ped ? definePiece(name, Object.assign(base, { kind: "gate_swing", pivot: [r.x0, 0, g.v], angle: -sd * 1.65 })) : tilt ? definePiece(name, Object.assign(base, { kind: "gate_tilting", pivot: [(r.x0 + r.x1) / 2, r.y1, g.v], angle: -sd * 1.45 })) : definePiece(name, Object.assign(base, { kind: "gate_sliding", pivot: [r.x0, 0, r.zm], travel: r.dx * g.width }));
|
|
8531
8674
|
if (p.col) p.col.off = p.target > 0.5;
|
|
8532
8675
|
const text = () => t(p.target > 0.5 ? "prompt.close" : "prompt.open", { what: t(ped ? "what.pedestrianGate" : "what.garageGate") });
|
|
8533
|
-
|
|
8676
|
+
I().items.push({ type: "gate", id: g.id, floor: -1, anchor: [g.u, 1, g.v + sd * 0.4], range: 2.8, angle: 0.9, pieces: [p], text, action: () => togglePiece(p), noWall: true });
|
|
8534
8677
|
});
|
|
8535
8678
|
}
|
|
8536
8679
|
function mailboxInteractive() {
|
|
8537
|
-
for (const m of
|
|
8680
|
+
for (const m of house().items) {
|
|
8538
8681
|
if (m.type !== "mailbox") continue;
|
|
8539
8682
|
const g = shared.ctx.parts && shared.ctx.parts["mailbox_" + m.id];
|
|
8540
8683
|
if (!g) continue;
|
|
8541
8684
|
const name = "ix:correio:" + m.id, def = definePiece(name, { kind: "part", pivot: [0, 0, 0], ry: 0, parent: "lot" });
|
|
8542
8685
|
def.inner = g;
|
|
8543
8686
|
const fx = Math.sin(m.ry || 0), fz = Math.cos(m.ry || 0), ay = (m.y || 1) + (m.h || 0.3) * 0.4;
|
|
8544
|
-
|
|
8687
|
+
I().items.push({ type: "mailbox", id: m.id, floor: -1, anchor: [m.x + fx * 0.2, ay, m.z + fz * 0.2], range: 2.2, angle: 0.7, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.mailbox") }), action: () => togglePiece(def), noWall: true });
|
|
8545
8688
|
applyPiece(def);
|
|
8546
8689
|
}
|
|
8547
8690
|
}
|
|
8548
8691
|
function placeSwitches() {
|
|
8549
|
-
const R =
|
|
8692
|
+
const R = house(), used = /* @__PURE__ */ new Set();
|
|
8550
8693
|
for (const c of R.rooms) {
|
|
8551
|
-
if (c.type === "void" || OPEN_AREA(c) || !
|
|
8694
|
+
if (c.type === "void" || OPEN_AREA(c) || !I().litRooms.has(c.id) || used.has(c.id) || shared.ctx.iv && shared.ctx.iv.switchRooms.has(c.id)) continue;
|
|
8552
8695
|
const doors = R.doors.filter((p) => p.floor === c.floor && (p.a === c.id || p.b === c.id));
|
|
8553
8696
|
doors.sort((p, q) => ((q.exterior ? 1 : 0) - (p.exterior ? 1 : 0)) * (c.type === "living" ? 1 : -1));
|
|
8554
8697
|
for (const p of doors) if (putSwitch(c, p)) {
|
|
@@ -8558,11 +8701,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8558
8701
|
}
|
|
8559
8702
|
}
|
|
8560
8703
|
function putSwitch(c, p) {
|
|
8561
|
-
const R =
|
|
8704
|
+
const R = house(), f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
|
|
8562
8705
|
const wref = R.walls.find((w) => w.floor === f && w.axis === p.axis && Math.abs((alongU ? w.v0 : w.u0) - L) < EPS3), th = wref ? wref.thickness || 0.15 : 0.15;
|
|
8563
8706
|
const inside2 = (sd2) => {
|
|
8564
8707
|
const cc = roomAt(f, alongU ? p.at : L + sd2 * 0.4, alongU ? L + sd2 * 0.4 : p.at);
|
|
8565
|
-
return cc && cc.id === c.id;
|
|
8708
|
+
return !!cc && cc.id === c.id;
|
|
8566
8709
|
};
|
|
8567
8710
|
const sd = inside2(1) ? 1 : inside2(-1) ? -1 : 0;
|
|
8568
8711
|
if (!sd) return false;
|
|
@@ -8585,19 +8728,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8585
8728
|
const piece2 = definePiece("ix:int:" + roomId, { kind: "light_switch", pivot: pv, ry: 0, parent: "f" + f, axis: alongU ? "x" : "z", sgn: alongU ? sd : -sd, t0: lightOn(roomId) ? 1 : 0 });
|
|
8586
8729
|
piece2.t = piece2.target = lightOn(roomId) ? 1 : 0;
|
|
8587
8730
|
const an = alongU ? [u, yc, face + sd * 0.12] : [face + sd * 0.12, yc, u];
|
|
8588
|
-
|
|
8731
|
+
I().items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece2], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
|
|
8589
8732
|
return true;
|
|
8590
8733
|
}
|
|
8591
8734
|
return false;
|
|
8592
8735
|
}
|
|
8593
|
-
|
|
8736
|
+
const defined = { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch };
|
|
8737
|
+
Object.assign(K, defined);
|
|
8594
8738
|
}
|
|
8595
8739
|
|
|
8596
8740
|
// src/interaction/doors.ts
|
|
8597
8741
|
function installInteractionDoors(K, shared) {
|
|
8598
8742
|
const { t, colliderChanged, invalidateShadow, applyPiece, hudMessage } = K;
|
|
8743
|
+
const leaves = () => shared.ctx.leaves;
|
|
8599
8744
|
function linkDoorLeaves() {
|
|
8600
|
-
|
|
8745
|
+
const I = shared.inter;
|
|
8746
|
+
for (const fo of leaves()) fo.handles = (fo.handleNames || []).map((n) => I.defs.get(n)).filter((d) => !!d);
|
|
8601
8747
|
}
|
|
8602
8748
|
function handleApply(fo) {
|
|
8603
8749
|
for (const mc of fo.handles || []) {
|
|
@@ -8607,11 +8753,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8607
8753
|
}
|
|
8608
8754
|
function toggleDoor(fo) {
|
|
8609
8755
|
if (fo.phase === "rattle") return;
|
|
8756
|
+
const col = fo.col;
|
|
8610
8757
|
if (fo.phase === "handle" || fo.phase === "swing") {
|
|
8611
8758
|
fo.open = !fo.open;
|
|
8612
8759
|
shared.doorState.set(fo.id, fo.open);
|
|
8613
|
-
|
|
8614
|
-
colliderChanged(
|
|
8760
|
+
col.off = fo.open;
|
|
8761
|
+
colliderChanged(col);
|
|
8615
8762
|
fo.anim = true;
|
|
8616
8763
|
fo.phase = "swing";
|
|
8617
8764
|
return;
|
|
@@ -8625,8 +8772,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8625
8772
|
}
|
|
8626
8773
|
fo.open = !fo.open;
|
|
8627
8774
|
shared.doorState.set(fo.id, fo.open);
|
|
8628
|
-
|
|
8629
|
-
colliderChanged(
|
|
8775
|
+
col.off = fo.open;
|
|
8776
|
+
colliderChanged(col);
|
|
8630
8777
|
fo.anim = true;
|
|
8631
8778
|
shared.ctx.animateDoorsOn = true;
|
|
8632
8779
|
if (fo.handles && fo.handles.length) {
|
|
@@ -8637,7 +8784,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8637
8784
|
function animateDoors(dt) {
|
|
8638
8785
|
if (!shared.ctx.animateDoorsOn) return;
|
|
8639
8786
|
let active = false;
|
|
8640
|
-
for (const fo of
|
|
8787
|
+
for (const fo of leaves()) {
|
|
8641
8788
|
if (!fo.phase) continue;
|
|
8642
8789
|
active = true;
|
|
8643
8790
|
if (fo.phase === "handle") {
|
|
@@ -8657,7 +8804,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8657
8804
|
handleApply(fo);
|
|
8658
8805
|
if (fo.hT <= 0) fo.phase = null;
|
|
8659
8806
|
} else if (fo.phase === "rattle") {
|
|
8660
|
-
fo.jig
|
|
8807
|
+
fo.jig = (fo.jig ?? 0) - dt;
|
|
8661
8808
|
fo.hT = fo.jig > 0 ? 0.55 * Math.abs(Math.sin(fo.jig * 26)) : 0;
|
|
8662
8809
|
handleApply(fo);
|
|
8663
8810
|
if (fo.jig <= 0) {
|
|
@@ -8671,9 +8818,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8671
8818
|
invalidateShadow();
|
|
8672
8819
|
}
|
|
8673
8820
|
function wallBlocks(ex, ez, ax, az, floor) {
|
|
8674
|
-
const n = shared.ctx.wallColliders != null ? shared.ctx.wallColliders : 0;
|
|
8821
|
+
const n = shared.ctx.wallColliders != null ? shared.ctx.wallColliders : 0, colliders = shared.ctx.colliders;
|
|
8675
8822
|
for (let i = 0; i < n; i++) {
|
|
8676
|
-
const c =
|
|
8823
|
+
const c = colliders[i];
|
|
8677
8824
|
if (c.f !== floor && !(c.f === -1 && floor === 0)) continue;
|
|
8678
8825
|
let t0 = 0, t1 = 1;
|
|
8679
8826
|
const dx = ax - ex, dz = az - ez;
|
|
@@ -8703,7 +8850,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8703
8850
|
g.updateMatrix();
|
|
8704
8851
|
}
|
|
8705
8852
|
}
|
|
8706
|
-
|
|
8853
|
+
const defined = { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf };
|
|
8854
|
+
Object.assign(K, defined);
|
|
8707
8855
|
}
|
|
8708
8856
|
|
|
8709
8857
|
// src/interaction/target.ts
|
|
@@ -8713,6 +8861,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8713
8861
|
function targetOf(o, opt) {
|
|
8714
8862
|
if (!o) return null;
|
|
8715
8863
|
opt = opt || {};
|
|
8864
|
+
const I = shared.inter;
|
|
8716
8865
|
const ex = o.x, ey = o.y, ez = o.z, floor = o.floor, cp = Math.cos(o.pitch || 0), vx = Math.sin(o.yaw) * cp, vy = Math.sin(o.pitch || 0), vz = Math.cos(o.yaw) * cp;
|
|
8717
8866
|
let best = null;
|
|
8718
8867
|
const tries = (score, text, action, target) => {
|
|
@@ -8726,16 +8875,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8726
8875
|
if (angle > 1.35 && d > 0.9) continue;
|
|
8727
8876
|
tries(angle * 1.6 + d * 0.5 + (angle < 0.25 ? 0 : 0.6), doorText(fo), () => toggleDoor(fo), fo);
|
|
8728
8877
|
}
|
|
8729
|
-
const vis =
|
|
8878
|
+
const vis = I.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
|
|
8730
8879
|
const kitA = shared.ctx.iv ? ivTarget(shared.ctx.iv, o, opt && opt.interactives) : null;
|
|
8731
8880
|
const nearKit = kitA && hit && Math.hypot(kitA.target.pos[0] - ex, kitA.target.pos[1] - ey, kitA.target.pos[2] - ez) < hit.distance + 0.1;
|
|
8732
8881
|
const pieceHit = hit && !nearKit && hit.object.userData.piece;
|
|
8733
|
-
for (const it of
|
|
8882
|
+
for (const it of I.items) {
|
|
8734
8883
|
if (it.floor !== floor && !(it.floor === -1 && floor === 0)) continue;
|
|
8735
8884
|
const [ax, ay, az] = it.anchor, dx = ax - ex, dy = ay - ey, dz = az - ez, d = Math.hypot(dx, dy, dz), dh = Math.hypot(dx, dz);
|
|
8736
8885
|
if (dh > it.range + 0.4) continue;
|
|
8737
8886
|
const angle = Math.acos(Math.max(-1, Math.min(1, (dx * vx + dy * vy + dz * vz) / (d || 1))));
|
|
8738
|
-
const byRay = pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
|
|
8887
|
+
const byRay = !!hit && pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
|
|
8739
8888
|
if (!byRay && !(dh <= it.range && angle <= it.angle)) continue;
|
|
8740
8889
|
if (!it.noWall && wallBlocks(ex, ez, ax, az, it.floor < 0 ? 0 : it.floor)) continue;
|
|
8741
8890
|
tries((byRay ? 0 : angle * 2) + d * 0.3 - (byRay ? 1.5 : 0), it.text(), it.action, it);
|
|
@@ -8743,7 +8892,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8743
8892
|
if (kitA) tries(kitA.score - (nearKit ? 0.5 : 0), kitA.text, kitA.action, kitA.target);
|
|
8744
8893
|
return best;
|
|
8745
8894
|
}
|
|
8746
|
-
|
|
8895
|
+
const defined = { targetOf };
|
|
8896
|
+
Object.assign(K, defined);
|
|
8747
8897
|
}
|
|
8748
8898
|
|
|
8749
8899
|
// src/interactables/bridge.ts
|
|
@@ -8800,7 +8950,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8800
8950
|
function ivBuild(h, water) {
|
|
8801
8951
|
const ik = K.IVK, r = shared.ctx.r, A = ik.A, world0 = null;
|
|
8802
8952
|
void world0;
|
|
8803
|
-
const
|
|
8953
|
+
const source = r;
|
|
8954
|
+
const plane2 = A.plan(source, { seed: r.seed });
|
|
8804
8955
|
const IV = { k: ik, plane: plane2, world: null, water, entries: /* @__PURE__ */ new Map(), roots: [], replace: /* @__PURE__ */ new Set(), roomStates: /* @__PURE__ */ new Map(), lampRoom: /* @__PURE__ */ new Map(), anim: /* @__PURE__ */ new Map(), screens: /* @__PURE__ */ new Map(), efx: null, items: null, itemsDirty: true, itemsT: 0, dirty: true, list: null, listT: 0, t: 0, circuits: [], switchRooms: /* @__PURE__ */ new Set(), warnings: [], tBuild: 0 };
|
|
8805
8956
|
h.IV = IV;
|
|
8806
8957
|
const t0 = performance.now();
|
|
@@ -8819,9 +8970,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8819
8970
|
const wants = (roomId) => lightBase(roomId);
|
|
8820
8971
|
const entById = new Map(plane2.items.map((e) => [e.id, e]));
|
|
8821
8972
|
const entByItem = new Map(plane2.items.map((e) => [e.item, e]));
|
|
8822
|
-
|
|
8973
|
+
const mats = shared.mats;
|
|
8974
|
+
IV.mats = { plain: mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.floor };
|
|
8823
8975
|
const ev = (e) => ivEvent(h, e);
|
|
8824
|
-
const world = IV.world = A.createWorld(
|
|
8976
|
+
const world = IV.world = A.createWorld(source, { water, seed: r.seed, onEvent: ev });
|
|
8825
8977
|
const add0 = world.add;
|
|
8826
8978
|
world.add = (id, spec, tr) => {
|
|
8827
8979
|
const e = entById.get(id);
|
|
@@ -8838,7 +8990,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8838
8990
|
}
|
|
8839
8991
|
return add0(id, spec, tr);
|
|
8840
8992
|
};
|
|
8841
|
-
const added = A.add(world, plane2, { isBlocked: A.blockedOf(
|
|
8993
|
+
const added = A.add(world, plane2, { isBlocked: A.blockedOf(source), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
|
|
8842
8994
|
world.add = add0;
|
|
8843
8995
|
IV.warnings = added.warnings;
|
|
8844
8996
|
IV.added = added;
|
|
@@ -8885,14 +9037,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8885
9037
|
}
|
|
8886
9038
|
function ivDraw(IV, ent, type, item) {
|
|
8887
9039
|
const ik = IV.k, loc = Object.assign({}, item, { x: 0, z: 0, ry: 0 });
|
|
9040
|
+
const ix = item.x, iz = item.z, iry = item.ry;
|
|
8888
9041
|
const mesh2 = ik.gfx.createMeshApi({ quality: "game", materials: IV.mats, shadows: true, mergeParts: true, swayAmplitude: 0.03 });
|
|
8889
9042
|
const spec = ik.A.household.build(type, loc, mesh2.api);
|
|
8890
9043
|
const out = mesh2.finish(spec);
|
|
8891
9044
|
for (const l of out.lights) l.removeFromParent();
|
|
8892
9045
|
const group = ivGroup(ent), g0 = cursor.group, root = new THREE.Group();
|
|
8893
9046
|
root.name = "iv:" + ent.id;
|
|
8894
|
-
root.position.set(
|
|
8895
|
-
root.rotation.y =
|
|
9047
|
+
root.position.set(ix, ent.floorY, iz);
|
|
9048
|
+
root.rotation.y = iry;
|
|
8896
9049
|
root.userData.iv = ent.id;
|
|
8897
9050
|
const screen = spec.devices && spec.devices.some((d) => d.kind === "screen");
|
|
8898
9051
|
let body = null;
|
|
@@ -8901,7 +9054,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8901
9054
|
if (type === "gas_bottle") {
|
|
8902
9055
|
cursor.pc = pieceRecord("gas_cylinder:" + ent.id, "steel", null, { floor: ent.floor, mass: 11, form: "cyl", thickness: 3e-3, fill: 0.03, contains: { fluid: "gas", liters: 13, pressurized: true }, explodes: { energy: 12e4, radius: 5, atC: 300 }, tags: ["gas_bottle"] });
|
|
8903
9056
|
for (const m of out.group.children) if (!m.name.startsWith("static:")) m.traverse((o) => {
|
|
8904
|
-
if (o
|
|
9057
|
+
if (isMesh(o)) {
|
|
8905
9058
|
o.userData.destructionPart = cursor.pc.id;
|
|
8906
9059
|
o.userData.destructionMaterial = "steel";
|
|
8907
9060
|
}
|
|
@@ -8909,13 +9062,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8909
9062
|
}
|
|
8910
9063
|
try {
|
|
8911
9064
|
for (const m of out.group.children.slice()) {
|
|
8912
|
-
if (m
|
|
9065
|
+
if (isMesh(m) && m.name.startsWith("static:")) {
|
|
8913
9066
|
if (screen && m.userData.material === "emissive") {
|
|
8914
9067
|
body = m;
|
|
8915
9068
|
root.add(m);
|
|
8916
9069
|
continue;
|
|
8917
9070
|
}
|
|
8918
|
-
ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry,
|
|
9071
|
+
ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, ix, ent.floorY, iz, iry, null);
|
|
8919
9072
|
m.geometry.dispose();
|
|
8920
9073
|
} else root.add(m);
|
|
8921
9074
|
}
|
|
@@ -8925,7 +9078,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8925
9078
|
}
|
|
8926
9079
|
const base = new Set(Object.values(IV.mats));
|
|
8927
9080
|
root.traverse((o) => {
|
|
8928
|
-
if (!o
|
|
9081
|
+
if (!isMesh(o)) return;
|
|
8929
9082
|
o.userData.iv = ent.id;
|
|
8930
9083
|
if (o.castShadow) {
|
|
8931
9084
|
if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
|
|
@@ -8936,7 +9089,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8936
9089
|
roomLightMask(m);
|
|
8937
9090
|
}
|
|
8938
9091
|
});
|
|
8939
|
-
const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [
|
|
9092
|
+
const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [ix, ent.floorY, iz], ry: iry, origin: ent.origin };
|
|
8940
9093
|
IV.entries.set(ent.id, E);
|
|
8941
9094
|
if (root.children.length) IV.roots.push(E);
|
|
8942
9095
|
return spec;
|
|
@@ -8964,7 +9117,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8964
9117
|
const wire = (spec.wires || []).find((x) => x.id === d.id + "_cord"), pts = (wire ? wire.points : [d.plug]).map((p) => wl(o, p));
|
|
8965
9118
|
const sid = w.power.pluggedInto(E.id, d.id);
|
|
8966
9119
|
if (sid) {
|
|
8967
|
-
const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && so.spec.sockets.find((s) => s.id === sid.slice(cut + 1));
|
|
9120
|
+
const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && (so.spec.sockets || []).find((s) => s.id === sid.slice(cut + 1));
|
|
8968
9121
|
if (so && sk) {
|
|
8969
9122
|
const sp = wl(so, sk.pos), dir = [Math.sin(so.transform.ry), Math.cos(so.transform.ry)], last = pts[pts.length - 1];
|
|
8970
9123
|
if (last[1] < 0.3 + E.pos[1]) {
|
|
@@ -8999,9 +9152,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8999
9152
|
roomLightMask(sc.material);
|
|
9000
9153
|
IV.screens.set(E.id, sc);
|
|
9001
9154
|
}
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9155
|
+
const mesh2 = E.screen;
|
|
9156
|
+
mesh2.material = sc.material;
|
|
9157
|
+
mesh2.castShadow = false;
|
|
9158
|
+
mesh2.receiveShadow = false;
|
|
9005
9159
|
}
|
|
9006
9160
|
function ivEvent(h, e) {
|
|
9007
9161
|
const IV = h.IV;
|
|
@@ -9037,16 +9191,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9037
9191
|
IV.itemsDirty = true;
|
|
9038
9192
|
break;
|
|
9039
9193
|
}
|
|
9040
|
-
|
|
9194
|
+
const ik = K.IVK;
|
|
9195
|
+
if (ik.onEvent) {
|
|
9041
9196
|
try {
|
|
9042
|
-
|
|
9197
|
+
ik.onEvent(e, IV.pub);
|
|
9043
9198
|
} catch (err) {
|
|
9044
9199
|
console.warn("interactables.onEvent", err);
|
|
9045
9200
|
}
|
|
9046
9201
|
}
|
|
9047
|
-
if (e.type === "seat" &&
|
|
9202
|
+
if (e.type === "seat" && ik.onSeat && e.actor === "player") {
|
|
9048
9203
|
try {
|
|
9049
|
-
|
|
9204
|
+
ik.onSeat(e.seated ? ivSeat(IV) : null, e);
|
|
9050
9205
|
} catch (err) {
|
|
9051
9206
|
console.warn("interactables.onSeat", err);
|
|
9052
9207
|
}
|
|
@@ -9055,7 +9210,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9055
9210
|
function ivSeat(IV) {
|
|
9056
9211
|
const w = IV.world, s = w.seatOf("player");
|
|
9057
9212
|
if (!s) return null;
|
|
9058
|
-
const o = w.get(s.object), seat = o.spec.seats.find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
|
|
9213
|
+
const o = w.get(s.object), seat = (o.spec.seats || []).find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
|
|
9059
9214
|
const eye = L(tr, [seat.pos[0], seat.pos[1] + (seat.eye === void 0 ? seat.pose === "lie" ? 0.18 : 0.62 : seat.eye), seat.pos[2]]);
|
|
9060
9215
|
return { object: s.object, seatInfo: s.seat, pose: seat.pose, eye, yaw: tr.ry + seat.ry, pitch: seat.pose === "lie" ? 0.55 : -0.08, exitPoint: L(tr, seat.exit), floor: E ? E.floor : 0, type: E ? E.type : null };
|
|
9061
9216
|
}
|
|
@@ -9097,18 +9252,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9097
9252
|
}
|
|
9098
9253
|
}
|
|
9099
9254
|
const em = w.emitters();
|
|
9100
|
-
|
|
9255
|
+
const ivk = K.IVK;
|
|
9256
|
+
if (em.length && !IV.efx && ivk.effects) {
|
|
9101
9257
|
const g = h.houseGroup;
|
|
9102
|
-
IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...
|
|
9258
|
+
IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...ivk.effectSink ? { effects: ivk.effectSink } : {} });
|
|
9103
9259
|
}
|
|
9104
9260
|
if (IV.efx) {
|
|
9105
9261
|
const alive = IV.efx.stats().alive;
|
|
9106
9262
|
if (em.length || alive) {
|
|
9107
|
-
IV.efx.update(dt, em,
|
|
9263
|
+
IV.efx.update(dt, em, ivk.camera ? typeof ivk.camera === "function" ? ivk.camera() : ivk.camera : void 0);
|
|
9108
9264
|
invalidate();
|
|
9109
9265
|
}
|
|
9110
9266
|
}
|
|
9111
|
-
if (
|
|
9267
|
+
if (ivk.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
|
|
9112
9268
|
}
|
|
9113
9269
|
const IV_SHAPE = {
|
|
9114
9270
|
can: [["cyl", 1, 1, 1, 0, 1]],
|
|
@@ -9143,7 +9299,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9143
9299
|
if (c.access && w.partT(E.id, c.access) < 0.02) continue;
|
|
9144
9300
|
const st = w.contents(E.id, c.id);
|
|
9145
9301
|
for (let i = 0; i < st.length; i++) {
|
|
9146
|
-
|
|
9302
|
+
const stack = st[i];
|
|
9303
|
+
if (stack && items[stack.type]) list2.push([E, c.id, i, items[stack.type]]);
|
|
9147
9304
|
}
|
|
9148
9305
|
}
|
|
9149
9306
|
}
|
|
@@ -9172,12 +9329,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9172
9329
|
gm.setIndex(new THREE.BufferAttribute(A.i.slice(0, A.ni), 1));
|
|
9173
9330
|
gm.computeBoundingSphere();
|
|
9174
9331
|
if (!IV.items) {
|
|
9175
|
-
|
|
9176
|
-
IV.items
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9332
|
+
const mesh2 = new THREE.Mesh(gm, shared.mats.plain);
|
|
9333
|
+
IV.items = mesh2;
|
|
9334
|
+
mesh2.name = "iv-items";
|
|
9335
|
+
mesh2.castShadow = false;
|
|
9336
|
+
mesh2.receiveShadow = true;
|
|
9337
|
+
mesh2.frustumCulled = false;
|
|
9338
|
+
h.houseGroup.add(mesh2);
|
|
9181
9339
|
} else {
|
|
9182
9340
|
IV.items.geometry.dispose();
|
|
9183
9341
|
IV.items.geometry = gm;
|
|
@@ -9311,7 +9469,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9311
9469
|
};
|
|
9312
9470
|
return IV.pub;
|
|
9313
9471
|
}
|
|
9314
|
-
|
|
9472
|
+
const defined = { IV_MATERIAL, IV_WIRE, IV_DOOR, ivGroup, ivAccumulate, ivBuild, ivRoomEffective, ivDraw, ivCords, ivAssemble, ivScreen, ivEvent, ivSeat, ivUpdate, IV_SHAPE, ivItems, ivTarget, ivRoomLight, ivParts, ivDispose, ivPublish };
|
|
9473
|
+
Object.assign(K, defined);
|
|
9315
9474
|
}
|
|
9316
9475
|
|
|
9317
9476
|
// src/animation/clotheslines.ts
|
|
@@ -9336,7 +9495,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9336
9495
|
}
|
|
9337
9496
|
invalidate();
|
|
9338
9497
|
}
|
|
9339
|
-
|
|
9498
|
+
const defined = { WIND, animateClotheslines };
|
|
9499
|
+
Object.assign(K, defined);
|
|
9340
9500
|
}
|
|
9341
9501
|
|
|
9342
9502
|
// src/build/instance.ts
|
|
@@ -9361,7 +9521,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9361
9521
|
shared.quality = h.quality;
|
|
9362
9522
|
}
|
|
9363
9523
|
const tagDamage = (type) => ({ type, hp: HP[type], hpMax: HP[type] });
|
|
9364
|
-
|
|
9524
|
+
const defined = { props, TYPES, newState, enter, tagDamage };
|
|
9525
|
+
Object.assign(K, defined);
|
|
9365
9526
|
}
|
|
9366
9527
|
|
|
9367
9528
|
// ../game-floorplan-interactables/dist/index.js
|
|
@@ -10748,17 +10909,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10748
10909
|
for (const k of ["wood", "foliage", "flowers", "fruit", "spines"]) roomLightMask(m[k]);
|
|
10749
10910
|
return m;
|
|
10750
10911
|
})());
|
|
10751
|
-
|
|
10912
|
+
const defined = { IVK, VEG, vegMaterials };
|
|
10913
|
+
Object.assign(K, defined);
|
|
10752
10914
|
}
|
|
10753
10915
|
|
|
10754
10916
|
// src/lights/room-light.ts
|
|
10917
|
+
var newGroup = (k, house, exterior) => ({ k, house, ls: [], exterior, pos: [0, 0, 0], color: 0, n: 0, range: 0, rects: [], y: [0, 0], exclusion: null, lumens: 0, dist: 0, decay: 0, floor: 0, roomId: null, dm: 0, d: 0 });
|
|
10755
10918
|
function installLightsRoomLight(K, shared) {
|
|
10756
10919
|
const { THREE, rectsOf: rectsOf2, cfg } = K;
|
|
10757
10920
|
const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
|
|
10758
10921
|
const LZU = { uRB0: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB1: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB2: { value: new Float32Array(MAX_LIGHTS * 4) }, uRBY: { value: new Float32Array(MAX_LIGHTS * 2) }, uREx: { value: new Float32Array(MAX_LIGHTS * 4) }, uIndK: { value: 0.06 } };
|
|
10759
10922
|
for (let i = 0; i < MAX_LIGHTS; i++) for (const k of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[k].value.set(EMPTY, i * 4);
|
|
10760
|
-
function roomLightMask(
|
|
10761
|
-
|
|
10923
|
+
function roomLightMask(material) {
|
|
10924
|
+
const m = material;
|
|
10925
|
+
if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return material;
|
|
10762
10926
|
m.userData = m.userData || {};
|
|
10763
10927
|
m.userData.roomLightMask = true;
|
|
10764
10928
|
const prev = m.onBeforeCompile, pk = m.customProgramCacheKey;
|
|
@@ -10786,12 +10950,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10786
10950
|
return (pk ? pk.call(this) : "") + "|rm1";
|
|
10787
10951
|
};
|
|
10788
10952
|
m.needsUpdate = true;
|
|
10789
|
-
return
|
|
10953
|
+
return material;
|
|
10790
10954
|
}
|
|
10791
|
-
function lighting(
|
|
10792
|
-
o =
|
|
10955
|
+
function lighting(options) {
|
|
10956
|
+
const o = options || {};
|
|
10793
10957
|
const scene = o.scene, N = Math.max(1, Math.min(MAX_LIGHTS, o.n || 6)), NS = Math.max(0, Math.min(N, o.shadows != null ? o.shadows : 2)), size = o.shadowSize || 512, MAX_EXTERNAL = o.external != null ? o.external : 2;
|
|
10794
|
-
|
|
10958
|
+
const mats = shared.mats;
|
|
10959
|
+
for (const k of Object.keys(mats)) roomLightMask(mats[k]);
|
|
10795
10960
|
const budget = o.budget, lease = budget ? budget.lease({ owner: "floorplan.rooms", point: N, shadows: NS }) : null;
|
|
10796
10961
|
if (budget && !lease) throw new Error("lighting: the LightBudget has no " + N + " free point slots (" + NS + " with shadow) for the rooms");
|
|
10797
10962
|
if (budget) for (const [key, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
|
|
@@ -10842,9 +11007,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10842
11007
|
}
|
|
10843
11008
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
10844
11009
|
};
|
|
10845
|
-
A.update = function(
|
|
10846
|
-
op =
|
|
10847
|
-
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
11010
|
+
A.update = function(houseOrList, focus, options2) {
|
|
11011
|
+
const op = options2 || {}, houses2 = (Array.isArray(houseOrList) ? houseOrList : [houseOrList]).filter((h) => !!h);
|
|
10848
11012
|
_f.set(focus.x, focus.y, focus.z);
|
|
10849
11013
|
const rooms = [], exterior = [];
|
|
10850
11014
|
for (const house of houses2) {
|
|
@@ -10856,7 +11020,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10856
11020
|
if (!house.lightOn(l.roomId)) continue;
|
|
10857
11021
|
const k = l.type === "outdoor" ? "ext:" + (l.id || exterior.length) : l.roomId != null ? l.roomId : l.room;
|
|
10858
11022
|
let g = by.get(k);
|
|
10859
|
-
if (!g) by.set(k, g =
|
|
11023
|
+
if (!g) by.set(k, g = newGroup(k, house, l.type === "outdoor"));
|
|
10860
11024
|
g.ls.push(l);
|
|
10861
11025
|
}
|
|
10862
11026
|
for (const g of by.values()) {
|
|
@@ -10891,9 +11055,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10891
11055
|
}
|
|
10892
11056
|
}
|
|
10893
11057
|
g.exclusion = [x0 + 0.03, z0 + 0.03, x1 - 0.03, z1 - 0.03];
|
|
10894
|
-
|
|
10895
|
-
g.
|
|
10896
|
-
g.
|
|
11058
|
+
const l0 = ls[0];
|
|
11059
|
+
g.lumens = l0.lumens != null ? l0.lumens : 3.2;
|
|
11060
|
+
g.dist = l0.dist != null ? l0.dist : 5.5;
|
|
11061
|
+
g.decay = l0.decay != null ? l0.decay : 2;
|
|
10897
11062
|
} else {
|
|
10898
11063
|
const c = house.r.rooms.find((q) => q.id === g.k);
|
|
10899
11064
|
if (!c) continue;
|
|
@@ -10994,8 +11159,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10994
11159
|
}
|
|
10995
11160
|
const effectsByBudget = /* @__PURE__ */ new WeakMap();
|
|
10996
11161
|
const OPENING_REACH = 2.5, OPENING_SIDE = 0.6;
|
|
10997
|
-
function effectLights(
|
|
10998
|
-
o =
|
|
11162
|
+
function effectLights(options) {
|
|
11163
|
+
const o = options || {};
|
|
10999
11164
|
const budget = o.budget;
|
|
11000
11165
|
if (!budget) throw new Error("effectLights: a LightBudget is required");
|
|
11001
11166
|
const known = effectsByBudget.get(budget);
|
|
@@ -11073,7 +11238,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11073
11238
|
const A = {
|
|
11074
11239
|
/** Once per frame, after the budget's `present`: points the mask of every lit slot that is not the house's at the rooms its light reaches. */
|
|
11075
11240
|
update(houses2) {
|
|
11076
|
-
const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(
|
|
11241
|
+
const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter((h) => !!h), cache2 = /* @__PURE__ */ new Map();
|
|
11077
11242
|
for (let at2 = 0; at2 < size; at2++) {
|
|
11078
11243
|
if (ours.has(at2)) continue;
|
|
11079
11244
|
const light = budget.group.children[at2];
|
|
@@ -11101,7 +11266,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11101
11266
|
if (!o.ours) effectsByBudget.set(budget, A);
|
|
11102
11267
|
return A;
|
|
11103
11268
|
}
|
|
11104
|
-
|
|
11269
|
+
const defined = { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights };
|
|
11270
|
+
Object.assign(K, defined);
|
|
11105
11271
|
}
|
|
11106
11272
|
|
|
11107
11273
|
// ../game-destruction/dist/index.js
|
|
@@ -11433,6 +11599,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11433
11599
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
11434
11600
|
};
|
|
11435
11601
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
11602
|
+
var splitAlong = (box3, count, axis, rnd) => {
|
|
11603
|
+
const shares = Array.from({ length: count }, () => 0.25 + 1.5 * rnd());
|
|
11604
|
+
const total = shares.reduce((sum, share) => sum + share, 0);
|
|
11605
|
+
const out = [];
|
|
11606
|
+
let from = box3.c[axis] - box3.s[axis] / 2;
|
|
11607
|
+
for (const share of shares) {
|
|
11608
|
+
const length = box3.s[axis] * share / total;
|
|
11609
|
+
const c = [box3.c[0], box3.c[1], box3.c[2]];
|
|
11610
|
+
const size = [box3.s[0], box3.s[1], box3.s[2]];
|
|
11611
|
+
c[axis] = from + length / 2;
|
|
11612
|
+
size[axis] = length;
|
|
11613
|
+
out.push({ c, s: size });
|
|
11614
|
+
from += length;
|
|
11615
|
+
}
|
|
11616
|
+
return out;
|
|
11617
|
+
};
|
|
11436
11618
|
var splinterBox = (inp, box3, limit = inp.maxFragments) => {
|
|
11437
11619
|
const { rnd } = inp;
|
|
11438
11620
|
const dims = box3.s;
|
|
@@ -11442,35 +11624,81 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11442
11624
|
const w = Math.max(fmin * 1.5, 0.01);
|
|
11443
11625
|
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
11444
11626
|
const maxLen = fmax * 4;
|
|
11445
|
-
const cells =
|
|
11627
|
+
const cells = [];
|
|
11628
|
+
for (const cell of bsp(box3, c, [a, b], rnd)) {
|
|
11629
|
+
const wide = cell.s[a] >= cell.s[b] ? a : b;
|
|
11630
|
+
if (rnd() < 0.4 && cell.s[wide] > fmin * 0.5) for (const part of splitAlong(cell, 2, wide, rnd)) cells.push(part);
|
|
11631
|
+
else cells.push(cell);
|
|
11632
|
+
}
|
|
11446
11633
|
const pieces = [];
|
|
11447
11634
|
for (const cell of cells) {
|
|
11448
|
-
const extra = rnd()
|
|
11635
|
+
const extra = Math.floor(rnd() * 3);
|
|
11449
11636
|
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
11450
|
-
for (const p of
|
|
11637
|
+
for (const p of splitAlong(cell, k, g, rnd)) pieces.push(p);
|
|
11451
11638
|
}
|
|
11452
11639
|
return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
|
|
11453
11640
|
};
|
|
11641
|
+
var PLY = 3e-3;
|
|
11642
|
+
var PLY_GAP = 0.6;
|
|
11643
|
+
var PLY_SHEET = 0.012;
|
|
11644
|
+
var plyBreak = (inp, root, limit) => {
|
|
11645
|
+
const { rnd } = inp;
|
|
11646
|
+
const dims = root.s;
|
|
11647
|
+
const sorted = [0, 1, 2].sort((x, y) => dims[x] - dims[y]);
|
|
11648
|
+
const t = sorted[0];
|
|
11649
|
+
const [u, v] = [sorted[1], sorted[2]].sort((x, y) => x - y);
|
|
11650
|
+
const along = dims[u] >= dims[v] ? u : v;
|
|
11651
|
+
const across = along === u ? v : u;
|
|
11652
|
+
const layers = clamp(Math.round(dims[t] / PLY / 2), 2, 3);
|
|
11653
|
+
const pitch = dims[t] / layers;
|
|
11654
|
+
const th = Math.min(pitch, PLY_SHEET);
|
|
11655
|
+
const per = Math.max(2, Math.floor(limit / layers));
|
|
11656
|
+
const out = [];
|
|
11657
|
+
for (let k = 0; k < layers; k++) {
|
|
11658
|
+
const layer = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
11659
|
+
layer.c[t] = root.c[t] + (-dims[t] / 2 + (k + 0.5) * pitch) * (pitch > PLY_SHEET ? 1 : 1 + PLY_GAP);
|
|
11660
|
+
layer.s[t] = th;
|
|
11661
|
+
for (const cell of bsp(layer, per, [u, v], rnd)) {
|
|
11662
|
+
if (out.length >= limit) return out;
|
|
11663
|
+
if (rnd() < 0.35) {
|
|
11664
|
+
const strand = cell.s[across] * (0.15 + 0.2 * rnd());
|
|
11665
|
+
out.push({ center: cell.c, size: [cell.s[along], strand, th * 0.7], q: frame(along, across, t), shape: "splinter", weight: cell.s[along] * strand * th });
|
|
11666
|
+
} else {
|
|
11667
|
+
out.push({ center: cell.c, size: [cell.s[u], cell.s[v], th], q: frame(u, v, t, (rnd() - 0.5) * 0.5), shape: "scrap", weight: cell.s[u] * cell.s[v] * th });
|
|
11668
|
+
}
|
|
11669
|
+
}
|
|
11670
|
+
}
|
|
11671
|
+
return out;
|
|
11672
|
+
};
|
|
11673
|
+
var granules = (inp, box3, count) => bsp(box3, count, [0, 1, 2], inp.rnd).map((b) => ({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] }));
|
|
11674
|
+
var CRUMBS = 6;
|
|
11454
11675
|
var severAt = (inp, root, at2, gap) => {
|
|
11455
11676
|
const dims = root.s;
|
|
11456
11677
|
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
11457
11678
|
const half = dims[L] / 2;
|
|
11458
11679
|
const lo = clamp(at2 - gap / 2, -half, half), hi = clamp(at2 + gap / 2, -half, half);
|
|
11459
11680
|
const out = [];
|
|
11460
|
-
const
|
|
11681
|
+
const fibrous = inp.form === "slivers" || inp.form === "plies";
|
|
11682
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== L);
|
|
11683
|
+
const stub = (from, to, breakAtEnd) => {
|
|
11461
11684
|
if (to - from < 0.02) return;
|
|
11462
11685
|
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
11463
11686
|
c[L] = (from + to) / 2;
|
|
11464
11687
|
sz[L] = to - from;
|
|
11465
|
-
|
|
11688
|
+
const weight = sz[0] * sz[1] * sz[2];
|
|
11689
|
+
if (fibrous) out.push({ center: c, size: [sz[L], sz[a], sz[b]], q: frame(L, a, b, breakAtEnd ? 0 : Math.PI), shape: "slab", weight });
|
|
11690
|
+
else out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight });
|
|
11466
11691
|
};
|
|
11467
|
-
stub(-half, lo);
|
|
11468
|
-
stub(hi, half);
|
|
11692
|
+
stub(-half, lo, true);
|
|
11693
|
+
stub(hi, half, false);
|
|
11469
11694
|
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
11470
11695
|
band.c[L] = (lo + hi) / 2;
|
|
11471
11696
|
band.s[L] = Math.max(hi - lo, 0.01);
|
|
11472
|
-
|
|
11473
|
-
|
|
11697
|
+
const room = inp.maxFragments - out.length;
|
|
11698
|
+
if (inp.style === "snap" && inp.form === "plies") for (const p of plyBreak(inp, band, Math.max(3, room))) out.push(p);
|
|
11699
|
+
else if (inp.style === "snap" && inp.form === "granules") for (const p of granules(inp, band, clamp(room, 3, 12))) out.push(p);
|
|
11700
|
+
else if (inp.style === "snap") {
|
|
11701
|
+
for (const b2 of bsp(band, Math.max(3, Math.min(6, room)), [0, 1, 2], inp.rnd)) out.push({ center: b2.c, size: b2.s, q: quat.identity(), shape: "chunk", weight: b2.s[0] * b2.s[1] * b2.s[2] });
|
|
11474
11702
|
} else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
11475
11703
|
return out;
|
|
11476
11704
|
};
|
|
@@ -11503,8 +11731,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11503
11731
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
11504
11732
|
if (style === "snap") {
|
|
11505
11733
|
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
11734
|
+
if (inp.form === "plies") return plyBreak(inp, root, maxFragments);
|
|
11506
11735
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd() * 3));
|
|
11507
11736
|
for (const b of bsp(root, n2, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
11737
|
+
if (inp.form !== "granules") return out;
|
|
11738
|
+
const crumbs = Math.min(CRUMBS, maxFragments - out.length);
|
|
11739
|
+
if (crumbs <= 0) return out;
|
|
11740
|
+
const band = { c: [0, 0, 0], s: [0, 0, 0] };
|
|
11741
|
+
for (let i = 0; i < 3; i++) {
|
|
11742
|
+
band.s[i] = Math.min(dims[i], Math.max(fmin, dims[i] * 0.2));
|
|
11743
|
+
band.c[i] = clamp(inp.hit[i], -dims[i] / 2 + band.s[i] / 2, dims[i] / 2 - band.s[i] / 2);
|
|
11744
|
+
}
|
|
11745
|
+
for (const p of granules(inp, band, crumbs)) out.push({ ...p, weight: p.weight * 0.5 });
|
|
11508
11746
|
return out;
|
|
11509
11747
|
}
|
|
11510
11748
|
if (style === "crumble" || style === "none") {
|
|
@@ -11611,6 +11849,88 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11611
11849
|
}
|
|
11612
11850
|
return marks;
|
|
11613
11851
|
};
|
|
11852
|
+
var JOINT_GAP = 1e-4;
|
|
11853
|
+
var MIN_BEARING_SHARE = 0.25;
|
|
11854
|
+
var unsupportedCells = (cells, thin, dims, standing) => {
|
|
11855
|
+
if (thin === 1) return [];
|
|
11856
|
+
const [u, v] = planeAxes(thin);
|
|
11857
|
+
const bottom = -dims[v] / 2;
|
|
11858
|
+
const rowOf = (y) => Math.round((y - bottom) * 1e4);
|
|
11859
|
+
const rows = /* @__PURE__ */ new Map();
|
|
11860
|
+
for (let i = 0; i < cells.length; i++) {
|
|
11861
|
+
if (!standing(i)) continue;
|
|
11862
|
+
const cell = cells[i];
|
|
11863
|
+
const key = rowOf(cell.center[v] - cell.size[v] / 2);
|
|
11864
|
+
const row = rows.get(key);
|
|
11865
|
+
if (row) row.push(i);
|
|
11866
|
+
else rows.set(key, [i]);
|
|
11867
|
+
}
|
|
11868
|
+
const held = /* @__PURE__ */ new Set();
|
|
11869
|
+
const queue = [];
|
|
11870
|
+
for (const i of rows.get(0) ?? []) {
|
|
11871
|
+
held.add(i);
|
|
11872
|
+
queue.push(i);
|
|
11873
|
+
}
|
|
11874
|
+
const overlap = (a, b) => Math.min(a.center[u] + a.size[u] / 2, b.center[u] + b.size[u] / 2) - Math.max(a.center[u] - a.size[u] / 2, b.center[u] - b.size[u] / 2);
|
|
11875
|
+
const climb = () => {
|
|
11876
|
+
while (queue.length > 0) {
|
|
11877
|
+
const cell = cells[queue.pop()];
|
|
11878
|
+
for (const j of rows.get(rowOf(cell.center[v] + cell.size[v] / 2)) ?? []) {
|
|
11879
|
+
const other = cells[j];
|
|
11880
|
+
if (held.has(j) || overlap(cell, other) <= Math.max(JOINT_GAP, MIN_BEARING_SHARE * Math.min(cell.size[u], other.size[u]))) continue;
|
|
11881
|
+
held.add(j);
|
|
11882
|
+
queue.push(j);
|
|
11883
|
+
}
|
|
11884
|
+
}
|
|
11885
|
+
};
|
|
11886
|
+
for (const row of rows.values()) row.sort((a, b) => cells[a].center[u] - cells[b].center[u]);
|
|
11887
|
+
const touching = (a, b) => Math.abs(a.center[u] + a.size[u] / 2 - (b.center[u] - b.size[u] / 2)) <= 1e-3;
|
|
11888
|
+
for (let wedged = true; wedged; ) {
|
|
11889
|
+
climb();
|
|
11890
|
+
wedged = false;
|
|
11891
|
+
for (const row of rows.values()) {
|
|
11892
|
+
for (let k = 1; k < row.length - 1; k++) {
|
|
11893
|
+
const i = row[k];
|
|
11894
|
+
if (held.has(i) || !held.has(row[k - 1]) || !held.has(row[k + 1])) continue;
|
|
11895
|
+
if (!touching(cells[row[k - 1]], cells[i]) || !touching(cells[i], cells[row[k + 1]])) continue;
|
|
11896
|
+
held.add(i);
|
|
11897
|
+
queue.push(i);
|
|
11898
|
+
wedged = true;
|
|
11899
|
+
}
|
|
11900
|
+
}
|
|
11901
|
+
}
|
|
11902
|
+
const loose = [];
|
|
11903
|
+
for (const row of rows.values()) for (const i of row) if (!held.has(i)) loose.push(i);
|
|
11904
|
+
return loose;
|
|
11905
|
+
};
|
|
11906
|
+
var clumpCells = (cells, thin, cap) => {
|
|
11907
|
+
if (cells.length <= cap) return [...cells];
|
|
11908
|
+
const [u, v] = planeAxes(thin);
|
|
11909
|
+
let lo0 = Infinity, lo1 = Infinity, hi0 = -Infinity, hi1 = -Infinity;
|
|
11910
|
+
for (const cell of cells) {
|
|
11911
|
+
lo0 = Math.min(lo0, cell.center[u] - cell.size[u] / 2);
|
|
11912
|
+
hi0 = Math.max(hi0, cell.center[u] + cell.size[u] / 2);
|
|
11913
|
+
lo1 = Math.min(lo1, cell.center[v] - cell.size[v] / 2);
|
|
11914
|
+
hi1 = Math.max(hi1, cell.center[v] + cell.size[v] / 2);
|
|
11915
|
+
}
|
|
11916
|
+
let side = Math.sqrt((hi0 - lo0) * (hi1 - lo1) / cap);
|
|
11917
|
+
for (; ; ) {
|
|
11918
|
+
const bins = /* @__PURE__ */ new Map();
|
|
11919
|
+
for (const cell of cells) {
|
|
11920
|
+
const key = `${Math.floor((cell.center[u] - lo0) / side)}:${Math.floor((cell.center[v] - lo1) / side)}`;
|
|
11921
|
+
const bin = bins.get(key) ?? { lo: [Infinity, Infinity, Infinity], hi: [-Infinity, -Infinity, -Infinity] };
|
|
11922
|
+
for (let k = 0; k < 3; k++) {
|
|
11923
|
+
bin.lo[k] = Math.min(bin.lo[k], cell.center[k] - cell.size[k] / 2);
|
|
11924
|
+
bin.hi[k] = Math.max(bin.hi[k], cell.center[k] + cell.size[k] / 2);
|
|
11925
|
+
}
|
|
11926
|
+
bins.set(key, bin);
|
|
11927
|
+
}
|
|
11928
|
+
if (bins.size <= cap) {
|
|
11929
|
+
return [...bins.values()].map(({ lo, hi }) => ({ center: [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2], size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]] }));
|
|
11930
|
+
}
|
|
11931
|
+
side *= 1.25;
|
|
11932
|
+
}
|
|
11933
|
+
};
|
|
11614
11934
|
var MAX_SPALLS = 64;
|
|
11615
11935
|
var thinAxisOf = (dims) => dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2;
|
|
11616
11936
|
var resolveLayer = (def, index, mat) => ({ index, def, mat, energy: mat.penetration * def.thickness * 1e3 });
|
|
@@ -12590,6 +12910,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12590
12910
|
},
|
|
12591
12911
|
{
|
|
12592
12912
|
id: "wood_soft",
|
|
12913
|
+
splitForm: "slivers",
|
|
12593
12914
|
density: 500,
|
|
12594
12915
|
hpPerKg: 90,
|
|
12595
12916
|
penetration: 9,
|
|
@@ -12635,6 +12956,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12635
12956
|
},
|
|
12636
12957
|
{
|
|
12637
12958
|
id: "wood_hard",
|
|
12959
|
+
splitForm: "slivers",
|
|
12638
12960
|
density: 750,
|
|
12639
12961
|
hpPerKg: 140,
|
|
12640
12962
|
penetration: 14,
|
|
@@ -12679,6 +13001,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12679
13001
|
},
|
|
12680
13002
|
{
|
|
12681
13003
|
id: "plywood",
|
|
13004
|
+
splitForm: "plies",
|
|
12682
13005
|
density: 600,
|
|
12683
13006
|
hpPerKg: 70,
|
|
12684
13007
|
penetration: 7,
|
|
@@ -12726,6 +13049,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12726
13049
|
},
|
|
12727
13050
|
{
|
|
12728
13051
|
id: "mdf",
|
|
13052
|
+
splitForm: "granules",
|
|
12729
13053
|
density: 750,
|
|
12730
13054
|
hpPerKg: 45,
|
|
12731
13055
|
penetration: 6,
|
|
@@ -12892,6 +13216,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12892
13216
|
floor: 60
|
|
12893
13217
|
}
|
|
12894
13218
|
},
|
|
13219
|
+
ricochetDeg: 12,
|
|
12895
13220
|
hitDebris: "chips",
|
|
12896
13221
|
breakDebris: "dust",
|
|
12897
13222
|
visual: { innerColor: 10197652 },
|
|
@@ -12923,6 +13248,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12923
13248
|
0.04,
|
|
12924
13249
|
0.12
|
|
12925
13250
|
],
|
|
13251
|
+
ricochetDeg: 10,
|
|
12926
13252
|
hitDebris: "chips",
|
|
12927
13253
|
breakDebris: "dust",
|
|
12928
13254
|
visual: { innerColor: 12085567 },
|
|
@@ -12980,6 +13306,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12980
13306
|
0.06,
|
|
12981
13307
|
0.3
|
|
12982
13308
|
],
|
|
13309
|
+
ricochetDeg: 15,
|
|
12983
13310
|
hitDebris: "chips",
|
|
12984
13311
|
breakDebris: "dust",
|
|
12985
13312
|
visual: { innerColor: 9407364 },
|
|
@@ -13237,6 +13564,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13237
13564
|
},
|
|
13238
13565
|
{
|
|
13239
13566
|
id: "green_wood",
|
|
13567
|
+
splitForm: "slivers",
|
|
13240
13568
|
density: 650,
|
|
13241
13569
|
hpPerKg: 5,
|
|
13242
13570
|
penetration: 10,
|
|
@@ -13407,6 +13735,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13407
13735
|
0.03,
|
|
13408
13736
|
0.15
|
|
13409
13737
|
],
|
|
13738
|
+
ricochetDeg: 8,
|
|
13410
13739
|
hitDebris: "chips",
|
|
13411
13740
|
breakDebris: "dust",
|
|
13412
13741
|
thermal: {
|
|
@@ -13506,6 +13835,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13506
13835
|
0.02,
|
|
13507
13836
|
0.08
|
|
13508
13837
|
],
|
|
13838
|
+
ricochetDeg: 8,
|
|
13509
13839
|
hitDebris: "chips",
|
|
13510
13840
|
breakDebris: "dust",
|
|
13511
13841
|
thermal: {
|
|
@@ -13517,6 +13847,127 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13517
13847
|
"brittle"
|
|
13518
13848
|
],
|
|
13519
13849
|
compressive: 1e5
|
|
13850
|
+
},
|
|
13851
|
+
{
|
|
13852
|
+
id: "mud",
|
|
13853
|
+
density: 1700,
|
|
13854
|
+
hpPerKg: 1,
|
|
13855
|
+
penetration: 5,
|
|
13856
|
+
ductility: 0.8,
|
|
13857
|
+
fracture: "crumble",
|
|
13858
|
+
fragmentSize: [
|
|
13859
|
+
0.02,
|
|
13860
|
+
0.08
|
|
13861
|
+
],
|
|
13862
|
+
hitDebris: "dust",
|
|
13863
|
+
breakDebris: "dust",
|
|
13864
|
+
thermal: {
|
|
13865
|
+
conductivity: 0.5,
|
|
13866
|
+
heatCapacity: 3.2
|
|
13867
|
+
},
|
|
13868
|
+
tags: [
|
|
13869
|
+
"soil",
|
|
13870
|
+
"wet"
|
|
13871
|
+
],
|
|
13872
|
+
compressive: 5e3
|
|
13873
|
+
},
|
|
13874
|
+
{
|
|
13875
|
+
id: "clay",
|
|
13876
|
+
density: 1800,
|
|
13877
|
+
hpPerKg: 5,
|
|
13878
|
+
penetration: 7,
|
|
13879
|
+
ductility: 0.05,
|
|
13880
|
+
fracture: "crumble",
|
|
13881
|
+
fragmentSize: [
|
|
13882
|
+
0.02,
|
|
13883
|
+
0.1
|
|
13884
|
+
],
|
|
13885
|
+
hitDebris: "chips",
|
|
13886
|
+
breakDebris: "dust",
|
|
13887
|
+
thermal: {
|
|
13888
|
+
conductivity: 0.15,
|
|
13889
|
+
heatCapacity: 2.2
|
|
13890
|
+
},
|
|
13891
|
+
tags: [
|
|
13892
|
+
"soil",
|
|
13893
|
+
"brittle"
|
|
13894
|
+
],
|
|
13895
|
+
compressive: 6e4
|
|
13896
|
+
},
|
|
13897
|
+
{
|
|
13898
|
+
id: "snow",
|
|
13899
|
+
density: 300,
|
|
13900
|
+
hpPerKg: 1,
|
|
13901
|
+
penetration: 3,
|
|
13902
|
+
ductility: 0.6,
|
|
13903
|
+
fracture: "crumble",
|
|
13904
|
+
fragmentSize: [
|
|
13905
|
+
0.01,
|
|
13906
|
+
0.05
|
|
13907
|
+
],
|
|
13908
|
+
hitDebris: "dust",
|
|
13909
|
+
breakDebris: "dust",
|
|
13910
|
+
thermal: {
|
|
13911
|
+
conductivity: 0.1,
|
|
13912
|
+
heatCapacity: 2.1
|
|
13913
|
+
},
|
|
13914
|
+
tags: [
|
|
13915
|
+
"soil",
|
|
13916
|
+
"frozen"
|
|
13917
|
+
],
|
|
13918
|
+
compressive: 1e3
|
|
13919
|
+
},
|
|
13920
|
+
{
|
|
13921
|
+
id: "cobble",
|
|
13922
|
+
density: 2650,
|
|
13923
|
+
hpPerKg: 25,
|
|
13924
|
+
penetration: 25,
|
|
13925
|
+
penetrationClass: "concrete",
|
|
13926
|
+
penetrationScale: 0.9,
|
|
13927
|
+
ductility: 0.03,
|
|
13928
|
+
fracture: "crumble",
|
|
13929
|
+
fragmentSize: [
|
|
13930
|
+
0.05,
|
|
13931
|
+
0.15
|
|
13932
|
+
],
|
|
13933
|
+
ricochetDeg: 15,
|
|
13934
|
+
hitDebris: "chips",
|
|
13935
|
+
breakDebris: "chips",
|
|
13936
|
+
thermal: {
|
|
13937
|
+
conductivity: 0.2,
|
|
13938
|
+
heatCapacity: 2.5
|
|
13939
|
+
},
|
|
13940
|
+
tags: [
|
|
13941
|
+
"masonry",
|
|
13942
|
+
"brittle"
|
|
13943
|
+
],
|
|
13944
|
+
compressive: 3e5
|
|
13945
|
+
},
|
|
13946
|
+
{
|
|
13947
|
+
id: "paver",
|
|
13948
|
+
density: 2300,
|
|
13949
|
+
hpPerKg: 14,
|
|
13950
|
+
penetration: 18,
|
|
13951
|
+
penetrationClass: "concrete",
|
|
13952
|
+
penetrationScale: 1,
|
|
13953
|
+
ductility: 0.03,
|
|
13954
|
+
fracture: "crumble",
|
|
13955
|
+
fragmentSize: [
|
|
13956
|
+
0.04,
|
|
13957
|
+
0.12
|
|
13958
|
+
],
|
|
13959
|
+
ricochetDeg: 12,
|
|
13960
|
+
hitDebris: "chips",
|
|
13961
|
+
breakDebris: "chips",
|
|
13962
|
+
thermal: {
|
|
13963
|
+
conductivity: 0.15,
|
|
13964
|
+
heatCapacity: 2.5
|
|
13965
|
+
},
|
|
13966
|
+
tags: [
|
|
13967
|
+
"masonry",
|
|
13968
|
+
"brittle"
|
|
13969
|
+
],
|
|
13970
|
+
compressive: 35e4
|
|
13520
13971
|
}
|
|
13521
13972
|
];
|
|
13522
13973
|
var material_hints_default = {
|
|
@@ -13729,6 +14180,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13729
14180
|
var BREACH_BLAST_FACTOR = 6;
|
|
13730
14181
|
var BREACH_AREA = 0.25;
|
|
13731
14182
|
var BREACH_BLAST_REACH = 0.12;
|
|
14183
|
+
var MEMBER_CUT_REACH = 0.5;
|
|
14184
|
+
var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
|
|
14185
|
+
var BLAST_EDGE_RAGGED = 0.3;
|
|
14186
|
+
var BLAST_EDGE_LOOSE = 1.35;
|
|
14187
|
+
var BLAST_EDGE_WEAR = 0.6;
|
|
13732
14188
|
var RESIDUAL_CAPACITY = 0.15;
|
|
13733
14189
|
var SEVER_BAND = 0.1;
|
|
13734
14190
|
var SEVER_ASPECT = 3;
|
|
@@ -14981,7 +15437,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14981
15437
|
if (j.st.open) continue;
|
|
14982
15438
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
14983
15439
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
14984
|
-
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
15440
|
+
j.st.hp -= span === void 0 ? amount : Math.min(amount, j.st.maxHp) * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
14985
15441
|
if (j.st.hp <= 0) {
|
|
14986
15442
|
j.st.hp = 0;
|
|
14987
15443
|
j.st.open = true;
|
|
@@ -15109,6 +15565,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15109
15565
|
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
15110
15566
|
const cut = (_b = p.rt).craters ?? (_b.craters = {});
|
|
15111
15567
|
const out = [];
|
|
15568
|
+
const wholeBefore = Object.values(worn).filter((w) => w === -1).length;
|
|
15112
15569
|
const shot = kind === "ballistic";
|
|
15113
15570
|
for (let i = 0; i < grid.length; i++) {
|
|
15114
15571
|
const cell = grid[i];
|
|
@@ -15167,6 +15624,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15167
15624
|
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
15168
15625
|
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
15169
15626
|
}
|
|
15627
|
+
if (Object.values(worn).filter((w) => w === -1).length > wholeBefore) dropUnsupported(o, p, src);
|
|
15170
15628
|
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
15171
15629
|
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
15172
15630
|
if (p.structural && !isLost(p)) {
|
|
@@ -15270,10 +15728,122 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15270
15728
|
setStage(o, p, 1, {}, src);
|
|
15271
15729
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
15272
15730
|
debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
15731
|
+
dropUnsupported(o, p, src);
|
|
15273
15732
|
const reinforcement = p.spec.reinforcement;
|
|
15274
15733
|
if (reinforcement) exposeRebar(o, p, src);
|
|
15275
15734
|
if (p.structural) solveStructure(o);
|
|
15276
15735
|
};
|
|
15736
|
+
const blastReachOf = (p, energy) => {
|
|
15737
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
15738
|
+
const resistance = Math.max(1, perKg * p.mat.density * p.thickness);
|
|
15739
|
+
return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
|
|
15740
|
+
};
|
|
15741
|
+
const blastUnits = (o, p, wp, energy, dist, src) => {
|
|
15742
|
+
var _a, _b;
|
|
15743
|
+
if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
|
|
15744
|
+
const reach = blastReachOf(p, energy);
|
|
15745
|
+
if (dist >= reach) return false;
|
|
15746
|
+
const radius = Math.sqrt(reach * reach - dist * dist);
|
|
15747
|
+
const [u, v] = planeAxes(p.thin);
|
|
15748
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
15749
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
15750
|
+
const grid = gridOf(p);
|
|
15751
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
15752
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
15753
|
+
const lobes = [rnd() * 2 * Math.PI, rnd() * 2 * Math.PI];
|
|
15754
|
+
const out = [];
|
|
15755
|
+
for (let i = 0; i < grid.length; i++) {
|
|
15756
|
+
const cell = grid[i];
|
|
15757
|
+
if (worn[i] === -1) continue;
|
|
15758
|
+
if (op && p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius) continue;
|
|
15759
|
+
const du = cell.center[u] - lp[u], dv = cell.center[v] - lp[v];
|
|
15760
|
+
const angle = Math.atan2(dv, du);
|
|
15761
|
+
const edge = radius * (1 + BLAST_EDGE_RAGGED * (0.5 * Math.sin(3 * angle + lobes[0]) + 0.3 * Math.sin(5 * angle + lobes[1]) + 0.4 * (rnd() - 0.5)));
|
|
15762
|
+
const d = Math.hypot(du, dv);
|
|
15763
|
+
if (d <= edge) {
|
|
15764
|
+
worn[i] = -1;
|
|
15765
|
+
out.push(i);
|
|
15766
|
+
} else if (d <= edge * BLAST_EDGE_LOOSE) {
|
|
15767
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
15768
|
+
worn[i] = Math.max(worn[i] ?? 0, perKg * mass * BLAST_EDGE_WEAR);
|
|
15769
|
+
}
|
|
15770
|
+
}
|
|
15771
|
+
if (out.length === 0) return false;
|
|
15772
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
|
|
15773
|
+
for (const i of loose) worn[i] = -1;
|
|
15774
|
+
const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
|
|
15775
|
+
const volume = (cells2) => cells2.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0);
|
|
15776
|
+
const blownMass = Math.min(p.st.mass, p.mat.density * volume(blown));
|
|
15777
|
+
const fallenMass = Math.min(p.st.mass - blownMass, p.mat.density * volume(fallen));
|
|
15778
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.02 / Math.max(blownMass, 0.05)), 1, 12);
|
|
15779
|
+
const { c, q } = partXf(o, p);
|
|
15780
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
15781
|
+
const tag = `x${chipped.length}_`;
|
|
15782
|
+
const fragments = [
|
|
15783
|
+
...cellFragments(o, p, clumpCells(blown, p.thin, maxFragments), wp, null, speed, blownMass, tag, true),
|
|
15784
|
+
...fallen.length > 0 ? cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), wp, null, 0.3, fallenMass, `${tag}f`, true) : []
|
|
15785
|
+
];
|
|
15786
|
+
const cells = [...blown, ...fallen];
|
|
15787
|
+
const holes = localHolesOf(p);
|
|
15788
|
+
p.st.holes = p.st.holes.filter((_, k) => !cells.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
15789
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
15790
|
+
for (const cell of cells) {
|
|
15791
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
15792
|
+
for (let k = 0; k < 3; k++) {
|
|
15793
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
15794
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
15795
|
+
}
|
|
15796
|
+
}
|
|
15797
|
+
p.st.mass = Math.max(0, p.st.mass - blownMass - fallenMass);
|
|
15798
|
+
p.rt.removed = (p.rt.removed ?? 0) + blownMass + fallenMass;
|
|
15799
|
+
markDamaged(p);
|
|
15800
|
+
setStage(o, p, 1, {}, src);
|
|
15801
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
15802
|
+
const units = cells.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
15803
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
15804
|
+
debris(o, p, p.mat.breakDebris, center, vec.normalize(vec.sub(center, wp), [0, 1, 0]), 14, 3, src);
|
|
15805
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
15806
|
+
if (p.structural && !isLost(p)) {
|
|
15807
|
+
solveStructure(o);
|
|
15808
|
+
collapseCheck(o, src);
|
|
15809
|
+
}
|
|
15810
|
+
return true;
|
|
15811
|
+
};
|
|
15812
|
+
const dropUnsupported = (o, p, src) => {
|
|
15813
|
+
var _a, _b;
|
|
15814
|
+
if (!p.spec.units || p.spec.units.mortar === p.spec.material || p.st.stripped || isLost(p)) return 0;
|
|
15815
|
+
const [u, v] = planeAxes(p.thin);
|
|
15816
|
+
const grid = gridOf(p);
|
|
15817
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
15818
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
15819
|
+
const opened = (cell) => !!op && !!p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius;
|
|
15820
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !opened(grid[i]));
|
|
15821
|
+
if (loose.length === 0) return 0;
|
|
15822
|
+
for (const i of loose) worn[i] = -1;
|
|
15823
|
+
const fallen = loose.map((i) => grid[i]);
|
|
15824
|
+
const mass = Math.min(p.st.mass, p.mat.density * fallen.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0));
|
|
15825
|
+
const { c, q } = partXf(o, p);
|
|
15826
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
15827
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
15828
|
+
for (const cell of fallen) {
|
|
15829
|
+
for (let k = 0; k < 3; k++) {
|
|
15830
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
15831
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
15832
|
+
}
|
|
15833
|
+
}
|
|
15834
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
15835
|
+
const fragments = cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), vec.add(center, [0, 1, 0]), null, 0.3, mass, `u${chipped.length}_`, true);
|
|
15836
|
+
const holes = localHolesOf(p);
|
|
15837
|
+
p.st.holes = p.st.holes.filter((_, k) => !fallen.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
15838
|
+
for (const cell of fallen) chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
15839
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
15840
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
15841
|
+
markDamaged(p);
|
|
15842
|
+
const units = fallen.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
15843
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
15844
|
+
debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
|
|
15845
|
+
return loose.length;
|
|
15846
|
+
};
|
|
15277
15847
|
const stripPart = (o, p, reinforcement, src) => {
|
|
15278
15848
|
const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
|
|
15279
15849
|
p.st.stripped = true;
|
|
@@ -15340,6 +15910,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15340
15910
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
15341
15911
|
const axis = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
15342
15912
|
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
15913
|
+
const planRnd = p.mat.splitForm ? splitStream(o.id, p.spec.id, hitLocal) : rnd;
|
|
15343
15914
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
15344
15915
|
style,
|
|
15345
15916
|
dims: p.dims,
|
|
@@ -15348,8 +15919,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15348
15919
|
hit: hitLocal,
|
|
15349
15920
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
15350
15921
|
maxFragments,
|
|
15351
|
-
rnd,
|
|
15922
|
+
rnd: planRnd,
|
|
15352
15923
|
sheet: p.mat.sheet,
|
|
15924
|
+
...p.mat.splitForm ? { form: p.mat.splitForm } : {},
|
|
15353
15925
|
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
15354
15926
|
});
|
|
15355
15927
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
@@ -15488,7 +16060,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15488
16060
|
const fragments = [];
|
|
15489
16061
|
for (let i = 0; i < n; i++) {
|
|
15490
16062
|
const back = !exit || i % 3 === 2;
|
|
15491
|
-
const
|
|
16063
|
+
const plies = p.mat.splitForm === "plies";
|
|
16064
|
+
const len = scale * (fibre ? 1.2 + 1.2 * rnd() : 3 + 4 * rnd()), w = scale * (0.8 + 0.8 * rnd()), t = scale * (fibre ? 0.7 + 0.6 * rnd() : plies ? 0.15 + 0.15 * rnd() : 0.4 + 0.4 * rnd());
|
|
15492
16065
|
const size = [w, w, w];
|
|
15493
16066
|
size[along] = len;
|
|
15494
16067
|
size[(along + 1) % 3] = w;
|
|
@@ -15649,7 +16222,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15649
16222
|
checkIgnite(o, p, src);
|
|
15650
16223
|
}
|
|
15651
16224
|
}
|
|
15652
|
-
wearJoints(o, p, Ein * 0.5, void 0, 0, src);
|
|
16225
|
+
wearJoints(o, p, Ein * 0.5, void 0, 0, src, false, 2 * BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3));
|
|
15653
16226
|
const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1);
|
|
15654
16227
|
if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes("glass")) {
|
|
15655
16228
|
frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...src !== void 0 ? { src } : {} });
|
|
@@ -15659,7 +16232,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15659
16232
|
const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
|
|
15660
16233
|
res.damage += dealt;
|
|
15661
16234
|
if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
|
|
15662
|
-
|
|
16235
|
+
const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
|
|
16236
|
+
if (p.spec.units && p.spec.units.mortar !== p.spec.material) blastUnits(o, p, wp, energy, dist, src);
|
|
16237
|
+
else if (p.spec.reinforcement && p.spec.units && dist > MEMBER_CUT_REACH * breachReach) blastUnits(o, p, wp, energy, dist, src);
|
|
16238
|
+
else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
15663
16239
|
return reach;
|
|
15664
16240
|
};
|
|
15665
16241
|
const blastProbe = { partsTested: 0, partsNear: 0 };
|
|
@@ -15905,6 +16481,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15905
16481
|
}
|
|
15906
16482
|
return h | 0;
|
|
15907
16483
|
};
|
|
16484
|
+
const splitStream = (objectId, partId, hit) => {
|
|
16485
|
+
const codes = Array.from(`${objectId}|${partId}`, (char) => char.charCodeAt(0) / 1e3);
|
|
16486
|
+
const stream = createRng(seedOf2(rng2.state() / 1e3, ...codes, hit[0], hit[1], hit[2]));
|
|
16487
|
+
return () => stream.next();
|
|
16488
|
+
};
|
|
15908
16489
|
const throwFragment = (frag, objectId, from, g, centre, index, src, shields, results, reports, mult) => {
|
|
15909
16490
|
const v = frag.velocity;
|
|
15910
16491
|
const speed = Math.hypot(v[0], v[1], v[2]);
|
|
@@ -17118,8 +17699,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17118
17699
|
|
|
17119
17700
|
// ../game-floorplan-structure/dist/index.js
|
|
17120
17701
|
var __defProp2 = Object.defineProperty;
|
|
17121
|
-
var
|
|
17122
|
-
var
|
|
17702
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
17703
|
+
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
17123
17704
|
var uniform = (joint) => ({ wall: joint, slab: joint, beam: joint, column: joint, truss: joint });
|
|
17124
17705
|
var CONSTRUCTION_SYSTEMS = /* @__PURE__ */ new Map([
|
|
17125
17706
|
["masonry", { walls: "brick_wall_plastered", joints: { wall: "mortar", slab: "rebar", beam: "mortar", column: "rebar", truss: "bolt" }, slabThickness: 0.12, plateThickness: 0.2, timber: false, wallRole: "rules", wallFill: 1 }],
|
|
@@ -17253,9 +17834,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17253
17834
|
var densityOf = (material) => DENSITY[material] ?? DEFAULT_DENSITY;
|
|
17254
17835
|
var StructureBuilder = class {
|
|
17255
17836
|
constructor() {
|
|
17256
|
-
|
|
17257
|
-
|
|
17258
|
-
|
|
17837
|
+
__publicField2(this, "parts", []);
|
|
17838
|
+
__publicField2(this, "supports", []);
|
|
17839
|
+
__publicField2(this, "ids", /* @__PURE__ */ new Set());
|
|
17259
17840
|
}
|
|
17260
17841
|
add(draft, options = {}) {
|
|
17261
17842
|
const { id, role, material, aabb, y0, y1 } = draft;
|
|
@@ -17321,12 +17902,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17321
17902
|
builder,
|
|
17322
17903
|
porchRoofOnPostsOnly: options.porchRoofOnPostsOnly,
|
|
17323
17904
|
rafterRoof: options.rafterRoof,
|
|
17905
|
+
wallPillarSpacing: options.wallPillarSpacing,
|
|
17906
|
+
visorSections: options.visorSections,
|
|
17324
17907
|
floorCount: floorCount2,
|
|
17325
17908
|
isUnit,
|
|
17326
17909
|
elevation,
|
|
17327
17910
|
isTimber: system.timber,
|
|
17328
17911
|
walls: [],
|
|
17329
17912
|
wallParts: /* @__PURE__ */ new Map(),
|
|
17913
|
+
groundBeams: /* @__PURE__ */ new Map(),
|
|
17330
17914
|
carriers: /* @__PURE__ */ new Map(),
|
|
17331
17915
|
plates: /* @__PURE__ */ new Map(),
|
|
17332
17916
|
pillars: /* @__PURE__ */ new Map(),
|
|
@@ -17397,7 +17981,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17397
17981
|
builder.rest(deck, base, system.joints.slab);
|
|
17398
17982
|
continue;
|
|
17399
17983
|
}
|
|
17400
|
-
const
|
|
17984
|
+
const half = context.visorSections ? 0.08 : 0.1;
|
|
17985
|
+
const pillar = builder.add({ id: `balcony_column_${room.id}`, role: "column", material: construction.frame.pillars, aabb: [box22[0] - half, box22[1] - half, box22[0] + half, box22[1] + half], y0: 0, y1: context.level(floor) - system.slabThickness }, { floor: 0 });
|
|
17401
17986
|
builder.rest(pillar, GROUND, "rebar");
|
|
17402
17987
|
builder.rest(deck, pillar, "rebar");
|
|
17403
17988
|
}
|
|
@@ -17462,8 +18047,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17462
18047
|
const top = context.level(floor) - thickness * 0.15;
|
|
17463
18048
|
const out = [];
|
|
17464
18049
|
for (let k = 0; k < count; k++) {
|
|
17465
|
-
const
|
|
17466
|
-
const aabb = alongU ? [
|
|
18050
|
+
const centre2 = (alongU ? box22[0] : box22[1]) + 0.05 + k * (span - 0.1) / (count - 1);
|
|
18051
|
+
const aabb = alongU ? [centre2 - 0.025, box22[1], centre2 + 0.025, box22[3]] : [box22[0], centre2 - 0.025, box22[2], centre2 + 0.025];
|
|
17467
18052
|
const joist = context.builder.add({ id: `joist_${floor}${suffix}_${k}`, role: "beam", material, aabb, y0: context.level(floor) - thickness, y1: top }, { floor, fill: 1, spacing: JOIST_PITCH });
|
|
17468
18053
|
out.push(joist);
|
|
17469
18054
|
const below = carriers.filter((carrier) => carrier.y0 <= top + 0.05);
|
|
@@ -17551,8 +18136,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17551
18136
|
const at2 = alongU ? box22[1] + line * (box22[3] - box22[1]) / (rows - 1) : box22[0] + line * (box22[2] - box22[0]) / (columns - 1);
|
|
17552
18137
|
const aabb = alongU ? [box22[0], at2 - 0.07, box22[2], at2 + 0.07] : [at2 - 0.07, box22[1], at2 + 0.07, box22[3]];
|
|
17553
18138
|
const beam = builder.add({ id: `base_beam_${line}`, role: "beam", material: construction.frame.timber, aabb, y0: height, y1: elevation - context.system.slabThickness }, { floor: 0 });
|
|
17554
|
-
const
|
|
17555
|
-
for (const pier of piers.filter((q) => Math.abs(
|
|
18139
|
+
const centre2 = (q) => alongU ? (q.aabb[1] + q.aabb[3]) / 2 : (q.aabb[0] + q.aabb[2]) / 2;
|
|
18140
|
+
for (const pier of piers.filter((q) => Math.abs(centre2(q) - at2) < 0.05)) builder.rest(beam, pier, "bolt");
|
|
17556
18141
|
beams.push(beam);
|
|
17557
18142
|
}
|
|
17558
18143
|
return beams;
|
|
@@ -17572,17 +18157,110 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17572
18157
|
else if (type === "crawl_space" || type === "piles" || type === "basement") addRaisedFloor(context);
|
|
17573
18158
|
else if (context.isTimber && type !== "ground") context.base0 = raft(context, Math.max(0.12, context.elevation), "concrete");
|
|
17574
18159
|
}
|
|
18160
|
+
var GROUND_BEAM_DEPTH = 0.3;
|
|
18161
|
+
function addGroundBeams(context) {
|
|
18162
|
+
const { builder, construction } = context;
|
|
18163
|
+
if (construction.system !== "masonry" || context.isUnit || construction.foundation.type !== "strip_footing") return;
|
|
18164
|
+
const top = context.level(0);
|
|
18165
|
+
for (const wall of context.walls) {
|
|
18166
|
+
if (wall.floor !== 0 || wall.type !== "wall") continue;
|
|
18167
|
+
const beam = builder.add({ id: `ground_beam_${context.groundBeams.size}`, role: "beam", material: construction.frame.beams, aabb: wall.box, y0: top - GROUND_BEAM_DEPTH, y1: top }, { floor: 0, beamKind: "ground_beam" });
|
|
18168
|
+
builder.rest(beam, GROUND, "rebar");
|
|
18169
|
+
context.groundBeams.set(wall.id, beam);
|
|
18170
|
+
}
|
|
18171
|
+
}
|
|
18172
|
+
var WALL_PILLAR_SPACING = 4;
|
|
18173
|
+
var WALL_PILLAR_SIDE = 0.2;
|
|
18174
|
+
var MERGE_DISTANCE = 0.45;
|
|
18175
|
+
var HALF = WALL_PILLAR_SIDE / 2;
|
|
18176
|
+
var TOLERANCE = 0.03;
|
|
18177
|
+
var alongRange = (wall) => wall.axis === "u" ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)];
|
|
18178
|
+
var acrossOf = (wall) => wall.axis === "u" ? wall.v0 : wall.u0;
|
|
18179
|
+
function stretchesOf(context, wall) {
|
|
18180
|
+
const [low, high] = alongRange(wall);
|
|
18181
|
+
const windows = (context.source.windows ?? []).filter((w) => w.floor === wall.floor && w.axis === wall.axis && Math.abs(w.pos - acrossOf(wall)) <= TOLERANCE && w.at + w.width / 2 > low && w.at - w.width / 2 < high).map((w) => [w.at - w.width / 2, w.at + w.width / 2]).sort((a, b) => a[0] - b[0]);
|
|
18182
|
+
const out = [];
|
|
18183
|
+
let cursor = low;
|
|
18184
|
+
for (const [from, to] of windows) {
|
|
18185
|
+
if (from - cursor > TOLERANCE) out.push({ wall, from: cursor, to: from });
|
|
18186
|
+
cursor = Math.max(cursor, to);
|
|
18187
|
+
}
|
|
18188
|
+
if (high - cursor > TOLERANCE) out.push({ wall, from: cursor, to: high });
|
|
18189
|
+
return out;
|
|
18190
|
+
}
|
|
18191
|
+
function junctionsOf(context, wall) {
|
|
18192
|
+
const [low, high] = alongRange(wall);
|
|
18193
|
+
const line = acrossOf(wall);
|
|
18194
|
+
const out = [];
|
|
18195
|
+
for (const other of context.walls) {
|
|
18196
|
+
if (other === wall || other.floor !== wall.floor || other.axis === wall.axis || other.type !== "wall") continue;
|
|
18197
|
+
const at2 = acrossOf(other);
|
|
18198
|
+
const [a, b] = alongRange(other);
|
|
18199
|
+
const meets = Math.abs(a - line) <= (wall.thickness ?? 0.15) / 2 + TOLERANCE || Math.abs(b - line) <= (wall.thickness ?? 0.15) / 2 + TOLERANCE;
|
|
18200
|
+
if (meets && at2 > low + HALF && at2 < high - HALF) out.push(at2);
|
|
18201
|
+
}
|
|
18202
|
+
return out;
|
|
18203
|
+
}
|
|
18204
|
+
function pillarStations(from, to, junctions, spacing) {
|
|
18205
|
+
const length = to - from;
|
|
18206
|
+
if (length < WALL_PILLAR_SIDE - 1e-6) return [];
|
|
18207
|
+
if (length < 2 * WALL_PILLAR_SIDE) return [(from + to) / 2];
|
|
18208
|
+
if (length < WALL_PILLAR_SIDE + MERGE_DISTANCE) return [from + HALF, to - HALF];
|
|
18209
|
+
const fixed = [from + HALF, ...junctions.filter((at2) => at2 > from + HALF + MERGE_DISTANCE && at2 < to - HALF - MERGE_DISTANCE), to - HALF].sort((a, b) => a - b);
|
|
18210
|
+
const out = [];
|
|
18211
|
+
fixed.forEach((at2, k) => {
|
|
18212
|
+
out.push(at2);
|
|
18213
|
+
const next = fixed[k + 1];
|
|
18214
|
+
if (next === void 0) return;
|
|
18215
|
+
const spans = Math.ceil((next - at2) / spacing - 1e-6);
|
|
18216
|
+
for (let s = 1; s < spans; s++) out.push(at2 + (next - at2) * s / spans);
|
|
18217
|
+
});
|
|
18218
|
+
return out;
|
|
18219
|
+
}
|
|
18220
|
+
function addWallPillars(context, walls, floor, plates, taken, spacing) {
|
|
18221
|
+
const { builder } = context;
|
|
18222
|
+
const pillars = [];
|
|
18223
|
+
const placed = taken.map((p) => [(p.aabb[0] + p.aabb[2]) / 2, (p.aabb[1] + p.aabb[3]) / 2]);
|
|
18224
|
+
const base = context.baseOf(floor);
|
|
18225
|
+
for (const wall of walls) {
|
|
18226
|
+
if (!wall.exterior || wall.type !== "wall") continue;
|
|
18227
|
+
const top = context.wallParts.get(wall.id).y1;
|
|
18228
|
+
const across = acrossOf(wall);
|
|
18229
|
+
const junctions = junctionsOf(context, wall);
|
|
18230
|
+
for (const stretch of stretchesOf(context, wall)) {
|
|
18231
|
+
const standing = (end) => placed.map(([pu, pv]) => wall.axis === "u" ? [pu, pv] : [pv, pu]).find(([a, c]) => Math.abs(c - across) <= TOLERANCE && Math.abs(a - end) < MERGE_DISTANCE + HALF)?.[0];
|
|
18232
|
+
const first = standing(stretch.from);
|
|
18233
|
+
const last = standing(stretch.to);
|
|
18234
|
+
const from = first === void 0 ? stretch.from : Math.min(stretch.from, first - HALF);
|
|
18235
|
+
const to = last === void 0 ? stretch.to : Math.max(stretch.to, last + HALF);
|
|
18236
|
+
for (const along of pillarStations(from, to, junctions, spacing)) {
|
|
18237
|
+
const [u, v] = wall.axis === "u" ? [along, across] : [across, along];
|
|
18238
|
+
const end = Math.abs(along - stretch.from) < Math.abs(along - stretch.to) ? stretch.from : stretch.to;
|
|
18239
|
+
const endPoint = wall.axis === "u" ? [end, across] : [across, end];
|
|
18240
|
+
const isEnd = Math.abs(along - end) <= HALF + TOLERANCE;
|
|
18241
|
+
if (placed.some(([pu, pv]) => Math.hypot(pu - u, pv - v) < MERGE_DISTANCE && (!isEnd || Math.hypot(pu - endPoint[0], pv - endPoint[1]) < MERGE_DISTANCE))) continue;
|
|
18242
|
+
placed.push([u, v]);
|
|
18243
|
+
const box22 = [u - HALF, v - HALF, u + HALF, v + HALF];
|
|
18244
|
+
const pillar = builder.add({ id: `wall_column_${floor}_${pillars.length}`, role: "column", material: context.construction.frame.pillars, aabb: box22, y0: context.level(floor), y1: top }, { floor });
|
|
18245
|
+
builder.rest(pillar, base === GROUND || !base ? GROUND : base, "rebar");
|
|
18246
|
+
for (const plate of plates.filter((p) => touches(p.aabb, box22, 0.01))) builder.rest(plate, pillar, "rebar");
|
|
18247
|
+
pillars.push(pillar);
|
|
18248
|
+
}
|
|
18249
|
+
}
|
|
18250
|
+
}
|
|
18251
|
+
return pillars;
|
|
18252
|
+
}
|
|
17575
18253
|
var MAX_GAP_WITHIN_RUN = 3.2;
|
|
17576
18254
|
var POST_SPACING = 2.4;
|
|
17577
18255
|
var POST_SIDE = 0.05;
|
|
17578
18256
|
var alongOf = (wall, pick2) => wall.axis === "u" ? pick2(wall.u0, wall.u1) : pick2(wall.v0, wall.v1);
|
|
17579
|
-
var
|
|
18257
|
+
var acrossOf2 = (wall) => wall.axis === "u" ? wall.v0 : wall.u0;
|
|
17580
18258
|
function runsOf(context, walls, floor) {
|
|
17581
18259
|
const lines = /* @__PURE__ */ new Map();
|
|
17582
18260
|
for (const wall of walls) {
|
|
17583
18261
|
if (!wall.exterior || wall.type !== "wall") continue;
|
|
17584
18262
|
const top = round2(context.wallParts.get(wall.id).y1);
|
|
17585
|
-
const key = `${floor}|${wall.axis}|${
|
|
18263
|
+
const key = `${floor}|${wall.axis}|${acrossOf2(wall).toFixed(2)}|${top.toFixed(2)}`;
|
|
17586
18264
|
lines.set(key, [...lines.get(key) ?? [], wall]);
|
|
17587
18265
|
}
|
|
17588
18266
|
return [...lines.values()].map((line) => {
|
|
@@ -17602,7 +18280,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17602
18280
|
}
|
|
17603
18281
|
function addShackPosts(context, run, plate, floor, index) {
|
|
17604
18282
|
const first = run.walls[0];
|
|
17605
|
-
const across =
|
|
18283
|
+
const across = acrossOf2(first);
|
|
17606
18284
|
const top = context.wallParts.get(first.id).y1;
|
|
17607
18285
|
const count = Math.max(1, Math.ceil((run.to - run.from) / POST_SPACING));
|
|
17608
18286
|
const posts = [];
|
|
@@ -17628,7 +18306,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17628
18306
|
for (const run of runs) {
|
|
17629
18307
|
const first = run.walls[0];
|
|
17630
18308
|
const half = (first.thickness ?? 0.15) / 2;
|
|
17631
|
-
const across =
|
|
18309
|
+
const across = acrossOf2(first);
|
|
17632
18310
|
const top = context.wallParts.get(first.id).y1;
|
|
17633
18311
|
const aabb = first.axis === "u" ? [run.from - half, across - half, run.to + half, across + half] : [across - half, run.from - half, across + half, run.to + half];
|
|
17634
18312
|
const material = context.isTimber ? construction.frame.timber : construction.frame.beams;
|
|
@@ -17667,7 +18345,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17667
18345
|
function addPlatesAndPillars(context, floor) {
|
|
17668
18346
|
const walls = context.walls.filter((wall) => wall.floor === floor);
|
|
17669
18347
|
const { plates, pillars } = addPlates(context, walls, floor);
|
|
17670
|
-
if (context.construction.system === "masonry")
|
|
18348
|
+
if (context.construction.system === "masonry") {
|
|
18349
|
+
const corners = addCornerPillars(context, walls, floor, plates);
|
|
18350
|
+
pillars.push(...corners);
|
|
18351
|
+
if (context.wallPillarSpacing) pillars.push(...addWallPillars(context, walls, floor, plates, corners, context.wallPillarSpacing));
|
|
18352
|
+
}
|
|
17671
18353
|
context.pillars.set(floor, pillars);
|
|
17672
18354
|
context.plates.set(floor, plates);
|
|
17673
18355
|
const innerBearing = walls.filter((wall) => wall.role === "wall" && !wall.exterior).map((wall) => context.wallParts.get(wall.id));
|
|
@@ -17942,21 +18624,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17942
18624
|
builder.rest(flight, builder.find("basement_slab"), "resting");
|
|
17943
18625
|
if (context.base0 && context.base0 !== GROUND) builder.rest(flight, context.base0, "nail");
|
|
17944
18626
|
}
|
|
17945
|
-
var
|
|
18627
|
+
var TOLERANCE2 = 0.02;
|
|
17946
18628
|
var DOOR_HEIGHT = 2.1;
|
|
17947
18629
|
var LINTEL_DEPTH = 0.2;
|
|
17948
18630
|
var LINTEL_BEARING = 0.2;
|
|
17949
18631
|
var crossOf = (wall) => wall.axis === "u" ? wall.v0 : wall.u0;
|
|
17950
|
-
var
|
|
18632
|
+
var alongRange2 = (wall) => wall.axis === "u" ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)];
|
|
17951
18633
|
function findOpenings(context) {
|
|
17952
18634
|
const openings = [];
|
|
17953
18635
|
for (const window of context.source.windows ?? []) {
|
|
17954
18636
|
const from = window.at - window.width / 2;
|
|
17955
18637
|
const to = window.at + window.width / 2;
|
|
17956
18638
|
const wall = context.walls.find((w) => {
|
|
17957
|
-
if (w.floor !== window.floor || w.axis !== window.axis || w.type !== "wall" || Math.abs(crossOf(w) - window.pos) >
|
|
17958
|
-
const [low, high] =
|
|
17959
|
-
return from >= low -
|
|
18639
|
+
if (w.floor !== window.floor || w.axis !== window.axis || w.type !== "wall" || Math.abs(crossOf(w) - window.pos) > TOLERANCE2) return false;
|
|
18640
|
+
const [low, high] = alongRange2(w);
|
|
18641
|
+
return from >= low - TOLERANCE2 && to <= high + TOLERANCE2;
|
|
17960
18642
|
});
|
|
17961
18643
|
if (!wall) continue;
|
|
17962
18644
|
const base = context.level(window.floor);
|
|
@@ -17971,18 +18653,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17971
18653
|
const cross = door.axis === "u" ? door.v : door.u;
|
|
17972
18654
|
const from = along - door.width / 2;
|
|
17973
18655
|
const to = along + door.width / 2;
|
|
17974
|
-
const beside = context.walls.filter((w) => w.floor === door.floor && w.axis === door.axis && w.type === "wall" && Math.abs(crossOf(w) - cross) <=
|
|
18656
|
+
const beside = context.walls.filter((w) => w.floor === door.floor && w.axis === door.axis && w.type === "wall" && Math.abs(crossOf(w) - cross) <= TOLERANCE2 && (Math.abs(alongRange2(w)[1] - from) <= 0.05 || Math.abs(alongRange2(w)[0] - to) <= 0.05));
|
|
17975
18657
|
if (!beside.length) continue;
|
|
17976
18658
|
const half = (beside[0].thickness ?? 0.15) / 2;
|
|
17977
18659
|
const lo = from - LINTEL_BEARING;
|
|
17978
18660
|
const hi = to + LINTEL_BEARING;
|
|
17979
18661
|
const box22 = door.axis === "u" ? [lo, cross - half, hi, cross + half] : [cross - half, lo, cross + half, hi];
|
|
17980
18662
|
const y0 = context.level(door.floor) + DOOR_HEIGHT;
|
|
17981
|
-
const
|
|
18663
|
+
const depth = Math.max(LINTEL_DEPTH, (door.width + LINTEL_BEARING) / 10);
|
|
18664
|
+
const lintel = builder.add({ id: `lintel_${door.id}`, role: "beam", material: system.timber ? construction.frame.timber : "concrete", aabb: box22, y0, y1: y0 + depth }, { floor: door.floor, ...system.timber ? {} : { assembly: "reinforced_concrete" } });
|
|
17982
18665
|
for (const wall of beside) builder.rest(lintel, context.wallParts.get(wall.id), system.joints.beam);
|
|
18666
|
+
const jambs = (context.pillars.get(door.floor) ?? []).filter((pillar) => pillar.material === "concrete" && overlapsInPlan(pillar.aabb, box22) && pillar.y1 >= y0);
|
|
18667
|
+
if (construction.system === "masonry" && hi - lo > WIDE_DOOR) jambs.push(...addJambPillars(context, { door, beside, from, to, cross }, jambs));
|
|
18668
|
+
for (const pillar of jambs) builder.rest(lintel, pillar, "rebar");
|
|
17983
18669
|
for (const plate of context.plates.get(door.floor) ?? []) if (overlapsInPlan(plate.aabb, box22)) builder.rest(plate, lintel, system.joints.beam);
|
|
17984
18670
|
}
|
|
17985
18671
|
}
|
|
18672
|
+
var WIDE_DOOR = 3;
|
|
18673
|
+
var HALF_PILLAR = WALL_PILLAR_SIDE / 2;
|
|
18674
|
+
function addJambPillars(context, gap, standing) {
|
|
18675
|
+
const { builder, construction } = context;
|
|
18676
|
+
const top = Math.max(...gap.beside.map((w) => context.wallParts.get(w.id).y1));
|
|
18677
|
+
const base = context.baseOf(gap.door.floor);
|
|
18678
|
+
const out = [];
|
|
18679
|
+
for (const [k, along] of [[0, gap.from - HALF_PILLAR], [1, gap.to + HALF_PILLAR]]) {
|
|
18680
|
+
const [u, v] = gap.door.axis === "u" ? [along, gap.cross] : [gap.cross, along];
|
|
18681
|
+
const box22 = [u - HALF_PILLAR, v - HALF_PILLAR, u + HALF_PILLAR, v + HALF_PILLAR];
|
|
18682
|
+
if (standing.some((p) => overlapsInPlan(p.aabb, box22))) continue;
|
|
18683
|
+
const pillar = builder.add({ id: `jamb_column_${gap.door.id}_${k}`, role: "column", material: construction.frame.pillars, aabb: box22, y0: context.level(gap.door.floor), y1: top }, { floor: gap.door.floor });
|
|
18684
|
+
builder.rest(pillar, base === GROUND || !base ? GROUND : base, "rebar");
|
|
18685
|
+
out.push(pillar);
|
|
18686
|
+
}
|
|
18687
|
+
return out;
|
|
18688
|
+
}
|
|
17986
18689
|
var overlapsInPlan = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
17987
18690
|
var RISER = 0.18;
|
|
17988
18691
|
var TREAD = 0.28;
|
|
@@ -18154,10 +18857,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18154
18857
|
const framed = system.studs !== void 0 && !isRailing;
|
|
18155
18858
|
const part = builder.add(
|
|
18156
18859
|
{ id: wall.id, role: wall.role, material: wall.material, aabb: wall.box, y0, y1: Math.max(y1, y0 + 0.2) },
|
|
18157
|
-
{ floor, fill: context.isTimber && wall.role === "wall" ? system.wallFill : 1, ...framed ? { studs: system.studs } : {}, ...isRailing ? {} : { assembly: assemblyOf(context) } }
|
|
18860
|
+
{ floor, fill: context.isTimber && wall.role === "wall" ? system.wallFill : 1, ...framed ? { studs: system.studs } : {}, ...isRailing ? {} : { assembly: assemblyOf(context) }, ...wall.exterior && !isRailing ? { exterior: true } : {} }
|
|
18158
18861
|
);
|
|
18159
18862
|
context.wallParts.set(wall.id, part);
|
|
18160
|
-
const base = isRailing ? railingBase(context, wall, floor) : context.baseOf(floor);
|
|
18863
|
+
const base = isRailing ? railingBase(context, wall, floor) : context.groundBeams.get(wall.id) ?? context.baseOf(floor);
|
|
18161
18864
|
const joint = isRailing ? "nail" : system.joints.wall;
|
|
18162
18865
|
if (base === GROUND || floor === 0 && !base) builder.rest(part, GROUND, joint);
|
|
18163
18866
|
else if (base) builder.rest(part, base, joint);
|
|
@@ -18173,6 +18876,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18173
18876
|
addUpperFloor(context, floor);
|
|
18174
18877
|
}
|
|
18175
18878
|
}
|
|
18879
|
+
var wallPillarSpacingOf = (options) => {
|
|
18880
|
+
const pillars = options.wallPillars ?? true;
|
|
18881
|
+
if (pillars === false) return 0;
|
|
18882
|
+
return pillars === true ? WALL_PILLAR_SPACING : pillars.spacing ?? WALL_PILLAR_SPACING;
|
|
18883
|
+
};
|
|
18176
18884
|
function buildStructure(source, options = {}) {
|
|
18177
18885
|
const refined = options.wallDetail !== "coarse";
|
|
18178
18886
|
const built = options.construction ? { construction: options.construction, extras: options.extras ?? {} } : resolveConstruction(source);
|
|
@@ -18180,8 +18888,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18180
18888
|
const extras = options.extras ?? built.extras ?? {};
|
|
18181
18889
|
if (construction.system === "canvas") return buildCanvasStructure(construction, extras);
|
|
18182
18890
|
const tank = options.tank !== void 0 ? options.tank : source.waterTank ?? null;
|
|
18183
|
-
const context = createContext(source, construction, extras, tank, { porchRoofOnPostsOnly: options.porchRoofOnPostsOnly ?? refined, rafterRoof: options.rafterRoof ?? refined });
|
|
18891
|
+
const context = createContext(source, construction, extras, tank, { porchRoofOnPostsOnly: options.porchRoofOnPostsOnly ?? refined, rafterRoof: options.rafterRoof ?? refined, wallPillarSpacing: wallPillarSpacingOf(options), visorSections: options.visorSections === true });
|
|
18184
18892
|
addFoundation(context);
|
|
18893
|
+
if (options.groundBeams !== false) addGroundBeams(context);
|
|
18185
18894
|
buildFloors(context);
|
|
18186
18895
|
addBalconies(context);
|
|
18187
18896
|
addPorchRoofs(context);
|
|
@@ -18930,6 +19639,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18930
19639
|
}
|
|
18931
19640
|
var LINTEL_DEPTH2 = 0.2;
|
|
18932
19641
|
var LINTEL_BEARING2 = 0.2;
|
|
19642
|
+
var SILL_BEAM_DEPTH = 0.1;
|
|
19643
|
+
var LINTEL_SPAN_RATIO = 10;
|
|
18933
19644
|
var MIN_PIECE = 0.05;
|
|
18934
19645
|
var frameOf = (wall) => {
|
|
18935
19646
|
const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1];
|
|
@@ -18943,6 +19654,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18943
19654
|
const drafts = [];
|
|
18944
19655
|
const piers = [];
|
|
18945
19656
|
const lintels = [];
|
|
19657
|
+
const sillBeams = [];
|
|
18946
19658
|
const spandrels = [];
|
|
18947
19659
|
const height = wall.y1 - wall.y0;
|
|
18948
19660
|
let cursor = frame2.from;
|
|
@@ -18953,23 +19665,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18953
19665
|
};
|
|
18954
19666
|
own.forEach((opening2, k) => {
|
|
18955
19667
|
addPier(Math.max(cursor, opening2.from));
|
|
18956
|
-
const
|
|
19668
|
+
const span = opening2.to - opening2.from;
|
|
19669
|
+
const lintelTop = Math.min(wall.y1, opening2.y1 + Math.max(LINTEL_DEPTH2, style.lintelDepth?.(span) ?? 0, (span + LINTEL_BEARING2) / LINTEL_SPAN_RATIO));
|
|
18957
19670
|
const lintelFrom = Math.max(frame2.from, opening2.from - LINTEL_BEARING2);
|
|
18958
19671
|
const lintelTo = Math.min(frame2.to, opening2.to + LINTEL_BEARING2);
|
|
18959
19672
|
const lintelHeight = lintelTop - opening2.y1;
|
|
18960
|
-
|
|
19673
|
+
const sillTop = style.sillBeam && opening2.y0 - wall.y0 > SILL_BEAM_DEPTH + MIN_PIECE ? opening2.y0 - SILL_BEAM_DEPTH : opening2.y0;
|
|
19674
|
+
if (sillTop - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: "partition", material: wall.material, from: opening2.from, to: opening2.to, y0: wall.y0, y1: sillTop, volume: (opening2.to - opening2.from) * (sillTop - wall.y0) });
|
|
19675
|
+
if (sillTop < opening2.y0) sillBeams.push({ id: `${wall.id}_sillbeam_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: sillTop, y1: opening2.y0, volume: (lintelTo - lintelFrom) * SILL_BEAM_DEPTH });
|
|
18961
19676
|
lintels.push({ id: `${wall.id}_lintel_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening2.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight });
|
|
18962
19677
|
spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf2, material: wall.material, from: opening2.from, to: opening2.to, y0: lintelTop, y1: wall.y1, volume: (opening2.to - opening2.from) * (wall.y1 - lintelTop) } : void 0);
|
|
18963
19678
|
cursor = opening2.to;
|
|
18964
19679
|
});
|
|
18965
19680
|
addPier(frame2.to);
|
|
18966
19681
|
for (const pier of piers) {
|
|
18967
|
-
for (const lintel of lintels) {
|
|
19682
|
+
for (const lintel of [...lintels, ...sillBeams]) {
|
|
18968
19683
|
const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from));
|
|
18969
19684
|
pier.volume -= overlap * (lintel.y1 - lintel.y0);
|
|
18970
19685
|
}
|
|
18971
19686
|
}
|
|
18972
|
-
const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
19687
|
+
const all = [...piers, ...drafts, ...sillBeams, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
18973
19688
|
const total = all.reduce((sum, d) => sum + d.volume, 0);
|
|
18974
19689
|
const pieces = all.map((d) => ({
|
|
18975
19690
|
id: d.id,
|
|
@@ -18984,6 +19699,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18984
19699
|
...d.role === "beam" ? style.lintelAssembly ? { assembly: style.lintelAssembly } : {} : wall.assembly ? { assembly: wall.assembly } : {}
|
|
18985
19700
|
}));
|
|
18986
19701
|
const internal = [];
|
|
19702
|
+
for (const beam of sillBeams) {
|
|
19703
|
+
const sill = drafts.find((d) => d.id === beam.id.replace("_sillbeam_", "_sill_"));
|
|
19704
|
+
if (sill) internal.push({ part: beam.id, on: sill.id, joint: style.lintelJoint });
|
|
19705
|
+
for (const pier of piers) if (Math.min(pier.to, beam.to) - Math.max(pier.from, beam.from) > 0) internal.push({ part: beam.id, on: pier.id, joint: style.lintelJoint });
|
|
19706
|
+
}
|
|
18987
19707
|
lintels.forEach((lintel, k) => {
|
|
18988
19708
|
for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint });
|
|
18989
19709
|
const spandrel = spandrels[k];
|
|
@@ -19013,7 +19733,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19013
19733
|
...system.timber ? {} : { lintelAssembly: "reinforced_concrete" },
|
|
19014
19734
|
lintelJoint: system.joints.beam,
|
|
19015
19735
|
wallJoint: system.joints.wall,
|
|
19016
|
-
...lintelDepth && !system.timber ? { lintelDepth } : {}
|
|
19736
|
+
...lintelDepth && !system.timber ? { lintelDepth } : {},
|
|
19737
|
+
...construction.system === "masonry" ? { sillBeam: true } : {}
|
|
19017
19738
|
});
|
|
19018
19739
|
if (split.pieces.length > 1) splits.set(part.id, split);
|
|
19019
19740
|
}
|
|
@@ -19021,7 +19742,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19021
19742
|
}
|
|
19022
19743
|
function applyPanels(input, structure, detail, lintelDepth) {
|
|
19023
19744
|
if (detail === "coarse") return input;
|
|
19024
|
-
return applySplits(input, panelSplits(input, structure, lintelDepth));
|
|
19745
|
+
return onJambPillars(applySplits(input, panelSplits(input, structure, lintelDepth)));
|
|
19746
|
+
}
|
|
19747
|
+
var OPENING_BEAM = /_(lintel|sillbeam)_\d+$/;
|
|
19748
|
+
var overlaps2 = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
19749
|
+
function onJambPillars(split) {
|
|
19750
|
+
const pillars = split.parts.filter((part) => part.role === "column" && part.material === "concrete");
|
|
19751
|
+
const extra = [];
|
|
19752
|
+
for (const beam of split.parts) {
|
|
19753
|
+
if (beam.role !== "beam" || !OPENING_BEAM.test(beam.id)) continue;
|
|
19754
|
+
for (const pillar of pillars) if (pillar.floor === beam.floor && overlaps2(pillar.aabb, beam.aabb) && pillar.y0 <= beam.y0 && pillar.y1 >= beam.y1 - 0.01) extra.push({ part: beam.id, on: pillar.id, joint: "rebar" });
|
|
19755
|
+
}
|
|
19756
|
+
return extra.length ? { parts: split.parts, supports: [...split.supports, ...extra] } : split;
|
|
19025
19757
|
}
|
|
19026
19758
|
function applyUnits(input, structure) {
|
|
19027
19759
|
const splits = /* @__PURE__ */ new Map();
|
|
@@ -19083,21 +19815,35 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19083
19815
|
};
|
|
19084
19816
|
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
19085
19817
|
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
19818
|
+
var CAGE_COVER = 0.03;
|
|
19819
|
+
var CAGE_BUCKLING_SHARE = 0.5;
|
|
19820
|
+
var DEFAULT_RESIDUAL = 0.15;
|
|
19821
|
+
function cageResidualCapacity(size, reinforcement, capacity) {
|
|
19822
|
+
const [a = 0, b = 0] = [...size].sort((x, y) => x - y);
|
|
19823
|
+
const perSide = (w) => Math.max(2, Math.floor(Math.max(0, w - 2 * CAGE_COVER) / reinforcement.spacing) + 1);
|
|
19824
|
+
const bars = 2 * perSide(a) + 2 * perSide(b) - 4;
|
|
19825
|
+
const steel = MATERIALS2.find((m) => m.id === reinforcement.material)?.compressive ?? 0;
|
|
19826
|
+
const carries2 = bars * Math.PI * (reinforcement.diameter / 2) ** 2 * steel * CAGE_BUCKLING_SHARE;
|
|
19827
|
+
if (!capacity || capacity <= 0 || carries2 <= 0) return DEFAULT_RESIDUAL;
|
|
19828
|
+
return Math.min(1, Math.max(DEFAULT_RESIDUAL, carries2 / capacity));
|
|
19829
|
+
}
|
|
19086
19830
|
var caged = (spec, part, rebar) => {
|
|
19087
19831
|
if (!rebar || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
19088
19832
|
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
19089
19833
|
if (!size) return spec;
|
|
19090
19834
|
const thin = Math.min(...size);
|
|
19835
|
+
const reinforcement = { material: rebar, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter };
|
|
19091
19836
|
return {
|
|
19092
19837
|
...spec,
|
|
19093
|
-
reinforcement: {
|
|
19838
|
+
reinforcement: part.role === "column" ? { ...reinforcement, residualCapacity: cageResidualCapacity(size, reinforcement, spec.structure?.capacity) } : reinforcement,
|
|
19094
19839
|
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
19095
19840
|
};
|
|
19096
19841
|
};
|
|
19097
19842
|
var partSpecOf = (part, capacity, detailed, rebar) => {
|
|
19098
19843
|
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
19099
19844
|
const spec = boxSpec(part, capacity);
|
|
19100
|
-
|
|
19845
|
+
const out = detailed ? caged(spec, part, rebar) : spec;
|
|
19846
|
+
return part.beamKind === "ground_beam" ? { ...out, anchored: true, structure: { role: "foundation" } } : out;
|
|
19101
19847
|
};
|
|
19102
19848
|
function toDestructibleSpec(structure, options = {}) {
|
|
19103
19849
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
@@ -19113,7 +19859,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19113
19859
|
const walled = applyPanels(slabbed, structure, detail, slabOptions && structure.construction.frame.rebar ? (span) => beamDepthFor(span, slabOptions) : void 0);
|
|
19114
19860
|
const panels = slabOptions && detail !== "coarse" ? deepenBondBeams(walled, structure, slabOptions) : walled;
|
|
19115
19861
|
const sizing = { safety, redundancy, safetyOthers };
|
|
19116
|
-
const
|
|
19862
|
+
const foundation = new Set(panels.parts.filter((part) => part.beamKind === "ground_beam").map((part) => part.id));
|
|
19863
|
+
const onFoundation = foundation.size ? panels.supports.filter((s) => !foundation.has(s.part)).map((s) => foundation.has(s.on) ? { ...s, on: GROUND } : s) : panels.supports;
|
|
19864
|
+
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts.filter((part) => !foundation.has(part.id)), onFoundation, sizing) };
|
|
19117
19865
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
19118
19866
|
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
19119
19867
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
@@ -19178,6 +19926,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19178
19926
|
out.parts = out.parts.map((p, i) => i === ground ? raft2 : p);
|
|
19179
19927
|
return out;
|
|
19180
19928
|
}
|
|
19929
|
+
var LOW_WINDOW = SILL_BEAM_DEPTH + 0.05;
|
|
19181
19930
|
var slabId = (g, f) => f === g.floors - 1 && g.roof ? "roof" : `slab_${f}`;
|
|
19182
19931
|
var storeyBase = (g, f) => f * (g.height + g.slab);
|
|
19183
19932
|
var slabHalf = (g) => [(g.spanX + g.columnSize + 0.2) / 2, (g.spanZ + g.columnSize + 0.2) / 2];
|
|
@@ -19336,7 +20085,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19336
20085
|
parts.push({ id, material: c.material, shape: box2(size), position, structure: { role: "partition" }, tags: ["infill"] });
|
|
19337
20086
|
for (const o of on) rests(joints, id, o, "mortar");
|
|
19338
20087
|
};
|
|
19339
|
-
const bay = (side, k, along,
|
|
20088
|
+
const bay = (side, k, along, centre2, fixed, length, c1, c2) => {
|
|
19340
20089
|
const clear = length - g.columnSize;
|
|
19341
20090
|
const win = clear * c.window;
|
|
19342
20091
|
const pier = (clear - win) / 2;
|
|
@@ -19347,11 +20096,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19347
20096
|
wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on);
|
|
19348
20097
|
};
|
|
19349
20098
|
const id = (name) => `infill_${f}_${side}_${k}_${name}`;
|
|
19350
|
-
put("sill", clear, sill, yb + sill / 2,
|
|
19351
|
-
put("pl", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
19352
|
-
put("pr", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
19353
|
-
put("head", clear, room - head, yb + head + (room - head) / 2,
|
|
19354
|
-
const gp = at2(
|
|
20099
|
+
put("sill", clear, sill, yb + sill / 2, centre2, [c1, c2]);
|
|
20100
|
+
put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre2 - clear / 2 + pier / 2, [c1, id("sill")]);
|
|
20101
|
+
put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre2 + clear / 2 - pier / 2, [c2, id("sill")]);
|
|
20102
|
+
put("head", clear, room - head, yb + head + (room - head) / 2, centre2, [c1, c2]);
|
|
20103
|
+
const gp = at2(centre2);
|
|
19355
20104
|
const gid = `glass_${f}_${side}_${k}`;
|
|
19356
20105
|
parts.push({
|
|
19357
20106
|
id: gid,
|
|
@@ -19995,7 +20744,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19995
20744
|
if (!pc || pc.unit) return sp;
|
|
19996
20745
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
19997
20746
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
19998
|
-
const
|
|
20747
|
+
const cage = def && def.reinforcement ? pc.role === "column" && sp.shape.kind === "box" ? { ...def.reinforcement, residualCapacity: cageResidualCapacity(sp.shape.size, def.reinforcement, sp.structure?.capacity) } : { ...def.reinforcement } : null;
|
|
20748
|
+
const out = cage && !sp.reinforcement ? { ...sp, reinforcement: cage } : sp;
|
|
19999
20749
|
if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
|
|
20000
20750
|
return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
|
|
20001
20751
|
}
|
|
@@ -20023,6 +20773,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20023
20773
|
const a = pos.array;
|
|
20024
20774
|
const u = mesh2.userData;
|
|
20025
20775
|
if (!u._p0) u._p0 = a.slice();
|
|
20776
|
+
if (!u.plainPositions) Object.defineProperty(u, "plainPositions", { value: u._p0, enumerable: false, configurable: true, writable: true });
|
|
20026
20777
|
const list2 = u.collapsedRanges ?? (u.collapsedRanges = []);
|
|
20027
20778
|
if (!list2.some((r) => r[0] === v0 && r[1] === v1)) list2.push([v0, v1]);
|
|
20028
20779
|
const saved = a.slice(v0 * 3, v1 * 3);
|
|
@@ -20106,10 +20857,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20106
20857
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
20107
20858
|
return [v.x, v.y, v.z];
|
|
20108
20859
|
};
|
|
20109
|
-
function cells(part, units) {
|
|
20860
|
+
function cells(part, units, mask) {
|
|
20110
20861
|
const [u0, v0, u1, v1] = part.aabb;
|
|
20111
|
-
const alongU =
|
|
20862
|
+
const alongU = mask.alongU;
|
|
20112
20863
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
20864
|
+
const offset = (alongU ? u0 : v0) - mask.start;
|
|
20113
20865
|
const [ul, uh] = units.size;
|
|
20114
20866
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
20115
20867
|
const rowH = (part.y1 - part.y0) / rows;
|
|
@@ -20120,7 +20872,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20120
20872
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
20121
20873
|
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
20122
20874
|
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
20123
|
-
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
20875
|
+
if (b - a > 1e-3) out.push({ a: offset + a, b: offset + b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
20124
20876
|
}
|
|
20125
20877
|
}
|
|
20126
20878
|
return out;
|
|
@@ -20134,8 +20886,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20134
20886
|
for (const q of structure.parts) {
|
|
20135
20887
|
if (q.id !== partId && same(q.aabb, part.aabb) && Math.abs(q.y1 - part.y0) < 0.01 && structure.meshesOf(q.id).some((it) => it.mesh)) return q.id;
|
|
20136
20888
|
}
|
|
20889
|
+
return part.role === "column" ? wallAround(part) : null;
|
|
20890
|
+
}
|
|
20891
|
+
function wallAround(part) {
|
|
20892
|
+
const cu = (part.aabb[0] + part.aabb[2]) / 2, cv = (part.aabb[1] + part.aabb[3]) / 2;
|
|
20893
|
+
for (const q of structure.parts) {
|
|
20894
|
+
if (q.id === part.id || q.role !== "wall" && q.role !== "partition" || !structure.meshesOf(q.id).some((it) => it.mesh)) continue;
|
|
20895
|
+
const inside2 = cu >= q.aabb[0] - 1e-3 && cu <= q.aabb[2] + 1e-3 && cv >= q.aabb[1] - 1e-3 && cv <= q.aabb[3] + 1e-3;
|
|
20896
|
+
if (inside2 && Math.min(q.y1, part.y1) - Math.max(q.y0, part.y0) > 0.5) return q.id;
|
|
20897
|
+
}
|
|
20137
20898
|
return null;
|
|
20138
20899
|
}
|
|
20900
|
+
const pillarSpans = (view) => structure.parts.filter((q) => q.role === "column" && wallAround(q) === view.host).map((q) => {
|
|
20901
|
+
const a = (view.mask.alongU ? q.aabb[0] : q.aabb[1]) - view.mask.start, b = (view.mask.alongU ? q.aabb[2] : q.aabb[3]) - view.mask.start;
|
|
20902
|
+
return { a, b, y0: q.y0, y1: q.y1 };
|
|
20903
|
+
});
|
|
20139
20904
|
const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
|
|
20140
20905
|
function shell(it, mask) {
|
|
20141
20906
|
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
@@ -20224,6 +20989,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20224
20989
|
texture.needsUpdate = true;
|
|
20225
20990
|
return { data, texture, w, h, alongU, start: alongU ? u0 : v0, len, y0, height: y1 - y0, rect: new THREE.Vector4(alongU ? u0 : v0, y0, len, y1 - y0) };
|
|
20226
20991
|
}
|
|
20992
|
+
function besidePillars(c, pillars) {
|
|
20993
|
+
let { a, b } = c;
|
|
20994
|
+
for (const k of pillars) {
|
|
20995
|
+
if (c.y1 <= k.y0 || c.y0 >= k.y1 || b <= k.a || a >= k.b) continue;
|
|
20996
|
+
const centre = (a + b) / 2;
|
|
20997
|
+
if (centre > k.a && centre < k.b) return [];
|
|
20998
|
+
if (centre <= k.a) b = Math.min(b, k.a);
|
|
20999
|
+
else a = Math.max(a, k.b);
|
|
21000
|
+
}
|
|
21001
|
+
return b - a > 1e-3 ? [{ ...c, a, b }] : [];
|
|
21002
|
+
}
|
|
20227
21003
|
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
20228
21004
|
const ellipseDistance = (s, y, cs, cy, rs, ry) => (Math.hypot((s - cs) / Math.max(rs, 1e-4), (y - cy) / Math.max(ry, 1e-4)) - 1) * Math.min(rs, ry);
|
|
20229
21005
|
function covered(c, boxes) {
|
|
@@ -20246,9 +21022,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20246
21022
|
const discs = [];
|
|
20247
21023
|
const flakes = [];
|
|
20248
21024
|
const shown = [];
|
|
21025
|
+
const pillars = pillarSpans(view);
|
|
20249
21026
|
for (const id of view.parts) {
|
|
20250
21027
|
const part = structure.byId.get(id), units2 = specOf(id).units, chips = view.chips.get(id), opening = view.openings.get(id), spalls = view.spalls.get(id);
|
|
20251
|
-
const
|
|
21028
|
+
const own = cells(part, units2, mask);
|
|
21029
|
+
const all = id === view.host ? own.flatMap((c) => besidePillars(c, pillars)) : own;
|
|
21030
|
+
if (view.fallen.has(id)) {
|
|
21031
|
+
holes.push(...all);
|
|
21032
|
+
continue;
|
|
21033
|
+
}
|
|
20252
21034
|
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
20253
21035
|
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
20254
21036
|
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
@@ -20344,52 +21126,55 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20344
21126
|
}
|
|
20345
21127
|
return { center: local(chip.center), along: a, up: u };
|
|
20346
21128
|
}
|
|
21129
|
+
function newView(hostId) {
|
|
21130
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
21131
|
+
if (!items.length) return null;
|
|
21132
|
+
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
21133
|
+
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
21134
|
+
return {
|
|
21135
|
+
host: hostId,
|
|
21136
|
+
parts,
|
|
21137
|
+
items,
|
|
21138
|
+
mask,
|
|
21139
|
+
core,
|
|
21140
|
+
unitMaterial: unitsMaterial(core),
|
|
21141
|
+
shells: [],
|
|
21142
|
+
saved: null,
|
|
21143
|
+
units: null,
|
|
21144
|
+
gone: 0,
|
|
21145
|
+
pits: 0,
|
|
21146
|
+
bounds: drawnBounds(items),
|
|
21147
|
+
chips: new Map(parts.map((id) => [id, []])),
|
|
21148
|
+
spalls: new Map(parts.map((id) => [id, []])),
|
|
21149
|
+
openings: /* @__PURE__ */ new Map(),
|
|
21150
|
+
flakes: 0,
|
|
21151
|
+
fallen: /* @__PURE__ */ new Set()
|
|
21152
|
+
};
|
|
21153
|
+
}
|
|
21154
|
+
function cut(view) {
|
|
21155
|
+
if (view.saved) return;
|
|
21156
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
21157
|
+
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
21158
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
21159
|
+
}
|
|
20347
21160
|
function draw2(partId, change) {
|
|
20348
21161
|
if (lod !== 0) return false;
|
|
20349
21162
|
const hostId = hostOf(partId);
|
|
20350
21163
|
if (!hostId || !specOf(partId)?.units) return false;
|
|
20351
|
-
|
|
20352
|
-
if (!view)
|
|
20353
|
-
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
20354
|
-
if (!items.length) return false;
|
|
20355
|
-
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
20356
|
-
if (!parts.includes(partId)) return false;
|
|
20357
|
-
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
20358
|
-
view = {
|
|
20359
|
-
host: hostId,
|
|
20360
|
-
parts,
|
|
20361
|
-
items,
|
|
20362
|
-
mask,
|
|
20363
|
-
core,
|
|
20364
|
-
unitMaterial: unitsMaterial(core),
|
|
20365
|
-
shells: [],
|
|
20366
|
-
saved: null,
|
|
20367
|
-
units: null,
|
|
20368
|
-
gone: 0,
|
|
20369
|
-
pits: 0,
|
|
20370
|
-
bounds: drawnBounds(items),
|
|
20371
|
-
chips: new Map(parts.map((id) => [id, []])),
|
|
20372
|
-
spalls: new Map(parts.map((id) => [id, []])),
|
|
20373
|
-
openings: /* @__PURE__ */ new Map(),
|
|
20374
|
-
flakes: 0
|
|
20375
|
-
};
|
|
20376
|
-
}
|
|
20377
|
-
if (!view.chips.has(partId)) return false;
|
|
21164
|
+
const view = views.get(hostId) ?? newView(hostId);
|
|
21165
|
+
if (!view || !view.chips.has(partId)) return false;
|
|
20378
21166
|
if (change.opening) {
|
|
20379
21167
|
if (view.openings.has(partId)) return false;
|
|
20380
21168
|
view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
|
|
20381
21169
|
}
|
|
20382
21170
|
if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
|
|
21171
|
+
for (const chip of change.chips ?? []) view.chips.get(partId).push(chipBox(chip, view.mask.alongU));
|
|
20383
21172
|
if (change.spall) {
|
|
20384
21173
|
const list2 = view.spalls.get(partId);
|
|
20385
21174
|
list2.push({ center: local(change.spall.center), radius: change.spall.radius });
|
|
20386
21175
|
if (list2.length > MAX_FLAKES) list2.shift();
|
|
20387
21176
|
}
|
|
20388
|
-
|
|
20389
|
-
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
20390
|
-
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
20391
|
-
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
20392
|
-
}
|
|
21177
|
+
cut(view);
|
|
20393
21178
|
views.set(hostId, view);
|
|
20394
21179
|
if (opts.deferPaint && change.spall) dirty.add(view);
|
|
20395
21180
|
else {
|
|
@@ -20500,14 +21285,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20500
21285
|
*/
|
|
20501
21286
|
chip(event) {
|
|
20502
21287
|
if (event.torn) return false;
|
|
20503
|
-
|
|
21288
|
+
const rotation = event.rotation ?? [0, 0, 0, 1];
|
|
21289
|
+
if (event.units?.length) return draw2(event.part, { chips: event.units.map((unit) => ({ center: unit.center, size: unit.size, rotation })) });
|
|
21290
|
+
return draw2(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation } });
|
|
20504
21291
|
},
|
|
20505
21292
|
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
20506
21293
|
drop(partId) {
|
|
20507
|
-
|
|
20508
|
-
if (!
|
|
21294
|
+
let host = views.get(partId) ?? [...views.values()].find((view) => view.parts.includes(partId));
|
|
21295
|
+
if (!host && lod === 0 && riders(partId).length > 0) {
|
|
21296
|
+
host = newView(partId);
|
|
21297
|
+
if (host) {
|
|
21298
|
+
cut(host);
|
|
21299
|
+
views.set(partId, host);
|
|
21300
|
+
}
|
|
21301
|
+
}
|
|
21302
|
+
if (!host) return;
|
|
21303
|
+
host.fallen.add(partId);
|
|
21304
|
+
if (host.parts.some((id) => !host.fallen.has(id))) {
|
|
21305
|
+
dirty.delete(host);
|
|
21306
|
+
paint(host);
|
|
21307
|
+
invalidate();
|
|
21308
|
+
invalidateShadow();
|
|
21309
|
+
return;
|
|
21310
|
+
}
|
|
21311
|
+
const v = host;
|
|
20509
21312
|
dispose(v);
|
|
20510
|
-
views.delete(
|
|
21313
|
+
views.delete(v.host);
|
|
20511
21314
|
if (v.saved) dropped.push(v);
|
|
20512
21315
|
},
|
|
20513
21316
|
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
@@ -20948,8 +21751,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20948
21751
|
// src/build/build.ts
|
|
20949
21752
|
function installBuildBuild(K, shared) {
|
|
20950
21753
|
const { THREE, cfg, rectsOf: rectsOf2, invalidateShadow, colliderChanged, VERSION: VERSION2, CARS, EPS: EPS3, LIGHTS, MIRRORS, Y0, animateClotheslines, animateDoors, animateInteractive, applyLeaf, applyOutbuildings, applyPart, applyPiece, assembleInteractive, baseboardAndSidewalk, buildStairs, building, carModel, chooseMirror, closeScene, collideAt, createWater, cursor, doorText, doors, electricalStructure, elevator, floorsAndSlabs, gatesInteractive, houseItems, ivAssemble, ivBuild, ivDispose, ivParts, ivPublish, ivUpdate, lightOn, linkDoorLeaves, mailboxInteractive, newInteractiveState, newMirrorState, outbuildings, paths, perimeter, placeSwitches, roofs, roomAt, solar, targetOf, terrain, toggleDoor, toggleLight, walls, waterPipes, windows, props, TYPES, IVK, VEG, vegMaterials, markGroups, assembleStructure, createHouseDestruction, newState, enter, tagDamage } = K;
|
|
20951
|
-
function build(r0,
|
|
20952
|
-
opts =
|
|
21754
|
+
function build(r0, options) {
|
|
21755
|
+
const opts = options || {};
|
|
20953
21756
|
const r = applyOutbuildings(r0);
|
|
20954
21757
|
const t0 = performance.now();
|
|
20955
21758
|
const h = { ctx: { mv: props, types: TYPES }, inter: newInteractiveState(), state: opts.state || newState(), mirrors: newMirrorState(), quality: opts.quality === "game" || opts.quality === "high" ? opts.quality : cfg.quality === "game" ? "game" : "high", lodCurrent: 0, lodMin: 0 };
|
|
@@ -20970,7 +21773,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20970
21773
|
shared.ctx.pieces = /* @__PURE__ */ new Map();
|
|
20971
21774
|
shared.ctx.pieceObjects = /* @__PURE__ */ new Map();
|
|
20972
21775
|
shared.ctx.structureIndex = {};
|
|
20973
|
-
for (const e of r0.structure
|
|
21776
|
+
for (const e of r0.structure?.parts || []) shared.ctx.structureIndex[e.id] = e;
|
|
20974
21777
|
{
|
|
20975
21778
|
const view = shared.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
|
|
20976
21779
|
shared.ctx.panelsOf = /* @__PURE__ */ new Map();
|
|
@@ -20982,17 +21785,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20982
21785
|
else shared.ctx.panelsOf.set(e.slab, [e]);
|
|
20983
21786
|
}
|
|
20984
21787
|
}
|
|
20985
|
-
shared.ctx.panes = r0.roof
|
|
21788
|
+
shared.ctx.panes = r0.roof?.panes || [];
|
|
20986
21789
|
shared.ctx.noPiece = false;
|
|
20987
21790
|
cursor.separate = opts.pieces === "meshes";
|
|
20988
21791
|
cursor.pc = null;
|
|
21792
|
+
shared.ctx.showPillars = opts.pillars !== "hidden";
|
|
20989
21793
|
shared.ctx.apartment = r.template === "apartment_modern";
|
|
20990
21794
|
shared.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
|
|
20991
21795
|
shared.ctx.pf = Math.max(1, Math.min(shared.ctx.pa, pr.floor != null ? pr.floor : 3));
|
|
20992
21796
|
shared.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
|
|
20993
21797
|
shared.ctx.showBuilding = shared.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
|
|
20994
21798
|
shared.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
|
|
20995
|
-
shared.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared.quality === "game" ? { quality: "game" } : { lod: 0, triangleBudget: 6e4 } } : null;
|
|
21799
|
+
shared.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared.quality === "game" ? { quality: "game" } : { quality: "high", lod: 0, triangleBudget: 6e4 } } : null;
|
|
20996
21800
|
shared.ctx.vegInfo = null;
|
|
20997
21801
|
terrain();
|
|
20998
21802
|
if (r.lot) {
|
|
@@ -21042,7 +21846,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21042
21846
|
const g = gs[gd.name];
|
|
21043
21847
|
if (!g) continue;
|
|
21044
21848
|
delete gs[gd.name];
|
|
21045
|
-
g.position.
|
|
21849
|
+
g.position.fromArray(gd.pos);
|
|
21046
21850
|
parent.add(g);
|
|
21047
21851
|
fo.gs.push(g);
|
|
21048
21852
|
}
|
|
@@ -21057,7 +21861,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21057
21861
|
root.add(house);
|
|
21058
21862
|
shared.mirrors.house = house;
|
|
21059
21863
|
if (shared.ctx.apartment) {
|
|
21060
|
-
const
|
|
21864
|
+
const units = r.building.units, u = units[Math.min(shared.ctx.pu, units.length - 1)];
|
|
21061
21865
|
house.position.set(u.u, shared.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
|
|
21062
21866
|
house.rotation.y = u.ry;
|
|
21063
21867
|
shared.ctx.unitRy = u.ry;
|
|
@@ -21173,7 +21977,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21173
21977
|
const wallAt = (f, axis, L) => r.walls.find((w) => w.floor === f && w.axis === axis && Math.abs((axis === "u" ? w.v0 : w.u0) - L) < EPS3);
|
|
21174
21978
|
for (const j of r.windows) {
|
|
21175
21979
|
const alongU = j.axis === "u", y0 = Y0(j.floor), a = j.at - j.width / 2, b = j.at + j.width / 2, w = wallAt(j.floor, j.axis, j.pos), th = w ? w.thickness || 0.15 : 0.15, L = j.pos, id = "window:" + j.id;
|
|
21176
|
-
|
|
21980
|
+
const jy0 = j.y0, jy1 = j.y1;
|
|
21981
|
+
parts[id] = { id, type: "window", group: null, virtual: true, floor: j.floor, aabb: alongU ? [a, y0 + jy0, L - th / 2, b, y0 + jy1, L + th / 2] : [L - th / 2, y0 + jy0, a, L + th / 2, y0 + jy1, b], damageable: tagDamage("glass"), opens: () => {
|
|
21177
21982
|
}, t: 0 };
|
|
21178
21983
|
}
|
|
21179
21984
|
for (const E of mirrorsCopy) {
|
|
@@ -21216,7 +22021,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21216
22021
|
const countDraw = () => {
|
|
21217
22022
|
let n = 0, t = 0;
|
|
21218
22023
|
root.traverseVisible((o) => {
|
|
21219
|
-
if (o
|
|
22024
|
+
if (isMesh(o)) {
|
|
21220
22025
|
n++;
|
|
21221
22026
|
t += (o.geometry.index ? o.geometry.index.count : o.geometry.attributes.position.count) / 3;
|
|
21222
22027
|
}
|
|
@@ -21230,8 +22035,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21230
22035
|
const budget = opts.drawCallBudget != null ? opts.drawCallBudget : cfg.drawCallBudget;
|
|
21231
22036
|
const stats2 = { quality: h.quality, drawCalls: s0.n, drawCallsLOD1: s1.n, triangles: s0.t, trianglesLod1: s1.t, budget: budget || null, overBudget: !!budget && s0.n > budget, tBuild: performance.now() - t0 };
|
|
21232
22037
|
shared.ctx.tBuild = stats2.tBuild;
|
|
21233
|
-
const applyLod = (
|
|
21234
|
-
n = Math.max(0, Math.min(2,
|
|
22038
|
+
const applyLod = (level) => {
|
|
22039
|
+
const n = Math.max(0, Math.min(2, level | 0));
|
|
21235
22040
|
if (n === h.lodCurrent) return;
|
|
21236
22041
|
h.lodCurrent = n;
|
|
21237
22042
|
for (const o of lodObjects) o.visible = n < 1;
|
|
@@ -21308,7 +22113,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21308
22113
|
lights: (() => {
|
|
21309
22114
|
const by = {};
|
|
21310
22115
|
for (const l of shared.ctx.lights) {
|
|
21311
|
-
const k = l.roomId != null ? l.roomId : l.room;
|
|
22116
|
+
const k = String(l.roomId != null ? l.roomId : l.room);
|
|
21312
22117
|
(by[k] || (by[k] = [])).push(l);
|
|
21313
22118
|
}
|
|
21314
22119
|
return { list: shared.ctx.lights, byRoom: by };
|
|
@@ -21348,9 +22153,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21348
22153
|
applyLod(Math.max(n, h.lodMin));
|
|
21349
22154
|
}
|
|
21350
22155
|
},
|
|
21351
|
-
show(
|
|
22156
|
+
show(options2) {
|
|
21352
22157
|
enter(h);
|
|
21353
|
-
o =
|
|
22158
|
+
const o = options2 || {};
|
|
21354
22159
|
const rr = shared.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
|
|
21355
22160
|
for (const [k, g] of Object.entries(gs)) {
|
|
21356
22161
|
let v = true;
|
|
@@ -21370,7 +22175,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21370
22175
|
enter(h);
|
|
21371
22176
|
const a = targetOf(o, opt);
|
|
21372
22177
|
if (!a) return false;
|
|
21373
|
-
return actOn(a.target && a.target.pub ? a.target.pub : { id: a.target && a.target.id || a.text, type: a.target && a.target.kit ? a.target.type : "door", label: a.text, ref: a.target, _action: a.action }, a);
|
|
22178
|
+
return actOn(a.target && a.target.pub ? a.target.pub : { id: a.target && a.target.id || a.text, type: a.target && a.target.kit ? a.target.type : "door", label: a.text, ref: a.target, _action: a.action, floor: 0, pos: [], radius: 0 }, a);
|
|
21374
22179
|
},
|
|
21375
22180
|
message() {
|
|
21376
22181
|
return shared.inter.msg && performance.now() < shared.inter.msg.until ? shared.inter.msg.text : null;
|
|
@@ -21427,13 +22232,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21427
22232
|
}
|
|
21428
22233
|
return null;
|
|
21429
22234
|
},
|
|
21430
|
-
partAt(p,
|
|
21431
|
-
tol =
|
|
22235
|
+
partAt(p, tolerance) {
|
|
22236
|
+
const tol = tolerance || 0.05;
|
|
21432
22237
|
let m = null;
|
|
21433
22238
|
for (const k in parts) {
|
|
21434
|
-
const
|
|
22239
|
+
const part = parts[k], a = part.aabb;
|
|
21435
22240
|
if (a && p.x >= a[0] - tol && p.x <= a[3] + tol && p.y >= a[1] - tol && p.y <= a[4] + tol && p.z >= a[2] - tol && p.z <= a[5] + tol) {
|
|
21436
|
-
m =
|
|
22241
|
+
m = part;
|
|
21437
22242
|
break;
|
|
21438
22243
|
}
|
|
21439
22244
|
}
|
|
@@ -21444,8 +22249,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21444
22249
|
destruction.deactivate();
|
|
21445
22250
|
if (h.IV) ivDispose(h);
|
|
21446
22251
|
root.traverse((o) => {
|
|
21447
|
-
if (o
|
|
21448
|
-
if (o.type === "Reflector" && o.dispose) o.dispose();
|
|
22252
|
+
if (isMesh(o) && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
|
|
22253
|
+
if (o.type === "Reflector" && "dispose" in o && typeof o.dispose === "function") o.dispose();
|
|
21449
22254
|
});
|
|
21450
22255
|
root.removeFromParent();
|
|
21451
22256
|
},
|
|
@@ -21453,7 +22258,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21453
22258
|
};
|
|
21454
22259
|
return res;
|
|
21455
22260
|
}
|
|
21456
|
-
|
|
22261
|
+
const defined = { build };
|
|
22262
|
+
Object.assign(K, defined);
|
|
21457
22263
|
}
|
|
21458
22264
|
|
|
21459
22265
|
// src/build/api.ts
|
|
@@ -21475,11 +22281,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21475
22281
|
lighting,
|
|
21476
22282
|
effectLights,
|
|
21477
22283
|
setNight(n) {
|
|
21478
|
-
shared.mats.glass
|
|
21479
|
-
|
|
22284
|
+
const glass = shared.mats.glass;
|
|
22285
|
+
glass.emissive.set(n ? 9067040 : 0);
|
|
22286
|
+
glass.opacity = n ? 0.4 : 0.24;
|
|
21480
22287
|
},
|
|
21481
22288
|
/** The chipped-plaster painting of every house of this renderer as a `DeferredQueue` for a frame budget (id `floorplan.breach-paint`); asking for it changes nothing. */
|
|
21482
22289
|
deferredQueue: () => K.breachPaintQueue,
|
|
22290
|
+
/* the destruction side is typed with the breach */
|
|
21483
22291
|
cars: { model: carModel, group: carGroup, info: (k, seed) => {
|
|
21484
22292
|
const m = carModel(k, seed);
|
|
21485
22293
|
return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
|
|
@@ -22116,7 +22924,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22116
22924
|
const stopListening = () => {
|
|
22117
22925
|
for (const off of listening.splice(0)) off?.();
|
|
22118
22926
|
};
|
|
22119
|
-
const collapsed = (list2) => list2.
|
|
22927
|
+
const collapsed = (list2) => list2.flatMap((e) => e.type === "collapse" ? e.parts.map((p) => p.id || p) : []);
|
|
22120
22928
|
const whole = (room, oid, pid) => {
|
|
22121
22929
|
const p = room.world.part(oid, pid);
|
|
22122
22930
|
return !!p && p.status !== "broken" && !p.stripped;
|
|
@@ -22153,10 +22961,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22153
22961
|
const list2 = events(room);
|
|
22154
22962
|
const columns = groundColumns(parts);
|
|
22155
22963
|
const laj = slabs(parts);
|
|
22156
|
-
const first = columns[0];
|
|
22157
|
-
const mate = columns.
|
|
22158
|
-
|
|
22159
|
-
blunt(room, oid,
|
|
22964
|
+
const first = columns.find((p) => !/^wall_column_/.test(p.id)) ?? columns[0];
|
|
22965
|
+
const mate = columns.filter((p) => p !== first && !/^wall_column_/.test(p.id)).filter((p) => Math.abs(p.position[0] - first.position[0]) < 0.5).sort((a, b) => Math.abs(b.position[2] - first.position[2]) - Math.abs(a.position[2] - first.position[2]))[0] ?? columns[1];
|
|
22966
|
+
const along = columns.filter((p) => /^wall_column_/.test(p.id) && Math.abs(p.position[0] - first.position[0]) < 0.5);
|
|
22967
|
+
for (const p of [first, mate, ...along]) blunt(room, oid, p.id, centre(p.id), 3e6);
|
|
22160
22968
|
step(90);
|
|
22161
22969
|
const fell = collapsed(list2);
|
|
22162
22970
|
expect(laj.some((id) => fell.includes(id)), fill(T2.two_slab_fell, { n: fell.length }));
|
|
@@ -22476,9 +23284,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22476
23284
|
return best;
|
|
22477
23285
|
};
|
|
22478
23286
|
const eyeOf = (p) => {
|
|
23287
|
+
const T2 = THREE;
|
|
22479
23288
|
const camera = host?.camera;
|
|
22480
23289
|
const at2 = toLocal2(p, camera.position.x, camera.position.y, camera.position.z);
|
|
22481
|
-
const forward = new
|
|
23290
|
+
const forward = new T2.Vector3(0, 0, -1).applyQuaternion(camera.quaternion).transformDirection(new T2.Matrix4().copy(p.house.group.matrixWorld).invert());
|
|
22482
23291
|
return { x: at2.x, y: at2.y, z: at2.z, floor: floorOf(p, camera.position.y), yaw: Math.atan2(forward.x, forward.z), pitch: Math.asin(Math.max(-1, Math.min(1, forward.y))) };
|
|
22483
23292
|
};
|
|
22484
23293
|
const blocked = (x, z, radius) => {
|
|
@@ -22494,8 +23303,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22494
23303
|
const standAt = (p, u, v, floor, lookU, lookV) => {
|
|
22495
23304
|
if (!host?.bench) return;
|
|
22496
23305
|
const y = p.house.y0(floor) + EYE;
|
|
22497
|
-
const
|
|
22498
|
-
const
|
|
23306
|
+
const T2 = THREE;
|
|
23307
|
+
const eye = p.house.group.localToWorld(new T2.Vector3(u, y, v));
|
|
23308
|
+
const target = p.house.group.localToWorld(new T2.Vector3(lookU, y - 0.1, lookV));
|
|
22499
23309
|
host.bench.look([eye.x, eye.y, eye.z], [target.x, target.y, target.z]);
|
|
22500
23310
|
floorNow = floor;
|
|
22501
23311
|
};
|
|
@@ -22545,16 +23355,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22545
23355
|
host?.log(fill(text.steps.door, { text: String(target.text) }));
|
|
22546
23356
|
};
|
|
22547
23357
|
const doorReach = (p, fo) => {
|
|
23358
|
+
const T2 = THREE;
|
|
22548
23359
|
const g = fo.gs[0];
|
|
22549
23360
|
const pivot = fo.handles[0].pivot;
|
|
22550
23361
|
const at2 = (angle) => {
|
|
22551
23362
|
const c = Math.cos(angle);
|
|
22552
23363
|
const s = Math.sin(angle);
|
|
22553
|
-
const v = new
|
|
23364
|
+
const v = new T2.Vector3(pivot[0] * c + pivot[2] * s, pivot[1], -pivot[0] * s + pivot[2] * c).add(g.position);
|
|
22554
23365
|
return g.parent ? g.parent.localToWorld(v) : v;
|
|
22555
23366
|
};
|
|
22556
23367
|
const camera = host?.camera;
|
|
22557
|
-
const eye = new
|
|
23368
|
+
const eye = new T2.Vector3(camera.position.x, 0, camera.position.z);
|
|
22558
23369
|
const flat = (v) => Math.hypot(v.x - eye.x, v.z - eye.z);
|
|
22559
23370
|
const closed = at2(0);
|
|
22560
23371
|
const open = at2(fo.rot);
|
|
@@ -22562,9 +23373,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22562
23373
|
return {
|
|
22563
23374
|
handle: () => {
|
|
22564
23375
|
g.updateMatrixWorld(true);
|
|
22565
|
-
return g.localToWorld(new
|
|
23376
|
+
return g.localToWorld(new T2.Vector3(pivot[0], pivot[1], pivot[2])).toArray();
|
|
22566
23377
|
},
|
|
22567
|
-
hinge: () => g.getWorldPosition(new
|
|
23378
|
+
hinge: () => g.getWorldPosition(new T2.Vector3()).toArray(),
|
|
22568
23379
|
seconds: fo.locked || fo.blockedFlag ? 0.6 : 0.55,
|
|
22569
23380
|
pull: opening ? flat(open) <= flat(closed) : flat(closed) <= flat(open),
|
|
22570
23381
|
locked: !!(fo.locked || fo.blockedFlag)
|
|
@@ -24329,6 +25140,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24329
25140
|
}
|
|
24330
25141
|
|
|
24331
25142
|
// src/wall.ts
|
|
25143
|
+
var WARM_UP_SHOT = { type: "ballistic", point: [0, 1.2, 0.1], direction: [0, 0, -1], energy: 3500, caliber: 7.62 };
|
|
25144
|
+
var WARM_UP_FRAMES = 5;
|
|
25145
|
+
var isTexture = (value) => typeof value === "object" && value !== null && value.isTexture === true;
|
|
24332
25146
|
var PLASTER = 15262420;
|
|
24333
25147
|
var WALL_ID = "wall_0_0";
|
|
24334
25148
|
function wallPlan(options) {
|
|
@@ -24359,9 +25173,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24359
25173
|
waterTank: null,
|
|
24360
25174
|
outbuildings: []
|
|
24361
25175
|
};
|
|
24362
|
-
|
|
24363
|
-
|
|
24364
|
-
return plan;
|
|
25176
|
+
const construction = masonryConstruction({ ...plan, facade: { ...facade, roof: "colonial" } });
|
|
25177
|
+
const structure = buildStructure({ ...plan, construction }, { wallDetail: "coarse", construction, roof: false });
|
|
25178
|
+
return Object.assign(plan, { construction, structure });
|
|
24365
25179
|
}
|
|
24366
25180
|
function draw(THREE, plan, options) {
|
|
24367
25181
|
return create3(THREE, { ...options, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true, pieces: "meshes" });
|
|
@@ -24371,7 +25185,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24371
25185
|
houses.set(house.group, house);
|
|
24372
25186
|
for (const [id, items] of Object.entries(house.destruction.ranges())) {
|
|
24373
25187
|
for (const item of items) {
|
|
24374
|
-
const object2 =
|
|
25188
|
+
const object2 = "isObject3D" in item ? item : item.mesh;
|
|
24375
25189
|
object2.userData.destructionPart = id;
|
|
24376
25190
|
}
|
|
24377
25191
|
}
|
|
@@ -24387,7 +25201,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24387
25201
|
plan,
|
|
24388
25202
|
spec,
|
|
24389
25203
|
build: (T2) => label(draw(T2, plan, houseOptions)),
|
|
24390
|
-
follow: (root, world, objectId) => houses.get(root)?.destruction?.follow?.(world, objectId, spec) ?? null
|
|
25204
|
+
follow: (root, world, objectId) => houses.get(root)?.destruction?.follow?.(world, objectId, spec) ?? null,
|
|
25205
|
+
warmUpProbes: (T2) => {
|
|
25206
|
+
const house = draw(T2, plan, houseOptions);
|
|
25207
|
+
const root = label(house);
|
|
25208
|
+
const world = createDestruction({ seed: 1 });
|
|
25209
|
+
const objectId = world.add(spec, { id: "warm_up_wall" });
|
|
25210
|
+
const destruction = house.destruction;
|
|
25211
|
+
const follower = destruction?.follow?.(world, objectId, spec) ?? null;
|
|
25212
|
+
world.hitPart(objectId, WALL_ID, WARM_UP_SHOT);
|
|
25213
|
+
for (let frame2 = 0; frame2 < WARM_UP_FRAMES; frame2++) {
|
|
25214
|
+
world.update(1 / 60);
|
|
25215
|
+
follower?.update?.();
|
|
25216
|
+
}
|
|
25217
|
+
for (let guard = 0; guard < WARM_UP_FRAMES && (destruction?.breach?.flush?.(Infinity) ?? 0) > 0; guard++) ;
|
|
25218
|
+
root.traverse((node) => {
|
|
25219
|
+
node.visible = true;
|
|
25220
|
+
node.frustumCulled = false;
|
|
25221
|
+
});
|
|
25222
|
+
return {
|
|
25223
|
+
group: root,
|
|
25224
|
+
// the materials stay: the warmup keeps them as anchors, and disposing the last material of a program frees the program it was drawn for (so the
|
|
25225
|
+
// follower is not disposed either: it would put the wall back and dispose the breach's materials; its world goes with the probe)
|
|
25226
|
+
dispose: () => {
|
|
25227
|
+
root.traverse((node) => {
|
|
25228
|
+
node.geometry?.dispose();
|
|
25229
|
+
for (const material of Array.isArray(node.material) ? node.material : node.material ? [node.material] : []) {
|
|
25230
|
+
for (const uniform2 of Object.values(material.uniforms ?? {})) if (isTexture(uniform2.value)) uniform2.value.dispose();
|
|
25231
|
+
material.map?.dispose();
|
|
25232
|
+
}
|
|
25233
|
+
});
|
|
25234
|
+
}
|
|
25235
|
+
};
|
|
25236
|
+
}
|
|
24391
25237
|
};
|
|
24392
25238
|
}
|
|
24393
25239
|
return __toCommonJS(index_exports);
|