1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup shdnodes
22  */
23 
24 #include "node_shader_util.h"
25 
26 /* **************** CURVE VEC  ******************** */
27 static bNodeSocketTemplate sh_node_curve_vec_in[] = {
28     {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
29     {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
30     {-1, ""},
31 };
32 
33 static bNodeSocketTemplate sh_node_curve_vec_out[] = {
34     {SOCK_VECTOR, N_("Vector")},
35     {-1, ""},
36 };
37 
node_shader_exec_curve_vec(void * UNUSED (data),int UNUSED (thread),bNode * node,bNodeExecData * UNUSED (execdata),bNodeStack ** in,bNodeStack ** out)38 static void node_shader_exec_curve_vec(void *UNUSED(data),
39                                        int UNUSED(thread),
40                                        bNode *node,
41                                        bNodeExecData *UNUSED(execdata),
42                                        bNodeStack **in,
43                                        bNodeStack **out)
44 {
45   float vec[3];
46 
47   /* stack order input:  vec */
48   /* stack order output: vec */
49   nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
50   BKE_curvemapping_evaluate3F(node->storage, out[0]->vec, vec);
51 }
52 
node_shader_init_curve_vec(bNodeTree * UNUSED (ntree),bNode * node)53 static void node_shader_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
54 {
55   node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
56 }
57 
gpu_shader_curve_vec(GPUMaterial * mat,bNode * node,bNodeExecData * UNUSED (execdata),GPUNodeStack * in,GPUNodeStack * out)58 static int gpu_shader_curve_vec(GPUMaterial *mat,
59                                 bNode *node,
60                                 bNodeExecData *UNUSED(execdata),
61                                 GPUNodeStack *in,
62                                 GPUNodeStack *out)
63 {
64   float *array, layer;
65   int size;
66 
67   CurveMapping *cumap = node->storage;
68 
69   BKE_curvemapping_table_RGBA(cumap, &array, &size);
70   GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
71 
72   float ext_xyz[3][4];
73   float range_xyz[3];
74 
75   for (int a = 0; a < 3; a++) {
76     const CurveMap *cm = &cumap->cm[a];
77     ext_xyz[a][0] = cm->mintable;
78     ext_xyz[a][2] = cm->maxtable;
79     range_xyz[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
80     /* Compute extrapolation gradients. */
81     if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
82       ext_xyz[a][1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_xyz[a])) :
83                                                 1e8f;
84       ext_xyz[a][3] = (cm->ext_out[0] != 0.0f) ?
85                           (cm->ext_out[1] / (cm->ext_out[0] * range_xyz[a])) :
86                           1e8f;
87     }
88     else {
89       ext_xyz[a][1] = 0.0f;
90       ext_xyz[a][3] = 0.0f;
91     }
92   }
93 
94   return GPU_stack_link(mat,
95                         node,
96                         "curves_vec",
97                         in,
98                         out,
99                         tex,
100                         GPU_constant(&layer),
101                         GPU_uniform(range_xyz),
102                         GPU_uniform(ext_xyz[0]),
103                         GPU_uniform(ext_xyz[1]),
104                         GPU_uniform(ext_xyz[2]));
105 }
106 
register_node_type_sh_curve_vec(void)107 void register_node_type_sh_curve_vec(void)
108 {
109   static bNodeType ntype;
110 
111   sh_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
112   node_type_socket_templates(&ntype, sh_node_curve_vec_in, sh_node_curve_vec_out);
113   node_type_init(&ntype, node_shader_init_curve_vec);
114   node_type_size_preset(&ntype, NODE_SIZE_LARGE);
115   node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
116   node_type_exec(&ntype, node_initexec_curves, NULL, node_shader_exec_curve_vec);
117   node_type_gpu(&ntype, gpu_shader_curve_vec);
118 
119   nodeRegisterType(&ntype);
120 }
121 
122 /* **************** CURVE RGB  ******************** */
123 static bNodeSocketTemplate sh_node_curve_rgb_in[] = {
124     {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_FACTOR},
125     {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
126     {-1, ""},
127 };
128 
129 static bNodeSocketTemplate sh_node_curve_rgb_out[] = {
130     {SOCK_RGBA, N_("Color")},
131     {-1, ""},
132 };
133 
node_shader_exec_curve_rgb(void * UNUSED (data),int UNUSED (thread),bNode * node,bNodeExecData * UNUSED (execdata),bNodeStack ** in,bNodeStack ** out)134 static void node_shader_exec_curve_rgb(void *UNUSED(data),
135                                        int UNUSED(thread),
136                                        bNode *node,
137                                        bNodeExecData *UNUSED(execdata),
138                                        bNodeStack **in,
139                                        bNodeStack **out)
140 {
141   float vec[3];
142   float fac;
143 
144   /* stack order input:  vec */
145   /* stack order output: vec */
146   nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
147   nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
148   BKE_curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec);
149   if (fac != 1.0f) {
150     interp_v3_v3v3(out[0]->vec, vec, out[0]->vec, fac);
151   }
152 }
153 
node_shader_init_curve_rgb(bNodeTree * UNUSED (ntree),bNode * node)154 static void node_shader_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
155 {
156   node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
157 }
158 
gpu_shader_curve_rgb(GPUMaterial * mat,bNode * node,bNodeExecData * UNUSED (execdata),GPUNodeStack * in,GPUNodeStack * out)159 static int gpu_shader_curve_rgb(GPUMaterial *mat,
160                                 bNode *node,
161                                 bNodeExecData *UNUSED(execdata),
162                                 GPUNodeStack *in,
163                                 GPUNodeStack *out)
164 {
165   float *array, layer;
166   int size;
167   bool use_opti = true;
168 
169   CurveMapping *cumap = node->storage;
170 
171   BKE_curvemapping_init(cumap);
172   BKE_curvemapping_table_RGBA(cumap, &array, &size);
173   GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
174 
175   float ext_rgba[4][4];
176   float range_rgba[4];
177 
178   for (int a = 0; a < CM_TOT; a++) {
179     const CurveMap *cm = &cumap->cm[a];
180     ext_rgba[a][0] = cm->mintable;
181     ext_rgba[a][2] = cm->maxtable;
182     range_rgba[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
183     /* Compute extrapolation gradients. */
184     if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
185       ext_rgba[a][1] = (cm->ext_in[0] != 0.0f) ?
186                            (cm->ext_in[1] / (cm->ext_in[0] * range_rgba[a])) :
187                            1e8f;
188       ext_rgba[a][3] = (cm->ext_out[0] != 0.0f) ?
189                            (cm->ext_out[1] / (cm->ext_out[0] * range_rgba[a])) :
190                            1e8f;
191     }
192     else {
193       ext_rgba[a][1] = 0.0f;
194       ext_rgba[a][3] = 0.0f;
195     }
196 
197     /* Check if rgb comps are just linear. */
198     if (a < 3) {
199       if (range_rgba[a] != 1.0f || ext_rgba[a][1] != 1.0f || ext_rgba[a][2] != 1.0f ||
200           cm->totpoint != 2 || cm->curve[0].x != 0.0f || cm->curve[0].y != 0.0f ||
201           cm->curve[1].x != 1.0f || cm->curve[1].y != 1.0f) {
202         use_opti = false;
203       }
204     }
205   }
206 
207   if (use_opti) {
208     return GPU_stack_link(mat,
209                           node,
210                           "curves_rgb_opti",
211                           in,
212                           out,
213                           tex,
214                           GPU_constant(&layer),
215                           GPU_uniform(range_rgba),
216                           GPU_uniform(ext_rgba[3]));
217   }
218 
219   return GPU_stack_link(mat,
220                         node,
221                         "curves_rgb",
222                         in,
223                         out,
224                         tex,
225                         GPU_constant(&layer),
226                         GPU_uniform(range_rgba),
227                         GPU_uniform(ext_rgba[0]),
228                         GPU_uniform(ext_rgba[1]),
229                         GPU_uniform(ext_rgba[2]),
230                         GPU_uniform(ext_rgba[3]));
231 }
232 
register_node_type_sh_curve_rgb(void)233 void register_node_type_sh_curve_rgb(void)
234 {
235   static bNodeType ntype;
236 
237   sh_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
238   node_type_socket_templates(&ntype, sh_node_curve_rgb_in, sh_node_curve_rgb_out);
239   node_type_init(&ntype, node_shader_init_curve_rgb);
240   node_type_size_preset(&ntype, NODE_SIZE_LARGE);
241   node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
242   node_type_exec(&ntype, node_initexec_curves, NULL, node_shader_exec_curve_rgb);
243   node_type_gpu(&ntype, gpu_shader_curve_rgb);
244 
245   nodeRegisterType(&ntype);
246 }
247