monte_carlo_blur.js 5.6 KB

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