Reference Source

src/viewer/scene/viewport/Viewport.js

/**
 * @desc controls the canvas viewport for a {@link Scene}.
 *
 * * One Viewport per scene.
 * * You can configure a Scene to render multiple times per frame, while setting the Viewport to different extents on each render.
 * * Make a Viewport automatically size to its {@link Scene} {@link Canvas} by setting its {@link Viewport#autoBoundary} ````true````.
 *
 *
 * Configuring the Scene to render twice on each frame, each time to a separate viewport:
 *
 * ````Javascript
 * // Load glTF model
 * var model = new xeokit.GLTFModel({
    src: "models/gltf/GearboxAssy/glTF-MaterialsCommon/GearboxAssy.gltf"
 });

 var scene = model.scene;
 var viewport = scene.viewport;

 // Configure Scene to render twice for each frame
 scene.passes = 2; // Default is 1
 scene.clearEachPass = false; // Default is false

 // Render to a separate viewport on each render

 var viewport = scene.viewport;
 viewport.autoBoundary = false;

 scene.on("rendering", function (e) {
     switch (e.pass) {
         case 0:
             viewport.boundary = [0, 0, 200, 200]; // xmin, ymin, width, height
             break;

         case 1:
             viewport.boundary = [200, 0, 200, 200];
             break;
     }
 });
 ````

 @class Viewport
 @module xeokit
 @submodule rendering
 @constructor
 @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well.
 @param {*} [cfg] Viewport configuration
 @param {String} [cfg.id] Optional ID, unique among all components in the parent
 {@link Scene}, generated automatically when omitted.
 @param {String:Object} [cfg.meta] Optional map of user-defined metadata to attach to this Viewport.
 @param [cfg.boundary] {Number[]} Canvas-space Viewport boundary, given as
 (min, max, width, height). Defaults to the size of the parent
 {@link Scene} {@link Canvas}.
 @param [cfg.autoBoundary=false] {Boolean} Indicates if this Viewport's {@link Viewport#boundary}
 automatically synchronizes with the size of the parent {@link Scene} {@link Canvas}.

 @extends Component
 */
import {Component} from '../Component.js';
import {RenderState} from '../webgl/RenderState.js';

class Viewport extends Component {

    /**
     @private
     */
    get type() {
        return "Viewport";
    }

    /**
     @private
     */
    constructor(owner, cfg = {}) {

        super(owner, cfg);

        this._state = new RenderState({
            boundary: [0, 0, 100, 100]
        });

        this.boundary = cfg.boundary;
        this.autoBoundary = cfg.autoBoundary;
    }


    /**
     * Sets the canvas-space boundary of this Viewport, indicated as ````[min, max, width, height]````.
     *
     * When {@link Viewport#autoBoundary} is ````true````, ignores calls to this method and automatically synchronizes with {@link Canvas#boundary}.
     *
     * Fires a "boundary"" event on change.
     *
     * Defaults to the {@link Canvas} extents.
     *
     * @param {Number[]} value New Viewport extents.
     */
    set boundary(value) {

        if (this._autoBoundary) {
            return;
        }

        if (!value) {

            const canvasBoundary = this.scene.canvas.boundary;

            const width = canvasBoundary[2];
            const height = canvasBoundary[3];

            value = [0, 0, width, height];
        }

        this._state.boundary = value;

        this.glRedraw();

        /**
         Fired whenever this Viewport's {@link Viewport#boundary} property changes.

         @event boundary
         @param value {Boolean} The property's new value
         */
        this.fire("boundary", this._state.boundary);
    }

    /**
     * Gets the canvas-space boundary of this Viewport, indicated as ````[min, max, width, height]````.
     *
     * @returns {Number[]} The Viewport extents.
     */
    get boundary() {
        return this._state.boundary;
    }

    /**
     * Sets if {@link Viewport#boundary} automatically synchronizes with {@link Canvas#boundary}.
     *
     * Default is ````false````.
     *
     * @param {Boolean} value Set true to automatically sycnhronize.
     */
    set autoBoundary(value) {

        value = !!value;

        if (value === this._autoBoundary) {
            return;
        }

        this._autoBoundary = value;

        if (this._autoBoundary) {
            this._onCanvasSize = this.scene.canvas.on("boundary",
                function (boundary) {

                    const width = boundary[2];
                    const height = boundary[3];

                    this._state.boundary = [0, 0, width, height];

                    this.glRedraw();

                    /**
                     Fired whenever this Viewport's {@link Viewport#boundary} property changes.

                     @event boundary
                     @param value {Boolean} The property's new value
                     */
                    this.fire("boundary", this._state.boundary);

                }, this);

        } else if (this._onCanvasSize) {
            this.scene.canvas.off(this._onCanvasSize);
            this._onCanvasSize = null;
        }

        /**
         Fired whenever this Viewport's {@link autoBoundary/autoBoundary} property changes.

         @event autoBoundary
         @param value The property's new value
         */
        this.fire("autoBoundary", this._autoBoundary);
    }

    /**
     * Gets if {@link Viewport#boundary} automatically synchronizes with {@link Canvas#boundary}.
     *
     * Default is ````false````.
     *
     * @returns {Boolean} Returns ````true```` when automatically sycnhronizing.
     */
    get autoBoundary() {
        return this._autoBoundary;
    }

    _getState() {
        return this._state;
    }

    /**
     * @private
     */
    destroy() {
        super.destroy();
        this._state.destroy();
    }
}

export {Viewport};