@expofp/renderer 3.1.2 → 3.1.3
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/index.js +64 -70
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1485,7 +1485,7 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1485
1485
|
/** Textures memory limit in megabytes */
|
|
1486
1486
|
memoryLimitMb;
|
|
1487
1487
|
packer;
|
|
1488
|
-
|
|
1488
|
+
atlasData = /* @__PURE__ */ new Map();
|
|
1489
1489
|
globalTranslationMatrix = new Matrix4();
|
|
1490
1490
|
originTranslationMatrix = new Matrix4();
|
|
1491
1491
|
rotationMatrix = new Matrix4();
|
|
@@ -1503,11 +1503,11 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1503
1503
|
}
|
|
1504
1504
|
dispose() {
|
|
1505
1505
|
super.dispose();
|
|
1506
|
-
this.
|
|
1506
|
+
this.atlasData.clear();
|
|
1507
1507
|
}
|
|
1508
1508
|
updateLayerImpl(group, layerDef) {
|
|
1509
1509
|
super.updateLayerImpl(group, layerDef);
|
|
1510
|
-
|
|
1510
|
+
this.renderAtlases();
|
|
1511
1511
|
}
|
|
1512
1512
|
buildLayer(layer) {
|
|
1513
1513
|
const is3D = layer.mode === "3D";
|
|
@@ -1522,9 +1522,8 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1522
1522
|
originalIndex: imageWithIndex.originalIndex
|
|
1523
1523
|
}))).sort((a, b) => a.originalIndex - b.originalIndex);
|
|
1524
1524
|
const instanceCount = rectsWithDef.length;
|
|
1525
|
-
const texture = createAtlas(bin);
|
|
1526
1525
|
const instanceMaterial = this.materialSystem.createTextureMaterial({
|
|
1527
|
-
map:
|
|
1526
|
+
map: createPlaceholderTexture(),
|
|
1528
1527
|
uvOffset: true,
|
|
1529
1528
|
depthEnable: is3D
|
|
1530
1529
|
});
|
|
@@ -1532,6 +1531,7 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1532
1531
|
const vertexCount = instanceGeometry.attributes["position"].count;
|
|
1533
1532
|
const batchedMesh = new BatchedMesh$1(instanceCount, vertexCount, instanceGeometry.index?.count ?? 0, instanceMaterial);
|
|
1534
1533
|
batchedMesh.sortObjects = false;
|
|
1534
|
+
batchedMesh.visible = false;
|
|
1535
1535
|
batchedMesh.addPerInstanceUniforms({ vertex: { uvOffset: "vec4" } });
|
|
1536
1536
|
const geometryId = batchedMesh.addGeometry(instanceGeometry);
|
|
1537
1537
|
for (const { def, rect } of rectsWithDef) {
|
|
@@ -1540,66 +1540,40 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1540
1540
|
batchedMesh.setUniformAt(instanceId, "uvOffset", uvOffset);
|
|
1541
1541
|
this.registerDefObject(def, batchedMesh, instanceId);
|
|
1542
1542
|
}
|
|
1543
|
-
|
|
1543
|
+
const resizable = !rectsWithDef.some(({ def }) => def.source instanceof HTMLCanvasElement);
|
|
1544
|
+
this.atlasData.set(batchedMesh, {
|
|
1545
|
+
bin,
|
|
1546
|
+
resizable,
|
|
1547
|
+
appliedScale: 0
|
|
1548
|
+
});
|
|
1544
1549
|
group.add(batchedMesh);
|
|
1545
1550
|
}
|
|
1546
1551
|
return group;
|
|
1547
1552
|
}
|
|
1548
1553
|
/**
|
|
1549
|
-
*
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1554
|
+
* Render (or re-render) atlas textures for all meshes, scaling to fit the memory limit when set.
|
|
1555
|
+
* Atlases are rendered directly at the target scale — no full-size intermediate is created.
|
|
1556
|
+
* Meshes already at the target scale are skipped.
|
|
1552
1557
|
*/
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
logger$12.debug("Memory limit is not set, unable to resize textures.");
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
|
-
logger$12.debug(`Resizing textures to fit memory limit: ${this.memoryLimitMb} MB`);
|
|
1559
|
-
const resizableMeshes = [];
|
|
1560
|
-
let totalOriginal = 0;
|
|
1561
|
-
let totalNonResizable = 0;
|
|
1558
|
+
renderAtlases() {
|
|
1559
|
+
const scale = this.computeResizeFactor();
|
|
1562
1560
|
for (const mesh of this.getAllObjects()) {
|
|
1563
|
-
const
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
resizableMeshes.push(mesh);
|
|
1568
|
-
} else totalNonResizable += getCanvasSizeBytes(texture.image, texture.generateMipmaps);
|
|
1569
|
-
}
|
|
1570
|
-
if (resizableMeshes.length === 0) {
|
|
1571
|
-
logger$12.debug("No resizable meshes found, no need to resize textures.");
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
const budget = this.memoryLimitMb * 1024 * 1024 - totalNonResizable;
|
|
1575
|
-
if (budget < 0) {
|
|
1576
|
-
logger$12.debug("Memory limit is too low, unable to resize textures.");
|
|
1577
|
-
return;
|
|
1578
|
-
}
|
|
1579
|
-
const resizeFactor = Math.sqrt(budget / totalOriginal);
|
|
1580
|
-
if (resizeFactor >= 1) {
|
|
1581
|
-
logger$12.debug("Textures are already within the memory limit, no need to resize");
|
|
1582
|
-
return;
|
|
1583
|
-
}
|
|
1584
|
-
logger$12.debug(`Resize factor: ${resizeFactor}`);
|
|
1585
|
-
let newTotal = totalNonResizable;
|
|
1586
|
-
for (const mesh of resizableMeshes) {
|
|
1561
|
+
const data = this.atlasData.get(mesh);
|
|
1562
|
+
if (!data) continue;
|
|
1563
|
+
const targetScale = data.resizable ? scale : 1;
|
|
1564
|
+
if (data.appliedScale === targetScale) continue;
|
|
1587
1565
|
const material = mesh.material;
|
|
1588
|
-
const
|
|
1589
|
-
|
|
1590
|
-
const resizedTexture = resizeCanvas(originalCanvas, resizeFactor);
|
|
1591
|
-
const originalDim = `${originalCanvas.width}x${originalCanvas.height}`;
|
|
1592
|
-
const resizedDim = `${resizedTexture.image.width}x${resizedTexture.image.height}`;
|
|
1593
|
-
logger$12.debug(`Resized atlas for ${mesh.name || mesh.parent?.name}, from ${originalDim} to ${resizedDim}`);
|
|
1594
|
-
newTotal += getCanvasSizeBytes(resizedTexture.image, resizedTexture.generateMipmaps);
|
|
1595
|
-
material.map = resizedTexture;
|
|
1566
|
+
const oldTexture = material.map;
|
|
1567
|
+
material.map = createAtlas(data.bin, targetScale);
|
|
1596
1568
|
material.needsUpdate = true;
|
|
1597
|
-
|
|
1569
|
+
oldTexture?.dispose();
|
|
1570
|
+
mesh.visible = true;
|
|
1571
|
+
data.appliedScale = targetScale;
|
|
1572
|
+
logger$12.debug(`Rendered atlas for ${mesh.name || mesh.parent?.name} at scale ${targetScale.toFixed(3)}`);
|
|
1598
1573
|
}
|
|
1599
|
-
logger$12.debug(`New memory usage after resizing: ${newTotal} bytes`);
|
|
1600
1574
|
}
|
|
1601
1575
|
disposeObject(object) {
|
|
1602
|
-
this.
|
|
1576
|
+
this.atlasData.delete(object);
|
|
1603
1577
|
super.disposeObject(object);
|
|
1604
1578
|
}
|
|
1605
1579
|
updateDefImpl(imageDef, mesh, instanceIds) {
|
|
@@ -1613,6 +1587,32 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1613
1587
|
const matrix = this.originTranslationMatrix.premultiply(this.scaleMatrix).premultiply(this.rotationMatrix).premultiply(this.globalTranslationMatrix);
|
|
1614
1588
|
mesh.setMatrixAt(instanceId, matrix);
|
|
1615
1589
|
}
|
|
1590
|
+
computeResizeFactor() {
|
|
1591
|
+
if (!this.memoryLimitMb) {
|
|
1592
|
+
logger$12.debug("Memory limit is not set, atlases will not be scaled");
|
|
1593
|
+
return 1;
|
|
1594
|
+
}
|
|
1595
|
+
let totalResizable = 0;
|
|
1596
|
+
let totalNonResizable = 0;
|
|
1597
|
+
for (const data of this.atlasData.values()) {
|
|
1598
|
+
const bytes = getAtlasSizeBytes(data.bin.width, data.bin.height);
|
|
1599
|
+
if (data.resizable) totalResizable += bytes;
|
|
1600
|
+
else totalNonResizable += bytes;
|
|
1601
|
+
}
|
|
1602
|
+
if (totalResizable === 0) {
|
|
1603
|
+
logger$12.debug("No resizable atlases, atlases will not be scaled");
|
|
1604
|
+
return 1;
|
|
1605
|
+
}
|
|
1606
|
+
const budget = this.memoryLimitMb * 1024 * 1024 - totalNonResizable;
|
|
1607
|
+
if (budget <= 0) {
|
|
1608
|
+
logger$12.debug("Memory limit is too low, unable to resize textures.");
|
|
1609
|
+
return 1;
|
|
1610
|
+
}
|
|
1611
|
+
const factor = Math.sqrt(budget / totalResizable);
|
|
1612
|
+
if (factor >= 1) return 1;
|
|
1613
|
+
logger$12.debug(`Resize factor: ${factor.toFixed(3)} (budget ${budget} bytes, resizable ${totalResizable} bytes)`);
|
|
1614
|
+
return factor;
|
|
1615
|
+
}
|
|
1616
1616
|
packImages(images) {
|
|
1617
1617
|
this.packer.reset();
|
|
1618
1618
|
const rectangles = [];
|
|
@@ -1646,23 +1646,19 @@ var ImageSystem = class extends RenderableSystem {
|
|
|
1646
1646
|
return this.packer.bins;
|
|
1647
1647
|
}
|
|
1648
1648
|
};
|
|
1649
|
-
function createAtlas(bin) {
|
|
1649
|
+
function createAtlas(bin, scale) {
|
|
1650
1650
|
const t0 = performance.now();
|
|
1651
1651
|
const canvas = document.createElement("canvas");
|
|
1652
|
-
canvas.width = bin.width;
|
|
1653
|
-
canvas.height = bin.height;
|
|
1652
|
+
canvas.width = Math.max(1, Math.floor(bin.width * scale));
|
|
1653
|
+
canvas.height = Math.max(1, Math.floor(bin.height * scale));
|
|
1654
1654
|
const ctx = canvas.getContext("2d");
|
|
1655
|
-
for (const rect of bin.rects) ctx.drawImage(rect.data[0].def.source, rect.x, rect.y, rect.width, rect.height);
|
|
1655
|
+
for (const rect of bin.rects) ctx.drawImage(rect.data[0].def.source, Math.floor(rect.x * scale), Math.floor(rect.y * scale), Math.floor(rect.width * scale), Math.floor(rect.height * scale));
|
|
1656
1656
|
const t1 = performance.now();
|
|
1657
|
-
logger$12.debug(`Create atlas took ${(t1 - t0).toFixed(2)} milliseconds.`);
|
|
1657
|
+
logger$12.debug(`Create atlas (${canvas.width}x${canvas.height}) took ${(t1 - t0).toFixed(2)} milliseconds.`);
|
|
1658
1658
|
return createTexture(canvas);
|
|
1659
1659
|
}
|
|
1660
|
-
function
|
|
1661
|
-
|
|
1662
|
-
canvas.width = Math.floor(source.width * resizeFactor);
|
|
1663
|
-
canvas.height = Math.floor(source.height * resizeFactor);
|
|
1664
|
-
canvas.getContext("2d").drawImage(source, 0, 0, canvas.width, canvas.height);
|
|
1665
|
-
return createTexture(canvas);
|
|
1660
|
+
function createPlaceholderTexture() {
|
|
1661
|
+
return new Texture(document.createElement("canvas"));
|
|
1666
1662
|
}
|
|
1667
1663
|
function createTexture(source) {
|
|
1668
1664
|
const texture = new Texture(source);
|
|
@@ -1672,8 +1668,8 @@ function createTexture(source) {
|
|
|
1672
1668
|
texture.needsUpdate = true;
|
|
1673
1669
|
return texture;
|
|
1674
1670
|
}
|
|
1675
|
-
function
|
|
1676
|
-
return Math.ceil(
|
|
1671
|
+
function getAtlasSizeBytes(width, height) {
|
|
1672
|
+
return Math.ceil(width * height * 4 * 1.33);
|
|
1677
1673
|
}
|
|
1678
1674
|
//#endregion
|
|
1679
1675
|
//#region src/geometry/line.ts
|
|
@@ -2511,10 +2507,8 @@ var LayerSystem = class {
|
|
|
2511
2507
|
for (const child of sceneDef.rootLayer.children) rootGroup.add(this.buildLayer(child));
|
|
2512
2508
|
this.updateLayer(sceneDef.rootLayer, false);
|
|
2513
2509
|
printTree(rootGroup, logger$8.debug);
|
|
2514
|
-
if (sceneDef.memoryLimit)
|
|
2515
|
-
|
|
2516
|
-
this.imageSystem.resizeTextures();
|
|
2517
|
-
}
|
|
2510
|
+
if (sceneDef.memoryLimit) this.imageSystem.memoryLimitMb = sceneDef.memoryLimit;
|
|
2511
|
+
this.imageSystem.renderAtlases();
|
|
2518
2512
|
return rootGroup;
|
|
2519
2513
|
}
|
|
2520
2514
|
/**
|