*/}}

ourshader.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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_SHADER_VERSION_430[]="#version 430\n#define WORKGROUP_SIZE 32";
  20. const char OUR_SHADER_VERSION_320ES[]="#version 320 es\n#define OUR_GLES\n#define WORKGROUP_SIZE 16";
  21. const char OUR_CANVAS_SHADER[]=R"(
  22. layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
  23. #ifdef OUR_GLES
  24. precision highp uimage2D;
  25. precision highp float;
  26. precision highp int;
  27. layout(r32ui, binding = 0) uniform uimage2D img;
  28. layout(r32ui, binding = 1) coherent uniform uimage2D smudge_buckets;
  29. #define OUR_FLT_EPS (1.0/255.0f)
  30. #else
  31. layout(rgba16ui, binding = 0) uniform uimage2D img;
  32. layout(rgba16ui, binding = 1) coherent uniform uimage2D smudge_buckets;
  33. #define OUR_FLT_EPS (1e-4)
  34. #endif
  35. uniform int uCanvasType;
  36. uniform int uCanvasRandom;
  37. uniform float uCanvasFactor;
  38. uniform ivec2 uImageOffset;
  39. uniform ivec2 uBrushCorner;
  40. uniform vec2 uBrushCenter;
  41. uniform float uBrushSize;
  42. uniform float uBrushHardness;
  43. uniform float uBrushSmudge;
  44. uniform float uBrushSlender;
  45. uniform float uBrushAngle;
  46. uniform vec2 uBrushDirection;
  47. uniform float uBrushForce;
  48. uniform float uBrushGunkyness;
  49. uniform float uBrushRecentness;
  50. uniform vec4 uBrushColor;
  51. uniform vec4 uBackgroundColor;
  52. uniform int uBrushErasing;
  53. uniform int uBrushMix;
  54. #ifdef OUR_GLES
  55. uniform int uBrushRoutineSelectionES;
  56. uniform int uMixRoutineSelectionES;
  57. vec4 cunpack(uint d){
  58. return vec4(float(d&0xFFu)/255.,float((d>>8u)&0xFFu)/255.,float((d>>16u)&0xFFu)/255.,float((d>>24u)&0xFFu)/255.);
  59. }
  60. uvec4 cpack(vec4 c){
  61. uint v= uint(uint(c.r*255.) | (uint(c.g*255.)<<8u) | (uint(c.b*255.)<<16u) | (uint(c.a*255.)<<24u));
  62. return uvec4(v,v,v,v);
  63. }
  64. #define OurImageLoad(img, p) \
  65. (cunpack(imageLoad(img,p).x))
  66. #define OurImageStore(img, p, color) \
  67. imageStore(img,p,cpack(color))
  68. #else
  69. #define OurImageLoad(img, p) \
  70. (vec4(imageLoad(img,p))/65535.)
  71. #define OurImageStore(img, p, color) \
  72. imageStore(img,p,uvec4(vec4(color)*65535.))
  73. #endif
  74. const vec4 p1_22=vec4(1.0/2.2,1.0/2.2,1.0/2.2,1.0/2.2);
  75. const vec4 p22=vec4(2.2,2.2,2.2,2.2);
  76. const float WGM_EPSILON=0.001f;
  77. const float T_MATRIX_SMALL[30] = float[30](0.026595621243689,0.049779426257903,0.022449850859496,-0.218453689278271
  78. ,-0.256894883201278,0.445881722194840,0.772365886289756,0.194498761382537
  79. ,0.014038157587820,0.007687264480513
  80. ,-0.032601672674412,-0.061021043498478,-0.052490001018404
  81. ,0.206659098273522,0.572496335158169,0.317837248815438,-0.021216624031211
  82. ,-0.019387668756117,-0.001521339050858,-0.000835181622534
  83. ,0.339475473216284,0.635401374177222,0.771520797089589,0.113222640692379
  84. ,-0.055251113343776,-0.048222578468680,-0.012966666339586
  85. ,-0.001523814504223,-0.000094718948810,-0.000051604594741);
  86. const float spectral_r_small[10] = float[10](0.009281362787953,0.009732627042016,0.011254252737167,0.015105578649573
  87. ,0.024797924177217,0.083622585502406,0.977865045723212,1.000000000000000
  88. ,0.999961046144372,0.999999992756822);
  89. const float spectral_g_small[10] = float[10](0.002854127435775,0.003917589679914,0.012132151699187,0.748259205918013
  90. ,1.000000000000000,0.865695937531795,0.037477469241101,0.022816789725717
  91. ,0.021747419446456,0.021384940572308);
  92. const float spectral_b_small[10] = float[10](0.537052150373386,0.546646402401469,0.575501819073983,0.258778829633924
  93. ,0.041709923751716,0.012662638828324,0.007485593127390,0.006766900622462
  94. ,0.006699764779016,0.006676219883241);
  95. void rgb_to_spectral (vec3 rgb, out float spectral_[10]) {
  96. float offset = 1.0 - WGM_EPSILON;
  97. float r = rgb.r * offset + WGM_EPSILON;
  98. float g = rgb.g * offset + WGM_EPSILON;
  99. float b = rgb.b * offset + WGM_EPSILON;
  100. float spec_r[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.); for (int i=0; i < 10; i++) {spec_r[i] = spectral_r_small[i] * r;}
  101. float spec_g[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.); for (int i=0; i < 10; i++) {spec_g[i] = spectral_g_small[i] * g;}
  102. float spec_b[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.); for (int i=0; i < 10; i++) {spec_b[i] = spectral_b_small[i] * b;}
  103. for (int i=0; i<10; i++) {spectral_[i] = spec_r[i] + spec_g[i] + spec_b[i];}
  104. }
  105. vec3 spectral_to_rgb (float spectral[10]) {
  106. float offset = 1.0 - WGM_EPSILON;
  107. // We need this tmp. array to allow auto vectorization. <-- How about on GPU?
  108. float tmp[3] = float[3](0.,0.,0.);
  109. for (int i=0; i<10; i++) {
  110. tmp[0] += T_MATRIX_SMALL[i] * spectral[i];
  111. tmp[1] += T_MATRIX_SMALL[10+i] * spectral[i];
  112. tmp[2] += T_MATRIX_SMALL[20+i] * spectral[i];
  113. }
  114. vec3 rgb_;
  115. for (int i=0; i<3; i++) {rgb_[i] = clamp((tmp[i] - WGM_EPSILON) / offset, 0.0f, 1.0f);}
  116. return rgb_;
  117. }
  118. vec2 hash( vec2 p ){
  119. p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
  120. return -1.0 + 2.0*fract(sin(p)*43758.5453123);
  121. }
  122. float rand(vec2 co){
  123. return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
  124. }
  125. float noise(in vec2 p){ // from iq
  126. const float K1 = 0.366025404; // (sqrt(3)-1)/2;
  127. const float K2 = 0.211324865; // (3-sqrt(3))/6;
  128. vec2 i = floor( p + (p.x+p.y)*K1 );
  129. vec2 a = p - i + (i.x+i.y)*K2;
  130. float m = step(a.y,a.x);
  131. vec2 o = vec2(m,1.0-m);
  132. vec2 b = a - o + K2;
  133. vec2 c = a - 1.0 + 2.0*K2;
  134. vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
  135. vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
  136. return dot( n, vec3(70.0) );
  137. }
  138. #define HEIGHT_STRAND(x,y) abs(fract(x)-.5)<.48? \
  139. (.4+.2*sin(3.14*(y+ceil(x))))* \
  140. ((max(abs(sin(3.14*x*2.)+0.2),abs(sin(3.14*x*2.)-0.2))+2.*abs(sin(3.14*x)))/2.+0.5):0.1
  141. #define PATTERN_CANVAS(x,y) \
  142. (max(HEIGHT_STRAND((x),(y)),HEIGHT_STRAND(-(y),(x))))
  143. float HEIGHT_CANVAS(float x,float y){
  144. if(uCanvasType == 1){
  145. return PATTERN_CANVAS(x,y);
  146. }else if(uCanvasType == 2){
  147. vec2 uv=vec2(x,y); float f; uv*=0.1; // from iq
  148. f = 0.2*noise( uv ); uv*=5.;
  149. f += 0.6*noise( uv ); uv*=3.;
  150. f += 0.5*noise( uv );
  151. f = 0.55 + 0.55*f;
  152. return pow(f,0.5);
  153. }
  154. return 1.;
  155. }
  156. float SampleCanvas(vec2 U, vec2 dir,float rfac, float force, float gunky){
  157. if(uCanvasType==0 || abs(gunky)<1.e-2){ return rfac; }
  158. U+=vec2(uImageOffset); U/=20.3; U.x=U.x+rand(U)/10.; U.y=U.y+rand(U)/10.;
  159. mat2 m = mat2(1.6,1.2,-1.2,1.6); vec2 _uv=U; _uv.x+=float(uCanvasRandom%65535)/174.41; _uv.y+=float(uCanvasRandom%65535)/439.87; _uv/=500.;
  160. U.x+=noise(_uv)*2.1; _uv = m*_uv; U.x+=noise(_uv)*0.71;
  161. _uv.y+=365.404;
  162. U.y+=noise(_uv)*1.9; _uv = m*_uv; U.y+=noise(_uv)*0.83;
  163. float d=0.1;
  164. float h=HEIGHT_CANVAS(U.x,U.y);
  165. float hr=HEIGHT_CANVAS(U.x+d,U.y);
  166. float hu=HEIGHT_CANVAS(U.x,U.y+d);
  167. vec3 vx=normalize(vec3(d,0,hr)-vec3(0,0,h)),vy=normalize(vec3(0,d,hu)-vec3(0,0,h)),vz=cross(vx,vy);
  168. float useforce=force*rfac;
  169. float scrape=dot(normalize(vz),vec3(-normalize(dir).xy,0))*mix(0.3,1.,useforce);
  170. float top=h-(1.-pow(useforce,1.5)*2.); float tophard=smoothstep(0.4,0.6,top);
  171. float fac=(gunky>=0.)?mix(mix(1.,top,gunky),tophard,gunky):mix(1.,1.-h,-gunky*0.8);
  172. fac=max(fac,scrape*clamp(gunky,0.,1.));
  173. fac=clamp(fac,0.,1.);
  174. fac*=rfac;
  175. return mix(rfac,fac,uCanvasFactor);
  176. }
  177. #ifndef OUR_GLES
  178. subroutine vec4 MixRoutines(vec4 a, vec4 b, float fac_a);
  179. #endif
  180. #ifndef OUR_GLES
  181. subroutine(MixRoutines)
  182. #endif
  183. vec4 DoMixNormal(vec4 a, vec4 b, float fac_a){
  184. return mix(a,b,1.0f-fac_a);
  185. }
  186. #ifndef OUR_GLES
  187. subroutine(MixRoutines)
  188. #endif
  189. vec4 DoMixSpectral(vec4 a, vec4 b, float fac_a){
  190. vec4 result = vec4(0,0,0,0);
  191. result.a=mix(a.a,b.a,1.0f-fac_a);
  192. float spec_a[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.); rgb_to_spectral(a.rgb, spec_a);
  193. float spec_b[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.); rgb_to_spectral(b.rgb, spec_b);
  194. float spectralmix[10] = float[10](0.,0.,0.,0.,0.,0.,0.,0.,0.,0.);
  195. for (int i=0; i < 10; i++) { spectralmix[i] = pow(spec_a[i], fac_a) * pow(spec_b[i], 1.0f-fac_a); }
  196. result.rgb=spectral_to_rgb(spectralmix);
  197. return result;
  198. }
  199. #ifdef OUR_GLES
  200. vec4 uMixRoutineSelection(vec4 a, vec4 b, float fac_a){
  201. if(uMixRoutineSelectionES==0){ return DoMixNormal(a,b,fac_a); }
  202. else{ return DoMixSpectral(a,b,fac_a); }
  203. }
  204. #else
  205. subroutine uniform MixRoutines uMixRoutineSelection;
  206. #endif
  207. vec4 spectral_mix(vec4 a, vec4 b, float fac_a){
  208. return uMixRoutineSelection(a,b,fac_a);
  209. }
  210. vec4 spectral_mix_unpre(vec4 colora, vec4 colorb, float fac){
  211. vec4 ca=(colora.a==0.0f)?colora:vec4(colora.rgb/colora.a,colora.a);
  212. vec4 cb=(colorb.a==0.0f)?colorb:vec4(colorb.rgb/colorb.a,colorb.a);
  213. float af=colora.a*(1.0f-fac);
  214. float aa=af/(af+fac*colorb.a+0.000001);
  215. vec4 result=spectral_mix(ca,cb,aa);
  216. result.a=mix(colora.a,colorb.a,fac);
  217. return vec4(result.rgb*result.a,result.a);
  218. }
  219. float atan2(in float y, in float x){
  220. bool s = (abs(x) > abs(y)); return mix(3.1415926535/2.0 - atan(x,y), atan(y,x), s);
  221. }
  222. vec2 rotate(vec2 v, float angle) {
  223. float s = sin(angle); float c = cos(angle);
  224. return mat2(c,-s,s,c) * v;
  225. }
  226. float brightness(vec4 color) {
  227. return color.r*0.2126+color.b*0.7152+color.g*0.0722;
  228. }
  229. vec4 mix_over(vec4 colora, vec4 colorb){
  230. vec4 a=(colora.a==0.0f)?colora:vec4(colora.rgb/colora.a,colora.a);
  231. vec4 b=(colorb.a==0.0f)?colorb:vec4(colorb.rgb/colorb.a,colorb.a);
  232. vec4 m=vec4(0,0,0,0); float aa=colora.a/(colora.a+(1.0f-colora.a)*colorb.a+OUR_FLT_EPS);
  233. m=spectral_mix(a,b,aa);
  234. m.a=colora.a+colorb.a*(1.0f-colora.a);
  235. m=vec4(m.rgb*m.a,m.a);
  236. return m;
  237. }
  238. int dab(float d, vec2 fpx, vec4 color, float size, float hardness, float smudge, vec4 smudge_color, vec4 last_color, out vec4 final){
  239. vec4 cc=color;
  240. float fac=1.0f-pow(d/size,1.0f+1.0f/(1.0f-hardness+OUR_FLT_EPS));
  241. float canvas=SampleCanvas(fpx,uBrushDirection,fac,uBrushForce,uBrushGunkyness);
  242. cc.a=color.a*canvas*(1.0f-smudge); cc.rgb=cc.rgb*cc.a;
  243. float erasing=float(uBrushErasing);
  244. cc=cc*(1.0f-erasing);
  245. // this looks better than the one commented out below
  246. vec4 c2=spectral_mix_unpre(last_color,smudge_color,smudge*fac*color.a*canvas);
  247. c2=mix_over(cc,c2);
  248. //vec4 c2=mix_over(cc,last_color);
  249. //c2=spectral_mix_unpre(c2,smudge_color,smudge*fac*color.a*canvas);
  250. c2=spectral_mix_unpre(c2,c2*(1.0f-fac*color.a),erasing*canvas);
  251. final=c2;
  252. return 1;
  253. }
  254. #ifndef saturate
  255. #define saturate(v) clamp(v, 0., 1.)
  256. #endif
  257. const float HCV_EPSILON = 1e-10;
  258. const float HCY_EPSILON = 1e-10;
  259. vec3 hue_to_rgb(float hue){
  260. float R = abs(hue * 6. - 3.) - 1.;
  261. float G = 2. - abs(hue * 6. - 2.);
  262. float B = 2. - abs(hue * 6. - 4.);
  263. return saturate(vec3(R,G,B));
  264. }
  265. vec3 hcy_to_rgb(vec3 hcy){
  266. const vec3 HCYwts = vec3(0.299, 0.587, 0.114);
  267. vec3 RGB = hue_to_rgb(hcy.x);
  268. float Z = dot(RGB, HCYwts);
  269. if (hcy.z < Z) { hcy.y *= hcy.z / Z; }
  270. else if (Z < 1.) { hcy.y *= (1. - hcy.z) / (1. - Z); }
  271. return (RGB - Z) * hcy.y + hcy.z;
  272. }
  273. vec3 rgb_to_hcv(vec3 rgb){
  274. // Based on work by Sam Hocevar and Emil Persson
  275. vec4 P = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0/3.0) : vec4(rgb.gb, 0.0, -1.0/3.0);
  276. vec4 Q = (rgb.r < P.x) ? vec4(P.xyw, rgb.r) : vec4(rgb.r, P.yzx);
  277. float C = Q.x - min(Q.w, Q.y);
  278. float H = abs((Q.w - Q.y) / (6. * C + HCV_EPSILON) + Q.z);
  279. return vec3(H, C, Q.x);
  280. }
  281. vec3 rgb_to_hcy(vec3 rgb){
  282. const vec3 HCYwts = vec3(0.299, 0.587, 0.114);
  283. // Corrected by David Schaeffer
  284. vec3 HCV = rgb_to_hcv(rgb);
  285. float Y = dot(rgb, HCYwts);
  286. float Z = dot(hue_to_rgb(HCV.x), HCYwts);
  287. if (Y < Z) { HCV.y *= Z / (HCY_EPSILON + Y); }
  288. else { HCV.y *= (1. - Z) / (HCY_EPSILON + 1. - Y); }
  289. return vec3(HCV.x, HCV.y, Y);
  290. }
  291. #ifndef OUR_GLES
  292. subroutine void BrushRoutines();
  293. #endif
  294. #ifndef OUR_GLES
  295. subroutine(BrushRoutines)
  296. #endif
  297. void DoDabs(){
  298. ivec2 px = ivec2(gl_GlobalInvocationID.xy)+uBrushCorner;
  299. if(px.x<0||px.y<0||px.x>1024||px.y>1024) return;
  300. vec2 fpx=vec2(px),origfpx=fpx;
  301. fpx=uBrushCenter+rotate(fpx-uBrushCenter,uBrushAngle);
  302. fpx.x=uBrushCenter.x+(fpx.x-uBrushCenter.x)*(1.+uBrushSlender);
  303. float dd=distance(fpx,uBrushCenter); if(dd>uBrushSize) return;
  304. vec4 dabc=OurImageLoad(img, px);
  305. vec4 smudgec=pow(spectral_mix_unpre(pow(OurImageLoad(smudge_buckets,ivec2(1,0)),p1_22),pow(OurImageLoad(smudge_buckets,ivec2(0,0)),p1_22),uBrushRecentness),p22);
  306. vec4 final_color;
  307. dab(dd,origfpx,uBrushColor,uBrushSize,uBrushHardness,uBrushSmudge,smudgec,dabc,final_color);
  308. if(final_color.a>0.){
  309. if(uBrushMix==0){ dabc=final_color; }
  310. else if(uBrushMix==1){ dabc.rgb=final_color.rgb/final_color.a*dabc.a;}
  311. else if(uBrushMix==2){ vec3 xyz=rgb_to_hcy(dabc.rgb); xyz.xy=rgb_to_hcy(final_color.rgb).xy; dabc.rgb=hcy_to_rgb(xyz); }
  312. else if(uBrushMix==3){ dabc.rgb=dabc.rgb+final_color.rgb*0.01;dabc.a=dabc.a*0.99+final_color.a*0.01; }
  313. OurImageStore(img, px, dabc);
  314. }
  315. }
  316. #ifndef OUR_GLES
  317. subroutine(BrushRoutines)
  318. #endif
  319. void DoSample(){
  320. ivec2 p=ivec2(gl_GlobalInvocationID.xy);
  321. int DoSample=1; vec4 color;
  322. if(p.y==0){
  323. vec2 sp=round(vec2(sin(float(p.x)),cos(float(p.x)))*uBrushSize);
  324. ivec2 px=ivec2(sp)+uBrushCorner; if(px.x<0||px.y<0||px.x>=1024||px.y>=1024){ DoSample=0; }
  325. if(DoSample!=0){
  326. ivec2 b=uBrushCorner; if(b.x>=0&&b.y>=0&&b.x<1024&&b.y<1024){ OurImageStore(smudge_buckets,ivec2(128+WORKGROUP_SIZE,0),OurImageLoad(img, b)); }
  327. color=OurImageLoad(img, px);
  328. OurImageStore(smudge_buckets,ivec2(p.x+128,0),color);
  329. }
  330. }else{DoSample=0;}
  331. memoryBarrier();barrier(); if(DoSample==0) return;
  332. if(uBrushErasing==0 || p.x!=0) return;
  333. color=vec4(0.,0.,0.,0.); for(int i=0;i<WORKGROUP_SIZE;i++){ color=color+OurImageLoad(smudge_buckets, ivec2(i+128,0)); }
  334. color=spectral_mix_unpre(color/vec4(WORKGROUP_SIZE),OurImageLoad(smudge_buckets, ivec2(128+WORKGROUP_SIZE,0)),0.6*(1.0f-uBrushColor.a)); vec4 oldcolor=OurImageLoad(smudge_buckets, ivec2(0,0));
  335. OurImageStore(smudge_buckets,ivec2(1,0),uBrushErasing==2?color:oldcolor);
  336. OurImageStore(smudge_buckets,ivec2(0,0),color);
  337. }
  338. #ifdef OUR_GLES
  339. void uBrushRoutineSelection(){
  340. if(uBrushRoutineSelectionES==0){ DoDabs(); }
  341. else{ DoSample(); }
  342. }
  343. #else
  344. subroutine uniform BrushRoutines uBrushRoutineSelection;
  345. #endif
  346. void main() {
  347. uBrushRoutineSelection();
  348. }
  349. )";
  350. const char OUR_COMPOSITION_SHADER[] = R"(
  351. layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
  352. #ifdef OUR_GLES
  353. precision highp uimage2D;
  354. precision highp float;
  355. precision highp int;
  356. layout(r32ui, binding = 0) uniform uimage2D top;
  357. layout(r32ui, binding = 1) uniform uimage2D bottom;
  358. #else
  359. layout(rgba16ui, binding = 0) uniform uimage2D top;
  360. layout(rgba16ui, binding = 1) uniform uimage2D bottom;
  361. #endif
  362. uniform int uBlendMode;
  363. uniform float uAlphaTop;
  364. uniform float uAlphaBottom;
  365. #ifdef OUR_GLES
  366. vec4 cunpack(uint d){
  367. return vec4(float(d&0xFFu)/255.,float((d>>8u)&0xFFu)/255.,float((d>>16u)&0xFFu)/255.,float((d>>24u)&0xFFu)/255.);
  368. }
  369. uvec4 cpack(vec4 c){
  370. uint v= uint(uint(c.r*255.) | (uint(c.g*255.)<<8u) | (uint(c.b*255.)<<16u) | (uint(c.a*255.)<<24u));
  371. return uvec4(v,v,v,v);
  372. }
  373. #define OurImageLoad(img, p) \
  374. (cunpack(imageLoad(img,p).x))
  375. #define OurImageStore(img, p, color) \
  376. imageStore(img,p,cpack(color))
  377. #else
  378. #define OurImageLoad(img, p) \
  379. (vec4(imageLoad(img,p))/65535.)
  380. #define OurImageStore(img, p, color) \
  381. imageStore(img,p,uvec4(vec4(color)*65535.))
  382. #endif
  383. vec4 mix_over(vec4 colora, vec4 colorb){
  384. colora=colora*uAlphaTop/uAlphaBottom;
  385. vec4 c; c.a=colora.a+colorb.a*(1.0f-colora.a);
  386. c.rgb=(colora.rgb+colorb.rgb*(1.0f-colora.a));
  387. return c;
  388. }
  389. vec4 add_over(vec4 colora, vec4 colorb){
  390. colora=colora*uAlphaTop/uAlphaBottom;
  391. vec4 a=colora+colorb; a.a=clamp(a.a,0.,1.); return a;
  392. }
  393. void main() {
  394. ivec2 px=ivec2(gl_GlobalInvocationID.xy);
  395. vec4 c1=OurImageLoad(top,px); vec4 c2=OurImageLoad(bottom,px);
  396. vec4 c=(uBlendMode==0)?mix_over(c1,c2):add_over(c1,c2);
  397. OurImageStore(bottom,px,c);
  398. OurImageStore(top,px,vec4(1.));
  399. }
  400. )";