Extensions

Source: rendering/BlendMode.js

const _createBlendMode = (functions, equations) => ({
  functionName: "blendFunc" + (functions.length < 3 ? "" : "Separate"),
  functions,
  equationName: "blendEquation" + (!equations || equations.length < 2 ? "" : "Separate"),
  equations: equations || [WebGL2RenderingContext.FUNC_ADD],
});

/**
 * @typedef {Object} BlendModeInfo
 * @property {string} functionName
 * @property {Array<number>} functions
 * @property {string} equationName
 * @property {Array<number>} equations
 */

/**
 * @typedef {function} createBlendMode
 * @param {Array<number>} functions
 * @param {Array<number>} equations
 * @returns {BlendModeInfo}
 */

/**
 * <pre>
 *  Blend modes
 *    - OVERLAY is an alias of NORMAL_PM, not a real overlay blend
 *    - Multiplicative modes (MULTIPLY, MULTIPLY_PM, SCREEN, SCREEN_PM, SHADOW, EXCLUSION):
 *      textures are premultiplied, so soft (semi-transparent) edges darken or fringe;
 *      image.alpha scales only the output alpha, so modes using DST_COLOR / SRC_COLOR
 *      ignore it for the rgb channels
 * </pre>
 * @typedef {Object} BlendMode
 * @property {createBlendMode} createBlendMode
 * @property {BlendModeInfo} NONE
 * @property {BlendModeInfo} NORMAL_PM
 * @property {BlendModeInfo} ADD_PM
 * @property {BlendModeInfo} MULTIPLY_PM Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 * @property {BlendModeInfo} SCREEN_PM Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 * @property {BlendModeInfo} ADD_NPM
 * @property {BlendModeInfo} SRC_IN
 * @property {BlendModeInfo} SRC_OUT
 * @property {BlendModeInfo} SRC_ATOP
 * @property {BlendModeInfo} DST_OVER
 * @property {BlendModeInfo} DST_IN
 * @property {BlendModeInfo} DST_OUT
 * @property {BlendModeInfo} DST_ATOP
 * @property {BlendModeInfo} XOR
 * @property {BlendModeInfo} NORMAL
 * @property {BlendModeInfo} ADD
 * @property {BlendModeInfo} MULTIPLY Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 * @property {BlendModeInfo} SCREEN Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 * @property {BlendModeInfo} OVERLAY Alias of NORMAL_PM, not a real overlay blend
 * @property {BlendModeInfo} EXCLUSION Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 * @property {BlendModeInfo} LIGHTEN
 * @property {BlendModeInfo} DARKEN
 * @property {BlendModeInfo} SHADOW Multiplicative: textures are premultiplied, so soft edges darken or fringe; image.alpha only scales the output alpha, so the DST_COLOR / SRC_COLOR factors ignore it
 */
export const BlendMode = {
  createBlendMode: _createBlendMode,

  NONE: _createBlendMode([0, 0]),

  NORMAL_PM: _createBlendMode([WebGL2RenderingContext.ONE, WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA]),
  ADD_PM: _createBlendMode([WebGL2RenderingContext.ONE, WebGL2RenderingContext.ONE]),
  MULTIPLY_PM: _createBlendMode([
    WebGL2RenderingContext.DST_COLOR,
    WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
  ]),
  SCREEN_PM: _createBlendMode([
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE_MINUS_SRC_COLOR,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
  ]),

  ADD_NPM: _createBlendMode([
    WebGL2RenderingContext.SRC_ALPHA,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE,
  ]),

  SRC_IN: _createBlendMode([WebGL2RenderingContext.DST_ALPHA, WebGL2RenderingContext.ZERO]),
  SRC_OUT: _createBlendMode([WebGL2RenderingContext.ONE_MINUS_DST_ALPHA, WebGL2RenderingContext.ZERO]),
  SRC_ATOP: _createBlendMode([WebGL2RenderingContext.DST_ALPHA, WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA]),
  DST_OVER: _createBlendMode([WebGL2RenderingContext.ONE_MINUS_DST_ALPHA, WebGL2RenderingContext.ONE]),
  DST_IN: _createBlendMode([WebGL2RenderingContext.ZERO, WebGL2RenderingContext.SRC_ALPHA]),
  DST_OUT: _createBlendMode([WebGL2RenderingContext.ZERO, WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA]),
  DST_ATOP: _createBlendMode([WebGL2RenderingContext.ONE_MINUS_DST_ALPHA, WebGL2RenderingContext.SRC_ALPHA]),
  XOR: _createBlendMode([WebGL2RenderingContext.ONE_MINUS_DST_ALPHA, WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA]),

  NORMAL: _createBlendMode([
    WebGL2RenderingContext.SRC_ALPHA,
    WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
  ]),
  ADD: _createBlendMode([
    WebGL2RenderingContext.SRC_ALPHA,
    WebGL2RenderingContext.DST_ALPHA,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.DST_ALPHA,
  ]),
  MULTIPLY: _createBlendMode([WebGL2RenderingContext.DST_COLOR, WebGL2RenderingContext.ZERO]),
  SCREEN: _createBlendMode([
    WebGL2RenderingContext.SRC_ALPHA,
    WebGL2RenderingContext.ONE_MINUS_SRC_COLOR,
    WebGL2RenderingContext.ONE,
    WebGL2RenderingContext.ONE_MINUS_SRC_COLOR,
  ]),
  OVERLAY: _createBlendMode([WebGL2RenderingContext.ONE, WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA]),
  EXCLUSION: _createBlendMode([WebGL2RenderingContext.ONE_MINUS_DST_COLOR, WebGL2RenderingContext.ONE_MINUS_SRC_COLOR]),
  LIGHTEN: _createBlendMode([WebGL2RenderingContext.ONE, WebGL2RenderingContext.ONE], [WebGL2RenderingContext.MAX]),
  DARKEN: _createBlendMode([WebGL2RenderingContext.ONE, WebGL2RenderingContext.ONE], [WebGL2RenderingContext.MIN]),
  SHADOW: _createBlendMode([WebGL2RenderingContext.DST_COLOR, WebGL2RenderingContext.SRC_COLOR]),
};