From a21000d429ec25e9f037ad37d9b9c905ddbad142 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Fri, 22 Nov 2024 14:40:37 +0100 Subject: [PATCH 1/6] fix: added alternative to roundRect it not supported --- .../renderers/canvas/CanvasCoreRenderer.ts | 12 ++- .../canvas/internal/C2DShaderUtils.ts | 93 +++++++++++++++++++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/core/renderers/canvas/CanvasCoreRenderer.ts b/src/core/renderers/canvas/CanvasCoreRenderer.ts index d4c53ab6..d5bb799f 100644 --- a/src/core/renderers/canvas/CanvasCoreRenderer.ts +++ b/src/core/renderers/canvas/CanvasCoreRenderer.ts @@ -30,7 +30,12 @@ import { type QuadOptions, } from '../CoreRenderer.js'; import { CanvasCoreTexture } from './CanvasCoreTexture.js'; -import { getBorder, getRadius, strokeLine } from './internal/C2DShaderUtils.js'; +import { + getBorder, + getRadius, + roundRect, + strokeLine, +} from './internal/C2DShaderUtils.js'; import { formatRgba, parseColorRgba, @@ -166,7 +171,7 @@ export class CanvasCoreRenderer extends CoreRenderer { if (radius) { const path = new Path2D(); - path.roundRect(tx, ty, width, height, radius); + roundRect.call(path, tx, ty, width, height, radius); ctx.clip(path); } @@ -224,7 +229,8 @@ export class CanvasCoreRenderer extends CoreRenderer { ctx.strokeStyle = borderColor; ctx.globalAlpha = alpha; if (radius) { - ctx.roundRect( + roundRect.call( + ctx, tx + borderInnerWidth, ty + borderInnerWidth, width - borderWidth, diff --git a/src/core/renderers/canvas/internal/C2DShaderUtils.ts b/src/core/renderers/canvas/internal/C2DShaderUtils.ts index 52fb7586..85446dda 100644 --- a/src/core/renderers/canvas/internal/C2DShaderUtils.ts +++ b/src/core/renderers/canvas/internal/C2DShaderUtils.ts @@ -84,6 +84,99 @@ export function getBorder( return undefined; } +export function roundRect( + this: CanvasRenderingContext2D | Path2D, + x: number, + y: number, + width: number, + height: number, + radius: number | DOMPointInit | (number | DOMPointInit)[], +) { + const context = Object.getPrototypeOf(this) as Path2D; + if (!context.roundRect) { + const fixOverlappingCorners = (radii: { + topLeft: number; + topRight: number; + bottomRight: number; + bottomLeft: number; + }) => { + const maxRadius = Math.min(width / 2, height / 2); + const totalHorizontal = + radii.topLeft + radii.topRight + radii.bottomRight + radii.bottomLeft; + + if (totalHorizontal > width || totalHorizontal > height) { + const scale = + maxRadius / + Math.max( + radii.topLeft, + radii.topRight, + radii.bottomRight, + radii.bottomLeft, + ); + radii.topLeft *= scale; + radii.topRight *= scale; + radii.bottomRight *= scale; + radii.bottomLeft *= scale; + } + }; + const radii = + typeof radius === 'number' + ? { + topLeft: radius, + topRight: radius, + bottomRight: radius, + bottomLeft: radius, + } + : { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0, ...radius }; + + fixOverlappingCorners(radii); + + this.moveTo(x + radii.topLeft, y); + this.lineTo(x + width - radii.topRight, y); + this.ellipse( + x + width - radii.topRight, + y + radii.topRight, + radii.topRight, + radii.topRight, + 0, + 1.5 * Math.PI, + 2 * Math.PI, + ); + this.lineTo(x + width, y + height - radii.bottomRight); + this.ellipse( + x + width - radii.bottomRight, + y + height - radii.bottomRight, + radii.bottomRight, + radii.bottomRight, + 0, + 0, + 0.5 * Math.PI, + ); + this.lineTo(x + radii.bottomLeft, y + height); + this.ellipse( + x + radii.bottomLeft, + y + height - radii.bottomLeft, + radii.bottomLeft, + radii.bottomLeft, + 0, + 0.5 * Math.PI, + Math.PI, + ); + this.lineTo(x, y + radii.topLeft); + this.ellipse( + x + radii.topLeft, + y + radii.topLeft, + radii.topLeft, + radii.topLeft, + 0, + Math.PI, + 1.5 * Math.PI, + ); + } else { + this.roundRect(x, y, width, height, radius); + } +} + export function strokeLine( ctx: CanvasRenderingContext2D, x: number, From 3830d5932e386c2ca6473bfba8249db208b8f1b7 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Fri, 22 Nov 2024 14:41:36 +0100 Subject: [PATCH 2/6] fix: added fallback if createImageBitmap(image, options) is not supported --- src/core/textures/ImageTexture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/textures/ImageTexture.ts b/src/core/textures/ImageTexture.ts index 24efd7f6..74f30216 100644 --- a/src/core/textures/ImageTexture.ts +++ b/src/core/textures/ImageTexture.ts @@ -166,7 +166,7 @@ export class ImageTexture extends Texture { premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none', colorSpaceConversion: 'none', imageOrientation: 'none', - }), + }).catch(() => createImageBitmap(blob)), premultiplyAlpha: hasAlphaChannel, }; } else { From 7c509712da1c6bd2b673adab1bdabf619d703022 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Fri, 22 Nov 2024 16:01:33 +0100 Subject: [PATCH 3/6] fix: createImageBitmap without (image, options) signature --- src/core/CoreTextureManager.ts | 29 ++++++++++++++++++++++++----- src/core/textures/ImageTexture.ts | 27 ++++++++++++++++----------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/core/CoreTextureManager.ts b/src/core/CoreTextureManager.ts index 8934e1ed..cc671cab 100644 --- a/src/core/CoreTextureManager.ts +++ b/src/core/CoreTextureManager.ts @@ -156,6 +156,7 @@ export class CoreTextureManager { imageWorkerManager: ImageWorkerManager | null = null; hasCreateImageBitmap = !!self.createImageBitmap; + createImageBitmapNotSupportsOptions = false; hasWorker = !!self.Worker; /** * Renderer that this texture manager is associated with @@ -183,11 +184,7 @@ export class CoreTextureManager { this.imageWorkerManager = new ImageWorkerManager(numImageWorkers); } - if (!this.hasCreateImageBitmap) { - console.warn( - '[Lightning] createImageBitmap is not supported on this browser. ImageTexture will be slower.', - ); - } + this.checkCompatibilities(); this.registerTextureType('ImageTexture', ImageTexture); this.registerTextureType('ColorTexture', ColorTexture); @@ -251,4 +248,26 @@ export class CoreTextureManager { keyCache.delete(cacheKey); } } + + checkCompatibilities() { + // check compatibility with createImageBitmap + if (!this.hasCreateImageBitmap) { + console.warn( + '[Lightning] createImageBitmap is not supported on this browser. ImageTexture will be slower.', + ); + } else { + self.createImageBitmap(new Blob(), {}).catch((e: unknown) => { + if ( + e instanceof Error && + e?.message === + "Failed to execute 'createImageBitmap' on 'Window': No function was found that matched the signature provided." + ) { + console.warn( + '[Lightning] createImageBitmap not supports (image, options) signature on this browser.', + ); + this.createImageBitmapNotSupportsOptions = true; + } + }); + } + } } diff --git a/src/core/textures/ImageTexture.ts b/src/core/textures/ImageTexture.ts index 74f30216..c13abec9 100644 --- a/src/core/textures/ImageTexture.ts +++ b/src/core/textures/ImageTexture.ts @@ -150,23 +150,28 @@ export class ImageTexture extends Texture { const hasAlphaChannel = premultiplyAlpha ?? this.hasAlphaChannel(blob.type); + let data; + if (sw !== null && sh !== null) { - return { - data: await createImageBitmap(blob, sx ?? 0, sy ?? 0, sw, sh, { - premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none', - colorSpaceConversion: 'none', - imageOrientation: 'none', - }), - premultiplyAlpha: hasAlphaChannel, - }; + data = await createImageBitmap(blob, sx ?? 0, sy ?? 0, sw, sh, { + premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none', + colorSpaceConversion: 'none', + imageOrientation: 'none', + }); } - return { - data: await createImageBitmap(blob, { + if (this.txManager.createImageBitmapNotSupportsOptions) { + data = await createImageBitmap(blob); + } else { + data = await createImageBitmap(blob, { premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none', colorSpaceConversion: 'none', imageOrientation: 'none', - }).catch(() => createImageBitmap(blob)), + }).catch(() => createImageBitmap(blob)); + } + + return { + data: data, premultiplyAlpha: hasAlphaChannel, }; } else { From 25fccdcf5674fed095aba3a0d6d093a563b4ff45 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Fri, 22 Nov 2024 16:40:12 +0100 Subject: [PATCH 4/6] fix: create shader error message --- src/core/lib/WebGlContextWrapper.ts | 16 ++++++++++++++++ src/core/renderers/webgl/WebGlCoreShader.ts | 8 +++++++- src/core/renderers/webgl/internal/ShaderUtils.ts | 12 +++++++++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/core/lib/WebGlContextWrapper.ts b/src/core/lib/WebGlContextWrapper.ts index f87f7e3c..dd1e00e5 100644 --- a/src/core/lib/WebGlContextWrapper.ts +++ b/src/core/lib/WebGlContextWrapper.ts @@ -84,6 +84,8 @@ export class WebGlContextWrapper { public readonly LINK_STATUS; public readonly DYNAMIC_DRAW; public readonly COLOR_ATTACHMENT0; + public readonly INVALID_ENUM: number; + public readonly INVALID_OPERATION: number; //#endregion WebGL Enums constructor(private gl: WebGLRenderingContext | WebGL2RenderingContext) { @@ -175,6 +177,8 @@ export class WebGlContextWrapper { this.LINK_STATUS = gl.LINK_STATUS; this.DYNAMIC_DRAW = gl.DYNAMIC_DRAW; this.COLOR_ATTACHMENT0 = gl.COLOR_ATTACHMENT0; + this.INVALID_ENUM = gl.INVALID_ENUM; + this.INVALID_OPERATION = gl.INVALID_OPERATION; } /** * Returns true if the WebGL context is WebGL2 @@ -1020,6 +1024,18 @@ export class WebGlContextWrapper { return gl.getExtension(name); } + /** + * ``` + * gl.getError(type); + * ``` + * + * @returns + */ + getError() { + const { gl } = this; + return gl.getError(); + } + /** * ``` * gl.createVertexArray(); diff --git a/src/core/renderers/webgl/WebGlCoreShader.ts b/src/core/renderers/webgl/WebGlCoreShader.ts index 323f1dd1..0345833d 100644 --- a/src/core/renderers/webgl/WebGlCoreShader.ts +++ b/src/core/renderers/webgl/WebGlCoreShader.ts @@ -142,9 +142,15 @@ export abstract class WebGlCoreShader extends CoreShader { glw.FRAGMENT_SHADER, fragmentSource, ); + if (!vertexShader || !fragmentShader) { throw new Error( - `Unable to create shader type: ${glw.FRAGMENT_SHADER}. Source: ${fragmentSource}`, + `Unable to create the following shader(s): ${[ + !vertexShader && 'VERTEX_SHADER', + !fragmentShader && 'FRAGMENT_SHADER', + ] + .filter(Boolean) + .join(' and ')}`, ); } diff --git a/src/core/renderers/webgl/internal/ShaderUtils.ts b/src/core/renderers/webgl/internal/ShaderUtils.ts index 1c682bca..09181b22 100644 --- a/src/core/renderers/webgl/internal/ShaderUtils.ts +++ b/src/core/renderers/webgl/internal/ShaderUtils.ts @@ -100,8 +100,14 @@ export function createShader( ) { const shader = glw.createShader(type); if (!shader) { - throw new Error(`Unable to create shader type: ${type}. Source: ${source}`); + const glError = glw.getError(); + throw new Error( + `Unable to create the shader: ${ + type === glw.VERTEX_SHADER ? 'VERTEX_SHADER' : 'FRAGMENT_SHADER' + }.${glError ? ` WebGlContext Error: ${glError}` : ''}`, + ); } + glw.shaderSource(shader, source); glw.compileShader(shader); const success = !!glw.getShaderParameter(shader, glw.COMPILE_STATUS); @@ -109,7 +115,7 @@ export function createShader( return shader; } - console.log(glw.getShaderInfoLog(shader)); + console.error(glw.getShaderInfoLog(shader)); glw.deleteShader(shader); } @@ -131,7 +137,7 @@ export function createProgram( return program; } - console.log(glw.getProgramInfoLog(program)); + console.warn(glw.getProgramInfoLog(program)); glw.deleteProgram(program); return undefined; } From 598dd80b96d4da22cf5215f9c97ac6ea93fc41df Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Fri, 22 Nov 2024 16:42:50 +0100 Subject: [PATCH 5/6] fix: typo --- src/core/CoreTextureManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/CoreTextureManager.ts b/src/core/CoreTextureManager.ts index cc671cab..8006e261 100644 --- a/src/core/CoreTextureManager.ts +++ b/src/core/CoreTextureManager.ts @@ -259,7 +259,7 @@ export class CoreTextureManager { self.createImageBitmap(new Blob(), {}).catch((e: unknown) => { if ( e instanceof Error && - e?.message === + e.message === "Failed to execute 'createImageBitmap' on 'Window': No function was found that matched the signature provided." ) { console.warn( From 7483a90c9a1d58fa075b22423c6ccdb2680218cd Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Mon, 25 Nov 2024 10:39:13 +0100 Subject: [PATCH 6/6] fix: removed unused vars --- src/core/textures/ImageTexture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/textures/ImageTexture.ts b/src/core/textures/ImageTexture.ts index c13abec9..b382793a 100644 --- a/src/core/textures/ImageTexture.ts +++ b/src/core/textures/ImageTexture.ts @@ -133,7 +133,7 @@ export class ImageTexture extends Texture { } async loadImage(src: string) { - const { premultiplyAlpha, sx, sy, sw, sh, width, height } = this.props; + const { premultiplyAlpha, sx, sy, sw, sh } = this.props; if (this.txManager.imageWorkerManager !== null) { return await this.txManager.imageWorkerManager.getImage(