@lightningjs/renderer 0.7.0 → 0.7.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.
- package/dist/exports/main-api.d.ts +1 -0
- package/dist/src/core/CoreNode.d.ts +4 -7
- package/dist/src/core/CoreNode.js +29 -25
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreShaderManager.d.ts +13 -6
- package/dist/src/core/CoreShaderManager.js +6 -6
- package/dist/src/core/CoreShaderManager.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +2 -2
- package/dist/src/core/CoreTextNode.js +1 -1
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/Stage.js +1 -1
- package/dist/src/core/Stage.js.map +1 -1
- package/dist/src/core/animations/CoreAnimation.d.ts +1 -0
- package/dist/src/core/animations/CoreAnimation.js +7 -0
- package/dist/src/core/animations/CoreAnimation.js.map +1 -1
- package/dist/src/core/lib/WebGlContextWrapper.d.ts +9 -0
- package/dist/src/core/lib/WebGlContextWrapper.js +12 -0
- package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
- package/dist/src/core/lib/textureCompression.d.ts +16 -0
- package/dist/src/core/lib/textureCompression.js +129 -0
- package/dist/src/core/lib/textureCompression.js.map +1 -0
- package/dist/src/core/lib/utils.d.ts +9 -0
- package/dist/src/core/lib/utils.js +48 -1
- package/dist/src/core/lib/utils.js.map +1 -1
- package/dist/src/core/renderers/CoreRenderer.d.ts +2 -2
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +12 -0
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +3 -3
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +5 -0
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.d.ts +4 -0
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +11 -0
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -2
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +10 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +21 -7
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +6 -10
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +73 -46
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +2 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +2 -2
- package/dist/src/core/textures/ImageTexture.js +5 -0
- package/dist/src/core/textures/ImageTexture.js.map +1 -1
- package/dist/src/core/textures/Texture.d.ts +28 -1
- package/dist/src/core/textures/Texture.js.map +1 -1
- package/dist/src/main-api/Inspector.d.ts +15 -0
- package/dist/src/main-api/Inspector.js +216 -0
- package/dist/src/main-api/Inspector.js.map +1 -0
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/exports/main-api.ts +9 -0
- package/package.json +1 -1
- package/src/core/CoreNode.ts +30 -29
- package/src/core/CoreShaderManager.ts +39 -6
- package/src/core/CoreTextNode.ts +2 -2
- package/src/core/Stage.ts +1 -1
- package/src/core/animations/CoreAnimation.ts +8 -0
- package/src/core/lib/WebGlContextWrapper.ts +27 -0
- package/src/core/lib/textureCompression.ts +152 -0
- package/src/core/lib/utils.ts +68 -1
- package/src/core/renderers/CoreRenderer.ts +2 -2
- package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +20 -0
- package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +3 -3
- package/src/core/renderers/webgl/WebGlCoreRenderer.ts +7 -1
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +15 -1
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +12 -4
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -1
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +16 -2
- package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +42 -8
- package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +96 -60
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +2 -1
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +4 -1
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +1 -1
- package/src/core/text-rendering/renderers/TextRenderer.ts +2 -2
- package/src/core/textures/ImageTexture.ts +9 -0
- package/src/core/textures/Texture.ts +33 -1
package/package.json
CHANGED
package/src/core/CoreNode.ts
CHANGED
|
@@ -37,7 +37,7 @@ import type {
|
|
|
37
37
|
NodeTextureLoadedPayload,
|
|
38
38
|
} from '../common/CommonTypes.js';
|
|
39
39
|
import { EventEmitter } from '../common/EventEmitter.js';
|
|
40
|
-
import { intersectRect, type
|
|
40
|
+
import { copyRect, intersectRect, type RectWithValid } from './lib/utils.js';
|
|
41
41
|
import { Matrix3d } from './lib/Matrix3d.js';
|
|
42
42
|
|
|
43
43
|
export interface CoreNodeProps {
|
|
@@ -150,9 +150,14 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
150
150
|
public globalTransform?: Matrix3d;
|
|
151
151
|
public scaleRotateTransform?: Matrix3d;
|
|
152
152
|
public localTransform?: Matrix3d;
|
|
153
|
-
public clippingRect:
|
|
153
|
+
public clippingRect: RectWithValid = {
|
|
154
|
+
x: 0,
|
|
155
|
+
y: 0,
|
|
156
|
+
width: 0,
|
|
157
|
+
height: 0,
|
|
158
|
+
valid: false,
|
|
159
|
+
};
|
|
154
160
|
public isRenderable = false;
|
|
155
|
-
private parentClippingRect: Rect | null = null;
|
|
156
161
|
public worldAlpha = 1;
|
|
157
162
|
public premultipliedColorTl = 0;
|
|
158
163
|
public premultipliedColorTr = 0;
|
|
@@ -296,7 +301,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
296
301
|
* @todo: test for correct calculation flag
|
|
297
302
|
* @param delta
|
|
298
303
|
*/
|
|
299
|
-
update(delta: number, parentClippingRect:
|
|
304
|
+
update(delta: number, parentClippingRect: RectWithValid): void {
|
|
300
305
|
if (this.updateType & UpdateType.ScaleRotate) {
|
|
301
306
|
this.updateScaleRotateTransform();
|
|
302
307
|
this.setUpdateType(UpdateType.Local);
|
|
@@ -473,40 +478,36 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
473
478
|
/**
|
|
474
479
|
* This function calculates the clipping rectangle for a node.
|
|
475
480
|
*
|
|
476
|
-
* If the parent clipping rectangle has not changed and the node's clipping rectangle is already set, the function returns immediately.
|
|
477
|
-
*
|
|
478
481
|
* The function then checks if the node is rotated. If the node requires clipping and is not rotated, a new clipping rectangle is created based on the node's global transform and dimensions.
|
|
479
482
|
* If a parent clipping rectangle exists, it is intersected with the node's clipping rectangle (if it exists), or replaces the node's clipping rectangle.
|
|
480
483
|
*
|
|
481
484
|
* Finally, the node's parentClippingRect and clippingRect properties are updated.
|
|
482
485
|
*/
|
|
483
|
-
calculateClippingRect(parentClippingRect:
|
|
486
|
+
calculateClippingRect(parentClippingRect: RectWithValid) {
|
|
484
487
|
assertTruthy(this.globalTransform);
|
|
488
|
+
const { clippingRect, props, globalTransform: gt } = this;
|
|
489
|
+
const { clipping } = props;
|
|
485
490
|
|
|
486
|
-
if (this.parentClippingRect === parentClippingRect && this.clippingRect) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const gt = this.globalTransform;
|
|
491
491
|
const isRotated = gt.tb !== 0 || gt.tc !== 0;
|
|
492
492
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
clippingRect
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
493
|
+
if (clipping && !isRotated) {
|
|
494
|
+
clippingRect.x = gt.tx;
|
|
495
|
+
clippingRect.y = gt.ty;
|
|
496
|
+
clippingRect.width = this.width * gt.ta;
|
|
497
|
+
clippingRect.height = this.height * gt.td;
|
|
498
|
+
clippingRect.valid = true;
|
|
499
|
+
} else {
|
|
500
|
+
clippingRect.valid = false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (parentClippingRect.valid && clippingRect.valid) {
|
|
504
|
+
// Intersect parent clipping rect with node clipping rect
|
|
505
|
+
intersectRect(parentClippingRect, clippingRect, clippingRect);
|
|
506
|
+
} else if (parentClippingRect.valid) {
|
|
507
|
+
// Copy parent clipping rect
|
|
508
|
+
copyRect(parentClippingRect, clippingRect);
|
|
509
|
+
clippingRect.valid = true;
|
|
510
|
+
}
|
|
510
511
|
}
|
|
511
512
|
|
|
512
513
|
calculateZIndex(): void {
|
|
@@ -31,17 +31,42 @@ import { SdfShader } from './renderers/webgl/shaders/SdfShader.js';
|
|
|
31
31
|
|
|
32
32
|
import { RadiusEffect } from './renderers/webgl/shaders/effects/RadiusEffect.js';
|
|
33
33
|
import { BorderEffect } from './renderers/webgl/shaders/effects/BorderEffect.js';
|
|
34
|
-
import {
|
|
35
|
-
|
|
34
|
+
import {
|
|
35
|
+
LinearGradientEffect,
|
|
36
|
+
type LinearGradientEffectProps,
|
|
37
|
+
} from './renderers/webgl/shaders/effects/LinearGradientEffect.js';
|
|
38
|
+
import {
|
|
39
|
+
GrayscaleEffect,
|
|
40
|
+
type GrayscaleEffectProps,
|
|
41
|
+
} from './renderers/webgl/shaders/effects/GrayscaleEffect.js';
|
|
36
42
|
import { BorderRightEffect } from './renderers/webgl/shaders/effects/BorderRightEffect.js';
|
|
37
43
|
import { BorderTopEffect } from './renderers/webgl/shaders/effects/BorderTopEffect.js';
|
|
38
44
|
import { BorderBottomEffect } from './renderers/webgl/shaders/effects/BorderBottomEffect.js';
|
|
39
45
|
import { BorderLeftEffect } from './renderers/webgl/shaders/effects/BorderLeftEffect.js';
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
import {
|
|
47
|
+
GlitchEffect,
|
|
48
|
+
type GlitchEffectProps,
|
|
49
|
+
} from './renderers/webgl/shaders/effects/GlitchEffect.js';
|
|
50
|
+
import {
|
|
51
|
+
FadeOutEffect,
|
|
52
|
+
type FadeOutEffectProps,
|
|
53
|
+
} from './renderers/webgl/shaders/effects/FadeOutEffect.js';
|
|
54
|
+
import {
|
|
55
|
+
RadialGradientEffect,
|
|
56
|
+
type RadialGradientEffectProps,
|
|
57
|
+
} from './renderers/webgl/shaders/effects/RadialGradientEffect.js';
|
|
43
58
|
import type { WebGlCoreRenderer } from './renderers/webgl/WebGlCoreRenderer.js';
|
|
44
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
RadialProgressEffect,
|
|
61
|
+
type RadialProgressEffectProps,
|
|
62
|
+
} from './renderers/webgl/shaders/effects/RadialProgressEffect.js';
|
|
63
|
+
|
|
64
|
+
export type { FadeOutEffectProps };
|
|
65
|
+
export type { LinearGradientEffectProps };
|
|
66
|
+
export type { RadialGradientEffectProps };
|
|
67
|
+
export type { GrayscaleEffectProps };
|
|
68
|
+
export type { GlitchEffectProps };
|
|
69
|
+
export type { RadialProgressEffectProps };
|
|
45
70
|
|
|
46
71
|
export interface ShaderMap {
|
|
47
72
|
DefaultShader: typeof DefaultShader;
|
|
@@ -71,6 +96,14 @@ export interface EffectMap {
|
|
|
71
96
|
radialProgress: typeof RadialProgressEffect;
|
|
72
97
|
}
|
|
73
98
|
|
|
99
|
+
export type EffectProps =
|
|
100
|
+
| FadeOutEffectProps
|
|
101
|
+
| LinearGradientEffectProps
|
|
102
|
+
| RadialGradientEffectProps
|
|
103
|
+
| GrayscaleEffectProps
|
|
104
|
+
| GlitchEffectProps
|
|
105
|
+
| RadialProgressEffectProps;
|
|
106
|
+
|
|
74
107
|
export class CoreShaderManager {
|
|
75
108
|
protected shCache: Map<string, InstanceType<ShaderMap[keyof ShaderMap]>> =
|
|
76
109
|
new Map();
|
package/src/core/CoreTextNode.ts
CHANGED
|
@@ -32,7 +32,7 @@ import type {
|
|
|
32
32
|
NodeTextFailedPayload,
|
|
33
33
|
NodeTextLoadedPayload,
|
|
34
34
|
} from '../common/CommonTypes.js';
|
|
35
|
-
import type { Rect } from './lib/utils.js';
|
|
35
|
+
import type { Rect, RectWithValid } from './lib/utils.js';
|
|
36
36
|
import { assertTruthy } from '../utils.js';
|
|
37
37
|
|
|
38
38
|
export interface CoreTextNodeProps extends CoreNodeProps, TrProps {
|
|
@@ -318,7 +318,7 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
318
318
|
this.textRenderer.set.debug(this.trState, value);
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
override update(delta: number, parentClippingRect:
|
|
321
|
+
override update(delta: number, parentClippingRect: RectWithValid) {
|
|
322
322
|
super.update(delta, parentClippingRect);
|
|
323
323
|
|
|
324
324
|
assertTruthy(this.globalTransform);
|
package/src/core/Stage.ts
CHANGED
|
@@ -210,7 +210,7 @@ export class Stage extends EventEmitter {
|
|
|
210
210
|
|
|
211
211
|
// Update tree if needed
|
|
212
212
|
if (this.root.updateType !== 0) {
|
|
213
|
-
this.root.update(this.deltaTime);
|
|
213
|
+
this.root.update(this.deltaTime, this.root.clippingRect);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// test if we need to update the scene
|
|
@@ -37,6 +37,7 @@ export class CoreAnimation extends EventEmitter {
|
|
|
37
37
|
public propStartValues: Partial<INodeAnimatableProps> = {};
|
|
38
38
|
public restoreValues: Partial<INodeAnimatableProps> = {};
|
|
39
39
|
private progress = 0;
|
|
40
|
+
private delayFor = 0;
|
|
40
41
|
private timingFunction: (t: number) => number | undefined;
|
|
41
42
|
private propsList: Array<keyof INodeAnimatableProps>; //fixme - aint got not time for this
|
|
42
43
|
|
|
@@ -57,10 +58,12 @@ export class CoreAnimation extends EventEmitter {
|
|
|
57
58
|
if (settings.easing && typeof settings.easing === 'string') {
|
|
58
59
|
this.timingFunction = getTimingFunction(settings.easing);
|
|
59
60
|
}
|
|
61
|
+
this.delayFor = settings.delay || 0;
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
reset() {
|
|
63
65
|
this.progress = 0;
|
|
66
|
+
this.delayFor = this.settings.delay || 0;
|
|
64
67
|
this.update(0);
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -104,6 +107,11 @@ export class CoreAnimation extends EventEmitter {
|
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
if (this.delayFor > 0) {
|
|
111
|
+
this.delayFor -= dt;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
107
115
|
this.progress += dt / duration;
|
|
108
116
|
|
|
109
117
|
if (this.progress > 1) {
|
|
@@ -335,7 +335,34 @@ export class WebGlContextWrapper {
|
|
|
335
335
|
);
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* ```
|
|
340
|
+
* gl.compressedTexImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, data);
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @remarks
|
|
344
|
+
* **WebGL Difference**: Bind target is always `gl.TEXTURE_2D`
|
|
345
|
+
*/
|
|
338
346
|
|
|
347
|
+
compressedTexImage2D(
|
|
348
|
+
level: GLint,
|
|
349
|
+
internalformat: GLenum,
|
|
350
|
+
width: GLsizei,
|
|
351
|
+
height: GLsizei,
|
|
352
|
+
border: GLint,
|
|
353
|
+
data?: ArrayBufferView,
|
|
354
|
+
): void {
|
|
355
|
+
const { gl } = this;
|
|
356
|
+
gl.compressedTexImage2D(
|
|
357
|
+
gl.TEXTURE_2D,
|
|
358
|
+
level,
|
|
359
|
+
internalformat,
|
|
360
|
+
width,
|
|
361
|
+
height,
|
|
362
|
+
border,
|
|
363
|
+
data as ArrayBufferView,
|
|
364
|
+
);
|
|
365
|
+
}
|
|
339
366
|
/**
|
|
340
367
|
* ```
|
|
341
368
|
* gl.pixelStorei(pname, param);
|
|
@@ -0,0 +1,152 @@
|
|
|
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 TextureData } from '../textures/Texture.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tests if the given location is a compressed texture container
|
|
24
|
+
* @param url
|
|
25
|
+
* @remarks
|
|
26
|
+
* This function is used to determine if the given image url is a compressed
|
|
27
|
+
* and only supports the following extensions: .ktx and .pvr
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
export function isCompressedTextureContainer(url: string): boolean {
|
|
31
|
+
return /\.(ktx|pvr)$/.test(url);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Loads a compressed texture container
|
|
36
|
+
* @param url
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
export const loadCompressedTexture = async (
|
|
40
|
+
url: string,
|
|
41
|
+
): Promise<TextureData> => {
|
|
42
|
+
const response = await fetch(url);
|
|
43
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
44
|
+
|
|
45
|
+
if (url.indexOf('.ktx') !== -1) {
|
|
46
|
+
return loadKTXData(arrayBuffer);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return loadPVRData(arrayBuffer);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Loads a KTX texture container and returns the texture data
|
|
54
|
+
* @param buffer
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
57
|
+
const loadKTXData = async (buffer: ArrayBuffer): Promise<TextureData> => {
|
|
58
|
+
const view = new DataView(buffer);
|
|
59
|
+
const littleEndian = view.getUint32(12) === 16909060 ? true : false;
|
|
60
|
+
const mipmaps = [];
|
|
61
|
+
|
|
62
|
+
const data = {
|
|
63
|
+
glInternalFormat: view.getUint32(28, littleEndian),
|
|
64
|
+
pixelWidth: view.getUint32(36, littleEndian),
|
|
65
|
+
pixelHeight: view.getUint32(40, littleEndian),
|
|
66
|
+
numberOfMipmapLevels: view.getUint32(56, littleEndian),
|
|
67
|
+
bytesOfKeyValueData: view.getUint32(60, littleEndian),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
let offset = 64;
|
|
71
|
+
|
|
72
|
+
// Key Value Pairs of data start at byte offset 64
|
|
73
|
+
// But the only known kvp is the API version, so skipping parsing.
|
|
74
|
+
offset += data.bytesOfKeyValueData;
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < data.numberOfMipmapLevels; i++) {
|
|
77
|
+
const imageSize = view.getUint32(offset);
|
|
78
|
+
offset += 4;
|
|
79
|
+
|
|
80
|
+
mipmaps.push(view.buffer.slice(offset, imageSize));
|
|
81
|
+
offset += imageSize;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
data: {
|
|
86
|
+
glInternalFormat: data.glInternalFormat,
|
|
87
|
+
mipmaps,
|
|
88
|
+
width: data.pixelWidth || 0,
|
|
89
|
+
height: data.pixelHeight || 0,
|
|
90
|
+
type: 'ktx',
|
|
91
|
+
},
|
|
92
|
+
premultiplyAlpha: false,
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Loads a PVR texture container and returns the texture data
|
|
98
|
+
* @param buffer
|
|
99
|
+
* @returns
|
|
100
|
+
*/
|
|
101
|
+
const loadPVRData = async (buffer: ArrayBuffer): Promise<TextureData> => {
|
|
102
|
+
// pvr header length in 32 bits
|
|
103
|
+
const pvrHeaderLength = 13;
|
|
104
|
+
// for now only we only support: COMPRESSED_RGB_ETC1_WEBGL
|
|
105
|
+
const pvrFormatEtc1 = 0x8d64;
|
|
106
|
+
const pvrWidth = 7;
|
|
107
|
+
const pvrHeight = 6;
|
|
108
|
+
const pvrMipmapCount = 11;
|
|
109
|
+
const pvrMetadata = 12;
|
|
110
|
+
const arrayBuffer = buffer;
|
|
111
|
+
const header = new Int32Array(arrayBuffer, 0, pvrHeaderLength);
|
|
112
|
+
|
|
113
|
+
// @ts-expect-error Object possibly undefined
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
115
|
+
const dataOffset = header[pvrMetadata] + 52;
|
|
116
|
+
const pvrtcData = new Uint8Array(arrayBuffer, dataOffset);
|
|
117
|
+
const mipmaps = [];
|
|
118
|
+
const data = {
|
|
119
|
+
pixelWidth: header[pvrWidth],
|
|
120
|
+
pixelHeight: header[pvrHeight],
|
|
121
|
+
numberOfMipmapLevels: header[pvrMipmapCount] || 0,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
let offset = 0;
|
|
125
|
+
let width = data.pixelWidth || 0;
|
|
126
|
+
let height = data.pixelHeight || 0;
|
|
127
|
+
|
|
128
|
+
for (let i = 0; i < data.numberOfMipmapLevels; i++) {
|
|
129
|
+
const level = ((width + 3) >> 2) * ((height + 3) >> 2) * 8;
|
|
130
|
+
const view = new Uint8Array(
|
|
131
|
+
arrayBuffer,
|
|
132
|
+
pvrtcData.byteOffset + offset,
|
|
133
|
+
level,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
mipmaps.push(view);
|
|
137
|
+
offset += level;
|
|
138
|
+
width = width >> 1;
|
|
139
|
+
height = height >> 1;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
data: {
|
|
144
|
+
glInternalFormat: pvrFormatEtc1,
|
|
145
|
+
mipmaps: mipmaps,
|
|
146
|
+
width: data.pixelWidth || 0,
|
|
147
|
+
height: data.pixelHeight || 0,
|
|
148
|
+
type: 'pvr',
|
|
149
|
+
},
|
|
150
|
+
premultiplyAlpha: false,
|
|
151
|
+
};
|
|
152
|
+
};
|
package/src/core/lib/utils.ts
CHANGED
|
@@ -81,6 +81,10 @@ export interface Rect {
|
|
|
81
81
|
height: number;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
export interface RectWithValid extends Rect {
|
|
85
|
+
valid: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
export interface Bound {
|
|
85
89
|
x1: number;
|
|
86
90
|
y1: number;
|
|
@@ -132,12 +136,50 @@ export function intersectBound<T extends Bound = Bound>(
|
|
|
132
136
|
return createBound(0, 0, 0, 0, intersection);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
|
-
export function
|
|
139
|
+
export function boundsOverlap(a: Bound, b: Bound): boolean {
|
|
140
|
+
return a.x1 < b.x2 && a.x2 > b.x1 && a.y1 < b.y2 && a.y2 > b.y1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function convertBoundToRect(bound: Bound): Rect;
|
|
144
|
+
export function convertBoundToRect<T extends Rect = Rect>(
|
|
145
|
+
bound: Bound,
|
|
146
|
+
out: T,
|
|
147
|
+
): T;
|
|
148
|
+
export function convertBoundToRect(bound: Bound, out?: Rect): Rect {
|
|
149
|
+
if (out) {
|
|
150
|
+
out.x = bound.x1;
|
|
151
|
+
out.y = bound.y1;
|
|
152
|
+
out.width = bound.x2 - bound.x1;
|
|
153
|
+
out.height = bound.y2 - bound.y1;
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
x: bound.x1,
|
|
158
|
+
y: bound.y1,
|
|
159
|
+
width: bound.x2 - bound.x1,
|
|
160
|
+
height: bound.y2 - bound.y1,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function intersectRect(a: Rect, b: Rect): Rect;
|
|
165
|
+
export function intersectRect<T extends Rect = Rect>(
|
|
166
|
+
a: Rect,
|
|
167
|
+
b: Rect,
|
|
168
|
+
out: T,
|
|
169
|
+
): T;
|
|
170
|
+
export function intersectRect(a: Rect, b: Rect, out?: Rect): Rect {
|
|
136
171
|
const x = Math.max(a.x, b.x);
|
|
137
172
|
const y = Math.max(a.y, b.y);
|
|
138
173
|
const width = Math.min(a.x + a.width, b.x + b.width) - x;
|
|
139
174
|
const height = Math.min(a.y + a.height, b.y + b.height) - y;
|
|
140
175
|
if (width > 0 && height > 0) {
|
|
176
|
+
if (out) {
|
|
177
|
+
out.x = x;
|
|
178
|
+
out.y = y;
|
|
179
|
+
out.width = width;
|
|
180
|
+
out.height = height;
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
141
183
|
return {
|
|
142
184
|
x,
|
|
143
185
|
y,
|
|
@@ -145,6 +187,13 @@ export function intersectRect(a: Rect, b: Rect): Rect {
|
|
|
145
187
|
height,
|
|
146
188
|
};
|
|
147
189
|
}
|
|
190
|
+
if (out) {
|
|
191
|
+
out.x = 0;
|
|
192
|
+
out.y = 0;
|
|
193
|
+
out.width = 0;
|
|
194
|
+
out.height = 0;
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
148
197
|
return {
|
|
149
198
|
x: 0,
|
|
150
199
|
y: 0,
|
|
@@ -153,6 +202,24 @@ export function intersectRect(a: Rect, b: Rect): Rect {
|
|
|
153
202
|
};
|
|
154
203
|
}
|
|
155
204
|
|
|
205
|
+
export function copyRect(a: Rect): Rect;
|
|
206
|
+
export function copyRect<T extends Rect = Rect>(a: Rect, out: T): T;
|
|
207
|
+
export function copyRect(a: Rect, out?: Rect): Rect {
|
|
208
|
+
if (out) {
|
|
209
|
+
out.x = a.x;
|
|
210
|
+
out.y = a.y;
|
|
211
|
+
out.width = a.width;
|
|
212
|
+
out.height = a.height;
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
x: a.x,
|
|
217
|
+
y: a.y,
|
|
218
|
+
width: a.width,
|
|
219
|
+
height: a.height,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
156
223
|
export function compareRect(a: Rect | null, b: Rect | null): boolean {
|
|
157
224
|
if (a === b) {
|
|
158
225
|
return true;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import type { CoreShaderManager } from '../CoreShaderManager.js';
|
|
21
21
|
import type { TextureOptions } from '../CoreTextureManager.js';
|
|
22
22
|
import type { Stage } from '../Stage.js';
|
|
23
|
-
import type { Rect } from '../lib/utils.js';
|
|
23
|
+
import type { Rect, RectWithValid } from '../lib/utils.js';
|
|
24
24
|
import type { Texture } from '../textures/Texture.js';
|
|
25
25
|
import { CoreContextTexture } from './CoreContextTexture.js';
|
|
26
26
|
import type { CoreRenderOp } from './CoreRenderOp.js';
|
|
@@ -39,7 +39,7 @@ export interface QuadOptions {
|
|
|
39
39
|
shader: CoreShader | null;
|
|
40
40
|
shaderProps: Record<string, unknown> | null;
|
|
41
41
|
alpha: number;
|
|
42
|
-
clippingRect:
|
|
42
|
+
clippingRect: RectWithValid;
|
|
43
43
|
tx: number;
|
|
44
44
|
ty: number;
|
|
45
45
|
ta: number;
|
|
@@ -168,6 +168,26 @@ export class WebGlCoreCtxTexture extends CoreContextTexture {
|
|
|
168
168
|
glw.UNSIGNED_BYTE,
|
|
169
169
|
TRANSPARENT_TEXTURE_DATA,
|
|
170
170
|
);
|
|
171
|
+
} else if ('mipmaps' in textureData.data && textureData.data.mipmaps) {
|
|
172
|
+
const {
|
|
173
|
+
mipmaps,
|
|
174
|
+
width = 0,
|
|
175
|
+
height = 0,
|
|
176
|
+
type,
|
|
177
|
+
glInternalFormat,
|
|
178
|
+
} = textureData.data;
|
|
179
|
+
const view =
|
|
180
|
+
type === 'ktx'
|
|
181
|
+
? new DataView(mipmaps[0] ?? new ArrayBuffer(0))
|
|
182
|
+
: (mipmaps[0] as unknown as ArrayBufferView);
|
|
183
|
+
|
|
184
|
+
glw.bindTexture(this._nativeCtxTexture);
|
|
185
|
+
glw.compressedTexImage2D(0, glInternalFormat, width, height, 0, view);
|
|
186
|
+
|
|
187
|
+
glw.texParameteri(glw.TEXTURE_WRAP_S, glw.CLAMP_TO_EDGE);
|
|
188
|
+
glw.texParameteri(glw.TEXTURE_WRAP_T, glw.CLAMP_TO_EDGE);
|
|
189
|
+
glw.texParameteri(glw.TEXTURE_MAG_FILTER, glw.LINEAR);
|
|
190
|
+
glw.texParameteri(glw.TEXTURE_MIN_FILTER, glw.LINEAR);
|
|
171
191
|
} else {
|
|
172
192
|
console.error(
|
|
173
193
|
`WebGlCoreCtxTexture.onLoadRequest: Unexpected textureData returned`,
|
|
@@ -23,7 +23,7 @@ import type { WebGlCoreCtxTexture } from './WebGlCoreCtxTexture.js';
|
|
|
23
23
|
import type { WebGlCoreRendererOptions } from './WebGlCoreRenderer.js';
|
|
24
24
|
import type { BufferCollection } from './internal/BufferCollection.js';
|
|
25
25
|
import type { Dimensions } from '../../../common/CommonTypes.js';
|
|
26
|
-
import type { Rect } from '../../lib/utils.js';
|
|
26
|
+
import type { Rect, RectWithValid } from '../../lib/utils.js';
|
|
27
27
|
import type { WebGlContextWrapper } from '../../lib/WebGlContextWrapper.js';
|
|
28
28
|
|
|
29
29
|
const MAX_TEXTURES = 8; // TODO: get from gl
|
|
@@ -45,7 +45,7 @@ export class WebGlCoreRenderOp extends CoreRenderOp {
|
|
|
45
45
|
readonly shader: WebGlCoreShader,
|
|
46
46
|
readonly shaderProps: Record<string, unknown>,
|
|
47
47
|
readonly alpha: number,
|
|
48
|
-
readonly clippingRect:
|
|
48
|
+
readonly clippingRect: RectWithValid,
|
|
49
49
|
readonly dimensions: Dimensions,
|
|
50
50
|
readonly bufferIdx: number,
|
|
51
51
|
readonly zIndex: number,
|
|
@@ -82,7 +82,7 @@ export class WebGlCoreRenderOp extends CoreRenderOp {
|
|
|
82
82
|
const quadIdx = (this.bufferIdx / 24) * 6 * 2;
|
|
83
83
|
|
|
84
84
|
// Clipping
|
|
85
|
-
if (this.clippingRect) {
|
|
85
|
+
if (this.clippingRect.valid) {
|
|
86
86
|
const { x, y, width, height } = this.clippingRect;
|
|
87
87
|
const pixelRatio = options.pixelRatio;
|
|
88
88
|
const canvasHeight = options.canvas.height;
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
compareRect,
|
|
51
51
|
getNormalizedRgbaComponents,
|
|
52
52
|
type Rect,
|
|
53
|
+
type RectWithValid,
|
|
53
54
|
} from '../../lib/utils.js';
|
|
54
55
|
import type { Dimensions } from '../../../common/CommonTypes.js';
|
|
55
56
|
import { WebGlCoreShader } from './WebGlCoreShader.js';
|
|
@@ -115,6 +116,11 @@ export class WebGlCoreRenderer extends CoreRenderer {
|
|
|
115
116
|
this.txManager = options.txManager;
|
|
116
117
|
this.shManager = options.shManager;
|
|
117
118
|
this.defaultTexture = new ColorTexture(this.txManager);
|
|
119
|
+
// When the default texture is loaded, request a render in case the
|
|
120
|
+
// RAF is paused. Fixes: https://github.com/lightning-js/renderer/issues/123
|
|
121
|
+
this.defaultTexture.once('loaded', () => {
|
|
122
|
+
this.stage.requestRender();
|
|
123
|
+
});
|
|
118
124
|
|
|
119
125
|
const gl = createWebGLContext(canvas, options.contextSpy);
|
|
120
126
|
const glw = (this.glw = new WebGlContextWrapper(gl));
|
|
@@ -412,7 +418,7 @@ export class WebGlCoreRenderer extends CoreRenderer {
|
|
|
412
418
|
shaderProps: Record<string, unknown>,
|
|
413
419
|
alpha: number,
|
|
414
420
|
dimensions: Dimensions,
|
|
415
|
-
clippingRect:
|
|
421
|
+
clippingRect: RectWithValid,
|
|
416
422
|
bufferIdx: number,
|
|
417
423
|
) {
|
|
418
424
|
const curRenderOp = new WebGlCoreRenderOp(
|
|
@@ -47,6 +47,10 @@ export class SdfTrFontFace<
|
|
|
47
47
|
> extends TrFontFace {
|
|
48
48
|
public readonly type: FontTypeT;
|
|
49
49
|
public readonly texture: ImageTexture;
|
|
50
|
+
/**
|
|
51
|
+
* Height of the tallest character in the font including the whitespace above it
|
|
52
|
+
*/
|
|
53
|
+
public readonly maxCharHeight: number = 0;
|
|
50
54
|
public readonly data: SdfFontData | undefined;
|
|
51
55
|
public readonly shaper: FontShaper | undefined;
|
|
52
56
|
public readonly glyphMap: Map<number, SdfFontData['chars'][0]> = new Map();
|
|
@@ -93,12 +97,22 @@ export class SdfTrFontFace<
|
|
|
93
97
|
(this.data as SdfFontData) = await response.json();
|
|
94
98
|
// Add all the glyphs to the glyph map
|
|
95
99
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
100
|
+
let maxCharHeight = 0;
|
|
96
101
|
this.data!.chars.forEach((glyph) => {
|
|
97
102
|
this.glyphMap.set(glyph.id, glyph);
|
|
103
|
+
const charHeight = glyph.yoffset + glyph.height;
|
|
104
|
+
if (charHeight > maxCharHeight) {
|
|
105
|
+
maxCharHeight = charHeight;
|
|
106
|
+
}
|
|
98
107
|
});
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
109
|
+
(this.maxCharHeight as number) = maxCharHeight;
|
|
99
110
|
// We know `data` is defined here, because we just set it
|
|
100
111
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
101
|
-
(this.shaper as FontShaper) = new SdfFontShaper(
|
|
112
|
+
(this.shaper as FontShaper) = new SdfFontShaper(
|
|
113
|
+
this.data!,
|
|
114
|
+
this.glyphMap,
|
|
115
|
+
);
|
|
102
116
|
this.checkLoaded();
|
|
103
117
|
})
|
|
104
118
|
.catch(console.error);
|