#include "pch.h" #include "app.h" #include "shader.h" using namespace ui; void App::initShaders() { static const char* shader_v = SHADER_VERSION "uniform mat4 mvp;" "in vec4 pos;" "in vec2 uvs;" "out vec2 uv;" "void main(){" " uv = uvs;" " gl_Position = mvp * vec4(pos.xyz, 1.0);" "}"; static const char* shader_f = SHADER_VERSION "uniform sampler2D tex;" "in mediump vec2 uv;" "out mediump vec4 frag;" "void main(){" " frag = texture(tex, uv);" "}"; static const char* shader_uv_f = SHADER_VERSION "in mediump vec2 uv;" "out mediump vec4 frag;" "void main(){" " frag = vec4(uv, 0.0, 1.0);" "}"; // 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 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 float alpha;\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" " frag = vec4(col.rgb, stroke * alpha);\n" "}"; // TEXTURE COMP ERASE static const char* shader_comp_erase_f = SHADER_VERSION "uniform sampler2D tex;\n" "uniform sampler2D tex_stroke;\n" "uniform mediump float alpha;\n" "uniform mediump vec2 resolution;\n" "uniform bool fragUV2;\n" "in mediump vec2 uv;\n" "out mediump vec4 frag;\n" "void main(){\n" " mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n" " mediump vec4 base = texture(tex, uv2);\n" " mediump vec4 stroke = texture(tex_stroke, uv);\n" " mediump float a = base.a - (stroke.a * alpha);\n" " frag = vec4(base.rgb, clamp(a, 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 sampler2D tex_stencil;\n" "uniform mediump float alpha;\n" "uniform mediump int blend_mode;\n" "uniform mediump vec2 resolution;\n" "uniform bool lock;\n" "uniform bool mask;\n" "uniform bool fragUV2;\n" "in mediump vec2 uv;\n" "out mediump vec4 frag;\n" "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" "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 vec3 blend(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot, int mode) {\n" " if (mode == 0) return blend_normal(base, stroke, alpha_tot);\n" " else if (mode == 1) return blend_multiply(base, stroke, alpha_tot);\n" " else if (mode == 2) return blend_screen(base, stroke, alpha_tot);\n" " else if (mode == 3) return blend_colorDodge(base, stroke, alpha_tot);\n" " else if (mode == 4) return blend_overlay(base, stroke, alpha_tot);\n" " else return blend_multiply(base, stroke, alpha_tot);\n" "}\n" "void main(){\n" " mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n" " mediump vec4 base = texture(tex, uv2);\n" " mediump vec4 stroke = texture(tex_stroke, uv);\n" " stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv2).r : stroke.a * alpha;\n" " if (!lock && base.a == 0.0) { frag = stroke; return; }\n" " mediump float contribution = (1.0 - base.a) * stroke.a;\n" " mediump float alpha_tot = base.a + contribution;" " mediump vec3 rgb = blend(base, stroke, alpha_tot, blend_mode);\n" " frag = vec4(rgb, (lock ? base.a : alpha_tot));\n" "}\n"; // TEXTURE ATLAS static const char* shader_atlas_v = SHADER_VERSION "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);" "}"; static const char* shader_atlas_f = SHADER_VERSION "uniform sampler2D tex;" "in mediump vec2 uv;" "out mediump vec4 frag;" "void main(){" " frag = texture(tex, uv);" "}"; // SOLID COLOR static const char* shader_color_v = SHADER_VERSION "uniform mat4 mvp;" "in vec4 pos;" "void main(){" " gl_Position = mvp * pos;" " gl_PointSize = 5.0;" "}"; static const char* shader_color_f = SHADER_VERSION "uniform mediump vec4 col;" "out mediump vec4 frag;" "void main(){" " frag = col;" "}"; // COLOR QUAD static const char* shader_color_quad_v = SHADER_VERSION "uniform mat4 mvp;" "in vec4 pos;" "in vec2 uvs;" "out vec3 uv;" "void main(){" " gl_Position = mvp * pos;" " uv = vec3(uvs, pos.w);" "}"; static const char* shader_color_quad_f = SHADER_VERSION "uniform mediump vec4 col; // HSV\n" "in mediump vec3 uv;" "out mediump vec4 frag;" "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);" "}" "void main() {" " frag = vec4(hsv2rgb(vec3(col.x, uv.x, 1.0 - uv.y)), 1.0);" "}"; // COLOR TRI static const char* shader_color_tri_f = SHADER_VERSION "uniform mediump vec4 col;" // in HSV "in mediump vec3 uv;" "out mediump vec4 frag;" "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);" "}" "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);" "}"; // HUE static const char* shader_color_hue_v = SHADER_VERSION "uniform mat4 mvp;" "in vec4 pos;" "in vec2 uvs;" "out vec3 uv;" "void main(){" " gl_Position = mvp * pos;" " uv = vec3(uvs, pos.w);" "}"; static const char* shader_color_hue_f = SHADER_VERSION "uniform mediump vec4 col;" "uniform bool dir;" // 0:horizontal, 1:vertical "in mediump vec3 uv;" "out mediump vec4 frag;" "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);" "}" "void main(){" " frag = vec4(hsv2rgb(vec3(dir?uv.y:uv.x, 1.0, 1.0)), 1.0);" "}"; // FONT static const char* shader_font_v = SHADER_VERSION "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);" "}"; static const char* shader_font_f = SHADER_VERSION "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);" "}"; // 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 #ifdef __IOS__ "#extension GL_EXT_shader_framebuffer_fetch : enable\n" // "#extension GL_EXT_shader_image_load_store : enable\n" #endif "uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_stencil;\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 vec2 stencil_offset;\n" "uniform mediump float stencil_alpha;\n" "uniform mediump float mix_alpha;\n" "uniform mediump float wet;\n" "in mediump vec2 uv;\n" "in mediump vec2 uv_2;\n" "in mediump float q;\n" #ifdef __IOS__ "inout mediump vec4 frag;\n" #else "out mediump vec4 frag;\n" #endif // http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ "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" //"highp float rand(mediump vec2 co) { return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); }\n" "void main(){\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" " mediump float stencil = 1.0 - (texture(tex_stencil, (uv2+stencil_offset) * 5.0).r) * stencil_alpha;\n" " mediump float brush_alpha = ( 1.0 - texture(tex, uv/q).r ) * alpha;\n" " mediump vec4 fg = vec4(col.rgb, brush_alpha * stencil);\n" #ifdef __IOS__ " mediump vec4 bg = frag;\n" #else " mediump vec4 bg = texture(tex_bg, uv2);\n" #endif " 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" // " mediump vec4 mbg = texture(tex_mix, uv_2 / q);\n" // " frag.rgb = mix(frag.rgb, mbg.rgb, mix_alpha * mbg.a);\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" "}"; static const char* shader_checkerboard_f = SHADER_VERSION "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" " frag = mix(c1, c2, alpha);\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" "}"; 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" "}"; // STROKE - INSTANCED static const char* shader_stroke_inst_v = SHADER_VERSION "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);" "}"; static const char* shader_stroke_inst_f = SHADER_VERSION "uniform mediump sampler2D tex;" "uniform mediump sampler2D tex_stencil;\n" "uniform mediump vec4 col;" "uniform mediump vec2 resolution;\n" "uniform mediump vec2 stencil_offset;\n" "uniform mediump float stencil_alpha;\n" "in mediump float alpha;" "in mediump vec3 uv;" "out mediump vec4 frag;" "void main(){" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" " mediump float stencil = 1.0 - (texture(tex_stencil, (uv2+stencil_offset)).r * 0.9) * stencil_alpha;\n" " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * stencil;" " frag = vec4(col.rgb, a);" "}"; // VERTEX COLOR static const char* shader_vertcol_v = SHADER_VERSION "uniform mat4 mvp;" "in vec4 pos;" "in vec4 col;" "out vec4 c;" "void main(){" " c = col;" " gl_Position = mvp * pos;" " gl_PointSize = 5.0;" "}"; static const char* shader_vertcol_f = SHADER_VERSION "in mediump vec4 c;" "out mediump vec4 frag;" "void main(){" " frag = c;" "}"; LOG("initializing shaders"); if (!ShaderManager::create(kShader::Texture, shader_v, shader_f)) LOG("Failed to create shader Texture"); if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f)) LOG("Failed to create shader TextureAlpha"); if (!ShaderManager::create(kShader::TextureAlphaSep, shader_v, shader_alpha_sep_f)) LOG("Failed to create shader TextureAlphaSep"); if (!ShaderManager::create(kShader::StrokePreview, shader_v, shader_stroke_preview_f)) LOG("Failed to create shader StrokePreview"); if (!ShaderManager::create(kShader::CompErase, shader_v, shader_comp_erase_f)) LOG("Failed to create shader CompErase"); if (!ShaderManager::create(kShader::CompDraw, shader_v, shader_comp_draw_f)) LOG("Failed to create shader CompDraw"); if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f)) LOG("Failed to create shader Color"); if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f)) LOG("Failed to create shader ColorQuad"); if (!ShaderManager::create(kShader::ColorTri, shader_color_quad_v, shader_color_tri_f)) LOG("Failed to create shader ColorTri"); if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f)) LOG("Failed to create shader ColorHue"); if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f)) LOG("Failed to create shader UVs"); if (!ShaderManager::create(kShader::Font, shader_font_v, shader_font_f)) LOG("Failed to create shader Font"); if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f)) LOG("Failed to create shader Atlas"); if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f)) LOG("Failed to create shader Stroke"); if (!ShaderManager::create(kShader::Checkerboard, shader_checkerboard_v, shader_checkerboard_f)) LOG("Failed to create shader Checkerboard"); if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f)) LOG("Failed to create shader Equirect"); if (!ShaderManager::create(kShader::BrushStroke, shader_stroke_inst_v, shader_stroke_inst_f)) LOG("Failed to create shader BrushStroke"); if (!ShaderManager::create(kShader::VertexColor, shader_vertcol_v, shader_vertcol_f)) LOG("Failed to create shader VertexColor"); LOG("shaders initialized"); }