@lightningtv/renderer
Version:
Lightning 3 Renderer
861 lines (860 loc) • 27.7 kB
TypeScript
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 { Dimensions } from '../common/CommonTypes.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { type Bound, type RectWithValid } from './lib/utils.js';
import { Matrix3d } from './lib/Matrix3d.js';
import { RenderCoords } from './lib/RenderCoords.js';
import type { AnimationSettings } from './animations/CoreAnimation.js';
import type { IAnimationController } from '../common/IAnimationController.js';
import type { CoreShaderNode } from './renderers/CoreShaderNode.js';
export declare enum CoreNodeRenderState {
Init = 0,
OutOfBounds = 2,
InBounds = 4,
InViewport = 8
}
export declare enum UpdateType {
/**
* Child updates
*/
Children = 1,
/**
* Scale/Rotate transform update
*
* @remarks
* CoreNode Properties Updated:
* - `scaleRotateTransform`
*/
ScaleRotate = 2,
/**
* Translate transform update (x/y/width/height/pivot/mount)
*
* @remarks
* CoreNode Properties Updated:
* - `localTransform`
*/
Local = 4,
/**
* Global Transform update
*
* @remarks
* CoreNode Properties Updated:
* - `globalTransform`
* - `renderCoords`
* - `renderBound`
*/
Global = 8,
/**
* Clipping rect update
*
* @remarks
* CoreNode Properties Updated:
* - `clippingRect`
*/
Clipping = 16,
/**
* Calculated ZIndex update
*
* @remarks
* CoreNode Properties Updated:
* - `calcZIndex`
*/
CalculatedZIndex = 32,
/**
* Z-Index Sorted Children update
*
* @remarks
* CoreNode Properties Updated:
* - `children` (sorts children by their `calcZIndex`)
*/
ZIndexSortedChildren = 64,
/**
* Premultiplied Colors update
*
* @remarks
* CoreNode Properties Updated:
* - `premultipliedColorTl`
* - `premultipliedColorTr`
* - `premultipliedColorBl`
* - `premultipliedColorBr`
*/
PremultipliedColors = 128,
/**
* World Alpha update
*
* @remarks
* CoreNode Properties Updated:
* - `worldAlpha` = `parent.worldAlpha` * `alpha`
*/
WorldAlpha = 256,
/**
* Render State update
*
* @remarks
* CoreNode Properties Updated:
* - `renderState`
*/
RenderState = 512,
/**
* Is Renderable update
*
* @remarks
* CoreNode Properties Updated:
* - `isRenderable`
*/
IsRenderable = 1024,
/**
* Render Texture update
*/
RenderTexture = 2048,
/**
* Track if parent has render texture
*/
ParentRenderTexture = 4096,
/**
* Render Bounds update
*/
RenderBounds = 8192,
/**
* None
*/
None = 0,
/**
* All
*/
All = 14335,
/**
* RecalcUniforms
*/
RecalcUniforms = 16384
}
/**
* A custom data map which can be stored on an CoreNode
*
* @remarks
* This is a map of key-value pairs that can be stored on an INode. It is used
* to store custom data that can be used by the application.
* The data stored can only be of type string, number or boolean.
*/
export type CustomDataMap = {
[key: string]: string | number | boolean | undefined;
};
/**
* Writable properties of a Node.
*/
export interface CoreNodeProps {
/**
* The x coordinate of the Node's Mount Point.
*
* @remarks
* See {@link mountX} and {@link mountY} for more information about setting
* the Mount Point.
*
* @default `0`
*/
x: number;
/**
* The y coordinate of the Node's Mount Point.
*
* @remarks
* See {@link mountX} and {@link mountY} for more information about setting
* the Mount Point.
*
* @default `0`
*/
y: number;
/**
* The width of the Node.
*
* @default `0`
*/
width: number;
/**
* The height of the Node.
*
* @default `0`
*/
height: number;
/**
* The alpha opacity of the Node.
*
* @remarks
* The alpha value is a number between 0 and 1, where 0 is fully transparent
* and 1 is fully opaque.
*
* @default `1`
*/
alpha: number;
/**
* Autosize mode
*
* @remarks
* When enabled, when a texture is loaded into the Node, the Node will
* automatically resize to the dimensions of the texture.
*
* Text Nodes are always autosized based on their text content regardless
* of this mode setting.
*
* @default `false`
*/
autosize: boolean;
/**
* Margin around the Node's bounds for preloading
*
* @default `null`
*/
boundsMargin: number | [number, number, number, number] | null;
/**
* Clipping Mode
*
* @remarks
* Enable Clipping Mode when you want to prevent the drawing of a Node and
* its descendants from overflowing outside of the Node's x/y/width/height
* bounds.
*
* For WebGL, clipping is implemented using the high-performance WebGL
* operation scissor. As a consequence, clipping does not work for
* non-rectangular areas. So, if the element is rotated
* (by itself or by any of its ancestors), clipping will not work as intended.
*
* TODO: Add support for non-rectangular clipping either automatically or
* via Render-To-Texture.
*
* @default `false`
*/
clipping: boolean;
/**
* The color of the Node.
*
* @remarks
* The color value is a number in the format 0xRRGGBBAA, where RR is the red
* component, GG is the green component, BB is the blue component, and AA is
* the alpha component.
*
* Gradient colors may be set by setting the different color sub-properties:
* {@link colorTop}, {@link colorBottom}, {@link colorLeft}, {@link colorRight},
* {@link colorTl}, {@link colorTr}, {@link colorBr}, {@link colorBl} accordingly.
*
* @default `0xffffffff` (opaque white)
*/
color: number;
/**
* The color of the top edge of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorTop: number;
/**
* The color of the bottom edge of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorBottom: number;
/**
* The color of the left edge of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorLeft: number;
/**
* The color of the right edge of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorRight: number;
/**
* The color of the top-left corner of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorTl: number;
/**
* The color of the top-right corner of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorTr: number;
/**
* The color of the bottom-right corner of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorBr: number;
/**
* The color of the bottom-left corner of the Node for gradient rendering.
*
* @remarks
* See {@link color} for more information about color values and gradient
* rendering.
*/
colorBl: number;
/**
* The Node's parent Node.
*
* @remarks
* The value `null` indicates that the Node has no parent. This may either be
* because the Node is the root Node of the scene graph, or because the Node
* has been removed from the scene graph.
*
* In order to make sure that a Node can be rendered on the screen, it must
* be added to the scene graph by setting it's parent property to a Node that
* is already in the scene graph such as the root Node.
*
* @default `null`
*/
parent: CoreNode | null;
/**
* The Node's z-index.
*
* @remarks
* TBD
*/
zIndex: number;
/**
* The Node's Texture.
*
* @remarks
* The `texture` defines a rasterized image that is contained within the
* {@link width} and {@link height} dimensions of the Node. If null, the
* Node will use an opaque white {@link ColorTexture} when being drawn, which
* essentially enables colors (including gradients) to be drawn.
*
* If set, by default, the texture will be drawn, as is, stretched to the
* dimensions of the Node. This behavior can be modified by setting the TBD
* and TBD properties.
*
* To create a Texture in order to set it on this property, call
* {@link RendererMain.createTexture}.
*
* If the {@link src} is set on a Node, the Node will use the
* {@link ImageTexture} by default and the Node will simply load the image at
* the specified URL.
*
* Note: If this is a Text Node, the Texture will be managed by the Node's
* {@link TextRenderer} and should not be set explicitly.
*/
texture: Texture | null;
/**
* [Deprecated]: Prevents the texture from being cleaned up when the Node is removed
*
* @remarks
* Please use the `preventCleanup` property on {@link TextureOptions} instead.
*
* @default false
*/
preventCleanup: boolean;
/**
* Options to associate with the Node's Texture
*/
textureOptions: TextureOptions;
/**
* The Node's shader
*
* @remarks
* The `shader` defines a {@link Shader} used to draw the Node. By default,
* the Default Shader is used which simply draws the defined {@link texture}
* or {@link color}(s) within the Node without any special effects.
*
* To create a Shader in order to set it on this property, call
* {@link RendererMain.createShader}.
*
* Note: If this is a Text Node, the Shader will be managed by the Node's
* {@link TextRenderer} and should not be set explicitly.
*/
shader: CoreShaderNode<any> | null;
/**
* Image URL
*
* @remarks
* When set, the Node's {@link texture} is automatically set to an
* {@link ImageTexture} using the source image URL provided (with all other
* settings being defaults)
*/
src: string | null;
zIndexLocked: number;
/**
* Scale to render the Node at
*
* @remarks
* The scale value multiplies the provided {@link width} and {@link height}
* of the Node around the Node's Pivot Point (defined by the {@link pivot}
* props).
*
* Behind the scenes, setting this property sets both the {@link scaleX} and
* {@link scaleY} props to the same value.
*
* NOTE: When the scaleX and scaleY props are explicitly set to different values,
* this property returns `null`. Setting `null` on this property will have no
* effect.
*
* @default 1.0
*/
scale: number | null;
/**
* Scale to render the Node at (X-Axis)
*
* @remarks
* The scaleX value multiplies the provided {@link width} of the Node around
* the Node's Pivot Point (defined by the {@link pivot} props).
*
* @default 1.0
*/
scaleX: number;
/**
* Scale to render the Node at (Y-Axis)
*
* @remarks
* The scaleY value multiplies the provided {@link height} of the Node around
* the Node's Pivot Point (defined by the {@link pivot} props).
*
* @default 1.0
*/
scaleY: number;
/**
* Combined position of the Node's Mount Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Mount Point at the top-left corner of the Node.
* - `0.5` defines it at the center of the Node.
* - `1.0` defines it at the bottom-right corner of the node.
*
* Use the {@link mountX} and {@link mountY} props seperately for more control
* of the Mount Point.
*
* When assigned, the same value is also passed to both the {@link mountX} and
* {@link mountY} props.
*
* @default 0 (top-left)
*/
mount: number;
/**
* X position of the Node's Mount Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Mount Point's X position as the left-most edge of the
* Node
* - `0.5` defines it as the horizontal center of the Node
* - `1.0` defines it as the right-most edge of the Node.
*
* The combination of {@link mountX} and {@link mountY} define the Mount Point
*
* @default 0 (left-most edge)
*/
mountX: number;
/**
* Y position of the Node's Mount Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Mount Point's Y position as the top-most edge of the
* Node
* - `0.5` defines it as the vertical center of the Node
* - `1.0` defines it as the bottom-most edge of the Node.
*
* The combination of {@link mountX} and {@link mountY} define the Mount Point
*
* @default 0 (top-most edge)
*/
mountY: number;
/**
* Combined position of the Node's Pivot Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Pivot Point at the top-left corner of the Node.
* - `0.5` defines it at the center of the Node.
* - `1.0` defines it at the bottom-right corner of the node.
*
* Use the {@link pivotX} and {@link pivotY} props seperately for more control
* of the Pivot Point.
*
* When assigned, the same value is also passed to both the {@link pivotX} and
* {@link pivotY} props.
*
* @default 0.5 (center)
*/
pivot: number;
/**
* X position of the Node's Pivot Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Pivot Point's X position as the left-most edge of the
* Node
* - `0.5` defines it as the horizontal center of the Node
* - `1.0` defines it as the right-most edge of the Node.
*
* The combination of {@link pivotX} and {@link pivotY} define the Pivot Point
*
* @default 0.5 (centered on x-axis)
*/
pivotX: number;
/**
* Y position of the Node's Pivot Point
*
* @remarks
* The value can be any number between `0.0` and `1.0`:
* - `0.0` defines the Pivot Point's Y position as the top-most edge of the
* Node
* - `0.5` defines it as the vertical center of the Node
* - `1.0` defines it as the bottom-most edge of the Node.
*
* The combination of {@link pivotX} and {@link pivotY} define the Pivot Point
*
* @default 0.5 (centered on y-axis)
*/
pivotY: number;
/**
* Rotation of the Node (in Radians)
*
* @remarks
* Sets the amount to rotate the Node by around it's Pivot Point (defined by
* the {@link pivot} props). Positive values rotate the Node clockwise, while
* negative values rotate it counter-clockwise.
*
* Example values:
* - `-Math.PI / 2`: 90 degree rotation counter-clockwise
* - `0`: No rotation
* - `Math.PI / 2`: 90 degree rotation clockwise
* - `Math.PI`: 180 degree rotation clockwise
* - `3 * Math.PI / 2`: 270 degree rotation clockwise
* - `2 * Math.PI`: 360 rotation clockwise
*/
rotation: number;
/**
* Whether the Node is rendered to a texture
*
* @remarks
* TBD
*
* @default false
*/
rtt: boolean;
/**
* Node data element for custom data storage (optional)
*
* @remarks
* This property is used to store custom data on the Node as a key/value data store.
* Data values are limited to string, numbers, booleans. Strings will be truncated
* to a 2048 character limit for performance reasons.
*
* This is not a data storage mechanism for large amounts of data please use a
* dedicated data storage mechanism for that.
*
* The custom data will be reflected in the inspector as part of `data-*` attributes
*
* @default `undefined`
*/
data?: CustomDataMap;
/**
* Image Type to explicitly set the image type that is being loaded
*
* @remarks
* This property must be used with a `src` that points at an image. In some cases
* the extension doesn't provide a reliable representation of the image type. In such
* cases set the ImageType explicitly.
*
* `regular` is used for normal images such as png, jpg, etc
* `compressed` is used for ETC1/ETC2 compressed images with a PVR or KTX container
* `svg` is used for scalable vector graphics
*
* @default `undefined`
*/
imageType?: 'regular' | 'compressed' | 'svg' | null;
/**
* She width of the rectangle from which the Image Texture will be extracted.
* This value can be negative. If not provided, the image's source natural
* width will be used.
*/
srcWidth?: number;
/**
* The height of the rectangle from which the Image Texture will be extracted.
* This value can be negative. If not provided, the image's source natural
* height will be used.
*/
srcHeight?: number;
/**
* The x coordinate of the reference point of the rectangle from which the Texture
* will be extracted. `width` and `height` are provided. And only works when
* createImageBitmap is available. Only works when createImageBitmap is supported on the browser.
*/
srcX?: number;
/**
* The y coordinate of the reference point of the rectangle from which the Texture
* will be extracted. Only used when source `srcWidth` width and `srcHeight` height
* are provided. Only works when createImageBitmap is supported on the browser.
*/
srcY?: number;
/**
* By enabling Strict bounds the renderer will not process & render child nodes of a node that is out of the visible area
*
* @remarks
* When enabled out of bound nodes, i.e. nodes that are out of the visible area, will
* **NOT** have their children processed and renderer anymore. This means the children of a out of bound
* node will not receive update processing such as positioning updates and will not be drawn on screen.
* As such the rest of the branch of the update tree that sits below this node will not be processed anymore
*
* This is a big performance gain but may be disabled in cases where the width of the parent node is
* unknown and the render must process the child nodes regardless of the viewport status of the parent node
*
* @default false
*/
strictBounds: boolean;
}
/**
* Grab all the number properties of type T
*/
type NumberProps<T> = {
[Key in keyof T as NonNullable<T[Key]> extends number ? Key : never]: number;
};
/**
* Properties of a Node used by the animate() function
*/
export interface CoreNodeAnimateProps extends NumberProps<CoreNodeProps> {
/**
* Shader properties to animate
*/
shaderProps: Record<string, number>;
}
/**
* A visual Node in the Renderer scene graph.
*
* @remarks
* CoreNode is an internally used class that represents a Renderer Node in the
* scene graph. See INode.ts for the public APIs exposed to Renderer users
* that include generic types for Shaders.
*/
export declare class CoreNode extends EventEmitter {
readonly stage: Stage;
readonly children: CoreNode[];
protected _id: number;
readonly props: CoreNodeProps;
updateType: UpdateType;
childUpdateType: UpdateType;
globalTransform?: Matrix3d;
scaleRotateTransform?: Matrix3d;
localTransform?: Matrix3d;
sceneGlobalTransform?: Matrix3d;
renderCoords?: RenderCoords;
sceneRenderCoords?: RenderCoords;
renderBound?: Bound;
strictBound?: Bound;
preloadBound?: Bound;
clippingRect: RectWithValid;
isRenderable: boolean;
renderState: CoreNodeRenderState;
worldAlpha: number;
premultipliedColorTl: number;
premultipliedColorTr: number;
premultipliedColorBl: number;
premultipliedColorBr: number;
calcZIndex: number;
hasRTTupdates: boolean;
parentHasRenderTexture: boolean;
rttParent: CoreNode | null;
constructor(stage: Stage, props: CoreNodeProps);
loadTexture(): void;
unloadTexture(): void;
autosizeNode(dimensions: Dimensions): void;
private onTextureLoaded;
private onTextureFailed;
private onTextureFreed;
/**
* Change types types is used to determine the scope of the changes being applied
*
* @remarks
* See {@link UpdateType} for more information on each type
*
* @param type
*/
setUpdateType(type: UpdateType): void;
sortChildren(): void;
updateScaleRotateTransform(): void;
updateLocalTransform(): void;
/**
* @todo: test for correct calculation flag
* @param delta
*/
update(delta: number, parentClippingRect: RectWithValid): void;
private findParentRTTNode;
private getRTTParentRenderState;
private notifyChildrenRTTOfUpdate;
private notifyParentRTTOfUpdate;
checkRenderBounds(): CoreNodeRenderState;
updateBoundingRect(): void;
createRenderBounds(): void;
updateRenderState(renderState: CoreNodeRenderState): void;
/**
* Updates the `isRenderable` property based on various conditions.
*/
updateIsRenderable(): void;
/**
* Checks if the node is renderable based on world alpha, dimensions and out of bounds status.
*/
checkBasicRenderability(): boolean;
/**
* Sets the renderable state and triggers changes if necessary.
* @param isRenderable - The new renderable state
*/
setRenderable(isRenderable: boolean): void;
/**
* Changes the renderable state of the node.
*/
updateTextureOwnership(isRenderable: boolean): void;
/**
* Checks if the node is out of the viewport bounds.
*/
isOutOfBounds(): boolean;
/**
* Checks if the node has dimensions (width/height)
*/
hasDimensions(): boolean;
/**
* Checks if the node has any color properties set.
*/
hasColorProperties(): boolean;
hasShader(): boolean;
calculateRenderCoords(): void;
/**
* This function calculates the clipping rectangle for a node.
*
* The function then checks if the node is rotated. If the node requires clipping and is not rotated, a new clipping rectangle is created based on the node's global transform and dimensions.
* If a parent clipping rectangle exists, it is intersected with the node's clipping rectangle (if it exists), or replaces the node's clipping rectangle.
*
* Finally, the node's parentClippingRect and clippingRect properties are updated.
*/
calculateClippingRect(parentClippingRect: RectWithValid): void;
calculateZIndex(): void;
/**
* Destroy the node and cleanup all resources
*/
destroy(): void;
renderQuads(renderer: CoreRenderer): void;
get id(): number;
get data(): CustomDataMap | undefined;
set data(d: CustomDataMap | undefined);
get x(): number;
set x(value: number);
get absX(): number;
get absY(): number;
get y(): number;
set y(value: number);
get width(): number;
set width(value: number);
get height(): number;
set height(value: number);
get scale(): number;
set scale(value: number);
get scaleX(): number;
set scaleX(value: number);
get scaleY(): number;
set scaleY(value: number);
get mount(): number;
set mount(value: number);
get mountX(): number;
set mountX(value: number);
get mountY(): number;
set mountY(value: number);
get pivot(): number;
set pivot(value: number);
get pivotX(): number;
set pivotX(value: number);
get pivotY(): number;
set pivotY(value: number);
get rotation(): number;
set rotation(value: number);
get alpha(): number;
set alpha(value: number);
get autosize(): boolean;
set autosize(value: boolean);
get boundsMargin(): number | [number, number, number, number] | null;
set boundsMargin(value: number | [number, number, number, number] | null);
get clipping(): boolean;
set clipping(value: boolean);
get color(): number;
set color(value: number);
get colorTop(): number;
set colorTop(value: number);
get colorBottom(): number;
set colorBottom(value: number);
get colorLeft(): number;
set colorLeft(value: number);
get colorRight(): number;
set colorRight(value: number);
get colorTl(): number;
set colorTl(value: number);
get colorTr(): number;
set colorTr(value: number);
get colorBl(): number;
set colorBl(value: number);
get colorBr(): number;
set colorBr(value: number);
get zIndexLocked(): number;
set zIndexLocked(value: number);
get zIndex(): number;
set zIndex(value: number);
get parent(): CoreNode | null;
set parent(newParent: CoreNode | null);
get preventCleanup(): boolean;
set preventCleanup(value: boolean);
get rtt(): boolean;
set rtt(value: boolean);
private initRenderTexture;
private cleanupRenderTexture;
private markChildrenWithRTT;
private applyRTTInheritance;
private clearRTTInheritance;
get shader(): CoreShaderNode<any> | null;
set shader(shader: CoreShaderNode<any> | null);
get src(): string | null;
set src(imageUrl: string | null);
set imageType(type: 'regular' | 'compressed' | 'svg' | null);
get imageType(): 'regular' | 'compressed' | 'svg' | null;
get srcHeight(): number | undefined;
set srcHeight(value: number);
get srcWidth(): number | undefined;
set srcWidth(value: number);
get srcX(): number | undefined;
set srcX(value: number);
get srcY(): number | undefined;
set srcY(value: number);
/**
* Returns the framebuffer dimensions of the node.
* If the node has a render texture, the dimensions are the same as the node's dimensions.
* If the node does not have a render texture, the dimensions are inherited from the parent.
* If the node parent has a render texture and the node is a render texture, the nodes dimensions are used.
*/
get framebufferDimensions(): Dimensions;
/**
* Returns the parent render texture node if it exists.
*/
get parentRenderTexture(): CoreNode | null;
get texture(): Texture | null;
set texture(value: Texture | null);
set textureOptions(value: TextureOptions);
get textureOptions(): TextureOptions;
get strictBounds(): boolean;
set strictBounds(v: boolean);
animate(props: Partial<CoreNodeAnimateProps>, settings: Partial<AnimationSettings>): IAnimationController;
flush(): void;
}
export {};