245 lines
15 KiB
JavaScript
245 lines
15 KiB
JavaScript
|
globalThis.effectInit = (canvas) => {
|
||
|
var gShaderToy = null;
|
||
|
|
||
|
function ShaderToy() {
|
||
|
this.mAudioContext = null;
|
||
|
this.mCreated = false;
|
||
|
this.mHttpReq = null;
|
||
|
this.mEffect = null;
|
||
|
this.mTo = null;
|
||
|
this.mTOffset = 0;
|
||
|
this.mCanvas = canvas;
|
||
|
this.mFpsFrame = 0;
|
||
|
this.mFpsTo = null;
|
||
|
this.mIsPaused = false;
|
||
|
this.mForceFrame = true;
|
||
|
this.mInfo = null;
|
||
|
this.mCode = null;
|
||
|
|
||
|
var me = this;
|
||
|
|
||
|
this.mHttpReq = new XMLHttpRequest();
|
||
|
this.mTo = new Date().getTime();
|
||
|
this.mTf = this.mTOffset;
|
||
|
this.mFpsTo = this.mTo;
|
||
|
this.mMouseIsDown = false;
|
||
|
this.mMouseOriX = 0;
|
||
|
this.mMouseOriY = 0;
|
||
|
this.mMousePosX = 0;
|
||
|
this.mMousePosY = 0;
|
||
|
|
||
|
// --- audio context ---------------------
|
||
|
|
||
|
this.mAudioContext = piCreateAudioContext();
|
||
|
|
||
|
var resizeCB = function (xres, yres) {
|
||
|
me.mForceFrame = true;
|
||
|
};
|
||
|
var crashCB = function () {};
|
||
|
this.mEffect = new Effect(
|
||
|
null,
|
||
|
this.mAudioContext,
|
||
|
this.mCanvas,
|
||
|
this.RefreshTexturThumbail,
|
||
|
this,
|
||
|
true,
|
||
|
false,
|
||
|
resizeCB,
|
||
|
crashCB
|
||
|
);
|
||
|
this.mCreated = true;
|
||
|
}
|
||
|
|
||
|
ShaderToy.prototype.startRendering = function () {
|
||
|
var me = this;
|
||
|
|
||
|
function renderLoop2() {
|
||
|
setTimeout(renderLoop2, 1000 / 60);
|
||
|
|
||
|
if (me.mIsPaused && !me.mForceFrame) {
|
||
|
me.mEffect.UpdateInputs(0, false);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
me.mForceFrame = false;
|
||
|
var time = new Date().getTime();
|
||
|
var ltime = me.mTOffset + time - me.mTo;
|
||
|
|
||
|
if (me.mIsPaused) ltime = me.mTf;
|
||
|
else me.mTf = ltime;
|
||
|
|
||
|
var dtime = 1000.0 / 60.0;
|
||
|
|
||
|
me.mEffect.Paint(
|
||
|
ltime / 1000.0,
|
||
|
dtime / 1000.0,
|
||
|
60,
|
||
|
me.mMouseOriX,
|
||
|
me.mMouseOriY,
|
||
|
me.mMousePosX,
|
||
|
me.mMousePosY,
|
||
|
me.mIsPaused
|
||
|
);
|
||
|
|
||
|
me.mFpsFrame++;
|
||
|
|
||
|
if (time - me.mFpsTo > 1000) {
|
||
|
var ffps = (1000.0 * me.mFpsFrame) / (time - me.mFpsTo);
|
||
|
me.mFpsFrame = 0;
|
||
|
me.mFpsTo = time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
renderLoop2();
|
||
|
};
|
||
|
|
||
|
//---------------------------------
|
||
|
|
||
|
ShaderToy.prototype.Stop = function () {
|
||
|
this.mIsPaused = true;
|
||
|
this.mEffect.StopOutputs();
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.pauseTime = function () {
|
||
|
var time = new Date().getTime();
|
||
|
if (!this.mIsPaused) {
|
||
|
this.Stop();
|
||
|
} else {
|
||
|
this.mTOffset = this.mTf;
|
||
|
this.mTo = time;
|
||
|
this.mIsPaused = false;
|
||
|
this.mEffect.ResumeOutputs();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.resetTime = function () {
|
||
|
this.mTOffset = 0;
|
||
|
this.mTo = new Date().getTime();
|
||
|
this.mTf = 0;
|
||
|
this.mFpsTo = this.mTo;
|
||
|
this.mFpsFrame = 0;
|
||
|
this.mForceFrame = true;
|
||
|
this.mEffect.ResetTime();
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.PauseInput = function (id) {
|
||
|
return this.mEffect.PauseInput(0, id);
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.MuteInput = function (id) {
|
||
|
return this.mEffect.MuteInput(0, id);
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.RewindInput = function (id) {
|
||
|
this.mEffect.RewindInput(0, id);
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.SetTexture = function (slot, url) {
|
||
|
this.mEffect.NewTexture(0, slot, url);
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.RefreshTexturThumbail = function (
|
||
|
myself,
|
||
|
slot,
|
||
|
img,
|
||
|
forceFrame,
|
||
|
gui,
|
||
|
guiID,
|
||
|
time
|
||
|
) {
|
||
|
myself.mForceFrame = forceFrame;
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.GetTotalCompilationTime = function () {
|
||
|
return this.mEffect.GetTotalCompilationTime();
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.Load = function (jsn) {
|
||
|
try {
|
||
|
var res = this.mEffect.Load(jsn, false);
|
||
|
this.mCode = res.mShader;
|
||
|
|
||
|
if (res.mFailed === false) {
|
||
|
this.mForceFrame = true;
|
||
|
}
|
||
|
|
||
|
this.mInfo = jsn.info;
|
||
|
|
||
|
return {
|
||
|
mFailed: false,
|
||
|
mDate: jsn.info.date,
|
||
|
mViewed: jsn.info.viewed,
|
||
|
mName: jsn.info.name,
|
||
|
mUserName: jsn.info.username,
|
||
|
mDescription: jsn.info.description,
|
||
|
mLikes: jsn.info.likes,
|
||
|
mPublished: jsn.info.published,
|
||
|
mHasLiked: jsn.info.hasliked,
|
||
|
mTags: jsn.info.tags,
|
||
|
};
|
||
|
} catch (e) {
|
||
|
return { mFailed: true };
|
||
|
}
|
||
|
};
|
||
|
|
||
|
ShaderToy.prototype.Compile = function (onResolve) {
|
||
|
this.mEffect.Compile(true, onResolve);
|
||
|
};
|
||
|
|
||
|
function iCompileAndStart(jsnShader) {
|
||
|
gShaderToy = new ShaderToy();
|
||
|
|
||
|
var gRes = gShaderToy.Load(jsnShader[0]);
|
||
|
if (gRes.mFailed) {
|
||
|
gShaderToy.pauseTime();
|
||
|
gShaderToy.resetTime();
|
||
|
} else {
|
||
|
gShaderToy.Compile(function (worked) {
|
||
|
if (!worked) return;
|
||
|
|
||
|
if (gShaderToy.mIsPaused) {
|
||
|
gShaderToy.Stop();
|
||
|
}
|
||
|
|
||
|
gShaderToy.startRendering();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function watchInit() {
|
||
|
var jsnShader = [
|
||
|
{
|
||
|
ver: "0.1",
|
||
|
info: {
|
||
|
id: "fstyD4",
|
||
|
date: "1653482786",
|
||
|
viewed: 4819,
|
||
|
name: "Coastal Landscape",
|
||
|
username: "bitless",
|
||
|
description:
|
||
|
"I wanted to do something in the spirit of Van Gogh. It looks better on the full screen.",
|
||
|
likes: 234,
|
||
|
published: 1,
|
||
|
flags: 0,
|
||
|
usePreview: 0,
|
||
|
tags: [],
|
||
|
},
|
||
|
renderpass: [
|
||
|
{
|
||
|
inputs: [],
|
||
|
outputs: [{ id: "4dfGRr", channel: 0 }],
|
||
|
code: '// Author: bitless\n// Title: Coastal Landscape\n\n// Thanks to Patricio Gonzalez Vivo & Jen Lowe for "The Book of Shaders"\n// and Fabrice Neyret (FabriceNeyret2) for https://shadertoyunofficial.wordpress.com/\n// and Inigo Quilez (iq) for https://iquilezles.org/www/index.htm\n// and whole Shadertoy community for inspiration.\n\n#define p(t, a, b, c, d) ( a + b*cos( 6.28318*(c*t+d) ) ) //IQ\'s palette function (https://www.iquilezles.org/www/articles/palettes/palettes.htm)\n#define sp(t) p(t,vec3(.26,.76,.77),vec3(1,.3,1),vec3(.8,.4,.7),vec3(0,.12,.54)) //sky palette\n#define hue(v) ( .6 + .76 * cos(6.3*(v) + vec4(0,23,21,0) ) ) //hue\n\n// "Hash without Sine" by Dave_Hoskins.\n// https://www.shadertoy.com/view/4djSRW\nfloat hash12(vec2 p)\n{\n vec3 p3 = fract(vec3(p.xyx) * .1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\nvec2 hash22(vec2 p)\n{\n vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));\n p3 += dot(p3, p3.yzx+33.33);\n return fract((p3.xx+p3.yz)*p3.zy);\n}\n////////////////////////\n\nvec2 rotate2D (vec2 st, float a){\n return mat2(cos(a),-sin(a),sin(a),cos(a))*st;\n}\n\nfloat st(float a, float b, float s) //AA bar\n{\n return smoothstep (a-s, a+s, b);\n}\n\nfloat noise( in vec2 p ) //gradient noise\n{\n vec2 i = floor( p );\n vec2 f = fract( p );\n \n vec2 u = f*f*(3.-2.*f);\n\n return mix( mix( dot( hash22( i+vec2(0,0) ), f-vec2(0,0) ), \n dot( hash22( i+vec2(1,0) ), f-vec2(1,0) ), u.x),\n mix( dot( hash22( i+vec2(0,1) ), f-vec2(0,1) ), \n dot( hash22( i+vec2(1,1) ), f-vec2(1,1) ), u.x), u.y);\n}\n\nvoid mainImage( out vec4 O, in vec2 g)\n{\n vec2 r = iResolution.xy\n ,uv = (g+g-r)/r.y\n ,sun_pos = vec2(r.x/r.y*.42,-.53) //sun position \n ,tree_pos = vec2(-r.x/r.y*.42,-.2) //tree position \n ,sh, u, id, lc, t;\n\n vec3 f, c;\n float xd, yd, h, a, l;\n vec4 C;\n \n float sm = 3./r.y; //smoothness factor for AA\n\n sh = rotate2D(sun_pos, noise(uv+iTime*.25)*.3); //big noise on the sky\n \n if (uv.y > -.4) //drawing the sky\n {\n u = uv + sh;\n \n yd = 60.; //number of rings \n \n id = vec2((length(u)+.01)*yd,0); //segment id: x - ring number, y - segment number in the ring \n xd = floor(id.x)*.09; //number of ring segments\n h = (hash12(floor(id.xx))*.5+.25)*(iTime+10.)*.25; //ring shift\n t = rotate2D (u,h); //rotate the ring to the desired angle\n \n id.y = atan(t.y,t.x)*xd;\n lc = fract(id); //segment local coordinates\n id -= lc;\n \n // determining the coordinates of the center of the segment in uv space\n t = vec2(cos((id.y+.5)/xd)*(id.x+.5)/yd,sin((id.y+.5)/xd)*(id.x+.5)/yd); \n t = rotate2D(t,-h) - sh;\n \n h = noise(t*vec2(.5,1)-vec2(iTime*.2,0)) //clouds\n * step(-.25,t.y); //do not draw clouds below -.25\n h = smoothstep (.052,.055, h);\n \n \n lc += (noise(lc*vec2(1,4)+id))*vec2(.7,.2); //add fine noise\n \n f = mix (sp(sin(length(u)-.1))*.35, //sky background\n mix(sp(sin(length(u)-.1)+(hash12(id)-.5)*.15),vec3(1),h), //mix sky color and clouds\n st(abs(lc.x-.5),.4,sm*yd)*st(abs(lc.y-.5),.48,sm*xd));\n };\n\n if (uv.y < -.35) //drawing water\n {\n\n float cld = noise(-sh*vec2(.5,1) - vec2(iTime*.2,0)); //cloud density opposite the center of the sun\n cld = 1.- smoothstep(.0,.15,cld)*.5;\n\n u = uv*vec2(1,15);\n id = floor(u);\n\n for (float i = 1.; i > -1.; i--) //drawing a wave and its neighbors from above and below\n {\n if (id.y+i < -5.)\n {\n lc = fract(u)-.5;\n lc.y = (lc.y+(sin(uv.x*12.-iTime*3.+id.y+i))*.25-i)*4.; //set the waveform and divide it into four strips\n h = hash12(vec2(id.y+i,floor(lc.y))); //the number of segments in the strip and its horizontal offset\n
|
||
|
name: "Image",
|
||
|
description: "",
|
||
|
type: "image",
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
];
|
||
|
|
||
|
iCompileAndStart(jsnShader);
|
||
|
}
|
||
|
|
||
|
watchInit();
|
||
|
};
|