Blender V5.0
iterator.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2003-2024 Blender Authors
3 * SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later */
6
10
11#include <cstring>
12
13#include "DNA_sequence_types.h"
14
15#include "BLI_listbase.h"
16
17#include "SEQ_connect.hh"
18#include "SEQ_effects.hh"
19#include "SEQ_iterator.hh"
20#include "SEQ_relations.hh"
21#include "SEQ_render.hh"
22#include "SEQ_time.hh"
23
24namespace blender::seq {
25
26static bool strip_for_each_recursive(ListBase *seqbase, ForEachFunc callback, void *user_data)
27{
28 LISTBASE_FOREACH (Strip *, strip, seqbase) {
29 if (!callback(strip, user_data)) {
30 /* Callback signaled stop, return. */
31 return false;
32 }
33 if (strip->type == STRIP_TYPE_META) {
34 if (!strip_for_each_recursive(&strip->seqbase, callback, user_data)) {
35 return false;
36 }
37 }
38 }
39 return true;
40}
41
43 blender::FunctionRef<bool(Strip *)> callback)
44{
45 LISTBASE_FOREACH (Strip *, strip, seqbase) {
46 if (!callback(strip)) {
47 /* Callback signaled stop, return. */
48 return false;
49 }
50 if (strip->type == STRIP_TYPE_META) {
51 if (!strip_for_each_recursive(&strip->seqbase, callback)) {
52 return false;
53 }
54 }
55 }
56 return true;
57}
58
59void foreach_strip(ListBase *seqbase, ForEachFunc callback, void *user_data)
60{
61 strip_for_each_recursive(seqbase, callback, user_data);
62}
63
64void foreach_strip(ListBase *seqbase, blender::FunctionRef<bool(Strip *)> callback)
65{
66 strip_for_each_recursive(seqbase, callback);
67}
68
70 const Scene *scene,
71 ListBase *seqbase,
72 void strip_query_func(const Scene *scene,
73 Strip *strip_reference,
74 ListBase *seqbase,
75 VectorSet<Strip *> &strips))
76{
77 VectorSet<Strip *> strips;
78 strip_query_func(scene, strip_reference, seqbase, strips);
79 return strips;
80}
81
82void iterator_set_expand(const Scene *scene,
83 ListBase *seqbase,
84 VectorSet<Strip *> &strips,
85 void strip_query_func(const Scene *scene,
86 Strip *strip_reference,
87 ListBase *seqbase,
88 VectorSet<Strip *> &strips))
89{
90 /* Collect expanded results for each sequence in provided VectorSet. */
91 VectorSet<Strip *> query_matches;
92
93 for (Strip *strip : strips) {
94 query_matches.add_multiple(query_by_reference(strip, scene, seqbase, strip_query_func));
95 }
96
97 /* Merge all expanded results in provided VectorSet. */
98 strips.add_multiple(query_matches);
99}
100
101static void query_all_strips_recursive(const ListBase *seqbase, VectorSet<Strip *> &strips)
102{
103 LISTBASE_FOREACH (Strip *, strip, seqbase) {
104 if (strip->type == STRIP_TYPE_META) {
105 query_all_strips_recursive(&strip->seqbase, strips);
106 }
107 strips.add(strip);
108 }
109}
110
112{
113 VectorSet<Strip *> strips;
114 query_all_strips_recursive(seqbase, strips);
115 return strips;
116}
117
118static void query_strips_recursive_at_frame(const Scene *scene,
119 const ListBase *seqbase,
120 const int timeline_frame,
121 VectorSet<Strip *> &strips)
122{
123 LISTBASE_FOREACH (Strip *, strip, seqbase) {
124 if (!time_strip_intersects_frame(scene, strip, timeline_frame)) {
125 continue;
126 }
127 if (strip->type == STRIP_TYPE_META) {
128 query_strips_recursive_at_frame(scene, &strip->seqbase, timeline_frame, strips);
129 }
130 strips.add(strip);
131 }
132}
133
135 const ListBase *seqbase,
136 const int timeline_frame)
137{
138 VectorSet<Strip *> strips;
139 query_strips_recursive_at_frame(scene, seqbase, timeline_frame, strips);
140 return strips;
141}
142
144{
145 VectorSet<Strip *> strips;
146 LISTBASE_FOREACH (Strip *, strip, seqbase) {
147 strips.add(strip);
148 }
149 return strips;
150}
151
153{
154 VectorSet<Strip *> strips;
155 LISTBASE_FOREACH (Strip *, strip, seqbase) {
156 if ((strip->flag & SELECT) != 0) {
157 strips.add(strip);
158 }
159 }
160 return strips;
161}
162
164 ListBase *seqbase,
165 const int timeline_frame)
166{
167 VectorSet<Strip *> strips;
168
169 LISTBASE_FOREACH (Strip *, strip, seqbase) {
170 if (time_strip_intersects_frame(scene, strip, timeline_frame)) {
171 strips.add(strip);
172 }
173 }
174 return strips;
175}
176
177static void collection_filter_channel_up_to_incl(VectorSet<Strip *> &strips, const int channel)
178{
179 strips.remove_if([&](Strip *strip) { return strip->channel > channel; });
180}
181
182/* Check if strip must be rendered. This depends on whole stack in some cases, not only strip
183 * itself. Order of applying these conditions is important. */
184bool must_render_strip(const VectorSet<Strip *> &strips, Strip *strip)
185{
186 bool strip_have_effect_in_stack = false;
187 for (Strip *strip_iter : strips) {
188 /* Strips is below another strip with replace blending are not rendered. */
189 if (strip_iter->blend_mode == STRIP_BLEND_REPLACE && strip->channel < strip_iter->channel) {
190 return false;
191 }
192
193 if (strip_iter->is_effect() && relation_is_effect_of_strip(strip_iter, strip)) {
194 /* Strips in same channel or higher than its effect are rendered. */
195 if (strip->channel >= strip_iter->channel) {
196 return true;
197 }
198 /* Mark that this strip has effect in stack, that is above the strip. */
199 strip_have_effect_in_stack = true;
200 }
201 }
202
203 /* All non-generator effects are rendered (with respect to conditions above). */
204 if (strip->is_effect() && effect_get_num_inputs(strip->type) != 0) {
205 return true;
206 }
207
208 /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */
209 if (strip_have_effect_in_stack) {
210 return false;
211 }
212
213 return true;
214}
215
216/* Remove strips we don't want to render from VectorSet. */
218{
219 /* Remove sound strips and muted strips from VectorSet, because these are not rendered.
220 * Function #must_render_strip() don't have to check for these strips anymore. */
221 strips.remove_if([&](Strip *strip) {
222 return strip->type == STRIP_TYPE_SOUND_RAM || render_is_muted(channels, strip);
223 });
224
225 strips.remove_if([&](Strip *strip) { return !must_render_strip(strips, strip); });
226}
227
229 ListBase *channels,
230 ListBase *seqbase,
231 const int timeline_frame,
232 const int displayed_channel)
233{
234 VectorSet strips = query_strips_at_frame(scene, seqbase, timeline_frame);
235 if (displayed_channel != 0) {
236 collection_filter_channel_up_to_incl(strips, displayed_channel);
237 }
238 collection_filter_rendered_strips(strips, channels);
239 return strips;
240}
241
243{
244 VectorSet<Strip *> strips;
245 LISTBASE_FOREACH (Strip *, strip, seqbase) {
246 if ((strip->flag & SELECT) != 0) {
247 continue;
248 }
249 strips.add(strip);
250 }
251 return strips;
252}
253
255 Strip *reference_strip,
256 ListBase *seqbase,
257 VectorSet<Strip *> &r_strips)
258{
259 if (r_strips.contains(reference_strip)) {
260 return; /* Strip is already in set, so all effects connected to it are as well. */
261 }
262
263 r_strips.add(reference_strip);
264
265 /* Find all input strips for `reference_strip`. */
266 if (reference_strip->is_effect()) {
267 if (reference_strip->input1) {
268 query_strip_effect_chain(scene, reference_strip->input1, seqbase, r_strips);
269 }
270 if (reference_strip->input2) {
271 query_strip_effect_chain(scene, reference_strip->input2, seqbase, r_strips);
272 }
273 }
274
275 /* Find all effect strips that have `reference_strip` as an input. */
276 LISTBASE_FOREACH (Strip *, strip_test, seqbase) {
277 if (strip_test->input1 == reference_strip || strip_test->input2 == reference_strip) {
278 query_strip_effect_chain(scene, strip_test, seqbase, r_strips);
279 }
280 }
281}
282
284 Strip *reference_strip,
285 ListBase *seqbase,
286 VectorSet<Strip *> &r_strips)
287{
288
290 pending.append(reference_strip);
291
292 while (!pending.is_empty()) {
293 Strip *current = pending.pop_last();
294
295 if (r_strips.contains(current)) {
296 continue;
297 }
298
299 r_strips.add(current);
300
301 VectorSet<Strip *> connections = connected_strips_get(current);
302 for (Strip *connection : connections) {
303 if (!r_strips.contains(connection)) {
304 pending.append(connection);
305 }
306 }
307
308 VectorSet<Strip *> effect_chain;
309 query_strip_effect_chain(scene, current, seqbase, effect_chain);
310 for (Strip *effect_strip : effect_chain) {
311 if (!r_strips.contains(effect_strip)) {
312 pending.append(effect_strip);
313 }
314 }
315 }
316}
317
318} // namespace blender::seq
#define LISTBASE_FOREACH(type, var, list)
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_META
@ STRIP_BLEND_REPLACE
bool add(const Key &key)
void add_multiple(Span< Key > keys)
bool contains(const Key &key) const
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
bool is_empty() const
#define SELECT
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2110
void foreach_strip(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
VectorSet< Strip * > query_all_strips(ListBase *seqbase)
Definition iterator.cc:143
static void collection_filter_channel_up_to_incl(VectorSet< Strip * > &strips, const int channel)
Definition iterator.cc:177
VectorSet< Strip * > query_selected_strips(ListBase *seqbase)
Definition iterator.cc:152
VectorSet< Strip * > query_unselected_strips(ListBase *seqbase)
Definition iterator.cc:242
static void query_all_strips_recursive(const ListBase *seqbase, VectorSet< Strip * > &strips)
Definition iterator.cc:101
static bool strip_for_each_recursive(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:26
static void collection_filter_rendered_strips(VectorSet< Strip * > &strips, ListBase *channels)
Definition iterator.cc:217
void query_strip_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:254
blender::VectorSet< Strip * > connected_strips_get(const Strip *strip)
static void query_strips_recursive_at_frame(const Scene *scene, const ListBase *seqbase, const int timeline_frame, VectorSet< Strip * > &strips)
Definition iterator.cc:118
void iterator_set_expand(const Scene *scene, ListBase *seqbase, VectorSet< Strip * > &strips, void strip_query_func(const Scene *scene, Strip *strip_reference, ListBase *seqbase, VectorSet< Strip * > &strips))
Definition iterator.cc:82
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
bool(*)(Strip *strip, void *user_data) ForEachFunc
static VectorSet< Strip * > query_strips_at_frame(const Scene *scene, ListBase *seqbase, const int timeline_frame)
Definition iterator.cc:163
VectorSet< Strip * > query_by_reference(Strip *strip_reference, const Scene *scene, ListBase *seqbase, void strip_query_func(const Scene *scene, Strip *strip_reference, ListBase *seqbase, VectorSet< Strip * > &strips))
Definition iterator.cc:69
bool must_render_strip(const VectorSet< Strip * > &strips, Strip *strip)
Definition iterator.cc:184
bool relation_is_effect_of_strip(const Strip *effect, const Strip *input)
VectorSet< Strip * > query_rendered_strips(const Scene *scene, ListBase *channels, ListBase *seqbase, const int timeline_frame, const int displayed_channel)
Definition iterator.cc:228
void query_strip_connected_and_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:283
int effect_get_num_inputs(int strip_type)
Definition effects.cc:327
struct Strip * input1
struct Strip * input2