From d10ea97053c5bca605d94ddb09dd2c5934fcccfb Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sun, 5 Sep 2021 15:22:30 -0400 Subject: Compositor: New Posterize Node The posterize node limits the number of colors per channel. This is useful to generate masks or to generate stylized images Both the tiled and full-frame implementation are included in this patch {F10314012} Reviewed By: manzanilla, jbakker Differential Revision: https://developer.blender.org/D12304 --- .../operations/COM_PosterizeOperation.cc | 82 ++++++++++++++++++++++ .../compositor/operations/COM_PosterizeOperation.h | 56 +++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 source/blender/compositor/operations/COM_PosterizeOperation.cc create mode 100644 source/blender/compositor/operations/COM_PosterizeOperation.h (limited to 'source/blender/compositor/operations') diff --git a/source/blender/compositor/operations/COM_PosterizeOperation.cc b/source/blender/compositor/operations/COM_PosterizeOperation.cc new file mode 100644 index 00000000000..db5860f48f8 --- /dev/null +++ b/source/blender/compositor/operations/COM_PosterizeOperation.cc @@ -0,0 +1,82 @@ +/* + * 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_PosterizeOperation.h" + +namespace blender::compositor { + +PosterizeOperation::PosterizeOperation() +{ + this->addInputSocket(DataType::Color); + this->addInputSocket(DataType::Value); + this->addOutputSocket(DataType::Color); + this->m_inputProgram = nullptr; + this->m_inputStepsProgram = nullptr; + flags.can_be_constant = true; +} + +void PosterizeOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputStepsProgram = this->getInputSocketReader(1); +} + +void PosterizeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float inputSteps[4]; + + this->m_inputProgram->readSampled(inputValue, x, y, sampler); + this->m_inputStepsProgram->readSampled(inputSteps, x, y, sampler); + CLAMP(inputSteps[0], 2.0f, 1024.0f); + const float steps_inv = 1.0f / inputSteps[0]; + + output[0] = floor(inputValue[0] / steps_inv) * steps_inv; + output[1] = floor(inputValue[1] / steps_inv) * steps_inv; + output[2] = floor(inputValue[2] / steps_inv) * steps_inv; + output[3] = inputValue[3]; +} + +void PosterizeOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span inputs) +{ + for (BuffersIterator it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *in_value = it.in(0); + const float *in_steps = it.in(1); + float steps = in_steps[0]; + CLAMP(steps, 2.0f, 1024.0f); + const float steps_inv = 1.0f / steps; + + it.out[0] = floor(in_value[0] / steps_inv) * steps_inv; + it.out[1] = floor(in_value[1] / steps_inv) * steps_inv; + it.out[2] = floor(in_value[2] / steps_inv) * steps_inv; + it.out[3] = in_value[3]; + } +} + +void PosterizeOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputStepsProgram = nullptr; +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PosterizeOperation.h b/source/blender/compositor/operations/COM_PosterizeOperation.h new file mode 100644 index 00000000000..c625cbb83c6 --- /dev/null +++ b/source/blender/compositor/operations/COM_PosterizeOperation.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#pragma once + +#include "COM_MultiThreadedOperation.h" + +namespace blender::compositor { + +class PosterizeOperation : public MultiThreadedOperation { + private: + /** + * Cached reference to the inputProgram + */ + SocketReader *m_inputProgram; + SocketReader *m_inputStepsProgram; + + public: + PosterizeOperation(); + + /** + * The inner loop of this operation. + */ + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + /** + * Initialize the execution + */ + void initExecution() override; + + /** + * Deinitialize the execution + */ + void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span inputs) override; +}; + +} // namespace blender::compositor -- cgit v1.2.3