Home Reference Source

src/components/Sprite.js

import RectangleRenderer from './RectangleRenderer';
import { vec2 } from '../utils/gl-matrix';

export default class Sprite extends RectangleRenderer {

  static factory() {
    return new Sprite();
  }

  static get propsTypes() {
    return {
      visible: RectangleRenderer.propsTypes.visible,
      shader: RectangleRenderer.propsTypes.shader,
      overrideUniforms: RectangleRenderer.propsTypes.overrideUniforms,
      overrideSamplers: RectangleRenderer.propsTypes.overrideSamplers,
      layers: RectangleRenderer.propsTypes.layers,
      width: RectangleRenderer.propsTypes.width,
      height: RectangleRenderer.propsTypes.height,
      xOffset: RectangleRenderer.propsTypes.xOffset,
      yOffset: RectangleRenderer.propsTypes.yOffset,
      xOrigin: RectangleRenderer.propsTypes.xOrigin,
      yOrigin: RectangleRenderer.propsTypes.yOrigin,
      color: RectangleRenderer.propsTypes.color,
      overrideBaseTexture: 'string_null',
      overrideBaseFiltering: 'enum(nearest, linear)',
      frameTopLeft: 'vec2',
      frameBottomRight: 'vec2'
    };
  }

  get overrideBaseTexture() {
    const { overrideSamplers } = this;
    const sampler = overrideSamplers.sBase;

    return !!sampler
      ? sampler.texture
      : null;
  }

  set overrideBaseTexture(value) {
    const { overrideSamplers } = this;

    if (!value) {
      delete overrideSamplers.sBase;
      this.overrideSamplers = overrideSamplers;
      return;
    }

    if (typeof value !== 'string') {
      throw new Error('`value` is not type of String!');
    }

    const sampler = overrideSamplers.sBase;

    if (!sampler) {
      overrideSamplers.sBase = {
        texture: value,
        filtering: 'linear'
      };
    } else {
      sampler.texture = value;
    }
    this.overrideSamplers = overrideSamplers;
  }

  get overrideBaseFiltering() {
    const { overrideSamplers } = this;
    const sampler = overrideSamplers.get('sBase');

    return !!sampler
      ? sampler.filtering
      : null;
  }

  set overrideBaseFiltering(value) {
    const { overrideSamplers } = this;

    if (typeof value !== 'string') {
      throw new Error('`value` is not type of String!');
    }

    const sampler = overrideSamplers.sBase;

    if (!sampler) {
      overrideSamplers.sBase = {
        texture: '',
        filtering: value
      };
    } else {
      sampler.filtering = value;
    }
    this.overrideSamplers = overrideSamplers;
  }

  get frameTopLeft() {
    return this._frameTopLeft;
  }

  set frameTopLeft(value) {
    if (!(value instanceof Array)) {
      throw new Error('`value` is not type of Array!');
    }
    if (value.length < 2) {
      throw new Error('`value` must have at least 2 elements!');
    }

    vec2.copy(this._frameTopLeft, value);
    this._rebuild = true;
  }

  get frameBottomRight() {
    return this._frameBottomRight;
  }

  set frameBottomRight(value) {
    if (!(value instanceof Array)) {
      throw new Error('`value` is not type of Array!');
    }
    if (value.length < 2) {
      throw new Error('`value` must have at least 2 elements!');
    }

    vec2.copy(this._frameBottomRight, value);
    this._rebuild = true;
  }

  constructor() {
    super();

    this._frameTopLeft = vec2.fromValues(0, 0);
    this._frameBottomRight = vec2.fromValues(1, 1);
  }

  onPropertySerialize(name, value) {
    if (name === 'frameTopLeft' || name === 'frameBottomRight') {
      return [ ...value ];
    } else if (name === 'overrideSamplers') {
      const result = super.onPropertySerialize(name, value);

      if (!result) {
        return null;
      }

      delete result.sBase;
      return Object.keys(result).length > 0 ? result : null;
    } else {
      return super.onPropertySerialize(name, value);
    }
  }

  ensureVertices(renderer) {
    if (!this._rebuild) {
      return;
    }

    let {
      _width,
      _height
    } = this;
    const {
      _xOffset,
      _yOffset,
      _xOrigin,
      _yOrigin,
      _frameTopLeft,
      _frameBottomRight
    } = this;
    if (_width < 0 || _height < 0) {
      const meta = renderer.getTextureMeta(this.overrideBaseTexture);
      if (_width < 0) {
        _width = !!meta ? meta.width : 0;
      }
      if (_height < 0) {
        _height = !!meta ? meta.height : 0;
      }
    }
    const xo = -_xOffset - (_xOrigin * _width);
    const yo = -_yOffset - (_yOrigin * _height);

    this.vertices = [
      xo,           yo,           _frameTopLeft[0],     _frameTopLeft[1],
      _width + xo,  yo,           _frameBottomRight[0], _frameTopLeft[1],
      _width + xo,  _height + yo, _frameBottomRight[0], _frameBottomRight[1],
      xo,           _height + yo, _frameTopLeft[0],     _frameBottomRight[1]
    ];
    this.indices = [ 0, 1, 2, 2, 3, 0 ];
    this._rebuild = false;
  }

}