|
Blender
V2.59
|
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