Blender V2.61 - r43446

node_composite_colorbalance.c

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