aboutsummaryrefslogtreecommitdiff
path: root/wiki
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-04-21 20:10:35 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-04-21 20:16:54 +0400
commit49f5402669012be33f8cd111311c3e39fd4751c0 (patch)
treea90eab10775b63cddb0772923d43875ee13ef8b6 /wiki
parent2ecbb3f6f8ceacdccc66a597e372c70029325dbf (diff)
downloadniri-49f5402669012be33f8cd111311c3e39fd4751c0.tar.gz
niri-49f5402669012be33f8cd111311c3e39fd4751c0.tar.bz2
niri-49f5402669012be33f8cd111311c3e39fd4751c0.zip
Implement window-resize custom-shader
Diffstat (limited to 'wiki')
-rw-r--r--wiki/Configuration:-Animations.md41
-rw-r--r--wiki/examples/resize-custom-shader.frag152
2 files changed, 193 insertions, 0 deletions
diff --git a/wiki/Configuration:-Animations.md b/wiki/Configuration:-Animations.md
index 39ad6ebf..8c933fdd 100644
--- a/wiki/Configuration:-Animations.md
+++ b/wiki/Configuration:-Animations.md
@@ -224,6 +224,47 @@ animations {
}
```
+##### `custom-shader`
+
+<sup>Since: 0.1.6, experimental</sup>
+
+You can write a custom shader for drawing the window during a resize animation.
+
+See [this example shader](./examples/resize-custom-shader.frag) for a full documentation with several animations to experiment with.
+
+If a custom shader fails to compile, niri will print a warning and fall back to the default, or previous successfully compiled shader.
+
+> [!NOTE]
+>
+> Custom shaders do not have a backwards compatibility guarantee.
+> I may need to change their interface as I'm developing new features.
+
+```
+animations {
+ window-resize {
+ spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
+
+ custom-shader r"
+ #version 100
+ precision mediump float;
+
+ varying vec2 v_coords;
+ uniform mat3 input_to_curr_geo;
+ uniform sampler2D tex_next;
+ uniform mat3 geo_to_tex_next;
+ uniform float alpha;
+
+ void main() {
+ vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
+ vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
+ vec4 color = texture2D(tex_next, vec2(coords_tex_next));
+ gl_FragColor = color * alpha;
+ }
+ "
+ }
+}
+```
+
#### `config-notification-open-close`
The open/close animation of the config parse error and new default config notifications.
diff --git a/wiki/examples/resize-custom-shader.frag b/wiki/examples/resize-custom-shader.frag
new file mode 100644
index 00000000..2ac93738
--- /dev/null
+++ b/wiki/examples/resize-custom-shader.frag
@@ -0,0 +1,152 @@
+#version 100
+
+precision mediump float;
+
+// Coordinates of the current pixel.
+//
+// These range from 0 to 1 over the whole area of the shader. The location and
+// the size of the area are unspecified, but niri will make it large enough to
+// accomodate a crossfade.
+//
+// You very likely want to convert these coordinates to geometry coordinates
+// before using them (see below).
+varying vec2 v_coords;
+
+// Pixel size of the whole area of the shader.
+uniform vec2 size;
+
+// Matrix that converts the input v_coords into coordinates inside the current
+// window geometry.
+//
+// The window geometry is its "visible bounds" from the user's perspective.
+// After applying this matrix, the 0 to 1 coordinate range will correspond to
+// the current geometry (in the middle of a resize), and pixels outside the
+// geometry will have coordinates below 0 or above 1.
+uniform mat3 input_to_curr_geo;
+
+// Matrix that converts the input v_coords into coordinates inside the previous
+// (before resize) window geometry.
+uniform mat3 input_to_prev_geo;
+
+// Matrix that converts the input v_coords into coordinates inside the next
+// (after resize) window geometry.
+uniform mat3 input_to_next_geo;
+
+// Previous (before resize) window texture.
+uniform sampler2D tex_prev;
+
+// Matrix that converts geometry coordinates into the previous window texture
+// coordinates.
+//
+// The window texture can and will go outside the geometry (for client-side
+// decoration shadows for example), which is why this matrix is necessary.
+uniform mat3 geo_to_tex_prev;
+
+// Next (after resize) window texture.
+uniform sampler2D tex_next;
+
+// Matrix that converts geometry coordinates into the next window texture
+// coordinates.
+uniform mat3 geo_to_tex_next;
+
+// Unclamped progress of the resize.
+//
+// Goes from 0 to 1 but may overshoot and oscillate.
+uniform float progress;
+
+// Clamped progress of the resize.
+//
+// Goes from 0 to 1, but will stop at 1 as soon as it first reaches 1. Will not
+// overshoot or oscillate.
+uniform float clamped_progress;
+
+// Additional opacity to apply to the final color.
+uniform float alpha;
+
+// Example: fill the current geometry with a solid vertical gradient.
+vec4 solid_gradient() {
+ vec3 coords = input_to_curr_geo * vec3(v_coords, 1.0);
+
+ vec4 color = vec4(0.0);
+
+ // Paint only the area inside the current geometry.
+ if (0.0 <= coords.x && coords.x <= 1.0
+ && 0.0 <= coords.y && coords.y <= 1.0)
+ {
+ vec4 from = vec4(1.0, 0.0, 0.0, 1.0);
+ vec4 to = vec4(0.0, 1.0, 0.0, 1.0);
+ color = mix(from, to, coords.y);
+ }
+
+ return color;
+}
+
+// Example: crossfade between previous and next texture, stretched to the
+// current geometry.
+vec4 crossfade() {
+ vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
+
+ vec3 coords_tex_prev = geo_to_tex_prev * coords_curr_geo;
+ vec4 color_prev = texture2D(tex_prev, vec2(coords_tex_prev));
+
+ vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
+ vec4 color_next = texture2D(tex_next, vec2(coords_tex_next));
+
+ vec4 color = mix(color_prev, color_next, clamped_progress);
+ return color;
+}
+
+// Example: next texture, stretched to the current geometry.
+vec4 stretch_next() {
+ vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
+ vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
+ vec4 color = texture2D(tex_next, vec2(coords_tex_next));
+ return color;
+}
+
+// Example: next texture, stretched to the current geometry if smaller, and
+// cropped if bigger.
+vec4 stretch_or_crop_next() {
+ vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
+ vec3 coords_next_geo = input_to_next_geo * vec3(v_coords, 1.0);
+
+ vec3 coords_stretch = geo_to_tex_next * coords_curr_geo;
+ vec3 coords_crop = geo_to_tex_next * coords_next_geo;
+
+ // If the crop coord is smaller than the stretch coord, then the next
+ // texture size is bigger than the current geometry, which means that we
+ // can crop.
+ vec3 coords = coords_stretch;
+ if (coords_crop.x < coords_stretch.x)
+ coords.x = coords_crop.x;
+ if (coords_crop.y < coords_stretch.y)
+ coords.y = coords_crop.y;
+
+ vec4 color = texture2D(tex_next, vec2(coords));
+
+ // However, when we crop, we also want to crop out anything outside the
+ // current geometry. This is because the area of the shader is unspecified
+ // and usually bigger than the current geometry, so if we don't fill pixels
+ // outside with transparency, the texture will leak out.
+ //
+ // When stretching, this is not an issue because the area outside will
+ // correspond to client-side decoration shadows, which are already supposed
+ // to be outside.
+ if (coords_crop.x < coords_stretch.x
+ && (coords_curr_geo.x < 0.0 || 1.0 < coords_curr_geo.x))
+ color = vec4(0.0);
+ if (coords_crop.y < coords_stretch.y
+ && (coords_curr_geo.y < 0.0 || 1.0 < coords_curr_geo.y))
+ color = vec4(0.0);
+
+ return color;
+}
+
+// The main entry point of the shader.
+void main() {
+ // You can pick one of the example functions or write your own.
+ vec4 color = stretch_or_crop_next();
+
+ gl_FragColor = color * alpha;
+}
+