Fix: smoke noise tile was saved in Blender executable directory, which is often write...
[blender.git] / intern / smoke / intern / smoke_API.cpp
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) 2009 by Daniel Genrich
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Genrich
22  *                 Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file smoke/intern/smoke_API.cpp
28  *  \ingroup smoke
29  */
30
31 #include "FLUID_3D.h"
32 #include "WTURBULENCE.h"
33 #include "spectrum.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38
39 #include "../extern/smoke_API.h"  /* to ensure valid prototypes */
40
41 extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors)
42 {
43         FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
44         return fluid;
45 }
46
47 extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
48 {
49         if (amplify)
50                 return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
51         else 
52                 return NULL;
53 }
54
55 extern "C" void smoke_free(FLUID_3D *fluid)
56 {
57         delete fluid;
58         fluid = NULL;
59 }
60
61 extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
62 {
63          delete wt;
64          wt = NULL;
65 }
66
67 extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
68 {
69         return x + y * max_x + z * max_x*max_y;
70 }
71
72 extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
73 {
74         return x + y * max_x;
75 }
76
77 extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
78 {
79         if (fluid->_fuel) {
80                 fluid->processBurn(fluid->_fuel, fluid->_density, fluid->_react, fluid->_flame, fluid->_heat,
81                                                    fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, (*fluid->_dtFactor)*dtSubdiv);
82         }
83         fluid->step(dtSubdiv, gravity);
84 }
85
86 extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
87 {
88         if (wt->_fuelBig) {
89                 fluid->processBurn(wt->_fuelBig, wt->_densityBig, wt->_reactBig, wt->_flameBig, 0,
90                                                    wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, fluid->_dt);
91         }
92         wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles); 
93 }
94
95 extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
96                                                                          float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
97 {
98         fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli, burning_rate, flame_smoke, flame_smoke_color, flame_vorticity, flame_ignition_temp, flame_max_temp);
99 }
100
101 extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
102 {
103         wt->initBlenderRNA(strength);
104 }
105
106 static void data_dissolve(float *density, float *heat, float *r, float *g, float *b, int total_cells, int speed, int log)
107 {
108         if (log) {
109                 /* max density/speed = dydx */
110                 float fac = 1.0f - (1.0f / (float)speed);
111
112                 for(size_t i = 0; i < total_cells; i++)
113                 {
114                         /* density */
115                         density[i] *= fac;
116
117                         /* heat */
118                         if (heat) {
119                                 heat[i] *= fac;
120                         }
121
122                         /* color */
123                         if (r) {
124                                 r[i] *= fac;
125                                 g[i] *= fac;
126                                 b[i] *= fac;
127                         }
128                 }
129         }
130         else // linear falloff
131         {
132                 /* max density/speed = dydx */
133                 float dydx = 1.0f / (float)speed;
134
135                 for(size_t i = 0; i < total_cells; i++)
136                 {
137                         float d = density[i];
138                         /* density */
139                         density[i] -= dydx;
140                         if (density[i] < 0.0f)
141                                 density[i] = 0.0f;
142
143                         /* heat */
144                         if (heat) {
145                                 if      (abs(heat[i]) < dydx) heat[i] = 0.0f;
146                                 else if (heat[i] > 0.0f) heat[i] -= dydx;
147                                 else if (heat[i] < 0.0f) heat[i] += dydx;
148                         }
149
150                         /* color */
151                         if (r && d) {
152                                 r[i] *= (density[i]/d);
153                                 g[i] *= (density[i]/d);
154                                 b[i] *= (density[i]/d);
155                         }
156                                 
157                 }
158         }
159 }
160
161 extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
162 {
163         data_dissolve(fluid->_density, fluid->_heat, fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, speed, log);
164 }
165
166 extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
167 {
168         data_dissolve(wt->_densityBig, 0, wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, speed, log);
169 }
170
171 extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, 
172                                                          float **heatold, float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles)
173 {
174         *dens = fluid->_density;
175         if(fuel)
176                 *fuel = fluid->_fuel;
177         if(react)
178                 *react = fluid->_react;
179         if(flame)
180                 *flame = fluid->_flame;
181         if(heat)
182                 *heat = fluid->_heat;
183         if(heatold)
184                 *heatold = fluid->_heatOld;
185         *vx = fluid->_xVelocity;
186         *vy = fluid->_yVelocity;
187         *vz = fluid->_zVelocity;
188         if(r)
189                 *r = fluid->_color_r;
190         if(g)
191                 *g = fluid->_color_g;
192         if(b)
193                 *b = fluid->_color_b;
194         *obstacles = fluid->_obstacles;
195         *dt = fluid->_dt;
196         *dx = fluid->_dx;
197 }
198
199 extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
200                                         float **r, float **g, float **b , float **tcu, float **tcv, float **tcw)
201 {
202         if (!wt)
203                 return;
204
205         *dens = wt->_densityBig;
206         if(fuel)
207                 *fuel = wt->_fuelBig;
208         if(react)
209                 *react = wt->_reactBig;
210         if(flame)
211                 *flame = wt->_flameBig;
212         if(r)
213                 *r = wt->_color_rBig;
214         if(g)
215                 *g = wt->_color_gBig;
216         if(b)
217                 *b = wt->_color_bBig;
218         *tcu = wt->_tcU;
219         *tcv = wt->_tcV;
220         *tcw = wt->_tcW;
221 }
222
223 extern "C" float *smoke_get_density(FLUID_3D *fluid)
224 {
225         return fluid->_density;
226 }
227
228 extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
229 {
230         return fluid->_fuel;
231 }
232
233 extern "C" float *smoke_get_react(FLUID_3D *fluid)
234 {
235         return fluid->_react;
236 }
237
238 extern "C" float *smoke_get_heat(FLUID_3D *fluid)
239 {
240         return fluid->_heat;
241 }
242
243 extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid)
244 {
245         return fluid->_xVelocity;
246 }
247
248 extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid)
249 {
250         return fluid->_yVelocity;
251 }
252
253 extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid)
254 {
255         return fluid->_zVelocity;
256 }
257
258 extern "C" float *smoke_get_force_x(FLUID_3D *fluid)
259 {
260         return fluid->_xForce;
261 }
262
263 extern "C" float *smoke_get_force_y(FLUID_3D *fluid)
264 {
265         return fluid->_yForce;
266 }
267
268 extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
269 {
270         return fluid->_zForce;
271 }
272
273 extern "C" float *smoke_get_flame(FLUID_3D *fluid)
274 {
275         return fluid->_flame;
276 }
277
278 extern "C" float *smoke_get_color_r(FLUID_3D *fluid)
279 {
280         return fluid->_color_r;
281 }
282
283 extern "C" float *smoke_get_color_g(FLUID_3D *fluid)
284 {
285         return fluid->_color_g;
286 }
287
288 extern "C" float *smoke_get_color_b(FLUID_3D *fluid)
289 {
290         return fluid->_color_b;
291 }
292
293 static void get_rgba(float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
294 {
295         int i;
296         int m = 4, i_g = 1, i_b = 2, i_a = 3;
297         /* sequential data */
298         if (sequential) {
299                 m = 1;
300                 i_g *= total_cells;
301                 i_b *= total_cells;
302                 i_a *= total_cells;
303         }
304
305         for (i=0; i<total_cells; i++) {
306                 float alpha = a[i];
307                 if (alpha) {
308                         data[i*m  ] = r[i];
309                         data[i*m+i_g] = g[i];
310                         data[i*m+i_b] = b[i];
311                 }
312                 else {
313                         data[i*m  ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
314                 }
315                 data[i*m+i_a] = alpha;
316         }
317 }
318
319 extern "C" void smoke_get_rgba(FLUID_3D *fluid, float *data, int sequential)
320 {
321         get_rgba(fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_density, fluid->_totalCells, data, sequential);
322 }
323
324 extern "C" void smoke_turbulence_get_rgba(WTURBULENCE *wt, float *data, int sequential)
325 {
326         get_rgba(wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_densityBig, wt->_totalCellsBig, data, sequential);
327 }
328
329 /* get a single color premultiplied voxel grid */
330 static void get_rgba_from_density(float color[3], float *a, int total_cells, float *data, int sequential)
331 {
332         int i;
333         int m = 4, i_g = 1, i_b = 2, i_a = 3;
334         /* sequential data */
335         if (sequential) {
336                 m = 1;
337                 i_g *= total_cells;
338                 i_b *= total_cells;
339                 i_a *= total_cells;
340         }
341
342         for (i=0; i<total_cells; i++) {
343                 float alpha = a[i];
344                 if (alpha) {
345                         data[i*m  ] = color[0] * alpha;
346                         data[i*m+i_g] = color[1] * alpha;
347                         data[i*m+i_b] = color[2] * alpha;
348                 }
349                 else {
350                         data[i*m  ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
351                 }
352                 data[i*m+i_a] = alpha;
353         }
354 }
355
356 extern "C" void smoke_get_rgba_from_density(FLUID_3D *fluid, float color[3], float *data, int sequential)
357 {
358         get_rgba_from_density(color, fluid->_density, fluid->_totalCells, data, sequential);
359 }
360
361 extern "C" void smoke_turbulence_get_rgba_from_density(WTURBULENCE *wt, float color[3], float *data, int sequential)
362 {
363         get_rgba_from_density(color, wt->_densityBig, wt->_totalCellsBig, data, sequential);
364 }
365
366 extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
367 {
368         return wt ? wt->getDensityBig() : NULL;
369 }
370
371 extern "C" float *smoke_turbulence_get_fuel(WTURBULENCE *wt)
372 {
373         return wt ? wt->getFuelBig() : NULL;
374 }
375
376 extern "C" float *smoke_turbulence_get_react(WTURBULENCE *wt)
377 {
378         return wt ? wt->_reactBig : NULL;
379 }
380
381 extern "C" float *smoke_turbulence_get_color_r(WTURBULENCE *wt)
382 {
383         return wt ? wt->_color_rBig : NULL;
384 }
385
386 extern "C" float *smoke_turbulence_get_color_g(WTURBULENCE *wt)
387 {
388         return wt ? wt->_color_gBig : NULL;
389 }
390
391 extern "C" float *smoke_turbulence_get_color_b(WTURBULENCE *wt)
392 {
393         return wt ? wt->_color_bBig : NULL;
394 }
395
396 extern "C" float *smoke_turbulence_get_flame(WTURBULENCE *wt)
397 {
398         return wt ? wt->getFlameBig() : NULL;
399 }
400
401 extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
402 {
403         if (wt) {
404                 Vec3Int r = wt->getResBig();
405                 res[0] = r[0];
406                 res[1] = r[1];
407                 res[2] = r[2];
408         }
409 }
410
411 extern "C" int smoke_turbulence_get_cells(WTURBULENCE *wt)
412 {
413         if (wt) {
414                 Vec3Int r = wt->getResBig();
415                 return r[0] * r[1] * r[2];
416         }
417         return 0;
418 }
419
420 extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
421 {
422         return fluid->_obstacles;
423 }
424
425 extern "C" void smoke_get_ob_velocity(FLUID_3D *fluid, float **x, float **y, float **z)
426 {
427         *x = fluid->_xVelocityOb;
428         *y = fluid->_yVelocityOb;
429         *z = fluid->_zVelocityOb;
430 }
431
432 #if 0
433 extern "C" unsigned char *smoke_get_obstacle_anim(FLUID_3D *fluid)
434 {
435         return fluid->_obstaclesAnim;
436 }
437 #endif
438
439 extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type, const char *noisefile_path)
440 {
441         wt->setNoise(type, noisefile_path);
442 }
443
444 extern "C" void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2)
445 {
446         spectrum(t1, t2, width, spec);
447 }
448
449 extern "C" int smoke_has_heat(FLUID_3D *fluid)
450 {
451         return (fluid->_heat) ? 1 : 0;
452 }
453
454 extern "C" int smoke_has_fuel(FLUID_3D *fluid)
455 {
456         return (fluid->_fuel) ? 1 : 0;
457 }
458
459 extern "C" int smoke_has_colors(FLUID_3D *fluid)
460 {
461         return (fluid->_color_r && fluid->_color_g && fluid->_color_b) ? 1 : 0;
462 }
463
464 extern "C" int smoke_turbulence_has_fuel(WTURBULENCE *wt)
465 {
466         return (wt->_fuelBig) ? 1 : 0;
467 }
468
469 extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
470 {
471         return (wt->_color_rBig && wt->_color_gBig && wt->_color_bBig) ? 1 : 0;
472 }
473
474 /* additional field initialization */
475 extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
476 {
477         if (fluid) {
478                 fluid->initHeat();
479         }
480 }
481
482 extern "C" void smoke_ensure_fire(FLUID_3D *fluid, WTURBULENCE *wt)
483 {
484         if (fluid) {
485                 fluid->initFire();
486         }
487         if (wt) {
488                 wt->initFire();
489         }
490 }
491
492 extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init_r, float init_g, float init_b)
493 {
494         if (fluid) {
495                 fluid->initColors(init_r, init_g, init_b);
496         }
497         if (wt) {
498                 wt->initColors(init_r, init_g, init_b);
499         }
500 }