Files
panopainter/engine/app_shaders.cpp

499 lines
20 KiB
C++

#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 vec3 uv;"
"void main(){"
" uv = vec3(uvs, pos.w);"
" gl_Position = mvp * vec4(pos.xyz, 1.0);"
"}";
static const char* shader_f =
SHADER_VERSION
"uniform sampler2D tex;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
//" frag = texture(tex, uv.xy/uv.z);"
" frag = texture(tex, uv.xy);"
"}";
static const char* shader_uv_f =
SHADER_VERSION
"uniform sampler2D tex;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
" frag = vec4(uv.xy, 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 vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec4 c = texture(tex, uv.xy);\n"
" frag = highlight ? \n"
" vec4(clamp(vec3(.3)+c.rgb, vec3(0), vec3(1)), c.a) : \n"
" texture(tex, uv.xy) * vec4(1,1,1,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 vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump float stroke = 1.0 - texture(tex, uv.xy).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 sampler2D tex_mask;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\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 image2D img_mixer;\n"
"uniform mediump float alpha;\n"
"uniform mediump int blend_mode;\n"
"uniform bool lock;\n"
"uniform bool mask;\n"
"in mediump vec3 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 vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\n"
" stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv.xy).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)) *.5 + .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"
"out vec2 uv;\n"
"out float q;\n"
"void main(){\n"
" uv = uvs;\n"
" q = pos.z;\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"
//"layout (binding=3, rgba8) uniform image2D 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 wet;\n"
"in mediump vec2 uv;\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"
" mediump float contribution = (1.0 - bg.a) * fg.a;\n"
" mediump float alpha_tot = bg.a + contribution;"
" 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"
"}";
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::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");
}