Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,13 @@ npm test
# Build API Documentation (builds into ./docs folder)
npm run typedoc

# Launch test examples (includes Build Renderer (watch mode))
# Launch test examples in dev mode (includes Build Renderer (watch mode))
npm start

# Launch test examples in production mode
# IMPORTANT: To run test examples on embedded devices that use older browser versions
# you MUST run the examples in this mode.
npm run prod
```

## Test Examples
Expand Down
2 changes: 1 addition & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"start": "concurrently -c \"auto\" \"npm:watch-renderer\" \"npm:dev\"",
"dev": "vite --open",
"build": "vite build",
"preview": "vite preview",
"preview": "vite preview --host",
"watch-renderer": "cd .. && npm run watch"
},
"author": "Frank Weindel",
Expand Down
23 changes: 23 additions & 0 deletions examples/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ import { defineConfig } from 'vite';
import * as path from 'path';
import { importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url';

/**
* Targeting ES2019 gets us at least to WPE 2.28
*
* Despite setting the target in 3 different places in the Vite config below
* this does not seem to have an effect on the output when running Vite in
* development mode (`npm start`). In order to properly test on embedded devices
* that require the set target, you must run `npm run build` and then serve the
* content via `npm run preview -- --host`.
*
* See the following for any updates on this:
* https://github.com/vitejs/vite/issues/13756#issuecomment-1751085158
*/
const target = 'es2019';

/**
* Vite Config
*/
Expand All @@ -30,7 +44,16 @@ export default defineConfig(({ command, mode, ssrBuild }) => {
worker: {
format: 'es',
},
esbuild: {
target,
},
optimizeDeps: {
esbuildOptions: {
target,
},
},
build: {
target,
minify: false,
sourcemap: true,
outDir: path.resolve(__dirname, 'dist'),
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"scripts": {
"start": "cd examples && npm start",
"prod": "npm run build && cd examples && npm run build && npm run preview",
"build": "tsc --build",
"watch": "tsc --build --watch",
"test": "vitest",
Expand Down
4 changes: 2 additions & 2 deletions src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export class WebGlCoreCtxSubTexture extends WebGlCoreCtxTexture {
override async onLoadRequest(): Promise<Dimensions> {
const props = await (this.textureSource as SubTexture).getTextureData();
return {
width: props.width || 0,
height: props.height || 0,
width: props.data?.width || 0,
height: props.data?.height || 0,
};
}
}
24 changes: 13 additions & 11 deletions src/core/renderers/webgl/WebGlCoreCtxTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,25 +133,27 @@ export class WebGlCoreCtxTexture extends CoreContextTexture {
assertTruthy(this._nativeCtxTexture);
// If textureData is null, the texture is empty (0, 0) and we don't need to
// upload any data to the GPU.
if (textureData instanceof ImageBitmap) {
width = textureData.width;
height = textureData.height;
if (
textureData.data instanceof ImageBitmap ||
textureData.data instanceof ImageData
) {
const data = textureData.data;
width = data.width;
height = data.height;
gl.bindTexture(gl.TEXTURE_2D, this._nativeCtxTexture);

gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
textureData,
gl.pixelStorei(
gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
!!textureData.premultiplyAlpha,
);

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);

// generate mipmaps for power-of-2 textures or in WebGL2RenderingContext
if (isWebGl2(gl) || (isPowerOfTwo(width) && isPowerOfTwo(height))) {
gl.generateMipmap(gl.TEXTURE_2D);
}
} else if (textureData === null) {
} else if (textureData.data === null) {
width = 0;
height = 0;
// Reset to a 1x1 transparent texture
Expand Down
4 changes: 2 additions & 2 deletions src/core/renderers/webgl/WebGlCoreShader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,13 @@ export abstract class WebGlCoreShader extends CoreShader {
const location = gl.getAttribLocation(this.program, attributeName);
if (location < 0) {
throw new Error(
`Vertex shader must have an attribute "${attributeName}"!`,
`${this.constructor.name}: Vertex shader must have an attribute "${attributeName}"!`,
);
}
const buffer = gl.createBuffer();
if (!buffer) {
throw new Error(
`Could not create buffer for attribute "${attributeName}"`,
`${this.constructor.name}: Could not create buffer for attribute "${attributeName}"`,
);
}

Expand Down
9 changes: 1 addition & 8 deletions src/core/renderers/webgl/shaders/RoundedRectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@ export class RoundedRectangle extends WebGlCoreShader {
constructor(renderer: WebGlCoreRenderer) {
super({
renderer,
attributes: [
'a_position',
'a_textureCoordinate',
'a_color',
'a_textureIndex',
],
attributes: ['a_position', 'a_textureCoordinate', 'a_color'],
uniforms: [
{ name: 'u_resolution', uniform: 'uniform2fv' },
{ name: 'u_pixelRatio', uniform: 'uniform1f' },
Expand Down Expand Up @@ -115,7 +110,6 @@ export class RoundedRectangle extends WebGlCoreShader {

varying vec4 v_color;
varying vec2 v_textureCoordinate;
varying float v_textureIndex;

void main() {
vec2 normalized = a_position * u_pixelRatio / u_resolution;
Expand All @@ -125,7 +119,6 @@ export class RoundedRectangle extends WebGlCoreShader {
// pass to fragment
v_color = a_color;
v_textureCoordinate = a_textureCoordinate;
v_textureIndex = a_textureIndex;

// flip y
gl_Position = vec4(clip_space * vec2(1.0, -1.0), 0, 1);
Expand Down
11 changes: 6 additions & 5 deletions src/core/textures/ColorTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import type { CoreTextureManager } from '../CoreTextureManager.js';
import { Texture } from './Texture.js';
import { Texture, type TextureData } from './Texture.js';

/**
* Properties of the {@link ColorTexture}
Expand Down Expand Up @@ -60,12 +60,13 @@ export class ColorTexture extends Texture {
this.props.color = color;
}

override async getTextureData(): Promise<ImageBitmap> {
override async getTextureData(): Promise<TextureData> {
const pixelData32 = new Uint32Array([this.color]);
const pixelData8 = new Uint8ClampedArray(pixelData32.buffer);
return await createImageBitmap(new ImageData(pixelData8, 1, 1), {
premultiplyAlpha: 'none',
});
return {
data: new ImageData(pixelData8, 1, 1),
premultiplyAlpha: true,
};
}

static override makeCacheKey(props: ColorTextureProps): string {
Expand Down
25 changes: 14 additions & 11 deletions src/core/textures/ImageTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,25 @@ export class ImageTexture extends Texture {
override async getTextureData(): Promise<TextureData> {
const { src, premultiplyAlpha } = this.props;
if (!src) {
return null;
return {
data: null,
};
}
if (src instanceof ImageData) {
return await createImageBitmap(src, {
premultiplyAlpha: premultiplyAlpha ? 'premultiply' : 'none',
colorSpaceConversion: 'none',
imageOrientation: 'none',
});
return {
data: src,
premultiplyAlpha,
};
}
const response = await fetch(src);
const blob = await response.blob();
return await createImageBitmap(blob, {
premultiplyAlpha: premultiplyAlpha ? 'premultiply' : 'none',
colorSpaceConversion: 'none',
imageOrientation: 'none',
});
return {
data: await createImageBitmap(blob, {
premultiplyAlpha: premultiplyAlpha ? 'premultiply' : 'none',
colorSpaceConversion: 'none',
imageOrientation: 'none',
}),
};
}

static override makeCacheKey(props: ImageTextureProps): string | false {
Expand Down
6 changes: 3 additions & 3 deletions src/core/textures/NoiseTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ export class NoiseTexture extends Texture {
pixelData8[i + 2] = v;
pixelData8[i + 3] = 255;
}
return await createImageBitmap(new ImageData(pixelData8, width, height), {
premultiplyAlpha: 'none',
});
return {
data: new ImageData(pixelData8, width, height),
};
}

static override makeCacheKey(props: NoiseTextureProps): string {
Expand Down
8 changes: 5 additions & 3 deletions src/core/textures/SubTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type {
} from '../../common/CommonTypes.js';
import type { TextureRef } from '../../main-api/RendererMain.js';
import type { CoreTextureManager } from '../CoreTextureManager.js';
import { Texture } from './Texture.js';
import { Texture, type TextureData } from './Texture.js';

/**
* Properties of the {@link SubTexture}
Expand Down Expand Up @@ -115,8 +115,10 @@ export class SubTexture extends Texture {
this.setState('failed', error);
};

override async getTextureData(): Promise<SubTextureProps> {
return this.props;
override async getTextureData(): Promise<TextureData> {
return {
data: this.props,
};
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
15 changes: 13 additions & 2 deletions src/core/textures/Texture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,20 @@ import type {
import { EventEmitter } from '../../common/EventEmitter.js';

/**
* Texture sources that are used to populate a CoreContextTexture
* TextureData that is used to populate a CoreContextTexture
*/
export type TextureData = ImageBitmap | SubTextureProps | null;
export interface TextureData {
/**
* The texture data
*/
data: ImageBitmap | ImageData | SubTextureProps | null;
/**
* Premultiply alpha when uploading texture data to the GPU
*
* @defaultValue `false`
*/
premultiplyAlpha?: boolean;
}

export type TextureState = 'loading' | 'loaded' | 'failed';

Expand Down