Blender V4.5
node_composite_scale.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 "BLI_assert.h"
10#include "BLI_listbase.h"
12#include "BLI_math_base.hh"
13#include "BLI_math_matrix.hh"
15#include "BLI_math_vector.hh"
17#include "BLI_string.h"
18
19#include "RNA_access.hh"
20
21#include "UI_interface.hh"
22#include "UI_resources.hh"
23
24#include "GPU_shader.hh"
25#include "GPU_texture.hh"
26
27#include "COM_node_operation.hh"
28#include "COM_utilities.hh"
29
31
32/* **************** Scale ******************** */
33
35
37
39{
40 b.add_input<decl::Color>("Image")
41 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
42 .compositor_realization_mode(CompositorInputRealizationMode::None);
43 b.add_input<decl::Float>("X").default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
44 b.add_input<decl::Float>("Y").default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
45
46 b.add_output<decl::Color>("Image");
47}
48
49static void node_composit_init_scale(bNodeTree * /*ntree*/, bNode *node)
50{
53 node->storage = data;
54}
55
57{
59
60 /* Only show X/Y scale factor inputs for modes using them! */
61 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
62 if (STR_ELEM(sock->name, "X", "Y")) {
63 bke::node_set_socket_availability(*ntree, *sock, use_xy_scale);
64 }
65 }
66}
67
69{
70 layout->prop(ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
71 layout->prop(ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
72
74 layout->prop(ptr,
75 "frame_method",
77 std::nullopt,
78 ICON_NONE);
79 }
80}
81
82using namespace blender::compositor;
83
85 public:
87
88 void execute() override
89 {
90 if (is_variable_size()) {
92 }
93 else {
95 }
96 }
97
99 {
100 const float2 scale = this->get_scale();
101 const float3x3 transformation = math::from_scale<float3x3>(scale);
102
103 const Result &input = this->get_input("Image");
104 Result &output = this->get_result("Image");
105 output.share_data(input);
106 output.transform(transformation);
107 output.get_realization_options().interpolation = this->get_interpolation();
108 }
109
111 {
112 if (this->context().use_gpu()) {
114 }
115 else {
117 }
118 }
119
121 {
122 GPUShader *shader = this->context().get_shader(this->get_realization_shader_name());
123 GPU_shader_bind(shader);
124
125 Result &input = get_input("Image");
126 /* The texture sampler should use bilinear interpolation for both the bilinear and bicubic
127 * cases, as the logic used by the bicubic realization shader expects textures to use bilinear
128 * interpolation. */
129 const Interpolation interpolation = this->get_interpolation();
130 const bool use_bilinear = ELEM(interpolation, Interpolation::Bilinear, Interpolation::Bicubic);
131 GPU_texture_filter_mode(input, use_bilinear);
133 input.bind_as_texture(shader, "input_tx");
134
135 Result &x_scale = get_input("X");
136 x_scale.bind_as_texture(shader, "x_scale_tx");
137
138 Result &y_scale = get_input("Y");
139 y_scale.bind_as_texture(shader, "y_scale_tx");
140
141 Result &output = get_result("Image");
142 const Domain domain = compute_domain();
143 output.allocate_texture(domain);
144 output.bind_as_image(shader, "output_img");
145
147
148 input.unbind_as_texture();
149 x_scale.unbind_as_texture();
150 y_scale.unbind_as_texture();
151 output.unbind_as_image();
153 }
154
156 {
157 const Result &input = this->get_input("Image");
158 const Result &x_scale = this->get_input("X");
159 const Result &y_scale = this->get_input("Y");
160
161 Result &output = this->get_result("Image");
162 const Interpolation interpolation = this->get_interpolation();
163 const Domain domain = compute_domain();
164 const int2 size = domain.size;
165 output.allocate_texture(domain);
166
167 parallel_for(size, [&](const int2 texel) {
168 float2 coordinates = (float2(texel) + float2(0.5f)) / float2(size);
169 float2 center = float2(0.5f);
170
171 float2 scale = float2(x_scale.load_pixel<float, true>(texel),
172 y_scale.load_pixel<float, true>(texel));
173 float2 scaled_coordinates = center +
174 (coordinates - center) / math::max(scale, float2(0.0001f));
175 switch (interpolation) {
177 output.store_pixel(texel, input.sample_cubic_wrap(scaled_coordinates, false, false));
178 break;
180 output.store_pixel(texel, input.sample_bilinear_wrap(scaled_coordinates, false, false));
181 break;
183 output.store_pixel(texel, input.sample_nearest_wrap(scaled_coordinates, false, false));
184 break;
185 }
186 });
187 }
188
189 const char *get_realization_shader_name() const
190 {
192 return "compositor_scale_variable_bicubic";
193 }
194 return "compositor_scale_variable";
195 }
196
198 {
199 switch (node_storage(bnode()).interpolation) {
206 }
207
210 }
211
213 {
214 switch (get_scale_method()) {
216 return get_scale_relative();
218 return get_scale_absolute();
222 return get_scale_render_size();
223 default:
225 return float2(1.0f);
226 }
227 }
228
229 /* Scale by the input factors. */
231 {
232 return float2(get_input("X").get_single_value_default(1.0f),
233 get_input("Y").get_single_value_default(1.0f));
234 }
235
236 /* Scale such that the new size matches the input absolute size. */
238 {
239 const float2 input_size = float2(get_input("Image").domain().size);
240 const float2 absolute_size = float2(get_input("X").get_single_value_default(1.0f),
241 get_input("Y").get_single_value_default(1.0f));
242 return absolute_size / input_size;
243 }
244
245 /* Scale by the render resolution percentage. */
247 {
248 return float2(context().get_render_percentage());
249 }
250
252 {
253 if (!context().is_valid_compositing_region()) {
254 return float2(1.0f);
255 }
256
264 default:
266 return float2(1.0f);
267 }
268 }
269
270 /* Scale such that the new size matches the render size. Since the input is freely scaled, it is
271 * potentially stretched, hence the name. */
273 {
274 const float2 input_size = float2(get_input("Image").domain().size);
275 const float2 render_size = float2(context().get_compositing_region_size());
276 return render_size / input_size;
277 }
278
279 /* Scale such that the dimension with the smaller scaling factor matches that of the render size
280 * while maintaining the input's aspect ratio. Since the other dimension is guaranteed not to
281 * exceed the render size region due to its larger scaling factor, the image is said to be fit
282 * inside that region, hence the name. */
284 {
285 const float2 input_size = float2(get_input("Image").domain().size);
286 const float2 render_size = float2(context().get_compositing_region_size());
287 const float2 scale = render_size / input_size;
288 return float2(math::min(scale.x, scale.y));
289 }
290
291 /* Scale such that the dimension with the larger scaling factor matches that of the render size
292 * while maintaining the input's aspect ratio. Since the other dimension is guaranteed to exceed
293 * the render size region due to its lower scaling factor, the image will be cropped inside that
294 * region, hence the name. */
296 {
297 const float2 input_size = float2(get_input("Image").domain().size);
298 const float2 render_size = float2(context().get_compositing_region_size());
299 const float2 scale = render_size / input_size;
300 return float2(math::max(scale.x, scale.y));
301 }
302
304 {
305 /* Only relative scaling can be variable. */
307 return false;
308 }
309
310 return !get_input("X").is_single_value() || !get_input("Y").is_single_value();
311 }
312
314 {
315 return static_cast<CMPNodeScaleMethod>(bnode().custom1);
316 }
317
322};
323
325{
326 return new ScaleOperation(context, node);
327}
328
329} // namespace blender::nodes::node_composite_scale_cc
330
332{
333 namespace file_ns = blender::nodes::node_composite_scale_cc;
334
335 static blender::bke::bNodeType ntype;
336
337 cmp_node_type_base(&ntype, "CompositorNodeScale", CMP_NODE_SCALE);
338 ntype.ui_name = "Scale";
339 ntype.ui_description = "Change the size of the image";
340 ntype.enum_name_legacy = "SCALE";
342 ntype.declare = file_ns::cmp_node_scale_declare;
343 ntype.draw_buttons = file_ns::node_composit_buts_scale;
344 ntype.initfunc = file_ns::node_composit_init_scale;
345 ntype.updatefunc = file_ns::node_composite_update_scale;
348 ntype.get_compositor_operation = file_ns::get_compositor_operation;
349
351}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#define NODE_CLASS_DISTORT
Definition BKE_node.hh:441
#define CMP_NODE_SCALE
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define LISTBASE_FOREACH(type, var, list)
#define STR_ELEM(...)
Definition BLI_string.h:656
#define ELEM(...)
@ CMP_NODE_INTERPOLATION_NEAREST
@ CMP_NODE_INTERPOLATION_BILINEAR
@ CMP_NODE_INTERPOLATION_BICUBIC
CMPNodeScaleRenderSizeMethod
@ CMP_NODE_SCALE_RENDER_SIZE_STRETCH
@ CMP_NODE_SCALE_RENDER_SIZE_FIT
@ CMP_NODE_SCALE_RENDER_SIZE_CROP
CMPNodeScaleMethod
@ CMP_NODE_SCALE_RENDER_SIZE
@ CMP_NODE_SCALE_RELATIVE
@ CMP_NODE_SCALE_ABSOLUTE
@ CMP_NODE_SCALE_RENDER_PERCENT
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_unbind()
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
@ UI_ITEM_R_EXPAND
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
Result & get_input(StringRef identifier) const
Definition operation.cc:138
virtual Domain compute_domain()
Definition operation.cc:56
void share_data(const Result &source)
Definition result.cc:401
void unbind_as_texture() const
Definition result.cc:389
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:365
T load_pixel(const int2 &texel) const
bool is_single_value() const
Definition result.cc:625
#define input
#define output
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:5011
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
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:170
void parallel_for(const int2 range, const Function &function)
T min(const T &a, const T &b)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
T max(const T &a, const T &b)
static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
static void node_composit_init_scale(bNodeTree *, bNode *node)
static void node_composit_buts_scale(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
static void register_node_type_cmp_scale()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
#define CMP_SCALE_MAX
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
int RNA_enum_get(PointerRNA *ptr, const char *name)
#define min(a, b)
Definition sort.cc:36
int16_t custom1
ListBase inputs
void * storage
int16_t custom2
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
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:269
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
max
Definition text_draw.cc:251
PointerRNA * ptr
Definition wm_files.cc:4227