Repository navigation
Expand file tree
/
Copy patheffects.cpp
More file actions
181 lines (165 loc) · 6.58 KB
/
Copy patheffects.cpp
File metadata and controls
181 lines (165 loc) · 6.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "view/effects.h"
#include "config/config.h"
#include "scene/effect_registry.h"
#include <algorithm>
extern "C" {
#include <umbrielfx/render/effect.h>
}
// clang-format off
#include "wlr.h"
// clang-format on
namespace umbriel {
void clearWindowEffectSlots(wlr_scene_node* node) {
if (node != nullptr) {
wlr_scene_node_set_animation(node, FX_SLOT_WINDOW, nullptr, nullptr);
wlr_scene_node_set_animation(node, FX_SLOT_OVERLAY, nullptr, nullptr);
}
}
void ViewEffects::resetSlots() {
m_borderSlot = {};
m_windowSlot = {};
m_border.clear();
m_window.clear();
m_overlay = false;
}
void ViewEffects::syncNames(const Effects& effects) {
m_border = m_borderSlot.effectiveName();
m_window = m_windowSlot.effectiveName();
const EffectPreset* border = m_border.empty() ? nullptr : findEffectPreset(effects, m_border);
m_overlay = border != nullptr && !border->overlay.empty();
}
int ViewEffects::borderPadding() const {
if (m_border.empty()) {
return 0;
}
const EffectRegistry& registry = effectRegistry();
return borderPresetPadding(
registry.presetConfig(m_border), registry.preset(m_border, EffectKind::Border) != nullptr
);
}
void ViewEffects::track(const void* owner) {
if (std::ranges::find(m_owners, owner) == m_owners.end()) {
m_owners.push_back(owner);
}
}
void ViewEffects::untrack(const void* owner) {
if (owner == nullptr || std::erase(m_owners, owner) == 0) {
return;
}
effectRegistry().removeInstance(owner);
}
void ViewEffects::apply(const ApplyInput& input) {
EffectRegistry& registry = effectRegistry();
const bool gateOpen = input.border != nullptr && !m_border.empty() && borderEffectApplies(input.gate);
fx_effect_shader* shader = gateOpen ? registry.preset(m_border, EffectKind::Border) : nullptr;
const EffectPreset* preset = shader != nullptr ? registry.presetConfig(m_border) : nullptr;
const bool advancing = preset != nullptr && preset->animated && preset->speed > 0.0F;
const float seconds = advancing ? input.seconds * preset->speed : 0.0F;
if (preset == nullptr) {
if (input.border != nullptr) {
wlr_scene_node_set_animation(input.border, FX_SLOT_BORDER_EFFECT, nullptr, nullptr);
}
untrack(input.border);
} else {
fx_animation_parameters parameters{};
parameters.scale = input.scale;
registry.fillTimeUniforms(parameters, seconds, *preset, shader);
if (preset->light) {
parameters.light = {
.enabled = true,
.spread = static_cast<float>(preset->light->spread) * input.scale,
.intensity = preset->light->intensity,
.threshold = preset->light->threshold,
};
}
wlr_scene_node_set_animation(input.border, FX_SLOT_BORDER_EFFECT, shader, ¶meters);
track(input.border);
registry.updateInstance(
input.border,
{
.output = input.output,
.visible = wlr_scene_node_visible_in_box(input.border, &input.outputBox),
.readsTime = fx_effect_shader_reads(shader, "umbriel_time"),
.advancing = advancing && input.clockAdvancing,
}
);
}
applyWindowSlots(input, preset, seconds, advancing);
}
void ViewEffects::applyWindowSlots(
const ApplyInput& input, const EffectPreset* border, float borderSeconds, bool borderAdvancing
) {
if (input.surface == nullptr) {
return;
}
EffectRegistry& registry = effectRegistry();
// Window slot: the default or window_effect preset, regardless of focus. Overlay: the border preset's window
// preset, only while the border effect applies.
const EffectPreset* windowPreset = m_window.empty() ? nullptr : registry.presetConfig(m_window);
fx_effect_shader* windowShader = windowPreset != nullptr ? registry.preset(m_window, EffectKind::Window) : nullptr;
const EffectPreset* overlayPreset =
border != nullptr && !border->overlay.empty() ? registry.presetConfig(border->overlay) : nullptr;
fx_effect_shader* overlayShader =
overlayPreset != nullptr ? registry.preset(border->overlay, EffectKind::Window) : nullptr;
const auto bindSlot = [&](wlr_scene_node* node, unsigned slot, const EffectPreset* preset, fx_effect_shader* shader,
float seconds) {
if (shader == nullptr) {
wlr_scene_node_set_animation(node, slot, nullptr, nullptr);
return;
}
fx_animation_parameters parameters{};
parameters.scale = input.scale;
registry.fillTimeUniforms(parameters, seconds, *preset, shader);
wlr_scene_node_set_animation(node, slot, shader, ¶meters);
};
const auto bind = [&](wlr_scene_node* node) {
bindSlot(node, FX_SLOT_WINDOW, windowPreset, windowShader, input.seconds);
bindSlot(node, FX_SLOT_OVERLAY, overlayPreset, overlayShader, borderSeconds);
};
bind(input.surface);
// The isolated toplevel capture shows window effects only when effects are included in captures.
if (config().effects.inCapture) {
if (input.captureSurface != nullptr) {
bind(input.captureSurface);
}
} else {
clearWindowEffectSlots(input.captureSurface);
}
// Two instances on the surface node, keyed by the node and by its addons member so each has its own owner: the
// window slot follows the output's clock, the overlay advances only while the border's clock does.
const bool visible = (windowShader != nullptr || overlayShader != nullptr)
&& wlr_scene_node_visible_in_box(input.surface, &input.outputBox);
const auto instance = [&](const void* owner, const fx_effect_shader* program, bool advancing) {
if (program == nullptr) {
untrack(owner);
return;
}
track(owner);
registry.updateInstance(
owner,
{
.output = input.output,
.visible = visible,
.readsTime = fx_effect_shader_reads(program, "umbriel_time"),
.advancing = advancing && input.clockAdvancing,
}
);
};
instance(input.surface, windowShader, true);
instance(&input.surface->addons, overlayShader, borderAdvancing);
}
void ViewEffects::detach() {
EffectRegistry& registry = effectRegistry();
for (const void* owner : m_owners) {
registry.removeInstance(owner);
}
m_owners.clear();
}
void ViewEffects::detachNodes(wlr_scene_node* surface, wlr_scene_node* border) {
untrack(surface);
if (surface != nullptr) {
untrack(&surface->addons);
}
untrack(border);
}
} // namespace umbriel