@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.
Files changed (2) hide show
  1. package/dist/index.js +64 -70
  2. 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
- originalAtlases = /* @__PURE__ */ new Map();
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.originalAtlases.clear();
1506
+ this.atlasData.clear();
1507
1507
  }
1508
1508
  updateLayerImpl(group, layerDef) {
1509
1509
  super.updateLayerImpl(group, layerDef);
1510
- if (this.memoryLimitMb) this.resizeTextures();
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: texture,
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
- if (!rectsWithDef.some(({ def }) => def.source instanceof HTMLCanvasElement)) this.originalAtlases.set(batchedMesh, texture.image);
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
- * Resize textures to fit the memory limit.
1550
- * Uses stored original atlases so that every call computes a globally proportional
1551
- * resize factor, regardless of how many layers have been loaded so far.
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
- resizeTextures() {
1554
- if (!this.memoryLimitMb) {
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 originalCanvas = this.originalAtlases.get(mesh);
1564
- const texture = mesh.material.map;
1565
- if (originalCanvas) {
1566
- totalOriginal += getCanvasSizeBytes(originalCanvas, texture.generateMipmaps);
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 currentTexture = material.map;
1589
- const originalCanvas = this.originalAtlases.get(mesh);
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
- currentTexture.dispose();
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.originalAtlases.delete(object);
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 resizeCanvas(source, resizeFactor) {
1661
- const canvas = document.createElement("canvas");
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 getCanvasSizeBytes(canvas, useMipmaps) {
1676
- return Math.ceil(canvas.width * canvas.height * 4 * (useMipmaps ? 1.33 : 1));
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
- this.imageSystem.memoryLimitMb = sceneDef.memoryLimit;
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
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expofp/renderer",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"