doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_colorbalance.c
index 9d3a670fad2b1b3908c09dc9465ed8b73f48046f..0cecb764722a44ae5748839fca81ad5bc61252de 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * 
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -15,7 +15,7 @@
  *
  * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2006 Blender Foundation.
  * All rights reserved.
@@ -43,38 +43,84 @@ static bNodeSocketType cmp_node_colorbalance_out[]={
        {-1,0,""}
 };
 
-DO_INLINE float colorbalance(float in, float slope, float offset, float power)
+/* this function implements ASC-CDL according to the spec at http://www.asctech.org/
+ Slope
+       S = in * slope
+ Offset
+       O = S + offset 
+         = (in * slope) + offset
+ Power
+     out = Clamp(O) ^ power
+         = Clamp((in * slope) + offset) ^ power
+ */
+DO_INLINE float colorbalance_cdl(float in, float offset, float power, float slope)
 {
        float x = in * slope + offset;
        
        /* prevent NaN */
-       if (x < 0.f) x = 0.f;
+       CLAMP(x, 0.0, 1.0);
        
        return powf(x, power);
 }
 
-static void do_colorbalance(bNode *node, float* out, float *in)
+/* note: lift_lgg is just 2-lift, gamma_inv is 1.0/gamma */
+DO_INLINE float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain)
+{
+       /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty
+        * but best keep it this way, sice testing for durian shows a similar calculation
+        * without lin/srgb conversions gives bad results (over-saturated shadows) with colors
+        * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or lighter tones - campbell */
+       float x= (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain;
+
+       /* prevent NaN */
+       if (x < 0.f) x = 0.f;
+
+       return powf(srgb_to_linearrgb(x), gamma_inv);
+}
+
+static void do_colorbalance_cdl(bNode *node, float* out, float *in)
 {
        NodeColorBalance *n= (NodeColorBalance *)node->storage;
        
-       out[0] = colorbalance(in[0], n->slope[0], n->offset[0], n->power[0]);
-       out[1] = colorbalance(in[1], n->slope[1], n->offset[1], n->power[1]);
-       out[2] = colorbalance(in[2], n->slope[2], n->offset[2], n->power[2]);
+       out[0] = colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
+       out[1] = colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
+       out[2] = colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
        out[3] = in[3];
 }
 
-static void do_colorbalance_fac(bNode *node, float* out, float *in, float *fac)
+static void do_colorbalance_cdl_fac(bNode *node, float* out, float *in, float *fac)
 {
        NodeColorBalance *n= (NodeColorBalance *)node->storage;
        const float mfac= 1.0f - *fac;
        
-       out[0] = mfac*in[0] + *fac * colorbalance(in[0], n->slope[0], n->offset[0], n->power[0]);
-       out[1] = mfac*in[1] + *fac * colorbalance(in[1], n->slope[1], n->offset[1], n->power[1]);
-       out[2] = mfac*in[2] + *fac * colorbalance(in[2], n->slope[2], n->offset[2], n->power[2]);
+       out[0] = mfac*in[0] + *fac * colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
+       out[1] = mfac*in[1] + *fac * colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
+       out[2] = mfac*in[2] + *fac * colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
        out[3] = in[3];
 }
 
-static void node_composit_exec_colorbalance(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+static void do_colorbalance_lgg(bNode *node, float* out, float *in)
+{
+       NodeColorBalance *n= (NodeColorBalance *)node->storage;
+
+       out[0] = colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
+       out[1] = colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
+       out[2] = colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
+       out[3] = in[3];
+}
+
+static void do_colorbalance_lgg_fac(bNode *node, float* out, float *in, float *fac)
+{
+       NodeColorBalance *n= (NodeColorBalance *)node->storage;
+       const float mfac= 1.0f - *fac;
+
+       out[0] = mfac*in[0] + *fac * colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
+       out[1] = mfac*in[1] + *fac * colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
+       out[2] = mfac*in[2] + *fac * colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
+       out[3] = in[3];
+}
+
+static void node_composit_exec_colorbalance(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
 {
        CompBuf *cbuf= in[1]->data;
        CompBuf *stackbuf;
@@ -87,15 +133,37 @@ static void node_composit_exec_colorbalance(void *data, bNode *node, bNodeStack
                out[0]->data = pass_on_compbuf(cbuf);
                return;
        }
-       
+
+       {
+               NodeColorBalance *n= (NodeColorBalance *)node->storage;
+               int c;
+
+               for (c = 0; c < 3; c++) {
+                       n->lift_lgg[c] = 2.0f - n->lift[c];
+                       n->gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f/n->gamma[c] : 1000000.0f;
+               }
+       }
+
        if (cbuf) {
                stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* create output based on image input */
-                               
-               if ((in[0]->data==NULL) && (in[0]->vec[0] == 1.f)) {
-                       composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance, CB_RGBA);
-               }
-               else {
-                       composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_colorbalance_fac, CB_RGBA, CB_VAL);
+                       
+               if (node->custom1 == 0) {
+                       /* lift gamma gain */
+                       if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
+                               composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_lgg, CB_RGBA);
+                       }
+                       else {
+                               composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_colorbalance_lgg_fac, CB_RGBA, CB_VAL);
+                       }
+               } else {
+                       /* offset/power/slope : ASC-CDL */
+                       if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
+                               composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_cdl, CB_RGBA);
+                       }
+                       else {
+                               composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_colorbalance_cdl_fac, CB_RGBA, CB_VAL);
+                       }
+                       
                }
 
                out[0]->data=stackbuf;
@@ -105,30 +173,24 @@ static void node_composit_exec_colorbalance(void *data, bNode *node, bNodeStack
 static void node_composit_init_colorbalance(bNode *node)
 {
        NodeColorBalance *n= node->storage= MEM_callocN(sizeof(NodeColorBalance), "node colorbalance");
-       n->slope[0] = n->slope[1] = n->slope[2] = 1.f;
-       n->offset[0] = n->offset[1] = n->offset[2] = 0.f;
-       n->power[0] = n->power[1] = n->power[2] = 1.f;
-       
-       /* for ui, converted to slope/offset/power in RNA */
-       n->lift[0] = n->lift[1] = n->lift[2] = 0.5f;
-       n->gamma[0] = n->gamma[1] = n->gamma[2] = 0.5f;
-       n->gain[0] = n->gain[1] = n->gain[2] = 0.5f;
+
+       n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
+       n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
+       n->gain[0] = n->gain[1] = n->gain[2] = 1.0f;
+}
+
+void register_node_type_cmp_colorbalance(ListBase *lb)
+{
+       static bNodeType ntype;
+
+       node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+               cmp_node_colorbalance_in, cmp_node_colorbalance_out);
+       node_type_size(&ntype, 400, 200, 400);
+       node_type_init(&ntype, node_composit_init_colorbalance);
+       node_type_storage(&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
+       node_type_exec(&ntype, node_composit_exec_colorbalance);
+
+       nodeRegisterType(lb, &ntype);
 }
 
-bNodeType cmp_node_colorbalance={
-       /* *next,*prev */       NULL, NULL,
-       /* type code   */       CMP_NODE_COLORBALANCE,
-       /* name        */       "Color Balance",
-       /* width+range */       400, 200, 400,
-       /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
-       /* input sock  */       cmp_node_colorbalance_in,
-       /* output sock */       cmp_node_colorbalance_out,
-       /* storage     */       "NodeColorBalance",
-       /* execfunc    */       node_composit_exec_colorbalance,
-       /* butfunc     */       NULL,
-       /* initfunc    */       node_composit_init_colorbalance,
-       /* freestoragefunc    */        node_free_standard_storage,
-       /* copystoragefunc    */        node_copy_standard_storage,
-       /* id          */       NULL
-};