@lightningjs/renderer 0.8.3 → 0.9.0

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 (177) hide show
  1. package/dist/src/core/CoreNode.d.ts +27 -1
  2. package/dist/src/core/CoreNode.js +130 -5
  3. package/dist/src/core/CoreNode.js.map +1 -1
  4. package/dist/src/core/CoreShaderManager.js +3 -2
  5. package/dist/src/core/CoreShaderManager.js.map +1 -1
  6. package/dist/src/core/CoreTextNode.js +20 -1
  7. package/dist/src/core/CoreTextNode.js.map +1 -1
  8. package/dist/src/core/CoreTextureManager.d.ts +2 -0
  9. package/dist/src/core/CoreTextureManager.js +2 -0
  10. package/dist/src/core/CoreTextureManager.js.map +1 -1
  11. package/dist/src/core/Stage.js +25 -9
  12. package/dist/src/core/Stage.js.map +1 -1
  13. package/dist/src/core/TextureMemoryManager.d.ts +1 -0
  14. package/dist/src/core/TextureMemoryManager.js +3 -1
  15. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  16. package/dist/src/core/lib/ImageWorker.d.ts +2 -1
  17. package/dist/src/core/lib/ImageWorker.js +10 -6
  18. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  19. package/dist/src/core/lib/Matrix3d.d.ts +38 -24
  20. package/dist/src/core/lib/Matrix3d.js +143 -166
  21. package/dist/src/core/lib/Matrix3d.js.map +1 -1
  22. package/dist/src/core/lib/WebGlContextWrapper.d.ts +26 -1
  23. package/dist/src/core/lib/WebGlContextWrapper.js +37 -1
  24. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  25. package/dist/src/core/renderers/CoreRenderer.d.ts +11 -0
  26. package/dist/src/core/renderers/CoreRenderer.js +1 -0
  27. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  28. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.d.ts +10 -4
  29. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js +18 -7
  30. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js.map +1 -1
  31. package/dist/src/core/renderers/canvas/CanvasCoreTexture.d.ts +2 -2
  32. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +8 -6
  33. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -1
  34. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.d.ts +1 -1
  35. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js +1 -1
  36. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js.map +1 -1
  37. package/dist/src/core/renderers/canvas/internal/ColorUtils.js +4 -4
  38. package/dist/src/core/renderers/canvas/internal/ColorUtils.js.map +1 -1
  39. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.d.ts +1 -1
  40. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.js +2 -2
  41. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.js.map +1 -1
  42. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.d.ts +11 -0
  43. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js +51 -0
  44. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js.map +1 -0
  45. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +11 -1
  46. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +22 -11
  47. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  48. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +4 -1
  49. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +7 -2
  50. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  51. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +16 -1
  52. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +119 -27
  53. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  54. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +19 -4
  55. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  56. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +4 -6
  57. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  58. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +6 -1
  59. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  60. package/dist/src/core/text-rendering/TextRenderingUtils.d.ts +12 -0
  61. package/dist/src/core/text-rendering/TextRenderingUtils.js +14 -0
  62. package/dist/src/core/text-rendering/TextRenderingUtils.js.map +1 -0
  63. package/dist/src/core/text-rendering/TextTextureRendererUtils.d.ts +19 -0
  64. package/dist/src/core/text-rendering/TextTextureRendererUtils.js +61 -0
  65. package/dist/src/core/text-rendering/TextTextureRendererUtils.js.map +1 -1
  66. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.d.ts +8 -2
  67. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +24 -3
  68. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  69. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +2 -0
  70. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
  71. package/dist/src/core/text-rendering/font-face-types/TrFontFace.d.ts +72 -1
  72. package/dist/src/core/text-rendering/font-face-types/TrFontFace.js +11 -1
  73. package/dist/src/core/text-rendering/font-face-types/TrFontFace.js.map +1 -1
  74. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.d.ts +5 -2
  75. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js +4 -3
  76. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +8 -0
  78. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +42 -16
  79. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  80. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +7 -1
  81. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +42 -11
  82. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +6 -1
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +27 -9
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +2 -1
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +32 -5
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +1 -1
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +2 -1
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +2 -1
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  92. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +10 -5
  93. package/dist/src/core/text-rendering/renderers/TextRenderer.js +6 -5
  94. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  95. package/dist/src/core/textures/RenderTexture.d.ts +28 -0
  96. package/dist/src/core/textures/RenderTexture.js +52 -0
  97. package/dist/src/core/textures/RenderTexture.js.map +1 -0
  98. package/dist/src/core/utils.d.ts +6 -1
  99. package/dist/src/core/utils.js +74 -82
  100. package/dist/src/core/utils.js.map +1 -1
  101. package/dist/src/main-api/INode.d.ts +9 -0
  102. package/dist/src/main-api/RendererMain.js +4 -3
  103. package/dist/src/main-api/RendererMain.js.map +1 -1
  104. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +3 -0
  105. package/dist/src/render-drivers/main/MainOnlyNode.js +29 -0
  106. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  107. package/dist/src/render-drivers/main/MainOnlyTextNode.js +2 -3
  108. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  109. package/dist/src/render-drivers/threadx/NodeStruct.d.ts +3 -0
  110. package/dist/src/render-drivers/threadx/NodeStruct.js +9 -0
  111. package/dist/src/render-drivers/threadx/NodeStruct.js.map +1 -1
  112. package/dist/src/render-drivers/threadx/SharedNode.d.ts +1 -0
  113. package/dist/src/render-drivers/threadx/SharedNode.js +1 -0
  114. package/dist/src/render-drivers/threadx/SharedNode.js.map +1 -1
  115. package/dist/src/render-drivers/threadx/TextNodeStruct.js +3 -1
  116. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -1
  117. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +2 -0
  118. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  119. package/dist/src/render-drivers/threadx/ThreadXMainNode.d.ts +3 -0
  120. package/dist/src/render-drivers/threadx/ThreadXMainNode.js +7 -0
  121. package/dist/src/render-drivers/threadx/ThreadXMainNode.js.map +1 -1
  122. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +1 -0
  123. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
  124. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +1 -0
  125. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  126. package/dist/src/render-drivers/threadx/worker/renderer.js +1 -0
  127. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  128. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  129. package/package.json +2 -2
  130. package/src/core/CoreNode.ts +164 -8
  131. package/src/core/CoreShaderManager.ts +6 -3
  132. package/src/core/CoreTextNode.ts +25 -0
  133. package/src/core/CoreTextureManager.ts +3 -0
  134. package/src/core/Stage.ts +32 -11
  135. package/src/core/TextureMemoryManager.ts +3 -1
  136. package/src/core/lib/ImageWorker.ts +12 -7
  137. package/src/core/lib/Matrix3d.ts +144 -190
  138. package/src/core/lib/WebGlContextWrapper.ts +51 -1
  139. package/src/core/renderers/CoreRenderer.ts +15 -1
  140. package/src/core/renderers/canvas/CanvasCoreRenderer.ts +59 -14
  141. package/src/core/renderers/canvas/CanvasCoreTexture.ts +24 -18
  142. package/src/core/renderers/canvas/internal/C2DShaderUtils.ts +6 -3
  143. package/src/core/renderers/canvas/internal/ColorUtils.ts +6 -6
  144. package/src/core/renderers/canvas/shaders/UnsupportedShader.ts +2 -3
  145. package/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.ts +79 -0
  146. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +26 -24
  147. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +4 -2
  148. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +166 -33
  149. package/src/core/renderers/webgl/WebGlCoreShader.ts +29 -4
  150. package/src/core/renderers/webgl/shaders/DefaultShader.ts +4 -6
  151. package/src/core/renderers/webgl/shaders/SdfShader.ts +6 -1
  152. package/src/core/text-rendering/TextRenderingUtils.ts +36 -0
  153. package/src/core/text-rendering/TextTextureRendererUtils.ts +74 -0
  154. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +41 -12
  155. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +2 -0
  156. package/src/core/text-rendering/font-face-types/TrFontFace.ts +86 -1
  157. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +13 -7
  158. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +52 -20
  159. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +59 -13
  160. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +36 -8
  161. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +38 -5
  162. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +5 -2
  163. package/src/core/text-rendering/renderers/TextRenderer.ts +17 -10
  164. package/src/core/textures/RenderTexture.ts +81 -0
  165. package/src/core/utils.ts +101 -93
  166. package/src/main-api/INode.ts +11 -0
  167. package/src/main-api/RendererMain.ts +4 -3
  168. package/src/render-drivers/main/MainOnlyNode.ts +44 -0
  169. package/src/render-drivers/main/MainOnlyTextNode.ts +2 -3
  170. package/src/render-drivers/threadx/NodeStruct.ts +10 -0
  171. package/src/render-drivers/threadx/SharedNode.ts +2 -0
  172. package/src/render-drivers/threadx/TextNodeStruct.ts +3 -1
  173. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +2 -0
  174. package/src/render-drivers/threadx/ThreadXMainNode.ts +9 -0
  175. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +1 -0
  176. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +1 -0
  177. package/src/render-drivers/threadx/worker/renderer.ts +1 -0
@@ -17,7 +17,9 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
+ import { assertTruthy } from '../../../../../utils.js';
20
21
  import type { Bound } from '../../../../lib/utils.js';
22
+ import type { SdfTrFontFace } from '../../../font-face-types/SdfTrFontFace/SdfTrFontFace.js';
21
23
  import type { TrProps, TextRendererState } from '../../TextRenderer.js';
22
24
  import type { SdfTextRendererState } from '../SdfTextRenderer.js';
23
25
  import type { SdfRenderWindow } from './setRenderWindow.js';
@@ -39,7 +41,7 @@ import type { SdfRenderWindow } from './setRenderWindow.js';
39
41
  export function getStartConditions(
40
42
  sdfFontSize: number,
41
43
  sdfLineHeight: number,
42
- lineHeight: number,
44
+ fontFace: SdfTrFontFace,
43
45
  verticalAlign: TrProps['verticalAlign'],
44
46
  offsetY: TrProps['offsetY'],
45
47
  fontSizeRatio: number,
@@ -59,17 +61,48 @@ export function getStartConditions(
59
61
  lineCache.length,
60
62
  );
61
63
 
62
- // TODO: (fontSize / 6.4286 / fontSizeRatio) Adding this to the startY helps the text line up better with Canvas rendered text
63
64
  const sdfStartX = 0;
65
+ const { metrics } = fontFace;
66
+ assertTruthy(metrics, 'Font metrics not loaded');
67
+ assertTruthy(fontFace.data, 'Font data not loaded');
68
+
69
+ /**
70
+ * Bare line height is the distance between the ascender and descender of the font.
71
+ * without the line gap metric.
72
+ */
73
+ const sdfBareLineHeight =
74
+ (metrics.ascender - metrics.descender) * sdfFontSize;
64
75
  let sdfVerticalAlignYOffset = 0;
65
76
  if (verticalAlign === 'middle') {
66
- sdfVerticalAlignYOffset = (sdfLineHeight - sdfFontSize) / 2;
77
+ sdfVerticalAlignYOffset = (sdfLineHeight - sdfBareLineHeight) / 2;
67
78
  } else if (verticalAlign === 'bottom') {
68
- sdfVerticalAlignYOffset = sdfLineHeight - sdfFontSize;
79
+ sdfVerticalAlignYOffset = sdfLineHeight - sdfBareLineHeight;
69
80
  }
81
+
70
82
  const sdfOffsetY = offsetY / fontSizeRatio;
83
+
84
+ /**
85
+ * This is the position from the top of the text drawing line to where the
86
+ * baseline of the text will be according to the encoded positioning data for
87
+ * each glyph in the SDF data. This also happens to be the ascender value
88
+ * that is encoded into the font data.
89
+ */
90
+ const sdfEncodedAscender = fontFace.data.common.base;
91
+ /**
92
+ * This is the ascender that is configured and overridable in the font face.
93
+ */
94
+ const sdfConfiguredAscender = metrics.ascender * sdfFontSize;
95
+ /**
96
+ * If the configured ascender is different from the SDF data's encoded
97
+ * ascender, the offset of the text will be adjusted by the difference.
98
+ */
99
+ const sdfAscenderAdjOffset = sdfConfiguredAscender - sdfEncodedAscender;
100
+
71
101
  const sdfStartY =
72
- sdfOffsetY + startLineIndex * sdfLineHeight + sdfVerticalAlignYOffset; // TODO: Figure out what determines the initial y offset of text.
102
+ sdfOffsetY +
103
+ sdfAscenderAdjOffset +
104
+ startLineIndex * sdfLineHeight +
105
+ sdfVerticalAlignYOffset; // TODO: Figure out what determines the initial y offset of text.
73
106
 
74
107
  // Don't attempt to render anything if we know we're starting past the established end of the text
75
108
  if (textH && sdfStartY >= textH / fontSizeRatio) {
@@ -39,7 +39,7 @@ export function layoutText(
39
39
  width: TrProps['width'],
40
40
  height: TrProps['height'],
41
41
  fontSize: TrProps['fontSize'],
42
- lineHeight: TrProps['lineHeight'],
42
+ lineHeight: number,
43
43
  letterSpacing: TrProps['letterSpacing'],
44
44
  /**
45
45
  * Mutated
@@ -63,6 +63,7 @@ export function layoutText(
63
63
  fullyProcessed: boolean;
64
64
  maxX: number;
65
65
  maxY: number;
66
+ numLines: number;
66
67
  } {
67
68
  assertTruthy(trFontFace, 'Font face must be loaded');
68
69
  assertTruthy(trFontFace.loaded, 'Font face must be loaded');
@@ -82,6 +83,7 @@ export function layoutText(
82
83
  * See above
83
84
  */
84
85
  const fontSizeRatio = fontSize / trFontFace.data.info.size;
86
+
85
87
  /**
86
88
  * `lineHeight` in vertex coordinates
87
89
  */
@@ -170,7 +172,7 @@ export function layoutText(
170
172
  */
171
173
  let xStartLastWordBoundary = 0;
172
174
 
173
- const lineIsBelowWindowTop = curY + vertexLineHeight >= rwSdf.y1;
175
+ const lineIsBelowWindowTop = curY + trFontFace.maxCharHeight >= rwSdf.y1;
174
176
  const lineIsAboveWindowBottom = curY <= rwSdf.y2;
175
177
  const lineIsWithinWindow = lineIsBelowWindowTop && lineIsAboveWindowBottom;
176
178
  // Layout glyphs in this line
@@ -390,5 +392,6 @@ export function layoutText(
390
392
  fullyProcessed: !!glyphResult.done,
391
393
  maxX,
392
394
  maxY,
395
+ numLines: lineCache.length,
393
396
  };
394
397
  }
@@ -17,6 +17,7 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
+ import type { Dimensions } from '../../../common/CommonTypes.js';
20
21
  import type { EventEmitter } from '../../../common/EventEmitter.js';
21
22
  import type { Stage } from '../../Stage.js';
22
23
  import type { Matrix3d } from '../../lib/Matrix3d.js';
@@ -52,7 +53,7 @@ export interface TextRendererState {
52
53
  * via queueMicrotask.
53
54
  */
54
55
  updateScheduled: boolean;
55
- status: 'initialState' | 'loading' | 'loaded' | 'failed';
56
+ status: 'initialState' | 'loading' | 'loaded' | 'failed' | 'destroyed';
56
57
  /**
57
58
  * Event emitter for the text renderer
58
59
  */
@@ -266,11 +267,15 @@ export interface TrProps extends TrFontProps {
266
267
  * Line height for text (in pixels)
267
268
  *
268
269
  * @remarks
269
- * This property sets the height of each line.
270
+ * This property sets the height of each line. If set to `undefined`, the
271
+ * line height will be calculated based on the font and font size to be the
272
+ * minimal height required to completely contain a line of text.
270
273
  *
271
- * @default 0
274
+ * See: https://github.com/lightning-js/renderer/issues/170
275
+ *
276
+ * @default `undefined`
272
277
  */
273
- lineHeight: number;
278
+ lineHeight: number | undefined;
274
279
  /**
275
280
  * Max lines for text
276
281
  *
@@ -508,12 +513,8 @@ export abstract class TextRenderer<
508
513
  * @param state
509
514
  */
510
515
  destroyState(state: StateT) {
511
- const stateEvents = ['loading', 'loaded', 'failed'];
512
-
513
- // Remove the old event listeners from previous state obj there was one
514
- stateEvents.forEach((eventName) => {
515
- state.emitter.off(eventName);
516
- });
516
+ this.setStatus(state, 'destroyed');
517
+ state.emitter.removeAllListeners();
517
518
  }
518
519
 
519
520
  /**
@@ -532,6 +533,10 @@ export abstract class TextRenderer<
532
533
  }
533
534
  state.updateScheduled = true;
534
535
  queueMicrotask(() => {
536
+ // If the state has been destroyed, don't update it
537
+ if (state.status === 'destroyed') {
538
+ return;
539
+ }
535
540
  state.updateScheduled = false;
536
541
  this.updateState(state);
537
542
  });
@@ -544,5 +549,7 @@ export abstract class TextRenderer<
544
549
  transform: Matrix3d,
545
550
  clippingRect: RectWithValid,
546
551
  alpha: number,
552
+ parentHasRenderTexture: boolean,
553
+ framebufferDimensions: Dimensions | undefined,
547
554
  ): void;
548
555
  }
@@ -0,0 +1,81 @@
1
+ /*
2
+ * If not stated otherwise in this file or this component's LICENSE file the
3
+ * following copyright and licenses apply:
4
+ *
5
+ * Copyright 2023 Comcast Cable Communications Management, LLC.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the License);
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ import type { CoreTextureManager } from '../CoreTextureManager.js';
21
+ import { Texture, type TextureData } from './Texture.js';
22
+
23
+ /**
24
+ * Properties of the {@link RenderTexture}
25
+ */
26
+ export interface RenderTextureProps {
27
+ /**
28
+ * WebGL Texture width
29
+ * @default 256
30
+ */
31
+ width?: number;
32
+
33
+ /**
34
+ * WebGL Texture height
35
+ * @default 256
36
+ */
37
+ height?: number;
38
+ }
39
+
40
+ export class RenderTexture extends Texture {
41
+ props: Required<RenderTextureProps>;
42
+
43
+ constructor(txManager: CoreTextureManager, props?: RenderTextureProps) {
44
+ super(txManager);
45
+ this.props = RenderTexture.resolveDefaults(props || {});
46
+ }
47
+
48
+ get width() {
49
+ return this.props.width;
50
+ }
51
+
52
+ set width(value: number) {
53
+ this.props.width = value;
54
+ }
55
+
56
+ get height() {
57
+ return this.props.height;
58
+ }
59
+
60
+ set height(value: number) {
61
+ this.props.height = value;
62
+ }
63
+
64
+ override async getTextureData(): Promise<TextureData> {
65
+ return {
66
+ data: null,
67
+ premultiplyAlpha: null,
68
+ };
69
+ }
70
+
71
+ static override resolveDefaults(
72
+ props: RenderTextureProps,
73
+ ): Required<RenderTextureProps> {
74
+ return {
75
+ width: props.width || 256,
76
+ height: props.height || 256,
77
+ };
78
+ }
79
+
80
+ static z$__type__Props: RenderTextureProps;
81
+ }
package/src/core/utils.ts CHANGED
@@ -23,8 +23,6 @@
23
23
  * @module
24
24
  */
25
25
 
26
- import memo from 'memize';
27
-
28
26
  export const EPSILON = 0.000001;
29
27
  export let ARRAY_TYPE =
30
28
  typeof Float32Array !== 'undefined' ? Float32Array : Array;
@@ -121,97 +119,107 @@ const getTimingBezier = (
121
119
  };
122
120
  };
123
121
 
124
- export const getTimingFunction = memo(
125
- (str: string): ((time: number) => number | undefined) => {
126
- switch (str) {
127
- case 'linear':
128
- return function (time: number) {
129
- return time;
130
- };
131
- case 'ease':
132
- return getTimingBezier(0.25, 0.1, 0.25, 1.0);
133
-
134
- case 'ease-in':
135
- return getTimingBezier(0.42, 0, 1.0, 1.0);
136
- case 'ease-out':
137
- return getTimingBezier(0, 0, 0.58, 1.0);
138
- case 'ease-in-out':
139
- return getTimingBezier(0.42, 0, 0.58, 1.0);
140
-
141
- case 'ease-in-sine':
142
- return getTimingBezier(0.12, 0, 0.39, 0);
143
- case 'ease-out-sine':
144
- return getTimingBezier(0.12, 0, 0.39, 0);
145
- case 'ease-in-out-sine':
146
- return getTimingBezier(0.37, 0, 0.63, 1);
147
-
148
- case 'ease-in-cubic':
149
- return getTimingBezier(0.32, 0, 0.67, 0);
150
- case 'ease-out-cubic':
151
- return getTimingBezier(0.33, 1, 0.68, 1);
152
- case 'ease-in-out-cubic':
153
- return getTimingBezier(0.65, 0, 0.35, 1);
154
-
155
- case 'ease-in-circ':
156
- return getTimingBezier(0.55, 0, 1, 0.45);
157
- case 'ease-out-circ':
158
- return getTimingBezier(0, 0.55, 0.45, 1);
159
- case 'ease-in-out-circ':
160
- return getTimingBezier(0.85, 0, 0.15, 1);
161
-
162
- case 'ease-in-back':
163
- return getTimingBezier(0.36, 0, 0.66, -0.56);
164
- case 'ease-out-back':
165
- return getTimingBezier(0.34, 1.56, 0.64, 1);
166
- case 'ease-in-out-back':
167
- return getTimingBezier(0.68, -0.6, 0.32, 1.6);
168
-
169
- case 'step-start':
170
- return function () {
171
- return 1;
172
- };
173
- case 'step-end':
174
- return function (time: number) {
175
- return time === 1 ? 1 : 0;
176
- };
177
- default:
178
- // eslint-disable-next-line no-case-declarations
179
- const s = 'cubic-bezier(';
180
- if (str && str.indexOf(s) === 0) {
181
- const parts = str
182
- .substr(s.length, str.length - s.length - 1)
183
- .split(',');
184
- if (parts.length !== 4) {
185
- console.warn('Unknown timing function: ' + str);
186
- // Fallback: use linear.
187
- return function (time) {
188
- return time;
189
- };
190
- }
191
- const a = parseFloat(parts[0] || '0.42');
192
- const b = parseFloat(parts[1] || '0');
193
- const c = parseFloat(parts[2] || '1');
194
- const d = parseFloat(parts[3] || '1');
195
-
196
- if (isNaN(a) || isNaN(b) || isNaN(c) || isNaN(d)) {
197
- console.warn(' Unknown timing function: ' + str);
198
- // Fallback: use linear.
199
- return function (time) {
200
- return time;
201
- };
202
- }
203
-
204
- return getTimingBezier(a, b, c, d);
205
- } else {
206
- console.warn('Unknown timing function: ' + str);
207
- // Fallback: use linear.
208
- return function (time) {
209
- return time;
210
- };
211
- }
212
- }
213
- },
214
- );
122
+ interface TimingFunctionMap {
123
+ [key: string]: (time: number) => number | undefined;
124
+ }
125
+
126
+ type TimingLookupArray = number[];
127
+ interface TimingLookup {
128
+ [key: string]: TimingLookupArray;
129
+ }
130
+
131
+ const timingMapping: TimingFunctionMap = {};
132
+
133
+ const timingLookup: TimingLookup = {
134
+ ease: [0.25, 0.1, 0.25, 1.0],
135
+ 'ease-in': [0.42, 0, 1.0, 1.0],
136
+ 'ease-out': [0, 0, 0.58, 1.0],
137
+ 'ease-in-out': [0.42, 0, 0.58, 1.0],
138
+ 'ease-in-sine': [0.12, 0, 0.39, 0],
139
+ 'ease-out-sine': [0.12, 0, 0.39, 0],
140
+ 'ease-in-out-sine': [0.37, 0, 0.63, 1],
141
+ 'ease-in-cubic': [0.32, 0, 0.67, 0],
142
+ 'ease-out-cubic': [0.33, 1, 0.68, 1],
143
+ 'ease-in-out-cubic': [0.65, 0, 0.35, 1],
144
+ 'ease-in-circ': [0.55, 0, 1, 0.45],
145
+ 'ease-out-circ': [0, 0.55, 0.45, 1],
146
+ 'ease-in-out-circ': [0.85, 0, 0.15, 1],
147
+ 'ease-in-back': [0.36, 0, 0.66, -0.56],
148
+ 'ease-out-back': [0.34, 1.56, 0.64, 1],
149
+ 'ease-in-out-back': [0.68, -0.6, 0.32, 1.6],
150
+ };
151
+
152
+ const defaultTiming = (t: number): number => t;
153
+
154
+ const parseCubicBezier = (str: string) => {
155
+ //cubic-bezier(0.84, 0.52, 0.56, 0.6)
156
+ const regex = /-?\d*\.?\d+/g;
157
+ const match = str.match(regex);
158
+
159
+ if (match) {
160
+ const [num1, num2, num3, num4] = match;
161
+ const a = parseFloat(num1 || '0.42');
162
+ const b = parseFloat(num2 || '0');
163
+ const c = parseFloat(num3 || '1');
164
+ const d = parseFloat(num4 || '1');
165
+
166
+ const timing = getTimingBezier(a, b, c, d);
167
+ timingMapping[str] = timing;
168
+
169
+ return timing;
170
+ }
171
+
172
+ // parse failed, return linear
173
+ console.warn('Unknown cubic-bezier timing: ' + str);
174
+ return defaultTiming;
175
+ };
176
+
177
+ export const getTimingFunction = (
178
+ str: string,
179
+ ): ((time: number) => number | undefined) => {
180
+ if (str === '') {
181
+ return defaultTiming;
182
+ }
183
+
184
+ if (timingMapping[str] !== undefined) {
185
+ return timingMapping[str] || defaultTiming;
186
+ }
187
+
188
+ if (str === 'linear') {
189
+ return (time: number) => {
190
+ return time;
191
+ };
192
+ }
193
+
194
+ if (str === 'step-start') {
195
+ return () => {
196
+ return 1;
197
+ };
198
+ }
199
+
200
+ if (str === 'step-end') {
201
+ return (time: number) => {
202
+ return time === 1 ? 1 : 0;
203
+ };
204
+ }
205
+
206
+ if (timingLookup[str] !== undefined) {
207
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
208
+ // @ts-ignore - TS doesn't understand that we've checked for undefined
209
+ const [a, b, c, d] = timingLookup[str];
210
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
211
+ const timing = getTimingBezier(a, b, c, d);
212
+ timingMapping[str] = timing;
213
+ return timing;
214
+ }
215
+
216
+ if (str.startsWith('cubic-bezier')) {
217
+ return parseCubicBezier(str);
218
+ }
219
+
220
+ console.warn('Unknown timing function: ' + str);
221
+ return defaultTiming;
222
+ };
215
223
 
216
224
  if (!Math.hypot)
217
225
  Math.hypot = (...args: number[]) => {
@@ -405,6 +405,17 @@ export interface INodeWritableProps {
405
405
  * - `2 * Math.PI`: 360 rotation clockwise
406
406
  */
407
407
  rotation: number;
408
+
409
+ /**
410
+ * Whether the Node is rendered to a texture
411
+ *
412
+ * @remarks
413
+ * TBD
414
+ *
415
+ * @default false
416
+ */
417
+ rtt: boolean;
418
+
408
419
  /**
409
420
  * Node data element for custom data storage (optional)
410
421
  *
@@ -350,7 +350,7 @@ export class RendererMain extends EventEmitter {
350
350
  settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
351
351
  enableContextSpy: settings.enableContextSpy ?? false,
352
352
  enableInspector: settings.enableInspector ?? false,
353
- renderMode: settings.renderMode ?? 'webgl'
353
+ renderMode: settings.renderMode ?? 'webgl',
354
354
  };
355
355
  this.settings = resolvedSettings;
356
356
 
@@ -498,10 +498,10 @@ export class RendererMain extends EventEmitter {
498
498
  scrollY: props.scrollY ?? 0,
499
499
  offsetY: props.offsetY ?? 0,
500
500
  letterSpacing: props.letterSpacing ?? 0,
501
- lineHeight: props.lineHeight ?? fontSize,
501
+ lineHeight: props.lineHeight, // `undefined` is a valid value
502
502
  maxLines: props.maxLines ?? 0,
503
503
  textBaseline: props.textBaseline ?? 'alphabetic',
504
- verticalAlign: props.verticalAlign ?? 'top',
504
+ verticalAlign: props.verticalAlign ?? 'middle',
505
505
  overflowSuffix: props.overflowSuffix ?? '...',
506
506
  debug: props.debug ?? {},
507
507
  };
@@ -570,6 +570,7 @@ export class RendererMain extends EventEmitter {
570
570
  pivotX: props.pivotX ?? props.pivot ?? 0.5,
571
571
  pivotY: props.pivotY ?? props.pivot ?? 0.5,
572
572
  rotation: props.rotation ?? 0,
573
+ rtt: props.rtt ?? false,
573
574
  data: data,
574
575
  };
575
576
  }
@@ -105,6 +105,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
105
105
  shaderProps: null,
106
106
  texture: null,
107
107
  textureOptions: null,
108
+ rtt: props.rtt,
108
109
  });
109
110
  // Forward loaded/failed events
110
111
  this.coreNode.on('loaded', this.onTextureLoaded);
@@ -121,6 +122,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
121
122
  this.shader = props.shader;
122
123
  this.texture = props.texture;
123
124
  this.src = props.src;
125
+ this.rtt = props.rtt;
124
126
  this._data = props.data;
125
127
  }
126
128
 
@@ -145,6 +147,16 @@ export class MainOnlyNode extends EventEmitter implements INode {
145
147
  }
146
148
 
147
149
  set width(value: number) {
150
+ if (value !== this.coreNode.width && this.coreNode.rtt) {
151
+ this.texture = this.rendererMain.createTexture(
152
+ 'RenderTexture',
153
+ {
154
+ width: this.width,
155
+ height: this.height,
156
+ },
157
+ { preload: true, flipY: true },
158
+ );
159
+ }
148
160
  this.coreNode.width = value;
149
161
  }
150
162
 
@@ -153,6 +165,16 @@ export class MainOnlyNode extends EventEmitter implements INode {
153
165
  }
154
166
 
155
167
  set height(value: number) {
168
+ if (value !== this.coreNode.height && this.coreNode.rtt) {
169
+ this.texture = this.rendererMain.createTexture(
170
+ 'RenderTexture',
171
+ {
172
+ width: this.width,
173
+ height: this.height,
174
+ },
175
+ { preload: true, flipY: true },
176
+ );
177
+ }
156
178
  this.coreNode.height = value;
157
179
  }
158
180
 
@@ -422,6 +444,28 @@ export class MainOnlyNode extends EventEmitter implements INode {
422
444
  }
423
445
  }
424
446
 
447
+ get rtt(): boolean {
448
+ return this.coreNode.rtt;
449
+ }
450
+
451
+ set rtt(value: boolean) {
452
+ if (value) {
453
+ this.texture = this.rendererMain.createTexture(
454
+ 'RenderTexture',
455
+ {
456
+ width: this.width,
457
+ height: this.height,
458
+ },
459
+ { preload: true, flipY: true },
460
+ );
461
+ }
462
+ this.coreNode.rtt = value;
463
+ }
464
+
465
+ get parentHasRenderTexture(): boolean {
466
+ return this.coreNode.parentHasRenderTexture;
467
+ }
468
+
425
469
  private onTextureLoaded: NodeLoadedEventHandler = (target, payload) => {
426
470
  this.emit('loaded', payload);
427
471
  };
@@ -94,6 +94,7 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
94
94
  textureOptions: null,
95
95
  shader: null,
96
96
  shaderProps: null,
97
+ rtt: false,
97
98
  }),
98
99
  );
99
100
  }
@@ -207,9 +208,7 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
207
208
  }
208
209
 
209
210
  set lineHeight(value: ITextNode['lineHeight']) {
210
- if (value) {
211
- this.coreNode.lineHeight = value;
212
- }
211
+ this.coreNode.lineHeight = value;
213
212
  }
214
213
 
215
214
  get maxLines(): ITextNode['maxLines'] {
@@ -48,6 +48,7 @@ export interface NodeStructWritableProps {
48
48
  pivotX: number;
49
49
  pivotY: number;
50
50
  rotation: number;
51
+ rtt: boolean;
51
52
  }
52
53
 
53
54
  export class NodeStruct
@@ -307,4 +308,13 @@ export class NodeStruct
307
308
  set zIndexLocked(value: number) {
308
309
  // Decorator will handle this
309
310
  }
311
+
312
+ @structProp('boolean')
313
+ get rtt(): boolean {
314
+ return false;
315
+ }
316
+
317
+ set rtt(value: boolean) {
318
+ // Decorator will handle this
319
+ }
310
320
  }
@@ -63,6 +63,7 @@ export class SharedNode extends SharedObject {
63
63
  pivotX: sharedNodeStruct.pivotX,
64
64
  pivotY: sharedNodeStruct.pivotY,
65
65
  rotation: sharedNodeStruct.rotation,
66
+ rtt: sharedNodeStruct.rtt,
66
67
  } satisfies NodeStructWritableProps);
67
68
  }
68
69
 
@@ -96,4 +97,5 @@ export class SharedNode extends SharedObject {
96
97
  protected declare parentId: number;
97
98
  declare zIndex: number;
98
99
  declare zIndexLocked: number;
100
+ declare rtt: boolean;
99
101
  }
@@ -164,7 +164,9 @@ export class TextNodeStruct
164
164
  // Decorator will handle this
165
165
  }
166
166
 
167
- @structProp('number')
167
+ @structProp('number', {
168
+ allowUndefined: true,
169
+ })
168
170
  get lineHeight(): TextNodeStructWritableProps['lineHeight'] {
169
171
  return 0;
170
172
  }