Blender  V2.59
CMP_colorbalance.c
Go to the documentation of this file.
00001 /*
00002  * 
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2006 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Matt Ebb.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00036 #include "../CMP_util.h"
00037 
00038 
00039 /* ******************* Color Balance ********************************* */
00040 static bNodeSocketType cmp_node_colorbalance_in[]={
00041         {SOCK_VALUE, 1, "Fac",  1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00042         {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
00043         {-1,0,""}
00044 };
00045 
00046 static bNodeSocketType cmp_node_colorbalance_out[]={
00047         {SOCK_RGBA,0,"Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
00048         {-1,0,""}
00049 };
00050 
00051 /* this function implements ASC-CDL according to the spec at http://www.asctech.org/
00052  Slope
00053        S = in * slope
00054  Offset
00055        O = S + offset 
00056          = (in * slope) + offset
00057  Power
00058      out = Clamp(O) ^ power
00059          = Clamp((in * slope) + offset) ^ power
00060  */
00061 DO_INLINE float colorbalance_cdl(float in, float offset, float power, float slope)
00062 {
00063         float x = in * slope + offset;
00064         
00065         /* prevent NaN */
00066         CLAMP(x, 0.0, 1.0);
00067         
00068         return powf(x, power);
00069 }
00070 
00071 /* note: lift_lgg is just 2-lift, gamma_inv is 1.0/gamma */
00072 DO_INLINE float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain)
00073 {
00074         /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty
00075          * but best keep it this way, sice testing for durian shows a similar calculation
00076          * without lin/srgb conversions gives bad results (over-saturated shadows) with colors
00077          * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or lighter tones - campbell */
00078         float x= (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain;
00079 
00080         /* prevent NaN */
00081         if (x < 0.f) x = 0.f;
00082 
00083         return powf(srgb_to_linearrgb(x), gamma_inv);
00084 }
00085 
00086 static void do_colorbalance_cdl(bNode *node, float* out, float *in)
00087 {
00088         NodeColorBalance *n= (NodeColorBalance *)node->storage;
00089         
00090         out[0] = colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
00091         out[1] = colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
00092         out[2] = colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
00093         out[3] = in[3];
00094 }
00095 
00096 static void do_colorbalance_cdl_fac(bNode *node, float* out, float *in, float *fac)
00097 {
00098         NodeColorBalance *n= (NodeColorBalance *)node->storage;
00099         const float mfac= 1.0f - *fac;
00100         
00101         out[0] = mfac*in[0] + *fac * colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
00102         out[1] = mfac*in[1] + *fac * colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
00103         out[2] = mfac*in[2] + *fac * colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
00104         out[3] = in[3];
00105 }
00106 
00107 static void do_colorbalance_lgg(bNode *node, float* out, float *in)
00108 {
00109         NodeColorBalance *n= (NodeColorBalance *)node->storage;
00110 
00111         out[0] = colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
00112         out[1] = colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
00113         out[2] = colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
00114         out[3] = in[3];
00115 }
00116 
00117 static void do_colorbalance_lgg_fac(bNode *node, float* out, float *in, float *fac)
00118 {
00119         NodeColorBalance *n= (NodeColorBalance *)node->storage;
00120         const float mfac= 1.0f - *fac;
00121 
00122         out[0] = mfac*in[0] + *fac * colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
00123         out[1] = mfac*in[1] + *fac * colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
00124         out[2] = mfac*in[2] + *fac * colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
00125         out[3] = in[3];
00126 }
00127 
00128 static void node_composit_exec_colorbalance(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
00129 {
00130         CompBuf *cbuf= in[1]->data;
00131         CompBuf *stackbuf;
00132         
00133         /* stack order input:  fac, image */
00134         /* stack order output: image */
00135         if(out[0]->hasoutput==0) return;
00136         
00137         if(in[0]->vec[0] == 0.f && in[0]->data == NULL) {
00138                 out[0]->data = pass_on_compbuf(cbuf);
00139                 return;
00140         }
00141 
00142         {
00143                 NodeColorBalance *n= (NodeColorBalance *)node->storage;
00144                 int c;
00145 
00146                 for (c = 0; c < 3; c++) {
00147                         n->lift_lgg[c] = 2.0f - n->lift[c];
00148                         n->gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f/n->gamma[c] : 1000000.0f;
00149                 }
00150         }
00151 
00152         if (cbuf) {
00153                 stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* create output based on image input */
00154                         
00155                 if (node->custom1 == 0) {
00156                         /* lift gamma gain */
00157                         if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
00158                                 composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_lgg, CB_RGBA);
00159                         }
00160                         else {
00161                                 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);
00162                         }
00163                 } else {
00164                         /* offset/power/slope : ASC-CDL */
00165                         if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
00166                                 composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_cdl, CB_RGBA);
00167                         }
00168                         else {
00169                                 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);
00170                         }
00171                         
00172                 }
00173 
00174                 out[0]->data=stackbuf;
00175         }
00176 }
00177 
00178 static void node_composit_init_colorbalance(bNode *node)
00179 {
00180         NodeColorBalance *n= node->storage= MEM_callocN(sizeof(NodeColorBalance), "node colorbalance");
00181 
00182         n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
00183         n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
00184         n->gain[0] = n->gain[1] = n->gain[2] = 1.0f;
00185 }
00186 
00187 void register_node_type_cmp_colorbalance(ListBase *lb)
00188 {
00189         static bNodeType ntype;
00190 
00191         node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, NODE_OPTIONS,
00192                 cmp_node_colorbalance_in, cmp_node_colorbalance_out);
00193         node_type_size(&ntype, 400, 200, 400);
00194         node_type_init(&ntype, node_composit_init_colorbalance);
00195         node_type_storage(&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
00196         node_type_exec(&ntype, node_composit_exec_colorbalance);
00197 
00198         nodeRegisterType(lb, &ntype);
00199 }
00200 
00201