Blender V4.5
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 for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data)
60{
61 strip_for_each_recursive(seqbase, callback, user_data);
62}
63
64void for_each_callback(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
119{
120 VectorSet<Strip *> strips;
121 LISTBASE_FOREACH (Strip *, strip, seqbase) {
122 strips.add(strip);
123 }
124 return strips;
125}
126
128{
129 VectorSet<Strip *> strips;
130 LISTBASE_FOREACH (Strip *, strip, seqbase) {
131 if ((strip->flag & SELECT) != 0) {
132 strips.add(strip);
133 }
134 }
135 return strips;
136}
137
139 ListBase *seqbase,
140 const int timeline_frame)
141{
142 VectorSet<Strip *> strips;
143
144 LISTBASE_FOREACH (Strip *, strip, seqbase) {
145 if (time_strip_intersects_frame(scene, strip, timeline_frame)) {
146 strips.add(strip);
147 }
148 }
149 return strips;
150}
151
152static void collection_filter_channel_up_to_incl(VectorSet<Strip *> &strips, const int channel)
153{
154 strips.remove_if([&](Strip *strip) { return strip->channel > channel; });
155}
156
157/* Check if strip must be rendered. This depends on whole stack in some cases, not only strip
158 * itself. Order of applying these conditions is important. */
159static bool must_render_strip(const VectorSet<Strip *> &strips, Strip *strip)
160{
161 bool strip_have_effect_in_stack = false;
162 for (Strip *strip_iter : strips) {
163 /* Strips is below another strip with replace blending are not rendered. */
164 if (strip_iter->blend_mode == SEQ_BLEND_REPLACE && strip->channel < strip_iter->channel) {
165 return false;
166 }
167
168 if ((strip_iter->type & STRIP_TYPE_EFFECT) != 0 &&
169 relation_is_effect_of_strip(strip_iter, strip))
170 {
171 /* Strips in same channel or higher than its effect are rendered. */
172 if (strip->channel >= strip_iter->channel) {
173 return true;
174 }
175 /* Mark that this strip has effect in stack, that is above the strip. */
176 strip_have_effect_in_stack = true;
177 }
178 }
179
180 /* All non-generator effects are rendered (with respect to conditions above). */
181 if ((strip->type & STRIP_TYPE_EFFECT) != 0 && effect_get_num_inputs(strip->type) != 0) {
182 return true;
183 }
184
185 /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */
186 if (strip_have_effect_in_stack) {
187 return false;
188 }
189
190 return true;
191}
192
193/* Remove strips we don't want to render from VectorSet. */
195{
196 /* Remove sound strips and muted strips from VectorSet, because these are not rendered.
197 * Function #must_render_strip() don't have to check for these strips anymore. */
198 strips.remove_if([&](Strip *strip) {
199 return strip->type == STRIP_TYPE_SOUND_RAM || render_is_muted(channels, strip);
200 });
201
202 strips.remove_if([&](Strip *strip) { return !must_render_strip(strips, strip); });
203}
204
206 ListBase *channels,
207 ListBase *seqbase,
208 const int timeline_frame,
209 const int displayed_channel)
210{
211 VectorSet strips = query_strips_at_frame(scene, seqbase, timeline_frame);
212 if (displayed_channel != 0) {
213 collection_filter_channel_up_to_incl(strips, displayed_channel);
214 }
215 collection_filter_rendered_strips(strips, channels);
216 return strips;
217}
218
220{
221 VectorSet<Strip *> strips;
222 LISTBASE_FOREACH (Strip *, strip, seqbase) {
223 if ((strip->flag & SELECT) != 0) {
224 continue;
225 }
226 strips.add(strip);
227 }
228 return strips;
229}
230
232 Strip *reference_strip,
233 ListBase *seqbase,
234 VectorSet<Strip *> &r_strips)
235{
236 if (r_strips.contains(reference_strip)) {
237 return; /* Strip is already in set, so all effects connected to it are as well. */
238 }
239
240 r_strips.add(reference_strip);
241
242 /* Find all input strips for `reference_strip`. */
243 if (reference_strip->type & STRIP_TYPE_EFFECT) {
244 if (reference_strip->input1) {
245 query_strip_effect_chain(scene, reference_strip->input1, seqbase, r_strips);
246 }
247 if (reference_strip->input2) {
248 query_strip_effect_chain(scene, reference_strip->input2, seqbase, r_strips);
249 }
250 }
251
252 /* Find all effect strips that have `reference_strip` as an input. */
253 LISTBASE_FOREACH (Strip *, strip_test, seqbase) {
254 if (strip_test->input1 == reference_strip || strip_test->input2 == reference_strip) {
255 query_strip_effect_chain(scene, strip_test, seqbase, r_strips);
256 }
257 }
258}
259
261 Strip *reference_strip,
262 ListBase *seqbase,
263 VectorSet<Strip *> &r_strips)
264{
265
267 pending.append(reference_strip);
268
269 while (!pending.is_empty()) {
270 Strip *current = pending.pop_last();
271
272 if (r_strips.contains(current)) {
273 continue;
274 }
275
276 r_strips.add(current);
277
278 VectorSet<Strip *> connections = connected_strips_get(current);
279 for (Strip *connection : connections) {
280 if (!r_strips.contains(connection)) {
281 pending.append(connection);
282 }
283 }
284
285 VectorSet<Strip *> effect_chain;
286 query_strip_effect_chain(scene, current, seqbase, effect_chain);
287 for (Strip *effect_strip : effect_chain) {
288 if (!r_strips.contains(effect_strip)) {
289 pending.append(effect_strip);
290 }
291 }
292 }
293}
294
295} // namespace blender::seq
#define LISTBASE_FOREACH(type, var, list)
@ SEQ_BLEND_REPLACE
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_EFFECT
@ STRIP_TYPE_META
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:2092
VectorSet< Strip * > query_all_strips(ListBase *seqbase)
Definition iterator.cc:118
static void collection_filter_channel_up_to_incl(VectorSet< Strip * > &strips, const int channel)
Definition iterator.cc:152
VectorSet< Strip * > query_selected_strips(ListBase *seqbase)
Definition iterator.cc:127
VectorSet< Strip * > query_unselected_strips(ListBase *seqbase)
Definition iterator.cc:219
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:194
void query_strip_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:231
blender::VectorSet< Strip * > connected_strips_get(const Strip *strip)
void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
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:138
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 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:205
void query_strip_connected_and_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:260
static bool must_render_strip(const VectorSet< Strip * > &strips, Strip *strip)
Definition iterator.cc:159
int effect_get_num_inputs(int strip_type)
Definition effects.cc:286
struct Strip * input1
struct Strip * input2