@expofp/renderer 2.0.0 → 2.0.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/index.d.ts CHANGED
@@ -408,8 +408,6 @@ export declare type RenderableDefCollection<T = RenderableDef> = T extends Rende
408
408
  * Main class for rendering the content of a {@link SceneDef}
409
409
  */
410
410
  export declare class Renderer {
411
- /** Whether to log debug information */
412
- readonly debugLog: boolean;
413
411
  /** {@link HTMLCanvasElement} that this renderer is rendering to */
414
412
  readonly canvas: HTMLCanvasElement;
415
413
  private ui?;
@@ -523,8 +521,6 @@ export declare interface RendererOptions {
523
521
  canvas: HTMLCanvasElement;
524
522
  /** Optional {@link WebGLRenderingContext} to use (e.g. for Mapbox GL JS) */
525
523
  gl?: WebGLRenderingContext;
526
- /** Whether to log debug information */
527
- debugLog?: boolean;
528
524
  /** Optional partial {@link UI} configuration */
529
525
  ui?: Partial<UI>;
530
526
  }
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ var _a;
5
5
  import { Color, Matrix4, Vector3, DataTexture, RGBAFormat, FloatType, RedFormat, UnsignedIntType, IntType, RGBAIntegerFormat, RGFormat, RGIntegerFormat, RedIntegerFormat, BatchedMesh as BatchedMesh$1, BufferAttribute, StreamDrawUsage, Vector4, AlwaysDepth, DoubleSide, MeshBasicMaterial, Texture, Group, PlaneGeometry, SRGBColorSpace, Vector2, Mesh, LessEqualDepth, Quaternion, BufferGeometry, LinearSRGBColorSpace, Plane, Raycaster, Sphere, Box3, Spherical, PerspectiveCamera, Camera, Scene, MathUtils, Clock, WebGLRenderer } from "three";
6
6
  import { traverseAncestorsGenerator } from "three/examples/jsm/utils/SceneUtils.js";
7
7
  import { BatchedText as BatchedText$1, Text as Text$1 } from "troika-three-text";
8
+ import createLog from "debug";
8
9
  import { LineMaterial, LineSegmentsGeometry } from "three/examples/jsm/Addons.js";
9
10
  import { MaxRectsPacker, Rectangle } from "maxrects-packer";
10
11
  import { converter, parse } from "culori";
@@ -366,6 +367,34 @@ const dimColorFrag = (
366
367
  return vec4(m * col.a, col.a);
367
368
  }`
368
369
  );
370
+ function createLogger(namespace) {
371
+ const info = createLog(namespace);
372
+ info.log = console.info.bind(console);
373
+ const debug = info.extend("debug");
374
+ debug.log = console.debug.bind(console);
375
+ const warn = info.extend("warn");
376
+ warn.log = console.warn.bind(console);
377
+ const error = info.extend("error");
378
+ error.log = console.error.bind(console);
379
+ return {
380
+ debug,
381
+ info,
382
+ warn,
383
+ error
384
+ };
385
+ }
386
+ function printTree(object, logger2) {
387
+ if (!logger2.enabled) return;
388
+ const isGroup = object.isGroup;
389
+ const name = object.name.split(":").at(-1);
390
+ if (isGroup) {
391
+ console.groupCollapsed(name);
392
+ object.children.forEach((child) => printTree(child, logger2));
393
+ console.groupEnd();
394
+ } else {
395
+ logger2.log(`${name}<${object.type}>, render order: ${object.renderOrder}`);
396
+ }
397
+ }
369
398
  function isObject(item) {
370
399
  return !!item && typeof item === "object" && !Array.isArray(item);
371
400
  }
@@ -394,7 +423,7 @@ function getSquareTextureSize(capacity, pixelsPerInstance) {
394
423
  }
395
424
  function getSquareTextureInfo(arrayType, channels, pixelsPerInstance, capacity) {
396
425
  if (channels === 3) {
397
- console.warn('"channels" cannot be 3. Set to 4. More info: https://github.com/mrdoob/three.js/pull/23228');
426
+ logger$b.debug('"channels" cannot be 3. Set to 4. More info: https://github.com/mrdoob/three.js/pull/23228');
398
427
  channels = 4;
399
428
  }
400
429
  const size = getSquareTextureSize(capacity, pixelsPerInstance);
@@ -416,6 +445,7 @@ function getSquareTextureInfo(arrayType, channels, pixelsPerInstance, capacity)
416
445
  }
417
446
  return { array, size, type, format };
418
447
  }
448
+ const logger$b = createLogger("SquareDataTexture");
419
449
  class SquareDataTexture extends DataTexture {
420
450
  /**
421
451
  * @param arrayType The constructor for the TypedArray.
@@ -453,7 +483,7 @@ class SquareDataTexture extends DataTexture {
453
483
  setUniformAt(id, name, value) {
454
484
  const schema = this.uniformMap.get(name);
455
485
  if (!schema) {
456
- console.warn(`SquareDataTexture.setUniformAt: uniform ${name} not found`);
486
+ logger$b.debug(`setUniformAt: uniform ${name} not found`);
457
487
  return;
458
488
  }
459
489
  const { offset, size } = schema;
@@ -474,7 +504,7 @@ class SquareDataTexture extends DataTexture {
474
504
  getUniformAt(id, name, target) {
475
505
  const schema = this.uniformMap.get(name);
476
506
  if (!schema) {
477
- console.warn(`SquareDataTexture.getUniformAt: uniform ${name} not found`);
507
+ logger$b.debug(`getUniformAt: uniform ${name} not found`);
478
508
  return 0;
479
509
  }
480
510
  const { offset, size } = schema;
@@ -620,6 +650,7 @@ class SquareDataTexture extends DataTexture {
620
650
  }
621
651
  const componentsArray = ["r", "g", "b", "a"];
622
652
  const batchIdName = "batchId";
653
+ const logger$a = createLogger("BatchedMesh");
623
654
  const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
624
655
  /**
625
656
  * @param instanceCount the max number of individual geometries planned to be added.
@@ -699,7 +730,7 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
699
730
  if (_BatchedMesh.useMultiDraw) return;
700
731
  const batchCount = this.batchCount;
701
732
  const gl = renderer.getContext();
702
- if (geometry.index == null) return console.warn("No index buffer", (_a2 = this.parent) == null ? void 0 : _a2.name);
733
+ if (geometry.index == null) return logger$a.debug("No index buffer", (_a2 = this.parent) == null ? void 0 : _a2.name);
703
734
  const type = this.getIndexType(gl, geometry.index);
704
735
  gl.drawElements(gl.TRIANGLES, batchCount, type, 0);
705
736
  renderer.info.update(batchCount, gl.TRIANGLES, 1);
@@ -714,7 +745,7 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
714
745
  */
715
746
  getUniformAt(id, name, target) {
716
747
  if (!this.uniformsTexture) {
717
- console.warn(`BatchedMesh.getUniformAt: uniforms texture not initialized`);
748
+ logger$a.debug(`getUniformAt: uniforms texture not initialized`);
718
749
  return 0;
719
750
  }
720
751
  return this.uniformsTexture.getUniformAt(id, name, target);
@@ -727,7 +758,7 @@ const _BatchedMesh = class _BatchedMesh extends BatchedMesh$1 {
727
758
  */
728
759
  setUniformAt(instanceId, name, value) {
729
760
  if (!this.uniformsTexture) {
730
- console.warn(`BatchedMesh.setUniformAt: uniforms texture not initialized`);
761
+ logger$a.debug(`setUniformAt: uniforms texture not initialized`);
731
762
  return;
732
763
  }
733
764
  this.uniformsTexture.setUniformAt(instanceId, name, value);
@@ -1086,12 +1117,14 @@ class RenderableSystem {
1086
1117
  /**
1087
1118
  * @param type readable name of the system's type for debugging
1088
1119
  * @param renderer {@link Renderer}
1120
+ * @param logger {@link Logger}
1089
1121
  */
1090
- constructor(type, renderer) {
1122
+ constructor(type, renderer, logger2) {
1091
1123
  __publicField(this, "mapDefToObject", /* @__PURE__ */ new Map());
1092
1124
  __publicField(this, "mapObjectToDefs", /* @__PURE__ */ new Map());
1093
1125
  this.type = type;
1094
1126
  this.renderer = renderer;
1127
+ this.logger = logger2;
1095
1128
  }
1096
1129
  /**
1097
1130
  * Update a def with its current properties.
@@ -1118,7 +1151,7 @@ class RenderableSystem {
1118
1151
  * @param layerDef {@link TypedLayerDef} layer definition to update
1119
1152
  */
1120
1153
  updateLayer(group, layerDef) {
1121
- if (this.renderer.debugLog) console.log(`Updating ${this.type} layer ${layerDef.name}`, layerDef);
1154
+ this.logger.debug(`Updating layer ${layerDef.name} %O`, layerDef);
1122
1155
  this.updateLayerImpl(group, layerDef);
1123
1156
  }
1124
1157
  /**
@@ -1223,7 +1256,7 @@ class RenderableSystem {
1223
1256
  registerDefObject(def, object, instanceIds) {
1224
1257
  const ids = Array.isArray(instanceIds) ? instanceIds : [instanceIds];
1225
1258
  if (ids.length === 0) {
1226
- console.warn(`[RenderableSystem] Tried to register def with empty instanceIds:`, def);
1259
+ this.logger.debug(`Tried to register def with empty instanceIds %O`, def);
1227
1260
  return;
1228
1261
  }
1229
1262
  this.mapDefToObject.set(def, { object, instanceIds: ids });
@@ -1282,7 +1315,7 @@ class RenderableSystem {
1282
1315
  getObjectInstanceByDef(def) {
1283
1316
  const mapping = this.mapDefToObject.get(def);
1284
1317
  if (!mapping) {
1285
- console.warn(`[RenderableSystem] No object mapping found for def:`, def);
1318
+ this.logger.debug(`No object mapping found for def %O`, def);
1286
1319
  return void 0;
1287
1320
  }
1288
1321
  return mapping;
@@ -1303,13 +1336,14 @@ class RenderableSystem {
1303
1336
  return Array.from(this.mapObjectToDefs.keys());
1304
1337
  }
1305
1338
  }
1339
+ const logger$9 = createLogger("image");
1306
1340
  class ImageSystem extends RenderableSystem {
1307
1341
  /**
1308
1342
  * @param materialSystem {@link MaterialSystem}
1309
1343
  * @param renderer {@link Renderer}
1310
1344
  */
1311
1345
  constructor(materialSystem, renderer) {
1312
- super("image", renderer);
1346
+ super("image", renderer, logger$9);
1313
1347
  /** Textures memory limit in megabytes */
1314
1348
  __publicField(this, "memoryLimitMb");
1315
1349
  __publicField(this, "packer");
@@ -1319,7 +1353,7 @@ class ImageSystem extends RenderableSystem {
1319
1353
  __publicField(this, "scaleMatrix", new Matrix4());
1320
1354
  this.materialSystem = materialSystem;
1321
1355
  const atlasTextureSize = renderer.context.capabilities.maxTextureSize;
1322
- console.log(`Max texture size: ${atlasTextureSize}`);
1356
+ logger$9.debug(`Max texture size: ${atlasTextureSize}`);
1323
1357
  const padding = 1;
1324
1358
  this.packer = new MaxRectsPacker(atlasTextureSize, atlasTextureSize, padding, { pot: false });
1325
1359
  }
@@ -1369,10 +1403,10 @@ class ImageSystem extends RenderableSystem {
1369
1403
  resizeTextures() {
1370
1404
  var _a2;
1371
1405
  if (!this.memoryLimitMb) {
1372
- console.warn("Memory limit is not set, unable to resize textures.");
1406
+ logger$9.debug("Memory limit is not set, unable to resize textures.");
1373
1407
  return;
1374
1408
  }
1375
- console.log(`Resizing textures to fit memory limit: ${this.memoryLimitMb} MB`);
1409
+ logger$9.debug(`Resizing textures to fit memory limit: ${this.memoryLimitMb} MB`);
1376
1410
  const texturesToResize = [];
1377
1411
  let totalResizable = 0;
1378
1412
  let totalNonResizable = 0;
@@ -1389,15 +1423,15 @@ class ImageSystem extends RenderableSystem {
1389
1423
  }
1390
1424
  const budget = this.memoryLimitMb * 1024 * 1024 - totalNonResizable;
1391
1425
  if (budget < 0) {
1392
- console.warn("Memory limit is too low, unable to resize textures.");
1426
+ logger$9.debug("Memory limit is too low, unable to resize textures.");
1393
1427
  return;
1394
1428
  }
1395
1429
  const resizeFactor = Math.sqrt(budget / totalResizable);
1396
1430
  if (resizeFactor >= 1) {
1397
- console.log("Textures are already within the memory limit, no need to resize");
1431
+ logger$9.debug("Textures are already within the memory limit, no need to resize");
1398
1432
  return;
1399
1433
  }
1400
- console.log(`Resize factor: ${resizeFactor}`);
1434
+ logger$9.debug(`Resize factor: ${resizeFactor}`);
1401
1435
  let newTotal = totalNonResizable;
1402
1436
  for (const mesh of texturesToResize) {
1403
1437
  const material = mesh.material;
@@ -1405,14 +1439,14 @@ class ImageSystem extends RenderableSystem {
1405
1439
  const resizedTexture = resizeTexture(texture, resizeFactor);
1406
1440
  const textureDim = `${texture.image.width}x${texture.image.height}`;
1407
1441
  const resizedDim = `${resizedTexture.image.width}x${resizedTexture.image.height}`;
1408
- console.log(`Resized atlas for ${mesh.name || ((_a2 = mesh.parent) == null ? void 0 : _a2.name)}, from ${textureDim} to ${resizedDim}`);
1442
+ logger$9.debug(`Resized atlas for ${mesh.name || ((_a2 = mesh.parent) == null ? void 0 : _a2.name)}, from ${textureDim} to ${resizedDim}`);
1409
1443
  newTotal += getTextureSizeBytes(resizedTexture);
1410
1444
  material.map = resizedTexture;
1411
1445
  material.needsUpdate = true;
1412
1446
  texture.dispose();
1413
1447
  mesh.userData["nonResizable"] = true;
1414
1448
  }
1415
- console.log(`New memory usage after resizing: ${newTotal} bytes`);
1449
+ logger$9.debug(`New memory usage after resizing: ${newTotal} bytes`);
1416
1450
  }
1417
1451
  updateDefImpl(imageDef, mesh, instanceIds) {
1418
1452
  const bounds = imageDef.bounds;
@@ -1441,8 +1475,8 @@ class ImageSystem extends RenderableSystem {
1441
1475
  const boundsArea = boundsWidth * boundsHeight;
1442
1476
  const ratio = sourceArea / boundsArea;
1443
1477
  if (ratio > 1e3) {
1444
- console.log(`Image bounds: ${boundsWidth}x${boundsHeight}`, `Image source: ${sourceWidth}x${sourceHeight}`);
1445
- console.warn(`Image bounds area is ${ratio.toFixed(2)} times smaller than the image.`);
1478
+ logger$9.debug(`Image bounds: ${boundsWidth}x${boundsHeight}`, `Image source: ${sourceWidth}x${sourceHeight}`);
1479
+ logger$9.warn(`Image bounds area is ${ratio.toFixed(2)} times smaller than the image.`);
1446
1480
  }
1447
1481
  const rect = new Rectangle(image.source.width, image.source.height);
1448
1482
  rect.data = [imageWithIndex];
@@ -1453,7 +1487,7 @@ class ImageSystem extends RenderableSystem {
1453
1487
  }
1454
1488
  }
1455
1489
  this.packer.addArray(rectangles);
1456
- this.packer.bins.forEach((bin) => console.log(`Bin: ${bin.width}x${bin.height}, ${bin.rects.length} rectangles`));
1490
+ this.packer.bins.forEach((bin) => logger$9.debug(`Bin: ${bin.width}x${bin.height}, ${bin.rects.length} rectangles`));
1457
1491
  return this.packer.bins;
1458
1492
  }
1459
1493
  }
@@ -1467,7 +1501,7 @@ function createAtlas(bin) {
1467
1501
  ctx.drawImage(rect.data[0].def.source, rect.x, rect.y, rect.width, rect.height);
1468
1502
  }
1469
1503
  const t1 = performance.now();
1470
- console.log(`Create atlas took ${(t1 - t0).toFixed(2)} milliseconds.`);
1504
+ logger$9.debug(`Create atlas took ${(t1 - t0).toFixed(2)} milliseconds.`);
1471
1505
  return createTexture(canvas);
1472
1506
  }
1473
1507
  function resizeTexture(texture, resizeFactor) {
@@ -1490,13 +1524,14 @@ function getTextureSizeBytes(texture) {
1490
1524
  const imageBytes = texture.image.width * texture.image.height * 4 * (texture.generateMipmaps ? 1.33 : 1);
1491
1525
  return Math.ceil(imageBytes);
1492
1526
  }
1527
+ const logger$8 = createLogger("line");
1493
1528
  class LineSystem extends RenderableSystem {
1494
1529
  /**
1495
1530
  * @param materialSystem {@link MaterialSystem}
1496
1531
  * @param renderer {@link Renderer}
1497
1532
  */
1498
1533
  constructor(materialSystem, renderer) {
1499
- super("line", renderer);
1534
+ super("line", renderer, logger$8);
1500
1535
  __publicField(this, "lineColor", new Color());
1501
1536
  this.materialSystem = materialSystem;
1502
1537
  }
@@ -1685,13 +1720,14 @@ class Polygon {
1685
1720
  return this;
1686
1721
  }
1687
1722
  }
1723
+ const logger$7 = createLogger("mesh");
1688
1724
  class MeshSystem extends RenderableSystem {
1689
1725
  /**
1690
1726
  * @param materialSystem {@link MaterialSystem}
1691
1727
  * @param renderer {@link Renderer}
1692
1728
  */
1693
1729
  constructor(materialSystem, renderer) {
1694
- super("mesh", renderer);
1730
+ super("mesh", renderer, logger$7);
1695
1731
  __publicField(this, "toRgbConverter", converter("rgb"));
1696
1732
  __publicField(this, "meshColor", new Color());
1697
1733
  this.materialSystem = materialSystem;
@@ -1802,13 +1838,14 @@ class MeshSystem extends RenderableSystem {
1802
1838
  });
1803
1839
  }
1804
1840
  }
1841
+ const logger$6 = createLogger("text");
1805
1842
  class TextSystem extends RenderableSystem {
1806
1843
  /**
1807
1844
  * @param materialSystem {@link MaterialSystem}
1808
1845
  * @param renderer {@link Renderer}
1809
1846
  */
1810
1847
  constructor(materialSystem, renderer) {
1811
- super("text", renderer);
1848
+ super("text", renderer, logger$6);
1812
1849
  __publicField(this, "initialTextScale", new Vector2(1, -1));
1813
1850
  __publicField(this, "textColor", new Color());
1814
1851
  __publicField(this, "pendingUpdates", /* @__PURE__ */ new Map());
@@ -1996,6 +2033,7 @@ function setAnchorsAndAlignment(text, alignment) {
1996
2033
  text.anchorY = alignment.vertical === "bottom" ? "bottom" : "top";
1997
2034
  text.textAlign = alignment.text ?? alignment.horizontal;
1998
2035
  }
2036
+ const logger$5 = createLogger("layer");
1999
2037
  class LayerSystem {
2000
2038
  /**
2001
2039
  * @param renderer {@link Renderer}
@@ -2067,12 +2105,8 @@ class LayerSystem {
2067
2105
  this.updateDef(def);
2068
2106
  processed++;
2069
2107
  }
2070
- const took = performance.now() - startTime;
2071
- if (processed && this.renderer.debugLog) {
2072
- console.log(
2073
- `LayerSystem: processed ${processed} defs in ${took.toFixed(2)}ms, ${this.pendingDefs.size} remaining`
2074
- );
2075
- }
2108
+ const took = (performance.now() - startTime).toFixed(2);
2109
+ if (processed) logger$5.debug(`processed ${processed} defs in ${took}ms, ${this.pendingDefs.size} remaining`);
2076
2110
  return processed > 0;
2077
2111
  }
2078
2112
  /**
@@ -2082,11 +2116,8 @@ class LayerSystem {
2082
2116
  */
2083
2117
  buildScene(sceneDef) {
2084
2118
  this.initRenderOrder(sceneDef.rootLayer);
2085
- if (this.renderer.debugLog)
2086
- console.log(
2087
- "Render order",
2088
- this.layerDefRenderOrder.map((layer) => this.getFullLayerName(layer))
2089
- );
2119
+ const renderOrder = this.layerDefRenderOrder.map((layer) => this.getFullLayerName(layer));
2120
+ logger$5.debug("Render order %O", renderOrder);
2090
2121
  const rootGroup = new Group();
2091
2122
  rootGroup.name = sceneDef.rootLayer.name;
2092
2123
  this.mapLayerDefsToObjects.set(sceneDef.rootLayer, rootGroup);
@@ -2095,7 +2126,7 @@ class LayerSystem {
2095
2126
  rootGroup.add(this.buildLayer(child));
2096
2127
  }
2097
2128
  this.updateLayer(sceneDef.rootLayer, false);
2098
- if (this.renderer.debugLog) printTree(rootGroup);
2129
+ printTree(rootGroup, logger$5.debug);
2099
2130
  if (sceneDef.memoryLimit) {
2100
2131
  this.imageSystem.memoryLimitMb = sceneDef.memoryLimit;
2101
2132
  this.imageSystem.resizeTextures();
@@ -2139,7 +2170,7 @@ class LayerSystem {
2139
2170
  }
2140
2171
  buildLayer(layerDef, parentPrefix = "") {
2141
2172
  const layerFullName = parentPrefix + layerDef.name;
2142
- console.log(`Building layer ${layerFullName}...`);
2173
+ logger$5.debug(`Building layer ${layerFullName}...`);
2143
2174
  let layerObject;
2144
2175
  if (isShapeLayer(layerDef)) layerObject = this.meshSystem.buildLayer(layerDef);
2145
2176
  else if (isImageLayer(layerDef)) layerObject = this.imageSystem.buildLayer(layerDef);
@@ -2209,19 +2240,6 @@ class LayerSystem {
2209
2240
  return fullName;
2210
2241
  }
2211
2242
  }
2212
- function printTree(object, fullName = false) {
2213
- object.traverse((obj) => {
2214
- let s = "";
2215
- let obj2 = obj;
2216
- while (obj2 !== object) {
2217
- s = "|___ " + s;
2218
- obj2 = (obj2 == null ? void 0 : obj2.parent) ?? null;
2219
- }
2220
- const renderOrder = obj.isGroup ? "" : `, RO: ${obj.renderOrder}`;
2221
- const name = fullName ? obj.name : obj.name.split(":").at(-1);
2222
- console.log(`${s}${name}<${obj.type}>${renderOrder}`);
2223
- });
2224
- }
2225
2243
  /*!
2226
2244
  * camera-controls
2227
2245
  * https://github.com/yomotsu/camera-controls
@@ -4750,14 +4768,13 @@ const subsetOfTHREE = {
4750
4768
  Plane
4751
4769
  };
4752
4770
  CameraControls.install({ THREE: subsetOfTHREE });
4771
+ const logger$4 = createLogger("cameraController");
4753
4772
  class CameraController extends CameraControls {
4754
4773
  /**
4755
4774
  * @param camera {@link PerspectiveCamera} instance
4756
- * @param renderer {@link Renderer} instance
4757
4775
  */
4758
- constructor(camera, renderer) {
4776
+ constructor(camera) {
4759
4777
  super(camera);
4760
- this.renderer = renderer;
4761
4778
  this.dollyToCursor = true;
4762
4779
  this.draggingSmoothTime = 0;
4763
4780
  void this.rotatePolarTo(0, false);
@@ -4774,15 +4791,13 @@ class CameraController extends CameraControls {
4774
4791
  };
4775
4792
  }
4776
4793
  update(delta) {
4777
- var _a2;
4778
4794
  const needsUpdate = super.update(delta);
4779
- if (needsUpdate && ((_a2 = this.renderer) == null ? void 0 : _a2.debugLog)) {
4780
- const position = this.camera.position.toArray().map((value) => value.toFixed(2)).join(", ");
4781
- const target = this._target.toArray().map((value) => value.toFixed(2)).join(", ");
4782
- const spherical = [this._spherical.theta * RAD2DEG, this._spherical.phi * RAD2DEG, this._spherical.radius].map((value) => value.toFixed(2)).join(", ");
4783
- console.log(`position: [${position}]
4784
- target: [${target}]
4785
- spherical: [${spherical}]`);
4795
+ if (needsUpdate) {
4796
+ const position = this.camera.position.toArray().map((value) => +value.toFixed(2));
4797
+ const target = this._target.toArray().map((value) => +value.toFixed(2));
4798
+ const { theta, phi, radius } = this._spherical;
4799
+ const spherical = [theta * RAD2DEG, phi * RAD2DEG, radius].map((value) => +value.toFixed(2));
4800
+ logger$4.debug("camera update %O", { position, target, spherical });
4786
4801
  }
4787
4802
  return needsUpdate;
4788
4803
  }
@@ -4810,7 +4825,7 @@ class CameraSystem {
4810
4825
  this.prevViewportHeightPx = h;
4811
4826
  this.camera = new PerspectiveCamera(this.defaultFov);
4812
4827
  this.camera.up.set(0, 0, -1);
4813
- this.controller = new CameraController(this.camera, this.renderer);
4828
+ this.controller = new CameraController(this.camera);
4814
4829
  this.controller.distance = this.zoomIdentityDistance;
4815
4830
  }
4816
4831
  /** Current camera zoom factor. */
@@ -4823,6 +4838,7 @@ class CameraSystem {
4823
4838
  * @returns Corresponding camera distance on the Z axis
4824
4839
  */
4825
4840
  zoomFactorToDistance(zoomFactor) {
4841
+ if (zoomFactor <= 0) return this.zoomIdentityDistance;
4826
4842
  return this.zoomIdentityDistance / zoomFactor;
4827
4843
  }
4828
4844
  /**
@@ -4878,6 +4894,7 @@ class CameraSystem {
4878
4894
  return zid / (this.controller.distance || zid);
4879
4895
  }
4880
4896
  }
4897
+ const logger$3 = createLogger("external");
4881
4898
  class ExternalSystem {
4882
4899
  /**
4883
4900
  * @param pickingSystem {@link PickingSystem} instance
@@ -4974,7 +4991,7 @@ class ExternalSystem {
4974
4991
  }
4975
4992
  validateMatrix(matrix, name) {
4976
4993
  if (matrix.length !== 16) {
4977
- console.warn(`[ViewportSystem.${name}]: Matrix must be 16 elements long`);
4994
+ logger$3.warn(`${name}: Matrix must be 16 elements long`);
4978
4995
  return false;
4979
4996
  }
4980
4997
  return true;
@@ -5102,6 +5119,7 @@ class SceneSystem {
5102
5119
  this.scene.matrixWorldNeedsUpdate = true;
5103
5120
  }
5104
5121
  }
5122
+ const logger$2 = createLogger("viewport");
5105
5123
  class ViewportSystem {
5106
5124
  /**
5107
5125
  * @param renderer {@link Renderer} instance
@@ -5172,7 +5190,7 @@ class ViewportSystem {
5172
5190
  updatePtScale() {
5173
5191
  const pxToSvgScale = this.pxToSvgScale;
5174
5192
  if (Math.abs(pxToSvgScale - (this.prevPxToSvgScale ?? 0)) < this.pxToSvgScaleThreshold) return;
5175
- if (this.renderer.debugLog) console.log("pxToSvgScale", +pxToSvgScale.toFixed(3));
5193
+ logger$2.debug(`pxToSvgScale ${+pxToSvgScale.toFixed(3)}`);
5176
5194
  this.eventSystem.emit("viewport:ptscale", pxToSvgScale);
5177
5195
  this.prevPxToSvgScale = pxToSvgScale;
5178
5196
  }
@@ -5219,9 +5237,13 @@ class ViewportSystem {
5219
5237
  * @returns Point in NDC space
5220
5238
  */
5221
5239
  canvasToNDC(point, out = new Vector2()) {
5240
+ const [w, h] = this.renderer.size;
5241
+ if (w <= 0 || h <= 0) {
5242
+ logger$2.warn("canvasToNDC: renderer size is 0");
5243
+ return out.set(0, 0);
5244
+ }
5222
5245
  const dpr = this.renderer.context.getPixelRatio();
5223
- const [width, height] = [this.renderer.size[0] / dpr, this.renderer.size[1] / dpr];
5224
- const uv = [point.x / width, point.y / height];
5246
+ const uv = [point.x / (w / dpr), point.y / (h / dpr)];
5225
5247
  const ndc = [uv[0] * 2 - 1, -uv[1] * 2 + 1];
5226
5248
  return out.set(MathUtils.clamp(ndc[0], -1, 1), MathUtils.clamp(ndc[1], -1, 1));
5227
5249
  }
@@ -5271,6 +5293,7 @@ function asViewportAPI(viewportSystem) {
5271
5293
  function eventToCanvas(event) {
5272
5294
  return { x: event.offsetX, y: event.offsetY };
5273
5295
  }
5296
+ const logger$1 = createLogger("controls");
5274
5297
  class ControlsSystem {
5275
5298
  /**
5276
5299
  * @param renderer {@link Renderer} instance
@@ -5321,6 +5344,10 @@ class ControlsSystem {
5321
5344
  [Math.min(...xValues), Math.min(...yValues)],
5322
5345
  [Math.max(...xValues), Math.max(...yValues)]
5323
5346
  );
5347
+ if (sourceRect.size.x <= 0 || sourceRect.size.y <= 0) {
5348
+ logger$1.warn("zoomTo: sourceRect size is 0");
5349
+ return;
5350
+ }
5324
5351
  const targetRect = visibleRect ? new Rect(visibleRect.min.clone().multiplyScalar(dpr), visibleRect.max.clone().multiplyScalar(dpr)) : new Rect([0, 0], [...this.renderer.size]);
5325
5352
  if (paddingPercent) targetRect.addPadding(targetRect.size.x * paddingPercent, targetRect.size.y * paddingPercent);
5326
5353
  const zoomByWidth = targetRect.size.x / sourceRect.size.x;
@@ -5329,7 +5356,7 @@ class ControlsSystem {
5329
5356
  const zoom = maxZoom ? Math.min(minZoom, maxZoom) : minZoom;
5330
5357
  const translate = sourceRect.center;
5331
5358
  if (visibleRect) {
5332
- const offset = new Vector2(...this.renderer.size).multiplyScalar(0.5).sub(targetRect.center).multiplyScalar(1 / zoom).rotateAround({ x: 0, y: 0 }, bearingAngle);
5359
+ const offset = new Vector2(...this.renderer.size).multiplyScalar(0.5).sub(targetRect.center).multiplyScalar(1 / (zoom || 1)).rotateAround({ x: 0, y: 0 }, bearingAngle);
5333
5360
  translate.add(offset);
5334
5361
  }
5335
5362
  const enableTransition = !immediate;
@@ -5390,7 +5417,6 @@ class ControlsSystem {
5390
5417
  const spherical = this.controller.getSpherical(new Spherical());
5391
5418
  const azimuthAngle = spherical.theta;
5392
5419
  const deltaAngleRad = shortestRotationAngle(targetAngleRad, azimuthAngle);
5393
- console.log("rollTo", deltaAngleRad * RAD2DEG, targetAngleRad * RAD2DEG, azimuthAngle * RAD2DEG);
5394
5420
  return this.rollBy(-deltaAngleRad * RAD2DEG, immediate);
5395
5421
  }
5396
5422
  /**
@@ -6186,14 +6212,12 @@ class InteractionsSystem {
6186
6212
  this.canvasListeners = void 0;
6187
6213
  }
6188
6214
  }
6215
+ const logger = createLogger("renderer");
6189
6216
  class Renderer {
6190
6217
  /**
6191
6218
  * @param opts {@link RendererOptions}
6192
6219
  */
6193
6220
  constructor(opts) {
6194
- /** Whether to log debug information */
6195
- __publicField(this, "debugLog");
6196
- //FIXME: Add https://www.npmjs.com/package/debug
6197
6221
  /** {@link HTMLCanvasElement} that this renderer is rendering to */
6198
6222
  __publicField(this, "canvas");
6199
6223
  __publicField(this, "ui");
@@ -6214,9 +6238,8 @@ class Renderer {
6214
6238
  __publicField(this, "initialized", false);
6215
6239
  __publicField(this, "disposed", false);
6216
6240
  __publicField(this, "needsRedraw", true);
6217
- const { canvas, gl, debugLog = false, ui } = opts;
6241
+ const { canvas, gl, ui } = opts;
6218
6242
  this.canvas = canvas;
6219
- this.debugLog = debugLog;
6220
6243
  this.ui = ui;
6221
6244
  this.gl = gl;
6222
6245
  const rendererOptions = {
@@ -6234,6 +6257,8 @@ class Renderer {
6234
6257
  this.layerSystem = new LayerSystem(this);
6235
6258
  this.interactionsSystem = new InteractionsSystem(this, this.eventSystem, this.viewportSystem, this.layerSystem);
6236
6259
  this.controlsSystem = new ControlsSystem(this, this.viewportSystem, this.interactionsSystem);
6260
+ this.canvas.addEventListener("webglcontextlost", (e) => this.onContextLost(e), false);
6261
+ this.canvas.addEventListener("webglcontextrestored", (e) => this.onContextRestored(e), false);
6237
6262
  this.initContext(this.renderer.getContext());
6238
6263
  BatchedMesh.useMultiDraw = this.renderer.extensions.has("WEBGL_multi_draw");
6239
6264
  }
@@ -6353,6 +6378,7 @@ class Renderer {
6353
6378
  this.interactionsSystem.init();
6354
6379
  this.viewportSystem.scene.add(this.layerSystem.buildScene(sceneDef));
6355
6380
  this.initialized = true;
6381
+ logger.info("initialized");
6356
6382
  }
6357
6383
  /**
6358
6384
  * Start the rendering loop
@@ -6363,6 +6389,7 @@ class Renderer {
6363
6389
  if (this.clock.running) return;
6364
6390
  this.clock.start();
6365
6391
  this.renderer.setAnimationLoop(() => this.render());
6392
+ logger.info("started");
6366
6393
  }
6367
6394
  /**
6368
6395
  * Update the given defs to make them reflect the current state
@@ -6402,6 +6429,7 @@ class Renderer {
6402
6429
  stop() {
6403
6430
  this.renderer.setAnimationLoop(null);
6404
6431
  this.clock.stop();
6432
+ logger.info("stopped");
6405
6433
  }
6406
6434
  /**
6407
6435
  * Dispose all WebGL resources. This calls {@link Renderer.stop} internally.
@@ -6419,6 +6447,7 @@ class Renderer {
6419
6447
  this.renderer.dispose();
6420
6448
  this.updateMemoryInfo();
6421
6449
  this.disposed = true;
6450
+ logger.info("disposed");
6422
6451
  }
6423
6452
  // https://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
6424
6453
  resizeCanvasToDisplaySize() {
@@ -6427,7 +6456,7 @@ class Renderer {
6427
6456
  const displayWidth = Math.floor(width * dpr);
6428
6457
  const displayHeight = Math.floor(height * dpr);
6429
6458
  if (this.canvas.width !== displayWidth || this.canvas.height !== displayHeight || this.renderer.getPixelRatio() !== dpr) {
6430
- if (this.debugLog) console.log("renderer resize", width, height, dpr);
6459
+ logger.debug("renderer resize", width, height, dpr);
6431
6460
  this.renderer.setSize(width, height, false);
6432
6461
  this.renderer.setPixelRatio(dpr);
6433
6462
  this.viewportSystem.updateViewport();
@@ -6442,7 +6471,7 @@ class Renderer {
6442
6471
  if (memoryInfo.memory["texture"] !== ((_b = this.memoryInfo) == null ? void 0 : _b.memory["texture"]) || memoryInfo.memory["buffer"] !== ((_c = this.memoryInfo) == null ? void 0 : _c.memory["buffer"]) || memoryInfo.memory["renderbuffer"] !== ((_d = this.memoryInfo) == null ? void 0 : _d.memory["renderbuffer"])) {
6443
6472
  const elapsedTime = this.clock.getElapsedTime() * 1e3;
6444
6473
  const logMarker = `memoryInfo [${elapsedTime.toFixed(2)}ms since start]`;
6445
- if (this.debugLog) console.log(logMarker, memoryInfo);
6474
+ logger.debug(logMarker, memoryInfo);
6446
6475
  this.memoryInfo = memoryInfo;
6447
6476
  this.ui.memoryInfoPanel.textContent = JSON.stringify(memoryInfo, null, 2);
6448
6477
  }
@@ -6451,7 +6480,7 @@ class Renderer {
6451
6480
  onContextLost(event) {
6452
6481
  var _a2, _b;
6453
6482
  event.preventDefault();
6454
- console.log("webglcontextlost event", event);
6483
+ logger.debug("webglcontextlost event", event);
6455
6484
  const stats = (_a2 = this.ui) == null ? void 0 : _a2.stats;
6456
6485
  const context = this.renderer.getContext();
6457
6486
  if (stats && "deleteQuery" in context) {
@@ -6470,7 +6499,7 @@ class Renderer {
6470
6499
  }
6471
6500
  onContextRestored(event) {
6472
6501
  event.preventDefault();
6473
- console.log("webglcontextrestored event", event);
6502
+ logger.debug("webglcontextrestored event", event);
6474
6503
  this.initContext(this.renderer.getContext());
6475
6504
  this.needsRedraw = true;
6476
6505
  this.start();
@@ -6482,35 +6511,35 @@ class Renderer {
6482
6511
  }
6483
6512
  assertNotDisposed(funcName) {
6484
6513
  if (this.disposed) {
6485
- console.warn(`[Renderer.${funcName}]: Renderer is used after being disposed. Please create a new instance.`);
6514
+ logger.warn(`[${funcName}]: Renderer is used after being disposed. Please create a new instance.`);
6486
6515
  return false;
6487
6516
  }
6488
6517
  return true;
6489
6518
  }
6490
6519
  assertInitialized(funcName) {
6491
6520
  if (!this.initialized) {
6492
- console.warn(`[Renderer.${funcName}]: Renderer is not initialized. Please call init() before using it.`);
6521
+ logger.warn(`${funcName}: Renderer is not initialized. Please call init() before using it.`);
6493
6522
  return false;
6494
6523
  }
6495
6524
  return true;
6496
6525
  }
6497
6526
  assertNotInitialized(funcName) {
6498
6527
  if (this.initialized) {
6499
- console.warn(`[Renderer.${funcName}]: Renderer is already initialized. Please call init() only once.`);
6528
+ logger.warn(`${funcName}: Renderer is already initialized. Please call init() only once.`);
6500
6529
  return false;
6501
6530
  }
6502
6531
  return true;
6503
6532
  }
6504
6533
  assertNotExternalMode(funcName) {
6505
6534
  if (this.isExternalMode) {
6506
- console.warn(`[Renderer.${funcName}]: This operation is not supported in external mode.`);
6535
+ logger.warn(`${funcName}: This operation is not supported in external mode.`);
6507
6536
  return false;
6508
6537
  }
6509
6538
  return true;
6510
6539
  }
6511
6540
  assertExternalMode(funcName) {
6512
6541
  if (!this.isExternalMode) {
6513
- console.warn(`[Renderer.${funcName}]: This operation is only supported in external mode.`);
6542
+ logger.warn(`${funcName}: This operation is only supported in external mode.`);
6514
6543
  return false;
6515
6544
  }
6516
6545
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expofp/renderer",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -11,6 +11,7 @@
11
11
  "exports": "./dist/index.js",
12
12
  "devDependencies": {
13
13
  "@types/culori": "^2.1.1",
14
+ "@types/debug": "^4.1.12",
14
15
  "@types/object-hash": "^3.0.6",
15
16
  "@types/three": "^0.174.0",
16
17
  "stats-gl": "^3.6.0",
@@ -22,6 +23,7 @@
22
23
  "dependencies": {
23
24
  "camera-controls": "^3.1.1",
24
25
  "culori": "^4.0.1",
26
+ "debug": "^4.4.3",
25
27
  "maxrects-packer": "^2.7.3",
26
28
  "mjolnir.js": "^3.0.0",
27
29
  "three": "^0.174.0",