diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-21 20:10:35 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-21 20:16:54 +0400 |
| commit | 49f5402669012be33f8cd111311c3e39fd4751c0 (patch) | |
| tree | a90eab10775b63cddb0772923d43875ee13ef8b6 /wiki | |
| parent | 2ecbb3f6f8ceacdccc66a597e372c70029325dbf (diff) | |
| download | niri-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.md | 41 | ||||
| -rw-r--r-- | wiki/examples/resize-custom-shader.frag | 152 |
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; +} + |
