New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@lightningjs/renderer

Package Overview
Dependencies
Maintainers
0
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lightningjs/renderer - npm Package Compare versions

Comparing version 2.9.0-beta2 to 2.9.0-beta3

COPYING

3

dist/src/core/CoreNode.d.ts
import type { TextureOptions } from './CoreTextureManager.js';
import type { CoreRenderer } from './renderers/CoreRenderer.js';
import type { Stage } from './Stage.js';
import type { Texture } from './textures/Texture.js';
import { type Texture } from './textures/Texture.js';
import type { Dimensions } from '../common/CommonTypes.js';

@@ -660,2 +660,3 @@ import { EventEmitter } from '../common/EventEmitter.js';

loadTexture(): void;
createDefaultTexture(): void;
unloadTexture(): void;

@@ -662,0 +663,0 @@ autosizeNode(dimensions: Dimensions): void;

@@ -20,2 +20,3 @@ /*

import { assertTruthy, getNewId, mergeColorAlphaPremultiplied, } from '../utils.js';
import {} from './textures/Texture.js';
import { EventEmitter } from '../common/EventEmitter.js';

@@ -210,2 +211,3 @@ import { copyRect, intersectRect, createBound, boundInsideBound, boundLargeThanBound, createPreloadBounds, } from './lib/utils.js';

UpdateType.RenderState);
this.createDefaultTexture();
}

@@ -222,6 +224,2 @@ //#region Textures

texture.preventCleanup = this.props.preventCleanup;
// Preload texture if required
if (this.textureOptions.preload) {
texture.ctxTexture.load();
}
texture.on('loaded', this.onTextureLoaded);

@@ -252,2 +250,11 @@ texture.on('failed', this.onTextureFailed);

}
createDefaultTexture() {
// load default texture if no texture is set
if (this.stage.defaultTexture !== null &&
this.props.src === null &&
this.props.texture === null &&
this.props.rtt === false) {
this.texture = this.stage.defaultTexture;
}
}
unloadTexture() {

@@ -269,2 +276,3 @@ if (this.texture !== null) {

this.autosizeNode(dimensions);
this.setUpdateType(UpdateType.IsRenderable);
// Texture was loaded. In case the RAF loop has already stopped, we request

@@ -277,6 +285,9 @@ // a render to ensure the texture is rendered.

}
this.emit('loaded', {
type: 'texture',
dimensions,
});
// ignore 1x1 pixel textures
if (dimensions.width > 1 && dimensions.height > 1) {
this.emit('loaded', {
type: 'texture',
dimensions,
});
}
// Trigger a local update if the texture is loaded and the resizeMode is 'contain'

@@ -288,2 +299,3 @@ if (this.props.textureOptions?.resizeMode?.type === 'contain') {

onTextureFailed = (_, error) => {
this.setUpdateType(UpdateType.IsRenderable);
// If parent has a render texture, flag that we need to update

@@ -299,2 +311,3 @@ if (this.parentHasRenderTexture) {

onTextureFreed = () => {
this.setUpdateType(UpdateType.IsRenderable);
// If parent has a render texture, flag that we need to update

@@ -560,4 +573,7 @@ if (this.parentHasRenderTexture) {

hasRenderableProperties() {
if (this.props.texture) {
return true;
if (this.texture !== null) {
if (this.texture.state === 'loaded') {
return true;
}
return false;
}

@@ -570,3 +586,3 @@ if (!this.props.width || !this.props.height) {

}
if (this.props.clipping) {
if (this.props.clipping === true) {
return true;

@@ -579,26 +595,12 @@ }

// Maybe add a forceRender prop for nodes that should always render.
if (this.props.colorTop !== 0) {
if (this.props.colorTop !== 0 ||
this.props.colorBottom !== 0 ||
this.props.colorLeft !== 0 ||
this.props.colorRight !== 0 ||
this.props.colorTl !== 0 ||
this.props.colorTr !== 0 ||
this.props.colorBl !== 0 ||
this.props.colorBr !== 0) {
return true;
}
if (this.props.colorBottom !== 0) {
return true;
}
if (this.props.colorLeft !== 0) {
return true;
}
if (this.props.colorRight !== 0) {
return true;
}
if (this.props.colorTl !== 0) {
return true;
}
if (this.props.colorTr !== 0) {
return true;
}
if (this.props.colorBl !== 0) {
return true;
}
if (this.props.colorBr !== 0) {
return true;
}
return false;

@@ -705,2 +707,9 @@ }

}
// If the texture is not loaded and the node is renderable, load the texture
// this only needs to happen once or until the texture is no longer loaded
if (this.texture !== null &&
this.texture.state === 'freed' &&
this.renderState > CoreNodeRenderState.OutOfBounds) {
this.stage.txManager.loadTexture(this.texture);
}
if (this.isRenderable !== newIsRenderable) {

@@ -828,2 +837,3 @@ this.isRenderable = newIsRenderable;

assertTruthy(this.renderCoords);
assertTruthy(this.texture);
// add to list of renderables to be sorted before rendering

@@ -902,7 +912,6 @@ renderer.addQuad({

if (this.props.rtt) {
this.texture = this.stage.txManager.loadTexture('RenderTexture', {
this.texture = this.stage.txManager.createTexture('RenderTexture', {
width: this.width,
height: this.height,
});
this.textureOptions.preload = true;
this.setUpdateType(UpdateType.RenderTexture);

@@ -920,7 +929,6 @@ }

if (this.props.rtt) {
this.texture = this.stage.txManager.loadTexture('RenderTexture', {
this.texture = this.stage.txManager.createTexture('RenderTexture', {
width: this.width,
height: this.height,
});
this.textureOptions.preload = true;
this.setUpdateType(UpdateType.RenderTexture);

@@ -1213,7 +1221,8 @@ }

initRenderTexture() {
this.texture = this.stage.txManager.loadTexture('RenderTexture', {
this.texture = this.stage.txManager.createTexture('RenderTexture', {
width: this.width,
height: this.height,
});
this.textureOptions.preload = true;
// call load immediately to ensure the texture is created
this.stage.txManager.loadTexture(this.texture, true);
this.stage.renderer?.renderToTexture(this); // Only this RTT node

@@ -1282,3 +1291,3 @@ }

}
this.texture = this.stage.txManager.loadTexture('ImageTexture', {
this.texture = this.stage.txManager.createTexture('ImageTexture', {
src: imageUrl,

@@ -1365,6 +1374,10 @@ width: this.props.width,

this.props.texture = value;
if (value) {
if (value !== null) {
value.setRenderableOwner(this, this.isRenderable);
this.loadTexture();
}
else {
// If the texture is null, create a default texture
this.createDefaultTexture();
}
this.setUpdateType(UpdateType.IsRenderable);

@@ -1391,5 +1404,3 @@ }

const animation = new CoreAnimation(this, props, settings);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
const controller = new CoreAnimationController(this.stage.animationManager, animation);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return controller;

@@ -1396,0 +1407,0 @@ }

@@ -84,15 +84,2 @@ import { ImageWorkerManager } from './lib/ImageWorker.js';

/**
* Preload the texture immediately even if it's not being rendered to the
* screen.
*
* @remarks
* This allows the texture to be used immediately without any delay when it
* is first needed for rendering. Otherwise the loading process will start
* when the texture is first rendered, which may cause a delay in that texture
* being shown properly.
*
* @defaultValue `false`
*/
preload?: boolean;
/**
* Flip the texture horizontally when rendering

@@ -131,2 +118,6 @@ *

txConstructors: Partial<TextureMap>;
private downloadTextureSourceQueue;
private priorityQueue;
private uploadTextureQueue;
private initialized;
imageWorkerManager: ImageWorkerManager | null;

@@ -161,5 +152,53 @@ hasCreateImageBitmap: boolean;

registerTextureType<Type extends keyof TextureMap>(textureType: Type, textureClass: TextureMap[Type]): void;
loadTexture<Type extends keyof TextureMap>(textureType: Type, props: ExtractProps<TextureMap[Type]>): InstanceType<TextureMap[Type]>;
private initTextureToCache;
/**
* Enqueue a texture for downloading its source image.
*/
enqueueDownloadTextureSource(texture: Texture): void;
/**
* Enqueue a texture for uploading to the GPU.
*
* @param texture - The texture to upload
*/
enqueueUploadTexture(texture: Texture): void;
/**
* Create a texture
*
* @param textureType - The type of texture to create
* @param props - The properties to use for the texture
*/
createTexture<Type extends keyof TextureMap>(textureType: Type, props: ExtractProps<TextureMap[Type]>): InstanceType<TextureMap[Type]>;
/**
* Override loadTexture to use the batched approach.
*
* @param texture - The texture to load
* @param immediate - Whether to prioritize the texture for immediate loading
*/
loadTexture(texture: Texture, priority?: boolean): void;
/**
* Upload a texture to the GPU
*
* @param texture Texture to upload
*/
uploadTexture(texture: Texture): void;
/**
* Process a limited number of downloads and uploads.
*
* @param maxItems - The maximum number of items to process
*/
processSome(maxItems?: number): void;
hasUpdates(): boolean;
/**
* Initialize a texture to the cache
*
* @param texture Texture to cache
* @param cacheKey Cache key for the texture
*/
initTextureToCache(texture: Texture, cacheKey: string): void;
/**
* Get a texture from the cache
*
* @param cacheKey
*/
getTextureFromCache(cacheKey: string): Texture | undefined;
/**
* Remove a texture from the cache

@@ -173,2 +212,9 @@ *

removeTextureFromCache(texture: Texture): void;
/**
* Resolve a parent texture from the cache or fallback to the provided texture.
*
* @param texture - The provided texture to resolve.
* @returns The cached or provided texture.
*/
resolveParentTexture(texture: ImageTexture): Texture;
}

@@ -39,2 +39,6 @@ /*

txConstructors = {};
downloadTextureSourceQueue = [];
priorityQueue = [];
uploadTextureQueue = [];
initialized = false;
imageWorkerManager = null;

@@ -84,2 +88,3 @@ hasCreateImageBitmap = !!self.createImageBitmap;

}
this.initialized = true;
this.emit('initialized');

@@ -90,2 +95,3 @@ })

// initialized without image worker manager and createImageBitmap
this.initialized = true;
this.emit('initialized');

@@ -101,28 +107,10 @@ });

// Test if createImageBitmap is supported using a simple 1x1 PNG image
// prettier-ignore (this is a binary PNG image)
// prettier-ignore
const pngBinaryData = new Uint8Array([
0x89,
0x50,
0x4e,
0x47,
0x0d,
0x0a,
0x1a,
0x0a, // PNG signature
0x00,
0x00,
0x00,
0x0d, // IHDR chunk length
0x49,
0x48,
0x44,
0x52, // "IHDR" chunk type
0x00,
0x00,
0x00,
0x01, // Width: 1
0x00,
0x00,
0x00,
0x01, // Height: 1
0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a, // PNG signature
0x00, 0x00, 0x00, 0x0d, // IHDR chunk length
0x49, 0x48, 0x44, 0x52, // "IHDR" chunk type
0x00, 0x00, 0x00, 0x01, // Width: 1
0x00, 0x00, 0x00, 0x01, // Height: 1
0x01, // Bit depth: 1

@@ -133,68 +121,20 @@ 0x03, // Color type: Indexed

0x00, // Interlace method: None
0x25,
0xdb,
0x56,
0xca, // CRC for IHDR
0x00,
0x00,
0x00,
0x03, // PLTE chunk length
0x50,
0x4c,
0x54,
0x45, // "PLTE" chunk type
0x00,
0x00,
0x00, // Palette entry: Black
0xa7,
0x7a,
0x3d,
0xda, // CRC for PLTE
0x00,
0x00,
0x00,
0x01, // tRNS chunk length
0x74,
0x52,
0x4e,
0x53, // "tRNS" chunk type
0x25, 0xdb, 0x56, 0xca, // CRC for IHDR
0x00, 0x00, 0x00, 0x03, // PLTE chunk length
0x50, 0x4c, 0x54, 0x45, // "PLTE" chunk type
0x00, 0x00, 0x00, // Palette entry: Black
0xa7, 0x7a, 0x3d, 0xda, // CRC for PLTE
0x00, 0x00, 0x00, 0x01, // tRNS chunk length
0x74, 0x52, 0x4e, 0x53, // "tRNS" chunk type
0x00, // Transparency for black: Fully transparent
0x40,
0xe6,
0xd8,
0x66, // CRC for tRNS
0x00,
0x00,
0x00,
0x0a, // IDAT chunk length
0x49,
0x44,
0x41,
0x54, // "IDAT" chunk type
0x08,
0xd7, // Deflate header
0x63,
0x60,
0x00,
0x00,
0x00,
0x02,
0x00,
0x01, // Zlib-compressed data
0xe2,
0x21,
0xbc,
0x33, // CRC for IDAT
0x00,
0x00,
0x00,
0x00, // IEND chunk length
0x49,
0x45,
0x4e,
0x44, // "IEND" chunk type
0xae,
0x42,
0x60,
0x82, // CRC for IEND
0x40, 0xe6, 0xd8, 0x66, // CRC for tRNS
0x00, 0x00, 0x00, 0x0a, // IDAT chunk length
0x49, 0x44, 0x41, 0x54, // "IDAT" chunk type
0x08, 0xd7, // Deflate header
0x63, 0x60, 0x00, 0x00,
0x00, 0x02, 0x00, 0x01, // Zlib-compressed data
0xe2, 0x21, 0xbc, 0x33, // CRC for IDAT
0x00, 0x00, 0x00, 0x00, // IEND chunk length
0x49, 0x45, 0x4e, 0x44, // "IEND" chunk type
0xae, 0x42, 0x60, 0x82, // CRC for IEND
]);

@@ -237,3 +177,27 @@ const support = {

}
loadTexture(textureType, props) {
/**
* Enqueue a texture for downloading its source image.
*/
enqueueDownloadTextureSource(texture) {
if (!this.downloadTextureSourceQueue.includes(texture)) {
this.downloadTextureSourceQueue.push(texture);
}
}
/**
* Enqueue a texture for uploading to the GPU.
*
* @param texture - The texture to upload
*/
enqueueUploadTexture(texture) {
if (this.uploadTextureQueue.includes(texture) === false) {
this.uploadTextureQueue.push(texture);
}
}
/**
* Create a texture
*
* @param textureType - The type of texture to create
* @param props - The properties to use for the texture
*/
createTexture(textureType, props) {
let texture;

@@ -244,19 +208,106 @@ const TextureClass = this.txConstructors[textureType];

}
if (!texture) {
const cacheKey = TextureClass.makeCacheKey(props);
if (cacheKey && this.keyCache.has(cacheKey)) {
// console.log('Getting texture by cache key', cacheKey);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
texture = this.keyCache.get(cacheKey);
const cacheKey = TextureClass.makeCacheKey(props);
if (cacheKey && this.keyCache.has(cacheKey)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
texture = this.keyCache.get(cacheKey);
}
else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
texture = new TextureClass(this, props);
if (cacheKey) {
this.initTextureToCache(texture, cacheKey);
}
else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
texture = new TextureClass(this, props);
if (cacheKey) {
this.initTextureToCache(texture, cacheKey);
}
}
}
return texture;
}
/**
* Override loadTexture to use the batched approach.
*
* @param texture - The texture to load
* @param immediate - Whether to prioritize the texture for immediate loading
*/
loadTexture(texture, priority) {
if (texture.state === 'loaded' || texture.state === 'loading') {
return;
}
texture.setSourceState('loading');
texture.setCoreCtxState('loading');
// if we're not initialized, just queue the texture into the priority queue
if (this.initialized === false) {
this.priorityQueue.push(texture);
return;
}
// prioritize the texture for immediate loading
if (priority === true) {
texture
.getTextureData()
.then(() => {
this.uploadTexture(texture);
})
.catch((err) => {
console.error(err);
});
}
// enqueue the texture for download and upload
this.enqueueDownloadTextureSource(texture);
}
/**
* Upload a texture to the GPU
*
* @param texture Texture to upload
*/
uploadTexture(texture) {
const coreContext = texture.loadCtxTexture();
coreContext.load();
}
/**
* Process a limited number of downloads and uploads.
*
* @param maxItems - The maximum number of items to process
*/
processSome(maxItems = 0) {
if (this.initialized === false) {
return;
}
let itemsProcessed = 0;
// Process priority queue
while (this.priorityQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const texture = this.priorityQueue.shift();
texture.getTextureData().then(() => {
this.uploadTexture(texture);
});
itemsProcessed++;
}
// Process uploads
while (this.uploadTextureQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.uploadTexture(this.uploadTextureQueue.shift());
itemsProcessed++;
}
// Process downloads
while (this.downloadTextureSourceQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const texture = this.downloadTextureSourceQueue.shift();
queueMicrotask(() => {
texture.getTextureData().then(() => {
this.enqueueUploadTexture(texture);
});
});
itemsProcessed++;
}
}
hasUpdates() {
return (this.downloadTextureSourceQueue.length > 0 ||
this.uploadTextureQueue.length > 0);
}
/**
* Initialize a texture to the cache
*
* @param texture Texture to cache
* @param cacheKey Cache key for the texture
*/
initTextureToCache(texture, cacheKey) {

@@ -268,2 +319,10 @@ const { keyCache, inverseKeyCache } = this;

/**
* Get a texture from the cache
*
* @param cacheKey
*/
getTextureFromCache(cacheKey) {
return this.keyCache.get(cacheKey);
}
/**
* Remove a texture from the cache

@@ -283,3 +342,19 @@ *

}
/**
* Resolve a parent texture from the cache or fallback to the provided texture.
*
* @param texture - The provided texture to resolve.
* @returns The cached or provided texture.
*/
resolveParentTexture(texture) {
if (!texture?.props) {
return texture;
}
const cacheKey = ImageTexture.makeCacheKey(texture.props);
const cachedTexture = cacheKey
? this.getTextureFromCache(cacheKey)
: undefined;
return cachedTexture ?? texture;
}
}
//# sourceMappingURL=CoreTextureManager.js.map

@@ -30,9 +30,9 @@ /*

function createImageWorker() {
var supportsOptionsCreateImageBitmap = false;
var supportsFullCreateImageBitmap = false;
function hasAlphaChannel(mimeType) {
return mimeType.indexOf('image/png') !== -1;
}
function getImage(src, premultiplyAlpha, x, y, width, height) {
function getImage(src, premultiplyAlpha, x, y, width, height, options) {
return new Promise(function (resolve, reject) {
var supportsOptionsCreateImageBitmap = options.supportsOptionsCreateImageBitmap;
var supportsFullCreateImageBitmap = options.supportsFullCreateImageBitmap;
var xhr = new XMLHttpRequest();

@@ -66,4 +66,3 @@ xhr.open('GET', src, true);

}
// createImageBitmap without crop but with options
if (supportsOptionsCreateImageBitmap === true) {
else if (supportsOptionsCreateImageBitmap === true) {
createImageBitmap(blob, {

@@ -80,13 +79,14 @@ premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none',

});
return;
}
// Fallback for browsers that do not support createImageBitmap with options
// this is supported for Chrome v50 to v52/54 that doesn't support options
createImageBitmap(blob)
.then(function (data) {
resolve({ data, premultiplyAlpha: premultiplyAlpha });
})
.catch(function (error) {
reject(error);
});
else {
// Fallback for browsers that do not support createImageBitmap with options
// this is supported for Chrome v50 to v52/54 that doesn't support options
createImageBitmap(blob)
.then(function (data) {
resolve({ data, premultiplyAlpha: premultiplyAlpha });
})
.catch(function (error) {
reject(error);
});
}
};

@@ -107,3 +107,9 @@ xhr.onerror = function () {

var height = event.data.sh;
getImage(src, premultiplyAlpha, x, y, width, height)
// these will be set to true if the browser supports the createImageBitmap options or full
var supportsOptionsCreateImageBitmap = false;
var supportsFullCreateImageBitmap = false;
getImage(src, premultiplyAlpha, x, y, width, height, {
supportsOptionsCreateImageBitmap,
supportsFullCreateImageBitmap,
})
.then(function (data) {

@@ -147,7 +153,10 @@ self.postMessage({ id: id, src: src, data: data });

// Replace placeholders with actual initialization values
const supportsOptions = createImageBitmapSupport.options ? 'true' : 'false';
const supportsFull = createImageBitmapSupport.full ? 'true' : 'false';
workerCode = workerCode.replace('var supportsOptionsCreateImageBitmap = false;', `var supportsOptionsCreateImageBitmap = ${supportsOptions};`);
workerCode = workerCode.replace('var supportsFullCreateImageBitmap = false;', `var supportsFullCreateImageBitmap = ${supportsFull};`);
const blob = new Blob([workerCode.replace('"use strict";', '')], {
if (createImageBitmapSupport.options) {
workerCode = workerCode.replace('var supportsOptionsCreateImageBitmap = false;', 'var supportsOptionsCreateImageBitmap = true;');
}
if (createImageBitmapSupport.full) {
workerCode = workerCode.replace('var supportsFullCreateImageBitmap = false;', 'var supportsFullCreateImageBitmap = true;');
}
workerCode = workerCode.replace('"use strict";', '');
const blob = new Blob([workerCode], {
type: 'application/javascript',

@@ -158,9 +167,3 @@ });

for (let i = 0; i < numWorkers; i++) {
const worker = new Worker(blobURL);
// Pass `createImageBitmap` support level during worker initialization
worker.postMessage({
type: 'init',
support: createImageBitmapSupport,
});
workers.push(worker);
workers.push(new Worker(blobURL));
}

@@ -167,0 +170,0 @@ return workers;

@@ -55,2 +55,3 @@ /**

readonly CLAMP_TO_EDGE: 33071;
readonly RGB: 6407;
readonly RGBA: 6408;

@@ -57,0 +58,0 @@ readonly UNSIGNED_BYTE: 5121;

@@ -65,2 +65,3 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */

CLAMP_TO_EDGE;
RGB;
RGBA;

@@ -137,2 +138,3 @@ UNSIGNED_BYTE;

this.CLAMP_TO_EDGE = gl.CLAMP_TO_EDGE;
this.RGB = gl.RGB;
this.RGBA = gl.RGBA;

@@ -139,0 +141,0 @@ this.UNSIGNED_BYTE = gl.UNSIGNED_BYTE;

import type { BaseShaderController } from '../../../main-api/ShaderController.js';
import type { CoreNode } from '../../CoreNode.js';
import type { CoreShaderManager } from '../../CoreShaderManager.js';
import type { Texture } from '../../textures/Texture.js';
import { type Texture } from '../../textures/Texture.js';
import type { CoreContextTexture } from '../CoreContextTexture.js';

@@ -6,0 +6,0 @@ import { CoreRenderer, type CoreRendererOptions, type QuadOptions } from '../CoreRenderer.js';

@@ -21,2 +21,3 @@ /*

import { SubTexture } from '../../textures/SubTexture.js';
import { TextureType } from '../../textures/Texture.js';
import { CoreRenderer, } from '../CoreRenderer.js';

@@ -27,2 +28,3 @@ import { CanvasCoreTexture } from './CanvasCoreTexture.js';

import { UnsupportedShader } from './shaders/UnsupportedShader.js';
import { assertTruthy } from '../../../utils.js';
export class CanvasCoreRenderer extends CoreRenderer {

@@ -75,2 +77,9 @@ context;

let frame;
const textureType = texture?.type;
assertTruthy(textureType, 'Texture type is not defined');
// The Canvas2D renderer only supports image and color textures
if (textureType !== TextureType.image &&
textureType !== TextureType.color) {
return;
}
if (texture) {

@@ -83,6 +92,5 @@ if (texture instanceof SubTexture) {

if (texture.state === 'freed') {
ctxTexture.load();
return;
}
if (texture.state !== 'loaded' || !ctxTexture.hasImage()) {
if (texture.state !== 'loaded') {
return;

@@ -126,3 +134,3 @@ }

}
if (ctxTexture) {
if (textureType === TextureType.image && ctxTexture) {
const image = ctxTexture.getImage(color);

@@ -144,3 +152,3 @@ ctx.globalAlpha = color.a ?? alpha;

}
else if (hasGradient) {
else if (textureType === TextureType.color && hasGradient) {
let endX = tx;

@@ -167,3 +175,3 @@ let endY = ty;

}
else {
else if (textureType === TextureType.color) {
ctx.fillStyle = formatRgba(color);

@@ -170,0 +178,0 @@ ctx.fillRect(tx, ty, width, height);

@@ -26,13 +26,10 @@ /*

load() {
if (this.textureSource.state !== 'freed') {
return;
}
this.textureSource.setState('loading');
this.textureSource.setCoreCtxState('loading');
this.onLoadRequest()
.then((size) => {
this.textureSource.setState('loaded', size);
this.textureSource.setCoreCtxState('loaded', size);
this.updateMemSize();
})
.catch((err) => {
this.textureSource.setState('failed', err);
this.textureSource.setCoreCtxState('failed', err);
});

@@ -43,3 +40,3 @@ }

this.tintCache = undefined;
this.textureSource.setState('freed');
this.textureSource.setCoreCtxState('freed');
this.setTextureMemUse(0);

@@ -103,3 +100,4 @@ }

async onLoadRequest() {
const { data } = await this.textureSource.getTextureData();
assertTruthy(this.textureSource?.textureData?.data, 'Texture data is null');
const { data } = this.textureSource.textureData;
// TODO: canvas from text renderer should be able to provide the canvas directly

@@ -106,0 +104,0 @@ // instead of having to re-draw it into a new canvas...

@@ -6,2 +6,3 @@ import type { TextureMemoryManager } from '../TextureMemoryManager.js';

private memManager;
state: 'freed' | 'loading' | 'loaded' | 'failed';
constructor(memManager: TextureMemoryManager, textureSource: Texture);

@@ -8,0 +9,0 @@ protected setTextureMemUse(byteSize: number): void;

@@ -22,2 +22,3 @@ /*

memManager;
state = 'freed';
constructor(memManager, textureSource) {

@@ -24,0 +25,0 @@ this.memManager = memManager;

@@ -0,0 +0,0 @@ import { WebGlCoreShader, } from '../WebGlCoreShader.js';

@@ -0,0 +0,0 @@ import { ShaderEffect, } from './ShaderEffect.js';

@@ -0,0 +0,0 @@ import { updateWebSafeRadius, validateArrayLength4 } from './EffectUtils.js';

@@ -19,2 +19,3 @@ /*

*/
import { assertTruthy } from '../../../utils.js';
import { WebGlCoreCtxTexture } from './WebGlCoreCtxTexture.js';

@@ -26,3 +27,4 @@ export class WebGlCoreCtxSubTexture extends WebGlCoreCtxTexture {

async onLoadRequest() {
const props = await this.textureSource.getTextureData();
const props = this.textureSource.textureData;
assertTruthy(props, 'SubTexture must have texture data');
if (props.data instanceof Uint8Array) {

@@ -29,0 +31,0 @@ // its a 1x1 Color Texture

@@ -20,7 +20,6 @@ import type { Dimensions } from '../../../common/CommonTypes.js';

protected _nativeCtxTexture: WebGLTexture | null;
private _state;
private _w;
private _h;
constructor(glw: WebGlContextWrapper, memManager: TextureMemoryManager, textureSource: Texture);
get ctxTexture(): WebGLTexture;
get ctxTexture(): WebGLTexture | null;
get w(): number;

@@ -27,0 +26,0 @@ get h(): number;

@@ -38,3 +38,2 @@ /*

_nativeCtxTexture = null;
_state = 'freed';
_w = 0;

@@ -47,4 +46,5 @@ _h = 0;

get ctxTexture() {
if (this._state === 'freed') {
if (this.state === 'freed') {
this.load();
return null;
}

@@ -71,11 +71,11 @@ assertTruthy(this._nativeCtxTexture);

// If the texture is already loading or loaded, don't load it again.
if (this._state === 'loading' || this._state === 'loaded') {
if (this.state === 'loading' || this.state === 'loaded') {
return;
}
this._state = 'loading';
this.textureSource.setState('loading');
this.state = 'loading';
this.textureSource.setCoreCtxState('loading');
this._nativeCtxTexture = this.createNativeCtxTexture();
if (this._nativeCtxTexture === null) {
this._state = 'failed';
this.textureSource.setState('failed', new Error('Could not create WebGL Texture'));
this.state = 'failed';
this.textureSource.setCoreCtxState('failed', new Error('Could not create WebGL Texture'));
console.error('Could not create WebGL Texture');

@@ -87,6 +87,6 @@ return;

// If the texture has been freed while loading, return early.
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'loaded';
this.state = 'loaded';
this._w = width;

@@ -96,11 +96,11 @@ this._h = height;

// for rendering.
this.textureSource.setState('loaded', { width, height });
this.textureSource.setCoreCtxState('loaded', { width, height });
})
.catch((err) => {
// If the texture has been freed while loading, return early.
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'failed';
this.textureSource.setState('failed', err);
this.state = 'failed';
this.textureSource.setCoreCtxState('failed', err);
console.error(err);

@@ -114,9 +114,10 @@ });

const { glw } = this;
const textureData = this.textureSource.textureData;
assertTruthy(textureData, 'Texture data is null');
// Set to a 1x1 transparent texture
glw.texImage2D(0, glw.RGBA, 1, 1, 0, glw.RGBA, glw.UNSIGNED_BYTE, null);
this.setTextureMemUse(TRANSPARENT_TEXTURE_DATA.byteLength);
const textureData = await this.textureSource?.getTextureData();
// If the texture has been freed while loading, return early.
if (!this._nativeCtxTexture) {
assertTruthy(this._state === 'freed');
assertTruthy(this.state === 'freed');
return { width: 0, height: 0 };

@@ -126,5 +127,6 @@ }

let height = 0;
assertTruthy(this._nativeCtxTexture);
glw.activeTexture(0);
const tdata = textureData.data;
const format = textureData.premultiplyAlpha ? glw.RGBA : glw.RGB;
const formatBytes = format === glw.RGBA ? 4 : 3;
// If textureData is null, the texture is empty (0, 0) and we don't need to

@@ -140,4 +142,4 @@ // upload any data to the GPU.

glw.pixelStorei(glw.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !!textureData.premultiplyAlpha);
glw.texImage2D(0, glw.RGBA, glw.RGBA, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * 4);
glw.texImage2D(0, format, format, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * formatBytes);
// generate mipmaps for power-of-2 textures or in WebGL2RenderingContext

@@ -153,3 +155,3 @@ if (glw.isWebGl2() || (isPowerOfTwo(width) && isPowerOfTwo(height))) {

glw.bindTexture(this._nativeCtxTexture);
glw.texImage2D(0, glw.RGBA, 1, 1, 0, glw.RGBA, glw.UNSIGNED_BYTE, TRANSPARENT_TEXTURE_DATA);
glw.texImage2D(0, format, 1, 1, 0, format, glw.UNSIGNED_BYTE, TRANSPARENT_TEXTURE_DATA);
this.setTextureMemUse(TRANSPARENT_TEXTURE_DATA.byteLength);

@@ -176,4 +178,4 @@ }

glw.pixelStorei(glw.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !!textureData.premultiplyAlpha);
glw.texImage2D(0, glw.RGBA, width, height, 0, glw.RGBA, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * 4);
glw.texImage2D(0, format, width, height, 0, format, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * formatBytes);
}

@@ -194,7 +196,7 @@ else {

free() {
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'freed';
this.textureSource.setState('freed');
this.state = 'freed';
this.textureSource.setCoreCtxState('freed');
this._w = 0;

@@ -201,0 +203,0 @@ this._h = 0;

@@ -35,3 +35,2 @@ import { CoreRenderer, type BufferInfo, type CoreRendererOptions, type QuadOptions } from '../CoreRenderer.js';

*/
defaultTexture: Texture;
quadBufferUsage: number;

@@ -38,0 +37,0 @@ /**

@@ -25,3 +25,2 @@ /*

import { Texture, TextureType } from '../../textures/Texture.js';
import { ColorTexture } from '../../textures/ColorTexture.js';
import { SubTexture } from '../../textures/SubTexture.js';

@@ -36,3 +35,2 @@ import { WebGlCoreCtxSubTexture } from './WebGlCoreCtxSubTexture.js';

import { WebGlCoreCtxRenderTexture } from './WebGlCoreCtxRenderTexture.js';
import { ImageTexture } from '../../textures/ImageTexture.js';
const WORDS_PER_QUAD = 24;

@@ -64,3 +62,2 @@ export class WebGlCoreRenderer extends CoreRenderer {

*/
defaultTexture;
quadBufferUsage = 0;

@@ -78,12 +75,2 @@ /**

const { canvas, clearColor, bufferMemory } = options;
this.defaultTexture = new ColorTexture(this.txManager);
// Mark the default texture as ALWAYS renderable
// This prevents it from ever being cleaned up.
// Fixes https://github.com/lightning-js/renderer/issues/262
this.defaultTexture.setRenderableOwner(this, true);
// When the default texture is loaded, request a render in case the
// RAF is paused. Fixes: https://github.com/lightning-js/renderer/issues/123
this.defaultTexture.once('loaded', () => {
this.stage.requestRender();
});
const gl = createWebGLContext(canvas, options.forceWebGL2, options.contextSpy);

@@ -180,3 +167,4 @@ const glw = (this.glw = new WebGlContextWrapper(gl));

const { fQuadBuffer, uiQuadBuffer } = this;
let texture = params.texture || this.defaultTexture;
let texture = params.texture;
assertTruthy(texture !== null, 'Texture is required');
/**

@@ -196,3 +184,2 @@ * If the shader props contain any automatic properties, update it with the

}
assertTruthy(texture.ctxTexture !== undefined, 'Invalid texture type');
let { curBufferIdx: bufferIdx, curRenderOp } = this;

@@ -205,3 +192,2 @@ const targetDims = { width: -1, height: -1 };

if (this.reuseRenderOp(params) === false) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.newRenderOp(targetShader, params.shaderProps, params.alpha, targetDims, params.clippingRect, bufferIdx, params.rtt, params.parentHasRenderTexture, params.framebufferDimensions);

@@ -263,3 +249,3 @@ curRenderOp = this.curRenderOp;

const ctxTexture = texture.ctxTexture;
assertTruthy(ctxTexture.ctxTexture !== undefined);
assertTruthy(ctxTexture instanceof WebGlCoreCtxTexture);
const textureIdx = this.addTexture(ctxTexture, bufferIdx);

@@ -552,2 +538,6 @@ assertTruthy(this.curRenderOp !== null);

}
if (!node.texture || !node.texture.ctxTexture) {
console.warn('Texture not loaded for RTT node', node);
continue;
}
// Set the active RTT node to the current node

@@ -554,0 +544,0 @@ // So we can prevent rendering children of nested RTT nodes

@@ -19,2 +19,3 @@ import { AnimationManager } from './animations/AnimationManager.js';

import { type Bound } from './lib/utils.js';
import type { Texture } from './textures/Texture.js';
export interface StageOptions {

@@ -39,2 +40,3 @@ appWidth: number;

strictBounds: boolean;
textureProcessingLimit: number;
}

@@ -58,2 +60,3 @@ export type StageFpsUpdateHandler = (stage: Stage, fpsData: FpsUpdatePayload) => void;

readonly strictBounds: boolean;
readonly defaultTexture: Texture | null;
/**

@@ -84,2 +87,6 @@ * Renderer Event Bus for the Stage to emit events onto

/**
* Create default PixelTexture
*/
createDefaultTexture(): void;
/**
* Update animations

@@ -86,0 +93,0 @@ */

@@ -34,2 +34,3 @@ /*

import { createBound, createPreloadBounds } from './lib/utils.js';
import { ColorTexture } from './textures/ColorTexture.js';
const bufferMemory = 2e6;

@@ -53,2 +54,3 @@ const autoStart = true;

strictBounds;
defaultTexture = null;
/**

@@ -82,2 +84,7 @@ * Renderer Event Bus for the Stage to emit events onto

this.txManager = new CoreTextureManager(numImageWorkers);
// Wait for the Texture Manager to initialize
// once it does, request a render
this.txManager.on('initialized', () => {
this.requestRender();
});
this.txMemManager = new TextureMemoryManager(this, textureMemory);

@@ -112,2 +119,3 @@ this.shManager = new CoreShaderManager();

const renderMode = this.renderer.mode || 'webgl';
this.createDefaultTexture();
this.defShaderCtr = this.renderer.getDefShaderCtr();

@@ -206,2 +214,21 @@ setPremultiplyMode(renderMode);

/**
* Create default PixelTexture
*/
createDefaultTexture() {
this.defaultTexture = this.txManager.createTexture('ColorTexture', {
color: 0xffffffff,
});
assertTruthy(this.defaultTexture instanceof ColorTexture);
this.txManager.loadTexture(this.defaultTexture, true);
// Mark the default texture as ALWAYS renderable
// This prevents it from ever being cleaned up.
// Fixes https://github.com/lightning-js/renderer/issues/262
this.defaultTexture.setRenderableOwner(this, true);
// When the default texture is loaded, request a render in case the
// RAF is paused. Fixes: https://github.com/lightning-js/renderer/issues/123
this.defaultTexture.once('loaded', () => {
this.requestRender();
});
}
/**
* Update animations

@@ -221,3 +248,5 @@ */

hasSceneUpdates() {
return !!this.root.updateType || this.renderRequested;
return (!!this.root.updateType ||
this.renderRequested ||
this.txManager.hasUpdates());
}

@@ -234,2 +263,5 @@ /**

}
// Process some textures
// TODO this should have a configurable amount
this.txManager.processSome(this.options.textureProcessingLimit);
// Reset render operations and clear the canvas

@@ -236,0 +268,0 @@ renderer.reset();

@@ -43,3 +43,3 @@ /*

// Load image
this.texture = stage.txManager.loadTexture('ImageTexture', {
this.texture = stage.txManager.createTexture('ImageTexture', {
src: atlasUrl,

@@ -52,2 +52,4 @@ // IMPORTANT: The SDF shader requires the alpha channel to NOT be

});
// Load the texture
stage.txManager.loadTexture(this.texture, true);
this.texture.on('loaded', () => {

@@ -58,6 +60,2 @@ this.checkLoaded();

});
// Pre-load it
stage.txManager.once('initialized', () => {
this.texture.ctxTexture.load();
});
// Set this.data to the fetched data from dataUrl

@@ -64,0 +62,0 @@ fetch(atlasDataUrl)

@@ -264,3 +264,4 @@ /*

const node = state.node;
const texture = this.stage.txManager.loadTexture('ImageTexture', {
const texture = this.stage.txManager.createTexture('ImageTexture', {
premultiplyAlpha: true,
src: function (lightning2TextRenderer, renderInfo) {

@@ -267,0 +268,0 @@ // load the canvas texture

@@ -57,3 +57,2 @@ import { bytesToMb } from './utils.js';

if (criticalThreshold === 0) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.setTextureMemUse = () => { };

@@ -129,3 +128,3 @@ }

if (texture.preventCleanup === false) {
texture.ctxTexture.free();
texture.free();
txManager.removeTextureFromCache(texture);

@@ -155,5 +154,3 @@ }

let renderableTexturesLoaded = 0;
const renderableMemUsed = [...this.loadedTextures.keys()].reduce(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(acc, texture) => {
const renderableMemUsed = [...this.loadedTextures.keys()].reduce((acc, texture) => {
renderableTexturesLoaded += texture.renderable ? 1 : 0;

@@ -160,0 +157,0 @@ return (acc + (texture.renderable ? this.loadedTextures.get(texture) : 0));

@@ -32,3 +32,3 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

set color(color: number);
getTextureData(): Promise<TextureData>;
getTextureSource(): Promise<TextureData>;
static makeCacheKey(props: ColorTextureProps): string;

@@ -35,0 +35,0 @@ static resolveDefaults(props: ColorTextureProps): Required<ColorTextureProps>;

@@ -45,3 +45,3 @@ /*

}
async getTextureData() {
async getTextureSource() {
const pixelData = new Uint8Array(4);

@@ -60,2 +60,3 @@ if (this.color === 0xffffffff) {

}
this.setSourceState('loaded', { width: 1, height: 1 });
return {

@@ -62,0 +63,0 @@ data: pixelData,

@@ -108,3 +108,10 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

loadImage(src: string): Promise<TextureData>;
getTextureData(): Promise<TextureData>;
getTextureSource(): Promise<TextureData>;
determineImageTypeAndLoadImage(): Promise<TextureData> | {
data: null;
premultiplyAlpha?: undefined;
} | {
data: ImageData | null;
premultiplyAlpha: boolean | null;
};
/**

@@ -111,0 +118,0 @@ * Generates a cache key for the ImageTexture based on the provided props.

@@ -109,3 +109,41 @@ /*

}
async getTextureData() {
async getTextureSource() {
let resp;
try {
resp = await this.determineImageTypeAndLoadImage();
}
catch (e) {
this.setSourceState('failed', e);
return {
data: null,
};
}
if (resp.data === null) {
this.setSourceState('failed', Error('ImageTexture: No image data'));
return {
data: null,
};
}
let width, height;
// check if resp.data is typeof Uint8ClampedArray else
// use resp.data.width and resp.data.height
if (resp.data instanceof Uint8Array) {
width = this.props.width ?? 0;
height = this.props.height ?? 0;
}
else {
width = resp.data?.width ?? (this.props.width || 0);
height = resp.data?.height ?? (this.props.height || 0);
}
// we're loaded!
this.setSourceState('loaded', {
width,
height,
});
return {
data: resp.data,
premultiplyAlpha: this.props.premultiplyAlpha ?? true,
};
}
determineImageTypeAndLoadImage() {
const { src, premultiplyAlpha, type } = this.props;

@@ -112,0 +150,0 @@ if (src === null) {

@@ -39,3 +39,3 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

constructor(txManager: CoreTextureManager, props: NoiseTextureProps);
getTextureData(): Promise<TextureData>;
getTextureSource(): Promise<TextureData>;
static makeCacheKey(props: NoiseTextureProps): string | false;

@@ -42,0 +42,0 @@ static resolveDefaults(props: NoiseTextureProps): Required<NoiseTextureProps>;

@@ -36,3 +36,3 @@ /*

}
async getTextureData() {
async getTextureSource() {
const { width, height } = this.props;

@@ -48,2 +48,3 @@ const size = width * height * 4;

}
this.setSourceState('loaded');
return {

@@ -50,0 +51,0 @@ data: new ImageData(pixelData8, width, height),

@@ -26,5 +26,5 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

set height(value: number);
getTextureData(): Promise<TextureData>;
getTextureSource(): Promise<TextureData>;
static resolveDefaults(props: RenderTextureProps): Required<RenderTextureProps>;
static z$__type__Props: RenderTextureProps;
}

@@ -39,3 +39,4 @@ /*

}
async getTextureData() {
async getTextureSource() {
this.setSourceState('loaded');
return {

@@ -42,0 +43,0 @@ data: null,

@@ -54,3 +54,3 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

onChangeIsRenderable(isRenderable: boolean): void;
getTextureData(): Promise<TextureData>;
getTextureSource(): Promise<TextureData>;
static makeCacheKey(props: SubTextureProps): string | false;

@@ -57,0 +57,0 @@ static resolveDefaults(props: SubTextureProps): Required<SubTextureProps>;

@@ -19,2 +19,4 @@ /*

*/
import { assertTruthy } from '../../utils.js';
import { ImageTexture } from './ImageTexture.js';
import { Texture, TextureType, } from './Texture.js';

@@ -38,3 +40,10 @@ /**

this.props = SubTexture.resolveDefaults(props || {});
this.parentTexture = this.props.texture;
assertTruthy(this.props.texture, 'SubTexture requires a parent texture');
assertTruthy(this.props.texture instanceof ImageTexture, 'SubTexture requires an ImageTexture parent');
// Resolve parent texture from cache or fallback to provided texture
this.parentTexture = txManager.resolveParentTexture(this.props.texture);
if (this.parentTexture.state === 'freed') {
this.txManager.loadTexture(this.parentTexture);
}
this.parentTexture.setRenderableOwner(this, true);
// If parent texture is already loaded / failed, trigger loaded event manually

@@ -59,9 +68,16 @@ // so that users get a consistent event experience.

// configured dimensions (because that's all that matters here)
this.setState('loaded', {
this.setSourceState('loaded', {
width: this.props.width,
height: this.props.height,
});
// If the parent already has a ctxTexture, we can set the core ctx state
if (this.parentTexture.ctxTexture !== undefined) {
this.setCoreCtxState('loaded', {
width: this.props.width,
height: this.props.height,
});
}
};
onParentTxFailed = (target, error) => {
this.setState('failed', error);
this.setSourceState('failed', error);
};

@@ -72,3 +88,4 @@ onChangeIsRenderable(isRenderable) {

}
async getTextureData() {
async getTextureSource() {
// Check if parent texture is loaded
return {

@@ -75,0 +92,0 @@ data: this.props,

@@ -79,8 +79,4 @@ import type { CoreTextureManager } from '../CoreTextureManager.js';

}
export type UpdateType = 'source' | 'coreCtx';
/**
* Like the built-in Parameters<> type but skips the first parameter (which is
* `target` currently)
*/
type ParametersSkipTarget<T extends (...args: any) => any> = T extends (target: any, ...args: infer P) => any ? P : never;
/**
* Represents a source of texture data for a CoreContextTexture.

@@ -105,3 +101,5 @@ *

readonly error: Error | null;
readonly state: TextureState;
state: TextureState;
private sourceState;
private coreCtxState;
readonly renderableOwners: Set<unknown>;

@@ -112,2 +110,4 @@ readonly renderable: boolean;

preventCleanup: boolean;
ctxTexture: CoreContextTexture | undefined;
textureData: TextureData | null;
constructor(txManager: CoreTextureManager);

@@ -140,24 +140,38 @@ /**

/**
* Get the CoreContextTexture for this Texture
* Load the core context texture for this Texture.
* The ctxTexture is created by the renderer and lives on the GPU.
*
* @returns
*/
loadCtxTexture(): CoreContextTexture;
/**
* Free the core context texture for this Texture.
*
* @remarks
* Each Texture has a corresponding CoreContextTexture that is used to
* manage the texture's native data depending on the renderer's mode
* (WebGL, Canvas, etc).
* The ctxTexture is created by the renderer and lives on the GPU.
*/
free(): void;
private setState;
/**
* Set the source state of the texture
*
* The Texture and CoreContextTexture are always linked together in a 1:1
* relationship.
* @remarks
* The source of the texture can either be generated by the texture itself or
* loaded from an external source.
*
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
get ctxTexture(): CoreContextTexture;
setSourceState(state: TextureState, errorOrDimensions?: Error | Dimensions): void;
/**
* Set the state of the texture
* Set the core context state of the texture
*
* @remark
* Intended for internal-use only but declared public so that it can be set
* by it's associated {@link CoreContextTexture}
* @remarks
* The core context state of the texture is the state of the texture on the GPU.
*
* @param state
* @param args
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
setState<State extends TextureState>(state: State, ...args: ParametersSkipTarget<TextureStateEventMap[State]>): void;
setCoreCtxState(state: TextureState, errorOrDimensions?: Error | Dimensions): void;
private updateState;
/**

@@ -173,4 +187,12 @@ * Get the texture data for this texture.

*/
abstract getTextureData(): Promise<TextureData>;
getTextureData(): Promise<TextureData>;
/**
* Get the texture source for this texture.
*
* @remarks
* This method is called by the CoreContextTexture when the texture is loaded.
* The texture source is then used to populate the CoreContextTexture.
*/
abstract getTextureSource(): Promise<TextureData>;
/**
* Make a cache key for this texture.

@@ -177,0 +199,0 @@ *

@@ -49,3 +49,8 @@ /*

error = null;
// aggregate state
state = 'freed';
// texture source state
sourceState = 'freed';
// texture (gpu) state
coreCtxState = 'freed';
renderableOwners = new Set();

@@ -56,2 +61,4 @@ renderable = false;

preventCleanup = false;
ctxTexture;
textureData = null;
constructor(txManager) {

@@ -81,3 +88,2 @@ super();

if (newSize > oldSize && newSize === 1) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
this.renderable = true;

@@ -92,3 +98,2 @@ this.lastRenderableChangeTime = this.txManager.frameTime;

if (newSize < oldSize && newSize === 0) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
this.renderable = false;

@@ -101,45 +106,112 @@ this.lastRenderableChangeTime = this.txManager.frameTime;

/**
* Get the CoreContextTexture for this Texture
* Load the core context texture for this Texture.
* The ctxTexture is created by the renderer and lives on the GPU.
*
* @returns
*/
loadCtxTexture() {
if (this.ctxTexture === undefined) {
this.ctxTexture = this.txManager.renderer.createCtxTexture(this);
}
return this.ctxTexture;
}
/**
* Free the core context texture for this Texture.
*
* @remarks
* Each Texture has a corresponding CoreContextTexture that is used to
* manage the texture's native data depending on the renderer's mode
* (WebGL, Canvas, etc).
* The ctxTexture is created by the renderer and lives on the GPU.
*/
free() {
this.ctxTexture?.free();
if (this.textureData !== null) {
this.textureData = null;
}
}
setState(state, type, errorOrDimensions) {
const stateObj = type === 'source' ? 'sourceState' : 'coreCtxState';
if (this[stateObj] === state) {
return;
}
this[stateObj] = state;
if (state === 'loaded') {
this.dimensions = errorOrDimensions;
}
else if (state === 'failed') {
this.error = errorOrDimensions;
}
this.updateState();
}
/**
* Set the source state of the texture
*
* The Texture and CoreContextTexture are always linked together in a 1:1
* relationship.
* @remarks
* The source of the texture can either be generated by the texture itself or
* loaded from an external source.
*
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
get ctxTexture() {
// The first time this is called, create the ctxTexture
const ctxTexture = this.txManager.renderer.createCtxTexture(this);
// And replace this getter with the value for future calls
Object.defineProperty(this, 'ctxTexture', { value: ctxTexture });
return ctxTexture;
setSourceState(state, errorOrDimensions) {
this.setState(state, 'source', errorOrDimensions);
}
/**
* Set the state of the texture
* Set the core context state of the texture
*
* @remark
* Intended for internal-use only but declared public so that it can be set
* by it's associated {@link CoreContextTexture}
* @remarks
* The core context state of the texture is the state of the texture on the GPU.
*
* @param state
* @param args
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
setState(state, ...args) {
if (this.state !== state) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
this.state = state;
if (state === 'loaded') {
const loadedArgs = args;
this.dimensions = loadedArgs[0];
}
else if (state === 'failed') {
const failedArgs = args;
this.error = failedArgs[0];
}
this.emit(state, ...args);
setCoreCtxState(state, errorOrDimensions) {
this.setState(state, 'coreCtx', errorOrDimensions);
}
updateState() {
const ctxState = this.coreCtxState;
const sourceState = this.sourceState;
let newState = 'freed';
let payload = null;
if (sourceState === 'failed' || ctxState === 'failed') {
newState = 'failed';
payload = this.error; // Error set by the source
}
else if (sourceState === 'loading' || ctxState === 'loading') {
newState = 'loading';
}
else if (sourceState === 'loaded' && ctxState === 'loaded') {
newState = 'loaded';
payload = this.dimensions; // Dimensions set by the source
}
else if ((sourceState === 'loaded' && ctxState === 'freed') ||
(ctxState === 'loaded' && sourceState === 'freed')) {
// If one is loaded and the other is freed, then we are in a loading state
newState = 'loading';
}
else {
newState = 'freed';
}
if (this.state === newState) {
return;
}
// emit the new state
this.state = newState;
this.emit(newState, payload);
}
/**
* Get the texture data for this texture.
*
* @remarks
* This method is called by the CoreContextTexture when the texture is loaded.
* The texture data is then used to populate the CoreContextTexture.
*
* @returns
* The texture data for this texture.
*/
async getTextureData() {
if (this.textureData === null) {
this.textureData = await this.getTextureSource();
}
return this.textureData;
}
/**
* Make a cache key for this texture.

@@ -146,0 +218,0 @@ *

@@ -219,2 +219,20 @@ import type { EffectMap, ShaderMap } from '../core/CoreShaderManager.js';

strictBounds?: boolean;
/**
* Texture Processing Limit
*
* @remarks
* The maximum number of textures to process in a single frame. This is used to
* prevent the renderer from processing too many textures in a single frame.
*
* @defaultValue `0`
*/
textureProcessingLimit?: number;
/**
* Canvas object to use for rendering
*
* @remarks
* This is used to render the scene graph. If not provided, a new canvas
* element will be created and appended to the target element.
*/
canvas?: HTMLCanvasElement;
}

@@ -221,0 +239,0 @@ /**

@@ -110,8 +110,9 @@ /*

strictBounds: settings.strictBounds ?? true,
textureProcessingLimit: settings.textureProcessingLimit || 0,
canvas: settings.canvas || document.createElement('canvas'),
};
this.settings = resolvedSettings;
const { appWidth, appHeight, deviceLogicalPixelRatio, devicePhysicalPixelRatio, inspector, } = resolvedSettings;
const { appWidth, appHeight, deviceLogicalPixelRatio, devicePhysicalPixelRatio, inspector, canvas, } = resolvedSettings;
const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
const canvas = document.createElement('canvas');
this.canvas = canvas;

@@ -142,2 +143,3 @@ canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;

strictBounds: this.settings.strictBounds,
textureProcessingLimit: this.settings.textureProcessingLimit,
});

@@ -239,3 +241,3 @@ // Extract the root node

createTexture(textureType, props) {
return this.stage.txManager.loadTexture(textureType, props);
return this.stage.txManager.createTexture(textureType, props);
}

@@ -356,3 +358,3 @@ /**

rerender() {
throw new Error('Not implemented');
this.stage.requestRender();
}

@@ -359,0 +361,0 @@ /**

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

{
"name": "@lightningjs/renderer",
"version": "2.9.0-beta2",
"version": "2.9.0-beta3",
"description": "Lightning 3 Renderer",

@@ -5,0 +5,0 @@ "type": "module",

@@ -0,0 +0,0 @@ # Lightning 3 Renderer

@@ -0,0 +0,0 @@ if (

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /* eslint-disable @typescript-eslint/unbound-method */

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -111,16 +111,2 @@ /*

/**
* Preload the texture immediately even if it's not being rendered to the
* screen.
*
* @remarks
* This allows the texture to be used immediately without any delay when it
* is first needed for rendering. Otherwise the loading process will start
* when the texture is first rendered, which may cause a delay in that texture
* being shown properly.
*
* @defaultValue `false`
*/
preload?: boolean;
/**
* Flip the texture horizontally when rendering

@@ -165,2 +151,7 @@ *

private downloadTextureSourceQueue: Array<Texture> = [];
private priorityQueue: Array<Texture> = [];
private uploadTextureQueue: Array<Texture> = [];
private initialized = false;
imageWorkerManager: ImageWorkerManager | null = null;

@@ -224,2 +215,3 @@ hasCreateImageBitmap = !!self.createImageBitmap;

this.initialized = true;
this.emit('initialized');

@@ -233,2 +225,3 @@ })

// initialized without image worker manager and createImageBitmap
this.initialized = true;
this.emit('initialized');

@@ -246,99 +239,33 @@ });

// Test if createImageBitmap is supported using a simple 1x1 PNG image
// prettier-ignore (this is a binary PNG image)
// prettier-ignore
const pngBinaryData = new Uint8Array([
0x89,
0x50,
0x4e,
0x47,
0x0d,
0x0a,
0x1a,
0x0a, // PNG signature
0x00,
0x00,
0x00,
0x0d, // IHDR chunk length
0x49,
0x48,
0x44,
0x52, // "IHDR" chunk type
0x00,
0x00,
0x00,
0x01, // Width: 1
0x00,
0x00,
0x00,
0x01, // Height: 1
0x01, // Bit depth: 1
0x03, // Color type: Indexed
0x00, // Compression method: Deflate
0x00, // Filter method: None
0x00, // Interlace method: None
0x25,
0xdb,
0x56,
0xca, // CRC for IHDR
0x00,
0x00,
0x00,
0x03, // PLTE chunk length
0x50,
0x4c,
0x54,
0x45, // "PLTE" chunk type
0x00,
0x00,
0x00, // Palette entry: Black
0xa7,
0x7a,
0x3d,
0xda, // CRC for PLTE
0x00,
0x00,
0x00,
0x01, // tRNS chunk length
0x74,
0x52,
0x4e,
0x53, // "tRNS" chunk type
0x00, // Transparency for black: Fully transparent
0x40,
0xe6,
0xd8,
0x66, // CRC for tRNS
0x00,
0x00,
0x00,
0x0a, // IDAT chunk length
0x49,
0x44,
0x41,
0x54, // "IDAT" chunk type
0x08,
0xd7, // Deflate header
0x63,
0x60,
0x00,
0x00,
0x00,
0x02,
0x00,
0x01, // Zlib-compressed data
0xe2,
0x21,
0xbc,
0x33, // CRC for IDAT
0x00,
0x00,
0x00,
0x00, // IEND chunk length
0x49,
0x45,
0x4e,
0x44, // "IEND" chunk type
0xae,
0x42,
0x60,
0x82, // CRC for IEND
0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a, // PNG signature
0x00, 0x00, 0x00, 0x0d, // IHDR chunk length
0x49, 0x48, 0x44, 0x52, // "IHDR" chunk type
0x00, 0x00, 0x00, 0x01, // Width: 1
0x00, 0x00, 0x00, 0x01, // Height: 1
0x01, // Bit depth: 1
0x03, // Color type: Indexed
0x00, // Compression method: Deflate
0x00, // Filter method: None
0x00, // Interlace method: None
0x25, 0xdb, 0x56, 0xca, // CRC for IHDR
0x00, 0x00, 0x00, 0x03, // PLTE chunk length
0x50, 0x4c, 0x54, 0x45, // "PLTE" chunk type
0x00, 0x00, 0x00, // Palette entry: Black
0xa7, 0x7a, 0x3d, 0xda, // CRC for PLTE
0x00, 0x00, 0x00, 0x01, // tRNS chunk length
0x74, 0x52, 0x4e, 0x53, // "tRNS" chunk type
0x00, // Transparency for black: Fully transparent
0x40, 0xe6, 0xd8, 0x66, // CRC for tRNS
0x00, 0x00, 0x00, 0x0a, // IDAT chunk length
0x49, 0x44, 0x41, 0x54, // "IDAT" chunk type
0x08, 0xd7, // Deflate header
0x63, 0x60, 0x00, 0x00,
0x00, 0x02, 0x00, 0x01, // Zlib-compressed data
0xe2, 0x21, 0xbc, 0x33, // CRC for IDAT
0x00, 0x00, 0x00, 0x00, // IEND chunk length
0x49, 0x45, 0x4e, 0x44, // "IEND" chunk type
0xae, 0x42, 0x60, 0x82, // CRC for IEND
]);

@@ -389,3 +316,29 @@

loadTexture<Type extends keyof TextureMap>(
/**
* Enqueue a texture for downloading its source image.
*/
enqueueDownloadTextureSource(texture: Texture): void {
if (!this.downloadTextureSourceQueue.includes(texture)) {
this.downloadTextureSourceQueue.push(texture);
}
}
/**
* Enqueue a texture for uploading to the GPU.
*
* @param texture - The texture to upload
*/
enqueueUploadTexture(texture: Texture): void {
if (this.uploadTextureQueue.includes(texture) === false) {
this.uploadTextureQueue.push(texture);
}
}
/**
* Create a texture
*
* @param textureType - The type of texture to create
* @param props - The properties to use for the texture
*/
createTexture<Type extends keyof TextureMap>(
textureType: Type,

@@ -400,20 +353,130 @@ props: ExtractProps<TextureMap[Type]>,

if (!texture) {
const cacheKey = TextureClass.makeCacheKey(props as any);
if (cacheKey && this.keyCache.has(cacheKey)) {
// console.log('Getting texture by cache key', cacheKey);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
texture = this.keyCache.get(cacheKey)!;
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
texture = new TextureClass(this, props as any);
if (cacheKey) {
this.initTextureToCache(texture, cacheKey);
}
const cacheKey = TextureClass.makeCacheKey(props as any);
if (cacheKey && this.keyCache.has(cacheKey)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
texture = this.keyCache.get(cacheKey)!;
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
texture = new TextureClass(this, props as any);
if (cacheKey) {
this.initTextureToCache(texture, cacheKey);
}
}
return texture as InstanceType<TextureMap[Type]>;
}
private initTextureToCache(texture: Texture, cacheKey: string) {
/**
* Override loadTexture to use the batched approach.
*
* @param texture - The texture to load
* @param immediate - Whether to prioritize the texture for immediate loading
*/
loadTexture(texture: Texture, priority?: boolean): void {
if (texture.state === 'loaded' || texture.state === 'loading') {
return;
}
texture.setSourceState('loading');
texture.setCoreCtxState('loading');
// if we're not initialized, just queue the texture into the priority queue
if (this.initialized === false) {
this.priorityQueue.push(texture);
return;
}
// prioritize the texture for immediate loading
if (priority === true) {
texture
.getTextureData()
.then(() => {
this.uploadTexture(texture);
})
.catch((err) => {
console.error(err);
});
}
// enqueue the texture for download and upload
this.enqueueDownloadTextureSource(texture);
}
/**
* Upload a texture to the GPU
*
* @param texture Texture to upload
*/
uploadTexture(texture: Texture): void {
const coreContext = texture.loadCtxTexture();
coreContext.load();
}
/**
* Process a limited number of downloads and uploads.
*
* @param maxItems - The maximum number of items to process
*/
processSome(maxItems = 0): void {
if (this.initialized === false) {
return;
}
let itemsProcessed = 0;
// Process priority queue
while (
this.priorityQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const texture = this.priorityQueue.shift()!;
texture.getTextureData().then(() => {
this.uploadTexture(texture);
});
itemsProcessed++;
}
// Process uploads
while (
this.uploadTextureQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.uploadTexture(this.uploadTextureQueue.shift()!);
itemsProcessed++;
}
// Process downloads
while (
this.downloadTextureSourceQueue.length > 0 &&
(maxItems === 0 || itemsProcessed < maxItems)
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const texture = this.downloadTextureSourceQueue.shift()!;
queueMicrotask(() => {
texture.getTextureData().then(() => {
this.enqueueUploadTexture(texture);
});
});
itemsProcessed++;
}
}
public hasUpdates(): boolean {
return (
this.downloadTextureSourceQueue.length > 0 ||
this.uploadTextureQueue.length > 0
);
}
/**
* Initialize a texture to the cache
*
* @param texture Texture to cache
* @param cacheKey Cache key for the texture
*/
initTextureToCache(texture: Texture, cacheKey: string) {
const { keyCache, inverseKeyCache } = this;

@@ -425,2 +488,11 @@ keyCache.set(cacheKey, texture);

/**
* Get a texture from the cache
*
* @param cacheKey
*/
getTextureFromCache(cacheKey: string): Texture | undefined {
return this.keyCache.get(cacheKey);
}
/**
* Remove a texture from the cache

@@ -440,2 +512,20 @@ *

}
/**
* Resolve a parent texture from the cache or fallback to the provided texture.
*
* @param texture - The provided texture to resolve.
* @returns The cached or provided texture.
*/
resolveParentTexture(texture: ImageTexture): Texture {
if (!texture?.props) {
return texture;
}
const cacheKey = ImageTexture.makeCacheKey(texture.props);
const cachedTexture = cacheKey
? this.getTextureFromCache(cacheKey)
: undefined;
return cachedTexture ?? texture;
}
}

@@ -0,0 +0,0 @@ /*

@@ -51,5 +51,2 @@ /*

function createImageWorker() {
var supportsOptionsCreateImageBitmap = false;
var supportsFullCreateImageBitmap = false;
function hasAlphaChannel(mimeType: string) {

@@ -66,4 +63,11 @@ return mimeType.indexOf('image/png') !== -1;

height: number | null,
options: {
supportsOptionsCreateImageBitmap: boolean;
supportsFullCreateImageBitmap: boolean;
},
): Promise<getImageReturn> {
return new Promise(function (resolve, reject) {
var supportsOptionsCreateImageBitmap =
options.supportsOptionsCreateImageBitmap;
var supportsFullCreateImageBitmap = options.supportsFullCreateImageBitmap;
var xhr = new XMLHttpRequest();

@@ -102,6 +106,3 @@ xhr.open('GET', src, true);

return;
}
// createImageBitmap without crop but with options
if (supportsOptionsCreateImageBitmap === true) {
} else if (supportsOptionsCreateImageBitmap === true) {
createImageBitmap(blob, {

@@ -118,14 +119,13 @@ premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none',

});
return;
} else {
// Fallback for browsers that do not support createImageBitmap with options
// this is supported for Chrome v50 to v52/54 that doesn't support options
createImageBitmap(blob)
.then(function (data) {
resolve({ data, premultiplyAlpha: premultiplyAlpha });
})
.catch(function (error) {
reject(error);
});
}
// Fallback for browsers that do not support createImageBitmap with options
// this is supported for Chrome v50 to v52/54 that doesn't support options
createImageBitmap(blob)
.then(function (data) {
resolve({ data, premultiplyAlpha: premultiplyAlpha });
})
.catch(function (error) {
reject(error);
});
};

@@ -152,3 +152,10 @@

getImage(src, premultiplyAlpha, x, y, width, height)
// these will be set to true if the browser supports the createImageBitmap options or full
var supportsOptionsCreateImageBitmap = false;
var supportsFullCreateImageBitmap = false;
getImage(src, premultiplyAlpha, x, y, width, height, {
supportsOptionsCreateImageBitmap,
supportsFullCreateImageBitmap,
})
.then(function (data) {

@@ -205,14 +212,18 @@ self.postMessage({ id: id, src: src, data: data });

// Replace placeholders with actual initialization values
const supportsOptions = createImageBitmapSupport.options ? 'true' : 'false';
const supportsFull = createImageBitmapSupport.full ? 'true' : 'false';
workerCode = workerCode.replace(
'var supportsOptionsCreateImageBitmap = false;',
`var supportsOptionsCreateImageBitmap = ${supportsOptions};`,
);
workerCode = workerCode.replace(
'var supportsFullCreateImageBitmap = false;',
`var supportsFullCreateImageBitmap = ${supportsFull};`,
);
if (createImageBitmapSupport.options) {
workerCode = workerCode.replace(
'var supportsOptionsCreateImageBitmap = false;',
'var supportsOptionsCreateImageBitmap = true;',
);
}
const blob: Blob = new Blob([workerCode.replace('"use strict";', '')], {
if (createImageBitmapSupport.full) {
workerCode = workerCode.replace(
'var supportsFullCreateImageBitmap = false;',
'var supportsFullCreateImageBitmap = true;',
);
}
workerCode = workerCode.replace('"use strict";', '');
const blob: Blob = new Blob([workerCode], {
type: 'application/javascript',

@@ -223,11 +234,3 @@ });

for (let i = 0; i < numWorkers; i++) {
const worker = new Worker(blobURL);
// Pass `createImageBitmap` support level during worker initialization
worker.postMessage({
type: 'init',
support: createImageBitmapSupport,
});
workers.push(worker);
workers.push(new Worker(blobURL));
}

@@ -234,0 +237,0 @@ return workers;

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ const rx1 = 0;

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ /*

@@ -71,2 +71,3 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */

public readonly CLAMP_TO_EDGE;
public readonly RGB;
public readonly RGBA;

@@ -162,2 +163,3 @@ public readonly UNSIGNED_BYTE;

this.CLAMP_TO_EDGE = gl.CLAMP_TO_EDGE;
this.RGB = gl.RGB;
this.RGBA = gl.RGBA;

@@ -1274,3 +1276,3 @@ this.UNSIGNED_BYTE = gl.UNSIGNED_BYTE;

type IsUniformMethod<MethodName, MethodType> = MethodName extends `uniform${string}`
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
?
MethodType extends (location: WebGLUniformLocation | null, ...args: any[]) => void

@@ -1277,0 +1279,0 @@ ? true

@@ -0,0 +0,0 @@ /*

@@ -25,3 +25,3 @@ /*

import { SubTexture } from '../../textures/SubTexture.js';
import type { Texture } from '../../textures/Texture.js';
import { TextureType, type Texture } from '../../textures/Texture.js';
import type { CoreContextTexture } from '../CoreContextTexture.js';

@@ -47,2 +47,3 @@ import {

import { UnsupportedShader } from './shaders/UnsupportedShader.js';
import { assertTruthy } from '../../../utils.js';

@@ -123,2 +124,13 @@ export class CanvasCoreRenderer extends CoreRenderer {

const textureType = texture?.type;
assertTruthy(textureType, 'Texture type is not defined');
// The Canvas2D renderer only supports image and color textures
if (
textureType !== TextureType.image &&
textureType !== TextureType.color
) {
return;
}
if (texture) {

@@ -132,6 +144,5 @@ if (texture instanceof SubTexture) {

if (texture.state === 'freed') {
ctxTexture.load();
return;
}
if (texture.state !== 'loaded' || !ctxTexture.hasImage()) {
if (texture.state !== 'loaded') {
return;

@@ -181,3 +192,3 @@ }

if (ctxTexture) {
if (textureType === TextureType.image && ctxTexture) {
const image = ctxTexture.getImage(color);

@@ -206,3 +217,3 @@ ctx.globalAlpha = color.a ?? alpha;

ctx.globalAlpha = 1;
} else if (hasGradient) {
} else if (textureType === TextureType.color && hasGradient) {
let endX: number = tx;

@@ -227,3 +238,3 @@ let endY: number = ty;

ctx.fillRect(tx, ty, width, height);
} else {
} else if (textureType === TextureType.color) {
ctx.fillStyle = formatRgba(color);

@@ -230,0 +241,0 @@ ctx.fillRect(tx, ty, width, height);

@@ -39,13 +39,11 @@ /*

load(): void {
if (this.textureSource.state !== 'freed') {
return;
}
this.textureSource.setState('loading');
this.textureSource.setCoreCtxState('loading');
this.onLoadRequest()
.then((size) => {
this.textureSource.setState('loaded', size);
this.textureSource.setCoreCtxState('loaded', size);
this.updateMemSize();
})
.catch((err) => {
this.textureSource.setState('failed', err as Error);
this.textureSource.setCoreCtxState('failed', err as Error);
});

@@ -57,3 +55,3 @@ }

this.tintCache = undefined;
this.textureSource.setState('freed');
this.textureSource.setCoreCtxState('freed');
this.setTextureMemUse(0);

@@ -131,3 +129,5 @@ }

private async onLoadRequest(): Promise<Dimensions> {
const { data } = await this.textureSource.getTextureData();
assertTruthy(this.textureSource?.textureData?.data, 'Texture data is null');
const { data } = this.textureSource.textureData;
// TODO: canvas from text renderer should be able to provide the canvas directly

@@ -150,4 +150,5 @@ // instead of having to re-draw it into a new canvas...

}
return { width: 0, height: 0 };
}
}

@@ -26,2 +26,3 @@ /*

private memManager: TextureMemoryManager;
public state: 'freed' | 'loading' | 'loaded' | 'failed' = 'freed';

@@ -28,0 +29,0 @@ constructor(memManager: TextureMemoryManager, textureSource: Texture) {

@@ -0,0 +0,0 @@ import type { DynamicShaderProps } from '../DynamicShader.js';

@@ -0,0 +0,0 @@ import type { EffectMap } from '../../../../CoreShaderManager.js';

@@ -21,2 +21,3 @@ /*

import type { Dimensions } from '../../../common/CommonTypes.js';
import { assertTruthy } from '../../../utils.js';
import type { TextureMemoryManager } from '../../TextureMemoryManager.js';

@@ -37,3 +38,4 @@ import type { WebGlContextWrapper } from '../../lib/WebGlContextWrapper.js';

override async onLoadRequest(): Promise<Dimensions> {
const props = await (this.textureSource as SubTexture).getTextureData();
const props = (this.textureSource as SubTexture).textureData;
assertTruthy(props, 'SubTexture must have texture data');

@@ -40,0 +42,0 @@ if (props.data instanceof Uint8Array) {

@@ -44,3 +44,2 @@ /*

protected _nativeCtxTexture: WebGLTexture | null = null;
private _state: 'freed' | 'loading' | 'loaded' | 'failed' = 'freed';
private _w = 0;

@@ -57,5 +56,6 @@ private _h = 0;

get ctxTexture(): WebGLTexture {
if (this._state === 'freed') {
get ctxTexture(): WebGLTexture | null {
if (this.state === 'freed') {
this.load();
return null;
}

@@ -85,11 +85,13 @@ assertTruthy(this._nativeCtxTexture);

// If the texture is already loading or loaded, don't load it again.
if (this._state === 'loading' || this._state === 'loaded') {
if (this.state === 'loading' || this.state === 'loaded') {
return;
}
this._state = 'loading';
this.textureSource.setState('loading');
this.state = 'loading';
this.textureSource.setCoreCtxState('loading');
this._nativeCtxTexture = this.createNativeCtxTexture();
if (this._nativeCtxTexture === null) {
this._state = 'failed';
this.textureSource.setState(
this.state = 'failed';
this.textureSource.setCoreCtxState(
'failed',

@@ -101,9 +103,11 @@ new Error('Could not create WebGL Texture'),

}
this.onLoadRequest()
.then(({ width, height }) => {
// If the texture has been freed while loading, return early.
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'loaded';
this.state = 'loaded';
this._w = width;

@@ -113,11 +117,11 @@ this._h = height;

// for rendering.
this.textureSource.setState('loaded', { width, height });
this.textureSource.setCoreCtxState('loaded', { width, height });
})
.catch((err) => {
// If the texture has been freed while loading, return early.
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'failed';
this.textureSource.setState('failed', err);
this.state = 'failed';
this.textureSource.setCoreCtxState('failed', err);
console.error(err);

@@ -132,2 +136,4 @@ });

const { glw } = this;
const textureData = this.textureSource.textureData;
assertTruthy(textureData, 'Texture data is null');

@@ -138,6 +144,5 @@ // Set to a 1x1 transparent texture

const textureData = await this.textureSource?.getTextureData();
// If the texture has been freed while loading, return early.
if (!this._nativeCtxTexture) {
assertTruthy(this._state === 'freed');
assertTruthy(this.state === 'freed');
return { width: 0, height: 0 };

@@ -148,5 +153,8 @@ }

assertTruthy(this._nativeCtxTexture);
glw.activeTexture(0);
const tdata = textureData.data;
const format = textureData.premultiplyAlpha ? glw.RGBA : glw.RGB;
const formatBytes = format === glw.RGBA ? 4 : 3;
// If textureData is null, the texture is empty (0, 0) and we don't need to

@@ -168,4 +176,4 @@ // upload any data to the GPU.

glw.texImage2D(0, glw.RGBA, glw.RGBA, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * 4);
glw.texImage2D(0, format, format, glw.UNSIGNED_BYTE, tdata);
this.setTextureMemUse(width * height * formatBytes);

@@ -184,7 +192,7 @@ // generate mipmaps for power-of-2 textures or in WebGL2RenderingContext

0,
glw.RGBA,
format,
1,
1,
0,
glw.RGBA,
format,
glw.UNSIGNED_BYTE,

@@ -223,7 +231,7 @@ TRANSPARENT_TEXTURE_DATA,

0,
glw.RGBA,
format,
width,
height,
0,
glw.RGBA,
format,
glw.UNSIGNED_BYTE,

@@ -233,3 +241,3 @@ tdata,

this.setTextureMemUse(width * height * 4);
this.setTextureMemUse(width * height * formatBytes);
} else {

@@ -254,7 +262,7 @@ console.error(

free() {
if (this._state === 'freed') {
if (this.state === 'freed') {
return;
}
this._state = 'freed';
this.textureSource.setState('freed');
this.state = 'freed';
this.textureSource.setCoreCtxState('freed');
this._w = 0;

@@ -261,0 +269,0 @@ this._h = 0;

@@ -39,3 +39,2 @@ /*

import { Texture, TextureType } from '../../textures/Texture.js';
import { ColorTexture } from '../../textures/ColorTexture.js';
import { SubTexture } from '../../textures/SubTexture.js';

@@ -57,3 +56,2 @@ import { WebGlCoreCtxSubTexture } from './WebGlCoreCtxSubTexture.js';

import type { BaseShaderController } from '../../../main-api/ShaderController.js';
import { ImageTexture } from '../../textures/ImageTexture.js';

@@ -100,3 +98,2 @@ const WORDS_PER_QUAD = 24;

*/
defaultTexture: Texture;

@@ -120,15 +117,2 @@ quadBufferUsage = 0;

this.defaultTexture = new ColorTexture(this.txManager);
// Mark the default texture as ALWAYS renderable
// This prevents it from ever being cleaned up.
// Fixes https://github.com/lightning-js/renderer/issues/262
this.defaultTexture.setRenderableOwner(this, true);
// When the default texture is loaded, request a render in case the
// RAF is paused. Fixes: https://github.com/lightning-js/renderer/issues/123
this.defaultTexture.once('loaded', () => {
this.stage.requestRender();
});
const gl = createWebGLContext(

@@ -244,4 +228,6 @@ canvas,

const { fQuadBuffer, uiQuadBuffer } = this;
let texture = params.texture || this.defaultTexture;
let texture = params.texture;
assertTruthy(texture !== null, 'Texture is required');
/**

@@ -263,4 +249,2 @@ * If the shader props contain any automatic properties, update it with the

assertTruthy(texture.ctxTexture !== undefined, 'Invalid texture type');
let { curBufferIdx: bufferIdx, curRenderOp } = this;

@@ -279,3 +263,2 @@ const targetDims = { width: -1, height: -1 };

if (this.reuseRenderOp(params) === false) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.newRenderOp(

@@ -363,3 +346,3 @@ targetShader,

const ctxTexture = texture.ctxTexture as WebGlCoreCtxTexture;
assertTruthy(ctxTexture.ctxTexture !== undefined);
assertTruthy(ctxTexture instanceof WebGlCoreCtxTexture);
const textureIdx = this.addTexture(ctxTexture, bufferIdx);

@@ -734,2 +717,7 @@

if (!node.texture || !node.texture.ctxTexture) {
console.warn('Texture not loaded for RTT node', node);
continue;
}
// Set the active RTT node to the current node

@@ -736,0 +724,0 @@ // So we can prevent rendering children of nested RTT nodes

@@ -56,2 +56,4 @@ /*

import { createBound, createPreloadBounds, type Bound } from './lib/utils.js';
import type { Texture } from './textures/Texture.js';
import { ColorTexture } from './textures/ColorTexture.js';

@@ -77,2 +79,3 @@ export interface StageOptions {

strictBounds: boolean;
textureProcessingLimit: number;
}

@@ -108,2 +111,3 @@

public readonly strictBounds: boolean;
public readonly defaultTexture: Texture | null = null;

@@ -154,2 +158,9 @@ /**

this.txManager = new CoreTextureManager(numImageWorkers);
// Wait for the Texture Manager to initialize
// once it does, request a render
this.txManager.on('initialized', () => {
this.requestRender();
});
this.txMemManager = new TextureMemoryManager(this, textureMemory);

@@ -190,2 +201,3 @@ this.shManager = new CoreShaderManager();

this.createDefaultTexture();
this.defShaderCtr = this.renderer.getDefShaderCtr();

@@ -298,2 +310,29 @@ setPremultiplyMode(renderMode);

/**
* Create default PixelTexture
*/
createDefaultTexture() {
(this.defaultTexture as ColorTexture) = this.txManager.createTexture(
'ColorTexture',
{
color: 0xffffffff,
},
);
assertTruthy(this.defaultTexture instanceof ColorTexture);
this.txManager.loadTexture(this.defaultTexture, true);
// Mark the default texture as ALWAYS renderable
// This prevents it from ever being cleaned up.
// Fixes https://github.com/lightning-js/renderer/issues/262
this.defaultTexture.setRenderableOwner(this, true);
// When the default texture is loaded, request a render in case the
// RAF is paused. Fixes: https://github.com/lightning-js/renderer/issues/123
this.defaultTexture.once('loaded', () => {
this.requestRender();
});
}
/**
* Update animations

@@ -314,3 +353,7 @@ */

hasSceneUpdates() {
return !!this.root.updateType || this.renderRequested;
return (
!!this.root.updateType ||
this.renderRequested ||
this.txManager.hasUpdates()
);
}

@@ -330,2 +373,6 @@

// Process some textures
// TODO this should have a configurable amount
this.txManager.processSome(this.options.textureProcessingLimit);
// Reset render operations and clear the canvas

@@ -332,0 +379,0 @@ renderer.reset();

@@ -80,3 +80,3 @@ /*

// Load image
this.texture = stage.txManager.loadTexture('ImageTexture', {
this.texture = stage.txManager.createTexture('ImageTexture', {
src: atlasUrl,

@@ -90,2 +90,5 @@ // IMPORTANT: The SDF shader requires the alpha channel to NOT be

// Load the texture
stage.txManager.loadTexture(this.texture, true);
this.texture.on('loaded', () => {

@@ -97,7 +100,2 @@ this.checkLoaded();

// Pre-load it
stage.txManager.once('initialized', () => {
this.texture.ctxTexture.load();
});
// Set this.data to the fetched data from dataUrl

@@ -104,0 +102,0 @@ fetch(atlasDataUrl)

@@ -340,3 +340,4 @@ /*

const texture = this.stage.txManager.loadTexture('ImageTexture', {
const texture = this.stage.txManager.createTexture('ImageTexture', {
premultiplyAlpha: true,
src: function (

@@ -364,2 +365,3 @@ this: CanvasTextRenderer,

});
if (state.textureNode) {

@@ -366,0 +368,0 @@ // Use the existing texture node

@@ -146,3 +146,2 @@ /*

if (criticalThreshold === 0) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.setTextureMemUse = () => {};

@@ -232,3 +231,3 @@ }

if (texture.preventCleanup === false) {
texture.ctxTexture.free();
texture.free();
txManager.removeTextureFromCache(texture);

@@ -263,3 +262,2 @@ }

const renderableMemUsed = [...this.loadedTextures.keys()].reduce(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(acc, texture) => {

@@ -266,0 +264,0 @@ renderableTexturesLoaded += texture.renderable ? 1 : 0;

@@ -65,3 +65,3 @@ /*

override async getTextureData(): Promise<TextureData> {
override async getTextureSource(): Promise<TextureData> {
const pixelData = new Uint8Array(4);

@@ -81,2 +81,4 @@

this.setSourceState('loaded', { width: 1, height: 1 });
return {

@@ -83,0 +85,0 @@ data: pixelData,

@@ -122,3 +122,3 @@ /*

export class ImageTexture extends Texture {
props: Required<ImageTextureProps>;
public props: Required<ImageTextureProps>;

@@ -230,3 +230,44 @@ public override type: TextureType = TextureType.image;

override async getTextureData(): Promise<TextureData> {
override async getTextureSource(): Promise<TextureData> {
let resp;
try {
resp = await this.determineImageTypeAndLoadImage();
} catch (e) {
this.setSourceState('failed', e as Error);
return {
data: null,
};
}
if (resp.data === null) {
this.setSourceState('failed', Error('ImageTexture: No image data'));
return {
data: null,
};
}
let width, height;
// check if resp.data is typeof Uint8ClampedArray else
// use resp.data.width and resp.data.height
if (resp.data instanceof Uint8Array) {
width = this.props.width ?? 0;
height = this.props.height ?? 0;
} else {
width = resp.data?.width ?? (this.props.width || 0);
height = resp.data?.height ?? (this.props.height || 0);
}
// we're loaded!
this.setSourceState('loaded', {
width,
height,
});
return {
data: resp.data,
premultiplyAlpha: this.props.premultiplyAlpha ?? true,
};
}
determineImageTypeAndLoadImage() {
const { src, premultiplyAlpha, type } = this.props;

@@ -233,0 +274,0 @@ if (src === null) {

@@ -66,3 +66,3 @@ /*

override async getTextureData(): Promise<TextureData> {
override async getTextureSource(): Promise<TextureData> {
const { width, height } = this.props;

@@ -78,2 +78,5 @@ const size = width * height * 4;

}
this.setSourceState('loaded');
return {

@@ -80,0 +83,0 @@ data: new ImageData(pixelData8, width, height),

@@ -66,3 +66,5 @@ /*

override async getTextureData(): Promise<TextureData> {
override async getTextureSource(): Promise<TextureData> {
this.setSourceState('loaded');
return {

@@ -69,0 +71,0 @@ data: null,

@@ -20,3 +20,5 @@ /*

import { assertTruthy } from '../../utils.js';
import type { CoreTextureManager } from '../CoreTextureManager.js';
import { ImageTexture } from './ImageTexture.js';
import {

@@ -87,4 +89,18 @@ Texture,

this.props = SubTexture.resolveDefaults(props || {});
this.parentTexture = this.props.texture;
assertTruthy(this.props.texture, 'SubTexture requires a parent texture');
assertTruthy(
this.props.texture instanceof ImageTexture,
'SubTexture requires an ImageTexture parent',
);
// Resolve parent texture from cache or fallback to provided texture
this.parentTexture = txManager.resolveParentTexture(this.props.texture);
if (this.parentTexture.state === 'freed') {
this.txManager.loadTexture(this.parentTexture);
}
this.parentTexture.setRenderableOwner(this, true);
// If parent texture is already loaded / failed, trigger loaded event manually

@@ -109,10 +125,18 @@ // so that users get a consistent event experience.

// configured dimensions (because that's all that matters here)
this.setState('loaded', {
this.setSourceState('loaded', {
width: this.props.width,
height: this.props.height,
});
// If the parent already has a ctxTexture, we can set the core ctx state
if (this.parentTexture.ctxTexture !== undefined) {
this.setCoreCtxState('loaded', {
width: this.props.width,
height: this.props.height,
});
}
};
private onParentTxFailed: TextureFailedEventHandler = (target, error) => {
this.setState('failed', error);
this.setSourceState('failed', error);
};

@@ -125,3 +149,4 @@

override async getTextureData(): Promise<TextureData> {
override async getTextureSource(): Promise<TextureData> {
// Check if parent texture is loaded
return {

@@ -128,0 +153,0 @@ data: this.props,

@@ -122,2 +122,4 @@ /*

export type UpdateType = 'source' | 'coreCtx';
/**

@@ -156,3 +158,8 @@ * Like the built-in Parameters<> type but skips the first parameter (which is

readonly state: TextureState = 'freed';
// aggregate state
public state: TextureState = 'freed';
// texture source state
private sourceState: TextureState = 'freed';
// texture (gpu) state
private coreCtxState: TextureState = 'freed';

@@ -169,2 +176,6 @@ readonly renderableOwners = new Set<unknown>();

public ctxTexture: CoreContextTexture | undefined;
public textureData: TextureData | null = null;
constructor(protected txManager: CoreTextureManager) {

@@ -194,3 +205,2 @@ super();

if (newSize > oldSize && newSize === 1) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(this.renderable as boolean) = true;

@@ -204,3 +214,2 @@ (this.lastRenderableChangeTime as number) = this.txManager.frameTime;

if (newSize < oldSize && newSize === 0) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(this.renderable as boolean) = false;

@@ -225,50 +234,115 @@ (this.lastRenderableChangeTime as number) = this.txManager.frameTime;

/**
* Get the CoreContextTexture for this Texture
* Load the core context texture for this Texture.
* The ctxTexture is created by the renderer and lives on the GPU.
*
* @returns
*/
loadCtxTexture(): CoreContextTexture {
if (this.ctxTexture === undefined) {
this.ctxTexture = this.txManager.renderer.createCtxTexture(this);
}
return this.ctxTexture;
}
/**
* Free the core context texture for this Texture.
*
* @remarks
* Each Texture has a corresponding CoreContextTexture that is used to
* manage the texture's native data depending on the renderer's mode
* (WebGL, Canvas, etc).
* The ctxTexture is created by the renderer and lives on the GPU.
*/
free(): void {
this.ctxTexture?.free();
if (this.textureData !== null) {
this.textureData = null;
}
}
private setState(
state: TextureState,
type: UpdateType,
errorOrDimensions?: Error | Dimensions,
): void {
const stateObj = type === 'source' ? 'sourceState' : 'coreCtxState';
if (this[stateObj] === state) {
return;
}
this[stateObj] = state;
if (state === 'loaded') {
(this.dimensions as Dimensions) = errorOrDimensions as Dimensions;
} else if (state === 'failed') {
(this.error as Error) = errorOrDimensions as Error;
}
this.updateState();
}
/**
* Set the source state of the texture
*
* The Texture and CoreContextTexture are always linked together in a 1:1
* relationship.
* @remarks
* The source of the texture can either be generated by the texture itself or
* loaded from an external source.
*
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
get ctxTexture() {
// The first time this is called, create the ctxTexture
const ctxTexture = this.txManager.renderer.createCtxTexture(this);
// And replace this getter with the value for future calls
Object.defineProperty(this, 'ctxTexture', { value: ctxTexture });
return ctxTexture;
public setSourceState(
state: TextureState,
errorOrDimensions?: Error | Dimensions,
): void {
this.setState(state, 'source', errorOrDimensions);
}
/**
* Set the state of the texture
* Set the core context state of the texture
*
* @remark
* Intended for internal-use only but declared public so that it can be set
* by it's associated {@link CoreContextTexture}
* @remarks
* The core context state of the texture is the state of the texture on the GPU.
*
* @param state
* @param args
* @param state State of the texture
* @param errorOrDimensions Error or dimensions of the texture
*/
setState<State extends TextureState>(
state: State,
...args: ParametersSkipTarget<TextureStateEventMap[State]>
public setCoreCtxState(
state: TextureState,
errorOrDimensions?: Error | Dimensions,
): void {
if (this.state !== state) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(this.state as TextureState) = state;
if (state === 'loaded') {
const loadedArgs = args as ParametersSkipTarget<
TextureStateEventMap['loaded']
>;
(this.dimensions as Dimensions) = loadedArgs[0];
} else if (state === 'failed') {
const failedArgs = args as ParametersSkipTarget<
TextureStateEventMap['failed']
>;
(this.error as Error) = failedArgs[0];
}
this.emit(state, ...args);
this.setState(state, 'coreCtx', errorOrDimensions);
}
private updateState(): void {
const ctxState = this.coreCtxState;
const sourceState = this.sourceState;
let newState: TextureState = 'freed';
let payload: Error | Dimensions | null = null;
if (sourceState === 'failed' || ctxState === 'failed') {
newState = 'failed';
payload = this.error; // Error set by the source
} else if (sourceState === 'loading' || ctxState === 'loading') {
newState = 'loading';
} else if (sourceState === 'loaded' && ctxState === 'loaded') {
newState = 'loaded';
payload = this.dimensions; // Dimensions set by the source
} else if (
(sourceState === 'loaded' && ctxState === 'freed') ||
(ctxState === 'loaded' && sourceState === 'freed')
) {
// If one is loaded and the other is freed, then we are in a loading state
newState = 'loading';
} else {
newState = 'freed';
}
if (this.state === newState) {
return;
}
// emit the new state
this.state = newState;
this.emit(newState, payload);
}

@@ -286,5 +360,20 @@

*/
abstract getTextureData(): Promise<TextureData>;
async getTextureData(): Promise<TextureData> {
if (this.textureData === null) {
this.textureData = await this.getTextureSource();
}
return this.textureData;
}
/**
* Get the texture source for this texture.
*
* @remarks
* This method is called by the CoreContextTexture when the texture is loaded.
* The texture source is then used to populate the CoreContextTexture.
*/
abstract getTextureSource(): Promise<TextureData>;
/**
* Make a cache key for this texture.

@@ -291,0 +380,0 @@ *

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ interface ImportMetaEnv {

@@ -0,0 +0,0 @@ import type { ShaderEffectValueMap } from '../../exports/index.js';

@@ -0,0 +0,0 @@ /*

@@ -0,0 +0,0 @@ import {

@@ -270,2 +270,22 @@ /*

strictBounds?: boolean;
/**
* Texture Processing Limit
*
* @remarks
* The maximum number of textures to process in a single frame. This is used to
* prevent the renderer from processing too many textures in a single frame.
*
* @defaultValue `0`
*/
textureProcessingLimit?: number;
/**
* Canvas object to use for rendering
*
* @remarks
* This is used to render the scene graph. If not provided, a new canvas
* element will be created and appended to the target element.
*/
canvas?: HTMLCanvasElement;
}

@@ -362,2 +382,4 @@

strictBounds: settings.strictBounds ?? true,
textureProcessingLimit: settings.textureProcessingLimit || 0,
canvas: settings.canvas || document.createElement('canvas'),
};

@@ -372,2 +394,3 @@ this.settings = resolvedSettings;

inspector,
canvas,
} = resolvedSettings;

@@ -378,3 +401,2 @@

const canvas = document.createElement('canvas');
this.canvas = canvas;

@@ -407,2 +429,3 @@ canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;

strictBounds: this.settings.strictBounds,
textureProcessingLimit: this.settings.textureProcessingLimit,
});

@@ -524,3 +547,3 @@

): InstanceType<TextureMap[TxType]> {
return this.stage.txManager.loadTexture(textureType, props);
return this.stage.txManager.createTexture(textureType, props);
}

@@ -665,3 +688,3 @@

rerender() {
throw new Error('Not implemented');
this.stage.requestRender();
}

@@ -668,0 +691,0 @@

@@ -0,0 +0,0 @@ import type { CustomDataMap } from '../core/CoreNode.js';

@@ -0,0 +0,0 @@ /*

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc