@forgeax/engine-scene 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -2
- package/dist/__tests__/fixtures/malformed-hierarchy-edge.d.ts +5 -3
- package/dist/__tests__/fixtures/malformed-hierarchy-edge.d.ts.map +1 -1
- package/dist/__tests__/hierarchy-propagation.perf.test.d.ts +2 -0
- package/dist/__tests__/hierarchy-propagation.perf.test.d.ts.map +1 -0
- package/dist/components/child-of.d.ts +11 -9
- package/dist/components/child-of.d.ts.map +1 -1
- package/dist/components/children.d.ts +14 -13
- package/dist/components/children.d.ts.map +1 -1
- package/dist/index.mjs +677 -157
- package/dist/index.mjs.map +1 -1
- package/dist/instances/scene-instances.d.ts +1 -1
- package/dist/systems/propagate-transforms.d.ts +21 -0
- package/dist/systems/propagate-transforms.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/fixtures/malformed-hierarchy-edge.ts +26 -4
- package/src/__tests__/hierarchy-propagation.perf.test.ts +149 -0
- package/src/__tests__/propagation.unit.test.ts +70 -6
- package/src/components/child-of.ts +26 -22
- package/src/components/children.ts +30 -37
- package/src/instances/scene-instances.ts +4 -4
- package/src/systems/propagate-transforms.ts +966 -195
package/dist/index.mjs
CHANGED
|
@@ -1234,15 +1234,30 @@ function sceneTopoSort(nodes) {
|
|
|
1234
1234
|
import {
|
|
1235
1235
|
defineSystem,
|
|
1236
1236
|
defineSystemSet,
|
|
1237
|
+
ENTITY_NULL_RAW as ENTITY_NULL_RAW2,
|
|
1237
1238
|
FixedUpdate,
|
|
1238
1239
|
Update
|
|
1239
1240
|
} from "@forgeax/engine-ecs";
|
|
1241
|
+
import {
|
|
1242
|
+
getDerivedWriter,
|
|
1243
|
+
worldInternal
|
|
1244
|
+
} from "@forgeax/engine-ecs/internal";
|
|
1240
1245
|
import { mat4 } from "@forgeax/engine-math";
|
|
1241
1246
|
import { err as err5, ok as ok5 } from "@forgeax/engine-types";
|
|
1242
1247
|
var PROPAGATE_TRANSFORMS_SYSTEM = "propagateTransforms";
|
|
1243
1248
|
var PROPAGATE_TRANSFORMS_FIXED_SYSTEM = "propagateTransformsFixed";
|
|
1244
1249
|
var TransformSet = defineSystemSet({ name: "transform" });
|
|
1245
1250
|
var TransformFixedSet = defineSystemSet({ name: "transform-fixed" });
|
|
1251
|
+
var propagationTrace;
|
|
1252
|
+
var hierarchyRootCursorAllocationCount = 0;
|
|
1253
|
+
function createHierarchyRootCursor() {
|
|
1254
|
+
hierarchyRootCursorAllocationCount += 1;
|
|
1255
|
+
return { bindingIndex: -1, row: -1 };
|
|
1256
|
+
}
|
|
1257
|
+
function countPropagation(name) {
|
|
1258
|
+
const trace = propagationTrace;
|
|
1259
|
+
if (trace !== void 0) trace[name] += 1;
|
|
1260
|
+
}
|
|
1246
1261
|
var SCRATCH = /* @__PURE__ */ new WeakMap();
|
|
1247
1262
|
var REGISTRATION_LEASES = /* @__PURE__ */ new WeakMap();
|
|
1248
1263
|
function pairError(entity, expected) {
|
|
@@ -1256,7 +1271,7 @@ function pairError(entity, expected) {
|
|
|
1256
1271
|
);
|
|
1257
1272
|
}
|
|
1258
1273
|
function ensureQueries(world, scratch) {
|
|
1259
|
-
if (scratch.flatQuery !== void 0 && scratch.
|
|
1274
|
+
if (scratch.flatQuery !== void 0 && scratch.hierarchyQuery !== void 0 && scratch.transformQuery !== void 0 && scratch.hierarchyWriter !== void 0 && scratch.transformWriter !== void 0 && scratch.missingGlobalQuery !== void 0 && scratch.missingTransformQuery !== void 0) {
|
|
1260
1275
|
return ok5(void 0);
|
|
1261
1276
|
}
|
|
1262
1277
|
const flatOutput = world.query({
|
|
@@ -1265,16 +1280,23 @@ function ensureQueries(world, scratch) {
|
|
|
1265
1280
|
without: [ChildOf],
|
|
1266
1281
|
changed: [Transform]
|
|
1267
1282
|
});
|
|
1268
|
-
const
|
|
1269
|
-
const
|
|
1283
|
+
const hierarchy = world.query({ read: [Transform, ChildOf], write: [GlobalTransform] });
|
|
1284
|
+
const transform = world.query({ read: [Transform], write: [GlobalTransform] });
|
|
1270
1285
|
const missingGlobal = world.query({ with: [Transform], without: [GlobalTransform] });
|
|
1271
1286
|
const missingTransform = world.query({ with: [GlobalTransform], without: [Transform] });
|
|
1272
|
-
if (!flatOutput.ok || !
|
|
1287
|
+
if (!flatOutput.ok || !hierarchy.ok || !transform.ok || !missingGlobal.ok || !missingTransform.ok) {
|
|
1273
1288
|
return pairError(0, "valid Transform and GlobalTransform pair queries");
|
|
1274
1289
|
}
|
|
1290
|
+
const hierarchyWriter = getDerivedWriter(hierarchy.value, GlobalTransform);
|
|
1291
|
+
const transformWriter = getDerivedWriter(transform.value, GlobalTransform);
|
|
1292
|
+
if (!hierarchyWriter.ok || !transformWriter.ok) {
|
|
1293
|
+
return pairError(0, "dense Transform and ChildOf derived bindings");
|
|
1294
|
+
}
|
|
1275
1295
|
scratch.flatQuery = flatOutput.value;
|
|
1276
|
-
scratch.outputQuery = output.value;
|
|
1277
1296
|
scratch.hierarchyQuery = hierarchy.value;
|
|
1297
|
+
scratch.transformQuery = transform.value;
|
|
1298
|
+
scratch.hierarchyWriter = hierarchyWriter.value;
|
|
1299
|
+
scratch.transformWriter = transformWriter.value;
|
|
1278
1300
|
scratch.missingGlobalQuery = missingGlobal.value;
|
|
1279
1301
|
scratch.missingTransformQuery = missingTransform.value;
|
|
1280
1302
|
return ok5(void 0);
|
|
@@ -1303,7 +1325,25 @@ function scratchFor(world) {
|
|
|
1303
1325
|
rotation: new Float32Array(4),
|
|
1304
1326
|
scale: new Float32Array(3),
|
|
1305
1327
|
local: mat4.create(),
|
|
1306
|
-
|
|
1328
|
+
parent: mat4.create(),
|
|
1329
|
+
candidate: mat4.create(),
|
|
1330
|
+
hierarchyStackEntities: [],
|
|
1331
|
+
hierarchyStackChildren: [],
|
|
1332
|
+
hierarchyProbeEntities: [],
|
|
1333
|
+
hierarchyCurrentCursor: { bindingIndex: -1, row: -1 },
|
|
1334
|
+
hierarchyParentCursor: { bindingIndex: -1, row: -1 },
|
|
1335
|
+
hierarchyChildCursor: { bindingIndex: -1, row: -1 },
|
|
1336
|
+
hierarchyResidualCursor: { bindingIndex: -1, row: -1 },
|
|
1337
|
+
hierarchyResidualParentCursor: { bindingIndex: -1, row: -1 },
|
|
1338
|
+
hierarchyRootCursor: createHierarchyRootCursor(),
|
|
1339
|
+
hierarchyStates: [],
|
|
1340
|
+
hierarchyChanged: [],
|
|
1341
|
+
hierarchyBindingTables: [],
|
|
1342
|
+
hierarchyBindingRows: [],
|
|
1343
|
+
flatChanged: [],
|
|
1344
|
+
flatBindingTables: [],
|
|
1345
|
+
flatBindingRows: [],
|
|
1346
|
+
flatStructureEpoch: -1
|
|
1307
1347
|
};
|
|
1308
1348
|
SCRATCH.set(world, created);
|
|
1309
1349
|
return created;
|
|
@@ -1363,40 +1403,7 @@ function composeFlatColumns(positions, rotations, scales, worlds, count) {
|
|
|
1363
1403
|
worlds[world + 15] = 1;
|
|
1364
1404
|
}
|
|
1365
1405
|
}
|
|
1366
|
-
function
|
|
1367
|
-
const row = output.at(entity);
|
|
1368
|
-
if (row === void 0) {
|
|
1369
|
-
return err5(
|
|
1370
|
-
new SceneError({
|
|
1371
|
-
code: "hierarchy-broken",
|
|
1372
|
-
expected: "each Transform entity to carry a GlobalTransform pair",
|
|
1373
|
-
hint: "attach GlobalTransform at scene authoring or import time, then retry propagation",
|
|
1374
|
-
detail: { entity, parent: entity }
|
|
1375
|
-
})
|
|
1376
|
-
);
|
|
1377
|
-
}
|
|
1378
|
-
const current = world.get(entity, GlobalTransform);
|
|
1379
|
-
if (!current.ok)
|
|
1380
|
-
return err5(
|
|
1381
|
-
new SceneError({
|
|
1382
|
-
code: "hierarchy-broken",
|
|
1383
|
-
expected: "each Transform entity to carry a GlobalTransform pair",
|
|
1384
|
-
hint: "attach GlobalTransform at scene authoring or import time, then retry propagation",
|
|
1385
|
-
detail: { entity, parent: entity }
|
|
1386
|
-
})
|
|
1387
|
-
);
|
|
1388
|
-
let changed = false;
|
|
1389
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
1390
|
-
if (current.value.world[index] !== value[index]) {
|
|
1391
|
-
changed = true;
|
|
1392
|
-
break;
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
if (!changed) return ok5(void 0);
|
|
1396
|
-
row.mut(GlobalTransform).world.set(value);
|
|
1397
|
-
return ok5(void 0);
|
|
1398
|
-
}
|
|
1399
|
-
function propagateFlat(scratch) {
|
|
1406
|
+
function propagateFlat(world, scratch) {
|
|
1400
1407
|
const query = scratch.flatQuery;
|
|
1401
1408
|
if (query === void 0)
|
|
1402
1409
|
return err5(
|
|
@@ -1412,161 +1419,674 @@ function propagateFlat(scratch) {
|
|
|
1412
1419
|
try {
|
|
1413
1420
|
for (const span of spans.value) {
|
|
1414
1421
|
const local = span.get(Transform);
|
|
1415
|
-
const
|
|
1416
|
-
composeFlatColumns(local.pos, local.quat, local.scale,
|
|
1422
|
+
const world2 = span.mut(GlobalTransform).world;
|
|
1423
|
+
composeFlatColumns(local.pos, local.quat, local.scale, world2, span.length);
|
|
1417
1424
|
bindingIndex += 1;
|
|
1418
1425
|
}
|
|
1419
1426
|
} catch (cause) {
|
|
1420
1427
|
const error = cause;
|
|
1421
|
-
return err5(
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1428
|
+
return err5(derivedWriteError(error, bindingIndex));
|
|
1429
|
+
}
|
|
1430
|
+
const transformWriter = scratch.transformWriter;
|
|
1431
|
+
if (transformWriter === void 0) {
|
|
1432
|
+
return pairError(0, "dense Transform and GlobalTransform derived bindings");
|
|
1433
|
+
}
|
|
1434
|
+
const transformBindings = transformWriter.bindings;
|
|
1435
|
+
const structureEpoch = world[worldInternal].getStructureEpoch();
|
|
1436
|
+
if (scratch.flatStructureEpoch === structureEpoch) return ok5(void 0);
|
|
1437
|
+
ensureFlatBuffers(scratch, transformBindings);
|
|
1438
|
+
resetFlatBuffers(scratch);
|
|
1439
|
+
for (let bindingIndex2 = 0; bindingIndex2 < transformBindings.length; bindingIndex2 += 1) {
|
|
1440
|
+
const binding = transformBindings[bindingIndex2];
|
|
1441
|
+
const changed = scratch.flatChanged[bindingIndex2];
|
|
1442
|
+
if (binding === void 0 || changed === void 0) continue;
|
|
1443
|
+
for (let row = 0; row < binding.rowCapacity; row += 1) {
|
|
1444
|
+
const entity = binding.entities[row] ?? 0;
|
|
1445
|
+
const parentRaw = world[worldInternal].getFieldValue(entity, ChildOf, "parent");
|
|
1446
|
+
if (parentRaw !== void 0 && parentRaw !== ENTITY_NULL_RAW2) continue;
|
|
1447
|
+
countPropagation("flatStructuralRootRows");
|
|
1448
|
+
composeBindingRow(binding, row, void 0, 0, scratch, changed);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
for (let bindingIndex2 = 0; bindingIndex2 < transformBindings.length; bindingIndex2 += 1) {
|
|
1452
|
+
const changed = scratch.flatChanged[bindingIndex2];
|
|
1453
|
+
if (changed === void 0) continue;
|
|
1454
|
+
const published = transformWriter.publishChangedRows(bindingIndex2, changed);
|
|
1455
|
+
if (!published.ok) return err5(derivedWriteError(published.error, bindingIndex2));
|
|
1438
1456
|
}
|
|
1457
|
+
scratch.flatStructureEpoch = structureEpoch;
|
|
1439
1458
|
return ok5(void 0);
|
|
1440
1459
|
}
|
|
1441
|
-
function
|
|
1442
|
-
|
|
1443
|
-
|
|
1460
|
+
function transformColumns(binding) {
|
|
1461
|
+
return binding.read;
|
|
1462
|
+
}
|
|
1463
|
+
function hierarchyColumns(binding) {
|
|
1464
|
+
return binding.read;
|
|
1465
|
+
}
|
|
1466
|
+
function worldColumn(binding) {
|
|
1467
|
+
return binding.write.world;
|
|
1468
|
+
}
|
|
1469
|
+
function hierarchyError(code, entity, parent, expected, hint) {
|
|
1470
|
+
return new SceneError({ code, expected, hint, detail: { entity, parent } });
|
|
1471
|
+
}
|
|
1472
|
+
function writeCandidate(binding, row, candidate, changed) {
|
|
1473
|
+
const worlds = worldColumn(binding);
|
|
1474
|
+
const base = row * 16;
|
|
1475
|
+
for (let index = 0; index < 16; index += 1) {
|
|
1476
|
+
if (worlds[base + index] !== candidate[index]) {
|
|
1477
|
+
worlds.set(candidate, base);
|
|
1478
|
+
changed[row] = 1;
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1444
1481
|
}
|
|
1445
|
-
return -1;
|
|
1446
1482
|
}
|
|
1447
|
-
function
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1483
|
+
function composeBindingRow(binding, row, parentBinding, parentRow, scratch, changed) {
|
|
1484
|
+
if ("parent" in binding.read) countPropagation("hierarchyRowsEvaluated");
|
|
1485
|
+
const local = transformColumns(binding);
|
|
1486
|
+
const offset = row * 3;
|
|
1487
|
+
composeColumns(local.pos, local.quat, local.scale, scratch.local, scratch, offset, row * 4);
|
|
1488
|
+
if (parentBinding === void 0) {
|
|
1489
|
+
scratch.candidate.set(scratch.local);
|
|
1490
|
+
} else {
|
|
1491
|
+
const parentWorld = worldColumn(parentBinding);
|
|
1492
|
+
const parentOffset = parentRow * 16;
|
|
1493
|
+
for (let index = 0; index < 16; index += 1) {
|
|
1494
|
+
scratch.parent[index] = parentWorld[parentOffset + index] ?? 0;
|
|
1457
1495
|
}
|
|
1458
|
-
|
|
1459
|
-
new SceneError({
|
|
1460
|
-
code: "hierarchy-cycle",
|
|
1461
|
-
expected: "a parent-before-child Transform hierarchy",
|
|
1462
|
-
hint: "repair the ChildOf cycle and retry TransformPropagation",
|
|
1463
|
-
detail: { entity: entry.entity, parent: cycleParent }
|
|
1464
|
-
})
|
|
1465
|
-
);
|
|
1496
|
+
mat4.multiply(scratch.candidate, scratch.parent, scratch.local);
|
|
1466
1497
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
let
|
|
1471
|
-
if (
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1498
|
+
writeCandidate(binding, row, scratch.candidate, changed);
|
|
1499
|
+
}
|
|
1500
|
+
function ensureHierarchyBuffers(scratch, bindings) {
|
|
1501
|
+
let same = scratch.hierarchyBindingTables.length === bindings.length;
|
|
1502
|
+
if (same) {
|
|
1503
|
+
for (let index = 0; index < bindings.length; index += 1) {
|
|
1504
|
+
const binding = bindings[index];
|
|
1505
|
+
if (binding === void 0 || scratch.hierarchyBindingTables[index] !== binding.tableId || scratch.hierarchyBindingRows[index] !== binding.rowCapacity) {
|
|
1506
|
+
same = false;
|
|
1507
|
+
break;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (same) return;
|
|
1512
|
+
scratch.hierarchyBindingTables = bindings.map((binding) => binding.tableId);
|
|
1513
|
+
scratch.hierarchyBindingRows = bindings.map((binding) => binding.rowCapacity);
|
|
1514
|
+
scratch.hierarchyStates = bindings.map((binding) => new Uint8Array(binding.rowCapacity));
|
|
1515
|
+
scratch.hierarchyChanged = bindings.map((binding) => new Uint8Array(binding.rowCapacity));
|
|
1516
|
+
}
|
|
1517
|
+
function resetHierarchyBuffers(scratch) {
|
|
1518
|
+
for (let index = 0; index < scratch.hierarchyStates.length; index += 1) {
|
|
1519
|
+
scratch.hierarchyStates[index]?.fill(0);
|
|
1520
|
+
scratch.hierarchyChanged[index]?.fill(0);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
function ensureFlatBuffers(scratch, bindings) {
|
|
1524
|
+
let same = scratch.flatBindingTables.length === bindings.length;
|
|
1525
|
+
if (same) {
|
|
1526
|
+
for (let index = 0; index < bindings.length; index += 1) {
|
|
1527
|
+
const binding = bindings[index];
|
|
1528
|
+
if (binding === void 0 || scratch.flatBindingTables[index] !== binding.tableId || scratch.flatBindingRows[index] !== binding.rowCapacity) {
|
|
1529
|
+
same = false;
|
|
1530
|
+
break;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
if (same) return;
|
|
1535
|
+
scratch.flatBindingTables = bindings.map((binding) => binding.tableId);
|
|
1536
|
+
scratch.flatBindingRows = bindings.map((binding) => binding.rowCapacity);
|
|
1537
|
+
scratch.flatChanged = bindings.map((binding) => new Uint8Array(binding.rowCapacity));
|
|
1538
|
+
}
|
|
1539
|
+
function resetFlatBuffers(scratch) {
|
|
1540
|
+
for (const changed of scratch.flatChanged) changed.fill(0);
|
|
1541
|
+
}
|
|
1542
|
+
function derivedWriteError(cause, bindingIndex) {
|
|
1543
|
+
return new SceneError({
|
|
1544
|
+
code: "hierarchy-broken",
|
|
1545
|
+
expected: "derived GlobalTransform range publication to succeed",
|
|
1546
|
+
hint: cause.hint ?? "retry propagation on a healthy World",
|
|
1547
|
+
detail: {
|
|
1548
|
+
kind: "derived-write",
|
|
1549
|
+
entity: 0,
|
|
1550
|
+
parent: 0,
|
|
1551
|
+
bindingIndex,
|
|
1552
|
+
base: 0,
|
|
1553
|
+
start: 0,
|
|
1554
|
+
count: 0,
|
|
1555
|
+
cause
|
|
1556
|
+
}
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
function findHierarchyLocation(writer, bindings, entity, cursor) {
|
|
1560
|
+
countPropagation("hierarchyEntityLookups");
|
|
1561
|
+
if (!writer.locateEntity(entity, cursor)) return void 0;
|
|
1562
|
+
return bindings[cursor.bindingIndex];
|
|
1563
|
+
}
|
|
1564
|
+
function findTransformLocation(writer, bindings, entity, cursor) {
|
|
1565
|
+
countPropagation("hierarchyEntityLookups");
|
|
1566
|
+
if (!writer.locateEntity(entity, cursor)) return void 0;
|
|
1567
|
+
return bindings[cursor.bindingIndex];
|
|
1568
|
+
}
|
|
1569
|
+
function countPublishedRows(changed) {
|
|
1570
|
+
const trace = propagationTrace;
|
|
1571
|
+
if (trace === void 0) return;
|
|
1572
|
+
let runOpen = false;
|
|
1573
|
+
for (let row = 0; row < changed.length; row += 1) {
|
|
1574
|
+
if ((changed[row] ?? 0) !== 0) {
|
|
1575
|
+
trace.hierarchyPublishedRows += 1;
|
|
1576
|
+
if (!runOpen) {
|
|
1577
|
+
trace.hierarchyPublishedRuns += 1;
|
|
1578
|
+
runOpen = true;
|
|
1579
|
+
}
|
|
1483
1580
|
} else {
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1581
|
+
runOpen = false;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
function noteHierarchyError(current, next) {
|
|
1586
|
+
if (current === void 0) return next;
|
|
1587
|
+
const currentEntity = Number(current.detail?.entity ?? Number.MAX_SAFE_INTEGER);
|
|
1588
|
+
const nextEntity = Number(next.detail?.entity ?? Number.MAX_SAFE_INTEGER);
|
|
1589
|
+
return nextEntity < currentEntity || nextEntity === currentEntity && next.code.localeCompare(current.code) < 0 ? next : current;
|
|
1590
|
+
}
|
|
1591
|
+
function composeLocalHierarchyEntity(writer, bindings, entity, scratch, changed) {
|
|
1592
|
+
const cursor = scratch.hierarchyCurrentCursor;
|
|
1593
|
+
const binding = findHierarchyLocation(writer, bindings, entity, cursor);
|
|
1594
|
+
if (binding === void 0) return false;
|
|
1595
|
+
composeBindingRow(
|
|
1596
|
+
binding,
|
|
1597
|
+
cursor.row,
|
|
1598
|
+
void 0,
|
|
1599
|
+
0,
|
|
1600
|
+
scratch,
|
|
1601
|
+
changed[cursor.bindingIndex]
|
|
1602
|
+
);
|
|
1603
|
+
const states = scratch.hierarchyStates[cursor.bindingIndex];
|
|
1604
|
+
if (states !== void 0) states[cursor.row] = 3;
|
|
1605
|
+
return true;
|
|
1606
|
+
}
|
|
1607
|
+
function handleActiveCycle(repeated, stackEntities, stackChildren, writer, bindings, scratch, changed, report) {
|
|
1608
|
+
let cycleStart = -1;
|
|
1609
|
+
for (let index = 0; index < stackEntities.length; index += 1) {
|
|
1610
|
+
if (stackEntities[index] === repeated) {
|
|
1611
|
+
cycleStart = index;
|
|
1612
|
+
break;
|
|
1495
1613
|
}
|
|
1496
1614
|
}
|
|
1497
|
-
if (
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1615
|
+
if (cycleStart < 0) return;
|
|
1616
|
+
const repeatedCursor = { bindingIndex: -1, row: -1 };
|
|
1617
|
+
const repeatedBinding = findHierarchyLocation(writer, bindings, repeated, repeatedCursor);
|
|
1618
|
+
const repeatedParent = repeatedBinding === void 0 ? repeated : hierarchyColumns(repeatedBinding).parent[repeatedCursor.row] ?? ENTITY_NULL_RAW2;
|
|
1619
|
+
report(
|
|
1620
|
+
hierarchyError(
|
|
1621
|
+
"hierarchy-cycle",
|
|
1622
|
+
repeated,
|
|
1623
|
+
repeatedParent,
|
|
1624
|
+
"a parent-before-child Transform hierarchy",
|
|
1625
|
+
"repair the ChildOf cycle and retry TransformPropagation"
|
|
1626
|
+
)
|
|
1627
|
+
);
|
|
1628
|
+
for (let index = cycleStart; index < stackEntities.length; index += 1) {
|
|
1629
|
+
const cycleEntity = stackEntities[index];
|
|
1630
|
+
if (cycleEntity === void 0) continue;
|
|
1631
|
+
composeLocalHierarchyEntity(writer, bindings, cycleEntity, scratch, changed);
|
|
1632
|
+
stackChildren[index] = 0;
|
|
1502
1633
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1634
|
+
}
|
|
1635
|
+
function walkChildren(world, root, writer, bindings, transformWriter, transformBindings, scratch, report, allowCompletedRoot) {
|
|
1636
|
+
countPropagation("hierarchyRootInvocations");
|
|
1637
|
+
const stackEntities = scratch.hierarchyStackEntities;
|
|
1638
|
+
const stackChildren = scratch.hierarchyStackChildren;
|
|
1639
|
+
stackEntities.length = 0;
|
|
1640
|
+
stackChildren.length = 0;
|
|
1641
|
+
if (allowCompletedRoot) {
|
|
1642
|
+
const rootCursor = scratch.hierarchyRootCursor;
|
|
1643
|
+
const rootBinding = findHierarchyLocation(writer, bindings, root, rootCursor);
|
|
1644
|
+
if (rootBinding !== void 0) {
|
|
1645
|
+
const state = scratch.hierarchyStates[rootCursor.bindingIndex]?.[rootCursor.row] ?? 0;
|
|
1646
|
+
if (state === 4) return;
|
|
1647
|
+
}
|
|
1507
1648
|
} else {
|
|
1508
|
-
|
|
1649
|
+
const rootCursor = scratch.hierarchyRootCursor;
|
|
1650
|
+
countPropagation("hierarchyRootCursorReuses");
|
|
1651
|
+
const rootBinding = findHierarchyLocation(writer, bindings, root, rootCursor);
|
|
1652
|
+
if (rootBinding !== void 0) {
|
|
1653
|
+
const state = scratch.hierarchyStates[rootCursor.bindingIndex]?.[rootCursor.row] ?? 0;
|
|
1654
|
+
if (state !== 0) return;
|
|
1655
|
+
}
|
|
1509
1656
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1657
|
+
stackEntities.push(root);
|
|
1658
|
+
stackChildren.push(-1);
|
|
1659
|
+
const currentCursor = scratch.hierarchyCurrentCursor;
|
|
1660
|
+
const parentCursor = scratch.hierarchyParentCursor;
|
|
1661
|
+
const childCursor = scratch.hierarchyChildCursor;
|
|
1662
|
+
while (stackEntities.length > 0) {
|
|
1663
|
+
const top = stackEntities.length - 1;
|
|
1664
|
+
const current = stackEntities[top];
|
|
1665
|
+
if (current === void 0) {
|
|
1666
|
+
stackEntities.pop();
|
|
1667
|
+
stackChildren.pop();
|
|
1668
|
+
continue;
|
|
1669
|
+
}
|
|
1670
|
+
const hierarchyBinding = findHierarchyLocation(writer, bindings, current, currentCursor);
|
|
1671
|
+
const nextChild = stackChildren[top] ?? -1;
|
|
1672
|
+
if (nextChild < 0) {
|
|
1673
|
+
if (hierarchyBinding !== void 0) {
|
|
1674
|
+
const state = scratch.hierarchyStates[currentCursor.bindingIndex]?.[currentCursor.row] ?? 0;
|
|
1675
|
+
if (state === 0) {
|
|
1676
|
+
const states = scratch.hierarchyStates[currentCursor.bindingIndex];
|
|
1677
|
+
if (states !== void 0) states[currentCursor.row] = 1;
|
|
1678
|
+
const parentRaw = hierarchyColumns(hierarchyBinding).parent[currentCursor.row] ?? ENTITY_NULL_RAW2;
|
|
1679
|
+
let completed = false;
|
|
1680
|
+
if (parentRaw === ENTITY_NULL_RAW2) {
|
|
1681
|
+
composeBindingRow(
|
|
1682
|
+
hierarchyBinding,
|
|
1683
|
+
currentCursor.row,
|
|
1684
|
+
void 0,
|
|
1685
|
+
0,
|
|
1686
|
+
scratch,
|
|
1687
|
+
scratch.hierarchyChanged[currentCursor.bindingIndex]
|
|
1688
|
+
);
|
|
1689
|
+
completed = true;
|
|
1690
|
+
} else {
|
|
1691
|
+
const parent = parentRaw;
|
|
1692
|
+
const parentBinding = findTransformLocation(
|
|
1693
|
+
transformWriter,
|
|
1694
|
+
transformBindings,
|
|
1695
|
+
parent,
|
|
1696
|
+
parentCursor
|
|
1697
|
+
);
|
|
1698
|
+
const parentHierarchy = findHierarchyLocation(writer, bindings, parent, childCursor);
|
|
1699
|
+
if (parentBinding === void 0) {
|
|
1700
|
+
report(
|
|
1701
|
+
hierarchyError(
|
|
1702
|
+
"hierarchy-broken",
|
|
1703
|
+
current,
|
|
1704
|
+
parent,
|
|
1705
|
+
"each ChildOf parent to carry Transform and GlobalTransform",
|
|
1706
|
+
"repair the missing parent pair before retrying propagation"
|
|
1707
|
+
)
|
|
1708
|
+
);
|
|
1709
|
+
composeBindingRow(
|
|
1710
|
+
hierarchyBinding,
|
|
1711
|
+
currentCursor.row,
|
|
1712
|
+
void 0,
|
|
1713
|
+
0,
|
|
1714
|
+
scratch,
|
|
1715
|
+
scratch.hierarchyChanged[currentCursor.bindingIndex]
|
|
1716
|
+
);
|
|
1717
|
+
completed = true;
|
|
1718
|
+
} else if (parentHierarchy !== void 0) {
|
|
1719
|
+
const parentState = scratch.hierarchyStates[childCursor.bindingIndex]?.[childCursor.row] ?? 0;
|
|
1720
|
+
if (parentState === 1) {
|
|
1721
|
+
handleActiveCycle(
|
|
1722
|
+
parent,
|
|
1723
|
+
stackEntities,
|
|
1724
|
+
stackChildren,
|
|
1725
|
+
writer,
|
|
1726
|
+
bindings,
|
|
1727
|
+
scratch,
|
|
1728
|
+
scratch.hierarchyChanged,
|
|
1729
|
+
report
|
|
1730
|
+
);
|
|
1731
|
+
completed = true;
|
|
1732
|
+
} else if (parentState === 0) {
|
|
1733
|
+
report(
|
|
1734
|
+
hierarchyError(
|
|
1735
|
+
"hierarchy-broken",
|
|
1736
|
+
current,
|
|
1737
|
+
parent,
|
|
1738
|
+
"Children to enumerate every parent-before-child edge",
|
|
1739
|
+
"repair the Children mirror and retry TransformPropagation"
|
|
1740
|
+
)
|
|
1741
|
+
);
|
|
1742
|
+
composeBindingRow(
|
|
1743
|
+
hierarchyBinding,
|
|
1744
|
+
currentCursor.row,
|
|
1745
|
+
void 0,
|
|
1746
|
+
0,
|
|
1747
|
+
scratch,
|
|
1748
|
+
scratch.hierarchyChanged[currentCursor.bindingIndex]
|
|
1749
|
+
);
|
|
1750
|
+
completed = true;
|
|
1751
|
+
} else {
|
|
1752
|
+
composeBindingRow(
|
|
1753
|
+
hierarchyBinding,
|
|
1754
|
+
currentCursor.row,
|
|
1755
|
+
parentBinding,
|
|
1756
|
+
parentCursor.row,
|
|
1757
|
+
scratch,
|
|
1758
|
+
scratch.hierarchyChanged[currentCursor.bindingIndex]
|
|
1759
|
+
);
|
|
1760
|
+
completed = true;
|
|
1761
|
+
}
|
|
1762
|
+
} else {
|
|
1763
|
+
composeBindingRow(
|
|
1764
|
+
hierarchyBinding,
|
|
1765
|
+
currentCursor.row,
|
|
1766
|
+
parentBinding,
|
|
1767
|
+
parentCursor.row,
|
|
1768
|
+
scratch,
|
|
1769
|
+
scratch.hierarchyChanged[currentCursor.bindingIndex]
|
|
1770
|
+
);
|
|
1771
|
+
completed = true;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
if (completed && states !== void 0 && states[currentCursor.row] === 1) {
|
|
1775
|
+
states[currentCursor.row] = 2;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
stackChildren[top] = 0;
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
const childrenLength = world[worldInternal].getArrayLength(current, Children, "entities") ?? 0;
|
|
1783
|
+
if (nextChild >= childrenLength) {
|
|
1784
|
+
stackEntities.pop();
|
|
1785
|
+
stackChildren.pop();
|
|
1786
|
+
if (allowCompletedRoot) {
|
|
1787
|
+
const completedCursor = scratch.hierarchyResidualCursor;
|
|
1788
|
+
const completedBinding = findHierarchyLocation(writer, bindings, current, completedCursor);
|
|
1789
|
+
const completedStates = completedBinding === void 0 ? void 0 : scratch.hierarchyStates[completedCursor.bindingIndex];
|
|
1790
|
+
if (completedStates !== void 0 && completedStates[completedCursor.row] === 3) {
|
|
1791
|
+
completedStates[completedCursor.row] = 4;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
continue;
|
|
1795
|
+
}
|
|
1796
|
+
stackChildren[top] = nextChild + 1;
|
|
1797
|
+
countPropagation("hierarchyEdgesVisited");
|
|
1798
|
+
const childRaw = world[worldInternal].getArrayElement(current, Children, "entities", nextChild);
|
|
1799
|
+
if (childRaw === void 0 || childRaw === ENTITY_NULL_RAW2) {
|
|
1800
|
+
report(
|
|
1801
|
+
hierarchyError(
|
|
1802
|
+
"hierarchy-broken",
|
|
1803
|
+
current,
|
|
1804
|
+
current,
|
|
1805
|
+
"Children.entities to contain live child handles",
|
|
1806
|
+
"repair the Children mirror and retry TransformPropagation"
|
|
1807
|
+
)
|
|
1808
|
+
);
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
const child = childRaw;
|
|
1812
|
+
const childBinding = findHierarchyLocation(writer, bindings, child, childCursor);
|
|
1813
|
+
if (childBinding === void 0) {
|
|
1814
|
+
report(
|
|
1815
|
+
hierarchyError(
|
|
1816
|
+
"hierarchy-broken",
|
|
1817
|
+
child,
|
|
1818
|
+
current,
|
|
1819
|
+
"each Children entry to carry Transform, GlobalTransform, and ChildOf",
|
|
1820
|
+
"repair the child component pair before retrying propagation"
|
|
1821
|
+
)
|
|
1822
|
+
);
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
const childParent = hierarchyColumns(childBinding).parent[childCursor.row] ?? ENTITY_NULL_RAW2;
|
|
1826
|
+
const childState = scratch.hierarchyStates[childCursor.bindingIndex]?.[childCursor.row] ?? 0;
|
|
1827
|
+
if (childParent !== current) {
|
|
1828
|
+
if (childState === 0) continue;
|
|
1829
|
+
report(
|
|
1830
|
+
hierarchyError(
|
|
1831
|
+
"hierarchy-broken",
|
|
1832
|
+
child,
|
|
1833
|
+
current,
|
|
1834
|
+
"Children and ChildOf to describe the same parent",
|
|
1835
|
+
"repair the relationship mirror and retry TransformPropagation"
|
|
1836
|
+
)
|
|
1837
|
+
);
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
if (childState === 1) {
|
|
1841
|
+
handleActiveCycle(
|
|
1842
|
+
child,
|
|
1843
|
+
stackEntities,
|
|
1844
|
+
stackChildren,
|
|
1845
|
+
writer,
|
|
1846
|
+
bindings,
|
|
1847
|
+
scratch,
|
|
1848
|
+
scratch.hierarchyChanged,
|
|
1849
|
+
report
|
|
1850
|
+
);
|
|
1851
|
+
} else if (childState === 0) {
|
|
1852
|
+
stackEntities.push(child);
|
|
1853
|
+
stackChildren.push(-1);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
function fallbackResidualPath(world, path, writer, bindings, transformWriter, transformBindings, scratch, report) {
|
|
1858
|
+
for (const entity of path) {
|
|
1859
|
+
composeLocalHierarchyEntity(writer, bindings, entity, scratch, scratch.hierarchyChanged);
|
|
1860
|
+
}
|
|
1861
|
+
for (const entity of path) {
|
|
1862
|
+
walkChildren(
|
|
1863
|
+
world,
|
|
1864
|
+
entity,
|
|
1865
|
+
writer,
|
|
1866
|
+
bindings,
|
|
1867
|
+
transformWriter,
|
|
1868
|
+
transformBindings,
|
|
1869
|
+
scratch,
|
|
1870
|
+
report,
|
|
1871
|
+
true
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
function resolveResidualPath(world, entity, writer, bindings, transformWriter, transformBindings, scratch, report) {
|
|
1876
|
+
const path = scratch.hierarchyProbeEntities;
|
|
1877
|
+
path.length = 0;
|
|
1878
|
+
const cursor = scratch.hierarchyResidualCursor;
|
|
1879
|
+
const parentTransformCursor = scratch.hierarchyParentCursor;
|
|
1880
|
+
const parentHierarchyCursor = scratch.hierarchyResidualParentCursor;
|
|
1881
|
+
let current = entity;
|
|
1882
|
+
while (true) {
|
|
1883
|
+
countPropagation("hierarchyResidualParentProbes");
|
|
1884
|
+
const binding = findHierarchyLocation(writer, bindings, current, cursor);
|
|
1885
|
+
if (binding === void 0) break;
|
|
1886
|
+
const states = scratch.hierarchyStates[cursor.bindingIndex];
|
|
1887
|
+
const state = states?.[cursor.row] ?? 0;
|
|
1888
|
+
if (state !== 0) {
|
|
1889
|
+
const columns = hierarchyColumns(binding);
|
|
1890
|
+
const parentRaw2 = columns.parent[cursor.row] ?? ENTITY_NULL_RAW2;
|
|
1891
|
+
report(
|
|
1892
|
+
hierarchyError(
|
|
1893
|
+
"hierarchy-cycle",
|
|
1894
|
+
current,
|
|
1895
|
+
parentRaw2 === ENTITY_NULL_RAW2 ? current : parentRaw2,
|
|
1896
|
+
"a parent-before-child Transform hierarchy",
|
|
1897
|
+
"repair the ChildOf cycle and retry TransformPropagation"
|
|
1898
|
+
)
|
|
1899
|
+
);
|
|
1900
|
+
fallbackResidualPath(
|
|
1901
|
+
world,
|
|
1902
|
+
path,
|
|
1903
|
+
writer,
|
|
1904
|
+
bindings,
|
|
1905
|
+
transformWriter,
|
|
1906
|
+
transformBindings,
|
|
1907
|
+
scratch,
|
|
1908
|
+
report
|
|
1909
|
+
);
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
if (states !== void 0) states[cursor.row] = 1;
|
|
1913
|
+
path.push(current);
|
|
1914
|
+
const parentRaw = hierarchyColumns(binding).parent[cursor.row] ?? ENTITY_NULL_RAW2;
|
|
1915
|
+
if (parentRaw === ENTITY_NULL_RAW2) {
|
|
1916
|
+
report(
|
|
1917
|
+
hierarchyError(
|
|
1918
|
+
"hierarchy-broken",
|
|
1919
|
+
current,
|
|
1920
|
+
current,
|
|
1921
|
+
"Children to enumerate every parent-before-child edge",
|
|
1922
|
+
"repair the Children mirror and retry TransformPropagation"
|
|
1923
|
+
)
|
|
1924
|
+
);
|
|
1925
|
+
fallbackResidualPath(
|
|
1926
|
+
world,
|
|
1927
|
+
path,
|
|
1928
|
+
writer,
|
|
1929
|
+
bindings,
|
|
1930
|
+
transformWriter,
|
|
1931
|
+
transformBindings,
|
|
1932
|
+
scratch,
|
|
1933
|
+
report
|
|
1934
|
+
);
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
const parent = parentRaw;
|
|
1938
|
+
const parentTransform = findTransformLocation(
|
|
1939
|
+
transformWriter,
|
|
1940
|
+
transformBindings,
|
|
1941
|
+
parent,
|
|
1942
|
+
parentTransformCursor
|
|
1943
|
+
);
|
|
1944
|
+
const parentHierarchy = findHierarchyLocation(writer, bindings, parent, parentHierarchyCursor);
|
|
1945
|
+
if (parentHierarchy === void 0) {
|
|
1946
|
+
report(
|
|
1947
|
+
hierarchyError(
|
|
1948
|
+
"hierarchy-broken",
|
|
1949
|
+
current,
|
|
1950
|
+
parent,
|
|
1951
|
+
parentTransform === void 0 ? "each ChildOf parent to carry Transform and GlobalTransform" : "Children to enumerate every parent-before-child edge",
|
|
1952
|
+
parentTransform === void 0 ? "repair the missing parent pair before retrying propagation" : "repair the Children mirror and retry TransformPropagation"
|
|
1953
|
+
)
|
|
1954
|
+
);
|
|
1955
|
+
fallbackResidualPath(
|
|
1956
|
+
world,
|
|
1957
|
+
path,
|
|
1958
|
+
writer,
|
|
1959
|
+
bindings,
|
|
1960
|
+
transformWriter,
|
|
1961
|
+
transformBindings,
|
|
1962
|
+
scratch,
|
|
1963
|
+
report
|
|
1964
|
+
);
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
const parentState = scratch.hierarchyStates[parentHierarchyCursor.bindingIndex]?.[parentHierarchyCursor.row] ?? 0;
|
|
1968
|
+
if (parentState === 0) {
|
|
1969
|
+
current = parent;
|
|
1970
|
+
continue;
|
|
1971
|
+
}
|
|
1972
|
+
if (parentState === 1) {
|
|
1973
|
+
report(
|
|
1974
|
+
hierarchyError(
|
|
1975
|
+
"hierarchy-cycle",
|
|
1976
|
+
parent,
|
|
1977
|
+
current,
|
|
1978
|
+
"a parent-before-child Transform hierarchy",
|
|
1979
|
+
"repair the ChildOf cycle and retry TransformPropagation"
|
|
1980
|
+
)
|
|
1981
|
+
);
|
|
1982
|
+
} else {
|
|
1983
|
+
report(
|
|
1984
|
+
hierarchyError(
|
|
1985
|
+
"hierarchy-broken",
|
|
1986
|
+
current,
|
|
1987
|
+
parent,
|
|
1988
|
+
"Children to enumerate every parent-before-child edge",
|
|
1989
|
+
"repair the Children mirror and retry TransformPropagation"
|
|
1990
|
+
)
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
fallbackResidualPath(
|
|
1994
|
+
world,
|
|
1995
|
+
path,
|
|
1996
|
+
writer,
|
|
1997
|
+
bindings,
|
|
1998
|
+
transformWriter,
|
|
1999
|
+
transformBindings,
|
|
2000
|
+
scratch,
|
|
2001
|
+
report
|
|
2002
|
+
);
|
|
2003
|
+
return;
|
|
1514
2004
|
}
|
|
1515
|
-
entry.state = 2;
|
|
1516
|
-
scratch.hierarchyPath.pop();
|
|
1517
|
-
return failure === void 0 ? ok5(void 0) : err5(failure);
|
|
1518
2005
|
}
|
|
1519
2006
|
function propagateHierarchy(world, scratch) {
|
|
1520
|
-
const
|
|
1521
|
-
const
|
|
1522
|
-
if (
|
|
2007
|
+
const hierarchyWriter = scratch.hierarchyWriter;
|
|
2008
|
+
const transformWriter = scratch.transformWriter;
|
|
2009
|
+
if (hierarchyWriter === void 0 || transformWriter === void 0) {
|
|
1523
2010
|
return err5(
|
|
1524
2011
|
new SceneError({
|
|
1525
2012
|
code: "hierarchy-broken",
|
|
1526
|
-
expected: "paired Transform and GlobalTransform
|
|
2013
|
+
expected: "paired Transform and GlobalTransform derived bindings",
|
|
1527
2014
|
hint: "register the scene components before running TransformPropagation"
|
|
1528
2015
|
})
|
|
1529
2016
|
);
|
|
1530
2017
|
}
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
parent,
|
|
1540
|
-
position: new Float32Array(local.pos),
|
|
1541
|
-
rotation: new Float32Array(local.quat),
|
|
1542
|
-
scale: new Float32Array(local.scale),
|
|
1543
|
-
world: mat4.create(),
|
|
1544
|
-
state: 0
|
|
1545
|
-
});
|
|
2018
|
+
const hierarchyBindings = hierarchyWriter.bindings;
|
|
2019
|
+
const transformBindings = transformWriter.bindings;
|
|
2020
|
+
if (hierarchyBindings.length === 0) {
|
|
2021
|
+
scratch.hierarchyBindingTables.length = 0;
|
|
2022
|
+
scratch.hierarchyBindingRows.length = 0;
|
|
2023
|
+
scratch.hierarchyStates.length = 0;
|
|
2024
|
+
scratch.hierarchyChanged.length = 0;
|
|
2025
|
+
return ok5(void 0);
|
|
1546
2026
|
}
|
|
1547
|
-
scratch
|
|
2027
|
+
ensureHierarchyBuffers(scratch, hierarchyBindings);
|
|
2028
|
+
resetHierarchyBuffers(scratch);
|
|
1548
2029
|
let firstError;
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
2030
|
+
const report = (error) => {
|
|
2031
|
+
firstError = noteHierarchyError(firstError, error);
|
|
2032
|
+
};
|
|
2033
|
+
for (const binding of transformBindings) {
|
|
2034
|
+
const entities = binding.entities;
|
|
2035
|
+
for (let row = 0; row < binding.rowCapacity; row += 1) {
|
|
2036
|
+
const entity = entities[row] ?? 0;
|
|
2037
|
+
const parentRaw = world[worldInternal].getFieldValue(entity, ChildOf, "parent");
|
|
2038
|
+
if (parentRaw === void 0 || parentRaw === ENTITY_NULL_RAW2) {
|
|
2039
|
+
walkChildren(
|
|
2040
|
+
world,
|
|
2041
|
+
entity,
|
|
2042
|
+
hierarchyWriter,
|
|
2043
|
+
hierarchyBindings,
|
|
2044
|
+
transformWriter,
|
|
2045
|
+
transformBindings,
|
|
2046
|
+
scratch,
|
|
2047
|
+
report,
|
|
2048
|
+
false
|
|
2049
|
+
);
|
|
1560
2050
|
}
|
|
1561
2051
|
}
|
|
1562
2052
|
}
|
|
2053
|
+
for (let bindingIndex = 0; bindingIndex < hierarchyBindings.length; bindingIndex += 1) {
|
|
2054
|
+
const binding = hierarchyBindings[bindingIndex];
|
|
2055
|
+
if (binding === void 0) continue;
|
|
2056
|
+
const entities = binding.entities;
|
|
2057
|
+
const states = scratch.hierarchyStates[bindingIndex];
|
|
2058
|
+
for (let row = 0; row < binding.rowCapacity; row += 1) {
|
|
2059
|
+
if ((states?.[row] ?? 0) !== 0) continue;
|
|
2060
|
+
const entity = entities[row] ?? 0;
|
|
2061
|
+
resolveResidualPath(
|
|
2062
|
+
world,
|
|
2063
|
+
entity,
|
|
2064
|
+
hierarchyWriter,
|
|
2065
|
+
hierarchyBindings,
|
|
2066
|
+
transformWriter,
|
|
2067
|
+
transformBindings,
|
|
2068
|
+
scratch,
|
|
2069
|
+
report
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
for (let bindingIndex = 0; bindingIndex < hierarchyBindings.length; bindingIndex += 1) {
|
|
2074
|
+
const changed = scratch.hierarchyChanged[bindingIndex];
|
|
2075
|
+
if (changed === void 0) continue;
|
|
2076
|
+
countPublishedRows(changed);
|
|
2077
|
+
const published = hierarchyWriter.publishChangedRows(bindingIndex, changed);
|
|
2078
|
+
if (!published.ok) {
|
|
2079
|
+
const cause = published.error;
|
|
2080
|
+
report(derivedWriteError(cause, bindingIndex));
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
1563
2083
|
return firstError === void 0 ? ok5(void 0) : err5(firstError);
|
|
1564
2084
|
}
|
|
1565
2085
|
function propagateTransforms(world) {
|
|
1566
2086
|
const scratch = scratchFor(world);
|
|
1567
2087
|
const pairs = validateTransformPairs(world, scratch);
|
|
1568
2088
|
if (!pairs.ok) return pairs;
|
|
1569
|
-
const flat = propagateFlat(scratch);
|
|
2089
|
+
const flat = propagateFlat(world, scratch);
|
|
1570
2090
|
if (!flat.ok) return flat;
|
|
1571
2091
|
return propagateHierarchy(world, scratch);
|
|
1572
2092
|
}
|