Blender V5.0
modifier.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
10
11#include "BLI_math_color.h"
12#include "BLI_math_interp.hh"
13#include "BLI_math_matrix.hh"
14#include "BLI_math_vector.hh"
15#include "BLI_task.hh"
16
17#include "IMB_imbuf.hh"
18
19struct bContext;
20struct ARegionType;
21struct ImBuf;
22struct Strip;
23struct uiLayout;
24struct Panel;
25struct PanelType;
26struct PointerRNA;
27
28namespace blender::seq {
29
30struct RenderData;
31struct SeqRenderState;
32
48 const Strip &strip;
49
50 /* Transformation from strip image local pixel coordinates to the
51 * full render area pixel coordinates.This is used to sample
52 * modifier masks (since masks are in full render area space). */
54 ImBuf *const image;
55
56 /* How much the resulting image should be translated, in pixels.
57 * Compositor modifier can have some nodes that translate the output
58 * image. */
60};
61
62void modifier_apply_stack(ModifierApplyContext &context, int timeline_frame);
63
65
67
68bool modifier_ui_poll(const bContext *C, PanelType *pt);
69
70using PanelDrawFn = void (*)(const bContext *, Panel *);
71
73 const eStripModifierType type,
75
77float4 load_pixel_premul(const float *ptr);
78void store_pixel_premul(const float4 pix, uchar *ptr);
79void store_pixel_premul(const float4 pix, float *ptr);
81float4 load_pixel_raw(const float *ptr);
82void store_pixel_raw(const float4 pix, uchar *ptr);
83void store_pixel_raw(const float4 pix, float *ptr);
84
85/* Mask sampler for #apply_modifier_op: no mask is present. */
87 void begin_row(int64_t /*y*/) {}
88 void apply_mask(const float4 /*input*/, float4 & /*result*/) {}
90 {
91 return 0.0f;
92 }
93};
94
95/* Mask sampler for #apply_modifier_op: floating point mask,
96 * same size as input, no transform. */
99 {
100 BLI_assert(mask && mask->float_buffer.data);
101 }
103 {
104 BLI_assert(y >= 0 && y < mask->y);
105 ptr = mask->float_buffer.data + y * mask->x * 4;
106 }
108 {
109 float3 m(this->ptr);
110 result.x = math::interpolate(input.x, result.x, m.x);
111 result.y = math::interpolate(input.y, result.y, m.y);
112 result.z = math::interpolate(input.z, result.z, m.z);
113 this->ptr += 4;
114 }
116 {
117 float r = min_fff(this->ptr[0], this->ptr[1], this->ptr[2]);
118 this->ptr += 4;
119 return r;
120 }
121 const float *ptr = nullptr;
122 const ImBuf *mask;
123};
124
125/* Mask sampler for #apply_modifier_op: byte mask,
126 * same size as input, no transform. */
129 {
130 BLI_assert(mask && mask->byte_buffer.data);
131 }
133 {
134 BLI_assert(y >= 0 && y < mask->y);
135 ptr = mask->byte_buffer.data + y * mask->x * 4;
136 }
138 {
139 float3 m;
140 rgb_uchar_to_float(m, this->ptr);
141 result.x = math::interpolate(input.x, result.x, m.x);
142 result.y = math::interpolate(input.y, result.y, m.y);
143 result.z = math::interpolate(input.z, result.z, m.z);
144 this->ptr += 4;
145 }
147 {
148 float r = float(min_iii(this->ptr[0], this->ptr[1], this->ptr[2])) * (1.0f / 255.0f);
149 this->ptr += 4;
150 return r;
151 }
152 const uchar *ptr = nullptr;
153 const ImBuf *mask;
154};
155
156/* Mask sampler for #apply_modifier_op: floating point mask,
157 * sample mask with a transform. */
161 {
162 BLI_assert(mask && mask->float_buffer.data);
163 start_uv = transform.location().xy();
164 add_x = transform.x_axis().xy();
165 add_y = transform.y_axis().xy();
166 }
168 {
169 this->cur_y = y;
170 this->cur_x = 0;
171 /* Sample at pixel centers. */
172 this->cur_uv_row = this->start_uv + (y + 0.5f) * this->add_y + 0.5f * this->add_x;
173 }
175 {
176 float2 uv = this->cur_uv_row + this->cur_x * this->add_x - 0.5f;
177 float4 m;
179 this->mask->float_buffer.data, m, this->mask->x, this->mask->y, 4, uv.x, uv.y);
180 result.x = math::interpolate(input.x, result.x, m.x);
181 result.y = math::interpolate(input.y, result.y, m.y);
182 result.z = math::interpolate(input.z, result.z, m.z);
183 this->cur_x++;
184 }
186 {
187 float2 uv = this->cur_uv_row + this->cur_x * this->add_x - 0.5f;
188 float4 m;
190 this->mask->float_buffer.data, m, this->mask->x, this->mask->y, 4, uv.x, uv.y);
191 float r = min_fff(m.x, m.y, m.z);
192 this->cur_x++;
193 return r;
194 }
196 const ImBuf *mask;
200};
201
202/* Mask sampler for #apply_modifier_op: byte mask,
203 * sample mask with a transform. */
207 {
208 BLI_assert(mask && mask->byte_buffer.data);
209 start_uv = transform.location().xy();
210 add_x = transform.x_axis().xy();
211 add_y = transform.y_axis().xy();
212 }
214 {
215 this->cur_y = y;
216 this->cur_x = 0;
217 /* Sample at pixel centers. */
218 this->cur_uv_row = this->start_uv + (y + 0.5f) * this->add_y + 0.5f * this->add_x;
219 }
221 {
222 float2 uv = this->cur_uv_row + this->cur_x * this->add_x - 0.5f;
224 this->mask->byte_buffer.data, this->mask->x, this->mask->y, uv.x, uv.y);
225 float3 m;
226 rgb_uchar_to_float(m, mb);
227 result.x = math::interpolate(input.x, result.x, m.x);
228 result.y = math::interpolate(input.y, result.y, m.y);
229 result.z = math::interpolate(input.z, result.z, m.z);
230 this->cur_x++;
231 }
233 {
234 float2 uv = this->cur_uv_row + this->cur_x * this->add_x - 0.5f;
236 this->mask->byte_buffer.data, this->mask->x, this->mask->y, uv.x, uv.y);
237 float r = float(min_iii(m.x, m.y, m.z)) * (1.0f / 255.0f);
238 this->cur_x++;
239 return r;
240 }
242 const ImBuf *mask;
246};
247
248/* Given `T` that implements an `apply` function:
249 *
250 * template <typename ImageT, typename MaskSampler>
251 * void apply(ImageT* image, MaskSampler &mask, int image_x, IndexRange y_range);
252 *
253 * this function calls the apply() function in parallel
254 * chunks of the image to process, and with needed
255 * uchar or float ImageT types, and with appropriate MaskSampler
256 * instantiated, depending on whether the mask exists, data type
257 * of the mask, and whether it needs a transformation or can be
258 * sampled directly.
259 *
260 * Both input and mask images are expected to have
261 * 4 (RGBA) color channels. Input is modified. */
262template<typename T>
263void apply_modifier_op(T &op, ImBuf *ibuf, const ImBuf *mask, const float3x3 &mask_transform)
264{
265 if (ibuf == nullptr) {
266 return;
267 }
268 BLI_assert_msg(ibuf->channels == 0 || ibuf->channels == 4,
269 "Sequencer only supports 4 channel images");
270 BLI_assert_msg(mask == nullptr || mask->channels == 0 || mask->channels == 4,
271 "Sequencer only supports 4 channel images");
272 const bool direct_mask_sampling = mask == nullptr || (mask->x == ibuf->x && mask->y == ibuf->y &&
273 math::is_identity(mask_transform));
274 const int image_x = ibuf->x;
275 threading::parallel_for(IndexRange(ibuf->y), 16, [&](IndexRange y_range) {
276 uchar *image_byte = ibuf->byte_buffer.data;
277 float *image_float = ibuf->float_buffer.data;
278 const uchar *mask_byte = mask ? mask->byte_buffer.data : nullptr;
279 const float *mask_float = mask ? mask->float_buffer.data : nullptr;
280
281 /* Instantiate the needed processing function based on image/mask
282 * data types. */
283 if (image_byte) {
284 if (mask_byte) {
285 if (direct_mask_sampling) {
286 MaskSamplerDirectByte sampler(mask);
287 op.apply(image_byte, sampler, image_x, y_range);
288 }
289 else {
290 MaskSamplerTransformedByte sampler(mask, mask_transform);
291 op.apply(image_byte, sampler, image_x, y_range);
292 }
293 }
294 else if (mask_float) {
295 if (direct_mask_sampling) {
296 MaskSamplerDirectFloat sampler(mask);
297 op.apply(image_byte, sampler, image_x, y_range);
298 }
299 else {
300 MaskSamplerTransformedFloat sampler(mask, mask_transform);
301 op.apply(image_byte, sampler, image_x, y_range);
302 }
303 }
304 else {
305 MaskSamplerNone sampler;
306 op.apply(image_byte, sampler, image_x, y_range);
307 }
308 }
309 else if (image_float) {
310 if (mask_byte) {
311 if (direct_mask_sampling) {
313 op.apply(image_float, sampler, image_x, y_range);
314 }
315 else {
316 MaskSamplerTransformedByte sampler(mask, mask_transform);
317 op.apply(image_float, sampler, image_x, y_range);
318 }
319 }
320 else if (mask_float) {
321 if (direct_mask_sampling) {
323 op.apply(image_float, sampler, image_x, y_range);
324 }
325 else {
326 MaskSamplerTransformedFloat sampler(mask, mask_transform);
327 op.apply(image_float, sampler, image_x, y_range);
328 }
329 }
330 else {
331 MaskSamplerNone sampler;
332 op.apply(image_float, sampler, image_x, y_range);
333 }
334 }
335 });
336}
337
338} // namespace blender::seq
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE int min_iii(int a, int b, int c)
MINLINE float min_fff(float a, float b, float c)
MINLINE void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
unsigned char uchar
eStripModifierType
#define C
Definition RandGen.cpp:29
long long int int64_t
nullptr float
#define input
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define T
float4 interpolate_bilinear_border_fl(const float *buffer, int width, int height, float u, float v)
T interpolate(const T &a, const T &b, const FactorT &t)
bool is_identity(const MatBase< T, NumCol, NumRow > &mat)
uchar4 interpolate_bilinear_border_byte(const uchar *buffer, int width, int height, float u, float v)
void store_pixel_raw(float4 pix, uchar *ptr)
void draw_mask_input_type_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr)
void apply_modifier_op(T &op, ImBuf *ibuf, const ImBuf *mask, const float3x3 &mask_transform)
Definition modifier.hh:263
void store_pixel_premul(float4 pix, uchar *ptr)
bool modifier_persistent_uids_are_valid(const Strip &strip)
float4 load_pixel_raw(const uchar *ptr)
float4 load_pixel_premul(const uchar *ptr)
void modifier_apply_stack(ModifierApplyContext &context, int timeline_frame)
bool modifier_ui_poll(const bContext *C, PanelType *)
void(*)(const bContext *, Panel *) PanelDrawFn
Definition modifier.hh:70
PanelType * modifier_panel_register(ARegionType *region_type, const eStripModifierType type, PanelDrawFn draw)
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
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
MaskSamplerDirectByte(const ImBuf *mask)
Definition modifier.hh:128
void apply_mask(const float4 input, float4 &result)
Definition modifier.hh:137
void apply_mask(const float4 input, float4 &result)
Definition modifier.hh:107
MaskSamplerDirectFloat(const ImBuf *mask)
Definition modifier.hh:98
void apply_mask(const float4, float4 &)
Definition modifier.hh:88
void apply_mask(const float4 input, float4 &result)
Definition modifier.hh:220
MaskSamplerTransformedByte(const ImBuf *mask, const float3x3 &transform)
Definition modifier.hh:205
void apply_mask(const float4 input, float4 &result)
Definition modifier.hh:174
MaskSamplerTransformedFloat(const ImBuf *mask, const float3x3 &transform)
Definition modifier.hh:159
const RenderData & render_data
Definition modifier.hh:46
ModifierApplyContext(const RenderData &render_data, SeqRenderState &render_state, const Strip &strip, const float3x3 &transform, ImBuf *image)
Definition modifier.hh:34
PointerRNA * ptr
Definition wm_files.cc:4238