monte_carlo_blur.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import GObject from 'gi://GObject';
  2. import * as utils from '../conveniences/utils.js';
  3. const St = await utils.import_in_shell_only('gi://St');
  4. const Shell = await utils.import_in_shell_only('gi://Shell');
  5. const Clutter = await utils.import_in_shell_only('gi://Clutter');
  6. const SHADER_FILENAME = 'monte_carlo_blur.glsl';
  7. const DEFAULT_PARAMS = {
  8. radius: 2., iterations: 5, brightness: .6,
  9. width: 0, height: 0, use_base_pixel: true,
  10. prefer_closer_pixels: true,
  11. };
  12. export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ?
  13. { default_params: DEFAULT_PARAMS } :
  14. new GObject.registerClass({
  15. GTypeName: "MonteCarloBlurEffect",
  16. Properties: {
  17. 'radius': GObject.ParamSpec.double(
  18. `radius`,
  19. `Radius`,
  20. `Blur radius`,
  21. GObject.ParamFlags.READWRITE,
  22. 0.0, 2000.0,
  23. 2.0,
  24. ),
  25. 'iterations': GObject.ParamSpec.int(
  26. `iterations`,
  27. `Iterations`,
  28. `Blur iterations`,
  29. GObject.ParamFlags.READWRITE,
  30. 0, 64,
  31. 5,
  32. ),
  33. 'brightness': GObject.ParamSpec.double(
  34. `brightness`,
  35. `Brightness`,
  36. `Blur brightness`,
  37. GObject.ParamFlags.READWRITE,
  38. 0.0, 1.0,
  39. 0.6,
  40. ),
  41. 'width': GObject.ParamSpec.double(
  42. `width`,
  43. `Width`,
  44. `Width`,
  45. GObject.ParamFlags.READWRITE,
  46. 0.0, Number.MAX_SAFE_INTEGER,
  47. 0.0,
  48. ),
  49. 'height': GObject.ParamSpec.double(
  50. `height`,
  51. `Height`,
  52. `Height`,
  53. GObject.ParamFlags.READWRITE,
  54. 0.0, Number.MAX_SAFE_INTEGER,
  55. 0.0,
  56. ),
  57. 'use_base_pixel': GObject.ParamSpec.boolean(
  58. `use_base_pixel`,
  59. `Use base pixel`,
  60. `Use base pixel`,
  61. GObject.ParamFlags.READWRITE,
  62. true,
  63. ),
  64. 'prefer_closer_pixels': GObject.ParamSpec.boolean(
  65. `prefer_closer_pixels`,
  66. `Prefer closer pixels`,
  67. `Prefer closer pixels`,
  68. GObject.ParamFlags.READWRITE,
  69. true,
  70. ),
  71. }
  72. }, class MonteCarloBlurEffect extends Clutter.ShaderEffect {
  73. constructor(params) {
  74. super(params);
  75. utils.setup_params(this, params);
  76. // set shader source
  77. this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
  78. if (this._source)
  79. this.set_shader_source(this._source);
  80. const theme_context = St.ThemeContext.get_for_stage(global.stage);
  81. theme_context.connectObject(
  82. 'notify::scale-factor',
  83. _ => this.set_uniform_value('radius',
  84. parseFloat(this._radius * theme_context.scale_factor - 1e-6)
  85. ),
  86. this
  87. );
  88. }
  89. static get default_params() {
  90. return DEFAULT_PARAMS;
  91. }
  92. get radius() {
  93. return this._radius;
  94. }
  95. set radius(value) {
  96. if (this._radius !== value) {
  97. this._radius = value;
  98. const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
  99. this.set_uniform_value('radius', parseFloat(this._radius * scale_factor - 1e-6));
  100. this.set_enabled(this.radius > 0. && this.iterations > 0);
  101. }
  102. }
  103. get iterations() {
  104. return this._iterations;
  105. }
  106. set iterations(value) {
  107. if (this._iterations !== value) {
  108. this._iterations = value;
  109. this.set_uniform_value('iterations', this._iterations);
  110. this.set_enabled(this.radius > 0. && this.iterations > 0);
  111. }
  112. }
  113. get brightness() {
  114. return this._brightness;
  115. }
  116. set brightness(value) {
  117. if (this._brightness !== value) {
  118. this._brightness = value;
  119. this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6));
  120. }
  121. }
  122. get width() {
  123. return this._width;
  124. }
  125. set width(value) {
  126. if (this._width !== value) {
  127. this._width = value;
  128. this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6));
  129. }
  130. }
  131. get height() {
  132. return this._height;
  133. }
  134. set height(value) {
  135. if (this._height !== value) {
  136. this._height = value;
  137. this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6));
  138. }
  139. }
  140. get use_base_pixel() {
  141. return this._use_base_pixel;
  142. }
  143. set use_base_pixel(value) {
  144. if (this._use_base_pixel !== value) {
  145. this._use_base_pixel = value;
  146. this.set_uniform_value('use_base_pixel', this._use_base_pixel ? 1 : 0);
  147. }
  148. }
  149. get prefer_closer_pixels() {
  150. return this._prefer_closer_pixels;
  151. }
  152. set prefer_closer_pixels(value) {
  153. if (this._prefer_closer_pixels !== value) {
  154. this._prefer_closer_pixels = value;
  155. this.set_uniform_value('prefer_closer_pixels', this._prefer_closer_pixels ? 1 : 0);
  156. }
  157. }
  158. vfunc_set_actor(actor) {
  159. if (this._actor_connection_size_id) {
  160. let old_actor = this.get_actor();
  161. old_actor?.disconnect(this._actor_connection_size_id);
  162. }
  163. if (actor) {
  164. this.width = actor.width;
  165. this.height = actor.height;
  166. this._actor_connection_size_id = actor.connect('notify::size', _ => {
  167. this.width = actor.width;
  168. this.height = actor.height;
  169. });
  170. }
  171. else
  172. this._actor_connection_size_id = null;
  173. super.vfunc_set_actor(actor);
  174. }
  175. });