diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj
index 2f9c14a..2186c19 100644
--- a/PanoPainter.vcxproj
+++ b/PanoPainter.vcxproj
@@ -404,6 +404,37 @@
Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PanoPainter.vcxproj.filters b/PanoPainter.vcxproj.filters
index 308fe48..eb3cb0a 100644
--- a/PanoPainter.vcxproj.filters
+++ b/PanoPainter.vcxproj.filters
@@ -52,6 +52,12 @@
{7b4f5b47-7a8b-4e4c-9e82-399bb5047ffc}
+
+ {b55fb692-a845-4ef2-9b0e-5b2dd8bd125f}
+
+
+ {a2cacb13-2854-44ee-9511-6cb8ac587428}
+
@@ -543,4 +549,93 @@
extras
+
+
+ shaders
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders\include
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
\ No newline at end of file
diff --git a/data/layout.xml b/data/layout.xml
index e8f59e5..c948d72 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -164,7 +164,7 @@
-
+
@@ -309,7 +309,7 @@
-
+
@@ -355,7 +355,7 @@
-
+
diff --git a/data/shaders/atlas.glsl b/data/shaders/atlas.glsl
new file mode 100644
index 0000000..26951a5
--- /dev/null
+++ b/data/shaders/atlas.glsl
@@ -0,0 +1,21 @@
+[[vertex]]
+uniform mat4 mvp;
+uniform vec2 tof;
+uniform vec2 tsz;
+in vec2 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = tof + uvs * tsz;
+ gl_Position = mvp * vec4(pos, 0.0, 1.0);
+};
+
+[[fragment]]
+uniform sampler2D tex;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ frag = texture(tex, uv);
+};
diff --git a/data/shaders/bake-uv.glsl b/data/shaders/bake-uv.glsl
new file mode 100644
index 0000000..e3d0593
--- /dev/null
+++ b/data/shaders/bake-uv.glsl
@@ -0,0 +1,27 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec3 nor;
+in vec2 uvs;
+out vec3 n;
+out vec3 p;
+void main()
+{
+ n = nor;
+ p = vec3(mvp * pos);
+ gl_Position = vec4(uvs * 2.0 - 1.0, 0.0, 1.0);
+}
+
+[[fragment]]
+uniform int mode;
+in highp vec3 n;
+in highp vec3 p;
+out highp vec3 frag;
+void main()
+{
+ switch(mode)
+ {
+ case 0: frag = normalize(n); break;
+ case 1: frag = p; break;
+ }
+}
diff --git a/data/shaders/checkerboard.glsl b/data/shaders/checkerboard.glsl
new file mode 100644
index 0000000..9d5089f
--- /dev/null
+++ b/data/shaders/checkerboard.glsl
@@ -0,0 +1,24 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+}
+
+[[fragment]]
+uniform bool colorize;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ const mediump vec4 c1 = vec4(1.0, 1.0, 1.0, 1.0);
+ const mediump vec4 c2 = vec4(0.9, 0.9, 0.9, 1.0);
+ mediump vec2 c = floor(fract(uv * 10.0) * 2.0);
+ mediump float alpha = mix(c.x, 1.0 - c.x, c.y);
+ if (colorize) frag = mix(c1, c2, alpha) * vec4(fract(uv.x * 5.0), uv.y, 1.0, 1.0);
+ else frag = mix(c1, c2, alpha);
+}
diff --git a/data/shaders/color-hue.glsl b/data/shaders/color-hue.glsl
new file mode 100644
index 0000000..8bce283
--- /dev/null
+++ b/data/shaders/color-hue.glsl
@@ -0,0 +1,22 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec3 uv;
+void main()
+{
+ gl_Position = mvp * pos;
+ uv = vec3(uvs, pos.w);
+};
+
+[[fragment]]
+#include "include/hsv.glsl"
+uniform mediump vec4 col;
+uniform bool dir; // 0:horizontal, 1:vertical
+in mediump vec3 uv;
+out mediump vec4 frag;
+void main()
+{
+ frag = vec4(hsv2rgb(vec3(dir?uv.y:uv.x, 1.0, 1.0)), 1.0);
+};
+
diff --git a/data/shaders/color-quad.glsl b/data/shaders/color-quad.glsl
new file mode 100644
index 0000000..2f4ea7d
--- /dev/null
+++ b/data/shaders/color-quad.glsl
@@ -0,0 +1,20 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec3 uv;
+void main()
+{
+ gl_Position = mvp * pos;
+ uv = vec3(uvs, pos.w);
+};
+
+[[fragment]]
+#include "include/hsv.glsl"
+uniform mediump vec4 col; // HSV
+in mediump vec3 uv;
+out mediump vec4 frag;
+void main()
+{
+ frag = vec4(hsv2rgb(vec3(col.x, uv.x, 1.0 - uv.y)), 1.0);
+};
diff --git a/data/shaders/color-tri.glsl b/data/shaders/color-tri.glsl
new file mode 100644
index 0000000..febc8a8
--- /dev/null
+++ b/data/shaders/color-tri.glsl
@@ -0,0 +1,21 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec3 uv;
+void main()
+{
+ gl_Position = mvp * pos;
+ uv = vec3(uvs, pos.w);
+};
+
+[[fragment]]
+#include "include/hsv.glsl"
+uniform mediump vec4 col; // in HSV
+in mediump vec3 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump float sat = tan(atan(uv.y, uv.x)) * 0.5 + 0.5;
+ frag = vec4(hsv2rgb(vec3(col.r, sat, uv.x)), 1.0);
+};
diff --git a/data/shaders/color.glsl b/data/shaders/color.glsl
new file mode 100644
index 0000000..1934e6b
--- /dev/null
+++ b/data/shaders/color.glsl
@@ -0,0 +1,16 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+void main()
+{
+ gl_Position = mvp * pos;
+ gl_PointSize = 5.0;
+};
+
+[[fragment]]
+uniform mediump vec4 col;
+out mediump vec4 frag;
+void main()
+{
+ frag = col;
+};
diff --git a/data/shaders/comp-draw.glsl b/data/shaders/comp-draw.glsl
new file mode 100644
index 0000000..db9e5eb
--- /dev/null
+++ b/data/shaders/comp-draw.glsl
@@ -0,0 +1,74 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+#include "include/blur.glsl"
+#include "include/blend.glsl"
+#include "include/blend-stroke.glsl"
+#include "include/color.glsl"
+
+uniform sampler2D tex;
+uniform sampler2D tex_stroke;
+uniform sampler2D tex_mask;
+uniform mediump float alpha;
+uniform mediump float stroke_alpha;
+uniform mediump int blend_mode;
+uniform mediump vec2 resolution;
+uniform bool lock;
+uniform bool mask;
+
+uniform bool use_dual;
+uniform sampler2D tex_dual;
+uniform mediump float dual_alpha;
+uniform mediump int dual_blend_mode;
+
+uniform bool use_pattern;
+uniform sampler2D tex_pattern;
+uniform mediump vec2 pattern_scale;
+uniform mediump float pattern_bright;
+uniform mediump float pattern_contr;
+uniform mediump float pattern_depth;
+uniform mediump vec2 pattern_offset;
+uniform mediump bool pattern_invert;
+uniform mediump int patt_blend_mode;
+
+in mediump vec2 uv;
+out mediump vec4 frag;
+
+void main()
+{
+ mediump vec4 base = texture(tex, uv);
+ mediump vec4 stroke = texture(tex_stroke, uv);
+ if (use_pattern)
+ {
+ mediump vec2 rscale = resolution / vec2(512.0);
+ mediump float patt = texture(tex_pattern, uv * (0.5 / pattern_scale) * rscale + pattern_offset).r;
+ if (pattern_invert)
+ patt = 1.0 - patt;
+ //" patt = patt * pattern_alpha + (1.0 - pattern_alpha);
+ if (pattern_bright != 0.5)
+ patt = brightness1(patt, 1.0 - pattern_bright);
+ if (pattern_contr != 0.5)
+ patt = contrast1(patt, pattern_contr);
+ //" mediump float pa = (1.0 - patt) * pow(pattern_depth, 0.25) + (stroke.a * pattern_depth * 10.0);
+ mediump float pa = pow((1.0 - patt), max(1.0, (1.0 - pattern_depth) * 10.0)) * pow(pattern_depth, 0.25) + (stroke.a * pattern_depth * 5.0);
+ stroke.a = mix(pa * stroke.a, stroke.a, 0.0);
+ }
+ if (use_dual)
+ {
+ mediump vec4 dual = texture(tex_dual, uv);
+ stroke.a = blend_stroke(stroke.a, dual.a * dual_alpha, dual_blend_mode);
+ }
+ stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv).r : stroke.a * stroke_alpha;
+ if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }
+ mediump vec4 blended = blend(base, stroke, blend_mode);
+ frag = vec4(blended.rgb, (lock ? base.a : blended.a) * alpha);
+};
diff --git a/data/shaders/comp-erase.glsl b/data/shaders/comp-erase.glsl
new file mode 100644
index 0000000..a0835dd
--- /dev/null
+++ b/data/shaders/comp-erase.glsl
@@ -0,0 +1,29 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+#include "include/blur.glsl"
+uniform sampler2D tex;
+uniform sampler2D tex_stroke;
+uniform sampler2D tex_mask;
+uniform mediump float alpha;
+uniform mediump float stroke_alpha;
+uniform mediump vec2 resolution;
+uniform bool mask;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump vec4 base = texture(tex, uv);
+ mediump vec4 stroke = texture(tex_stroke, uv);
+ stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv).r : stroke.a * stroke_alpha;
+ frag = vec4(base.rgb, clamp((base.a - stroke.a) * alpha, 0.0, 1.0));
+};
diff --git a/data/shaders/equirect.glsl b/data/shaders/equirect.glsl
new file mode 100644
index 0000000..994e24d
--- /dev/null
+++ b/data/shaders/equirect.glsl
@@ -0,0 +1,29 @@
+[[vertex]]
+#define PI 3.1415926535897932384626433832795
+#define TWO_PI 6.283185307179586476925286766559
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = (vec2(1.0) - uvs + vec2(0.25,0.0)) * vec2(TWO_PI, PI);
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+}
+
+[[fragment]]
+uniform samplerCube tex;
+in highp vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ highp float anglex = uv.x;
+ highp float angley = uv.y;
+ highp float sx = sin(anglex);
+ highp float cx = cos(anglex);
+ highp vec3 dir = vec3(0.0, 0.0, 0.0);
+ dir.x = sin(angley) * cx;
+ dir.y = cos(angley);
+ dir.z = sin(angley) * sx;
+ frag = texture(tex, dir);
+}
diff --git a/data/shaders/font.glsl b/data/shaders/font.glsl
new file mode 100644
index 0000000..f95c801
--- /dev/null
+++ b/data/shaders/font.glsl
@@ -0,0 +1,22 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec2 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos, 0.0, 1.0);
+};
+
+[[fragment]]
+uniform mediump sampler2D tex;
+uniform mediump vec4 col;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump float a = texture(tex, uv).r;
+ frag = vec4(col.rgb, a);
+};
+
diff --git a/data/shaders/include/blend-stroke.glsl b/data/shaders/include/blend-stroke.glsl
new file mode 100644
index 0000000..dd581f8
--- /dev/null
+++ b/data/shaders/include/blend-stroke.glsl
@@ -0,0 +1,9 @@
+mediump float blend_stroke(mediump float base, mediump float stroke, int mode)
+{
+ if (mode == 0) /* normal */ return (base + stroke) * 0.5;
+ else if (mode == 1) /* multiply */ return base * stroke;
+ else if (mode == 2) /* screen */ return 1.0-(1.0-base)*(1.0-stroke);
+ else if (mode == 3) /* color-dodge */ return base/(1.0-stroke);
+ else if (mode == 4) /* overlay */ return mix(2.0*base*stroke, 1.0-2.0*(1.0-base)*(1.0-stroke), floor(base*2.0));
+ else return 1.0;
+}
diff --git a/data/shaders/include/blend.glsl b/data/shaders/include/blend.glsl
new file mode 100644
index 0000000..09a4a6f
--- /dev/null
+++ b/data/shaders/include/blend.glsl
@@ -0,0 +1,20 @@
+mediump vec3 blend_normal(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)
+{ return mix(base.rgb, stroke.rgb, stroke.a/alpha_tot); }
+mediump vec3 blend_multiply(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)
+{ return mix(stroke.rgb, mix(base.rgb, base.rgb*stroke.rgb, stroke.a/alpha_tot), base.a/alpha_tot); }
+mediump vec3 blend_screen(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)
+{ return mix(stroke.rgb, mix(base.rgb, 1.0-(1.0-base.rgb)*(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }
+mediump vec3 blend_colorDodge(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)
+{ return mix(stroke.rgb, mix(base.rgb, base.rgb/(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }
+mediump vec3 blend_overlay(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)
+{ return mix(stroke.rgb, mix(base.rgb, mix(2.0*base.rgb*stroke.rgb, 1.0-2.0*(1.0-base.rgb)*(1.0-stroke.rgb), floor(base.rgb*2.0)), stroke.a/alpha_tot), base.a/alpha_tot); }
+mediump vec4 blend(mediump vec4 base, mediump vec4 stroke, int mode) {
+ mediump float contribution = (1.0 - base.a) * stroke.a;
+ mediump float alpha_tot = base.a + contribution;
+ if (mode == 0) return vec4(blend_normal(base, stroke, alpha_tot), alpha_tot);
+ else if (mode == 1) return vec4(blend_multiply(base, stroke, alpha_tot), alpha_tot);
+ else if (mode == 2) return vec4(blend_screen(base, stroke, alpha_tot), alpha_tot);
+ else if (mode == 3) return vec4(blend_colorDodge(base, stroke, alpha_tot), alpha_tot);
+ else if (mode == 4) return vec4(blend_overlay(base, stroke, alpha_tot), alpha_tot);
+ else return vec4(1.0, 0.0, 0.0, 1.0);
+}
diff --git a/data/shaders/include/blur.glsl b/data/shaders/include/blur.glsl
new file mode 100644
index 0000000..c6f098d
--- /dev/null
+++ b/data/shaders/include/blur.glsl
@@ -0,0 +1,13 @@
+mediump vec4 blur(sampler2D t, mediump vec2 uv)
+{
+ mediump vec4 sum = texture(t, uv);
+ sum += textureOffset(t, uv, ivec2(-1, -1));
+ sum += textureOffset(t, uv, ivec2(-1, 0));
+ sum += textureOffset(t, uv, ivec2(-1, 1));
+ sum += textureOffset(t, uv, ivec2( 0, -1));
+ sum += textureOffset(t, uv, ivec2( 0, 1));
+ sum += textureOffset(t, uv, ivec2( 1, -1));
+ sum += textureOffset(t, uv, ivec2( 1, 0));
+ sum += textureOffset(t, uv, ivec2( 1, 1));
+ return sum / vec4(9.0);
+}
diff --git a/data/shaders/include/color.glsl b/data/shaders/include/color.glsl
new file mode 100644
index 0000000..1d91f10
--- /dev/null
+++ b/data/shaders/include/color.glsl
@@ -0,0 +1,20 @@
+mediump vec3 brightness3(mediump vec3 c, mediump float val)
+{
+ return clamp(c + vec3(val * 2.0 - 1.0), vec3(0), vec3(1));
+}
+mediump vec3 contrast3(mediump vec3 c, mediump float val)
+{
+ val = val * 2.0 - 1.0;
+ mediump float factor = ((259.0 / 255.0) * (val + 1.0)) / (1.0 * ((259.0 / 255.0) - val));
+ return clamp(factor * (c - 0.5) + 0.5, vec3(0), vec3(1));
+}
+mediump float brightness1(mediump float c, mediump float val)
+{
+ return clamp(c + (val * 2.0 - 1.0), 0.0, 1.0);
+}
+mediump float contrast1(mediump float c, mediump float val)
+{
+ val = val * 2.0 - 1.0;
+ mediump float factor = ((259.0 / 255.0) * (val + 1.0)) / (1.0 * ((259.0 / 255.0) - val));
+ return clamp(factor * (c - 0.5) + 0.5, 0.0, 1.0);
+}
diff --git a/data/shaders/include/ext-fb-fetch.glsl b/data/shaders/include/ext-fb-fetch.glsl
new file mode 100644
index 0000000..72401de
--- /dev/null
+++ b/data/shaders/include/ext-fb-fetch.glsl
@@ -0,0 +1,5 @@
+#if defined(GL_EXT_shader_framebuffer_fetch)
+ #extension GL_EXT_shader_framebuffer_fetch : enable
+#elif defined(GL_ARM_shader_framebuffer_fetch)
+ #extension GL_ARM_shader_framebuffer_fetch : enable
+#endif
diff --git a/data/shaders/include/hsv.glsl b/data/shaders/include/hsv.glsl
new file mode 100644
index 0000000..7100be9
--- /dev/null
+++ b/data/shaders/include/hsv.glsl
@@ -0,0 +1,15 @@
+mediump vec3 rgb2hsv(mediump vec3 c)
+{
+ mediump vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
+ mediump vec4 p = mix(vec4(c.bg, k.wz), vec4(c.gb, k.xy), step(c.b, c.g));
+ mediump vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
+ mediump float d = q.x - min(q.w, q.y);
+ mediump float e = 1.0e-10;
+ return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
+}
+mediump vec3 hsv2rgb(mediump vec3 c)
+{
+ mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
+}
diff --git a/data/shaders/include/rand.glsl b/data/shaders/include/rand.glsl
new file mode 100644
index 0000000..5f7caa8
--- /dev/null
+++ b/data/shaders/include/rand.glsl
@@ -0,0 +1,10 @@
+// http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
+highp float rand(mediump vec2 co)
+{
+ highp float a = 12.9898;
+ highp float b = 78.233;
+ highp float c = 43758.5453;
+ highp float dt= dot(co.xy, vec2(a,b));
+ highp float sn= mod(dt, 3.14);
+ return fract(sin(sn) * c);
+}
diff --git a/data/shaders/lambert.glsl b/data/shaders/lambert.glsl
new file mode 100644
index 0000000..26c2302
--- /dev/null
+++ b/data/shaders/lambert.glsl
@@ -0,0 +1,23 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec3 nor;
+in vec2 uvs;
+out vec3 n;
+void main()
+{
+ n = nor;
+ gl_Position = mvp * pos;
+}
+
+[[fragment]]
+uniform mediump vec3 light_dir;
+uniform mediump float ambient;
+in mediump vec3 n;
+out mediump vec4 frag;
+void main()
+{
+ mediump float d = max(0.0, dot(normalize(n), light_dir));
+ frag = vec4(vec3(d) + ambient, 1.0);
+ //frag = vec4(normalize(n) * 0.5 + 0.5, 1.0);
+}
diff --git a/data/shaders/lightmap.glsl b/data/shaders/lightmap.glsl
new file mode 100644
index 0000000..f6be00f
--- /dev/null
+++ b/data/shaders/lightmap.glsl
@@ -0,0 +1,27 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec3 nor;
+in vec2 uvs;
+out vec3 n;
+out vec2 uv;
+void main()
+{
+ n = nor;
+ uv = uvs;
+ gl_Position = mvp * pos;
+}
+
+[[fragment]]
+uniform mediump sampler2D tex;
+uniform mediump vec3 light_dir;
+uniform mediump float ambient;
+in mediump vec3 n;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump float d = max(0.0, dot(normalize(n), normalize(light_dir)));
+ mediump vec4 c = texture(tex, uv);
+ frag = vec4(c.rgb * d + ambient, 1.0);
+}
diff --git a/data/shaders/stroke-instanced.glsl b/data/shaders/stroke-instanced.glsl
new file mode 100644
index 0000000..b3b1977
--- /dev/null
+++ b/data/shaders/stroke-instanced.glsl
@@ -0,0 +1,31 @@
+[[vertex]]
+in vec4 pos;
+in vec2 uvs;
+in mat4 a_mvp;
+in float a_flow;
+out vec3 uv;
+out float alpha;
+void main()
+{
+ uv = vec3(uvs, pos.w);
+ alpha = a_flow;
+ gl_Position = a_mvp * vec4(pos.xyz, 1.0);
+}
+
+[[fragment]]
+uniform mediump sampler2D tex;
+uniform mediump sampler2D tex_pattern;
+uniform mediump vec4 col;
+uniform mediump vec2 resolution;
+uniform mediump vec2 pattern_offset;
+uniform mediump float pattern_alpha;
+in mediump float alpha;
+in mediump vec3 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump vec2 uv2 = gl_FragCoord.st / resolution;
+ mediump float pattern = 1.0 - (texture(tex_pattern, (uv2+pattern_offset)).r * 0.9) * pattern_alpha;
+ mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * pattern;
+ frag = vec4(col.rgb, a);
+}
diff --git a/data/shaders/stroke-preview.glsl b/data/shaders/stroke-preview.glsl
new file mode 100644
index 0000000..c118caf
--- /dev/null
+++ b/data/shaders/stroke-preview.glsl
@@ -0,0 +1,31 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+uniform sampler2D tex;
+uniform mediump vec4 col;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main() {
+ mediump float stroke = 1.0 - texture(tex, uv).r;
+ int zero_count = 0;
+ if (textureOffset(tex, uv, ivec2(-1, -1)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2(-1, 0)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2(-1, +1)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2( 0, -1)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2( 0, 0)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2( 0, +1)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2(+1, -1)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2(+1, 0)).r > 0.99) zero_count++;
+ if (textureOffset(tex, uv, ivec2(+1, +1)).r > 0.99) zero_count++;
+ mediump float edge = (zero_count > 1 && zero_count < 9) ? 0.75 : 0.0;
+ frag = vec4(col.rgb, edge * (1.0 - float(zero_count) / 9.f));
+};
diff --git a/data/shaders/stroke.glsl b/data/shaders/stroke.glsl
new file mode 100644
index 0000000..6fc8dd5
--- /dev/null
+++ b/data/shaders/stroke.glsl
@@ -0,0 +1,93 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+in vec2 uvs2;
+out vec2 uv;
+out vec2 uv_2;
+out float q;
+void main()
+{
+ uv = uvs;
+ uv_2 = uvs2;
+ q = pos.w;
+ gl_Position = mvp * vec4(pos.xy, 0.0, 1.0);
+};
+
+[[fragment]]
+#include "include/ext-fb-fetch.glsl"
+#include "include/rand.glsl"
+#include "include/color.glsl"
+
+uniform mediump sampler2D tex;
+uniform mediump sampler2D tex_bg;
+uniform mediump sampler2D tex_mix;
+uniform mediump vec4 col;
+uniform mediump vec2 resolution;
+uniform mediump float alpha;
+uniform mediump float noise;
+uniform mediump float mix_alpha;
+uniform mediump float wet;
+
+uniform bool use_pattern;
+uniform mediump sampler2D tex_pattern;
+uniform mediump vec2 pattern_scale;
+uniform mediump float pattern_bright;
+uniform mediump float pattern_contr;
+uniform mediump float pattern_depth;
+uniform mediump vec2 pattern_offset;
+uniform mediump bool pattern_invert;
+
+in mediump vec2 uv;
+in mediump vec2 uv_2;
+in mediump float q;
+#if defined(GL_EXT_shader_framebuffer_fetch)
+ inout mediump vec4 frag;
+#else
+ out mediump vec4 frag;
+#endif
+
+void main()
+{
+ mediump vec2 uv2 = gl_FragCoord.st / resolution;
+ mediump float brush_alpha = ( 1.0 - texture(tex, uv/q).r ) * alpha;
+ mediump vec4 fg = vec4(col.rgb, brush_alpha);
+ if (use_pattern)
+ {
+ mediump vec2 rscale = resolution / vec2(512.0);
+ mediump float patt = texture(tex_pattern, uv2 * (0.5 / pattern_scale) * rscale + pattern_offset).r;
+ if (pattern_invert)
+ patt = 1.0 - patt;
+ patt = patt * pattern_depth + (1.0 - pattern_depth);
+ if (pattern_bright != 0.5)
+ patt = brightness1(patt, 1.0 - pattern_bright);
+ if (pattern_contr != 0.5)
+ patt = contrast1(patt, pattern_contr);
+ fg.a = mix(fg.a, fg.a * patt, pattern_depth);
+ }
+
+#if defined(GL_EXT_shader_framebuffer_fetch)
+ mediump vec4 bg = frag;
+#elif defined(GL_ARM_shader_framebuffer_fetch)
+ mediump vec4 bg = gl_LastFragColorARM;
+#else
+ mediump vec4 bg = texture(tex_bg, uv2);
+#endif
+
+ fg.a *= 1.0-rand(uv2+uv)*noise;
+ if (fg.a == 0.0) discard;
+ if (mix_alpha > 0.0)
+ {
+ mediump vec2 uv_mix = uv_2 / q;
+ if (uv_mix.x < 0.0 || uv_mix.x > 1.0 || uv_mix.y < 0.0 || uv_mix.y > 1.0) discard;
+ mediump vec4 mbg = texture(tex_mix, uv_mix);
+ fg.rgb = mix(fg.rgb, mbg.rgb, mix_alpha * mbg.a);
+ }
+ mediump float contribution = (1.0 - bg.a) * fg.a;
+ mediump float alpha_tot = bg.a + contribution;
+ mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);
+ mediump vec4 frag_wet = vec4(rgb, max(bg.a, fg.a * 1.2));
+ mediump vec4 frag_dry = vec4(rgb, alpha_tot);
+ frag = mix(frag_dry, frag_wet, wet);
+};
+
diff --git a/data/shaders/texture-alpha-sep.glsl b/data/shaders/texture-alpha-sep.glsl
new file mode 100644
index 0000000..c43638f
--- /dev/null
+++ b/data/shaders/texture-alpha-sep.glsl
@@ -0,0 +1,28 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+uniform sampler2D tex;
+uniform sampler2D tex_alpha;
+uniform sampler2D tex_bg;
+uniform mediump float alpha;
+uniform bool highlight;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump vec3 rgb = texture(tex, uv).rgb;
+ mediump float a = texture(tex_alpha, uv).a;
+ mediump vec4 c = vec4(rgb, a);
+ frag = highlight ?
+ vec4(clamp(vec3(0.3) + c.rgb, vec3(0.0), vec3(1.0)), c.a) :
+ texture(tex, uv) * vec4(1.0, 1.0, 1.0, alpha);
+};
diff --git a/data/shaders/texture-alpha.glsl b/data/shaders/texture-alpha.glsl
new file mode 100644
index 0000000..938c182
--- /dev/null
+++ b/data/shaders/texture-alpha.glsl
@@ -0,0 +1,24 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+uniform sampler2D tex;
+uniform mediump float alpha;
+uniform bool highlight;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ mediump vec4 c = texture(tex, uv);
+ frag = highlight ?
+ vec4(clamp(vec3(0.3) + c.rgb, vec3(0.0), vec3(1.0)), c.a) :
+ c * vec4(1.0, 1.0, 1.0, alpha);
+};
diff --git a/data/shaders/texture-blend.glsl b/data/shaders/texture-blend.glsl
new file mode 100644
index 0000000..df3fe63
--- /dev/null
+++ b/data/shaders/texture-blend.glsl
@@ -0,0 +1,38 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+#include "include/ext-fb-fetch.glsl"
+#include "include/blend.glsl"
+uniform sampler2D tex;
+uniform sampler2D tex_alpha;
+uniform sampler2D tex_bg;
+uniform mediump float alpha;
+uniform int blend_mode;
+in mediump vec2 uv;
+#if defined(GL_EXT_shader_framebuffer_fetch)
+ inout highp vec4 frag;
+#else
+ out mediump vec4 frag;
+#endif
+void main() {
+#if defined(GL_EXT_shader_framebuffer_fetch)
+ highp vec4 bg = frag;
+#elif defined(GL_ARM_shader_framebuffer_fetch)
+ highp vec4 bg = gl_LastFragColorARM;
+#else
+ mediump vec4 bg = texture(tex_bg, uv);
+#endif
+ mediump vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a);
+ if (fg.a == 0.0) { frag = bg; return; }
+ mediump vec4 blended = blend(bg, fg, blend_mode);
+ frag = vec4(blended.rgb, blended.a * alpha);
+};
diff --git a/data/shaders/texture.glsl b/data/shaders/texture.glsl
new file mode 100644
index 0000000..c1360ae
--- /dev/null
+++ b/data/shaders/texture.glsl
@@ -0,0 +1,19 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+uniform sampler2D tex;
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ frag = texture(tex, uv);
+};
diff --git a/data/shaders/uvs.glsl b/data/shaders/uvs.glsl
new file mode 100644
index 0000000..7e4eebe
--- /dev/null
+++ b/data/shaders/uvs.glsl
@@ -0,0 +1,18 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec2 uvs;
+out vec2 uv;
+void main()
+{
+ uv = uvs;
+ gl_Position = mvp * vec4(pos.xyz, 1.0);
+};
+
+[[fragment]]
+in mediump vec2 uv;
+out mediump vec4 frag;
+void main()
+{
+ frag = vec4(uv, 0.0, 1.0);
+};
diff --git a/data/shaders/vertex-color.glsl b/data/shaders/vertex-color.glsl
new file mode 100644
index 0000000..b166c30
--- /dev/null
+++ b/data/shaders/vertex-color.glsl
@@ -0,0 +1,19 @@
+[[vertex]]
+uniform mat4 mvp;
+in vec4 pos;
+in vec4 col;
+out vec4 c;
+void main()
+{
+ c = col;
+ gl_Position = mvp * pos;
+ gl_PointSize = 5.0;
+};
+
+[[fragment]]
+in mediump vec4 c;
+out mediump vec4 frag;
+void main()
+{
+ frag = c;
+};
diff --git a/src/abr.cpp b/src/abr.cpp
index 004911f..b6285bf 100644
--- a/src/abr.cpp
+++ b/src/abr.cpp
@@ -149,7 +149,7 @@ std::vector> ABR::compute_brushes(const std::string& path
auto patt_uid = wstr2str(patt->value("Idnt"));
b->m_pattern_path = path + "/patterns/" + patt_uid + ".png";
//b->m_brush_thumb_path = path + "/patterns/thumbs/" + patt_uid + ".png";
- b->m_pattern_opacity = p->value("textureDepth") * 0.01f;
+ b->m_pattern_depth = p->value("textureDepth") * 0.01f;
}
ret.push_back(b);
}
diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp
index 20482b0..67d6a8a 100644
--- a/src/app_shaders.cpp
+++ b/src/app_shaders.cpp
@@ -2,673 +2,8 @@
#include "app.h"
#include "shader.h"
-#define SHADER_FUNCTION_BLUR \
- "mediump vec4 blur(sampler2D t, mediump vec2 uv){\n"\
- " mediump vec4 sum = texture(t, uv);\n"\
- " sum += textureOffset(t, uv, ivec2(-1, -1));\n"\
- " sum += textureOffset(t, uv, ivec2(-1, 0));\n"\
- " sum += textureOffset(t, uv, ivec2(-1, 1));\n"\
- " sum += textureOffset(t, uv, ivec2( 0, -1));\n"\
- " sum += textureOffset(t, uv, ivec2( 0, 1));\n"\
- " sum += textureOffset(t, uv, ivec2( 1, -1));\n"\
- " sum += textureOffset(t, uv, ivec2( 1, 0));\n"\
- " sum += textureOffset(t, uv, ivec2( 1, 1));\n"\
- " return sum / vec4(9.0);\n"\
- "}\n"
-
-#define SHADER_FUNCTION_BLEND \
- "mediump vec3 blend_normal(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
- "{ return mix(base.rgb, stroke.rgb, stroke.a/alpha_tot); }\n"\
- "mediump vec3 blend_multiply(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
- "{ return mix(stroke.rgb, mix(base.rgb, base.rgb*stroke.rgb, stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
- "mediump vec3 blend_screen(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
- "{ return mix(stroke.rgb, mix(base.rgb, 1.0-(1.0-base.rgb)*(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
- "mediump vec3 blend_colorDodge(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
- "{ return mix(stroke.rgb, mix(base.rgb, base.rgb/(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
- "mediump vec3 blend_overlay(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
- "{ return mix(stroke.rgb, mix(base.rgb, mix(2.0*base.rgb*stroke.rgb, 1.0-2.0*(1.0-base.rgb)*(1.0-stroke.rgb), floor(base.rgb*2.0)), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
- "mediump vec4 blend(mediump vec4 base, mediump vec4 stroke, int mode) {\n"\
- " mediump float contribution = (1.0 - base.a) * stroke.a;\n"\
- " mediump float alpha_tot = base.a + contribution;\n"\
- " if (mode == 0) return vec4(blend_normal(base, stroke, alpha_tot), alpha_tot);\n"\
- " else if (mode == 1) return vec4(blend_multiply(base, stroke, alpha_tot), alpha_tot);\n"\
- " else if (mode == 2) return vec4(blend_screen(base, stroke, alpha_tot), alpha_tot);\n"\
- " else if (mode == 3) return vec4(blend_colorDodge(base, stroke, alpha_tot), alpha_tot);\n"\
- " else if (mode == 4) return vec4(blend_overlay(base, stroke, alpha_tot), alpha_tot);\n"\
- " else return vec4(1.0, 0.0, 0.0, 1.0);\n"\
- "}\n"
-
-#define SHADER_FUNCTION_BLEND_STROKE \
- "mediump float blend_stroke(mediump float base, mediump float stroke, int mode) {\n"\
- " if (mode == 0) return (base + stroke) * 0.5;\n"\
- " else if (mode == 1) return base * stroke;\n"\
- " else if (mode == 2) return 1.0-(1.0-base)*(1.0-stroke);\n"\
- " else if (mode == 3) return base/(1.0-stroke);\n"\
- " else if (mode == 4) return mix(2.0*base*stroke, 1.0-2.0*(1.0-base)*(1.0-stroke), floor(base*2.0));\n"\
- " else return 1.0;\n"\
- "}\n"
-
-#define SHADER_FUNCTION_HSV \
- "mediump vec3 rgb2hsv(mediump vec3 c) {\n"\
- " mediump vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"\
- " mediump vec4 p = mix(vec4(c.bg, k.wz), vec4(c.gb, k.xy), step(c.b, c.g));\n"\
- " mediump vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"\
- " mediump float d = q.x - min(q.w, q.y);\n"\
- " mediump float e = 1.0e-10;\n"\
- " return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"\
- "}\n"\
- "mediump vec3 hsv2rgb(mediump vec3 c) {\n"\
- " mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"\
- " mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"\
- " return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"\
- "}\n"
-
-#define SHADER_FUNCTION_COLOR \
- "mediump vec3 brightness3(mediump vec3 c, mediump float val) {\n"\
- " return clamp(c + vec3(val * 2.0 - 1.0), vec3(0), vec3(1));\n"\
- "}\n"\
- "mediump vec3 contrast3(mediump vec3 c, mediump float val) {\n"\
- " val = val * 2.0 - 1.0;\n"\
- " mediump float factor = ((259.0 / 255.0) * (val + 1.0)) / (1.0 * ((259.0 / 255.0) - val));\n"\
- " return clamp(factor * (c - 0.5) + 0.5, vec3(0), vec3(1));\n"\
- "}\n"\
- "mediump float brightness1(mediump float c, mediump float val) {\n"\
- " return clamp(c + (val * 2.0 - 1.0), 0.0, 1.0);\n"\
- "}\n"\
- "mediump float contrast1(mediump float c, mediump float val) {\n"\
- " val = val * 2.0 - 1.0;\n"\
- " mediump float factor = ((259.0 / 255.0) * (val + 1.0)) / (1.0 * ((259.0 / 255.0) - val));\n"\
- " return clamp(factor * (c - 0.5) + 0.5, 0.0, 1.0);\n"\
- "}\n"
-
-// http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
-#define SHADER_FUNCTION_RAND \
- "highp float rand(mediump vec2 co)\n"\
- "{\n"\
- " highp float a = 12.9898;\n"\
- " highp float b = 78.233;\n"\
- " highp float c = 43758.5453;\n"\
- " highp float dt= dot(co.xy, vec2(a,b));\n"\
- " highp float sn= mod(dt, 3.14);\n"\
- " return fract(sin(sn) * c);\n"\
- "}\n"
-
-#define SHADER_EXT_FB_FETCH \
- "#if defined(GL_EXT_shader_framebuffer_fetch)\n"\
- " #extension GL_EXT_shader_framebuffer_fetch : enable\n"\
- "#elif defined(GL_ARM_shader_framebuffer_fetch)\n"\
- " #extension GL_ARM_shader_framebuffer_fetch : enable\n"\
- "#endif\n"
-
void App::initShaders()
{
- static const char* shader_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " uv = uvs;\n"
- " gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
- "}\n";
- static const char* shader_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " frag = texture(tex, uv);\n"
- "}\n";
- static const char* shader_blend_f =
- SHADER_VERSION
- SHADER_EXT_FB_FETCH
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex_alpha;\n"
- "uniform sampler2D tex_bg;\n"
- "uniform mediump float alpha;\n"
- "uniform int blend_mode;\n"
- "in mediump vec2 uv;\n"
- "#if defined(GL_EXT_shader_framebuffer_fetch)\n"
- " inout highp vec4 frag;\n"
- "#else\n"
- " out mediump vec4 frag;\n"
- "#endif\n"
- SHADER_FUNCTION_BLEND
- "void main() {\n"
- "#if defined(GL_EXT_shader_framebuffer_fetch)\n"
- " highp vec4 bg = frag;\n"
- "#elif defined(GL_ARM_shader_framebuffer_fetch)\n"
- " highp vec4 bg = gl_LastFragColorARM;\n"
- "#else\n"
- " mediump vec4 bg = texture(tex_bg, uv);\n"
- "#endif\n"
- " mediump vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a);\n"
- " if (fg.a == 0.0) { frag = bg; return; }\n"
- " mediump vec4 blended = blend(bg, fg, blend_mode);\n"
- " frag = vec4(blended.rgb, blended.a * alpha);\n"
- "}\n";
- static const char* shader_uv_f =
- SHADER_VERSION
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " frag = vec4(uv, 0.0, 1.0);\n"
- "}\n";
- // TEXTURE ALPHA
- static const char* shader_alpha_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "uniform mediump float alpha;\n"
- "uniform bool highlight;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump vec4 c = texture(tex, uv);\n"
- " frag = highlight ? \n"
- " vec4(clamp(vec3(0.3) + c.rgb, vec3(0.0), vec3(1.0)), c.a) : \n"
- " c * vec4(1.0, 1.0, 1.0, alpha);\n"
- "}\n";
- // TEXTURE ALPHA SEPARATED
- static const char* shader_alpha_sep_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex_alpha;\n"
- "uniform sampler2D tex_bg;\n"
- "uniform mediump float alpha;\n"
- "uniform bool highlight;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump vec3 rgb = texture(tex, uv).rgb;\n"
- " mediump float a = texture(tex_alpha, uv).a;\n"
- " mediump vec4 c = vec4(rgb, a);\n"
- " frag = highlight ? \n"
- " vec4(clamp(vec3(0.3) + c.rgb, vec3(0.0), vec3(1.0)), c.a) : \n"
- " texture(tex, uv) * vec4(1.0, 1.0, 1.0, alpha);\n"
- "}\n";
- // STROKE PREVIEW
- static const char* shader_stroke_preview_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "uniform mediump vec4 col;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump float stroke = 1.0 - texture(tex, uv).r;\n"
- " int zero_count = 0;\n"
- " if (textureOffset(tex, uv, ivec2(-1, -1)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2(-1, 0)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2(-1, +1)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2( 0, -1)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2( 0, 0)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2( 0, +1)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2(+1, -1)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2(+1, 0)).r > 0.99) zero_count++;\n"
- " if (textureOffset(tex, uv, ivec2(+1, +1)).r > 0.99) zero_count++;\n"
- " mediump float edge = (zero_count > 1 && zero_count < 9) ? 0.75 : 0.0;\n"
- " frag = vec4(col.rgb, edge * (1.0 - float(zero_count) / 9.f));\n"
- "}\n";
- // TEXTURE COMP ERASE
- static const char* shader_comp_erase_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex_stroke;\n"
- "uniform sampler2D tex_mask;\n"
- "uniform mediump float alpha;\n"
- "uniform mediump float stroke_alpha;\n"
- "uniform mediump vec2 resolution;\n"
- "uniform bool mask;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- SHADER_FUNCTION_BLUR
- "void main() {\n"
- " mediump vec4 base = texture(tex, uv);\n"
- " mediump vec4 stroke = texture(tex_stroke, uv);\n"
- " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv).r : stroke.a * stroke_alpha;\n"
- " frag = vec4(base.rgb, clamp((base.a - stroke.a) * alpha, 0.0, 1.0));\n"
- "}\n";
- // TEXTURE COMP DRAW
- static const char* shader_comp_draw_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex_stroke;\n"
- "uniform sampler2D tex_mask;\n"
- "uniform mediump float alpha;\n"
- "uniform mediump float stroke_alpha;\n"
- "uniform mediump int blend_mode;\n"
- "uniform mediump vec2 resolution;\n"
- "uniform bool lock;\n"
- "uniform bool mask;\n"
-
- "uniform bool use_dual;\n"
- "uniform sampler2D tex_dual;\n"
- "uniform mediump float dual_alpha;\n"
- "uniform mediump int dual_blend_mode;\n"
-
- "uniform bool use_pattern;\n"
- "uniform sampler2D tex_pattern;\n"
- "uniform mediump float pattern_alpha;\n"
- "uniform mediump vec2 pattern_scale;\n"
- "uniform mediump float pattern_bright;\n"
- "uniform mediump float pattern_contr;\n"
- "uniform mediump vec2 pattern_offset;\n"
- "uniform mediump bool pattern_invert;\n"
-
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- SHADER_FUNCTION_BLUR
- SHADER_FUNCTION_BLEND
- SHADER_FUNCTION_BLEND_STROKE
- SHADER_FUNCTION_COLOR
- "void main() {\n"
- " mediump vec4 base = texture(tex, uv);\n"
- " mediump vec4 stroke = texture(tex_stroke, uv);\n"
- " if (use_pattern){\n"
- " mediump vec2 rscale = resolution / vec2(512.0);\n"
- " mediump float patt = texture(tex_pattern, uv * (0.5 / pattern_scale) * rscale + pattern_offset).r;\n"
- " if (pattern_invert)\n"
- " patt = 1.0 - patt;\n"
- " if (pattern_bright != 0.5)\n"
- " patt = brightness1(patt, 1.0 - pattern_bright);\n"
- " if (pattern_contr != 0.5)\n"
- " patt = contrast1(patt, pattern_contr);\n"
- " stroke.a = mix(stroke.a, stroke.a * patt, pattern_alpha);\n"
- " }\n"
- " if (use_dual){\n"
- " mediump vec4 dual = texture(tex_dual, uv);\n"
- " stroke.a = blend_stroke(stroke.a, dual.a * dual_alpha, dual_blend_mode);\n"
- " }\n"
- " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv).r : stroke.a * stroke_alpha;\n"
- " if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n"
- " mediump vec4 blended = blend(base, stroke, blend_mode);\n"
- " frag = vec4(blended.rgb, (lock ? base.a : blended.a) * alpha);\n"
- "}\n";
-
- // TEXTURE ATLAS
- static const char* shader_atlas_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "uniform vec2 tof;\n"
- "uniform vec2 tsz;\n"
- "in vec2 pos;\n"
- "in vec2 uvs;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " uv = tof + uvs * tsz;\n"
- " gl_Position = mvp * vec4(pos, 0.0, 1.0);\n"
- "}\n";
- static const char* shader_atlas_f =
- SHADER_VERSION
- "uniform sampler2D tex;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " frag = texture(tex, uv);\n"
- "}\n";
-
- // SOLID COLOR
- static const char* shader_color_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "void main() {\n"
- " gl_Position = mvp * pos;\n"
- " gl_PointSize = 5.0;\n"
- "}\n";
- static const char* shader_color_f =
- SHADER_VERSION
- "uniform mediump vec4 col;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " frag = col;\n"
- "}\n";
-
- // COLOR QUAD
- static const char* shader_color_quad_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "out vec3 uv;\n"
- "void main() {\n"
- " gl_Position = mvp * pos;\n"
- " uv = vec3(uvs, pos.w);\n"
- "}\n";
- static const char* shader_color_quad_f =
- SHADER_VERSION
- "uniform mediump vec4 col; // HSV\n"
- "in mediump vec3 uv;\n"
- "out mediump vec4 frag;\n"
- SHADER_FUNCTION_HSV
- "void main() {\n"
- " frag = vec4(hsv2rgb(vec3(col.x, uv.x, 1.0 - uv.y)), 1.0);\n"
- "}\n";
- // COLOR TRI
- static const char* shader_color_tri_f =
- SHADER_VERSION
- "uniform mediump vec4 col;\n" // in HSV
- "in mediump vec3 uv;\n"
- "out mediump vec4 frag;\n"
- SHADER_FUNCTION_HSV
- "void main() {\n"
- " mediump float sat = tan(atan(uv.y, uv.x)) * 0.5 + 0.5;\n"
- " frag = vec4(hsv2rgb(vec3(col.r, sat, uv.x)), 1.0);\n"
- "}\n";
-
- // HUE
- static const char* shader_color_hue_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "out vec3 uv;\n"
- "void main() {\n"
- " gl_Position = mvp * pos;\n"
- " uv = vec3(uvs, pos.w);\n"
- "}\n";
- static const char* shader_color_hue_f =
- SHADER_VERSION
- "uniform mediump vec4 col;\n"
- "uniform bool dir;\n" // 0:horizontal, 1:vertical
- "in mediump vec3 uv;\n"
- "out mediump vec4 frag;\n"
- SHADER_FUNCTION_HSV
- "void main() {\n"
- " frag = vec4(hsv2rgb(vec3(dir?uv.y:uv.x, 1.0, 1.0)), 1.0);\n"
- "}\n";
-
- // FONT
- static const char* shader_font_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec2 pos;\n"
- "in vec2 uvs;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " uv = uvs;\n"
- " gl_Position = mvp * vec4(pos, 0.0, 1.0);\n"
- "}\n";
- static const char* shader_font_f =
- SHADER_VERSION
- "uniform mediump sampler2D tex;\n"
- "uniform mediump vec4 col;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump float a = texture(tex, uv).r;\n"
- " frag = vec4(col.rgb, a);\n"
- "}\n";
-
- // STROKE
- static const char* shader_stroke_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "in vec2 uvs2;\n"
- "out vec2 uv;\n"
- "out vec2 uv_2;\n"
- "out float q;\n"
- "void main() {\n"
- " uv = uvs;\n"
- " uv_2 = uvs2;\n"
- " q = pos.w;\n"
- " gl_Position = mvp * vec4(pos.xy, 0.0, 1.0);\n"
- "}\n";
- static const char* shader_stroke_f =
- SHADER_VERSION
- SHADER_EXT_FB_FETCH
- "uniform mediump sampler2D tex;\n"
- "uniform mediump sampler2D tex_bg;\n"
- "uniform mediump sampler2D tex_mix;\n"
- "uniform mediump vec4 col;\n"
- "uniform mediump vec2 resolution;\n"
- "uniform mediump float alpha;\n"
- "uniform mediump float noise;\n"
- "uniform mediump float mix_alpha;\n"
- "uniform mediump float wet;\n"
-
- "uniform bool use_pattern;\n"
- "uniform mediump sampler2D tex_pattern;\n"
- "uniform mediump float pattern_alpha;\n"
- "uniform mediump vec2 pattern_scale;\n"
- "uniform mediump float pattern_bright;\n"
- "uniform mediump float pattern_contr;\n"
- "uniform mediump vec2 pattern_offset;\n"
- "uniform mediump bool pattern_invert;\n"
-
- "in mediump vec2 uv;\n"
- "in mediump vec2 uv_2;\n"
- "in mediump float q;\n"
- "#if defined(GL_EXT_shader_framebuffer_fetch)\n"
- " inout mediump vec4 frag;\n"
- "#else\n"
- " out mediump vec4 frag;\n"
- "#endif\n"
- SHADER_FUNCTION_RAND
- SHADER_FUNCTION_COLOR
- "void main() {\n"
- " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
- " mediump float brush_alpha = ( 1.0 - texture(tex, uv/q).r ) * alpha;\n"
- " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
- " if (use_pattern){\n"
- " mediump vec2 rscale = resolution / vec2(512.0);\n"
- " mediump float patt = texture(tex_pattern, uv2 * (0.5 / pattern_scale) * rscale + pattern_offset).r;\n"
- " if (pattern_invert)\n"
- " patt = 1.0 - patt;\n"
- " if (pattern_bright != 0.5)\n"
- " patt = brightness1(patt, 1.0 - pattern_bright);\n"
- " if (pattern_contr != 0.5)\n"
- " patt = contrast1(patt, pattern_contr);\n"
- " fg.a = mix(fg.a, fg.a * patt, pattern_alpha);\n"
- " }\n"
- "#if defined(GL_EXT_shader_framebuffer_fetch)\n"
- " mediump vec4 bg = frag;\n"
- "#elif defined(GL_ARM_shader_framebuffer_fetch)\n"
- " mediump vec4 bg = gl_LastFragColorARM;\n"
- "#else\n"
- " mediump vec4 bg = texture(tex_bg, uv2);\n"
- "#endif\n"
- " fg.a *= 1.0-rand(uv2+uv)*noise;\n"
- " if (fg.a == 0.0) discard;\n"
- " if (mix_alpha > 0.0){\n"
- " mediump vec2 uv_mix = uv_2 / q;\n"
- " if (uv_mix.x < 0.0 || uv_mix.x > 1.0 || uv_mix.y < 0.0 || uv_mix.y > 1.0) discard;\n"
- " mediump vec4 mbg = texture(tex_mix, uv_mix);\n"
- " fg.rgb = mix(fg.rgb, mbg.rgb, mix_alpha * mbg.a);\n"
- " }\n"
- " mediump float contribution = (1.0 - bg.a) * fg.a;\n"
- " mediump float alpha_tot = bg.a + contribution;\n"
- " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
- " mediump vec4 frag_wet = vec4(rgb, max(bg.a, fg.a * 1.2));\n"
- " mediump vec4 frag_dry = vec4(rgb, alpha_tot);\n"
- " frag = mix(frag_dry, frag_wet, wet);\n"
- "}\n";
-
- static const char* shader_checkerboard_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " uv = uvs;\n"
- " gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
- "}\n";
- static const char* shader_checkerboard_f =
- SHADER_VERSION
- "uniform bool colorize;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " const mediump vec4 c1 = vec4(1.0, 1.0, 1.0, 1.0);\n"
- " const mediump vec4 c2 = vec4(0.9, 0.9, 0.9, 1.0);\n"
- " mediump vec2 c = floor(fract(uv * 10.0) * 2.0);\n"
- " mediump float alpha = mix(c.x, 1.0 - c.x, c.y);\n"
- " if (colorize) frag = mix(c1, c2, alpha) * vec4(fract(uv.x * 5.0), uv.y, 1.0, 1.0);\n"
- " else frag = mix(c1, c2, alpha);\n"
- "}\n";
-
- static const char* shader_equirect_v =
- SHADER_VERSION
- "#define PI 3.1415926535897932384626433832795\n"
- "#define TWO_PI 6.283185307179586476925286766559\n"
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " uv = (vec2(1.0) - uvs + vec2(0.25,0.0)) * vec2(TWO_PI, PI);\n"
- " gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
- "}\n";
- static const char* shader_equirect_f =
- SHADER_VERSION
- "uniform samplerCube tex;\n"
- "in highp vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " highp float anglex = uv.x;\n"
- " highp float angley = uv.y;\n"
- " highp float sx = sin(anglex);\n"
- " highp float cx = cos(anglex);\n"
- " highp vec3 dir = vec3(0.0, 0.0, 0.0);\n"
- " dir.x = sin(angley) * cx;\n"
- " dir.y = cos(angley);\n"
- " dir.z = sin(angley) * sx;\n"
- " frag = texture(tex, dir);\n"
- "}\n";
-
- // STROKE - INSTANCED
- static const char* shader_stroke_inst_v =
- SHADER_VERSION
- "in vec4 pos;\n"
- "in vec2 uvs;\n"
- "in mat4 a_mvp;\n"
- "in float a_flow;\n"
- "out vec3 uv;\n"
- "out float alpha;\n"
- "void main() {\n"
- " uv = vec3(uvs, pos.w);\n"
- " alpha = a_flow;\n"
- " gl_Position = a_mvp * vec4(pos.xyz, 1.0);\n"
- "}\n";
- static const char* shader_stroke_inst_f =
- SHADER_VERSION
- "uniform mediump sampler2D tex;\n"
- "uniform mediump sampler2D tex_pattern;\n"
- "uniform mediump vec4 col;\n"
- "uniform mediump vec2 resolution;\n"
- "uniform mediump vec2 pattern_offset;\n"
- "uniform mediump float pattern_alpha;\n"
- "in mediump float alpha;\n"
- "in mediump vec3 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
- " mediump float pattern = 1.0 - (texture(tex_pattern, (uv2+pattern_offset)).r * 0.9) * pattern_alpha;\n"
- " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * pattern;\n"
- " frag = vec4(col.rgb, a);\n"
- "}\n";
-
- // VERTEX COLOR
- static const char* shader_vertcol_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec4 col;\n"
- "out vec4 c;\n"
- "void main() {\n"
- " c = col;\n"
- " gl_Position = mvp * pos;\n"
- " gl_PointSize = 5.0;\n"
- "}\n";
- static const char* shader_vertcol_f =
- SHADER_VERSION
- "in mediump vec4 c;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " frag = c;\n"
- "}\n";
-
- // LAMBERT
- static const char* shader_lambert_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec3 nor;\n"
- "in vec2 uvs;\n"
- "out vec3 n;\n"
- "void main() {\n"
- " n = nor;\n"
- " gl_Position = mvp * pos;\n"
- "}\n";
- static const char* shader_lambert_f =
- SHADER_VERSION
- "uniform mediump vec3 light_dir;\n"
- "uniform mediump float ambient;\n"
- "in mediump vec3 n;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump float d = max(0.0, dot(normalize(n), light_dir));\n"
- " frag = vec4(vec3(d) + ambient, 1.0);\n"
- //" frag = vec4(normalize(n) * 0.5 + 0.5, 1.0);\n"
- "}\n";
-
- // LAMBERT LIGHTMAP
- static const char* shader_lambert_lightmap_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec3 nor;\n"
- "in vec2 uvs;\n"
- "out vec3 n;\n"
- "out vec2 uv;\n"
- "void main() {\n"
- " n = nor;\n"
- " uv = uvs;\n"
- " gl_Position = mvp * pos;\n"
- "}\n";
- static const char* shader_lambert_lightmap_f =
- SHADER_VERSION
- "uniform mediump sampler2D tex;\n"
- "uniform mediump vec3 light_dir;\n"
- "uniform mediump float ambient;\n"
- "in mediump vec3 n;\n"
- "in mediump vec2 uv;\n"
- "out mediump vec4 frag;\n"
- "void main() {\n"
- " mediump float d = max(0.0, dot(normalize(n), normalize(light_dir)));\n"
- " mediump vec4 c = texture(tex, uv);\n"
- " frag = vec4(c.rgb * d + ambient, 1.0);\n"
- "}\n";
-
- // BAKE UVS
- static const char* shader_bakeuv_v =
- SHADER_VERSION
- "uniform mat4 mvp;\n"
- "in vec4 pos;\n"
- "in vec3 nor;\n"
- "in vec2 uvs;\n"
- "out vec3 n;\n"
- "out vec3 p;\n"
- "void main() {\n"
- " n = nor;\n"
- " p = vec3(mvp * pos);\n"
- " gl_Position = vec4(uvs * 2.0 - 1.0, 0.0, 1.0);\n"
- "}\n";
- static const char* shader_bakeuv_f =
- SHADER_VERSION
- "uniform int mode;\n"
- "in highp vec3 n;\n"
- "in highp vec3 p;\n"
- "out highp vec3 frag;\n"
- "void main() {\n"
- " switch(mode) {\n"
- " case 0: frag = normalize(n); break;\n"
- " case 1: frag = p; break;\n"
- " }\n"
- "}\n";
GLint n_exts;
glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
@@ -684,49 +19,49 @@ void App::initShaders()
LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled");
LOG("initializing shaders");
- if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
+ if (!ShaderManager::load(kShader::Texture, "data/shaders/texture.glsl"))
LOG("Failed to create shader Texture");
- if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f))
+ if (!ShaderManager::load(kShader::TextureAlpha, "data/shaders/texture-alpha.glsl"))
LOG("Failed to create shader TextureAlpha");
- if (!ShaderManager::create(kShader::TextureAlphaSep, shader_v, shader_alpha_sep_f))
+ if (!ShaderManager::load(kShader::TextureAlphaSep, "data/shaders/texture-alpha-sep.glsl"))
LOG("Failed to create shader TextureAlphaSep");
- if (!ShaderManager::create(kShader::TextureBlend, shader_v, shader_blend_f))
+ if (!ShaderManager::load(kShader::TextureBlend, "data/shaders/texture-blend.glsl"))
LOG("Failed to create shader TextureBlend");
- if (!ShaderManager::create(kShader::StrokePreview, shader_v, shader_stroke_preview_f))
+ if (!ShaderManager::load(kShader::StrokePreview, "data/shaders/stroke-preview.glsl"))
LOG("Failed to create shader StrokePreview");
- if (!ShaderManager::create(kShader::CompErase, shader_v, shader_comp_erase_f))
+ if (!ShaderManager::load(kShader::CompErase, "data/shaders/comp-erase.glsl"))
LOG("Failed to create shader CompErase");
- if (!ShaderManager::create(kShader::CompDraw, shader_v, shader_comp_draw_f))
+ if (!ShaderManager::load(kShader::CompDraw, "data/shaders/comp-draw.glsl"))
LOG("Failed to create shader CompDraw");
- if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f))
+ if (!ShaderManager::load(kShader::Color, "data/shaders/color.glsl"))
LOG("Failed to create shader Color");
- if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f))
+ if (!ShaderManager::load(kShader::ColorQuad, "data/shaders/color-quad.glsl"))
LOG("Failed to create shader ColorQuad");
- if (!ShaderManager::create(kShader::ColorTri, shader_color_quad_v, shader_color_tri_f))
+ if (!ShaderManager::load(kShader::ColorTri, "data/shaders/color-tri.glsl"))
LOG("Failed to create shader ColorTri");
- if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f))
+ if (!ShaderManager::load(kShader::ColorHue, "data/shaders/color-hue.glsl"))
LOG("Failed to create shader ColorHue");
- if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f))
+ if (!ShaderManager::load(kShader::UVs, "data/shaders/uvs.glsl"))
LOG("Failed to create shader UVs");
- if (!ShaderManager::create(kShader::Font, shader_font_v, shader_font_f))
+ if (!ShaderManager::load(kShader::Font, "data/shaders/font.glsl"))
LOG("Failed to create shader Font");
- if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f))
+ if (!ShaderManager::load(kShader::Atlas, "data/shaders/atlas.glsl"))
LOG("Failed to create shader Atlas");
- if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f))
+ if (!ShaderManager::load(kShader::Stroke, "data/shaders/stroke.glsl"))
LOG("Failed to create shader Stroke");
- if (!ShaderManager::create(kShader::Checkerboard, shader_checkerboard_v, shader_checkerboard_f))
+ if (!ShaderManager::load(kShader::Checkerboard, "data/shaders/checkerboard.glsl"))
LOG("Failed to create shader Checkerboard");
- if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f))
+ if (!ShaderManager::load(kShader::Equirect, "data/shaders/equirect.glsl"))
LOG("Failed to create shader Equirect");
- if (!ShaderManager::create(kShader::BrushStroke, shader_stroke_inst_v, shader_stroke_inst_f))
+ if (!ShaderManager::load(kShader::BrushStroke, "data/shaders/stroke-instanced.glsl"))
LOG("Failed to create shader BrushStroke");
- if (!ShaderManager::create(kShader::VertexColor, shader_vertcol_v, shader_vertcol_f))
+ if (!ShaderManager::load(kShader::VertexColor, "data/shaders/vertex-color.glsl"))
LOG("Failed to create shader VertexColor");
- if (!ShaderManager::create(kShader::Lambert, shader_lambert_v, shader_lambert_f))
+ if (!ShaderManager::load(kShader::Lambert, "data/shaders/lambert.glsl"))
LOG("Failed to create shader Lambert");
- if (!ShaderManager::create(kShader::LambertLightmap, shader_lambert_lightmap_v, shader_lambert_lightmap_f))
+ if (!ShaderManager::load(kShader::LambertLightmap, "data/shaders/lightmap.glsl"))
LOG("Failed to create shader LambertLightmap");
- if (!ShaderManager::create(kShader::BakeUV, shader_bakeuv_v, shader_bakeuv_f))
+ if (!ShaderManager::load(kShader::BakeUV, "data/shaders/bake-uv.glsl"))
LOG("Failed to create shader BakeUV");
LOG("shaders initialized");
}
diff --git a/src/app_vr.cpp b/src/app_vr.cpp
index 4ef6408..c8276b8 100644
--- a/src/app_vr.cpp
+++ b/src/app_vr.cpp
@@ -100,7 +100,6 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
ShaderManager::u_vec2(kShaderUniform::Resolution, canvas->m_canvas->m_size);
ShaderManager::u_int(kShaderUniform::TexPattern, 3);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity);
ShaderManager::u_int(kShaderUniform::Lock, canvas->m_canvas->m_layers[layer_index].m_alpha_locked);
ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
@@ -112,6 +111,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset);
glActiveTexture(GL_TEXTURE0);
diff --git a/src/brush.h b/src/brush.h
index 1fe1ef3..ec6e6d2 100644
--- a/src/brush.h
+++ b/src/brush.h
@@ -30,7 +30,6 @@ public:
float m_tip_angle = 0;
float m_tip_angle_delay = 0;
float m_tip_mix = 0;
- float m_pattern_opacity = 1.f;
float m_tip_wet = 0;
float m_tip_noise = 0;
float m_tip_hue = 0;
@@ -78,6 +77,7 @@ public:
float m_pattern_brightness = 0.5f;
float m_pattern_contrast = 0.5f;
bool m_pattern_rand_offset = false;
+ float m_pattern_depth = 1.f;
bool load_tip(const std::string& path, const std::string& thumb);
bool load_dual(const std::string& path, const std::string& thumb);
diff --git a/src/canvas.cpp b/src/canvas.cpp
index 244ebdb..c389c32 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -249,7 +249,6 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
ShaderManager::u_int(kShaderUniform::TexPattern, 3);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Lock, false/*m_layers[layer_index].m_alpha_locked*/);
ShaderManager::u_int(kShaderUniform::Mask, false/*m_smask_active*/);
@@ -496,11 +495,11 @@ void Canvas::stroke_draw()
ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer
//ShaderManager::u_int(kShaderUniform::TexMixA, 4); // mixer
ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height });
- ShaderManager::u_float(kShaderUniform::PatternAlpha, brush->m_pattern_opacity);
ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale);
ShaderManager::u_float(kShaderUniform::PatternInvert, brush->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, brush->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, brush->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, brush->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, m_pattern_offset);
ShaderManager::u_int(kShaderUniform::UsePattern, brush->m_pattern_enabled && brush->m_pattern_eachsample);
ShaderManager::u_float(kShaderUniform::MixAlpha, brush->m_tip_mix);
@@ -799,7 +798,6 @@ void Canvas::stroke_commit()
ShaderManager::u_int(kShaderUniform::TexPattern, 4);
ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode);
@@ -811,6 +809,7 @@ void Canvas::stroke_commit()
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, m_pattern_offset);
ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity);
diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp
index 18e6af5..9770250 100644
--- a/src/node_canvas.cpp
+++ b/src/node_canvas.cpp
@@ -216,7 +216,6 @@ void NodeCanvas::draw()
ShaderManager::u_vec2(kShaderUniform::Resolution, Canvas::I->m_size);
ShaderManager::u_int(kShaderUniform::TexPattern, 4);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
@@ -229,6 +228,7 @@ void NodeCanvas::draw()
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset);
ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity);
diff --git a/src/node_checkbox.cpp b/src/node_checkbox.cpp
index d13bb58..25031f8 100644
--- a/src/node_checkbox.cpp
+++ b/src/node_checkbox.cpp
@@ -108,6 +108,14 @@ void NodeCheckBox::set_icon(const std::string& icon_path)
update_icon();
}
+void NodeCheckBox::set_value(bool checked, bool trigger_event)
+{
+ this->checked = checked;
+ update_icon();
+ if (trigger_event && on_value_changed)
+ on_value_changed(this, checked);
+}
+
void NodeCheckBox::update_icon()
{
if (m_icon_path.empty())
diff --git a/src/node_checkbox.h b/src/node_checkbox.h
index 9b45b88..8991170 100644
--- a/src/node_checkbox.h
+++ b/src/node_checkbox.h
@@ -20,6 +20,6 @@ public:
virtual void draw() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
void set_icon(const std::string& icon_path);
- void set_value(bool checked) { this->checked = checked; update_icon(); }
+ void set_value(bool checked, bool trigger_event = false);
void update_icon();
};
diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp
index ceb4d4b..ee21bfa 100644
--- a/src/node_panel_brush.cpp
+++ b/src/node_panel_brush.cpp
@@ -538,79 +538,80 @@ bool NodePanelBrushPreset::save()
fwrite(&h, sizeof(h), 1, fp);
for (int ci = 0; ci < m_container->m_children.size(); ci++)
{
- auto b = static_cast(m_container->get_child_at(ci));
+ auto bpi = static_cast(m_container->get_child_at(ci));
+ auto& b = bpi->m_brush;
item_t i;
- i.m_name_len = b->m_brush->m_name.size();
- i.m_brush_path_len = b->m_brush->m_brush_path.size();
- i.m_brush_thumb_path_len = b->m_brush->m_brush_thumb_path.size();
- i.m_dual_path_len = b->m_brush->m_brush_path.size();
- i.m_dual_thumb_path_len = b->m_brush->m_brush_thumb_path.size();
- i.m_stencil_path_len = b->m_brush->m_pattern_path.size();
- i.m_stencil_thumb_path_len = b->m_brush->m_texture_thumb_path.size();
- i.m_tip_color = b->m_brush->m_tip_color;
- i.m_tip_size = b->m_brush->m_tip_size;
- i.m_tip_spacing = b->m_brush->m_tip_spacing;
- i.m_tip_flow = b->m_brush->m_tip_flow;
- i.m_tip_opacity = b->m_brush->m_tip_opacity;
- i.m_tip_angle = b->m_brush->m_tip_angle;
- i.m_tip_angle_delay = b->m_brush->m_tip_angle_delay;
- i.m_tip_mix = b->m_brush->m_tip_mix;
- i.m_pattern_opacity = b->m_brush->m_pattern_opacity;
- i.m_tip_wet = b->m_brush->m_tip_wet;
- i.m_tip_noise = b->m_brush->m_tip_noise;
- i.m_tip_hue = b->m_brush->m_tip_hue;
- i.m_tip_sat = b->m_brush->m_tip_sat;
- i.m_tip_val = b->m_brush->m_tip_val;
- i.m_tip_angle_follow = b->m_brush->m_tip_angle_follow;
- i.m_tip_flow_pressure = b->m_brush->m_tip_flow_pressure;
- i.m_tip_size_pressure = b->m_brush->m_tip_size_pressure;
- i.m_jitter_scale = b->m_brush->m_jitter_scale;
- i.m_jitter_angle = b->m_brush->m_jitter_angle;
- i.m_jitter_spread = b->m_brush->m_jitter_spread;
- i.m_jitter_flow = b->m_brush->m_jitter_flow;
- i.m_jitter_hue = b->m_brush->m_jitter_hue;
- i.m_jitter_sat = b->m_brush->m_jitter_sat;
- i.m_jitter_val = b->m_brush->m_jitter_val;
- i.m_blend_mode = b->m_brush->m_blend_mode;
+ i.m_name_len = b->m_name.size();
+ i.m_brush_path_len = b->m_brush_path.size();
+ i.m_brush_thumb_path_len = b->m_brush_thumb_path.size();
+ i.m_dual_path_len = b->m_brush_path.size();
+ i.m_dual_thumb_path_len = b->m_brush_thumb_path.size();
+ i.m_stencil_path_len = b->m_pattern_path.size();
+ i.m_stencil_thumb_path_len = b->m_texture_thumb_path.size();
+ i.m_tip_color = b->m_tip_color;
+ i.m_tip_size = b->m_tip_size;
+ i.m_tip_spacing = b->m_tip_spacing;
+ i.m_tip_flow = b->m_tip_flow;
+ i.m_tip_opacity = b->m_tip_opacity;
+ i.m_tip_angle = b->m_tip_angle;
+ i.m_tip_angle_delay = b->m_tip_angle_delay;
+ i.m_tip_mix = b->m_tip_mix;
+ i.m_tip_wet = b->m_tip_wet;
+ i.m_tip_noise = b->m_tip_noise;
+ i.m_tip_hue = b->m_tip_hue;
+ i.m_tip_sat = b->m_tip_sat;
+ i.m_tip_val = b->m_tip_val;
+ i.m_tip_angle_follow = b->m_tip_angle_follow;
+ i.m_tip_flow_pressure = b->m_tip_flow_pressure;
+ i.m_tip_size_pressure = b->m_tip_size_pressure;
+ i.m_jitter_scale = b->m_jitter_scale;
+ i.m_jitter_angle = b->m_jitter_angle;
+ i.m_jitter_spread = b->m_jitter_spread;
+ i.m_jitter_flow = b->m_jitter_flow;
+ i.m_jitter_hue = b->m_jitter_hue;
+ i.m_jitter_sat = b->m_jitter_sat;
+ i.m_jitter_val = b->m_jitter_val;
+ i.m_blend_mode = b->m_blend_mode;
- i.m_tip_invert = b->m_brush->m_tip_invert;
- i.m_tip_flipx = b->m_brush->m_tip_flipx;
- i.m_tip_flipy = b->m_brush->m_tip_flipy;
- i.m_pattern_enabled = b->m_brush->m_pattern_enabled;
- i.m_dual_enabled = b->m_brush->m_dual_enabled;
- i.m_dual_blend_mode = b->m_brush->m_dual_blend_mode;
- i.m_dual_randflip = b->m_brush->m_dual_randflip;
- i.m_dual_size = b->m_brush->m_dual_size;
- i.m_dual_spacing = b->m_brush->m_dual_spacing;
- i.m_dual_scatter = b->m_brush->m_dual_scatter;
- i.m_dual_scatter_axis = b->m_brush->m_dual_scatter_axis;
- i.m_dual_invert = b->m_brush->m_dual_invert;
- i.m_dual_flipx = b->m_brush->m_dual_flipx;
- i.m_dual_flipy = b->m_brush->m_dual_flipy;
- i.m_tip_randflipx = b->m_brush->m_tip_randflipx;
- i.m_tip_randflipy = b->m_brush->m_tip_randflipy;
- i.m_tip_aspect = b->m_brush->m_tip_aspect;
- i.m_dual_flow = b->m_brush->m_dual_flow;
- i.m_dual_opacity = b->m_brush->m_dual_opacity;
- i.m_dual_rotate = b->m_brush->m_dual_rotate;
+ i.m_tip_invert = b->m_tip_invert;
+ i.m_tip_flipx = b->m_tip_flipx;
+ i.m_tip_flipy = b->m_tip_flipy;
+ i.m_pattern_enabled = b->m_pattern_enabled;
+ i.m_dual_enabled = b->m_dual_enabled;
+ i.m_dual_blend_mode = b->m_dual_blend_mode;
+ i.m_dual_randflip = b->m_dual_randflip;
+ i.m_dual_size = b->m_dual_size;
+ i.m_dual_spacing = b->m_dual_spacing;
+ i.m_dual_scatter = b->m_dual_scatter;
+ i.m_dual_scatter_axis = b->m_dual_scatter_axis;
+ i.m_dual_invert = b->m_dual_invert;
+ i.m_dual_flipx = b->m_dual_flipx;
+ i.m_dual_flipy = b->m_dual_flipy;
+ i.m_tip_randflipx = b->m_tip_randflipx;
+ i.m_tip_randflipy = b->m_tip_randflipy;
+ i.m_tip_aspect = b->m_tip_aspect;
+ i.m_dual_flow = b->m_dual_flow;
+ i.m_dual_opacity = b->m_dual_opacity;
+ i.m_dual_rotate = b->m_dual_rotate;
- i.m_pattern_eachsample = b->m_brush->m_pattern_eachsample;
- i.m_pattern_invert = b->m_brush->m_pattern_invert;
- i.m_pattern_flipx = b->m_brush->m_pattern_flipx;
- i.m_pattern_flipy = b->m_brush->m_pattern_flipy;
- i.m_pattern_scale = b->m_brush->m_pattern_scale;
- i.m_pattern_brightness = b->m_brush->m_pattern_brightness;
- i.m_pattern_contrast = b->m_brush->m_pattern_contrast;
- i.m_pattern_rand_offset = b->m_brush->m_pattern_rand_offset;
+ i.m_pattern_eachsample = b->m_pattern_eachsample;
+ i.m_pattern_invert = b->m_pattern_invert;
+ i.m_pattern_flipx = b->m_pattern_flipx;
+ i.m_pattern_flipy = b->m_pattern_flipy;
+ i.m_pattern_scale = b->m_pattern_scale;
+ i.m_pattern_brightness = b->m_pattern_brightness;
+ i.m_pattern_contrast = b->m_pattern_contrast;
+ i.m_pattern_rand_offset = b->m_pattern_rand_offset;
+ i.m_pattern_depth = b->m_pattern_depth;
fwrite(&i, sizeof(i), 1, fp);
- fwrite(b->m_brush->m_name.c_str(), 1, b->m_brush->m_name.size(), fp);
- fwrite(b->m_brush->m_brush_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp);
- fwrite(b->m_brush->m_brush_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp);
- fwrite(b->m_brush->m_dual_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp);
- fwrite(b->m_brush->m_dual_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp);
- fwrite(b->m_brush->m_pattern_path.c_str(), 1, b->m_brush->m_pattern_path.size(), fp);
- fwrite(b->m_brush->m_texture_thumb_path.c_str(), 1, b->m_brush->m_texture_thumb_path.size(), fp);
+ fwrite(b->m_name.c_str(), 1, b->m_name.size(), fp);
+ fwrite(b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp);
+ fwrite(b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
+ fwrite(b->m_dual_path.c_str(), 1, b->m_brush_path.size(), fp);
+ fwrite(b->m_dual_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
+ fwrite(b->m_pattern_path.c_str(), 1, b->m_pattern_path.size(), fp);
+ fwrite(b->m_texture_thumb_path.c_str(), 1, b->m_texture_thumb_path.size(), fp);
}
fclose(fp);
return true;
@@ -651,7 +652,6 @@ bool NodePanelBrushPreset::restore()
b->m_tip_angle = i.m_tip_angle;
b->m_tip_angle_delay = i.m_tip_angle_delay;
b->m_tip_mix = i.m_tip_mix;
- b->m_pattern_opacity = i.m_pattern_opacity;
b->m_tip_wet = i.m_tip_wet;
b->m_tip_noise = i.m_tip_noise;
b->m_tip_hue = i.m_tip_hue;
@@ -696,6 +696,7 @@ bool NodePanelBrushPreset::restore()
b->m_pattern_brightness = i.m_pattern_brightness;
b->m_pattern_contrast = i.m_pattern_contrast;
b->m_pattern_rand_offset = i.m_pattern_rand_offset;
+ b->m_pattern_depth = i.m_pattern_depth;
b->m_name.resize(i.m_name_len);
b->m_brush_path.resize(i.m_brush_path_len);
diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h
index 06a5a85..b5713bf 100644
--- a/src/node_panel_brush.h
+++ b/src/node_panel_brush.h
@@ -111,7 +111,6 @@ class NodePanelBrushPreset : public Node
float m_tip_angle = 0;
float m_tip_angle_delay = 0;
float m_tip_mix = 0;
- float m_pattern_opacity = 0;
float m_tip_wet = 0;
float m_tip_noise = 0;
float m_tip_hue = 0;
@@ -158,6 +157,7 @@ class NodePanelBrushPreset : public Node
float m_pattern_brightness = 0.5f;
float m_pattern_contrast = 0.5f;
bool m_pattern_rand_offset = false;
+ float m_pattern_depth = 1.f;
};
public:
std::function& brush)> on_brush_changed;
diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp
index c3ed845..a967e56 100644
--- a/src/node_panel_stroke.cpp
+++ b/src/node_panel_stroke.cpp
@@ -31,7 +31,6 @@ void NodePanelStroke::update_controls()
m_tip_opacity->m_value.x = b->m_tip_opacity;
m_tip_angle->m_value.x = b->m_tip_angle;
m_tip_angle_delay->m_value.x = b->m_tip_angle_delay;
- m_pattern_opacity->m_value.x = b->m_pattern_opacity;
m_tip_wet->m_value.x = b->m_tip_wet;
m_tip_noise->m_value.x = b->m_tip_noise;
m_jitter_scale->m_value.x = b->m_jitter_scale;
@@ -74,6 +73,7 @@ void NodePanelStroke::update_controls()
m_pattern_scale->m_value.x = b->m_pattern_scale;
m_pattern_brightness->m_value.x = b->m_pattern_brightness;
m_pattern_contrast->m_value.x = b->m_pattern_contrast;
+ m_pattern_depth->m_value.x = b->m_pattern_depth;
m_blend_mode->set_index(b->m_blend_mode);
m_dual_blend_mode->set_index(b->m_dual_blend_mode);
@@ -285,6 +285,7 @@ void NodePanelStroke::init_controls()
};
m_pattern_popup->on_brush_changed = [this](Node*, int index) {
+ m_pattern_enabled->set_value(true, true);
if (on_pattern_changed)
on_pattern_changed(this, m_pattern_popup->get_texture_path(index), m_pattern_popup->get_thumb_path(index));
m_pattern_thumb->set_image(m_pattern_popup->get_thumb_path(index));
@@ -308,7 +309,6 @@ void NodePanelStroke::init_controls()
init_slider(m_tip_angle, "tip-angle", &Brush::m_tip_angle);
init_slider(m_tip_angle_delay, "tip-angle-delay", &Brush::m_tip_angle_delay);
init_slider(m_tip_mix, "tip-mix", &Brush::m_tip_mix);
- init_slider(m_pattern_opacity, "pattern-opacity", &Brush::m_pattern_opacity);
init_slider(m_tip_wet, "tip-wet", &Brush::m_tip_wet);
init_slider(m_tip_noise, "tip-noise", &Brush::m_tip_noise);
init_slider(m_tip_hue, "tip-hue", &Brush::m_tip_hue);
@@ -355,6 +355,7 @@ void NodePanelStroke::init_controls()
init_slider(m_pattern_scale, "pattern-scale", &Brush::m_pattern_scale);
init_slider(m_pattern_brightness, "pattern-brightness", &Brush::m_pattern_brightness);
init_slider(m_pattern_contrast, "pattern-contrast", &Brush::m_pattern_contrast);
+ init_slider(m_pattern_depth, "pattern-depth", &Brush::m_pattern_depth);
auto curve_cubic = [](float v) { return glm::pow(v, 3.f); };
auto curve_quad = [](float v) { return glm::pow(v, 2.f); };
diff --git a/src/node_panel_stroke.h b/src/node_panel_stroke.h
index 528fbbf..02d8bb4 100644
--- a/src/node_panel_stroke.h
+++ b/src/node_panel_stroke.h
@@ -21,7 +21,6 @@ public:
NodeSliderH* m_tip_angle;
NodeSliderH* m_tip_angle_delay;
NodeSliderH* m_tip_mix;
- NodeSliderH* m_pattern_opacity;
NodeSliderH* m_tip_wet;
NodeSliderH* m_tip_noise;
NodeSliderH* m_tip_hue;
@@ -78,6 +77,7 @@ public:
NodeSliderH* m_pattern_scale;
NodeSliderH* m_pattern_brightness;
NodeSliderH* m_pattern_contrast;
+ NodeSliderH* m_pattern_depth;
std::shared_ptr m_brush_popup;
std::shared_ptr m_pattern_popup;
diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp
index ed982dc..594653b 100644
--- a/src/node_stroke_preview.cpp
+++ b/src/node_stroke_preview.cpp
@@ -82,7 +82,6 @@ void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2
ShaderManager::u_int(kShaderUniform::TexPattern, 4);
ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Lock, false);
ShaderManager::u_int(kShaderUniform::Mask, false);
@@ -95,7 +94,8 @@ void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
- ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f: 0.0f));
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
+ ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f));
ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity);
m_sampler_linear.bind(0);
@@ -297,11 +297,11 @@ void NodeStrokePreview::draw_stroke()
ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer
//ShaderManager::u_int(kShaderUniform::TexMixA, 4); // mixer
ShaderManager::u_vec2(kShaderUniform::Resolution, size);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale);
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f));
ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && b->m_pattern_eachsample);
ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj);
@@ -393,7 +393,6 @@ void NodeStrokePreview::draw_stroke()
ShaderManager::u_int(kShaderUniform::TexPattern, 4);
ShaderManager::u_vec2(kShaderUniform::Resolution, size);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity);
- ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Mask, false);
ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode);
@@ -405,6 +404,7 @@ void NodeStrokePreview::draw_stroke()
ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
+ ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f));
ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity);
diff --git a/src/shader.cpp b/src/shader.cpp
index 5a0cbff..53b0bd9 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -1,11 +1,122 @@
#include "pch.h"
#include "log.h"
#include "shader.h"
+#include "asset.h"
std::map ShaderManager::m_shaders;
Shader* ShaderManager::m_current;
bool ShaderManager::ext_framebuffer_fetch = false;
+std::string Shader::read(const std::string& path)
+{
+ Asset a;
+ std::string ret;
+ if (a.open(path.c_str()))
+ {
+ std::regex reg_include(R"!(#include "([^"]+)")!");
+ std::string data((char*)a.read_all(), a.m_len);
+
+ // split path
+ std::string name, base, ext;
+ std::regex reg_path(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
+ std::smatch m;
+ if (std::regex_search(path, m, reg_path))
+ {
+ base = m[1].str();
+ name = m[2].str();
+ ext = m[3].str();
+ }
+
+ for (const auto& l : split(data, '\n'))
+ {
+ std::smatch m;
+ if (std::regex_search(l, m, reg_include))
+ {
+ std::string inc = base + "/" + m[1].str();
+ if (Asset::exist(inc.c_str()))
+ {
+ std::string subdata = read(inc);
+ ret.append(subdata + "\n");
+ }
+ }
+ else
+ {
+ ret.append(l + "\n");
+ }
+ }
+ }
+ return ret;
+}
+
+void Shader::parse_error(const char* msg, const char* code)
+{
+ auto code_lines = split(code, '\n');
+ auto error_lines = split(msg, '\n');
+ std::smatch m;
+ std::regex r(R"(\((\d+)\))");
+ for (const auto& line : error_lines)
+ {
+ LOG("%s", line.c_str());
+ if (std::regex_search(line, m, r))
+ {
+ int ln = std::stoi(m[1].str());
+ if (ln < code_lines.size())
+ {
+ int n = 2;
+ int s = std::max(ln - n, 1);
+ int e = std::min((int)code_lines.size() - 1, ln + n);
+ for (int i = s; i < e; i++)
+ {
+ LOG("- line %02d: %s", i, code_lines[i - 1].c_str());
+ }
+ }
+ }
+ }
+}
+
+bool Shader::load(const std::string& path)
+{
+ std::string data = read(path);
+ if (data.empty()) return false;
+
+ std::map> sections;
+ std::shared_ptr current_section = nullptr;
+ std::regex reg_section(R"!(\[\[(.*)\]\])!");
+ for (const auto& l : split(data, '\n'))
+ {
+ std::smatch m;
+ if (std::regex_search(l, m, reg_section))
+ {
+ std::string section_name = m[1].str();
+ if (!sections[section_name])
+ sections[section_name] = std::make_shared();
+ current_section = sections[section_name];
+ }
+ else
+ {
+ // create an un-named section
+ if (!current_section)
+ current_section = sections[""] = std::make_shared();
+ current_section->append(l + "\n");
+ }
+ }
+
+ if (sections.find("vertex") != sections.end() && sections.find("fragment") != sections.end())
+ {
+ *sections["vertex"] = SHADER_VERSION + *sections["vertex"];
+ *sections["fragment"] = SHADER_VERSION + *sections["fragment"];
+ return create(sections["vertex"]->c_str(), sections["fragment"]->c_str());
+ }
+ else
+ {
+ LOG("could not find [[vertex]] and [[fragment]] sections on %s", path.c_str());
+ }
+
+ m_path = path;
+
+ return false;
+}
+
bool Shader::create(const char* vertex, const char* fragment)
{
GLint status;
@@ -24,7 +135,10 @@ bool Shader::create(const char* vertex, const char* fragment)
glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog);
if (infolen > 0)
- LOG("VERTEX SHADER:\n%s", infolog);
+ {
+ LOG("\nVERTEX SHADER:");
+ parse_error(infolog, vertex);
+ }
if (status == 0)
{
glDeleteShader(vs);
@@ -43,7 +157,10 @@ bool Shader::create(const char* vertex, const char* fragment)
glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog);
if (infolen > 0)
- LOG("FRAGMENT SHADER:\n%s", infolog);
+ {
+ LOG("\nFRAGMENT SHADER:");
+ parse_error(infolog, fragment);
+ }
if (status == 0)
{
glDeleteShader(vs);
@@ -159,6 +276,12 @@ GLint Shader::GetAttribLocation(const char* name)
return glGetAttribLocation(prog, name);
}
+bool ShaderManager::load(kShader id, const std::string& path)
+{
+ m_shaders[id].name = id;
+ return m_shaders[id].load(path);
+}
+
bool ShaderManager::create(kShader id, const char* vertex, const char* fragment)
{
m_shaders[id].name = id;
diff --git a/src/shader.h b/src/shader.h
index 95eeba8..ad47747 100644
--- a/src/shader.h
+++ b/src/shader.h
@@ -40,6 +40,7 @@ enum class kShaderUniform : uint16_t
PatternScale = const_hash("pattern_scale"),
PatternBright = const_hash("pattern_bright"),
PatternContrast = const_hash("pattern_contr"),
+ PatternDepth = const_hash("pattern_depth"),
Colorize = const_hash("colorize"),
DualAlpha = const_hash("dual_alpha"),
};
@@ -73,10 +74,14 @@ enum class kShader : uint16_t
class Shader
{
+ std::string m_path;
std::map m_umap;
GLuint prog;
+ std::string read(const std::string& path);
public:
kShader name;
+ void parse_error(const char* msg, const char* code);
+ bool load(const std::string& path);
bool create(const char* vertex, const char* fragment);
void use();
void u_vec4(kShaderUniform id, const glm::vec4& v);
@@ -94,6 +99,7 @@ class ShaderManager
static Shader* m_current;
public:
static bool ext_framebuffer_fetch;
+ static bool load(kShader id, const std::string& path);
static bool create(kShader id, const char* vertex, const char* fragment);
static void use(kShader id);
static void use(const char* name);