mirror of
https://github.com/dyuri/repa-shader.git
synced 2025-12-16 03:04:11 +00:00
texture loader
This commit is contained in:
parent
e79127a474
commit
9b2d99e5a0
BIN
demo/avatar.png
Normal file
BIN
demo/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 762 KiB |
BIN
demo/futas.mp4
Normal file
BIN
demo/futas.mp4
Normal file
Binary file not shown.
@ -22,7 +22,10 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<repa-shader fs-input="fsinput" alpha mouse snippets="noise.glsl" width=512 height=512>
|
||||
<repa-shader id="demoshader" fs-input="fsinput" alpha mouse snippets="noise.glsl" width=512 height=512>
|
||||
<repa-texture src="avatar.png"></repa-texture>
|
||||
<repa-texture src="futas.mp4"></repa-texture>
|
||||
<!-- repa-texture src="webcam"></repa-texture -->
|
||||
<script type="x-shader/x-fragmen[DELETE]t">
|
||||
// https://twigl.app/?ol=true&ss=-NOAlYulOVLklxMdxBDx
|
||||
void main() {
|
||||
|
||||
@ -7,6 +7,14 @@ const createLogger = pfx => {
|
||||
};
|
||||
};
|
||||
|
||||
const isImage = (src) => {
|
||||
return /\w+\.(jpg|png|jpeg|svg|webp)(?=\?|$)/i.test(src);
|
||||
};
|
||||
|
||||
const isVideo = (src) => {
|
||||
return /\w+\.(mp4|3gp|webm|ogv|avif)(?=\?|$)/i.test(src);
|
||||
};
|
||||
|
||||
const CHUNKS = {
|
||||
es300: '#version 300 es\n',
|
||||
geeker: `
|
||||
@ -52,7 +60,7 @@ class RepaShader extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.logger = createLogger(["%c[repa-shader]", "background: #1d2021; color: #bada55"]);
|
||||
this.logger = createLogger(["%c[repa-shader]", "background: #282828; color: #b8bb26"]);
|
||||
this._snippets = {};
|
||||
}
|
||||
|
||||
@ -595,8 +603,218 @@ void main() {
|
||||
return source;
|
||||
}
|
||||
|
||||
get canvas() {
|
||||
return this._target;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO
|
||||
* - display content on canvas
|
||||
* - src change
|
||||
* - ready promise
|
||||
**
|
||||
* types: image, [video, webcam], [canvas, shader]
|
||||
*/
|
||||
class RepaTexture extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.logger = createLogger(["%c[repa-texture]", "background: #282828; color: #fabd2f"]);
|
||||
this.ready = false;
|
||||
this._forceUpdate = false;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['src', 'type', 'name', 'mag-filter', 'min-filter', 'wrap-s', 'wrap-t'];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
// TODO
|
||||
this.logger.info(`Attribute changed: ${name} ${oldValue} -> ${newValue}`);
|
||||
this._load();
|
||||
}
|
||||
|
||||
async _load() {
|
||||
this.ready = false;
|
||||
|
||||
const ref = this.getAttribute('ref');
|
||||
if (ref) {
|
||||
const refEl = document.getElementById(ref);
|
||||
if (refEl) {
|
||||
this.ref = refEl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.ref) {
|
||||
const src = this.getAttribute('src');
|
||||
if (src) {
|
||||
this.ref = await this._loadSource(src);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ref) {
|
||||
this.ready = true;
|
||||
this._forceUpdate = true;
|
||||
} else {
|
||||
this.logger.error('Source cannot be loaded');
|
||||
}
|
||||
}
|
||||
|
||||
async _loadSource(src) {
|
||||
const type = this.getAttribute('type') || this._guessType(this.src);
|
||||
this._type = type;
|
||||
|
||||
if (!type) {
|
||||
this.logger.error(`Unknown type: ${src}`);
|
||||
} else {
|
||||
this.logger.log(`Loading ${src} as ${type}`);
|
||||
}
|
||||
|
||||
let ref = null;
|
||||
|
||||
switch (type) {
|
||||
case 'image':
|
||||
ref = await this._loadImage(src);
|
||||
break;
|
||||
case 'video':
|
||||
ref = await this._loadVideo(src);
|
||||
break;
|
||||
case 'webcam':
|
||||
ref = await this._createWebcam();
|
||||
break;
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
_hideInDOM(el) {
|
||||
const hiddenEl = document.createElement('div');
|
||||
hiddenEl.style.width = hiddenEl.style.height = '1px';
|
||||
hiddenEl.style.overflow = 'hidden';
|
||||
hiddenEl.style.position = 'absolute';
|
||||
hiddenEl.style.top = hiddenEl.style.left = '-100px';
|
||||
hiddenEl.style.zIndex = '-100';
|
||||
hiddenEl.style.opacity = '0';
|
||||
hiddenEl.style.pointerEvents = 'none';
|
||||
hiddenEl.appendChild(el);
|
||||
|
||||
document.body.appendChild(hiddenEl);
|
||||
}
|
||||
|
||||
async _loadImage(src) {
|
||||
const imgEl = document.createElement('img');
|
||||
imgEl.crossOrigin = 'anonymous';
|
||||
const loader = new Promise((resolve, reject) => {
|
||||
imgEl.onload = () => resolve(imgEl);
|
||||
imgEl.onerror = reject;
|
||||
imgEl.src = src;
|
||||
});
|
||||
|
||||
this._hideInDOM(imgEl);
|
||||
|
||||
return await loader;
|
||||
}
|
||||
|
||||
async _loadVideo(src) {
|
||||
const videoEl = document.createElement('video');
|
||||
videoEl.crossOrigin = 'anonymous';
|
||||
videoEl.autoplay = true;
|
||||
videoEl.loop = true;
|
||||
videoEl.muted = true;
|
||||
videoEl.playsInline = true;
|
||||
videoEl.src = src;
|
||||
|
||||
this._hideInDOM(videoEl);
|
||||
|
||||
return videoEl;
|
||||
}
|
||||
|
||||
async _createWebcam() {
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
const videoEl = document.createElement('video');
|
||||
videoEl.autoplay = true;
|
||||
videoEl.width = 640;
|
||||
videoEl.height = 480;
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
videoEl.srcObject = stream;
|
||||
|
||||
this._hideInDOM(videoEl);
|
||||
|
||||
return videoEl;
|
||||
}
|
||||
|
||||
this.logger.error('Webcam is not supported');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
get src() {
|
||||
return this.getAttribute('src');
|
||||
}
|
||||
|
||||
get type() {
|
||||
if (this._type) {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
if (this.ref) {
|
||||
if (this.ref instanceof HTMLImageElement) {
|
||||
return 'image';
|
||||
} else if (this.ref instanceof HTMLVideoElement) {
|
||||
return 'video';
|
||||
} else if (this.ref instanceof HTMLCanvasElement) {
|
||||
return 'canvas';
|
||||
} else if (this.ref instanceof RepaShader) {
|
||||
return 'shader';
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_guessType(src) {
|
||||
if (src.toLowerCase() === 'webcam') {
|
||||
return 'webcam';
|
||||
}
|
||||
|
||||
if (isImage(src)) {
|
||||
return 'image';
|
||||
}
|
||||
|
||||
if (isVideo(src)) {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
get shouldUpdate() {
|
||||
return this._forceUpdate || (this.ref && this.ref instanceof HTMLVideoElement && this.ref.readyState === this.ref.HAVE_ENOUGH_DATA);
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.ref?.videoWidth || this.ref?.width || 0;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.ref?.videoHeight || this.ref?.height || 0;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("repa-shader", RepaShader);
|
||||
customElements.define("repa-texture", RepaTexture);
|
||||
|
||||
export default RepaShader;
|
||||
|
||||
export {
|
||||
RepaShader,
|
||||
RepaTexture,
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user