Blender V4.5
vse_effect_wipe.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "BLI_task.hh"
12
13#include "DNA_sequence_types.h"
14
15#include "IMB_imbuf.hh"
16
17#include "SEQ_render.hh"
18
19#include "effects.hh"
20
21namespace blender::seq {
22
23struct WipeZone {
24 float angle;
25 int flip;
26 int xo, yo;
27 int width;
28 float pythangle;
30 int type;
31 bool forward;
32};
33
34static WipeZone precalc_wipe_zone(const WipeVars *wipe, int xo, int yo)
35{
36 WipeZone zone;
37 zone.flip = (wipe->angle < 0.0f);
38 zone.angle = tanf(fabsf(wipe->angle));
39 zone.xo = xo;
40 zone.yo = yo;
41 zone.width = int(wipe->edgeWidth * ((xo + yo) / 2.0f));
42 zone.pythangle = 1.0f / sqrtf(zone.angle * zone.angle + 1.0f);
43 zone.clockWidth = wipe->edgeWidth * float(M_PI);
44 zone.type = wipe->wipetype;
45 zone.forward = wipe->forward != 0;
46 return zone;
47}
48
52static float in_band(float width, float dist, int side, int dir)
53{
54 float alpha;
55
56 if (width == 0) {
57 return float(side);
58 }
59
60 if (width < dist) {
61 return float(side);
62 }
63
64 if (side == 1) {
65 alpha = (dist + 0.5f * width) / (width);
66 }
67 else {
68 alpha = (0.5f * width - dist) / (width);
69 }
70
71 if (dir == 0) {
72 alpha = 1 - alpha;
73 }
74
75 return alpha;
76}
77
78static float check_zone(const WipeZone *wipezone, int x, int y, float fac)
79{
80 float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
81 float temp1, temp2, temp3, temp4; /* some placeholder variables */
82 int xo = wipezone->xo;
83 int yo = wipezone->yo;
84 float halfx = xo * 0.5f;
85 float halfy = yo * 0.5f;
86 float widthf, output = 0;
87 int width;
88
89 if (wipezone->flip) {
90 x = xo - x;
91 }
92 angle = wipezone->angle;
93
94 if (wipezone->forward) {
95 posx = fac * xo;
96 posy = fac * yo;
97 }
98 else {
99 posx = xo - fac * xo;
100 posy = yo - fac * yo;
101 }
102
103 switch (wipezone->type) {
104 case DO_SINGLE_WIPE:
105 width = min_ii(wipezone->width, fac * yo);
106 width = min_ii(width, yo - fac * yo);
107
108 if (angle == 0.0f) {
109 b1 = posy;
110 b2 = y;
111 hyp = fabsf(y - posy);
112 }
113 else {
114 b1 = posy - (-angle) * posx;
115 b2 = y - (-angle) * x;
116 hyp = fabsf(angle * x + y + (-posy - angle * posx)) * wipezone->pythangle;
117 }
118
119 if (angle < 0) {
120 temp1 = b1;
121 b1 = b2;
122 b2 = temp1;
123 }
124
125 if (wipezone->forward) {
126 if (b1 < b2) {
127 output = in_band(width, hyp, 1, 1);
128 }
129 else {
130 output = in_band(width, hyp, 0, 1);
131 }
132 }
133 else {
134 if (b1 < b2) {
135 output = in_band(width, hyp, 0, 1);
136 }
137 else {
138 output = in_band(width, hyp, 1, 1);
139 }
140 }
141 break;
142
143 case DO_DOUBLE_WIPE:
144 if (!wipezone->forward) {
145 fac = 1.0f - fac; /* Go the other direction */
146 }
147
148 width = wipezone->width; /* calculate the blur width */
149 hwidth = width * 0.5f;
150 if (angle == 0) {
151 b1 = posy * 0.5f;
152 b3 = yo - posy * 0.5f;
153 b2 = y;
154
155 hyp = fabsf(y - posy * 0.5f);
156 hyp2 = fabsf(y - (yo - posy * 0.5f));
157 }
158 else {
159 b1 = posy * 0.5f - (-angle) * posx * 0.5f;
160 b3 = (yo - posy * 0.5f) - (-angle) * (xo - posx * 0.5f);
161 b2 = y - (-angle) * x;
162
163 hyp = fabsf(angle * x + y + (-posy * 0.5f - angle * posx * 0.5f)) * wipezone->pythangle;
164 hyp2 = fabsf(angle * x + y + (-(yo - posy * 0.5f) - angle * (xo - posx * 0.5f))) *
165 wipezone->pythangle;
166 }
167
168 hwidth = min_ff(hwidth, fabsf(b3 - b1) / 2.0f);
169
170 if (b2 < b1 && b2 < b3) {
171 output = in_band(hwidth, hyp, 0, 1);
172 }
173 else if (b2 > b1 && b2 > b3) {
174 output = in_band(hwidth, hyp2, 0, 1);
175 }
176 else {
177 if (hyp < hwidth && hyp2 > hwidth) {
178 output = in_band(hwidth, hyp, 1, 1);
179 }
180 else if (hyp > hwidth && hyp2 < hwidth) {
181 output = in_band(hwidth, hyp2, 1, 1);
182 }
183 else {
184 output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
185 }
186 }
187 if (!wipezone->forward) {
188 output = 1 - output;
189 }
190 break;
191 case DO_CLOCK_WIPE:
192 /*
193 * temp1: angle of effect center in rads
194 * temp2: angle of line through (halfx, halfy) and (x, y) in rads
195 * temp3: angle of low side of blur
196 * temp4: angle of high side of blur
197 */
198 output = 1.0f - fac;
199 widthf = wipezone->clockWidth;
200 temp1 = 2.0f * float(M_PI) * fac;
201
202 if (wipezone->forward) {
203 temp1 = 2.0f * float(M_PI) - temp1;
204 }
205
206 x = x - halfx;
207 y = y - halfy;
208
209 temp2 = atan2f(y, x);
210 if (temp2 < 0.0f) {
211 temp2 += 2.0f * float(M_PI);
212 }
213
214 if (wipezone->forward) {
215 temp3 = temp1 - widthf * fac;
216 temp4 = temp1 + widthf * (1 - fac);
217 }
218 else {
219 temp3 = temp1 - widthf * (1 - fac);
220 temp4 = temp1 + widthf * fac;
221 }
222 temp3 = std::max<float>(temp3, 0);
223 temp4 = std::min(temp4, 2.0f * float(M_PI));
224
225 if (temp2 < temp3) {
226 output = 0;
227 }
228 else if (temp2 > temp4) {
229 output = 1;
230 }
231 else {
232 output = (temp2 - temp3) / (temp4 - temp3);
233 }
234 if (x == 0 && y == 0) {
235 output = 1;
236 }
237 if (output != output) {
238 output = 1;
239 }
240 if (wipezone->forward) {
241 output = 1 - output;
242 }
243 break;
244 case DO_IRIS_WIPE:
245 if (xo > yo) {
246 yo = xo;
247 }
248 else {
249 xo = yo;
250 }
251
252 if (!wipezone->forward) {
253 fac = 1 - fac;
254 }
255
256 width = wipezone->width;
257 hwidth = width * 0.5f;
258
259 temp1 = (halfx - (halfx)*fac);
260 pointdist = hypotf(temp1, temp1);
261
262 temp2 = hypotf(halfx - x, halfy - y);
263 if (temp2 > pointdist) {
264 output = in_band(hwidth, fabsf(temp2 - pointdist), 0, 1);
265 }
266 else {
267 output = in_band(hwidth, fabsf(temp2 - pointdist), 1, 1);
268 }
269
270 if (!wipezone->forward) {
271 output = 1 - output;
272 }
273
274 break;
275 }
276 if (output < 0) {
277 output = 0;
278 }
279 else if (output > 1) {
280 output = 1;
281 }
282 return output;
283}
284
285static void init_wipe_effect(Strip *strip)
286{
287 if (strip->effectdata) {
288 MEM_freeN(strip->effectdata);
289 }
290
291 strip->effectdata = MEM_callocN<WipeVars>("wipevars");
292}
293
294static int num_inputs_wipe()
295{
296 return 2;
297}
298
299static void free_wipe_effect(Strip *strip, const bool /*do_id_user*/)
300{
302}
303
304static void copy_wipe_effect(Strip *dst, const Strip *src, const int /*flag*/)
305{
307}
308
309template<typename T>
310static void do_wipe_effect(
311 const Strip *strip, float fac, int width, int height, const T *rect1, const T *rect2, T *out)
312{
313 using namespace blender;
314 const WipeVars *wipe = (const WipeVars *)strip->effectdata;
315 const WipeZone wipezone = precalc_wipe_zone(wipe, width, height);
316
317 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
318 const T *cp1 = rect1 ? rect1 + y_range.first() * width * 4 : nullptr;
319 const T *cp2 = rect2 ? rect2 + y_range.first() * width * 4 : nullptr;
320 T *rt = out + y_range.first() * width * 4;
321 for (const int y : y_range) {
322 for (int x = 0; x < width; x++) {
323 float check = check_zone(&wipezone, x, y, fac);
324 if (check) {
325 if (cp1) {
326 float4 col1 = load_premul_pixel(cp1);
327 float4 col2 = load_premul_pixel(cp2);
328 float4 col = col1 * check + col2 * (1.0f - check);
330 }
331 else {
333 }
334 }
335 else {
336 if (cp2) {
337 memcpy(rt, cp2, sizeof(T) * 4);
338 }
339 else {
341 }
342 }
343
344 rt += 4;
345 if (cp1 != nullptr) {
346 cp1 += 4;
347 }
348 if (cp2 != nullptr) {
349 cp2 += 4;
350 }
351 }
352 }
353 });
354}
355
356static ImBuf *do_wipe_effect(const RenderData *context,
357 Strip *strip,
358 float /*timeline_frame*/,
359 float fac,
360 ImBuf *ibuf1,
361 ImBuf *ibuf2)
362{
363 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
364
365 if (out->float_buffer.data) {
366 do_wipe_effect(strip,
367 fac,
368 context->rectx,
369 context->recty,
370 ibuf1->float_buffer.data,
371 ibuf2->float_buffer.data,
372 out->float_buffer.data);
373 }
374 else {
375 do_wipe_effect(strip,
376 fac,
377 context->rectx,
378 context->recty,
379 ibuf1->byte_buffer.data,
380 ibuf2->byte_buffer.data,
381 out->byte_buffer.data);
382 }
383
384 return out;
385}
386
397
398} // namespace blender::seq
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
#define M_PI
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
constexpr int64_t first() const
#define tanf(x)
#define atan2f(x, y)
#define hypotf(x, y)
#define fabsf(x)
#define sqrtf(x)
uint col
#define out
#define output
#define MEM_SAFE_FREE(v)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
static float check_zone(const WipeZone *wipezone, int x, int y, float fac)
static void free_wipe_effect(Strip *strip, const bool)
void wipe_effect_get_handle(EffectHandle &rval)
static void copy_wipe_effect(Strip *dst, const Strip *src, const int)
static int num_inputs_wipe()
static void init_wipe_effect(Strip *strip)
void store_premul_pixel(const blender::float4 &pix, uchar *dst)
Definition effects.hh:57
ImBuf * prepare_effect_imbufs(const RenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, bool uninitialized_pixels)
Definition effects.cc:28
void store_opaque_black_pixel(uchar *dst)
Definition effects.hh:67
void get_default_fac_fade(const Scene *scene, const Strip *strip, float timeline_frame, float *fac)
Definition effects.cc:152
blender::float4 load_premul_pixel(const uchar *ptr)
Definition effects.hh:45
static void do_wipe_effect(const Strip *strip, float fac, int width, int height, const T *rect1, const T *rect2, T *out)
static WipeZone precalc_wipe_zone(const WipeVars *wipe, int xo, int yo)
static float in_band(float width, float dist, int side, int dir)
StripEarlyOut early_out_fade(const Strip *, float fac)
Definition effects.cc:117
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< float, 4 > float4
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
void * effectdata
void(* copy)(Strip *dst, const Strip *src, int flag)
ImBuf *(* execute)(const RenderData *context, Strip *strip, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
void(* get_default_fac)(const Scene *scene, const Strip *strip, float timeline_frame, float *fac)
void(* free)(Strip *strip, bool do_id_user)
StripEarlyOut(* early_out)(const Strip *strip, float fac)
void(* init)(Strip *strip)