Blender V4.5
node_composite_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_node.hh"
10#include "BLI_math_base.hh"
11#include "BLI_math_vector.hh"
13
15
16#include "NOD_multi_function.hh"
17
18#include "DNA_color_types.h"
19
20#include "BKE_colortools.hh"
21
22#include "UI_interface.hh"
23
24#include "GPU_material.hh"
25
26#include "COM_node_operation.hh"
28
30
31/* **************** CURVE Time ******************** */
32
34
36{
37 b.add_input<decl::Int>("Start Frame").default_value(1).compositor_expects_single_value();
38 b.add_input<decl::Int>("End Frame").default_value(250).compositor_expects_single_value();
39
40 b.add_output<decl::Float>("Fac");
41}
42
43static void node_composit_init_curves_time(bNodeTree * /*ntree*/, bNode *node)
44{
45 node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
46}
47
48using namespace blender::compositor;
49
51 public:
53
54 void execute() override
55 {
56 Result &result = this->get_result("Fac");
57 result.allocate_single_value();
58
59 CurveMapping *curve_mapping = const_cast<CurveMapping *>(this->get_curve_mapping());
60 BKE_curvemapping_init(curve_mapping);
61 const float time = BKE_curvemapping_evaluateF(
62 curve_mapping, 0, this->compute_normalized_time());
63 result.set_single_value(math::clamp(time, 0.0f, 1.0f));
64 }
65
67 {
68 const int frame_number = this->context().get_frame_number();
69 if (frame_number < this->get_start_frame()) {
70 return 0.0f;
71 }
72 if (frame_number > this->get_end_frame()) {
73 return 1.0f;
74 }
75 if (this->get_start_frame() == this->get_end_frame()) {
76 return 0.0f;
77 }
78 return float(frame_number - this->get_start_frame()) /
79 float(this->get_end_frame() - this->get_start_frame());
80 }
81
83 {
84 return this->get_input("Start Frame").get_single_value_default(1);
85 }
86
88 {
89 return this->get_input("End Frame").get_single_value_default(250);
90 }
91
93 {
94 return static_cast<const CurveMapping *>(bnode().storage);
95 }
96};
97
99{
100 return new TimeCurveOperation(context, node);
101}
102
103} // namespace blender::nodes::node_composite_time_curves_cc
104
106{
108
109 static blender::bke::bNodeType ntype;
110
111 cmp_node_type_base(&ntype, "CompositorNodeTime", CMP_NODE_TIME);
112 ntype.ui_name = "Time Curve";
113 ntype.ui_description =
114 "Generate a factor value (from 0.0 to 1.0) between scene start and end time, using a curve "
115 "mapping";
116 ntype.enum_name_legacy = "TIME";
117 ntype.nclass = NODE_CLASS_INPUT;
118 ntype.declare = file_ns::cmp_node_time_declare;
119 blender::bke::node_type_size(ntype, 200, 140, 320);
120 ntype.initfunc = file_ns::node_composit_init_curves_time;
122 ntype.get_compositor_operation = file_ns::get_compositor_operation;
123
125}
127
128/* **************** CURVE VEC ******************** */
129
131
133{
134 b.add_input<decl::Vector>("Vector")
135 .default_value({0.0f, 0.0f, 0.0f})
136 .min(-1.0f)
137 .max(1.0f)
139 b.add_output<decl::Vector>("Vector");
140}
141
142static void node_composit_init_curve_vec(bNodeTree * /*ntree*/, bNode *node)
143{
144 node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
145}
146
147static void node_buts_curvevec(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
148{
149 uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
150}
151
152using namespace blender::compositor;
153
155{
156 return static_cast<CurveMapping *>(node.storage);
157}
158
159static int node_gpu_material(GPUMaterial *material,
160 bNode *node,
161 bNodeExecData * /*execdata*/,
164{
165 CurveMapping *curve_mapping = get_curve_mapping(*node);
166
167 BKE_curvemapping_init(curve_mapping);
168 float *band_values;
169 int band_size;
170 BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
171 float band_layer;
172 GPUNodeLink *band_texture = GPU_color_band(material, band_size, band_values, &band_layer);
173
174 float start_slopes[CM_TOT];
175 float end_slopes[CM_TOT];
176 BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
177 float range_minimums[CM_TOT];
178 BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
179 float range_dividers[CM_TOT];
180 BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
181
182 return GPU_stack_link(material,
183 node,
184 "curves_vector",
185 inputs,
186 outputs,
187 band_texture,
188 GPU_constant(&band_layer),
189 GPU_uniform(range_minimums),
190 GPU_uniform(range_dividers),
191 GPU_uniform(start_slopes),
192 GPU_uniform(end_slopes));
193}
194
196{
197 CurveMapping *curve_mapping = get_curve_mapping(builder.node());
198 BKE_curvemapping_init(curve_mapping);
199
201 return mf::build::SI1_SO<float3, float3>(
202 "Vector Curves",
203 [=](const float3 &vector) -> float3 {
204 float3 output_vector = float3(0.0f);
205 BKE_curvemapping_evaluate3F(curve_mapping, output_vector, vector);
206 return output_vector;
207 },
208 mf::build::exec_presets::AllSpanOrSingle());
209 });
210}
211
212} // namespace blender::nodes::node_composite_vector_curves_cc
213
215{
217
218 static blender::bke::bNodeType ntype;
219
220 cmp_node_type_base(&ntype, "CompositorNodeCurveVec", CMP_NODE_CURVE_VEC);
221 ntype.ui_name = "Vector Curves";
222 ntype.ui_description = "Map input vector components with curves";
223 ntype.enum_name_legacy = "CURVE_VEC";
225 ntype.declare = file_ns::cmp_node_curve_vec_declare;
226 ntype.draw_buttons = file_ns::node_buts_curvevec;
227 blender::bke::node_type_size(ntype, 200, 140, 320);
228 ntype.initfunc = file_ns::node_composit_init_curve_vec;
230 ntype.gpu_fn = file_ns::node_gpu_material;
231 ntype.build_multi_function = file_ns::node_build_multi_function;
232 ntype.gather_link_search_ops = nullptr;
233
235}
237
238/* **************** CURVE RGB ******************** */
239
241
243{
244 b.add_input<decl::Float>("Fac")
245 .default_value(1.0f)
246 .min(0.0f)
247 .max(1.0f)
249 .compositor_domain_priority(1)
250 .description("Amount of influence the node exerts on the image");
251 b.add_input<decl::Color>("Image")
252 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
253 .compositor_domain_priority(0)
254 .description("Image/Color input on which RGB color transformation will be applied");
255 b.add_input<decl::Color>("Black Level")
256 .default_value({0.0f, 0.0f, 0.0f, 1.0f})
257 .description("Input color that should be mapped to black");
258 b.add_input<decl::Color>("White Level")
259 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
260 .description("Input color that should be mapped to white");
261 b.add_output<decl::Color>("Image");
262}
263
264static void node_composit_init_curve_rgb(bNodeTree * /*ntree*/, bNode *node)
265{
266 node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
267}
268
269using namespace blender::compositor;
270
272{
273 return static_cast<CurveMapping *>(node.storage);
274}
275
276static int node_gpu_material(GPUMaterial *material,
277 bNode *node,
278 bNodeExecData * /*execdata*/,
281{
282 CurveMapping *curve_mapping = get_curve_mapping(*node);
283
284 BKE_curvemapping_init(curve_mapping);
285 float *band_values;
286 int band_size;
287 BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
288 float band_layer;
289 GPUNodeLink *band_texture = GPU_color_band(material, band_size, band_values, &band_layer);
290
291 float start_slopes[CM_TOT];
292 float end_slopes[CM_TOT];
293 BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
294 float range_minimums[CM_TOT];
295 BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
296 float range_dividers[CM_TOT];
297 BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
298
299 if (curve_mapping->tone == CURVE_TONE_FILMLIKE) {
300 return GPU_stack_link(material,
301 node,
302 "curves_film_like",
303 inputs,
304 outputs,
305 band_texture,
306 GPU_constant(&band_layer),
307 GPU_uniform(&range_minimums[3]),
308 GPU_uniform(&range_dividers[3]),
309 GPU_uniform(&start_slopes[3]),
310 GPU_uniform(&end_slopes[3]));
311 }
312
313 const float min = 0.0f;
314 const float max = 1.0f;
315 GPU_link(material,
316 "clamp_value",
317 get_shader_node_input_link(*node, inputs, "Fac"),
320 &get_shader_node_input(*node, inputs, "Fac").link);
321
322 /* If the RGB curves do nothing, use a function that skips RGB computations. */
323 if (BKE_curvemapping_is_map_identity(curve_mapping, 0) &&
324 BKE_curvemapping_is_map_identity(curve_mapping, 1) &&
325 BKE_curvemapping_is_map_identity(curve_mapping, 2))
326 {
327 return GPU_stack_link(material,
328 node,
329 "curves_combined_only",
330 inputs,
331 outputs,
332 band_texture,
333 GPU_constant(&band_layer),
334 GPU_uniform(&range_minimums[3]),
335 GPU_uniform(&range_dividers[3]),
336 GPU_uniform(&start_slopes[3]),
337 GPU_uniform(&end_slopes[3]));
338 }
339
340 return GPU_stack_link(material,
341 node,
342 "curves_combined_rgb",
343 inputs,
344 outputs,
345 band_texture,
346 GPU_constant(&band_layer),
347 GPU_uniform(range_minimums),
348 GPU_uniform(range_dividers),
349 GPU_uniform(start_slopes),
350 GPU_uniform(end_slopes));
351}
352
354{
355 CurveMapping *curve_mapping = get_curve_mapping(builder.node());
356 BKE_curvemapping_init(curve_mapping);
357 BKE_curvemapping_premultiply(curve_mapping, false);
358
360 return mf::build::SI4_SO<float, float4, float4, float4, float4>(
361 "RGB Curves",
362 [=](const float factor, const float4 &color, const float4 &black, const float4 &white)
363 -> float4 {
364 float3 black_white_scale;
365 BKE_curvemapping_set_black_white_ex(black, white, black_white_scale);
366
369 curve_mapping, result, color, black, black_white_scale);
370 return float4(math::interpolate(color.xyz(), result, math::clamp(factor, 0.0f, 1.0f)),
371 color.w);
372 },
373 mf::build::exec_presets::SomeSpanOrSingle<1>());
374 });
375}
376
377} // namespace blender::nodes::node_composite_rgb_curves_cc
378
380{
382
383 static blender::bke::bNodeType ntype;
384
385 cmp_node_type_base(&ntype, "CompositorNodeCurveRGB", CMP_NODE_CURVE_RGB);
386 ntype.ui_name = "RGB Curves";
387 ntype.ui_description = "Perform level adjustments on each color channel of an image";
388 ntype.enum_name_legacy = "CURVE_RGB";
390 ntype.declare = file_ns::cmp_node_rgbcurves_declare;
391 blender::bke::node_type_size(ntype, 200, 140, 320);
392 ntype.initfunc = file_ns::node_composit_init_curve_rgb;
394 ntype.gpu_fn = file_ns::node_gpu_material;
395 ntype.build_multi_function = file_ns::node_build_multi_function;
396
398}
void BKE_curvemapping_compute_range_dividers(const CurveMapping *curve_mapping, float dividers[4])
void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
void BKE_curvemapping_get_range_minimums(const CurveMapping *curve_mapping, float minimums[4])
void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3], const float black[3], const float bwmul[3])
bool BKE_curvemapping_is_map_identity(const CurveMapping *curve_mapping, int index)
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3])
void BKE_curvemapping_init(CurveMapping *cumap)
CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition colortools.cc:89
void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
void BKE_curvemapping_compute_slopes(const CurveMapping *curve_mapping, float start_slopes[4], float end_slopes[4])
#define NODE_CLASS_OP_VECTOR
Definition BKE_node.hh:436
#define NODE_CLASS_OP_COLOR
Definition BKE_node.hh:435
#define NODE_CLASS_INPUT
Definition BKE_node.hh:433
#define CMP_NODE_TIME
#define CMP_NODE_CURVE_RGB
#define CMP_NODE_CURVE_VEC
@ CURVE_TONE_FILMLIKE
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
GPUNodeLink * GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *r_row)
bool GPU_link(GPUMaterial *mat, const char *name,...)
GPUNodeLink * GPU_uniform(const float *num)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_FACTOR
Definition RNA_types.hh:239
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
Result & get_input(StringRef identifier) const
Definition operation.cc:138
T get_single_value_default(const T &default_value) const
void set_single_value(const T &value)
void construct_and_set_matching_fn_cb(Fn &&create_multi_function)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
#define CM_TOT
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5573
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
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:5603
GPUNodeStack & get_shader_node_input(const bNode &node, GPUNodeStack inputs[], StringRef identifier)
GPUNodeLink * get_shader_node_input_link(const bNode &node, GPUNodeStack inputs[], StringRef identifier)
T clamp(const T &a, const T &min, const T &max)
T interpolate(const T &a, const T &b, const FactorT &t)
static CurveMapping * get_curve_mapping(const bNode &node)
static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
static void node_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
static void node_composit_init_curve_rgb(bNodeTree *, bNode *node)
static int node_gpu_material(GPUMaterial *material, bNode *node, bNodeExecData *, GPUNodeStack *inputs, GPUNodeStack *outputs)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void cmp_node_time_declare(NodeDeclarationBuilder &b)
static void node_composit_init_curves_time(bNodeTree *, bNode *node)
static CurveMapping * get_curve_mapping(const bNode &node)
static void node_buts_curvevec(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_composit_init_curve_vec(bNodeTree *, bNode *node)
static void node_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
static int node_gpu_material(GPUMaterial *material, bNode *node, bNodeExecData *, GPUNodeStack *inputs, GPUNodeStack *outputs)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
static void register_node_type_cmp_curve_vec()
static void register_node_type_cmp_curve_time()
static void register_node_type_cmp_curve_rgb()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
void node_copy_curves(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:49
void node_free_curves(bNode *node)
Definition node_util.cc:37
#define min(a, b)
Definition sort.cc:36
void * storage
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:336
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:330
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:344
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
NodeDeclareFunction declare
Definition BKE_node.hh:355
max
Definition text_draw.cc:251
PointerRNA * ptr
Definition wm_files.cc:4226