diff --git a/README.md b/README.md index ac9a0ac..096f168 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,19 @@ sandbox.setUniform("u_color",1,0,0); // Load a new texture and assign it to "uniform sampler2D u_texture" sandbox.setUniform("u_texture","data/texture.jpg"); +``` +### Include Files + +Basic include support is offered for **fragment shaders only** in the style of [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Includes must come after your ```#ifdef GL_ES...#endif``` definition. In order to utilize this support you can define imports in your fragment shader as follows: + +``` +#ifdef GL_ES + precision mediump float; +#endif + +#include data/random.glsl +#include data/additional.glsl + ``` ### Quick start demo diff --git a/data/additional.glsl b/data/additional.glsl new file mode 100644 index 0000000..008a708 --- /dev/null +++ b/data/additional.glsl @@ -0,0 +1,4 @@ +float circle(vec2 st) +{ + return smoothstep(0.0,0.001,-(length(st-0.5)-0.33)); +} \ No newline at end of file diff --git a/data/random.glsl b/data/random.glsl new file mode 100644 index 0000000..62895ec --- /dev/null +++ b/data/random.glsl @@ -0,0 +1,9 @@ +float random(vec2 st){ return fract( sin( dot(st,vec2(3.678,678.90)) )*678910.0 ); } +float random (in float x) { return fract(sin(x)*43758.5453123); } + +vec2 random2(vec2 st) +{ + st = vec2( dot(st,vec2(127.1,311.7)), + dot(st,vec2(269.5,183.3)) ); + return -1.0 + 2.0*fract(sin(st)*43758.5453123); +} \ No newline at end of file diff --git a/data/test.frag b/data/test.frag new file mode 100644 index 0000000..871d041 --- /dev/null +++ b/data/test.frag @@ -0,0 +1,20 @@ +#ifdef GL_ES + precision mediump float; +#endif + +#include data/random.glsl +#include data/additional.glsl + +#define SECONDS 6.0 + +uniform vec2 u_resolution; +uniform float u_time; + +void main() +{ + vec2 st = u_resolution.xy/gl_FragCoord.xy; + float t = abs(fract(u_time/SECONDS)-0.5); + vec3 c = vec3(random(st+t)); + c += circle(st); + gl_FragColor = vec4(c,1.0); +} \ No newline at end of file diff --git a/dist/GlslCanvas.es.js b/dist/GlslCanvas.es.js index 4043d02..2a5c227 100644 --- a/dist/GlslCanvas.es.js +++ b/dist/GlslCanvas.es.js @@ -1,4 +1,5 @@ import xhr from 'xhr'; +import 'constants'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; @@ -948,6 +949,189 @@ Texture.getMaxTextureSize = function (gl) { // Global set of textures, by name Texture.activeUnit = -1; +var Includes = function () { + function Includes() { + classCallCheck(this, Includes); + + this.files = {}; + this.file = ''; + } + + createClass(Includes, [{ + key: 'fileIncluded', + value: function fileIncluded(file) {} // going to over-ride this as callback in super class + + }, { + key: 'cancelPromiseCallbacks', + value: function cancelPromiseCallbacks() { + var c = Object.keys(this.files).length; + + if (c <= 0) return; + + var values = Object.values(this.files); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = values[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var value = _step.value; + + value.parse = false; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + this.files = {}; + } + }, { + key: 'stripIncludes', + value: function stripIncludes(source) { + var _this = this; + + // cancel any current promises + this.cancelPromiseCallbacks(); + + // define our file to strip here + this.file = source; + + var exp = /^#include\s([\w].*)/igm; //previous /#include\s([\w].*)/ig; // ^(?!\/\/).* + var m; + do { + m = exp.exec(source); + if (m) { + console.log(m); + if (this.isFileNew(m[1]) == false) { + (function () { + var src = m[1]; + var f = src; + var p = _this.loadIncludeFile(src).then(function (data) { + return { 'src': src, 'data': data }; + }).catch(function (res) { + return console.log('include error:', src, ' ', res); + }); + var o = { + 'src': f, + 'promise': p, + 'include:': '', + 'parse': true + }; + _this.files[src] = o; + })(); + } + } + } while (m); + + source = source.replace(exp, ""); + this.file = source; + + var promises = Object.values(this.files).map(function (i) { + return i.promise; + }); + var t = this; + Promise.all(promises).then(function (includes) { + includes.forEach(function (include) { + t.includeFileLoaded(include.src, include.data); + }); + t.fileIncluded(t.file); + }); + + return source; + } + }, { + key: 'injectIncludeFile', + value: function injectIncludeFile(src, includeSrc) { + var def = /\#ifdef(\s\S*)+\#endif/img; + var header = src.match(def); + src = src.replace(def, header + '\n\n' + includeSrc); + return src; + } + }, { + key: 'includeFileLoaded', + value: function includeFileLoaded(src, include) { + var f = this.files[src]; + + if (f.parse == false) return false; + + this.files[src].include = include; + this.files[src].parse = false; + + this.file = this.injectIncludeFile(this.file, include); + + // this.fileIncluded(this.file); + return this.file; + } + }, { + key: 'loadIncludeFile', + value: function loadIncludeFile(src) { + return new Promise(function (resolve, reject) { + var client = new XMLHttpRequest(); + client.open('GET', src + "?" + Date.now(), true); + client.overrideMimeType("text/plain"); + client.setRequestHeader("Content-type", "text/html; charset=utf-8"); + client.onreadystatechange = function () { + + if (client.readyState == 4) { + if (client.status == 200 || client.responseText != '') // || client.status == 0 + resolve(client.responseText);else reject(client.type); + } + }; + client.onerror = function (ex) { + return reject(ex); + }; + client.send(); + }); + } + + // need to recreate this based on new structure + + }, { + key: 'isFileNew', + value: function isFileNew(src) { + var keys = Object.keys(this.files); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var key = _step2.value; + + if (key === src) return true; + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return false; + } + }]); + return Includes; +}(); + /* The MIT License (MIT) @@ -1000,12 +1184,14 @@ var GlslCanvas = function () { this.uniforms = {}; this.vbo = {}; this.isValid = false; + this.includes = new Includes(); this.BUFFER_COUNT = 0; // this.TEXTURE_COUNT = 0; - - this.vertexString = contextOptions.vertexString || '\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nattribute vec2 a_position;\nattribute vec2 a_texcoord;\n\nvarying vec2 v_texcoord;\n\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_texcoord = a_texcoord;\n}\n'; - this.fragmentString = contextOptions.fragmentString || '\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nvarying vec2 v_texcoord;\n\nvoid main(){\n gl_FragColor = vec4(0.0);\n}\n'; + this.defaultVertexString = '\n #ifdef GL_ES\n precision mediump float;\n #endif\n \n attribute vec2 a_position;\n attribute vec2 a_texcoord;\n \n varying vec2 v_texcoord;\n \n void main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_texcoord = a_texcoord;\n }\n '; + this.defaultFragmentString = '\n #ifdef GL_ES\n precision mediump float;\n #endif\n \n varying vec2 v_texcoord;\n \n void main(){\n gl_FragColor = vec4(0.0);\n }\n '; + this.vertexString = contextOptions.vertexString || this.defaultVertexString; + this.fragmentString = contextOptions.fragmentString || this.defaultFragmentString; // GL Context var gl = setupWebGL(canvas, contextOptions, options.onError); @@ -1017,6 +1203,7 @@ var GlslCanvas = function () { this.timeDelta = 0.0; this.forceRender = true; this.paused = false; + this.deferLoadForIncludes = false; this.realToCSSPixels = window.devicePixelRatio || 1; // Allow alpha @@ -1025,6 +1212,7 @@ var GlslCanvas = function () { // Load shader if (canvas.hasAttribute('data-fragment')) { this.fragmentString = canvas.getAttribute('data-fragment'); + this.load(); } else if (canvas.hasAttribute('data-fragment-url')) { var source = canvas.getAttribute('data-fragment-url'); xhr.get(source, function (error, response, body) { @@ -1035,6 +1223,7 @@ var GlslCanvas = function () { // Load shader if (canvas.hasAttribute('data-vertex')) { this.vertexString = canvas.getAttribute('data-vertex'); + this.load(); } else if (canvas.hasAttribute('data-vertex-url')) { var _source = canvas.getAttribute('data-vertex-url'); xhr.get(_source, function (error, response, body) { @@ -1042,7 +1231,8 @@ var GlslCanvas = function () { }); } - this.load(); + // need to load our default shaders to progress through process + this.load_after_includes(this.defaultFragmentString, this.defaultVertexString); if (!this.program) { return; @@ -1123,10 +1313,12 @@ var GlslCanvas = function () { } this.program = null; this.gl = null; + this.includes.cancelPromiseCallbacks(); } }, { key: 'load', value: function load(fragString, vertString) { + var _this2 = this; // Load vertex shader if there is one if (vertString) { @@ -1138,16 +1330,27 @@ var GlslCanvas = function () { this.fragmentString = fragString; } + this.includes.stripIncludes(this.fragmentString); + this.includes.fileIncluded = function (file) { + _this2.fragmentString = file; + _this2.load_after_includes(_this2.fragmentString, _this2.vertexString); + }; + } + }, { + key: 'load_after_includes', + value: function load_after_includes(fragString, vertString) { + // Should probably just strip my include and deal with shit here + this.animated = false; - this.nDelta = (this.fragmentString.match(/u_delta/g) || []).length; - this.nTime = (this.fragmentString.match(/u_time/g) || []).length; - this.nDate = (this.fragmentString.match(/u_date/g) || []).length; - this.nMouse = (this.fragmentString.match(/u_mouse/g) || []).length; + this.nDelta = (fragString.match(/u_delta/g) || []).length; + this.nTime = (fragString.match(/u_time/g) || []).length; + this.nDate = (fragString.match(/u_date/g) || []).length; + this.nMouse = (fragString.match(/u_mouse/g) || []).length; this.animated = this.nDate > 1 || this.nTime > 1 || this.nMouse > 1; - var nTextures = this.fragmentString.search(/sampler2D/g); + var nTextures = fragString.search(/sampler2D/g); if (nTextures) { - var lines = this.fragmentString.split('\n'); + var lines = fragString.split('\n'); for (var i = 0; i < lines.length; i++) { var match = lines[i].match(/uniform\s*sampler2D\s*([\w]*);\s*\/\/\s*([\w|\:\/\/|\.|\-|\_]*)/i); if (match) { @@ -1163,8 +1366,8 @@ var GlslCanvas = function () { } } - var vertexShader = createShader(this, this.vertexString, this.gl.VERTEX_SHADER); - var fragmentShader = createShader(this, this.fragmentString, this.gl.FRAGMENT_SHADER); + var vertexShader = createShader(this, vertString, this.gl.VERTEX_SHADER); + var fragmentShader = createShader(this, fragString, this.gl.FRAGMENT_SHADER); // If Fragment shader fails load a empty one to sign the error if (!fragmentShader) { @@ -1188,7 +1391,7 @@ var GlslCanvas = function () { this.change = true; this.BUFFER_COUNT = 0; - var buffers = this.getBuffers(this.fragmentString); + var buffers = this.getBuffers(fragString); if (Object.keys(buffers).length) { this.loadPrograms(buffers); } @@ -1258,7 +1461,7 @@ var GlslCanvas = function () { }, { key: 'loadTexture', value: function loadTexture(name, urlElementOrData, options) { - var _this2 = this; + var _this3 = this; if (!options) { options = {}; @@ -1278,13 +1481,13 @@ var GlslCanvas = function () { if (this.textures[name]) { this.textures[name].load(options); this.textures[name].on('loaded', function (args) { - _this2.forceRender = true; + _this3.forceRender = true; }); } } else { this.textures[name] = new Texture(this.gl, name, options); this.textures[name].on('loaded', function (args) { - _this2.forceRender = true; + _this3.forceRender = true; }); } } diff --git a/dist/GlslCanvas.js b/dist/GlslCanvas.js index 9cd18ee..ae6436f 100644 --- a/dist/GlslCanvas.js +++ b/dist/GlslCanvas.js @@ -1,8 +1,8 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.GlslCanvas = factory()); -}(this, (function () { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('constants')) : + typeof define === 'function' && define.amd ? define(['constants'], factory) : + (global.GlslCanvas = factory(global.constants)); +}(this, (function (constants) { 'use strict'; var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -1353,6 +1353,189 @@ Texture.getMaxTextureSize = function (gl) { // Global set of textures, by name Texture.activeUnit = -1; +var Includes = function () { + function Includes() { + classCallCheck(this, Includes); + + this.files = {}; + this.file = ''; + } + + createClass(Includes, [{ + key: 'fileIncluded', + value: function fileIncluded(file) {} // going to over-ride this as callback in super class + + }, { + key: 'cancelPromiseCallbacks', + value: function cancelPromiseCallbacks() { + var c = Object.keys(this.files).length; + + if (c <= 0) return; + + var values = Object.values(this.files); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = values[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var value = _step.value; + + value.parse = false; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + this.files = {}; + } + }, { + key: 'stripIncludes', + value: function stripIncludes(source) { + var _this = this; + + // cancel any current promises + this.cancelPromiseCallbacks(); + + // define our file to strip here + this.file = source; + + var exp = /^#include\s([\w].*)/igm; //previous /#include\s([\w].*)/ig; // ^(?!\/\/).* + var m; + do { + m = exp.exec(source); + if (m) { + console.log(m); + if (this.isFileNew(m[1]) == false) { + (function () { + var src = m[1]; + var f = src; + var p = _this.loadIncludeFile(src).then(function (data) { + return { 'src': src, 'data': data }; + }).catch(function (res) { + return console.log('include error:', src, ' ', res); + }); + var o = { + 'src': f, + 'promise': p, + 'include:': '', + 'parse': true + }; + _this.files[src] = o; + })(); + } + } + } while (m); + + source = source.replace(exp, ""); + this.file = source; + + var promises = Object.values(this.files).map(function (i) { + return i.promise; + }); + var t = this; + Promise.all(promises).then(function (includes) { + includes.forEach(function (include) { + t.includeFileLoaded(include.src, include.data); + }); + t.fileIncluded(t.file); + }); + + return source; + } + }, { + key: 'injectIncludeFile', + value: function injectIncludeFile(src, includeSrc) { + var def = /\#ifdef(\s\S*)+\#endif/img; + var header = src.match(def); + src = src.replace(def, header + '\n\n' + includeSrc); + return src; + } + }, { + key: 'includeFileLoaded', + value: function includeFileLoaded(src, include) { + var f = this.files[src]; + + if (f.parse == false) return false; + + this.files[src].include = include; + this.files[src].parse = false; + + this.file = this.injectIncludeFile(this.file, include); + + // this.fileIncluded(this.file); + return this.file; + } + }, { + key: 'loadIncludeFile', + value: function loadIncludeFile(src) { + return new Promise(function (resolve, reject) { + var client = new XMLHttpRequest(); + client.open('GET', src + "?" + Date.now(), true); + client.overrideMimeType("text/plain"); + client.setRequestHeader("Content-type", "text/html; charset=utf-8"); + client.onreadystatechange = function () { + + if (client.readyState == 4) { + if (client.status == 200 || client.responseText != '') // || client.status == 0 + resolve(client.responseText);else reject(client.type); + } + }; + client.onerror = function (ex) { + return reject(ex); + }; + client.send(); + }); + } + + // need to recreate this based on new structure + + }, { + key: 'isFileNew', + value: function isFileNew(src) { + var keys = Object.keys(this.files); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var key = _step2.value; + + if (key === src) return true; + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return false; + } + }]); + return Includes; +}(); + /* The MIT License (MIT) @@ -1405,12 +1588,14 @@ var GlslCanvas = function () { this.uniforms = {}; this.vbo = {}; this.isValid = false; + this.includes = new Includes(); this.BUFFER_COUNT = 0; // this.TEXTURE_COUNT = 0; - - this.vertexString = contextOptions.vertexString || '\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nattribute vec2 a_position;\nattribute vec2 a_texcoord;\n\nvarying vec2 v_texcoord;\n\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_texcoord = a_texcoord;\n}\n'; - this.fragmentString = contextOptions.fragmentString || '\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nvarying vec2 v_texcoord;\n\nvoid main(){\n gl_FragColor = vec4(0.0);\n}\n'; + this.defaultVertexString = '\n #ifdef GL_ES\n precision mediump float;\n #endif\n \n attribute vec2 a_position;\n attribute vec2 a_texcoord;\n \n varying vec2 v_texcoord;\n \n void main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_texcoord = a_texcoord;\n }\n '; + this.defaultFragmentString = '\n #ifdef GL_ES\n precision mediump float;\n #endif\n \n varying vec2 v_texcoord;\n \n void main(){\n gl_FragColor = vec4(0.0);\n }\n '; + this.vertexString = contextOptions.vertexString || this.defaultVertexString; + this.fragmentString = contextOptions.fragmentString || this.defaultFragmentString; // GL Context var gl = setupWebGL(canvas, contextOptions, options.onError); @@ -1422,6 +1607,7 @@ var GlslCanvas = function () { this.timeDelta = 0.0; this.forceRender = true; this.paused = false; + this.deferLoadForIncludes = false; this.realToCSSPixels = window.devicePixelRatio || 1; // Allow alpha @@ -1430,6 +1616,7 @@ var GlslCanvas = function () { // Load shader if (canvas.hasAttribute('data-fragment')) { this.fragmentString = canvas.getAttribute('data-fragment'); + this.load(); } else if (canvas.hasAttribute('data-fragment-url')) { var source = canvas.getAttribute('data-fragment-url'); xhr.get(source, function (error, response, body) { @@ -1440,6 +1627,7 @@ var GlslCanvas = function () { // Load shader if (canvas.hasAttribute('data-vertex')) { this.vertexString = canvas.getAttribute('data-vertex'); + this.load(); } else if (canvas.hasAttribute('data-vertex-url')) { var _source = canvas.getAttribute('data-vertex-url'); xhr.get(_source, function (error, response, body) { @@ -1447,7 +1635,8 @@ var GlslCanvas = function () { }); } - this.load(); + // need to load our default shaders to progress through process + this.load_after_includes(this.defaultFragmentString, this.defaultVertexString); if (!this.program) { return; @@ -1528,10 +1717,12 @@ var GlslCanvas = function () { } this.program = null; this.gl = null; + this.includes.cancelPromiseCallbacks(); } }, { key: 'load', value: function load(fragString, vertString) { + var _this2 = this; // Load vertex shader if there is one if (vertString) { @@ -1543,16 +1734,27 @@ var GlslCanvas = function () { this.fragmentString = fragString; } + this.includes.stripIncludes(this.fragmentString); + this.includes.fileIncluded = function (file) { + _this2.fragmentString = file; + _this2.load_after_includes(_this2.fragmentString, _this2.vertexString); + }; + } + }, { + key: 'load_after_includes', + value: function load_after_includes(fragString, vertString) { + // Should probably just strip my include and deal with shit here + this.animated = false; - this.nDelta = (this.fragmentString.match(/u_delta/g) || []).length; - this.nTime = (this.fragmentString.match(/u_time/g) || []).length; - this.nDate = (this.fragmentString.match(/u_date/g) || []).length; - this.nMouse = (this.fragmentString.match(/u_mouse/g) || []).length; + this.nDelta = (fragString.match(/u_delta/g) || []).length; + this.nTime = (fragString.match(/u_time/g) || []).length; + this.nDate = (fragString.match(/u_date/g) || []).length; + this.nMouse = (fragString.match(/u_mouse/g) || []).length; this.animated = this.nDate > 1 || this.nTime > 1 || this.nMouse > 1; - var nTextures = this.fragmentString.search(/sampler2D/g); + var nTextures = fragString.search(/sampler2D/g); if (nTextures) { - var lines = this.fragmentString.split('\n'); + var lines = fragString.split('\n'); for (var i = 0; i < lines.length; i++) { var match = lines[i].match(/uniform\s*sampler2D\s*([\w]*);\s*\/\/\s*([\w|\:\/\/|\.|\-|\_]*)/i); if (match) { @@ -1568,8 +1770,8 @@ var GlslCanvas = function () { } } - var vertexShader = createShader(this, this.vertexString, this.gl.VERTEX_SHADER); - var fragmentShader = createShader(this, this.fragmentString, this.gl.FRAGMENT_SHADER); + var vertexShader = createShader(this, vertString, this.gl.VERTEX_SHADER); + var fragmentShader = createShader(this, fragString, this.gl.FRAGMENT_SHADER); // If Fragment shader fails load a empty one to sign the error if (!fragmentShader) { @@ -1593,7 +1795,7 @@ var GlslCanvas = function () { this.change = true; this.BUFFER_COUNT = 0; - var buffers = this.getBuffers(this.fragmentString); + var buffers = this.getBuffers(fragString); if (Object.keys(buffers).length) { this.loadPrograms(buffers); } @@ -1663,7 +1865,7 @@ var GlslCanvas = function () { }, { key: 'loadTexture', value: function loadTexture(name, urlElementOrData, options) { - var _this2 = this; + var _this3 = this; if (!options) { options = {}; @@ -1683,13 +1885,13 @@ var GlslCanvas = function () { if (this.textures[name]) { this.textures[name].load(options); this.textures[name].on('loaded', function (args) { - _this2.forceRender = true; + _this3.forceRender = true; }); } } else { this.textures[name] = new Texture(this.gl, name, options); this.textures[name].on('loaded', function (args) { - _this2.forceRender = true; + _this3.forceRender = true; }); } } diff --git a/dist/GlslCanvas.min.js b/dist/GlslCanvas.min.js index 6ca51fb..14b2f1a 100644 --- a/dist/GlslCanvas.min.js +++ b/dist/GlslCanvas.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.GlslCanvas=t()}(this,function(){"use strict";var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var t="undefined"!=typeof window?window:void 0!==e?e:"undefined"!=typeof self?self:{},r=function(e){var t=i.call(e);return"[object Function]"===t||"function"==typeof e&&"[object RegExp]"!==t||"undefined"!=typeof window&&(e===window.setTimeout||e===window.alert||e===window.confirm||e===window.prompt)},i=Object.prototype.toString;var n,a=(function(e,t){(t=e.exports=function(e){return e.replace(/^\s*|\s*$/g,"")}).left=function(e){return e.replace(/^\s*/,"")},t.right=function(e){return e.replace(/\s*$/,"")}}(n={exports:{}},n.exports),n.exports),s=function(e,t,i){if(!r(t))throw new TypeError("iterator must be a function");arguments.length<3&&(i=this);"[object Array]"===o.call(e)?function(e,t,r){for(var i=0,n=e.length;i0&&(u=setTimeout(function(){if(!s){s=!0,o.abort("timeout");var e=new Error("XMLHttpRequest timeout");e.code="ETIMEDOUT",i(e)}},e.timeout)),o.setRequestHeader)for(a in c)c.hasOwnProperty(a)&&o.setRequestHeader(a,c[a]);else if(e.headers&&!function(e){for(var t in e)if(e.hasOwnProperty(t))return!1;return!0}(e.headers))throw new Error("Headers cannot be set on an XDomainRequest object");return"responseType"in e&&(o.responseType=e.responseType),"beforeSend"in e&&"function"==typeof e.beforeSend&&e.beforeSend(o),o.send(d||null),o}v.XMLHttpRequest=t.XMLHttpRequest||function(){},v.XDomainRequest="withCredentials"in new v.XMLHttpRequest?v.XMLHttpRequest:t.XDomainRequest,function(e,t){for(var r=0;r\n\n
\n
'+n+"
\n
\n\n"))}if(!window.WebGLRenderingContext)return i(x,_),null;var n=function(e,t){for(var r=["webgl","experimental-webgl"],i=null,n=0;n1?r-1:0),n=1;n2&&void 0!==arguments[2]?arguments[2]:{};T(this,e),L(this),this.gl=t,this.texture=t.createTexture(),this.texture&&(this.valid=!0),this.bind(),this.name=r,this.source=null,this.sourceType=null,this.loading=null,this.setData(1,1,new Uint8Array([0,0,0,255]),{filtering:"linear"}),this.setFiltering(i.filtering),this.load(i)}return p(e,[{key:"destroy",value:function(){this.valid&&(this.gl.deleteTexture(this.texture),this.texture=null,delete this.data,this.data=null,this.valid=!1)}},{key:"bind",value:function(t){this.valid&&("number"==typeof t&&e.activeUnit!==t&&(this.gl.activeTexture(this.gl.TEXTURE0+t),e.activeUnit=t),e.activeTexture!==this.texture&&(this.gl.bindTexture(this.gl.TEXTURE_2D,this.texture),e.activeTexture=this.texture))}},{key:"load",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.loading=null,"string"==typeof e.url?void 0!==this.url&&e.url===this.url||this.setUrl(e.url,e):e.element?this.setElement(e.element,e):e.data&&e.width&&e.height&&this.setData(e.width,e.height,e.data,e)}},{key:"setUrl",value:function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(this.valid)return this.url=e,this.source=this.url,this.sourceType="url",this.loading=new Promise(function(i,n){var a=e.split(".").pop().toLowerCase(),s="ogv"===a||"webm"===a||"mp4"===a,o=void 0;s?((o=document.createElement("video")).autoplay=!0,r.filtering="nearest"):o=new Image,o.onload=function(){try{t.setElement(o,r)}catch(e){console.log("Texture '"+t.name+"': failed to load url: '"+t.source+"'",e,r)}i(t)},o.onerror=function(e){console.log("Texture '"+t.name+"': failed to load url: '"+t.source+"'",e,r),i(t)},/^((?!chrome|android).)*safari/i.test(navigator.userAgent)&&"data:"===t.source.slice(0,5)||(o.crossOrigin="anonymous"),o.src=t.source,s&&t.setElement(o,r)}),this.loading}},{key:"setData",value:function(e,t,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return this.width=e,this.height=t,this.source=r,this.sourceType="data",this.update(i),this.setFiltering(i),this.loading=Promise.resolve(this),this.loading}},{key:"setElement",value:function(e,t){var r=this,i=e;if("string"==typeof e&&(e=document.querySelector(e)),e instanceof HTMLCanvasElement||e instanceof HTMLImageElement||e instanceof HTMLVideoElement)this.source=e,this.sourceType="element",e instanceof HTMLVideoElement?(e.addEventListener("canplaythrough",function(){r.intervalID=setInterval(function(){r.update(t)},15)},!0),e.addEventListener("ended",function(){e.currentTime=0,e.play()},!0)):this.update(t),this.setFiltering(t);else{var n="the 'element' parameter (`element: "+JSON.stringify(i)+"`) must be a CSS ";n+="selector string, or a , or