@sangwonl/pocato-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +34 -0
- package/dist/index.js +1700 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1700 @@
|
|
|
1
|
+
// src/event-emitter.ts
|
|
2
|
+
var EventEmitter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, handler) {
|
|
7
|
+
if (!this.listeners.has(event)) {
|
|
8
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
9
|
+
}
|
|
10
|
+
this.listeners.get(event).add(handler);
|
|
11
|
+
}
|
|
12
|
+
off(event, handler) {
|
|
13
|
+
this.listeners.get(event)?.delete(handler);
|
|
14
|
+
}
|
|
15
|
+
emit(event, ...args) {
|
|
16
|
+
this.listeners.get(event)?.forEach((handler) => {
|
|
17
|
+
try {
|
|
18
|
+
handler(...args);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
console.error(`[pocato] Error in ${event} handler:`, e);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
removeAllListeners() {
|
|
25
|
+
this.listeners.clear();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/renderer/index.ts
|
|
30
|
+
import * as THREE2 from "three";
|
|
31
|
+
|
|
32
|
+
// src/renderer/shader-bootstrap.ts
|
|
33
|
+
import * as THREE from "three";
|
|
34
|
+
|
|
35
|
+
// src/shaders/lygia/math/permute.glsl
|
|
36
|
+
var permute_default = '#include "mod289.glsl"\n\n/*\ncontributors: [Stefan Gustavson, Ian McEwan]\ndescription: permute\nuse: <float|vec2|vec3|vec4> permute(<float|vec2|vec3|vec4> x)\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/math_functions.frag\n*/\n\n#ifndef FNC_PERMUTE\n#define FNC_PERMUTE\n\nfloat permute(const in float v) { return mod289(((v * 34.0) + 1.0) * v); }\nvec2 permute(const in vec2 v) { return mod289(((v * 34.0) + 1.0) * v); }\nvec3 permute(const in vec3 v) { return mod289(((v * 34.0) + 1.0) * v); }\nvec4 permute(const in vec4 v) { return mod289(((v * 34.0) + 1.0) * v); }\n\n#endif\n';
|
|
37
|
+
|
|
38
|
+
// src/shaders/lygia/math/mod289.glsl
|
|
39
|
+
var mod289_default = "/*\ncontributors: [Stefan Gustavson, Ian McEwan]\ndescription: modulus of 289\nuse: <float|vec2|vec3|vec4> mod289(<float|vec2|vec3|vec4> x)\n*/\n\n#ifndef FNC_MOD289\n#define FNC_MOD289\n\nfloat mod289(const in float x) { return x - floor(x * (1. / 289.)) * 289.; }\nvec2 mod289(const in vec2 x) { return x - floor(x * (1. / 289.)) * 289.; }\nvec3 mod289(const in vec3 x) { return x - floor(x * (1. / 289.)) * 289.; }\nvec4 mod289(const in vec4 x) { return x - floor(x * (1. / 289.)) * 289.; }\n\n#endif\n";
|
|
40
|
+
|
|
41
|
+
// src/shaders/lygia/math/taylorInvSqrt.glsl
|
|
42
|
+
var taylorInvSqrt_default = "/*\ncontributors: [Stefan Gustavson, Ian McEwan]\ndescription: Fast, accurate inverse square root. \nuse: <float|vec2|vec3|vec4> taylorInvSqrt(<float|vec2|vec3|vec4> x)\n*/\n\n#ifndef FNC_TAYLORINVSQRT\n#define FNC_TAYLORINVSQRT\nfloat taylorInvSqrt(in float r) { return 1.79284291400159 - 0.85373472095314 * r; }\nvec2 taylorInvSqrt(in vec2 r) { return 1.79284291400159 - 0.85373472095314 * r; }\nvec3 taylorInvSqrt(in vec3 r) { return 1.79284291400159 - 0.85373472095314 * r; }\nvec4 taylorInvSqrt(in vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n#endif";
|
|
43
|
+
|
|
44
|
+
// src/shaders/lygia/math/grad4.glsl
|
|
45
|
+
var grad4_default = "/*\ncontributors: [Stefan Gustavson, Ian McEwan]\ndescription: grad4, used for snoise(vec4 v)\nuse: grad4(<float> j, <vec4> ip)\n*/\n\n#ifndef FNC_GRAD4\n#define FNC_GRAD4\nvec4 grad4(float j, vec4 ip) {\n const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);\n vec4 p,s;\n p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;\n p.w = 1.5 - dot(abs(p.xyz), ones.xyz);\n s = vec4(lessThan(p, vec4(0.0)));\n p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;\n return p;\n}\n#endif\n";
|
|
46
|
+
|
|
47
|
+
// src/shaders/lygia/math/rotate4d.glsl
|
|
48
|
+
var rotate4d_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: returns a 4x4 rotation matrix\nuse: <mat4> rotate4d(<vec3> axis, <float> radians)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_ROTATE4D\n#define FNC_ROTATE4D\nmat4 rotate4d(in vec3 a, const in float r) {\n a = normalize(a);\n float s = sin(r);\n float c = cos(r);\n float oc = 1.0 - c;\n vec4 col1 = vec4(oc * a.x * a.x + c, oc * a.x * a.y + a.z * s, oc * a.z * a.x - a.y * s, 0.0);\n vec4 col2 = vec4(oc * a.x * a.y - a.z * s, oc * a.y * a.y + c, oc * a.y * a.z + a.x * s, 0.0);\n vec4 col3 = vec4(oc * a.z * a.x + a.y * s, oc * a.y * a.z - a.x * s, oc * a.z * a.z + c, 0.0);\n vec4 col4 = vec4(0.0, 0.0, 0.0, 1.0);\n return mat4(col1, col2, col3, col4);\n}\n#endif\n";
|
|
49
|
+
|
|
50
|
+
// src/shaders/lygia/math/cubic.glsl
|
|
51
|
+
var cubic_default = "/*\ncontributors: Inigo Quiles\ndescription: cubic polynomial https://iquilezles.org/articles/smoothsteps/\nuse: <float|vec2|vec3|vec4> cubic(<float|vec2|vec3|vec4> value[, <float> in, <float> out]);\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/math_functions.frag\n*/\n\n#ifndef FNC_CUBIC\n#define FNC_CUBIC \nfloat cubic(const in float v) { return v*v*(3.0-2.0*v); }\nvec2 cubic(const in vec2 v) { return v*v*(3.0-2.0*v); }\nvec3 cubic(const in vec3 v) { return v*v*(3.0-2.0*v); }\nvec4 cubic(const in vec4 v) { return v*v*(3.0-2.0*v); }\n\nfloat cubic(const in float v, in float slope0, in float slope1) {\n float a = slope0 + slope1 - 2.;\n float b = -2. * slope0 - slope1 + 3.;\n float c = slope0;\n float v2 = v * v;\n float v3 = v * v2;\n return a * v3 + b * v2 + c * v;\n}\n\nvec2 cubic(const in vec2 v, in float slope0, in float slope1) {\n float a = slope0 + slope1 - 2.;\n float b = -2. * slope0 - slope1 + 3.;\n float c = slope0;\n vec2 v2 = v * v;\n vec2 v3 = v * v2;\n return a * v3 + b * v2 + c * v;\n}\n\nvec3 cubic(const in vec3 v, in float slope0, in float slope1) {\n float a = slope0 + slope1 - 2.;\n float b = -2. * slope0 - slope1 + 3.;\n float c = slope0;\n vec3 v2 = v * v;\n vec3 v3 = v * v2;\n return a * v3 + b * v2 + c * v;\n}\n\nvec4 cubic(const in vec4 v, in float slope0, in float slope1) {\n float a = slope0 + slope1 - 2.;\n float b = -2. * slope0 - slope1 + 3.;\n float c = slope0;\n vec4 v2 = v * v;\n vec4 v3 = v * v2;\n return a * v3 + b * v2 + c * v;\n}\n#endif";
|
|
52
|
+
|
|
53
|
+
// src/shaders/lygia/math/quintic.glsl
|
|
54
|
+
var quintic_default = "/*\ncontributors: Inigo Quiles\ndescription: quintic polynomial https://iquilezles.org/articles/smoothsteps/\nuse: <float|vec2|vec3|vec4> quintic(<float|vec2|vec3|vec4> value);\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/math_functions.frag\n*/\n\n#ifndef FNC_QUINTIC\n#define FNC_QUINTIC \n\nfloat quintic(const in float v) { return v*v*v*(v*(v*6.0-15.0)+10.0); }\nvec2 quintic(const in vec2 v) { return v*v*v*(v*(v*6.0-15.0)+10.0); }\nvec3 quintic(const in vec3 v) { return v*v*v*(v*(v*6.0-15.0)+10.0); }\nvec4 quintic(const in vec4 v) { return v*v*v*(v*(v*6.0-15.0)+10.0); }\n\n#endif";
|
|
55
|
+
|
|
56
|
+
// src/shaders/lygia/math/sum.glsl
|
|
57
|
+
var sum_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: Sum elements of a vector\nuse: <float> sum(<vec2|vec3|vec4> value)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_SUM\n#define FNC_SUM\nfloat sum( float v ) { return v; }\nfloat sum( vec2 v ) { return v.x+v.y; }\nfloat sum( vec3 v ) { return v.x+v.y+v.z; }\nfloat sum( vec4 v ) { return v.x+v.y+v.z+v.w; }\n#endif\n";
|
|
58
|
+
|
|
59
|
+
// src/shaders/lygia/math/saturate.glsl
|
|
60
|
+
var saturate_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: clamp a value between 0 and 1\nuse: <float|vec2|vec3|vec4> saturation(<float|vec2|vec3|vec4> value)\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/math_functions.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#if !defined(FNC_SATURATE) && !defined(saturate)\n#define FNC_SATURATE\n#define saturate(V) clamp(V, 0.0, 1.0)\n#endif";
|
|
61
|
+
|
|
62
|
+
// src/shaders/lygia/math/gaussian.glsl
|
|
63
|
+
var gaussian_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: gaussian coefficient\nuse: <vec4|vec3|vec2|float> gaussian(<float> sigma, <vec4|vec3|vec2|float> d)\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/math_gaussian.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_GAUSSIAN\n#define FNC_GAUSSIAN\nfloat gaussian(float d, float s) { return exp(-(d*d) / (2.0 * s*s)); }\nfloat gaussian( vec2 d, float s) { return exp(-( d.x*d.x + d.y*d.y) / (2.0 * s*s)); }\nfloat gaussian( vec3 d, float s) { return exp(-( d.x*d.x + d.y*d.y + d.z*d.z ) / (2.0 * s*s)); }\nfloat gaussian( vec4 d, float s) { return exp(-( d.x*d.x + d.y*d.y + d.z*d.z + d.w*d.w ) / (2.0 * s*s)); }\n#endif";
|
|
64
|
+
|
|
65
|
+
// src/shaders/lygia/space/ratio.glsl
|
|
66
|
+
var ratio_default = '/*\ncontributors: Patricio Gonzalez Vivo\ndescription: "Fix the aspect ratio of a space keeping things squared for you, \\nin\\\n \\ a similar way that aspect.glsl does, but while scaling the \\nspace to keep the\\\n \\ entire 0.0,0.0 ~ 1.0,1.0 range visible\\n"\nuse: <vec2> ratio(<vec2> st, <vec2> st_size)\nexamples:\n - https://raw.githubusercontent.com/patriciogonzalezvivo/lygia_examples/main/draw_shapes.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_RATIO\n#define FNC_RATIO\nvec2 ratio(in vec2 v, in vec2 s) {\n return mix( vec2((v.x*s.x/s.y)-(s.x*.5-s.y*.5)/s.y,v.y),\n vec2(v.x,v.y*(s.y/s.x)-(s.y*.5-s.x*.5)/s.x),\n step(s.x,s.y));\n}\n#endif\n';
|
|
67
|
+
|
|
68
|
+
// src/shaders/lygia/generative/random.glsl
|
|
69
|
+
var random_default = '/*\ncontributors: ["Patricio Gonzalez Vivo", "David Hoskins", "Inigo Quilez"]\ndescription: Pass a value and get some random normalize value between 0 and 1\nuse: float random[2|3](<float|vec2|vec3> value)\noptions:\n - RANDOM_HIGHER_RANGE: for working with a range over 0 and 1\n - RANDOM_SINLESS: Use sin-less random, which tolerates bigger values before producing pattern. From https://www.shadertoy.com/view/4djSRW\n - RANDOM_SCALE: by default this scale if for number with a big range. For producing good random between 0 and 1 use bigger range\nexamples:\n - /shaders/generative_random.frag\nlicense:\n - MIT License (MIT) Copyright 2014, David Hoskins\n*/\n\n#ifndef RANDOM_SCALE\n#ifdef RANDOM_HIGHER_RANGE\n#define RANDOM_SCALE vec4(.1031, .1030, .0973, .1099)\n#else\n#define RANDOM_SCALE vec4(443.897, 441.423, .0973, .1099)\n#endif\n#endif\n\n#ifndef FNC_RANDOM\n#define FNC_RANDOM\nfloat random(in float x) {\n#ifdef RANDOM_SINLESS\n x = fract(x * RANDOM_SCALE.x);\n x *= x + 33.33;\n x *= x + x;\n return fract(x);\n#else\n return fract(sin(x) * 43758.5453);\n#endif\n}\n\nfloat random(in vec2 st) {\n#ifdef RANDOM_SINLESS\n vec3 p3 = fract(vec3(st.xyx) * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n#else\n return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);\n#endif\n}\n\nfloat random(in vec3 pos) {\n#ifdef RANDOM_SINLESS\n pos = fract(pos * RANDOM_SCALE.xyz);\n pos += dot(pos, pos.zyx + 31.32);\n return fract((pos.x + pos.y) * pos.z);\n#else\n return fract(sin(dot(pos.xyz, vec3(70.9898, 78.233, 32.4355))) * 43758.5453123);\n#endif\n}\n\nfloat random(in vec4 pos) {\n#ifdef RANDOM_SINLESS\n pos = fract(pos * RANDOM_SCALE);\n pos += dot(pos, pos.wzxy + 33.33);\n return fract((pos.x + pos.y) * (pos.z + pos.w));\n#else\n float dot_product = dot(pos, vec4(12.9898,78.233,45.164,94.673));\n return fract(sin(dot_product) * 43758.5453);\n#endif\n}\n\nvec2 random2(float p) {\n vec3 p3 = fract(vec3(p) * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yzx + 19.19);\n return fract((p3.xx + p3.yz) * p3.zy);\n}\n\nvec2 random2(vec2 p) {\n vec3 p3 = fract(p.xyx * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yzx + 19.19);\n return fract((p3.xx + p3.yz) * p3.zy);\n}\n\nvec2 random2(vec3 p3) {\n p3 = fract(p3 * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yzx + 19.19);\n return fract((p3.xx + p3.yz) * p3.zy);\n}\n\nvec3 random3(float p) {\n vec3 p3 = fract(vec3(p) * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yzx + 19.19);\n return fract((p3.xxy + p3.yzz) * p3.zyx); \n}\n\nvec3 random3(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * RANDOM_SCALE.xyz);\n p3 += dot(p3, p3.yxz + 19.19);\n return fract((p3.xxy + p3.yzz) * p3.zyx);\n}\n\nvec3 random3(vec3 p) {\n p = fract(p * RANDOM_SCALE.xyz);\n p += dot(p, p.yxz + 19.19);\n return fract((p.xxy + p.yzz) * p.zyx);\n}\n\nvec4 random4(float p) {\n vec4 p4 = fract(p * RANDOM_SCALE);\n p4 += dot(p4, p4.wzxy + 19.19);\n return fract((p4.xxyz + p4.yzzw) * p4.zywx); \n}\n\nvec4 random4(vec2 p) {\n vec4 p4 = fract(p.xyxy * RANDOM_SCALE);\n p4 += dot(p4, p4.wzxy + 19.19);\n return fract((p4.xxyz + p4.yzzw) * p4.zywx);\n}\n\nvec4 random4(vec3 p) {\n vec4 p4 = fract(p.xyzx * RANDOM_SCALE);\n p4 += dot(p4, p4.wzxy + 19.19);\n return fract((p4.xxyz + p4.yzzw) * p4.zywx);\n}\n\nvec4 random4(vec4 p4) {\n p4 = fract(p4 * RANDOM_SCALE);\n p4 += dot(p4, p4.wzxy + 19.19);\n return fract((p4.xxyz + p4.yzzw) * p4.zywx);\n}\n#endif';
|
|
70
|
+
|
|
71
|
+
// src/shaders/lygia/generative/srandom.glsl
|
|
72
|
+
var srandom_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: Signed Random\nuse: srandomX(<vec2|vec3> x)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_SRANDOM\n#define FNC_SRANDOM\n\nfloat srandom(in float x) {\n return -1. + 2. * fract(sin(x) * 43758.5453);\n}\n\nfloat srandom(in vec2 st) {\n return -1. + 2. * fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nfloat srandom(in vec3 pos) {\n return -1. + 2. * fract(sin(dot(pos.xyz, vec3(70.9898, 78.233, 32.4355))) * 43758.5453123);\n}\n\nfloat srandom(in vec4 pos) {\n float dot_product = dot(pos, vec4(12.9898,78.233,45.164,94.673));\n return -1. + 2. * fract(sin(dot_product) * 43758.5453);\n}\n\nvec2 srandom2(in vec2 st) {\n const vec2 k = vec2(.3183099, .3678794);\n st = st * k + k.yx;\n return -1. + 2. * fract(16. * k * fract(st.x * st.y * (st.x + st.y)));\n}\n\nvec3 srandom3(in vec3 p) {\n p = vec3( dot(p, vec3(127.1, 311.7, 74.7)),\n dot(p, vec3(269.5, 183.3, 246.1)),\n dot(p, vec3(113.5, 271.9, 124.6)));\n return -1. + 2. * fract(sin(p) * 43758.5453123);\n}\n\nvec2 srandom2(in vec2 p, const in float tileLength) {\n p = mod(p, vec2(tileLength));\n return srandom2(p);\n}\n\nvec3 srandom3(in vec3 p, const in float tileLength) {\n p = mod(p, vec3(tileLength));\n return srandom3(p);\n}\n\n#endif";
|
|
73
|
+
|
|
74
|
+
// src/shaders/lygia/generative/gnoise.glsl
|
|
75
|
+
var gnoise_default = '#include "random.glsl"\n#include "srandom.glsl"\n#include "../math/cubic.glsl"\n#include "../math/quintic.glsl"\n\n/*\ncontributors: Patricio Gonzalez Vivo\ndescription: Gradient Noise\nuse: gnoise(<float> x)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_GNOISE\n#define FNC_GNOISE\n\nfloat gnoise(float x) {\n float i = floor(x); // integer\n float f = fract(x); // fraction\n return mix(random(i), random(i + 1.0), smoothstep(0.,1.,f)); \n}\n\nfloat gnoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = random(i);\n float b = random(i + vec2(1.0, 0.0));\n float c = random(i + vec2(0.0, 1.0));\n float d = random(i + vec2(1.0, 1.0));\n vec2 u = cubic(f);\n return mix( a, b, u.x) +\n (c - a)* u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\nfloat gnoise(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n vec3 u = quintic(f);\n return -1.0 + 2.0 * mix( mix( mix( random(i + vec3(0.0,0.0,0.0)), \n random(i + vec3(1.0,0.0,0.0)), u.x),\n mix( random(i + vec3(0.0,1.0,0.0)), \n random(i + vec3(1.0,1.0,0.0)), u.x), u.y),\n mix( mix( random(i + vec3(0.0,0.0,1.0)), \n random(i + vec3(1.0,0.0,1.0)), u.x),\n mix( random(i + vec3(0.0,1.0,1.0)), \n random(i + vec3(1.0,1.0,1.0)), u.x), u.y), u.z );\n}\n\nfloat gnoise(vec3 p, float tileLength) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n \n vec3 u = quintic(f);\n \n return mix( mix( mix( dot( srandom3(i + vec3(0.0,0.0,0.0), tileLength), f - vec3(0.0,0.0,0.0)), \n dot( srandom3(i + vec3(1.0,0.0,0.0), tileLength), f - vec3(1.0,0.0,0.0)), u.x),\n mix( dot( srandom3(i + vec3(0.0,1.0,0.0), tileLength), f - vec3(0.0,1.0,0.0)), \n dot( srandom3(i + vec3(1.0,1.0,0.0), tileLength), f - vec3(1.0,1.0,0.0)), u.x), u.y),\n mix( mix( dot( srandom3(i + vec3(0.0,0.0,1.0), tileLength), f - vec3(0.0,0.0,1.0)), \n dot( srandom3(i + vec3(1.0,0.0,1.0), tileLength), f - vec3(1.0,0.0,1.0)), u.x),\n mix( dot( srandom3(i + vec3(0.0,1.0,1.0), tileLength), f - vec3(0.0,1.0,1.0)), \n dot( srandom3(i + vec3(1.0,1.0,1.0), tileLength), f - vec3(1.0,1.0,1.0)), u.x), u.y), u.z );\n}\n\nvec3 gnoise3(vec3 x) {\n return vec3(gnoise(x+vec3(123.456, 0.567, 0.37)),\n gnoise(x+vec3(0.11, 47.43, 19.17)),\n gnoise(x) );\n}\n\n#endif';
|
|
76
|
+
|
|
77
|
+
// src/shaders/lygia/generative/snoise.glsl
|
|
78
|
+
var snoise_default = '#include "../math/mod289.glsl"\n#include "../math/permute.glsl"\n#include "../math/taylorInvSqrt.glsl"\n#include "../math/grad4.glsl"\n\n/*\ncontributors: [Stefan Gustavson, Ian McEwan]\ndescription: Simplex Noise https://github.com/stegu/webgl-noise\nuse: snoise(<vec2|vec3|vec4> pos)\nlicense: |\n Copyright 2021-2023 by Stefan Gustavson and Ian McEwan.\n Published under the terms of the MIT license:\n https://opensource.org/license/mit/\nexamples:\n - /shaders/generative_snoise.frag\n*/\n\n#ifndef FNC_SNOISE\n#define FNC_SNOISE\nfloat snoise(in vec2 v) {\n const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0\n 0.366025403784439, // 0.5*(sqrt(3.0)-1.0)\n -0.577350269189626, // -1.0 + 2.0 * C.x\n 0.024390243902439); // 1.0 / 41.0\n // First corner\n vec2 i = floor(v + dot(v, C.yy) );\n vec2 x0 = v - i + dot(i, C.xx);\n\n // Other corners\n vec2 i1;\n //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0\n //i1.y = 1.0 - i1.x;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n // x0 = x0 - 0.0 + 0.0 * C.xx ;\n // x1 = x0 - i1 + 1.0 * C.xx ;\n // x2 = x0 - 1.0 + 2.0 * C.xx ;\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n\n // Permutations\n i = mod289(i); // Avoid truncation effects in permutation\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n + i.x + vec3(0.0, i1.x, 1.0 ));\n\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n\n // Gradients: 41 points uniformly over a line, mapped onto a diamond.\n // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)\n\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n\n // Normalise gradients implicitly by scaling m\n // Approximation of: m *= inversesqrt( a0*a0 + h*h );\n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n\n // Compute final noise value at P\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\n\nfloat snoise(in vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n // First corner\n vec3 i = floor(v + dot(v, C.yyy) );\n vec3 x0 = v - i + dot(i, C.xxx) ;\n\n // Other corners\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min( g.xyz, l.zxy );\n vec3 i2 = max( g.xyz, l.zxy );\n\n // x0 = x0 - 0.0 + 0.0 * C.xxx;\n // x1 = x0 - i1 + 1.0 * C.xxx;\n // x2 = x0 - i2 + 2.0 * C.xxx;\n // x3 = x0 - 1.0 + 3.0 * C.xxx;\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y\n vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y\n\n // Permutations\n i = mod289(i);\n vec4 p = permute( permute( permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0 ))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));\n\n // Gradients: 7x7 points over a square, mapped onto an octahedron.\n // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n float n_ = 0.142857142857; // 1.0/7.0\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4( x.xy, y.xy );\n vec4 b1 = vec4( x.zw, y.zw );\n\n //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;\n //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;\n\n vec3 p0 = vec3(a0.xy,h.x);\n vec3 p1 = vec3(a0.zw,h.y);\n vec3 p2 = vec3(a1.xy,h.z);\n vec3 p3 = vec3(a1.zw,h.w);\n\n //Normalise gradients\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n // Mix final noise value\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),\n dot(p2,x2), dot(p3,x3) ) );\n}\n\nfloat snoise(in vec4 v) {\n const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4\n 0.276393202250021, // 2 * G4\n 0.414589803375032, // 3 * G4\n -0.447213595499958); // -1 + 4 * G4\n\n // First corner\n vec4 i = floor(v + dot(v, vec4(.309016994374947451)) ); // (sqrt(5) - 1)/4\n vec4 x0 = v - i + dot(i, C.xxxx);\n\n // Other corners\n\n // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)\n vec4 i0;\n vec3 isX = step( x0.yzw, x0.xxx );\n vec3 isYZ = step( x0.zww, x0.yyz );\n // i0.x = dot( isX, vec3( 1.0 ) );\n i0.x = isX.x + isX.y + isX.z;\n i0.yzw = 1.0 - isX;\n // i0.y += dot( isYZ.xy, vec2( 1.0 ) );\n i0.y += isYZ.x + isYZ.y;\n i0.zw += 1.0 - isYZ.xy;\n i0.z += isYZ.z;\n i0.w += 1.0 - isYZ.z;\n\n // i0 now contains the unique values 0,1,2,3 in each channel\n vec4 i3 = clamp( i0, 0.0, 1.0 );\n vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );\n vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );\n\n // x0 = x0 - 0.0 + 0.0 * C.xxxx\n // x1 = x0 - i1 + 1.0 * C.xxxx\n // x2 = x0 - i2 + 2.0 * C.xxxx\n // x3 = x0 - i3 + 3.0 * C.xxxx\n // x4 = x0 - 1.0 + 4.0 * C.xxxx\n vec4 x1 = x0 - i1 + C.xxxx;\n vec4 x2 = x0 - i2 + C.yyyy;\n vec4 x3 = x0 - i3 + C.zzzz;\n vec4 x4 = x0 + C.wwww;\n\n // Permutations\n i = mod289(i);\n float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);\n vec4 j1 = permute( permute( permute( permute (\n i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))\n + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))\n + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))\n + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));\n\n // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope\n // 7*7*6 = 294, which is close to the ring size 17*17 = 289.\n vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;\n\n vec4 p0 = grad4(j0, ip);\n vec4 p1 = grad4(j1.x, ip);\n vec4 p2 = grad4(j1.y, ip);\n vec4 p3 = grad4(j1.z, ip);\n vec4 p4 = grad4(j1.w, ip);\n\n // Normalise gradients\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n p4 *= taylorInvSqrt(dot(p4,p4));\n\n // Mix contributions from the five corners\n vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);\n vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);\n m0 = m0 * m0;\n m1 = m1 * m1;\n return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))\n + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;\n}\n\nvec2 snoise2( vec2 x ){\n float s = snoise(vec2( x ));\n float s1 = snoise(vec2( x.y - 19.1, x.x + 47.2 ));\n return vec2( s , s1 );\n}\n\nvec3 snoise3( vec3 x ){\n float s = snoise(vec3( x ));\n float s1 = snoise(vec3( x.y - 19.1 , x.z + 33.4 , x.x + 47.2 ));\n float s2 = snoise(vec3( x.z + 74.2 , x.x - 124.5 , x.y + 99.4 ));\n return vec3( s , s1 , s2 );\n}\n\nvec3 snoise3( vec4 x ){\n float s = snoise(vec4( x ));\n float s1 = snoise(vec4( x.y - 19.1 , x.z + 33.4 , x.x + 47.2, x.w ));\n float s2 = snoise(vec4( x.z + 74.2 , x.x - 124.5 , x.y + 99.4, x.w ));\n return vec3( s , s1 , s2 );\n}\n\n#endif\n';
|
|
79
|
+
|
|
80
|
+
// src/shaders/lygia/generative/fbm.glsl
|
|
81
|
+
var fbm_default = `#include "snoise.glsl"
|
|
82
|
+
#include "gnoise.glsl"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
contributors: Patricio Gonzalez Vivo
|
|
87
|
+
description: Fractal Brownian Motion
|
|
88
|
+
use: fbm(<vec2> pos)
|
|
89
|
+
options:
|
|
90
|
+
FBM_OCTAVES: numbers of octaves. Default is 4.
|
|
91
|
+
FBM_NOISE_FNC(UV): noise function to use Default 'snoise(UV)' (simplex noise)
|
|
92
|
+
FBM_VALUE_INITIAL: initial value. Default is 0.
|
|
93
|
+
FBM_SCALE_SCALAR: scalar. Default is 2.
|
|
94
|
+
FBM_AMPLITUDE_INITIAL: initial amplitude value. Default is 0.5
|
|
95
|
+
FBM_AMPLITUDE_SCALAR: amplitude scalar. Default is 0.5
|
|
96
|
+
examples:
|
|
97
|
+
- /shaders/generative_fbm.frag
|
|
98
|
+
license:
|
|
99
|
+
- Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0
|
|
100
|
+
- Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
#ifndef FBM_OCTAVES
|
|
104
|
+
#define FBM_OCTAVES 4
|
|
105
|
+
#endif
|
|
106
|
+
|
|
107
|
+
#ifndef FBM_NOISE_FNC
|
|
108
|
+
#define FBM_NOISE_FNC(UV) snoise(UV)
|
|
109
|
+
#endif
|
|
110
|
+
|
|
111
|
+
#ifndef FBM_NOISE2_FNC
|
|
112
|
+
#define FBM_NOISE2_FNC(UV) FBM_NOISE_FNC(UV)
|
|
113
|
+
#endif
|
|
114
|
+
|
|
115
|
+
#ifndef FBM_NOISE3_FNC
|
|
116
|
+
#define FBM_NOISE3_FNC(UV) FBM_NOISE_FNC(UV)
|
|
117
|
+
#endif
|
|
118
|
+
|
|
119
|
+
#ifndef FBM_NOISE_TILABLE_FNC
|
|
120
|
+
#define FBM_NOISE_TILABLE_FNC(UV, TILE) gnoise(UV, TILE)
|
|
121
|
+
#endif
|
|
122
|
+
|
|
123
|
+
#ifndef FBM_NOISE3_TILABLE_FNC
|
|
124
|
+
#define FBM_NOISE3_TILABLE_FNC(UV, TILE) FBM_NOISE_TILABLE_FNC(UV, TILE)
|
|
125
|
+
#endif
|
|
126
|
+
|
|
127
|
+
#ifndef FBM_NOISE_TYPE
|
|
128
|
+
#define FBM_NOISE_TYPE float
|
|
129
|
+
#endif
|
|
130
|
+
|
|
131
|
+
#ifndef FBM_VALUE_INITIAL
|
|
132
|
+
#define FBM_VALUE_INITIAL 0.0
|
|
133
|
+
#endif
|
|
134
|
+
|
|
135
|
+
#ifndef FBM_SCALE_SCALAR
|
|
136
|
+
#define FBM_SCALE_SCALAR 2.0
|
|
137
|
+
#endif
|
|
138
|
+
|
|
139
|
+
#ifndef FBM_AMPLITUDE_INITIAL
|
|
140
|
+
#define FBM_AMPLITUDE_INITIAL 0.5
|
|
141
|
+
#endif
|
|
142
|
+
|
|
143
|
+
#ifndef FBM_AMPLITUDE_SCALAR
|
|
144
|
+
#define FBM_AMPLITUDE_SCALAR 0.5
|
|
145
|
+
#endif
|
|
146
|
+
|
|
147
|
+
#ifndef FNC_FBM
|
|
148
|
+
#define FNC_FBM
|
|
149
|
+
FBM_NOISE_TYPE fbm(in vec2 st) {
|
|
150
|
+
// Initial values
|
|
151
|
+
FBM_NOISE_TYPE value = FBM_NOISE_TYPE(FBM_VALUE_INITIAL);
|
|
152
|
+
float amplitude = FBM_AMPLITUDE_INITIAL;
|
|
153
|
+
|
|
154
|
+
// Loop of octaves
|
|
155
|
+
for (int i = 0; i < FBM_OCTAVES; i++) {
|
|
156
|
+
value += amplitude * FBM_NOISE2_FNC(st);
|
|
157
|
+
st *= FBM_SCALE_SCALAR;
|
|
158
|
+
amplitude *= FBM_AMPLITUDE_SCALAR;
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
FBM_NOISE_TYPE fbm(in vec3 pos) {
|
|
164
|
+
// Initial values
|
|
165
|
+
FBM_NOISE_TYPE value = FBM_NOISE_TYPE(FBM_VALUE_INITIAL);
|
|
166
|
+
float amplitude = FBM_AMPLITUDE_INITIAL;
|
|
167
|
+
|
|
168
|
+
// Loop of octaves
|
|
169
|
+
for (int i = 0; i < FBM_OCTAVES; i++) {
|
|
170
|
+
value += amplitude * FBM_NOISE3_FNC(pos);
|
|
171
|
+
pos *= FBM_SCALE_SCALAR;
|
|
172
|
+
amplitude *= FBM_AMPLITUDE_SCALAR;
|
|
173
|
+
}
|
|
174
|
+
return value;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
FBM_NOISE_TYPE fbm(vec3 p, float tileLength) {
|
|
178
|
+
const float persistence = 0.5;
|
|
179
|
+
const float lacunarity = 2.0;
|
|
180
|
+
|
|
181
|
+
float amplitude = 0.5;
|
|
182
|
+
FBM_NOISE_TYPE total = FBM_NOISE_TYPE(0.0);
|
|
183
|
+
float normalization = 0.0;
|
|
184
|
+
|
|
185
|
+
for (int i = 0; i < FBM_OCTAVES; ++i) {
|
|
186
|
+
float noiseValue = FBM_NOISE3_TILABLE_FNC(p, tileLength * lacunarity * 0.5) * 0.5 + 0.5;
|
|
187
|
+
total += noiseValue * amplitude;
|
|
188
|
+
normalization += amplitude;
|
|
189
|
+
amplitude *= persistence;
|
|
190
|
+
p = p * lacunarity;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return total / normalization;
|
|
194
|
+
}
|
|
195
|
+
#endif
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
// src/shaders/lygia/morphological/dilation.glsl
|
|
199
|
+
var dilation_default = '#include "../sampler.glsl"\n#include "../math/saturate.glsl"\n#include "../math/sum.glsl"\n\n/*\ncontributors: Patricio Gonzalez Vivo\ndescription: "morphological dilation operation. Based on: \\n https://lettier.github.io/3d-game-shaders-for-beginners/dilation.html\\n\\\n \\ https://www.shadertoy.com/view/WsyXWc\\n"\nuse: dilation(<SAMPLER_TYPE> texture, <float2> st, <float2> pixels_scale, <int> passes)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - DILATION_TYPE\n - DILATION_SAMPLE_FNC(TEX, UV)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef DILATION_TYPE\n#define DILATION_TYPE float\n#endif\n\n#ifndef DILATION_MAX_RADIUS\n#define DILATION_MAX_RADIUS 16\n#endif\n\n#ifndef DILATION_SAMPLE_FNC\n#define DILATION_SAMPLE_FNC(TEX, UV) SAMPLER_FNC(TEX, UV).r\n#endif\n\n#ifndef FNC_DILATE\n#define FNC_DILATE\n\nDILATION_TYPE dilation(SAMPLER_TYPE tex, vec2 st, vec2 pixel, int radius) {\n float invKR = 1.0 / float(radius);\n DILATION_TYPE acc = DILATION_TYPE(0.0);\n float w = 0.0;\n\n #ifdef PLATFORM_WEBGL\n for(int i = -DILATION_MAX_RADIUS; i <= DILATION_MAX_RADIUS; ++i) {\n if (i >= radius) break;\n for(int j = -DILATION_MAX_RADIUS; j <= DILATION_MAX_RADIUS; ++j) {\n if (j >= radius) break;\n #else\n for(int i = -radius; i <= radius; ++i) {\n for(int j = -radius; j <= radius; ++j) {\n #endif\n vec2 rxy = vec2(ivec2(i, j));\n vec2 kst = rxy * invKR * 2.0;\n vec2 texOffset = st + rxy * pixel;\n float kernel = saturate(1.0 - dot(kst, kst));\n DILATION_TYPE t = DILATION_SAMPLE_FNC(tex, texOffset);\n DILATION_TYPE v = t + kernel;\n if (sum(v) > sum(acc)) {\n acc = v;\n w = kernel;\n }\n }\n }\n \n return acc - w;\n}\n\n#endif';
|
|
200
|
+
|
|
201
|
+
// src/shaders/lygia/sampler.glsl
|
|
202
|
+
var sampler_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: It defines the default sampler type and function for the shader based on the version of GLSL.\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n#ifndef SAMPLER_FNC\n#if __VERSION__ >= 300\n#define SAMPLER_FNC(TEX, UV) texture(TEX, UV)\n#else\n#define SAMPLER_FNC(TEX, UV) texture2D(TEX, UV)\n#endif\n#endif\n\n#ifndef SAMPLER_TYPE\n#define SAMPLER_TYPE sampler2D\n#endif";
|
|
203
|
+
|
|
204
|
+
// src/shaders/lygia/sample/clamp2edge.glsl
|
|
205
|
+
var clamp2edge_default = '#include "../sampler.glsl"\n\n/*\ncontributors: Patricio Gonzalez Vivo\ndescription: fakes a clamp to edge texture\nuse: <vec4> sampleClamp2edge(<SAMPLER_TYPE> tex, <vec2> st [, <vec2> texResolution]);\noptions:\n - SAMPLER_FNC(TEX, UV)\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef FNC_SAMPLECLAMP2EDGE\n#define FNC_SAMPLECLAMP2EDGE\nvec4 sampleClamp2edge(SAMPLER_TYPE tex, vec2 st, vec2 texResolution) {\n vec2 pixel = 1.0/texResolution;\n return SAMPLER_FNC( tex, clamp(st, pixel, 1.0-pixel) );\n}\n\nvec4 sampleClamp2edge(SAMPLER_TYPE tex, vec2 st) { \n return SAMPLER_FNC( tex, clamp(st, vec2(0.01), vec2(0.99) ) ); \n}\n\nvec4 sampleClamp2edge(SAMPLER_TYPE tex, vec2 st, float edge) { \n return SAMPLER_FNC( tex, clamp(st, vec2(edge), vec2(1.0 - edge) ) ); \n}\n#endif';
|
|
206
|
+
|
|
207
|
+
// src/shaders/lygia/draw/digits.glsl
|
|
208
|
+
var digits_default = "/*\ncontributors: Patricio Gonzalez Vivo\ndescription: |\n Draws all the digits of a floating point number, useful for debugging.\n Requires high precision to work properly.\nuse: digits(<vec2> st, <float> value [, <float> nDecDigit])\noptions:\n DIGITS_DECIMALS: number of decimals after the point, defaults to 2\n DIGITS_SIZE: size of the font, defaults to vec2(.025)\nexamples:\n - /shaders/draw_digits.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef DIGITS_SIZE\n#define DIGITS_SIZE vec2(.02)\n#endif\n\n#ifndef DIGITS_DECIMALS\n#define DIGITS_DECIMALS 2.0\n#endif\n\n#ifndef DIGITS_VALUE_OFFSET\n#define DIGITS_VALUE_OFFSET vec2(-6.0, 3.0) \n#endif\n\n#ifndef FNC_DIGITS\n#define FNC_DIGITS\nfloat digits(in vec2 st, in float value, in float nDecDigit) {\n st /= DIGITS_SIZE;\n\n float absValue = abs(value);\n float biggestDigitIndex = max(floor(log2(absValue) / log2(10.)), 0.);\n float counter = floor(absValue);\n float nIntDigits = 1.;\n for (int i = 0; i < 9; i++) {\n counter = floor(counter*.1);\n nIntDigits++;\n if (counter == 0.)\n break;\n }\n\n float digit = 12.;\n float digitIndex = (nIntDigits-1.) - floor(st.x);\n if (digitIndex > (-nDecDigit - 1.5)) {\n if (digitIndex > biggestDigitIndex) {\n if (value < 0.) {\n if (digitIndex < (biggestDigitIndex+1.5)) {\n digit = 11.;\n }\n }\n } \n else {\n if (digitIndex == -1.) {\n if (nDecDigit > 0.) {\n digit = 10.;\n }\n } \n else {\n if (digitIndex < 0.) {\n digitIndex += 1.;\n }\n float digitValue = (absValue / (pow(10., digitIndex)));\n digit = mod(floor(0.0001+digitValue), 10.);\n }\n }\n }\n vec2 pos = vec2(fract(st.x), st.y);\n\n if (pos.x < 0.) return 0.;\n if (pos.y < 0.) return 0.;\n if (pos.x >= 1.) return 0.;\n if (pos.y >= 1.) return 0.;\n\n // make a 4x5 array of bits\n float bin = 0.;\n if (digit < 0.5) // 0\n bin = 7. + 5. * 16. + 5. * 256. + 5. * 4096. + 7. * 65536.; \n else if (digit < 1.5) // 1\n bin = 2. + 2. * 16. + 2. * 256. + 2. * 4096. + 2. * 65536.;\n else if (digit < 2.5) // 2\n bin = 7. + 1. * 16. + 7. * 256. + 4. * 4096. + 7. * 65536.;\n else if (digit < 3.5) // 3\n bin = 7. + 4. * 16. + 7. * 256. + 4. * 4096. + 7. * 65536.;\n else if (digit < 4.5) // 4\n bin = 4. + 7. * 16. + 5. * 256. + 1. * 4096. + 1. * 65536.;\n else if (digit < 5.5) // 5\n bin = 7. + 4. * 16. + 7. * 256. + 1. * 4096. + 7. * 65536.;\n else if (digit < 6.5) // 6\n bin = 7. + 5. * 16. + 7. * 256. + 1. * 4096. + 7. * 65536.;\n else if (digit < 7.5) // 7\n bin = 4. + 4. * 16. + 4. * 256. + 4. * 4096. + 7. * 65536.;\n else if (digit < 8.5) // 8\n bin = 7. + 5. * 16. + 7. * 256. + 5. * 4096. + 7. * 65536.;\n else if (digit < 9.5) // 9\n bin = 7. + 4. * 16. + 7. * 256. + 5. * 4096. + 7. * 65536.;\n else if (digit < 10.5) // '.'\n bin = 2. + 0. * 16. + 0. * 256. + 0. * 4096. + 0. * 65536.;\n else if (digit < 11.5) // '-'\n bin = 0. + 0. * 16. + 7. * 256. + 0. * 4096. + 0. * 65536.;\n\n vec2 pixel = floor(pos * vec2(4., 5.));\n return mod(floor(bin / pow(2., (pixel.x + (pixel.y * 4.)))), 2.);\n}\n\nfloat digits(in vec2 st, in float value, in float nDecDigit, in float nIntDigits) {\n vec2 st2 = st;\n float result = 0.0;\n float dig = nDecDigit;\n\n #ifndef DIGITS_LEADING_INT\n #if defined(PLATFORM_WEBGL)\n #define DIGITS_LEADING_INT 1.0\n #else\n #define DIGITS_LEADING_INT nIntDigits\n #endif\n #endif\n\n for (float i = DIGITS_LEADING_INT - 1.0; i > 0.0 ; i--) {\n if (i * 10.0 > value) {\n result += digits(st2, 0.0, 0.0);\n st2.x -= DIGITS_SIZE.x;\n }\n }\n result += digits(st2, value, nDecDigit);\n return result; \n}\n\nfloat digits(in vec2 st, in int value) {\n return digits(st, float(value), 0.0);\n}\n\nfloat digits(in vec2 st, in float value) {\n return digits(st, value, (DIGITS_DECIMALS));\n}\n\nfloat digits(in vec2 st, in vec2 v) {\n float rta = 0.0;\n for (int i = 0; i < 2; i++) {\n vec2 pos = st + vec2(float(i), 0.0) * DIGITS_SIZE * DIGITS_VALUE_OFFSET;\n float value = i == 0 ? v.x : v.y;\n rta += digits( pos, value );\n }\n return rta;\n}\n\nfloat digits(in vec2 st, in vec3 v) {\n float rta = 0.0;\n for (int i = 0; i < 3; i++) {\n vec2 pos = st + vec2(float(i), 0.0) * DIGITS_SIZE * DIGITS_VALUE_OFFSET;\n float value = i == 0 ? v.x : i == 1 ? v.y : v.z;\n rta += digits( pos, value );\n }\n return rta;\n}\n\nfloat digits(in vec2 st, in vec4 v) {\n float rta = 0.0;\n for (int i = 0; i < 4; i++) {\n vec2 pos = st + vec2(float(i), 0.0) * DIGITS_SIZE * DIGITS_VALUE_OFFSET;\n float value = i == 0 ? v.x : i == 1 ? v.y : i == 2 ? v.z : v.w;\n rta += digits( pos, value );\n }\n return rta;\n}\n\nfloat digits(in vec2 st, in mat2 _matrix) {\n float rta = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n vec2 pos = st + vec2(float(i), float(j)) * DIGITS_SIZE * DIGITS_VALUE_OFFSET - DIGITS_SIZE * vec2(0.0, 3.0);\n float value = _matrix[j][i];\n rta += digits( pos, value );\n }\n }\n return rta;\n}\n\nfloat digits(in vec2 st, in mat3 _matrix) {\n float rta = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n vec2 pos = st + vec2(float(i), float(j)) * DIGITS_SIZE * DIGITS_VALUE_OFFSET - DIGITS_SIZE * vec2(0.0, 6.0);\n float value = _matrix[j][i];\n rta += digits( pos, value );\n }\n }\n return rta;\n}\n\nfloat digits(in vec2 st, in mat4 _matrix) {\n float rta = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n vec2 pos = st + vec2(float(i), float(j)) * DIGITS_SIZE * DIGITS_VALUE_OFFSET - DIGITS_SIZE * vec2(0.0, 9.0);\n float value = _matrix[j][i];\n rta += digits( pos, value );\n }\n }\n return rta;\n}\n#endif\n";
|
|
209
|
+
|
|
210
|
+
// src/shaders/lygia/filter/gaussianBlur.glsl
|
|
211
|
+
var gaussianBlur_default = '#include "../sampler.glsl"\n\n/*\ncontributors:\n - Matt DesLauriers\n - Patricio Gonzalez Vivo\ndescription: Adapted versions from 5, 9 and 13 gaussian fast blur from https://github.com/Jam3/glsl-fast-gaussian-blur\nuse: gaussianBlur(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction [, const int kernelSize])\noptions:\n - GAUSSIANBLUR_AMOUNT: gaussianBlur5 gaussianBlur9 gaussianBlur13\n - GAUSSIANBLUR_2D: default to 1D\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\nexamples:\n - /shaders/filter_gaussianBlur2D.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef GAUSSIANBLUR_AMOUNT\n#define GAUSSIANBLUR_AMOUNT gaussianBlur13\n#endif\n\n#ifndef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR_TYPE vec4\n#endif\n\n#ifndef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR_SAMPLER_FNC(TEX, UV) SAMPLER_FNC(TEX, UV)\n#endif\n\n#include "gaussianBlur/2D.glsl"\n#include "gaussianBlur/1D.glsl"\n#include "gaussianBlur/1D_fast13.glsl"\n#include "gaussianBlur/1D_fast9.glsl"\n#include "gaussianBlur/1D_fast5.glsl"\n\n#ifndef FNC_GAUSSIANBLUR\n#define FNC_GAUSSIANBLUR\nGAUSSIANBLUR_TYPE gaussianBlur13(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n#ifdef GAUSSIANBLUR_2D\n return gaussianBlur2D(tex, st, offset, 7);\n#else\n return gaussianBlur1D_fast13(tex, st, offset);\n#endif\n}\n\nGAUSSIANBLUR_TYPE gaussianBlur9(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n#ifdef GAUSSIANBLUR_2D\n return gaussianBlur2D(tex, st, offset, 5);\n#else\n return gaussianBlur1D_fast9(tex, st, offset);\n#endif\n}\n\nGAUSSIANBLUR_TYPE gaussianBlur5(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n#ifdef GAUSSIANBLUR_2D\n return gaussianBlur2D(tex, st, offset, 3);\n#else\n return gaussianBlur1D_fast5(tex, st, offset);\n#endif\n}\n\nGAUSSIANBLUR_TYPE gaussianBlur(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset, const int kernelSize) {\n#ifdef GAUSSIANBLUR_2D\n return gaussianBlur2D(tex, st, offset, kernelSize);\n#else\n return gaussianBlur1D(tex, st, offset, kernelSize);\n#endif\n}\n\nGAUSSIANBLUR_TYPE gaussianBlur(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n return GAUSSIANBLUR_AMOUNT(tex, st, offset);\n}\n#endif\n';
|
|
212
|
+
|
|
213
|
+
// src/shaders/lygia/filter/gaussianBlur/2D.glsl
|
|
214
|
+
var D_default = '#include "../../math/gaussian.glsl"\n#include "../../sample/clamp2edge.glsl"\n\n/*\ncontributors: Patricio Gonzalez Vivo\ndescription: Two dimension Gaussian Blur to be applied in only one passes\nuse: gaussianBlur2D(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction, const int kernelSize)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - GAUSSIANBLUR2D_TYPE: Default `vec4`\n - GAUSSIANBLUR2D_SAMPLER_FNC(TEX, UV): Default `texture2D(tex, TEX, UV)`\n - GAUSSIANBLUR2D_KERNELSIZE: Use only for WebGL 1.0 and OpenGL ES 2.0 . For example RaspberryPis is not happy with dynamic loops. Default is \'kernelSize\'\nexamples:\n - /shaders/filter_gaussianBlur2D.frag\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef GAUSSIANBLUR2D_TYPE\n#ifdef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR2D_TYPE GAUSSIANBLUR_TYPE\n#else\n#define GAUSSIANBLUR2D_TYPE vec4\n#endif\n#endif\n\n#ifndef GAUSSIANBLUR2D_SAMPLER_FNC\n#ifdef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR2D_SAMPLER_FNC(TEX, UV) GAUSSIANBLUR_SAMPLER_FNC(TEX, UV)\n#else\n#define GAUSSIANBLUR2D_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)\n#endif\n#endif\n\n#ifndef FNC_GAUSSIANBLUR2D\n#define FNC_GAUSSIANBLUR2D\nGAUSSIANBLUR2D_TYPE gaussianBlur2D(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset, const int kernelSize) {\n GAUSSIANBLUR2D_TYPE accumColor = GAUSSIANBLUR2D_TYPE(0.);\n \n #ifndef GAUSSIANBLUR2D_KERNELSIZE\n \n #if defined(PLATFORM_WEBGL)\n #define GAUSSIANBLUR2D_KERNELSIZE 20\n float kernelSizef = float(kernelSize);\n #else\n #define GAUSSIANBLUR2D_KERNELSIZE kernelSize\n float kernelSizef = float(GAUSSIANBLUR2D_KERNELSIZE);\n #endif\n\n #else\n float kernelSizef = float(GAUSSIANBLUR2D_KERNELSIZE);\n #endif\n\n float accumWeight = 0.;\n const float k = 0.15915494; // 1 / (2*PI)\n vec2 xy = vec2(0.0);\n for (int j = 0; j < GAUSSIANBLUR2D_KERNELSIZE; j++) {\n #if defined(PLATFORM_WEBGL)\n if (j >= kernelSize)\n break;\n #endif\n xy.y = -.5 * (kernelSizef - 1.) + float(j);\n for (int i = 0; i < GAUSSIANBLUR2D_KERNELSIZE; i++) {\n #if defined(PLATFORM_WEBGL)\n if (i >= kernelSize)\n break;\n #endif\n xy.x = -0.5 * (kernelSizef - 1.) + float(i);\n float weight = (k / kernelSizef) * gaussian(xy, kernelSizef);\n accumColor += weight * GAUSSIANBLUR2D_SAMPLER_FNC(tex, st + xy * offset);\n accumWeight += weight;\n }\n }\n return accumColor / accumWeight;\n}\n#endif\n';
|
|
215
|
+
|
|
216
|
+
// src/shaders/lygia/filter/gaussianBlur/1D.glsl
|
|
217
|
+
var D_default2 = '#include "../../math/gaussian.glsl"\n#include "../../sample/clamp2edge.glsl"\n\n/*\ncontributors: Patricio Gonzalez Vivo\ndescription: One dimension Gaussian Blur to be applied in two passes\nuse: gaussianBlur1D(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction , const int kernelSize)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - GAUSSIANBLUR1D_TYPE: null\n - GAUSSIANBLUR1D_SAMPLER_FNC(TEX, UV): null\nlicense:\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Prosperity License - https://prosperitylicense.com/versions/3.0.0\n - Copyright (c) 2021 Patricio Gonzalez Vivo under Patron License - https://lygia.xyz/license\n*/\n\n#ifndef GAUSSIANBLUR1D_TYPE\n#ifdef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR1D_TYPE GAUSSIANBLUR_TYPE\n#else\n#define GAUSSIANBLUR1D_TYPE vec4\n#endif\n#endif\n\n#ifndef GAUSSIANBLUR1D_SAMPLER_FNC\n#ifdef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR1D_SAMPLER_FNC(TEX, UV) GAUSSIANBLUR_SAMPLER_FNC(TEX, UV)\n#else\n#define GAUSSIANBLUR1D_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)\n#endif\n#endif\n\n#ifndef FNC_GAUSSIANBLUR1D\n#define FNC_GAUSSIANBLUR1D\n\n#ifdef PLATFORM_WEBGL\n\nGAUSSIANBLUR1D_TYPE gaussianBlur1D(in SAMPLER_TYPE tex,in vec2 st,in vec2 offset,const int kernelSize){\n GAUSSIANBLUR1D_TYPE accumColor = GAUSSIANBLUR1D_TYPE(0.0);\n\n float kernelSizef = float(kernelSize);\n float accumWeight = 0.0;\n const float k = 0.39894228;// 1 / sqrt(2*PI)\n for (int i = 0; i < 16; i++) {\n if( i >= kernelSize)\n break;\n float x = -0.5 * (float(kernelSize) - 1.0)+float(i);\n float weight = (k/float(kernelSize)) * gaussian(x, kernelSizef);\n GAUSSIANBLUR1D_TYPE tex = GAUSSIANBLUR1D_SAMPLER_FNC(tex, st + x * offset);\n accumColor += weight * tex;\n accumWeight += weight;\n }\n return accumColor/accumWeight;\n}\n\n#else\n\nGAUSSIANBLUR1D_TYPE gaussianBlur1D(in SAMPLER_TYPE tex,in vec2 st,in vec2 offset,const int kernelSize){\n GAUSSIANBLUR1D_TYPE accumColor=GAUSSIANBLUR1D_TYPE(0.);\n\n float kernelSizef = float(kernelSize);\n \n float accumWeight = 0.0;\n const float k = 0.39894228;// 1 / sqrt(2*PI)\n for (int i = 0; i < kernelSize; i++) {\n float x = -0.5 * ( kernelSizef -1.0) + float(i);\n float weight = (k / kernelSizef) * gaussian(x, kernelSizef);\n GAUSSIANBLUR1D_TYPE tex = GAUSSIANBLUR1D_SAMPLER_FNC(tex, st + x * offset);\n accumColor += weight * tex;\n accumWeight += weight;\n }\n return accumColor/accumWeight;\n}\n#endif\n\n#endif\n';
|
|
218
|
+
|
|
219
|
+
// src/shaders/lygia/filter/gaussianBlur/1D_fast13.glsl
|
|
220
|
+
var D_fast13_default = '#include "../../sample/clamp2edge.glsl"\n\n/*\nfunction: gaussianBlur1D_fast13\ncontributors: Matt DesLauriers\ndescription: Adapted versions of gaussian fast blur 13 from https://github.com/Jam3/glsl-fast-gaussian-blur\nuse: gaussianBlur1D_fast13(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - GAUSSIANBLUR1D_FAST13_TYPE\n - GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(TEX, UV)\n*/\n\n#ifndef GAUSSIANBLUR1D_FAST13_TYPE\n#ifdef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR1D_FAST13_TYPE GAUSSIANBLUR_TYPE\n#else\n#define GAUSSIANBLUR1D_FAST13_TYPE vec4\n#endif\n#endif\n\n#ifndef GAUSSIANBLUR1D_FAST13_SAMPLER_FNC\n#ifdef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(TEX, UV) GAUSSIANBLUR_SAMPLER_FNC(TEX, UV)\n#else\n#define GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)\n#endif\n#endif\n\n#ifndef FNC_GAUSSIANBLUR1D_FAST13\n#define FNC_GAUSSIANBLUR1D_FAST13\nGAUSSIANBLUR1D_FAST13_TYPE gaussianBlur1D_fast13(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n GAUSSIANBLUR1D_FAST13_TYPE color = GAUSSIANBLUR1D_FAST13_TYPE(0.);\n vec2 off1 = vec2(1.411764705882353) * offset;\n vec2 off2 = vec2(3.2941176470588234) * offset;\n vec2 off3 = vec2(5.176470588235294) * offset;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st) * .1964825501511404;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st + (off1)) * .2969069646728344;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st - (off1)) * .2969069646728344;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st + (off2)) * .09447039785044732;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st - (off2)) * .09447039785044732;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st + (off3)) * .010381362401148057;\n color += GAUSSIANBLUR1D_FAST13_SAMPLER_FNC(tex, st - (off3)) * .010381362401148057;\n return color;\n}\n#endif\n';
|
|
221
|
+
|
|
222
|
+
// src/shaders/lygia/filter/gaussianBlur/1D_fast9.glsl
|
|
223
|
+
var D_fast9_default = '#include "../../sample/clamp2edge.glsl"\n\n/*\ncontributors: Matt DesLauriers\ndescription: Adapted versions of gaussian fast blur 13 from https://github.com/Jam3/glsl-fast-gaussian-blur\nuse: gaussianBlur1D_fast9(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - GAUSSIANBLUR1D_FAST9_TYPE\n - GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(TEX, UV)\n*/\n\n#ifndef GAUSSIANBLUR1D_FAST9_TYPE\n#ifdef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR1D_FAST9_TYPE GAUSSIANBLUR_TYPE\n#else\n#define GAUSSIANBLUR1D_FAST9_TYPE vec4\n#endif\n#endif\n\n#ifndef GAUSSIANBLUR1D_FAST9_SAMPLER_FNC\n#ifdef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(TEX, UV) GAUSSIANBLUR_SAMPLER_FNC(TEX, UV)\n#else\n#define GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)\n#endif\n#endif\n\n#ifndef FNC_GAUSSIANBLUR1D_FAST9\n#define FNC_GAUSSIANBLUR1D_FAST9\nGAUSSIANBLUR1D_FAST9_TYPE gaussianBlur1D_fast9(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n GAUSSIANBLUR1D_FAST9_TYPE color = GAUSSIANBLUR1D_FAST9_TYPE(0.);\n vec2 off1 = vec2(1.3846153846) * offset;\n vec2 off2 = vec2(3.2307692308) * offset;\n color += GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(tex, st) * .2270270270;\n color += GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(tex, st + (off1)) * .3162162162;\n color += GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(tex, st - (off1)) * .3162162162;\n color += GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(tex, st + (off2)) * .0702702703;\n color += GAUSSIANBLUR1D_FAST9_SAMPLER_FNC(tex, st - (off2)) * .0702702703;\n return color;\n}\n#endif\n';
|
|
224
|
+
|
|
225
|
+
// src/shaders/lygia/filter/gaussianBlur/1D_fast5.glsl
|
|
226
|
+
var D_fast5_default = '#include "../../sample/clamp2edge.glsl"\n\n/*\ncontributors: Matt DesLauriers\ndescription: Adapted versions of gaussian fast blur 13 from https://github.com/Jam3/glsl-fast-gaussian-blur\nuse: gaussianBlur1D_fast5(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel_direction)\noptions:\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n - GAUSSIANBLUR1D_FAST5_TYPE\n - GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(TEX, UV)\n*/\n\n#ifndef GAUSSIANBLUR1D_FAST5_TYPE\n#ifdef GAUSSIANBLUR_TYPE\n#define GAUSSIANBLUR1D_FAST5_TYPE GAUSSIANBLUR_TYPE\n#else\n#define GAUSSIANBLUR1D_FAST5_TYPE vec4\n#endif\n#endif\n\n#ifndef GAUSSIANBLUR1D_FAST5_SAMPLER_FNC\n#ifdef GAUSSIANBLUR_SAMPLER_FNC\n#define GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(TEX, UV) GAUSSIANBLUR_SAMPLER_FNC(TEX, UV)\n#else\n#define GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)\n#endif\n#endif\n\n#ifndef FNC_GAUSSIANBLUR1D_FAST5\n#define FNC_GAUSSIANBLUR1D_FAST5\nGAUSSIANBLUR1D_FAST5_TYPE gaussianBlur1D_fast5(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset) {\n GAUSSIANBLUR1D_FAST5_TYPE color = GAUSSIANBLUR1D_FAST5_TYPE(0.);\n vec2 off1 = vec2(1.3333333333333333) * offset;\n color += GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(tex, st) * .29411764705882354;\n color += GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(tex, st + (off1)) * .35294117647058826;\n color += GAUSSIANBLUR1D_FAST5_SAMPLER_FNC(tex, st - (off1)) * .35294117647058826;\n return color;\n}\n#endif\n';
|
|
227
|
+
|
|
228
|
+
// src/shaders/lygia/filter/kuwahara.glsl
|
|
229
|
+
var kuwahara_default = '#include "../sampler.glsl"\n\n/*\ncontributors: [Brad Larson, Ben Cochran, Hugues Lismonde, Keitaroh Kobayashi, Alaric Cole, Matthew Clark, Jacob Gundersen, Chris Williams.]\ndescription: Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication "Anisotropic Kuwahara Filtering on the GPU" within the GPU Pro collection. This produces an oil-painting-like image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2. This might be best used for still images.\nuse: kuwahara(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel, <float> radius)\noptions:\n - KUWAHARA_TYPE: defaults to vec3\n - KUWAHARA_SAMPLER_FNC(TEX, UV): defaults to texture2D(tex, TEX, UV).rgb\n - KUWAHARA_RADIUS radius\n - SAMPLER_FNC(TEX, UV): optional depending the target version of GLSL (texture2D(...) or texture(...))\n*/\n\n#ifndef KUWAHARA_TYPE\n#define KUWAHARA_TYPE vec4\n#endif\n\n#ifndef KUWAHARA_SAMPLER_FNC\n#define KUWAHARA_SAMPLER_FNC(TEX, UV) SAMPLER_FNC(TEX, UV)\n#endif\n\n#ifndef FNC_KUWAHARA\n#define FNC_KUWAHARA\n\n#ifdef TARGET_MOBILE\nKUWAHARA_TYPE kuwahara(in SAMPLER_TYPE tex, in vec2 st, in vec2 pixel, in float radius) {\n\n #ifndef KUWAHARA_RADIUS\n #define KUWAHARA_RADIUS radius\n #endif\n\n float n = (KUWAHARA_RADIUS + 1.0) * (KUWAHARA_RADIUS + 1.0);\n KUWAHARA_TYPE m0 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m1 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m2 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m3 = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE s0 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s1 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s2 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s3 = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE rta = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE c = KUWAHARA_TYPE(0.0);\n\n for (float j = -KUWAHARA_RADIUS; j <= 0.0; ++j) {\n for (float i = -KUWAHARA_RADIUS; i <= 0.0; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m0 += c;\n s0 += c * c;\n }\n }\n\n for (float j = -KUWAHARA_RADIUS; j <= 0.0; ++j) {\n for (float i = 0.0; i <= KUWAHARA_RADIUS; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m1 += c;\n s1 += c * c;\n }\n }\n\n for (float j = 0.0; j <= KUWAHARA_RADIUS; ++j) {\n for (float i = 0.0; i <= KUWAHARA_RADIUS; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m2 += c;\n s2 += c * c;\n }\n }\n\n for (float j = 0.0; j <= KUWAHARA_RADIUS; ++j) {\n for (float i = -KUWAHARA_RADIUS; i <= 0.0; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m3 += c;\n s3 += c * c;\n }\n }\n\n float min_sigma2 = 1e+2;\n m0 /= n;\n s0 = abs(s0 / n - m0 * m0);\n\n float sigma2 = s0.r + s0.g + s0.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m0;\n }\n\n m1 /= n;\n s1 = abs(s1 / n - m1 * m1);\n\n sigma2 = s1.r + s1.g + s1.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m1;\n }\n\n m2 /= n;\n s2 = abs(s2 / n - m2 * m2);\n\n sigma2 = s2.r + s2.g + s2.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m2;\n }\n\n m3 /= n;\n s3 = abs(s3 / n - m3 * m3);\n\n sigma2 = s3.r + s3.g + s3.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m3;\n }\n\n return rta;\n}\n\n#else\n\nKUWAHARA_TYPE kuwahara(in SAMPLER_TYPE tex, in vec2 st, in vec2 pixel, in float radius) {\n\n #ifndef KUWAHARA_RADIUS\n\n #if defined(PLATFORM_WEBGL)\n #define KUWAHARA_RADIUS 20.0\n float n = (radius + 1.0) * (radius + 1.0);\n #else\n #define KUWAHARA_RADIUS radius\n float n = (KUWAHARA_RADIUS + 1.0) * (KUWAHARA_RADIUS + 1.0);\n #endif\n\n #else\n float n = (KUWAHARA_RADIUS + 1.0) * (KUWAHARA_RADIUS + 1.0);\n #endif\n\n KUWAHARA_TYPE m0 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m1 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m2 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE m3 = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE s0 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s1 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s2 = KUWAHARA_TYPE(0.0); KUWAHARA_TYPE s3 = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE rta = KUWAHARA_TYPE(0.0);\n KUWAHARA_TYPE c = KUWAHARA_TYPE(0.0);\n \n for (float j = -KUWAHARA_RADIUS; j <= 0.0; ++j) { \n for (float i = -KUWAHARA_RADIUS; i <= 0.0; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m0 += c;\n s0 += c * c;\n }\n }\n \n for (float j = -KUWAHARA_RADIUS; j <= 0.0; ++j) {\n for (float i = 0.0; i <= KUWAHARA_RADIUS; ++i) {\n #if defined(PLATFORM_WEBGL)\n if (i > radius)\n break;\n #endif\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m1 += c;\n s1 += c * c;\n }\n }\n \n for (float j = 0.0; j <= KUWAHARA_RADIUS; ++j) {\n #if defined(PLATFORM_WEBGL)\n if (j > radius)\n break;\n #endif\n for (float i = 0.0; i <= KUWAHARA_RADIUS; ++i) {\n #if defined(PLATFORM_WEBGL)\n if (i > radius)\n break;\n #endif\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m2 += c;\n s2 += c * c;\n }\n }\n \n for (float j = 0.0; j <= KUWAHARA_RADIUS; ++j) {\n for (float i = -KUWAHARA_RADIUS; i <= 0.0; ++i) {\n c = KUWAHARA_SAMPLER_FNC(tex, st + vec2(i,j) * pixel);\n m3 += c;\n s3 += c * c;\n }\n }\n \n \n float min_sigma2 = 1e+2;\n m0 /= n;\n s0 = abs(s0 / n - m0 * m0);\n \n float sigma2 = s0.r + s0.g + s0.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m0;\n }\n \n m1 /= n;\n s1 = abs(s1 / n - m1 * m1);\n \n sigma2 = s1.r + s1.g + s1.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m1;\n }\n \n m2 /= n;\n s2 = abs(s2 / n - m2 * m2);\n \n sigma2 = s2.r + s2.g + s2.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m2;\n }\n \n m3 /= n;\n s3 = abs(s3 / n - m3 * m3);\n \n sigma2 = s3.r + s3.g + s3.b;\n if (sigma2 < min_sigma2) {\n min_sigma2 = sigma2;\n rta = m3;\n }\n\n return rta;\n}\n\n#endif\n\n#endif';
|
|
230
|
+
|
|
231
|
+
// src/shaders/utils/glsl.ts
|
|
232
|
+
var glsl = (x) => String.raw(x);
|
|
233
|
+
|
|
234
|
+
// src/shaders/utils/default-lighting.glsl.ts
|
|
235
|
+
var default_lighting_glsl_default = glsl`
|
|
236
|
+
mat3 rotationX(float angle) {
|
|
237
|
+
float s = sin(angle);
|
|
238
|
+
float c = cos(angle);
|
|
239
|
+
return mat3(
|
|
240
|
+
1.0, 0.0, 0.0,
|
|
241
|
+
0.0, c, -s,
|
|
242
|
+
0.0, s, c
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
mat3 rotationY(float angle) {
|
|
247
|
+
float s = sin(angle);
|
|
248
|
+
float c = cos(angle);
|
|
249
|
+
return mat3(
|
|
250
|
+
c, 0.0, s,
|
|
251
|
+
0.0, 1.0, 0.0,
|
|
252
|
+
-s, 0.0, c
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
vec4 defaultLighting(vec4 color, vec2 res, vec2 rot, float diff) {
|
|
257
|
+
float aspectRatio = res.y / res.x;
|
|
258
|
+
vec2 uv = (gl_FragCoord.xy / res.xy) * 2.0 - 1.0;
|
|
259
|
+
vec2 specPos = vec2(rot.x * 3.8, rot.y * 2.2);
|
|
260
|
+
|
|
261
|
+
vec3 baseNormal = vec3(0.0, 0.0, 1.0);
|
|
262
|
+
mat3 rotMatrix = rotationX(rot.y) * rotationY(rot.x);
|
|
263
|
+
vec3 normal = normalize(rotMatrix * baseNormal);
|
|
264
|
+
|
|
265
|
+
vec3 lightDir = normalize(vec3(0.1, 0.5, 1.0));
|
|
266
|
+
vec3 viewDir = normalize(vec3(0.0, 0.0, 1.0));
|
|
267
|
+
|
|
268
|
+
vec3 halfDir = normalize(lightDir + viewDir);
|
|
269
|
+
float spec = pow(max(dot(normal, halfDir), 0.0), 64.0);
|
|
270
|
+
|
|
271
|
+
vec2 diffPos = uv - specPos;
|
|
272
|
+
diffPos.y *= aspectRatio;
|
|
273
|
+
float dist = length(diffPos);
|
|
274
|
+
float mask = exp(-dist * 0.6);
|
|
275
|
+
float lightFalloff = 1.0 / (dist + 1.3);
|
|
276
|
+
spec *= mask * lightFalloff;
|
|
277
|
+
|
|
278
|
+
return vec4(color.rgb * diff + vec3(1.0) * spec, 1.0);
|
|
279
|
+
}
|
|
280
|
+
`;
|
|
281
|
+
|
|
282
|
+
// src/renderer/shader-bootstrap.ts
|
|
283
|
+
var bootstrapped = false;
|
|
284
|
+
var shortNameMap = /* @__PURE__ */ new Map();
|
|
285
|
+
function buildShortNameMap() {
|
|
286
|
+
const chunks = THREE.ShaderChunk;
|
|
287
|
+
for (const key of Object.keys(chunks)) {
|
|
288
|
+
const parts = key.split("/");
|
|
289
|
+
const shortName = parts[parts.length - 1];
|
|
290
|
+
if (!shortNameMap.has(shortName)) {
|
|
291
|
+
shortNameMap.set(shortName, key);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function resolveIncludes(source) {
|
|
296
|
+
if (shortNameMap.size === 0) buildShortNameMap();
|
|
297
|
+
const pattern = /^[ \t]*#include\s+[<"]([^>"]+)[>"]/gm;
|
|
298
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
299
|
+
function resolve(src, depth = 0) {
|
|
300
|
+
if (depth > 15) return src;
|
|
301
|
+
return src.replace(pattern, (_match, rawName) => {
|
|
302
|
+
const name = rawName.replace(/\.glsl$/, "");
|
|
303
|
+
if (resolved.has(name)) return "";
|
|
304
|
+
const chunks = THREE.ShaderChunk;
|
|
305
|
+
let chunk = chunks[name];
|
|
306
|
+
if (chunk === void 0) {
|
|
307
|
+
const shortName = name.split("/").pop();
|
|
308
|
+
const fullKey = shortNameMap.get(shortName);
|
|
309
|
+
if (fullKey) chunk = chunks[fullKey];
|
|
310
|
+
}
|
|
311
|
+
if (chunk === void 0 && (name.startsWith("../") || name.startsWith("./"))) {
|
|
312
|
+
const cleaned = name.replace(/^\.\.\//, "").replace(/^\.\//, "");
|
|
313
|
+
chunk = chunks["lygia/" + cleaned];
|
|
314
|
+
if (chunk === void 0) {
|
|
315
|
+
const shortName = cleaned.split("/").pop();
|
|
316
|
+
const fullKey = shortNameMap.get(shortName);
|
|
317
|
+
if (fullKey) chunk = chunks[fullKey];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (chunk !== void 0) {
|
|
321
|
+
resolved.add(name);
|
|
322
|
+
return resolve(chunk, depth + 1);
|
|
323
|
+
}
|
|
324
|
+
console.warn(`[pocato] Shader chunk not found: ${rawName}`);
|
|
325
|
+
return `/* chunk not found: ${rawName} */`;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
return resolve(source);
|
|
329
|
+
}
|
|
330
|
+
function bootstrapShaders() {
|
|
331
|
+
if (bootstrapped) return;
|
|
332
|
+
bootstrapped = true;
|
|
333
|
+
const ThreeShaderChunk = THREE.ShaderChunk;
|
|
334
|
+
ThreeShaderChunk["lygia/math/permute"] = permute_default;
|
|
335
|
+
ThreeShaderChunk["lygia/math/mod289"] = mod289_default;
|
|
336
|
+
ThreeShaderChunk["lygia/math/taylorInvSqrt"] = taylorInvSqrt_default;
|
|
337
|
+
ThreeShaderChunk["lygia/math/grad4"] = grad4_default;
|
|
338
|
+
ThreeShaderChunk["lygia/math/rotate4d"] = rotate4d_default;
|
|
339
|
+
ThreeShaderChunk["lygia/math/cubic"] = cubic_default;
|
|
340
|
+
ThreeShaderChunk["lygia/math/quintic"] = quintic_default;
|
|
341
|
+
ThreeShaderChunk["lygia/math/sum"] = sum_default;
|
|
342
|
+
ThreeShaderChunk["lygia/math/saturate"] = saturate_default;
|
|
343
|
+
ThreeShaderChunk["lygia/math/gaussian"] = gaussian_default;
|
|
344
|
+
ThreeShaderChunk["lygia/space/ratio"] = ratio_default;
|
|
345
|
+
ThreeShaderChunk["lygia/generative/random"] = random_default;
|
|
346
|
+
ThreeShaderChunk["lygia/generative/srandom"] = srandom_default;
|
|
347
|
+
ThreeShaderChunk["lygia/generative/gnoise"] = gnoise_default;
|
|
348
|
+
ThreeShaderChunk["lygia/generative/snoise"] = snoise_default;
|
|
349
|
+
ThreeShaderChunk["lygia/generative/fbm"] = fbm_default;
|
|
350
|
+
ThreeShaderChunk["lygia/morphological/dilation"] = dilation_default;
|
|
351
|
+
ThreeShaderChunk["lygia/sampler"] = sampler_default;
|
|
352
|
+
ThreeShaderChunk["lygia/sample/clamp2edge"] = clamp2edge_default;
|
|
353
|
+
ThreeShaderChunk["lygia/draw/digits"] = digits_default;
|
|
354
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur"] = gaussianBlur_default;
|
|
355
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur/2D"] = D_default;
|
|
356
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur/1D"] = D_default2;
|
|
357
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur/1D_fast13"] = D_fast13_default;
|
|
358
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur/1D_fast9"] = D_fast9_default;
|
|
359
|
+
ThreeShaderChunk["lygia/filter/gaussianBlur/1D_fast5"] = D_fast5_default;
|
|
360
|
+
ThreeShaderChunk["lygia/filter/kuwahara"] = kuwahara_default;
|
|
361
|
+
ThreeShaderChunk["utils/defaultLighting"] = default_lighting_glsl_default;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/shaders/common.vert.ts
|
|
365
|
+
var common_vert_default = glsl`
|
|
366
|
+
// three.js built-in attributes
|
|
367
|
+
// attribute vec3 position;
|
|
368
|
+
// attribute vec3 normal;
|
|
369
|
+
// attribute vec2 uv;
|
|
370
|
+
|
|
371
|
+
// three.js built-in uniforms
|
|
372
|
+
// uniform mat4 modelMatrix; // a.k.a worldMatrix
|
|
373
|
+
// uniform mat4 viewMatrix;
|
|
374
|
+
// uniform mat4 modelViewMatrix;
|
|
375
|
+
// uniform mat3 normalMatrix;
|
|
376
|
+
// uniform mat4 projectionMatrix;
|
|
377
|
+
// uniform vec3 cameraPosition;
|
|
378
|
+
|
|
379
|
+
// world transformed attributes for the fragment shader
|
|
380
|
+
varying vec3 vNormal;
|
|
381
|
+
varying vec3 vPosition;
|
|
382
|
+
varying vec2 vUv;
|
|
383
|
+
varying vec3 vView;
|
|
384
|
+
|
|
385
|
+
void main() {
|
|
386
|
+
// vec4 pos = viewMatrix * modelMatrix * vec4(position, 1.0);
|
|
387
|
+
vec4 pos = modelViewMatrix * vec4(position, 1.0);
|
|
388
|
+
|
|
389
|
+
// normalMatrix = transpose(inverse(mat3(modelMatrix)));
|
|
390
|
+
// because transform matrix for normal vector is L^-1T
|
|
391
|
+
vUv = uv;
|
|
392
|
+
vPosition = pos.xyz;
|
|
393
|
+
vView = normalize(cameraPosition - vPosition);
|
|
394
|
+
vNormal = normalize(normalMatrix * normal);
|
|
395
|
+
|
|
396
|
+
// transform the position to clip space
|
|
397
|
+
gl_Position = projectionMatrix * pos;
|
|
398
|
+
}
|
|
399
|
+
`;
|
|
400
|
+
|
|
401
|
+
// src/shaders/glare.frag.ts
|
|
402
|
+
var glare_frag_default = glsl`
|
|
403
|
+
#ifdef GL_ES
|
|
404
|
+
precision mediump float;
|
|
405
|
+
#endif
|
|
406
|
+
|
|
407
|
+
uniform vec2 uResolution;
|
|
408
|
+
uniform vec2 uMouse;
|
|
409
|
+
uniform vec2 uMove;
|
|
410
|
+
uniform vec2 uRotate;
|
|
411
|
+
uniform float uTime;
|
|
412
|
+
uniform sampler2D uImgBase;
|
|
413
|
+
uniform sampler2D uImgPopup;
|
|
414
|
+
|
|
415
|
+
varying vec2 vUv;
|
|
416
|
+
|
|
417
|
+
#include <utils/defaultLighting>
|
|
418
|
+
|
|
419
|
+
void main() {
|
|
420
|
+
// 기본 카드 텍스처 샘플링
|
|
421
|
+
vec4 baseColor = texture2D(uImgBase, vUv);
|
|
422
|
+
|
|
423
|
+
// 팝업 텍스처 샘플링 (움직임 반영)
|
|
424
|
+
float popupOffset = 0.0;
|
|
425
|
+
vec2 popupUv = vUv + (uMove / uResolution) * popupOffset; // 팝업 이동 효과
|
|
426
|
+
vec4 popupColor = texture2D(uImgPopup, popupUv);
|
|
427
|
+
|
|
428
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
429
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
430
|
+
|
|
431
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
432
|
+
}
|
|
433
|
+
`;
|
|
434
|
+
|
|
435
|
+
// src/shaders/glare-3d.frag.ts
|
|
436
|
+
var glare_3d_frag_default = glsl`
|
|
437
|
+
#ifdef GL_ES
|
|
438
|
+
precision mediump float;
|
|
439
|
+
#endif
|
|
440
|
+
|
|
441
|
+
uniform vec2 uResolution;
|
|
442
|
+
uniform vec2 uMouse;
|
|
443
|
+
uniform vec2 uMove;
|
|
444
|
+
uniform vec2 uRotate;
|
|
445
|
+
uniform float uTime;
|
|
446
|
+
uniform sampler2D uImgBase;
|
|
447
|
+
uniform sampler2D uImgPopup;
|
|
448
|
+
|
|
449
|
+
varying vec2 vUv;
|
|
450
|
+
|
|
451
|
+
#include <utils/defaultLighting>
|
|
452
|
+
|
|
453
|
+
void main() {
|
|
454
|
+
// 기본 카드 텍스처 샘플링
|
|
455
|
+
vec4 baseColor = texture2D(uImgBase, vUv);
|
|
456
|
+
|
|
457
|
+
// 팝업 텍스처 샘플링 (움직임 반영)
|
|
458
|
+
vec2 popupOffset = vec2(-uRotate.x * 0.08, -uRotate.y * 0.06);
|
|
459
|
+
vec2 popupUv = vUv + popupOffset; // 팝업 이동 효과
|
|
460
|
+
vec4 popupColor = texture2D(uImgPopup, popupUv);
|
|
461
|
+
|
|
462
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
463
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
464
|
+
|
|
465
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
466
|
+
}
|
|
467
|
+
`;
|
|
468
|
+
|
|
469
|
+
// src/shaders/snowfall.frag.ts
|
|
470
|
+
var snowfall_frag_default = glsl`
|
|
471
|
+
#ifdef GL_ES
|
|
472
|
+
precision mediump float;
|
|
473
|
+
#endif
|
|
474
|
+
|
|
475
|
+
uniform vec2 uResolution;
|
|
476
|
+
uniform vec2 uMouse;
|
|
477
|
+
uniform vec2 uMove;
|
|
478
|
+
uniform vec2 uRotate;
|
|
479
|
+
uniform float uTime;
|
|
480
|
+
uniform sampler2D uImgBase;
|
|
481
|
+
uniform sampler2D uImgPopup;
|
|
482
|
+
|
|
483
|
+
varying vec2 vUv;
|
|
484
|
+
|
|
485
|
+
#define mod289(x) mod(x, 289.)
|
|
486
|
+
|
|
487
|
+
vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); }
|
|
488
|
+
|
|
489
|
+
float snoise(vec2 coord) {
|
|
490
|
+
const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
|
|
491
|
+
vec2 intPart = floor(coord + dot(coord, C.yy));
|
|
492
|
+
vec2 fracPart = coord - intPart + dot(intPart, C.xx);
|
|
493
|
+
|
|
494
|
+
vec2 offset;
|
|
495
|
+
offset = (fracPart.x > fracPart.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
|
496
|
+
vec4 combined = fracPart.xyxy + C.xxzz;
|
|
497
|
+
combined.xy -= offset;
|
|
498
|
+
|
|
499
|
+
intPart = mod289(intPart);
|
|
500
|
+
vec3 perm = permute(permute(intPart.y + vec3(0.0, offset.y, 1.0))
|
|
501
|
+
+ intPart.x + vec3(0.0, offset.x, 1.0));
|
|
502
|
+
|
|
503
|
+
vec3 gradient = max(0.5 - vec3(dot(fracPart, fracPart), dot(combined.xy, combined.xy), dot(combined.zw, combined.zw)), 0.0);
|
|
504
|
+
gradient *= gradient;
|
|
505
|
+
gradient *= gradient;
|
|
506
|
+
|
|
507
|
+
vec3 noiseVec = 2.0 * fract(perm * C.www) - 1.0;
|
|
508
|
+
vec3 absDiff = abs(noiseVec) - 0.5;
|
|
509
|
+
vec3 offsetVec = floor(noiseVec + 0.5);
|
|
510
|
+
vec3 gradientVec = noiseVec - offsetVec;
|
|
511
|
+
|
|
512
|
+
gradient *= 1.79284291400159 - 0.85373472095314 * (gradientVec * gradientVec + absDiff * absDiff);
|
|
513
|
+
|
|
514
|
+
vec3 finalGrad;
|
|
515
|
+
finalGrad.x = gradientVec.x * fracPart.x + absDiff.x * fracPart.y;
|
|
516
|
+
finalGrad.yz = gradientVec.yz * combined.xz + absDiff.yz * combined.yw;
|
|
517
|
+
|
|
518
|
+
return 130.0 * dot(gradient, finalGrad);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
float fbm(vec2 position) {
|
|
522
|
+
float result = 0.0;
|
|
523
|
+
float weight = 0.5;
|
|
524
|
+
for (int i = 0; i < 5; i++) {
|
|
525
|
+
result += weight * snoise(position);
|
|
526
|
+
position *= 2.0;
|
|
527
|
+
weight *= 0.5;
|
|
528
|
+
}
|
|
529
|
+
return result;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// snowfall
|
|
533
|
+
const int LAYERS = 66;
|
|
534
|
+
const float DEPTH_NEAR = 0.3;
|
|
535
|
+
const float WIDTH_NEAR = 0.4;
|
|
536
|
+
const float SPEED_NEAR = 0.6;
|
|
537
|
+
const float DEPTH_FAR = 0.1;
|
|
538
|
+
const float WIDTH_FAR = 0.3;
|
|
539
|
+
const float SPEED_FAR = 0.1;
|
|
540
|
+
|
|
541
|
+
float computeSnow(in vec2 uv, int layerStart, int layerEnd) {
|
|
542
|
+
const mat3 permutationMatrix = mat3(13.323122, 23.5112, 21.71123, 21.1212, 28.7312, 11.9312, 21.8112, 14.7212, 61.3934);
|
|
543
|
+
vec2 moveNormalized = uMove.xy / uResolution.xy;
|
|
544
|
+
moveNormalized.x = max(0.15, smoothstep(0.15, 0.8, moveNormalized.x));
|
|
545
|
+
uv.x += moveNormalized.x * 0.2;
|
|
546
|
+
float totalLayers = float(LAYERS);
|
|
547
|
+
float accumulation = 0.0;
|
|
548
|
+
float depthOfField = 5.0 * sin(uTime * 0.1);
|
|
549
|
+
for (int i = max(layerStart, 0); i < min(layerEnd, LAYERS); i++) {
|
|
550
|
+
float layer = float(i);
|
|
551
|
+
float depthFactor = smoothstep(DEPTH_NEAR, DEPTH_FAR, layer / totalLayers);
|
|
552
|
+
float widthFactor = smoothstep(WIDTH_NEAR, WIDTH_FAR, layer / totalLayers);
|
|
553
|
+
float speedFactor = smoothstep(SPEED_NEAR, SPEED_FAR, layer / totalLayers);
|
|
554
|
+
vec2 offsetUv = uv * (1.0 + layer * depthFactor);
|
|
555
|
+
float windEffect = widthFactor * mod(layer * 7.238917, 1.0) - widthFactor * 0.1 * sin(uTime * 2.0 + layer);
|
|
556
|
+
offsetUv += vec2(offsetUv.y * windEffect, speedFactor * uTime / (1.0 + layer * depthFactor * 0.03));
|
|
557
|
+
vec3 noiseInput = vec3(floor(offsetUv), 31.189 + layer);
|
|
558
|
+
vec3 permuted = floor(noiseInput) * 0.00001 + fract(noiseInput);
|
|
559
|
+
vec3 noise = fract((31415.9 + permuted) / fract(permutationMatrix * permuted));
|
|
560
|
+
vec2 particleShape = abs(mod(offsetUv, 1.0) - 0.5 + 0.9 * noise.xy - 0.45);
|
|
561
|
+
particleShape += 0.01 * abs(2.0 * fract(10.0 * offsetUv.yx) - 1.0);
|
|
562
|
+
float distance = 0.6 * max(particleShape.x - particleShape.y, particleShape.x + particleShape.y) + max(particleShape.x, particleShape.y) - 0.01;
|
|
563
|
+
float edgeThreshold = 0.05 + 0.05 * min(0.5 * abs(layer - 5.0 - depthOfField), 1.0);
|
|
564
|
+
accumulation += smoothstep(edgeThreshold, -edgeThreshold, distance) * (noise.x / (1.0 + 0.02 * layer * depthFactor));
|
|
565
|
+
}
|
|
566
|
+
return accumulation;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
void main() {
|
|
570
|
+
vec4 baseTexture = texture2D(uImgBase, vUv);
|
|
571
|
+
gl_FragColor = mix(gl_FragColor, baseTexture, baseTexture.a);
|
|
572
|
+
|
|
573
|
+
float snowEffect = computeSnow(vUv, 5, 15);
|
|
574
|
+
gl_FragColor += vec4(vec3(snowEffect), 1.0);
|
|
575
|
+
|
|
576
|
+
float popupMoveOffset = 0.0;
|
|
577
|
+
vec2 popupOffsetUv = vUv + (uMove.xy / uResolution.xy) * popupMoveOffset;
|
|
578
|
+
vec4 popupTexture = texture2D(uImgPopup, popupOffsetUv);
|
|
579
|
+
gl_FragColor = mix(gl_FragColor, popupTexture, popupTexture.a);
|
|
580
|
+
|
|
581
|
+
snowEffect = computeSnow(vUv, 16, 20);
|
|
582
|
+
gl_FragColor += vec4(vec3(snowEffect), 1.0);
|
|
583
|
+
}
|
|
584
|
+
`;
|
|
585
|
+
|
|
586
|
+
// src/shaders/snowfall-3d.frag.ts
|
|
587
|
+
var snowfall_3d_frag_default = glsl`
|
|
588
|
+
#ifdef GL_ES
|
|
589
|
+
precision mediump float;
|
|
590
|
+
#endif
|
|
591
|
+
|
|
592
|
+
uniform vec2 uResolution;
|
|
593
|
+
uniform vec2 uMouse;
|
|
594
|
+
uniform vec2 uMove;
|
|
595
|
+
uniform vec2 uRotate;
|
|
596
|
+
uniform float uTime;
|
|
597
|
+
uniform sampler2D uImgBase;
|
|
598
|
+
uniform sampler2D uImgPopup;
|
|
599
|
+
|
|
600
|
+
varying vec2 vUv;
|
|
601
|
+
|
|
602
|
+
#define mod289(x) mod(x, 289.)
|
|
603
|
+
|
|
604
|
+
vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); }
|
|
605
|
+
|
|
606
|
+
float snoise(vec2 coord) {
|
|
607
|
+
const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
|
|
608
|
+
vec2 intPart = floor(coord + dot(coord, C.yy));
|
|
609
|
+
vec2 fracPart = coord - intPart + dot(intPart, C.xx);
|
|
610
|
+
|
|
611
|
+
vec2 offset;
|
|
612
|
+
offset = (fracPart.x > fracPart.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
|
613
|
+
vec4 combined = fracPart.xyxy + C.xxzz;
|
|
614
|
+
combined.xy -= offset;
|
|
615
|
+
|
|
616
|
+
intPart = mod289(intPart);
|
|
617
|
+
vec3 perm = permute(permute(intPart.y + vec3(0.0, offset.y, 1.0))
|
|
618
|
+
+ intPart.x + vec3(0.0, offset.x, 1.0));
|
|
619
|
+
|
|
620
|
+
vec3 gradient = max(0.5 - vec3(dot(fracPart, fracPart), dot(combined.xy, combined.xy), dot(combined.zw, combined.zw)), 0.0);
|
|
621
|
+
gradient *= gradient;
|
|
622
|
+
gradient *= gradient;
|
|
623
|
+
|
|
624
|
+
vec3 noiseVec = 2.0 * fract(perm * C.www) - 1.0;
|
|
625
|
+
vec3 absDiff = abs(noiseVec) - 0.5;
|
|
626
|
+
vec3 offsetVec = floor(noiseVec + 0.5);
|
|
627
|
+
vec3 gradientVec = noiseVec - offsetVec;
|
|
628
|
+
|
|
629
|
+
gradient *= 1.79284291400159 - 0.85373472095314 * (gradientVec * gradientVec + absDiff * absDiff);
|
|
630
|
+
|
|
631
|
+
vec3 finalGrad;
|
|
632
|
+
finalGrad.x = gradientVec.x * fracPart.x + absDiff.x * fracPart.y;
|
|
633
|
+
finalGrad.yz = gradientVec.yz * combined.xz + absDiff.yz * combined.yw;
|
|
634
|
+
|
|
635
|
+
return 130.0 * dot(gradient, finalGrad);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
float fbm(vec2 position) {
|
|
639
|
+
float result = 0.0;
|
|
640
|
+
float weight = 0.5;
|
|
641
|
+
for (int i = 0; i < 5; i++) {
|
|
642
|
+
result += weight * snoise(position);
|
|
643
|
+
position *= 2.0;
|
|
644
|
+
weight *= 0.5;
|
|
645
|
+
}
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// snowfall
|
|
650
|
+
const int LAYERS = 66;
|
|
651
|
+
const float DEPTH_NEAR = 0.3;
|
|
652
|
+
const float WIDTH_NEAR = 0.4;
|
|
653
|
+
const float SPEED_NEAR = 0.6;
|
|
654
|
+
const float DEPTH_FAR = 0.1;
|
|
655
|
+
const float WIDTH_FAR = 0.3;
|
|
656
|
+
const float SPEED_FAR = 0.1;
|
|
657
|
+
|
|
658
|
+
float computeSnow(in vec2 uv, int layerStart, int layerEnd) {
|
|
659
|
+
const mat3 permutationMatrix = mat3(13.323122, 23.5112, 21.71123, 21.1212, 28.7312, 11.9312, 21.8112, 14.7212, 61.3934);
|
|
660
|
+
vec2 moveNormalized = uMove.xy / uResolution.xy;
|
|
661
|
+
moveNormalized.x = max(0.15, smoothstep(0.15, 0.8, moveNormalized.x));
|
|
662
|
+
uv.x += moveNormalized.x * 0.2;
|
|
663
|
+
float totalLayers = float(LAYERS);
|
|
664
|
+
float accumulation = 0.0;
|
|
665
|
+
float depthOfField = 5.0 * sin(uTime * 0.1);
|
|
666
|
+
for (int i = max(layerStart, 0); i < min(layerEnd, LAYERS); i++) {
|
|
667
|
+
float layer = float(i);
|
|
668
|
+
float depthFactor = smoothstep(DEPTH_NEAR, DEPTH_FAR, layer / totalLayers);
|
|
669
|
+
float widthFactor = smoothstep(WIDTH_NEAR, WIDTH_FAR, layer / totalLayers);
|
|
670
|
+
float speedFactor = smoothstep(SPEED_NEAR, SPEED_FAR, layer / totalLayers);
|
|
671
|
+
vec2 offsetUv = uv * (1.0 + layer * depthFactor);
|
|
672
|
+
float windEffect = widthFactor * mod(layer * 7.238917, 1.0) - widthFactor * 0.1 * sin(uTime * 2.0 + layer);
|
|
673
|
+
offsetUv += vec2(offsetUv.y * windEffect, speedFactor * uTime / (1.0 + layer * depthFactor * 0.03));
|
|
674
|
+
vec3 noiseInput = vec3(floor(offsetUv), 31.189 + layer);
|
|
675
|
+
vec3 permuted = floor(noiseInput) * 0.00001 + fract(noiseInput);
|
|
676
|
+
vec3 noise = fract((31415.9 + permuted) / fract(permutationMatrix * permuted));
|
|
677
|
+
vec2 particleShape = abs(mod(offsetUv, 1.0) - 0.5 + 0.9 * noise.xy - 0.45);
|
|
678
|
+
particleShape += 0.01 * abs(2.0 * fract(10.0 * offsetUv.yx) - 1.0);
|
|
679
|
+
float distance = 0.6 * max(particleShape.x - particleShape.y, particleShape.x + particleShape.y) + max(particleShape.x, particleShape.y) - 0.01;
|
|
680
|
+
float edgeThreshold = 0.05 + 0.05 * min(0.5 * abs(layer - 5.0 - depthOfField), 1.0);
|
|
681
|
+
accumulation += smoothstep(edgeThreshold, -edgeThreshold, distance) * (noise.x / (1.0 + 0.02 * layer * depthFactor));
|
|
682
|
+
}
|
|
683
|
+
return accumulation;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
void main() {
|
|
687
|
+
vec4 baseTexture = texture2D(uImgBase, vUv);
|
|
688
|
+
gl_FragColor = mix(gl_FragColor, baseTexture, baseTexture.a);
|
|
689
|
+
|
|
690
|
+
float snowEffect = computeSnow(vUv, 5, 15);
|
|
691
|
+
gl_FragColor += vec4(vec3(snowEffect), 1.0);
|
|
692
|
+
|
|
693
|
+
// 3D parallax offset for popup layer
|
|
694
|
+
vec2 popupOffset = vec2(-uRotate.x * 0.08, -uRotate.y * 0.06);
|
|
695
|
+
vec2 popupOffsetUv = vUv + popupOffset;
|
|
696
|
+
vec4 popupTexture = texture2D(uImgPopup, popupOffsetUv);
|
|
697
|
+
gl_FragColor = mix(gl_FragColor, popupTexture, popupTexture.a);
|
|
698
|
+
|
|
699
|
+
snowEffect = computeSnow(vUv, 16, 20);
|
|
700
|
+
gl_FragColor += vec4(vec3(snowEffect), 1.0);
|
|
701
|
+
}
|
|
702
|
+
`;
|
|
703
|
+
|
|
704
|
+
// src/shaders/brush.frag.ts
|
|
705
|
+
var brush_frag_default = glsl`
|
|
706
|
+
#ifdef GL_ES
|
|
707
|
+
precision mediump float;
|
|
708
|
+
#endif
|
|
709
|
+
|
|
710
|
+
uniform vec2 uResolution;
|
|
711
|
+
uniform vec2 uMouse;
|
|
712
|
+
uniform vec2 uMove;
|
|
713
|
+
uniform vec2 uRotate;
|
|
714
|
+
uniform float uTime;
|
|
715
|
+
uniform sampler2D uImgBase;
|
|
716
|
+
uniform sampler2D uImgPopup;
|
|
717
|
+
|
|
718
|
+
varying vec2 vUv;
|
|
719
|
+
|
|
720
|
+
#include <lygia/sample/clamp2edge>
|
|
721
|
+
#define KUWAHARA_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
|
|
722
|
+
#include <lygia/filter/kuwahara>
|
|
723
|
+
#include <lygia/draw/digits>
|
|
724
|
+
#include <utils/defaultLighting>
|
|
725
|
+
|
|
726
|
+
void main() {
|
|
727
|
+
vec2 pixel = 1.0 / uResolution.xy;
|
|
728
|
+
vec2 popUpUv = vUv + (uMove.xy / uResolution.xy) * 0.008;
|
|
729
|
+
|
|
730
|
+
vec4 baseColor = kuwahara(uImgBase, vUv, pixel, 4.0);
|
|
731
|
+
vec4 popupColor = kuwahara(uImgPopup, popUpUv, pixel, 4.0);
|
|
732
|
+
|
|
733
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
734
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
735
|
+
|
|
736
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
737
|
+
}
|
|
738
|
+
`;
|
|
739
|
+
|
|
740
|
+
// src/shaders/brush-3d.frag.ts
|
|
741
|
+
var brush_3d_frag_default = glsl`
|
|
742
|
+
#ifdef GL_ES
|
|
743
|
+
precision mediump float;
|
|
744
|
+
#endif
|
|
745
|
+
|
|
746
|
+
uniform vec2 uResolution;
|
|
747
|
+
uniform vec2 uMouse;
|
|
748
|
+
uniform vec2 uMove;
|
|
749
|
+
uniform vec2 uRotate;
|
|
750
|
+
uniform float uTime;
|
|
751
|
+
uniform sampler2D uImgBase;
|
|
752
|
+
uniform sampler2D uImgPopup;
|
|
753
|
+
|
|
754
|
+
varying vec2 vUv;
|
|
755
|
+
|
|
756
|
+
#include <lygia/sample/clamp2edge>
|
|
757
|
+
#define KUWAHARA_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
|
|
758
|
+
#include <lygia/filter/kuwahara>
|
|
759
|
+
#include <lygia/draw/digits>
|
|
760
|
+
#include <utils/defaultLighting>
|
|
761
|
+
|
|
762
|
+
void main() {
|
|
763
|
+
vec2 pixel = 1.0 / uResolution.xy;
|
|
764
|
+
|
|
765
|
+
// 3D parallax offset for popup layer
|
|
766
|
+
vec2 popupOffset = vec2(-uRotate.x * 0.08, -uRotate.y * 0.06);
|
|
767
|
+
vec2 popUpUv = vUv + popupOffset;
|
|
768
|
+
|
|
769
|
+
vec4 baseColor = kuwahara(uImgBase, vUv, pixel, 4.0);
|
|
770
|
+
vec4 popupColor = kuwahara(uImgPopup, popUpUv, pixel, 4.0);
|
|
771
|
+
|
|
772
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
773
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
774
|
+
|
|
775
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
776
|
+
}
|
|
777
|
+
`;
|
|
778
|
+
|
|
779
|
+
// src/shaders/blur.frag.ts
|
|
780
|
+
var blur_frag_default = glsl`
|
|
781
|
+
#ifdef GL_ES
|
|
782
|
+
precision mediump float;
|
|
783
|
+
#endif
|
|
784
|
+
|
|
785
|
+
uniform vec2 uResolution;
|
|
786
|
+
uniform vec2 uMouse;
|
|
787
|
+
uniform vec2 uMove;
|
|
788
|
+
uniform vec2 uRotate;
|
|
789
|
+
uniform float uTime;
|
|
790
|
+
uniform sampler2D uImgBase;
|
|
791
|
+
uniform sampler2D uImgPopup;
|
|
792
|
+
|
|
793
|
+
varying vec2 vUv;
|
|
794
|
+
|
|
795
|
+
// #define GAUSSIANBLUR_2D
|
|
796
|
+
#include <lygia/sample/clamp2edge>
|
|
797
|
+
#define GAUSSIANBLUR_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
|
|
798
|
+
#include <lygia/filter/gaussianBlur>
|
|
799
|
+
#include <lygia/draw/digits>
|
|
800
|
+
#include <utils/defaultLighting>
|
|
801
|
+
|
|
802
|
+
void main() {
|
|
803
|
+
vec2 pixel = 1.0 / uResolution.xy;
|
|
804
|
+
vec2 popUpUv = vUv + (uMove.xy / uResolution.xy) * 0.008;
|
|
805
|
+
|
|
806
|
+
vec4 baseColor = gaussianBlur(uImgBase, vUv, pixel, 12);
|
|
807
|
+
vec4 popupColor = texture2D(uImgPopup, popUpUv);
|
|
808
|
+
|
|
809
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
810
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
811
|
+
|
|
812
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
813
|
+
}
|
|
814
|
+
`;
|
|
815
|
+
|
|
816
|
+
// src/shaders/blur-3d.frag.ts
|
|
817
|
+
var blur_3d_frag_default = glsl`
|
|
818
|
+
#ifdef GL_ES
|
|
819
|
+
precision mediump float;
|
|
820
|
+
#endif
|
|
821
|
+
|
|
822
|
+
uniform vec2 uResolution;
|
|
823
|
+
uniform vec2 uMouse;
|
|
824
|
+
uniform vec2 uMove;
|
|
825
|
+
uniform vec2 uRotate;
|
|
826
|
+
uniform float uTime;
|
|
827
|
+
uniform sampler2D uImgBase;
|
|
828
|
+
uniform sampler2D uImgPopup;
|
|
829
|
+
|
|
830
|
+
varying vec2 vUv;
|
|
831
|
+
|
|
832
|
+
// #define GAUSSIANBLUR_2D
|
|
833
|
+
#include <lygia/sample/clamp2edge>
|
|
834
|
+
#define GAUSSIANBLUR_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
|
|
835
|
+
#include <lygia/filter/gaussianBlur>
|
|
836
|
+
#include <lygia/draw/digits>
|
|
837
|
+
#include <utils/defaultLighting>
|
|
838
|
+
|
|
839
|
+
void main() {
|
|
840
|
+
vec2 pixel = 1.0 / uResolution.xy;
|
|
841
|
+
|
|
842
|
+
// 3D parallax offset for popup layer
|
|
843
|
+
vec2 popupOffset = vec2(-uRotate.x * 0.08, -uRotate.y * 0.06);
|
|
844
|
+
vec2 popUpUv = vUv + popupOffset;
|
|
845
|
+
|
|
846
|
+
vec4 baseColor = gaussianBlur(uImgBase, vUv, pixel, 12);
|
|
847
|
+
vec4 popupColor = texture2D(uImgPopup, popUpUv);
|
|
848
|
+
|
|
849
|
+
float aSoft = smoothstep(0.4, 1.0, popupColor.a);
|
|
850
|
+
vec4 pocaColor = mix(baseColor, popupColor, aSoft);
|
|
851
|
+
|
|
852
|
+
gl_FragColor = defaultLighting(pocaColor, uResolution, uRotate, 1.0);
|
|
853
|
+
}
|
|
854
|
+
`;
|
|
855
|
+
|
|
856
|
+
// src/renderer/index.ts
|
|
857
|
+
var FRAG_SHADERS = {
|
|
858
|
+
"glare": glare_frag_default,
|
|
859
|
+
"glare-3d": glare_3d_frag_default,
|
|
860
|
+
"snowfall": snowfall_frag_default,
|
|
861
|
+
"snowfall-3d": snowfall_3d_frag_default,
|
|
862
|
+
"brush": brush_frag_default,
|
|
863
|
+
"brush-3d": brush_3d_frag_default,
|
|
864
|
+
"blur": blur_frag_default,
|
|
865
|
+
"blur-3d": blur_3d_frag_default
|
|
866
|
+
};
|
|
867
|
+
var Renderer = class {
|
|
868
|
+
constructor(container, options, onError, onReady) {
|
|
869
|
+
this.container = container;
|
|
870
|
+
this.options = options;
|
|
871
|
+
this.onError = onError;
|
|
872
|
+
this.onReady = onReady;
|
|
873
|
+
this.scene = null;
|
|
874
|
+
this.camera = null;
|
|
875
|
+
this.webglRenderer = null;
|
|
876
|
+
this.material = null;
|
|
877
|
+
this.mesh = null;
|
|
878
|
+
this.clock = new THREE2.Clock();
|
|
879
|
+
this.rafId = null;
|
|
880
|
+
this.textures = [];
|
|
881
|
+
this.resizeObserver = null;
|
|
882
|
+
this.injectStyles();
|
|
883
|
+
this.cardEl = document.createElement("div");
|
|
884
|
+
this.cardEl.className = "pocato-card pocato-loading";
|
|
885
|
+
this.rotatorEl = document.createElement("div");
|
|
886
|
+
this.rotatorEl.className = "pocato-rotator";
|
|
887
|
+
this.backEl = document.createElement("div");
|
|
888
|
+
this.backEl.className = "pocato-back";
|
|
889
|
+
if (options.backImage) {
|
|
890
|
+
const backImg = document.createElement("img");
|
|
891
|
+
backImg.src = options.backImage;
|
|
892
|
+
backImg.className = "pocato-back-img";
|
|
893
|
+
this.backEl.appendChild(backImg);
|
|
894
|
+
}
|
|
895
|
+
this.frontEl = document.createElement("div");
|
|
896
|
+
this.frontEl.className = "pocato-front";
|
|
897
|
+
this.canvas = document.createElement("canvas");
|
|
898
|
+
this.canvas.className = "pocato-canvas";
|
|
899
|
+
this.frontContentEl = document.createElement("div");
|
|
900
|
+
this.frontContentEl.className = "pocato-content pocato-front-content";
|
|
901
|
+
this.backContentEl = document.createElement("div");
|
|
902
|
+
this.backContentEl.className = "pocato-content pocato-back-content";
|
|
903
|
+
this.frontEl.appendChild(this.canvas);
|
|
904
|
+
this.frontEl.appendChild(this.frontContentEl);
|
|
905
|
+
this.backEl.appendChild(this.backContentEl);
|
|
906
|
+
this.rotatorEl.appendChild(this.backEl);
|
|
907
|
+
this.rotatorEl.appendChild(this.frontEl);
|
|
908
|
+
this.cardEl.appendChild(this.rotatorEl);
|
|
909
|
+
this.container.appendChild(this.cardEl);
|
|
910
|
+
bootstrapShaders();
|
|
911
|
+
this.init();
|
|
912
|
+
}
|
|
913
|
+
injectStyles() {
|
|
914
|
+
const id = "pocato-styles";
|
|
915
|
+
if (document.getElementById(id)) return;
|
|
916
|
+
const style = document.createElement("style");
|
|
917
|
+
style.id = id;
|
|
918
|
+
style.textContent = `
|
|
919
|
+
.pocato-card {
|
|
920
|
+
width: 100%;
|
|
921
|
+
height: 100%;
|
|
922
|
+
perspective: 1000px;
|
|
923
|
+
touch-action: none;
|
|
924
|
+
user-select: none;
|
|
925
|
+
transform: translate3d(0,0,0);
|
|
926
|
+
opacity: 0;
|
|
927
|
+
transition: opacity 0.5s ease;
|
|
928
|
+
}
|
|
929
|
+
.pocato-card.pocato-ready {
|
|
930
|
+
opacity: 1;
|
|
931
|
+
}
|
|
932
|
+
.pocato-rotator {
|
|
933
|
+
width: 100%;
|
|
934
|
+
height: 100%;
|
|
935
|
+
position: relative;
|
|
936
|
+
transform-style: preserve-3d;
|
|
937
|
+
transform-origin: center;
|
|
938
|
+
transform: rotateY(var(--pocato-rotate-x, 0deg)) rotateX(var(--pocato-rotate-y, 0deg));
|
|
939
|
+
border-radius: 2%;
|
|
940
|
+
will-change: transform, box-shadow;
|
|
941
|
+
transition: box-shadow 0.4s ease;
|
|
942
|
+
box-shadow:
|
|
943
|
+
0px 10px 20px -5px rgba(0,0,0,0.4),
|
|
944
|
+
0 2px 15px -5px rgba(0,0,0,0.3);
|
|
945
|
+
pointer-events: auto;
|
|
946
|
+
}
|
|
947
|
+
.pocato-front {
|
|
948
|
+
position: absolute;
|
|
949
|
+
top: 0; left: 0;
|
|
950
|
+
width: 100%;
|
|
951
|
+
height: 100%;
|
|
952
|
+
backface-visibility: hidden;
|
|
953
|
+
-webkit-backface-visibility: hidden;
|
|
954
|
+
transform: translate3d(0,0,0);
|
|
955
|
+
border-radius: 2%;
|
|
956
|
+
overflow: hidden;
|
|
957
|
+
}
|
|
958
|
+
.pocato-back {
|
|
959
|
+
position: absolute;
|
|
960
|
+
top: 0; left: 0;
|
|
961
|
+
width: 100%;
|
|
962
|
+
height: 100%;
|
|
963
|
+
backface-visibility: hidden;
|
|
964
|
+
-webkit-backface-visibility: hidden;
|
|
965
|
+
transform: rotateY(180deg) translateZ(0);
|
|
966
|
+
border-radius: 2%;
|
|
967
|
+
overflow: hidden;
|
|
968
|
+
background-color: #1a1a2e;
|
|
969
|
+
}
|
|
970
|
+
.pocato-back-img {
|
|
971
|
+
width: 100%;
|
|
972
|
+
height: 100%;
|
|
973
|
+
object-fit: cover;
|
|
974
|
+
pointer-events: none;
|
|
975
|
+
}
|
|
976
|
+
.pocato-canvas {
|
|
977
|
+
width: 100%;
|
|
978
|
+
height: 100%;
|
|
979
|
+
display: block;
|
|
980
|
+
}
|
|
981
|
+
.pocato-content {
|
|
982
|
+
position: absolute;
|
|
983
|
+
top: 0; left: 0;
|
|
984
|
+
width: 100%;
|
|
985
|
+
height: 100%;
|
|
986
|
+
pointer-events: none;
|
|
987
|
+
z-index: 1;
|
|
988
|
+
}
|
|
989
|
+
.pocato-content > * {
|
|
990
|
+
pointer-events: auto;
|
|
991
|
+
}
|
|
992
|
+
`;
|
|
993
|
+
document.head.appendChild(style);
|
|
994
|
+
}
|
|
995
|
+
init() {
|
|
996
|
+
const { width, height } = this.container.getBoundingClientRect();
|
|
997
|
+
this.scene = new THREE2.Scene();
|
|
998
|
+
this.camera = new THREE2.Camera();
|
|
999
|
+
this.webglRenderer = new THREE2.WebGLRenderer({
|
|
1000
|
+
canvas: this.canvas,
|
|
1001
|
+
alpha: true
|
|
1002
|
+
});
|
|
1003
|
+
this.webglRenderer.setPixelRatio(window.devicePixelRatio);
|
|
1004
|
+
this.webglRenderer.setSize(width, height);
|
|
1005
|
+
const pixelWidth = this.canvas.width;
|
|
1006
|
+
const pixelHeight = this.canvas.height;
|
|
1007
|
+
const uniforms = this.createUniforms(pixelWidth, pixelHeight);
|
|
1008
|
+
const rawFragmentShader = this.options.customShader ?? FRAG_SHADERS[this.options.type];
|
|
1009
|
+
const fragmentShader = resolveIncludes(rawFragmentShader);
|
|
1010
|
+
this.material = new THREE2.ShaderMaterial({
|
|
1011
|
+
vertexShader: resolveIncludes(common_vert_default),
|
|
1012
|
+
fragmentShader,
|
|
1013
|
+
uniforms,
|
|
1014
|
+
transparent: true
|
|
1015
|
+
});
|
|
1016
|
+
const geometry = new THREE2.PlaneGeometry(2, 2);
|
|
1017
|
+
this.mesh = new THREE2.Mesh(geometry, this.material);
|
|
1018
|
+
this.scene.add(this.mesh);
|
|
1019
|
+
this.loadTextures();
|
|
1020
|
+
this.setupResizeObserver();
|
|
1021
|
+
this.startRenderLoop();
|
|
1022
|
+
requestAnimationFrame(() => {
|
|
1023
|
+
this.cardEl.classList.remove("pocato-loading");
|
|
1024
|
+
this.cardEl.classList.add("pocato-ready");
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
createUniforms(width, height) {
|
|
1028
|
+
return {
|
|
1029
|
+
uTime: { value: 0 },
|
|
1030
|
+
uResolution: { value: new THREE2.Vector2(width, height) },
|
|
1031
|
+
uMouse: { value: new THREE2.Vector2(0, 0) },
|
|
1032
|
+
uMove: { value: new THREE2.Vector2(0, 0) },
|
|
1033
|
+
uRotate: { value: new THREE2.Vector2(0, 0) },
|
|
1034
|
+
uCardOpacity: { value: 1 },
|
|
1035
|
+
uImgBase: { value: null },
|
|
1036
|
+
uImgPopup: { value: null },
|
|
1037
|
+
uImgMask: { value: null }
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
loadTextures() {
|
|
1041
|
+
const loader = new THREE2.TextureLoader();
|
|
1042
|
+
const load = (url, uniform) => {
|
|
1043
|
+
if (!url) return;
|
|
1044
|
+
loader.load(
|
|
1045
|
+
url,
|
|
1046
|
+
(texture) => {
|
|
1047
|
+
this.textures.push(texture);
|
|
1048
|
+
if (this.material) {
|
|
1049
|
+
this.material.uniforms[uniform].value = texture;
|
|
1050
|
+
}
|
|
1051
|
+
},
|
|
1052
|
+
void 0,
|
|
1053
|
+
() => {
|
|
1054
|
+
this.onError?.(new Error(`Failed to load texture: ${url}`));
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
};
|
|
1058
|
+
load(this.options.baseImage, "uImgBase");
|
|
1059
|
+
load(this.options.popupImage, "uImgPopup");
|
|
1060
|
+
load(this.options.maskImage, "uImgMask");
|
|
1061
|
+
this.onReady?.();
|
|
1062
|
+
}
|
|
1063
|
+
setupResizeObserver() {
|
|
1064
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
|
1065
|
+
const entry = entries[0];
|
|
1066
|
+
if (!entry) return;
|
|
1067
|
+
const { width, height } = entry.contentRect;
|
|
1068
|
+
if (width === 0 || height === 0) return;
|
|
1069
|
+
this.webglRenderer?.setSize(width, height);
|
|
1070
|
+
if (this.material) {
|
|
1071
|
+
this.material.uniforms.uResolution.value.set(this.canvas.width, this.canvas.height);
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
this.resizeObserver.observe(this.container);
|
|
1075
|
+
}
|
|
1076
|
+
startRenderLoop() {
|
|
1077
|
+
const animate = () => {
|
|
1078
|
+
this.rafId = requestAnimationFrame(animate);
|
|
1079
|
+
if (!this.material || !this.scene || !this.camera || !this.webglRenderer) return;
|
|
1080
|
+
const delta = this.clock.getDelta();
|
|
1081
|
+
this.material.uniforms.uTime.value += delta;
|
|
1082
|
+
this.webglRenderer.render(this.scene, this.camera);
|
|
1083
|
+
};
|
|
1084
|
+
this.rafId = requestAnimationFrame(animate);
|
|
1085
|
+
}
|
|
1086
|
+
updateUniforms(updates) {
|
|
1087
|
+
if (!this.material) return;
|
|
1088
|
+
const u = this.material.uniforms;
|
|
1089
|
+
if (updates.rotate) {
|
|
1090
|
+
this.rotatorEl.style.setProperty("--pocato-rotate-x", `${updates.rotate.x}deg`);
|
|
1091
|
+
this.rotatorEl.style.setProperty("--pocato-rotate-y", `${updates.rotate.y}deg`);
|
|
1092
|
+
u.uRotate.value.set(
|
|
1093
|
+
updates.rotate.x * (Math.PI / 180),
|
|
1094
|
+
updates.rotate.y * (Math.PI / 180)
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
if (updates.mouse) u.uMouse.value.set(updates.mouse.x, updates.mouse.y);
|
|
1098
|
+
if (updates.move) u.uMove.value.set(updates.move.x, updates.move.y);
|
|
1099
|
+
if (updates.opacity !== void 0) u.uCardOpacity.value = updates.opacity;
|
|
1100
|
+
}
|
|
1101
|
+
updateShader(fragmentShader) {
|
|
1102
|
+
if (!this.material) return;
|
|
1103
|
+
this.material.fragmentShader = resolveIncludes(fragmentShader);
|
|
1104
|
+
this.material.needsUpdate = true;
|
|
1105
|
+
}
|
|
1106
|
+
updateTextures(options) {
|
|
1107
|
+
const loader = new THREE2.TextureLoader();
|
|
1108
|
+
const load = (url, uniform) => {
|
|
1109
|
+
if (!url) return;
|
|
1110
|
+
loader.load(url, (texture) => {
|
|
1111
|
+
this.textures.push(texture);
|
|
1112
|
+
if (this.material) {
|
|
1113
|
+
this.material.uniforms[uniform].value = texture;
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
};
|
|
1117
|
+
if (options.baseImage) load(options.baseImage, "uImgBase");
|
|
1118
|
+
if (options.popupImage) load(options.popupImage, "uImgPopup");
|
|
1119
|
+
if (options.maskImage) load(options.maskImage, "uImgMask");
|
|
1120
|
+
}
|
|
1121
|
+
getContainerRect() {
|
|
1122
|
+
return this.container.getBoundingClientRect();
|
|
1123
|
+
}
|
|
1124
|
+
getRotatorEl() {
|
|
1125
|
+
return this.rotatorEl;
|
|
1126
|
+
}
|
|
1127
|
+
getFrontContentEl() {
|
|
1128
|
+
return this.frontContentEl;
|
|
1129
|
+
}
|
|
1130
|
+
getBackContentEl() {
|
|
1131
|
+
return this.backContentEl;
|
|
1132
|
+
}
|
|
1133
|
+
destroy() {
|
|
1134
|
+
if (this.rafId !== null) cancelAnimationFrame(this.rafId);
|
|
1135
|
+
this.resizeObserver?.disconnect();
|
|
1136
|
+
this.textures.forEach((t) => t.dispose());
|
|
1137
|
+
this.mesh?.geometry.dispose();
|
|
1138
|
+
this.material?.dispose();
|
|
1139
|
+
this.webglRenderer?.dispose();
|
|
1140
|
+
if (this.cardEl.parentNode) {
|
|
1141
|
+
this.cardEl.parentNode.removeChild(this.cardEl);
|
|
1142
|
+
}
|
|
1143
|
+
this.scene = null;
|
|
1144
|
+
this.camera = null;
|
|
1145
|
+
this.webglRenderer = null;
|
|
1146
|
+
this.material = null;
|
|
1147
|
+
this.mesh = null;
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
// src/utils/math.ts
|
|
1152
|
+
var round = (value, precision = 3) => parseFloat(value.toFixed(precision));
|
|
1153
|
+
var clamp = (value, min = 0, max = 100) => Math.min(Math.max(value, min), max);
|
|
1154
|
+
var distance = (x1, y1, x2, y2) => Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
1155
|
+
|
|
1156
|
+
// src/animation/spring.ts
|
|
1157
|
+
var tasks = /* @__PURE__ */ new Set();
|
|
1158
|
+
var rafId = null;
|
|
1159
|
+
function runLoop() {
|
|
1160
|
+
if (tasks.size === 0) {
|
|
1161
|
+
rafId = null;
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
for (const task of tasks) {
|
|
1165
|
+
if (!task()) {
|
|
1166
|
+
tasks.delete(task);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
rafId = requestAnimationFrame(runLoop);
|
|
1170
|
+
}
|
|
1171
|
+
function scheduleTask(task) {
|
|
1172
|
+
tasks.add(task);
|
|
1173
|
+
if (rafId === null) {
|
|
1174
|
+
rafId = requestAnimationFrame(runLoop);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
function tickSpring(ctx, stiffness, damping, precision) {
|
|
1178
|
+
const delta = ctx.target - ctx.val;
|
|
1179
|
+
const velocity = ctx.val - ctx.lastVal;
|
|
1180
|
+
const springForce = stiffness * delta;
|
|
1181
|
+
const damperForce = damping * velocity;
|
|
1182
|
+
const acceleration = (springForce - damperForce) * ctx.invMass;
|
|
1183
|
+
const d = velocity + acceleration;
|
|
1184
|
+
if (Math.abs(d) < precision && Math.abs(delta) < precision) {
|
|
1185
|
+
ctx.val = ctx.target;
|
|
1186
|
+
ctx.lastVal = ctx.target;
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
ctx.lastVal = ctx.val;
|
|
1190
|
+
ctx.val += d;
|
|
1191
|
+
return true;
|
|
1192
|
+
}
|
|
1193
|
+
function spring(initialValue, onChange, opts = {}) {
|
|
1194
|
+
const stiffness = opts.stiffness ?? 0.15;
|
|
1195
|
+
const damping = opts.damping ?? 0.8;
|
|
1196
|
+
const precision = opts.precision ?? 0.01;
|
|
1197
|
+
const ctx = {
|
|
1198
|
+
val: initialValue,
|
|
1199
|
+
lastVal: initialValue,
|
|
1200
|
+
target: initialValue,
|
|
1201
|
+
invMass: 1
|
|
1202
|
+
};
|
|
1203
|
+
let currentResolve = null;
|
|
1204
|
+
const s = {
|
|
1205
|
+
stiffness,
|
|
1206
|
+
damping,
|
|
1207
|
+
precision,
|
|
1208
|
+
get() {
|
|
1209
|
+
return ctx.val;
|
|
1210
|
+
},
|
|
1211
|
+
set(value, updateOpts) {
|
|
1212
|
+
ctx.target = value;
|
|
1213
|
+
if (updateOpts?.hard) {
|
|
1214
|
+
ctx.val = value;
|
|
1215
|
+
ctx.lastVal = value;
|
|
1216
|
+
onChange(value);
|
|
1217
|
+
return Promise.resolve();
|
|
1218
|
+
}
|
|
1219
|
+
if (updateOpts?.soft) {
|
|
1220
|
+
const rate = typeof updateOpts.soft === "number" ? updateOpts.soft : 0.5;
|
|
1221
|
+
ctx.invMass = Math.min(ctx.invMass, rate);
|
|
1222
|
+
}
|
|
1223
|
+
return new Promise((resolve) => {
|
|
1224
|
+
currentResolve = resolve;
|
|
1225
|
+
scheduleTask(() => {
|
|
1226
|
+
const invMassTarget = 1;
|
|
1227
|
+
ctx.invMass = Math.min(ctx.invMass + 0.02, invMassTarget);
|
|
1228
|
+
const moving = tickSpring(ctx, s.stiffness, s.damping, s.precision);
|
|
1229
|
+
onChange(ctx.val);
|
|
1230
|
+
if (!moving) {
|
|
1231
|
+
currentResolve?.();
|
|
1232
|
+
currentResolve = null;
|
|
1233
|
+
}
|
|
1234
|
+
return moving;
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
return s;
|
|
1240
|
+
}
|
|
1241
|
+
function springVec2(initial, onChange, opts = {}) {
|
|
1242
|
+
const state = { x: initial.x, y: initial.y };
|
|
1243
|
+
let dirty = false;
|
|
1244
|
+
const flush = () => {
|
|
1245
|
+
if (dirty) {
|
|
1246
|
+
dirty = false;
|
|
1247
|
+
onChange({ ...state });
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
const sx = spring(initial.x, (v) => {
|
|
1251
|
+
state.x = v;
|
|
1252
|
+
dirty = true;
|
|
1253
|
+
queueMicrotask(flush);
|
|
1254
|
+
}, opts);
|
|
1255
|
+
const sy = spring(initial.y, (v) => {
|
|
1256
|
+
state.y = v;
|
|
1257
|
+
dirty = true;
|
|
1258
|
+
queueMicrotask(flush);
|
|
1259
|
+
}, opts);
|
|
1260
|
+
return {
|
|
1261
|
+
stiffness: opts.stiffness ?? 0.15,
|
|
1262
|
+
damping: opts.damping ?? 0.8,
|
|
1263
|
+
precision: opts.precision ?? 0.01,
|
|
1264
|
+
get() {
|
|
1265
|
+
return { x: sx.get(), y: sy.get() };
|
|
1266
|
+
},
|
|
1267
|
+
async set(value, updateOpts) {
|
|
1268
|
+
await Promise.all([
|
|
1269
|
+
sx.set(value.x, updateOpts),
|
|
1270
|
+
sy.set(value.y, updateOpts)
|
|
1271
|
+
]);
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
function springVec3(initial, onChange, opts = {}) {
|
|
1276
|
+
const state = { x: initial.x, y: initial.y, o: initial.o };
|
|
1277
|
+
let dirty = false;
|
|
1278
|
+
const flush = () => {
|
|
1279
|
+
if (dirty) {
|
|
1280
|
+
dirty = false;
|
|
1281
|
+
onChange({ ...state });
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
const sx = spring(initial.x, (v) => {
|
|
1285
|
+
state.x = v;
|
|
1286
|
+
dirty = true;
|
|
1287
|
+
queueMicrotask(flush);
|
|
1288
|
+
}, opts);
|
|
1289
|
+
const sy = spring(initial.y, (v) => {
|
|
1290
|
+
state.y = v;
|
|
1291
|
+
dirty = true;
|
|
1292
|
+
queueMicrotask(flush);
|
|
1293
|
+
}, opts);
|
|
1294
|
+
const so = spring(initial.o, (v) => {
|
|
1295
|
+
state.o = v;
|
|
1296
|
+
dirty = true;
|
|
1297
|
+
queueMicrotask(flush);
|
|
1298
|
+
}, opts);
|
|
1299
|
+
return {
|
|
1300
|
+
stiffness: opts.stiffness ?? 0.15,
|
|
1301
|
+
damping: opts.damping ?? 0.8,
|
|
1302
|
+
precision: opts.precision ?? 0.01,
|
|
1303
|
+
get() {
|
|
1304
|
+
return { x: sx.get(), y: sy.get(), o: so.get() };
|
|
1305
|
+
},
|
|
1306
|
+
async set(value, updateOpts) {
|
|
1307
|
+
await Promise.all([
|
|
1308
|
+
sx.set(value.x, updateOpts),
|
|
1309
|
+
sy.set(value.y, updateOpts),
|
|
1310
|
+
so.set(value.o, updateOpts)
|
|
1311
|
+
]);
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/interaction/index.ts
|
|
1317
|
+
var SPRING_INTERACT = { stiffness: 0.095, damping: 0.5 };
|
|
1318
|
+
var SPRING_FLIP = { stiffness: 0.03, damping: 0.25 };
|
|
1319
|
+
var THROTTLE_MS = 1e3 / 60;
|
|
1320
|
+
var DBLCLICK_MS = 200;
|
|
1321
|
+
var InteractionHandler = class {
|
|
1322
|
+
constructor(container, callbacks, flippable, initialFlipped) {
|
|
1323
|
+
this.container = container;
|
|
1324
|
+
this.callbacks = callbacks;
|
|
1325
|
+
this.flippable = flippable;
|
|
1326
|
+
this.flipped = false;
|
|
1327
|
+
this.interacting = false;
|
|
1328
|
+
this.boundingRect = { left: 0, top: 0, width: 0, height: 0 };
|
|
1329
|
+
this.interactionOrigin = { x: 0, y: 0 };
|
|
1330
|
+
this.lastThrottleTime = 0;
|
|
1331
|
+
this.clickCount = 0;
|
|
1332
|
+
this.dblClickTimer = null;
|
|
1333
|
+
this.activePointerId = null;
|
|
1334
|
+
this.flipped = initialFlipped;
|
|
1335
|
+
this.springRotate = springVec2({ x: 0, y: 0 }, (v) => {
|
|
1336
|
+
callbacks.onRotate(v);
|
|
1337
|
+
callbacks.onDistFromCenter(clamp(distance(v.x, v.y, 0, 0) / 50, 0, 1));
|
|
1338
|
+
}, SPRING_INTERACT);
|
|
1339
|
+
this.springGlare = springVec3({ x: 50, y: 50, o: 0 }, (v) => {
|
|
1340
|
+
callbacks.onGlare(v);
|
|
1341
|
+
}, SPRING_INTERACT);
|
|
1342
|
+
this.boundPointerDown = this.onPointerDown.bind(this);
|
|
1343
|
+
this.boundPointerMove = this.onPointerMove.bind(this);
|
|
1344
|
+
this.boundPointerUp = this.onPointerUp.bind(this);
|
|
1345
|
+
this.boundClick = this.onClick.bind(this);
|
|
1346
|
+
this.boundTouchHandler = (e) => {
|
|
1347
|
+
e.stopPropagation();
|
|
1348
|
+
};
|
|
1349
|
+
this.container.addEventListener("pointerdown", this.boundPointerDown);
|
|
1350
|
+
this.container.addEventListener("pointermove", this.boundPointerMove);
|
|
1351
|
+
this.container.addEventListener("pointerup", this.boundPointerUp);
|
|
1352
|
+
this.container.addEventListener("pointercancel", this.boundPointerUp);
|
|
1353
|
+
this.container.addEventListener("click", this.boundClick);
|
|
1354
|
+
this.container.addEventListener("touchstart", this.boundTouchHandler, { passive: true });
|
|
1355
|
+
this.container.addEventListener("touchmove", this.boundTouchHandler, { passive: true });
|
|
1356
|
+
}
|
|
1357
|
+
updateRect(rect) {
|
|
1358
|
+
this.boundingRect = rect;
|
|
1359
|
+
}
|
|
1360
|
+
onPointerDown(e) {
|
|
1361
|
+
e.preventDefault();
|
|
1362
|
+
e.stopPropagation();
|
|
1363
|
+
this.interacting = true;
|
|
1364
|
+
this.activePointerId = e.pointerId;
|
|
1365
|
+
this.container.setPointerCapture(e.pointerId);
|
|
1366
|
+
const rect = this.container.getBoundingClientRect();
|
|
1367
|
+
this.boundingRect = { left: rect.left, top: rect.top, width: rect.width, height: rect.height };
|
|
1368
|
+
this.interactionOrigin = { x: e.clientX, y: e.clientY };
|
|
1369
|
+
this.doInteract(e.clientX, e.clientY);
|
|
1370
|
+
}
|
|
1371
|
+
onPointerMove(e) {
|
|
1372
|
+
if (!this.interacting) return;
|
|
1373
|
+
const now = performance.now();
|
|
1374
|
+
if (now - this.lastThrottleTime < THROTTLE_MS) return;
|
|
1375
|
+
this.lastThrottleTime = now;
|
|
1376
|
+
this.doInteract(e.clientX, e.clientY);
|
|
1377
|
+
}
|
|
1378
|
+
onPointerUp(_e) {
|
|
1379
|
+
if (!this.interacting) return;
|
|
1380
|
+
this.interacting = false;
|
|
1381
|
+
if (this.activePointerId !== null) {
|
|
1382
|
+
try {
|
|
1383
|
+
this.container.releasePointerCapture(this.activePointerId);
|
|
1384
|
+
} catch {
|
|
1385
|
+
}
|
|
1386
|
+
this.activePointerId = null;
|
|
1387
|
+
}
|
|
1388
|
+
this.endInteract();
|
|
1389
|
+
}
|
|
1390
|
+
onClick(_e) {
|
|
1391
|
+
if (!this.flippable) return;
|
|
1392
|
+
this.clickCount++;
|
|
1393
|
+
if (this.dblClickTimer) clearTimeout(this.dblClickTimer);
|
|
1394
|
+
this.dblClickTimer = setTimeout(() => {
|
|
1395
|
+
if (this.clickCount >= 2) {
|
|
1396
|
+
this.flip();
|
|
1397
|
+
}
|
|
1398
|
+
this.clickCount = 0;
|
|
1399
|
+
}, DBLCLICK_MS);
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Core interaction math — faithfully ported from Angular move.service.ts doInteract()
|
|
1403
|
+
*/
|
|
1404
|
+
doInteract(clientX, clientY) {
|
|
1405
|
+
const rect = this.boundingRect;
|
|
1406
|
+
if (rect.width === 0 || rect.height === 0) return;
|
|
1407
|
+
const deltaX = clientX - this.interactionOrigin.x;
|
|
1408
|
+
const deltaY = clientY - this.interactionOrigin.y;
|
|
1409
|
+
const touchPosFromLT = {
|
|
1410
|
+
x: clientX - rect.left,
|
|
1411
|
+
y: clientY - rect.top
|
|
1412
|
+
};
|
|
1413
|
+
const touchPercentFromLT = {
|
|
1414
|
+
x: clamp(round(100 / rect.width * touchPosFromLT.x)),
|
|
1415
|
+
y: clamp(round(100 / rect.height * touchPosFromLT.y))
|
|
1416
|
+
};
|
|
1417
|
+
const touchPosFromCenter = {
|
|
1418
|
+
x: rect.width / 2 + deltaX,
|
|
1419
|
+
y: rect.height / 2 + deltaY
|
|
1420
|
+
};
|
|
1421
|
+
const touchPercentFromCenter = {
|
|
1422
|
+
x: clamp(round(100 / rect.width * touchPosFromCenter.x)),
|
|
1423
|
+
y: clamp(round(100 / rect.height * touchPosFromCenter.y))
|
|
1424
|
+
};
|
|
1425
|
+
const touchPercentBasedCenter = {
|
|
1426
|
+
x: touchPercentFromCenter.x - 50,
|
|
1427
|
+
y: touchPercentFromCenter.y - 50
|
|
1428
|
+
};
|
|
1429
|
+
this.callbacks.onMoveDelta({ x: deltaX, y: deltaY });
|
|
1430
|
+
const dpr = window.devicePixelRatio || 1;
|
|
1431
|
+
this.callbacks.onMousePos({
|
|
1432
|
+
x: (clientX - rect.left) * dpr,
|
|
1433
|
+
y: (rect.height - (clientY - rect.top)) * dpr
|
|
1434
|
+
});
|
|
1435
|
+
const rotate = {
|
|
1436
|
+
x: round(touchPercentBasedCenter.x / 3.5),
|
|
1437
|
+
y: round(touchPercentBasedCenter.y / 2)
|
|
1438
|
+
};
|
|
1439
|
+
const glare = {
|
|
1440
|
+
x: round(touchPercentFromLT.x),
|
|
1441
|
+
y: round(touchPercentFromLT.y),
|
|
1442
|
+
o: 1
|
|
1443
|
+
};
|
|
1444
|
+
this.updateSprings(glare, rotate);
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Apply spring targets with flip-aware rotation sign.
|
|
1448
|
+
* Angular: { x: flipped ? 180 - rotate.x : -rotate.x, y: flipped ? -rotate.y : rotate.y }
|
|
1449
|
+
*/
|
|
1450
|
+
updateSprings(glare, rotate) {
|
|
1451
|
+
this.springGlare.stiffness = SPRING_INTERACT.stiffness;
|
|
1452
|
+
this.springGlare.damping = SPRING_INTERACT.damping;
|
|
1453
|
+
this.springGlare.set(glare);
|
|
1454
|
+
this.springRotate.stiffness = SPRING_INTERACT.stiffness;
|
|
1455
|
+
this.springRotate.damping = SPRING_INTERACT.damping;
|
|
1456
|
+
this.springRotate.set({
|
|
1457
|
+
x: this.flipped ? 180 - rotate.x : -rotate.x,
|
|
1458
|
+
y: this.flipped ? -rotate.y : rotate.y
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
endInteract() {
|
|
1462
|
+
this.springRotate.set({ x: this.flipped ? 180 : 0, y: 0 });
|
|
1463
|
+
this.springGlare.set({ x: 50, y: 50, o: 0 });
|
|
1464
|
+
this.callbacks.onMoveDelta({ x: 0, y: 0 });
|
|
1465
|
+
const rect = this.boundingRect;
|
|
1466
|
+
const dpr = window.devicePixelRatio || 1;
|
|
1467
|
+
this.callbacks.onMousePos({
|
|
1468
|
+
x: rect.width / 2 * dpr,
|
|
1469
|
+
y: rect.height / 2 * dpr
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
flip(flipped) {
|
|
1473
|
+
this.flipped = flipped ?? !this.flipped;
|
|
1474
|
+
this.springRotate.stiffness = SPRING_FLIP.stiffness;
|
|
1475
|
+
this.springRotate.damping = SPRING_FLIP.damping;
|
|
1476
|
+
this.springRotate.set({ x: this.flipped ? 180 : 0, y: 0 }).then(() => {
|
|
1477
|
+
this.springRotate.stiffness = SPRING_INTERACT.stiffness;
|
|
1478
|
+
this.springRotate.damping = SPRING_INTERACT.damping;
|
|
1479
|
+
});
|
|
1480
|
+
this.callbacks.onFlip(this.flipped);
|
|
1481
|
+
return this.flipped;
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Wiggle support: start a synthetic interaction.
|
|
1485
|
+
* Matches Angular: startInteraction(0, 0, false)
|
|
1486
|
+
* Sets origin at (0,0) so wiggle coordinates become deltas directly.
|
|
1487
|
+
*/
|
|
1488
|
+
startSyntheticInteraction() {
|
|
1489
|
+
const rect = this.container.getBoundingClientRect();
|
|
1490
|
+
this.boundingRect = { left: rect.left, top: rect.top, width: rect.width, height: rect.height };
|
|
1491
|
+
this.interactionOrigin = { x: 0, y: 0 };
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Feed raw clientX/Y directly to doInteract.
|
|
1495
|
+
* Used by wiggle where coordinates come from DefaultWiggler(0,0,100).
|
|
1496
|
+
*/
|
|
1497
|
+
simulateInteractRaw(clientX, clientY) {
|
|
1498
|
+
this.doInteract(clientX, clientY);
|
|
1499
|
+
}
|
|
1500
|
+
simulateEndInteract() {
|
|
1501
|
+
this.endInteract();
|
|
1502
|
+
}
|
|
1503
|
+
isFlipped() {
|
|
1504
|
+
return this.flipped;
|
|
1505
|
+
}
|
|
1506
|
+
destroy() {
|
|
1507
|
+
if (this.activePointerId !== null) {
|
|
1508
|
+
try {
|
|
1509
|
+
this.container.releasePointerCapture(this.activePointerId);
|
|
1510
|
+
} catch {
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
this.container.removeEventListener("pointerdown", this.boundPointerDown);
|
|
1514
|
+
this.container.removeEventListener("pointermove", this.boundPointerMove);
|
|
1515
|
+
this.container.removeEventListener("pointerup", this.boundPointerUp);
|
|
1516
|
+
this.container.removeEventListener("pointercancel", this.boundPointerUp);
|
|
1517
|
+
this.container.removeEventListener("click", this.boundClick);
|
|
1518
|
+
this.container.removeEventListener("touchstart", this.boundTouchHandler);
|
|
1519
|
+
this.container.removeEventListener("touchmove", this.boundTouchHandler);
|
|
1520
|
+
if (this.dblClickTimer) clearTimeout(this.dblClickTimer);
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
|
|
1524
|
+
// src/animation/wiggle.ts
|
|
1525
|
+
var easeOut = (t) => 1 - (1 - t) ** 3;
|
|
1526
|
+
var easeInOut = (t) => t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
1527
|
+
var easeIn = (t) => t * t * t;
|
|
1528
|
+
function tween(opts) {
|
|
1529
|
+
let cancelled = false;
|
|
1530
|
+
let rafId2 = null;
|
|
1531
|
+
const promise = new Promise((resolve) => {
|
|
1532
|
+
const start = performance.now();
|
|
1533
|
+
const range = opts.to - opts.from;
|
|
1534
|
+
function tick(now) {
|
|
1535
|
+
if (cancelled) {
|
|
1536
|
+
resolve();
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
const elapsed = now - start;
|
|
1540
|
+
const t = Math.min(elapsed / opts.duration, 1);
|
|
1541
|
+
const value = opts.from + range * opts.easing(t);
|
|
1542
|
+
opts.onUpdate(value);
|
|
1543
|
+
if (t < 1) {
|
|
1544
|
+
rafId2 = requestAnimationFrame(tick);
|
|
1545
|
+
} else {
|
|
1546
|
+
resolve();
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
rafId2 = requestAnimationFrame(tick);
|
|
1550
|
+
});
|
|
1551
|
+
const controller = Object.assign(promise, {
|
|
1552
|
+
cancel() {
|
|
1553
|
+
cancelled = true;
|
|
1554
|
+
if (rafId2 !== null) cancelAnimationFrame(rafId2);
|
|
1555
|
+
}
|
|
1556
|
+
});
|
|
1557
|
+
return controller;
|
|
1558
|
+
}
|
|
1559
|
+
function wiggle(cx, cy, radius, onUpdate) {
|
|
1560
|
+
let stopped = false;
|
|
1561
|
+
const cancellers = [];
|
|
1562
|
+
async function run() {
|
|
1563
|
+
let currentRadius = 0;
|
|
1564
|
+
let theta = 0;
|
|
1565
|
+
const expand = tween({
|
|
1566
|
+
from: 0,
|
|
1567
|
+
to: radius,
|
|
1568
|
+
duration: 500,
|
|
1569
|
+
easing: easeOut,
|
|
1570
|
+
onUpdate: (r) => {
|
|
1571
|
+
if (stopped) return;
|
|
1572
|
+
currentRadius = r;
|
|
1573
|
+
onUpdate({ x: cx + r, y: cy }, false);
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
cancellers.push(expand.cancel);
|
|
1577
|
+
await expand;
|
|
1578
|
+
if (stopped) return;
|
|
1579
|
+
const rotate = tween({
|
|
1580
|
+
from: 0,
|
|
1581
|
+
to: Math.PI,
|
|
1582
|
+
duration: 500,
|
|
1583
|
+
easing: easeInOut,
|
|
1584
|
+
onUpdate: (t) => {
|
|
1585
|
+
if (stopped) return;
|
|
1586
|
+
theta = t;
|
|
1587
|
+
onUpdate({
|
|
1588
|
+
x: cx + currentRadius * Math.cos(theta),
|
|
1589
|
+
y: cy + currentRadius * Math.sin(theta)
|
|
1590
|
+
}, false);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
cancellers.push(rotate.cancel);
|
|
1594
|
+
await rotate;
|
|
1595
|
+
if (stopped) return;
|
|
1596
|
+
const shrink = tween({
|
|
1597
|
+
from: currentRadius,
|
|
1598
|
+
to: 0,
|
|
1599
|
+
duration: 300,
|
|
1600
|
+
easing: easeIn,
|
|
1601
|
+
onUpdate: (r) => {
|
|
1602
|
+
if (stopped) return;
|
|
1603
|
+
currentRadius = r;
|
|
1604
|
+
onUpdate({ x: cx + r * Math.cos(theta), y: cy }, false);
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
cancellers.push(shrink.cancel);
|
|
1608
|
+
await shrink;
|
|
1609
|
+
if (!stopped) {
|
|
1610
|
+
onUpdate({ x: cx, y: cy }, true);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
run();
|
|
1614
|
+
return {
|
|
1615
|
+
stop() {
|
|
1616
|
+
stopped = true;
|
|
1617
|
+
cancellers.forEach((c) => c());
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
// src/poca-card.ts
|
|
1623
|
+
var PocaCard = class extends EventEmitter {
|
|
1624
|
+
constructor(container, options) {
|
|
1625
|
+
super();
|
|
1626
|
+
this.wiggleController = null;
|
|
1627
|
+
this.renderer = new Renderer(
|
|
1628
|
+
container,
|
|
1629
|
+
{
|
|
1630
|
+
type: options.type,
|
|
1631
|
+
baseImage: options.baseImage,
|
|
1632
|
+
popupImage: options.popupImage,
|
|
1633
|
+
maskImage: options.maskImage,
|
|
1634
|
+
backImage: options.backImage,
|
|
1635
|
+
customShader: options.customShader
|
|
1636
|
+
},
|
|
1637
|
+
(error) => this.emit("error", error),
|
|
1638
|
+
() => this.emit("ready")
|
|
1639
|
+
);
|
|
1640
|
+
this.interaction = new InteractionHandler(
|
|
1641
|
+
this.renderer.getRotatorEl(),
|
|
1642
|
+
{
|
|
1643
|
+
onRotate: (rotate) => this.renderer.updateUniforms({ rotate }),
|
|
1644
|
+
onGlare: () => {
|
|
1645
|
+
},
|
|
1646
|
+
onMousePos: (pos) => this.renderer.updateUniforms({ mouse: pos }),
|
|
1647
|
+
onMoveDelta: (delta) => this.renderer.updateUniforms({ move: delta }),
|
|
1648
|
+
onDistFromCenter: (_dist) => {
|
|
1649
|
+
},
|
|
1650
|
+
onFlip: (flipped) => this.emit("flip", flipped)
|
|
1651
|
+
},
|
|
1652
|
+
options.flippable ?? false,
|
|
1653
|
+
options.initialFlipped ?? false
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
getFrontContentEl() {
|
|
1657
|
+
return this.renderer.getFrontContentEl();
|
|
1658
|
+
}
|
|
1659
|
+
getBackContentEl() {
|
|
1660
|
+
return this.renderer.getBackContentEl();
|
|
1661
|
+
}
|
|
1662
|
+
flip() {
|
|
1663
|
+
this.interaction.flip();
|
|
1664
|
+
}
|
|
1665
|
+
wiggle() {
|
|
1666
|
+
this.wiggleController?.stop();
|
|
1667
|
+
this.interaction.startSyntheticInteraction();
|
|
1668
|
+
this.wiggleController = wiggle(0, 0, 100, (pos, done) => {
|
|
1669
|
+
if (done) {
|
|
1670
|
+
this.interaction.simulateEndInteract();
|
|
1671
|
+
this.wiggleController = null;
|
|
1672
|
+
} else {
|
|
1673
|
+
this.interaction.simulateInteractRaw(pos.x, pos.y);
|
|
1674
|
+
}
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
reset() {
|
|
1678
|
+
this.wiggleController?.stop();
|
|
1679
|
+
this.wiggleController = null;
|
|
1680
|
+
this.interaction.simulateEndInteract();
|
|
1681
|
+
}
|
|
1682
|
+
updateOptions(options) {
|
|
1683
|
+
if (options.customShader) {
|
|
1684
|
+
this.renderer.updateShader(options.customShader);
|
|
1685
|
+
}
|
|
1686
|
+
if (options.baseImage || options.popupImage || options.maskImage) {
|
|
1687
|
+
this.renderer.updateTextures(options);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
destroy() {
|
|
1691
|
+
this.wiggleController?.stop();
|
|
1692
|
+
this.interaction.destroy();
|
|
1693
|
+
this.renderer.destroy();
|
|
1694
|
+
this.removeAllListeners();
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
export {
|
|
1698
|
+
PocaCard
|
|
1699
|
+
};
|
|
1700
|
+
//# sourceMappingURL=index.js.map
|