import { RENDERER_TYPE } from '@pixi/constants';
import { extensions, ExtensionType } from '@pixi/extensions';
import { Matrix } from '@pixi/math';
import { settings } from '@pixi/settings';
import { deprecation, isWebGLSupported } from '@pixi/utils';
import { UniformGroup } from './shader/UniformGroup';
import { SystemManager } from './system/SystemManager';
import type { ColorSource } from '@pixi/color';
import type { MSAA_QUALITY } from '@pixi/constants';
import type { ExtensionMetadata } from '@pixi/extensions';
import type { Rectangle } from '@pixi/math';
import type { ICanvas } from '@pixi/settings';
import type { BackgroundSystem } from './background/BackgroundSystem';
import type { BatchSystem } from './batch/BatchSystem';
import type { ContextSystem } from './context/ContextSystem';
import type { FilterSystem } from './filters/FilterSystem';
import type { FramebufferSystem } from './framebuffer/FramebufferSystem';
import type { MultisampleSystem } from './framebuffer/MultisampleSystem';
import type { BufferSystem } from './geometry/BufferSystem';
import type { GeometrySystem } from './geometry/GeometrySystem';
import type { IRenderableObject, IRenderer, IRendererOptions, IRendererRenderOptions, IRenderingContext } from './IRenderer';
import type { MaskSystem } from './mask/MaskSystem';
import type { ScissorSystem } from './mask/ScissorSystem';
import type { StencilSystem } from './mask/StencilSystem';
import type { IRendererPlugins, PluginSystem } from './plugin/PluginSystem';
import type { ProjectionSystem } from './projection/ProjectionSystem';
import type { ObjectRendererSystem } from './render/ObjectRendererSystem';
import type { GenerateTextureSystem, IGenerateTextureOptions } from './renderTexture/GenerateTextureSystem';
import type { RenderTexture } from './renderTexture/RenderTexture';
import type { RenderTextureSystem } from './renderTexture/RenderTextureSystem';
import type { ShaderSystem } from './shader/ShaderSystem';
import type { StartupSystem } from './startup/StartupSystem';
import type { StateSystem } from './state/StateSystem';
import type { TextureGCSystem } from './textures/TextureGCSystem';
import type { TextureSystem } from './textures/TextureSystem';
import type { TransformFeedbackSystem } from './transformFeedback/TransformFeedbackSystem';
import type { ViewSystem } from './view/ViewSystem';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Renderer extends GlobalMixins.Renderer {}
/**
* The Renderer draws the scene and all its content onto a WebGL enabled canvas.
*
* This renderer should be used for browsers that support WebGL.
*
* This renderer works by automatically managing WebGLBatches, so no need for Sprite Batches or Sprite Clouds.
* Don't forget to add the view to your DOM or you will not see anything!
*
* Renderer is composed of systems that manage specific tasks. The following systems are added by default
* whenever you create a renderer:
*
* | System | Description |
* | ------------------------------------ | ----------------------------------------------------------------------------- |
*
* | Generic Systems | Systems that manage functionality that all renderer types share |
* | ------------------------------------ | ----------------------------------------------------------------------------- |
* | PIXI.ViewSystem | This manages the main view of the renderer usually a Canvas |
* | PIXI.PluginSystem | This manages plugins for the renderer |
* | PIXI.BackgroundSystem | This manages the main views background color and alpha |
* | PIXI.StartupSystem | Boots up a renderer and initiatives all the systems |
* | PIXI.EventSystem | This manages UI events. |
*
* | WebGL Core Systems | Provide an optimised, easy to use API to work with WebGL |
* | ------------------------------------ | ----------------------------------------------------------------------------- |
* | PIXI.ContextSystem | This manages the WebGL context and extensions. |
* | PIXI.FramebufferSystem | This manages framebuffers, which are used for offscreen rendering. |
* | PIXI.GeometrySystem | This manages geometries & buffers, which are used to draw object meshes. |
* | PIXI.ShaderSystem | This manages shaders, programs that run on the GPU to calculate 'em pixels. |
* | PIXI.StateSystem | This manages the WebGL state variables like blend mode, depth testing, etc. |
* | PIXI.TextureSystem | This manages textures and their resources on the GPU. |
* | PIXI.TextureGCSystem | This will automatically remove textures from the GPU if they are not used. |
* | PIXI.MultisampleSystem | This manages the multisample const on the WEbGL Renderer |
*
* | PixiJS High-Level Systems | Set of specific systems designed to work with PixiJS objects |
* | ------------------------------------ | ----------------------------------------------------------------------------- |
* | PIXI.GenerateTextureSystem | This adds the ability to generate textures from any PIXI.DisplayObject |
* | PIXI.ProjectionSystem | This manages the `projectionMatrix`, used by shaders to get NDC coordinates. |
* | PIXI.RenderTextureSystem | This manages render-textures, which are an abstraction over framebuffers. |
* | PIXI.MaskSystem | This manages masking operations. |
* | PIXI.ScissorSystem | This handles scissor masking, and is used internally by PIXI.MaskSystem |
* | PIXI.StencilSystem | This handles stencil masking, and is used internally by PIXI.MaskSystem |
* | PIXI.FilterSystem | This manages the filtering pipeline for post-processing effects. |
* | PIXI.BatchSystem | This manages object renderers that defer rendering until a flush. |
* | PIXI.Prepare | This manages uploading assets to the GPU. |
* | PIXI.Extract | This extracts image data from display objects. |
*
* The breadth of the API surface provided by the renderer is contained within these systems.
* @memberof PIXI
*/
export class Renderer extends SystemManager<Renderer> implements IRenderer
{
/** @ignore */
static extension: ExtensionMetadata = {
type: ExtensionType.Renderer,
priority: 1,
};
/**
* The type of the renderer. will be PIXI.RENDERER_TYPE.CANVAS
* @member {number}
* @see PIXI.RENDERER_TYPE
*/
public readonly type = RENDERER_TYPE.WEBGL;
/**
* Options passed to the constructor.
* @type {PIXI.IRendererOptions}
*/
public readonly options: IRendererOptions;
/**
* WebGL context, set by this.context.
* @readonly
* @member {WebGLRenderingContext}
*/
public gl: IRenderingContext;
/**
* Global uniforms
* Add any uniforms you want shared across your shaders.
* the must be added before the scene is rendered for the first time
* as we dynamically buildcode to handle all global var per shader
*
*/
public globalUniforms: UniformGroup;
/** Unique UID assigned to the renderer's WebGL context. */
public CONTEXT_UID: number;
// systems
/**
* Mask system instance
* @readonly
*/
public readonly mask: MaskSystem;
/**
* Context system instance
* @readonly
*/
public readonly context: ContextSystem;
/**
* State system instance
* @readonly
*/
public readonly state: StateSystem;
/**
* Shader system instance
* @readonly
*/
public readonly shader: ShaderSystem;
/**
* Texture system instance
* @readonly
*/
public readonly texture: TextureSystem;
/**
* Buffer system instance
* @readonly
*/
public readonly buffer: BufferSystem;
/**
* TransformFeedback system instance
* @readonly
*/
public transformFeedback: TransformFeedbackSystem;
/**
* Geometry system instance
* @readonly
*/
public readonly geometry: GeometrySystem;
/**
* Framebuffer system instance
* @readonly
*/
public readonly framebuffer: FramebufferSystem;
/**
* Scissor system instance
* @readonly
*/
public readonly scissor: ScissorSystem;
/**
* Stencil system instance
* @readonly
*/
public readonly stencil: StencilSystem;
/**
* Projection system instance
* @readonly
*/
public readonly projection: ProjectionSystem;
/**
* Texture garbage collector system instance
* @readonly
*/
public readonly textureGC: TextureGCSystem;
/**
* Filter system instance
* @readonly
*/
public readonly filter: FilterSystem;
/**
* RenderTexture system instance
* @readonly
*/
public readonly renderTexture: RenderTextureSystem;
/**
* Batch system instance
* @readonly
*/
public readonly batch: BatchSystem;
/**
* plugin system instance
* @readonly
*/
public readonly _plugin: PluginSystem;
/**
* _multisample system instance
* @readonly
*/
public readonly _multisample: MultisampleSystem;
/**
* textureGenerator system instance
* @readonly
*/
public readonly textureGenerator: GenerateTextureSystem;
/**
* background system instance
* @readonly
*/
public readonly background: BackgroundSystem;
/**
* _view system instance
* @readonly
*/
public readonly _view: ViewSystem;
/**
* _render system instance
* @readonly
*/
public readonly objectRenderer: ObjectRendererSystem;
/**
* startup system instance
* @readonly
*/
public readonly startup: StartupSystem;
/**
* Create renderer if WebGL is available. Overrideable
* by the **@pixi/canvas-renderer** package to allow fallback.
* throws error if WebGL is not available.
* @param options
* @private
*/
static test(options?: Partial<IRendererOptions>): boolean
{
if (options?.forceCanvas)
{
return false;
}
return isWebGLSupported();
}
/**
* @param {PIXI.IRendererOptions} [options] - See PIXI.settings.RENDER_OPTIONS for defaults.
*/
constructor(options?: Partial<IRendererOptions>)
{
super();
// Add the default render options
options = Object.assign({}, settings.RENDER_OPTIONS, options);
this.gl = null;
this.CONTEXT_UID = 0;
this.globalUniforms = new UniformGroup({
projectionMatrix: new Matrix(),
}, true);
const systemConfig = {
runners: [
'init',
'destroy',
'contextChange',
'resolutionChange',
'reset',
'update',
'postrender',
'prerender',
'resize'
],
systems: Renderer.__systems,
priority: [
'_view',
'textureGenerator',
'background',
'_plugin',
'startup',
// low level WebGL systems
'context',
'state',
'texture',
'buffer',
'geometry',
'framebuffer',
'transformFeedback',
// high level pixi specific rendering
'mask',
'scissor',
'stencil',
'projection',
'textureGC',
'filter',
'renderTexture',
'batch',
'objectRenderer',
'_multisample'
],
};
this.setup(systemConfig);
if ('useContextAlpha' in options)
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'options.useContextAlpha is deprecated, use options.premultipliedAlpha and options.backgroundAlpha instead');
// #endif
options.premultipliedAlpha = options.useContextAlpha && options.useContextAlpha !== 'notMultiplied';
options.backgroundAlpha = options.useContextAlpha === false ? 1 : options.backgroundAlpha;
}
this._plugin.rendererPlugins = Renderer.__plugins;
this.options = options as IRendererOptions;
this.startup.run(this.options);
}
/**
* Renders the object to its WebGL view.
* @param displayObject - The object to be rendered.
* @param {object} [options] - Object to use for render options.
* @param {PIXI.RenderTexture} [options.renderTexture] - The render texture to render to.
* @param {boolean} [options.clear=true] - Should the canvas be cleared before the new render.
* @param {PIXI.Matrix} [options.transform] - A transform to apply to the render texture before rendering.
* @param {boolean} [options.skipUpdateTransform=false] - Should we skip the update transform pass?
*/
render(displayObject: IRenderableObject, options?: IRendererRenderOptions): void
{
this.objectRenderer.render(displayObject, options);
}
/**
* Resizes the WebGL view to the specified width and height.
* @param desiredScreenWidth - The desired width of the screen.
* @param desiredScreenHeight - The desired height of the screen.
*/
resize(desiredScreenWidth: number, desiredScreenHeight: number): void
{
this._view.resizeView(desiredScreenWidth, desiredScreenHeight);
}
/**
* Resets the WebGL state so you can render things however you fancy!
* @returns Returns itself.
*/
reset(): this
{
this.runners.reset.emit();
return this;
}
/** Clear the frame buffer. */
clear(): void
{
this.renderTexture.bind();
this.renderTexture.clear();
}
/**
* Removes everything from the renderer (event listeners, spritebatch, etc...)
* @param [removeView=false] - Removes the Canvas element from the DOM.
* See: https://github.com/pixijs/pixijs/issues/2233
*/
destroy(removeView = false): void
{
this.runners.destroy.items.reverse();
this.emitWithCustomOptions(this.runners.destroy, {
_view: removeView,
});
super.destroy();
}
/** Collection of plugins */
get plugins(): IRendererPlugins
{
return this._plugin.plugins;
}
/** The number of msaa samples of the canvas. */
get multisample(): MSAA_QUALITY
{
return this._multisample.multisample;
}
/**
* Same as view.width, actual number of pixels in the canvas by horizontal.
* @member {number}
* @readonly
* @default 800
*/
get width(): number
{
return this._view.element.width;
}
/**
* Same as view.height, actual number of pixels in the canvas by vertical.
* @default 600
*/
get height(): number
{
return this._view.element.height;
}
/** The resolution / device pixel ratio of the renderer. */
get resolution(): number
{
return this._view.resolution;
}
set resolution(value: number)
{
this._view.resolution = value;
this.runners.resolutionChange.emit(value);
}
/** Whether CSS dimensions of canvas view should be resized to screen dimensions automatically. */
get autoDensity(): boolean
{
return this._view.autoDensity;
}
/** The canvas element that everything is drawn to.*/
get view(): ICanvas
{
return this._view.element;
}
/**
* Measurements of the screen. (0, 0, screenWidth, screenHeight).
*
* Its safe to use as filterArea or hitArea for the whole stage.
* @member {PIXI.Rectangle}
*/
get screen(): Rectangle
{
return this._view.screen;
}
/** the last object rendered by the renderer. Useful for other plugins like interaction managers */
get lastObjectRendered(): IRenderableObject
{
return this.objectRenderer.lastObjectRendered;
}
/** Flag if we are rendering to the screen vs renderTexture */
get renderingToScreen(): boolean
{
return this.objectRenderer.renderingToScreen;
}
/** When logging Pixi to the console, this is the name we will show */
get rendererLogId(): string
{
return `WebGL ${this.context.webGLVersion}`;
}
/**
* This sets weather the screen is totally cleared between each frame withthe background color and alpha
* @deprecated since 7.0.0
*/
get clearBeforeRender(): boolean
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.clearBeforeRender has been deprecated, please use renderer.background.clearBeforeRender instead.');
// #endif
return this.background.clearBeforeRender;
}
/**
* Pass-thru setting for the canvas' context `alpha` property. This is typically
* not something you need to fiddle with. If you want transparency, use `backgroundAlpha`.
* @deprecated since 7.0.0
* @member {boolean}
*/
get useContextAlpha(): boolean | 'notMultiplied'
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.useContextAlpha has been deprecated, please use renderer.context.premultipliedAlpha instead.');
// #endif
return this.context.useContextAlpha;
}
/**
* readonly drawing buffer preservation
* we can only know this if Pixi created the context
* @deprecated since 7.0.0
*/
get preserveDrawingBuffer(): boolean
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.preserveDrawingBuffer has been deprecated, we cannot truly know this unless pixi created the context');
// #endif
return this.context.preserveDrawingBuffer;
}
/**
* The background color to fill if not transparent
* @member {number}
* @deprecated since 7.0.0
*/
get backgroundColor(): ColorSource
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.backgroundColor has been deprecated, use renderer.background.color instead.');
// #endif
return this.background.color;
}
set backgroundColor(value: ColorSource)
{
// #if _DEBUG
deprecation('7.0.0', 'renderer.backgroundColor has been deprecated, use renderer.background.color instead.');
// #endif
this.background.color = value;
}
/**
* The background color alpha. Setting this to 0 will make the canvas transparent.
* @member {number}
* @deprecated since 7.0.0
*/
get backgroundAlpha(): number
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.backgroundAlpha has been deprecated, use renderer.background.alpha instead.');
// #endif
return this.background.alpha;
}
/**
* @deprecated since 7.0.0
*/
set backgroundAlpha(value: number)
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.backgroundAlpha has been deprecated, use renderer.background.alpha instead.');
// #endif
this.background.alpha = value;
}
/**
* @deprecated since 7.0.0
*/
get powerPreference(): WebGLPowerPreference
{
// #if _DEBUG
// eslint-disable-next-line max-len
deprecation('7.0.0', 'renderer.powerPreference has been deprecated, we can only know this if pixi creates the context');
// #endif
return this.context.powerPreference;
}
/**
* Useful function that returns a texture of the display object that can then be used to create sprites
* This can be quite useful if your displayObject is complicated and needs to be reused multiple times.
* @param displayObject - The displayObject the object will be generated from.
* @param {object} options - Generate texture options.
* @param {PIXI.SCALE_MODES} options.scaleMode - The scale mode of the texture.
* @param {number} options.resolution - The resolution / device pixel ratio of the texture being generated.
* @param {PIXI.Rectangle} options.region - The region of the displayObject, that shall be rendered,
* if no region is specified, defaults to the local bounds of the displayObject.
* @param {PIXI.MSAA_QUALITY} options.multisample - The number of samples of the frame buffer.
* @returns A texture of the graphics object.
*/
generateTexture(displayObject: IRenderableObject, options?: IGenerateTextureOptions): RenderTexture
{
return this.textureGenerator.generateTexture(displayObject, options);
}
/**
* Collection of installed plugins. These are included by default in PIXI, but can be excluded
* by creating a custom build. Consult the README for more information about creating custom
* builds and excluding plugins.
* @private
*/
static readonly __plugins: IRendererPlugins = {};
/**
* The collection of installed systems.
* @private
*/
static readonly __systems: Record<string, any> = {};
}
// Handle registration of extensions
extensions.handleByMap(ExtensionType.RendererPlugin, Renderer.__plugins);
extensions.handleByMap(ExtensionType.RendererSystem, Renderer.__systems);
extensions.add(Renderer);