@lightningjs/renderer 0.8.0 → 0.8.2

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 (65) hide show
  1. package/dist/src/core/CoreNode.d.ts +7 -2
  2. package/dist/src/core/CoreNode.js +43 -13
  3. package/dist/src/core/CoreNode.js.map +1 -1
  4. package/dist/src/core/CoreShaderManager.d.ts +2 -0
  5. package/dist/src/core/CoreShaderManager.js +2 -0
  6. package/dist/src/core/CoreShaderManager.js.map +1 -1
  7. package/dist/src/core/Stage.js +1 -0
  8. package/dist/src/core/Stage.js.map +1 -1
  9. package/dist/src/core/lib/ImageWorker.js +1 -1
  10. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +1 -0
  11. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +23 -0
  12. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  13. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.d.ts +58 -0
  14. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js +112 -0
  15. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js.map +1 -0
  16. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +3 -0
  17. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  18. package/dist/src/main-api/INode.d.ts +13 -0
  19. package/dist/src/main-api/Inspector.js +4 -0
  20. package/dist/src/main-api/Inspector.js.map +1 -1
  21. package/dist/src/main-api/RendererMain.js +1 -0
  22. package/dist/src/main-api/RendererMain.js.map +1 -1
  23. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +2 -0
  24. package/dist/src/render-drivers/main/MainOnlyNode.js +7 -0
  25. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  26. package/dist/src/render-drivers/main/MainOnlyTextNode.js +1 -0
  27. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  28. package/dist/src/render-drivers/threadx/NodeStruct.d.ts +3 -0
  29. package/dist/src/render-drivers/threadx/NodeStruct.js +9 -0
  30. package/dist/src/render-drivers/threadx/NodeStruct.js.map +1 -1
  31. package/dist/src/render-drivers/threadx/SharedNode.d.ts +1 -0
  32. package/dist/src/render-drivers/threadx/SharedNode.js +1 -0
  33. package/dist/src/render-drivers/threadx/SharedNode.js.map +1 -1
  34. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +2 -0
  35. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  36. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +1 -0
  37. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
  38. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +1 -0
  39. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  40. package/dist/src/render-drivers/threadx/worker/renderer.js +1 -0
  41. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  42. package/dist/src/utils.d.ts +8 -0
  43. package/dist/src/utils.js +10 -0
  44. package/dist/src/utils.js.map +1 -1
  45. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  46. package/package.json +1 -1
  47. package/src/core/CoreNode.ts +63 -19
  48. package/src/core/CoreShaderManager.ts +3 -0
  49. package/src/core/Stage.ts +1 -0
  50. package/src/core/lib/ImageWorker.ts +1 -1
  51. package/src/core/renderers/webgl/shaders/DynamicShader.ts +31 -0
  52. package/src/core/renderers/webgl/shaders/effects/HolePunchEffect.ts +166 -0
  53. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +3 -0
  54. package/src/main-api/INode.ts +13 -0
  55. package/src/main-api/Inspector.ts +5 -0
  56. package/src/main-api/RendererMain.ts +1 -0
  57. package/src/render-drivers/main/MainOnlyNode.ts +9 -0
  58. package/src/render-drivers/main/MainOnlyTextNode.ts +1 -0
  59. package/src/render-drivers/threadx/NodeStruct.ts +10 -0
  60. package/src/render-drivers/threadx/SharedNode.ts +2 -0
  61. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +2 -0
  62. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +1 -0
  63. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +1 -0
  64. package/src/render-drivers/threadx/worker/renderer.ts +1 -0
  65. package/src/utils.ts +11 -0
@@ -170,6 +170,37 @@ export class DynamicShader extends WebGlCoreShader {
170
170
  });
171
171
  }
172
172
 
173
+ override canBatchShaderProps(
174
+ propsA: Required<DynamicShaderProps>,
175
+ propsB: Required<DynamicShaderProps>,
176
+ ): boolean {
177
+ if (
178
+ propsA.$dimensions.width !== propsB.$dimensions.width ||
179
+ propsA.$dimensions.height !== propsB.$dimensions.height ||
180
+ propsA.effects.length !== propsB.effects.length
181
+ ) {
182
+ return false;
183
+ }
184
+ const propsEffectsLen = propsA.effects.length;
185
+ let i = 0;
186
+ for (; i < propsEffectsLen; i++) {
187
+ const effectA = propsA.effects[i]!;
188
+ const effectB = propsB.effects[i]!;
189
+ if (effectA.type !== effectB.type) {
190
+ return false;
191
+ }
192
+ for (const key in effectA.props) {
193
+ if (
194
+ (effectB.props && !effectB.props[key]) ||
195
+ effectA.props[key] !== effectB.props![key]
196
+ ) {
197
+ return false;
198
+ }
199
+ }
200
+ }
201
+ return true;
202
+ }
203
+
173
204
  static createShader(
174
205
  props: DynamicShaderProps,
175
206
  effectContructors: Partial<EffectMap>,
@@ -0,0 +1,166 @@
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
+ import {
20
+ ShaderEffect,
21
+ type DefaultEffectProps,
22
+ type ShaderEffectUniforms,
23
+ } from './ShaderEffect.js';
24
+
25
+ /**
26
+ * Properties of the {@link RadiusEffect} shader
27
+ */
28
+ export interface HolePunchEffectProps extends DefaultEffectProps {
29
+ /**
30
+ * X position where the hole punch starts
31
+ */
32
+ x?: number;
33
+ /**
34
+ * Y position where the hole punch starts
35
+ */
36
+ y?: number;
37
+ /**
38
+ * Width of the hole punch
39
+ */
40
+ width?: number;
41
+ /**
42
+ * height of the hole punch
43
+ *
44
+ * @remarks if not defined uses the width value
45
+ */
46
+ height?: number;
47
+ /**
48
+ * Corner radius in pixels, to cut out of the corners of the hole punch
49
+ *
50
+ * @remarks
51
+ * You can input an array with a length of up to four or a number.
52
+ *
53
+ * array length 4:
54
+ * [topLeft, topRight, bottomRight, bottomLeft]
55
+ *
56
+ * array length 2:
57
+ * [20, 40] -> [20(topLeft), 40(topRight), 20(bottomRight), 40(bottomLeft)]
58
+ *
59
+ * array length 3:
60
+ * [20, 40, 60] -> [20(topLeft), 40(topRight), 60(bottomRight), 20(bottomLeft)]
61
+ *
62
+ * number:
63
+ * 30 -> [30, 30, 30, 30]
64
+ *
65
+ * @default 0
66
+ */
67
+ radius?: number | number[];
68
+ }
69
+
70
+ /**
71
+ * Masks the current maskcolor a holepunch effect with rounded corners similar to {@link RoundedRectangle}
72
+ */
73
+ export class HolePunchEffect extends ShaderEffect {
74
+ static z$__type__Props: HolePunchEffectProps;
75
+ override readonly name = 'holePunch';
76
+
77
+ static override getEffectKey(): string {
78
+ return `holePunch`;
79
+ }
80
+
81
+ static override uniforms: ShaderEffectUniforms = {
82
+ x: {
83
+ value: 0,
84
+ method: 'uniform1f',
85
+ type: 'float',
86
+ },
87
+ y: {
88
+ value: 0,
89
+ method: 'uniform1f',
90
+ type: 'float',
91
+ },
92
+ width: {
93
+ value: 0,
94
+ method: 'uniform1f',
95
+ type: 'float',
96
+ },
97
+ height: {
98
+ value: 0,
99
+ method: 'uniform1f',
100
+ type: 'float',
101
+ },
102
+ radius: {
103
+ value: 0,
104
+ method: 'uniform4fv',
105
+ type: 'vec4',
106
+ validator: (value: number | number[]) => {
107
+ let r = value;
108
+ if (Array.isArray(r)) {
109
+ if (r.length === 2) {
110
+ r = [r[0], r[1], r[0], r[1]] as number[];
111
+ } else if (r.length === 3) {
112
+ r = [r[0], r[1], r[2], r[0]] as number[];
113
+ } else if (r.length !== 4) {
114
+ r = [r[0], r[0], r[0], r[0]] as number[];
115
+ }
116
+ } else if (typeof r === 'number') {
117
+ r = [r, r, r, r];
118
+ }
119
+ return r;
120
+ },
121
+ },
122
+ };
123
+
124
+ static override resolveDefaults(
125
+ props: HolePunchEffectProps,
126
+ ): Required<HolePunchEffectProps> {
127
+ return {
128
+ x: props.x || 0,
129
+ y: props.y || 0,
130
+ width: props.width || 50,
131
+ height: props.height || 50,
132
+ radius: props.radius ?? 0,
133
+ };
134
+ }
135
+
136
+ static override methods: Record<string, string> = {
137
+ fillMask: `
138
+ float function(float dist) {
139
+ return clamp(-dist, 0.0, 1.0);
140
+ }
141
+ `,
142
+ boxDist: `
143
+ float function(vec2 p, vec2 size, float radius) {
144
+ size -= vec2(radius);
145
+ vec2 d = abs(p) - size;
146
+ return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius;
147
+ }
148
+ `,
149
+ };
150
+
151
+ static override onShaderMask = `
152
+ vec2 halfDimensions = u_dimensions * 0.5;
153
+ vec2 size = vec2(width, height) * 0.5;
154
+ vec2 basePos = v_textureCoordinate.xy * u_dimensions.xy - vec2(x, y);
155
+ vec2 pos = basePos - size;
156
+ float r = radius[0] * step(pos.x, 0.5) * step(pos.y, 0.5);
157
+ r = r + radius[1] * step(0.5, pos.x) * step(pos.y, 0.5);
158
+ r = r + radius[2] * step(0.5, pos.x) * step(0.5, pos.y);
159
+ r = r + radius[3] * step(pos.x, 0.5) * step(0.5, pos.y);
160
+ return $boxDist(pos, size, r);
161
+ `;
162
+
163
+ static override onEffectMask = `
164
+ return mix(maskColor, vec4(0.0), $fillMask(shaderMask));
165
+ `;
166
+ }
@@ -235,6 +235,9 @@ export function layoutText(
235
235
  );
236
236
  curX = lastWord.xStart;
237
237
  bufferOffset = lastWord.bufferOffset;
238
+ // HACK: For the rest of the line when inserting the overflow suffix,
239
+ // set contain = 'none' to prevent an infinite loop.
240
+ contain = 'none';
238
241
  }
239
242
  } else {
240
243
  // This glyph fits, so we can add it to the buffer
@@ -72,6 +72,19 @@ export interface INodeWritableProps {
72
72
  * @default `1`
73
73
  */
74
74
  alpha: number;
75
+ /**
76
+ * Autosize mode
77
+ *
78
+ * @remarks
79
+ * When enabled, when a texture is loaded into the Node, the Node will
80
+ * automatically resize to the dimensions of the texture.
81
+ *
82
+ * Text Nodes are always autosized based on their text content regardless
83
+ * of this mode setting.
84
+ *
85
+ * @default `false`
86
+ */
87
+ autosize: boolean;
75
88
  /**
76
89
  * Clipping Mode
77
90
  *
@@ -260,6 +260,11 @@ export class Inspector {
260
260
  ): ITextNode {
261
261
  const node = driver.createTextNode(properties);
262
262
  const div = this.createDiv(node, properties);
263
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
264
+ (div as any).node = node;
265
+
266
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
267
+ (node as any).div = div;
263
268
  return this.createProxy(node, div) as ITextNode;
264
269
  }
265
270
 
@@ -534,6 +534,7 @@ export class RendererMain extends EventEmitter {
534
534
  width: props.width ?? 0,
535
535
  height: props.height ?? 0,
536
536
  alpha: props.alpha ?? 1,
537
+ autosize: props.autosize ?? false,
537
538
  clipping: props.clipping ?? false,
538
539
  color,
539
540
  colorTop: props.colorTop ?? color,
@@ -78,6 +78,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
78
78
  width: props.width,
79
79
  height: props.height,
80
80
  alpha: props.alpha,
81
+ autosize: props.autosize,
81
82
  clipping: props.clipping,
82
83
  color: props.color,
83
84
  colorTop: props.colorTop,
@@ -163,6 +164,14 @@ export class MainOnlyNode extends EventEmitter implements INode {
163
164
  this.coreNode.alpha = value;
164
165
  }
165
166
 
167
+ get autosize(): boolean {
168
+ return this.coreNode.autosize;
169
+ }
170
+
171
+ set autosize(value: boolean) {
172
+ this.coreNode.autosize = value;
173
+ }
174
+
166
175
  get clipping(): boolean {
167
176
  return this.coreNode.clipping;
168
177
  }
@@ -45,6 +45,7 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
45
45
  width: props.width,
46
46
  height: props.height,
47
47
  alpha: props.alpha,
48
+ autosize: props.autosize,
48
49
  clipping: props.clipping,
49
50
  color: props.color,
50
51
  colorTop: props.colorTop,
@@ -25,6 +25,7 @@ export interface NodeStructWritableProps {
25
25
  width: number;
26
26
  height: number;
27
27
  alpha: number;
28
+ autosize: boolean;
28
29
  clipping: boolean;
29
30
  color: number;
30
31
  colorTop: number;
@@ -100,6 +101,15 @@ export class NodeStruct
100
101
  // Decorator will handle this
101
102
  }
102
103
 
104
+ @structProp('boolean')
105
+ get autosize(): boolean {
106
+ return false;
107
+ }
108
+
109
+ set autosize(value: boolean) {
110
+ // Decorator will handle this
111
+ }
112
+
103
113
  @structProp('boolean')
104
114
  get clipping(): boolean {
105
115
  return false;
@@ -40,6 +40,7 @@ export class SharedNode extends SharedObject {
40
40
  width: sharedNodeStruct.width,
41
41
  height: sharedNodeStruct.height,
42
42
  alpha: sharedNodeStruct.alpha,
43
+ autosize: sharedNodeStruct.autosize,
43
44
  clipping: sharedNodeStruct.clipping,
44
45
  color: sharedNodeStruct.color,
45
46
  colorTop: sharedNodeStruct.colorTop,
@@ -72,6 +73,7 @@ export class SharedNode extends SharedObject {
72
73
  declare width: number;
73
74
  declare height: number;
74
75
  declare alpha: number;
76
+ declare autosize: boolean;
75
77
  declare clipping: boolean;
76
78
  declare color: number;
77
79
  declare colorTop: number;
@@ -151,6 +151,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
151
151
  width: props.width,
152
152
  height: props.height,
153
153
  parentId: props.parent ? props.parent.id : 0,
154
+ autosize: props.autosize,
154
155
  clipping: props.clipping,
155
156
  color: props.color,
156
157
  colorTop: props.colorTop,
@@ -208,6 +209,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
208
209
  colorBl: props.colorBl,
209
210
  colorBr: props.colorBr,
210
211
  alpha: props.alpha,
212
+ autosize: props.autosize,
211
213
  zIndex: props.zIndex,
212
214
  zIndexLocked: props.zIndexLocked,
213
215
  scaleX: props.scaleX,
@@ -209,6 +209,7 @@ export class ThreadXRendererNode extends SharedNode {
209
209
  width: sharedNodeStruct.width,
210
210
  height: sharedNodeStruct.height,
211
211
  alpha: sharedNodeStruct.alpha,
212
+ autosize: sharedNodeStruct.autosize,
212
213
  clipping: sharedNodeStruct.clipping,
213
214
  color: sharedNodeStruct.color,
214
215
  colorTop: sharedNodeStruct.colorTop,
@@ -46,6 +46,7 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode {
46
46
  width: sharedNodeStruct.width,
47
47
  height: sharedNodeStruct.height,
48
48
  alpha: sharedNodeStruct.alpha,
49
+ autosize: sharedNodeStruct.autosize,
49
50
  clipping: sharedNodeStruct.clipping,
50
51
  color: sharedNodeStruct.color,
51
52
  colorTop: sharedNodeStruct.colorTop,
@@ -90,6 +90,7 @@ const threadx = ThreadX.init({
90
90
  width: coreRootNode.width,
91
91
  height: coreRootNode.height,
92
92
  alpha: coreRootNode.alpha,
93
+ autosize: coreRootNode.autosize,
93
94
  clipping: coreRootNode.clipping,
94
95
  color: coreRootNode.color,
95
96
  colorTop: coreRootNode.colorTop,
package/src/utils.ts CHANGED
@@ -206,6 +206,17 @@ export function deg2Rad(degrees: number): number {
206
206
  return (degrees * Math.PI) / 180;
207
207
  }
208
208
 
209
+ /**
210
+ * Returns image aspect ratio
211
+ *
212
+ * @param width
213
+ * @param height
214
+ * @returns
215
+ */
216
+ export function getImageAspectRatio(width: number, height: number): number {
217
+ return width / height;
218
+ }
219
+
209
220
  /**
210
221
  * Checks import.meta if env is production
211
222
  *