Blender V5.0
node_composite_movieclip.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array.hh"
11
12#include "IMB_imbuf.hh"
13
14#include "BKE_context.hh"
15#include "BKE_lib_id.hh"
16#include "BKE_movieclip.h"
17#include "BKE_tracking.h"
18
19#include "DNA_defaults.h"
20
21#include "RNA_access.hh"
22
23#include "UI_interface.hh"
25
26#include "GPU_texture.hh"
27
28#include "COM_node_operation.hh"
29#include "COM_utilities.hh"
30
32
34
36{
37 b.add_output<decl::Color>("Image").structure_type(StructureType::Dynamic);
38 b.add_output<decl::Float>("Alpha").structure_type(StructureType::Dynamic);
39 b.add_output<decl::Float>("Offset X");
40 b.add_output<decl::Float>("Offset Y");
41 b.add_output<decl::Float>("Scale");
42 b.add_output<decl::Float>("Angle");
43}
44
45static void init(const bContext *C, PointerRNA *ptr)
46{
47 bNode *node = (bNode *)ptr->data;
48 Scene *scene = CTX_data_scene(C);
50
51 node->id = (ID *)scene->clip;
52 id_us_plus(node->id);
53 node->storage = user;
54 user->framenr = 1;
55}
56
58{
59 uiTemplateID(layout, C, ptr, "clip", nullptr, "CLIP_OT_open", nullptr);
60}
61
63{
64 bNode *node = (bNode *)ptr->data;
65 PointerRNA clipptr;
66
67 uiTemplateID(layout, C, ptr, "clip", nullptr, "CLIP_OT_open", nullptr);
68
69 if (!node->id) {
70 return;
71 }
72
73 clipptr = RNA_pointer_get(ptr, "clip");
74
75 uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
76}
77
78using namespace blender::compositor;
79
81 public:
83
84 void execute() override
85 {
86 ImBuf *movie_clip_buffer = get_movie_clip_buffer();
87
88 compute_image(movie_clip_buffer);
89 compute_alpha(movie_clip_buffer);
90 compute_stabilization_data(movie_clip_buffer);
91
92 IMB_freeImBuf(movie_clip_buffer);
93 }
94
95 void compute_image(ImBuf *movie_clip_buffer)
96 {
97 if (!should_compute_output("Image")) {
98 return;
99 }
100
101 Result &result = get_result("Image");
102 if (!movie_clip_buffer) {
103 result.allocate_invalid();
104 return;
105 }
106
107 const int2 size = int2(movie_clip_buffer->x, movie_clip_buffer->y);
108 result.allocate_texture(Domain(size));
109
110 if (context().use_gpu()) {
112 }
113 else {
114 parallel_for(size, [&](const int2 texel) {
115 int64_t pixel_index = (int64_t(texel.y) * size.x + texel.x) * 4;
116 result.store_pixel(texel, float4(movie_clip_buffer->float_buffer.data + pixel_index));
117 });
118 }
119 }
120
121 void compute_alpha(ImBuf *movie_clip_buffer)
122 {
123 if (!should_compute_output("Alpha")) {
124 return;
125 }
126
127 Result &result = get_result("Alpha");
128 if (!movie_clip_buffer) {
129 result.allocate_single_value();
130 result.set_single_value(1.0f);
131 return;
132 }
133
134 const int2 size = int2(movie_clip_buffer->x, movie_clip_buffer->y);
135 result.allocate_texture(Domain(size));
136
137 if (context().use_gpu()) {
138 Array<float> alpha_values(size.x * size.y);
139 parallel_for(size, [&](const int2 texel) {
140 int64_t pixel_index = int64_t(texel.y) * size.x + texel.x;
141 int64_t input_pixel_index = pixel_index * 4;
142 alpha_values[pixel_index] = movie_clip_buffer->float_buffer.data[input_pixel_index + 3];
143 });
145 }
146 else {
147 parallel_for(size, [&](const int2 texel) {
148 int64_t pixel_index = (int64_t(texel.y) * size.x + texel.x) * 4;
149 result.store_pixel(texel, movie_clip_buffer->float_buffer.data[pixel_index + 3]);
150 });
151 }
152 }
153
154 void compute_stabilization_data(ImBuf *movie_clip_buffer)
155 {
156 /* The movie clip buffer is invalid or missing, set appropriate fallback values. */
157 if (!movie_clip_buffer) {
158 if (should_compute_output("Offset X")) {
159 Result &result = get_result("Offset X");
160 result.allocate_single_value();
161 result.set_single_value(0.0f);
162 }
163 if (should_compute_output("Offset Y")) {
164 Result &result = get_result("Offset Y");
165 result.allocate_single_value();
166 result.set_single_value(0.0f);
167 }
168 if (should_compute_output("Scale")) {
169 Result &result = get_result("Scale");
170 result.allocate_single_value();
171 result.set_single_value(1.0f);
172 }
173 if (should_compute_output("Angle")) {
174 Result &result = get_result("Angle");
175 result.allocate_single_value();
176 result.set_single_value(0.0f);
177 }
178 return;
179 }
180
181 MovieClip *movie_clip = get_movie_clip();
182 const int frame_number = BKE_movieclip_remap_scene_to_clip_frame(movie_clip,
183 context().get_frame_number());
184 const int width = movie_clip_buffer->x;
185 const int height = movie_clip_buffer->y;
186
187 /* If the movie clip has no stabilization data, it will initialize the given values with
188 * fallback values regardless, so no need to handle that case. */
189 float2 offset;
190 float scale, angle;
192 movie_clip, frame_number, width, height, offset, &scale, &angle);
193
194 if (should_compute_output("Offset X")) {
195 Result &result = get_result("Offset X");
196 result.allocate_single_value();
197 result.set_single_value(offset.x);
198 }
199 if (should_compute_output("Offset Y")) {
200 Result &result = get_result("Offset Y");
201 result.allocate_single_value();
202 result.set_single_value(offset.y);
203 }
204 if (should_compute_output("Scale")) {
205 Result &result = get_result("Scale");
206 result.allocate_single_value();
207 result.set_single_value(scale);
208 }
209 if (should_compute_output("Angle")) {
210 Result &result = get_result("Angle");
211 result.allocate_single_value();
212 result.set_single_value(angle);
213 }
214 }
215
216 /* Get a float image buffer contacting the movie content at the current frame. If the movie clip
217 * does not exist or is invalid, return nullptr. */
219 {
220 MovieClip *movie_clip = get_movie_clip();
221 if (!movie_clip) {
222 return nullptr;
223 }
224
225 MovieClipUser *movie_clip_user = get_movie_clip_user();
226 BKE_movieclip_user_set_frame(movie_clip_user, context().get_frame_number());
227
228 ImBuf *movie_clip_buffer = BKE_movieclip_get_ibuf(movie_clip, movie_clip_user);
229 if (!movie_clip_buffer) {
230 return nullptr;
231 }
232
233 if (movie_clip_buffer->float_buffer.data) {
234 return movie_clip_buffer;
235 }
236
237 /* Create a float buffer from the byte buffer if it exists, if not, return nullptr. */
238 IMB_float_from_byte(movie_clip_buffer);
239 if (!movie_clip_buffer->float_buffer.data) {
240 return nullptr;
241 }
242
243 return movie_clip_buffer;
244 }
245
247 {
248 return reinterpret_cast<MovieClip *>(bnode().id);
249 }
250
252 {
253 return static_cast<MovieClipUser *>(bnode().storage);
254 }
255};
256
258{
259 return new MovieClipOperation(context, node);
260}
261
262} // namespace blender::nodes::node_composite_movieclip_cc
263
265{
267
268 static blender::bke::bNodeType ntype;
269
270 cmp_node_type_base(&ntype, "CompositorNodeMovieClip", CMP_NODE_MOVIECLIP);
271 ntype.ui_name = "Movie Clip";
272 ntype.ui_description =
273 "Input image or movie from a movie clip data-block, typically used for motion tracking";
274 ntype.enum_name_legacy = "MOVIECLIP";
275 ntype.nclass = NODE_CLASS_INPUT;
276 ntype.declare = file_ns::cmp_node_movieclip_declare;
277 ntype.draw_buttons = file_ns::node_composit_buts_movieclip;
278 ntype.draw_buttons_ex = file_ns::node_composit_buts_movieclip_ex;
279 ntype.get_compositor_operation = file_ns::get_compositor_operation;
280 ntype.initfunc_api = file_ns::init;
281 ntype.flag |= NODE_PREVIEW;
284
286}
Scene * CTX_data_scene(const bContext *C)
void id_us_plus(ID *id)
Definition lib_id.cc:358
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
struct ImBuf * BKE_movieclip_get_ibuf(struct MovieClip *clip, const struct MovieClipUser *user)
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define CMP_NODE_MOVIECLIP
void BKE_tracking_stabilization_data_get(struct MovieClip *clip, int framenr, int width, int height, float translation[2], float *scale, float *angle)
#define DNA_struct_default_alloc(struct_name)
@ NODE_PREVIEW
@ GPU_DATA_FLOAT
void GPU_texture_update(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
void IMB_freeImBuf(ImBuf *ibuf)
void IMB_float_from_byte(ImBuf *ibuf)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, blender::StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, std::optional< blender::StringRef > text=std::nullopt)
void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname)
void init()
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
const T * data() const
Definition BLI_array.hh:312
bool should_compute_output(StringRef identifier)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
void parallel_for(const int2 range, const Function &function)
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
static void register_node_type_cmp_movieclip()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:414
ImBufFloatBuffer float_buffer
struct MovieClip * clip
struct ID * id
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:348
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:261
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* initfunc_api)(const bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:302
PointerRNA * ptr
Definition wm_files.cc:4238