This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/compositor/operations/COM_MixOperation.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

951 lines
27 KiB
C++
Raw Normal View History

/*
* 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 2011, Blender Foundation.
*/
#include "COM_MixOperation.h"
#include "BLI_math.h"
2021-03-23 17:12:27 +01:00
namespace blender::compositor {
/* ******** Mix Base Operation ******** */
MixBaseOperation::MixBaseOperation()
{
2021-03-19 14:26:24 +01:00
this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Color);
this->addOutputSocket(DataType::Color);
this->m_inputValueOperation = nullptr;
this->m_inputColor1Operation = nullptr;
this->m_inputColor2Operation = nullptr;
this->setUseValueAlphaMultiply(false);
this->setUseClamp(false);
}
void MixBaseOperation::initExecution()
{
this->m_inputValueOperation = this->getInputSocketReader(0);
this->m_inputColor1Operation = this->getInputSocketReader(1);
this->m_inputColor2Operation = this->getInputSocketReader(2);
}
void MixBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]);
output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]);
output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]);
output[3] = inputColor1[3];
}
void MixBaseOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
Structural cleanup and improvements for the compositor. Many parts of the compositor are unnecessarily complicated. This patch aims at reducing the complexity of writing nodes and making the code more transparent. == Separating Nodes and Operations == Currently these are both mixed in the same graph, even though they have very different purposes and are used at distinct stages in the compositing process. The patch introduces dedicated graph classes for nodes and for operations. This removes the need for a lot of special case checks (isOperation etc.) and explicit type casts. It simplifies the code since it becomes clear at every stage what type of node we are dealing with. The compiler can use static typing to avoid common bugs from mixing up these types and fewer runtime sanity checks are needed. == Simplified Node Conversion == Converting nodes to operations was previously based on "relinking", i.e. nodes would start with by mirroring links in the Blender DNA node trees, then add operations and redirect these links to them. This was very hard to follow in many cases and required a lot of attention to avoid invalid states. Now there is a helper class called the NodeConverter, which is passed to nodes and implements a much simpler API for this process. Nodes can add operations and explicit connections as before, but defining "external" links to the inputs/outputs of the original node now uses mapping instead of directly modifying link data. Input data (node graph) and result (operations graph) are cleanly separated. == Removed Redundant Data Structures == A few redundant data structures have been removed, notably the SocketConnection. These are only needed temporarily during graph construction. For executing the compositor operations it is perfectly sufficient to store only the direct input link pointers. A common pointer indirection is avoided this way (which might also give a little performance improvement). == Avoid virtual recursive functions == Recursive virtual functions are evil. They are very hard to follow during debugging. At least in the parts this patch is concerned with these functions have been replaced by a non-virtual recursive core function (which might then call virtual non-recursive functions if needed). See for example NodeOperationBuilder::group_operations.
2014-04-15 16:06:12 +02:00
NodeOperationInput *socket;
unsigned int tempPreferredResolution[2] = {0, 0};
unsigned int tempResolution[2];
socket = this->getInputSocket(1);
socket->determineResolution(tempResolution, tempPreferredResolution);
if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) {
this->setResolutionInputSocketIndex(1);
}
else {
socket = this->getInputSocket(2);
socket->determineResolution(tempResolution, tempPreferredResolution);
if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) {
this->setResolutionInputSocketIndex(2);
}
else {
this->setResolutionInputSocketIndex(0);
}
}
NodeOperation::determineResolution(resolution, preferredResolution);
}
void MixBaseOperation::deinitExecution()
{
this->m_inputValueOperation = nullptr;
this->m_inputColor1Operation = nullptr;
this->m_inputColor2Operation = nullptr;
}
/* ******** Mix Add Operation ******** */
MixAddOperation::MixAddOperation()
{
/* pass */
}
void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
output[0] = inputColor1[0] + value * inputColor2[0];
output[1] = inputColor1[1] + value * inputColor2[1];
output[2] = inputColor1[2] + value * inputColor2[2];
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Blend Operation ******** */
MixBlendOperation::MixBlendOperation()
{
/* pass */
}
void MixBlendOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
float value;
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
value = inputValue[0];
2018-06-17 17:05:29 +02:00
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]);
output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]);
output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Burn Operation ******** */
MixColorBurnOperation::MixColorBurnOperation()
{
/* pass */
}
2019-08-25 15:59:04 +10:00
void MixColorBurnOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
float tmp;
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
tmp = valuem + value * inputColor2[0];
if (tmp <= 0.0f) {
output[0] = 0.0f;
}
else {
tmp = 1.0f - (1.0f - inputColor1[0]) / tmp;
if (tmp < 0.0f) {
output[0] = 0.0f;
}
else if (tmp > 1.0f) {
output[0] = 1.0f;
}
else {
output[0] = tmp;
}
}
tmp = valuem + value * inputColor2[1];
if (tmp <= 0.0f) {
output[1] = 0.0f;
}
else {
tmp = 1.0f - (1.0f - inputColor1[1]) / tmp;
if (tmp < 0.0f) {
output[1] = 0.0f;
}
else if (tmp > 1.0f) {
output[1] = 1.0f;
}
else {
output[1] = tmp;
}
}
tmp = valuem + value * inputColor2[2];
if (tmp <= 0.0f) {
output[2] = 0.0f;
}
else {
tmp = 1.0f - (1.0f - inputColor1[2]) / tmp;
if (tmp < 0.0f) {
output[2] = 0.0f;
}
else if (tmp > 1.0f) {
output[2] = 1.0f;
}
else {
output[2] = tmp;
}
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Color Operation ******** */
MixColorOperation::MixColorOperation()
{
/* pass */
}
void MixColorOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
float colH, colS, colV;
rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
if (colS != 0.0f) {
float rH, rS, rV;
float tmpr, tmpg, tmpb;
rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
output[0] = (valuem * inputColor1[0]) + (value * tmpr);
output[1] = (valuem * inputColor1[1]) + (value * tmpg);
output[2] = (valuem * inputColor1[2]) + (value * tmpb);
}
else {
copy_v3_v3(output, inputColor1);
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Darken Operation ******** */
MixDarkenOperation::MixDarkenOperation()
{
/* pass */
}
void MixDarkenOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
output[0] = min_ff(inputColor1[0], inputColor2[0]) * value + inputColor1[0] * valuem;
output[1] = min_ff(inputColor1[1], inputColor2[1]) * value + inputColor1[1] * valuem;
output[2] = min_ff(inputColor1[2], inputColor2[2]) * value + inputColor1[2] * valuem;
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Difference Operation ******** */
MixDifferenceOperation::MixDifferenceOperation()
{
/* pass */
}
void MixDifferenceOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
2015-08-25 08:50:53 +10:00
output[0] = valuem * inputColor1[0] + value * fabsf(inputColor1[0] - inputColor2[0]);
output[1] = valuem * inputColor1[1] + value * fabsf(inputColor1[1] - inputColor2[1]);
output[2] = valuem * inputColor1[2] + value * fabsf(inputColor1[2] - inputColor2[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Difference Operation ******** */
MixDivideOperation::MixDivideOperation()
{
/* pass */
}
void MixDivideOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
if (inputColor2[0] != 0.0f) {
output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0];
}
else {
output[0] = 0.0f;
}
if (inputColor2[1] != 0.0f) {
output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1];
}
else {
output[1] = 0.0f;
}
if (inputColor2[2] != 0.0f) {
output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2];
}
else {
output[2] = 0.0f;
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Dodge Operation ******** */
MixDodgeOperation::MixDodgeOperation()
{
/* pass */
}
void MixDodgeOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
float tmp;
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
if (inputColor1[0] != 0.0f) {
tmp = 1.0f - value * inputColor2[0];
if (tmp <= 0.0f) {
output[0] = 1.0f;
}
else {
tmp = inputColor1[0] / tmp;
if (tmp > 1.0f) {
output[0] = 1.0f;
}
else {
output[0] = tmp;
}
}
}
else {
output[0] = 0.0f;
}
if (inputColor1[1] != 0.0f) {
tmp = 1.0f - value * inputColor2[1];
if (tmp <= 0.0f) {
output[1] = 1.0f;
}
else {
tmp = inputColor1[1] / tmp;
if (tmp > 1.0f) {
output[1] = 1.0f;
}
else {
output[1] = tmp;
}
}
}
else {
output[1] = 0.0f;
}
if (inputColor1[2] != 0.0f) {
tmp = 1.0f - value * inputColor2[2];
if (tmp <= 0.0f) {
output[2] = 1.0f;
}
else {
tmp = inputColor1[2] / tmp;
if (tmp > 1.0f) {
output[2] = 1.0f;
}
else {
output[2] = tmp;
}
}
}
else {
output[2] = 0.0f;
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Glare Operation ******** */
MixGlareOperation::MixGlareOperation()
{
/* pass */
}
void MixGlareOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
float value;
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
value = inputValue[0];
float mf = 2.0f - 2.0f * fabsf(value - 0.5f);
if (inputColor1[0] < 0.0f) {
inputColor1[0] = 0.0f;
}
if (inputColor1[1] < 0.0f) {
inputColor1[1] = 0.0f;
}
if (inputColor1[2] < 0.0f) {
inputColor1[2] = 0.0f;
}
2021-03-05 14:54:32 +01:00
output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f);
output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f);
output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Hue Operation ******** */
MixHueOperation::MixHueOperation()
{
/* pass */
}
void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
float colH, colS, colV;
rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
if (colS != 0.0f) {
float rH, rS, rV;
float tmpr, tmpg, tmpb;
rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
output[0] = valuem * (inputColor1[0]) + value * tmpr;
output[1] = valuem * (inputColor1[1]) + value * tmpg;
output[2] = valuem * (inputColor1[2]) + value * tmpb;
}
else {
copy_v3_v3(output, inputColor1);
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Lighten Operation ******** */
MixLightenOperation::MixLightenOperation()
{
/* pass */
}
void MixLightenOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float tmp;
tmp = value * inputColor2[0];
if (tmp > inputColor1[0]) {
output[0] = tmp;
}
else {
output[0] = inputColor1[0];
}
tmp = value * inputColor2[1];
if (tmp > inputColor1[1]) {
output[1] = tmp;
}
else {
output[1] = inputColor1[1];
}
tmp = value * inputColor2[2];
if (tmp > inputColor1[2]) {
output[2] = tmp;
}
else {
output[2] = inputColor1[2];
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Linear Light Operation ******** */
MixLinearLightOperation::MixLinearLightOperation()
{
/* pass */
}
void MixLinearLightOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
if (inputColor2[0] > 0.5f) {
output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f));
}
else {
output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f);
}
if (inputColor2[1] > 0.5f) {
output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f));
}
else {
output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f);
}
if (inputColor2[2] > 0.5f) {
output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f));
}
else {
output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f);
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Multiply Operation ******** */
MixMultiplyOperation::MixMultiplyOperation()
{
/* pass */
}
void MixMultiplyOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
output[0] = inputColor1[0] * (valuem + value * inputColor2[0]);
output[1] = inputColor1[1] * (valuem + value * inputColor2[1]);
output[2] = inputColor1[2] * (valuem + value * inputColor2[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
2021-02-05 16:23:34 +11:00
/* ******** Mix Overlay Operation ******** */
MixOverlayOperation::MixOverlayOperation()
{
/* pass */
}
void MixOverlayOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
if (inputColor1[0] < 0.5f) {
output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]);
}
else {
output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]);
}
if (inputColor1[1] < 0.5f) {
output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]);
}
else {
output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]);
}
if (inputColor1[2] < 0.5f) {
output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]);
}
else {
output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]);
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Saturation Operation ******** */
MixSaturationOperation::MixSaturationOperation()
{
/* pass */
}
void MixSaturationOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
float rH, rS, rV;
rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
if (rS != 0.0f) {
float colH, colS, colV;
rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]);
}
else {
copy_v3_v3(output, inputColor1);
}
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Screen Operation ******** */
MixScreenOperation::MixScreenOperation()
{
/* pass */
}
void MixScreenOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]);
output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]);
output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Soft Light Operation ******** */
MixSoftLightOperation::MixSoftLightOperation()
{
/* pass */
}
void MixSoftLightOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
float scr, scg, scb;
/* first calculate non-fac based Screen mix */
scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]);
scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]);
scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]);
output[0] = valuem * (inputColor1[0]) +
value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) +
(inputColor1[0] * scr));
output[1] = valuem * (inputColor1[1]) +
value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) +
(inputColor1[1] * scg));
output[2] = valuem * (inputColor1[2]) +
value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) +
(inputColor1[2] * scb));
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Subtract Operation ******** */
MixSubtractOperation::MixSubtractOperation()
{
/* pass */
}
void MixSubtractOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
output[0] = inputColor1[0] - value * (inputColor2[0]);
output[1] = inputColor1[1] - value * (inputColor2[1]);
output[2] = inputColor1[2] - value * (inputColor2[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
/* ******** Mix Value Operation ******** */
MixValueOperation::MixValueOperation()
{
/* pass */
}
void MixValueOperation::executePixelSampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float inputColor1[4];
float inputColor2[4];
float inputValue[4];
this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
float value = inputValue[0];
if (this->useValueAlphaMultiply()) {
value *= inputColor2[3];
}
float valuem = 1.0f - value;
float rH, rS, rV;
float colH, colS, colV;
rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]);
output[3] = inputColor1[3];
clampIfNeeded(output);
}
2021-03-23 17:12:27 +01:00
} // namespace blender::compositor