Blender V4.3
COM_NodeOperation.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
5#include <cstdio>
6
8
10#include "COM_NodeOperation.h" /* own include */
11
12namespace blender::compositor {
13
14/*******************
15 **** NodeOperation ****
16 *******************/
17
19{
20 canvas_input_index_ = 0;
22 btree_ = nullptr;
23}
24
26{
27 BLI_assert(outputs_.size() > 0 && get_output_socket()->get_data_type() == DataType::Value);
28 return *get_constant_elem_default(&default_value);
29}
30
31const float *NodeOperation::get_constant_elem_default(const float *default_elem)
32{
33 BLI_assert(outputs_.size() > 0);
34 if (get_flags().is_constant_operation) {
35 return static_cast<ConstantOperation *>(this)->get_constant_elem();
36 }
37
38 return default_elem;
39}
40
41std::optional<NodeOperationHash> NodeOperation::generate_hash()
42{
43 params_hash_ = get_default_hash(canvas_.xmin, canvas_.xmax);
44
45 /* Hash subclasses params. */
46 is_hash_output_params_implemented_ = true;
48 if (!is_hash_output_params_implemented_) {
49 return std::nullopt;
50 }
51
53 if (outputs_.size() > 0) {
54 BLI_assert(outputs_.size() == 1);
55 hash_param(this->get_output_socket()->get_data_type());
56 }
58 hash.params_hash_ = params_hash_;
59
60 hash.parents_hash_ = 0;
61 for (NodeOperationInput &socket : inputs_) {
62 if (!socket.is_connected()) {
63 continue;
64 }
65
66 NodeOperation &input = socket.get_link()->get_operation();
67 const bool is_constant = input.get_flags().is_constant_operation;
68 combine_hashes(hash.parents_hash_, get_default_hash(is_constant));
69 if (is_constant) {
70 const float *elem = ((ConstantOperation *)&input)->get_constant_elem();
71 const int num_channels = COM_data_type_num_channels(socket.get_data_type());
72 for (const int i : IndexRange(num_channels)) {
73 combine_hashes(hash.parents_hash_, get_default_hash(elem[i]));
74 }
75 }
76 else {
77 combine_hashes(hash.parents_hash_, get_default_hash(input.get_id()));
78 }
79 }
80
81 hash.type_hash_ = typeid(*this).hash_code();
82 hash.operation_ = this;
83
84 return hash;
85}
86
88{
89 return &outputs_[index];
90}
91
93{
94 return &inputs_[index];
95}
96
98{
99 inputs_.append(NodeOperationInput(this, datatype, resize_mode));
100}
101
103{
104 outputs_.append(NodeOperationOutput(this, datatype));
105}
106
107void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
108{
109 uint used_canvas_index = 0;
110 if (canvas_input_index_ == RESOLUTION_INPUT_ANY) {
111 for (NodeOperationInput &input : inputs_) {
112 rcti any_area = COM_AREA_NONE;
113 const bool determined = input.determine_canvas(preferred_area, any_area);
114 if (determined) {
115 r_area = any_area;
116 break;
117 }
118 used_canvas_index += 1;
119 }
120 }
121 else if (canvas_input_index_ < inputs_.size()) {
122 NodeOperationInput &input = inputs_[canvas_input_index_];
123 input.determine_canvas(preferred_area, r_area);
124 used_canvas_index = canvas_input_index_;
125 }
126
127 if (modify_determined_canvas_fn_) {
128 modify_determined_canvas_fn_(r_area);
129 }
130
131 rcti unused_area = COM_AREA_NONE;
132 const rcti &local_preferred_area = r_area;
133 for (uint index = 0; index < inputs_.size(); index++) {
134 if (index == used_canvas_index) {
135 continue;
136 }
137 NodeOperationInput &input = inputs_[index];
138 if (input.is_connected()) {
139 input.determine_canvas(local_preferred_area, unused_area);
140 }
141 }
142}
143
145{
146 this->canvas_input_index_ = index;
147}
148
150{
151 /* Pass. */
152}
154{
155 /* pass */
156}
157
159{
160 /* pass */
161}
162
163void NodeOperation::set_canvas(const rcti &canvas_area)
164{
165 canvas_ = canvas_area;
166 flags_.is_canvas_set = true;
167}
168
170{
171 return canvas_;
172}
173
175{
176 BLI_assert(inputs_.is_empty());
177 flags_.is_canvas_set = false;
178}
179
184
186{
187 NodeOperationInput *input = get_input_socket(index);
188 if (input && input->is_connected()) {
189 return &input->get_link()->get_operation();
190 }
191
192 return nullptr;
193}
194
195/* -------------------------------------------------------------------- */
199void NodeOperation::get_area_of_interest(const int /*input_idx*/,
200 const rcti &output_area,
201 rcti &r_input_area)
202{
203 r_input_area = output_area;
204}
205
207 const rcti &output_area,
208 rcti &r_input_area)
209{
210 for (int i = 0; i < get_number_of_input_sockets(); i++) {
211 if (input_op == get_input_operation(i)) {
212 get_area_of_interest(i, output_area, r_input_area);
213 return;
214 }
215 }
216 BLI_assert_msg(0, "input_op is not an input operation.");
217}
218
220 Span<rcti> areas,
221 Span<MemoryBuffer *> inputs_bufs)
222{
223 render_full_frame(output_buf, areas, inputs_bufs);
224}
225
226void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
227 Span<rcti> areas,
228 Span<MemoryBuffer *> inputs_bufs)
229{
231 for (const rcti &area : areas) {
232 update_memory_buffer(output_buf, area, inputs_bufs);
233 }
235}
236
239/*****************
240 **** OpInput ****
241 *****************/
242
244 DataType datatype,
245 ResizeMode resize_mode)
246 : operation_(op), datatype_(datatype), resize_mode_(resize_mode), link_(nullptr)
247{
248}
249
251{
252 if (is_connected()) {
253 return &link_->get_operation();
254 }
255
256 return nullptr;
257}
258
259bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_area)
260{
261 if (link_) {
262 link_->determine_canvas(preferred_area, r_area);
263 return !BLI_rcti_is_empty(&r_area);
264 }
265 return false;
266}
267
268/******************
269 **** OpOutput ****
270 ******************/
271
273 : operation_(op), datatype_(datatype)
274{
275}
276
277void NodeOperationOutput::determine_canvas(const rcti &preferred_area, rcti &r_area)
278{
279 NodeOperation &operation = get_operation();
280 if (operation.get_flags().is_canvas_set) {
281 r_area = operation.get_canvas();
282 }
283 else {
284 operation.determine_canvas(preferred_area, r_area);
285 if (!BLI_rcti_is_empty(&r_area)) {
286 operation.set_canvas(r_area);
287 }
288 }
289}
290
291std::ostream &operator<<(std::ostream &os, const NodeOperationFlags &node_operation_flags)
292{
293 if (node_operation_flags.use_render_border) {
294 os << "render_border,";
295 }
296 if (node_operation_flags.use_viewer_border) {
297 os << "view_border,";
298 }
299 if (node_operation_flags.is_canvas_set) {
300 os << "canvas_set,";
301 }
302 if (node_operation_flags.is_proxy_operation) {
303 os << "proxy,";
304 }
305 if (node_operation_flags.is_viewer_operation) {
306 os << "viewer,";
307 }
308 if (node_operation_flags.is_preview_operation) {
309 os << "preview,";
310 }
311 if (!node_operation_flags.use_datatype_conversion) {
312 os << "no_conversion,";
313 }
314 if (node_operation_flags.is_constant_operation) {
315 os << "contant_operation,";
316 }
317 if (node_operation_flags.can_be_constant) {
318 os << "can_be_constant,";
319 }
320
321 return os;
322}
323
324std::ostream &operator<<(std::ostream &os, const NodeOperation &node_operation)
325{
326 NodeOperationFlags flags = node_operation.get_flags();
327 os << "NodeOperation(";
328 os << "id=" << node_operation.get_id();
329 if (!node_operation.get_name().empty()) {
330 os << ",name=" << node_operation.get_name();
331 }
332 os << ",flags={" << flags << "}";
333 os << ")";
334
335 return os;
336}
337
338} // namespace blender::compositor
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
bool BLI_rcti_is_empty(const struct rcti *rect)
unsigned int uint
a MemoryBuffer contains access to the data
bool determine_canvas(const rcti &preferred_area, rcti &r_area)
NodeOperationInput(NodeOperation *op, DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
NodeOperationOutput(NodeOperation *op, DataType datatype)
void determine_canvas(const rcti &preferred_area, rcti &r_area)
NodeOperation contains calculation logic.
static void combine_hashes(size_t &combined, size_t other)
void set_canvas(const rcti &canvas_area)
void add_output_socket(DataType datatype)
const NodeOperationFlags get_flags() const
SocketReader * get_input_socket_reader(unsigned int index)
virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area)
Get input operation area being read by this operation on rendering given output area.
std::optional< NodeOperationHash > generate_hash()
float get_constant_value_default(float default_value)
unsigned int get_number_of_input_sockets() const
NodeOperationOutput * get_output_socket(unsigned int index=0)
NodeOperation * get_input_operation(int index)
const float * get_constant_elem_default(const float *default_elem)
NodeOperationInput * get_input_socket(unsigned int index)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
virtual void update_memory_buffer(MemoryBuffer *, const rcti &, Span< MemoryBuffer * >)
const std::string get_name() const
void set_canvas_input_index(unsigned int index)
set the index of the input socket that will determine the canvas of this operation
void hash_params(T1 param1, T2 param2)
void render(MemoryBuffer *output_buf, Span< rcti > areas, Span< MemoryBuffer * > inputs_bufs)
virtual void determine_canvas(const rcti &preferred_area, rcti &r_area)
DataType
possible data types for sockets
Definition COM_defines.h:21
ResizeMode
Resize modes of inputsockets How are the input and working resolutions matched.
static constexpr unsigned int RESOLUTION_INPUT_ANY
constexpr int COM_data_type_num_channels(const DataType datatype)
Definition COM_defines.h:35
constexpr rcti COM_AREA_NONE
Definition COM_defines.h:89
std::ostream & operator<<(std::ostream &os, const eCompositorPriority &priority)
Definition COM_Enums.cc:27
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
#define hash
Definition noise.c:154
int ymin
int ymax
int xmin
int xmax