*/}}

ourshader.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Our Paint: A light weight GPU powered painting program.
  3. * Copyright (C) 2022-2023 Wu Yiming
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "ourpaint.h"
  19. const char OUR_CANVAS_SHADER[]=R"(#version 430
  20. layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
  21. layout(rgba16, binding = 0) uniform image2D img;
  22. layout(rgba16, binding = 1) coherent uniform image2D smudge_buckets;
  23. uniform ivec2 uBrushCorner;
  24. uniform vec2 uBrushCenter;
  25. uniform float uBrushSize;
  26. uniform float uBrushHardness;
  27. uniform float uBrushSmudge;
  28. uniform float uBrushSlender;
  29. uniform float uBrushAngle;
  30. uniform float uBrushRecentness;
  31. uniform vec4 uBrushColor;
  32. uniform vec4 uBackgroundColor;
  33. uniform int uBrushErasing;
  34. const vec4 p1_22=vec4(1.0/2.2,1.0/2.2,1.0/2.2,1.0/2.2);
  35. const vec4 p22=vec4(2.2,2.2,2.2,2.2);
  36. const float WGM_EPSILON=0.001f;
  37. const float T_MATRIX_SMALL[3][12] = {{0.016163474652781, 0.001420445523172, -0.054887305841183,
  38. -0.065871603913166, -0.205903208273135, -0.062532921841612,
  39. 0.074959700955855, 0.180474083483825, 0.398778827864023,
  40. 0.461711312001723, 0.253843485461910, 0.001944673073610},
  41. {-0.023482789468200, -0.016937259153745, 0.054365284958976,
  42. 0.068868972628298, 0.258888405935374, 0.412123548933354,
  43. 0.280003145201754, 0.029172844285245, -0.016952611829275,
  44. -0.028985388398516, -0.016912989806334, -0.000181721110369},
  45. {0.451833383178114, 0.622986272902632, 0.020381940564709,
  46. 0.015460521778453, -0.003629434201241, -0.048676538578416,
  47. -0.036229432289079, -0.007323977526407, -0.005984077846982,
  48. -0.005755040132913, -0.003041519739360, -0.000016761047877}};
  49. const float spectral_r_small[12] = {0.021146405259067, 0.000101655202080, 0.398199126291765,
  50. 0.001743053489250, 0.000148554860119, 0.000146064594547,
  51. 0.000328614570185, 0.910913102591031, 0.916608409655475,
  52. 0.700400409331843, 0.657122476831633, 0.142235538434584};
  53. const float spectral_g_small[12] = {0.147994747800981, 0.000101679918159, 0.496335365339077,
  54. 0.882788054089882, 0.964096335484527, 0.978765395560054,
  55. 0.985895331330888, 0.076452920947158, 0.080461223658394,
  56. 0.296672324245411, 0.339468867320878, 0.139019679306543};
  57. const float spectral_b_small[12] = {0.831573896245073, 0.998692793883148, 0.105770703333882,
  58. 0.112984668836056, 0.037214012464483, 0.022337434144516,
  59. 0.015090957392503, 0.010456093241942, 0.002660665934598,
  60. 0.002980934458404, 0.002468909304878, 0.716325888182986};
  61. void rgb_to_spectral (vec3 rgb, out float spectral_[12]) {
  62. float offset = 1.0 - WGM_EPSILON;
  63. float r = rgb.r * offset + WGM_EPSILON;
  64. float g = rgb.g * offset + WGM_EPSILON;
  65. float b = rgb.b * offset + WGM_EPSILON;
  66. float spec_r[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; for (int i=0; i < 12; i++) {spec_r[i] = spectral_r_small[i] * r;}
  67. float spec_g[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; for (int i=0; i < 12; i++) {spec_g[i] = spectral_g_small[i] * g;}
  68. float spec_b[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; for (int i=0; i < 12; i++) {spec_b[i] = spectral_b_small[i] * b;}
  69. for (int i=0; i<12; i++) {spectral_[i] = spec_r[i] + spec_g[i] + spec_b[i];}
  70. }
  71. vec3 spectral_to_rgb (float spectral[12]) {
  72. float offset = 1.0 - WGM_EPSILON;
  73. // We need this tmp. array to allow auto vectorization. <-- How about on GPU?
  74. float tmp[3] = {0,0,0};
  75. for (int i=0; i<12; i++) {
  76. tmp[0] += T_MATRIX_SMALL[0][i] * spectral[i];
  77. tmp[1] += T_MATRIX_SMALL[1][i] * spectral[i];
  78. tmp[2] += T_MATRIX_SMALL[2][i] * spectral[i];
  79. }
  80. vec3 rgb_;
  81. for (int i=0; i<3; i++) {rgb_[i] = clamp((tmp[i] - WGM_EPSILON) / offset, 0.0f, 1.0f);}
  82. return rgb_;
  83. }
  84. subroutine vec4 MixRoutines(vec4 a, vec4 b, float fac_a);
  85. subroutine(MixRoutines) vec4 DoMixNormal(vec4 a, vec4 b, float fac_a){
  86. return mix(a,b,1-fac_a);
  87. }
  88. subroutine(MixRoutines) vec4 DoMixSpectral(vec4 a, vec4 b, float fac_a){
  89. vec4 result = vec4(0,0,0,0);
  90. result.a=mix(a.a,b.a,1-fac_a);
  91. float spec_a[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; rgb_to_spectral(a.rgb, spec_a);
  92. float spec_b[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; rgb_to_spectral(b.rgb, spec_b);
  93. float spectralmix[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  94. for (int i=0; i < 12; i++) { spectralmix[i] = pow(spec_a[i], fac_a) * pow(spec_b[i], 1-fac_a); }
  95. result.rgb=spectral_to_rgb(spectralmix);
  96. return result;
  97. }
  98. subroutine uniform MixRoutines uMixRoutineSelection;
  99. vec4 spectral_mix(vec4 a, vec4 b, float fac_a){
  100. return uMixRoutineSelection(a,b,fac_a);
  101. }
  102. vec4 spectral_mix_unpre(vec4 colora, vec4 colorb, float fac){
  103. vec4 ca=(colora.a==0)?colora:vec4(colora.rgb/colora.a,colora.a);
  104. vec4 cb=(colorb.a==0)?colorb:vec4(colorb.rgb/colorb.a,colorb.a);
  105. float af=colora.a*(1-fac);
  106. float aa=af/(af+(1-af)*colorb.a+0.000001);
  107. vec4 result=spectral_mix(ca,cb,aa);
  108. result.a=mix(colora.a,colorb.a,fac);
  109. return vec4(result.rgb*result.a,result.a);
  110. }
  111. float atan2(in float y, in float x){
  112. bool s = (abs(x) > abs(y)); return mix(3.1415926535/2.0 - atan(x,y), atan(y,x), s);
  113. }
  114. vec2 rotate(vec2 v, float angle) {
  115. float s = sin(angle); float c = cos(angle);
  116. return mat2(c,-s,s,c) * v;
  117. }
  118. float brightness(vec4 color) {
  119. return color.r*0.2126+color.b*0.7152+color.g*0.0722;
  120. }
  121. vec4 mix_over(vec4 colora, vec4 colorb){
  122. vec4 a=(colora.a==0)?colora:vec4(colora.rgb/colora.a,colora.a);
  123. vec4 b=(colorb.a==0)?colorb:vec4(colorb.rgb/colorb.a,colorb.a);
  124. vec4 m=vec4(0,0,0,0); float aa=colora.a/(colora.a+(1-colora.a)*colorb.a+0.0001);
  125. m=spectral_mix(a,b,aa);
  126. m.a=colora.a+colorb.a*(1-colora.a);
  127. m=vec4(m.rgb*m.a,m.a);
  128. return m;
  129. }
  130. int dab(float d, vec4 color, float size, float hardness, float smudge, vec4 smudge_color, vec4 last_color, out vec4 final){
  131. vec4 cc=color;
  132. float fac=1-pow(d/size,1+1/(1-hardness+1e-4));
  133. cc.a=color.a*fac*(1-smudge); cc.rgb=cc.rgb*cc.a;
  134. float erasing=float(uBrushErasing);
  135. cc=cc*(1-erasing);
  136. // this looks better than the one commented out below
  137. vec4 c2=spectral_mix_unpre(last_color,smudge_color,smudge*fac*color.a);
  138. c2=mix_over(cc,c2);
  139. //vec4 c2=mix_over(cc,last_color);
  140. //c2=spectral_mix_unpre(c2,smudge_color,smudge*fac*color.a);
  141. c2=spectral_mix_unpre(c2,c2*(1-fac*color.a),erasing);
  142. final=c2;
  143. return 1;
  144. }
  145. subroutine void BrushRoutines();
  146. subroutine(BrushRoutines) void DoDabs(){
  147. ivec2 px = ivec2(gl_GlobalInvocationID.xy)+uBrushCorner;
  148. if(px.x<0||px.y<0||px.x>1024||px.y>1024) return;
  149. vec2 fpx=vec2(px);
  150. fpx=uBrushCenter+rotate(fpx-uBrushCenter,uBrushAngle);
  151. fpx.x=uBrushCenter.x+(fpx.x-uBrushCenter.x)*(1+uBrushSlender);
  152. float dd=distance(fpx,uBrushCenter); if(dd>uBrushSize) return;
  153. vec4 dabc=imageLoad(img, px);
  154. vec4 smudgec=pow(spectral_mix_unpre(pow(imageLoad(smudge_buckets,ivec2(1,0)),p1_22),pow(imageLoad(smudge_buckets,ivec2(0,0)),p1_22),uBrushRecentness),p22);
  155. vec4 final_color;
  156. dab(dd,uBrushColor,uBrushSize,uBrushHardness,uBrushSmudge,smudgec,dabc,final_color);
  157. dabc=final_color;
  158. imageStore(img, px, dabc);
  159. }
  160. subroutine(BrushRoutines) void DoSample(){
  161. ivec2 p=ivec2(gl_GlobalInvocationID.xy);
  162. int DoSample=1; vec4 color;
  163. if(p.y==0){
  164. vec2 sp=round(vec2(sin(float(p.x)),cos(float(p.x)))*uBrushSize);
  165. ivec2 px=ivec2(sp)+uBrushCorner; if(px.x<0||px.y<0||px.x>=1024||px.y>=1024){ DoSample=0; }
  166. if(DoSample!=0){
  167. ivec2 b=uBrushCorner; if(b.x>=0&&b.y>=0&&b.x<1024&&b.y<1024){ imageStore(smudge_buckets,ivec2(128+32,0),imageLoad(img, b)); }
  168. color=imageLoad(img, px);
  169. imageStore(smudge_buckets,ivec2(p.x+128,0),color);
  170. }
  171. }else{DoSample=0;}
  172. memoryBarrier();barrier(); if(DoSample==0) return;
  173. if(uBrushErasing==0 || p.x!=0) return;
  174. color=vec4(0,0,0,0); for(int i=0;i<32;i++){ color=color+imageLoad(smudge_buckets, ivec2(i+128,0)); }
  175. color=spectral_mix_unpre(color/32,imageLoad(smudge_buckets, ivec2(128+32,0)),0.6*(1-uBrushColor.a)); vec4 oldcolor=imageLoad(smudge_buckets, ivec2(0,0));
  176. imageStore(smudge_buckets,ivec2(1,0),uBrushErasing==2?color:oldcolor);
  177. imageStore(smudge_buckets,ivec2(0,0),color);
  178. }
  179. subroutine uniform BrushRoutines uBrushRoutineSelection;
  180. void main() {
  181. uBrushRoutineSelection();
  182. }
  183. )";
  184. const char OUR_COMPOSITION_SHADER[]=R"(#version 430
  185. layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
  186. layout(rgba16, binding = 0) uniform image2D top;
  187. layout(rgba16, binding = 1) uniform image2D bottom;
  188. uniform int uBlendMode;
  189. uniform float uAlphaTop;
  190. uniform float uAlphaBottom;
  191. vec4 mix_over(vec4 colora, vec4 colorb){
  192. colora=colora*uAlphaTop/uAlphaBottom;
  193. vec4 c; c.a=colora.a+colorb.a*(1-colora.a);
  194. c.rgb=(colora.rgb+colorb.rgb*(1-colora.a));
  195. return c;
  196. }
  197. vec4 add_over(vec4 colora, vec4 colorb){
  198. colora=colora*uAlphaTop/uAlphaBottom;
  199. vec4 a=colora+colorb; a.a=clamp(a.a,0,1); return a;
  200. }
  201. void main() {
  202. ivec2 px=ivec2(gl_GlobalInvocationID.xy);
  203. vec4 c1=imageLoad(top,px); vec4 c2=imageLoad(bottom,px);
  204. vec4 c=(uBlendMode==0)?mix_over(c1,c2):add_over(c1,c2);
  205. imageStore(bottom,px,c);
  206. imageStore(top,px,vec4(0,0,0,0));
  207. }
  208. )";