Source: packages/core/src/renderTexture/GenerateTextureSystem.ts

import { extensions, ExtensionType } from '@pixi/extensions';
import { Matrix, Transform } from '@pixi/math';
import { RenderTexture } from './RenderTexture';

import type { MSAA_QUALITY, SCALE_MODES } from '@pixi/constants';
import type { ExtensionMetadata } from '@pixi/extensions';
import type { Rectangle } from '@pixi/math';
import type { IRenderableContainer, IRenderableObject, IRenderer } from '../IRenderer';
import type { ISystem } from '../system/ISystem';

const tempTransform = new Transform();

// TODO could this just be part of extract?
export interface IGenerateTextureOptions
{
    /** The scale mode of the texture. Optional, defaults to `PIXI.BaseTexture.defaultOptions.scaleMode`. */
    scaleMode?: SCALE_MODES;
    /** The resolution / device pixel ratio of the texture being generated. Optional defaults to Renderer resolution. */
    resolution?: number;
    /**
     * The region of the displayObject, that shall be rendered,
     * if no region is specified, defaults to the local bounds of the displayObject.
     */
    region?: Rectangle;
    /** The number of samples of the frame buffer. */
    multisample?: MSAA_QUALITY;
}

/**
 * System that manages the generation of textures from the renderer.
 * @memberof PIXI
 */
export class GenerateTextureSystem implements ISystem
{
    /** @ignore */
    static extension: ExtensionMetadata = {
        type: [
            ExtensionType.RendererSystem,
            ExtensionType.CanvasRendererSystem
        ],
        name: 'textureGenerator',
    };

    renderer: IRenderer;

    private readonly _tempMatrix: Matrix;

    constructor(renderer: IRenderer)
    {
        this.renderer = renderer;

        this._tempMatrix = new Matrix();
    }

    /**
     * A 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 {IGenerateTextureOptions} options - Generate texture options.
     * @returns a shiny new texture of the display object passed in
     */
    generateTexture(displayObject: IRenderableObject, options?: IGenerateTextureOptions): RenderTexture
    {
        const { region: manualRegion, ...textureOptions } = options || {};

        const region = manualRegion || (displayObject as IRenderableContainer).getLocalBounds(null, true);

        // minimum texture size is 1x1, 0x0 will throw an error
        if (region.width === 0) region.width = 1;
        if (region.height === 0) region.height = 1;

        const renderTexture = RenderTexture.create(
            {
                width: region.width,
                height: region.height,
                ...textureOptions,
            });

        this._tempMatrix.tx = -region.x;
        this._tempMatrix.ty = -region.y;

        const transform = displayObject.transform;

        displayObject.transform = tempTransform;

        this.renderer.render(displayObject, {
            renderTexture,
            transform: this._tempMatrix,
            skipUpdateTransform: !!displayObject.parent,
            blit: true,
        });

        displayObject.transform = transform;

        return renderTexture;
    }

    destroy(): void
    {
        // ka boom!
    }
}

extensions.add(GenerateTextureSystem);