canvas_sdf.glsl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* clang-format off */
  2. #[modes]
  3. mode_load = #define MODE_LOAD
  4. mode_load_shrink = #define MODE_LOAD_SHRINK
  5. mode_process = #define MODE_PROCESS
  6. mode_store = #define MODE_STORE
  7. mode_store_shrink = #define MODE_STORE_SHRINK
  8. #[specializations]
  9. #[vertex]
  10. layout(location = 0) in vec2 vertex_attrib;
  11. /* clang-format on */
  12. uniform ivec2 size;
  13. uniform int stride;
  14. uniform int shift;
  15. uniform ivec2 base_size;
  16. void main() {
  17. gl_Position = vec4(vertex_attrib, 1.0, 1.0);
  18. }
  19. /* clang-format off */
  20. #[fragment]
  21. #define SDF_MAX_LENGTH 16384.0
  22. #if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK)
  23. uniform lowp sampler2D src_pixels;//texunit:0
  24. #else
  25. uniform highp isampler2D src_process;//texunit:0
  26. #endif
  27. uniform ivec2 size;
  28. uniform int stride;
  29. uniform int shift;
  30. uniform ivec2 base_size;
  31. #if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK) || defined(MODE_PROCESS)
  32. layout(location = 0) out ivec4 distance_field;
  33. #else
  34. layout(location = 0) out vec4 distance_field;
  35. #endif
  36. vec4 float_to_vec4(float p_float) {
  37. highp vec4 comp = fract(p_float * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
  38. comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
  39. return comp;
  40. }
  41. void main() {
  42. ivec2 pos = ivec2(gl_FragCoord.xy);
  43. #ifdef MODE_LOAD
  44. bool solid = texelFetch(src_pixels, pos, 0).r > 0.5;
  45. distance_field = solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0);
  46. #endif
  47. #ifdef MODE_LOAD_SHRINK
  48. int s = 1 << shift;
  49. ivec2 base = pos << shift;
  50. ivec2 center = base + ivec2(shift);
  51. ivec2 rel = ivec2(32767);
  52. float d = 1e20;
  53. int found = 0;
  54. int solid_found = 0;
  55. for (int i = 0; i < s; i++) {
  56. for (int j = 0; j < s; j++) {
  57. ivec2 src_pos = base + ivec2(i, j);
  58. if (any(greaterThanEqual(src_pos, base_size))) {
  59. continue;
  60. }
  61. bool solid = texelFetch(src_pixels, src_pos, 0).r > 0.5;
  62. if (solid) {
  63. float dist = length(vec2(src_pos - center));
  64. if (dist < d) {
  65. d = dist;
  66. rel = src_pos;
  67. }
  68. solid_found++;
  69. }
  70. found++;
  71. }
  72. }
  73. if (solid_found == found) {
  74. //mark solid only if all are solid
  75. rel = ivec2(-32767);
  76. }
  77. distance_field = ivec4(rel, 0, 0);
  78. #endif
  79. #ifdef MODE_PROCESS
  80. ivec2 base = pos << shift;
  81. ivec2 center = base + ivec2(shift);
  82. ivec2 rel = texelFetch(src_process, pos, 0).xy;
  83. bool solid = rel.x < 0;
  84. if (solid) {
  85. rel = -rel - ivec2(1);
  86. }
  87. if (center != rel) {
  88. //only process if it does not point to itself
  89. const int ofs_table_size = 8;
  90. const ivec2 ofs_table[ofs_table_size] = ivec2[](
  91. ivec2(-1, -1),
  92. ivec2(0, -1),
  93. ivec2(+1, -1),
  94. ivec2(-1, 0),
  95. ivec2(+1, 0),
  96. ivec2(-1, +1),
  97. ivec2(0, +1),
  98. ivec2(+1, +1));
  99. float dist = length(vec2(rel - center));
  100. for (int i = 0; i < ofs_table_size; i++) {
  101. ivec2 src_pos = pos + ofs_table[i] * stride;
  102. if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, size))) {
  103. continue;
  104. }
  105. ivec2 src_rel = texelFetch(src_process, src_pos, 0).xy;
  106. bool src_solid = src_rel.x < 0;
  107. if (src_solid) {
  108. src_rel = -src_rel - ivec2(1);
  109. }
  110. if (src_solid != solid) {
  111. src_rel = ivec2(src_pos << shift); //point to itself if of different type
  112. }
  113. float src_dist = length(vec2(src_rel - center));
  114. if (src_dist < dist) {
  115. dist = src_dist;
  116. rel = src_rel;
  117. }
  118. }
  119. }
  120. if (solid) {
  121. rel = -rel - ivec2(1);
  122. }
  123. distance_field = ivec4(rel, 0, 0);
  124. #endif
  125. #ifdef MODE_STORE
  126. ivec2 rel = texelFetch(src_process, pos, 0).xy;
  127. bool solid = rel.x < 0;
  128. if (solid) {
  129. rel = -rel - ivec2(1);
  130. }
  131. float d = length(vec2(rel - pos));
  132. if (solid) {
  133. d = -d;
  134. }
  135. d /= SDF_MAX_LENGTH;
  136. d = clamp(d, -1.0, 1.0);
  137. distance_field = float_to_vec4(d*0.5+0.5);
  138. #endif
  139. #ifdef MODE_STORE_SHRINK
  140. ivec2 base = pos << shift;
  141. ivec2 center = base + ivec2(shift);
  142. ivec2 rel = texelFetch(src_process, pos, 0).xy;
  143. bool solid = rel.x < 0;
  144. if (solid) {
  145. rel = -rel - ivec2(1);
  146. }
  147. float d = length(vec2(rel - center));
  148. if (solid) {
  149. d = -d;
  150. }
  151. d /= SDF_MAX_LENGTH;
  152. d = clamp(d, -1.0, 1.0);
  153. distance_field = float_to_vec4(d*0.5+0.5);
  154. #endif
  155. }