mirror of
https://github.com/dyuri/repa-shader.git
synced 2025-12-16 11:14:25 +00:00
mrt, vertex-shader loading
This commit is contained in:
parent
b0d7efe523
commit
e79127a474
10
TODO.md
Normal file
10
TODO.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
- textures
|
||||||
|
- image
|
||||||
|
- canvas
|
||||||
|
- video
|
||||||
|
- webcam
|
||||||
|
- audio
|
||||||
|
- mic?
|
||||||
|
- fix mouse, add button, drag
|
||||||
|
- device orientation
|
||||||
|
|
||||||
@ -23,18 +23,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<repa-shader fs-input="fsinput" alpha mouse snippets="noise.glsl" width=512 height=512>
|
<repa-shader fs-input="fsinput" alpha mouse snippets="noise.glsl" width=512 height=512>
|
||||||
<script type="x-shader/x-fragment">
|
<script type="x-shader/x-fragmen[DELETE]t">
|
||||||
void main() {
|
|
||||||
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
|
||||||
vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4));
|
|
||||||
|
|
||||||
float dist = distance(uv, mouse);
|
|
||||||
float circle = smoothstep(.15, .2, dist);
|
|
||||||
vec4 acolor = vec4(col * (1. - circle), (1. - circle)) + circle * texture(backbuffer, uv - vec2(.01, .01)) * .9;
|
|
||||||
outColor = vec4(acolor);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="x-shader/x-fragmen">
|
|
||||||
// https://twigl.app/?ol=true&ss=-NOAlYulOVLklxMdxBDx
|
// https://twigl.app/?ol=true&ss=-NOAlYulOVLklxMdxBDx
|
||||||
void main() {
|
void main() {
|
||||||
vec2 n,N,q,p=FC.xy/r.y;
|
vec2 n,N,q,p=FC.xy/r.y;
|
||||||
|
|||||||
69
demo/mrt.html
Normal file
69
demo/mrt.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title><repa-shader> demo</title>
|
||||||
|
<script type="module" src="../src/repa-shader.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: repeating-linear-gradient(45deg, #333, #333 10px, #666 10px, #666 20px);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#fsinput {
|
||||||
|
width: 90vw;
|
||||||
|
height: 50vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<repa-shader fs-input="fsinput" mouse snippets="noise.glsl" width=512 height=512 render-target-count=2>
|
||||||
|
<script type="x-shader/x-fragment">
|
||||||
|
#define R rotate2D
|
||||||
|
vec2 c=FC.xy;
|
||||||
|
vec2 uv=FC.xy/r.xy;
|
||||||
|
vec2 q;
|
||||||
|
vec2 p=(c+c-r)/r.y;
|
||||||
|
vec2 n;
|
||||||
|
vec4 color;
|
||||||
|
|
||||||
|
float S=6.;
|
||||||
|
float a;
|
||||||
|
float d=dot(p,p);
|
||||||
|
float e=200.;
|
||||||
|
p/=.7-d;
|
||||||
|
p+=t/PI;
|
||||||
|
|
||||||
|
for(float i = 0.; i < e; i++) {
|
||||||
|
color+=(texture(b1,(c/r-.5)*i/e+.5))/e;
|
||||||
|
p*=R(5.);
|
||||||
|
n*=R(5.);
|
||||||
|
a+=dot(sin(q=p*S+i-abs(n)*R(t*.2))/S,r/r);
|
||||||
|
n+=cos(q),S*=1.1;
|
||||||
|
}
|
||||||
|
// a = max(s,.9-a*.2-d);
|
||||||
|
a = max(0.,.9-a*.2-d);
|
||||||
|
o1=pow(a+a*vec4(8,4,1,0)/e,color+40.);
|
||||||
|
float center = smoothstep(.45, .55, uv.x);
|
||||||
|
o0=center*color + o1;
|
||||||
|
</script>
|
||||||
|
</repa-shader>
|
||||||
|
<div>
|
||||||
|
<textarea id="fsinput"></textarea>
|
||||||
|
</div>
|
||||||
|
<button id="update">Update</button>
|
||||||
|
<script>
|
||||||
|
const updateButton = document.getElementById('update');
|
||||||
|
updateButton.addEventListener('click', () => {
|
||||||
|
const fsinput = document.getElementById('fsinput');
|
||||||
|
const shader = document.querySelector('repa-shader');
|
||||||
|
shader.render(fsinput.value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -15,16 +15,12 @@ const CHUNKS = {
|
|||||||
#define m mouse
|
#define m mouse
|
||||||
#define t time
|
#define t time
|
||||||
#define f frame
|
#define f frame
|
||||||
#define b backbuffer
|
|
||||||
#define o outColor
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
uniform vec2 mouse;
|
uniform vec3 mouse;
|
||||||
uniform float time;
|
uniform float time;
|
||||||
uniform float frame;
|
uniform float frame;
|
||||||
uniform sampler2D backbuffer;
|
`,
|
||||||
out vec4 outColor;
|
|
||||||
`, // TODO MRT
|
|
||||||
geekestStart: `
|
geekestStart: `
|
||||||
void main() {
|
void main() {
|
||||||
`,
|
`,
|
||||||
@ -34,22 +30,24 @@ void main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DEMO_FS = `
|
const DEMO_FS = `
|
||||||
precision highp float;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
uniform vec2 mouse;
|
|
||||||
uniform float time;
|
|
||||||
out vec4 outColor;
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
||||||
vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4));
|
vec3 col = .5 + .5 * cos(uv.xyx + time + vec3(0, 2, 4));
|
||||||
|
|
||||||
float dist = distance(uv, mouse);
|
float dist = distance(uv, mouse.xy);
|
||||||
float circle = smoothstep(.1, .2, dist) * .5 + .5;
|
float circle = smoothstep(.1, .2, dist) * .5 + .5;
|
||||||
vec4 acolor = vec4(col * circle, circle);
|
vec4 acolor = vec4(col * circle, circle);
|
||||||
outColor = vec4(acolor);
|
outColor = vec4(acolor);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const DEFAULT_VS = `#version 300 es
|
||||||
|
in vec3 position;
|
||||||
|
void main(){
|
||||||
|
gl_Position=vec4(position, 1.);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
class RepaShader extends HTMLElement {
|
class RepaShader extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -94,12 +92,16 @@ class RepaShader extends HTMLElement {
|
|||||||
this._gl.disable(this._gl.BLEND);
|
this._gl.disable(this._gl.BLEND);
|
||||||
this._gl.clearColor(0,0,0,1);
|
this._gl.clearColor(0,0,0,1);
|
||||||
|
|
||||||
this.render(this.getFragmentShaderSource());
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
render(source, time) {
|
disconnectedCallback() {
|
||||||
|
// TODO stop animation
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(source, time) {
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return;
|
source = await this.getFragmentShaderSource();
|
||||||
}
|
}
|
||||||
this._fsSource = source;
|
this._fsSource = source;
|
||||||
this.reset(time);
|
this.reset(time);
|
||||||
@ -161,10 +163,11 @@ class RepaShader extends HTMLElement {
|
|||||||
this._gl.viewport(0, 0, width, height);
|
this._gl.viewport(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseMove(e) {
|
_onMouseEvent(e) {
|
||||||
const x = Math.min(Math.max(e.offsetX, 0), this._target.width);
|
const x = Math.min(Math.max(e.offsetX, 0), this._target.width);
|
||||||
const y = Math.min(Math.max(e.offsetY, 0), this._target.height);
|
const y = Math.min(Math.max(e.offsetY, 0), this._target.height);
|
||||||
this._mousePosition = [x / this._target.width, 1 - y / this._target.height];
|
const btn = e.buttons;
|
||||||
|
this._mousePosition = [x / this._target.width, 1 - y / this._target.height, btn];
|
||||||
}
|
}
|
||||||
|
|
||||||
_resetBuffer(buff) {
|
_resetBuffer(buff) {
|
||||||
@ -186,11 +189,15 @@ class RepaShader extends HTMLElement {
|
|||||||
buff.renderbuffer = null;
|
buff.renderbuffer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// texture
|
// textures
|
||||||
if (buff.texture && this._gl.isTexture(buff.texture)) {
|
if (buff.textures?.length) {
|
||||||
this._gl.bindTexture(this._gl.TEXTURE_2D, null);
|
buff.textures.forEach(t => {
|
||||||
this._gl.deleteTexture(buff.texture);
|
if (this._gl.isTexture(t)) {
|
||||||
buff.texture = null;
|
this._gl.bindTexture(this._gl.TEXTURE_2D, null);
|
||||||
|
this._gl.deleteTexture(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
buff.textures = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,15 +214,21 @@ class RepaShader extends HTMLElement {
|
|||||||
this._gl.renderbufferStorage(this._gl.RENDERBUFFER, this._gl.DEPTH_COMPONENT16, w, h);
|
this._gl.renderbufferStorage(this._gl.RENDERBUFFER, this._gl.DEPTH_COMPONENT16, w, h);
|
||||||
this._gl.framebufferRenderbuffer(this._gl.FRAMEBUFFER, this._gl.DEPTH_ATTACHMENT, this._gl.RENDERBUFFER, buff.renderbuffer);
|
this._gl.framebufferRenderbuffer(this._gl.FRAMEBUFFER, this._gl.DEPTH_ATTACHMENT, this._gl.RENDERBUFFER, buff.renderbuffer);
|
||||||
|
|
||||||
// texture
|
// textures
|
||||||
buff.texture = this._gl.createTexture();
|
buff.textures = [];
|
||||||
this._gl.bindTexture(this._gl.TEXTURE_2D, buff.texture);
|
buff.buffers = []; // TODO ???
|
||||||
this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, w, h, 0, this._gl.RGBA, this._gl.UNSIGNED_BYTE, null);
|
for (let i = 0; i < this.mrt; i++) {
|
||||||
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
|
let texture = this._gl.createTexture();
|
||||||
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
|
this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
|
||||||
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
|
this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, w, h, 0, this._gl.RGBA, this._gl.UNSIGNED_BYTE, null);
|
||||||
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
|
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
|
||||||
this._gl.framebufferTexture2D(this._gl.FRAMEBUFFER, this._gl.COLOR_ATTACHMENT0, this._gl.TEXTURE_2D, buff.texture, 0);
|
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
|
||||||
|
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
|
||||||
|
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
|
||||||
|
this._gl.framebufferTexture2D(this._gl.FRAMEBUFFER, this._gl.COLOR_ATTACHMENT0 + i, this._gl.TEXTURE_2D, texture, 0);
|
||||||
|
buff.textures.push(texture);
|
||||||
|
buff.buffers.push(this._gl.COLOR_ATTACHMENT0 + i);
|
||||||
|
}
|
||||||
|
|
||||||
// unbind
|
// unbind
|
||||||
this._gl.bindTexture(this._gl.TEXTURE_2D, null);
|
this._gl.bindTexture(this._gl.TEXTURE_2D, null);
|
||||||
@ -233,17 +246,19 @@ class RepaShader extends HTMLElement {
|
|||||||
async reset(time) {
|
async reset(time) {
|
||||||
this._resizeTarget();
|
this._resizeTarget();
|
||||||
this._resetBuffers();
|
this._resetBuffers();
|
||||||
this.backbuffer = this._createBuffer(this._target.width, this._target.height);
|
|
||||||
this.frontbuffer = this._createBuffer(this._target.width, this._target.height);
|
this.frontbuffer = this._createBuffer(this._target.width, this._target.height);
|
||||||
|
this.backbuffer = this._createBuffer(this._target.width, this._target.height);
|
||||||
|
|
||||||
if (this.hasAttribute('mouse')) {
|
if (this.hasAttribute('mouse')) {
|
||||||
this._target.addEventListener('pointermove', this._onMouseMove.bind(this));
|
this._target.addEventListener('mousemove', this._onMouseEvent.bind(this));
|
||||||
|
this._target.addEventListener('mousedown', this._onMouseEvent.bind(this));
|
||||||
|
this._target.addEventListener('mouseup', this._onMouseEvent.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mode = this.getAttribute('mode') || this.mode;
|
this.mode = this.getAttribute('mode') || this.mode;
|
||||||
|
|
||||||
const program = this._gl.createProgram();
|
const program = this._gl.createProgram();
|
||||||
const vs = this._createShader(program, this.VS, true);
|
const vs = this._createShader(program, await this.getVS(), true);
|
||||||
if (!vs) {
|
if (!vs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -265,7 +280,7 @@ class RepaShader extends HTMLElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO sound? mrt? textures?
|
// TODO sound? textures?
|
||||||
|
|
||||||
if (this._program) {
|
if (this._program) {
|
||||||
this._gl.deleteProgram(this._program);
|
this._gl.deleteProgram(this._program);
|
||||||
@ -277,10 +292,14 @@ class RepaShader extends HTMLElement {
|
|||||||
this._uniLocation.mouse = this._gl.getUniformLocation(this.program, 'mouse');
|
this._uniLocation.mouse = this._gl.getUniformLocation(this.program, 'mouse');
|
||||||
this._uniLocation.time = this._gl.getUniformLocation(this.program, 'time');
|
this._uniLocation.time = this._gl.getUniformLocation(this.program, 'time');
|
||||||
this._uniLocation.frame = this._gl.getUniformLocation(this.program, 'frame');
|
this._uniLocation.frame = this._gl.getUniformLocation(this.program, 'frame');
|
||||||
this._uniLocation.backbuffer = this._gl.getUniformLocation(this.program, 'backbuffer');
|
|
||||||
|
// backbuffers
|
||||||
|
for (let i = 0; i < this.mrt; i++) {
|
||||||
|
this._uniLocation[`backbuffer${i}`] = this._gl.getUniformLocation(this.program, `backbuffer${i}`);
|
||||||
|
}
|
||||||
|
|
||||||
this._attLocation = this._gl.getAttribLocation(this.program, 'position');
|
this._attLocation = this._gl.getAttribLocation(this.program, 'position');
|
||||||
this._mousePosition= [0, 0];
|
this._mousePosition= [0, 0, 0];
|
||||||
this._startTime = Date.now();
|
this._startTime = Date.now();
|
||||||
this._frame = 0;
|
this._frame = 0;
|
||||||
|
|
||||||
@ -288,10 +307,6 @@ class RepaShader extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw(time) {
|
draw(time) {
|
||||||
if (this.running) {
|
|
||||||
requestAnimationFrame(this.draw.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time) {
|
if (time) {
|
||||||
this._nowTime = time;
|
this._nowTime = time;
|
||||||
} else {
|
} else {
|
||||||
@ -305,15 +320,19 @@ class RepaShader extends HTMLElement {
|
|||||||
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, this.frontbuffer.framebuffer);
|
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, this.frontbuffer.framebuffer);
|
||||||
|
|
||||||
// backbuffer
|
// backbuffer
|
||||||
this._gl.activeTexture(this._gl.TEXTURE0);
|
this._gl.drawBuffers(this.frontbuffer.buffers);
|
||||||
this._gl.bindTexture(this._gl.TEXTURE_2D, this.backbuffer.texture);
|
|
||||||
this._gl.uniform1i(this._uniLocation.backbuffer, 0);
|
for (let i = 0; i < this.mrt; i++) {
|
||||||
|
this._gl.activeTexture(this._gl.TEXTURE0 + i);
|
||||||
|
this._gl.bindTexture(this._gl.TEXTURE_2D, this.backbuffer.textures[i]);
|
||||||
|
this._gl.uniform1i(this._uniLocation[`backbuffer${i}`], i);
|
||||||
|
}
|
||||||
|
|
||||||
this._gl.enableVertexAttribArray(this._attLocation);
|
this._gl.enableVertexAttribArray(this._attLocation);
|
||||||
this._gl.vertexAttribPointer(this._attLocation, 3, this._gl.FLOAT, false, 0, 0);
|
this._gl.vertexAttribPointer(this._attLocation, 3, this._gl.FLOAT, false, 0, 0);
|
||||||
this._gl.clear(this._gl.COLOR_BUFFER_BIT);
|
this._gl.clear(this._gl.COLOR_BUFFER_BIT);
|
||||||
this._gl.uniform2fv(this._uniLocation.resolution, [this._target.width, this._target.height]);
|
this._gl.uniform2fv(this._uniLocation.resolution, [this._target.width, this._target.height]);
|
||||||
this._gl.uniform2fv(this._uniLocation.mouse, this._mousePosition);
|
this._gl.uniform3fv(this._uniLocation.mouse, this._mousePosition);
|
||||||
this._gl.uniform1f(this._uniLocation.time, this._nowTime * .001);
|
this._gl.uniform1f(this._uniLocation.time, this._nowTime * .001);
|
||||||
this._gl.uniform1f(this._uniLocation.frame, this._frame);
|
this._gl.uniform1f(this._uniLocation.frame, this._frame);
|
||||||
|
|
||||||
@ -323,7 +342,7 @@ class RepaShader extends HTMLElement {
|
|||||||
this._gl.useProgram(this._postProgram);
|
this._gl.useProgram(this._postProgram);
|
||||||
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, null);
|
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, null);
|
||||||
this._gl.activeTexture(this._gl.TEXTURE0);
|
this._gl.activeTexture(this._gl.TEXTURE0);
|
||||||
this._gl.bindTexture(this._gl.TEXTURE_2D, this.frontbuffer.texture);
|
this._gl.bindTexture(this._gl.TEXTURE_2D, this.frontbuffer.textures[0]);
|
||||||
this._gl.enableVertexAttribArray(this._postAttLocation);
|
this._gl.enableVertexAttribArray(this._postAttLocation);
|
||||||
this._gl.vertexAttribPointer(this._postAttLocation, 3, this._gl.FLOAT, false, 0, 0);
|
this._gl.vertexAttribPointer(this._postAttLocation, 3, this._gl.FLOAT, false, 0, 0);
|
||||||
this._gl.clear(this._gl.COLOR_BUFFER_BIT);
|
this._gl.clear(this._gl.COLOR_BUFFER_BIT);
|
||||||
@ -336,6 +355,10 @@ class RepaShader extends HTMLElement {
|
|||||||
[this.frontbuffer, this.backbuffer] = [this.backbuffer, this.frontbuffer];
|
[this.frontbuffer, this.backbuffer] = [this.backbuffer, this.frontbuffer];
|
||||||
|
|
||||||
// TODO draw callback
|
// TODO draw callback
|
||||||
|
|
||||||
|
if (this.running) {
|
||||||
|
requestAnimationFrame(this.draw.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run() {
|
run() {
|
||||||
@ -377,11 +400,11 @@ class RepaShader extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get width() {
|
get width() {
|
||||||
return this.getAttribute('width');
|
return parseInt(this.getAttribute('width'), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
get height() {
|
get height() {
|
||||||
return this.getAttribute('height');
|
return parseInt(this.getAttribute('height'), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createTarget() {
|
_createTarget() {
|
||||||
@ -412,12 +435,8 @@ class RepaShader extends HTMLElement {
|
|||||||
return this._target;
|
return this._target;
|
||||||
}
|
}
|
||||||
|
|
||||||
get VS() {
|
get mrt() {
|
||||||
return `#version 300 es
|
return +this.getAttribute('render-target-count') || 1;
|
||||||
in vec3 position;
|
|
||||||
void main(){
|
|
||||||
gl_Position=vec4(position, 1.);
|
|
||||||
}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get postVS() {
|
get postVS() {
|
||||||
@ -441,13 +460,59 @@ void main() {
|
|||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getRenderTargets() {
|
||||||
|
const targets = [];
|
||||||
|
|
||||||
|
if (this.mrt > 1) {
|
||||||
|
for (let i = 0; i < this.mrt; i++) {
|
||||||
|
const target = `
|
||||||
|
#define b${i} backbuffer${i}
|
||||||
|
#define o${i} outColor${i}
|
||||||
|
uniform sampler2D backbuffer${i};
|
||||||
|
layout (location = ${i}) out vec4 outColor${i};
|
||||||
|
`;
|
||||||
|
targets.push(target);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targets.push(`
|
||||||
|
#define b backbuffer0
|
||||||
|
#define o outColor0
|
||||||
|
#define backbuffer backbuffer0
|
||||||
|
#define outColor outColor0
|
||||||
|
uniform sampler2D backbuffer0;
|
||||||
|
layout (location = 0) out vec4 outColor0;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targets.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getVS() {
|
||||||
|
let source = '';
|
||||||
|
|
||||||
|
const vsEl = this.querySelector('script[type="x-shader/x-vertex"]');
|
||||||
|
if (vsEl) {
|
||||||
|
const vsSrc = vsEl.getAttribute('src');
|
||||||
|
if (vsSrc) {
|
||||||
|
source = await fetch(vsSrc).then(res => res.text());
|
||||||
|
} else {
|
||||||
|
source = vsEl.textContent.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!source) {
|
||||||
|
source = DEFAULT_VS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
async getFS() {
|
async getFS() {
|
||||||
// auto guessing mode
|
// auto guessing mode
|
||||||
// - starts with #version -> raw
|
// - starts with #version -> raw
|
||||||
// - contains `precision` -> twigl classic300es
|
// - contains `precision` -> twigl classic300es
|
||||||
// - no `precision`, but has `main()` -> twigl geeker300es
|
// - no `precision`, but has `main()` -> twigl geeker300es
|
||||||
// - no `precision`, no `main()` -> twigl geekest300es
|
// - no `precision`, no `main()` -> twigl geekest300es
|
||||||
// TODO: mrt
|
|
||||||
let mode = this.mode;
|
let mode = this.mode;
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
const hasVersion = this._fsSource.startsWith('#version');
|
const hasVersion = this._fsSource.startsWith('#version');
|
||||||
@ -476,12 +541,14 @@ void main() {
|
|||||||
break;
|
break;
|
||||||
case 'geeker':
|
case 'geeker':
|
||||||
snippets = await this._getSnippets();
|
snippets = await this._getSnippets();
|
||||||
start = CHUNKS.es300 + CHUNKS.geeker + snippets;
|
start = CHUNKS.es300 + CHUNKS.geeker + this._getRenderTargets() + snippets;
|
||||||
break;
|
break;
|
||||||
case 'geekest':
|
case 'geekest':
|
||||||
snippets = await this._getSnippets();
|
snippets = await this._getSnippets();
|
||||||
const noise = await this.getSnippet('noise.glsl');
|
if (!snippets) {
|
||||||
start = CHUNKS.es300 + CHUNKS.geeker + noise + snippets + CHUNKS.geekestStart;
|
snippets = await this.getSnippet('noise.glsl');
|
||||||
|
}
|
||||||
|
start = CHUNKS.es300 + CHUNKS.geeker + this._getRenderTargets() + snippets + CHUNKS.geekestStart;
|
||||||
end = CHUNKS.geekestEnd;
|
end = CHUNKS.geekestEnd;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -489,7 +556,7 @@ void main() {
|
|||||||
return `${start}\n${this._fsSource}\n${end}`;
|
return `${start}\n${this._fsSource}\n${end}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFragmentShaderSource() {
|
async getFragmentShaderSource() {
|
||||||
let source = '';
|
let source = '';
|
||||||
|
|
||||||
// text area editor
|
// text area editor
|
||||||
@ -506,7 +573,12 @@ void main() {
|
|||||||
if (!source) {
|
if (!source) {
|
||||||
const fsEl = this.querySelector('script[type="x-shader/x-fragment"]');
|
const fsEl = this.querySelector('script[type="x-shader/x-fragment"]');
|
||||||
if (fsEl) {
|
if (fsEl) {
|
||||||
source = fsEl.textContent;
|
const fsSrc = fsEl.getAttribute('src');
|
||||||
|
if (fsSrc) {
|
||||||
|
source = await fetch(fsSrc).then(res => res.text());
|
||||||
|
} else {
|
||||||
|
source = fsEl.textContent.trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user