Cycles: working towards texture workflow design
[blender.git] / source / blender / nodes / intern / SHD_nodes / SHD_tex_musgrave.c
1 /**
2  * $Id: SHD_output.c 32517 2010-10-16 14:32:17Z campbellbarton $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2005 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "../SHD_util.h"
31 #include "SHD_noise.h"
32
33 /* Musgrave fBm
34  *
35  * H: fractal increment parameter
36  * lacunarity: gap between successive frequencies
37  * octaves: number of frequencies in the fBm
38  *
39  * from "Texturing and Modelling: A procedural approach"
40  */
41
42 static float noise_musgrave_fBm(float p[3], int basis, float H, float lacunarity, float octaves)
43 {
44         float rmd;
45         float value = 0.0f;
46         float pwr = 1.0f;
47         float pwHL = pow(lacunarity, -H);
48         int i;
49
50         for(i = 0; i < (int)octaves; i++) {
51                 value += noise_basis(p, basis) * pwr;
52                 pwr *= pwHL;
53                 mul_v3_fl(p, lacunarity);
54         }
55
56         rmd = octaves - floor(octaves);
57         if(rmd != 0.0f)
58                 value += rmd * noise_basis(p, basis) * pwr;
59
60         return value;
61 }
62
63 /* Musgrave Multifractal
64  *
65  * H: highest fractal dimension
66  * lacunarity: gap between successive frequencies
67  * octaves: number of frequencies in the fBm
68  */
69
70 static float noise_musgrave_multi_fractal(float p[3], int basis, float H, float lacunarity, float octaves)
71 {
72         float rmd;
73         float value = 1.0f;
74         float pwr = 1.0f;
75         float pwHL = pow(lacunarity, -H);
76         int i;
77
78         for(i = 0; i < (int)octaves; i++) {
79                 value *= (pwr * noise_basis(p, basis) + 1.0f);
80                 pwr *= pwHL;
81                 mul_v3_fl(p, lacunarity);
82         }
83
84         rmd = octaves - floor(octaves);
85         if(rmd != 0.0f)
86                 value *= (rmd * pwr * noise_basis(p, basis) + 1.0f); /* correct? */
87
88         return value;
89 }
90
91 /* Musgrave Heterogeneous Terrain
92  *
93  * H: fractal dimension of the roughest area
94  * lacunarity: gap between successive frequencies
95  * octaves: number of frequencies in the fBm
96  * offset: raises the terrain from `sea level'
97  */
98
99 static float noise_musgrave_hetero_terrain(float p[3], int basis, float H, float lacunarity, float octaves, float offset)
100 {
101         float value, increment, rmd;
102         float pwHL = pow(lacunarity, -H);
103         float pwr = pwHL;
104         int i;
105
106         /* first unscaled octave of function; later octaves are scaled */
107         value = offset + noise_basis(p, basis);
108         mul_v3_fl(p, lacunarity);
109
110         for(i = 1; i < (int)octaves; i++) {
111                 increment = (noise_basis(p, basis) + offset) * pwr * value;
112                 value += increment;
113                 pwr *= pwHL;
114                 mul_v3_fl(p, lacunarity);
115         }
116
117         rmd = octaves - floor(octaves);
118         if(rmd != 0.0f) {
119                 increment = (noise_basis(p, basis) + offset) * pwr * value;
120                 value += rmd * increment;
121         }
122
123         return value;
124 }
125
126 /* Hybrid Additive/Multiplicative Multifractal Terrain
127  *
128  * H: fractal dimension of the roughest area
129  * lacunarity: gap between successive frequencies
130  * octaves: number of frequencies in the fBm
131  * offset: raises the terrain from `sea level'
132  */
133
134 static float noise_musgrave_hybrid_multi_fractal(float p[3], int basis, float H, float lacunarity, float octaves, float offset, float gain)
135 {
136         float result, signal, weight, rmd;
137         float pwHL = pow(lacunarity, -H);
138         float pwr = pwHL;
139         int i;
140
141         result = noise_basis(p, basis) + offset;
142         weight = gain * result;
143         mul_v3_fl(p, lacunarity);
144
145         for(i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
146                 if(weight > 1.0f)
147                         weight = 1.0f;
148
149                 signal = (noise_basis(p, basis) + offset) * pwr;
150                 pwr *= pwHL;
151                 result += weight * signal;
152                 weight *= gain * signal;
153                 mul_v3_fl(p, lacunarity);
154         }
155
156         rmd = octaves - floor(octaves);
157         if(rmd != 0.0f)
158                 result += rmd * ((noise_basis(p, basis) + offset) * pwr);
159
160         return result;
161 }
162
163 /* Ridged Multifractal Terrain
164  *
165  * H: fractal dimension of the roughest area
166  * lacunarity: gap between successive frequencies
167  * octaves: number of frequencies in the fBm
168  * offset: raises the terrain from `sea level'
169  */
170
171 static float noise_musgrave_ridged_multi_fractal(float p[3], int basis, float H, float lacunarity, float octaves, float offset, float gain)
172 {
173         float result, signal, weight;
174         float pwHL = pow(lacunarity, -H);
175         float pwr = pwHL;
176         int i;
177
178         signal = offset - fabsf(noise_basis(p, basis));
179         signal *= signal;
180         result = signal;
181         weight = 1.0f;
182
183         for(i = 1; i < (int)octaves; i++) {
184                 mul_v3_fl(p, lacunarity);
185                 weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
186                 signal = offset - fabsf(noise_basis(p, basis));
187                 signal *= signal;
188                 signal *= weight;
189                 result += signal * pwr;
190                 pwr *= pwHL;
191         }
192
193         return result;
194 }
195
196 static float musgrave(int type, int basis, float dimension, float lacunarity, float octaves, float offset, float intensity, float gain, float size, float vec[3])
197 {
198         float p[3];
199
200         mul_v3_v3fl(p, vec, 1.0f/size);
201
202         if(type == SHD_MUSGRAVE_MULTIFRACTAL)
203                 return intensity*noise_musgrave_multi_fractal(p, basis, dimension, lacunarity, octaves);
204         else if(type == SHD_MUSGRAVE_FBM)
205                 return intensity*noise_musgrave_fBm(p, basis, dimension, lacunarity, octaves);
206         else if(type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL)
207                 return intensity*noise_musgrave_hybrid_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
208         else if(type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL)
209                 return intensity*noise_musgrave_ridged_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
210         else if(type == SHD_MUSGRAVE_HETERO_TERRAIN)
211                 return intensity*noise_musgrave_hetero_terrain(p, basis, dimension, lacunarity, octaves, offset);
212         
213         return 0.0f;
214 }
215
216 /* **************** MUSGRAVE ******************** */
217
218 static bNodeSocketType sh_node_tex_musgrave_in[]= {
219         {       SOCK_VECTOR, 1, "Vector",               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, SOCK_NO_VALUE},
220         {       SOCK_VALUE, 1, "Size",                  0.25f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
221         {       SOCK_VALUE, 1, "Dimension",             2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
222         {       SOCK_VALUE, 1, "Lacunarity",    1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
223         {       SOCK_VALUE, 1, "Octaves",               2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
224         {       SOCK_VALUE, 1, "Offset",                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
225         {       SOCK_VALUE, 1, "Gain",                  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
226         {       -1, 0, ""       }
227 };
228
229 static bNodeSocketType sh_node_tex_musgrave_out[]= {
230         {       SOCK_VALUE, 0, "Fac",           0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
231         {       -1, 0, ""       }
232 };
233
234 static void node_shader_init_tex_musgrave(bNode *node)
235 {
236         NodeTexMusgrave *tex = MEM_callocN(sizeof(NodeTexMusgrave), "NodeTexMusgrave");
237         tex->type = SHD_MUSGRAVE_FBM;
238         tex->basis = SHD_NOISE_PERLIN;
239
240         node->storage = tex;
241 }
242
243 static void node_shader_exec_tex_musgrave(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
244 {
245         ShaderCallData *scd= (ShaderCallData*)data;
246         NodeTexMusgrave *tex= (NodeTexMusgrave*)node->storage;
247         bNodeSocket *vecsock = node->inputs.first;
248         float vec[3], size, dimension, lacunarity, octaves, offset, gain;
249         
250         if(vecsock->link)
251                 nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
252         else
253                 copy_v3_v3(vec, scd->co);
254
255         nodestack_get_vec(&size, SOCK_VALUE, in[1]);
256         nodestack_get_vec(&dimension, SOCK_VALUE, in[2]);
257         nodestack_get_vec(&lacunarity, SOCK_VALUE, in[3]);
258         nodestack_get_vec(&octaves, SOCK_VALUE, in[4]);
259         nodestack_get_vec(&offset, SOCK_VALUE, in[5]);
260         nodestack_get_vec(&gain, SOCK_VALUE, in[6]);
261
262         out[0]->vec[0]= musgrave(tex->type, tex->basis, dimension, lacunarity, octaves, offset, 1.0f, gain, size, vec);
263 }
264
265 static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
266 {
267         if(!in[0].link)
268                 in[0].link = GPU_attribute(CD_ORCO, "");
269
270         return GPU_stack_link(mat, "node_tex_musgrave", in, out);
271 }
272
273 /* node type definition */
274 void register_node_type_sh_tex_musgrave(ListBase *lb)
275 {
276         static bNodeType ntype;
277
278         node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0,
279                 sh_node_tex_musgrave_in, sh_node_tex_musgrave_out);
280         node_type_size(&ntype, 150, 60, 200);
281         node_type_init(&ntype, node_shader_init_tex_musgrave);
282         node_type_storage(&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
283         node_type_exec(&ntype, node_shader_exec_tex_musgrave);
284         node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
285
286         nodeRegisterType(lb, &ntype);
287 };
288