Home Reference Source Test

src/component/Renderable.js

import Component from './Component';
import SceneManager from '../manager/SceneManager';
import RenderManager from '../manager/RenderManager';
import ProgramManager from '../manager/ProgramManager';
import Matrix3 from '../render/WebGL/Matrix3';
import Color from '../internal/Color';

const DepthRange = 10000000;

/**
 * Base Renderable Component for all Components that want to draw to the screen. If
 * you want to show something on screen, it should derive Renderable.
 * 
 * Contained in the class are functions for attaching the Renderable to viewports,
 * and updating Transform data into matricies for use with the Render Manager.
 * 
 * The Renderable Component contains data on how the Renderable expects to be rendered.
 * Programs, render vectors, shader data, and other data that is on a per-object basis
 * for rendering is defined here.
 * 
 * Classes which derive a Renderable should handle all base data and add or modify data
 * as needed to achieve certain effects.
 */
export default class Renderable extends Component {
    /**
     * Constructor for the Renderable component. Allows defaults to be assigned without
     * having to call setter functions later.
     * 
     * @param {Program} program A Program Object from the ProgramManager.
     */
    constructor(program = ProgramManager.getProgram('Default')) {
        super(true);
        this.deregisterViewports = {};

        //currently unused
        this.program = program;
        this._matrixPosition = new Matrix3();
        this._matrixScale = new Matrix3();
        this._matrixRotation = new Matrix3();
        this._matrixOriginOffset = new Matrix3();
        this.color = new Color();
        this.renderPositions = [0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1];
        this.primitiveType = RenderManager.GL.TRIANGLES;
        this.primitiveCount = 6;

        //textures
        this.textures = [];
        this._subSpriteData = [0, 0, 1, 1];
        
        this.depth = 0.5;
    }

    requestRedraw() {
        RenderManager.forceUpdate();
    }

    setColor(r, g, b, a) {
        this.color.set(r, g, b, a);
        this.requestRedraw();
    }

    setDepth(depth) {
        this.depth = (Math.max(-DepthRange, Math.min(depth, DepthRange)) + DepthRange) / (DepthRange * 2);
        this.requestRedraw();
    }

    setSubIndex(spriteIndex) {
        if (this.textures.length < 1)
            return;

        let framesWidth = this.textures[0].frameWidth / this.textures[0].width;
        let framesHeight = this.textures[0].frameHeight / this.textures[0].height;

        let frameWidthIndex = spriteIndex % (1 / framesWidth);
        let frameHeightIndex = Math.floor(spriteIndex * framesWidth);

        this._subSpriteData = [-frameWidthIndex, -frameHeightIndex, framesWidth, framesHeight];
        this.requestRedraw();
    }

    setUniformData(positionMatrix) {
        this.program.setUniforms({
            'u_color': this.color.color,
            'u_matrix': positionMatrix,
            'u_depth': this.depth,
            'u_texture': 0,
            'u_subTexcoord': this._subSpriteData,
        });
        return true;
    }

    setTexture(textureObject) {
        this.textures[0] = textureObject;
        this.requestRedraw();
    }

    /**
     * Returns a joined matrix of position, scale, rotation and origin adjustment.
     */
    getMatrix() {       
        return Matrix3.copy(this._matrixPosition).multiply(this._matrixRotation).multiply(this._matrixScale).multiply(this._matrixOriginOffset);
    }

    /**
     * Sets the position matrix to the new position point assigned.
     * 
     * @param {Point} point A position point.
     */
    setPosition(point) {
        this._matrixPosition.setPosition(point.x, point.y); //point.z if we had 3D to override this
        this.requestRedraw();
    }

    /**
     * Sets the origin offset matrix to the new position point assigned. This matrix reacts differently from other matrix
     * assignment. 0,0 is regular top left corner origin, -0.5, -0.5 centers the origin to the center of the Transform, and
     * -1, -1 will align the origin to the bottom right.
     * 
     * @param {Point} point Origin offset point.
     */
    setOriginOffset(point) {
        this._matrixOriginOffset.setPosition(point.x, point.y); //point.z if we had 3D to override this
    }

    /**
     * Sets the rotation matrix to the new rotation value assigned.
     * 
     * TODO: Change to a rotation point for x, y, z rotation instead of just z.
     * 
     * @param {number} rotation A rotation in degrees.
     */
    setRotation(rotation) {
        this._matrixRotation.setRotation(rotation);
        this.requestRedraw();
    }

    /**
     * Sets the scale matrix to the new scale point assigned.
     * 
     * @param {Point} scale A scale point.
     */
    setScale(scale) {
        this._matrixScale.setScale(scale.x, scale.y);
        this.requestRedraw();
    }

    /**
     * Called immediatly after the Render component is added to a game object.
     * 
     * Updates the data of this renderable to the current Transform data.
     */
    onAddComponent() {
        let transform = this.gameObject.getComponent("Transform");
        transform.renderable = this;
        this.setPosition(transform._position);
        this.setScale(transform._scale);
        this.setRotation(transform._rotation);
        this.requestRedraw();
    }

    /**
     * Adds this component to another viewport to be drawn. 
     * 
     * @param {number} viewportID Object ID of the viewport.
     */
    addToViewport(viewportID) {
        this.deregisterViewports[viewportID] = SceneManager.getCurrentScene().registerRenderableComponent(this, viewportID);
        this.requestRedraw();
        return this;
    }

    /**
     * Removes the renderable from all viewports.
     */
    removeFromViewports() {
        let objKeys = Object.keys(this.deregisterViewports);
        for (let i = 0; i < objKeys.length; i++) {
            this.deregisterViewports[objKeys[i]]();
        }
        this.requestRedraw();
    }

    onEnd() {
        this.removeFromViewports();
    }
}