diff options
Diffstat (limited to 'source/blender/compositor/operations/COM_TransformOperation.cc')
-rw-r--r-- | source/blender/compositor/operations/COM_TransformOperation.cc | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc new file mode 100644 index 00000000000..2feaa0ae16d --- /dev/null +++ b/source/blender/compositor/operations/COM_TransformOperation.cc @@ -0,0 +1,156 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_TransformOperation.h" +#include "COM_ConstantOperation.h" +#include "COM_RotateOperation.h" +#include "COM_ScaleOperation.h" + +#include "BLI_math.h" + +namespace blender::compositor { + +TransformOperation::TransformOperation() +{ + addInputSocket(DataType::Color); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addOutputSocket(DataType::Color); + translate_factor_x_ = 1.0f; + translate_factor_y_ = 1.0f; + convert_degree_to_rad_ = false; + sampler_ = PixelSampler::Bilinear; + invert_ = false; +} + +void TransformOperation::init_data() +{ + /* Translation. */ + translate_x_ = 0; + NodeOperation *x_op = getInputOperation(X_INPUT_INDEX); + if (x_op->get_flags().is_constant_operation) { + translate_x_ = static_cast<ConstantOperation *>(x_op)->get_constant_elem()[0] * + translate_factor_x_; + } + translate_y_ = 0; + NodeOperation *y_op = getInputOperation(Y_INPUT_INDEX); + if (y_op->get_flags().is_constant_operation) { + translate_y_ = static_cast<ConstantOperation *>(y_op)->get_constant_elem()[0] * + translate_factor_y_; + } + + /* Scaling. */ + scale_center_x_ = getWidth() / 2.0; + scale_center_y_ = getHeight() / 2.0; + constant_scale_ = 1.0f; + NodeOperation *scale_op = getInputOperation(SCALE_INPUT_INDEX); + if (scale_op->get_flags().is_constant_operation) { + constant_scale_ = static_cast<ConstantOperation *>(scale_op)->get_constant_elem()[0]; + } + + /* Rotation. */ + rotate_center_x_ = (getWidth() - 1.0) / 2.0; + rotate_center_y_ = (getHeight() - 1.0) / 2.0; + NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); + const bool is_constant_degree = degree_op->get_flags().is_constant_operation; + const float degree = is_constant_degree ? + static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] : + 0.0f; + const double rad = convert_degree_to_rad_ ? DEG2RAD((double)degree) : degree; + rotate_cosine_ = cos(rad); + rotate_sine_ = sin(rad); +} + +void TransformOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case IMAGE_INPUT_INDEX: { + BLI_rcti_translate(&r_input_area, translate_x_, translate_y_); + ScaleOperation::scale_area( + r_input_area, scale_center_x_, scale_center_y_, constant_scale_, constant_scale_); + RotateOperation::get_area_rotation_bounds(r_input_area, + rotate_center_x_, + rotate_center_y_, + rotate_sine_, + rotate_cosine_, + r_input_area); + expand_area_for_sampler(r_input_area, sampler_); + break; + } + case X_INPUT_INDEX: + case Y_INPUT_INDEX: + case DEGREE_INPUT_INDEX: { + r_input_area = COM_SINGLE_ELEM_AREA; + break; + } + case SCALE_INPUT_INDEX: { + r_input_area = output_area; + break; + } + } +} + +void TransformOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *input_scale = inputs[SCALE_INPUT_INDEX]; + BuffersIterator<float> it = output->iterate_with({input_scale}, area); + if (invert_) { + transform_inverted(it, input_img); + } + else { + transform(it, input_img); + } +} + +void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img) +{ + for (; !it.is_end(); ++it) { + const float scale = *it.in(0); + float x = it.x - translate_x_; + float y = it.y - translate_y_; + RotateOperation::rotate_coords( + x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); + x = ScaleOperation::scale_coord(x, scale_center_x_, scale); + y = ScaleOperation::scale_coord(y, scale_center_y_, scale); + input_img->read_elem_sampled(x, y, sampler_, it.out); + } +} + +void TransformOperation::transform_inverted(BuffersIterator<float> &it, + const MemoryBuffer *input_img) +{ + for (; !it.is_end(); ++it) { + const float scale = *it.in(0); + float x = ScaleOperation::scale_coord(it.x, scale_center_x_, scale); + float y = ScaleOperation::scale_coord(it.y, scale_center_y_, scale); + RotateOperation::rotate_coords( + x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); + x -= translate_x_; + y -= translate_y_; + input_img->read_elem_sampled(x, y, sampler_, it.out); + } +} + +} // namespace blender::compositor |