* removed clamp from color correction
[blender.git] / source / blender / compositor / operations / COM_ColorCorrectionOperation.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include "COM_ColorCorrectionOperation.h"
24 #include "BLI_math.h"
25
26 ColorCorrectionOperation::ColorCorrectionOperation(): NodeOperation()
27 {
28         this->addInputSocket(COM_DT_COLOR);
29         this->addInputSocket(COM_DT_VALUE);
30         this->addOutputSocket(COM_DT_COLOR);
31         this->inputImage = NULL;
32         this->inputMask = NULL;
33         this->redChannelEnabled = true;
34         this->greenChannelEnabled = true;
35         this->blueChannelEnabled = true;
36 }
37 void ColorCorrectionOperation::initExecution()
38 {
39         this->inputImage = this->getInputSocketReader(0);
40         this->inputMask = this->getInputSocketReader(1);
41 }
42
43 void ColorCorrectionOperation::executePixel(float *output, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[])
44 {
45         float inputImageColor[4];
46         float inputMask[4];
47         this->inputImage->read(inputImageColor, x, y, sampler, inputBuffers);
48         this->inputMask->read(inputMask, x, y, sampler, inputBuffers);
49         
50         float level = (inputImageColor[0] + inputImageColor[1] + inputImageColor[2])/3.0f;
51         float contrast = this->data->master.contrast;
52         float saturation = this->data->master.saturation;
53         float gamma = this->data->master.gamma;
54         float gain = this->data->master.gain;
55         float lift = this->data->master.lift;
56         float r, g, b;
57         
58         float value = inputMask[0];
59         value = min(1.0f, value);
60         const float mvalue = 1.0f - value;
61         
62         float levelShadows = 0.0;
63         float levelMidtones = 0.0;
64         float levelHighlights = 0.0;
65 #define MARGIN 0.10
66 #define MARGIN_DIV (0.5/MARGIN)
67         if (level < this->data->startmidtones-MARGIN) {
68                 levelShadows = 1.0f;
69         }
70         else if (level < this->data->startmidtones+MARGIN) {
71                 levelMidtones = ((level-this->data->startmidtones)*MARGIN_DIV)+0.5;
72                 levelShadows = 1.0 - levelMidtones;
73         }
74         else if (level < this->data->endmidtones-MARGIN) {
75                 levelMidtones = 1.0f;
76         }
77         else if (level < this->data->endmidtones+MARGIN) {
78                 levelHighlights = ((level-this->data->endmidtones)*MARGIN_DIV)+0.5;
79                 levelMidtones = 1.0 - levelHighlights;
80         }
81         else {
82                 levelHighlights = 1.0f;
83         }
84 #undef MARGIN
85 #undef MARGIN_DIV
86         contrast *= (levelShadows*this->data->shadows.contrast)+(levelMidtones*this->data->midtones.contrast)+(levelHighlights*this->data->highlights.contrast);
87         saturation *= (levelShadows*this->data->shadows.saturation)+(levelMidtones*this->data->midtones.saturation)+(levelHighlights*this->data->highlights.saturation);
88         gamma *= (levelShadows*this->data->shadows.gamma)+(levelMidtones*this->data->midtones.gamma)+(levelHighlights*this->data->highlights.gamma);
89         gain *= (levelShadows*this->data->shadows.gain)+(levelMidtones*this->data->midtones.gain)+(levelHighlights*this->data->highlights.gain);
90         lift += (levelShadows*this->data->shadows.lift)+(levelMidtones*this->data->midtones.lift)+(levelHighlights*this->data->highlights.lift);
91         
92         r = inputImageColor[0];
93         g = inputImageColor[1];
94         b = inputImageColor[2];
95         
96         float invgamma = 1.0f/gamma;
97         float luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
98         r = (luma + saturation * (r - luma));
99         g = (luma + saturation * (g - luma));
100         b = (luma + saturation * (b - luma));
101         
102         r = 0.5+((r-0.5)*contrast);
103         g = 0.5+((g-0.5)*contrast);
104         b = 0.5+((b-0.5)*contrast);
105         
106         r = powf(r*gain+lift, invgamma);
107         g = powf(g*gain+lift, invgamma);
108         b = powf(b*gain+lift, invgamma);
109         
110         
111         // mix with mask
112         r = mvalue*inputImageColor[0] + value * r;
113         g = mvalue*inputImageColor[1] + value * g;
114         b = mvalue*inputImageColor[2] + value * b;
115         
116         if (this->redChannelEnabled) {
117                 output[0] = r;
118         }
119         else {
120                 output[0] = inputImageColor[0];
121         }
122         if (this->greenChannelEnabled) {
123                 output[1] = g;
124         }
125         else {
126                 output[1] = inputImageColor[1];
127         }
128         if (this->blueChannelEnabled) {
129                 output[2] = b;
130         }
131         else {
132                 output[2] = inputImageColor[2];
133         }
134         output[3] = inputImageColor[3];
135 }
136
137 void ColorCorrectionOperation::deinitExecution()
138 {
139         this->inputImage = NULL;
140         this->inputMask = NULL;
141 }
142