mirror of
https://github.com/YaLTeR/niri.git
synced 2024-09-11 12:35:58 +03:00
Implement custom shader for window-close anim
This commit is contained in:
parent
29c7552852
commit
9004c83954
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -186,7 +186,7 @@ dependencies = [
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand 2.0.2",
|
||||
"fastrand 2.1.0",
|
||||
"futures-lite 2.3.0",
|
||||
"slab",
|
||||
]
|
||||
@ -434,7 +434,7 @@ dependencies = [
|
||||
"async-channel",
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"fastrand 2.0.2",
|
||||
"fastrand 2.1.0",
|
||||
"futures-io",
|
||||
"futures-lite 2.3.0",
|
||||
"piper",
|
||||
@ -1081,9 +1081,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.2"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
@ -1225,7 +1225,7 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
||||
dependencies = [
|
||||
"fastrand 2.0.2",
|
||||
"fastrand 2.1.0",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"parking",
|
||||
@ -2203,6 +2203,7 @@ dependencies = [
|
||||
"clap",
|
||||
"directories",
|
||||
"drm-ffi 0.7.1",
|
||||
"fastrand 2.1.0",
|
||||
"futures-util",
|
||||
"git-version",
|
||||
"glam",
|
||||
@ -2583,7 +2584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand 2.0.2",
|
||||
"fastrand 2.1.0",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
@ -3337,7 +3338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.0.2",
|
||||
"fastrand 2.1.0",
|
||||
"rustix 0.38.32",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
@ -51,6 +51,7 @@ calloop = { version = "0.13.0", features = ["executor", "futures-io"] }
|
||||
clap = { workspace = true, features = ["string"] }
|
||||
directories = "5.0.1"
|
||||
drm-ffi = "0.7.1"
|
||||
fastrand = "2.1.0"
|
||||
futures-util = { version = "0.3.30", default-features = false, features = ["std", "io"] }
|
||||
git-version = "0.3.9"
|
||||
glam = "0.27.0"
|
||||
|
@ -552,18 +552,24 @@ impl Default for WindowOpenAnim {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct WindowCloseAnim(pub Animation);
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct WindowCloseAnim {
|
||||
pub anim: Animation,
|
||||
pub custom_shader: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for WindowCloseAnim {
|
||||
fn default() -> Self {
|
||||
Self(Animation {
|
||||
off: false,
|
||||
kind: AnimationKind::Easing(EasingParams {
|
||||
duration_ms: 150,
|
||||
curve: AnimationCurve::EaseOutQuad,
|
||||
}),
|
||||
})
|
||||
Self {
|
||||
anim: Animation {
|
||||
off: false,
|
||||
kind: AnimationKind::Easing(EasingParams {
|
||||
duration_ms: 150,
|
||||
curve: AnimationCurve::EaseOutQuad,
|
||||
}),
|
||||
},
|
||||
custom_shader: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1420,10 +1426,21 @@ where
|
||||
node: &knuffel::ast::SpannedNode<S>,
|
||||
ctx: &mut knuffel::decode::Context<S>,
|
||||
) -> Result<Self, DecodeError<S>> {
|
||||
let default = Self::default().0;
|
||||
Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
|
||||
Ok(false)
|
||||
})?))
|
||||
let default = Self::default().anim;
|
||||
let mut custom_shader = None;
|
||||
let anim = Animation::decode_node(node, ctx, default, |child, ctx| {
|
||||
if &**child.node_name == "custom-shader" {
|
||||
custom_shader = parse_arg_node("custom-shader", child, ctx)?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
anim,
|
||||
custom_shader,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,6 +500,9 @@ impl Tty {
|
||||
if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
|
||||
shaders::set_custom_resize_program(gles_renderer, Some(src));
|
||||
}
|
||||
if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
|
||||
shaders::set_custom_close_program(gles_renderer, Some(src));
|
||||
}
|
||||
drop(config);
|
||||
|
||||
niri.layout.update_shaders();
|
||||
|
@ -140,6 +140,9 @@ impl Winit {
|
||||
if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
|
||||
shaders::set_custom_resize_program(renderer, Some(src));
|
||||
}
|
||||
if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
|
||||
shaders::set_custom_close_program(renderer, Some(src));
|
||||
}
|
||||
drop(config);
|
||||
|
||||
niri.layout.update_shaders();
|
||||
|
@ -1,6 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use glam::{Mat3, Vec2};
|
||||
use niri_config::BlockOutFrom;
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::texture::TextureRenderElement;
|
||||
@ -8,13 +10,15 @@ use smithay::backend::renderer::element::utils::{
|
||||
Relocate, RelocateRenderElement, RescaleRenderElement,
|
||||
};
|
||||
use smithay::backend::renderer::element::{Id, Kind, RenderElement};
|
||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
||||
use smithay::backend::renderer::Renderer as _;
|
||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform};
|
||||
use smithay::backend::renderer::{Renderer as _, Texture};
|
||||
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
|
||||
|
||||
use crate::animation::Animation;
|
||||
use crate::niri_render_elements;
|
||||
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||
use crate::render_helpers::shader_element::ShaderRenderElement;
|
||||
use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders};
|
||||
use crate::render_helpers::snapshot::RenderSnapshot;
|
||||
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget};
|
||||
|
||||
@ -49,11 +53,15 @@ pub struct ClosingWindow {
|
||||
|
||||
/// The closing animation.
|
||||
anim: Animation,
|
||||
|
||||
/// Random seed for the shader.
|
||||
random_seed: f32,
|
||||
}
|
||||
|
||||
niri_render_elements! {
|
||||
ClosingWindowRenderElement => {
|
||||
Texture = RelocateRenderElement<RescaleRenderElement<PrimaryGpuTextureRenderElement>>,
|
||||
Shader = ShaderRenderElement,
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,6 +108,7 @@ impl ClosingWindow {
|
||||
texture_offset,
|
||||
blocked_out_texture_offset,
|
||||
anim,
|
||||
random_seed: fastrand::f32(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -108,16 +117,18 @@ impl ClosingWindow {
|
||||
}
|
||||
|
||||
pub fn are_animations_ongoing(&self) -> bool {
|
||||
!self.anim.is_clamped_done()
|
||||
!self.anim.is_done()
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
renderer: &mut GlesRenderer,
|
||||
view_rect: Rectangle<i32, Logical>,
|
||||
scale: Scale<f64>,
|
||||
target: RenderTarget,
|
||||
) -> ClosingWindowRenderElement {
|
||||
let val = self.anim.clamped_value();
|
||||
let progress = self.anim.value();
|
||||
let clamped_progress = self.anim.clamped_value().clamp(0., 1.);
|
||||
|
||||
let (texture, offset) = if target.should_block_out(self.block_out_from) {
|
||||
(&self.blocked_out_texture, self.blocked_out_texture_offset)
|
||||
@ -125,6 +136,43 @@ impl ClosingWindow {
|
||||
(&self.texture, self.texture_offset)
|
||||
};
|
||||
|
||||
if Shaders::get(renderer).program(ProgramType::Close).is_some() {
|
||||
let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32);
|
||||
let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32);
|
||||
|
||||
let geo_loc = Vec2::new(self.pos.x as f32, self.pos.y as f32);
|
||||
let geo_size = Vec2::new(self.geo_size.w as f32, self.geo_size.h as f32);
|
||||
|
||||
let input_to_geo = Mat3::from_scale(area_size / geo_size)
|
||||
* Mat3::from_translation((area_loc - geo_loc) / area_size);
|
||||
|
||||
let tex_scale = Vec2::new(self.texture_scale.x as f32, self.texture_scale.y as f32);
|
||||
let tex_loc = Vec2::new(offset.x as f32, offset.y as f32);
|
||||
let tex_size = Vec2::new(texture.width() as f32, texture.height() as f32) / tex_scale;
|
||||
|
||||
let geo_to_tex =
|
||||
Mat3::from_translation(-tex_loc / tex_size) * Mat3::from_scale(geo_size / tex_size);
|
||||
|
||||
return ShaderRenderElement::new(
|
||||
ProgramType::Close,
|
||||
view_rect.size,
|
||||
None,
|
||||
1.,
|
||||
vec![
|
||||
mat3_uniform("niri_input_to_geo", input_to_geo),
|
||||
Uniform::new("niri_geo_size", geo_size.to_array()),
|
||||
mat3_uniform("niri_geo_to_tex", geo_to_tex),
|
||||
Uniform::new("niri_progress", progress as f32),
|
||||
Uniform::new("niri_clamped_progress", clamped_progress as f32),
|
||||
Uniform::new("niri_random_seed", self.random_seed),
|
||||
],
|
||||
HashMap::from([(String::from("niri_tex"), texture.clone())]),
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.with_location(Point::from((0, 0)))
|
||||
.into();
|
||||
}
|
||||
|
||||
let elem = TextureRenderElement::from_static_texture(
|
||||
Id::new(),
|
||||
self.texture_renderer_id,
|
||||
@ -132,7 +180,7 @@ impl ClosingWindow {
|
||||
texture.clone(),
|
||||
self.texture_scale.x as i32,
|
||||
Transform::Normal,
|
||||
Some(val.clamp(0., 1.) as f32),
|
||||
Some(1. - clamped_progress as f32),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@ -145,7 +193,7 @@ impl ClosingWindow {
|
||||
let elem = RescaleRenderElement::from_element(
|
||||
elem,
|
||||
(center - offset).to_physical_precise_round(scale),
|
||||
(val / 5. + 0.8).max(0.),
|
||||
((1. - clamped_progress) / 5. + 0.8).max(0.),
|
||||
);
|
||||
|
||||
let mut location = self.pos.to_f64() + offset;
|
||||
|
@ -1344,7 +1344,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
tile_pos.x -= offset;
|
||||
}
|
||||
|
||||
let anim = Animation::new(1., 0., 0., self.options.animations.window_close.0);
|
||||
let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim);
|
||||
|
||||
let res = ClosingWindow::new(
|
||||
renderer,
|
||||
@ -2095,7 +2095,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
// Draw the closing windows on top.
|
||||
let view_rect = Rectangle::from_loc_and_size((self.view_pos(), 0), self.view_size);
|
||||
for closing in &self.closing_windows {
|
||||
let elem = closing.render(view_rect, output_scale, target);
|
||||
let elem = closing.render(renderer.as_gles_renderer(), view_rect, output_scale, target);
|
||||
rv.push(elem.into());
|
||||
}
|
||||
|
||||
|
10
src/niri.rs
10
src/niri.rs
@ -941,6 +941,16 @@ impl State {
|
||||
shaders_changed = true;
|
||||
}
|
||||
|
||||
if config.animations.window_close.custom_shader
|
||||
!= old_config.animations.window_close.custom_shader
|
||||
{
|
||||
let src = config.animations.window_close.custom_shader.as_deref();
|
||||
self.backend.with_primary_renderer(|renderer| {
|
||||
shaders::set_custom_close_program(renderer, src);
|
||||
});
|
||||
shaders_changed = true;
|
||||
}
|
||||
|
||||
if config.debug != old_config.debug {
|
||||
debug_config_changed = true;
|
||||
}
|
||||
|
16
src/render_helpers/shaders/close_epilogue.frag
Normal file
16
src/render_helpers/shaders/close_epilogue.frag
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
void main() {
|
||||
vec3 coords_geo = niri_input_to_geo * vec3(niri_v_coords, 1.0);
|
||||
vec3 size_geo = vec3(niri_geo_size, 1.0);
|
||||
|
||||
vec4 color = close_color(coords_geo, size_geo);
|
||||
|
||||
color = color * niri_alpha;
|
||||
|
||||
#if defined(DEBUG_FLAGS)
|
||||
if (niri_tint == 1.0)
|
||||
color = vec4(0.0, 0.2, 0.0, 0.2) + color * 0.8;
|
||||
#endif
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
21
src/render_helpers/shaders/close_prelude.frag
Normal file
21
src/render_helpers/shaders/close_prelude.frag
Normal file
@ -0,0 +1,21 @@
|
||||
precision mediump float;
|
||||
|
||||
#if defined(DEBUG_FLAGS)
|
||||
uniform float niri_tint;
|
||||
#endif
|
||||
|
||||
varying vec2 niri_v_coords;
|
||||
uniform vec2 niri_size;
|
||||
|
||||
uniform mat3 niri_input_to_geo;
|
||||
uniform vec2 niri_geo_size;
|
||||
|
||||
uniform sampler2D niri_tex;
|
||||
uniform mat3 niri_geo_to_tex;
|
||||
|
||||
uniform float niri_progress;
|
||||
uniform float niri_clamped_progress;
|
||||
uniform float niri_random_seed;
|
||||
|
||||
uniform float niri_alpha;
|
||||
|
@ -14,12 +14,14 @@ pub struct Shaders {
|
||||
pub clipped_surface: Option<GlesTexProgram>,
|
||||
pub resize: Option<ShaderProgram>,
|
||||
pub custom_resize: RefCell<Option<ShaderProgram>>,
|
||||
pub custom_close: RefCell<Option<ShaderProgram>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ProgramType {
|
||||
Border,
|
||||
Resize,
|
||||
Close,
|
||||
}
|
||||
|
||||
impl Shaders {
|
||||
@ -72,6 +74,7 @@ impl Shaders {
|
||||
clipped_surface,
|
||||
resize,
|
||||
custom_resize: RefCell::new(None),
|
||||
custom_close: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +98,13 @@ impl Shaders {
|
||||
self.custom_resize.replace(program)
|
||||
}
|
||||
|
||||
pub fn replace_custom_close_program(
|
||||
&self,
|
||||
program: Option<ShaderProgram>,
|
||||
) -> Option<ShaderProgram> {
|
||||
self.custom_close.replace(program)
|
||||
}
|
||||
|
||||
pub fn program(&self, program: ProgramType) -> Option<ShaderProgram> {
|
||||
match program {
|
||||
ProgramType::Border => self.border.clone(),
|
||||
@ -103,6 +113,7 @@ impl Shaders {
|
||||
.borrow()
|
||||
.clone()
|
||||
.or_else(|| self.resize.clone()),
|
||||
ProgramType::Close => self.custom_close.borrow().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,6 +173,49 @@ pub fn set_custom_resize_program(renderer: &mut GlesRenderer, src: Option<&str>)
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_close_program(
|
||||
renderer: &mut GlesRenderer,
|
||||
src: &str,
|
||||
) -> Result<ShaderProgram, GlesError> {
|
||||
let mut program = include_str!("close_prelude.frag").to_string();
|
||||
program.push_str(src);
|
||||
program.push_str(include_str!("close_epilogue.frag"));
|
||||
|
||||
ShaderProgram::compile(
|
||||
renderer,
|
||||
&program,
|
||||
&[
|
||||
UniformName::new("niri_input_to_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_geo_size", UniformType::_2f),
|
||||
UniformName::new("niri_geo_to_tex", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_progress", UniformType::_1f),
|
||||
UniformName::new("niri_clamped_progress", UniformType::_1f),
|
||||
UniformName::new("niri_random_seed", UniformType::_1f),
|
||||
],
|
||||
&["niri_tex"],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_custom_close_program(renderer: &mut GlesRenderer, src: Option<&str>) {
|
||||
let program = if let Some(src) = src {
|
||||
match compile_close_program(renderer, src) {
|
||||
Ok(program) => Some(program),
|
||||
Err(err) => {
|
||||
warn!("error compiling custom close shader: {err:?}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(prev) = Shaders::get(renderer).replace_custom_close_program(program) {
|
||||
if let Err(err) = prev.destroy(renderer) {
|
||||
warn!("error destroying previous custom close shader: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mat3_uniform(name: &str, mat: Mat3) -> Uniform {
|
||||
Uniform::new(
|
||||
name,
|
||||
|
@ -169,6 +169,47 @@ animations {
|
||||
}
|
||||
```
|
||||
|
||||
##### `custom-shader`
|
||||
|
||||
<sup>Since: 0.1.6, experimental</sup>
|
||||
|
||||
You can write a custom shader for drawing the window during a close animation.
|
||||
|
||||
See [this example shader](./examples/close-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.
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> Custom shaders do not have a backwards compatibility guarantee.
|
||||
> I may need to change their interface as I'm developing new features.
|
||||
|
||||
Example: close will fill the current geometry with a solid gradient that gradually fades away.
|
||||
|
||||
```
|
||||
animations {
|
||||
window-resize {
|
||||
spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
|
||||
|
||||
custom-shader r"
|
||||
vec4 close_color(vec3 coords_geo, vec3 size_geo) {
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
if (0.0 <= coords_geo.x && coords_geo.x <= 1.0
|
||||
&& 0.0 <= coords_geo.y && coords_geo.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_geo.y);
|
||||
}
|
||||
|
||||
return color * (1.0 - niri_clamped_progress);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `horizontal-view-movement`
|
||||
|
||||
All horizontal camera view movement animations, such as:
|
||||
|
113
wiki/examples/close_custom_shader.frag
Normal file
113
wiki/examples/close_custom_shader.frag
Normal file
@ -0,0 +1,113 @@
|
||||
// Your shader must contain one function (see the bottom of this file).
|
||||
//
|
||||
// It should not contain any uniform definitions or anything else, as niri
|
||||
// provides them for you.
|
||||
//
|
||||
// All symbols defined by niri will have a niri_ prefix, so don't use it for
|
||||
// your own variables and functions.
|
||||
|
||||
// The function that you must define looks like this:
|
||||
vec4 close_color(vec3 coords_geo, vec3 size_geo) {
|
||||
vec4 color = /* ...compute the color... */;
|
||||
return color;
|
||||
}
|
||||
|
||||
// It takes as input:
|
||||
//
|
||||
// * coords_geo: coordinates of the current pixel relative to the window
|
||||
// geometry.
|
||||
//
|
||||
// These are homogeneous (the Z component is equal to 1) and scaled in such a
|
||||
// way that the 0 to 1 coordinates lie within the window geometry. Pixels
|
||||
// outside the window geometry will have coordinates below 0 or above 1.
|
||||
//
|
||||
// The window geometry is its "visible bounds" from the user's perspective.
|
||||
//
|
||||
// The shader runs over the full screen area, so you must expect and handle
|
||||
// coordinates outside the [0, 1] range. If the window is scrolled off-screen,
|
||||
// all of the coordinates to the shader can fall outside the [0, 1] range.
|
||||
//
|
||||
// * size_geo: size of the window geometry in logical pixels.
|
||||
//
|
||||
// It is homogeneous (the Z component is equal to 1).
|
||||
//
|
||||
// The function must return the color of the pixel (with premultiplied alpha).
|
||||
// The pixel color will be further processed by niri (for example, to apply the
|
||||
// final opacity from window rules).
|
||||
|
||||
// Now let's go over the uniforms that niri defines.
|
||||
//
|
||||
// You should only rely on the uniforms documented here. Any other uniforms can
|
||||
// change or be removed without notice.
|
||||
|
||||
// The window texture.
|
||||
uniform sampler2D niri_tex;
|
||||
|
||||
// Matrix that converts geometry coordinates into the 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 niri_geo_to_tex;
|
||||
|
||||
|
||||
// Unclamped progress of the animation.
|
||||
//
|
||||
// Goes from 0 to 1 but may overshoot and oscillate.
|
||||
uniform float niri_progress;
|
||||
|
||||
// Clamped progress of the animation.
|
||||
//
|
||||
// Goes from 0 to 1, but will stop at 1 as soon as it first reaches 1. Will not
|
||||
// overshoot or oscillate.
|
||||
uniform float niri_clamped_progress;
|
||||
|
||||
// Random float in [0; 1), consistent for the duration of the animation.
|
||||
uniform float niri_random_seed;
|
||||
|
||||
// Now let's look at some examples. You can copy everything below this line
|
||||
// into your custom-shader to experiment.
|
||||
|
||||
// Example: fill the current geometry with a solid vertical gradient and
|
||||
// gradually make transparent.
|
||||
vec4 solid_gradient(vec3 coords_geo, vec3 size_geo) {
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// Paint only the area inside the current geometry.
|
||||
if (0.0 <= coords_geo.x && coords_geo.x <= 1.0
|
||||
&& 0.0 <= coords_geo.y && coords_geo.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_geo.y);
|
||||
}
|
||||
|
||||
// Make it transparent.
|
||||
color *= (1.0 - niri_clamped_progress);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// Example: gradually scale down and make transparent, equivalent to the
|
||||
// default closing animation.
|
||||
vec4 default_close(vec3 coords_geo, vec3 size_geo) {
|
||||
// Scale down the window.
|
||||
float scale = max(0.0, ((1.0 - niri_clamped_progress) / 5.0 + 0.8));
|
||||
coords_geo = vec3((coords_geo.xy - vec2(0.5)) / scale + vec2(0.5), 1.0);
|
||||
|
||||
// Get color from the window texture.
|
||||
vec3 coords_tex = niri_geo_to_tex * coords_geo;
|
||||
vec4 color = texture2D(niri_tex, coords_tex.st);
|
||||
|
||||
// Make the window transparent.
|
||||
color *= (1.0 - niri_clamped_progress);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// This is the function that you must define.
|
||||
vec4 close_color(vec3 coords_geo, vec3 size_geo) {
|
||||
// You can pick one of the example functions or write your own.
|
||||
return solid_gradient(coords_geo, size_geo);
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
// final opacity from window rules).
|
||||
|
||||
// Now let's go over the uniforms that niri defines.
|
||||
//
|
||||
// You should only rely on the uniforms documented here. Any other uniforms can
|
||||
// change or be removed without notice.
|
||||
|
||||
// Previous (before resize) window texture.
|
||||
uniform sampler2D niri_tex_prev;
|
||||
@ -65,12 +68,12 @@ uniform mat3 niri_curr_geo_to_prev_geo;
|
||||
uniform mat3 niri_curr_geo_to_next_geo;
|
||||
|
||||
|
||||
// Unclamped progress of the resize.
|
||||
// Unclamped progress of the animation.
|
||||
//
|
||||
// Goes from 0 to 1 but may overshoot and oscillate.
|
||||
uniform float niri_progress;
|
||||
|
||||
// Clamped progress of the resize.
|
||||
// Clamped progress of the animation.
|
||||
//
|
||||
// Goes from 0 to 1, but will stop at 1 as soon as it first reaches 1. Will not
|
||||
// overshoot or oscillate.
|
||||
|
Loading…
Reference in New Issue
Block a user