diff --git a/TODO.md b/TODO.md index bfe6ff3..cc71cfd 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,3 @@ -- textures - - canvas / other shader - - audio - - mic? - fix mouse, add button, drag - device orientation diff --git a/demo/audio.html b/demo/audio.html new file mode 100644 index 0000000..be3647e --- /dev/null +++ b/demo/audio.html @@ -0,0 +1,53 @@ + + + + + <repa-shader> demo + + + + + + + + + +void main() { + vec2 uv = gl_FragCoord.xy / resolution.xy; + vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4)); + col *= texture(texture1, vec2(.5 - .5*uv.y, 1.0)).rgb * texture(tex_avatar, uv).rgb; + + outColor = vec4(col, 1.0); +} + +
+ +
+ + + + diff --git a/demo/canvas.html b/demo/canvas.html index 3964e47..a7a11be 100644 --- a/demo/canvas.html +++ b/demo/canvas.html @@ -57,7 +57,7 @@ void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4)); - col *= texture(texture0, vec2(uv.x, 1.-uv.y)).rgb; + col *= texture(texture0, vec2(uv.x, uv.y)).rgb; float dist = distance(uv, mouse.xy); float circle = smoothstep(.1, .2, dist) * .5 + .5; diff --git a/demo/demo_audio.mp3 b/demo/demo_audio.mp3 new file mode 100644 index 0000000..bdb33f5 Binary files /dev/null and b/demo/demo_audio.mp3 differ diff --git a/demo/index.html b/demo/index.html index ca2acff..10f7997 100644 --- a/demo/index.html +++ b/demo/index.html @@ -26,7 +26,7 @@ - [[1, 2, 3, 4, 5, 6, 128, 255], [255, 128, 64, 32, 4, 3, 2, 1]] + + + + + + + + + +void main() { + vec2 uv = gl_FragCoord.xy / resolution.xy; + vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4)); + col *= texture(texture1, vec2(.5*uv.y, 1.0)).rgb; + + vec3 futas = texture(texture0, uv).rgb; + + col = mix(col, futas, uv.x); + + outColor = vec4(col, 1.0); +} + +
+ +
+ + + + diff --git a/src/repa-texture.js b/src/repa-texture.js index e347b33..dedc752 100644 --- a/src/repa-texture.js +++ b/src/repa-texture.js @@ -188,6 +188,9 @@ class RepaTexture extends HTMLElement { get type() { if (this._type) { return this._type; + } else if (this.hasAttribute('type')) { + this._type = this.getAttribute('type'); + return this._type; } if (this.ref) { @@ -197,6 +200,8 @@ class RepaTexture extends HTMLElement { return 'video'; } else if (this.ref instanceof HTMLCanvasElement) { return 'canvas'; + } else if (this.ref instanceof HTMLAudioElement) { + return 'audio'; } else if (this.ref.nodeName === 'REPA-SHADER') { return 'shader'; } @@ -211,13 +216,7 @@ class RepaTexture extends HTMLElement { return this.type !== 'raw'; } - // Array of Arrays - set content(data) { - this.ready = true; - this._type = 'raw'; - this._format = 'luminance'; - this._forceUpdate = true; - + setContent(data) { this._width = data[0].length; this._height = data.length; this._content = new Uint8Array(this._width * this._height); @@ -227,10 +226,21 @@ class RepaTexture extends HTMLElement { }); } + set content(data) { + this.ready = true; + this._type = 'raw'; + this._format = 'luminance'; + this._forceUpdate = true; + + this.setContent(data); + } + get content() { if (this.ref) { if (this.type === 'shader') { return this.ref.target; + } else if (this.type === 'audio') { + return this.audioData; } return this.ref; } @@ -238,6 +248,47 @@ class RepaTexture extends HTMLElement { return this._content; } + get analyser() { + if (this.type !== 'audio' || !this.ref || !this.ref.currentTime) { + return this._analyser; + } + + if (!this._analyser) { + const audioCtx = new AudioContext(); + const analyser = audioCtx.createAnalyser(); + + this._binCount = analyser.frequencyBinCount; + this._freqData = new Uint8Array(this._binCount); + this._timeData = new Uint8Array(this._binCount); + + const source = audioCtx.createMediaElementSource(this.ref); + source.connect(analyser); + analyser.connect(audioCtx.destination); + + this._analyser = analyser; + } + + return this._analyser; + } + + get audioData() { + // setup + this._format = 'luminance'; + this._filter = 'nearest'; + + const analyser = this.analyser; + if (analyser) { + analyser.getByteFrequencyData(this._freqData); + analyser.getByteTimeDomainData(this._timeData); + + this.setContent([this._freqData, this._timeData]); + } else { + this.setContent([[255, 128, 64, 32, 16, 8, 4, 2], [2, 4, 8, 16, 32, 64, 128, 255]]); + } + + return this._content; + } + _guessType(src) { if (src.toLowerCase() === 'webcam') { return 'webcam'; @@ -267,7 +318,8 @@ class RepaTexture extends HTMLElement { return this.ready && (this._forceUpdate || ( this.ref && ( - (this.ref instanceof HTMLVideoElement && this.ref.readyState === this.ref.HAVE_ENOUGH_DATA) || + (this.ref instanceof HTMLVideoElement && this.ref.readyState >= this.ref.HAVE_ENOUGH_DATA) || + (this.ref instanceof HTMLAudioElement && this.ref.readyState >= this.ref.HAVE_ENOUGH_DATA && !this.ref.paused && !this.ref.ended && this.ref.currentTime) || (this.ref instanceof HTMLCanvasElement) ) ) @@ -283,11 +335,11 @@ class RepaTexture extends HTMLElement { } get magFilter() { - return this.getAttribute('mag-filter') || this.getAttribute('filter') || 'linear'; + return this._filter || this.getAttribute('mag-filter') || this.getAttribute('filter') || 'linear'; } get minFilter() { - return this.getAttribute('min-filter') || this.getAttribute('filter') || 'linear'; + return this._filter || this.getAttribute('min-filter') || this.getAttribute('filter') || 'linear'; } get wrapS() {