UNPKG

fluid-canvas

Version:

A JavaScript library that allows for easy deployment of WebGL rendered fluid simulations.

832 lines (710 loc) 220 kB
/*! * * 🌊 fluid-canvas 🌊 - A JavaScript library that allows for easy deployment of WebGL rendered fluid simulations. * Library By: Malik Tillman * Version: v0.9.1 * GitHub: https://github.com/malik-tillman/Fluid-JS#readme * License: ISC * */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Fluid"] = factory(); else root["Fluid"] = factory(); })(window, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/fluid.js"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./assets/dither.png": /*!***************************!*\ !*** ./assets/dither.png ***! \***************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = "data:image/png;base64,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" /***/ }), /***/ "./src/defualts.js": /*!*************************!*\ !*** ./src/defualts.js ***! \*************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setBehaviors = setBehaviors; exports.SHADER_SOURCE = exports.DRAWING_PARAMS = exports.behavior = void 0; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var behavior = { sim_resolution: 128, dye_resolution: 512, paused: false, clamp_values: true, embedded_dither: true, /* Fluid Dissipation Behaviors*/ dissipation: .97, velocity: .98, pressure: .8, pressure_iteration: 20, /* Fluid Color */ fluid_color: [[0, 0, 0], [.4, .2, 0]], /* Characteristics */ curl: 0, emitter_size: 0.5, render_shaders: true, multi_color: true, /* Bloom */ render_bloom: false, bloom_iterations: 8, bloom_resolution: 256, intensity: 0.8, threshold: 0.6, soft_knee: 0.7, // bloom_resolution: 256*4, // bloom_iterations: 1, // intensity: 0.6, // threshold: 0.3, // soft_knee: 1.0, /* Background */ background_color: { r: 15, g: 15, b: 15 }, transparent: false }; exports.behavior = behavior; var DRAWING_PARAMS = { alpha: true, depth: false, stencil: false, antialias: false, preserveDrawingBuffer: false, powerPreference: "default" }; exports.DRAWING_PARAMS = DRAWING_PARAMS; var SHADER_SOURCE = { blank: "", vertex: "\n precision highp float;\n \n attribute vec2 aPosition;\n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform vec2 texelSize;\n \n void main () {\n vUv = aPosition * 0.5 + 0.5;\n vL = vUv - vec2(texelSize.x, 0.0);\n vR = vUv + vec2(texelSize.x, 0.0);\n vT = vUv + vec2(0.0, texelSize.y);\n vB = vUv - vec2(0.0, texelSize.y);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n }", clear: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying highp vec2 vUv;\n uniform sampler2D uTexture;\n uniform float value;\n \n void main () {\n gl_FragColor = value * texture2D(uTexture, vUv);\n }\n ", color: "\n precision mediump float;\n \n uniform vec4 color;\n \n void main () {\n gl_FragColor = color;\n }\n ", background: "\n void main() { \n gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n } \n ", display: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uTexture;\n \n void main () {\n vec3 C = texture2D(uTexture, vUv).rgb;\n float a = max(C.r, max(C.g, C.b));\n gl_FragColor = vec4(C, a);\n }\n ", displayBloom: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uTexture;\n uniform sampler2D uBloom;\n uniform sampler2D uDithering;\n uniform vec2 ditherScale;\n \n void main () {\n vec3 C = texture2D(uTexture, vUv).rgb;\n vec3 bloom = texture2D(uBloom, vUv).rgb;\n vec3 noise = texture2D(uDithering, vUv * ditherScale).rgb;\n noise = noise * 2.0 - 1.0;\n bloom += noise / 800.0;\n bloom = pow(bloom.rgb, vec3(1.0 / 2.2));\n C += bloom;\n float a = max(C.r, max(C.g, C.b));\n gl_FragColor = vec4(C, a);\n }\n ", displayShading: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uTexture;\n uniform vec2 texelSize;\n \n void main () {\n vec3 L = texture2D(uTexture, vL).rgb;\n vec3 R = texture2D(uTexture, vR).rgb;\n vec3 T = texture2D(uTexture, vT).rgb;\n vec3 B = texture2D(uTexture, vB).rgb;\n vec3 C = texture2D(uTexture, vUv).rgb;\n \n float dx = length(R) - length(L);\n float dy = length(T) - length(B);\n \n vec3 n = normalize(vec3(dx, dy, length(texelSize)));\n vec3 l = vec3(0.0, 0.0, 1.0);\n \n float diffuse = clamp(dot(n, l) + 0.7, 0.7, 1.0);\n C.rgb *= diffuse;\n \n float a = max(C.r, max(C.g, C.b));\n gl_FragColor = vec4(C, a);\n }\n ", displayBloomShading: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uTexture;\n uniform sampler2D uBloom;\n uniform sampler2D uDithering;\n uniform vec2 ditherScale;\n uniform vec2 texelSize;\n \n void main () {\n vec3 L = texture2D(uTexture, vL).rgb;\n vec3 R = texture2D(uTexture, vR).rgb;\n vec3 T = texture2D(uTexture, vT).rgb;\n vec3 B = texture2D(uTexture, vB).rgb;\n vec3 C = texture2D(uTexture, vUv).rgb;\n \n float dx = length(R) - length(L);\n float dy = length(T) - length(B);\n \n vec3 n = normalize(vec3(dx, dy, length(texelSize)));\n vec3 l = vec3(0.0, 0.0, 1.0);\n \n float diffuse = clamp(dot(n, l) + 0.7, 0.7, 1.0);\n C *= diffuse;\n \n vec3 bloom = texture2D(uBloom, vUv).rgb;\n vec3 noise = texture2D(uDithering, vUv * ditherScale).rgb;\n noise = noise * 2.0 - 1.0;\n bloom += noise / 800.0;\n bloom = pow(bloom.rgb, vec3(1.0 / 2.2));\n C += bloom;\n \n float a = max(C.r, max(C.g, C.b));\n gl_FragColor = vec4(C, a);\n }\n ", bloomPreFilter: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uTexture;\n uniform vec3 curve;\n uniform float threshold;\n \n void main () {\n vec3 c = texture2D(uTexture, vUv).rgb;\n float br = max(c.r, max(c.g, c.b));\n float rq = clamp(br - curve.x, 0.0, curve.y);\n rq = curve.z * rq * rq;\n c *= max(rq, br - threshold) / max(br, 0.0001);\n gl_FragColor = vec4(c, 0.0);\n }\n ", bloomBlur: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uTexture;\n \n void main () {\n vec4 sum = vec4(0.0);\n sum += texture2D(uTexture, vL);\n sum += texture2D(uTexture, vR);\n sum += texture2D(uTexture, vT);\n sum += texture2D(uTexture, vB);\n sum *= 0.25;\n gl_FragColor = sum;\n }\n ", bloomFinal: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uTexture;\n uniform float intensity;\n \n void main () {\n vec4 sum = vec4(0.0);\n sum += texture2D(uTexture, vL);\n sum += texture2D(uTexture, vR);\n sum += texture2D(uTexture, vT);\n sum += texture2D(uTexture, vB);\n sum *= 0.25;\n gl_FragColor = sum * intensity;\n }\n ", splat: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uTarget;\n uniform float aspectRatio;\n uniform vec3 color;\n uniform vec2 point;\n uniform float radius;\n \n void main () {\n vec2 p = vUv - point.xy;\n p.x *= aspectRatio;\n vec3 splat = exp(-dot(p, p) / radius) * color;\n vec3 base = texture2D(uTarget, vUv).xyz;\n gl_FragColor = vec4(base + splat, 1.0);\n }\n ", advectionManualFiltering: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uVelocity;\n uniform sampler2D uSource;\n uniform vec2 texelSize;\n uniform vec2 dyeTexelSize;\n uniform float dt;\n uniform float dissipation;\n \n vec4 bilerp (sampler2D sam, vec2 uv, vec2 tsize) {\n vec2 st = uv / tsize - 0.5;\n \n vec2 iuv = floor(st);\n vec2 fuv = fract(st);\n \n vec4 a = texture2D(sam, (iuv + vec2(0.5, 0.5)) * tsize);\n vec4 b = texture2D(sam, (iuv + vec2(1.5, 0.5)) * tsize);\n vec4 c = texture2D(sam, (iuv + vec2(0.5, 1.5)) * tsize);\n vec4 d = texture2D(sam, (iuv + vec2(1.5, 1.5)) * tsize);\n \n return mix(mix(a, b, fuv.x), mix(c, d, fuv.x), fuv.y);\n }\n \n void main () {\n vec2 coord = vUv - dt * bilerp(uVelocity, vUv, texelSize).xy * texelSize;\n gl_FragColor = dissipation * bilerp(uSource, coord, dyeTexelSize);\n gl_FragColor.a = 1.0;\n }\n ", advection: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n uniform sampler2D uVelocity;\n uniform sampler2D uSource;\n uniform vec2 texelSize;\n uniform float dt;\n uniform float dissipation;\n \n void main () {\n vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;\n gl_FragColor = dissipation * texture2D(uSource, coord);\n gl_FragColor.a = 1.0;\n }\n ", divergence: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uVelocity;\n \n void main () {\n float L = texture2D(uVelocity, vL).x;\n float R = texture2D(uVelocity, vR).x;\n float T = texture2D(uVelocity, vT).y;\n float B = texture2D(uVelocity, vB).y;\n \n vec2 C = texture2D(uVelocity, vUv).xy;\n if (vL.x < 0.0) { L = -C.x; }\n if (vR.x > 1.0) { R = -C.x; }\n if (vT.y > 1.0) { T = -C.y; }\n if (vB.y < 0.0) { B = -C.y; }\n \n float div = 0.5 * (R - L + T - B);\n gl_FragColor = vec4(div, 0.0, 0.0, 1.0);\n }\n ", curl: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uVelocity;\n \n void main () {\n float L = texture2D(uVelocity, vL).y;\n float R = texture2D(uVelocity, vR).y;\n float T = texture2D(uVelocity, vT).x;\n float B = texture2D(uVelocity, vB).x;\n float vorticity = R - L - T + B;\n gl_FragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0);\n }\n ", vorticity: "\n precision highp float;\n precision highp sampler2D;\n \n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uCurl;\n uniform float curl;\n uniform float dt;\n \n void main () {\n float L = texture2D(uCurl, vL).x;\n float R = texture2D(uCurl, vR).x;\n float T = texture2D(uCurl, vT).x;\n float B = texture2D(uCurl, vB).x;\n float C = texture2D(uCurl, vUv).x;\n \n vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= curl * C;\n force.y *= -1.0;\n \n vec2 vel = texture2D(uVelocity, vUv).xy;\n gl_FragColor = vec4(vel + force * dt, 0.0, 1.0);\n }\n ", pressure: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uDivergence;\n \n vec2 boundary (vec2 uv) {\n return uv;\n // uncomment if you use wrap or repeat texture mode\n // uv = min(max(uv, 0.0), 1.0);\n // return uv;\n }\n \n void main () {\n float L = texture2D(uPressure, boundary(vL)).x;\n float R = texture2D(uPressure, boundary(vR)).x;\n float T = texture2D(uPressure, boundary(vT)).x;\n float B = texture2D(uPressure, boundary(vB)).x;\n float C = texture2D(uPressure, vUv).x;\n float divergence = texture2D(uDivergence, vUv).x;\n float pressure = (L + R + B + T - divergence) * 0.25;\n gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0);\n }\n ", gradientSubtract: "\n precision mediump float;\n precision mediump sampler2D;\n \n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uVelocity;\n \n vec2 boundary (vec2 uv) {\n return uv;\n // uv = min(max(uv, 0.0), 1.0);\n // return uv;\n }\n \n void main () {\n float L = texture2D(uPressure, boundary(vL)).x;\n float R = texture2D(uPressure, boundary(vR)).x;\n float T = texture2D(uPressure, boundary(vT)).x;\n float B = texture2D(uPressure, boundary(vB)).x;\n vec2 velocity = texture2D(uVelocity, vUv).xy;\n velocity.xy -= vec2(R - L, T - B);\n gl_FragColor = vec4(velocity, 0.0, 1.0);\n }\n " }; exports.SHADER_SOURCE = SHADER_SOURCE; function setBehaviors(params) { exports.behavior = behavior = _objectSpread({}, behavior, {}, params); } /***/ }), /***/ "./src/fluid.js": /*!**********************!*\ !*** ./src/fluid.js ***! \**********************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* Refs https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants */ var _defualts = __webpack_require__(/*! ./defualts */ "./src/defualts.js"); var _initializer = __webpack_require__(/*! ./initializer */ "./src/initializer.js"); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } module.exports = /*#__PURE__*/ function () { function Fluid(canvas) { _classCallCheck(this, Fluid); this.PARAMS = _defualts.behavior; /* Set canvas to desired width and height TODO: Change to dynamic sizing */ canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; this.canvas = canvas; var _initWebGL = (0, _initializer.initWebGL)(), programs = _initWebGL.programs, webGL = _initWebGL.webGL, colorFormats = _initWebGL.colorFormats, pointers = _initWebGL.pointers; this.programs = programs; this.webGL = webGL; this.colorFormats = colorFormats; this.pointers = pointers; } /** * Activate Fluid Canvas * Initiates WebGL fluid loop. * * TODO: Finish commenting * */ _createClass(Fluid, [{ key: "activate", value: function activate() { (0, _initializer.activator)(this.canvas, this.webGL, this.colorFormats, this.programs, this.pointers); } /** * Deactivate Fluid Canvas * Notifies active fluid canvas to clear buffers and erase fluid from call stack. * */ }, { key: "deactivate", value: function deactivate() {} /** * Reset Fluid Simulation * Re-initializes WebGL context and activates simulation based on new context. * */ }, { key: "reset", value: function reset() { (0, _initializer.initWebGL)(); this.activate(); } /** * Map Fluid Behaviors * Uses spread operators to add parameter values only in the places specified. * * @param params: specific parameter value. * */ }, { key: "mapBehaviors", value: function mapBehaviors(params) { this.PARAMS = _objectSpread({}, this.PARAMS, {}, params); (0, _defualts.setBehaviors)(this.PARAMS); } /** * Set Fluid as Background * Pushes canvas back in z space and absolutely positions it. * * @param shouldSet: true sets it, false un-sets it. Defaults to true. * */ }, { key: "setAsBackground", value: function setAsBackground() { var shouldSet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; /* Pushes back in Z Index */ canvas.style.zIndex = shouldSet ? '-99' : '0'; /* Position Absolutely */ canvas.style.position = shouldSet ? 'absolute' : 'relative'; } /** * Apply Background * Sets fluid canvas's background and resets view. * * @param type: Image, Gradient, or Solid. The type of background to be applied. * @param value: The value to apply to the image type. * @param options: Additional options to configure background (optional) * * @param canvas */ }, { key: "applyBackground", value: function applyBackground(type, value) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var canvas = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : this.canvas; type = type.toLowerCase(); /* Make transparent */ this.PARAMS.transparent = true; /* Check for Background Type */ switch (type) { case 'gradient': gradient(); break; case 'image': image(); break; case 'solid': /* Make Opaque Background and Set Color * value must be in { r: red, b: blue, g: green } format * * Best way to change background color: * * yourFluid.PARAM.BACK_COLOR.R = red; * yourFluid.PARAM.BACK_COLOR.G = blue; * yourFluid.PARAM.BACK_COLOR.B = green; * * or * * let color = { * r: red, * b: blue, * g: green * }; * * yourFluid.PARAM.BACK_COLOR = color; * */ default: this.PARAMS.transparent = false; this.PARAMS.background_color = value; } /* Reset WebGL */ this.reset(); /** Set to Gradient * Sets canvas background value to desired gradient. */ function gradient() { /** Gradient * Holds the gradient css statement. * * @type {string} */ var gradient = ""; /* Configure Gradient to Options */ switch (options) { case 'radial': gradient = "radial-gradient(" + value + ")"; break; case 'conic': gradient = "conic-gradient(" + value + ")"; break; case 'repeating-linear': gradient = "repeating-linear-gradient(" + value + ")"; break; case 'repeating-radial': gradient = "repeating-radial-gradient(" + value + ")"; break; case 'linear': default: gradient = "linear-gradient(" + value + ")"; } /* Set Gradient Dom Style */ canvas.style.backgroundImage = gradient; } /** Set to Image * Sets canvas background image value to desired image and configure styles. */ function image() { /* Set background image to desired URL, throw error if invalid URL */ canvas.style.backgroundImage = "url('" + value + "')"; /* Modify CSS Properties */ if (options) { /* Set Repeat */ canvas.style.backgroundRepeat = options.repeat ? 'repeat' : 'no-repeat'; /* Set Position */ canvas.style.backgroundPosition = options.position ? options.position : 'center'; /* Set Size */ canvas.style.backgroundSize = options.size ? options.size : 'contain'; /* Set Color */ canvas.style.backgroundColor = options.color ? options.color : 'none'; } } } /** * Set Dither URL * Sets the URL to an image to be used for dithering. This method is only responsible for calling * the action in the initializer. The dither will not be applied until the next activation call. * * @param url: Path to dither in root directory. */ }, { key: "setDitherURL", value: function setDitherURL(url) { (0, _initializer.setDitherURL)(url); } }]); return Fluid; }(); /***/ }), /***/ "./src/initializer.js": /*!****************************!*\ !*** ./src/initializer.js ***! \****************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.initWebGL = initWebGL; exports.activator = activator; exports.setDitherURL = setDitherURL; var defualts = _interopRequireWildcard(__webpack_require__(/*! ./defualts */ "./src/defualts.js")); var dither = _interopRequireWildcard(__webpack_require__(/*! ../assets/dither.png */ "./assets/dither.png")); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var active = false; var cancel = false; var ditherURL = "./assets/dither.png"; /** * Initiate WebGL Object * Gets WebGL context and compiles shader programs. * */ function initWebGL() { /* Add default pointer */ var pointers = []; pointers.push(new Pointer()); /* Get webGL context */ var webGL = canvas.getContext('webgl2', defualts.DRAWING_PARAMS); var isWebGL2 = !!webGL; if (!isWebGL2) webGL = canvas.getContext('webgl', defualts.DRAWING_PARAMS) || canvas.getContext('experimental-webgl', defualts.DRAWING_PARAMS); /* Get color formats */ var colorFormats = getFormats(); /* Case support adjustments */ if (isMobile()) defualts.behavior.render_shaders = false; if (!colorFormats.supportLinearFiltering) { defualts.behavior.render_shaders = false; defualts.behavior.render_bloom = false; } /* Make our shaders and shader programs */ var SHADER = { baseVertex: compileShader(webGL.VERTEX_SHADER, defualts.SHADER_SOURCE.vertex), clear: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.clear), color: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.color), background: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.background), display: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.display), displayBloom: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.displayBloom), displayShading: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.displayShading), displayBloomShading: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.displayBloomShading), bloomPreFilter: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.bloomPreFilter), bloomBlur: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.bloomBlur), bloomFinal: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.bloomFinal), splat: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.splat), advectionManualFiltering: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.advectionManualFiltering), advection: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.advection), divergence: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.divergence), curl: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.curl), vorticity: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.vorticity), pressure: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.pressure), gradientSubtract: compileShader(webGL.FRAGMENT_SHADER, defualts.SHADER_SOURCE.gradientSubtract) }; var programs = formShaderPrograms(colorFormats.supportLinearFiltering); /* Worker Classes and Functions */ /** * Is It Mobile?: * Detects whether or not a device is mobile by checking the user agent string * * @returns {boolean} */ function isMobile() { return /Mobi|Android/i.test(navigator.userAgent); } /** * Get Formats: * Enable color extensions, linear filtering extensions, and return usable color formats RGBA, * RG (Red-Green), and R (Red). * * @returns {{formatRGBA: {internalFormat, format}, supportLinearFiltering: OES_texture_half_float_linear, * formatR: {internalFormat, format}, halfFloatTexType: *, formatRG: {internalFormat, format}}} */ function getFormats() { /* Color Formats */ var formatRGBA; var formatRG; var formatR; var halfFloat; var supportLinearFiltering; /* Enables webGL color extensions and get linear filtering extension*/ if (isWebGL2) { webGL.getExtension('EXT_color_buffer_float'); supportLinearFiltering = webGL.getExtension('OES_texture_float_linear'); } else { halfFloat = webGL.getExtension('OES_texture_half_float'); supportLinearFiltering = webGL.getExtension('OES_texture_half_float_linear'); } var HALF_FLOAT_TEXTURE_TYPE = isWebGL2 ? webGL.HALF_FLOAT : halfFloat.HALF_FLOAT_OES; /* Set color to black for when color buffers are cleared */ webGL.clearColor(0.0, 0.0, 0.0, 1.0); /* Retrieve color formats */ if (isWebGL2) { formatRGBA = getSupportedFormat(webGL.RGBA16F, webGL.RGBA, HALF_FLOAT_TEXTURE_TYPE); formatRG = getSupportedFormat(webGL.RG16F, webGL.RG, HALF_FLOAT_TEXTURE_TYPE); formatR = getSupportedFormat(webGL.R16F, webGL.RED, HALF_FLOAT_TEXTURE_TYPE); } else { formatRGBA = getSupportedFormat(webGL.RGBA, webGL.RGBA, HALF_FLOAT_TEXTURE_TYPE); formatRG = getSupportedFormat(webGL.RGBA, webGL.RGBA, HALF_FLOAT_TEXTURE_TYPE); formatR = getSupportedFormat(webGL.RGBA, webGL.RGBA, HALF_FLOAT_TEXTURE_TYPE); } /** Get Supported Format * Using the specified internal format, we retrieve and return the desired color format to be * rendered with * * @param internalFormat: A GLenum that specifies the color components within the texture * @param format: Another GLenum that specifies the format of the texel data. * @returns {{internalFormat: *, format: *}|null|({internalFormat, format}|null)} */ function getSupportedFormat(internalFormat, format, type) { var isSupportRenderTextureFormat; var texture = webGL.createTexture(); /* Set texture parameters */ webGL.bindTexture(webGL.TEXTURE_2D, texture); webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_MIN_FILTER, webGL.NEAREST); webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_MAG_FILTER, webGL.NEAREST); webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_WRAP_S, webGL.CLAMP_TO_EDGE); webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_WRAP_T, webGL.CLAMP_TO_EDGE); /* Specify a 2D texture image */ webGL.texImage2D(webGL.TEXTURE_2D, 0, internalFormat, 4, 4, 0, format, type, null); /* Attach texture to frame buffer */ var fbo = webGL.createFramebuffer(); webGL.bindFramebuffer(webGL.FRAMEBUFFER, fbo); webGL.framebufferTexture2D(webGL.FRAMEBUFFER, webGL.COLOR_ATTACHMENT0, webGL.TEXTURE_2D, texture, 0); /* Check if current format is supported */ var status = webGL.checkFramebufferStatus(webGL.FRAMEBUFFER); isSupportRenderTextureFormat = status === webGL.FRAMEBUFFER_COMPLETE; /* If not supported use fallback format, until we have no fallback */ if (!isSupportRenderTextureFormat) { switch (internalFormat) { case webGL.R16F: return getSupportedFormat(webGL.RG16F, webGL.RG, type); case webGL.RG16F: return getSupportedFormat(webGL.RGBA16F, webGL.RGBA, type); default: return null; } } return { internalFormat: internalFormat, format: format }; } return { formatRGBA: formatRGBA, formatRG: formatRG, formatR: formatR, halfFloatTexType: HALF_FLOAT_TEXTURE_TYPE, supportLinearFiltering: supportLinearFiltering }; } /** * Compile Shader: * Makes a new webGL shader of type `type` using the provided GLSL source. The `type` is either of * `VERTEX_SHADER` or `FRAGMENT_SHADER` * * @param type: Passed to `createShader` to define the shader type * @param source: A GLSL source script, used to define the shader properties * @returns {WebGLShader}: A webGL shader of the parameterized type and source */ function compileShader(type, source) { /* Create shader, link the source, and compile the GLSL*/ var shader = webGL.createShader(type); webGL.shaderSource(shader, source); webGL.compileShader(shader); /* TODO: Finish error checking */ if (!webGL.getShaderParameter(shader, webGL.COMPILE_STATUS)) throw webGL.getShaderInfoLog(shader); return shader; } /** * Form Shader Programs: * Assembles shaders into a webGl program we can use to write to our context * * @param supportLinearFiltering: A bool letting us know if we support linear filtering * @returns {{displayBloomProgram: GLProgram, vorticityProgram: GLProgram, displayShadingProgram: GLProgram, * displayBloomShadingProgram: GLProgram, gradientSubtractProgram: GLProgram, advectionProgram: GLProgram, * bloomBlurProgram: GLProgram, colorProgram: GLProgram, divergenceProgram: GLProgram, clearProgram: GLProgram, * splatProgram: GLProgram, displayProgram: GLProgram, bloomPreFilterProgram: GLProgram, curlProgram: GLProgram, * bloomFinalProgram: GLProgram, pressureProgram: GLProgram, backgroundProgram: GLProgram}}: Programs used to * render shaders * */ function formShaderPrograms(supportLinearFiltering) { return { clearProgram: new GLProgram(SHADER.baseVertex, SHADER.clear, webGL), colorProgram: new GLProgram(SHADER.baseVertex, SHADER.color, webGL), backgroundProgram: new GLProgram(SHADER.baseVertex, SHADER.background, webGL), displayProgram: new GLProgram(SHADER.baseVertex, SHADER.display, webGL), displayBloomProgram: new GLProgram(SHADER.baseVertex, SHADER.displayBloom, webGL), displayShadingProgram: new GLProgram(SHADER.baseVertex, SHADER.displayShading, webGL), displayBloomShadingProgram: new GLProgram(SHADER.baseVertex, SHADER.displayBloomShading, webGL), bloomPreFilterProgram: new GLProgram(SHADER.baseVertex, SHADER.bloomPreFilter, webGL), bloomBlurProgram: new GLProgram(SHADER.baseVertex, SHADER.bloomBlur, webGL), bloomFinalProgram: new GLProgram(SHADER.baseVertex, SHADER.bloomFinal, webGL), splatProgram: new GLProgram(SHADER.baseVertex, SHADER.splat, webGL), advectionProgram: new GLProgram(SHADER.baseVertex, supportLinearFiltering ? SHADER.advection : SHADER.advectionManualFiltering, webGL), divergenceProgram: new GLProgram(SHADER.baseVertex, SHADER.divergence, webGL), curlProgram: new GLProgram(SHADER.baseVertex, SHADER.curl, webGL), vorticityProgram: new GLProgram(SHADER.baseVertex, SHADER.vorticity, webGL), pressureProgram: new GLProgram(SHADER.baseVertex, SHADER.pressure, webGL), gradientSubtractProgram: new GLProgram(SHADER.baseVertex, SHADER.gradientSubtract, webGL) }; } return { programs: programs, webGL: webGL, colorFormats: colorFormats, pointers: pointers }; } function activator(canvas, webGL, colorFormat, PROGRAMS, pointers) { if (active) { var nPointers = []; nPointers.push(new Pointer()); pointers = nPointers; } active = true; /* TODO: Retrieve haul style */ var PARAMS = defualts.behavior; var bloomFrameBuffers = []; var splatStack = []; var simWidth; var simHeight; var dyeWidth; var dyeHeight; var density; var velocity; var divergence; var curl; var pressure; var bloom; var blit = function () { webGL.bindBuffer(webGL.ARRAY_BUFFER, webGL.createBuffer()); webGL.bufferData(webGL.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), webGL.STATIC_DRAW); webGL.bindBuffer(webGL.ELEMENT_ARRAY_BUFFER, webGL.createBuffer()); webGL.bufferData(webGL.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), webGL.STATIC_DRAW); webGL.vertexAttribPointer(0, 2, webGL.FLOAT, false, 0, 0); webGL.enableVertexAttribArray(0); return function (destination) { webGL.bindFramebuffer(webGL.FRAMEBUFFER, destination); webGL.drawElements(webGL.TRIANGLES, 6, webGL.UNSIGNED_SHORT, 0); }; }(); /** Dithering Texture * Initialize fluid overlay/dither * * @type {{texture: WebGLTexture, width: number, attach(*): *, height: number}} */ var ditheringTexture = PARAMS.embedded_dither ? createTextureAsync(dither["default"]) : createTextureAsync(ditherURL); /* Initialize Fluid */ init(); multipleSplats(parseInt(Math.random() * 20) + 5); /* Game Loop */ var lastColorChangeTime = Date.now(); update(); /* Game Loop */ /** * Initialize Fluid * Prepares frame buffers for rendering * */ function init() { /* Color Formats */ var texType = colorFormat.halfFloatTexType; var rgba = colorFormat.formatRGBA; var rg = colorFormat.formatRG; var r = colorFormat.formatR; var filtering = colorFormat.supportLinearFiltering ? webGL.LINEAR : webGL.NEAREST; /* Set simulation and pointer width and height */ var simRes = getResolution(PARAMS.sim_resolution); var dyeRes = getResolution(PARAMS.dye_resolution); var bloomRes = getResolution(PARAMS.bloom_resolution); simWidth = simRes.width; simHeight = simRes.height; dyeWidth = dyeRes.width; dyeHeight = dyeRes.height; /* Density, Velocity, and Bloom Double Frame Buffers */ density = !density ? createDoubleFBO(dyeWidth, dyeHeight, rgba.internalFormat, rgba.format, texType, filter