doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_colorbalance.c
index f2e5815dfeb99461040dc8ff7e6be82ad0040b43..0cecb764722a44ae5748839fca81ad5bc61252de 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * 
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -43,25 +43,39 @@ static bNodeSocketType cmp_node_colorbalance_out[]={
        {-1,0,""}
 };
 
+/* 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);
        
-       //powf(in * slope + offset, power)
-       return powf(x, 1.f/power);
+       return powf(x, power);
 }
 
-DO_INLINE float colorbalance_lgg(float in, float lift, float gamma, float gain)
+/* 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)
 {
-       float x= powf(in * gain, lift);
+       /* 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(x, (1.f/gamma));
+
+       return powf(srgb_to_linearrgb(x), gamma_inv);
 }
 
 static void do_colorbalance_cdl(bNode *node, float* out, float *in)
@@ -89,9 +103,9 @@ 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[0], n->gain[0]);
-       out[1] = colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma[1], n->gain[1]);
-       out[2] = colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma[2], n->gain[2]);
+       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];
 }
 
@@ -100,13 +114,13 @@ static void do_colorbalance_lgg_fac(bNode *node, float* out, float *in, float *f
        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[0], n->gain[0]);
-       out[1] = mfac*in[1] + *fac * colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma[1], n->gain[1]);
-       out[2] = mfac*in[2] + *fac * colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma[2], n->gain[2]);
+       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 *data, bNode *node, bNodeStack **in, bNodeStack **out)
+static void node_composit_exec_colorbalance(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
 {
        CompBuf *cbuf= in[1]->data;
        CompBuf *stackbuf;
@@ -123,8 +137,10 @@ static void node_composit_exec_colorbalance(void *data, bNode *node, bNodeStack
        {
                NodeColorBalance *n= (NodeColorBalance *)node->storage;
                int c;
+
                for (c = 0; c < 3; c++) {
-                       n->lift_lgg[c] = 2.0f - pow(n->lift[c], 2);
+                       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;
                }
        }
 
@@ -163,20 +179,18 @@ static void node_composit_init_colorbalance(bNode *node)
        n->gain[0] = n->gain[1] = n->gain[2] = 1.0f;
 }
 
-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
-};
+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);
+}
+