c3e2fc54c78ce7faa5b0be675ba7c908ac2e37ed
[blender.git] / source / blender / nodes / shader / nodes / node_shader_math.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/shader/nodes/node_shader_math.c
29  *  \ingroup shdnodes
30  */
31
32
33 #include "node_shader_util.h"
34
35
36 /* **************** SCALAR MATH ******************** */ 
37 static bNodeSocketTemplate sh_node_math_in[] = {
38         { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
39         { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
40         { -1, 0, "" }
41 };
42
43 static bNodeSocketTemplate sh_node_math_out[] = {
44         { SOCK_FLOAT, 0, N_("Value")},
45         { -1, 0, "" }
46 };
47
48 static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) 
49 {
50         switch (node->custom1) {
51         
52         case 0: /* Add */
53                 out[0]->vec[0] = in[0]->vec[0] + in[1]->vec[0];
54                 break; 
55         case 1: /* Subtract */
56                 out[0]->vec[0] = in[0]->vec[0] - in[1]->vec[0];
57                 break; 
58         case 2: /* Multiply */
59                 out[0]->vec[0] = in[0]->vec[0] * in[1]->vec[0];
60                 break; 
61         case 3: /* Divide */
62                 {
63                         if (in[1]->vec[0]==0)   /* We don't want to divide by zero. */
64                                 out[0]->vec[0] = 0.0;
65                         else
66                                 out[0]->vec[0] = in[0]->vec[0] / in[1]->vec[0];
67                         }
68                 break;
69         case 4: /* Sine */
70                 {
71                         if (in[0]->hasinput || !in[1]->hasinput)  /* This one only takes one input, so we've got to choose. */
72                                 out[0]->vec[0] = sin(in[0]->vec[0]);
73                         else
74                                 out[0]->vec[0] = sin(in[1]->vec[0]);
75                 }
76                 break;
77         case 5: /* Cosine */
78                 {
79                         if (in[0]->hasinput || !in[1]->hasinput)  /* This one only takes one input, so we've got to choose. */
80                                 out[0]->vec[0] = cos(in[0]->vec[0]);
81                         else
82                                 out[0]->vec[0] = cos(in[1]->vec[0]);
83                 }
84                 break;
85         case 6: /* Tangent */
86                 {
87                         if (in[0]->hasinput || !in[1]->hasinput)  /* This one only takes one input, so we've got to choose. */
88                                 out[0]->vec[0] = tan(in[0]->vec[0]);
89                         else
90                                 out[0]->vec[0] = tan(in[1]->vec[0]);
91                 }
92                 break;
93         case 7: /* Arc-Sine */
94                 {
95                         if (in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
96                                 /* Can't do the impossible... */
97                                 if (in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1)
98                                         out[0]->vec[0] = asin(in[0]->vec[0]);
99                                 else
100                                         out[0]->vec[0] = 0.0;
101                         }
102                         else {
103                                 /* Can't do the impossible... */
104                                 if (in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1)
105                                         out[0]->vec[0] = asin(in[1]->vec[0]);
106                                 else
107                                         out[0]->vec[0] = 0.0;
108                         }
109                 }
110                 break;
111         case 8: /* Arc-Cosine */
112                 {
113                         if (in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
114                                 /* Can't do the impossible... */
115                                 if (in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1)
116                                         out[0]->vec[0] = acos(in[0]->vec[0]);
117                                 else
118                                         out[0]->vec[0] = 0.0;
119                         }
120                         else {
121                                 /* Can't do the impossible... */
122                                 if (in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1)
123                                         out[0]->vec[0] = acos(in[1]->vec[0]);
124                                 else
125                                         out[0]->vec[0] = 0.0;
126                         }
127                 }
128                 break;
129         case 9: /* Arc-Tangent */
130                 {
131                         if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
132                                 out[0]->vec[0] = atan(in[0]->vec[0]);
133                         else
134                                 out[0]->vec[0] = atan(in[1]->vec[0]);
135                 }
136                 break;
137         case 10: /* Power */
138                 {
139                         /* Only raise negative numbers by full integers */
140                         if (in[0]->vec[0] >= 0) {
141                                 out[0]->vec[0] = pow(in[0]->vec[0], in[1]->vec[0]);
142                         }
143                         else {
144                                 float y_mod_1 = fabsf(fmodf(in[1]->vec[0], 1.0f));
145                                 
146                                 /* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */
147                                 if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
148                                         out[0]->vec[0] = powf(in[0]->vec[0], floorf(in[1]->vec[0] + 0.5f));
149                                 }
150                                 else {
151                                         out[0]->vec[0] = 0.0f;
152                                 }
153                         }
154
155                 }
156                 break;
157         case 11: /* Logarithm */
158                 {
159                         /* Don't want any imaginary numbers... */
160                         if (in[0]->vec[0] > 0  && in[1]->vec[0] > 0)
161                                 out[0]->vec[0] = log(in[0]->vec[0]) / log(in[1]->vec[0]);
162                         else
163                                 out[0]->vec[0] = 0.0;
164                 }
165                 break;
166         case 12: /* Minimum */
167                 {
168                         if (in[0]->vec[0] < in[1]->vec[0])
169                                 out[0]->vec[0] = in[0]->vec[0];
170                         else
171                                 out[0]->vec[0] = in[1]->vec[0];
172                 }
173                 break;
174         case 13: /* Maximum */
175                 {
176                         if (in[0]->vec[0] > in[1]->vec[0])
177                                 out[0]->vec[0] = in[0]->vec[0];
178                         else
179                                 out[0]->vec[0] = in[1]->vec[0];
180                 }
181                 break;
182         case 14: /* Round */
183                 {
184                         if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
185                                 out[0]->vec[0] = (in[0]->vec[0] < 0) ? (int)(in[0]->vec[0] - 0.5f) : (int)(in[0]->vec[0] + 0.5f);
186                         else
187                                 out[0]->vec[0] = (in[1]->vec[0] < 0) ? (int)(in[1]->vec[0] - 0.5f) : (int)(in[1]->vec[0] + 0.5f);
188                 }
189                 break;
190         case 15: /* Less Than */
191                 {
192                         if (in[0]->vec[0] < in[1]->vec[0])
193                                 out[0]->vec[0] = 1.0f;
194                         else
195                                 out[0]->vec[0] = 0.0f;
196                 }
197                 break;
198         case 16: /* Greater Than */
199                 {
200                         if (in[0]->vec[0] > in[1]->vec[0])
201                                 out[0]->vec[0] = 1.0f;
202                         else
203                                 out[0]->vec[0] = 0.0f;
204                 }
205                 break;
206         }
207 }
208
209 static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
210 {
211         static const char *names[] = {"math_add", "math_subtract", "math_multiply",
212                 "math_divide", "math_sine", "math_cosine", "math_tangent", "math_asin",
213                 "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max",
214                 "math_round", "math_less_than", "math_greater_than"};
215
216         switch (node->custom1) {
217                 case 0:
218                 case 1:
219                 case 2:
220                 case 3:
221                 case 10:
222                 case 11:
223                 case 12:
224                 case 13:
225                 case 15:
226                 case 16:
227                         GPU_stack_link(mat, names[node->custom1], in, out);
228                         break;
229                 case 4:
230                 case 5:
231                 case 6:
232                 case 7:
233                 case 8:
234                 case 9:
235                 case 14:
236                         if (in[0].hasinput || !in[1].hasinput) {
237                                 /* use only first item and terminator */
238                                 GPUNodeStack tmp_in[2];
239                                 memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
240                                 memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
241                                 GPU_stack_link(mat, names[node->custom1], tmp_in, out);
242                         }
243                         else {
244                                 /* use only second item and terminator */
245                                 GPUNodeStack tmp_in[2];
246                                 memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
247                                 memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
248                                 GPU_stack_link(mat, names[node->custom1], tmp_in, out);
249                         }
250                         break;
251                 default:
252                         return 0;
253         }
254         
255         return 1;
256 }
257
258 void register_node_type_sh_math(void)
259 {
260         static bNodeType ntype;
261
262         sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
263         node_type_compatibility(&ntype, NODE_OLD_SHADING|NODE_NEW_SHADING);
264         node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
265         node_type_size(&ntype, 120, 110, 160);
266         node_type_label(&ntype, node_math_label);
267         node_type_storage(&ntype, "node_math", NULL, NULL);
268         node_type_exec(&ntype, NULL, NULL, node_shader_exec_math);
269         node_type_gpu(&ntype, gpu_shader_math);
270
271         nodeRegisterType(&ntype);
272 }