diff --git a/demo/index.html b/demo/index.html
index dcee0c7..ca2acff 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -26,20 +26,9 @@
+ [[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(tex_avatar, uv).rgb;
+
+ float dist = distance(uv, mouse.xy);
+ float circle = smoothstep(.1, .2, dist) * .5 + .5;
+ vec4 acolor = vec4(col * circle, circle);
+ outColor = vec4(acolor);
+}
diff --git a/src/repa-shader.js b/src/repa-shader.js
index d9fab59..07e6b83 100644
--- a/src/repa-shader.js
+++ b/src/repa-shader.js
@@ -244,11 +244,15 @@ class RepaShader extends HTMLElement {
}
_getWrap(wrap) {
- return this._gl[wrap.toUpperCase().replaceAll('-', '_')] || this._gl.CLAMP_TO_EDGE;
+ return (wrap && this._gl[wrap.toUpperCase().replaceAll('-', '_')]) || this._gl.CLAMP_TO_EDGE;
}
_getFilter(filter) {
- return this._gl[filter.toUpperCase().replaceAll('-', '_')] || this._gl.LINEAR;
+ return (filter && this._gl[filter.toUpperCase().replaceAll('-', '_')]) || this._gl.LINEAR;
+ }
+
+ _getFormat(format) {
+ return (format && this._gl[format.toUpperCase().replaceAll('-', '_')]) || this._gl.RGBA;
}
_collectTextures() {
@@ -382,7 +386,10 @@ class RepaShader extends HTMLElement {
// update if needed
if (t.texElement.shouldUpdate) {
- this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, t.texElement.update());
+ const format = this._getFormat(t.texElement.format);
+ this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, t.texElement.flipY);
+
+ this._gl.texImage2D(this._gl.TEXTURE_2D, 0, format, t.texElement.width, t.texElement.height, 0, format, this._gl.UNSIGNED_BYTE, t.texElement.update());
}
this._gl.uniform1i(this._uniLocation[t.texElement.name], i + this.mrt);
@@ -644,6 +651,11 @@ void main() {
}
}
+ // text content
+ if (!source) {
+ source = Array.from(this.childNodes).filter(n => n.nodeType === Node.TEXT_NODE).map(n => n.textContent).join('').trim();
+ }
+
// fallback demo
if (!source) {
source = DEMO_FS;
diff --git a/src/repa-texture.js b/src/repa-texture.js
index 32cecaa..e347b33 100644
--- a/src/repa-texture.js
+++ b/src/repa-texture.js
@@ -16,10 +16,9 @@ const isVideo = (src) => {
};
/* TODO
- * - display content on canvas
* - ready promise
**
- * types: image, [video, webcam], [canvas, shader]
+ * types: image, [video, webcam], [canvas, shader], raw
*/
class RepaTexture extends HTMLElement {
constructor() {
@@ -34,7 +33,7 @@ class RepaTexture extends HTMLElement {
}
static get observedAttributes() {
- return ['src', 'type', 'mag-filter', 'min-filter', 'filter', 'wrap-s', 'wrap-t', 'wrap'];
+ return ['src', 'type', 'mag-filter', 'min-filter', 'filter', 'wrap-s', 'wrap-t', 'wrap', 'format'];
}
attributeChangedCallback(name, oldValue, newValue) {
@@ -85,6 +84,8 @@ class RepaTexture extends HTMLElement {
if (this.ref) {
this.ready = true;
this._forceUpdate = true;
+ } else if (this.textContent) {
+ this.content = JSON.parse(this.textContent);
} else {
this.logger.error('Source cannot be loaded');
}
@@ -199,21 +200,42 @@ class RepaTexture extends HTMLElement {
} else if (this.ref.nodeName === 'REPA-SHADER') {
return 'shader';
}
+ } else if (this._content) {
+ return 'raw';
}
return null;
}
+ get flipY() {
+ return this.type !== 'raw';
+ }
+
+ // Array of Arrays
+ set content(data) {
+ this.ready = true;
+ this._type = 'raw';
+ this._format = 'luminance';
+ this._forceUpdate = true;
+
+ this._width = data[0].length;
+ this._height = data.length;
+ this._content = new Uint8Array(this._width * this._height);
+
+ data.forEach((row, y) => {
+ this._content.set(row, y * this._width);
+ });
+ }
+
get content() {
if (this.ref) {
if (this.type === 'shader') {
return this.ref.target;
- } else {
- return this.ref;
}
+ return this.ref;
}
- return null;
+ return this._content;
}
_guessType(src) {
@@ -253,11 +275,11 @@ class RepaTexture extends HTMLElement {
}
get width() {
- return this.ref?.videoWidth || this.ref?.width || 0;
+ return this._width || this.ref?.videoWidth || this.ref?.width || 0;
}
get height() {
- return this.ref?.videoHeight || this.ref?.height || 0;
+ return this._height || this.ref?.videoHeight || this.ref?.height || 0;
}
get magFilter() {
@@ -276,6 +298,10 @@ class RepaTexture extends HTMLElement {
return this.getAttribute('wrap-t') || this.getAttribute('wrap') || 'clamp-to-edge';
}
+ get format() {
+ return this._format || this.getAttribute('format') || 'rgba';
+ }
+
get name() {
if (!this._name) {
let name = this.getAttribute('name');